[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-73179":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":17,"stars7d":18,"stars30d":19,"stars90d":16,"forks30d":16,"starsTrendScore":20,"compositeScore":21,"rankGlobal":10,"rankLanguage":10,"license":10,"archived":22,"fork":22,"defaultBranch":23,"hasWiki":22,"hasPages":22,"topics":24,"createdAt":10,"pushedAt":10,"updatedAt":33,"readmeContent":34,"aiSummary":35,"trendingCount":16,"starSnapshotCount":16,"syncStatus":15,"lastSyncTime":36,"discoverSource":37},73179,"zapret2","bol-van\u002Fzapret2","bol-van","anti-dpi software","",null,"C",4468,169,53,2,0,11,139,456,61,28.69,false,"master",[25,26,27,28,29,30,31,32],"anti-dpi","censorship-circumvention","freebsd","linux","openbsd","openwrt","russian","windows","2026-06-12 02:03:09","## English\n\n[Manual](manual.en.md)\n\n## Зачем это нужно\n\nАвтономное средство противодействия DPI, которое не требует подключения каких-либо сторонних серверов. Может помочь\nобойти блокировки или замедление сайтов HTTP(S), сигнатурный анализ TCP и UDP протоколов, например, с целью блокировки\nVPN. Может использоваться для частичной прозрачной обфускации протоколов.\n\nПроект нацелен прежде всего на маломощные embedded устройства - роутеры, работающие под OpenWrt. Поддерживаются\nтрадиционные Linux-системы, FreeBSD, OpenBSD, Windows. В некоторых случаях возможна самостоятельная прикрутка\nрешения к различным прошивкам.\n\n[Полный мануал](manual.md)\n\n\n## Поддержать разработчика. Donations\n\nЕсли вы считаете проект полезным и желаете поддержать разработку, направляйте ваши пожертвования на следующие адреса криптокошельков :\n\nIf you find this project useful and wish to donate here are crypto wallets :\n\nUSDT ERC `0x3d52Ce15B7Be734c53fc9526ECbAB8267b63d66E` \n\nUSDT TRC `TEzAAtn4VhndqEaAyuCM78xh5W2gCjwWEo`\n\nBTC  `bc1qhqew3mrvp47uk2vevt5sctp7p2x9m7m5kkchve`\n\nETH  `0x3d52Ce15B7Be734c53fc9526ECbAB8267b63d66E`\n\n\n## Чем это отличается от zapret1\n\nzapret2 является дальнейшим развитием проекта zapret.\nПроблема его основной части *nfqws1* в том, что он перегружен опциями и в условиях нарастающего противостояния регулятора и пользователей\nне обеспечивает достаточную гибкость воздействия на трафик.\nОбход DPI требует все более тонких и специфических воздействий, которые меняются со временем, а старые перестают работать.\n\nСтратегии - это программы, управляющие сценарием атаки на DPI. В *nfqws1* они зашиваются в C код. Написание C кода - занятие нелегкое,\nтребующее достаточной квалификации разработчика и времени.\n\nЦель *nfqws2* - сделать так, чтобы программы стратегий мог написать любой человек, владеющий знаниями в области сетей, понимающий уязвимости DPI\nили хотя бы область , в которой их можно искать, плюс владеющий базовыми навыками программирования.\n\n*nfqws2* оставляет в себе практически тот же функционал - распознавание протоколов, реассемблинг, дешифровка, управление профилями, хостлисты, ipset-ы, базовая фильтрация.\nНо он полностью лишается возможностей самостоятельно воздействовать на трафик. Часть \"дурения\" переносится в скриптовой язык программирования Lua.\n\nLua код получает от C кода структурированное представление приходящих пакетов в виде дерева (диссекты), подобного тем, что вы видите в wireshark.\nТуда же приходят результаты сборки или дешифровки частей некоторых протоколов (tls, quic).\nС код предоставляет функции-хелперы, позволяющие отсылать пакеты, работать с двоичными данными, разбирать TLS, искать маркер-позиции и т.д.\nИмеется библиотека хелперов, написанных на Lua, а так же готовая библиотека программ атаки на DPI (стратегий), реализующая функции *nfqws1* в расширенном варианте\nи с большей гибкостью.\n\nВы всегда сможете взять и дописать что-то свое. В этом и есть смысл, чтобы борьбой с DPI смог заняться любой, кто разбирается в пакетах.\nМог \"потыкать\" его, проверить свои идеи. А потом поделиться с друзьями своим решением \"одного клика\".\nzapret2 - инструмент для таких энтузиастов. Но это не готовое решение для чайников. Проект не ставит себе целью сделать все простым для всех.\nАвтор считает, что это невозможно в принципе по обьективным причинам.\n\n\n## С чего начать\n\nХотелось бы избежать [талмуда](manual.md) на главной странице. Поэтому начнем со способа запуска *nfqws2* и описания способов портирования стратегий *nfqws1* - как в *nfqws2* сделать то же самое, что можно было в *nfqws1*.\nКогда вы поймете как это работает, вы можете посмотреть Lua код, находящийся \"под капотом\". Разобрать как он работает, попробовать написать что-то свое, руководствуясь [талмудом](manual.md) как справочником.\n\n### Механика обработки трафика\n\nИзначально сетевой трафик в любой ОС появляется в ядре. Первая задача - извлечь его оттуда и перенаправить на процесс *nfqws2*.\nЭта задача решается в Linux с помощью iptables и nftables, в BSD - ipfw и pf, в Windows - windivert.\nПроцесс перенаправления трафика из ядра отнимает достаточно много ресурсов, поэтому лучше всего отфильтровать как можно больше прямо в нем.\n\nДля экспериментов на Linux можно начать со следующих nftables, которые перенаправят начальные пакеты соединений на порты tcp 80,443 и udp 443 в очередь NFQUEUE с номером 200.\n\n```\nnft delete table inet ztest\nnft create table inet ztest\nnft add chain inet ztest post \"{type filter hook postrouting priority 101;}\"\nnft add rule inet ztest post meta mark and 0x40000000 == 0 tcp dport \"{80,443}\" ct original packets 1-12 queue num 200 bypass\nnft add rule inet ztest post meta mark and 0x40000000 == 0 udp dport \"{443}\" ct original packets 1-12 queue num 200 bypass\n\nsysctl net.netfilter.nf_conntrack_tcp_be_liberal=1 \nnft add chain inet ztest pre \"{type filter hook prerouting priority -101;}\"\nnft add rule inet ztest pre meta mark and 0x40000000 == 0 tcp sport \"{80,443}\" ct reply packets 1-12 queue num 200 bypass\nnft add rule inet ztest pre meta mark and 0x40000000 == 0 udp sport \"{443}\" ct reply packets 1-12 queue num 200 bypass\n\nnft add chain inet ztest predefrag \"{type filter hook output priority -401;}\"\nnft add rule inet ztest predefrag \"mark & 0x40000000 != 0x00000000 notrack\"\n```\n\nВ windows функция перехвата вшита прямо в код движка для windows, который называется *winws2*. Он использует драйвер windivert.\nДля перехвата портов целиком используются параметры `--wf-tcp-in`, `--wf-tcp-out`, `--wf-udp-in`, `--wf-udp-out`.\nОни относятся к протоколам tcp или udp, к входящим или исходящим пакетам. Например, `--wf-tcp-out=80,443`.\nДля более точного перехвата пишутся фильтры на языке фильтров windivert. Он похож на язык фильтров tcpdump или wireshark.\nФильтры отдаются *winws2* в параметрах `--wf-raw-part`. Конструктор фильтров обьединяет все указанные опции перехвата в\nединый raw фильтр и запускает перехват windivert.\n\nК сожалению, самый болезненный недостаток windivert (а так же BSD ipfw и pf) - отсутствие ограничителя на номер пакета в соединении (connbytes в iptables, ct packets в nftables).\nwindivert вообще не отслеживает соединения. Поэтому если перехватывать порт целиком, то все соединение по указанному направлению\nпойдет на перехват, что нелегко для процессора, если там передаются многие мегабайты.\nПоэтому по возможности пишите собственные фильтры windivert, проверяющие тип пейлоада хотя бы частично. Дофильтрацию может выполнить *winws2*.\n\nДальше под рутом нужно запустить *nfqws2* с параметрами командной строки. Они строятся примерно следующим образом :\n\n```\nnfqws2 --qnum 200 --debug --lua-init=@zapret-lib.lua --lua-init=@zapret-antidpi.lua \\\n  --filter-tcp=80,443 --filter-l7=tls,http \\\n  --payload=tls_client_hello --lua-desync=fake:blob=fake_default_tls:tcp_md5:tls_mod=rnd,rndsni,dupsid \\\n  --payload=http_req --lua-desync=fake:blob=fake_default_http:tcp_md5 \\\n  --payload=tls_client_hello,http_req --lua-desync=multisplit:pos=1:seqovl=5:seqovl_pattern=0x1603030000\n```\n\nДанный пример предполагает, что в той же директории находятся файлы `zapret-lib.lua` - библиотека хелперов на Lua и `zapret-antidpi.lua` - библиотека базовых стратегий.\n`--lua-init` может содержать Lua код в виде строки. Так удобно писать простой код, например присвоить константу переменной, чтобы не создавать файлы ради этой мелочи.\nЛибо подцепляется файл, если значение параметра начинается с `@`. Код из `--lua-init` выполняется 1 раз при старте.\n\nДалее указаны параметры `--lua-desync`. Они содержат имя Lua функции, вызываемой при обработке каждого пакета, проходящего через профиль мультистратегии.\nПосле двоеточия и через двоеточия следуют параметры для данной функции в формате `param[=value]`. В примере реализована стратегия\n\n```\nnfqws --qnum 200 --debug \\\n--filter-tcp=80,443 --filter-l7=tls,http \\\n --dpi-desync=fake,multisplit --dpi-desync-fooling=md5sig --dpi-desync-split-pos=1,midsld \\\n --dpi-desync-split-seqovl=5 --dpi-desync-split-seqovl-pattern=0x1603030000 \\\n --dpi-desync-fake-tls-mod=rnd,rndsni,dupsid\n```\n\nЧто сразу заметно - это наличие понятия \"payload\". В *nfqws1* были только протоколы соединения, которые участвовали в фильтрации профилей.\nОни так же остались в *nfqws2*, но введено другое понятие - тип пейлоада. Пейлоад - это содержание текущего пакета.\nТип пейлоада - тип данных, содержащихся в пакете или группе пакетов. Например, протокол соединения может быть tls, а пейлоады - tls_client_hello, tls_server_hello, unknown.\n\nДругое важное отличие - отсутствие жестко определенных фаз десинхронизации. То, что вы раньше писали как `fake,multisplit` реализуется двумя\nпоследовательно вызываемыми Lua функциями. Их может быть столько, сколько нужно, учитывая логику прохождения пакетов и операций с ними, и у каждой могут быть свои параметры.\nМожет даже несколько раз вызываться одна и так же функция с разными параметрами. Так, например, можно послать несколько фейков, причем с разными фулингами.\nКонкретный вызов `--lua-desync` функции называется инстансом. Инстанс - это связка имени функции, номера вызова внутри профиля и номера самого профиля.\nЭто похоже на одну программу, которую можно запустить много раз с разными параметрами.\n\nДругое немаловажное отличие - поддержка автоматической tcp сегментации средствами `zapret-lib.lua`. Вам больше не нужно думать о размерах отсылаемых tcp пакетов.\nПо каждому соединению отслеживается MSS. Если пакет не влезает в MSS, выполняется сегментация.\nНапример, это может случиться при отправке tls фейка с kyber. Или если вы режете kyber tls так, что одна из частей получается размером 1600 байт,\nчто, очевидно, не влезает в MTU. Или если вы задали seqovl=10000. В *nfqws1* такое значение вызвало бы ошибку. Функция Lua `rawsend_dissect_segmented` отправит\nнесколько tcp сегментов с начальным sequence -10000 общим размером 10000 байт, в последнем из которых будет кусок оригинального сообщения.\n\nВ *nfqws2* нет жестко зашитых параметров кастомных фейков типа `--dpi-desync-fake-tls`, `dpi-desync-fake-http` и тд.\nВместо них есть блобы. Блоб (blob) - это переменная Lua типа *string*, содержащая блок двоичных данных произвольной длины. От 1 байта до гигабайтов.\n*nfqws2* автоматически инициализирует блобы со стандартными фейками tls, http, quic, как это и было в *nfqws1*.\nБлобы могут быть заданы как hex-строка прямо в параметре desync функции, либо пред-загружены при старте с помощью параметра `--blob=name:0xHEX|[+ofs]@filename`\n\nЧто касается профилей мультистратегии и хостлистов , то они остались практически в неизменном виде. За исключением одной тонкости автолиста.\nТеперь профиль с автолистом берет на себя только те соединения, для которых уже известен хост. Пока хоста нет - они проходят мимо.\nВ *nfqws1* они падали на профиль с автолистом.\n\n```\nnfqws2 --qnum 200 --debug --lua-init=@zapret-lib.lua --lua-init=@zapret-antidpi.lua \\\n--filter-tcp=80 --filter-l7=http --hostlist=mylist1.txt --lua-desync=multisplit --new \\\n--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 \\\n--filter-tcp=443 --filter-l7=tls --hostlist=mylist1.txt --lua-desync=multidisorder\n```\n\nПараметры *nfqws1* start\u002Fcutoff (`--dpi-desync-start`, `--dpi-desync-cutoff`, ...) теперь называются диапазонами (ranges).\nОстались только 2 range : `--in-range` и `--out-range`. Они относятся к входящему и исходящему направлению соответственно.\nДа, теперь можно полноценно работать как с входящими пакетами, так и с исходящими. Есть и специальный режим для сервера - `--server`, который\nадаптирует интерпретацию IP адресов и портов источника\u002Fприемника, чтобы корректно работали ipset-ы и фильтры.\n\nrange задается как `mX-mY`, `mX\u003CmY`, `-mY`, `\u003CmY`, `mX-`.\nБуква `m` означает режим счетчика. `n` - номер пакета, `d` - номер пакета с данными, `b` - количество переданных байт, `s` - относительный sequence для tcp.\nПосле буквы режима пишется число. Например, `n5-s10000` означает с 5-го по очереди пакета до смещения 10000 байт относительно начала tcp соединения.\nЕсть и режимы, не требущие числа - `a` - всегда, `x` - никогда.\nЕсли разделителем указан знак '-' - конечная позиция включительна, а если '\u003C' - не включительна.\n\nУстановка по умолчанию `--in-range=x --out-range=a --payload all`. То есть отсекаются все входящие пакеты и берутся все исходящие.\n\n`--in-range`, `--out-range` и `--payload` фильтры могут присутствовать множественно в одном профиле.\nИх действие распространяется на все последующие `--lua-desync` функции до следующего фильтра того же типа или до конца профиля.\nСледующий профиль снова принимает значения по умолчанию.\n\nЧто будет, если вы не напишите фильтр `--payload` для fake или multisplit ? В *nfqws1* без `--dpi-desync-any-protocol` они работали только по известным пейлоадам.\nВ *nfqws2* \"any protocol\" - режим по умолчанию. Однако, функции из библиотеки `zapret-antidpi.lua` написаны так, что по умолчанию работают только по известным пейлоадам\nи не работают по пустым пакетам или unknown - точно так же, как это было в *nfqws1*.\nНо лучше все-же писать фильтры `--payload`, потому что они работают на уровне C кода, который выполняется существенно быстрее, чем Lua.\n\nДиссект пакета проходит поочередно по всем `--lua-desync` инстансам профиля, для которых не выполняется условие отсечения (cutoff).\nОтсечение может быть по range, payload или добровольное отсечение. Последний вариант - когда инстанс сам отказывается обрабатывать пакеты\nпо входящему, исходящему или обоим направлениям. Например, задача стратегии wsize - отреагировать только на пакет с tcp флагами SYN,ACK. После этого он не нужен, в коде вызывается функция отсечения.\nЭто сделано для экономии ресурсов процессора.\nЕсли все инстансы в профиле точно никогда больше не будут вызваны по соединению + направлению - вошли в превышение верхней границы range или выполнили добровольный cutoff, то движок Lua не вызывается вообще.\n\nОт инстанса к инстансу содержимое диссекта может ими меняться. Следующий инстанс видит изменения предыдущего.\nКаждый инстанс выносит свой вердикт - что делать с текущим диссектом. VERDICT_PASS - означает отправить как есть,\nVERDICT_MODIFY - отправить модифицированную версию, VERDICT_DROP - дропнуть диссект (не отправлять).\nИтоговый вердикт формируется на основании вердиктов отдельных инстансов.\nЕсли какой-либо инстанс выдал VERDICT_DROP - итоговый результат - всегда VERDICT_DROP.\nЕсли ни один инстанс не выдал VERDICT_DROP, а какой-либо инстанс выдал VERDICT_MODIFY, то будет VERDICT_MODIFY.\nЕсли все инстансы выдали VERDICT_PASS - будет VERDICT_PASS.\n\nНапример, функция pktmod применяет фулинг к текущему диссекту и выставляет вердикт VERDICT_MODIFY.\nЕсли после этого будет вызван инстанс multisplit, то произойдет резка текущего уже измененного диссекта, отправка частей и в случае успеха VERDICT_DROP.\nПолучается, что мы применили фулинг и отправили с этим фулингом все tcp сегменты.\n\n### Примеры портирования стратегий *nfqws1*\n\nКратко, на примерах, покажем как стратегии с *nfqws1* переписываются под *nfqws2*.\nДля краткости здесь опущены директивы `--qnum`, `--lua-init`, `--wf-tcp-out` и тому подобное, что не касается напрямую стратегий и их непосредственного обслуживания.\n\nПараметр `--filter-l7` относится к фильтру профиля мультистратегии. Здесь приведен как указание, что будет обрабатываться только конкретный протокол.\n\n\nАвтоматического использования ttl для ipv6 больше нет. Нужно писать отдельно для ipv4 и ipv6. Если не будет написано для ipv6, то к нему не будет применен ttl.\nФункция pktmod применяет фулинг к текущему диссекту.\n\n```\nnfqws \\\n --filter-l7=http --dpi-desync=fake --dpi-desync-fake-http=0x00000000 --dpi-desync-ttl=6 \\\n --orig-ttl=1 --orig-mod-start=s1 --orig-mod-cutoff=d1\n\nnfqws2 \\\n --filter-l7=http \\\n --payload=http_req --lua-desync=fake:blob=0x00000000:ip_ttl=6:ip6_ttl=6 \\\n --payload=empty --out-range=\"s1\u003Cd1\" --lua-desync=pktmod:ip_ttl=1:ip6_ttl=1\n```\n\nbadseq без параметров в *nfqws1* применял инкремент -10000 для syn и -66000 для ack.\nВ функциях `zapret-antidpi.lua` понятия badseq нет. Есть фулинги - уменьшить seq или ack на указанное значение.\n\ntcp_ts_up - очень странное явление, обнаруженное в процессе тестирования *nfqws2*.\nОказывается, если есть tcp опция timestamp, linux стабильно отбрасывает пакеты с валидным seq и инвалидным ack только если опция идет первой.\n*nfqws1* не соблюдал порядок tcp опций, timestamp получался первым всегда.\nПоэтому оказалось, что старая версия работает стабильно , а новая нет.\ntcp_ts_up дублирует старое поведение - двигает timestamp в самый верх.\n\n```\nnfqws \\\n --filter-l7=http \\\n --dpi-desync=fakedsplit --dpi-desync-fooling=badseq --dpi-desync-badseq-increment=0 --dpi-desync-split-pos=method+2\n\nnfqws2 \\\n --filter-l7=http \\\n --payload=http_req --lua-desync=fakedsplit:pos=method+2:tcp_ack=-66000:tcp_ts_up\n```\n\nautottl пишется полностью в формате `delta,min-max`. Вместо двоеточия используется запятая, чтобы не конфликтовать с разделителем параметров функции.\n\n```\nnfqws \\\n --filter-l7=tls \\\n --dpi-desync=fakedsplit --dpi-desync-fakedsplit-pattern=tls_clienthello_google_com.bin \\\n --dpi-desync-ttl=1 --dpi-desync-autottl=-1 --dpi-desync-split-pos=method+2 --dpi-desync-fakedsplit-mod=altorder=1\n\nnfqws2 \\\n --blob=tls_google:@tls_clienthello_google_com.bin \\\n --filter-l7=tls \\\n --payload tls_client_hello,http_req \\\n --lua-desync=fakedsplit:pattern=tls_google:pos=method+2:nofake1:ip_ttl=1:ip6_ttl=1:ip_autottl=-1,3-20:ip6_autottl=-1,3-20\n```\n\nЗдесь важен порядок вызова функций.\nwssize работает как модификатор диссекта - переписывает window size и scale factor. syndata должна быть отослана с модифицированными\nwsize и scale. Если перепутать порядок следования, то syndata будет отправлена без wssize. Поскольку важна модификация, начиная с SYN пакета,\nто wssize не сработает ожидаемым образом.\n\n```\nnfqws --dpi-desync=syndata,multisplit --dpi-desync-split-pos=midsld --wssize 1:6\n\nnfqws2 --lua-desync=wssize:wsize=1:scale=6 --lua-desync=syndata --lua-desync=multisplit:pos=midsld\n```\n\nВ первом примере все модификации tls применяются на лету.\nЭто так же означает, что рандомы будут применяться каждый раз, а не один раз, как в *nfqws1*.\nПоведение можно привести к варианту *nfqws1* при желании - во втором примере показано как.\n\n```\nnfqws1 \\\n --filter-l7 tls \\\n --dpi-desync=fake --dpi-desync-fooling=datanoack --dpi-desync-fake-tls=! \\\n --dpi-desync-fake-tls-mod=rnd,rndsni,dupsid\n\nnfqws2\n --filter-l7 tls \\\n --payload=tls_client_hello --lua-desync=fake:blob=fake_default_tls:tcp_flags_unset=ack:tls_mod=rnd,rndsni,dupsid,padencap \\\n --payload=empty --out-range=\"s1\u003Cd1\" --lua-desync=pktmod:ip_ttl=1:ip6_ttl=1\n\n\nnfqws2 \\\n --lua-init=\"fake_default_tls=tls_mod(fake_default_tls,'rnd,rndsni')\" \\\n --filter-l7 tls \\\n --payload=tls_client_hello --lua-desync=fake:blob=fake_default_tls:tcp_flags_unset=ack:tls_mod=dupsid,padencap \\\n --payload=empty --out-range=\"s1\u003Cd1\" --lua-desync=pktmod:ip_ttl=1:ip6_ttl=1\n```\n\nIP фрагментация является теперь опцией процесса отсылки. Функция send отсылает текущий диссект, применяя указанные модификаторы, но не дропает оригинал.\nЧтобы оригинал не пошел следом - применяется функция drop. Она ничего не делает, только выносит VERDICT_DROP.\nПри желании ipfrag можно применить и к fake, multisplit и другим функциям. Так же можно писать свои функции IP фрагментации.\nФункция по умолчанию ipfrag2 делит пакет на 2 части. Но вы можете написать функцию, которая разделит его на 10 частей и указать ее как `ipfrag=my_frag_function`.\nФункция фрагментации получает диссект подлежащего фрагментации пакета на вход и возвращает массив диссектов - фрагментов.\n\n```\nnfqws --dpi-desync=ipfrag2 --dpi-desync-ipfrag-pos-udp=8\nnfqws2 --lua-desync=send:ipfrag:ipfrag_pos_udp=8 --lua-desync=drop\n```\n\nРассмотрим теперь пример из zapret-win-bundle. Как `preset_example.cmd` был переписан в `preset2_example.cmd`.\n\nФильтр windivert поменялся только одним - больше нет параметров `--wf-tcp` и `--wf-udp`. Они разделены по направлениям in\u002Fout.\nДля отлова UDP не перехватывается весь udp порт - используются пейлоад фильтры windivert. Тем самым во много раз экономятся ресурсы процессора,\nвплоть до сотен раз. Когда попадет что-то на мощную выгрузку торрента, и она пойдет через winws, вы вполне можете словить загрузку целого ядра CPU\nи вой кулеров вашего ноута. А так его не будет.\n\nДля TCP так тоже можно было бы сделать, но не всегда. Во-первых, надо перехватывать SYN по порту, чтобы работал conntrack.\nНо это решаемо. А что не решаемо - это перехват вторых частей kyber tls hello. Их невозможно опознать без связи с предыдущими фрагментами. Поэтому перехватывается весь порт.\nДля HTTP вопрос решаемый, поскольку там нет реассемблирования запросов, но http сейчас стал настолько редким, что и смысла нет заморачиваться.\n\nВезде расставлены фильтры профиля мультистратегии `--filter-l7`, фильтры по `--out-range` и по `--payload`. Зачем ? В основном для сокращения вызовов Lua кода, который заведомо медленнее C кода.\nЕсли пакет не попадет в профили с Lua - ни о каком вызове кода Lua речи быть не может. Если пакет попал в профиль с Lua, то после первых 10 пакетов с данными наступает отсечение по верхней границе range. Все Lua инстансы входят в состояние instance cutoff, соединение входит в состояние \"lua cutoff\" по направлению \"out\". Значит вызовов Lua не будет вообще. Не просто вызовов, а даже обращения к движку Lua с какой-либо целью. Будет только C код, который посмотрит на признак \"cutoff\" и сразу же отпустит пакет.\n\nПочему именно `-d10` ? Чтобы хватило для отработки большинства вариантов стратегий, учитывая возможные ретрансмиссии и плохую связь. В winws2 по умолчанию включен параметр `--wf-tcp-empty=0`. Он блокирует перехват пустых пакетов с ACK, что позволяет примерно в 2 раза сэкономить на процессоре при интенсивных скачиваниях. Пустые ACK в большинстве стратегий не нужны. Но это же и ломает счетчик \"n\" - он не будет показывать реальное количество пакетов по соединению. Счетчик \"d\" работать будет как надо.\n\nПочему нет \"-d10\" на udp ? Потому что используется windivert фильтр на пейлоад. Счетчики будут считать не реальное количество пакетов в потоке, а количество перехваченных с отфильтрованными пейлоадами. Причем если интервал между ними будет более 1 минуты, то счет будет начинаться заново, поскольку таймаут udp по умолчанию - 60 сек. После таймаута запись conntrack будет удалена. Следующий пакет пойдет как новый поток.\n\nТак же везде расставлены фильтры по payload type. Отчасти так же с целью сократить вызовы Lua даже в пределах первых 10 пакетов с данными.\nС другой стороны, даже при совпадении протокола соединения (`--filter-l7`) может пробежать не интересующий нас пейлоад.\nПо умолчанию многие функции из `zapret-antidpi.lua` реагируют только на известные типы пейлоада, но не на конкретные, а на любые известные.\nЕсли допустить малореальный, но гипотетически возможный сценарий, что в рамках протокола http будет отправлен блок данных с tls или фраза, похожая на сообщение из xmpp, то тип пейлоада выскочит tls_client_hello или xmpp_stream, например. Лучше от этого сразу уберечься. Тем более что в других видах протоколов - xmpp, например, -\nпейлоады могут проскакивать нескольких типов вполне ожидаемо. Но работать надо не по всем.\n\nВ фейке для TLS по умолчанию - fake_default_tls - однократно при старте меняется SNI с \"www.microsoft.com\" на случайный и рандомизируется поле \"random\" в TLS handshake.\nЭто делается простой строчкой Lua кода. Больше нет никаких специальных параметров *nfqws2* для модификации пейлоадов.\nВ профиле для youtube на лету меняется SNI на \"www.google.com\", копируется поле TLS \"session id\" с обрабатываемого в данный момент TLS handshake.\n\n```\nstart \"zapret: http,https,quic\" \u002Fmin \"%~dp0winws.exe\" ^\n--wf-tcp=80,443 ^\n--wf-raw-part=@\"%~dp0windivert.filter\\windivert_part.discord_media.txt\" ^\n--wf-raw-part=@\"%~dp0windivert.filter\\windivert_part.stun.txt\" ^\n--wf-raw-part=@\"%~dp0windivert.filter\\windivert_part.wireguard.txt\" ^\n--wf-raw-part=@\"%~dp0windivert.filter\\windivert_part.quic_initial_ietf.txt\" ^\n--filter-tcp=80 --dpi-desync=fake,fakedsplit --dpi-desync-autottl=2 --dpi-desync-fooling=md5sig --new ^\n--filter-tcp=443 --hostlist=\"%~dp0files\\list-youtube.txt\" --dpi-desync=fake,multidisorder --dpi-desync-split-pos=1,midsld --dpi-desync-repeats=11 --dpi-desync-fooling=md5sig --dpi-desync-fake-tls-mod=rnd,dupsid,sni=www.google.com --new ^\n--filter-tcp=443 --dpi-desync=fake,multidisorder --dpi-desync-split-pos=midsld --dpi-desync-repeats=6 --dpi-desync-fooling=badseq,md5sig --new ^\n--filter-l7=quic --hostlist=\"%~dp0files\\list-youtube.txt\" --dpi-desync=fake --dpi-desync-repeats=11 --dpi-desync-fake-quic=\"%~dp0files\\quic_initial_www_google_com.bin\" --new ^\n--filter-l7=quic --dpi-desync=fake --dpi-desync-repeats=11 ^\n--filter-l7=wireguard,stun,discord --dpi-desync=fake --dpi-desync-repeats=2\n\n\nstart \"zapret: http,https,quic\" \u002Fmin \"%~dp0winws2.exe\" ^\n--wf-tcp-out=80,443 ^\n--lua-init=@\"%~dp0lua\\zapret-lib.lua\" --lua-init=@\"%~dp0lua\\zapret-antidpi.lua\" ^\n--lua-init=\"fake_default_tls = tls_mod(fake_default_tls,'rnd,rndsni')\" ^\n--blob=quic_google:@\"%~dp0files\\quic_initial_www_google_com.bin\" ^\n--wf-raw-part=@\"%~dp0windivert.filter\\windivert_part.discord_media.txt\" ^\n--wf-raw-part=@\"%~dp0windivert.filter\\windivert_part.stun.txt\" ^\n--wf-raw-part=@\"%~dp0windivert.filter\\windivert_part.wireguard.txt\" ^\n--wf-raw-part=@\"%~dp0windivert.filter\\windivert_part.quic_initial_ietf.txt\" ^\n--filter-tcp=80 --filter-l7=http ^\n  --out-range=-d10 ^\n  --payload=http_req ^\n   --lua-desync=fake:blob=fake_default_http:ip_autottl=-2,3-20:ip6_autottl=-2,3-20:tcp_md5 ^\n   --lua-desync=fakedsplit:ip_autottl=-2,3-20:ip6_autottl=-2,3-20:tcp_md5 ^\n  --new ^\n--filter-tcp=443 --filter-l7=tls --hostlist=\"%~dp0files\\list-youtube.txt\" ^\n  --out-range=-d10 ^\n  --payload=tls_client_hello ^\n   --lua-desync=fake:blob=fake_default_tls:tcp_md5:repeats=11:tls_mod=rnd,dupsid,sni=www.google.com ^\n   --lua-desync=multidisorder:pos=1,midsld ^\n  --new ^\n--filter-tcp=443 --filter-l7=tls ^\n  --out-range=-d10 ^\n  --payload=tls_client_hello ^\n   --lua-desync=fake:blob=fake_default_tls:tcp_md5:tcp_seq=-10000:repeats=6 ^\n   --lua-desync=multidisorder:pos=midsld ^\n  --new ^\n--filter-udp=443 --filter-l7=quic --hostlist=\"%~dp0files\\list-youtube.txt\" ^\n  --payload=quic_initial ^\n   --lua-desync=fake:blob=quic_google:repeats=11 ^\n  --new ^\n--filter-udp=443 --filter-l7=quic ^\n  --payload=quic_initial ^\n   --lua-desync=fake:blob=fake_default_quic:repeats=11 ^\n  --new ^\n--filter-l7=wireguard,stun,discord ^\n  --payload=wireguard_initiation,wireguard_cookie,stun,discord_ip_discovery ^\n   --lua-desync=fake:blob=0x00000000000000000000000000000000:repeats=2\n```\n\nИ напоследок стоит продемонстрировать как делаются нестандартные вещи. То, что очень непросто запрограммировать в чисто описательном виде\nв фиксированном коде, не превращая программу в монстро-комбайн, перегруженный частными функциями и разваливающийся под своей тяжестью со временем,\nкогда эти частные функции перестают быть нужны и забываются.\n\nНадо послать исходный запрос с известным пейлоадом с seqovl случайного размера от 5 до 10 символов со случайным содержимым, состоящим из букв от ‘a’ до ‘z’.\nЗдесь раскрывается не декларативный характер стратегий, а алгоритмический. Стратегия - это программа, и пишите ее вы на языке программирования.\nДля облегчения простых или стандартных действий есть готовые средства, так что далеко не всегда надо писать свою функцию.\nЧастенько можно обойтись простенькими кусками Lua кода в дополнение к имеющимся.\n\nЗдесь используется функция `luaexec`, предназначенная для динамического выполнения Lua кода в процессе обработки текущего диссекта.\nОна инициализирует требуемый blob, записывая его в таблицу desync, которая передается от инстанса к инстансу.\nСледующий инстанс `tcpseg` использует `rnd` как blob - источник seqovl паттерна.\n\nСимволы `%` и `#` используются для разименования блобов и подстановки их размера соответственно. Реализовано на уровне C кода.\ndesync функция получает уже подставленные значения. В данном случае seqovl устанавливается как размер сгенерированного блоба.\n\nФункция `tcpseg` предназначена для отсылки tcp сегмента - части текущего пейлоада (или реасма - сборки нескольких пакетов, например в случае tls kyber).\n`pos=0,-1` - это диапазон, состоящий из двух маркеров - начала и конца. 0 - положительный абсолютный маркер, соответствующий началу пакета.\n-1 - отрицательный абсолютный маркер, соответствующий концу пакета. Получается, мы отсылаем целиком текущий пейлоад, но с seqovl.\n`tcpseg` не дропает пакет. Его надо дропнуть отдельно. По умолчанию `tcpseg` работает только с известными пейлоадами, а функция `drop` - с любыми.\nПоэтому нужно ей указать дропать только известные пейлоады.\n\nТакая связка из 3 инстансов решает поставленную задачу без кучи частных параметров вида `--dpi-desync...`.\n\n```\nnfqws2 \\\n --lua-desync=luaexec:code='desync.rnd=brandom_az(math.random(5,10))' \\\n --lua-desync=tcpseg:pos=0,-1:seqovl=#rnd:seqovl_pattern=rnd \\\n --lua-desync=drop:payload=known\n```\n\n### Какие есть еще параметры\n\nКак узнать какие есть еще функции и какие у них бывают параметры ? Смотрите `zapret-antidpi.lua`. Перед каждой функцией подробно описано какие параметры она берет.\nОписание стандартных блоков параметров есть в начале. \nИли сразу читайте [талмуд](manual.md) . Там все документировано.\n\n### Очень важный совет\n\nНаучитесь пользоваться `--debug` логом. Без него будет очень сложно понять *nfqws2* на начальном этапе и приспособиться к новой схеме.\nОшибок будет много. Особенно, когда вы начнете писать свой Lua код. Их надо читать.\n\n### Не только лишь автономный обман DPI\n\nРабочий тестовый пример icmp обфускатора udp от винды к серверу на vps.\nДля теста используем wireguard. Ничего в конфигах менять не надо - wireguard будет думать, что он работает по udp, но на самом деле он преобразуется в пинги icmp, которые могут проходить NAT. Размер пакетов не изменяется, потому проблемы MTU нет.\n\nБудем загонять исходящие с клиента в icmp type 8 (echo request) code 199 , исходящие с сервера в icmp type 0 (echo reply) code 199.\nКод у обоих концов делаем одинаковый, иначе NAT не соотнесет. Без NAT можно коды делать разными для клиента и сервера.\nОсобый icmp code нужен для фильтрации от обычных пингов.\n\nПо стандарту код должен быть 0, но на практике с большой вероятностью работают любые коды.\nРазные имплементации NAT теоретически могут фильтровать ненулевой код, соотносить или не соотносить код вместе с identifier. Linux NAT соотносит.\nПри любых проблемах убираем wireguard, ставим netcat с обоих концов и пробуем общаться, посматривая в wireshark.\nВсегда можно откатиться на нулевой код, но тогда у сервера без фильтра по IP клиента будет плохая защита от обычных пингов - все они будут преобразовываться в udp и направляться в wireguard,\nкоторый будет их игнорировать, поскольку передается мусор. Сервер перестанет пингаться.\n\nДругой способ избежать проблемы и уйти от стандартных пингов - использовать другие типы icmp. Работающие пары, пробрасываемые Linux NAT :\n\n- `ctype=8:stype=0` - echo request - echo reply (используется по умолчанию)\n- `ctype=13:stype=14` - timestamp - timestamp reply\n- `ctype=15:stype=16` - information request - information reply\n- `ctype=17:stype=18` - address mask request - address mask reply\n\nНа провайдерских NAT или на аппаратном ускорении роутера может быть другой расклад по работающим парам.\nНужно пробовать и смотреть что выходит в сеть после NAT и что приходит на сервер.\nНапример, Linux NAT вообще не пробрасывает type 42 - extended echo request. Но аппаратная железка может пробросить и провайдер тоже.\n\nКто знает, может быть DPI настроен сечь icmp тоннели на стандартных пингах, а на других типах icmp нет ?\n\n\nwireguard server - `1.2.3.4:5555`\n\n```\ntable ip ztest {\n        chain post {\n                type filter hook output priority mangle; policy accept;\n                meta mark & 0x40000000 == 0x00000000 udp sport 5555 queue flags bypass to 200\n        }\n\n        chain pre {\n                type filter hook input priority mangle; policy accept;\n                meta mark & 0x40000000 == 0x00000000 icmp type echo-request icmp code 199 queue flags bypass to 200\n        }\n}\n```\n\n```\nnfqws2 --qnum 200 --server\n --lua-init=@\u002Fopt\u002Fzapret2\u002Flua\u002Fzapret-lib.lua\n --lua-init=@\u002Fopt\u002Fzapret2\u002Flua\u002Fzapret-obfs.lua\n --in-range=a\n --lua-desync=udp2icmp:ccode=199:scode=199\n```\n\nКлиент на винде :\n\n```\nwinws2\n --wf-icmp-in=0:199 --wf-udp-out=5555\n --wf-raw-filter=\"ip.SrcAddr=1.2.3.4 or ip.DstAddr=1.2.3.4\"\n --lua-init=@lua\u002Fzapret-lib.lua\n --lua-init=@lua\u002Fzapret-obfs.lua\n --in-range=a\n --lua-desync=udp2icmp:ccode=199:scode=199\n```\n\nВсе лишнее отсекается в ядре в windivert - проц зазря не грузит.\n--wf-raw-filter сочетается со всем остальным собранным конструктором по AND. Отсекает по IP адресу сервера.\n--wf-icmp-in отсекает входящие icmp типа 0 с кодом 199.\n\nИ включаем wireguard.\nВ шарке сплошняком пинги и реплаи с кодом 199\n\nЕсли IP клиента постоянен, можно дополнительно на стороне сервера сделать фильтр по IP клиента.\n\nДополнительно можно сделать dataxor=blob на обоих концах, чтобы поксорить пейлоад.\nblob растягивается на размер пакета как pattern. Можно использовать от 1 hex byte до специально нагенеренного рандома. На обоих концах должен быть одинаковый\n","zapret2 是一款反深度包检测（DPI）软件，旨在帮助用户绕过网络审查和流量限制。其核心功能包括对HTTP(S)网站的封锁规避、TCP与UDP协议特征分析的对抗以及部分透明协议混淆。技术上，该项目支持多种操作系统如Linux、FreeBSD、OpenBSD及Windows，并特别优化了在资源受限的嵌入式设备如运行OpenWrt系统的路由器上的性能。通过将策略控制从C语言转移至Lua脚本语言实现，使得非专业开发者也能编写自定义策略来对抗不断变化的DPI技术。适合需要增强在线隐私保护或面临互联网访问限制的个人及小型组织使用。","2026-06-11 03:44:22","high_star"]