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>
1055 lines
119 KiB
Markdown
1055 lines
119 KiB
Markdown
---
|
||
date: 2026-02-17
|
||
tags:
|
||
- zapret
|
||
- zapret2
|
||
- nfqws2
|
||
- lua
|
||
- lua-desync
|
||
- antidpi
|
||
- tcp
|
||
- tcpseg
|
||
- seqovl
|
||
aliases:
|
||
- tcpseg
|
||
description: "Справочник по функции tcpseg в Zapret2/nfqws2: отправка TCP-сегмента из диапазона pos, seqovl без сегментации, связка с drop и примеры стратегий."
|
||
---
|
||
|
||
> [!mirror] Резервное зеркало
|
||
> Актуальная версия этой страницы — на основной вики: [wiki2.zapret.moe/Zapret2/desync/tcpseg](https://wiki2.zapret.moe/Zapret2/desync/tcpseg)
|
||
|
||
# `tcpseg` -- отправка TCP-сегмента из диапазона (zapret2 / nfqws2)
|
||
|
||
## Коротко и по-простому
|
||
|
||
Когда браузер открывает сайт по HTTPS, первым сообщением с данными он отправляет TLS ClientHello («привет от клиента»). В нём браузер перечисляет, какое шифрование умеет, и открытым текстом называет нужный сайт: имя лежит в поле SNI (Server Name Indication, «указание имени сервера»). У обычного HTTP без шифрования то же имя стоит в строке `Host:` запроса. ТСПУ (Технические средства противодействия угрозам — оборудование [[DPI/DPI|DPI]], то есть глубокой инспекции трафика, которое стоит у провайдера) ищет это имя в первом пакете соединения и по нему решает, что делать с соединением дальше.
|
||
|
||
HTTP-запросы и TLS-соединения идут поверх протокола TCP, а TCP отправляет данные кусками — сегментами. У каждого байта в соединении есть порядковый номер (sequence number, коротко seq), и сервер раскладывает принятые куски в свой буфер по этим номерам. Кроме того, сервер принимает только те байты, чьи номера попадают в его окно приёма (receive window): оно начинается с номера следующего байта, которого сервер ждёт. Всё, что лежит левее этой границы, TCP-стек молча отбрасывает как повтор или мусор — это штатное поведение, а не ошибка. Почему сборку по номерам гарантирует именно TCP, разобрано в [[Zapret2/desync/multisplit#1. Работает только с TCP — и почему|нюансе multisplit «Работает только с TCP»]].
|
||
|
||
Движок Zapret 2 (`nfqws2`) перехватывает исходящий пакет с ClientHello или HTTP-запросом, а функция `tcpseg` берёт из его данных один кусок и отправляет его в сеть отдельным TCP-сегментом, который она собирает сама. Данные пакета без сетевых заголовков называют payload: это сам HTTP-запрос или сам ClientHello. Границы куска задаёт аргумент `pos` — ровно два маркера через запятую, начало и конец диапазона. Маркер — это число (`0` — первый байт данных, `-1` — последний) или название места в запросе, например `midsld` — середина домена второго уровня, то есть главной части имени сайта (у `www.example.com` это `example`). Запись `pos=0,-1` означает «весь payload», а `pos=0,midsld` — «от начала до середины домена». В отличие от [[Zapret2/desync/multisplit#Маркеры позиций (pos)|multisplit]], у `tcpseg` нет значения `pos` по умолчанию: без него функция выдаёт ошибку. Все виды маркеров разобраны в разделе [[#Маркеры позиций (pos) -- диапазон из двух маркеров|Маркеры позиций (pos) -- диапазон из двух маркеров]].
|
||
|
||
Кусок отправляют отдельным сегментом, который функция собирает сама, и его параметры задаются аргументами команды: какие байты берутся (`pos`), сколько байт фальшивки приклеивается слева и как сдвигается seq (`seqovl`), сколько раз сегмент отправляется (`repeats`) и какие заголовки в нём меняются (fooling, о нём ниже). Этим можно воспользоваться тремя способами. Первый — отправить весь ClientHello одним сегментом, но с фальшивым префиксом слева (приём seqovl, о нём ниже). Второй — многократно отправить начало запроса в расчёте на то, что буфер DPI окажется забит. Третий — поставить `tcpseg` кирпичиком в цепочку рядом с другими инстансами, то есть записями `--lua-desync=…` в [[Zapret2/profile#Анатомия профиля|профиле]] (наборе правил Zapret 2 для определённого трафика), например рядом с `drop` (отдельной функцией, которая выбрасывает оригинальный пакет). Подробно — в разделе [[#Зачем нужен tcpseg|Зачем нужен tcpseg]].
|
||
|
||
К отправляемому куску можно добавить приём seqovl (Sequence Overlap, «перекрытие по номерам последовательности»). `tcpseg` дописывает слева N байт фальшивки — по умолчанию это нули, другой узор задаёт `seqovl_pattern` — и сдвигает seq сегмента назад на те же N. Для сервера эти байты оказываются левее границы окна приёма: он их выбрасывает и принимает остальное. DPI же может прочитать сегмент целиком и принять фальшивку за начало потока: так бывает, если он читает сегмент от начала и не сверяется с тем, какие байты примет сервер. Обычно фейк прячут от сервера иначе: отдельному пакету-обманке ([[Zapret2/desync/fake#Зачем нужен fake|fake]]) портят заголовки, например TTL (счётчик «времени жизни» пакета) или номера seq и ack (номер подтверждения), чтобы пакет не дошёл до сервера или сервер его отбросил, а DPI прочитал; такая порча называется fooling ([[Zapret2/ts-and-fooling#Что такое fooling|Что такое fooling]]). У seqovl заголовки остаются правильными, портить их не приходится. В `tcpseg` seqovl относится к единственному отправляемому сегменту, поэтому весь ClientHello можно отправить одним сегментом с префиксом, без нарезки. Механика по байтам — в разделе [[#seqovl -- скрытый фейк внутри сегмента|seqovl -- скрытый фейк внутри сегмента]], а как seqovl устроен в `multisplit` — в [[Zapret2/desync/multisplit#seqovl — скрытый фейк внутри сегмента|его разделе]].
|
||
|
||
Вердикт — это решение движка о судьбе перехваченного оригинального пакета: пропустить его как есть (`VERDICT_PASS`), выбросить (`VERDICT_DROP`) или заменить изменённым (`VERDICT_MODIFY`). Если функция вердикт не вернула, движок считает это за `VERDICT_PASS`. `multisplit` после отправки кусков сам выносит `VERDICT_DROP`. `tcpseg` не выносит вердикт вообще, поэтому оригинал остаётся жить: если после `tcpseg` в профиле нет других инстансов, отсутствие вердикта означает «пропустить как есть», оригинал уходит как обычно, и сервер получает данные дважды, из сегмента `tcpseg` и из оригинала. Вердикты всех инстансов профиля движок складывает, и `VERDICT_DROP` перебивает остальные, а инстансы после него всё равно вызываются. Поэтому, чтобы оригинал не ушёл, следом ставят отдельный инстанс `drop`: он только выносит `VERDICT_DROP`. Подробно — в разделе [[#Вердикт и комбинация с drop|Вердикт и комбинация с drop]], а как движок складывает вердикты нескольких инстансов — в [[Zapret2/жизненный цикл desync-функции#Стадия 8. Вердикт и его агрегация|стадии 8 жизненного цикла]]. Есть и нюанс с фильтрами: `drop` по умолчанию выбрасывает пакеты любого типа, а `tcpseg` работает только с распознанными протоколами, см. [[#5. drop по умолчанию дропает ВСЕ payload|нюанс 5]].
|
||
|
||
Связка из быстрого старта `tcpseg:pos=0,-1:seqovl=1` + `drop` заменяет оригинальный пакет одним сегментом. Сам `tcpseg` вердикт не выносит, поэтому оригинал выбрасывает второй инстанс `drop`, а в сеть уходит тот же ClientHello с одним байтом мусора спереди и seq, сдвинутым на единицу назад. ТСПУ видит поток, который начинается с этого байта, и разбор ClientHello может сбиться; сервер отрезает байт, лежащий левее окна приёма (на схеме — левее вертикальной линии seq=0). Как читать схему: строки — пакеты в порядке отправки, подписанные в тех же обозначениях, что и таблицы в этой статье; по горизонтали — место данных в TCP-потоке (номер последовательности, seq); в колонке справа — что сделал с пакетом сервер; внизу — буфер сервера, в который принятые куски встают по своим seq.
|
||
|
||
![[desync-anim-tcpseg.svg|Анимация tcpseg: оригинал выброшен, вместо него уходит ClientHello с байтом seqovl левее окна приёма]]
|
||
|
||
Самая короткая команда — та, что на схеме: весь payload (`pos=0,-1`), один нулевой байт спереди (`seqovl=1`) и `drop` следом. Строку `--lua-desync=…` пишут в профиль. Для HTTPS к ней добавляют фильтр `--payload=tls_client_hello`, чтобы функция срабатывала только на TLS ClientHello, как в [[#1. Минимальный seqovl без сегментации (TLS)|практическом примере 1]]; остальные готовые команды собраны в разделах [[#Быстрый старт|Быстрый старт]] и [[#Практические примеры|Практические примеры]]. Вот команда без фильтра:
|
||
|
||
```bash
|
||
--lua-desync=tcpseg:pos=0,-1:seqovl=1 --lua-desync=drop
|
||
```
|
||
|
||
`tcpseg` пригождается и без `drop`. Строка `--payload=http_req --lua-desync=tcpseg:pos=0,method+2:ip_id=rnd:repeats=20` отправляет начало HTTP-запроса до маркера `method+2` (что именно попадает в кусок, показано в примере 6) 20 раз подряд со случайным идентификатором IP-пакета (IP ID), а потом уходит и оригинал. Смысл в том, чтобы забить буфер DPI: он может переполниться, и тогда DPI перестанет анализировать поток. См. [[#6. Повторная отправка начала HTTP-запроса (без drop)|пример 6]] и [[#11. Повторная отправка (repeats) без drop -- атака повторами|нюанс 11]].
|
||
|
||
Готового рецепта на все случаи `tcpseg` не даёт. Расчёт seqovl — на DPI, который читает сегмент от начала и не сверяется с окном приёма сервера (так устроены не все DPI), а работает ли выбранная комбинация у конкретного провайдера, проверяют на практике по [[Zapret2/verify-strategy#Короткий чек-лист честной проверки|чек-листу честной проверки]]. `tcpseg` работает только с TCP и самостоятельной стратегией обычно не служит: это строительный блок, который ставят в связку с другими инстансами. Близкие соседи: [[multisplit]] режет весь payload на несколько сегментов и сам выбрасывает оригинал; [[Zapret2/desync/multidisorder#Обратный порядок отправки — суть disorder|multidisorder]] отправляет куски в обратном порядке; [[Zapret2/desync/fakedsplit#Зачем нужен fakedsplit|fakedsplit]] и [[Zapret2/desync/fakeddisorder#Зачем нужен fakeddisorder|fakeddisorder]] подмешивают к настоящим кускам фейки; [[Zapret2/desync/fake#Зачем нужен fake|fake]] — отдельный пакет-обманка. Если к `tcpseg` без `drop` добавить fooling, из-за которого сервер отбросит сам сегмент (например, `tcp_ack=-66000`), по смыслу он станет ближе к `fake`, чем к сегментации: об этом раздел [[#Варианты tcpseg без drop из набора стратегий GUI|Варианты tcpseg без drop из набора стратегий GUI]]. Все отличия от соседей сведены в таблицу раздела [[#Отличия от других функций сегментации|Отличия от других функций сегментации]].
|
||
|
||
---
|
||
|
||
## Оглавление
|
||
|
||
- [Коротко и по-простому](#коротко-и-по-простому)
|
||
- [Справка: где функция в коде и родственники](#справка-где-функция-в-коде-и-родственники)
|
||
- [Зачем нужен tcpseg](#зачем-нужен-tcpseg)
|
||
- [Быстрый старт](#быстрый-старт)
|
||
- [Откуда берутся данные](#откуда-берутся-данные)
|
||
- [Маркеры позиций (pos) -- диапазон из двух маркеров](#маркеры-позиций-pos----диапазон-из-двух-маркеров)
|
||
- [Отличие от multisplit: resolve_range vs resolve_multi_pos](#отличие-от-multisplit-resolve_range-vs-resolve_multi_pos)
|
||
- [Типы маркеров](#типы-маркеров)
|
||
- [Относительные маркеры](#относительные-маркеры)
|
||
- [Арифметика маркеров](#арифметика-маркеров)
|
||
- [Поведение resolve_range при неразрешённых маркерах](#поведение-resolve_range-при-неразрешённых-маркерах)
|
||
- [Важные нюансы pos](#важные-нюансы-pos)
|
||
- [seqovl -- скрытый фейк внутри сегмента](#seqovl----скрытый-фейк-внутри-сегмента)
|
||
- [Принцип работы seqovl](#принцип-работы-seqovl)
|
||
- [Зачем seqovl лучше обычного fooling](#зачем-seqovl-лучше-обычного-fooling)
|
||
- [seqovl_pattern](#seqovl_pattern)
|
||
- [Вердикт и комбинация с drop](#вердикт-и-комбинация-с-drop)
|
||
- [Полный список аргументов](#полный-список-аргументов)
|
||
- [A) Собственные аргументы tcpseg](#a-собственные-аргументы-tcpseg)
|
||
- [B) Standard direction](#b-standard-direction)
|
||
- [C) Standard payload](#c-standard-payload)
|
||
- [D) Standard fooling](#d-standard-fooling)
|
||
- [E) Standard ipid](#e-standard-ipid)
|
||
- [F) Standard ipfrag](#f-standard-ipfrag)
|
||
- [G) Standard reconstruct](#g-standard-reconstruct)
|
||
- [H) Standard rawsend](#h-standard-rawsend)
|
||
- [Порядок отправки](#порядок-отправки)
|
||
- [Поведение при replay / reasm](#поведение-при-replay--reasm)
|
||
- [Автосегментация по MSS](#автосегментация-по-mss)
|
||
- [Место в общем скелете](#место-в-общем-скелете)
|
||
- [Псевдокод алгоритма](#псевдокод-алгоритма)
|
||
- [Нюансы и подводные камни](#нюансы-и-подводные-камни)
|
||
- [Отличия от других функций сегментации](#отличия-от-других-функций-сегментации)
|
||
- [Практические примеры](#практические-примеры)
|
||
- [Варианты tcpseg без drop из набора стратегий GUI](#варианты-tcpseg-без-drop-из-набора-стратегий-gui)
|
||
- [📚 См. также](#-см-также)
|
||
|
||
---
|
||
|
||
## Справка: где функция в коде и родственники
|
||
|
||
Паспорт функции для тех, кто сверяется с исходниками zapret2: в каком файле и на какой строке лежит код, какой ключ первой версии zapret она заменяет и как объявлена.
|
||
|
||
**Файл:** `lua/zapret-antidpi.lua:1043`
|
||
**nfqws1 эквивалент:** отсутствует (NEW функция в nfqws2)
|
||
**Сигнатура:** `function tcpseg(ctx, desync)`
|
||
|
||
`tcpseg` -- функция отправки **части** текущего payload (или reasm, или blob), ограниченной **двумя** маркерами позиций (диапазоном), в виде TCP-сегмента. В отличие от [[multisplit]], которая разрезает весь payload на множество сегментов по списку позиций, `tcpseg` вырезает и отправляет **один** конкретный диапазон данных. При этом `tcpseg` **не выносит вердикт** (ни `VERDICT_DROP`, ни `VERDICT_PASS`) -- для замещения оригинального пакета необходимо комбинировать с функцией `drop`.
|
||
|
||
> [!note] Проще говоря
|
||
> Payload — полезные данные пакета без сетевых заголовков: сам HTTP-запрос или сам ClientHello. Reasm — те же данные, собранные движком из нескольких пакетов, если запрос в один не влез. Blob — заранее заготовленные данные, которые можно подсунуть вместо настоящих. Какой из трёх источников выбирается, разобрано в разделе [[#Откуда берутся данные|Откуда берутся данные]]. Маркер — способ указать место в данных, диапазон — кусок между двумя маркерами ([[#Маркеры позиций (pos) -- диапазон из двух маркеров|Маркеры позиций (pos) -- диапазон из двух маркеров]]). `VERDICT_DROP` — решение «перехваченный пакет не отправлять», `VERDICT_PASS` — «пропустить как есть»; как движок складывает такие решения от разных функций, описано в [[Zapret2/жизненный цикл desync-функции#Стадия 8. Вердикт и его агрегация|стадии 8 жизненного цикла]]. Функция `drop` — отдельный инстанс, который только выносит `VERDICT_DROP`.
|
||
|
||
Родственные функции: [[multisplit]] (множественная сегментация), [[multidisorder]] (обратный порядок), [[fakedsplit]] (с фейками), [[fakeddisorder]] (фейки + обратный порядок), [[hostfakesplit]] (по hostname), [[oob]] (urgent byte).
|
||
|
||
Общий для всех техник дурения порядок работы — восемь стадий от отсева чужого транспорта до вердикта — разобран в [[жизненный цикл desync-функции]]; здесь описано только то, чем `tcpseg` от этого скелета отличается.
|
||
|
||
---
|
||
|
||
## Зачем нужен tcpseg
|
||
|
||
`tcpseg` решает задачу, которую не решает [[multisplit]]: отправить **конкретный фрагмент** payload (или весь payload целиком) как отдельный TCP-сегмент, с опциональным seqovl, **без автоматического вынесения вердикта**.
|
||
|
||
Как seqovl устроен в `multisplit`, разобрано в [[Zapret2/desync/multisplit#seqovl — скрытый фейк внутри сегмента|его разделе]]; здесь он разобран для `tcpseg` в разделе [[#seqovl -- скрытый фейк внутри сегмента|seqovl -- скрытый фейк внутри сегмента]], а вердикт — в разделе [[#Вердикт и комбинация с drop|Вердикт и комбинация с drop]].
|
||
|
||
Основные сценарии использования:
|
||
|
||
1. **seqovl без сегментации.** Отправить весь payload целиком с seqovl-префиксом, подменяющим начало потока для DPI. Маркеры `pos=0,-1` задают диапазон "от начала до конца" -- весь payload
|
||
2. **Повторная отправка начала потока.** Отправить первые N байт payload многократно (`repeats=N`), чтобы забить буфер DPI мусором. Маркеры `pos=0,method+2` или `pos=0,midsld` отправляют только начало
|
||
3. **Модульная композиция.** Поскольку `tcpseg` не выносит вердикт, его можно комбинировать с другими инстансами (например, `drop`, `luaexec`) в цепочке
|
||
|
||
Первый сценарий в двух словах: весь ClientHello уходит одним сегментом, но с фальшивым префиксом слева, который для DPI выглядит как начало потока, а сервер его отбрасывает (пример: [[#1. Минимальный seqovl без сегментации (TLS)|Минимальный seqovl без сегментации (TLS)]]). Второй: начало запроса отправляется много раз, и DPI, по описанию в примере [[#7. Повторная отправка до midsld (TLS)|Повторная отправка до midsld (TLS)]], может переполнить свой буфер и перестать анализировать поток. Третий: `tcpseg` сам оригинал не заменяет, поэтому его ставят в цепочку рядом с инстансом, который это сделает, например с `drop`, или с `luaexec` (он выполняет произвольный Lua-код, как в примере [[#4. Динамический случайный seqovl через luaexec|Динамический случайный seqovl через luaexec]]).
|
||
|
||
**Ключевое отличие от multisplit:** [[multisplit]] разрезает и отправляет **весь** payload, затем дропает оригинал. `tcpseg` отправляет **часть** (или весь) payload и **не** дропает оригинал -- нужна отдельная команда `drop`.
|
||
|
||
> [!note] Проще говоря
|
||
> [[multisplit]] работает по схеме «разрезал всё, отправил куски, оригинал выбросил». `tcpseg` работает по схеме «вырезал один кусок и отправил, а оригинал остаётся на усмотрение остальных инстансов профиля». Если после `tcpseg` не поставить `drop`, оригинал уйдёт вслед за ним.
|
||
|
||
---
|
||
|
||
## Быстрый старт
|
||
|
||
Ниже четыре готовые строки для [[Zapret2/profile#Анатомия профиля|профиля]] Zapret 2, от самой короткой к более сложным. Флаг `--payload=…` работает как фильтр для всех вызовов `--lua-desync`, которые идут после него (до следующего `--payload` или до конца профиля): они срабатывают только на данных указанного типа. Поэтому `--payload` пишут перед `--lua-desync`, а не после (подробно — в [[последовательность аргументов]]).
|
||
|
||
Минимальный seqovl (весь payload + 1 байт нулевого seqovl, dir=out, payload=known):
|
||
|
||
```bash
|
||
--lua-desync=tcpseg:pos=0,-1:seqovl=1 --lua-desync=drop
|
||
```
|
||
|
||
Здесь `pos=0,-1` — весь payload, `seqovl=1` — один нулевой байт слева, а второй инстанс `drop` выбрасывает оригинал. Значения `dir=out` и `payload=known` берутся по умолчанию: только исходящие пакеты и только распознанные протоколы; оба аргумента разобраны в разделах [B) Standard direction](#b-standard-direction) и [C) Standard payload](#c-standard-payload).
|
||
|
||
seqovl с кастомным паттерном (TLS):
|
||
|
||
```bash
|
||
--payload=tls_client_hello \
|
||
--lua-desync=tcpseg:pos=0,-1:seqovl=5:seqovl_pattern=0x1603030000 \
|
||
--lua-desync=drop
|
||
```
|
||
|
||
Функция срабатывает только на TLS ClientHello, отправляет его целиком, а слева приклеивает 5 байт `0x1603030000`, похожих на начало TLS record — заголовка записи TLS. Эти байты задаёт `seqovl_pattern`, см. раздел [[#seqovl_pattern|seqovl_pattern]].
|
||
|
||
Повторная отправка начала HTTP-запроса:
|
||
|
||
```bash
|
||
--payload=http_req --lua-desync=tcpseg:pos=0,method+2:ip_id=rnd:repeats=20
|
||
```
|
||
|
||
Здесь отправляется начало запроса до `method+2` (что именно попадает в кусок, показано в примере 6), `ip_id=rnd` задаёт случайные IP ID, а `repeats=20` — 20 повторов. `drop` нет, поэтому оригинал тоже уходит. Разбор — в [[#6. Повторная отправка начала HTTP-запроса (без drop)|примере 6]].
|
||
|
||
Динамический seqovl со случайным паттерном:
|
||
|
||
```bash
|
||
--lua-desync=luaexec:code='desync.rnd=brandom_az(math.random(5,10))' \
|
||
--lua-desync=tcpseg:pos=0,-1:seqovl=#rnd:seqovl_pattern=rnd \
|
||
--lua-desync=drop:payload=known
|
||
```
|
||
|
||
Перед `tcpseg` `luaexec` на каждый пакет генерирует случайную строку из букв a-z длиной от 5 до 10 символов; она служит и паттерном (`seqovl_pattern=rnd`), и источником длины (`seqovl=#rnd` — размер этого blob). `drop:payload=known` выбрасывает оригинал только для распознанных протоколов. Разбор — в [[#4. Динамический случайный seqovl через luaexec|примере 4]].
|
||
|
||
---
|
||
|
||
## Откуда берутся данные
|
||
|
||
Внутри `tcpseg` данные (`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 может распознать.
|
||
|
||
Разберём три источника. Первый — blob: заранее заготовленные данные, которые можно подсунуть вместо настоящих; что это такое и как их объявлять, описано в [[blob]]. Если задан `blob=имя`, функция берёт его содержимое и полностью игнорирует реальный payload. Второй — реассемблированные данные (reasm, от английского reassembly — «повторная сборка»): запрос, склеенный движком из нескольких TCP-пакетов, если он в один не влез; как такой запрос отправляется, описано в разделе [[#Поведение при replay / reasm|Поведение при replay / reasm]]. Третий — payload текущего пакета, `desync.dis.payload`: здесь `dis` — диссект, то есть пакет, заранее разобранный движком на поля (его устройство — в [[структура desync и диссекта]]). Lua-оператор `or` возвращает первый истинный операнд, поэтому цепочка читается «сверху вниз, берём первое, что есть». Та же цепочка общая для большинства функций дурения и описана как [[Zapret2/жизненный цикл desync-функции#Стадия 4. Выбор данных: blob → reasm → payload|стадия 4 жизненного цикла]].
|
||
|
||
Если blob задан, а относительные маркеры вроде `midsld` не срабатывают, причина может быть в том, что движок не распознал содержимое blob как TLS или HTTP. Тип payload — это название распознанного протокола вроде `tls_client_hello` или `http_req`; как он определяется, описано в [[Zapret2/payload#Что такое тип payload (и чем он отличается от протокола потока)|заметке о типах payload]].
|
||
|
||
> [!note] Проще говоря
|
||
> Функция спрашивает: «мне подсунули blob? — беру его. Есть запрос, собранный из кусков? — беру его. Иначе беру тело текущего пакета». Маркеры и seqovl всегда работают по тем данным, которые выиграли этот выбор.
|
||
|
||
---
|
||
|
||
## Маркеры позиций (pos) -- диапазон из двух маркеров
|
||
|
||
![[desync-anim-hub-markers.svg|Анимация: маркеры позиций pos на HTTP-запросе и на TLS ClientHello, разрез по pos=host,midsld,endhost]]
|
||
|
||
`pos` -- **обязательный** аргумент `tcpseg`. Если `pos` не задан, функция вызовет `error("tcpseg: no pos specified")`. Это отличает `tcpseg` от [[multisplit]], где `pos` по умолчанию `"2"`.
|
||
|
||
Задаётся как строка с **ровно двумя** маркерами через запятую. Первый маркер -- начало диапазона, второй -- конец.
|
||
|
||
Маркер — это «адрес» байта в данных: число или название места в запросе. Превратить маркер в конкретный номер байта — значит его разрешить; для диапазона это делает функция `resolve_range`. Диапазон — кусок данных между первым и вторым маркерами: именно он вырезается и отправляется. Как те же маркеры служат точками разреза в `multisplit`, разобрано в [[Zapret2/desync/multisplit#Маркеры позиций (pos)|его разделе]].
|
||
|
||
> [!note] Проще говоря
|
||
> `pos=A,B` значит «отправь кусок от A до B». Например, `pos=0,-1` — весь запрос, а `pos=0,midsld` — от начала до середины домена второго уровня.
|
||
|
||
### Отличие от multisplit: resolve_range vs resolve_multi_pos
|
||
|
||
Таблица показывает, чем `tcpseg` отличается от [[Zapret2/desync/multisplit#Как маркеры разрешаются в коде|multisplit]] при разборе `pos`. «Функция разрешения» — та, что превращает названия маркеров в номера байтов; обе написаны на C и вызываются из Lua. Главная разница: `multisplit` получает список точек разреза, а `tcpseg` — начало и конец одного куска.
|
||
|
||
| Аспект | `tcpseg` | `multisplit` |
|
||
|:-------|:---------|:-------------|
|
||
| Функция разрешения | `resolve_range` (C-код) | `resolve_multi_pos` (C-код) |
|
||
| Количество маркеров | **Ровно 2** (ошибка, если не 2) | Любое количество |
|
||
| Семантика маркеров | Начало и конец **диапазона** | Точки **разреза** |
|
||
| Результат | Таблица из 2 позиций `{start, end}` или `nil` | Массив уникальных позиций |
|
||
| Что отправляется | `data:sub(pos[1], pos[2])` -- данные **между** маркерами | Весь payload, разрезанный по позициям |
|
||
|
||
### Типы маркеров
|
||
|
||
Маркеры бывают трёх видов. Абсолютные отсчитывают байты от начала или от конца данных и не зависят от содержимого. Относительные ищут место по смыслу — начало имени хоста, середину домена — и потому работают, только если движок распознал протокол; как он это делает, описано в [[Zapret2/payload#Что такое тип payload (и чем он отличается от протокола потока)|заметке о типах payload]]. Те же маркеры с примерами для разрезов разобраны в [[Zapret2/desync/multisplit#Типы маркеров|multisplit]].
|
||
|
||
| Тип | Описание | Пример |
|
||
|:----|:---------|:-------|
|
||
| **Абсолютный положительный** | Смещение от начала payload. `0` = первый байт (в resolve_range используется zero-based нумерация на входе, но внутренне конвертируется в 1-based Lua) | `0`, `5`, `100` |
|
||
| **Абсолютный отрицательный** | Смещение от конца payload. `-1` = последний байт | `-1`, `-10`, `-50` |
|
||
| **Относительный** | Логическая позиция внутри распознанного payload. Привязана к структуре протокола | `midsld`, `host`, `sniext` |
|
||
|
||
### Относительные маркеры
|
||
|
||
В правой колонке указано, в каких типах payload маркер имеет смысл: `http_req` — HTTP-запрос, `tls_client_hello` — TLS ClientHello. 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 /` диапазон `0..method+2` захватит `GE`) |
|
||
| `sniext+1` | один байт после начала данных SNI extension |
|
||
| `host+3` | три байта после начала hostname |
|
||
| `0` | начало payload |
|
||
| `-1` | последний байт payload |
|
||
|
||
### Поведение resolve_range при неразрешённых маркерах
|
||
|
||
Маркер называют неразрешённым, если движок не нашёл для него места в данных: например, `midsld` для `unknown` payload, то есть для данных, тип которых не распознан. Таблица ниже говорит, что делает `resolve_range` в таких случаях; «non-strict режим» означает, что функция вызвана без флага `strict`.
|
||
|
||
`resolve_range` реализована в C-коде (`nfq2/lua.c:3281`). Поведение при неразрешённых маркерах:
|
||
|
||
| Ситуация | Поведение (non-strict режим) |
|
||
|:---------|:-----------------------------|
|
||
| Оба маркера разрешены | Возвращает `{pos[0], pos[1]}` -- нормальный диапазон |
|
||
| Первый маркер не разрешён, второй разрешён | Первый маркер заменяется на `0` (начало данных) |
|
||
| Первый маркер разрешён, второй не разрешён | Второй маркер заменяется на `len-1` (конец данных) |
|
||
| Оба маркера не разрешены | Возвращает `nil` -- диапазон не может быть определён |
|
||
| `pos[0] > pos[1]` (начало после конца) | Возвращает `nil` -- невалидный диапазон |
|
||
|
||
**Важно:** `tcpseg` вызывает `resolve_range` **без** флага `strict`. Это означает, что если один из маркеров не разрешается, он расширяется до границы данных. Если нужна строгая логика -- используйте абсолютные маркеры.
|
||
|
||
> [!note] Проще говоря
|
||
> Если не нашёлся один маркер, диапазон растягивается до края данных: пропавший первый маркер становится началом данных, пропавший второй — концом. Если не нашлись оба или начало оказалось правее конца, `tcpseg` ничего не отправляет и пишет об этом в лог (подробнее — [[#10. При неразрешённом диапазоне -- тихий пропуск|нюанс 10]]).
|
||
|
||
### Важные нюансы pos
|
||
|
||
- **pos обязателен.** В отличие от [[multisplit]], где `pos` по умолчанию `"2"`, в `tcpseg` отсутствие `pos` вызывает `error()`. Это жёсткое требование
|
||
- **Ровно 2 маркера.** Если передать 1 или 3+ маркера, `resolve_range` вызовет `luaL_error("resolve_range require 2 markers")`
|
||
- **Маркер `0` -- начало данных.** В отличие от [[multisplit]], где позиция 1 удаляется (`delete_pos_1`), в `tcpseg` маркер `0` -- это валидное начало диапазона
|
||
- **Маркеры `0,-1` -- весь payload.** Самый частый паттерн: `pos=0,-1` означает "от начала до конца" -- весь payload целиком. Используется для seqovl без сегментации
|
||
|
||
Те же требования разобраны отдельно в нюансах [[#2. pos обязателен -- нет дефолта|2]], [[#3. Ровно 2 маркера -- не больше и не меньше|3]] и [[#6. Маркер 0 -- это начало, не "нулевая позиция Lua"|6]]. Про удаление позиции в `multisplit` — [[Zapret2/desync/multisplit#2. Разрез в самом начале данных отбрасывается|нюанс 2]] его статьи.
|
||
|
||
---
|
||
|
||
## seqovl -- скрытый фейк внутри сегмента
|
||
|
||
**seqovl** (Sequence Overlap) -- техника скрытого замешивания фейковых данных в реальный TCP-сегмент через манипуляцию TCP sequence number. В `tcpseg` seqovl применяется к отправляемому сегменту (он всегда один).
|
||
|
||
Смысл приёма в том, что TCP-получатель принимает не все байты подряд. Он держит окно приёма (receive window) и принимает байты, номера которых попадают в него, начиная с номера следующего ожидаемого байта; всё левее этой границы отбрасывается как повтор или мусор. Если приклеить слева фальшивку и сдвинуть seq назад на её длину, фальшивка окажется левее границы: сервер её выбросит, а DPI, читающий сегмент от начала, увидит её вместе с остальным. Полное объяснение по шагам — в [[Zapret2/desync/multisplit#Принцип работы seqovl|принципе работы seqovl в multisplit]]; ниже те же цифры для `tcpseg`, где сегмент один.
|
||
|
||
В [[Zapret2/desync/multidisorder#seqovl — перезапись буфера сокета через перекрытие|multidisorder]] приём с тем же названием устроен иначе: там он перезаписывает буфер сокета на сервере через перекрытие сегментов, поэтому переносить знания о seqovl между функциями нужно осторожно.
|
||
|
||
### Принцип работы seqovl
|
||
|
||
![[desync-anim-hub-seqovl.svg|Анимация: seqovl дописывает слева паттерн и сдвигает seq на 990; DPI читает сегмент целиком, сервер выбрасывает байты левее 1000]]
|
||
|
||
Схема выше показывает один сегмент с `pos=0,-1` и `seqovl=10`. `TCP seq: 1000` — номер, с которого начинались бы данные без seqovl; после seqovl он уменьшается на 10, а перед данными встают 10 байт паттерна.
|
||
|
||
|
||
|
||
![[wiki-anim-z2-tcpseg-seqovl.svg|Анимация: tcpseg с pos=0,midsld и seqovl=5 отправляет начало с паттерном]]
|
||
|
||
Во втором случае отправляется только часть payload — от начала до `midsld`; `-5` в `seq` — сдвиг относительно начала отправляемого куска.
|
||
|
||
> [!note] Проще говоря
|
||
> `tcpseg` дописывает перед куском лишние байты и подписывает их номерами, которые сервер уже не ждёт. Сервер выбрасывает эти байты, а DPI, читающий сегмент целиком, видит их вместе с настоящими данными. В `tcpseg` сегмент один, поэтому seqovl относится ровно к нему; в `multisplit` он относится только к первому из нескольких сегментов.
|
||
|
||
### Зачем seqovl лучше обычного fooling
|
||
|
||
Обычный способ спрятать фейк от сервера — [[Zapret2/ts-and-fooling#Что такое fooling|fooling]]: пакету-обманке портят заголовки (TTL, номера seq или ack, опцию md5sig), и сервер (или маршрутизатор по пути) отбрасывает такой пакет целиком. `seqovl` добивается похожего результата другим путём; таблица сравнивает оба подхода и совпадает с той, что приведена в [[Zapret2/desync/multisplit#Зачем seqovl лучше обычного fooling|multisplit]].
|
||
|
||
| Критерий | Обычный fooling (TTL, badseq, md5sig) | seqovl |
|
||
|:---------|:---------------------------------------|:-------|
|
||
| Заголовки | Модифицируются (TTL, seq, ack, md5) | **Не модифицируются** -- пакет выглядит полностью легитимным |
|
||
| Обнаружение | DPI может детектировать подозрительные заголовки | DPI видит "честный" сегмент с правильными заголовками |
|
||
| Механизм отбрасывания | Сервер отбрасывает весь пакет из-за невалидных заголовков | Сервер отбрасывает только часть, выходящую за TCP window |
|
||
| Надёжность | Зависит от поведения конкретного стека | Основан на фундаментальном свойстве TCP |
|
||
|
||
**Вывод:** seqovl -- средство создания скрытых фейков, не требующее fooling. Это его ключевое преимущество. В `tcpseg` seqovl особенно силён в комбинации с `pos=0,-1`, где весь payload отправляется с фейковым префиксом.
|
||
|
||
### seqovl_pattern
|
||
|
||
Паттерн, которым заполняется seqovl-область (N байт слева от реальных данных). По умолчанию -- `0x00` (нули).
|
||
|
||
В `tcpseg` `seqovl_pattern` -- это **имя blob**. Паттерн повторяется до нужной длины `seqovl`. Blob можно записать прямо в команде шестнадцатеричной строкой (inline hex, `0x…`), заранее объявить флагом `--blob` и сослаться на него по имени или сгенерировать на лету через `luaexec`, как в третьем примере ниже; подробно про blob — в заметке [[blob]].
|
||
|
||
```bash
|
||
# Inline hex blob (маскировка под начало TLS record)
|
||
--lua-desync=tcpseg:pos=0,-1:seqovl=5:seqovl_pattern=0x1603030000
|
||
|
||
# Предзагруженный blob
|
||
--blob=tlspat:0x1603030100 \
|
||
--lua-desync=tcpseg:pos=0,-1:seqovl=8:seqovl_pattern=tlspat
|
||
|
||
# Динамически сгенерированный blob через luaexec
|
||
--lua-desync=luaexec:code='desync.rnd=brandom_az(math.random(5,10))' \
|
||
--lua-desync=tcpseg:pos=0,-1:seqovl=#rnd:seqovl_pattern=rnd
|
||
```
|
||
|
||
Если `optional` задан и blob `seqovl_pattern` отсутствует -- используется нулевой паттерн (операция не отменяется). Сам флаг описан в разделе [[#A) Собственные аргументы tcpseg|A) Собственные аргументы tcpseg]].
|
||
|
||
**Важно в tcpseg:** `seqovl` -- только **число**, маркеры не поддерживаются (как и в [[multisplit]], в отличие от [[multidisorder]] и [[fakeddisorder]], где seqovl может быть маркером). Как seqovl задаётся маркером там, разобрано в разделах [[Zapret2/desync/multidisorder#seqovl как маркер|seqovl как маркер]] и [[Zapret2/desync/fakeddisorder#seqovl — маркер, а не число|seqovl — маркер, а не число]].
|
||
|
||
---
|
||
|
||
## Вердикт и комбинация с drop
|
||
|
||
Вердикт — решение движка о судьбе перехваченного оригинального пакета: `VERDICT_PASS` пропускает его как есть, `VERDICT_DROP` выбрасывает, `VERDICT_MODIFY` заменяет пакет изменённым; отсутствие вердикта приравнивается к `VERDICT_PASS`. Полная таблица и правила сложения вердиктов от разных инстансов — в [[Zapret2/жизненный цикл desync-функции#Стадия 8. Вердикт и его агрегация|стадии 8 жизненного цикла]].
|
||
|
||
**Ключевая особенность `tcpseg`:** функция **не выносит вердикт**. Она не возвращает ни `VERDICT_DROP`, ни `VERDICT_PASS`. Это означает:
|
||
|
||
1. После выполнения `tcpseg` оригинальный пакет **не блокируется**
|
||
2. Следующие инстансы в цепочке **продолжают обработку**
|
||
3. Если после `tcpseg` нет других инстансов -- оригинальный пакет уйдёт как есть
|
||
|
||
Вердикты нескольких инстансов складываются по правилу «`VERDICT_MODIFY` перебивает `VERDICT_PASS`, `VERDICT_DROP` перебивает оба»: поэтому `drop` в профиле выбрасывает оригинал, даже если сам `tcpseg` ничего не решил. Дроп цепочку не обрывает: инстансы после него всё равно вызываются и видят тот же пакет.
|
||
|
||
Для замещения оригинального пакета `tcpseg` нужно комбинировать с `drop`:
|
||
|
||
```bash
|
||
# tcpseg отправляет payload с seqovl, drop блокирует оригинал
|
||
--lua-desync=tcpseg:pos=0,-1:seqovl=5 --lua-desync=drop
|
||
```
|
||
|
||
**Нюанс с payload-фильтрами:** по умолчанию `tcpseg` работает только с `known` payload, а `drop` -- с `all`. Если вы хотите дропать только известные payload (чтобы неизвестные проходили без изменений), укажите:
|
||
|
||
```bash
|
||
--lua-desync=tcpseg:pos=0,-1:seqovl=5 --lua-desync=drop:payload=known
|
||
```
|
||
|
||
Здесь `known` — только распознанные протоколы (`http_req`, `tls_client_hello` и другие), а `all` — любой payload, включая `unknown`, то есть данные, тип которых движок не распознал. Подробнее — в разделе [[#C) Standard payload|C) Standard payload]] и в [[Zapret2/payload#Что такое тип payload (и чем он отличается от протокола потока)|заметке о типах payload]].
|
||
|
||
![[wiki-anim-z2-tcpseg-drop.svg|Схема: tcpseg без drop и с drop]]
|
||
|
||
|
||
> [!note] Проще говоря
|
||
> `tcpseg` только добавляет в сеть свой сегмент, а оригинал не трогает, пока этого не сделает другой инстанс. С `drop` данные уходят один раз, сегментом `tcpseg`; без `drop` дважды. Как `multisplit` решает то же самое сам и зачем ему для отладки аргумент `nodrop`, описано в [[Zapret2/desync/multisplit#4. nodrop создаёт дублирование|его нюансе 4]].
|
||
|
||
---
|
||
|
||
## Полный список аргументов
|
||
|
||
Аргументы делятся на собственные аргументы `tcpseg` (раздел A) и стандартные (разделы B–H): их понимают и другие функции дурения, а общий обзор есть в [[desync]]. Формат вызова:
|
||
|
||
```
|
||
--lua-desync=tcpseg[:arg1[=val1][:arg2[=val2]]...]
|
||
```
|
||
|
||
Все `val` приходят в Lua как строки. Если `=val` не указан, значение = пустая строка `""` (в Lua это truthy, то есть считается истинным значением), поэтому флаги пишутся просто как `:optional`.
|
||
|
||
### A) Собственные аргументы tcpseg
|
||
|
||
#### `pos`
|
||
|
||
- **Формат:** `pos=<marker1,marker2>`
|
||
- **Тип:** строка с **ровно двумя** маркерами через запятую
|
||
- **По умолчанию:** нет (обязательный параметр; если не задан -- `error()`)
|
||
- **Описание:** Диапазон данных для отправки. Первый маркер -- начало, второй -- конец (включительно). Из данных вырезается `data:sub(pos[1], pos[2])` и отправляется как TCP-сегмент (в Lua `sub` берёт кусок строки от первого номера до второго). Подробно о маркерах — в разделе [[#Маркеры позиций (pos) -- диапазон из двух маркеров|Маркеры позиций (pos) -- диапазон из двух маркеров]]
|
||
- **Примеры:**
|
||
- `pos=0,-1` -- весь payload (от начала до конца)
|
||
- `pos=0,midsld` -- от начала до середины SLD
|
||
- `pos=0,method+2` -- от начала до 2 байт после начала HTTP-метода
|
||
- `pos=host,endhost` -- hostname и ещё один байт сразу после него (`endhost` указывает на байт после имени, а конец диапазона включительный)
|
||
- `pos=0,1` -- первые два байта (для TLS: первые два байта TLS record)
|
||
- `pos=sniext,endhost` -- от начала SNI extension data до конца hostname и один байт после него
|
||
|
||
> [!warning] Конец диапазона включительный — проверено по коду
|
||
> `resolve_range` (`nfq2/lua.c`) переводит оба маркера в позиции и прибавляет единицу для Lua, а `data:sub(pos[1], pos[2])` берёт оба конца. Поэтому байт, на который указывает второй маркер, тоже попадает в сегмент: числовой маркер `1` — это второй байт payload, и `pos=0,1` отправляет **два** байта, а `pos=0,method+2` для `GET /` отправляет `GET`, а не `GE`. Чтобы закончить диапазон ровно перед маркером, вычтите единицу: `pos=0,method+1` даст `GE`, `pos=host,endhost-1` — ровно hostname. Комментарий «захватит `GE`» в схеме арифметики маркеров, раздел «Пример без seqovl (pos=host,endhost)» и заголовок примера 10 «Только первый байт TLS record» написаны без учёта этой единицы.
|
||
|
||
#### `seqovl`
|
||
|
||
- **Формат:** `seqovl=N` (где N > 0)
|
||
- **Тип:** только число (маркеры **не поддерживаются** -- как и в [[multisplit]])
|
||
- **По умолчанию:** не задан (нет seqovl)
|
||
- **Описание:** К данным сегмента слева добавляется N байт `seqovl_pattern`, а TCP `th_seq` (поле номера последовательности в TCP-заголовке) уменьшается на N. Сервер отбросит левую часть, DPI -- может не отбросить. Механика — в разделе [[#seqovl -- скрытый фейк внутри сегмента|seqovl -- скрытый фейк внутри сегмента]]
|
||
- **Примеры:**
|
||
- `seqovl=1` -- 1 байт фейка слева (минимальный)
|
||
- `seqovl=5` -- 5 байт фейка слева
|
||
- `seqovl=#rnd` -- размер blob `rnd` (C-подстановка через `#`)
|
||
- `seqovl=10000` -- 10000 байт (автосегментация по MSS разобьёт на несколько TCP-сегментов)
|
||
|
||
#### `seqovl_pattern`
|
||
|
||
- **Формат:** `seqovl_pattern=<blobName>`
|
||
- **Тип:** имя blob-переменной
|
||
- **По умолчанию:** один байт `0x00`, повторяемый до длины `seqovl`
|
||
- **Описание:** Данные для заполнения seqovl-области. Blob повторяется функцией `pattern()` до нужного размера. Подробно — в разделе [[#seqovl_pattern|seqovl_pattern]]
|
||
- **Поведение с `optional`:** если `optional` задан и blob отсутствует -- используется нулевой паттерн, seqovl не отменяется
|
||
- **Примеры:**
|
||
- `seqovl_pattern=0x1603030000` -- inline hex (маскировка под TLS)
|
||
- `seqovl_pattern=rnd` -- динамически сгенерированный blob
|
||
- `seqovl_pattern=fake_default_tls` -- стандартный TLS-фейк как паттерн
|
||
|
||
#### `blob`
|
||
|
||
- **Формат:** `blob=<blobName>`
|
||
- **Тип:** имя blob-переменной
|
||
- **По умолчанию:** не задан
|
||
- **Описание:** Заменить текущий payload/reasm на указанный blob и отправить из него диапазон pos. Используется для отправки произвольных данных. Что такое blob и как его объявить — в [[blob]]
|
||
- **Примеры:**
|
||
- `blob=fake_default_tls` -- стандартный TLS-фейк
|
||
- `blob=0xDEADBEEF` -- inline hex
|
||
- `blob=my_custom_data` -- предзагруженный blob
|
||
|
||
#### `optional`
|
||
|
||
- **Формат:** `optional` (флаг, без значения)
|
||
- **Описание:** Мягкий режим:
|
||
- Если задан `blob=...` и blob отсутствует -- tcpseg **ничего не делает** (тихий skip, без ошибок)
|
||
- Если задан `seqovl_pattern=...` и blob отсутствует -- используется нулевой паттерн (seqovl не отменяется)
|
||
- **Использование:** защита от ошибок при использовании blob, которые могут отсутствовать (например, если blob генерируется другой функцией). Та же проверка описана в [[Zapret2/жизненный цикл desync-функции#Стадия 3. Ранняя проверка аргументов|стадии 3 жизненного цикла]]
|
||
|
||
---
|
||
|
||
### B) Standard direction
|
||
|
||
| Параметр | Значения | По умолчанию |
|
||
|:---------|:---------|:-------------|
|
||
| `dir` | `in`, `out`, `any` | `out` |
|
||
|
||
Фильтр по направлению пакета. `tcpseg` по умолчанию работает только с исходящими (`out`).
|
||
|
||
- `dir=out` -- только исходящие (от клиента к серверу)
|
||
- `dir=in` -- только входящие (от сервера к клиенту)
|
||
- `dir=any` -- оба направления
|
||
|
||
При первом вызове с указанным `dir` функция делает `direction_cutoff_opposite` -- отсекает себя от противоположного направления. Проще говоря, инстанс перестаёт получать пакеты не своего направления, и движок не тратит время на Lua-вызовы там, где они заведомо бесполезны; проверка направления текущего пакета (`direction_check`) выполняется позже, см. [[Zapret2/жизненный цикл desync-функции#Стадия 2. Отсечение противоположного направления|стадию 2 жизненного цикла]].
|
||
|
||
---
|
||
|
||
### C) Standard payload
|
||
|
||
| Параметр | Значения | По умолчанию |
|
||
|:---------|:---------|:-------------|
|
||
| `payload` | список типов через запятую | `known` |
|
||
|
||
Фильтр по типу payload на уровне Lua. Это **дополнительный** фильтр к `--payload=...` на уровне профиля. Тип payload — название протокола, который движок распознал в данных пакета; см. [[Zapret2/payload#Что такое тип payload (и чем он отличается от протокола потока)|заметку о типах payload]].
|
||
|
||
- `payload=known` -- только распознанные протоколы (`http_req`, `tls_client_hello`, `quic_initial` и т.д.)
|
||
- `payload=all` -- любой payload, включая `unknown`
|
||
- `payload=tls_client_hello,http_req` -- конкретные типы
|
||
- `payload=~unknown` -- инверсия: всё кроме unknown
|
||
|
||
**Важно:** лучше ставить `--payload=...` на уровне профиля (C-код, быстрее), а не полагаться только на Lua-фильтр.
|
||
|
||
---
|
||
|
||
### D) Standard fooling
|
||
|
||
Модификации L3/L4 заголовков (то есть заголовков IP и TCP), то самое «портящее» вмешательство — fooling; общий разбор — в [[Zapret2/ts-and-fooling#Что такое fooling|Что такое fooling]] и [[Zapret2/ts-and-fooling#Как заставить fake умереть: каталог способов|каталоге способов]]. В `tcpseg` применяются к отправляемому сегменту.
|
||
|
||
| Параметр | Описание | Пример |
|
||
|:---------|:---------|:-------|
|
||
| `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 в `tcpseg` применяется к **реальному** сегменту (не к фейку). Если задать `tcp_ack=-66000`, сервер отбросит сегмент. Fooling в tcpseg имеет смысл только для безопасных вещей: `tcp_ts_up`, `ip_id`, IPv6 extension headers.
|
||
|
||
> [!note] Проще говоря
|
||
> Fooling в `tcpseg` бьёт по тому самому сегменту, который должен дойти до сервера. Поэтому опции, из-за которых сервер отбросит пакет (например, `tcp_ack=-66000`), портят задуманное. Исключение — вариант из раздела [[#Варианты tcpseg без drop из набора стратегий GUI|Варианты tcpseg без drop из набора стратегий GUI]], где сегмент с fooling нарочно превращается в фейк. Подробнее про сами опции — в [[ts-and-fooling]].
|
||
|
||
---
|
||
|
||
### 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-сегментации, см. [[#Автосегментация по MSS|Автосегментация по MSS]]).
|
||
|
||
---
|
||
|
||
### F) Standard ipfrag
|
||
|
||
IP-фрагментация **поверх** TCP-сегмента. Отправленный TCP-сегмент дополнительно фрагментируется на уровне IP. Проще говоря: сегмент, уже вырезанный `tcpseg`, при отправке ещё раз делится на части, но теперь средствами протокола IP, а собирает их обратно получатель на уровне IP. Пример — [[#9. seqovl без сегментации + IP-фрагментация|seqovl без сегментации + IP-фрагментация]].
|
||
|
||
| Параметр | Описание | По умолчанию |
|
||
|:---------|:---------|:-------------|
|
||
| `ipfrag[=func]` | Включить IP-фрагментацию. Если без значения -- `ipfrag2` | -- |
|
||
| `ipfrag_disorder` | Отправить IP-фрагменты в обратном порядке | -- |
|
||
| `ipfrag_pos_tcp=N` | Позиция фрагментации TCP (кратно 8) | `32` |
|
||
| `ipfrag_pos_udp=N` | Позиция фрагментации UDP (кратно 8). Для tcpseg бесполезно -- он только TCP | `8` |
|
||
| `ipfrag_next=N` | IPv6: next protocol во 2-м фрагменте (penetration атака на фаерволы) | -- |
|
||
|
||
---
|
||
|
||
### G) Standard reconstruct
|
||
|
||
Реконструкция — сборка готового raw-пакета («сырого», со всеми заголовками) перед отправкой.
|
||
|
||
| Параметр | Описание |
|
||
|:---------|:---------|
|
||
| `badsum` | Испортить L4 (TCP) checksum при реконструкции raw-пакета. Сервер отбросит такой пакет |
|
||
|
||
---
|
||
|
||
### H) Standard rawsend
|
||
|
||
Rawsend — отправка готовых сегментов в сеть самой функцией; в `tcpseg` её выполняет `rawsend_payload_segmented` (см. [[#Автосегментация по MSS|Автосегментация по MSS]]). Эти параметры управляют отправкой.
|
||
|
||
| Параметр | Описание |
|
||
|:---------|:---------|
|
||
| `repeats=N` | Отправить сегмент N раз (идентичные повторы) |
|
||
| `ifout=<iface>` | Интерфейс для отправки (по умолчанию определяется автоматически) |
|
||
| `fwmark=N` | Firewall mark (только Linux, nftables/iptables) |
|
||
|
||
---
|
||
|
||
## Порядок отправки
|
||
|
||
`tcpseg` отправляет **один** сегмент (диапазон данных между двумя маркерами), опционально с seqovl-префиксом. Для сравнения: `multisplit` отправляет несколько сегментов и следит за их порядком ([[Zapret2/desync/multisplit#Порядок отправки сегментов|его раздел]]), а здесь сегмент один. Подпись `seq=` на схемах ниже — сдвиг номера последовательности первого байта сегмента: смещение первого байта сегмента относительно начала данных. В примере с `host` это `host_offset`. Если seqovl задан, смещение уменьшается на его длину; отрицательным оно получается в примерах `pos=0,…` (`-10`, `-5`), где кусок начинается с нулевого байта. В коде это третий аргумент вызова `rawsend_payload_segmented`, `pos[1]-1-seqovl`.
|
||
|
||
### Пример без seqovl (pos=host,endhost)
|
||
|
||
![[wiki-anim-z2-tcpseg-host.svg|Анимация: tcpseg с pos=host,endhost отправляет только имя сайта]]
|
||
|
||
Диапазон между маркерами `host` и `endhost` уходит отдельным сегментом, а оригинал остаётся нетронутым: у `tcpseg` вердикта нет.
|
||
|
||
### Пример с seqovl=10 (pos=0,-1)
|
||
|
||
```
|
||
Payload (600 байт), pos=0,-1, seqovl=10:
|
||
|
||
Сегмент: [PATTERN(10)][ВЕСЬ_PAYLOAD_600_БАЙТ]
|
||
seq=-10 len=610
|
||
|
||
Сервер: отбросит первые 10 байт, примет 600
|
||
DPI: проанализирует все 610 байт
|
||
```
|
||
|
||
Проще говоря: `tcpseg` дописывает 10 байт паттерна спереди и сдвигает seq на −10. Сервер принимает 600 настоящих байт, а 10 байт паттерна отбрасывает как вышедшие за окно приёма; DPI видит все 610.
|
||
|
||
### Пример с частичной отправкой и seqovl (pos=0,midsld, seqovl=5)
|
||
|
||
![[wiki-anim-z2-tcpseg-seqovl.svg|Анимация: tcpseg с pos=0,midsld и seqovl=5 отправляет начало с паттерном]]
|
||
|
||
Здесь отправляется только начало payload: от первого байта до `midsld`. Перед ним стоят 5 байт паттерна с seq на 5 меньше. Чтобы оригинал не ушёл следом, нужен `drop`.
|
||
|
||
---
|
||
|
||
## Поведение при replay / reasm
|
||
|
||
Многопакетный запрос `nfqws2` придерживает, собирает в буфер `reasm_data` и перепроигрывает через desync-функции ([[жизненный цикл desync-функции]], стадия 6). `tcpseg` использует из этой развилки только первую половину: на первой части вырезает диапазон из собранного буфера и отправляет его, на остальных частях логирует «not acting on further replay pieces» и возвращает `nil`.
|
||
|
||
Вторую половину — дроп последующих частей — функция не применяет сознательно: она ничего не заменяет, а лишь добавляет в поток дополнительный сегмент.
|
||
|
||
**Важный нюанс:** поскольку `tcpseg` не выносит вердикт, на последующих частях replay оригинальные пакеты **пройдут без изменений**. Если `drop` стоит после `tcpseg` -- он заблокирует все пакеты (и первую часть, и последующие). Поэтому связка `tcpseg` + `drop` корректно обрабатывает reasm: tcpseg отправляет весь reasm при первой части, drop блокирует все оригинальные части.
|
||
|
||
> [!note] Проще говоря
|
||
> Если запрос пришёл несколькими пакетами, движок сначала собирает его целиком (reasm), а затем по очереди вызывает функцию на каждой придержанной части (replay — «перепроигрывание»). `tcpseg` отправляет свой кусок один раз, на первой части. Остальные части сам не дропает: их судьбу решает `drop`, если он стоит в профиле. `multisplit` устроен по-другому: он сам дропает остальные части, см. [[Zapret2/desync/multisplit#Поведение при replay / reasm|его раздел]].
|
||
|
||
---
|
||
|
||
## Автосегментация по MSS
|
||
|
||
![[desync-anim-hub-mss.svg|Анимация: кусок данных больше MSS автоматически режется на под-сегменты с растущим seq]]
|
||
|
||
MSS (Maximum Segment Size) — наибольший объём данных, который помещается в один TCP-сегмент данного соединения. О размерах TCP-сегментов думать **не нужно**. Функция `rawsend_payload_segmented` из `zapret-lib.lua` автоматически:
|
||
|
||
1. Отслеживает MSS для каждого TCP-соединения
|
||
2. Если отправляемая часть (включая seqovl) превышает MSS -- дополнительно режет по MSS
|
||
3. Каждый под-сегмент отправляется с корректным TCP sequence
|
||
|
||
**Пример:** если вы задали `pos=0,-1:seqovl=10000`, это не вызовет ошибку. `rawsend_payload_segmented` отправит несколько TCP-сегментов с начальным sequence -(10000), общим размером 10000 байт seqovl-pattern, и в последних сегментах -- реальные данные payload.
|
||
|
||
> [!note] Проще говоря
|
||
> Слишком большой сегмент функция сама режет на допустимые куски и каждому ставит правильный seq; настраивать ничего не нужно. Так же это устроено в [[Zapret2/desync/multisplit#Автосегментация по MSS|multisplit]].
|
||
|
||
---
|
||
|
||
## Место в общем скелете
|
||
|
||
Тело `tcpseg` построено по тому же шаблону, что и все остальные функции дурения: восемь стадий от отсева чужого транспорта до вердикта. Разобраны они один раз в [[жизненный цикл desync-функции]] — здесь только отклонения. Гвард (guard) — проверка, которая решает, работать ли функции с этим конкретным пакетом. Названия стадий в левой колонке — ссылки на их подробный разбор.
|
||
|
||
| Стадия общего скелета | Что делает `tcpseg` |
|
||
|:----------------------|:----------------|
|
||
| [[Zapret2/жизненный цикл desync-функции#Стадия 1. Отсев чужого транспорта и instance cutoff\|1. Отсев транспорта]] | только TCP; на не-TCP делает `instance_cutoff` (кроме связанного ICMP) |
|
||
| [[Zapret2/жизненный цикл desync-функции#Стадия 2. Отсечение противоположного направления\|2. Направление]] | `dir=out` по умолчанию, отключается от входящего |
|
||
| [[Zapret2/жизненный цикл desync-функции#Стадия 3. Ранняя проверка аргументов\|3. Аргументы]] | **`pos` обязателен** — без него `error()`; `optional` + отсутствующий `blob` → тихий выход |
|
||
| [[Zapret2/жизненный цикл desync-функции#Стадия 4. Выбор данных: blob → reasm → payload\|4. Данные]] | штатная цепочка `blob → reasm → payload` |
|
||
| [[Zapret2/жизненный цикл desync-функции#Стадия 5. Три гварда\|5. Гварды]] | штатные `#data>0`, `direction_check`, `payload_check` (по умолчанию `known`) |
|
||
| [[Zapret2/жизненный цикл desync-функции#Стадия 6. Развилка перепроигрывания (replay)\|6. replay]] | использует только первую половину развилки: работает на первой части, остальные **не дропает** |
|
||
| [[Zapret2/жизненный цикл desync-функции#Стадия 7. Собственно техника\|7. Своя техника]] | `resolve_range` разрешает ровно два маркера в диапазон, отправляется один сегмент с этим куском данных |
|
||
| [[Zapret2/жизненный цикл desync-функции#Стадия 8. Вердикт и его агрегация\|8. Вердикт]] | **не выносит никакого** — оригинальный пакет уходит как обычно |
|
||
|
||
Последние две строки таблицы объясняют, почему `tcpseg` ведёт себя не как остальные техники сегментации. Он ничего не дропает и не заменяет исходный поток, а лишь **дополнительно** отправляет выбранный кусок данных. Поэтому его применяют как строительный блок в связке с другими инстансами, а не как самостоятельную стратегию.
|
||
|
||
> [!note] Проще говоря
|
||
> `tcpseg` проходит все стадии скелета, но на последней ничего не решает. Поэтому оригинальный пакет он сам не заменяет: это делает другой инстанс, например `drop`.
|
||
|
||
---
|
||
|
||
## Псевдокод алгоритма
|
||
|
||
Тело функции целиком, включая общие для всех техник стадии — они пронумерованы так же, как в [[жизненный цикл desync-функции]]:
|
||
|
||
```lua
|
||
function tcpseg(ctx, desync)
|
||
-- 1. Проверка: только TCP
|
||
if not desync.dis.tcp then
|
||
if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end
|
||
return -- без вердикта
|
||
end
|
||
|
||
-- 2. Cutoff противоположного направления
|
||
direction_cutoff_opposite(ctx, desync)
|
||
|
||
-- 3. pos ОБЯЗАТЕЛЕН
|
||
if not desync.arg.pos then
|
||
error("tcpseg: no pos specified")
|
||
end
|
||
|
||
-- 4. Проверка optional blob
|
||
if optional and blob specified and blob not exists then
|
||
DLOG("tcpseg: blob not found. skipped")
|
||
return -- без вердикта, тихий skip
|
||
end
|
||
|
||
-- 5. Выбор данных
|
||
data = blob_or_def(blob) or reasm_data or dis.payload
|
||
|
||
-- 6. Проверки: данные не пусты, направление OK, payload OK
|
||
if #data > 0 and direction_check() and payload_check() then
|
||
|
||
-- 7. Только первый replay
|
||
if replay_first(desync) then
|
||
|
||
-- 8. Разрешение ДИАПАЗОНА (ровно 2 маркера)
|
||
pos = resolve_range(data, l7payload, pos_arg)
|
||
-- pos = {start, end} или nil
|
||
|
||
if pos then
|
||
-- 9. Вырезать диапазон
|
||
part = data:sub(pos[1], pos[2])
|
||
|
||
-- 10. seqovl
|
||
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 not blob_exist(seqovl_pattern) then
|
||
-- используем нулевой паттерн
|
||
else
|
||
pat = blob(seqovl_pattern)
|
||
end
|
||
end
|
||
part = pattern(pat, 1, seqovl) .. part
|
||
end
|
||
|
||
-- 11. Отправка с автосегментацией
|
||
rawsend_payload_segmented(desync, part, pos[1]-1-seqovl)
|
||
|
||
else
|
||
DLOG("tcpseg: range cannot be resolved")
|
||
end
|
||
else
|
||
-- 12. Не первый replay -- ничего не делаем
|
||
DLOG("tcpseg: not acting on further replay pieces")
|
||
end
|
||
end
|
||
|
||
-- 13. ВЕРДИКТ НЕ ВЫНОСИТСЯ -- return без значения
|
||
end
|
||
```
|
||
|
||
**Ключевые отличия от псевдокода [[multisplit]]:**
|
||
- Шаг 3: `error()` при отсутствии `pos` (в multisplit -- дефолт `"2"`)
|
||
- Шаг 8: `resolve_range` вместо `resolve_multi_pos` (2 маркера, не список)
|
||
- Шаг 9: `data:sub(pos[1], pos[2])` -- диапазон, не цикл по частям
|
||
- Шаг 11: одна отправка (не цикл)
|
||
- Шаг 13: **нет return VERDICT_DROP / VERDICT_PASS** -- нет `replay_drop_set()`, нет `nodrop`
|
||
|
||
> [!note] Проще говоря
|
||
> По шагам функция делает вот что. Проверяет, что пакет TCP, и отключается от противоположного направления. Требует `pos`. Если задан blob, а его нет и указан `optional`, тихо выходит. Выбирает данные. На первой части replay разрешает два маркера в диапазон, вырезает его, при `seqovl` приклеивает слева паттерн и отправляет результат одним вызовом с автосегментацией. На остальных частях ничего не делает. Вердикт не возвращает.
|
||
|
||
---
|
||
|
||
## Нюансы и подводные камни
|
||
|
||
### 1. Работает только с TCP
|
||
|
||
Если текущий пакет не TCP (UDP, ICMP и т.д.), `tcpseg` делает `instance_cutoff_shim` -- отключает себя для этого потока навсегда. Исключение: связанные ICMP-пакеты (related icmp) не вызывают cutoff. Почему TCP-приёмы не переносятся на UDP, разобрано в [[Zapret2/desync/multisplit#1. Работает только с TCP — и почему|нюансе multisplit]], а сам `instance_cutoff` описан в [[Zapret2/жизненный цикл desync-функции#Стадия 1. Отсев чужого транспорта и instance cutoff|стадии 1 жизненного цикла]].
|
||
|
||
### 2. pos обязателен -- нет дефолта
|
||
|
||
В отличие от [[multisplit]] (дефолт `"2"`), `tcpseg` без `pos` вызовет `error()`. Всегда указывайте `pos`. Это жёсткое требование: `error()` — ошибка Lua: `nfqws2` при этом не падает, ядро пишет её в лог и прекращает обработку пакета, но профиль с таким инстансом фактически не работает (см. [[Zapret2/жизненный цикл desync-функции#Стадия 3. Ранняя проверка аргументов|стадию 3 жизненного цикла]]).
|
||
|
||
### 3. Ровно 2 маркера -- не больше и не меньше
|
||
|
||
`resolve_range` в C-коде проверяет `ctm != 2` и вызывает `luaL_error`. Один маркер или три маркера -- ошибка. Проще говоря: пишите ровно два маркера через запятую, например `pos=0,-1` или `pos=0,midsld`.
|
||
|
||
### 4. Не выносит вердикт -- нужен drop
|
||
|
||
Самая частая ошибка: забыть `drop` после `tcpseg`. Без `drop` оригинальный пакет уйдёт, и сервер получит данные дважды. Это может работать (TCP-стек дедуплицирует), но неоптимально и может путать DPI. Проще говоря: оригинал `tcpseg` не выбрасывает, потому что вердикта у него нет; выбрасывает `drop`. Подробно — в разделе [[#Вердикт и комбинация с drop|Вердикт и комбинация с drop]].
|
||
|
||
### 5. drop по умолчанию дропает ВСЕ payload
|
||
|
||
Функция `drop` по умолчанию работает с `payload=all`. Если `tcpseg` работает только с `known`, то `drop` без ограничений заблокирует и `unknown` payload. Здесь `known` — распознанные протоколы, `unknown` — данные, тип которых движок не распознал ([[Zapret2/payload#Что такое тип payload (и чем он отличается от протокола потока)|подробнее о типах payload]]); фильтры описаны в разделе [[#C) Standard payload|C) Standard payload]]. Решение:
|
||
|
||
```bash
|
||
--lua-desync=tcpseg:pos=0,-1:seqovl=5 --lua-desync=drop:payload=known
|
||
```
|
||
|
||
### 6. Маркер 0 -- это начало, не "нулевая позиция Lua"
|
||
|
||
В `resolve_range` маркер `0` -- это абсолютный маркер начала данных. Внутри C-кода `pos[0]=0` соответствует первому байту. При возврате в Lua конвертируется в 1-based (`pos[0]+1`). Проще говоря: в командной строке `0` — первый байт данных, а пересчёт в нумерацию Lua с единицы функция делает сама.
|
||
|
||
### 7. Fooling применяется к реальному сегменту
|
||
|
||
В отличие от [[fakedsplit]], где fooling идёт только на фейки, в `tcpseg` fooling модифицирует **реальный** отправляемый сегмент. Использование `tcp_ack=-66000` приведёт к тому, что сервер отбросит сегмент. Безопасные fooling-опции: `ip_id=rnd`, `tcp_ts_up`, IPv6 extension headers. Fooling у соседей описан в разделах [[Zapret2/desync/fakedsplit#D) Standard fooling|fakedsplit]] и [[Zapret2/desync/fakeddisorder#D) Standard fooling|fakeddisorder]], а сами опции — в [[ts-and-fooling]]; параметры `tcpseg` — в разделе [[#D) Standard fooling|D) Standard fooling]].
|
||
|
||
### 8. seqovl=10000 не вызовет ошибку
|
||
|
||
В отличие от nfqws1, где большие значения seqovl вызывали ошибку, nfqws2 автоматически сегментирует по MSS. Большой seqovl просто создаст много под-сегментов. Как они строятся, описано в разделе [[#Автосегментация по MSS|Автосегментация по MSS]].
|
||
|
||
### 9. Нет nodrop -- потому что нет drop
|
||
|
||
В `tcpseg` нет параметра `nodrop`, потому что функция и так никогда не дропает. Для управления вердиктом используйте отдельный инстанс `drop`. Проще говоря: `nodrop` нужен там, где функция сама выбрасывает оригинал и иногда этого не хочется; у `tcpseg` выбрасывать нечего. Как это выглядит у соседа — в [[Zapret2/desync/multisplit#4. nodrop создаёт дублирование|нюансе 4 multisplit]].
|
||
|
||
### 10. При неразрешённом диапазоне -- тихий пропуск
|
||
|
||
Если оба маркера не разрешаются (например, `pos=midsld,endhost` для `unknown` payload), `resolve_range` вернёт `nil`, и `tcpseg` залогирует "range cannot be resolved" и ничего не сделает. Без ошибки, без вердикта. Проще говоря: если диапазон определить не удалось, ничего не отправляется, а ошибки в работе нет; о причине можно узнать из лога.
|
||
|
||
### 11. Повторная отправка (repeats) без drop -- атака повторами
|
||
|
||
`tcpseg` с `repeats=N` без `drop` отправит N копий сегмента, а затем оригинальный пакет тоже уйдёт. Это осознанная стратегия для забивания буфера DPI (см. blockcheck2/15-misc.sh). Примеры повторов: [[#6. Повторная отправка начала HTTP-запроса (без drop)|6]], [[#7. Повторная отправка до midsld (TLS)|7]] и [[#10. Только первый байт TLS record (повторы)|10]]. Проще говоря: повторы вместе с оригиналом — задуманное поведение, а не ошибка.
|
||
|
||
---
|
||
|
||
## Отличия от других функций сегментации
|
||
|
||
Пять функций ниже отправляют данные TCP-сегментами, но различаются числом маркеров, порядком отправки, наличием фейков и тем, как устроен seqovl. Подробности о соседях — в разделах [[Zapret2/desync/multisplit#Отличия от других функций сегментации|multisplit]], [[Zapret2/desync/multidisorder#Обратный порядок отправки — суть disorder|multidisorder]], [[Zapret2/desync/fakedsplit#Зачем нужен fakedsplit|fakedsplit]] и [[Zapret2/desync/fakeddisorder#Зачем нужен fakeddisorder|fakeddisorder]].
|
||
|
||
| Аспект | `tcpseg` | `multisplit` | `multidisorder` | `fakedsplit` | `fakeddisorder` |
|
||
|:-------|:---------|:-------------|:----------------|:-------------|:----------------|
|
||
| Количество маркеров | **Ровно 2** (диапазон) | Список (любое кол-во) | Список (любое кол-во) | **Одна** | **Одна** |
|
||
| Что отправляется | **Часть** payload (диапазон) | **Весь** payload (разрезанный) | **Весь** payload (разрезанный) | **Весь** payload | **Весь** payload |
|
||
| Функция разрешения pos | `resolve_range` | `resolve_multi_pos` | `resolve_multi_pos` | `resolve_pos` | `resolve_pos` |
|
||
| pos обязателен | **Да** (error если нет) | Нет (дефолт "2") | Нет (дефолт "2") | Нет (дефолт "2") | Нет (дефолт "2") |
|
||
| Вердикт | **Нет** (не выносит) | `VERDICT_DROP` | `VERDICT_DROP` | `VERDICT_DROP` | `VERDICT_DROP` |
|
||
| nodrop | Нет (не нужен) | Да | Да | Да | Да |
|
||
| Порядок отправки | Один сегмент | Прямой (1->2->3) | Обратный (3->2->1) | Прямой | Обратный |
|
||
| Фейковые сегменты | **Нет** | **Нет** | **Нет** | Да (до 4 шт.) | Да (до 4 шт.) |
|
||
| seqovl тип | Только число | Только число | **Маркер** | Только число | **Маркер** |
|
||
| Fooling к | Реальному сегменту | Всем сегментам | Всем сегментам | Только к фейкам | Только к фейкам |
|
||
| ipfrag | Да | Да | Да | **Нет** | **Нет** |
|
||
| Нужен отдельный drop | **Да** | Нет (встроен) | Нет (встроен) | Нет (встроен) | Нет (встроен) |
|
||
|
||
Проще говоря: `multisplit`, `multidisorder`, `fakedsplit` и `fakeddisorder` режут весь payload и сами выбрасывают оригинал, а `tcpseg` отправляет один выбранный кусок и оригинал не трогает, поэтому ему нужен отдельный `drop`.
|
||
|
||
---
|
||
|
||
## Практические примеры
|
||
|
||
Каждый пример — готовая строка для [[Zapret2/profile#Анатомия профиля|профиля]]; под ней объяснено, что получится на выходе.
|
||
|
||
### 1. Минимальный seqovl без сегментации (TLS)
|
||
|
||
```bash
|
||
--payload=tls_client_hello \
|
||
--lua-desync=tcpseg:pos=0,-1:seqovl=1 \
|
||
--lua-desync=drop
|
||
```
|
||
|
||
Отправляет весь payload с 1 нулевым байтом seqovl слева. Drop блокирует оригинал. Проще говоря: `pos=0,-1` — весь запрос, `seqovl=1` — один нулевой байт слева, `drop` не даёт оригиналу уйти следом (раздел [[#Вердикт и комбинация с drop|Вердикт и комбинация с drop]]).
|
||
|
||
### 2. seqovl с TLS-фейковым паттерном
|
||
|
||
```bash
|
||
--payload=tls_client_hello \
|
||
--lua-desync=tcpseg:pos=0,-1:seqovl=5:seqovl_pattern=0x1603030000 \
|
||
--lua-desync=drop
|
||
```
|
||
|
||
5-байтовый TLS record header как seqovl-prefix. DPI видит начало "нового" TLS record перед настоящим ClientHello. Паттерн задаёт `seqovl_pattern`, см. [[#seqovl_pattern|seqovl_pattern]].
|
||
|
||
### 3. seqovl с предзагруженным фейком и tls_mod
|
||
|
||
```bash
|
||
--payload=tls_client_hello \
|
||
--blob=seqovl_pat:@fake_tls.bin \
|
||
--lua-init=seqovl_pat=tls_mod(seqovl_pat,'rnd') \
|
||
--lua-desync=tcpseg:pos=0,-1:seqovl=#seqovl_pat:seqovl_pattern=seqovl_pat \
|
||
--lua-desync=drop
|
||
```
|
||
|
||
Blob загружается из файла, рандомизируется через `tls_mod`, используется как seqovl_pattern с размером blob в качестве seqovl. Здесь `tls_mod` — набор изменений blob перед отправкой (он подстраивает ClientHello под текущее соединение; опции — в [[Zapret2/desync/fake#Опции tls_mod|Опции tls_mod]]), `--blob=seqovl_pat:@fake_tls.bin` загружает blob из файла, а `--lua-init` готовит blob заранее.
|
||
|
||
### 4. Динамический случайный seqovl через luaexec
|
||
|
||
```bash
|
||
--lua-desync=luaexec:code='desync.rnd=brandom_az(math.random(5,10))' \
|
||
--lua-desync=tcpseg:pos=0,-1:seqovl=#rnd:seqovl_pattern=rnd \
|
||
--lua-desync=drop:payload=known
|
||
```
|
||
|
||
На каждый пакет генерируется случайная строка из букв a-z длиной 5-10 символов. Используется как seqovl_pattern, а её размер -- как значение seqovl. Drop только для known payload. `luaexec` выполняет произвольный Lua-код ([[desync]]), а `seqovl=#rnd` берёт размер blob `rnd`.
|
||
|
||
### 5. seqovl с padencap и tls_mod (продвинутый)
|
||
|
||
```bash
|
||
--payload=tls_client_hello \
|
||
--blob=seqovl_pat:@fake_tls.bin \
|
||
--lua-desync=luaexec:code="desync.patmod=tls_mod(seqovl_pat,'rnd,dupsid,padencap',desync.reasm_data)" \
|
||
--lua-desync=tcpseg:pos=0,-1:seqovl=#patmod:seqovl_pattern=patmod \
|
||
--lua-desync=drop
|
||
```
|
||
|
||
Динамическая модификация фейка с учётом реального payload (через `desync.reasm_data`). Паттерн маскируется под TLS с padding, рандомизацией и дублированием session ID. `padencap` подкорректирует blob так, чтобы оригинальный payload стал частью padding extension — подробнее в разделе [[Zapret2/desync/fake#padencap — подробности|padencap — подробности]]; `rnd` и `dupsid` — другие опции `tls_mod` ([[Zapret2/desync/fake#Опции tls_mod|Опции tls_mod]]).
|
||
|
||
### 6. Повторная отправка начала HTTP-запроса (без drop)
|
||
|
||
```bash
|
||
--payload=http_req \
|
||
--lua-desync=tcpseg:pos=0,method+2:ip_id=rnd:repeats=20
|
||
```
|
||
|
||
Отправляет начало HTTP-запроса до маркера `method+2` включительно — по коду это первые 3 байта, `GET` из `GET /` (почему не `GE`, объяснено в предупреждении к описанию аргумента `pos`) 20 раз со случайными IP ID. Оригинальный пакет тоже уходит (нет drop). Стратегия забивания буфера DPI. Здесь `ip_id=rnd` — случайные IP ID, а `repeats=20` — 20 копий сегмента (параметры описаны в разделах [[#E) Standard ipid|E) Standard ipid]] и [[#H) Standard rawsend|H) Standard rawsend]]).
|
||
|
||
### 7. Повторная отправка до midsld (TLS)
|
||
|
||
```bash
|
||
--payload=tls_client_hello \
|
||
--lua-desync=tcpseg:pos=0,midsld:ip_id=rnd:repeats=100
|
||
```
|
||
|
||
Отправляет начало ClientHello до середины SNI 100 раз. DPI может переполнить свой буфер и перестать анализировать поток.
|
||
|
||
### 8. Отправка только hostname
|
||
|
||
```bash
|
||
--payload=tls_client_hello \
|
||
--lua-desync=tcpseg:pos=host,endhost
|
||
```
|
||
|
||
Вырезает и отправляет **только** hostname из SNI. Без drop и без seqovl -- чисто для экспериментов или в составе сложной цепочки.
|
||
|
||
### 9. seqovl без сегментации + IP-фрагментация
|
||
|
||
```bash
|
||
--payload=tls_client_hello \
|
||
--lua-desync=tcpseg:pos=0,-1:seqovl=5:ipfrag:ipfrag_disorder:ipfrag_pos_tcp=32 \
|
||
--lua-desync=drop
|
||
```
|
||
|
||
Весь payload с seqovl отправляется, TCP-сегмент дополнительно фрагментируется на IP-уровне в обратном порядке. Параметры `ipfrag` описаны в разделе [[#F) Standard ipfrag|F) Standard ipfrag]].
|
||
|
||
### 10. Только первый байт TLS record (повторы)
|
||
|
||
```bash
|
||
--payload=tls_client_hello \
|
||
--lua-desync=tcpseg:pos=0,1:ip_id=rnd:repeats=260
|
||
```
|
||
|
||
Отправляет начало TLS record 260 раз. Несмотря на заголовок примера, по коду `pos=0,1` захватывает первые **два** байта (см. предупреждение к описанию аргумента `pos`). Используется в blockcheck2 для тестирования misc-стратегий.
|
||
|
||
### 11. Комбинация: fake + tcpseg + drop (полная стратегия)
|
||
|
||
```bash
|
||
--payload=tls_client_hello \
|
||
--lua-desync=fake:blob=fake_default_tls:tcp_md5:tls_mod=rnd,rndsni,dupsid \
|
||
--lua-desync=tcpseg:pos=0,-1:seqovl=5:seqovl_pattern=0x1603030000 \
|
||
--lua-desync=drop
|
||
```
|
||
|
||
1. `fake` отправляет фейковый TLS ClientHello с md5sig fooling
|
||
2. `tcpseg` отправляет настоящий payload с seqovl
|
||
3. `drop` блокирует оригинальный пакет
|
||
|
||
Здесь [[Zapret2/desync/fake#Зачем нужен fake|fake]] — отдельный пакет-обманка, который сервер отбрасывает из-за порчи заголовков (`tcp_md5` — вариант fooling), а `tls_mod` подстраивает фейковый ClientHello. Инстансы выполняются в порядке записи: сначала `fake`, затем `tcpseg`, затем `drop`.
|
||
|
||
### 12. Защита от отсутствующего blob
|
||
|
||
```bash
|
||
--lua-desync=tcpseg:pos=0,-1:blob=maybe_missing:optional:seqovl=5
|
||
```
|
||
|
||
Если blob `maybe_missing` не существует -- tcpseg тихо пропускает. Без ошибок. Флаг `optional` описан в разделе [[#A) Собственные аргументы tcpseg|A) Собственные аргументы tcpseg]].
|
||
|
||
### 13. HTTP: seqovl=1 + drop (минимальный рабочий пример)
|
||
|
||
```bash
|
||
--payload=http_req \
|
||
--lua-desync=tcpseg:pos=0,-1:seqovl=1 \
|
||
--lua-desync=drop
|
||
```
|
||
|
||
Один нулевой байт seqovl перед HTTP-запросом. Минимальная модификация, но может обмануть DPI, который ожидает HTTP-метод с первого байта TCP-потока.
|
||
|
||
### 14. wssize + tcpseg + drop (контроль TCP window)
|
||
|
||
```bash
|
||
--payload=tls_client_hello \
|
||
--lua-desync=wssize:wsize=1:scale=6 \
|
||
--lua-desync=tcpseg:pos=0,-1:seqovl=5:seqovl_pattern=fake_default_tls \
|
||
--lua-desync=drop
|
||
```
|
||
|
||
Сначала `wssize` устанавливает маленький TCP window, затем `tcpseg` отправляет payload с seqovl, и `drop` блокирует оригинал. Здесь `wssize` подменяет размер TCP window — поле в заголовке TCP, которым получатель сообщает, сколько байт он готов принять (`wsize=1:scale=6` — параметры окна); почему это крайняя мера, разобрано в [[Zapret/wssize|отдельной заметке]].
|
||
|
||
---
|
||
|
||
## Варианты tcpseg без drop из набора стратегий GUI
|
||
|
||
Для каталога стратегий [[guide|Zapret 2 GUI]] готовился набор «упрощённых» вариантов на `tcpseg`. Их идея: вместо того чтобы резать ClientHello на части, как [[multisplit]], отправить его одним сегментом и спрятать перед ним чужие данные через seqovl. Набор полезен как иллюстрация того, как `tcpseg` ведёт себя без `drop`, но в его исходном описании были ошибки: он обещал «один пакет вместо двух» и меньшую нагрузку на сеть. Ниже варианты разобраны заново, с поправками по исходному коду `lua/zapret-antidpi.lua`.
|
||
|
||
> [!warning] Названия и состав могут отличаться от текущего GUI
|
||
> Набор описан по черновику каталога стратегий. В каталоге GUI `strategy_catalogs/winws2/tcp.txt` этих вариантов на сентябрь 2026 нет, поэтому внутренние имена (`tcpseg_226_simple` и т.п.) и номера файлов `tls_clienthello_*.bin` проверяйте в своей версии программы. В черновике перед флагами стратегии стоял общий фильтр категории, который GUI подставляет сам, — ниже он опущен.
|
||
|
||
### Общая часть всех вариантов
|
||
|
||
Каждый вариант строится из одних и тех же деталей. Сначала через `--blob` загружается готовый TLS ClientHello из файла программы, например `--blob=bin_tls18:@bin\tls_clienthello_18.bin` (что такое блоб — в [[blob]]). Затем идут фильтры: [[payload|--payload=tls_client_hello]] ограничивает стратегию первым сообщением TLS, а [[out-range|--out-range=-d10]] — первыми десятью пакетами с данными. После них вызывается сама функция:
|
||
|
||
```bash
|
||
--lua-desync=tcpseg:pos=0,-1:seqovl=226:seqovl_pattern=bin_tls18
|
||
```
|
||
|
||
Маркеры `pos=0,-1` берут весь ClientHello целиком. `seqovl=226` добавляет перед ним 226 байт из блоба `bin_tls18` и сдвигает номер последовательности сегмента на 226 назад (механика — в разделе [seqovl -- скрытый фейк внутри сегмента](#seqovl----скрытый-фейк-внутри-сегмента)). Сервер считает эти 226 байт уже пройденной частью потока и отбрасывает их, а DPI, который не учитывает перекрытие, видит в начале потока постороннее содержимое.
|
||
|
||
Проще говоря: DPI первым делом натыкается на начало чужого ClientHello из файла, а сервер получает только настоящий.
|
||
|
||
### Главная поправка: оригинал тоже уходит
|
||
|
||
Во всех вариантах набора нет `--lua-desync=drop`. Как разобрано в нюансе «Не выносит вердикт -- нужен drop», `tcpseg` не блокирует оригинальный пакет. Поэтому в сеть уходят **два** пакета: сегмент с seqovl и следом нетронутый оригинальный ClientHello с настоящим SNI. Утверждение «один пакет без резки» неверно, и экономии трафика по сравнению с [[multisplit]] нет: `multisplit` сам выносит `VERDICT_DROP` и отправляет только нарезанные части, а здесь к оригиналу добавляется ещё один полноразмерный сегмент.
|
||
|
||
Что это значит на практике, зависит от варианта:
|
||
|
||
- **без fooling** сервер принимает данные из сегмента с seqovl, а оригинал отбрасывает как повтор. DPI видит оба пакета, и сработает ли обход, зависит от того, по какому из них DPI принимает решение;
|
||
- **с fooling** (последние три строки таблицы ниже) сервер отбрасывает сам сегмент с seqovl, потому что fooling в `tcpseg` применяется к реальному сегменту (нюанс 7). Сегмент превращается в фейк, который видит только DPI, а соединение продолжается на оригинале. По смыслу это ближе к [[fake]], чем к сегментации.
|
||
|
||
Оба поведения подтверждены на стенде (сентябрь 2026, `nfqws2` и TLS-сервер на Linux): без fooling сервер принял данные из сегмента с seqovl, а оригинал пришёл повтором; с `tcp_ack=-66000` или `tcp_flags_unset=ack` сервер сегмент отверг и принял оригинал. В обоих случаях соединение устанавливалось без задержки.
|
||
|
||
Чтобы получить классическую схему, где до сервера доходит только сегмент с seqovl, добавьте `drop` в конце, как в разделе «Быстрый старт»: `--lua-desync=tcpseg:pos=0,-1:seqovl=226:seqovl_pattern=bin_tls18 --lua-desync=drop`.
|
||
|
||
### Таблица вариантов
|
||
|
||
| Вариант | Что добавлено к общей части | Флаги (без загрузки блоба) |
|
||
|:--|:--|:--|
|
||
| Простой seqovl | Перекрытие 211, 226, 286 или 308 байт шаблонами `tls_clienthello_5`, `_18`, `_11`, `_9` соответственно | `--lua-desync=tcpseg:pos=0,-1:seqovl=226:seqovl_pattern=bin_tls18` |
|
||
| Дубль первого пакета | Перед `tcpseg` копии ClientHello на первом пакете с данными | `--out-range=-d1 --lua-desync=send:repeats=2 --out-range=-d10 --lua-desync=tcpseg:…` |
|
||
| Дубль в первых трёх пакетах | То же, но окно считается по всем перехваченным пакетам | `--out-range=-n3 --lua-desync=send:repeats=2 --out-range=-d10 --lua-desync=tcpseg:…` |
|
||
| Google SNI без файлов | Шаблон собирается из встроенного `fake_default_tls` с SNI `www.google.com` | `--lua-init="tls_google = tls_mod(fake_default_tls,'sni=www.google.com')"` и `seqovl_pattern=tls_google` |
|
||
| datanoack | У сегмента снят флаг ACK, сервер его отбросит | `…:seqovl_pattern=bin_tls18:tcp_flags_unset=ack` |
|
||
| Фиксированный TTL | Сегмент живёт 5 хопов и не доходит до сервера | `…:seqovl_pattern=bin_tls18:ip_ttl=5:ip6_ttl=5` |
|
||
| badseq | Номер подтверждения сдвинут на −66000 | `…:seqovl_pattern=bin_tls18:tcp_ack=-66000` |
|
||
|
||
Про строки с дублями. Функция `send` отправляет копию текущего пакета и сама его не блокирует, поэтому `repeats=2` добавляет две копии поверх оригинала. Действует она только на ClientHello, потому что выше стоит `--payload=tls_client_hello`. В черновике вариант с `-n3` описывался как «дублирование первых трёх пакетов», но это не так: `n` считает все перехваченные пакеты соединения, включая рукопожатие, а фильтр payload пропускает к `send` только ClientHello. Какой по счёту пакет окажется ClientHello, зависит от того, какие пакеты перехватывает WinDivert, — это разобрано в [[zapret2_start_cutoff]]. Формат диапазонов — в [[out-range]].
|
||
|
||
Про строки с fooling. `ip_ttl=5` жёстко задаёт время жизни: если сервер ближе пяти хопов, сегмент до него дойдёт и схема поведёт себя как вариант без fooling. `tcp_ack=-66000` на Linux-серверах надёжно отбрасывается только вместе с `tcp_ts_up`. Подробнее обо всех обманках — в [[основные флаги]] и [[ts-and-fooling]].
|
||
|
||
### С чего начинать проверку
|
||
|
||
Разумный порядок — от простого к сложному: сначала вариант с Google SNI без дублей (ему не нужны файлы), затем тот же вариант с дублем, и только если оба не помогли — стратегии с резкой через [[multisplit]] или [[multidisorder]]. Проверять каждую ступень нужно новым соединением, а не обновлением вкладки: автоподбор и F5 легко показывают ложный успех, см. [[verify-strategy]].
|
||
|
||
---
|
||
|
||
## 📚 См. также
|
||
|
||
- [[desync]] — обзор всех функций `--lua-desync` и общий контракт: кто вызывает функцию, что ей передаёт и как складываются вердикты
|
||
- [[жизненный цикл desync-функции]] — восемь стадий, общих для всех техник дурения: отсев транспорта, выбор данных, replay, вердикты
|
||
- [[структура desync и диссекта]] — устройство таблицы `desync` и диссекта пакета
|
||
- [[multisplit]] — разрез всего payload на несколько сегментов с собственным вердиктом `VERDICT_DROP`; там же подробный разбор seqovl
|
||
- [[multidisorder]] — тот же разрез, но сегменты уходят в обратном порядке; seqovl там работает иначе
|
||
- [[fakedsplit]] · [[fakeddisorder]] — разрез по одной позиции с подмешиванием фейковых сегментов
|
||
- [[hostfakesplit]] — разрез по границам имени хоста с подмешиванием фейкового имени
|
||
- [[oob]] — сегментация с urgent-байтом вместо разреза
|
||
- [[fake]] — отдельный фейковый пакет, с которым `tcpseg` комбинируют в полной стратегии
|
||
- [[blob]] — как объявлять и передавать данные для аргументов `blob` и `seqovl_pattern`
|
||
- [[payload]] — распознавание типов протоколов, от которого зависит работа относительных маркеров
|
||
- [[ts-and-fooling]] — опции fooling и почему в `tcpseg` большинство из них вредны
|
||
- [[verify-strategy]] — как честно проверить, работает ли подобранная комбинация
|
||
- [[последовательность аргументов]] — как выстраивается цепочка инстансов в профиле
|
||
- [[profile]] — где `--lua-desync` живёт среди остальных настроек
|
||
- [[DPI/DPI|DPI и ТСПУ]] — как устроена инспекция трафика, против которой работает `tcpseg`
|
||
|
||
---
|
||
|
||
> **Источники:** `lua/zapret-antidpi.lua:1030-1076`, `nfq2/lua.c:3281-3328` (resolve_range), `docs/manual.md:4248-4274`, `docs/readme.md:394-412`, `blockcheck2.d/standard/15-misc.sh`, `blockcheck2.d/standard/23-seqovl.sh` из репозитория zapret2.
|
||
|
||
---
|
||
|
||
> [!quote] 🤖 Эти статьи открыты — можно обучать на них ИИ
|
||
> При желании вы можете натренировать ИИ на наших статьях. Исходное форматирование доступно в Forgejo: [исходник этой заметки](https://git2.zapret.moe/zapretdiscordyoutube/todo/src/branch/main/Zapret2/desync/tcpseg.md) · [скачать весь репозиторий одним zip-архивом](https://git2.zapret.moe/zapretdiscordyoutube/todo/archive/main.zip).
|