## Зачем это нужно Автономное средство противодействия DPI, которое не требует подключения каких-либо сторонних серверов. Может помочь обойти блокировки или замедление сайтов HTTP(S), сигнатурный анализ TCP и UDP протоколов, например, с целью блокировки VPN. Может использоваться для частичной прозрачной обфускации протоколов. Проект нацелен прежде всего на маломощные embedded устройства - роутеры, работающие под OpenWrt. Поддерживаются традиционные Linux-системы, FreeBSD, OpenBSD, Windows. В некоторых случаях возможна самостоятельная прикрутка решения к различным прошивкам. [Полный мануал](manual.md) ## Поддержать разработчика Если вы считаете проект полезным и желаете поддержать разработку, направляйте ваши пожертвования на следующие адреса криптокошельков : USDT `0x3d52Ce15B7Be734c53fc9526ECbAB8267b63d66E` (предпочительно сеть ERC-20) BTC `bc1qhqew3mrvp47uk2vevt5sctp7p2x9m7m5kkchve` ETH `0x3d52Ce15B7Be734c53fc9526ECbAB8267b63d66E` ## Чем это отличается от zapret1 zapret2 является дальнейшим развитием проекта zapret. Проблема его основной части *nfqws1* в том, что он перегружен опциями и в условиях нарастающего противостояния регулятора и пользователей не обеспечивает достаточную гибкость воздействия на трафик. Обход DPI требует все более тонких и специфических воздействий, которые меняются со временем, а старые перестают работать. Стратегии - это программы, управляющие сценарием атаки на DPI. В *nfqws1* они зашиваются в C код. Написание C кода - занятие нелегкое, требующее достаточной квалификации разработчика и времени. Цель *nfqws2* - сделать так, чтобы программы стратегий мог написать любой человек, владеющий знаниями в области сетей, понимающий уязвимости DPI или хотя бы область , в которой их можно искать, плюс владеющий базовыми навыками программирования. *nfqws2* оставляет в себе практически тот же функционал - распознавание протоколов, реассемблинг, дешифровка, управление профилями, хостлисты, ipset-ы, базовая фильтрация. Но он полностью лишается возможностей самостоятельно воздействовать на трафик. Часть "дурения" переносится в скриптовой язык программирования LUA. LUA код получает от C кода структурированное представление приходящих пакетов в виде дерева (диссекты), подобного тем, что вы видите в wireshark. Туда же приходят результаты сборки или дешифровки частей некоторых протоколов (tls, quic). С код предоставляет функции-хелперы, позволяющие отсылать пакеты, работать с двоичными данными, разбирать TLS, искать маркер-позции и т.д. Имеется библиотека хелперов, написанных на LUA, а так же готовая библиотека программ атаки на DPI (стратегий), реализующая функции *nfqws1* в расширенном варианте и с большей гибкостью. Вы всегда сможете взять и дописать что-то свое. В этом и есть смысл, чтобы борьбой с DPI смог заняться любой, кто разбирается в пакетах. Мог "потыкать" его, проверить свои идеи. А потом поделиться с друзьями своим решением "одного клика". zapret2 - инструмент для таких энтузиастов. Но это не готовое решение для чайников. Проект не ставит себе целью сделать все простым для всех. Автор считает, что это невозможно в принципе по обьективным причинам. ## С чего начать Хотелось бы избежать [талмуда](manual.md) на главной странице. Поэтому начнем со способа запуска *nfqws2* и описания способов портирования стратегий *nfqws1* - как в *nfqws2* сделать то же самое, что можно было в *nfqws1*. Когда вы поймете как это работает, вы можете посмотреть LUA код, находящийся "под капотом". Разобрать как он работает, попробовать написать что-то свое. "талмуд" обязательно будет, как он есть у любых более-менее сложных проектов. Он нужен как справочник. ### Механика обработки трафика Изначально сетевой трафик в любой ОС появляется в ядре. Первая задача - извлечь его оттуда и перенаправить на процесс *nfqws2*. Эта задача решается в Linux с помощью iptables и nftables, в BSD - ipfw и pf, в Windows - windivert. Процесс перенаправления трафика из ядра отнимает достаточно много ресурсов, поэтому лучше всего отфильтровать как можно больше прямо в нем. Для экспериментов на Linux можно начать со следующих nftables, которые перенаправят начальные пакеты соединений на порты tcp 80,443 и udp 443 в очередь NFQUEUE с номером 200. ``` nft delete table inet ztest nft create table inet ztest nft add chain inet ztest post "{type filter hook postrouting priority 101;}" nft add rule inet ztest post meta mark and 0x40000000 == 0 tcp dport "{80,443}" ct original packets 1-12 queue num 200 bypass nft add rule inet ztest post meta mark and 0x40000000 == 0 udp dport "{443}" ct original packets 1-12 queue num 200 bypass sysctl net.netfilter.nf_conntrack_tcp_be_liberal=1 nft add chain inet ztest pre "{type filter hook prerouting priority -101;}" nft add rule inet ztest pre meta mark and 0x40000000 == 0 tcp sport "{80,443}" ct reply packets 1-12 queue num 200 bypass nft add rule inet ztest pre meta mark and 0x40000000 == 0 udp sport "{443}" ct reply packets 1-12 queue num 200 bypass nft add chain inet ztest predefrag "{type filter hook output priority -401;}" nft add rule inet ztest predefrag "mark & 0x40000000 != 0x00000000 notrack" ``` В windows функция перехвата вшита прямо в код движка для windows, который называется *winws2*. Он использует драйвер windivert. Для перехвата портов целиком используются параметры `--wf-tcp-in`, `--wf-tcp-out`, `--wf-udp-in`, `--wf-udp-out`. Они относятся к протоколам tcp или udp, к входящим или исходящим пакетам. Например, `--wf-tcp-out=80,443`. Для более точного перехвата пишутся фильтры на языке фильтров windivert. Он похож на язык фильтров tcpdump или wireshark. Фильтры отдаются *winws2* в параметрах `--wf-raw-part`. Конструктор фильтров обьединяет все указанные опции перехвата в единый raw фильтр и запускает перехват windivert. К сожалению, самый болезненный недостаток windivert (а так же BSD ipfw и pf) - отсутствие ограничителя на номер пакета в соединении (connbytes в iptables, ct packets в nftables). windivert вообще не отслеживает соединения. Поэтому если перехватывать порт целиком, то все соединение по указанному направлению пойдет на перехват, что нелегко для процессора, если там передаются многие мегабайты. Поэтому по возможности пишите собственные фильтры windivert, проверяющие тип пейлоада хотя бы частично. Дофильтрацию может выполнить *winws2*. Дальше под рутом нужно запустить *nfqws2* с параметрами командной строки. Они строятся примерно следующим образом : ``` nfqws2 --qnum 200 --debug --lua-init=@zapret-lib.lua --lua-init=@zapret-antidpi.lua \ --filter-tcp=80,443 --filter-l7=tls,http \ --payload=tls_client_hello --lua-desync=fake:blob=fake_default_tls:tcp_md5:tls_mod=rnd,rndsni,dupsid \ --payload=http_req --lua-desync=fake:blob=fake_default_http:tcp_md5 \ --payload=tls_client_hello,http_req --lua-desync=multisplit:pos=1:seqovl=5:seqovl_pattern=0x1603030000 ``` Данный пример предполагает, что в той же директории находятся файлы `zapret-lib.lua` - библиотека хелперов на LUA и `zapret-antidpi.lua` - библиотека базовых стратегий. `--lua-init` может содержать LUA код в виде строки. Так удобно писать простой код, например присвоить константу переменной, чтобы не создавать файлы ради этой мелочи. Либо подцепляется файл, если значение параметра начинается с `@`. Код из `--lua-init` выполняется 1 раз при старте. Далее указаны параметры `--lua-desync`. Они содержат имя LUA функции, вызываемой при обработке каждого пакета, проходящего через профиль мультистратегии. После двоеточия и через двоеточия следуют параметры для данной функции в формате `param[=value]`. В примере реализована стратегия ``` nfqws --qnum 200 --debug \ --filter-tcp=80,443 --filter-l7=tls,http \ --dpi-desync=fake,multisplit --dpi-desync-fooling=md5sig --dpi-desync-split-pos=1,midsld \ --dpi-desync-split-seqovl=5 --dpi-desync-split-seqovl-pattern=0x1603030000 \ --dpi-desync-fake-tls-mod=rnd,rndsni,dupsid ``` Что сразу заметно - это наличие понятия "payload". В *nfqws1* были только протоколы соединения, которые участвовали в фильтрации профилей. Они так же остались в *nfqws2*, но введено другое понятие - тип пейлоада. Пейлоад - это содержание текущего пакета. Тип пейлоада - тип данных, содержащихся в пакете или группе пакетов. Например, протокол соединения может быть tls, а пейлоады - tls_client_hello, tls_server_hello, unknown. Другое важное отличие - отсутствие жестко определенных фаз десинхронизации. То, что вы раньше писали как `fake,multisplit` реализуется двумя последовательно вызываемыми LUA функциями. Их может быть столько, сколько нужно, учитывая логику прохождения пакетов и операций с ними, и у каждой могут быть свои параметры. Может даже несколько раз вызываться одна и так же функция с разными параметрами. Так, например, можно послать несколько фейков, причем с разными фулингами. Конкретный вызов `--lua-desync` функции называется инстансом. Инстанс - это связка имени функции, номера вызова внутри профиля и номера самого профиля. Это похоже на одну программу, которую можно запустить много раз с разными параметрами. Другое немаловажное отличие - поддержка автоматической tcp сегментации средствами `zapret-lib.lua`. Вам больше не нужно думать о размерах отсылаемых tcp пакетов. По каждому соединению отслеживается MSS. Если пакет не влезает в MSS, выполняется сегментация. Например, это может случиться при отправке tls фейка с kyber. Или если вы режете kyber tls так, что одна из частей получается размером 1600 байт, что, очевидно, не влезает в MTU. Или если вы задали seqovl=10000. В *nfqws1* такое значение вызвало бы ошибку. Функция LUA `rawsend_dissect_segmented` отправит несколько tcp сегментов с начальным sequence -10000 общим размером 10000 байт, в последнем из которых будет кусок оригинального сообщения. В *nfqws2* нет жестко зашитых параметров кастомных фейков типа `--dpi-desync-fake-tls`, `dpi-desync-fake-http` и тд. Вместо них есть блобы. Блоб (blob) - это переменная LUA типа *string*, содержащая блок двоичных данных произвольной длины. От 1 байта до гигабайтов. *nfqws2* автоматически инициализирует блобы со стандартными фейками tls, http, quic, как это и было в *nfqws1*. Блобы могут быть заданы как hex-строка прямо в параметре desync функции, либо пред-загружены при старте с помощью параметра `--blob=name:0xHEX|[+ofs]@filename` Что касается профилей мультистратегии и хостлистов , то они остались практически в неизменном виде. За исключением одной тонкости автолиста. Теперь профиль с автолистом берет на себя только те соединения, для которых уже известен хост. Пока хоста нет - они проходят мимо. В *nfqws1* они падали на профиль с автолистом. ``` nfqws2 --qnum 200 --debug --lua-init=@zapret-lib.lua --lua-init=@zapret-antidpi.lua \ --filter-tcp=80 --filter-l7=http --hostlist=mylist1.txt --lua-desync=multisplit --new \ --filter-tcp=80 --filter-l7=http --hostlist-exclude=mylist2.txt --lua-desync=fake:blob=0x00000000:ip_ttl=5:ip6_ttl=3 --lua-desync=multidisorder:pos=5,endhost-1 --new \ --filter-tcp=443 --filter-l7=tls --hostlist=mylist1.txt --lua-desync=multidisorder ``` Параметры *nfqws1* start/cutoff (`--dpi-desync-start`, `--dpi-desync-cutoff`, ...) теперь называются диапазонами (ranges). Остались только 2 range : `--in-range` и `--out-range`. Они относятся к входящему и исходящему направлению соответственно. Да, теперь можно полноценно работать как с входящими пакетами, так и с исходящими. Есть и специальный режим для сервера - `--server`, который адаптирует интерпретацию IP адресов и портов источника/приемника, чтобы корректно работали ipset-ы и фильтры. range задается как `mX-mY`, `mX