Аудит репозитория после #25 и #26. Расхождения между тем, что написано, и тем, что есть: - README обещал `tglock-cli-*` в таблице загрузок, но в релизе v2.0.0-beta.1 такого артефакта нет: задача `cli` в release.yml сработает только на следующем теге. Заменено на честную формулировку с командой сборки из main. - ui/main.ts держал начальным значением маршрута строку «Автоматический маршрут», которую бэкенд больше не отдаёт: при коде 0 возвращается «Маршрут ещё не выбран». Иначе до первого опроса статуса интерфейс показывал название несуществующего маршрута. - ARCHITECTURE_V2.md не упоминал ни разделения на библиотеку и два бинаря, ни фичи `gui`, ни правила различения протоколов, ни политики прямого релея, ни того, что GUI не запускается без WebView. Добавлены разделы, а последнее внесено в Current limitations вместе с отсутствием подписи бинарей. - ISSUE_AUDIT.md описывал состояние на 29 июля. Сам аудит оставлен как фиксация на дату, сверху добавлен статус на 30 июля: что закрыто, что осталось открытым и почему, и что исправлено вне списка issues. - HABR.md — черновик статьи, а не документация, но был указан в README как «подробный технический разбор». В нём «два файла, 350 строк, четыре платформы», тогда как сейчас 2872 строки Rust, семь файлов и три платформы плюс headless. Добавлена шапка с поправкой, ссылка в README переписана так, чтобы читателя не отправляли к устаревшим числам за документацией. Проверено: fmt, clippy в обоих вариантах сборки, 47 + 12 тестов, npm run build, все ссылки на файлы в .md существуют. Co-authored-by: by-sonic <171230345+by-sonic@users.noreply.github.com>
8.5 KiB
TGLock 2.0 architecture
Сборка: ядро, GUI и headless
Крейт собирается в библиотеку и два бинаря:
src/lib.rs— ядро:mtproto,transport,proxy,config. Не зависит ни от Tauri, ни от оконной системы;src/main.rs— GUI, доступен только при включённой фичеgui(required-features);src/bin/cli.rs— headlesstglock-cli.
Фича gui включена по умолчанию и подтягивает tauri, tauri-build и open.
При --no-default-features ни Tauri, ни системный WebView, ни фронтенд в сборку
не попадают, и build.rs не вызывает tauri_build. Это единственный способ
собрать и запустить TGLock там, где WebView не создаёт окно: сервер, контейнер,
виртуалка, машина без монитора или без 3D-ускорения.
Local protocols
Один TCP-порт автоматически принимает два типа клиентов:
- MTProto proxy с постоянным 16-байтовым secret — основной режим;
- SOCKS5 без авторизации — режим совместимости.
MTProto init проверяется по secret и transport tag. Из него извлекаются DC, признак media-соединения и тип транспорта. Для upstream создаётся новый стандартный obfuscated2 init, а последующий поток пере-шифровывается между локальным secret и Telegram.
Различение протоколов
Определять протокол по первому байту нельзя. SOCKS5-приветствие начинается с
0x05, но MTProto init — это 64 случайных байта, и is_reserved_init
исключает только 0xef, 0xee, 0xdd, HTTP-глаголы и заголовок TLS-записи.
Значение 0x05 попадается примерно в одном init из 256, и такое соединение
уходило в SOCKS5-ветку и умирало — снаружи это выглядит как «Telegram
отправляет сообщения через раз».
Поэтому неоднозначный первый байт разрешается так: не потребляя данные, ожидается полный 64-байтовый init и делается попытка разобрать его под текущим secret. Успешный разбор означает MTProto. Настоящий SOCKS5-клиент присылает короткое приветствие и блокируется на ответе, поэтому 64 байта у него не появятся и по истечении короткого таймаута он корректно уходит в SOCKS5-ветку.
Политика прямого релея
Не-Telegram адреса релеятся напрямую, без шифрования, и пользы для обхода в
этом нет. Поэтому такой релей разрешён только когда прокси слушает loopback,
где до него дотягиваются лишь локальные процессы. На 0.0.0.0 и любом другом
сетевом адресе не-Telegram запросы отклоняются кодом SOCKS5 0x02, иначе
LAN-режим превращал бы машину в открытый прокси. Правило выражено в типе
config::ListenConfig, а не в условиях по месту вызова; переопределяется
только явным --allow-direct в CLI.
Учёт состояния
Stats::ws считает установленные туннели: счётчик поднимается после
успешного transport.connect, а не перед попыткой. Иначе интерфейс
рапортовал бы «Telegram на связи», пока рукопожатие ещё перебирает маршруты по
несколько секунд каждый. Состояния «порт открыт», «идёт перебор маршрутов» и
«туннель установлен» различимы и в GUI, и в выводе CLI.
Секрет прокси — половина ссылки tg://proxy. Для сервиса его нужно закрепить
файлом (--secret-file): под DynamicUser и ProtectHome домашней папки нет,
путь по умолчанию не определяется, и секрет генерировался бы заново при каждом
старте, отключая всех уже настроенных клиентов.
Transport cascade
Для каждого DC и отдельно для media-соединений строится список маршрутов:
- сохранённый успешный маршрут;
- точный Telegram IP с
kwsNилиkwsN-1в TLS SNI и WebSocket Host; - дополнительный Telegram IP, если он определён;
- системный DNS;
- явно настроенный пользователем Cloudflare Worker.
Поддерживаются DC1–5 и media/CDN DC203. DC203 использует WebSocket-host DC2, но подключается к собственному IP.
После ошибки маршрут получает exponential cooldown от 30 секунд до 30 минут. Успешный маршрут становится первым для следующего соединения того же DC и типа трафика.
TLS policy
Проверка сертификатов и hostname никогда не отключается. При подключении к
заданному Telegram IP TCP destination отделён от URI host: TLS продолжает
проверять сертификат настоящего kws*.web.telegram.org.
Cloudflare Worker принимается только как пользовательская настройка. TGLock не загружает и не скрывает публичные списки чужих доменов.
Cloudflare Worker contract
Worker должен принимать WebSocket на:
/apiws?dst=<telegram-ip>&dc=<dc-id>
и проксировать бинарные frames в TCP <telegram-ip>:443. Рекомендуется
добавить собственную авторизацию до стабильного релиза; поэтому Worker
остаётся расширенной опцией alpha-версии.
Current limitations
- SNI camouflage не включена: небезопасное отключение hostname verification из референсной реализации не переносится.
- Голосовые звонки по UDP не поддерживаются.
- GUI не запускается там, где WebView не может создать окно — нет
3D-ускорения, дефолтный видеодрайвер, отсутствует монитор, виртуальная
машина. Это ограничение Tauri, а не транспорта; программный рендер как
обходной путь не проверен. Рабочий вариант для таких машин —
tglock-cli(issues #10, #17). - Windows-инсталлятор не подписан, macOS-сборка не нотарифицирована. Часть антивирусов реагирует на неподписанный установщик, открывающий локальный сокет; проверяемый ответ — сборка из исходников либо публичные логи GitHub Actions.
- Работоспособность медиа зависит от конкретного DC аккаунта и доступности Telegram/Cloudflare у провайдера.
- Пулы заранее открытых WebSocket-соединений будут добавлены после измерения, что они не создают лишнюю нагрузку и не ухудшают стабильность.