Files
tglock/docs/LIVE_PROBE.md
T
Никита Sonic 8ce9355243 fix: медиа и «прокси не настроен»: пакет на кадр, настоящие фронты, kwsN-1 только для медиа; beta.19 (#75)
* fix(tunnel): медиа и «прокси не настроен»: один пакет на кадр, настоящие фронты, kwsN-1 только для медиа

Три причины, каждая проверена на живом Telegram запросом req_DH_params:
сервер сверяет номер DC внутри него с собой и отвечает -444 на чужой.

- WebSocket-фронт разбирает один пакет на входящий кадр, остаток ждёт
  следующего. Клиент пишет запросы пачками, TGLock слал их одним кадром,
  и всё, что шло вторым, застревало: текст проходил, файлы вставали.
  Теперь поток режется на пакеты, как в Flowseal/tg-ws-proxy. Пачка через
  beta.18 висит на всех DC, через эту сборку принимается на всех.
- Кластер kwsN-1 отвергает обычное соединение с -444, а Telegram Desktop
  в ответ выключает прокси как настроенный неверно. При сбое kwsN основное
  соединение откатывалось именно туда. Теперь kwsN-1 только для медиа.
- Адреса из списка DC не говорят на TLS ни из какой сети (проверено с чистой
  сети), поэтому первый маршрут каждого DC не работал никогда. Закреплены
  настоящие фронты, и DC1, DC3, DC5 стали доступны по WebSocket, чего не было.
  У CDN203 своего фронта нет: остались TCP, Worker и CF-прокси.

Обрыв туннеля, через который уже шли данные, больше не ставит маршрут на
паузу. Таймаут соединения 8 с, как в tg-ws-proxy. probe_proxy.mjs получил
--identity и --batched: они и нашли эти баги.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat: журнал ошибок в диагностике, --log-file для роутеров; 2.0.0-beta.19

«Скопировать диагностику» отдавала только счётчики, и по ней нельзя было
понять, какой маршрут не ответил. Теперь в отчёте есть строки сбоев туннелей,
а домены Worker и CF-прокси в них заменены на <домен>.

--log-file и --log-max-mb (log_file, log_max_mb в настройках), как в
tg-ws-proxy: журнал идёт в файл с ротацией, а не в системный журнал роутера.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(routes): запасной WebSocket на порту 80 родных адресов, включая CDN203

Родные адреса Telegram принимают WebSocket без TLS на порту 80. Измерено
req_DH_params: DC определяется адресом, имя хоста не важно, а 91.105.192.100
отдаёт ключи CDN. Для CDN203, откуда часто идёт видео, это первый прямой
WebSocket: на 443 фронта у него нет, и там, где провайдер закрыл только 443,
до него раньше было не достать без Worker.

Защита та же, что у родного TCP: внутри тот же обфусцированный MTProto. В Host
идёт адрес, имени Telegram в открытом виде нет. Маршрут разрешён только до
закреплённых адресов и пробуется последним.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(routes): паузы маршрутов по результатам ревью, пределы и журнал

- Обрыв не наказывает маршрут, только если туннель работал и получал ответы
  15 с. Одного ответа мало: маршрут, который ответил раз и умер, оставался
  предпочтительным навсегда.
- Клиент спросил, не дождался ответа за 5 с и ушёл: маршрут считается
  неработающим. Иначе CDN, принявший TCP и молчащий, держал первое место, и
  очередь до порта 80 не доходила.
- Предел пакета 2 МиБ вместо 16: чужое устройство в LAN-режиме не заставит
  роутер копить десятки мегабайт на соединение.
- Журнал: разовая ошибка записи его больше не выключает, неудачная ротация
  не теряет бэкап и держит предел, права 0600 и на уже существующем файле.
- В отчёт диагностики не попадает Worker, заданный адресом.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: babin <Thartewerner536e@engineer.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 07:32:03 +00:00

82 lines
4.1 KiB
Markdown

# Manual protocol probe
`scripts/probe_proxy.mjs` uses only Node.js built-ins and is independent of the
Rust transport helpers. It connects to an already running TGLock listener at
`127.0.0.1`, sends one unauthenticated `req_pq_multi` through a secret-protected
obfuscated2 padded-intermediate stream, and validates the returned `resPQ`, its
request nonce, and the lengths of its TL fields. It stops before creating an
authorization key. No Telegram account, API ID, API hash or login is needed.
The secret is read from an explicitly supplied file and is never printed. Use
the same secret file as the running CLI. Do not paste proxy links or secret
values into public logs.
```sh
# Offline validation first: no network access.
node scripts/probe_proxy.mjs --self-test
# Start a local CLI separately, using a persistent secret file.
tglock-cli --port 18080 --secret-file /private/path/tglock-secret
# Ordinary DC, media route, and CDN route; run each explicitly.
node scripts/probe_proxy.mjs --port 18080 --secret-file /private/path/tglock-secret --dc 2
node scripts/probe_proxy.mjs --port 18080 --secret-file /private/path/tglock-secret --dc -4 --fragment-size 7
node scripts/probe_proxy.mjs --port 18080 --secret-file /private/path/tglock-secret --dc 203
```
On Windows, supply the downloaded CLI executable and a Windows file path in the
same commands. Supported DC values are `1` through `5` and `203`; a negative
value requests a media route. `--timeout-ms` defaults to 15000 and is bounded at
120000. The response is bounded at 2 MiB. `--fragment-size 7` sends small writes
with 2 ms gaps to exercise stream fragmentation; TCP can still combine writes.
A successful JSON report contains `response: "resPQ"`, `nonceMatches: true`, the
requested DC, the public RSA fingerprint count, and elapsed time. Exit status 1
means connection, timeout, decryption/framing or response validation failed.
The ordinary CI suite does not run this live probe.
Success demonstrates a correctly relayed protocol exchange. It does **not**
authenticate the responding server, prove its DC identity, log into an account,
or verify message sending, media downloads or Android lifecycle. In particular,
`requestedDc` describes the request, not an independently confirmed backend.
## Confirm which data centre answers
`--identity` continues the handshake with `req_DH_params`. The DC number sealed
inside it is checked by the server against itself, and a mismatch is answered
with transport error `-444`, so this does prove the backend. `resPQ` alone proves
nothing here: every server answers it for any DC in the header. The handshake
stops before an authorization key exists. CDN DC203 uses its own RSA keys, so
the report says `identity: "skipped: CDN keys"` for it.
`--batched` implies `--identity` and sends `req_DH_params` glued behind another
packet in one write, the way real clients batch requests. A WebSocket frontend
reads one packet per frame, so a proxy that forwards the write as a single frame
times out here while a lone request still passes. Run it before every release:
```sh
for dc in 1 2 -2 3 4 -4 5 203; do
node scripts/probe_proxy.mjs --port 18080 --secret-file /private/path/tglock-secret --dc $dc --batched
done
```
## Isolate CDN transport failures
To distinguish an unavailable CDN WebSocket endpoint from an unavailable CDN
TCP connection, explicitly run:
```sh
node scripts/probe_proxy.mjs --direct-cdn --dc 203
```
This optional mode bypasses local TGLock and connects **only** to the pinned
Telegram CDN address `91.105.192.100:443`, using raw obfuscated2 TCP without a
proxy secret or TLS. It supports no arbitrary host. It performs the same single
unauthenticated exchange and still does not prove account or media operation.
The parser accepts trailing bytes after the complete `resPQ` TL object because
live CDN replies can include random padding in the declared message length.
Protocol references: [handshake initiation](https://core.telegram.org/mtproto/auth_key),
[obfuscated transports](https://core.telegram.org/mtproto/mtproto-transports),
and [unencrypted messages](https://core.telegram.org/mtproto/description#unencrypted-message).