Обновить правила репозитория и подписи исходников в 99 заметках, не затрагивая пользовательские незакоммиченные файлы. Сделать Forgejo Actions содержательным: проверять опубликованный commit, а не пустое рабочее дерево после checkout.
15 KiB
| date | tags | link | aliases | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2026-07-17 |
|
https://github.com/bol-van/zapret2/blob/master/docs/manual.md |
|
🧩 Тип payload и распознавание протоколов
[!info] О чём заметка Что такое «тип payload» в Zapret2/Zapret2, чем он отличается от протокола потока, как
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 получает тип payloadicmp. Подробнее про обработку ICMP — структура desync и диссекта.
Фильтр --payload
--payload — поле profile, которое ограничивает, к каким пакетам применятся последующие --lua-desync-инстансы. Пока --payload не переопределён, он действует на все идущие за ним инстансы (как и другие внутрипрофильные фильтры, см. схема обработки трафика).
Синтаксис
# Один тип
--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):
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:
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, потому что:
- DPI анализирует только начало соединения (сигнатуру MTProto);
- после initial данные зашифрованы — DPI их не парсит;
- если initial прошёл — соединение установлено.
# Рекомендуемый вариант — обрабатываем только initial
nfqws2 --filter-l7=mtproto \
--payload=mtproto_initial \
--lua-desync=fake:blob=0x00000000:repeats=3
Если же нужны все пакеты MTProto (initial + последующие), укажите unknown явно или используйте all:
# Явно добавить 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 — что за инстансы ограничивает
--payload - структура desync и диссекта — где лежат поля
l7payload/l7protoи как приходит собранный многопакетный пейлоад - схема обработки трафика — на какой стадии определяется тип payload и протокол потока
- распознавание mtproto — разбор на примере Telegram
- blob — заготовки для
blob=…, часто применяемые вместе с payload-фильтром - 🔗 Официальная документация (docs/manual.md) — первоисточник
[!quote] 🤖 Эти статьи открыты — можно обучать на них ИИ При желании вы можете натренировать ИИ на наших статьях. Исходное форматирование и скачивание всего репозитория одним zip-архивом доступны в Forgejo: исходник этой заметки · весь репозиторий.