bolvan
December 4, 2025, 9:39am
1
anti-dpi software
Все вопросы по zapret2 обсуждаем здесь (кроме чайниковских типа на что мне нажать, как открыть программу и тд)
zapret2 является дальнейшим развитием проекта zapret. Проблема его основной части nfqws1 в том, что он перегружен опциями и в условиях нарастающего противостояния регулятора и пользователей не обеспечивает достаточную гибкость воздействия на трафик. Обход DPI требует все более тонких и специфических воздействий, которые меняются со временем, а старые перестают работать.
Стратегии - это программы, управляющие сценарием атаки на DPI. В nfqws1 они зашиваются в C код. Написание C кода - занятие нелегкое, требующее достаточной квалификации разработчика и времени.
Цель nfqws2 - сделать так, чтобы программы стратегий мог написать любой человек, владеющий знаниями в области сетей, понимающий уязвимости DPI или хотя бы область , в которой их можно искать, плюс владеющий базовыми навыками программирования.
А можно константы по умолчанию (из zapret1) куда-то внести?
#define BADSEQ_INCREMENT_DEFAULT -10000
#define BADSEQ_ACK_INCREMENT_DEFAULT -66000
Что бы потом их использовать, например, так:
:tcp_ack=DEF_tcp_ack:tcp_seq=def_tcp_seq: Или вообще просто tcp_seq:tcp_ack
?
Правильно я понимаю, что datanoack это tcp_flags_unset=ACK?
Zapret2 не запустился и файл лога был пустой, т.к. один из параметров не прошел валидацию. Можно такие ошибки писать в лог?
nfqws2 --out-range=n3 --debug=@/tmp/nfqws-210.log --daemon --user=nobody --qnum=211
bolvan
December 4, 2025, 10:05am
4
Напишите параметр --debug первым, тогда будет срабатывать
bolvan
December 4, 2025, 10:06am
5
Вряд ли стоит. Лучше пусть чел сам понимает что такое “bad”. Ведь bad может быть очень разным.
Да
bolvan
December 4, 2025, 10:14am
7
Если уж очень хочется, можно самому сделать файлик, где накидать присвоение переменных (либо inline text без файлика), а потом использовать parameter=%value
где value - имя переменной. value будет заменено прозрачно на значение переменной value
bolvan
December 4, 2025, 10:48am
8
бросился тысьтировать новый zogpret2 (хотя и старый не освоил ) ну и вот кароч blockcheck нового запрета проверяет по три часа даже при выборе варианта quick, я помню так было и в первом запрете но потом пофиксил вроде как или это не баг а фича и ещё заметил что там сплош wf-tcp а как тыстировать udp тогда?! в стандартном примере пресета есть фильтар quicа --filter-udp=443 --filter-l7=quic --hostlist="%~dp0files\list-youtube.txt" ^ а блокчек его проверяет вобще? у пролистал лог там только wf-tcp-out хотя я вроде как выбирал quic этот когда он спрашивает вначале там, я не шарю если что за это дело толком
blockcheck2 — копия.log (2.8 MB)
По логу мне непоятно что произошло.
Такого у меня не воспроизводится.
tls12 оно прогнало. дальше начинается tls13 и ошибка ресолвинга, по quic - тоже ошибка ресолвинга.
но дело в том, что ресолвинг реально только 1 раз происходит, а затем результат кэшируется.
похоже система ресолва с кэшированием сломалась, буду проверять
avenger
December 4, 2025, 11:46am
9
С ходу не получилось. Пробовал разные варианты. Все мимо. С файлом думаю все будет отлично, но хочется без него.
LUA RUN STR: luaexec:code=’
LUA ERROR: [string “luaexec:code='”]:1: function arguments expected near ‘=’
NFQWS_ARGS="
--lua-init=luaexec:code='
DEF_TCP_ACK=-66000
DEF_TCP_SEQ=-10000
'
"
LUA RUN STR: "
LUA ERROR: [string “”"]:1: unfinished string near ‘’
LUA SHUTDOWN
NFQWS_ARGS="
--lua-init=\"
DEF_TCP_ACK=-66000
DEF_TCP_SEQ=-10000
\"
"
bolvan
December 4, 2025, 11:59am
10
В переменных shell большая хрень творится с переносами строки. В смысле, чтобы они корректно дошли до параметров. Они не дойдут.
Стоит использовать ; для разделения стейтментов lua и писать в одну строку
luaexec - это desync функция, она к init не имеет никакого отношения и не будет работать в таком виде
--lua-init="DEF_TCP_ACK=-66000 ; DEF_TCP_SEQ=-10000" ........ --lua-desync=fake:tcp_seq=%DEF_TCP_SEQ:tcp_ack=%DEF_TCP_ACK
avenger
December 4, 2025, 12:03pm
11
Спасибо.
В стратегии пишет:
LUA RUN FILE: /opt/share/zapret/lua/zapret-lib.lua
LUA RUN FILE: /opt/share/zapret/lua/zapret-antidpi.lua
LUA RUN STR: DEF_TCP_ACK=-66000;DEF_TCP_SEQ=-10000
LUA INIT DONE
profile 1 lua tcp_seq="%DEF_TCP_SEQ"
Это (tcp_seq=“%DEF_TCP_SEQ”) нормально?
bolvan
December 4, 2025, 12:05pm
12
Не похоже на нормально. Полная строка запуска какая ?
bolvan
December 4, 2025, 12:07pm
13
MDIG cache и в 1, и во 2-м блокчеке был давно и полностью сломан. Только щас всплыло.
вылит фикс
avenger
December 4, 2025, 12:08pm
14
Примерно так:
NFQWS_ARGS="
--lua-init=DEF_TCP_ACK=-66000;DEF_TCP_SEQ=-10000
--filter-tcp=443 --filter-l7=tls
--payload=tls_client_hello --lua-desync=multisplit:seqovl_pattern=tls_clienthello_www_google_com:seqovl=31:pos=1:tcp_ack=%DEF_TCP_ACK:ip6_hopbyhop2
"
nfqws2 $DEBUG --daemon --user=nobody --fwmark=0x40000000 --qnum=211 --lua-init=@$zapret_lua_dir/zapret-lib.lua --lua-init=@$zapret_lua_dir/zapret-antidpi.lua --pidfile=/var/run/nfqws.pid $NFQWS_ARGS
bolvan
December 4, 2025, 12:12pm
15
Не вижу такого вывода у себя.
Это в процессе дергания или сразу ?
LUA RUN FILE: /opt/zapret2/lua/zapret-lib.lua
LUA RUN FILE: /opt/zapret2/lua/zapret-antidpi.lua
LUA RUN STR: DEF_TCP_ACK=-66000;DEF_TCP_SEQ=-10000
LUA INIT DONE
opening nfq library handle
unbinding existing nf_queue handler for AF_INET (if any)
binding nfnetlink_queue as nf_queue handler for AF_INET
binding this socket to queue '200'
setting copy_packet mode
avenger
December 4, 2025, 12:22pm
16
Проверил
Спойлер
#!/bin/sh
zapret_lua_dir=/opt/share/zapret/lua
zapret_fake_dir=/opt/share/zapret/fake
DEBUG="--debug=@/tmp/log/nfqws-210.log"
NFQWS_ARGS="
--lua-init=DEF_TCP_ACK=-66000;DEF_TCP_SEQ=-10000
--filter-tcp=443 --filter-l7=tls
--payload=tls_client_hello --lua-desync=multisplit:seqovl_pattern=tls_clienthello_www_google_com:seqovl=31:pos=1:tcp_ack=%DEF_TCP_ACK:ip6_hopbyhop2
"
nfqws2 $DEBUG --user=nobody --qnum=211 --lua-init=@$zapret_lua_dir/zapret-lib.lua --lua-init=@$zapret_lua_dir/zapret-antidpi.lua $NFQWS_ARGS
Лог:
adding low-priority default empty desync profile
we have 1 user defined desync profile(s) and default low priority profile 0
profile 1 lua multisplit(ip6_hopbyhop2="",tcp_ack="%DEF_TCP_ACK",pos="1",seqovl="31",seqovl_pattern="tls_clienthello_www_google_com" range_in=x0-x0 range_out=a0-a0 payload_type= tls_client_hello)
lists summary:
blobs summary:
blob 'fake_default_tls' : size=680 alloc=808
blob 'fake_default_http' : size=263 alloc=263
blob 'fake_default_quic' : size=620 alloc=620
initializing conntrack with timeouts tcp=60:300:60 udp=60
ipcache lifetime 7200s
Running as UID=65534 GID=65534,65534
seccomp: Invalid argument
seccomp: this can be safely ignored if kernel does not support seccomp
initializing raw sockets bind-fix4=0 bind-fix6=0
set_socket_buffers fd=4 rcvbuf=2048 sndbuf=32768
fd=4 SO_RCVBUF=4096
fd=4 SO_SNDBUF=65536
set_socket_buffers fd=5 rcvbuf=2048 sndbuf=32768
fd=5 SO_RCVBUF=4096
fd=5 SO_SNDBUF=65536
LUA INIT
LUA v5.1 LuaJIT 2.1.1756211046 OpenResty
LUA REMOVE: os.execute io.popen package.loadlib debug package.loaded.debug
LUA BLOB: fake_default_tls (size=680)
LUA BLOB: fake_default_http (size=263)
LUA BLOB: fake_default_quic (size=620)
LUA NUMERIC: qnum desync_fwmark VERDICT_PASS VERDICT_MODIFY VERDICT_DROP DEFAULT_MSS IP_BASE_LEN IP6_BASE_LEN TCP_BASE_LEN UDP_BASE_LEN TCP_KIND_END TCP_KIND_NOOP TCP_KIND_MSS TCP_KIND_SCALE TCP_KIND_SACK_PERM TCP_KIND_SACK TCP_KIND_TS TCP_KIND_MD5 TCP_KIND_AO TCP_KIND_FASTOPEN TH_FIN TH_SYN TH_RST TH_PUSH TH_ACK TH_FIN TH_URG TH_ECE TH_CWR IP_RF IP_DF IP_MF IP_OFFMASK IP_FLAGMASK IPTOS_ECN_MASK IPTOS_ECN_ECT1 IPTOS_ECN_ECT0 IPTOS_ECN_CE IP6F_MORE_FRAG IPPROTO_IP IPPROTO_IPV6 IPPROTO_ICMP IPPROTO_TCP IPPROTO_UDP IPPROTO_ICMPV6 IPPROTO_HOPOPTS IPPROTO_ROUTING IPPROTO_FRAGMENT IPPROTO_AH IPPROTO_ESP IPPROTO_DSTOPTS IPPROTO_MH IPPROTO_HIP IPPROTO_SHIM6 IPPROTO_NONE
LUA BOOL: b_debug b_daemon b_server b_ipcache_hostname b_ctrack_disable
LUA RUN FILE: /opt/share/zapret/lua/zapret-lib.lua
LUA RUN FILE: /opt/share/zapret/lua/zapret-antidpi.lua
LUA RUN STR: DEF_TCP_ACK=-66000;DEF_TCP_SEQ=-10000
LUA INIT DONE
opening nfq library handle
unbinding existing nf_queue handler for AF_INET (if any)
binding nfnetlink_queue as nf_queue handler for AF_INET
binding this socket to queue '211'
setting copy_packet mode
Результат
profile 1 lua multisplit(ip6_hopbyhop2="",tcp_ack="%DEF_TCP_ACK",pos="1",seqovl="31",seqovl_pattern="tls_clienthello_www_google_com" range_in=x0-x0 range_out=a0-a0 payload_type= tls_client_hello)
tcp_ack="%DEF_TCP_ACK"
bolvan
December 4, 2025, 12:25pm
17
Не стоит вырывать из контекста отдельные куски, не предоставляя сам контекст.
Внутри этой строчки - нормально, как отдельная строка - ненормально
Разименование происходит динамически в процессе выполнения, а не на init стадии
Так можно формировать одними функциями входные значения для других, при этом лучше не засирать глобальный неймспейс, а использовать поля таблицы desync. Там ищется в первую очередь имя для разименования. Но для констант - глобал вполне годится
avenger
December 4, 2025, 6:55pm
18
profile 1 lua fake(repeats="2",blob="0x00000000000000000000000000000000" range_in=x0-x0 range_out=a0-a0 payload_type= stun_binding_req)
Не определяет протокол. На v1 все отлично.
Спойлер
packet: id=1 len=372 mark=00000000 ifin=(0) ifout=eth3(7)
IP4: 192.168.97.119 => 157.240.205.62 proto=udp ttl=63 sport=58118 dport=3478
UDP: len=344 : 00 03 01 44 21 12 A4 42 77 3C 21 2D F3 26 3C 40 82 51 A3 73 40 00 00 B6 09 0F 01 F4 8B 2E A9 A3 … : …D!..Bw<!-.&<@.Q.s@… …
client mode desync profile/ipcache search target ip=157.240.205.62 port=3478
desync profile search for udp ip=157.240.205.62 port=3478 l7proto=unknown ssid=‘’ hostname=‘’
desync profile 1 matches
dpi desync src=192.168.97.119:58118 dst=157.240.205.62:3478 track_direction=out fixed_direction=out connection_proto=unknown payload_type=unknown
all out desync functions do not want unknown payload
packet: id=1 pass unmodified
Спойлер
packet: id=1 len=364 mark=00000000 ifin=(0) ifout=eth3(7)
IP4: 192.168.97.119 => 157.240.205.62 proto=udp ttl=63 sport=57412 dport=3478
UDP: len=336 : 00 03 01 3C 21 12 A4 42 D8 55 1B 16 7B 07 50 70 27 DA 72 25 40 00 00 B6 09 0F 01 F4 76 59 06 A4 … : …<!..B.U..{.Pp’.r%@…vY.. …
desync profile search for udp target=157.240.205.62:3478 l7proto=unknown ssid=‘’ hostname=‘’
desync profile 1 matches
packet contains STUN message
discovered l7 protocol
desync profile search for udp target=157.240.205.62:3478 l7proto=stun ssid=‘’ hostname=‘’
desync profile 1 matches
dpi desync src=192.168.97.119:57412 dst=157.240.205.62:3478
sending fake[1] : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 … : … …
sending original ttl 63
applying linux postnat conntrack workaround
packet: id=1 pass modified. len=364
avenger
December 4, 2025, 7:10pm
19
Есть подозрение, что проблема здесь
Спойлер
bool IsStunMessage(const uint8_t *data, size_t len)
{
return len>=20 && // header size
(data[0]&0xC0)==0 && // 2 most significant bits must be zeroes
bool IsStunBindingRequest(const uint8_t *data, size_t len)
{
return len>=20 && // header size
data[0]==0 && data[1]==1 &&
bolvan
December 4, 2025, 7:20pm
20
Это не баг, а фича.
nfqws1 учитывал только тип протокола соединения. этот же учитывает еще и тип пейлоада.
Он определяет только stun_binding_request, а здесь allocate request
Из-за этого не срабатывает обход ?
Надо в шарке посмотреть какие message type есть в исходящих
avenger
December 4, 2025, 7:21pm
21
Да, все верно не срабатывает обход.