todo/mtproxy/telegram-wss-limits.md
loop-uh 0505fa6b4a
Some checks failed
Published content check / validate (push) Has been cancelled
Заметки о вредоносных сборках вынесены в раздел virus/
В корне создан раздел virus/: каталог вирусных сборок, разборы Bypass
Ultimate, фейкового Flowseal со стилером, зачистки GitHub, приманки Fixit
и заметка про Cactuz. Вместе с ними перенесены 58 иллюстраций в
virus/attachments — все они использовались только этими заметками.

Обновлены Forgejo-футеры перенесённых заметок и ссылки с явным путём
в mtproxy/telegram-wss-*.md и banks-malware-scan-2027.md. Ссылки по имени
файла продолжают работать без правок.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 14:56:51 +03:00

47 KiB
Raw Permalink Blame History

date tags aliases
2026-08-06
mtproto
telegram
wss
websocket
диагностика
обход-блокировок
cloudflare
Почему не грузятся стикеры через WSS прокси
WSS прокси Telegram не работает
Не грузит фото и видео в Telegram через прокси
Почему звонки не работают через прокси Telegram
Ошибка 429 Cloudflare Worker Telegram
The proxy you are using is not configured correctly
Ограничения WSS транспорта Telegram

🧯 Ограничения WSS для Telegram: что не работает и почему

[!info] О чём заметка У транспорта, который прячет MTProto в WebSocket и отправляет на веб-релеи Telegram, длинный список оговорок: работают не все датацентры, стикеры и реакции могут не грузиться, звонки не проксируются вовсе, а бесплатные запасные пути упираются в лимиты Cloudflare. Здесь собраны симптомы, их причины и то, чем каждый случай подтверждается. Как транспорт устроен изнутри — в парной заметке mtproxy/telegram-wss-transport.

[!warning] Откуда взяты данные Заметка собрана из трёх типов источников по состоянию на 6 августа 2026: комментарии и константы в коде четырёх проектов (tg-ws-proxy, модуль telegram_proxy в ZapretGUI, форки ZaStoGram для Android и Desktop), их журналы исправлений и обсуждения в трекере tg-ws-proxy — включая пользовательский FAQ, который ведёт сообщество в issue #389, а не разработчики Telegram. Результаты замеров относятся к конкретным сетям и датам и не являются спецификацией: у другого провайдера и в другой месяц поведение релеев может отличаться.


TL;DR

  1. Кадр WebSocket — единица разбора, а не просто нарезка. Релей обрабатывает только первый MTProto-пакет кадра и молча выбрасывает остальные, поэтому склеивать пакеты нельзя (разрезать один пакет на несколько кадров — можно). Нарушение этого правила оставляет датацентр без ключа: рукопожатие висит на втором шаге, и медиа оттуда не грузится при внешне рабочем соединении.
  2. Веб-релеи работают у всех датацентров DC1DC5 (проверено живыми соединениями 8 августа 2026). Распространённое «только DC2 и DC4» — следствие ошибки метода: у каждого датацентра свой входной адрес, и обращение к чужому даёт редирект 302 или тишину. Реализации, рассчитанные только на DC2/DC4, ограничены собственным зашитым адресом, а не инфраструктурой Telegram.
  3. Самый частый симптом — «всё работает, но не грузятся фото, видео, стикеры и реакции». Причина обычно не в аккаунте, а в том, что нужный контент лежит на датацентре, релей которого закрыт именно в вашей сети. Проверять доступность надо по TCP, а не пингом: ICMP проходит и там, где порт 443 заблокирован — см. #Релей закрыт: «фото грузятся, эмодзи нет».
  4. Звонки и групповые войс-чаты такой прокси не переносит — они ходят по UDP, а WebSocket живёт поверх TCP. Это не значит, что они не работают: трафик звонка идёт мимо туннеля напрямую, и закрывает его пакетный обход вроде Zapret2/Zapret2 (он перехватывает UDP и STUN), а не прокси.
  5. Отдельный класс отказов — «соединение установилось, данных нет»: рукопожатие прошло, recv остаётся нулевым. Реализации ловят это таймерами и уводят маршрут в карантин на 60 секунд, час или полчаса — в зависимости от проекта.
  6. Бесплатные запасные пути через Cloudflare упираются в лимиты: общие домены отдают 429, неверный режим TLS даёт ошибку 525, а сами подсети Cloudflare в РФ тоже могут блокироваться.
  7. WSS несовместим с MTProxy и (в Android-форке) с обычным прокси: включение одного гасит другое, и это поведение задумано, а не баг.
  8. Клиентские форки долго не откатывались на обычный TCP: при недоступном релее попытки повторялись, пока пользователь не выключит транспорт руками. В обоих форках ZaStoGram откат теперь есть — датацентр с закрытым релеем уходит на прямое соединение, остальные продолжают идти через WSS. Причина отказа в интерфейс по-прежнему не выводится.

Почему считалось, что работают только DC2 и DC4

[!warning] Раздел исправлен 8 августа 2026 Утверждение «релеи есть только у DC2 и DC4» опровергнуто живыми соединениями. Работают все DC1DC5. Ниже разобрано, откуда взялось заблуждение и почему оно так убедительно выглядело.

У Telegram пять обычных датацентров плюс отдельные идентификаторы для CDN. Веб-релеи по схеме kwsN.web.telegram.org строятся для любого номера — и, как выяснилось, принимают соединения тоже все.

Источник заблуждения — не универсальность ingress-адресов. У каждого датацентра свой входной адрес: 149.154.174.100 обслуживает DC1/DC3, 149.154.167.220 — DC2/DC4, 149.154.170.100 — DC5. Инструмент, который держит один зашитый адрес на все датацентры, при попытке достучаться до чужого получает либо редирект 302 на core.telegram.org, либо — что коварнее — принятое соединение и тишину до таймаута. Отсюда и вывод «релея нет», хотя релей есть, просто вход не тот. Сервер даже подсказывает правильный: в ответе 302 есть заголовок X-Redirect-Host с нужным именем.

Проверка 8 августа 2026 (по несколько повторов на каждую пару «адрес + имя», чтобы отсеять обычные для DPI одиночные таймауты) показала: все три адреса принимают апгрейд и проксируют настоящий MTProto, включая медийные kwsN-1. Каталог маршрутов ZapretGUI, где kws1, kws3, kws5 помечены как «только запасной путь», и комментарий в коде Desktop-форка про «веб-сокеты существуют только для DC2/DC4» отражают ограничение самих этих инструментов, а не инфраструктуры Telegram.

Desktop-форк ZaStoGram зашивает ограничение прямо в код: маршрут строится, только если номер датацентра равен 2 или 4. Android-форк держит таблицу из трёх адресов и покрывает DC1DC5 — и именно его подход оказался верным. Любопытно, что расширение до пяти датацентров внесли 5 августа 2026 по аналогии, без проверки живым соединением; догадка подтвердилась только три дня спустя.

Как проверять правильно. Релей проверяется парой «адрес + имя», а не адресом отдельно: для датацентра N берите обслуживающий его ingress и ставьте Host и TLS SNI равными kwsN.web.telegram.org. Ещё надёжнее не хардкодить адреса вовсе — DNS отдаёт правильный ingress сам (имена kwsN и kwsN-1 резолвятся в один и тот же адрес; суффикс различает класс трафика на стороне релея). И обязательно делайте 45 повторов: одиночный таймаут TCP на 443 к диапазонам Telegram ничего не доказывает.

С CDN-датацентром история отдельная. Домена kws203.web.telegram.org не существует: обращение к нему падает на резолве, маршрут отправляется в чёрный список, а прямой запасной путь по адресам вроде 149.154.175.50 в РФ часто заблокирован — соединение остаётся без вариантов. Автор tg-ws-proxy в обсуждении убрал переопределение DC203 из настроек по умолчанию, посчитав, что без него работает не хуже.

[!danger] Не «просто перенаправьте на другой релей» Заманчивая идея — пустить трафик несуществующего релея через рабочий kws2 — не работает и вредит. В ZapretGUI такую попытку зафиксировали замером 14 июня 2026: 276 подключений дали 608 случаев нулевого приёма, 42 обрыва на неполном чтении и 18 таймаутов, после чего Telegram показал «The proxy you are using is not configured correctly and will be disabled» и отключил прокси. С тех пор в режиме MTProxy кросс-датацентровая маршрутизация запрещена явной проверкой: если у датацентра нет своего релея, соединение сразу идёт в запасной путь.

Причина разной строгости — в том, как Telegram относится к двум типам прокси. SOCKS5 для него непрозрачная труба: попросил соединение до адреса, получил байты, содержимое не проверяет. MTProxy — участник протокола: клиент проверяет секрет, форму init-пакета и поведение прокси, и при расхождениях выключает его целиком, а не просто повторяет попытку.


Релей закрыт: «фото грузятся, эмодзи нет»

Самый частый и самый обманчивый случай. Клиент выглядит исправным: переписка идёт, скорость нормальная, ошибок нет — но часть медиа не загружается никогда. Обычно это выглядит как «фотографии открываются, а эмодзи, реакции и стикеры не прогружаются».

Причина в том, что содержимое Telegram разложено по датацентрам, а доступность релеев в конкретной сети разная. Замеры 9 августа 2026 у одного российского провайдера, порт 443:

Куда Что это ping TCP 443
149.154.167.220 релей DC2 и DC4 отвечает открыт
149.154.174.100 релей DC1 и DC3 отвечает закрыт
2001:b28:...:338 тот же релей по IPv6 отвечает закрыт
149.154.175.50 прямой адрес DC1 отвечает, 178 мс закрыт

Открыт один путь из четырёх. Фотографии в переписке лежали на DC2 — грузились. Эмодзи и реакции на DC1 — не грузились ничем.

[!warning] ping в этом случае обманывает ICMP проходит везде, TCP на 443 — только в одном случае. DPI режет по порту, оставляя пинг живым. Проверять надо TCP:

tnc 149.154.174.100 -Port 443

и смотреть TcpTestSucceeded. Частая ошибка — писать Test-NetConnection - 1.2.3.4:443: адрес с припиской порта PowerShell ищет как имя хоста и висит до таймаута, что легко принять за блокировку.

Почему нельзя подставить другой адрес. У каждого датацентра ровно один ingress-адрес IPv4, и чужой не подходит: обращение к адресу DC2 с именем kws1 даёт редирект 302. Запасных адресов у Telegram нет, так что закрытый ingress означает мёртвый WSS для этого датацентра.

IPv6 — не универсальное спасение. AAAA-записи есть у всех релеев, и у DC1 с DC5 их по два против одного IPv4. Но в измеренной сети IPv6 был закрыт целиком, включая релей DC2, работавший по IPv4. Поэтому клиент не должен предпочитать IPv6 автоматически: это может заменить единственный рабочий путь заведомо мёртвым.

Как это должен вести себя клиент. Не держать датацентр в вечных попытках: несколько неудач подряд, не дошедших даже до установленного TCP, означают недоступный релей, и для такого датацентра нужно вернуться к обычному соединению. WSS остаётся там, где работает. В ZaStoGram это добавлено в обоих форках — Android 1.1.18 и Desktop f6bd0740, по одному принципу: три неудачи до TCP отключают маршрут на десять минут, успешный апгрейд счётчик сбрасывает.

Когда WSS вообще не подходит. Он рассчитан на сеть, где режут адреса датацентров, но не трогают web.telegram.org. Если закрыты и релеи, и прямые адреса, нужен туннель через доступный сервер — MTProxy или VPN: они проксируют все датацентры одинаково. Проверять это стоит раньше, чем искать баги в транспорте.


«Соединение есть, данных нет»

Отдельный и самый неочевидный класс отказов: TCP открылся, TLS прошёл, WebSocket ответил 101а данных от Telegram нет. С точки зрения кода соединение успешно; с точки зрения пользователя Telegram висит в «Соединение…».

Проще говоря: успешное рукопожатие доказывает, что до сервера достучались, но не доказывает, что маршрут рабочий. Именно поэтому все реализации завели отдельные счётчики «сколько байт реально пришло», а не полагаются на статус соединения.

Как с этим борются:

  • ZapretGUI держит таймер на 8 секунд: если за это время не пришло ни байта, датацентр считается заблокированным, и следующие подключения к нему сразу идут через внешний SOCKS5, минуя повторное восьмисекундное ожидание. Домен релея после одной такой неудачи уходит в карантин на 60 секунд и потом возвращается в пул. Важная тонкость: если клиент сам оборвал соединение раньше таймера — это не считается доказательством блокировки, потому что Telegram обрывает лишние соединения постоянно.
  • tg-ws-proxy реагирует на редиректы: если все домены датацентра ответили 302, датацентр попадает в чёрный список до перезапуска прокси; если часть — включается минутный «полукарантин» с укороченным таймаутом. Отдельно запоминается адрес, до которого не удалось достучаться, — на час.
  • Клиентские форки ZaStoGram запоминают на 30 минут, что сработало лучше: зашитый IP релея или его доменное имя. В Desktop-версии есть ещё один механизм — если WebSocket-соединение через выбранный SOCKS5 рвётся удалённой стороной, WSS помечается недоступным для этого прокси на полчаса, а галочка в настройках становится неактивной.

Смысл всех этих таймеров одинаковый: не долбиться в мёртвый маршрут на каждом новом подключении, но и не хоронить его навсегда — состояние сети меняется.


Медиа, стикеры и CDN

Самая частая жалоба звучит как «текст ходит, картинки нет». Второй по частоте вариант — «у знакомого с Premium всё грузится, у меня нет», из-за чего проблему регулярно приписывают подписке.

Дело не в подписке. Аккаунты с разными номерами телефонов живут на разных датацентрах, а медиа-трафик вдобавок идёт по отдельным медийным подключениям и через CDN. Релей есть у каждого датацентра, но пользуется им не каждый инструмент: если ваш датацентр — не DC2 и не DC4, а инструмент держит единственный зашитый адрес, ускорять нечего — трафик уходит в запасные маршруты, которые могут быть медленнее или недоступны. README tg-ws-proxy предлагает в этом случае оставить в списке «датацентр → адрес» только 4:149.154.167.220, а если не помогло — очистить список полностью; более правильное решение — добавить в список адреса остальных датацентров (1:149.154.174.100, 3:149.154.174.100, 5:149.154.170.100).

Реакции и стикеры лежат на CDN, до которого схема не дотягивается вовсе. Android-форк решил это честнее всех: при включённом WSS клиент сообщает серверу, что не умеет в CDN-редиректы, и исходный датацентр отдаёт файл через свой медиа-релей вместо перенаправления. До появления этого флага загрузка файлов при активном WSS ломалась: сервер отправлял клиента на CDN-датацентр, для которого маршрута нет. В Desktop-форке отдельного флага нет — там ограничение получается само собой, потому что маршрут строится только для DC2/DC4.

ZapretGUI добавил для этого случая подсказку в интерфейсе: если медиа или CDN-датацентр упали на запасном пути, пользователю предлагают включить внешний SOCKS5 или настроить свой домен либо воркер Cloudflare. Раньше эта же диагностика врала в другую сторону: медийные датацентры с именами вида «DC2 media» не проходили проверку на число и попадали в список «релея нет», хотя реально проксировались через kws2-1.


Звонки

Голосовые и видеозвонки через WSS не работают ни в одной реализации, и это не недоработка, а свойство схемы. WebSocket работает поверх TCP, а звонки Telegram используют UDP и отдельную инфраструктуру ретрансляторов. Прокси, который переносит MTProto-сессию, звонки просто не видит.

То же ограничение действует и для классического MTProxy — оно упомянуто как архитектурное ещё в Zapret/mtproto/00-overview. Автор tg-ws-proxy формулирует коротко: звонки не поддерживают MTProto.

В клиентских форках это доведено до логики интерфейса. В Android-версии включение «прокси для звонков» гасит тумблер WSS, потому что одновременно они существовать не могут. В Desktop-версии проксирование звонков отключено в коде целиком: функция, проверяющая поддержку, всегда возвращает «нет», а старая реализация через SOCKS5 закомментирована — то есть трафик звонков всегда идёт напрямую, независимо от настроек.

Единственная попытка провести звонки через сам прокси — экспериментальный проброс UDP через внешний SOCKS5 в ZapretGUI, помеченный в интерфейсе как «поможет только если Telegram и выбранный сервер поддерживают UDP через SOCKS5». Ограничений у него два: сервер должен уметь UDP ASSOCIATE, а фрагментированные датаграммы реализация отбрасывает явной ошибкой — а именно они характерны для видеозвонков.

[!important] «Не проксируются» не означает «не работают» Здесь легко сделать неверный вывод. Прокси звонки не переносит — но он их и не ломает: голосовой трафик просто идёт мимо туннеля, напрямую. Заработает он или нет, зависит от того, режет ли провайдер сам этот UDP-поток, а не от настроек WSS.

Отсюда и правильный инструмент для звонков — не прокси, а обход на уровне пакетов. Zapret2/Zapret2 работает через WinDivert и перехватывает в том числе UDP: типовые профили покрывают UDP 443, диапазон 5000050100 и STUN — то есть ровно тот трафик, из которого состоит звонок. P2P-звонки, где медиапоток идёт напрямую между абонентами, при таком обходе работают, и наличие или отсутствие WSS-прокси на это не влияет никак.

Практический вывод: WSS-прокси закрывает переписку и медиа, звонки закрывает пакетный обход (или VPN). Это два разных инструмента для двух разных задач, и включать их имеет смысл вместе, а не вместо друг друга.


Запасные пути через Cloudflare

Когда прямой релей недоступен, tg-ws-proxy и ZapretGUI умеют пойти в обход через Cloudflare — либо через бесплатный воркер, либо через домен пользователя с A-записями на адреса датацентров. Путь рабочий, но у него свои грабли.

Общие домены перегружены. Список доменов по умолчанию один на всех пользователей, и при высокой нагрузке Cloudflare начинает отвечать 429. Совет авторов — разворачивать свой воркер или свой домен. В самой документации проекта прямо сказано, что у Cloudflare есть лимиты на число одновременных WebSocket-подключений и домен по умолчанию может перестать работать в любой момент.

Автоматическое отключение перегруженного воркера не работает. В коде tg-ws-proxy есть функция, которая должна была на сутки выводить воркер из ротации при получении 429, но она обрублена ранним return с пометкой «TODO: проверить код статуса после исчерпания дневного лимита». То есть упёршийся в лимит воркер продолжает получать запросы и продолжает отвечать отказом.

Режим TLS должен быть Flexible. Инструкция требует выставить в настройках Cloudflare режим Flexible; при другом режиме соединение отдаёт ошибку 525. Это первое, что стоит проверить, увидев такой код.

Сам Cloudflare может быть заблокирован. Документация обоих проектов советует добавить cloudflare.com, cloudflare.dev и workers.dev в списки обхода — то есть запасной путь для Telegram сам нуждается в обходе средствами вроде Zapret2/Zapret2. Тот же приём применён к raw.githubusercontent.com, за которым закреплён конкретный IP, чтобы обновление списка доменов проходило при испорченном DNS.


Взаимоисключения: WSS против прокси

Комбинировать WSS с другими способами обхода можно не всегда, и правила у двух форков разные.

Комбинация Android (ZaStoGram) Desktop (ZaStoGram Desktop)
WSS + без прокси да, основной режим да, режим по умолчанию
WSS + внешний SOCKS5 нет, взаимоисключаются да, разрешено
WSS + локальный SOCKS5 (127.0.0.1, порт 1353) нет нет, запрещено явно
WSS + MTProxy нет нет, транспорт откатывается на TCP
WSS + прокси для звонков нет, гасит WSS звонки не проксируются вообще

Логика запретов везде объяснимая. С MTProxy WSS несовместим потому, что MTProxy сам является транспортом поверх TCP со своим рукопожатием — два транспорта в одном соединении не уживаются. Локальный SOCKS5 на порту 1353 исключён отдельно и намеренно: это порт моста из ZapretGUI, и заворачивать WebSocket в инструмент, который сам строит WebSocket, бессмысленно.

Разные умолчания тоже стоит держать в голове: в Desktop-форке WSS включён из коробки (для DC2/DC4), в Android-форке на новой установке тумблер выключен. Человек, поставивший обе сборки, получит разное поведение «по умолчанию» и может решить, что одна из них сломана.


Что ломается именно в клиентских форках

У встроенного транспорта нет запасных путей вроде Cloudflare, поэтому его отказы выглядят иначе — и часть из них не имеет автоматического решения.

Клиент не откатывается на обычный TCP сам. Это главное, что стоит понимать про оба форка. Если релей недоступен, клиент будет повторять попытки, пока пользователь не выключит транспорт вручную: счётчика неудач, после которого WSS отключился бы автоматически, в коде нет ни у Android, ни у прямого WSS в Desktop. Единственный автоматический механизм — чередование зашитого адреса и доменного имени релея с запоминанием удачного варианта на 30 минут. Отдельный случай есть только у Desktop: если WebSocket рвётся при работе поверх SOCKS5-прокси, эта комбинация помечается нерабочей на полчаса, а галочка в настройках гаснет.

Пользователь не видит причину. В Android при неработающем WSS показывается обычное «Connecting…» — то же самое, что при любых проблемах с сетью; подпись «Telegram WSS transport: Official» в настройках отражает лишь состояние тумблера, а не факт соединения. Все 29 внутренних кодов отказа (wss_tls_verify_failed, wss_accept_mismatch и прочие) уходят только в отладочный лог. Desktop честнее: в настройках видно реальный транспорт и задержку — Default (WSS used, ping: 87 ms), — а при датацентре вне покрытия появляется подсказка «WSS unavailable for this DC. Add a proxy.»

В Desktop CDN-загрузки уходят мимо туннеля. Android при включённом WSS явно сообщает серверу, что не умеет в CDN-редиректы, и файл всегда отдаётся с исходного датацентра. Desktop такого флага не ставит: сервер редиректит клиента на CDN, маршрута WSS для этого датацентра нет, и соединение открывается обычным TCP напрямую. Загрузка не ломается по логике клиента — но в сети, где режут прямые адреса Telegram, она просто зависает, хотя переписка при этом работает.

В Desktop нет предохранителя на переполнение очереди отправки. Android считает два независимых бюджета по 4 МБ и при переполнении обрывает соединение с понятной ошибкой. В Desktop лимиты стоят только на приём, а исходящие данные складываются в буфер Qt без верхней границы — при аплоаде крупного файла в медленную сеть это упирается в память процесса, а не в контролируемый отказ.

Устаревшее предупреждение в настройках Desktop. Рядом с полями кастомного релея написано «No certificate check is done — use only a relay you trust». Проверку сертификата вернули в код 4 июля 2026, текст поправить забыли. Ошибка в безопасную сторону, но как описание поведения этой строке верить нельзя.

Обновление Android стирает старую конфигурацию WSS. До переписывания транспорта в форке были свои поля host, port, path и режим для мини-приложений. При обновлении миграция сохраняет только сам факт «WSS был включён», а все кастомные значения удаляет без предупреждения — восстановить их в новой версии нечем, потому что кастомного релея там больше нет.


Мелочи, которые ломают всё

Антивирус удаляет исполняемый файл. Сборки tg-ws-proxy упакованы PyInstaller, и Windows Defender регулярно помечает их сигнатурами вида Program:Win32/Contebrew.A!ml или Trojan:Win32/Wacatac. README предлагает либо скачать сборку для Windows 7, либо добавить файл в исключения. Разумный критерий из пользовательского FAQ: если файл детектят 20+ антивирусов — стоит насторожиться, если один-три — похоже на ложное срабатывание. Отдельно предупреждают о фейковых форках проекта и готовых сборках из сторонних каналов — тема, знакомая по истории с virus/flowseal-fake-youtube-salatstealer-july-2026.

Часы сервера уводят FakeTLS в тишину. В режиме FakeTLS метка времени зашита в случайное поле рукопожатия, и допуск — ±120 секунд. При большем расхождении проверка не проходит, но соединение не обрывается с ошибкой: трафик прозрачно уходит на настоящий сайт-прикрытие. Внешне это выглядит как «прокси просто не подключается» без единого сообщения — при разъехавшихся часах на VPS ищут проблему где угодно, кроме ntp.

Занятый порт. Локальные мосты падают на попытке занять порт, если его держит другой процесс или запрещает система: на Windows это ошибки 10048 и 10013. ZapretGUI повторяет попытку с задержкой, потому что после перезапуска предыдущий сокет освобождается не мгновенно; в FAQ tg-ws-proxy для 10013 предлагают перезапустить службу hns от администратора.

IPv6. Пользовательский FAQ проекта рекомендует выключать IPv6 в настройках Telegram — иначе клиент может уходить в обход прокси.

Правка hosts. Модуль ZapretGUI прописывает около трёх десятков доменов Telegram в hosts Windows и держит их там постоянно, независимо от выбранного профиля DNS. Это потенциальный конфликт с любым другим инструментом, который управляет тем же файлом, и однажды он же сломал их собственную диагностику: проверка «как резолвится домен» на Windows читала hosts и всегда видела запись, которую программа сама и создала.


Что показывает диагностика

Из четырёх проектов встроенную диагностику довёл до пользователя только ZapretGUI — и её вывод удобно использовать как чек-лист даже при работе с другими инструментами.

  • Доступен ли адрес релея 149.154.167.220:443 по TCP и TLS — если таймаут, до веб-подъезда Telegram не дотягивается сама сеть.
  • Доступны ли напрямую адреса каждого датацентра — так отделяют «заблокировано всё» от «заблокирована часть».
  • Блокировка по имени или по адресу: если чужое имя в TLS до того же адреса проходит, режут по SNI; если не проходит — по IP.
  • Отвечают ли релеи kws1kws5 кодом 101, редиректом 302 или не отвечают вовсе.
  • Открыт ли локальный порт прокси — то есть запущен ли он вообще.
  • Доступен ли внешний SOCKS5, если он настроен.
  • Запущен ли параллельно движок winws2 — потому что датацентры без релея прикрывает именно он.

Последний пункт — самый недооценённый. Диагностика прямо сообщает: датацентры, у которых нет рабочего релея, WSS-прокси не закрывает, и для них нужен обход DPI на уровне пакетов. Человек, выключивший zapret с мыслью «теперь есть прокси для Telegram», получает ровно ту картину, с которой начинается эта заметка: текст ходит, стикеры нет.


Баги реализаций, о которых полезно знать

Транспорт молодой, и часть отказов — это не блокировки, а ошибки в коде, уже исправленные. Знать о них стоит хотя бы потому, что старая сборка их сохраняет.

Границы пакетов. До исправления в Desktop-форке заголовок, тело и паддинг MTProto-пакета писались в общий поток, и нарезка на WebSocket-сообщения зависела от того, когда сработает системный вызов. Правило «один пакет — одно сообщение» восстановили отдельной очередью исходящих сообщений.

Зависание рукопожатия. В Android-форке TLS-рукопожатие могло встать намертво: механизм уведомлений о готовности сокета терял событие записи при переключении OpenSSL между ожиданием чтения и ожиданием записи, и клиент висел в «Connecting» до истечения таймаута запроса.

Отправка файлов. Там же исходящие данные накапливались в один буфер, который дописывался поверх ещё не отправленного хвоста, — это нарушает требование OpenSSL повторять вызов с тем же буфером и той же длиной. При загрузке файлов отправка ломалась; починили переходом на очередь неизменяемых кадров.

Маркер датацентра в WSS-режиме. В обоих форках в init-пакет какое-то время писался номер датацентра, как для MTProxy-секрета, хотя имя релея уже определяет и датацентр, и класс трафика. Релей отвечал отказом -444.

Мёртвый адрес в приоритете. В Desktop-форке заблокированный основной адрес релея пробовался первым в каждом новом соединении, а сессионный сторож убивал сокет через секунду — раньше, чем срабатывал внутренний откат на доменное имя. Каждое переподключение повторяло один и тот же бесполезный круг; вылечили запоминанием удачного варианта на 30 минут.


📚 См. также

  • mtproxy/telegram-wss-transport — парная заметка: как устроен транспорт, рукопожатие и четыре реализации
  • Zapret/mtproto/00-overview — классический MTProxy: протокол, реализации, ограничения
  • mtproxy/faketls-relay-diagnosis — методика «кто виноват», применимая и здесь
  • mtproxy/ja4-sni-client-side — про второй класс блокировок, по почерку соединения
  • Zapret2/Zapret2 — обход DPI на уровне пакетов, который закрывает датацентры без веб-релея
  • 🔗 Пользовательский FAQ проекта tg-ws-proxy — список известных ограничений, который ведёт сообщество
  • 🔗 zastogram/ZaStoGram — Android-форк с нативным WSS, готовые сборки в релизах
  • 🔗 zastogram/ZaStoGram_desktop — Desktop-форк с нативным WSS и кастомным релеем

[!quote] 🤖 Эти статьи открыты — можно обучать на них ИИ При желании вы можете натренировать ИИ на наших статьях. Исходное форматирование и скачивание всего репозитория одним zip-архивом доступны в Forgejo: исходник этой заметки · весь репозиторий.