MTproxy-reanimation
- title
- MTproxy-reanimation
- type
- toolbox
- summary
- SYN-лимитер в nftables и серверный TCP-десинхрон для MTProto-прокси Telemt с управлением через bash-меню
- tags
- shell, networking, censorship-circumvention, dpi, nftables, telegram, watchlist
- language
- Shell (bash)
- license
- MIT
- created
- 2026-07-29
- updated
- 2026-07-29
- lang
- ru
- translation_of
- mtproxy-reanimation
- source_updated
- 2026-07-29
- translated
- 2026-09-01
- translator
- lllm/antigravity/gemini-3.7-flash-medium
MTproxy-reanimation ("реаниматор") решает одну конкретную проблему: клиенты Telegram не могут завершить первое TCP-соединение с MTProto-прокси. Сам прокси работает; глушится именно рукопожатие. Инструмент представляет собой bash-меню под названием mtpr, которое настраивает правила nftables для обхода этой проблемы, а также выполняет небольшую безопасную оптимизацию Telemt и MTProxyMax. Он не заменяет ни один из них - он работает рядом и управляет правилами на уровне ядра и несколькими параметрами конфигурации.
Установка сама находит прокси: MTProxyMax, Docker-контейнер, юнит systemd или обычный локальный процесс. Скрипт читает конфигурацию Telemt, чтобы найти API-порт ([server.api], по умолчанию 9091), делает резервную копию конфигурации перед любыми изменениями и предлагает восстановиться из неё при удалении. Конфигурации Telemt Panel скрипт намеренно не трогает.
Выбор хука netfilter
Первая неочевидная деталь - выбор хука в зависимости от способа развёртывания. Telemt на хосте или с host networking получает правила в цепочке input. Telemt в сети Docker bridge получает forward, поскольку пакеты маршрутизируются в контейнер, а не доставляются локально. Для bridge есть два варианта: простой режим, который сопоставляет только порт, и точный режим Docker, который сопоставляет внутренний IP контейнера и запускает фоновый сервис (mtpr-bridge-watch.service), отслеживающий смену адреса. В README советуют сначала пробовать точный режим.
SYN-лимитер: Classic и Smart
Изначальный механизм - ограничение частоты входящих SYN-пакетов для каждого источника. Режим Classic использует один счётчик на всех:
tcp dport <PORT>
tcp flags & (syn | ack) == syn
meter { ip saddr timeout 60s limit rate over 1/second burst 1 packets }
counter drop
Ограничение входящих попыток подключения для починки связи кажется парадоксальным, пока не станет понятен его смысл. При помехах клиент Telegram агрессивно повторяет рукопожатия по нескольким возможным путям; принудительное замедление этого потока заставляет его быстрее зафиксироваться на рабочем маршруте, а не метаться без толку. Слабое место режима Classic в том, что он использует drop: клиент, попавший под лимит, ждёт таймаута повторной отправки, и установка соединения растягивается на 10-20 секунд.
Smart By-MEKO, рекомендуемый режим, делит клиентов на две ветки и меняет способ сброса. Клиенты на iOS определяются по TCP SYN fingerprint - прямому сопоставлению смещений в заголовке TCP, проверяющему структуру опций и значения окна вместо эвристик:
@th,108,20 0x2ffff @th,160,16 0x204 @th,192,16 0x103
@th,224,24 0x10108 @th,320,32 0x4020000
iOS получает мягкий лимит (частота 15/сек, burst 30) и TCP reset при его превышении; всё остальное получает строгий лимит (частота 54/мин, burst 1) и по умолчанию reject with icmp type host-unreachable. Обе ветки работают на одном порту. Смысл ICMP вместо drop в том, что явный отказ Telegram воспринимает как быстрый сбой и немедленно пробует другое соединение. Согласно README, это сокращает время подключения до 3-8 секунд и, в частности, убирает долгое зависание при отправке медиафайлов с Android- и Desktop-клиентов. Лимит для любой из веток можно отключить вовсе. Более старый метод фингерпринтинга - ip ttl < 65 AND meta length 64 - остаётся доступным для совместимости.
Подход с фингерпринтами пришёл из MTPROTO-FIX-By-MEKO, которому в README отдают должное как за разделение iOS/Android, так и за идею быстрого сброса.
Режим zapret2: десинхронизацию выполняет сервер
В версии 1.2.0 (июль 2026 года) появился совершенно другой механизм, построенный на модификаторе пакетов nfqws2 из zapret2 со скриптами на Lua. Он не дополняет SYN-лимитер, а заменяет его: включение режима zapret2 автоматически отключает лимитер.
Последовательность шагов, которая полностью выполняется на сервере для его собственных исходящих пакетов:
- SYN+ACK отправляется с
window = 1400, из-за чего клиент вынужден фрагментировать свой первый пакет с данными вместо отправки ClientHello целиком. - Пустые ACK от сервера отправляются с
window = 10, пока клиент не передаст полезную нагрузку, сохраняя ограничение. - Первый пакет данных от клиента - ClientHello Fake-TLS - нарезается на три части. Первая уходит как обычно, третья - тоже как обычно со своим смещением, а средняя - с намеренно повреждённой контрольной суммой.
- Middlebox видит неполный и нарушенный по порядку ClientHello, который не может разобрать, а повреждённый сегмент отбрасывается до того, как пакет соберётся воедино.
- Клиент повторно отправляет среднюю часть, соединение устанавливается, а весь последующий трафик проходит без изменений - он пропускается через
fwmarkвместе с метками conntrack и параметромinstance_cutoffв Lua-скрипте.
Это зеркальное отражение техники из tls-desync-fake-clienthello. Там клиент сбивает с толку DPI, отправляя фальшивый ClientHello с низким TTL перед настоящим; здесь же сервер делает так, чтобы ни один целый ClientHello не прошёл через middlebox в читаемом виде. Цель та же - проверка SNI в системах вроде tspu, но с противоположного конца соединения. Здесь используется та же терминология split/disorder/badsum, что и в семействе zapret, и, в отличие от eBPF-подхода в gecit, на стороне клиента ничего устанавливать не требуется.
Для клиентов на iOS сделано исключение: они определяются по фингерпринту на этапе SYN, помечаются через fwmark = 0x40000 и отправляются через rawsend_dissect_segmented без манипуляций с размером окна, так как игры с окном ухудшают их соединения. В более ранних версиях они просто пропускались (VERDICT_PASS), из-за чего пакеты зацикливались обратно в очередь netfilter.
Таблица nftables состоит из четырёх цепочек, выстроенных так, чтобы уже обработанные пакеты не попадали в очередь повторно:
table ip MTProto {
chain predefrag # output priority -401: fwmark accept + notrack
chain output # route mangle: ct mark set for marked packets
chain postrouting # srcnat+1: ct mark accept + queue
chain prerouting # mangle: ct mark accept + queue
}
Ограничение wscale
Обход работает только в том случае, если анонсируемое окно приёма действительно мало, а TCP window scaling этому мешает. Эффективный размер окна равен win_ACK × 2^wscale, и ядро выбирает wscale исходя из размера буфера приёма. Поэтому сервер, оптимизированный под высокую пропускную способность, в принципе не может анонсировать достаточно маленькое окно:
| wscale | 2^wscale | подходящий win ACK | эффективное окно |
|---|---|---|---|
| 7 | 128 | 10 | 1280 байт |
| 9 | 512 | 2 | 1024 байта |
| 11 | 2048 | - | невозможно |
При wscale ≥ 11 (буфер от 64 МБ) не существует целого числа, дающего значение меньше 1400, и установщик выводит инструкции по уменьшению net.core.rmem_max. Эта проверка запускается при установке и повторно в пункте меню диагностики; её нужно выполнять заново при любом изменении параметров буферов в ядре. Это хороший пример техники обхода, применимость которой зависит от совершенно постороннего параметра sysctl.
Тонкая настройка и остальное меню
Помимо работы с netfilter скрипт управляет тремя таймаутами Telemt - tg_connect 30, client_handshake 90, client_keepalive 120 - и значениями client_mss / client_mss_bulk, которые в README рекомендуют отключать как в режиме Smart, так и в Zapret2, поскольку они решают ту же проблему хуже. Скрипт получает ссылки tg://proxy?... для пользователей через API Telemt с помощью jq, отфильтровывая записи IPv6 и учитывая public_host/public_port. Два старых обходных пути для iOS (параметры sysctl для TCP keepalive; отдельный порт 4443 с MSS=92 и прозрачным редиректом) были перенесены в подменю "legacy settings", так как оба текущих режима сделали их ненужными.
Один совет из README не связан напрямую с самим инструментом, но важен: домен для Fake-TLS обязан поддерживать постквантовый гибридный обмен ключами (X25519MLKEM768), иначе клиенты на iOS не подключатся вовсе. Никакая настройка nftables это не исправит.
Ограничения и нюансы
Репозиторий создан 2026-06-10 и представляет собой bash-скрипт одного автора с 294 звёздами и 5 форками. Он устанавливается через curl | sudo bash, создаёт юниты systemd и меняет правила фаервола на уровне ядра на рабочем сервере - сначала прочитайте скрипт. Всё описанное выше - это изложение из README о работе на серверах самого автора; независимых замеров цифры в 3-8 секунд или зависания при отправке медиа нет. Режим Docker bridge не тестировался с zapret2, согласно примечанию о совместимости в самом README. Кроме того, апстрим развивается: в Telemt 3.4.18+ появились возможности, пересекающиеся с функциями реаниматора, и в README рекомендуется выбрать что-то одно, а не запускать оба решения вместе.
Тег watchlist - см. watchlist. Инструменты для обхода цензуры быстро устаревают, а этот привязан к единственной реализации прокси, которая сама перенимает его возможности.
Клиентская сторона той же проблемы описана в xray-tutorial и happ-proxy; маршрутизация через полученные прокси - в mihomo и wirez.
MIT, ~294★ на 2026-07-29.