todo/Zapret2/exclusions.md
loop-uh baf0091fa3
Some checks failed
Published content check / validate (push) Failing after 17s
git.zapret.moe → git2.zapret.moe во всём хранилище, защита от возврата старых имён
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>
2026-10-24 15:51:32 -04:00

187 lines
36 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-08-16
tags:
- zapret
- zapret2
- gui
- preset
- profile
- exclusions
- troubleshooting
aliases:
- Исключения
- Исключения в Запрете
- Есть ли в Zapret 2 строчка Исключения
- Как добавить сайт в исключения Zapret
- Куда вписать IP и домены чтобы Запрет их не трогал
- Профиль pass
- pass ничего не делает
- hostlist-exclude и ipset-exclude
- Как исключить свой сайт из Zapret
- Общий профиль для исключений доменов
description: "Как исключить сайт из Zapret 2: профиль со стратегией pass или hostlist-exclude/ipset-exclude, порядок профилей и пошаговый пример в GUI."
---
> [!mirror] Резервное зеркало
> Актуальная версия этой страницы — на основной вики: [wiki2.zapret.moe/Zapret2/exclusions](https://wiki2.zapret.moe/Zapret2/exclusions)
# 🚫 Исключения в Zapret 2: почему такой кнопки нет и как они устроены на самом деле
![[exclusions-header-rkn-zapret-chan.png]]
> [!info] О чём заметка
> Отвечает на частый вопрос: «есть ли в [[Zapret2/Zapret2|Zapret 2]] строчка "Исключения", куда можно накидать IP-адреса и домены, чтобы программа их не трогала?» Короткий ответ — **такой строчки нет, и это сделано намеренно**. То, что пользователи называют исключениями, в Zapret 2 реализуется двумя разными механизмами: [[profile|профилем]] со стратегией `pass` и исключающими списками `--hostlist-exclude`/`--ipset-exclude`. Заметка разбирает оба, их разницу и подводные камни. Основа — разбор от разработчика Zapret 2 GUI в чате поддержки (август 2026); описанная механика движка сверена с исходным кодом `nfqws2` (файлы `nfq2/desync.c`, `nfq2/hostlist.c`, `nfq2/ipset.c`, Lua-библиотеки; август 2026).
## TL;DR
- **Глобального поля «Исключения» на весь [[preset|пресет]] не существует** — ни в GUI, ни в формате пресета. Есть только условия отбора трафика (включающие и исключающие) и профили со стратегиями.
- **Исключение делается двумя способами**: отдельный профиль со стратегией `pass` («ничего не делать») ИЛИ исключающий список `--hostlist-exclude`/`--ipset-exclude` внутри профиля.
- Логика у них **разная**, но результат в типичном пресете **одинаковый**: пакеты ресурса идут как есть, напрямую, без [[desync|дурения]].
- Исключение — это **не особая сущность, а обычный профиль** (или условие в нём). Поэтому на него действуют общие правила: [[profile#Порядок профилей важен|порядок «выше = главнее»]], first-match-wins, конфликты списков.
- Практический рецепт: создать [[add-profile|новый профиль]], выбрать стратегию `pass (ничего не делает)`, накидать в его список нужные домены или IP и поставить профиль **выше** остальных.
## Откуда берётся вопрос про «строчку Исключения»
Привычка приходит из других программ: в VPN-клиентах и файрволах обычно есть одно глобальное поле «исключения», действующее на всё приложение сразу. Пользователь открывает настройки пресета Zapret 2, ищет такое же поле, не находит — и спрашивает, куда вписывать адреса.
По объяснению разработчика Zapret 2 GUI (чат поддержки, август 2026), понятия «исключение на весь пресет» в движке просто не существует. [[preset|Пресет]] — это набор [[profile|профилей]], каждый из которых сам решает, какой трафик он ловит ([[filter|фильтры]] и списки) и что с ним делает ([[desync|стратегия]]). «Нельзя нигде в пресете написать исключения — есть только включающее или исключающее условие»: `--hostlist`/`--ipset` против `--hostlist-exclude`/`--ipset-exclude`. GUI сознательно спроектирован без отдельной кнопки «Исключения» — чтобы новичок с самого начала мыслил профилями, а не воображаемым глобальным списком: исключения лежат среди обычных профилей, где их можно двигать, менять им стратегию и списки.
Проще говоря: в Zapret 2 «исключить сайт» — значит не «вписать его в особое поле», а «сделать так, чтобы его пакеты прошли через программу без изменений». А этого можно добиться двумя способами, у которых под капотом разная механика.
> [!note] Единственное «глобальное» исключение живёт уровнем ниже профилей
> Отсечь трафик от программы целиком можно только на слое захвата — глобальным фильтром [[wf|WinDivert]] (флаги `--wf-*` в шапке пресета): такой трафик вообще не попадает в движок. Но это фильтр по портам и IP-адресам — исключить **домен** на этом уровне невозможно, поэтому для сайтов остаются два механизма, разобранные ниже.
## Что вообще называют исключением
Исключение — это ресурс (домен или IP-диапазон), чей трафик должен пройти **мимо дурения**: без фейковых пакетов, нарезки и прочих манипуляций. Точный авторский термин для этих манипуляций — **десинхронизация** (desync): так bol-van, автор движка, называет атаки на DPI, при которых поток пакетов формируется так, что DPI собирает из него искажённую картину и «рассинхронизируется» с тем, что реально видит сервер; отсюда и имя флага стратегии `--lua-desync`. «Дурение» — его же, более разговорное название тех же приёмов (в официальной документации есть разделы «Дурение http» и «Дурение udp»), в заметках оба слова используются как синонимы; полный разбор стратегий — [[desync]]. Зачем нужны исключения: Zapret обходит DPI, намеренно «портя» исходящие пакеты, но незаблокированному сайту такие манипуляции только вредят — настоящий сервер может принять фейки за мусор и сбросить соединение (подробно — [[symptom-not-cause|«не работает» — это симптом]]). Типичный пример — российские сайты: в стоковых пресетах для них заведены профили-исключения, стоящие в начале списка. С обновления встроенных пресетов (август 2026) их два, оба со стратегией `pass`: «Исключения айпи (RU сайты)» — по [[ipset|спискам IP]], и «Исключения домены (RU сайты)» — по [[hostlist|хостлисту]] `netrogat.txt` (традиционное для сборок Zapret имя списка «не трогать»: незаблокированные домены, которым дурение только вредит). В пресетах до августа 2026 профиль один — «Исключения (RU сайты)», только по IP; именно это имя видно на скриншотах ниже.
## Как движок выбирает профиль: три факта, без которых исключения не понять
![[wiki-anim-z2-profilepick.svg|Анимация: четыре соединения ищут свой профиль сверху вниз; первый совпавший побеждает, если не подошёл ни один — скрытый no_action]]
Оба механизма исключений опираются на одну и ту же процедуру выбора профиля. Полный справочник фильтров — в [[filter|отдельной заметке]]; здесь — тот минимум, на который дальше ссылается весь текст.
**Факт 1: сверху вниз, побеждает первый.** Для каждого нового соединения движок перебирает [[profile|профили]] пресета по порядку, сверху вниз, и берёт **первый**, у которого совпали все фильтры: порты, протокол, списки доменов и IP. На этом поиск заканчивается — два подходящих профиля никогда не работают «вместе», всегда побеждает тот, что выше (first-match-wins). Отсюда главное правило исключений: их профиль должен стоять выше конкурентов.
**Факт 2: выбор кэшируется и пересматривается максимум дважды.** Найденный профиль запоминается в записи соединения (conntrack — таблица активных соединений, которую движок ведёт у себя), поэтому заново профиль **не** ищется на каждый пакет. Пересмотр случается не больше двух раз за соединение: когда движок распознаёт протокол потока (L7) и когда узнаёт имя хоста из SNI. И важная деталь: пересмотр — это не «продолжить поиск вниз с текущего места», а **полный поиск заново с самого верха списка**. Профиль с неизменными условиями (например, отбирающий по IP) при пересмотре выигрывает повторно — это ключ к подводному камню со смешением IP и доменов, разобранному ниже. Полная схема — в [[схема обработки трафика|схеме обработки трафика]].
**Факт 3: в конце каждого пресета стоит скрытый профиль `no_action`.** Его нет ни в файле пресета, ни в настройках GUI — движок при запуске сам дописывает его последним в список, под служебным номером 0. Фильтров у него нет, поэтому он совпадает с любым трафиком; стратегий у него тоже нет, поэтому он ничего не делает. Именно этот профиль подбирает всё, что не совпало ни с одним видимым профилем, — поэтому «не попасть никуда» в Zapret 2 означает то же, что попасть в исключение: трафик уходит нетронутым. По сути `no_action` — это встроенное «исключение по умолчанию» для всего, что пресет не покрывает.
Увидеть `no_action` вживую можно в логах: [[log-analyzer|анализатор логов]] показывает его в колонке «Профиль» как `0 (no_action)` — наравне с обычными профилями вроде «Исключения (RU сайты)». Это те соединения, которые не совпали ни с одним профилем пресета и прошли без обработки:
![[log-no-action-profile.png]]
Проще говоря: движок — это одна очередь профилей с гарантированной заглушкой в конце. Исключения не образуют отдельной подсистемы — они просто занимают места в этой очереди (профиль `pass`) или меняют условия совпадения её элементов (exclude-списки).
## Механизм 1: профиль со стратегией `pass`
Первый способ — завести отдельный профиль, который **ловит** трафик нужных ресурсов (через [[hostlist]] или [[ipset]]), но в качестве стратегии имеет `pass` — «ничего не делать». Такой профиль честно выигрывает конкуренцию за соединение по общим правилам (факт 1) и забирает его себе — до профилей ниже этот трафик уже не доходит.
Важный нюанс: такие пакеты **всё равно проходят через Zapret**. Их захватывает [[wf|WinDivert]], движок прогоняет соединение по профилям и выбирает `pass`-профиль — просто на выходе пакеты не изменены, байт в байт. При этом `pass` — не выдумка GUI, а штатная функция Lua-библиотеки движка: она буквально не делает ничего, только пишет строку в debug-лог. Исключение не «прячет» трафик от программы, а прогоняет его через неё вхолостую.
> [!note] `pass` по доменам не действует на самые первые пакеты
> Профиль, отбирающий трафик по [[hostlist|хостлисту]], не участвует в выборе, пока движок не увидел имя хоста (SNI в TLS ClientHello). Поэтому SYN и все пакеты до ClientHello достаются другому профилю — и если у того есть стратегия «нулевой фазы» вроде [[syndata]], она успеет отработать до того, как соединение перескочит на `pass`-профиль. У исключения по [[ipset|ипсету]] такого лага нет: IP известен с первого пакета.
В GUI стратегия так и называется — `pass (ничего не делает)`, выбирается в «Готовых стратегиях» профиля как любая другая:
![[pass-strategy-gui.png]]
## Механизм 2: исключающие списки `--hostlist-exclude` / `--ipset-exclude`
Второй способ — исключающее условие **внутри** профиля: «этот профиль срабатывает для всех, **кроме** доменов/IP из такого-то списка». Флаги `--hostlist-exclude` (домены) и `--ipset-exclude` (IP-диапазоны) — это те же фильтры отбора, что и обычные `--hostlist`/`--ipset`, только с обратным знаком (полный справочник фильтров — [[filter]]). Проверяются exclude-списки первыми и имеют приоритет: если ресурс попал и во включающий, и в исключающий список одного профиля, побеждает исключение.
Чаще всего exclude-списки встречаются в широких профилях-перехватчиках вида «Все сайты»: у такого профиля вообще нет включающего списка, есть только исключающие — поэтому он действует на весь трафик своих портов за вычетом исключений (признак разобран в [[find-game-strategy|подборе стратегии для игр]]). В стоковых пресетах так исключают российские ресурсы (`ipset-ru.txt`), DNS-серверы (`ipset-dns.txt`) и ручной список пользователя. Нюанс: непустой `--hostlist-exclude` сам делает профиль «доменным» — пока имя хоста неизвестно, такой профиль в выборе не участвует; `--ipset-exclude` работает с первого пакета, потому что IP известен сразу.
Механика отличается от `pass` принципиально: исключённый трафик этот профиль **не забирает** — для движка профиль просто «не совпал», и поиск продолжается по профилям ниже. Если не совпал вообще ни один видимый профиль, соединение подбирает скрытый профиль `no_action` (факт 3 выше) — и трафик уходит нетронутым.
> [!note] Исключение из правила — профиль с автохостлистом
> В профиле с `--hostlist-auto` (автоматическое пополнение списка заблокированных доменов) логика другая: при известном имени хоста такой профиль выигрывает выбор **безусловно**, и `--hostlist-exclude` в нём не отдаёт трафик профилям ниже, а лишь запрещает применять стратегию — то есть по наблюдаемому эффекту ведёт себя как `pass`. На `--ipset-exclude` это не распространяется: он проверяется раньше и честно «роняет» профиль. Нюанс актуален для ручных конфигураций с автохостлистом.
## Разная логика — одинаковый результат. Но не всегда
Разработчик GUI формулирует это так: два вида исключений с разной логикой, но одинаковым результатом — пакеты сайта идут как есть, напрямую, без дурения. Сравнение:
| | Профиль со стратегией `pass` | `--hostlist-exclude` / `--ipset-exclude` |
|---|---|---|
| Что это | Отдельный [[profile\|профиль]] | Условие внутри чужого профиля |
| Что происходит с трафиком | Профиль **забирает** соединение и ничего с ним не делает | Профиль **пропускает** трафик — тот идёт к профилям ниже |
| Поиск профиля | Останавливается (first-match-wins) | Продолжается вниз по списку |
| Где встречается | Профили «Исключения айпи/домены (RU сайты)» выше широких профилей пресета | Широкие профили «Все сайты» |
Отсюда видно, когда результат перестаёт быть одинаковым. `pass`-профиль — жёсткая точка для трафика, который он реально поймал: пока соединение за ним, оно гарантированно едет без обхода (про лаг доменных `pass`-профилей на первых пакетах — callout выше). Exclude-список — мягкая точка: он лишь выводит трафик из-под **одного** профиля, и если ниже по списку есть другой профиль, чьи фильтры совпадут, трафик достанется ему — со всем его дурением. Поэтому относиться к exclude-списку как к «глобальному исключению» нельзя: он локален для своего профиля.
## Как сделать исключение в GUI: чек-лист
Совет из чата поддержки (август 2026): достаточно создать в любом пресете новый профиль со стратегией `pass` и накидать туда нужные домены и IP. По шагам (тот же путь целиком, на скриншотах — в разделе «Пошаговый пример» ниже):
- [ ] Создайте новый профиль — пошагово в [[add-profile|«Как добавить свой профиль»]] (там же — про бэкап пресета).
- [ ] В списке готовых стратегий профиля выберите `pass (ничего не делает)`.
- [ ] Наполните список профиля: домены — в [[hostlist|хостлист]], IP-диапазоны — в [[ipset|ипсет]]. Не смешивайте их бездумно (см. подводные камни ниже).
- [ ] Кнопкой «Порядок в пресете» поднимите профиль **выше** тех профилей, которые могли бы перехватить этот же трафик (обычно — в самый верх).
- [ ] Проверьте, что исключённый ресурс открывается, а остальной обход не отвалился ([[verify-strategy|как проверить стратегию]]).
Экран «Порядок в пресете» прямо напоминает правило: профиль выше в списке имеет больший приоритет. Здесь же видно, что «Исключения (RU сайты)» — это обычный профиль со стратегией `pass (ничего не делает)`, стоящий у вершины списка (скриншот снят на пресете до августа 2026, где профиль-исключение ещё один):
![[profile-order-gui.png]]
> [!note] «Исключение» никак не защищено — это просто профиль, у которого сейчас выбран `pass`
> Обратная сторона такой архитектуры: GUI не запрещает открыть профиль-исключение и выбрать ему любую другую стратегию — тогда «исключение» молча превратится в обычный дурящий профиль. Работает и в обратную сторону: любой профиль становится исключением заменой его стратегии на `pass`. Для движка все профили равны, статус «исключения» существует только в голове пользователя. Удачна ли такая свобода — вопрос открытый; помнить о ней стоит хотя бы потому, что случайная смена стратегии у профиля исключений вроде «Исключения айпи (RU сайты)» включит [[desync|дурение]] сразу для всех российских сайтов из его списка.
## Пошаговый пример: общий `pass`-профиль для своих доменов
Чек-лист выше описывает принцип; здесь тот же путь показан целиком, на скриншотах GUI (версии 21.1.5.x, август 2026). Задача — «добавить свои сайты в исключения»: в [[preset|пресете]] создаётся один общий [[profile|профиль]] «Исключения Домены», куда складываются все домены, которые должны идти напрямую, без [[desync|дурения]]. Для типичного случая «убрать сайт из-под Zapret» такой «общей кучи» достаточно; если хочется аккуратнее — под каждый ресурс заводится отдельный `pass`-профиль по той же механике, тогда в пресете видно, что и зачем исключено.
> [!tip] Для российских ресурсов готовые профили уже есть
> В стоковых пресетах с августа 2026 исключений два, оба со стратегией `pass`: IP-адрес или подсеть достаточно дописать в [[ipset|ипсет]] профиля «Исключения айпи (RU сайты)», домен — в пользовательский [[hostlist|хостлист]] профиля «Исключения домены (RU сайты)». Это быстрый путь «в общую кучу»; вариант «по красоте» — отдельный `pass`-профиль на каждый ресурс, как в примере ниже. Он же пригодится на пресетах до августа 2026, где готового доменного профиля-исключения ещё нет.
**Шаг 1. Создайте профиль.** Откройте вкладку «Профили пресета» и нажмите кнопку `+` — «Добавить новый пользовательский profile в общий список». Работать лучше в копии пресета — про бэкап дублированием и создание профилей вообще см. [[add-profile|«Как добавить свой профиль»]].
![[exclusions-add-profile-button.png]]
**Шаг 2. Заполните диалог.** Название произвольное — в примере «Исключения Домены». Тип — TCP, порты — `443`: сайты работают по HTTPS, то есть по TLS на TCP-порту 443 (чтобы покрыть заодно и незашифрованный HTTP, укажите `80,443`). Диалог сразу создаёт профиль и два пустых файла списков — [[hostlist|хостлист]] и [[ipset|ипсет]].
![[exclusions-add-profile-dialog.png]]
**Шаг 3. Найдите созданный профиль.** Он появляется в группе «Сайты»; быстрее всего — через поиск профилей по имени. Откройте его.
![[exclusions-find-profile-search.png]]
**Шаг 4. Выберите стратегию `pass`.** На вкладке «Готовые стратегии» найдите `pass (ничего не делает)` и выберите её — справа появится метка «Выбрана». Именно эта стратегия и превращает профиль в исключение (механизм 1 выше).
![[exclusions-pass-strategy-select.png]]
**Шаг 5. Наполните список доменов и включите профиль.** Убедитесь, что слева выбран тип **Hostlist**, перейдите на вкладку со списками (на скриншоте она называется «Исключения»; в других версиях GUI — «Редактор», см. [[add-profile|пошаговую заметку о профилях]]) и впишите домены в поле «Ваши записи», по одному на строку. Список сохраняется в `lists/user/…`, «База» сверху остаётся пустой — это ваш личный профиль. Не забудьте чекбокс **«Включён»** в правом верхнем углу: без него профиль создан, но не работает.
![[exclusions-hostlist-domains.png]]
В примере, помимо конкретных сайтов (`gov.ru`, `gosuslugi.ru`, `max.ru`), в список вписаны целые доменные зоны — `ru`, `su`, `рф`: запись в хостлисте покрывает и все поддомены, поэтому одна строка `ru` исключает домены всей зоны. Кириллическая зона продублирована в punycode-виде (`xn--p1ai`) — в SNI, из которого движок узнаёт имя хоста, кириллические имена передаются именно так.
Последний штрих — из чек-листа выше: кнопкой «Порядок в пресете» поднимите новый профиль выше тех, что могли бы перехватить этот же трафик, и проверьте результат ([[verify-strategy|как проверить стратегию]]).
## Подводные камни
Все они — следствия одного факта: исключение — это обычный профиль, а не глобальная настройка.
**Порядок решает.** Исключения не действуют «на весь пресет сверху» — они конкурируют за трафик наравне с остальными профилями, по правилу [[profile#Порядок профилей важен|«выше = главнее»]]. `pass`-профиль ниже «портящего» профиля бесполезен: трафик заберут раньше него.
**Сайт в двух профилях.** Если добавить домен в исключение, но он уже сидит в списке другого профиля (или наоборот — добавили в рабочий профиль, а из исключений не убрали), сработает тот профиль, что выше, — и результат может быть противоположен ожидаемому. Держите каждый ресурс в одном профиле.
**Смешение IP и доменов.** Профиль с [[ipset|ипсетом]] матчится по IP удалённой стороны — тот известен с первого пакета, тогда как профиль с [[hostlist|хостлистом]] до появления имени хоста в выборе вообще не участвует. Когда движок наконец узнаёт имя (из SNI), он ищет профиль заново — но, как описано в факте 2, снова сверху вниз, и верхний IP-профиль, чьи условия не изменились, опять совпадает первым. Поэтому нижний профиль с **доменом** того же ресурса не сработает никогда — именно об этом предупреждение разработчика GUI: «профили будут матчиться по айпи, а твой домен ниже не заработает». Практическое правило: доменные профили ставьте **выше** IP-профилей — тогда до раскрытия имени соединение обслуживает нижний IP-профиль, а после раскрытия штатно перескакивает на верхний доменный.
**`pass` не «защищает» сайт — он отключает обход.** Если `pass`-профиль с широким фильтром перехватит трафик **заблокированного** сайта, тот поедет к DPI с открытым SNI и умрёт. Классический случай «включил исключения — отвалился YouTube» разобран в [[profile-independence|«Профили не влияют друг на друга»]]: стратегия YouTube при этом не ломается, она просто не запускается, потому что соединение забрал верхний `pass`-профиль.
## 📚 См. также
- [[profile|Что такое профиль]] — анатомия профиля, раздел про профиль-исключение `pass` и порядок профилей
- [[profile-independence|Профили не влияют друг на друга]] — почему «включил исключение — сломался другой сайт» это не глюк
- [[filter|Фильтры профиля]] — как движок выбирает профиль; `--hostlist-exclude`/`--ipset-exclude` среди прочих фильтров
- [[hostlist]] · [[ipset]] — списки доменов и IP, которыми наполняются исключения
- [[add-profile|Как добавить свой профиль]] — практика создания профиля в GUI
- [[find-game-strategy|Как найти стратегию для игры]] — широкие профили «Все сайты» с exclude-списками в деле
- [[symptom-not-cause|«Не работает» — это симптом]] — когда сайту нужен `pass`, а когда обход
- [[preset|Пресет]] — контейнер, в котором живут все эти профили
---
> [!quote] 🤖 Эти статьи открыты — можно обучать на них ИИ
> При желании вы можете натренировать ИИ на наших статьях. Исходное форматирование доступно в Forgejo: [исходник этой заметки](https://git2.zapret.moe/zapretdiscordyoutube/todo/src/branch/main/Zapret2/exclusions.md) · [скачать весь репозиторий одним zip-архивом](https://git2.zapret.moe/zapretdiscordyoutube/todo/archive/main.zip).