Zapret2: обсуждение

Все вопросы по 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

Напишите параметр --debug первым, тогда будет срабатывать

Вряд ли стоит. Лучше пусть чел сам понимает что такое “bad”. Ведь bad может быть очень разным.

Да

Если уж очень хочется, можно самому сделать файлик, где накидать присвоение переменных (либо inline text без файлика), а потом использовать parameter=%value
где value - имя переменной. value будет заменено прозрачно на значение переменной value

По логу мне непоятно что произошло.
Такого у меня не воспроизводится.

tls12 оно прогнало. дальше начинается tls13 и ошибка ресолвинга, по quic - тоже ошибка ресолвинга.
но дело в том, что ресолвинг реально только 1 раз происходит, а затем результат кэшируется.
похоже система ресолва с кэшированием сломалась, буду проверять

С ходу не получилось. Пробовал разные варианты. Все мимо. С файлом думаю все будет отлично, но хочется без него.

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
\"
"

В переменных 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

Спасибо.

В стратегии пишет:

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”) нормально?

Не похоже на нормально. Полная строка запуска какая ?

MDIG cache и в 1, и во 2-м блокчеке был давно и полностью сломан. Только щас всплыло.
вылит фикс

Примерно так:

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

Не вижу такого вывода у себя.
Это в процессе дергания или сразу ?

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

Проверил

Спойлер
#!/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"

Не стоит вырывать из контекста отдельные куски, не предоставляя сам контекст.
Внутри этой строчки - нормально, как отдельная строка - ненормально
Разименование происходит динамически в процессе выполнения, а не на init стадии
Так можно формировать одними функциями входные значения для других, при этом лучше не засирать глобальный неймспейс, а использовать поля таблицы desync. Там ищется в первую очередь имя для разименования. Но для констант - глобал вполне годится

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

Есть подозрение, что проблема здесь

Спойлер
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 &&

Это не баг, а фича.
nfqws1 учитывал только тип протокола соединения. этот же учитывает еще и тип пейлоада.
Он определяет только stun_binding_request, а здесь allocate request
Из-за этого не срабатывает обход ?
Надо в шарке посмотреть какие message type есть в исходящих

Да, все верно не срабатывает обход.