fake — прямой фейк (zapret2 / nfqws2)

Коротко и по-простому

Когда браузер открывает сайт по HTTPS, первым сообщением с данными он отправляет TLS ClientHello («привет от клиента»). В нём браузер перечисляет, какое шифрование умеет, и открытым текстом называет нужный сайт: имя лежит в поле SNI (Server Name Indication, «указание имени сервера»). У обычного HTTP без шифрования то же имя стоит в строке Host: запроса. ТСПУ (Технические средства противодействия угрозам — оборудование DPI, то есть глубокой инспекции трафика, которое стоит у провайдера) ищет это имя в первом пакете соединения и по нему решает, что делать с соединением дальше.

HTTP-запросы и TLS-соединения передаются по протоколу TCP, а TCP отправляет данные кусками — сегментами. У каждого байта в соединении есть порядковый номер (sequence number, коротко seq), и сервер раскладывает принятые куски в свой буфер по этим номерам. Если сервер примет чужие данные на те номера, где должен лежать настоящий запрос, поток развалится: настоящий ClientHello придёт с пересекающимися номерами, и, как описано в нюансе «Без fooling фейк бесполезен или вреден», соединение оборвётся.

На этом строится fake. Движок Zapret 2 (nfqws2) перехватывает исходящий пакет с ClientHello или HTTP-запросом, а fake перед ним отправляет отдельный пакет-обманку — фейк, то есть заранее заготовленные данные с ложным содержимым, например ClientHello с безобидным именем www.w3.org вместо настоящего. Сам оригинал fake не трогает и не режет: он уходит следом как ни в чём не бывало. У функции нет вердикта, то есть она не приказывает выбросить перехваченный пакет, как это делают функции сегментации вроде multisplit. Отсюда порядок: сначала фейк, потом настоящий запрос. Данные для фейка берутся из аргумента blob. Blob — это заранее заготовленный набор байт с именем; у Zapret 2 есть три готовых, fake_default_tls, fake_default_http и fake_default_quic (что внутри, разобрано в разделе Стандартные blob-ы). Аргумент blob у fake обязателен: без него функция завершается ошибкой и молча шаг не пропускает (нюанс 5).

Главное, что нужно понять о fake: фейк должен дойти до DPI, но не быть принят сервером. Если сервер примет его за настоящие данные, соединение сломается, как описано выше. Поэтому фейк намеренно портят: меняют его служебные поля (заголовки) так, чтобы сервер или промежуточные маршрутизаторы его отбросили, а DPI, по замыслу, всё равно прочитал. Такая порча называется fooling («одурачивание»); что это и зачем, разобрано в заметке ts-and-fooling, в разделе Что такое fooling. Два самых частых способа. tcp_md5 добавляет к TCP-заголовку фейка опцию с подписью MD5: серверы на Linux отбрасывают такие пакеты, если MD5-аутентификация у них не настроена. ip_ttl=1 (для IPv6 — ip6_ttl=1) задаёт пакету TTL — предельное число промежуточных узлов, через которые он пройдёт; при значении 1 пакет умирает уже на первом хопе (хоп — один переход между узлами сети), поэтому до сервера не доходит, а DPI его увидит, если стоит ближе к клиенту, чем сервер. Есть и другие способы: испорченная контрольная сумма (badsum), неверный номер seq и так далее. Все они собраны в разделе D) Standard fooling, а выбор под конкретную среду разобран в каталоге способов.

В итоге сервер получает правильные данные, а DPI сначала видит ложные. Фейк сервер должен отбросить из-за порчи, а принять только настоящий запрос и ответить как обычно; если порча не сработала и сервер принял фейк, соединение может сломаться (нюанс 2 ниже). DPI читает фейк первым и может принять решение по нему: пропустить соединение из-за безобидного SNI, потерять состояние потока из-за невалидных данных или не суметь заблокировать, потому что в фейке другое имя (подробно — в разделе Зачем нужен fake). Гарантий нет: это лишь возможные исходы.

Команда из быстрого старта (fake:blob=fake_default_tls:tcp_md5) сначала отправляет фейковый ClientHello с именем www.w3.org, а следом уходит оригинал с youtube.com; оба занимают одни и те же позиции потока. ТСПУ (система DPI на стороне провайдера) читает фейк первым, и один из возможных исходов — решение по соединению принимается по нему. Сервер фейк отбрасывает: в пакете испорчена подпись TCP MD5. Как читать схему: строки — пакеты в порядке отправки, подписанные в тех же обозначениях, что и таблицы в этой статье; по горизонтали — место данных в TCP-потоке (номер последовательности, seq); в колонке справа — что сделал с пакетом сервер; внизу — буфер сервера, в который принятые куски встают по своим seq.

fake: фейковый ClientHello перед оригиналом Карта потока для fake с blob=fake_default_tls и tcp_md5: сначала уходит фейковый ClientHello с именем www.w3.org на тех же позициях потока, затем оригинал с youtube.com. Сервер отбрасывает фейк по неверной подписи TCP MD5 и принимает оригинал. пакет в порядке отправки место в потоке (seq) → сервер 0 26 #1 FAKE seq=0 blob ···········www.w3.org····· отброшен: md5 #2 ORIG seq=0 len=26 ···········youtube.com···· принят буфер сервера ···········youtube.com···· поток собран DPI первым читает ClientHello с www.w3.org; если решение принято по нему, настоящий пакет уже не проверяется сервер фейк отбрасывает по неверной подписи TCP MD5 (tcp_md5), принимает оригинал

Минимальная команда для HTTPS — первая из Быстрого старта. --payload=tls_client_hello значит «срабатывать только на TLS ClientHello», blob=fake_default_tls выбирает, какой фейк отправить, а tcp_md5 портит его так, чтобы сервер отбросил:

--payload=tls_client_hello --lua-desync=fake:blob=fake_default_tls:tcp_md5

Для HTTP меняются только тип данных и blob: --payload=http_req и fake_default_http. fake работает и с UDP, а значит, с QUIC — протоколом на основе UDP, у которого тоже есть первый пакет (QUIC Initial), где DPI ищет сигнатуры, то есть заранее известные строки. У UDP нет сквозной нумерации байтов и TCP-опций (почему так, объяснено в нюансе «Работает только с TCP» статьи про multisplit), поэтому TCP-fooling вроде tcp_md5 для него бессмыслен. Вместо него берут IP-уровневые способы, в первую очередь ip_ttl=1:ip6_ttl=1 (нюанс 6).

fake — «огонь по площадям»: он бросает в поток одну или несколько обманок и не трогает настоящий пакет. Поэтому его почти всегда ставят первым инстансом (одной записью --lua-desync=… в профиле — наборе правил Zapret 2 для определённого трафика), а следом — технику сегментации, например multisplit: фейк может сбить DPI, а нарезка — помешать ему найти имя в настоящем пакете (нюанс 8). Если одного фейка мало, может помочь repeats=N: некоторые DPI сбрасывают состояние после N-го пакета, поэтому серия фейков, например repeats=11, может оказаться эффективнее одного (нюанс 7). Работает ли выбранная комбинация у вашего провайдера, проверяют по чек-листу честной проверки.

У fake есть близкие соседи. fakedsplit и fakeddisorder замешивают фейки прямо между кусками настоящего запроса; fakedsplit заменяет связку fake + multisplit, но ограничен одной позицией разреза. syndata кладёт данные уже в SYN — первый пакет рукопожатия (handshake), с которого TCP-соединение устанавливается. А скрытый фейк внутри настоящего сегмента дают seqovl: в multisplit для этого, по описанию в его статье, не приходится портить заголовки, а в multidisorder тот же приём устроен иначе: фейк остаётся в буфере сокета сервера и затирается следующим сегментом. Все отличия сведены в таблицу в разделе Сравнение с syndata и fakedsplit.


Оглавление


Справка: где функция в коде и родственники

Паспорт функции для тех, кто сверяется с исходниками zapret2: в каком файле и на какой строке лежит код, какой ключ первой версии zapret она заменяет и как объявлена.

Файл: lua/zapret-antidpi.lua:449 nfqws1 эквивалент: --dpi-desync=fake Сигнатура: function fake(ctx, desync)

fake — самая часто используемая функция в zapret. Она отправляет отдельный пакет (или группу пакетов) с фейковым payload из указанного blob. При этом функция не выносит вердикт и не блокирует отправку оригинала — оригинальный пакет уходит следом. DPI видит сначала фейк, затем настоящий трафик. Задача фейка — “отравить” состояние DPI ложными данными (неверный SNI, невалидный HTTP-запрос и т.д.).

Работает с TCP и UDP (в отличие от функций сегментации, которые только TCP).

Проще говоря

Payload — полезные данные пакета без сетевых заголовков: сам ClientHello, HTTP-запрос или первый пакет QUIC. Blob — заранее заготовленные данные, которые fake отправляет вместо настоящих. «Отравить состояние DPI» значит подсунуть ему ложные данные, по которым он сделает неверный вывод о соединении. Вердикт — решение «перехваченный пакет не отправлять»; у fake его нет, поэтому оригинал уходит следом, как описано в стадии 8 жизненного цикла.

Родственные функции: syndata (payload в SYN), fakedsplit (фейки + сегментация), fakeddisorder (фейки + обратный порядок), multisplit (чистая сегментация), multidisorder (сегментация в обратном порядке).

Общий для всех техник дурения порядок работы — восемь стадий от отсева чужого транспорта до вердикта — разобран в жизненный цикл desync-функции; здесь описано только то, чем fake от этого скелета отличается.


Зачем нужен fake

DPI анализирует первые пакеты TCP/UDP-потока, ища сигнатуры (SNI в TLS ClientHello, Host в HTTP, QUIC Initial). Сигнатура здесь — заранее известная строка, по которой DPI узнаёт сайт. Если перед настоящим пакетом отправить фейковый пакет с ложными данными, DPI может:

  1. Принять фейк за реальный трафик: DPI обработает фейковый SNI/Host и примет решение на его основе — пропустит соединение
  2. Сбиться с состояния: получив невалидные данные, DPI потеряет контекст потока и перестанет его анализировать
  3. Не суметь заблокировать: если DPI блокирует по hostname, а в фейке другой hostname — реальный запрос может пройти

При этом сервер должен отбросить фейк. Для этого к фейку применяется fooling — порча заголовков (TTL, badseq, md5sig, badsum), из-за которой сервер или промежуточные маршрутизаторы отбрасывают пакет, а DPI — нет.

fake — “огонь по площадям”: он шлёт фейк отдельным пакетом, не трогая оригинал. Для более тонкой работы (замешивание фейков внутри сегментов) используйте fakedsplit/fakeddisorder, для скрытых фейков через TCP window — seqovl в multisplit/multidisorder.

Проще говоря

fake заранее показывает DPI ложную картину: другое имя сайта или бессмысленные данные. Сервер эту картину не видит, потому что фейк специально испорчен, и получает только настоящий запрос. TCP window (окно приёма) — диапазон номеров байт, которые получатель готов принять; скрытые фейки, которые строятся на приёме и отбрасывании байт, fake не делает, это работа seqovl (в multisplit фейк оказывается левее окна приёма и сервер его выбрасывает, в multidisorder — иначе, как сказано в начале статьи). Как испортить фейк правильно, зависит от того, где стоит DPI и что стоит между вами и сервером: разбор — в заметке ts-and-fooling.


Быстрый старт

Ниже четыре готовые строки для профиля Zapret 2, от минимальных вариантов к боевой связке. Флаг --payload=… работает как фильтр для всех вызовов --lua-desync, которые идут после него (до следующего --payload или до конца профиля): они срабатывают только на данных указанного типа. Поэтому --payload пишут перед --lua-desync (подробно — в последовательность аргументов; типы данных описаны в заметке о типах payload).

Минимальный TLS-фейк (обязателен blob + fooling):

--payload=tls_client_hello --lua-desync=fake:blob=fake_default_tls:tcp_md5

Сервер отбросит такой фейк из-за TCP MD5 option. fake_default_tls — один из стандартных blob-ов (что в нём, разобрано в разделе Стандартные blob-ы).

Минимальный HTTP-фейк:

--payload=http_req --lua-desync=fake:blob=fake_default_http:tcp_md5

То же для HTTP: другой тип данных и другой стандартный blob.

QUIC-фейк (UDP):

--payload=quic_initial --lua-desync=fake:blob=fake_default_quic:ip_ttl=1:ip6_ttl=1

Для UDP TCP-fooling неприменим, поэтому фейк ограничен по TTL (подробно — в нюансе «Для UDP нет TCP-fooling»).

Типовая боевая связка fake + multisplit:

--payload=tls_client_hello \
  --lua-desync=fake:blob=fake_default_tls:tcp_md5:tls_mod=rnd,rndsni,dupsid,padencap \
  --lua-desync=multisplit:pos=1,midsld

Фейк уходит первым, а следом multisplit режет настоящий ClientHello после первого байта и посередине домена второго уровня (маркеры pos разобраны в разделе Маркеры позиций (pos)). Набор tls_mod=… меняет содержимое самого фейка, см. раздел tls_mod.


Место в общем скелете

Тело fake построено по тому же шаблону, что и все остальные функции дурения: восемь стадий от отсева чужого транспорта до вердикта. Разобраны они один раз в жизненный цикл desync-функции — здесь только отклонения, и их у fake больше, чем у прочих техник. Несколько слов из таблицы. Cutoff (отсечение) значит, что движок больше не будет вызывать функцию на пакетах этого потока или направления. Гвард — проверка «работать ли с этим пакетом». Replay (перепроигрывание) — повторный вызов функций на придержанных частях многопакетного запроса. Вердикт — решение движка, что сделать с перехваченным пакетом.

Стадия общего скелетаЧто делает fake
1. Отсев транспортаисключение из правила: работает и с TCP, и с UDP, поэтому instance_cutoff не делает вовсе — просто условие if (desync.dis.tcp or desync.dis.udp)
2. Направлениеdir=out по умолчанию, отключается от входящего
3. Аргументыblob обязателен — без него error(); с флагом optional отсутствующий blob даёт тихий выход
4. Данныене использует цепочку blob → reasm → payload: всегда шлёт содержимое своего blob, а reasm_data нужен лишь как образец для tls_mod
5. Гвардыштатные direction_check и payload_check (по умолчанию known)
6. replayштатный replay_first: фейк уходит один раз, на первой части многопакетного запроса
7. Своя техниказагрузить blob, при необходимости применить tls_mod, отправить rawsend_payload_segmented
8. Вердиктне выносит никакого — оригинал уходит следом за фейком как ни в чём не бывало

Две последние строки таблицы и объясняют, почему fake комбинируется с чем угодно: он ничего не дропает и ничего не модифицирует, а просто добавляет в поток лишний пакет перед настоящим. Поэтому в профиле его почти всегда ставят первым инстансом, а следом — технику сегментации вроде multisplit.

Проще говоря

Почти каждая функция дурения проходит одни и те же восемь шагов, а fake от этого шаблона отличается тем, что берёт данные из своего blob, не выносит вердикт и умеет работать и с TCP, и с UDP.

Каждую стадию по отдельности разбирает жизненный цикл: стадия 1 (транспорт), стадия 2 (направление), стадия 3 (аргументы), стадия 4 (данные), стадия 5 (гварды), стадия 6 (replay), стадия 7 (своя техника) и стадия 8 (вердикт).


blob — источник фейковых данных

blob — обязательный аргумент fake. Он указывает, что именно отправить в качестве фейкового payload. Blob — заранее заготовленный набор байт с именем; как их объявлять и что в них можно положить, разобрано в заметке blob, а здесь описано только то, что нужно для fake.

Стандартные blob-ы

Zapret автоматически создаёт три стандартных blob-а при инициализации. Таблица показывает, какой из них к какому типу данных подходит; тип данных задаёт --payload=… в профиле:

BlobОписаниеТипичное использование
fake_default_tlsВалидный TLS ClientHello с SNI www.w3.org--payload=tls_client_hello
fake_default_httpВалидный HTTP GET запрос--payload=http_req
fake_default_quicQUIC Initial пакет--payload=quic_initial

Эти blob-ы содержат полноценные протокольные структуры, которые DPI может распознать и обработать. Именно поэтому fake_default_tls — самый частый выбор для TLS-фейков: DPI парсит его как настоящий ClientHello, видит www.w3.org вместо заблокированного домена.

Проще говоря

Стандартный blob — это готовый «пример запроса» с безобидным содержимым. fake отправляет его как есть, а DPI разбирает его так же, как настоящий.

Пользовательские blob-ы

Свой blob можно задать несколько способами: прямо в команде шестнадцатеричной строкой (inline hex), загрузить из файла, взять из Lua-переменной, в том числе созданной другой функцией. Примеры:

# Inline hex (произвольные байты)
--lua-desync=fake:blob=0xDEADBEEF:tcp_md5
 
# Нулевые байты (4 байта нулей)
--lua-desync=fake:blob=0x00000000:ip_ttl=6:ip6_ttl=6
 
# Из файла (предзагруженный)
--blob=my_fake_ch:@/path/to/custom_clienthello.bin
--lua-desync=fake:blob=my_fake_ch:tcp_md5
 
# Из Lua-переменной (например, клонированный ClientHello)
--lua-desync=tls_client_hello_clone:blob=cloned_ch:sni_del:sni_add=www.google.com
--lua-desync=fake:blob=cloned_ch:tcp_md5

Blob разрешается функцией blob_exist() / blob() в следующем порядке:

  1. Если имя начинается с 0x — inline hex, создаётся на лету
  2. desync[name] — поле в текущем контексте desync (например, сгенерированное tls_client_hello_clone)
  3. _G[name] — глобальная Lua-переменная (например, fake_default_tls)

Проще говоря

Сначала смотрится, не hex ли записан прямо в аргументе, потом — не создал ли имя предыдущий инстанс в текущем контексте desync (устройство таблицы — в структура desync и диссекта), и в последнюю очередь — среди глобальных переменных Lua. Если имя не нашлось нигде, fake завершится ошибкой, а с флагом optional тихо пропустит шаг (нюанс 5).


tls_mod — модификации TLS в фейке

tls_mod позволяет модифицировать содержимое blob-а перед отправкой, подстраивая фейковый ClientHello под текущее соединение. Это делает фейк более убедительным для DPI. Среди полей ClientHello есть случайные 32 байта (Random), идентификатор сессии (Session ID) и набор расширений (extensions), среди которых SNI с именем сайта и padding — заполнитель. Опции ниже меняют эти поля blob-а перед отправкой; остальные модификации TLS-блобов описаны в заметке blob.

Опции tls_mod

ОпцияОписаниеТребования
noneНичего не делать—
rndЗаполнить поля Random (32 байта) и Session ID случайными даннымиblob должен содержать валидный TLS ClientHello
rndsniЗаменить SNI на случайный домен. Если длина оригинального SNI >= 7 символов — случайный поддомен из известных 3-буквенных TLD. Иначе — случайные символы [a-z][a-z0-9]*blob должен содержать SNI extension
sni=<domain>Заменить SNI на конкретный домен (изменяет длины внутри TLS-структур)blob должен содержать SNI extension
dupsidСкопировать Session ID из оригинального payload (из desync.reasm_data) в фейк. Выполняется после rnd. Требует совпадения длин session idвалидный TLS в reasm_data
padencapПодкорректировать blob так, чтобы оригинальный payload стал частью padding extension. Увеличивает поля длины TLS record/handshake/extensions/padding на len(original_payload)blob должен содержать padding extension (type 21)

Порядок применения модов: они применяются в порядке перечисления, но dupsid всегда выполняется после rnd (чтобы рандомизированный Session ID был перезаписан реальным).

Проще говоря

rnd делает случайными служебные поля фейка, rndsni и sni= подменяют имя сайта в нём, dupsid копирует идентификатор сессии из настоящего запроса, а padencap готовит фейк так, чтобы настоящий запрос выглядел его продолжением (подробности — ниже). Образцом для dupsid и padencap служит настоящий запрос, собранный движком, — desync.reasm_data; что такое reasm, объяснено в разделе Приём многопакетных пейлоадов.

Подстановка sni=%var

Внутри tls_mod поддерживается специальная запись sni=%variable: вместо готового домена в SNI подставляется значение переменной. Значение desync.target устанавливается механизмом hostlist (списки доменов профиля, см. Списки IP и доменов).

# Подстановка из desync.target (устанавливается механизмом hostlist)
--lua-desync=fake:blob=fake_default_tls:tcp_md5:tls_mod=sni=%target
 
# Подстановка из глобальной Lua-переменной
--lua-init="my_domain='www.google.com'" \
--lua-desync=fake:blob=fake_default_tls:tcp_md5:tls_mod=sni=%my_domain

Порядок поиска переменной:

  1. desync[var] — поле в текущем контексте desync
  2. _G[var] — глобальная Lua-переменная

Если переменная не найдена — вызывается error("tls_mod_shim: non-existent var 'varname'").

Когда tls_mod применяется, а когда нет

В fake tls_mod вызывается только если одновременно выполнены оба условия:

  1. desync.reasm_data существует (обычно есть при TLS ClientHello, который был реассемблирован)
  2. Аргумент tls_mod задан

Reasm (reasm_data) — запрос, собранный движком из нескольких пакетов; для tls_mod он служит образцом настоящего ClientHello.

Если reasm_data отсутствует (например, маленький пакет, не потребовавший реассемблирования, или UDP) — tls_mod молча пропускается, без ошибок. Это отличие от syndata, где tls_mod вызывается всегда (с payload=nil), потому что syndata работает на SYN-пакете, где никакого реального payload ещё нет.

Проще говоря

Нет образца настоящего запроса — модификации молча не применяются, и фейк уходит таким, каким лежит в blob-е.

Обходной путь, если tls_mod нужен без reasm_data:

# Заранее модифицировать blob через lua-init
--lua-init="fake_default_tls=tls_mod(fake_default_tls,'rnd,rndsni')"

padencap — подробности

padencap — техника, при которой фейковый blob подготавливается так, чтобы реальный payload, отправленный следом, воспринимался DPI как продолжение padding extension в фейковом ClientHello. DPI, парсящий TLS, может объединить фейк и оригинал в один record, и реальный SNI окажется “внутри” padding — невидим для анализа.

Для этого в blob должна присутствовать padding extension (type 0x0015), а padencap увеличивает все поля длины (TLS record length, Handshake length, Extensions length, Padding extension length) на len(original_payload).

Проще говоря

Фейк заранее объявляет: «моё поле-заполнитель длиннее, чем кажется». Настоящий ClientHello, который придёт следом, DPI может принять за продолжение этого заполнителя, и тогда настоящий SNI останется незамеченным. Ограничения этого трюка — в нюансе 10.


Полный список аргументов

Аргументы делятся на собственные аргументы fake (раздел A) и стандартные (разделы B–H): их понимают и другие функции дурения, а общий обзор есть в desync. Формат вызова:

--lua-desync=fake[:arg1[=val1][:arg2[=val2]]...]

Все val приходят в Lua как строки. Если =val не указан, значение = пустая строка "" (в Lua это truthy), поэтому флаги пишутся просто как :optional, :tcp_md5, :badsum.

A) Собственные аргументы fake

blob (обязательный)

  • Формат: blob=<blobName>
  • Тип: имя blob-переменной (загружается через --blob=<name>:@file|0xHEX, через desync[name] или как глобальная Lua-переменная)
  • По умолчанию: нет (обязательный аргумент)
  • Описание: Blob, содержащий фейковый payload. Может быть любой длины — для TCP сегментация по MSS выполняется автоматически. Для UDP отправляется как есть
  • Ошибка: если blob не указан, вызывается error("fake: 'blob' arg required") — Lua exception, останавливающий обработку пакета
  • Примеры:
    • blob=fake_default_tls — стандартный TLS-фейк
    • blob=fake_default_http — стандартный HTTP-фейк
    • blob=fake_default_quic — стандартный QUIC-фейк
    • blob=0xDEADBEEF — inline hex
    • blob=0x00000000 — четыре нулевых байта
    • blob=my_custom_blob — предзагруженный или сгенерированный blob

Проще говоря: blob — единственный аргумент, без которого fake не работает. Как он ищется, описано в разделе blob — источник фейковых данных.

optional

  • Формат: optional (флаг, без значения)
  • Описание: Если blob отсутствует (не найден ни как inline hex, ни как desync[name], ни как _G[name]) — тихий пропуск без ошибки. Без optional отсутствие blob-а вызывает error()
  • Использование: защита от ошибок при использовании blob-ов, которые могут отсутствовать (например, генерируемых tls_client_hello_clone — если payload не TLS, clone не создаст blob)

Проще говоря: без optional отсутствие blob-а останавливает обработку пакета ошибкой, с optional fake просто ничего не делает (нюанс 5).

tls_mod

  • Формат: tls_mod=<commaSeparatedList>
  • Тип: строка вида opt1,opt2,...
  • По умолчанию: не задан (модификации не применяются)
  • Описание: Список TLS-модификаций, применяемых к blob перед отправкой. Работает только при наличии desync.reasm_data
  • Опции: none, rnd, rndsni, sni=<domain>, dupsid, padencap
  • Подстановка: sni=%variable — подстановка из desync[var] или _G[var]
  • Примеры:
    • tls_mod=rnd — рандомизировать Random и Session ID
    • tls_mod=rnd,rndsni,dupsid — рандомизировать + случайный SNI + скопировать реальный Session ID
    • tls_mod=rnd,rndsni,dupsid,padencap — полный набор модификаций
    • tls_mod=sni=www.google.com — конкретный домен в SNI
    • tls_mod=sni=%target — подстановка из переменной target

Каждая опция разобрана в разделе tls_mod — модификации TLS в фейке.


B) Standard direction

Направление говорит, в какую сторону идёт пакет: от вашего компьютера к серверу (исходящий) или обратно (входящий).

ПараметрЗначенияПо умолчанию
dirin, out, anyout

Фильтр по направлению пакета. fake по умолчанию работает только с исходящими (out).

  • dir=out — только исходящие (от клиента к серверу)
  • dir=in — только входящие (от сервера к клиенту)
  • dir=any — оба направления

При первом вызове с указанным dir функция делает direction_cutoff_opposite — отсекает себя от противоположного направления. Cutoff (отсечение) значит, что движок больше не будет вызывать функцию на пакетах этого направления в текущем соединении; подробно — в стадии 2 жизненного цикла.


C) Standard payload

Здесь фильтр — по типу payload, то есть по названию распознанного протокола (tls_client_hello, http_req, quic_initial).

ПараметрЗначенияПо умолчанию
payloadсписок типов через запятуюknown

Фильтр по типу payload на уровне Lua. Это дополнительный фильтр к --payload=... на уровне профиля.

  • payload=known — только распознанные протоколы (http_req, tls_client_hello, quic_initial и т.д.)
  • payload=all — любой payload, включая unknown
  • payload=tls_client_hello,http_req — конкретные типы
  • payload=~unknown — инверсия: всё кроме unknown

Важно: лучше ставить --payload=... на уровне профиля (C-код, быстрее), а не полагаться только на Lua-фильтр.

Проще говоря: фильтр --payload= на уровне профиля работает в быстром ядре программы, написанном на C, а аргумент payload= проверяется уже в Lua, то есть медленнее. Поэтому основной отбор лучше делать на уровне профиля.


D) Standard fooling

Fooling — намеренная порча заголовков пакета, обычно для того, чтобы сервер отбросил фейк, а DPI его прочитал (подробно — Что такое fooling). Здесь это модификации L3/L4 заголовков, то есть заголовков IP (сетевой уровень) и TCP (транспортный уровень). В fake fooling применяется только к фейковым пакетам (а не к оригиналу — тот уходит без изменений). Это ключевое отличие от multisplit, где fooling идёт на все сегменты.

ПараметрОписаниеПример
ip_ttl=NУстановить IPv4 TTLip_ttl=6
ip6_ttl=NУстановить IPv6 Hop Limitip6_ttl=6
ip_autottl=delta,min-maxАвтоматический TTL (delta от серверного TTL)ip_autottl=-2,40-64
ip6_autottl=delta,min-maxАналогично для IPv6ip6_autottl=-2,40-64
ip6_hopbyhop[=HEX]Вставить extension header hop-by-hop (по умолчанию 6 нулей)ip6_hopbyhop
ip6_hopbyhop2[=HEX]Второй hop-by-hop headerip6_hopbyhop2
ip6_destopt[=HEX]Destination options headerip6_destopt
ip6_destopt2[=HEX]Второй destination optionsip6_destopt2
ip6_routing[=HEX]Routing headerip6_routing
ip6_ah[=HEX]Authentication headerip6_ah
tcp_seq=NСместить TCP sequence (+ или -)tcp_seq=-10000
tcp_ack=NСместить TCP ack (+ или -)tcp_ack=-66000
tcp_ts=NСместить TCP timestamptcp_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-функция foolingfool=my_fooler

Типичные комбинации fooling для fake:

  • tcp_md5 — самый популярный. Серверы (Linux) отбрасывают пакеты с TCP MD5 option, если MD5-аутентификация не настроена
  • ip_ttl=1:ip6_ttl=1 — TTL=1: фейк не дойдёт до сервера, но DPI на пути его увидит
  • badsum — испорченная контрольная сумма: сервер отбросит, DPI может пропустить
  • tcp_flags_unset=ACK — datanoack: убрать ACK-флаг, сервер отбросит пакет без ACK в установленном соединении
  • tcp_seq=-10000 — badseq: невалидный sequence number, сервер отбросит

Проще говоря

Все опции таблицы — способы сделать фейк «неправильным» в одном из мест: время жизни пакета (ip_ttl), номера seq и ack, TCP-опции (tcp_md5, tcp_ts), флаги, контрольная сумма (badsum, раздел G). Какая опция сработает, зависит от среды: почему у каждой свой «слой смерти» и где она ломается, описано в каталоге способов.


E) Standard ipid

IP ID — идентификатор в заголовке IPv4-пакета. Эти параметры задают, какие значения получат отправляемые пакеты.

ПараметрОписаниеПо умолчанию
ip_id=seqПоследовательные IP IDseq
ip_id=rndСлучайные IP ID—
ip_id=zeroНулевые IP ID—
ip_id=noneНе менять IP ID—
ip_id_connСквозная нумерация IP ID в рамках соединения (требует tracking)—

ip_id применяется к каждому отправляемому пакету (включая под-сегменты при MSS-сегментации для TCP, см. Автосегментация по MSS).


F) Standard ipfrag

IP-фрагментация фейковых пакетов. Каждый пакет дополнительно фрагментируется на уровне IP.

Проще говоря: пакет-фейк при отправке ещё раз делится на части, но уже средствами протокола IP, а собирает их обратно получатель на уровне IP.

ПараметрОписаниеПо умолчанию
ipfrag[=func]Включить IP-фрагментацию. Если без значения — ipfrag2—
ipfrag_disorderОтправить IP-фрагменты в обратном порядке—
ipfrag_pos_tcp=NПозиция фрагментации TCP (кратно 8)32
ipfrag_pos_udp=NПозиция фрагментации UDP (кратно 8). Актуально для QUIC-фейков8
ipfrag_next=NIPv6: next protocol во 2-м фрагменте (penetration атака на фаерволы)—

G) Standard reconstruct

Реконструкция — сборка готового raw-пакета («сырого», со всеми заголовками) перед отправкой.

ПараметрОписание
badsumИспортить L4 (TCP/UDP) checksum при реконструкции raw-пакета. Сервер отбросит такой пакет

H) Standard rawsend

Rawsend — отправка готовых пакетов в сеть самой функцией; в fake её выполняет rawsend_payload_segmented (см. Автосегментация по MSS). Эти параметры управляют отправкой.

ПараметрОписание
repeats=NОтправить каждый пакет/сегмент N раз (идентичные повторы)
ifout=<iface>Интерфейс для отправки (по умолчанию определяется автоматически)
fwmark=NFirewall mark (только Linux, nftables/iptables)

Автосегментация по MSS

MSS (Maximum Segment Size) — наибольший объём данных, который помещается в один TCP-сегмент данного соединения. Для TCP о размерах пакетов думать не нужно. Функция rawsend_payload_segmented из zapret-lib.lua автоматически:

  1. Отслеживает MSS для каждого TCP-соединения
  2. Если blob превышает MSS — автоматически режет по MSS
  3. Каждый под-сегмент отправляется с корректным TCP sequence

Пример: blob из 10000 байт при MSS=1460 будет отправлен как 7 TCP-сегментов (6 x 1460 + 1 x 240).

Проще говоря

Даже длинный фейк можно не готовить заранее: функция сама нарежет его на пакеты допустимого размера и проставит каждому правильный seq.

Для UDP сегментации нет — blob отправляется как один UDP-пакет. Если blob больше MTU, пакет будет фрагментирован на уровне IP (или отброшен, если DF-бит установлен). MTU — наибольший размер пакета, который проходит по каналу без разбиения на части, а DF-бит (Don’t Fragment) — флаг «не фрагментировать».


Поведение при replay / reasm

Многопакетный запрос (тот, что не влез в один пакет) nfqws2 придерживает, собирает в буфер reasm_data (reasm — повторная сборка) и перепроигрывает через desync-функции: replay (перепроигрывание) означает, что движок по очереди вызывает функции на каждой придержанной части. Механика описана в жизненный цикл desync-функции, стадия 6. fake использует из неё только половину: срабатывает на первой части (replay_first) и молчит на остальных, логируя «not acting on further replay pieces».

Вторую половину развилки — дроп последующих частей — fake не применяет, потому что ему нечего дропать: он не отправляет реальные данные, а лишь добавляет фейк. Поэтому все части replay проходят дальше по цепочке инстансов, и стоящая следом multisplit или multidisorder нарежет собранный реасм как обычно.

Проще говоря

Фейку хватает одного срабатывания на первой части запроса, а остальные части идут дальше нетронутыми: их обработает следующая функция в цепочке, например multisplit, который на первой части режет и отправляет весь собранный буфер.


Псевдокод алгоритма

Ниже — запись тела fake на Lua, чтобы видно было, в каком порядке функция проверяет условия и что отправляет. Тело функции целиком, включая общие для всех техник стадии — они пронумерованы так же, как в жизненный цикл desync-функции:

function fake(ctx, desync)
    -- 1. Cutoff противоположного направления
    direction_cutoff_opposite(ctx, desync)
 
    -- 2. Проверка: только TCP или UDP
    if not (desync.dis.tcp or desync.dis.udp) then return end
 
    -- 3. Проверки: направление OK, payload OK
    if not direction_check(desync) then return end
    if not payload_check(desync) then return end
 
    -- 4. Только первый replay
    if replay_first(desync) then
 
        -- 5. blob обязателен
        if not desync.arg.blob then
            error("fake: 'blob' arg required")
        end
 
        -- 6. optional: тихий пропуск если blob нет
        if optional and not blob_exist(desync, desync.arg.blob) then
            DLOG("fake: blob not found. skipped")
            return  -- НЕ error, просто return
        end
 
        -- 7. Загрузка blob
        fake_payload = blob(desync, desync.arg.blob)
 
        -- 8. tls_mod (только если есть reasm_data)
        if desync.reasm_data and desync.arg.tls_mod then
            fake_payload = tls_mod_shim(desync, fake_payload,
                                         desync.arg.tls_mod,
                                         desync.reasm_data)
        end
 
        -- 9. Отправка (с fooling, ipid, reconstruct, ipfrag, rawsend)
        rawsend_payload_segmented(desync, fake_payload)
        -- НЕ возвращает вердикт!
    else
        DLOG("fake: not acting on further replay pieces")
    end
    -- 10. Нет return VERDICT_DROP — оригинал уходит
end

Ключевое отличие от multisplit: multisplit возвращает VERDICT_DROP после успешной отправки (оригинал блокируется), а fake ничего не возвращает (оригинал проходит). Псевдокод самого multisplit — в разделе Псевдокод алгоритма его статьи.

Проще говоря

Функция проверяет транспорт, направление и тип данных, на первой части запроса берёт blob, при необходимости применяет tls_mod, отправляет результат и выходит, ничего не решая насчёт оригинала.


Сравнение с syndata и fakedsplit

Таблица ниже сопоставляет fake с двумя ближайшими соседями. syndata работает на SYN-пакете (это самый первый пакет соединения, с него начинается рукопожатие TCP), а fakedsplit сам режет payload и вставляет фейки между частями.

Аспектfakesyndatafakedsplit
Когда работаетНа payload (после TCP handshake)На SYN-пакете (до handshake)На payload (после handshake)
ПротоколыTCP и UDPТолько TCPТолько TCP
Что делаетШлёт отдельный фейковый пакетВкладывает payload в SYNРежет payload + вставляет фейки между частями
ВердиктНет (оригинал проходит)VERDICT_DROP (заменяет SYN)VERDICT_DROP (заменяет оригинал)
blob обязателенДа (error если нет)Нет (дефолт: 16 нулевых байт)Нет (фейки из pattern)
tls_mod условиеНужен reasm_dataВсегда (payload=nil)Нет tls_mod
fooling к чемуК фейковым пакетамК SYN-пакетуТолько к фейковым сегментам
АвтосегментацияДа (TCP по MSS)Нет (должен влезть в 1 пакет)Да
Типичная позиция в цепочкеПервый (перед split)Самый первый (на SYN)Единственный (заменяет split)

Когда что использовать:

  • fake — когда нужен простой фейк перед реальным трафиком. Самый универсальный вариант, работает с TCP и UDP
  • syndata — когда DPI анализирует уже SYN-пакет. Очень ранняя стадия, но ограничен размером одного пакета
  • fakedsplit — когда нужно одновременно и нарезать, и подмешать фейки. Заменяет связку fake + multisplit, но ограничен одной позицией разреза

Сравнение с сегментирующими функциями — в статьях fakeddisorder (фейки + обратный порядок) и multisplit (чистая нарезка без фейков).


Нюансы и подводные камни

1. fake не делает DROP

Оригинальный пакет уйдёт следом (если другие инстансы не дропнут его). Это ожидаемое поведение — fake лишь добавляет фейковые пакеты перед оригиналом. DROP — вердикт «перехваченный пакет не отправлять»; как движок складывает вердикты разных инстансов, описано в стадии 8 жизненного цикла.

2. Без fooling фейк бесполезен или вреден

Если не задать fooling, сервер примет фейковый payload как настоящий. Для TCP это приведёт к рассинхронизации потока (данные с неверным seq будут интерпретированы неправильно). Для UDP сервер просто обработает фейковый пакет. Всегда используйте fooling (tcp_md5, badsum, ip_ttl=1, tcp_flags_unset=ACK, tcp_seq=-10000 и т.д.). Рассинхронизация здесь означает, что данные с неверным seq сервер интерпретирует неправильно. Пример ниже показывает, как выглядит такая ошибка в конфиге; каталог способов испортить фейк — в заметке про fooling.

Так делать НЕЛЬЗЯ — fake на TCP без ограничителей

--lua-desync=fake:blob=fake_tls_vk:repeats=2:strategy=4

Здесь нет ни одного fooling-параметра (tcp_md5, ip_ttl=, badsum, tcp_flags_unset=ack, tcp_seq=). Фейковый пакет уходит с валидными TCP seq, checksum и нормальным TTL → сервер принимает его как легитимные данные потока → приходит настоящий ClientHello с пересекающимся seq → рассинхронизация → гарантированный разрыв соединения.

Цитата bolvan (Zapret anti-DPI staff) по этому конфигу:

fake без ограничителей на tcp = гарантированный слом соединения. https скорее всего работает, потому что через warp, но без работать не будет.

То есть если кажется, что «работает» — это заслуга туннеля (WARP заворачивает реальный трафик в WireGuard/UDP, и битый fake-на-TCP по нему не бьёт), а не конфига. Убери WARP — голый HTTPS пойдёт по обычному TCP, и битый fake его сломает.

Примечание: параметра strategy= у fake нет (см. полный список аргументов) — он игнорируется и fooling не добавляет.

Как чинить — добавить любой ограничитель:

--lua-desync=fake:blob=fake_tls_vk:tcp_md5:repeats=2

Выбор fooling зависит от того, где относительно тебя стоит DPI: ip_ttl= работает, если DPI ближе клиента, чем сервер; tcp_md5/badsum/tcp_seq= — сервер отбросит фейк сам.

3. fake работает только на первом replay-куске

При многопакетных payload (реассемблированных) fake срабатывает ровно один раз — на первом куске. На последующих частях он ничего не делает. Это правильно: фейк нужен один раз, перед началом реальных данных. Что такое replay и почему fake срабатывает лишь на первой части, описано в разделе Поведение при replay / reasm.

4. tls_mod молча пропускается без reasm_data

Если вы задали tls_mod=rnd,rndsni, но reasm_data отсутствует (например, payload влез в один пакет и реассемблирование не потребовалось для некоторых конфигураций) — tls_mod просто не применится. Фейк будет отправлен с немодифицированным blob. Для гарантированных модификаций используйте --lua-init для подготовки blob заранее (пример — в разделе Когда tls_mod применяется, а когда нет).

5. blob обязателен — без optional будет Lua exception

Без blob=... функция вызывает error(). Это не тихий пропуск, а exception, который прервёт обработку всех инстансов для данного пакета. Если blob может отсутствовать — всегда указывайте optional. Lua exception — аварийная остановка выполнения Lua-кода с сообщением об ошибке; здесь её вызывает функция error().

6. Для UDP нет TCP-fooling

UDP не нумерует байты и не имеет TCP-заголовка с опциями; почему TCP-приёмы к нему неприменимы, разобрано в нюансе «Работает только с TCP» статьи про multisplit.

При использовании с UDP (QUIC) параметры tcp_md5, tcp_seq, tcp_ack, tcp_flags_unset и другие TCP-специфичные fooling не имеют смысла. Для UDP используйте IP-уровневые fooling: ip_ttl, ip6_ttl, badsum, ipfrag, IPv6 extension headers.

7. repeats может быть очень полезен

repeats=N отправляет каждый пакет/сегмент N раз. Для fake это означает N фейков подряд. Некоторые DPI сбрасывают состояние после N-го пакета, поэтому “заваливание” фейками (repeats=11 или repeats=20) может быть эффективнее одного.

8. Порядок инстансов: fake всегда первый

В типичной конфигурации fake стоит перед multisplit/multidisorder. Порядок важен: сначала уходит фейк, затем (следующий инстанс) нарезает и отправляет реальный payload. Если поставить fake после split — фейк уйдёт после реальных данных, что может быть неэффективно. Инстанс — одна запись --lua-desync=… в профиле; как инстансы выстраиваются в цепочку, описано в последовательность аргументов, а общий разбор порядка — в нюансе «Порядок инстансов важен» статьи про multisplit.

9. fake не отсекается на не-TCP/не-UDP

В отличие от multisplit (который делает instance_cutoff на не-TCP), fake просто ничего не делает для пакетов, не являющихся TCP или UDP. Он не отсекает себя — будет продолжать проверять следующие пакеты в потоке. Что такое instance_cutoff и почему он экономит ресурсы, описано в стадии 1 жизненного цикла.

10. padencap + реальный payload — тонкий трюк

padencap увеличивает длины в TLS-структуре фейка на размер реального payload. Идея: DPI увидит фейковый ClientHello с padding extension, длина которой “обещает” ещё N байт. Реальный ClientHello (следующий пакет) может быть воспринят DPI как продолжение padding, а не как отдельный ClientHello. Это работает только с DPI, которые реассемблируют TCP и парсят TLS record по полям длины. Реассемблирование — склейка данных из нескольких TCP-пакетов обратно в единый поток; см. также padencap — подробности.


Миграция с nfqws1

nfqws1 — движок первой версии zapret, у которого fake включался ключом --dpi-desync=fake. Ниже — как перенести такую настройку в nfqws2. Общая таблица соответствия флагов nfqws1 и nfqws2 лежит в обзоре desync.

Соответствие параметров

Слева ключи nfqws1, справа их запись в аргументах fake; тип payload в nfqws2 задаётся отдельным флагом --payload=….

nfqws1nfqws2
--dpi-desync=fake--lua-desync=fake:blob=<blob>
--dpi-desync-fake-http=<hex>--payload=http_req --lua-desync=fake:blob=<hex>
--dpi-desync-fake-tls=<hex|!>--payload=tls_client_hello --lua-desync=fake:blob=<hex|fake_default_tls>
--dpi-desync-fake-quic=<hex>--payload=quic_initial --lua-desync=fake:blob=<hex>
--dpi-desync-fake-tls-mod=<list>:tls_mod=<list>
--dpi-desync-fooling=md5sig:tcp_md5
--dpi-desync-fooling=badseq:tcp_seq=-10000
--dpi-desync-fooling=badack:tcp_ack=-66000
--dpi-desync-fooling=datanoack:tcp_flags_unset=ack
--dpi-desync-fooling=hopbyhop:ip6_hopbyhop
--dpi-desync-fooling=hopbyhop2:ip6_hopbyhop2
--dpi-desync-fooling=destopt:ip6_destopt
--dpi-desync-fooling=ipfrag1:ipfrag
--dpi-desync-ttl=N:ip_ttl=N:ip6_ttl=N
--dpi-desync-autottl=...:ip_autottl=...:ip6_autottl=...
--dpi-desync-repeats=N:repeats=N
--dpi-desync-badseq-increment=N:tcp_seq=N
--dpi-desync-badack-increment=N:tcp_ack=N
--dpi-desync-any-protocolНе нужно; или payload=all в инстансе

Ключевое отличие: в nfqws1 fake был “глобальный”

В nfqws1 --dpi-desync=fake автоматически выбирал blob по типу payload: для TLS — --dpi-desync-fake-tls, для HTTP — --dpi-desync-fake-http, для QUIC — --dpi-desync-fake-quic. В nfqws2 blob задаётся вручную, и для разных payload нужны отдельные инстансы.

Проще говоря

В nfqws1 достаточно было включить --dpi-desync=fake: движок сам выбирал blob по типу данных, по ключам --dpi-desync-fake-tls, --dpi-desync-fake-http и --dpi-desync-fake-quic. В nfqws2 вы сами говорите, какой blob для какого типа данных, и для каждого типа пишете свой инстанс.

Пример полной миграции: fake с TTL

Ключ --dpi-desync-fake-http превращается в --payload=http_req и blob=…, а --dpi-desync-ttl — в пару ip_ttl и ip6_ttl.

# nfqws1:
nfqws --dpi-desync=fake \
  --dpi-desync-fake-http=0x00000000 \
  --dpi-desync-ttl=6
 
# nfqws2 (эквивалент):
nfqws2 \
  --payload=http_req \
    --lua-desync=fake:blob=0x00000000:ip_ttl=6:ip6_ttl=6

Пример полной миграции: fake с tls_mod + datanoack

--dpi-desync-fooling=datanoack становится tcp_flags_unset=ack, а --dpi-desync-fake-tls=! — стандартным blob-ом fake_default_tls; список --dpi-desync-fake-tls-mod переносится в tls_mod=; в эквиваленте к нему добавлен padencap, которого в записи nfqws1 не было.

# nfqws1:
nfqws --dpi-desync=fake \
  --dpi-desync-fooling=datanoack \
  --dpi-desync-fake-tls=! \
  --dpi-desync-fake-tls-mod=rnd,rndsni,dupsid
 
# nfqws2 (эквивалент):
nfqws2 \
  --payload=tls_client_hello \
    --lua-desync=fake:blob=fake_default_tls:tcp_flags_unset=ack:tls_mod=rnd,rndsni,dupsid,padencap

Пример полной миграции: fake + multisplit

Одна команда nfqws1 с fake,multisplit разделяется на отдельные инстансы: для TLS и HTTP нужны разные blob-ы, поэтому fake пишется дважды, а multisplit получает свои аргументы, включая seqovl и seqovl_pattern.

# nfqws1:
nfqws --dpi-desync=fake,multisplit \
  --dpi-desync-fooling=md5sig \
  --dpi-desync-split-pos=1,midsld \
  --dpi-desync-split-seqovl=5 \
  --dpi-desync-split-seqovl-pattern=0x1603030000 \
  --dpi-desync-fake-tls-mod=rnd,rndsni,dupsid
 
# nfqws2 (эквивалент — отдельные инстансы):
nfqws2 \
  --payload=tls_client_hello \
    --lua-desync=fake:blob=fake_default_tls:tcp_md5:tls_mod=rnd,rndsni,dupsid \
  --payload=http_req \
    --lua-desync=fake:blob=fake_default_http:tcp_md5 \
  --payload=tls_client_hello,http_req \
    --lua-desync=multisplit:pos=1,midsld:seqovl=5:seqovl_pattern=0x1603030000

Практические примеры

Двадцать готовых вариантов: от минимального фейка до связок с другими функциями. К большинству добавлено короткое пояснение, что произойдёт с пакетом.

1. Минимальный TLS-фейк (обязателен blob + fooling)

--payload=tls_client_hello --lua-desync=fake:blob=fake_default_tls:tcp_md5

Отправляет стандартный фейковый ClientHello с www.w3.org, сервер отбросит из-за TCP MD5 option.

2. Минимальный HTTP-фейк

--payload=http_req --lua-desync=fake:blob=fake_default_http:tcp_md5

То же, что в первом примере, но для HTTP: стандартный blob fake_default_http (см. Стандартные blob-ы), а сервер отбросит фейк из-за TCP MD5 option.

3. QUIC (UDP) фейк с TTL

--payload=quic_initial --lua-desync=fake:blob=fake_default_quic:ip_ttl=1:ip6_ttl=1

Для UDP TCP-fooling невозможен, используем TTL=1 — фейк не дойдёт до сервера. См. нюанс «Для UDP нет TCP-fooling».

4. optional: тихо пропустить, если blob не загружен

--lua-desync=fake:blob=cloned_ch:optional:tcp_md5

Если blob cloned_ch не был создан предыдущим инстансом — пропуск без ошибки.

5. Множественные повторы фейка

--payload=tls_client_hello --lua-desync=fake:blob=fake_default_tls:tcp_md5:repeats=11

11 одинаковых фейков подряд. Эффективно против DPI, который “считает” пакеты. См. нюанс «repeats может быть очень полезен».

6. rnd: рандомизировать Random и Session ID

--payload=tls_client_hello --lua-desync=fake:blob=fake_default_tls:tcp_md5:tls_mod=rnd

Каждый фейк будет с уникальным Random и Session ID.

7. rndsni: случайный SNI в фейке

--payload=tls_client_hello --lua-desync=fake:blob=fake_default_tls:tcp_md5:tls_mod=rndsni

SNI в фейке будет случайным доменом (DPI не увидит ни реальный, ни www.w3.org).

8. sni=domain: конкретный SNI в фейке

--payload=tls_client_hello --lua-desync=fake:blob=fake_default_tls:tcp_md5:tls_mod=sni=www.google.com

DPI увидит www.google.com в фейке. Полезно, если DPI блокирует по whitelist.

9. sni=%var: подстановка SNI из переменной

--lua-init="target='www.google.com'" \
--payload=tls_client_hello \
  --lua-desync=fake:blob=fake_default_tls:tcp_md5:tls_mod=sni=%target

Домен для SNI берётся из глобальной Lua-переменной target, которую задаёт --lua-init; порядок поиска переменной описан в разделе Подстановка sni=%var.

10. dupsid: копирование Session ID из реального ClientHello

--payload=tls_client_hello --lua-desync=fake:blob=fake_default_tls:tcp_md5:tls_mod=rnd,dupsid

Session ID фейка совпадёт с реальным — DPI может привязать фейк к текущей сессии.

11. Полный набор tls_mod (типовой пресет)

--payload=tls_client_hello \
  --lua-desync=fake:blob=fake_default_tls:tcp_md5:tls_mod=rnd,rndsni,dupsid,padencap

Максимальная маскировка фейка: случайные Random/SID, случайный SNI, скопированный реальный SID, padencap.

12. TTL-fooling (жёсткий фейк)

--payload=tls_client_hello --lua-desync=fake:blob=fake_default_tls:ip_ttl=1:ip6_ttl=1

Фейк умрёт на первом хопе. Работает, если DPI стоит ближе к клиенту, чем сервер.

13. datanoack + badsum (комбинированный fooling)

--payload=tls_client_hello \
  --lua-desync=fake:blob=fake_default_tls:badsum:tcp_flags_unset=ack:tls_mod=rnd,dupsid,padencap

Два уровня защиты: испорченная контрольная сумма + снятый ACK.

14. IP-фрагментация фейка (TCP)

--payload=tls_client_hello --lua-desync=fake:blob=fake_default_tls:tcp_md5:ipfrag:ipfrag_pos_tcp=32

Фейк фрагментируется на IP-уровне. DPI может не уметь реассемблировать IP-фрагменты. Параметры разобраны в разделе F) Standard ipfrag.

15. IP-фрагментация фейка (UDP/QUIC) в обратном порядке

--payload=quic_initial --lua-desync=fake:blob=fake_default_quic:ipfrag:ipfrag_pos_udp=8:ipfrag_disorder

QUIC-фейк фрагментируется на уровне IP: ipfrag_pos_udp=8 задаёт позицию фрагментации для UDP (кратно 8, по умолчанию 8), а ipfrag_disorder отправляет IP-фрагменты в обратном порядке. Параметры описаны в разделе F) Standard ipfrag.

16. Произвольный hex blob (нулевые байты)

--payload=http_req --lua-desync=fake:blob=0x00000000:ip_ttl=6:ip6_ttl=6

4 нулевых байта как фейк. DPI увидит “мусор” перед реальным HTTP.

17. Боевая связка: fake + multisplit для YouTube

--filter-tcp=443 --hostlist=youtube.txt \
  --lua-desync=fake:blob=fake_default_tls:tcp_md5:repeats=11 \
  --lua-desync=multisplit:pos=1,midsld

11 фейков подряд (с MD5 fooling) + реальный payload разрезан на 3 части. Как multisplit режет по маркерам, описано в разделе Маркеры позиций (pos).

18. Боевая связка: fake + multisplit + seqovl

--payload=tls_client_hello \
  --lua-desync=fake:blob=fake_default_tls:tcp_md5:tls_mod=rnd,rndsni,dupsid \
  --lua-desync=multisplit:pos=1,midsld:seqovl=5:seqovl_pattern=0x1603030000

Фейк с полным tls_mod, затем реальный payload нарезан с seqovl. Приём seqovl разобран в разделе seqovl — скрытый фейк внутри сегмента.

19. fake с клонированным ClientHello (двухинстансная схема)

--payload=tls_client_hello \
  --lua-desync=tls_client_hello_clone:blob=cloned_ch:sni_del:sni_add=www.google.com \
  --lua-desync=fake:blob=cloned_ch:optional:tcp_md5

Первый инстанс клонирует реальный ClientHello и подменяет SNI. Второй — отправляет клон как фейк. Флаг optional нужен на случай, если payload не TLS и клон не создан (см. нюанс 5).

20. fake для нескольких протоколов (отдельные профили)

--payload=tls_client_hello \
  --lua-desync=fake:blob=fake_default_tls:tcp_md5:tls_mod=rnd,rndsni,dupsid,padencap \
  --lua-desync=multisplit:pos=1,midsld \
--payload=http_req \
  --lua-desync=fake:blob=fake_default_http:tcp_md5 \
  --lua-desync=multisplit:pos=host,midsld \
--payload=quic_initial \
  --lua-desync=fake:blob=fake_default_quic:ip_ttl=1:ip6_ttl=1

Для каждого протокола — свой blob и свой fooling. Как --payload= разделяет профиль на такие блоки, описано в заметке о типах payload и в анатомии профиля.


📚 См. также

  • desync — обзор всех функций --lua-desync и общий контракт: кто вызывает функцию, что ей передаёт и как складываются вердикты
  • жизненный цикл desync-функции — восемь стадий, общих для всех техник дурения, и отличия fake от общего скелета
  • структура desync и диссекта — устройство таблицы desync и диссекта пакета, в том числе reasm_data
  • ts-and-fooling — зачем фейк обязан умереть до сервера и какие бывают способы его испортить
  • blob — как объявлять и передавать данные для аргумента blob
  • payload — типы payload и фильтр --payload
  • multisplit · multidisorder — сегментация, с которой fake чаще всего комбинируют
  • fakedsplit · fakeddisorder — разрез с подмешиванием фейковых сегментов
  • syndata — payload в SYN-пакете
  • verify-strategy — как честно проверить, работает ли подобранная комбинация
  • последовательность аргументов — как выстраивается цепочка инстансов в профиле
  • profile · preset — где --lua-desync живёт среди остальных настроек
  • DPI и ТСПУ — как устроена инспекция трафика, против которой работает fake

Источники: lua/zapret-antidpi.lua:438-461, lua/zapret-lib.lua:625-636 (tls_mod_shim), lua/zapret-lib.lua:1194-1203 (rawsend_payload_segmented), docs/manual.md:3991-4009, docs/manual.md:2425-2442 из репозитория zapret2.


🤖 Эти статьи открыты — можно обучать на них ИИ

При желании вы можете натренировать ИИ на наших статьях. Исходное форматирование доступно в Forgejo: исходник этой заметки · скачать весь репозиторий одним zip-архивом.