Template
1
0
mirror of https://github.com/bol-van/zapret2.git synced 2026-03-16 14:58:17 +00:00

79 Commits

Author SHA1 Message Date
bol-van
ca14fbe9c8 AI inspired fixes 2026-01-17 23:09:08 +03:00
bol-van
c81968b94b nfqws2: fix wrong ipv6 dissection 2026-01-17 22:40:08 +03:00
bol-van
a2d567c7a0 nfqws2: fix wrong ipv6 dissection 2026-01-17 22:31:21 +03:00
bol-van
5026199f24 zapret-antidpi: oob instance cutoff if called not from the very beginning of tcp 2026-01-17 19:45:54 +03:00
bol-van
68435f64ea update docs 2026-01-17 18:11:01 +03:00
bol-van
d84dfaf61d blockcheck2, winws: multiple instances compat 2026-01-17 18:03:06 +03:00
bol-van
4c13c63d27 AI inspired fixes 2026-01-17 13:31:48 +03:00
bol-van
5dde1264ce update docs 2026-01-17 10:26:36 +03:00
bol-van
cc989c52ed update docs 2026-01-17 10:01:38 +03:00
bol-van
0446b1493b AI inspired fixes 2026-01-17 10:01:26 +03:00
bol-van
97cd8cebca update docs 2026-01-17 09:53:37 +03:00
bol-van
2d02eeb578 blockcheck2: tcp_nop_del for openbsd 2026-01-17 09:50:39 +03:00
bol-van
fe318a42e8 zapret-lib: tcp_nop_del 2026-01-16 21:34:18 +03:00
bol-van
73c10e3f15 update docs 2026-01-16 18:37:58 +03:00
bol-van
17cf260fd0 update docs 2026-01-16 18:33:19 +03:00
bol-van
fa15c635bb update docs 2026-01-16 18:24:13 +03:00
bol-van
74690047b5 update docs 2026-01-16 18:18:56 +03:00
bol-van
d24453da69 update docs 2026-01-16 18:16:56 +03:00
bol-van
af200628cd update docs 2026-01-16 18:15:19 +03:00
bol-van
76fe7bff82 update docs 2026-01-16 18:14:16 +03:00
bol-van
1d1eedbb3b update docs 2026-01-16 18:06:56 +03:00
bol-van
274b331825 blockcheck2: remove drop_ack from oob 2026-01-16 17:12:53 +03:00
bol-van
69f900b3da udpate docs 2026-01-16 17:06:10 +03:00
bol-van
da9faabf97 udpate docs 2026-01-16 17:00:16 +03:00
bol-van
60934f5ab8 udpate docs 2026-01-16 16:53:17 +03:00
bol-van
eb7043fc12 zapret-antidpi: oob remove drop_ack 2026-01-16 16:37:56 +03:00
bol-van
681c53c3b4 AI inspired fixes 2026-01-16 16:17:34 +03:00
bol-van
65f6923383 update docs 2026-01-16 15:30:00 +03:00
bol-van
f0f59261bb update docs 2026-01-16 15:29:37 +03:00
bol-van
06cf59d050 update docs 2026-01-16 15:24:48 +03:00
bol-van
f0bff44219 update docs 2026-01-16 15:24:15 +03:00
bol-van
da0016ed0e update docs 2026-01-16 15:23:12 +03:00
bol-van
704c73f821 zapret-antidpi: oob error if char != 1 symbol 2026-01-16 15:05:23 +03:00
bol-van
201dd40b46 zapret-antidpi: oob error if char > 1 symbol 2026-01-16 15:04:16 +03:00
bol-van
aa13a1f5d2 blockcheck2: oob --wf-tcp-empty=1 in windows 2026-01-16 14:57:59 +03:00
bol-van
2a3b6f2a8b zapret-antidpi: oob dlog drop_ack event 2026-01-16 14:56:39 +03:00
bol-van
801dec81c8 ask_list default value fix 2026-01-16 14:18:26 +03:00
bol-van
14359afb93 AI inspired fixes 2026-01-16 13:52:46 +03:00
bol-van
372c6748ca zapret-lib,antidpi: optimizations 2026-01-15 23:30:55 +03:00
bol-van
87d2fcd5a1 blockcheck2: AI fixes and oob 2026-01-15 22:34:15 +03:00
bol-van
74ddd4f9d2 AI inspired fixes 2026-01-15 21:29:37 +03:00
bol-van
6b7507deb5 nfqws2: set desync.tcp_mss to minimum of both ends or default if at least one is unknown 2026-01-15 20:51:57 +03:00
bol-van
f8156a3d38 blockcheck2: ttl/autottl disable fix for BSD 2026-01-15 20:29:40 +03:00
bol-van
67a8ee47e3 zapret-antidpi: oob 2026-01-15 20:05:22 +03:00
bol-van
93d81ca4b2 blockcheck: multiple NOTEST fixes 2026-01-15 15:08:30 +03:00
bol-van
3d9a36600b blockcheck: NOTEST_SEQOVL fix 2026-01-15 15:04:01 +03:00
bol-van
c3adb3f045 nfqws2: simplify complex unwinds in lua code 2026-01-15 11:46:36 +03:00
bol-van
f919533873 nfqws2: simplify complex unwinds in lua code 2026-01-15 11:40:39 +03:00
bol-van
17bdfe16b1 blockcheck2: custom test special chars escape warning 2026-01-15 10:22:00 +03:00
bol-van
bc0102fbdc nfqws2: do not require / in the beginning of URI in http 2026-01-15 10:13:08 +03:00
bol-van
10d72b3242 AI inspired fixes 2026-01-15 09:41:55 +03:00
bol-van
9dd14dfc7c nfqws2: check ipv6 plen 2026-01-14 19:13:46 +03:00
bol-van
10201f1abf nfqws2: bitset/bitget check negative from-to 2026-01-14 17:39:15 +03:00
bol-van
236550918b update docs 2026-01-14 17:22:27 +03:00
bol-van
72a269e88d makefile fixes 2026-01-14 17:08:35 +03:00
bol-van
d3199eebd3 zapret-tests: fixes and ipv6 rawsend 2026-01-14 16:40:44 +03:00
bol-van
ffcb14726d AI and manual fixes 2026-01-14 16:39:16 +03:00
bol-van
aa5a1f4183 zapret-wgobfs: add comment 2026-01-14 09:49:28 +03:00
bol-van
ca186a6566 AI inspired fixes 2026-01-14 09:47:12 +03:00
bol-van
dced388652 update docs 2026-01-13 13:48:20 +03:00
bol-van
1f7d10bf5b update docs 2026-01-13 13:47:48 +03:00
bol-van
6b1b4adddb update docs 2026-01-13 13:46:49 +03:00
bol-van
cfe7b76352 update docs 2026-01-13 13:43:52 +03:00
bol-van
62fd0dc432 update docs 2026-01-13 13:42:11 +03:00
bol-van
050a01bda2 update docs 2026-01-13 13:40:57 +03:00
bol-van
4c5d84c19e update docs 2026-01-13 13:40:23 +03:00
bol-van
d430b4775d update docs 2026-01-13 13:38:49 +03:00
bol-van
807565968e update docs 2026-01-13 13:38:16 +03:00
bol-van
e062b1795e update docs 2026-01-13 13:37:28 +03:00
bol-van
3417e50438 update docs 2026-01-13 13:35:56 +03:00
bol-van
70f5a88ec0 update docs 2026-01-13 13:22:34 +03:00
bol-van
4b3fba3fb2 nfqws2: add comments 2026-01-13 10:39:15 +03:00
bol-van
9cded5448a nfqws2: add comments 2026-01-13 10:38:00 +03:00
bol-van
2302ac6949 nfqws2: optimize unmodified csum fix logic 2026-01-13 10:33:59 +03:00
bol-van
0be76b902e nfqws2: minor optimize 2026-01-12 20:23:54 +03:00
bol-van
fa89e011fb nfqws2: align packet buffers 2026-01-12 18:32:52 +03:00
bol-van
622a81001d AI inspired fixes 2026-01-12 16:51:40 +03:00
bol-van
4d793b73a4 nfqws2: do nothing on signals if quit requested 2026-01-12 11:32:38 +03:00
bol-van
a47b6a529b update docs 2026-01-12 10:51:29 +03:00
48 changed files with 828 additions and 385 deletions

View File

@@ -2,9 +2,11 @@
Скопируйте эту директорию под другим именем в blockcheck2.d, отредактируйте list файлы, впишите туда свои стратегии.
В диалоге blockcheck2.sh выберите тест с названием вашей директории.
Можно комментировать строки символом '#' в начале строки.
Параметры со спец символами типа "<" должны быть эскейпнуты по правилам shell.
Альтернативный путь до файлов стратегий можно задать переменными LIST_HTTP, LIST_HTTPS_TLS12, LIST_HTTPS_TLS13, LIST_QUIC.
This is simple strategy tester from a file.
Copy this folder, write your strategies into list files and select your test in blockcheck2 dialog.
Lines can be commented using the '#' symbol at the line start.
Parameters with special symbols like "<" must be escaped.
Strategy list files paths can be overriden in env variables : LIST_HTTP, LIST_HTTPS_TLS12, LIST_HTTPS_TLS13, LIST_QUIC.

View File

@@ -1,4 +1,5 @@
# write nfqws2 parameters here
# WARNING : parameters with special symbols like "<" must be escaped or will cause error
--payload=http_req --lua-desync=http_hostcase
--payload=http_req --lua-desync=http_methodeol
--payload=http_req --lua-desync=fake:blob=fake_default_http:tcp_ts=-1000

View File

@@ -1,3 +1,4 @@
# write nfqws2 parameters here
# WARNING : parameters with special symbols like "<" must be escaped or will cause error
--payload tls_client_hello --lua-desync=fake:blob=fake_default_tls:tcp_ts=-1000
--payload=tls_client_hello --lua-desync=fake:blob=0x00000000:tcp_md5:repeats=1 --lua-desync=fake:blob=fake_default_tls:tcp_md5:tls_mod=rnd,dupsid:repeats=1 --lua-desync=multisplit:pos=2

View File

@@ -1,4 +1,5 @@
# write nfqws2 parameters here
# WARNING : parameters with special symbols like "<" must be escaped or will cause error
--payload tls_client_hello --lua-desync=fake:blob=fake_default_tls:tcp_ts=-1000
--payload tls_client_hello --lua-desync=tcpseg:pos=0,-1:seqovl=1 --lua-desync=drop
--payload tls_client_hello --lua-desync=luaexec:code="desync.pat=tls_mod(fake_default_tls,'rnd,rndsni,dupsid,padencap',desync.reasm_data)" --lua-desync=tcpseg:pos=0,-1:seqovl=#pat:seqovl_pattern=pat --lua-desync=drop

View File

@@ -1,3 +1,4 @@
# write nfqws2 parameters here
# WARNING : parameters with special symbols like "<" must be escaped or will cause error
--payload quic_initial --lua-desync=fake:blob=fake_default_quic:repeats=11
--payload quic_initial --lua-desync=send:ipfrag --lua-desync=drop

View File

@@ -0,0 +1,39 @@
. "$TESTDIR/def.inc"
pktws_oob()
{
# $1 - test function
# $2 - domain
local dropacks urp
for urp in b 0 2 midsld; do
pktws_curl_test_update "$1" "$2" --in-range=-s1 --lua-desync=oob:urp=$urp$dropack
done
}
pktws_check_http()
{
# $1 - test function
# $2 - domain
[ "$NOTEST_OOB_HTTP" = 1 ] && { echo "SKIPPED"; return; }
pktws_oob "$@"
}
pktws_check_https_tls12()
{
# $1 - test function
# $2 - domain
[ "$NOTEST_OOB_HTTPS" = 1 ] && { echo "SKIPPED"; return; }
pktws_oob "$@"
}
pktws_check_https_tls13()
{
# $1 - test function
# $2 - domain
pktws_check_https_tls12 "$1" "$2"
}

View File

@@ -1,18 +1,22 @@
. "$TESTDIR/def.inc"
pktws_simple_split_tests()
{
# $1 - test function
# $2 - domain/uri
# $3 - splits
# $4 - PRE args for nfqws2
local pos ok ok_any pre="$4"
local splitf splitfs="multisplit $MULTIDISORDER"
local pos ok ok_any pre="$4" func
local splitf splitfs="multisplit multidisorder"
ok_any=0
for splitf in $splitfs; do
func=$splitf
[ "$func" = multidisorder ] && func=$MULTIDISORDER
eval need_$splitf=0
ok=0
for pos in $3; do
pktws_curl_test_update $1 $2 $pre $PAYLOAD --lua-desync=$splitf:pos=$pos && ok=1
pktws_curl_test_update $1 $2 $pre $PAYLOAD --lua-desync=$func:pos=$pos && ok=1
done
[ "$ok" = 1 -a "$SCANLEVEL" != force ] || eval need_$splitf=1
[ "$ok" = 1 ] && ok_any=1
@@ -41,8 +45,6 @@ pktws_check_https_tls()
local splits_tls='2 1 sniext+1 sniext+4 host+1 midsld 1,midsld 1,midsld,1220 1,sniext+1,host+1,midsld-2,midsld,midsld+2,endhost-1'
local PAYLOAD="--payload=tls_client_hello"
[ "$NOTEST_MULTI_HTTPS" = 1 ] && { echo "SKIPPED"; return; }
pktws_simple_split_tests "$1" "$2" "$splits_tls" "$3"
}
@@ -50,6 +52,9 @@ pktws_check_https_tls12()
{
# $1 - test function
# $2 - domain
[ "$NOTEST_MULTI_HTTPS" = 1 ] && { echo "SKIPPED"; return; }
pktws_check_https_tls "$1" "$2" && [ "$SCANLEVEL" != force ] && return
# do not use 'need' values obtained with wssize
@@ -62,5 +67,8 @@ pktws_check_https_tls13()
{
# $1 - test function
# $2 - domain
[ "$NOTEST_MULTI_HTTPS" = 1 ] && { echo "SKIPPED"; return; }
pktws_check_https_tls "$1" "$2"
}

View File

@@ -1,3 +1,5 @@
. "$TESTDIR/def.inc"
pktws_check_http()
{
# $1 - test function
@@ -34,6 +36,7 @@ pktws_seqovl_tests_tls()
# $1 - test function
# $2 - domain/uri
# $3 - PRE args for nfqws2
local ok ok_any
local testf=$1 domain="$2" pre="$3"
local pat rnd_mod padencap_mod split f f2
@@ -47,14 +50,14 @@ pktws_seqovl_tests_tls()
ok=0
pktws_curl_test_update $testf $domain $pre $PAYLOAD --lua-desync=tcpseg:pos=0,-1:seqovl=1 --lua-desync=drop && ok=1
pktws_curl_test_update $testf $domain ${SEQOVL_PATTERN_HTTPS:+--blob=$pat:@"$SEQOVL_PATTERN_HTTPS" }$rnd_mod $pre $PAYLOAD --lua-desync=tcpseg:pos=0,-1:seqovl=#$pat:seqovl_pattern=$pat --lua-desync=drop && ok=1
pktws_curl_test_update $testf $domain ${SEQOVL_PATTERN_HTTPS:+--blob=$pat:@"$SEQOVL_PATTERN_HTTPS" }$pre $PAYLOAD $padencap_mod --lua-desync=tcpseg:pos=0,-1:seqovl=#pat:seqovl_pattern=$pat --lua-desync=drop && ok=1
pktws_curl_test_update $testf $domain ${SEQOVL_PATTERN_HTTPS:+--blob=$pat:@"$SEQOVL_PATTERN_HTTPS" }$pre $PAYLOAD $padencap_mod --lua-desync=tcpseg:pos=0,-1:seqovl=#$pat:seqovl_pattern=$pat --lua-desync=drop && ok=1
ok_any=$ok
ok=0
for split in 10 10,sniext+1 10,sniext+4 10,midsld; do
pktws_curl_test_update $testf $domain $pre $PAYLOAD --lua-desync=multisplit:pos=$split:seqovl=1 && ok=1
pktws_curl_test_update $testf $domain ${SEQOVL_PATTERN_HTTPS:+--blob=$pat:@"$SEQOVL_PATTERN_HTTPS" }$rnd_mod $pre $PAYLOAD --lua-desync=multisplit:pos=$split:seqovl=#$pat:seqovl_pattern=$pat && ok=1
pktws_curl_test_update $testf $domain ${SEQOVL_PATTERN_HTTPS:+--blob=$pat:@"$SEQOVL_PATTERN_HTTPS" }$pre $PAYLOAD $padencap_mod --lua-desync=multisplit:pos=$split:seqovl=#pat:seqovl_pattern=$pat && ok=1
pktws_curl_test_update $testf $domain ${SEQOVL_PATTERN_HTTPS:+--blob=$pat:@"$SEQOVL_PATTERN_HTTPS" }$pre $PAYLOAD $padencap_mod --lua-desync=multisplit:pos=$split:seqovl=#$pat:seqovl_pattern=$pat && ok=1
[ "$ok" = 1 -a "$SCANLEVEL" != force ] && break
done
for split in '1 2' 'sniext sniext+1' 'sniext+3 sniext+4' 'midsld-1 midsld' '1 2,midsld'; do
@@ -67,21 +70,13 @@ pktws_seqovl_tests_tls()
[ "$ok_any" = 1 ]
}
pktws_check_https_tls()
{
# $1 - test function
# $2 - domain
# $3 - PRE args for nfqws2
[ "$NOTEST_SEQOVL_HTTPS" = 1 ] && { echo "SKIPPED"; return; }
pktws_seqovl_tests_tls "$1" "$2" "$3"
}
pktws_check_https_tls12()
{
# $1 - test function
# $2 - domain
[ "$NOTEST_SEQOVL_HTTPS" = 1 ] && { echo "SKIPPED"; return; }
pktws_seqovl_tests_tls "$1" "$2" && [ "$SCANLEVEL" != force ] && return
pktws_seqovl_tests_tls "$1" "$2" --lua-desync=wssize:wsize=1:scale=6
}
@@ -90,5 +85,8 @@ pktws_check_https_tls13()
{
# $1 - test function
# $2 - domain
[ "$NOTEST_SEQOVL_HTTPS" = 1 ] && { echo "SKIPPED"; return; }
pktws_seqovl_tests_tls "$1" "$2"
}

View File

@@ -23,8 +23,6 @@ pktws_check_https_tls()
local PAYLOAD="--payload=tls_client_hello" ok=0 pre="$3" split
[ "$NOTEST_SYNDATA_HTTPS" = 1 ] && { echo "SKIPPED"; return; }
for split in '' multisplit $MULTIDISORDER; do
pktws_curl_test_update "$1" "$2" $pre --lua-desync=syndata ${split:+$PAYLOAD --lua-desync=$split} && ok=1
pktws_curl_test_update "$1" "$2" $pre --lua-desync=syndata:blob=0x1603 ${split:+$PAYLOAD --lua-desync=$split} && ok=1
@@ -40,6 +38,8 @@ pktws_check_https_tls12()
# $1 - test function
# $2 - domain
[ "$NOTEST_SYNDATA_HTTPS" = 1 ] && { echo "SKIPPED"; return; }
pktws_check_https_tls "$1" "$2" && [ "$SCANLEVEL" != force ] && return
pktws_check_https_tls "$1" "$2" --lua-desync=wssize:wsize=1:scale=6
}
@@ -49,5 +49,7 @@ pktws_check_https_tls13()
# $1 - test function
# $2 - domain
[ "$NOTEST_SYNDATA_HTTPS" = 1 ] && { echo "SKIPPED"; return; }
pktws_check_https_tls "$1" "$2"
}

View File

@@ -18,8 +18,8 @@ pktws_check_http()
need_fake=0
ttls=$(seq -s ' ' $MIN_TTL $MAX_TTL)
attls=$(seq -s ' ' $MIN_AUTOTTL_DELTA $MAX_AUTOTTL_DELTA)
[ "$MAX_TTL" = 0 ] || ttls=$(seq -s ' ' $MIN_TTL $MAX_TTL)
[ "$MAX_AUTOTTL_DELTA" = 0 ] || attls=$(seq -s ' ' $MIN_AUTOTTL_DELTA $MAX_AUTOTTL_DELTA)
ok_any=0
ok=0
@@ -40,7 +40,7 @@ pktws_check_http()
for ff in $fake 0x00000000; do
pktws_curl_test_update $testf $domain ${FAKE_HTTP:+--blob=fake_http:@"$FAKE_HTTP" }$PAYLOAD --lua-desync=fake:blob=$ff:$fooling:repeats=$FAKE_REPEATS && ok=1
# duplicate SYN with MD5
contains "$fooling" tcp_md5 && pktws_curl_test_update $testf $domain ${FAKE_HTTP:+--blob=$fake:@"$FAKE_HTTP" }$PAYLOAD --lua-desync=fake:blob=$ff:$fooling:repeats=$FAKE_REPEATS --payload=empty "--out-range=<s1" --lua-desync=send:tcp_md5 && ok=1
contains "$fooling" tcp_md5 && pktws_curl_test_update $testf $domain ${FAKE_HTTP:+--blob=$fake:@"$FAKE_HTTP" }$PAYLOAD --lua-desync=fake:blob=$ff:$fooling:repeats=$FAKE_REPEATS --payload=empty "--out-range=<s1" --lua-desync=send:$TCP_MD5 && ok=1
done
done
for ttl in $attls; do
@@ -55,8 +55,8 @@ pktws_check_http()
done
[ $ok = 0 -a "$SCANLEVEL" != force ] && need_fake=1
[ $ok = 1 ] && okany=1
[ $okany = 1 ]
[ $ok = 1 ] && ok_any=1
[ $ok_any = 1 ]
}
pktws_fake_https_vary_()
@@ -76,7 +76,7 @@ pktws_fake_https_vary()
pktws_fake_https_vary_ "$1" "$2" "$3" "$4" "$5" && ok_any=1
# duplicate SYN with MD5
contains "$fooling" tcp_md5 && \
pktws_fake_https_vary_ "$1" "$2" "$3" "$4" "${5:+$5 }--payload=empty --out-range=<s1 --lua-desync=send:tcp_md5" && ok_any=1
pktws_fake_https_vary_ "$1" "$2" "$3" "$4" "${5:+$5 }--payload=empty --out-range=<s1 --lua-desync=send:$TCP_MD5" && ok_any=1
[ "$ok_any" = 1 ]
}
@@ -86,8 +86,6 @@ pktws_check_https_tls()
# $2 - domain
# $3 - PRE args for nfqws2
[ "$NOTEST_FAKE_HTTPS" = 1 ] && { echo "SKIPPED"; return; }
local testf=$1 domain="$2" pre="$3"
local ok ok_any ttls attls f fake fooling
local PAYLOAD="--payload=tls_client_hello"
@@ -125,14 +123,17 @@ pktws_check_https_tls()
done
[ $ok = 0 -a "$SCANLEVEL" != force ] && need_fake=1
[ $ok = 1 ] && okany=1
[ $okany = 1 ]
[ $ok = 1 ] && ok_any=1
[ $ok_any = 1 ]
}
pktws_check_https_tls12()
{
# $1 - test function
# $2 - domain
[ "$NOTEST_FAKE_HTTPS" = 1 ] && { echo "SKIPPED"; return; }
pktws_check_https_tls "$1" "$2" && [ "$SCANLEVEL" != force ] && return
# do not use 'need' values obtained with wssize
@@ -145,5 +146,8 @@ pktws_check_https_tls13()
{
# $1 - test function
# $2 - domain
[ "$NOTEST_FAKE_HTTPS" = 1 ] && { echo "SKIPPED"; return; }
pktws_check_https_tls "$1" "$2"
}

View File

@@ -14,8 +14,8 @@ pktws_check_faked()
local PAYLOAD="--payload=$3"
local FAKED_PATTERN="$5"
ttls=$(seq -s ' ' $MIN_TTL $MAX_TTL)
attls=$(seq -s ' ' $MIN_AUTOTTL_DELTA $MAX_AUTOTTL_DELTA)
[ "$MAX_TTL" = 0 ] || ttls=$(seq -s ' ' $MIN_TTL $MAX_TTL)
[ "$MAX_AUTOTTL_DELTA" = 0 ] || attls=$(seq -s ' ' $MIN_AUTOTTL_DELTA $MAX_AUTOTTL_DELTA)
# do not test fakedsplit if multisplit works
[ "$need_multisplit" = 0 -a "$SCANLEVEL" != force ] || splitfs=fakedsplit
@@ -42,7 +42,7 @@ pktws_check_faked()
for split in $splits; do
pktws_curl_test_update $testf $domain ${FAKED_PATTERN:+--blob=faked_pat:@"$FAKED_PATTERN" }$pre $PAYLOAD --lua-desync=$splitf:${FAKED_PATTERN:+pattern=faked_pat:}pos=$split:$fooling && ok=1
# duplicate SYN with MD5
contains "$fooling" tcp_md5 && pktws_curl_test_update $testf $domain ${FAKED_PATTERN:+--blob=faked_pat:@"$FAKED_PATTERN" }$pre $PAYLOAD --lua-desync=$splitf:${FAKED_PATTERN:+pattern=faked_pat:}pos=$split:$fooling:repeats=$FAKE_REPEATS --payload=empty --out-range="<s1" --lua-desync=send:tcp_md5 && ok=1
contains "$fooling" tcp_md5 && pktws_curl_test_update $testf $domain ${FAKED_PATTERN:+--blob=faked_pat:@"$FAKED_PATTERN" }$pre $PAYLOAD --lua-desync=$splitf:${FAKED_PATTERN:+pattern=faked_pat:}pos=$split:$fooling:repeats=$FAKE_REPEATS --payload=empty --out-range="<s1" --lua-desync=send:$TCP_MD5 && ok=1
done
done
for ttl in $attls; do
@@ -77,7 +77,6 @@ pktws_check_https_tls()
# $1 - test function
# $2 - domain
# $3 - PRE args for nfqws2
[ "$NOTEST_FAKED_HTTPS" = 1 ] && { echo "SKIPPED"; return; }
local splits='2 1 sniext+1 sniext+4 host+1 midsld 1,midsld 1,sniext+1,host+1,midsld-2,midsld,midsld+2,endhost-1'
pktws_check_faked $1 "$2" tls_client_hello "$splits" "$FAKED_PATTERN_HTTPS" "$3"
@@ -87,6 +86,9 @@ pktws_check_https_tls12()
{
# $1 - test function
# $2 - domain
[ "$NOTEST_FAKED_HTTPS" = 1 ] && { echo "SKIPPED"; return; }
pktws_check_https_tls "$1" "$2" && [ "$SCANLEVEL" != force ] && return
# do not use 'need' values obtained with wssize
@@ -99,5 +101,8 @@ pktws_check_https_tls13()
{
# $1 - test function
# $2 - domain
[ "$NOTEST_FAKED_HTTPS" = 1 ] && { echo "SKIPPED"; return; }
pktws_check_https_tls "$1" "$2"
}

View File

@@ -1,6 +1,5 @@
. "$TESTDIR/def.inc"
pktws_hostfake_vary_()
{
local ok_any=0 testf=$1 domain="$2" fooling="$3" pre="$4" post="$5" disorder
@@ -22,7 +21,7 @@ pktws_hostfake_vary()
pktws_hostfake_vary_ "$1" "$2" "$3" "$4" "$5" && ok_any=1
# duplicate SYN with MD5
contains "$fooling" tcp_md5 && \
pktws_hostfake_vary_ "$1" "$2" "$3" "$4" "${5:+$5 }--payload=empty --out-range=<s1 --lua-desync=send:tcp_md5" && ok_any=1
pktws_hostfake_vary_ "$1" "$2" "$3" "$4" "${5:+$5 }--payload=empty --out-range=<s1 --lua-desync=send:$TCP_MD5" && ok_any=1
[ "$ok_any" = 1 ]
}
@@ -37,8 +36,8 @@ pktws_check_hostfake()
local ok ttls attls f fooling
local PAYLOAD="--payload=$3"
ttls=$(seq -s ' ' $MIN_TTL $MAX_TTL)
attls=$(seq -s ' ' $MIN_AUTOTTL_DELTA $MAX_AUTOTTL_DELTA)
[ "$MAX_TTL" = 0 ] || ttls=$(seq -s ' ' $MIN_TTL $MAX_TTL)
[ "$MAX_AUTOTTL_DELTA" = 0 ] || attls=$(seq -s ' ' $MIN_AUTOTTL_DELTA $MAX_AUTOTTL_DELTA)
need_hostfakesplit=0
ok=0
@@ -58,7 +57,7 @@ pktws_check_hostfake()
pktws_hostfake_vary $testf $domain "ip${IPVV}_autottl=-$ttl,3-20" "$pre" "$f" && [ "$SCANLEVEL" != force ] && break
done
done
[ $ok = 0 -a "$SCANLEVEL" != force ] && eval need_hostfake=1
[ $ok = 0 -a "$SCANLEVEL" != force ] && need_hostfakesplit=1
[ $ok = 1 ]
}
@@ -77,14 +76,15 @@ pktws_check_https_tls()
# $2 - domain
# $3 - PRE args for nfqws2
[ "$NOTEST_HOSTFAKE_HTTPS" = 1 ] && { echo "SKIPPED"; return; }
pktws_check_hostfake $1 "$2" tls_client_hello "$3"
}
pktws_check_https_tls12()
{
# $1 - test function
# $2 - domain
[ "$NOTEST_HOSTFAKE_HTTPS" = 1 ] && { echo "SKIPPED"; return; }
pktws_check_https_tls "$1" "$2" && [ "$SCANLEVEL" != force ] && return
# do not use 'need' values obtained with wssize
@@ -97,5 +97,8 @@ pktws_check_https_tls13()
{
# $1 - test function
# $2 - domain
[ "$NOTEST_HOSTFAKE_HTTPS" = 1 ] && { echo "SKIPPED"; return; }
pktws_check_https_tls "$1" "$2"
}

View File

@@ -16,8 +16,8 @@ pktws_check_http()
fake=fake_default_http
fi
ttls=$(seq -s ' ' $MIN_TTL $MAX_TTL)
attls=$(seq -s ' ' $MIN_AUTOTTL_DELTA $MAX_AUTOTTL_DELTA)
[ "$MAX_TTL" = 0 ] || ttls=$(seq -s ' ' $MIN_TTL $MAX_TTL)
[ "$MAX_AUTOTTL_DELTA" = 0 ] || attls=$(seq -s ' ' $MIN_AUTOTTL_DELTA $MAX_AUTOTTL_DELTA)
# do not test fake + multisplit if multisplit works
[ "$need_multisplit" = 0 -a "$SCANLEVEL" != force ] || splitfs=multisplit
@@ -46,7 +46,7 @@ pktws_check_http()
for ff in $fake 0x00000000; do
pktws_curl_test_update $testf $domain ${FAKE_HTTP:+--blob=$fake:@"$FAKE_HTTP" }$PAYLOAD --lua-desync=fake:blob=$ff:$fooling:repeats=$FAKE_REPEATS --lua-desync=$splitf:pos=$split && ok=1
# duplicate SYN with MD5
contains "$fooling" tcp_md5 && pktws_curl_test_update $testf $domain ${FAKE_HTTP:+--blob=fake_http:@"$FAKE_HTTP" }$PAYLOAD --lua-desync=fake:blob=$ff:$fooling:repeats=$FAKE_REPEATS --lua-desync=$splitf:pos=$split --payload=empty "--out-range=<s1" --lua-desync=send:tcp_md5 && ok=1
contains "$fooling" tcp_md5 && pktws_curl_test_update $testf $domain ${FAKE_HTTP:+--blob=fake_http:@"$FAKE_HTTP" }$PAYLOAD --lua-desync=fake:blob=$ff:$fooling:repeats=$FAKE_REPEATS --lua-desync=$splitf:pos=$split --payload=empty "--out-range=<s1" --lua-desync=send:$TCP_MD5 && ok=1
done
done
done
@@ -82,7 +82,7 @@ pktws_fake_https_vary()
pktws_fake_https_vary_ "$1" "$2" "$3" "$4" "$5" && ok_any=1
# duplicate SYN with MD5
contains "$fooling" tcp_md5 && \
pktws_fake_https_vary_ "$1" "$2" "$3" "$4" "${5:+$5 }--payload=empty --out-range=<s1 --lua-desync=send:tcp_md5" && ok_any=1
pktws_fake_https_vary_ "$1" "$2" "$3" "$4" "${5:+$5 }--payload=empty --out-range=<s1 --lua-desync=send:$TCP_MD5" && ok_any=1
[ "$ok_any" = 1 ]
}
@@ -92,8 +92,6 @@ pktws_check_https_tls()
# $2 - domain
# $3 - PRE args for nfqws2
[ "$NOTEST_FAKE_MULTI_HTTPS" = 1 ] && { echo "SKIPPED"; return 0; }
local testf=$1 domain="$2" pre="$3"
local ok ok_any ttls attls f fake fooling splitf splitfs= split splits='2 1 sniext+1 sniext+4 host+1 midsld 1,midsld 1,midsld,1220 1,sniext+1,host+1,midsld-2,midsld,midsld+2,endhost-1'
local PAYLOAD="--payload=tls_client_hello"
@@ -148,6 +146,9 @@ pktws_check_https_tls12()
{
# $1 - test function
# $2 - domain
[ "$NOTEST_FAKE_MULTI_HTTPS" = 1 ] && { echo "SKIPPED"; return 0; }
pktws_check_https_tls "$1" "$2" && [ "$SCANLEVEL" != force ] && return
pktws_check_https_tls "$1" "$2" --lua-desync=wssize:wsize=1:scale=6
}
@@ -156,5 +157,8 @@ pktws_check_https_tls13()
{
# $1 - test function
# $2 - domain
[ "$NOTEST_FAKE_MULTI_HTTPS" = 1 ] && { echo "SKIPPED"; return 0; }
pktws_check_https_tls "$1" "$2"
}

View File

@@ -16,8 +16,8 @@ pktws_check_http()
fake=fake_default_http
fi
ttls=$(seq -s ' ' $MIN_TTL $MAX_TTL)
attls=$(seq -s ' ' $MIN_AUTOTTL_DELTA $MAX_AUTOTTL_DELTA)
[ "$MAX_TTL" = 0 ] || ttls=$(seq -s ' ' $MIN_TTL $MAX_TTL)
[ "$MAX_AUTOTTL_DELTA" = 0 ] || attls=$(seq -s ' ' $MIN_AUTOTTL_DELTA $MAX_AUTOTTL_DELTA)
# do not test fake + multisplit if multisplit works
[ "$need_fakedsplit" = 0 -a "$SCANLEVEL" != force ] || splitfs=fakedsplit
@@ -46,7 +46,7 @@ pktws_check_http()
for ff in $fake 0x00000000; do
pktws_curl_test_update $testf $domain ${FAKE_HTTP:+--blob=$fake:@"$FAKE_HTTP" }${FAKED_PATTERN_HTTP:+--blob=faked_pat:@"$FAKED_PATTERN_HTTP" }$PAYLOAD --lua-desync=fake:blob=$ff:$fooling:repeats=$FAKE_REPEATS --lua-desync=$splitf:${FAKED_PATTERN_HTTP:+pattern=faked_pat:}pos=$split:$fooling:repeats=$FAKE_REPEATS && ok=1
# duplicate SYN with MD5
contains "$fooling" tcp_md5 && pktws_curl_test_update $testf $domain ${FAKE_HTTP:+--blob=$fake:@"$FAKE_HTTP" }${FAKED_PATTERN_HTTP:+--blob=faked_pat:@"$FAKED_PATTERN_HTTP" }$PAYLOAD --lua-desync=fake:blob=$ff:$fooling:repeats=$FAKE_REPEATS --lua-desync=$splitf:${FAKED_PATTERN_HTTP:+pattern=faked_pat:}pos=$split:$fooling:repeats=$FAKE_REPEATS --payload=empty "--out-range=<s1" --lua-desync=send:tcp_md5 && ok=1
contains "$fooling" tcp_md5 && pktws_curl_test_update $testf $domain ${FAKE_HTTP:+--blob=$fake:@"$FAKE_HTTP" }${FAKED_PATTERN_HTTP:+--blob=faked_pat:@"$FAKED_PATTERN_HTTP" }$PAYLOAD --lua-desync=fake:blob=$ff:$fooling:repeats=$FAKE_REPEATS --lua-desync=$splitf:${FAKED_PATTERN_HTTP:+pattern=faked_pat:}pos=$split:$fooling:repeats=$FAKE_REPEATS --payload=empty "--out-range=<s1" --lua-desync=send:$TCP_MD5 && ok=1
done
done
done
@@ -83,7 +83,7 @@ pktws_fake_https_vary()
pktws_fake_https_vary_ "$1" "$2" "$3" "$4" "$5" && ok_any=1
# duplicate SYN with MD5
contains "$fooling" tcp_md5 && \
pktws_fake_https_vary_ "$1" "$2" "$3" "$4" "${5:+$5 }--payload=empty --out-range=<s1 --lua-desync=send:tcp_md5" && ok_any=1
pktws_fake_https_vary_ "$1" "$2" "$3" "$4" "${5:+$5 }--payload=empty --out-range=<s1 --lua-desync=send:$TCP_MD5" && ok_any=1
[ "$ok_any" = 1 ]
}
@@ -93,8 +93,6 @@ pktws_check_https_tls()
# $2 - domain
# $3 - PRE args for nfqws2
[ "$NOTEST_FAKE_FAKED_HTTPS" = 1 ] && { echo "SKIPPED"; return 0; }
local testf=$1 domain="$2" pre="$3"
local ok ok_any ttls attls f fake fooling splitf splitfs= split splits='2 1 sniext+1 sniext+4 host+1 midsld 1,midsld 1,sniext+1,host+1,midsld-2,midsld,midsld+2,endhost-1'
local PAYLOAD="--payload=tls_client_hello"
@@ -149,6 +147,9 @@ pktws_check_https_tls12()
{
# $1 - test function
# $2 - domain
[ "$NOTEST_FAKE_FAKED_HTTPS" = 1 ] && { echo "SKIPPED"; return 0; }
pktws_check_https_tls "$1" "$2" && [ "$SCANLEVEL" != force ] && return
pktws_check_https_tls "$1" "$2" --lua-desync=wssize:wsize=1:scale=6
}
@@ -157,5 +158,8 @@ pktws_check_https_tls13()
{
# $1 - test function
# $2 - domain
[ "$NOTEST_FAKE_FAKED_HTTPS" = 1 ] && { echo "SKIPPED"; return 0; }
pktws_check_https_tls "$1" "$2"
}

View File

@@ -20,7 +20,7 @@ pktws_hostfake_vary()
pktws_hostfake_vary_ "$1" "$2" "$3" "$4" "$5"
# duplicate SYN with MD5
contains "$fooling" tcp_md5 && \
pktws_hostfake_vary_ "$1" "$2" "$3" "$4" "${5:+$5 }--payload=empty --out-range=<s1 --lua-desync=send:tcp_md5"
pktws_hostfake_vary_ "$1" "$2" "$3" "$4" "${5:+$5 }--payload=empty --out-range=<s1 --lua-desync=send:$TCP_MD5"
}
pktws_check_hostfake()
@@ -33,8 +33,8 @@ pktws_check_hostfake()
[ "$need_hostfakesplit" = 0 ] && return 0
ttls=$(seq -s ' ' $MIN_TTL $MAX_TTL)
attls=$(seq -s ' ' $MIN_AUTOTTL_DELTA $MAX_AUTOTTL_DELTA)
[ "$MAX_TTL" = 0 ] || ttls=$(seq -s ' ' $MIN_TTL $MAX_TTL)
[ "$MAX_AUTOTTL_DELTA" = 0 ] || attls=$(seq -s ' ' $MIN_AUTOTTL_DELTA $MAX_AUTOTTL_DELTA)
ok=0
for ttl in $ttls; do
@@ -69,7 +69,7 @@ pktws_check_http()
local FAKE="$FAKE_HTTP"
if [ -n "$FAKE_HTTP" ]; then
fake=bfake
fake=fake_http
else
fake=fake_default_http
fi
@@ -83,13 +83,11 @@ pktws_check_https_tls()
# $2 - domain
# $3 - PRE args for nfqws2
[ "$NOTEST_FAKE_HOSTFAKE_HTTPS" = 1 ] && { echo "SKIPPED"; return 0; }
local PAYLOAD="--payload=tls_client_hello"
local FAKE="$FAKE_HTTPS"
if [ -n "$FAKE_HTTPS" ]; then
fake=bfake
fake=fake_tls
else
fake=fake_default_tls
fi
@@ -101,6 +99,9 @@ pktws_check_https_tls12()
{
# $1 - test function
# $2 - domain
[ "$NOTEST_FAKE_HOSTFAKE_HTTPS" = 1 ] && { echo "SKIPPED"; return 0; }
pktws_check_https_tls "$1" "$2" && [ "$SCANLEVEL" != force ] && return
pktws_check_https_tls "$1" "$2" --lua-desync=wssize:wsize=1:scale=6
}
@@ -109,5 +110,8 @@ pktws_check_https_tls13()
{
# $1 - test function
# $2 - domain
[ "$NOTEST_FAKE_HOSTFAKE_HTTPS" = 1 ] && { echo "SKIPPED"; return 0; }
pktws_check_https_tls "$1" "$2"
}

View File

@@ -15,3 +15,7 @@ MAX_AUTOTTL_DELTA=${MAX_AUTOTTL_DELTA:-5}
# can use MULTIDISORER=multidisorder_legacy
MULTIDISORDER=${MULTIDISORDER:-multidisorder}
TCP_MD5=tcp_md5
# OpenBSD can occupy 24 bytes in tcp options in SYN packet leaving no space for the md5 header
[ "$UNAME" = OpenBSD ] && TCP_MD5=$TCP_MD5:tcp_nop_del

View File

@@ -26,7 +26,6 @@ CURL=${CURL:-curl}
TEST_DEFAULT=${TEST_DEFAULT:-standard}
DOMAINS_DEFAULT=${DOMAINS_DEFAULT:-rutracker.org}
QNUM=${QNUM:-59781}
SOCKS_PORT=${SOCKS_PORT:-1993}
WS_UID=${WS_UID:-1}
WS_GID=${WS_GID:-3003}
@@ -35,8 +34,6 @@ DVTWS2=${DVTWS2:-${ZAPRET_BASE}/nfq2/dvtws2}
WINWS2=${WINWS2:-${ZAPRET_BASE}/nfq2/winws2}
MDIG=${MDIG:-${ZAPRET_BASE}/mdig/mdig}
DESYNC_MARK=0x10000000
IPFW_RULE_NUM=${IPFW_RULE_NUM:-1}
IPFW_DIVERT_PORT=${IPFW_DIVERT_PORT:-59780}
CURL_MAX_TIME=${CURL_MAX_TIME:-2}
CURL_MAX_TIME_QUIC=${CURL_MAX_TIME_QUIC:-$CURL_MAX_TIME}
CURL_MAX_TIME_DOH=${CURL_MAX_TIME_DOH:-2}
@@ -45,12 +42,20 @@ HTTP_PORT=${HTTP_PORT:-80}
HTTPS_PORT=${HTTPS_PORT:-443}
QUIC_PORT=${QUIC_PORT:-443}
UNBLOCKED_DOM=${UNBLOCKED_DOM:-iana.org}
PARALLEL_OUT=/tmp/zapret_parallel
SIM_SUCCESS_RATE=${SIM_SUCCESS_RATE:-10}
HDRTEMP=/tmp/zapret-hdr
IPFW_RULE_MAX=${IPFW_RULE_MAX:-999}
IPFW_RULE_NUM=${IPFW_RULE_NUM:-$(($$ % $IPFW_RULE_MAX + 1))}
IPFW_DIVERT_PORT=${IPFW_DIVERT_PORT:-$(($$ % 64536 + 1000))}
QNUM=${QNUM:-$(($$ % 64536 + 1000))}
NFT_TABLE=blockcheck
IPSET_FILE=/tmp/blockcheck_ipset_$$.txt
PARALLEL_OUT=/tmp/zapret_parallel_$$
HDRTEMP=/tmp/zapret-hdr-$$
NFT_TABLE=blockcheck$$
IPT_OUT_CHAIN=blockcheck_output_$$
IPT_IN_CHAIN=blockcheck_input_$$
IPT_COMMENT="-m comment --comment blockcheck_$$"
DNSCHECK_DNS=${DNSCHECK_DNS:-8.8.8.8 1.1.1.1 77.88.8.1}
DNSCHECK_DOM=${DNSCHECK_DOM:-pornhub.com ej.ru rutracker.org www.torproject.org bbc.com}
@@ -59,7 +64,6 @@ DNSCHECK_DIG1=/tmp/dig1.txt
DNSCHECK_DIG2=/tmp/dig2.txt
DNSCHECK_DIGS=/tmp/digs.txt
IPSET_FILE=/tmp/blockcheck_ipset.txt
unset PF_STATUS
PF_RULES_SAVE=/tmp/pf-zapret-save.conf
@@ -240,7 +244,7 @@ mdig_vars()
# $1 - ip version 4/6
# $2 - hostname
hostvar=$(echo $2 | sed -e 's/[\./?&#@%*$^:~=!()+-]/_/g')
hostvar=$(echo $2 | sed -e 's/[\./?&#@%*$^:~=!()+-]/_/g' | tr 'A-Z' 'a-z')
cachevar=DNSCACHE_${hostvar}_$1
countvar=${cachevar}_COUNT
eval count=\$${countvar}
@@ -297,7 +301,7 @@ mdig_resolve_all()
mdig_vars "$1" "$sdom"
if [ -n "$count" ]; then
n=0
while [ "$n" -le $count ]; do
while [ "$n" -lt $count ]; do
eval ip__=\$${cachevar}_$n
if [ -n "$ips__" ]; then
ips__="$ips__ $ip__"
@@ -408,8 +412,14 @@ zp_already_running()
CYGWIN)
win_process_exists $PKTWSD || win_process_exists winws || win_process_exists goodbyedpi
;;
*)
FreeBSD|OpenBSD)
process_exists $PKTWSD || process_exists tpws || process_exists dvtws
;;
Linux)
process_exists $PKTWSD || process_exists tpws || process_exists nfqws
;;
*)
return 1
esac
}
check_already()
@@ -633,11 +643,11 @@ curl_with_dig()
# $2 - domain name
# $3 - port
# $4+ - curl params
local dom=$2 port=$3
local dom="$2" port=$3
local sdom suri ip
split_by_separator "$dom" / sdom suri
mdig_resolve $1 ip $sdom
mdig_resolve $1 ip "$sdom"
shift ; shift ; shift
if [ -n "$ip" ]; then
curl_with_subst_ip "$sdom" "$port" "$ip" "$@"
@@ -652,12 +662,12 @@ curl_probe()
# $3 - port
# $4 - subst ip
# $5+ - curl params
local ipv=$1 dom=$2 port=$3 subst=$4
local ipv=$1 dom="$2" port=$3 subst=$4
shift; shift; shift; shift
if [ -n "$subst" ]; then
curl_with_subst_ip $dom $port $subst "$@"
curl_with_subst_ip "$dom" $port $subst "$@"
else
curl_with_dig $ipv $dom $port "$@"
curl_with_dig $ipv "$dom" $port "$@"
fi
}
curl_test_http()
@@ -668,7 +678,7 @@ curl_test_http()
# $4 - "detail" - detail info
local code loc hdrt="${HDRTEMP}_${!:-$$}.txt" dom="$(tolower "$2")"
curl_probe $1 $2 $HTTP_PORT "$3" -SsD "$hdrt" -A "$USER_AGENT" --max-time $CURL_MAX_TIME $CURL_OPT "http://$2" -o /dev/null 2>&1 || {
curl_probe $1 "$2" $HTTP_PORT "$3" -SsD "$hdrt" -A "$USER_AGENT" --max-time $CURL_MAX_TIME $CURL_OPT "http://$2" -o /dev/null 2>&1 || {
code=$?
rm -f "$hdrt"
return $code
@@ -680,6 +690,7 @@ curl_test_http()
code=$(hdrfile_http_code "$hdrt")
[ "$code" = 301 -o "$code" = 302 -o "$code" = 307 -o "$code" = 308 ] && {
loc=$(hdrfile_location "$hdrt")
split_by_separator "$dom" / dom
tolower "$loc" | grep -qE "^https?://.*$dom(/|$)" ||
tolower "$loc" | grep -vqE '^https?://' || {
echo suspicious redirection $code to : $loc
@@ -703,7 +714,7 @@ curl_test_https_tls12()
# $3 - subst ip
# do not use tls 1.3 to make sure server certificate is not encrypted
curl_probe $1 $2 $HTTPS_PORT "$3" $HTTPS_HEAD -Ss -A "$USER_AGENT" --max-time $CURL_MAX_TIME $CURL_OPT --tlsv1.2 $TLSMAX12 "https://$2" -o /dev/null 2>&1
curl_probe $1 "$2" $HTTPS_PORT "$3" $HTTPS_HEAD -Ss -A "$USER_AGENT" --max-time $CURL_MAX_TIME $CURL_OPT --tlsv1.2 $TLSMAX12 "https://$2" -o /dev/null 2>&1
}
curl_test_https_tls13()
{
@@ -712,7 +723,7 @@ curl_test_https_tls13()
# $3 - subst ip
# force TLS1.3 mode
curl_probe $1 $2 $HTTPS_PORT "$3" $HTTPS_HEAD -Ss -A "$USER_AGENT" --max-time $CURL_MAX_TIME $CURL_OPT --tlsv1.3 $TLSMAX13 "https://$2" -o /dev/null 2>&1
curl_probe $1 "$2" $HTTPS_PORT "$3" $HTTPS_HEAD -Ss -A "$USER_AGENT" --max-time $CURL_MAX_TIME $CURL_OPT --tlsv1.3 $TLSMAX13 "https://$2" -o /dev/null 2>&1
}
curl_test_http3()
@@ -721,7 +732,7 @@ curl_test_http3()
# $2 - domain name
# force QUIC only mode without tcp
curl_with_dig $1 $2 $QUIC_PORT $HTTPS_HEAD -Ss -A "$USER_AGENT" --max-time $CURL_MAX_TIME_QUIC --http3-only $CURL_OPT "https://$2" -o /dev/null 2>&1
curl_with_dig $1 "$2" $QUIC_PORT $HTTPS_HEAD -Ss -A "$USER_AGENT" --max-time $CURL_MAX_TIME_QUIC --http3-only $CURL_OPT "https://$2" -o /dev/null 2>&1
}
ipt_aux_scheme()
@@ -731,24 +742,24 @@ ipt_aux_scheme()
# $3 - port
# to avoid possible INVALID state drop
[ "$2" = tcp ] && IPT_ADD_DEL $1 INPUT -p $2 --sport $3 ! --syn -j ACCEPT
[ "$2" = tcp ] && IPT_ADD_DEL $1 INPUT -p $2 --sport $3 ! $IPT_COMMENT --syn -j ACCEPT
local icmp_filter="-p icmp -m icmp --icmp-type"
[ "$IPV" = 6 ] && icmp_filter="-p icmpv6 -m icmp6 --icmpv6-type"
IPT_ADD_DEL $1 INPUT $icmp_filter time-exceeded -m connmark --mark $DESYNC_MARK/$DESYNC_MARK -j DROP
IPT_ADD_DEL $1 INPUT $icmp_filter time-exceeded -m connmark --mark $DESYNC_MARK/$DESYNC_MARK $IPT_COMMENT -j DROP
# for strategies with incoming packets involved (autottl)
IPT_ADD_DEL $1 OUTPUT -p $2 --dport $3 -m conntrack --ctstate INVALID -j ACCEPT
IPT_ADD_DEL $1 OUTPUT -p $2 --dport $3 -m conntrack --ctstate INVALID $IPT_COMMENT -j ACCEPT
if [ "$IPV" = 6 -a -n "$IP6_DEFRAG_DISABLE" ]; then
# the only way to reliable disable ipv6 defrag. works only in 4.16+ kernels
IPT_ADD_DEL $1 OUTPUT -t raw -p $2 -m frag -j CT --notrack
IPT_ADD_DEL $1 OUTPUT -t raw -p $2 -m frag $IPT_COMMENT -j CT --notrack
elif [ "$IPV" = 4 ]; then
# enable fragments
IPT_ADD_DEL $1 OUTPUT -f -j ACCEPT
IPT_ADD_DEL $1 OUTPUT -f $IPT_COMMENT -j ACCEPT
fi
# enable everything generated by nfqws (works only in OUTPUT, not in FORWARD)
# raw table may not be present
IPT_ADD_DEL $1 OUTPUT -t raw -m mark --mark $DESYNC_MARK/$DESYNC_MARK -j CT --notrack
IPT_ADD_DEL $1 OUTPUT -t raw -m mark --mark $DESYNC_MARK/$DESYNC_MARK $IPT_COMMENT -j CT --notrack
}
ipt_scheme()
{
@@ -758,18 +769,18 @@ ipt_scheme()
local ip
$IPTABLES -t mangle -N blockcheck_output 2>/dev/null
$IPTABLES -t mangle -F blockcheck_output
IPT OUTPUT -t mangle -j blockcheck_output
$IPTABLES -t mangle -N $IPT_OUT_CHAIN 2>/dev/null
$IPTABLES -t mangle -F $IPT_OUT_CHAIN
IPT OUTPUT -t mangle -j $IPT_OUT_CHAIN
# prevent loop
$IPTABLES -t mangle -A blockcheck_output -m mark --mark $DESYNC_MARK/$DESYNC_MARK -j RETURN
$IPTABLES -t mangle -A blockcheck_output ! -p $1 -j RETURN
$IPTABLES -t mangle -A blockcheck_output -p $1 ! --dport $2 -j RETURN
$IPTABLES -t mangle -A $IPT_OUT_CHAIN -m mark --mark $DESYNC_MARK/$DESYNC_MARK -j RETURN
$IPTABLES -t mangle -A $IPT_OUT_CHAIN ! -p $1 -j RETURN
$IPTABLES -t mangle -A $IPT_OUT_CHAIN -p $1 ! --dport $2 -j RETURN
for ip in $3; do
$IPTABLES -t mangle -A blockcheck_output -d $ip -j CONNMARK --or-mark $DESYNC_MARK
$IPTABLES -t mangle -A blockcheck_output -d $ip -j NFQUEUE --queue-num $QNUM
$IPTABLES -t mangle -A $IPT_OUT_CHAIN -d $ip -j CONNMARK --or-mark $DESYNC_MARK
$IPTABLES -t mangle -A $IPT_OUT_CHAIN -d $ip -j NFQUEUE --queue-num $QNUM
done
ipt_aux_scheme 1 $1 $2
@@ -845,9 +856,9 @@ pktws_ipt_unprepare()
case "$FWTYPE" in
iptables)
ipt_aux_scheme 0 $1 $2
IPT_DEL OUTPUT -t mangle -j blockcheck_output
$IPTABLES -t mangle -F blockcheck_output 2>/dev/null
$IPTABLES -t mangle -X blockcheck_output 2>/dev/null
IPT_DEL OUTPUT -t mangle -j $IPT_OUT_CHAIN
$IPTABLES -t mangle -F $IPT_OUT_CHAIN 2>/dev/null
$IPTABLES -t mangle -X $IPT_OUT_CHAIN 2>/dev/null
;;
nftables)
nft delete table inet $NFT_TABLE 2>/dev/null
@@ -875,17 +886,17 @@ pktws_ipt_prepare_tcp()
pktws_ipt_prepare tcp $1 "$2"
# for autottl mode
# for autottl mode and tcp_mss detection
case "$FWTYPE" in
iptables)
$IPTABLES -N blockcheck_input -t mangle 2>/dev/null
$IPTABLES -F blockcheck_input -t mangle 2>/dev/null
IPT INPUT -t mangle -j blockcheck_input
$IPTABLES -t mangle -A blockcheck_input ! -p tcp -j RETURN
$IPTABLES -t mangle -A blockcheck_input -p tcp ! --sport $1 -j RETURN
$IPTABLES -t mangle -A blockcheck_input -p tcp ! --tcp-flags SYN,ACK SYN,ACK -j RETURN
$IPTABLES -N $IPT_IN_CHAIN -t mangle 2>/dev/null
$IPTABLES -F $IPT_IN_CHAIN -t mangle 2>/dev/null
IPT INPUT -t mangle -j $IPT_IN_CHAIN
$IPTABLES -t mangle -A $IPT_IN_CHAIN ! -p tcp -j RETURN
$IPTABLES -t mangle -A $IPT_IN_CHAIN -p tcp ! --sport $1 -j RETURN
$IPTABLES -t mangle -A $IPT_IN_CHAIN -p tcp ! --tcp-flags SYN,ACK SYN,ACK -j RETURN
for ip in $2; do
$IPTABLES -A blockcheck_input -t mangle -s $ip -j NFQUEUE --queue-num $QNUM
$IPTABLES -A $IPT_IN_CHAIN -t mangle -s $ip -j NFQUEUE --queue-num $QNUM
done
;;
nftables)
@@ -909,9 +920,9 @@ pktws_ipt_unprepare_tcp()
case "$FWTYPE" in
iptables)
IPT_DEL INPUT -t mangle -j blockcheck_input
$IPTABLES -t mangle -F blockcheck_input 2>/dev/null
$IPTABLES -t mangle -X blockcheck_input 2>/dev/null
IPT_DEL INPUT -t mangle -j $IPT_IN_CHAIN
$IPTABLES -t mangle -F $IPT_IN_CHAIN 2>/dev/null
$IPTABLES -t mangle -X $IPT_IN_CHAIN 2>/dev/null
;;
esac
}
@@ -939,7 +950,8 @@ pktws_start()
"$DVTWS2" --port=$IPFW_DIVERT_PORT --lua-init=@"$ZAPRET_BASE/lua/zapret-lib.lua" --lua-init=@"$ZAPRET_BASE/lua/zapret-antidpi.lua" "$@" >/dev/null &
;;
CYGWIN)
"$WINWS2" $WF --ipset="$IPSET_FILE" --lua-init=@"$ZAPRET_BASE/lua/zapret-lib.lua" --lua-init=@"$ZAPRET_BASE/lua/zapret-antidpi.lua" "$@" >/dev/null &
# allow multiple PKTWS instances with the same wf filter but different ipset
"$WINWS2" --wf-dup-check=0 $WF --ipset="$IPSET_FILE" --lua-init=@"$ZAPRET_BASE/lua/zapret-lib.lua" --lua-init=@"$ZAPRET_BASE/lua/zapret-antidpi.lua" "$@" >/dev/null &
;;
esac
PID=$!
@@ -990,7 +1002,7 @@ curl_test()
if [ "$PARALLEL" = 1 ]; then
rm -f "${PARALLEL_OUT}"*
for n in $(seq -s ' ' 1 $REPEATS); do
$1 "$IPV" $2 $3 "$4" >"${PARALLEL_OUT}_$n" &
$1 "$IPV" "$2" $3 "$4" >"${PARALLEL_OUT}_$n" &
pids="${pids:+$pids }$!"
done
n=1
@@ -1009,7 +1021,7 @@ curl_test()
while [ $n -lt $REPEATS ]; do
n=$(($n+1))
[ $REPEATS -gt 1 ] && printf "[attempt $n] "
if $1 "$IPV" $2 $3 "$4" ; then
if $1 "$IPV" "$2" $3 "$4" ; then
[ $REPEATS -gt 1 ] && echo 'AVAILABLE'
else
code=$?
@@ -1034,7 +1046,7 @@ ws_curl_test()
# $2 - test function
# $3 - domain
# $4,$5,$6, ... - ws params
local code ws_start=$1 testf=$2 dom=$3
local code ws_start=$1 testf=$2 dom="$3"
[ "$SIMULATE" = 1 ] && {
n=$(random 0 99)
@@ -1050,7 +1062,7 @@ ws_curl_test()
shift
shift
$ws_start "$@"
curl_test $testf $dom
curl_test $testf "$dom"
code=$?
ws_kill
return $code
@@ -1060,11 +1072,11 @@ pktws_curl_test()
# $1 - test function
# $2 - domain
# $3,$4,$5, ... - nfqws/dvtws params
local testf=$1 dom=$2 strategy code
local testf=$1 dom="$2" strategy code
shift; shift;
echo - $testf ipv$IPV $dom : $PKTWSD ${WF:+$WF }${PKTWS_EXTRA_PRE:+$PKTWS_EXTRA_PRE }${PKTWS_EXTRA_PRE_1:+"$PKTWS_EXTRA_PRE_1" }${PKTWS_EXTRA_PRE_2:+"$PKTWS_EXTRA_PRE_2" }${PKTWS_EXTRA_PRE_3:+"$PKTWS_EXTRA_PRE_3" }${PKTWS_EXTRA_PRE_4:+"$PKTWS_EXTRA_PRE_4" }${PKTWS_EXTRA_PRE_5:+"$PKTWS_EXTRA_PRE_5" }${PKTWS_EXTRA_PRE_6:+"$PKTWS_EXTRA_PRE_6" }${PKTWS_EXTRA_PRE_7:+"$PKTWS_EXTRA_PRE_7" }${PKTWS_EXTRA_PRE_8:+"$PKTWS_EXTRA_PRE_8" }${PKTWS_EXTRA_PRE_9:+"$PKTWS_EXTRA_PRE_9" }$@${PKTWS_EXTRA_POST:+ $PKTWS_EXTRA_POST}${PKTWS_EXTRA_POST_1:+ "$PKTWS_EXTRA_POST_1"}${PKTWS_EXTRA_POST_2:+ "$PKTWS_EXTRA_POST_2"}${PKTWS_EXTRA_POST_3:+ "$PKTWS_EXTRA_POST_3"}${PKTWS_EXTRA_POST_4:+ "$PKTWS_EXTRA_POST_4"}${PKTWS_EXTRA_POST_5:+ "$PKTWS_EXTRA_POST_5"}${PKTWS_EXTRA_POST_6:+ "$PKTWS_EXTRA_POST_6"}${PKTWS_EXTRA_POST_7:+ "$PKTWS_EXTRA_POST_7"}${PKTWS_EXTRA_POST_8:+ "$PKTWS_EXTRA_POST_8"}${PKTWS_EXTRA_POST_9:+ "$PKTWS_EXTRA_POST_9"}
ws_curl_test pktws_start $testf $dom ${PKTWS_EXTRA_PRE:+$PKTWS_EXTRA_PRE }${PKTWS_EXTRA_PRE_1:+"$PKTWS_EXTRA_PRE_1" }${PKTWS_EXTRA_PRE_2:+"$PKTWS_EXTRA_PRE_2" }${PKTWS_EXTRA_PRE_3:+"$PKTWS_EXTRA_PRE_3" }${PKTWS_EXTRA_PRE_4:+"$PKTWS_EXTRA_PRE_4" }${PKTWS_EXTRA_PRE_5:+"$PKTWS_EXTRA_PRE_5" }${PKTWS_EXTRA_PRE_6:+"$PKTWS_EXTRA_PRE_6" }${PKTWS_EXTRA_PRE_7:+"$PKTWS_EXTRA_PRE_7" }${PKTWS_EXTRA_PRE_8:+"$PKTWS_EXTRA_PRE_8" }${PKTWS_EXTRA_PRE_9:+"$PKTWS_EXTRA_PRE_9" }"$@"${PKTWS_EXTRA_POST:+ $PKTWS_EXTRA_POST}${PKTWS_EXTRA_POST_1:+ "$PKTWS_EXTRA_POST_1"}${PKTWS_EXTRA_POST_2:+ "$PKTWS_EXTRA_POST_2"}${PKTWS_EXTRA_POST_3:+ "$PKTWS_EXTRA_POST_3"}${PKTWS_EXTRA_POST_4:+ "$PKTWS_EXTRA_POST_4"}${PKTWS_EXTRA_POST_5:+ "$PKTWS_EXTRA_POST_5"}${PKTWS_EXTRA_POST_6:+ "$PKTWS_EXTRA_POST_6"}${PKTWS_EXTRA_POST_7:+ "$PKTWS_EXTRA_POST_7"}${PKTWS_EXTRA_POST_8:+ "$PKTWS_EXTRA_POST_8"}${PKTWS_EXTRA_POST_9:+ "$PKTWS_EXTRA_POST_9"}
ws_curl_test pktws_start $testf "$dom" ${PKTWS_EXTRA_PRE:+$PKTWS_EXTRA_PRE }${PKTWS_EXTRA_PRE_1:+"$PKTWS_EXTRA_PRE_1" }${PKTWS_EXTRA_PRE_2:+"$PKTWS_EXTRA_PRE_2" }${PKTWS_EXTRA_PRE_3:+"$PKTWS_EXTRA_PRE_3" }${PKTWS_EXTRA_PRE_4:+"$PKTWS_EXTRA_PRE_4" }${PKTWS_EXTRA_PRE_5:+"$PKTWS_EXTRA_PRE_5" }${PKTWS_EXTRA_PRE_6:+"$PKTWS_EXTRA_PRE_6" }${PKTWS_EXTRA_PRE_7:+"$PKTWS_EXTRA_PRE_7" }${PKTWS_EXTRA_PRE_8:+"$PKTWS_EXTRA_PRE_8" }${PKTWS_EXTRA_PRE_9:+"$PKTWS_EXTRA_PRE_9" }"$@"${PKTWS_EXTRA_POST:+ $PKTWS_EXTRA_POST}${PKTWS_EXTRA_POST_1:+ "$PKTWS_EXTRA_POST_1"}${PKTWS_EXTRA_POST_2:+ "$PKTWS_EXTRA_POST_2"}${PKTWS_EXTRA_POST_3:+ "$PKTWS_EXTRA_POST_3"}${PKTWS_EXTRA_POST_4:+ "$PKTWS_EXTRA_POST_4"}${PKTWS_EXTRA_POST_5:+ "$PKTWS_EXTRA_POST_5"}${PKTWS_EXTRA_POST_6:+ "$PKTWS_EXTRA_POST_6"}${PKTWS_EXTRA_POST_7:+ "$PKTWS_EXTRA_POST_7"}${PKTWS_EXTRA_POST_8:+ "$PKTWS_EXTRA_POST_8"}${PKTWS_EXTRA_POST_9:+ "$PKTWS_EXTRA_POST_9"}
code=$?
[ "$code" = 0 ] && {
@@ -1086,11 +1098,11 @@ xxxws_curl_test_update()
# $2 - test function
# $3 - domain
# $4,$5,$6, ... - nfqws2/dvtws2 params
local code xxxf=$1 testf=$2 dom=$3
local code xxxf=$1 testf=$2 dom="$3"
shift
shift
shift
$xxxf $testf $dom "$@"
$xxxf $testf "$dom" "$@"
code=$?
[ $code = 0 ] && strategy="${strategy:-$@}"
return $code
@@ -1314,7 +1326,6 @@ check_domain_http_tcp()
local ips
# in case was interrupted before
pktws_ipt_unprepare_tcp $2
ws_kill
check_domain_prolog $1 $2 $4 || return
@@ -1342,7 +1353,6 @@ check_domain_http_udp()
local ips
# in case was interrupted before
pktws_ipt_unprepare_udp $2
ws_kill
check_domain_prolog $1 $2 $3 || return

View File

@@ -95,7 +95,7 @@ end_with_newline()
}
trim()
{
awk '{gsub(/^ +| +$/,"")}1'
awk '{gsub(/^[ \t]+|[ \t]+$/,"")}1'
}
split_by_separator()
{
@@ -119,7 +119,7 @@ dir_is_not_empty()
# $1 - directory
local n
[ -d "$1" ] || return 1
n=$(ls "$1" | wc -c | xargs)
n=$(ls -A "$1" | wc -c | xargs)
[ "$n" != 0 ]
}
@@ -343,7 +343,7 @@ setup_md5()
{
[ -n "$MD5" ] && return
MD5=md5sum
exists $MD5 || MD5=md5
exists $MD5 || MD5="md5 -q"
}
md5f()
@@ -394,9 +394,9 @@ shell_name()
process_exists()
{
if exists pgrep; then
pgrep ^$1$ >/dev/null
pgrep "^$1$" >/dev/null
elif exists pidof; then
pidof $1 >/dev/null
pidof "$1" >/dev/null
else
return 1
fi

View File

@@ -36,8 +36,8 @@ ask_list()
# $3 - (optional) default value
local M_DEFAULT
eval M_DEFAULT="\$$1"
local M_ALL=$M_DEFAULT
local M="" m M_OLD
local M_DEFAULT_VAR="$M_DEFAULT"
local M="" m
[ -n "$3" ] && { find_str_in_list "$M_DEFAULT" "$2" || M_DEFAULT="$3" ;}
@@ -53,5 +53,5 @@ ask_list()
echo selected : $M
eval $1="\"$M\""
[ "$M" != "$M_DEFAULT" ]
[ "$M" != "$M_DEFAULT_VAR" ]
}

View File

@@ -256,7 +256,7 @@ check_system()
get_free_space_mb()
{
df -m $PWD | awk '/[0-9]%/{print $(NF-2)}'
df -m "$1" | awk '/[0-9]%/{print $(NF-2)}'
}
get_ram_kb()
{
@@ -779,7 +779,9 @@ select_fwtype()
echo WARNING ! if you need large lists it may be necessary to fall back to iptables+ipset firewall
}
echo select firewall type :
ask_list FWTYPE "iptables nftables" "$FWTYPE" && write_config_var FWTYPE
ask_list FWTYPE "iptables nftables" "$FWTYPE"
# always write config var to prevent auto discovery every time
write_config_var FWTYPE
}
dry_run_nfqws_()

View File

@@ -77,8 +77,7 @@ nft_rule_exists()
nft_add_rule ruletest "$2"
rule=$(nft list chain inet $ZAPRET_NFT_TABLE ruletest | sed -n '3s/\t//gp')
nft_flush_chain ruletest
local yes=$(nft list chain inet $ZAPRET_NFT_TABLE $1 | sed -n "s/^[\t]*$rule\$/1/p")
[ -n "$yes" ]
nft list chain inet $ZAPRET_NFT_TABLE $1 | trim | grep -qxF "$rule"
}
nft_del_all_chains_from_table()

View File

@@ -178,3 +178,20 @@ v0.8.1
* nfqws2: alternative representation of payload filter in execution_plan item
* nfqws2: --payload-disable
* nfqws2: gracefully shutdown on SIGINT and SIGTERM
* nfqws2: harden wireguard detection. do not detect if reserved bytes 1..3 != 0
0.8.5
* nfqws2: do not require / in the beginning of URI in http
* zapret-lib: rawsend_dissect_segmented support URG
* zapret-antidpi: oob
* blockcheck2: 17-oob.sh
* nfqws2: set desync.tcp_mss to minimum of both ends or default if at least one is unknown
* zapret-lib: tcp_nop_del
* blockcheck2: tcp_nop_del in SYN packets with md5 in openbsd
0.8.6
* winws2, blockcheck2: allow multiple instances in windows, linux, freebsd (not openbsd)
* nfqws2: fix critical bug - wrong ipv6 dissection
* zapret-auto: fix standard_failure_detector http redirect regression

View File

@@ -5,6 +5,7 @@ make -C /opt/zapret2 systemd
FreeBSD :
pkg install pkgconf
pkg search luajit-2
# see what's the version available
pkg install luajit-2.1.0.20250728

View File

@@ -182,6 +182,7 @@
- [fakeddisorder](#fakeddisorder)
- [hostfakesplit](#hostfakesplit)
- [tcpseg](#tcpseg)
- [oob](#oob)
- [UDP Fooling](#udp-fooling)
- [udplen](#udplen)
- [dht\_dn](#dht_dn)
@@ -263,7 +264,10 @@
- [openrc integration principles](#openrc-integration-principles)
- [openrc cheat sheet](#openrc-cheat-sheet)
- [Alternative installation on systemd](#alternative-installation-on-systemd)
- [Other firmwares](#other-firmwares)
- [Other firmwares](#other-firmwares)
- [Windows](#windows)
- [Windows 7](#windows-7)
- [Windows Server](#windows-server)
# Introduction
@@ -276,6 +280,8 @@ The core component of zapret2 is the **nfqws2** program (**dvtws2** on BSD, **wi
Consequently, the Lua code is the next most critical part of the project. The base package includes the [zapret-lib.lua](#zapret-liblua-base-function-library) helper library, the [zapret-antidpi.lua](#zapret-antidpilua-dpi-attack-program-library) DPI attack library, and the [zapret-auto.lua](#zapret-autolua-automation-and-orchestration-library) orchestration library for dynamic decision-making. Additionally, it features `zapret-tests.lua` for testing C functions, `zapret-wgobfs.lua` for WireGuard protocol obfuscation, and `zapret-pcap.lua` for capturing traffic into .cap files.
Project requires LuaJIT-2.1+ or PUC Lua 5.3+. Older versions are not tested and not supported.
Traffic redirection from the kernel is handled by [iptables](#traffic-interception-using-iptables) and [nftables](#traffic-interception-using-nftables) in [Linux](#traffic-interception-in-the-linux-kernel), [ipfw](#traffic-interception-in-the-freebsd-kernel) in [FreeBSD](#traffic-interception-in-the-freebsd-kernel), and [pf](#traffic-interception-in-the-openbsd-kernel) in [OpenBSD](#traffic-interception-in-the-openbsd-kernel). On [Windows](#traffic-interception-in-the-windows-kernel), this functionality is built directly into the winws2 process via the WinDivert driver. The kernel interception scheme, nfqws2, and the Lua code constitute the project's minimal working core. Everything else is supplementary, secondary, or optional.
Secondary components include Linux [startup scripts](#startup-scripts) (`init.d`, `common`, `ipset`, `install_easy.sh`, `uninstall_easy.sh`) and [blockcheck2](#blockcheck2), a tool for automated strategy testing. The purpose of the startup scripts is to coordinate the initialization of tables and nfqws2 instances while accounting for the specifics of various distributions (OpenWrt, systemd, OpenRC). They also provide support for synchronized updates of various [lists](#list-management-system) and [loading](#create_ipsetsh) IP lists into kernel-space (ipset). Users can implement these tasks using their own tools if preferred or if the provided [startup scripts](#startup-scripts) do not meet their needs. These scripts store all settings in a [config](#config-file) file located in the project root; this config is specific to the scripts, and nfqws2 is unaware of it.
@@ -697,6 +703,7 @@ Specific parameters for winws2:
--wf-raw-part=<filter>|@<filename> ; WinDivert constructor: partial WinDivert raw filter. Combined using the OR principle.
--wf-filter-lan=0|1 ; WinDivert constructor: filter out non-global IP addresses. Default is yes.
--wf-raw=<filter>|@<filename> ; full WinDivert filter. Overrides the constructor.
--wf-dup-check[=0|1] ; 1 (default) = do not allow duplicate winws2 instances with the same wf filter
--wf-save=<filename> ; save the final complete WinDivert filter to a file
LOGICAL NETWORK FILTER:
--ssid-filter=ssid1[,ssid2,ssid3,...] ; list of WiFi networks; interception is enabled only when connected to these, otherwise it is disabled.
@@ -1307,7 +1314,7 @@ desync
| l7payload | string | [payload type](#protocol-detection) of the current packet or packet group | defaults to "unknown" if undetermined |
| l7proto | string | [flow protocol](#protocol-detection) | defaults to "unknown" if undetermined |
| reasm_data | string | result of reassembling a multi-packet message, or the payload itself if no reassembly occurred | currently applied only to TCP |
| reasm_offset | string | offset of the current replayed packet within the reassembled data | currently applied only to TCP |
| reasm_offset | number | offset of the current replayed packet within the reassembled data | currently applied only to TCP |
| decrypt_data | string | result of reassembling and decrypting the payload or payloads of multiple packets | used for QUIC |
| tcp_mss | number | MSS of the remote end of the TCP connection | always present, only for TCP |
| track | table | data bound to the conntrack entry | only if conntrack is present; may be absent |
@@ -3025,9 +3032,10 @@ On any OS, it is possible to maintain a continuous linear `ip_id` order for a pe
| tcp_ack | A positive or negative offset for the TCP Acknowledgment Number. |
| tcp_ts | A positive or negative offset for the TCP Timestamp. This only functions if the Timestamp option is already present. |
| tcp_md5 | Add a TCP MD5 Signature header if it is not already present. Defaults to random bytes, but a 16-byte hex string can be specified. |
| tcp_flags_set | Set TCP flags. Flags are provided as a comma-separated list: FIN, SYN, RST, PUSH, ACK, URG, ECE, CWR. |
| tcp_flags_set | Set TCP flags. Flags are provided as a comma-separated list: FIN, SYN, RST, PUSH, ACK, URG, ECE, CWR. |
| tcp_flags_unset | Clear (unset) TCP flags. Follows the same format as `tcp_flags_set`. |
| tcp_ts_up | Move the TCP Timestamp option to the very beginning of the options list, if present. |
| tcp_nop_del | Delete all NOP TCP options to free space in the header |
| fool | Name of the custom fooling function. It takes a dissect and a `fooling_options` table. |
IPv6 extension headers are added in the following order:
@@ -3144,6 +3152,10 @@ function rawsend_dissect_segmented(desync, dis, mss, options)
Sends dissect `dis` with automatic TCP segmentation based on MSS, applying `options.fooling` and `options.ipid`.
The `ipid` is applied to each fragment. Segmentation is not possible for UDP and is not performed.
- if dis is nil, desync.dis is used.
- if mss is nil, desync.tcp_mss is used.
- if options is nil, options are created from desync.arg
### rawsend_payload_segmented
```
@@ -3795,6 +3807,42 @@ No verdict is issued.
Using `tcpseg`, you can perform `seqovl` without segmentation by using markers "0,-1". To replace the current dissect, it can be combined with `drop`.
### oob
```
function oob(ctx, desync)
```
- arg: [standard fooling](#standard-fooling)
- arg: [standard ipid](#standard-ipid)
- arg: [standard ipfrag](#standard-ipfrag)
- arg: [standard reconstruct](#standard-reconstruct)
- arg: [standard rawsend](#standard-rawsend)
- arg: char - one OOB character
- arg: byte - one OOB byte 0..255
- arg: urp - urgent pointer [marker](#markers), "b" or "e". "b" is default.
Function intercepts TCP handshake shifting sequence numbers one byte to the left then inserts OOB byte into the first non-empty payload.
After it's done it executes [instance cutoff](#instance_cutoff).
Target OS throws away OOB byte from the stream but DPI may analyze message with OOB byte as it's part thus breaking the message.
- OOB is obsolete but still supported in most OS. There are two RFCs. One assumes that th_urp points to the OOB byte,
another one - to the next byte. Therefore, the value th_urp=0 is invalid according to one of the standards, but it can still work.
To enable it, specify "urp=b".
- Marker "urp" defines 0-based position of the OOB byte. Resulting th_urp , except the "b" case, is set incremented by 1. This is what most of the modern OS expect.
- "urp=e" inserts an OOB byte after the very last byte of the payload - generally useless for DPI bypass, since DPI gets the entire original message.
- For protocols in which the server initially waits for a client request, `--in-range=-s1` is enough. In Windows `--wf-tcp-in` is not needed. Automatically intercepted incoming packets with the SYN flag are sufficient.
- For protocols in which the server sends data before the first message from client all incoming packets before that message should be intercepted. In Windows `--wf-tcp-in` is required.
- Cannot be filtered by payload because after the start it's not possible to stop and not to insert the byte. Inserting a byte without OOB breaks the data.
- oob is "lasting" desync. If profile switch occurs before oob is finished it must be duplicated to that profile or TCP will break because of sequence desync.
- If this function is called for the first time not from the very beginning of the tcp connection it [cuts off](#instance_cutoff) immediately.
- Hostlist filtering is possible only with '--ipcache-hostname'.
- Can't work with functions that resend modified payload. multisplit, multidisorder, fakedsplit, fakeddisorder, etc will send duplicates without OOB.
- If the payload is [multi-segment](#handling-multi-packet-payloads), the entire [reasm](#handling-multi-packet-payloads) is sent. OOB is inserted into the segment where urp hits.
In this segment the th_urp is normalized by segment offset, the TH_URG flag is set. The rest of the parts are sent as is. The function drops the whole replay then [cuts itself off](#instance_cutoff).
## UDP Fooling
There are far fewer options for UDP than for TCP due to the simplicity of the protocol. There isn't much that can be done with it.
@@ -5052,7 +5100,7 @@ On classic Linux distributions with systemd, you can use the provided template u
This method does not apply ip/nf tables rules - you will have to handle that separately, as well as write the rules themselves. The rules must be placed somewhere so they are applied after the system starts. For example, you can create a separate systemd unit that runs a shell script or `nft -f /path/to/file.nft`.
## Other firmwares
# Other firmwares
For static binaries, the host environment doesn't matter: PC, Android, set-top box, router, or any other device. Any firmware or Linux distribution will work; static binaries run on everything. They only require a kernel with the necessary build options or modules. However, in addition to binaries, the project uses scripts that rely on certain standard utilities.
@@ -5096,3 +5144,41 @@ It was chosen for this project based on the following characteristics:
* All `iptables` modules are available in the repository and can be installed via `opkg`.
* The repository contains a vast number of standard programs and additional software.
* The availability of an SDK, allowing you to compile any missing components.
# Windows
zapret was initially written for unix. It uses unix emulation layer cygwin on Windows to help migration.
If winws2 is run standalone cygwin1.dll is required in it's directory. If winws2 is run inside cygwin environment - cygwin1.dll must NOT be present in it's directory or it won't run.
cygwin emulate shared PID namespace and deliver signals only within one cygwin1.dll instance !
To send signals sending program (kill, killall) must be run with the same cygwin1.dll as winws2.
It's possible to install cygwin and use winws2 inside cygwin installation.
But it may be more comfortable to use [zapret-win-bundle](https://github.com/bol-van/zapret-win-bundle) which includes minimal cygwin.
cygwin prompt is pre-configured with aliases for blockcheck, blockcheck2, winws, winws2, winws2 with standard Lua scripts.
32-bit Windows versions are not supported by zapret-win-bundle.
## Windows 7
Requirements for windows driver signing have changed in 2021.
Official free updates of windows 7 ended in 2020.
After 2020 for the years paid updates were available (ESU).
One of the updates from ESU enables signatures used in windivert 2.2.2-A.
There are several options :
1. Take `windivert64.sys` and `windivert.dll` version `2.2.0-C` or `2.2.0-D` from [here](https://reqrypt.org/download) and replace existing files.
2. [Hack ESU](https://hackandpwn.com/windows-7-esu-patching)
3. Use "BypassESU" patcher. Google it by name.
4. Use [UpdatePack7R2](https://blog.simplix.info). If you are in Russia or Belarus temporary change region in Control Panel.
## Windows Server
winws2 is linked against wlanapi.dll which is absent by default.
To solve this problem run power shell as administrator and execute command `Install-WindowsFeature -Name Wireless-Networking`.
Then reboot the system.

View File

@@ -181,6 +181,7 @@
- [fakeddisorder](#fakeddisorder)
- [hostfakesplit](#hostfakesplit)
- [tcpseg](#tcpseg)
- [oob](#oob)
- [Дурение udp](#дурение-udp)
- [udplen](#udplen)
- [dht\_dn](#dht_dn)
@@ -261,7 +262,10 @@
- [Принципы интеграции с openrc](#принципы-интеграции-с-openrc)
- [Шпаргалка openrc](#шпаргалка-openrc)
- [Альтернативная установка на systemd](#альтернативная-установка-на-systemd)
- [Другие прошивки](#другие-прошивки)
- [Другие прошивки](#другие-прошивки)
- [Особенности Windows](#особенности-windows)
- [Windows 7](#windows-7)
- [Windows Server](#windows-server)
# Введение
@@ -280,6 +284,8 @@ zapret2 является пакетным манипулятором, основ
Поэтому следующая по важности часть проекта - Lua код. В базовый комплект входит библиотека функций-хелперов [zapret-lib.lua](#библиотека-базовых-функций-zapret-liblua), библиотека программ автономных атак на DPI [zapret-antidpi.lua](#библиотека-программ-атаки-на-dpi-zapret-antidpilua), библиотека функций принятия динамических решений (оркестрации) [zapret-auto.lua](#библиотека-программ-автоматизации-и-оркестрации-zapret-autolua).
Дополнительно присутствует набор тестов C функций `zapret-tests.lua`, средство обфускации wireguard протокола `zapret-wgobfs.lua` и средство записи дампа пакетов в cap файлы `zapret-pcap.lua`.
Проект может работать с LuaJIT-2.1+ или с PUC Lua 5.3+. Более старые версии могут иметь несовместимости, не тестируются и не поддерживаются.
Функции перенаправления трафика из ядра в [Linux](#перехват-трафика-в-ядре-linux) возложены на [iptables](#перехват-трафика-с-помощью-iptables) и [nftables](#перехват-трафика-с-помощью-nftables), в [FreeBSD](#перехват-трафика-в-ядре-freebsd) - на [ipfw](#перехват-трафика-в-ядре-freebsd), в [OpenBSD](#перехват-трафика-в-ядре-openbsd) - на [pf](#перехват-трафика-в-ядре-openbsd), в [Windows](#перехват-трафика-в-ядре-windows) - встроены в сам процесс winws2 посредством драйвера windivert.
Схема перехвата трафика из ядра , nfqws2 и lua код составляют минимально рабочее ядро проекта. Все остальное является дополнительным, второстепенным и опциональным.
@@ -753,6 +759,7 @@ LUA DESYNC ACTION:
--wf-raw-part=<filter>|@<filename> ; windivert конструктор : частичный windivert raw фильтр. обьединяется по принципу ИЛИ.
--wf-filter-lan=0|1 ; windivert конструктор : отфильтровывать неглобальные IP адреса. по умолчанию - да.
--wf-raw=<filter>|@<filename> ; полный windivert фильтр. замещает конструктор.
--wf-dup-check[=0|1] ; управление проверкой на повторный запуск с теми же параметрами фильтра --wf ( по умолчанию 1 )
--wf-save=<filename> ; сохранить полный итоговый windivert фильтр в файл
LOGICAL NETWORK FILTER:
--ssid-filter=ssid1[,ssid2,ssid3,...] ; список сетей wifi, при наличии подключения к которым перехват включается, а иначе не включается.
@@ -1446,7 +1453,7 @@ desync
| l7payload | string | тип [пейлоада](#распознавание-протоколов) текущего пакета или группы пакетов | если неизвестно - unknown |
| l7proto | string | тип [протокола потока](#распознавание-протоколов) | если неизвестно - unknown |
| reasm_data | string | результат сборки многопакетного сообщения, либо сам пейлоад, если сборки не было | пока применяется только для tcp |
| reasm_offset | string | смещение текущего переигрываемого пакета в сборке | пока применяется только для tcp |
| reasm_offset | number | смещение текущего переигрываемого пакета в сборке | пока применяется только для tcp |
| decrypt_data | string | результат сборки и дешифровки пейлоада или пейлоадов нескольких пакетов | применяется для quic |
| tcp_mss | number | MSS противоположного конца tcp соединения | присутствует всегда, только для tcp |
| track | table | данные, привязанные к записи conntrack | только если есть conntrack, может не быть |
@@ -3204,6 +3211,7 @@ Windows заменяет нулевые ip_id на собственную пос
| tcp_flags_set | установить флаги TCP. флаги представлены списком через зяпятую : FIN,SYN,RST,PUSH,ACK,FIN,URG,ECE,CWR |
| tcp_flags_unset | снять флаги TCP. аналогично tcp_flags_set |
| tcp_ts_up | поднять tcp timestamp опцию в самое начало, если она есть |
| tcp_nop_del | удалить все TCP опции NOP для освобождения места в заголовке TCP |
| fool | имя кастомной функции фулинга. она берет диссект и таблицу fooling_options |
ipv6 extension headers добавляются в следующем порядке:
@@ -3323,6 +3331,10 @@ function rawsend_dissect_segmented(desync, dis, mss, options)
Отправить диссект dis с автоматической tcp сегментацией на базе mss с применением `options.fooling` и `options.ipid`.
ipid применяется к каждому фрагменту. Для udp сегментация невозможна и не выполняется.
- Если dis отсутствует, берется desync.dis.
- Если mss отсутствует, берется desync.tcp_mss.
- Если options отсутствуют, они создаются на базе desync.arg.
### rawsend_payload_segmented
```
@@ -3982,6 +3994,41 @@ function tcpseg(ctx, desync)
С помощью tcpseg можно сделать seqovl без сегментации, используя маркеры "0,-1". Для замещения текущего диссекта можно комбинировать с drop.
### oob
```
function oob(ctx, desync)
```
- arg: [standard fooling](#standard-fooling)
- arg: [standard ipid](#standard-ipid)
- arg: [standard ipfrag](#standard-ipfrag)
- arg: [standard reconstruct](#standard-reconstruct)
- arg: [standard rawsend](#standard-rawsend)
- arg: char - 1 символ oob
- arg: byte - числовое значение байта OOB 0..255
- arg: urp - позиционный [маркер](#маркеры) для urgent pointer, "b" или "e". по умолчанию - "b"
Функция перехватывает TCP handshake, сдвигая sequence влево на 1 байт, затем вставляет 1 байт OOB в первый отсылаемый пейлоад и отсылает его.
После отработки функция уходит в [cutoff](#instance_cutoff) по обоим направлениям.
ОС получателя выбрасывает OOB байт из потока, DPI может не выбрасывать и получать оригинальное сообщение со вставленным в него посторонним байтом, что может портить смысл всего сообщения.
- OOB - устаревший, но все еще поддерживаемый в ОС механизм. Имеется 2 стандарта. Один предполагает, что th_urp указывает на байт OOB,
другой - на следующий за ним байт. Поэтому значение th_urp=0 невалидно по одному из стандартов, но все еще может работать.
Чтобы задействовать его укажите "urp=b". Как показывает практика, "b" работает только на Linux серверах, остальные ломает.
- Значение маркера urp означает позицию самого OOB байта. th_urp , кроме случая "b", увеличивается на 1 - согласно интерпретации RFC, поддерживаемой в основных ОС.
- "urp=e" вставляет OOB байт после самого последнего байта пейлоада - для обхода DPI как правило бесполезно, поскольку DPI получает все оригинальное сообщение.
- Для протоколов, в которых в самом начале сервер ждет запроса от клиента, требуется разрешение входящих в пределах `--in-range=-s1`. В Windows `--wf-tcp-in` не нужен. Достаточно автоматически перехватываемых SYN. К таким протоколам относятся http и tls.
- Для протоколов, где сервер что-то шлет до первого сообщения от клиента, требуется разрешить все входящие пакеты до отсылки первого исходящего пакета с данными. В Windows `--wf-tcp-in` обязателен.
- Не может быть отфильтровано по пейлоаду, поскольку после начала модификации tcp handshake соскок уже невозможен, иначе поедут sequence.
- oob - длящаяся десинхронизация. Если возможно переключение профилей до момента окончания работы oob, oob должен быть дублирован в другой профиль, иначе TCP будет сломан из-за десинхронизации sequence.
- Функция помечает специальный флаг, что была вызвана с самого начала соединения. Если управление получено после перескока профиля, происходит немедленный cutoff.
- Фильтрация по хостлистам возможна только при `--ipcache-hostname`. Если в кэше хоста еще нет, и профиль получает управление не с начала соединения, срабатывает предыдущий пункт.
- Не может работать с функциями, предполагающими отправку текущего пейлоада - multisplit, multidisorder, fakedsplit, fakeddisorder и тд. Они будут работать, но будут слать дубль без OOB. Ожидаемый результат "разбить на сегменты и всунуть OOB" как в tpws получить таким образом невозможно.
- Если пейлоад [многопакетный](#особенности-приема-многопакетных-пейлоадов) - отсылается весь [reasm](#особенности-приема-многопакетных-пейлоадов). OOB вставляется в тот сегмент, куда попал urp.
В этом сегменте th_urp нормализуется по смещению сегмента, выставляется флаг TH_URG. Остальные части шлются как есть. Функция дропает весь replay, затем уходит в [cutoff](#instance_cutoff) по обоим направлениям.
## Дурение udp
Для udp намного меньше вариантов, чем для tcp, в силу простоты данного протокола. С ним особо нечего делать.
@@ -5238,7 +5285,7 @@ rc-update add zapret2
Этот способ не поднимает правила ip/nf tables - вам это придется сделать отдельно, как и написать сами правила. Правила нужно прописать куда-то, чтобы они поднимались после старта системы. Например, можно сделать отдельный systemd unit с запуском шелл скрипта или `nft -f /path/to/file.nft`.
## Другие прошивки
# Другие прошивки
Для статических бинарников не имеет значения на чем они запущены: PC, android, приставка, роутер, любой другой девайс.
Подойдет любая прошивка, дистрибутив Linux. Статические бинарники запустятся на всем.
@@ -5300,3 +5347,51 @@ OpenWrt является одной из немногих относительн
* в репозитории есть все модули iptables, их можно доустановить через opkg
* в репозитории есть огромное количество стандартных программ и дополнительного софта
* наличие SDK, позволяющего собрать недостающее
# Особенности Windows
zapret изначально был написан для unix. Для облегчения портирования под Windows используется обертка cygwin, эмулирующая unix среду.
Если winws2 запускается отдельно - требуется cygwin1.dll в той же директории, если в составе cygwin среды - cygwin1.dll не должно быть в той же директории,
иначе не запустится !
cygwin эмулирует общее пространство PID процессов и сигналы только в пределах одного cygwin1.dll !
Чтобы иметь возможность послать сигнал, нужно, чтобы winws2 и программа для посылки сигнала (kill, killall) запускались с одним cygwin1.dll.
Можно использовать отдельно установленную среду cygwin, а можно скачать готовый [zapret-win-bundle](https://github.com/bol-van/zapret-win-bundle), где уже
присутствует минимальный комплект cygwin. cygwin prompt настроен с aliases на запуск blockcheck, blockcheck2, winws, winws2, winws2 со станадртными Lua скриптами,
чтобы не возиться с путями, а сосредоточиться на главном.
32-битные версии Windows в zapret-win-bundle не поддерживаются.
## Windows 7
Требования к подписи драйверов windows изменились в 2021 году.
Официальные бесплатные обновления windows 7 закончились в 2020.
После этого несколько лет продолжали идти платные обновления по программе ESU.
Именно в этих ES* обновлениях находится обновление ядра windows 7, позволяющее загрузить драйвер
windivert 2.2.2-A, который идет в поставке zapret.
Поэтому варианты следующие :
1) Взять `windivert64.sys` и `windivert.dll` версии 2.2.0-C или 2.2.0-D [отсюда](https://reqrypt.org/download) и заменить эти 2 файла.
2) Взломать ESU : [Ссылка 1](https://hackandpwn.com/windows-7-esu-patching) [Ссылка 2](http://www.bifido.net/tweaks-and-scripts/8-extended-security-updates-installer.html)
3) Использовать готовый патчер-взламыватель ESU - "BypassESU". Его надо искать по названию.
4) Использовать [UpdatePack7R2 от simplix](https://blog.simplix.info)
> [!WARNING]
> Но с этим паком есть проблема. Автор из Украины, он очень обиделся на русских.
> Если в панели управления стоит регион RU или BY, появляется неприятный диалог.
> Чтобы эту проблему обойти, можно поставить временно любой другой регион, потом вернуть.
> Так же нет никаких гарантий, что автор не поместил туда какой-то зловредный код.
> Использовать на свой страх и риск.
Более безопасный вариант - скачать последнюю нормальную [довоенную версию : 22.2.10](https://nnmclub.to/forum/viewtopic.php?t=1530323).
Ее достаточно, чтобы windivert 2.2.2-A заработал на windows 7.
## Windows Server
winws2 слинкован с wlanapi.dll, который по умолчанию не установлен в Windows Server.
Для решения этой проблемы запустите power shell под администратором и выполните команду `Install-WindowsFeature -Name Wireless-Networking`.
После чего перезагрузите систему.

View File

@@ -59,8 +59,7 @@ zapret2 - инструмент для таких энтузиастов. Но э
## С чего начать
Хотелось бы избежать [талмуда](manual.md) на главной странице. Поэтому начнем со способа запуска *nfqws2* и описания способов портирования стратегий *nfqws1* - как в *nfqws2* сделать то же самое, что можно было в *nfqws1*.
Когда вы поймете как это работает, вы можете посмотреть Lua код, находящийся "под капотом". Разобрать как он работает, попробовать написать что-то свое.
"талмуд" обязательно будет, как он есть у любых более-менее сложных проектов. Он нужен как справочник.
Когда вы поймете как это работает, вы можете посмотреть Lua код, находящийся "под капотом". Разобрать как он работает, попробовать написать что-то свое, руководствуясь [талмудом](manual.md) как справочником.
### Механика обработки трафика

13
files/fake/sip.bin Normal file
View File

@@ -0,0 +1,13 @@
REGISTER sip:192.168.1.1 SIP/2.0
Via: SIP/2.0/UDP 192.168.1.2:42931;rport;branch=z9hG4bKPj3fd2e8713ffcd90c43f6ce69f6c98461
Max-Forwards: 50
From: <sip:703@192.168.1.1>;tag=ca565d7bd4e24a6d80c631d395ee117e
To: <sip:703@192.168.1.1>
Call-ID: dfec38302b8cea3d83c1452527c895c1
CSeq: 26139 REGISTER
User-Agent: MicroSIP/3.21.5
Contact: <sip:703@192.168.1.2:42931;ob>
Expires: 300
Allow: PRACK, INVITE, ACK, BYE, CANCEL, UPDATE, INFO, SUBSCRIBE, NOTIFY, REFER, MESSAGE, OPTIONS
Content-Length: 0

View File

@@ -288,7 +288,7 @@ ask_config_tmpdir()
echo /tmp in openwrt is tmpfs. on low RAM systems there may be not enough RAM to store downloaded files
echo default tmpfs has size of 50% RAM
echo "RAM : $(get_ram_mb) Mb"
echo "DISK : $(get_free_space_mb) Mb"
echo "DISK : $(get_free_space_mb "$EXEDIR/tmp") Mb"
echo select temp file location
[ -z "$TMPDIR" ] && TMPDIR=/tmp
ask_list TMPDIR "/tmp $EXEDIR/tmp" && {

View File

@@ -38,6 +38,7 @@ standard fooling :
* tcp_flags_set=<list> - set tcp flags in comma separated list
* tcp_flags_unset=<list> - unset tcp flags in comma separated list
* tcp_ts_up - move timestamp tcp option to the top if present (workaround for badack without badseq fooling)
* tcp_nop_del - delete NOP tcp options to free space in tcp header
* fool=fool_function - custom fooling function : fool_func(dis, fooling_options)
@@ -511,11 +512,10 @@ function multisplit(ctx, desync)
end
end
-- internal function for code deduplication. do not call directly
function pos_normalize(pos, low, hi)
return (pos>=low and pos<hi) and (pos-low+1) or nil
end
-- internal function for code deduplication. do not call directly
function pos_array_normalize(pos, low, hi)
-- remove positions outside of hi,low range. normalize others to low
local i=1
@@ -1055,6 +1055,105 @@ function tcpseg(ctx, desync)
end
end
-- nfqws1 : not available
-- tpws : close analog is "--split-pos=.. --oob" but works not the same way
-- standard args : fooling, ip_id, rawsend, reconstruct, ipfrag
-- arg : char - oob char
-- arg : byte - oob byte
-- arg : urp - urgent pointer position marker, 'b' or 'e'. default - 0
function oob(ctx, desync)
if not desync.track then return end
if not desync.dis.tcp then
instance_cutoff_shim(ctx, desync)
return
end
local key = desync.func_instance.."_syn"
if not desync.track.lua_state[key] then
if bitand(desync.dis.tcp.th_flags, TH_SYN+TH_ACK)~=TH_SYN then
DLOG("oob: must be applied since the very beginning of the tcp connection - SYN packet")
instance_cutoff_shim(ctx, desync)
return
end
desync.track.lua_state[key] = true
end
if desync.outgoing then
-- direct pos - outgoing
local pos = pos_get(desync, 's', false)
if pos<=1 then
local dseq = u32add(desync.dis.tcp.th_seq, -1)
DLOG("oob: decreasing outgoing seq : "..desync.dis.tcp.th_seq.." => "..dseq)
desync.dis.tcp.th_seq = dseq
end
if pos==0 then
return VERDICT_MODIFY
elseif pos==1 then
local data = desync.reasm_data or desync.dis.payload
if #data==0 then
-- empty ACK
return VERDICT_MODIFY
else
local oob = desync.arg.char or (desync.arg.byte and bu8(desync.arg.byte) or nil) or "\x00"
if #oob~=1 then
error("oob: OOB must be exactly one byte")
end
local dis_oob = deepcopy(desync.dis)
local urp
if not desync.arg.urp or desync.arg.urp=='b' then
urp = 1
dis_oob.tcp.th_urp = 0
elseif desync.arg.urp=='e' then
urp = #data+1
dis_oob.tcp.th_urp = urp
else
urp = resolve_pos(data, desync.l7payload, desync.arg.urp)
DLOG("oob: resolved urp marker to "..urp-1)
if not urp then
DLOG("oob: cannot resolve urp marker '"..desync.arg.urp.."'")
instance_cutoff_shim(ctx, desync)
return
end
dis_oob.tcp.th_urp = urp
end
DLOG("oob: th_urp "..dis_oob.tcp.th_urp)
-- one byte OOB payload
dis_oob.payload = string.sub(data, 1, urp-1) .. oob .. string.sub(data, urp)
dis_oob.tcp.th_flags = bitor(dis_oob.tcp.th_flags, TH_URG)
DLOG("oob: sending OOB")
if not rawsend_dissect_segmented(desync, dis_oob) then
instance_cutoff_shim(ctx, desync)
return
end
if not desync.replay then
instance_cutoff_shim(ctx, desync)
end
end
return VERDICT_DROP
else
-- drop replay and cutoff
if desync.replay then
DLOG("oob: dropping replay piece")
if desync.replay_piece_last then
instance_cutoff_shim(ctx, desync)
end
return VERDICT_DROP
end
instance_cutoff_shim(ctx, desync)
end
else
-- reverse pos - outgoing
local pos = pos_get(desync, 's', true)
if pos>1 then
DLOG("oob: unexpected outgoing position "..pos)
instance_cutoff_shim(ctx, desync)
return
end
local dack = u32add(desync.dis.tcp.th_ack, 1)
DLOG("oob: increasing incoming ack : "..desync.dis.tcp.th_ack.." => "..dack)
desync.dis.tcp.th_ack = dack
return VERDICT_MODIFY
end
end
-- nfqws1 : "--dpi-desync=udplen"
-- standard args : direction, payload
-- arg : min=N . do not act on payloads smaller than N bytes

View File

@@ -58,6 +58,7 @@ function automate_host_record(desync)
end
-- per-connection storage
function automate_conn_record(desync)
if not desync.track then return nil end
if not desync.track.lua_state.automate then
desync.track.lua_state.automate = {}
end
@@ -180,13 +181,16 @@ function standard_failure_detector(desync, crec)
end
elseif not arg.no_http_redirect and desync.l7payload=="http_reply" and desync.track.hostname then
local hdis = http_dissect_reply(desync.dis.payload)
if hdis and (hdis.code==302 or hdis.code==307) and hdis.headers.location and hdis.headers.location then
trigger = is_dpi_redirect(desync.track.hostname, hdis.headers.location.value)
if b_debug then
if trigger then
DLOG("standard_failure_detector: http redirect "..hdis.code.." to '"..hdis.headers.location.value.."'. looks like DPI redirect.")
else
DLOG("standard_failure_detector: http redirect "..hdis.code.." to '"..hdis.headers.location.value.."'. NOT a DPI redirect.")
if hdis and (hdis.code==302 or hdis.code==307) then
local idx_loc = array_field_search(hdis.headers, "header_low", "location")
if idx_loc then
trigger = is_dpi_redirect(desync.track.hostname, hdis.headers[idx_loc].value)
if b_debug then
if trigger then
DLOG("standard_failure_detector: http redirect "..hdis.code.." to '"..hdis.headers[idx_loc].value.."'. looks like DPI redirect.")
else
DLOG("standard_failure_detector: http redirect "..hdis.code.." to '"..hdis.headers[idx_loc].value.."'. NOT a DPI redirect.")
end
end
end
end

View File

@@ -18,9 +18,14 @@ function luaexec(ctx, desync)
if not desync.arg.code then
error("luaexec: no 'code' parameter")
end
local fname = desync.func_instance.."_luaexec_code"
local fname = desync.func_instance.."_code"
if not _G[fname] then
_G[fname] = load(desync.arg.code, fname)
local err
_G[fname], err = load(desync.arg.code, fname)
if not _G[fname] then
error(err)
return
end
end
-- allow dynamic code to access desync
_G.desync = desync
@@ -242,9 +247,9 @@ end
-- if seq is over 2G s and p position comparision can be wrong
function pos_counter_overflow(desync, mode, reverse)
if not desync.track or not desync.track.tcp or (mode~='s' and mode~='p') then return false end
if not desync.track or (mode~='s' and mode~='p') then return false end
local track_pos = reverse and desync.track.pos.reverse or desync.track.pos.direct
return track_pos.tcp.rseq_over_2G
return track_pos.tcp and track_pos.tcp.rseq_over_2G
end
-- these functions duplicate range check logic from C code
-- mode must be n,d,b,s,x,a
@@ -310,6 +315,7 @@ function pos_str(desync, pos)
return pos.mode..pos_get(desync, pos.mode)
end
-- convert array a to packed string using 'packer' function. only numeric indexes starting from 1, order preserved
function barray(a, packer)
if a then
@@ -628,7 +634,7 @@ end
-- find first tcp options of specified kind in dissect.tcp.options
function find_tcp_option(options, kind)
if options then
for i, opt in pairs(options) do
for i, opt in ipairs(options) do
if opt.kind==kind then return i end
end
end
@@ -638,7 +644,7 @@ end
-- find first ipv6 extension header of specified protocol in dissect.ip6.exthdr
function find_ip6_exthdr(exthdr, proto)
if exthdr then
for i, hdr in pairs(exthdr) do
for i, hdr in ipairs(exthdr) do
if hdr.type==proto then return i end
end
end
@@ -788,6 +794,7 @@ end
-- tcp_flags_set=<list> - set tcp flags in comma separated list
-- tcp_flags_unset=<list> - unset tcp flags in comma separated list
-- tcp_ts_up - move timestamp tcp option to the top if it's present. this allows linux not to accept badack segments without badseq. this is very strange discovery but it works.
-- tcp_nop_del - delete NOP tcp options to free space in tcp header
-- fool - custom fooling function : fool_func(dis, fooling_options)
function apply_fooling(desync, dis, fooling_options)
@@ -849,6 +856,13 @@ function apply_fooling(desync, dis, fooling_options)
if fooling_options.tcp_flags_set then
dis.tcp.th_flags = bitor(dis.tcp.th_flags, parse_tcp_flags(fooling_options.tcp_flags_set))
end
if fooling_options.tcp_nop_del then
for i=#dis.tcp.options,1,-1 do
if dis.tcp.options[i].kind==TCP_KIND_NOOP then
table.remove(dis.tcp.options,i)
end
end
end
if tonumber(fooling_options.tcp_ts) then
local idx = find_tcp_option(dis.tcp.options,TCP_KIND_TS)
if idx and (dis.tcp.options[idx].data and #dis.tcp.options[idx].data or 0)==8 then
@@ -1052,7 +1066,7 @@ function rawsend_dissect_ipfrag(dis, options)
if not rawsend_dissect(fragments[i], options.rawsend, reconstruct_frag) then return false end
end
else
for i, d in pairs(fragments) do
for i, d in ipairs(fragments) do
DLOG("sending ip fragment "..i)
-- C function
if not rawsend_dissect(d, options.rawsend, reconstruct_frag) then return false end
@@ -1068,13 +1082,18 @@ end
-- send dissect with tcp segmentation based on mss value. appply specified rawsend options.
function rawsend_dissect_segmented(desync, dis, mss, options)
dis = dis or desync.dis
local discopy = deepcopy(dis)
options = options or desync_opts(desync)
apply_fooling(desync, discopy, options and options.fooling)
if dis.tcp then
mss = mss or desync.tcp_mss
local extra_len = l3l4_extra_len(discopy)
if extra_len >= mss then return false end
local max_data = mss - extra_len
local urp = dis.tcp.th_urp
local oob = bitand(dis.tcp.th_flags, TH_URG)~=0
if #discopy.payload > max_data then
local pos=1
local len
@@ -1083,6 +1102,15 @@ function rawsend_dissect_segmented(desync, dis, mss, options)
while pos <= #payload do
len = #payload - pos + 1
if len > max_data then len = max_data end
if oob then
if urp>=pos and urp<(pos+len)then
discopy.tcp.th_flags = bitor(dis.tcp.th_flags, TH_URG)
discopy.tcp.th_urp = urp-pos+1
else
discopy.tcp.th_flags = bitand(dis.tcp.th_flags, bitnot(TH_URG))
discopy.tcp.th_urp = 0
end
end
discopy.payload = string.sub(payload,pos,pos+len-1)
apply_ip_id(desync, discopy, options and options.ipid)
if not rawsend_dissect_ipfrag(discopy, options) then
@@ -1102,20 +1130,20 @@ end
-- send specified payload based on existing L3/L4 headers in the dissect. add seq to tcp.th_seq.
function rawsend_payload_segmented(desync, payload, seq, options)
options = options or desync_opts(desync)
local dis = deepcopy(desync.dis)
-- save some cpu and ram
local dis = (payload or seq and seq~=0) and deepcopy(desync.dis) or desync.dis
if payload then dis.payload = payload end
if dis.tcp and seq then
dis.tcp.th_seq = dis.tcp.th_seq + seq
end
return rawsend_dissect_segmented(desync, dis, desync.tcp_mss, options)
return rawsend_dissect_segmented(desync, dis, nil, options)
end
-- check if desync.outgoing comply with arg.dir or def if it's not present or "out" of they are not present both. dir can be "in","out","any"
function direction_check(desync, def)
local dir = desync.arg.dir or def or "out"
return desync.outgoing and desync.arg.dir~="in" or not desync.outgoing and dir~="out"
return desync.outgoing and dir~="in" or not desync.outgoing and dir~="out"
end
-- if dir "in" or "out" cutoff current desync function from opposite direction
function direction_cutoff_opposite(ctx, desync, def)
@@ -1158,9 +1186,9 @@ function replay_drop_set(desync, v)
if v == nil then v=true end
local rdk = replay_drop_key(desync)
if v then
if desync.replay then desync.track.lua_state[replay_drop_key] = true end
if desync.replay then desync.track.lua_state[rdk] = true end
else
desync.track.lua_state[replay_drop_key] = nil
desync.track.lua_state[rdk] = nil
end
end
end
@@ -1168,7 +1196,7 @@ end
-- return true if the caller should return VERDICT_DROP
function replay_drop(desync)
if desync.track then
local drop = desync.replay and desync.track.lua_state[replay_drop_key]
local drop = desync.replay and desync.track.lua_state[replay_drop_key(desync)]
if not desync.replay or desync.replay_piece_last then
-- replay stopped or last piece of reasm
replay_drop_set(desync, false)
@@ -1481,7 +1509,7 @@ function gzip_file(filename, data, expected_ratio, level, memlevel, compress_blo
if not f then
error("gzip_file: "..err)
end
if not write_block_size then compress_block_size=16384 end
if not compress_block_size then compress_block_size=16384 end
if not expected_ratio then expected_ratio=2 end
gz = gzip_init(nil, level, memlevel)
@@ -1530,6 +1558,9 @@ function writefile(filename, data)
end
local s,err = f:write(data)
f:close()
if not s then
error("writefile: "..err)
end
end
-- DISSECTORS
@@ -1545,7 +1576,7 @@ function http_dissect_header(header)
end
-- make table with structured http header representation
function http_dissect_headers(http, pos)
local eol,pnext,header,value,idx,headers,pos_endheader,pos_startvalue,pos_headers_next
local eol,pnext,header,value,idx,headers,pos_endheader,pos_startvalue,pos_headers_end
headers={}
while pos do
eol,pnext = find_next_line(http,pos)
@@ -1604,9 +1635,10 @@ function http_dissect_reply(http)
s = string.sub(http,1,8)
if s~="HTTP/1.1" and s~="HTTP/1.0" then return nil end
pos = string.find(http,"[ \t\r\n]",10)
if not pos then return nil end
code = tonumber(string.sub(http,10,pos-1))
if not code then return nil end
pos = find_next_line(http,pos)
s,pos = find_next_line(http,pos)
local hdis = { code = code }
hdis.headers, hdis.pos_headers_end = http_dissect_headers(http,pos)
if hdis.pos_headers_end then

View File

@@ -688,13 +688,13 @@ function test_rawsend(opts)
end
end
end
local function rawsend_dissect_print(dis, options)
local function rawsend_dissect_print(dis, options, reconstruct)
if options then
options.ifout = ifout
else
options = { ifout = ifout }
end
local b = rawsend_dissect(dis, options)
local b = rawsend_dissect(dis, options, reconstruct)
if not b then
print("rawsend_dissect failed")
rawsend_fail_warning()
@@ -760,8 +760,17 @@ function test_rawsend(opts)
print("send ipv6 udp")
test_assert(rawsend_dissect_print(dis, {repeats=3}))
ip2 = deepcopy(ip6)
ip2.ip6_plen = UDP_BASE_LEN + #payload;
raw_ip = reconstruct_ip6hdr(ip2, {ip6_last_proto = IPPROTO_UDP})
raw_udp = reconstruct_udphdr({uh_sport = udp.uh_sport, uh_dport = udp.uh_dport, uh_ulen = UDP_BASE_LEN + #payload})
raw_udp = csum_udp_fix(raw_ip,raw_udp,payload)
raw = raw_ip .. raw_udp .. payload
print("send ipv6 udp using pure rawsend without dissect")
test_assert(rawsend_print(raw, {repeats=7}))
ddis = ipfrag2(dis, {ipfrag_pos_udp = 80})
for k,d in pairs(ddis) do
for k,d in ipairs(ddis) do
print("send ipv6 udp frag "..k)
test_assert(rawsend_dissect_print(d))
end
@@ -771,7 +780,7 @@ function test_rawsend(opts)
test_assert(rawsend_dissect_print(dis, {repeats=3}))
ddis = ipfrag2(dis, {ipfrag_pos_udp = 80})
for k,d in pairs(ddis) do
for k,d in ipairs(ddis) do
print("send ipv6 udp frag "..k.." with hopbyhop ext header")
test_assert(rawsend_dissect_print(d))
end
@@ -780,7 +789,7 @@ function test_rawsend(opts)
table.insert(ip6.exthdr, { type = IPPROTO_DSTOPTS, data = "\x00\x00\x00\x00\x00\x00" })
ip6.ip6_flow = 0x60001234;
ddis = ipfrag2(dis, {ipfrag_pos_udp = 80})
for k,d in pairs(ddis) do
for k,d in ipairs(ddis) do
print("send ipv6 udp frag "..k.." with hopbyhop, destopt ext headers in unfragmentable part and another destopt ext header in fragmentable part")
test_assert(rawsend_dissect_print(d, {fwmark = 0x50EA}))
end
@@ -788,7 +797,7 @@ function test_rawsend(opts)
fix_ip6_next(ip6) -- required to forge next proto in the second fragment
ip6.ip6_flow = 0x6000AE38;
ddis = ipfrag2(dis, {ipfrag_pos_udp = 80, ipfrag_next = IPPROTO_TCP})
for k,d in pairs(ddis) do
for k,d in ipairs(ddis) do
print("send ipv6 udp frag "..k.." with hopbyhop, destopt ext headers in unfragmentable part and another destopt ext header in fragmentable part. forge next proto in fragment header of the second fragment to TCP")
-- reconstruct dissect using next proto fields in the dissect. do not auto fix next proto chain.
-- by default reconstruct fixes next proto chain

View File

@@ -7,6 +7,7 @@
-- arg : secret - shared secret. any string. must be the same on both peers
-- arg : padmin - min random garbage bytes. 0 by default
-- arg : padmax - max random garbage bytes. 16 by default
-- NOTE : this function does not depend on zapret-lib.lua and should not be run under orchestrator (uses direct instance_cutoff)
function wgobfs(ctx, desync)
local padmin = desync.arg.padmin and tonumber(desync.arg.padmin) or 0
local padmax = desync.arg.padmax and tonumber(desync.arg.padmax) or 16
@@ -46,7 +47,7 @@ function wgobfs(ctx, desync)
if padmin>padmax then
error("wgobfs: padmin>padmax")
end
if desync.l7payload=="wireguard_initiation" or desync.l7payload=="wireguard_response" or desync.l7payload=="wireguard_cookie" and #desync.dis.payload<65506 then
if (desync.l7payload=="wireguard_initiation" or desync.l7payload=="wireguard_response" or desync.l7payload=="wireguard_cookie") and #desync.dis.payload<65506 then
DLOG("wgobfs: encrypting '"..desync.l7payload.."'. size "..#desync.dis.payload)
local key = genkey()
-- in aes-gcm every message require it's own crypto secure random iv

View File

@@ -80,15 +80,15 @@ static bool dom_valid(char *dom)
{
if (!dom || *dom=='.') return false;
for (; *dom; dom++)
if (*dom < 0x20 || (*dom & 0x80) || !(*dom == '.' || *dom == '-' || *dom == '_' || (*dom >= '0' && *dom <= '9') || (*dom >= 'a' && *dom <= 'z') || (*dom >= 'A' && *dom <= 'Z')))
return false;
if (!(*dom == '.' || *dom == '-' || *dom == '_' || (*dom >= '0' && *dom <= '9') || (*dom >= 'a' && *dom <= 'z') || (*dom >= 'A' && *dom <= 'Z')))
return false;
return true;
}
static void invalid_domain_beautify(char *dom)
{
for (int i = 0; *dom && i < 64; i++, dom++)
if (*dom < 0x20 || *dom<0) *dom = '?';
if (*dom < 0x20 || (*dom & 0x80)) *dom = '?';
if (*dom) *dom = 0;
}
@@ -436,7 +436,7 @@ int dns_parse_query()
_setmode(_fileno(stdin), _O_BINARY);
#endif
l = fread(a,1,sizeof(a),stdin);
if (!l || !feof(stdin))
if (!l || ferror(stdin))
{
fprintf(stderr, "could not read DNS reply blob from stdin\n");
return 10;

View File

@@ -1,4 +1,5 @@
CC ?= cc
PKG_CONFIG ?= pkg-config
OPTIMIZE ?= -Os
CFLAGS += -std=gnu99 -s $(OPTIMIZE) -flto=auto -Wno-address-of-packed-member
LIBS = -lz -lm
@@ -26,8 +27,8 @@ OSNAME!=uname
.endif
LUA_LIB!= pkg-config --libs $(LUA_PKG)
LUA_CFLAGS!= pkg-config --cflags $(LUA_PKG)
LUA_LIB!= $(PKG_CONFIG) --libs $(LUA_PKG)
LUA_CFLAGS!= $(PKG_CONFIG) --cflags $(LUA_PKG)
.if "${LUA_JIT}" == "1"
LUA_CFLAGS+=-DLUAJIT

View File

@@ -1,4 +1,5 @@
CC ?= cc
PKG_CONFIG ?= pkg-config
OPTIMIZE ?= -Os
CFLAGS += -std=gnu99 $(OPTIMIZE) -flto=auto
CFLAGS_SYSTEMD = -DUSE_SYSTEMD
@@ -16,7 +17,6 @@ RES_CYGWIN32 = windows/res/32/winmanifest.o windows/res/32/winicon.o
RES_CYGWIN64 = windows/res/64/winmanifest.o windows/res/64/winicon.o
SRC_FILES = *.c crypto/*.c
LUA_JIT?=1
ifeq ($(LUA_JIT),1)
@@ -29,13 +29,13 @@ $(info trying luajit $(LUAJIT_VER) lua $(LUAJIT_LUA_VER))
LUA_LIB_NAME=
ifeq ($(LUA_CFLAGS),)
LUA_CFLAGS := $(shell pkg-config --cflags $(LUA_PKG) 2>/dev/null)
LUA_CFLAGS := $(shell $(PKG_CONFIG) --cflags $(LUA_PKG) 2>/dev/null)
ifeq ($(LUA_CFLAGS),)
LUA_CFLAGS := -I/usr/local/include/luajit-$(LUAJIT_VER) -I/usr/include/luajit-$(LUAJIT_VER)
endif
endif
ifeq ($(LUA_LIB),)
LUA_LIB := $(shell pkg-config --libs $(LUA_PKG) 2>/dev/null)
LUA_LIB := $(shell $(PKG_CONFIG) --libs $(LUA_PKG) 2>/dev/null)
LUA_LIB_DIR :=
ifeq ($(LUA_LIB),)
@@ -87,13 +87,13 @@ else
endif
ifeq ($(LUA_CFLAGS),)
LUA_CFLAGS := $(shell pkg-config --cflags $(LUA_PKG) 2>/dev/null)
LUA_CFLAGS := $(shell $(PKG_CONFIG) --cflags $(LUA_PKG) 2>/dev/null)
ifeq ($(LUA_CFLAGS),)
LUA_CFLAGS := -I/usr/local/include/lua$(LUA_VER) -I/usr/local/include/lua-$(LUA_VER) -I/usr/include/lua$(LUA_VER) -I/usr/include/lua-$(LUA_VER)
endif
endif
ifeq ($(LUA_LIB),)
LUA_LIB := $(shell pkg-config --libs $(LUA_PKG) 2>/dev/null)
LUA_LIB := $(shell $(PKG_CONFIG) --libs $(LUA_PKG) 2>/dev/null)
LUA_LIB_DIR :=
ifeq ($(LUA_LIB),)
ifneq ($(wildcard /usr/local/lib/liblua-$(LUA_VER).*),)

View File

@@ -339,21 +339,28 @@ void proto_skip_udp(const uint8_t **data, size_t *len)
bool proto_check_ipv6(const uint8_t *data, size_t len)
{
return len >= sizeof(struct ip6_hdr) && (data[0] & 0xF0) == 0x60 &&
(len - sizeof(struct ip6_hdr)) >= ntohs(((struct ip6_hdr*)data)->ip6_ctlun.ip6_un1.ip6_un1_plen);
return len >= sizeof(struct ip6_hdr) && (data[0] & 0xF0) == 0x60;
}
bool proto_check_ipv6_payload(const uint8_t *data, size_t len)
{
return len >= (ntohs(((struct ip6_hdr*)data)->ip6_ctlun.ip6_un1.ip6_un1_plen) + sizeof(struct ip6_hdr));
}
// move to transport protocol
// proto_type = 0 => error
void proto_skip_ipv6(const uint8_t **data, size_t *len, uint8_t *proto_type, const uint8_t **last_header_type)
void proto_skip_ipv6(const uint8_t **data, size_t *len, uint8_t *proto_type)
{
size_t hdrlen;
uint8_t HeaderType;
uint16_t plen;
struct ip6_hdr *ip6 = (struct ip6_hdr*)*data;
if (proto_type) *proto_type = 0; // put error in advance
HeaderType = (*data)[6]; // NextHeader field
if (last_header_type) *last_header_type = (*data)+6;
HeaderType = ip6->ip6_nxt;
if (proto_type) *proto_type = HeaderType;
plen = ntohs(ip6->ip6_ctlun.ip6_un1.ip6_un1_plen);
*data += sizeof(struct ip6_hdr); *len -= sizeof(struct ip6_hdr); // skip ipv6 base header
if (plen < *len) *len = plen;
while (*len) // need at least one byte for NextHeader field
{
switch (HeaderType)
@@ -384,7 +391,6 @@ void proto_skip_ipv6(const uint8_t **data, size_t *len, uint8_t *proto_type, con
}
if (*len < hdrlen) return; // error
HeaderType = **data;
if (last_header_type) *last_header_type = *data;
// advance to the next header location
*len -= hdrlen;
*data += hdrlen;
@@ -392,60 +398,18 @@ void proto_skip_ipv6(const uint8_t **data, size_t *len, uint8_t *proto_type, con
// we have garbage
}
bool proto_set_last_ip6_proto(struct ip6_hdr *ip6, size_t len, uint8_t proto)
{
size_t hdrlen;
uint8_t HeaderType, *pproto, *data;
if (len<sizeof(struct ip6_hdr)) return false;
pproto = &ip6->ip6_ctlun.ip6_un1.ip6_un1_nxt;
data = (uint8_t*)(ip6+1);
len -= sizeof(struct ip6_hdr);
while (len) // need at least one byte for NextHeader field
{
switch (*pproto)
{
case IPPROTO_HOPOPTS:
case IPPROTO_ROUTING:
case IPPROTO_DSTOPTS:
case IPPROTO_MH: // mobility header
case IPPROTO_HIP: // Host Identity Protocol Version v2
case IPPROTO_SHIM6:
if (len < 2) return false; // error
hdrlen = 8 + (data[1] << 3);
break;
case IPPROTO_FRAGMENT: // fragment. length fixed to 8, hdrlen field defined as reserved
hdrlen = 8;
break;
case IPPROTO_AH:
// special case. length in ah header is in 32-bit words minus 2
if (len < 2) return false; // error
hdrlen = 8 + (data[1] << 2);
break;
default:
// we found some meaningful payload. it can be tcp, udp, icmp or some another exotic shit
*pproto = proto;
return true;
}
if (len < hdrlen) return false; // error
pproto = data;
len -= hdrlen; data += hdrlen;
}
*pproto = proto;
return true;
}
uint8_t *proto_find_ip6_exthdr(struct ip6_hdr *ip6, size_t len, uint8_t proto)
{
size_t hdrlen;
uint8_t HeaderType, last_proto, *data;
uint16_t plen;
if (len<sizeof(struct ip6_hdr)) return false;
plen = ntohs(ip6->ip6_ctlun.ip6_un1.ip6_un1_plen);
last_proto = ip6->ip6_ctlun.ip6_un1.ip6_un1_nxt;
data = (uint8_t*)(ip6+1);
len -= sizeof(struct ip6_hdr);
if (plen < len) len = plen;
while (len) // need at least one byte for NextHeader field
{
if (last_proto==proto) return data; // found
@@ -498,11 +462,11 @@ void proto_dissect_l3l4(const uint8_t *data, size_t len, struct dissect *dis)
proto_skip_ipv4(&data, &len);
dis->len_l3 = data-p;
}
else if (proto_check_ipv6(data, len))
else if (proto_check_ipv6(data, len) && proto_check_ipv6_payload(data, len))
{
dis->ip6 = (const struct ip6_hdr *) data;
p = data;
proto_skip_ipv6(&data, &len, &dis->proto, NULL);
proto_skip_ipv6(&data, &len, &dis->proto);
dis->len_l3 = data-p;
}
else
@@ -2063,7 +2027,7 @@ bool make_writeable_dir()
char testfile[PATH_MAX];
snprintf(testfile,sizeof(testfile),"%s/test_XXXXXX",wrdir);
int fd = mkstemp(testfile);
if (fd>0)
if (fd>=0)
{
close(fd);
unlink(testfile);

View File

@@ -135,8 +135,8 @@ void str_udphdr(char *s, size_t s_len, const struct udphdr *udphdr);
bool proto_check_ipv4(const uint8_t *data, size_t len);
void proto_skip_ipv4(const uint8_t **data, size_t *len);
bool proto_check_ipv6(const uint8_t *data, size_t len);
void proto_skip_ipv6(const uint8_t **data, size_t *len, uint8_t *proto_type, const uint8_t **last_header_type);
bool proto_set_last_ip6_proto(struct ip6_hdr *ip6, size_t len, uint8_t proto);
bool proto_check_ipv6_payload(const uint8_t *data, size_t len);
void proto_skip_ipv6(const uint8_t **data, size_t *len, uint8_t *proto_type);
uint8_t *proto_find_ip6_exthdr(struct ip6_hdr *ip6, size_t len, uint8_t proto);
bool proto_check_tcp(const uint8_t *data, size_t len);
void proto_skip_tcp(const uint8_t **data, size_t *len);

View File

@@ -425,17 +425,6 @@ static bool send_delayed(t_ctrack *ctrack)
return true;
}
static bool rawpacket_queue_csum_fix(struct rawpacket_tailhead *q, const struct dissect *dis, const t_ctrack_positions *tpos, const struct sockaddr_storage* dst, uint32_t fwmark, uint32_t desync_fwmark, const char *ifin, const char *ifout)
{
// this breaks const pointer to l4 header
if (dis->tcp)
verdict_tcp_csum_fix(VERDICT_PASS, (struct tcphdr *)dis->tcp, dis->transport_len, dis->ip, dis->ip6);
else if (dis->udp)
verdict_udp_csum_fix(VERDICT_PASS, (struct udphdr *)dis->udp, dis->transport_len, dis->ip, dis->ip6);
return rawpacket_queue(q, dst, fwmark, desync_fwmark, ifin, ifout, dis->data_pkt, dis->len_pkt, dis->len_payload, tpos);
}
static bool reasm_start(t_ctrack *ctrack, t_reassemble *reasm, uint8_t proto, uint32_t seq, size_t sz, size_t szMax, const uint8_t *data_payload, size_t len_payload)
{
ReasmClear(reasm);
@@ -870,9 +859,11 @@ static uint8_t desync(
if (dis->tcp)
{
// recommended mss value for generated packets
if (rpos && rpos->mss)
lua_pushf_int(params.L, "tcp_mss", rpos->mss);
if (pos && pos->mss && rpos && rpos->mss)
// use minimum MSS of two ends or can fail with "message too long"
lua_pushf_int(params.L, "tcp_mss", rpos->mss > pos->mss ? pos->mss : rpos->mss);
else
// this value should always work
lua_pushf_global(params.L, "tcp_mss", "DEFAULT_MSS");
}
ref_arg = luaL_ref(params.L, LUA_REGISTRYINDEX);
@@ -1163,7 +1154,7 @@ static uint8_t dpi_desync_tcp_packet_play(
return verdict;
}
HostFailPoolPurgeRateLimited(&dp->hostlist_auto_fail_counters);
HostFailPoolPurgeRateLimited(&dp->hostlist_auto_fail_counters, &dp->hostlist_auto_last_purge);
//ConntrackPoolDump(&params.conntrack);
@@ -1335,7 +1326,7 @@ static uint8_t dpi_desync_tcp_packet_play(
if (!ReasmIsEmpty(&ctrack->reasm_client))
{
if (rawpacket_queue_csum_fix(&ctrack->delayed, dis, &ctrack->pos, &dst, fwmark, desync_fwmark, ifin, ifout))
if (rawpacket_queue(&ctrack->delayed, &dst, fwmark, desync_fwmark, ifin, ifout, dis->data_pkt, dis->len_pkt, dis->len_payload, &ctrack->pos))
{
DLOG("DELAY desync until reasm is complete (#%u)\n", rawpacket_queue_count(&ctrack->delayed));
}
@@ -1699,7 +1690,7 @@ static uint8_t dpi_desync_udp_packet_play(
return verdict;
}
HostFailPoolPurgeRateLimited(&dp->hostlist_auto_fail_counters);
HostFailPoolPurgeRateLimited(&dp->hostlist_auto_fail_counters, &dp->hostlist_auto_last_purge);
//ConntrackPoolDump(&params.conntrack);
if (bReverseFixed)
@@ -1793,7 +1784,7 @@ static uint8_t dpi_desync_udp_packet_play(
}
if (!ReasmIsEmpty(&ctrack->reasm_client))
{
if (rawpacket_queue_csum_fix(&ctrack->delayed, dis, &ctrack->pos, &dst, fwmark, desync_fwmark, ifin, ifout))
if (rawpacket_queue(&ctrack->delayed, &dst, fwmark, desync_fwmark, ifin, ifout, dis->data_pkt, dis->len_pkt, dis->len_payload, &ctrack->pos))
{
DLOG("DELAY desync until reasm is complete (#%u)\n", rawpacket_queue_count(&ctrack->delayed));
}
@@ -1833,7 +1824,7 @@ static uint8_t dpi_desync_udp_packet_play(
if (!reasm_client_start(ctrack, IPPROTO_UDP, UDP_MAX_REASM, UDP_MAX_REASM, clean, clean_len))
goto pass_reasm_cancel;
}
if (rawpacket_queue_csum_fix(&ctrack->delayed, dis, &ctrack->pos, &dst, fwmark, desync_fwmark, ifin, ifout))
if (rawpacket_queue(&ctrack->delayed, &dst, fwmark, desync_fwmark, ifin, ifout, dis->data_pkt, dis->len_pkt, dis->len_payload, &ctrack->pos))
{
DLOG("DELAY desync until reasm is complete (#%u)\n", rawpacket_queue_count(&ctrack->delayed));
}
@@ -2024,6 +2015,8 @@ static uint8_t dpi_desync_packet_play(
struct dissect dis;
uint8_t verdict = VERDICT_PASS;
// NOTE ! OS can pass wrong checksum to queue. cannot rely on it !
proto_dissect_l3l4(data_pkt, len_pkt, &dis);
if (!!dis.ip != !!dis.ip6)
{
@@ -2034,16 +2027,20 @@ static uint8_t dpi_desync_packet_play(
if (dis.tcp)
{
verdict = dpi_desync_tcp_packet_play(replay_piece, replay_piece_count, reasm_offset, fwmark, ifin, ifout, tpos, &dis, mod_pkt, len_mod_pkt);
// we fix csum before pushing to replay queue
if (!replay_piece_count) verdict_tcp_csum_fix(verdict, (struct tcphdr *)dis.tcp, dis.transport_len, dis.ip, dis.ip6);
// fix csum if unmodified and if OS can pass wrong csum to queue (depends on OS)
// modified means we have already fixed the checksum or made it invalid intentionally
// this is the only point we VIOLATE const to fix the checksum in the original buffer to avoid copying to mod_pkt
verdict_tcp_csum_fix(verdict, (struct tcphdr *)dis.tcp, dis.transport_len, dis.ip, dis.ip6);
}
break;
case IPPROTO_UDP:
if (dis.udp)
{
verdict = dpi_desync_udp_packet_play(replay_piece, replay_piece_count, reasm_offset, fwmark, ifin, ifout, tpos, &dis, mod_pkt, len_mod_pkt);
// we fix csum before pushing to replay queue
if (!replay_piece_count) verdict_udp_csum_fix(verdict, (struct udphdr *)dis.udp, dis.transport_len, dis.ip, dis.ip6);
// fix csum if unmodified and if OS can pass wrong csum to queue (depends on OS)
// modified means we have already fixed the checksum or made it invalid intentionally
// this is the only point we VIOLATE const to fix the checksum in the original buffer to avoid copying to mod_pkt
verdict_udp_csum_fix(verdict, (struct udphdr *)dis.udp, dis.transport_len, dis.ip, dis.ip6);
}
break;
}
@@ -2052,6 +2049,8 @@ static uint8_t dpi_desync_packet_play(
}
uint8_t dpi_desync_packet(uint32_t fwmark, const char *ifin, const char *ifout, const uint8_t *data_pkt, size_t len_pkt, uint8_t *mod_pkt, size_t *len_mod_pkt)
{
// NOTE ! OS can pass wrong checksum to queue. cannot rely on it !
ipcachePurgeRateLimited(&params.ipcache, params.ipcache_lifetime);
return dpi_desync_packet_play(0, 0, 0, fwmark, ifin, ifout, NULL, data_pkt, len_pkt, mod_pkt, len_mod_pkt);
}

View File

@@ -599,14 +599,14 @@ bool packet_range_parse(const char *s, struct packet_range *range)
void fill_random_bytes(uint8_t *p,size_t sz)
{
size_t k,sz16 = sz>>1;
for(k=0;k<sz16;k++) ((uint16_t*)p)[k]=(uint16_t)random();
size_t k;
for (k=0 ; (k+1)<sz ; k+=2) phton16(p+k, (uint16_t)random());
if (sz & 1) p[sz-1]=(uint8_t)random();
}
void fill_random_az(uint8_t *p,size_t sz)
{
size_t k;
for(k=0;k<sz;k++) p[k] = 'a'+(random() % ('z'-'a'));
for(k=0;k<sz;k++) p[k] = 'a'+(random() % ('z'-'a'+1));
}
void fill_random_az09(uint8_t *p,size_t sz)
{

View File

@@ -71,16 +71,20 @@ static int luacall_bitlshift(lua_State *L)
{
lua_check_argc(L,"bitlshift",2);
int64_t v=(int64_t)luaL_checklint(L,1);
if (v>0xFFFFFFFFFFFF || v<-(int64_t)0xFFFFFFFFFFFF) luaL_error(L, "out of range");
lua_pushlint(L,(((uint64_t)v) << luaL_checkinteger(L,2)) & 0xFFFFFFFFFFFF);
lua_Integer shift = luaL_checkinteger(L,2);
if (shift>48 || shift<0 || v>0xFFFFFFFFFFFF || v<-(int64_t)0xFFFFFFFFFFFF) luaL_error(L, "out of range");
uint64_t u = v & 0xFFFFFFFFFFFF;
lua_pushlint(L,(u << shift) & 0xFFFFFFFFFFFF);
return 1;
}
static int luacall_bitrshift(lua_State *L)
{
lua_check_argc(L,"bitrshift",2);
int64_t v=(int64_t)luaL_checklint(L,1);
if (v>0xFFFFFFFFFFFF || v<-(int64_t)0xFFFFFFFFFFFF) luaL_error(L, "out of range");
lua_pushlint(L,((uint64_t)v) >> luaL_checkinteger(L,2));
lua_Integer shift = luaL_checkinteger(L,2);
if (shift>48 || shift<0 || v>0xFFFFFFFFFFFF || v<-(int64_t)0xFFFFFFFFFFFF) luaL_error(L, "out of range");
uint64_t u = v & 0xFFFFFFFFFFFF;
lua_pushlint(L,u >> shift);
return 1;
}
static int luacall_bitand(lua_State *L)
@@ -93,7 +97,7 @@ static int luacall_bitand(lua_State *L)
{
v=(int64_t)luaL_checklint(L,i);
if (v>0xFFFFFFFFFFFF || v<-(int64_t)0xFFFFFFFFFFFF) luaL_error(L, "out of range");
sum&=(uint64_t)v;
sum &= (uint64_t)v;
}
lua_pushlint(L,sum);
return 1;
@@ -108,7 +112,22 @@ static int luacall_bitor(lua_State *L)
{
v=(int64_t)luaL_checklint(L,i);
if (v>0xFFFFFFFFFFFF || v<-(int64_t)0xFFFFFFFFFFFF) luaL_error(L, "out of range");
sum|=(uint64_t)v;
sum |= (uint64_t)(v & 0xFFFFFFFFFFFF);
}
lua_pushlint(L,sum);
return 1;
}
static int luacall_bitxor(lua_State *L)
{
lua_check_argc_range(L,"bitxor",1,100);
int argc = lua_gettop(L);
int64_t v;
uint64_t sum=0;
for(int i=1;i<=argc;i++)
{
v=(int64_t)luaL_checklint(L,i);
if (v>0xFFFFFFFFFFFF || v<-(int64_t)0xFFFFFFFFFFFF) luaL_error(L, "out of range");
sum ^= (uint64_t)(v & 0xFFFFFFFFFFFF);
}
lua_pushlint(L,sum);
return 1;
@@ -146,21 +165,6 @@ static int luacall_bitnot48(lua_State *L)
lua_check_argc(L,"bitnot48",1);
return lua_bitnotx(L, 0xFFFFFFFFFFFF);
}
static int luacall_bitxor(lua_State *L)
{
lua_check_argc_range(L,"bitxor",1,100);
int argc = lua_gettop(L);
int64_t v;
uint64_t sum=0;
for(int i=1;i<=argc;i++)
{
v=(int64_t)luaL_checklint(L,i);
if (v>0xFFFFFFFFFFFF || v<-(int64_t)0xFFFFFFFFFFFF) luaL_error(L, "out of range");
sum^=(uint64_t)v;
}
lua_pushlint(L,sum);
return 1;
}
static int luacall_bitget(lua_State *L)
{
lua_check_argc(L,"bitget",3);
@@ -170,10 +174,10 @@ static int luacall_bitget(lua_State *L)
uint64_t what = (uint64_t)iwhat;
lua_Integer from = luaL_checkinteger(L,2);
lua_Integer to = luaL_checkinteger(L,3);
if (from>to || from>47 || to>47)
if (from<0 || to<0 || from>to || from>47 || to>47)
luaL_error(L, "bit range invalid");
what = (what >> from) & ~((lua_Integer)-1 << (to-from+1));
what = (what >> from) & ~((uint64_t)-1 << (to-from+1));
lua_pushlint(L,what);
return 1;
@@ -190,7 +194,7 @@ static int luacall_bitset(lua_State *L)
int64_t iset = (int64_t)luaL_checklint(L,4);
if (iset>0xFFFFFFFFFFFF || iset<-(int64_t)0xFFFFFFFFFFFF) luaL_error(L, "out of range");
uint64_t set = (uint64_t)iset;
if (from>to || from>47 || to>47)
if (from<0 || to<0 || from>to || from>47 || to>47)
luaL_error(L, "bit range invalid");
uint64_t mask = ~((uint64_t)-1 << (to-from+1));
@@ -423,7 +427,7 @@ static int luacall_brandom(lua_State *L)
{
lua_check_argc(L,"brandom",1);
lua_Integer len = luaL_checkinteger(L,1);
if (len<0) luaL_error(L, "brandom: invalid arg");
uint8_t *p = malloc(len);
if (!p) luaL_error(L, "out of memory");
fill_random_bytes(p,len);
@@ -436,7 +440,7 @@ static int luacall_brandom_az(lua_State *L)
{
lua_check_argc(L,"brandom_az",1);
lua_Integer len = luaL_checkinteger(L,1);
if (len<0) luaL_error(L, "brandom_az: invalid arg");
uint8_t *p = malloc(len);
if (!p) luaL_error(L, "out of memory");
fill_random_az(p,len);
@@ -449,7 +453,7 @@ static int luacall_brandom_az09(lua_State *L)
{
lua_check_argc(L,"brandom_az09",1);
lua_Integer len = luaL_checkinteger(L,1);
if (len<0) luaL_error(L, "brandom_az09: invalid arg");
uint8_t *p = malloc(len);
if (!p) luaL_error(L, "out of memory");
fill_random_az09(p,len);
@@ -461,6 +465,7 @@ static int luacall_brandom_az09(lua_State *L)
// hacky function. breaks immutable string behavior.
// if you change a string, it will change in all variables that hold the same string
/*
static int luacall_memcpy(lua_State *L)
{
// memcpy(to,to_offset,from,from_offset,size)
@@ -481,7 +486,7 @@ static int luacall_memcpy(lua_State *L)
memcpy(to+off_to,from+off_from,size);
return 0;
}
*/
static int luacall_parse_hex(lua_State *L)
{
@@ -531,6 +536,7 @@ static int luacall_bcryptorandom(lua_State *L)
LUA_STACK_GUARD_ENTER(L)
lua_Integer len = luaL_checkinteger(L,1);
if (len<0) luaL_error(L, "bcryptorandom: invalid arg");
uint8_t *p = malloc(len);
if (!p) luaL_error(L, "out of memory");
@@ -686,7 +692,8 @@ static int luacall_hkdf(lua_State *L)
const uint8_t *ikm = lua_type(L,3) == LUA_TNIL ? NULL : (uint8_t*)luaL_checklstring(L,3,&ikm_len);
size_t info_len=0;
const uint8_t *info = lua_type(L,4) == LUA_TNIL ? NULL : (uint8_t*)luaL_checklstring(L,4,&info_len);
size_t okm_len = (size_t)luaL_checkinteger(L,5);
lua_Integer okm_len = luaL_checkinteger(L,5);
if (okm_len<0) luaL_error(L, "hkdf: invalid arg");
uint8_t *okm = malloc(okm_len);
if (!okm) luaL_error(L, "out of memory");
@@ -950,7 +957,7 @@ static int luacall_execution_plan(lua_State *L)
lua_pushf_args(L,&func->args, -1, false);
lua_pushf_str(L,"func", func->func);
lua_pushf_int(L,"func_n", ctx->func_n);
lua_pushf_int(L,"func_n", n);
lua_pushf_str(L,"func_instance", instance);
lua_pushf_range(L,"range", range);
@@ -1179,7 +1186,7 @@ void lua_pushf_tcphdr_options(lua_State *L, const struct tcphdr *tcp, size_t len
uint8_t *t = (uint8_t*)(tcp+1);
uint8_t *end = (uint8_t*)tcp + (tcp->th_off<<2);
uint8_t opt;
if ((end-(uint8_t*)tcp) < len) end=(uint8_t*)tcp + len;
if ((end-(uint8_t*)tcp) > len) end=(uint8_t*)tcp + len;
lua_Integer idx=1;
while(t<end)
{
@@ -1263,7 +1270,7 @@ void lua_pushf_iphdr(lua_State *L, const struct ip *ip, size_t len)
if (ip && len>=sizeof(struct ip))
{
uint16_t hl = ip->ip_hl<<2;
bool b_has_opt = hl>sizeof(struct tcphdr) && hl<=len;
bool b_has_opt = hl>sizeof(struct ip) && hl<=len;
lua_createtable(L, 0, 11+b_has_opt);
lua_pushf_int(L,"ip_v",ip->ip_v);
lua_pushf_int(L,"ip_hl",ip->ip_hl);
@@ -1273,11 +1280,11 @@ void lua_pushf_iphdr(lua_State *L, const struct ip *ip, size_t len)
lua_pushf_int(L,"ip_off",ntohs(ip->ip_off));
lua_pushf_int(L,"ip_ttl",ip->ip_ttl);
lua_pushf_int(L,"ip_p",ip->ip_p);
lua_pushf_int(L,"ip_sum",ip->ip_sum);
lua_pushf_int(L,"ip_sum",ntohs(ip->ip_sum));
lua_pushf_raw(L,"ip_src",&ip->ip_src,sizeof(struct in_addr));
lua_pushf_raw(L,"ip_dst",&ip->ip_dst,sizeof(struct in_addr));
if (b_has_opt)
lua_pushf_raw(L,"options",(uint8_t*)(ip+1),hl-sizeof(struct tcphdr));
lua_pushf_raw(L,"options",(uint8_t*)(ip+1),hl-sizeof(struct ip));
}
else
lua_pushnil(L);
@@ -1292,6 +1299,7 @@ void lua_pushf_ip6exthdr(lua_State *L, const struct ip6_hdr *ip6, size_t len)
// assume ipv6 packet structure was already checked for validity
size_t hdrlen;
uint8_t HeaderType, *data;
uint16_t plen;
lua_Integer idx = 1;
lua_pushliteral(L, "exthdr");
@@ -1301,6 +1309,8 @@ void lua_pushf_ip6exthdr(lua_State *L, const struct ip6_hdr *ip6, size_t len)
HeaderType = ip6->ip6_ctlun.ip6_un1.ip6_un1_nxt;
data=(uint8_t*)(ip6+1);
len-=sizeof(struct ip6_hdr);
plen = ntohs(ip6->ip6_ctlun.ip6_un1.ip6_un1_plen);
if (plen < len) len = plen;
while (len > 0) // need at least one byte for NextHeader field
{
switch (HeaderType)
@@ -1432,11 +1442,11 @@ void lua_pushf_ctrack(lua_State *L, const t_ctrack *ctrack, const t_ctrack_posit
{
LUA_STACK_GUARD_ENTER(L)
if (!tpos) tpos = &ctrack->pos;
lua_pushliteral(L, "track");
if (ctrack)
{
if (!tpos) tpos = &ctrack->pos;
lua_createtable(L, 0, 9);
if (ctrack->incoming_ttl)
@@ -1449,7 +1459,7 @@ void lua_pushf_ctrack(lua_State *L, const t_ctrack *ctrack, const t_ctrack_posit
lua_pushf_reg(L, "lua_state", ctrack->lua_state);
lua_pushf_bool(L, "lua_in_cutoff", ctrack->b_lua_in_cutoff);
lua_pushf_bool(L, "lua_out_cutoff", ctrack->b_lua_out_cutoff);
lua_pushf_lint(L, "t_start", (lua_Number)ctrack->t_start.tv_sec + ctrack->t_start.tv_nsec/1000000000.);
lua_pushf_number(L, "t_start", (lua_Number)ctrack->t_start.tv_sec + ctrack->t_start.tv_nsec/1000000000.);
lua_pushliteral(L, "pos");
lua_createtable(L, 0, 5);
@@ -1553,7 +1563,7 @@ void lua_pushf_range(lua_State *L, const char *name, const struct packet_range *
LUA_STACK_GUARD_ENTER(L)
lua_pushf_table(L, name);
lua_getfield(L, -1, "range");
lua_getfield(L, -1, name);
lua_pushf_bool(L, "upper_cutoff",range->upper_cutoff);
lua_pushf_pos(L, "from", &range->from);
lua_pushf_pos(L, "to", &range->to);
@@ -1599,12 +1609,11 @@ static void lua_reconstruct_extract_options(lua_State *L, int idx, bool *badsum,
static bool lua_reconstruct_ip6exthdr(lua_State *L, int idx, struct ip6_hdr *ip6, size_t *len, uint8_t proto, bool preserve_next)
{
LUA_STACK_GUARD_ENTER(L)
// proto = last header type
if (*len<sizeof(struct tcphdr)) return false;
uint8_t *last_proto = &ip6->ip6_ctlun.ip6_un1.ip6_un1_nxt;
uint8_t filled = sizeof(struct ip6_hdr);
size_t filled = sizeof(struct ip6_hdr);
lua_getfield(L,idx,"exthdr");
if (lua_type(L,-1)==LUA_TTABLE)
{
@@ -1624,10 +1633,10 @@ static bool lua_reconstruct_ip6exthdr(lua_State *L, int idx, struct ip6_hdr *ip6
}
else
{
if (lua_type(L,-1)!=LUA_TTABLE) goto err2;
if (lua_type(L,-1)!=LUA_TTABLE) goto err;
lua_getfield(L,-1, "type");
if (lua_type(L,-1)!=LUA_TNUMBER) goto err3;
if (lua_type(L,-1)!=LUA_TNUMBER) goto err;
type = (uint8_t)lua_tointeger(L,-1);
lua_pop(L, 1);
@@ -1636,9 +1645,9 @@ static bool lua_reconstruct_ip6exthdr(lua_State *L, int idx, struct ip6_hdr *ip6
lua_pop(L, 1);
lua_getfield(L,-1, "data");
if (lua_type(L,-1)!=LUA_TSTRING) goto err3;
p=(uint8_t*)lua_tolstring(L,-1,&l);
if (!l || (l+2)>left || ((type==IPPROTO_AH) ? (l<6 || ((l+2) & 3)) : ((l+2) & 7))) goto err3;
if (lua_type(L,-1)!=LUA_TSTRING) goto err;
if (!(p=(uint8_t*)lua_tolstring(L,-1,&l))) l=0;
if (!l || (l+2)>left || ((type==IPPROTO_AH) ? (l<6 || ((l+2) & 3)) : ((l+2) & 7))) goto err;
memcpy(data+2,p,l);
l+=2;
data[0] = next; // may be overwritten later
@@ -1657,13 +1666,8 @@ static bool lua_reconstruct_ip6exthdr(lua_State *L, int idx, struct ip6_hdr *ip6
lua_pop(L, 1);
LUA_STACK_GUARD_LEAVE(L, 0)
return true;
err2:
lua_pop(L, 2);
goto err;
err3:
lua_pop(L, 3);
err:
LUA_STACK_GUARD_LEAVE(L, 0)
LUA_STACK_GUARD_UNWIND(L)
return false;
}
bool lua_reconstruct_ip6hdr(lua_State *L, int idx, struct ip6_hdr *ip6, size_t *len, uint8_t last_proto, bool preserve_next)
@@ -1696,17 +1700,20 @@ bool lua_reconstruct_ip6hdr(lua_State *L, int idx, struct ip6_hdr *ip6, size_t *
lua_getfield(L,idx,"ip6_src");
if (lua_type(L,-1)!=LUA_TSTRING) goto err;
p = lua_tolstring(L,-1,&l);
if (l!=sizeof(struct in6_addr)) goto err;
if (!p || l!=sizeof(struct in6_addr)) goto err;
ip6->ip6_src = *(struct in6_addr*)p;
lua_pop(L, 1);
lua_getfield(L,idx,"ip6_dst");
if (lua_type(L,-1)!=LUA_TSTRING) goto err;
p = lua_tolstring(L,-1,&l);
if (l!=sizeof(struct in6_addr)) goto err;
if (!p || l!=sizeof(struct in6_addr)) goto err;
ip6->ip6_dst = *(struct in6_addr*)p;
lua_pop(L, 1);
return lua_reconstruct_ip6exthdr(L, idx, ip6, len, last_proto, preserve_next);
bool b = lua_reconstruct_ip6exthdr(L, idx, ip6, len, last_proto, preserve_next);
LUA_STACK_GUARD_LEAVE(L, 0)
return b;
err:
lua_pop(L, 1);
@@ -1774,14 +1781,14 @@ bool lua_reconstruct_iphdr(lua_State *L, int idx, struct ip *ip, size_t *len)
lua_getfield(L,idx,"ip_src");
if (lua_type(L,-1)!=LUA_TSTRING) goto err;
p = lua_tolstring(L,-1,&l);
if (l!=sizeof(struct in_addr)) goto err;
if (!p || l!=sizeof(struct in_addr)) goto err;
ip->ip_src = *(struct in_addr*)p;
lua_pop(L, 1);
lua_getfield(L,idx,"ip_dst");
if (lua_type(L,-1)!=LUA_TSTRING) goto err;
p = lua_tolstring(L,-1,&l);
if (l!=sizeof(struct in_addr)) goto err;
if (!p || l!=sizeof(struct in_addr)) goto err;
ip->ip_dst = *(struct in_addr*)p;
lua_pop(L, 1);
@@ -1857,10 +1864,10 @@ static bool lua_reconstruct_tcphdr_options(lua_State *L, int idx, struct tcphdr
{
// uses 'key' (at index -2) and 'value' (at index -1)
if (!left || lua_type(L,-1)!=LUA_TTABLE) goto err2;
if (!left || lua_type(L,-1)!=LUA_TTABLE) goto err;
lua_getfield(L,-1, "kind");
if (lua_type(L,-1)!=LUA_TNUMBER) goto err3;
if (lua_type(L,-1)!=LUA_TNUMBER) goto err;
kind = (uint8_t)lua_tointeger(L,-1);
lua_pop(L, 1);
@@ -1878,7 +1885,7 @@ static bool lua_reconstruct_tcphdr_options(lua_State *L, int idx, struct tcphdr
lua_getfield(L,-1, "data");
l = 0;
p = lua_type(L,-1)==LUA_TSTRING ? (uint8_t*)lua_tolstring(L,-1,&l) : NULL;
if ((2+l)>left) goto err3;
if ((2+l)>left) goto err;
if (p) memcpy(data+2,p,l);
l+=2;
data[0] = kind;
@@ -1894,7 +1901,7 @@ static bool lua_reconstruct_tcphdr_options(lua_State *L, int idx, struct tcphdr
end:
while(filled & 3)
{
if (!left) goto err1;
if (!left) goto err;
*data = TCP_KIND_NOOP; data++; left--; filled++;
}
}
@@ -1905,16 +1912,8 @@ end:
lua_pop(L, 1);
LUA_STACK_GUARD_LEAVE(L, 0)
return true;
err1:
lua_pop(L, 1);
goto err;
err2:
lua_pop(L, 2);
goto err;
err3:
lua_pop(L, 3);
err:
LUA_STACK_GUARD_LEAVE(L, 0)
LUA_STACK_GUARD_UNWIND(L)
return false;
}
bool lua_reconstruct_tcphdr(lua_State *L, int idx, struct tcphdr *tcp, size_t *len)
@@ -1969,8 +1968,9 @@ bool lua_reconstruct_tcphdr(lua_State *L, int idx, struct tcphdr *tcp, size_t *l
tcp->th_off = 5;
bool b = lua_reconstruct_tcphdr_options(L, idx, tcp, len);
LUA_STACK_GUARD_LEAVE(L, 0)
return lua_reconstruct_tcphdr_options(L, idx, tcp, len);
return b;
err:
lua_pop(L, 1);
LUA_STACK_GUARD_LEAVE(L, 0)
@@ -2121,12 +2121,14 @@ bool lua_reconstruct_dissect(lua_State *L, int idx, uint8_t *buf, size_t *len, b
lua_getfield(L,idx,"payload");
p = lua_tolstring(L,-1,&lpayload);
if (p && lpayload)
if (p)
{
if (left<lpayload) goto err;
memcpy(data,p,lpayload);
data+=lpayload; left-=lpayload;
}
else
lpayload = 0;
lua_pop(L, 1);
l = data-buf;
@@ -2200,8 +2202,7 @@ bool lua_reconstruct_dissect(lua_State *L, int idx, uint8_t *buf, size_t *len, b
LUA_STACK_GUARD_LEAVE(L, 0)
return true;
err:
lua_pop(L, 1);
LUA_STACK_GUARD_LEAVE(L, 0)
LUA_STACK_GUARD_UNWIND(L)
return false;
}
static int luacall_reconstruct_dissect(lua_State *L)
@@ -2212,7 +2213,7 @@ static int luacall_reconstruct_dissect(lua_State *L)
LUA_STACK_GUARD_ENTER(L)
size_t l;
uint8_t buf[RECONSTRUCT_MAX_SIZE];
uint8_t buf[RECONSTRUCT_MAX_SIZE] __attribute__((aligned(16)));
l = sizeof(buf);
bool ip6_preserve_next, badsum;
@@ -2277,7 +2278,7 @@ static int luacall_csum_tcp_fix(lua_State *L)
if (proto_check_ipv4(b_ip, l_ip))
ip = (struct ip*)b_ip;
else if (proto_check_ipv6(b_ip, sizeof(struct ip6_hdr) + ntohs(((struct ip6_hdr*)b_ip)->ip6_ctlun.ip6_un1.ip6_un1_plen)))
else if (proto_check_ipv6(b_ip, l_ip))
ip6 = (struct ip6_hdr*)b_ip;
else
luaL_error(L, "invalid ip header");
@@ -2318,7 +2319,7 @@ static int luacall_csum_udp_fix(lua_State *L)
if (proto_check_ipv4(b_ip, l_ip))
ip = (struct ip*)b_ip;
else if (proto_check_ipv6(b_ip, sizeof(struct ip6_hdr) + ntohs(((struct ip6_hdr*)b_ip)->ip6_ctlun.ip6_un1.ip6_un1_plen)))
else if (proto_check_ipv6(b_ip, l_ip))
ip6 = (struct ip6_hdr*)b_ip;
else
luaL_error(L, "invalid ip header");
@@ -2412,6 +2413,7 @@ static void lua_rawsend_extract_options(lua_State *L, int idx, int *repeats, uin
{
lua_getfield(L,idx,"repeats");
*repeats=(int)lua_tointeger(L,-1);
if (*repeats<0) luaL_error(L, "rawsend: negative repeats");
if (!*repeats) *repeats=1;
lua_pop(L,1);
}
@@ -2471,7 +2473,7 @@ static int luacall_rawsend_dissect(lua_State *L)
uint32_t fwmark;
sockaddr_in46 sa;
bool b, badsum, ip6_preserve_next;
uint8_t buf[RECONSTRUCT_MAX_SIZE];
uint8_t buf[RECONSTRUCT_MAX_SIZE] __attribute__((aligned(16)));
len = sizeof(buf);
luaL_checktype(L,1,LUA_TTABLE);
@@ -3260,7 +3262,7 @@ static void lua_init_const(void)
{"IPTOS_ECN_ECT1",IPTOS_ECN_ECT1},
{"IPTOS_ECN_ECT0",IPTOS_ECN_ECT0},
{"IPTOS_ECN_CE",IPTOS_ECN_CE},
{"IPTOS_DSCP_MASK",0xF0},
{"IPTOS_DSCP_MASK",0xFC},
{"IP6F_MORE_FRAG",0x0001}, // in ip6.h it's defined depending of machine byte order
{"IPV6_FLOWLABEL_MASK",0x000FFFFF},
{"IPV6_FLOWINFO_MASK",0x0FFFFFFF},
@@ -3377,7 +3379,7 @@ static void lua_init_functions(void)
{"divint",luacall_divint},
// hacky function, write to immutable strings
{"memcpy",luacall_memcpy},
//{"memcpy",luacall_memcpy},
// random blob generation
{"brandom",luacall_brandom},

View File

@@ -38,7 +38,7 @@
#define LUA_STACK_GUARD_ENTER(L) int _lsg=lua_gettop(L);
#define LUA_STACK_GUARD_LEAVE(L,N) if ((_lsg+N)!=lua_gettop(L)) luaL_error(L,"stack guard failure");
#define LUA_STACK_GUARD_RETURN(L,N) LUA_STACK_GUARD_LEAVE(L,N); return N;
#define LUA_STACK_GUARD_UNWIND(L) lua_settop(L,_lsg);
void desync_instance(const char *func, unsigned int dp_n, unsigned int func_n, char *instance, size_t inst_size);

View File

@@ -56,6 +56,8 @@ bool bQuit = false;
static void onhup(int sig)
{
if (bQuit) return;
const char *msg = "HUP received ! Lists will be reloaded.\n";
size_t wr = write(1, msg, strlen(msg));
bReload = true;
@@ -82,12 +84,16 @@ static void ReloadCheck()
static void onusr1(int sig)
{
if (bQuit) return;
printf("\nCONNTRACK DUMP\n");
ConntrackPoolDump(&params.conntrack);
printf("\n");
}
static void onusr2(int sig)
{
if (bQuit) return;
printf("\nHOSTFAIL POOL DUMP\n");
struct desync_profile_list *dpl;
@@ -102,12 +108,16 @@ static void onusr2(int sig)
}
static void onint(int sig)
{
if (bQuit) return;
const char *msg = "INT received !\n";
size_t wr = write(1, msg, strlen(msg));
bQuit = true;
}
static void onterm(int sig)
{
if (bQuit) return;
const char *msg = "TERM received !\n";
size_t wr = write(1, msg, strlen(msg));
bQuit = true;
@@ -181,7 +191,7 @@ static int nfq_cb(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, struct nfq_da
char ifout[IFNAMSIZ], ifin[IFNAMSIZ];
size_t modlen;
uint32_t mark;
uint8_t mod[RECONSTRUCT_MAX_SIZE];
uint8_t mod[RECONSTRUCT_MAX_SIZE] __attribute__((aligned(16)));
ph = nfq_get_msg_packet_hdr(nfa);
id = ph ? ntohl(ph->packet_id) : 0;
@@ -311,7 +321,7 @@ static int nfq_main(void)
int res, fd, e;
ssize_t rd;
FILE *Fpid = NULL;
uint8_t buf[RECONSTRUCT_MAX_SIZE] __attribute__((aligned));
uint8_t buf[RECONSTRUCT_MAX_SIZE] __attribute__((aligned(16)));
if (*params.pidfile && !(Fpid = fopen(params.pidfile, "w")))
{
@@ -625,7 +635,7 @@ static int win_main()
WINDIVERT_ADDRESS wa;
char ifname[IFNAMSIZ];
int res=0;
uint8_t packet[RECONSTRUCT_MAX_SIZE];
uint8_t packet[RECONSTRUCT_MAX_SIZE] __attribute__((aligned(16)));
if (params.daemon) daemonize();
@@ -1159,7 +1169,7 @@ static bool parse_ip_list(char *opt, ipset *pp)
static bool parse_strlist(char *opt, struct str_list_head *list)
{
char *e, *p = optarg;
char *e, *p = opt;
while (p)
{
e = strchr(p, ',');
@@ -1431,6 +1441,7 @@ static void exithelp(void)
" --wf-filter-lan=0|1\t\t\t\t\t; add excluding filter for non-global IP (default : 1)\n"
" --wf-filter-loopback=0|1\t\t\t\t; add excluding filter for loopback (default : 1)\n"
" --wf-raw=<filter>|@<filename>\t\t\t\t; full raw windivert filter string or filename. replaces --wf-tcp,--wf-udp,--wf-raw-part\n"
" --wf-dup-check=0|1\t\t\t\t\t; 1 (default) = do not allow duplicate winws2 instances with the same wf filter\n"
" --wf-save=<filename>\t\t\t\t\t; save windivert filter string to a file and exit\n"
"\nLOGICAL NETWORK FILTER:\n"
" --ssid-filter=ssid1[,ssid2,ssid3,...]\t\t\t; enable winws2 only if any of specified wifi SSIDs connected\n"
@@ -1625,6 +1636,7 @@ enum opt_indices {
IDX_WF_RAW_PART,
IDX_WF_FILTER_LAN,
IDX_WF_FILTER_LOOPBACK,
IDX_WF_DUP_CHECK,
IDX_WF_SAVE,
IDX_SSID_FILTER,
IDX_NLM_FILTER,
@@ -1717,6 +1729,7 @@ static const struct option long_options[] = {
[IDX_WF_FILTER_LAN] = {"wf-filter-lan", required_argument, 0, 0},
[IDX_WF_FILTER_LOOPBACK] = {"wf-filter-loopback", required_argument, 0, 0},
[IDX_WF_SAVE] = {"wf-save", required_argument, 0, 0},
[IDX_WF_DUP_CHECK] = {"wf-dup-check", optional_argument, 0, 0},
[IDX_SSID_FILTER] = {"ssid-filter", required_argument, 0, 0},
[IDX_NLM_FILTER] = {"nlm-filter", required_argument, 0, 0},
[IDX_NLM_LIST] = {"nlm-list", optional_argument, 0, 0},
@@ -1752,7 +1765,7 @@ int main(int argc, char **argv)
#endif
int result, v;
int option_index = 0;
bool bSkip = false, bDry = false, bTemplate;
bool bSkip = false, bDry = false, bDupCheck = true, bTemplate;
struct hostlist_file *anon_hl = NULL, *anon_hl_exclude = NULL;
struct ipset_file *anon_ips = NULL, *anon_ips_exclude = NULL;
uint64_t payload_type=0;
@@ -2488,6 +2501,9 @@ int main(int argc, char **argv)
strncpy(wf_save_file, optarg, sizeof(wf_save_file));
wf_save_file[sizeof(wf_save_file) - 1] = '\0';
break;
case IDX_WF_DUP_CHECK:
bDupCheck = !optarg || !!atoi(optarg);
break;
case IDX_SSID_FILTER:
hash_ssid_filter = hash_jen(optarg, strlen(optarg));
if (!parse_strlist(optarg, &params.ssid_filter))
@@ -2683,7 +2699,8 @@ int main(int argc, char **argv)
exit_clean(1);
}
}
HANDLE hMutexArg;
HANDLE hMutexArg = NULL;
if (bDupCheck)
{
char mutex_name[128];
snprintf(mutex_name, sizeof(mutex_name), "Global\\winws2_arg_%u_%u_%u_%u_%u_%u_%u_%u_%u_%u_%u_%u",

View File

@@ -85,6 +85,7 @@ struct desync_profile
bool hostlist_auto_retrans_reset;
hostfail_pool *hostlist_auto_fail_counters;
time_t hostlist_auto_last_purge;
struct func_list_head lua_desync;
};

View File

@@ -112,15 +112,14 @@ void HostFailPoolPurge(hostfail_pool **pp)
HostFailPoolDel(pp, elem);
}
}
static time_t host_fail_purge_prev=0;
void HostFailPoolPurgeRateLimited(hostfail_pool **pp)
void HostFailPoolPurgeRateLimited(hostfail_pool **pp, time_t *purge_prev)
{
time_t now = time(NULL);
// do not purge too often to save resources
if (host_fail_purge_prev != now)
if (*purge_prev != now)
{
HostFailPoolPurge(pp);
host_fail_purge_prev = now;
*purge_prev = now;
}
}
void HostFailPoolDump(hostfail_pool *p)

View File

@@ -75,9 +75,9 @@ void funclist_destroy(struct func_list_head *head);
typedef struct hostfail_pool {
char *str; /* key */
int counter; /* value */
time_t expire; /* when to expire record (unixtime) */
char *str;
int counter;
time_t expire; // when to expire record (unixtime)
UT_hash_handle hh; /* makes this structure hashable */
} hostfail_pool;
@@ -86,7 +86,7 @@ hostfail_pool *HostFailPoolAdd(hostfail_pool **pp,const char *s,int fail_time);
hostfail_pool *HostFailPoolFind(hostfail_pool *p,const char *s);
void HostFailPoolDel(hostfail_pool **pp, hostfail_pool *elem);
void HostFailPoolPurge(hostfail_pool **pp);
void HostFailPoolPurgeRateLimited(hostfail_pool **pp);
void HostFailPoolPurgeRateLimited(hostfail_pool **pp, time_t *purge_prev);
void HostFailPoolDump(hostfail_pool *p);

View File

@@ -74,7 +74,7 @@ bool l7_payload_match(t_l7payload l7payload, uint64_t filter_l7p)
}
bool l7_payload_str_list(uint64_t l7p, char *buf, size_t size)
{
char *p;
char *p, *e;
const char *pstr;
size_t lstr;
t_l7payload pl;
@@ -86,17 +86,17 @@ bool l7_payload_str_list(uint64_t l7p, char *buf, size_t size)
memcpy(buf,"all",4);
return true;
}
for(pl=0, p=buf, *buf=0 ; pl<L7P_LAST ; pl++)
for(pl=0, p=buf, e=p+size, *buf=0 ; pl<L7P_LAST ; pl++)
{
if (l7p & (1<<pl))
{
pstr = l7payload_str(pl);
lstr = strlen(pstr);
if (size < ((p!=buf) + lstr + 1)) return false;
if ((p + (p!=buf) + lstr + 1) > e) return false;
if (p!=buf) *p++=','; // not first
memcpy(p,pstr,lstr);
p[lstr]=0;
p+=lstr;
p += lstr;
}
}
return true;
@@ -243,24 +243,38 @@ void ResolveMultiPos(const uint8_t *data, size_t sz, t_l7payload l7payload, cons
}
const char *http_methods[] = { "GET /","POST /","HEAD /","OPTIONS ","PUT /","DELETE /","CONNECT ","TRACE /",NULL };
const char *HttpMethod(const uint8_t *data, size_t len)
static const char *http_methods[] = { "GET ","POST ","HEAD ","OPTIONS ","PUT ","DELETE ","CONNECT ","TRACE ",NULL };
static const char *HttpMethod(const uint8_t *data, size_t len)
{
const char **method;
size_t method_len;
for (method = http_methods; *method; method++)
if (len>=4)
{
method_len = strlen(*method);
if (method_len <= len && !memcmp(data, *method, method_len))
return *method;
for (method = http_methods; *method; method++)
{
method_len = strlen(*method);
if (method_len <= len && !memcmp(data, *method, method_len))
return *method;
}
}
return NULL;
}
bool IsHttp(const uint8_t *data, size_t len)
{
return !!HttpMethod(data,len);
if (!HttpMethod(data,len)) return false;
// GET /uri HTTP/1.1
// skip method
for(; len && *data!=' ' && *data!='\t' && *data!='\r' && *data!='\n'; data++, len--);
if (!len || *data!=' ' && *data!='\t') return false;
for(; len && (*data==' '|| *data=='\t'); data++, len--);
// skip URI
for(; len && *data!=' ' && *data!='\t' && *data!='\r' && *data!='\n'; data++, len--);
if (!len || *data!=' ' && *data!='\t') return false;
for(; len && (*data==' '|| *data=='\t'); data++, len--);
if (len<10 || *data=='\r' || *data=='\n') return false;
return !memcmp(data,"HTTP/1.",7);
}
static bool IsHostAt(const uint8_t *p)
{
return \
@@ -394,10 +408,11 @@ ssize_t HttpPos(t_marker posmarker, int16_t pos, const uint8_t *data, size_t sz)
case PM_HTTP_METHOD:
// recognize some tpws pre-applied hacks
method=data;
if (sz<10) break;
if (sz<12) break;
if (*method=='\n' || *method=='\r') method++;
if (*method=='\n' || *method=='\r') method++;
for (p=method,i=0;i<7;i++) if (*p>='A' && *p<='Z') p++;
// max length is PROPPATCH
for (p=method,i=0;i<9;i++) if (*p>='A' && *p<='Z') p++;
if (i<3 || *p!=' ') break;
return CheckPos(sz,method-data+pos);
case PM_HOST:
@@ -985,6 +1000,10 @@ bool IsQUICCryptoHello(const uint8_t *data, size_t len, size_t *hello_offset, si
return true;
}
static bool is_quic_v2(uint32_t version)
{
return (version == 0x709A50C4) || (version == 0x6b3343cf);
}
/* Returns the QUIC draft version or 0 if not applicable. */
uint8_t QUICDraftVersion(uint32_t version)
{
@@ -1016,7 +1035,7 @@ uint8_t QUICDraftVersion(uint32_t version)
return 34;
/* QUIC Version 2 */
/* TODO: for the time being use 100 as a number for V2 and let see how v2 drafts evolve */
if ((version == 0x709A50C4) || (version == 0x6b3343cf))
if (is_quic_v2(version))
return 100;
return 0;
@@ -1026,10 +1045,6 @@ static bool is_quic_draft_max(uint32_t draft_version, uint8_t max_version)
{
return draft_version && draft_version <= max_version;
}
static bool is_quic_v2(uint32_t version)
{
return (version == 0x709A50C4) || (version == 0x6b3343cf);
}
static bool quic_hkdf_expand_label(const uint8_t *secret, uint8_t secret_len, const char *label, uint8_t *out, size_t out_len)
{
@@ -1140,7 +1155,7 @@ bool QUICIsLongHeader(const uint8_t *data, size_t len)
uint32_t QUICExtractVersion(const uint8_t *data, size_t len)
{
// long header, fixed bit, type=initial
return QUICIsLongHeader(data, len) ? ntohl(*(uint32_t*)(data + 1)) : 0;
return QUICIsLongHeader(data, len) ? pntoh32(data + 1) : 0;
}
bool QUICExtractDCID(const uint8_t *data, size_t len, quic_cid_t *cid)
{
@@ -1177,6 +1192,7 @@ bool QUICDecryptInitial(const uint8_t *data, size_t data_len, uint8_t *clean, si
if ((pn_offset + tvb_get_size(data[pn_offset])) >= data_len) return false;
pn_offset += tvb_get_varint(data + pn_offset, &token_len);
pn_offset += token_len;
if (pn_offset >= data_len) return false;
if ((pn_offset + tvb_get_size(data[pn_offset])) >= data_len) return false;
pn_offset += tvb_get_varint(data + pn_offset, &payload_len);
if (payload_len<20 || (pn_offset + payload_len)>data_len) return false;
@@ -1429,12 +1445,12 @@ bool IsMTProto(const uint8_t *data, size_t len)
if (len>=64)
{
/*
uint8_t decrypt[64];
uint8_t decrypt[64] __attribute__((aligned));
aes_ctr_crypt(data+8, 32, data+40, data, 64, decrypt);
return !memcmp(decrypt+56,"\xEF\xEF\xEF\xEF",4);
*/
// this way requires only one AES instead of 4
uint8_t decrypt[16], iv[16];
uint8_t decrypt[16] __attribute__((aligned)), iv[16];
aes_context ctx;
memcpy(iv, data+40, 16);

View File

@@ -90,16 +90,12 @@ ssize_t TLSPos(t_marker posmarker, int16_t pos, const uint8_t *data, size_t sz);
ssize_t ResolvePos(const uint8_t *data, size_t sz, t_l7payload l7payload, const struct proto_pos *sp);
void ResolveMultiPos(const uint8_t *data, size_t sz, t_l7payload l7payload, const struct proto_pos *marker, int marker_count, ssize_t *pos, int *pos_count);
extern const char *http_methods[9];
const char *HttpMethod(const uint8_t *data, size_t len);
bool IsHttp(const uint8_t *data, size_t len);
bool HttpFindHost(uint8_t **pHost,uint8_t *buf,size_t bs);
bool HttpFindHostConst(const uint8_t **pHost,const uint8_t *buf,size_t bs);
// header must be passed like this : "\nHost:"
bool HttpExtractHeader(const uint8_t *data, size_t len, const char *header, char *buf, size_t len_buf);
bool HttpExtractHost(const uint8_t *data, size_t len, char *host, size_t len_host);
bool IsHttpReply(const uint8_t *data, size_t len);
const char *HttpFind2ndLevelDomain(const char *host);
// must be pre-checked by IsHttpReply
int HttpReplyCode(const uint8_t *data, size_t len);
// must be pre-checked by IsHttpReply