mirror of
https://github.com/bol-van/zapret2.git
synced 2026-03-14 22:22:29 +00:00
Compare commits
244 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ca14fbe9c8 | ||
|
|
c81968b94b | ||
|
|
a2d567c7a0 | ||
|
|
5026199f24 | ||
|
|
68435f64ea | ||
|
|
d84dfaf61d | ||
|
|
4c13c63d27 | ||
|
|
5dde1264ce | ||
|
|
cc989c52ed | ||
|
|
0446b1493b | ||
|
|
97cd8cebca | ||
|
|
2d02eeb578 | ||
|
|
fe318a42e8 | ||
|
|
73c10e3f15 | ||
|
|
17cf260fd0 | ||
|
|
fa15c635bb | ||
|
|
74690047b5 | ||
|
|
d24453da69 | ||
|
|
af200628cd | ||
|
|
76fe7bff82 | ||
|
|
1d1eedbb3b | ||
|
|
274b331825 | ||
|
|
69f900b3da | ||
|
|
da9faabf97 | ||
|
|
60934f5ab8 | ||
|
|
eb7043fc12 | ||
|
|
681c53c3b4 | ||
|
|
65f6923383 | ||
|
|
f0f59261bb | ||
|
|
06cf59d050 | ||
|
|
f0bff44219 | ||
|
|
da0016ed0e | ||
|
|
704c73f821 | ||
|
|
201dd40b46 | ||
|
|
aa13a1f5d2 | ||
|
|
2a3b6f2a8b | ||
|
|
801dec81c8 | ||
|
|
14359afb93 | ||
|
|
372c6748ca | ||
|
|
87d2fcd5a1 | ||
|
|
74ddd4f9d2 | ||
|
|
6b7507deb5 | ||
|
|
f8156a3d38 | ||
|
|
67a8ee47e3 | ||
|
|
93d81ca4b2 | ||
|
|
3d9a36600b | ||
|
|
c3adb3f045 | ||
|
|
f919533873 | ||
|
|
17bdfe16b1 | ||
|
|
bc0102fbdc | ||
|
|
10d72b3242 | ||
|
|
9dd14dfc7c | ||
|
|
10201f1abf | ||
|
|
236550918b | ||
|
|
72a269e88d | ||
|
|
d3199eebd3 | ||
|
|
ffcb14726d | ||
|
|
aa5a1f4183 | ||
|
|
ca186a6566 | ||
|
|
dced388652 | ||
|
|
1f7d10bf5b | ||
|
|
6b1b4adddb | ||
|
|
cfe7b76352 | ||
|
|
62fd0dc432 | ||
|
|
050a01bda2 | ||
|
|
4c5d84c19e | ||
|
|
d430b4775d | ||
|
|
807565968e | ||
|
|
e062b1795e | ||
|
|
3417e50438 | ||
|
|
70f5a88ec0 | ||
|
|
4b3fba3fb2 | ||
|
|
9cded5448a | ||
|
|
2302ac6949 | ||
|
|
0be76b902e | ||
|
|
fa89e011fb | ||
|
|
622a81001d | ||
|
|
4d793b73a4 | ||
|
|
a47b6a529b | ||
|
|
7c320c8d57 | ||
|
|
b18f0770c8 | ||
|
|
f7fc845014 | ||
|
|
2c1a885a07 | ||
|
|
9eb308d84c | ||
|
|
3e724c3810 | ||
|
|
c179d55d88 | ||
|
|
3f1af1441e | ||
|
|
4c1b2b65f3 | ||
|
|
918258413f | ||
|
|
e6206c5a5f | ||
|
|
f93c6de772 | ||
|
|
5a7e2b1ca2 | ||
|
|
ca8104c72a | ||
|
|
3aad1f9ed9 | ||
|
|
fd288d5e7d | ||
|
|
349fe3f7d7 | ||
|
|
4554b7c15b | ||
|
|
0b595ae3a8 | ||
|
|
3e69e1b8c1 | ||
|
|
02b895910b | ||
|
|
b2a53e9c64 | ||
|
|
a626cfce8a | ||
|
|
ebcbfc37ba | ||
|
|
33d3c94b68 | ||
|
|
d55dbb7717 | ||
|
|
cb82be9eab | ||
|
|
024d36acc4 | ||
|
|
08c6151a4c | ||
|
|
520317dc3c | ||
|
|
6bc0bf1b97 | ||
|
|
d18fec9053 | ||
|
|
e60e5a0578 | ||
|
|
84576a7039 | ||
|
|
7957a0a425 | ||
|
|
7ba4110416 | ||
|
|
4babaef6a8 | ||
|
|
872e37d160 | ||
|
|
a8219f4897 | ||
|
|
36267b7e9b | ||
|
|
99a7f06976 | ||
|
|
3617b8934f | ||
|
|
8e6387a6df | ||
|
|
3bc0e8e350 | ||
|
|
7f12334872 | ||
|
|
0f42ff1731 | ||
|
|
801328dc02 | ||
|
|
fdb9c9be60 | ||
|
|
5e89db0c7b | ||
|
|
0e95de6083 | ||
|
|
3ec585c97e | ||
|
|
577959f442 | ||
|
|
36731cd9b5 | ||
|
|
b3b8133c39 | ||
|
|
5f96ce1099 | ||
|
|
2088f593d4 | ||
|
|
03152ba76f | ||
|
|
f94d1b1d16 | ||
|
|
790a2ca355 | ||
|
|
f318397726 | ||
|
|
5a116cf9be | ||
|
|
d40f05865b | ||
|
|
e47603281c | ||
|
|
8ba58c8f16 | ||
|
|
2def9397a0 | ||
|
|
a61895778b | ||
|
|
a622061b45 | ||
|
|
1bbd342ff2 | ||
|
|
84f978cee4 | ||
|
|
dd3cffca5f | ||
|
|
b699e5d9ec | ||
|
|
e6591575fe | ||
|
|
ca7569f68a | ||
|
|
3a16523399 | ||
|
|
2fd172118c | ||
|
|
c43574d056 | ||
|
|
22d4df73f6 | ||
|
|
23d6cddb30 | ||
|
|
c3b5d5e9ed | ||
|
|
20856321c3 | ||
|
|
75f3c7eac3 | ||
|
|
129461dc45 | ||
|
|
91a3badc67 | ||
|
|
ff15bcceae | ||
|
|
61b20f86a7 | ||
|
|
2de8809ead | ||
|
|
c77e8f799f | ||
|
|
4cdf498a14 | ||
|
|
4bbfc3081d | ||
|
|
1099cf013d | ||
|
|
cb85f6e672 | ||
|
|
823f4a6fb6 | ||
|
|
05647e84ef | ||
|
|
8bc74d0c4f | ||
|
|
0eb6cc9722 | ||
|
|
13594401c6 | ||
|
|
2983c681d7 | ||
|
|
68eefd9dd7 | ||
|
|
73f6f7c522 | ||
|
|
df83a29b98 | ||
|
|
9881cc4da2 | ||
|
|
44f8ad6747 | ||
|
|
c651367d6a | ||
|
|
90f88271c5 | ||
|
|
9ba8d6cbdf | ||
|
|
27efbb37d7 | ||
|
|
d725bd8fd7 | ||
|
|
0ef50d04dc | ||
|
|
fdae4b1812 | ||
|
|
d0644f6160 | ||
|
|
b4f1765574 | ||
|
|
8454d48fcd | ||
|
|
70d7a77d06 | ||
|
|
2a48f82feb | ||
|
|
c5d997ce48 | ||
|
|
c950edb380 | ||
|
|
0d96b03f49 | ||
|
|
9772641813 | ||
|
|
7307a03ff7 | ||
|
|
b529198f24 | ||
|
|
5f5cfb434c | ||
|
|
2f1aa5734e | ||
|
|
062360f3f3 | ||
|
|
7122808425 | ||
|
|
515921522e | ||
|
|
c0ce825a95 | ||
|
|
c4b23d21ce | ||
|
|
0847d9f140 | ||
|
|
b239690e33 | ||
|
|
4f6510daf1 | ||
|
|
0cad2329a1 | ||
|
|
24d9eb1fe2 | ||
|
|
f98445d36b | ||
|
|
7278bb1b87 | ||
|
|
5b58997e3e | ||
|
|
93a6487eb5 | ||
|
|
fdca797671 | ||
|
|
bb9e78e8fb | ||
|
|
2a15a1a778 | ||
|
|
bf89b415bb | ||
|
|
735936efc5 | ||
|
|
9d09d8adcc | ||
|
|
3874e16075 | ||
|
|
cbb05967ba | ||
|
|
665bd5f318 | ||
|
|
fa1d7c30c3 | ||
|
|
940f94162d | ||
|
|
60108bf378 | ||
|
|
5a68245e32 | ||
|
|
b2dbdd4dd7 | ||
|
|
5bc65c3b91 | ||
|
|
6bf7f2c7c0 | ||
|
|
44a80abb3f | ||
|
|
89f0f39b83 | ||
|
|
ad6f1db149 | ||
|
|
9154fe1677 | ||
|
|
5e63a0f5c5 | ||
|
|
0521053991 | ||
|
|
7b7ed1ad60 | ||
|
|
2915647c63 | ||
|
|
958a4e918b | ||
|
|
cb332dad74 | ||
|
|
17e9e0a8e6 | ||
|
|
78b348a193 | ||
|
|
8103a02689 |
6
.github/ISSUE_TEMPLATE/issue-warning.md
vendored
6
.github/ISSUE_TEMPLATE/issue-warning.md
vendored
@@ -11,7 +11,11 @@ Issues - это место для обращений к разработчику
|
||||
Discussions - место для обсуждения вопросов между пользователями.
|
||||
|
||||
Все, что выходит за рамки багов и технически грамотных предложений, идей,
|
||||
вопросы типа "как мне это запустить", "что нажать", "что вписать" - будет безжалостно удаляться.
|
||||
вопросы типа "как мне это запустить", "что нажать", "что вписать", "перестало открываться" - будет безжалостно удаляться.
|
||||
Если вы не знаете как пользоваться, для вас что-то сложно, здесь - не место обучению программе или linux и не место для вопросов подобного рода.
|
||||
Поймите, пожалуйста, что zapret - это инструмент, а не готовое решение для пользователя. В его функциях нет кнопки "открыть сайты", поэтому
|
||||
если они перестали открываться - это не issue. Функцию "открыть сайты" дают только сборки - ищите их и все вопросы адресуйте туда.
|
||||
Если вы игнорируете данное требование, вы не достигните своих целей , а только добавите желания удалить ваш issue или при настойчивости забанить.
|
||||
Идите в дискуссии, не захламляйте issues.
|
||||
|
||||
Here is the place for bugs only. All questions, especially user-like questions (non-technical) go to Discussions.
|
||||
|
||||
6
.github/workflows/build.yml
vendored
6
.github/workflows/build.yml
vendored
@@ -75,11 +75,11 @@ jobs:
|
||||
sudo dpkg --add-architecture i386
|
||||
sudo apt update -qq
|
||||
if [[ "$ARCH" == lexra ]]; then
|
||||
sudo apt install -y libcap-dev libc6:i386 zlib1g:i386
|
||||
sudo apt install -y pigz libcap-dev libc6:i386 zlib1g:i386
|
||||
URL=https://github.com/$REPO/raw/refs/heads/master/$DIR.txz
|
||||
else
|
||||
# luajit buildvm requires 32 bit executable on host platform for 32 bit cross targets
|
||||
sudo apt install -y libcap-dev libc6-dev gcc-multilib
|
||||
sudo apt install -y pigz libcap-dev libc6-dev gcc-multilib
|
||||
URL=https://github.com/$REPO/releases/download/latest/$TOOL.tar.xz
|
||||
fi
|
||||
mkdir -p $HOME/tools
|
||||
@@ -553,7 +553,7 @@ jobs:
|
||||
rm -rf binaries/{android*,freebsd*,win*} \
|
||||
init.d/{openrc,pfsense,runit,s6,systemd,windivert.filter.examples} \
|
||||
nfq2 ip2net mdig docs Makefile
|
||||
gzip lua/*.lua
|
||||
pigz -11 lua/*.lua
|
||||
)
|
||||
tar --owner=0 --group=0 -czf ${{ env.repo_dir }}-openwrt-embedded.tar.gz ${{ env.repo_dir }}
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -6,7 +6,7 @@ pktws_check_http()
|
||||
|
||||
[ "$NOTEST_BASIC_HTTP" = 1 ] && { echo "SKIPPED"; return; }
|
||||
|
||||
for s in 'http_hostcase' 'http_hostcase:spell=hoSt' 'http_domcase' 'http_methodeol'; do
|
||||
pktws_curl_test_update $1 $2 --payload http_req --lua-desync=$s
|
||||
for s in 'http_hostcase' 'http_hostcase:spell=hoSt' 'http_domcase' 'http_methodeol' 'http_unixeol'; do
|
||||
pktws_curl_test_update $1 $2 --payload=http_req --lua-desync=$s
|
||||
done
|
||||
}
|
||||
|
||||
@@ -5,7 +5,9 @@ pktws_check_http()
|
||||
# $1 - test function
|
||||
# $2 - domain
|
||||
|
||||
local PAYLOAD="--payload http_req" repeats ok
|
||||
local PAYLOAD="--payload=http_req" repeats ok
|
||||
|
||||
[ "$NOTEST_MISC_HTTP" = 1 ] && { echo "SKIPPED"; return; }
|
||||
|
||||
for repeats in 1 20 100 260; do
|
||||
# send starting bytes of original payload
|
||||
@@ -20,7 +22,9 @@ pktws_check_https_tls12()
|
||||
# $1 - test function
|
||||
# $2 - domain
|
||||
|
||||
local PAYLOAD="--payload tls_client_hello" repeats ok
|
||||
local PAYLOAD="--payload=tls_client_hello" repeats ok
|
||||
|
||||
[ "$NOTEST_MISC_HTTPS" = 1 ] && { echo "SKIPPED"; return; }
|
||||
|
||||
for repeats in 1 20 100 260; do
|
||||
# send starting bytes of original payload
|
||||
|
||||
39
blockcheck2.d/standard/17-oob.sh
Normal file
39
blockcheck2.d/standard/17-oob.sh
Normal 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"
|
||||
}
|
||||
@@ -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
|
||||
@@ -26,7 +30,7 @@ pktws_check_http()
|
||||
# $1 - test function
|
||||
# $2 - domain
|
||||
local splits_http='method+2 midsld method+2,midsld'
|
||||
local PAYLOAD="--payload http_req"
|
||||
local PAYLOAD="--payload=http_req"
|
||||
|
||||
[ "$NOTEST_MULTI_HTTP" = 1 ] && { echo "SKIPPED"; return; }
|
||||
|
||||
@@ -39,9 +43,7 @@ pktws_check_https_tls()
|
||||
# $2 - domain
|
||||
# $3 - PRE args for nfqws2
|
||||
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; }
|
||||
local PAYLOAD="--payload=tls_client_hello"
|
||||
|
||||
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"
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
. "$TESTDIR/def.inc"
|
||||
|
||||
pktws_check_http()
|
||||
{
|
||||
# $1 - test function
|
||||
@@ -5,7 +7,7 @@ pktws_check_http()
|
||||
|
||||
[ "$NOTEST_SEQOVL_HTTP" = 1 ] && { echo "SKIPPED"; return; }
|
||||
|
||||
local PAYLOAD="--payload http_req"
|
||||
local PAYLOAD="--payload=http_req"
|
||||
|
||||
local ok pat= split f f2
|
||||
|
||||
@@ -34,10 +36,11 @@ 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
|
||||
local PAYLOAD="--payload tls_client_hello"
|
||||
local PAYLOAD="--payload=tls_client_hello"
|
||||
|
||||
pat=${SEQOVL_PATTERN_HTTPS:+seqovl_pat}
|
||||
pat=${pat:-fake_default_tls}
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -5,7 +5,9 @@ pktws_check_http()
|
||||
# $1 - test function
|
||||
# $2 - domain
|
||||
|
||||
local PAYLOAD="--payload http_req" split
|
||||
local PAYLOAD="--payload=http_req" split
|
||||
|
||||
[ "$NOTEST_SYNDATA_HTTP" = 1 ] && { echo "SKIPPED"; return; }
|
||||
|
||||
for split in '' multisplit $MULTIDISORDER; do
|
||||
pktws_curl_test_update "$1" "$2" --lua-desync=syndata ${split:+$PAYLOAD --lua-desync=$split}
|
||||
@@ -19,7 +21,7 @@ pktws_check_https_tls()
|
||||
# $2 - domain
|
||||
# $3 - PRE args for nfqws2
|
||||
|
||||
local PAYLOAD="--payload tls_client_hello" ok=0 pre="$3" split
|
||||
local PAYLOAD="--payload=tls_client_hello" ok=0 pre="$3" split
|
||||
|
||||
for split in '' multisplit $MULTIDISORDER; do
|
||||
pktws_curl_test_update "$1" "$2" $pre --lua-desync=syndata ${split:+$PAYLOAD --lua-desync=$split} && ok=1
|
||||
@@ -36,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
|
||||
}
|
||||
@@ -45,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"
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ pktws_check_http3()
|
||||
[ "$NOTEST_QUIC" = 1 ] && { echo "SKIPPED"; return; }
|
||||
|
||||
local repeats fake pos fool
|
||||
local PAYLOAD="--payload quic_initial"
|
||||
local PAYLOAD="--payload=quic_initial"
|
||||
|
||||
if [ -n "$FAKE_QUIC" ]; then
|
||||
fake=fake_quic
|
||||
|
||||
@@ -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
|
||||
|
||||
126
blockcheck2.sh
126
blockcheck2.sh
@@ -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
|
||||
|
||||
@@ -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 ]
|
||||
}
|
||||
|
||||
@@ -172,15 +172,23 @@ unique()
|
||||
|
||||
is_linked_to_busybox()
|
||||
{
|
||||
local IFS F P
|
||||
|
||||
local IFS F P BB
|
||||
|
||||
BB="$(which busybox)"
|
||||
|
||||
IFS=:
|
||||
for path in $PATH; do
|
||||
F=$path/$1
|
||||
P="$(readlink $F)"
|
||||
if [ -z "$P" ] && [ -x $F ] && [ ! -L $F ]; then return 1; fi
|
||||
[ "${P%busybox*}" != "$P" ] && return
|
||||
F="$path/$1"
|
||||
if [ -L "$F" ]; then
|
||||
P="$(readlink $F)"
|
||||
if [ -z "$P" ] && [ -x $F ] && [ ! -L $F ]; then return 1; fi
|
||||
[ "${P%busybox*}" != "$P" ] && return
|
||||
elif [ -f "$F" -a -n "$BB" ]; then
|
||||
# possible hardlink
|
||||
[ $(get_dir_inode "$F") = $(get_dir_inode "$BB") ] && return
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
get_dir_inode()
|
||||
{
|
||||
@@ -335,7 +343,7 @@ setup_md5()
|
||||
{
|
||||
[ -n "$MD5" ] && return
|
||||
MD5=md5sum
|
||||
exists $MD5 || MD5=md5
|
||||
exists $MD5 || MD5="md5 -q"
|
||||
}
|
||||
|
||||
md5f()
|
||||
@@ -358,7 +366,7 @@ random()
|
||||
local r rs
|
||||
setup_random
|
||||
if [ -c /dev/urandom ]; then
|
||||
read rs </dev/urandom
|
||||
rs=$(dd if=/dev/urandom count=1 bs=16 2>/dev/null | hexdump -e '1 "%02x"')
|
||||
else
|
||||
rs="$RANDOM$RANDOM$(date)"
|
||||
fi
|
||||
@@ -386,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
|
||||
|
||||
@@ -36,9 +36,8 @@ ask_list()
|
||||
# $3 - (optional) default value
|
||||
local M_DEFAULT
|
||||
eval M_DEFAULT="\$$1"
|
||||
local M_ALL=$M_DEFAULT
|
||||
local M=""
|
||||
local m
|
||||
local M_DEFAULT_VAR="$M_DEFAULT"
|
||||
local M="" m
|
||||
|
||||
[ -n "$3" ] && { find_str_in_list "$M_DEFAULT" "$2" || M_DEFAULT="$3" ;}
|
||||
|
||||
@@ -54,5 +53,5 @@ ask_list()
|
||||
echo selected : $M
|
||||
eval $1="\"$M\""
|
||||
|
||||
[ "$M" != "$M_OLD" ]
|
||||
[ "$M" != "$M_DEFAULT_VAR" ]
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
@@ -522,11 +522,6 @@ install_openwrt_firewall()
|
||||
{
|
||||
echo \* installing firewall script $1
|
||||
|
||||
[ -n "MODE" ] || {
|
||||
echo should specify MODE in $ZAPRET_CONFIG
|
||||
exitp 7
|
||||
}
|
||||
|
||||
echo "linking : $FW_SCRIPT_SRC => $OPENWRT_FW_INCLUDE"
|
||||
ln -fs "$FW_SCRIPT_SRC" "$OPENWRT_FW_INCLUDE"
|
||||
|
||||
@@ -784,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_()
|
||||
|
||||
@@ -41,7 +41,7 @@ ipt6_add_del()
|
||||
}
|
||||
ipt6a_add_del()
|
||||
{
|
||||
on_off_function ipt6 ipt6a_del "$@"
|
||||
on_off_function ipt6a ipt6_del "$@"
|
||||
}
|
||||
|
||||
is_ipt_flow_offload_avail()
|
||||
|
||||
@@ -25,7 +25,7 @@ filter_apply_hostlist_target()
|
||||
{
|
||||
# $1 - var name of nfqws params
|
||||
|
||||
local v parm parm1 parm2 parm3 parm4 parm5 parm6 parm7 parm8 parm9 parm10 param11 param12 param13 parmNA
|
||||
local v parm parm1 parm2 parm3 parm4 parm5 parm6 parm7 parm8 parm9 parm10 parm11 parm12 parm13 parmNA
|
||||
eval v="\$$1"
|
||||
if contains "$v" "$HOSTLIST_MARKER" || contains "$v" "$HOSTLIST_NOAUTO_MARKER"; then
|
||||
[ "$MODE_FILTER" = hostlist -o "$MODE_FILTER" = autohostlist ] &&
|
||||
|
||||
@@ -18,6 +18,18 @@ nft_list_table()
|
||||
nft -t list table inet $ZAPRET_NFT_TABLE
|
||||
}
|
||||
|
||||
nft_add_chain()
|
||||
{
|
||||
# $1 - chain
|
||||
# $2 - params
|
||||
nft add chain inet $ZAPRET_NFT_TABLE $1 "{ $2 }"
|
||||
}
|
||||
nft_del_chain()
|
||||
{
|
||||
# $1 - chain
|
||||
nft delete chain inet $ZAPRET_NFT_TABLE $1
|
||||
}
|
||||
|
||||
nft_create_set()
|
||||
{
|
||||
# $1 - set name
|
||||
@@ -52,7 +64,7 @@ nft_flush_chain()
|
||||
nft_chain_empty()
|
||||
{
|
||||
# $1 - chain name
|
||||
local count=$(nft list chain inet $ZAPRET_NFT_TABLE prerouting | wc -l)
|
||||
local count=$(nft list chain inet $ZAPRET_NFT_TABLE $1 | wc -l)
|
||||
[ "$count" -le 4 ]
|
||||
}
|
||||
nft_rule_exists()
|
||||
@@ -65,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()
|
||||
@@ -163,10 +174,10 @@ cat << EOF | nft -f -
|
||||
add chain inet $ZAPRET_NFT_TABLE postnat_hook { type filter hook postrouting priority 101; }
|
||||
flush chain inet $ZAPRET_NFT_TABLE postnat_hook
|
||||
|
||||
add chain inet $ZAPRET_NFT_TABLE prerouting_hook { type filter hook prerouting priority -99; }
|
||||
flush chain inet $ZAPRET_NFT_TABLE prerouting_hook
|
||||
add chain inet $ZAPRET_NFT_TABLE prerouting
|
||||
flush chain inet $ZAPRET_NFT_TABLE prerouting
|
||||
add chain inet $ZAPRET_NFT_TABLE prerouting_hook { type filter hook prerouting priority -99; }
|
||||
flush chain inet $ZAPRET_NFT_TABLE prerouting_hook
|
||||
|
||||
add chain inet $ZAPRET_NFT_TABLE prenat_hook { type filter hook prerouting priority -101; }
|
||||
flush chain inet $ZAPRET_NFT_TABLE prenat_hook
|
||||
@@ -185,6 +196,7 @@ cat << EOF | nft -f -
|
||||
|
||||
add set inet $ZAPRET_NFT_TABLE wanif { type ifname; }
|
||||
add set inet $ZAPRET_NFT_TABLE wanif6 { type ifname; }
|
||||
add set inet $ZAPRET_NFT_TABLE lanif { type ifname; }
|
||||
|
||||
add chain inet $ZAPRET_NFT_TABLE ruletest
|
||||
flush chain inet $ZAPRET_NFT_TABLE ruletest
|
||||
@@ -230,8 +242,6 @@ cat << EOF | nft -f - 2>/dev/null
|
||||
delete chain inet $ZAPRET_NFT_TABLE flow_offload_always
|
||||
delete chain inet $ZAPRET_NFT_TABLE ruletest
|
||||
EOF
|
||||
# unfortunately this approach breaks udp desync of the connection initiating packet (new, first one)
|
||||
# delete chain inet $ZAPRET_NFT_TABLE predefrag
|
||||
}
|
||||
nft_del_flowtable()
|
||||
{
|
||||
@@ -257,14 +267,17 @@ nft_create_or_update_flowtable()
|
||||
nft_flush_ifsets()
|
||||
{
|
||||
cat << EOF | nft -f - 2>/dev/null
|
||||
flush set inet $ZAPRET_NFT_TABLE wanif
|
||||
flush set inet $ZAPRET_NFT_TABLE wanif6
|
||||
|
||||
for set in wanif wanif6 lanif; do
|
||||
flush set inet $ZAPRET_NFT_TABLE $set
|
||||
done
|
||||
EOF
|
||||
}
|
||||
nft_list_ifsets()
|
||||
{
|
||||
nft list set inet $ZAPRET_NFT_TABLE wanif
|
||||
nft list set inet $ZAPRET_NFT_TABLE wanif6
|
||||
for set in wanif wanif6 lanif; do
|
||||
nft list set inet $ZAPRET_NFT_TABLE $set
|
||||
done
|
||||
nft list flowtable inet $ZAPRET_NFT_TABLE ft 2>/dev/null
|
||||
}
|
||||
|
||||
@@ -402,7 +415,9 @@ nft_fill_ifsets()
|
||||
# calling all in one shot helps not to waste cpu time many times
|
||||
|
||||
script="flush set inet $ZAPRET_NFT_TABLE wanif
|
||||
flush set inet $ZAPRET_NFT_TABLE wanif6"
|
||||
flush set inet $ZAPRET_NFT_TABLE wanif6
|
||||
flush set inet $ZAPRET_NFT_TABLE lanif"
|
||||
nft_script_add_ifset_element lanif "$1"
|
||||
|
||||
[ "$DISABLE_IPV4" = "1" ] || nft_script_add_ifset_element wanif "$2"
|
||||
[ "$DISABLE_IPV6" = "1" ] || nft_script_add_ifset_element wanif6 "$3"
|
||||
|
||||
@@ -41,6 +41,10 @@ AUTOHOSTLIST_DEBUGLOG=0
|
||||
|
||||
# number of parallel threads for domain list resolves
|
||||
MDIG_THREADS=30
|
||||
# EAI_AGAIN retries
|
||||
MDIG_EAGAIN=10
|
||||
# delay between EAI_AGAIN retries (ms)
|
||||
MDIG_EAGAIN_DELAY=500
|
||||
|
||||
# ipset/*.sh can compress large lists
|
||||
GZIP_LISTS=1
|
||||
@@ -54,7 +58,7 @@ GZIP_LISTS=1
|
||||
DESYNC_MARK=0x40000000
|
||||
DESYNC_MARK_POSTNAT=0x20000000
|
||||
|
||||
# do not pass outgoing traffic to tpws/nfqws not marked with this bit
|
||||
# do not pass outgoing traffic to nfqws not marked with this bit
|
||||
# this setting allows to write your own rules to limit traffic that should be fooled
|
||||
# for example based on source IP or incoming interface name
|
||||
# no filter if not defined
|
||||
|
||||
@@ -144,3 +144,54 @@ v0.8.0
|
||||
* zapret-antidpi: tls_client_hello_clone
|
||||
* zapret-antidpi: "optional" arg to blob taking functions
|
||||
* nfqws2: support gzipped lua file. auto use script.lua.gz
|
||||
|
||||
v0.8.1
|
||||
|
||||
* nfqws2: fix bu48 crash and wrong results in bitset
|
||||
* zapret-lib: http_reconstruct_req
|
||||
* zapret-antidpi: http_unixeol
|
||||
* blockcheck2: http_unixeol test
|
||||
|
||||
0.8.2
|
||||
|
||||
* nfqws2: do not start if NFQWS2_COMPAT_VER unexpected
|
||||
* nfqws2: cache dns response IP addresses if --ipcache-hostname enabled
|
||||
* winws2: remove hardcoded filter for loopback
|
||||
* init.d: ressurect @lanif in nft scheme
|
||||
* init.d: fix broken @wanif/@wanif6 fill in sysv nft scheme
|
||||
* init.d: 80-dns-intercept
|
||||
* winws2: --wf-filter-loopback
|
||||
* blockcheck2: NOTEST_MISC_HTTP[S], NOTEST_SYNDATA_HTTP[S]
|
||||
|
||||
0.8.3
|
||||
|
||||
* nfqws2, zapret-lib: gzip compression and decompression
|
||||
* nfqws2: ignore trailing spaces and tabs in hostlists and ipsets. "host.com " or "1.2.3.4 " are ok now
|
||||
* init.d: 99-lan-filter custom script
|
||||
* mdig: --eagain, --eagain-delay
|
||||
|
||||
0.8.4
|
||||
|
||||
* winws2: fix loopback large packets processing (up to 64K)
|
||||
* zapret-lib, zapret-antidpi: use numeric indexes in http dissects
|
||||
* nfqws2: move ctx from lightuserdata to userdata. prevents crashes on specific ARM cpus
|
||||
* 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
|
||||
|
||||
@@ -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
|
||||
|
||||
5184
docs/manual.en.md
Normal file
5184
docs/manual.en.md
Normal file
File diff suppressed because it is too large
Load Diff
412
docs/manual.md
412
docs/manual.md
@@ -14,6 +14,7 @@
|
||||
- [nfqws2](#nfqws2)
|
||||
- [Общие принципы задания параметров](#общие-принципы-задания-параметров)
|
||||
- [Полный список опций](#полный-список-опций)
|
||||
- [Распознавание протоколов](#распознавание-протоколов)
|
||||
- [Использование множественных профилей](#использование-множественных-профилей)
|
||||
- [Шаблоны профилей](#шаблоны-профилей)
|
||||
- [Фильтрация по листам](#фильтрация-по-листам)
|
||||
@@ -60,6 +61,9 @@
|
||||
- [aes\_gcm](#aes_gcm)
|
||||
- [aes\_ctr](#aes_ctr)
|
||||
- [hkdf](#hkdf)
|
||||
- [Компрессия](#компрессия)
|
||||
- [gunzip](#gunzip)
|
||||
- [gzip](#gzip)
|
||||
- [Системные функции](#системные-функции)
|
||||
- [uname](#uname)
|
||||
- [clock\_gettime](#clock_gettime)
|
||||
@@ -119,6 +123,8 @@
|
||||
- [genhost](#genhost)
|
||||
- [host\_ip](#host_ip)
|
||||
- [Операции с именами файлов и путями](#операции-с-именами-файлов-и-путями)
|
||||
- [Чтение и запись файлов](#чтение-и-запись-файлов)
|
||||
- [Компрессия данных](#компрессия-данных)
|
||||
- [autottl](#autottl)
|
||||
- [Операции с диссектами](#операции-с-диссектами)
|
||||
- [standard ipid](#standard-ipid)
|
||||
@@ -158,12 +164,13 @@
|
||||
- [http\_hostcase](#http_hostcase)
|
||||
- [http\_domcase](#http_domcase)
|
||||
- [http\_methodeol](#http_methodeol)
|
||||
- [http\_unixeol](#http_unixeol)
|
||||
- [Замена window size](#замена-window-size)
|
||||
- [wsize](#wsize)
|
||||
- [wssize](#wssize)
|
||||
- [Фейки](#фейки)
|
||||
- [syndata](#syndata)
|
||||
- [tls_client_hello_clone](#tls_client_hello_clone)
|
||||
- [tls\_client\_hello\_clone](#tls_client_hello_clone)
|
||||
- [fake](#fake)
|
||||
- [rst](#rst)
|
||||
- [TCP сегментация](#tcp-сегментация)
|
||||
@@ -174,6 +181,7 @@
|
||||
- [fakeddisorder](#fakeddisorder)
|
||||
- [hostfakesplit](#hostfakesplit)
|
||||
- [tcpseg](#tcpseg)
|
||||
- [oob](#oob)
|
||||
- [Дурение udp](#дурение-udp)
|
||||
- [udplen](#udplen)
|
||||
- [dht\_dn](#dht_dn)
|
||||
@@ -254,6 +262,10 @@
|
||||
- [Принципы интеграции с openrc](#принципы-интеграции-с-openrc)
|
||||
- [Шпаргалка openrc](#шпаргалка-openrc)
|
||||
- [Альтернативная установка на systemd](#альтернативная-установка-на-systemd)
|
||||
- [Другие прошивки](#другие-прошивки)
|
||||
- [Особенности Windows](#особенности-windows)
|
||||
- [Windows 7](#windows-7)
|
||||
- [Windows Server](#windows-server)
|
||||
|
||||
# Введение
|
||||
|
||||
@@ -272,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 код составляют минимально рабочее ядро проекта. Все остальное является дополнительным, второстепенным и опциональным.
|
||||
|
||||
@@ -661,10 +675,11 @@ nfqws2 использует стандартный парсер getopt_long_only
|
||||
--pidfile=<filename> ; запись PID в файл
|
||||
--ctrack-timeouts=S:E:F[:U] ; таймауты conntrack для стадий tcp SYN, ESTABLISHED, FIN и для udp
|
||||
--ctrack-disable=[0|1] ; 1 отключает conntrack
|
||||
--payload-disable=[type[,type]] ; отключить распознавание указанных типов пейлоадов. без аргумента - отключить все.
|
||||
--server=[0|1] ; серверный режим. для обслуживания listener-ов меняются многие аспекты выбора направления и ip/port источника/приемника
|
||||
--ipcache-lifetime=<int> ; время жизни записей кэша IP в секундах. 0 - без ограничений.
|
||||
--ipcache-hostname=[0|1] ; 1 или отсутствие аргумента включают кэширование имен хостов для применения в стратегиях нулевой фазы
|
||||
--reasm-disable=[proto[,proto]] ; отключить сборку фрагментов для списка пейлоадов : tls_client_hello quic_initial . без аргумента - отключить reasm для всего.
|
||||
--reasm-disable=[type[,type]] ; отключить сборку фрагментов для списка пейлоадов : tls_client_hello quic_initial . без аргумента - отключить reasm для всего.
|
||||
|
||||
DESYNC ENGINE INIT:
|
||||
--writeable[=<dir_name>] ; создать директорию для Lua с разрешением записи и поместить путь к ней в переменную env "WRITEABLE" (только одна директория)
|
||||
@@ -682,7 +697,7 @@ MULTI-STRATEGY:
|
||||
--filter-l3=ipv4|ipv6 ; фильтр профиля : версия ip протокола
|
||||
--filter-tcp=[~]port1[-port2]|* ; фильтр профиля : порты tcp или диапазоны портов через запятую
|
||||
--filter-udp=[~]port1[-port2]|* ; фильтр профиля : порты udp или диапазоны портов через запятую
|
||||
--filter-l7=proto[,proto] ; фильтр профиля : список протоколов потока. полный список доступен в help тексте программы.
|
||||
--filter-l7=proto[,proto] ; фильтр профиля : список протоколов потока
|
||||
--ipset=<filename> ; фильтр профиля : включающий список ip адресов или подсетей из файла. может быть смешанным ipv4+ipv6.
|
||||
--ipset-ip=<ip_list> ; фильтр профиля : включающий фиксированный список ip адресов или подсетей через запятую
|
||||
--ipset-exclude=<filename> ; фильтр профиля : исключающий список ip адресов или подсетей из файла. может быть смешанным ipv4+ipv6.
|
||||
@@ -703,7 +718,7 @@ MULTI-STRATEGY:
|
||||
--hostlist-auto-debug=<logfile> ; дебаг лог автолиста
|
||||
|
||||
LUA PACKET PASS MODE:
|
||||
--payload=type[,type] ; внутрипрофильный фильтр : фильтр пейлоада для последующих инстансов внутри профиля. список пейлоадов доступен в help тексте программы.
|
||||
--payload=type[,type] ; внутрипрофильный фильтр : фильтр пейлоада для последующих инстансов внутри профиля
|
||||
--out-range=[(n|a|d|s|p)<int>](-|<)[(n|a|d|s|p)<int>] ; внутрипрофильный фильтр : диапазон счетчиков conntrack для последующих инстансов внутри профиля - исходящее направление
|
||||
--in-range=[(n|a|d|s|p)<int>](-|<)[(n|a|d|s|p)<int>] ; внутрипрофильный фильтр : диапазон счетчиков conntrack для последующих инстансов внутри профиля - входящее направление
|
||||
|
||||
@@ -744,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, при наличии подключения к которым перехват включается, а иначе не включается.
|
||||
@@ -751,6 +767,30 @@ LOGICAL NETWORK FILTER:
|
||||
--nlm-list[=all] ; вывести список подключенных NLM сетей. all - список всех NLM сетей
|
||||
```
|
||||
|
||||
## Распознавание протоколов
|
||||
|
||||
nfqws2 сигнатурно распознает типы пейлоадов отдельно взятых пакетов или групп пакетов.
|
||||
Все пустые пакеты имеют пейлоад empty, неизвестные - unknown.
|
||||
Протокол потока присваивается после получение первого известного пейлоада и остается с потоком до конца его существования.
|
||||
При этом последующие пейлоады могут иметь как известный тип, так и неизвестный.
|
||||
В фильтрах по пейлоаду и протоколу потока доступны специальные значения - all и known. All означает любой, known - не empty и не unknown.
|
||||
|
||||
Таблица распознаваемых типов пейлоада и протоколов потока
|
||||
|
||||
| Протокол потока | L4 | Пейлоады |
|
||||
| :-------------- | :-- | :------- |
|
||||
| http | tcp | http_req<br>http_reply |
|
||||
| tls | tcp | tls_client_hello<br>tls_server_hello |
|
||||
| xmpp | tcp | xmpp_stream<br>xmpp_starttls<br>xmpp_proceed<br>xmpp_features |
|
||||
| mtproto | tcp | mtproto_initial |
|
||||
| quic | udp | quic_initial |
|
||||
| wireguard | udp | wireguard_initiation<br>wireguard_response<br>wireguard_cookie<br>wireguard_keepalive |
|
||||
| dht | udp | dht |
|
||||
| discord | udp | discord_ip_discovery |
|
||||
| stun | udp | stun |
|
||||
| dns | udp | dns_query<br>dns_response |
|
||||
| dtls | udp | dtls_client_hello<br>dtls_server_hello |
|
||||
|
||||
## Использование множественных профилей
|
||||
|
||||
Профили существуют, чтобы в зависимости от указанных условий фильтра выбрать ту или иную стратегию воздействия на трафик.
|
||||
@@ -972,6 +1012,16 @@ ipcache представляет собой структуру в памяти
|
||||
Домен может скакать по разным IP на CDN. Сейчас один адрес, через час - другой. Эта проблема решается через время жизни записей кэша : `--ipcache-lifetime`. По умолчанию 2 часа.
|
||||
Однако, может случиться и так, что в вашем случае применение техники несет больше пользы, чем проблем. Будьте готовы к непонятному на первый взгляд поведению, которое может быть исследовано только через `--debug` лог.
|
||||
|
||||
Имена хостов для кэширования берутся из анализа L7 протоколов и из DNS ответов (не DoH).
|
||||
Извлечение DNS работает только по udp протоколу и требует перенаправления пакетов с порта 53. Нужны только ответы DNS, имеющие source port 53.
|
||||
На Windows это будет `--wf-udp-in=53`. Скорее всего будет обращение к DNS внутри локальной сети, поэтому нужен параметр `--wf-filter-lan=0`.
|
||||
Если на Windows крутится какой-то dns proxy, а DNS настроен на localhost, потребуется еще и `--wf-filter-loopback=0`.
|
||||
На роутере, если используется шифрованный DNS, надо ловить запросы от клиента еще до шифрования - на LAN интерфейсе.
|
||||
Если шифрование не используется, можно ловить и на WAN.
|
||||
Для LAN интерфейса они будут исходящими, для интерфейса WAN - входящими, по направлению conntrack - reply.
|
||||
|
||||
При использовании [скриптов запуска](#скрипты-запуска) в Linux для перехвата DNS ответов существует [custom script](#custom-скрипты) `80-dns-intercept`. Его достаточно скопировать в "custom.d".
|
||||
|
||||
## Сигналы
|
||||
|
||||
- **SIGHUP** принудительно перечитывает все файлы хостлистов и ipset
|
||||
@@ -1068,7 +1118,7 @@ Lua код выполняется с ограниченными правами,
|
||||
Они бывают трех видов - `--payload`, `--in-range`, `--out-range`.
|
||||
Значения фильтров действуют с момента их указания до следующего переопределения.
|
||||
|
||||
- `--payload=type1[,type2][,type2]...` принимает список известных пейлоадов через зяпятую, "all" или "known". Список известных пейлоадов доступен в help тексте nfqws2. По умолчанию `--payload=all`.
|
||||
- `--payload=type1[,type2][,type2]...` принимает список известных пейлоадов через зяпятую, "all" или "known". [Список известных пейлоадов](#распознавание-протоколов). По умолчанию `--payload=all`.
|
||||
- `--(in-range|out-range)=[(n|a|d|s|p)<int>](-|<)[(n|a|d|s|p)<int>]` задает диапазоны счетчиков conntrack по входящему и исходящему направлениям. По умолчанию `--in-range=x`, `--out-range=a`.
|
||||
|
||||
Диапазоны задаются в формах : `mX-mY`, `mX<mY`, `-mY`, `<mY`, `mX-`, где m - режим счетчика, X - нижнее значение, Y - верхнее значение.
|
||||
@@ -1400,10 +1450,10 @@ desync
|
||||
| replay_piece | number | номер проигрываемой части | нумерация с 1 |
|
||||
| replay_piece_count | number | количество проигрываемых частей | |
|
||||
| replay_piece_last | bool | последняя проигрываемая часть | |
|
||||
| l7payload | string | тип пейлоада текущего пакета или группы пакетов. список возможных в help тексте nfqws2 | если неизвестно - unknown |
|
||||
| l7proto | string | тип протокола потока | если неизвестно - unknown |
|
||||
| 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, может не быть |
|
||||
@@ -1537,7 +1587,7 @@ ipv6 extension headers и tcp options представляются в форме
|
||||
| Поле | Тип | Описание | Примечание |
|
||||
| :------------- | :----- | :-------------------------------------------------------------- | :----------------------------------------------- |
|
||||
| incoming_ttl | number | ttl/hl первого входящего пакета по потоку | может не быть, если не определено |
|
||||
| l7proto | string | протокол потока. список возможных доступен в help тексте nfqws2 | есть всегда. если неизвестно - unknown |
|
||||
| l7proto | string | [протокол потока](#распознавание-протоколов) | есть всегда. если неизвестно - unknown |
|
||||
| hostname | string | имя хоста. определяется на основе анализа L6/L7 протоколов | появляется только после определения |
|
||||
| hostname_is_ip | bool | является ли hostname ip адресом | только если есть hostname |
|
||||
| lua_state | table | таблица для хранения состояния, привязанного к потоку | есть всегда, передается с каждым пакетом потока |
|
||||
@@ -1834,7 +1884,9 @@ nfqws2 не использует никакие криптобиблиотеки
|
||||
function bcryptorandom(size)
|
||||
```
|
||||
|
||||
Генерирует raw строку - криптографически стойкий блок случайных данных указанного размера. Источник - `/dev/random`
|
||||
Генерирует raw строку - криптографически стойкий блок случайных данных указанного размера. Источник - `/dev/random`.
|
||||
Если пул энтропии исчерпывается, может вызывать зависания. Чтобы этого не было - установите haveged или rngd.
|
||||
Не стоит использовать для получения случайных данных, не требующих крипто-стойкости.
|
||||
|
||||
#### hash
|
||||
|
||||
@@ -1905,6 +1957,34 @@ HKDF - HMAC-based Key Derivation Function. Генератор ключей на
|
||||
- okm_len - требуемая длина okm - output keying material
|
||||
- возвращается raw строка - okm
|
||||
|
||||
### Компрессия
|
||||
|
||||
#### gunzip
|
||||
|
||||
```
|
||||
function gunzip_init(windowBits)
|
||||
function gunzip_end(zstream)
|
||||
function gunzip_inflate(zstream, compressed_data, expected_uncompressed_chunk_size)
|
||||
```
|
||||
|
||||
* gunzip_init создает и возвращает контекст gzip потока для последующих вызовов других функций. Значение windowBits см. в документации по zlib (по умолчанию 47).
|
||||
* gunzip_end освобождает контекст gzip. может быть освобожден сборщиком мусора, но лучше вызывать явно.
|
||||
* gunzip_inflate разжимает очередную часть зипованных данных. Данные можно скармливать частями. Разжатые части конкатенируются для получения полных данных. Возвращается 2 аргумента : расжатые данные и bool признак конца gzip. В случае испорченных данных или при нехватке памяти возвращается nil.
|
||||
* expected_uncompressed_chunk_size - необязательный параметр для оптимизации выделения памяти под разжимаемые данные. Если буфера не хватает, вызываются realloc, копирующие блоки памяти и влияющие на производительность. Размер следует выбирать согласно ожидаемой степени сжатия с небольшим запасом. По умолчанию - четырехкратный размер compressed_data.
|
||||
|
||||
#### gzip
|
||||
|
||||
```
|
||||
function gzip_init(windowBits, level, memlevel)
|
||||
function gzip_end(zstream)
|
||||
function gzip_deflate(zstream, uncompressed_data, expected_compressed_chunk_size)
|
||||
```
|
||||
|
||||
* gzip_init создает и возвращает контекст gzip потока для последующих вызовов других функций. Значение windowBits см. в документации по zlib (по умолчанию 31). level - уровень сжатия от 1 до 9 (по умолчанию 9), memlevel - допустимый уровень использования памяти от 1 до 8 (по умолчанию 8).
|
||||
* gzip_end освобождает контекст gzip. может быть освобожден сборщиком мусора, но лучше вызывать явно.
|
||||
* gzip_deflate cжимает очередную часть данных. Данные можно скармливать частями. Cжатые части конкатенируются для получения полных данных. Для финализации потока по окончанию скармливания данных функция должна быть вызвана с uncompressed_data=nil или uncompressed_data="". Возвращается 2 аргумента : сжатые данные и bool признак конца gzip. При ошибках gzip или нехватке памяти возвращается nil.
|
||||
* expected_compressed_chunk_size - необязательный параметр для оптимизации выделения памяти под cжимаемые данные. Если буфера не хватает, вызываются realloc, копирующие блоки памяти и влияющие на производительность. Размер следует выбирать согласно ожидаемой степени сжатия с небольшим запасом. По умолчанию - половина размера uncompressed_data.
|
||||
|
||||
### Системные функции
|
||||
|
||||
#### uname
|
||||
@@ -2165,7 +2245,8 @@ function execution_plan(ctx)
|
||||
| func_n | number | номер инстанса внутри профиля |
|
||||
| func_instance | string | название инстанса | производная имени функции, номера инстанса и номера профиля |
|
||||
| range | table | эффективный диапазон [счетчиков](#внутрипрофильные-фильтры) `--in-range` или `--out-range` в зависимости от текущего направления |
|
||||
| payload_filter | string | эффективный `--payload-filter` . список названий пейлоадов через запятую |
|
||||
| payload | table | эффективный `--payload-filter` . таблица с индексами - названиями типа пейлоада |
|
||||
| payload_filter | string | эффективный `--payload-filter` . список названий пейлоадов через запятую (иное представление payload) |
|
||||
|
||||
**range**
|
||||
|
||||
@@ -2234,10 +2315,10 @@ function pktdebug(ctx, desync)
|
||||
function argdebug(ctx, desync)
|
||||
```
|
||||
|
||||
### posdebug
|
||||
|
||||
Вывести таблицу аргументов в debug log.
|
||||
|
||||
### posdebug
|
||||
|
||||
```
|
||||
function posdebug(ctx, desync)
|
||||
```
|
||||
@@ -2373,8 +2454,12 @@ function blob_or_def(desync, name, def)
|
||||
|
||||
```
|
||||
function barray(a, packer)
|
||||
function btable(a, packer)
|
||||
```
|
||||
|
||||
- barray использует только числовые индексы, начиная с 1. порядок соблюдается
|
||||
- btable использует все индексы, но не гарантирует порядок
|
||||
|
||||
Упаковка элементов массива a в порядке возрастания индекса от 1 до последнего.
|
||||
`packer` - функция, берущая элемент a и возвращающая raw string.
|
||||
Для числовых массивов в качестве packer можно использовать [функции паковки чисел](#bux).
|
||||
@@ -2463,12 +2548,17 @@ function dissect_nld(domain, level)
|
||||
```
|
||||
function http_dissect_req(http)
|
||||
function http_dissect_reply(http)
|
||||
function http_reconstruct_req(hdis, unixeol)
|
||||
```
|
||||
|
||||
Разборка HTTP запроса или ответа http. http представляет собой многострочный текст.
|
||||
Разборка представляет собой таблицу с вложенными подтаблицами.
|
||||
В заголовках выдаются позиции начала и конца названия заголовка и самого значения.
|
||||
Названия полей в таблице headers соответствуют названию заголовков в нижнем регисте. Все позиции - внутри строки http.
|
||||
Все позиции - внутри строки http.
|
||||
|
||||
Для нахождения хедеров по названию используйте [array_field_search](#array_search) по полю "header_low", которое содержит название хедера в нижнем регистре.
|
||||
|
||||
Реконструктор http запроса берет таблицу-разбор и воссоздает raw string. Параметр unixeol заменяет стандартный для http перевод сктроки 0D0A на 0A. Это нестандарт и ломает все сервера, кроме nginx.
|
||||
|
||||
<details>
|
||||
<summary><b>Пример разборки http запроса `http://testhost.com/testuri`</b></summary>
|
||||
@@ -2476,9 +2566,11 @@ function http_dissect_reply(http)
|
||||
.uri
|
||||
string /test_uri
|
||||
.headers
|
||||
.content-length
|
||||
.1
|
||||
.header
|
||||
string Content-Length
|
||||
.header_low
|
||||
string content-length
|
||||
.value
|
||||
string 330
|
||||
.pos_start
|
||||
@@ -2489,9 +2581,11 @@ function http_dissect_reply(http)
|
||||
number 56
|
||||
.pos_value_start
|
||||
number 59
|
||||
.host
|
||||
.2
|
||||
.header
|
||||
string Host
|
||||
.header_low
|
||||
string host
|
||||
.value
|
||||
string testhost.com
|
||||
.pos_start
|
||||
@@ -2512,26 +2606,30 @@ function http_dissect_reply(http)
|
||||
.code
|
||||
number 200
|
||||
.headers
|
||||
.content-type
|
||||
.1
|
||||
.pos_header_end
|
||||
number 28
|
||||
.pos_value_start
|
||||
number 31
|
||||
.header
|
||||
string Content-Type
|
||||
.header_low
|
||||
string content-type
|
||||
.value
|
||||
string text/html
|
||||
.pos_start
|
||||
number 17
|
||||
.pos_end
|
||||
number 39
|
||||
.content-length
|
||||
.2
|
||||
.pos_header_end
|
||||
number 54
|
||||
.pos_value_start
|
||||
number 57
|
||||
.header
|
||||
string Content-Length
|
||||
.header_low
|
||||
string content-length
|
||||
.value
|
||||
string 650
|
||||
.pos_start
|
||||
@@ -2558,7 +2656,9 @@ function tls_reconstruct(tdis)
|
||||
7. Если есть record layer, реконструкция выполняется согласно длинам отдельных records. Если последняя часть не влезает, tls record расширяется под оставшиеся данные.
|
||||
8. При отсутствии изменений dissect+reconstruct дают бинарно идентичные блобы.
|
||||
|
||||
Функции не работают с DTLS. В случае ошибки возвращается nil.
|
||||
Функции не работают с DTLS.
|
||||
|
||||
`tls_dissect` возвращает таблицу - разбор raw строки tls со смещения offset (начиная с 1), `reconstruct_dissect` возвращает raw строку собранного разбора tdis. В случае ошибки возвращается nil.
|
||||
|
||||
Простейший способ получить образец диссекта : `--payload=tls_client_hello --lua-desync=luaexec:code="var_debug(tls_dissect(desync.reasm_data))"`.
|
||||
И вызвать TLS запрос.
|
||||
@@ -2872,13 +2972,15 @@ function tls_reconstruct(tdis)
|
||||
Для некоторых элементов заполняется поле "name". Оно служит для удобства визуального анализа и больше ни для чего не используется.
|
||||
Первичными являются поля type.
|
||||
|
||||
Для нахождения значений в списках используйте [функции поиска в массивах](#служебные-функции).
|
||||
Для нахождения значений в списках используйте [функции поиска в массивах](#array_search).
|
||||
|
||||
Множество констант, связанных с TLS, определено в `zapret-lib.lua`. Прежде чем писать фиксированные значения, посмотрите нет ли нужной константы.
|
||||
|
||||
Таблица handshake индексируется по типу hadnshake. Самыми типичными являются `TLS_HANDSHAKE_TYPE_CLIENT` и `TLS_HANDSHAKE_TYPE_SERVER`.
|
||||
Таблица handshake индексируется по типу handshake. Самыми типичными являются `TLS_HANDSHAKE_TYPE_CLIENT` и `TLS_HANDSHAKE_TYPE_SERVER`.
|
||||
Они имеют значения 1 и 2 соответственно, поэтому может показаться, что элементы handshake идут от 1 и по возрастающей. Это не так.
|
||||
|
||||
extensions и другие списки индексируются по номеру с 1, а не по типу, потому что важен порядок их следования, и может быть несколько элементов одного типа.
|
||||
|
||||
Если вы что-то добавляете свое, вам нужно воспроизвести минимальный вариант исходной структуры.
|
||||
Можно заполнить только raw data field. Если нет подтаблицы dis - при реконструкции будет взято оно.
|
||||
Если есть dis, то он должен быть заполнен корректно согласно рассматриваемому элементу данных.
|
||||
@@ -3000,6 +3102,51 @@ function writeable_file_name(filename)
|
||||
- writeable_file_name возвращает filename, если filename содержит абсолютный путь или env `WRITEABLE` отсутствует.
|
||||
Иначе берется путь из env `WRITEABLE` и к нему дописывается имя файла filename через append_path.
|
||||
|
||||
## Чтение и запись файлов
|
||||
|
||||
```
|
||||
function readfile(filename)
|
||||
```
|
||||
|
||||
Читает весь файл. Вызывается error в случае ошибки при открытии или чтении файла.
|
||||
|
||||
```
|
||||
function z_readfile(filename, expected_ratio)
|
||||
```
|
||||
|
||||
Автоматически определяет является ли файл gzip. Если да - разжимает, если нет - читает без изменений. Вызывается error в случае ошибки при открытии или чтении файла.
|
||||
expected_ratio - ожидаемое соотношение длины разжатых данных к длине сжатых данных (по умолчанию 4).
|
||||
|
||||
```
|
||||
function writefile(filename, data)
|
||||
```
|
||||
|
||||
Записывает data в файл. Вызывается error в случае ошибки при открытии файла.
|
||||
|
||||
|
||||
## Компрессия данных
|
||||
|
||||
```
|
||||
function is_gzip_file(filename)
|
||||
```
|
||||
|
||||
true, если файл является gzip, иначе false. При ошибке открытия файла вызывается error.
|
||||
|
||||
```
|
||||
function gunzip_file(filename, expected_ratio, read_block_size)
|
||||
```
|
||||
|
||||
Разжимает файл и возвращает raw string. В случае ошибки открытия или чтения файла вызывается error. При нехватке памяти возвращается nil. read_block_size - частями какого размера читается файл (по умолчанию 16K).
|
||||
expected_ratio - ожидаемое соотношение длины разжатых данных к длине сжатых данных (по умолчанию 4).
|
||||
|
||||
```
|
||||
function gzip_file(filename, data, expected_ratio, level, memlevel, compress_block_size)
|
||||
```
|
||||
|
||||
Сжимает raw строку в gzip файл. В случае ошибки открытия или чтения файла вызывается error. При испорченных gzip данных или нехватке памяти возвращается nil.
|
||||
level - уровень сжатия от 1 до 9 (по умолчанию 9), memlevel - допустимый уровень использования памяти от 1 до 8 (по умолчанию 8). compress_block_size - частями какого размера жмется файл (по умолчанию 16K).
|
||||
expected_ratio - ожидаемое соотношение длины разжатых данных к длине сжатых данных (по умолчанию 2).
|
||||
|
||||
## autottl
|
||||
|
||||
```
|
||||
@@ -3064,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 добавляются в следующем порядке:
|
||||
@@ -3183,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
|
||||
|
||||
```
|
||||
@@ -3216,7 +3368,8 @@ function payload_match_filter(l7payload, l7payload_filter, def)
|
||||
function payload_check(desync, def)
|
||||
```
|
||||
|
||||
Функции работают со строкой - списком пейлоадов через запятую. Список известных типов пейлоада можно получить из help текста nfqws2. Все пустые пакеты имеют пейлоад empty, неизвестные - unknown. Особые значения - all и known. all означает любой пейлоад, known - не unknown и не empty. Префикс `~` в начале означает логическую инверсию - несоответствие списку.
|
||||
Функции работают со строкой - списком пейлоадов через запятую. Особые значения - all и known. all означает любой пейлоад, known - не unknown и не empty. Префикс `~` в начале означает логическую инверсию - несоответствие списку.
|
||||
См. [распознавание протоколов](#распознавание-протоколов).
|
||||
|
||||
- payload_match_filter проверяет соответствие l7payload списку l7payload_filter или def, если l7payload_filter=nil. Если оба nil - список берется как "known".
|
||||
- payload_check вызывает `payload_match_filter(desync.l7payload, desync.arg.payload, def)`
|
||||
@@ -3365,7 +3518,7 @@ nfqws2 ничего не знает о том, что нужно `--lua-desync`
|
||||
|
||||
### standard payload
|
||||
|
||||
Фильтр по пейлоаду берет список типов пейлоада. Список известных типов пейлоада можно получить из help текста nfqws2. Все пустые пакеты имеют пейлоад empty, неизвестные - unknown. Особые значения - all и known. all означает любой пейлоад, known - не unknown и не empty.
|
||||
Фильтр по пейлоаду берет список [типов пейлоада](#распознавание-протоколов).
|
||||
|
||||
**standard payload**
|
||||
|
||||
@@ -3447,6 +3600,17 @@ function http_methodeol(ctx, desync)
|
||||
- arg: [standard direction](#standard-direction)
|
||||
|
||||
Вставляет '\r\n' перед методом, отрезая 2 последних символа из содержимого заголовка `User-Agent:`. Работает только на nginx, остальные сервера ломает.
|
||||
Если используется совместно с другими функциями http тамперинга, должен идти последним.
|
||||
|
||||
### http_unixeol
|
||||
|
||||
```
|
||||
function http_unixeol(ctx, desync)
|
||||
```
|
||||
|
||||
- arg: [standard direction](#standard-direction)
|
||||
|
||||
Заменяет перевод строки 0D0A на 0A. Разницу в длине добавляет пробелами в конец хедера "User-Agent". Работает только на nginx, остальные сервера ломает.
|
||||
|
||||
## Замена window size
|
||||
|
||||
@@ -3830,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, в силу простоты данного протокола. С ним особо нечего делать.
|
||||
@@ -3853,7 +4052,7 @@ function udplen(ctx, desync)
|
||||
- arg: pattern_offset - начальное смещение внутри pattern
|
||||
- payload фильтр по умолчанию - "known"
|
||||
|
||||
Функция увеличивает или уменьшает длину L4 пейлоада udp. При уменьшении часть информации обрезается и теряется, при увеличении - заполняется pattern. Сегментация udp невозможна - при превышении MTU или PMTU пакет не дойдет до адресата. Ошибка в случае превышения MTU будет только на Linux, остальные системы молча не отправят пакет (windivert и ipdivert не имеют средств обнаружения ошибки).
|
||||
Функция увеличивает или уменьшает длину L4 пейлоада udp. При уменьшении часть информации обрезается и теряется, при увеличении - заполняется pattern. Сегментация udp невозможна - при превышении MTU или PMTU ОС выполнит фрагментацию на уровне IP. Ошибка в случае превышения MTU будет только на Linux, остальные системы молча не отправят пакет (windivert и ipdivert не имеют средств обнаружения ошибки).
|
||||
|
||||
### dht_dn
|
||||
|
||||
@@ -3935,7 +4134,7 @@ function standard_hostkey(desync)
|
||||
### automate_host_record
|
||||
|
||||
```
|
||||
function automate_conn_record(desync)
|
||||
function automate_host_record(desync)
|
||||
```
|
||||
|
||||
- arg: key - ключ внутри глобальной таблицы autostate. если не задано, в качестве ключа используется имя текущего инстанса
|
||||
@@ -4211,8 +4410,10 @@ ip2net фильтрует входные данные, выкидывая неп
|
||||
Она берет из stdin список доменов и выводит в stdout результат ресолвинга. Ошибки выводятся в stderr.
|
||||
|
||||
```
|
||||
--threads=<threads_number> ; количество потоков. по умолчанию 1.
|
||||
--family=<4|6|46> ; выбор семейства IP адресов : ipv4, ipv6, ipv4+ipv6
|
||||
--threads=<threads_number> ; количество потоков. по умолчанию 1.
|
||||
--eagain=<eagain_retries> ; количество попыток повтора после EAI_AGAIN. по умолчанию 10
|
||||
--eagain-delay=<ms> ; время ожидания в мсек между повторами по EAI_AGAIN. по умолчанию 500.
|
||||
--verbose ; дебаг-лог на консоль
|
||||
--stats=N ; выводить статистику каждые N доменов
|
||||
--log-resolved=<file> ; сохранять успешно отресолвленные домены в файл
|
||||
@@ -4428,10 +4629,14 @@ SEQOVL_PATTERN_HTTPS - путь к файлу с seqovl pattern для https
|
||||
MULTIDISORDER=multidisorder_legacy - заменить multidisorder на вариант из nfqws1
|
||||
|
||||
NOTEST_BASIC_HTTP=1 - отмена тестов 10-http-basic.sh
|
||||
NOTEST_MISC_HTTP=1 - отмена тестов http 15-misc.sh
|
||||
NOTEST_MISC_HTTPS=1 - отмена тестов https 15-misc.sh
|
||||
NOTEST_MULTI_HTTP=1 - отмена тестов http 20-multi.sh
|
||||
NOTEST_MULTI_HTTPS=1 - отмена тестов https 20-multi.sh
|
||||
NOTEST_SEQOVL_HTTP=1 - отмена тестов http 23-seqovl.sh
|
||||
NOTEST_SEQOVL_HTTPS=1 - отмена тестов https 23-seqovl.sh
|
||||
NOTEST_SYNDATA_HTTP=1 - отмена тестов http 24-syndata.sh
|
||||
NOTEST_SYNDATA_HTTPS=1 - отмена тестов https 24-syndata.sh
|
||||
NOTEST_FAKE_HTTP=1 - отмена тестов http 25-fake.sh
|
||||
NOTEST_FAKE_HTTPS=1 - отмена тестов https 25-fake.sh
|
||||
NOTEST_FAKED_HTTP=1 - отмена тестов http 25-faked.sh
|
||||
@@ -4451,6 +4656,10 @@ NOTEST_QUIC=1 - отмена тестов 90-quic.sh
|
||||
|
||||
Простой тестировщик по списку стратегий из файлов. Стратегии должны быть на отдельных строчках, переносы строки не допускаются. Используются отдельные списки для протоколов - `list_http.txt`, `list_https_tls12.txt`, `list_https_tls13.txt`, `list_quic.sh`. В файлах поддерживаются комментарии, начинающиеся на `#`.
|
||||
|
||||
При записи параметров следует учитывать, что они будут интерпретироваься как параметры shell. Специальные символы нужно экранировать по правилам shell.
|
||||
Если вы оставите "<" без кавычек на всем параметре или возьмете в кавычки параметр `--luaexec=code=print("abc")`, будет ошибка. Если в lua коде используются строки - их стоит заключать в одинарные кавычки, а вокруг параметра - двойные.
|
||||
blockcheck2 будет выдавать параметры стратегий без экранирования.
|
||||
|
||||
Самый правильный способ применения - скопировать в свою поддиректорию внутри `blockcheck2.d` и заполнить txt файлы с тестами. Выбрать свое имя теста в диалоге.
|
||||
|
||||
## Summary
|
||||
@@ -4501,13 +4710,17 @@ SIM_SUCCESS_RATE=<percent> - вероятность успеха симуляц
|
||||
blockcheck проверяет доступность одного отдельно взятого "domain[/uri]" с отдельно взятым протоколом, не более.
|
||||
Броузер делает куда больше. В чем же разница ?
|
||||
|
||||
1. Может все начинаться с DNS. blockcheck использует системный или doh, а броузер - наоборот. Такие сайты, как instagram, частично заблокированы по IP. Успех зависит от того, какой именно IP выдается конкретным DNS.
|
||||
1. Может все начинаться с DNS. blockcheck использует системный или doh, а броузер - наоборот. Такие сайты, как instagram, частично заблокированы по IP. Успех зависит от того, какой именно IP выдается конкретным DNS. Если же у вас DNS отравлен провайдером, а ваш клиент не поддерживает шифрованный DNS, то это сразу конец всем обходам. Вы пойдете на IP адрес заглушки, и , естественно, никакой zapret не поможет. Бывает, провайдер вообще не выдает DNS ответ на заблокированный домен или выдает 127.0.0.1.
|
||||
2. Сайт - это не один домен и не один URI. Жмете F12 в броузере и во вкладке "сеть" смотрите куда лезет сайт. Он может споткнуться на другом домене.
|
||||
3. Цель броузера - открыть сайт как можно быстрее, не нагружая пользователя техническими терминами, которые для него неотличимы от китайского языка. Поэтому он лезет на сайт по разным протоколам так, чтобы страница открылась быстрее. Может скакать между ipv4 и ipv6, между tls и quic. Уже 4 комбинации. А ведь для каждого из них отдельный тест блокчека. Все ли они пробились одной стратегией ? Корректно ли вы перенесли эти стратегии в рабочий конфиг ? Правильно ли их обьединили ?
|
||||
4. Отдельный важный параметр - kyber. Постквантовая криптография, которая однопакетный запрос TLS/QUIC превращает в 2 или 3 пакетный. Само по себе фактор при обходе DPI. Современные броузеры обычно используют kyber. curl - зависит от его старости и от старости криптобиблиотеки, с которой он слинкован. OpenSSL 3.5.0 выдает kyber, старее - нет. LibreSSL или mbedTLS не выдают kyber. Сейчас. А завтра выдадут, потому что тренд идет в ту сторону.
|
||||
5. Блокираторы ничем не брезгуют. Бывает они даже привязываются к фингерприту клиента. Что это такое ? Наличие/порядок tls extensions прежде всего, характерный для броузера или curl.
|
||||
6. Знаменитый "16 кб" блок. Как проверить 16 кб блок ? Дернуть curl какой-то URI, на котором сайт выдаст достаточно длинную страницу. Если загрузка виснет посередине - это оно. Поставлена задача загнать всех под российскую юрисдикцию, а для этого гнобят крупные хостинги - cloudfare, hetzner, akamai, aws и другие. Им надо оставить несколько важных сайтов. hp.com - откуда еще драйвера для LaserJet качать ? А hp на одном из таких хостингов. Получается белый список. Следовательно, вам нужен пейлоад, который ему удовлетворяет. Но беда в том, что блокчек , как и сам zapret, - всего лишь инструмент. Он не включает в себя готовых рецептов. Вам самим нужно искать чем пробивать конкретные хостинги. Сейчас это так, а завтра будет еще что-то другое. Автор не будет гнаться за ситуацией, не будет оперативно менять блокчек, чтобы он вам выдавал готовые copy+paste рецепты. Вам нужно самим смотреть на ситуацию и искать решение. Сегодня белые списки в стиле "16 кб" пробиваются или белым SNI, или каким-то другим белым типом протокола, не TLS. Завтра будет что-то другое. [Стандартный чекер](#тест-standard) берет целый список переменных для кустомизации сканирования. Есть возможность подсунуть [что-то до и что-то после](#shell-переменные) стратегии. Наконец, свет клином не сошелся на блокчеке. Иногда удобнее вручную проверять.
|
||||
7. Ходит информации о поведении DPI в стиле "наказать шалуна". DPI видит попытки его задурить и на некоторое время блокирует доступ по IP. Раз-два прошло, потом никакие конекты не проходят. Если IP динамический, помогает переподключение к линии провайдера, но лишь до новой попытки. Автор не сталкивался с подобными блокировками, но сами динамические блокировки - это тот путь, которым прошел Китай. В России тоже можно ожидать.
|
||||
5. Блокираторы ничем не брезгуют. Бывает они даже привязываются к фингерприту клиента. Что это такое ? Наличие/порядок tls extensions прежде всего, характерный для броузера или curl. Никак нельзя забанить IP адреса, но нужно устранить очередной новый VPN клиент ? Смотрят его handshake, находят уникальные особенности и рубят по ним. Заодно отрубается что-то еще. Но им на это уже плевать.
|
||||
6. ECH - технология зашифрованной передачи SNI, чтобы блокираторы не видели к какому ресурсу обращаются. Технология отличная, но, к сожалению, запоздавшая. Точка, когда технология уже окончательно вьелась в стандарты де-факто, не была пройдена. Поэтому могут банить как по самому наличию ECH, так и по внешнему SNI-заглушке. На cloudflare это "cloudflare-ech.com". curl дергает сайт без ECH, а броузер может с ним - вот и разница.
|
||||
7. Версия TLS протокола. По умолчанию blockcheck2 тестирует TLS 1.2 как самый тяжелый для обхода вариант. Броузер скорее всего полезет по TLS 1.3. Были случаи, когда блокираторы намеренно банили протокол TLS 1.3, потому что его использует и требует популярный метод обхода через VLESS-REALITY. Уровень пофигизма на сопутствующий ущерб уже настолько высок, что поломка множества легальных ресурсов их не останавливает.
|
||||
8. Знаменитый "16 кб" блок. Как проверить 16 кб блок ? Дернуть curl какой-то URI, на котором сайт выдаст достаточно длинную страницу. Если загрузка виснет посередине - это оно. По умолчанию blockcheck2 на https использует HEAD, чтобы не мучать сервер и экономить трафик - все равно под https ничего не видно. Это можно поменять через [CURL_HTTPS_GET=1](#shell-переменные). Но так вы скорее всего начнете получать сплошные "UNAVAILABLE". Стандартный вариант дает стратегии, которые будут работать при обходе 16кб блока, поэтому более информативен. Почему же они это делают ? Поставлена задача загнать всех под российскую юрисдикцию, а для этого гнобят крупные хостинги - cloudfare, hetzner, akamai, aws и другие. CDN часто используются для скрытого проброса прокси или VPN. Им надо оставить несколько важных сайтов. hp.com - откуда еще драйвера для LaserJet качать ? А hp на одном из таких хостингов. Получается белый список. Следовательно, вам нужен пейлоад, который ему удовлетворяет. Но беда в том, что блокчек , как и сам zapret, - всего лишь инструмент. Он не включает в себя готовых рецептов. Вам самим нужно искать чем пробивать конкретные хостинги. Сейчас это так, а завтра будет еще что-то другое. Автор не будет гнаться за ситуацией, не будет оперативно менять блокчек, чтобы он вам выдавал готовые copy+paste рецепты. Вам нужно самим смотреть на ситуацию и искать решение. Сегодня белые списки в стиле "16 кб" пробиваются или белым SNI, или каким-то другим белым типом протокола, не TLS. Завтра будет что-то другое. [Стандартный чекер](#тест-standard) берет целый список переменных для кустомизации сканирования. Есть возможность подсунуть [что-то до и что-то после](#shell-переменные) стратегии. Наконец, свет клином не сошелся на блокчеке. Иногда удобнее вручную проверять.
|
||||
9. В продолжение предыдущего пункта - широко развилась практика вводить особые правила на диапазонах IP адресов. Поэтому вы можете найти стратегию, работающую для большинства ресурсов, но на некоторых она работать не будет.
|
||||
10. Ходит информация о поведении DPI в стиле "наказать шалуна". DPI видит попытки его задурить и на некоторое время блокирует доступ по IP. Раз-два прошло, потом никакие конекты не проходят. Если IP динамический, помогает переподключение к линии провайдера, но лишь до новой попытки. Другой вариант - отправка udp пакета на триггерный IP (например, через торрент клиент) и последующий блок некоторых IP диапазонов. Автор не сталкивался с подобными блокировками, но сами динамические блокировки - это тот путь, которым прошел Китай. В России тоже можно ожидать.
|
||||
11. Нестабильность стратегии. Балансировка на провайдерах - явление частое. Трафик может идти то через один DPI, то через другой, и стратегия может работать через раз. blockcheck2 по умолчанию тестирует только одну попытку. Если есть сомнения в стабильности - следует увеличить количество попыток минимум до 5. Можно использовать [PARALLEL=1](#shell-переменные), но это может привести к срабатыванию защиты самого ресурса от долбежки.
|
||||
|
||||
Гланая цель блокираторов - устранить массовое нарушение их блокировок.
|
||||
Если 99% нажимает на кнопку, и она не срабатывает, для них решение не работает.
|
||||
@@ -4541,6 +4754,8 @@ nfqws2 может работать и самостоятельно без скр
|
||||
| IPSET_HOOK | скрипт, который получает имя ipset в $1, выдает в stdout список ip, и они добавляются в ipset |
|
||||
| IP2NET_OPT4<br>IP2NET_OPT6 | настройки ip2net для скриптов получения ip листов |
|
||||
| MDIG_THREADS | количество потоков mdig. используется при ресолвинге хостлистов |
|
||||
| MDIG_EAGAIN | количество попыток при получении EAI_AGAIN |
|
||||
| MDIG_EAGAIN_DELAY | задержка в мсек между попытками при получении EAI_AGAIN |
|
||||
| AUTOHOSTLIST_INCOMING_MAXSEQ<br>AUTOHOSTLIST_RETRANS_MAXSEQ<br>AUTOHOSTLIST_RETRANS_THRESHOLD<br>AUTOHOSTLIST_RETRANS_RESET<br>AUTOHOSTLIST_FAIL_THRESHOLD<br>AUTOHOSTLIST_FAIL_TIME<br>AUTOHOSTLIST_UDP_IN<br>AUTOHOSTLIST_UDP_OUT | параметры [автохостлистов](#детектор-неудач-автохостлистов) |
|
||||
| AUTOHOSTLIST_DEBUGLOG | включение autohostlist debug log. лог пишется в `ipset/zapret-hosts-auto-debug.log` |
|
||||
| GZIP_LISTS | применять ли сжатие gzip для генерируемых хост и ip листов |
|
||||
@@ -4588,6 +4803,9 @@ ip листы разделяются на ipv4 и ipv6. ipv6 листы имею
|
||||
|
||||
В зависимости от режима хостлисты могут ресолвиться в ip листы через [mdig](#mdig) или применяться как есть. Если хостлисты применяются как есть в nfqws2, учитываются только имена доменов, а IP адреса и подсети - нет.
|
||||
|
||||
Включающие ip листы загоняются в сеты ядра и применяются в правилах таблиц только, если указан [MODE_FILTER=ipset](#файл-config).
|
||||
Исключающий ip лист загоняется в сеты ядра и применяется всегда в правилах таблиц.
|
||||
|
||||
| Хостлист | Тип | Назначение | ip листы |
|
||||
| :---------------------------- | :--------------- | :-------------- | :---------------------------------------------------- |
|
||||
| zapret-hosts-user.txt | пользовательский | включающий | zapret-ip-user.txt<br>zapret-ip-user6.txt |
|
||||
@@ -4696,8 +4914,8 @@ create_ipset no-update
|
||||
| start<br>stop<br>restart | запуск/останов/перезапуск демонов и firewall. firewall не запускается, если [INIT_APPLY_FW](#файл-config) не равно 1. На openwrt с fw3 (iptables) firewall запускается отдельно, команды работают только с демонами и не трогают firewall |
|
||||
| start_daemons<br>stop_daemons<br>restart_daemons | запуск/останов/перезапуск демонов |
|
||||
| start_fw<br>stop_fw<br>restart_fw | запуск/останов/перезапуск firewall. На openwrt с fw3 (iptables) команды работают, но firewall запускается отдельно через firewall include в `/etc/config/firewall`. Отдельные операции не рекомендованы. |
|
||||
| reload_ifsets | (только для nftables) перезагрузка сетов wanif и wanif6 |
|
||||
| list_ifsets | (только для nftables) показ wanif, wanif6 и flowtable |
|
||||
| reload_ifsets | (только для nftables) перезагрузка сетов wanif, wanif6, lanif |
|
||||
| list_ifsets | (только для nftables) показ wanif, wanif6, lanif и flowtable |
|
||||
| list_table | (только для nftables) показ таблицы zapret2 |
|
||||
|
||||
sysv вариант предназначен для любых Linux, не являющихся OpenWRT. На системах с различными системами запуска все равно работает sysv скрипт, а прикрутка к системам запуска представляет собой лишь адаптер, его запускающий. На системах с неподдерживаемыми системами запуска и на прошивках вы сами должны знать куда прикрутить "zapret2 start" и "zapret2 stop", чтобы работал автостарт и останов в рамках вашей системы запуска.
|
||||
@@ -4712,7 +4930,7 @@ sysv вариант предназначен для любых Linux, не яв
|
||||
|
||||
#### Интеграция с OpenWRT firewall
|
||||
|
||||
Готовая интеграция с firewall имеется для OpenWRT. Скрипты запуска автоматически определяют fw3 и отключат управление firewall через start/stop/restart. Вместо этого в `/etc/config/firewall` прописывается firewall include `firewall.zapret2`, который и запускает правила zapret синхронно после поднятия fw3. Дополнительно вешается хук `90-zapret2` в `/etc/hotplug.d/iface` на поднятие/опускание интерфейсов. В варианте fw3 происходит рестарт fw3, чтобы правила применились к новым интерфейсам или наоборот - были удалены для более несуществующих интерфейсов. В варианте nftables происходит лишь перезагрузка сетов wanif, wanif6 и flowtable.
|
||||
Готовая интеграция с firewall имеется для OpenWRT. Скрипты запуска автоматически определяют fw3 и отключат управление firewall через start/stop/restart. Вместо этого в `/etc/config/firewall` прописывается firewall include `firewall.zapret2`, который и запускает правила zapret синхронно после поднятия fw3. Дополнительно вешается хук `90-zapret2` в `/etc/hotplug.d/iface` на поднятие/опускание интерфейсов. В варианте fw3 происходит рестарт fw3, чтобы правила применились к новым интерфейсам или наоборот - были удалены для более несуществующих интерфейсов. В варианте nftables происходит лишь перезагрузка сетов wanif, wanif6, lanif и flowtable.
|
||||
|
||||
### custom скрипты
|
||||
|
||||
@@ -4723,7 +4941,7 @@ sysv вариант предназначен для любых Linux, не яв
|
||||
custom скрипт может иметь следующие shell функции, которые вызываются системой запуска :
|
||||
|
||||
- **zapret_custom_daemons** - поднятие и останов демонов. $1 = 1 - поднятие, 0 - останов.
|
||||
- **zapret_custom_firewall** - поднятие и снятие правил iptables. $1 - поднятие, 0 - снятие.
|
||||
- **zapret_custom_firewall** - поднятие и снятие правил iptables. $1 = 1 - поднятие, 0 - снятие.
|
||||
- **zapret_custom_firewall_nft** - поднятие правил nftables. останов не требуется, поскольку основной код при останове очищает цепочки nft вместе с custom правилами.
|
||||
- **zapret_custom_firewall_nft_flush** - вызывается при останове nftables, чтобы можно было удалить обьекты, выходящие за рамки стандартных цепочек - такие, как собственные set-ы или собственные цепочки.
|
||||
|
||||
@@ -4904,6 +5122,11 @@ nft_reverse_nfqws_rule()
|
||||
Замена элементов nftables фильтра с прямого на обратное направление - меняется dst на src. Результат выводится в stdout.
|
||||
|
||||
```
|
||||
nft_add_chain()
|
||||
# $1 - имя цепочки
|
||||
# $2 - параметры внутри { }
|
||||
nft_delete_chain()
|
||||
# $1 - имя цепочки
|
||||
nft_create_set()
|
||||
# $1 - имя сета
|
||||
# $2 - параметры внутри { }
|
||||
@@ -4972,13 +5195,13 @@ ln -s /opt/zapret2/init.d/openwrt/zapret2 /etc/init.d
|
||||
/etc/init.d/zapret2 enable
|
||||
```
|
||||
|
||||
1. Обновление правил firewall по событию поднятия/опускания интерфейсов.
|
||||
2. Обновление правил firewall по событию поднятия/опускания интерфейсов.
|
||||
|
||||
```
|
||||
ln -s /opt/zapret2/init.d/openwrt/90-zapret2 /etc/hotplug.d/iface
|
||||
```
|
||||
|
||||
1. (только для fw3) Интеграция с firewall.
|
||||
3. (только для fw3) Интеграция с firewall.
|
||||
|
||||
```
|
||||
ln -s /opt/zapret2/init.d/openwrt/firewall.zapret2 /etc
|
||||
@@ -4988,7 +5211,7 @@ uci set firewall.@include[-1].reload=1
|
||||
uci commit
|
||||
```
|
||||
|
||||
1. Обновление листов - cron job на вызов `/opt/zapret2/ipset/get_config.sh` ночью в случайное время каждые 2 дня - для обновления листов. Рассчет идет на роутер, работающий круглосуточно.
|
||||
4. Обновление листов - cron job на вызов `/opt/zapret2/ipset/get_config.sh` ночью в случайное время каждые 2 дня - для обновления листов. Рассчет идет на роутер, работающий круглосуточно.
|
||||
|
||||
### Шпаргалка OpenWRT
|
||||
|
||||
@@ -5009,7 +5232,7 @@ systemctl daemon-reload
|
||||
systemctl enable zapret2
|
||||
```
|
||||
|
||||
1. Таймер для обновления листов - в случайное время суток каждые 2 дня. Рассчет идет на любую систему, в том числе десктопную, которую могут включать только днем.
|
||||
2. Таймер для обновления листов - в случайное время суток каждые 2 дня. Рассчет идет на любую систему, в том числе десктопную, которую могут включать только днем.
|
||||
|
||||
```
|
||||
cp /opt/zapret2/init.d/systemd/zapret2-list-update.* /lib/systemd/system
|
||||
@@ -5036,7 +5259,7 @@ ln -s /opt/zapret2/init.d/openrc/zapret2 /etc/init.d
|
||||
rc-update add zapret2
|
||||
```
|
||||
|
||||
1. Обновление листов - cron job на вызов `/opt/zapret2/ipset/get_config.sh` днем в случайное время каждые 2 дня. Рассчет идет на любую систему, в том числе десктопную, которую могут включать только днем.
|
||||
2. Обновление листов - cron job на вызов `/opt/zapret2/ipset/get_config.sh` днем в случайное время каждые 2 дня. Рассчет идет на любую систему, в том числе десктопную, которую могут включать только днем.
|
||||
|
||||
### Шпаргалка openrc
|
||||
|
||||
@@ -5061,3 +5284,114 @@ rc-update add zapret2
|
||||
8. Перезапуск : `systemctl restart nfqws2@INSTANCE`
|
||||
|
||||
Этот способ не поднимает правила ip/nf tables - вам это придется сделать отдельно, как и написать сами правила. Правила нужно прописать куда-то, чтобы они поднимались после старта системы. Например, можно сделать отдельный systemd unit с запуском шелл скрипта или `nft -f /path/to/file.nft`.
|
||||
|
||||
# Другие прошивки
|
||||
|
||||
Для статических бинарников не имеет значения на чем они запущены: PC, android, приставка, роутер, любой другой девайс.
|
||||
Подойдет любая прошивка, дистрибутив Linux. Статические бинарники запустятся на всем.
|
||||
Им нужно только ядро с необходимыми опциями сборки или модулями.
|
||||
Но кроме бинарников в проекте используются еще и скрипты, в которых задействуются некоторые
|
||||
стандартные программы.
|
||||
|
||||
Основные причины почему нельзя просто так взять и установить эту систему на что угодно:
|
||||
* отсутствие доступа к девайсу через shell
|
||||
* отсутствие рута
|
||||
* отсутствие раздела r/w для записи и энергонезависимого хранения файлов
|
||||
* отсутствие возможности поставить что-то в автозапуск
|
||||
* отсутствие cron
|
||||
* неотключаемый flow offload или другая проприетарщина в netfilter
|
||||
* недостаток модулей ядра или опций его сборки
|
||||
* недостаток модулей iptables (/usr/lib/iptables/lib*.so)
|
||||
* недостаток стандартных программ (типа ipset, curl) или их кастрированность (облегченная замена)
|
||||
* кастрированный или нестандартный шелл sh
|
||||
|
||||
Если в вашей прошивке есть все необходимое, то вы можете адаптировать zapret под ваш девайс в той или иной степени.
|
||||
|
||||
Пересобрать ядро или модули для него будет скорее всего достаточно трудно.
|
||||
Для этого вам необходимо будет по крайней мере получить исходники вашей прошивки.
|
||||
User mode компоненты могут быть привнесены относительно безболезненно, если есть место куда их записать.
|
||||
Специально для девайсов, имеющих область r/w, существует проект entware.
|
||||
Некоторые прошивки даже имеют возможность его облегченной установки через веб интерфейс.
|
||||
entware содержит репозиторий user-mode компонент, которые устанавливаются в /opt.
|
||||
С их помощью можно компенсировать недостаток ПО основной прошивки, за исключением ядра.
|
||||
|
||||
Можно попытаться использовать [sysv init script](#стартовые-скрипты).
|
||||
В случае ругани на отсутствие каких-то базовых программ, их следует восполнить посредством entware.
|
||||
Перед запуском скрипта путь к дополнительным программам должен быть помещен в PATH.
|
||||
|
||||
Обратите внимание, что entware патчен на предмет замены стандартных путей файлов типа /etc/passwd на /opt/etc/passwd.
|
||||
Статические бинарники zapret собраны без учета этой особенности, поэтому оцпия --user может не работать - юзер ищется в /etc/passwd,
|
||||
который находится на r/o разделе, в том время как adduser добавляет юзеров в /opt/etc/passwd.
|
||||
Поэтому может понадобиться раскомментировать в [config](#файл-config) WS_USER и указать юзера, который есть в /etc/passwd.
|
||||
|
||||
Для keenetic существуют дополнительные важные особенности, без учета которых zapret будет "слетать" каждые несколько минут или не работать с udp.
|
||||
Существуют готовые сторонние решения по интеграции с keenetic.
|
||||
|
||||
Подробное описание настроек для других прошивок выходит за рамки данного проекта.
|
||||
|
||||
OpenWrt является одной из немногих относительно полноценных linux систем для embedded devices.
|
||||
Она характеризуется следующими вещами, которые и послужили основой выбора именно этой прошивки:
|
||||
* полный root доступ к девайсу через shell. на заводских прошивках чаще всего отсутствует, на многих альтернативных есть
|
||||
* корень r/w. это практически уникальная особенность OpenWrt. заводские и большинство альтернативных прошивок
|
||||
построены на базе squashfs root (r/o), а конфигурация хранится в специально отформатированной области
|
||||
встроенной памяти, называемой nvram. не имеющие r/w корня системы сильно кастрированы. они не имеют
|
||||
возможности доустановки ПО из репозитория без специальных вывертов и заточены в основном
|
||||
на чуть более продвинутого, чем обычно, пользователя и управление имеющимся функционалом через веб интерфейс,
|
||||
но функционал фиксированно ограничен. альтернативные прошивки, как правило, могут монтировать r/w раздел
|
||||
в какую-то область файловой системы, заводские обычно могут монтировать лишь флэшки, подключенные к USB,
|
||||
и не факт, что есть поддержка unix файловых системы. может быть поддержка только fat и ntfs.
|
||||
* возможность выноса корневой файловой системы на внешний носитель (extroot) или создания на нем оверлея (overlay)
|
||||
* наличие менеджера пакетов opkg и репозитория софта
|
||||
* flow offload предсказуемо, стандартно и выборочно управляем, а так же отключаем
|
||||
* в репозитории есть все модули ядра, их можно доустановить через opkg. ядро пересобирать не нужно.
|
||||
* в репозитории есть все модули 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`.
|
||||
После чего перезагрузите систему.
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## English
|
||||
|
||||
[Manual](manual.en.md)
|
||||
|
||||
## Зачем это нужно
|
||||
|
||||
Автономное средство противодействия DPI, которое не требует подключения каких-либо сторонних серверов. Может помочь
|
||||
@@ -11,11 +15,13 @@ VPN. Может использоваться для частичной проз
|
||||
[Полный мануал](manual.md)
|
||||
|
||||
|
||||
## Поддержать разработчика
|
||||
## Поддержать разработчика. Donations
|
||||
|
||||
Если вы считаете проект полезным и желаете поддержать разработку, направляйте ваши пожертвования на следующие адреса криптокошельков :
|
||||
|
||||
USDT `0x3d52Ce15B7Be734c53fc9526ECbAB8267b63d66E` (предпочительно сеть ERC-20)
|
||||
If you find this project useful and wish to donate here are crypto wallets :
|
||||
|
||||
USDT `0x3d52Ce15B7Be734c53fc9526ECbAB8267b63d66E` (предпочительно сеть ERC-20. ERC-20 preferred)
|
||||
|
||||
BTC `bc1qhqew3mrvp47uk2vevt5sctp7p2x9m7m5kkchve`
|
||||
|
||||
@@ -53,8 +59,7 @@ zapret2 - инструмент для таких энтузиастов. Но э
|
||||
## С чего начать
|
||||
|
||||
Хотелось бы избежать [талмуда](manual.md) на главной странице. Поэтому начнем со способа запуска *nfqws2* и описания способов портирования стратегий *nfqws1* - как в *nfqws2* сделать то же самое, что можно было в *nfqws1*.
|
||||
Когда вы поймете как это работает, вы можете посмотреть Lua код, находящийся "под капотом". Разобрать как он работает, попробовать написать что-то свое.
|
||||
"талмуд" обязательно будет, как он есть у любых более-менее сложных проектов. Он нужен как справочник.
|
||||
Когда вы поймете как это работает, вы можете посмотреть Lua код, находящийся "под капотом". Разобрать как он работает, попробовать написать что-то свое, руководствуясь [талмудом](manual.md) как справочником.
|
||||
|
||||
### Механика обработки трафика
|
||||
|
||||
|
||||
13
files/fake/sip.bin
Normal file
13
files/fake/sip.bin
Normal 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
|
||||
|
||||
@@ -1,30 +1,30 @@
|
||||
# this custom script demonstrates how to launch extra nfqws instance limited by ipset
|
||||
|
||||
# can override in config :
|
||||
NFQWS_MY1_OPT="${NFQWS_MY1_OPT:---filter-udp=* --payload known,unknown --lua-desync=fake:blob=0x00000000000000000000000000000000:repeats=2:payload=all --new --filter-tcp=* --payload=known,unknown --lua-desync=multisplit}"
|
||||
NFQWS_MY1_SUBNETS4="${NFQWS_MY1_SUBNETS4:-173.194.0.0/16 108.177.0.0/17 74.125.0.0/16 64.233.160.0/19 172.217.0.0/16}"
|
||||
NFQWS_MY1_SUBNETS6="${NFQWS_MY1_SUBNETS6:-2a00:1450::/29}"
|
||||
NFQWS_MY1_PORTS_TCP=${NFQWS_MY1_PORTS_TCP:-$NFQWS_PORTS_TCP}
|
||||
NFQWS_MY1_PORTS_UDP=${NFQWS_MY1_PORTS_UDP:-$NFQWS_PORTS_UDP}
|
||||
NFQWS_MY1_TCP_PKT_OUT=${NFQWS_MY1_TCP_PKT_OUT:-$NFQWS_TCP_PKT_OUT}
|
||||
NFQWS_MY1_UDP_PKT_OUT=${NFQWS_MY1_UDP_PKT_OUT:-$NFQWS_UDP_PKT_OUT}
|
||||
NFQWS_MY1_TCP_PKT_IN=${NFQWS_MY1_TCP_PKT_IN:-$NFQWS_TCP_PKT_IN}
|
||||
NFQWS_MY1_UDP_PKT_IN=${NFQWS_MY1_UDP_PKT_IN:-$NFQWS_UDP_PKT_IN}
|
||||
NFQWS2_MY1_OPT="${NFQWS2_MY1_OPT:---filter-udp=* --payload known,unknown --lua-desync=fake:blob=0x00000000000000000000000000000000:repeats=2:payload=all --new --filter-tcp=* --payload=known,unknown --lua-desync=multisplit}"
|
||||
NFQWS2_MY1_SUBNETS4="${NFQWS2_MY1_SUBNETS4:-173.194.0.0/16 108.177.0.0/17 74.125.0.0/16 64.233.160.0/19 172.217.0.0/16}"
|
||||
NFQWS2_MY1_SUBNETS6="${NFQWS2_MY1_SUBNETS6:-2a00:1450::/29}"
|
||||
NFQWS2_MY1_PORTS_TCP=${NFQWS2_MY1_PORTS_TCP:-$NFQWS2_PORTS_TCP}
|
||||
NFQWS2_MY1_PORTS_UDP=${NFQWS2_MY1_PORTS_UDP:-$NFQWS2_PORTS_UDP}
|
||||
NFQWS2_MY1_TCP_PKT_OUT=${NFQWS2_MY1_TCP_PKT_OUT:-$NFQWS2_TCP_PKT_OUT}
|
||||
NFQWS2_MY1_UDP_PKT_OUT=${NFQWS2_MY1_UDP_PKT_OUT:-$NFQWS2_UDP_PKT_OUT}
|
||||
NFQWS2_MY1_TCP_PKT_IN=${NFQWS2_MY1_TCP_PKT_IN:-$NFQWS2_TCP_PKT_IN}
|
||||
NFQWS2_MY1_UDP_PKT_IN=${NFQWS2_MY1_UDP_PKT_IN:-$NFQWS2_UDP_PKT_IN}
|
||||
|
||||
NFQWS_MY1_IPSET_SIZE=${NFQWS_MY1_IPSET_SIZE:-4096}
|
||||
NFQWS_MY1_IPSET_OPT="${NFQWS_MY1_IPSET_OPT:-hash:net hashsize 8192 maxelem $NFQWS_MY1_IPSET_SIZE}"
|
||||
NFQWS2_MY1_IPSET_SIZE=${NFQWS2_MY1_IPSET_SIZE:-4096}
|
||||
NFQWS2_MY1_IPSET_OPT="${NFQWS2_MY1_IPSET_OPT:-hash:net hashsize 8192 maxelem $NFQWS2_MY1_IPSET_SIZE}"
|
||||
|
||||
alloc_dnum DNUM_NFQWS_MY1
|
||||
alloc_qnum QNUM_NFQWS_MY1
|
||||
NFQWS_MY1_NAME4=my1nfqws4
|
||||
NFQWS_MY1_NAME6=my1nfqws6
|
||||
alloc_dnum DNUM_NFQWS2_MY1
|
||||
alloc_qnum QNUM_NFQWS2_MY1
|
||||
NFQWS2_MY1_NAME4=my1nfqws4
|
||||
NFQWS2_MY1_NAME6=my1nfqws6
|
||||
|
||||
zapret_custom_daemons()
|
||||
{
|
||||
# $1 - 1 - run, 0 - stop
|
||||
|
||||
local opt="--qnum=$QNUM_NFQWS_MY1 $NFQWS_MY1_OPT"
|
||||
do_nfqws $1 $DNUM_NFQWS_MY1 "$opt"
|
||||
local opt="--qnum=$QNUM_NFQWS2_MY1 $NFQWS2_MY1_OPT"
|
||||
do_nfqws $1 $DNUM_NFQWS2_MY1 "$opt"
|
||||
}
|
||||
|
||||
zapret_custom_firewall()
|
||||
@@ -32,103 +32,103 @@ zapret_custom_firewall()
|
||||
# $1 - 1 - run, 0 - stop
|
||||
|
||||
local f4 f6 subnet
|
||||
local NFQWS_MY1_PORTS_TCP=$(replace_char - : $NFQWS_MY1_PORTS_TCP)
|
||||
local NFQWS_MY1_PORTS_UDP=$(replace_char - : $NFQWS_MY1_PORTS_UDP)
|
||||
local NFQWS2_MY1_PORTS_TCP=$(replace_char - : $NFQWS2_MY1_PORTS_TCP)
|
||||
local NFQWS2_MY1_PORTS_UDP=$(replace_char - : $NFQWS2_MY1_PORTS_UDP)
|
||||
|
||||
[ "$1" = 1 -a "$DISABLE_IPV4" != 1 ] && {
|
||||
ipset create $NFQWS_MY1_NAME4 $NFQWS_MY1_IPSET_OPT family inet 2>/dev/null
|
||||
ipset flush $NFQWS_MY1_NAME4
|
||||
for subnet in $NFQWS_MY1_SUBNETS4; do
|
||||
echo add $NFQWS_MY1_NAME4 $subnet
|
||||
ipset create $NFQWS2_MY1_NAME4 $NFQWS2_MY1_IPSET_OPT family inet 2>/dev/null
|
||||
ipset flush $NFQWS2_MY1_NAME4
|
||||
for subnet in $NFQWS2_MY1_SUBNETS4; do
|
||||
echo add $NFQWS2_MY1_NAME4 $subnet
|
||||
done | ipset -! restore
|
||||
}
|
||||
[ "$1" = 1 -a "$DISABLE_IPV6" != 1 ] && {
|
||||
ipset create $NFQWS_MY1_NAME6 $NFQWS_MY1_IPSET_OPT family inet6 2>/dev/null
|
||||
ipset flush $NFQWS_MY1_NAME6
|
||||
for subnet in $NFQWS_MY1_SUBNETS6; do
|
||||
echo add $NFQWS_MY1_NAME6 $subnet
|
||||
ipset create $NFQWS2_MY1_NAME6 $NFQWS2_MY1_IPSET_OPT family inet6 2>/dev/null
|
||||
ipset flush $NFQWS2_MY1_NAME6
|
||||
for subnet in $NFQWS2_MY1_SUBNETS6; do
|
||||
echo add $NFQWS2_MY1_NAME6 $subnet
|
||||
done | ipset -! restore
|
||||
}
|
||||
|
||||
[ -n "$NFQWS_MY1_PORTS_TCP" ] && {
|
||||
[ -n "$NFQWS_MY1_TCP_PKT_OUT" -a "$NFQWS_MY1_TCP_PKT_OUT" != 0 ] && {
|
||||
f4="-p tcp -m multiport --dports $NFQWS_MY1_PORTS_TCP $ipt_connbytes 1:$NFQWS_MY1_TCP_PKT_OUT -m set --match-set"
|
||||
f6="$f4 $NFQWS_MY1_NAME6 dst"
|
||||
f4="$f4 $NFQWS_MY1_NAME4 dst"
|
||||
fw_nfqws_post $1 "$f4" "$f6" $QNUM_NFQWS_MY1
|
||||
[ -n "$NFQWS2_MY1_PORTS_TCP" ] && {
|
||||
[ -n "$NFQWS2_MY1_TCP_PKT_OUT" -a "$NFQWS2_MY1_TCP_PKT_OUT" != 0 ] && {
|
||||
f4="-p tcp -m multiport --dports $NFQWS2_MY1_PORTS_TCP $ipt_connbytes 1:$NFQWS2_MY1_TCP_PKT_OUT -m set --match-set"
|
||||
f6="$f4 $NFQWS2_MY1_NAME6 dst"
|
||||
f4="$f4 $NFQWS2_MY1_NAME4 dst"
|
||||
fw_nfqws_post $1 "$f4" "$f6" $QNUM_NFQWS2_MY1
|
||||
}
|
||||
[ -n "$NFQWS_MY1_TCP_PKT_IN" -a "$NFQWS_MY1_TCP_PKT_IN" != 0 ] && {
|
||||
f4="-p tcp -m multiport --sports $NFQWS_MY1_PORTS_TCP $ipt_connbytes 1:$NFQWS_MY1_TCP_PKT_IN -m set --match-set"
|
||||
f6="$f4 $NFQWS_MY1_NAME6 src"
|
||||
f4="$f4 $NFQWS_MY1_NAME4 src"
|
||||
fw_nfqws_pre $1 "$f4" "$f6" $QNUM_NFQWS_MY1
|
||||
[ -n "$NFQWS2_MY1_TCP_PKT_IN" -a "$NFQWS2_MY1_TCP_PKT_IN" != 0 ] && {
|
||||
f4="-p tcp -m multiport --sports $NFQWS2_MY1_PORTS_TCP $ipt_connbytes 1:$NFQWS2_MY1_TCP_PKT_IN -m set --match-set"
|
||||
f6="$f4 $NFQWS2_MY1_NAME6 src"
|
||||
f4="$f4 $NFQWS2_MY1_NAME4 src"
|
||||
fw_nfqws_pre $1 "$f4" "$f6" $QNUM_NFQWS2_MY1
|
||||
}
|
||||
}
|
||||
[ -n "$NFQWS_MY1_PORTS_UDP" ] && {
|
||||
[ -n "$NFQWS_MY1_UDP_PKT_OUT" -a "$NFQWS_MY1_UDP_PKT_OUT" != 0 ] && {
|
||||
f4="-p udp -m multiport --dports $NFQWS_MY1_PORTS_UDP $ipt_connbytes 1:$NFQWS_MY1_UDP_PKT_OUT -m set --match-set"
|
||||
f6="$f4 $NFQWS_MY1_NAME6 dst"
|
||||
f4="$f4 $NFQWS_MY1_NAME4 dst"
|
||||
fw_nfqws_post $1 "$f4" "$f6" $QNUM_NFQWS_MY1
|
||||
[ -n "$NFQWS2_MY1_PORTS_UDP" ] && {
|
||||
[ -n "$NFQWS2_MY1_UDP_PKT_OUT" -a "$NFQWS2_MY1_UDP_PKT_OUT" != 0 ] && {
|
||||
f4="-p udp -m multiport --dports $NFQWS2_MY1_PORTS_UDP $ipt_connbytes 1:$NFQWS2_MY1_UDP_PKT_OUT -m set --match-set"
|
||||
f6="$f4 $NFQWS2_MY1_NAME6 dst"
|
||||
f4="$f4 $NFQWS2_MY1_NAME4 dst"
|
||||
fw_nfqws_post $1 "$f4" "$f6" $QNUM_NFQWS2_MY1
|
||||
}
|
||||
[ -n "$NFQWS_MY1_UDP_PKT_IN" -a "$NFQWS_MY1_UDP_PKT_IN" != 0 ] && {
|
||||
f4="-p udp -m multiport --sports $NFQWS_MY1_PORTS_UDP $ipt_connbytes 1:$NFQWS_MY1_UDP_PKT_IN -m set --match-set"
|
||||
f6="$f4 $NFQWS_MY1_NAME6 src"
|
||||
f4="$f4 $NFQWS_MY1_NAME4 src"
|
||||
fw_nfqws_pre $1 "$f4" "$f6" $QNUM_NFQWS_MY1
|
||||
[ -n "$NFQWS2_MY1_UDP_PKT_IN" -a "$NFQWS2_MY1_UDP_PKT_IN" != 0 ] && {
|
||||
f4="-p udp -m multiport --sports $NFQWS2_MY1_PORTS_UDP $ipt_connbytes 1:$NFQWS2_MY1_UDP_PKT_IN -m set --match-set"
|
||||
f6="$f4 $NFQWS2_MY1_NAME6 src"
|
||||
f4="$f4 $NFQWS2_MY1_NAME4 src"
|
||||
fw_nfqws_pre $1 "$f4" "$f6" $QNUM_NFQWS2_MY1
|
||||
}
|
||||
}
|
||||
|
||||
[ "$1" = 1 ] || {
|
||||
ipset destroy $NFQWS_MY1_NAME4 2>/dev/null
|
||||
ipset destroy $NFQWS_MY1_NAME6 2>/dev/null
|
||||
ipset destroy $NFQWS2_MY1_NAME4 2>/dev/null
|
||||
ipset destroy $NFQWS2_MY1_NAME6 2>/dev/null
|
||||
}
|
||||
}
|
||||
|
||||
zapret_custom_firewall_nft()
|
||||
{
|
||||
local f4 f6 subnets
|
||||
local first_packets_only="$nft_connbytes 1-$NFQWS_MY1_PKT_OUT"
|
||||
local first_packets_only="$nft_connbytes 1-$NFQWS2_MY1_PKT_OUT"
|
||||
|
||||
[ "$DISABLE_IPV4" != 1 ] && {
|
||||
make_comma_list subnets $NFQWS_MY1_SUBNETS4
|
||||
nft_create_set $NFQWS_MY1_NAME4 "type ipv4_addr; size $NFQWS_MY1_IPSET_SIZE; auto-merge; flags interval;"
|
||||
nft_flush_set $NFQWS_MY1_NAME4
|
||||
nft_add_set_element $NFQWS_MY1_NAME4 "$subnets"
|
||||
make_comma_list subnets $NFQWS2_MY1_SUBNETS4
|
||||
nft_create_set $NFQWS2_MY1_NAME4 "type ipv4_addr; size $NFQWS2_MY1_IPSET_SIZE; auto-merge; flags interval;"
|
||||
nft_flush_set $NFQWS2_MY1_NAME4
|
||||
nft_add_set_element $NFQWS2_MY1_NAME4 "$subnets"
|
||||
}
|
||||
[ "$DISABLE_IPV6" != 1 ] && {
|
||||
make_comma_list subnets $NFQWS_MY1_SUBNETS6
|
||||
nft_create_set $NFQWS_MY1_NAME6 "type ipv6_addr; size $NFQWS_MY1_IPSET_SIZE; auto-merge; flags interval;"
|
||||
nft_flush_set $NFQWS_MY1_NAME6
|
||||
nft_add_set_element $NFQWS_MY1_NAME6 "$subnets"
|
||||
make_comma_list subnets $NFQWS2_MY1_SUBNETS6
|
||||
nft_create_set $NFQWS2_MY1_NAME6 "type ipv6_addr; size $NFQWS2_MY1_IPSET_SIZE; auto-merge; flags interval;"
|
||||
nft_flush_set $NFQWS2_MY1_NAME6
|
||||
nft_add_set_element $NFQWS2_MY1_NAME6 "$subnets"
|
||||
}
|
||||
|
||||
[ -n "$NFQWS_MY1_PORTS_TCP" ] && {
|
||||
[ -n "$NFQWS_MY1_TCP_PKT_OUT" -a "$NFQWS_MY1_TCP_PKT_OUT" != 0 ] && {
|
||||
f4="tcp dport {$NFQWS_MY1_PORTS_TCP} $(nft_first_packets $NFQWS_MY1_TCP_PKT_OUT)"
|
||||
f6="$f4 ip6 daddr @$NFQWS_MY1_NAME6"
|
||||
f4="$f4 ip daddr @$NFQWS_MY1_NAME4"
|
||||
nft_fw_nfqws_post $1 "$f4" "$f6" $QNUM_NFQWS_MY1
|
||||
[ -n "$NFQWS2_MY1_PORTS_TCP" ] && {
|
||||
[ -n "$NFQWS2_MY1_TCP_PKT_OUT" -a "$NFQWS2_MY1_TCP_PKT_OUT" != 0 ] && {
|
||||
f4="tcp dport {$NFQWS2_MY1_PORTS_TCP} $(nft_first_packets $NFQWS2_MY1_TCP_PKT_OUT)"
|
||||
f6="$f4 ip6 daddr @$NFQWS2_MY1_NAME6"
|
||||
f4="$f4 ip daddr @$NFQWS2_MY1_NAME4"
|
||||
nft_fw_nfqws_post $1 "$f4" "$f6" $QNUM_NFQWS2_MY1
|
||||
}
|
||||
[ -n "$NFQWS_MY1_TCP_PKT_IN" -a "$NFQWS_MY1_TCP_PKT_IN" != 0 ] && {
|
||||
f4="tcp sport {$NFQWS_MY1_PORTS_TCP} $(nft_first_packets $NFQWS_MY1_TCP_PKT_IN)"
|
||||
f6="$f4 ip6 saddr @$NFQWS_MY1_NAME6"
|
||||
f4="$f4 ip saddr @$NFQWS_MY1_NAME4"
|
||||
nft_fw_nfqws_pre $1 "$f4" "$f6" $QNUM_NFQWS_MY1
|
||||
[ -n "$NFQWS2_MY1_TCP_PKT_IN" -a "$NFQWS2_MY1_TCP_PKT_IN" != 0 ] && {
|
||||
f4="tcp sport {$NFQWS2_MY1_PORTS_TCP} $(nft_first_packets $NFQWS2_MY1_TCP_PKT_IN)"
|
||||
f6="$f4 ip6 saddr @$NFQWS2_MY1_NAME6"
|
||||
f4="$f4 ip saddr @$NFQWS2_MY1_NAME4"
|
||||
nft_fw_nfqws_pre $1 "$f4" "$f6" $QNUM_NFQWS2_MY1
|
||||
}
|
||||
}
|
||||
[ -n "$NFQWS_MY1_PORTS_UDP" ] && {
|
||||
[ -n "$NFQWS_MY1_UDP_PKT_OUT" -a "$NFQWS_MY1_UDP_PKT_OUT" != 0 ] && {
|
||||
f4="udp dport {$NFQWS_MY1_PORTS_UDP} $(nft_first_packets $NFQWS_MY1_UDP_PKT_OUT)"
|
||||
f6="$f4 ip6 daddr @$NFQWS_MY1_NAME6"
|
||||
f4="$f4 ip daddr @$NFQWS_MY1_NAME4"
|
||||
nft_fw_nfqws_post $1 "$f4" "$f6" $QNUM_NFQWS_MY1
|
||||
[ -n "$NFQWS2_MY1_PORTS_UDP" ] && {
|
||||
[ -n "$NFQWS2_MY1_UDP_PKT_OUT" -a "$NFQWS2_MY1_UDP_PKT_OUT" != 0 ] && {
|
||||
f4="udp dport {$NFQWS2_MY1_PORTS_UDP} $(nft_first_packets $NFQWS2_MY1_UDP_PKT_OUT)"
|
||||
f6="$f4 ip6 daddr @$NFQWS2_MY1_NAME6"
|
||||
f4="$f4 ip daddr @$NFQWS2_MY1_NAME4"
|
||||
nft_fw_nfqws_post $1 "$f4" "$f6" $QNUM_NFQWS2_MY1
|
||||
}
|
||||
[ -n "$NFQWS_MY1_UDP_PKT_IN" -a "$NFQWS_MY1_UDP_PKT_IN" != 0 ] && {
|
||||
f4="udp sport {$NFQWS_MY1_PORTS_UDP} $(nft_first_packets $NFQWS_MY1_UDP_PKT_IN)"
|
||||
f6="$f4 ip6 saddr @$NFQWS_MY1_NAME6"
|
||||
f4="$f4 ip saddr @$NFQWS_MY1_NAME4"
|
||||
nft_fw_nfqws_pre $1 "$f4" "$f6" $QNUM_NFQWS_MY1
|
||||
[ -n "$NFQWS2_MY1_UDP_PKT_IN" -a "$NFQWS2_MY1_UDP_PKT_IN" != 0 ] && {
|
||||
f4="udp sport {$NFQWS2_MY1_PORTS_UDP} $(nft_first_packets $NFQWS2_MY1_UDP_PKT_IN)"
|
||||
f6="$f4 ip6 saddr @$NFQWS2_MY1_NAME6"
|
||||
f4="$f4 ip saddr @$NFQWS2_MY1_NAME4"
|
||||
nft_fw_nfqws_pre $1 "$f4" "$f6" $QNUM_NFQWS2_MY1
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -139,6 +139,6 @@ zapret_custom_firewall_nft_flush()
|
||||
# this function is called after all nft fw rules are deleted
|
||||
# however sets are not deleted. it's desired to clear sets here.
|
||||
|
||||
nft_del_set $NFQWS_MY1_NAME4 2>/dev/null
|
||||
nft_del_set $NFQWS_MY1_NAME6 2>/dev/null
|
||||
nft_del_set $NFQWS2_MY1_NAME4 2>/dev/null
|
||||
nft_del_set $NFQWS2_MY1_NAME6 2>/dev/null
|
||||
}
|
||||
|
||||
62
init.d/custom.d.examples.linux/80-dns-intercept
Normal file
62
init.d/custom.d.examples.linux/80-dns-intercept
Normal file
@@ -0,0 +1,62 @@
|
||||
# this custom script feeds dns response data to main nfqws2 instance
|
||||
# DISABLE_IPV{4,6} filters are not used intentionally. despite of not having wan ipv6 it's possible to query LAN DNS server over local ipv6
|
||||
|
||||
zapret_custom_firewall()
|
||||
{
|
||||
# $1 - 1 - run, 0 - stop
|
||||
local filt="-p udp --sport 53"
|
||||
local jump="-j NFQUEUE --queue-num $QNUM --queue-bypass"
|
||||
local rule chain lan lanifs
|
||||
|
||||
get_lanif lanifs
|
||||
|
||||
# router
|
||||
for lan in $lanifs; do
|
||||
rule="-o $lan $filt $jump"
|
||||
ipt_print_op $1 "$rule" "nfqws FORWARD (qnum $QNUM)"
|
||||
ipt_add_del $1 FORWARD -t mangle $rule
|
||||
ipt_print_op $1 "$rule" "nfqws FORWARD (qnum $QNUM)" 6
|
||||
ipt6_add_del $1 FORWARD -t mangle $rule
|
||||
done
|
||||
# dns client server
|
||||
for chain in INPUT OUTPUT ; do
|
||||
rule="$filt $jump"
|
||||
ipt_print_op $1 "$rule" "nfqws $chain (qnum $QNUM)"
|
||||
ipt_add_del $1 $chain -t mangle $rule
|
||||
ipt_print_op $1 "$rule" "nfqws $chain (qnum $QNUM)" 6
|
||||
ipt6_add_del $1 $chain -t mangle $rule
|
||||
done
|
||||
}
|
||||
|
||||
zapret_custom_firewall_nft()
|
||||
{
|
||||
# stop logic is not required
|
||||
|
||||
local rule="udp sport 53 queue num $QNUM bypass"
|
||||
|
||||
# router
|
||||
nft_print_op "oifname @lanif $rule" "nfqws forward (qnum $QNUM)" "4+6"
|
||||
nft_add_chain forward_dns_feed "type filter hook forward priority mangle;"
|
||||
nft_flush_chain forward_dns_feed
|
||||
nft_add_rule forward_dns_feed oifname @lanif $rule
|
||||
|
||||
# dns client
|
||||
nft_print_op "$rule" "nfqws input (qnum $QNUM)" "4+6"
|
||||
nft_add_chain input_dns_feed "type filter hook input priority mangle;"
|
||||
nft_flush_chain input_dns_feed
|
||||
nft_add_rule input_dns_feed $rule
|
||||
|
||||
# dns server
|
||||
nft_print_op "$rule" "nfqws output (qnum $QNUM)" "4+6"
|
||||
nft_add_chain output_dns_feed "type filter hook output priority mangle;"
|
||||
nft_flush_chain output_dns_feed
|
||||
nft_add_rule output_dns_feed $rule
|
||||
}
|
||||
|
||||
zapret_custom_firewall_nft_flush()
|
||||
{
|
||||
local chain
|
||||
for chain in forward_dns_feed input_dns_feed output_dns_feed; do
|
||||
nft_del_chain $chain 2>/dev/null
|
||||
done
|
||||
}
|
||||
145
init.d/custom.d.examples.linux/99-lan-filter
Normal file
145
init.d/custom.d.examples.linux/99-lan-filter
Normal file
@@ -0,0 +1,145 @@
|
||||
# this custom script sets FILTER_MARK to specified source ips
|
||||
|
||||
# NOTE !!! SCRIPT REQUIRES FILTER_MARK VAR IN CONFIG FILE !!!
|
||||
# NOTE !!! WITHOUT FILTER_MARK IT DOES NOTHING !!!
|
||||
|
||||
# NOTE !!! ON NON-OPENWRT SYSTEMS SCRIPT REQUIRES IFACE_LAN VAR IN CONFIG FILE !!!
|
||||
|
||||
# can override in config :
|
||||
# LAN ip/cidr list to be fooled. elements are space separated
|
||||
FILTER_LAN_IP="${FILTER_LAN_IP:-192.168.0.0/16}"
|
||||
FILTER_LAN_IP6="${FILTER_LAN_IP6:-fc00::/7}"
|
||||
# allow fooling from local system (0|1) ?
|
||||
FILTER_LAN_ALLOW_OUTPUT="${FILTER_LAN_ALLOW_OUTPUT:-1}"
|
||||
|
||||
FILTER_LAN_SET="lanfilter"
|
||||
FILTER_LAN_SET6="${FILTER_LAN_SET}6"
|
||||
FILTER_LAN_IPSET_SIZE=${FILTER_LAN_IPSET_SIZE:-256}
|
||||
FILTER_LAN_IPSET_OPT="${FILTER_LAN_IPSET_OPT:-hash:net hashsize 8192 maxelem $FILTER_LAN_IPSET_SIZE}"
|
||||
|
||||
filter_mark_check()
|
||||
{
|
||||
[ -n "$FILTER_MARK" ] || {
|
||||
echo "WARNING ! lan filter cannot work without FILTER_MARK set in config"
|
||||
return 1
|
||||
}
|
||||
[ "$DISABLE_IPV4" = 1 -a "$DISABLE_IPV6" = 1 ] && return 1
|
||||
return 0
|
||||
}
|
||||
|
||||
zapret_custom_firewall()
|
||||
{
|
||||
# $1 - 1 - run, 0 - stop
|
||||
|
||||
filter_mark_check || return
|
||||
|
||||
local subnet lanifs rule
|
||||
local setmark="-j MARK --set-mark $FILTER_MARK/$FILTER_MARK"
|
||||
local filt4="-m set --match-set $FILTER_LAN_SET src"
|
||||
local filt6="-m set --match-set $FILTER_LAN_SET6 src"
|
||||
|
||||
get_lanif lanifs
|
||||
|
||||
[ "$DISABLE_IPV4" != 1 ] && {
|
||||
[ "$FILTER_LAN_ALLOW_OUTPUT" = 1 ] && {
|
||||
ipt_print_op $1 "$setmark" "filter output"
|
||||
ipt_add_del $1 OUTPUT -t mangle $setmark
|
||||
}
|
||||
[ -n "$lanifs" ] && {
|
||||
[ "$1" = 1 ] && {
|
||||
ipset create $FILTER_LAN_SET $FILTER_LAN_IPSET_OPT family inet 2>/dev/null
|
||||
ipset flush $FILTER_LAN_SET
|
||||
for subnet in $FILTER_LAN_IP; do
|
||||
echo add $FILTER_LAN_SET $subnet
|
||||
done | ipset -! restore
|
||||
}
|
||||
for lan in $lanifs; do
|
||||
rule="-i $lan $filt4 $setmark"
|
||||
ipt_print_op $1 "$rule" "filter forward"
|
||||
ipt_add_del $1 FORWARD -t mangle $rule
|
||||
done
|
||||
}
|
||||
}
|
||||
[ "$DISABLE_IPV6" != 1 ] && {
|
||||
[ "$FILTER_LAN_ALLOW_OUTPUT" = 1 ] && {
|
||||
ipt_print_op $1 "$setmark" "filter output" 6
|
||||
ipt6_add_del $1 OUTPUT -t mangle $setmark
|
||||
}
|
||||
[ -n "$lanifs" ] && {
|
||||
[ "$1" = 1 ] && {
|
||||
ipset create $FILTER_LAN_SET6 $FILTER_LAN_IPSET_OPT family inet6 2>/dev/null
|
||||
ipset flush $FILTER_LAN_SET6
|
||||
for subnet in $FILTER_LAN_IP6; do
|
||||
echo add $FILTER_LAN_SET6 $subnet
|
||||
done | ipset -! restore
|
||||
}
|
||||
for lan in $lanifs; do
|
||||
rule="-i $lan $filt6 $setmark"
|
||||
ipt_print_op $1 "$rule" "filter forward" 6
|
||||
ipt6_add_del $1 FORWARD -t mangle $rule
|
||||
done
|
||||
}
|
||||
}
|
||||
|
||||
[ "$1" = 1 ] || {
|
||||
ipset destroy $FILTER_LAN_SET 2>/dev/null
|
||||
ipset destroy $FILTER_LAN_SET6 2>/dev/null
|
||||
}
|
||||
}
|
||||
|
||||
zapret_custom_firewall_nft()
|
||||
{
|
||||
filter_mark_check || return
|
||||
|
||||
local subnets rule
|
||||
local setmark="meta mark set meta mark or $FILTER_MARK"
|
||||
local filt4="ip saddr == @$FILTER_LAN_SET"
|
||||
local filt6="ip6 saddr == @$FILTER_LAN_SET6"
|
||||
local lanif="iifname @lanif"
|
||||
|
||||
nft_add_chain forward_lan_filter "type filter hook forward priority mangle;"
|
||||
nft_flush_chain forward_lan_filter
|
||||
|
||||
if [ "$FILTER_LAN_ALLOW_OUTPUT" = 1 ]; then
|
||||
nft_add_chain output_lan_filter "type filter hook output priority mangle;"
|
||||
nft_flush_chain output_lan_filter
|
||||
nft_print_op "$setmark" "filter output" "4+6"
|
||||
nft_add_rule output_lan_filter $setmark
|
||||
else
|
||||
nft_del_chain output_lan_filter 2>/dev/null
|
||||
fi
|
||||
|
||||
[ "$DISABLE_IPV4" != 1 ] && {
|
||||
make_comma_list subnets $FILTER_LAN_IP
|
||||
nft_create_set $FILTER_LAN_SET "type ipv4_addr; size $FILTER_LAN_IPSET_SIZE; auto-merge; flags interval;"
|
||||
nft_flush_set $FILTER_LAN_SET
|
||||
nft_add_set_element $FILTER_LAN_SET "$subnets"
|
||||
|
||||
rule="$lanif $filt4 $setmark"
|
||||
nft_print_op "$rule" "filter forward" "4"
|
||||
nft_add_rule forward_lan_filter $rule
|
||||
}
|
||||
[ "$DISABLE_IPV6" != 1 ] && {
|
||||
make_comma_list subnets $FILTER_LAN_IP6
|
||||
nft_create_set $FILTER_LAN_SET6 "type ipv6_addr; size $FILTER_LAN_IPSET_SIZE; auto-merge; flags interval;"
|
||||
nft_flush_set $FILTER_LAN_SET6
|
||||
nft_add_set_element $FILTER_LAN_SET6 "$subnets"
|
||||
|
||||
rule="$lanif $filt6 $setmark"
|
||||
nft_print_op "$rule" "filter forward" "6"
|
||||
nft_add_rule forward_lan_filter $rule
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
zapret_custom_firewall_nft_flush()
|
||||
{
|
||||
# this function is called after all nft fw rules are deleted
|
||||
# however sets are not deleted. it's desired to clear sets here.
|
||||
|
||||
nft_del_chain forward_lan_filter 2>/dev/null
|
||||
nft_del_chain output_lan_filter 2>/dev/null
|
||||
|
||||
nft_del_set $FILTER_LAN_SET 2>/dev/null
|
||||
nft_del_set $FILTER_LAN_SET6 2>/dev/null
|
||||
}
|
||||
@@ -62,6 +62,20 @@ network_find_wanX_devices()
|
||||
call_for_multiple_items network_get_device $2 "$ifaces"
|
||||
}
|
||||
|
||||
get_wanif46()
|
||||
{
|
||||
# $1 - 4/6
|
||||
# $2 - var to receive interface list
|
||||
local ifaces
|
||||
network_find_wan${1}_all ifaces
|
||||
call_for_multiple_items network_get_device $2 "$ifaces"
|
||||
}
|
||||
get_lanif()
|
||||
{
|
||||
# $1 - var to receive interface list
|
||||
call_for_multiple_items network_get_device $1 "$OPENWRT_LAN"
|
||||
}
|
||||
|
||||
|
||||
fw_nfqws_prepost_x()
|
||||
{
|
||||
@@ -71,10 +85,8 @@ fw_nfqws_prepost_x()
|
||||
# $4 - 4/6
|
||||
# $5 - post/pre
|
||||
|
||||
local ifaces DWAN
|
||||
network_find_wan${4}_all ifaces
|
||||
call_for_multiple_items network_get_device DWAN "$ifaces"
|
||||
|
||||
local DWAN
|
||||
get_wanif46 $4 DWAN
|
||||
[ -n "$DWAN" ] && _fw_nfqws_${5}${4} $1 "$2" $3 "$(unique $DWAN)"
|
||||
}
|
||||
fw_nfqws_post4()
|
||||
|
||||
@@ -75,6 +75,26 @@ NFQWS2="${NFQWS2:-$ZAPRET_BASE/nfq2/nfqws2}"
|
||||
LUAOPT="--lua-init=@$ZAPRET_BASE/lua/zapret-lib.lua --lua-init=@$ZAPRET_BASE/lua/zapret-antidpi.lua --lua-init=@$ZAPRET_BASE/lua/zapret-auto.lua"
|
||||
NFQWS2_OPT_BASE="$USEROPT --fwmark=$DESYNC_MARK $LUAOPT"
|
||||
|
||||
get_wanif46()
|
||||
{
|
||||
# $1 - 4/6
|
||||
# $2 - var to receive interface list
|
||||
case $1 in
|
||||
6)
|
||||
eval $2="\${IFACE_WAN6:-$IFACE_WAN}"
|
||||
;;
|
||||
4)
|
||||
eval $2="\$IFACE_WAN"
|
||||
;;
|
||||
*)
|
||||
eval $2=
|
||||
esac
|
||||
}
|
||||
get_lanif()
|
||||
{
|
||||
# $1 - var to receive interface list
|
||||
eval $1="\$IFACE_LAN"
|
||||
}
|
||||
|
||||
fw_nfqws_post4()
|
||||
{
|
||||
@@ -119,7 +139,7 @@ nft_wanif6_filter_present()
|
||||
}
|
||||
nft_fill_ifsets_overload()
|
||||
{
|
||||
nft_fill_ifsets "$IFACE_WAN" "${IFACE_WAN6:-$IFACE_WAN}" "$IFACE_LAN"
|
||||
nft_fill_ifsets "$IFACE_LAN" "$IFACE_WAN" "${IFACE_WAN6:-$IFACE_WAN}"
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
udp.PayloadLength=148 and udp.Payload[0]=0x01 or
|
||||
udp.PayloadLength=92 and udp.Payload[0]=0x02 or
|
||||
udp.PayloadLength=64 and udp.Payload[0]=0x03
|
||||
udp.PayloadLength=148 and udp.Payload32[0]=0x01000000 or
|
||||
udp.PayloadLength=92 and udp.Payload32[0]=0x02000000 or
|
||||
udp.PayloadLength=64 and udp.Payload32[0]=0x03000000
|
||||
|
||||
@@ -31,7 +31,7 @@ select_test_method()
|
||||
elif exists zsh && [ "$UNAME" != CYGWIN ] ; then
|
||||
TEST=zsh
|
||||
elif [ "$UNAME" != CYGWIN ]; then
|
||||
if exists hexdump and exists dd; then
|
||||
if exists hexdump && exists dd; then
|
||||
# macos does not use ELF
|
||||
TEST=elf
|
||||
ELF=
|
||||
|
||||
@@ -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" && {
|
||||
@@ -601,7 +601,7 @@ check_dns()
|
||||
|
||||
install_systemd()
|
||||
{
|
||||
INIT_SCRIPT_SRC="$EXEDIR/init.d/sysv/zapret"
|
||||
INIT_SCRIPT_SRC="$EXEDIR/init.d/sysv/zapret2"
|
||||
CUSTOM_DIR="$ZAPRET_RW/init.d/sysv"
|
||||
|
||||
check_bins
|
||||
|
||||
@@ -49,7 +49,7 @@ static int ucmp(const void * a, const void * b, void *arg)
|
||||
}
|
||||
static uint32_t mask_from_bitcount(uint32_t zct)
|
||||
{
|
||||
return zct<32 ? ~((1 << zct) - 1) : 0;
|
||||
return zct<32 ? ~((1u << zct) - 1) : 0;
|
||||
}
|
||||
// make presorted array unique. return number of unique items.
|
||||
// 1,1,2,3,3,0,0,0 (ct=8) => 1,2,3,0 (ct=4)
|
||||
@@ -138,7 +138,7 @@ static void mask_from_bitcount6_make(uint32_t zct, struct in6_addr *a)
|
||||
int32_t n = (127 - zct) >> 3;
|
||||
memset(a->s6_addr,0xFF,n);
|
||||
memset(a->s6_addr+n,0x00,16-n);
|
||||
a->s6_addr[n] = ~((1 << (zct & 7)) - 1);
|
||||
a->s6_addr[n] = ~((1u << (zct & 7)) - 1);
|
||||
}
|
||||
}
|
||||
static struct in6_addr ip6_mask[129];
|
||||
|
||||
@@ -68,7 +68,6 @@ ipset_restore()
|
||||
{
|
||||
# $1 - ipset name
|
||||
# $2 - filename
|
||||
|
||||
zzexist "$2" || return
|
||||
local fsize=$(zzsize "$2")
|
||||
local svram=0
|
||||
@@ -77,7 +76,7 @@ ipset_restore()
|
||||
|
||||
local T="Adding to ipset $1 "
|
||||
[ "$svram" = "1" ] && T="$T (saveram)"
|
||||
T="$T : $f"
|
||||
T="$T : $2"
|
||||
echo $T
|
||||
|
||||
if [ "$svram" = "1" ]; then
|
||||
|
||||
15
ipset/def.sh
15
ipset/def.sh
@@ -44,7 +44,9 @@ ZUSERLIST_EXCLUDE="$IPSET_RW_DIR/zapret-hosts-user-exclude.txt"
|
||||
|
||||
[ -n "$IP2NET" ] || IP2NET="$ZAPRET_BASE/ip2net/ip2net"
|
||||
[ -n "$MDIG" ] || MDIG="$ZAPRET_BASE/mdig/mdig"
|
||||
[ -z "$MDIG_THREADS" ] && MDIG_THREADS=30
|
||||
MDIG_THREADS=${MDIG_THREADS:-30}
|
||||
MDIG_EAGAIN=${MDIG_EAGAIN:-10}
|
||||
MDIG_EAGAIN_DELAY=${MDIG_EAGAIN_DELAY:-500}
|
||||
|
||||
|
||||
|
||||
@@ -124,7 +126,7 @@ zzcat()
|
||||
zz()
|
||||
{
|
||||
if [ "$GZIP_LISTS" = "1" ]; then
|
||||
gzip -c >"$1.gz"
|
||||
gzip -9c >"$1.gz"
|
||||
rm -f "$1"
|
||||
else
|
||||
cat >"$1"
|
||||
@@ -161,7 +163,7 @@ digger()
|
||||
if [ -x "$MDIG" ]; then
|
||||
local cmd
|
||||
[ "$2" = "s" ] && cmd=--stats=1000
|
||||
"$MDIG" --family=$1 --threads=$MDIG_THREADS $cmd
|
||||
"$MDIG" --family=$1 --threads=$MDIG_THREADS --eagain=$MDIG_EAGAIN --eagain-delay=$MDIG_EAGAIN_DELAY $cmd
|
||||
else
|
||||
local A=A
|
||||
[ "$1" = "6" ] && A=AAAA
|
||||
@@ -272,11 +274,10 @@ hup_zapret_daemons()
|
||||
{
|
||||
echo forcing zapret daemons to reload their hostlist
|
||||
if exists killall; then
|
||||
killall -HUP tpws nfqws dvtws 2>/dev/null
|
||||
killall -HUP nfqws2 dvtws2 2>/dev/null
|
||||
elif exists pkill; then
|
||||
pkill -HUP ^tpws$
|
||||
pkill -HUP ^nfqws$
|
||||
pkill -HUP ^dvtws$
|
||||
pkill -HUP ^nfqws2$
|
||||
pkill -HUP ^dvtws2$
|
||||
else
|
||||
echo no mass killer available ! cant HUP zapret daemons
|
||||
fi
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -149,12 +150,17 @@ function http_hostcase(ctx, desync)
|
||||
error("http_hostcase: invalid host spelling '"..spell.."'")
|
||||
else
|
||||
local hdis = http_dissect_req(desync.dis.payload)
|
||||
if hdis.headers.host then
|
||||
DLOG("http_hostcase: 'Host:' => '"..spell.."'")
|
||||
desync.dis.payload = string.sub(desync.dis.payload,1,hdis.headers.host.pos_start-1)..spell..string.sub(desync.dis.payload,hdis.headers.host.pos_header_end+1)
|
||||
return VERDICT_MODIFY
|
||||
if hdis then
|
||||
local idx_host = array_field_search(hdis.headers, "header_low", "host")
|
||||
if idx_host then
|
||||
DLOG("http_hostcase: 'Host:' => '"..spell.."'")
|
||||
desync.dis.payload = string.sub(desync.dis.payload,1,hdis.headers[idx_host].pos_start-1)..spell..string.sub(desync.dis.payload,hdis.headers[idx_host].pos_header_end+1)
|
||||
return VERDICT_MODIFY
|
||||
else
|
||||
DLOG("http_hostcase: 'Host:' header not found")
|
||||
end
|
||||
else
|
||||
DLOG("http_hostcase: 'Host:' header not found")
|
||||
DLOG("http_hostcase: http dissect error")
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -162,6 +168,7 @@ end
|
||||
|
||||
-- nfqws1 : "--methodeol"
|
||||
-- standard args : direction
|
||||
-- NOTE : if using with other http tampering methodeol should be the last !
|
||||
function http_methodeol(ctx, desync)
|
||||
if not desync.dis.tcp then
|
||||
instance_cutoff_shim(ctx, desync)
|
||||
@@ -170,17 +177,57 @@ function http_methodeol(ctx, desync)
|
||||
direction_cutoff_opposite(ctx, desync)
|
||||
if desync.l7payload=="http_req" and direction_check(desync) then
|
||||
local hdis = http_dissect_req(desync.dis.payload)
|
||||
local ua = hdis.headers["user-agent"]
|
||||
if ua then
|
||||
if (ua.pos_end - ua.pos_value_start) < 2 then
|
||||
DLOG("http_methodeol: 'User-Agent:' header is too short")
|
||||
if hdis then
|
||||
local idx_ua = array_field_search(hdis.headers, "header_low", "user-agent")
|
||||
if idx_ua then
|
||||
local ua = hdis.headers[idx_ua]
|
||||
if (ua.pos_end - ua.pos_value_start) < 2 then
|
||||
DLOG("http_methodeol: 'User-Agent:' header is too short")
|
||||
else
|
||||
DLOG("http_methodeol: applied")
|
||||
desync.dis.payload="\r\n"..string.sub(desync.dis.payload,1,ua.pos_end-2)..(string.sub(desync.dis.payload,ua.pos_end+1) or "");
|
||||
return VERDICT_MODIFY
|
||||
end
|
||||
else
|
||||
DLOG("http_methodeol: applied")
|
||||
desync.dis.payload="\r\n"..string.sub(desync.dis.payload,1,ua.pos_end-2)..(string.sub(desync.dis.payload,ua.pos_end+1) or "");
|
||||
return VERDICT_MODIFY
|
||||
DLOG("http_methodeol: 'User-Agent:' header not found")
|
||||
end
|
||||
else
|
||||
DLOG("http_methodeol: 'User-Agent:' header not found")
|
||||
DLOG("http_methodeol: http dissect error")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- nfqws1 : not available
|
||||
-- tpws : --unixeol
|
||||
-- standard args : direction
|
||||
function http_unixeol(ctx, desync)
|
||||
if not desync.dis.tcp then
|
||||
instance_cutoff_shim(ctx, desync)
|
||||
return
|
||||
end
|
||||
direction_cutoff_opposite(ctx, desync)
|
||||
if desync.l7payload=="http_req" and direction_check(desync) then
|
||||
local hdis = http_dissect_req(desync.dis.payload)
|
||||
if hdis then
|
||||
local idx_ua = array_field_search(hdis.headers, "header_low", "user-agent")
|
||||
if idx_ua then
|
||||
local http = http_reconstruct_req(hdis, true)
|
||||
if #http < #desync.dis.payload then
|
||||
hdis.headers[idx_ua].value = hdis.headers[idx_ua].value .. string.rep(" ", #desync.dis.payload - #http)
|
||||
end
|
||||
local http = http_reconstruct_req(hdis, true)
|
||||
if #http==#desync.dis.payload then
|
||||
desync.dis.payload = http
|
||||
DLOG("http_unixeol: applied")
|
||||
return VERDICT_MODIFY
|
||||
else
|
||||
DLOG("http_unixeol: reconstruct differs in size from original: "..#http.."!="..#desync.dis.payload)
|
||||
end
|
||||
else
|
||||
DLOG("http_unixeol: 'User-Agent:' header absent")
|
||||
end
|
||||
else
|
||||
DLOG("http_unixeol: could not dissect http")
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -305,7 +352,7 @@ function tls_client_hello_clone(ctx, desync)
|
||||
direction_cutoff_opposite(ctx, desync)
|
||||
if direction_check(desync) then
|
||||
if not desync.arg.blob then
|
||||
error("fake: 'blob' arg required")
|
||||
error("tls_client_hello_clone: 'blob' arg required")
|
||||
end
|
||||
if desync.l7payload=="tls_client_hello" then
|
||||
desync[desync.arg.blob] = tls_client_hello_mod(desync.reasm_data or desync.dis.payload, desync.arg)
|
||||
@@ -465,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
|
||||
@@ -1009,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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
NFQWS2_COMPAT_VER_REQUIRED=4
|
||||
|
||||
if NFQWS2_COMPAT_VER~=NFQWS2_COMPAT_VER_REQUIRED then
|
||||
error("Incompatible NFQWS2_COMPAT_VER. Use pktws and lua scripts from the same release !")
|
||||
end
|
||||
|
||||
HEXDUMP_DLOG_MAX = HEXDUMP_DLOG_MAX or 32
|
||||
NOT3=bitnot(3)
|
||||
NOT7=bitnot(7)
|
||||
@@ -12,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
|
||||
@@ -236,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
|
||||
@@ -304,7 +315,8 @@ function pos_str(desync, pos)
|
||||
return pos.mode..pos_get(desync, pos.mode)
|
||||
end
|
||||
|
||||
-- convert array a to packed string using 'packer' function
|
||||
|
||||
-- convert array a to packed string using 'packer' function. only numeric indexes starting from 1, order preserved
|
||||
function barray(a, packer)
|
||||
if a then
|
||||
local s=""
|
||||
@@ -314,6 +326,16 @@ function barray(a, packer)
|
||||
return s
|
||||
end
|
||||
end
|
||||
-- convert table a to packed string using 'packer' function. any indexes, any order
|
||||
function btable(a, packer)
|
||||
if a then
|
||||
local s=""
|
||||
for k,v in pairs(a) do
|
||||
s = s .. packer(v)
|
||||
end
|
||||
return s
|
||||
end
|
||||
end
|
||||
|
||||
-- sequence comparision functions. they work only within 2G interval
|
||||
-- seq1>=seq2
|
||||
@@ -553,7 +575,6 @@ function array_search(a, v)
|
||||
return k
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
-- linear search array a for a[index].f==v. return index
|
||||
function array_field_search(a, f, v)
|
||||
@@ -562,7 +583,6 @@ function array_field_search(a, f, v)
|
||||
return k
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
-- find pos of the next eol and pos of the next non-eol character after eol
|
||||
@@ -614,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
|
||||
@@ -624,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
|
||||
@@ -774,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)
|
||||
@@ -835,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
|
||||
@@ -1038,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
|
||||
@@ -1054,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
|
||||
@@ -1069,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
|
||||
@@ -1088,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)
|
||||
@@ -1144,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
|
||||
@@ -1154,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)
|
||||
@@ -1410,6 +1452,117 @@ function tls_client_hello_mod(tls, options)
|
||||
return tls
|
||||
end
|
||||
|
||||
-- checks if filename is gzip compressed
|
||||
function is_gzip_file(filename)
|
||||
local f, err = io.open(filename, "r")
|
||||
if not f then
|
||||
error("is_gzip_file: "..err)
|
||||
end
|
||||
local hdr = f:read(2)
|
||||
f:close()
|
||||
return hdr and hdr=="\x1F\x8B"
|
||||
end
|
||||
-- ungzip file to raw string
|
||||
-- expected_ratio = uncompressed_size/compressed_size (default 4)
|
||||
function gunzip_file(filename, expected_ratio, read_block_size)
|
||||
local f, err = io.open(filename, "r")
|
||||
if not f then
|
||||
error("gunzip_file: "..err)
|
||||
end
|
||||
if not read_block_size then read_block_size=16384 end
|
||||
if not expected_ratio then expected_ratio=4 end
|
||||
|
||||
local decompressed=""
|
||||
gz = gunzip_init()
|
||||
if not gz then
|
||||
error("gunzip_file: stream init error")
|
||||
end
|
||||
repeat
|
||||
local compressed, err = f:read(read_block_size)
|
||||
if not compressed then
|
||||
f:close()
|
||||
gunzip_end(gz)
|
||||
if err then
|
||||
error("gunzip_file: file read error : "..err)
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
local decomp, eof = gunzip_inflate(gz, compressed, #compressed * expected_ratio)
|
||||
if not decomp then
|
||||
f:close()
|
||||
gunzip_end(gz)
|
||||
return nil
|
||||
end
|
||||
decompressed = decompressed .. decomp
|
||||
until eof
|
||||
f:close()
|
||||
gunzip_end(gz)
|
||||
return decompressed
|
||||
end
|
||||
-- zip file to raw string
|
||||
-- expected_ratio = uncompressed_size/compressed_size (default 2)
|
||||
-- level : 1..9 (default 9)
|
||||
-- memlevel : 1..8 (default 8)
|
||||
function gzip_file(filename, data, expected_ratio, level, memlevel, compress_block_size)
|
||||
local f, err = io.open(filename, "w")
|
||||
if not f then
|
||||
error("gzip_file: "..err)
|
||||
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)
|
||||
if not gz then
|
||||
error("gzip_file: stream init error")
|
||||
end
|
||||
local off=1, block_size
|
||||
repeat
|
||||
block_size = #data-off+1
|
||||
if block_size>compress_block_size then block_size=compress_block_size end
|
||||
local comp, eof = gzip_deflate(gz, string.sub(data,off,off+block_size-1), block_size / expected_ratio)
|
||||
if not comp then
|
||||
f:close()
|
||||
gzip_end(gz)
|
||||
return nil
|
||||
end
|
||||
f:write(comp)
|
||||
off = off + block_size
|
||||
until eof
|
||||
f:close()
|
||||
gzip_end(gz)
|
||||
end
|
||||
-- reads the whole file
|
||||
function readfile(filename)
|
||||
local f, err = io.open(filename, "r")
|
||||
if not f then
|
||||
error("readfile: "..err)
|
||||
end
|
||||
local s,err = f:read("*a")
|
||||
f:close()
|
||||
if err then
|
||||
error("readfile: "..err)
|
||||
end
|
||||
return s
|
||||
end
|
||||
-- reads plain or gzipped file with transparent decompression
|
||||
-- expected_ratio = uncompressed_size/compressed_size (default 4)
|
||||
function z_readfile(filename, expected_ratio)
|
||||
return is_gzip_file(filename) and gunzip_file(filename, expected_ratio) or readfile(filename)
|
||||
end
|
||||
-- write data to filename
|
||||
function writefile(filename, data)
|
||||
local f, err = io.open(filename, "w")
|
||||
if not f then
|
||||
error("writefile: "..err)
|
||||
end
|
||||
local s,err = f:write(data)
|
||||
f:close()
|
||||
if not s then
|
||||
error("writefile: "..err)
|
||||
end
|
||||
end
|
||||
|
||||
-- DISSECTORS
|
||||
|
||||
function http_dissect_header(header)
|
||||
@@ -1423,19 +1576,22 @@ 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
|
||||
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)
|
||||
header = string.sub(http,pos,eol)
|
||||
if #header == 0 then break end
|
||||
if #header == 0 then
|
||||
pos_headers_end = pnext
|
||||
break
|
||||
end
|
||||
header,value,pos_endheader,pos_startvalue = http_dissect_header(header)
|
||||
if header then
|
||||
headers[string.lower(header)] = { header = header, value = value, pos_start = pos, pos_end = eol, pos_header_end = pos+pos_endheader-1, pos_value_start = pos+pos_startvalue-1 }
|
||||
headers[#headers+1] = { header_low = string.lower(header), header = header, value = value, pos_start = pos, pos_end = eol, pos_header_end = pos+pos_endheader-1, pos_value_start = pos+pos_startvalue-1 }
|
||||
end
|
||||
pos=pnext
|
||||
end
|
||||
return headers
|
||||
return headers, pos_headers_end
|
||||
end
|
||||
-- make table with structured http request representation
|
||||
function http_dissect_req(http)
|
||||
@@ -1457,9 +1613,21 @@ function http_dissect_req(http)
|
||||
pos = string.find(req,"[^ \t]",pos+1)
|
||||
if not pos then return nil end
|
||||
pnext = string.find(req,"[ \t]",pos+1)
|
||||
if not pnext then pnext = #http + 1 end
|
||||
if not pnext then pnext = #req + 1 end
|
||||
local uri = string.sub(req,pos,pnext-1)
|
||||
return { method = method, uri = uri, headers = http_dissect_headers(http,hdrpos) }
|
||||
pos = string.find(req,"[^ \t]",pnext)
|
||||
local http_ver
|
||||
if pos then
|
||||
pnext = string.find(req,"[\r\n]",pos)
|
||||
if not pnext then pnext = #req + 1 end
|
||||
http_ver = string.sub(req,pos,pnext-1)
|
||||
end
|
||||
local hdis = { method = method, uri = uri, http_ver = http_ver }
|
||||
hdis.headers, hdis.pos_headers_end = http_dissect_headers(http,hdrpos)
|
||||
if hdis.pos_headers_end then
|
||||
hdis.body = string.sub(http, hdis.pos_headers_end)
|
||||
end
|
||||
return hdis
|
||||
end
|
||||
function http_dissect_reply(http)
|
||||
if not http then return nil; end
|
||||
@@ -1467,10 +1635,24 @@ 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)
|
||||
return { code = code, headers = http_dissect_headers(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
|
||||
hdis.body = string.sub(http, hdis.pos_headers_end)
|
||||
end
|
||||
return hdis
|
||||
end
|
||||
function http_reconstruct_headers(headers, unixeol)
|
||||
local eol = unixeol and "\n" or "\r\n"
|
||||
return headers and barray(headers, function(a) return a.header..": "..a.value..eol end) or ""
|
||||
end
|
||||
function http_reconstruct_req(hdis, unixeol)
|
||||
local eol = unixeol and "\n" or "\r\n"
|
||||
return hdis.method.." "..hdis.uri..(hdis.http_ver and (" "..hdis.http_ver) or "")..eol..http_reconstruct_headers(hdis.headers, unixeol)..eol..(hdis.body or "")
|
||||
end
|
||||
|
||||
function dissect_url(url)
|
||||
|
||||
@@ -13,7 +13,7 @@ end
|
||||
|
||||
|
||||
function test_all(...)
|
||||
test_run({test_crypto, test_bin, test_ipstr, test_dissect, test_csum, test_resolve, test_rawsend},...)
|
||||
test_run({test_crypto, test_bin, test_gzip, test_ipstr, test_dissect, test_csum, test_resolve, test_rawsend},...)
|
||||
end
|
||||
|
||||
|
||||
@@ -304,6 +304,39 @@ function test_bit()
|
||||
end
|
||||
end
|
||||
|
||||
function test_swap()
|
||||
local v1, v2, v3
|
||||
|
||||
v1 = math.random(0,0xFFFF)
|
||||
v2 = swap16(v1)
|
||||
v3 = divint(v1,0x100) + v1%0x100*0x100
|
||||
print("swap16: "..(v2==v3 and "OK" or "FAIL"))
|
||||
test_assert(v2==v3)
|
||||
|
||||
v1 = math.random(0,0xFFFFFF)
|
||||
v2 = swap24(v1)
|
||||
v3 = divint(v1,0x10000) + divint(v1,0x100)%0x100*0x100 + v1%0x100*0x10000
|
||||
print("swap24: "..(v2==v3 and "OK" or "FAIL"))
|
||||
test_assert(v2==v3)
|
||||
|
||||
v1 = math.random(0,0xFFFFFFFF)
|
||||
v2 = swap32(v1)
|
||||
v3 = divint(v1,0x1000000) + divint(v1,0x10000)%0x100*0x100 + divint(v1,0x100)%0x100*0x10000 + v1%0x100*0x1000000
|
||||
print("swap32: "..(v2==v3 and "OK" or "FAIL"))
|
||||
test_assert(v2==v3)
|
||||
|
||||
v1 = math.random(0,0xFFFFFFFFFFFF)
|
||||
v2 = swap48(v1)
|
||||
v3 = divint(v1,0x10000000000) +
|
||||
divint(v1,0x100000000)%0x100*0x100 +
|
||||
divint(v1,0x1000000)%0x100*0x10000 +
|
||||
divint(v1,0x10000)%0x100*0x1000000 +
|
||||
divint(v1,0x100)%0x100*0x100000000 +
|
||||
v1%0x100*0x10000000000
|
||||
print("swap48: "..(v2==v3 and "OK" or "FAIL"))
|
||||
test_assert(v2==v3)
|
||||
end
|
||||
|
||||
function test_ux()
|
||||
local v1, v2, v3, usum, sum
|
||||
for k,test in pairs({
|
||||
@@ -330,9 +363,38 @@ function test_ux()
|
||||
end
|
||||
|
||||
function test_bin(...)
|
||||
test_run({test_ub, test_bit, test_ux},...)
|
||||
test_run({test_ub, test_bit, test_swap, test_ux},...)
|
||||
end
|
||||
|
||||
function test_gzip()
|
||||
local s=""
|
||||
for i=1,math.random(2000,3000) do
|
||||
local rnd=brandom(math.random(1,50))
|
||||
s=s..rnd..string.rep(bu8(math.random(0,255)),100-#rnd)
|
||||
end
|
||||
local v=math.random(100001,199999)
|
||||
local level=math.random(1,9)
|
||||
local memlevel=math.random(1,8)
|
||||
print("gzip: original size "..#s)
|
||||
print("gzip: cut point "..(v+1))
|
||||
print("gzip: level "..level)
|
||||
print("gzip: memlevel "..memlevel)
|
||||
local gz = gzip_init(nil, level, memlevel)
|
||||
local zip = gzip_deflate(gz,string.sub(s,1,v))
|
||||
zip = zip..gzip_deflate(gz,string.sub(s,v+1))
|
||||
zip = zip..gzip_deflate(gz,nil) -- finalize
|
||||
gzip_end(gz)
|
||||
print("gzip: deflated size "..#zip)
|
||||
local v=math.random(2,#zip-1)
|
||||
print("gunzip: cut point "..(v+1))
|
||||
gz = gunzip_init()
|
||||
local unzip = gunzip_inflate(gz,string.sub(zip,1,v))
|
||||
unzip = unzip..gunzip_inflate(gz,string.sub(zip,v+1))
|
||||
gunzip_end(gz)
|
||||
print("gunzip: inflated size "..#unzip)
|
||||
print("gzip+gunzip: "..(s==unzip and "OK" or "FAIL"))
|
||||
test_assert(s==unzip)
|
||||
end
|
||||
|
||||
function test_ipstr()
|
||||
local s_ip, ip, s_ip2
|
||||
@@ -570,25 +632,50 @@ end
|
||||
function test_resolve()
|
||||
local pos
|
||||
|
||||
pos = zero_based_pos(resolve_multi_pos(fake_default_tls,"tls_client_hello","1,extlen,sniext,host,sld,midsld,endsld,endhost,-5"))
|
||||
local tdis = tls_dissect(fake_default_tls)
|
||||
local extlen_pos = 5 + 6 + 32 + 1 + 2 + 1 + #tdis.handshake[TLS_HANDSHAKE_TYPE_CLIENT].dis.session_id + #tdis.handshake[TLS_HANDSHAKE_TYPE_CLIENT].dis.cipher_suites*2 + #tdis.handshake[TLS_HANDSHAKE_TYPE_CLIENT].dis.compression_methods
|
||||
print("fake_default_tls size "..#fake_default_tls.." extlen="..extlen_pos)
|
||||
local m="1,extlen,sniext,host,sld,midsld,endsld,endhost,-5"
|
||||
pos = resolve_multi_pos(fake_default_tls,"tls_client_hello",m,true)
|
||||
test_assert(pos)
|
||||
print("resolve_multi_pos tls : "..table.concat(pos," "))
|
||||
pos = zero_based_pos(resolve_range(fake_default_tls,"tls_client_hello","host,endhost"))
|
||||
print("resolve_multi_pos tls : "..m.." : "..table.concat(pos," "))
|
||||
m = "host,endhost"
|
||||
pos = resolve_range(fake_default_tls,"tls_client_hello",m,false,true)
|
||||
test_assert(pos)
|
||||
print("resolve_range tls : "..table.concat(pos," "))
|
||||
pos = resolve_pos(fake_default_tls,"tls_client_hello","midsld")
|
||||
print("resolve_range tls : "..m.." : "..table.concat(pos," "))
|
||||
m = "1"
|
||||
pos = resolve_pos(fake_default_tls,"tls_client_hello",m,true)
|
||||
test_assert(pos==1)
|
||||
print("resolve_pos tls : "..m.." : "..pos)
|
||||
m = "-1"
|
||||
pos = resolve_pos(fake_default_tls,"tls_client_hello",m,true)
|
||||
test_assert(pos==(#fake_default_tls-1))
|
||||
print("resolve_pos tls : "..m.." : "..pos)
|
||||
m = "extlen"
|
||||
pos = resolve_pos(fake_default_tls,"tls_client_hello",m,true)
|
||||
test_assert(pos==extlen_pos)
|
||||
print("resolve_pos tls : "..m.." : "..pos)
|
||||
m = "midsld"
|
||||
pos = resolve_pos(fake_default_tls,"tls_client_hello",m,true)
|
||||
test_assert(pos)
|
||||
print("resolve_pos tls : "..pos - 1)
|
||||
pos = resolve_pos(fake_default_tls,"tls_client_hello","method")
|
||||
print("resolve_pos tls : "..m.." : "..pos)
|
||||
m = "method"
|
||||
pos = resolve_pos(fake_default_tls,"tls_client_hello",m,true)
|
||||
test_assert(not pos)
|
||||
print("resolve_pos tls non-existent : "..tostring(pos))
|
||||
print("resolve_pos tls non-existent : "..m.." : "..tostring(pos))
|
||||
|
||||
pos = zero_based_pos(resolve_multi_pos(fake_default_http,"http_req","method,host,sld,midsld,endsld,endhost,-5"))
|
||||
local host_pos = string.find(fake_default_http,"Host: ")+6-1
|
||||
print("fake_default_http size "..#fake_default_http.." host="..host_pos)
|
||||
m = "method,host,sld,midsld,endsld,endhost,-5"
|
||||
pos = resolve_multi_pos(fake_default_http,"http_req",m,true)
|
||||
test_assert(pos)
|
||||
print("resolve_multi_pos http : "..table.concat(pos," "))
|
||||
pos = resolve_pos(fake_default_http,"http_req","sniext")
|
||||
test_assert(pos[1]==0)
|
||||
test_assert(pos[2]==host_pos)
|
||||
print("resolve_multi_pos http : "..m.." : "..table.concat(pos," "))
|
||||
m = "sniext"
|
||||
pos = resolve_pos(fake_default_http,"http_req",m,true)
|
||||
test_assert(not pos)
|
||||
print("resolve_pos http non-existent : "..tostring(pos))
|
||||
print("resolve_pos http non-existent : "..m.." : "..tostring(pos))
|
||||
end
|
||||
|
||||
function test_rawsend(opts)
|
||||
@@ -601,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()
|
||||
@@ -673,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
|
||||
@@ -684,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
|
||||
@@ -693,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
|
||||
@@ -701,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
|
||||
|
||||
@@ -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
|
||||
|
||||
58
mdig/mdig.c
58
mdig/mdig.c
@@ -30,7 +30,8 @@
|
||||
#endif
|
||||
#include <time.h>
|
||||
|
||||
#define RESOLVER_EAGAIN_ATTEMPTS 2
|
||||
#define RESOLVER_EAGAIN_ATTEMPTS 10
|
||||
#define RESOLVER_EAGAIN_DELAY 500
|
||||
|
||||
static void trimstr(char *s)
|
||||
{
|
||||
@@ -79,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>0x7F) *dom = '?';
|
||||
if (*dom < 0x20 || (*dom & 0x80)) *dom = '?';
|
||||
if (*dom) *dom = 0;
|
||||
}
|
||||
|
||||
@@ -97,7 +98,7 @@ static struct
|
||||
{
|
||||
char verbose;
|
||||
char family;
|
||||
int threads;
|
||||
int threads, eagain, eagain_delay;
|
||||
time_t start_time;
|
||||
pthread_mutex_t flock;
|
||||
pthread_mutex_t slock; // stats lock
|
||||
@@ -193,11 +194,12 @@ static void *t_resolver(void *arg)
|
||||
int i, r;
|
||||
char dom[256];
|
||||
bool is_ok;
|
||||
struct addrinfo hints;
|
||||
struct addrinfo *result;
|
||||
struct addrinfo hints, *result;
|
||||
struct timespec ts_eagain = { .tv_sec = glob.eagain_delay/1000, .tv_nsec=glob.eagain_delay%1000*1000000 };
|
||||
|
||||
VLOG("started");
|
||||
|
||||
|
||||
memset(&hints, 0, sizeof(struct addrinfo));
|
||||
hints.ai_family = (glob.family == FAMILY4) ? AF_INET : (glob.family == FAMILY6) ? AF_INET6 : AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_DGRAM;
|
||||
@@ -244,12 +246,16 @@ static void *t_resolver(void *arg)
|
||||
else if (dom_valid(dom))
|
||||
{
|
||||
VLOG("resolving %s", dom);
|
||||
for (i = 0; i < RESOLVER_EAGAIN_ATTEMPTS; i++)
|
||||
for (i = 0; i < glob.eagain; i++)
|
||||
{
|
||||
if ((r = getaddrinfo(dom, NULL, &hints, &result)))
|
||||
{
|
||||
VLOG("failed to resolve %s : result %d (%s)", dom, r, eai_str(r));
|
||||
if (r == EAI_AGAIN) continue; // temporary failure. should retry
|
||||
if (r == EAI_AGAIN)
|
||||
{
|
||||
nanosleep(&ts_eagain, NULL);
|
||||
continue; // temporary failure. should retry
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -430,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;
|
||||
@@ -447,14 +453,18 @@ int dns_parse_query()
|
||||
static void exithelp(void)
|
||||
{
|
||||
printf(
|
||||
" --threads=<threads_number>\n"
|
||||
" --family=<4|6|46>\t\t; ipv4, ipv6, ipv4+ipv6\n"
|
||||
" --threads=<threads_number>\n"
|
||||
" --eagain=<eagain_retries>\t; how many times to retry if EAI_AGAIN received. default %u\n"
|
||||
" --eagain-delay=<ms>\t\t; time in msec to wait between EAI_AGAIN attempts. default %u\n"
|
||||
" --verbose\t\t\t; print query progress to stderr\n"
|
||||
" --stats=N\t\t\t; print resolve stats to stderr every N domains\n"
|
||||
" --log-resolved=<file>\t\t; log successfully resolved domains to a file\n"
|
||||
" --log-failed=<file>\t\t; log failed domains to a file\n"
|
||||
" --dns-make-query=<domain>\t; output to stdout binary blob with DNS query. use --family to specify ip version.\n"
|
||||
" --dns-parse-query\t\t; read from stdin binary DNS answer blob and parse it to ipv4/ipv6 addresses\n"
|
||||
" --dns-parse-query\t\t; read from stdin binary DNS answer blob and parse it to ipv4/ipv6 addresses\n",
|
||||
RESOLVER_EAGAIN_ATTEMPTS,
|
||||
RESOLVER_EAGAIN_DELAY
|
||||
);
|
||||
exit(1);
|
||||
}
|
||||
@@ -469,6 +479,8 @@ static void exithelp(void)
|
||||
|
||||
enum opt_indices {
|
||||
IDX_HELP,
|
||||
IDX_EAGAIN,
|
||||
IDX_EAGAIN_DELAY,
|
||||
IDX_THREADS,
|
||||
IDX_FAMILY,
|
||||
IDX_VERBOSE,
|
||||
@@ -483,6 +495,8 @@ enum opt_indices {
|
||||
static const struct option long_options[] = {
|
||||
[IDX_HELP] = {"help", no_argument, 0, 0},
|
||||
[IDX_THREADS] = {"threads", required_argument, 0, 0},
|
||||
[IDX_EAGAIN] = {"eagain", required_argument, 0, 0},
|
||||
[IDX_EAGAIN_DELAY] = {"eagain-delay", required_argument, 0, 0},
|
||||
[IDX_FAMILY] = {"family", required_argument, 0, 0},
|
||||
[IDX_VERBOSE] = {"verbose", no_argument, 0, 0},
|
||||
[IDX_STATS] = {"stats", required_argument, 0, 0},
|
||||
@@ -503,6 +517,8 @@ int main(int argc, char **argv)
|
||||
*fn1 = *fn2 = *dom = 0;
|
||||
glob.family = FAMILY4;
|
||||
glob.threads = 1;
|
||||
glob.eagain = RESOLVER_EAGAIN_ATTEMPTS;
|
||||
glob.eagain_delay = RESOLVER_EAGAIN_DELAY;
|
||||
while ((v = getopt_long_only(argc, argv, "", long_options, &option_index)) != -1)
|
||||
{
|
||||
if (v) exithelp();
|
||||
@@ -513,13 +529,29 @@ int main(int argc, char **argv)
|
||||
exithelp();
|
||||
break;
|
||||
case IDX_THREADS:
|
||||
glob.threads = optarg ? atoi(optarg) : 0;
|
||||
glob.threads = atoi(optarg);
|
||||
if (glob.threads <= 0 || glob.threads > 100)
|
||||
{
|
||||
fprintf(stderr, "thread number must be within 1..100\n");
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case IDX_EAGAIN:
|
||||
glob.eagain = atoi(optarg);
|
||||
if (glob.eagain <= 0 || glob.eagain > 1000)
|
||||
{
|
||||
fprintf(stderr, "eagain must be within 1..1000\n");
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case IDX_EAGAIN_DELAY:
|
||||
glob.eagain_delay = atoi(optarg);
|
||||
if (glob.eagain_delay < 0 || glob.eagain_delay > 100000)
|
||||
{
|
||||
fprintf(stderr, "eagain-delay must be within 0..100000\n");
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case IDX_FAMILY:
|
||||
if (!strcmp(optarg, "4"))
|
||||
glob.family = FAMILY4;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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).*),)
|
||||
|
||||
@@ -51,11 +51,6 @@ uint32_t net16_add(uint16_t netorder_value, uint16_t cpuorder_increment)
|
||||
return htons(ntohs(netorder_value)+cpuorder_increment);
|
||||
}
|
||||
|
||||
bool ip_has_df(const struct ip *ip)
|
||||
{
|
||||
return ip && !!(ntohs(ip->ip_off) & IP_DF);
|
||||
}
|
||||
|
||||
uint8_t *tcp_find_option(struct tcphdr *tcp, uint8_t kind)
|
||||
{
|
||||
uint8_t *t = (uint8_t*)(tcp+1);
|
||||
@@ -80,11 +75,6 @@ uint8_t *tcp_find_option(struct tcphdr *tcp, uint8_t kind)
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
uint32_t *tcp_find_timestamps(struct tcphdr *tcp)
|
||||
{
|
||||
uint8_t *t = tcp_find_option(tcp, TCP_KIND_TS);
|
||||
return (t && t[1]==10) ? (uint32_t*)(t+2) : NULL;
|
||||
}
|
||||
uint8_t tcp_find_scale_factor(const struct tcphdr *tcp)
|
||||
{
|
||||
uint8_t *scale = tcp_find_option((struct tcphdr*)tcp, TCP_KIND_SCALE);
|
||||
@@ -349,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)
|
||||
@@ -394,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;
|
||||
@@ -402,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
|
||||
@@ -508,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
|
||||
@@ -632,7 +586,7 @@ BOOL LowMandatoryLevel(void)
|
||||
|
||||
label_low.Label.Sid = (PSID)buf1;
|
||||
InitializeSid(label_low.Label.Sid, &label_authority, 1);
|
||||
label_low.Label.Attributes = 0;
|
||||
label_low.Label.Attributes = SE_GROUP_INTEGRITY;
|
||||
*GetSidSubAuthority(label_low.Label.Sid, 0) = SECURITY_MANDATORY_LOW_RID;
|
||||
|
||||
// S-1-16-12288 : Mandatory Label\High Mandatory Level
|
||||
@@ -902,7 +856,7 @@ bool win_dark_init(const struct str_list_head *ssid_filter, const struct str_lis
|
||||
wlan_filter_ssid = ssid_filter;
|
||||
return true;
|
||||
}
|
||||
bool win_dark_deinit(void)
|
||||
void win_dark_deinit(void)
|
||||
{
|
||||
if (pNetworkListManager)
|
||||
{
|
||||
@@ -1007,11 +961,12 @@ bool nlm_list(bool bAll)
|
||||
}
|
||||
else
|
||||
bRet = false;
|
||||
|
||||
CoUninitialize();
|
||||
}
|
||||
else
|
||||
bRet = false;
|
||||
|
||||
CoUninitialize();
|
||||
return bRet;
|
||||
}
|
||||
|
||||
@@ -1181,8 +1136,11 @@ static HANDLE windivert_init_filter(const char *filter, UINT64 flags)
|
||||
|
||||
FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL, w_win32_error, MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), (LPSTR)&errormessage, 0, NULL);
|
||||
DLOG_ERR("windivert: error opening filter: %s", errormessage);
|
||||
LocalFree(errormessage);
|
||||
if (errormessage)
|
||||
{
|
||||
DLOG_ERR("windivert: error opening filter: %s", errormessage);
|
||||
LocalFree(errormessage);
|
||||
}
|
||||
if (w_win32_error == ERROR_INVALID_IMAGE_HASH)
|
||||
DLOG_ERR("windivert: try to disable secure boot and install OS patches\n");
|
||||
|
||||
@@ -2069,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);
|
||||
|
||||
@@ -80,15 +80,11 @@ void extract_ports(const struct tcphdr *tcphdr, const struct udphdr *udphdr, uin
|
||||
void extract_endpoints(const struct ip *ip,const struct ip6_hdr *ip6hdr,const struct tcphdr *tcphdr,const struct udphdr *udphdr, struct sockaddr_storage *src, struct sockaddr_storage *dst);
|
||||
bool extract_dst(const uint8_t *data, size_t len, struct sockaddr* dst);
|
||||
uint8_t *tcp_find_option(struct tcphdr *tcp, uint8_t kind);
|
||||
uint32_t *tcp_find_timestamps(struct tcphdr *tcp);
|
||||
uint8_t tcp_find_scale_factor(const struct tcphdr *tcp);
|
||||
uint16_t tcp_find_mss(const struct tcphdr *tcp);
|
||||
bool tcp_synack_segment(const struct tcphdr *tcphdr);
|
||||
bool tcp_syn_segment(const struct tcphdr *tcphdr);
|
||||
|
||||
bool ip_has_df(const struct ip *ip);
|
||||
|
||||
|
||||
bool make_writeable_dir();
|
||||
bool ensure_file_access(const char *filename);
|
||||
#ifdef __CYGWIN__
|
||||
@@ -98,7 +94,7 @@ bool ensure_dir_access(const char *filename);
|
||||
bool prepare_low_appdata();
|
||||
bool win_sandbox(void);
|
||||
bool win_dark_init(const struct str_list_head *ssid_filter, const struct str_list_head *nlm_filter);
|
||||
bool win_dark_deinit(void);
|
||||
void win_dark_deinit(void);
|
||||
bool logical_net_filter_present(void);
|
||||
bool logical_net_filter_match(void);
|
||||
bool nlm_list(bool bAll);
|
||||
@@ -139,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);
|
||||
|
||||
350
nfq2/desync.c
350
nfq2/desync.c
@@ -30,7 +30,7 @@ static void protocol_probe(t_protocol_probe *probe, int probe_count, const uint8
|
||||
{
|
||||
for (int i = 0; i < probe_count; i++)
|
||||
{
|
||||
if ((!probe[i].l7match || *l7proto==probe[i].l7) && probe[i].check(data_payload, len_payload))
|
||||
if (!l7_payload_match(probe[i].l7p, params.payload_disable) && (!probe[i].l7match || *l7proto==probe[i].l7) && probe[i].check(data_payload, len_payload))
|
||||
{
|
||||
*l7payload = probe[i].l7p;
|
||||
if (*l7proto == L7_UNKNOWN)
|
||||
@@ -274,14 +274,14 @@ static bool auto_hostlist_retrans
|
||||
if (dis->tcp && ctrack->dp->hostlist_auto_retrans_reset && (dis->ip || dis->ip6))
|
||||
{
|
||||
uint8_t pkt[sizeof(struct ip6_hdr)+sizeof(struct tcphdr)];
|
||||
struct ip *ip;
|
||||
struct ip6_hdr *ip6;
|
||||
struct ip *ip=NULL;
|
||||
struct ip6_hdr *ip6=NULL;
|
||||
struct tcphdr *tcp;
|
||||
uint16_t pktlen;
|
||||
|
||||
if (dis->ip)
|
||||
{
|
||||
ip = (struct ip*)pkt; ip6=NULL;
|
||||
ip = (struct ip*)pkt;
|
||||
pktlen = sizeof(struct ip) + sizeof(struct tcphdr);
|
||||
*ip = *dis->ip;
|
||||
ip->ip_hl = sizeof(struct ip)/4; // remove ip options
|
||||
@@ -292,7 +292,7 @@ static bool auto_hostlist_retrans
|
||||
}
|
||||
else if (dis->ip6)
|
||||
{
|
||||
ip6 = (struct ip6_hdr*)pkt; ip=NULL;
|
||||
ip6 = (struct ip6_hdr*)pkt;
|
||||
pktlen = sizeof(struct ip6_hdr) + sizeof(struct tcphdr);
|
||||
*ip6 = *dis->ip6;
|
||||
ip6->ip6_plen = htons(sizeof(struct tcphdr));
|
||||
@@ -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);
|
||||
@@ -753,7 +742,6 @@ static uint8_t desync(
|
||||
struct func_list *func;
|
||||
int ref_arg = LUA_NOREF, status;
|
||||
bool b, b_cutoff_all, b_unwanted_payload;
|
||||
t_lua_desync_context ctx = { .magic = 0, .dp = dp, .ctrack = ctrack, .dis = dis, .cancel = false, .incoming = bIncoming };
|
||||
const char *sDirection = bIncoming ? "in" : "out";
|
||||
struct packet_range *range;
|
||||
size_t l;
|
||||
@@ -782,13 +770,24 @@ static uint8_t desync(
|
||||
|
||||
if (LIST_FIRST(&dp->lua_desync))
|
||||
{
|
||||
lua_rawgeti(params.L, LUA_REGISTRYINDEX, params.ref_desync_ctx);
|
||||
t_lua_desync_context *ctx = (t_lua_desync_context *)luaL_checkudata(params.L, 1, "desync_ctx");
|
||||
// this is singleton stored in the registry. safe to pop
|
||||
lua_pop(params.L,1);
|
||||
|
||||
ctx->dp = dp;
|
||||
ctx->ctrack = ctrack;
|
||||
ctx->dis = dis;
|
||||
ctx->cancel = false;
|
||||
ctx->incoming = bIncoming;
|
||||
|
||||
b_cutoff_all = b_unwanted_payload = true;
|
||||
ctx.func_n = 1;
|
||||
ctx->func_n = 1;
|
||||
LIST_FOREACH(func, &dp->lua_desync, next)
|
||||
{
|
||||
ctx.func = func->func;
|
||||
desync_instance(func->func, dp->n, ctx.func_n, instance, sizeof(instance));
|
||||
ctx.instance = instance;
|
||||
ctx->func = func->func;
|
||||
desync_instance(func->func, dp->n, ctx->func_n, instance, sizeof(instance));
|
||||
ctx->instance = instance;
|
||||
range = bIncoming ? &func->range_in : &func->range_out;
|
||||
|
||||
if (b_unwanted_payload)
|
||||
@@ -796,7 +795,7 @@ static uint8_t desync(
|
||||
|
||||
if (b_cutoff_all)
|
||||
{
|
||||
if (lua_instance_cutoff_check(&ctx, bIncoming))
|
||||
if (lua_instance_cutoff_check(params.L, ctx, bIncoming))
|
||||
DLOG("* lua '%s' : voluntary cutoff\n", instance);
|
||||
else if (check_pos_cutoff(pos, range))
|
||||
{
|
||||
@@ -814,7 +813,7 @@ static uint8_t desync(
|
||||
else
|
||||
b_cutoff_all = false;
|
||||
}
|
||||
ctx.func_n++;
|
||||
ctx->func_n++;
|
||||
}
|
||||
if (b_cutoff_all)
|
||||
{
|
||||
@@ -827,54 +826,56 @@ static uint8_t desync(
|
||||
{
|
||||
// create arg table that persists across multiple desync function calls
|
||||
lua_newtable(params.L);
|
||||
lua_pushf_dissect(dis);
|
||||
lua_pushf_ctrack(ctrack, tpos, bIncoming);
|
||||
lua_pushf_int("profile_n", dp->n);
|
||||
if (dp->name) lua_pushf_str("profile_name", dp->name);
|
||||
if (dp->n_tpl) lua_pushf_int("template_n", dp->n_tpl);
|
||||
if (dp->name_tpl) lua_pushf_str("template_name", dp->name_tpl);
|
||||
if (dp->cookie) lua_pushf_str("cookie", dp->cookie);
|
||||
lua_pushf_bool("outgoing", !bIncoming);
|
||||
lua_pushf_str("ifin", (ifin && *ifin) ? ifin : NULL);
|
||||
lua_pushf_str("ifout", (ifout && *ifout) ? ifout : NULL);
|
||||
lua_pushf_lint("fwmark", fwmark);
|
||||
lua_pushf_table("target");
|
||||
lua_pushf_dissect(params.L, dis);
|
||||
lua_pushf_ctrack(params.L, ctrack, tpos, bIncoming);
|
||||
lua_pushf_int(params.L, "profile_n", dp->n);
|
||||
if (dp->name) lua_pushf_str(params.L, "profile_name", dp->name);
|
||||
if (dp->n_tpl) lua_pushf_int(params.L, "template_n", dp->n_tpl);
|
||||
if (dp->name_tpl) lua_pushf_str(params.L, "template_name", dp->name_tpl);
|
||||
if (dp->cookie) lua_pushf_str(params.L, "cookie", dp->cookie);
|
||||
lua_pushf_bool(params.L, "outgoing", !bIncoming);
|
||||
lua_pushf_str(params.L, "ifin", (ifin && *ifin) ? ifin : NULL);
|
||||
lua_pushf_str(params.L, "ifout", (ifout && *ifout) ? ifout : NULL);
|
||||
lua_pushf_lint(params.L, "fwmark", fwmark);
|
||||
lua_pushf_table(params.L, "target");
|
||||
lua_getfield(params.L,-1,"target");
|
||||
if (sdport) lua_pushf_int("port",sdport);
|
||||
if (sdp4) lua_pushf_lstr("ip",(const char*)sdp4,sizeof(*sdp4));
|
||||
if (sdp6) lua_pushf_lstr("ip6",(const char*)sdp6,sizeof(*sdp6));
|
||||
if (sdport) lua_pushf_int(params.L, "port",sdport);
|
||||
if (sdp4) lua_pushf_lstr(params.L, "ip",(const char*)sdp4,sizeof(*sdp4));
|
||||
if (sdp6) lua_pushf_lstr(params.L, "ip6",(const char*)sdp6,sizeof(*sdp6));
|
||||
lua_pop(params.L,1);
|
||||
lua_pushf_bool("replay", !!replay_piece_count);
|
||||
lua_pushf_bool(params.L, "replay", !!replay_piece_count);
|
||||
if (replay_piece_count)
|
||||
{
|
||||
lua_pushf_int("replay_piece", replay_piece+1);
|
||||
lua_pushf_int("replay_piece_count", replay_piece_count);
|
||||
lua_pushf_bool("replay_piece_last", (replay_piece+1)>=replay_piece_count);
|
||||
lua_pushf_int(params.L, "replay_piece", replay_piece+1);
|
||||
lua_pushf_int(params.L, "replay_piece_count", replay_piece_count);
|
||||
lua_pushf_bool(params.L, "replay_piece_last", (replay_piece+1)>=replay_piece_count);
|
||||
}
|
||||
lua_pushf_str("l7payload", l7payload_str(l7payload));
|
||||
lua_pushf_str("l7proto", l7proto_str(l7proto));
|
||||
lua_pushf_int("reasm_offset", reasm_offset);
|
||||
lua_pushf_raw("reasm_data", rdata_payload, rlen_payload);
|
||||
lua_pushf_raw("decrypt_data", data_decrypt, len_decrypt);
|
||||
lua_pushf_str(params.L, "l7payload", l7payload_str(l7payload));
|
||||
lua_pushf_str(params.L, "l7proto", l7proto_str(l7proto));
|
||||
lua_pushf_int(params.L, "reasm_offset", reasm_offset);
|
||||
lua_pushf_raw(params.L, "reasm_data", rdata_payload, rlen_payload);
|
||||
lua_pushf_raw(params.L, "decrypt_data", data_decrypt, len_decrypt);
|
||||
//if (ctrack) lua_pushf_reg("instance_cutoff", ctrack->lua_instance_cutoff);
|
||||
if (dis->tcp)
|
||||
{
|
||||
// recommended mss value for generated packets
|
||||
if (rpos && rpos->mss)
|
||||
lua_pushf_int("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
|
||||
lua_pushf_global("tcp_mss", "DEFAULT_MSS");
|
||||
// this value should always work
|
||||
lua_pushf_global(params.L, "tcp_mss", "DEFAULT_MSS");
|
||||
}
|
||||
ref_arg = luaL_ref(params.L, LUA_REGISTRYINDEX);
|
||||
|
||||
ctx.func_n = 1;
|
||||
ctx->func_n = 1;
|
||||
LIST_FOREACH(func, &dp->lua_desync, next)
|
||||
{
|
||||
ctx.func = func->func;
|
||||
desync_instance(func->func, dp->n, ctx.func_n, instance, sizeof(instance));
|
||||
ctx.instance = instance;
|
||||
ctx->func = func->func;
|
||||
desync_instance(func->func, dp->n, ctx->func_n, instance, sizeof(instance));
|
||||
ctx->instance = instance;
|
||||
|
||||
if (!lua_instance_cutoff_check(&ctx, bIncoming))
|
||||
if (!lua_instance_cutoff_check(params.L, ctx, bIncoming))
|
||||
{
|
||||
range = bIncoming ? &func->range_in : &func->range_out;
|
||||
if (check_pos_range(pos, range))
|
||||
@@ -897,19 +898,17 @@ static uint8_t desync(
|
||||
DLOG_ERR("desync function '%s' does not exist\n", func->func);
|
||||
goto err;
|
||||
}
|
||||
lua_pushlightuserdata(params.L, &ctx);
|
||||
lua_rawgeti(params.L, LUA_REGISTRYINDEX, params.ref_desync_ctx);
|
||||
lua_rawgeti(params.L, LUA_REGISTRYINDEX, ref_arg);
|
||||
lua_pushf_args(&func->args, -1, true);
|
||||
lua_pushf_str("func", func->func);
|
||||
lua_pushf_int("func_n", ctx.func_n);
|
||||
lua_pushf_str("func_instance", instance);
|
||||
lua_pushf_args(params.L, &func->args, -1, true);
|
||||
lua_pushf_str(params.L, "func", func->func);
|
||||
lua_pushf_int(params.L, "func_n", ctx->func_n);
|
||||
lua_pushf_str(params.L, "func_instance", instance);
|
||||
|
||||
// lua should not store and access ctx outside of this call
|
||||
// if this happens make our best to prevent access to bad memory
|
||||
// this is not crash-proof but better than nothing
|
||||
ctx.magic = MAGIC_CTX; // mark struct as valid
|
||||
// prevent use of desync ctx object outside of function call
|
||||
ctx->valid = true;
|
||||
status = lua_pcall(params.L, 2, LUA_MULTRET, 0);
|
||||
ctx.magic = 0; // mark struct as invalid
|
||||
ctx->valid = false;
|
||||
|
||||
if (status)
|
||||
{
|
||||
@@ -939,8 +938,8 @@ static uint8_t desync(
|
||||
range->upper_cutoff ? '<' : '-',
|
||||
range->to.mode, range->to.pos);
|
||||
}
|
||||
if (ctx.cancel) break;
|
||||
ctx.func_n++;
|
||||
if (ctx->cancel) break;
|
||||
ctx->func_n++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -960,7 +959,7 @@ static uint8_t desync(
|
||||
}
|
||||
else
|
||||
{
|
||||
b = lua_reconstruct_dissect(-1, mod_pkt, len_mod_pkt, false, false);
|
||||
b = lua_reconstruct_dissect(params.L, -1, mod_pkt, len_mod_pkt, false, false);
|
||||
lua_pop(params.L, 2);
|
||||
if (!b)
|
||||
{
|
||||
@@ -1117,7 +1116,7 @@ static uint8_t dpi_desync_tcp_packet_play(
|
||||
}
|
||||
}
|
||||
// in absence of conntrack guess direction by presence of interface names. won't work on BSD
|
||||
bReverseFixed = ctrack ? (bReverse ^ params.server) : (bReverse = ifin && ifin && (!ifout || !*ifout));
|
||||
bReverseFixed = ctrack ? (bReverse ^ params.server) : (bReverse = ifin && *ifin && (!ifout || !*ifout));
|
||||
setup_direction(dis, bReverseFixed, &src, &dst, &sdip4, &sdip6, &sdport);
|
||||
ifname = bReverse ? ifin : ifout;
|
||||
#ifdef HAS_FILTER_SSID
|
||||
@@ -1155,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(¶ms.conntrack);
|
||||
|
||||
@@ -1272,19 +1271,32 @@ static uint8_t dpi_desync_tcp_packet_play(
|
||||
|
||||
process_retrans_fail(ctrack, dis, (struct sockaddr*)&src, ifin);
|
||||
|
||||
if (IsHttp(rdata_payload, rlen_payload))
|
||||
// do not detect payload if reasm is in progress
|
||||
if (!ctrack_replay || ReasmIsEmpty(&ctrack_replay->reasm_client))
|
||||
{
|
||||
DLOG("packet contains HTTP request\n");
|
||||
l7payload = L7P_HTTP_REQ;
|
||||
if (l7proto == L7_UNKNOWN)
|
||||
t_protocol_probe testers[] = {
|
||||
{L7P_TLS_CLIENT_HELLO,L7_TLS,IsTLSClientHelloPartial},
|
||||
{L7P_HTTP_REQ,L7_HTTP,IsHttp,false},
|
||||
{L7P_XMPP_STREAM,L7_XMPP,IsXMPPStream,false},
|
||||
{L7P_XMPP_STARTTLS,L7_XMPP,IsXMPPStartTLS,false}
|
||||
};
|
||||
protocol_probe(testers, sizeof(testers) / sizeof(*testers), dis->data_payload, dis->len_payload, ctrack, &l7proto, &l7payload);
|
||||
|
||||
if (l7payload==L7P_UNKNOWN)
|
||||
{
|
||||
l7proto = L7_HTTP;
|
||||
if (ctrack && ctrack->l7proto == L7_UNKNOWN) ctrack->l7proto = l7proto;
|
||||
// this is special type. detection requires AES and can be successful only for the first data packet. no reason to AES every packet
|
||||
if (ctrack && (ctrack->pos.client.seq_last - ctrack->pos.client.seq0)==1)
|
||||
{
|
||||
t_protocol_probe testers[] = {
|
||||
{L7P_MTPROTO_INITIAL,L7_MTPROTO,IsMTProto}
|
||||
};
|
||||
protocol_probe(testers, sizeof(testers) / sizeof(*testers), dis->data_payload, dis->len_payload, ctrack, &l7proto, &l7payload);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// we do not reassemble http
|
||||
reasm_client_cancel(ctrack);
|
||||
|
||||
if (l7payload==L7P_HTTP_REQ)
|
||||
{
|
||||
bHaveHost = HttpExtractHost(rdata_payload, rlen_payload, host, sizeof(host));
|
||||
if (!bHaveHost)
|
||||
{
|
||||
@@ -1292,21 +1304,17 @@ static uint8_t dpi_desync_tcp_packet_play(
|
||||
goto pass;
|
||||
}
|
||||
}
|
||||
else if (IsTLSClientHello(rdata_payload, rlen_payload, TLS_PARTIALS_ENABLE))
|
||||
else if (l7payload==L7P_TLS_CLIENT_HELLO || l7proto==L7_TLS && l7payload==L7P_UNKNOWN && ctrack_replay && !ReasmIsEmpty(&ctrack_replay->reasm_client))
|
||||
{
|
||||
bool bReqFull = IsTLSRecordFull(rdata_payload, rlen_payload);
|
||||
DLOG(bReqFull ? "packet contains full TLS ClientHello\n" : "packet contains partial TLS ClientHello\n");
|
||||
l7payload = L7P_TLS_CLIENT_HELLO;
|
||||
if (l7proto == L7_UNKNOWN)
|
||||
{
|
||||
l7proto = L7_TLS;
|
||||
if (ctrack && ctrack->l7proto == L7_UNKNOWN) ctrack->l7proto = l7proto;
|
||||
}
|
||||
|
||||
bool bReqFull = IsTLSRecordFull(rdata_payload, rlen_payload);
|
||||
DLOG(bReqFull ? "TLS client hello is FULL\n" : "TLS client hello is PARTIAL\n");
|
||||
|
||||
if (bReqFull) TLSDebug(rdata_payload, rlen_payload);
|
||||
|
||||
bHaveHost = TLSHelloExtractHost(rdata_payload, rlen_payload, host, sizeof(host), TLS_PARTIALS_ENABLE);
|
||||
if (ctrack && !(params.reasm_payload_disable && l7_payload_match(l7payload, params.reasm_payload_disable)))
|
||||
bHaveHost = TLSHelloExtractHost(rdata_payload, rlen_payload, host, sizeof(host), true);
|
||||
if (ctrack && !l7_payload_match(l7payload, params.reasm_payload_disable))
|
||||
{
|
||||
// do not reasm retransmissions
|
||||
if (!bReqFull && ReasmIsEmpty(&ctrack->reasm_client) && !is_retransmission(&ctrack->pos.client))
|
||||
@@ -1318,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));
|
||||
}
|
||||
@@ -1336,26 +1344,6 @@ static uint8_t dpi_desync_tcp_packet_play(
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (ctrack && (ctrack->pos.client.seq_last - ctrack->pos.client.seq0)==1 && IsMTProto(dis->data_payload, dis->len_payload))
|
||||
{
|
||||
DLOG("packet contains telegram mtproto2 initial\n");
|
||||
// mtproto detection requires aes. react only on the first tcp data packet. do not detect if ctrack unavailable.
|
||||
l7payload = L7P_MTPROTO_INITIAL;
|
||||
if (l7proto == L7_UNKNOWN)
|
||||
{
|
||||
l7proto = L7_MTPROTO;
|
||||
if (ctrack->l7proto == L7_UNKNOWN) ctrack->l7proto = l7proto;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
t_protocol_probe testers[] = {
|
||||
{L7P_XMPP_STREAM,L7_XMPP,IsXMPPStream,false},
|
||||
{L7P_XMPP_STARTTLS,L7_XMPP,IsXMPPStartTLS,false}
|
||||
};
|
||||
protocol_probe(testers, sizeof(testers) / sizeof(*testers), dis->data_payload, dis->len_payload, ctrack, &l7proto, &l7payload);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (bHaveHost)
|
||||
@@ -1492,6 +1480,88 @@ static void udp_standard_protocol_probe(const uint8_t *data_payload, size_t len_
|
||||
protocol_probe(testers, sizeof(testers) / sizeof(*testers), data_payload, len_payload, ctrack, l7proto, l7payload);
|
||||
}
|
||||
|
||||
static const uint8_t *dns_extract_name(const uint8_t *a, const uint8_t *b, const uint8_t *e, char *name, size_t name_size)
|
||||
{
|
||||
size_t nl, off;
|
||||
const uint8_t *p;
|
||||
bool bptr = (*a & 0xC0)==0xC0;
|
||||
|
||||
if (bptr)
|
||||
{
|
||||
// name pointer
|
||||
off = (*a & 0x3F)<<8 | a[1];
|
||||
p = b + off;
|
||||
}
|
||||
else
|
||||
// real name
|
||||
p = a;
|
||||
|
||||
if (p>=e) return NULL;
|
||||
for (nl=0; *p ;)
|
||||
{
|
||||
if ((p+*p+1)>=e || (*p+1)>=(name_size-nl)) return NULL;
|
||||
if (nl) name[nl++] = '.';
|
||||
memcpy(name + nl, p + 1, *p);
|
||||
nl += *p;
|
||||
p += *p + 1;
|
||||
}
|
||||
name[nl] = 0;
|
||||
return bptr ? a+2 : p+1;
|
||||
}
|
||||
static bool feed_dns_response(const uint8_t *a, size_t len)
|
||||
{
|
||||
if (!params.cache_hostname) return true;
|
||||
|
||||
// check of minimum header length and response flag
|
||||
uint16_t k, off, dlen, qcount = a[4]<<8 | a[5], acount = a[6]<<8 | a[7];
|
||||
char s_ip[40];
|
||||
const uint8_t *b = a, *p;
|
||||
const uint8_t *e = b + len;
|
||||
size_t nl;
|
||||
char name[256] = "";
|
||||
|
||||
if (len<12 || !(a[2]&0x80)) return false;
|
||||
a+=12; len-=12;
|
||||
for(k=0;k<qcount;k++)
|
||||
{
|
||||
// remember original query name
|
||||
if (!(p = dns_extract_name(a, b, e, name, sizeof(name)))) return false;
|
||||
len -= p-a;
|
||||
// must be A or AAAA query. others are not interesting
|
||||
if ((len<4) || p[0] || p[1]!=1 && p[1]!=28 || p[2] || p[3]!=1) return false;
|
||||
// skip type, class
|
||||
a=p+4; len-=4;
|
||||
}
|
||||
if (!*name) return false;
|
||||
for(k=0;k<acount;k++)
|
||||
{
|
||||
// 11 higher bits indicate pointer
|
||||
if (len<12 || (*a & 0xC0)!=0xC0) return false;
|
||||
|
||||
dlen = a[10]<<8 | a[11];
|
||||
if (len<(dlen+12)) return false;
|
||||
if (a[4]==0 && a[5]==1 && a[2]==0) // IN class and higher byte of type = 0
|
||||
{
|
||||
switch(a[3])
|
||||
{
|
||||
case 1: // A
|
||||
if (dlen!=4) break;
|
||||
if (params.debug && inet_ntop(AF_INET, a+12, s_ip, sizeof(s_ip)))
|
||||
DLOG("DNS response : %s\n", s_ip);
|
||||
ipcache_put_hostname((struct in_addr *)(a+12), NULL, name, false);
|
||||
break;
|
||||
case 28: // AAAA
|
||||
if (dlen!=16) break;
|
||||
if (params.debug && inet_ntop(AF_INET6, a+12, s_ip, sizeof(s_ip)))
|
||||
DLOG("DNS response : %s\n", s_ip);
|
||||
ipcache_put_hostname(NULL, (struct in6_addr *)(a+12), name, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
len -= 12+dlen; a += 12+dlen;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static uint8_t dpi_desync_udp_packet_play(
|
||||
unsigned int replay_piece, unsigned int replay_piece_count, size_t reasm_offset,
|
||||
@@ -1581,7 +1651,7 @@ static uint8_t dpi_desync_udp_packet_play(
|
||||
}
|
||||
}
|
||||
// in absence of conntrack guess direction by presence of interface names. won't work on BSD
|
||||
bReverseFixed = ctrack ? (bReverse ^ params.server) : (bReverse = ifin && ifin && (!ifout || !*ifout));
|
||||
bReverseFixed = ctrack ? (bReverse ^ params.server) : (bReverse = ifin && *ifin && (!ifout || !*ifout));
|
||||
setup_direction(dis, bReverseFixed, &src, &dst, &sdip4, &sdip6, &sdport);
|
||||
|
||||
ifname = bReverse ? ifin : ifout;
|
||||
@@ -1620,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(¶ms.conntrack);
|
||||
|
||||
if (bReverseFixed)
|
||||
@@ -1652,22 +1722,13 @@ static uint8_t dpi_desync_udp_packet_play(
|
||||
if (dis->len_payload)
|
||||
{
|
||||
bool bHaveHost = false, bHostIsIp = false;
|
||||
if (bReverse)
|
||||
|
||||
udp_standard_protocol_probe(dis->data_payload, dis->len_payload, ctrack, &l7proto, &l7payload);
|
||||
|
||||
if (!bReverse)
|
||||
{
|
||||
udp_standard_protocol_probe(dis->data_payload, dis->len_payload, ctrack, &l7proto, &l7payload);
|
||||
}
|
||||
else
|
||||
{
|
||||
struct blob_collection_head *fake;
|
||||
if (IsQUICInitial(dis->data_payload, dis->len_payload))
|
||||
if (l7payload==L7P_QUIC_INITIAL)
|
||||
{
|
||||
DLOG("packet contains QUIC initial\n");
|
||||
l7payload = L7P_QUIC_INITIAL;
|
||||
|
||||
l7proto = L7_QUIC;
|
||||
// update ctrack l7proto here because reasm can happen
|
||||
if (ctrack && ctrack->l7proto == L7_UNKNOWN) ctrack->l7proto = l7proto;
|
||||
|
||||
uint8_t clean[UDP_MAX_REASM], *pclean;
|
||||
size_t clean_len;
|
||||
|
||||
@@ -1683,7 +1744,7 @@ static uint8_t dpi_desync_udp_packet_play(
|
||||
}
|
||||
if (pclean)
|
||||
{
|
||||
bool reasm_disable = params.reasm_payload_disable && l7_payload_match(l7payload, params.reasm_payload_disable);
|
||||
bool reasm_disable = l7_payload_match(l7payload, params.reasm_payload_disable);
|
||||
if (ctrack && !reasm_disable && !ReasmIsEmpty(&ctrack->reasm_client))
|
||||
{
|
||||
if (ReasmHasSpace(&ctrack->reasm_client, clean_len))
|
||||
@@ -1723,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));
|
||||
}
|
||||
@@ -1745,7 +1806,7 @@ static uint8_t dpi_desync_udp_packet_play(
|
||||
{
|
||||
data_decrypt = defrag + hello_offset;
|
||||
len_decrypt = hello_len;
|
||||
bHaveHost = TLSHelloExtractHostFromHandshake(data_decrypt, len_decrypt, host, sizeof(host), TLS_PARTIALS_ENABLE);
|
||||
bHaveHost = TLSHelloExtractHostFromHandshake(data_decrypt, len_decrypt, host, sizeof(host), true);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1763,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));
|
||||
}
|
||||
@@ -1789,15 +1850,14 @@ static uint8_t dpi_desync_udp_packet_play(
|
||||
quic_reasm_cancel(ctrack, "QUIC initial decryption failed");
|
||||
}
|
||||
}
|
||||
else // not QUIC initial
|
||||
{
|
||||
// not quic initial - stop reasm
|
||||
reasm_client_cancel(ctrack);
|
||||
|
||||
udp_standard_protocol_probe(dis->data_payload, dis->len_payload, ctrack, &l7proto, &l7payload);
|
||||
}
|
||||
}
|
||||
|
||||
reasm_client_cancel(ctrack);
|
||||
|
||||
if (l7payload==L7P_DNS_RESPONSE)
|
||||
feed_dns_response(dis->data_payload, dis->len_payload);
|
||||
|
||||
|
||||
if (bHaveHost)
|
||||
{
|
||||
bHostIsIp = strip_host_to_ip(host);
|
||||
@@ -1955,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)
|
||||
{
|
||||
@@ -1965,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;
|
||||
}
|
||||
@@ -1983,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(¶ms.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);
|
||||
}
|
||||
|
||||
@@ -31,7 +31,12 @@ int z_readfile(FILE *F, char **buf, size_t *size, size_t extra_alloc)
|
||||
r = Z_ERRNO;
|
||||
goto zerr;
|
||||
}
|
||||
if (!zs.avail_in) break;
|
||||
if (!zs.avail_in)
|
||||
{
|
||||
// file is not full
|
||||
r = Z_DATA_ERROR;
|
||||
goto zerr;
|
||||
}
|
||||
zs.next_in = in;
|
||||
do
|
||||
{
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
#define UNIQ_SORT \
|
||||
{ \
|
||||
int i, j, u; \
|
||||
size_t i, j, u; \
|
||||
for (i = j = 0; j < ct; i++) \
|
||||
{ \
|
||||
u = pu[j++]; \
|
||||
@@ -396,16 +396,16 @@ void phton64(uint8_t *p, uint64_t v)
|
||||
p[7] = (uint8_t)v;
|
||||
}
|
||||
|
||||
uint16_t swap16(uint16_t u)
|
||||
uint16_t bswap16(uint16_t u)
|
||||
{
|
||||
// __builtin_bswap16 is absent in ancient lexra gcc 4.6
|
||||
return (u>>8) | ((u&0xFF)<<8);
|
||||
}
|
||||
uint32_t swap24(uint32_t u)
|
||||
uint32_t bswap24(uint32_t u)
|
||||
{
|
||||
return (u>>16) & 0xFF | u & 0xFF00 | (u<<16) & 0xFF0000;
|
||||
}
|
||||
uint64_t swap48(uint64_t u)
|
||||
uint64_t bswap48(uint64_t u)
|
||||
{
|
||||
return ((u & 0xFF0000000000) >> 40) | ((u & 0xFF00000000) >> 24) | ((u & 0xFF000000) >> 8) | ((u & 0xFF0000) << 8) | ((u & 0xFF00) << 24) | ((u & 0xFF) << 40);
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
@@ -642,42 +642,13 @@ bool set_env_exedir(const char *argv0)
|
||||
if ((s = strdup(argv0)))
|
||||
{
|
||||
if ((d = dirname(s)))
|
||||
setenv("EXEDIR",s,1);
|
||||
bOK = !setenv("EXEDIR",d,1);
|
||||
free(s);
|
||||
}
|
||||
return bOK;
|
||||
}
|
||||
|
||||
|
||||
static void mask_from_preflen6_make(uint8_t plen, struct in6_addr *a)
|
||||
{
|
||||
if (plen >= 128)
|
||||
memset(a->s6_addr,0xFF,16);
|
||||
else
|
||||
{
|
||||
uint8_t n = plen >> 3;
|
||||
memset(a->s6_addr,0xFF,n);
|
||||
memset(a->s6_addr+n,0x00,16-n);
|
||||
a->s6_addr[n] = (uint8_t)(0xFF00 >> (plen & 7));
|
||||
}
|
||||
}
|
||||
struct in6_addr ip6_mask[129];
|
||||
void mask_from_preflen6_prepare(void)
|
||||
{
|
||||
for (int plen=0;plen<=128;plen++) mask_from_preflen6_make(plen, ip6_mask+plen);
|
||||
}
|
||||
|
||||
#if defined(__GNUC__) && !defined(__llvm__)
|
||||
__attribute__((optimize ("no-strict-aliasing")))
|
||||
#endif
|
||||
void ip6_and(const struct in6_addr * restrict a, const struct in6_addr * restrict b, struct in6_addr * restrict result)
|
||||
{
|
||||
// int128 requires 16-bit alignment. in struct sockaddr_in6.sin6_addr is 8-byte aligned.
|
||||
// it causes segfault on x64 arch with latest compiler. it can cause misalign slowdown on other archs
|
||||
// use 64-bit AND
|
||||
((uint64_t*)result->s6_addr)[0] = ((uint64_t*)a->s6_addr)[0] & ((uint64_t*)b->s6_addr)[0];
|
||||
((uint64_t*)result->s6_addr)[1] = ((uint64_t*)a->s6_addr)[1] & ((uint64_t*)b->s6_addr)[1];
|
||||
}
|
||||
|
||||
void str_cidr4(char *s, size_t s_len, const struct cidr4 *cidr)
|
||||
{
|
||||
|
||||
@@ -66,9 +66,9 @@ void phton48(uint8_t *p, uint64_t v);
|
||||
uint64_t pntoh64(const uint8_t *p);
|
||||
void phton64(uint8_t *p, uint64_t v);
|
||||
|
||||
uint16_t swap16(uint16_t u);
|
||||
uint32_t swap24(uint32_t u);
|
||||
uint64_t swap48(uint64_t u);
|
||||
uint16_t bswap16(uint16_t u);
|
||||
uint32_t bswap24(uint32_t u);
|
||||
uint64_t bswap48(uint64_t u);
|
||||
|
||||
bool parse_hex_str(const char *s, uint8_t *pbuf, size_t *size);
|
||||
char hex_digit(uint8_t v);
|
||||
@@ -139,15 +139,3 @@ bool parse_cidr4(char *s, struct cidr4 *cidr);
|
||||
bool parse_cidr6(char *s, struct cidr6 *cidr);
|
||||
|
||||
bool parse_int16(const char *p, int16_t *v);
|
||||
|
||||
static inline uint32_t mask_from_preflen(uint32_t preflen)
|
||||
{
|
||||
return preflen ? preflen<32 ? ~((1 << (32-preflen)) - 1) : 0xFFFFFFFF : 0;
|
||||
}
|
||||
void ip6_and(const struct in6_addr * restrict a, const struct in6_addr * restrict b, struct in6_addr * restrict result);
|
||||
extern struct in6_addr ip6_mask[129];
|
||||
void mask_from_preflen6_prepare(void);
|
||||
static inline const struct in6_addr *mask_from_preflen6(uint8_t preflen)
|
||||
{
|
||||
return ip6_mask+preflen;
|
||||
}
|
||||
|
||||
@@ -8,13 +8,8 @@ static bool addpool(hostlist_pool **hostlist, char **s, const char *end, int *ct
|
||||
{
|
||||
char *p=*s;
|
||||
|
||||
// comment line
|
||||
if ( *p == '#' || *p == ';' || *p == '/' || *p == '\r' || *p == '\n')
|
||||
{
|
||||
// advance until eol
|
||||
for (; p<end && *p && *p!='\r' && *p != '\n'; p++);
|
||||
}
|
||||
else
|
||||
// comment line ?
|
||||
if ( *p != '#' && *p != ';' && *p != '/' && *p != '\r' && *p != '\n')
|
||||
{
|
||||
// advance until eol lowering all chars
|
||||
uint32_t flags = 0;
|
||||
@@ -23,7 +18,7 @@ static bool addpool(hostlist_pool **hostlist, char **s, const char *end, int *ct
|
||||
p = ++(*s);
|
||||
flags |= HOSTLIST_POOL_FLAG_STRICT_MATCH;
|
||||
}
|
||||
for (; p<end && *p && *p!='\r' && *p != '\n'; p++) *p=tolower(*p);
|
||||
for (; p<end && *p && *p!=' ' && *p!='\t' && *p!='\r' && *p != '\n'; p++) *p=tolower(*p);
|
||||
if (!HostlistPoolAddStrLen(hostlist, *s, p-*s, flags))
|
||||
{
|
||||
HostlistPoolDestroy(hostlist);
|
||||
@@ -32,6 +27,8 @@ static bool addpool(hostlist_pool **hostlist, char **s, const char *end, int *ct
|
||||
}
|
||||
if (ct) (*ct)++;
|
||||
}
|
||||
// skip remaining non-eol chars
|
||||
for (; p<end && *p && *p!='\r' && *p != '\n'; p++);
|
||||
// advance to the next line
|
||||
for (; p<end && (!*p || *p=='\r' || *p=='\n') ; p++);
|
||||
*s = p;
|
||||
@@ -82,7 +79,7 @@ bool AppendHostList(hostlist_pool **hostlist, const char *filename)
|
||||
}
|
||||
else
|
||||
{
|
||||
DLOG_ERR("zlib decompression failed : result %d\n",r);
|
||||
DLOG_ERR("zlib decompression failed : result %d\n", r);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#include "helpers.h"
|
||||
|
||||
|
||||
// inplace tolower() and add to pool
|
||||
static bool addpool(ipset *ips, char **s, const char *end, int *ct)
|
||||
{
|
||||
char *p, cidr[128];
|
||||
@@ -12,8 +11,7 @@ static bool addpool(ipset *ips, char **s, const char *end, int *ct)
|
||||
struct cidr4 c4;
|
||||
struct cidr6 c6;
|
||||
|
||||
// advance until eol
|
||||
for (p=*s; p<end && *p && *p!='\r' && *p != '\n'; p++);
|
||||
for (p=*s; p<end && *p && *p!=' ' && *p!='\t' && *p!='\r' && *p != '\n'; p++);
|
||||
|
||||
// comment line
|
||||
if (!(**s == '#' || **s == ';' || **s == '/' || **s == '\r' || **s == '\n' ))
|
||||
@@ -22,7 +20,6 @@ static bool addpool(ipset *ips, char **s, const char *end, int *ct)
|
||||
if (l>=sizeof(cidr)) l=sizeof(cidr)-1;
|
||||
memcpy(cidr,*s,l);
|
||||
cidr[l]=0;
|
||||
rtrim(cidr);
|
||||
|
||||
if (parse_cidr4(cidr,&c4))
|
||||
{
|
||||
@@ -46,6 +43,8 @@ static bool addpool(ipset *ips, char **s, const char *end, int *ct)
|
||||
DLOG_ERR("bad ip or subnet : %s\n",cidr);
|
||||
}
|
||||
|
||||
// skip remaining non-eol chars
|
||||
for (; p<end && *p && *p!='\r' && *p != '\n'; p++);
|
||||
// advance to the next line
|
||||
for (; p<end && (!*p || *p=='\r' || *p=='\n') ; p++);
|
||||
*s = p;
|
||||
|
||||
1872
nfq2/lua.c
1872
nfq2/lua.c
File diff suppressed because it is too large
Load Diff
89
nfq2/lua.h
89
nfq2/lua.h
@@ -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);
|
||||
|
||||
@@ -57,59 +57,58 @@ int lua_absindex(lua_State *L, int idx);
|
||||
// push - create object and push to the stack
|
||||
// pushf - create object and set it as a named field of a table already present on the stack
|
||||
// pushi - create object and set it as a index field of a table already present on the stack
|
||||
void lua_pushf_nil(const char *field);
|
||||
void lua_pushi_nil(lua_Integer idx);
|
||||
void lua_pushf_bool(const char *field, bool b);
|
||||
void lua_pushi_bool(lua_Integer idx, bool b);
|
||||
void lua_pushf_str(const char *field, const char *str);
|
||||
void lua_pushi_str(lua_Integer idx, const char *str);
|
||||
void lua_pushf_lstr(const char *field, const char *str, size_t len);
|
||||
void lua_pushi_lstr(lua_Integer idx, const char *str, size_t len);
|
||||
void lua_pushf_int(const char *field, lua_Integer v);
|
||||
void lua_pushi_int(lua_Integer idx, lua_Integer v);
|
||||
void lua_pushf_lint(const char *field, int64_t v);
|
||||
void lua_pushi_lint(lua_Integer idx, int64_t v);
|
||||
void lua_pushf_number(const char *field, lua_Number v);
|
||||
void lua_pushi_number(lua_Integer idx, lua_Number v);
|
||||
void lua_push_raw(const void *v, size_t l);
|
||||
void lua_pushf_raw(const char *field, const void *v, size_t l);
|
||||
void lua_pushi_raw(lua_Integer idx, const void *v, size_t l);
|
||||
void lua_pushf_reg(const char *field, int ref);
|
||||
void lua_pushf_lud(const char *field, void *p);
|
||||
void lua_pushf_table(const char *field);
|
||||
void lua_pushi_table(lua_Integer idx);
|
||||
void lua_pushf_nil(lua_State *L, const char *field);
|
||||
void lua_pushi_nil(lua_State *L, lua_Integer idx);
|
||||
void lua_pushf_bool(lua_State *L, const char *field, bool b);
|
||||
void lua_pushi_bool(lua_State *L, lua_Integer idx, bool b);
|
||||
void lua_pushf_str(lua_State *L, const char *field, const char *str);
|
||||
void lua_pushi_str(lua_State *L, lua_Integer idx, const char *str);
|
||||
void lua_pushf_lstr(lua_State *L, const char *field, const char *str, size_t len);
|
||||
void lua_pushi_lstr(lua_State *L, lua_Integer idx, const char *str, size_t len);
|
||||
void lua_pushf_int(lua_State *L, const char *field, lua_Integer v);
|
||||
void lua_pushi_int(lua_State *L, lua_Integer idx, lua_Integer v);
|
||||
void lua_pushf_lint(lua_State *L, const char *field, int64_t v);
|
||||
void lua_pushi_lint(lua_State *L, lua_Integer idx, int64_t v);
|
||||
void lua_pushf_number(lua_State *L, const char *field, lua_Number v);
|
||||
void lua_pushi_number(lua_State *L, lua_Integer idx, lua_Number v);
|
||||
void lua_push_raw(lua_State *L, const void *v, size_t l);
|
||||
void lua_pushf_raw(lua_State *L, const char *field, const void *v, size_t l);
|
||||
void lua_pushi_raw(lua_State *L, lua_Integer idx, const void *v, size_t l);
|
||||
void lua_pushf_reg(lua_State *L, const char *field, int ref);
|
||||
void lua_pushf_lud(lua_State *L, const char *field, void *p);
|
||||
void lua_pushf_table(lua_State *L, const char *field);
|
||||
void lua_pushi_table(lua_State *L, lua_Integer idx);
|
||||
|
||||
void lua_push_blob(int idx_desync, const char *blob);
|
||||
void lua_pushf_blob(int idx_desync, const char *field, const char *blob);
|
||||
void lua_push_blob(lua_State *L, int idx_desync, const char *blob);
|
||||
void lua_pushf_blob(lua_State *L, int idx_desync, const char *field, const char *blob);
|
||||
|
||||
void lua_pushf_tcphdr_options(const struct tcphdr *tcp, size_t len);
|
||||
void lua_pushf_tcphdr(const struct tcphdr *tcp, size_t len);
|
||||
void lua_pushf_udphdr(const struct udphdr *udp, size_t len);
|
||||
void lua_pushf_iphdr(const struct ip *ip, size_t len);
|
||||
void lua_pushf_ip6hdr(const struct ip6_hdr *ip6, size_t len);
|
||||
void lua_push_dissect(const struct dissect *dis);
|
||||
void lua_pushf_dissect(const struct dissect *dis);
|
||||
void lua_pushf_ctrack(const t_ctrack *ctrack, const t_ctrack_positions *tpos, bool bIncoming);
|
||||
void lua_pushf_args(const struct str2_list_head *args, int idx_desync, bool subst_prefix);
|
||||
void lua_pushf_pos(const char *name, const struct packet_pos *pos);
|
||||
void lua_pushf_range(const char *name, const struct packet_range *range);
|
||||
void lua_pushf_global(const char *field, const char *global);
|
||||
void lua_pushf_tcphdr_options(lua_State *L, const struct tcphdr *tcp, size_t len);
|
||||
void lua_pushf_tcphdr(lua_State *L, const struct tcphdr *tcp, size_t len);
|
||||
void lua_pushf_udphdr(lua_State *L, const struct udphdr *udp, size_t len);
|
||||
void lua_pushf_iphdr(lua_State *L, const struct ip *ip, size_t len);
|
||||
void lua_pushf_ip6hdr(lua_State *L, const struct ip6_hdr *ip6, size_t len);
|
||||
void lua_push_dissect(lua_State *L, const struct dissect *dis);
|
||||
void lua_pushf_dissect(lua_State *L, const struct dissect *dis);
|
||||
void lua_pushf_ctrack(lua_State *L, const t_ctrack *ctrack, const t_ctrack_positions *tpos, bool bIncoming);
|
||||
void lua_pushf_args(lua_State *L, const struct str2_list_head *args, int idx_desync, bool subst_prefix);
|
||||
void lua_pushf_pos(lua_State *L, const char *name, const struct packet_pos *pos);
|
||||
void lua_pushf_range(lua_State *L, const char *name, const struct packet_range *range);
|
||||
void lua_pushf_global(lua_State *L, const char *field, const char *global);
|
||||
|
||||
bool lua_reconstruct_ip6hdr(int idx, struct ip6_hdr *ip6, size_t *len, uint8_t last_proto, bool preserve_next);
|
||||
bool lua_reconstruct_iphdr(int idx, struct ip *ip, size_t *len);
|
||||
bool lua_reconstruct_tcphdr(int idx, struct tcphdr *tcp, size_t *len);
|
||||
bool lua_reconstruct_udphdr(int idx, struct udphdr *udp);
|
||||
bool lua_reconstruct_dissect(int idx, uint8_t *buf, size_t *len, bool badsum, bool ip6_preserve_next);
|
||||
bool lua_reconstruct_ip6hdr(lua_State *L, int idx, struct ip6_hdr *ip6, size_t *len, uint8_t last_proto, bool preserve_next);
|
||||
bool lua_reconstruct_iphdr(lua_State *L, int idx, struct ip *ip, size_t *len);
|
||||
bool lua_reconstruct_tcphdr(lua_State *L, int idx, struct tcphdr *tcp, size_t *len);
|
||||
bool lua_reconstruct_udphdr(lua_State *L, int idx, struct udphdr *udp);
|
||||
bool lua_reconstruct_dissect(lua_State *L, int idx, uint8_t *buf, size_t *len, bool badsum, bool ip6_preserve_next);
|
||||
|
||||
#define MAGIC_CTX 0xE73DC935
|
||||
typedef struct {
|
||||
uint32_t magic;
|
||||
unsigned int func_n;
|
||||
const char *func, *instance;
|
||||
const struct desync_profile *dp;
|
||||
const struct dissect *dis;
|
||||
t_ctrack *ctrack;
|
||||
bool incoming,cancel;
|
||||
bool incoming, cancel;
|
||||
bool valid;
|
||||
} t_lua_desync_context;
|
||||
|
||||
bool lua_instance_cutoff_check(const t_lua_desync_context *ctx, bool bIn);
|
||||
bool lua_instance_cutoff_check(lua_State *L, const t_lua_desync_context *ctx, bool bIn);
|
||||
|
||||
226
nfq2/nfqws.c
226
nfq2/nfqws.c
@@ -51,14 +51,15 @@
|
||||
#define MAX_CONFIG_FILE_SIZE 16384
|
||||
|
||||
struct params_s params;
|
||||
static bool bReload = false;
|
||||
#ifdef __CYGWIN__
|
||||
static volatile sig_atomic_t bReload = false;
|
||||
bool bQuit = false;
|
||||
#endif
|
||||
|
||||
static void onhup(int sig)
|
||||
{
|
||||
printf("HUP received ! Lists will be reloaded.\n");
|
||||
if (bQuit) return;
|
||||
|
||||
const char *msg = "HUP received ! Lists will be reloaded.\n";
|
||||
size_t wr = write(1, msg, strlen(msg));
|
||||
bReload = true;
|
||||
}
|
||||
static void ReloadCheck()
|
||||
@@ -83,12 +84,16 @@ static void ReloadCheck()
|
||||
|
||||
static void onusr1(int sig)
|
||||
{
|
||||
if (bQuit) return;
|
||||
|
||||
printf("\nCONNTRACK DUMP\n");
|
||||
ConntrackPoolDump(¶ms.conntrack);
|
||||
printf("\n");
|
||||
}
|
||||
static void onusr2(int sig)
|
||||
{
|
||||
if (bQuit) return;
|
||||
|
||||
printf("\nHOSTFAIL POOL DUMP\n");
|
||||
|
||||
struct desync_profile_list *dpl;
|
||||
@@ -101,12 +106,41 @@ static void onusr2(int sig)
|
||||
ipcachePrint(¶ms.ipcache);
|
||||
printf("\n");
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
static void pre_desync(void)
|
||||
{
|
||||
signal(SIGHUP, onhup);
|
||||
signal(SIGUSR1, onusr1);
|
||||
signal(SIGUSR2, onusr2);
|
||||
struct sigaction sa;
|
||||
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_sigaction = NULL;
|
||||
sa.sa_flags = 0;
|
||||
|
||||
sa.sa_handler = onhup;
|
||||
sigaction(SIGHUP, &sa, NULL);
|
||||
sa.sa_handler = onusr1;
|
||||
sigaction(SIGUSR1, &sa, NULL);
|
||||
sa.sa_handler = onusr2;
|
||||
sigaction(SIGUSR2, &sa, NULL);
|
||||
sa.sa_handler = onint;
|
||||
sigaction(SIGINT, &sa, NULL);
|
||||
sa.sa_handler = onterm;
|
||||
sigaction(SIGTERM, &sa, NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -155,13 +189,14 @@ static int nfq_cb(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, struct nfq_da
|
||||
uint8_t *data;
|
||||
uint32_t ifidx_out, ifidx_in;
|
||||
char ifout[IFNAMSIZ], ifin[IFNAMSIZ];
|
||||
uint8_t mod[RECONSTRUCT_MAX_SIZE];
|
||||
size_t modlen;
|
||||
uint32_t mark;
|
||||
uint8_t mod[RECONSTRUCT_MAX_SIZE] __attribute__((aligned(16)));
|
||||
|
||||
ph = nfq_get_msg_packet_hdr(nfa);
|
||||
id = ph ? ntohl(ph->packet_id) : 0;
|
||||
|
||||
uint32_t mark = nfq_get_nfmark(nfa);
|
||||
mark = nfq_get_nfmark(nfa);
|
||||
ilen = nfq_get_payload(nfa, &data);
|
||||
|
||||
ifidx_out = nfq_get_outdev(nfa);
|
||||
@@ -281,12 +316,12 @@ static void notify_ready(void)
|
||||
|
||||
static int nfq_main(void)
|
||||
{
|
||||
uint8_t buf[RECONSTRUCT_MAX_SIZE] __attribute__((aligned));
|
||||
struct nfq_handle *h = NULL;
|
||||
struct nfq_q_handle *qh = NULL;
|
||||
int res, fd, e;
|
||||
ssize_t rd;
|
||||
FILE *Fpid = NULL;
|
||||
uint8_t buf[RECONSTRUCT_MAX_SIZE] __attribute__((aligned(16)));
|
||||
|
||||
if (*params.pidfile && !(Fpid = fopen(params.pidfile, "w")))
|
||||
{
|
||||
@@ -347,6 +382,7 @@ static int nfq_main(void)
|
||||
{
|
||||
while ((rd = recv(fd, buf, sizeof(buf), 0)) >= 0)
|
||||
{
|
||||
if (bQuit) goto quit;
|
||||
ReloadCheck();
|
||||
lua_do_gc();
|
||||
#ifdef HAS_FILTER_SSID
|
||||
@@ -362,6 +398,11 @@ static int nfq_main(void)
|
||||
else
|
||||
DLOG("recv from nfq returned 0 !\n");
|
||||
}
|
||||
if (errno==EINTR)
|
||||
{
|
||||
if (bQuit) goto quit;
|
||||
continue;
|
||||
}
|
||||
e = errno;
|
||||
DLOG_ERR("recv: recv=%zd errno %d\n", rd, e);
|
||||
errno = e;
|
||||
@@ -369,6 +410,7 @@ static int nfq_main(void)
|
||||
// do not fail on ENOBUFS
|
||||
} while (e == ENOBUFS);
|
||||
|
||||
exok:
|
||||
res=0;
|
||||
ex:
|
||||
nfq_deinit(&h, &qh);
|
||||
@@ -376,18 +418,21 @@ ex:
|
||||
#ifdef HAS_FILTER_SSID
|
||||
wlan_info_deinit();
|
||||
#endif
|
||||
rawsend_cleanup();
|
||||
return res;
|
||||
err:
|
||||
if (Fpid) fclose(Fpid);
|
||||
res=1;
|
||||
goto ex;
|
||||
quit:
|
||||
DLOG_CONDUP("quit requested\n");
|
||||
goto exok;
|
||||
}
|
||||
|
||||
#elif defined(BSD)
|
||||
|
||||
static int dvt_main(void)
|
||||
{
|
||||
uint8_t buf[RECONSTRUCT_MAX_SIZE] __attribute__((aligned));
|
||||
struct sockaddr_storage sa_from;
|
||||
int fd[2] = { -1,-1 }; // 4,6
|
||||
int i, r, res = 1, fdct = 1, fdmax;
|
||||
@@ -396,6 +441,9 @@ static int dvt_main(void)
|
||||
ssize_t rd, wr;
|
||||
fd_set fdset;
|
||||
FILE *Fpid = NULL;
|
||||
struct sockaddr_in bp4;
|
||||
struct sockaddr_in6 bp6;
|
||||
uint8_t buf[RECONSTRUCT_MAX_SIZE] __attribute__((aligned));
|
||||
|
||||
if (*params.pidfile && !(Fpid = fopen(params.pidfile, "w")))
|
||||
{
|
||||
@@ -403,49 +451,42 @@ static int dvt_main(void)
|
||||
return 1;
|
||||
}
|
||||
|
||||
bp4.sin_family = AF_INET;
|
||||
bp4.sin_port = htons(params.port);
|
||||
bp4.sin_addr.s_addr = INADDR_ANY;
|
||||
DLOG_CONDUP("creating divert4 socket\n");
|
||||
fd[0] = socket_divert(AF_INET);
|
||||
if (fd[0] == -1) {
|
||||
DLOG_PERROR("socket (DIVERT4)");
|
||||
goto exiterr;
|
||||
}
|
||||
DLOG_CONDUP("binding divert4 socket\n");
|
||||
if (bind(fd[0], (struct sockaddr*)&bp4, sizeof(bp4)) < 0)
|
||||
{
|
||||
struct sockaddr_in bp4;
|
||||
bp4.sin_family = AF_INET;
|
||||
bp4.sin_port = htons(params.port);
|
||||
bp4.sin_addr.s_addr = INADDR_ANY;
|
||||
|
||||
DLOG_CONDUP("creating divert4 socket\n");
|
||||
fd[0] = socket_divert(AF_INET);
|
||||
if (fd[0] == -1) {
|
||||
DLOG_PERROR("socket (DIVERT4)");
|
||||
goto exiterr;
|
||||
}
|
||||
DLOG_CONDUP("binding divert4 socket\n");
|
||||
if (bind(fd[0], (struct sockaddr*)&bp4, sizeof(bp4)) < 0)
|
||||
{
|
||||
DLOG_PERROR("bind (DIVERT4)");
|
||||
goto exiterr;
|
||||
}
|
||||
DLOG_PERROR("bind (DIVERT4)");
|
||||
goto exiterr;
|
||||
}
|
||||
|
||||
|
||||
#ifdef __OpenBSD__
|
||||
{
|
||||
// in OpenBSD must use separate divert sockets for ipv4 and ipv6
|
||||
struct sockaddr_in6 bp6;
|
||||
memset(&bp6, 0, sizeof(bp6));
|
||||
bp6.sin6_family = AF_INET6;
|
||||
bp6.sin6_port = htons(params.port);
|
||||
// in OpenBSD must use separate divert sockets for ipv4 and ipv6
|
||||
memset(&bp6, 0, sizeof(bp6));
|
||||
bp6.sin6_family = AF_INET6;
|
||||
bp6.sin6_port = htons(params.port);
|
||||
|
||||
DLOG_CONDUP("creating divert6 socket\n");
|
||||
fd[1] = socket_divert(AF_INET6);
|
||||
if (fd[1] == -1) {
|
||||
DLOG_PERROR("socket (DIVERT6)");
|
||||
goto exiterr;
|
||||
}
|
||||
DLOG_CONDUP("binding divert6 socket\n");
|
||||
if (bind(fd[1], (struct sockaddr*)&bp6, sizeof(bp6)) < 0)
|
||||
{
|
||||
DLOG_PERROR("bind (DIVERT6)");
|
||||
goto exiterr;
|
||||
}
|
||||
fdct++;
|
||||
DLOG_CONDUP("creating divert6 socket\n");
|
||||
fd[1] = socket_divert(AF_INET6);
|
||||
if (fd[1] == -1) {
|
||||
DLOG_PERROR("socket (DIVERT6)");
|
||||
goto exiterr;
|
||||
}
|
||||
DLOG_CONDUP("binding divert6 socket\n");
|
||||
if (bind(fd[1], (struct sockaddr*)&bp6, sizeof(bp6)) < 0)
|
||||
{
|
||||
DLOG_PERROR("bind (DIVERT6)");
|
||||
goto exiterr;
|
||||
}
|
||||
fdct++;
|
||||
#endif
|
||||
fdmax = (fd[0] > fd[1] ? fd[0] : fd[1]) + 1;
|
||||
|
||||
@@ -485,13 +526,14 @@ static int dvt_main(void)
|
||||
FD_ZERO(&fdset);
|
||||
for (i = 0; i < fdct; i++) FD_SET(fd[i], &fdset);
|
||||
r = select(fdmax, &fdset, NULL, NULL, NULL);
|
||||
if (bQuit)
|
||||
{
|
||||
DLOG_CONDUP("quit requested\n");
|
||||
goto exitok;
|
||||
}
|
||||
if (r == -1)
|
||||
{
|
||||
if (errno == EINTR)
|
||||
{
|
||||
// a signal received
|
||||
continue;
|
||||
}
|
||||
if (errno == EINTR) continue;
|
||||
DLOG_PERROR("select");
|
||||
goto exiterr;
|
||||
}
|
||||
@@ -569,12 +611,14 @@ static int dvt_main(void)
|
||||
}
|
||||
}
|
||||
|
||||
exitok:
|
||||
res = 0;
|
||||
exiterr:
|
||||
if (Fpid) fclose(Fpid);
|
||||
if (fd[0] != -1) close(fd[0]);
|
||||
if (fd[1] != -1) close(fd[1]);
|
||||
lua_shutdown();
|
||||
rawsend_cleanup();
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -587,11 +631,11 @@ static int win_main()
|
||||
unsigned int id;
|
||||
uint8_t verdict;
|
||||
bool bOutbound;
|
||||
uint8_t packet[RECONSTRUCT_MAX_SIZE];
|
||||
uint32_t mark;
|
||||
WINDIVERT_ADDRESS wa;
|
||||
char ifname[IFNAMSIZ];
|
||||
int res=0;
|
||||
uint8_t packet[RECONSTRUCT_MAX_SIZE] __attribute__((aligned(16)));
|
||||
|
||||
if (params.daemon) daemonize();
|
||||
|
||||
@@ -618,7 +662,7 @@ static int win_main()
|
||||
{
|
||||
if (bQuit)
|
||||
{
|
||||
DLOG("QUIT requested\n");
|
||||
DLOG("quit requested\n");
|
||||
goto ex;
|
||||
}
|
||||
usleep(500000);
|
||||
@@ -659,12 +703,11 @@ static int win_main()
|
||||
else if (errno == ENODEV)
|
||||
{
|
||||
DLOG_CONDUP("logical network disappeared. deinitializing windivert.\n");
|
||||
rawsend_cleanup();
|
||||
break;
|
||||
}
|
||||
else if (errno == EINTR)
|
||||
{
|
||||
DLOG("QUIT requested\n");
|
||||
DLOG("quit requested\n");
|
||||
goto ex;
|
||||
}
|
||||
DLOG_ERR("windivert: recv failed. errno %d\n", errno);
|
||||
@@ -683,11 +726,6 @@ static int win_main()
|
||||
DLOG("windivert: passing impostor packet\n");
|
||||
verdict = VERDICT_PASS;
|
||||
}
|
||||
else if (wa.Loopback)
|
||||
{
|
||||
DLOG("windivert: passing loopback packet\n");
|
||||
verdict = VERDICT_PASS;
|
||||
}
|
||||
else
|
||||
{
|
||||
mark = 0;
|
||||
@@ -715,6 +753,7 @@ static int win_main()
|
||||
ex:
|
||||
win_dark_deinit();
|
||||
lua_shutdown();
|
||||
rawsend_cleanup();
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -1130,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, ',');
|
||||
@@ -1257,7 +1296,7 @@ static bool wf_make_pf(char *opt, const char *l4, const char *portname, char *bu
|
||||
// HTTP/1.? 30(2|7)
|
||||
#define DIVERT_HTTP_REDIRECT "tcp.PayloadLength>=12 and tcp.Payload32[0]==0x48545450 and tcp.Payload16[2]==0x2F31 and tcp.Payload[6]==0x2E and tcp.Payload16[4]==0x2033 and tcp.Payload[10]==0x30 and (tcp.Payload[11]==0x32 or tcp.Payload[11]==0x37)"
|
||||
|
||||
#define DIVERT_PROLOG "!impostor and !loopback"
|
||||
#define DIVERT_PROLOG "!impostor"
|
||||
|
||||
static bool wf_make_filter(
|
||||
char *wf, size_t len,
|
||||
@@ -1268,12 +1307,14 @@ static bool wf_make_filter(
|
||||
const char *pf_tcp_src_in, const char *pf_tcp_dst_in,
|
||||
const char *pf_udp_src_in, const char *pf_udp_dst_out,
|
||||
const struct str_list_head *wf_raw_part,
|
||||
bool bFilterOutLAN)
|
||||
bool bFilterOutLAN, bool bFilterOutLoopback)
|
||||
{
|
||||
struct str_list *wfpart;
|
||||
bool bHaveTCP = *pf_tcp_src_in || *pf_tcp_dst_out;
|
||||
|
||||
snprintf(wf, len, "%s", DIVERT_PROLOG);
|
||||
if (bFilterOutLoopback)
|
||||
snprintf(wf + strlen(wf), len - strlen(wf), " and !loopback");
|
||||
if (IfIdx)
|
||||
snprintf(wf + strlen(wf), len - strlen(wf), " and ifIdx=%u and subIfIdx=%u", IfIdx, SubIfIdx);
|
||||
if (ipv4 ^ ipv6)
|
||||
@@ -1340,7 +1381,7 @@ static void exithelp(void)
|
||||
*all_payloads=0;
|
||||
for (t_l7payload pl=0 ; pl<L7P_LAST; pl++)
|
||||
{
|
||||
if (pl) strncat(all_payloads, " ", sizeof(all_payloads)-1-1);
|
||||
if (pl) strncat(all_payloads, " ", sizeof(all_payloads)-strlen(all_payloads)-1);
|
||||
strncat(all_payloads, l7payload_str(pl), sizeof(all_payloads)-strlen(all_payloads)-1);
|
||||
}
|
||||
*all_protos=0;
|
||||
@@ -1382,10 +1423,11 @@ static void exithelp(void)
|
||||
#endif
|
||||
" --ctrack-timeouts=S:E:F[:U]\t\t\t\t; internal conntrack timeouts for TCP SYN, ESTABLISHED, FIN stages, UDP timeout. default %u:%u:%u:%u\n"
|
||||
" --ctrack-disable=[0|1]\t\t\t\t\t; 1 or no argument disables conntrack\n"
|
||||
" --payload-disable=[type[,type]]\t\t\t; do not discover these payload types. for available payload types see '--payload'. disable all if no argument.\n"
|
||||
" --server=[0|1]\t\t\t\t\t\t; change multiple aspects of src/dst ip/port handling for incoming connections\n"
|
||||
" --ipcache-lifetime=<int>\t\t\t\t; time in seconds to keep cached hop count and domain name (default %u). 0 = no expiration\n"
|
||||
" --ipcache-hostname=[0|1]\t\t\t\t; 1 or no argument enables ip->hostname caching\n"
|
||||
" --reasm-disable=[proto[,proto]]\t\t\t; disable reasm for these L7 payloads : tls_client_hello quic_initial . if no argument - disable all reasm.\n"
|
||||
" --reasm-disable=[type[,type]]\t\t\t\t; disable reasm for these L7 payloads : tls_client_hello quic_initial . if no argument - disable all reasm.\n"
|
||||
#ifdef __CYGWIN__
|
||||
"\nWINDIVERT FILTER:\n"
|
||||
" --wf-iface=<int>[.<int>]\t\t\t\t; numeric network interface and subinterface indexes\n"
|
||||
@@ -1397,7 +1439,9 @@ static void exithelp(void)
|
||||
" --wf-tcp-empty=[0|1]\t\t\t\t\t; enable processing of empty tcp packets without flags SYN,RST,FIN (default : 0)\n"
|
||||
" --wf-raw-part=<filter>|@<filename>\t\t\t; partial raw windivert filter string or filename\n"
|
||||
" --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"
|
||||
@@ -1495,10 +1539,6 @@ void config_from_file(const char *filename)
|
||||
}
|
||||
#endif
|
||||
|
||||
static void check_dp(const struct desync_profile *dp)
|
||||
{
|
||||
}
|
||||
|
||||
static void ApplyDefaultBlobs(struct blob_collection_head *blobs)
|
||||
{
|
||||
load_const_blob_to_collection("fake_default_tls",fake_tls_clienthello_default,sizeof(fake_tls_clienthello_default),blobs,BLOB_EXTRA_BYTES);
|
||||
@@ -1530,6 +1570,7 @@ enum opt_indices {
|
||||
#endif
|
||||
IDX_CTRACK_TIMEOUTS,
|
||||
IDX_CTRACK_DISABLE,
|
||||
IDX_PAYLOAD_DISABLE,
|
||||
IDX_SERVER,
|
||||
IDX_IPCACHE_LIFETIME,
|
||||
IDX_IPCACHE_HOSTNAME,
|
||||
@@ -1594,6 +1635,8 @@ enum opt_indices {
|
||||
IDX_WF_RAW,
|
||||
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,
|
||||
@@ -1622,6 +1665,7 @@ static const struct option long_options[] = {
|
||||
#endif
|
||||
[IDX_CTRACK_TIMEOUTS] = {"ctrack-timeouts", required_argument, 0, 0},
|
||||
[IDX_CTRACK_DISABLE] = {"ctrack-disable", optional_argument, 0, 0},
|
||||
[IDX_PAYLOAD_DISABLE] = {"payload-disable", optional_argument, 0, 0},
|
||||
[IDX_SERVER] = {"server", optional_argument, 0, 0},
|
||||
[IDX_IPCACHE_LIFETIME] = {"ipcache-lifetime", required_argument, 0, 0},
|
||||
[IDX_IPCACHE_HOSTNAME] = {"ipcache-hostname", optional_argument, 0, 0},
|
||||
@@ -1683,7 +1727,9 @@ static const struct option long_options[] = {
|
||||
[IDX_WF_RAW] = {"wf-raw", required_argument, 0, 0},
|
||||
[IDX_WF_RAW_PART] = {"wf-raw-part", required_argument, 0, 0},
|
||||
[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},
|
||||
@@ -1719,14 +1765,14 @@ 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;
|
||||
struct packet_range range_in = PACKET_RANGE_NEVER, range_out = PACKET_RANGE_ALWAYS;
|
||||
#ifdef __CYGWIN__
|
||||
char wf_save_file[256]="";
|
||||
bool wf_ipv4 = true, wf_ipv6 = true, wf_filter_lan = true, wf_tcp_empty = false;
|
||||
bool wf_ipv4 = true, wf_ipv6 = true, wf_filter_lan = true, wf_filter_loopback = true, wf_tcp_empty = false;
|
||||
unsigned int IfIdx = 0, SubIfIdx = 0;
|
||||
unsigned int hash_wf_tcp_in = 0, hash_wf_udp_in = 0, hash_wf_tcp_out = 0, hash_wf_udp_out = 0, hash_wf_raw = 0, hash_wf_raw_part = 0, hash_ssid_filter = 0, hash_nlm_filter = 0;
|
||||
#endif
|
||||
@@ -1735,7 +1781,6 @@ int main(int argc, char **argv)
|
||||
|
||||
srandom(time(NULL));
|
||||
aes_init_keygen_tables(); // required for aes
|
||||
mask_from_preflen6_prepare();
|
||||
set_env_exedir(argv[0]);
|
||||
set_console_io_buffering();
|
||||
#ifdef __CYGWIN__
|
||||
@@ -1951,6 +1996,18 @@ int main(int argc, char **argv)
|
||||
case IDX_IPCACHE_HOSTNAME:
|
||||
params.cache_hostname = !optarg || atoi(optarg);
|
||||
break;
|
||||
case IDX_PAYLOAD_DISABLE:
|
||||
if (optarg)
|
||||
{
|
||||
if (!parse_l7p_list(optarg, ¶ms.payload_disable))
|
||||
{
|
||||
DLOG_ERR("Invalid payload filter : %s\n", optarg);
|
||||
exit_clean(1);
|
||||
}
|
||||
}
|
||||
else
|
||||
params.payload_disable = L7P_ALL;
|
||||
break;
|
||||
case IDX_REASM_DISABLE:
|
||||
if (optarg)
|
||||
{
|
||||
@@ -1961,7 +2018,7 @@ int main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
else
|
||||
params.reasm_payload_disable = 0xFFFFFFFFFFFFFFFF;
|
||||
params.reasm_payload_disable = L7P_ALL;
|
||||
break;
|
||||
#if defined(__linux__)
|
||||
case IDX_FWMARK:
|
||||
@@ -2136,7 +2193,6 @@ int main(int argc, char **argv)
|
||||
}
|
||||
else
|
||||
{
|
||||
check_dp(dp);
|
||||
if (bTemplate)
|
||||
{
|
||||
if (dp->name && dp_list_search_name(¶ms.desync_templates, dp->name))
|
||||
@@ -2228,7 +2284,7 @@ int main(int argc, char **argv)
|
||||
DLOG_ERR("Invalid port filter : %s\n", optarg);
|
||||
exit_clean(1);
|
||||
}
|
||||
// deny tcp if not set
|
||||
// deny udp if not set
|
||||
if (!port_filters_deny_if_empty(&dp->pf_udp))
|
||||
exit_clean(1);
|
||||
break;
|
||||
@@ -2438,10 +2494,16 @@ int main(int argc, char **argv)
|
||||
case IDX_WF_FILTER_LAN:
|
||||
wf_filter_lan = !!atoi(optarg);
|
||||
break;
|
||||
case IDX_WF_FILTER_LOOPBACK:
|
||||
wf_filter_loopback = !!atoi(optarg);
|
||||
break;
|
||||
case IDX_WF_SAVE:
|
||||
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, ¶ms.ssid_filter))
|
||||
@@ -2477,7 +2539,6 @@ int main(int argc, char **argv)
|
||||
}
|
||||
else
|
||||
{
|
||||
check_dp(dp);
|
||||
if (bTemplate)
|
||||
{
|
||||
if (dp->name && dp_list_search_name(¶ms.desync_templates, dp->name))
|
||||
@@ -2607,13 +2668,13 @@ int main(int argc, char **argv)
|
||||
params.wf_pf_tcp_dst_out, params.wf_pf_tcp_src_out,
|
||||
params.wf_pf_tcp_dst_in, params.wf_pf_tcp_src_in,
|
||||
params.wf_pf_udp_dst_in, params.wf_pf_udp_src_out,
|
||||
¶ms.wf_raw_part, wf_filter_lan) :
|
||||
¶ms.wf_raw_part, wf_filter_lan, wf_filter_loopback) :
|
||||
wf_make_filter(params.windivert_filter, WINDIVERT_MAX, IfIdx, SubIfIdx, wf_ipv4, wf_ipv6,
|
||||
wf_tcp_empty,
|
||||
params.wf_pf_tcp_src_out, params.wf_pf_tcp_dst_out,
|
||||
params.wf_pf_tcp_src_in, params.wf_pf_tcp_dst_in,
|
||||
params.wf_pf_udp_src_in, params.wf_pf_udp_dst_out,
|
||||
¶ms.wf_raw_part, wf_filter_lan);
|
||||
¶ms.wf_raw_part, wf_filter_lan, wf_filter_loopback);
|
||||
cleanup_windivert_portfilters(¶ms);
|
||||
if (!b)
|
||||
{
|
||||
@@ -2638,10 +2699,12 @@ 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", hash_wf_tcp_in, hash_wf_udp_in, hash_wf_tcp_out, hash_wf_udp_out, hash_wf_raw, hash_wf_raw_part, hash_ssid_filter, hash_nlm_filter, IfIdx, SubIfIdx, wf_ipv4, wf_ipv6);
|
||||
snprintf(mutex_name, sizeof(mutex_name), "Global\\winws2_arg_%u_%u_%u_%u_%u_%u_%u_%u_%u_%u_%u_%u",
|
||||
hash_wf_tcp_in, hash_wf_udp_in, hash_wf_tcp_out, hash_wf_udp_out, hash_wf_raw, hash_wf_raw_part, hash_ssid_filter, hash_nlm_filter, IfIdx, SubIfIdx, wf_ipv4, wf_ipv6);
|
||||
|
||||
hMutexArg = CreateMutexA(NULL, TRUE, mutex_name);
|
||||
if (hMutexArg && GetLastError() == ERROR_ALREADY_EXISTS)
|
||||
@@ -2692,7 +2755,6 @@ int main(int argc, char **argv)
|
||||
#error unsupported OS
|
||||
#endif
|
||||
ex:
|
||||
rawsend_cleanup();
|
||||
cleanup_params(¶ms);
|
||||
#ifdef __CYGWIN__
|
||||
if (hMutexArg)
|
||||
|
||||
@@ -496,6 +496,9 @@ void cleanup_params(struct params_s *params)
|
||||
hostlist_files_destroy(¶ms->hostlists);
|
||||
ipset_files_destroy(¶ms->ipsets);
|
||||
ipcacheDestroy(¶ms->ipcache);
|
||||
blob_collection_destroy(¶ms->blobs);
|
||||
strlist_destroy(¶ms->lua_init_scripts);
|
||||
|
||||
#ifdef __CYGWIN__
|
||||
strlist_destroy(¶ms->ssid_filter);
|
||||
strlist_destroy(¶ms->nlm_filter);
|
||||
@@ -529,6 +532,8 @@ void init_params(struct params_s *params)
|
||||
LIST_INIT(¶ms->blobs);
|
||||
LIST_INIT(¶ms->lua_init_scripts);
|
||||
|
||||
params->reasm_payload_disable = params->payload_disable = 1<<L7P_NONE;
|
||||
|
||||
#ifdef __CYGWIN__
|
||||
LIST_INIT(¶ms->ssid_filter);
|
||||
LIST_INIT(¶ms->nlm_filter);
|
||||
|
||||
@@ -21,8 +21,6 @@
|
||||
#include <wordexp.h>
|
||||
#endif
|
||||
|
||||
#define TLS_PARTIALS_ENABLE true
|
||||
|
||||
#define RAW_SNDBUF (64*1024) // in bytes
|
||||
|
||||
#define Q_MAXLEN 1024 // in packets
|
||||
@@ -45,7 +43,7 @@
|
||||
// this MSS is used for ipv6 in windows and linux
|
||||
#define DEFAULT_MSS 1220
|
||||
|
||||
#define RECONSTRUCT_MAX_SIZE 16384
|
||||
#define RECONSTRUCT_MAX_SIZE 65536
|
||||
|
||||
#define LUA_GC_INTERVAL 60
|
||||
|
||||
@@ -87,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;
|
||||
};
|
||||
@@ -176,12 +175,14 @@ struct params_s
|
||||
unsigned int ipcache_lifetime;
|
||||
ip_cache ipcache;
|
||||
uint64_t reasm_payload_disable;
|
||||
uint64_t payload_disable;
|
||||
|
||||
struct str_list_head lua_init_scripts;
|
||||
bool writeable_dir_enable;
|
||||
char writeable_dir[PATH_MAX];
|
||||
|
||||
int lua_gc;
|
||||
int ref_desync_ctx; // desync ctx userdata registry ref
|
||||
lua_State *L;
|
||||
};
|
||||
|
||||
|
||||
14
nfq2/pools.c
14
nfq2/pools.c
@@ -98,6 +98,7 @@ hostfail_pool *HostFailPoolFind(hostfail_pool *p,const char *s)
|
||||
}
|
||||
void HostFailPoolDel(hostfail_pool **p, hostfail_pool *elem)
|
||||
{
|
||||
free(elem->str);
|
||||
HASH_DEL(*p, elem);
|
||||
free(elem);
|
||||
}
|
||||
@@ -108,22 +109,17 @@ void HostFailPoolPurge(hostfail_pool **pp)
|
||||
HASH_ITER(hh, *pp, elem, tmp)
|
||||
{
|
||||
if (now >= elem->expire)
|
||||
{
|
||||
free(elem->str);
|
||||
HASH_DEL(*pp, elem);
|
||||
free(elem);
|
||||
}
|
||||
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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
|
||||
@@ -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:
|
||||
@@ -675,7 +690,7 @@ ssize_t TLSPos(t_marker posmarker, int16_t pos, const uint8_t *data, size_t sz)
|
||||
case PM_HOST_MIDSLD:
|
||||
case PM_HOST_ENDSLD:
|
||||
case PM_SNI_EXT:
|
||||
if (TLSFindExt(data,sz,0,&ext,&elen,TLS_PARTIALS_ENABLE))
|
||||
if (TLSFindExt(data,sz,0,&ext,&elen,true))
|
||||
{
|
||||
if (posmarker==PM_SNI_EXT)
|
||||
{
|
||||
@@ -985,28 +1000,26 @@ 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)
|
||||
{
|
||||
/* IETF Draft versions */
|
||||
if ((version >> 8) == 0xff0000) {
|
||||
if ((version >> 8) == 0xff0000)
|
||||
return (uint8_t)version;
|
||||
}
|
||||
/* Facebook mvfst, based on draft -22. */
|
||||
if (version == 0xfaceb001) {
|
||||
if (version == 0xfaceb001)
|
||||
return 22;
|
||||
}
|
||||
/* Facebook mvfst, based on draft -27. */
|
||||
if (version == 0xfaceb002 || version == 0xfaceb00e) {
|
||||
if (version == 0xfaceb002 || version == 0xfaceb00e)
|
||||
return 27;
|
||||
}
|
||||
/* GQUIC Q050, T050 and T051: they are not really based on any drafts,
|
||||
* but we must return a sensible value */
|
||||
if (version == 0x51303530 ||
|
||||
version == 0x54303530 ||
|
||||
version == 0x54303531) {
|
||||
if (version == 0x51303530 || version == 0x54303530 || version == 0x54303531)
|
||||
return 27;
|
||||
}
|
||||
/* https://tools.ietf.org/html/draft-ietf-quic-transport-32#section-15
|
||||
"Versions that follow the pattern 0x?a?a?a?a are reserved for use in
|
||||
forcing version negotiation to be exercised"
|
||||
@@ -1014,19 +1027,17 @@ uint8_t QUICDraftVersion(uint32_t version)
|
||||
used to select a proper salt (which depends on the version itself), but
|
||||
we don't have a real version here! Let's hope that we need to handle
|
||||
only latest drafts... */
|
||||
if ((version & 0x0F0F0F0F) == 0x0a0a0a0a) {
|
||||
if ((version & 0x0F0F0F0F) == 0x0a0a0a0a)
|
||||
return 29;
|
||||
}
|
||||
/* QUIC (final?) constants for v1 are defined in draft-33, but draft-34 is the
|
||||
final draft version */
|
||||
if (version == 0x00000001) {
|
||||
if (version == 0x00000001)
|
||||
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) {
|
||||
if (is_quic_v2(version))
|
||||
return 100;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1034,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 == 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)
|
||||
{
|
||||
@@ -1148,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)
|
||||
{
|
||||
@@ -1185,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;
|
||||
@@ -1386,24 +1394,24 @@ bool IsDNSResponse(const uint8_t *data, size_t len)
|
||||
}
|
||||
bool IsWireguardHandshakeInitiation(const uint8_t *data, size_t len)
|
||||
{
|
||||
return len==148 && data[0]==1;
|
||||
return len==148 && pntoh32(data)==0x01000000;
|
||||
}
|
||||
bool IsWireguardHandshakeResponse(const uint8_t *data, size_t len)
|
||||
{
|
||||
return len==92 && data[0]==2;
|
||||
return len==92 && pntoh32(data)==0x02000000;
|
||||
}
|
||||
bool IsWireguardHandshakeCookie(const uint8_t *data, size_t len)
|
||||
{
|
||||
return len==64 && data[0]==3;
|
||||
return len==64 && pntoh32(data)==0x03000000;
|
||||
}
|
||||
bool IsWireguardData(const uint8_t *data, size_t len)
|
||||
{
|
||||
// 16 bytes wg header + min 20 bytes for ipv4 encrypted header + 16 byte auth tag
|
||||
return len>=52 && data[0]==4;
|
||||
return len>=52 && pntoh32(data)==0x04000000;
|
||||
}
|
||||
bool IsWireguardKeepalive(const uint8_t *data, size_t len)
|
||||
{
|
||||
return len==32 && data[0]==4;
|
||||
return len==32 && pntoh32(data)==0x04000000;
|
||||
}
|
||||
bool IsDht(const uint8_t *data, size_t len)
|
||||
{
|
||||
@@ -1437,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);
|
||||
|
||||
@@ -20,7 +20,7 @@ typedef enum {
|
||||
L7_XMPP,
|
||||
L7_DNS,
|
||||
L7_MTPROTO,
|
||||
L7_LAST, L7_INVALID=L7_LAST
|
||||
L7_LAST, L7_INVALID=L7_LAST, L7_NONE=L7_LAST
|
||||
} t_l7proto;
|
||||
const char *l7proto_str(t_l7proto l7);
|
||||
t_l7proto l7proto_from_name(const char *name);
|
||||
@@ -53,7 +53,7 @@ typedef enum {
|
||||
L7P_DNS_QUERY,
|
||||
L7P_DNS_RESPONSE,
|
||||
L7P_MTPROTO_INITIAL,
|
||||
L7P_LAST, L7P_INVALID=L7P_LAST
|
||||
L7P_LAST, L7P_INVALID=L7P_LAST, L7P_NONE=L7P_LAST
|
||||
} t_l7payload;
|
||||
t_l7payload l7payload_from_name(const char *name);
|
||||
const char *l7payload_str(t_l7payload l7);
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user