Zapret: what's new

Где-то месяца два назад пробовал смотреть почему не работает приложение youtube TV.
Оно использует GQUIC, который zapret не опознает и не реагирует на него.
Думал уже надо делать поддержку GQUIC.
Но поставив свежую версию с apkmirror обнаружил, что GQUIC больше нет, есть IETF QUIC, и все и так работает.
Следовательно страждующим - обновляйте приложение.

У меня заработало вот это
com.google.android.youtube.tv_5.21.300-521300320_minAPI24(armeabi-v7a)(nodpi)_apkmirror.com.apk

На эмуляторе genymotion под образом android 12 версия для x64 не работает, но не из-за блокировки, а по причине отсутствия чего-то в системе. Возможно, кодеков. На реальном устройстве заработало без проблем

Делаю вывод, что тратить силы на поддержку GQUIC не имеет смысла, тк протокол устаревший, и используется только в старых версиях отдельных приложений. И есть обновление, которое отказалось от использования этого протокола

Приложение Android TV завелось на чистом Android 9 (не сток) без установленных gapps. Официальные требования - Android 7.0+. Следовательно, могу предположить, что требования не очень мощные, и должно пойти на достаточном количестве устройств. Но должно быть какие-то старые телики и приставки обломаются, поскольку нельзя на них обновить версию приложения.
Android 5.0 поддерживают только старые версии приложения 2.x

Для владельцев старых девайсов можно сделать дурение всего UDP на 443 без листов
--filter-udp=443 --dpi-desync=fake --dpi-desync-any-protocol --dpi-desync-cutoff=d2 --dpi-desync-repeats=СКОЛЬКО_НАДО
Хуже не будет

Или отдельно для quic через `–filter-udp=443 --filter-l7=quic", затем вышеописанное

В блокчеке 2 нововведения

  1. Переменная PARALLEL=1 включает параллельные попытки тестирования стратегий. По умолчанию не включается из-за опасности обидеть сайт дятло-долбежкой и получить неверный результат.

  2. Возможность задать ответы на диалоговые вопросы через переменные и убрать тем самым эти вопросы. Чтобы сразу запускался процесс и не было вопросов на что-нибудь нажать или что-нибудь ввести.
    CURL_MAX_TIME=1 CURL_MAX_TIME_QUIC=2 SKIP_DNSCHECK=1 DOMAINS=nnmclub.to IPVS=46 ENABLE_HTTP=1 ENABLE_HTTPS_TLS12=1 ENABLE_HTTPS_TLS13=1 ENABLE_HTTP3=1 REPEATS=8 PARALLEL=1 SCANLEVEL=standard BATCH=1 ./blockcheck.sh

Для использования с релизом достаточно заменить файл blockcheck.sh из git.

v70.5

  • nfqws: множественные фейки для всех типов протоколов через указание множественных параметров --dpi-desync-fake-???. (кроме syndata, это - не протокол)
  • nfqws: поддержка меж-пакетной дефрагментации QUIC фреймов CRYPTO. так стали делать свежие chrome броузеры. на более старой версии пакеты не собираются, хост не вытаскивается

Если не обновлять pktws, на последних chrome слетит дурение quic и перестанут работать хостлисты по quic. Либо придется отключать KYBER

В последней версии сделано распознавание discord и stun протоколов.
Поэтому нужды в ipset и any protocol больше нет.
Скрипт 50-discord удален.
Вместо него вы добавляете в основной конфиг еще один профиль такого вида.

--filter-udp=50000-50099 --filter-l7=discord,stun --dpi-desync=fake --dpi-desync-repeats=6

На linux при использовании скриптов запуска
NFQWS_PORTS_UDP=443,50000-50099

На винде
--wf-udp=443,50000-50099

repeats не знаю надо или нет. лучше без.
Пока только в исходниках. Прошу протестировать.

Есть один недостаток такого решения. Если на винде или BSD пойдет раздача торрентов и попадет на указанные порты, будет загрузка проца, тк все пойдет через winws. На linux нас спасет connbytes.
Зато избавляемся от фиксированной привязки к IP, за которыми надо следить.

v70.6

  • nfqws: определение протоколов discord voice IP discovery и STUN
  • nfqws: удален custom скрипт 50-discord. вместо него пишем в основные опции nfqws --filter-udp=50000-50099 --filter-l7=discord,stun --dpi-desync=fake и включаем перехват портов udp 50000-50099 в NFQWS_PORTS_UDP (пример : NFQWS_PORTS_UDP=443,50000-50099)
  • nfqws: модификация tls фейков на конкретный SNI. пример : --dpi-desync-fake-tls-mod=sni=www.google.com,rnd,dupsid
  • nfqws: поддержка различных модификаций для разных TLS фейков. множественные опции --dpi-desync-fake-tls и --dpi-desync-fake-tls-mod в одном профиле.
  • nfqws: обновление tls фейка по умолчанию. firefox 136.0.4 finger, no kyber, SNI=www.microsoft.com
  • blockcheck: в тестах tpws c множественными сплитами включаем --fix-seg на linux

В zapret-win-bundle удален ipset discord, стратегия переписана.
Удален TLS фейк гугла, вместо него используем tls-mod

Немного пояснений из области философии продукта.

По мере закручивания гаек может случиться так, что для пробития отдельных ресурсов потребуется точечный тюнинг. Более-менее общие стабильные стратегии для большинства ресурсов может не получиться найти.
Закончился ли на этом zapret ? Для классических потребителей - вероятно да.

А что будет дальше ? Дальше придется лезть через сторонние сервера.
Но и там нас ждут сюрпризы и противодействие.

Перед zapret я ставлю задачу точечного пробития канала до стороннего сервера. Может быть до своего сервера. Может быть с помощью встречного пробития со своего сервера.
Такой вот fine-tuning под один точечный пробив, который позволяет открыть всю сеть путем проксирования или VPN.

proxy/VPN и zapret могут не исключать друг друга, а дополнять. Практические кейсы уже есть.

1 Like

Несколько тестов скорости ипсетов , реализованных в tpws/nfqws, чтобы примерно представлять степень их эффективности.

Тестовая схема : загоняем 100000 случайных записей со случайным prefix length в диапазоне 16-128 для ipv6, 16-32 для ipv4.
Выполняем 100000 проверок на вхождение случайного адреса. Вычисляем время выполнения, из него высчитываем пропорцией количество проверок за секунду.

core i7 12700K : ipv4 1000000/s ipv6 125000/s
MT7621 : ipv4 29000/s ipv6 8300/s

Почему так отличается ? Потому что для проверки ipv6 нужно 128 проверок по hash, а для ipv4 - 32 проверки. Возросшая длина ключа с 8 до 20 байт, для которого считается hash, дополнительная операция ip6_and для 16 байт по пред-вычисленной маске подсети.
К тому же имеет значение вероятность попадания тестового адреса в ipset. Как только попадание случилось, дальнейшая проверка по другим маскам подсетей останавливается.
Но примерную картину себе представить можно.

Вероятно, реализация не самая эффективная, но есть как есть.
К счастью, операция проверки выполняется не на каждый пакет, если задействован conntrack. Выбранный профиль запоминается, перепроверка профиля происходит только при появлении имени хоста или опознавании L7 протокола.

Проблема бездумного использования ipset есть, но она не связана с эффективностью алгоритма ipset в tpws/nfqws, а связана с тяжелым процессом перенаправления трафика из ядра в процесс.

Если у вас есть стратегия для https, но надо еще и сделать частный случай для cloudflare, написать --ipset можно без проблем. Это удобно, не надо мучаться с поднятием отдельного инстанса через кастом скрипт.

Но если у вас появляется условный discord на порту udp 50000, а не дай бог еще и 50000-65535, и вам ничего больше оттуда не надо, вы не используете ограничитель в ядре connbytes (например, перенаправление идет через NFQWS_PORTS_UDP_KEEPALIVE или вовсе без скриптов запуска zapret, своими правилами для таблиц) и вы пишите --ipset, то это плохо. Пошел торент, попал на эти порты, и ваш nfqws мучается. А так бы в ядре сразу отсекалось по ipset-у ядра, и на nfqws даже не приходило.
ipset-ы ядра есть на всех системах , кроме windows. На windows при небольшом количестве адресов эти адреса можно загнать в собственный windivert фильтр --wf-raw, который можно построить на базе фильтра, генерируемого winws (–wf-save)

UPD. Ипсеты перведены но другой способ хранения в памяти с использованием AVL tree.
Эффективность по CPU выше в десятки раз, тк там нужна только одна проверка, а не до 32 или до 128, когда применялся hash поиск по равенству

Поясню по поводу --ipcache-hostname.
Этот параметр позволяет запоминать соответствие ip и hostname и со 2-го раза задействовать поиск профиля с учетом hostname прямо с самого начала. Включая нулевую фазу.
Но есть нюанс использования этой схемы вместе с autohostlist.

Предположим, у нас имеется такая схема :

–dpi-desync=syndata --hostlist-auto=autolist.txt

syndata будет применяться всегда, потому что профиль auto hostlist приоритетный

–dpi-desync=syndata --hostlist=list.txt

здесь без --ipcache-hostname syndata не будет применяться никогда, потому что на 0 фазе хост неизвестен

–ipcache-hostname --dpi-desync=syndata --hostlist=list.txt

здесь syndata будет применяться с 2 раза, когда будет известно соответствие ip->hostname. соответствие будет храниться --ipcache-lifetime секунд, 2 часа по умолчанию, или до рестарта процесса nfqws. соответствие хранится в RAM, никуда не сохраняется в файлы. Если попадется запрос на тот же IP с другим hostname, до выяснения хоста из содержимого запроса будет так, как будто бы идет обращение к первоначальному хосту со всеми вытекающими следствиями для алгоритма поиска профиля. Как только будет выяснен хост из запроса, произойдет повторный поиск профиля, который может привести к его смене. Хост в кэше будет замещен на последний вариант. Если пойдет опять первый хостнейм, то схема повторится. Это легко может быть , когда сайт использует несколько технических доменов или поддоменов на одном IP адресе. Он может работать нестабильно из-за чехарды разных доменов, конкурирующих на одном IP. Хаотичность может возникнуть так же из-за соответствия одного домена разным IP. Если rutracker.org ресолвится в 10 IP, а static.rutracker.org в те же 10 IP, то тут будет работать закон случая. То так работает, то сяк. Клиент берет рандомный IP для подключения. Так работает load balancing через DNS. Если даже перекрытия по доменам нет, но просто есть 10 IP, в которые ресолвится домен, то оно может срабатывать с 10 раза. Потому что на каждом запросе будет другой IP, и на каждый IP будет своя история со “2-м разом”
Надо понимать ограничения технологии ipcache. Это не взрывная фича, решающая все проблемы. Но пользы от нее может быть больше, чем вреда. Пробуйте, смотрите.

а что делать, если нужно, чтобы syndata работала по автохостлисту только на те домены, которые попадут в лист ? нужно клонировать профиль с автохостлистом

–ipcache-hostname --dpi-desync=syndata --hostlist=autolist.txt --new --hostlist-auto=autolist.txt

пока домена нет в autolist.txt, первый профиль срабатывать не будет. будет срабатывать профиль с автолистом. но поскольку там нет syndata, то она применяться не будет
когда домен попадет в autolist.txt, в следующий раз сработает первый профиль, а в нем и syndata.
дополнительной RAM такое написание не потребует, потому что листы хранятся в RAM только единожды, а из профилей на них идут ссылки. листы идентифицируются по типу (hostlist,ipset) и имени файла. внесение изменений в лист в RAM автоматически меняет его для всех профилей, потому что по сути это один лист в одном месте в памяти

вариант со стандартным листом из скриптов запуска :

NFQWS_OPT="--ipcache-hostname --dpi-desync=syndata <HOSTLIST_NOAUTO> --new <HOSTLIST>"
MODE_FILTER=autohostlist

При смене MODE_FILTER на hostlist такая схема будет избыточна и только тратить лишний ресурс cpu на повторную проверку листов без какого-либо смысла.

параметр --ipcache-hostname глобален и не относится к профилю. где его писать значения не имеет

Новый фильтр профиля в nfqws : --filter-ssid.
Берет перечень сетей wifi через запятую.
Реализовано только для linux !
Если вы видите в “iw dev wlan0 info” ssid, то это должно работать.
Если вы там его не видите, это не будет работать.
Почему-то в android работает, в linux под wpa_supplicant ssid не возвращается. Почему - пока не выяснено.
Но делалось это в основном с прицелом на android.

По поводу различий с виндой.
В винде есть аналогичный, но глобальный параметр, --ssid-filter.
Он включает winws, если система подключена к одной из указанных wifi сетей и выключает его, если это не так. При выключении winws полностью отключает себя от windivert, тем самым ресурсы не тратятся совсем, пока сеть снова не всплывет.
Можно запустить несколько инстансов winws , каждый для разных сетей.

В linux так сделать проблематично.
Интерфейс для разных сетей все равно один. wlan0, допустим.
Фильтра по ssid в ip/nf tables нет. Слишком частное понятие.
Несколько обработчиков nfqueue повесить на одну очередь невозможно.
Если делать как в винде, разные инстансы nfqws должны отключать себя от очереди при определенных условиях, а другие подключать. При этом должна быть какая-то синхронизация, чтобы не было гонок. Не получится сделать пересечение по условиям. Разные инстансы будут пытаться включаться.
Это все сложно и ненадежно.
Потому решение принято другое.
Рулит очередь , как и раньше, только один инстанс. Он никуда не отключается.
Но в профиле появился параметр --filter-ssid.

Схема задействования примерно такая

iptables -t mangle -I POSTROUTING -o wlan0 -p tcp -m multiport --dports 80,443 -m connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes 1:6 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num 200 --queue-bypass
iptables -t mangle -I POSTROUTING -o wlan0 -p udp --dport 443 -m connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes 1:6 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num 200 --queue-bypass
nfqws --qnum 200 \
 --filter-ssid=home_wifi --filter-tcp=443 --dpi-desync=fake --dpi-desync-ttl=5 --new
 --filter-ssid=rabota_wifi --filter-udp=443 --dpi-desync=fake --dpi-desync-repeats=5 --new
 --filter-ssid=rabota_wifi --filter-tcp=80,443 --dpi-desync=fake,multisplit --dpi-desync-ttl=3

ПРЕЖДЕ ЧЕМ ЭТИМ ПОЛЬЗОВАТЬСЯ СДЕЛАЙТЕ
iw dev wlan0 info
(конечно, вы догадались, что wlan0 нужно заменить на свой wireless интерфейс)
ЕСЛИ ТАМ НЕТ SSID, РАБОТАТЬ НЕ БУДЕТ

Сверка ssid производится по исходящему интерфейсу для пакетов прямого направления и по входящему интерфейсу пакетов обратного направления.
Не чаще раза в секунду обновляется список interface_name => ssid
При приходе пакета ищется ssid по interface_name. Дальше работает алгоритм поиска профиля

Таким способом можно сделать раздельное дурение разные wifi сетей и не трогать остальные, чтобы не испортить

В tpws аналогичная функция не реализована, поскольку там нельзя определить исходящий интерфейс для соединения. Теоретически может быть балансировака нагрузки, исходящие пакеты уходить по разным аплинкам, а входящие приходить через третий аплинк. linux позволяет писать очень сложные ip rules. Пытаться угадать интерфейс, куда пойдут пакеты соединения, дублированием функций маршрутизации linux, занятие сложное и неблагодарное. Всего не учтешь.
nfqws получает пакет с уже принятым routing decision. Действие выполняется по каждому пакету раздельно.
Но можно сделать вариант как в windows. Переводить его в режим без дурения, если нет нужной сети.

Дополнительная удобная функция для android : --debug=android
позволяет смотреть логи по logcat
Работает только в версиях, собранных под NDK

1 Like

Оказывается, вариант с выдергиванием SSID через nl80211 сплошняком не работает на обычном linux и работает на android. Пробовал разные системы и разные wifi адаптеры. Ядра все новые - 6.8+. Но почему-то когда не возвращается SSID через nl, то через wireless extensions он всегда возвращается.
Что за чертовщина ? wext считается deprecated и реализован как compat layer over cfg80211
То есть новая подсистема имеет SSID, выдает его через старый API и не выдает через новый.
И ладно если бы я накосячил с netlink , но тоже самое с официальными тулзами.

wext : iwgetid
nl80211 : iw dev wlan0 info

Так можно продебажить нетлинк
iw --debug dev wlan0 info
Чисто по дампу hex в блоке возвращаемых данных нет SSID. Нет аттрибута, содержащего SSID.

UPD. Сломано, начиная с ядра 5.19 до самых последних. 6.14 не работает

В zapret-win-bundle появился curl-kyber.exe
А так же blockcheck_kyber.cmd и alias “blockcheck-kyber” в cygwin prompt.

Обычный curl.exe собран с openssl 3.4.0 и не поддерживает kyber.
curl-kyber.exe собран с openssl 3.5.0 и поддерживает kyber.
kyber работает как на tls, так и на quic
Для QUIC на обоих curl-ах использована конфигурация --with-nghttp3 --with-openssl-quic

Таким способом можно сравнить какие стратегии работают на kyber, какие нет.

На linux сейчас точка перехода к новой openssl.
На 3.5.0 curl будет с kyber, на меньшей версии - нет.
Новейшие дистрибутивы уже включают openssl 3.5.0, классические пока еще все сидят на более старых.
Таким образом в зависимости от дистрибутива могут быть разные результаты из-за наличия/отсутствия kyber.

Здесь есть статики под все платформы.

Последний без кибера - 8.13.0
Новее - с кибером

Если на openwrt нет места, можно переписать в /tmp, дать ему chmod +x и задать CURL=/tmp/curl перед запуском blockcheck. Так вы сможете нормально протестировать современный вариант, не ограничиваясь урезанным собственным curl от openwrt

Заметил такую ерунду.
Клиент отсылает 2 кибер куик пакета длиной 1200.
На роутере MT7621 на br-lan получается пакет 2400.
На wan он уходит как 2x1200. Все хорошо.
Включаем nfqueue, и все это ломается. Один пакет теряется. nfqws не срабатывает как надо.

Вылечилось вот так

for int in lan1 lan2 lan3 lan4; do
 ethtool -K $int rx-gro-list off
done

если включить rx-gro-list на PC с 2 сетевухами realtek, проблемы не наблюдается
какой-то косяк драйверов медиатек ?
происходит как на eth, так и на wlan

Так можно сделать универсально без привязки к портам и именам интерфейсов точек доступа
append_separator_list()
{
    # $1 - var name to receive result
    # $2 - separator
    # $3 - quoter
    # $4,$5,... - elements
    local _var="$1" sep="$2" quo="$3" i

    eval i="\$$_var"
    shift; shift; shift
    while [ -n "$1" ]; do
        if [ -n "$i" ] ; then
            i="$i$sep$quo$1$quo"
        else
            i="$quo$1$quo"
        fi
        shift
    done
    eval $_var="\$i"
}
resolve_lower_devices()
{
    # $1 - bridge interface name
    [ -d "/sys/class/net/$1" ] && {
        find "/sys/class/net/$1" -follow -maxdepth 1 -name "lower_*" |
        {
            local l lower lowers
            while read lower; do
                lower="$(basename "$lower")"
                l="${lower#lower_*}"
                [  "$l" != "$lower" ] && append_separator_list lowers ' ' '' "$l"
            done
            printf "$lowers"
        }
    }
}

# it breaks nfqueue
lans=$(resolve_lower_devices br-lan)
for int in $lans; do
 ethtool -K $int rx-gro-list off
done

В исходниках сделано так, чтобы десинхронизация udp шла на все replay пакеты, кроме fake.
Если DPI stateless и сечет любые quic initial, то при применении ipfrag2 2-й пакет уходил в оригинале. Что вызывало триггер блока.
Теперь fake уходит как раньше - только перед первым пакетом серии reasm. Все остальное идет на каждый пакет серии.

Пример : --dpi-desync=fake,ipfrag2
Вход : 2 x quic initial kyber
Выход : fake, frag(quic1), frag(quic2)

Надоели однотипные вопросы и issue по бинарикам.
Надо предвосхитить

./install_bin.sh 
no binaries found
you need to download release from github or build binaries from source
building from source requires debian/ubuntu packages : make gcc zlib1g-dev libcap-dev libnetfilter-queue-dev libmnl-dev libsystemd-dev
libsystemd-dev required only on systemd based systems
on distributions with other package manager find dev package analogs
to compile on systems with systemd : make systemd
to compile on other systems : make

Как правило на github выкладываются только исходники.
Бинарики либо отсутствуют вовсе, либо собираются автоматически гитхабом в рамках релиза.
Это общепринятая практика.
Если вы скачали исходники, там бинариков нет. Будет попытка собрать, которая по умолчанию обречена на провал. Это нормально, поскольку требуются dev пакеты. Если вы не понимаете что это, вам linux противопоказан. Не мучайте себя сборкой, качайте релиз.
Если вы скачали embedded релиз на традиционный linux или mac, будет отлуп. Там отсутствуют файлы, необходимые для традиционной системы. Они были выкинуты, чтобы сократить обьем релиза. Эта версия для роутеров.

Оказалось, что в новых версиях OpenBSD сломан (намеренно или нет - вопрос) механизм получения адреса назначения из /dev/pf через ioctl DIOCNATLOOK. Он используется при перенаправлении при помощи rdr-to. getsockname возвращает адреса заворота, потому нужен доп механизм для выяснения оригинального адреса назначения.
Предлагается использовать divert-to вместо rdr-to. Тогда getsockname выдает оригинальный адрес назначения, специального механизма не требуется.
В openbsd схема работы tpws с pf приравнена к варианту в freebsd.
Если хотите делать rdr, нужно --enable-pf. Это сделано, чтобы не сыпало ошибками DIOCNATLOOK.
В openbsd 6.8 DIOCNATLOOK еще срабатывает, в 7.4 - уже нет

Если tpws остается с адресом заворота, то срабатывает механизм детекта зацикливания, соединение разрывается.

Преимущество divert-to в отсутствии требования рута. /dev/pf требует рута. Открытие /dev/pf происходит до сброса привилегий, потом идет сброс, так что tpws все равно выполняется не под рутом. Но если /dev/pf не нужен, то tpws можно запускать сразу не от рута.
Правда, я бы не рекомендовал так делать, поскольку придется использовать непривилегированные порты >=1024 и перенаправлять трафик туда. Если вдруг tpws по какими-то причинам слетит или не будет запущен, любой процесс может занять его место и получать трафик.
Лучше все же сажать tpws на порты <1024, а для этого нужен запуск от рута. Аналога linux caps в BSD нет.

На некоторых провайдерах есть гадкие фильтры, блокирующие любой quic.
Сканируются все пакеты, при обнаружении идет блок двойной связки ip-port.
Например, этим страдает globalnet и его дочерние конторы.
Фейки тут бесполезны, единственный шанс - ipfrag2.
Потому в nfqws сделана десинхронизация каждого пакета из кибер куика, не только первого, кроме метода fake. fake идет перед группой кибер пакетов, но дальше каждый кибер пакет фрагментируется на уровне ip. В предыдущих версиях шла работа только с первым пакетом кибер группы, остальные отсылались как есть.

Регулярно возникает такой вопрос.
Как мне сделать, чтобы дурился трафик не со всех адресов в локальной сети.
Только мой комп, остальные нет. Все, только не телик. Только проводные, но не wifi. И тд.
Критериев можно придумать бесконечное множество.
Философия zapret категорически отвергает шаблонные схемы. Да, можно было бы сделать переменную типа FOOL_ONLY_FROM=192.168.10.0/24. Это просто и удобно. Но не универсально.
Потому поступаем иначе.
Вводится переменная FILTER_MARK=0x10000000.
Если она установлена, в правила ip/nf tables добавляется фильтр по этому mark bit.
Устанавливаете mark bit вы сами по каким угодно критериям. Учите ip/nf tables, за вас делать это zapret не будет.
Важно установить mark до фактического перенаправления трафика. Перенаправление на tpws идет на этапе prerouting или output. На nfqws - на этапе postrouting. Потому универсально это можно сделать

  • для nftables в хуках prerouting и output с приоритетом -102 или ниже
  • для iptables потребуется синхронизация с применением правил zapret. Можно использовать скрипты, указываемые в переменных конфига INIT_FW_POST_UP_HOOK и INIT_FW_PRE_DOWN_HOOK. Правила следует добавлять через iptables -t mangle -I PREROUTING или iptables -t mangle -I OUTPUT для проходящего и исходящего с самой системы трафика , соответственно. Можно так же и отказаться от INIT_APPLY_FW и применять фаервол самостоятельно (в доке Прикручивание к системе управления фаерволом или своей системе запуска)

Для nftables основная схема процессинга nfqws - POSTNAT. nfqws не видит исходных адресов локальной сети, потому даже если вписать дополнительные условия в правила, это не сработает, если надо отсеивать отдельные клиенты в локалке.

Пример команд для nftables :

nft add table inet mytable
nft add chain inet mytable pre "{type nat hook prerouting priority -102;}"
nft add rule inet mytable pre iifname eth2 mark set mark or 0x10000000
nft add rule inet mytable pre ip saddr 192.168.10.0/24 mark set mark or 0x10000000
nft add rule inet mytable pre ip6 saddr fd00:1::/16 mark set mark or 0x10000000
nft add chain inet mytable out "{type nat hook output priority -102;}"
nft add rule inet mytable out mark set mark or 0x10000000

Здесь дурится

  • все, исходящее с самой системы
  • все, пришедшее с интерфейса eth2
  • все, имеющее source ipv4 192.168.10.0/24
  • все, имеющее source ipv6 fd00:1::/16

Осталось это куда-нибудь красиво поместить. На openwrt лучше всего использовать файлы в /etc/nftables.d . В этой директории пишутся файлы, содержащие не команды nft, а файлы описания цепочек внутри таблицы fw4

Перепись того же самого в файл /etc/nftables/99-my.nft

chain my_pre {
    type nat hook prerouting priority -102;
    iifname eth2 mark set mark or 0x10000000;
    ip saddr 192.168.10.0/24 mark set mark or 0x10000000;
    ip6 saddr fd00:1::/16 mark set mark or 0x10000000;
}
chain my_out {
    type nat hook output priority -102;
    mark set mark or 0x10000000;
}

А если надо только wifi ? Тут вам придется переиграть стандартную lan/wan схему в openwrt.
Отделить проводные интерфейсы в lan1, беспроводные в lan2.
Будет 2 моста или 1 мост, а другой интерфейс без моста.
Или даже сделать 2 wifi сети с разными интерфейсами. Одну для себя, другую для роскомнадзора.
Чтобы входящие интерфейсы были разными , имели разные локальные подсети.
И с каждого интерфейса настроить маршрутизацию в wan.

Есть и другой способ решить поставленную задачу. См custom script 20-fw-extra

Добавлен новый фулинг ts.

ts прибавляет к значению TSval таймштампа tcp значение ts increment (по умолчанию -600000). Сервера отбрасывают пакеты с TSval в определенных пределах. По практическим тестам инкремент должен быть где-то от -100 до -0x80000000. timestamps генерирует клиентская ОС. В linux таймштампы включены по умолчанию, в windows выключены по умолчанию. Можно включить через команду netsh interface tcp set global timestamps=enabled. ts fooling требует, чтобы таймштампы были включены, иначе работать не будет. Включать надо на каждом клиентском устройстве. TSecr оставляется без изменений. Так же требуется, чтобы сервер понимал timestamps, но это в большинстве случаев так.

Вроде неплохой фулинг. Со всеми ОС работает, где есть timestamps.
В Windows хотя по умолчанию ts выключены для исходящих tcp, но если входящий tcp идет с ts, то система отвечает тоже с ts. Весь сеанс идет с ts. Поэтому с windows серверами оно тоже работает без действий со стороны сервера. Таймштампы в винде были реализованы еще в XP SP2 и server 2003.

Делаю поддержку более корректной работы с хостами типа “vk.com:8000” , “1.1.1.1”, “[fda6:1800::5]:8000”
Если хост похож на IP адрес, то всю мишуру отсекаем, оставляя голое текстовое представление IP.
Поиск по хостлистам идет только по целой строке. “1.1.1.1”, “1.1.1”, “1.1”, “1” - такого больше не будет.
Если это не IP, то отсекаем : и все, что после него.

Такие хосты приходят в хедере Host: в http. В TLS в случае запроса по IP обычно не вставляется SNI extension. Порт так же не вставляется, если запрос идет по домену на нестандартный порт

В связи с попытками давить на голосовой трафик воцап/телеги добавил custom script 50-stun4all.
Суть этого скрипта, как и 50-wg4all, в распознавании на уровне ядра сигнатуры соотв протокола для перенаправления в nfqws.
Чтобы не завязываться на номер порта, не перехватывать весь порт и тем более все порты
Нагрузки практически нет
В отличие , если бы вы сделали что-то вроде : winws --wf-udp=* --filter-l7=stun --dpi-desync=fake. Последнее - это ужас. Для достижения того же эффекта на винде без зубодробительной нагрузки на проц можно написать собственный raw windivert filter. Проверка пейлоадов там есть. Запускать отдельным инстансом