mirror of
https://github.com/bol-van/zapret2.git
synced 2026-03-16 14:58:17 +00:00
Compare commits
440 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c72c48432e | ||
|
|
c5894b0708 | ||
|
|
79b018dd74 | ||
|
|
56cce72dac | ||
|
|
a8b4007386 | ||
|
|
2977c20044 | ||
|
|
d432e770a6 | ||
|
|
0574d609de | ||
|
|
043b85dfb4 | ||
|
|
22b7861603 | ||
|
|
8b24076c20 | ||
|
|
3abc22baf5 | ||
|
|
739c24cdf3 | ||
|
|
5c97563698 | ||
|
|
2ddfe55d9a | ||
|
|
a781f3d1ce | ||
|
|
080655c4c2 | ||
|
|
3434739144 | ||
|
|
740cbfbc34 | ||
|
|
37f0f4589f | ||
|
|
9d7fed4c67 | ||
|
|
2533a3debc | ||
|
|
6e90adad5b | ||
|
|
aa359128bb | ||
|
|
fed07a0249 | ||
|
|
055ae067f9 | ||
|
|
2490ef6951 | ||
|
|
a531da39fd | ||
|
|
b920964ab3 | ||
|
|
7d9f5a4b83 | ||
|
|
b157613b1a | ||
|
|
4081878b36 | ||
|
|
b1fbf5c81a | ||
|
|
04d940e619 | ||
|
|
bd9aec8374 | ||
|
|
e9bffca658 | ||
|
|
001942fe74 | ||
|
|
f5d1108cce | ||
|
|
27d387c76d | ||
|
|
d5306fb97a | ||
|
|
5f87b7670a | ||
|
|
2a2a3e4f73 | ||
|
|
1f99fb49af | ||
|
|
b99b59bbdb | ||
|
|
9128601820 | ||
|
|
584d3b5925 | ||
|
|
eff7e6488a | ||
|
|
27c49bcfe4 | ||
|
|
48fbd39ada | ||
|
|
6eb4970c9b | ||
|
|
ba5cff29f1 | ||
|
|
bd155daa91 | ||
|
|
5de6595ccd | ||
|
|
4253b7b408 | ||
|
|
389a331d83 | ||
|
|
540094baac | ||
|
|
a3c4724542 | ||
|
|
79f33ef75a | ||
|
|
d4c1126961 | ||
|
|
9e378f629d | ||
|
|
227c2e76e3 | ||
|
|
2f74d21923 | ||
|
|
4376aa0cdf | ||
|
|
331e0dcbab | ||
|
|
f1af8cbde9 | ||
|
|
b865591f2a | ||
|
|
384d219597 | ||
|
|
7880782a95 | ||
|
|
d914472542 | ||
|
|
6a32bc46e2 | ||
|
|
8cf0d68d58 | ||
|
|
04134d78ee | ||
|
|
47f6410946 | ||
|
|
a29e159895 | ||
|
|
e5fd657a8a | ||
|
|
faea98da74 | ||
|
|
c8722d1ed9 | ||
|
|
77e405e24d | ||
|
|
7c5dfad8e2 | ||
|
|
b25f16126b | ||
|
|
4970c01344 | ||
|
|
4e412ab2d6 | ||
|
|
a2374f0fcf | ||
|
|
65337446d4 | ||
|
|
be88140bb0 | ||
|
|
27fff3f5c3 | ||
|
|
8ba5739ef2 | ||
|
|
a788975268 | ||
|
|
e441711b05 | ||
|
|
314627d851 | ||
|
|
4560ef6d5b | ||
|
|
431e794356 | ||
|
|
f50bd701f7 | ||
|
|
15f29169d5 | ||
|
|
a106519f1e | ||
|
|
5b016f62e4 | ||
|
|
68c15864a4 | ||
|
|
752cafad7c | ||
|
|
12853b8052 | ||
|
|
1d869650b1 | ||
|
|
12a9bf8b19 | ||
|
|
4ade6f7e82 | ||
|
|
6adb789314 | ||
|
|
78b3baa03f | ||
|
|
90fa71d6d6 | ||
|
|
e33e1a9b89 | ||
|
|
e7f0e79f78 | ||
|
|
8b11d6c279 | ||
|
|
30044e8c61 | ||
|
|
1cffa0f5ec | ||
|
|
8bee9efcf0 | ||
|
|
848221b096 | ||
|
|
fb3bdd9b70 | ||
|
|
ca6d145312 | ||
|
|
01d78e8dc4 | ||
|
|
db050b9ba1 | ||
|
|
b65da8d8db | ||
|
|
1359986d29 | ||
|
|
36ee42bc8c | ||
|
|
a8373a8400 | ||
|
|
33b1e81041 | ||
|
|
577d9e6aba | ||
|
|
3caf1ce10a | ||
|
|
8e67260a23 | ||
|
|
378b1c727d | ||
|
|
14bd4832a4 | ||
|
|
6d8b405bf0 | ||
|
|
00b6d70efc | ||
|
|
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 | ||
|
|
a2dedc45c0 | ||
|
|
f0d3a63df9 | ||
|
|
c6ca25a656 | ||
|
|
71b87f749d | ||
|
|
3d756c9702 | ||
|
|
13864fe5c5 | ||
|
|
cc2601af2f | ||
|
|
07319a329e | ||
|
|
52f5c2697b | ||
|
|
6b0dde5643 | ||
|
|
e42265e071 | ||
|
|
939f7a9558 | ||
|
|
b62ebd8fcb | ||
|
|
521fafc05d | ||
|
|
419d6769bd | ||
|
|
dde3f59d32 | ||
|
|
78e1fb85ac | ||
|
|
f73790b871 | ||
|
|
33f3378094 | ||
|
|
af7a6f6c10 | ||
|
|
9cc348e5bd | ||
|
|
8628c34941 | ||
|
|
eec9f3e87c | ||
|
|
e4a8f51775 | ||
|
|
fb962df188 | ||
|
|
173dcd47d1 | ||
|
|
3439dc4f21 | ||
|
|
6e04162a20 | ||
|
|
883a3d6233 | ||
|
|
e8cde6b0a2 | ||
|
|
43872a21a6 | ||
|
|
ff2c3e81f9 | ||
|
|
bcbfb45c53 | ||
|
|
fa6a75f139 | ||
|
|
e96c06598c | ||
|
|
58320aecbe | ||
|
|
ba526b75e1 | ||
|
|
b9321619fc | ||
|
|
d1a489a196 | ||
|
|
cf91697dfb | ||
|
|
401886bf32 | ||
|
|
8baf81a840 | ||
|
|
417cd8335a | ||
|
|
5a9d40ad3f | ||
|
|
af0be0fd94 | ||
|
|
68e0c367c9 | ||
|
|
0969d22391 | ||
|
|
94daca8ced | ||
|
|
1982984a86 | ||
|
|
6a520f508a | ||
|
|
70d0dd5d79 | ||
|
|
4ca0f6b574 | ||
|
|
76e85d8969 | ||
|
|
f458a76880 | ||
|
|
6077d363ec | ||
|
|
c70f114c3a | ||
|
|
2c037dca73 | ||
|
|
fe2fc0337f | ||
|
|
b3a86d0d8a | ||
|
|
5618be9a71 | ||
|
|
715ae4bf1c | ||
|
|
f44b6bf769 | ||
|
|
e75857c448 | ||
|
|
bc008e2cf3 | ||
|
|
752226208b | ||
|
|
9e2222549e | ||
|
|
b0686b16f7 | ||
|
|
d5b2c41daa |
2
.gitattributes
vendored
2
.gitattributes
vendored
@@ -1,5 +1,7 @@
|
||||
* text=auto eol=lf
|
||||
*.cmd eol=crlf
|
||||
*.bat eol=crlf
|
||||
*.manifest eol=crlf
|
||||
*.rc eol=crlf
|
||||
init.d/windivert.filter.examples/** eol=crlf
|
||||
files/** binary
|
||||
|
||||
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.
|
||||
|
||||
16
.github/workflows/build.yml
vendored
16
.github/workflows/build.yml
vendored
@@ -26,8 +26,6 @@ jobs:
|
||||
tool: aarch64-unknown-linux-musl
|
||||
- arch: arm
|
||||
tool: arm-unknown-linux-musleabi
|
||||
- arch: arm-old
|
||||
tool: arm-unknown-linux-musleabi
|
||||
# - arch: armhf
|
||||
# tool: arm-unknown-linux-musleabihf
|
||||
# - arch: armv7
|
||||
@@ -77,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
|
||||
@@ -95,8 +93,8 @@ jobs:
|
||||
CFLAGS: ${{ matrix.env.CFLAGS != '' && matrix.env.CFLAGS || null }}
|
||||
LDFLAGS: ${{ matrix.env.LDFLAGS != '' && matrix.env.LDFLAGS || null }}
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
LUA_VER: 5.4
|
||||
LUA_RELEASE: 5.4.8
|
||||
LUA_VER: 5.5
|
||||
LUA_RELEASE: 5.5.0
|
||||
LUAJIT_VER: 2.1
|
||||
LUAJIT_RELEASE: 2.1-20250826
|
||||
LUAJIT_LUAVER: 5.1
|
||||
@@ -110,7 +108,7 @@ jobs:
|
||||
export PKG_CONFIG_PATH=$DEPS_DIR/lib/pkgconfig
|
||||
export STAGING_DIR=$RUNNER_TEMP
|
||||
|
||||
if [[ "$ARCH" == lexra ]] || [[ "$ARCH" == ppc ]] || [[ "$ARCH" == x86 ]] || [[ "$ARCH" == arm-old ]]; then
|
||||
if [[ "$ARCH" == lexra ]] || [[ "$ARCH" == ppc ]] || [[ "$ARCH" == x86 ]] ; then
|
||||
# use classic lua
|
||||
wget -qO- https://www.lua.org/ftp/lua-${LUA_RELEASE}.tar.gz | tar -xz
|
||||
(
|
||||
@@ -393,7 +391,7 @@ jobs:
|
||||
with:
|
||||
platform: ${{ matrix.arch }}
|
||||
site: ${{ matrix.arch == 'x86_64' && 'http://ctm.crouchingtigerhiddenfruitbat.org/pub/cygwin/circa/64bit/2024/01/30/231215' || null }}
|
||||
check-sig: ${{ matrix.arch == 'x86_64' && 'false' || null }}
|
||||
check-sig: 'false'
|
||||
packages: >-
|
||||
gcc-core
|
||||
make
|
||||
@@ -529,7 +527,6 @@ jobs:
|
||||
*-android-x86_64 ) run_dir android-x86_64 ;;
|
||||
*-freebsd-x86_64 ) run_dir freebsd-x86_64 ;;
|
||||
*-linux-arm ) run_dir linux-arm ;;
|
||||
*-linux-arm-old ) run_dir linux-arm-old ;;
|
||||
*-linux-arm64 ) run_dir linux-arm64 ;;
|
||||
*-linux-mips64 ) run_dir linux-mips64 ;;
|
||||
*-linux-mipselsf ) run_dir linux-mipsel ;;
|
||||
@@ -556,6 +553,7 @@ jobs:
|
||||
rm -rf binaries/{android*,freebsd*,win*} \
|
||||
init.d/{openrc,pfsense,runit,s6,systemd,windivert.filter.examples} \
|
||||
nfq2 ip2net mdig docs Makefile
|
||||
pigz -11 lua/*.lua
|
||||
)
|
||||
tar --owner=0 --group=0 -czf ${{ env.repo_dir }}-openwrt-embedded.tar.gz ${{ env.repo_dir }}
|
||||
|
||||
|
||||
2
binaries/readme.txt
Normal file
2
binaries/readme.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
Бинари только в релизах. Собираем с исходников или качаем релиз с гитхаба ! Инфа по сборке в docs/compile.
|
||||
Binaries are only in releases. Build from source or download release from github ! See docs/compile.
|
||||
@@ -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,27 +36,28 @@ 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}
|
||||
rnd_mod="--lua-init=$pat=tls_mod($pat,'rnd')"
|
||||
padencap_mod="--lua-desync=luaexec:code=desync.pat=tls_mod($pat,'rnd,dupsid,padencap',desync.reasm_data)"
|
||||
padencap_mod="--lua-desync=luaexec:code=desync.patmod=tls_mod($pat,'rnd,dupsid,padencap',desync.reasm_data)"
|
||||
|
||||
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=#patmod:seqovl_pattern=patmod --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=#patmod:seqovl_pattern=patmod && 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"
|
||||
@@ -102,8 +100,8 @@ pktws_check_https_tls()
|
||||
|
||||
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
|
||||
@@ -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
|
||||
@@ -71,7 +71,7 @@ pktws_fake_https_vary_()
|
||||
shift; shift; shift
|
||||
pktws_curl_test_update $testf $domain ${FAKE_HTTPS:+--blob=$fake:@"$FAKE_HTTPS" }$pre $PAYLOAD --lua-desync=fake:blob=$fake:$fooling:repeats=$FAKE_REPEATS --lua-desync=$splitf:pos=$split $post && ok_any=1
|
||||
pktws_curl_test_update $testf $domain $pre $PAYLOAD --lua-desync=fake:blob=0x00000000:$fooling:repeats=$FAKE_REPEATS --lua-desync=$splitf:pos=$split $post && ok_any=1
|
||||
pktws_curl_test_update $testf $domain $pre $PAYLOAD --lua-desync=fake:blob=0x00000000:$fooling:repeats=$FAKE_REPEATS --lua-desync=fake:blob=$fake:$fooling:tls_mod=rnd,dupsid:repeats=$FAKE_REPEATS --lua-desync=$splitf:pos=$split $post && ok_any=1
|
||||
pktws_curl_test_update $testf $domain ${FAKE_HTTPS:+--blob=$fake:@"$FAKE_HTTPS" }$pre $PAYLOAD --lua-desync=fake:blob=0x00000000:$fooling:repeats=$FAKE_REPEATS --lua-desync=fake:blob=$fake:$fooling:tls_mod=rnd,dupsid:repeats=$FAKE_REPEATS --lua-desync=$splitf:pos=$split $post && ok_any=1
|
||||
pktws_curl_test_update $testf $domain ${FAKE_HTTPS:+--blob=$fake:@"$FAKE_HTTPS" }$pre $PAYLOAD --lua-desync=multisplit:blob=$fake:$fooling:pos=2:nodrop:repeats=$FAKE_REPEATS --lua-desync=$splitf:pos=$split $post && ok_any=1
|
||||
pktws_curl_test_update $testf $domain ${FAKE_HTTPS:+--blob=$fake:@"$FAKE_HTTPS" }$pre $PAYLOAD --lua-desync=fake:blob=$fake:$fooling:tls_mod=rnd,dupsid,padencap:repeats=$FAKE_REPEATS --lua-desync=$splitf:pos=$split $post && ok_any=1
|
||||
[ "$ok_any" = 1 ] && ok=1
|
||||
@@ -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"
|
||||
@@ -106,8 +104,8 @@ pktws_check_https_tls()
|
||||
fake=fake_default_tls
|
||||
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
|
||||
@@ -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
|
||||
@@ -71,7 +71,7 @@ pktws_fake_https_vary_()
|
||||
shift; shift; shift
|
||||
pktws_curl_test_update $testf $domain ${FAKE_HTTPS:+--blob=$fake:@"$FAKE_HTTPS" }${FAKED_PATTERN_HTTPS:+--blob=faked_pat:@"$FAKED_PATTERN_HTTPS" }$pre $PAYLOAD --lua-desync=fake:blob=$fake:$fooling:repeats=$FAKE_REPEATS --lua-desync=$splitf:${FAKED_PATTERN_HTTPS+pattern=faked_pat:}pos=$split:$fooling $post && ok_any=1
|
||||
pktws_curl_test_update $testf $domain ${FAKED_PATTERN_HTTPS:+--blob=faked_pat:@"$FAKED_PATTERN_HTTPS" }$pre $PAYLOAD --lua-desync=fake:blob=0x00000000:$fooling:repeats=$FAKE_REPEATS --lua-desync=$splitf:${FAKED_PATTERN_HTTPS+pattern=faked_pat:}pos=$split:$fooling $post && ok_any=1
|
||||
pktws_curl_test_update $testf $domain ${FAKED_PATTERN_HTTPS:+--blob=faked_pat:@"$FAKED_PATTERN_HTTPS" }$pre $PAYLOAD --lua-desync=fake:blob=0x00000000:$fooling:repeats=$FAKE_REPEATS --lua-desync=fake:blob=$fake:$fooling:tls_mod=rnd,dupsid:repeats=$FAKE_REPEATS --lua-desync=$splitf:${FAKED_PATTERN_HTTPS+pattern=faked_pat:}pos=$split:$fooling $post && ok_any=1
|
||||
pktws_curl_test_update $testf $domain ${FAKE_HTTPS:+--blob=$fake:@"$FAKE_HTTPS" }${FAKED_PATTERN_HTTPS:+--blob=faked_pat:@"$FAKED_PATTERN_HTTPS" }$pre $PAYLOAD --lua-desync=fake:blob=0x00000000:$fooling:repeats=$FAKE_REPEATS --lua-desync=fake:blob=$fake:$fooling:tls_mod=rnd,dupsid:repeats=$FAKE_REPEATS --lua-desync=$splitf:${FAKED_PATTERN_HTTPS+pattern=faked_pat:}pos=$split:$fooling $post && ok_any=1
|
||||
pktws_curl_test_update $testf $domain ${FAKE_HTTPS:+--blob=$fake:@"$FAKE_HTTPS" }${FAKED_PATTERN_HTTPS:+--blob=faked_pat:@"$FAKED_PATTERN_HTTPS" }$pre $PAYLOAD --lua-desync=multisplit:blob=$fake:$fooling:pos=2:nodrop:repeats=$FAKE_REPEATS --lua-desync=$splitf:${FAKED_PATTERN_HTTPS+pattern=faked_pat:}pos=$split:$fooling $post && ok_any=1
|
||||
pktws_curl_test_update $testf $domain ${FAKE_HTTPS:+--blob=$fake:@"$FAKE_HTTPS" }${FAKED_PATTERN_HTTPS:+--blob=faked_pat:@"$FAKED_PATTERN_HTTPS" }$pre $PAYLOAD --lua-desync=fake:blob=$fake:$fooling:tls_mod=rnd,dupsid,padencap:repeats=$FAKE_REPEATS --lua-desync=$splitf:${FAKED_PATTERN_HTTPS+pattern=faked_pat:}pos=$split:$fooling $post && ok_any=1
|
||||
[ "$ok_any" = 1 ] && ok=1
|
||||
@@ -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"
|
||||
@@ -107,8 +105,8 @@ pktws_check_https_tls()
|
||||
fake=fake_default_tls
|
||||
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 + fakedsplit if fakedsplit works
|
||||
[ "$need_fakedsplit" = 0 -a "$SCANLEVEL" != force ] || splitfs=fakedsplit
|
||||
@@ -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()
|
||||
@@ -29,12 +29,12 @@ pktws_check_hostfake()
|
||||
# $2 - domain
|
||||
# $3 - PRE args for nfqws2
|
||||
local testf=$1 domain="$2" pre="$3"
|
||||
local ok ttls attls f fake fooling
|
||||
local ok ttls attls f fooling
|
||||
|
||||
[ "$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
|
||||
|
||||
127
blockcheck2.sh
127
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 ! --syn $IPT_COMMENT -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,9 @@ 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
|
||||
# some methods require empty acks
|
||||
"$WINWS2" --wf-dup-check=0 --wf-tcp-empty=1 $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 +1003,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 +1022,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 +1047,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 +1063,7 @@ ws_curl_test()
|
||||
shift
|
||||
shift
|
||||
$ws_start "$@"
|
||||
curl_test $testf $dom
|
||||
curl_test $testf "$dom"
|
||||
code=$?
|
||||
ws_kill
|
||||
return $code
|
||||
@@ -1060,11 +1073,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 +1099,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 +1327,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 +1354,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
|
||||
|
||||
@@ -133,3 +133,84 @@ v0.7.6
|
||||
* nfqws2: autohostlist reset retransmitter to break long wait
|
||||
* zapret-auto: stadard_failure_detector reset retransmitter to break long wait
|
||||
* nfqws2, init.d, windivert : dht and wg detection changes
|
||||
|
||||
v0.8.0
|
||||
|
||||
* init.d: 50-dht4all NFQWS_OPT_DHT_PKT_OUT
|
||||
* nfqws2: (LUA_COMPAT_VER=4) support 48-bit arithmetics
|
||||
* github actions: remove arm-old target - luajit fail reason revealed
|
||||
* nfqws2: do not treat quic handshake messages as initials
|
||||
* zapret-lib: tls dissector/reconstructor
|
||||
* 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
|
||||
|
||||
0.9.0
|
||||
|
||||
* nfqws2: removed hard check for host: presence in http_req
|
||||
* nfqws2: file open test before destroying in-memory content of ipset/hostlist
|
||||
* github actions: lua 5.5
|
||||
* nfqws2: enable dead reasm protection in wsize=0 case
|
||||
* nfqws2: --intercept
|
||||
* winws2: changed icon to multi-res png up to 256px
|
||||
* nfqws2: support icmp and ipp
|
||||
* nfqws2: VERDICT_PRESERVE_NEXT
|
||||
* nfqws2: keepsum reconstruct option
|
||||
* nfqws2: more helpers
|
||||
* zapret-obfs: ippxor, udp2icmp, synhide
|
||||
* nfqws2: LUA_COMPAT_VER=5
|
||||
* winws2: --wf-raw-filter
|
||||
* nfqws2: conntrack_feed
|
||||
* winws2: use windivert bulk mode
|
||||
* nfqws2: template free import
|
||||
|
||||
@@ -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
|
||||
@@ -12,5 +13,5 @@ make -C /opt/zapret2
|
||||
|
||||
OpenBSD :
|
||||
|
||||
pkg_add luajit gmake bsd
|
||||
gmake -C /opt/zapret2
|
||||
pkg_add luajit gmake
|
||||
gmake -C /opt/zapret2 bsd
|
||||
|
||||
@@ -26,7 +26,7 @@ define Package/nfqws2
|
||||
CATEGORY:=Network
|
||||
TITLE:=nfqws2
|
||||
SUBMENU:=Zapret
|
||||
DEPENDS:=+libnetfilter-queue +lmnl +libcap +zlib +$(LUA_DEP)
|
||||
DEPENDS:=+libnetfilter-queue +libmnl +libcap +zlib +$(LUA_DEP)
|
||||
endef
|
||||
|
||||
define Build/Prepare
|
||||
|
||||
5419
docs/manual.en.md
Normal file
5419
docs/manual.en.md
Normal file
File diff suppressed because it is too large
Load Diff
1621
docs/manual.md
1621
docs/manual.md
File diff suppressed because it is too large
Load Diff
133
docs/readme.md
133
docs/readme.md
@@ -1,3 +1,7 @@
|
||||
## English
|
||||
|
||||
[Manual](manual.en.md)
|
||||
|
||||
## Зачем это нужно
|
||||
|
||||
Автономное средство противодействия DPI, которое не требует подключения каких-либо сторонних серверов. Может помочь
|
||||
@@ -11,11 +15,15 @@ VPN. Может использоваться для частичной проз
|
||||
[Полный мануал](manual.md)
|
||||
|
||||
|
||||
## Поддержать разработчика
|
||||
## Поддержать разработчика. Donations
|
||||
|
||||
Если вы считаете проект полезным и желаете поддержать разработку, направляйте ваши пожертвования на следующие адреса криптокошельков :
|
||||
|
||||
USDT `0x3d52Ce15B7Be734c53fc9526ECbAB8267b63d66E` (предпочительно сеть ERC-20)
|
||||
If you find this project useful and wish to donate here are crypto wallets :
|
||||
|
||||
USDT ERC `0x3d52Ce15B7Be734c53fc9526ECbAB8267b63d66E`
|
||||
|
||||
USDT TRC `TEzAAtn4VhndqEaAyuCM78xh5W2gCjwWEo`
|
||||
|
||||
BTC `bc1qhqew3mrvp47uk2vevt5sctp7p2x9m7m5kkchve`
|
||||
|
||||
@@ -36,12 +44,12 @@ zapret2 является дальнейшим развитием проекта
|
||||
или хотя бы область , в которой их можно искать, плюс владеющий базовыми навыками программирования.
|
||||
|
||||
*nfqws2* оставляет в себе практически тот же функционал - распознавание протоколов, реассемблинг, дешифровка, управление профилями, хостлисты, ipset-ы, базовая фильтрация.
|
||||
Но он полностью лишается возможностей самостоятельно воздействовать на трафик. Часть "дурения" переносится в скриптовой язык программирования LUA.
|
||||
Но он полностью лишается возможностей самостоятельно воздействовать на трафик. Часть "дурения" переносится в скриптовой язык программирования Lua.
|
||||
|
||||
LUA код получает от C кода структурированное представление приходящих пакетов в виде дерева (диссекты), подобного тем, что вы видите в wireshark.
|
||||
Lua код получает от C кода структурированное представление приходящих пакетов в виде дерева (диссекты), подобного тем, что вы видите в wireshark.
|
||||
Туда же приходят результаты сборки или дешифровки частей некоторых протоколов (tls, quic).
|
||||
С код предоставляет функции-хелперы, позволяющие отсылать пакеты, работать с двоичными данными, разбирать TLS, искать маркер-позции и т.д.
|
||||
Имеется библиотека хелперов, написанных на LUA, а так же готовая библиотека программ атаки на DPI (стратегий), реализующая функции *nfqws1* в расширенном варианте
|
||||
Имеется библиотека хелперов, написанных на Lua, а так же готовая библиотека программ атаки на DPI (стратегий), реализующая функции *nfqws1* в расширенном варианте
|
||||
и с большей гибкостью.
|
||||
|
||||
Вы всегда сможете взять и дописать что-то свое. В этом и есть смысл, чтобы борьбой с DPI смог заняться любой, кто разбирается в пакетах.
|
||||
@@ -53,8 +61,7 @@ zapret2 - инструмент для таких энтузиастов. Но э
|
||||
## С чего начать
|
||||
|
||||
Хотелось бы избежать [талмуда](manual.md) на главной странице. Поэтому начнем со способа запуска *nfqws2* и описания способов портирования стратегий *nfqws1* - как в *nfqws2* сделать то же самое, что можно было в *nfqws1*.
|
||||
Когда вы поймете как это работает, вы можете посмотреть LUA код, находящийся "под капотом". Разобрать как он работает, попробовать написать что-то свое.
|
||||
"талмуд" обязательно будет, как он есть у любых более-менее сложных проектов. Он нужен как справочник.
|
||||
Когда вы поймете как это работает, вы можете посмотреть Lua код, находящийся "под капотом". Разобрать как он работает, попробовать написать что-то свое, руководствуясь [талмудом](manual.md) как справочником.
|
||||
|
||||
### Механика обработки трафика
|
||||
|
||||
@@ -102,11 +109,11 @@ nfqws2 --qnum 200 --debug --lua-init=@zapret-lib.lua --lua-init=@zapret-antidpi.
|
||||
--payload=tls_client_hello,http_req --lua-desync=multisplit:pos=1:seqovl=5:seqovl_pattern=0x1603030000
|
||||
```
|
||||
|
||||
Данный пример предполагает, что в той же директории находятся файлы `zapret-lib.lua` - библиотека хелперов на LUA и `zapret-antidpi.lua` - библиотека базовых стратегий.
|
||||
`--lua-init` может содержать LUA код в виде строки. Так удобно писать простой код, например присвоить константу переменной, чтобы не создавать файлы ради этой мелочи.
|
||||
Данный пример предполагает, что в той же директории находятся файлы `zapret-lib.lua` - библиотека хелперов на Lua и `zapret-antidpi.lua` - библиотека базовых стратегий.
|
||||
`--lua-init` может содержать Lua код в виде строки. Так удобно писать простой код, например присвоить константу переменной, чтобы не создавать файлы ради этой мелочи.
|
||||
Либо подцепляется файл, если значение параметра начинается с `@`. Код из `--lua-init` выполняется 1 раз при старте.
|
||||
|
||||
Далее указаны параметры `--lua-desync`. Они содержат имя LUA функции, вызываемой при обработке каждого пакета, проходящего через профиль мультистратегии.
|
||||
Далее указаны параметры `--lua-desync`. Они содержат имя Lua функции, вызываемой при обработке каждого пакета, проходящего через профиль мультистратегии.
|
||||
После двоеточия и через двоеточия следуют параметры для данной функции в формате `param[=value]`. В примере реализована стратегия
|
||||
|
||||
```
|
||||
@@ -122,7 +129,7 @@ nfqws --qnum 200 --debug \
|
||||
Тип пейлоада - тип данных, содержащихся в пакете или группе пакетов. Например, протокол соединения может быть tls, а пейлоады - tls_client_hello, tls_server_hello, unknown.
|
||||
|
||||
Другое важное отличие - отсутствие жестко определенных фаз десинхронизации. То, что вы раньше писали как `fake,multisplit` реализуется двумя
|
||||
последовательно вызываемыми LUA функциями. Их может быть столько, сколько нужно, учитывая логику прохождения пакетов и операций с ними, и у каждой могут быть свои параметры.
|
||||
последовательно вызываемыми Lua функциями. Их может быть столько, сколько нужно, учитывая логику прохождения пакетов и операций с ними, и у каждой могут быть свои параметры.
|
||||
Может даже несколько раз вызываться одна и так же функция с разными параметрами. Так, например, можно послать несколько фейков, причем с разными фулингами.
|
||||
Конкретный вызов `--lua-desync` функции называется инстансом. Инстанс - это связка имени функции, номера вызова внутри профиля и номера самого профиля.
|
||||
Это похоже на одну программу, которую можно запустить много раз с разными параметрами.
|
||||
@@ -130,11 +137,11 @@ nfqws --qnum 200 --debug \
|
||||
Другое немаловажное отличие - поддержка автоматической tcp сегментации средствами `zapret-lib.lua`. Вам больше не нужно думать о размерах отсылаемых tcp пакетов.
|
||||
По каждому соединению отслеживается MSS. Если пакет не влезает в MSS, выполняется сегментация.
|
||||
Например, это может случиться при отправке tls фейка с kyber. Или если вы режете kyber tls так, что одна из частей получается размером 1600 байт,
|
||||
что, очевидно, не влезает в MTU. Или если вы задали seqovl=10000. В *nfqws1* такое значение вызвало бы ошибку. Функция LUA `rawsend_dissect_segmented` отправит
|
||||
что, очевидно, не влезает в MTU. Или если вы задали seqovl=10000. В *nfqws1* такое значение вызвало бы ошибку. Функция Lua `rawsend_dissect_segmented` отправит
|
||||
несколько tcp сегментов с начальным sequence -10000 общим размером 10000 байт, в последнем из которых будет кусок оригинального сообщения.
|
||||
|
||||
В *nfqws2* нет жестко зашитых параметров кастомных фейков типа `--dpi-desync-fake-tls`, `dpi-desync-fake-http` и тд.
|
||||
Вместо них есть блобы. Блоб (blob) - это переменная LUA типа *string*, содержащая блок двоичных данных произвольной длины. От 1 байта до гигабайтов.
|
||||
Вместо них есть блобы. Блоб (blob) - это переменная Lua типа *string*, содержащая блок двоичных данных произвольной длины. От 1 байта до гигабайтов.
|
||||
*nfqws2* автоматически инициализирует блобы со стандартными фейками tls, http, quic, как это и было в *nfqws1*.
|
||||
Блобы могут быть заданы как hex-строка прямо в параметре desync функции, либо пред-загружены при старте с помощью параметра `--blob=name:0xHEX|[+ofs]@filename`
|
||||
|
||||
@@ -169,13 +176,13 @@ range задается как `mX-mY`, `mX<mY`, `-mY`, `<mY`, `mX-`.
|
||||
Что будет, если вы не напишите фильтр `--payload` для fake или multisplit ? В *nfqws1* без `--dpi-desync-any-protocol` они работали только по известным пейлоадам.
|
||||
В *nfqws2* "any protocol" - режим по умолчанию. Однако, функции из библиотеки `zapret-antidpi.lua` написаны так, что по умолчанию работают только по известным пейлоадам
|
||||
и не работают по пустым пакетам или unknown - точно так же, как это было в *nfqws1*.
|
||||
Но лучше все-же писать фильтры `--payload`, потому что они работают на уровне C кода, который выполняется существенно быстрее, чем LUA.
|
||||
Но лучше все-же писать фильтры `--payload`, потому что они работают на уровне C кода, который выполняется существенно быстрее, чем Lua.
|
||||
|
||||
Диссект пакета проходит поочередно по всем `--lua-desync` инстансам профиля, для которых не выполняется условие отсечения (cutoff).
|
||||
Отсечение может быть по range, payload или добровольное отсечение. Последний вариант - когда инстанс сам отказывается обрабатывать пакеты
|
||||
по входящему, исходящему или обоим направлениям. Например, задача стратегии wsize - отреагировать только на пакет с tcp флагами SYN,ACK. После этого он не нужен, в коде вызывается функция отсечения.
|
||||
Это сделано для экономии ресурсов процессора.
|
||||
Если все инстансы в профиле точно никогда больше не будут вызваны по соединению + направлению - вошли в превышение верхней границы range или выполнили добровольный cutoff, то движок LUA не вызывается вообще.
|
||||
Если все инстансы в профиле точно никогда больше не будут вызваны по соединению + направлению - вошли в превышение верхней границы range или выполнили добровольный cutoff, то движок Lua не вызывается вообще.
|
||||
|
||||
От инстанса к инстансу содержимое диссекта может ими меняться. Следующий инстанс видит изменения предыдущего.
|
||||
Каждый инстанс выносит свой вердикт - что делать с текущим диссектом. VERDICT_PASS - означает отправить как есть,
|
||||
@@ -301,19 +308,21 @@ nfqws2 --lua-desync=send:ipfrag:ipfrag_pos_udp=8 --lua-desync=drop
|
||||
Но это решаемо. А что не решаемо - это перехват вторых частей kyber tls hello. Их невозможно опознать без связи с предыдущими фрагментами. Поэтому перехватывается весь порт.
|
||||
Для HTTP вопрос решаемый, поскольку там нет реассемблирования запросов, но http сейчас стал настолько редким, что и смысла нет заморачиваться.
|
||||
|
||||
Везде расставлены фильтры профиля мультистратегии `--filter-l7`, фильтры по `--out-range` и по `--payload`. Зачем ? В основном для сокращения вызовов LUA кода, который заведомо медленнее C кода.
|
||||
Если пакет не попадет в профили с LUA - ни о каком вызове кода LUA речи быть не может. Если пакет попал в профиль с LUA, то после первых 10 пакетов с данными наступает отсечение по верхней границе range. Все LUA инстансы входят в состояние instance cutoff, соединение входит в состояние "lua cutoff" по направлению "out". Значит вызовов LUA не будет вообще. Не просто вызовов, а даже обращения к движку LUA с какой-либо целью. Будет только C код, который посмотрит на признак "cutoff" и сразу же отпустит пакет.
|
||||
Везде расставлены фильтры профиля мультистратегии `--filter-l7`, фильтры по `--out-range` и по `--payload`. Зачем ? В основном для сокращения вызовов Lua кода, который заведомо медленнее C кода.
|
||||
Если пакет не попадет в профили с Lua - ни о каком вызове кода Lua речи быть не может. Если пакет попал в профиль с Lua, то после первых 10 пакетов с данными наступает отсечение по верхней границе range. Все Lua инстансы входят в состояние instance cutoff, соединение входит в состояние "lua cutoff" по направлению "out". Значит вызовов Lua не будет вообще. Не просто вызовов, а даже обращения к движку Lua с какой-либо целью. Будет только C код, который посмотрит на признак "cutoff" и сразу же отпустит пакет.
|
||||
|
||||
Почему именно `-d10` ? Чтобы хватило для отработки большинства вариантов стратегий, учитывая возможные ретрансмиссии и плохую связь. В winws2 по умолчанию включен параметр `--wf-tcp-empty=0`. Он блокирует перехват пустых пакетов с ACK, что позволяет примерно в 2 раза сэкономить на процессоре при интенсивных скачиваниях. Пустые ACK в большинстве стратегий не нужны. Но это же и ломает счетчик "n" - он не будет показывать реальное количество пакетов по соединению. Счетчик "d" работать будет как надо.
|
||||
|
||||
Так же везде расставлены фильтры по payload type. Отчасти так же с целью сократить вызовы LUA даже в пределах первых 10 пакетов с данными.
|
||||
Почему нет "-d10" на udp ? Потому что используется windivert фильтр на пейлоад. Счетчики будут считать не реальное количество пакетов в потоке, а количество перехваченных с отфильтрованными пейлоадами. Причем если интервал между ними будет более 1 минуты, то счет будет начинаться заново, поскольку таймаут udp по умолчанию - 60 сек. После таймаута запись conntrack будет удалена. Следующий пакет пойдет как новый поток.
|
||||
|
||||
Так же везде расставлены фильтры по payload type. Отчасти так же с целью сократить вызовы Lua даже в пределах первых 10 пакетов с данными.
|
||||
С другой стороны, даже при совпадении протокола соединения (`--filter-l7`) может пробежать не интересующий нас пейлоад.
|
||||
По умолчанию многие функции из `zapret-antidpi.lua` реагируют только на известные типы пейлоада, но не на конкретные, а на любые известные.
|
||||
Если допустить малореальный, но гипотетически возможный сценарий, что в рамках протокола http будет отправлен блок данных с tls или фраза, похожая на сообщение из xmpp, то тип пейлоада выскочит tls_client_hello или xmpp_stream, например. Лучше от этого сразу уберечься. Тем более что в других видах протоколов - xmpp, например, -
|
||||
пейлоады могут проскакивать нескольких типов вполне ожидаемо. Но работать надо не по всем.
|
||||
|
||||
В фейке для TLS по умолчанию - fake_default_tls - однократно при старте меняется SNI с "www.microsoft.com" на случайный и рандомизируется поле "random" в TLS handshake.
|
||||
Это делается простой строчкой LUA кода. Больше нет никаких специальных параметров *nfqws2* для модификации пейлоадов.
|
||||
Это делается простой строчкой Lua кода. Больше нет никаких специальных параметров *nfqws2* для модификации пейлоадов.
|
||||
В профиле для youtube на лету меняется SNI на "www.google.com", копируется поле TLS "session id" с обрабатываемого в данный момент TLS handshake.
|
||||
|
||||
```
|
||||
@@ -359,17 +368,14 @@ start "zapret: http,https,quic" /min "%~dp0winws2.exe" ^
|
||||
--lua-desync=multidisorder:pos=midsld ^
|
||||
--new ^
|
||||
--filter-udp=443 --filter-l7=quic --hostlist="%~dp0files\list-youtube.txt" ^
|
||||
--out-range=-d10 ^
|
||||
--payload=quic_initial ^
|
||||
--lua-desync=fake:blob=quic_google:repeats=11 ^
|
||||
--new ^
|
||||
--filter-udp=443 --filter-l7=quic ^
|
||||
--out-range=-d10 ^
|
||||
--payload=quic_initial ^
|
||||
--lua-desync=fake:blob=fake_default_quic:repeats=11 ^
|
||||
--new ^
|
||||
--filter-l7=wireguard,stun,discord ^
|
||||
--out-range=-d10 ^
|
||||
--payload=wireguard_initiation,wireguard_cookie,stun,discord_ip_discovery ^
|
||||
--lua-desync=fake:blob=0x00000000000000000000000000000000:repeats=2
|
||||
```
|
||||
@@ -381,9 +387,9 @@ start "zapret: http,https,quic" /min "%~dp0winws2.exe" ^
|
||||
Надо послать исходный запрос с известным пейлоадом с seqovl случайного размера от 5 до 10 символов со случайным содержимым, состоящим из букв от ‘a’ до ‘z’.
|
||||
Здесь раскрывается не декларативный характер стратегий, а алгоритмический. Стратегия - это программа, и пишите ее вы на языке программирования.
|
||||
Для облегчения простых или стандартных действий есть готовые средства, так что далеко не всегда надо писать свою функцию.
|
||||
Частенько можно обойтись простенькими кусками LUA кода в дополнение к имеющимся.
|
||||
Частенько можно обойтись простенькими кусками Lua кода в дополнение к имеющимся.
|
||||
|
||||
Здесь используется функция `luaexec`, предназначенная для динамического выполнения LUA кода в процессе обработки текущего диссекта.
|
||||
Здесь используется функция `luaexec`, предназначенная для динамического выполнения Lua кода в процессе обработки текущего диссекта.
|
||||
Она инициализирует требуемый blob, записывая его в таблицу desync, которая передается от инстанса к инстансу.
|
||||
Следующий инстанс `tcpseg` использует `rnd` как blob - источник seqovl паттерна.
|
||||
|
||||
@@ -414,4 +420,81 @@ nfqws2 \
|
||||
### Очень важный совет
|
||||
|
||||
Научитесь пользоваться `--debug` логом. Без него будет очень сложно понять *nfqws2* на начальном этапе и приспособиться к новой схеме.
|
||||
Ошибок будет много. Особенно, когда вы начнете писать свой LUA код. Их надо читать.
|
||||
Ошибок будет много. Особенно, когда вы начнете писать свой Lua код. Их надо читать.
|
||||
|
||||
### Не только лишь автономный обман DPI
|
||||
|
||||
Рабочий тестовый пример icmp обфускатора udp от винды к серверу на vps.
|
||||
Для теста используем wireguard. Ничего в конфигах менять не надо - wireguard будет думать, что он работает по udp, но на самом деле он преобразуется в пинги icmp, которые могут проходить NAT. Размер пакетов не изменяется, потому проблемы MTU нет.
|
||||
|
||||
Будем загонять исходящие с клиента в icmp type 8 (echo request) code 199 , исходящие с сервера в icmp type 0 (echo reply) code 199.
|
||||
Код у обоих концов делаем одинаковый, иначе NAT не соотнесет. Без NAT можно коды делать разными для клиента и сервера.
|
||||
Особый icmp code нужен для фильтрации от обычных пингов.
|
||||
|
||||
По стандарту код должен быть 0, но на практике с большой вероятностью работают любые коды.
|
||||
Разные имплементации NAT теоретически могут фильтровать ненулевой код, соотносить или не соотносить код вместе с identifier. Linux NAT соотносит.
|
||||
При любых проблемах убираем wireguard, ставим netcat с обоих концов и пробуем общаться, посматривая в wireshark.
|
||||
Всегда можно откатиться на нулевой код, но тогда у сервера без фильтра по IP клиента будет плохая защита от обычных пингов - все они будут преобразовываться в udp и направляться в wireguard,
|
||||
который будет их игнорировать, поскольку передается мусор. Сервер перестанет пингаться.
|
||||
|
||||
Другой способ избежать проблемы и уйти от стандартных пингов - использовать другие типы icmp. Работающие пары, пробрасываемые Linux NAT :
|
||||
|
||||
- `ctype=8:stype=0` - echo request - echo reply (используется по умолчанию)
|
||||
- `ctype=13:stype=14` - timestamp - timestamp reply
|
||||
- `ctype=15:stype=16` - information request - information reply
|
||||
- `ctype=17:stype=18` - address mask request - address mask reply
|
||||
|
||||
На провайдерских NAT или на аппаратном ускорении роутера может быть другой расклад по работающим парам.
|
||||
Нужно пробовать и смотреть что выходит в сеть после NAT и что приходит на сервер.
|
||||
Например, Linux NAT вообще не пробрасывает type 42 - extended echo request. Но аппаратная железка может пробросить и провайдер тоже.
|
||||
|
||||
Кто знает, может быть DPI настроен сечь icmp тоннели на стандартных пингах, а на других типах icmp нет ?
|
||||
|
||||
|
||||
wireguard server - `1.2.3.4:5555`
|
||||
|
||||
```
|
||||
table ip ztest {
|
||||
chain post {
|
||||
type filter hook output priority mangle; policy accept;
|
||||
meta mark & 0x40000000 == 0x00000000 udp sport 5555 queue flags bypass to 200
|
||||
}
|
||||
|
||||
chain pre {
|
||||
type filter hook input priority mangle; policy accept;
|
||||
meta mark & 0x40000000 == 0x00000000 icmp type echo-request icmp code 199 queue flags bypass to 200
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```
|
||||
nfqws2 --qnum 200 --server
|
||||
--lua-init=@/opt/zapret2/lua/zapret-lib.lua
|
||||
--lua-init=@/opt/zapret2/lua/zapret-obfs.lua
|
||||
--in-range=a
|
||||
--lua-desync=udp2icmp:ccode=199:scode=199
|
||||
```
|
||||
|
||||
Клиент на винде :
|
||||
|
||||
```
|
||||
winws2
|
||||
--wf-icmp-in=0:199 --wf-udp-out=5555
|
||||
--wf-raw-filter="ip.SrcAddr=1.2.3.4 or ip.DstAddr=1.2.3.4"
|
||||
--lua-init=@lua/zapret-lib.lua
|
||||
--lua-init=@lua/zapret-obfs.lua
|
||||
--in-range=a
|
||||
--lua-desync=udp2icmp:ccode=199:scode=199
|
||||
```
|
||||
|
||||
Все лишнее отсекается в ядре в windivert - проц зазря не грузит.
|
||||
--wf-raw-filter сочетается со всем остальным собранным конструктором по AND. Отсекает по IP адресу сервера.
|
||||
--wf-icmp-in отсекает входящие icmp типа 0 с кодом 199.
|
||||
|
||||
И включаем wireguard.
|
||||
В шарке сплошняком пинги и реплаи с кодом 199
|
||||
|
||||
Если IP клиента постоянен, можно дополнительно на стороне сервера сделать фильтр по IP клиента.
|
||||
|
||||
Дополнительно можно сделать dataxor=blob на обоих концах, чтобы поксорить пейлоад.
|
||||
blob растягивается на размер пакета как pattern. Можно использовать от 1 hex byte до специально нагенеренного рандома. На обоих концах должен быть одинаковый
|
||||
|
||||
BIN
files/fake/bgp_open.bin
Normal file
BIN
files/fake/bgp_open.bin
Normal file
Binary file not shown.
BIN
files/fake/bitcoin.bin
Normal file
BIN
files/fake/bitcoin.bin
Normal file
Binary file not shown.
BIN
files/fake/dtls_serverhello.bin
Normal file
BIN
files/fake/dtls_serverhello.bin
Normal file
Binary file not shown.
BIN
files/fake/ntp4.bin
Normal file
BIN
files/fake/ntp4.bin
Normal file
Binary file not shown.
4
files/fake/rtsp_options.bin
Normal file
4
files/fake/rtsp_options.bin
Normal file
@@ -0,0 +1,4 @@
|
||||
OPTIONS rtsp://10.2.2.2:8554/ RTSP/1.0
|
||||
CSeq: 2
|
||||
User-Agent: LibVLC/3.0.16 (LIVE555 Streaming Media v2016.11.28)
|
||||
|
||||
13
files/fake/sip_register.bin
Normal file
13
files/fake/sip_register.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
files/fake/smtp_ehlo.bin
Normal file
1
files/fake/smtp_ehlo.bin
Normal file
@@ -0,0 +1 @@
|
||||
EHLO delta.peach.mil
|
||||
BIN
files/fake/snmp_get_next_request.bin
Normal file
BIN
files/fake/snmp_get_next_request.bin
Normal file
Binary file not shown.
BIN
files/fake/tls_alert.bin
Normal file
BIN
files/fake/tls_alert.bin
Normal file
Binary file not shown.
BIN
files/fake/tls_clienthello_google_com_tlsrec.bin
Normal file
BIN
files/fake/tls_clienthello_google_com_tlsrec.bin
Normal file
Binary file not shown.
BIN
files/fake/tls_serverhello_google_com_tls13.bin
Normal file
BIN
files/fake/tls_serverhello_google_com_tls13.bin
Normal file
Binary file not shown.
@@ -3,6 +3,8 @@
|
||||
|
||||
# can override in config :
|
||||
NFQWS_OPT_DESYNC_DHT="${NFQWS_OPT_DESYNC_DHT:---payload dht --lua-desync=dht_dn}"
|
||||
# set it to "keepalive" to fool all packets, not just the first. or set number of packets to be fooled.
|
||||
NFQWS_OPT_DHT_PKT_OUT=${NFQWS_OPT_DHT_PKT_OUT:-20}
|
||||
|
||||
alloc_dnum DNUM_DHT4ALL
|
||||
alloc_qnum QNUM_DHT4ALL
|
||||
@@ -19,7 +21,7 @@ zapret_custom_firewall()
|
||||
# $1 - 1 - run, 0 - stop
|
||||
|
||||
local f uf4 uf6
|
||||
local first_packet_only="$ipt_connbytes 1:1"
|
||||
local first_packet_only=$(ipt_first_packets $NFQWS_OPT_DHT_PKT_OUT)
|
||||
|
||||
f='-p udp -m u32 --u32'
|
||||
uf4='0>>22&0x3C@4>>16=13:0xFFFF&&0>>22&0x3C@8>>16=0x6431:0x6432'
|
||||
@@ -31,7 +33,7 @@ zapret_custom_firewall_nft()
|
||||
# stop logic is not required
|
||||
|
||||
local f
|
||||
local first_packet_only="$nft_connbytes 1"
|
||||
local first_packet_only=$(nft_first_packets $NFQWS_OPT_DHT_PKT_OUT)
|
||||
|
||||
f="udp length ge 13 meta l4proto udp @ih,0,16 0x6431-0x6432"
|
||||
nft_fw_nfqws_post "$f $first_packet_only" "$f $first_packet_only" $QNUM_DHT4ALL
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
# this custom script runs desync to all wireguard handshake initiation packets
|
||||
# this custom script runs desync to all wireguard handshake initiation, response and cookie packets
|
||||
# NOTE: this works for original wireguard and may not work for 3rd party implementations such as xray
|
||||
# NOTE: @ih requires nft 1.0.1+ and updated kernel version. it's confirmed to work on 5.15 (openwrt 23) and not work on 5.10 (openwrt 22)
|
||||
|
||||
# can override in config :
|
||||
NFQWS_OPT_DESYNC_WG="${NFQWS_OPT_DESYNC_WG:---payload wireguard_initiation --lua-desync=fake:blob=0x00000000000000000000000000000000:repeats=2}"
|
||||
NFQWS_OPT_DESYNC_WG="${NFQWS_OPT_DESYNC_WG:---payload wireguard_initiation,wireguard_response,wireguard_cookie --lua-desync=fake:blob=0x00000000000000000000000000000000:repeats=2}"
|
||||
|
||||
alloc_dnum DNUM_WG4ALL
|
||||
alloc_qnum QNUM_WG4ALL
|
||||
@@ -21,7 +21,9 @@ zapret_custom_firewall()
|
||||
# $1 - 1 - run, 0 - stop
|
||||
|
||||
local f='-p udp -m u32 --u32'
|
||||
fw_nfqws_post $1 "$f 0>>22&0x3C@4>>16=0x9c&&0>>22&0x3C@8=0x01000000" "$f 44>>16=0x9c&&48=0x01000000" $QNUM_WG4ALL
|
||||
fw_nfqws_post $1 "$f 0>>22&0x3C@4>>16=156&&0>>22&0x3C@8=0x01000000" "$f 44>>16=156&&48=0x01000000" $QNUM_WG4ALL
|
||||
fw_nfqws_post $1 "$f 0>>22&0x3C@4>>16=100&&0>>22&0x3C@8=0x02000000" "$f 44>>16=100&&48=0x02000000" $QNUM_WG4ALL
|
||||
fw_nfqws_post $1 "$f 0>>22&0x3C@4>>16=72&&0>>22&0x3C@8=0x03000000" "$f 44>>16=72&&48=0x03000000" $QNUM_WG4ALL
|
||||
}
|
||||
zapret_custom_firewall_nft()
|
||||
{
|
||||
@@ -29,4 +31,8 @@ zapret_custom_firewall_nft()
|
||||
|
||||
local f="udp length 156 @ih,0,32 0x01000000"
|
||||
nft_fw_nfqws_post "$f" "$f" $QNUM_WG4ALL
|
||||
local f="udp length 100 @ih,0,32 0x02000000"
|
||||
nft_fw_nfqws_post "$f" "$f" $QNUM_WG4ALL
|
||||
local f="udp length 72 @ih,0,32 0x03000000"
|
||||
nft_fw_nfqws_post "$f" "$f" $QNUM_WG4ALL
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
@@ -64,8 +65,10 @@ standard ipfrag :
|
||||
|
||||
* ipfrag[=frag_function] - ipfrag function name. "ipfrag2" by default if empty
|
||||
* ipfrag_disorder - send fragments from last to first
|
||||
* ipfrag2 : ipfrag_pos_udp - udp frag position. ipv4 : starting from L4 header. ipb6: starting from fragmentable part. must be multiple of 8. default 8
|
||||
* ipfrag2 : ipfrag_pos_tcp - tcp frag position. ipv4 : starting from L4 header. ipb6: starting from fragmentable part. must be multiple of 8. default 32
|
||||
* ipfrag2 : ipfrag_pos_tcp - tcp frag position. ipv4 : starting from L4 header. ipv6: starting from fragmentable part. must be multiple of 8. default 32
|
||||
* ipfrag2 : ipfrag_pos_udp - udp frag position. ipv4 : starting from L4 header. ipv6: starting from fragmentable part. must be multiple of 8. default 8
|
||||
* ipfrag2 : ipfrag_pos_icmp - icmp frag position. ipv4 : starting from L4 header. ipv6: starting from fragmentable part. must be multiple of 8. default 8
|
||||
* ipfrag2 : ipfrag_pos - frag position for other L4. ipv4 : starting from L4 header. ipv6: starting from fragmentable part. must be multiple of 8. default 32
|
||||
* ipfrag2 : ipfrag_next - next protocol field in ipv6 fragment extenstion header of the second fragment. same as first by default.
|
||||
|
||||
]]
|
||||
@@ -113,7 +116,8 @@ end
|
||||
-- standard args : direction
|
||||
function http_domcase(ctx, desync)
|
||||
if not desync.dis.tcp then
|
||||
instance_cutoff_shim(ctx, desync)
|
||||
-- do not cutoff on related icmp
|
||||
if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end
|
||||
return
|
||||
end
|
||||
direction_cutoff_opposite(ctx, desync)
|
||||
@@ -139,7 +143,8 @@ end
|
||||
-- arg : spell=<str> . spelling of the "Host" header. must be exactly 4 chars long
|
||||
function http_hostcase(ctx, desync)
|
||||
if not desync.dis.tcp then
|
||||
instance_cutoff_shim(ctx, desync)
|
||||
-- do not cutoff on related icmp
|
||||
if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end
|
||||
return
|
||||
end
|
||||
direction_cutoff_opposite(ctx, desync)
|
||||
@@ -149,12 +154,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,25 +172,68 @@ 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)
|
||||
-- do not cutoff on related icmp
|
||||
if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end
|
||||
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)
|
||||
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
|
||||
-- do not cutoff on related icmp
|
||||
if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end
|
||||
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
|
||||
@@ -224,7 +277,8 @@ function synack_split(ctx, desync)
|
||||
instance_cutoff_shim(ctx, desync) -- mission complete
|
||||
end
|
||||
else
|
||||
instance_cutoff_shim(ctx, desync)
|
||||
-- do not cutoff on related icmp
|
||||
if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -241,7 +295,8 @@ function synack(ctx, desync)
|
||||
instance_cutoff_shim(ctx, desync) -- mission complete
|
||||
end
|
||||
else
|
||||
instance_cutoff_shim(ctx, desync)
|
||||
-- do not cutoff on related icmp
|
||||
if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -259,7 +314,8 @@ function wsize(ctx, desync)
|
||||
instance_cutoff_shim(ctx, desync) -- mission complete
|
||||
end
|
||||
else
|
||||
instance_cutoff_shim(ctx, desync)
|
||||
-- do not cutoff on related icmp
|
||||
if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -270,7 +326,8 @@ end
|
||||
-- arg : forced_cutoff=<list> - comma separated list of payloads that trigger forced wssize cutoff. by default - any non-empty payload
|
||||
function wssize(ctx, desync)
|
||||
if not desync.dis.tcp then
|
||||
instance_cutoff_shim(ctx, desync)
|
||||
-- do not cutoff on related icmp
|
||||
if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end
|
||||
return
|
||||
end
|
||||
local verdict = VERDICT_PASS
|
||||
@@ -287,6 +344,40 @@ function wssize(ctx, desync)
|
||||
return verdict
|
||||
end
|
||||
|
||||
-- nfqws1 : not available
|
||||
-- standard args : direction
|
||||
-- arg: blob - blob name to store cloned tls client hello (stored in desync, not global)
|
||||
-- arg: fallback - copy this blob if could not clone
|
||||
-- arg: sni_snt - server name type value in existing names
|
||||
-- arg: sni_snt_new - server name type value for new names
|
||||
-- arg: sni_del_ext - delete sni extension
|
||||
-- arg: sni_del - delete all names
|
||||
-- arg: sni_first - add name to the beginning
|
||||
-- arg: sni_last - add name to the end
|
||||
function tls_client_hello_clone(ctx, desync)
|
||||
if not desync.dis.tcp then
|
||||
-- do not cutoff on related icmp
|
||||
if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end
|
||||
return
|
||||
end
|
||||
direction_cutoff_opposite(ctx, desync)
|
||||
if direction_check(desync) then
|
||||
if not desync.arg.blob then
|
||||
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)
|
||||
if desync[desync.arg.blob] then
|
||||
DLOG("tls_client_hello_clone: cloned to desync."..desync.arg.blob)
|
||||
end
|
||||
end
|
||||
if not desync[desync.arg.blob] and desync.arg.fallback then
|
||||
DLOG("tls_client_hello_clone: desync."..desync.arg.blob.."="..desync.arg.fallback)
|
||||
desync[desync.arg.blob] = blob(desync, desync.arg.fallback)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- nfqws1 : "--dpi-desync=syndata"
|
||||
-- standard args : fooling, rawsend, reconstruct, ipfrag
|
||||
-- arg : blob=<blob> - fake payload. must fit to single packet. no segmentation possible. default - 16 zero bytes.
|
||||
@@ -308,7 +399,8 @@ function syndata(ctx, desync)
|
||||
instance_cutoff_shim(ctx, desync) -- mission complete
|
||||
end
|
||||
else
|
||||
instance_cutoff_shim(ctx, desync)
|
||||
-- do not cutoff on related icmp
|
||||
if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -317,7 +409,8 @@ end
|
||||
-- arg : rstack - send RST,ACK instead of RST
|
||||
function rst(ctx, desync)
|
||||
if not desync.dis.tcp then
|
||||
instance_cutoff_shim(ctx, desync)
|
||||
-- do not cutoff on related icmp
|
||||
if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end
|
||||
return
|
||||
end
|
||||
direction_cutoff_opposite(ctx, desync)
|
||||
@@ -340,15 +433,20 @@ end
|
||||
-- nfqws1 : "--dpi-desync=fake"
|
||||
-- standard args : direction, payload, fooling, ip_id, rawsend, reconstruct, ipfrag
|
||||
-- arg : blob=<blob> - fake payload
|
||||
-- arg : optional - skip if blob is absent
|
||||
-- arg : tls_mod=<list> - comma separated list of tls mods : rnd,rndsni,sni=<str>,dupsid,padencap . sni=%var is supported
|
||||
function fake(ctx, desync)
|
||||
direction_cutoff_opposite(ctx, desync)
|
||||
-- by default process only outgoing known payloads
|
||||
if direction_check(desync) and payload_check(desync) then
|
||||
-- by default process only outgoing known payloads. works only for tcp and udp
|
||||
if (desync.dis.tcp or desync.dis.udp) and direction_check(desync) and payload_check(desync) then
|
||||
if replay_first(desync) then
|
||||
if not desync.arg.blob then
|
||||
error("fake: 'blob' arg required")
|
||||
end
|
||||
if desync.arg.optional and not blob_exist(desync, desync.arg.blob) then
|
||||
DLOG("fake: blob '"..desync.arg.blob.."' not found. skipped")
|
||||
return
|
||||
end
|
||||
local fake_payload = blob(desync, desync.arg.blob)
|
||||
if desync.reasm_data and desync.arg.tls_mod then
|
||||
fake_payload = tls_mod_shim(desync, fake_payload, desync.arg.tls_mod, desync.reasm_data)
|
||||
@@ -368,14 +466,19 @@ end
|
||||
-- arg : seqovl=N . decrease seq number of the first segment by N and fill N bytes with pattern (default - all zero)
|
||||
-- arg : seqovl_pattern=<blob> . override pattern
|
||||
-- arg : blob=<blob> - use this data instead of desync.dis.payload
|
||||
-- arg : optional - skip if blob is absent. use zero pattern if seqovl_pattern blob is absent
|
||||
-- arg : nodrop - do not drop current dissect
|
||||
function multisplit(ctx, desync)
|
||||
if not desync.dis.tcp then
|
||||
instance_cutoff_shim(ctx, desync)
|
||||
-- do not cutoff on related icmp
|
||||
if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end
|
||||
return
|
||||
end
|
||||
direction_cutoff_opposite(ctx, desync)
|
||||
-- by default process only outgoing known payloads
|
||||
if desync.arg.optional and desync.arg.blob and not blob_exist(desync, desync.arg.blob) then
|
||||
DLOG("multisplit: blob '"..desync.arg.blob.."' not found. skipped")
|
||||
return
|
||||
end
|
||||
local data = blob_or_def(desync, desync.arg.blob) or desync.reasm_data or desync.dis.payload
|
||||
if #data>0 and direction_check(desync) and payload_check(desync) then
|
||||
if replay_first(desync) then
|
||||
@@ -393,7 +496,14 @@ function multisplit(ctx, desync)
|
||||
local seqovl=0
|
||||
if i==0 and desync.arg.seqovl and tonumber(desync.arg.seqovl)>0 then
|
||||
seqovl = tonumber(desync.arg.seqovl)
|
||||
local pat = desync.arg.seqovl_pattern and blob(desync,desync.arg.seqovl_pattern) or "\x00"
|
||||
local pat="\x00"
|
||||
if desync.arg.seqovl_pattern then
|
||||
if desync.arg.optional and not blob_exist(desync, desync.arg.seqovl_pattern) then
|
||||
DLOG("multisplit: blob '"..desync.arg.seqovl_pattern.."' not found. using zero pattern")
|
||||
else
|
||||
pat = blob(desync,desync.arg.seqovl_pattern)
|
||||
end
|
||||
end
|
||||
part = pattern(pat,1,seqovl)..part
|
||||
end
|
||||
if b_debug then DLOG("multisplit: sending part "..(i+1).." "..(pos_start-1).."-"..(pos_end-1).." len="..#part.." seqovl="..seqovl.." : "..hexdump_dlog(part)) end
|
||||
@@ -416,11 +526,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
|
||||
@@ -445,7 +554,14 @@ function multidisorder_send(desync, data, seqovl, pos)
|
||||
DLOG("multidisorder: seqovl cancelled because seqovl "..(seqovl-1).." is not less than the first split pos "..(pos[1]-1))
|
||||
else
|
||||
ovl = seqovl - 1
|
||||
local pat = desync.arg.seqovl_pattern and blob(desync,desync.arg.seqovl_pattern) or "\x00"
|
||||
local pat="\x00"
|
||||
if desync.arg.seqovl_pattern then
|
||||
if desync.arg.optional and not blob_exist(desync, desync.arg.seqovl_pattern) then
|
||||
DLOG("multidisorder: blob '"..desync.arg.seqovl_pattern.."' not found. using zero pattern")
|
||||
else
|
||||
pat = blob(desync,desync.arg.seqovl_pattern)
|
||||
end
|
||||
end
|
||||
part = pattern(pat,1,ovl)..part
|
||||
end
|
||||
end
|
||||
@@ -464,14 +580,19 @@ end
|
||||
-- arg : seqovl=N . decrease seq number of the second segment in the original order by N and fill N bytes with pattern (default - all zero). N must be less than the first split pos.
|
||||
-- arg : seqovl_pattern=<blob> . override pattern
|
||||
-- arg : blob=<blob> - use this data instead of reasm_data
|
||||
-- arg : optional - skip if blob is absent. use zero pattern if seqovl_pattern blob is absent
|
||||
-- arg : nodrop - do not drop current dissect
|
||||
function multidisorder(ctx, desync)
|
||||
if not desync.dis.tcp then
|
||||
instance_cutoff_shim(ctx, desync)
|
||||
-- do not cutoff on related icmp
|
||||
if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end
|
||||
return
|
||||
end
|
||||
direction_cutoff_opposite(ctx, desync)
|
||||
-- by default process only outgoing known payloads
|
||||
if desync.arg.optional and desync.arg.blob and not blob_exist(desync, desync.arg.blob) then
|
||||
DLOG("multidisorder: blob '"..desync.arg.blob.."' not found. skipped")
|
||||
return
|
||||
end
|
||||
local data = blob_or_def(desync, desync.arg.blob) or desync.reasm_data or desync.dis.payload
|
||||
if #data>0 and direction_check(desync) and payload_check(desync) then
|
||||
if replay_first(desync) then
|
||||
@@ -512,9 +633,11 @@ end
|
||||
-- arg : pos=<postmarker list> . position marker list. example : "1,host,midsld+1,-10"
|
||||
-- arg : seqovl=N . decrease seq number of the second segment in the original order by N and fill N bytes with pattern (default - all zero). N must be less than the first split pos.
|
||||
-- arg : seqovl_pattern=<blob> . override pattern
|
||||
-- arg : optional - use zero pattern if seqovl_pattern blob is absent
|
||||
function multidisorder_legacy(ctx, desync)
|
||||
if not desync.dis.tcp then
|
||||
instance_cutoff_shim(ctx, desync)
|
||||
-- do not cutoff on related icmp
|
||||
if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end
|
||||
return
|
||||
end
|
||||
direction_cutoff_opposite(ctx, desync)
|
||||
@@ -567,14 +690,19 @@ end
|
||||
-- arg : nofake1, nofake2 - do not send individual fakes
|
||||
-- arg : disorder_after=<posmarker> - send after_host part in 2 disordered segments. if posmarker is empty string use marker "-1"
|
||||
-- arg : blob=<blob> - use this data instead of desync.dis.payload
|
||||
-- arg : optional - skip if blob is absent
|
||||
-- arg : nodrop - do not drop current dissect
|
||||
function hostfakesplit(ctx, desync)
|
||||
if not desync.dis.tcp then
|
||||
instance_cutoff_shim(ctx, desync)
|
||||
-- do not cutoff on related icmp
|
||||
if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end
|
||||
return
|
||||
end
|
||||
direction_cutoff_opposite(ctx, desync)
|
||||
-- by default process only outgoing known payloads
|
||||
if desync.arg.optional and desync.arg.blob and not blob_exist(desync, desync.arg.blob) then
|
||||
DLOG("hostfakesplit: blob '"..desync.arg.blob.."' not found. skipped")
|
||||
return
|
||||
end
|
||||
local data = blob_or_def(desync, desync.arg.blob) or desync.reasm_data or desync.dis.payload
|
||||
if #data>0 and direction_check(desync) and payload_check(desync) then
|
||||
if replay_first(desync) then
|
||||
@@ -680,14 +808,19 @@ end
|
||||
-- arg : seqovl=N . decrease seq number of the first segment by N and fill N bytes with pattern (default - all zero)
|
||||
-- arg : seqovl_pattern=<blob> . override seqovl pattern
|
||||
-- arg : blob=<blob> - use this data instead of reasm_data
|
||||
-- arg : optional - skip if blob is absent. use zero pattern if seqovl_pattern blob is absent
|
||||
-- arg : nodrop - do not drop current dissect
|
||||
function fakedsplit(ctx, desync)
|
||||
if not desync.dis.tcp then
|
||||
instance_cutoff_shim(ctx, desync)
|
||||
-- do not cutoff on related icmp
|
||||
if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end
|
||||
return
|
||||
end
|
||||
direction_cutoff_opposite(ctx, desync)
|
||||
-- by default process only outgoing known payloads
|
||||
if desync.arg.optional and desync.arg.blob and not blob_exist(desync, desync.arg.blob) then
|
||||
DLOG("fakedsplit: blob '"..desync.arg.blob.."' not found. skipped")
|
||||
return
|
||||
end
|
||||
local data = blob_or_def(desync, desync.arg.blob) or desync.reasm_data or desync.dis.payload
|
||||
if #data>0 and direction_check(desync) and payload_check(desync) then
|
||||
if replay_first(desync) then
|
||||
@@ -719,7 +852,14 @@ function fakedsplit(ctx, desync)
|
||||
local seqovl=0
|
||||
if desync.arg.seqovl and tonumber(desync.arg.seqovl)>0 then
|
||||
seqovl = tonumber(desync.arg.seqovl)
|
||||
pat = desync.arg.seqovl_pattern and blob(desync,desync.arg.seqovl_pattern) or "\x00"
|
||||
pat="\x00"
|
||||
if desync.arg.seqovl_pattern then
|
||||
if desync.arg.optional and not blob_exist(desync, desync.arg.seqovl_pattern) then
|
||||
DLOG("fakedsplit: blob '"..desync.arg.seqovl_pattern.."' not found. using zero pattern")
|
||||
else
|
||||
pat = blob(desync,desync.arg.seqovl_pattern)
|
||||
end
|
||||
end
|
||||
part = pattern(pat,1,seqovl)..part
|
||||
end
|
||||
if b_debug then DLOG("fakedsplit: sending real part 1 : 0-"..(pos-2).." len="..#part.." seqovl="..seqovl.." : "..hexdump_dlog(part)) end
|
||||
@@ -773,14 +913,19 @@ end
|
||||
-- arg : seqovl=N . decrease seq number of the second segment by N and fill N bytes with pattern (default - all zero). N must be less than the split pos.
|
||||
-- arg : seqovl_pattern=<blob> . override seqovl pattern
|
||||
-- arg : blob=<blob> - use this data instead of desync.dis.payload
|
||||
-- arg : optional - skip if blob is absent. use zero pattern if seqovl_pattern blob is absent
|
||||
-- arg : nodrop - do not drop current dissect
|
||||
function fakeddisorder(ctx, desync)
|
||||
if not desync.dis.tcp then
|
||||
instance_cutoff_shim(ctx, desync)
|
||||
-- do not cutoff on related icmp
|
||||
if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end
|
||||
return
|
||||
end
|
||||
direction_cutoff_opposite(ctx, desync)
|
||||
-- by default process only outgoing known payloads
|
||||
if desync.arg.optional and desync.arg.blob and not blob_exist(desync, desync.arg.blob) then
|
||||
DLOG("fakeddisorder: blob '"..desync.arg.blob.."' not found. skipped")
|
||||
return
|
||||
end
|
||||
local data = blob_or_def(desync, desync.arg.blob) or desync.reasm_data or desync.dis.payload
|
||||
if #data>0 and direction_check(desync) and payload_check(desync) then
|
||||
if replay_first(desync) then
|
||||
@@ -817,7 +962,14 @@ function fakeddisorder(ctx, desync)
|
||||
DLOG("fakeddisorder: seqovl cancelled because seqovl "..seqovl.." is not less than the split pos "..(pos-1))
|
||||
seqovl = 0
|
||||
else
|
||||
local pat = desync.arg.seqovl_pattern and blob(desync,desync.arg.seqovl_pattern) or "\x00"
|
||||
local pat="\x00"
|
||||
if desync.arg.seqovl_pattern then
|
||||
if desync.arg.optional and not blob_exist(desync, desync.arg.seqovl_pattern) then
|
||||
DLOG("fakeddisorder: blob '"..desync.arg.seqovl_pattern.."' not found. using zero pattern")
|
||||
else
|
||||
pat = blob(desync,desync.arg.seqovl_pattern)
|
||||
end
|
||||
end
|
||||
part = pattern(pat,1,seqovl)..part
|
||||
end
|
||||
else
|
||||
@@ -874,16 +1026,21 @@ end
|
||||
-- arg : seqovl=N . decrease seq number of the first segment by N and fill N bytes with pattern (default - all zero)
|
||||
-- arg : seqovl_pattern=<blob> . override pattern
|
||||
-- arg : blob=<blob> - use this data instead of desync.dis.payload
|
||||
-- arg : optional - skip if blob is absent. use zero pattern if seqovl_pattern blob is absent
|
||||
function tcpseg(ctx, desync)
|
||||
if not desync.dis.tcp then
|
||||
instance_cutoff_shim(ctx, desync)
|
||||
-- do not cutoff on related icmp
|
||||
if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end
|
||||
return
|
||||
end
|
||||
direction_cutoff_opposite(ctx, desync)
|
||||
if not desync.arg.pos then
|
||||
error("tcpseg: no pos specified")
|
||||
end
|
||||
-- by default process only outgoing known payloads
|
||||
if desync.arg.optional and desync.arg.blob and not blob_exist(desync, desync.arg.blob) then
|
||||
DLOG("tcpseg: blob '"..desync.arg.blob.."' not found. skipped")
|
||||
return
|
||||
end
|
||||
local data = blob_or_def(desync, desync.arg.blob) or desync.reasm_data or desync.dis.payload
|
||||
if #data>0 and direction_check(desync) and payload_check(desync) then
|
||||
if replay_first(desync) then
|
||||
@@ -897,7 +1054,14 @@ function tcpseg(ctx, desync)
|
||||
local seqovl=0
|
||||
if desync.arg.seqovl and tonumber(desync.arg.seqovl)>0 then
|
||||
seqovl = tonumber(desync.arg.seqovl)
|
||||
local pat = desync.arg.seqovl_pattern and blob(desync,desync.arg.seqovl_pattern) or "\x00"
|
||||
local pat="\x00"
|
||||
if desync.arg.seqovl_pattern then
|
||||
if desync.arg.optional and not blob_exist(desync, desync.arg.seqovl_pattern) then
|
||||
DLOG("tcpseg: blob '"..desync.arg.seqovl_pattern.."' not found. using zero pattern")
|
||||
else
|
||||
pat = blob(desync,desync.arg.seqovl_pattern)
|
||||
end
|
||||
end
|
||||
part = pattern(pat,1,seqovl)..part
|
||||
end
|
||||
if b_debug then DLOG("tcpseg: sending "..(pos[1]-1).."-"..(pos[2]-1).." len="..#part.." seqovl="..seqovl.." : "..hexdump_dlog(part)) end
|
||||
@@ -911,6 +1075,106 @@ 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
|
||||
-- do not cutoff on related icmp
|
||||
if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end
|
||||
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)
|
||||
if not urp then
|
||||
DLOG("oob: cannot resolve urp marker '"..desync.arg.urp.."'")
|
||||
instance_cutoff_shim(ctx, desync)
|
||||
return
|
||||
end
|
||||
DLOG("oob: resolved urp marker to "..urp-1)
|
||||
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
|
||||
@@ -920,7 +1184,8 @@ end
|
||||
-- arg : pattern_offset=N . offset in the pattern. 0 by default
|
||||
function udplen(ctx, desync)
|
||||
if not desync.dis.udp then
|
||||
instance_cutoff_shim(ctx, desync)
|
||||
-- do not cutoff on related icmp
|
||||
if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end
|
||||
return
|
||||
end
|
||||
direction_cutoff_opposite(ctx, desync)
|
||||
@@ -953,15 +1218,16 @@ end
|
||||
|
||||
-- nfqws1 : "--dpi-desync=tamper" for dht proto
|
||||
-- standard args : direction
|
||||
-- arg : dn=N - message starts from "dN". 2 by default
|
||||
-- arg : dn=N - message starts from "dN". 3 by default
|
||||
function dht_dn(ctx, desync)
|
||||
if not desync.dis.udp then
|
||||
instance_cutoff_shim(ctx, desync)
|
||||
-- do not cutoff on related icmp
|
||||
if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end
|
||||
return
|
||||
end
|
||||
direction_cutoff_opposite(ctx, desync)
|
||||
if desync.l7payload=="dht" and direction_check(desync) then
|
||||
local N = tonumber(desync.arg.dn) or 2
|
||||
local N = tonumber(desync.arg.dn) or 3
|
||||
-- remove "d1" from the start not breaking bencode
|
||||
local prefix = "d"..tostring(N)..":"..string.rep("0",N).."1:x"
|
||||
desync.dis.payload = prefix..string.sub(desync.dis.payload,2)
|
||||
|
||||
@@ -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
|
||||
@@ -399,7 +403,7 @@ function cond_payload_str(desync)
|
||||
if not desync.arg.pattern then
|
||||
error("cond_payload_str: missing 'pattern'")
|
||||
end
|
||||
return string.find(desync.dis.payload,desync.arg.pattern,1,true)
|
||||
return desync.dis.payload and string.find(desync.dis.payload,desync.arg.pattern,1,true)
|
||||
end
|
||||
-- check iff function available. error if not
|
||||
function require_iff(desync, name)
|
||||
@@ -454,13 +458,17 @@ end
|
||||
function repeater(ctx, desync)
|
||||
local repeats = tonumber(desync.arg.repeats)
|
||||
if not repeats then
|
||||
error("repeat: missing 'repeats'")
|
||||
error("repeater: missing 'repeats'")
|
||||
end
|
||||
local iff = desync.arg.iff or "cond_true"
|
||||
if type(_G[iff])~="function" then
|
||||
error(name..": invalid 'iff' function '"..iff.."'")
|
||||
error("repeater: invalid 'iff' function '"..iff.."'")
|
||||
end
|
||||
orchestrate(ctx, desync)
|
||||
if #desync.plan==0 then
|
||||
DLOG("repeater: execution plan is empty - nothing to repeat")
|
||||
return
|
||||
end
|
||||
local neg = desync.arg.neg
|
||||
local stop = desync.arg.stop
|
||||
local clear = desync.arg.clear
|
||||
|
||||
1450
lua/zapret-lib.lua
1450
lua/zapret-lib.lua
File diff suppressed because it is too large
Load Diff
482
lua/zapret-obfs.lua
Normal file
482
lua/zapret-obfs.lua
Normal file
@@ -0,0 +1,482 @@
|
||||
-- test case : --in-range=a --out-range=a --lua-desync=wgobfs:secret=mycoolpassword
|
||||
-- encrypt standard wireguard messages - initiation, response, cookie - and change udp packet size
|
||||
-- do not encrypt data messages and keepalives
|
||||
-- wgobfs adds maximum of 30+padmax bytes to udp size
|
||||
-- reduce MTU of wireguard interface to avoid ip fragmentation !
|
||||
-- without knowing the secret encrypted packets should be crypto strong white noise with no signature
|
||||
-- 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)
|
||||
if not desync.dis.udp then
|
||||
instance_cutoff_shim(ctx, desync)
|
||||
return
|
||||
end
|
||||
|
||||
local padmin = desync.arg.padmin and tonumber(desync.arg.padmin) or 0
|
||||
local padmax = desync.arg.padmax and tonumber(desync.arg.padmax) or 16
|
||||
local function genkey()
|
||||
-- cache key in a global var bound to instance name
|
||||
local key_cache_name = desync.func_instance.."_key"
|
||||
local key = _G[key_cache_name]
|
||||
if not key then
|
||||
key = hkdf("sha256", "wgobfs_salt", desync.arg.secret, nil, 16)
|
||||
_G[key_cache_name] = key
|
||||
end
|
||||
return key
|
||||
end
|
||||
local function maybe_encrypted_payload(payload)
|
||||
for k,plsize in pairs({2+12+16+148, 2+12+16+92, 2+12+16+64}) do
|
||||
if #payload>=(plsize+padmin) and #payload<=(plsize+padmax) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
local function wg_payload_from_size(payload)
|
||||
if #payload==148 then return "wireguard_initiation"
|
||||
elseif #payload==92 then return "wireguard_response"
|
||||
elseif #payload==64 then return "wireguard_cookie"
|
||||
else return nil
|
||||
end
|
||||
end
|
||||
|
||||
if not desync.arg.secret or #desync.arg.secret==0 then
|
||||
error("wgobfs: secret required")
|
||||
end
|
||||
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
|
||||
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
|
||||
-- encrypting more than one message with the same iv is considered catastrophic failure
|
||||
-- iv must be sent with encrypted message
|
||||
local iv = bcryptorandom(12)
|
||||
local encrypted, atag = aes_gcm(true, key, iv, bu16(#desync.dis.payload)..desync.dis.payload..brandom(math.random(padmin,padmax)), nil)
|
||||
desync.dis.payload = iv..atag..encrypted
|
||||
return VERDICT_MODIFY
|
||||
end
|
||||
|
||||
if desync.l7payload=="unknown" and maybe_encrypted_payload(desync.dis.payload) then
|
||||
local key = genkey()
|
||||
local iv = string.sub(desync.dis.payload,1,12)
|
||||
local atag = string.sub(desync.dis.payload,13,28)
|
||||
local decrypted, atag2 = aes_gcm(false, key, iv, string.sub(desync.dis.payload,29))
|
||||
if atag==atag2 then
|
||||
local plen = u16(decrypted)
|
||||
if plen>(#decrypted-2) then
|
||||
DLOG("wgobfs: bad decrypted payload data")
|
||||
else
|
||||
desync.dis.payload = string.sub(decrypted, 3, 3+plen-1)
|
||||
if b_debug then DLOG("wgobfs: decrypted '"..(wg_payload_from_size(desync.dis.payload) or "unknown").."' message. size "..plen) end
|
||||
return VERDICT_MODIFY
|
||||
end
|
||||
else
|
||||
DLOG("wgobfs: decrypt auth tag mismatch")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- test case :
|
||||
-- endpoint1:
|
||||
-- --filter-icmp=0,8,128,129 --filter-ipp=193,198,209,250 --filter-tcp=* --filter-udp=* --in-range=a --lua-desync=ippxor:xor=192:dataxor=0xABCD
|
||||
-- nft add rule inet ztest pre meta mark and 0x40000000 == 0 meta l4proto {193, 198, 209, 250} queue num 200 bypass
|
||||
-- nft add rule inet ztest post meta mark and 0x40000000 == 0 tcp dport "{5001}" queue num 200 bypass
|
||||
-- nft add rule inet ztest post meta mark and 0x40000000 == 0 udp dport "{5001}" queue num 200 bypass
|
||||
-- iperf -i 1 -c endpoint2
|
||||
-- endpoint2:
|
||||
-- --filter-icmp=0,8,128,129 --filter-ipp=193,198,209,250 --filter-tcp=* --filter-udp=* --in-range=a --lua-desync=ippxor:xor=192:dataxor=0xABCD --server
|
||||
-- nft add rule inet ztest pre meta mark and 0x40000000 == 0 meta l4proto {193, 198, 209, 250} queue num 200 bypass
|
||||
-- nft add rule inet ztest post meta mark and 0x40000000 == 0 tcp sport "{5001}" queue num 200 bypass
|
||||
-- nft add rule inet ztest post meta mark and 0x40000000 == 0 udp sport "{5001}" queue num 200 bypass
|
||||
-- iperf -s
|
||||
-- xor ip protocol number and optionally xor tcp,udp,icmp payload with supplied blob pattern
|
||||
-- arg : ippxor - value to xor ip protocol number
|
||||
-- arg : dataxor - blob to xor tcp, udp or icmp payload
|
||||
-- arg : rebuild - always reconstruct desync.dis if after ippxor packet becomes tcp,udp or icmp
|
||||
function ippxor(ctx, desync)
|
||||
local dataxor
|
||||
local function need_dxor(dis)
|
||||
return dataxor and dis.payload and #dis.payload>0 and (dis.tcp or dis.udp or dis.icmp)
|
||||
end
|
||||
local function dxor(dis)
|
||||
dis.payload = bxor(dis.payload, pattern(dataxor,1,#dis.payload))
|
||||
end
|
||||
|
||||
if not desync.arg.ippxor then
|
||||
error("ippxor: ippxor value required")
|
||||
end
|
||||
local ippxor = tonumber(desync.arg.ippxor)
|
||||
if ippxor<0 or ippxor>0xFF then
|
||||
error("ippxor: invalid ippxor value. should be 0..255")
|
||||
end
|
||||
if desync.arg.dataxor then
|
||||
dataxor = blob(desync,desync.arg.dataxor)
|
||||
if #dataxor==0 then
|
||||
error("ippxor: empty dataxor value")
|
||||
end
|
||||
end
|
||||
|
||||
local bdxor = need_dxor(desync.dis)
|
||||
if bdxor then
|
||||
DLOG("ippxor: dataxor size="..#desync.dis.payload)
|
||||
dxor(desync.dis)
|
||||
end
|
||||
|
||||
local l3_from = ip_proto_l3(desync.dis)
|
||||
local l3_to = bitxor(l3_from, ippxor)
|
||||
DLOG("ippxor: "..l3_from.." => "..l3_to)
|
||||
fix_ip_proto(desync.dis, l3_to)
|
||||
|
||||
if (not bdxor and dataxor or desync.arg.rebuild) and
|
||||
(l3_to==IPPROTO_TCP and not desync.dis.tcp or
|
||||
l3_to==IPPROTO_UDP and not desync.dis.udp or
|
||||
l3_to==IPPROTO_ICMP and not (desync.dis.ip and desync.dis.icmp) or
|
||||
l3_to==IPPROTO_ICMPV6 and not (desync.dis.ip6 and desync.dis.icmp))
|
||||
then
|
||||
DLOG("ippxor: packet rebuild")
|
||||
local raw_ip = reconstruct_dissect(desync.dis, {ip6_preserve_next=true})
|
||||
local dis = dissect(raw_ip)
|
||||
if not dis.ip and not dis.ip6 then
|
||||
DLOG_ERR("ippxor: could not rebuild packet")
|
||||
return
|
||||
end
|
||||
desync.dis = dis
|
||||
end
|
||||
|
||||
if not bdxor and need_dxor(desync.dis) then
|
||||
DLOG("ippxor: dataxor size="..#desync.dis.payload)
|
||||
dxor(desync.dis)
|
||||
end
|
||||
|
||||
return VERDICT_MODIFY + VERDICT_PRESERVE_NEXT
|
||||
end
|
||||
|
||||
-- test case:
|
||||
-- endpoint1:
|
||||
-- --in-range=a --lua-desync=udp2icmp
|
||||
-- nft add rule inet ztest post meta mark and 0x40000000 == 0 udp dport 12345 queue num 200 bypass
|
||||
-- nft add rule inet ztest pre meta mark and 0x40000000 == 0 meta l4proto "{icmp,icmpv6}" queue num 200 bypass
|
||||
-- endpoint2:
|
||||
-- --in-range=a --lua-desync=udp2icmp --server
|
||||
-- nft add rule inet ztest post meta mark and 0x40000000 == 0 udp sport 12345 queue num 200 bypass
|
||||
-- nft add rule inet ztest pre meta mark and 0x40000000 == 0 meta l4proto "{icmp,icmpv6}" queue num 200 bypass
|
||||
-- packs udp datagram to icmp message without changing packet size
|
||||
-- function keeps icmp identifier as (sport xor dport) to help traverse NAT (it won't help if NAT changes id)
|
||||
-- one end must be in server mode, another - in client mode
|
||||
-- arg : ctype - client icmp type
|
||||
-- arg : ccode - client icmp code
|
||||
-- arg : stype - server icmp type
|
||||
-- arg : scode - server icmp code
|
||||
-- arg : dataxor - blob to xor udp payload
|
||||
-- arg : server=[0|1] - override server mode. by default use "--server" nfqws2 parameter
|
||||
function udp2icmp(ctx, desync)
|
||||
local dataxor
|
||||
local bserver = desync.arg.server and (desync.arg.server~="0") or b_server
|
||||
|
||||
local function one_byte_arg(name)
|
||||
if desync.arg[name] then
|
||||
local v = tonumber(desync.arg[name])
|
||||
if v<0 or v>0xFF then
|
||||
error("udp2icmp: invalid type or code value. should be 0..255")
|
||||
end
|
||||
return v
|
||||
end
|
||||
end
|
||||
local function ictype(send)
|
||||
local ctype = one_byte_arg("ctype")
|
||||
local stype = one_byte_arg("stype")
|
||||
if logical_xor(ctype,stype) then
|
||||
error("udp2icmp: ctype and stype must be both set or not set")
|
||||
end
|
||||
if not ctype then
|
||||
ctype = desync.dis.ip6 and ICMP6_ECHO_REQUEST or ICMP_ECHO
|
||||
stype = desync.dis.ip6 and ICMP6_ECHO_REPLY or ICMP_ECHOREPLY
|
||||
end
|
||||
return logical_xor(send,bserver) and ctype or stype
|
||||
end
|
||||
local function iccode(send)
|
||||
local ccode = one_byte_arg("ccode")
|
||||
local scode = one_byte_arg("scode")
|
||||
if logical_xor(ccode,scode) then
|
||||
error("udp2icmp: ccode and scode must be both set or not set")
|
||||
end
|
||||
if not ccode then
|
||||
ccode = 0
|
||||
scode = 0
|
||||
end
|
||||
return logical_xor(send,bserver) and ccode or scode
|
||||
end
|
||||
local function plxor()
|
||||
if dataxor then
|
||||
DLOG("udp2icmp: dataxor")
|
||||
desync.dis.payload = bxor(desync.dis.payload, pattern(dataxor,1,#desync.dis.payload))
|
||||
end
|
||||
end
|
||||
|
||||
if desync.arg.dataxor then
|
||||
dataxor = blob(desync,desync.arg.dataxor)
|
||||
if #dataxor==0 then
|
||||
error("udp2icmp: empty dataxor value")
|
||||
end
|
||||
end
|
||||
|
||||
if desync.dis.udp then
|
||||
plxor()
|
||||
if b_debug then -- save some cpu
|
||||
DLOG("udp2icmp: udp => icmp sport="..desync.dis.udp.uh_sport.." dport="..desync.dis.udp.uh_dport.." size="..#desync.dis.payload)
|
||||
end
|
||||
desync.dis.icmp = {
|
||||
icmp_type = ictype(true),
|
||||
icmp_code = iccode(true),
|
||||
icmp_data = u32(
|
||||
bu16(bitxor(desync.dis.udp.uh_sport,desync.dis.udp.uh_dport))..
|
||||
(bserver and bu16(desync.dis.udp.uh_sport) or bu16(desync.dis.udp.uh_dport)))
|
||||
}
|
||||
desync.dis.udp = nil
|
||||
fix_ip_proto(desync.dis)
|
||||
return VERDICT_MODIFY
|
||||
elseif desync.dis.icmp and desync.dis.icmp.icmp_type==ictype(false) and desync.dis.icmp.icmp_code==iccode(false) then
|
||||
local pl = bitand(desync.dis.icmp.icmp_data,0xFFFF)
|
||||
local pm = bitxor(bitrshift(desync.dis.icmp.icmp_data,16),pl)
|
||||
desync.dis.udp = {
|
||||
uh_sport = bserver and pm or pl,
|
||||
uh_dport = bserver and pl or pm,
|
||||
uh_ulen = UDP_BASE_LEN + #desync.dis.payload
|
||||
}
|
||||
desync.dis.icmp = nil
|
||||
fix_ip_proto(desync.dis)
|
||||
if b_debug then -- save some cpu
|
||||
DLOG("udp2icmp: icmp => udp sport="..desync.dis.udp.uh_sport.." dport="..desync.dis.udp.uh_dport.." size="..#desync.dis.payload)
|
||||
end
|
||||
plxor()
|
||||
return VERDICT_MODIFY
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
test case :
|
||||
both:
|
||||
nft create table inet ztest
|
||||
nft add chain inet ztest post "{type filter hook output priority mangle;}"
|
||||
nft add chain inet ztest pre "{type filter hook input priority mangle;}"
|
||||
nft add chain inet ztest predefrag "{type filter hook output priority -401;}"
|
||||
nft add rule inet ztest predefrag "mark & 0x40000000 != 0x00000000 notrack"
|
||||
client:
|
||||
--in-range="<d1" --out-range="<d1" --lua-desync=synhide:synack:ghost=2
|
||||
nft add rule inet ztest post "meta mark & 0x40000000 == 0x00000000 tcp dport { 80, 443 } tcp flags & (fin | syn | rst | ack | urg) == syn queue flags bypass to 200"
|
||||
nft add rule inet ztest pre meta "mark & 0x40000000 == 0x00000000 tcp sport { 80, 443 } tcp flags & (fin | syn | rst | ack | urg) == (rst | ack) tcp urgptr != 0 queue flags bypass to 200"
|
||||
nft add rule inet ztest pre meta "mark & 0x40000000 == 0x00000000 tcp sport { 80, 443 } tcp flags & (fin | syn | rst | ack | urg) == (rst | ack) tcp option 172 exists queue flags bypass to 200"
|
||||
nft add rule inet ztest pre meta "mark & 0x40000000 == 0x00000000 tcp sport { 80, 443 } tcp flags & (fin | syn | rst | ack | urg) == (rst | ack) @th,100,4 != 0 queue flags bypass to 200"
|
||||
server:
|
||||
--in-range=a --lua-desync=synhide:synack
|
||||
nft add rule inet ztest post "meta mark & 0x40000000 == 0x00000000 tcp sport { 80, 443 } tcp flags & (fin | syn | rst | ack | urg) == (syn | ack) queue flags bypass to 200"
|
||||
nft add rule inet ztest pre "meta mark & 0x40000000 == 0x00000000 tcp dport { 80, 443 } tcp flags & (fin | syn | rst | ack | urg) == ack tcp urgptr != 0 queue flags bypass to 200"
|
||||
nft add rule inet ztest pre "meta mark & 0x40000000 == 0x00000000 tcp dport { 80, 443 } tcp flags & (fin | syn | rst | ack | urg) == ack tcp option 172 exists queue flags bypass to 200"
|
||||
nft add rule inet ztest pre "meta mark & 0x40000000 == 0x00000000 tcp dport { 80, 443 } tcp flags & (fin | syn | rst | ack | urg) == ack @th,100,4 != 0 queue flags bypass to 200"
|
||||
nft add rule inet ztest pre "meta mark & 0x40000000 == 0x00000000 tcp dport { 80, 443 } tcp flags & (fin | syn | rst | ack | urg) == ack ct state new queue flags bypass to 200"
|
||||
|
||||
hides tcp handshake from DPI optionally using ghost SYN packet with low ttl to punch NAT hole
|
||||
NOTE: linux conntrack treats packets without SYN in SYN_SENT state as INVALID ! NAT does not work !
|
||||
NOTE: the only found workaround - put NFQUEUE handler to that packet. It should only return pass verdict.
|
||||
NOTE: BSD and CGNAT should work
|
||||
NOTE: won't likely pass home routers even with hardware offload enabled - SYN state is managed in netfilter before offload. but can work from router itself.
|
||||
|
||||
arg : ghost - ghost syn ttl for ipv4. must be hop_to_last_nat+1. syn is not ghosted if not supplied
|
||||
arg : ghost6 - ghost syn hl for ipv6. must be hop_to_last_nat+1. syn is not ghosted if not supplied
|
||||
arg : synack - also fake synack. NOTE: will likely not work with magic=tsecr on *nix clients because they expect valid echoed tsecr in SYN,ACK
|
||||
arg : magic=[x2|urp|opt|tsecr] - where to put magic value to recognize modified packets
|
||||
arg : x2=bit - th_x2 bit used for magic=x2 - 1,2,4,8
|
||||
arg : kind - kind of tcp option for magic=opt
|
||||
arg : opt=hex - tcp option value
|
||||
arg : xorseq=hex - 4 hex bytes to xor seq
|
||||
--]]
|
||||
function synhide(ctx, desync)
|
||||
if not desync.dis.tcp then
|
||||
instance_cutoff_shim(ctx, desync)
|
||||
return
|
||||
end
|
||||
|
||||
local fl = bitand(desync.dis.tcp.th_flags, TH_SYN+TH_ACK+TH_FIN+TH_RST+TH_URG)
|
||||
local tsidx = find_tcp_option(desync.dis.tcp.options, TCP_KIND_TS)
|
||||
local magic
|
||||
if desync.arg.magic then
|
||||
if desync.arg.magic~="tsecr" and desync.arg.magic~="x2" and desync.arg.magic~="urp" and desync.arg.magic~="opt" then
|
||||
error("synhide: invalid magic mode '"..desync.arg.magic.."'")
|
||||
end
|
||||
magic = desync.arg.magic
|
||||
if magic=="tsecr" and not tsidx then
|
||||
DLOG("synhide: cannot use tsecr magic because timestamp option is absent")
|
||||
instance_cutoff_shim(ctx, desync)
|
||||
return
|
||||
end
|
||||
else
|
||||
magic = "x2"
|
||||
end
|
||||
DLOG("synhide: magic="..magic)
|
||||
|
||||
local x2
|
||||
if desync.arg.x2 then
|
||||
x2 = tonumber(desync.arg.x2)
|
||||
if x2<1 or x2>0x0F then
|
||||
error("synhide: invalid x2 value")
|
||||
end
|
||||
else
|
||||
-- some firewalls allow only AECN bit (1). if reserved bits are !=0 => administratively prohibited
|
||||
x2 = 1
|
||||
end
|
||||
|
||||
local kind
|
||||
if desync.arg.kind then
|
||||
kind = tonumber(desync.arg.kind)
|
||||
-- do not allow noop and end
|
||||
if kind<2 or kind>0xFF then
|
||||
error("synhide: invalid kind value")
|
||||
end
|
||||
else
|
||||
kind = 172 -- accurate ecn
|
||||
end
|
||||
|
||||
local opt
|
||||
if desync.arg.opt then
|
||||
opt = parse_hex(desync.arg.opt)
|
||||
if not opt then
|
||||
error("synhide: invalid opt value")
|
||||
end
|
||||
else
|
||||
opt=""
|
||||
end
|
||||
|
||||
|
||||
local xorseq
|
||||
if desync.arg.xorseq then
|
||||
xorseq = parse_hex(desync.arg.xorseq)
|
||||
if not xorseq or #xorseq~=4 then
|
||||
error("synhide: invalid xorseq value")
|
||||
end
|
||||
xorseq = u32(xorseq)
|
||||
end
|
||||
|
||||
local function make_magic(client)
|
||||
local m
|
||||
-- use client seq0
|
||||
m = client and desync.dis.tcp.th_seq or desync.dis.tcp.th_ack-1
|
||||
m = bitxor(bitrshift(m,16),bitand(m,0xFFFF))
|
||||
if m==0 then
|
||||
-- 0 is not acceptable
|
||||
m = client and desync.dis.tcp.th_dport or desync.dis.tcp.th_sport
|
||||
end
|
||||
return m
|
||||
end
|
||||
local function xorhdr()
|
||||
if xorseq then
|
||||
desync.dis.tcp.th_ack = bitxor(desync.dis.tcp.th_ack, xorseq)
|
||||
desync.dis.tcp.th_seq = bitxor(desync.dis.tcp.th_seq, xorseq)
|
||||
end
|
||||
end
|
||||
local function ver_magic(client)
|
||||
local r = false
|
||||
xorhdr()
|
||||
if magic=="tsecr" then
|
||||
r = make_magic(client)==u16(string.sub(desync.dis.tcp.options[tsidx].data,7))
|
||||
elseif magic=="x2" then
|
||||
r = bitand(desync.dis.tcp.th_x2, x2)~=0
|
||||
elseif magic=="urp" then
|
||||
r = desync.dis.tcp.th_urp == make_magic(client)
|
||||
elseif magic=="opt" then
|
||||
local idx = find_tcp_option(desync.dis.tcp.options, kind)
|
||||
r = idx and desync.dis.tcp.options[idx].data == opt
|
||||
end
|
||||
xorhdr()
|
||||
return r
|
||||
end
|
||||
local function set_magic(client)
|
||||
if magic=="tsecr" then
|
||||
desync.dis.tcp.options[tsidx].data = string.sub(desync.dis.tcp.options[tsidx].data,1,6) .. bu16(make_magic(client))
|
||||
elseif magic=="x2" then
|
||||
desync.dis.tcp.th_x2 = bitor(desync.dis.tcp.th_x2, x2)
|
||||
elseif magic=="urp" then
|
||||
desync.dis.tcp.th_urp = make_magic(client)
|
||||
elseif magic=="opt" then
|
||||
table.insert(desync.dis.tcp.options, {kind=kind, data=opt})
|
||||
end
|
||||
xorhdr()
|
||||
end
|
||||
local function clear_magic()
|
||||
xorhdr()
|
||||
if magic=="tsecr" then
|
||||
desync.dis.tcp.options[tsidx].data = string.sub(desync.dis.tcp.options[tsidx].data,1,6) .. "\x00\x00"
|
||||
elseif magic=="x2" then
|
||||
desync.dis.tcp.th_x2 = bitand(desync.dis.tcp.th_x2,bitnot(x2))
|
||||
elseif magic=="urp" then
|
||||
desync.dis.tcp.th_urp = 0
|
||||
elseif magic=="opt" then
|
||||
local idx = find_tcp_option(desync.dis.tcp.options, kind)
|
||||
if idx then
|
||||
table.remove(desync.dis.tcp.options, idx)
|
||||
end
|
||||
end
|
||||
desync.track = conntrack_feed(desync.dis)
|
||||
end
|
||||
|
||||
if fl==TH_SYN then
|
||||
-- client sent
|
||||
local ttl = tonumber(desync.dis.ip and desync.arg.ghost or desync.arg.ghost6)
|
||||
if ttl then
|
||||
DLOG("synhide: punch NAT hole with ttl="..ttl)
|
||||
local dis = deepcopy(desync.dis)
|
||||
if dis.ip then
|
||||
dis.ip.ip_ttl = ttl
|
||||
elseif dis.ip6 then
|
||||
dis.ip6.ip6_hlim = ttl
|
||||
end
|
||||
if not rawsend_dissect(dis, rawsend_opts_base(desync)) then
|
||||
instance_cutoff_shim(ctx, desync) -- failed
|
||||
return
|
||||
end
|
||||
end
|
||||
DLOG("synhide: client sends SYN. remove SYN")
|
||||
set_magic(true)
|
||||
-- remove SYN, set ACK
|
||||
desync.dis.tcp.th_flags = bitor(bitand(desync.dis.tcp.th_flags, bitnot(TH_SYN)), TH_ACK)
|
||||
if not desync.arg.synack then
|
||||
DLOG("synhide: mission complete")
|
||||
instance_cutoff_shim(ctx, desync)
|
||||
end
|
||||
return VERDICT_MODIFY
|
||||
elseif fl==(TH_SYN+TH_ACK) then
|
||||
-- server sent
|
||||
if desync.arg.synack then
|
||||
DLOG("synhide: server sends SYN+ACK. remove SYN, set RST")
|
||||
set_magic(false)
|
||||
desync.dis.tcp.th_flags = bitor(bitand(desync.dis.tcp.th_flags, bitnot(TH_SYN)), TH_RST)
|
||||
return VERDICT_MODIFY
|
||||
else
|
||||
DLOG("synhide: server sends SYN+ACK. do not remove SYN because 'synack' arg is not set.")
|
||||
instance_cutoff_shim(ctx, desync)
|
||||
return -- do nothing
|
||||
end
|
||||
elseif fl==TH_ACK and ver_magic(true) then
|
||||
DLOG("synhide: server received magic. restore SYN")
|
||||
desync.dis.tcp.th_flags = bitor(bitand(desync.dis.tcp.th_flags, bitnot(TH_ACK)), TH_SYN)
|
||||
clear_magic()
|
||||
if not desync.arg.synack then
|
||||
DLOG("synhide: mission complete")
|
||||
instance_cutoff_shim(ctx, desync)
|
||||
end
|
||||
return VERDICT_MODIFY
|
||||
elseif fl==(TH_ACK+TH_RST) and ver_magic(false) then
|
||||
DLOG("synhide: client received magic. restore SYN, remove RST")
|
||||
desync.dis.tcp.th_flags = bitor(bitand(desync.dis.tcp.th_flags, bitnot(TH_RST)), TH_SYN)
|
||||
clear_magic()
|
||||
DLOG("synhide: mission complete")
|
||||
instance_cutoff_shim(ctx, desync)
|
||||
return VERDICT_MODIFY
|
||||
end
|
||||
|
||||
DLOG("synhide: sequence failed")
|
||||
instance_cutoff_shim(ctx, desync)
|
||||
end
|
||||
@@ -30,7 +30,7 @@ function pcap(ctx, desync)
|
||||
os.remove(_G[fn_cache_name])
|
||||
end
|
||||
end
|
||||
local f = io.open(_G[fn_cache_name], "a")
|
||||
local f = io.open(_G[fn_cache_name], "ab")
|
||||
if not f then
|
||||
error("pcap: could not write to '".._G[fn_cache_name].."'")
|
||||
end
|
||||
|
||||
@@ -13,15 +13,19 @@ 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_get_source_ip, test_ifaddrs, test_rawsend},...)
|
||||
end
|
||||
|
||||
|
||||
function test_crypto(...)
|
||||
test_run({test_random, test_aes, test_aes_gcm, test_aes_ctr, test_hkdf, test_hash},...)
|
||||
test_run({test_random, test_bop, test_aes, test_aes_gcm, test_aes_ctr, test_hkdf, test_hash},...)
|
||||
end
|
||||
|
||||
function test_random()
|
||||
print("* random")
|
||||
|
||||
local rnds={}
|
||||
for i=1,20 do
|
||||
local rnd = bcryptorandom(math.random(10,20))
|
||||
@@ -31,7 +35,35 @@ function test_random()
|
||||
end
|
||||
end
|
||||
|
||||
function test_bop()
|
||||
print("* bop")
|
||||
|
||||
for n,test in ipairs(
|
||||
{
|
||||
{ fb = bxor, fbit = bitxor, nb = "bxor", nbit="bitxor" },
|
||||
{ fb = bor, fbit = bitor, nb = "bor", nbit="bitor" },
|
||||
{ fb = band, fbit = bitand, nb = "band", nbit="bitand" }
|
||||
}) do
|
||||
for k=1,5 do
|
||||
local r = {}
|
||||
for i=1,6 do r[i] = math.random(0,0xFFFFFFFFFFFF) end
|
||||
local v1 = bu48(r[1])..bu48(r[2])..bu48(r[3])
|
||||
local v2 = bu48(r[4])..bu48(r[5])..bu48(r[6])
|
||||
print("x1 : "..string2hex(v1))
|
||||
print("x2 : "..string2hex(v2))
|
||||
local v3 = test.fb(v1,v2)
|
||||
local v4 = bu48(test.fbit(r[1],r[4]))..bu48(test.fbit(r[2],r[5]))..bu48(test.fbit(r[3],r[6]))
|
||||
print(test.nb.." : "..string2hex(v3))
|
||||
print(test.nbit.." : "..string2hex(v4))
|
||||
print("result : "..(v3==v4 and "OK" or "FAIL"))
|
||||
test_assert(v3==v4)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function test_hash()
|
||||
print("* hash")
|
||||
|
||||
local hashes={}
|
||||
for i=1,5 do
|
||||
local rnd = brandom(math.random(5,64))
|
||||
@@ -48,6 +80,8 @@ function test_hash()
|
||||
end
|
||||
|
||||
function test_hkdf()
|
||||
print("* hkdf")
|
||||
|
||||
local nblob = 2
|
||||
local okms = {}
|
||||
for nsalt=1,nblob do
|
||||
@@ -84,6 +118,8 @@ function test_hkdf()
|
||||
end
|
||||
|
||||
function test_aes()
|
||||
print("* aes")
|
||||
|
||||
local clear_text="test "..brandom_az09(11)
|
||||
local iv, key, encrypted, decrypted
|
||||
|
||||
@@ -93,7 +129,7 @@ function test_aes()
|
||||
print()
|
||||
print("* aes test key_size "..tostring(key_size))
|
||||
|
||||
print("clear text: "..clear_text);
|
||||
print("clear text: "..clear_text)
|
||||
|
||||
print("* encrypting")
|
||||
encrypted = aes(true, key, clear_text)
|
||||
@@ -121,6 +157,8 @@ function test_aes()
|
||||
end
|
||||
|
||||
function test_aes_gcm()
|
||||
print("* aes_gcm")
|
||||
|
||||
local authenticated_data = "authenticated message "..brandom_az09(math.random(10,50))
|
||||
local clear_text="test message "..brandom_az09(math.random(10,50))
|
||||
local iv, key, encrypted, atag, decrypted, atag2
|
||||
@@ -132,8 +170,8 @@ function test_aes_gcm()
|
||||
print()
|
||||
print("* aes_gcm test key_size "..tostring(key_size))
|
||||
|
||||
print("clear text: "..clear_text);
|
||||
print("authenticated data: "..authenticated_data);
|
||||
print("clear text: "..clear_text)
|
||||
print("authenticated data: "..authenticated_data)
|
||||
|
||||
print("* encrypting")
|
||||
encrypted, atag = aes_gcm(true, key, iv, clear_text, authenticated_data)
|
||||
@@ -188,6 +226,8 @@ function test_aes_gcm()
|
||||
end
|
||||
|
||||
function test_aes_ctr()
|
||||
print("* aes_ctr")
|
||||
|
||||
local clear_text="test message "..brandom_az09(math.random(10,50))
|
||||
local iv, key, encrypted, decrypted
|
||||
|
||||
@@ -198,7 +238,7 @@ function test_aes_ctr()
|
||||
print()
|
||||
print("* aes_ctr test key_size "..tostring(key_size))
|
||||
|
||||
print("clear text: "..clear_text);
|
||||
print("clear text: "..clear_text)
|
||||
|
||||
print("* encrypting")
|
||||
encrypted = aes_ctr(key, iv, clear_text)
|
||||
@@ -251,61 +291,109 @@ function test_aes_ctr()
|
||||
end
|
||||
|
||||
function test_ub()
|
||||
for k,f in pairs({{u8,bu8,0xFF,8}, {u16,bu16,0xFFFF,16}, {u24,bu24,0xFFFFFF,24}, {u32,bu32,0xFFFFFFFF,32}}) do
|
||||
print("* ub")
|
||||
|
||||
for k,f in pairs({{u8,bu8,0xFF,8}, {u16,bu16,0xFFFF,16}, {u24,bu24,0xFFFFFF,24}, {u32,bu32,0xFFFFFFFF,32}, {u48,bu48,0xFFFFFFFFFFFF,48}}) do
|
||||
local v = math.random(0,f[3])
|
||||
local pos = math.random(1,20)
|
||||
local s = brandom(pos-1)..f[2](v)..brandom(20)
|
||||
local v2 = f[1](s,pos)
|
||||
print("u"..tostring(f[4]).." pos="..tostring(pos).." "..tostring(v).." "..tostring(v2))
|
||||
print(string.format("u%u pos=%u %016X %016X",f[4],pos,v,v2))
|
||||
test_assert(v==v2)
|
||||
end
|
||||
end
|
||||
|
||||
function test_bit()
|
||||
print("* bit")
|
||||
|
||||
local v, v2, v3, v4, b1, b2, pow
|
||||
|
||||
v = math.random(0,0xFFFFFFFF)
|
||||
b1 = math.random(1,16)
|
||||
for i=1,100 do
|
||||
v = math.random(0,0xFFFFFFFFFFFF)
|
||||
b1 = math.random(1,16)
|
||||
|
||||
v2 = bitrshift(v, b1)
|
||||
pow = 2^b1
|
||||
v3 = divint(v, pow)
|
||||
print(string.format("rshift(0x%X,%u) = 0x%X 0x%X/%u = 0x%X", v,b1,v2, v,pow,v3))
|
||||
v2 = bitrshift(v, b1)
|
||||
pow = 2^b1
|
||||
v3 = divint(v, pow)
|
||||
print(string.format("rshift(0x%X,%u) = 0x%X 0x%X/%u = 0x%X", v,b1,v2, v,pow,v3))
|
||||
test_assert(v2==v3)
|
||||
|
||||
v = math.random(0,0xFFFFFFFFF)
|
||||
b1 = math.random(1,12)
|
||||
v2 = bitlshift(v, b1)
|
||||
pow = 2^b1
|
||||
v3 = (v * pow) % 0x1000000000000
|
||||
print(string.format("lshift(0x%X,%u) = 0x%X 0x%X*%u %% 0x100000000000 = 0x%X", v,b1,v2, v,pow,v3))
|
||||
test_assert(v2==v3)
|
||||
|
||||
v2 = math.random(0,0xFFFFFFFFFFFF)
|
||||
v3 = bitxor(v, v2)
|
||||
v4 = bitor(v, v2) - bitand(v, v2)
|
||||
print(string.format("xor(0x%X,0x%X) = %X or/and/minus = %X", v, v2, v3, v4))
|
||||
test_assert(v3==v4)
|
||||
|
||||
b1 = math.random(1,31)
|
||||
b2 = b1 + math.random(1,16)
|
||||
v2 = bitget(v, b1, b2)
|
||||
pow = 2^(b2-b1+1) - 1
|
||||
v3 = bitand(bitrshift(v,b1), pow)
|
||||
print(string.format("bitget(0x%X,%u,%u) = 0x%X bitand/bitrshift/pow = 0x%X", v, b1, b2, v2, v3))
|
||||
test_assert(v2==v3)
|
||||
|
||||
v4 = math.random(0,pow)
|
||||
v2 = bitset(v, b1, b2, v4)
|
||||
v3 = bitor(bitlshift(v4, b1), bitand(v, bitnot(bitlshift(pow, b1))))
|
||||
print(string.format("bitset(0x%X,%u,%u,0x%X) = 0x%X bitand/bitnot/bitlshift/pow = 0x%X", v, b1, b2, v4, v2, v3))
|
||||
test_assert(v2==v3)
|
||||
end
|
||||
end
|
||||
|
||||
function test_swap()
|
||||
print("* 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)
|
||||
|
||||
v2 = bitlshift(v, b1)
|
||||
pow = 2^b1
|
||||
v3 = (v * pow) % 0x100000000
|
||||
print(string.format("lshift(0x%X,%u) = 0x%X 0x%X*%u %% 0x10000000 = 0x%X", v,b1,v2, v,pow,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)
|
||||
|
||||
v2 = math.random(0,0xFFFFFFFF)
|
||||
v3 = bitxor(v, v2)
|
||||
v4 = bitor(v, v2) - bitand(v, v2)
|
||||
print(string.format("xor(0x%X,0x%X) = %X or/and/minus = %X", v, v2, v3, v4))
|
||||
test_assert(v3==v4)
|
||||
|
||||
b2 = b1 + math.random(1,15)
|
||||
v2 = bitget(v, b1, b2)
|
||||
pow = 2^(b2-b1+1) - 1
|
||||
v3 = bitand(bitrshift(v,b1), pow)
|
||||
print(string.format("bitget(0x%X,%u,%u) = 0x%X bitand/bitrshift/pow = 0x%X", v, b1, b2, 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)
|
||||
|
||||
v4 = math.random(0,pow)
|
||||
v2 = bitset(v, b1, b2, v4)
|
||||
v3 = bitor(bitlshift(v4, b1), bitand(v, bitnot(bitlshift(pow, b1))))
|
||||
print(string.format("bitset(0x%X,%u,%u,0x%X) = 0x%X bitand/bitnot/bitlshift/pow = 0x%X", v, b1, b2, v4, 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()
|
||||
print("* ux")
|
||||
|
||||
local v1, v2, v3, usum, sum
|
||||
|
||||
for k,test in pairs({
|
||||
{ add=u8add, fname="u8add", max = 0xFF },
|
||||
{ add=u16add, fname="u16add", max = 0xFFFF },
|
||||
{ add=u24add, fname="u24add", max = 0xFFFFFF },
|
||||
{ add=u32add, fname="u32add", max = 0xFFFFFFFF }
|
||||
{ add=u32add, fname="u32add", max = 0xFFFFFFFF },
|
||||
{ add=u48add, fname="u48add", max = 0xFFFFFFFFFFFF }
|
||||
}) do
|
||||
io.write(test.fname.." : ")
|
||||
for i=1,1000 do
|
||||
@@ -315,7 +403,7 @@ function test_ux()
|
||||
usum = test.add(v1,v2,v3)
|
||||
sum = bitand((v1+v2+v3)%(test.max+1),test.max)
|
||||
if sum~=usum then
|
||||
print("FAIL")
|
||||
print(string.format("FAIL: 0x%012X + 0x%012X + 0x%012X = 0x%012X 0x%012X",v1,v2,v3,usum,sum))
|
||||
end
|
||||
test_assert(sum==usum)
|
||||
end
|
||||
@@ -324,14 +412,47 @@ 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()
|
||||
print("* 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()
|
||||
print("* ipstr")
|
||||
|
||||
local s_ip, ip, s_ip2
|
||||
|
||||
s_ip = string.format("%u.%u.%u.%u", math.random(0,255), math.random(0,255), math.random(0,255), math.random(0,255));
|
||||
s_ip = string.format("%u.%u.%u.%u", math.random(0,255), math.random(0,255), math.random(0,255), math.random(0,255))
|
||||
ip = pton(s_ip)
|
||||
s_ip2 = ntop(ip)
|
||||
print("IP: "..s_ip)
|
||||
@@ -339,7 +460,7 @@ function test_ipstr()
|
||||
print("IP2: "..s_ip2)
|
||||
test_assert(s_ip==s_ip2)
|
||||
|
||||
s_ip = string.format("%x:%x:%x:%x:%x:%x:%x:%x", math.random(1,0xFFFF), math.random(1,0xFFFF), math.random(1,0xFFFF), math.random(1,0xFFFF), math.random(1,0xFFFF), math.random(1,0xFFFF), math.random(1,0xFFFF), math.random(1,0xFFFF));
|
||||
s_ip = string.format("%x:%x:%x:%x:%x:%x:%x:%x", math.random(1,0xFFFF), math.random(1,0xFFFF), math.random(1,0xFFFF), math.random(1,0xFFFF), math.random(1,0xFFFF), math.random(1,0xFFFF), math.random(1,0xFFFF), math.random(1,0xFFFF))
|
||||
ip = pton(s_ip)
|
||||
s_ip2 = ntop(ip)
|
||||
print("IP: "..s_ip)
|
||||
@@ -350,6 +471,8 @@ end
|
||||
|
||||
|
||||
function test_dissect()
|
||||
print("* dissect")
|
||||
|
||||
local dis, raw1, raw2
|
||||
|
||||
for i=1,20 do
|
||||
@@ -387,13 +510,56 @@ function test_dissect()
|
||||
}
|
||||
raw1 = reconstruct_dissect(ip_tcp)
|
||||
print("IP+TCP : "..string2hex(raw1))
|
||||
dis1 = dissect(raw1);
|
||||
dis1 = dissect(raw1)
|
||||
raw2 = reconstruct_dissect(dis1)
|
||||
dis2 = dissect(raw2);
|
||||
dis2 = dissect(raw2)
|
||||
print("IP+TCP2: "..string2hex(raw2))
|
||||
print( raw1==raw2 and "DISSECT OK" or "DISSECT FAILED" )
|
||||
test_assert(raw1==raw2)
|
||||
|
||||
print("IP standalone")
|
||||
raw1 = reconstruct_iphdr(ip_tcp.ip)
|
||||
print("IP1: "..string2hex(raw1))
|
||||
dis1 = dissect_iphdr(raw1)
|
||||
raw2 = reconstruct_iphdr(dis1)
|
||||
print("IP2: "..string2hex(raw2))
|
||||
print( raw1==raw2 and "DISSECT OK" or "DISSECT FAILED" )
|
||||
test_assert(raw1==raw2)
|
||||
|
||||
print("TCP standalone")
|
||||
raw1 = reconstruct_tcphdr(ip_tcp.tcp)
|
||||
print("TCP1: "..string2hex(raw1))
|
||||
dis1 = dissect_tcphdr(raw1)
|
||||
raw2 = reconstruct_tcphdr(dis1)
|
||||
print("TCP2: "..string2hex(raw2))
|
||||
print( raw1==raw2 and "DISSECT OK" or "DISSECT FAILED" )
|
||||
test_assert(raw1==raw2)
|
||||
|
||||
local ip_icmp = {
|
||||
ip = {
|
||||
ip_tos = math.random(0,255),
|
||||
ip_id = math.random(0,0xFFFF),
|
||||
ip_off = 0,
|
||||
ip_ttl = math.random(0,255),
|
||||
ip_p = IPPROTO_ICMP,
|
||||
ip_src = brandom(4),
|
||||
ip_dst = brandom(4),
|
||||
options = brandom(math.random(0,40))
|
||||
},
|
||||
icmp = {
|
||||
icmp_type = ICMP_DEST_UNREACH, icmp_code=ICMP_UNREACH_PORT,
|
||||
icmp_data = math.random(1,0xFFFFFFFF)
|
||||
}
|
||||
}
|
||||
print("ICMP standalone")
|
||||
raw1 = reconstruct_icmphdr(ip_icmp.icmp)
|
||||
print("ICMP1: "..string2hex(raw1))
|
||||
dis1 = dissect_icmphdr(raw1)
|
||||
raw2 = reconstruct_icmphdr(dis1)
|
||||
print("ICMP2: "..string2hex(raw2))
|
||||
print( raw1==raw2 and "DISSECT OK" or "DISSECT FAILED" )
|
||||
test_assert(raw1==raw2)
|
||||
|
||||
local ip6_udp = {
|
||||
ip6 = {
|
||||
ip6_flow = 0x60000000 + math.random(0,0xFFFFFFF),
|
||||
@@ -414,18 +580,56 @@ function test_dissect()
|
||||
|
||||
raw1 = reconstruct_dissect(ip6_udp)
|
||||
print("IP6+UDP : "..string2hex(raw1))
|
||||
dis1 = dissect(raw1);
|
||||
dis1 = dissect(raw1)
|
||||
raw2 = reconstruct_dissect(dis1)
|
||||
dis2 = dissect(raw2);
|
||||
dis2 = dissect(raw2)
|
||||
print("IP6+UDP2: "..string2hex(raw2))
|
||||
print( raw1==raw2 and "DISSECT OK" or "DISSECT FAILED" )
|
||||
test_assert(raw1==raw2)
|
||||
|
||||
raw1 = string.sub(reconstruct_dissect(ip6_udp),1,-4-#ip6_udp.payload)
|
||||
dis1 = dissect(raw1, false)
|
||||
dis2 = dissect(raw1, true)
|
||||
local ok = not dis1.ip6 and dis2.ip6
|
||||
print("IP6 partial : "..(ok and "OK" or "FAIL"))
|
||||
test_assert(ok)
|
||||
|
||||
print("IP6+IPP")
|
||||
dis1 = {ip6 = ip6_udp.ip6, payload=brandom(math.random(1,1))}
|
||||
raw1 = reconstruct_dissect(dis1,{ip6_last_proto=IPPROTO_IPIP})
|
||||
dis2 = dissect(raw1)
|
||||
raw2 = reconstruct_dissect(dis2,{ip6_preserve_next=true})
|
||||
print("IP6+IPP1: "..string2hex(raw1))
|
||||
print("IP6+IPP2: "..string2hex(raw2))
|
||||
print( raw1==raw2 and "DISSECT OK" or "DISSECT FAILED" )
|
||||
test_assert(raw1==raw2)
|
||||
|
||||
print("UDP standalone")
|
||||
raw1 = reconstruct_udphdr(ip6_udp.udp)
|
||||
print("UDP1: "..string2hex(raw1))
|
||||
dis1 = dissect_udphdr(raw1)
|
||||
raw2 = reconstruct_udphdr(dis1)
|
||||
print("UDP2: "..string2hex(raw2))
|
||||
print( raw1==raw2 and "DISSECT OK" or "DISSECT FAILED" )
|
||||
test_assert(raw1==raw2)
|
||||
|
||||
print("IP6 standalone")
|
||||
ip6_udp.ip6.ip6_plen = nil
|
||||
raw1 = reconstruct_ip6hdr(ip6_udp.ip6,{ip6_last_proto=IPPROTO_UDP})
|
||||
print("IP1: "..string2hex(raw1))
|
||||
dis1 = dissect_ip6hdr(raw1)
|
||||
raw2 = reconstruct_ip6hdr(dis1,{ip6_last_proto=IPPROTO_UDP})
|
||||
print("IP2: "..string2hex(raw2))
|
||||
print( raw1==raw2 and "DISSECT OK" or "DISSECT FAILED" )
|
||||
test_assert(raw1==raw2)
|
||||
end
|
||||
end
|
||||
|
||||
function test_csum()
|
||||
print("* csum")
|
||||
|
||||
local payload = brandom(math.random(10,20))
|
||||
local ip4b, ip6b, raw, tcpb, udpb, dis1, dis2
|
||||
local ip4b, ip6b, raw, tcpb, udpb, icmpb, dis1, dis2
|
||||
local ip = {
|
||||
ip_tos = math.random(0,255),
|
||||
ip_id = math.random(0,0xFFFF),
|
||||
@@ -526,18 +730,17 @@ function test_csum()
|
||||
print( dis1.tcp.th_sum==dis2.tcp.th_sum and "TCP+IP6 CSUM OK" or "TCP+IP6 CSUM FAILED" )
|
||||
test_assert(dis1.tcp.th_sum==dis2.tcp.th_sum)
|
||||
|
||||
|
||||
ip.ip_p = IPPROTO_UDP
|
||||
ip4b = reconstruct_iphdr(ip)
|
||||
ip6.ip6_plen = packet_len({ip6=ip6,udp=udp,payload=payload}) - IP6_BASE_LEN
|
||||
ip6b = reconstruct_ip6hdr(ip6, {ip6_last_proto=IPPROTO_UDP})
|
||||
|
||||
local udp = {
|
||||
uh_sport = math.random(0,0xFFFF),
|
||||
uh_dport = math.random(0,0xFFFF),
|
||||
uh_ulen = UDP_BASE_LEN + #payload
|
||||
}
|
||||
|
||||
ip.ip_p = IPPROTO_UDP
|
||||
ip4b = reconstruct_iphdr(ip)
|
||||
ip6.ip6_plen = packet_len({ip6=ip6,udp=udp,payload=payload}) - IP6_BASE_LEN
|
||||
ip6b = reconstruct_ip6hdr(ip6, {ip6_last_proto=IPPROTO_UDP})
|
||||
|
||||
udpb = reconstruct_udphdr(udp)
|
||||
raw = bu16(udp.uh_sport) ..
|
||||
bu16(udp.uh_dport) ..
|
||||
@@ -559,33 +762,117 @@ function test_csum()
|
||||
dis2 = dissect(ip6b..udpb..payload)
|
||||
print( dis1.udp.uh_sum==dis2.udp.uh_sum and "UDP+IP6 CSUM OK" or "UDP+IP6 CSUM FAILED" )
|
||||
test_assert(dis1.udp.uh_sum==dis2.udp.uh_sum)
|
||||
|
||||
local icmp = {
|
||||
icmp_type = math.random(0,0xFF), icmp_code=math.random(0,0xFF),
|
||||
icmp_data = math.random(0,0xFFFFFFFF)
|
||||
}
|
||||
ip.ip_p = IPPROTO_ICMP
|
||||
ip4b = reconstruct_iphdr(ip)
|
||||
ip6.ip6_plen = packet_len({ip6=ip6,icmp=icmp,payload=payload}) - IP6_BASE_LEN
|
||||
ip6b = reconstruct_ip6hdr(ip6, {ip6_last_proto=IPPROTO_ICMPV6})
|
||||
|
||||
icmpb = reconstruct_icmphdr(icmp)
|
||||
raw = bu8(icmp.icmp_type) ..
|
||||
bu8(icmp.icmp_code) ..
|
||||
bu16(0) ..
|
||||
bu32(icmp.icmp_data)
|
||||
print( raw==icmpb and "ICMP RECONSTRUCT OK" or "ICMP RECONSTRUCT FAILED" )
|
||||
test_assert(raw==icmpb)
|
||||
|
||||
raw = reconstruct_dissect({ip=ip, icmp=icmp, payload=payload})
|
||||
dis1 = dissect(raw)
|
||||
icmpb = csum_icmp_fix(ip4b,icmpb,payload)
|
||||
dis2 = dissect(ip4b..icmpb..payload)
|
||||
print( dis1.icmp.icmp_cksum==dis2.icmp.icmp_cksum and "ICMP+IP4 CSUM OK" or "ICMP+IP4 CSUM FAILED" )
|
||||
test_assert(dis1.icmp.icmp_cksum==dis2.icmp.icmp_cksum)
|
||||
|
||||
raw = reconstruct_dissect({ip6=ip6, icmp=icmp, payload=payload})
|
||||
dis1 = dissect(raw)
|
||||
icmpb = csum_icmp_fix(ip6b,icmpb,payload)
|
||||
dis2 = dissect(ip6b..icmpb..payload)
|
||||
print( dis1.icmp.icmp_cksum==dis2.icmp.icmp_cksum and "ICMP+IP6 CSUM OK" or "ICMP+IP6 CSUM FAILED" )
|
||||
test_assert(dis1.icmp.icmp_cksum==dis2.icmp.icmp_cksum)
|
||||
end
|
||||
|
||||
function test_resolve()
|
||||
print("* 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_get_source_ip(opts)
|
||||
print("* get_source_ip")
|
||||
|
||||
for k,d in ipairs({
|
||||
'127.0.0.1','192.168.1.1','10.1.1.1','1.1.1.1','255.255.255.255',
|
||||
'::1','fc81::4','2a06::1','2001:470::1','2002:0101:0101::1','::1.1.1.1'})
|
||||
do
|
||||
local src = get_source_ip(pton(d))
|
||||
print((src and ntop(src) or "?").." => "..d)
|
||||
end
|
||||
end
|
||||
function test_ifaddrs(opts)
|
||||
print("* ifaddrs")
|
||||
|
||||
local ifa = get_ifaddrs()
|
||||
test_assert(ifa)
|
||||
for ifname,ifinfo in pairs(ifa) do
|
||||
print(ifname.." index="..tostring(ifinfo.index).." mtu="..tostring(ifinfo.mtu))
|
||||
for i,addr in ipairs(ifinfo.addr) do
|
||||
print(" "..ntop(addr.addr)..(addr.netmask and " mask "..tostring(ntop(addr.netmask)) or ""))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function test_rawsend(opts)
|
||||
print("* rawsend")
|
||||
|
||||
local ifout = (opts and opts.ifout) and opts.ifout
|
||||
local function rawsend_fail_warning()
|
||||
if not opts or not opts.ifout or #opts.ifout==0 then
|
||||
@@ -595,13 +882,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()
|
||||
@@ -626,15 +913,30 @@ function test_rawsend(opts)
|
||||
local payload = brandom(math.random(100,1200))
|
||||
local b
|
||||
|
||||
local target
|
||||
for ifname,ifinfo in pairs(get_ifaddrs()) do
|
||||
for k,v in pairs(ifinfo.addr) do
|
||||
if #v.addr==4 and string.sub(v.addr,1,2)=="\xC0\xA8" then
|
||||
target = string.sub(v.addr,1,3)..bu8(u8add(u8(v.addr,4),1))
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
target = target or pton("192.168.254.32")
|
||||
print("ipv4 target is "..ntop(target))
|
||||
ip = {
|
||||
ip_tos = 0,
|
||||
ip_id = math.random(0,0xFFFF),
|
||||
ip_off = 0,
|
||||
ip_ttl = 1,
|
||||
ip_p = IPPROTO_UDP,
|
||||
ip_src = pton("192.168.1.1"),
|
||||
ip_dst = pton("192.168.1.2")
|
||||
ip_src = get_source_ip(target),
|
||||
ip_dst = target
|
||||
}
|
||||
if not ip.ip_src then
|
||||
print("dest "..ntop(target).." unreachable")
|
||||
test_assert(false)
|
||||
end
|
||||
udp = {
|
||||
uh_sport = math.random(0,0xFFFF),
|
||||
uh_dport = math.random(0,0xFFFF)
|
||||
@@ -657,18 +959,42 @@ function test_rawsend(opts)
|
||||
print("send ipv4 udp using pure rawsend without dissect")
|
||||
test_assert(rawsend_print(raw, {repeats=5}))
|
||||
|
||||
local target
|
||||
for ifname,ifinfo in pairs(get_ifaddrs()) do
|
||||
for k,v in pairs(ifinfo.addr) do
|
||||
if #v.addr==16 and (string.sub(v.addr,1,1)=="\xFC" or string.sub(v.addr,1,1)=="\xFD") then
|
||||
target = string.sub(v.addr,1,1)..bu8(u8add(u8(v.addr,2),1))..string.sub(v.addr,3)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
target = target or pton("fdce:3124:164a:5318::2")
|
||||
print("ipv6 target is "..ntop(target))
|
||||
ip6 = {
|
||||
ip6_flow = 0x60000000,
|
||||
ip6_hlim = 1,
|
||||
ip6_src = pton("fdce:3124:164a:5318::1"),
|
||||
ip6_dst = pton("fdce:3124:164a:5318::2")
|
||||
ip6_src = get_source_ip(target),
|
||||
ip6_dst = target
|
||||
}
|
||||
if not ip6.ip6_src then
|
||||
print("dest "..ntop(target).." unreachable")
|
||||
test_assert(false)
|
||||
end
|
||||
dis = {ip6 = ip6, udp = udp, payload = payload}
|
||||
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
|
||||
@@ -678,27 +1004,67 @@ 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
|
||||
|
||||
table.insert(ip6.exthdr, { type = IPPROTO_DSTOPTS, data = "\x00\x00\x00\x00\x00\x00" })
|
||||
table.insert(ip6.exthdr, { type = IPPROTO_DSTOPTS, data = "\x00\x00\x00\x00\x00\x00" })
|
||||
ip6.ip6_flow = 0x60001234;
|
||||
insert_ip6_exthdr(ip6, nil, IPPROTO_DSTOPTS, "\x00\x00\x00\x00\x00\x00")
|
||||
insert_ip6_exthdr(ip6, nil, IPPROTO_DSTOPTS, "\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
|
||||
|
||||
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
|
||||
fix_ip_proto(dis) -- ip6_preserve_next requires next fields in ip6.exthdr
|
||||
ip6.ip6_flow = 0x6000AE38
|
||||
ddis = ipfrag2(dis, {ipfrag_pos_udp = 72, ipfrag_next = IPPROTO_TCP})
|
||||
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
|
||||
test_assert(rawsend_dissect_print(d, {fwmark = 0x409A, repeats=2}, {ip6_preserve_next = true}))
|
||||
end
|
||||
|
||||
local icmp = {
|
||||
icmp_type = ICMP_ECHO, icmp_code=0,
|
||||
icmp_data = u32(bu16(math.random(1,0xFFFF))..bu16(1))
|
||||
}
|
||||
ip.ip_p = IPPROTO_ICMP
|
||||
payload=brandom_az09(math.random(10,1100))
|
||||
dis = {ip = ip, icmp = icmp, payload = payload}
|
||||
print("send ipv4 icmp")
|
||||
test_assert(rawsend_dissect_print(dis, {fwmark = 0xD133, repeats=3}))
|
||||
|
||||
ip6.exthdr={{ type = IPPROTO_HOPOPTS, data = "\x00\x00\x00\x00\x00\x00" }}
|
||||
ip6.ip6_flow=0x60009E3B
|
||||
icmp.icmp_type = ICMP6_ECHO_REQUEST
|
||||
dis = {ip6 = ip6, icmp = icmp, payload = payload}
|
||||
print("send ipv6 icmp")
|
||||
test_assert(rawsend_dissect_print(dis, {fwmark = 0x8E10, repeats=3}))
|
||||
|
||||
local ip2 = {
|
||||
ip_tos = 0,
|
||||
ip_id = math.random(0,0xFFFF),
|
||||
ip_off = 0,
|
||||
ip_ttl = 64,
|
||||
ip_p = IPPROTO_UDP,
|
||||
ip_src = pton("10.1.1.1"),
|
||||
ip_dst = pton("10.1.1.2"),
|
||||
}
|
||||
|
||||
dis = {ip = ip2, udp = udp, payload = payload}
|
||||
raw_udp = reconstruct_dissect(dis)
|
||||
|
||||
ip6.ip6_flow=0x6000583F
|
||||
dis = {ip6 = ip6, payload = raw_udp}
|
||||
print("send ipv6 ipip")
|
||||
test_assert(rawsend_dissect_print(dis, {fwmark = 0x8E10, repeats=3}, {ip6_last_proto=IPPROTO_IPIP}))
|
||||
|
||||
dis = {ip = ip, payload = raw_udp}
|
||||
dis.ip.ip_p = IPPROTO_IPIP
|
||||
print("send ipv4 ipip")
|
||||
test_assert(rawsend_dissect_print(dis, {fwmark = 0x8E10, repeats=3}, {ip6_last_proto=IPPROTO_IPIP}))
|
||||
end
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
-- test case : --in-range=a --out-range=a --lua-desync=wgobfs:secret=mycoolpassword
|
||||
-- encrypt standard wireguard messages - initiation, response, cookie - and change udp packet size
|
||||
-- do not encrypt data messages and keepalives
|
||||
-- wgobfs adds maximum of 30+padmax bytes to udp size
|
||||
-- reduce MTU of wireguard interface to avoid ip fragmentation !
|
||||
-- without knowing the secret encrypted packets should be crypto strong white noise with no signature
|
||||
-- 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
|
||||
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
|
||||
local function genkey()
|
||||
-- cache key in a global var bound to instance name
|
||||
local key_cache_name = desync.func_instance.."_key"
|
||||
key = _G[key_cache_name]
|
||||
if not key then
|
||||
key = hkdf("sha256", "wgobfs_salt", desync.arg.secret, nil, 16)
|
||||
_G[key_cache_name] = key
|
||||
end
|
||||
return key
|
||||
end
|
||||
local function maybe_encrypted_payload(payload)
|
||||
for k,plsize in pairs({2+12+16+148, 2+12+16+92, 2+12+16+64}) do
|
||||
if #payload>=(plsize+padmin) and #payload<=(plsize+padmax) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
local function wg_payload_from_size(payload)
|
||||
if #payload==148 then return "wireguard_initiation"
|
||||
elseif #payload==92 then return "wireguard_response"
|
||||
elseif #payload==64 then return "wireguard_cookie"
|
||||
else return nil
|
||||
end
|
||||
end
|
||||
|
||||
if not desync.dis.udp then
|
||||
instance_cutoff(ctx)
|
||||
return
|
||||
end
|
||||
if not desync.arg.secret or #desync.arg.secret==0 then
|
||||
error("wgobfs requires secret")
|
||||
end
|
||||
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
|
||||
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
|
||||
-- encrypting more than one message with the same iv is considered catastrophic failure
|
||||
-- iv must be sent with encrypted message
|
||||
local iv = bcryptorandom(12)
|
||||
local encrypted, atag = aes_gcm(true, key, iv, bu16(#desync.dis.payload)..desync.dis.payload..brandom(math.random(padmin,padmax)), nil)
|
||||
desync.dis.payload = iv..atag..encrypted
|
||||
return VERDICT_MODIFY
|
||||
end
|
||||
|
||||
if desync.l7payload=="unknown" and maybe_encrypted_payload(desync.dis.payload) then
|
||||
local key = genkey()
|
||||
local iv = string.sub(desync.dis.payload,1,12)
|
||||
local atag = string.sub(desync.dis.payload,13,28)
|
||||
local decrypted, atag2 = aes_gcm(false, key, iv, string.sub(desync.dis.payload,29))
|
||||
if atag==atag2 then
|
||||
local plen = u16(decrypted)
|
||||
if plen>(#decrypted-2) then
|
||||
DLOG("wgobfs: bad decrypted payload data")
|
||||
else
|
||||
desync.dis.payload = string.sub(decrypted, 3, 3+plen-1)
|
||||
if b_debug then DLOG("wgobfs: decrypted '"..(wg_payload_from_size(desync.dis.payload) or "unknown").."' message. size "..plen) end
|
||||
return VERDICT_MODIFY
|
||||
end
|
||||
else
|
||||
DLOG("wgobfs: decrypt auth tag mismatch")
|
||||
end
|
||||
end
|
||||
end
|
||||
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
|
||||
@@ -14,7 +15,7 @@ LUA_PKG:=luajit
|
||||
|
||||
.else
|
||||
|
||||
LUA_VER ?= 5.4
|
||||
LUA_VER ?= 5.5
|
||||
LUA_VER_UNDOTTED!= echo $(LUA_VER) | sed 's/\.//g'
|
||||
|
||||
OSNAME!=uname
|
||||
@@ -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,6 +1,8 @@
|
||||
CC ?= cc
|
||||
PKG_CONFIG ?= pkg-config
|
||||
OPTIMIZE ?= -Os
|
||||
CFLAGS += -std=gnu99 $(OPTIMIZE) -flto=auto
|
||||
CFLAGS_LINUX = -Wno-alloc-size-larger-than
|
||||
CFLAGS_SYSTEMD = -DUSE_SYSTEMD
|
||||
CFLAGS_BSD = -Wno-address-of-packed-member
|
||||
CFLAGS_CYGWIN = -Wno-address-of-packed-member -static
|
||||
@@ -9,13 +11,13 @@ LIBS =
|
||||
LIBS_LINUX = -lz -lnetfilter_queue -lnfnetlink -lmnl -lm
|
||||
LIBS_SYSTEMD = -lsystemd
|
||||
LIBS_BSD = -lz -lm
|
||||
LIBS_CYGWIN = -lz -Lwindows/windivert -Iwindows -lwlanapi -lole32 -loleaut32
|
||||
LIBS_CYGWIN = -lz -Lwindows/windivert -Iwindows -lwlanapi -lole32 -loleaut32 -liphlpapi -lntdll
|
||||
LIBS_CYGWIN32 = -lwindivert32
|
||||
LIBS_CYGWIN64 = -lwindivert64
|
||||
RES_CYGWIN32 = windows/res/32/winmanifest.o windows/res/32/winicon.o
|
||||
RES_CYGWIN64 = windows/res/64/winmanifest.o windows/res/64/winicon.o
|
||||
RES_CYGWIN32 = windows/res/winws_res32.o
|
||||
RES_CYGWIN64 = windows/res/winws_res64.o
|
||||
SRC_FILES = *.c crypto/*.c
|
||||
|
||||
SRC_FILES_ANDROID = $(SRC_FILES) andr/*.c
|
||||
|
||||
LUA_JIT?=1
|
||||
|
||||
@@ -29,13 +31,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),)
|
||||
@@ -72,7 +74,7 @@ ifeq ($(LUA_LIB),)
|
||||
|
||||
# no success with luajit
|
||||
|
||||
LUA_VER?=5.4
|
||||
LUA_VER?=5.5
|
||||
LUA_VER_UNDOTTED:=$(shell echo $(LUA_VER) | sed 's/\.//g')
|
||||
|
||||
LUA_CFL :=
|
||||
@@ -87,13 +89,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)
|
||||
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) -I/usr/local/include/lua -I/usr/local/include
|
||||
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).*),)
|
||||
@@ -131,13 +133,13 @@ LUA_CFL += $(LUA_CFLAGS)
|
||||
all: nfqws2
|
||||
|
||||
nfqws2: $(SRC_FILES)
|
||||
$(CC) -s $(CFLAGS) $(LUA_CFL) -o nfqws2 $(SRC_FILES) $(LIBS) $(LUA_LIB) $(LIBS_LINUX) $(LDFLAGS)
|
||||
$(CC) -s $(CFLAGS) $(LUA_CFL) $(CFLAGS_LINUX) -o nfqws2 $(SRC_FILES) $(LIBS) $(LUA_LIB) $(LIBS_LINUX) $(LDFLAGS)
|
||||
|
||||
systemd: $(SRC_FILES)
|
||||
$(CC) -s $(CFLAGS) $(LUA_CFL) $(CFLAGS_SYSTEMD) -o nfqws2 $(SRC_FILES) $(LIBS) $(LUA_LIB) $(LIBS_LINUX) $(LIBS_SYSTEMD) $(LDFLAGS)
|
||||
$(CC) -s $(CFLAGS) $(LUA_CFL) $(CFLAGS_LINUX) $(CFLAGS_SYSTEMD) -o nfqws2 $(SRC_FILES) $(LIBS) $(LUA_LIB) $(LIBS_LINUX) $(LIBS_SYSTEMD) $(LDFLAGS)
|
||||
|
||||
android: $(SRC_FILES)
|
||||
$(CC) -s $(CFLAGS) $(LUA_CFL) -o nfqws2 $(SRC_FILES) $(LIBS) $(LUA_LIB) $(LIBS_LINUX) $(LDFLAGS) $(LDFLAGS_ANDROID)
|
||||
android: $(SRC_FILES_ANDROID)
|
||||
$(CC) -s $(CFLAGS) $(LUA_CFL) -o nfqws2 $(SRC_FILES_ANDROID) $(LIBS) $(LUA_LIB) $(LIBS_LINUX) $(LDFLAGS) $(LDFLAGS_ANDROID)
|
||||
|
||||
bsd: $(SRC_FILES)
|
||||
$(CC) -s $(CFLAGS) $(LUA_CFL) $(CFLAGS_BSD) -o dvtws2 $(SRC_FILES) $(LIBS) $(LUA_LIB) $(LIBS_BSD) $(LDFLAGS)
|
||||
|
||||
216
nfq2/andr/getifaddrs.c
Normal file
216
nfq2/andr/getifaddrs.c
Normal file
@@ -0,0 +1,216 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <syscall.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#include "netlink.h"
|
||||
|
||||
#define IFADDRS_HASH_SIZE 64
|
||||
|
||||
/* getifaddrs() reports hardware addresses with PF_PACKET that implies
|
||||
* struct sockaddr_ll. But e.g. Infiniband socket address length is
|
||||
* longer than sockaddr_ll.ssl_addr[8] can hold. Use this hack struct
|
||||
* to extend ssl_addr - callers should be able to still use it. */
|
||||
struct sockaddr_ll_hack {
|
||||
unsigned short sll_family, sll_protocol;
|
||||
int sll_ifindex;
|
||||
unsigned short sll_hatype;
|
||||
unsigned char sll_pkttype, sll_halen;
|
||||
unsigned char sll_addr[24];
|
||||
};
|
||||
|
||||
union sockany {
|
||||
struct sockaddr sa;
|
||||
struct sockaddr_ll_hack ll;
|
||||
struct sockaddr_in v4;
|
||||
struct sockaddr_in6 v6;
|
||||
};
|
||||
|
||||
struct ifaddrs_storage {
|
||||
struct ifaddrs ifa;
|
||||
struct ifaddrs_storage *hash_next;
|
||||
union sockany addr, netmask, ifu;
|
||||
unsigned int index;
|
||||
char name[IFNAMSIZ+1];
|
||||
};
|
||||
|
||||
struct ifaddrs_ctx {
|
||||
struct ifaddrs *first;
|
||||
struct ifaddrs *last;
|
||||
struct ifaddrs_storage *hash[IFADDRS_HASH_SIZE];
|
||||
};
|
||||
|
||||
void freeifaddrs(struct ifaddrs *ifp)
|
||||
{
|
||||
struct ifaddrs *n;
|
||||
while (ifp) {
|
||||
n = ifp->ifa_next;
|
||||
free(ifp);
|
||||
ifp = n;
|
||||
}
|
||||
}
|
||||
|
||||
static void copy_addr(struct sockaddr **r, int af, union sockany *sa, void *addr, size_t addrlen, int ifindex)
|
||||
{
|
||||
uint8_t *dst;
|
||||
int len;
|
||||
|
||||
switch (af) {
|
||||
case AF_INET:
|
||||
dst = (uint8_t*) &sa->v4.sin_addr;
|
||||
len = 4;
|
||||
break;
|
||||
case AF_INET6:
|
||||
dst = (uint8_t*) &sa->v6.sin6_addr;
|
||||
len = 16;
|
||||
if (IN6_IS_ADDR_LINKLOCAL(addr) || IN6_IS_ADDR_MC_LINKLOCAL(addr))
|
||||
sa->v6.sin6_scope_id = ifindex;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
if (addrlen < len) return;
|
||||
sa->sa.sa_family = af;
|
||||
memcpy(dst, addr, len);
|
||||
*r = &sa->sa;
|
||||
}
|
||||
|
||||
static void gen_netmask(struct sockaddr **r, int af, union sockany *sa, int prefixlen)
|
||||
{
|
||||
uint8_t addr[16] = {0};
|
||||
int i;
|
||||
|
||||
if (prefixlen > 8*sizeof(addr)) prefixlen = 8*sizeof(addr);
|
||||
i = prefixlen / 8;
|
||||
memset(addr, 0xff, i);
|
||||
if (i < sizeof(addr)) addr[i++] = 0xff << (8 - (prefixlen % 8));
|
||||
copy_addr(r, af, sa, addr, sizeof(addr), 0);
|
||||
}
|
||||
|
||||
static void copy_lladdr(struct sockaddr **r, union sockany *sa, void *addr, size_t addrlen, int ifindex, unsigned short hatype)
|
||||
{
|
||||
if (addrlen > sizeof(sa->ll.sll_addr)) return;
|
||||
sa->ll.sll_family = AF_PACKET;
|
||||
sa->ll.sll_ifindex = ifindex;
|
||||
sa->ll.sll_hatype = hatype;
|
||||
sa->ll.sll_halen = addrlen;
|
||||
memcpy(sa->ll.sll_addr, addr, addrlen);
|
||||
*r = &sa->sa;
|
||||
}
|
||||
|
||||
static int netlink_msg_to_ifaddr(void *pctx, struct nlmsghdr *h)
|
||||
{
|
||||
struct ifaddrs_ctx *ctx = pctx;
|
||||
struct ifaddrs_storage *ifs, *ifs0;
|
||||
struct ifinfomsg *ifi = NLMSG_DATA(h);
|
||||
struct ifaddrmsg *ifa = NLMSG_DATA(h);
|
||||
struct rtattr *rta;
|
||||
int stats_len = 0;
|
||||
|
||||
if (h->nlmsg_type == RTM_NEWLINK) {
|
||||
for (rta = NLMSG_RTA(h, sizeof(*ifi)); NLMSG_RTAOK(rta, h); rta = RTA_NEXT(rta)) {
|
||||
if (rta->rta_type != IFLA_STATS) continue;
|
||||
stats_len = RTA_DATALEN(rta);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
for (ifs0 = ctx->hash[ifa->ifa_index % IFADDRS_HASH_SIZE]; ifs0; ifs0 = ifs0->hash_next)
|
||||
if (ifs0->index == ifa->ifa_index)
|
||||
break;
|
||||
if (!ifs0) return 0;
|
||||
}
|
||||
|
||||
ifs = calloc(1, sizeof(struct ifaddrs_storage) + stats_len);
|
||||
if (ifs == 0) return -1;
|
||||
|
||||
if (h->nlmsg_type == RTM_NEWLINK) {
|
||||
ifs->index = ifi->ifi_index;
|
||||
ifs->ifa.ifa_flags = ifi->ifi_flags;
|
||||
|
||||
for (rta = NLMSG_RTA(h, sizeof(*ifi)); NLMSG_RTAOK(rta, h); rta = RTA_NEXT(rta)) {
|
||||
switch (rta->rta_type) {
|
||||
case IFLA_IFNAME:
|
||||
if (RTA_DATALEN(rta) < sizeof(ifs->name)) {
|
||||
memcpy(ifs->name, RTA_DATA(rta), RTA_DATALEN(rta));
|
||||
ifs->ifa.ifa_name = ifs->name;
|
||||
}
|
||||
break;
|
||||
case IFLA_ADDRESS:
|
||||
copy_lladdr(&ifs->ifa.ifa_addr, &ifs->addr, RTA_DATA(rta), RTA_DATALEN(rta), ifi->ifi_index, ifi->ifi_type);
|
||||
break;
|
||||
case IFLA_BROADCAST:
|
||||
copy_lladdr(&ifs->ifa.ifa_broadaddr, &ifs->ifu, RTA_DATA(rta), RTA_DATALEN(rta), ifi->ifi_index, ifi->ifi_type);
|
||||
break;
|
||||
case IFLA_STATS:
|
||||
ifs->ifa.ifa_data = (void*)(ifs+1);
|
||||
memcpy(ifs->ifa.ifa_data, RTA_DATA(rta), RTA_DATALEN(rta));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ifs->ifa.ifa_name) {
|
||||
unsigned int bucket = ifs->index % IFADDRS_HASH_SIZE;
|
||||
ifs->hash_next = ctx->hash[bucket];
|
||||
ctx->hash[bucket] = ifs;
|
||||
}
|
||||
} else {
|
||||
ifs->ifa.ifa_name = ifs0->ifa.ifa_name;
|
||||
ifs->ifa.ifa_flags = ifs0->ifa.ifa_flags;
|
||||
for (rta = NLMSG_RTA(h, sizeof(*ifa)); NLMSG_RTAOK(rta, h); rta = RTA_NEXT(rta)) {
|
||||
switch (rta->rta_type) {
|
||||
case IFA_ADDRESS:
|
||||
/* If ifa_addr is already set we, received an IFA_LOCAL before
|
||||
* so treat this as destination address */
|
||||
if (ifs->ifa.ifa_addr)
|
||||
copy_addr(&ifs->ifa.ifa_dstaddr, ifa->ifa_family, &ifs->ifu, RTA_DATA(rta), RTA_DATALEN(rta), ifa->ifa_index);
|
||||
else
|
||||
copy_addr(&ifs->ifa.ifa_addr, ifa->ifa_family, &ifs->addr, RTA_DATA(rta), RTA_DATALEN(rta), ifa->ifa_index);
|
||||
break;
|
||||
case IFA_BROADCAST:
|
||||
copy_addr(&ifs->ifa.ifa_broadaddr, ifa->ifa_family, &ifs->ifu, RTA_DATA(rta), RTA_DATALEN(rta), ifa->ifa_index);
|
||||
break;
|
||||
case IFA_LOCAL:
|
||||
/* If ifa_addr is set and we get IFA_LOCAL, assume we have
|
||||
* a point-to-point network. Move address to correct field. */
|
||||
if (ifs->ifa.ifa_addr) {
|
||||
ifs->ifu = ifs->addr;
|
||||
ifs->ifa.ifa_dstaddr = &ifs->ifu.sa;
|
||||
memset(&ifs->addr, 0, sizeof(ifs->addr));
|
||||
}
|
||||
copy_addr(&ifs->ifa.ifa_addr, ifa->ifa_family, &ifs->addr, RTA_DATA(rta), RTA_DATALEN(rta), ifa->ifa_index);
|
||||
break;
|
||||
case IFA_LABEL:
|
||||
if (RTA_DATALEN(rta) < sizeof(ifs->name)) {
|
||||
memcpy(ifs->name, RTA_DATA(rta), RTA_DATALEN(rta));
|
||||
ifs->ifa.ifa_name = ifs->name;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ifs->ifa.ifa_addr)
|
||||
gen_netmask(&ifs->ifa.ifa_netmask, ifa->ifa_family, &ifs->netmask, ifa->ifa_prefixlen);
|
||||
}
|
||||
|
||||
if (ifs->ifa.ifa_name) {
|
||||
if (!ctx->first) ctx->first = &ifs->ifa;
|
||||
if (ctx->last) ctx->last->ifa_next = &ifs->ifa;
|
||||
ctx->last = &ifs->ifa;
|
||||
} else {
|
||||
free(ifs);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int getifaddrs(struct ifaddrs **ifap)
|
||||
{
|
||||
struct ifaddrs_ctx _ctx, *ctx = &_ctx;
|
||||
int r;
|
||||
memset(ctx, 0, sizeof *ctx);
|
||||
r = __rtnetlink_enumerate(AF_UNSPEC, AF_UNSPEC, netlink_msg_to_ifaddr, ctx);
|
||||
if (r == 0) *ifap = ctx->first;
|
||||
else freeifaddrs(ctx->first);
|
||||
return r;
|
||||
}
|
||||
8
nfq2/andr/ifaddrs.h
Normal file
8
nfq2/andr/ifaddrs.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <ifaddrs.h>
|
||||
|
||||
#if __ANDROID_API__ < 24
|
||||
void freeifaddrs(struct ifaddrs *);
|
||||
int getifaddrs(struct ifaddrs **);
|
||||
#endif
|
||||
54
nfq2/andr/netlink.c
Normal file
54
nfq2/andr/netlink.c
Normal file
@@ -0,0 +1,54 @@
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <syscall.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "netlink.h"
|
||||
|
||||
static int __netlink_enumerate(int fd, unsigned int seq, int type, int af,
|
||||
int (*cb)(void *ctx, struct nlmsghdr *h), void *ctx)
|
||||
{
|
||||
struct nlmsghdr *h;
|
||||
union {
|
||||
uint8_t buf[8192];
|
||||
struct {
|
||||
struct nlmsghdr nlh;
|
||||
struct rtgenmsg g;
|
||||
} req;
|
||||
struct nlmsghdr reply;
|
||||
} u;
|
||||
int r, ret;
|
||||
|
||||
memset(&u.req, 0, sizeof(u.req));
|
||||
u.req.nlh.nlmsg_len = sizeof(u.req);
|
||||
u.req.nlh.nlmsg_type = type;
|
||||
u.req.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
|
||||
u.req.nlh.nlmsg_seq = seq;
|
||||
u.req.g.rtgen_family = af;
|
||||
r = send(fd, &u.req, sizeof(u.req), 0);
|
||||
if (r < 0) return r;
|
||||
|
||||
while (1) {
|
||||
r = recv(fd, u.buf, sizeof(u.buf), 0);
|
||||
if (r <= 0) return -1;
|
||||
for (h = &u.reply; NLMSG_OK(h, (void*)&u.buf[r]); h = NLMSG_NEXT(h)) {
|
||||
if (h->nlmsg_type == NLMSG_DONE) return 0;
|
||||
if (h->nlmsg_type == NLMSG_ERROR) return -1;
|
||||
ret = cb(ctx, h);
|
||||
if (ret) return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int __rtnetlink_enumerate(int link_af, int addr_af, int (*cb)(void *ctx, struct nlmsghdr *h), void *ctx)
|
||||
{
|
||||
int fd, r;
|
||||
|
||||
fd = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC, NETLINK_ROUTE);
|
||||
if (fd < 0) return -1;
|
||||
r = __netlink_enumerate(fd, 1, RTM_GETLINK, link_af, cb, ctx);
|
||||
if (!r) r = __netlink_enumerate(fd, 2, RTM_GETADDR, addr_af, cb, ctx);
|
||||
close(fd);
|
||||
return r;
|
||||
}
|
||||
94
nfq2/andr/netlink.h
Normal file
94
nfq2/andr/netlink.h
Normal file
@@ -0,0 +1,94 @@
|
||||
#include <stdint.h>
|
||||
|
||||
/* linux/netlink.h */
|
||||
|
||||
#define NETLINK_ROUTE 0
|
||||
|
||||
struct nlmsghdr {
|
||||
uint32_t nlmsg_len;
|
||||
uint16_t nlmsg_type;
|
||||
uint16_t nlmsg_flags;
|
||||
uint32_t nlmsg_seq;
|
||||
uint32_t nlmsg_pid;
|
||||
};
|
||||
|
||||
#define NLM_F_REQUEST 1
|
||||
#define NLM_F_MULTI 2
|
||||
#define NLM_F_ACK 4
|
||||
|
||||
#define NLM_F_ROOT 0x100
|
||||
#define NLM_F_MATCH 0x200
|
||||
#define NLM_F_ATOMIC 0x400
|
||||
#define NLM_F_DUMP (NLM_F_ROOT|NLM_F_MATCH)
|
||||
|
||||
#define NLMSG_NOOP 0x1
|
||||
#define NLMSG_ERROR 0x2
|
||||
#define NLMSG_DONE 0x3
|
||||
#define NLMSG_OVERRUN 0x4
|
||||
|
||||
/* linux/rtnetlink.h */
|
||||
|
||||
#define RTM_NEWLINK 16
|
||||
#define RTM_GETLINK 18
|
||||
#define RTM_NEWADDR 20
|
||||
#define RTM_GETADDR 22
|
||||
|
||||
struct rtattr {
|
||||
unsigned short rta_len;
|
||||
unsigned short rta_type;
|
||||
};
|
||||
|
||||
struct rtgenmsg {
|
||||
unsigned char rtgen_family;
|
||||
};
|
||||
|
||||
struct ifinfomsg {
|
||||
unsigned char ifi_family;
|
||||
unsigned char __ifi_pad;
|
||||
unsigned short ifi_type;
|
||||
int ifi_index;
|
||||
unsigned ifi_flags;
|
||||
unsigned ifi_change;
|
||||
};
|
||||
|
||||
/* linux/if_link.h */
|
||||
|
||||
#define IFLA_ADDRESS 1
|
||||
#define IFLA_BROADCAST 2
|
||||
#define IFLA_IFNAME 3
|
||||
#define IFLA_STATS 7
|
||||
|
||||
/* linux/if_addr.h */
|
||||
|
||||
struct ifaddrmsg {
|
||||
uint8_t ifa_family;
|
||||
uint8_t ifa_prefixlen;
|
||||
uint8_t ifa_flags;
|
||||
uint8_t ifa_scope;
|
||||
uint32_t ifa_index;
|
||||
};
|
||||
|
||||
#define IFA_ADDRESS 1
|
||||
#define IFA_LOCAL 2
|
||||
#define IFA_LABEL 3
|
||||
#define IFA_BROADCAST 4
|
||||
|
||||
/* musl */
|
||||
|
||||
#define NETLINK_ALIGN(len) (((len)+3) & ~3)
|
||||
#define NLMSG_DATA(nlh) ((void*)((char*)(nlh)+sizeof(struct nlmsghdr)))
|
||||
#define NLMSG_DATALEN(nlh) ((nlh)->nlmsg_len-sizeof(struct nlmsghdr))
|
||||
#define NLMSG_DATAEND(nlh) ((char*)(nlh)+(nlh)->nlmsg_len)
|
||||
#define NLMSG_NEXT(nlh) (struct nlmsghdr*)((char*)(nlh)+NETLINK_ALIGN((nlh)->nlmsg_len))
|
||||
#define NLMSG_OK(nlh,end) ((char*)(end)-(char*)(nlh) >= sizeof(struct nlmsghdr))
|
||||
|
||||
#define RTA_DATA(rta) ((void*)((char*)(rta)+sizeof(struct rtattr)))
|
||||
#define RTA_DATALEN(rta) ((rta)->rta_len-sizeof(struct rtattr))
|
||||
#define RTA_DATAEND(rta) ((char*)(rta)+(rta)->rta_len)
|
||||
#define RTA_NEXT(rta) (struct rtattr*)((char*)(rta)+NETLINK_ALIGN((rta)->rta_len))
|
||||
#define RTA_OK(rta,end) ((char*)(end)-(char*)(rta) >= sizeof(struct rtattr))
|
||||
|
||||
#define NLMSG_RTA(nlh,len) ((void*)((char*)(nlh)+sizeof(struct nlmsghdr)+NETLINK_ALIGN(len)))
|
||||
#define NLMSG_RTAOK(rta,nlh) RTA_OK(rta,NLMSG_DATAEND(nlh))
|
||||
|
||||
int __rtnetlink_enumerate(int link_af, int addr_af, int (*cb)(void *ctx, struct nlmsghdr *h), void *ctx);
|
||||
@@ -95,10 +95,7 @@ static uint16_t do_csum(const uint8_t *buff, size_t len)
|
||||
return u16;
|
||||
}
|
||||
|
||||
uint16_t csum_partial(const void *buff, size_t len)
|
||||
{
|
||||
return do_csum(buff, len);
|
||||
}
|
||||
#define csum_partial(buff, len) do_csum((const uint8_t*)buff,len)
|
||||
|
||||
uint16_t csum_tcpudp_magic(uint32_t saddr, uint32_t daddr, size_t len, uint8_t proto, uint16_t sum)
|
||||
{
|
||||
@@ -107,7 +104,7 @@ uint16_t csum_tcpudp_magic(uint32_t saddr, uint32_t daddr, size_t len, uint8_t p
|
||||
|
||||
uint16_t ip4_compute_csum(const void *buff, size_t len)
|
||||
{
|
||||
return ~from64to16(do_csum(buff, len));
|
||||
return ~csum_partial(buff, len);
|
||||
}
|
||||
void ip4_fix_checksum(struct ip *ip)
|
||||
{
|
||||
@@ -158,3 +155,21 @@ void udp_fix_checksum(struct udphdr *udp, size_t len, const struct ip *ip, const
|
||||
else if (ip6hdr)
|
||||
udp6_fix_checksum(udp, len, &ip6hdr->ip6_src, &ip6hdr->ip6_dst);
|
||||
}
|
||||
|
||||
void icmp4_fix_checksum(struct icmp46 *icmp, size_t len)
|
||||
{
|
||||
icmp->icmp_cksum = 0;
|
||||
icmp->icmp_cksum = ~csum_partial(icmp, len);
|
||||
}
|
||||
void icmp6_fix_checksum(struct icmp46 *icmp, size_t len, const struct ip6_hdr *ip6hdr)
|
||||
{
|
||||
icmp->icmp_cksum = 0;
|
||||
icmp->icmp_cksum = csum_ipv6_magic(&ip6hdr->ip6_src, &ip6hdr->ip6_dst, len, IPPROTO_ICMPV6, csum_partial(icmp, len));
|
||||
}
|
||||
void icmp_fix_checksum(struct icmp46 *icmp, size_t len, const struct ip6_hdr *ip6hdr)
|
||||
{
|
||||
if (ip6hdr)
|
||||
icmp6_fix_checksum(icmp, len, ip6hdr);
|
||||
else
|
||||
icmp4_fix_checksum(icmp, len);
|
||||
}
|
||||
|
||||
@@ -11,7 +11,20 @@
|
||||
#include <netinet/tcp.h>
|
||||
#include <netinet/udp.h>
|
||||
|
||||
uint16_t csum_partial(const void *buff, size_t len);
|
||||
// icmp 4 and 6 are basically compatible although checksums are calculated differently
|
||||
// do not use version specific structs
|
||||
struct icmp46
|
||||
{
|
||||
uint8_t icmp_type, icmp_code;
|
||||
uint16_t icmp_cksum;
|
||||
union
|
||||
{
|
||||
uint32_t icmp_data32;
|
||||
uint16_t icmp_data16[2];
|
||||
uint8_t icmp_data8[4];
|
||||
};
|
||||
};
|
||||
|
||||
uint16_t csum_tcpudp_magic(uint32_t saddr, uint32_t daddr, size_t len, uint8_t proto, uint16_t sum);
|
||||
uint16_t csum_ipv6_magic(const void *saddr, const void *daddr, size_t len, uint8_t proto, uint16_t sum);
|
||||
|
||||
@@ -25,3 +38,7 @@ void tcp_fix_checksum(struct tcphdr *tcp,size_t len,const struct ip *ip,const st
|
||||
void udp4_fix_checksum(struct udphdr *udp,size_t len, const struct in_addr *src_addr, const struct in_addr *dest_addr);
|
||||
void udp6_fix_checksum(struct udphdr *udp,size_t len, const struct in6_addr *src_addr, const struct in6_addr *dest_addr);
|
||||
void udp_fix_checksum(struct udphdr *udp,size_t len,const struct ip *ip,const struct ip6_hdr *ip6hdr);
|
||||
|
||||
void icmp4_fix_checksum(struct icmp46 *icmp, size_t len);
|
||||
void icmp6_fix_checksum(struct icmp46 *icmp, size_t len, const struct ip6_hdr *ip6hdr);
|
||||
void icmp_fix_checksum(struct icmp46 *icmp, size_t len, const struct ip6_hdr *ip6hdr);
|
||||
|
||||
@@ -70,7 +70,7 @@ void ConntrackPoolInit(t_conntrack *p, time_t purge_interval, uint32_t timeout_s
|
||||
p->pool = NULL;
|
||||
}
|
||||
|
||||
void ConntrackExtractConn(t_conn *c, bool bReverse, const struct dissect *dis)
|
||||
bool ConntrackExtractConn(t_conn *c, bool bReverse, const struct dissect *dis)
|
||||
{
|
||||
memset(c, 0, sizeof(*c));
|
||||
if (dis->ip)
|
||||
@@ -86,8 +86,9 @@ void ConntrackExtractConn(t_conn *c, bool bReverse, const struct dissect *dis)
|
||||
c->src.ip6 = bReverse ? dis->ip6->ip6_dst : dis->ip6->ip6_src;
|
||||
}
|
||||
else
|
||||
c->l3proto = -1;
|
||||
return false;
|
||||
extract_ports(dis->tcp, dis->udp, &c->l4proto, bReverse ? &c->dport : &c->sport, bReverse ? &c->sport : &c->dport);
|
||||
return c->l4proto!=IPPROTO_NONE;
|
||||
}
|
||||
|
||||
|
||||
@@ -102,7 +103,7 @@ static void ConntrackInitTrack(t_ctrack *t)
|
||||
{
|
||||
memset(t, 0, sizeof(*t));
|
||||
t->l7proto = L7_UNKNOWN;
|
||||
t->pos.client.scale = t->pos.server.scale = SCALE_NONE;
|
||||
t->pos.client.scale = t->pos.server.scale = 0;
|
||||
rawpacket_queue_init(&t->delayed);
|
||||
lua_newtable(params.L);
|
||||
t->lua_state = luaL_ref(params.L, LUA_REGISTRYINDEX);
|
||||
@@ -139,7 +140,7 @@ static void ConntrackApplyPos(t_ctrack *t, bool bReverse, const struct dissect *
|
||||
if (dis->ip6) direct->ip6flow = ntohl(dis->ip6->ip6_ctlun.ip6_un1.ip6_un1_flow);
|
||||
|
||||
scale = tcp_find_scale_factor(dis->tcp);
|
||||
mss = ntohs(tcp_find_mss(dis->tcp));
|
||||
mss = tcp_find_mss(dis->tcp);
|
||||
|
||||
direct->seq_last = ntohl(dis->tcp->th_seq);
|
||||
direct->pos = direct->seq_last + dis->len_payload;
|
||||
@@ -152,11 +153,10 @@ static void ConntrackApplyPos(t_ctrack *t, bool bReverse, const struct dissect *
|
||||
if (!((direct->pos - direct->uppos) & 0x80000000))
|
||||
direct->uppos = direct->pos;
|
||||
}
|
||||
direct->winsize = ntohs(dis->tcp->th_win);
|
||||
direct->winsize_calc = direct->winsize;
|
||||
direct->winsize_calc = direct->winsize = ntohs(dis->tcp->th_win);
|
||||
if (scale != SCALE_NONE) direct->scale = scale;
|
||||
if (direct->scale != SCALE_NONE) direct->winsize_calc <<= direct->scale;
|
||||
if (mss && !direct->mss) direct->mss = mss;
|
||||
if (scale != SCALE_NONE) direct->scale = scale;
|
||||
|
||||
if (!direct->rseq_over_2G && ((direct->seq_last - direct->seq0) & 0x80000000))
|
||||
direct->rseq_over_2G = true;
|
||||
@@ -225,7 +225,7 @@ static bool ConntrackPoolDoubleSearchPool(t_conntrack_pool **pp, const struct di
|
||||
t_conn conn, connswp;
|
||||
t_conntrack_pool *ctr;
|
||||
|
||||
ConntrackExtractConn(&conn, false, dis);
|
||||
if (!ConntrackExtractConn(&conn, false, dis)) return false;
|
||||
if ((ctr = ConntrackPoolSearch(*pp, &conn)))
|
||||
{
|
||||
if (bReverse) *bReverse = false;
|
||||
@@ -256,7 +256,7 @@ static bool ConntrackPoolFeedPool(t_conntrack_pool **pp, const struct dissect *d
|
||||
bool b_rev;
|
||||
uint8_t proto = dis->tcp ? IPPROTO_TCP : dis->udp ? IPPROTO_UDP : IPPROTO_NONE;
|
||||
|
||||
ConntrackExtractConn(&conn, false, dis);
|
||||
if (!ConntrackExtractConn(&conn, false, dis)) return false;
|
||||
if ((ctr = ConntrackPoolSearch(*pp, &conn)))
|
||||
{
|
||||
ConntrackFeedPacket(&ctr->track, (b_rev = false), dis);
|
||||
@@ -296,7 +296,7 @@ static bool ConntrackPoolDropPool(t_conntrack_pool **pp, const struct dissect *d
|
||||
{
|
||||
t_conn conn, connswp;
|
||||
t_conntrack_pool *t;
|
||||
ConntrackExtractConn(&conn, false, dis);
|
||||
if (!ConntrackExtractConn(&conn, false, dis)) return false;
|
||||
if (!(t = ConntrackPoolSearch(*pp, &conn)))
|
||||
{
|
||||
connswap(&conn, &connswp);
|
||||
@@ -371,7 +371,7 @@ void ConntrackPoolDump(const t_conntrack *p)
|
||||
t->track.pos.client.seq_last, t->track.pos.client.pos,
|
||||
t->track.pos.server.seq_last, t->track.pos.server.pos);
|
||||
printf(" req_retrans=%u cutoff=%u lua_in_cutoff=%u lua_out_cutoff=%u hostname=%s l7proto=%s\n",
|
||||
t->track.req_retrans_counter, t->track.b_cutoff, t->track.b_lua_in_cutoff, t->track.b_lua_out_cutoff, t->track.hostname, l7proto_str(t->track.l7proto));
|
||||
t->track.req_retrans_counter, t->track.b_cutoff, t->track.b_lua_in_cutoff, t->track.b_lua_out_cutoff, t->track.hostname ? t->track.hostname : "", l7proto_str(t->track.l7proto));
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -105,7 +105,7 @@ bool ConntrackPoolFeed(t_conntrack *p, const struct dissect *dis, t_ctrack **ctr
|
||||
// do not create, do not update. only find existing
|
||||
bool ConntrackPoolDoubleSearch(t_conntrack *p, const struct dissect *dis, t_ctrack **ctrack, bool *bReverse);
|
||||
bool ConntrackPoolDrop(t_conntrack *p, const struct dissect *dis);
|
||||
void ConntrackExtractConn(t_conn *c, bool bReverse, const struct dissect *dis);
|
||||
bool ConntrackExtractConn(t_conn *c, bool bReverse, const struct dissect *dis);
|
||||
void ConntrackPoolDump(const t_conntrack *p);
|
||||
void ConntrackPoolPurge(t_conntrack *p);
|
||||
void ConntrackClearHostname(t_ctrack *track);
|
||||
|
||||
@@ -103,9 +103,6 @@ int hkdfExtract(SHAversion whichSha,
|
||||
salt_len = USHAHashSize(whichSha);
|
||||
memset(nullSalt, '\0', salt_len);
|
||||
}
|
||||
else if (salt_len < 0) {
|
||||
return shaBadParam;
|
||||
}
|
||||
return hmac(whichSha, ikm, ikm_len, salt, salt_len, prk);
|
||||
}
|
||||
|
||||
@@ -154,11 +151,7 @@ int hkdfExpand(SHAversion whichSha, const uint8_t prk[], size_t prk_len,
|
||||
info = (const unsigned char *)"";
|
||||
info_len = 0;
|
||||
}
|
||||
else if (info_len < 0) {
|
||||
return shaBadParam;
|
||||
}
|
||||
if (okm_len <= 0) return shaBadParam;
|
||||
if (!okm) return shaBadParam;
|
||||
if (!okm || !okm_len) return shaBadParam;
|
||||
|
||||
hash_len = USHAHashSize(whichSha);
|
||||
if (prk_len < hash_len) return shaBadParam;
|
||||
|
||||
515
nfq2/darkmagic.c
515
nfq2/darkmagic.c
@@ -33,6 +33,8 @@
|
||||
#define ERROR_INVALID_IMAGE_HASH __MSABI_LONG(577)
|
||||
#endif
|
||||
|
||||
#include "nthacks.h"
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
@@ -51,11 +53,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 +77,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);
|
||||
@@ -94,7 +86,7 @@ uint8_t tcp_find_scale_factor(const struct tcphdr *tcp)
|
||||
uint16_t tcp_find_mss(const struct tcphdr *tcp)
|
||||
{
|
||||
uint8_t *t = tcp_find_option((struct tcphdr *)tcp, TCP_KIND_MSS);
|
||||
return (t && t[1]==4) ? *(uint16_t*)(t+2) : 0;
|
||||
return (t && t[1]==4) ? pntoh16(t+2) : 0;
|
||||
}
|
||||
bool tcp_synack_segment(const struct tcphdr *tcphdr)
|
||||
{
|
||||
@@ -108,11 +100,11 @@ bool tcp_syn_segment(const struct tcphdr *tcphdr)
|
||||
}
|
||||
|
||||
|
||||
void extract_ports(const struct tcphdr *tcphdr, const struct udphdr *udphdr, uint8_t *proto, uint16_t *sport, uint16_t *dport)
|
||||
void extract_ports(const struct tcphdr *tcphdr, const struct udphdr *udphdr,uint8_t *proto, uint16_t *sport, uint16_t *dport)
|
||||
{
|
||||
if (sport) *sport = htons(tcphdr ? tcphdr->th_sport : udphdr ? udphdr->uh_sport : 0);
|
||||
if (dport) *dport = htons(tcphdr ? tcphdr->th_dport : udphdr ? udphdr->uh_dport : 0);
|
||||
if (proto) *proto = tcphdr ? IPPROTO_TCP : udphdr ? IPPROTO_UDP : -1;
|
||||
if (proto) *proto = tcphdr ? IPPROTO_TCP : udphdr ? IPPROTO_UDP : IPPROTO_NONE;
|
||||
}
|
||||
|
||||
bool extract_dst(const uint8_t *data, size_t len, struct sockaddr* dst)
|
||||
@@ -184,6 +176,11 @@ void extract_endpoints(const struct ip *ip,const struct ip6_hdr *ip6hdr,const st
|
||||
si->sin6_scope_id = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
memset(src,0,sizeof(*src));
|
||||
memset(dst,0,sizeof(*dst));
|
||||
}
|
||||
}
|
||||
|
||||
const char *proto_name(uint8_t proto)
|
||||
@@ -202,8 +199,6 @@ const char *proto_name(uint8_t proto)
|
||||
return "igmp";
|
||||
case IPPROTO_ESP:
|
||||
return "esp";
|
||||
case IPPROTO_AH:
|
||||
return "ah";
|
||||
case IPPROTO_IPV6:
|
||||
return "6in4";
|
||||
case IPPROTO_IPIP:
|
||||
@@ -220,7 +215,7 @@ const char *proto_name(uint8_t proto)
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
static void str_proto_name(char *s, size_t s_len, uint8_t proto)
|
||||
void str_proto_name(char *s, size_t s_len, uint8_t proto)
|
||||
{
|
||||
const char *name = proto_name(proto);
|
||||
if (name)
|
||||
@@ -238,6 +233,56 @@ uint16_t family_from_proto(uint8_t l3proto)
|
||||
}
|
||||
}
|
||||
|
||||
const char *icmp_type_name(bool v6, uint8_t type)
|
||||
{
|
||||
if (v6)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case ICMP6_ECHO_REQUEST: return "echo_req6";
|
||||
case ICMP6_ECHO_REPLY: return "echo_reply6";
|
||||
case ICMP6_DST_UNREACH: return "dest_unreach6";
|
||||
case ICMP6_PACKET_TOO_BIG: return "packet_too_big";
|
||||
case ICMP6_TIME_EXCEEDED: return "time_exceeded6";
|
||||
case ICMP6_PARAM_PROB: return "param_problem6";
|
||||
case MLD_LISTENER_QUERY: return "mld_listener_query";
|
||||
case MLD_LISTENER_REPORT: return "mld_listener_report";
|
||||
case MLD_LISTENER_REDUCTION: return "mld_listener_reduction";
|
||||
case ND_ROUTER_SOLICIT: return "router_sol";
|
||||
case ND_ROUTER_ADVERT: return "router_adv";
|
||||
case ND_NEIGHBOR_SOLICIT: return "neigh_sol";
|
||||
case ND_NEIGHBOR_ADVERT: return "neigh_adv";
|
||||
case ND_REDIRECT: return "redirect6";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case ICMP_ECHOREPLY: return "echo_reply";
|
||||
case ICMP_DEST_UNREACH: return "dest_unreach";
|
||||
case ICMP_REDIRECT: return "redirect";
|
||||
case ICMP_ECHO: return "echo_req";
|
||||
case ICMP_TIME_EXCEEDED: return "time_exceeded";
|
||||
case ICMP_PARAMETERPROB: return "param_problem";
|
||||
case ICMP_TIMESTAMP: return "ts";
|
||||
case ICMP_TIMESTAMPREPLY: return "ts_reply";
|
||||
case ICMP_INFO_REQUEST: return "info_req";
|
||||
case ICMP_INFO_REPLY: return "info_reply";
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
void str_icmp_type_name(char *s, size_t s_len, bool v6, uint8_t type)
|
||||
{
|
||||
const char *name = icmp_type_name(v6, type);
|
||||
if (name)
|
||||
snprintf(s,s_len,"%s",name);
|
||||
else
|
||||
snprintf(s,s_len,"%u",type);
|
||||
}
|
||||
|
||||
|
||||
static void str_srcdst_ip(char *s, size_t s_len, const void *saddr,const void *daddr)
|
||||
{
|
||||
char s_ip[16],d_ip[16];
|
||||
@@ -308,62 +353,97 @@ void print_udphdr(const struct udphdr *udphdr)
|
||||
str_udphdr(s,sizeof(s),udphdr);
|
||||
printf("%s",s);
|
||||
}
|
||||
|
||||
void str_icmphdr(char *s, size_t s_len, bool v6, const struct icmp46 *icmp)
|
||||
{
|
||||
char stype[32];
|
||||
str_icmp_type_name(stype,sizeof(stype),v6,icmp->icmp_type);
|
||||
if (icmp->icmp_type==ICMP_ECHO || icmp->icmp_type==ICMP_ECHOREPLY || icmp->icmp_type==ICMP6_ECHO_REQUEST || icmp->icmp_type==ICMP6_ECHO_REPLY)
|
||||
snprintf(s,s_len,"icmp_type=%s icmp_code=%u id=0x%04X seq=%u",stype,icmp->icmp_code,ntohs(icmp->icmp_data16[0]),ntohs(icmp->icmp_data16[1]));
|
||||
else
|
||||
snprintf(s,s_len,"icmp_type=%s icmp_code=%u data=0x%08X",stype,icmp->icmp_code,ntohl(icmp->icmp_data32));
|
||||
}
|
||||
void print_icmphdr(const struct icmp46 *icmp, bool v6)
|
||||
{
|
||||
char s[48];
|
||||
str_icmphdr(s,sizeof(s),v6,icmp);
|
||||
printf("%s",s);
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool proto_check_ipv4(const uint8_t *data, size_t len)
|
||||
{
|
||||
return len >= sizeof(struct ip) && (data[0] & 0xF0) == 0x40 &&
|
||||
len >= ((data[0] & 0x0F) << 2);
|
||||
if (len < sizeof(struct ip)) return false;
|
||||
if (((struct ip*)data)->ip_v!=4) return false;
|
||||
uint8_t off = ((struct ip*)data)->ip_hl << 2;
|
||||
return off>=sizeof(struct ip) && len>=off;
|
||||
}
|
||||
// move to transport protocol
|
||||
void proto_skip_ipv4(const uint8_t **data, size_t *len)
|
||||
{
|
||||
size_t l;
|
||||
|
||||
l = (**data & 0x0F) << 2;
|
||||
*data += l;
|
||||
*len -= l;
|
||||
uint8_t off = ((struct ip*)*data)->ip_hl << 2;
|
||||
*data += off;
|
||||
*len -= off;
|
||||
}
|
||||
bool proto_check_tcp(const uint8_t *data, size_t len)
|
||||
{
|
||||
return len >= sizeof(struct tcphdr) && len >= ((data[12] & 0xF0) >> 2);
|
||||
if (len < sizeof(struct tcphdr)) return false;
|
||||
uint8_t off = ((struct tcphdr*)data)->th_off << 2;
|
||||
return off>=sizeof(struct tcphdr) && len>=off;
|
||||
}
|
||||
void proto_skip_tcp(const uint8_t **data, size_t *len)
|
||||
{
|
||||
size_t l;
|
||||
l = ((*data)[12] & 0xF0) >> 2;
|
||||
*data += l;
|
||||
*len -= l;
|
||||
uint8_t off = ((struct tcphdr*)*data)->th_off << 2;
|
||||
*data += off;
|
||||
*len -= off;
|
||||
}
|
||||
bool proto_check_udp(const uint8_t *data, size_t len)
|
||||
{
|
||||
return len >= sizeof(struct udphdr) && len>=(data[4]<<8 | data[5]);
|
||||
return len >= sizeof(struct udphdr);
|
||||
}
|
||||
bool proto_check_udp_payload(const uint8_t *data, size_t len)
|
||||
{
|
||||
uint16_t l = ntohs(((struct udphdr*)data)->uh_ulen);
|
||||
return l>=sizeof(struct udphdr) && len >= l;
|
||||
}
|
||||
void proto_skip_udp(const uint8_t **data, size_t *len)
|
||||
{
|
||||
*data += 8;
|
||||
*len -= 8;
|
||||
*data += sizeof(struct udphdr);
|
||||
*len -= sizeof(struct udphdr);
|
||||
}
|
||||
bool proto_check_icmp(const uint8_t *data, size_t len)
|
||||
{
|
||||
return len >= sizeof(struct icmp46);
|
||||
}
|
||||
void proto_skip_icmp(const uint8_t **data, size_t *len)
|
||||
{
|
||||
*data += sizeof(struct icmp46);
|
||||
*len -= sizeof(struct icmp46);
|
||||
}
|
||||
|
||||
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 +474,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 +481,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
|
||||
@@ -491,7 +528,7 @@ uint8_t *proto_find_ip6_exthdr(struct ip6_hdr *ip6, size_t len, uint8_t proto)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void proto_dissect_l3l4(const uint8_t *data, size_t len, struct dissect *dis)
|
||||
void proto_dissect_l3l4(const uint8_t *data, size_t len, struct dissect *dis, bool no_payload_check)
|
||||
{
|
||||
const uint8_t *p;
|
||||
|
||||
@@ -508,11 +545,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) && (no_payload_check || 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
|
||||
@@ -520,31 +557,36 @@ void proto_dissect_l3l4(const uint8_t *data, size_t len, struct dissect *dis)
|
||||
return;
|
||||
}
|
||||
|
||||
dis->transport_len = len;
|
||||
|
||||
if (dis->proto==IPPROTO_TCP && proto_check_tcp(data, len))
|
||||
{
|
||||
dis->tcp = (const struct tcphdr *) data;
|
||||
dis->transport_len = len;
|
||||
|
||||
p = data;
|
||||
proto_skip_tcp(&data, &len);
|
||||
dis->len_l4 = data-p;
|
||||
|
||||
dis->data_payload = data;
|
||||
dis->len_payload = len;
|
||||
|
||||
}
|
||||
else if (dis->proto==IPPROTO_UDP && proto_check_udp(data, len))
|
||||
else if (dis->proto==IPPROTO_UDP && proto_check_udp(data, len) && (no_payload_check || proto_check_udp_payload(data, len)))
|
||||
{
|
||||
dis->udp = (const struct udphdr *) data;
|
||||
dis->transport_len = len;
|
||||
|
||||
p = data;
|
||||
proto_skip_udp(&data, &len);
|
||||
dis->len_l4 = data-p;
|
||||
|
||||
dis->data_payload = data;
|
||||
dis->len_payload = len;
|
||||
}
|
||||
else if ((dis->proto==IPPROTO_ICMP || dis->proto==IPPROTO_ICMPV6) && proto_check_icmp(data, len))
|
||||
{
|
||||
dis->icmp = (const struct icmp46 *) data;
|
||||
p = data;
|
||||
proto_skip_icmp(&data, &len);
|
||||
dis->len_l4 = data-p;
|
||||
}
|
||||
else
|
||||
{
|
||||
dis->len_l4 = 0;
|
||||
}
|
||||
|
||||
dis->data_payload = data;
|
||||
dis->len_payload = len;
|
||||
}
|
||||
|
||||
void reverse_ip(struct ip *ip, struct ip6_hdr *ip6)
|
||||
@@ -581,12 +623,137 @@ uint8_t ttl46(const struct ip *ip, const struct ip6_hdr *ip6)
|
||||
}
|
||||
|
||||
|
||||
bool get_source_ip4(const struct in_addr *target, struct in_addr *source)
|
||||
{
|
||||
int sock = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (sock < 0) return false;
|
||||
|
||||
struct sockaddr_in serv,name;
|
||||
socklen_t namelen;
|
||||
|
||||
memset(&serv,0,sizeof(serv)); // or valgrind complains about uninitialized
|
||||
serv.sin_family = AF_INET;
|
||||
serv.sin_addr = *target;
|
||||
serv.sin_port = 0xFFFF;
|
||||
|
||||
// Connect triggers the kernel's route lookup
|
||||
if (!connect(sock, (const struct sockaddr*)&serv, sizeof(serv)))
|
||||
{
|
||||
namelen = sizeof(name);
|
||||
if (!getsockname(sock, (struct sockaddr*)&name, &namelen))
|
||||
{
|
||||
close(sock);
|
||||
*source = name.sin_addr;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
close(sock);
|
||||
return false;
|
||||
}
|
||||
bool get_source_ip6(const struct in6_addr *target, struct in6_addr *source)
|
||||
{
|
||||
int sock = socket(AF_INET6, SOCK_DGRAM, 0);
|
||||
if (sock < 0) return false;
|
||||
|
||||
struct sockaddr_in6 serv,name;
|
||||
socklen_t namelen;
|
||||
|
||||
memset(&serv,0,sizeof(serv)); // or valgrind complains about uninitialized
|
||||
serv.sin6_family = AF_INET6;
|
||||
serv.sin6_addr = *target;
|
||||
serv.sin6_port = 0xFFFF;
|
||||
|
||||
// Connect triggers the kernel's route lookup
|
||||
if (!connect(sock, (const struct sockaddr*)&serv, sizeof(serv)))
|
||||
{
|
||||
namelen = sizeof(name);
|
||||
if (!getsockname(sock, (struct sockaddr*)&name, &namelen))
|
||||
{
|
||||
close(sock);
|
||||
*source = name.sin6_addr;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
close(sock);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
#ifdef __CYGWIN__
|
||||
|
||||
uint32_t w_win32_error=0;
|
||||
|
||||
BOOL AdjustPrivileges(HANDLE hToken, const LPCTSTR *privs, BOOL bEnable)
|
||||
{
|
||||
DWORD dwSize, k, n;
|
||||
PTOKEN_PRIVILEGES TokenPrivsData;
|
||||
LUID luid;
|
||||
|
||||
dwSize = 0;
|
||||
GetTokenInformation(hToken, TokenPrivileges, NULL, 0, &dwSize ); // will fail
|
||||
w_win32_error = GetLastError();
|
||||
if (w_win32_error == ERROR_INSUFFICIENT_BUFFER)
|
||||
{
|
||||
w_win32_error = 0;
|
||||
if (TokenPrivsData = (PTOKEN_PRIVILEGES)LocalAlloc(LMEM_FIXED, dwSize))
|
||||
{
|
||||
if (GetTokenInformation(hToken, TokenPrivileges, TokenPrivsData, dwSize, &dwSize))
|
||||
{
|
||||
n = 0;
|
||||
while (privs[n])
|
||||
{
|
||||
if (LookupPrivilegeValue(NULL, privs[n], &luid))
|
||||
{
|
||||
w_win32_error = ERROR_PRIVILEGE_NOT_HELD;
|
||||
for (k = 0; k < TokenPrivsData->PrivilegeCount; k++)
|
||||
if (!memcmp(&TokenPrivsData->Privileges[k].Luid, &luid, sizeof(LUID)))
|
||||
{
|
||||
if (bEnable)
|
||||
TokenPrivsData->Privileges[k].Attributes |= SE_PRIVILEGE_ENABLED;
|
||||
else
|
||||
TokenPrivsData->Privileges[k].Attributes &= ~SE_PRIVILEGE_ENABLED;
|
||||
w_win32_error = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
w_win32_error = GetLastError();
|
||||
if (w_win32_error) break;
|
||||
n++;
|
||||
}
|
||||
if (!w_win32_error)
|
||||
{
|
||||
if (!AdjustTokenPrivileges(hToken, FALSE, TokenPrivsData, 0, NULL, NULL))
|
||||
w_win32_error = GetLastError();
|
||||
}
|
||||
}
|
||||
else
|
||||
w_win32_error = GetLastError();
|
||||
LocalFree(TokenPrivsData);
|
||||
}
|
||||
else
|
||||
w_win32_error = GetLastError();
|
||||
}
|
||||
return !w_win32_error;
|
||||
}
|
||||
BOOL AdjustPrivilegesForCurrentProcess(const LPCTSTR *privs, BOOL bEnable)
|
||||
{
|
||||
HANDLE hTokenThisProcess;
|
||||
|
||||
w_win32_error = 0;
|
||||
if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, &hTokenThisProcess))
|
||||
{
|
||||
if (!AdjustPrivileges(hTokenThisProcess, privs, bEnable))
|
||||
w_win32_error = GetLastError();
|
||||
CloseHandle(hTokenThisProcess);
|
||||
}
|
||||
else
|
||||
w_win32_error = GetLastError();
|
||||
|
||||
return !w_win32_error;
|
||||
}
|
||||
|
||||
static BOOL RemoveTokenPrivs(void)
|
||||
{
|
||||
BOOL bRes = FALSE;
|
||||
@@ -632,7 +799,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
|
||||
@@ -712,6 +879,26 @@ err:
|
||||
if (!bRes) w_win32_error = GetLastError();
|
||||
return bRes;
|
||||
}
|
||||
BOOL SetMandatoryLabelObject(HANDLE h, SE_OBJECT_TYPE ObjType, DWORD dwMandatoryLabelRID, DWORD dwAceRevision, DWORD dwAceFlags)
|
||||
{
|
||||
BOOL bRes = FALSE;
|
||||
DWORD dwErr;
|
||||
char buf_label[16], buf_pacl[32];
|
||||
PSID label = (PSID)buf_label;
|
||||
PACL pacl = (PACL)buf_pacl;
|
||||
|
||||
InitializeSid(label, &label_authority, 1);
|
||||
*GetSidSubAuthority(label, 0) = dwMandatoryLabelRID;
|
||||
if (InitializeAcl(pacl, sizeof(buf_pacl), ACL_REVISION) && AddMandatoryAce(pacl, dwAceRevision, dwAceFlags, SYSTEM_MANDATORY_LABEL_NO_WRITE_UP, label))
|
||||
{
|
||||
dwErr = SetSecurityInfo(h, ObjType, LABEL_SECURITY_INFORMATION, NULL, NULL, NULL, pacl);
|
||||
SetLastError(dwErr);
|
||||
bRes = dwErr == ERROR_SUCCESS;
|
||||
}
|
||||
if (!bRes) w_win32_error = GetLastError();
|
||||
return bRes;
|
||||
}
|
||||
|
||||
|
||||
bool ensure_file_access(const char *filename)
|
||||
{
|
||||
@@ -745,6 +932,85 @@ bool prepare_low_appdata()
|
||||
return b;
|
||||
}
|
||||
|
||||
// cygwin uses nt directory to store it's state. low mandatory breaks write access there and cause some functions to fail
|
||||
// it's not possible to reproduce exact directory names, have to iterate and set low integrity to all
|
||||
BOOL RelaxCygwinNTDir()
|
||||
{
|
||||
NTSTATUS status;
|
||||
PROCESS_SESSION_INFORMATION psi;
|
||||
WCHAR bno_name[32], cyg_name[256];
|
||||
CHAR scyg_name[256];
|
||||
UNICODE_STRING bno_us, cyg_us;
|
||||
OBJECT_ATTRIBUTES attr;
|
||||
HANDLE hDir, hDirCyg;
|
||||
BYTE buf[4096];
|
||||
ULONG context, rsize;
|
||||
BOOL b,ball,restart;
|
||||
POBJECT_DIRECTORY_INFORMATION pdir;
|
||||
|
||||
LPCTSTR Privs[] = { SE_TAKE_OWNERSHIP_NAME , NULL };
|
||||
|
||||
if (!AdjustPrivilegesForCurrentProcess(Privs, TRUE))
|
||||
return FALSE;
|
||||
|
||||
status = NtQueryInformationProcess(GetCurrentProcess(), ProcessSessionInformation, &psi, sizeof psi, NULL);
|
||||
if (NT_SUCCESS(status))
|
||||
swprintf(bno_name, sizeof(bno_name)/sizeof(*bno_name), L"\\Sessions\\BNOLINKS\\%u", psi.SessionId);
|
||||
else
|
||||
swprintf(bno_name, sizeof(bno_name)/sizeof(*bno_name), L"\\BaseNamedObjects");
|
||||
|
||||
RtlInitUnicodeString(&bno_us, bno_name);
|
||||
InitializeObjectAttributes(&attr, &bno_us, 0, NULL, NULL);
|
||||
|
||||
ball = TRUE;
|
||||
w_win32_error = 0;
|
||||
status = NtOpenDirectoryObject(&hDir, DIRECTORY_QUERY, &attr);
|
||||
if (NT_SUCCESS(status))
|
||||
{
|
||||
context = 0;
|
||||
restart = TRUE;
|
||||
while (NT_SUCCESS(status = NtQueryDirectoryObject(hDir, buf, sizeof(buf), restart, FALSE, &context, &rsize)))
|
||||
{
|
||||
|
||||
for (pdir = (POBJECT_DIRECTORY_INFORMATION)buf; pdir->Name.Length; pdir++)
|
||||
if (pdir->TypeName.Length == 18 && !memcmp(pdir->TypeName.Buffer, L"Directory", 18) &&
|
||||
pdir->Name.Length >= 14 && !memcmp(pdir->Name.Buffer, L"cygwin1", 14))
|
||||
{
|
||||
swprintf(cyg_name, sizeof(cyg_name)/sizeof(*cyg_name), L"%ls\\%ls", bno_name, pdir->Name.Buffer);
|
||||
if (!WideCharToMultiByte(CP_ACP, 0, cyg_name, -1, scyg_name, sizeof(scyg_name), NULL, NULL))
|
||||
*scyg_name=0;
|
||||
RtlInitUnicodeString(&cyg_us, cyg_name);
|
||||
InitializeObjectAttributes(&attr, &cyg_us, 0, NULL, NULL);
|
||||
status = NtOpenDirectoryObject(&hDirCyg, WRITE_OWNER, &attr);
|
||||
if (NT_SUCCESS(status))
|
||||
{
|
||||
b = SetMandatoryLabelObject(hDirCyg, SE_KERNEL_OBJECT, SECURITY_MANDATORY_LOW_RID, ACL_REVISION_DS, 0);
|
||||
if (!b)
|
||||
{
|
||||
w_win32_error = GetLastError();
|
||||
DLOG_ERR("could not set integrity label on '%s' . error %u\n", scyg_name, w_win32_error);
|
||||
}
|
||||
else
|
||||
DLOG("set low integrity label on '%s'\n", scyg_name);
|
||||
ball = ball && b;
|
||||
NtClose(hDirCyg);
|
||||
}
|
||||
}
|
||||
restart = FALSE;
|
||||
}
|
||||
NtClose(hDir);
|
||||
}
|
||||
else
|
||||
{
|
||||
w_win32_error = RtlNtStatusToDosError(status);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return ball;
|
||||
}
|
||||
|
||||
|
||||
|
||||
BOOL JobSandbox()
|
||||
{
|
||||
BOOL bRes = FALSE;
|
||||
@@ -776,6 +1042,9 @@ bool win_sandbox(void)
|
||||
// there's no way to return privs
|
||||
if (!b_sandbox_set)
|
||||
{
|
||||
if (!RelaxCygwinNTDir())
|
||||
DLOG_ERR("could not set low mandatory label on cygwin NT directory. some functions may not work. error %u\n", w_win32_error);
|
||||
|
||||
if (!RemoveTokenPrivs())
|
||||
return FALSE;
|
||||
|
||||
@@ -902,7 +1171,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 +1276,12 @@ bool nlm_list(bool bAll)
|
||||
}
|
||||
else
|
||||
bRet = false;
|
||||
|
||||
CoUninitialize();
|
||||
}
|
||||
else
|
||||
bRet = false;
|
||||
|
||||
CoUninitialize();
|
||||
return bRet;
|
||||
}
|
||||
|
||||
@@ -1181,8 +1451,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");
|
||||
|
||||
@@ -1220,7 +1493,7 @@ bool windivert_init(const char *filter)
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool windivert_recv_filter(HANDLE hFilter, uint8_t *packet, size_t *len, WINDIVERT_ADDRESS *wa)
|
||||
static bool windivert_recv_filter(HANDLE hFilter, uint8_t *packet, size_t *len, WINDIVERT_ADDRESS *wa, unsigned int *wa_count)
|
||||
{
|
||||
UINT recv_len;
|
||||
DWORD err;
|
||||
@@ -1239,8 +1512,10 @@ static bool windivert_recv_filter(HANDLE hFilter, uint8_t *packet, size_t *len,
|
||||
}
|
||||
usleep(0);
|
||||
|
||||
if (WinDivertRecvEx(hFilter, packet, *len, &recv_len, 0, wa, NULL, &ovl))
|
||||
*wa_count *= sizeof(WINDIVERT_ADDRESS);
|
||||
if (WinDivertRecvEx(hFilter, packet, *len, &recv_len, 0, wa, wa_count, &ovl))
|
||||
{
|
||||
*wa_count /= sizeof(WINDIVERT_ADDRESS);
|
||||
*len = recv_len;
|
||||
return true;
|
||||
}
|
||||
@@ -1269,6 +1544,7 @@ static bool windivert_recv_filter(HANDLE hFilter, uint8_t *packet, size_t *len,
|
||||
}
|
||||
if (!GetOverlappedResult(hFilter,&ovl,&rd,TRUE))
|
||||
continue;
|
||||
*wa_count /= sizeof(WINDIVERT_ADDRESS);
|
||||
*len = rd;
|
||||
return true;
|
||||
case ERROR_INSUFFICIENT_BUFFER:
|
||||
@@ -1284,9 +1560,9 @@ static bool windivert_recv_filter(HANDLE hFilter, uint8_t *packet, size_t *len,
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool windivert_recv(uint8_t *packet, size_t *len, WINDIVERT_ADDRESS *wa)
|
||||
bool windivert_recv(uint8_t *packet, size_t *len, WINDIVERT_ADDRESS *wa, unsigned int *wa_count)
|
||||
{
|
||||
return windivert_recv_filter(w_filter,packet,len,wa);
|
||||
return windivert_recv_filter(w_filter,packet,len,wa,wa_count);
|
||||
}
|
||||
|
||||
static bool windivert_send_filter(HANDLE hFilter, const uint8_t *packet, size_t len, const WINDIVERT_ADDRESS *wa)
|
||||
@@ -1993,8 +2269,29 @@ void verdict_udp_csum_fix(uint8_t verdict, struct udphdr *udphdr, size_t transpo
|
||||
#ifdef __FreeBSD__
|
||||
if (ip6hdr)
|
||||
#endif
|
||||
{
|
||||
DLOG("fixing udp checksum\n");
|
||||
udp_fix_checksum(udphdr,transport_len,ip,ip6hdr);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void verdict_icmp_csum_fix(uint8_t verdict, struct icmp46 *icmphdr, size_t transport_len, const struct ip6_hdr *ip6hdr)
|
||||
{
|
||||
// always fix csum for windivert. original can be partial or bad
|
||||
// FreeBSD tend to pass ipv6 frames with wrong checksum (OBSERVED EARLIER, MAY BE FIXED NOW)
|
||||
// Linux passes correct checksums
|
||||
#ifndef __linux__
|
||||
if (!(verdict & VERDICT_NOCSUM) && (verdict & VERDICT_MASK)==VERDICT_PASS)
|
||||
{
|
||||
#ifdef __FreeBSD__
|
||||
if (ip6hdr)
|
||||
#endif
|
||||
{
|
||||
DLOG("fixing icmp checksum\n");
|
||||
icmp_fix_checksum(icmphdr,transport_len,ip6hdr);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -2069,7 +2366,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);
|
||||
|
||||
@@ -25,6 +25,11 @@
|
||||
#ifdef __CYGWIN__
|
||||
#define INITGUID
|
||||
#include "windivert/windivert.h"
|
||||
#include "netinet/icmp6.h"
|
||||
#include "netinet/ip_icmp.h"
|
||||
#else
|
||||
#include <netinet/icmp6.h>
|
||||
#include <netinet/ip_icmp.h>
|
||||
#endif
|
||||
|
||||
#ifndef IPPROTO_DIVERT
|
||||
@@ -58,6 +63,34 @@
|
||||
#ifndef IPPROTO_SHIM6
|
||||
#define IPPROTO_SHIM6 140
|
||||
#endif
|
||||
#ifndef IPPROTO_SCTP
|
||||
#define IPPROTO_SCTP 132
|
||||
#endif
|
||||
|
||||
#ifndef ICMP_DEST_UNREACH
|
||||
#define ICMP_DEST_UNREACH 3
|
||||
#endif
|
||||
#ifndef ICMP_TIME_EXCEEDED
|
||||
#define ICMP_TIME_EXCEEDED 11
|
||||
#endif
|
||||
#ifndef ICMP_PARAMETERPROB
|
||||
#define ICMP_PARAMETERPROB 12
|
||||
#endif
|
||||
#ifndef ICMP_TIMESTAMP
|
||||
#define ICMP_TIMESTAMP 13
|
||||
#endif
|
||||
#ifndef ICMP_TIMESTAMPREPLY
|
||||
#define ICMP_TIMESTAMPREPLY 14
|
||||
#endif
|
||||
#ifndef ICMP_INFO_REQUEST
|
||||
#define ICMP_INFO_REQUEST 15
|
||||
#endif
|
||||
#ifndef ICMP_INFO_REPLY
|
||||
#define ICMP_INFO_REPLY 16
|
||||
#endif
|
||||
#ifndef MLD_LISTENER_REDUCTION
|
||||
#define MLD_LISTENER_REDUCTION 132
|
||||
#endif
|
||||
|
||||
// returns netorder value
|
||||
uint32_t net32_add(uint32_t netorder_value, uint32_t cpuorder_increment);
|
||||
@@ -69,8 +102,10 @@ uint32_t net16_add(uint16_t netorder_value, uint16_t cpuorder_increment);
|
||||
#define VERDICT_MODIFY 1
|
||||
#define VERDICT_DROP 2
|
||||
#define VERDICT_MASK 3
|
||||
#define VERDICT_NOCSUM 4
|
||||
#define VERDICT_MASK_VALID 7
|
||||
#define VERDICT_PRESERVE_NEXT 4
|
||||
#define VERDICT_MASK_VALID_LUA (VERDICT_MASK|VERDICT_PRESERVE_NEXT)
|
||||
#define VERDICT_NOCSUM 8
|
||||
#define VERDICT_MASK_VALID 15
|
||||
|
||||
#define IP4_TOS(ip_header) (ip_header ? ip_header->ip_tos : 0)
|
||||
#define IP4_IP_ID(ip_header) (ip_header ? ip_header->ip_id : 0)
|
||||
@@ -80,14 +115,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);
|
||||
@@ -98,12 +130,12 @@ 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);
|
||||
bool windivert_init(const char *filter);
|
||||
bool windivert_recv(uint8_t *packet, size_t *len, WINDIVERT_ADDRESS *wa);
|
||||
bool windivert_recv(uint8_t *packet, size_t *len, WINDIVERT_ADDRESS *wa, unsigned int *wa_count);
|
||||
bool windivert_send(const uint8_t *packet, size_t len, const WINDIVERT_ADDRESS *wa);
|
||||
#else
|
||||
#define ensure_dir_access(dir) ensure_file_access(dir)
|
||||
@@ -125,27 +157,36 @@ int socket_divert(sa_family_t family);
|
||||
#endif
|
||||
|
||||
const char *proto_name(uint8_t proto);
|
||||
void str_proto_name(char *s, size_t s_len, uint8_t proto);
|
||||
const char *icmp_type_name(bool v6, uint8_t type);
|
||||
void str_icmp_type_name(char *s, size_t s_len, bool v6, uint8_t type);
|
||||
uint16_t family_from_proto(uint8_t l3proto);
|
||||
void print_ip(const struct ip *ip);
|
||||
void print_ip6hdr(const struct ip6_hdr *ip6hdr, uint8_t proto);
|
||||
void print_tcphdr(const struct tcphdr *tcphdr);
|
||||
void print_udphdr(const struct udphdr *udphdr);
|
||||
void print_icmphdr(const struct icmp46 *icmp, bool v6);
|
||||
void str_ip(char *s, size_t s_len, const struct ip *ip);
|
||||
void str_ip6hdr(char *s, size_t s_len, const struct ip6_hdr *ip6hdr, uint8_t proto);
|
||||
void str_srcdst_ip6(char *s, size_t s_len, const void *saddr,const void *daddr);
|
||||
void str_tcphdr(char *s, size_t s_len, const struct tcphdr *tcphdr);
|
||||
void str_udphdr(char *s, size_t s_len, const struct udphdr *udphdr);
|
||||
void str_icmphdr(char *s, size_t s_len, bool v6, const struct icmp46 *icmp);
|
||||
|
||||
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);
|
||||
bool proto_check_udp(const uint8_t *data, size_t len);
|
||||
bool proto_check_udp_payload(const uint8_t *data, size_t len);
|
||||
void proto_skip_udp(const uint8_t **data, size_t *len);
|
||||
bool proto_check_icmp(const uint8_t *data, size_t len);
|
||||
void proto_skip_icmp(const uint8_t **data, size_t *len);
|
||||
|
||||
struct dissect
|
||||
{
|
||||
const uint8_t *data_pkt;
|
||||
@@ -156,19 +197,24 @@ struct dissect
|
||||
uint8_t proto;
|
||||
const struct tcphdr *tcp;
|
||||
const struct udphdr *udp;
|
||||
const struct icmp46 *icmp;
|
||||
size_t len_l4;
|
||||
size_t transport_len;
|
||||
const uint8_t *data_payload;
|
||||
size_t len_payload;
|
||||
};
|
||||
void proto_dissect_l3l4(const uint8_t *data, size_t len, struct dissect *dis);
|
||||
void proto_dissect_l3l4(const uint8_t *data, size_t len, struct dissect *dis, bool no_payload_check);
|
||||
void reverse_ip(struct ip *ip, struct ip6_hdr *ip6);
|
||||
void reverse_tcp(struct tcphdr *tcp);
|
||||
|
||||
uint8_t ttl46(const struct ip *ip, const struct ip6_hdr *ip6);
|
||||
|
||||
bool get_source_ip4(const struct in_addr *target, struct in_addr *source);
|
||||
bool get_source_ip6(const struct in6_addr *target, struct in6_addr *source);
|
||||
|
||||
void verdict_tcp_csum_fix(uint8_t verdict, struct tcphdr *tcphdr, size_t transport_len, const struct ip *ip, const struct ip6_hdr *ip6hdr);
|
||||
void verdict_udp_csum_fix(uint8_t verdict, struct udphdr *udphdr, size_t transport_len, const struct ip *ip, const struct ip6_hdr *ip6hdr);
|
||||
void verdict_icmp_csum_fix(uint8_t verdict, struct icmp46 *icmphdr, size_t transport_len, const struct ip6_hdr *ip6hdr);
|
||||
|
||||
void dbgprint_socket_buffers(int fd);
|
||||
bool set_socket_buffers(int fd, int rcvbuf, int sndbuf);
|
||||
|
||||
1514
nfq2/desync.c
1514
nfq2/desync.c
File diff suppressed because it is too large
Load Diff
236
nfq2/filter.c
Normal file
236
nfq2/filter.c
Normal file
@@ -0,0 +1,236 @@
|
||||
#include "filter.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
bool pf_match(uint16_t port, const port_filter *pf)
|
||||
{
|
||||
return port && (((!pf->from && !pf->to) || (port>=pf->from && port<=pf->to)) ^ pf->neg);
|
||||
}
|
||||
bool pf_parse(const char *s, port_filter *pf)
|
||||
{
|
||||
unsigned int v1,v2;
|
||||
char c;
|
||||
|
||||
if (!s) return false;
|
||||
if (*s=='*' && s[1]==0)
|
||||
{
|
||||
pf->from=1; pf->to=0xFFFF;
|
||||
return true;
|
||||
}
|
||||
if (*s=='~')
|
||||
{
|
||||
pf->neg=true;
|
||||
s++;
|
||||
}
|
||||
else
|
||||
pf->neg=false;
|
||||
if (sscanf(s,"%u-%u%c",&v1,&v2,&c)==2)
|
||||
{
|
||||
if (v1>65535 || v2>65535 || v1>v2) return false;
|
||||
pf->from=(uint16_t)v1;
|
||||
pf->to=(uint16_t)v2;
|
||||
}
|
||||
else if (sscanf(s,"%u%c",&v1,&c)==1)
|
||||
{
|
||||
if (v1>65535) return false;
|
||||
pf->to=pf->from=(uint16_t)v1;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
// deny all case
|
||||
if (!pf->from && !pf->to) pf->neg=true;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool fltmode_parse(const char *s, uint8_t *mode)
|
||||
{
|
||||
if (*s=='*' && !s[1])
|
||||
{
|
||||
*mode = FLTMODE_ANY;
|
||||
return true;
|
||||
}
|
||||
else if (*s=='-' && !s[1])
|
||||
{
|
||||
*mode = FLTMODE_SKIP;
|
||||
return true;
|
||||
}
|
||||
*mode = FLTMODE_SKIP;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool icf_match(uint8_t type, uint8_t code, const icmp_filter *icf)
|
||||
{
|
||||
return icf->mode==FLTMODE_ANY || icf->mode==FLTMODE_FILTER && icf->type==type && (!icf->code_valid || icf->code==code);
|
||||
}
|
||||
bool icf_parse(const char *s, icmp_filter *icf)
|
||||
{
|
||||
unsigned int u1,u2;
|
||||
char c1,c2;
|
||||
|
||||
icf->type = icf->code = 0;
|
||||
icf->code_valid = false;
|
||||
if (fltmode_parse(s, &icf->mode)) return true;
|
||||
switch(sscanf(s,"%u%c%u%c",&u1,&c1,&u2,&c2))
|
||||
{
|
||||
case 1:
|
||||
if (u1>0xFF) return false;
|
||||
icf->type = (uint8_t)u1;
|
||||
icf->mode = FLTMODE_FILTER;
|
||||
break;
|
||||
case 3:
|
||||
if (c1!=':' || (u1>0xFF) || (u2>0xFF)) return false;
|
||||
icf->type = (uint8_t)u1;
|
||||
icf->code = (uint8_t)u2;
|
||||
icf->code_valid = true;
|
||||
icf->mode = FLTMODE_FILTER;
|
||||
break;
|
||||
default:
|
||||
icf->mode = FLTMODE_SKIP;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ipp_match(uint8_t proto, const ipp_filter *ipp)
|
||||
{
|
||||
return ipp->mode==FLTMODE_ANY || ipp->mode==FLTMODE_FILTER && ipp->proto==proto;
|
||||
}
|
||||
bool ipp_parse(const char *s, ipp_filter *ipp)
|
||||
{
|
||||
unsigned int u1;
|
||||
char c;
|
||||
|
||||
ipp->proto = 0xFF;
|
||||
if (fltmode_parse(s, &ipp->mode)) return true;
|
||||
if (sscanf(s,"%u%c",&u1,&c)!=1 || u1>0xFF) return false;
|
||||
ipp->proto = (uint8_t)u1;
|
||||
ipp->mode = FLTMODE_FILTER;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool packet_pos_parse(const char *s, struct packet_pos *pos)
|
||||
{
|
||||
if (*s!='n' && *s!='d' && *s!='s' && *s!='p' && *s!='b' && *s!='x' && *s!='a') return false;
|
||||
pos->mode=*s;
|
||||
if (pos->mode=='x' || pos->mode=='a')
|
||||
{
|
||||
pos->pos=0;
|
||||
return true;
|
||||
}
|
||||
return sscanf(s+1,"%u",&pos->pos)==1;
|
||||
}
|
||||
bool packet_range_parse(const char *s, struct packet_range *range)
|
||||
{
|
||||
const char *p;
|
||||
|
||||
range->upper_cutoff = false;
|
||||
if (*s=='-' || *s=='<')
|
||||
{
|
||||
range->from = PACKET_POS_ALWAYS;
|
||||
range->upper_cutoff = *s=='<';
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!packet_pos_parse(s,&range->from)) return false;
|
||||
if (range->from.mode=='x')
|
||||
{
|
||||
range->to = range->from;
|
||||
return true;
|
||||
}
|
||||
if (!(p = strchr(s,'-')))
|
||||
p = strchr(s,'<');
|
||||
if (p)
|
||||
{
|
||||
s = p;
|
||||
range->upper_cutoff = *s=='<';
|
||||
}
|
||||
else
|
||||
{
|
||||
if (range->from.mode=='a')
|
||||
{
|
||||
range->to = range->from;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
s++;
|
||||
if (*s)
|
||||
{
|
||||
return packet_pos_parse(s,&range->to);
|
||||
}
|
||||
else
|
||||
{
|
||||
range->to = PACKET_POS_ALWAYS;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void str_cidr4(char *s, size_t s_len, const struct cidr4 *cidr)
|
||||
{
|
||||
char s_ip[16];
|
||||
*s_ip=0;
|
||||
inet_ntop(AF_INET, &cidr->addr, s_ip, sizeof(s_ip));
|
||||
snprintf(s,s_len,cidr->preflen<32 ? "%s/%u" : "%s", s_ip, cidr->preflen);
|
||||
}
|
||||
void print_cidr4(const struct cidr4 *cidr)
|
||||
{
|
||||
char s[19];
|
||||
str_cidr4(s,sizeof(s),cidr);
|
||||
printf("%s",s);
|
||||
}
|
||||
void str_cidr6(char *s, size_t s_len, const struct cidr6 *cidr)
|
||||
{
|
||||
char s_ip[40];
|
||||
*s_ip=0;
|
||||
inet_ntop(AF_INET6, &cidr->addr, s_ip, sizeof(s_ip));
|
||||
snprintf(s,s_len,cidr->preflen<128 ? "%s/%u" : "%s", s_ip, cidr->preflen);
|
||||
}
|
||||
void print_cidr6(const struct cidr6 *cidr)
|
||||
{
|
||||
char s[44];
|
||||
str_cidr6(s,sizeof(s),cidr);
|
||||
printf("%s",s);
|
||||
}
|
||||
bool parse_cidr4(char *s, struct cidr4 *cidr)
|
||||
{
|
||||
char *p,d;
|
||||
bool b;
|
||||
unsigned int plen;
|
||||
|
||||
if ((p = strchr(s, '/')))
|
||||
{
|
||||
if (sscanf(p + 1, "%u", &plen)!=1 || plen>32)
|
||||
return false;
|
||||
cidr->preflen = (uint8_t)plen;
|
||||
d=*p; *p=0; // backup char
|
||||
}
|
||||
else
|
||||
cidr->preflen = 32;
|
||||
b = (inet_pton(AF_INET, s, &cidr->addr)==1);
|
||||
if (p) *p=d; // restore char
|
||||
return b;
|
||||
}
|
||||
bool parse_cidr6(char *s, struct cidr6 *cidr)
|
||||
{
|
||||
char *p,d;
|
||||
bool b;
|
||||
unsigned int plen;
|
||||
|
||||
if ((p = strchr(s, '/')))
|
||||
{
|
||||
if (sscanf(p + 1, "%u", &plen)!=1 || plen>128)
|
||||
return false;
|
||||
cidr->preflen = (uint8_t)plen;
|
||||
d=*p; *p=0; // backup char
|
||||
}
|
||||
else
|
||||
cidr->preflen = 128;
|
||||
b = (inet_pton(AF_INET6, s, &cidr->addr)==1);
|
||||
if (p) *p=d; // restore char
|
||||
return b;
|
||||
}
|
||||
64
nfq2/filter.h
Normal file
64
nfq2/filter.h
Normal file
@@ -0,0 +1,64 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t from,to;
|
||||
bool neg;
|
||||
} port_filter;
|
||||
bool pf_match(uint16_t port, const port_filter *pf);
|
||||
bool pf_parse(const char *s, port_filter *pf);
|
||||
|
||||
#define FLTMODE_SKIP 0
|
||||
#define FLTMODE_ANY 1
|
||||
#define FLTMODE_FILTER 2
|
||||
typedef struct
|
||||
{
|
||||
uint8_t mode, type, code;
|
||||
bool code_valid;
|
||||
} icmp_filter;
|
||||
bool icf_match(uint8_t type, uint8_t code, const icmp_filter *icf);
|
||||
bool icf_parse(const char *s, icmp_filter *icf);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t mode, proto;
|
||||
} ipp_filter;
|
||||
bool ipp_match(uint8_t proto, const ipp_filter *ipp);
|
||||
bool ipp_parse(const char *s, ipp_filter *ipp);
|
||||
|
||||
struct packet_pos
|
||||
{
|
||||
char mode; // n - packets, d - data packets, s - relative sequence
|
||||
unsigned int pos;
|
||||
};
|
||||
struct packet_range
|
||||
{
|
||||
struct packet_pos from, to;
|
||||
bool upper_cutoff; // true - do not include upper limit, false - include upper limit
|
||||
};
|
||||
#define PACKET_POS_NEVER (struct packet_pos){'x',0}
|
||||
#define PACKET_POS_ALWAYS (struct packet_pos){'a',0}
|
||||
#define PACKET_RANGE_NEVER (struct packet_range){PACKET_POS_NEVER,PACKET_POS_NEVER}
|
||||
#define PACKET_RANGE_ALWAYS (struct packet_range){PACKET_POS_ALWAYS,PACKET_POS_ALWAYS}
|
||||
bool packet_range_parse(const char *s, struct packet_range *range);
|
||||
|
||||
struct cidr4
|
||||
{
|
||||
struct in_addr addr;
|
||||
uint8_t preflen;
|
||||
};
|
||||
struct cidr6
|
||||
{
|
||||
struct in6_addr addr;
|
||||
uint8_t preflen;
|
||||
};
|
||||
void str_cidr4(char *s, size_t s_len, const struct cidr4 *cidr);
|
||||
void print_cidr4(const struct cidr4 *cidr);
|
||||
void str_cidr6(char *s, size_t s_len, const struct cidr6 *cidr);
|
||||
void print_cidr6(const struct cidr6 *cidr);
|
||||
bool parse_cidr4(char *s, struct cidr4 *cidr);
|
||||
bool parse_cidr6(char *s, struct cidr6 *cidr);
|
||||
13
nfq2/gzip.c
13
nfq2/gzip.c
@@ -7,7 +7,7 @@
|
||||
#define BUFMIN 128
|
||||
#define BUFCHUNK (1024*128)
|
||||
|
||||
int z_readfile(FILE *F, char **buf, size_t *size)
|
||||
int z_readfile(FILE *F, char **buf, size_t *size, size_t extra_alloc)
|
||||
{
|
||||
z_stream zs;
|
||||
int r;
|
||||
@@ -31,14 +31,19 @@ int z_readfile(FILE *F, char **buf, size_t *size)
|
||||
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
|
||||
{
|
||||
if ((bufsize - *size) < BUFMIN)
|
||||
{
|
||||
bufsize += BUFCHUNK;
|
||||
newbuf = *buf ? realloc(*buf, bufsize) : malloc(bufsize);
|
||||
newbuf = *buf ? realloc(*buf, bufsize + extra_alloc) : malloc(bufsize + extra_alloc);
|
||||
if (!newbuf)
|
||||
{
|
||||
r = Z_MEM_ERROR;
|
||||
@@ -57,7 +62,7 @@ int z_readfile(FILE *F, char **buf, size_t *size)
|
||||
if (*size < bufsize)
|
||||
{
|
||||
// free extra space
|
||||
if ((newbuf = realloc(*buf, *size))) *buf = newbuf;
|
||||
if ((newbuf = realloc(*buf, *size + extra_alloc))) *buf = newbuf;
|
||||
}
|
||||
|
||||
inflateEnd(&zs);
|
||||
|
||||
@@ -4,5 +4,5 @@
|
||||
#include <zlib.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
int z_readfile(FILE *F,char **buf,size_t *size);
|
||||
int z_readfile(FILE *F, char **buf, size_t *size, size_t extra_alloc);
|
||||
bool is_gzip(FILE* F);
|
||||
|
||||
380
nfq2/helpers.c
380
nfq2/helpers.c
@@ -8,11 +8,11 @@
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <libgen.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define UNIQ_SORT \
|
||||
{ \
|
||||
int i, j, u; \
|
||||
size_t i, j, u; \
|
||||
for (i = j = 0; j < ct; i++) \
|
||||
{ \
|
||||
u = pu[j++]; \
|
||||
@@ -61,25 +61,27 @@ void replace_char(char *s, char from, char to)
|
||||
for(;*s;s++) if (*s==from) *s=to;
|
||||
}
|
||||
|
||||
char *strncasestr(const char *s, const char *find, size_t slen)
|
||||
const char *strncasestr(const char *s, const char *find, size_t slen)
|
||||
{
|
||||
char c, sc;
|
||||
size_t len;
|
||||
|
||||
if ((c = *find++) != '\0')
|
||||
if ((c = *find++))
|
||||
{
|
||||
len = strlen(find);
|
||||
do
|
||||
{
|
||||
do
|
||||
{
|
||||
if (slen-- < 1 || (sc = *s++) == '\0') return NULL;
|
||||
} while (toupper(c) != toupper(sc));
|
||||
if (!slen) return NULL;
|
||||
slen--;
|
||||
sc = *s++;
|
||||
} while (toupper((unsigned char)c) != toupper((unsigned char)sc));
|
||||
if (len > slen) return NULL;
|
||||
} while (strncasecmp(s, find, len) != 0);
|
||||
} while (strncasecmp(s, find, len));
|
||||
s--;
|
||||
}
|
||||
return (char *)s;
|
||||
return s;
|
||||
}
|
||||
|
||||
static inline bool is_letter(char c)
|
||||
@@ -109,7 +111,7 @@ bool load_file(const char *filename, off_t offset, void *buffer, size_t *buffer_
|
||||
|
||||
if (offset)
|
||||
{
|
||||
if (-1 == lseek(fileno(F), offset, SEEK_SET))
|
||||
if (fseek(F, offset, SEEK_SET))
|
||||
{
|
||||
fclose(F);
|
||||
return false;
|
||||
@@ -126,27 +128,24 @@ bool load_file(const char *filename, off_t offset, void *buffer, size_t *buffer_
|
||||
fclose(F);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool load_file_nonempty(const char *filename, off_t offset, void *buffer, size_t *buffer_size)
|
||||
{
|
||||
bool b = load_file(filename, offset, buffer, buffer_size);
|
||||
return b && *buffer_size;
|
||||
}
|
||||
bool save_file(const char *filename, const void *buffer, size_t buffer_size)
|
||||
{
|
||||
FILE *F;
|
||||
|
||||
F = fopen(filename, "wb");
|
||||
if (!F) return false;
|
||||
|
||||
fwrite(buffer, 1, buffer_size, F);
|
||||
size_t wr = fwrite(buffer, 1, buffer_size, F);
|
||||
if (ferror(F))
|
||||
{
|
||||
fclose(F);
|
||||
return false;
|
||||
}
|
||||
|
||||
fclose(F);
|
||||
if (wr!=buffer_size)
|
||||
{
|
||||
errno = EIO;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool append_to_list_file(const char *filename, const char *s)
|
||||
@@ -262,50 +261,6 @@ void print_sockaddr(const struct sockaddr *sa)
|
||||
printf("%s", ip_port);
|
||||
}
|
||||
|
||||
bool pton4_port(const char *s, struct sockaddr_in *sa)
|
||||
{
|
||||
char ip[16],*p;
|
||||
size_t l;
|
||||
unsigned int u;
|
||||
|
||||
p = strchr(s,':');
|
||||
if (!p) return false;
|
||||
l = p-s;
|
||||
if (l<7 || l>15) return false;
|
||||
memcpy(ip,s,l);
|
||||
ip[l]=0;
|
||||
p++;
|
||||
|
||||
sa->sin_family = AF_INET;
|
||||
if (inet_pton(AF_INET,ip,&sa->sin_addr)!=1 || sscanf(p,"%u",&u)!=1 || !u || u>0xFFFF) return false;
|
||||
sa->sin_port = htons((uint16_t)u);
|
||||
|
||||
return true;
|
||||
}
|
||||
bool pton6_port(const char *s, struct sockaddr_in6 *sa)
|
||||
{
|
||||
char ip[40],*p;
|
||||
size_t l;
|
||||
unsigned int u;
|
||||
|
||||
if (*s++!='[') return false;
|
||||
p = strchr(s,']');
|
||||
if (!p || p[1]!=':') return false;
|
||||
l = p-s;
|
||||
if (l<2 || l>39) return false;
|
||||
p+=2;
|
||||
memcpy(ip,s,l);
|
||||
ip[l]=0;
|
||||
|
||||
sa->sin6_family = AF_INET6;
|
||||
if (inet_pton(AF_INET6,ip,&sa->sin6_addr)!=1 || sscanf(p,"%u",&u)!=1 || !u || u>0xFFFF) return false;
|
||||
sa->sin6_port = htons((uint16_t)u);
|
||||
sa->sin6_flowinfo = 0;
|
||||
sa->sin6_scope_id = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint16_t saport(const struct sockaddr *sa)
|
||||
{
|
||||
return ntohs(sa->sa_family==AF_INET ? ((struct sockaddr_in*)sa)->sin_port :
|
||||
@@ -367,6 +322,19 @@ void phton32(uint8_t *p, uint32_t v)
|
||||
p[2] = (uint8_t)(v>>8);
|
||||
p[3] = (uint8_t)v;
|
||||
}
|
||||
uint64_t pntoh48(const uint8_t *p)
|
||||
{
|
||||
return ((uint64_t)p[0] << 40) | ((uint64_t)p[1] << 32) | ((uint64_t)p[2] << 24) | ((uint64_t)p[3] << 16) | ((uint64_t)p[4] << 8) | p[5];
|
||||
}
|
||||
void phton48(uint8_t *p, uint64_t v)
|
||||
{
|
||||
p[0] = (uint8_t)(v>>40);
|
||||
p[1] = (uint8_t)(v>>32);
|
||||
p[2] = (uint8_t)(v>>24);
|
||||
p[3] = (uint8_t)(v>>16);
|
||||
p[4] = (uint8_t)(v>>8);
|
||||
p[5] = (uint8_t)v;
|
||||
}
|
||||
uint64_t pntoh64(const uint8_t *p)
|
||||
{
|
||||
return ((uint64_t)p[0] << 56) | ((uint64_t)p[1] << 48) | ((uint64_t)p[2] << 40) | ((uint64_t)p[3] << 32) | ((uint64_t)p[4] << 24) | ((uint64_t)p[5] << 16) | ((uint64_t)p[6] << 8) | p[7];
|
||||
@@ -383,6 +351,20 @@ void phton64(uint8_t *p, uint64_t v)
|
||||
p[7] = (uint8_t)v;
|
||||
}
|
||||
|
||||
uint16_t bswap16(uint16_t u)
|
||||
{
|
||||
// __builtin_bswap16 is absent in ancient lexra gcc 4.6
|
||||
return (u>>8) | ((u&0xFF)<<8);
|
||||
}
|
||||
uint32_t bswap24(uint32_t u)
|
||||
{
|
||||
return (u>>16) & 0xFF | u & 0xFF00 | (u<<16) & 0xFF0000;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
#define INVALID_HEX_DIGIT ((uint8_t)-1)
|
||||
static inline uint8_t parse_hex_digit(char c)
|
||||
@@ -468,118 +450,17 @@ bool file_open_test(const char *filename, int flags)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool pf_in_range(uint16_t port, const port_filter *pf)
|
||||
{
|
||||
return port && (((!pf->from && !pf->to) || (port>=pf->from && port<=pf->to)) ^ pf->neg);
|
||||
}
|
||||
bool pf_parse(const char *s, port_filter *pf)
|
||||
{
|
||||
unsigned int v1,v2;
|
||||
char c;
|
||||
|
||||
if (!s) return false;
|
||||
if (*s=='*' && s[1]==0)
|
||||
{
|
||||
pf->from=1; pf->to=0xFFFF;
|
||||
return true;
|
||||
}
|
||||
if (*s=='~')
|
||||
{
|
||||
pf->neg=true;
|
||||
s++;
|
||||
}
|
||||
else
|
||||
pf->neg=false;
|
||||
if (sscanf(s,"%u-%u%c",&v1,&v2,&c)==2)
|
||||
{
|
||||
if (v1>65535 || v2>65535 || v1>v2) return false;
|
||||
pf->from=(uint16_t)v1;
|
||||
pf->to=(uint16_t)v2;
|
||||
}
|
||||
else if (sscanf(s,"%u%c",&v1,&c)==1)
|
||||
{
|
||||
if (v1>65535) return false;
|
||||
pf->to=pf->from=(uint16_t)v1;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
// deny all case
|
||||
if (!pf->from && !pf->to) pf->neg=true;
|
||||
return true;
|
||||
}
|
||||
bool pf_is_empty(const port_filter *pf)
|
||||
{
|
||||
return !pf->neg && !pf->from && !pf->to;
|
||||
}
|
||||
|
||||
bool packet_pos_parse(const char *s, struct packet_pos *pos)
|
||||
{
|
||||
if (*s!='n' && *s!='d' && *s!='s' && *s!='p' && *s!='b' && *s!='x' && *s!='a') return false;
|
||||
pos->mode=*s;
|
||||
if (pos->mode=='x' || pos->mode=='a')
|
||||
{
|
||||
pos->pos=0;
|
||||
return true;
|
||||
}
|
||||
return sscanf(s+1,"%u",&pos->pos)==1;
|
||||
}
|
||||
bool packet_range_parse(const char *s, struct packet_range *range)
|
||||
{
|
||||
const char *p;
|
||||
|
||||
range->upper_cutoff = false;
|
||||
if (*s=='-' || *s=='<')
|
||||
{
|
||||
range->from = PACKET_POS_ALWAYS;
|
||||
range->upper_cutoff = *s=='<';
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!packet_pos_parse(s,&range->from)) return false;
|
||||
if (range->from.mode=='x')
|
||||
{
|
||||
range->to = range->from;
|
||||
return true;
|
||||
}
|
||||
if (!(p = strchr(s,'-')))
|
||||
p = strchr(s,'<');
|
||||
if (p)
|
||||
{
|
||||
s = p;
|
||||
range->upper_cutoff = *s=='<';
|
||||
}
|
||||
else
|
||||
{
|
||||
if (range->from.mode=='a')
|
||||
{
|
||||
range->to = range->from;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
s++;
|
||||
if (*s)
|
||||
{
|
||||
return packet_pos_parse(s,&range->to);
|
||||
}
|
||||
else
|
||||
{
|
||||
range->to = PACKET_POS_ALWAYS;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
@@ -601,12 +482,55 @@ bool fill_crypto_random_bytes(uint8_t *p,size_t sz)
|
||||
return b;
|
||||
}
|
||||
|
||||
#if defined(__GNUC__) && !defined(__llvm__)
|
||||
__attribute__((optimize ("no-strict-aliasing")))
|
||||
#endif
|
||||
void bxor(const uint8_t *x1, const uint8_t *x2, uint8_t *result, size_t sz)
|
||||
{
|
||||
for (; sz>=8 ; x1+=8, x2+=8, result+=8, sz-=8)
|
||||
*(uint64_t*)result = *(uint64_t*)x1 ^ *(uint64_t*)x2;
|
||||
for (; sz ; x1++, x2++, result++, sz--)
|
||||
*result = *x1 ^ *x2;
|
||||
}
|
||||
#if defined(__GNUC__) && !defined(__llvm__)
|
||||
__attribute__((optimize ("no-strict-aliasing")))
|
||||
#endif
|
||||
void bor(const uint8_t *x1, const uint8_t *x2, uint8_t *result, size_t sz)
|
||||
{
|
||||
for (; sz>=8 ; x1+=8, x2+=8, result+=8, sz-=8)
|
||||
*(uint64_t*)result = *(uint64_t*)x1 | *(uint64_t*)x2;
|
||||
for (; sz ; x1++, x2++, result++, sz--)
|
||||
*result = *x1 | *x2;
|
||||
}
|
||||
#if defined(__GNUC__) && !defined(__llvm__)
|
||||
__attribute__((optimize ("no-strict-aliasing")))
|
||||
#endif
|
||||
void band(const uint8_t *x1, const uint8_t *x2, uint8_t *result, size_t sz)
|
||||
{
|
||||
for (; sz>=8 ; x1+=8, x2+=8, result+=8, sz-=8)
|
||||
*(uint64_t*)result = *(uint64_t*)x1 & *(uint64_t*)x2;
|
||||
for (; sz ; x1++, x2++, result++, sz--)
|
||||
*result = *x1 & *x2;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void set_console_io_buffering(void)
|
||||
{
|
||||
setvbuf(stdout, NULL, _IOLBF, 0);
|
||||
setvbuf(stderr, NULL, _IOLBF, 0);
|
||||
}
|
||||
void close_std(void)
|
||||
{
|
||||
// free memory allocated by setvbuf
|
||||
fclose(stdout);
|
||||
fclose(stderr);
|
||||
}
|
||||
void close_std_and_exit(int code)
|
||||
{
|
||||
close_std();
|
||||
exit(code);
|
||||
}
|
||||
|
||||
bool set_env_exedir(const char *argv0)
|
||||
{
|
||||
@@ -615,108 +539,12 @@ 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)
|
||||
{
|
||||
char s_ip[16];
|
||||
*s_ip=0;
|
||||
inet_ntop(AF_INET, &cidr->addr, s_ip, sizeof(s_ip));
|
||||
snprintf(s,s_len,cidr->preflen<32 ? "%s/%u" : "%s", s_ip, cidr->preflen);
|
||||
}
|
||||
void print_cidr4(const struct cidr4 *cidr)
|
||||
{
|
||||
char s[19];
|
||||
str_cidr4(s,sizeof(s),cidr);
|
||||
printf("%s",s);
|
||||
}
|
||||
void str_cidr6(char *s, size_t s_len, const struct cidr6 *cidr)
|
||||
{
|
||||
char s_ip[40];
|
||||
*s_ip=0;
|
||||
inet_ntop(AF_INET6, &cidr->addr, s_ip, sizeof(s_ip));
|
||||
snprintf(s,s_len,cidr->preflen<128 ? "%s/%u" : "%s", s_ip, cidr->preflen);
|
||||
}
|
||||
void print_cidr6(const struct cidr6 *cidr)
|
||||
{
|
||||
char s[44];
|
||||
str_cidr6(s,sizeof(s),cidr);
|
||||
printf("%s",s);
|
||||
}
|
||||
bool parse_cidr4(char *s, struct cidr4 *cidr)
|
||||
{
|
||||
char *p,d;
|
||||
bool b;
|
||||
unsigned int plen;
|
||||
|
||||
if ((p = strchr(s, '/')))
|
||||
{
|
||||
if (sscanf(p + 1, "%u", &plen)!=1 || plen>32)
|
||||
return false;
|
||||
cidr->preflen = (uint8_t)plen;
|
||||
d=*p; *p=0; // backup char
|
||||
}
|
||||
else
|
||||
cidr->preflen = 32;
|
||||
b = (inet_pton(AF_INET, s, &cidr->addr)==1);
|
||||
if (p) *p=d; // restore char
|
||||
return b;
|
||||
}
|
||||
bool parse_cidr6(char *s, struct cidr6 *cidr)
|
||||
{
|
||||
char *p,d;
|
||||
bool b;
|
||||
unsigned int plen;
|
||||
|
||||
if ((p = strchr(s, '/')))
|
||||
{
|
||||
if (sscanf(p + 1, "%u", &plen)!=1 || plen>128)
|
||||
return false;
|
||||
cidr->preflen = (uint8_t)plen;
|
||||
d=*p; *p=0; // backup char
|
||||
}
|
||||
else
|
||||
cidr->preflen = 128;
|
||||
b = (inet_pton(AF_INET6, s, &cidr->addr)==1);
|
||||
if (p) *p=d; // restore char
|
||||
return b;
|
||||
}
|
||||
|
||||
bool parse_int16(const char *p, int16_t *v)
|
||||
{
|
||||
if (*p == '+' || *p == '-' || *p >= '0' && *p <= '9')
|
||||
@@ -727,3 +555,29 @@ bool parse_int16(const char *p, int16_t *v)
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t mask_from_bitcount(uint32_t zct)
|
||||
{
|
||||
return zct<32 ? ~((1u << zct) - 1) : 0;
|
||||
}
|
||||
static void mask_from_bitcount6_make(uint32_t zct, struct in6_addr *a)
|
||||
{
|
||||
if (zct >= 128)
|
||||
memset(a->s6_addr,0x00,16);
|
||||
else
|
||||
{
|
||||
int32_t n = (127 - zct) >> 3;
|
||||
memset(a->s6_addr,0xFF,n);
|
||||
memset(a->s6_addr+n,0x00,16-n);
|
||||
a->s6_addr[n] = ~((1u << (zct & 7)) - 1);
|
||||
}
|
||||
}
|
||||
static struct in6_addr ip6_mask[129];
|
||||
void mask_from_bitcount6_prepare(void)
|
||||
{
|
||||
for (int zct=0;zct<=128;zct++) mask_from_bitcount6_make(zct, ip6_mask+zct);
|
||||
}
|
||||
const struct in6_addr *mask_from_bitcount6(uint32_t zct)
|
||||
{
|
||||
return ip6_mask+zct;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#define UNARY_PLUS(v) (v>0 ? "+" : "")
|
||||
|
||||
@@ -28,12 +29,11 @@ void qsort_ssize_t(ssize_t *array, int ct);
|
||||
int str_index(const char **strs, int count, const char *str);
|
||||
void rtrim(char *s);
|
||||
void replace_char(char *s, char from, char to);
|
||||
char *strncasestr(const char *s,const char *find, size_t slen);
|
||||
const char *strncasestr(const char *s,const char *find, size_t slen);
|
||||
// [a-zA-z][a-zA-Z0-9]*
|
||||
bool is_identifier(const char *p);
|
||||
|
||||
bool load_file(const char *filename, off_t offset, void *buffer, size_t *buffer_size);
|
||||
bool load_file_nonempty(const char *filename, off_t offset, void *buffer, size_t *buffer_size);
|
||||
bool save_file(const char *filename, const void *buffer, size_t buffer_size);
|
||||
bool append_to_list_file(const char *filename, const char *s);
|
||||
|
||||
@@ -45,8 +45,6 @@ void print_sockaddr(const struct sockaddr *sa);
|
||||
void ntopa46(const struct in_addr *ip, const struct in6_addr *ip6,char *str, size_t len);
|
||||
void ntop46(const struct sockaddr *sa, char *str, size_t len);
|
||||
void ntop46_port(const struct sockaddr *sa, char *str, size_t len);
|
||||
bool pton4_port(const char *s, struct sockaddr_in *sa);
|
||||
bool pton6_port(const char *s, struct sockaddr_in6 *sa);
|
||||
|
||||
uint16_t saport(const struct sockaddr *sa);
|
||||
bool sa_has_addr(const struct sockaddr *sa);
|
||||
@@ -61,9 +59,15 @@ uint32_t pntoh24(const uint8_t *p);
|
||||
void phton24(uint8_t *p, uint32_t v);
|
||||
uint32_t pntoh32(const uint8_t *p);
|
||||
void phton32(uint8_t *p, uint32_t v);
|
||||
uint64_t pntoh48(const uint8_t *p);
|
||||
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 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);
|
||||
|
||||
@@ -81,67 +85,22 @@ time_t file_mod_time(const char *filename);
|
||||
bool file_size(const char *filename, off_t *size);
|
||||
bool file_open_test(const char *filename, int flags);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t from,to;
|
||||
bool neg;
|
||||
} port_filter;
|
||||
bool pf_in_range(uint16_t port, const port_filter *pf);
|
||||
bool pf_parse(const char *s, port_filter *pf);
|
||||
bool pf_is_empty(const port_filter *pf);
|
||||
|
||||
struct packet_pos
|
||||
{
|
||||
char mode; // n - packets, d - data packets, s - relative sequence
|
||||
unsigned int pos;
|
||||
};
|
||||
struct packet_range
|
||||
{
|
||||
struct packet_pos from, to;
|
||||
bool upper_cutoff; // true - do not include upper limit, false - include upper limit
|
||||
};
|
||||
#define PACKET_POS_NEVER (struct packet_pos){'x',0}
|
||||
#define PACKET_POS_ALWAYS (struct packet_pos){'a',0}
|
||||
#define PACKET_RANGE_NEVER (struct packet_range){PACKET_POS_NEVER,PACKET_POS_NEVER}
|
||||
#define PACKET_RANGE_ALWAYS (struct packet_range){PACKET_POS_ALWAYS,PACKET_POS_ALWAYS}
|
||||
bool packet_range_parse(const char *s, struct packet_range *range);
|
||||
|
||||
void fill_random_bytes(uint8_t *p,size_t sz);
|
||||
void fill_random_az(uint8_t *p,size_t sz);
|
||||
void fill_random_az09(uint8_t *p,size_t sz);
|
||||
bool fill_crypto_random_bytes(uint8_t *p,size_t sz);
|
||||
|
||||
void bxor(const uint8_t *x1, const uint8_t *x2, uint8_t *result, size_t sz);
|
||||
void band(const uint8_t *x1, const uint8_t *x2, uint8_t *result, size_t sz);
|
||||
void bor(const uint8_t *x1, const uint8_t *x2, uint8_t *result, size_t sz);
|
||||
|
||||
void set_console_io_buffering(void);
|
||||
void close_std(void);
|
||||
void close_std_and_exit(int code);
|
||||
bool set_env_exedir(const char *argv0);
|
||||
|
||||
|
||||
struct cidr4
|
||||
{
|
||||
struct in_addr addr;
|
||||
uint8_t preflen;
|
||||
};
|
||||
struct cidr6
|
||||
{
|
||||
struct in6_addr addr;
|
||||
uint8_t preflen;
|
||||
};
|
||||
void str_cidr4(char *s, size_t s_len, const struct cidr4 *cidr);
|
||||
void print_cidr4(const struct cidr4 *cidr);
|
||||
void str_cidr6(char *s, size_t s_len, const struct cidr6 *cidr);
|
||||
void print_cidr6(const struct cidr6 *cidr);
|
||||
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;
|
||||
}
|
||||
uint32_t mask_from_bitcount(uint32_t zct);
|
||||
void mask_from_bitcount6_prepare(void);
|
||||
const struct in6_addr *mask_from_bitcount6(uint32_t zct);
|
||||
|
||||
@@ -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((unsigned char)*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;
|
||||
@@ -45,7 +42,7 @@ bool AppendHostlistItem(hostlist_pool **hostlist, char *s)
|
||||
|
||||
bool AppendHostList(hostlist_pool **hostlist, const char *filename)
|
||||
{
|
||||
char *p, *e, s[256], *zbuf;
|
||||
char *p, *e, s[4096], *zbuf;
|
||||
size_t zsize;
|
||||
int ct = 0;
|
||||
FILE *F;
|
||||
@@ -61,7 +58,7 @@ bool AppendHostList(hostlist_pool **hostlist, const char *filename)
|
||||
|
||||
if (is_gzip(F))
|
||||
{
|
||||
r = z_readfile(F,&zbuf,&zsize);
|
||||
r = z_readfile(F,&zbuf,&zsize,0);
|
||||
fclose(F);
|
||||
if (r==Z_OK)
|
||||
{
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -116,10 +113,18 @@ static bool LoadHostList(struct hostlist_file *hfile)
|
||||
{
|
||||
// stat() error
|
||||
DLOG_PERROR("file_mod_signature");
|
||||
DLOG_ERR("cannot access hostlist file '%s'. in-memory content remains unchanged.\n",hfile->filename);
|
||||
return true;
|
||||
goto unchanged;
|
||||
}
|
||||
if (FILE_MOD_COMPARE(&hfile->mod_sig,&fsig)) return true; // up to date
|
||||
// check if it's readable. do not destroy in-memory copy if not
|
||||
if (!file_open_test(hfile->filename, O_RDONLY))
|
||||
{
|
||||
DLOG_PERROR("file_open_test");
|
||||
goto unchanged;
|
||||
}
|
||||
// don't want to keep backup copy in memory - it will require *2 RAM. Problem on low-ram devices. It's better to fail hostlist read than have OOM.
|
||||
// if a file can be opened there're few chances it can't be read. fs corruption, disk error, deleted or made inaccessible between 2 syscals ?
|
||||
// it's all hypotetically possible but very unlikely. but OOM is much more real problem on an embedded device if list is large enough
|
||||
HostlistPoolDestroy(&hfile->hostlist);
|
||||
if (!AppendHostList(&hfile->hostlist, hfile->filename))
|
||||
{
|
||||
@@ -129,6 +134,9 @@ static bool LoadHostList(struct hostlist_file *hfile)
|
||||
hfile->mod_sig=fsig;
|
||||
}
|
||||
return true;
|
||||
unchanged:
|
||||
DLOG_ERR("cannot access hostlist file '%s'. in-memory content remains unchanged.\n",hfile->filename);
|
||||
return true;
|
||||
}
|
||||
static bool LoadHostLists(struct hostlist_files_head *list)
|
||||
{
|
||||
|
||||
51
nfq2/ipset.c
51
nfq2/ipset.c
@@ -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;
|
||||
@@ -60,7 +59,7 @@ bool AppendIpsetItem(ipset *ips, char *ip)
|
||||
|
||||
static bool AppendIpset(ipset *ips, const char *filename)
|
||||
{
|
||||
char *p, *e, s[256], *zbuf;
|
||||
char *p, *e, s[4096], *zbuf;
|
||||
size_t zsize;
|
||||
int ct = 0;
|
||||
FILE *F;
|
||||
@@ -76,7 +75,7 @@ static bool AppendIpset(ipset *ips, const char *filename)
|
||||
|
||||
if (is_gzip(F))
|
||||
{
|
||||
r = z_readfile(F,&zbuf,&zsize);
|
||||
r = z_readfile(F,&zbuf,&zsize,0);
|
||||
fclose(F);
|
||||
if (r==Z_OK)
|
||||
{
|
||||
@@ -131,10 +130,18 @@ static bool LoadIpset(struct ipset_file *hfile)
|
||||
{
|
||||
// stat() error
|
||||
DLOG_PERROR("file_mod_signature");
|
||||
DLOG_ERR("cannot access ipset file '%s'. in-memory content remains unchanged.\n",hfile->filename);
|
||||
return true;
|
||||
goto unchanged;
|
||||
}
|
||||
if (FILE_MOD_COMPARE(&hfile->mod_sig,&fsig)) return true; // up to date
|
||||
// check if it's readable. do not destroy in-memory copy if not
|
||||
if (!file_open_test(hfile->filename, O_RDONLY))
|
||||
{
|
||||
DLOG_PERROR("file_open_test");
|
||||
goto unchanged;
|
||||
}
|
||||
// don't want to keep backup copy in memory - it will require *2 RAM. Problem on low-ram devices. It's better to fail ipset read than have OOM.
|
||||
// if a file can be opened there're few chances it can't be read. fs corruption, disk error, deleted or made inaccessible between 2 syscals ?
|
||||
// it's all hypotetically possible but very unlikely. but OOM is much more real problem on an embedded device if list is large enough
|
||||
ipsetDestroy(&hfile->ipset);
|
||||
if (!AppendIpset(&hfile->ipset, hfile->filename))
|
||||
{
|
||||
@@ -144,6 +151,9 @@ static bool LoadIpset(struct ipset_file *hfile)
|
||||
hfile->mod_sig=fsig;
|
||||
}
|
||||
return true;
|
||||
unchanged:
|
||||
DLOG_ERR("cannot access ipset file '%s'. in-memory content remains unchanged.\n",hfile->filename);
|
||||
return true;
|
||||
}
|
||||
static bool LoadIpsets(struct ipset_files_head *list)
|
||||
{
|
||||
@@ -205,7 +215,11 @@ bool IpsetsReloadCheckForProfile(const struct desync_profile *dp)
|
||||
return IpsetsReloadCheck(&dp->ips_collection) && IpsetsReloadCheck(&dp->ips_collection_exclude);
|
||||
}
|
||||
|
||||
static bool IpsetCheck_(const struct ipset_collection_head *ips, const struct ipset_collection_head *ips_exclude, const struct in_addr *ipv4, const struct in6_addr *ipv6)
|
||||
static bool IpsetCheck_(
|
||||
const struct ipset_collection_head *ips, const struct ipset_collection_head *ips_exclude,
|
||||
const struct in_addr *ipv4, const struct in6_addr *ipv6,
|
||||
const struct in_addr *ipv4r, const struct in6_addr *ipv6r
|
||||
)
|
||||
{
|
||||
struct ipset_item *item;
|
||||
|
||||
@@ -217,6 +231,12 @@ static bool IpsetCheck_(const struct ipset_collection_head *ips, const struct ip
|
||||
DLOG("[%s] exclude ",item->hfile->filename ? item->hfile->filename : "fixed");
|
||||
if (SearchIpset(&item->hfile->ipset, ipv4, ipv6))
|
||||
return false;
|
||||
if (ipv4r || ipv6r)
|
||||
{
|
||||
DLOG("[%s] exclude ",item->hfile->filename ? item->hfile->filename : "fixed");
|
||||
if (SearchIpset(&item->hfile->ipset, ipv4r, ipv6r))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// old behavior compat: all include lists are empty means check passes
|
||||
if (!ipset_collection_is_empty(ips))
|
||||
@@ -226,17 +246,26 @@ static bool IpsetCheck_(const struct ipset_collection_head *ips, const struct ip
|
||||
DLOG("[%s] include ",item->hfile->filename ? item->hfile->filename : "fixed");
|
||||
if (SearchIpset(&item->hfile->ipset, ipv4, ipv6))
|
||||
return true;
|
||||
if (ipv4r || ipv6r)
|
||||
{
|
||||
DLOG("[%s] include ",item->hfile->filename ? item->hfile->filename : "fixed");
|
||||
if (SearchIpset(&item->hfile->ipset, ipv4r, ipv6r))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IpsetCheck(const struct desync_profile *dp, const struct in_addr *ipv4, const struct in6_addr *ipv6)
|
||||
bool IpsetCheck(
|
||||
const struct desync_profile *dp,
|
||||
const struct in_addr *ipv4, const struct in6_addr *ipv6,
|
||||
const struct in_addr *ipv4r, const struct in6_addr *ipv6r)
|
||||
{
|
||||
if (PROFILE_IPSETS_ABSENT(dp)) return true;
|
||||
DLOG("* ipset check for profile %u (%s)\n",dp->n,PROFILE_NAME(dp));
|
||||
return IpsetCheck_(&dp->ips_collection,&dp->ips_collection_exclude,ipv4,ipv6);
|
||||
return IpsetCheck_(&dp->ips_collection,&dp->ips_collection_exclude,ipv4,ipv6,ipv4r,ipv6r);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -6,7 +6,10 @@
|
||||
#include "pools.h"
|
||||
|
||||
bool LoadAllIpsets();
|
||||
bool IpsetCheck(const struct desync_profile *dp, const struct in_addr *ipv4, const struct in6_addr *ipv6);
|
||||
bool IpsetCheck(
|
||||
const struct desync_profile *dp,
|
||||
const struct in_addr *ipv4, const struct in6_addr *ipv6,
|
||||
const struct in_addr *ipv4r, const struct in6_addr *ipv6r);
|
||||
struct ipset_file *RegisterIpset(struct desync_profile *dp, bool bExclude, const char *filename);
|
||||
void IpsetsDebug();
|
||||
bool AppendIpsetItem(ipset *ips, char *ip);
|
||||
|
||||
2949
nfq2/lua.c
2949
nfq2/lua.c
File diff suppressed because it is too large
Load Diff
105
nfq2/lua.h
105
nfq2/lua.h
@@ -38,12 +38,12 @@
|
||||
#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);
|
||||
|
||||
|
||||
bool lua_test_init_script_files(void);
|
||||
void lua_req_quit(void);
|
||||
bool lua_init(void);
|
||||
void lua_shutdown(void);
|
||||
void lua_dlog_error(void);
|
||||
@@ -54,62 +54,75 @@ int lua_absindex(lua_State *L, int idx);
|
||||
#define lua_rawlen lua_objlen
|
||||
#endif
|
||||
|
||||
const char *lua_reqlstring(lua_State *L,int idx,size_t *len);
|
||||
const char *lua_reqstring(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_push_ipaddr(lua_State *L, const struct sockaddr *sa);
|
||||
void lua_pushf_ipaddr(lua_State *L, const char *field, const struct sockaddr *sa);
|
||||
void lua_pushi_ipaddr(lua_State *L, lua_Integer idx, const struct sockaddr *sa);
|
||||
void lua_pushi_str(lua_State *L, lua_Integer idx, const char *str);
|
||||
void lua_pushf_tcphdr_options(lua_State *L, const struct tcphdr *tcp, size_t len);
|
||||
void lua_push_tcphdr(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_push_udphdr(lua_State *L, const struct udphdr *udp, size_t len);
|
||||
void lua_pushf_udphdr(lua_State *L, const struct udphdr *udp, size_t len);
|
||||
void lua_pushf_icmphdr(lua_State *L, const struct icmp46 *icmp, size_t len);
|
||||
void lua_push_iphdr(lua_State *L, const struct ip *ip, size_t len);
|
||||
void lua_pushf_iphdr(lua_State *L, const struct ip *ip, size_t len);
|
||||
void lua_push_ip6hdr(lua_State *L, const struct ip6_hdr *ip6, 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_push_ctrack(lua_State *L, const t_ctrack *ctrack, const t_ctrack_positions *tpos, bool bIncoming);
|
||||
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_icmphdr(lua_State *L, int idx, struct icmp46 *icmp);
|
||||
bool lua_reconstruct_dissect(lua_State *L, int idx, uint8_t *buf, size_t *len, bool keepsum, bool badsum, uint8_t last_proto, 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);
|
||||
|
||||
830
nfq2/nfqws.c
830
nfq2/nfqws.c
File diff suppressed because it is too large
Load Diff
@@ -1,15 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <signal.h>
|
||||
|
||||
#ifdef __linux__
|
||||
#define HAS_FILTER_SSID 1
|
||||
#endif
|
||||
|
||||
#ifdef __CYGWIN__
|
||||
extern bool bQuit;
|
||||
extern volatile sig_atomic_t bQuit;
|
||||
#endif
|
||||
int main(int argc, char *argv[]);
|
||||
|
||||
// when something changes that can break LUA compatibility this version should be increased
|
||||
#define LUA_COMPAT_VER 3
|
||||
#define LUA_COMPAT_VER 5
|
||||
|
||||
@@ -337,6 +337,8 @@ void dp_init_dynamic(struct desync_profile *dp)
|
||||
LIST_INIT(&dp->ips_collection_exclude);
|
||||
LIST_INIT(&dp->pf_tcp);
|
||||
LIST_INIT(&dp->pf_udp);
|
||||
LIST_INIT(&dp->icf);
|
||||
LIST_INIT(&dp->ipf);
|
||||
LIST_INIT(&dp->lua_desync);
|
||||
#ifdef HAS_FILTER_SSID
|
||||
LIST_INIT(&dp->filter_ssid);
|
||||
@@ -354,12 +356,10 @@ void dp_init(struct desync_profile *dp)
|
||||
dp->hostlist_auto_incoming_maxseq = HOSTLIST_AUTO_INCOMING_MAXSEQ;
|
||||
dp->hostlist_auto_udp_out = HOSTLIST_AUTO_UDP_OUT;
|
||||
dp->hostlist_auto_udp_in = HOSTLIST_AUTO_UDP_IN;
|
||||
dp->filter_ipv4 = dp->filter_ipv6 = true;
|
||||
}
|
||||
static void dp_clear_dynamic(struct desync_profile *dp)
|
||||
{
|
||||
free(dp->name);
|
||||
free(dp->name_tpl);
|
||||
free(dp->cookie);
|
||||
|
||||
hostlist_collection_destroy(&dp->hl_collection);
|
||||
@@ -368,6 +368,8 @@ static void dp_clear_dynamic(struct desync_profile *dp)
|
||||
ipset_collection_destroy(&dp->ips_collection_exclude);
|
||||
port_filters_destroy(&dp->pf_tcp);
|
||||
port_filters_destroy(&dp->pf_udp);
|
||||
icmp_filters_destroy(&dp->icf);
|
||||
ipp_filters_destroy(&dp->ipf);
|
||||
funclist_destroy(&dp->lua_desync);
|
||||
#ifdef HAS_FILTER_SSID
|
||||
strlist_destroy(&dp->filter_ssid);
|
||||
@@ -411,18 +413,48 @@ struct desync_profile_list *dp_list_add(struct desync_profile_list_head *head)
|
||||
|
||||
return entry;
|
||||
}
|
||||
bool dp_list_copy(struct desync_profile *to, const struct desync_profile *from)
|
||||
#define DP_COPY_SIMPLE(v) if (from->b_##v) {to->v=from->v; to->b_##v=true;}
|
||||
bool dp_copy(struct desync_profile *to, const struct desync_profile *from)
|
||||
{
|
||||
// clear everything in target
|
||||
dp_clear(to);
|
||||
// first copy all simple type values
|
||||
*to = *from;
|
||||
// prepare empty dynamic structures
|
||||
dp_init_dynamic(to);
|
||||
DP_COPY_SIMPLE(hostlist_auto_fail_threshold)
|
||||
DP_COPY_SIMPLE(hostlist_auto_fail_time)
|
||||
DP_COPY_SIMPLE(hostlist_auto_retrans_threshold)
|
||||
DP_COPY_SIMPLE(hostlist_auto_retrans_maxseq)
|
||||
DP_COPY_SIMPLE(hostlist_auto_incoming_maxseq)
|
||||
DP_COPY_SIMPLE(hostlist_auto_retrans_reset)
|
||||
DP_COPY_SIMPLE(hostlist_auto_udp_out)
|
||||
DP_COPY_SIMPLE(hostlist_auto_udp_in)
|
||||
DP_COPY_SIMPLE(filter_l7)
|
||||
if (from->b_filter_l3)
|
||||
{
|
||||
if (to->b_filter_l3)
|
||||
{
|
||||
to->filter_ipv4 |= from->filter_ipv4;
|
||||
to->filter_ipv6 |= from->filter_ipv6;
|
||||
}
|
||||
else
|
||||
{
|
||||
to->filter_ipv4 = from->filter_ipv4;
|
||||
to->filter_ipv6 = from->filter_ipv6;
|
||||
to->b_filter_l3 = true;
|
||||
}
|
||||
}
|
||||
|
||||
// copy dynamic structures
|
||||
if (from->name && !(to->name = strdup(from->name))) return false;
|
||||
if (from->name_tpl && !(to->name_tpl = strdup(from->name_tpl))) return false;
|
||||
if (from->cookie && !(to->cookie = strdup(from->cookie))) return false;
|
||||
if (from->cookie)
|
||||
{
|
||||
free(to->cookie);
|
||||
if (!(to->cookie = strdup(from->cookie))) return false;
|
||||
}
|
||||
if (from->hostlist_auto)
|
||||
{
|
||||
if (to->hostlist_auto)
|
||||
{
|
||||
DLOG_ERR("autohostlist replacement is not supported\n");
|
||||
return false;
|
||||
}
|
||||
to->hostlist_auto = from->hostlist_auto;
|
||||
}
|
||||
if (
|
||||
#ifdef HAS_FILTER_SSID
|
||||
!strlist_copy(&to->filter_ssid, &from->filter_ssid) ||
|
||||
@@ -431,8 +463,13 @@ bool dp_list_copy(struct desync_profile *to, const struct desync_profile *from)
|
||||
!ipset_collection_copy(&to->ips_collection, &from->ips_collection) ||
|
||||
!ipset_collection_copy(&to->ips_collection_exclude, &from->ips_collection_exclude) ||
|
||||
!hostlist_collection_copy(&to->hl_collection, &from->hl_collection) ||
|
||||
!hostlist_collection_copy(&to->hl_collection_exclude, &from->hl_collection_exclude))
|
||||
!hostlist_collection_copy(&to->hl_collection_exclude, &from->hl_collection_exclude) ||
|
||||
!port_filters_copy(&to->pf_tcp, &from->pf_tcp) ||
|
||||
!port_filters_copy(&to->pf_udp, &from->pf_udp) ||
|
||||
!icmp_filters_copy(&to->icf, &from->icf) ||
|
||||
!ipp_filters_copy(&to->ipf, &from->ipf))
|
||||
{
|
||||
DLOG_ERR("dynamic structure copy failed\n");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -475,11 +512,34 @@ void cleanup_windivert_portfilters(struct params_s *params)
|
||||
{
|
||||
char **wdbufs[] =
|
||||
{¶ms->wf_pf_tcp_src_in, ¶ms->wf_pf_tcp_dst_in, ¶ms->wf_pf_udp_src_in, ¶ms->wf_pf_udp_dst_in,
|
||||
¶ms->wf_pf_tcp_src_out, ¶ms->wf_pf_tcp_dst_out, ¶ms->wf_pf_udp_src_out, ¶ms->wf_pf_udp_dst_out};
|
||||
¶ms->wf_pf_tcp_src_out, ¶ms->wf_pf_tcp_dst_out, ¶ms->wf_pf_udp_src_out, ¶ms->wf_pf_udp_dst_out,
|
||||
¶ms->wf_icf_in, ¶ms->wf_icf_out,
|
||||
¶ms->wf_ipf_in, ¶ms->wf_ipf_out,
|
||||
¶ms->wf_raw_filter};
|
||||
for (int i=0 ; i<(sizeof(wdbufs)/sizeof(*wdbufs)) ; i++)
|
||||
{
|
||||
free(*wdbufs[i]); *wdbufs[i] = NULL;
|
||||
free(*wdbufs[i]);
|
||||
*wdbufs[i] = NULL;
|
||||
}
|
||||
strlist_destroy(¶ms->wf_raw_part);
|
||||
}
|
||||
bool alloc_windivert_portfilters(struct params_s *params)
|
||||
{
|
||||
char **wdbufs[] =
|
||||
{¶ms->wf_pf_tcp_src_in, ¶ms->wf_pf_tcp_dst_in, ¶ms->wf_pf_udp_src_in, ¶ms->wf_pf_udp_dst_in,
|
||||
¶ms->wf_pf_tcp_src_out, ¶ms->wf_pf_tcp_dst_out, ¶ms->wf_pf_udp_src_out, ¶ms->wf_pf_udp_dst_out,
|
||||
¶ms->wf_icf_in, ¶ms->wf_icf_out,
|
||||
¶ms->wf_ipf_in, ¶ms->wf_ipf_out};
|
||||
for (int i=0 ; i<(sizeof(wdbufs)/sizeof(*wdbufs)) ; i++)
|
||||
{
|
||||
if (!(*wdbufs[i] = malloc(WINDIVERT_PORTFILTER_MAX)))
|
||||
return false;
|
||||
**wdbufs[i] = 0;
|
||||
}
|
||||
if (!(params->wf_raw_filter = malloc(WINDIVERT_MAX)))
|
||||
return false;
|
||||
*params->wf_raw_filter = 0;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
void cleanup_params(struct params_s *params)
|
||||
@@ -496,6 +556,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);
|
||||
@@ -511,6 +574,7 @@ void init_params(struct params_s *params)
|
||||
{
|
||||
memset(params, 0, sizeof(*params));
|
||||
|
||||
params->intercept = true;
|
||||
#ifdef __linux__
|
||||
params->qnum = -1;
|
||||
#elif defined(BSD)
|
||||
@@ -529,6 +593,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
|
||||
|
||||
@@ -59,12 +57,12 @@ struct desync_profile
|
||||
{
|
||||
unsigned int n; // number of the profile
|
||||
char *name; // optional malloced name string
|
||||
unsigned int n_tpl; // number of imported template
|
||||
char *name_tpl; // imported template name
|
||||
char *cookie; // optional malloced string
|
||||
|
||||
bool filter_ipv4,filter_ipv6;
|
||||
struct port_filters_head pf_tcp,pf_udp;
|
||||
struct icmp_filters_head icf;
|
||||
struct ipp_filters_head ipf;
|
||||
uint64_t filter_l7; // L7_PROTO_* bits
|
||||
|
||||
#ifdef HAS_FILTER_SSID
|
||||
@@ -87,8 +85,16 @@ 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;
|
||||
|
||||
// was option set ?
|
||||
bool b_hostlist_auto_fail_threshold, b_hostlist_auto_fail_time,b_hostlist_auto_retrans_threshold;
|
||||
bool b_hostlist_auto_retrans_maxseq, b_hostlist_auto_incoming_maxseq, b_hostlist_auto_retrans_reset;
|
||||
bool b_hostlist_auto_udp_out, b_hostlist_auto_udp_in;
|
||||
bool b_filter_l3, b_filter_l7;
|
||||
|
||||
};
|
||||
#define PROFILE_NAME(dp) ((dp)->name ? (dp)->name : "noname")
|
||||
|
||||
@@ -103,7 +109,7 @@ struct desync_profile_list {
|
||||
LIST_HEAD(desync_profile_list_head, desync_profile_list);
|
||||
struct desync_profile_list *dp_list_add(struct desync_profile_list_head *head);
|
||||
void dp_list_move(struct desync_profile_list_head *target, struct desync_profile_list *dpl);
|
||||
bool dp_list_copy(struct desync_profile *to, const struct desync_profile *from);
|
||||
bool dp_copy(struct desync_profile *to, const struct desync_profile *from);
|
||||
struct desync_profile_list *dp_list_search_name(struct desync_profile_list_head *head, const char *name);
|
||||
void dp_entry_destroy(struct desync_profile_list *entry);
|
||||
void dp_list_destroy(struct desync_profile_list_head *head);
|
||||
@@ -126,7 +132,7 @@ struct params_s
|
||||
char debug_logfile[PATH_MAX];
|
||||
bool debug;
|
||||
|
||||
bool daemon;
|
||||
bool daemon, intercept;
|
||||
|
||||
#ifdef __linux__
|
||||
int qnum;
|
||||
@@ -145,6 +151,8 @@ struct params_s
|
||||
char *windivert_filter;
|
||||
char *wf_pf_tcp_src_in, *wf_pf_tcp_dst_in, *wf_pf_udp_src_in, *wf_pf_udp_dst_in;
|
||||
char *wf_pf_tcp_src_out, *wf_pf_tcp_dst_out, *wf_pf_udp_src_out, *wf_pf_udp_dst_out;
|
||||
char *wf_icf_in, *wf_icf_out, *wf_ipf_in, *wf_ipf_out;
|
||||
char *wf_raw_filter;
|
||||
#else
|
||||
bool droproot;
|
||||
char *user;
|
||||
@@ -176,12 +184,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;
|
||||
};
|
||||
|
||||
@@ -193,6 +203,7 @@ void init_params(struct params_s *params);
|
||||
void cleanup_args(struct params_s *params);
|
||||
#endif
|
||||
#ifdef __CYGWIN__
|
||||
bool alloc_windivert_portfilters(struct params_s *params);
|
||||
void cleanup_windivert_portfilters(struct params_s *params);
|
||||
#endif
|
||||
void cleanup_params(struct params_s *params);
|
||||
|
||||
205
nfq2/pools.c
205
nfq2/pools.c
@@ -68,7 +68,7 @@ hostlist_pool *HostlistPoolGetStr(hostlist_pool *p, const char *s)
|
||||
}
|
||||
bool HostlistPoolCheckStr(hostlist_pool *p, const char *s)
|
||||
{
|
||||
return !!HostlistPoolGetStr(p,s);
|
||||
return HostlistPoolGetStr(p,s);
|
||||
}
|
||||
|
||||
void HostlistPoolDestroy(hostlist_pool **pp)
|
||||
@@ -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)
|
||||
@@ -138,13 +134,17 @@ void HostFailPoolDump(hostfail_pool *p)
|
||||
static struct str_list *strlist_entry_alloc(const char *str)
|
||||
{
|
||||
struct str_list *entry = malloc(sizeof(struct str_list));
|
||||
if (!entry) return false;
|
||||
entry->str = strdup(str);
|
||||
if (!entry->str)
|
||||
if (!entry) return NULL;
|
||||
if (str)
|
||||
{
|
||||
free(entry);
|
||||
return NULL;
|
||||
if (!(entry->str = strdup(str)))
|
||||
{
|
||||
free(entry);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
entry->str = NULL;
|
||||
return entry;
|
||||
}
|
||||
|
||||
@@ -244,14 +244,13 @@ static struct str2_list *str2list_entry_copy(const struct str2_list *entry)
|
||||
{
|
||||
struct str2_list *e2 = str2list_entry_alloc();
|
||||
if (!e2) return NULL;
|
||||
e2->str1 = strdup(entry->str1);
|
||||
e2->str2 = strdup(entry->str2);
|
||||
if (!e2->str1 || !e2->str2)
|
||||
{
|
||||
str2list_entry_destroy(e2);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (entry->str1) if (!(e2->str1 = strdup(entry->str1))) goto err;
|
||||
if (entry->str2) if (!(e2->str2 = strdup(entry->str2))) goto err;
|
||||
return e2;
|
||||
err:
|
||||
str2list_entry_destroy(e2);
|
||||
return NULL;
|
||||
}
|
||||
bool str2list_copy(struct str2_list_head *to, const struct str2_list_head *from)
|
||||
{
|
||||
@@ -287,7 +286,7 @@ void funclist_destroy(struct func_list_head *head)
|
||||
static struct func_list *funclist_entry_alloc(const char *func)
|
||||
{
|
||||
struct func_list *entry = malloc(sizeof(struct func_list));
|
||||
if (!entry) return false;
|
||||
if (!entry) return NULL;
|
||||
entry->func = strdup(func);
|
||||
if (!entry->func)
|
||||
{
|
||||
@@ -321,7 +320,7 @@ static struct func_list *funclist_entry_copy(const struct func_list *entry)
|
||||
if (!str2list_copy(&e2->args, &entry->args))
|
||||
{
|
||||
funclist_entry_destroy(e2);
|
||||
return false;
|
||||
return NULL;
|
||||
}
|
||||
return e2;
|
||||
}
|
||||
@@ -350,7 +349,7 @@ struct hostlist_file *hostlist_files_add(struct hostlist_files_head *head, const
|
||||
if (!(entry->filename = strdup(filename)))
|
||||
{
|
||||
free(entry);
|
||||
return false;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -540,7 +539,7 @@ static bool ipset_kavl_add(struct kavl_bit_elem **ipset, const void *a, uint8_t
|
||||
|
||||
bool ipset4Check(const struct kavl_bit_elem *ipset, const struct in_addr *a, uint8_t preflen)
|
||||
{
|
||||
return !!kavl_bit_get(ipset,a,preflen);
|
||||
return kavl_bit_get(ipset,a,preflen);
|
||||
}
|
||||
bool ipset4Add(struct kavl_bit_elem **ipset, const struct in_addr *a, uint8_t preflen)
|
||||
{
|
||||
@@ -568,7 +567,7 @@ void ipset4Print(struct kavl_bit_elem *ipset)
|
||||
|
||||
bool ipset6Check(const struct kavl_bit_elem *ipset, const struct in6_addr *a, uint8_t preflen)
|
||||
{
|
||||
return !!kavl_bit_get(ipset,a,preflen);
|
||||
return kavl_bit_get(ipset,a,preflen);
|
||||
}
|
||||
bool ipset6Add(struct kavl_bit_elem **ipset, const struct in6_addr *a, uint8_t preflen)
|
||||
{
|
||||
@@ -616,7 +615,7 @@ struct ipset_file *ipset_files_add(struct ipset_files_head *head, const char *fi
|
||||
if (!(entry->filename = strdup(filename)))
|
||||
{
|
||||
free(entry);
|
||||
return false;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -724,16 +723,35 @@ bool ipset_collection_is_empty(const struct ipset_collection_head *head)
|
||||
}
|
||||
|
||||
|
||||
bool port_filter_add(struct port_filters_head *head, const port_filter *pf)
|
||||
static struct port_filter_item *port_filter_entry_alloc(const port_filter *pf)
|
||||
{
|
||||
struct port_filter_item *entry = malloc(sizeof(struct port_filter_item));
|
||||
if (entry)
|
||||
{
|
||||
entry->pf = *pf;
|
||||
LIST_INSERT_HEAD(head, entry, next);
|
||||
}
|
||||
if (entry) entry->pf = *pf;
|
||||
return entry;
|
||||
}
|
||||
bool port_filter_add(struct port_filters_head *head, const port_filter *pf)
|
||||
{
|
||||
struct port_filter_item *entry = port_filter_entry_alloc(pf);
|
||||
if (entry) LIST_INSERT_HEAD(head, entry, next);
|
||||
return entry;
|
||||
}
|
||||
static struct port_filter_item *port_filter_entry_copy(const struct port_filter_item *pfi)
|
||||
{
|
||||
return port_filter_entry_alloc(&pfi->pf);
|
||||
}
|
||||
bool port_filters_copy(struct port_filters_head *to, const struct port_filters_head *from)
|
||||
{
|
||||
struct port_filter_item *tail, *item, *entry;
|
||||
|
||||
LIST_TAIL(to, tail, item);
|
||||
LIST_FOREACH(item, from, next)
|
||||
{
|
||||
if (!(entry = port_filter_entry_copy(item))) return false;
|
||||
LIST_INSERT_TAIL(to, tail, entry, next);
|
||||
tail = tail ? LIST_NEXT(tail, next) : LIST_FIRST(to);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
void port_filters_destroy(struct port_filters_head *head)
|
||||
{
|
||||
struct port_filter_item *entry;
|
||||
@@ -743,14 +761,14 @@ void port_filters_destroy(struct port_filters_head *head)
|
||||
free(entry);
|
||||
}
|
||||
}
|
||||
bool port_filters_in_range(const struct port_filters_head *head, uint16_t port)
|
||||
bool port_filters_match(const struct port_filters_head *head, uint16_t port)
|
||||
{
|
||||
const struct port_filter_item *item;
|
||||
|
||||
if (LIST_EMPTY(head)) return true;
|
||||
LIST_FOREACH(item, head, next)
|
||||
{
|
||||
if (pf_in_range(port, &item->pf))
|
||||
if (pf_match(port, &item->pf))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -763,6 +781,121 @@ bool port_filters_deny_if_empty(struct port_filters_head *head)
|
||||
}
|
||||
|
||||
|
||||
static struct icmp_filter_item *icmp_filter_entry_alloc(const icmp_filter *icf)
|
||||
{
|
||||
struct icmp_filter_item *entry = malloc(sizeof(struct icmp_filter_item));
|
||||
if (entry) entry->icf = *icf;
|
||||
return entry;
|
||||
}
|
||||
bool icmp_filter_add(struct icmp_filters_head *head, const icmp_filter *icf)
|
||||
{
|
||||
struct icmp_filter_item *entry = icmp_filter_entry_alloc(icf);
|
||||
if (entry) LIST_INSERT_HEAD(head, entry, next);
|
||||
return entry;
|
||||
}
|
||||
static struct icmp_filter_item *icmp_filter_entry_copy(const struct icmp_filter_item *ifi)
|
||||
{
|
||||
return icmp_filter_entry_alloc(&ifi->icf);
|
||||
}
|
||||
bool icmp_filters_copy(struct icmp_filters_head *to, const struct icmp_filters_head *from)
|
||||
{
|
||||
struct icmp_filter_item *tail, *item, *entry;
|
||||
|
||||
LIST_TAIL(to, tail, item);
|
||||
LIST_FOREACH(item, from, next)
|
||||
{
|
||||
if (!(entry = icmp_filter_entry_copy(item))) return false;
|
||||
LIST_INSERT_TAIL(to, tail, entry, next);
|
||||
tail = tail ? LIST_NEXT(tail, next) : LIST_FIRST(to);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
void icmp_filters_destroy(struct icmp_filters_head *head)
|
||||
{
|
||||
struct icmp_filter_item *entry;
|
||||
while ((entry = LIST_FIRST(head)))
|
||||
{
|
||||
LIST_REMOVE(entry, next);
|
||||
free(entry);
|
||||
}
|
||||
}
|
||||
bool icmp_filters_match(const struct icmp_filters_head *head, uint8_t type, uint8_t code)
|
||||
{
|
||||
const struct icmp_filter_item *item;
|
||||
|
||||
if (LIST_EMPTY(head)) return true;
|
||||
LIST_FOREACH(item, head, next)
|
||||
{
|
||||
if (icf_match(type, code, &item->icf))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool icmp_filters_deny_if_empty(struct icmp_filters_head *head)
|
||||
{
|
||||
icmp_filter icf;
|
||||
if (!LIST_EMPTY(head)) return true;
|
||||
return icf_parse("-",&icf) && icmp_filter_add(head,&icf);
|
||||
}
|
||||
|
||||
|
||||
static struct ipp_filter_item *ipp_filter_entry_alloc(const ipp_filter *ipp)
|
||||
{
|
||||
struct ipp_filter_item *entry = malloc(sizeof(struct ipp_filter_item));
|
||||
if (entry) entry->ipp = *ipp;
|
||||
return entry;
|
||||
}
|
||||
bool ipp_filter_add(struct ipp_filters_head *head, const ipp_filter *ipp)
|
||||
{
|
||||
struct ipp_filter_item *entry = ipp_filter_entry_alloc(ipp);
|
||||
if (entry) LIST_INSERT_HEAD(head, entry, next);
|
||||
return entry;
|
||||
}
|
||||
static struct ipp_filter_item *ipp_filter_entry_copy(const struct ipp_filter_item *ifi)
|
||||
{
|
||||
return ipp_filter_entry_alloc(&ifi->ipp);
|
||||
}
|
||||
bool ipp_filters_copy(struct ipp_filters_head *to, const struct ipp_filters_head *from)
|
||||
{
|
||||
struct ipp_filter_item *tail, *item, *entry;
|
||||
|
||||
LIST_TAIL(to, tail, item);
|
||||
LIST_FOREACH(item, from, next)
|
||||
{
|
||||
if (!(entry = ipp_filter_entry_copy(item))) return false;
|
||||
LIST_INSERT_TAIL(to, tail, entry, next);
|
||||
tail = tail ? LIST_NEXT(tail, next) : LIST_FIRST(to);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
void ipp_filters_destroy(struct ipp_filters_head *head)
|
||||
{
|
||||
struct ipp_filter_item *entry;
|
||||
while ((entry = LIST_FIRST(head)))
|
||||
{
|
||||
LIST_REMOVE(entry, next);
|
||||
free(entry);
|
||||
}
|
||||
}
|
||||
bool ipp_filters_match(const struct ipp_filters_head *head, uint8_t proto)
|
||||
{
|
||||
const struct ipp_filter_item *item;
|
||||
|
||||
if (LIST_EMPTY(head)) return true;
|
||||
LIST_FOREACH(item, head, next)
|
||||
{
|
||||
if (ipp_match(proto, &item->ipp))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool ipp_filters_deny_if_empty(struct ipp_filters_head *head)
|
||||
{
|
||||
ipp_filter ipp;
|
||||
if (!LIST_EMPTY(head)) return true;
|
||||
return ipp_parse("-",&ipp) && ipp_filter_add(head,&ipp);
|
||||
}
|
||||
|
||||
|
||||
struct blob_item *blob_collection_add(struct blob_collection_head *head)
|
||||
{
|
||||
|
||||
33
nfq2/pools.h
33
nfq2/pools.h
@@ -7,6 +7,7 @@
|
||||
#include <time.h>
|
||||
|
||||
#include "helpers.h"
|
||||
#include "filter.h"
|
||||
|
||||
//#define HASH_BLOOM 20
|
||||
#define HASH_NONFATAL_OOM 1
|
||||
@@ -75,9 +76,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 +87,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);
|
||||
|
||||
|
||||
@@ -185,10 +186,32 @@ struct port_filter_item {
|
||||
};
|
||||
LIST_HEAD(port_filters_head, port_filter_item);
|
||||
bool port_filter_add(struct port_filters_head *head, const port_filter *pf);
|
||||
bool port_filters_copy(struct port_filters_head *to, const struct port_filters_head *from);
|
||||
void port_filters_destroy(struct port_filters_head *head);
|
||||
bool port_filters_in_range(const struct port_filters_head *head, uint16_t port);
|
||||
bool port_filters_match(const struct port_filters_head *head, uint16_t port);
|
||||
bool port_filters_deny_if_empty(struct port_filters_head *head);
|
||||
|
||||
struct icmp_filter_item {
|
||||
icmp_filter icf;
|
||||
LIST_ENTRY(icmp_filter_item) next;
|
||||
};
|
||||
LIST_HEAD(icmp_filters_head, icmp_filter_item);
|
||||
bool icmp_filter_add(struct icmp_filters_head *head, const icmp_filter *icf);
|
||||
bool icmp_filters_copy(struct icmp_filters_head *to, const struct icmp_filters_head *from);
|
||||
void icmp_filters_destroy(struct icmp_filters_head *head);
|
||||
bool icmp_filters_match(const struct icmp_filters_head *head, uint8_t type, uint8_t code);
|
||||
bool icmp_filters_deny_if_empty(struct icmp_filters_head *head);
|
||||
|
||||
struct ipp_filter_item {
|
||||
ipp_filter ipp;
|
||||
LIST_ENTRY(ipp_filter_item) next;
|
||||
};
|
||||
LIST_HEAD(ipp_filters_head, ipp_filter_item);
|
||||
bool ipp_filter_add(struct ipp_filters_head *head, const ipp_filter *ipp);
|
||||
bool ipp_filters_copy(struct ipp_filters_head *to, const struct ipp_filters_head *from);
|
||||
void ipp_filters_destroy(struct ipp_filters_head *head);
|
||||
bool ipp_filters_match(const struct ipp_filters_head *head, uint8_t proto);
|
||||
bool ipp_filters_deny_if_empty(struct ipp_filters_head *head);
|
||||
|
||||
struct blob_item {
|
||||
uint8_t *data; // main data blob
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user