# 🚫 Исключения в 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|«не работает» — это симптом]]). Типичный пример — российские сайты: в стоковых пресетах для них заведён профиль «Исключения (RU сайты)», который стоит в начале списка. ## Как движок выбирает профиль: три факта, без которых исключения не понять Оба механизма исключений опираются на одну и ту же процедуру выбора профиля. Полный справочник фильтров — в [[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 (ничего не делает)`, стоящий у вершины списка: ![[profile-order-gui.png]] > [!note] «Исключение» никак не защищено — это просто профиль, у которого сейчас выбран `pass` > Обратная сторона такой архитектуры: GUI не запрещает открыть профиль-исключение и выбрать ему любую другую стратегию — тогда «исключение» молча превратится в обычный дурящий профиль. Работает и в обратную сторону: любой профиль становится исключением заменой его стратегии на `pass`. Для движка все профили равны, статус «исключения» существует только в голове пользователя. Удачна ли такая свобода — вопрос открытый; помнить о ней стоит хотя бы потому, что случайная смена стратегии у профиля «Исключения (RU сайты)» включит [[desync|дурение]] сразу для всех российских сайтов из его списка. ## Подводные камни Все они — следствия одного факта: исключение — это обычный профиль, а не глобальная настройка. **Порядок решает.** Исключения не действуют «на весь пресет сверху» — они конкурируют за трафик наравне с остальными профилями, по правилу [[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://git.zapret.moe/zapretdiscordyoutube/todo/src/branch/main/Zapret2/exclusions.md) · [скачать весь репозиторий одним zip-архивом](https://git.zapret.moe/zapretdiscordyoutube/todo/archive/main.zip).