todo/Zapret2/desync/syndata.md
loop-uh f4099f81c5 Чистка битых wikilinks по всему хранилищу
Исправлены ссылки с лишним префиксом Privacy/ (Hysteria/00-overview,
Zapret/download), несуществующие цели заменены: fooling → ts-and-fooling,
wssize и маркеры → обзор desync, genhost и instance_cutoff → инлайн-код.

Проверка obsidian unresolved: было 28 неразрешённых ссылок, осталась одна
в Zapret/home.md (отсутствующая картинка, файл владельца не трогаем).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-25 01:30:39 +03:00

40 KiB
Raw Permalink Blame History

date tags aliases
2026-02-17
zapret
zapret2
nfqws2
lua
lua-desync
antidpi
tcp
syndata
tls_mod
syndata

syndata --- payload в TCP SYN (zapret2 / nfqws2)

Файл: 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-сегментация), Zapret2/desync (управление размером окна), multidisorder, fakedsplit, fakeddisorder.

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


Оглавление


Зачем нужен syndata

Некоторые DPI начинают анализировать соединение уже с первого пакета --- с SYN. Они запоминают IP и порт клиента, ждут данные и сопоставляют их с сигнатурами. syndata атакует этот механизм на самом раннем этапе:

  1. Ложные данные в SYN: DPI видит SYN-пакет с payload (например, фейковый TLS ClientHello) и может принять его за начало реального соединения
  2. Сбой трекинга: если DPI привязывает сессию к содержимому первого пакета, подменный SYN может направить трекинг по ложному пути
  3. Обход до handshake: воздействие происходит до TCP handshake --- DPI ещё не видел реальных данных приложения

Важно: TCP SYN с payload --- это валидная TCP-операция (RFC 793 разрешает данные в SYN, хотя многие стеки их игнорируют до завершения handshake). Сервер примет SYN, но payload из него обычно отбросит --- 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

Принцип работы

Что такое 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)
  • Пропустить реальные данные, которые пойдут позже

Нулевая фаза

syndata --- стратегия нулевой фазы. В терминологии zapret это означает:

Фаза Когда Что доступно Примеры функций
Фаза 0 (SYN) До TCP handshake Только SYN-пакет. Нет payload от приложения syndata, [[Zapret2/desync
Фаза 1 (данные) После handshake, первые данные Реальный payload (TLS ClientHello, HTTP request и т.д.) fake, multisplit, fakedsplit

Следствия нулевой фазы:

  • Нет реального payload: приложение ещё ничего не отправило, поэтому syndata работает только с blob-данными или нулями
  • Нет hostname: на этом этапе zapret не знает, к какому домену обращается клиент --- хостлисты работают только через --ipcache-hostname
  • Нет payload filter: параметры --payload=... и payload=... не применимы --- SYN-пакет не содержит данных приложения
  • Воздействие на все ретрансмиссии SYN: если TCP-стек ретранслирует SYN (timeout), syndata обработает и его

Логика обработки пакетов

Пакет пришёл в 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)

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

Формат вызова:

--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 не вызывается.

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

blob

  • Формат: blob=<blobName>
  • Тип: имя blob-переменной
  • По умолчанию: 16 нулевых байт (\x00 x 16)
  • Описание: Payload, который будет добавлен в SYN-пакет. Должен помещаться в один пакет --- сегментация невозможна (используется rawsend_dissect_ipfrag, а не rawsend_payload_segmented). Если blob не задан, отправляются 16 нулевых байт
  • Примеры:
    • blob=fake_default_tls --- стандартный TLS-фейк из zapret
    • blob=fake_default_http --- стандартный HTTP-фейк
    • blob=0xDEADBEEF --- inline hex
    • blob=my_custom_payload --- предзагруженный blob
    • без blob= --- 16 нулей (дефолт)

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 --- рандомизация SNI
    • tls_mod=sni=google.com --- замена SNI
    • tls_mod=rnd,rndsni,sni=google.com --- комбинация
    • tls_mod=dupsid --- не даст ошибки, но молча проигнорируется

B) Standard fooling

Модификации L3/L4 заголовков. В syndata применяются к копии dissect (через apply_fooling после deepcopy). Оригинальный пакет не модифицируется --- он дропается.

Параметр Описание Пример
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.


C) Standard reconstruct

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

Предупреждение: badsum в syndata означает, что сервер не получит SYN вообще --- TCP handshake не состоится. Используйте только если хотите отправить "мусорный" SYN, за которым пойдёт ретрансмиссия.


D) Standard rawsend

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

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 атака на фаерволы) ---

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 от приложения). Это ключевой момент, определяющий какие модификации работают, а какие --- нет.

Работающие модификации

Мод Описание Работает? Причина
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 и 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".


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

Тело 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 не существует.


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

Тело функции целиком, включая общие для всех техник стадии — они пронумерованы так же, как в жизненный цикл 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 нет многопакетных данных

Отличия от 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 Не поддерживается Поддерживается

Когда использовать syndata вместо fake:

  • DPI начинает трекинг с SYN и не реагирует на фейки после handshake
  • Нужно "отравить" DPI ложными данными до того, как пойдёт реальный трафик
  • В комбинации с Zapret2/desync и 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

Как это работает:

  1. Первое соединение к IP-адресу проходит без syndata (hostname ещё не известен)
  2. Из первого соединения zapret узнаёт hostname (из TLS ClientHello или HTTP Host) и кеширует привязку IP -> hostname
  3. Последующие SYN к этому IP уже проходят через syndata, потому что zapret знает hostname из кеша

Следствие: syndata с хостлистом не подействует на первое соединение к данному IP. Это может быть проблемой для сайтов с уникальными IP или CDN с ротацией адресов.


Комбинирование с другими функциями

syndata часто используется в цепочке с другими функциями. Порядок инстансов важен!

Типовая цепочка: wssize + syndata + multisplit

--lua-desync=wssize:wsize=1:scale=6 \
--lua-desync=syndata \
--lua-desync=multisplit:pos=midsld

Что происходит:

  1. SYN-пакет приходит:

    • wssize модифицирует TCP Window Size в SYN (wsize=1, scale=6)
    • syndata добавляет payload в SYN, дропает оригинал, отправляет модифицированный
    • multisplit ничего не делает (SYN, нет данных для нарезки)
  2. Первый data-пакет (например, TLS ClientHello) приходит:

    • wssize --- миссия уже выполнена (cutoff или пропуск)
    • syndata делает instance_cutoff (пакет не SYN)
    • multisplit нарезает payload по позиции midsld

Почему wssize перед syndata: Zapret2/desync модифицирует TCP Window Size в SYN-пакете. Если поставить после syndata, wssize увидит VERDICT_DROP и не получит SYN. Если перед --- wssize модифицирует dissect, затем syndata использует deepcopy этого (уже модифицированного) dissect.

Цепочка: 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

Многоуровневая атака:

  1. Фаза 0: SYN с фейковым TLS
  2. Фаза 1: фейковый пакет с fooling (tcp_md5)
  3. Фаза 1: реальный payload нарезан на сегменты

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

1. Payload должен помещаться в один пакет

syndata использует rawsend_dissect_ipfrag, а не rawsend_payload_segmented. Это означает, что TCP-сегментация невозможна. Если blob слишком большой и не влезает в один Ethernet frame (с учётом MTU), пакет может быть отброшен сетевым стеком или фрагментирован на IP-уровне (если включён ipfrag).

2. Fooling может сломать handshake

В отличие от fake, где fooling должен заставить сервер отбросить пакет, в syndata fooling применяется к пакету, который сервер должен принять. Деструктивные параметры:

  • tcp_seq=N --- сервер не увидит SYN с правильным sequence
  • tcp_ack=N --- невалидный ack в SYN
  • badsum --- сервер отбросит пакет с плохой checksum
  • tcp_flags_unset=SYN --- пакет перестанет быть SYN

Безопасные параметры:

  • tcp_md5 --- сервер без MD5 проигнорирует опцию (RFC 2385)
  • tcp_ts_up --- перестановка timestamp option (не влияет на валидность)
  • tcp_nop_del --- удаление NOP (не влияет на валидность)
  • IPv6 extension headers --- для обхода DPI/фаерволов на пути

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 "перезапишет" данные в трекере.

5. deepcopy защищает оригинал

syndata делает deepcopy(desync.dis) и работает с копией. Это значит, что apply_fooling и замена payload не затрагивают оригинальный dissect. Если после syndata стоят другие инстансы и SYN не дропнут (rawsend failed), они увидят немодифицированный пакет.

6. instance_cutoff на не-SYN

Как только syndata видит пакет без флага SYN (ACK, PSH+ACK и т.д.), он делает instance_cutoff --- отключает себя для этого потока навсегда. Это правильно: миссия syndata --- только SYN-пакеты. Последующие данные должны обрабатываться другими функциями (multisplit, fake и т.д.).

7. ICMP не вызывает cutoff

Если в цепочке инстансов через syndata проходит ICMP-пакет (например, ICMP Destination Unreachable в ответ на SYN), syndata не делает instance_cutoff. Это защита от преждевременного отключения --- ICMP может быть связан с SYN и не означает конец потока.

8. Дефолтный blob --- 16 нулей, а не обязательный параметр

В отличие от fake, где blob обязателен, syndata имеет fallback --- 16 нулевых байт. --lua-desync=syndata без blob= отправит SYN с 16 байтами 0x00. Это может быть достаточно, чтобы сбить DPI, который не ожидает payload в SYN.

9. tls_mod без blob бессмыслен

Если вы указали tls_mod=rnd,rndsni без blob=, tls_mod попытается модифицировать 16 нулевых байт как TLS --- результат будет непредсказуемым. Всегда используйте tls_mod вместе с blob, содержащим валидный TLS ClientHello.


Миграция с nfqws1

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

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:
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

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

Минимальный (дефолт: 16 нулей в SYN)

--lua-desync=syndata

Отправляет SYN с 16 нулевыми байтами вместо обычного SYN. Простейший вариант --- может сбить DPI, не ожидающий payload в SYN.

С TLS-фейком

--lua-desync=syndata:blob=fake_default_tls

SYN содержит стандартный 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=0x160301000100

6 байт inline hex --- минимальный TLS record header.

С рандомизацией TLS

--lua-desync=syndata:blob=fake_default_tls:tls_mod=rnd,rndsni

TLS-фейк с рандомизированными полями и SNI. Каждый SYN будет содержать уникальные random/session_id/SNI.

С заменой SNI

--lua-desync=syndata:blob=fake_default_tls:tls_mod=sni=google.com

SYN содержит TLS ClientHello с SNI google.com. DPI может записать в трекер "это соединение к google.com" и не блокировать.

С TCP MD5

--lua-desync=syndata:tcp_md5

SYN с 16 нулями и TCP MD5 option. Сервер без MD5 проигнорирует опцию, DPI может быть сбит нестандартным TCP-заголовком.

С TTL fooling (осторожно!)

--lua-desync=syndata:blob=fake_default_tls:ip_ttl=5:ip6_ttl=5

SYN с TTL=5. Если DPI ближе 5 хопов --- увидит фейк. Если сервер дальше 5 хопов --- SYN не дойдёт, handshake не состоится. Ретрансмиссия SYN тоже получит TTL=5 и тоже не дойдёт. Используйте только если точно знаете расстояние до DPI и сервера.

С IP-фрагментацией

--lua-desync=syndata:blob=fake_default_tls:ipfrag:ipfrag_disorder

SYN с 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.

Отладка: повторы отправки

--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_destopt

SYN с hop-by-hop и destination options extension headers. Некоторые DPI/фаерволы не умеют парсить IPv6 extension headers и пропускают пакет.


Источники: lua/zapret-antidpi.lua:385, lua/zapret-lib.lua, docs/manual.md:3944-3961 из репозитория zapret2.