todo/Zapret2/desync/fakeddisorder.md
loop-uh baf0091fa3
Some checks failed
Published content check / validate (push) Failing after 17s
git.zapret.moe → git2.zapret.moe во всём хранилище, защита от возврата старых имён
git.zapret.moe в России заблокирован по имени, как и wiki.zapret.moe. Ссылки
на Forgejo во всех заметках, футерах, wizard.html и главной заменены на
git2.zapret.moe (включая закодированные адреса значков shields.io).

Какое имя рабочее, теперь решают реестры хоста /etc/zapret-*-domains.conf через
zapret-site-names: pre-commit хук vault отклоняет добавленные строки с
заблокированным именем, сборка Quartz сама переводит ссылки и baseUrl на
рабочие имена. Правило в AGENTS.md переписано под этот механизм.

scripts/wiki-stats.py: переходы с любых имён вики и git (wikiN, gitN) больше
не считаются внешними сайтами. content-check: проверка зеркал сторонних
проектов узнаёт любое имя git.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 15:51:32 -04:00

1224 lines
108 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
date: 2026-02-17
tags:
- zapret
- zapret2
- nfqws2
- lua
- lua-desync
- antidpi
- tcp
- fakeddisorder
- fakedsplit
- disorder
- seqovl
aliases:
- fakeddisorder
description: "Справочник по fakeddisorder в zapret2/nfqws2: разрез TCP-payload с фейками в обратном порядке, маркеры pos и seqovl, все аргументы, миграция с nfqws1."
---
> [!mirror] Резервное зеркало
> Актуальная версия этой страницы — на основной вики: [wiki2.zapret.moe/Zapret2/desync/fakeddisorder](https://wiki2.zapret.moe/Zapret2/desync/fakeddisorder)
# `fakeddisorder` — TCP-сегментация с фейками в обратном порядке (zapret2 / nfqws2)
## Коротко и по-простому
Когда браузер открывает сайт по HTTPS, первым сообщением с данными он отправляет TLS ClientHello («привет от клиента»). В нём браузер перечисляет, какое шифрование умеет, и открытым текстом называет нужный сайт: имя лежит в поле SNI (Server Name Indication, «указание имени сервера»). У обычного HTTP без шифрования то же имя стоит в строке `Host:` запроса. ТСПУ (Технические средства противодействия угрозам — оборудование [[DPI/DPI|DPI]], то есть глубокой инспекции трафика, которое стоит у провайдера) ищет это имя в первом пакете соединения и по нему решает, что делать с соединением дальше.
HTTP-запросы и TLS-соединения передаются по протоколу TCP, а TCP отправляет данные кусками — сегментами. У каждого байта в соединении есть порядковый номер (sequence number, коротко seq), и сервер раскладывает принятые куски в свой буфер строго по этим номерам. Поэтому ему безразлично, в каком порядке куски доехали: если конец запроса пришёл раньше начала, сервер подержит его в буфере, дождётся начала и соберёт исходный поток. Почему это гарантирует именно TCP, разобрано в нюансе [[Zapret2/desync/multisplit#1. Работает только с TCP — и почему|«Работает только с TCP» из статьи про multisplit]].
`fakeddisorder` использует эту особенность TCP дважды, и понять его проще, если сначала разобрать два приёма по отдельности. Первый приём — фейки. Фейк — это пакет-обманка: он несёт мусорные данные (по умолчанию нули), но у него тот же размер и тот же seq, что у настоящего куска, поэтому со стороны он похож на повторную отправку этого куска. Если сервер примет такой пакет, мусор попадёт в поток и соединение сломается ([[#4. Fooling ОБЯЗАТЕЛЕН для фейков|нюанс 4]]). Поэтому фейкам нарочно портят заголовок так, чтобы сервер их отбросил, а DPI всё равно мог прочитать; эту порчу называют fooling ([[Zapret2/ts-and-fooling#Что такое fooling|Что такое fooling]]). В большинстве команд этой статьи фейкам сдвигают номер подтверждения (ACK, поле «что подтверждено») на 66000: `tcp_ack=-66000`. Из опций порчи к настоящим кускам применяется только `tcp_ts_up` (плюс политика нумерации `ip_id`): он ничего не портит, а поднимает опцию TCP timestamp в начало заголовка, и без этого Linux-сервер ненадёжно отбрасывает фейки с неверным ACK; подробнее в нюансе [[#5. tcp_ts_up рекомендуется с tcp_ack|5]] и в разделе [[#Применение fooling и reconstruct|Применение fooling и reconstruct]].
Второй приём — обратный порядок (по-английски disorder): куски отправляются не от начала к концу, а наоборот. Серверный TCP-стек рассчитан на куски вразнобой, он буферизирует их и ждёт недостающие. DPI, как правило, такой роскоши не имеет: получив конец запроса первым, он видит данные без начала и может не распознать протокол; DPI с пересборкой потока теоретически справится, но у многих ограниченный буфер или таймаут, и они не дожидаются всех частей. Подробнее — в разделе [[Zapret2/desync/multidisorder#Почему disorder ломает DPI|Почему disorder ломает DPI]] статьи про multidisorder.
Теперь шаги самого `fakeddisorder`. Движок Zapret 2 (`nfqws2`) перехватывает исходящий пакет с ClientHello или HTTP-запросом, и функция делает четыре вещи. Сначала режет данные пакета в одном месте на две части: место задаёт аргумент `pos`, это может быть число или маркер, привязанный к устройству запроса, например `midsld` — середина домена второго уровня, то есть главной части имени сайта (у `www.youtube.com` это `youtube`); по умолчанию разрез после второго байта, а список позиций, как у [[Zapret2/desync/multisplit|multisplit]], здесь не принимается — только один маркер ([[#Маркер позиции (pos)|Маркер позиции (pos)]]). Потом готовит по два фейка на каждую часть с тем же размером и тем же seq. Потом отправляет шесть пакетов, начиная со второй части: FAKE2, REAL2, FAKE2, FAKE1, REAL1, FAKE1, где REAL — настоящий кусок, FAKE — фейк, а цифра — номер части запроса. В конце выбрасывает перехваченный оригинал, чтобы те же данные не ушли второй раз. Подробная раскладка по пакетам — в разделе [[#Порядок отправки сегментов (6 пакетов)|Порядок отправки сегментов (6 пакетов)]].
Сервер получает все шесть пакетов, четыре фейка отбрасывает из-за испорченного ACK, принимает REAL2, держит его в буфере до прихода REAL1 и по номерам seq собирает ровно тот запрос, который отправил браузер, поэтому отвечает как обычно. DPI видит другое: по три сегмента на каждую позицию (настоящий и два фейка, со стороны они похожи на повторные отправки одного и того же) и конец запроса раньше начала. Какой из трёх сегментов настоящий, DPI не знает, и он может проглотить фейки как реальные данные. Как это выглядит с обеих сторон, показано в разделах [[Zapret2/desync/fakedsplit#Что видит DPI|Что видит DPI]] и [[Zapret2/desync/fakedsplit#Что видит сервер|Что видит сервер]] статьи про fakedsplit, где схема та же, но порядок прямой. Сработает ли это на конкретном провайдере, заранее сказать нельзя: результат зависит от конкретного DPI, способ порчи фейков выбирают по месту запуска и подтверждают тестами ([[Zapret2/ts-and-fooling#Как заставить fake умереть: каталог способов|каталог способов]]), а итог проверяют на своём провайдере по [[Zapret2/verify-strategy#Короткий чек-лист честной проверки|чек-листу честной проверки]].
Команда из быстрого старта `fakeddisorder:pos=midsld:tcp_ack=-66000:tcp_ts_up` режет ClientHello посередине домена второго уровня, но первой отправляет вторую часть, и каждая часть окружена фейками того же размера и с тем же seq: FAKE2, REAL2, FAKE2, FAKE1, REAL1, FAKE1. ТСПУ получает по три сегмента на каждую позицию, да ещё конец запроса раньше начала; сервер отбрасывает фейки по испорченному номеру подтверждения (ACK сдвинут на 66000) и держит REAL2 в буфере до прихода REAL1. Как читать схему: строки — пакеты в порядке отправки, подписанные в тех же обозначениях, что и таблицы в этой статье; по горизонтали — место данных в TCP-потоке (номер последовательности, seq); в колонке справа — что сделал с пакетом сервер; внизу — буфер сервера, в который принятые куски встают по своим seq.
![[desync-anim-fakeddisorder.svg|Анимация fakeddisorder: части ClientHello в обратном порядке, каждая окружена фейками с тем же seq]]
Самая короткая команда включает `fakeddisorder` со значениями по умолчанию: один разрез после второго байта (`pos=2`), обработка только распознанных протоколов (`payload=known`) и только исходящих пакетов (`dir=out`), а фейкам портится ACK. Строку `--lua-desync=…` пишут в [[Zapret2/profile#Анатомия профиля|профиль]] — набор правил Zapret 2 для определённого трафика:
```bash
--lua-desync=fakeddisorder:tcp_ack=-66000
```
Статья советует добавлять к `tcp_ack` ещё и `tcp_ts_up` (см. [[#5. tcp_ts_up рекомендуется с tcp_ack|нюанс 5]]). Для HTTPS обычно берут вариант из анимации: `--payload=tls_client_hello --lua-desync=fakeddisorder:pos=midsld:tcp_ack=-66000:tcp_ts_up`; здесь `--payload=tls_client_hello` значит «срабатывать только на TLS ClientHello». Остальные готовые команды собраны в разделах [[#Быстрый старт|Быстрый старт]] и [[#Практические примеры|Практические примеры]].
К разрезу можно добавить приём `seqovl`. Тогда перед второй частью, которая уходит первой из настоящих, дописывается несколько байт заполнителя (`seqovl_pattern`, по умолчанию нули), а номер seq этой части сдвигается назад на ту же длину. Сервер эти байты отбрасывает как вышедшие за левую границу окна приёма, а DPI видит цельный сегмент вместе с заполнителем и может не распознать в нём имя сайта; общий принцип с раскладкой по байтам разобран в разделе [[Zapret2/desync/multisplit#seqovl — скрытый фейк внутри сегмента|seqovl — скрытый фейк внутри сегмента]] статьи про multisplit. У `fakeddisorder` два отличия от `multisplit` и `fakedsplit`. Во-первых, `seqovl` здесь применяется ко второй части, а не к первой. Во-вторых, его значение не число, а маркер того же вида, что `pos` (`seqovl=host`, `seqovl=midsld-2`), как у [[Zapret2/desync/multidisorder#seqovl как маркер|multidisorder]]; результат (после вычитания единицы) должен быть строго меньше `pos-1`, иначе `seqovl` отменяется. Подробно — в разделах [[#seqovl — скрытый фейк внутри реального сегмента|seqovl — скрытый фейк внутри реального сегмента]] и [[#seqovl — маркер, а не число|seqovl — маркер, а не число]].
Ближайшие соседи `fakeddisorder` — три техники с одним из его приёмов. [[Zapret2/desync/multisplit#Зачем нужен multisplit|multisplit]] только режет и шлёт по порядку, без фейков. [[Zapret2/desync/multidisorder#Обратный порядок отправки — суть disorder|multidisorder]] режет и шлёт в обратном порядке, тоже без фейков. [[Zapret2/desync/fakedsplit#Зачем нужен fakedsplit|fakedsplit]] окружает части такими же фейками, но шлёт в прямом порядке. Сводная таблица по ним — в разделе [[#Отличия от fakedsplit, multisplit и multidisorder|Отличия от fakedsplit, multisplit и multidisorder]], а подсказка «когда что брать» — в подразделе [[#Когда что использовать|Когда что использовать]]: `fakeddisorder` рассчитан на DPI, который проверяет и порядок, и содержимое. Ограничения такие: `pos` — один маркер, а не список ([[#2. Только ОДИН маркер в pos|нюанс 2]]); IP-фрагментации функция не поддерживает, для неё нужен `multisplit` или `multidisorder` ([[#6. ipfrag НЕ задействуется|нюанс 6]]); работает только с TCP ([[#1. Работает только с TCP|нюанс 1]]). Флаги `nofake1`–`nofake4` отключают отдельные фейки, а если отключить все четыре, останется [[multidisorder]] с одной позицией ([[#11. Без всех фейков (эквивалент disorder)|пример 11]]).
---
## Оглавление
- [Коротко и по-простому](#коротко-и-по-простому)
- [Справка: где функция в коде и родственники](#справка-где-функция-в-коде-и-родственники)
- [Зачем нужен fakeddisorder](#зачем-нужен-fakeddisorder)
- [Быстрый старт](#быстрый-старт)
- [Откуда берутся данные для нарезки](#откуда-берутся-данные-для-нарезки)
- [Маркер позиции (pos)](#маркер-позиции-pos)
- [Типы маркеров](#типы-маркеров)
- [Относительные маркеры](#относительные-маркеры)
- [Арифметика маркеров](#арифметика-маркеров)
- [Как маркер разрешается в коде](#как-маркер-разрешается-в-коде)
- [Важные нюансы pos](#важные-нюансы-pos)
- [seqovl — скрытый фейк внутри реального сегмента](#seqovl--скрытый-фейк-внутри-реального-сегмента)
- [Принцип работы seqovl в fakeddisorder](#принцип-работы-seqovl-в-fakeddisorder)
- [seqovl — маркер, а не число](#seqovl--маркер-а-не-число)
- [Зачем seqovl лучше обычного fooling](#зачем-seqovl-лучше-обычного-fooling)
- [seqovl_pattern](#seqovl_pattern)
- [Фейковые сегменты и pattern](#фейковые-сегменты-и-pattern)
- [Полный список аргументов](#полный-список-аргументов)
- [A) Собственные аргументы fakeddisorder](#a-собственные-аргументы-fakeddisorder)
- [B) Standard direction](#b-standard-direction)
- [C) Standard payload](#c-standard-payload)
- [D) Standard fooling](#d-standard-fooling)
- [E) Standard ipid](#e-standard-ipid)
- [F) Standard reconstruct](#f-standard-reconstruct)
- [G) Standard rawsend](#g-standard-rawsend)
- [Порядок отправки сегментов (6 пакетов)](#порядок-отправки-сегментов-6-пакетов)
- [ASCII-диаграмма полной последовательности](#ascii-диаграмма-полной-последовательности)
- [Пример с seqovl](#пример-с-seqovl)
- [Пример с nofake-флагами](#пример-с-nofake-флагами)
- [Применение fooling и reconstruct](#применение-fooling-и-reconstruct)
- [Поведение при replay / reasm](#поведение-при-replay--reasm)
- [Автосегментация по MSS](#автосегментация-по-mss)
- [Место в общем скелете](#место-в-общем-скелете)
- [Псевдокод алгоритма](#псевдокод-алгоритма)
- [Нюансы и подводные камни](#нюансы-и-подводные-камни)
- [Отличия от fakedsplit, multisplit и multidisorder](#отличия-от-fakedsplit-multisplit-и-multidisorder)
- [Миграция с nfqws1](#миграция-с-nfqws1)
- [Практические примеры](#практические-примеры)
- [📚 См. также](#-см-также)
---
## Справка: где функция в коде и родственники
Паспорт функции для тех, кто сверяется с исходниками zapret2: в каком файле и на какой строке лежит код, какой ключ первой версии zapret она заменяет и как объявлена.
**Файл:** `lua/zapret-antidpi.lua:931`
**nfqws1 эквивалент:** `--dpi-desync=fakeddisorder`
**Сигнатура:** `function fakeddisorder(ctx, desync)`
`fakeddisorder` — функция TCP-десинхронизации с **двойным запутыванием** DPI: по содержимому (реальные vs фейковые сегменты) и по порядку (обратная последовательность — disorder). Payload разрезается по **одной** позиции на 2 части, и каждая часть обрамляется фейковыми сегментами. Отправка идёт в обратном порядке: сначала вторая часть (с фейками), затем первая (с фейками). Итого — 6 пакетов. После успешной отправки выносит `VERDICT_DROP`, чтобы оригинальный пакет не ушёл.
> [!note] Проще говоря
> Payload — полезные данные пакета без сетевых заголовков: сам HTTP-запрос или сам ClientHello. Reasm — те же данные, собранные движком из нескольких пакетов, если запрос в один пакет не влез. Blob — заранее заготовленные данные, которые можно подсунуть вместо настоящих. Какой из трёх источников выбирается, разобрано в разделе [[#Откуда берутся данные для нарезки|Откуда берутся данные для нарезки]]. `VERDICT_DROP` — решение «перехваченный пакет не отправлять»; как движок складывает такие решения от разных функций, описано в [[Zapret2/жизненный цикл desync-функции#Стадия 8. Вердикт и его агрегация|стадии 8 жизненного цикла]]. «Двойное запутывание» — это два приёма сразу: фейки (запутывание по содержимому) и обратный порядок отправки (запутывание по порядку); оба разобраны в разделе [[#Зачем нужен fakeddisorder|Зачем нужен fakeddisorder]].
Родственные функции: [[multisplit]] (прямой порядок, без фейков), [[multidisorder]] (обратный порядок, без фейков), [[fakedsplit]] (с фейками, прямой порядок), [[hostfakesplit]] (по hostname), [[tcpseg]] (диапазон), [[oob]] (urgent byte).
Общий для всех техник дурения порядок работы — восемь стадий от отсева чужого транспорта до вердикта — разобран в [[жизненный цикл desync-функции]]; здесь описано только то, чем `fakeddisorder` от этого скелета отличается.
---
## Зачем нужен fakeddisorder
DPI анализирует TCP-поток, пытаясь собрать полный payload и найти в нём сигнатуры (hostname в HTTP, SNI в TLS). `fakeddisorder` атакует DPI двумя способами одновременно:
1. **Запутывание по содержимому (fake).** Между реальными сегментами посылаются фейковые, содержащие мусорные данные. DPI должен отличить настоящие сегменты от поддельных. Фейки отбрасываются сервером благодаря [[Zapret2/ts-and-fooling|fooling]] (badseq, badsum, TTL и т.д.), но DPI может их проглотить.
2. **Запутывание по порядку (disorder).** Сегменты отправляются в **обратном порядке**: сначала вторая часть payload, затем первая. DPI, ожидающий последовательного потока, может быть сбит с толку.
> [!note] Проще говоря
> Сигнатура — заранее известная строка, по которой DPI узнаёт сайт. Фейк — пакет-обманка с мусором вместо данных, у которого тот же размер и тот же seq (порядковый номер байта в потоке), что у настоящего куска: сервер отбрасывает его благодаря порче заголовка, а DPI может принять за настоящие данные. Disorder — отправка кусков не по порядку: сервер ждёт недостающие и склеивает всё по seq, а DPI, которому нужен последовательный поток, может запутаться. Фейки подробнее разобраны в разделах [[Zapret2/desync/fake#Зачем нужен fake|Зачем нужен fake]] и [[Zapret2/desync/fakedsplit#Зачем нужен fakedsplit|Зачем нужен fakedsplit]], обратный порядок — в разделе [[Zapret2/desync/multidisorder#Обратный порядок отправки — суть disorder|Обратный порядок отправки — суть disorder]].
**Двойное запутывание** (содержимое + порядок) эффективнее, чем каждый приём по отдельности:
![[wiki-anim-z2-orders.svg|Анимация: порядок отправки у multisplit, multidisorder, fakedsplit и fakeddisorder]]
Как читать схему: четыре строки — четыре функции, стрелка показывает порядок отправки, каждые квадратные скобки — один TCP-сегмент. `F1`–`F4` — фейковые сегменты, «часть 1» и «часть 2» — настоящие куски payload. В нижней строке фейки стоят по обе стороны от каждой настоящей части, а часть 2 уходит раньше части 1. Раскладка на шесть пакетов подробно показана в разделе [[#Порядок отправки сегментов (6 пакетов)|Порядок отправки сегментов (6 пакетов)]].
Сервер при этом корректно собирает поток — TCP-стек гарантирует это через sequence numbers, а фейки отбрасываются благодаря fooling.
> [!note] Проще говоря
> Для сервера порядок прибытия не важен: TCP-стек сам расставит куски по seq и отбросит фейки. Для DPI важны и порядок, и то, какие из сегментов настоящие, поэтому обман сразу по двум признакам может сработать там, где одного было бы мало. Какую функцию брать под какой тип DPI, подсказывает таблица в подразделе [[#Когда что использовать|Когда что использовать]].
---
## Быстрый старт
Ниже готовые строки для [[Zapret2/profile#Анатомия профиля|профиля]] Zapret 2, от самой короткой к более сложным. Флаг `--payload=…` работает как фильтр для всех вызовов `--lua-desync`, которые идут после него (до следующего `--payload` или до конца профиля): они срабатывают только на данных указанного типа. Поэтому `--payload` пишут перед `--lua-desync`, а не после (подробно — в [[последовательность аргументов]]).
Минимально (разрез по позиции 2, payload=known, dir=out):
```bash
--lua-desync=fakeddisorder:tcp_ack=-66000
```
Здесь `payload=known` означает «только распознанные протоколы», а `dir=out` — «только исходящие пакеты»; оба аргумента разобраны в разделах [[#B) Standard direction|B) Standard direction]] и [[#C) Standard payload|C) Standard payload]]. Фейкам портится ACK (`tcp_ack=-66000`), а `tcp_ts_up` в этой минимальной строке нет: статья советует ставить его всегда вместе с `tcp_ack` ([[#5. tcp_ts_up рекомендуется с tcp_ack|нюанс 5]]).
Типовой TLS-разрез посередине SNI:
```bash
--payload=tls_client_hello --lua-desync=fakeddisorder:pos=midsld:tcp_ack=-66000:tcp_ts_up
```
Функция срабатывает только на TLS ClientHello и режет его посередине домена второго уровня; уходят шесть пакетов, вторая часть первой.
TLS с seqovl для тройного запутывания:
```bash
--payload=tls_client_hello --lua-desync=fakeddisorder:pos=midsld:seqovl=5:seqovl_pattern=0x1603030000:tcp_ack=-66000:tcp_ts_up
```
К настоящей второй части слева приклеивается заполнитель `0x1603030000`, похожий на начало TLS record — заголовка записи TLS (для `seqovl=5` это 4 байта, см. пример 3 в разделе [[#Практические примеры|Практические примеры]]). Как это работает, разобрано в разделе [[#seqovl — скрытый фейк внутри реального сегмента|seqovl — скрытый фейк внутри реального сегмента]].
HTTP с кастомным паттерном фейков:
```bash
--payload=http_req --lua-desync=fakeddisorder:pos=host:pattern=0x474554202F:tcp_ack=-66000
```
Здесь `pos=host` режет HTTP-запрос в начале имени хоста, а `pattern=0x474554202F` заполняет фейки не нулями, а образцом, похожим на начало HTTP GET; подробнее — в разделе [[#Фейковые сегменты и pattern|Фейковые сегменты и pattern]].
---
## Откуда берутся данные для нарезки
Внутри `fakeddisorder` данные (`data`) выбираются в следующем порядке приоритетов:
```
1. blob_or_def(desync, desync.arg.blob) — если задан blob= и он существует
2. desync.reasm_data — если есть реассемблированные данные (multi-packet payload)
3. desync.dis.payload — текущий пакет (fallback)
```
**Следствие:** все маркеры `pos`, `seqovl` и прочие аргументы применяются именно к тем данным, которые реально выбраны. Если вы задали `blob=myblob`, маркеры вроде `midsld` будут работать только если `myblob` содержит валидный TLS/HTTP payload, который zapret может распознать.
> [!note] Проще говоря
> Payload — полезные данные текущего пакета без сетевых заголовков, reasm — те же данные, собранные движком из нескольких пакетов, blob — заранее заготовленные данные, которые подставляются вместо настоящих (как их объявлять — в заметке [[blob]]). Функция берёт первый из трёх источников, который есть: сначала blob, если он задан, потом собранный reasm, в последнюю очередь текущий пакет. Тот же выбор описан как стадия 4 общего скелета в заметке [[жизненный цикл desync-функции]]. Какие payload распознаёт `nfqws2` и почему от этого зависят относительные маркеры вроде `midsld`, разобрано в заметке [[Zapret2/payload#Что такое тип payload (и чем он отличается от протокола потока)|о типах payload]].
---
## Маркер позиции (pos)
![[desync-anim-hub-markers.svg|Анимация: маркеры позиций pos на HTTP-запросе и на TLS ClientHello, разрез по pos=host,midsld,endhost]]
`pos` — главный аргумент `fakeddisorder`. Определяет **где** внутри payload будет произведён разрез. В отличие от [[multisplit]] и [[multidisorder]], `pos` — это **один маркер**, а не список. Payload всегда разрезается на **ровно 2 части**.
> [!note] Проще говоря
> Маркер — способ указать место разреза либо числом байт, либо словом («середина домена второго уровня»), которое `nfqws2` сам переводит в число по устройству запроса. В `fakeddisorder` маркер один, поэтому запрос всегда делится ровно на две части. Как задают список маркеров, разобрано в разделах [[Zapret2/desync/multisplit#Маркеры позиций (pos)|Маркеры позиций (pos)]] статьи про multisplit и [[Zapret2/desync/multidisorder#Маркеры позиций (pos)|Маркеры позиций (pos)]] статьи про multidisorder.
### Типы маркеров
| Тип | Описание | Пример |
|:----|:---------|:-------|
| **Абсолютный положительный** | Смещение от начала payload, считая с 0. `pos=N` → первые N байт становятся отдельным сегментом | `2`, `5`, `100` |
| **Абсолютный отрицательный** | Смещение от конца payload. `-1` = последний байт | `-1`, `-10`, `-50` |
| **Относительный** | Логическая позиция внутри распознанного payload. Привязана к структуре протокола | `midsld`, `host`, `sniext` |
Абсолютные маркеры не зависят от содержимого. Относительные привязаны к устройству запроса и работают только тогда, когда `nfqws2` распознал протокол: в столбце «Для каких payload» таблицы ниже указано, для каких типов данных маркер имеет смысл (про типы payload — [[Zapret2/payload#Что такое тип payload (и чем он отличается от протокола потока)|Что такое тип payload]]).
### Относительные маркеры
| Маркер | Описание | Для каких payload |
|:-------|:---------|:------------------|
| `method` | Начало HTTP-метода (`GET`, `POST`, `HEAD`, `PUT` и т.д.). Обычно позиция 0, но может стать 1-2 при использовании `http_methodeol` | `http_req` |
| `host` | Первый байт имени хоста (`Host:` в HTTP, SNI в TLS) | `http_req`, `tls_client_hello` |
| `endhost` | Байт, **следующий** за последним байтом имени хоста. Т.е. `host..endhost-1` = полный hostname | `http_req`, `tls_client_hello` |
| `sld` | Первый байт домена второго уровня (SLD). Для `www.example.com` — это `e` в `example` | `http_req`, `tls_client_hello` |
| `endsld` | Байт, следующий за последним байтом SLD. Для `example.com` — это `.` после `example` | `http_req`, `tls_client_hello` |
| `midsld` | Середина SLD (самый популярный маркер). Для `example` (7 символов) — позиция 3-го или 4-го символа | `http_req`, `tls_client_hello` |
| `sniext` | Начало поля данных SNI extension в TLS ClientHello. Extension состоит из type (2 байта) + length (2 байта) + **данные** — sniext указывает на начало данных | `tls_client_hello` |
| `extlen` | Поле длины всех TLS extensions | `tls_client_hello` |
### Арифметика маркеров
К любому маркеру можно прибавить (+) или вычесть (-) целое число:
```
midsld+1 — один байт ПОСЛЕ середины SLD
midsld-1 — один байт ДО середины SLD
endhost-2 — два байта до конца hostname
method+2 — два байта после начала метода
sniext+1 — один байт после начала SNI extension data
host+3 — три байта после начала hostname
-1 — последний байт payload (абсолютный, не относительный)
```
Проще говоря, `midsld+1` значит «на один байт правее середины домена второго уровня», а `-1` — последний байт всего payload, потому что абсолютное число не привязано к структуре протокола.
### Как маркер разрешается в коде
В отличие от [[multisplit]] (который использует `resolve_multi_pos` для списка маркеров), `fakeddisorder` использует `resolve_pos` — функцию для **одного** маркера:
```lua
local spos = desync.arg.pos or "2"
local pos = resolve_pos(data, desync.l7payload, spos)
```
`resolve_pos` возвращает одно число (абсолютную Lua-позицию, 1-based) или `nil`, если маркер не может быть разрешён.
> [!note] Проще говоря
> `resolve_pos` — функция, которая переводит слово-маркер в номер байта. Lua нумерует позиции с единицы, а смещения в командной строке считаются с нуля, поэтому маркеру `0` соответствует Lua-позиция 1; именно её функция отвергает (см. следующий раздел).
### Важные нюансы pos
- **Только ОДИН маркер.** `pos=midsld,endhost` — невалидно (в отличие от multisplit/multidisorder, которые принимают списки). Если вам нужно несколько позиций разреза с фейками — используйте несколько инстансов `fakeddisorder` в цепочке.
- **Разрез в самом начале данных запрещён.** Если маркер разрешается в Lua-позицию 1 — это маркер `0`, поскольку смещения в командной строке считаются с нуля, — fakeddisorder логирует `"split pos resolved to 0. cannot split."` и ничего не делает. Не работает именно `pos=0`; `pos=1` (первый байт отдельным сегментом) корректен. Частая жертва правила — `pos=method` для HTTP, где метод лежит на смещении 0.
- **Неразрешимый маркер = ничего не делает.** Если маркер не может быть разрешён (например, `midsld` для `unknown` payload), fakeddisorder логирует `"cannot resolve pos"` и пропускает операцию.
- **По умолчанию pos="2".** Если `pos` не задан, разрез по позиции 2 — payload делится на первые 2 байта и весь остаток (`pos=N` даёт первые N байт отдельным сегментом, см. таблицу типов маркеров выше; описание «1-й байт и остальное» относится к `pos=1`).
> [!note] Проще говоря
> Если разрез не получился (позиция 0 или неразрешимый маркер), функция ничего не отправляет и только записывает причину в лог. Такие случаи разобраны и в нюансах [[#2. Только ОДИН маркер в pos|2]] и [[#3. Позиция 1 не работает|3]] ниже.
---
## seqovl — скрытый фейк внутри реального сегмента
**seqovl** (Sequence Overlap) — техника скрытого замешивания фейковых данных в реальный TCP-сегмент через манипуляцию TCP sequence number. В `fakeddisorder` seqovl применяется **только ко второму реальному сегменту** (real part 2 — первый реальный пакет в порядке отправки).
Sequence Overlap — «перекрытие по номерам последовательности». В [[Zapret2/desync/multisplit#seqovl — скрытый фейк внутри сегмента|multisplit]] и [[Zapret2/desync/fakedsplit#seqovl — скрытый фейк внутри сегмента|fakedsplit]] эта техника применяется к первому настоящему сегменту, а в `fakeddisorder` — ко второму, который уходит первым из настоящих: сравнение — в [[#8. seqovl применяется только к real part 2|нюансе 8]]. У [[Zapret2/desync/multidisorder#seqovl — перезапись буфера сокета через перекрытие|multidisorder]] `seqovl` тоже маркер, и его механика разобрана в отдельном разделе той статьи.
### Принцип работы seqovl в fakeddisorder
![[desync-anim-hub-seqovl.svg|Анимация: seqovl дописывает слева паттерн и сдвигает seq на 990; DPI читает сегмент целиком, сервер выбрасывает байты левее 1000]]
> [!note] Проще говоря
> Перед настоящей второй частью приклеено 10 байт заполнителя (`PATTERN`), а seq сдвинут назад на 10. Границей приёма служит `pos-1`: всё левее сервер выбрасывает, всё от границы принимает. DPI видит цельный сегмент, начинающийся с `pos-11`, и может не распознать в нём SNI. Общее объяснение окна приёма и разбор того, что видят DPI и сервер, есть в разделе [[Zapret2/desync/multisplit#Принцип работы seqovl|Принцип работы seqovl]] статьи про multisplit.
### seqovl — маркер, а не число
**Критическое отличие от [[multisplit]] и [[fakedsplit]]:** в `fakeddisorder` (как и в [[multidisorder]]) `seqovl` — это **маркер**, а не просто число. Он разрешается через `resolve_pos`:
```lua
seqovl = resolve_pos(data, desync.l7payload, desync.arg.seqovl)
seqovl = seqovl - 1 -- Lua→0-based
```
Это значит, что можно использовать:
- `seqovl=5` — абсолютное число (разрешится в 5, станет 4 после `-1`)
- `seqovl=host` — относительный маркер (разрешится в позицию начала hostname, `-1`)
- `seqovl=midsld-2` — маркер с арифметикой
> [!note] Проще говоря
> `seqovl` задают так же, как место разреза: числом или словом-маркером. Внутри функции позиция сначала переводится в номер байта, а потом от неё отнимается 1 (Lua→0-based, то есть переход от счёта с единицы к счёту с нуля). Как то же устроено у другой функции — в разделе [[Zapret2/desync/multidisorder#seqovl как маркер|seqovl как маркер]] статьи про multidisorder.
**Ограничение:** результат `seqovl` (после `-1`) должен быть **строго меньше** `pos-1`. Иначе seqovl отменяется с логом:
```
fakeddisorder: seqovl cancelled because seqovl N is not less than the split pos M
```
Если маркер не разрешается, seqovl тоже отменяется:
```
fakeddisorder: seqovl cancelled because could not resolve marker 'xxx'
```
> [!note] Проще говоря
> Отмена `seqovl` не отменяет всю функцию: по псевдокоду ниже в этом случае `seqovl` обнуляется, а разрез и отправка шести пакетов идут дальше.
### Зачем seqovl лучше обычного fooling
Обычный способ спрятать фейк от сервера — [[Zapret2/ts-and-fooling#Что такое fooling|fooling]]: пакету-обманке портят заголовки (TTL, номера seq или ack, опцию md5sig), и сервер отбрасывает такой пакет. `seqovl` добивается похожего результата другим путём, и таблица ниже сравнивает оба подхода.
| Критерий | Обычный fooling (TTL, badseq, md5sig) | seqovl |
|:---------|:---------------------------------------|:-------|
| Заголовки | Модифицируются (TTL, seq, ack, md5) | **Не модифицируются** — пакет выглядит полностью легитимным |
| Обнаружение | DPI может детектировать подозрительные заголовки | DPI видит "честный" сегмент с правильными заголовками |
| Механизм отбрасывания | Сервер отбрасывает весь пакет из-за невалидных заголовков | Сервер отбрасывает только часть, выходящую за TCP window |
| Надёжность | Зависит от поведения конкретного стека | Основан на фундаментальном свойстве TCP |
**Вывод:** seqovl добавляет третий уровень запутывания (к фейкам и disorder), причём реальный сегмент с seqovl выглядит абсолютно легитимно для DPI.
### seqovl_pattern
Паттерн, которым заполняется seqovl-область. По умолчанию — `0x00` (нули).
В `fakeddisorder` `seqovl_pattern` — это **имя blob**. Паттерн повторяется до нужной длины `seqovl`.
Blob можно записать прямо в команде шестнадцатеричной строкой (inline hex, `0x…`) или заранее объявить флагом `--blob` и сослаться на него по имени; подробно — в заметке [[blob]].
```bash
# Inline hex blob (маскировка под начало TLS record)
--lua-desync=fakeddisorder:pos=midsld:seqovl=5:seqovl_pattern=0x1603030000:tcp_ack=-66000
# Предзагруженный blob
--blob=tlspat:0x1603030100 \
--lua-desync=fakeddisorder:pos=midsld:seqovl=8:seqovl_pattern=tlspat:tcp_ack=-66000
```
Если `optional` задан и blob `seqovl_pattern` отсутствует — используется нулевой паттерн (seqovl не отменяется).
---
## Фейковые сегменты и pattern
Фейковые сегменты генерируются функцией `pattern()`:
```lua
fakepat = desync.arg.pattern and blob(desync, desync.arg.pattern) or "\x00"
fake_part2 = pattern(fakepat, pos, #data - pos + 1) -- фейк для части 2
fake_part1 = pattern(fakepat, 1, pos - 1) -- фейк для части 1
```
**Ключевые свойства:**
- Фейк **совпадает по размеру** с реальной частью, которую он имитирует
- `pattern()` принимает смещение (`pos` или `1`), что означает, что фейк заполняется так, как будто он начинается с той же позиции в payload. Это делает его TCP sequence корректным для DPI
- По умолчанию `pattern` = `\x00` (нули). Можно задать свой blob через `pattern=<blob>`
- Blob повторяется до нужной длины
**Важно:** фейки **отправляются с полным fooling** (badseq, TTL и т.д.), чтобы сервер их отбросил. Без fooling сервер примет фейки как реальные данные и поток будет повреждён.
> [!note] Проще говоря
> `pattern()` — функция, которая повторяет образец (по умолчанию один нулевой байт) до нужной длины. Фейк для части 2 по размеру равен части 2, фейк для части 1 — части 1, а seq у них такие же, как у настоящих частей. Образец задаёт аргумент `pattern`, его значение — имя blob (см. [[blob]]). Как именно фейкам портят заголовки, разобрано в разделе [[#Применение fooling и reconstruct|Применение fooling и reconstruct]].
---
## Полный список аргументов
Аргументы делятся на собственные аргументы `fakeddisorder` (раздел A) и стандартные (разделы B–G): их понимают и другие функции дурения, а общий обзор есть в [[desync]].
Формат вызова:
```
--lua-desync=fakeddisorder[:arg1[=val1][:arg2[=val2]]...]
```
Все `val` приходят в Lua как строки. Если `=val` не указан, значение = пустая строка `""` (в Lua это truthy), поэтому флаги пишутся просто как `:optional`, `:nodrop`, `:tcp_ts_up`.
### A) Собственные аргументы fakeddisorder
#### `pos`
- **Формат:** `pos=<marker>`
- **Тип:** строка с **одним** маркером (НЕ список!)
- **По умолчанию:** `"2"`
- **Описание:** Точка разреза. Payload делится на 2 части: `data[1..pos-1]` и `data[pos..#data]`
- **Примеры:**
- `pos=2` — разрез после 2-го байта (дефолт)
- `pos=1` — первый байт уходит отдельным сегментом
- `pos=midsld` — разрез посередине SLD
- `pos=host` — разрез в начале hostname
- `pos=sniext+1` — один байт после начала SNI extension data
- `pos=endhost-2` — два байта до конца hostname
#### `seqovl`
- **Формат:** `seqovl=<marker>`
- **Тип:** **маркер** (не только число — в отличие от multisplit/fakedsplit!)
- **По умолчанию:** не задан (нет seqovl)
- **Описание:** Применяется ко **второму реальному сегменту** (real part 2). К данным слева добавляется `seqovl` байт `seqovl_pattern`, а TCP `th_seq` уменьшается на `seqovl`. Маркер разрешается через `resolve_pos`, затем результат уменьшается на 1 (Lua→0-based). Результат должен быть строго меньше `pos-1`
- **Примеры:**
- `seqovl=5` — 4 байта фейка слева (5→resolve→5, 5-1=4)
- `seqovl=host` — seqovl равен позиции начала hostname (минус 1)
- `seqovl=sld-2` — маркер с арифметикой
#### `seqovl_pattern`
- **Формат:** `seqovl_pattern=<blobName>`
- **Тип:** имя blob-переменной
- **По умолчанию:** один байт `0x00`, повторяемый до длины `seqovl`
- **Описание:** Данные для заполнения seqovl-области. Blob повторяется функцией `pattern()` до нужного размера
- **Поведение с `optional`:** если `optional` задан и blob отсутствует — используется нулевой паттерн, seqovl не отменяется
- **Примеры:**
- `seqovl_pattern=0x1603030000` — inline hex (маскировка под TLS)
- `seqovl_pattern=my_pattern_blob` — предзагруженный blob
#### `pattern`
- **Формат:** `pattern=<blobName>`
- **Тип:** имя blob-переменной
- **По умолчанию:** один байт `0x00`
- **Описание:** Данные для заполнения **фейковых** сегментов. Blob повторяется до размера соответствующей реальной части
- **Примеры:**
- `pattern=0x474554202F` — inline hex (маскировка под начало HTTP GET)
- `pattern=fake_tls_pat` — предзагруженный blob
#### `blob`
- **Формат:** `blob=<blobName>`
- **Тип:** имя blob-переменной
- **По умолчанию:** не задан
- **Описание:** Заменить текущий payload/reasm на указанный blob и резать/слать его. Используется для отправки произвольных данных (фейковых payload, модифицированных ClientHello и т.д.)
- **Примеры:**
- `blob=fake_default_tls` — стандартный TLS-фейк
- `blob=0xDEADBEEF` — inline hex
- `blob=my_custom_ch` — предзагруженный blob
#### `nofake1`
- **Формат:** `nofake1` (флаг, без значения)
- **Описание:** Не отправлять **первый** фейковый пакет (fake part 2, первый по порядку отправки)
#### `nofake2`
- **Формат:** `nofake2` (флаг, без значения)
- **Описание:** Не отправлять **третий** пакет (fake part 2 повторно, после реального part 2)
#### `nofake3`
- **Формат:** `nofake3` (флаг, без значения)
- **Описание:** Не отправлять **четвёртый** пакет (fake part 1, перед реальным part 1)
#### `nofake4`
- **Формат:** `nofake4` (флаг, без значения)
- **Описание:** Не отправлять **шестой** пакет (fake part 1 повторно, после реального part 1)
> [!note] Проще говоря
> Четыре флага соответствуют четырём фейкам по порядку отправки: `nofake1` — пакет 1, `nofake2` — пакет 3, `nofake3` — пакет 4, `nofake4` — пакет 6. Флага для отключения настоящих пакетов 2 и 5 среди аргументов нет. Примеры — в разделе [[#Пример с nofake-флагами|Пример с nofake-флагами]].
#### `optional`
- **Формат:** `optional` (флаг, без значения)
- **Описание:** Мягкий режим:
- Если задан `blob=...` и blob отсутствует — fakeddisorder **ничего не делает** (тихий skip, без ошибок)
- Если задан `seqovl_pattern=...` и blob отсутствует — используется нулевой паттерн (seqovl не отменяется)
> [!note] Проще говоря
> `optional` смягчает две ситуации: если не найден blob для данных, функция тихо ничего не делает, а если не найден blob-образец для `seqovl`, заполнитель будет нулевым.
#### `nodrop`
- **Формат:** `nodrop` (флаг, без значения)
- **Описание:** После успешной отправки **не выносить** `VERDICT_DROP` (вместо этого вернуть `VERDICT_PASS`). Оригинальный пакет тоже будет отправлен (наряду с 6 нарезанными пакетами)
- **Предупреждение:** в боевых профилях `nodrop` обычно нежелателен — оригинал ещё раз уйдёт, что создаст дублирование
---
### B) Standard direction
| Параметр | Значения | По умолчанию |
|:---------|:---------|:-------------|
| `dir` | `in`, `out`, `any` | `out` |
Фильтр по направлению пакета. `fakeddisorder` по умолчанию работает только с исходящими (`out`).
- `dir=out` — только исходящие (от клиента к серверу)
- `dir=in` — только входящие (от сервера к клиенту)
- `dir=any` — оба направления
При первом вызове с указанным `dir` функция делает `direction_cutoff_opposite` — отсекает себя от противоположного направления.
> [!note] Проще говоря
> Cutoff (отсечение) — команда «эта функция больше не вызывается для такого направления или потока». Что происходит на стадии отсечения направления, описано в заметке [[Zapret2/жизненный цикл desync-функции#Стадия 2. Отсечение противоположного направления|стадия 2 жизненного цикла]].
---
### C) Standard payload
| Параметр | Значения | По умолчанию |
|:---------|:---------|:-------------|
| `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-фильтр.
> [!note] Проще говоря
> Тип payload — то, что движок распознал в данных пакета (`tls_client_hello`, `http_req` и другие). Подробнее — в заметке [[Zapret2/payload#Что такое тип payload (и чем он отличается от протокола потока)|Что такое тип payload]]; порядок `--payload` и `--lua-desync` в профиле разобран в [[последовательность аргументов]].
---
### D) Standard fooling
Модификации L3/L4 заголовков. В `fakeddisorder` fooling применяется **только к фейковым сегментам**. К реальным применяется **только** `tcp_ts_up`.
Каждая строка таблицы — один способ порчи заголовков IP или TCP у фейка, чтобы сервер его отбросил. Разбор способов по слоям и того, где какой ломается, есть в разделе [[Zapret2/ts-and-fooling#Как заставить fake умереть: каталог способов|Как заставить fake умереть: каталог способов]].
| Параметр | Описание | Пример |
|:---------|:---------|:-------|
| `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` |
**Ключевое:** `tcp_ts_up` — единственный параметр fooling, который применяется и к реальным, и к фейковым сегментам. Все остальные fooling-параметры применяются **только к фейкам**.
**Заметка про tcp_ts_up:** На Linux-серверах пакеты с инвалидным ACK стабильно отбрасываются **только если** TCP timestamp option идёт первой в заголовке. `tcp_ts_up` перемещает её в начало, обеспечивая корректную работу badseq-fooling. Поэтому `tcp_ts_up` рекомендуется включать всегда вместе с `tcp_ack`.
> [!note] Проще говоря
> TCP timestamp — необязательная опция в конце TCP-заголовка (устройство опций разобрано в разделе [[Zapret2/ts-and-fooling#Что такое TCP options (и зачем fooling с ними играет)|Что такое TCP options]]). `tcp_ts_up` только переставляет её в начало и ничего не портит, поэтому его безопасно применять и к настоящим сегментам.
---
### E) Standard ipid
| Параметр | Описание | По умолчанию |
|:---------|:---------|:-------------|
| `ip_id=seq` | Последовательные IP ID | `seq` |
| `ip_id=rnd` | Случайные IP ID | — |
| `ip_id=zero` | Нулевые IP ID | — |
| `ip_id=none` | Не менять IP ID | — |
| `ip_id_conn` | Сквозная нумерация IP ID в рамках соединения (требует tracking) | — |
`ip_id` применяется **и к фейкам, и к оригиналам**.
> [!note] Проще говоря
> `ip_id` задаёт, как нумеруются IP ID пакетов: `seq` — по порядку, `rnd` — случайно, `zero` — нулями, `none` — не менять. К фейкам и к настоящим сегментам он применяется одинаково (таблица в разделе [[#Применение fooling и reconstruct|Применение fooling и reconstruct]]).
---
### F) Standard reconstruct
| Параметр | Описание |
|:---------|:---------|
| `badsum` | Испортить L4 (TCP) checksum при реконструкции raw-пакета |
`reconstruct` применяется **только к фейкам**. К оригиналам reconstruct не применяется.
> [!note] Проще говоря
> Reconstruct — сборка готового сырого пакета из полей и данных; `badsum` при такой сборке нарочно портит контрольную сумму TCP. Настоящие сегменты собираются без этого.
---
### G) Standard rawsend
| Параметр | Описание |
|:---------|:---------|
| `repeats=N` | Отправить каждый пакет N раз (применяется **только к фейкам**) |
| `ifout=<iface>` | Интерфейс для отправки (по умолчанию определяется автоматически) |
| `fwmark=N` | Firewall mark (только Linux, nftables/iptables) |
**Важно:** `repeats` в `fakeddisorder` применяется **только к фейковым** сегментам (через `rawsend_opts`), а не ко всем. Реальные сегменты отправляются через `rawsend_opts_base`, где repeats не задействуется.
**Важно:** `ipfrag` **не задействуется** в fakeddisorder — ни для фейков, ни для оригиналов. Объект `ipfrag` установлен в пустую таблицу `{}` для обоих типов пакетов.
> [!note] Проще говоря
> Rawsend — отправка собранных пакетов в сеть; его параметры задают число повторов, интерфейс и метку firewall. IP-фрагментация — деление пакета на части на уровне IP: [[Zapret2/desync/multisplit#F) Standard ipfrag|multisplit её поддерживает]], а `fakeddisorder` нет.
---
## Порядок отправки сегментов (6 пакетов)
`fakeddisorder` всегда отправляет **6 пакетов** (если все nofake-флаги не установлены). Порядок **обратный** по отношению к [[fakedsplit]]: сначала идёт вторая часть (с фейками), затем первая (с фейками).
> [!note] Проще говоря
> Пакеты 1–3 — вторая часть запроса в окружении двух фейков, пакеты 4–6 — первая часть в таком же окружении. Смещение (seq offset) считается от начала payload и у фейка равно смещению настоящей части, которую он копирует. Столбец `nofake` показывает, каким флагом отключается пакет.
### ASCII-диаграмма полной последовательности
![[wiki-anim-z2-fakeddisorder6.svg|Анимация: шесть пакетов fakeddisorder, seqovl=10 и пропуск фейков флагами nofake]]
На схеме выше те же шесть пакетов в порядке отправки: справа подписано, что с каждым делает сервер.
**Сравнение с fakedsplit (прямой порядок):**
![[wiki-anim-z2-orders.svg|Анимация: порядок отправки у multisplit, multidisorder, fakedsplit и fakeddisorder]]
> [!note] Проще говоря
> Это та же схема, что у fakedsplit, только две половины поменялись местами: у fakedsplit сначала уходит первая часть, у `fakeddisorder` вторая. Схема fakedsplit для сравнения — в разделе [[Zapret2/desync/fakedsplit#Последовательность отправки (6 пакетов)|Последовательность отправки (6 пакетов)]].
### Пример с seqovl
Здесь у пакета 2 смещение 29, то есть 39 минус 10 байт заполнителя. По схеме выше окно приёма сервера для этого пакета начинается с seq=39, поэтому байты 29–38 он отбрасывает, а с 39-го принимает настоящую часть 2.
### Пример с nofake-флагами
> [!note] Проще говоря
> `nofake2` и `nofake4` убирают повторные фейки, которые идут после настоящих частей; остаётся по одному фейку перед каждой настоящей частью, всего четыре пакета.
Можно отключить все фейки кроме одного, или вообще все:
```
# Только 2 реальных пакета (все фейки отключены) = multidisorder с одной позицией
fakeddisorder:pos=midsld:nofake1:nofake2:nofake3:nofake4
```
---
## Применение fooling и reconstruct
Это ключевое отличие от [[multisplit]] и [[multidisorder]], где fooling применяется ко всем сегментам.
> [!note] Проще говоря
> У пакетов два набора опций: `opts_orig` для настоящих сегментов и `opts_fake` для фейков. Общий разбор наборов опций — в разделе [[Zapret2/жизненный цикл desync-функции#Наборы опций: кто их применяет и к чему|Наборы опций: кто их применяет и к чему]] заметки про жизненный цикл, а у fakedsplit — в разделе [[Zapret2/desync/fakedsplit#Два набора опций: opts_orig vs opts_fake|Два набора опций: opts_orig vs opts_fake]].
| | `opts_orig` (настоящие сегменты) | `opts_fake` (фейковые сегменты) |
|:--|:--|:--|
| fooling | только `tcp_ts_up` | всё: `tcp_ack`, `tcp_seq`, `ip_ttl`, `tcp_md5` и другое |
| reconstruct | пусто (`{}`) | всё: `badsum` и другое |
| ipfrag | пусто (`{}`) | пусто (`{}`) |
| ipid | `desync.arg` (полный) | `desync.arg` (полный) |
| rawsend | `rawsend_opts_base` | `rawsend_opts` (с `repeats`) |
**Почему так:** реальные сегменты должны дойти до сервера в неповреждённом виде. Fooling вроде `tcp_ack=-66000` сделал бы их невалидными для сервера. Поэтому fooling идёт только на фейки — чтобы сервер их отбросил, а DPI — запутался.
Исключение — `tcp_ts_up`. Он не портит пакет, а лишь перемещает TCP timestamp в начало заголовка. Это полезно для обеспечения корректной работы badseq/badack на принимающей стороне и применяется ко всем сегментам.
---
## Поведение при replay / reasm
![[desync-anim-hub-reasm.svg|Анимация: большой ClientHello приходит тремя пакетами, ядро собирает reasm_data, функция режет весь буфер на первой части, остальные части дропаются]]
Многопакетный запрос `nfqws2` придерживает, собирает в буфер `reasm_data` и перепроигрывает через desync-функции. `fakeddisorder` использует штатную развилку из общего скелета desync-функций ([[жизненный цикл desync-функции]], стадия 6) без изменений: на первой части отправляет всю шестёрку пакетов (2 реальных + 4 фейка) по собранному буферу, остальные части дропает. Если отправка сорвалась, флаг «реасм уже отправлен» не ставится и оставшиеся части проходят как есть.
> [!note] Проще говоря
> Если ClientHello не влез в один пакет, движок придерживает пакеты, собирает запрос целиком в буфер `reasm_data` (reasm — от reassembly, «пересборка») и «проигрывает» (replay) его по кускам через функции дурения. Функция должна сработать один раз, на первом куске, а остальные куски выбросить. Подробно — в разделе [[Zapret2/жизненный цикл desync-функции#Стадия 6. Развилка перепроигрывания (replay)|Стадия 6. Развилка перепроигрывания (replay)]].
Специфика функции: раз работа идёт по всему реасму, обратный порядок и размеры фейков определяются целым запросом, а не отдельным пакетом.
---
## Автосегментация по MSS
![[desync-anim-hub-mss.svg|Анимация: кусок данных больше MSS автоматически режется на под-сегменты с растущим seq]]
О размерах TCP-сегментов думать **не нужно**. Функция `rawsend_payload_segmented` из `zapret-lib.lua` автоматически:
1. Отслеживает MSS для каждого TCP-соединения
2. Если часть payload превышает MSS — дополнительно режет по MSS
3. Каждый под-сегмент отправляется с корректным TCP sequence
> [!note] Проще говоря
> MSS (Maximum Segment Size) — максимальный размер TCP-сегмента: если часть запроса больше, она уходит несколькими сегментами, и у каждого seq правильный. Указывать это в аргументах не нужно.
---
## Место в общем скелете
Тело `fakeddisorder` построено по тому же шаблону, что и все остальные функции дурения: восемь стадий от отсева чужого транспорта до вердикта. Разобраны они один раз в [[жизненный цикл desync-функции]] — здесь только отклонения:
| Стадия общего скелета | Что делает `fakeddisorder` |
|:----------------------|:----------------|
| 1. Отсев транспорта | только TCP; на не-TCP делает `instance_cutoff` (кроме связанного ICMP) |
| 2. Направление | `dir=out` по умолчанию, отключается от входящего |
| 3. Аргументы | обязательных нет; `optional` + отсутствующий `blob` → тихий выход |
| 4. Данные | штатная цепочка `blob → reasm → payload` |
| 5. Гварды | штатные `#data>0`, `direction_check`, `payload_check` (по умолчанию `known`) |
| 6. replay | штатная развилка: работа на первой части, дроп остальных |
| 7. **Своя техника** | одна позиция разреза, два реальных сегмента и до четырёх фейков, отправка в обратном порядке, `seqovl` как маркер — этому посвящена вся заметка |
| 8. Вердикт | `VERDICT_DROP` после успешной отправки, `VERDICT_PASS` при `nodrop` или сбое `rawsend` |
Как и [[fakedsplit]], функция собирает **два разных набора опций**: фейкам достаются fooling, reconstruct и `repeats` в полном объёме, реальным частям — только `tcp_ts_up` и политика `ip_id`. Смысл в том, что фейк сервер обязан отвергнуть, а реальные данные — принять. Общий разбор наборов опций — в [[жизненный цикл desync-функции]].
> [!note] Проще говоря
> Cutoff (отсечение) — «эта функция больше не вызывается»; вердикт — решение, что делать с перехваченным пакетом: `VERDICT_DROP` выбросить его, `VERDICT_PASS` пропустить. Как вердикты складываются между функциями, описано в заметке [[Zapret2/жизненный цикл desync-функции#Стадия 8. Вердикт и его агрегация|Стадия 8. Вердикт и его агрегация]].
---
## Псевдокод алгоритма
Тело функции целиком, включая общие для всех техник стадии — они пронумерованы так же, как в [[жизненный цикл desync-функции]]:
Читать код удобнее вместе с таблицей из раздела [[#Место в общем скелете|Место в общем скелете]] и схемой из раздела [[#Порядок отправки сегментов (6 пакетов)|Порядок отправки сегментов (6 пакетов)]]: комментарии в коде отмечают, где кончается общая часть и начинаются шесть отправок.
```lua
function fakeddisorder(ctx, desync)
-- 1. Проверка: только TCP
if not desync.dis.tcp then
if not desync.dis.icmp then instance_cutoff_shim() end
return
end
-- 2. Cutoff противоположного направления
direction_cutoff_opposite(ctx, desync)
-- 3. Проверка optional blob
if optional and blob specified and blob not exists then
DLOG("blob not found. skipped")
return
end
-- 4. Выбор данных
data = blob_or_def(blob) or reasm_data or dis.payload
-- 5. Проверки: данные не пусты, направление OK, payload OK
if #data > 0 and direction_check() and payload_check() then
-- 6. Только первый replay
if replay_first() then
-- 7. Разрешение маркера (ОДИН, не список!)
spos = desync.arg.pos or "2"
pos = resolve_pos(data, l7payload, spos)
if pos == nil then
DLOG("cannot resolve pos")
elseif pos == 1 then
DLOG("split pos resolved to 0. cannot split.")
else
-- 8. Подготовка opts
opts_orig = {
fooling = {tcp_ts_up = desync.arg.tcp_ts_up}, -- ТОЛЬКО tcp_ts_up
reconstruct = {}, -- пусто
ipfrag = {}, -- пусто
ipid = desync.arg,
rawsend = rawsend_opts_base(desync)
}
opts_fake = {
fooling = desync.arg, -- ПОЛНЫЙ fooling
reconstruct = reconstruct_opts(desync), -- ПОЛНЫЙ reconstruct
ipfrag = {}, -- пусто
ipid = desync.arg,
rawsend = rawsend_opts(desync) -- с repeats
}
fakepat = pattern_blob or "\x00"
-- ============ ЧАСТЬ 2 (ОБРАТНЫЙ ПОРЯДОК!) ============
-- 9. Fake part 2 (пакет 1)
fake2 = pattern(fakepat, pos, #data - pos + 1)
if not nofake1 then
rawsend_payload_segmented(fake2, pos-1, opts_fake)
end
-- 10. Real part 2 + seqovl (пакет 2)
part2 = data:sub(pos)
seqovl = 0
if desync.arg.seqovl then
seqovl = resolve_pos(data, l7payload, desync.arg.seqovl)
if seqovl then
seqovl = seqovl - 1 -- Lua→0-based
if seqovl >= (pos-1) then
DLOG("seqovl cancelled: not less than split pos")
seqovl = 0
else
pat = seqovl_pattern_blob or "\x00"
part2 = pattern(pat, 1, seqovl) .. part2
end
else
DLOG("seqovl cancelled: cannot resolve marker")
seqovl = 0
end
end
rawsend_payload_segmented(part2, pos-1-seqovl, opts_orig)
-- 11. Fake part 2 again (пакет 3)
if not nofake2 then
rawsend_payload_segmented(fake2, pos-1, opts_fake)
end
-- ============ ЧАСТЬ 1 ============
-- 12. Fake part 1 (пакет 4)
fake1 = pattern(fakepat, 1, pos-1)
if not nofake3 then
rawsend_payload_segmented(fake1, 0, opts_fake)
end
-- 13. Real part 1 (пакет 5)
part1 = data:sub(1, pos-1)
rawsend_payload_segmented(part1, 0, opts_orig)
-- 14. Fake part 1 again (пакет 6)
if not nofake4 then
rawsend_payload_segmented(fake1, 0, opts_fake)
end
-- 15. Пометить как отправленное
replay_drop_set()
return nodrop and VERDICT_PASS or VERDICT_DROP
end
else
-- 16. Не первый replay
DLOG("not acting on further replay pieces")
end
-- 17. Дропнуть если ранее успешно отправлено
if replay_drop() then
return nodrop and VERDICT_PASS or VERDICT_DROP
end
end
end
```
---
## Нюансы и подводные камни
### 1. Работает только с TCP
Если текущий пакет не TCP (UDP, ICMP и т.д.), `fakeddisorder` делает `instance_cutoff_shim` — отключает себя для этого потока навсегда. Исключение — ICMP-пакеты (related), для которых cutoff не выполняется (просто return).
> [!note] Проще говоря
> Instance cutoff — отключение функции для этого потока до его конца. Почему техника работает только с TCP, разобрано в нюансе [[Zapret2/desync/multisplit#1. Работает только с TCP — и почему|«Работает только с TCP — и почему»]] статьи про multisplit; о самой стадии отсева — в разделе [[Zapret2/жизненный цикл desync-функции#Стадия 1. Отсев чужого транспорта и instance cutoff|Стадия 1]].
### 2. Только ОДИН маркер в pos
В отличие от [[multisplit]] и [[multidisorder]], `fakeddisorder` принимает **один** маркер, а не список. `pos=midsld,endhost` не будет работать как два разреза. Если нужно несколько разрезов с фейками, используйте цепочку инстансов (хотя это нетривиально из-за VERDICT_DROP).
> [!note] Проще говоря
> Цепочка инстансов нетривиальна из-за `VERDICT_DROP`: по нюансу 11 инстанс, стоящий после `fakeddisorder`, увидит `VERDICT_DROP` и не получит оригинальный payload ([[#11. Порядок инстансов важен|нюанс 11]]). Про списки маркеров у соседей — [[Zapret2/desync/multisplit#Маркеры позиций (pos)|Маркеры позиций (pos)]].
### 3. Позиция 1 не работает
Если маркер разрешается в Lua-позицию 1 (то есть задан маркер `0`), fakeddisorder логирует `"split pos resolved to 0. cannot split."` и ничего не делает. Минимальный работающий разрез — `pos=1`, дефолт — `pos=2`.
### 4. Fooling ОБЯЗАТЕЛЕН для фейков
Без fooling-параметров (tcp_ack, tcp_seq, ip_ttl, tcp_md5, badsum и т.д.) сервер **примет фейковые сегменты** как реальные данные. Это повредит TCP-поток. Всегда указывайте хотя бы один fooling-параметр:
```bash
# ПЛОХО: фейки без fooling — сервер их примет!
--lua-desync=fakeddisorder:pos=midsld
# ХОРОШО: фейки с badseq
--lua-desync=fakeddisorder:pos=midsld:tcp_ack=-66000:tcp_ts_up
```
> [!note] Проще говоря
> Фейк без порчи заголовка сервер не отличит от настоящих данных и примет. Как фейкам портят заголовки, разобрано в разделе [[Zapret2/ts-and-fooling#Что такое fooling|Что такое fooling]].
### 5. tcp_ts_up рекомендуется с tcp_ack
На Linux-серверах пакеты с инвалидным ACK стабильно отбрасываются **только если** TCP timestamp option идёт первой в заголовке. Без `tcp_ts_up` есть риск, что сервер примет фейк с `tcp_ack=-66000`.
> [!note] Проще говоря
> Инвалидный ACK — номер подтверждения, который не подходит серверу; именно его портит `tcp_ack=-66000`. Опция timestamp и её порядок в заголовке описаны в разделе [[Zapret2/ts-and-fooling#Что такое TCP options (и зачем fooling с ними играет)|Что такое TCP options]].
### 6. ipfrag НЕ задействуется
В отличие от [[multisplit]] и [[multidisorder]], `fakeddisorder` не поддерживает IP-фрагментацию. Объект `ipfrag` установлен в `{}` и для фейков, и для оригиналов. Если нужна IP-фрагментация — используйте `multidisorder` (без фейков, но с ipfrag).
> [!note] Проще говоря
> IP-фрагментация — деление пакета на части на уровне IP, ниже TCP. Здесь её нет ни для фейков, ни для настоящих сегментов; функцию, которая её поддерживает, описывает раздел [[Zapret2/desync/multisplit#F) Standard ipfrag|F) Standard ipfrag]] статьи про multisplit.
### 7. seqovl — маркер, а не число
В [[multisplit]] и [[fakedsplit]] seqovl — просто `tonumber(desync.arg.seqovl)`. В `fakeddisorder` (как и в [[multidisorder]]) seqovl разрешается через `resolve_pos`. Это значит:
- `seqovl=5` работает (разрешится в абсолютную позицию 5, затем -1 = 4)
- `seqovl=host` тоже работает
- Но результат должен быть < pos-1
### 8. seqovl применяется только к real part 2
В отличие от [[fakedsplit]] (где seqovl к real part 1 — первому реальному), в `fakeddisorder` seqovl применяется к real part 2 — первому реальному по порядку отправки (но второму по порядку в payload). Это логично: в disorder-порядке сначала отправляется вторая часть, и именно она получает seqovl.
> [!note] Проще говоря
> Real part 2 — вторая часть запроса, которая при обратном порядке уходит первой из настоящих; поэтому `seqovl` достаётся именно ей.
### 9. nodrop создаёт дублирование
С `nodrop` fakeddisorder отправляет 6 нарезанных пакетов И пропускает оригинальный. Сервер получит данные дважды. Используйте `nodrop` только для отладки.
> [!note] Проще говоря
> Без `nodrop` оригинальный пакет выбрасывается, и сервер получает данные один раз; с `nodrop` уходят и оригинал, и все шесть пакетов, поэтому флаг годится только для отладки.
### 10. Ошибка rawsend прерывает цепочку
Если любой из 6 вызовов `rawsend_payload_segmented` возвращает `false`, fakeddisorder немедленно возвращает `VERDICT_PASS` (оригинальный пакет пропускается). Остальные пакеты из 6 не отправляются, `replay_drop_set` не вызывается.
> [!note] Проще говоря
> Если хотя бы одна отправка не удалась, остальные не выполняются, а оригинальный пакет пропускается как есть.
### 11. Порядок инстансов важен
Если перед `fakeddisorder` стоит `fake` — он отправит свой фейк до того, как fakeddisorder начнёт свою последовательность. Если после fakeddisorder стоит ещё один инстанс — он увидит VERDICT_DROP и не получит оригинальный payload.
> [!note] Проще говоря
> Как показывает пример с `fake` перед `fakeddisorder`, инстансы отрабатывают по очереди, в порядке записи в профиле. Про такой же нюанс у самого `fake` — [[Zapret2/desync/fake#8. Порядок инстансов: fake всегда первый|8. Порядок инстансов: fake всегда первый]].
---
## Отличия от fakedsplit, multisplit и multidisorder
Таблица сравнивает четыре функции по строкам; жирным выделено то, что относится к `fakeddisorder`. Отличия от других функций сегментации со стороны соседей разобраны в разделах [[Zapret2/desync/multisplit#Отличия от других функций сегментации|multisplit]], [[Zapret2/desync/multidisorder#Отличия от других функций сегментации|multidisorder]] и [[Zapret2/desync/fakedsplit#Отличия от других функций сегментации|fakedsplit]].
| Аспект | `multisplit` | `multidisorder` | `fakedsplit` | `fakeddisorder` |
|:-------|:-------------|:----------------|:-------------|:----------------|
| Количество позиций | Список (любое кол-во) | Список (любое кол-во) | **Одна** | **Одна** |
| Порядок отправки | Прямой (1-2-3) | Обратный (3-2-1) | Прямой (1-2) | **Обратный (2-1)** |
| Фейковые сегменты | **Нет** | **Нет** | Да (до 4 шт.) | **Да (до 4 шт.)** |
| Всего пакетов (max) | N+1 (по кол-ву позиций) | N+1 | **6** | **6** |
| seqovl тип | Только число | **Маркер** | Только число | **Маркер** |
| seqovl к какому сегменту | 1-й (прямой) | 2-й (предпоследний) | 1-й реальный (part 1) | **2-й реальный (part 2)** |
| Fooling к | **Всем** сегментам | **Всем** сегментам | Только к фейкам | **Только к фейкам** |
| reconstruct к | **Всем** | **Всем** | Только к фейкам | **Только к фейкам** |
| repeats к | **Всем** | **Всем** | Только к фейкам | **Только к фейкам** |
| ipfrag | Да | Да | **Нет** | **Нет** |
| Уровень запутывания | Один (разрез) | Два (разрез + порядок) | Два (разрез + фейки) | **Три (разрез + фейки + порядок)** |
### Когда что использовать
| Сценарий | Рекомендация |
|:---------|:-------------|
| DPI не реассемблирует TCP, достаточно разрезать | [[multisplit]] |
| DPI реассемблирует, но не проверяет порядок | [[multidisorder]] |
| DPI проверяет порядок, но не отличает фейки | [[fakedsplit]] |
| DPI проверяет и порядок, и содержимое | **`fakeddisorder`** |
| Нужна IP-фрагментация поверх TCP | [[multisplit]] или [[multidisorder]] |
| Нужно несколько позиций разреза с фейками | Цепочка [[fakedsplit]] / `fakeddisorder` |
Таблица выше отвечает на вопрос, какую функцию брать под какой тип DPI; для конкретного провайдера выбор всё равно проверяют на деле по [[Zapret2/verify-strategy#Короткий чек-лист честной проверки|чек-листу честной проверки]]. Для нескольких позиций разреза с фейками остаётся цепочка инстансов ([[#2. Только ОДИН маркер в pos|нюанс 2]]).
---
## Миграция с nfqws1
nfqws1 — движок первой версии zapret: там техники включаются флагами `--dpi-desync-*`, а во второй версии `--lua-desync`. Таблица ниже переводит ключи первой версии в аргументы `fakeddisorder`, общая таблица соответствий флагов есть в заметке [[desync]].
### Соответствие параметров
| nfqws1 | nfqws2 |
|:-------|:-------|
| `--dpi-desync=fakeddisorder` | `--lua-desync=fakeddisorder` |
| `--dpi-desync-split-pos=midsld` | `:pos=midsld` |
| `--dpi-desync-fooling=badseq` | `:tcp_ack=-66000:tcp_ts_up` |
| `--dpi-desync-fooling=badack` | `:tcp_ack=-66000:tcp_ts_up` |
| `--dpi-desync-fooling=md5sig` | `:tcp_md5` |
| `--dpi-desync-fooling=datanoack` | `:tcp_flags_unset=ACK` |
| `--dpi-desync-fooling=hopbyhop` | `:ip6_hopbyhop` |
| `--dpi-desync-fooling=hopbyhop2` | `:ip6_hopbyhop2` |
| `--dpi-desync-split-seqovl=N` | `:seqovl=N` |
| `--dpi-desync-split-seqovl-pattern=HEX` | `:seqovl_pattern=HEX` |
| `--dpi-desync-fake-tls=FILE` | `:pattern=<blobname>` (предзагрузить через `--blob=`) |
| `--dpi-desync-any-protocol` | Не нужно; или `payload=all` в инстансе |
### Пример полной миграции
```bash
# nfqws1:
nfqws --dpi-desync=fakeddisorder \
--dpi-desync-fooling=badseq \
--dpi-desync-split-pos=midsld
# nfqws2 (эквивалент):
nfqws2 \
--payload=tls_client_hello \
--lua-desync=fakeddisorder:pos=midsld:tcp_ack=-66000:tcp_ts_up
```
```bash
# nfqws1 (комплексный):
nfqws --dpi-desync=fakeddisorder \
--dpi-desync-fooling=md5sig \
--dpi-desync-split-pos=midsld \
--dpi-desync-split-seqovl=5 \
--dpi-desync-split-seqovl-pattern=0x1603030000
# nfqws2 (эквивалент):
nfqws2 \
--payload=tls_client_hello \
--lua-desync=fakeddisorder:pos=midsld:tcp_md5:seqovl=5:seqovl_pattern=0x1603030000
```
```bash
# nfqws1 (фулл):
nfqws --dpi-desync=fake,fakeddisorder \
--dpi-desync-fooling=badseq \
--dpi-desync-split-pos=midsld \
--dpi-desync-fake-tls-mod=rnd,rndsni,dupsid
# nfqws2 (эквивалент — fake отдельным инстансом):
nfqws2 \
--payload=tls_client_hello \
--lua-desync=fake:blob=fake_default_tls:tcp_ack=-66000:tcp_ts_up:tls_mod=rnd,rndsni,dupsid \
--lua-desync=fakeddisorder:pos=midsld:tcp_ack=-66000:tcp_ts_up
```
---
## Практические примеры
Ниже 18 примеров: от минимального до боевых. Каждая команда — строка для [[Zapret2/profile#Анатомия профиля|профиля]]; подробности про аргументы `pos`, `seqovl`, `pattern`, `nofake1`–`nofake4` — в разделах [[#Маркер позиции (pos)|Маркер позиции (pos)]], [[#seqovl — скрытый фейк внутри реального сегмента|seqovl]] и [[#Полный список аргументов|Полный список аргументов]].
### 1. Минимальный (с fooling)
```bash
--lua-desync=fakeddisorder:tcp_ack=-66000:tcp_ts_up
```
Разрезает payload после 2-го байта (`pos=2` по умолчанию) с badseq fooling для фейков. 6 пакетов.
### 2. TLS: разрез посередине SNI
```bash
--payload=tls_client_hello --lua-desync=fakeddisorder:pos=midsld:tcp_ack=-66000:tcp_ts_up
```
SNI разрезан пополам. DPI видит 6 пакетов с перемешанными фейковыми и реальными сегментами в обратном порядке — двойное запутывание.
### 3. TLS: разрез + seqovl (тройное запутывание)
```bash
--payload=tls_client_hello --lua-desync=fakeddisorder:pos=midsld:seqovl=5:seqovl_pattern=0x1603030000:tcp_ack=-66000:tcp_ts_up
```
Три уровня: фейки + disorder + seqovl. Real part 2 имеет 4-байтовый TLS-фейк слева (5→resolve→5, 5-1=4), который DPI может принять за начало TLS record.
### 4. TLS: seqovl как маркер
```bash
--payload=tls_client_hello --lua-desync=fakeddisorder:pos=midsld:seqovl=sld:tcp_ack=-66000:tcp_ts_up
```
seqovl разрешается в позицию начала SLD. Фейковая часть слева от real part 2 — от начала SLD до позиции разреза.
### 5. HTTP: разрез в начале hostname
```bash
--payload=http_req --lua-desync=fakeddisorder:pos=host:tcp_ack=-66000:tcp_ts_up
```
Для `GET / HTTP/1.1\r\nHost: example.com\r\n...` разрежет так, что часть 1 содержит заголовки до hostname, а часть 2 — hostname и далее.
### 6. HTTP: кастомный паттерн для фейков
```bash
--payload=http_req --lua-desync=fakeddisorder:pos=host:pattern=0x474554202F20485454502F312E310D0A:tcp_ack=-66000:tcp_ts_up
```
Фейки заполняются паттерном, похожим на начало HTTP-запроса (`GET / HTTP/1.1\r\n`). DPI может принять фейк за реальный запрос к другому хосту.
### 7. С tcp_md5 fooling
```bash
--payload=tls_client_hello --lua-desync=fakeddisorder:pos=midsld:tcp_md5:tcp_ts_up
```
Вместо badseq используется TCP MD5 signature option. Сервер отбрасывает пакеты с неверной MD5 подписью.
### 8. С badsum reconstruct
```bash
--payload=tls_client_hello --lua-desync=fakeddisorder:pos=midsld:tcp_ack=-66000:tcp_ts_up:badsum
```
Фейки отправляются с испорченным TCP checksum. Двойная защита: и badseq, и badsum.
### 9. Без первого и последнего фейка (4 пакета)
```bash
--payload=tls_client_hello --lua-desync=fakeddisorder:pos=midsld:tcp_ack=-66000:tcp_ts_up:nofake1:nofake4
```
Отключены фейки "снаружи" (первый и последний). Остаётся: real part 2, fake part 2 (после), fake part 1 (перед), real part 1. 4 пакета.
### 10. Только внутренние фейки (4 пакета)
```bash
--payload=tls_client_hello --lua-desync=fakeddisorder:pos=midsld:tcp_ack=-66000:tcp_ts_up:nofake1:nofake2
```
Вся часть 2 — только реальная (без обрамления фейками). Часть 1 — с фейками. Полезно, когда DPI анализирует только начало потока.
### 11. Без всех фейков (эквивалент disorder)
```bash
--payload=tls_client_hello --lua-desync=fakeddisorder:pos=midsld:nofake1:nofake2:nofake3:nofake4
```
Отключены все 4 фейка. Остаются только 2 реальных пакета в обратном порядке. Фактически — [[multidisorder]] с одной позицией. Fooling не нужен (применяется только к фейкам, которых нет).
### 12. Цепочка: fake + fakeddisorder
```bash
--payload=tls_client_hello \
--lua-desync=fake:blob=fake_default_tls:repeats=5:tcp_md5 \
--lua-desync=fakeddisorder:pos=midsld:tcp_ack=-66000:tcp_ts_up
```
Сначала 5 фейковых TLS ClientHello (с md5sig fooling), затем fakeddisorder с 6 пакетами. Итого 11 пакетов. Массированная атака на DPI.
### 13. С произвольным blob вместо payload
```bash
--blob=mydata:@custom_payload.bin \
--lua-desync=fakeddisorder:blob=mydata:pos=50:tcp_ack=-66000:tcp_ts_up
```
Режет и отправляет произвольные данные из файла вместо реального payload.
### 14. С optional для необязательного blob
```bash
--lua-desync=fakeddisorder:blob=maybe_missing:optional:pos=midsld:tcp_ack=-66000:tcp_ts_up
```
Если blob `maybe_missing` не существует — тихий пропуск, без ошибок.
### 15. Боевой пример для YouTube
```bash
--filter-tcp=443 --hostlist=youtube.txt \
--payload=tls_client_hello \
--lua-desync=fakeddisorder:pos=midsld:tcp_ack=-66000:tcp_ts_up
```
Разрезает TLS ClientHello посередине SNI домена YouTube с фейками в обратном порядке.
### 16. Комбинация fooling + repeats для фейков
```bash
--payload=tls_client_hello \
--lua-desync=fakeddisorder:pos=midsld:tcp_ack=-66000:tcp_ts_up:repeats=3
```
Каждый из 4 фейковых пакетов отправляется 3 раза. Реальные — по 1 разу. Итого 14 пакетов (4*3 + 2).
### 17. IPv6: hop-by-hop fooling
```bash
--payload=tls_client_hello \
--lua-desync=fakeddisorder:pos=midsld:ip6_hopbyhop:tcp_ts_up
```
Для IPv6: фейки отправляются с extension header hop-by-hop, который сбрасывается на первом маршрутизаторе. Реальные сегменты — без hop-by-hop.
### 18. Отладка: не блокировать оригинал
```bash
--payload=tls_client_hello --lua-desync=fakeddisorder:pos=midsld:tcp_ack=-66000:tcp_ts_up:nodrop
```
Отправляет 6 нарезанных пакетов И пропускает оригинальный (для экспериментов/отладки).
---
## 📚 См. также
- [[desync]] — обзор всех функций `--lua-desync` и общий контракт: кто вызывает функцию, что ей передаёт и как складываются вердикты
- [[жизненный цикл desync-функции]] — восемь стадий, общих для всех техник дурения: отсев транспорта, выбор данных, replay, вердикты
- [[multisplit]] — тот же разрез, но без фейков и без обратного порядка; там же подробно разобран принцип `seqovl`
- [[multidisorder]] — тот же обратный порядок, но без фейков; там `seqovl` тоже маркер, разобранный в разделе [[Zapret2/desync/multidisorder#seqovl как маркер|seqovl как маркер]]
- [[fakedsplit]] — те же фейки вокруг каждой части, но части уходят в прямом порядке
- [[hostfakesplit]] — разрез по границам имени хоста с подмешиванием фейкового имени
- [[tcpseg]] — отправка произвольного диапазона данных, ограниченного двумя маркерами
- [[oob]] — сегментация с urgent-байтом вместо разреза
- [[fake]] — отдельный фейковый пакет, с которым `fakeddisorder` комбинируют в цепочке
- [[blob]] — как объявлять и передавать данные для аргументов `blob`, `pattern` и `seqovl_pattern`
- [[payload]] — распознавание типов протоколов, от которого зависит работа относительных маркеров
- [[ts-and-fooling]] — что такое fooling, как фейк заставляют «умереть» до сервера и зачем нужен `tcp_ts_up`
- [[verify-strategy]] — как честно проверить, работает ли подобранная комбинация
- [[последовательность аргументов]] — как выстраивается цепочка инстансов в профиле
- [[profile]] — где `--lua-desync` живёт среди остальных настроек
- [[DPI/DPI|DPI и ТСПУ]] — как устроена инспекция трафика, против которой работает `fakeddisorder`
---
> **Источники:** `lua/zapret-antidpi.lua:908-1021`, `docs/manual.md:4165-4206`, `docs/manual.en.md:3984-4025` из репозитория zapret2.
---
> [!quote] 🤖 Эти статьи открыты — можно обучать на них ИИ
> При желании вы можете натренировать ИИ на наших статьях. Исходное форматирование доступно в Forgejo: [исходник этой заметки](https://git2.zapret.moe/zapretdiscordyoutube/todo/src/branch/main/Zapret2/desync/fakeddisorder.md) · [скачать весь репозиторий одним zip-архивом](https://git2.zapret.moe/zapretdiscordyoutube/todo/archive/main.zip).