todo/Zapret2/payload.md
loop-uh 08b4491545
Some checks failed
Published content check / validate (push) Failing after 3s
Завершить переезд базы знаний на Forgejo
Обновить правила репозитория и подписи исходников в 99 заметках, не затрагивая пользовательские незакоммиченные файлы. Сделать Forgejo Actions содержательным: проверять опубликованный commit, а не пустое рабочее дерево после checkout.
2026-08-07 08:27:28 +03:00

210 lines
15 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

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

---
date: 2026-07-17
tags:
- zapret
- zapret2
- nfqws2
- payload
- filter
- l7
- protocol-detection
link: https://github.com/bol-van/zapret2/blob/master/docs/manual.md
aliases:
- Тип payload
- --payload
- l7payload
- Распознавание протоколов
- Типы пейлоада
---
# 🧩 Тип payload и распознавание протоколов
> [!info] О чём заметка
> Что такое «тип payload» в [[Zapret2/Zapret2|Zapret 2]], чем он отличается от протокола потока, как `nfqws2` распознаёт протоколы по сигнатурам, какие типы бывают и как работает фильтр `--payload`. Также — как объявить **свой** детектор протокола на Lua. Фильтр `--payload` — одно из полей [[profile|профиля]] рядом с [[filter|`--filter-*`]]; где поля `l7payload`/`l7proto` лежат в данных пакета — см. [[структура desync и диссекта]].
## TL;DR
- **Тип payload** (`l7payload`) — это распознанное содержимое **одного пакета**: `tls_client_hello`, `http_req`, `quic_initial` и т. д. Пустой пакет — `empty`, нераспознанный — `unknown`.
- **Протокол потока** (`l7proto`) — ярлык на **всё соединение**; ставится по первому известному пейлоаду и держится до конца, даже если дальше идут `unknown`-пакеты.
- Фильтр **`--payload`** ограничивает, к каким пакетам применится последующий [[desync|`--lua-desync`]]. По умолчанию `known` (всё, кроме `empty` и `unknown`).
- Спецзначения фильтра: **`all`** — любой пейлоад, **`known`** — не `empty` и не `unknown`. Префикс **`~`** — инверсия.
- Распознавание **сигнатурное** и живёт в C-ядре. Свой тип можно назначить Lua-детектором (`detect_payload_str`), но такой тип **не виден** C-фильтру `--payload` — только payload-фильтрам самих desync-функций.
---
## Что такое тип payload (и чем он отличается от протокола потока)
Это два разных понятия, и их постоянно путают.
**Тип payload** (в данных пакета — поле `desync.l7payload`) — это распознанный тип содержимого **одного конкретного пакета**. Например, в TLS-соединении первый пакет от клиента имеет тип `tls_client_hello`, ответ сервера — `tls_server_hello`, а дальше идут уже зашифрованные пакеты, которые распознать нельзя, — их тип `unknown`.
**Протокол потока** (поле `desync.l7proto`, а в фильтрах профиля — [[filter|`--filter-l7`]]) — это ярлык на **всё соединение целиком**. Он присваивается, как только в потоке встретился первый известный пейлоад, и остаётся с потоком **до конца его существования** — даже если последующие пакеты имеют тип `unknown`.
> [!note] Проще говоря
> Протокол потока — как табличка на двери всего «разговора»: повесили один раз («это TLS») и не меняем. Тип payload — как ярлык на каждой отдельной реплике внутри разговора: у первой реплики `tls_client_hello`, у следующих может быть `unknown`. Одно соединение (`tls`) → много пакетов с разными типами payload.
Два особых типа payload есть всегда:
- **`empty`** — пакет без прикладных данных (например, «пустой» ACK).
- **`unknown`** — данные есть, но их тип не распознан (зашифрованная середина соединения, неизвестный протокол).
Полное описание, где именно поля `l7payload` и `l7proto` лежат в таблице пакета, — в [[структура desync и диссекта]].
---
## Как `nfqws2` распознаёт протоколы
Распознавание **сигнатурное**: C-ядро `nfqws2` смотрит на характерные байты в начале пейлоада (или группы пакетов) и по ним определяет тип. Это происходит на быстрой стороне C-кода ещё до вызова Lua (см. [[схема обработки трафика]]).
В фильтрах по типу payload и по протоколу потока доступны два спецзначения:
- **`all`** — совпадает с любым пейлоадом (в том числе `empty` и `unknown`);
- **`known`** — совпадает со всем, что **не** `empty` и **не** `unknown` (то есть только с реально распознанными типами).
### Таблица распознаваемых типов
Ниже — какие протоколы потока `nfqws2` умеет распознавать, на каком транспорте (L4) они работают и какие типы payload внутри них бывают.
| Протокол потока | L4 | Типы payload внутри |
|:----------------|:---|:--------------------|
| `http` | TCP | `http_req`, `http_reply` |
| `tls` | TCP | `tls_client_hello`, `tls_server_hello` |
| `xmpp` | TCP | `xmpp_stream`, `xmpp_starttls`, `xmpp_proceed`, `xmpp_features` |
| `mtproto` | TCP | `mtproto_initial` |
| `bt` | TCP | `bt_handshake` |
| `quic` | UDP | `quic_initial` |
| `wireguard` | UDP | `wireguard_initiation`, `wireguard_response`, `wireguard_cookie`, `wireguard_keepalive` |
| `dht` | UDP | `dht` |
| `utp_bt` | UDP | `utp_bt_handshake` |
| `discord` | UDP | `discord_ip_discovery` |
| `stun` | UDP | `stun` |
| `dns` | UDP | `dns_query`, `dns_response` |
| `dtls` | UDP | `dtls_client_hello`, `dtls_server_hello` |
| *(любой)* | ICMP | `ipv4`, `ipv6`, `icmp` |
> [!note] Особые типы `ipv4` / `ipv6` / `icmp`
> Это типы payload для ICMP-пакетов. `ipv4` и `ipv6` генерируются, когда ICMP несёт **прикреплённый исходный пакет** (например, ICMP «destination unreachable» с куском исходного соединения). Во всех остальных случаях ICMP получает тип payload `icmp`. Подробнее про обработку ICMP — [[структура desync и диссекта]].
---
## Фильтр `--payload`
`--payload` — поле [[profile|профиля]], которое ограничивает, к каким пакетам применятся **последующие** `--lua-desync`-инстансы. Пока `--payload` не переопределён, он действует на все идущие за ним инстансы (как и другие внутрипрофильные фильтры, см. [[схема обработки трафика]]).
### Синтаксис
```bash
# Один тип
--payload=tls_client_hello
# Несколько типов через запятую
--payload=http_req,http_reply
# Все известные типы (не empty и не unknown) — это же значение по умолчанию
--payload=known
# Вообще все пакеты, включая empty и unknown
--payload=all
# Инверсия: всё, КРОМЕ указанного
--payload=~empty
```
### Значение по умолчанию — `known`
Если `--payload` не указан, используется `known`. Вот реальный код фильтра (`lua/zapret-lib.lua`):
```lua
function payload_match_filter(l7payload, l7payload_filter, def)
local argpl = l7payload_filter or def or "known"
local neg = string.sub(argpl,1,1)=="~"
local pl = neg and string.sub(argpl,2) or argpl
return neg ~= (in_list(pl, "all") or in_list(pl, l7payload) or in_list(pl, "known") and l7payload~="unknown" and l7payload~="empty")
end
```
По умолчанию (`known`) фильтр:
- ✅ пропускает любой распознанный payload (`tls_client_hello`, `mtproto_initial`, `http_req`, …);
-**не** пропускает `unknown`;
-**не** пропускает `empty`.
Инверсия через `~` означает «всё, кроме»: `--payload=~empty` — любой непустой пакет, `--payload=~unknown` — всё, кроме нераспознанного.
> [!important] `--payload` (C-уровень) vs payload-фильтр инстанса (Lua)
> `--payload` на уровне профиля обрабатывается быстрым C-кодом. У многих desync-функций есть **свой** аргумент `payload=` — это дополнительный фильтр уже на стороне Lua. Практика: держите основной фильтр на `--payload` профиля (быстрее), а `payload=` инстанса используйте для тонкой донастройки. Разница станет важной ниже, в разделе про кастомные детекторы.
---
## Свой детектор протокола на Lua (`detect_payload_str`)
Иногда нужного протокола нет в списке распознаваемых, но у его пакетов есть характерная подстрока. Тогда тип payload можно назначить самому — простейшим Lua-детектором. В комплекте есть пример-функция `detect_payload_str`:
```lua
function detect_payload_str(ctx, desync)
-- arg: pattern — подстрока для поиска в desync.dis.payload
-- arg: payload — какое значение присвоить desync.l7payload, если подстрока найдена
-- arg: undetected — какое значение присвоить, если подстрока НЕ найдена (необязательно)
end
```
Логика простая: функция ищет подстроку `pattern` в пейлоаде текущего пакета (`desync.dis.payload`); если находит — присваивает `desync.l7payload = desync.arg.payload`; иначе, если задан `undetected`, присваивает `desync.l7payload = desync.arg.undetected`.
> [!warning] Кастомный тип не виден C-коду и фильтру `--payload`
> Такие Lua-детекторы **не имеют силы для C-кода**: ядро ничего не знает о вашем протоколе и вашем типе payload. Поэтому ваше значение **нельзя** указать в `--payload` (это C-уровневый фильтр). Но его **можно** использовать в payload-фильтрах (`payload=`) многих desync-функций — они работают уже на стороне Lua, после того как ваш детектор отработал. Схема такая: сначала инстанс `detect_payload_str` проставляет `l7payload`, а следующий инстанс с `payload=ваш_тип` на него реагирует.
---
## Практика: MTProto (Telegram)
Хороший пример, где важна разница «пакет vs поток». В соединении MTProto распознаётся только первый пакет:
| Пакет | `l7payload` | Пройдёт фильтр `known`? |
|:------|:------------|:------------------------|
| Первый пакет с данными | `mtproto_initial` | ✅ Да |
| Последующие пакеты | `unknown` | ❌ Нет |
Нужно ли добавлять `payload=unknown`? Обычно **нет**. Для обхода блокировки Telegram, как правило, достаточно обработать только `mtproto_initial`, потому что:
1. DPI анализирует только начало соединения (сигнатуру MTProto);
2. после initial данные зашифрованы — DPI их не парсит;
3. если initial прошёл — соединение установлено.
```bash
# Рекомендуемый вариант — обрабатываем только initial
nfqws2 --filter-l7=mtproto \
--payload=mtproto_initial \
--lua-desync=fake:blob=0x00000000:repeats=3
```
Если же нужны **все** пакеты MTProto (initial + последующие), укажите `unknown` явно или используйте `all`:
```bash
# Явно добавить unknown-пакеты отдельным фильтром
nfqws2 --filter-l7=mtproto \
--payload=mtproto_initial --lua-desync=fake:blob=... \
--payload=unknown --lua-desync=send:ip_ttl=3
# Или разом все пакеты
nfqws2 --filter-l7=mtproto \
--payload=all \
--lua-desync=fake:blob=...
```
Детальный разбор распознавания Telegram — в [[распознавание mtproto]].
---
## 📚 См. также
- [[filter|Фильтры профиля]] — `--filter-l7` (протокол потока) и другие фильтры рядом с `--payload`
- [[desync|Механизм --lua-desync]] — что за инстансы ограничивает `--payload`
- [[структура desync и диссекта|Структура desync]] — где лежат поля `l7payload`/`l7proto` и как приходит собранный многопакетный пейлоад
- [[схема обработки трафика|Схема обработки трафика]] — на какой стадии определяется тип payload и протокол потока
- [[распознавание mtproto|Распознавание MTProto]] — разбор на примере Telegram
- [[blob|Blob-данные]] — заготовки для `blob=…`, часто применяемые вместе с payload-фильтром
- 🔗 [Официальная документация (docs/manual.md)](https://github.com/bol-van/zapret2/blob/master/docs/manual.md) — первоисточник
---
> [!quote] 🤖 Эти статьи открыты — можно обучать на них ИИ
> При желании вы можете натренировать ИИ на наших статьях. Исходное форматирование и скачивание всего репозитория одним zip-архивом доступны в Forgejo: [исходник этой заметки](https://git.zapret.moe/zapretdiscordyoutube/todo/src/branch/main/Zapret2/payload.md) · [весь репозиторий](https://git.zapret.moe/zapretdiscordyoutube/todo/src/branch/main).