syndata --- payload в TCP SYN (zapret2 / nfqws2)
Коротко и по-простому
Когда браузер открывает сайт по HTTPS, первым сообщением с данными он отправляет TLS ClientHello («привет от клиента»). В нём браузер перечисляет, какое шифрование умеет, и открытым текстом называет нужный сайт: имя лежит в поле SNI (Server Name Indication, «указание имени сервера»). У обычного HTTP без шифрования то же имя стоит в строке Host: запроса. ТСПУ (Технические средства противодействия угрозам — оборудование DPI, то есть глубокой инспекции трафика, которое стоит у провайдера) ищет это имя в первом пакете соединения с данными и по нему решает, что делать с соединением дальше.
Но ClientHello уходит не первым. Перед данными TCP устраивает «рукопожатие» (handshake) из трёх пакетов. Первый, SYN, клиент отправляет, чтобы попросить о соединении: в обычном виде в нём нет данных, только заголовки с флагом SYN. Сервер отвечает пакетом SYN-ACK, клиент подтверждает его пакетом ACK, и только после этого браузер отправляет ClientHello. Имени сайта в SYN нет, поэтому на этом этапе его не знает и сам Zapret: чем это грозит хостлистам, описано в разделе Работа с хостлистами.
Рукопожатие как звонок
SYN — «Алло, можем говорить?», SYN-ACK — «Да, говори», ACK — «Ок». Если начать рассказывать своё дело ещё до ответа «Да, говори», собеседник, скорее всего, пропустит эти слова мимо ушей. Примерно так обычно ведёт себя и сервер с данными, которые пришли в SYN.
Дальше данные идут кусками — сегментами. У каждого байта в соединении есть порядковый номер (sequence number, коротко seq), и сервер раскладывает принятые куски в свой буфер по этим номерам; почему это гарантирует именно TCP, разобрано в нюансе «Работает только с TCP» в статье про multisplit. Фейк — это пакет-обманка с ложными данными, например с поддельным ClientHello. Обычно фейк «портят»: искажают его заголовки так, чтобы сервер пакет отбросил, а DPI прочитал. Такая порча называется fooling, подробно — в разделе Что такое fooling. У syndata с fooling своя особенность: портить приходится пакет, который сервер обязан принять (см. нюанс 2).
syndata — функция «нулевой фазы»: она работает до рукопожатия, на самом первом пакете соединения. Движок Zapret 2 (nfqws2) перехватывает исходящий SYN, а syndata делает четыре шага. Сначала копирует перехваченный SYN, сам оригинал при этом не трогая. Потом дописывает к копии данные из blob — заготовленного куска данных с именем, например стандартного TLS-фейка fake_default_tls (про блобы — Блобы); если blob не указан, берутся 16 нулевых байт. Затем при желании портит копию по правилам fooling и правит TLS-поля через tls_mod, например заменяет SNI в фейке. И наконец отправляет копию вместо оригинала, а оригинал выбрасывает. Как только по соединению приходит пакет без флага SYN, то есть рукопожатие прошло, syndata отключает себя для этого соединения.
Формально TCP разрешает данные в SYN (RFC 793), но большинство TCP-стеков завершают рукопожатие ответом SYN-ACK и данные из SYN игнорируют: соединение ещё не установлено, и payload отбрасывается. Настоящий ClientHello браузер отправит после рукопожатия обычным порядком, и сервер прочитает именно его. DPI может повести себя иначе: принять содержимое SYN за начало потока данных, записать ложные сведения о соединении (например, фейковое имя сайта) и пропустить настоящие данные, не проверив имя в них. Это «может»: как поведёт себя конкретная система, зависит от её устройства.
Команда из быстрого старта syndata:blob=fake_default_tls приклеивает к первому пакету соединения (SYN) фейковый ClientHello с именем www.w3.org. Его байты приходятся на те же позиции потока, что и будущий настоящий ClientHello. Большинство TCP-стеков отвечают SYN-ACK и данные из SYN не принимают, а ТСПУ может счесть их началом потока и не проверить имя в настоящем ClientHello, который уходит после рукопожатия. Как читать схему: строки — пакеты в порядке отправки, подписанные в тех же обозначениях, что и таблицы в этой статье; по горизонтали — место данных в TCP-потоке (номер последовательности, seq); в колонке справа — что сделал с пакетом сервер; внизу — буфер сервера, в который принятые куски встают по своим seq.
Самая короткая команда включает syndata без аргументов: в SYN уходят 16 нулевых байт. Строку --lua-desync=… пишут в профиль — набор правил Zapret 2 для определённого трафика:
--lua-desync=syndataВариант со схемы, syndata:blob=fake_default_tls, кладёт в SYN TLS-фейк. Остальные готовые команды собраны в разделах Быстрый старт и Практические примеры.
Функцию стоит пробовать, если DPI начинает следить за соединением уже с SYN и не реагирует на фейки после рукопожатия, а также когда нужно «отравить» DPI ложными данными до того, как пойдёт реальный трафик. Ограничения у неё такие. Данные в SYN должны поместиться в один пакет: разрезать их на TCP-сегменты на этом этапе нельзя (нюанс 1). Fooling здесь бьёт по SYN, который сервер должен принять, поэтому часть параметров, например badsum или tcp_seq, ломает рукопожатие. Хостлисты напрямую не работают: имени сайта ещё нет, и остаётся только --ipcache-hostname, а первое соединение к каждому IP пройдёт без syndata (Работа с хостлистами). Ту же нулевую фазу использует wssize, который управляет размером окна TCP (сколько байт получатель готов принять) и заставляет сервер слать маленькие сегменты; почему из-за нулевой фазы --wssize считается крайней мерой, объяснено в отдельной заметке.
Ближайший сосед syndata — fake. Он тоже подсовывает DPI ложные данные, но отдельным пакетом уже после рукопожатия, оригинал при этом уходит дальше, а fooling нужен, чтобы сервер фейк отбросил. syndata кладёт данные в сам SYN и заменяет им оригинал. Все различия сведены в таблицу в разделе Отличия от fake, а с точки зрения fake — в Сравнение с syndata и fakedsplit. С техниками сегментации syndata обычно стоит в одной цепочке: он занимается SYN, а multisplit режет настоящий ClientHello уже после рукопожатия (см. Комбинирование с другими функциями). Остальные функции, которые работают с данными после рукопожатия, — multidisorder, fakedsplit и fakeddisorder. Рабочую комбинацию для своего провайдера подбирают и проверяют по чек-листу честной проверки.
Оглавление
- Коротко и по-простому
- Справка: где функция в коде и родственники
- Зачем нужен syndata
- Быстрый старт
- Принцип работы
- Полный список аргументов
- tls_mod --- модификация TLS в syndata
- Место в общем скелете
- Псевдокод алгоритма
- Отличия от fake
- Работа с хостлистами
- Комбинирование с другими функциями
- Нюансы и подводные камни
- Миграция с nfqws1
- Практические примеры
- 📚 См. также
Справка: где функция в коде и родственники
Паспорт функции для тех, кто сверяется с исходниками zapret2: в каком файле и на какой строке лежит код, какой ключ первой версии zapret она заменяет и как объявлена.
Файл: lua/zapret-antidpi.lua:395
nfqws1 эквивалент: --dpi-desync=syndata
Сигнатура: function syndata(ctx, desync)
syndata --- стратегия “нулевой фазы” в zapret2. Она добавляет произвольный payload в TCP SYN-пакет, применяет модификации (fooling, tls_mod) и отправляет его вместо оригинального SYN. Оригинальный пакет дропается (VERDICT_DROP). Работает до установления TCP-соединения --- на этапе, когда клиент ещё только отправляет SYN.
Родственные/сопутствующие функции: fake (фейковый пакет после SYN), multisplit (TCP-сегментация), wssize (управление размером окна), multidisorder, fakedsplit, fakeddisorder.
Общий для всех техник дурения порядок работы — восемь стадий от отсева чужого транспорта до вердикта — разобран в жизненный цикл desync-функции; здесь описано только то, чем syndata от этого скелета отличается.
Проще говоря
«Нулевая фаза» — этап до завершения рукопожатия, когда у приложения ещё нет данных для отправки; подробнее в разделе Нулевая фаза. Fooling — намеренная порча заголовков пакета, разобранная в Что такое fooling.
VERDICT_DROP— решение «перехваченный пакет не отправлять»: вместо оригинала уходит подделанная копия; как движок складывает такие решения от разных функций, описано в стадии 8 жизненного цикла. Блоб (blob) — заранее заготовленные данные, которые можно подсунуть в пакет; см. Блобы.
Зачем нужен syndata
Некоторые DPI начинают анализировать соединение уже с первого пакета --- с SYN. Они запоминают IP и порт клиента, ждут данные и сопоставляют их с сигнатурами. syndata атакует этот механизм на самом раннем этапе:
- Ложные данные в SYN: DPI видит SYN-пакет с payload (например, фейковый TLS ClientHello) и может принять его за начало реального соединения
- Сбой трекинга: если DPI привязывает сессию к содержимому первого пакета, подменный SYN может направить трекинг по ложному пути
- Обход до handshake: воздействие происходит до TCP handshake --- DPI ещё не видел реальных данных приложения
Важно: TCP SYN с payload --- это валидная TCP-операция (RFC 793 разрешает данные в SYN, хотя многие стеки их игнорируют до завершения handshake). Сервер примет SYN, но payload из него обычно отбросит --- DPI же может попытаться его проанализировать.
Проще говоря
Трекинг — слежение DPI за соединением: он запоминает IP и порт клиента, ждёт данные и сопоставляет их с сигнатурами, то есть заранее известными строками.
syndataподсовывает ему данные раньше настоящих, ещё в SYN. Сервер их обычно не читает: разговор для него ещё не начался. Что такое рукопожатие (handshake) и почему данные в SYN обычно игнорируются, объяснено в начале статьи, в разделе Коротко и по-простому. Слова «может» и «обычно» в тексте выше не случайны: как поведёт себя конкретный DPI или конкретный сервер, зависит от их устройства.
Быстрый старт
Минимально (16 нулевых байт в SYN):
--lua-desync=syndataС TLS-фейком:
--lua-desync=syndata:blob=fake_default_tlsС TLS-фейком и модификацией SNI:
--lua-desync=syndata:blob=fake_default_tls:tls_mod=rnd,rndsniТиповая комбинация (wssize + syndata + multisplit):
--lua-desync=wssize:wsize=1:scale=6 \
--lua-desync=syndata \
--lua-desync=multisplit:pos=midsldЧетыре блока идут от простого к сложному: без аргументов, с TLS-фейком, с TLS-фейком и модификацией SNI и, наконец, цепочка из трёх функций. Аргументы blob и tls_mod разобраны в разделе A) Собственные аргументы syndata. Цепочка описана в разделе Типовая цепочка: wssize + syndata + multisplit, там же объяснено, почему wssize стоит первым. Строки --lua-desync=… пишут в профиль; порядок вызовов в цепочке важен, подробнее в последовательность аргументов.
Принцип работы
Что такое SYN с payload
Обычный TCP SYN-пакет не содержит данных --- только заголовки с флагом SYN. syndata берёт этот пакет, добавляет в него payload (указанный в blob или 16 нулевых байт по умолчанию), применяет модификации и отправляет через raw socket вместо оригинала.
Обычный SYN:
[IP Header][TCP Header (SYN)]
SYN после syndata:
[IP Header][TCP Header (SYN)][PAYLOAD (blob или 16x 0x00)]
Сервер получит SYN с данными. Большинство TCP-стеков:
- Завершат handshake (SYN-ACK), проигнорировав payload в SYN
- Payload будет отброшен, потому что соединение ещё не установлено
DPI же может:
- Проанализировать payload из SYN как начало потока данных
- Записать ложную информацию о соединении (фейковый SNI, фейковый HTTP Host)
- Пропустить реальные данные, которые пойдут позже
Проще говоря
Payload — полезные данные пакета без сетевых заголовков. Обычный SYN — «конверт» без письма;
syndataвкладывает в конверт письмо (содержимоеblobили 16 нулей) и отправляет через raw socket, то есть сырым пакетом помимо очереди перехваченных пакетов; способы отправки разобраны в разделе Четыре способа выпустить пакет. Сервер это письмо обычно не прочтёт, а DPI может прочесть.
Нулевая фаза
syndata --- стратегия нулевой фазы. В терминологии zapret это означает:
| Фаза | Когда | Что доступно | Примеры функций |
|---|---|---|---|
| Фаза 0 (SYN) | До TCP handshake | Только SYN-пакет. Нет payload от приложения | syndata, wssize |
| Фаза 1 (данные) | После handshake, первые данные | Реальный payload (TLS ClientHello, HTTP request и т.д.) | fake, multisplit, fakedsplit |
Фаза здесь — этап жизни соединения. В фазе 0 идёт только рукопожатие, и у приложения ещё нет данных. В фазе 1 первые данные уже отправлены, и Zapret видит настоящий ClientHello или HTTP-запрос. Функции фазы 1 (fake, multisplit, fakedsplit) работают с этими данными, а функции фазы 0 их ещё не видят. К фазе 0 относится и wssize.
Следствия нулевой фазы:
- Нет реального payload: приложение ещё ничего не отправило, поэтому syndata работает только с blob-данными или нулями
- Нет hostname: на этом этапе zapret не знает, к какому домену обращается клиент --- хостлисты работают только через
--ipcache-hostname - Нет payload filter: параметры
--payload=...иpayload=...не применимы --- SYN-пакет не содержит данных приложения - Воздействие на все ретрансмиссии SYN: если TCP-стек ретранслирует SYN (timeout), syndata обработает и его
Проще говоря
Пока идёт рукопожатие, Zapret не знает, какой сайт открывает клиент: имя появится только в ClientHello или в HTTP-запросе. Отсюда следствия. Нечего сверять с хостлистом по имени: остаётся кеш
--ipcache-hostname, см. Работа с хостлистами. Нечего фильтровать по типу данных: фильтрpayload(см. payload) для SYN не применим. Ретрансмиссия — повторная отправка SYN, если первый не дошёл или ответ потерялся;syndataобработает и её, подробнее в нюансе 4. Все ретрансмиссии SYN обрабатываются.
Логика обработки пакетов
Пакет пришёл в syndata
|
+-- Не TCP? --> instance_cutoff (кроме ICMP)
|
+-- TCP:
|
+-- Флаг SYN (не SYN+ACK)? --> deepcopy dis, добавить payload,
| apply_fooling, tls_mod,
| rawsend + VERDICT_DROP
|
+-- Не SYN? --> instance_cutoff (миссия завершена)
Ключевые моменты:
- Проверяется именно
TH_SYNбезTH_ACK--- то есть только исходящий SYN от клиента, не SYN+ACK от сервера deepcopy--- работа ведётся с копией dissect, оригинал не модифицируется- Если пакет не SYN (например, ACK, PSH+ACK) --- это значит, что handshake уже прошёл, и syndata отключает себя (
instance_cutoff) - Для ICMP cutoff не выполняется --- ICMP может быть связан с SYN (например, ICMP Destination Unreachable)
Проще говоря
Dissect (диссект) — пакет, разобранный движком на поля: заголовки, флаги, данные; устройство этой таблицы описано в заметке структура desync и диссекта.
deepcopy— полная копия такой таблицы: правки идут в копию, а оригинал остаётся нетронутым.instance_cutoff— «этот вызов функции больше не нужен для данного соединения»: после него движок перестаёт вызыватьsyndataдля потока, см. стадию 1 жизненного цикла.VERDICT_DROP— «оригинальный пакет не отправлять». Логика в целом такая: пришёл исходящий SYN, значит подменяем его; пришёл любой другой TCP-пакет, значит рукопожатие уже прошло и функция отключается; ICMP-пакет сигналом к отключению не считается.
Полный список аргументов
Формат вызова:
--lua-desync=syndata[:arg1[=val1][:arg2[=val2]]...]
Все val приходят в Lua как строки. Если =val не указан, значение = пустая строка "" (в Lua это truthy), поэтому флаги пишутся просто как :tcp_md5, :badsum, :ipfrag.
Важно: syndata не поддерживает стандартные аргументы direction, payload (фильтр) и ipid. Это связано с тем, что syndata работает на фазе 0 (SYN), где нет данных приложения, нет понятия “payload type”, и apply_ip_id не вызывается.
Проще говоря
direction— фильтр «какое направление пакетов обрабатывать»,payload— фильтр по типу данных,ipid— управление полем IP ID в заголовке пакета. В SYN нет ни данных приложения, ни выбора направления, поэтому этих аргументов уsyndataнет; причины разобраны в нюансе 3. Нет direction, payload filter, ipid. Стандартные блоки B–E ниже общие для многих функций; их описание для другой функции можно сверить, например, с разделом Полный список аргументов статьи про fake.
A) Собственные аргументы syndata
blob
- Формат:
blob=<blobName> - Тип: имя blob-переменной
- По умолчанию: 16 нулевых байт (
\x00x 16) - Описание: Payload, который будет добавлен в SYN-пакет. Должен помещаться в один пакет --- сегментация невозможна (используется
rawsend_dissect_ipfrag, а неrawsend_payload_segmented). Если blob не задан, отправляются 16 нулевых байт - Примеры:
blob=fake_default_tls--- стандартный TLS-фейк из zapretblob=fake_default_http--- стандартный HTTP-фейкblob=0xDEADBEEF--- inline hexblob=my_custom_payload--- предзагруженный blob- без
blob=--- 16 нулей (дефолт)
Проще говоря
Blob — заранее заготовленный кусок данных с именем. Какие бывают стандартные и как объявить свой, объяснено в заметке Блобы и в разделе blob — источник фейковых данных статьи про fake. Inline hex — байты, записанные прямо в команде (
0xDEADBEEF), без отдельного файла. Сегментация — разрезание данных на несколько TCP-пакетов, как в multisplit; на этапе SYN она невозможна, поэтому весь blob должен уйти одним пакетом (нюанс 1).
tls_mod
- Формат:
tls_mod=<mod1[,mod2,...]> - Тип: строка со списком модификаций через запятую
- По умолчанию: не задан
- Описание: Модификации TLS-данных в payload перед отправкой. Применяется после
apply_fooling. Подробности --- в разделе tls_mod - Работающие значения:
rnd,rndsni,sni=<str>(включаяsni=%var) - Молча игнорируемые:
dupsid,padencap - Примеры:
tls_mod=rnd--- рандомизация TLS-полейtls_mod=rndsni--- рандомизация SNItls_mod=sni=google.com--- замена SNItls_mod=rnd,rndsni,sni=google.com--- комбинацияtls_mod=dupsid--- не даст ошибки, но молча проигнорируется
Проще говоря
tls_modправит поля TLS-фейка перед отправкой: например, подменяет имя сайта (SNI) или заменяет случайные значенияsession_idиrandom. Работает только часть значений, и почему именно эта, объяснено в разделе tls_mod --- модификация TLS в syndata. Какtls_modустроен вfake, где настоящий ClientHello уже есть, описано в разделах tls_mod — модификации TLS в фейке и Опции tls_mod.
B) Standard fooling
Модификации L3/L4 заголовков. В syndata применяются к копии dissect (через apply_fooling после deepcopy). Оригинальный пакет не модифицируется --- он дропается.
Проще говоря
Fooling — «порча» заголовков пакета (TTL, флагов, номеров seq и ack, контрольной суммы), из-за которой пакет либо не доходит до сервера, либо сервер его отбрасывает; идея разобрана в Что такое fooling, а способы — в каталоге способов. L3 и L4 в названии — это заголовки IP и TCP. Параметры
ip_*иip6_*относятся к IPv4 и IPv6,tcp_*— к TCP. TTL (у IPv6 Hop Limit) — предельное число хопов, то есть маршрутизаторов на пути, после которого пакет пропадает.
| Параметр | Описание | Пример |
|---|---|---|
ip_ttl=N | Установить IPv4 TTL | ip_ttl=6 |
ip6_ttl=N | Установить IPv6 Hop Limit | ip6_ttl=6 |
ip_autottl=delta,min-max | Автоматический TTL (delta от серверного TTL) | ip_autottl=-2,40-64 |
ip6_autottl=delta,min-max | Аналогично для IPv6 | ip6_autottl=-2,40-64 |
ip6_hopbyhop[=HEX] | Вставить extension header hop-by-hop (по умолчанию 6 нулей) | ip6_hopbyhop |
ip6_hopbyhop2[=HEX] | Второй hop-by-hop header | ip6_hopbyhop2 |
ip6_destopt[=HEX] | Destination options header | ip6_destopt |
ip6_destopt2[=HEX] | Второй destination options | ip6_destopt2 |
ip6_routing[=HEX] | Routing header | ip6_routing |
ip6_ah[=HEX] | Authentication header | ip6_ah |
tcp_seq=N | Сместить TCP sequence (+ или -) | tcp_seq=-10000 |
tcp_ack=N | Сместить TCP ack (+ или -) | tcp_ack=-66000 |
tcp_ts=N | Сместить TCP timestamp | tcp_ts=-100 |
tcp_md5[=HEX] | Добавить TCP MD5 option (16 байт; по умолчанию случайные) | tcp_md5 |
tcp_flags_set=LIST | Установить TCP-флаги | tcp_flags_set=FIN,PUSH |
tcp_flags_unset=LIST | Снять TCP-флаги | tcp_flags_unset=ACK |
tcp_ts_up | Поднять TCP timestamp option в начало заголовка | tcp_ts_up |
tcp_nop_del | Удалить все TCP NOP опции | tcp_nop_del |
fool=<func> | Кастомная Lua-функция fooling | fool=my_fooler |
Заметка: fooling в syndata имеет иной смысл, чем в fake или fakedsplit. В fake fooling нужен, чтобы сервер отбросил фейк. В syndata fooling модифицирует сам SYN-пакет, который сервер должен принять для установления соединения. Поэтому деструктивные fooling-параметры (tcp_seq, tcp_ack, badsum) сломают handshake --- сервер не получит валидный SYN. Безопасные варианты: ip_ttl/ip6_ttl (если TTL хватит до DPI, но не до сервера --- спорно для SYN), tcp_md5 (сервер без MD5 проигнорирует опцию), IPv6 extension headers.
Проще говоря
В
fakeпорча нужна, чтобы сервер выбросил фейк. Вsyndataпакет один, и он же должен дойти до сервера: это SYN, без которого не будет рукопожатия. Поэтому портить его приходится осторожно. Параметрыtcp_seq,tcp_ackиbadsumлишают сервер валидного SYN, аtcp_md5и IPv6 extension headers (дополнительные заголовки IPv6) в тексте выше названы безопасными. Проip_ttlв заметке сказано «спорно для SYN», см. пример С TTL fooling (осторожно!). Подробнее — в нюансе 2. Fooling может сломать handshake.
C) Standard reconstruct
| Параметр | Описание |
|---|---|
badsum | Испортить L4 (TCP) checksum при реконструкции raw-пакета. Сервер отбросит такой пакет |
Предупреждение: badsum в syndata означает, что сервер не получит SYN вообще --- TCP handshake не состоится. Используйте только если хотите отправить “мусорный” SYN, за которым пойдёт ретрансмиссия.
Проще говоря
Reconstruct — сборка сырого пакета заново из полей перед отправкой.
badsumпортит контрольную сумму (checksum) TCP, по которой получатель проверяет пакет; с неверной суммой пакет отбрасывается, и сервер SYN просто не увидит. Про повторную отправку SYN — нюанс 4. Все ретрансмиссии SYN обрабатываются.
D) Standard rawsend
| Параметр | Описание |
|---|---|
repeats=N | Отправить пакет N раз (идентичные повторы) |
ifout=<iface> | Интерфейс для отправки (по умолчанию определяется автоматически) |
fwmark=N | Firewall mark (только Linux, nftables/iptables) |
Rawsend — этап отправки готового пакета в сеть (см. Четыре способа выпустить пакет). repeats отправляет копии подряд (пример — Отладка: повторы отправки), ifout выбирает сетевой интерфейс, fwmark ставит метку пакета для фаервола Linux.
E) Standard ipfrag
IP-фрагментация SYN-пакета. Каждый отправляемый SYN+payload фрагментируется на уровне IP.
| Параметр | Описание | По умолчанию |
|---|---|---|
ipfrag[=func] | Включить IP-фрагментацию. Если без значения --- ipfrag2 | --- |
ipfrag_disorder | Отправить IP-фрагменты в обратном порядке | --- |
ipfrag_pos_tcp=N | Позиция фрагментации TCP (кратно 8) | 32 |
ipfrag_pos_udp=N | Позиция фрагментации UDP (кратно 8). Для syndata бесполезно --- он только TCP | 8 |
ipfrag_next=N | IPv6: next protocol во 2-м фрагменте (penetration атака на фаерволы) | --- |
IP-фрагментация — разбиение одного IP-пакета на несколько частей (фрагментов); получатель склеивает их обратно, а DPI, который фрагменты не собирает, не увидит пакет целиком. Это другой уровень, чем TCP-сегментация в multisplit: режется IP-пакет, а не поток данных TCP. Для syndata доступна только она, TCP-сегментации нет (нюанс 1). Примеры: С IP-фрагментацией и С IP-фрагментацией (кастомная позиция); те же параметры для fake — в разделе F) Standard ipfrag.
tls_mod --- модификация TLS в syndata
tls_mod позволяет модифицировать TLS-данные внутри payload перед отправкой. Вызывается после apply_fooling:
if desync.arg.tls_mod then
dis.payload = tls_mod_shim(desync, dis.payload, desync.arg.tls_mod, nil)
endЧетвёртый аргумент --- nil (реальный payload от приложения). Это ключевой момент, определяющий какие модификации работают, а какие --- нет.
Проще говоря
Вызов
tls_mod_shimполучает четвёртым аргументом «настоящие данные клиента». Вsyndataих нет: клиент ещё ничего не отправил, поэтому передаётсяnil, то есть «ничего». Модификации, которые только правят поля самого blob (случайные значения, имя сайта), работают. Модификации, которым нужен настоящий ClientHello, пропускаются. Как то же устроено вfake, где настоящий ClientHello есть, описано в разделе Когда tls_mod применяется, а когда нет.
Работающие модификации
| Мод | Описание | Работает? | Причина |
|---|---|---|---|
rnd | Рандомизация TLS-полей (session_id, random) | Да | Код находится вне блока if(payload) |
rndsni | Рандомизация SNI (замена на случайные символы) | Да | Код находится вне блока if(payload) |
sni=<str> | Замена SNI на указанную строку. Поддерживает sni=%var | Да | Код находится вне блока if(payload) |
Пример: если blob содержит TLS ClientHello с SNI www.example.com, а вы указали tls_mod=sni=google.com, в отправленном SYN-пакете SNI будет заменён на google.com.
dupsid и padencap --- молчаливое игнорирование
| Мод | Описание | Работает? | Причина |
|---|---|---|---|
dupsid | Дублирование session_id из реального ClientHello | Молча игнорируется | Требует реальный payload (4-й аргумент != NULL) |
padencap | Упаковка в padding extension | Молча игнорируется | Требует реальный payload (4-й аргумент != NULL) |
Поведение при использовании dupsid/padencap:
| Аспект | Результат |
|---|---|
| Вызывают ошибку? | НЕТ |
| Выводят warning в лог? | НЕТ |
| Возвращают false? | НЕТ (возвращают true = “успех”) |
| Применяются? | НЕТ --- код просто пропускается |
Проще говоря: dupsid копирует идентификатор сессии (session_id) из настоящего ClientHello клиента в фейк, а padencap упаковывает настоящие данные в расширение padding. Если написать tls_mod=dupsid, ничего не сломается и ничего не произойдёт: ни ошибки, ни предупреждения, функция просто сделает вид, что всё выполнила.
Почему dupsid и padencap не работают
В C-коде (protocol.c) логика dupsid и padencap находится внутри блока if (payload):
// protocol.c
if (payload) // <-- syndata передаёт NULL сюда
{
if (tls_mod->mod & FAKE_TLS_MOD_DUP_SID)
// ... копирование session_id из реального ClientHello
// этот код НЕ выполнится
if (tls_mod->mod & FAKE_TLS_MOD_PADENCAP)
// ... упаковка реального payload в padding
// и этот тоже
}
return bRes; // возвращает true --- "всё ОК"Причина: dupsid копирует session_id из реального ClientHello клиента в фейк. На фазе SYN реального ClientHello ещё не существует (клиент его не отправлял). Аналогично padencap упаковывает реальный payload в padding extension --- на фазе SYN упаковывать нечего.
Это дизайн-решение, а не баг. Но отсутствие warning в логе может ввести в заблуждение --- конфигурация с tls_mod=dupsid будет молча работать “без dupsid”.
Проще говоря
В коде выше
if (payload)значит «если есть настоящие данные».syndataпередаёт тудаNULL, то есть данных нет, и весь блок пропускается, а функция всё равно возвращаетtrue, «успех». Поэтому предупреждения в логе нет. Хотите использоватьdupsidилиpadencap— берите fake, где настоящий ClientHello есть.
Место в общем скелете
Тело syndata построено по тому же шаблону, что и все остальные функции дурения: восемь стадий от отсева чужого транспорта до вердикта. Разобраны они один раз в жизненный цикл desync-функции — здесь только отклонения:
| Стадия общего скелета | Что делает syndata |
|---|---|
| 1. Отсев транспорта | нужен TCP и именно SYN без ACK; после прохождения фазы рукопожатия делает instance_cutoff с пометкой «mission complete» |
| 2. Направление | отклонение: аргумента dir нет вообще — SYN по определению исходящий |
| 3. Аргументы | обязательных нет: без blob подставляются 16 нулевых байт |
| 4. Данные | отклонение: цепочка blob → reasm → payload не используется, берётся только blob |
| 5. Гварды | отклонение: штатных гвардов нет, единственный фильтр — флаги TCP |
| 6. replay | не используется: SYN всегда одиночный пакет |
| 7. Своя техника | подставить payload в SYN, применить fooling и tls_mod, отправить rawsend_dissect_ipfrag |
| 8. Вердикт | VERDICT_DROP при успешной отправке — оригинальный SYN заменяется подделанным |
Отклонений здесь много именно потому, что syndata работает до появления прикладных данных. Отсюда же ограничение, о котором легко забыть: payload должен помещаться в один пакет — сегментации на этапе SYN не существует.
Проще говоря
Расшифровка терминов из таблицы. Гвард — проверка в начале функции, которая отсеивает ненужные пакеты: у большинства функций это проверки размера данных, направления и типа payload (Стадия 5). Reasm — данные, которые движок собрал из нескольких пакетов, придержав их (Стадия 4). Replay — повторный прогон собранных данных через desync-функции (Стадия 6). Вердикт — решение, что делать с перехваченным пакетом (Стадия 8). У SYN нет ни собранных данных, ни повторного прогона: он всегда одиночный пакет.
Псевдокод алгоритма
Тело функции целиком, включая общие для всех техник стадии — они пронумерованы так же, как в жизненный цикл desync-функции:
function syndata(ctx, desync)
-- 1. Проверка: только TCP
if not desync.dis.tcp then
-- ICMP пропускаем (не делаем cutoff), остальное --- cutoff
if not desync.dis.icmp then instance_cutoff(ctx, desync) end
return
end
-- 2. Проверка: только SYN (не SYN+ACK)
if bitand(th_flags, TH_SYN + TH_ACK) == TH_SYN then
-- 3. Глубокая копия dissect (оригинал не трогаем)
dis = deepcopy(desync.dis)
-- 4. Установка payload: blob или 16 нулей
dis.payload = blob(desync, arg.blob, "\x00" * 16)
-- 5. Применение fooling к копии
apply_fooling(desync, dis)
-- 6. tls_mod (если задан)
if arg.tls_mod then
dis.payload = tls_mod_shim(desync, dis.payload, arg.tls_mod, nil)
-- ^^^ payload от приложения = nil
end
-- 7. Отправка и фрагментация
if rawsend_dissect_ipfrag(dis, desync_opts(desync)) then
return VERDICT_DROP -- оригинальный SYN дропается
end
else
-- 8. Не SYN --- миссия завершена
instance_cutoff(ctx, desync)
end
endКлючевые отличия от функций сегментации (multisplit, fakedsplit и т.д.):
- Нет цикла по позициям --- payload отправляется одним пакетом целиком
rawsend_dissect_ipfragвместоrawsend_payload_segmented--- нет TCP-сегментации, только IP-фрагментацияdeepcopy--- полная копия dissect, а не создание нового пакета- Нет replay/reasm логики --- на фазе SYN нет многопакетных данных
Проще говоря
Псевдокод читается как рецепт. Проверить, что пакет TCP. Проверить, что это SYN без ACK: в комментарии к коду эта проверка так и названа, а выражение
bitand(th_flags, TH_SYN + TH_ACK) == TH_SYNоставляет из флагов пакета только SYN и ACK и сравнивает результат с одним SYN. Скопировать пакет, вложить payload, применить fooling иtls_mod. Отправить копию и выбросить оригинал. Если пакет не SYN, отключить функцию для этого соединения. Сегментированную отправку (rawsend_payload_segmented) используют функции вроде multisplit, там же есть цикл по позициям разреза: см. Стадия 7: нарезка и отправка.
Отличия от fake
Обе функции подсовывают DPI ложные данные, но в разное время и по-разному. В таблице слева названа строка сравнения, посередине стоит значение для syndata, справа для fake.
| Аспект | syndata | fake |
|---|---|---|
| Фаза | 0 (SYN, до handshake) | 1 (после handshake, есть реальные данные) |
| Что отправляет | SYN-пакет с payload | Отдельный data-пакет (не SYN) |
| Дефолтный blob | 16 нулевых байт | Обязательный --- без blob ничего не отправится |
| Сегментация | Невозможна (один пакет) | Невозможна (один пакет) |
| Заменяет оригинал | Да (VERDICT_DROP на SYN) | Нет (оригинал проходит дальше) |
| Fooling | Модифицирует сам SYN --- осторожно! | Модифицирует фейк --- сервер должен его отбросить |
| tls_mod=dupsid | Молча игнорируется | Работает (есть реальный ClientHello) |
| tls_mod=padencap | Молча игнорируется | Работает (есть реальный payload) |
| Хостлисты | Только --ipcache-hostname | Работают напрямую (payload уже содержит hostname) |
| Воздействие на ретрансмиссии | Да --- каждый SYN обрабатывается | Нет --- работает с конкретным data-пакетом |
| direction | Не поддерживается | Поддерживается |
| payload filter | Не поддерживается | Поддерживается |
| ipid | Не поддерживается | Поддерживается |
Проще говоря
fake— отдельный дополнительный пакет после рукопожатия, который сервер должен отбросить, а оригинальные данные уходят дальше.syndataподменяет сам SYN, который сервер должен принять. Из этого следуют остальные строки таблицы: уsyndataнет настоящих данных, поэтомуdupsidиpadencapне работают, нет hostname, нет фильтров. Подробнее оfake— в разделе Зачем нужен fake, сравнение с его стороны — в Сравнение с syndata и fakedsplit.
Когда использовать syndata вместо fake:
- DPI начинает трекинг с SYN и не реагирует на фейки после handshake
- Нужно “отравить” DPI ложными данными до того, как пойдёт реальный трафик
- В комбинации с wssize и multisplit для многоуровневой атаки
О связке с wssize и multisplit — раздел Комбинирование с другими функциями, а пример с фейком после рукопожатия — Боевая комбинация: syndata + fake + multisplit.
Работа с хостлистами
На фазе 0 (SYN) zapret не знает hostname --- приложение ещё не отправило HTTP-запрос или TLS ClientHello. Поэтому стандартная фильтрация по хостлистам (--hostlist=...) не работает с syndata напрямую.
Единственный способ --- --ipcache-hostname:
nfqws2 --ipcache-hostname \
--hostlist=blocked.txt \
--lua-desync=syndata:blob=fake_default_tlsКак это работает:
- Первое соединение к IP-адресу проходит без syndata (hostname ещё не известен)
- Из первого соединения zapret узнаёт hostname (из TLS ClientHello или HTTP Host) и кеширует привязку IP → hostname
- Последующие SYN к этому IP уже проходят через syndata, потому что zapret знает hostname из кеша
Следствие: syndata с хостлистом не подействует на первое соединение к данному IP. Это может быть проблемой для сайтов с уникальными IP или CDN с ротацией адресов.
Та же проблема нулевой фазы у классического --wssize в nfqws — почему из-за неё wssize считается крайней мерой, разобрано в отдельной заметке.
Проще говоря
Хостлист — файл со списком доменов, к которым нужно применять технику (см. Хостлисты). Чтобы сверить соединение со списком, нужно знать имя сайта, а в SYN его нет. Выход — кеш: Zapret запоминает, какому имени соответствовал IP при прошлом соединении. Поэтому первое соединение к IP пройдёт без
syndata, а следующие уже с ним. CDN (сеть серверов, раздающих сайт с разных адресов) с ротацией адресов для такой схемы неудобны: каждый новый IP для Zapret «первый». Ключ--ipcache-hostnameописан в Zapret flags, а хостлист вместе с ним в профиле показан в примере Боевая комбинация: syndata + fake + multisplit.
Комбинирование с другими функциями
syndata часто используется в цепочке с другими функциями. Порядок инстансов важен!
Инстанс — один вызов --lua-desync=… в профиле. Каждая строка в блоках ниже — отдельный инстанс, и порядок записи определяет порядок, в котором они увидят пакет; подробнее в последовательность аргументов.
Типовая цепочка: wssize + syndata + multisplit
--lua-desync=wssize:wsize=1:scale=6 \
--lua-desync=syndata \
--lua-desync=multisplit:pos=midsldЧто происходит:
-
SYN-пакет приходит:
wssizeмодифицирует TCP Window Size в SYN (wsize=1, scale=6)syndataдобавляет payload в SYN, дропает оригинал, отправляет модифицированныйmultisplitничего не делает (SYN, нет данных для нарезки)
-
Первый data-пакет (например, TLS ClientHello) приходит:
wssize--- миссия уже выполнена (cutoff или пропуск)syndataделаетinstance_cutoff(пакет не SYN)multisplitнарезает payload по позицииmidsld
Почему wssize перед syndata: wssize модифицирует TCP Window Size в SYN-пакете. Если поставить после syndata, wssize увидит VERDICT_DROP и не получит SYN. Если перед --- wssize модифицирует dissect, затем syndata использует deepcopy этого (уже модифицированного) dissect.
Проще говоря
Сначала wssize меняет размер окна в SYN (окно — сколько байт получатель готов принять, см. Что делает wssize; в цепочке оно заставляет сервер слать маленькие сегменты), потом
syndataкопирует уже изменённый SYN, дописывает данные и отправляет вместо оригинала. Если поставить их наоборот, wssize увидит уже принятое решение «оригинал выбросить», и SYN до него не дойдёт.midsld— маркер «середина домена второго уровня», все маркеры перечислены в разделе Маркеры позиций (pos).
Цепочка: syndata + fake + multisplit
--lua-desync=syndata:blob=fake_default_tls \
--lua-desync=fake:blob=fake_default_tls:tcp_md5 \
--lua-desync=multisplit:pos=1,midsldМногоуровневая атака:
- Фаза 0: SYN с фейковым TLS
- Фаза 1: фейковый пакет с fooling (tcp_md5)
- Фаза 1: реальный payload нарезан на сегменты
Проще говоря
Три функции работают в разное время.
syndataдействует на SYN. fake после рукопожатия отправляет отдельный пакет-обманку, испорченный foolingtcp_md5(см. Что такое fooling). multisplit режет настоящий ClientHello на сегменты поpos=1,midsld: после первого байта и посередине домена второго уровня. Оговорка проtcp_md5. Вfakeего берут, чтобы сервер отбросил фейк: так сказано в статье про fake, где серверы на Linux отбрасывают пакеты с MD5-опцией, если MD5-аутентификация у них не настроена. А вsyndataтот жеtcp_md5назван безопасным для SYN, потому что сервер без MD5 опцию игнорирует (нюанс 2). Эти два описания поведения сервера в источниках стоят порознь и не сведены к одному; как поведёт себя конкретный сервер, здесь не утверждается, а подобранную комбинацию стоит проверять по чек-листу.
Нюансы и подводные камни
1. Payload должен помещаться в один пакет
syndata использует rawsend_dissect_ipfrag, а не rawsend_payload_segmented. Это означает, что TCP-сегментация невозможна. Если blob слишком большой и не влезает в один Ethernet frame (с учётом MTU), пакет может быть отброшен сетевым стеком или фрагментирован на IP-уровне (если включён ipfrag).
Проще говоря
SYN — один пакет, и разрезать его на TCP-сегменты нельзя. MTU — наибольший размер пакета, который проходит по каналу за один раз. Другие функции сегментации сами доводят куски до размера MSS (наибольший объём данных в одном TCP-сегменте, см. Автосегментация по MSS);
syndataотправляет черезrawsend_dissect_ipfrag, где такого разбиения нет (Четыре способа выпустить пакет).
2. Fooling может сломать handshake
В отличие от fake, где fooling должен заставить сервер отбросить пакет, в syndata fooling применяется к пакету, который сервер должен принять. Деструктивные параметры:
tcp_seq=N--- сервер не увидит SYN с правильным sequencetcp_ack=N--- невалидный ack в SYNbadsum--- сервер отбросит пакет с плохой checksumtcp_flags_unset=SYN--- пакет перестанет быть SYN
Безопасные параметры:
tcp_md5--- сервер без MD5 проигнорирует опцию (RFC 2385)tcp_ts_up--- перестановка timestamp option (не влияет на валидность)tcp_nop_del--- удаление NOP (не влияет на валидность)- IPv6 extension headers --- для обхода DPI/фаерволов на пути
Проще говоря
Ломать нельзя то, без чего сервер не примет SYN: seq, ack, контрольную сумму, флаг SYN. Безопасными названы
tcp_md5,tcp_ts_up,tcp_nop_del(NOP — пустая опция-заполнитель в заголовке TCP) и IPv6 extension headers. Проtcp_md5есть оговорка в цепочке с fake. Сверьте с таблицей в разделе B) Standard fooling; каталог способов порчи — в ts-and-fooling.
3. Нет direction, payload filter, ipid
syndata не вызывает direction_cutoff_opposite, direction_check, payload_check или apply_ip_id. Эти стандартные блоки просто отсутствуют в коде функции:
- direction --- SYN всегда исходящий, фильтрация по направлению бессмысленна
- payload filter --- в SYN нет данных приложения, фильтровать нечего
- ipid ---
apply_ip_idне вызывается, IP ID не контролируется
Проще говоря
4. Все ретрансмиссии SYN обрабатываются
Если первый SYN не дошёл (или SYN+ACK потерялся), TCP-стек отправит ретрансмиссию SYN. syndata обработает каждую ретрансмиссию --- добавит payload, применит модификации, дропнет оригинал. Это полезно: DPI может обрабатывать только первый SYN, а ретрансмиссия с payload “перезапишет” данные в трекере.
Проще говоря
Ретрансмиссия — повторная отправка SYN средствами TCP-стека самой системы, если ответа нет.
syndataподменяет каждый такой SYN, поэтому, если DPI обрабатывает только первый SYN, повторный тоже придёт с данными и может «перезаписать» то, что DPI уже запомнил. Трекер здесь — «память» DPI о соединении.
5. deepcopy защищает оригинал
syndata делает deepcopy(desync.dis) и работает с копией. Это значит, что apply_fooling и замена payload не затрагивают оригинальный dissect. Если после syndata стоят другие инстансы и SYN не дропнут (rawsend failed), они увидят немодифицированный пакет.
Проще говоря
Копия — черновик, оригинал — чистовик. Правки идут в копию, оригинал остаётся как был. Оригинал выбрасывается только после успешной отправки копии. Если отправка не удалась, оригинальный SYN остаётся и попадает к следующим инстансам без изменений.
6. instance_cutoff на не-SYN
Как только syndata видит пакет без флага SYN (ACK, PSH+ACK и т.д.), он делает instance_cutoff --- отключает себя для этого потока навсегда. Это правильно: миссия syndata --- только SYN-пакеты. Последующие данные должны обрабатываться другими функциями (multisplit, fake и т.д.).
Как работает cutoff для всех функций сразу, описано в стадии 1 жизненного цикла.
7. ICMP не вызывает cutoff
Если в цепочке инстансов через syndata проходит ICMP-пакет (например, ICMP Destination Unreachable в ответ на SYN), syndata не делает instance_cutoff. Это защита от преждевременного отключения --- ICMP может быть связан с SYN и не означает конец потока.
ICMP — служебный протокол сети, которым сообщают об ошибках доставки, например «получатель недоступен».
8. Дефолтный blob --- 16 нулей, а не обязательный параметр
В отличие от fake, где blob обязателен, syndata имеет fallback --- 16 нулевых байт. --lua-desync=syndata без blob= отправит SYN с 16 байтами 0x00. Это может быть достаточно, чтобы сбить DPI, который не ожидает payload в SYN.
Про обязательный blob у fake — нюанс 5. blob обязателен — без optional будет Lua exception в статье про fake.
9. tls_mod без blob бессмыслен
Если вы указали tls_mod=rnd,rndsni без blob=, tls_mod попытается модифицировать 16 нулевых байт как TLS --- результат будет непредсказуемым. Всегда используйте tls_mod вместе с blob, содержащим валидный TLS ClientHello.
Проще говоря
tls_modрассчитан на данные, которые выглядят как TLS ClientHello, а 16 нулей таким ClientHello не являются, поэтому результат непредсказуем. Стандартный blob с TLS-фейком, который подходит для парыblobиtls_mod, описан в заметке Блобы.
Миграция с nfqws1
nfqws1 — движок первой версии zapret: там техники включаются флагами --dpi-desync-*, а в nfqws2 — вызовами --lua-desync. Ниже таблица соответствия для syndata и примеры перехода. Общая таблица всех флагов — в разделе Соответствие флагов nfqws1 → nfqws2, аналогичный раздел для сегментации — Миграция с nfqws1 в статье про multisplit.
Соответствие параметров
| nfqws1 | nfqws2 |
|---|---|
--dpi-desync=syndata | --lua-desync=syndata |
--dpi-desync-fake-tls=<file> | --blob=name:@file + :blob=name |
--dpi-desync-fake-tls-mod=rnd,rndsni | :tls_mod=rnd,rndsni |
--dpi-desync-fooling=md5sig | :tcp_md5 |
--wssize 1:6 | --lua-desync=wssize:wsize=1:scale=6 (отдельный инстанс, перед syndata) |
Проще говоря: в nfqws1 --wssize — глобальный флаг, а в nfqws2 это отдельный вызов wssize, который нужно поставить в цепочке перед syndata; причина описана в разделе Типовая цепочка: wssize + syndata + multisplit.
Пример полной миграции
# nfqws1:
nfqws --dpi-desync=syndata,multisplit \
--dpi-desync-split-pos=midsld \
--wssize 1:6
# nfqws2 (порядок инстансов важен!):
nfqws2 \
--lua-desync=wssize:wsize=1:scale=6 \
--lua-desync=syndata \
--lua-desync=multisplit:pos=midsld# nfqws1:
nfqws --dpi-desync=syndata \
--dpi-desync-fake-tls-mod=rnd,rndsni
# nfqws2:
nfqws2 \
--lua-desync=syndata:blob=fake_default_tls:tls_mod=rnd,rndsni# nfqws1:
nfqws --dpi-desync=syndata \
--dpi-desync-fooling=md5sig
# nfqws2:
nfqws2 \
--lua-desync=syndata:tcp_md5Практические примеры
Примеры идут от простых к сложным. Каждый блок кода — строки для профиля Zapret 2; аргументы разобраны в разделе Полный список аргументов.
Минимальный (дефолт: 16 нулей в SYN)
--lua-desync=syndataОтправляет SYN с 16 нулевыми байтами вместо обычного SYN. Простейший вариант --- может сбить DPI, не ожидающий payload в SYN.
С TLS-фейком
--lua-desync=syndata:blob=fake_default_tlsSYN содержит стандартный TLS ClientHello из zapret. DPI может принять это за начало TLS-сессии.
С кастомным blob из файла
--blob=mysyndata:@custom_syn_payload.bin \
--lua-desync=syndata:blob=mysyndataЗагружает произвольный payload из файла и вставляет в SYN.
С inline hex blob
--lua-desync=syndata:blob=0x1603010001006 байт inline hex --- минимальный TLS record header.
Проще говоря: TLS record — «запись», в которую TLS упаковывает передаваемые данные, а её заголовок стоит в начале записи.
С рандомизацией TLS
--lua-desync=syndata:blob=fake_default_tls:tls_mod=rnd,rndsniTLS-фейк с рандомизированными полями и SNI. Каждый SYN будет содержать уникальные random/session_id/SNI.
С заменой SNI
--lua-desync=syndata:blob=fake_default_tls:tls_mod=sni=google.comSYN содержит TLS ClientHello с SNI google.com. DPI может записать в трекер “это соединение к google.com” и не блокировать.
С TCP MD5
--lua-desync=syndata:tcp_md5SYN с 16 нулями и TCP MD5 option. Сервер без MD5 проигнорирует опцию, DPI может быть сбит нестандартным TCP-заголовком.
С TTL fooling (осторожно!)
--lua-desync=syndata:blob=fake_default_tls:ip_ttl=5:ip6_ttl=5SYN с TTL=5. Если DPI ближе 5 хопов --- увидит фейк. Если сервер дальше 5 хопов --- SYN не дойдёт, handshake не состоится. Ретрансмиссия SYN тоже получит TTL=5 и тоже не дойдёт. Используйте только если точно знаете расстояние до DPI и сервера.
Проще говоря: хоп — один переход пакета между маршрутизаторами. Пакет с TTL=5 успеет пройти пять хопов и дальше пропадёт. Про TTL как способ fooling и его слабые места — каталог способов в заметке про fooling.
С IP-фрагментацией
--lua-desync=syndata:blob=fake_default_tls:ipfrag:ipfrag_disorderSYN с TLS-фейком, фрагментированный на IP-уровне в обратном порядке. DPI, не собирающий IP-фрагменты, не увидит полный пакет.
С IP-фрагментацией (кастомная позиция)
--lua-desync=syndata:blob=fake_default_tls:ipfrag:ipfrag_pos_tcp=24Фрагментация по позиции 24 байта (кратно 8). Первый фрагмент содержит TCP-заголовок, второй --- payload.
Типовая боевая комбинация: wssize + syndata + multisplit
--filter-tcp=443 \
--lua-desync=wssize:wsize=1:scale=6 \
--lua-desync=syndata \
--lua-desync=multisplit:pos=midsldТрёхуровневая атака на DPI: маленькое окно (заставляет сервер слать маленькие сегменты) + payload в SYN + нарезка реального ClientHello.
Боевая комбинация: syndata + fake + multisplit
--filter-tcp=443 --hostlist=blocked.txt --ipcache-hostname \
--lua-desync=syndata:blob=fake_default_tls:tls_mod=rnd,rndsni \
--lua-desync=fake:blob=fake_default_tls:tcp_md5:tls_mod=rnd,rndsni,dupsid \
--lua-desync=multisplit:pos=1,midsldМаксимальная комбинация: фейк в SYN, фейк после handshake (с dupsid --- здесь он работает, потому что это fake, а не syndata), нарезка реального payload.
Проще говоря: --hostlist=blocked.txt ограничивает профиль доменами из списка, а --ipcache-hostname включает кеш имён, без которого syndata хостлист не увидит (см. Работа с хостлистами).
Отладка: повторы отправки
--lua-desync=syndata:blob=fake_default_tls:repeats=3Каждый SYN с payload отправляется 3 раза. Полезно для отладки или если DPI обрабатывает только N-й пакет.
IPv6: extension headers
--lua-desync=syndata:blob=fake_default_tls:ip6_hopbyhop:ip6_destoptSYN с hop-by-hop и destination options extension headers. Некоторые DPI/фаерволы не умеют парсить IPv6 extension headers и пропускают пакет.
📚 См. также
- desync — обзор всех функций
--lua-desyncи общий контракт: кто вызывает функцию, что ей передаёт и как складываются вердикты - жизненный цикл desync-функции — восемь стадий, общих для всех техник дурения
- структура desync и диссекта — подробное устройство таблицы
desyncи диссекта пакета - fake — отдельный фейковый пакет после рукопожатия; сравнение с
syndata - blob — как объявлять и передавать данные для аргумента
blob - payload — распознавание типов протоколов и фильтр
--payload - multisplit — нарезка настоящего ClientHello, с которой
syndataобычно стоит в одной цепочке - ts-and-fooling — что такое fooling и как им портят пакеты
- verify-strategy — как честно проверить, работает ли подобранная комбинация
- последовательность аргументов — как выстраивается цепочка инстансов в профиле
- wssize в zapret — та же нулевая фаза и та же проблема хостлистов
- Хостлисты — списки доменов, с которыми связан
--ipcache-hostname - DPI и ТСПУ — как устроена инспекция трафика, против которой работает
syndata
Источники:
lua/zapret-antidpi.lua:385,lua/zapret-lib.lua,docs/manual.md:3944-3961из репозитория zapret2.
🤖 Эти статьи открыты — можно обучать на них ИИ
При желании вы можете натренировать ИИ на наших статьях. Исходное форматирование доступно в Forgejo: исходник этой заметки · скачать весь репозиторий одним zip-архивом.