---
date: 2026-02-17
tags:
  - zapret
  - zapret2
  - nfqws2
  - lua
  - lua-desync
  - antidpi
  - tcp
  - multidisorder
  - seqovl
  - disorder
aliases:
  - multidisorder
---

# `multidisorder` — TCP-сегментация в обратном порядке (zapret2 / nfqws2)

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

`multidisorder` — функция TCP-сегментации в zapret2, которая берёт текущий payload (или reasm, или blob), разрезает его на несколько TCP-сегментов по заданным позициям и отправляет их в **обратном порядке** (от последнего к первому). Обратный порядок (disorder) эксплуатирует поведение TCP-стека: при получении внеочередных сегментов стек буферизирует их и собирает поток, а DPI зачастую не справляется с реассемблированием разупорядоченных данных. После успешной отправки выносит `VERDICT_DROP`, чтобы оригинальный пакет не ушёл.

Родственные функции: [[multisplit]] (прямой порядок), [[fakedsplit]] (с фейками), [[fakeddisorder]] (фейки + обратный порядок), [[hostfakesplit]] (по hostname), [[tcpseg]] (диапазон), [[oob]] (urgent byte), [[multidisorder_legacy]] (совместимый с nfqws1 алгоритм).

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

---

## Оглавление

- [Зачем нужен multidisorder](#зачем-нужен-multidisorder)
- [Быстрый старт](#быстрый-старт)
- [Откуда берутся данные для нарезки](#откуда-берутся-данные-для-нарезки)
- [Маркеры позиций (pos)](#маркеры-позиций-pos)
  - [Типы маркеров](#типы-маркеров)
  - [Относительные маркеры](#относительные-маркеры)
  - [Арифметика маркеров](#арифметика-маркеров)
  - [Как маркеры разрешаются в коде](#как-маркеры-разрешаются-в-коде)
  - [Важные нюансы pos](#важные-нюансы-pos)
- [Обратный порядок отправки — суть disorder](#обратный-порядок-отправки--суть-disorder)
  - [Почему disorder ломает DPI](#почему-disorder-ломает-dpi)
  - [Ограничение: Windows-серверы](#ограничение-windows-серверы)
- [seqovl — перезапись буфера сокета через перекрытие](#seqovl--перезапись-буфера-сокета-через-перекрытие)
  - [Принцип работы seqovl в disorder](#принцип-работы-seqovl-в-disorder)
  - [Отличие seqovl от multisplit](#отличие-seqovl-от-multisplit)
  - [seqovl как маркер](#seqovl-как-маркер)
  - [Валидация seqovl: должен быть меньше pos 1](#валидация-seqovl-должен-быть-меньше-pos-1)
  - [Нюанс реализации: ovl = seqovl - 1](#нюанс-реализации-ovl--seqovl---1)
  - [seqovl_pattern](#seqovl_pattern)
- [Полный список аргументов](#полный-список-аргументов)
  - [A) Собственные аргументы multidisorder](#a-собственные-аргументы-multidisorder)
  - [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 ipfrag](#f-standard-ipfrag)
  - [G) Standard reconstruct](#g-standard-reconstruct)
  - [H) Standard rawsend](#h-standard-rawsend)
- [Порядок отправки сегментов](#порядок-отправки-сегментов)
- [Поведение при replay / reasm](#поведение-при-replay--reasm)
- [Автосегментация по MSS](#автосегментация-по-mss)
- [Место в общем скелете](#место-в-общем-скелете)
- [Псевдокод алгоритма](#псевдокод-алгоритма)
- [Нюансы и подводные камни](#нюансы-и-подводные-камни)
- [Отличия от других функций сегментации](#отличия-от-других-функций-сегментации)
- [Миграция с nfqws1](#миграция-с-nfqws1)
- [Практические примеры](#практические-примеры)

---

## Зачем нужен multidisorder

DPI анализирует TCP-поток, пытаясь собрать полный payload и найти в нём сигнатуры (hostname в HTTP, SNI в TLS). Разрезание payload на сегменты уже усложняет работу DPI ([[multisplit]]), но **обратный порядок** отправки создаёт дополнительную проблему:

1. **DPI не реассемблирует out-of-order сегменты:** многие DPI работают потоково (stream-based) и ожидают сегменты в порядке sequence number. Получив сначала хвост потока, DPI может потерять контекст или не дождаться головы
2. **DPI не может сопоставить hostname:** если разрез проходит через SNI/Host, а сегменты приходят задом наперёд, ни попакетный, ни потоковый DPI не найдёт сигнатуру
3. **seqovl в режиме disorder перезаписывает буфер:** в отличие от [[multisplit]], где seqovl работает через выход за TCP window, в disorder фейковые данные сначала попадают в буфер сокета, а затем **перезаписываются** реальными данными из последнего сегмента

Сервер при этом корректно собирает поток — TCP-стек буферизирует внеочередные сегменты и отдаёт данные приложению только после сборки непрерывной последовательности.

**multidisorder** vs **multisplit:** disorder работает за счёт разупорядочивания, а не за счёт линейного дробления. Для замешивания фейковых сегментов (отдельные пакеты с fooling) есть [[fakeddisorder]].

---

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

Минимально (разрез по позиции 2, payload=known, dir=out):

```bash
--lua-desync=multidisorder
```

Типовой TLS-разрез:

```bash
--payload=tls_client_hello --lua-desync=multidisorder:pos=midsld
```

TLS с seqovl (маркер):

```bash
--payload=tls_client_hello --lua-desync=multidisorder:pos=midsld:seqovl=midsld-1
```

HTTP с разрезом по hostname:

```bash
--payload=http_req --lua-desync=multidisorder:pos=host,midsld,endhost
```

---

## Откуда берутся данные для нарезки

Внутри `multidisorder` данные (`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 может распознать.

---

## Маркеры позиций (pos)

`pos` — главный аргумент `multidisorder`. Определяет **где** внутри payload будет произведён разрез. Задаётся как строка со списком маркеров через запятую.

### Типы маркеров

| Тип | Описание | Пример |
|:----|:---------|:-------|
| **Абсолютный положительный** | Смещение от начала payload, считая с 0. `pos=N` → первые N байт становятся отдельным сегментом | `1`, `5`, `100` |
| **Абсолютный отрицательный** | Смещение от конца payload. `-1` = последний байт | `-1`, `-10`, `-50` |
| **Относительный** | Логическая позиция внутри распознанного payload. Привязана к структуре протокола | `midsld`, `host`, `sniext` |

### Относительные маркеры

| Маркер | Описание | Для каких 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      — два байта после начала метода (разрежет "GET " после "GE")
sniext+1      — один байт после начала SNI extension data
host+3        — три байта после начала hostname
-1            — последний байт payload (абсолютный, не относительный)
```

Арифметика работает и с абсолютными маркерами, хотя это избыточно (`5+3` = `8`).

### Пример списка маркеров

```
pos=100,midsld,sniext+1,endhost-2,-10
```

Здесь 5 маркеров -> payload разрежется максимум на 6 частей (если все маркеры успешно разрешатся и дадут различные позиции).

### Как маркеры разрешаются в коде

Внутри `multidisorder` вызывается:

```lua
local pos = resolve_multi_pos(data, desync.l7payload, spos)
```

Функция `resolve_multi_pos`:

1. Разбивает строку `spos` по запятым
2. Для каждого маркера вызывает `resolve_pos(blob, l7payload_type, marker)`
3. Если маркер не может быть разрешён (например, `midsld` для `unknown` payload) — он **молча пропускается**
4. Результаты дедуплицируются и сортируются
5. Возвращается массив **уникальных** позиций, уже переведённых в 1-based индексы Lua (маркер `1` превращается в позицию `2`, маркер `0` — в позицию `1`)

Затем вызывается:

```lua
delete_pos_1(pos)  -- удалить Lua-позицию 1, то есть маркер 0
```

### Важные нюансы pos

- **Разрез в самом начале данных отбрасывается.** `delete_pos_1` удаляет Lua-позицию 1, которая соответствует маркеру `0`: первый сегмент вышел бы пустым. Считать маркеры нужно с нуля, поэтому под удаление попадает `pos=0`, а `pos=1` (первый байт отдельным сегментом) работает и применяется часто. Частая жертва этого правила — `pos=method` для HTTP: метод обычно лежит на смещении 0, разреза не произойдёт; нужен сдвиг вроде `pos=method+2`
- **Дублирующиеся позиции объединяются.** `pos=5,5,5` = `pos=5`
- **Неразрешимые маркеры пропускаются.** Если `midsld` не разрешается (payload = unknown), он просто исчезает из списка. Если все маркеры не разрешились — multidisorder ничего не делает (логирует "no valid split positions")
- **Позиции сортируются.** Независимо от порядка записи, `pos=100,5,50` будет обработано как `5,50,100`
- **По умолчанию `pos=2`.** Если `pos` не задан, payload делится на 2 части: первые 2 байта отдельным сегментом, весь остаток — вторым

---

## Обратный порядок отправки — суть disorder

Ключевое отличие `multidisorder` от [[multisplit]]: сегменты отправляются **от последнего к первому** (в порядке убывания sequence number). Цикл в `multidisorder_send`:

```lua
for i=#pos,0,-1 do
```

```
multisplit:      отправка 1 -> 2 -> 3 -> 4  (прямой порядок)
multidisorder:   отправка 4 -> 3 -> 2 -> 1  (обратный порядок)
```

### Почему disorder ломает DPI

TCP-стек сервера спроектирован для работы с внеочередными сегментами — он буферизирует их и ждёт недостающие части. DPI, как правило, не имеет такой роскоши:

1. **Потоковые DPI** обрабатывают данные по мере поступления. Получив последний сегмент первым, DPI видит данные без начала (без заголовков HTTP/TLS) и не может распознать протокол
2. **Попакетные DPI** анализируют каждый пакет отдельно. В каждом отдельном сегменте нет полной сигнатуры
3. **DPI с реассемблированием** теоретически могут собрать поток, но на практике многие имеют ограниченный буфер или timeout и не дожидаются всех частей

### Ограничение: Windows-серверы

Техника seqovl в режиме disorder **не работает с Windows-серверами**. При перекрытии sequence numbers:

- **Linux/BSD/macOS:** более поздний сегмент **перезаписывает** ранее буферизированные данные
- **Windows:** **сохраняет** первые полученные данные, игнорируя перекрывающиеся

Это означает, что seqovl_pattern, записанный в буфер предпоследним сегментом, на Windows **не будет перезаписан** реальными данными из последнего сегмента — сервер получит мусор.

**Без seqovl** multidisorder работает нормально на всех системах — простое разупорядочивание не зависит от поведения при перекрытии.

---

## seqovl — перезапись буфера сокета через перекрытие

В `multidisorder` техника seqovl работает **принципиально иначе**, чем в [[multisplit]]. Здесь seqovl эксплуатирует переписывание данных в буфере сокета при получении перекрывающихся сегментов.

### Принцип работы seqovl в disorder

Рассмотрим payload из 2 частей: `pos=100` (одна точка разреза).

```
Payload (300 байт): [ЧАСТЬ_1: 100 байт][ЧАСТЬ_2: 200 байт]
                                         ^pos=100

seqovl=midsld (разрешился в 50), ovl = 50 - 1 = 49

Порядок отправки (обратный, i от #pos до 0):

  Шаг 1 (i=1): ЧАСТЬ_2 с seqovl!
     К ЧАСТЬ_2 слева приписывается 49 байт PATTERN
     part = [PATTERN(49)][ЧАСТЬ_2(200)]
     seq  = pos_start - 1 - ovl = 100 - 1 - 49 = 50
     len  = 249
     Отправляется первым

  Шаг 2 (i=0): ЧАСТЬ_1 без seqovl
     part = [ЧАСТЬ_1(100)]
     seq  = 0
     len  = 100
     Отправляется последним
```

**Что происходит на сервере (Linux/BSD):**

```
t1: приходит [PATTERN(49)][ЧАСТЬ_2(200)] seq=50 len=249

  Буфер сокета:
  позиции:  0                50               100             300
            [     пусто     ][PATTERN(49)][ЧАСТЬ_2(200)........]
                              ^--- PATTERN занимает позиции 50..98
                                           ^--- ЧАСТЬ_2 начинается с позиции 99

  Данные НЕ выдаются приложению — нет непрерывной последовательности от 0

t2: приходит [ЧАСТЬ_1(100)] seq=0 len=100

  Буфер сокета (Linux/BSD — позднее ПЕРЕЗАПИСЫВАЕТ):
  позиции:  0                               100             300
            [ЧАСТЬ_1(100)....................][ЧАСТЬ_2(200)........]
            ^--- ЧАСТЬ_1 занимает позиции 0..99
                 PATTERN ПЕРЕЗАПИСАН реальными данными!

  Непрерывная последовательность 0..299 -> выдаётся приложению корректно
```

**На Windows-сервере:**

```
t2: приходит [ЧАСТЬ_1(100)] seq=0 len=100

  Буфер сокета (Windows — СОХРАНЯЕТ старое):
  позиции:  0          50               100             300
            [ЧАСТЬ_1(50)][PATTERN(49)][ЧАСТЬ_2(200)........]
            ^--- только байты 0..49 из ЧАСТЬ_1 записались
                 ^--- байты 50..98 остались от PATTERN (мусор!)

  Приложение получает повреждённые данные!
```

### Отличие seqovl от multisplit

| Аспект | seqovl в multisplit | seqovl в multidisorder |
|:-------|:--------------------|:-----------------------|
| Механизм | Выход за левую границу TCP window | **Перезапись буфера** перекрывающимся сегментом |
| К какому сегменту | 1-й отправляемый (1-й в оригинале, `i==0`) | **Предпоследний** отправляемый (2-й в оригинале, `i==1`) |
| Тип значения | Только число | **Маркер** (число, имя маркера, маркер+арифметика) |
| Кто отбрасывает фейк | TCP-стек (данные за пределами window) | **Перезапись** следующим сегментом (последним отправляемым) |
| Работает на Windows | Да (TCP window — универсальный механизм) | **Нет** (Windows не перезаписывает буфер) |

### seqovl как маркер

В отличие от [[multisplit]], где `seqovl` принимает только число, в `multidisorder` seqovl разрешается через `resolve_pos()` — полноценный маркер:

```lua
seqovl = resolve_pos(data, desync.l7payload, desync.arg.seqovl)
```

Это означает, что поддерживаются:

```
seqovl=5               — число (абсолютная позиция, как в multisplit)
seqovl=midsld-1        — маркер с арифметикой (типичное использование)
seqovl=host+2          — маркер с арифметикой
seqovl=sld             — маркер без арифметики
seqovl=-10             — отрицательная позиция (от конца данных)
```

**Типичный паттерн:** `pos=midsld` + `seqovl=midsld-1`. Разрез по середине SLD, а seqovl перекрывает почти всю первую часть.

**Если маркер не резолвится** (например, `seqovl=midsld-1` для unknown payload) — seqovl отменяется, но сегментация в обратном порядке всё равно происходит. В лог записывается "seqovl cancelled because could not resolve marker".

### Валидация seqovl: должен быть меньше pos[1]

Из `multidisorder_send`:

```lua
if seqovl>=pos[1] then
    DLOG("multidisorder: seqovl cancelled because seqovl "..
         (seqovl-1).." is not less than the first split pos "..(pos[1]-1))
```

seqovl (разрешённое значение маркера) **обязательно должен быть строго меньше** `pos[1]` (первой позиции разреза). Если это условие не выполнено — seqovl отменяется (но сегментация всё равно происходит, просто без перекрытия).

**Почему:** seqovl приписывается к сегменту `i==1` (ЧАСТЬ_2, от `pos[1]` до конца или до `pos[2]-1`). Перекрытие заползает назад на `ovl` байт. Если seqovl >= pos[1], перекрытие вылезло бы за начало данных первого сегмента, что не имеет смысла.

Пример:

```
pos=10,50       -> pos[1]=10
seqovl=midsld   -> разрешился в 8    -> OK (8 < 10)
seqovl=midsld   -> разрешился в 10   -> CANCELLED (10 >= 10, не строго меньше)
seqovl=midsld   -> разрешился в 15   -> CANCELLED (15 >= 10)
```

### Нюанс реализации: ovl = seqovl - 1

В коде `multidisorder_send` есть важная деталь:

```lua
ovl = seqovl - 1
```

Реальный размер перекрытия на 1 байт **меньше** разрешённого значения маркера. Это связано с тем, что `seqovl` возвращается как позиция (1-based в Lua), а `ovl` используется как размер смещения (0-based). Для пользователя это означает:

```
seqovl=midsld  (разрешился, скажем, в 50)
-> ovl = 49
-> К сегменту приписывается 49 байт pattern слева
-> TCP seq уменьшается на 49
```

**Следствие:** если seqovl разрешится в 1, то `ovl = 0` — seqovl фактически не применяется. Минимальный эффективный seqovl — значение 2 (ovl = 1, 1 байт перекрытия).

### seqovl_pattern

Паттерн, которым заполняется seqovl-область (ovl байт слева от реальных данных). По умолчанию — `0x00` (нули).

В `multidisorder` `seqovl_pattern` — это **имя blob**. Паттерн повторяется функцией `pattern()` до нужной длины `ovl` (= seqovl - 1).

```bash
# Inline hex blob (маскировка под начало TLS record)
--lua-desync=multidisorder:pos=midsld:seqovl=midsld-1:seqovl_pattern=0x1603030000

# Предзагруженный blob
--blob=tlspat:0x1603030100 \
--lua-desync=multidisorder:pos=midsld:seqovl=midsld-1:seqovl_pattern=tlspat
```

Если `optional` задан и blob `seqovl_pattern` отсутствует — используется нулевой паттерн (операция не отменяется).

---

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

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

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

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

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

#### `pos`

- **Формат:** `pos=<marker[,marker2,...]>`
- **Тип:** строка со списком маркеров через запятую
- **По умолчанию:** `"2"`
- **Описание:** Точки разреза. Каждый маркер определяет позицию, по которой payload будет разрезан. N маркеров -> до N+1 сегментов. Сегменты отправляются в **обратном** порядке
- **Примеры:**
  - `pos=2` — разрез после 2-го байта (дефолт)
  - `pos=1` — первый байт уходит отдельным сегментом
  - `pos=midsld` — разрез посередине SLD
  - `pos=1,midsld` — два разреза: после 1-го байта и посередине SLD -> 3 сегмента
  - `pos=host,midsld,endhost-2,-10` — четыре разреза -> до 5 сегментов
  - `pos=method+2` — после первых 2 символов HTTP-метода

#### `seqovl`

- **Формат:** `seqovl=<marker>` (маркер, число, или маркер+арифметика)
- **Тип:** **маркер** (в отличие от multisplit, где только число). Разрешается через `resolve_pos()`
- **По умолчанию:** не задан (нет seqovl)
- **Описание:** Применяется к сегменту `i==1` (2-й в оригинальном порядке, предпоследний отправляемый). К данным этого сегмента слева добавляется `seqovl-1` байт `seqovl_pattern`, а TCP `th_seq` уменьшается на `seqovl-1`. Последний отправляемый сегмент (1-й в оригинале) перезаписывает фейковые данные в буфере сервера
- **Ограничение:** разрешённое значение seqovl **должно быть строго меньше** pos[1], иначе seqovl отменяется
- **Примеры:**
  - `seqovl=5` — 4 байта фейка слева (ovl = 5-1)
  - `seqovl=midsld-1` — типичное использование с `pos=midsld`
  - `seqovl=host+2` — маркер с арифметикой
  - `seqovl=sld` — маркер без арифметики

#### `seqovl_pattern`

- **Формат:** `seqovl_pattern=<blobName>`
- **Тип:** имя blob-переменной
- **По умолчанию:** один байт `0x00`, повторяемый до длины `ovl` (= seqovl - 1)
- **Описание:** Данные для заполнения seqovl-области. Blob повторяется функцией `pattern()` до нужного размера
- **Поведение с `optional`:** если `optional` задан и blob отсутствует — используется нулевой паттерн, seqovl не отменяется
- **Примеры:**
  - `seqovl_pattern=0x1603030000` — inline hex (маскировка под TLS)
  - `seqovl_pattern=my_pattern_blob` — предзагруженный blob

#### `blob`

- **Формат:** `blob=<blobName>`
- **Тип:** имя blob-переменной
- **По умолчанию:** не задан
- **Описание:** Заменить текущий payload/reasm на указанный blob и резать/слать его. Используется для отправки произвольных данных (фейковых payload, модифицированных ClientHello и т.д.)
- **Примеры:**
  - `blob=fake_default_tls` — стандартный TLS-фейк
  - `blob=0xDEADBEEF` — inline hex
  - `blob=my_custom_ch` — предзагруженный blob

#### `optional`

- **Формат:** `optional` (флаг, без значения)
- **Описание:** Мягкий режим:
  - Если задан `blob=...` и blob отсутствует -> multidisorder **ничего не делает** (тихий skip, без ошибок)
  - Если задан `seqovl_pattern=...` и blob отсутствует -> используется нулевой паттерн (seqovl не отменяется)
- **Использование:** защита от ошибок при использовании blob, которые могут отсутствовать (например, если blob генерируется другой функцией)

#### `nodrop`

- **Формат:** `nodrop` (флаг, без значения)
- **Описание:** После успешной отправки сегментов **не выносить** `VERDICT_DROP` (вместо этого вернуть `VERDICT_PASS`). Это означает, что оригинальный пакет тоже будет отправлен (наряду с нарезанными сегментами)
- **Использование:** для отладки, для отправки произвольных данных без блокировки оригинала
- **Предупреждение:** в боевых профилях `nodrop` обычно нежелателен — оригинал ещё раз уйдёт, что создаст дублирование и может ухудшить обход

---

### B) Standard direction

| Параметр | Значения | По умолчанию |
|:---------|:---------|:-------------|
| `dir` | `in`, `out`, `any` | `out` |

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

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

При первом вызове с указанным `dir` функция делает `direction_cutoff_opposite` — отсекает себя от противоположного направления.

---

### 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-фильтр.

---

### D) Standard fooling

Модификации L3/L4 заголовков. В `multidisorder` применяются **ко всем** отправляемым сегментам (в отличие от [[fakeddisorder]], где fooling идёт только на фейки).

| Параметр | Описание | Пример |
|:---------|:---------|:-------|
| `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:** На Linux-серверах пакеты с инвалидным ACK стабильно отбрасываются **только если** TCP timestamp option идёт первой в заголовке. `tcp_ts_up` перемещает её в начало, обеспечивая корректную работу badseq-fooling.

---

### 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` применяется к **каждому** отправляемому сегменту (включая под-сегменты при MSS-сегментации).

---

### F) Standard ipfrag

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

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

---

### G) Standard reconstruct

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

---

### H) Standard rawsend

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

---

## Порядок отправки сегментов

`multidisorder` всегда отправляет сегменты в **обратном порядке** — от последнего к первому (в порядке убывания TCP sequence). Цикл в `multidisorder_send`: `for i=#pos,0,-1`.

### Пример с 3 позициями разреза (без seqovl)

```
Payload (600 байт):
[AAA...100 байт...AAA][BBB...200 байт...BBB][CCC...150 байт...CCC][DDD...150 байт...DDD]
                       ^pos=100               ^pos=300               ^pos=450

                        Оригинальный порядок          Порядок отправки
                        -------------------          ----------------
Сегмент 0 (i=0):       [AAA...100] seq=0             4-й (последний)
Сегмент 1 (i=1):       [BBB...200] seq=100           3-й
Сегмент 2 (i=2):       [CCC...150] seq=300           2-й
Сегмент 3 (i=3):       [DDD...150] seq=450           1-й (первым отправляется)

Реальная последовательность отправки:
  1. [DDD...150] seq=450  len=150   (i=3, последний сегмент данных)
  2. [CCC...150] seq=300  len=150   (i=2)
  3. [BBB...200] seq=100  len=200   (i=1)
  4. [AAA...100] seq=0    len=100   (i=0, первый сегмент данных)
```

### Пример с seqovl (2 сегмента)

```
Payload (300 байт), pos=100, seqovl=midsld (разрешился в 50):
ovl = 50 - 1 = 49

                        Оригинальный порядок          Порядок отправки
                        -------------------          ----------------
Сегмент 0 (i=0):       [ЧАСТЬ_1: 100 байт] seq=0    2-й (последний)
Сегмент 1 (i=1):       [ЧАСТЬ_2: 200 байт] seq=100  1-й (первым)

Реальная последовательность отправки:
  1. i=1: [PATTERN(49)][ЧАСТЬ_2(200)]  seq=100-1-49=50   len=249  (seqovl!)
  2. i=0: [ЧАСТЬ_1(100)]               seq=0              len=100  (перезаписывает PATTERN)
```

### ASCII-диаграмма: хронология буфера сокета на сервере

```
Время -->

  t1: приходит [PATTERN(49)][ЧАСТЬ_2(200)]    seq=50  len=249

      Буфер сокета:
      позиция: 0           50          99  100                    299
               [  пусто   ][PATRN(49)][?? ][ЧАСТЬ_2(200)..............]
                            ^^^^^^^^^^^^--- PATTERN записан в позиции 50-98
                                            ^^^--- ЧАСТЬ_2 в позициях 99-298
      Данные НЕ выдаются приложению (нет непрерывности от 0)

  t2: приходит [ЧАСТЬ_1(100)]    seq=0  len=100

      Linux/BSD (поздний ПЕРЕЗАПИСЫВАЕТ):
      позиция: 0                        100                    299
               [ЧАСТЬ_1(100)............][ЧАСТЬ_2(200)..............]
               ^--- ЧАСТЬ_1 перезаписала позиции 0-99
                    PATTERN уничтожен, данные корректны!

      Windows (СОХРАНЯЕТ раннее):
      позиция: 0           50          99  100                    299
               [ЧАСТЬ_1(50)][PATRN(49)][?? ][ЧАСТЬ_2(200)..............]
               ^--- только позиции 0-49 обновились
                    позиции 50-98 остались от PATTERN = МУСОР
```

### Пример с 3 позициями + seqovl

```
Payload (600 байт), pos=100,300,450, seqovl=host (разрешился в 80):
ovl = 80 - 1 = 79

Порядок отправки:
  1. i=3: [DDD...150]                  seq=450      len=150   (без seqovl)
  2. i=2: [CCC...150]                  seq=300      len=150   (без seqovl)
  3. i=1: [PATTERN(79)][BBB...200]     seq=100-1-79=20  len=279  (seqovl! только i==1)
  4. i=0: [AAA...100]                  seq=0        len=100   (перезаписывает PATTERN)
```

**Обратите внимание:** seqovl применяется **только** к `i==1` (2-й сегмент в оригинальном порядке, предпоследний в порядке отправки), независимо от количества позиций разреза.

---

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

Многопакетный запрос (большой TLS ClientHello с post-quantum ключами и т. п.) `nfqws2` придерживает, собирает в буфер `reasm_data` и перепроигрывает через desync-функции. `multidisorder` использует штатную развилку перепроигрывания из общего скелета desync-функций ([[жизненный цикл desync-функции]], стадия 6) без изменений: нарезает и отправляет **весь** собранный буфер на первой части, а остальные части дропает, потому что их содержимое уже ушло в составе нарезки. Если отправка сорвалась, флаг «реасм уже отправлен» не ставится и оставшиеся части проходят как есть.

Специфика `multidisorder` — в следствии этого поведения. Раз режется весь реасм целиком, обратный порядок распространяется на весь запрос, а не на отдельные пакеты: последний сегмент всего ClientHello уйдёт первым, даже если исходно он приехал третьим пакетом.

**Отличие от [[multidisorder_legacy]]:** legacy-версия развилку не использует вовсе — она обрабатывает каждую часть replay отдельно, нормализуя позиции разреза под границы конкретного пакета, как это делал nfqws1. Из-за этого порядок сегментов при многопакетных запросах у двух функций разный. Для полной совместимости с nfqws1 нужен именно legacy-вариант.

---

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

О размерах TCP-сегментов думать **не нужно**. Отправкой занимается `rawsend_payload_segmented` из `zapret-lib.lua`, и она сама доводит куски до допустимого размера:

1. MSS берётся из `desync.tcp_mss` — движок отслеживает его для каждого TCP-соединения
2. Если кусок вместе с заголовками превышает MSS — он дополнительно режется по MSS
3. Каждый под-сегмент отправляется с корректным TCP sequence

**Пример:** если seqovl разрешился в большое значение (скажем, 5000), это не вызовет ошибку. `rawsend_payload_segmented` отправит несколько TCP-сегментов общим размером, равным seqovl_pattern + данные сегмента.

---

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

Тело `multidisorder` построено по тому же шаблону, что и все остальные функции дурения: восемь стадий от отсева чужого транспорта до вердикта. Разобраны они один раз в [[жизненный цикл desync-функции]] — здесь только отклонения:

| Стадия общего скелета | Что делает `multidisorder` |
|:----------------------|:---------------------------|
| 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` |

Отличие от [[multisplit]] сосредоточено ровно в одной стадии — седьмой. Всё остальное у двух функций совпадает буквально построчно, вплоть до общего хелпера `multidisorder_send`, который и разворачивает порядок отправки.

---

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

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

```lua
function multidisorder(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. Разрешение маркеров позиций
            pos = resolve_multi_pos(data, l7payload, pos_arg or "2")
            delete_pos_1(pos)  -- удалить Lua-позицию 1 (маркер 0)

            if #pos > 0 then
                -- 8. Разрешение seqovl (МАРКЕР, не число!)
                seqovl = nil
                if arg.seqovl then
                    seqovl = resolve_pos(data, l7payload, arg.seqovl)
                    if not seqovl then
                        DLOG("seqovl cancelled: marker not resolved")
                    end
                end

                -- 9. multidisorder_send: цикл ОБРАТНЫЙ
                for i = #pos, 0, -1 do         -- <--- от последнего к первому!
                    pos_start = pos[i] or 1
                    pos_end   = (i < #pos) and pos[i+1]-1 or #data
                    part      = data:sub(pos_start, pos_end)

                    -- 10. seqovl только для i==1 (предпоследний отправляемый)
                    ovl = 0
                    if i == 1 and seqovl and seqovl > 0 then
                        if seqovl >= pos[1] then
                            DLOG("seqovl cancelled: not less than first split pos")
                        else
                            ovl = seqovl - 1     -- ВАЖНО: минус 1!
                            pat = seqovl_pattern_blob or "\x00"
                            part = pattern(pat, 1, ovl) .. part
                        end
                    end

                    -- 11. Отправка с автосегментацией
                    rawsend_payload_segmented(part, pos_start - 1 - ovl)
                end

                -- 12. Пометить как отправленное
                replay_drop_set()
                return nodrop and VERDICT_PASS or VERDICT_DROP
            else
                DLOG("no valid split positions")
            end
        else
            -- 13. Не первый replay
            DLOG("not acting on further replay pieces")
        end
        -- 14. Дропнуть если ранее успешно отправлено
        if replay_drop() then
            return nodrop and VERDICT_PASS or VERDICT_DROP
        end
    end
end
```

---

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

### 1. Работает только с TCP

Если текущий пакет не TCP (UDP, ICMP и т.д.), `multidisorder` делает `instance_cutoff_shim` — отключает себя для этого потока навсегда (кроме ICMP-ответов, для которых cutoff не вызывается).

### 2. Разрез в самом начале данных отбрасывается

`delete_pos_1(pos)` убирает из списка Lua-позицию 1 — она соответствует маркеру `0`, то есть разрезу перед первым байтом, от которого первый сегмент вышел бы пустым. Если после этой чистки не осталось ни одной позиции, `multidisorder` не делает ничего.

Путаться тут легко из-за разной нумерации: в командной строке маркеры считаются от нуля, внутри Lua — от единицы. Поэтому под удаление попадает не `pos=1`, а `pos=0`. Самая частая реальная жертва — `pos=method` для HTTP: метод обычно лежит на смещении 0, маркер разрешается в удаляемую позицию, и разреза не происходит. Рабочий вариант — `pos=method+2`.

### 3. Все маркеры могут не разрешиться

Если вы указали `pos=midsld,sniext` для HTTP-payload, оба маркера (специфичные для TLS) не разрешатся. Multidisorder напишет в лог "no valid split positions" и ничего не сделает.

### 4. seqovl как маркер тоже может не разрешиться

В отличие от [[multisplit]] (где seqovl — число и всегда валидно), в multidisorder `seqovl=midsld-1` может не разрешиться (например, для unknown payload). В этом случае seqovl отменяется (логируется), но сегментация в обратном порядке всё равно происходит.

### 5. seqovl НЕ работает на Windows-серверах

Если целевой сервер работает под Windows, seqovl бесполезен: Windows сохраняет первые полученные данные и не перезаписывает буфер при получении перекрывающихся сегментов. Результат — сервер получит мусор (seqovl_pattern) вместо реальных данных. **Без seqovl** multidisorder работает на всех ОС нормально.

### 6. ovl = seqovl - 1: размер перекрытия на 1 меньше

Из-за строки `ovl = seqovl - 1` в `multidisorder_send`, если seqovl разрешился в 1, то ovl будет 0 — фактически seqovl не применяется. Минимальный эффективный seqovl — значение 2 (ovl = 1, 1 байт перекрытия).

### 7. seqovl >= pos[1] -> отмена seqovl

Если разрешённое значение seqovl больше или равно первой позиции разреза, seqovl отменяется. Это частая ошибка при использовании маркеров, которые разрешаются в большие значения. Логируется как "seqovl cancelled because seqovl N is not less than the first split pos M".

### 8. nodrop создаёт дублирование

С `nodrop` multidisorder отправляет нарезанные сегменты И пропускает оригинальный пакет. Сервер получит данные дважды. Используйте `nodrop` только для отладки или когда это осознанно нужно.

### 9. Fooling применяется ко ВСЕМ сегментам

В отличие от [[fakeddisorder]], где fooling идёт только на фейки, в `multidisorder` все сегменты получают fooling. Если задать `tcp_ack=-66000`, **все** сегменты получат инвалидный ack — сервер их отбросит, и ничего не заработает. Fooling в multidisorder имеет смысл только для специфических вещей (например, `tcp_ts_up`, `ip_id`, IPv6 extension headers).

### 10. Алгоритм отличается от nfqws1

Из комментария в коде: "algorithm is not 100% the same as in nfqws1. multi-segment queries can produce different segment ordering." nfqws2 работает с целым reasm, а nfqws1 — по отдельным частям replay. Для полной совместимости с nfqws1 используйте [[multidisorder_legacy]].

### 11. Порядок инстансов важен

Если перед `multidisorder` стоит `fake`, он отправит фейк первым. Если после multidisorder стоит ещё один инстанс — он увидит VERDICT_DROP и не получит оригинальный payload.

---

## Отличия от других функций сегментации

| Аспект | `multisplit` | `multidisorder` | `fakedsplit` | `fakeddisorder` |
|:-------|:-------------|:----------------|:-------------|:----------------|
| Количество позиций | Список (любое кол-во) | Список (любое кол-во) | **Одна** | **Одна** |
| Порядок отправки | Прямой (1->2->3) | **Обратный (3->2->1)** | Прямой | Обратный |
| Фейковые сегменты | **Нет** | **Нет** | Да (до 4 шт.) | Да (до 4 шт.) |
| seqovl тип | Только число | **Маркер** | Только число | **Маркер** |
| seqovl к какому сегменту | 1-й (первый отправляемый, `i==0`) | **2-й в оригинале (предпоследний отправляемый, `i==1`)** | 1-й реальный | 2-й реальный |
| seqovl механизм | Выход за TCP window | **Перезапись буфера** | Выход за TCP window | **Перезапись буфера** |
| Windows-серверы (seqovl) | Работает | **Не работает** | Работает | **Не работает** |
| Fooling к | Всем сегментам | Всем сегментам | Только к фейкам | Только к фейкам |
| ipfrag | Да | Да | **Нет** | **Нет** |
| blob аргумент | Да | Да | Нет | Нет |
| reasm | Целый reasm на replay_first | Целый reasm на replay_first | По частям | По частям |

---

## Миграция с nfqws1

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

| nfqws1 | nfqws2 |
|:-------|:-------|
| `--dpi-desync=multidisorder` | `--lua-desync=multidisorder` |
| `--dpi-desync-split-pos=midsld` | `:pos=midsld` |
| `--dpi-desync-split-pos=1,midsld` | `:pos=1,midsld` |
| `--dpi-desync-split-seqovl=5` | `:seqovl=5` |
| `--dpi-desync-split-seqovl-pattern=0x1603030000` | `:seqovl_pattern=0x1603030000` |
| `--dpi-desync-any-protocol` | Не нужно; или `payload=all` в инстансе |

### Простая миграция

```bash
# nfqws1:
nfqws --dpi-desync=multidisorder --dpi-desync-split-pos=midsld

# nfqws2:
nfqws2 --lua-desync=multidisorder:pos=midsld
```

### Миграция с fake + multidisorder

```bash
# nfqws1:
nfqws --dpi-desync=fake,multidisorder \
  --dpi-desync-split-pos=1,midsld \
  --dpi-desync-repeats=11 \
  --dpi-desync-fooling=md5sig

# nfqws2:
nfqws2 \
  --lua-desync=fake:blob=fake_default_tls:repeats=11:tcp_md5 \
  --lua-desync=multidisorder:pos=1,midsld
```

### Миграция с seqovl

```bash
# nfqws1:
nfqws --dpi-desync=multidisorder \
  --dpi-desync-split-pos=midsld \
  --dpi-desync-split-seqovl=5 \
  --dpi-desync-split-seqovl-pattern=0x1603030000

# nfqws2 (seqovl теперь может быть маркером!):
nfqws2 --lua-desync=multidisorder:pos=midsld:seqovl=5:seqovl_pattern=0x1603030000
# или с маркером (новая возможность nfqws2):
nfqws2 --lua-desync=multidisorder:pos=midsld:seqovl=midsld-1:seqovl_pattern=0x1603030000
```

### Полная миграция: fake + disorder + seqovl + fooling

```bash
# nfqws1:
nfqws --dpi-desync=fake,multidisorder \
  --dpi-desync-fooling=md5sig \
  --dpi-desync-split-pos=1,midsld \
  --dpi-desync-split-seqovl=5 \
  --dpi-desync-split-seqovl-pattern=0x1603030000 \
  --dpi-desync-fake-tls-mod=rnd,rndsni,dupsid

# nfqws2 (эквивалент):
nfqws2 \
  --payload=tls_client_hello \
    --lua-desync=fake:blob=fake_default_tls:tcp_md5:tls_mod=rnd,rndsni,dupsid \
  --payload=http_req \
    --lua-desync=fake:blob=fake_default_http:tcp_md5 \
  --payload=tls_client_hello,http_req \
    --lua-desync=multidisorder:pos=1,midsld:seqovl=5:seqovl_pattern=0x1603030000
```

**Замечание о совместимости:** алгоритм multidisorder в nfqws2 **не на 100% совпадает** с nfqws1 при многопакетных запросах (multi-segment queries). nfqws2 работает с целым reasm, а nfqws1 — по частям. Для полной совместимости используйте [[multidisorder_legacy]].

---

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

### 1. Минимальный (дефолт: pos=2, dir=out, payload=known)

```bash
--lua-desync=multidisorder
```

Разрезает payload после 2-го байта -> 2 сегмента (первые 2 байта и остаток), отправляемых в обратном порядке.

### 2. TLS: разрез посередине SNI

```bash
--payload=tls_client_hello --lua-desync=multidisorder:pos=midsld
```

SNI разрезан пополам, хвост отправлен первым — DPI не может собрать домен.

### 3. TLS: разрез + seqovl маркером (классическая комбинация)

```bash
--payload=tls_client_hello --lua-desync=multidisorder:pos=midsld:seqovl=midsld-1
```

Разрез по midsld, seqovl перекрывает почти всю первую часть фейковыми данными. Типичный паттерн для disorder.

### 4. TLS: seqovl + кастомный паттерн

```bash
--payload=tls_client_hello \
  --lua-desync=multidisorder:pos=midsld:seqovl=midsld-1:seqovl_pattern=0x1603030000
```

seqovl-область заполнена данными, похожими на начало TLS record — DPI может принять за легитимный TLS-трафик.

### 5. HTTP: разрез после метода (disorder)

```bash
--payload=http_req --lua-desync=multidisorder:pos=method+2
```

Для `GET /path...` разрежет после `GE` -> хвост уйдёт первым, голова — вторым.

### 6. HTTP: несколько разрезов вокруг hostname

```bash
--payload=http_req --lua-desync=multidisorder:pos=host,midsld,endhost
```

Разрезает: до hostname | первая половина | вторая половина | после hostname -> 4 сегмента в обратном порядке.

### 7. Два разреза с seqovl

```bash
--payload=tls_client_hello --lua-desync=multidisorder:pos=2,midsld:seqovl=sld
```

3 сегмента, seqovl применяется к сегменту i=1 (второй в оригинале). Маркер `sld` определяет размер перекрытия.

### 8. Произвольный blob вместо payload

```bash
--blob=mydata:@custom_payload.bin \
--lua-desync=multidisorder:blob=mydata:pos=10,100,-20
```

Режет и отправляет произвольные данные из файла вместо реального payload, в обратном порядке.

### 9. Защита от отсутствующего blob

```bash
--lua-desync=multidisorder:blob=maybe_missing:optional:pos=midsld
```

Если blob не существует — тихий пропуск, без ошибок и без VERDICT_DROP.

### 10. Отладка: не блокировать оригинал

```bash
--payload=http_req --lua-desync=multidisorder:pos=host,midsld:nodrop
```

Отправляет нарезанные сегменты в обратном порядке И пропускает оригинальный пакет (для экспериментов).

### 11. IP-фрагментация поверх TCP-сегментации (двойной disorder)

```bash
--payload=tls_client_hello \
  --lua-desync=multidisorder:pos=1,midsld:ipfrag:ipfrag_disorder:ipfrag_pos_tcp=32
```

Каждый TCP-сегмент дополнительно фрагментируется на IP-уровне в обратном порядке. Двойной disorder: TCP-сегменты в обратном порядке + IP-фрагменты каждого сегмента тоже в обратном порядке.

### 12. Комбинация: fake -> multidisorder (типичный боевой профиль)

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

Сначала отправляется фейковый TLS ClientHello (с fooling), затем реальный — нарезанный на 3 сегмента в обратном порядке с seqovl.

### 13. Боевой пример для YouTube

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

11 фейков подряд + реальный payload разрезан на 3 части в обратном порядке.

### 14. С TCP timestamp + IP ID

```bash
--payload=tls_client_hello --lua-desync=multidisorder:pos=1:tcp_ts_up:ip_id=seq:ip_id_conn
```

### 15. Повторы отправки

```bash
--payload=tls_client_hello --lua-desync=multidisorder:pos=midsld:repeats=2
```

Каждый сегмент отправляется 2 раза (бинарные повторы).

---

> **Источники:** `lua/zapret-antidpi.lua:546-629`, `lua/zapret-lib.lua`, `docs/manual.md:4067-4097`, `docs/readme.md` из репозитория zapret2.
