Привет, Хабр!
1 апреля MTProxy начал массово ломаться - причём не точечно, а сразу у разных пользователей, провайдеров и даже на зарубежных серверах.
Прокси подключался, но не работал: сообщения не отправлялись, медиа не грузились, соединение зависало на этапе TLS.
Разбор показал неожиданную причину - фильтрацию по TLS fingerprint.
Как это выглядит для пользователя
Типичная жалоба выглядела примерно так:
прокси «подключается», но сообщения не отправляются;
картинки и видео не загружаются;
соединение висит несколько секунд и только потом становится активным;
после сворачивания приложения или переподключения всё может снова отвалиться;
на одном и том же прокси desktop и mobile ведут себя по-разному.
Отдельно интересно, что многие отмечали нестабильность не в виде полного обрыва, а как будто в виде странного «окна допуска»: несколько подключений проходят, потом идут отказы. У кого-то прокси «держится», пока приложение не уходит в фон, у кого-то помогает переключение режима полёта, у кого-то один и тот же сервер то работает, то перестаёт подключаться.
Что видно в логах
Ключевая зацепка - логи.
Во всех случаях повторяется один и тот же паттерн: после TLS ClientHello трафик просто перестаёт приходить.

Это означает, что проблема, скорее всего, возникает не на уровне «прокси не поднялся» и не на уровне «сервер недоступен вообще».
Если бы дело было только в портах, DNS или банальном падении сервера, мы бы видели более простой и более предсказуемый профиль отказа.
Здесь же картина похожа на избирательную фильтрацию именно на этапе установления TLS-сессии.
Коротко: проблема почти точно не в серверах и не в прокси. Она возникает на этапе TLS - ещё до установления соединения.
Как это может работать на практике
Если упростить, у любого TLS-клиента есть довольно узнаваемый отпечаток. Он складывается из порядка cipher suites, списка extensions, supported groups, signature algorithms и других параметров ClientHello. У разных клиентов эти параметры отличаются, и в сумме получается то, что обычно называют TLS fingerprint. В случае Telegram этот отпечаток, судя по наблюдениям, достаточно характерный, чтобы фильтр мог использовать его как один из признаков.
Дальше возможны два шага.
Сравнение самого ClientHello с известными шаблонами.
Анализ того, как соединение ведёт себя дальше. Обычный HTTPS после рукопожатия начинает выглядеть как веб-сессия: сервер отвечает, появляются предсказуемые паттерны обмена данными, запросы и ответы имеют более-менее понятную структуру. У MTProxy через Fake-TLS поведение другое: даже если внешне всё похоже на TLS, дальше идёт совсем не тот профиль трафика, который ожидается от браузера.
Именно поэтому в обсуждении так часто всплывает ощущение, что проблема не в «конкретном прокси», а в том, что сам трафик стал узнаваемым.
Впрочем, вторая версия с чисто поведенческим детектом (без учёта TLS-фингерпринта) выглядит менее убедительно. Косвенно это подтверждается уже появившимися экспериментами в сообществе: один из участников сделал патч Telegram Desktop, минимально изменил параметры ClientHello и пересобрал клиент. В результате EE-прокси снова начали стабильно работать - причём это было проверено на нескольких провайдерах и разных прокси-инстансах.
Такой результат сложно объяснить только анализом поведения трафика: если бы DPI опирался исключительно на паттерны обмена после установления соединения, небольшие изменения в ClientHello не давали бы столь заметного эффекта. Отсюда следует, что TLS-фингерпринт играет ключевую ролей в детекте.
Что происходит на уровне сети
В упрощённом виде это выглядит так:
Клиент открывает TCP соединение
Отправляет ClientHello
DPI анализирует fingerprint + возможно поведение
Если совпало:
— drop пакетов
— или деградация
— или RST
Отдельно стоит сказать про RST, потому что вокруг него много путаницы.
В нормальной ситуации RST отправляет одна из сторон соединения - либо клиент, либо сервер, если сокет неожиданно закрывается или приходит пакет вне ожидаемого состояния.
Но в сценариях с DPI возможна инъекция: фильтр, находясь на пути трафика, формирует поддельный RST-пакет и отправляет его так, как будто он пришёл от одной из сторон. Обычно такие пакеты подделывают IP и порт (совпадающие с реальным соединением), а также sequence number, чтобы стек TCP принял их как валидные и немедленно закрыл соединение.
Косвенно такие RST можно отличить по аномальному TTL (не совпадает с остальными пакетами в сессии), временным рассинхронизациям или появлению RST «слишком рано» - например, сразу после ClientHello, когда сервер физически не успел бы принять решение и ответить.
При этом важно, что по текущим наблюдениям RST используется не всегда: в ряде случаев соединение просто «глохнет» без явного сброса, что указывает на комбинацию техник - где-то фильтр рвёт соединение явно, а где-то просто дропает пакеты, оставляя TCP самому дойти до таймаута.
А что делать?
Если проблема действительно упирается в TLS-фингерпринт, то и практические варианты ограничены не так сильно, как кажется, но каждый из них имеет свои нюансы. Самый очевидный путь - ждать изменений на стороне клиента, например патча от Telegram, который будет менять параметры ClientHello. Эксперименты уже показывают, что даже небольшие изменения здесь дают заметный эффект.
Из более технологичных подходов часто упоминается Encrypted Client Hello, который скрывает часть параметров TLS-рукопожатия. Теоретически это могло бы решить проблему на уровне протокола, но на практике технология пока не получила широкого распространения и в ряде сетей просто блокируется или не проходит из-за несовместимости с инфраструктурой.
Вывод
Ситуация с MTProxy в этот раз - это не столько про «конец подхода», сколько про очередной виток уже идущей гонки. Судя по наблюдениям, ключевым фактором действительно становится узнаваемый TLS-фингерпринт, а значит проблема во многом лежит на уровне конкретной реализации клиента, а не всей схемы целиком.
При этом важно, что решение здесь не выглядит фундаментально сложным. Эксперименты с изменением ClientHello уже показывают, что даже небольшие правки способны вернуть стабильную работу. Это означает, что текущий детект, скорее всего, опирается на относительно простые сигнатуры, а не на сложный поведенческий анализ всего трафика.
На практике это сводит ситуацию к привычной модели: сигнатура появляется -> её меняют -> детект адаптируется. И хотя более продвинутые решения вроде Reality изначально лучше маскируются под нормальный HTTPS, в случае MTProxy речь, судя по всему, пока идёт не о необходимости полной смены подхода, а о доработке клиента и обновлении его сетевого «отпечатка». Это не блокировка MTProxy как технологии, а блокировка конкретной реализации клиента TLS.
UPD: Похоже, что помимо общего TLS-фингерпринта есть и более приземлённая причина, упрощающая детект.
В коде генерации encrypted_client_hello у Telegram обнаружили ошибку, из-за которой формируется нетипичное расширение (неверный ID и некорректная длина). В итоге ClientHello получается с довольно характерным паттерном, который легко матчится ТСПУ.
При этом исправление, с которым EE-прокси работают исправно, уже подготовлено и интегрировано в сборки Telegram Desktop, однако в официальный репозиторий tdesktop соответствующий PR момент написания ещё не смерджен.
Если правка дойдёт до релизной версии клиента, есть шанс, что значительная часть текущих проблем уйдёт без дополнительных обходов.