🧨 Десинхронизация: флаг --lua-desync

О чём заметка

Обзор --lua-desync — главного механизма обхода DPI в Zapret 2: что это за флаг, как он вызывается для каждого пакета и какие бывают функции-стратегии. Это заметка-хаб: здесь общая картина и каталог функций со ссылками, а детальные аргументы каждой функции — в её собственной заметке (multisplit, fake и т. д.). Устройство входных данных функции (ctx, desync, диссект, track) вынесено в структура desync и диссекта. Где --lua-desync стоит среди других полей — см. профиль и пресет, а где вызов происходит в общем конвейере — схема обработки трафика.

Что такое --lua-desync

DPI (Deep Packet Inspection) блокирует соединения, распознавая в трафике сигнатуры — домен в SNI у TLS, Host: у HTTP. Чтобы обойти блокировку, пакеты нужно так изменить или дополнить, чтобы DPI не собрал корректную картину, а сервер-получатель — собрал. В Zapret 2 вся эта логика вынесена из C-ядра в Lua-функции (почему так — структура проекта), и подключаются они флагом --lua-desync.

--lua-desync вызывает одну Lua-функцию для каждого пакета, прошедшего через фильтры профиля. Синтаксис:

--lua-desync=<функция>[:параметр1=значение1[:параметр2=значение2]]

Флаг можно указать несколько раз — каждый вызов называется инстансом, и инстансы выполняются строго по порядку задания (порядок важен: сначала фейк, потом нарезка — не то же самое, что наоборот; см. последовательность аргументов). Параметры пишутся через двоеточие: param=value — со значением, param без значения = true.

Как это работает по шагам

Пакет проходит через фильтры профиля (--filter-tcp, --filter-l7, --hostlist) → если соответствует, вызывается Lua-функция инстанса → функция выполняет действие (отправляет фейк, разбивает пакет, модифицирует заголовки) → возвращает вердикт (VERDICT_PASS, VERDICT_MODIFY, VERDICT_DROP), который агрегируется по всей цепочке инстансов.


🔗 Что функция получает, что отдаёт и как связана с C-ядром

Это раздел про контракт desync-функции: где она живёт, кто её вызывает, что подаётся ей на вход, что она возвращает и как это стыкуется с C-ядром nfqws2. Понимание этого контракта — ключ ко всем отдельным техникам (fake, multisplit, multidisorder и др.): все они устроены по одной схеме.

Где desync-функция стоит в структуре проекта

Zapret 2 состоит из двух половин (подробно — в структура проекта): быстрое C-ядро nfqws2 и Lua-код с логикой обхода. desync-функции — это как раз Lua: они лежат в файле zapret-antidpi.lua (плюс базовые в zapret-lib.lua). Само C-ядро обхода не делает — оно только перехватывает, разбирает и отправляет пакеты, а решение, что с пакетом сделать, отдаёт в Lua.

Момент вызова — предпоследняя стадия конвейера обработки пакета. К этому времени C-ядро уже перехватило пакет из ядра ОС, разобрало его (диссекция), привязало к потоку (conntrack), определило тип пейлоада и выбрало профиль. Дальше ядро идёт по инстансам профиля (каждый --lua-desync=... — один инстанс) строго по порядку и для каждого вызывает Lua-функцию.

Инстанс — это один вызов

Инстанс = один экземпляр вызова Lua-функции из профиля, заданный одним флагом --lua-desync. Одна и та же функция может быть вызвана несколько раз с разными параметрами — это разные инстансы. Порядок инстансов принципиален (см. последовательность аргументов).

Сигнатура: два параметра на входе

Каждая desync-функция объявляется с двумя аргументами:

function fake(ctx, desync)   -- пример: функция fake
  • ctx — «контекст», непрозрачный мост к C-коду. Сам по себе он ничего не значит для чтения; его передают обратно в C-функции (отправка пакетов, cutoff), чтобы те знали, к какому пакету/очереди относится вызов. Грубо говоря, ctx — это «телефонная линия обратно в ядро».
  • desync — большая Lua-таблица со всеми данными обрабатываемого пакета и его потока. Это главный вход: из неё функция читает всё, что ей нужно. Полный разбор всех полей (arg, dis, track, reasm/replay и пр.) — в отдельной заметке структура desync и диссекта.

Проще говоря

desync — это «что за пакет и что мы про него знаем» (данные, которые C передал в Lua). ctx — это «как достучаться обратно до C, чтобы что-то отправить или отключиться». Первое читают, второе используют как ручку для команд.

Что функция делает в середине

Получив desync, инстанс может:

  • читать поля пакета и потока (диссект, тип пейлоада, счётчики conntrack, собранный reasm);
  • создавать копии текущего диссекта, менять в них поля (sequence number, TTL, флаги, payload) и генерировать собственные диссекты (например, фейковый ClientHello);
  • отправлять эти диссекты сырыми пакетами прямо в сеть — через C-функции вроде rawsend_* (именно тут используется ctx). Это происходит немедленно, ещё до того как функция вернёт вердикт;
  • хранить состояние: в самой таблице desync — для передачи данных следующим инстансам этого же пакета; в desync.track.lua_state — для данных, живущих между пакетами одного потока (эту таблицу C выдаёт одну и ту же на каждый пакет потока).

Что функция отдаёт: два вида выхода

У desync-функции, как и у multisplit, два «выхода», и их важно различать.

1. Побочный эффект — уже отправленные пакеты. Основную работу фейка или нарезки функция делает не через return, а вызовами отправки (rawsend_*) прямо посреди тела. К моменту return фейковые/нарезанные пакеты уже улетели в сеть.

2. Возвращаемое значение — вердикт оригинальному пакету. Перехваченный пакет всё ещё ждёт решения. Функция возвращает одно из:

ВердиктЧто значит
VERDICT_PASSне делать с оригиналом ничего (пропустить как есть)
VERDICT_MODIFYв конце всей цепочки отправить изменённое содержимое диссекта
VERDICT_DROPвыбросить оригинал (например, потому что данные уже ушли нарезанными)
nil (без return)бездействие — функция решила не вмешиваться

Агрегация по цепочке. Вердикты всех инстансов профиля объединяются по приоритету: MODIFY перебивает PASS, а DROP перебивает и PASS, и MODIFY. Достаточно одному инстансу вернуть DROP — оригинал будет выброшен, что бы ни вернули соседи (иначе, например, при нарезке сервер получил бы данные дважды).

Управляющий «выход» — cutoff. Кроме вердикта функция может управлять своим будущим: instance_cutoff отключает этот инстанс от дальнейших пакетов потока по направлению, lua_cutoff отключает направление потока от всей Lua-обработки, а инстанс-оркестратор может вовсе взять управление остальной цепочкой на себя. Это способ сэкономить CPU и строить динамические сценарии (подробнее — схема обработки трафика, стадия про cutoff).

Связь C ↔ Lua одной картинкой

  • Из C в Lua передаётся desync — данные: диссект, conntrack, тип пейлоада, аргументы инстанса, replay-инфо. C уже сделал всю «тяжёлую» работу (перехват, разбор, отслеживание потока) и сложил результат в таблицу.
  • Из Lua в C идут команды — через ctx: отправить сырой пакет, испортить checksum, поставить cutoff. Плюс вердикт через return — что C сделать с оригиналом в конце.

Такое разделение и есть главная идея Zapret 2: медленную логику обхода можно править в текстовых Lua-файлах без перекомпиляции C-ядра.


📦 Доступные функции из zapret-antidpi.lua

Аргументы

КатегорияАргументОписание
Directiondirin | out | any
Foolingip_ttl=NTTL для IPv4
ip6_ttl=NTTL для IPv6
ip_autottl=delta,min-maxАвто-определение TTL
ip6_autottl=delta,min-maxАвто-определение TTL для IPv6
ip6_hopbyhop[=hex]Добавить hop-by-hop заголовок
ip6_hopbyhop2[=hex]Второй hop-by-hop
ip6_destopt[=hex]Destopt заголовок
ip6_destopt2[=hex]Второй destopt
ip6_routing[=hex]Routing заголовок
ip6_ah[=hex]Authentication заголовок
tcp_seq=NДобавить N к tcp.th_seq
tcp_ack=NДобавить N к tcp.th_ack
tcp_ts=NДобавить N к timestamp
tcp_md5[=hex]Добавить MD5 опцию
tcp_flags_set=Установить TCP флаги
tcp_flags_unset=Снять TCP флаги
tcp_ts_upПереместить timestamp наверх
fool=Кастомная функция fooling
ReconstructbadsumНевалидная L4 checksum
RawsendrepeatsСколько раз отправить пакет
ifoutOverride исходящего интерфейса
fwmarkOverride fwmark
PayloadpayloadСписок разрешённых типов payload
IP_IDip_idseq|rnd|zero|none
ip_id_connСохранять ip_id между пакетами
IPfragipfrag[=func]Функция фрагментации (default: ipfrag2)
ipfrag_disorderОтправить фрагменты в обратном порядке
ipfrag_pos_udpПозиция UDP фрагмента (default: 8)
ipfrag_pos_tcpПозиция TCP фрагмента (default: 32)
ipfrag_nextNext protocol для второго фрагмента IPv6

Базовые:

ФункцияОписание
dropОтбросить пакет
sendОтправить пакет как есть (с возможной модификацией заголовков)
pktmodМодифицировать заголовки пакета (fooling)
ФункцияStd argsСпецифичные args
dropdirection, payload-
senddirection, fooling, ip_id, ipfrag, rawsend, reconstruct-
pktmoddirection, fooling, ip_id-

HTTP модификации:

ФункцияОписание
http_domcaseИзменить регистр домена (HoSt)
http_hostcaseИзменить регистр заголовка Host
http_methodeolМодифицировать конец строки метода

TCP сплит и disorder:

ФункцияОписание
multisplitРазбить пакет на несколько TCP сегментов
multidisorderРазбить + отправить в обратном порядке
tcpsegTCP сегментация
ФункцияStd argsСпецифичные args
multisplitdirection, payload, fooling, ip_id, rawsend, reconstruct, ipfragpos= (default: “2”), seqovl=N, seqovl_pattern=, blob=, nodrop
multidisorderdirection, payload, fooling, ip_id, rawsend, reconstruct, ipfragpos= (default: “2”), seqovl=N, seqovl_pattern=, blob=, nodrop
tcpsegdirection, payload, fooling, ip_id, rawsend, reconstruct, ipfragpos= (обязательный, 2 позиции), seqovl=N, seqovl_pattern=, blob=

Fake-атаки:

ФункцияОписание
fakeОтправить fake пакет
fakedsplitFake + сплит оригинала
fakeddisorderFake + disorder оригинала
hostfakesplitFake только для хоста + сплит
ФункцияStd argsСпецифичные args
fakedirection, payload, fooling, ip_id, rawsend, reconstruct, ipfragblob= (обязательный), tls_mod= (rnd,rndsni,sni=,dupsid,padencap)
fakedsplitdirection, payload, fooling, ip_id, rawsend, reconstructpos= (default: “2”), nofake1, nofake2, nofake3, nofake4, pattern=, seqovl=N, seqovl_pattern=, blob=, nodrop
fakeddisorderdirection, payload, fooling, ip_id, rawsend, reconstructpos= (default: “2”), nofake1-4, pattern=, seqovl=N, seqovl_pattern=, blob=, nodrop
hostfakesplitdirection, payload, fooling, ip_id, rawsend, reconstructhost= (шаблон хоста), midhost=, nofake1, nofake2, disorder_after=, blob=, nodrop

SYN-атаки:

ФункцияОписание
syndataОтправить SYN с данными
synackРабота с SYN/ACK
synack_splitСплит по SYN/ACK

Window size:

ФункцияОписание
wsizeИзменить window size на SYN-ACK
wssizeИзменить window size на всех пакетах

Прочее:

ФункцияОписание
rstОтправить RST
udplenИзменить длину UDP
dht_dnDHT domain name injection

Из zapret-lib.lua:

ФункцияОписание
passНичего не делать (для отладки)
pktdebugВывести содержимое desync в лог
argdebugВывести аргументы в лог
posdebugВывести позиции conntrack
luaexecВыполнить произвольный Lua код

💡 Примеры использования

Простой fake:

--lua-desync=fake:blob=fake_default_tls

Fake с параметрами:

--lua-desync=fake:blob=fake_default_tls:tcp_md5:ip_ttl=3:repeats=5

Multisplit:

--lua-desync=multisplit:pos=1,midsld

Комбинация функций:

--lua-desync=fake:blob=fake_default_tls:tcp_md5 \
--lua-desync=multisplit:pos=1,midsld

С фильтром payload:

--payload=tls_client_hello --lua-desync=fake:blob=fake_default_tls \
--payload=http_req --lua-desync=fake:blob=fake_default_http

📊 Структура параметров

--lua-desync=функция:param1=val1:param2=val2:param3
            ─────────┬─────────────────────────────

         параметры через двоеточие

Типы параметров:

  • param=value — параметр со значением
  • param — булевый параметр (без значения = true)

🔍 Что получает функция — кратко

Второй параметр — таблица desync — это весь вход функции. Коротко её ключевые части:

  • desync.arg — аргументы этого инстанса (всё после двоеточий в --lua-desync); значения приходят строками, флаг без значения = "" (в Lua истинно).
  • desync.dis — диссект: разобранный на поля текущий пакет (ip/ip6, tcp/udp, payload).
  • desync.l7payload / desync.outgoing — тип содержимого пакета и направление.
  • desync.track — данные потока из conntrack (может отсутствовать!); внутри track.lua_state — память, живущая между пакетами потока.
  • desync.reasm_data / decrypt_data + поля replay* — собранные из нескольких пакетов пейлоады.

Увидеть полное содержимое desync на конкретном пакете можно инстансом pktdebug.

Полный справочник по всем полям — в отдельной заметке

Прототип функции, все вердикты (включая VERDICT_PRESERVE_NEXT), полная структура desync, диссекта (ip/ip6/tcp/udp/icmp, exthdr, tcp options), track со счётчиками, механика reasm/replay, работа с 32-битными sequence и обработка ICMP/raw IP — всё это подробно разобрано в структура desync и диссекта.


🎯 Полный пример

winws2 ^
  --wf-tcp-out=80,443 ^
  --lua-init=@zapret-lib.lua --lua-init=@zapret-antidpi.lua ^
  --filter-tcp=80 --filter-l7=http ^
  --payload=http_req --lua-desync=fake:blob=fake_default_http:tcp_md5 ^
  --lua-desync=multisplit:pos=method+2 ^
  --new ^
  --filter-tcp=443 --filter-l7=tls ^
  --payload=tls_client_hello --lua-desync=fake:blob=fake_default_tls:tcp_md5:tls_mod=rnd,rndsni ^
  --lua-desync=multidisorder:pos=1,midsld

Итог

--lua-desync — это сердце nfqws2:

  • 🔹 Вызывает Lua функцию для каждого пакета
  • 🔹 Передаёт параметры через двоеточие
  • 🔹 Можно указывать несколько раз (выполняются последовательно)
  • 🔹 Работает с фильтрами --payload, --out-range, --in-range
  • 🔹 Можно писать свои функции

📋 Полная таблица функций --lua-desync

🔹 Базовые функции (zapret-lib.lua)

ФункцияОписаниеПараметры
passНичего не делает (для отладки)
pktdebugВыводит содержимое desync в лог
argdebugВыводит аргументы функции в лог
posdebugВыводит позиции conntrack в лог
luaexecВыполняет произвольный Lua кодcode=<lua_code>

🔹 Функции из zapret-antidpi.lua

Базовые действия

ФункцияАналог nfqws1ОписаниеПараметры
dropОтбросить пакетdir, payload
send--dupОтправить копию пакетаdir, fooling, ip_id, ipfrag, rawsend, reconstruct
pktmod--origМодифицировать текущий пакетdir, fooling, ip_id

HTTP модификации

ФункцияАналог nfqws1ОписаниеПараметры
http_domcase--domcaseИзменить регистр домена (HoSt)dir
http_hostcase--hostcaseИзменить регистр заголовка Hostdir, spell=<str> (4 символа)
http_methodeol--methodeolМодифицировать EOL методаdir, method=cr|lf|crlf|lfcr, no_space

SYN-атаки

ФункцияАналог nfqws1ОписаниеПараметры
syndata--dpi-desync=syndataОтправить SYN с даннымиblob=<blob>, tls_mod=<list>, fooling, rawsend, reconstruct, ipfrag
synackОтправить SYN-ACKfooling, rawsend, reconstruct, ipfrag
synack_splitСплит по SYN-ACKpos=<posmarker>, seqovl=N, seqovl_pattern=<blob>

Window size

ФункцияАналог nfqws1ОписаниеПараметры
wsize--wssizeИзменить window size на SYN-ACKwsize=N, scale=N
wssize--wssizeИзменить window size на всех пакетахwsize=N, scale=N

RST

ФункцияАналог nfqws1ОписаниеПараметры
rst--dpi-desync=rstОтправить RSTdir, payload, fooling, ip_id, rawsend, reconstruct, ipfrag, rstack

Fake-атаки

ФункцияАналог nfqws1ОписаниеПараметры
fake--dpi-desync=fakeОтправить fake пакетblob=<blob> (обязательный), tls_mod=<list>, dir, payload, fooling, ip_id, rawsend, reconstruct, ipfrag

Сплит и disorder

ФункцияАналог nfqws1ОписаниеПараметры
multisplit--dpi-desync=multisplitРазбить на TCP сегментыpos=<posmarker_list>, seqovl=N, seqovl_pattern=<blob>, blob=<blob>, nodrop
multidisorder--dpi-desync=multidisorderРазбить + обратный порядокpos=<posmarker_list>, seqovl=<posmarker>, seqovl_pattern=<blob>, blob=<blob>, nodrop
tcpsegTCP сегментация по диапазонуpos=<range> (обязательный), seqovl=N, seqovl_pattern=<blob>, blob=<blob>

Fake + сплит комбинации

ФункцияАналог nfqws1ОписаниеПараметры
hostfakesplit--dpi-desync=hostfakesplitFake только для хоста + сплитhost=<template>, midhost=<posmarker>, nofake1, nofake2, disorder_after=<posmarker>, blob=<blob>, nodrop
fakedsplit--dpi-desync=fakedsplitFake + сплит оригиналаpos=<posmarker>, nofake1, nofake2, nofake3, nofake4, pattern=<blob>, seqovl=N, seqovl_pattern=<blob>, blob=<blob>, nodrop
fakeddisorder--dpi-desync=fakeddisorderFake + disorder оригиналаpos=<posmarker>, nofake1, nofake2, nofake3, nofake4, pattern=<blob>, seqovl=<posmarker>, seqovl_pattern=<blob>, blob=<blob>, nodrop

UDP

ФункцияАналог nfqws1ОписаниеПараметры
udplen--dpi-desync=udplenИзменить длину UDP пакетаdir, payload, min=N, max=N, increment=N (по умолч. 2), pattern=<blob>, pattern_offset=N
dht_dn--dpi-desync=tamper (dht)DHT domain name injectiondir, dn=N (по умолч. 2)

🔧 Стандартные параметры (применимы ко многим функциям)

Direction (направление)

ПараметрОписание
dir=inТолько входящие пакеты
dir=outТолько исходящие (по умолчанию)
dir=anyОба направления

Payload фильтр

ПараметрОписание
payload=<type_list>Фильтр по типу payload

Fooling (обманки)

ПараметрОписание
ip_ttl=NУстановить TTL IPv4
ip6_ttl=NУстановить Hop Limit IPv6
ip_autottl=delta,min-maxАвтоматический TTL
ip6_autottl=delta,min-maxАвтоматический Hop Limit
ip6_hopbyhop[=hex]Добавить Hop-by-Hop заголовок
ip6_hopbyhop2[=hex]Второй Hop-by-Hop
ip6_destopt[=hex]Добавить Destination Options
ip6_destopt2[=hex]Второй Destination Options
ip6_routing[=hex]Добавить Routing заголовок
ip6_ah[=hex]Добавить Authentication Header
tcp_seq=NДобавить к TCP sequence
tcp_ack=NДобавить к TCP ack
tcp_ts=NДобавить к timestamp
tcp_md5[=hex]Добавить TCP MD5 опцию
tcp_flags_set=<list>Установить TCP флаги
tcp_flags_unset=<list>Снять TCP флаги
tcp_ts_upПереместить timestamp наверх
fool=<function>Пользовательская функция обманки

Reconstruct

ПараметрОписание
badsumНевалидная контрольная сумма L4

Rawsend

ПараметрОписание
repeats=NКоличество повторов
ifout=<iface>Интерфейс отправки
fwmark=Nfwmark пакета

IP ID

ПараметрОписание
ip_id=seq|rnd|zero|noneПолитика IP ID
ip_id_connСохранять IP ID между пакетами

IP фрагментация

ПараметрОписание
ipfrag[=function]Включить IP фрагментацию
ipfrag_disorderОтправить фрагменты в обратном порядке
ipfrag_pos_tcp=NПозиция фрагментации TCP (кратно 8)
ipfrag_pos_udp=NПозиция фрагментации UDP (кратно 8)
ipfrag_next=NNext proto для второго фрагмента

TLS модификации

ПараметрОписание
tls_mod=rndРандомизировать поле random
tls_mod=rndsniСлучайный SNI
tls_mod=sni=<domain>Установить конкретный SNI
tls_mod=dupsidКопировать Session ID
tls_mod=padencapPadding encapsulation

📍 Position markers (маркеры позиций)

МаркерОписание
NАбсолютная позиция (число)
-NПозиция с конца
hostНачало хоста
endhostКонец хоста
sldSecond-level domain
midsldСередина SLD
endsldКонец SLD
methodHTTP метод
extlenTLS extensions length
sniextTLS SNI extension
marker+NМаркер + смещение
marker-NМаркер - смещение

💡 Примеры

# Простой fake
--lua-desync=fake:blob=fake_default_tls:tcp_md5
 
# Fake с TTL и повторами
--lua-desync=fake:blob=fake_default_tls:ip_ttl=3:repeats=5:tls_mod=rnd,rndsni
 
# Multisplit с seqovl
--lua-desync=multisplit:pos=1,midsld:seqovl=10
 
# Fakedsplit
--lua-desync=fakedsplit:pos=midsld:nofake1:tcp_md5
 
# Комбинация fake + multidisorder
--lua-desync=fake:blob=fake_default_tls:tcp_md5 --lua-desync=multidisorder:pos=1,midsld
 
# UDP length
--lua-desync=udplen:increment=4:min=50

Соответствие флагов nfqws1 → nfqws2

В nfqws1 были готовые флаги --dpi-desync-fooling=. В nfqws2 их нет — вместо этого используются отдельные параметры для каждого действия.


📋 Таблица соответствия

nfqws1 флагnfqws2 параметрОписание
md5sigtcp_md5Добавить TCP MD5 signature опцию
badsumbadsumНевалидная контрольная сумма L4
badseqtcp_seq=-10000Сдвинуть TCP sequence (для SYN)
badseqtcp_ack=-66000Сдвинуть TCP ack (для данных)
datanoacktcp_flags_unset=ackСнять флаг ACK
badacktcp_ack=-66000Сдвинуть TCP ack
hopbyhopip6_hopbyhopIPv6 Hop-by-Hop header
hopbyhop2ip6_hopbyhop2Второй Hop-by-Hop header
destoptip6_destoptIPv6 Destination Options
destopt2ip6_destopt2Второй Destination Options
ipfrag1ipfragIP фрагментация

🔧 Детали каждого флага

md5sigtcp_md5

Добавляет TCP опцию MD5 signature (RFC 2385). DPI не может проверить подпись.

# nfqws1
--dpi-desync-fooling=md5sig
 
# nfqws2
--lua-desync=fake:blob=fake_default_tls:tcp_md5

badsumbadsum

Делает контрольную сумму TCP/UDP невалидной. Сервер отбросит пакет.

# nfqws1
--dpi-desync-fooling=badsum
 
# nfqws2
--lua-desync=fake:blob=fake_default_tls:badsum

badseqtcp_seq / tcp_ack

В nfqws1 badseq применял разные значения для SYN и обычных пакетов:

  • SYN пакеты: tcp_seq=-10000
  • Обычные пакеты: tcp_ack=-66000
# nfqws1
--dpi-desync-fooling=badseq
 
# nfqws2 (для обычных пакетов)
--lua-desync=fake:blob=fake_default_tls:tcp_ack=-66000
 
# nfqws2 (для SYN)
--lua-desync=fake:blob=fake_default_tls:tcp_seq=-10000

badacktcp_ack

Сдвигает TCP acknowledgment number.

# nfqws1
--dpi-desync-fooling=badack
 
# nfqws2
--lua-desync=fake:blob=fake_default_tls:tcp_ack=-66000

Важно! Для Linux нужен tcp_ts_up чтобы работало без badseq:

--lua-desync=fake:blob=fake_default_tls:tcp_ack=-66000:tcp_ts_up

datanoacktcp_flags_unset=ack

Снимает флаг ACK с пакета.

# nfqws1
--dpi-desync-fooling=datanoack
 
# nfqws2
--lua-desync=fake:blob=fake_default_tls:tcp_flags_unset=ack

hopbyhopip6_hopbyhop

Добавляет IPv6 Hop-by-Hop extension header.

# nfqws1
--dpi-desync-fooling=hopbyhop
 
# nfqws2
--lua-desync=fake:blob=fake_default_tls:ip6_hopbyhop

hopbyhop2ip6_hopbyhop2

Добавляет второй Hop-by-Hop header (нестандартно, ломает обработку).

# nfqws1
--dpi-desync-fooling=hopbyhop2
 
# nfqws2
--lua-desync=fake:blob=fake_default_tls:ip6_hopbyhop2

destoptip6_destopt

Добавляет IPv6 Destination Options header.

# nfqws1
--dpi-desync-fooling=destopt
 
# nfqws2
--lua-desync=fake:blob=fake_default_tls:ip6_destopt

ipfrag1ipfrag

IP фрагментация пакета.

# nfqws1
--dpi-desync-fooling=ipfrag1
 
# nfqws2
--lua-desync=send:ipfrag

💡 Примеры комбинаций

Классический fake с md5sig:

# nfqws1
--dpi-desync=fake --dpi-desync-fooling=md5sig
 
# nfqws2
--lua-desync=fake:blob=fake_default_tls:tcp_md5

Fake с badseq + md5sig:

# nfqws1
--dpi-desync=fake --dpi-desync-fooling=badseq,md5sig
 
# nfqws2
--lua-desync=fake:blob=fake_default_tls:tcp_ack=-66000:tcp_md5

Fake с TTL:

# nfqws1
--dpi-desync=fake --dpi-desync-ttl=3
 
# nfqws2
--lua-desync=fake:blob=fake_default_tls:ip_ttl=3

Fake с autottl:

# nfqws1
--dpi-desync=fake --dpi-desync-autottl=-1,3-20
 
# nfqws2
--lua-desync=fake:blob=fake_default_tls:ip_autottl=-1,3-20:ip6_autottl=-1,3-20

Fakedsplit с badseq + md5sig:

# nfqws1
--dpi-desync=fakedsplit --dpi-desync-fooling=badseq,md5sig --dpi-desync-split-pos=2
 
# nfqws2
--lua-desync=fakedsplit:pos=2:tcp_ack=-66000:tcp_md5

IPv6 hopbyhop + destopt:

# nfqws1
--dpi-desync=fake --dpi-desync-fooling=hopbyhop,destopt
 
# nfqws2
--lua-desync=fake:blob=fake_default_tls:ip6_hopbyhop:ip6_destopt

📝 Полный список fooling параметров nfqws2

ПараметрЗначениеОписание
tcp_md5[=hex]TCP MD5 signature (16 байт)
tcp_seq=NСдвиг TCP sequence
tcp_ack=NСдвиг TCP ack
tcp_ts=NСдвиг TCP timestamp
tcp_flags_set=listУстановить TCP флаги
tcp_flags_unset=listСнять TCP флаги
tcp_ts_upПереместить timestamp наверх
badsumНевалидная контрольная сумма
ip_ttl=NУстановить TTL
ip6_ttl=NУстановить Hop Limit
ip_autottl=delta,min-maxАвто TTL
ip6_autottl=delta,min-maxАвто Hop Limit
ip6_hopbyhop[=hex]Hop-by-Hop header
ip6_hopbyhop2[=hex]Второй Hop-by-Hop
ip6_destopt[=hex]Destination Options
ip6_destopt2[=hex]Второй Destination Options
ip6_routing[=hex]Routing header
ip6_ah[=hex]Authentication header

Быстрая шпаргалка

# md5sig
:tcp_md5
 
# badsum
:badsum
 
# badseq (для данных)
:tcp_ack=-66000
 
# badseq (для SYN)
:tcp_seq=-10000
 
# badack
:tcp_ack=-66000:tcp_ts_up
 
# datanoack
:tcp_flags_unset=ack
 
# TTL
:ip_ttl=3:ip6_ttl=3
 
# autottl
:ip_autottl=-1,3-20:ip6_autottl=-1,3-20
 
# IPv6 headers
:ip6_hopbyhop:ip6_destopt

Нет, badseq и badack — это разные вещи!


📊 Разница

ФлагЧто меняетПоле TCPТипичное значение
badseqSequence numbertcp.th_seq-10000
badackAcknowledgment numbertcp.th_ack-66000

🔬 Как работают

badseq (tcp_seq)

Сдвигает номер последовательности (sequence number) пакета.

Оригинальный пакет:  seq=1000, ack=5000
С badseq (-10000):   seq=-9000 (990), ack=5000
  • Сервер видит пакет с “неправильным” seq
  • Пакет не попадает в окно приёма → отбрасывается
  • DPI может обработать пакет, но сервер его игнорирует

badack (tcp_ack)

Сдвигает номер подтверждения (acknowledgment number) пакета.

Оригинальный пакет:  seq=1000, ack=5000
С badack (-66000):   seq=1000, ack=-61000
  • Сервер видит пакет с “неправильным” ack
  • Пакет может быть отброшен или обработан (зависит от ОС)
  • На Linux с опцией timestamp пакет может быть принят!

⚠️ Важный нюанс для Linux

На Linux badack без badseq может не работать, если есть TCP timestamp опция!

Linux отбрасывает пакеты с плохим ack только если timestamp опция идёт первой в списке TCP опций.

Поэтому в nfqws2 есть параметр tcp_ts_up — он перемещает timestamp наверх:

# Чтобы badack работал на Linux:
--lua-desync=fake:blob=fake_default_tls:tcp_ack=-66000:tcp_ts_up

📝 В nfqws1

В nfqws1 флаг badseq был универсальным и применял разные значения в зависимости от типа пакета:

Тип пакетаЧто менялосьЗначение
SYNtcp_seq-10000
Данныеtcp_ack-66000

Поэтому --dpi-desync-fooling=badseq фактически менял либо seq, либо ack в зависимости от контекста.


🎯 В nfqws2

В nfqws2 нет такой “магии” — вы явно указываете что хотите изменить:

# Изменить sequence (для SYN)
:tcp_seq=-10000
 
# Изменить ack (для данных)
:tcp_ack=-66000
 
# Изменить оба
:tcp_seq=-10000:tcp_ack=-66000

💡 Рекомендации

Для fake пакетов (данные):

# Вариант 1: badack с tcp_ts_up (надёжнее на Linux)
--lua-desync=fake:blob=fake_default_tls:tcp_ack=-66000:tcp_ts_up
 
# Вариант 2: md5sig (проще, работает везде)
--lua-desync=fake:blob=fake_default_tls:tcp_md5
 
# Вариант 3: TTL (если известно расстояние до DPI)
--lua-desync=fake:blob=fake_default_tls:ip_ttl=3

Для syndata (SYN пакеты):

--lua-desync=syndata:blob=fake_default_tls:tcp_seq=-10000

Итог

badseqbadack
ПолеSequenceAcknowledgment
nfqws2 параметрtcp_seq=Ntcp_ack=N
Типичное значение-10000-66000
Для SYN✅ Да❌ Нет
Для данных⚠️ Редко✅ Да
Нужен tcp_ts_upНетДа (на Linux)

Короткий ответ: badseq меняет seq, badack меняет ack — это разные поля TCP заголовка.

tcp_ts_up — нужен не всегда, но рекомендуется для Linux


🔍 Когда tcp_ts_up НУЖЕН

Только на Linux, и только если:

  1. Вы используете tcp_ack (badack) без tcp_seq (badseq)
  2. В пакете есть TCP timestamp опция

Почему?

Linux проверяет timestamp опцию для валидации пакетов. Но есть баг/особенность:

  • Linux отбрасывает пакеты с плохим ack только если timestamp идёт первой в списке TCP опций
  • Если timestamp не первая — пакет может быть принят несмотря на плохой ack!

tcp_ts_up перемещает timestamp в начало списка опций → Linux корректно отбрасывает пакет.


Когда tcp_ts_up НЕ нужен

  1. Целевой сервер — не Linux (Windows, BSD и др.)
  2. Используете tcp_seq (badseq) — тогда пакет отбрасывается по другой причине
  3. Используете tcp_md5 — md5sig работает независимо
  4. Используете ip_ttl — пакет не дойдёт до сервера
  5. В пакете нет timestamp опции — нечего перемещать

📊 Таблица: когда нужен tcp_ts_up

FoolingLinuxWindows/BSDtcp_ts_up нужен?
tcp_ack только⚠️ Может не работать✅ РаботаетДа (для Linux)
tcp_seq только✅ Работает✅ РаботаетНет
tcp_ack + tcp_seq✅ Работает✅ РаботаетНет
tcp_md5✅ Работает✅ РаботаетНет
ip_ttl✅ Работает✅ РаботаетНет

💡 Рекомендация

Если не уверены — добавляйте tcp_ts_up. Он не навредит, но гарантирует работу на Linux:

# Безопасный вариант (работает везде)
--lua-desync=fake:blob=fake_default_tls:tcp_ack=-66000:tcp_ts_up
 
# Или просто используйте md5sig — проще и надёжнее
--lua-desync=fake:blob=fake_default_tls:tcp_md5

🎯 Короткий ответ

Нет, не обязательно, но:

  • На Linux без tcp_ts_up badack может не сработать
  • На Windows/BSD работает и без него
  • Рекомендуется добавлять для универсальности

autottl — формат обязателен, значений по умолчанию нет!


Нельзя использовать без цифр

# ОШИБКА! Так нельзя:
--lua-desync=fake:blob=fake_default_tls:ip_autottl
 
# ОШИБКА! Так тоже нельзя:
--lua-desync=fake:blob=fake_default_tls:ip_autottl=

Будет ошибка:

parse_autottl: invalid value '...'

Обязательный формат

ip_autottl=delta,min-max
ip6_autottl=delta,min-max
ПараметрОписание
deltaСдвиг от вычисленного hop count (может быть отрицательным)
minМинимальное значение TTL
maxМаксимальное значение TTL

💡 Примеры

# Стандартный вариант: delta=-1, диапазон 3-20
:ip_autottl=-1,3-20:ip6_autottl=-1,3-20
 
# Более агрессивный: delta=-2
:ip_autottl=-2,3-20:ip6_autottl=-2,3-20
 
# Осторожный: delta=0 (точно до DPI)
:ip_autottl=0,3-20:ip6_autottl=0,3-20

🔬 Как работает autottl

  1. Получает incoming TTL из ответа сервера (SYN-ACK)
  2. Угадывает начальный TTL сервера (64, 128 или 255)
  3. Вычисляет hop count = начальный TTL - incoming TTL
  4. Применяет формулу: fake_ttl = hop_count + delta
  5. Ограничивает результат диапазоном min-max

Пример расчёта:

Incoming TTL = 52
Угаданный начальный TTL = 64
Hop count = 64 - 52 = 12
delta = -1
Результат = 12 + (-1) = 11

Если min=3, max=20: итоговый TTL = 11 ✓

⚠️ Важно

  • Требует conntrack — нужно видеть входящие пакеты для определения TTL
  • Не работает если incoming TTL не попадает в диапазоны (32-64, 96-128, 223-255)
  • Fallback на ip_ttl — если autottl не сработал, используется ip_ttl если указан
# С fallback на фиксированный TTL:
:ip_ttl=5:ip_autottl=-1,3-20

📝 Типичное использование

# Полный пример с autottl и fallback
--lua-desync=fake:blob=fake_default_tls:tcp_md5:ip_ttl=5:ip_autottl=-1,3-20:ip6_ttl=5:ip6_autottl=-1,3-20

📚 См. также

Где --lua-desync в общей картине:

  • Что такое профиль — блок, внутри которого живёт --lua-desync; как перебирать стратегии под свой DPI
  • Пресет — файл стратегии целиком (набор профилей)

Соседние поля профиля:

  • filter — фильтры (--filter-tcp/udp/l7, --hostlist, --ipset): какой трафик попадёт в desync
  • payload — типы содержимого пакета (--payload)
  • out-range — на каких по счёту пакетах срабатывать (--out-range)
  • blob — именованные заготовки пакетов (blob=…), на которые ссылаются fake/syndata

Отдельные техники десинхронизации:

Как это встроено в общую картину:

  • Жизненный цикл desync-функции — общий скелет всех техник: восемь стадий от отсева чужого транспорта до вердикта, и чем каждая функция от скелета отличается
  • Прототип и структура desync — полный справочник входных данных функции: ctx/desync, вердикты, диссект, track, reasm/replay, ICMP/raw IP
  • Структура проекта — почему логика обхода вынесена в Lua, а C-ядро её только вызывает
  • Схема обработки трафика — где именно в конвейере пакета вызываются desync-инстансы
  • multisplit — детальный разбор одной функции: что она получает в desync и что возвращает

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

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