---
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).
