Some checks failed
Published content check / validate (push) Failing after 17s
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>
1259 lines
116 KiB
Markdown
1259 lines
116 KiB
Markdown
---
|
||
date: 2026-02-17
|
||
tags:
|
||
- zapret
|
||
- zapret2
|
||
- nfqws2
|
||
- lua
|
||
- lua-desync
|
||
- antidpi
|
||
- tcp
|
||
- fakedsplit
|
||
- fake
|
||
- seqovl
|
||
aliases:
|
||
- fakedsplit
|
||
description: "Техника fakedsplit в zapret2/nfqws2: разрез TCP payload с фейковыми сегментами-«ретрансмиссиями», маркеры pos, seqovl, fooling и примеры команд."
|
||
---
|
||
|
||
> [!mirror] Резервное зеркало
|
||
> Актуальная версия этой страницы — на основной вики: [wiki2.zapret.moe/Zapret2/desync/fakedsplit](https://wiki2.zapret.moe/Zapret2/desync/fakedsplit)
|
||
|
||
# `fakedsplit` — 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]]. Когда один и тот же кусок отправляется второй раз с тем же номером seq, в TCP это называется ретрансмиссией — повторной отправкой (её делают, когда считают, что первая копия потерялась).
|
||
|
||
Теперь о том, что такое фейк. Фейк — пакет-обманка: он выглядит как часть соединения, но вместо настоящих данных в нём мусор (по умолчанию нулевые байты). Если бы сервер принял такой пакет как настоящий, вместо запроса он получил бы мусор, и TCP-поток сломался бы ([[#4. Fooling ОБЯЗАТЕЛЕН для фейков|нюанс 4]]). Поэтому фейк «портят»: меняют в его заголовке поле так, чтобы TCP-стек сервера молча выбросил пакет. Такая порча называется fooling («одурачивание»; разбор — [[Zapret2/ts-and-fooling#Что такое fooling|Что такое fooling]]). В командах этой статьи портится поле ACK (номер подтверждения: до какого байта собеседника отправитель уже всё получил): `tcp_ack=-66000` сдвигает его на 66000, и сервер такой пакет не принимает. Вторая опция, `tcp_ts_up`, переставляет TCP-опцию timestamp в начало заголовка: на Linux-серверах пакет с неверным ACK надёжно отбрасывается только при таком порядке опций ([[#5. tcp_ts_up рекомендуется вместе с tcp_ack/tcp_seq|нюанс 5]]). Есть и другие способы испортить фейк (TTL, контрольная сумма, MD5-опция), их каталог — в разделе [[Zapret2/ts-and-fooling#Как заставить fake умереть: каталог способов|Как заставить fake умереть]].
|
||
|
||
`fakedsplit` перехватывает исходящий пакет с ClientHello или HTTP-запросом и делает с ним три шага. Сначала режет данные ровно в одном месте (аргумент `pos`, по умолчанию после второго байта) на две настоящие части. Потом отправляет шесть пакетов подряд: фейк первой части, настоящую первую часть, ещё один фейк первой части, фейк второй части, настоящую вторую часть и ещё один фейк второй части. Каждый фейк — того же размера, что и его часть, и с тем же seq, то есть претендует на то же место в потоке. Испорчены только фейки: настоящие части уходят с правильными заголовками (из всей порчи к ним добавляется лишь безвредная `tcp_ts_up`; исключение — `seqovl` первой части, о нём ниже). В конце перехваченный оригинал выбрасывается, чтобы те же данные не ушли второй раз. Проще говоря: вокруг каждой настоящей части стоят два фейка того же размера. Порядок и опции каждого из шести пакетов — в разделе [[#Последовательность отправки (6 пакетов)|Последовательность отправки (6 пакетов)]].
|
||
|
||
Сервер выбрасывает все четыре фейка из-за испорченного ACK, принимает две настоящие части, раскладывает их по seq и получает исходный запрос целиком, поэтому отвечает как обычно. ТСПУ видит другое: на каждое место в потоке приходится по три сегмента с одним и тем же seq, и снаружи это похоже на серию ретрансмиссий. Какой из трёх сегментов настоящий, DPI может не понять. К тому же в фейках вместо имени сайта по умолчанию нули, а сама настоящая часть содержит имя не целиком, потому что разрез проходит внутри него (при `pos=midsld` — посередине домена второго уровня, главной части имени сайта: у `www.example.com` это `example`). Это расчёт, а не гарантия: подробнее о том, что видит DPI и что видит сервер, — в разделах [[#Что видит DPI|Что видит DPI]] и [[#Что видит сервер|Что видит сервер]].
|
||
|
||
Команда из быстрого старта `fakedsplit:pos=midsld:tcp_ack=-66000:tcp_ts_up` режет ClientHello посередине домена второго уровня и окружает каждую настоящую часть двумя фейками того же размера и с тем же seq: FAKE1, REAL1, FAKE1, FAKE2, REAL2, FAKE2. Фейки заполнены мусором (на схеме — `X`). ТСПУ получает по три сегмента на каждую позицию и может не понять, какой из них настоящий; сервер отбрасывает фейки по испорченному номеру подтверждения (ACK сдвинут на 66000). Как читать схему: строки — пакеты в порядке отправки, подписанные в тех же обозначениях, что и таблицы в этой статье; по горизонтали — место данных в TCP-потоке (номер последовательности, seq); в колонке справа — что сделал с пакетом сервер; внизу — буфер сервера, в который принятые куски встают по своим seq.
|
||
|
||
![[desync-anim-fakedsplit.svg|Анимация fakedsplit: каждая часть ClientHello окружена фейками с тем же seq, сервер отбрасывает фейки по неверному ACK]]
|
||
|
||
Минимальная команда включает `fakedsplit` со значениями по умолчанию: один разрез после второго байта (`pos=2`), обработка только распознанных протоколов (`payload=known`) и только исходящих пакетов (`dir=out`), а `tcp_ack=-66000` портит фейки. Строку `--lua-desync=…` пишут в [[Zapret2/profile#Анатомия профиля|профиль]] — набор правил Zapret 2 для определённого трафика:
|
||
|
||
```bash
|
||
--lua-desync=fakedsplit:tcp_ack=-66000
|
||
```
|
||
|
||
Без хотя бы одного способа испортить фейки сервер примет их за настоящие данные и поток сломается, а `tcp_ts_up` рекомендуется ставить вместе с `tcp_ack` всегда. Для HTTPS берут вариант с ClientHello, как в команде со схемы: `--payload=tls_client_hello --lua-desync=fakedsplit:pos=midsld:tcp_ack=-66000:tcp_ts_up`; здесь `--payload=tls_client_hello` значит «срабатывать только на TLS ClientHello». К разрезу можно добавить `seqovl` — несколько лишних байт слева от первой настоящей части, которые сервер выбросит, а DPI может прочитать вместе с остальным сегментом ([[#seqovl — скрытый фейк внутри сегмента|подробно]]). Фейки можно отключать по одному флагами `nofake1`…`nofake4` ([[#nofake1..nofake4 — отключение отдельных фейков|подробно]]), а начинку фейков задаёт аргумент `pattern` ([[#pattern — заполнение фейков|подробно]]). Остальные готовые команды собраны в разделах [[#Быстрый старт|Быстрый старт]] и [[#Практические примеры|Практические примеры]].
|
||
|
||
Замысел `fakedsplit` — обойти два известных слабых места отдельных приёмов: отдельный фейк-пакет DPI может отбросить по эвристикам (слишком другой TTL, плохой seq), а простой разрез он может просто собрать обратно. `fakedsplit` соединяет оба приёма, и фейки в нём устроены как повторы настоящих сегментов ([[#Зачем нужен fakedsplit|Зачем нужен fakedsplit]]). Сработает ли это против конкретного DPI, заранее не сказать. На случай, когда DPI всё же научился отбрасывать фейки, в статье предусмотрен `seqovl`: его лишние байты внутри настоящего сегмента DPI может не распознать. Работает техника только с TCP, а надёжность порчи фейков зависит от места запуска: один и тот же вид fooling бывает отличным в одном месте запуска (например, на роутере) и бесполезным в другом (за роутером) ([[Zapret2/ts-and-fooling#Как заставить fake умереть: каталог способов|каталог способов]]). Цена — до шести пакетов вместо одного, а `nofake2` и `nofake4` сокращают их до четырёх ([[#8. Без "задних" фейков (оптимизация трафика)|пример 8]]). Способ порчи фейков выбирают по месту запуска и подтверждают тестами, а не на слух ([[Zapret2/ts-and-fooling#Как заставить fake умереть: каталог способов|каталог способов]]); результат проверяют по [[Zapret2/verify-strategy#Короткий чек-лист честной проверки|чек-листу честной проверки]].
|
||
|
||
У `fakedsplit` есть близкие родственники. [[Zapret2/desync/multisplit#Зачем нужен multisplit|multisplit]] режет так же, но фейков не подмешивает и позиций может быть сколько угодно. [[Zapret2/desync/fake#Зачем нужен fake|fake]] отправляет отдельный фейк-пакет перед настоящим и не трогает оригинал. [[Zapret2/desync/fakeddisorder#Зачем нужен fakeddisorder|fakeddisorder]] делает такой же один разрез с фейками вокруг частей, но первой отправляет вторую часть, то есть конец запроса раньше начала; сам приём обратного порядка разобран в [[Zapret2/desync/multidisorder#Обратный порядок отправки — суть disorder|multidisorder]], где фейков нет. [[Zapret2/desync/hostfakesplit#Зачем нужен hostfakesplit|hostfakesplit]] режет запрос по границам имени хоста и подмешивает фейковое имя. Все отличия сведены в таблицу раздела [[#Отличия от других функций сегментации|Отличия от других функций сегментации]]; функцию `fake` можно поставить в одну цепочку с `fakedsplit` ([[#11. Цепочка: fake + fakedsplit|пример 11]]).
|
||
|
||
---
|
||
|
||
## Оглавление
|
||
|
||
- [Коротко и по-простому](#коротко-и-по-простому)
|
||
- [Справка: где функция в коде и родственники](#справка-где-функция-в-коде-и-родственники)
|
||
- [Зачем нужен fakedsplit](#зачем-нужен-fakedsplit)
|
||
- [Быстрый старт](#быстрый-старт)
|
||
- [Откуда берутся данные для нарезки](#откуда-берутся-данные-для-нарезки)
|
||
- [Маркер позиции (pos)](#маркер-позиции-pos)
|
||
- [Типы маркеров](#типы-маркеров)
|
||
- [Относительные маркеры](#относительные-маркеры)
|
||
- [Арифметика маркеров](#арифметика-маркеров)
|
||
- [Как маркер разрешается в коде](#как-маркер-разрешается-в-коде)
|
||
- [Важные нюансы pos](#важные-нюансы-pos)
|
||
- [Последовательность отправки (6 пакетов)](#последовательность-отправки-6-пакетов)
|
||
- [ASCII-диаграмма](#ascii-диаграмма)
|
||
- [Что видит DPI](#что-видит-dpi)
|
||
- [Что видит сервер](#что-видит-сервер)
|
||
- [Два набора опций: opts_orig vs opts_fake](#два-набора-опций-opts_orig-vs-opts_fake)
|
||
- [seqovl — скрытый фейк внутри сегмента](#seqovl--скрытый-фейк-внутри-сегмента)
|
||
- [Принцип работы seqovl](#принцип-работы-seqovl)
|
||
- [seqovl_pattern](#seqovl_pattern)
|
||
- [pattern — заполнение фейков](#pattern--заполнение-фейков)
|
||
- [nofake1..nofake4 — отключение отдельных фейков](#nofake1nofake4--отключение-отдельных-фейков)
|
||
- [Полный список аргументов](#полный-список-аргументов)
|
||
- [A) Собственные аргументы fakedsplit](#a-собственные-аргументы-fakedsplit)
|
||
- [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)
|
||
- [Порядок отправки — подробно с seqovl](#порядок-отправки--подробно-с-seqovl)
|
||
- [Поведение при replay / reasm](#поведение-при-replay--reasm)
|
||
- [Автосегментация по MSS](#автосегментация-по-mss)
|
||
- [Место в общем скелете](#место-в-общем-скелете)
|
||
- [Псевдокод алгоритма](#псевдокод-алгоритма)
|
||
- [Нюансы и подводные камни](#нюансы-и-подводные-камни)
|
||
- [Отличия от других функций сегментации](#отличия-от-других-функций-сегментации)
|
||
- [Миграция с nfqws1](#миграция-с-nfqws1)
|
||
- [Практические примеры](#практические-примеры)
|
||
- [📚 См. также](#-см-также)
|
||
|
||
---
|
||
|
||
## Справка: где функция в коде и родственники
|
||
|
||
Паспорт функции для тех, кто сверяется с исходниками zapret2: в каком файле и на какой строке лежит код, какой ключ первой версии zapret она заменяет и как объявлена.
|
||
|
||
**Файл:** `lua/zapret-antidpi.lua:826`
|
||
**nfqws1 эквивалент:** `--dpi-desync=fakedsplit`
|
||
**Сигнатура:** `function fakedsplit(ctx, desync)`
|
||
|
||
`fakedsplit` разрезает TCP payload на **две** части по одной позиции и отправляет их вперемешку с **фейковыми** сегментами того же размера. Фейки содержат мусор (pattern), но имеют те же TCP sequence и размеры, что и оригиналы. Для DPI это выглядит как серия ретрансмиссий — он не может понять, какой сегмент настоящий, а какой — подделка. Для сервера фейки отбрасываются благодаря fooling (badseq, md5sig, badsum и т.д.).
|
||
|
||
> [!note] Проще говоря
|
||
> Payload — полезные данные пакета без сетевых заголовков: сам HTTP-запрос или сам ClientHello. Pattern — заполнитель, которым набивают фейки; TCP sequence — тот самый порядковый номер seq. Fooling — намеренная порча заголовков фейка, чтобы сервер его отбросил ([[Zapret2/ts-and-fooling#Что такое fooling|Что такое fooling]]). Seqovl — приём с лишними байтами слева от первой настоящей части ([[#seqovl — скрытый фейк внутри сегмента|seqovl — скрытый фейк внутри сегмента]]).
|
||
|
||
Родственные функции: [[multisplit]] (простая сегментация), [[multidisorder]] (обратный порядок), [[fakeddisorder]] (фейки + обратный порядок), [[hostfakesplit]] (по hostname), [[tcpseg]] (диапазон), [[oob]] (urgent byte).
|
||
|
||
> [!note] Проще говоря
|
||
> Фейки есть не у всех родственников: у [[Zapret2/desync/multisplit#Зачем нужен multisplit|multisplit]] их нет совсем, у [[Zapret2/desync/fake#Зачем нужен fake|fake]] это единственный пакет, а `fakedsplit` и [[Zapret2/desync/fakeddisorder#Зачем нужен fakeddisorder|fakeddisorder]] замешивают их между частями. Полная таблица различий — в разделе [[#Отличия от других функций сегментации|Отличия от других функций сегментации]].
|
||
|
||
Общий для всех техник дурения порядок работы — восемь стадий от отсева чужого транспорта до вердикта — разобран в [[жизненный цикл desync-функции]]; здесь описано только то, чем `fakedsplit` от этого скелета отличается.
|
||
|
||
---
|
||
|
||
## Зачем нужен fakedsplit
|
||
|
||
Обычная сегментация ([[multisplit]]) разрезает payload, но DPI может просто реассемблировать поток. Отдельная отправка фейка ([[fake]]) работает, но DPI может отбросить фейк по эвристикам (слишком другой TTL, плохой sequence).
|
||
|
||
`fakedsplit` комбинирует оба подхода: он **одновременно** разрезает и замешивает фейки. При этом фейки:
|
||
|
||
1. **Совпадают по размеру** с реальными частями
|
||
2. **Имеют те же TCP sequence numbers** — выглядят как ретрансмиссии
|
||
3. **Окружают** каждую реальную часть с двух сторон (до и после)
|
||
|
||
Для DPI поток выглядит так: 6 TCP-сегментов, из которых по 3 сегмента (две тройки) — "ретрансмиссии" одного и того же. Какой из трёх сегментов каждой тройки настоящий? DPI не знает. Сервер знает — потому что фейки имеют невалидные заголовки (fooling), и TCP-стек их молча отбросит.
|
||
|
||
> [!note] Проще говоря
|
||
> Реассемблировать поток — склеить сегменты обратно в исходные данные; так может поступать DPI, который следит за всем соединением, а не за отдельными пакетами. Ретрансмиссия — повторная отправка того же куска с тем же номером seq: TCP так делает, когда считает, что первая отправка потерялась. `fakedsplit` рисует для DPI такую картину нарочно: на каждое из двух мест в потоке приходится по три сегмента с одинаковым seq (фейк, настоящая часть, фейк). Сервер отличает настоящий, потому что фейки он выбрасывает из-за испорченных заголовков; DPI этого различия может не увидеть. Отдельный фейк-пакет разобран в [[Zapret2/desync/fake#Зачем нужен fake|fake]], разрез без фейков — в [[Zapret2/desync/multisplit#Зачем нужен multisplit|multisplit]], а их сочетание с обратным порядком — в [[Zapret2/desync/fakeddisorder#Зачем нужен fakeddisorder|fakeddisorder]].
|
||
|
||
---
|
||
|
||
## Быстрый старт
|
||
|
||
Ниже четыре готовые строки для [[Zapret2/profile#Анатомия профиля|профиля]] Zapret 2, от самой короткой к более сложным (полный набор — в разделе [[#Практические примеры|Практические примеры]]). Флаг `--payload=…` работает как фильтр для всех вызовов `--lua-desync`, которые идут после него (до следующего `--payload` или до конца профиля): они срабатывают только на данных указанного [[Zapret2/payload#Что такое тип payload (и чем он отличается от протокола потока)|типа payload]]. Поэтому `--payload` пишут перед `--lua-desync`, а не после (подробно — в [[последовательность аргументов]]).
|
||
|
||
Минимально (разрез по позиции 2, payload=known, dir=out):
|
||
|
||
```bash
|
||
--lua-desync=fakedsplit:tcp_ack=-66000
|
||
```
|
||
|
||
Здесь `payload=known` означает «только распознанные протоколы», а `dir=out` — «только исходящие пакеты»; оба аргумента разобраны в разделах [[#B) Standard direction|B) Standard direction]] и [[#C) Standard payload|C) Standard payload]]. `tcp_ack=-66000` портит ACK у фейков, чтобы сервер их выбросил. В этой строке `tcp_ts_up` нет, хотя статья рекомендует ставить его вместе с `tcp_ack` ([[#5. tcp_ts_up рекомендуется вместе с tcp_ack/tcp_seq|нюанс 5]]).
|
||
|
||
Типовой TLS-разрез с badseq:
|
||
|
||
```bash
|
||
--payload=tls_client_hello --lua-desync=fakedsplit:pos=midsld:tcp_ack=-66000:tcp_ts_up
|
||
```
|
||
|
||
Функция срабатывает только на TLS ClientHello и режет его посередине домена второго уровня (SLD; у `www.example.com` это `example`): каждая из двух частей окружена фейками, всего шесть пакетов. `tcp_ts_up` нужен, чтобы сервер надёжно отбрасывал фейки с испорченным ACK.
|
||
|
||
HTTP с разрезом по методу:
|
||
|
||
```bash
|
||
--payload=http_req --lua-desync=fakedsplit:pos=method+2:tcp_ack=-66000:tcp_ts_up
|
||
```
|
||
|
||
Здесь `--payload=http_req` значит «только HTTP-запросы», а `method+2` — две позиции после начала метода: `GET` разрежется после `GE`.
|
||
|
||
С seqovl для дополнительной маскировки:
|
||
|
||
```bash
|
||
--payload=tls_client_hello --lua-desync=fakedsplit:pos=midsld:tcp_ack=-66000:tcp_ts_up:seqovl=5:seqovl_pattern=0x1603030000
|
||
```
|
||
|
||
Здесь к первой настоящей части слева приклеиваются 5 байт `0x1603030000`, похожих на начало TLS record — заголовка записи TLS. Сервер отбросит эти байты, DPI — может не отбросить; как это работает, разобрано в разделе [[#seqovl — скрытый фейк внутри сегмента|seqovl — скрытый фейк внутри сегмента]].
|
||
|
||
---
|
||
|
||
## Откуда берутся данные для нарезки
|
||
|
||
Внутри `fakedsplit` данные (`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] Проще говоря
|
||
> Функция сначала спрашивает: «мне явно подсунули blob? — режу его». Если нет: «есть payload, собранный из нескольких пакетов? — режу его». Если и его нет: «режу тело текущего пакета». Blob — заранее заготовленные данные, которые можно подставить вместо настоящих (что это такое и как их задавать — в заметке [[blob]]). Reasm (`reasm_data`) — тот же запрос, собранный движком из нескольких TCP-пакетов, если в один он не поместился ([[#Поведение при replay / reasm|Поведение при replay / reasm]]). Payload — полезные данные пакета без сетевых заголовков. Та же цепочка общая для большинства функций дурения и описана как [[Zapret2/жизненный цикл desync-функции#Стадия 4. Выбор данных: blob → reasm → payload|стадия 4 жизненного цикла]]. Распознанный тип данных (`http_req`, `tls_client_hello`) объяснён в заметке [[Zapret2/payload#Что такое тип payload (и чем он отличается от протокола потока)|о типах payload]]: от него зависит, сработают ли относительные маркеры.
|
||
|
||
---
|
||
|
||
## Маркер позиции (pos)
|
||
|
||
![[desync-anim-hub-markers.svg|Анимация: маркеры позиций pos на HTTP-запросе и на TLS ClientHello, разрез по pos=host,midsld,endhost]]
|
||
|
||
`pos` — главный аргумент `fakedsplit`. Определяет **где** внутри payload будет произведён разрез. В отличие от [[multisplit]], `pos` — это **один маркер**, а не список. Payload всегда делится ровно на **две части**.
|
||
|
||
Маркер — способ указать место разреза: либо числом байт, либо названием места в запросе (например, «середина домена»). В командной строке числа считаются с нуля: `pos=N` значит «первые N байт уходят отдельным сегментом». Внутри Lua те же позиции хранятся как индексы с единицы, отсюда и два нюанса ниже. Список маркеров через запятую и полную таблицу маркеров разбирает статья о multisplit ([[Zapret2/desync/multisplit#Маркеры позиций (pos)|Маркеры позиций (pos)]]); здесь то же самое сказано применительно к одному маркеру.
|
||
|
||
### Типы маркеров
|
||
|
||
| Тип | Описание | Пример |
|
||
|:----|:---------|:-------|
|
||
| **Абсолютный положительный** | Смещение от начала payload, считая с 0. `pos=N` → первые N байт становятся отдельным сегментом | `2`, `5`, `100` |
|
||
| **Абсолютный отрицательный** | Смещение от конца payload. `-1` = последний байт | `-1`, `-10`, `-50` |
|
||
| **Относительный** | Логическая позиция внутри распознанного payload. Привязана к структуре протокола | `midsld`, `host`, `sniext` |
|
||
|
||
### Относительные маркеры
|
||
|
||
В правой колонке указано, в каких типах payload маркер имеет смысл: `http_req` — HTTP-запрос, `tls_client_hello` — TLS ClientHello (как движок определяет тип — в заметке [[Zapret2/payload#Что такое тип payload (и чем он отличается от протокола потока)|о типах payload]]). SLD (second-level domain) — домен второго уровня: в `www.example.com` это `example`. SNI extension — расширение ClientHello, в котором браузер передаёт имя сайта.
|
||
|
||
| Маркер | Описание | Для каких 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 (абсолютный, не относительный)
|
||
```
|
||
|
||
### Как маркер разрешается в коде
|
||
|
||
Разрешить маркер — значит превратить его название в конкретный номер байта в выбранных данных. В отличие от [[multisplit]], который вызывает `resolve_multi_pos` (парсит список через запятую; как это устроено, описано в разделе [[Zapret2/desync/multisplit#Как маркеры разрешаются в коде|Как маркеры разрешаются в коде]]), `fakedsplit` вызывает **`resolve_pos`** напрямую — для одного маркера:
|
||
|
||
```lua
|
||
local pos = resolve_pos(data, desync.l7payload, spos)
|
||
```
|
||
|
||
Функция `resolve_pos`:
|
||
|
||
1. Разбирает маркер (имя + арифметика)
|
||
2. Если маркер не может быть разрешён (например, `midsld` для `unknown` payload) — возвращает `nil`
|
||
3. При успехе возвращает абсолютную позицию (1-based, как в Lua)
|
||
|
||
Далее проверяется:
|
||
|
||
```lua
|
||
if pos == 1 then
|
||
DLOG("fakedsplit: split pos resolved to 0. cannot split.")
|
||
-- ничего не делает
|
||
end
|
||
```
|
||
|
||
> [!note] Проще говоря
|
||
> Функция превращает маркер в номер байта. Если превратить не получилось (например, `midsld` для `unknown` payload — данных, тип которых движок не распознал) или получился разрез перед самым первым байтом, разрезать нечего, и `fakedsplit` ничего не отправляет. Что в этом случае происходит с оригинальным пакетом, сказано в [[#11. Неразрешённый маркер != ошибка|нюансе 11]].
|
||
|
||
### Важные нюансы pos
|
||
|
||
- **Только ОДИН маркер.** `pos=midsld,endhost` НЕ работает. Запятая не парсится — это не список. Если нужно несколько точек разреза с фейками — используйте цепочку нескольких `fakedsplit`
|
||
- **Разрез в самом начале данных отбрасывается.** Если маркер разрешается в Lua-позицию 1 — а это маркер `0`, поскольку в командной строке смещения считаются с нуля, — функция логирует "split pos resolved to 0. cannot split." и ничего не делает. Под запрет попадает `pos=0`, а не `pos=1`; частая жертва правила — `pos=method` для HTTP, где метод лежит на смещении 0
|
||
- **Неразрешимый маркер => ничего не делается.** Если `resolve_pos` вернул `nil` (маркер не разрешился), fakedsplit логирует "cannot resolve pos" и пропускает
|
||
- **По умолчанию `pos=2`.** Если `pos` не задан, payload делится на 2 части: первые 2 байта отдельным сегментом, весь остаток — вторым
|
||
|
||
> [!note] Проще говоря
|
||
> В командной строке пишите, сколько байт должно уйти в первом куске. `pos=0` не сработает, и `pos=method` для HTTP тоже: метод лежит на смещении 0, поэтому нужен сдвиг, например `pos=method+2`. Тот же разрез по числу байт удобнее всего проверять на примерах в разделе [[#Порядок отправки — подробно с seqovl|Порядок отправки — подробно с seqovl]].
|
||
|
||
---
|
||
|
||
## Последовательность отправки (6 пакетов)
|
||
|
||
![[desync-anim-hub-fakedsplit6.svg|Анимация: шесть пакетов fakedsplit — две тройки, в каждой настоящая часть зажата между фейками]]
|
||
|
||
`fakedsplit` отправляет **до 6 пакетов** (при включённых всех фейках). В таблице пакеты перечислены в порядке отправки. Столбец «Тип» показывает, что это: фейк (fake) или настоящая часть (orig, «оригинальная»). Столбец «Отключение» — флаг, которым пакет можно не отправлять ([[#nofake1..nofake4 — отключение отдельных фейков|nofake1..nofake4]]); у настоящих частей отключения нет. Столбец «Опции» — какой из двух наборов настроек отправки применяется к пакету ([[#Два набора опций: opts_orig vs opts_fake|Два набора опций]]):
|
||
|
||
| # | Что | Тип | Отключение | Опции |
|
||
|:--|:----|:----|:-----------|:------|
|
||
| 1 | Фейк 1-й части | fake | `nofake1` | `opts_fake` (полный fooling + reconstruct + repeats) |
|
||
| 2 | Реальная 1-я часть (+seqovl) | orig | -- | `opts_orig` (только tcp_ts_up, без repeats) |
|
||
| 3 | Фейк 1-й части (повтор) | fake | `nofake2` | `opts_fake` |
|
||
| 4 | Фейк 2-й части | fake | `nofake3` | `opts_fake` |
|
||
| 5 | Реальная 2-я часть | orig | -- | `opts_orig` |
|
||
| 6 | Фейк 2-й части (повтор) | fake | `nofake4` | `opts_fake` |
|
||
|
||
**Ключевой момент:** каждая реальная часть **окружена** фейками того же размера и с тем же TCP sequence. DPI видит "тройки ретрансмиссий" и не может определить, какая из трёх — настоящая.
|
||
|
||
> [!note] Проще говоря
|
||
> Тройка — это три сегмента с одним seq: фейк, настоящая часть, ещё один фейк. Для первой части это пакеты №1–№3, для второй — №4–№6. Настоящая часть всегда стоит в середине тройки, а фейк идёт и до неё, и после. Что такое ретрансмиссия и почему тройка выглядит для DPI как повторы, — в разделе [[#Зачем нужен fakedsplit|Зачем нужен fakedsplit]].
|
||
|
||
### ASCII-диаграмма
|
||
|
||
| # | Пакет | seq | len | Опции |
|
||
|:--|:--|:--|:--|:--|
|
||
| 1 | FAKE1 | `0` | `pos-1` | `opts_fake` |
|
||
| 2 | REAL1 | `-seqovl` | `pos-1+sovl` | `opts_orig` |
|
||
| 3 | FAKE1 | `0` | `pos-1` | `opts_fake` |
|
||
| 4 | FAKE2 | `pos-1` | `#data-pos+1` | `opts_fake` |
|
||
| 5 | REAL2 | `pos-1` | `#data-pos+1` | `opts_orig` |
|
||
| 6 | FAKE2 | `pos-1` | `#data-pos+1` | `opts_fake` |
|
||
|
||
FAKE — мусор (pattern), REAL — настоящие данные.
|
||
|
||
Номера seq здесь — смещения от начала данных: у первой части это `0`, у второй записано `pos-1` (в нём `pos` — позиция в нумерации Lua, с единицы). Колонки `len` показывают длину данных пакета (`sovl` — то же, что `seqovl`), а `opts_orig` и `opts_fake` — какой набор опций применён к пакету.
|
||
|
||
### Что видит DPI
|
||
|
||
DPI видит три сегмента с одним seq в начале запроса и три с одним seq в начале второй части. Это похоже на ретрансмиссии, и какой сегмент в каждой тройке настоящий, неясно.
|
||
|
||
Начало второй части в таблице выше и в псевдокоде равно `pos-1` (в примерах ниже при `pos=4` это `seq=3`); `PPP` — байты `seqovl_pattern`, которые есть только при заданном `seqovl`, `sovl` — число этих байт. Это картина «может не понять», а не гарантия; если DPI научился отбрасывать фейковые сегменты, на помощь приходит `seqovl` ([[#seqovl — скрытый фейк внутри сегмента|seqovl — скрытый фейк внутри сегмента]]).
|
||
|
||
### Что видит сервер
|
||
|
||
| seq | Данные | Что делает сервер |
|
||
|:--|:--|:--|
|
||
| `0` | мусор | отбрасывает: fooling (badseq, md5, badsum) |
|
||
| `-sovl` | PPP + REAL1 | часть seqovl левее окна отбрасывает, REAL1 принимает |
|
||
| `0` | мусор | отбрасывает: fooling |
|
||
| `pos` | мусор | отбрасывает: fooling |
|
||
| `pos` | REAL2 | принимает: нормальный пакет |
|
||
| `pos` | мусор | отбрасывает: fooling |
|
||
|
||
Сервер собрал `[REAL1][REAL2]` — полный исходный payload.
|
||
|
||
Слова «за window» здесь значат «левее границы окна приёма»: окно — диапазон номеров seq, которые сервер готов принять, а всё левее считается повтором и выбрасывается (подробно — [[Zapret2/desync/multisplit#Принцип работы seqovl|Принцип работы seqovl]]). Фейки сервер выбрасывает целиком из-за fooling: например, при `tcp_ack=-66000` ACK в них заведомо неверный. Проще говоря: сервер выбрасывает пакеты с испорченными заголовками, а принятые куски склеивает по seq.
|
||
|
||
---
|
||
|
||
## Два набора опций: opts_orig vs opts_fake
|
||
|
||
Это ключевое отличие `fakedsplit` от [[multisplit]]. Внутри функции создаются **два набора** опций.
|
||
|
||
Опции здесь — настройки того, как строится и отправляется пакет: какие поля заголовков портить (fooling), портить ли контрольную сумму (`badsum`; reconstruct — сборка готового «сырого» пакета со всеми заголовками), сколько раз повторять отправку (`repeats`), какие IP ID ставить (`ipid`), делить ли пакет на IP-фрагменты (`ipfrag`). Rawsend — отправка готовых пакетов в сеть самой функцией. Общий разбор того, кто применяет какие наборы, — в разделе [[Zapret2/жизненный цикл desync-функции#Наборы опций: кто их применяет и к чему|Наборы опций: кто их применяет и к чему]], а суть fooling — в [[Zapret2/ts-and-fooling#Что такое fooling|Что такое fooling]].
|
||
|
||
```lua
|
||
-- Для оригинальных частей:
|
||
local opts_orig = {
|
||
rawsend = rawsend_opts_base(desync), -- БЕЗ repeats!
|
||
reconstruct = {}, -- пустой (без badsum)
|
||
ipfrag = {}, -- пустой (без IP-фрагментации)
|
||
ipid = desync.arg, -- ip_id применяется
|
||
fooling = {tcp_ts_up = desync.arg.tcp_ts_up} -- ТОЛЬКО tcp_ts_up
|
||
}
|
||
|
||
-- Для фейковых частей:
|
||
local opts_fake = {
|
||
rawsend = rawsend_opts(desync), -- С repeats!
|
||
reconstruct = reconstruct_opts(desync), -- badsum если задан
|
||
ipfrag = {}, -- пустой (без IP-фрагментации)
|
||
ipid = desync.arg, -- ip_id применяется
|
||
fooling = desync.arg -- ВСЁ fooling целиком
|
||
}
|
||
```
|
||
|
||
**Сводная таблица:**
|
||
|
||
| Что | opts_orig (оригиналы) | opts_fake (фейки) |
|
||
|:----|:----------------------|:-------------------|
|
||
| **fooling** | Только `tcp_ts_up` | Всё (tcp_ack, tcp_seq, tcp_md5, ip_ttl, badseq, ...) |
|
||
| **reconstruct** | Нет (пустой `{}`) | Да (`badsum` если задан) |
|
||
| **rawsend.repeats** | Нет (`rawsend_opts_base`) | Да (`rawsend_opts`) |
|
||
| **rawsend.ifout** | Да | Да |
|
||
| **rawsend.fwmark** | Да | Да |
|
||
| **ipid** | Да | Да |
|
||
| **ipfrag** | Нет (пустой `{}`) | Нет (пустой `{}`) |
|
||
|
||
**Почему так:**
|
||
- Оригиналы **должны** быть приняты сервером => никакого fooling (кроме безвредного tcp_ts_up), никакого badsum
|
||
- Фейки **должны** быть отброшены сервером => полный fooling + badsum
|
||
- `repeats` — множественная отправка имеет смысл только для фейков (больше шума для DPI)
|
||
- `ipfrag` **не используется** ни для чего — fakedsplit работает исключительно на уровне TCP-сегментов
|
||
- `ipid` и базовый `rawsend` (ifout, fwmark) нужны обоим — это уровень IP/маршрутизации
|
||
|
||
> [!note] Проще говоря
|
||
> Настоящие части уходят почти чистыми: из всей порчи заголовков к ним добавляется только безвредная перестановка опции timestamp (`tcp_ts_up`). На фейки навешивается всё сразу: испорченные заголовки, при желании испорченная контрольная сумма и повторы. Отсюда правило из нюансов: `repeats` действует только на фейки ([[#6. repeats применяются ТОЛЬКО к фейкам|нюанс 6]]), а `ipfrag` не используется вовсе ([[#7. ipfrag НЕ используется|нюанс 7]]).
|
||
|
||
---
|
||
|
||
## seqovl — скрытый фейк внутри сегмента
|
||
|
||
**seqovl** (Sequence Overlap) — техника скрытого замешивания фейковых данных в реальный TCP-сегмент через манипуляцию TCP sequence number. В `fakedsplit` seqovl применяется **только к первому реальному сегменту** (пакет #2).
|
||
|
||
Подробная механика (как получатель решает, какие байты принять, и раскладка по байтам) разобрана в статье о multisplit: [[Zapret2/desync/multisplit#seqovl — скрытый фейк внутри сегмента|seqovl — скрытый фейк внутри сегмента]], а сравнение с обычным fooling — в разделе [[Zapret2/desync/multisplit#Зачем seqovl лучше обычного fooling|Зачем seqovl лучше обычного fooling]]. Здесь то же самое сказано применительно к `fakedsplit`, где seqovl добавляется поверх уже имеющихся фейков. В [[Zapret2/desync/multidisorder#seqovl — перезапись буфера сокета через перекрытие|multidisorder]] приём с тем же названием устроен иначе, поэтому переносить знания между функциями нужно осторожно.
|
||
|
||
### Принцип работы seqovl
|
||
|
||
![[desync-anim-hub-seqovl.svg|Анимация: seqovl дописывает слева паттерн и сдвигает seq на 990; DPI читает сегмент целиком, сервер выбрасывает байты левее 1000]]
|
||
|
||
```
|
||
Без seqovl:
|
||
TCP seq: 0
|
||
Данные: [РЕАЛЬНАЯ_ЧАСТЬ_1]
|
||
Сервер: принимает [РЕАЛЬНАЯ_ЧАСТЬ_1] целиком
|
||
|
||
С seqovl=10:
|
||
TCP seq: -10 (уменьшен на 10)
|
||
Данные: [PATTERN_10_БАЙТ][РЕАЛЬНАЯ_ЧАСТЬ_1]
|
||
|
||
Что видит DPI:
|
||
Единый TCP-сегмент начиная с seq -10.
|
||
DPI анализирует весь блок, включая PATTERN.
|
||
Если PATTERN содержит ложный SNI — DPI может принять его за настоящий.
|
||
|
||
Что видит сервер (TCP-стек):
|
||
TCP window начинается с seq 0.
|
||
Байты -10..-1 выходят за левую границу window => отбрасываются.
|
||
Байты с 0 (РЕАЛЬНАЯ_ЧАСТЬ_1) => принимаются.
|
||
```
|
||
|
||
**Визуализация:**
|
||
|
||
```
|
||
TCP window boundary
|
||
|
|
||
| ОТБРОСИТЬ | ПРИНЯТЬ |
|
||
| PATTERN(10) | РЕАЛЬНАЯ_ЧАСТЬ_1 |
|
||
^seq=-10 ^seq=0
|
||
```
|
||
|
||
> [!note] Проще говоря
|
||
> Перед настоящей первой частью стоят лишние байты, а seq сдвинут назад ровно на их число. Сервер держит окно приёма: он принимает номера, начиная с того, который ждёт следующим, а всё левее выбрасывает как дубликат или мусор. Поэтому лишние байты пропадают, а настоящая часть принимается. DPI видит один цельный сегмент вместе с лишними байтами.
|
||
|
||
**seqovl в fakedsplit — дополнительный уровень защиты** поверх фейков. Даже если DPI научился отбрасывать фейковые сегменты, seqovl-данные внутри реального сегмента он может не распознать.
|
||
|
||
**Важно:** в `fakedsplit` `seqovl` — только **число** (не маркер). Маркеры поддерживаются в [[fakeddisorder]] и [[multidisorder]], но не здесь. Как задаётся seqovl-маркер там, разобрано в разделах [[Zapret2/desync/fakeddisorder#seqovl — маркер, а не число|seqovl — маркер, а не число]] и [[Zapret2/desync/multidisorder#seqovl как маркер|seqovl как маркер]].
|
||
|
||
### seqovl_pattern
|
||
|
||
Паттерн, которым заполняется seqovl-область (N байт слева от реальных данных). По умолчанию — `0x00` (нули).
|
||
|
||
В `fakedsplit` `seqovl_pattern` — это **имя blob**. Паттерн повторяется до нужной длины `seqovl`. Blob можно записать прямо в команде шестнадцатеричной строкой (inline hex, `0x…`) или заранее объявить флагом `--blob` и сослаться на него по имени; подробно — в заметке [[blob]].
|
||
|
||
```bash
|
||
# Inline hex blob (маскировка под начало TLS record)
|
||
--lua-desync=fakedsplit:pos=midsld:tcp_ack=-66000:seqovl=5:seqovl_pattern=0x1603030000
|
||
|
||
# Предзагруженный blob
|
||
--blob=tlspat:0x1603030100 \
|
||
--lua-desync=fakedsplit:pos=midsld:tcp_ack=-66000:seqovl=8:seqovl_pattern=tlspat
|
||
```
|
||
|
||
Если `optional` задан и blob `seqovl_pattern` отсутствует — используется нулевой паттерн (seqovl не отменяется). Сам флаг описан в разделе [[#A) Собственные аргументы fakedsplit|A) Собственные аргументы fakedsplit]].
|
||
|
||
---
|
||
|
||
## pattern — заполнение фейков
|
||
|
||
Аргумент `pattern` задаёт содержимое фейковых сегментов. Это имя blob, из которого генерируется паттерн для заполнения фейков. Blob — заранее заготовленные данные под именем (про них — заметка [[blob]]); про фейки как таковые — в разделе [[Zapret2/ts-and-fooling#Что такое fooling|Что такое fooling]].
|
||
|
||
```lua
|
||
fakepat = desync.arg.pattern and blob(desync, desync.arg.pattern) or "\x00"
|
||
```
|
||
|
||
- По умолчанию: `\x00` (нулевые байты)
|
||
- Фейк первой части: `pattern(fakepat, 1, pos-1)` — паттерн со смещением 1, длиной pos-1
|
||
- Фейк второй части: `pattern(fakepat, pos, #data-pos+1)` — паттерн со смещением pos, длиной остатка
|
||
|
||
Смещение паттерна (`pos`) соответствует смещению TCP sequence отсылаемой части. Это значит, что если DPI сравнивает байты фейка и оригинала побайтово — он увидит разные данные в одних и тех же позициях. Но если он просто реассемблирует поток — паттерн не сможет "обмануть" конкретную сигнатуру (для этого нужен осмысленный blob).
|
||
|
||
> [!note] Проще говоря
|
||
> По умолчанию фейки набиты нулями. Если нужно, чтобы фейк был похож на что-то осмысленное, задайте `pattern` с подходящим blob: паттерн повторяется до нужной длины фейка, а его смещение совпадает с местом фейка в потоке. Сигнатурой в этих словах названа заранее известная DPI строка данных, на которую он реагирует; нулями такую строку не сымитировать. Готовый пример с HTTP-подобным заполнением — [[#5. С кастомным паттерном для фейков|пример 5]].
|
||
|
||
```bash
|
||
# Фейки заполнены случайными данными из blob
|
||
--blob=rndpat:0xDEADBEEFCAFEBABE \
|
||
--lua-desync=fakedsplit:pos=midsld:tcp_ack=-66000:pattern=rndpat
|
||
|
||
# Фейки заполнены нулями (по умолчанию)
|
||
--lua-desync=fakedsplit:pos=midsld:tcp_ack=-66000
|
||
```
|
||
|
||
---
|
||
|
||
## nofake1..nofake4 — отключение отдельных фейков
|
||
|
||
Каждый из 4 фейковых пакетов можно отключить индивидуально. Номер флага — номер фейка в порядке отправки: `nofake1` и `nofake2` относятся к первой части (до неё и после), `nofake3` и `nofake4` — ко второй:
|
||
|
||
| Флаг | Отключает | Позиция в потоке |
|
||
|:-----|:----------|:-----------------|
|
||
| `nofake1` | Фейк 1-й части (до реальной 1-й) | #1 |
|
||
| `nofake2` | Фейк 1-й части (после реальной 1-й) | #3 |
|
||
| `nofake3` | Фейк 2-й части (до реальной 2-й) | #4 |
|
||
| `nofake4` | Фейк 2-й части (после реальной 2-й) | #6 |
|
||
|
||
Минимально необходимые пакеты — только два реальных (#2, #5). Все 4 фейка можно отключить:
|
||
|
||
```bash
|
||
# Без фейков вообще (по сути = multisplit с одной позицией)
|
||
--lua-desync=fakedsplit:pos=midsld:nofake1:nofake2:nofake3:nofake4
|
||
```
|
||
|
||
Типичные комбинации (о том, сколько пакетов остаётся, — в примерах [[#8. Без "задних" фейков (оптимизация трафика)|8]] и [[#9. С повторами фейков (максимальный шум)|9]]):
|
||
|
||
```bash
|
||
# Только "передние" фейки (до реальных частей)
|
||
--lua-desync=fakedsplit:pos=midsld:tcp_ack=-66000:nofake2:nofake4
|
||
|
||
# Только "задние" фейки (после реальных частей)
|
||
--lua-desync=fakedsplit:pos=midsld:tcp_ack=-66000:nofake1:nofake3
|
||
|
||
# Фейки только для 1-й части
|
||
--lua-desync=fakedsplit:pos=midsld:tcp_ack=-66000:nofake3:nofake4
|
||
```
|
||
|
||
---
|
||
|
||
## Полный список аргументов
|
||
|
||
Аргументы делятся на собственные аргументы `fakedsplit` (раздел A) и стандартные (разделы B–G): их понимают и другие функции дурения, а общий обзор есть в [[desync]]. Формат вызова:
|
||
|
||
```
|
||
--lua-desync=fakedsplit[:arg1[=val1][:arg2[=val2]]...]
|
||
```
|
||
|
||
Все `val` приходят в Lua как строки. Если `=val` не указан, значение = пустая строка `""` (в Lua это truthy), поэтому флаги пишутся просто как `:optional`, `:nodrop`, `:tcp_ts_up`.
|
||
|
||
### A) Собственные аргументы fakedsplit
|
||
|
||
#### `pos`
|
||
|
||
- **Формат:** `pos=<marker>`
|
||
- **Тип:** строка — **один** маркер (НЕ список!)
|
||
- **По умолчанию:** `"2"`
|
||
- **Описание:** Точка разреза. Payload делится на 2 части: `data[1..pos-1]` и `data[pos..#data]`. Виды маркеров — в разделе [[#Маркер позиции (pos)|Маркер позиции (pos)]]
|
||
- **Примеры:**
|
||
- `pos=2` — разрез после 2-го байта (дефолт)
|
||
- `pos=1` — первый байт уходит отдельным сегментом
|
||
- `pos=midsld` — разрез посередине SLD
|
||
- `pos=method+2` — после первых 2 символов HTTP-метода
|
||
- `pos=host` — перед началом hostname
|
||
- `pos=sniext+1` — после начала SNI extension data
|
||
|
||
#### `pattern`
|
||
|
||
- **Формат:** `pattern=<blobName>`
|
||
- **Тип:** имя blob-переменной
|
||
- **По умолчанию:** `\x00` (нулевой байт)
|
||
- **Описание:** Данные для заполнения фейковых сегментов. Blob повторяется функцией `pattern()` до нужного размера. Подробнее — в разделе [[#pattern — заполнение фейков|pattern — заполнение фейков]]
|
||
- **Примеры:**
|
||
- `pattern=0xDEADBEEF` — inline hex
|
||
- `pattern=my_fake_pattern` — предзагруженный blob
|
||
|
||
#### `seqovl`
|
||
|
||
- **Формат:** `seqovl=N` (где N > 0)
|
||
- **Тип:** только число (маркеры **не поддерживаются** — в отличие от [[fakeddisorder]])
|
||
- **По умолчанию:** не задан (нет seqovl)
|
||
- **Описание:** Применяется **только к первому реальному сегменту** (пакет #2). К данным первого сегмента слева добавляется N байт `seqovl_pattern`, а TCP `th_seq` уменьшается на N. Сервер отбросит левую часть, DPI — может не отбросить. Механика — в разделе [[#seqovl — скрытый фейк внутри сегмента|seqovl — скрытый фейк внутри сегмента]]
|
||
- **Примеры:**
|
||
- `seqovl=5` — 5 байт фейка слева
|
||
- `seqovl=13` — 13 байт фейка слева
|
||
|
||
#### `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
|
||
|
||
#### `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 отсутствует => fakedsplit **ничего не делает** (тихий skip, без ошибок)
|
||
- Если задан `seqovl_pattern=...` и blob отсутствует => используется нулевой паттерн (seqovl не отменяется)
|
||
- **Использование:** защита от ошибок при использовании blob, которые могут отсутствовать
|
||
|
||
#### `nodrop`
|
||
|
||
- **Формат:** `nodrop` (флаг, без значения)
|
||
- **Описание:** После успешной отправки сегментов **не выносить** `VERDICT_DROP` (вместо этого вернуть `VERDICT_PASS`). Это означает, что оригинальный пакет тоже будет отправлен (наряду с нарезанными сегментами и фейками). `VERDICT_DROP` — решение «перехваченный пакет не отправлять», `VERDICT_PASS` — «пропустить пакет как есть» ([[Zapret2/жизненный цикл desync-функции#Стадия 8. Вердикт и его агрегация|стадия 8 жизненного цикла]])
|
||
- **Использование:** для отладки
|
||
- **Предупреждение:** в боевых профилях `nodrop` обычно нежелателен (см. [[#9. nodrop создаёт сильное дублирование|нюанс 9]])
|
||
|
||
#### `nofake1`
|
||
|
||
- **Формат:** `nofake1` (флаг, без значения)
|
||
- **Описание:** Не отправлять фейк 1-й части **до** реальной 1-й части (пакет #1)
|
||
|
||
#### `nofake2`
|
||
|
||
- **Формат:** `nofake2` (флаг, без значения)
|
||
- **Описание:** Не отправлять фейк 1-й части **после** реальной 1-й части (пакет #3)
|
||
|
||
#### `nofake3`
|
||
|
||
- **Формат:** `nofake3` (флаг, без значения)
|
||
- **Описание:** Не отправлять фейк 2-й части **до** реальной 2-й части (пакет #4)
|
||
|
||
#### `nofake4`
|
||
|
||
- **Формат:** `nofake4` (флаг, без значения)
|
||
- **Описание:** Не отправлять фейк 2-й части **после** реальной 2-й части (пакет #6)
|
||
|
||
---
|
||
|
||
### B) Standard direction
|
||
|
||
Направление говорит, в какую сторону идёт пакет: от вашего компьютера к серверу (исходящий) или обратно (входящий).
|
||
|
||
| Параметр | Значения | По умолчанию |
|
||
|:---------|:---------|:-------------|
|
||
| `dir` | `in`, `out`, `any` | `out` |
|
||
|
||
Фильтр по направлению пакета. `fakedsplit` по умолчанию работает только с исходящими (`out`).
|
||
|
||
- `dir=out` — только исходящие (от клиента к серверу)
|
||
- `dir=in` — только входящие (от сервера к клиенту)
|
||
- `dir=any` — оба направления
|
||
|
||
При первом вызове с указанным `dir` функция делает `direction_cutoff_opposite` — отсекает себя от противоположного направления. Cutoff (отсечение) значит, что движок больше не будет вызывать функцию на пакетах этого направления в текущем соединении; подробно — в [[Zapret2/жизненный цикл desync-функции#Стадия 2. Отсечение противоположного направления|стадии 2 жизненного цикла]].
|
||
|
||
---
|
||
|
||
### C) Standard payload
|
||
|
||
| Параметр | Значения | По умолчанию |
|
||
|:---------|:---------|:-------------|
|
||
| `payload` | список типов через запятую | `known` |
|
||
|
||
Фильтр по [[Zapret2/payload#Что такое тип payload (и чем он отличается от протокола потока)|типу payload]] на уровне Lua. Это **дополнительный** фильтр к `--payload=...` на уровне [[Zapret2/profile#Анатомия профиля|профиля]].
|
||
|
||
- `payload=known` — только распознанные протоколы (`http_req`, `tls_client_hello`, `quic_initial` и т.д.)
|
||
- `payload=all` — любой payload, включая `unknown`
|
||
- `payload=tls_client_hello,http_req` — конкретные типы
|
||
- `payload=~unknown` — инверсия: всё кроме unknown
|
||
|
||
**Важно:** лучше ставить `--payload=...` на уровне профиля (C-код, быстрее), а не полагаться только на Lua-фильтр.
|
||
|
||
Проще говоря: фильтр `--payload=` на уровне профиля работает в быстром ядре программы, написанном на C, а аргумент `payload=` проверяется уже в Lua, то есть медленнее. Поэтому основной отбор лучше делать на уровне профиля.
|
||
|
||
---
|
||
|
||
### D) Standard fooling
|
||
|
||
Fooling — намеренная порча заголовков пакета, чтобы сервер отбросил фейк, а DPI его прочитал (подробно — [[Zapret2/ts-and-fooling#Что такое fooling|Что такое fooling]]; каталог способов, где какой ломается, — [[Zapret2/ts-and-fooling#Как заставить fake умереть: каталог способов|Как заставить fake умереть]]). Модификации L3/L4 заголовков, то есть заголовков IP (сетевой уровень) и TCP (транспортный уровень). В `fakedsplit` применяются **только к фейкам** (opts_fake). К оригиналам из всего fooling идёт **только tcp_ts_up**.
|
||
|
||
| Параметр | Описание | Пример |
|
||
|:---------|:---------|:-------|
|
||
| `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` |
|
||
|
||
**Важно для fakedsplit:** `tcp_ts_up` — единственный параметр fooling, который применяется и к оригиналам. Все остальные — только к фейкам. Это значит, что `tcp_ack=-66000` безопасен — оригиналы будут иметь валидный ACK, а фейки — невалидный.
|
||
|
||
**Заметка про tcp_ts_up:** На Linux-серверах пакеты с инвалидным ACK стабильно отбрасываются **только если** TCP timestamp option идёт первой в заголовке. `tcp_ts_up` перемещает её в начало, обеспечивая корректную работу badseq-fooling. Поскольку `tcp_ts_up` безвреден (не портит данные, просто переупорядочивает опции), он применяется и к оригиналам.
|
||
|
||
---
|
||
|
||
### E) Standard ipid
|
||
|
||
IP ID — идентификатор в заголовке IPv4-пакета. Эти параметры задают, какие значения получат отправляемые сегменты.
|
||
|
||
| Параметр | Описание | По умолчанию |
|
||
|:---------|:---------|:-------------|
|
||
| `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` применяется **и к фейкам, и к оригиналам** (оба набора опций содержат `ipid = desync.arg`).
|
||
|
||
---
|
||
|
||
### F) Standard reconstruct
|
||
|
||
Реконструкция — сборка готового raw-пакета («сырого», со всеми заголовками) перед отправкой.
|
||
|
||
| Параметр | Описание |
|
||
|:---------|:---------|
|
||
| `badsum` | Испортить L4 (TCP) checksum при реконструкции raw-пакета. Сервер отбросит такой пакет |
|
||
|
||
В `fakedsplit` `badsum` применяется **только к фейкам** (`opts_fake`). Оригиналы имеют пустой `reconstruct = {}`.
|
||
|
||
---
|
||
|
||
### G) Standard rawsend
|
||
|
||
Rawsend — отправка готовых сегментов в сеть самой функцией; в `fakedsplit` её выполняет `rawsend_payload_segmented` (см. [[#Автосегментация по MSS|Автосегментация по MSS]]). Эти параметры управляют отправкой.
|
||
|
||
| Параметр | Описание |
|
||
|:---------|:---------|
|
||
| `repeats=N` | Отправить каждый сегмент N раз (идентичные повторы) |
|
||
| `ifout=<iface>` | Интерфейс для отправки (по умолчанию определяется автоматически) |
|
||
| `fwmark=N` | Firewall mark (только Linux, nftables/iptables) |
|
||
|
||
**Важная деталь:** `repeats` применяется **только к фейкам**. Оригиналы используют `rawsend_opts_base`, который не включает `repeats`. `ifout` и `fwmark` применяются к обоим.
|
||
|
||
---
|
||
|
||
## Порядок отправки — подробно с seqovl
|
||
|
||
В примерах ниже payload — десять байт `ABCDEFGHIJ`, настоящие данные обозначены буквами, а фейки набиты байтом `0xFF`. В них `pos=4` — это позиция в нумерации Lua (с единицы), поэтому первая часть (`data[1..pos-1]` из описания аргумента `pos`) содержит три байта `ABC`; в командной строке такой разрез записывался бы как `pos=3` ([[#Важные нюансы pos|Важные нюансы pos]]). Номера seq здесь — смещения от начала данных.
|
||
|
||
### Без seqovl
|
||
|
||
```
|
||
Payload "ABCDEFGHIJ" (10 байт), pos=4, pattern=0xFF
|
||
|
||
Пакет #1 (fake1): seq=0 data=[FF FF FF] len=3 opts_fake
|
||
Пакет #2 (real1): seq=0 data=[A B C ] len=3 opts_orig
|
||
Пакет #3 (fake1'): seq=0 data=[FF FF FF] len=3 opts_fake
|
||
Пакет #4 (fake2): seq=3 data=[FF FF FF FF FF FF FF] len=7 opts_fake
|
||
Пакет #5 (real2): seq=3 data=[D E F G H I J] len=7 opts_orig
|
||
Пакет #6 (fake2'): seq=3 data=[FF FF FF FF FF FF FF] len=7 opts_fake
|
||
```
|
||
|
||
### С seqovl=5
|
||
|
||
```
|
||
Payload "ABCDEFGHIJ" (10 байт), pos=4, pattern=0xFF, seqovl=5, seqovl_pattern=0x00
|
||
|
||
Пакет #1 (fake1): seq=0 data=[FF FF FF] len=3 opts_fake
|
||
Пакет #2 (real1): seq=-5 data=[00 00 00 00 00 A B C ] len=8 opts_orig
|
||
Пакет #3 (fake1'): seq=0 data=[FF FF FF] len=3 opts_fake
|
||
Пакет #4 (fake2): seq=3 data=[FF FF FF FF FF FF FF] len=7 opts_fake
|
||
Пакет #5 (real2): seq=3 data=[D E F G H I J] len=7 opts_orig
|
||
Пакет #6 (fake2'): seq=3 data=[FF FF FF FF FF FF FF] len=7 opts_fake
|
||
|
||
Сервер:
|
||
Пакет #2: seq=-5, байты -5..-1 за window => отброшены; байты 0..2 = [A B C] => приняты
|
||
Пакет #5: seq=3, байты 3..9 = [D E F G H I J] => приняты
|
||
Итого: [A B C D E F G H I J] = полный payload
|
||
```
|
||
|
||
> [!note] Проще говоря
|
||
> Пакет №2 стал на 5 байт длиннее (слева пять нулей) и начинается с seq −5. Сервер выбрасывает то, что левее его окна приёма (нули), и принимает `ABC`; вторую часть он принимает целиком. Фейки в обоих примерах отброшены, поэтому в итоге сервер собрал полный `ABCDEFGHIJ`. Механика seqovl — в разделе [[#seqovl — скрытый фейк внутри сегмента|seqovl — скрытый фейк внутри сегмента]].
|
||
|
||
---
|
||
|
||
## Поведение при replay / reasm
|
||
|
||
![[desync-anim-hub-reasm.svg|Анимация: большой ClientHello приходит тремя пакетами, ядро собирает reasm_data, функция режет весь буфер на первой части, остальные части дропаются]]
|
||
|
||
Многопакетный запрос (например, большой TLS ClientHello, не влезающий в один TCP-сегмент) `nfqws2` придерживает, собирает в буфер `reasm_data` (reasm — повторная сборка) и перепроигрывает через desync-функции. Перепроигрывание (replay) означает, что движок по очереди вызывает функции на каждой придержанной части, но уже с собранным целым на руках. `fakedsplit` использует штатную развилку из общего скелета desync-функций ([[жизненный цикл desync-функции]], стадия 6) без изменений: разрезает и отправляет **весь** собранный буфер вместе с фейками на первой части, а остальные части дропает. Если отправка сорвалась, флаг «реасм уже отправлен» не ставится и оставшиеся части проходят как есть.
|
||
|
||
Специфика функции здесь одна, зато существенная: фейковые сегменты строятся по размерам реальных частей **всего реасма**, а не отдельного пакета. Поэтому при многопакетном ClientHello фейки получаются крупными — ровно такими же, как реальные куски.
|
||
|
||
> [!note] Проще говоря
|
||
> Если запрос пришёл несколькими пакетами, `fakedsplit` дожидается, пока движок соберёт его целиком, режет собранное и отправляет шесть пакетов один раз — на первой части; остальные придержанные части выбрасываются, потому что их содержимое уже ушло. Как движок собирает и перепроигрывает такие запросы, описано в [[структура desync и диссекта#Приём многопакетных пейлоадов (reasm / decrypt / replay)|заметке о структуре desync]], а как то же самое устроено у соседней функции — в [[Zapret2/desync/multisplit#Поведение при replay / reasm|multisplit]].
|
||
|
||
---
|
||
|
||
## Автосегментация по MSS
|
||
|
||
![[desync-anim-hub-mss.svg|Анимация: кусок данных больше MSS автоматически режется на под-сегменты с растущим seq]]
|
||
|
||
MSS (Maximum Segment Size) — наибольший объём данных, который помещается в один TCP-сегмент данного соединения. О размерах TCP-сегментов думать **не нужно**. Функция `rawsend_payload_segmented` из `zapret-lib.lua` автоматически:
|
||
|
||
1. Отслеживает MSS для каждого TCP-соединения
|
||
2. Если часть payload превышает MSS — дополнительно режет по MSS
|
||
3. Каждый под-сегмент отправляется с корректным TCP sequence
|
||
|
||
Это относится и к фейкам, и к оригиналам. Та же автосегментация (и что применяется к под-сегментам) описана в статье о multisplit: [[Zapret2/desync/multisplit#Автосегментация по MSS|Автосегментация по MSS]].
|
||
|
||
---
|
||
|
||
## Место в общем скелете
|
||
|
||
Тело `fakedsplit` построено по тому же шаблону, что и все остальные функции дурения: восемь стадий от отсева чужого транспорта до вердикта. Разобраны они один раз в [[жизненный цикл desync-функции]] — здесь только отклонения:
|
||
|
||
| Стадия общего скелета | Что делает `fakedsplit` |
|
||
|:----------------------|:----------------|
|
||
| 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. **Своя техника** | одна позиция разреза (`resolve_pos`, не список), два реальных сегмента и до четырёх фейков между ними — этому посвящена вся заметка |
|
||
| 8. Вердикт | `VERDICT_DROP` после успешной отправки, `VERDICT_PASS` при `nodrop` или сбое `rawsend` |
|
||
|
||
> [!note] Проще говоря
|
||
> Из восьми стадий общего скелета своя у `fakedsplit` одна — седьмая: один разрез, два реальных сегмента и до четырёх фейков между ними. Остальные стадии такие же, как у других функций. Про стадию 6 подробнее сказано в [[Zapret2/жизненный цикл desync-функции#Стадия 6. Развилка перепроигрывания (replay)|стадии 6]], про вердикты (`VERDICT_DROP` — «перехваченный пакет не отправлять», `VERDICT_PASS` — «пропустить») — в [[Zapret2/жизненный цикл desync-функции#Стадия 8. Вердикт и его агрегация|стадии 8]].
|
||
|
||
Отдельно стоит запомнить, как `fakedsplit` обращается с опциями. В отличие от [[multisplit]], он собирает **два разных набора**: фейкам достаются fooling и reconstruct в полном объёме (фейк обязан быть отвергнут сервером), а реальным частям — только `tcp_ts_up` и политика `ip_id`. Повторы `repeats` тоже уходят лишь на фейки. Общий разбор наборов опций — в [[жизненный цикл desync-функции]].
|
||
|
||
---
|
||
|
||
## Псевдокод алгоритма
|
||
|
||
Тело функции целиком, включая общие для всех техник стадии — они пронумерованы так же, как в [[жизненный цикл desync-функции]]. Комментарии `-- N.` нумеруют шаги: первые шаги совпадают со стадиями общего скелета, шаги с разрезом и отправкой шести пакетов — это собственно техника, а последние — пометка об отправке и вердикт. Проще говоря, функция находит место разреза, собирает два набора опций и отправляет шесть пакетов в порядке фейк 1-й части, настоящая 1-я, фейк 1-й, фейк 2-й, настоящая 2-я, фейк 2-й, а затем выбрасывает оригинал (если не задан `nodrop`):
|
||
|
||
```lua
|
||
function fakedsplit(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_pos(data, l7payload, pos_arg or "2")
|
||
|
||
if pos == nil then
|
||
DLOG("cannot resolve pos")
|
||
elseif pos == 1 then
|
||
DLOG("split pos resolved to 0. cannot split.")
|
||
else
|
||
-- 8. Создание двух наборов опций
|
||
opts_orig = {rawsend=base, reconstruct={}, ipfrag={},
|
||
ipid=arg, fooling={tcp_ts_up=arg.tcp_ts_up}}
|
||
opts_fake = {rawsend=full, reconstruct=reconstruct_opts,
|
||
ipfrag={}, ipid=arg, fooling=arg}
|
||
|
||
-- 9. Паттерн для фейков
|
||
fakepat = arg.pattern blob or "\x00"
|
||
|
||
-- 10. ФЕЙК 1-й части
|
||
fake = pattern(fakepat, 1, pos-1)
|
||
if not nofake1 then
|
||
rawsend_payload_segmented(fake, 0, opts_fake)
|
||
end
|
||
|
||
-- 11. РЕАЛЬНАЯ 1-я часть (+seqovl)
|
||
part = data:sub(1, pos-1)
|
||
seqovl = 0
|
||
if arg.seqovl and tonumber(arg.seqovl) > 0 then
|
||
seqovl = tonumber(arg.seqovl)
|
||
pat = "\x00"
|
||
if arg.seqovl_pattern then
|
||
if optional and blob not exists then
|
||
pat = "\x00" -- fallback
|
||
else
|
||
pat = blob(seqovl_pattern)
|
||
end
|
||
end
|
||
part = pattern(pat, 1, seqovl) .. part
|
||
end
|
||
rawsend_payload_segmented(part, -seqovl, opts_orig)
|
||
|
||
-- 12. ФЕЙК 1-й части (повтор)
|
||
if not nofake2 then
|
||
rawsend_payload_segmented(fake, 0, opts_fake)
|
||
end
|
||
|
||
-- 13. ФЕЙК 2-й части
|
||
fake = pattern(fakepat, pos, #data-pos+1)
|
||
if not nofake3 then
|
||
rawsend_payload_segmented(fake, pos-1, opts_fake)
|
||
end
|
||
|
||
-- 14. РЕАЛЬНАЯ 2-я часть
|
||
part = data:sub(pos)
|
||
rawsend_payload_segmented(part, pos-1, opts_orig)
|
||
|
||
-- 15. ФЕЙК 2-й части (повтор)
|
||
if not nofake4 then
|
||
rawsend_payload_segmented(fake, pos-1, opts_fake)
|
||
end
|
||
|
||
-- 16. Пометить как отправленное
|
||
replay_drop_set()
|
||
return nodrop and VERDICT_PASS or VERDICT_DROP
|
||
end
|
||
else
|
||
-- 17. Не первый replay
|
||
DLOG("not acting on further replay pieces")
|
||
end
|
||
|
||
-- 18. Drop replayed packets если ранее успешно отправлено
|
||
if replay_drop() then
|
||
return nodrop and VERDICT_PASS or VERDICT_DROP
|
||
end
|
||
end
|
||
end
|
||
```
|
||
|
||
---
|
||
|
||
## Нюансы и подводные камни
|
||
|
||
### 1. Работает только с TCP
|
||
|
||
Если текущий пакет не TCP (UDP, ICMP и т.д.), `fakedsplit` делает `instance_cutoff_shim` — отключает себя для этого потока навсегда. Исключение: ICMP-пакеты (связанные с TCP) не вызывают cutoff. Почему приём вообще завязан на TCP (сквозная нумерация байтов, окно приёма), разобрано в статье о multisplit: [[Zapret2/desync/multisplit#1. Работает только с TCP — и почему|1. Работает только с TCP — и почему]]; механика cutoff — в [[Zapret2/жизненный цикл desync-функции#Стадия 1. Отсев чужого транспорта и instance cutoff|стадии 1 жизненного цикла]].
|
||
|
||
### 2. Только ОДНА позиция разреза
|
||
|
||
В отличие от [[multisplit]], `fakedsplit` принимает **один** маркер, не список. `pos=midsld,endhost` не будет работать как два разреза — строка целиком передастся в `resolve_pos`, который не умеет парсить запятые. Если нужно несколько точек разреза с фейками — используйте цепочку инстансов или [[fakeddisorder]]. Инстанс — одна запись `--lua-desync=…` в профиле.
|
||
|
||
### 3. Позиция 1 не работает
|
||
|
||
Если `resolve_pos` возвращает Lua-позицию 1, fakedsplit логирует "split pos resolved to 0. cannot split." и ничего не делает. Это соответствует маркеру `0` (смещения в командной строке считаются с нуля), а не `pos=1`. Практический пример: `pos=method` для HTTP не сработает, рабочий вариант — `pos=method+2`.
|
||
|
||
### 4. Fooling ОБЯЗАТЕЛЕН для фейков
|
||
|
||
Без fooling фейки будут приняты сервером как валидные данные, что сломает TCP-поток. Всегда указывайте хотя бы один метод fooling (что это такое — в разделе [[Zapret2/ts-and-fooling#Что такое fooling|Что такое fooling]]):
|
||
|
||
```bash
|
||
# НЕПРАВИЛЬНО — фейки будут приняты сервером!
|
||
--lua-desync=fakedsplit:pos=midsld
|
||
|
||
# ПРАВИЛЬНО — фейки отброшены по невалидному ACK
|
||
--lua-desync=fakedsplit:pos=midsld:tcp_ack=-66000:tcp_ts_up
|
||
```
|
||
|
||
### 5. tcp_ts_up рекомендуется вместе с tcp_ack/tcp_seq
|
||
|
||
На Linux-серверах `tcp_ack=-66000` надёжно отбрасывает пакеты только если TCP timestamp option идёт первой. `tcp_ts_up` обеспечивает это (то же сказано в таблице [[Zapret2/ts-and-fooling#Как заставить fake умереть: каталог способов|Как заставить fake умереть]], строка про bad ack). Всегда комбинируйте:
|
||
|
||
```bash
|
||
:tcp_ack=-66000:tcp_ts_up
|
||
```
|
||
|
||
### 6. repeats применяются ТОЛЬКО к фейкам
|
||
|
||
`repeats=N` — сколько раз отправить каждый сегмент. Если задать `repeats=5`, каждый фейк отправится 5 раз, а каждый оригинал — 1 раз. Это сделано специально: больше фейков => больше шума для DPI, но данные не дублируются.
|
||
|
||
### 7. ipfrag НЕ используется
|
||
|
||
IP-фрагментация — деление пакета на части на уровне IP, а не TCP. В отличие от [[multisplit]] и [[multidisorder]], `fakedsplit` не поддерживает IP-фрагментацию. Оба набора опций имеют пустой `ipfrag = {}`. Если нужна IP-фрагментация поверх фейков — это не поддерживается напрямую.
|
||
|
||
### 8. badsum идёт только на фейки
|
||
|
||
`badsum` портит контрольную сумму TCP: по ней получатель проверяет, что пакет не повреждён. Это часть `reconstruct`, который применяется только к фейкам. Оригиналы всегда имеют валидный checksum. Это безопасно и является ещё одним методом fooling.
|
||
|
||
### 9. nodrop создаёт сильное дублирование
|
||
|
||
С `nodrop` fakedsplit отправляет до 6 сегментов (фейки + оригиналы) И пропускает оригинальный пакет. Сервер получит данные как минимум дважды. Используйте `nodrop` только для отладки. О том, как движок обращается с `VERDICT_DROP` и `VERDICT_PASS`, — в [[Zapret2/жизненный цикл desync-функции#Стадия 8. Вердикт и его агрегация|стадии 8 жизненного цикла]].
|
||
|
||
### 10. Порядок инстансов важен
|
||
|
||
Если перед `fakedsplit` стоит `pktmod` с модификацией — pktmod изменит payload, и fakedsplit порежет уже изменённые данные. Если после fakedsplit стоит ещё один инстанс — он увидит VERDICT_DROP и не получит оригинальный payload.
|
||
|
||
Уточнение из разбора вердиктов: `VERDICT_DROP` не обрывает цепочку. Движок проходит все инстансы профиля и складывает их вердикты (`VERDICT_DROP` перебивает `VERDICT_PASS` и `VERDICT_MODIFY`), так что инстансы после `fakedsplit` вызываются как обычно, а дроп означает лишь то, что оригинальный пакет в итоге не уйдёт ([[Zapret2/жизненный цикл desync-функции#Стадия 8. Вердикт и его агрегация|стадия 8 жизненного цикла]]; то же — в [[Zapret2/desync/multisplit#7. Порядок инстансов важен|нюансе о порядке инстансов в multisplit]]). Как аргументы и инстансы выстраиваются в цепочку — в [[последовательность аргументов]].
|
||
|
||
### 11. Неразрешённый маркер != ошибка
|
||
|
||
Если `resolve_pos` не смог разрешить маркер (например, `midsld` для `unknown` payload), fakedsplit логирует "cannot resolve pos" и **ничего не делает** — ни фейков, ни разреза. Оригинальный пакет проходит как есть.
|
||
|
||
---
|
||
|
||
## Отличия от других функций сегментации
|
||
|
||
Четыре функции ниже режут данные на TCP-сегменты, но различаются числом разрезов, порядком отправки, наличием фейков и тем, как устроен `seqovl`. Строки таблицы читаются слева направо: сначала обычная сегментация, затем варианты с фейками. Подробности о каждой функции — в разделах [[Zapret2/desync/multisplit#Отличия от других функций сегментации|multisplit]], [[Zapret2/desync/multidisorder#Отличия от других функций сегментации|multidisorder]] и [[Zapret2/desync/fakeddisorder#Отличия от fakedsplit, multisplit и multidisorder|fakeddisorder]].
|
||
|
||
| Аспект | `multisplit` | `multidisorder` | `fakedsplit` | `fakeddisorder` |
|
||
|:-------|:-------------|:----------------|:-------------|:----------------|
|
||
| Количество позиций | Список (любое кол-во) | Список (любое кол-во) | **Одна** | **Одна** |
|
||
| Резолвер позиций | `resolve_multi_pos` | `resolve_multi_pos` | **`resolve_pos`** | **`resolve_pos`** |
|
||
| Порядок отправки | Прямой (1->2->3) | Обратный (3->2->1) | Прямой (с фейками) | Обратный (с фейками) |
|
||
| Фейковые сегменты | **Нет** | **Нет** | Да (до 4 шт.) | Да (до 4 шт.) |
|
||
| Пакетов на выходе | N+1 (N позиций) | N+1 (N позиций) | До 6 (2 реальных + 4 фейка) | До 6 (2 реальных + 4 фейка) |
|
||
| seqovl тип | Только число | **Маркер** | Только число | **Маркер** |
|
||
| seqovl к какому сегменту | 1-й | 2-й (предпоследний) | 1-й реальный | 2-й реальный |
|
||
| Fooling к | Всем сегментам | Всем сегментам | **Только к фейкам** | **Только к фейкам** |
|
||
| reconstruct к | Всем сегментам | Всем сегментам | **Только к фейкам** | **Только к фейкам** |
|
||
| repeats к | Всем сегментам | Всем сегментам | **Только к фейкам** | **Только к фейкам** |
|
||
| ipfrag | Да | Да | **Нет** | **Нет** |
|
||
| ipid к | Всем сегментам | Всем сегментам | И фейкам, и оригиналам | И фейкам, и оригиналам |
|
||
| tcp_ts_up к оригиналам | Да (как часть fooling) | Да (как часть fooling) | **Да (единственный fooling)** | **Да (единственный fooling)** |
|
||
|
||
Проще говоря: главная развилка — есть ли фейки и в каком порядке уходят части. У `multisplit` и `multidisorder` фейков нет (порядок прямой и обратный), у `fakedsplit` и `fakeddisorder` они есть и достаются только фейкам (порядок прямой и обратный).
|
||
|
||
---
|
||
|
||
## Миграция с nfqws1
|
||
|
||
nfqws1 — движок первой версии zapret; там техники включались ключами `--dpi-desync-…`, а в nfqws2 они стали Lua-функциями `--lua-desync=<функция>:<аргументы>`. Таблица ниже сопоставляет ключи `fakedsplit`, а примеры показывают перевод команд целиком. Про сам fooling и то, чем `badseq` отличается от `tcp_ack`, — в разделе [[Zapret2/ts-and-fooling#Как заставить fake умереть: каталог способов|Как заставить fake умереть]].
|
||
|
||
### Соответствие параметров
|
||
|
||
| nfqws1 | nfqws2 |
|
||
|:-------|:-------|
|
||
| `--dpi-desync=fakedsplit` | `--lua-desync=fakedsplit` |
|
||
| `--dpi-desync-split-pos=midsld` | `:pos=midsld` |
|
||
| `--dpi-desync-split-pos=method+2` | `:pos=method+2` |
|
||
| `--dpi-desync-fooling=badseq` | `:tcp_ack=-66000:tcp_ts_up` (или другой fooling) |
|
||
| `--dpi-desync-badseq-increment=0` | `:tcp_seq=0` (если нужен нулевой seq инкремент) |
|
||
| `--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=fakedsplit \
|
||
--dpi-desync-fooling=badseq \
|
||
--dpi-desync-badseq-increment=0 \
|
||
--dpi-desync-split-pos=method+2
|
||
|
||
# nfqws2 (эквивалент):
|
||
nfqws2 \
|
||
--payload=http_req \
|
||
--lua-desync=fakedsplit:pos=method+2:tcp_ack=-66000:tcp_ts_up
|
||
```
|
||
|
||
```bash
|
||
# nfqws1:
|
||
nfqws --dpi-desync=fakedsplit \
|
||
--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=fakedsplit:pos=midsld:tcp_md5:tcp_ts_up:seqovl=5:seqovl_pattern=0x1603030000
|
||
```
|
||
|
||
```bash
|
||
# nfqws1 с несколькими protocol:
|
||
nfqws --dpi-desync=fakedsplit \
|
||
--dpi-desync-fooling=badseq \
|
||
--dpi-desync-split-pos=2
|
||
|
||
# nfqws2 (разделяем по payload):
|
||
nfqws2 \
|
||
--payload=tls_client_hello,http_req \
|
||
--lua-desync=fakedsplit:pos=2:tcp_ack=-66000:tcp_ts_up
|
||
```
|
||
|
||
---
|
||
|
||
## Практические примеры
|
||
|
||
Примеры собраны от простого к сложному. В каждом после команды сказано, что уходит в сеть и что может увидеть DPI. Флаг `--payload=…` работает как фильтр для всех `--lua-desync`, которые идут после него; аргументы и порядок инстансов в профиле — в разделе [[последовательность аргументов]], а как проверить, что подобранная команда действительно работает, — в [[Zapret2/verify-strategy#Короткий чек-лист честной проверки|чек-листе честной проверки]].
|
||
|
||
### 1. Минимальный (дефолт: pos=2, fooling=badseq)
|
||
|
||
```bash
|
||
--lua-desync=fakedsplit:tcp_ack=-66000:tcp_ts_up
|
||
```
|
||
|
||
Разрезает payload после 2-го байта => 2 реальных + 4 фейка = 6 пакетов. Фейки отбрасываются по невалидному ACK.
|
||
|
||
### 2. TLS: разрез посередине SNI
|
||
|
||
```bash
|
||
--payload=tls_client_hello --lua-desync=fakedsplit:pos=midsld:tcp_ack=-66000:tcp_ts_up
|
||
```
|
||
|
||
SNI разрезан пополам. В каждом фейке — нули вместо реальных данных. DPI не может собрать hostname ни из одного отдельного сегмента.
|
||
|
||
### 3. HTTP: разрез после метода
|
||
|
||
```bash
|
||
--payload=http_req --lua-desync=fakedsplit:pos=method+2:tcp_ack=-66000:tcp_ts_up
|
||
```
|
||
|
||
Для `GET /path...` разрежет после `GE`. DPI видит 6 сегментов — 3 "ретрансмиссии" для `GE*` и 3 для `T /path...`.
|
||
|
||
### 4. С seqovl (двойная защита)
|
||
|
||
```bash
|
||
--payload=tls_client_hello \
|
||
--lua-desync=fakedsplit:pos=midsld:tcp_ack=-66000:tcp_ts_up:seqovl=5:seqovl_pattern=0x1603030000
|
||
```
|
||
|
||
Фейки + seqovl в первом реальном сегменте. Даже если DPI отбросит фейки, seqovl-данные (выглядящие как начало TLS record) могут его сбить.
|
||
|
||
### 5. С кастомным паттерном для фейков
|
||
|
||
```bash
|
||
--blob=fakepat:0x474554202F HTTP --payload=http_req \
|
||
--lua-desync=fakedsplit:pos=host:tcp_ack=-66000:tcp_ts_up:pattern=fakepat
|
||
```
|
||
|
||
Фейки заполнены данными, похожими на HTTP-запрос. DPI ещё больше запутывается. Как задавать blob и inline hex — в заметке [[blob]].
|
||
|
||
### 6. С badsum вместо badseq
|
||
|
||
```bash
|
||
--payload=tls_client_hello --lua-desync=fakedsplit:pos=midsld:badsum:tcp_ts_up
|
||
```
|
||
|
||
Фейки отбрасываются сервером из-за невалидного TCP checksum. Не все DPI проверяют checksum, поэтому для многих этого достаточно. Где `badsum` ломается (например, за NAT), сказано в [[Zapret2/ts-and-fooling#Как заставить fake умереть: каталог способов|каталоге способов]].
|
||
|
||
### 7. С TCP MD5 signature
|
||
|
||
```bash
|
||
--payload=tls_client_hello --lua-desync=fakedsplit:pos=midsld:tcp_md5:tcp_ts_up
|
||
```
|
||
|
||
Фейки содержат TCP MD5 option. Сервер без настроенного MD5 отбросит такие пакеты.
|
||
|
||
### 8. Без "задних" фейков (оптимизация трафика)
|
||
|
||
```bash
|
||
--payload=tls_client_hello \
|
||
--lua-desync=fakedsplit:pos=midsld:tcp_ack=-66000:tcp_ts_up:nofake2:nofake4
|
||
```
|
||
|
||
Только 4 пакета вместо 6. Фейки идут только **до** реальных частей. Для многих DPI этого достаточно.
|
||
|
||
### 9. С повторами фейков (максимальный шум)
|
||
|
||
```bash
|
||
--payload=tls_client_hello \
|
||
--lua-desync=fakedsplit:pos=midsld:tcp_ack=-66000:tcp_ts_up:repeats=3
|
||
```
|
||
|
||
Каждый фейк отправляется 3 раза => 4*3 + 2 = 14 пакетов. Оригиналы — по 1 разу. Максимальное замусоривание потока для DPI.
|
||
|
||
### 10. С TTL-fooling (вместо badseq)
|
||
|
||
```bash
|
||
--payload=tls_client_hello \
|
||
--lua-desync=fakedsplit:pos=midsld:ip_ttl=4:tcp_ts_up
|
||
```
|
||
|
||
Фейки имеют TTL=4 — не доживут до сервера, но DPI на пути их увидит. Менее надёжно, чем badseq (зависит от числа хопов). TTL — счётчик «прыжков» (хопов) пакета по сети: он уменьшается на каждом маршрутизаторе, и при нуле пакет выбрасывается; про TTL-fooling подробнее — в [[Zapret2/ts-and-fooling#Как заставить fake умереть: каталог способов|каталоге способов]].
|
||
|
||
### 11. Цепочка: fake + fakedsplit
|
||
|
||
```bash
|
||
--payload=tls_client_hello \
|
||
--lua-desync=fake:blob=fake_default_tls:tcp_md5:tls_mod=rnd,rndsni,dupsid \
|
||
--lua-desync=fakedsplit:pos=midsld:tcp_ack=-66000:tcp_ts_up
|
||
```
|
||
|
||
Сначала отправляется полноценный TLS-фейк (поддельный ClientHello), затем реальный payload нарезается с замешиванием фейков. Двойной удар по DPI. Как устроена функция [[Zapret2/desync/fake#Зачем нужен fake|fake]] и что означает `tls_mod`, — в её статье: [[Zapret2/desync/fake#tls_mod — модификации TLS в фейке|tls_mod — модификации TLS в фейке]]; `fake_default_tls` — один из [[Zapret2/desync/fake#Стандартные blob-ы|стандартных blob-ов]].
|
||
|
||
### 12. Комбинация с wssize и syndata
|
||
|
||
```bash
|
||
--lua-desync=wssize:wsize=1:scale=6 \
|
||
--lua-desync=syndata \
|
||
--payload=tls_client_hello \
|
||
--lua-desync=fakedsplit:pos=midsld:tcp_ack=-66000:tcp_ts_up:seqovl=5
|
||
```
|
||
|
||
Window size manipulation + SYN data + fakedsplit с seqovl. Многоуровневая защита. `wssize` меняет размер окна приёма (перечень таких функций — в [[desync]]), `syndata` отправляет SYN с данными ([[syndata]]).
|
||
|
||
### 13. Защита от отсутствующего blob
|
||
|
||
```bash
|
||
--lua-desync=fakedsplit:blob=maybe_missing:optional:pos=midsld:tcp_ack=-66000:tcp_ts_up
|
||
```
|
||
|
||
Если blob не существует — тихий пропуск, без ошибок и без VERDICT_DROP. Флаг `optional` описан в разделе [[#A) Собственные аргументы fakedsplit|A) Собственные аргументы fakedsplit]].
|
||
|
||
### 14. Отладка: не блокировать оригинал
|
||
|
||
```bash
|
||
--payload=http_req --lua-desync=fakedsplit:pos=method+2:tcp_ack=-66000:tcp_ts_up:nodrop
|
||
```
|
||
|
||
Отправляет нарезанные сегменты с фейками И пропускает оригинальный пакет (для экспериментов).
|
||
|
||
### 15. Боевой пример для YouTube (TLS)
|
||
|
||
```bash
|
||
--filter-tcp=443 --hostlist=youtube.txt \
|
||
--payload=tls_client_hello \
|
||
--lua-desync=fakedsplit:pos=midsld:tcp_ack=-66000:tcp_ts_up:seqovl=5:seqovl_pattern=0x1603030000
|
||
```
|
||
|
||
Разрез SNI пополам + seqovl маскировка + badseq fooling. Оптимальная комбинация для TLS-трафика.
|
||
|
||
### 16. Боевой пример для HTTP
|
||
|
||
```bash
|
||
--filter-tcp=80 --hostlist=blocked.txt \
|
||
--payload=http_req \
|
||
--lua-desync=fakedsplit:pos=host:tcp_ack=-66000:tcp_ts_up
|
||
```
|
||
|
||
Разрез перед hostname в HTTP Host header. Ни один сегмент не содержит полный `Host: blocked.example.com`.
|
||
|
||
### 17. Вариант из каталога GUI: fake + fakedsplit для порта 80
|
||
|
||
В каталоге стратегий [[guide|Zapret 2 GUI]] (`strategy_catalogs/winws2/tcp.txt`, запись `fake_fakedsplit_autottl_2` с подписью «рекомендуется для 80 порта», проверено в сентябре 2026) есть связка из фейкового запроса и `fakedsplit` с одинаковым fooling. `--payload` и `--out-range` ниже добавлены для наглядности, в каталоге их подставляет категория:
|
||
|
||
```bash
|
||
--payload=http_req --out-range=-d10 \
|
||
--lua-desync=fake:blob=fake_default_http:ip_autottl=2,3-20:ip6_autottl=2,3-20:tcp_ack=-66000:tcp_ts_up \
|
||
--lua-desync=fakedsplit:ip_autottl=2,3-20:ip6_autottl=2,3-20:tcp_ack=-66000:tcp_ts_up
|
||
```
|
||
|
||
Сначала уходит фейковый HTTP-запрос ([[fake]]), затем настоящий режется по позиции по умолчанию (`pos=2`, после второго байта) с фейками вокруг частей. У `fakedsplit` fooling применяется только к фейкам (см. таблицу «Отличия от других функций сегментации»), поэтому настоящие части доходят до сервера без изменений.
|
||
|
||
> [!note] Положительный autottl не убивает фейки
|
||
> `ip_autottl=2,3-20` означает «TTL на два хопа **больше** оценённого пути, но в пределах 3–20». С положительной дельтой фейк доходит до сервера, а не умирает по дороге, как при `ip_autottl=-2`. Отбрасывает его сервер уже по `tcp_ack=-66000` вместе с `tcp_ts_up`. Расчёт на то, что так фейк точно пройдёт мимо всех узлов DPI на пути; но autottl — эвристика, которая угадывает длину пути не всегда, а убивать фейк здесь остаётся только badseq; если сервер фейк не отбросит, он получит мусор. Механика autottl — в [[основные флаги]], зачем фейк должен «умереть» — в [[ts-and-fooling]].
|
||
|
||
---
|
||
|
||
## 📚 См. также
|
||
|
||
- [[desync]] — обзор всех функций `--lua-desync` и общий контракт: кто вызывает функцию, что ей передаёт и как складываются вердикты
|
||
- [[жизненный цикл desync-функции]] — восемь стадий, общих для всех техник дурения: отсев транспорта, выбор данных, replay, вердикты
|
||
- [[структура desync и диссекта]] — устройство таблицы `desync` и диссекта пакета
|
||
- [[multisplit]] — тот же разрез без фейков, с любым числом позиций; там же полный разбор `seqovl` и маркеров
|
||
- [[multidisorder]] — разрез с обратным порядком отправки, без фейков
|
||
- [[fakeddisorder]] — один разрез, фейки вокруг частей, но части уходят в обратном порядке
|
||
- [[hostfakesplit]] — разрез по границам имени хоста с подмешиванием фейкового имени
|
||
- [[fake]] — отдельный фейковый пакет, с которым `fakedsplit` можно ставить в одну цепочку
|
||
- [[ts-and-fooling]] — что такое fooling, чем `tcp_ts_up` отличается от `ts` и как фейк «умирает» до сервера
|
||
- [[blob]] — как объявлять данные для аргументов `pattern`, `seqovl_pattern` и `blob`
|
||
- [[payload]] — типы payload, от которых зависят относительные маркеры
|
||
- [[verify-strategy]] — как честно проверить, работает ли подобранная комбинация
|
||
- [[последовательность аргументов]] — как выстраивается цепочка инстансов в профиле
|
||
- [[profile]] — где `--lua-desync` живёт среди остальных настроек
|
||
- [[DPI/DPI|DPI и ТСПУ]] — как устроена инспекция трафика, против которой работает `fakedsplit`
|
||
|
||
---
|
||
|
||
> **Источники:** `lua/zapret-antidpi.lua:803-906`, `lua/zapret-lib.lua:385-422`, `docs/manual.md:4122-4164` из репозитория zapret2.
|
||
|
||
---
|
||
|
||
> [!quote] 🤖 Эти статьи открыты — можно обучать на них ИИ
|
||
> При желании вы можете натренировать ИИ на наших статьях. Исходное форматирование доступно в Forgejo: [исходник этой заметки](https://git2.zapret.moe/zapretdiscordyoutube/todo/src/branch/main/Zapret2/desync/fakedsplit.md) · [скачать весь репозиторий одним zip-архивом](https://git2.zapret.moe/zapretdiscordyoutube/todo/archive/main.zip).
|