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

4.1 KiB

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.

# 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:

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:

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, obfuscated transports, and unencrypted messages.