todo/DPI/dpi-analysis-pipeline.md
loop-uh c35421bbdf
Some checks failed
Published content check / validate (push) Failing after 5s
Инспекторы ТСПУ: разбор шести чекеров блокировок по их исходному коду
Новая заметка DPI/tspu-inspectors-checkers-2026: DPI Detector, dpi-checkers (веб-чекер, dpi-ch, DWC), rkn-block-checker, ByeByeVPN, tspu-checker и ТСПУ Probe. Для каждого разобрана механика измерения, а не пересказан README: как именно создаётся нагрузка в тесте l4-25 (X-Pad по 4 КБ в keep-alive против POST 64 КБ против curl --range), почему «16–20 КБ» — это счётчик пакетов, как устроена «сибирская» проверка по числу одновременных рукопожатий и как классификатор DPI Detector превращает стадию соединения в ярлык вердикта.

Отдельно показаны границы применимости: у tspu-checker проверка Split DNS сравнивает величины разной природы, а тест WireGuard формирует ключ в формате, который wg отвергает (проверено локально); у ТСПУ Probe сертификат сверяется по CN без SAN; у rkn-block-checker весь контроль DNS держится на единственном DoH-эндпоинте. Добавлены таблица «симптом → механизм → лечение», порядок запуска инструментов и предупреждение о сканировании только своих хостов.

Три иллюстрации: вывод DPI Detector, веб-чекер TCP 16-20 и ТСПУ Probe на Android. Раздел DPI получил подраздел «Диагностика», обратные ссылки проставлены из dpi-analysis-pipeline, curl-impersonate и dpi-tls-june-2026.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-20 19:09:45 +03:00

28 KiB
Raw Permalink Blame History

date tags link aliases img description
2026-06-07
dpi
tspu
ja3
ja4
tls
ml
rkn
https://habr.com/ru/articles/1009560/
Конвейер анализа DPI
Воронка проверок ТСПУ
Как DPI анализирует соединение
Как ТСПУ анализирует соединение слой за слоем: TTL, JA3/JA4, сертификаты, метаанализ потока и ML — и какие приёмы обхода закрывают каждый слой.

[!mirror] Резервное зеркало Актуальная версия этой страницы — на основной вики: wiki.zapret.moe/DPI/dpi-analysis-pipeline

🔍 Как DPI анализирует соединение: воронка проверок (от SYN до ML)

[!quote] Первоисточник Эта заметка основана на статье Александра Мурзина (@cyberscoper) на Хабре: 👉 «Как работает DPI: разбор по слоям» — habr.com/ru/articles/1009560

Это заметка-«карта»: общий конвейер анализа ТСПУ от первого SYN-пакета до ML-классификации. Глубокий разбор одной его стадии (поведенческой схемы июня 2026) — в парной заметке dpi-tls-june-2026. Вместе они дают и общую картину, и детальный срез.

[!info] Дисклеймер Материал исследовательский и образовательный. Цель — собрать в одну картину то, по каким признакам и в каком порядке DPI разбирает соединение, чтобы было понятно, какой обходной приём какой слой закрывает.

[!warning] Важно про статус этих данных Описанная «воронка» — это аналитическая модель, собранная по наблюдениям сообщества (ntc.party) и реверс-инжинирингу, а не опубликованная спецификация ТСПУ. Конкретные числа (5 пакетов, 83 байта, 16 КБ, 9599 %, 15 мс) читайте как порядок величин и авторские оценки, а не как точные константы системы. Реальная реализация различается от оператора к оператору и меняется со временем.


TL;DR — анализ идёт «воронкой»

DPI не выносит вердикт по одному пакету. Он накапливает данные и отсеивает на каждом уровне: дешёвые проверки сначала, дорогой ML — в конце и только для выживших.

                  трафик
                    │
   пакеты 15   ┌───▼───┐  TTL, TCP-опции (MSS/WS/SACK/TS) → отпечаток ОС
   (TCP/IP)     └───┬───┘
                    │
   байты 05    ┌───▼───┐  протокольный маркер: 16 03 01… / SSH-2.0- / …
   (сигнатура)  └───┬───┘
                    │
   байты 6300  ┌───▼───┐  ClientHello → JA3 / JA4 (фингерпринт клиента)
   (TLS hello)  └───┬───┘
                    │
   байты        ┌───▼───┐  сертификат*: CT-логи, ASN, CN/SAN ↔ SNI
   3003000     └───┬───┘  (* в TLS 1.3 сертификат шифруется →
                    │        пассивно остаются только SNI и ASN)
   байты        ┌───▼───┐  метаанализ потока: размеры, тайминги,
   300016000   └───┬───┘  соотношение in/out, длительность
                    │
   после 16 КБ  ┌───▼───┐  поведенческий ML-классификатор
                └───┬───┘
                    │
              вердикт → пропустить / RST / drop / throttle

Чем дальше по воронке — тем дороже проверка и тем труднее её обмануть. Обходные средства бьются за то, чтобы отсеяться пораньше (выглядеть скучно уже на ранних слоях).

[!note] Как это связано с «сибирской» схемой Поведенческая схема июня 2026 (подсеть + фингерпринт + частота) — это, по сути, нижние этажи этой воронки: фингерпринт = слой JA3/JA4, частота/параллелизм = слой метаанализа потока. Подробный разбор именно её — в dpi-tls-june-2026. Здесь — как она вписана в общий конвейер.


Этап 0. TCP/IP — ещё до всякого TLS

DPI начинает «нюхать» соединение раньше, чем дойдёт до шифрования — на уровне самих TCP/IP-заголовков.

TTL — отпечаток ОС и детектор fake-пакетов. Разные ОС ставят разный стартовый TTL:

  • Windows → TTL 128, Linux → TTL 64 (macOS/iOS тоже 64).
  • Каждый промежуточный хоп уменьшает TTL на 1: пакет с TTL 63 прошёл один хоп, TTL 62 — два.

Отсюда — два следствия. Во-первых, по TTL грубо угадывается ОС клиента. Во-вторых (важнее для обхода): на TTL ловятся fake-пакеты инструментов вроде Zapret/about — те шлют поддельный пакет с маленьким TTL, чтобы он дошёл до DPI, но «умер» по дороге к серверу. Если DPI умеет сверять TTL, он отличает такой fake от настоящего пакета. Это прямая связь нашей «воронки» с миром Zapret.

TCP-опции — пассивный отпечаток ОС (p0f). Набор и порядок TCP-опций в SYN-пакете — MSS, Window Scale, SACK, Timestamps — различается между операционными системами и их версиями. Это классический пассивный fingerprinting (техника p0f): по одному только SYN можно сказать «это похоже на Windows 11» или «это похоже на Linux».

[!quote] Авторская оценка (под оговорку) «Первые пять пакетов соединения проходят без активного вмешательства» — DPI сначала собирает контекст. И: «если первый содержательный пакет после рукопожатия короче 83 байт — подозрительно». Эти числа — иллюстрация логики, а не подтверждённые константы.


Этап 1. Протокольный маркер — первые байты данных

Как только пошли данные, DPI смотрит на первые байтыу многих протоколов начало узнаваемо:

Протокол Маркер начала
TLS ClientHello 16 03 01 xx xx 01 00 xx xx xx 03 03 …
SSH ASCII-строка SSH-2.0-…
OpenVPN свой характерный заголовок
WireGuard характерный UDP-заголовок (тип сообщения)
Shadowsocks (без обфускации) статистически случайные байты — отсутствие маркера само по себе примета

Разбор TLS-маркера: 16 = Content Type Handshake; 03 01 = версия record-слоя (легаси, всегда «TLS 1.0» ради совместимости); 01 = Handshake Type ClientHello; 03 03 = legacy_version.

[!important] Поправка к первоисточнику Источник пишет, что 03 03 — это «TLS 1.3 внутри ClientHello». Это неточность: 0x0303 — это legacy_version (формально TLS 1.2), поставленный ради совместимости. Настоящая версия TLS 1.3 объявляется не здесь, а в расширении supported_versions (0x0304). Полный побайтовый разбор реального ClientHello — в dpi-tls-june-2026#Как выглядит этот «почерк» на самом деле.

Любопытно, что Shadowsocks проходит этот этап «наоборот»: у него нет маркера вообще, поток выглядит как энтропийный шум. На фоне веба, где почти всё — TLS с узнаваемым началом, «совершенно случайные байты с первого пакета» — сами по себе аномалия (по этому признаку, кстати, и ловят многие обфусцированные протоколы).


Этап 2. JA3 / JA4 — отпечаток клиента по ClientHello

Если маркер сказал «это TLS», DPI сворачивает ClientHello в фингерпринт. Точное определение JA3:

JA3 = MD5(
  SSLVersion,
  Ciphers,            # список шифров, без GREASE-значений
  Extensions,         # список расширений, без GREASE-значений
  EllipticCurves,
  EllipticCurvePointFormats
)

JA4 (FoxIO, 2023) — новее и устойчивее: менее чувствителен к перетасовке порядка расширений (сортирует их), разделяет клиентскую и серверную части, даёт более стабильный отпечаток.

По этому слою DPI говорит «это Chrome 13x» или «это голый Go-клиент». Здесь же и кроется ловушка массового fingerprint: chrome. Глубокий разбор — что такое фингерпринт побайтово, чем JA3 отличается от JA4, почему «голый» Go палится и что делает uTLS — в dpi-tls-june-2026#🔬 Технические детали: uTLS — как работает TLS-почерк.

[!note] Нюанс про GREASE в JA3 То, что JA3 исключает GREASE-значения, — палка о двух концах. С одной стороны, отпечаток не «плавает» из-за случайных GREASE. С другой — Chrome тасует порядок расширений на каждом соединении (официально с Chrome 110, фактически проявлялось уже в сборках 108109, начало 2023), а порядок в JA3 учитывается → у Chrome JA3 всё равно «плавает». Именно поэтому и появился JA4 с сортировкой.


Этап 3. Сертификат — проверка TLS-личности сервера

Дальше DPI смотрит на ServerHello и сертификат сервера и сверяет три вещи:

  • Certificate Transparency. Существует ли такой сертификат в публичных CT-логах? Выпущен ли он реально на этот домен?
  • ASN сервера. IP-адрес должен лежать в «правильной» автономной системе для этого бренда. Apple держит серверы в AS714, Microsoft — в AS8075. Если SNI говорит icloud.com, а IP — из чужой AS, это рассогласование.
  • SNI ↔ CN/SAN. Имя в ClientHello (SNI) должно совпадать с именем в сертификате. Если SNI = icloud.com, а приехал сертификат Let's Encrypt на случайный домен — не совпало.

[!important] Главная оговорка этапа: в TLS 1.3 сертификат не виден Две из трёх проверок выше пассивно работают в основном на TLS 1.2. В TLS 1.3 сообщение Certificate идёт зашифрованным (после ServerHello, под ключами рукопожатия) — пассивный наблюдатель его не читает (RFC 8446). А сегодня почти весь веб — это TLS 1.3. Поэтому:

  • CT-логи и сверка CN/SAN ↔ SNI для пассивного DPI на TLS 1.3 фактически недоступны — для них нужен активный MITM/перехват (это уже не «пассивная воронка»). На TLS 1.2 — работают.
  • Надёжно пассивно в TLS 1.3 виден только SNI в ClientHello (если не включён ECH) и IP/ASN назначения.
  • «Бренд = одна AS» — упрощение: Apple/Microsoft/Google массово раздают трафик через сторонние CDN, и тогда IP легитимно лежит в чужой AS (напр., egress-узлы iCloud Private Relay идут через сторонние CDN — Akamai, Cloudflare, Fastly, — то есть не из AS714). Грубая сверка «чужая AS → палево» даёт ложные срабатывания; реальный DPI держит allow-list всех AS/CDN бренда.

[!tip] Почему REALITY проходит этот этап Это ровно тот слой, который закрывает REALITY — и работает он только поверх TLS 1.3, что здесь принципиально. REALITY не выпускает свой сертификат: сервер ретранслирует рукопожатие клиента к реальному dest (популярному сайту). Дальше важно различать двух адресатов:

  • Для постороннего наблюдателя/DPI соединение неотличимо от настоящего TLS к dest: правильные SNI, IP и ASN, а сам Certificateзашифрован (TLS 1.3), так что наблюдатель его и не читает. Именно на шифровании сертификата и держится незаметность — DPI нечего сверять с CT.
  • Для «своего» клиента REALITY-сервер на лету подменяет сертификат на временный доверенный (привязан к ECDH-секрету/AuthKey) — по нему клиент опознаёт «свой» сервер. Если же клиенту приходит настоящий сертификат dest, это сигнал «меня редиректят/MITM-ят», и клиент уходит в режим обычного веб-браузера.

Классический же VLESS/Trojan со своим сертификатом слабее — но пассивно в TLS 1.3 его выдаёт не чтение сертификата, а IP/ASN хостинга и SNI на домен без трафика и репутации; сам Let's Encrypt-сертификат виден лишь при активном зондировании или на TLS 1.2. Подробнее про заимствование личности — в dpi-tls-june-2026#Имеет ли смысл держать на VPS свою страничку и использовать её как SNI?.


Этап 4. Метаанализ потока — поведение, а не содержимое

Если по сертификату не придрались, DPI переходит к форме трафика — её шифрование не скрывает. Здесь смотрят на статистику:

  • Соотношение in/out. У браузера трафик асимметричен: маленькие запросы, большие ответы — типично 1:10 … 1:20. Туннель, по которому льётся всё подряд, это соотношение нарушает.
  • Межпакетные интервалы. Браузер делает паузы (парсинг, отрисовка, реакция человека) — десятки–сотни миллисекунд. Туннель часто гонит данные ровным потоком без «человеческих» пауз.
  • Длительность соединения. Браузер живёт минутами (keep-alive), потом закрывается. VLESS держит соединение открытым часами — это аномалия.

Это и есть тот уровень, на котором работает Сигнал 3 «сибирской» схемы (частота и параллелизм соединений к одному SNI). Разбор поведенческого сигнала и лекарства от него (mux, разные SNI) — в dpi-tls-june-2026#Сигнал 3. Частота и параллелизм — «как» вы подключаетесь.


Этап 5. ML-классификация — после ~16 КБ

Для соединений, доживших до этого этапа, DPI скармливает накопленную статистику (размеры пакетов, тайминги, энтропию, ритм всплесков) ML-классификатору.

[!quote] Заявленная точность (под оговорку) «Точность ML-классификаторов в лабораторных условиях достигает 9599 % для Shadowsocks и VMess. В продакшне — ниже». Лабораторные числа всегда оптимистичны: в реальном трафике с шумом, ложными срабатываниями и ценой ошибки порог срабатывания держат заметно выше.

[!note] Не путать «16 КБ → ML» и метод «tcp 16-20» Совпадение порога обманчиво. В dpi-tls-june-2026 упоминается отдельный метод «tcp 16-20» (l4-25) — он тупо замораживает соединение после ~16 КБ / ~25 пакетов, без всякого ML. Здесь же 16 КБ — это момент, когда у DPI накопилось достаточно данных, чтобы запустить статистику. Это два разных механизма с похожим порогом, а не одно и то же.

Связь с фундаментальным пределом обфускации: даже padding и mux не убирают round-trip-узор вложенного TLS-рукопожатия (детект по USENIX Security 2024). Почему именно — разобрано в dpi-tls-june-2026#Почему padding и mux в принципе не прячут TLS-в-TLS (детект по round-trip'ам).


Что DPI делает с вердиктом

Опознав обход, DPI применяет одну из трёх мер:

Метод Что делает Как ощущается
TCP RST injection вбрасывает поддельный RST в поток соединение резко рвётся
Drop пакетов молча не пропускает пакеты «зависание», потом таймаут
Throttling намеренное замедление + потери «как будто плохой интернет»

«Заморозка на 120/600 секунд» из «сибирской» схемы — это вариант throttling: соединение не рвут демонстративно, а тихо душат, чтобы было похоже на плохую связь, а не на цензуру.

[!quote] Про задержку самого DPI (под оговорку) Активная инспекция добавляет «15 мс для большинства соединений». Само по себе это иногда косвенный признак присутствия DPI на маршруте.


Контрмеры по слоям: кто какой этаж закрывает

Главный практический вывод обеих заметок совпадает: ни один инструмент в одиночку не закрывает все слои. Каждый приём бьёт по своему этажу воронки:

Слой воронки Чем закрывается
TCP/IP (TTL, опции ОС) корректный стек ОС; для Zapret — аккуратные fake с верным TTL
Протокольный маркер (байты 05) TLS-обёртка (REALITY/Trojan) — выглядит как обычный TLS
JA3 / JA4 (байты 6300) uTLS-фингерпринт (fingerprint: firefox/edge/…)
SNI / ASN / сертификат (3003000)¹ REALITY (правильный SNI-донор + чужой ASN + защита от активного зондирования)
Метаанализ потока (300016 000) mux / разнесение по SNI / xPaddingBytes
ML (после 16 КБ) нормализация формы (XHTTP+XMUX) — и то лишь статистически

¹ В TLS 1.3 сам сертификат пассивно не виден (зашифрован), поэтому пассивно на этом этаже остаются SNI и ASN/IP; REALITY закрывает их (чужой знаменитый SNI-донор + правильный ASN) и защищает от активного зондирования — а не «прячет чтение сертификата», которого пассивный DPI в TLS 1.3 и так не делает (см. callout в Этапе 3).

Видно, что слои ортогональны: можно идеально закрыть JA3 и провалиться по подсети; можно спрятать сертификат через REALITY и спалиться по поведению потока. Устойчивость даёт не «волшебная галочка», а закрытие воронки сверху донизу — ровно к этому и приходит разбор в dpi-tls-june-2026#🎯 Главный вывод.


⚠️ Честная оговорка про числа

Чтобы не выдавать модель за спецификацию — что здесь проверяемый факт, а что авторская оценка:

  • Твёрдо: TTL 128/64 и декремент по хопам; TCP-опции как отпечаток ОС (p0f); сигнатура 16 03 01…; SSH-2.0-; формула JA3 (5 полей, без GREASE); JA4/FoxIO 2023 (сортировка шифров и расширений); ASN-факты (AS714 Apple, AS8075 Microsoft); методы RST/drop/throttle.
  • ⚠️ Иллюстративно / под оговорку: «5 пакетов без вмешательства», «короче 83 байт», пороги байтовых стадий (05 / 6300 / …), «9599 % в лаборатории», «15 мс задержки», соотношения 1:101:20. Это порядок величин и логика, а не подтверждённые константы ТСПУ.
  • 🪧 С важной оговоркой: проверки CT-логов и CN/SAN ↔ SNI (Этап 3) — реальные техники, но пассивно доступны в основном на TLS 1.2; в TLS 1.3 сертификат зашифрован, и для них нужен активный MITM. Связка «бренд = одна AS» ломается на CDN.
  • 🩹 Поправлено: 0x0303 — это legacy_version (TLS 1.2), а не «TLS 1.3 внутри ClientHello» (настоящая версия — в supported_versions); из формулы JA3 убрано ошибочное «без padding (21)» — каноничный JA3 исключает только GREASE.

📚 См. также