mirror of
https://github.com/bol-van/zapret2.git
synced 2026-03-17 23:19:44 +00:00
467 lines
52 KiB
Markdown
467 lines
52 KiB
Markdown
# МАНУАЛ В ПРОЦЕССЕ НАПИСАНИЯ
|
||
|
||
|
||
# Введение
|
||
|
||
zapret2 является пакетным манипулятором, основная задача которого - совершение различных автономных атак на DPI в реальном времени
|
||
с целью преодоления ограничений (блокировок) ресурсов или сетевых протоколов.
|
||
Однако, этим возможности zapret2 не ограничиваются. Архитектура позволяет выполнять и другие виды пакетных манипуляций.
|
||
Например, двусторонняя (клиент+сервер) обфускация протоколов с целью их сокрытия от DPI. Возможны и иные применения.
|
||
|
||
# Структура проекта
|
||
|
||
Главный компонент zapret2 - программа nfqws2 (dvtws2 на BSD, winws2 на Windows), написанная на C, которая и является пакетным манипулятором.
|
||
Содержит функции по перехвату пакетов, базовой фильтрации, рапознавания основных протоколов и пейлоадов, поддержки хост и IP листов, автоматических хостлистов
|
||
с распознаванием блокировок, систему множественных профилей (стратегий), возможности по отсылке raw пакетов и другие сервисные функции.
|
||
Однако, там нет никаких возможностей собственно для воздействия на трафик. Это вынесено в код на языке LUA, вызываемый из nfqws2.
|
||
|
||
Поэтому следующая по важности часть проекта - LUA код. В базовый комплект входит библиотека функций-хелперов `zapret-lib.lua`,
|
||
библиотека программ автономных атак на DPI `zapret-antidpi.lua`, библиотека функций принятия динамических решений (оркестрации) `zapret-auto.lua`.
|
||
Дополнительно присутствует набор тестов C функций `zapret-tests.lua`, средство обфускации wireguard протокола `zapret-wgobfs.lua` и средство записи дампа пакетов в cap файлы `zapret-pcap.lua`.
|
||
|
||
Функции перенаправления трафика из ядра в Linux возложены на iptables и nftables, в FreeBSD - на ipfw, в OpenBSD - на pf, в Windows - встроены в сам процесс winws2 посредством драйвера windivert.
|
||
Схема перехвата трафика из ядра , nfqws2 и lua код составляют минимально рабочее ядро проекта. Все остальное является дополнительным, второстепенным и опциональным.
|
||
|
||
Из второстепенных компонент - скрипты запуска под Linux - `init.d`, `common`, `ipset`, `install_easy.sh`, `uninstall_easy.sh` и средство автоматизации тестирования стратегий `blockcheck2`.
|
||
Цель скриптов запуска - согласовать процесс поднятия таблиц и запуск инстансов nfqws2, учесть особенности интеграции в различные дистрибутивы (openwrt, systemd, openrc).
|
||
Дополнительная функция - обеспечить поддержку и согласованное обновление различных листов и загрузку IP листов в пространство ядра - ipset.
|
||
Все это можно сделать при желании и собственными средствами, если так удобнее или функционал скриптов запуска не подходит.
|
||
Скрипты запуска выносят все настройки в файл config, лежащий в корне проекта. Этот конфиг относится только к ним, nfqws2 ничего о нем не знает.
|
||
|
||
Для обработки листов предусмотрены 2 программы, написанные на C. mdig - многопоточный ресолвер хостлистов неограниченного обьема.
|
||
ip2net - программа для группировки отдельных IP адресов в подсети с целью сокращения их обьема.
|
||
Эти программы испльзуются в скриптах запуска и в blockcheck2.
|
||
|
||
Скрипты запуска и инсталятор поддерживает установку на любые классические дистрибутивы Linux с systemd или openrc , из прошивок - на openwrt.
|
||
Если система не удовлетворяет указанным требованиям - возможна самостоятельная "доприкрутка" к системе.
|
||
|
||
MacOS не поддерживается по причине отсутствия подходящего средства перехвата и управления пакетами. Стандартное для BSD средство ipdivert было убрано из ядра производителем.
|
||
|
||
# Схема обработки трафика
|
||
|
||
Сети работают с IP пакетами. Поэтому единицей обработки являются именно они. Приемом и отправкой пакетов занимается сетевая подсистема в ядре ОС.
|
||
nfqws2 работает не в ядре (kernel mode), а является процессом пространства пользователя (user mode). Поэтому первая часть процесса обработки состоит
|
||
в передаче пакетов из ядра ОС в процесс nfqws2. Все 4 средства перехвата обладают некоторыми возможностями фильтрации пакетов. Максимальные возможности - в Linux.
|
||
Чем больше на этом этапе будет отсечено ненужного трафика, тем меньше будет нагрузка на процессор, поскольку передача пакетов из ядра в user mode и обратно сопряжена со значительными накладными расходами.
|
||
|
||
Пакет пришел в nfqws2. Первое, что он делает, это разбирает его по уровням OSI модели - выделяет ip , ipv6, tcp, udp заголовки и поле данных. Это называется диссекцией.
|
||
Результатом диссекции является диссект - представление пакета в виде структур, которые можно адресовать по полям.
|
||
|
||
Далее задействуется встроенная в nfqws2 подсистема conntrack - система отслеживания потоков поверх отдельно взятых пакетов.
|
||
Ищется уже имеющаяся запись о соединении на основании данных L3/L4 пакета. Если ее нет - создается. Старые записи, по которым давно нет активности, удаляются.
|
||
conntrack отслеживает логическое направление пакетов в потоке (входящее/исходящее), ведет подсчет количество прошедших пакетов и байт в обе стороны,
|
||
следит за sequence numbers для tcp. Он же используется в случае необходимости для сборки сообщений, передаваемых несколькими пакетами.
|
||
|
||
Сигнатурно определяется тип пейлоада - содержимого отдельно взятого пакета или группы пакетов. На основании типа пейлоада определяется тип протокола
|
||
всего потока, который сохраняется за потоком до конца его существования. В рамках одного соединения могут проходить разные типы пейлоадов.
|
||
Например, протокол потока xmpp обычно несет несколько видов специфических для xmpp сообщений и сообщения, связанные с tls.
|
||
Тип протокола потока xmpp остается, но последующие пакеты получают различные типы пейлоада - как известные, так и неизвестные. Неизвестные пейлоады определяются как тип "unknown".
|
||
|
||
Если для конкретного пейлоада и типа протокола потока выясняется необходимость реконструкции сообщения из нескольких пакетов, nfqws2 начинает их накапливать в связи с записью в conntrack
|
||
и запрещает их немедленную отправку. После приема всех пакетов сообщения происходит реконструкция и при необходимости дешифровка составного пейлоада.
|
||
Дальнейшие решения принимаются уже на базе полностью собранного пейлоада - reasm или результата сборки и дешифровки - decrypt.
|
||
|
||
Когда необходимая информация о пейлоаде получена, наступает очередь системы классификации по профилям.
|
||
Профили содержат систему фильтров и команды действия внутри профиля.
|
||
Профили фильтруются по L3 - версия IP протокола, ipset-ы - списки IP адресов, L4 - порты tcp или udp, L6/L7 - тип протокола потока, списки доменов (хостлисты).
|
||
Профили сканируются строго в порядке от первого к последнему. При первом совпадении условий фильтра профиля выбирается этот профиль, а сканирование прекращается.
|
||
Если ни одно из условий не выполнено, выбирается профиль по умолчанию, в котором нет никаких действий.
|
||
|
||
Все дальнейшие действия выполняются уже в рамках выбранного профиля. Выбранный профиль кэшируется в записи conntrack, поэтому для каждого пакета поиск заново не выполняется.
|
||
Повторный поиск выполняется в случае изменения исходных данных - при обнаружении L7 протокола и при обнаружении имени хоста. В последних случаях производится повторный поиск
|
||
и при необходимости переключение профиля. Таких переключений может быть за соединение до двух, поскольку есть лишь 2 изменяемых параметра.
|
||
|
||
Профиль выбран. Из чего состоит его содержание, отвечающее за действия ?
|
||
За действия отвечают LUA функции. В профиле их может быть произвольное количество.
|
||
Каждый вызов LUA функции из профиля называется инстансом. Функция может быть одна, вызовов несколько - с разными параметрами.
|
||
Поэтому и применяется понятие инстанса - экземпляра вызываемой функции, который идентифицируется номером профиля и порядковым номером вызова внутри профиля.
|
||
Инстансы вызываются через параметры `--lua-desync`. Каждый инстанс получает набор произвольных параметров, задаваемых в `--lua-desync`.
|
||
Порядок вызовов имеет принципиальное значение для логики стратегии и выполняется строго в порядке задания параметров `--lua-desync`.
|
||
|
||
Присутствуют и внутипрофильные фильтры. Их 3 типа - фильтр `--payload` - список принимаемых инстансом пейлоадов, и 2 диапазонных фильтра `--in-range` и `--out-range`,
|
||
позволяющих задать диапазон позиций внутри потока, который интересен для инстанса. Внутрипрофильные фильтры после их определения действуют на все последующие инстансы
|
||
до их переопределения. Главный смысл наличия внутрипрофильных фильтров - сократить число относительно медленных вызовов LUA , принимая максимум решений на стороне C кода.
|
||
|
||
Пакет пришел в LUA инстанс. Функция имеет 2 параметра - ctx и desync. ctx - это контекст для связи с некоторыми функциями на стороне C кода.
|
||
desync - таблица, содержащая множество параметров обрабатываемого пакета. Прежде всего это диссект - подтаблица `dis`.
|
||
Информация из записи conntrack - подтаблица `track`. Еще целый ряд параметров, который можно увидеть, выполнив `var_debug(desync)` или просто вызвав готовый инстанс `pktdebug`.
|
||
|
||
Если идет перепроигрывание задержанных пакетов (replay), LUA инстанс получает информацию о номере части, количестве частей исходного сообщения, позиции текущей части,
|
||
reasm или decrypt при наличии.
|
||
|
||
LUA код может использовать глобальное пространство переменных для хранения данных, не относящихся к конкретному обрабатываемому пакету. Ему доступна таблица `desync.track.lua_state`,
|
||
в которой он может хранить любую информацию, связанную с записью conntrack. При каждом новом пакете потока в LUA выдается одна и та же таблица.
|
||
Таблицу desync можно использовать для генерации и хранения временных данных, актуальных в цепочке обработки текущего пакета.
|
||
Следующие LUA инстансы получают ту же таблицу desync и тем самым могут принимать данные от предыдущих инстансов.
|
||
|
||
LUA инстанс может создавать копии текущего диссекта, вносить в них изменения, генерировать собственные диссекты, отправлять их через вызовы C кода.
|
||
Итогом работы каждого инстанса является вердикт - VERDICT_PASS - не делать ничего с текущим диссектом, VERDICT_MODIFY - в конце всей цепочки отослать модифицированное содержимое диссекта,
|
||
VERDICT_DROP - дропнуть текущий диссект. Вердикты всех инстансов аггрегируются - MODIFY замещает PASS, а DROP замещает и PASS, и MODIFY.
|
||
|
||
LUA инстанс может сам себя отключить от получения дальнейших пакетов потока по направлению in/out - это назвается instance cutoff.
|
||
Может отключить направление in/out текущего потока от всей LUA обработки - lua cutoff.
|
||
Может запросить отмену всей дальнейшей цепочки вызовов LUA инстансов по текущему диссекту. Инстанс, принимающий такое решение, берет на себя функцию координации дальнейших действий.
|
||
Такой инстанс называется оркестратором. Он получает от C кода план дальнейшего выполнения со всеми фильтрами профиля и параметрами вызова всех оставшихся инстансов
|
||
и сам принимает решения когда и при каких условиях их вызывать или не вызывать, менять их параметры. Так реализуются динамические сценарии без модификации основных составлящих кода стратегии.
|
||
Например, определение блокировки ресурса и смена стратегии, если предыдущая не сработала.
|
||
|
||
Если все инстансы текущего профиля вошли в состояние cutoff по текущему потоку, либо текущая позиция потока находится за верхней границей range фильтров, значит по этому потоку больше не будет LUA
|
||
вызовов. C код помечает такие потоки специальным признаком "lua cutoff", который проверяется максимально быстро без вызовов кода LUA. Тем самым экономятся ресурсы процессора.
|
||
|
||
После выполнения всей цепочки инстансов профиля C код получает итоговый вердикт - что делать с текущим диссектом. Отправить как есть, отправить модифицированный вариант или дропнуть.
|
||
|
||
В конце nfqws2 переходит к ожиданию следующего пакета, и цикл повторяется вновь.
|
||
|
||
# Перехват трафика из ядра ОС
|
||
|
||
## Перехват трафика в ядре Linux
|
||
|
||
Осуществляется при помощи iptables или nftables с использованием механизма очередей NFQUEUE.
|
||
nftables - предпочтительны, потому что позволяют работать с трафиком после NAT, а iptables - нет.
|
||
Это важно при обработке проходящего (forwarded) трафика. На iptables перехват после NAT невозможен, поэтому некоторые воздействия, ломающие NAT,
|
||
на iptables на проходящем трафике нереализуемы.
|
||
У nftables есть один важный недостаток - чрезмерное требование к памяти при загрузке
|
||
больших set-ов. Например, чтобы загрузить 100K IP адресов, требуется от 256-320 Mb, что для роутеров часто оказывается за пределом возможностей.
|
||
ipset от iptables такое может провернуть даже на 64 Mb RAM.
|
||
|
||
Приведенные далее тестовые примеры предназначены для своей системы запуска или запуска вручную.
|
||
Скрипты запуска zapret сами генерируют необходимые правила, никаких ip/nf tables самому писать не нужно.
|
||
|
||
### Перехват трафика с помощью nftables
|
||
|
||
Тестовая таблица для POSTNAT схемы.
|
||
Обеспечивает перехват первых входящих и исходящих пакетов по потоку после NAT, если таковой присутствует.
|
||
Из-за NAT IP адреса клиентов теряются, замещаясь IP wan интерфейса.
|
||
Количество первых пакетов регулируется согласно вашей стратегии. Лишний перехват - дополнительная нагрузка на CPU.
|
||
Перехват RST и FIN желателен для максимально корректной работы conntrack.
|
||
|
||
Фильтр по mark необходим для предотвращения кольца. Без этого возможны зависания и неправильная работа.
|
||
|
||
notrack нужен, чтобы NAT не ломал техники, которые не совместимы с NAT.
|
||
Генерируемые nfqws2 пакеты не должны проходить проверки на валидность с точки зрения NAT и дропаться стандартными правилами таблиц.
|
||
Подстановка IP адресов NAT не требуется, поскольку попадающий на nfqws2 пакет уже прошел NAT и имеет корректные адрес и порт источника для wan.
|
||
|
||
|
||
```
|
||
IFACE_WAN=wan
|
||
MAX_PKT_IN=15
|
||
MAX_PKT_OUT=15
|
||
FWMARK=0x40000000
|
||
PORTS_TCP=80,443
|
||
PORTS_UDP=443
|
||
QNUM=200
|
||
|
||
nft create table inet ztest
|
||
|
||
nft add chain inet ztest postnat "{type filter hook postrouting priority srcnat+1;}"
|
||
nft add rule inet ztest postnat oifname $IFACE_WAN meta mark and $FWMARK == 0 udp dport "{$PORTS_UDP}" ct original packets 1-$MAX_PKT_OUT queue num $QNUM bypass
|
||
nft add rule inet ztest postnat oifname $IFACE_WAN meta mark and $FWMARK == 0 tcp dport "{$PORTS_TCP}" ct original packets 1-$MAX_PKT_OUT queue num $QNUM bypass
|
||
nft add rule inet ztest postnat oifname $IFACE_WAN meta mark and $FWMARK == 0 tcp dport "{$PORTS_TCP}" tcp flags fin,rst queue num $QNUM bypass
|
||
|
||
nft add chain inet ztest pre "{type filter hook prerouting priority filter;}"
|
||
nft add rule inet ztest pre iifname $IFACE_WAN udp sport "{$PORTS_UDP}" ct reply packets 1-$MAX_PKT_IN queue num $QNUM bypass
|
||
nft add rule inet ztest pre iifname $IFACE_WAN tcp sport "{$PORTS_TCP}" ct reply packets 1-$MAX_PKT_IN queue num $QNUM bypass
|
||
nft add rule inet ztest pre iifname $IFACE_WAN tcp sport "{$PORTS_TCP}" "tcp flags & (syn | ack) == (syn | ack)" queue num $QNUM bypass
|
||
nft add rule inet ztest pre iifname $IFACE_WAN tcp sport "{$PORTS_TCP}" tcp flags fin,rst queue num $QNUM bypass
|
||
|
||
nft add chain inet ztest predefrag "{type filter hook output priority -401;}"
|
||
nft add rule inet ztest predefrag "mark & $FWMARK != 0x00000000 notrack"
|
||
```
|
||
|
||
Удаление тестовой таблицы :
|
||
|
||
```
|
||
nft delete table inet ztest
|
||
```
|
||
|
||
### Перехват трафика с помощью iptables
|
||
|
||
> [!CAUTION]
|
||
> Начиная с ядер Linux 6.17 присутствует параметр конфигурации ядра CONFIG_NETFILTER_XTABLES_LEGACY, который по умолчанию в дистрибутиве может быть "not set". Отсутствие этой настройки выключает iptables-legacy. Это часть процесса депрекации iptables. Тем не менее iptables-nft будут работать, поскольку используют backend nftables.
|
||
|
||
Тестовые правила для PRENAT схемы.
|
||
Обеспечивают перехват первых входящих и исходящих пакетов по потоку до NAT, если таковой присутствует.
|
||
Адреса и порты источника внутренней сети сохраняются. Атаки на проходящий трафик, ломающие NAT, невозможны, но возможны с самой системы.
|
||
|
||
```
|
||
IFACE_WAN=wan
|
||
MAX_PKT_IN=15
|
||
MAX_PKT_OUT=15
|
||
FWMARK=0x40000000
|
||
PORTS_TCP=80,443
|
||
PORTS_UDP=443
|
||
QNUM=200
|
||
|
||
JNFQ="-j NFQUEUE --queue-num $QNUM --queue-bypass"
|
||
CHECKMARK="-m mark ! --mark $FWMARK/$FWMARK"
|
||
CB_ORIG="-m connbytes --connbytes-dir=original --connbytes-mode=packets"
|
||
CB_REPLY="-m connbytes --connbytes-dir=reply --connbytes-mode=packets"
|
||
for tables in iptables ip6tables; do
|
||
$tables -t mangle -N ztest_post 2>/dev/null
|
||
$tables -t mangle -F ztest_post
|
||
$tables -t mangle -C POSTROUTING -j ztest_post 2>/dev/null || $tables -t mangle -A POSTROUTING -j ztest_post
|
||
$tables -t mangle -N ztest_pre 2>/dev/null
|
||
$tables -t mangle -F ztest_pre
|
||
$tables -t mangle -C PREROUTING -j ztest_pre 2>/dev/null || $tables -t mangle -A PREROUTING -j ztest_pre
|
||
$tables -t mangle -I ztest_post -o $IFACE_WAN $CHECKMARK -p udp -m multiport --dports $PORTS_UDP $CB_ORIG --connbytes 1:$MAX_PKT_OUT $JNFQ
|
||
$tables -t mangle -I ztest_post -o $IFACE_WAN $CHECKMARK -p tcp -m multiport --dports $PORTS_TCP $CB_ORIG --connbytes 1:$MAX_PKT_OUT $JNFQ
|
||
$tables -t mangle -I ztest_post -o $IFACE_WAN $CHECKMARK -p tcp -m multiport --dports $PORTS_TCP --tcp-flags fin fin $JNFQ
|
||
$tables -t mangle -I ztest_post -o $IFACE_WAN $CHECKMARK -p tcp -m multiport --dports $PORTS_TCP --tcp-flags rst rst $JNFQ
|
||
$tables -t mangle -I ztest_pre -i $IFACE_WAN -p udp -m multiport --sports $PORTS_UDP $CB_REPLY --connbytes 1:$MAX_PKT_IN $JNFQ
|
||
$tables -t mangle -I ztest_pre -i $IFACE_WAN -p tcp -m multiport --sports $PORTS_TCP $CB_REPLY --connbytes 1:$MAX_PKT_IN $JNFQ
|
||
$tables -t mangle -I ztest_pre -i $IFACE_WAN -p tcp -m multiport --sports $PORTS_TCP --tcp-flags syn,ack syn,ack $JNFQ
|
||
$tables -t mangle -I ztest_pre -i $IFACE_WAN -p tcp -m multiport --sports $PORTS_TCP --tcp-flags fin fin $JNFQ
|
||
$tables -t mangle -I ztest_pre -i $IFACE_WAN -p tcp -m multiport --sports $PORTS_TCP --tcp-flags rst rst $JNFQ
|
||
done
|
||
```
|
||
|
||
Удаление тестовых правил zapret :
|
||
|
||
```
|
||
for tables in iptables ip6tables; do
|
||
$tables -t mangle -D POSTROUTING -j ztest_post
|
||
$tables -t mangle -D PREROUTING -j ztest_pre
|
||
$tables -t mangle -F ztest_post
|
||
$tables -t mangle -X ztest_post
|
||
$tables -t mangle -F ztest_pre
|
||
$tables -t mangle -X ztest_pre
|
||
done
|
||
```
|
||
|
||
Удаление всех правил из таблицы mangle, включая и иные правила :
|
||
```
|
||
iptables -F -t mangle
|
||
ip6tables -F -t mangle
|
||
```
|
||
|
||
## Перехват трафика в ядре FreeBSD
|
||
|
||
Основная боль при перехвате трафика на системах, отличных от Linux, - невозможность перехватить первые пакеты потока.
|
||
Можно перехватить только весь поток целиком по направлению.
|
||
В BSD с этим дела хуже всего - нет даже возможностей фильтрации raw payload, то есть по содержимому пакета.
|
||
Поэтому первый набор правил - это перехват всех исходящих по портам и перехват только SYN+ACK,FIN,RST для TCP, чтобы
|
||
без нагрузки на процессор можно было задействовать режим autottl и максимально корректно работал conntrack.
|
||
Однако, в таком варианте не будет работать ничего, что требует иного входящего трафика.
|
||
|
||
```
|
||
RULE=100
|
||
IFACE_WAN=vmx0
|
||
PORTS_TCP=80,443
|
||
PORTS_UDP=443
|
||
PORT_DIVERT=989
|
||
|
||
ipfw delete $RULE
|
||
ipfw add $RULE divert $PORT_DIVERT tcp from any to any $PORTS_TCP out not diverted xmit $IFACE_WAN
|
||
ipfw add $RULE divert $PORT_DIVERT udp from any to any $PORTS_UDP out not diverted xmit $IFACE_WAN
|
||
ipfw add $RULE divert $PORT_DIVERT tcp from any $PORTS_TCP to any tcpflags syn,ack in not diverted recv $IFACE_WAN
|
||
ipfw add $RULE divert $PORT_DIVERT tcp from any $PORTS_TCP to any tcpflags fin in not diverted recv $IFACE_WAN
|
||
ipfw add $RULE divert $PORT_DIVERT tcp from any $PORTS_TCP to any tcpflags rst in not diverted recv $IFACE_WAN
|
||
```
|
||
|
||
Вариант с перехватом потока в обе стороны. Особо сильно загружает процессор.
|
||
Все скачиваемые гигабайты пойдут через dvtws2. Из них обычно нужно всего 1-2 пакета, все остальное - впустую расходует CPU,
|
||
но средства ipfw не предоставляют иных возможностей.
|
||
|
||
```
|
||
RULE=100
|
||
IFACE_WAN=vmx0
|
||
PORTS_TCP=80,443
|
||
PORTS_UDP=443
|
||
PORT_DIVERT=989
|
||
|
||
ipfw delete $RULE
|
||
ipfw add $RULE divert $PORT_DIVERT tcp from any to any $PORTS_TCP out not diverted xmit $IFACE_WAN
|
||
ipfw add $RULE divert $PORT_DIVERT udp from any to any $PORTS_UDP out not diverted xmit $IFACE_WAN
|
||
ipfw add $RULE divert $PORT_DIVERT tcp from any $PORTS_TCP to any in not diverted recv $IFACE_WAN
|
||
ipfw add $RULE divert $PORT_DIVERT udp from any $PORTS_UDP to any in not diverted recv $IFACE_WAN
|
||
```
|
||
|
||
Теоретически возможен перехват через pf divert-to, но на практике механизм предотвращения зацикливания сломан,
|
||
поэтому использовать pf нереально.
|
||
На pfsense и opnsense требуются дополнительные меры для задействования pf и ipfw одновременно.
|
||
Часто с этим бывают проблемы, конфликты и глюки.
|
||
|
||
## Перехват трафика в ядре OpenBSD
|
||
|
||
В OpenBSD есть только pf. С механизмом предотвращения зацикливания divert все в порядке.
|
||
|
||
Первый вариант - перехват всех исходящих по портам и перехват только SYN+ACK,FIN,RST для TCP, чтобы
|
||
без нагрузки на процессор можно было задействовать режим autottl и максимально корректно работал conntrack.
|
||
Однако, в таком варианте не будет работать ничего, что требует иного входящего трафика.
|
||
|
||
pf требует файлов с правилами. Вы пишите pf файл (обычно используется /etc/pf.conf), потом его применяете через
|
||
`pfctl -f /etc/pf.conf`. `pfctl -e` включает pf, `pfctl -d` - выключает.
|
||
Возможно использование якорей (anchors) с отдельными файлами правил, читайте документацию по pf.
|
||
|
||
Трюки с no state нужны, чтобы предотвратить автоматический перехват и входящих пакетов по потоку.
|
||
|
||
```
|
||
IFACE_WAN = "em0"
|
||
PORTS_TCP = "80,443"
|
||
PORTS_UDP = "443"
|
||
PORT_DIVERT = "989"
|
||
|
||
pass in quick on $IFACE_WAN proto tcp from port { $PORTS_TCP } flags SA/SA divert-packet port $PORT_DIVERT no state
|
||
pass in quick on $IFACE_WAN proto tcp from port { $PORTS_TCP } flags R/R divert-packet port $PORT_DIVERT no state
|
||
pass in quick on $IFACE_WAN proto tcp from port { $PORTS_TCP } flags F/F divert-packet port $PORT_DIVERT no state
|
||
pass in quick on $IFACE_WAN proto tcp from port { $PORTS_TCP } no state
|
||
pass out quick on $IFACE_WAN proto tcp to port { $PORTS_TCP } divert-packet port $PORT_DIVERT no state
|
||
pass out quick on $IFACE_WAN proto udp to port { $PORTS_UDP } divert-packet port $PORT_DIVERT no state
|
||
```
|
||
|
||
Вариант с перехватом потока в обе стороны. Особо сильно загружает процессор.
|
||
Все скачиваемые гигабайты пойдут через dvtws2. Из них обычно нужно всего 1-2 пакета, все остальное - впустую расходует CPU,
|
||
но средства pf не предоставляют иных возможностей.
|
||
|
||
Перехват входящих по тем же портам обеспечивается автоматически за счет state.
|
||
|
||
```
|
||
IFACE_WAN = "em0"
|
||
PORTS_TCP = "80,443"
|
||
PORTS_UDP = "443"
|
||
PORT_DIVERT = "989"
|
||
|
||
pass out quick on $IFACE_WAN proto tcp to port { $PORTS_TCP } divert-packet port $PORT_DIVERT
|
||
pass out quick on $IFACE_WAN proto udp to port { $PORTS_UDP } divert-packet port $PORT_DIVERT
|
||
```
|
||
|
||
> [!CAUTION]
|
||
> В FreeBSD другая версия pf и немного другой синтаксис. Однако, фактически pf в FreeBSD сломан, поскольку не работает предотвращение зацикливания. В MacOS хотя и используется pf, ipdivert из ядра убран, правила работать не будут.
|
||
|
||
## Перехват трафика в ядре Windows
|
||
|
||
В Windows нет встроенных средств для перехвата трафика. Используется стороннее решение - драйвер windivert.
|
||
Управление интегрируется в сам процесс winws2.
|
||
|
||
windivert принимает [текстовые фильтры](https://reqrypt.org/windivert-doc.html#filter_language), похожие на фильтры wireshark и tcpdump.
|
||
В них есть возможности фильтрации по ip (без ipset), портам и raw пейлоадам. Нет побитовых логических операций и сдвигов.
|
||
Нет отслеживания потоков и ограничения по первым пакетам.
|
||
|
||
Драйвер windivert больше не разрабатывается, однако имеются подписанные варианты драйвера, совместимые со всеми современными windows,
|
||
но только для архитектуры x86_64. На arm64 есть неподписанный драйвер, требующий тестового режима подписи драйверов.
|
||
При использовании winws2 на Windows 11 arm64 приходится пользоваться x86_64 версией, поскольку winws2 написан под cygwin, а его нет для arm.
|
||
Драйвер .sys при этом заменяется на неподписанную arm64 версию. Запуск на Windows 10 arm64 теоретически возможен, но только с 32-битной
|
||
версией winws2 x86, поскольку эмуляция x64 в Windows 10 не предусмотрена.
|
||
|
||
windivert является частой целью для нападок антивирусов. Это хакерский инструмент, но вирусом он не является.
|
||
Правильнее воспринимать его как замену iptables для windows.
|
||
Иногда случаются конфликты со сторонним ПО, использующим драйвера режима ядра - прежде всего антивирусы и фаерволы, вплоть до синих экранов.
|
||
Практически исправить это нереально хотя бы из-за подписи драйверов, которую получить простому смертному без стоящих за ним корпораций очень непросто и накладно.
|
||
|
||
windivert не может обеспечить корректного перехвата проходящего трафика при раздаче сети средствами windows и как следствие использовании NAT,
|
||
поэтому возможности работы по проходящему трафику не реализованы. Единственный доступный вариант - установить proxy server.
|
||
|
||
winws2 может принимать полные raw фильтры - вы пишите фильтр сами и указываете его в параметре `--wf-raw=<filter>` или `--wf-raw=@<filter_file>`.
|
||
Но это обычно не очень удобно, поэтому существует встроенный конструктор фильтров.
|
||
|
||
`--wf-tcp-out`, `--wf-tcp-in`, `--wf-udp-out`, `--wf-udp-in` берут список портов (`80,443`) или диапазонов портов (`80,443,500-1000`)
|
||
и включают полный перехват портов по указанному направлению.
|
||
|
||
`--wf-raw-part` принимает частичные windivert фильтры. Синтаксис аналогичен `--wf-raw`. `--wf-raw-part` может быть несколько.
|
||
Частичные фильтры встраиваются конструктором в итоговый фильтр по принципу OR. Или указанные порты, или ваш фильтр1 или ваш фильтр2.
|
||
|
||
`--wf-save=<filter_file>` записывает созданный конструктором фильтр в файл для последующего анализа и модификации.
|
||
|
||
Конструктор фильтров автоматически перехватывает входящие tcp с флагами SYN+ACK,FIN,RST. Писать специально правила не нужно.
|
||
|
||
`--wf-filter-lan` (по умолчанию включен) отфильтровывает пакеты на не глобальные IP адреса, такие как `192.168.0.0/16`.
|
||
|
||
`--wf-tcp-empty` (по умолчанию выключен) включает перехват пустых tcp пакетов без флагов SYN,FIN,RST.
|
||
Если параметр не включен, перехват пустых ACK пакетов не производится, что позволяет существенно сэкономить на процессоре.
|
||
Но для некоторых стратегий эти пакеты могут понадобиться. Только вы можете знать нужны они вам или нет.
|
||
|
||
Если есть перехват любого tcp порта, автоматически включается перехват всех http редиректов, чтобы работал autohostlist.
|
||
Перехват http redirect работает по payload сигнатуре, то есть проверяются байты в определенных позициях содержимого пакета.
|
||
|
||
Предпочтительно по udp протоколам, особенно по тем, где порт не определен, использовать свои `--wf-raw-part` фильтры,
|
||
чтобы сэкономить на процессоре. Для tcp тоже возможны фильтры, но надо учитывать потребности conntrack. Он нуждается
|
||
как минимум в SYN пакете, а желательно еще и FIN, RST. Если нужна фильтрация по сообщениям , занимающим более одного tcp сегмента,
|
||
такое отфильтровать средствами windivert невозможно - требуется полный перехват порта по направлению.
|
||
|
||
|
||
# nfqws2
|
||
|
||
## Общие принципы задания параметров
|
||
|
||
Все параметры nfqws2 передаются в командной строке, либо загружаются из файла в том же самом формате.
|
||
nfqws2 использует стандартный парсер getopt_long_only.
|
||
Опции имеют формат `--name[=value]`. Некоторые опции не требуют параметров, другие требуют, а третьи могут их брать опционально.
|
||
Парсер getopt позволяет задавать значение через знак `=` или через пробел. Лишние значения через пробел могут игнорироваться,
|
||
поэтому казалось бы ошибочные параметры могут не вызвать ошибку. Лучше всегда писать значения через знак `=`.
|
||
|
||
Чтение параметров из файла реализовано через задание единственной опции `@config_file`.
|
||
Все остальные параметры командной строки будут проигнорированы.
|
||
Опции будут прочитаны из файла, как будто бы вы ввели его содержимое в командой строке.
|
||
Возможность не поддерживается в Android и OpenBSD версиях.
|
||
|
||
## Полный список опций
|
||
|
||
|
||
```
|
||
@<config_file> ; чтение опций командной строки из файла. все остальные опции из командной строки игнорируются.
|
||
|
||
--debug=0|1|syslog|android|@<filename> ; писать дебаг лог. 0 - нет , 1 - на консоль, syslog - в unix syslog, android - системный log android, @<filename> - в файл
|
||
--version ; вывести версию и выйти
|
||
--dry-run ; проверить валидность параметров командной строки и наличие файлов. не проверяет корректность скриптов LUA !
|
||
--comment=any_text ; любой текст. игнорируется
|
||
--qnum=<nfqueue_number> ; номер очереди NFQUEUE в Linux
|
||
--port=<port> ; номер divert порта в BSD
|
||
--daemon ; отключиться от консоли (демонизироваться)
|
||
--pidfile=<filename> ; запись PID в файл
|
||
--user=<username> ; сменить uid/gid на те, что связаны с указанным именем пользователя
|
||
--uid=uid[:gid1,gid2,...] ; сменить uid/gid на указанные числовые значения
|
||
--bind-fix4 ; лечение проблемы ухода генерированных пакетов на Linux с неверного интерфейса при использовании PBR (ipv4)
|
||
--bind-fix6 ; аналогично для ipv6
|
||
--fwmark=<int|0xHEX> ; бит в mark для предотвращения зацикливания. default = 0x40000000
|
||
--ctrack-timeouts=S:E:F[:U] ; таймауты conntrack для стадий tcp SYN, ESTABLISHED, FIN и для udp
|
||
--ctrack-disable=[0|1] ; 1 отключает conntrack
|
||
--server=[0|1] ; серверный режим. для обслуживания listener-ов меняются многие аспекты выбора направления и ip/port источника/приемника
|
||
--ipcache-lifetime=<int> ; время жизни записей кэша IP в секундах. 0 - без ограничений.
|
||
--ipcache-hostname=[0|1] ; 1 или отсутствие аргумента включают кэширование имен хостов для применения в стратегиях нулевой фазы
|
||
--reasm-disable=[proto[,proto]] ; отключить сборку фрагментов для списка пейлоадов : tls_client_hello quic_initial . без аргумента - отключить reasm для всего.
|
||
|
||
DESYNC ENGINE INIT:
|
||
--writeable[=<dir_name>] ; создать директорию для LUA с разрешением записи и поместить путь к ней в переменную env "WRITEABLE" (только одна директория)
|
||
--blob=<item_name>:[+ofs]@<filename>|0xHEX ; загрузить бинарный файл или hex строку в переменную LUA <item_name>. +ofs задает смещение от начала файла
|
||
--lua-init=@<filename>|<lua_text> ; однократно при старте выполнить LUA код из строки или из файла
|
||
--lua-gc=<int> ; интервал вызова сборщика мусора LUA в секундах. 0 отключает периодический вызов.
|
||
|
||
MULTI-STRATEGY:
|
||
--new ; начало нового профиля
|
||
--skip ; игнорировать профиль
|
||
--name=<name> ; установить имя профиля
|
||
--template[=<name>] ; использовать профиль как шаблон, задать имя
|
||
--cookie[=<string>] ; установить значение LUA переменной "desync.cookie", передаваемое каждому инстансу данного профиля
|
||
--import=<name> ; копировать настройки из шаблона в текущий профиль с полным замещением
|
||
--filter-l3=ipv4|ipv6 ; фильтр профиля : версия ip протокола
|
||
--filter-tcp=[~]port1[-port2]|* ; фильтр профиля : порты tcp
|
||
--filter-udp=[~]port1[-port2]|* ; фильтр профиля : порты udp
|
||
--filter-l7=proto[,proto] ; фильтр профиля : список протоколов потока. полный список доступен в help тексте программы.
|
||
--filter-ssid=ssid1[,ssid2,ssid3,...] ; фильтр профиля : имя wifi сети
|
||
--ipset=<filename> ; фильтр профиля : включающий список ip адресов или подсетей из файла. может быть смешанным ipv4+ipv6.
|
||
--ipset-ip=<ip_list> ; фильтр профиля : включающий фиксированный список ip адресов или подсетей через запятую
|
||
--ipset-exclude=<filename> ; фильтр профиля : исключающий список ip адресов или подсетей из файла. может быть смешанным ipv4+ipv6.
|
||
--ipset-exclude-ip=<ip_list> ; фильтр профиля : исключающий фиксированный список ip адресов или подсетей через запятую
|
||
--hostlist=<filename> ; фильтр профиля : включающий список доменов из файла
|
||
--hostlist-domains=<domain_list> ; фильтр профиля : включающий фиксированный список доменов из файла
|
||
--hostlist-exclude=<filename> ; фильтр профиля : исключающий список доменов из файла
|
||
--hostlist-exclude-domains=<domain_list> ; фильтр профиля : исключающий фиксированный список доменов из файла
|
||
--hostlist-auto=<filename> ; фильтр профиля : автоматически пополняемый по обратной связи включающий фильтр доменов
|
||
--hostlist-auto-fail-threshold=<int> ; параметр автолиста : количество неудач подряд для занесения в лист. по умолчанию 3
|
||
--hostlist-auto-fail-time=<int> ; параметр автолиста : максимальное время между неудачами без сброса счетчика. по умолчанию 60 секунд
|
||
--hostlist-auto-retrans-threshold=<int> ; параметр автолиста : количество tcp ретрансмиссий в одном сеансе для фиксации неудачи. по умолчанию 3
|
||
--hostlist-auto-retrans-maxseq=<int> ; параметр автолиста : исходящий relative sequence, после которого детект неудачи прекращается. по умолчанию 65536
|
||
--hostlist-auto-incoming-maxseq=<int> ; параметр автолиста : входящий relative sequence, после которого детект неудачи прекращается, а счетчик сбрасывается. по умолчанию 4096
|
||
--hostlist-auto-udp-out=<int> ; параметр автолиста : условие неудачи udp : количество исходящих пакетов больше или равно значению. по умолчанию 4
|
||
--hostlist-auto-udp-in=<int> ; параметр автолиста : условие неудачи udp : количество входящих пакетов меньше или равно значению. по умолчанию 1
|
||
--hostlist-auto-debug=<logfile> ; дебаг лог автолиста
|
||
|
||
LUA PACKET PASS MODE:
|
||
--payload=type[,type] ; внутрипрофильный фильтр : фильтр пейлоада для последующих инстансов внутри профиля. список пейлоадов доступен в help тексте программы.
|
||
--out-range=[(n|a|d|s|p)<int>](-|<)[(n|a|d|s|p)<int>] ; внутрипрофильный фильтр : диапазон счетчиков conntrack для последующих инстансов внутри профиля - исходящее направление
|
||
--in-range=[(n|a|d|s|p)<int>](-|<)[(n|a|d|s|p)<int>] ; внутрипрофильный фильтр : диапазон счетчиков conntrack для последующих инстансов внутри профиля - входящее направление
|
||
|
||
LUA DESYNC ACTION:
|
||
--lua-desync=<functon>[:param1=val1[:param2=val2]] ; при обработке профиля вызвать LUA инстанс с указанными параметрами, если соблюдены условия внутрипрофильных фильтров
|
||
```
|