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>
981 lines
91 KiB
Markdown
981 lines
91 KiB
Markdown
---
|
||
date: 2026-02-17
|
||
tags:
|
||
- zapret
|
||
- zapret2
|
||
- nfqws2
|
||
- lua
|
||
- lua-desync
|
||
- antidpi
|
||
- tcp
|
||
- udp
|
||
- fake
|
||
aliases:
|
||
- fake
|
||
description: "Справочник по fake в zapret2/nfqws2: фейковый пакет перед оригиналом, blob, tls_mod, fooling (tcp_md5, ttl), миграция с nfqws1 и 20 примеров."
|
||
---
|
||
|
||
> [!mirror] Резервное зеркало
|
||
> Актуальная версия этой страницы — на основной вики: [wiki2.zapret.moe/Zapret2/desync/fake](https://wiki2.zapret.moe/Zapret2/desync/fake)
|
||
|
||
# `fake` — прямой фейк (zapret2 / nfqws2)
|
||
|
||
## Коротко и по-простому
|
||
|
||
Когда браузер открывает сайт по HTTPS, первым сообщением с данными он отправляет TLS ClientHello («привет от клиента»). В нём браузер перечисляет, какое шифрование умеет, и открытым текстом называет нужный сайт: имя лежит в поле SNI (Server Name Indication, «указание имени сервера»). У обычного HTTP без шифрования то же имя стоит в строке `Host:` запроса. ТСПУ (Технические средства противодействия угрозам — оборудование [[DPI/DPI|DPI]], то есть глубокой инспекции трафика, которое стоит у провайдера) ищет это имя в первом пакете соединения и по нему решает, что делать с соединением дальше.
|
||
|
||
HTTP-запросы и TLS-соединения передаются по протоколу TCP, а TCP отправляет данные кусками — сегментами. У каждого байта в соединении есть порядковый номер (sequence number, коротко seq), и сервер раскладывает принятые куски в свой буфер по этим номерам. Если сервер примет чужие данные на те номера, где должен лежать настоящий запрос, поток развалится: настоящий ClientHello придёт с пересекающимися номерами, и, как описано в нюансе [[#2. Без fooling фейк бесполезен или вреден|«Без fooling фейк бесполезен или вреден»]], соединение оборвётся.
|
||
|
||
На этом строится `fake`. Движок Zapret 2 (`nfqws2`) перехватывает исходящий пакет с ClientHello или HTTP-запросом, а `fake` перед ним отправляет отдельный пакет-обманку — фейк, то есть заранее заготовленные данные с ложным содержимым, например ClientHello с безобидным именем `www.w3.org` вместо настоящего. Сам оригинал `fake` не трогает и не режет: он уходит следом как ни в чём не бывало. У функции нет вердикта, то есть она не приказывает выбросить перехваченный пакет, как это делают функции сегментации вроде [[Zapret2/desync/multisplit#Зачем нужен multisplit|multisplit]]. Отсюда порядок: сначала фейк, потом настоящий запрос. Данные для фейка берутся из аргумента `blob`. Blob — это заранее заготовленный набор байт с именем; у Zapret 2 есть три готовых, `fake_default_tls`, `fake_default_http` и `fake_default_quic` (что внутри, разобрано в разделе [[#Стандартные blob-ы|Стандартные blob-ы]]). Аргумент `blob` у `fake` обязателен: без него функция завершается ошибкой и молча шаг не пропускает ([[#5. blob обязателен — без optional будет Lua exception|нюанс 5]]).
|
||
|
||
Главное, что нужно понять о `fake`: фейк должен дойти до DPI, но не быть принят сервером. Если сервер примет его за настоящие данные, соединение сломается, как описано выше. Поэтому фейк намеренно портят: меняют его служебные поля (заголовки) так, чтобы сервер или промежуточные маршрутизаторы его отбросили, а DPI, по замыслу, всё равно прочитал. Такая порча называется fooling («одурачивание»); что это и зачем, разобрано в заметке [[ts-and-fooling]], в разделе [[Zapret2/ts-and-fooling#Что такое fooling|Что такое fooling]]. Два самых частых способа. `tcp_md5` добавляет к TCP-заголовку фейка опцию с подписью MD5: серверы на Linux отбрасывают такие пакеты, если MD5-аутентификация у них не настроена. `ip_ttl=1` (для IPv6 — `ip6_ttl=1`) задаёт пакету TTL — предельное число промежуточных узлов, через которые он пройдёт; при значении 1 пакет умирает уже на первом хопе (хоп — один переход между узлами сети), поэтому до сервера не доходит, а DPI его увидит, если стоит ближе к клиенту, чем сервер. Есть и другие способы: испорченная контрольная сумма (`badsum`), неверный номер seq и так далее. Все они собраны в разделе [[#D) Standard fooling|D) Standard fooling]], а выбор под конкретную среду разобран в [[Zapret2/ts-and-fooling#Как заставить fake умереть: каталог способов|каталоге способов]].
|
||
|
||
В итоге сервер получает правильные данные, а DPI сначала видит ложные. Фейк сервер должен отбросить из-за порчи, а принять только настоящий запрос и ответить как обычно; если порча не сработала и сервер принял фейк, соединение может сломаться (нюанс 2 ниже). DPI читает фейк первым и может принять решение по нему: пропустить соединение из-за безобидного SNI, потерять состояние потока из-за невалидных данных или не суметь заблокировать, потому что в фейке другое имя (подробно — в разделе [[#Зачем нужен fake|Зачем нужен fake]]). Гарантий нет: это лишь возможные исходы.
|
||
|
||
Команда из быстрого старта (`fake:blob=fake_default_tls:tcp_md5`) сначала отправляет фейковый ClientHello с именем `www.w3.org`, а следом уходит оригинал с `youtube.com`; оба занимают одни и те же позиции потока. ТСПУ (система DPI на стороне провайдера) читает фейк первым, и один из возможных исходов — решение по соединению принимается по нему. Сервер фейк отбрасывает: в пакете испорчена подпись TCP MD5. Как читать схему: строки — пакеты в порядке отправки, подписанные в тех же обозначениях, что и таблицы в этой статье; по горизонтали — место данных в TCP-потоке (номер последовательности, seq); в колонке справа — что сделал с пакетом сервер; внизу — буфер сервера, в который принятые куски встают по своим seq.
|
||
|
||
![[desync-anim-fake.svg|Анимация fake: фейковый ClientHello уходит перед оригиналом на те же позиции потока, сервер отбрасывает фейк]]
|
||
|
||
Минимальная команда для HTTPS — первая из [[#Быстрый старт|Быстрого старта]]. `--payload=tls_client_hello` значит «срабатывать только на TLS ClientHello», `blob=fake_default_tls` выбирает, какой фейк отправить, а `tcp_md5` портит его так, чтобы сервер отбросил:
|
||
|
||
```bash
|
||
--payload=tls_client_hello --lua-desync=fake:blob=fake_default_tls:tcp_md5
|
||
```
|
||
|
||
Для HTTP меняются только тип данных и blob: `--payload=http_req` и `fake_default_http`. `fake` работает и с UDP, а значит, с QUIC — протоколом на основе UDP, у которого тоже есть первый пакет (QUIC Initial), где DPI ищет сигнатуры, то есть заранее известные строки. У UDP нет сквозной нумерации байтов и TCP-опций (почему так, объяснено в нюансе [[Zapret2/desync/multisplit#1. Работает только с TCP — и почему|«Работает только с TCP»]] статьи про multisplit), поэтому TCP-fooling вроде `tcp_md5` для него бессмыслен. Вместо него берут IP-уровневые способы, в первую очередь `ip_ttl=1:ip6_ttl=1` ([[#6. Для UDP нет TCP-fooling|нюанс 6]]).
|
||
|
||
`fake` — «огонь по площадям»: он бросает в поток одну или несколько обманок и не трогает настоящий пакет. Поэтому его почти всегда ставят первым инстансом (одной записью `--lua-desync=…` в [[Zapret2/profile#Анатомия профиля|профиле]] — наборе правил Zapret 2 для определённого трафика), а следом — технику сегментации, например [[multisplit]]: фейк может сбить DPI, а нарезка — помешать ему найти имя в настоящем пакете ([[#8. Порядок инстансов: fake всегда первый|нюанс 8]]). Если одного фейка мало, может помочь `repeats=N`: некоторые DPI сбрасывают состояние после N-го пакета, поэтому серия фейков, например `repeats=11`, может оказаться эффективнее одного ([[#7. repeats может быть очень полезен|нюанс 7]]). Работает ли выбранная комбинация у вашего провайдера, проверяют по [[Zapret2/verify-strategy#Короткий чек-лист честной проверки|чек-листу честной проверки]].
|
||
|
||
У `fake` есть близкие соседи. [[Zapret2/desync/fakedsplit#Зачем нужен fakedsplit|fakedsplit]] и [[Zapret2/desync/fakeddisorder#Зачем нужен fakeddisorder|fakeddisorder]] замешивают фейки прямо между кусками настоящего запроса; `fakedsplit` заменяет связку fake + [[multisplit]], но ограничен одной позицией разреза. [[Zapret2/desync/syndata#Зачем нужен syndata|syndata]] кладёт данные уже в SYN — первый пакет рукопожатия (handshake), с которого TCP-соединение устанавливается. А скрытый фейк внутри настоящего сегмента дают `seqovl`: в [[Zapret2/desync/multisplit#seqovl — скрытый фейк внутри сегмента|multisplit]] для этого, по описанию в его статье, не приходится портить заголовки, а в [[Zapret2/desync/multidisorder#seqovl — перезапись буфера сокета через перекрытие|multidisorder]] тот же приём устроен иначе: фейк остаётся в буфере сокета сервера и затирается следующим сегментом. Все отличия сведены в таблицу в разделе [[#Сравнение с syndata и fakedsplit|Сравнение с syndata и fakedsplit]].
|
||
|
||
---
|
||
|
||
## Оглавление
|
||
|
||
- [Коротко и по-простому](#коротко-и-по-простому)
|
||
- [Справка: где функция в коде и родственники](#справка-где-функция-в-коде-и-родственники)
|
||
- [Зачем нужен fake](#зачем-нужен-fake)
|
||
- [Быстрый старт](#быстрый-старт)
|
||
- [Место в общем скелете](#место-в-общем-скелете)
|
||
- [blob — источник фейковых данных](#blob--источник-фейковых-данных)
|
||
- [Стандартные blob-ы](#стандартные-blob-ы)
|
||
- [Пользовательские blob-ы](#пользовательские-blob-ы)
|
||
- [tls_mod — модификации TLS в фейке](#tls_mod--модификации-tls-в-фейке)
|
||
- [Опции tls_mod](#опции-tls_mod)
|
||
- [Подстановка sni=%var](#подстановка-snivar)
|
||
- [Когда tls_mod применяется, а когда нет](#когда-tls_mod-применяется-а-когда-нет)
|
||
- [padencap — подробности](#padencap--подробности)
|
||
- [Полный список аргументов](#полный-список-аргументов)
|
||
- [A) Собственные аргументы fake](#a-собственные-аргументы-fake)
|
||
- [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)
|
||
- [Автосегментация по MSS](#автосегментация-по-mss)
|
||
- [Поведение при replay / reasm](#поведение-при-replay--reasm)
|
||
- [Псевдокод алгоритма](#псевдокод-алгоритма)
|
||
- [Сравнение с syndata и fakedsplit](#сравнение-с-syndata-и-fakedsplit)
|
||
- [Нюансы и подводные камни](#нюансы-и-подводные-камни)
|
||
- [Миграция с nfqws1](#миграция-с-nfqws1)
|
||
- [Практические примеры](#практические-примеры)
|
||
- [📚 См. также](#-см-также)
|
||
|
||
---
|
||
|
||
## Справка: где функция в коде и родственники
|
||
|
||
Паспорт функции для тех, кто сверяется с исходниками zapret2: в каком файле и на какой строке лежит код, какой ключ первой версии zapret она заменяет и как объявлена.
|
||
|
||
**Файл:** `lua/zapret-antidpi.lua:449`
|
||
**nfqws1 эквивалент:** `--dpi-desync=fake`
|
||
**Сигнатура:** `function fake(ctx, desync)`
|
||
|
||
`fake` — самая часто используемая функция в zapret. Она отправляет **отдельный** пакет (или группу пакетов) с фейковым payload из указанного blob. При этом функция **не выносит вердикт** и **не блокирует** отправку оригинала — оригинальный пакет уходит следом. DPI видит сначала фейк, затем настоящий трафик. Задача фейка — "отравить" состояние DPI ложными данными (неверный SNI, невалидный HTTP-запрос и т.д.).
|
||
|
||
Работает с **TCP и UDP** (в отличие от функций сегментации, которые только TCP).
|
||
|
||
> [!note] Проще говоря
|
||
> Payload — полезные данные пакета без сетевых заголовков: сам ClientHello, HTTP-запрос или первый пакет QUIC. Blob — заранее заготовленные данные, которые `fake` отправляет вместо настоящих. «Отравить состояние DPI» значит подсунуть ему ложные данные, по которым он сделает неверный вывод о соединении. Вердикт — решение «перехваченный пакет не отправлять»; у `fake` его нет, поэтому оригинал уходит следом, как описано в [[Zapret2/жизненный цикл desync-функции#Стадия 8. Вердикт и его агрегация|стадии 8 жизненного цикла]].
|
||
|
||
Родственные функции: [[syndata]] (payload в SYN), [[fakedsplit]] (фейки + сегментация), [[fakeddisorder]] (фейки + обратный порядок), [[multisplit]] (чистая сегментация), [[multidisorder]] (сегментация в обратном порядке).
|
||
|
||
Общий для всех техник дурения порядок работы — восемь стадий от отсева чужого транспорта до вердикта — разобран в [[жизненный цикл desync-функции]]; здесь описано только то, чем `fake` от этого скелета отличается.
|
||
|
||
---
|
||
|
||
## Зачем нужен fake
|
||
|
||
[[DPI/DPI|DPI]] анализирует первые пакеты TCP/UDP-потока, ища сигнатуры (SNI в TLS ClientHello, Host в HTTP, QUIC Initial). Сигнатура здесь — заранее известная строка, по которой DPI узнаёт сайт. Если **перед** настоящим пакетом отправить фейковый пакет с ложными данными, DPI может:
|
||
|
||
1. **Принять фейк за реальный трафик:** DPI обработает фейковый SNI/Host и примет решение на его основе — пропустит соединение
|
||
2. **Сбиться с состояния:** получив невалидные данные, DPI потеряет контекст потока и перестанет его анализировать
|
||
3. **Не суметь заблокировать:** если DPI блокирует по hostname, а в фейке другой hostname — реальный запрос может пройти
|
||
|
||
При этом **сервер должен отбросить фейк**. Для этого к фейку применяется [[Zapret2/ts-and-fooling#Что такое fooling|fooling]] — порча заголовков (TTL, badseq, md5sig, badsum), из-за которой сервер или промежуточные маршрутизаторы отбрасывают пакет, а DPI — нет.
|
||
|
||
**fake** — "огонь по площадям": он шлёт фейк отдельным пакетом, не трогая оригинал. Для более тонкой работы (замешивание фейков внутри сегментов) используйте [[fakedsplit]]/[[fakeddisorder]], для скрытых фейков через TCP window — [[Zapret2/desync/multisplit#seqovl — скрытый фейк внутри сегмента|seqovl]] в [[multisplit]]/[[multidisorder]].
|
||
|
||
> [!note] Проще говоря
|
||
> `fake` заранее показывает DPI ложную картину: другое имя сайта или бессмысленные данные. Сервер эту картину не видит, потому что фейк специально испорчен, и получает только настоящий запрос. TCP window (окно приёма) — диапазон номеров байт, которые получатель готов принять; скрытые фейки, которые строятся на приёме и отбрасывании байт, `fake` не делает, это работа `seqovl` (в multisplit фейк оказывается левее окна приёма и сервер его выбрасывает, в multidisorder — иначе, как сказано в начале статьи). Как испортить фейк правильно, зависит от того, где стоит DPI и что стоит между вами и сервером: разбор — в заметке [[ts-and-fooling]].
|
||
|
||
---
|
||
|
||
## Быстрый старт
|
||
|
||
Ниже четыре готовые строки для [[Zapret2/profile#Анатомия профиля|профиля]] Zapret 2, от минимальных вариантов к боевой связке. Флаг `--payload=…` работает как фильтр для всех вызовов `--lua-desync`, которые идут после него (до следующего `--payload` или до конца профиля): они срабатывают только на данных указанного типа. Поэтому `--payload` пишут перед `--lua-desync` (подробно — в [[последовательность аргументов]]; типы данных описаны в заметке [[Zapret2/payload#Что такое тип payload (и чем он отличается от протокола потока)|о типах payload]]).
|
||
|
||
Минимальный TLS-фейк (обязателен `blob` + fooling):
|
||
|
||
```bash
|
||
--payload=tls_client_hello --lua-desync=fake:blob=fake_default_tls:tcp_md5
|
||
```
|
||
|
||
Сервер отбросит такой фейк из-за TCP MD5 option. `fake_default_tls` — один из стандартных blob-ов (что в нём, разобрано в разделе [[#Стандартные blob-ы|Стандартные blob-ы]]).
|
||
|
||
Минимальный HTTP-фейк:
|
||
|
||
```bash
|
||
--payload=http_req --lua-desync=fake:blob=fake_default_http:tcp_md5
|
||
```
|
||
|
||
То же для HTTP: другой тип данных и другой стандартный blob.
|
||
|
||
QUIC-фейк (UDP):
|
||
|
||
```bash
|
||
--payload=quic_initial --lua-desync=fake:blob=fake_default_quic:ip_ttl=1:ip6_ttl=1
|
||
```
|
||
|
||
Для UDP TCP-fooling неприменим, поэтому фейк ограничен по TTL (подробно — в нюансе [[#6. Для UDP нет TCP-fooling|«Для UDP нет TCP-fooling»]]).
|
||
|
||
Типовая боевая связка fake + [[multisplit]]:
|
||
|
||
```bash
|
||
--payload=tls_client_hello \
|
||
--lua-desync=fake:blob=fake_default_tls:tcp_md5:tls_mod=rnd,rndsni,dupsid,padencap \
|
||
--lua-desync=multisplit:pos=1,midsld
|
||
```
|
||
|
||
Фейк уходит первым, а следом [[multisplit]] режет настоящий ClientHello после первого байта и посередине домена второго уровня (маркеры `pos` разобраны в разделе [[Zapret2/desync/multisplit#Маркеры позиций (pos)|Маркеры позиций (pos)]]). Набор `tls_mod=…` меняет содержимое самого фейка, см. раздел [[#tls_mod — модификации TLS в фейке|tls_mod]].
|
||
|
||
---
|
||
|
||
## Место в общем скелете
|
||
|
||
Тело `fake` построено по тому же шаблону, что и все остальные функции дурения: восемь стадий от отсева чужого транспорта до вердикта. Разобраны они один раз в [[жизненный цикл desync-функции]] — здесь только отклонения, и их у `fake` больше, чем у прочих техник. Несколько слов из таблицы. Cutoff (отсечение) значит, что движок больше не будет вызывать функцию на пакетах этого потока или направления. Гвард — проверка «работать ли с этим пакетом». Replay (перепроигрывание) — повторный вызов функций на придержанных частях многопакетного запроса. Вердикт — решение движка, что сделать с перехваченным пакетом.
|
||
|
||
| Стадия общего скелета | Что делает `fake` |
|
||
|:----------------------|:------------------|
|
||
| 1. Отсев транспорта | **исключение из правила**: работает и с TCP, и с UDP, поэтому `instance_cutoff` не делает вовсе — просто условие `if (desync.dis.tcp or desync.dis.udp)` |
|
||
| 2. Направление | `dir=out` по умолчанию, отключается от входящего |
|
||
| 3. Аргументы | `blob` **обязателен** — без него `error()`; с флагом `optional` отсутствующий blob даёт тихий выход |
|
||
| 4. Данные | **не использует цепочку** `blob → reasm → payload`: всегда шлёт содержимое своего `blob`, а `reasm_data` нужен лишь как образец для `tls_mod` |
|
||
| 5. Гварды | штатные `direction_check` и `payload_check` (по умолчанию `known`) |
|
||
| 6. replay | штатный `replay_first`: фейк уходит один раз, на первой части многопакетного запроса |
|
||
| 7. **Своя техника** | загрузить blob, при необходимости применить `tls_mod`, отправить `rawsend_payload_segmented` |
|
||
| 8. Вердикт | **не выносит никакого** — оригинал уходит следом за фейком как ни в чём не бывало |
|
||
|
||
Две последние строки таблицы и объясняют, почему `fake` комбинируется с чем угодно: он ничего не дропает и ничего не модифицирует, а просто добавляет в поток лишний пакет перед настоящим. Поэтому в профиле его почти всегда ставят первым инстансом, а следом — технику сегментации вроде [[multisplit]].
|
||
|
||
> [!note] Проще говоря
|
||
> Почти каждая функция дурения проходит одни и те же восемь шагов, а `fake` от этого шаблона отличается тем, что берёт данные из своего `blob`, не выносит вердикт и умеет работать и с TCP, и с UDP.
|
||
|
||
Каждую стадию по отдельности разбирает жизненный цикл: [[Zapret2/жизненный цикл desync-функции#Стадия 1. Отсев чужого транспорта и instance cutoff|стадия 1]] (транспорт), [[Zapret2/жизненный цикл desync-функции#Стадия 2. Отсечение противоположного направления|стадия 2]] (направление), [[Zapret2/жизненный цикл desync-функции#Стадия 3. Ранняя проверка аргументов|стадия 3]] (аргументы), [[Zapret2/жизненный цикл desync-функции#Стадия 4. Выбор данных: blob → reasm → payload|стадия 4]] (данные), [[Zapret2/жизненный цикл desync-функции#Стадия 5. Три гварда|стадия 5]] (гварды), [[Zapret2/жизненный цикл desync-функции#Стадия 6. Развилка перепроигрывания (replay)|стадия 6]] (replay), [[Zapret2/жизненный цикл desync-функции#Стадия 7. Собственно техника|стадия 7]] (своя техника) и [[Zapret2/жизненный цикл desync-функции#Стадия 8. Вердикт и его агрегация|стадия 8]] (вердикт).
|
||
|
||
---
|
||
|
||
## blob — источник фейковых данных
|
||
|
||
`blob` — обязательный аргумент `fake`. Он указывает, **что** именно отправить в качестве фейкового payload. Blob — заранее заготовленный набор байт с именем; как их объявлять и что в них можно положить, разобрано в заметке [[blob]], а здесь описано только то, что нужно для `fake`.
|
||
|
||
### Стандартные blob-ы
|
||
|
||
Zapret автоматически создаёт три стандартных blob-а при инициализации. Таблица показывает, какой из них к какому типу данных подходит; тип данных задаёт `--payload=…` в [[Zapret2/profile#Анатомия профиля|профиле]]:
|
||
|
||
| Blob | Описание | Типичное использование |
|
||
|:-----|:---------|:-----------------------|
|
||
| `fake_default_tls` | Валидный TLS ClientHello с SNI `www.w3.org` | `--payload=tls_client_hello` |
|
||
| `fake_default_http` | Валидный HTTP GET запрос | `--payload=http_req` |
|
||
| `fake_default_quic` | QUIC Initial пакет | `--payload=quic_initial` |
|
||
|
||
Эти blob-ы содержат полноценные протокольные структуры, которые DPI может распознать и обработать. Именно поэтому `fake_default_tls` — самый частый выбор для TLS-фейков: DPI парсит его как настоящий ClientHello, видит `www.w3.org` вместо заблокированного домена.
|
||
|
||
> [!note] Проще говоря
|
||
> Стандартный blob — это готовый «пример запроса» с безобидным содержимым. `fake` отправляет его как есть, а DPI разбирает его так же, как настоящий.
|
||
|
||
### Пользовательские blob-ы
|
||
|
||
Свой blob можно задать несколько способами: прямо в команде шестнадцатеричной строкой (inline hex), загрузить из файла, взять из Lua-переменной, в том числе созданной другой функцией. Примеры:
|
||
|
||
```bash
|
||
# Inline hex (произвольные байты)
|
||
--lua-desync=fake:blob=0xDEADBEEF:tcp_md5
|
||
|
||
# Нулевые байты (4 байта нулей)
|
||
--lua-desync=fake:blob=0x00000000:ip_ttl=6:ip6_ttl=6
|
||
|
||
# Из файла (предзагруженный)
|
||
--blob=my_fake_ch:@/path/to/custom_clienthello.bin
|
||
--lua-desync=fake:blob=my_fake_ch:tcp_md5
|
||
|
||
# Из Lua-переменной (например, клонированный ClientHello)
|
||
--lua-desync=tls_client_hello_clone:blob=cloned_ch:sni_del:sni_add=www.google.com
|
||
--lua-desync=fake:blob=cloned_ch:tcp_md5
|
||
```
|
||
|
||
Blob разрешается функцией `blob_exist()` / `blob()` в следующем порядке:
|
||
|
||
1. Если имя начинается с `0x` — inline hex, создаётся на лету
|
||
2. `desync[name]` — поле в текущем контексте desync (например, сгенерированное `tls_client_hello_clone`)
|
||
3. `_G[name]` — глобальная Lua-переменная (например, `fake_default_tls`)
|
||
|
||
> [!note] Проще говоря
|
||
> Сначала смотрится, не hex ли записан прямо в аргументе, потом — не создал ли имя предыдущий инстанс в текущем контексте `desync` (устройство таблицы — в [[структура desync и диссекта]]), и в последнюю очередь — среди глобальных переменных Lua. Если имя не нашлось нигде, `fake` завершится ошибкой, а с флагом `optional` тихо пропустит шаг ([[#5. blob обязателен — без optional будет Lua exception|нюанс 5]]).
|
||
|
||
---
|
||
|
||
## tls_mod — модификации TLS в фейке
|
||
|
||
`tls_mod` позволяет модифицировать содержимое blob-а перед отправкой, подстраивая фейковый ClientHello под текущее соединение. Это делает фейк более убедительным для DPI. Среди полей ClientHello есть случайные 32 байта (`Random`), идентификатор сессии (`Session ID`) и набор расширений (extensions), среди которых SNI с именем сайта и padding — заполнитель. Опции ниже меняют эти поля blob-а перед отправкой; остальные модификации TLS-блобов описаны в заметке [[blob]].
|
||
|
||
![[desync-anim-hub-tlsmod.svg|Анимация: что меняют опции tls_mod rnd, rndsni, sni=, dupsid и padencap в фейковом ClientHello]]
|
||
|
||
### Опции tls_mod
|
||
|
||
| Опция | Описание | Требования |
|
||
| :------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :------------------------------------------------ |
|
||
| `none` | Ничего не делать | — |
|
||
| `rnd` | Заполнить поля `Random` (32 байта) и `Session ID` случайными данными | blob должен содержать валидный TLS ClientHello |
|
||
| `rndsni` | Заменить SNI на случайный домен. Если длина оригинального SNI >= 7 символов — случайный поддомен из известных 3-буквенных TLD. Иначе — случайные символы `[a-z][a-z0-9]*` | blob должен содержать SNI extension |
|
||
| `sni=<domain>` | Заменить SNI на конкретный домен (изменяет длины внутри TLS-структур) | blob должен содержать SNI extension |
|
||
| `dupsid` | Скопировать Session ID из **оригинального** payload (из `desync.reasm_data`) в фейк. Выполняется после `rnd`. Требует совпадения длин session id | валидный TLS в `reasm_data` |
|
||
| `padencap` | Подкорректировать blob так, чтобы оригинальный payload стал частью padding extension. Увеличивает поля длины TLS record/handshake/extensions/padding на `len(original_payload)` | blob должен содержать padding extension (type 21) |
|
||
|
||
**Порядок применения модов:** они применяются в порядке перечисления, но `dupsid` всегда выполняется после `rnd` (чтобы рандомизированный Session ID был перезаписан реальным).
|
||
|
||
> [!note] Проще говоря
|
||
> `rnd` делает случайными служебные поля фейка, `rndsni` и `sni=` подменяют имя сайта в нём, `dupsid` копирует идентификатор сессии из настоящего запроса, а `padencap` готовит фейк так, чтобы настоящий запрос выглядел его продолжением (подробности — [[#padencap — подробности|ниже]]). Образцом для `dupsid` и `padencap` служит настоящий запрос, собранный движком, — `desync.reasm_data`; что такое reasm, объяснено в разделе [[Zapret2/структура desync и диссекта#Приём многопакетных пейлоадов (reasm / decrypt / replay)|Приём многопакетных пейлоадов]].
|
||
|
||
### Подстановка sni=%var
|
||
|
||
Внутри `tls_mod` поддерживается специальная запись `sni=%variable`: вместо готового домена в SNI подставляется значение переменной. Значение `desync.target` устанавливается механизмом hostlist (списки доменов профиля, см. [[Zapret2/filter#Списки IP и доменов|Списки IP и доменов]]).
|
||
|
||
```bash
|
||
# Подстановка из desync.target (устанавливается механизмом hostlist)
|
||
--lua-desync=fake:blob=fake_default_tls:tcp_md5:tls_mod=sni=%target
|
||
|
||
# Подстановка из глобальной Lua-переменной
|
||
--lua-init="my_domain='www.google.com'" \
|
||
--lua-desync=fake:blob=fake_default_tls:tcp_md5:tls_mod=sni=%my_domain
|
||
```
|
||
|
||
Порядок поиска переменной:
|
||
1. `desync[var]` — поле в текущем контексте desync
|
||
2. `_G[var]` — глобальная Lua-переменная
|
||
|
||
Если переменная не найдена — вызывается `error("tls_mod_shim: non-existent var 'varname'")`.
|
||
|
||
### Когда tls_mod применяется, а когда нет
|
||
|
||
В `fake` tls_mod вызывается **только если одновременно выполнены оба условия:**
|
||
|
||
1. `desync.reasm_data` существует (обычно есть при TLS ClientHello, который был реассемблирован)
|
||
2. Аргумент `tls_mod` задан
|
||
|
||
Reasm (reasm_data) — запрос, собранный движком из нескольких пакетов; для `tls_mod` он служит образцом настоящего ClientHello.
|
||
|
||
Если `reasm_data` отсутствует (например, маленький пакет, не потребовавший реассемблирования, или UDP) — `tls_mod` **молча пропускается**, без ошибок. Это отличие от [[syndata]], где `tls_mod` вызывается всегда (с `payload=nil`), потому что syndata работает на SYN-пакете, где никакого реального payload ещё нет.
|
||
|
||
> [!note] Проще говоря
|
||
> Нет образца настоящего запроса — модификации молча не применяются, и фейк уходит таким, каким лежит в blob-е.
|
||
|
||
**Обходной путь**, если tls_mod нужен без reasm_data:
|
||
|
||
```bash
|
||
# Заранее модифицировать blob через lua-init
|
||
--lua-init="fake_default_tls=tls_mod(fake_default_tls,'rnd,rndsni')"
|
||
```
|
||
|
||
### padencap — подробности
|
||
|
||
`padencap` — техника, при которой фейковый blob подготавливается так, чтобы **реальный payload**, отправленный следом, воспринимался DPI как продолжение padding extension в фейковом ClientHello. DPI, парсящий TLS, может объединить фейк и оригинал в один record, и реальный SNI окажется "внутри" padding — невидим для анализа.
|
||
|
||
Для этого в blob должна присутствовать padding extension (type 0x0015), а `padencap` увеличивает все поля длины (TLS record length, Handshake length, Extensions length, Padding extension length) на `len(original_payload)`.
|
||
|
||
> [!note] Проще говоря
|
||
> Фейк заранее объявляет: «моё поле-заполнитель длиннее, чем кажется». Настоящий ClientHello, который придёт следом, DPI может принять за продолжение этого заполнителя, и тогда настоящий SNI останется незамеченным. Ограничения этого трюка — в нюансе [[#10. padencap + реальный payload — тонкий трюк|10]].
|
||
|
||
---
|
||
|
||
## Полный список аргументов
|
||
|
||
Аргументы делятся на собственные аргументы `fake` (раздел A) и стандартные (разделы B–H): их понимают и другие функции дурения, а общий обзор есть в [[desync]]. Формат вызова:
|
||
|
||
```
|
||
--lua-desync=fake[:arg1[=val1][:arg2[=val2]]...]
|
||
```
|
||
|
||
Все `val` приходят в Lua как строки. Если `=val` не указан, значение = пустая строка `""` (в Lua это truthy), поэтому флаги пишутся просто как `:optional`, `:tcp_md5`, `:badsum`.
|
||
|
||
### A) Собственные аргументы fake
|
||
|
||
#### `blob` (обязательный)
|
||
|
||
- **Формат:** `blob=<blobName>`
|
||
- **Тип:** имя blob-переменной (загружается через `--blob=<name>:@file|0xHEX`, через `desync[name]` или как глобальная Lua-переменная)
|
||
- **По умолчанию:** нет (обязательный аргумент)
|
||
- **Описание:** Blob, содержащий фейковый payload. Может быть любой длины — для TCP сегментация по MSS выполняется автоматически. Для UDP отправляется как есть
|
||
- **Ошибка:** если `blob` не указан, вызывается `error("fake: 'blob' arg required")` — Lua exception, останавливающий обработку пакета
|
||
- **Примеры:**
|
||
- `blob=fake_default_tls` — стандартный TLS-фейк
|
||
- `blob=fake_default_http` — стандартный HTTP-фейк
|
||
- `blob=fake_default_quic` — стандартный QUIC-фейк
|
||
- `blob=0xDEADBEEF` — inline hex
|
||
- `blob=0x00000000` — четыре нулевых байта
|
||
- `blob=my_custom_blob` — предзагруженный или сгенерированный blob
|
||
|
||
Проще говоря: `blob` — единственный аргумент, без которого `fake` не работает. Как он ищется, описано в разделе [[#blob — источник фейковых данных|blob — источник фейковых данных]].
|
||
|
||
#### `optional`
|
||
|
||
- **Формат:** `optional` (флаг, без значения)
|
||
- **Описание:** Если blob отсутствует (не найден ни как inline hex, ни как `desync[name]`, ни как `_G[name]`) — тихий пропуск без ошибки. Без `optional` отсутствие blob-а вызывает `error()`
|
||
- **Использование:** защита от ошибок при использовании blob-ов, которые могут отсутствовать (например, генерируемых `tls_client_hello_clone` — если payload не TLS, clone не создаст blob)
|
||
|
||
Проще говоря: без `optional` отсутствие blob-а останавливает обработку пакета ошибкой, с `optional` `fake` просто ничего не делает ([[#5. blob обязателен — без optional будет Lua exception|нюанс 5]]).
|
||
|
||
#### `tls_mod`
|
||
|
||
- **Формат:** `tls_mod=<commaSeparatedList>`
|
||
- **Тип:** строка вида `opt1,opt2,...`
|
||
- **По умолчанию:** не задан (модификации не применяются)
|
||
- **Описание:** Список TLS-модификаций, применяемых к blob перед отправкой. Работает только при наличии `desync.reasm_data`
|
||
- **Опции:** `none`, `rnd`, `rndsni`, `sni=<domain>`, `dupsid`, `padencap`
|
||
- **Подстановка:** `sni=%variable` — подстановка из `desync[var]` или `_G[var]`
|
||
- **Примеры:**
|
||
- `tls_mod=rnd` — рандомизировать Random и Session ID
|
||
- `tls_mod=rnd,rndsni,dupsid` — рандомизировать + случайный SNI + скопировать реальный Session ID
|
||
- `tls_mod=rnd,rndsni,dupsid,padencap` — полный набор модификаций
|
||
- `tls_mod=sni=www.google.com` — конкретный домен в SNI
|
||
- `tls_mod=sni=%target` — подстановка из переменной target
|
||
|
||
Каждая опция разобрана в разделе [[#tls_mod — модификации TLS в фейке|tls_mod — модификации TLS в фейке]].
|
||
|
||
---
|
||
|
||
### B) Standard direction
|
||
|
||
Направление говорит, в какую сторону идёт пакет: от вашего компьютера к серверу (исходящий) или обратно (входящий).
|
||
|
||
| Параметр | Значения | По умолчанию |
|
||
|:---------|:---------|:-------------|
|
||
| `dir` | `in`, `out`, `any` | `out` |
|
||
|
||
Фильтр по направлению пакета. `fake` по умолчанию работает только с исходящими (`out`).
|
||
|
||
- `dir=out` — только исходящие (от клиента к серверу)
|
||
- `dir=in` — только входящие (от сервера к клиенту)
|
||
- `dir=any` — оба направления
|
||
|
||
При первом вызове с указанным `dir` функция делает `direction_cutoff_opposite` — отсекает себя от противоположного направления. Cutoff (отсечение) значит, что движок больше не будет вызывать функцию на пакетах этого направления в текущем соединении; подробно — в [[Zapret2/жизненный цикл desync-функции#Стадия 2. Отсечение противоположного направления|стадии 2 жизненного цикла]].
|
||
|
||
---
|
||
|
||
### C) Standard payload
|
||
|
||
Здесь фильтр — по [[Zapret2/payload#Что такое тип payload (и чем он отличается от протокола потока)|типу payload]], то есть по названию распознанного протокола (`tls_client_hello`, `http_req`, `quic_initial`).
|
||
|
||
| Параметр | Значения | По умолчанию |
|
||
|:---------|:---------|:-------------|
|
||
| `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-фильтр.
|
||
|
||
Проще говоря: фильтр `--payload=` на уровне профиля работает в быстром ядре программы, написанном на C, а аргумент `payload=` проверяется уже в Lua, то есть медленнее. Поэтому основной отбор лучше делать на уровне профиля.
|
||
|
||
---
|
||
|
||
### D) Standard fooling
|
||
|
||
Fooling — намеренная порча заголовков пакета, обычно для того, чтобы сервер отбросил фейк, а DPI его прочитал (подробно — [[Zapret2/ts-and-fooling#Что такое fooling|Что такое fooling]]). Здесь это модификации L3/L4 заголовков, то есть заголовков IP (сетевой уровень) и TCP (транспортный уровень). В `fake` fooling применяется **только к фейковым пакетам** (а не к оригиналу — тот уходит без изменений). Это ключевое отличие от [[multisplit]], где 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` |
|
||
|
||
**Типичные комбинации fooling для fake:**
|
||
|
||
- `tcp_md5` — самый популярный. Серверы (Linux) отбрасывают пакеты с TCP MD5 option, если MD5-аутентификация не настроена
|
||
- `ip_ttl=1:ip6_ttl=1` — TTL=1: фейк не дойдёт до сервера, но DPI на пути его увидит
|
||
- `badsum` — испорченная контрольная сумма: сервер отбросит, DPI может пропустить
|
||
- `tcp_flags_unset=ACK` — datanoack: убрать ACK-флаг, сервер отбросит пакет без ACK в установленном соединении
|
||
- `tcp_seq=-10000` — badseq: невалидный sequence number, сервер отбросит
|
||
|
||
> [!note] Проще говоря
|
||
> Все опции таблицы — способы сделать фейк «неправильным» в одном из мест: время жизни пакета (`ip_ttl`), номера seq и ack, TCP-опции (`tcp_md5`, `tcp_ts`), флаги, контрольная сумма (`badsum`, раздел G). Какая опция сработает, зависит от среды: почему у каждой свой «слой смерти» и где она ломается, описано в [[Zapret2/ts-and-fooling#Как заставить fake умереть: каталог способов|каталоге способов]].
|
||
|
||
---
|
||
|
||
### 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` применяется к **каждому** отправляемому пакету (включая под-сегменты при MSS-сегментации для TCP, см. [[#Автосегментация по MSS|Автосегментация по MSS]]).
|
||
|
||
---
|
||
|
||
### F) Standard ipfrag
|
||
|
||
IP-фрагментация фейковых пакетов. Каждый пакет дополнительно фрагментируется на уровне IP.
|
||
|
||
Проще говоря: пакет-фейк при отправке ещё раз делится на части, но уже средствами протокола IP, а собирает их обратно получатель на уровне IP.
|
||
|
||
| Параметр | Описание | По умолчанию |
|
||
|:---------|:---------|:-------------|
|
||
| `ipfrag[=func]` | Включить IP-фрагментацию. Если без значения — `ipfrag2` | — |
|
||
| `ipfrag_disorder` | Отправить IP-фрагменты в обратном порядке | — |
|
||
| `ipfrag_pos_tcp=N` | Позиция фрагментации TCP (кратно 8) | `32` |
|
||
| `ipfrag_pos_udp=N` | Позиция фрагментации UDP (кратно 8). Актуально для QUIC-фейков | `8` |
|
||
| `ipfrag_next=N` | IPv6: next protocol во 2-м фрагменте (penetration атака на фаерволы) | — |
|
||
|
||
---
|
||
|
||
### G) Standard reconstruct
|
||
|
||
Реконструкция — сборка готового raw-пакета («сырого», со всеми заголовками) перед отправкой.
|
||
|
||
| Параметр | Описание |
|
||
|:---------|:---------|
|
||
| `badsum` | Испортить L4 (TCP/UDP) checksum при реконструкции raw-пакета. Сервер отбросит такой пакет |
|
||
|
||
---
|
||
|
||
### H) Standard rawsend
|
||
|
||
Rawsend — отправка готовых пакетов в сеть самой функцией; в `fake` её выполняет `rawsend_payload_segmented` (см. [[#Автосегментация по MSS|Автосегментация по MSS]]). Эти параметры управляют отправкой.
|
||
|
||
| Параметр | Описание |
|
||
|:---------|:---------|
|
||
| `repeats=N` | Отправить каждый пакет/сегмент N раз (идентичные повторы) |
|
||
| `ifout=<iface>` | Интерфейс для отправки (по умолчанию определяется автоматически) |
|
||
| `fwmark=N` | Firewall mark (только Linux, nftables/iptables) |
|
||
|
||
---
|
||
|
||
## Автосегментация по MSS
|
||
|
||
![[desync-anim-hub-mss.svg|Анимация: кусок данных больше MSS автоматически режется на под-сегменты с растущим seq]]
|
||
|
||
MSS (Maximum Segment Size) — наибольший объём данных, который помещается в один TCP-сегмент данного соединения. Для TCP о размерах пакетов думать **не нужно**. Функция `rawsend_payload_segmented` из `zapret-lib.lua` автоматически:
|
||
|
||
1. Отслеживает MSS для каждого TCP-соединения
|
||
2. Если blob превышает MSS — автоматически режет по MSS
|
||
3. Каждый под-сегмент отправляется с корректным TCP sequence
|
||
|
||
**Пример:** blob из 10000 байт при MSS=1460 будет отправлен как 7 TCP-сегментов (6 x 1460 + 1 x 240).
|
||
|
||
> [!note] Проще говоря
|
||
> Даже длинный фейк можно не готовить заранее: функция сама нарежет его на пакеты допустимого размера и проставит каждому правильный seq.
|
||
|
||
Для UDP сегментации нет — blob отправляется как один UDP-пакет. Если blob больше MTU, пакет будет фрагментирован на уровне IP (или отброшен, если DF-бит установлен). MTU — наибольший размер пакета, который проходит по каналу без разбиения на части, а DF-бит (Don't Fragment) — флаг «не фрагментировать».
|
||
|
||
---
|
||
|
||
## Поведение при replay / reasm
|
||
|
||
Многопакетный запрос (тот, что не влез в один пакет) `nfqws2` придерживает, собирает в буфер `reasm_data` (reasm — повторная сборка) и перепроигрывает через desync-функции: replay (перепроигрывание) означает, что движок по очереди вызывает функции на каждой придержанной части. Механика описана в [[Zapret2/жизненный цикл desync-функции#Стадия 6. Развилка перепроигрывания (replay)|жизненный цикл desync-функции, стадия 6]]. `fake` использует из неё только половину: срабатывает на первой части (`replay_first`) и молчит на остальных, логируя «not acting on further replay pieces».
|
||
|
||
Вторую половину развилки — дроп последующих частей — `fake` не применяет, потому что ему нечего дропать: он не отправляет реальные данные, а лишь добавляет фейк. Поэтому все части replay проходят дальше по цепочке инстансов, и стоящая следом [[multisplit]] или [[multidisorder]] нарежет собранный реасм как обычно.
|
||
|
||
> [!note] Проще говоря
|
||
> Фейку хватает одного срабатывания на первой части запроса, а остальные части идут дальше нетронутыми: их обработает следующая функция в цепочке, например [[Zapret2/desync/multisplit#Поведение при replay / reasm|multisplit, который на первой части режет и отправляет весь собранный буфер]].
|
||
|
||
---
|
||
|
||
## Псевдокод алгоритма
|
||
|
||
Ниже — запись тела `fake` на Lua, чтобы видно было, в каком порядке функция проверяет условия и что отправляет. Тело функции целиком, включая общие для всех техник стадии — они пронумерованы так же, как в [[жизненный цикл desync-функции]]:
|
||
|
||
```lua
|
||
function fake(ctx, desync)
|
||
-- 1. Cutoff противоположного направления
|
||
direction_cutoff_opposite(ctx, desync)
|
||
|
||
-- 2. Проверка: только TCP или UDP
|
||
if not (desync.dis.tcp or desync.dis.udp) then return end
|
||
|
||
-- 3. Проверки: направление OK, payload OK
|
||
if not direction_check(desync) then return end
|
||
if not payload_check(desync) then return end
|
||
|
||
-- 4. Только первый replay
|
||
if replay_first(desync) then
|
||
|
||
-- 5. blob обязателен
|
||
if not desync.arg.blob then
|
||
error("fake: 'blob' arg required")
|
||
end
|
||
|
||
-- 6. optional: тихий пропуск если blob нет
|
||
if optional and not blob_exist(desync, desync.arg.blob) then
|
||
DLOG("fake: blob not found. skipped")
|
||
return -- НЕ error, просто return
|
||
end
|
||
|
||
-- 7. Загрузка blob
|
||
fake_payload = blob(desync, desync.arg.blob)
|
||
|
||
-- 8. tls_mod (только если есть reasm_data)
|
||
if desync.reasm_data and desync.arg.tls_mod then
|
||
fake_payload = tls_mod_shim(desync, fake_payload,
|
||
desync.arg.tls_mod,
|
||
desync.reasm_data)
|
||
end
|
||
|
||
-- 9. Отправка (с fooling, ipid, reconstruct, ipfrag, rawsend)
|
||
rawsend_payload_segmented(desync, fake_payload)
|
||
-- НЕ возвращает вердикт!
|
||
else
|
||
DLOG("fake: not acting on further replay pieces")
|
||
end
|
||
-- 10. Нет return VERDICT_DROP — оригинал уходит
|
||
end
|
||
```
|
||
|
||
**Ключевое отличие от [[multisplit]]**: multisplit возвращает `VERDICT_DROP` после успешной отправки (оригинал блокируется), а fake **ничего не возвращает** (оригинал проходит). Псевдокод самого `multisplit` — в разделе [[Zapret2/desync/multisplit#Псевдокод алгоритма|Псевдокод алгоритма]] его статьи.
|
||
|
||
> [!note] Проще говоря
|
||
> Функция проверяет транспорт, направление и тип данных, на первой части запроса берёт blob, при необходимости применяет `tls_mod`, отправляет результат и выходит, ничего не решая насчёт оригинала.
|
||
|
||
---
|
||
|
||
## Сравнение с syndata и fakedsplit
|
||
|
||
Таблица ниже сопоставляет `fake` с двумя ближайшими соседями. [[Zapret2/desync/syndata#Отличия от fake|syndata]] работает на SYN-пакете (это самый первый пакет соединения, с него начинается рукопожатие TCP), а [[Zapret2/desync/fakedsplit#Зачем нужен fakedsplit|fakedsplit]] сам режет payload и вставляет фейки между частями.
|
||
|
||
| Аспект | `fake` | `syndata` | `fakedsplit` |
|
||
|:-------|:-------|:----------|:-------------|
|
||
| Когда работает | На payload (после TCP handshake) | На SYN-пакете (до handshake) | На payload (после handshake) |
|
||
| Протоколы | TCP **и** UDP | Только TCP | Только TCP |
|
||
| Что делает | Шлёт отдельный фейковый пакет | Вкладывает payload в SYN | Режет payload + вставляет фейки между частями |
|
||
| Вердикт | **Нет** (оригинал проходит) | `VERDICT_DROP` (заменяет SYN) | `VERDICT_DROP` (заменяет оригинал) |
|
||
| blob обязателен | **Да** (error если нет) | Нет (дефолт: 16 нулевых байт) | Нет (фейки из `pattern`) |
|
||
| tls_mod условие | Нужен `reasm_data` | Всегда (payload=nil) | Нет tls_mod |
|
||
| fooling к чему | К фейковым пакетам | К SYN-пакету | Только к фейковым сегментам |
|
||
| Автосегментация | Да (TCP по MSS) | **Нет** (должен влезть в 1 пакет) | Да |
|
||
| Типичная позиция в цепочке | **Первый** (перед split) | **Самый первый** (на SYN) | Единственный (заменяет split) |
|
||
|
||
**Когда что использовать:**
|
||
|
||
- **fake** — когда нужен простой фейк перед реальным трафиком. Самый универсальный вариант, работает с TCP и UDP
|
||
- **syndata** — когда DPI анализирует уже SYN-пакет. Очень ранняя стадия, но ограничен размером одного пакета
|
||
- **fakedsplit** — когда нужно одновременно и нарезать, и подмешать фейки. Заменяет связку fake + [[multisplit]], но ограничен одной позицией разреза
|
||
|
||
Сравнение с сегментирующими функциями — в статьях [[Zapret2/desync/fakeddisorder#Зачем нужен fakeddisorder|fakeddisorder]] (фейки + обратный порядок) и [[multisplit]] (чистая нарезка без фейков).
|
||
|
||
---
|
||
|
||
## Нюансы и подводные камни
|
||
|
||
### 1. fake не делает DROP
|
||
|
||
Оригинальный пакет уйдёт следом (если другие инстансы не дропнут его). Это **ожидаемое поведение** — fake лишь добавляет фейковые пакеты перед оригиналом. DROP — вердикт «перехваченный пакет не отправлять»; как движок складывает вердикты разных инстансов, описано в [[Zapret2/жизненный цикл desync-функции#Стадия 8. Вердикт и его агрегация|стадии 8 жизненного цикла]].
|
||
|
||
### 2. Без fooling фейк бесполезен или вреден
|
||
|
||
Если не задать fooling, сервер примет фейковый payload как настоящий. Для TCP это приведёт к рассинхронизации потока (данные с неверным seq будут интерпретированы неправильно). Для UDP сервер просто обработает фейковый пакет. **Всегда используйте fooling** (`tcp_md5`, `badsum`, `ip_ttl=1`, `tcp_flags_unset=ACK`, `tcp_seq=-10000` и т.д.). Рассинхронизация здесь означает, что данные с неверным seq сервер интерпретирует неправильно. Пример ниже показывает, как выглядит такая ошибка в конфиге; каталог способов испортить фейк — в [[Zapret2/ts-and-fooling#Как заставить fake умереть: каталог способов|заметке про fooling]].
|
||
|
||
> [!danger] Так делать НЕЛЬЗЯ — fake на TCP без ограничителей
|
||
> ```
|
||
> --lua-desync=fake:blob=fake_tls_vk:repeats=2:strategy=4
|
||
> ```
|
||
> Здесь нет ни одного fooling-параметра (`tcp_md5`, `ip_ttl=`, `badsum`, `tcp_flags_unset=ack`, `tcp_seq=`). Фейковый пакет уходит с **валидными TCP seq, checksum и нормальным TTL** → сервер принимает его как легитимные данные потока → приходит настоящий ClientHello с пересекающимся seq → **рассинхронизация → гарантированный разрыв соединения**.
|
||
>
|
||
> Цитата bolvan (Zapret anti-DPI staff) по этому конфигу:
|
||
> > fake без ограничителей на tcp = гарантированный слом соединения. https скорее всего работает, потому что через warp, но без работать не будет.
|
||
>
|
||
> То есть если кажется, что «работает» — это заслуга туннеля (WARP заворачивает реальный трафик в WireGuard/UDP, и битый fake-на-TCP по нему не бьёт), а **не** конфига. Убери WARP — голый HTTPS пойдёт по обычному TCP, и битый fake его сломает.
|
||
>
|
||
> **Примечание:** параметра `strategy=` у `fake` нет (см. [полный список аргументов](#a-собственные-аргументы-fake)) — он игнорируется и fooling не добавляет.
|
||
>
|
||
> **Как чинить** — добавить любой ограничитель:
|
||
> ```
|
||
> --lua-desync=fake:blob=fake_tls_vk:tcp_md5:repeats=2
|
||
> ```
|
||
> Выбор fooling зависит от того, где относительно тебя стоит DPI: `ip_ttl=` работает, если DPI ближе клиента, чем сервер; `tcp_md5`/`badsum`/`tcp_seq=` — сервер отбросит фейк сам.
|
||
|
||
### 3. fake работает только на первом replay-куске
|
||
|
||
При многопакетных payload (реассемблированных) fake срабатывает ровно один раз — на первом куске. На последующих частях он ничего не делает. Это правильно: фейк нужен один раз, перед началом реальных данных. Что такое replay и почему `fake` срабатывает лишь на первой части, описано в разделе [[#Поведение при replay / reasm|Поведение при replay / reasm]].
|
||
|
||
### 4. tls_mod молча пропускается без reasm_data
|
||
|
||
Если вы задали `tls_mod=rnd,rndsni`, но `reasm_data` отсутствует (например, payload влез в один пакет и реассемблирование не потребовалось для некоторых конфигураций) — tls_mod просто не применится. Фейк будет отправлен с немодифицированным blob. Для гарантированных модификаций используйте `--lua-init` для подготовки blob заранее (пример — в разделе [[#Когда tls_mod применяется, а когда нет|Когда tls_mod применяется, а когда нет]]).
|
||
|
||
### 5. blob обязателен — без optional будет Lua exception
|
||
|
||
Без `blob=...` функция вызывает `error()`. Это не тихий пропуск, а exception, который прервёт обработку всех инстансов для данного пакета. Если blob может отсутствовать — **всегда указывайте `optional`**. Lua exception — аварийная остановка выполнения Lua-кода с сообщением об ошибке; здесь её вызывает функция `error()`.
|
||
|
||
### 6. Для UDP нет TCP-fooling
|
||
|
||
UDP не нумерует байты и не имеет TCP-заголовка с опциями; почему TCP-приёмы к нему неприменимы, разобрано в нюансе [[Zapret2/desync/multisplit#1. Работает только с TCP — и почему|«Работает только с TCP»]] статьи про multisplit.
|
||
|
||
При использовании с UDP (QUIC) параметры `tcp_md5`, `tcp_seq`, `tcp_ack`, `tcp_flags_unset` и другие TCP-специфичные fooling не имеют смысла. Для UDP используйте IP-уровневые fooling: `ip_ttl`, `ip6_ttl`, `badsum`, `ipfrag`, IPv6 extension headers.
|
||
|
||
### 7. repeats может быть очень полезен
|
||
|
||
`repeats=N` отправляет каждый пакет/сегмент N раз. Для fake это означает N фейков подряд. Некоторые DPI сбрасывают состояние после N-го пакета, поэтому "заваливание" фейками (`repeats=11` или `repeats=20`) может быть эффективнее одного.
|
||
|
||
### 8. Порядок инстансов: fake всегда первый
|
||
|
||
В типичной конфигурации `fake` стоит **перед** [[multisplit]]/[[multidisorder]]. Порядок важен: сначала уходит фейк, затем (следующий инстанс) нарезает и отправляет реальный payload. Если поставить fake после split — фейк уйдёт после реальных данных, что может быть неэффективно. Инстанс — одна запись `--lua-desync=…` в профиле; как инстансы выстраиваются в цепочку, описано в [[последовательность аргументов]], а общий разбор порядка — в нюансе [[Zapret2/desync/multisplit#7. Порядок инстансов важен|«Порядок инстансов важен»]] статьи про multisplit.
|
||
|
||
### 9. fake не отсекается на не-TCP/не-UDP
|
||
|
||
В отличие от [[multisplit]] (который делает `instance_cutoff` на не-TCP), fake просто ничего не делает для пакетов, не являющихся TCP или UDP. Он **не отсекает** себя — будет продолжать проверять следующие пакеты в потоке. Что такое `instance_cutoff` и почему он экономит ресурсы, описано в [[Zapret2/жизненный цикл desync-функции#Стадия 1. Отсев чужого транспорта и instance cutoff|стадии 1 жизненного цикла]].
|
||
|
||
### 10. padencap + реальный payload — тонкий трюк
|
||
|
||
`padencap` увеличивает длины в TLS-структуре фейка на размер реального payload. Идея: DPI увидит фейковый ClientHello с padding extension, длина которой "обещает" ещё N байт. Реальный ClientHello (следующий пакет) может быть воспринят DPI как продолжение padding, а не как отдельный ClientHello. Это работает только с DPI, которые реассемблируют TCP и парсят TLS record по полям длины. Реассемблирование — склейка данных из нескольких TCP-пакетов обратно в единый поток; см. также [[#padencap — подробности|padencap — подробности]].
|
||
|
||
---
|
||
|
||
## Миграция с nfqws1
|
||
|
||
nfqws1 — движок первой версии zapret, у которого `fake` включался ключом `--dpi-desync=fake`. Ниже — как перенести такую настройку в nfqws2. Общая таблица соответствия флагов nfqws1 и nfqws2 лежит в [[Zapret2/desync#Соответствие флагов nfqws1 → nfqws2|обзоре desync]].
|
||
|
||
### Соответствие параметров
|
||
|
||
Слева ключи nfqws1, справа их запись в аргументах `fake`; тип payload в nfqws2 задаётся отдельным флагом `--payload=…`.
|
||
|
||
| nfqws1 | nfqws2 |
|
||
|:-------|:-------|
|
||
| `--dpi-desync=fake` | `--lua-desync=fake:blob=<blob>` |
|
||
| `--dpi-desync-fake-http=<hex>` | `--payload=http_req --lua-desync=fake:blob=<hex>` |
|
||
| `--dpi-desync-fake-tls=<hex\|!>` | `--payload=tls_client_hello --lua-desync=fake:blob=<hex\|fake_default_tls>` |
|
||
| `--dpi-desync-fake-quic=<hex>` | `--payload=quic_initial --lua-desync=fake:blob=<hex>` |
|
||
| `--dpi-desync-fake-tls-mod=<list>` | `:tls_mod=<list>` |
|
||
| `--dpi-desync-fooling=md5sig` | `:tcp_md5` |
|
||
| `--dpi-desync-fooling=badseq` | `:tcp_seq=-10000` |
|
||
| `--dpi-desync-fooling=badack` | `:tcp_ack=-66000` |
|
||
| `--dpi-desync-fooling=datanoack` | `:tcp_flags_unset=ack` |
|
||
| `--dpi-desync-fooling=hopbyhop` | `:ip6_hopbyhop` |
|
||
| `--dpi-desync-fooling=hopbyhop2` | `:ip6_hopbyhop2` |
|
||
| `--dpi-desync-fooling=destopt` | `:ip6_destopt` |
|
||
| `--dpi-desync-fooling=ipfrag1` | `:ipfrag` |
|
||
| `--dpi-desync-ttl=N` | `:ip_ttl=N:ip6_ttl=N` |
|
||
| `--dpi-desync-autottl=...` | `:ip_autottl=...:ip6_autottl=...` |
|
||
| `--dpi-desync-repeats=N` | `:repeats=N` |
|
||
| `--dpi-desync-badseq-increment=N` | `:tcp_seq=N` |
|
||
| `--dpi-desync-badack-increment=N` | `:tcp_ack=N` |
|
||
| `--dpi-desync-any-protocol` | Не нужно; или `payload=all` в инстансе |
|
||
|
||
### Ключевое отличие: в nfqws1 fake был "глобальный"
|
||
|
||
В nfqws1 `--dpi-desync=fake` автоматически выбирал blob по типу payload: для TLS — `--dpi-desync-fake-tls`, для HTTP — `--dpi-desync-fake-http`, для QUIC — `--dpi-desync-fake-quic`. В nfqws2 blob задаётся вручную, и для разных payload нужны **отдельные инстансы**.
|
||
|
||
> [!note] Проще говоря
|
||
> В nfqws1 достаточно было включить `--dpi-desync=fake`: движок сам выбирал blob по типу данных, по ключам `--dpi-desync-fake-tls`, `--dpi-desync-fake-http` и `--dpi-desync-fake-quic`. В nfqws2 вы сами говорите, какой blob для какого типа данных, и для каждого типа пишете свой инстанс.
|
||
|
||
### Пример полной миграции: fake с TTL
|
||
|
||
Ключ `--dpi-desync-fake-http` превращается в `--payload=http_req` и `blob=…`, а `--dpi-desync-ttl` — в пару `ip_ttl` и `ip6_ttl`.
|
||
|
||
```bash
|
||
# nfqws1:
|
||
nfqws --dpi-desync=fake \
|
||
--dpi-desync-fake-http=0x00000000 \
|
||
--dpi-desync-ttl=6
|
||
|
||
# nfqws2 (эквивалент):
|
||
nfqws2 \
|
||
--payload=http_req \
|
||
--lua-desync=fake:blob=0x00000000:ip_ttl=6:ip6_ttl=6
|
||
```
|
||
|
||
### Пример полной миграции: fake с tls_mod + datanoack
|
||
|
||
`--dpi-desync-fooling=datanoack` становится `tcp_flags_unset=ack`, а `--dpi-desync-fake-tls=!` — стандартным blob-ом `fake_default_tls`; список `--dpi-desync-fake-tls-mod` переносится в `tls_mod=`; в эквиваленте к нему добавлен `padencap`, которого в записи nfqws1 не было.
|
||
|
||
```bash
|
||
# nfqws1:
|
||
nfqws --dpi-desync=fake \
|
||
--dpi-desync-fooling=datanoack \
|
||
--dpi-desync-fake-tls=! \
|
||
--dpi-desync-fake-tls-mod=rnd,rndsni,dupsid
|
||
|
||
# nfqws2 (эквивалент):
|
||
nfqws2 \
|
||
--payload=tls_client_hello \
|
||
--lua-desync=fake:blob=fake_default_tls:tcp_flags_unset=ack:tls_mod=rnd,rndsni,dupsid,padencap
|
||
```
|
||
|
||
### Пример полной миграции: fake + multisplit
|
||
|
||
Одна команда nfqws1 с `fake,multisplit` разделяется на отдельные инстансы: для TLS и HTTP нужны разные blob-ы, поэтому `fake` пишется дважды, а [[multisplit]] получает свои аргументы, включая `seqovl` и [[Zapret2/desync/multisplit#seqovl_pattern|seqovl_pattern]].
|
||
|
||
```bash
|
||
# nfqws1:
|
||
nfqws --dpi-desync=fake,multisplit \
|
||
--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=multisplit:pos=1,midsld:seqovl=5:seqovl_pattern=0x1603030000
|
||
```
|
||
|
||
---
|
||
|
||
## Практические примеры
|
||
|
||
Двадцать готовых вариантов: от минимального фейка до связок с другими функциями. К большинству добавлено короткое пояснение, что произойдёт с пакетом.
|
||
|
||
### 1. Минимальный TLS-фейк (обязателен blob + fooling)
|
||
|
||
```bash
|
||
--payload=tls_client_hello --lua-desync=fake:blob=fake_default_tls:tcp_md5
|
||
```
|
||
|
||
Отправляет стандартный фейковый ClientHello с `www.w3.org`, сервер отбросит из-за TCP MD5 option.
|
||
|
||
### 2. Минимальный HTTP-фейк
|
||
|
||
```bash
|
||
--payload=http_req --lua-desync=fake:blob=fake_default_http:tcp_md5
|
||
```
|
||
|
||
То же, что в первом примере, но для HTTP: стандартный blob `fake_default_http` (см. [[#Стандартные blob-ы|Стандартные blob-ы]]), а сервер отбросит фейк из-за TCP MD5 option.
|
||
|
||
### 3. QUIC (UDP) фейк с TTL
|
||
|
||
```bash
|
||
--payload=quic_initial --lua-desync=fake:blob=fake_default_quic:ip_ttl=1:ip6_ttl=1
|
||
```
|
||
|
||
Для UDP TCP-fooling невозможен, используем TTL=1 — фейк не дойдёт до сервера. См. нюанс [[#6. Для UDP нет TCP-fooling|«Для UDP нет TCP-fooling»]].
|
||
|
||
### 4. optional: тихо пропустить, если blob не загружен
|
||
|
||
```bash
|
||
--lua-desync=fake:blob=cloned_ch:optional:tcp_md5
|
||
```
|
||
|
||
Если blob `cloned_ch` не был создан предыдущим инстансом — пропуск без ошибки.
|
||
|
||
### 5. Множественные повторы фейка
|
||
|
||
```bash
|
||
--payload=tls_client_hello --lua-desync=fake:blob=fake_default_tls:tcp_md5:repeats=11
|
||
```
|
||
|
||
11 одинаковых фейков подряд. Эффективно против DPI, который "считает" пакеты. См. нюанс [[#7. repeats может быть очень полезен|«repeats может быть очень полезен»]].
|
||
|
||
### 6. rnd: рандомизировать Random и Session ID
|
||
|
||
```bash
|
||
--payload=tls_client_hello --lua-desync=fake:blob=fake_default_tls:tcp_md5:tls_mod=rnd
|
||
```
|
||
|
||
Каждый фейк будет с уникальным Random и Session ID.
|
||
|
||
### 7. rndsni: случайный SNI в фейке
|
||
|
||
```bash
|
||
--payload=tls_client_hello --lua-desync=fake:blob=fake_default_tls:tcp_md5:tls_mod=rndsni
|
||
```
|
||
|
||
SNI в фейке будет случайным доменом (DPI не увидит ни реальный, ни `www.w3.org`).
|
||
|
||
### 8. sni=domain: конкретный SNI в фейке
|
||
|
||
```bash
|
||
--payload=tls_client_hello --lua-desync=fake:blob=fake_default_tls:tcp_md5:tls_mod=sni=www.google.com
|
||
```
|
||
|
||
DPI увидит `www.google.com` в фейке. Полезно, если DPI блокирует по whitelist.
|
||
|
||
### 9. sni=%var: подстановка SNI из переменной
|
||
|
||
```bash
|
||
--lua-init="target='www.google.com'" \
|
||
--payload=tls_client_hello \
|
||
--lua-desync=fake:blob=fake_default_tls:tcp_md5:tls_mod=sni=%target
|
||
```
|
||
|
||
Домен для SNI берётся из глобальной Lua-переменной `target`, которую задаёт `--lua-init`; порядок поиска переменной описан в разделе [[#Подстановка sni=%var|Подстановка sni=%var]].
|
||
|
||
### 10. dupsid: копирование Session ID из реального ClientHello
|
||
|
||
```bash
|
||
--payload=tls_client_hello --lua-desync=fake:blob=fake_default_tls:tcp_md5:tls_mod=rnd,dupsid
|
||
```
|
||
|
||
Session ID фейка совпадёт с реальным — DPI может привязать фейк к текущей сессии.
|
||
|
||
### 11. Полный набор tls_mod (типовой пресет)
|
||
|
||
```bash
|
||
--payload=tls_client_hello \
|
||
--lua-desync=fake:blob=fake_default_tls:tcp_md5:tls_mod=rnd,rndsni,dupsid,padencap
|
||
```
|
||
|
||
Максимальная маскировка фейка: случайные Random/SID, случайный SNI, скопированный реальный SID, padencap.
|
||
|
||
### 12. TTL-fooling (жёсткий фейк)
|
||
|
||
```bash
|
||
--payload=tls_client_hello --lua-desync=fake:blob=fake_default_tls:ip_ttl=1:ip6_ttl=1
|
||
```
|
||
|
||
Фейк умрёт на первом хопе. Работает, если DPI стоит ближе к клиенту, чем сервер.
|
||
|
||
### 13. datanoack + badsum (комбинированный fooling)
|
||
|
||
```bash
|
||
--payload=tls_client_hello \
|
||
--lua-desync=fake:blob=fake_default_tls:badsum:tcp_flags_unset=ack:tls_mod=rnd,dupsid,padencap
|
||
```
|
||
|
||
Два уровня защиты: испорченная контрольная сумма + снятый ACK.
|
||
|
||
### 14. IP-фрагментация фейка (TCP)
|
||
|
||
```bash
|
||
--payload=tls_client_hello --lua-desync=fake:blob=fake_default_tls:tcp_md5:ipfrag:ipfrag_pos_tcp=32
|
||
```
|
||
|
||
Фейк фрагментируется на IP-уровне. DPI может не уметь реассемблировать IP-фрагменты. Параметры разобраны в разделе [[#F) Standard ipfrag|F) Standard ipfrag]].
|
||
|
||
### 15. IP-фрагментация фейка (UDP/QUIC) в обратном порядке
|
||
|
||
```bash
|
||
--payload=quic_initial --lua-desync=fake:blob=fake_default_quic:ipfrag:ipfrag_pos_udp=8:ipfrag_disorder
|
||
```
|
||
|
||
QUIC-фейк фрагментируется на уровне IP: `ipfrag_pos_udp=8` задаёт позицию фрагментации для UDP (кратно 8, по умолчанию 8), а `ipfrag_disorder` отправляет IP-фрагменты в обратном порядке. Параметры описаны в разделе [[#F) Standard ipfrag|F) Standard ipfrag]].
|
||
|
||
### 16. Произвольный hex blob (нулевые байты)
|
||
|
||
```bash
|
||
--payload=http_req --lua-desync=fake:blob=0x00000000:ip_ttl=6:ip6_ttl=6
|
||
```
|
||
|
||
4 нулевых байта как фейк. DPI увидит "мусор" перед реальным HTTP.
|
||
|
||
### 17. Боевая связка: fake + multisplit для YouTube
|
||
|
||
```bash
|
||
--filter-tcp=443 --hostlist=youtube.txt \
|
||
--lua-desync=fake:blob=fake_default_tls:tcp_md5:repeats=11 \
|
||
--lua-desync=multisplit:pos=1,midsld
|
||
```
|
||
|
||
11 фейков подряд (с MD5 fooling) + реальный payload разрезан на 3 части. Как [[multisplit]] режет по маркерам, описано в разделе [[Zapret2/desync/multisplit#Маркеры позиций (pos)|Маркеры позиций (pos)]].
|
||
|
||
### 18. Боевая связка: fake + multisplit + seqovl
|
||
|
||
```bash
|
||
--payload=tls_client_hello \
|
||
--lua-desync=fake:blob=fake_default_tls:tcp_md5:tls_mod=rnd,rndsni,dupsid \
|
||
--lua-desync=multisplit:pos=1,midsld:seqovl=5:seqovl_pattern=0x1603030000
|
||
```
|
||
|
||
Фейк с полным tls_mod, затем реальный payload нарезан с seqovl. Приём `seqovl` разобран в разделе [[Zapret2/desync/multisplit#seqovl — скрытый фейк внутри сегмента|seqovl — скрытый фейк внутри сегмента]].
|
||
|
||
### 19. fake с клонированным ClientHello (двухинстансная схема)
|
||
|
||
```bash
|
||
--payload=tls_client_hello \
|
||
--lua-desync=tls_client_hello_clone:blob=cloned_ch:sni_del:sni_add=www.google.com \
|
||
--lua-desync=fake:blob=cloned_ch:optional:tcp_md5
|
||
```
|
||
|
||
Первый инстанс клонирует реальный ClientHello и подменяет SNI. Второй — отправляет клон как фейк. Флаг `optional` нужен на случай, если payload не TLS и клон не создан (см. нюанс [[#5. blob обязателен — без optional будет Lua exception|5]]).
|
||
|
||
### 20. fake для нескольких протоколов (отдельные профили)
|
||
|
||
```bash
|
||
--payload=tls_client_hello \
|
||
--lua-desync=fake:blob=fake_default_tls:tcp_md5:tls_mod=rnd,rndsni,dupsid,padencap \
|
||
--lua-desync=multisplit:pos=1,midsld \
|
||
--payload=http_req \
|
||
--lua-desync=fake:blob=fake_default_http:tcp_md5 \
|
||
--lua-desync=multisplit:pos=host,midsld \
|
||
--payload=quic_initial \
|
||
--lua-desync=fake:blob=fake_default_quic:ip_ttl=1:ip6_ttl=1
|
||
```
|
||
|
||
Для каждого протокола — свой blob и свой fooling. Как `--payload=` разделяет профиль на такие блоки, описано в заметке [[Zapret2/payload#Что такое тип payload (и чем он отличается от протокола потока)|о типах payload]] и в [[Zapret2/profile#Анатомия профиля|анатомии профиля]].
|
||
|
||
|
||
---
|
||
|
||
## 📚 См. также
|
||
|
||
- [[desync]] — обзор всех функций `--lua-desync` и общий контракт: кто вызывает функцию, что ей передаёт и как складываются вердикты
|
||
- [[жизненный цикл desync-функции]] — восемь стадий, общих для всех техник дурения, и отличия `fake` от общего скелета
|
||
- [[структура desync и диссекта]] — устройство таблицы `desync` и диссекта пакета, в том числе `reasm_data`
|
||
- [[ts-and-fooling]] — зачем фейк обязан умереть до сервера и какие бывают способы его испортить
|
||
- [[blob]] — как объявлять и передавать данные для аргумента `blob`
|
||
- [[payload]] — типы payload и фильтр `--payload`
|
||
- [[multisplit]] · [[multidisorder]] — сегментация, с которой `fake` чаще всего комбинируют
|
||
- [[fakedsplit]] · [[fakeddisorder]] — разрез с подмешиванием фейковых сегментов
|
||
- [[syndata]] — payload в SYN-пакете
|
||
- [[verify-strategy]] — как честно проверить, работает ли подобранная комбинация
|
||
- [[последовательность аргументов]] — как выстраивается цепочка инстансов в профиле
|
||
- [[profile]] · [[preset]] — где `--lua-desync` живёт среди остальных настроек
|
||
- [[DPI/DPI|DPI и ТСПУ]] — как устроена инспекция трафика, против которой работает `fake`
|
||
|
||
---
|
||
|
||
> **Источники:** `lua/zapret-antidpi.lua:438-461`, `lua/zapret-lib.lua:625-636` (`tls_mod_shim`), `lua/zapret-lib.lua:1194-1203` (`rawsend_payload_segmented`), `docs/manual.md:3991-4009`, `docs/manual.md:2425-2442` из репозитория zapret2.
|
||
|
||
---
|
||
|
||
> [!quote] 🤖 Эти статьи открыты — можно обучать на них ИИ
|
||
> При желании вы можете натренировать ИИ на наших статьях. Исходное форматирование доступно в Forgejo: [исходник этой заметки](https://git2.zapret.moe/zapretdiscordyoutube/todo/src/branch/main/Zapret2/desync/fake.md) · [скачать весь репозиторий одним zip-архивом](https://git2.zapret.moe/zapretdiscordyoutube/todo/archive/main.zip).
|