mirror of
https://github.com/bol-van/zapret.git
synced 2025-04-17 12:32:57 +03:00
Compare commits
188 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
b996abd5ce | ||
|
12461de3b0 | ||
|
7dab497b57 | ||
|
41dbba1c4c | ||
|
d19f6c19a4 | ||
|
b12b1a5a17 | ||
|
8022e2576d | ||
|
f4ea264ba9 | ||
|
061acb27e4 | ||
|
8eb830d304 | ||
|
2fb93c6add | ||
|
ad5c246629 | ||
|
58e73d0331 | ||
|
9ebeff621a | ||
|
69df271a16 | ||
|
e285b2401d | ||
|
6e1e7e43bc | ||
|
d04419a60c | ||
|
fc1bf47e82 | ||
|
929df3f094 | ||
|
7272b243cb | ||
|
72d48d957a | ||
|
f4069d484a | ||
|
1c82b0a6af | ||
|
c08e69aa65 | ||
|
8097f08020 | ||
|
4cae291e6f | ||
|
82ad5508dc | ||
|
fa8ddcfc79 | ||
|
b560e32e18 | ||
|
67e1aee8a8 | ||
|
1d8385a9b4 | ||
|
340dec62a7 | ||
|
db4585c02f | ||
|
e792ca67ef | ||
|
e5e53db6b8 | ||
|
e14ee9d1fe | ||
|
360506ba4e | ||
|
aa769e05c6 | ||
|
6b0bc7a96b | ||
|
93bdfdb6be | ||
|
6d95eada2b | ||
|
e452ee8688 | ||
|
6e746f94cd | ||
|
9fd61e5d38 | ||
|
0c0fba4461 | ||
|
056e4c588a | ||
|
4b288643ac | ||
|
cbdee74e5f | ||
|
743eb5a4a2 | ||
|
4e8e3a9ed9 | ||
|
b9b91a0e68 | ||
|
9de7b66eef | ||
|
a2ffa3455d | ||
|
60b97dbed0 | ||
|
e56e4f5f35 | ||
|
5305ea83c8 | ||
|
14b3dd459b | ||
|
66fda2c33d | ||
|
77df43b9cb | ||
|
85f2b37c88 | ||
|
e2d600fcc6 | ||
|
37eda0ad98 | ||
|
770be21e1c | ||
|
1b880d42f9 | ||
|
6387315c0b | ||
|
3d4b395bfe | ||
|
55950ed7d0 | ||
|
f2b0341484 | ||
|
b2d89c5d22 | ||
|
778b611f86 | ||
|
ffaf91c251 | ||
|
326b42fafd | ||
|
94d4238af2 | ||
|
15e22fa1bd | ||
|
bd8decddc5 | ||
|
2db1ebafe3 | ||
|
33bcf6f7b4 | ||
|
f037f1acb2 | ||
|
cdd9b32b27 | ||
|
7934125c09 | ||
|
6493d55977 | ||
|
cafbb17e70 | ||
|
9ac73f7d2f | ||
|
08a6e8e069 | ||
|
644a934099 | ||
|
0eec445af0 | ||
|
b8acc1b979 | ||
|
123eb057ae | ||
|
56d06456fb | ||
|
a6efe05aa6 | ||
|
a1d29b0c3a | ||
|
756603338b | ||
|
8b73e2ea8e | ||
|
2a0e952153 | ||
|
1065202349 | ||
|
307d38f6af | ||
|
8ac4fc0af5 | ||
|
af89d03118 | ||
|
d89daaaeac | ||
|
f62b289cb5 | ||
|
5f9fa28251 | ||
|
bd67b41f32 | ||
|
00619c8dab | ||
|
58e26c3e9d | ||
|
eddbc3c3e0 | ||
|
2cc73de15c | ||
|
9762f2d22b | ||
|
8c9aa188c3 | ||
|
2f151c0943 | ||
|
9498456c4a | ||
|
860607bce2 | ||
|
94f59511f0 | ||
|
b07ce8d8ca | ||
|
6fc4e75d89 | ||
|
fb894a8e2c | ||
|
86352430d4 | ||
|
e5f20d05f6 | ||
|
b610f08a9c | ||
|
8bbd2d97d5 | ||
|
972f665d88 | ||
|
a9a497fa77 | ||
|
14a170c9a3 | ||
|
d4080b6c6f | ||
|
20f1fb2cfd | ||
|
35c3216287 | ||
|
628f629c49 | ||
|
33d3059dc8 | ||
|
f5cf7917fb | ||
|
b39508de7f | ||
|
c69a92f901 | ||
|
aba1fdeb04 | ||
|
02c76a4fb6 | ||
|
2ff6ec03aa | ||
|
80a0b38295 | ||
|
e0e935c2ae | ||
|
31cf106728 | ||
|
502e34a96d | ||
|
29ab747e5b | ||
|
b897ec5d9a | ||
|
440878cb9f | ||
|
1935473bd1 | ||
|
de6cadf8e4 | ||
|
d509497bb8 | ||
|
d7949f70b1 | ||
|
0912b7d104 | ||
|
29ff997a3f | ||
|
f21bd0c63c | ||
|
41693b1008 | ||
|
d000345043 | ||
|
f986da9ae2 | ||
|
c6e729b237 | ||
|
12a800db97 | ||
|
5e84656707 | ||
|
e87965cd2f | ||
|
4585cc4656 | ||
|
c0a08d3353 | ||
|
77474c9f76 | ||
|
15b2ee2d82 | ||
|
709279d6cf | ||
|
35d676406c | ||
|
9aff90b466 | ||
|
bc463930aa | ||
|
6fe9471077 | ||
|
884213f7ac | ||
|
80bf409615 | ||
|
3fe46ffb82 | ||
|
42c52014ee | ||
|
8aabc8b743 | ||
|
5df9b5d109 | ||
|
50616896c8 | ||
|
eb1cf7c15a | ||
|
b878c313f8 | ||
|
869e2cd8f9 | ||
|
8a996b415e | ||
|
62d2de904b | ||
|
a02be13dd1 | ||
|
c6058a4ea9 | ||
|
27ffe77243 | ||
|
3eb969cdaf | ||
|
73040bb156 | ||
|
c2bda9388f | ||
|
6cd0de7a0b | ||
|
85d319568c | ||
|
b3fd5c5dc1 | ||
|
202b7224fb | ||
|
647ee11917 | ||
|
63fbf2857c |
2
.gitattributes
vendored
2
.gitattributes
vendored
@ -1,5 +1,3 @@
|
|||||||
* text=auto eol=lf
|
* text=auto eol=lf
|
||||||
binaries/win64/readme.txt eol=crlf
|
|
||||||
binaries/win32/readme.txt eol=crlf
|
|
||||||
*.cmd eol=crlf
|
*.cmd eol=crlf
|
||||||
*.bat eol=crlf
|
*.bat eol=crlf
|
||||||
|
1
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
1
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
blank_issues_enabled: false
|
19
.github/ISSUE_TEMPLATE/issue-warning.md
vendored
Normal file
19
.github/ISSUE_TEMPLATE/issue-warning.md
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
---
|
||||||
|
name: bugs
|
||||||
|
about: do not write lame questions
|
||||||
|
title: ''
|
||||||
|
labels: ''
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
1. Здесь не место для вопросов, касающихся компьютерной грамотности и навыков использования ОС
|
||||||
|
2. Здесь не место для вопросов "у меня не работает" без технических подробностей
|
||||||
|
3. Здесь не место для вопросов "как мне открыть ютуб", "что писать в ...", "перестало открываться".
|
||||||
|
4. Здесь не место для обсуждения сборок
|
||||||
|
5. Вирусов здесь нет. У вас либо чья-то сборка, либо ваш антивирус давно пора отправить на покой. Антивирусы в основном жалуются на upx и windivert, которые убраны НЕ будут. upx - это паковщик для сокращения требуемого места на openwrt, windivert - замена iptables для windows, потенциальный инструмент хакера или компонент зловредной программы, но сам по себе вирусом не является. Не согласны - удаляйте софт. За агрессивные наезды "почему автор распространяет вирусы" молча схватите бан.
|
||||||
|
|
||||||
|
Все означенное обсуждать в дискуссиях или на форумах.
|
||||||
|
При нарушении будет закрываться или конвертироваться в дискуссии.
|
||||||
|
Issue только для обсуждения проблем самого софта. Неработа стратегии или ваше неумение настроить - это ваша проблема, а не проблема софта.
|
||||||
|
Однокнопочные решения дают только сборщики, поэтому "открытие сайта" не является функцией программы, и нет смысла жаловаться, что он не открывается. Но можно это обсудить в дискуссиях. Не захламляйте issues !
|
10
.github/issue_template.md
vendored
10
.github/issue_template.md
vendored
@ -1,10 +0,0 @@
|
|||||||
1. Здесь не место для вопросов, касающихся компьютерной грамотности и навыков использования ОС
|
|
||||||
2. Здесь не место для вопросов "у меня не работает" без технических подробностей
|
|
||||||
3. Здесь не место для вопросов "как мне открыть ютуб" или "что писать в ..."
|
|
||||||
4. Здесь не место для обсуждения сборок
|
|
||||||
5. Вирусов здесь нет. У вас либо чья-то сборка, либо ваш антивирус давно пора отправить на покой. Не согласны - удаляйте софт.
|
|
||||||
|
|
||||||
Все означенное обсуждать в дискуссиях или на форумах.
|
|
||||||
При нарушении будет закрываться или конвертироваться в дискуссии.
|
|
||||||
Issue только для обсуждения проблем самого софта. Неработа стратегии или ваше неумение настроить - это ваша проблема, а не проблема софта.
|
|
||||||
|
|
57
.github/workflows/build.yml
vendored
57
.github/workflows/build.yml
vendored
@ -22,9 +22,6 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- arch: lexra
|
|
||||||
tool: mips-linux
|
|
||||||
dir: rsdk-4.6.4-5281-EB-3.10-0.9.33-m32ub-20141001
|
|
||||||
- arch: arm64
|
- arch: arm64
|
||||||
tool: aarch64-unknown-linux-musl
|
tool: aarch64-unknown-linux-musl
|
||||||
- arch: arm
|
- arch: arm
|
||||||
@ -55,6 +52,13 @@ jobs:
|
|||||||
tool: i586-unknown-linux-musl
|
tool: i586-unknown-linux-musl
|
||||||
- arch: x86_64
|
- arch: x86_64
|
||||||
tool: x86_64-unknown-linux-musl
|
tool: x86_64-unknown-linux-musl
|
||||||
|
- arch: lexra
|
||||||
|
tool: mips-linux
|
||||||
|
dir: rsdk-4.6.4-5281-EB-3.10-0.9.33-m32ub-20141001
|
||||||
|
env:
|
||||||
|
CFLAGS: '-march=5281'
|
||||||
|
LDFLAGS: '-lgcc_eh'
|
||||||
|
repo: 'bol-van/build'
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
@ -63,27 +67,31 @@ jobs:
|
|||||||
|
|
||||||
- name: Set up build tools
|
- name: Set up build tools
|
||||||
env:
|
env:
|
||||||
REPO: 'spvkgn/musl-cross'
|
|
||||||
REPO_LEXRA: 'bol-van/build'
|
|
||||||
ARCH: ${{ matrix.arch }}
|
ARCH: ${{ matrix.arch }}
|
||||||
TOOL: ${{ matrix.tool }}
|
TOOL: ${{ matrix.tool }}
|
||||||
DIR: ${{ matrix.dir }}
|
REPO: ${{ matrix.arch == 'lexra' && matrix.repo || 'spvkgn/musl-cross' }}
|
||||||
|
DIR: ${{ matrix.arch == 'lexra' && matrix.dir || matrix.tool }}
|
||||||
run: |
|
run: |
|
||||||
DIR=${DIR:-$TOOL}
|
if [[ "$ARCH" == lexra ]]; then
|
||||||
[ "$ARCH" = lexra ] && sudo dpkg --add-architecture i386
|
sudo dpkg --add-architecture i386
|
||||||
sudo apt update -qq
|
sudo apt update -qq
|
||||||
sudo apt install -y libcap-dev
|
sudo apt install -y libcap-dev libc6:i386 zlib1g:i386
|
||||||
[ "$ARCH" = lexra ] && sudo apt install -y libc6:i386 zlib1g:i386
|
URL=https://github.com/$REPO/raw/refs/heads/master/$DIR.txz
|
||||||
|
else
|
||||||
|
sudo apt update -qq
|
||||||
|
sudo apt install -y libcap-dev
|
||||||
|
URL=https://github.com/$REPO/releases/download/latest/$TOOL.tar.xz
|
||||||
|
fi
|
||||||
mkdir -p $HOME/tools
|
mkdir -p $HOME/tools
|
||||||
URL=https://github.com/$REPO/releases/download/latest/$DIR.tar.xz
|
|
||||||
[ "$ARCH" = lexra ] && URL=https://github.com/$REPO_LEXRA/raw/refs/heads/master/$DIR.txz
|
|
||||||
wget -qO- $URL | tar -C $HOME/tools -xJ || exit 1
|
wget -qO- $URL | tar -C $HOME/tools -xJ || exit 1
|
||||||
[ -d "$HOME/tools/$DIR/bin" ] && echo "$HOME/tools/$DIR/bin" >> $GITHUB_PATH
|
[[ -d "$HOME/tools/$DIR/bin" ]] && echo "$HOME/tools/$DIR/bin" >> $GITHUB_PATH
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
env:
|
env:
|
||||||
ARCH: ${{ matrix.arch }}
|
ARCH: ${{ matrix.arch }}
|
||||||
TARGET: ${{ matrix.tool }}
|
TARGET: ${{ matrix.tool }}
|
||||||
|
CFLAGS: ${{ matrix.env.CFLAGS != '' && matrix.env.CFLAGS || null }}
|
||||||
|
LDFLAGS: ${{ matrix.env.LDFLAGS != '' && matrix.env.LDFLAGS || null }}
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
run: |
|
run: |
|
||||||
DEPS_DIR=$GITHUB_WORKSPACE/deps
|
DEPS_DIR=$GITHUB_WORKSPACE/deps
|
||||||
@ -93,10 +101,7 @@ jobs:
|
|||||||
export NM=$TARGET-nm
|
export NM=$TARGET-nm
|
||||||
export STRIP=$TARGET-strip
|
export STRIP=$TARGET-strip
|
||||||
export PKG_CONFIG_PATH=$DEPS_DIR/lib/pkgconfig
|
export PKG_CONFIG_PATH=$DEPS_DIR/lib/pkgconfig
|
||||||
export STAGING_DIR=/tmp
|
export STAGING_DIR=$RUNNER_TEMP
|
||||||
LDFLAGS=
|
|
||||||
[ "$ARCH" = lexra ] && LDFLAGS=-lgcc_eh
|
|
||||||
export LDFLAGS
|
|
||||||
|
|
||||||
# netfilter libs
|
# netfilter libs
|
||||||
wget -qO- https://www.netfilter.org/pub/libnfnetlink/libnfnetlink-1.0.2.tar.bz2 | tar -xj
|
wget -qO- https://www.netfilter.org/pub/libnfnetlink/libnfnetlink-1.0.2.tar.bz2 | tar -xj
|
||||||
@ -106,7 +111,7 @@ jobs:
|
|||||||
for i in libmnl libnfnetlink libnetfilter_queue ; do
|
for i in libmnl libnfnetlink libnetfilter_queue ; do
|
||||||
(
|
(
|
||||||
cd $i-*
|
cd $i-*
|
||||||
CFLAGS="-Os -flto=auto" \
|
CFLAGS="-Os -flto=auto $CFLAGS" \
|
||||||
./configure --prefix= --host=$TARGET --enable-static --disable-shared --disable-dependency-tracking
|
./configure --prefix= --host=$TARGET --enable-static --disable-shared --disable-dependency-tracking
|
||||||
make install -j$(nproc) DESTDIR=$DEPS_DIR
|
make install -j$(nproc) DESTDIR=$DEPS_DIR
|
||||||
)
|
)
|
||||||
@ -118,7 +123,7 @@ jobs:
|
|||||||
xargs -I{} wget -qO- https://github.com/madler/zlib/archive/refs/tags/{}.tar.gz | tar -xz
|
xargs -I{} wget -qO- https://github.com/madler/zlib/archive/refs/tags/{}.tar.gz | tar -xz
|
||||||
(
|
(
|
||||||
cd zlib-*
|
cd zlib-*
|
||||||
CFLAGS="-Os -flto=auto" \
|
CFLAGS="-Os -flto=auto $CFLAGS" \
|
||||||
./configure --prefix= --static
|
./configure --prefix= --static
|
||||||
make install -j$(nproc) DESTDIR=$DEPS_DIR
|
make install -j$(nproc) DESTDIR=$DEPS_DIR
|
||||||
)
|
)
|
||||||
@ -129,7 +134,7 @@ jobs:
|
|||||||
install -Dm644 -t $DEPS_DIR/include/sys /usr/include/x86_64-linux-gnu/sys/queue.h /usr/include/sys/capability.h
|
install -Dm644 -t $DEPS_DIR/include/sys /usr/include/x86_64-linux-gnu/sys/queue.h /usr/include/sys/capability.h
|
||||||
|
|
||||||
# zapret
|
# zapret
|
||||||
CFLAGS="-DZAPRET_GH_VER=${{ github.ref_name }} -DZAPRET_GH_HASH=${{ github.sha }} -static-libgcc -static -I$DEPS_DIR/include" \
|
CFLAGS="-DZAPRET_GH_VER=${{ github.ref_name }} -DZAPRET_GH_HASH=${{ github.sha }} -static-libgcc -static -I$DEPS_DIR/include $CFLAGS" \
|
||||||
LDFLAGS="-L$DEPS_DIR/lib $LDFLAGS" \
|
LDFLAGS="-L$DEPS_DIR/lib $LDFLAGS" \
|
||||||
make -C zapret -j$(nproc)
|
make -C zapret -j$(nproc)
|
||||||
tar -C zapret/binaries/my -cJf zapret-linux-$ARCH.tar.xz .
|
tar -C zapret/binaries/my -cJf zapret-linux-$ARCH.tar.xz .
|
||||||
@ -322,11 +327,12 @@ jobs:
|
|||||||
- name: Build
|
- name: Build
|
||||||
env:
|
env:
|
||||||
ABI: ${{ matrix.abi }}
|
ABI: ${{ matrix.abi }}
|
||||||
|
API: 21
|
||||||
TARGET: ${{ matrix.target }}
|
TARGET: ${{ matrix.target }}
|
||||||
|
GH_TOKEN: ${{ github.token }}
|
||||||
run: |
|
run: |
|
||||||
DEPS_DIR=$GITHUB_WORKSPACE/deps
|
DEPS_DIR=$GITHUB_WORKSPACE/deps
|
||||||
export TOOLCHAIN=$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64
|
export TOOLCHAIN=$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64
|
||||||
export API=21
|
|
||||||
export CC="$TOOLCHAIN/bin/clang --target=$TARGET$API"
|
export CC="$TOOLCHAIN/bin/clang --target=$TARGET$API"
|
||||||
export AR=$TOOLCHAIN/bin/llvm-ar
|
export AR=$TOOLCHAIN/bin/llvm-ar
|
||||||
export AS=$CC
|
export AS=$CC
|
||||||
@ -355,6 +361,12 @@ jobs:
|
|||||||
CFLAGS="-DZAPRET_GH_VER=${{ github.ref_name }} -DZAPRET_GH_HASH=${{ github.sha }} -I$DEPS_DIR/include" \
|
CFLAGS="-DZAPRET_GH_VER=${{ github.ref_name }} -DZAPRET_GH_HASH=${{ github.sha }} -I$DEPS_DIR/include" \
|
||||||
LDFLAGS="-L$DEPS_DIR/lib" \
|
LDFLAGS="-L$DEPS_DIR/lib" \
|
||||||
make -C zapret android -j$(nproc)
|
make -C zapret android -j$(nproc)
|
||||||
|
|
||||||
|
# strip unwanted ELF sections to prevent warnings on old Android versions
|
||||||
|
gh api repos/termux/termux-elf-cleaner/releases/latest --jq '.tag_name' |\
|
||||||
|
xargs -I{} wget -O elf-cleaner https://github.com/termux/termux-elf-cleaner/releases/download/{}/termux-elf-cleaner
|
||||||
|
chmod +x elf-cleaner
|
||||||
|
./elf-cleaner --api-level $API zapret/binaries/my/*
|
||||||
zip zapret-android-$ABI.zip -j zapret/binaries/my/*
|
zip zapret-android-$ABI.zip -j zapret/binaries/my/*
|
||||||
|
|
||||||
- name: Upload artifacts
|
- name: Upload artifacts
|
||||||
@ -389,6 +401,7 @@ jobs:
|
|||||||
uses: crazy-max/ghaction-upx@v3
|
uses: crazy-max/ghaction-upx@v3
|
||||||
with:
|
with:
|
||||||
install-only: true
|
install-only: true
|
||||||
|
version: v4.2.4
|
||||||
|
|
||||||
- name: Prepare binaries
|
- name: Prepare binaries
|
||||||
shell: bash
|
shell: bash
|
||||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -4,9 +4,9 @@ mdig/mdig
|
|||||||
nfq/dvtws
|
nfq/dvtws
|
||||||
nfq/nfqws
|
nfq/nfqws
|
||||||
nfq/winws.exe
|
nfq/winws.exe
|
||||||
|
nfq/WinDivert*
|
||||||
tpws/tpws
|
tpws/tpws
|
||||||
binaries/my/
|
binaries/my/
|
||||||
init.d/**/custom
|
|
||||||
ipset/zapret-ip*.txt
|
ipset/zapret-ip*.txt
|
||||||
ipset/zapret-ip*.gz
|
ipset/zapret-ip*.gz
|
||||||
ipset/zapret-hosts*.txt
|
ipset/zapret-hosts*.txt
|
||||||
|
13
Makefile
13
Makefile
@ -15,6 +15,19 @@ all: clean
|
|||||||
done \
|
done \
|
||||||
done
|
done
|
||||||
|
|
||||||
|
systemd: clean
|
||||||
|
@mkdir -p "$(TGT)"; \
|
||||||
|
for dir in $(DIRS); do \
|
||||||
|
find "$$dir" -type f \( -name "*.c" -o -name "*.h" -o -name "*akefile" \) -exec chmod -x {} \; ; \
|
||||||
|
$(MAKE) -C "$$dir" systemd || exit; \
|
||||||
|
for exe in "$$dir/"*; do \
|
||||||
|
if [ -f "$$exe" ] && [ -x "$$exe" ]; then \
|
||||||
|
mv -f "$$exe" "${TGT}" ; \
|
||||||
|
ln -fs "../${TGT}/$$(basename "$$exe")" "$$exe" ; \
|
||||||
|
fi \
|
||||||
|
done \
|
||||||
|
done
|
||||||
|
|
||||||
android: clean
|
android: clean
|
||||||
@mkdir -p "$(TGT)"; \
|
@mkdir -p "$(TGT)"; \
|
||||||
for dir in $(DIRS); do \
|
for dir in $(DIRS); do \
|
||||||
|
310
blockcheck.sh
310
blockcheck.sh
@ -23,6 +23,7 @@ CURL=${CURL:-curl}
|
|||||||
. "$ZAPRET_BASE/common/fwtype.sh"
|
. "$ZAPRET_BASE/common/fwtype.sh"
|
||||||
. "$ZAPRET_BASE/common/virt.sh"
|
. "$ZAPRET_BASE/common/virt.sh"
|
||||||
|
|
||||||
|
DOMAINS_DEFAULT=${DOMAINS_DEFAULT:-rutracker.org}
|
||||||
QNUM=${QNUM:-59780}
|
QNUM=${QNUM:-59780}
|
||||||
SOCKS_PORT=${SOCKS_PORT:-1993}
|
SOCKS_PORT=${SOCKS_PORT:-1993}
|
||||||
TPWS_UID=${TPWS_UID:-1}
|
TPWS_UID=${TPWS_UID:-1}
|
||||||
@ -35,9 +36,9 @@ MDIG=${MDIG:-${ZAPRET_BASE}/mdig/mdig}
|
|||||||
DESYNC_MARK=0x10000000
|
DESYNC_MARK=0x10000000
|
||||||
IPFW_RULE_NUM=${IPFW_RULE_NUM:-1}
|
IPFW_RULE_NUM=${IPFW_RULE_NUM:-1}
|
||||||
IPFW_DIVERT_PORT=${IPFW_DIVERT_PORT:-59780}
|
IPFW_DIVERT_PORT=${IPFW_DIVERT_PORT:-59780}
|
||||||
DOMAINS=${DOMAINS:-rutracker.org}
|
|
||||||
CURL_MAX_TIME=${CURL_MAX_TIME:-2}
|
CURL_MAX_TIME=${CURL_MAX_TIME:-2}
|
||||||
CURL_MAX_TIME_QUIC=${CURL_MAX_TIME_QUIC:-$CURL_MAX_TIME}
|
CURL_MAX_TIME_QUIC=${CURL_MAX_TIME_QUIC:-$CURL_MAX_TIME}
|
||||||
|
CURL_MAX_TIME_DOH=${CURL_MAX_TIME_DOH:-2}
|
||||||
MIN_TTL=${MIN_TTL:-1}
|
MIN_TTL=${MIN_TTL:-1}
|
||||||
MAX_TTL=${MAX_TTL:-12}
|
MAX_TTL=${MAX_TTL:-12}
|
||||||
USER_AGENT=${USER_AGENT:-Mozilla}
|
USER_AGENT=${USER_AGENT:-Mozilla}
|
||||||
@ -45,8 +46,9 @@ HTTP_PORT=${HTTP_PORT:-80}
|
|||||||
HTTPS_PORT=${HTTPS_PORT:-443}
|
HTTPS_PORT=${HTTPS_PORT:-443}
|
||||||
QUIC_PORT=${QUIC_PORT:-443}
|
QUIC_PORT=${QUIC_PORT:-443}
|
||||||
UNBLOCKED_DOM=${UNBLOCKED_DOM:-iana.org}
|
UNBLOCKED_DOM=${UNBLOCKED_DOM:-iana.org}
|
||||||
|
PARALLEL_OUT=/tmp/zapret_parallel
|
||||||
|
|
||||||
HDRTEMP=/tmp/zapret-hdr.txt
|
HDRTEMP=/tmp/zapret-hdr
|
||||||
|
|
||||||
NFT_TABLE=blockcheck
|
NFT_TABLE=blockcheck
|
||||||
|
|
||||||
@ -77,9 +79,11 @@ exitp()
|
|||||||
{
|
{
|
||||||
local A
|
local A
|
||||||
|
|
||||||
echo
|
[ "$BATCH" = 1 ] || {
|
||||||
echo press enter to continue
|
echo
|
||||||
read A
|
echo press enter to continue
|
||||||
|
read A
|
||||||
|
}
|
||||||
exit $1
|
exit $1
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -212,7 +216,7 @@ doh_resolve()
|
|||||||
# $1 - ip version 4/6
|
# $1 - ip version 4/6
|
||||||
# $2 - hostname
|
# $2 - hostname
|
||||||
# $3 - doh server URL. use $DOH_SERVER if empty
|
# $3 - doh server URL. use $DOH_SERVER if empty
|
||||||
$MDIG --family=$1 --dns-make-query=$2 | $CURL -s --data-binary @- -H "Content-Type: application/dns-message" "${3:-$DOH_SERVER}" | $MDIG --dns-parse-query
|
$MDIG --family=$1 --dns-make-query=$2 | $CURL --max-time $CURL_MAX_TIME_DOH -s --data-binary @- -H "Content-Type: application/dns-message" "${3:-$DOH_SERVER}" | $MDIG --dns-parse-query
|
||||||
}
|
}
|
||||||
doh_find_working()
|
doh_find_working()
|
||||||
{
|
{
|
||||||
@ -337,12 +341,19 @@ netcat_test()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tpws_can_fix_seg()
|
||||||
|
{
|
||||||
|
# fix-seg requires kernel 4.6+
|
||||||
|
"$TPWS" --port 1 --dry-run --fix-seg >/dev/null 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
check_system()
|
check_system()
|
||||||
{
|
{
|
||||||
echo \* checking system
|
echo \* checking system
|
||||||
|
|
||||||
UNAME=$(uname)
|
UNAME=$(uname)
|
||||||
SUBSYS=
|
SUBSYS=
|
||||||
|
FIX_SEG=
|
||||||
local s
|
local s
|
||||||
|
|
||||||
# can be passed FWTYPE=iptables to override default nftables preference
|
# can be passed FWTYPE=iptables to override default nftables preference
|
||||||
@ -350,6 +361,14 @@ check_system()
|
|||||||
Linux)
|
Linux)
|
||||||
PKTWS="$NFQWS"
|
PKTWS="$NFQWS"
|
||||||
PKTWSD=nfqws
|
PKTWSD=nfqws
|
||||||
|
if [ -x "$TPWS" ] ; then
|
||||||
|
if tpws_can_fix_seg ; then
|
||||||
|
echo tpws supports --fix-seg on this system
|
||||||
|
FIX_SEG='--fix-seg'
|
||||||
|
else
|
||||||
|
echo tpws does not support --fix-seg on this system
|
||||||
|
fi
|
||||||
|
fi
|
||||||
linux_fwtype
|
linux_fwtype
|
||||||
[ "$FWTYPE" = iptables -o "$FWTYPE" = nftables ] || {
|
[ "$FWTYPE" = iptables -o "$FWTYPE" = nftables ] || {
|
||||||
echo firewall type $FWTYPE not supported in $UNAME
|
echo firewall type $FWTYPE not supported in $UNAME
|
||||||
@ -560,7 +579,7 @@ curl_supports_tls13()
|
|||||||
[ $? = 2 ] && return 1
|
[ $? = 2 ] && return 1
|
||||||
# curl can have tlsv1.3 key present but ssl library without TLS 1.3 support
|
# curl can have tlsv1.3 key present but ssl library without TLS 1.3 support
|
||||||
# this is online test because there's no other way to trigger library incompatibility case
|
# this is online test because there's no other way to trigger library incompatibility case
|
||||||
$CURL --tlsv1.3 --max-time $CURL_MAX_TIME -Is -o /dev/null https://iana.org 2>/dev/null
|
$CURL --tlsv1.3 --max-time 1 -Is -o /dev/null https://iana.org 2>/dev/null
|
||||||
r=$?
|
r=$?
|
||||||
[ $r != 4 -a $r != 35 ]
|
[ $r != 4 -a $r != 35 ]
|
||||||
}
|
}
|
||||||
@ -651,28 +670,28 @@ curl_test_http()
|
|||||||
# $3 - subst ip
|
# $3 - subst ip
|
||||||
# $4 - "detail" - detail info
|
# $4 - "detail" - detail info
|
||||||
|
|
||||||
local code loc
|
local code loc hdrt="${HDRTEMP}_${!:-$$}.txt"
|
||||||
curl_probe $1 $2 $HTTP_PORT "$3" -SsD "$HDRTEMP" -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=$?
|
code=$?
|
||||||
rm -f "$HDRTEMP"
|
rm -f "$hdrt"
|
||||||
return $code
|
return $code
|
||||||
}
|
}
|
||||||
if [ "$4" = "detail" ] ; then
|
if [ "$4" = "detail" ] ; then
|
||||||
head -n 1 "$HDRTEMP"
|
head -n 1 "$hdrt"
|
||||||
grep "^[lL]ocation:" "$HDRTEMP"
|
grep "^[lL]ocation:" "$hdrt"
|
||||||
else
|
else
|
||||||
code=$(hdrfile_http_code "$HDRTEMP")
|
code=$(hdrfile_http_code "$hdrt")
|
||||||
[ "$code" = 301 -o "$code" = 302 -o "$code" = 307 -o "$code" = 308 ] && {
|
[ "$code" = 301 -o "$code" = 302 -o "$code" = 307 -o "$code" = 308 ] && {
|
||||||
loc=$(hdrfile_location "$HDRTEMP")
|
loc=$(hdrfile_location "$hdrt")
|
||||||
echo "$loc" | grep -qE "^https?://.*$2(/|$)" ||
|
echo "$loc" | grep -qE "^https?://.*$2(/|$)" ||
|
||||||
echo "$loc" | grep -vqE '^https?://' || {
|
echo "$loc" | grep -vqE '^https?://' || {
|
||||||
echo suspicious redirection $code to : $loc
|
echo suspicious redirection $code to : $loc
|
||||||
rm -f "$HDRTEMP"
|
rm -f "$hdrt"
|
||||||
return 254
|
return 254
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fi
|
fi
|
||||||
rm -f "$HDRTEMP"
|
rm -f "$hdrt"
|
||||||
[ "$code" = 400 ] && {
|
[ "$code" = 400 ] && {
|
||||||
# this can often happen if the server receives fake packets it should not receive
|
# this can often happen if the server receives fake packets it should not receive
|
||||||
echo http code $code. likely the server receives fakes.
|
echo http code $code. likely the server receives fakes.
|
||||||
@ -964,18 +983,38 @@ curl_test()
|
|||||||
# $2 - domain
|
# $2 - domain
|
||||||
# $3 - subst ip
|
# $3 - subst ip
|
||||||
# $4 - param of test function
|
# $4 - param of test function
|
||||||
local code=0 n=0
|
local code=0 n=0 p pids
|
||||||
|
|
||||||
while [ $n -lt $REPEATS ]; do
|
if [ "$PARALLEL" = 1 ]; then
|
||||||
n=$(($n+1))
|
rm -f "${PARALLEL_OUT}"*
|
||||||
[ $REPEATS -gt 1 ] && printf "[attempt $n] "
|
for n in $(seq -s ' ' 1 $REPEATS); do
|
||||||
if $1 "$IPV" $2 $3 "$4" ; then
|
$1 "$IPV" $2 $3 "$4" >"${PARALLEL_OUT}_$n" &
|
||||||
[ $REPEATS -gt 1 ] && echo 'AVAILABLE'
|
pids="${pids:+$pids }$!"
|
||||||
else
|
done
|
||||||
code=$?
|
n=1
|
||||||
[ "$SCANLEVEL" = quick ] && break
|
for p in $pids; do
|
||||||
fi
|
[ $REPEATS -gt 1 ] && printf "[attempt $n] "
|
||||||
done
|
if wait $p; then
|
||||||
|
[ $REPEATS -gt 1 ] && echo 'AVAILABLE'
|
||||||
|
else
|
||||||
|
code=$?
|
||||||
|
cat "${PARALLEL_OUT}_$n"
|
||||||
|
fi
|
||||||
|
n=$(($n+1))
|
||||||
|
done
|
||||||
|
rm -f "${PARALLEL_OUT}"*
|
||||||
|
else
|
||||||
|
while [ $n -lt $REPEATS ]; do
|
||||||
|
n=$(($n+1))
|
||||||
|
[ $REPEATS -gt 1 ] && printf "[attempt $n] "
|
||||||
|
if $1 "$IPV" $2 $3 "$4" ; then
|
||||||
|
[ $REPEATS -gt 1 ] && echo 'AVAILABLE'
|
||||||
|
else
|
||||||
|
code=$?
|
||||||
|
[ "$SCANLEVEL" = quick ] && break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
[ "$4" = detail ] || {
|
[ "$4" = detail ] || {
|
||||||
if [ $code = 254 ]; then
|
if [ $code = 254 ]; then
|
||||||
echo "UNAVAILABLE"
|
echo "UNAVAILABLE"
|
||||||
@ -1121,7 +1160,10 @@ test_has_fake()
|
|||||||
warn_fool()
|
warn_fool()
|
||||||
{
|
{
|
||||||
case "$1" in
|
case "$1" in
|
||||||
md5sig) echo 'WARNING ! although md5sig fooling worked it will not work on all sites. it typically works only on linux servers.' ;;
|
md5sig) echo 'WARNING ! although md5sig fooling worked it will not work on all sites. it typically works only on linux servers.'
|
||||||
|
[ "$2" = "fakedsplit" -o "$2" = "fakeddisorder" ] && \
|
||||||
|
echo "WARNING ! fakedsplit/fakeddisorder with md5sig fooling and low split position causes MTU overflow with multi-segment TLS (kyber)"
|
||||||
|
;;
|
||||||
datanoack) echo 'WARNING ! although datanoack fooling worked it may break NAT and may only work with external IP. Additionally it may require nftables to work correctly.' ;;
|
datanoack) echo 'WARNING ! although datanoack fooling worked it may break NAT and may only work with external IP. Additionally it may require nftables to work correctly.' ;;
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
@ -1133,13 +1175,16 @@ pktws_curl_test_update_vary()
|
|||||||
# $4 - desync mode
|
# $4 - desync mode
|
||||||
# $5,$6,... - strategy
|
# $5,$6,... - strategy
|
||||||
|
|
||||||
local testf=$1 sec=$2 domain=$3 desync=$4 proto zerofake= splits= pos fake ret=1
|
local testf=$1 sec=$2 domain=$3 desync=$4 proto zerofake= tlsmod= splits= pos fake ret=1
|
||||||
|
|
||||||
shift; shift; shift; shift
|
shift; shift; shift; shift
|
||||||
|
|
||||||
proto=http
|
proto=http
|
||||||
[ "$sec" = 0 ] || proto=tls
|
[ "$sec" = 0 ] || proto=tls
|
||||||
test_has_fake $desync && zerofake="--dpi-desync-fake-$proto=0x00000000"
|
test_has_fake $desync && {
|
||||||
|
zerofake="--dpi-desync-fake-$proto=0x00000000"
|
||||||
|
[ "$sec" = 0 ] || tlsmod="--dpi-desync-fake-tls-mod=rnd,dupsid,rndsni,padencap"
|
||||||
|
}
|
||||||
if test_has_fakedsplit $desync ; then
|
if test_has_fakedsplit $desync ; then
|
||||||
splits="method+2 midsld"
|
splits="method+2 midsld"
|
||||||
[ "$sec" = 0 ] || splits="1 midsld"
|
[ "$sec" = 0 ] || splits="1 midsld"
|
||||||
@ -1147,7 +1192,7 @@ pktws_curl_test_update_vary()
|
|||||||
splits="method+2 midsld"
|
splits="method+2 midsld"
|
||||||
[ "$sec" = 0 ] || splits="1 midsld 1,midsld"
|
[ "$sec" = 0 ] || splits="1 midsld 1,midsld"
|
||||||
fi
|
fi
|
||||||
for fake in '' $zerofake ; do
|
for fake in '' $zerofake $tlsmod ; do
|
||||||
if [ -n "$splits" ]; then
|
if [ -n "$splits" ]; then
|
||||||
for pos in $splits ; do
|
for pos in $splits ; do
|
||||||
pktws_curl_test_update $testf $domain --dpi-desync=$desync "$@" --dpi-desync-split-pos=$pos $fake && {
|
pktws_curl_test_update $testf $domain --dpi-desync=$desync "$@" --dpi-desync-split-pos=$pos $fake && {
|
||||||
@ -1245,7 +1290,7 @@ pktws_check_domain_http_bypass_()
|
|||||||
[ "$IPV" = 6 ] && f="$f hopbyhop hopbyhop2"
|
[ "$IPV" = 6 ] && f="$f hopbyhop hopbyhop2"
|
||||||
for fooling in $f; do
|
for fooling in $f; do
|
||||||
pktws_curl_test_update_vary $1 $2 $3 $desync --dpi-desync-fooling=$fooling $e && {
|
pktws_curl_test_update_vary $1 $2 $3 $desync --dpi-desync-fooling=$fooling $e && {
|
||||||
warn_fool $fooling
|
warn_fool $fooling $desync
|
||||||
[ "$SCANLEVEL" = quick ] && return
|
[ "$SCANLEVEL" = quick ] && return
|
||||||
need_wssize=0
|
need_wssize=0
|
||||||
}
|
}
|
||||||
@ -1400,6 +1445,11 @@ warn_mss()
|
|||||||
[ -n "$1" ] && echo 'WARNING ! although mss worked it may not work on all sites and will likely cause significant slowdown. it may only be required for TLS1.2, not TLS1.3'
|
[ -n "$1" ] && echo 'WARNING ! although mss worked it may not work on all sites and will likely cause significant slowdown. it may only be required for TLS1.2, not TLS1.3'
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
fix_seg()
|
||||||
|
{
|
||||||
|
# $1 - split-pos
|
||||||
|
[ -n "$FIX_SEG" ] && contains "$1" , && echo "$FIX_SEG"
|
||||||
|
}
|
||||||
|
|
||||||
tpws_check_domain_http_bypass_()
|
tpws_check_domain_http_bypass_()
|
||||||
{
|
{
|
||||||
@ -1425,7 +1475,7 @@ tpws_check_domain_http_bypass_()
|
|||||||
done
|
done
|
||||||
for s2 in '' '--hostcase' '--oob' '--disorder' ${oobdis:+"$oobdis"}; do
|
for s2 in '' '--hostcase' '--oob' '--disorder' ${oobdis:+"$oobdis"}; do
|
||||||
for s in $splits_http ; do
|
for s in $splits_http ; do
|
||||||
tpws_curl_test_update $1 $3 --split-pos=$s $s2 && [ "$SCANLEVEL" != force ] && {
|
tpws_curl_test_update $1 $3 --split-pos=$s $(fix_seg $s) $s2 && [ "$SCANLEVEL" != force ] && {
|
||||||
[ "$SCANLEVEL" = quick ] && return
|
[ "$SCANLEVEL" = quick ] && return
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -1440,7 +1490,7 @@ tpws_check_domain_http_bypass_()
|
|||||||
s3=${mss:+--mss=$mss}
|
s3=${mss:+--mss=$mss}
|
||||||
for s2 in '' '--oob' '--disorder' ${oobdis:+"$oobdis"}; do
|
for s2 in '' '--oob' '--disorder' ${oobdis:+"$oobdis"}; do
|
||||||
for pos in $splits_tls; do
|
for pos in $splits_tls; do
|
||||||
tpws_curl_test_update $1 $3 --split-pos=$pos $s2 $s3 && warn_mss $s3 && [ "$SCANLEVEL" != force ] && {
|
tpws_curl_test_update $1 $3 --split-pos=$pos $(fix_seg $pos) $s2 $s3 && warn_mss $s3 && [ "$SCANLEVEL" != force ] && {
|
||||||
[ "$SCANLEVEL" = quick ] && return
|
[ "$SCANLEVEL" = quick ] && return
|
||||||
need_mss=0
|
need_mss=0
|
||||||
break
|
break
|
||||||
@ -1448,7 +1498,7 @@ tpws_check_domain_http_bypass_()
|
|||||||
done
|
done
|
||||||
done
|
done
|
||||||
for s in '' '--oob' '--disorder' ${oobdis:+"$oobdis"}; do
|
for s in '' '--oob' '--disorder' ${oobdis:+"$oobdis"}; do
|
||||||
for s2 in '--tlsrec=midsld' '--tlsrec=sniext+1 --split-pos=midsld' '--tlsrec=sniext+4 --split-pos=midsld' '--tlsrec=sniext+1 --split-pos=1,midsld' '--tlsrec=sniext+4 --split-pos=1,midsld' ; do
|
for s2 in '--tlsrec=midsld' '--tlsrec=sniext+1 --split-pos=midsld' '--tlsrec=sniext+4 --split-pos=midsld' "--tlsrec=sniext+1 --split-pos=1,midsld $FIX_SEG" "--tlsrec=sniext+4 --split-pos=1,midsld $FIX_SEG" ; do
|
||||||
tpws_curl_test_update $1 $3 $s2 $s $s3 && warn_mss $s3 && [ "$SCANLEVEL" != force ] && {
|
tpws_curl_test_update $1 $3 $s2 $s $s3 && warn_mss $s3 && [ "$SCANLEVEL" != force ] && {
|
||||||
[ "$SCANLEVEL" = quick ] && return
|
[ "$SCANLEVEL" = quick ] && return
|
||||||
need_mss=0
|
need_mss=0
|
||||||
@ -1551,7 +1601,7 @@ check_domain_http_tcp()
|
|||||||
|
|
||||||
check_domain_prolog $1 $2 $4 || return
|
check_domain_prolog $1 $2 $4 || return
|
||||||
|
|
||||||
check_dpi_ip_block $1 $4
|
[ "$SKIP_IPBLOCK" = 1 ] || check_dpi_ip_block $1 $4
|
||||||
|
|
||||||
[ "$SKIP_TPWS" = 1 ] || {
|
[ "$SKIP_TPWS" = 1 ] || {
|
||||||
echo
|
echo
|
||||||
@ -1597,22 +1647,22 @@ check_domain_http_udp()
|
|||||||
check_domain_http()
|
check_domain_http()
|
||||||
{
|
{
|
||||||
# $1 - domain
|
# $1 - domain
|
||||||
check_domain_http_tcp curl_test_http 80 0 $1
|
check_domain_http_tcp curl_test_http $HTTP_PORT 0 $1
|
||||||
}
|
}
|
||||||
check_domain_https_tls12()
|
check_domain_https_tls12()
|
||||||
{
|
{
|
||||||
# $1 - domain
|
# $1 - domain
|
||||||
check_domain_http_tcp curl_test_https_tls12 443 1 $1
|
check_domain_http_tcp curl_test_https_tls12 $HTTPS_PORT 1 $1
|
||||||
}
|
}
|
||||||
check_domain_https_tls13()
|
check_domain_https_tls13()
|
||||||
{
|
{
|
||||||
# $1 - domain
|
# $1 - domain
|
||||||
check_domain_http_tcp curl_test_https_tls13 443 2 $1
|
check_domain_http_tcp curl_test_https_tls13 $HTTPS_PORT 2 $1
|
||||||
}
|
}
|
||||||
check_domain_http3()
|
check_domain_http3()
|
||||||
{
|
{
|
||||||
# $1 - domain
|
# $1 - domain
|
||||||
check_domain_http_udp curl_test_http3 443 $1
|
check_domain_http_udp curl_test_http3 $QUIC_PORT $1
|
||||||
}
|
}
|
||||||
|
|
||||||
configure_ip_version()
|
configure_ip_version()
|
||||||
@ -1707,76 +1757,119 @@ ask_params()
|
|||||||
exitp 1
|
exitp 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
echo "specify domain(s) to test. multiple domains are space separated."
|
|
||||||
printf "domain(s) (default: $DOMAINS) : "
|
|
||||||
local dom
|
local dom
|
||||||
read dom
|
[ -n "$DOMAINS" ] || {
|
||||||
[ -n "$dom" ] && DOMAINS="$dom"
|
DOMAINS="$DOMAINS_DEFAULT"
|
||||||
|
[ "$BATCH" = 1 ] || {
|
||||||
|
echo "specify domain(s) to test. multiple domains are space separated."
|
||||||
|
printf "domain(s) (default: $DOMAINS) : "
|
||||||
|
read dom
|
||||||
|
[ -n "$dom" ] && DOMAINS="$dom"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
local IPVS_def=4
|
local IPVS_def=4
|
||||||
# yandex public dns
|
[ -n "$IPVS" ] || {
|
||||||
pingtest 6 2a02:6b8::feed:0ff && IPVS_def=46
|
# yandex public dns
|
||||||
printf "ip protocol version(s) - 4, 6 or 46 for both (default: $IPVS_def) : "
|
pingtest 6 2a02:6b8::feed:0ff && IPVS_def=46
|
||||||
read IPVS
|
[ "$BATCH" = 1 ] || {
|
||||||
[ -n "$IPVS" ] || IPVS=$IPVS_def
|
printf "ip protocol version(s) - 4, 6 or 46 for both (default: $IPVS_def) : "
|
||||||
[ "$IPVS" = 4 -o "$IPVS" = 6 -o "$IPVS" = 46 ] || {
|
read IPVS
|
||||||
echo 'invalid ip version(s). should be 4, 6 or 46.'
|
}
|
||||||
exitp 1
|
[ -n "$IPVS" ] || IPVS=$IPVS_def
|
||||||
|
[ "$IPVS" = 4 -o "$IPVS" = 6 -o "$IPVS" = 46 ] || {
|
||||||
|
echo 'invalid ip version(s). should be 4, 6 or 46.'
|
||||||
|
exitp 1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
[ "$IPVS" = 46 ] && IPVS="4 6"
|
[ "$IPVS" = 46 ] && IPVS="4 6"
|
||||||
|
|
||||||
configure_curl_opt
|
configure_curl_opt
|
||||||
|
|
||||||
ENABLE_HTTP=1
|
[ -n "$ENABLE_HTTP" ] || {
|
||||||
echo
|
ENABLE_HTTP=1
|
||||||
ask_yes_no_var ENABLE_HTTP "check http"
|
[ "$BATCH" = 1 ] || {
|
||||||
|
echo
|
||||||
ENABLE_HTTPS_TLS12=1
|
ask_yes_no_var ENABLE_HTTP "check http"
|
||||||
echo
|
}
|
||||||
ask_yes_no_var ENABLE_HTTPS_TLS12 "check https tls 1.2"
|
|
||||||
|
|
||||||
ENABLE_HTTPS_TLS13=0
|
|
||||||
echo
|
|
||||||
if [ -n "$TLS13" ]; then
|
|
||||||
echo "TLS 1.3 uses encrypted ServerHello. DPI cannot check domain name in server response."
|
|
||||||
echo "This can allow more bypass strategies to work."
|
|
||||||
echo "What works for TLS 1.2 will also work for TLS 1.3 but not vice versa."
|
|
||||||
echo "Most sites nowadays support TLS 1.3 but not all. If you can't find a strategy for TLS 1.2 use this test."
|
|
||||||
echo "TLS 1.3 only strategy is better than nothing."
|
|
||||||
ask_yes_no_var ENABLE_HTTPS_TLS13 "check https tls 1.3"
|
|
||||||
else
|
|
||||||
echo "installed curl version does not support TLS 1.3 . tests disabled."
|
|
||||||
fi
|
|
||||||
|
|
||||||
ENABLE_HTTP3=0
|
|
||||||
echo
|
|
||||||
if [ -n "$HTTP3" ]; then
|
|
||||||
echo "make sure target domain(s) support QUIC or result will be negative in any case"
|
|
||||||
ENABLE_HTTP3=1
|
|
||||||
ask_yes_no_var ENABLE_HTTP3 "check http3 QUIC"
|
|
||||||
else
|
|
||||||
echo "installed curl version does not support http3 QUIC. tests disabled."
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo
|
|
||||||
echo "sometimes ISPs use multiple DPIs or load balancing. bypass strategies may work unstable."
|
|
||||||
printf "how many times to repeat each test (default: 1) : "
|
|
||||||
read REPEATS
|
|
||||||
REPEATS=$((0+${REPEATS:-1}))
|
|
||||||
[ "$REPEATS" = 0 ] && {
|
|
||||||
echo invalid repeat count
|
|
||||||
exitp 1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
echo
|
[ -n "$ENABLE_HTTPS_TLS12" ] || {
|
||||||
echo quick - scan as fast as possible to reveal any working strategy
|
ENABLE_HTTPS_TLS12=1
|
||||||
echo standard - do investigation what works on your DPI
|
[ "$BATCH" = 1 ] || {
|
||||||
echo force - scan maximum despite of result
|
echo
|
||||||
SCANLEVEL=${SCANLEVEL:-standard}
|
ask_yes_no_var ENABLE_HTTPS_TLS12 "check https tls 1.2"
|
||||||
ask_list SCANLEVEL "quick standard force" "$SCANLEVEL"
|
}
|
||||||
# disable tpws checks by default in quick mode
|
}
|
||||||
[ "$SCANLEVEL" = quick -a -z "$SKIP_TPWS" -a "$UNAME" != Darwin ] && SKIP_TPWS=1
|
|
||||||
|
[ -n "$ENABLE_HTTPS_TLS13" ] || {
|
||||||
|
ENABLE_HTTPS_TLS13=0
|
||||||
|
if [ -n "$TLS13" ]; then
|
||||||
|
[ "$BATCH" = 1 ] || {
|
||||||
|
echo
|
||||||
|
echo "TLS 1.3 uses encrypted ServerHello. DPI cannot check domain name in server response."
|
||||||
|
echo "This can allow more bypass strategies to work."
|
||||||
|
echo "What works for TLS 1.2 will also work for TLS 1.3 but not vice versa."
|
||||||
|
echo "Most sites nowadays support TLS 1.3 but not all. If you can't find a strategy for TLS 1.2 use this test."
|
||||||
|
echo "TLS 1.3 only strategy is better than nothing."
|
||||||
|
ask_yes_no_var ENABLE_HTTPS_TLS13 "check https tls 1.3"
|
||||||
|
}
|
||||||
|
else
|
||||||
|
echo
|
||||||
|
echo "installed curl version does not support TLS 1.3 . tests disabled."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
[ -n "$ENABLE_HTTP3" ] || {
|
||||||
|
ENABLE_HTTP3=0
|
||||||
|
if [ -n "$HTTP3" ]; then
|
||||||
|
ENABLE_HTTP3=1
|
||||||
|
[ "$BATCH" = 1 ] || {
|
||||||
|
echo
|
||||||
|
echo "make sure target domain(s) support QUIC or result will be negative in any case"
|
||||||
|
ask_yes_no_var ENABLE_HTTP3 "check http3 QUIC"
|
||||||
|
}
|
||||||
|
else
|
||||||
|
echo
|
||||||
|
echo "installed curl version does not support http3 QUIC. tests disabled."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
[ -n "$REPEATS" ] || {
|
||||||
|
[ "$BATCH" = 1 ] || {
|
||||||
|
echo
|
||||||
|
echo "sometimes ISPs use multiple DPIs or load balancing. bypass strategies may work unstable."
|
||||||
|
printf "how many times to repeat each test (default: 1) : "
|
||||||
|
read REPEATS
|
||||||
|
}
|
||||||
|
REPEATS=$((0+${REPEATS:-1}))
|
||||||
|
[ "$REPEATS" = 0 ] && {
|
||||||
|
echo invalid repeat count
|
||||||
|
exitp 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[ -z "$PARALLEL" -a $REPEATS -gt 1 ] && {
|
||||||
|
PARALLEL=0
|
||||||
|
[ "$BATCH" = 1 ] || {
|
||||||
|
echo
|
||||||
|
echo "parallel scan can greatly increase speed but may also trigger DDoS protection and cause false result"
|
||||||
|
ask_yes_no_var PARALLEL "enable parallel scan"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PARALLEL=${PARALLEL:-0}
|
||||||
|
|
||||||
|
[ -n "$SCANLEVEL" ] || {
|
||||||
|
SCANLEVEL=standard
|
||||||
|
[ "$BATCH" = 1 ] || {
|
||||||
|
echo
|
||||||
|
echo quick - scan as fast as possible to reveal any working strategy
|
||||||
|
echo standard - do investigation what works on your DPI
|
||||||
|
echo force - scan maximum despite of result
|
||||||
|
ask_list SCANLEVEL "quick standard force" "$SCANLEVEL"
|
||||||
|
# disable tpws checks by default in quick mode
|
||||||
|
[ "$SCANLEVEL" = quick -a -z "$SKIP_TPWS" -a "$UNAME" != Darwin ] && SKIP_TPWS=1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
echo
|
echo
|
||||||
|
|
||||||
@ -1981,14 +2074,15 @@ check_dns()
|
|||||||
unprepare_all()
|
unprepare_all()
|
||||||
{
|
{
|
||||||
# make sure we are not in a middle state that impacts connectivity
|
# make sure we are not in a middle state that impacts connectivity
|
||||||
rm -f "$HDRTEMP"
|
|
||||||
[ -n "$IPV" ] && {
|
|
||||||
pktws_ipt_unprepare_tcp 80
|
|
||||||
pktws_ipt_unprepare_tcp 443
|
|
||||||
pktws_ipt_unprepare_udp 443
|
|
||||||
}
|
|
||||||
ws_kill
|
ws_kill
|
||||||
|
wait
|
||||||
|
[ -n "$IPV" ] && {
|
||||||
|
pktws_ipt_unprepare_tcp $HTTP_PORT
|
||||||
|
pktws_ipt_unprepare_tcp $HTTPS_PORT
|
||||||
|
pktws_ipt_unprepare_udp $QUIC_PORT
|
||||||
|
}
|
||||||
cleanup
|
cleanup
|
||||||
|
rm -f "${HDRTEMP}"* "${PARALLEL_OUT}"*
|
||||||
}
|
}
|
||||||
sigint()
|
sigint()
|
||||||
{
|
{
|
||||||
@ -2034,10 +2128,10 @@ for dom in $DOMAINS; do
|
|||||||
for IPV in $IPVS; do
|
for IPV in $IPVS; do
|
||||||
configure_ip_version
|
configure_ip_version
|
||||||
[ "$ENABLE_HTTP" = 1 ] && {
|
[ "$ENABLE_HTTP" = 1 ] && {
|
||||||
check_domain_port_block $dom $HTTP_PORT
|
[ "$SKIP_IPBLOCK" = 1 ] || check_domain_port_block $dom $HTTP_PORT
|
||||||
check_domain_http $dom
|
check_domain_http $dom
|
||||||
}
|
}
|
||||||
[ "$ENABLE_HTTPS_TLS12" = 1 -o "$ENABLE_HTTPS_TLS13" = 1 ] && check_domain_port_block $dom $HTTPS_PORT
|
[ "$ENABLE_HTTPS_TLS12" = 1 -o "$ENABLE_HTTPS_TLS13" = 1 ] && [ "$SKIP_IPBLOCK" != 1 ] && check_domain_port_block $dom $HTTPS_PORT
|
||||||
[ "$ENABLE_HTTPS_TLS12" = 1 ] && check_domain_https_tls12 $dom
|
[ "$ENABLE_HTTPS_TLS12" = 1 ] && check_domain_https_tls12 $dom
|
||||||
[ "$ENABLE_HTTPS_TLS13" = 1 ] && check_domain_https_tls13 $dom
|
[ "$ENABLE_HTTPS_TLS13" = 1 ] && check_domain_https_tls13 $dom
|
||||||
[ "$ENABLE_HTTP3" = 1 ] && check_domain_http3 $dom
|
[ "$ENABLE_HTTP3" = 1 ] && check_domain_http3 $dom
|
||||||
|
@ -241,7 +241,7 @@ fix_sbin_path()
|
|||||||
# it can calculate floating point expr
|
# it can calculate floating point expr
|
||||||
calc()
|
calc()
|
||||||
{
|
{
|
||||||
awk "BEGIN { print $*}";
|
LC_ALL=C awk "BEGIN { print $*}";
|
||||||
}
|
}
|
||||||
|
|
||||||
fsleep_setup()
|
fsleep_setup()
|
||||||
@ -318,18 +318,27 @@ setup_md5()
|
|||||||
exists $MD5 || MD5=md5
|
exists $MD5 || MD5=md5
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setup_random()
|
||||||
|
{
|
||||||
|
[ -n "$RCUT" ] && return
|
||||||
|
RCUT="cut -c 1-17"
|
||||||
|
# some shells can operate with 32 bit signed int
|
||||||
|
[ $((0x100000000)) = 0 ] && RCUT="cut -c 1-9"
|
||||||
|
}
|
||||||
|
|
||||||
random()
|
random()
|
||||||
{
|
{
|
||||||
# $1 - min, $2 - max
|
# $1 - min, $2 - max
|
||||||
local r rs
|
local r rs
|
||||||
setup_md5
|
setup_md5
|
||||||
|
setup_random
|
||||||
if [ -c /dev/urandom ]; then
|
if [ -c /dev/urandom ]; then
|
||||||
read rs </dev/urandom
|
read rs </dev/urandom
|
||||||
else
|
else
|
||||||
rs="$RANDOM$RANDOM$(date)"
|
rs="$RANDOM$RANDOM$(date)"
|
||||||
fi
|
fi
|
||||||
# shells use signed int64
|
# shells use signed int64
|
||||||
r=1$(echo $rs | $MD5 | sed 's/[^0-9]//g' | cut -c 1-17)
|
r=1$(echo $rs | $MD5 | sed 's/[^0-9]//g' | $RCUT)
|
||||||
echo $(( ($r % ($2-$1+1)) + $1 ))
|
echo $(( ($r % ($2-$1+1)) + $1 ))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
readonly GET_LIST_PREFIX=/ipset/get_
|
GET_LIST_PREFIX=/ipset/get_
|
||||||
|
|
||||||
SYSTEMD_DIR=/lib/systemd
|
SYSTEMD_DIR=/lib/systemd
|
||||||
[ -d "$SYSTEMD_DIR" ] || SYSTEMD_DIR=/usr/lib/systemd
|
[ -d "$SYSTEMD_DIR" ] || SYSTEMD_DIR=/usr/lib/systemd
|
||||||
@ -617,11 +617,17 @@ write_config_var()
|
|||||||
replace_var_def $1 "$M" "$ZAPRET_CONFIG"
|
replace_var_def $1 "$M" "$ZAPRET_CONFIG"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
no_prereq_exit()
|
||||||
|
{
|
||||||
|
echo could not install prerequisites
|
||||||
|
exitp 6
|
||||||
|
}
|
||||||
check_prerequisites_linux()
|
check_prerequisites_linux()
|
||||||
{
|
{
|
||||||
echo \* checking prerequisites
|
echo \* checking prerequisites
|
||||||
|
|
||||||
local s cmd PKGS UTILS req="curl curl"
|
local s cmd PKGS UTILS req="curl curl"
|
||||||
|
local APTGET DNF YUM PACMAN ZYPPER EOPKG APK
|
||||||
case "$FWTYPE" in
|
case "$FWTYPE" in
|
||||||
iptables)
|
iptables)
|
||||||
req="$req iptables iptables ip6tables iptables ipset ipset"
|
req="$req iptables iptables ip6tables iptables ipset ipset"
|
||||||
@ -650,6 +656,7 @@ check_prerequisites_linux()
|
|||||||
echo packages required : $PKGS
|
echo packages required : $PKGS
|
||||||
|
|
||||||
APTGET=$(whichq apt-get)
|
APTGET=$(whichq apt-get)
|
||||||
|
DNF=$(whichq dnf)
|
||||||
YUM=$(whichq yum)
|
YUM=$(whichq yum)
|
||||||
PACMAN=$(whichq pacman)
|
PACMAN=$(whichq pacman)
|
||||||
ZYPPER=$(whichq zypper)
|
ZYPPER=$(whichq zypper)
|
||||||
@ -657,39 +664,23 @@ check_prerequisites_linux()
|
|||||||
APK=$(whichq apk)
|
APK=$(whichq apk)
|
||||||
if [ -x "$APTGET" ] ; then
|
if [ -x "$APTGET" ] ; then
|
||||||
"$APTGET" update
|
"$APTGET" update
|
||||||
"$APTGET" install -y --no-install-recommends $PKGS dnsutils || {
|
"$APTGET" install -y --no-install-recommends $PKGS dnsutils || no_prereq_exit
|
||||||
echo could not install prerequisites
|
elif [ -x "$DNF" ] ; then
|
||||||
exitp 6
|
"$DNF" -y install $PKGS || no_prereq_exit
|
||||||
}
|
|
||||||
elif [ -x "$YUM" ] ; then
|
elif [ -x "$YUM" ] ; then
|
||||||
"$YUM" -y install $PKGS || {
|
"$YUM" -y install $PKGS || no_prereq_exit
|
||||||
echo could not install prerequisites
|
|
||||||
exitp 6
|
|
||||||
}
|
|
||||||
elif [ -x "$PACMAN" ] ; then
|
elif [ -x "$PACMAN" ] ; then
|
||||||
"$PACMAN" -Syy
|
"$PACMAN" -Syy
|
||||||
"$PACMAN" --noconfirm -S $PKGS || {
|
"$PACMAN" --noconfirm -S $PKGS || no_prereq_exit
|
||||||
echo could not install prerequisites
|
|
||||||
exitp 6
|
|
||||||
}
|
|
||||||
elif [ -x "$ZYPPER" ] ; then
|
elif [ -x "$ZYPPER" ] ; then
|
||||||
"$ZYPPER" --non-interactive install $PKGS || {
|
"$ZYPPER" --non-interactive install $PKGS || no_prereq_exit
|
||||||
echo could not install prerequisites
|
|
||||||
exitp 6
|
|
||||||
}
|
|
||||||
elif [ -x "$EOPKG" ] ; then
|
elif [ -x "$EOPKG" ] ; then
|
||||||
"$EOPKG" -y install $PKGS || {
|
"$EOPKG" -y install $PKGS || no_prereq_exit
|
||||||
echo could not install prerequisites
|
|
||||||
exitp 6
|
|
||||||
}
|
|
||||||
elif [ -x "$APK" ] ; then
|
elif [ -x "$APK" ] ; then
|
||||||
"$APK" update
|
"$APK" update
|
||||||
# for alpine
|
# for alpine
|
||||||
[ "$FWTYPE" = iptables ] && [ -n "$($APK list ip6tables)" ] && PKGS="$PKGS ip6tables"
|
[ "$FWTYPE" = iptables ] && [ -n "$($APK list ip6tables)" ] && PKGS="$PKGS ip6tables"
|
||||||
"$APK" add $PKGS || {
|
"$APK" add $PKGS || no_prereq_exit
|
||||||
echo could not install prerequisites
|
|
||||||
exitp 6
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
echo supported package manager not found
|
echo supported package manager not found
|
||||||
echo you must manually install : $UTILS
|
echo you must manually install : $UTILS
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
std_ports
|
std_ports
|
||||||
readonly ipt_connbytes="-m connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes"
|
ipt_connbytes="-m connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes"
|
||||||
|
IPSET_EXCLUDE="-m set ! --match-set nozapret"
|
||||||
|
IPSET_EXCLUDE6="-m set ! --match-set nozapret6"
|
||||||
|
IPBAN_EXCLUDE="-m set ! --match-set ipban"
|
||||||
|
IPBAN_EXCLUDE6="-m set ! --match-set ipban6"
|
||||||
|
|
||||||
ipt()
|
ipt()
|
||||||
{
|
{
|
||||||
@ -132,7 +136,7 @@ _fw_tpws4()
|
|||||||
|
|
||||||
ipt_print_op $1 "$2" "tpws (port $3)"
|
ipt_print_op $1 "$2" "tpws (port $3)"
|
||||||
|
|
||||||
rule="$2 $IPSET_EXCLUDE dst -j DNAT --to $TPWS_LOCALHOST4:$3"
|
rule="$2 $IPSET_EXCLUDE dst $IPBAN_EXCLUDE dst -j DNAT --to $TPWS_LOCALHOST4:$3"
|
||||||
for i in $4 ; do
|
for i in $4 ; do
|
||||||
ipt_add_del $1 PREROUTING -t nat -i $i $rule
|
ipt_add_del $1 PREROUTING -t nat -i $i $rule
|
||||||
done
|
done
|
||||||
@ -160,7 +164,7 @@ _fw_tpws6()
|
|||||||
|
|
||||||
ipt_print_op $1 "$2" "tpws (port $3)" 6
|
ipt_print_op $1 "$2" "tpws (port $3)" 6
|
||||||
|
|
||||||
rule="$2 $IPSET_EXCLUDE6 dst"
|
rule="$2 $IPSET_EXCLUDE6 dst $IPBAN_EXCLUDE6 dst"
|
||||||
for i in $4 ; do
|
for i in $4 ; do
|
||||||
_dnat6_target $i DNAT6
|
_dnat6_target $i DNAT6
|
||||||
[ -n "$DNAT6" -a "$DNAT6" != "-" ] && ipt6_add_del $1 PREROUTING -t nat -i $i $rule -j DNAT --to [$DNAT6]:$3
|
[ -n "$DNAT6" -a "$DNAT6" != "-" ] && ipt6_add_del $1 PREROUTING -t nat -i $i $rule -j DNAT --to [$DNAT6]:$3
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
# PREROUTING - can't DNAT to ::1. can DNAT to link local of -i interface or to any global addr
|
# PREROUTING - can't DNAT to ::1. can DNAT to link local of -i interface or to any global addr
|
||||||
# not a good idea to expose tpws to the world (bind to ::)
|
# not a good idea to expose tpws to the world (bind to ::)
|
||||||
|
|
||||||
|
# max wait time for the link local ipv6 on the LAN interface
|
||||||
|
LINKLOCAL_WAIT_SEC=${LINKLOCAL_WAIT_SEC:-5}
|
||||||
|
|
||||||
get_ipv6_linklocal()
|
get_ipv6_linklocal()
|
||||||
{
|
{
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
readonly HOSTLIST_MARKER="<HOSTLIST>"
|
HOSTLIST_MARKER="<HOSTLIST>"
|
||||||
readonly HOSTLIST_NOAUTO_MARKER="<HOSTLIST_NOAUTO>"
|
HOSTLIST_NOAUTO_MARKER="<HOSTLIST_NOAUTO>"
|
||||||
|
|
||||||
find_hostlists()
|
find_hostlists()
|
||||||
{
|
{
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
[ -n "$ZAPRET_NFT_TABLE" ] || ZAPRET_NFT_TABLE=zapret
|
[ -n "$ZAPRET_NFT_TABLE" ] || ZAPRET_NFT_TABLE=zapret
|
||||||
readonly nft_connbytes="ct original packets"
|
nft_connbytes="ct original packets"
|
||||||
|
|
||||||
# required for : nft -f -
|
# required for : nft -f -
|
||||||
create_dev_stdin
|
create_dev_stdin
|
||||||
@ -263,28 +263,6 @@ nft_add_flow_offload_exemption()
|
|||||||
[ "$DISABLE_IPV6" = "1" -o -z "$2" ] || nft_add_rule flow_offload oifname @wanif6 $2 ip6 daddr != @nozapret6 return comment \"$3\"
|
[ "$DISABLE_IPV6" = "1" -o -z "$2" ] || nft_add_rule flow_offload oifname @wanif6 $2 ip6 daddr != @nozapret6 return comment \"$3\"
|
||||||
}
|
}
|
||||||
|
|
||||||
nft_hw_offload_supported()
|
|
||||||
{
|
|
||||||
# $1,$2,... - interface names
|
|
||||||
local devices res=1
|
|
||||||
make_quoted_comma_list devices "$@"
|
|
||||||
[ -n "$devices" ] && devices="devices={$devices};"
|
|
||||||
nft add table ${ZAPRET_NFT_TABLE}_test && nft add flowtable ${ZAPRET_NFT_TABLE}_test ft "{ flags offload; $devices }" 2>/dev/null && res=0
|
|
||||||
nft delete table ${ZAPRET_NFT_TABLE}_test 2>/dev/null
|
|
||||||
return $res
|
|
||||||
}
|
|
||||||
|
|
||||||
nft_hw_offload_find_supported()
|
|
||||||
{
|
|
||||||
# $1,$2,... - interface names
|
|
||||||
local supported_list
|
|
||||||
while [ -n "$1" ]; do
|
|
||||||
nft_hw_offload_supported "$1" && append_separator_list supported_list ' ' '' "$1"
|
|
||||||
shift
|
|
||||||
done
|
|
||||||
echo $supported_list
|
|
||||||
}
|
|
||||||
|
|
||||||
nft_apply_flow_offloading()
|
nft_apply_flow_offloading()
|
||||||
{
|
{
|
||||||
# ft can be absent
|
# ft can be absent
|
||||||
@ -370,17 +348,15 @@ flush set inet $ZAPRET_NFT_TABLE lanif"
|
|||||||
nft_create_or_update_flowtable 'offload' 2>/dev/null
|
nft_create_or_update_flowtable 'offload' 2>/dev/null
|
||||||
# then add elements. some of them can cause error because unsupported
|
# then add elements. some of them can cause error because unsupported
|
||||||
for i in $ALLDEVS; do
|
for i in $ALLDEVS; do
|
||||||
if nft_hw_offload_supported $i; then
|
# first try to add interface itself
|
||||||
nft_create_or_update_flowtable 'offload' $i
|
nft_create_or_update_flowtable 'offload' $i 2>/dev/null
|
||||||
else
|
# bridge members must be added instead of the bridge itself
|
||||||
# bridge members must be added instead of the bridge itself
|
# some members may not support hw offload. example : lan1 lan2 lan3 support, wlan0 wlan1 - not
|
||||||
# some members may not support hw offload. example : lan1 lan2 lan3 support, wlan0 wlan1 - not
|
devs=$(resolve_lower_devices $i)
|
||||||
devs=$(resolve_lower_devices $i)
|
for j in $devs; do
|
||||||
for j in $devs; do
|
# do not display error if addition failed
|
||||||
# do not display error if addition failed
|
nft_create_or_update_flowtable 'offload' $j 2>/dev/null
|
||||||
nft_create_or_update_flowtable 'offload' $j 2>/dev/null
|
done
|
||||||
done
|
|
||||||
fi
|
|
||||||
done
|
done
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
@ -411,8 +387,8 @@ _nft_fw_tpws4()
|
|||||||
[ "$DISABLE_IPV4" = "1" -o -z "$1" ] || {
|
[ "$DISABLE_IPV4" = "1" -o -z "$1" ] || {
|
||||||
local filter="$1" port="$2"
|
local filter="$1" port="$2"
|
||||||
nft_print_op "$filter" "tpws (port $2)" 4
|
nft_print_op "$filter" "tpws (port $2)" 4
|
||||||
nft_insert_rule dnat_output skuid != $WS_USER ${3:+oifname @wanif }$filter ip daddr != @nozapret $FW_EXTRA_POST dnat ip to $TPWS_LOCALHOST4:$port
|
nft_insert_rule dnat_output skuid != $WS_USER ${3:+oifname @wanif }$filter ip daddr != @nozapret ip daddr != @ipban $FW_EXTRA_POST dnat ip to $TPWS_LOCALHOST4:$port
|
||||||
nft_insert_rule dnat_pre iifname @lanif $filter ip daddr != @nozapret $FW_EXTRA_POST dnat ip to $TPWS_LOCALHOST4:$port
|
nft_insert_rule dnat_pre iifname @lanif $filter ip daddr != @nozapret ip daddr != @ipban $FW_EXTRA_POST dnat ip to $TPWS_LOCALHOST4:$port
|
||||||
prepare_route_localnet
|
prepare_route_localnet
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -426,9 +402,9 @@ _nft_fw_tpws6()
|
|||||||
[ "$DISABLE_IPV6" = "1" -o -z "$1" ] || {
|
[ "$DISABLE_IPV6" = "1" -o -z "$1" ] || {
|
||||||
local filter="$1" port="$2" DNAT6 i
|
local filter="$1" port="$2" DNAT6 i
|
||||||
nft_print_op "$filter" "tpws (port $port)" 6
|
nft_print_op "$filter" "tpws (port $port)" 6
|
||||||
nft_insert_rule dnat_output skuid != $WS_USER ${4:+oifname @wanif6 }$filter ip6 daddr != @nozapret6 $FW_EXTRA_POST dnat ip6 to [::1]:$port
|
nft_insert_rule dnat_output skuid != $WS_USER ${4:+oifname @wanif6 }$filter ip6 daddr != @nozapret6 ip6 daddr != @ipban6 $FW_EXTRA_POST dnat ip6 to [::1]:$port
|
||||||
[ -n "$3" ] && {
|
[ -n "$3" ] && {
|
||||||
nft_insert_rule dnat_pre $filter ip6 daddr != @nozapret6 $FW_EXTRA_POST dnat ip6 to iifname map @link_local:$port
|
nft_insert_rule dnat_pre $filter ip6 daddr != @nozapret6 ip6 daddr != @ipban6 $FW_EXTRA_POST dnat ip6 to iifname map @link_local:$port
|
||||||
for i in $3; do
|
for i in $3; do
|
||||||
_dnat6_target $i DNAT6
|
_dnat6_target $i DNAT6
|
||||||
# can be multiple tpws processes on different ports
|
# can be multiple tpws processes on different ports
|
||||||
|
@ -97,7 +97,7 @@ NFQWS_OPT="
|
|||||||
# none,ipset,hostlist,autohostlist
|
# none,ipset,hostlist,autohostlist
|
||||||
MODE_FILTER=none
|
MODE_FILTER=none
|
||||||
|
|
||||||
# openwrt only : donttouch,none,software,hardware
|
# donttouch,none,software,hardware
|
||||||
FLOWOFFLOAD=donttouch
|
FLOWOFFLOAD=donttouch
|
||||||
|
|
||||||
# openwrt: specify networks to be treated as LAN. default is "lan"
|
# openwrt: specify networks to be treated as LAN. default is "lan"
|
||||||
|
@ -434,3 +434,54 @@ v69.8
|
|||||||
|
|
||||||
winws: accept empty outgoing RST and FIN packets for conntrack needs
|
winws: accept empty outgoing RST and FIN packets for conntrack needs
|
||||||
repo: lexra build
|
repo: lexra build
|
||||||
|
|
||||||
|
v69.9
|
||||||
|
|
||||||
|
init.d: exclude ipban from tpws redirection
|
||||||
|
macos: fix install_easy
|
||||||
|
macos: fix national decimal separator in sleep
|
||||||
|
ipset: scripts maintenance
|
||||||
|
|
||||||
|
v70
|
||||||
|
|
||||||
|
blockcheck: override all dialog questions and enable batch mode
|
||||||
|
blockcheck: parallel attempts
|
||||||
|
nfqws: weaken wireguard initiation recognition. use len=148 and data[0]=1 signature
|
||||||
|
nfqws: apply split+seqovl only to the first reasm fragment
|
||||||
|
install_easy: dnf packager support
|
||||||
|
nfqws,tpws: hostlist/ipset track not only file mod time but also file size
|
||||||
|
nfqws,tpws,ipset: return lists reload on HUP
|
||||||
|
nfqws,blockcheck: --dpi-desync-fake-tls-mod
|
||||||
|
|
||||||
|
v70.1
|
||||||
|
|
||||||
|
nfqws: --dpi-desync-fake-tls-mod=dupsid
|
||||||
|
nfqws,tpws: test accessibility of list files after privs drop
|
||||||
|
nfqws,tpws: --version
|
||||||
|
|
||||||
|
v70.4
|
||||||
|
|
||||||
|
nfqws,tpws: ^ prefix in hostlist to disable subdomain matches
|
||||||
|
nfqws,tpws: optional systemd notify support. compile using 'make systemd'
|
||||||
|
nfqws,tpws: systemd instance templates for nfqws and tpws
|
||||||
|
nfqws,tpws: separate droproot from dropcaps
|
||||||
|
tpws: detect WSL 1 and warn about non-working options
|
||||||
|
|
||||||
|
v70.5
|
||||||
|
|
||||||
|
nfqws: multiple --dpi-desync-fake-xxx
|
||||||
|
nfqws: support of inter-packet fragmented QUIC CRYPTO
|
||||||
|
|
||||||
|
v70.6
|
||||||
|
|
||||||
|
nfqws: detect Discord Voice IP discovery packets
|
||||||
|
nfqws: detect STUN message packets
|
||||||
|
nfqws: change SNI to specified value tls mod : --dpi-desync-fake-tls-mod sni=<sni>
|
||||||
|
nfqws: update default TLS ClientHello fake. firefox 136.0.4 finger, no kyber, SNI=microsoft.com
|
||||||
|
nfqws: multiple mods for multiple TLS fakes
|
||||||
|
init.d: remove 50-discord
|
||||||
|
blockcheck: use tpws --fix-seg on linux for multiple splits
|
||||||
|
|
||||||
|
v70.7
|
||||||
|
|
||||||
|
nfqws,tpws: debug tls version, alpn, ech
|
||||||
|
@ -12,10 +12,10 @@ Other packages may be required on your distribution. Look for the errors.
|
|||||||
|
|
||||||
examples :
|
examples :
|
||||||
|
|
||||||
curl -o - https://downloads.openwrt.org/releases/23.05.5/targets/x86/64/openwrt-sdk-23.05.5-x86-64_gcc-12.3.0_musl.Linux-x86_64.tar.xz | tar -Jxvf -
|
curl -o - https://downloads.openwrt.org/releases/23.05.5/targets/x86/64/openwrt-sdk-23.05.5-x86-64_gcc-12.3.0_musl.Linux-x86_64.tar.xz | tar -Jxv
|
||||||
cd openwrt-sdk-23.05.5-x86-64_gcc-12.3.0_musl.Linux-x86_64
|
cd openwrt-sdk-23.05.5-x86-64_gcc-12.3.0_musl.Linux-x86_64
|
||||||
|
|
||||||
curl -o - https://downloads.openwrt.org/snapshots/targets/x86/64/openwrt-sdk-x86-64_gcc-13.3.0_musl.Linux-x86_64.tar.zst | tar --zstd -xvf -
|
curl -o - https://downloads.openwrt.org/snapshots/targets/x86/64/openwrt-sdk-x86-64_gcc-13.3.0_musl.Linux-x86_64.tar.zst | tar --zstd -xv
|
||||||
cd openwrt-sdk-x86-64_gcc-13.3.0_musl.Linux-x86_64
|
cd openwrt-sdk-x86-64_gcc-13.3.0_musl.Linux-x86_64
|
||||||
|
|
||||||
3) Install required libs
|
3) Install required libs
|
||||||
@ -48,7 +48,7 @@ static build : make CFLAGS=-static package/{tpws,nfqws,mdig,ip2net}/compile
|
|||||||
executables only : build_dir/target/<progname>
|
executables only : build_dir/target/<progname>
|
||||||
ipk or apk packages : bin/packages/*/base
|
ipk or apk packages : bin/packages/*/base
|
||||||
|
|
||||||
8) Installating to openwrt to use with zapret
|
8) Installing to openwrt to use with zapret
|
||||||
|
|
||||||
zapret with or without binaries should be already installed in /opt/zapret.
|
zapret with or without binaries should be already installed in /opt/zapret.
|
||||||
Install ipk's or apk's with all compiled progs using opkg or apk.
|
Install ipk's or apk's with all compiled progs using opkg or apk.
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
debian,ubuntu :
|
debian,ubuntu :
|
||||||
|
|
||||||
apt install make gcc zlib1g-dev libcap-dev libnetfilter-queue-dev
|
apt install make gcc zlib1g-dev libcap-dev libnetfilter-queue-dev libsystemd-dev
|
||||||
make -C /opt/zapret
|
make -C /opt/zapret systemd
|
||||||
|
|
||||||
FreeBSD :
|
FreeBSD :
|
||||||
|
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
> [!CAUTION]
|
> [!CAUTION]
|
||||||
> Не пишите в issue вопросы типа "как скопировать файл", "как скачать", "как
|
> Не пишите в issue вопросы типа "как скопировать файл", "как скачать", "как
|
||||||
> запустить", ... То есть все , что касается базовых навыков обращения с ОС
|
> запустить" и т.п. То есть все, что касается базовых навыков обращения с ОС
|
||||||
> linux. Эти вопросы будут закрывать сразу. Если у вас подобные вопросы
|
> Linux. Эти вопросы будут закрывать сразу. Если у вас подобные вопросы
|
||||||
> возникают, рекомендую не использовать данный софт или искать помощь где-то в
|
> возникают, рекомендую не использовать данный софт или искать помощь где-то в
|
||||||
> другом месте. То же самое могу сказать тем, кто хочет нажать 1 кнопку, чтобы
|
> другом месте. То же самое могу сказать тем, кто хочет нажать 1 кнопку, чтобы
|
||||||
> все заработало, и совсем не хочет читать и изучать. Увы, такое не подвезли и
|
> все заработало, и совсем не хочет читать и изучать. Увы, такое не подвезли и
|
||||||
@ -89,14 +89,15 @@
|
|||||||
>
|
>
|
||||||
> Проверить работает ли этот вариант можно так:
|
> Проверить работает ли этот вариант можно так:
|
||||||
> ```sh
|
> ```sh
|
||||||
> $ dig -p 53 @77.88.8.88 rutracker.org dig -p 1253 @77.88.8.88 rutracker.org
|
> $ dig -p 53 @77.88.8.88 rutracker.org
|
||||||
|
> $ dig -p 1253 @77.88.8.88 rutracker.org
|
||||||
> ```
|
> ```
|
||||||
>
|
>
|
||||||
> Если DNS действительно подменяется, и ответ на эти 2 команды разный,
|
> Если DNS действительно подменяется, и ответ на эти 2 команды разный,
|
||||||
> значит метод вероятно работает.
|
> значит метод вероятно работает.
|
||||||
>
|
>
|
||||||
> В openwrt DNS на нестандартном порту можно прописать в `/etc/config/dhcp`
|
> В openwrt DNS на нестандартном порту можно прописать в `/etc/config/dhcp`
|
||||||
> таким способом :
|
> таким способом:
|
||||||
>
|
>
|
||||||
> ```
|
> ```
|
||||||
> config dnsmasq
|
> config dnsmasq
|
||||||
@ -163,7 +164,7 @@
|
|||||||
> Если кратко, то обычно параметры конструируются так:
|
> Если кратко, то обычно параметры конструируются так:
|
||||||
> ```sh
|
> ```sh
|
||||||
> "--filter-udp=443 'параметры для quic' <HOSTLIST_NOAUTO> --new
|
> "--filter-udp=443 'параметры для quic' <HOSTLIST_NOAUTO> --new
|
||||||
> --filter-tcp=80,443 'обьединенные параметры для http и https' <HOSTLIST>"
|
> --filter-tcp=80,443 'объединенные параметры для http и https' <HOSTLIST>"
|
||||||
> ```
|
> ```
|
||||||
>
|
>
|
||||||
> Или так:
|
> Или так:
|
||||||
@ -193,7 +194,7 @@
|
|||||||
> "--filter-l3=ipv4 --filter-udp=443 lпараметры для quic ipv4' <HOSTLIST_NOAUTO> --new
|
> "--filter-l3=ipv4 --filter-udp=443 lпараметры для quic ipv4' <HOSTLIST_NOAUTO> --new
|
||||||
> --filter-l3=ipv4 --filter-tcp=80 'параметры для http ipv4' <HOSTLIST> --new
|
> --filter-l3=ipv4 --filter-tcp=80 'параметры для http ipv4' <HOSTLIST> --new
|
||||||
> --filter-l3=ipv4 --filter-tcp=443 'параметры для https ipv4' <HOSTLIST> --new
|
> --filter-l3=ipv4 --filter-tcp=443 'параметры для https ipv4' <HOSTLIST> --new
|
||||||
> --filter-l3=ipv6 --filter-udp=443 "параметры для quic ipv6" <HOSTLIST_NOAUTO> --new
|
> --filter-l3=ipv6 --filter-udp=443 'параметры для quic ipv6' <HOSTLIST_NOAUTO> --new
|
||||||
> --filter-l3=ipv6 --filter-tcp=80 'параметры для http ipv6' <HOSTLIST> --new
|
> --filter-l3=ipv6 --filter-tcp=80 'параметры для http ipv6' <HOSTLIST> --new
|
||||||
> --filter-l3=ipv6 --filter-tcp=443 'параметры для https ipv6' <HOSTLIST>"
|
> --filter-l3=ipv6 --filter-tcp=443 'параметры для https ipv6' <HOSTLIST>"
|
||||||
> ```
|
> ```
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# zapret v69.8
|
# zapret v70.6
|
||||||
|
|
||||||
# SCAMMER WARNING
|
# SCAMMER WARNING
|
||||||
|
|
||||||
@ -19,6 +19,7 @@ ___
|
|||||||
- [nfqws](#nfqws)
|
- [nfqws](#nfqws)
|
||||||
- [DPI desync attack](#dpi-desync-attack)
|
- [DPI desync attack](#dpi-desync-attack)
|
||||||
- [Fakes](#fakes)
|
- [Fakes](#fakes)
|
||||||
|
- [Fake mods](#fake-mods)
|
||||||
- [TCP segmentation](#tcp-segmentation)
|
- [TCP segmentation](#tcp-segmentation)
|
||||||
- [Sequence numbers overlap](#sequence-numbers-overlap)
|
- [Sequence numbers overlap](#sequence-numbers-overlap)
|
||||||
- [ipv6 specific modes](#ipv6-specific-modes)
|
- [ipv6 specific modes](#ipv6-specific-modes)
|
||||||
@ -119,7 +120,7 @@ You need to run them with the necessary parameters and redirect certain traffic
|
|||||||
when blocked domains are queried. If this is the case change DNS to public ones, such as 8.8.8.8 or 1.1.1.1.Sometimes ISP hijacks queries to any DNS server. Dnscrypt or dns-over-tls help.
|
when blocked domains are queried. If this is the case change DNS to public ones, such as 8.8.8.8 or 1.1.1.1.Sometimes ISP hijacks queries to any DNS server. Dnscrypt or dns-over-tls help.
|
||||||
* If blocking is done by IP.
|
* If blocking is done by IP.
|
||||||
* If a connection passes through a filter capable of reconstructing a TCP connection, and which
|
* If a connection passes through a filter capable of reconstructing a TCP connection, and which
|
||||||
follows all standards. For example, we are routed to squid. Connection goes through the full OS tcpip stack, fragmentation disappears immediately as a means of circumvention. Squid is correct, it will find everything as it should, it is useless to deceive him. BUT. Only small providers can afford using squid, since it is very resource intensive. Large companies usually use DPI, which is designed for much greater bandwidth.
|
follows all standards. For example, we are routed to squid. Connection goes through the full OS tcpip stack. This project targets DPI only, not full OS stack and not server applications.
|
||||||
|
|
||||||
## nfqws
|
## nfqws
|
||||||
|
|
||||||
@ -132,6 +133,7 @@ nfqws takes the following parameters:
|
|||||||
|
|
||||||
--debug=0|1
|
--debug=0|1
|
||||||
--dry-run ; verify parameters and exit with code 0 if successful
|
--dry-run ; verify parameters and exit with code 0 if successful
|
||||||
|
--version ; print version and exit
|
||||||
--comment ; any text (ignored)
|
--comment ; any text (ignored)
|
||||||
--qnum=<nfqueue_number>
|
--qnum=<nfqueue_number>
|
||||||
--daemon ; daemonize
|
--daemon ; daemonize
|
||||||
@ -172,31 +174,34 @@ nfqws takes the following parameters:
|
|||||||
--dpi-desync-any-protocol=0|1 ; 0(default)=desync only http and tls 1=desync any nonempty data packet
|
--dpi-desync-any-protocol=0|1 ; 0(default)=desync only http and tls 1=desync any nonempty data packet
|
||||||
--dpi-desync-fake-http=<filename>|0xHEX ; file containing fake http request
|
--dpi-desync-fake-http=<filename>|0xHEX ; file containing fake http request
|
||||||
--dpi-desync-fake-tls=<filename>|0xHEX ; file containing fake TLS ClientHello (for https)
|
--dpi-desync-fake-tls=<filename>|0xHEX ; file containing fake TLS ClientHello (for https)
|
||||||
|
--dpi-desync-fake-tls-mod=mod[,mod] ; comma separated list of TLS fake mods. available mods : none,rnd,rndsni,sni=<sni>,dupsid,padencap
|
||||||
--dpi-desync-fake-unknown=<filename>|0xHEX ; file containing unknown protocol fake payload
|
--dpi-desync-fake-unknown=<filename>|0xHEX ; file containing unknown protocol fake payload
|
||||||
--dpi-desync-fake-syndata=<filename>|0xHEX ; file containing SYN data payload
|
--dpi-desync-fake-syndata=<filename>|0xHEX ; file containing SYN data payload
|
||||||
--dpi-desync-fake-quic=<filename>|0xHEX ; file containing fake QUIC Initial
|
--dpi-desync-fake-quic=<filename>|0xHEX ; file containing fake QUIC Initial
|
||||||
--dpi-desync-fake-wireguard=<filename>|0xHEX ; file containing fake wireguard handshake initiation
|
--dpi-desync-fake-wireguard=<filename>|0xHEX ; file containing fake wireguard handshake initiation
|
||||||
--dpi-desync-fake-dht=<filename>|0xHEX ; file containing fake DHT (d1..e)
|
--dpi-desync-fake-dht=<filename>|0xHEX ; file containing fake DHT (d1..e)
|
||||||
|
--dpi-desync-fake-discord=<filename>|0xHEX ; file containing fake Discord voice connection initiation packet (IP Discovery)
|
||||||
|
--dpi-desync-fake-stun=<filename>|0xHEX ; file containing fake STUN message
|
||||||
--dpi-desync-fake-unknown-udp=<filename>|0xHEX ; file containing unknown udp protocol fake payload
|
--dpi-desync-fake-unknown-udp=<filename>|0xHEX ; file containing unknown udp protocol fake payload
|
||||||
--dpi-desync-udplen-increment=<int> ; increase or decrease udp packet length by N bytes (default 2). negative values decrease length.
|
--dpi-desync-udplen-increment=<int> ; increase or decrease udp packet length by N bytes (default 2). negative values decrease length.
|
||||||
--dpi-desync-udplen-pattern=<filename>|0xHEX ; udp tail fill pattern
|
--dpi-desync-udplen-pattern=<filename>|0xHEX ; udp tail fill pattern
|
||||||
--dpi-desync-start=[n|d|s]N ; apply dpi desync only to packet numbers (n, default), data packet numbers (d), relative sequence (s) greater or equal than N
|
--dpi-desync-start=[n|d|s]N ; apply dpi desync only to packet numbers (n, default), data packet numbers (d), relative sequence (s) greater or equal than N
|
||||||
--dpi-desync-cutoff=[n|d|s]N ; apply dpi desync only to packet numbers (n, default), data packet numbers (d), relative sequence (s) less than N
|
--dpi-desync-cutoff=[n|d|s]N ; apply dpi desync only to packet numbers (n, default), data packet numbers (d), relative sequence (s) less than N
|
||||||
--hostlist=<filename> ; apply dpi desync only to the listed hosts (one host per line, subdomains auto apply, gzip supported, multiple hostlists allowed)
|
--hostlist=<filename> ; apply dpi desync only to the listed hosts (one host per line, subdomains auto apply if not prefixed with `^`, gzip supported, multiple hostlists allowed)
|
||||||
--hostlist-domains=<domain_list> ; comma separated fixed domain list
|
--hostlist-domains=<domain_list> ; comma separated fixed domain list
|
||||||
--hostlist-exclude=<filename> ; do not apply dpi desync to the listed hosts (one host per line, subdomains auto apply, gzip supported, multiple hostlists allowed)
|
--hostlist-exclude=<filename> ; do not apply dpi desync to the listed hosts (one host per line, subdomains auto apply if not prefixed with `^`, gzip supported, multiple hostlists allowed)
|
||||||
--hostlist-exclude-domains=<domain_list> ; comma separated fixed domain list
|
--hostlist-exclude-domains=<domain_list> ; comma separated fixed domain list
|
||||||
--hostlist-auto=<filename> ; detect DPI blocks and build hostlist automatically
|
--hostlist-auto=<filename> ; detect DPI blocks and build hostlist automatically
|
||||||
--hostlist-auto-fail-threshold=<int> ; how many failed attempts cause hostname to be added to auto hostlist (default : 3)
|
--hostlist-auto-fail-threshold=<int> ; how many failed attempts cause hostname to be added to auto hostlist (default : 3)
|
||||||
--hostlist-auto-fail-time=<int> ; all failed attemps must be within these seconds (default : 60)
|
--hostlist-auto-fail-time=<int> ; all failed attemps must be within these seconds (default : 60)
|
||||||
--hostlist-auto-retrans-threshold=<int> ; how many request retransmissions cause attempt to fail (default : 3)
|
--hostlist-auto-retrans-threshold=<int> ; how many request retransmissions cause attempt to fail (default : 3)
|
||||||
--hostlist-auto-debug=<logfile> ; debug auto hostlist positives
|
--hostlist-auto-debug=<logfile> ; debug auto hostlist positives
|
||||||
--new ; begin new strategy (new profile)
|
--new ; begin new strategy (new profile)
|
||||||
--skip ; do not use this profile
|
--skip ; do not use this profile
|
||||||
--filter-l3=ipv4|ipv6 ; L3 protocol filter. multiple comma separated values allowed.
|
--filter-l3=ipv4|ipv6 ; L3 protocol filter. multiple comma separated values allowed.
|
||||||
--filter-tcp=[~]port1[-port2]|* ; TCP port filter. ~ means negation. setting tcp and not setting udp filter denies udp. comma separated list supported.
|
--filter-tcp=[~]port1[-port2]|* ; TCP port filter. ~ means negation. setting tcp and not setting udp filter denies udp. comma separated list supported.
|
||||||
--filter-udp=[~]port1[-port2]|* ; UDP port filter. ~ means negation. setting udp and not setting tcp filter denies tcp. comma separated list supported.
|
--filter-udp=[~]port1[-port2]|* ; UDP port filter. ~ means negation. setting udp and not setting tcp filter denies tcp. comma separated list supported.
|
||||||
--filter-l7=[http|tls|quic|wireguard|dht|unknown] ; L6-L7 protocol filter. multiple comma separated values allowed.
|
--filter-l7=<proto> ; L6-L7 protocol filter. multiple comma separated values allowed. proto: http tls quic wireguard dht discord stun unknown
|
||||||
--ipset=<filename> ; ipset include filter (one ip/CIDR per line, ipv4 and ipv6 accepted, gzip supported, multiple ipsets allowed)
|
--ipset=<filename> ; ipset include filter (one ip/CIDR per line, ipv4 and ipv6 accepted, gzip supported, multiple ipsets allowed)
|
||||||
--ipset-ip=<ip_list> ; comma separated fixed subnet list
|
--ipset-ip=<ip_list> ; comma separated fixed subnet list
|
||||||
--ipset-exclude=<filename> ; ipset exclude filter (one ip/CIDR per line, ipv4 and ipv6 accepted, gzip supported, multiple ipsets allowed)
|
--ipset-exclude=<filename> ; ipset exclude filter (one ip/CIDR per line, ipv4 and ipv6 accepted, gzip supported, multiple ipsets allowed)
|
||||||
@ -216,7 +221,9 @@ There're attacks based on TCP sequence numbers. Methods can be combined in many
|
|||||||
|
|
||||||
Fakes are separate generated by nfqws packets carrying false information for DPI. They must either not reach the server or be rejected by it. Otherwise TCP connection or data stream would be broken. There're multiple ways to solve this task.
|
Fakes are separate generated by nfqws packets carrying false information for DPI. They must either not reach the server or be rejected by it. Otherwise TCP connection or data stream would be broken. There're multiple ways to solve this task.
|
||||||
|
|
||||||
* **md5sig** does not work on all servers
|
* **md5sig** does not work on all servers. It typically works only on Linux servers. MD5 tcp option requires additional space in TCP header
|
||||||
|
and can cause MTU overflow during fakedsplit/fakeddisorder on low positions when multisegment query (TLS kyber) is transmitted.
|
||||||
|
`nfqws` cannot redistribute data between original TCP segments. The error displayed is 'message too long'.
|
||||||
* **badsum** doesn't work if your device is behind NAT which does not pass invalid packets.
|
* **badsum** doesn't work if your device is behind NAT which does not pass invalid packets.
|
||||||
The most common Linux NAT router configuration does not pass them. Most home routers are Linux based.
|
The most common Linux NAT router configuration does not pass them. Most home routers are Linux based.
|
||||||
The default sysctl configuration `net.netfilter.nf_conntrack_checksum=1` causes contrack to verify tcp and udp checksums
|
The default sysctl configuration `net.netfilter.nf_conntrack_checksum=1` causes contrack to verify tcp and udp checksums
|
||||||
@ -261,6 +268,37 @@ Fakes are separate generated by nfqws packets carrying false information for DPI
|
|||||||
`--dpi-desync-fooling` takes multiple comma separated values.
|
`--dpi-desync-fooling` takes multiple comma separated values.
|
||||||
|
|
||||||
|
|
||||||
|
Multiple parameters `--dpi-desync-fake-???` are supported except for the `--dpi-desync-fake-syndata`.
|
||||||
|
Fakes are sent in the specified order. `--dpi-desync-repeats` resends each fake.
|
||||||
|
Resulting order would be : `fake1 fake1 fake1 fake2 fake2 fake2 fake3 fake3 fake3 .....`
|
||||||
|
|
||||||
|
|
||||||
|
### FAKE mods
|
||||||
|
|
||||||
|
**nfqws** has built-in TLS fake. It can be customized with `--dpi-desync-fake-tls` option.
|
||||||
|
Customized fake data can be anything - valid TLS Client Hello or arbitrary data.
|
||||||
|
It's possible to use TLS Client Hello with any fingerprint and any SNI.
|
||||||
|
|
||||||
|
**nfqws** can do some modifications of valid TLS Client Hello fakes in runtime with `--dpi-desync-fake-tls-mod` option.
|
||||||
|
|
||||||
|
* `none`. Do not do any mods.
|
||||||
|
* `rnd`. Randomize `random` and `session id` fields. Applied on every request.
|
||||||
|
* `rndsni`. Randomize SNI. If SNI >=7 symbols random SLD is applied with known TLD. Otherwise filled with random symbols. Applied only once at startup.
|
||||||
|
* `dupsid`. Copy `session ID` from original TLS Client Hello. Takes precedence over `rnd`. Applied on every request.
|
||||||
|
* `sni=<sni>`. Set specified SNI value. Changes TLS fake length, fixes lengths in TLS structure. Applied once at startup before `rndsni`.
|
||||||
|
* `padencap`. Padding extension is extended by original TLS Client Hello size (including multi packet variation with kyber). Padding extension is added to the end if not present, otherwise it must be the last extension. All lengths are increased. Fake size is not changed. Can be useful if DPI does not analyze sequence numbers properly. Applied on every request.
|
||||||
|
|
||||||
|
By default if custom fake is not defined `rnd,rndsni,dupsid` mods are applied. If defined - `none`.
|
||||||
|
This behaviour is compatible with previous versions with addition of `dupsid`.
|
||||||
|
|
||||||
|
If multiple TLS fakes are present each one takes the last mod.
|
||||||
|
If a mod is specified after fake it replaces previous mod.
|
||||||
|
This way it's possible to use different mods for every TLS fake.
|
||||||
|
|
||||||
|
If a mod is set to non-TLS fake it causes error. Use `--dpi-desync-fake-tls-mod=none'.
|
||||||
|
|
||||||
|
Example : `--dpi-desync-fake-tls=iana_org.bin --dpi-desync-fake-tls-mod=rndsni --dpi-desync-fake-tls=0xaabbccdd --dpi-desync-fake-tls-mod=none'
|
||||||
|
|
||||||
### TCP segmentation
|
### TCP segmentation
|
||||||
|
|
||||||
* `multisplit`. split request at specified in `--dpi-desync-split-pos` positions
|
* `multisplit`. split request at specified in `--dpi-desync-split-pos` positions
|
||||||
@ -443,7 +481,7 @@ This option can resist DPIs that track outgoing UDP packet sizes.
|
|||||||
Requires that application protocol does not depend on udp payload size.
|
Requires that application protocol does not depend on udp payload size.
|
||||||
|
|
||||||
QUIC initial packets are recognized. Decryption and hostname extraction is supported so `--hostlist` parameter will work.
|
QUIC initial packets are recognized. Decryption and hostname extraction is supported so `--hostlist` parameter will work.
|
||||||
Wireguard handshake initiation and DHT packets are also recognized.
|
Wireguard handshake initiation, DHT, STUN and [Discord Voice IP Discovery](https://discord.com/developers/docs/topics/voice-connections#ip-discovery) packets are also recognized.
|
||||||
For other protocols desync use `--dpi-desync-any-protocol`.
|
For other protocols desync use `--dpi-desync-any-protocol`.
|
||||||
|
|
||||||
Conntrack supports udp. `--dpi-desync-cutoff` will work. UDP conntrack timeout can be set in the 4th parameter of `--ctrack-timeouts`.
|
Conntrack supports udp. `--dpi-desync-cutoff` will work. UDP conntrack timeout can be set in the 4th parameter of `--ctrack-timeouts`.
|
||||||
@ -642,6 +680,7 @@ tpws is transparent proxy.
|
|||||||
--debug=0|1|2|syslog|@<filename> ; 1 and 2 means log to console and set debug level. for other targets use --debug-level.
|
--debug=0|1|2|syslog|@<filename> ; 1 and 2 means log to console and set debug level. for other targets use --debug-level.
|
||||||
--debug-level=0|1|2 ; specify debug level for syslog and @<filename>
|
--debug-level=0|1|2 ; specify debug level for syslog and @<filename>
|
||||||
--dry-run ; verify parameters and exit with code 0 if successful
|
--dry-run ; verify parameters and exit with code 0 if successful
|
||||||
|
--version ; print version and exit
|
||||||
--bind-addr=<v4_addr>|<v6_addr> ; for v6 link locals append %interface_name : fe80::1%br-lan
|
--bind-addr=<v4_addr>|<v6_addr> ; for v6 link locals append %interface_name : fe80::1%br-lan
|
||||||
--bind-iface4=<interface_name> ; bind to the first ipv4 addr of interface
|
--bind-iface4=<interface_name> ; bind to the first ipv4 addr of interface
|
||||||
--bind-iface6=<interface_name> ; bind to the first ipv6 addr of interface
|
--bind-iface6=<interface_name> ; bind to the first ipv6 addr of interface
|
||||||
@ -683,9 +722,9 @@ tpws is transparent proxy.
|
|||||||
--ipset-exclude=<filename> ; ipset exclude filter (one ip/CIDR per line, ipv4 and ipv6 accepted, gzip supported, multiple ipsets allowed)
|
--ipset-exclude=<filename> ; ipset exclude filter (one ip/CIDR per line, ipv4 and ipv6 accepted, gzip supported, multiple ipsets allowed)
|
||||||
--ipset-exclude-ip=<ip_list> ; comma separated fixed subnet list
|
--ipset-exclude-ip=<ip_list> ; comma separated fixed subnet list
|
||||||
|
|
||||||
--hostlist=<filename> ; only act on hosts in the list (one host per line, subdomains auto apply, gzip supported, multiple hostlists allowed)
|
--hostlist=<filename> ; only act on hosts in the list (one host per line, subdomains auto apply if not prefixed with '^', gzip supported, multiple hostlists allowed)
|
||||||
--hostlist-domains=<domain_list> ; comma separated fixed domain list
|
--hostlist-domains=<domain_list> ; comma separated fixed domain list
|
||||||
--hostlist-exclude=<filename> ; do not act on hosts in the list (one host per line, subdomains auto apply, gzip supported, multiple hostlists allowed)
|
--hostlist-exclude=<filename> ; do not act on hosts in the list (one host per line, subdomains auto apply if not prefixed with '^', gzip supported, multiple hostlists allowed)
|
||||||
--hostlist-exclude-domains=<domain_list> ; comma separated fixed domain list
|
--hostlist-exclude-domains=<domain_list> ; comma separated fixed domain list
|
||||||
--hostlist-auto=<filename> ; detect DPI blocks and build hostlist automatically
|
--hostlist-auto=<filename> ; detect DPI blocks and build hostlist automatically
|
||||||
--hostlist-auto-fail-threshold=<int> ; how many failed attempts cause hostname to be added to auto hostlist (default : 3)
|
--hostlist-auto-fail-threshold=<int> ; how many failed attempts cause hostname to be added to auto hostlist (default : 3)
|
||||||
@ -964,8 +1003,10 @@ If all include lists are empty it works like no include lists exist at all.
|
|||||||
If you need "all except" mode you dont have to delete zapret-hosts-users.txt. Just make it empty.
|
If you need "all except" mode you dont have to delete zapret-hosts-users.txt. Just make it empty.
|
||||||
|
|
||||||
Subdomains auto apply. For example, "ru" in the list affects "*.ru" .
|
Subdomains auto apply. For example, "ru" in the list affects "*.ru" .
|
||||||
|
`^` prefix symbol disables subdomain match.
|
||||||
|
|
||||||
**tpws** and **nfqws** automatically reload lists if their modification date is changed.
|
**tpws** and **nfqws** automatically reload lists if their modification time or file size is changed.
|
||||||
|
HUP signal forcibly reloads all lists.
|
||||||
|
|
||||||
When filtering by domain name, daemons should run without filtering by ipset.
|
When filtering by domain name, daemons should run without filtering by ipset.
|
||||||
When using large regulator lists estimate the amount of RAM on the router !
|
When using large regulator lists estimate the amount of RAM on the router !
|
||||||
@ -1410,12 +1451,8 @@ If this is the case then run another script in background and add some delay the
|
|||||||
|
|
||||||
Are welcome here :
|
Are welcome here :
|
||||||
|
|
||||||
<img src=https://cdn-icons-png.flaticon.com/16/14446/14446252.png alt="USDT" style="vertical-align: middle;"/> USDT
|
USDT `0x3d52Ce15B7Be734c53fc9526ECbAB8267b63d66E`
|
||||||
```
|
|
||||||
0x3d52Ce15B7Be734c53fc9526ECbAB8267b63d66E
|
|
||||||
```
|
|
||||||
|
|
||||||
<img src=https://cdn-icons-png.flaticon.com/16/5968/5968260.png alt="USDT" style="vertical-align: middle;"/> BTC
|
BTC `bc1qhqew3mrvp47uk2vevt5sctp7p2x9m7m5kkchve`
|
||||||
```
|
|
||||||
bc1qhqew3mrvp47uk2vevt5sctp7p2x9m7m5kkchve
|
ETH `0x3d52Ce15B7Be734c53fc9526ECbAB8267b63d66E`
|
||||||
```
|
|
||||||
|
426
docs/readme.md
426
docs/readme.md
@ -1,4 +1,4 @@
|
|||||||
# zapret v69.8
|
# zapret v70.6
|
||||||
|
|
||||||
# ВНИМАНИЕ, остерегайтесь мошенников
|
# ВНИМАНИЕ, остерегайтесь мошенников
|
||||||
|
|
||||||
@ -21,6 +21,7 @@ zapret является свободным и open source.
|
|||||||
- [nfqws](#nfqws)
|
- [nfqws](#nfqws)
|
||||||
- [АТАКА ДЕСИНХРОНИЗАЦИИ DPI](#атака-десинхронизации-dpi)
|
- [АТАКА ДЕСИНХРОНИЗАЦИИ DPI](#атака-десинхронизации-dpi)
|
||||||
- [ФЕЙКИ](#фейки)
|
- [ФЕЙКИ](#фейки)
|
||||||
|
- [МОДИФИКАЦИЯ ФЕЙКОВ](#модификация-фейков)
|
||||||
- [TCP СЕГМЕНТАЦИЯ](#tcp-сегментация)
|
- [TCP СЕГМЕНТАЦИЯ](#tcp-сегментация)
|
||||||
- [ПЕРЕКРЫТИЕ SEQUENCE NUMBERS](#перекрытие-sequence-numbers)
|
- [ПЕРЕКРЫТИЕ SEQUENCE NUMBERS](#перекрытие-sequence-numbers)
|
||||||
- [СПЕЦИФИЧЕСКИЕ РЕЖИМЫ IPV6](#специфические-режимы-ipv6)
|
- [СПЕЦИФИЧЕСКИЕ РЕЖИМЫ IPV6](#специфические-режимы-ipv6)
|
||||||
@ -46,9 +47,9 @@ zapret является свободным и open source.
|
|||||||
- [СЛУЖЕБНЫЕ ПАРАМЕТРЫ](#служебные-параметры)
|
- [СЛУЖЕБНЫЕ ПАРАМЕТРЫ](#служебные-параметры)
|
||||||
- [IPTABLES ДЛЯ TPWS](#iptables-для-tpws)
|
- [IPTABLES ДЛЯ TPWS](#iptables-для-tpws)
|
||||||
- [NFTABLES ДЛЯ TPWS](#nftables-для-tpws)
|
- [NFTABLES ДЛЯ TPWS](#nftables-для-tpws)
|
||||||
- [Способы получения списка заблокированных IP](#способы-получения-списка-заблокированных-ip)
|
|
||||||
- [ip2net](#ip2net)
|
- [ip2net](#ip2net)
|
||||||
- [mdig](#mdig)
|
- [mdig](#mdig)
|
||||||
|
- [Способы получения списка заблокированных IP](#способы-получения-списка-заблокированных-ip)
|
||||||
- [Фильтрация по именам доменов](#фильтрация-по-именам-доменов)
|
- [Фильтрация по именам доменов](#фильтрация-по-именам-доменов)
|
||||||
- [Режим фильтрации autohostlist](#режим-фильтрации-autohostlist)
|
- [Режим фильтрации autohostlist](#режим-фильтрации-autohostlist)
|
||||||
- [Проверка провайдера](#проверка-провайдера)
|
- [Проверка провайдера](#проверка-провайдера)
|
||||||
@ -56,6 +57,7 @@ zapret является свободным и open source.
|
|||||||
- [Прикручивание к системе управления фаерволом или своей системе запуска](#прикручивание-к-системе-управления-фаерволом-или-своей-системе-запуска)
|
- [Прикручивание к системе управления фаерволом или своей системе запуска](#прикручивание-к-системе-управления-фаерволом-или-своей-системе-запуска)
|
||||||
- [Вариант custom](#вариант-custom)
|
- [Вариант custom](#вариант-custom)
|
||||||
- [Простая установка](#простая-установка)
|
- [Простая установка](#простая-установка)
|
||||||
|
- [Установка под systemd](#установка-под-systemd)
|
||||||
- [Простая установка на openwrt](#простая-установка-на-openwrt)
|
- [Простая установка на openwrt](#простая-установка-на-openwrt)
|
||||||
- [Установка на openwrt в режиме острой нехватки места на диске](#установка-на-openwrt-в-режиме-острой-нехватки-места-на-диске)
|
- [Установка на openwrt в режиме острой нехватки места на диске](#установка-на-openwrt-в-режиме-острой-нехватки-места-на-диске)
|
||||||
- [Android](#android)
|
- [Android](#android)
|
||||||
@ -71,14 +73,14 @@ zapret является свободным и open source.
|
|||||||
## Зачем это нужно
|
## Зачем это нужно
|
||||||
|
|
||||||
Автономное средство противодействия DPI, которое не требует подключения каких-либо сторонних серверов. Может помочь
|
Автономное средство противодействия DPI, которое не требует подключения каких-либо сторонних серверов. Может помочь
|
||||||
обойти блокировки или замедление сайтов http(s), сигнатурный анализ tcp и udp протоколов, например с целью блокировки
|
обойти блокировки или замедление сайтов HTTP(S), сигнатурный анализ TCP и UDP протоколов, например, с целью блокировки
|
||||||
VPN.
|
VPN.
|
||||||
|
|
||||||
Проект нацелен прежде всего на маломощные embedded устройства - роутеры, работающие под openwrt. Поддерживаются
|
Проект нацелен прежде всего на маломощные embedded устройства - роутеры, работающие под OpenWrt. Поддерживаются
|
||||||
традиционные Linux системы, FreeBSD, OpenBSD, частично MacOS. В некоторых случаях возможна самостоятельная прикрутка
|
традиционные Linux-системы, FreeBSD, OpenBSD, частично macOS. В некоторых случаях возможна самостоятельная прикрутка
|
||||||
решения к различным прошивкам.
|
решения к различным прошивкам.
|
||||||
|
|
||||||
Большая часть функционала работает на windows.
|
Большая часть функционала работает на Windows.
|
||||||
|
|
||||||
## Быстрый старт
|
## Быстрый старт
|
||||||
|
|
||||||
@ -89,25 +91,25 @@ VPN.
|
|||||||
|
|
||||||
В самом простейшем случае вы имеете дело с пассивным DPI. Пассивный DPI может читать трафик из потока, может инжектить
|
В самом простейшем случае вы имеете дело с пассивным DPI. Пассивный DPI может читать трафик из потока, может инжектить
|
||||||
свои пакеты, но не может блокировать проходящие пакеты. Если запрос "плохой", пассивный DPI инжектит пакет RST,
|
свои пакеты, но не может блокировать проходящие пакеты. Если запрос "плохой", пассивный DPI инжектит пакет RST,
|
||||||
опционально дополняя его пакетом http redirect. Если фейк пакет инжектится только для клиента, в этом случае можно
|
опционально дополняя его пакетом HTTP redirect. Если фейк пакет инжектится только для клиента, в этом случае можно
|
||||||
обойтись командами iptables для дропа RST и/или редиректа на заглушку по определенным условиям, которые нужно подбирать
|
обойтись командами iptables для дропа RST и/или редиректа на заглушку по определённым условиям, которые нужно подбирать
|
||||||
для каждого провайдера индивидуально. Так мы обходим последствия срабатывания триггера запрета. Если пассивный DPI
|
для каждого провайдера индивидуально. Так мы обходим последствия срабатывания триггера запрета. Если пассивный DPI
|
||||||
направляет пакет RST в том числе и серверу, то вы ничего с этим не сможете сделать. Ваша задача - не допустить
|
направляет пакет RST в том числе и серверу, то вы ничего с этим не сможете сделать. Ваша задача — не допустить
|
||||||
срабатывания триггера запрета. Одними iptables уже не обойдетесь. Этот проект нацелен именно на предотвращение
|
срабатывания триггера запрета. Одними iptables уже не обойтись. Этот проект нацелен именно на предотвращение
|
||||||
срабатывания запрета, а не ликвидацию его последствий.
|
срабатывания запрета, а не ликвидацию его последствий.
|
||||||
|
|
||||||
Активный DPI ставится в разрез провода и может дропать пакеты по любым критериям, в том числе распознавать TCP потоки и
|
Активный DPI ставится в разрез провода и может дропать пакеты по любым критериям, в том числе распознавать TCP-потоки и
|
||||||
блокировать любые пакеты, принадлежащие потоку.
|
блокировать любые пакеты, принадлежащие потоку.
|
||||||
|
|
||||||
Как не допустить срабатывания триггера запрета ? Послать то, на что DPI не рассчитывает и что ломает ему алгоритм
|
Как не допустить срабатывания триггера запрета? Послать то, на что DPI не рассчитывает и что ломает ему алгоритм
|
||||||
распознавания запросов и их блокировки.
|
распознавания запросов и их блокировки.
|
||||||
|
|
||||||
Некоторые DPI не могут распознать http запрос, если он разделен на TCP сегменты. Например, запрос
|
Некоторые DPI не могут распознать HTTP-запрос, если он разделен на TCP-сегменты. Например, запрос
|
||||||
вида `GET / HTTP/1.1\r\nHost: kinozal.tv......`
|
вида `GET / HTTP/1.1\r\nHost: kinozal.tv......`
|
||||||
мы посылаем 2 частями : сначала идет `GET`, затем `/ HTTP/1.1\r\nHost: kinozal.tv.....`. Другие DPI спотыкаются, когда
|
мы посылаем двумя частями: сначала идет `GET`, затем `/ HTTP/1.1\r\nHost: kinozal.tv.....`. Другие DPI спотыкаются, когда
|
||||||
заголовок `Host:` пишется в другом регистре : например,`host:`. Кое-где работает добавление дополнительного пробела
|
заголовок `Host:` пишется в другом регистре: например, `host:`. Кое-где работает добавление дополнительного пробела
|
||||||
после метода : `GET /` => `GET /`
|
после метода: `GET /` → `GET /`
|
||||||
или добавление точки в конце имени хоста : `Host: kinozal.tv.`
|
или добавление точки в конце имени хоста: `Host: kinozal.tv.`
|
||||||
|
|
||||||
Существует и более продвинутая магия, направленная на преодоление DPI на пакетном уровне.
|
Существует и более продвинутая магия, направленная на преодоление DPI на пакетном уровне.
|
||||||
|
|
||||||
@ -144,14 +146,9 @@ DPI. Все больше становится внереестровых бло
|
|||||||
* Если подменяется DNS. С этой проблемой легко справиться.
|
* Если подменяется DNS. С этой проблемой легко справиться.
|
||||||
* Если блокировка осуществляется по IP.
|
* Если блокировка осуществляется по IP.
|
||||||
* Если соединение проходит через фильтр, способный реконструировать TCP соединение, и который следует всем стандартам.
|
* Если соединение проходит через фильтр, способный реконструировать TCP соединение, и который следует всем стандартам.
|
||||||
Например, нас заворачивают на squid. Соединение идет через полноценный стек tcpip операционной системы, фрагментация
|
Например, нас заворачивают на squid. Соединение идет через полноценный стек tcpip операционной системы.
|
||||||
отпадает сразу как средство обхода. Squid правильный, он все найдет как надо, обманывать его бесполезно. НО.
|
Проект нацелен на обман DPI, который всилу ограниченности ресурсов и большого трафика вынужден интерпретировать его лишь ограниченно.
|
||||||
Заворачивать на squid могут позволить себе лишь небольшие провайдеры, поскольку это очень ресурсоемко. Большие
|
Обмануть полноценный стек ОС и полноценные серверные приложения не получится.
|
||||||
компании обычно используют DPI, который рассчитан на гораздо большую пропускную способность. Может применяться
|
|
||||||
комбинированный подход, когда на DPI заворачивают только IP из "плохого" списка, и дальше уже DPI решает пропускать
|
|
||||||
или нет. Так можно снизить нагрузку на DPI в десятки, если не сотни раз, а следовательно не покупать очень дорогие
|
|
||||||
решения, обойдясь чем-то существенно более дешевым. Мелкие провайдеры могут покупать услугу фильтрации у вышестоящих,
|
|
||||||
чтобы самим не морочиться, и они уже будут применять DPI.
|
|
||||||
|
|
||||||
## nfqws
|
## nfqws
|
||||||
|
|
||||||
@ -163,6 +160,7 @@ dvtws, собираемый из тех же исходников (см. [док
|
|||||||
|
|
||||||
--debug=0|1 ; 1=выводить отладочные сообщения
|
--debug=0|1 ; 1=выводить отладочные сообщения
|
||||||
--dry-run ; проверить опции командной строки и выйти. код 0 - успешная проверка.
|
--dry-run ; проверить опции командной строки и выйти. код 0 - успешная проверка.
|
||||||
|
--version ; вывести версию и выйти
|
||||||
--comment ; любой текст (игнорируется)
|
--comment ; любой текст (игнорируется)
|
||||||
--daemon ; демонизировать прогу
|
--daemon ; демонизировать прогу
|
||||||
--pidfile=<file> ; сохранить PID в файл
|
--pidfile=<file> ; сохранить PID в файл
|
||||||
@ -198,16 +196,19 @@ dvtws, собираемый из тех же исходников (см. [док
|
|||||||
--dpi-desync-any-protocol=0|1 ; 0(default)=работать только по http request и tls clienthello 1=по всем непустым пакетам данных
|
--dpi-desync-any-protocol=0|1 ; 0(default)=работать только по http request и tls clienthello 1=по всем непустым пакетам данных
|
||||||
--dpi-desync-fake-http=<filename>|0xHEX ; файл, содержащий фейковый http запрос для dpi-desync=fake, на замену стандартному www.iana.org
|
--dpi-desync-fake-http=<filename>|0xHEX ; файл, содержащий фейковый http запрос для dpi-desync=fake, на замену стандартному www.iana.org
|
||||||
--dpi-desync-fake-tls=<filename>|0xHEX ; файл, содержащий фейковый tls clienthello для dpi-desync=fake, на замену стандартному
|
--dpi-desync-fake-tls=<filename>|0xHEX ; файл, содержащий фейковый tls clienthello для dpi-desync=fake, на замену стандартному
|
||||||
|
--dpi-desync-fake-tls-mod=mod[,mod] ; список через запятую режимов runtime модификации фейков : none,rnd,rndsni,sni=<sni>,dupsid,padencap
|
||||||
--dpi-desync-fake-unknown=<filename>|0xHEX ; файл, содержащий фейковый пейлоад неизвестного протокола для dpi-desync=fake, на замену стандартным нулям 256 байт
|
--dpi-desync-fake-unknown=<filename>|0xHEX ; файл, содержащий фейковый пейлоад неизвестного протокола для dpi-desync=fake, на замену стандартным нулям 256 байт
|
||||||
--dpi-desync-fake-syndata=<filename>|0xHEX ; файл, содержащий фейковый пейлоад пакета SYN для режима десинхронизации syndata
|
--dpi-desync-fake-syndata=<filename>|0xHEX ; файл, содержащий фейковый пейлоад пакета SYN для режима десинхронизации syndata
|
||||||
--dpi-desync-fake-quic=<filename>|0xHEX ; файл, содержащий фейковый QUIC Initial
|
--dpi-desync-fake-quic=<filename>|0xHEX ; файл, содержащий фейковый QUIC Initial
|
||||||
--dpi-desync-fake-dht=<filename>|0xHEX ; файл, содержащий фейковый пейлоад DHT протокола для dpi-desync=fake, на замену стандартным нулям 64 байт
|
--dpi-desync-fake-dht=<filename>|0xHEX ; файл, содержащий фейковый пейлоад DHT протокола для dpi-desync=fake, на замену стандартным нулям 64 байт
|
||||||
|
--dpi-desync-fake-discord=<filename>|0xHEX ; файл, содержащий фейковый пейлоад Discord протокола нахождения IP адреса для голосовых чатов для dpi-desync=fake, на замену стандартным нулям 64 байт
|
||||||
|
--dpi-desync-fake-stun=<filename>|0xHEX ; файл, содержащий фейковый пейлоад STUN протокола для dpi-desync=fake, на замену стандартным нулям 64 байт
|
||||||
--dpi-desync-fake-unknown-udp=<filename>|0xHEX ; файл, содержащий фейковый пейлоад неизвестного udp протокола для dpi-desync=fake, на замену стандартным нулям 64 байт
|
--dpi-desync-fake-unknown-udp=<filename>|0xHEX ; файл, содержащий фейковый пейлоад неизвестного udp протокола для dpi-desync=fake, на замену стандартным нулям 64 байт
|
||||||
--dpi-desync-udplen-increment=<int> ; насколько увеличивать длину udp пейлоада в режиме udplen
|
--dpi-desync-udplen-increment=<int> ; насколько увеличивать длину udp пейлоада в режиме udplen
|
||||||
--dpi-desync-udplen-pattern=<filename>|0xHEX ; чем добивать udp пакет в режиме udplen. по умолчанию - нули
|
--dpi-desync-udplen-pattern=<filename>|0xHEX ; чем добивать udp пакет в режиме udplen. по умолчанию - нули
|
||||||
--dpi-desync-start=[n|d|s]N ; применять dpi desync только в исходящих пакетах (n), пакетах данных (d), относительных sequence (s) по номеру больше или равно N
|
--dpi-desync-start=[n|d|s]N ; применять dpi desync только в исходящих пакетах (n), пакетах данных (d), относительных sequence (s) по номеру больше или равно N
|
||||||
--dpi-desync-cutoff=[n|d|s]N ; применять dpi desync только в исходящих пакетах (n), пакетах данных (d), относительных sequence (s) по номеру меньше N
|
--dpi-desync-cutoff=[n|d|s]N ; применять dpi desync только в исходящих пакетах (n), пакетах данных (d), относительных sequence (s) по номеру меньше N
|
||||||
--hostlist=<filename> ; действовать только над доменами, входящими в список из filename. поддомены автоматически учитываются.
|
--hostlist=<filename> ; действовать только над доменами, входящими в список из filename. поддомены автоматически учитываются, если хост не начинается с '^'.
|
||||||
; в файле должен быть хост на каждой строке.
|
; в файле должен быть хост на каждой строке.
|
||||||
; список читается при старте и хранится в памяти в виде иерархической структуры для быстрого поиска.
|
; список читается при старте и хранится в памяти в виде иерархической структуры для быстрого поиска.
|
||||||
; при изменении времени модификации файла он перечитывается автоматически по необходимости
|
; при изменении времени модификации файла он перечитывается автоматически по необходимости
|
||||||
@ -227,7 +228,7 @@ dvtws, собираемый из тех же исходников (см. [док
|
|||||||
--filter-l3=ipv4|ipv6 ; фильтр версии ip для текущей стратегии
|
--filter-l3=ipv4|ipv6 ; фильтр версии ip для текущей стратегии
|
||||||
--filter-tcp=[~]port1[-port2]|* ; фильтр портов tcp для текущей стратегии. ~ означает инверсию. установка фильтра tcp и неустановка фильтра udp запрещает udp. поддерживается список через запятую.
|
--filter-tcp=[~]port1[-port2]|* ; фильтр портов tcp для текущей стратегии. ~ означает инверсию. установка фильтра tcp и неустановка фильтра udp запрещает udp. поддерживается список через запятую.
|
||||||
--filter-udp=[~]port1[-port2]|* ; фильтр портов udp для текущей стратегии. ~ означает инверсию. установка фильтра udp и неустановка фильтра tcp запрещает tcp. поддерживается список через запятую.
|
--filter-udp=[~]port1[-port2]|* ; фильтр портов udp для текущей стратегии. ~ означает инверсию. установка фильтра udp и неустановка фильтра tcp запрещает tcp. поддерживается список через запятую.
|
||||||
--filter-l7=[http|tls|quic|wireguard|dht|unknown] ; фильтр протокола L6-L7. поддерживается несколько значений через запятую.
|
--filter-l7=<proto> ; фильтр протокола L6-L7. поддерживается несколько значений через запятую. proto : http tls quic wireguard dht discord stun unknown
|
||||||
--ipset=<filename> ; включающий ip list. на каждой строчке ip или cidr ipv4 или ipv6. поддерживается множество листов и gzip. перечитка автоматическая.
|
--ipset=<filename> ; включающий ip list. на каждой строчке ip или cidr ipv4 или ipv6. поддерживается множество листов и gzip. перечитка автоматическая.
|
||||||
--ipset-ip=<ip_list> ; фиксированный список подсетей через запятую. можно использовать # в начале для комментирования отдельных подсетей.
|
--ipset-ip=<ip_list> ; фиксированный список подсетей через запятую. можно использовать # в начале для комментирования отдельных подсетей.
|
||||||
--ipset-exclude=<filename> ; исключающий ip list. на каждой строчке ip или cidr ipv4 или ipv6. поддерживается множество листов и gzip. перечитка автоматическая.
|
--ipset-exclude=<filename> ; исключающий ip list. на каждой строчке ip или cidr ipv4 или ipv6. поддерживается множество листов и gzip. перечитка автоматическая.
|
||||||
@ -262,13 +263,17 @@ dvtws, собираемый из тех же исходников (см. [док
|
|||||||
Есть ряд методов для решения этой задачи.
|
Есть ряд методов для решения этой задачи.
|
||||||
|
|
||||||
* `md5sig` добавляет TCP опцию **MD5 signature**. Работает не на всех серверах. Пакеты с md5 обычно отбрасывают только linux.
|
* `md5sig` добавляет TCP опцию **MD5 signature**. Работает не на всех серверах. Пакеты с md5 обычно отбрасывают только linux.
|
||||||
|
Требуется значительное увеличение длины tcp пакета, чтобы вместить tcp option. При обработке многосегментных запросов (TLS Kyber)
|
||||||
|
первый пакет идет полный под MTU. При fakedsplit/fakeddisorder на небольших позициях отдельные tcp сегменты достаточно велики, чтобы внедрение
|
||||||
|
md5 tcp option вызвало переполнение MTU и ошибку отправки "message too long". `nfqws` не умеет перераспределять данные между tcp сегментами,
|
||||||
|
поэтому надо или отказываться от kyber, или увеличивать сплит-позицию, или отказываться от fakedsplit/fakeddisorder.
|
||||||
* `badsum` портит контрольную сумму TCP. Не сработает, если ваше устройство за NAT, который не пропускает пакеты с инвалидной суммой. Наиболее
|
* `badsum` портит контрольную сумму TCP. Не сработает, если ваше устройство за NAT, который не пропускает пакеты с инвалидной суммой. Наиболее
|
||||||
распространенная настройка NAT роутера в Linux их не пропускает. На Linux построено большинство домашних роутеров.
|
распространенная настройка NAT роутера в Linux их не пропускает. На Linux построено большинство домашних роутеров.
|
||||||
Непропускание обеспечивается так : настройка ядра sysctl по умолчанию
|
Непропускание обеспечивается так : настройка ядра sysctl по умолчанию
|
||||||
`net.netfilter.nf_conntrack_checksum=1` заставляет conntrack проверять tcp и udp чексуммы входящих пакетов и
|
`net.netfilter.nf_conntrack_checksum=1` заставляет conntrack проверять tcp и udp чексуммы входящих пакетов и
|
||||||
выставлять state INVALID для пакетов с инвалидной суммой. Обычно в правилах iptables вставляется правило для дропа
|
выставлять state INVALID для пакетов с инвалидной суммой. Обычно в правилах iptables вставляется правило для дропа
|
||||||
пакетов с состоянием INVALID в цепочке FORWARD. Совместное сочетание этих факторов приводит к непрохождению badsum
|
пакетов с состоянием INVALID в цепочке FORWARD. Совместное сочетание этих факторов приводит к непрохождению badsum
|
||||||
через такой роутер. В openwrt из коробки `net.netfilter.nf_conntrack_checksum=0`, в других роутерах часто нет, и не
|
через такой роутер. В OpenWrt из коробки `net.netfilter.nf_conntrack_checksum=0`, в других роутерах часто нет, и не
|
||||||
всегда это можно изменить. Чтобы nfqws мог работать через роутер, нужно на нем выставить указанное значение sysctl в 0.
|
всегда это можно изменить. Чтобы nfqws мог работать через роутер, нужно на нем выставить указанное значение sysctl в 0.
|
||||||
nfqws на самом роутере будет работать и без этой настройки, потому что чексумма локально созданных пакетов не
|
nfqws на самом роутере будет работать и без этой настройки, потому что чексумма локально созданных пакетов не
|
||||||
проверяется никогда. Если роутер за другим NAT, например провайдерским, и он не пропускает invalid packets вы ничего
|
проверяется никогда. Если роутер за другим NAT, например провайдерским, и он не пропускает invalid packets вы ничего
|
||||||
@ -282,7 +287,7 @@ dvtws, собираемый из тех же исходников (см. [док
|
|||||||
Такие пакеты будут наверняка отброшены принимающим узлом, но так же и DPI, если он ориентируется на sequence
|
Такие пакеты будут наверняка отброшены принимающим узлом, но так же и DPI, если он ориентируется на sequence
|
||||||
numbers. По умолчанию смещение seq выбирается -10000. Практика показала, что некоторые DPI не пропускают seq вне
|
numbers. По умолчанию смещение seq выбирается -10000. Практика показала, что некоторые DPI не пропускают seq вне
|
||||||
определенного окна. Однако, такое небольшое смещение может вызвать проблемы при существенной потоковой передаче и
|
определенного окна. Однако, такое небольшое смещение может вызвать проблемы при существенной потоковой передаче и
|
||||||
потере пакетов. Если вы используете `--dpi-desync-any-protocol`, может понадобится установить badseq increment
|
потере пакетов. Если вы используете `--dpi-desync-any-protocol`, может понадобиться установить badseq increment
|
||||||
0x80000000. Это обеспечит надежную гарантию, что поддельный пакет не вклинится в tcp window на сервере. Так же было
|
0x80000000. Это обеспечит надежную гарантию, что поддельный пакет не вклинится в tcp window на сервере. Так же было
|
||||||
замечено, что badseq ломает логику некоторых DPI при анализе http, вызывая зависание соединения. Причем на тех же DPI
|
замечено, что badseq ломает логику некоторых DPI при анализе http, вызывая зависание соединения. Причем на тех же DPI
|
||||||
TLS с badseq работает нормально.
|
TLS с badseq работает нормально.
|
||||||
@ -297,7 +302,7 @@ dvtws, собираемый из тех же исходников (см. [док
|
|||||||
* `hopbyhop` относится только к ipv6. Добавляется ipv6 extenstion header `hop-by-hop options`. В варианте `hopbyhop2`
|
* `hopbyhop` относится только к ipv6. Добавляется ipv6 extenstion header `hop-by-hop options`. В варианте `hopbyhop2`
|
||||||
добавляются 2 хедера, что является нарушением стандарта и гарантированно отбрасывается стеком протоколов во всех ОС.
|
добавляются 2 хедера, что является нарушением стандарта и гарантированно отбрасывается стеком протоколов во всех ОС.
|
||||||
Один хедер hop-by-hop принимается всеми ОС, однако на некоторых каналах/провайдерах такие пакеты могут фильтроваться и
|
Один хедер hop-by-hop принимается всеми ОС, однако на некоторых каналах/провайдерах такие пакеты могут фильтроваться и
|
||||||
не доходить. Расчет идет на то, что DPI проанализирует пакет с hop-by-hop, но он либо не дойдет до адресата всилу
|
не доходить. Расчет идет на то, что DPI проанализирует пакет с hop-by-hop, но он либо не дойдет до адресата в силу
|
||||||
фильтров провайдера, либо будет отброшен сервером, потому что хедера два.
|
фильтров провайдера, либо будет отброшен сервером, потому что хедера два.
|
||||||
* `datanoack` высылает фейки со снятым tcp флагом ACK. Сервера такое не принимают, а DPI может принять. Эта техника
|
* `datanoack` высылает фейки со снятым tcp флагом ACK. Сервера такое не принимают, а DPI может принять. Эта техника
|
||||||
может ломать NAT и не всегда работает с iptables, если используется masquerade, даже с локальной системы (почти всегда
|
может ломать NAT и не всегда работает с iptables, если используется masquerade, даже с локальной системы (почти всегда
|
||||||
@ -317,6 +322,40 @@ dvtws, собираемый из тех же исходников (см. [док
|
|||||||
|
|
||||||
Режимы дурения могут сочетаться в любых комбинациях. `--dpi-desync-fooling` берет множество значений через запятую.
|
Режимы дурения могут сочетаться в любых комбинациях. `--dpi-desync-fooling` берет множество значений через запятую.
|
||||||
|
|
||||||
|
Возможно задание множества фейков через повторение парамеров `--dpi-desync-fake-???`, кроме `--dpi-desync-fake-syndata`.
|
||||||
|
Фейки будут отосланы в указанном порядке. `--dpi-desync-repeats` повторяет каждый отосланный фейк.
|
||||||
|
Итоговый порядок будет такой : `fake1 fake1 fake1 fake2 fake2 fake2 fake3 fake3 fake3 .....`
|
||||||
|
|
||||||
|
### МОДИФИКАЦИЯ ФЕЙКОВ
|
||||||
|
|
||||||
|
В nfqws зашит базовый вариант фейка для TLS. Его можно переопределить опцией `--dpi-desync-fake-tls`.
|
||||||
|
Переопределение фейков дает возможность использовать любые данные в качестве фейка для TLS.
|
||||||
|
Можно использовать фейковый Client Hello с любым фингерпринтом и с любым SNI.
|
||||||
|
|
||||||
|
Некоторые модификации можно делать в процессе выполнения с помощью `--dpi-desync-fake-tls-mod`.
|
||||||
|
Часть из них работает при обработке каждого TLS Client Hello и может подстраиваться под отправляемые данные.
|
||||||
|
Модификации требуют наличия полного валидного TLS Client Hello в качестве фейка, они не работают с произвольными данными.
|
||||||
|
|
||||||
|
* `none`. Не применять никакие модификации.
|
||||||
|
* `rnd`. Рандомизировать поля `random` и `session id`. Выполняется на каждый запрос.
|
||||||
|
* `dupsid`. Копировать `session ID` из передаваемого TLS Client Hello. Имеет приоритет над `rnd`. Выполняется на каждый запрос.
|
||||||
|
* `rndsni`. Рандомизировать SNI. Если SNI >=7 символов, применяется случайный домен 2 уровня с известным TLD, иначе заполняется случайными символами без точки. Выполняется один раз при старте.
|
||||||
|
* `sni=<sni>`. Заменить sni на указанное значение. Макс длина SNI - 63 байта. Общая длина TLS фейка и длины в структуре TLS Client Hello меняются. Выполняется один раз при старте. Если сочетается с `rndsni`, выполняется до него.
|
||||||
|
* `padencap`. Расширяется padding extension на размер передаваемого TLS Client Hello (включая многопакетный вариант с kyber). Если padding отсутствует, он добавляется в конец. Если присутствует - требуется, чтобы padding шел последним extension. Правятся все длины, чтобы создать видимость включения передаваемого TLS Client Hello в padding extension. Размер фейка не изменяется. Расчет идет на DPI, который не анализирует sequence numbers должным образом. Выполняется на каждый запрос.
|
||||||
|
|
||||||
|
По умолчанию если не задан собственный фейк для TLS используются модификации `rnd,rndsni,dupsid`. Если фейк задан, используется `none`.
|
||||||
|
Это соответствует поведению программы более старых версий с добавлением функции `dupsid`.
|
||||||
|
|
||||||
|
Если задан режим модификации и имеется множество TLS фейков, к каждому из них применяется последний режим модификации.
|
||||||
|
Если режим модификации задан после фейка, то он замещает предыдущий режим.
|
||||||
|
Таким образом можно использовать разные режимы модификации для разных фейков.
|
||||||
|
При невозможности модифицировать фейк на этапе запуска программа завершается с ошибкой.
|
||||||
|
|
||||||
|
Если сначала идет TLS фейк, для него задан режим однократной модификации, затем идет не TLS фейк, то будет ошибка.
|
||||||
|
Нужно использовать `--dpi-desync-fake-tls-mod=none'.
|
||||||
|
|
||||||
|
Пример : `--dpi-desync-fake-tls=iana_org.bin --dpi-desync-fake-tls-mod=rndsni --dpi-desync-fake-tls=0xaabbccdd --dpi-desync-fake-tls-mod=none'
|
||||||
|
|
||||||
### TCP СЕГМЕНТАЦИЯ
|
### TCP СЕГМЕНТАЦИЯ
|
||||||
|
|
||||||
* `multisplit`. нарезаем запрос на указанных в `--dpi-desync-split-pos` позициях.
|
* `multisplit`. нарезаем запрос на указанных в `--dpi-desync-split-pos` позициях.
|
||||||
@ -329,6 +368,9 @@ dvtws, собираемый из тех же исходников (см. [док
|
|||||||
Размеры фейков соответствуют длинам отсылаемых частей.
|
Размеры фейков соответствуют длинам отсылаемых частей.
|
||||||
Цель этих режимов - максимально усложнить выявление оригинальных данных среди фейков.
|
Цель этих режимов - максимально усложнить выявление оригинальных данных среди фейков.
|
||||||
|
|
||||||
|
Использование `fakedsplit` или `fakeddisorder` на TLS kyber с md5sig fooling может привести к ошибкам "message too long", если позиция сплита мала,
|
||||||
|
поскольку будет превышение MTU из-за md5 tcp option.
|
||||||
|
|
||||||
Для определения позиций нарезки используются маркеры.
|
Для определения позиций нарезки используются маркеры.
|
||||||
|
|
||||||
* **Абсолютный положительный маркер** - числовое смещение внутри пакета или группы пакетов от начала.
|
* **Абсолютный положительный маркер** - числовое смещение внутри пакета или группы пакетов от начала.
|
||||||
@ -513,8 +555,8 @@ window size итоговый размер окна стал максимальн
|
|||||||
### РЕАССЕМБЛИНГ
|
### РЕАССЕМБЛИНГ
|
||||||
|
|
||||||
nfqws поддерживает реассемблинг некоторых видов запросов.
|
nfqws поддерживает реассемблинг некоторых видов запросов.
|
||||||
На текущий момент это TLS и QUIC ClientHello. Они бывает длинными, если в chrome включить пост-квантовую
|
На текущий момент это TLS и QUIC ClientHello. Они бывают длинными, если в chrome включить пост-квантовую
|
||||||
криптографию tls-kyber, и занимают как правило 2 или 3 пакета. kyber включен по умолчанию, начиная с chromium 124.
|
криптографию tls-kyber, и занимают, как правило, 2 или 3 пакета. kyber включен по умолчанию, начиная с chromium 124.
|
||||||
chrome рандомизирует фингерпринт TLS. SNI может оказаться как в начале, так и в конце, то есть
|
chrome рандомизирует фингерпринт TLS. SNI может оказаться как в начале, так и в конце, то есть
|
||||||
попасть в любой пакет. stateful DPI обычно реассемблирует запрос целиком, и только потом
|
попасть в любой пакет. stateful DPI обычно реассемблирует запрос целиком, и только потом
|
||||||
принимает решение о блокировке.
|
принимает решение о блокировке.
|
||||||
@ -543,7 +585,8 @@ chrome рандомизирует фингерпринт TLS. SNI может о
|
|||||||
На текущий момент работает только с DHT.
|
На текущий момент работает только с DHT.
|
||||||
Поддерживается определение пакетов QUIC Initial с расшифровкой содержимого и имени хоста, то есть параметр
|
Поддерживается определение пакетов QUIC Initial с расшифровкой содержимого и имени хоста, то есть параметр
|
||||||
`--hostlist` будет работать.
|
`--hostlist` будет работать.
|
||||||
Определяются пакеты wireguard handshake initiation и DHT (начинается с 'd1', кончается 'e').
|
Определяются пакеты wireguard handshake initiation, DHT (начинается с 'd1', кончается 'e'), STUN и
|
||||||
|
[Discord Voice IP Discovery](https://discord.com/developers/docs/topics/voice-connections#ip-discovery).
|
||||||
Для десинхронизации других протоколов обязательно указывать `--dpi-desync-any-protocol`.
|
Для десинхронизации других протоколов обязательно указывать `--dpi-desync-any-protocol`.
|
||||||
Реализован conntrack для udp. Можно пользоваться --dpi-desync-cutoff. Таймаут conntrack для udp
|
Реализован conntrack для udp. Можно пользоваться --dpi-desync-cutoff. Таймаут conntrack для udp
|
||||||
можно изменить 4-м параметром в `--ctrack-timeouts`.
|
можно изменить 4-м параметром в `--ctrack-timeouts`.
|
||||||
@ -571,7 +614,7 @@ ipv6 : Нет способа для приложения гарантирова
|
|||||||
Чтобы не загромождать описание, смотрите пример решения этой проблемы в `blockcheck.sh`.
|
Чтобы не загромождать описание, смотрите пример решения этой проблемы в `blockcheck.sh`.
|
||||||
|
|
||||||
Иногда требуется подгружать модуль `ip6table_raw` с параметром `raw_before_defrag=1`.
|
Иногда требуется подгружать модуль `ip6table_raw` с параметром `raw_before_defrag=1`.
|
||||||
В openwrt параметры модулей указываются через пробел после их названий в файлах `/etc/modules.d`.
|
В OpenWrt параметры модулей указываются через пробел после их названий в файлах `/etc/modules.d`.
|
||||||
В традиционных системах посмотрите используется ли `iptables-legacy` или `iptables-nft`. Если legacy, то нужно создать файл
|
В традиционных системах посмотрите используется ли `iptables-legacy` или `iptables-nft`. Если legacy, то нужно создать файл
|
||||||
`/etc/modprobe.d/ip6table_raw.conf` с содержимым :
|
`/etc/modprobe.d/ip6table_raw.conf` с содержимым :
|
||||||
```
|
```
|
||||||
@ -603,7 +646,7 @@ options ip6table_raw raw_before_defrag=1
|
|||||||
|
|
||||||
При использовании iptables и NAT, похоже, что нет способа прицепить обработчик очереди после NAT.
|
При использовании iptables и NAT, похоже, что нет способа прицепить обработчик очереди после NAT.
|
||||||
Пакет попадает в nfqws с source адресом внутренней сети, затем фрагментируется и уже не обрабатывается NAT.
|
Пакет попадает в nfqws с source адресом внутренней сети, затем фрагментируется и уже не обрабатывается NAT.
|
||||||
Так и уходит во внешюю сеть с src ip 192.168.x.x. Следовательно, метод не срабатывает.
|
Так и уходит во внешнюю сеть с src ip 192.168.x.x. Следовательно, метод не срабатывает.
|
||||||
Видимо единственный рабочий метод - отказаться от iptables и использовать nftables.
|
Видимо единственный рабочий метод - отказаться от iptables и использовать nftables.
|
||||||
Хук должен быть с приоритетом 101 или выше.
|
Хук должен быть с приоритетом 101 или выше.
|
||||||
|
|
||||||
@ -627,7 +670,7 @@ L7 протокол становится известен обычно посл
|
|||||||
Если имя хоста удовлетворяет листам, выбирается этот профиль. Иначе идет переход к следующему.
|
Если имя хоста удовлетворяет листам, выбирается этот профиль. Иначе идет переход к следующему.
|
||||||
Может так случиться, что до получения имени хоста или узнавания L7 протокола соединение идет по одному профилю,
|
Может так случиться, что до получения имени хоста или узнавания L7 протокола соединение идет по одному профилю,
|
||||||
а при выяснении этих параметров профиль меняется на лету. Это может произойти даже дважды - при выяснении L7
|
а при выяснении этих параметров профиль меняется на лету. Это может произойти даже дважды - при выяснении L7
|
||||||
и имени хоста. Чаще всего это выяснение совмещается в одно действие, поскольку по одному пакету как правило узнается и L7, и хост.
|
и имени хоста. Чаще всего это выяснение совмещается в одно действие, поскольку по одному пакету, как правило, узнается и L7, и хост.
|
||||||
Поэтому если у вас есть параметры дурения нулевой фазы, тщательно продумывайте что может произойти при переключении стратегии.
|
Поэтому если у вас есть параметры дурения нулевой фазы, тщательно продумывайте что может произойти при переключении стратегии.
|
||||||
Смотрите debug log, чтобы лучше понять что делает nfqws.
|
Смотрите debug log, чтобы лучше понять что делает nfqws.
|
||||||
Нумерация профилей идет с 1 до N. Последним в цепочке создается пустой профиль с номером 0.
|
Нумерация профилей идет с 1 до N. Последним в цепочке создается пустой профиль с номером 0.
|
||||||
@ -641,7 +684,7 @@ L7 протокол становится известен обычно посл
|
|||||||
|
|
||||||
> [!IMPORTANT]
|
> [!IMPORTANT]
|
||||||
> user-mode реализация ipset создавалась не как удобная замена *nix версии, реализованной в ядре.
|
> user-mode реализация ipset создавалась не как удобная замена *nix версии, реализованной в ядре.
|
||||||
> Вариант в ядре работает гораздо эффективнее. Это создавалось для систем без подержки ipset в ядре.
|
> Вариант в ядре работает гораздо эффективнее. Это создавалось для систем без подд3ержки ipset в ядре.
|
||||||
> Конкретно - Windows и ядра Linux, собранные без nftables и ipset модулей ядра. Например, в android нет ipset.
|
> Конкретно - Windows и ядра Linux, собранные без nftables и ipset модулей ядра. Например, в android нет ipset.
|
||||||
|
|
||||||
### IPTABLES ДЛЯ NFQWS
|
### IPTABLES ДЛЯ NFQWS
|
||||||
@ -661,7 +704,7 @@ iptables -t mangle -I POSTROUTING -o <внешний_интерфейс> -p tcp
|
|||||||
```
|
```
|
||||||
|
|
||||||
mark нужен, чтобы сгенерированный поддельный пакет не попал опять к нам на обработку. nfqws выставляет fwmark при его отсылке.
|
mark нужен, чтобы сгенерированный поддельный пакет не попал опять к нам на обработку. nfqws выставляет fwmark при его отсылке.
|
||||||
хотя nfqws способен самостоятельно различать помеченные пакеты, фильтр в iptables по mark нужен при использовании connbytes,
|
Хотя nfqws способен самостоятельно различать помеченные пакеты, фильтр в iptables по mark нужен при использовании connbytes,
|
||||||
чтобы не допустить изменения порядка следования пакетов. Процессинг очереди - процесс отложенный.
|
чтобы не допустить изменения порядка следования пакетов. Процессинг очереди - процесс отложенный.
|
||||||
Если ядро имеет пакеты на отсылку вне очереди - оно их отправляет незамедлительно.
|
Если ядро имеет пакеты на отсылку вне очереди - оно их отправляет незамедлительно.
|
||||||
Изменение правильного порядка следования пакетов при десинхронизации ломает всю идею.
|
Изменение правильного порядка следования пакетов при десинхронизации ломает всю идею.
|
||||||
@ -674,7 +717,7 @@ mark нужен, чтобы сгенерированный поддельный
|
|||||||
* 3 - стандартная ситуация приема одного пакета запроса
|
* 3 - стандартная ситуация приема одного пакета запроса
|
||||||
* 4-6 - на случай ретрансмиссии или запроса длиной в несколько пакетов (TLSClientHello с kyber, например)
|
* 4-6 - на случай ретрансмиссии или запроса длиной в несколько пакетов (TLSClientHello с kyber, например)
|
||||||
|
|
||||||
Для режима autottl необходимо перенаправление входящего `SYN,ACK` пакета или первого пакета соединения (что обычно есть тоже самое).
|
Для режима autottl необходимо перенаправление входящего `SYN,ACK` пакета или первого пакета соединения (что обычно есть то же самое).
|
||||||
Для режима autohostlist необходимы входящие RST и http redirect.
|
Для режима autohostlist необходимы входящие RST и http redirect.
|
||||||
Можно построить фильтр на tcp flags для выделения `SYN,ACK` и модуле u32 для поиска характерных паттернов http redirect,
|
Можно построить фильтр на tcp flags для выделения `SYN,ACK` и модуле u32 для поиска характерных паттернов http redirect,
|
||||||
но проще использовать connbytes для выделения нескольких начальных входящих пакетов.
|
но проще использовать connbytes для выделения нескольких начальных входящих пакетов.
|
||||||
@ -744,12 +787,21 @@ iptables могут не работать. При включенном offloadin
|
|||||||
Пакеты, проходящие через SFO, так же проходят мимо большей части механизмов iptables. При включенном SFO работает
|
Пакеты, проходящие через SFO, так же проходят мимо большей части механизмов iptables. При включенном SFO работает
|
||||||
DNAT/REDIRECT (tpws). Эти соединения исключаются из offloading. Однако, остальные соединения идут через SFO, потому
|
DNAT/REDIRECT (tpws). Эти соединения исключаются из offloading. Однако, остальные соединения идут через SFO, потому
|
||||||
NFQUEUE будет срабатывать только до помещения соединения в flowtable. Практически это означает, что почти весь функционал nfqws работать не будет.
|
NFQUEUE будет срабатывать только до помещения соединения в flowtable. Практически это означает, что почти весь функционал nfqws работать не будет.
|
||||||
Offload включается через специальный target в iptables `FLOWOFFLOAD`. Не обязательно пропускать весь трафик через offload. Можно исключить из
|
Offload включается через специальный target в iptables `FLOWOFFLOAD` или через flowtable в nftables.
|
||||||
offload соединения, которые должны попасть на tpws или nfqws. openwrt не предусматривает выборочного управления offload.
|
|
||||||
Поэтому скрипты zapret поддерживают свою систему выборочного управления offload в openwrt.
|
|
||||||
|
|
||||||
iptables target `FLOWOFFLOAD` - это проприетарное изобретение openwrt.
|
Не обязательно пропускать весь трафик через offload.
|
||||||
|
tpws и так обходит offload "by design", а для отработки nfqws достаточно первых нескольких пакетов в tcp соединении или udp сеансе.
|
||||||
|
Пока сеанс не направлен на offload, он процессится обычным образом через полноценный netfilter.
|
||||||
|
Как только срабатывает правило offload по любому входящему или исходящему пакету, весь сеанс окончательно уходит из netfilter в offload.
|
||||||
|
Поэтому скрипты zapret берут правила для NFQUEUE, что они создали, и из них создают exemption правила, которые не дают раньше времени попасть сеансу в offload, а потом его "отпускают".
|
||||||
|
При этом входящим пакетам не дают начать offload, триггером выступают только исходящие пакеты.
|
||||||
|
Эта схема обеспечивает практически нулевой негативный эффект на скорость, одновременно покрывая нужды nfqws и упрощая правила таблиц.
|
||||||
|
|
||||||
|
OpenWrt не предусматривает выборочного управления offload, поэтому скрипты zapret поддерживают свою систему выборочного управления.
|
||||||
|
|
||||||
|
iptables target `FLOWOFFLOAD` - это проприетарное изобретение OpenWrt.
|
||||||
Управление offload в nftables реализовано в базовом ядре linux без патчей.
|
Управление offload в nftables реализовано в базовом ядре linux без патчей.
|
||||||
|
nftables - единственный способ включения offload на классическом Linux.
|
||||||
|
|
||||||
|
|
||||||
## tpws
|
## tpws
|
||||||
@ -761,6 +813,7 @@ tpws - это transparent proxy.
|
|||||||
--debug=0|1|2|syslog|@<filename> ; 0,1,2 = логирование на косоль : 0=тихо, 1(default)=подробно, 2=отладка.
|
--debug=0|1|2|syslog|@<filename> ; 0,1,2 = логирование на косоль : 0=тихо, 1(default)=подробно, 2=отладка.
|
||||||
--debug-level=0|1|2 ; указать уровень логирования для syslog и @<filename>
|
--debug-level=0|1|2 ; указать уровень логирования для syslog и @<filename>
|
||||||
--dry-run ; проверить опции командной строки и выйти. код 0 - успешная проверка.
|
--dry-run ; проверить опции командной строки и выйти. код 0 - успешная проверка.
|
||||||
|
--version ; вывести версию и выйти
|
||||||
|
|
||||||
--daemon ; демонизировать прогу
|
--daemon ; демонизировать прогу
|
||||||
--pidfile=<file> ; сохранить PID в файл
|
--pidfile=<file> ; сохранить PID в файл
|
||||||
@ -828,7 +881,7 @@ tpws - это transparent proxy.
|
|||||||
--mss=<int> ; установить MSS для клиента. может заставить сервер разбивать ответы, но существенно снижает скорость
|
--mss=<int> ; установить MSS для клиента. может заставить сервер разбивать ответы, но существенно снижает скорость
|
||||||
--tamper-start=[n]<pos> ; начинать дурение только с указанной байтовой позиции или номера блока исходяшего потока (считается позиция начала принятого блока)
|
--tamper-start=[n]<pos> ; начинать дурение только с указанной байтовой позиции или номера блока исходяшего потока (считается позиция начала принятого блока)
|
||||||
--tamper-cutoff=[n]<pos> ; закончить дурение на указанной байтовой позиции или номере блока исходящего потока (считается позиция начала принятого блока)
|
--tamper-cutoff=[n]<pos> ; закончить дурение на указанной байтовой позиции или номере блока исходящего потока (считается позиция начала принятого блока)
|
||||||
--hostlist=<filename> ; действовать только над доменами, входящими в список из filename. поддомены автоматически учитываются.
|
--hostlist=<filename> ; действовать только над доменами, входящими в список из filename. поддомены автоматически учитываются, если хост не начинается с '^'.
|
||||||
; в файле должен быть хост на каждой строке.
|
; в файле должен быть хост на каждой строке.
|
||||||
; список читается при старте и хранится в памяти в виде иерархической структуры для быстрого поиска.
|
; список читается при старте и хранится в памяти в виде иерархической структуры для быстрого поиска.
|
||||||
; при изменении времени модификации файла он перечитывается автоматически по необходимости
|
; при изменении времени модификации файла он перечитывается автоматически по необходимости
|
||||||
@ -865,7 +918,7 @@ tpws, как и nfqws, поддерживает множественную се
|
|||||||
Однако, если в момент send уже имеется неотосланный буфер, то ОС присоединит данные к нему,
|
Однако, если в момент send уже имеется неотосланный буфер, то ОС присоединит данные к нему,
|
||||||
никакой отсылки отдельным пакетом не будет. Но в этом случае и так нет никакой гарантии,
|
никакой отсылки отдельным пакетом не будет. Но в этом случае и так нет никакой гарантии,
|
||||||
что какой-то блок сообщения пойдет в начале пакета, на что собственно и заточены DPI.
|
что какой-то блок сообщения пойдет в начале пакета, на что собственно и заточены DPI.
|
||||||
Разбиение будет производится согласно MSS, который зависит от MTU исходящего интерфейса.
|
Разбиение будет производиться согласно MSS, который зависит от MTU исходящего интерфейса.
|
||||||
Таким образом DPI, смотрящие в начало поля данных TCP пакета, будут поломаны в любом случае.
|
Таким образом DPI, смотрящие в начало поля данных TCP пакета, будут поломаны в любом случае.
|
||||||
Протокол http относится к запрос-ответным протоколам. Новое сообщение посылается только тогда,
|
Протокол http относится к запрос-ответным протоколам. Новое сообщение посылается только тогда,
|
||||||
когда сервер получил запрос и полностью вернул ответ. Значит запрос фактически был не только отослан,
|
когда сервер получил запрос и полностью вернул ответ. Значит запрос фактически был не только отослан,
|
||||||
@ -878,13 +931,15 @@ tpws, как и nfqws, поддерживает множественную се
|
|||||||
указанным сплит позициям. Другие ОС в этом вопросе ведут себя более предсказуемо. Спонтанного обьединения замечено не было.
|
указанным сплит позициям. Другие ОС в этом вопросе ведут себя более предсказуемо. Спонтанного обьединения замечено не было.
|
||||||
Поэтому не стоит злоупотреблять сплитами и в особенности мелкими соседними пакетами.
|
Поэтому не стоит злоупотреблять сплитами и в особенности мелкими соседними пакетами.
|
||||||
|
|
||||||
Как показывается практика, проблемы могут начаться , если количество сплит позиций превышает 8.
|
Как показывается практика, проблемы могут начаться , если количество сплитов более одного.
|
||||||
|
На каких-то системах наблюдался стабильный результат до 8 сплитов, на других проблемы уже начинались после 2 сплитов.
|
||||||
|
Один сплит работает стабильно, если не является частью массивной потоковой передачи.
|
||||||
При неудаче сегментации будет выводиться сообщение `WARNING ! segmentation failed`.
|
При неудаче сегментации будет выводиться сообщение `WARNING ! segmentation failed`.
|
||||||
Если вы его видите, это повод снизить количество сплит позиций.
|
Если вы его видите, это повод снизить количество сплит позиций.
|
||||||
Если это не вариант, для ядер Linux >=4.6 есть параметр `--fix-seg`. Он позволяет подождать завершение отсылки перед отправкой следующей части.
|
Если это не вариант, для ядер Linux >=4.6 есть параметр `--fix-seg`. Он позволяет подождать завершение отсылки перед отправкой следующей части.
|
||||||
Но этот вариант ломает модель асинхронной обработки событий. Пока идет ожидание, все остальные соединения не обрабатываются
|
Но этот вариант ломает модель асинхронной обработки событий. Пока идет ожидание, все остальные соединения не обрабатываются
|
||||||
и кратковременно подвисают. На практике это может быть совсем небольшое ожидание - менее 10 мс.
|
и кратковременно подвисают. На практике это может быть совсем небольшое ожидание - менее 10 мс.
|
||||||
И производится оно только , если происходит split, и в ожидании есть реальная необходимость.
|
Выполняется оно только , если происходит split, и в ожидании есть реальная необходимость.
|
||||||
В высоконагруженных системах данный вариант не рекомендуется. Но для домашнего использования может подойти, и вы эти задержки даже не заметите.
|
В высоконагруженных системах данный вариант не рекомендуется. Но для домашнего использования может подойти, и вы эти задержки даже не заметите.
|
||||||
|
|
||||||
Если вы пытаетесь сплитнуть массивную передачу с `--split-any-protocol`, когда информация поступает быстрее отсылки,
|
Если вы пытаетесь сплитнуть массивную передачу с `--split-any-protocol`, когда информация поступает быстрее отсылки,
|
||||||
@ -1051,7 +1106,7 @@ route_localnet :
|
|||||||
динамически вписывать в команду. В любом случае требуются дополнительные усилия. Использование route_localnet тоже имеет
|
динамически вписывать в команду. В любом случае требуются дополнительные усилия. Использование route_localnet тоже имеет
|
||||||
потенциальные проблемы с безопасностью. Вы делаете доступным все, что висит на `127.0.0.0/8` для локальной подсети <
|
потенциальные проблемы с безопасностью. Вы делаете доступным все, что висит на `127.0.0.0/8` для локальной подсети <
|
||||||
внутренний_интерфейс>. Службы обычно привязываются к `127.0.0.1`, поэтому можно средствами iptables запретить входящие
|
внутренний_интерфейс>. Службы обычно привязываются к `127.0.0.1`, поэтому можно средствами iptables запретить входящие
|
||||||
на `127.0.0.1` не с интерфейса lo, либо повесить tpws на любой другой IP из из `127.0.0.0/8`, например на `127.0.0.127`,
|
на `127.0.0.1` не с интерфейса lo, либо повесить tpws на любой другой IP из `127.0.0.0/8`, например на `127.0.0.127`,
|
||||||
и разрешить входящие не с lo только на этот IP.
|
и разрешить входящие не с lo только на этот IP.
|
||||||
|
|
||||||
```
|
```
|
||||||
@ -1100,6 +1155,78 @@ nft add rule inet ztest dnat_pre meta iifname $IFACE_LAN tcp dport { 80, 443 } d
|
|||||||
nft delete table inet ztest
|
nft delete table inet ztest
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## ip2net
|
||||||
|
|
||||||
|
Утилита ip2net предназначена для преобразования ipv4 или ipv6 списка ip в список подсетей
|
||||||
|
с целью сокращения размера списка. Входные данные берутся из stdin, выходные выдаются в `stdout`.
|
||||||
|
|
||||||
|
```
|
||||||
|
-4 ; лист - ipv4 (по умолчанию)
|
||||||
|
-6 ; лист - ipv6
|
||||||
|
--prefix-length=min[-max] ; диапазон рассматриваемых длин префиксов. например : 22-30 (ipv4), 56-64 (ipv6)
|
||||||
|
--v4-threshold=mul/div ; ipv4 : включать подсети, в которых заполнено по крайней мере mul/div адресов. например : 3/4
|
||||||
|
--v6-threshold=N ; ipv6 : минимальное количество ip для создания подсети
|
||||||
|
```
|
||||||
|
В списке могут присутствовать записи вида ip/prefix и ip1-ip2. Такие записи выкидываются в stdout без изменений.
|
||||||
|
Они принимаются командой ipset. ipset умеет для листов hash:net из ip1-ip2 делать оптимальное покрытие ip/prefix.
|
||||||
|
ipfw из FreeBSD понимает ip/prefix, но не понимает ip1-ip2.
|
||||||
|
ip2net фильтрует входные данные, выкидывая неправильные IP адреса.
|
||||||
|
|
||||||
|
Выбирается подсеть, в которой присутствует указанный минимум адресов.
|
||||||
|
Для ipv4 минимум задается как процент от размера подсети (mul/div. например, 3/4), для ipv6 минимум задается напрямую.
|
||||||
|
|
||||||
|
Размер подсети выбирается следующим алгоритмом:
|
||||||
|
Сначала в указанном диапазоне длин префиксов ищутся подсети, в которых количество адресов - максимально.
|
||||||
|
Если таких сетей найдено несколько, берется наименьшая сеть (префикс больше).
|
||||||
|
Например, заданы параметры v6_threshold=2 prefix_length=32-64, имеются следующие ipv6 :
|
||||||
|
```
|
||||||
|
1234:5678:aaaa::5
|
||||||
|
1234:5678:aaaa::6
|
||||||
|
1234:5678:aaac::5
|
||||||
|
Результат будет :
|
||||||
|
1234:5678:aaa8::/45
|
||||||
|
```
|
||||||
|
Эти адреса так же входят в подсеть /32. Однако, нет смысла проходиться ковровой бомбардировкой,
|
||||||
|
когда те же самые адреса вполне влезают в /45 и их ровно столько же.
|
||||||
|
Если изменить v6_threshold=4, то результат будет:
|
||||||
|
```
|
||||||
|
1234:5678:aaaa::5
|
||||||
|
1234:5678:aaaa::6
|
||||||
|
1234:5678:aaac::5
|
||||||
|
```
|
||||||
|
То есть ip не объединятся в подсеть, потому что их слишком мало.
|
||||||
|
Если изменить `prefix_length=56-64`, результат будет:
|
||||||
|
```
|
||||||
|
1234:5678:aaaa::/64
|
||||||
|
1234:5678:aaac::5
|
||||||
|
```
|
||||||
|
|
||||||
|
Требуемое процессорное время для вычислений сильно зависит от ширины диапазона длин префиксов, размера искомых подсетей и длины листа.
|
||||||
|
Если ip2net думает слишком долго, не используйте слишком большие подсети и уменьшите диапазон длин префиксов.
|
||||||
|
Учтите, что арифметика mul/div - целочисленная. При превышении разрядной сетки 32 bit результат непредсказуем.
|
||||||
|
Не надо делать такое: 5000000/10000000. 1/2 - гораздо лучше.
|
||||||
|
|
||||||
|
## mdig
|
||||||
|
|
||||||
|
Программа предназначена для многопоточного ресолвинга больших листов через системный DNS.
|
||||||
|
Она берет из stdin список доменов и выводит в stdout результат ресолвинга. Ошибки выводятся в stderr.
|
||||||
|
|
||||||
|
```
|
||||||
|
--threads=<threads_number> ; количество потоков. по умолчанию 1.
|
||||||
|
--family=<4|6|46> ; выбор семейства IP адресов : ipv4, ipv6, ipv4+ipv6
|
||||||
|
--verbose ; дебаг-лог на консоль
|
||||||
|
--stats=N ; выводить статистику каждые N доменов
|
||||||
|
--log-resolved=<file> ; сохранять успешно отресолвленные домены в файл
|
||||||
|
--log-failed=<file> ; сохранять неудачно отресолвленные домены в файл
|
||||||
|
--dns-make-query=<domain> ; вывести в stdout бинарный DNS запрос по домену. если --family=6, запрос будет AAAA, иначе A.
|
||||||
|
--dns-parse-query ; распарсить бинарный DNS ответ и выдать все ivp4 и ipv6 адреса из него в stdout
|
||||||
|
```
|
||||||
|
|
||||||
|
Параметры `--dns-make-query` и `--dns-parse-query` позволяют провести ресолвинг одного домена через произвольный канал.
|
||||||
|
Например, следующим образом можно выполнить DoH запрос, используя лишь mdig и curl :
|
||||||
|
```
|
||||||
|
mdig --family=6 --dns-make-query=rutracker.org | curl --data-binary @- -H "Content-Type: application/dns-message" https://cloudflare-dns.com/dns-query | mdig --dns-parse-query
|
||||||
|
```
|
||||||
|
|
||||||
## Способы получения списка заблокированных IP
|
## Способы получения списка заблокированных IP
|
||||||
|
|
||||||
@ -1198,79 +1325,6 @@ ipfw таблицы в отличие от ipset могут содержать
|
|||||||
Это особенно полезно на BSD системах с PF.
|
Это особенно полезно на BSD системах с PF.
|
||||||
LISTS_RELOAD=- отключает перезагрузку листов.
|
LISTS_RELOAD=- отключает перезагрузку листов.
|
||||||
|
|
||||||
## ip2net
|
|
||||||
|
|
||||||
Утилита ip2net предназначена для преобразования ipv4 или ipv6 списка ip в список подсетей
|
|
||||||
с целью сокращения размера списка. Входные данные берутся из stdin, выходные выдаются в `stdout`.
|
|
||||||
|
|
||||||
```
|
|
||||||
-4 ; лист - ipv4 (по умолчанию)
|
|
||||||
-6 ; лист - ipv6
|
|
||||||
--prefix-length=min[-max] ; диапазон рассматриваемых длин префиксов. например : 22-30 (ipv4), 56-64 (ipv6)
|
|
||||||
--v4-threshold=mul/div ; ipv4 : включать подсети, в которых заполнено по крайней мере mul/div адресов. например : 3/4
|
|
||||||
--v6-threshold=N ; ipv6 : минимальное количество ip для создания подсети
|
|
||||||
```
|
|
||||||
В списке могут присутствовать записи вида ip/prefix и ip1-ip2. Такие записи выкидываются в stdout без изменений.
|
|
||||||
Они принимаются командой ipset. ipset умеет для листов hash:net из ip1-ip2 делать оптимальное покрытие ip/prefix.
|
|
||||||
ipfw из FreeBSD понимает ip/prefix, но не понимает ip1-ip2.
|
|
||||||
ip2net фильтрует входные данные, выкидывая неправильные IP адреса.
|
|
||||||
|
|
||||||
Выбирается подсеть, в которой присутствует указанный минимум адресов.
|
|
||||||
Для ipv4 минимум задается как процент от размера подсети (mul/div. например, 3/4), для ipv6 минимум задается напрямую.
|
|
||||||
|
|
||||||
Размер подсети выбирается следующим алгоритмом:
|
|
||||||
Сначала в указанном диапазоне длин префиксов ищутся подсети, в которых количество адресов - максимально.
|
|
||||||
Если таких сетей найдено несколько, берется наименьшая сеть (префикс больше).
|
|
||||||
Например, заданы параметры v6_threshold=2 prefix_length=32-64, имеются следующие ipv6 :
|
|
||||||
```
|
|
||||||
1234:5678:aaaa::5
|
|
||||||
1234:5678:aaaa::6
|
|
||||||
1234:5678:aaac::5
|
|
||||||
Результат будет :
|
|
||||||
1234:5678:aaa8::/45
|
|
||||||
```
|
|
||||||
Эти адреса так же входят в подсеть /32. Однако, нет смысла проходиться ковровой бомбардировкой,
|
|
||||||
когда те же самые адреса вполне влезают в /45 и их ровно столько же.
|
|
||||||
Если изменить v6_threshold=4, то результат будет:
|
|
||||||
```
|
|
||||||
1234:5678:aaaa::5
|
|
||||||
1234:5678:aaaa::6
|
|
||||||
1234:5678:aaac::5
|
|
||||||
```
|
|
||||||
То есть ip не объединятся в подсеть, потому что их слишком мало.
|
|
||||||
Если изменить `prefix_length=56-64`, результат будет:
|
|
||||||
```
|
|
||||||
1234:5678:aaaa::/64
|
|
||||||
1234:5678:aaac::5
|
|
||||||
```
|
|
||||||
|
|
||||||
Требуемое процессорное время для вычислений сильно зависит от ширины диапазона длин префиксов, размера искомых подсетей и длины листа.
|
|
||||||
Если ip2net думает слишком долго, не используйте слишком большие подсети и уменьшите диапазон длин префиксов.
|
|
||||||
Учтите, что арифметика mul/div - целочисленная. При превышении разрядной сетки 32 bit результат непредсказуем.
|
|
||||||
Не надо делать такое: 5000000/10000000. 1/2 - гораздо лучше.
|
|
||||||
|
|
||||||
## mdig
|
|
||||||
|
|
||||||
Программа предназначена для многопоточного ресолвинга больших листов через системный DNS.
|
|
||||||
Она берет из stdin список доменов и выводит в stdout результат ресолвинга. Ошибки выводятся в stderr.
|
|
||||||
|
|
||||||
```
|
|
||||||
--threads=<threads_number> ; количество потоков. по умолчанию 1.
|
|
||||||
--family=<4|6|46> ; выбор семейства IP адресов : ipv4, ipv6, ipv4+ipv6
|
|
||||||
--verbose ; дебаг-лог на консоль
|
|
||||||
--stats=N ; выводить статистику каждые N доменов
|
|
||||||
--log-resolved=<file> ; сохранять успешно отресолвленные домены в файл
|
|
||||||
--log-failed=<file> ; сохранять неудачно отресолвленные домены в файл
|
|
||||||
--dns-make-query=<domain> ; вывести в stdout бинарный DNS запрос по домену. если --family=6, запрос будет AAAA, иначе A.
|
|
||||||
--dns-parse-query ; распарсить бинарный DNS ответ и выдать все ivp4 и ipv6 адреса из него в stdout
|
|
||||||
```
|
|
||||||
|
|
||||||
Параметры `--dns-make-query` и `--dns-parse-query` позволяют провести ресолвинг одного домена через произвольный канал.
|
|
||||||
Например, следующим образом можно выполнить DoH запрос, используя лишь mdig и curl :
|
|
||||||
```
|
|
||||||
mdig --family=6 --dns-make-query=rutracker.org | curl --data-binary @- -H "Content-Type: application/dns-message" https://cloudflare-dns.com/dns-query | mdig --dns-parse-query
|
|
||||||
```
|
|
||||||
|
|
||||||
## Фильтрация по именам доменов
|
## Фильтрация по именам доменов
|
||||||
|
|
||||||
Альтернативой ipset является использование tpws или nfqws со списком доменов.
|
Альтернативой ipset является использование tpws или nfqws со списком доменов.
|
||||||
@ -1294,10 +1348,11 @@ mdig --family=6 --dns-make-query=rutracker.org | curl --data-binary @- -H "Conte
|
|||||||
При режимах фильтрации `MODE_FILTER=hostlist` или `MODE_FILTER=autohostlist` система запуска передает **nfqws** или **tpws** все листы, файлы которых присутствуют.
|
При режимах фильтрации `MODE_FILTER=hostlist` или `MODE_FILTER=autohostlist` система запуска передает **nfqws** или **tpws** все листы, файлы которых присутствуют.
|
||||||
Передача происходит через замену маркеров `<HOSTLIST>` и `<HOSTLIST_NOAUTO>` на реальные параметры `--hostlist`, `--hostlist-exclude`, `--hostlist-auto`.
|
Передача происходит через замену маркеров `<HOSTLIST>` и `<HOSTLIST_NOAUTO>` на реальные параметры `--hostlist`, `--hostlist-exclude`, `--hostlist-auto`.
|
||||||
Если вдруг листы include присутствуют, но все они пустые, то работа аналогична отсутствию include листа.
|
Если вдруг листы include присутствуют, но все они пустые, то работа аналогична отсутствию include листа.
|
||||||
Файл есть, но не смотря на это дурится все, кроме exclude.
|
Файл есть, но несмотря на это дурится все, кроме exclude.
|
||||||
Если вам нужен именно такой режим - не обязательно удалять `zapret-hosts-users.txt`. Достаточно сделать его пустым.
|
Если вам нужен именно такой режим - не обязательно удалять `zapret-hosts-users.txt`. Достаточно сделать его пустым.
|
||||||
|
|
||||||
Поддомены учитываются автоматически. Например, строчка "ru" вносит в список "*.ru". Строчка "*.ru" в списке не сработает.
|
Поддомены учитываются автоматически. Например, строчка "ru" вносит в список "*.ru". Строчка "*.ru" в списке не сработает.
|
||||||
|
Можно использовать символ `^` в начале хоста, чтобы отказаться от автоматического учета поддоменов.
|
||||||
|
|
||||||
Список доменов РКН может быть получен скриптами
|
Список доменов РКН может быть получен скриптами
|
||||||
```
|
```
|
||||||
@ -1308,7 +1363,8 @@ ipset/get_refilter_domains.sh
|
|||||||
```
|
```
|
||||||
Он кладется в `ipset/zapret-hosts.txt.gz`.
|
Он кладется в `ipset/zapret-hosts.txt.gz`.
|
||||||
|
|
||||||
При изменении времени модификации файлов списки перечитываются автоматически.
|
При изменении времени модификации или размера файлов списки перечитываются автоматически.
|
||||||
|
После неатомарных операций изменения можно послать tpws/nfqws сигнал HUP для принудительной перечитки всех листов.
|
||||||
|
|
||||||
При фильтрации по именам доменов демон должен запускаться без фильтрации по ipset.
|
При фильтрации по именам доменов демон должен запускаться без фильтрации по ipset.
|
||||||
tpws и nfqws решают нужно ли применять дурение в зависимости от хоста, полученного из протокола прикладного уровня (http, tls, quic).
|
tpws и nfqws решают нужно ли применять дурение в зависимости от хоста, полученного из протокола прикладного уровня (http, tls, quic).
|
||||||
@ -1330,7 +1386,7 @@ tpws и nfqws решают нужно ли применять дурение в
|
|||||||
Крайне рекомендовано использовать ограничитель `connbytes`, чтобы **nfqws** не обрабатывал гигабайты.
|
Крайне рекомендовано использовать ограничитель `connbytes`, чтобы **nfqws** не обрабатывал гигабайты.
|
||||||
По этой же причине не рекомендуется использование режима на BSD системах. Там нет фильтра `connbytes`.
|
По этой же причине не рекомендуется использование режима на BSD системах. Там нет фильтра `connbytes`.
|
||||||
|
|
||||||
На linux системах при использовании nfqws и фильтра connbytes может понадобится :
|
На linux системах при использовании nfqws и фильтра connbytes может понадобиться :
|
||||||
`sysctl net.netfilter.nf_conntrack_tcp_be_liberal=1`
|
`sysctl net.netfilter.nf_conntrack_tcp_be_liberal=1`
|
||||||
Было замечено, что некоторые DPI в России возвращают RST с неверным ACK. Это принимается tcp/ip стеком
|
Было замечено, что некоторые DPI в России возвращают RST с неверным ACK. Это принимается tcp/ip стеком
|
||||||
linux, но через раз приобретает статус INVALID в conntrack. Поэтому правила с `connbytes` срабатывают
|
linux, но через раз приобретает статус INVALID в conntrack. Поэтому правила с `connbytes` срабатывают
|
||||||
@ -1345,7 +1401,7 @@ linux, но через раз приобретает статус INVALID в con
|
|||||||
свое клиенту. Применяется нечасто, поскольку броузеры на такое ругаются.
|
свое клиенту. Применяется нечасто, поскольку броузеры на такое ругаются.
|
||||||
|
|
||||||
**nfqws** и **tpws** могут сечь варианты 1-3, 4 они не распознают.
|
**nfqws** и **tpws** могут сечь варианты 1-3, 4 они не распознают.
|
||||||
Всилу специфики работы с отдельными пакетами или с TCP каналом tpws и nfqws распознают эти ситуации
|
В силу специфики работы с отдельными пакетами или с TCP каналом tpws и nfqws распознают эти ситуации
|
||||||
по-разному.
|
по-разному.
|
||||||
Что считается ситуацией, похожей на блокировку :
|
Что считается ситуацией, похожей на блокировку :
|
||||||
1) **nfqws** Несколько ретрансмиссий первого запроса в TCP сеансе, в котором имеется host.
|
1) **nfqws** Несколько ретрансмиссий первого запроса в TCP сеансе, в котором имеется host.
|
||||||
@ -1371,7 +1427,7 @@ linux, но через раз приобретает статус INVALID в con
|
|||||||
Если сайт не ведет себя как заблокированный, значит обход применен не будет.
|
Если сайт не ведет себя как заблокированный, значит обход применен не будет.
|
||||||
В противном случае терять все равно нечего.
|
В противном случае терять все равно нечего.
|
||||||
Однако, могут быть временные сбои сервера, приводящие к ситуации, аналогичной блокировке.
|
Однако, могут быть временные сбои сервера, приводящие к ситуации, аналогичной блокировке.
|
||||||
Могут происходит ложные срабатывания. Если такое произошло, стратегия может начать ломать
|
Могут происходить ложные срабатывания. Если такое произошло, стратегия может начать ломать
|
||||||
незаблокированный сайт. Эту ситуацию, увы, придется вам контролировать вручную.
|
незаблокированный сайт. Эту ситуацию, увы, придется вам контролировать вручную.
|
||||||
Заносите такие домены в `ipset/zapret-hosts-user-exclude.txt`, чтобы избежать повторения.
|
Заносите такие домены в `ipset/zapret-hosts-user-exclude.txt`, чтобы избежать повторения.
|
||||||
Чтобы впоследствии разобраться почему домен был занесен в лист, можно включить `autohostlist debug log`.
|
Чтобы впоследствии разобраться почему домен был занесен в лист, можно включить `autohostlist debug log`.
|
||||||
@ -1432,11 +1488,22 @@ linux, но через раз приобретает статус INVALID в con
|
|||||||
CURL - замена программы curl
|
CURL - замена программы curl
|
||||||
CURL_MAX_TIME - время таймаута curl в секундах
|
CURL_MAX_TIME - время таймаута curl в секундах
|
||||||
CURL_MAX_TIME_QUIC - время таймаута curl для quic. если не задано, используется значение CURL_MAX_TIME
|
CURL_MAX_TIME_QUIC - время таймаута curl для quic. если не задано, используется значение CURL_MAX_TIME
|
||||||
|
CURL_MAX_TIME_DOH - время таймаута curl для DoH серверов
|
||||||
CURL_CMD=1 - показывать команды curl
|
CURL_CMD=1 - показывать команды curl
|
||||||
CURL_OPT - дополнительные параметры curl. `-k` - игнор сертификатов. `-v` - подробный вывод протокола
|
CURL_OPT - дополнительные параметры curl. `-k` - игнор сертификатов. `-v` - подробный вывод протокола
|
||||||
DOMAINS - список тестируемых доменов через пробел
|
DOMAINS - список тестируемых доменов через пробел
|
||||||
|
IPVS=4|6|46 - тестируемые версии ip протокола
|
||||||
|
ENABLE_HTTP=0|1 - включить тест plain http
|
||||||
|
ENABLE_HTTPS_TLS12=0|1 - включить тест https TLS 1.2
|
||||||
|
ENABLE_HTTPS_TLS13=0|1 - включить тест https TLS 1.3
|
||||||
|
ENABLE_HTTP3=0|1 - включить тест QUIC
|
||||||
|
REPEATS - количество попыток тестирования
|
||||||
|
PARALLEL=0|1 - включить параллельные попытки. может обидеть сайт из-за долбежки и привести к неверному результату
|
||||||
|
SCANLEVEL=quick|standard|force - уровень сканирования
|
||||||
|
BATCH=1 - пакетный режим без вопросов и ожидания ввода в консоли
|
||||||
HTTP_PORT, HTTPS_PORT, QUIC_PORT - номера портов для соответствующих протоколов
|
HTTP_PORT, HTTPS_PORT, QUIC_PORT - номера портов для соответствующих протоколов
|
||||||
SKIP_DNSCHECK=1 - отказ от проверки DNS
|
SKIP_DNSCHECK=1 - отказ от проверки DNS
|
||||||
|
SKIP_IPBLOCK=1 - отказ от тестов блокировки по порту или IP
|
||||||
SKIP_TPWS=1 - отказ от тестов tpws
|
SKIP_TPWS=1 - отказ от тестов tpws
|
||||||
SKIP_PKTWS=1 - отказ от тестов nfqws/dvtws/winws
|
SKIP_PKTWS=1 - отказ от тестов nfqws/dvtws/winws
|
||||||
PKTWS_EXTRA, TPWS_EXTRA - дополнительные параметры nfqws/dvtws/winws и tpws
|
PKTWS_EXTRA, TPWS_EXTRA - дополнительные параметры nfqws/dvtws/winws и tpws
|
||||||
@ -1444,13 +1511,14 @@ PKTWS_EXTRA_1 .. PKTWS_EXTRA_9, TPWS_EXTRA_1 .. TPWS_EXTRA_9 - отдельно
|
|||||||
SECURE_DNS=0|1 - принудительно выключить или включить DoH
|
SECURE_DNS=0|1 - принудительно выключить или включить DoH
|
||||||
DOH_SERVERS - список URL DoH через пробел для автоматического выбора работающего сервера
|
DOH_SERVERS - список URL DoH через пробел для автоматического выбора работающего сервера
|
||||||
DOH_SERVER - конкретный DoH URL, отказ от поиска
|
DOH_SERVER - конкретный DoH URL, отказ от поиска
|
||||||
|
UNBLOCKED_DOM - незаблокированный домен, который используется для тестов IP block
|
||||||
```
|
```
|
||||||
|
|
||||||
Пример запуска с переменными:\
|
Пример запуска с переменными:\
|
||||||
`SECURE_DNS=1 SKIP_TPWS=1 CURL_MAX_TIME=1 CURL=/tmp/curl ./blockcheck.sh`
|
`SECURE_DNS=1 SKIP_TPWS=1 CURL_MAX_TIME=1 CURL=/tmp/curl ./blockcheck.sh`
|
||||||
|
|
||||||
**СКАН ПОРТОВ**\
|
**СКАН ПОРТОВ**\
|
||||||
Если в системе присутствует совместимый `netcat` (ncat от nmap или openbsd ncat. в openwrt по умолчанию нет),
|
Если в системе присутствует совместимый `netcat` (ncat от nmap или openbsd ncat. в OpenWrt по умолчанию нет),
|
||||||
то выполняется сканирование портов http или https всех IP адресов домена.
|
то выполняется сканирование портов http или https всех IP адресов домена.
|
||||||
Если ни один IP не отвечает, то результат очевиден. Можно останавливать сканирование.
|
Если ни один IP не отвечает, то результат очевиден. Можно останавливать сканирование.
|
||||||
Автоматически оно не остановится, потому что netcat-ы недостаточно подробно информируют о причинах ошибки.
|
Автоматически оно не остановится, потому что netcat-ы недостаточно подробно информируют о причинах ошибки.
|
||||||
@ -1557,7 +1625,7 @@ curl: (28) Connection timed out after 2002 milliseconds
|
|||||||
|
|
||||||
На linux системах можно выбрать использовать `iptables` или `nftables`.
|
На linux системах можно выбрать использовать `iptables` или `nftables`.
|
||||||
По умолчанию на традиционных linux выбирается `nftables`, если установлен nft.
|
По умолчанию на традиционных linux выбирается `nftables`, если установлен nft.
|
||||||
На openwrt по умолчанию выбирается `nftables` на новых версиях с firewall4.
|
На OpenWrt по умолчанию выбирается `nftables` на новых версиях с firewall4.
|
||||||
|
|
||||||
`FWTYPE=iptables`
|
`FWTYPE=iptables`
|
||||||
|
|
||||||
@ -1768,11 +1836,11 @@ LISTS_RELOAD="pfctl -f /etc/pf.conf"
|
|||||||
LISTS_RELOAD=-
|
LISTS_RELOAD=-
|
||||||
```
|
```
|
||||||
|
|
||||||
В openwrt существует сеть по умолчанию 'lan'. Только трафик с этой сети будет перенаправлен на tpws.
|
В OpenWrt существует сеть по умолчанию 'lan'. Только трафик с этой сети будет перенаправлен на tpws.
|
||||||
Но возможно задать другие сети или список сетей:\
|
Но возможно задать другие сети или список сетей:\
|
||||||
`OPENWRT_LAN="lan lan2 lan3"`
|
`OPENWRT_LAN="lan lan2 lan3"`
|
||||||
|
|
||||||
В openwrt в качестве wan берутся интерфейсы, имеющие default route. Отдельно для ipv4 и ipv6.
|
В OpenWrt в качестве wan берутся интерфейсы, имеющие default route. Отдельно для ipv4 и ipv6.
|
||||||
Это можно переопределить:
|
Это можно переопределить:
|
||||||
```
|
```
|
||||||
OPENWRT_WAN4="wan4 vpn"
|
OPENWRT_WAN4="wan4 vpn"
|
||||||
@ -1782,7 +1850,7 @@ OPENWRT_WAN6="wan6 vpn6"
|
|||||||
Параметр INIT_APPLY_FW=1 разрешает init скрипту самостоятельно применять правила iptables.\
|
Параметр INIT_APPLY_FW=1 разрешает init скрипту самостоятельно применять правила iptables.\
|
||||||
При иных значениях или если параметр закомментирован, правила применены не будут.\
|
При иных значениях или если параметр закомментирован, правила применены не будут.\
|
||||||
Это полезно, если у вас есть система управления фаерволом, в настройки которой и следует прикрутить правила.\
|
Это полезно, если у вас есть система управления фаерволом, в настройки которой и следует прикрутить правила.\
|
||||||
На openwrt неприменимо при использовании firewall3+iptables.
|
На OpenWrt неприменимо при использовании firewall3+iptables.
|
||||||
|
|
||||||
***Следующие настройки не актуальны для openwrt:***
|
***Следующие настройки не актуальны для openwrt:***
|
||||||
|
|
||||||
@ -1836,7 +1904,7 @@ _Для `nftables` предусмотрено несколько дополни
|
|||||||
|
|
||||||
Обновить set-ы интерфейсов, относящихся к lan, wan и wan6.
|
Обновить set-ы интерфейсов, относящихся к lan, wan и wan6.
|
||||||
Для традиционных linux список интерфейсов берется из переменных конфига IFACE_LAN, IFACE_WAN.
|
Для традиционных linux список интерфейсов берется из переменных конфига IFACE_LAN, IFACE_WAN.
|
||||||
Для openwrt определяется автоматически. Множество lanif может быть расширено параметром OPENWRT_LAN.
|
Для OpenWrt определяется автоматически. Множество lanif может быть расширено параметром OPENWRT_LAN.
|
||||||
Все интерфейсы lan и wan так же добавляются в ingress hook от flow table.\
|
Все интерфейсы lan и wan так же добавляются в ingress hook от flow table.\
|
||||||
`/opt/zapret/init.d/sysv/zapret reload_ifsets`
|
`/opt/zapret/init.d/sysv/zapret reload_ifsets`
|
||||||
|
|
||||||
@ -1860,7 +1928,7 @@ nfset-ы принадлежат только одной таблице, след
|
|||||||
|
|
||||||
custom скрипты - это маленькие shell программы, управляющие нестандартными режимами применения zapret
|
custom скрипты - это маленькие shell программы, управляющие нестандартными режимами применения zapret
|
||||||
или частными случаями, которые не могут быть интегрированы в основную часть без загромождения и замусоривания кода.
|
или частными случаями, которые не могут быть интегрированы в основную часть без загромождения и замусоривания кода.
|
||||||
Для применеия custom следует помещать файлы в следующие директории в зависимости от вашей системы:
|
Для применения custom следует помещать файлы в следующие директории в зависимости от вашей системы:
|
||||||
```
|
```
|
||||||
/opt/zapret/init.d/sysv/custom.d
|
/opt/zapret/init.d/sysv/custom.d
|
||||||
/opt/zapret/init.d/openwrt/custom.d
|
/opt/zapret/init.d/openwrt/custom.d
|
||||||
@ -1888,7 +1956,7 @@ zapret_custom_firewall_v6
|
|||||||
|
|
||||||
zapret_custom_daemons поднимает демоны **nfqws**/**tpws** в нужном вам количестве и с нужными вам параметрами.
|
zapret_custom_daemons поднимает демоны **nfqws**/**tpws** в нужном вам количестве и с нужными вам параметрами.
|
||||||
В первом параметре передается код операции: 1 = запуск, 0 = останов.
|
В первом параметре передается код операции: 1 = запуск, 0 = останов.
|
||||||
Схема запуска демонов в openwrt отличается - используется procd.
|
Схема запуска демонов в OpenWrt отличается - используется procd.
|
||||||
Поэтому логика останова отсутствует за ненадобностью, останов никогда не вызывается.
|
Поэтому логика останова отсутствует за ненадобностью, останов никогда не вызывается.
|
||||||
|
|
||||||
zapret_custom_firewall поднимает и убирает правила `iptables`.
|
zapret_custom_firewall поднимает и убирает правила `iptables`.
|
||||||
@ -1930,7 +1998,7 @@ zapret_custom_firewall_nft поднимает правила nftables.
|
|||||||
## Простая установка
|
## Простая установка
|
||||||
|
|
||||||
`install_easy.sh` автоматизирует ручные варианты процедур установки.
|
`install_easy.sh` автоматизирует ручные варианты процедур установки.
|
||||||
Он поддерживает OpenWRT, linux системы на базе systemd или openrc и MacOS.
|
Он поддерживает OpenWrt, linux системы на базе systemd или openrc и MacOS.
|
||||||
|
|
||||||
Для более гибкой настройки перед запуском инсталлятора следует выполнить раздел "Выбор параметров".
|
Для более гибкой настройки перед запуском инсталлятора следует выполнить раздел "Выбор параметров".
|
||||||
|
|
||||||
@ -1947,10 +2015,10 @@ zapret_custom_firewall_nft поднимает правила nftables.
|
|||||||
|
|
||||||
`install_easy.sh make`
|
`install_easy.sh make`
|
||||||
|
|
||||||
Под openwrt все уже сразу готово для использования системы в качестве роутера.
|
Под OpenWrt все уже сразу готово для использования системы в качестве роутера.
|
||||||
Имена интерфейсов WAN и LAN известны из настроек системы.
|
Имена интерфейсов WAN и LAN известны из настроек системы.
|
||||||
Под другими системами роутер вы настраиваете самостоятельно. Инсталлятор в это не вмешивается.
|
Под другими системами роутер вы настраиваете самостоятельно. Инсталлятор в это не вмешивается.
|
||||||
инсталлятор в зависимости от выбранного режима может спросить LAN и WAN интерфейсы.
|
Инсталлятор в зависимости от выбранного режима может спросить LAN и WAN интерфейсы.
|
||||||
Нужно понимать, что заворот проходящего трафика на **tpws** в прозрачном режиме происходит до выполнения маршрутизации,
|
Нужно понимать, что заворот проходящего трафика на **tpws** в прозрачном режиме происходит до выполнения маршрутизации,
|
||||||
следовательно возможна фильтрация по LAN и невозможна по WAN.
|
следовательно возможна фильтрация по LAN и невозможна по WAN.
|
||||||
Решение о завороте на **tpws** локального исходящего трафика принимается после выполнения маршрутизации,
|
Решение о завороте на **tpws** локального исходящего трафика принимается после выполнения маршрутизации,
|
||||||
@ -1960,6 +2028,15 @@ zapret_custom_firewall_nft поднимает правила nftables.
|
|||||||
|
|
||||||
Деинсталляция выполняется через `uninstall_easy.sh`. После выполнения деинсталляции можно удалить каталог `/opt/zapret`.
|
Деинсталляция выполняется через `uninstall_easy.sh`. После выполнения деинсталляции можно удалить каталог `/opt/zapret`.
|
||||||
|
|
||||||
|
## Установка под systemd
|
||||||
|
|
||||||
|
Если вам нравится systemd и хочется максимально под него заточиться, можно отказаться от скриптов запуска zapret
|
||||||
|
и поднимать инстансы `tpws` и `nfqws` как отдельные юниты systemd. При этом вам придется вручную написать правила iptables/nftables
|
||||||
|
и каким-то образом их поднимать. Например, написать дополнительный systemd unit для этого.
|
||||||
|
Так же требуется собрать бинарники особым образом через `make systemd`.
|
||||||
|
|
||||||
|
В комплекте zapret есть шаблоны `init.d/systemd/{nfqws@.service,tpws@.service}`.
|
||||||
|
Краткий перечень команд для их использования приведен в комментариях в этих файлах.
|
||||||
|
|
||||||
## Простая установка на openwrt
|
## Простая установка на openwrt
|
||||||
|
|
||||||
@ -2072,17 +2149,18 @@ adb push tpws /data/local/tmp/zapret
|
|||||||
chmod 755 /data/local/tmp/zapret /data/local/tmp/zapret/tpws
|
chmod 755 /data/local/tmp/zapret /data/local/tmp/zapret/tpws
|
||||||
chcon u:object_r:system_file:s0 /data/local/tmp/zapret/tpws
|
chcon u:object_r:system_file:s0 /data/local/tmp/zapret/tpws
|
||||||
```
|
```
|
||||||
Как найти стратегию обхода сотового оператора: проще всего раздать инет на комп с linux.
|
Как найти стратегию обхода сотового оператора: проще всего раздать инет на комп.
|
||||||
Можно записать live image linux на флэшку и загрузиться с нее или запустить виртуалку с linux
|
Для этого подойдет любая поддерживаемая ОС. Подключите android через USB кабель к компу и включите режим модема.
|
||||||
и пробросить в нее usb устройство от режима модема с телефона.
|
Прогоните стандартную процедуру blockcheck. При переносе правил на телефон уменьшить TTL на 1,
|
||||||
На компе с linux прогнать стандартную процедуру blockcheck. При переносе правил на телефон уменьшить TTL на 1,
|
если правила с TTL присутствуют в стратегии. Если проверялось на windows, убрать параметры `--wf-*`.
|
||||||
если правила с TTL присутствуют в стратегии.
|
|
||||||
Можно развернуть rootfs какого-нибудь дистрибутива linux прямо на телефоне, имея рута.
|
Работа blockcheck в android shell не поддерживается, но имея рута можно развернуть rootfs какого-нибудь дистрибутива linux.
|
||||||
Это лучше всего делать с компа через adb shell.
|
Это лучше всего делать с компа через adb shell.
|
||||||
Если компа нет, то это единственный вариант, хотя и неудобный.
|
Если компа нет, то развертка chroot - единственный вариант, хотя и неудобный.
|
||||||
Подойдет что-то легковесное, например, alpine или даже openwrt.
|
Подойдет что-то легковесное, например, alpine или даже OpenWrt.
|
||||||
Если это не эмулятор android, то универсальная архитектура - arm (любой вариант).
|
Если это не эмулятор android, то универсальная архитектура - arm (любой вариант).
|
||||||
Если вы точно знаете, что ОС у вас 64-разрядная, то лучше вместо arm - aarch64.
|
Если вы точно знаете, что ОС у вас 64-разрядная, то лучше вместо arm - aarch64.
|
||||||
|
Выяснить архитектуру можно командой `uname -a`.
|
||||||
|
|
||||||
```
|
```
|
||||||
mount --bind /dev /data/linux/dev
|
mount --bind /dev /data/linux/dev
|
||||||
@ -2130,7 +2208,7 @@ Wifi сеть - обычно `wlan0`.
|
|||||||
|
|
||||||
tpws работает обычным образом.
|
tpws работает обычным образом.
|
||||||
|
|
||||||
`nfqueue` поломан, можно собрать фиксящий модуль https://github.com/im-0/unfuck-nfqueue-on-e3372h,
|
`nfqueue` поломан, можно собрать фиксящий модуль https://github.com/im-0/unfuck-nfqueue-on-e3372h,
|
||||||
используя исходники с huawei open source. Исходники содержат тулчейн и полусобирающееся,
|
используя исходники с huawei open source. Исходники содержат тулчейн и полусобирающееся,
|
||||||
неактуальное ядро. Конфиг можно взять с рабочего модема из `/proc/config.gz`.
|
неактуальное ядро. Конфиг можно взять с рабочего модема из `/proc/config.gz`.
|
||||||
С помощью этих исходников умельцы могут собрать модуль `unfuck_nfqueue.ko`.
|
С помощью этих исходников умельцы могут собрать модуль `unfuck_nfqueue.ko`.
|
||||||
@ -2183,10 +2261,10 @@ curl: (7) Failed to connect to www.ru port 80: Host is unreachable
|
|||||||
|
|
||||||
## Другие прошивки
|
## Другие прошивки
|
||||||
|
|
||||||
Для статических бинариков не имеет значения на чем они запущены: PC, android, приставка, роутер, любой другой девайс.
|
Для статических бинарников не имеет значения на чем они запущены: PC, android, приставка, роутер, любой другой девайс.
|
||||||
Подойдет любая прошивка, дистрибутив linux. Статические бинарники запустятся на всем.
|
Подойдет любая прошивка, дистрибутив linux. Статические бинарники запустятся на всем.
|
||||||
Им нужно только ядро с необходимыми опциями сборки или модулями.
|
Им нужно только ядро с необходимыми опциями сборки или модулями.
|
||||||
Но кроме бинариков в проекте используются еще и скрипты, в которых задействуются некоторые
|
Но кроме бинарников в проекте используются еще и скрипты, в которых задействуются некоторые
|
||||||
стандартные программы.
|
стандартные программы.
|
||||||
|
|
||||||
Основные причины почему нельзя просто так взять и установить эту систему на что угодно:
|
Основные причины почему нельзя просто так взять и установить эту систему на что угодно:
|
||||||
@ -2223,15 +2301,15 @@ entware содержит репозиторий user-mode компонент, к
|
|||||||
|
|
||||||
_Подробное описание настроек для других прошивок выходит за рамки данного проекта._
|
_Подробное описание настроек для других прошивок выходит за рамки данного проекта._
|
||||||
|
|
||||||
Openwrt является одной из немногих относительно полноценных linux систем для embedded devices.
|
OpenWrt является одной из немногих относительно полноценных linux систем для embedded devices.
|
||||||
Она характеризуется следующими вещами, которые и послужили основой выбора именно этой прошивк:
|
Она характеризуется следующими вещами, которые и послужили основой выбора именно этой прошивки:
|
||||||
* полный root доступ к девайсу через shell. на заводских прошивках чаще всего отсутствует, на многих альтернативных есть
|
* полный root доступ к девайсу через shell. на заводских прошивках чаще всего отсутствует, на многих альтернативных есть
|
||||||
* корень r/w. это практически уникальная особенность openwrt. заводские и большинство альтернативных прошивок
|
* корень r/w. это практически уникальная особенность OpenWrt. заводские и большинство альтернативных прошивок
|
||||||
построены на базе squashfs root (r/o), а конфигурация хранится в специально отформатированной области
|
построены на базе squashfs root (r/o), а конфигурация хранится в специально отформатированной области
|
||||||
встроенной памяти, называемой nvram. не имеющие r/w корня системы сильно кастрированы. они не имеют
|
встроенной памяти, называемой nvram. не имеющие r/w корня системы сильно кастрированы. они не имеют
|
||||||
возможности доустановки ПО из репозитория без специальных вывертов и заточены в основном
|
возможности доустановки ПО из репозитория без специальных вывертов и заточены в основном
|
||||||
на чуть более продвинутого, чем обычно, пользователя и управление имеющимся функционалом через веб интерфейс,
|
на чуть более продвинутого, чем обычно, пользователя и управление имеющимся функционалом через веб интерфейс,
|
||||||
но функционал фиксированно ограничен. альтернативные прошивки как правило могут монтировать r/w раздел
|
но функционал фиксированно ограничен. альтернативные прошивки, как правило, могут монтировать r/w раздел
|
||||||
в какую-то область файловой системы, заводские обычно могут монтировать лишь флэшки, подключенные к USB,
|
в какую-то область файловой системы, заводские обычно могут монтировать лишь флэшки, подключенные к USB,
|
||||||
и не факт, что есть поддержка unix файловых системы. может быть поддержка только fat и ntfs.
|
и не факт, что есть поддержка unix файловых системы. может быть поддержка только fat и ntfs.
|
||||||
* возможность выноса корневой файловой системы на внешний носитель (extroot) или создания на нем оверлея (overlay)
|
* возможность выноса корневой файловой системы на внешний носитель (extroot) или создания на нем оверлея (overlay)
|
||||||
@ -2247,55 +2325,51 @@ Openwrt является одной из немногих относительн
|
|||||||
|
|
||||||
Если не работает автономный обход, приходится перенаправлять трафик через сторонний хост.
|
Если не работает автономный обход, приходится перенаправлять трафик через сторонний хост.
|
||||||
Предлагается использовать прозрачный редирект через socks5 посредством `iptables+redsocks`, либо `iptables+iproute+vpn`.
|
Предлагается использовать прозрачный редирект через socks5 посредством `iptables+redsocks`, либо `iptables+iproute+vpn`.
|
||||||
Настройка варианта с redsocks на openwrt описана в [redsocks.txt](./redsocks.txt).
|
Настройка варианта с redsocks на OpenWrt описана в [redsocks.txt](./redsocks.txt).
|
||||||
Настройка варианта с `iproute+wireguard` - в [wireguard_iproute_openwrt.txt](./wireguard_iproute_openwrt.txt).
|
Настройка варианта с `iproute+wireguard` - в [wireguard_iproute_openwrt.txt](./wireguard_iproute_openwrt.txt).
|
||||||
|
|
||||||
|
|
||||||
## Почему стоит вложиться в покупку VPS
|
## Почему стоит вложиться в покупку VPS
|
||||||
|
|
||||||
VPS - это виртуальный сервер. Существует огромное множество датацентров, предлагающих данную услугу.
|
VPS — это виртуальный сервер. Существует огромное множество датацентров, предлагающих данную услугу.
|
||||||
На VPS могут выполняться какие угодно задачи. От простого веб сайта до навороченной системы собственной разработки.
|
На VPS могут выполняться какие угодно задачи. От простого веб-сайта до навороченной системы собственной разработки.
|
||||||
Можно использовать VPS и для поднятия собственного vpn или прокси.
|
Можно использовать VPS и для поднятия собственного VPN или прокси.
|
||||||
Сама широта возможных способов применения, распространенность услуги сводят к минимуму возможности
|
Сама широта возможных способов применения и распространенность услуги сводят к минимуму возможности
|
||||||
регуляторов по бану сервисов такого типа. Да, если введут белые списки, то решение загнется, но это будет уже другая
|
регуляторов по бану сервисов такого типа. Да, если введут белые списки, то решение загнется, но это будет уже другая
|
||||||
реальность, в которой придется изобретать иные решения.
|
реальность, в которой придется изобретать иные решения.
|
||||||
Пока этого не сделали, никто не будет банить хостинги просто потому, что они предоставляют хостинг услуги.
|
Пока этого не сделали, никто не будет банить хостинги просто потому, что они предоставляют хостинг услуги.
|
||||||
Вы как индивидуум скорее всего никому не нужны. Подумайте чем вы отличаетесь от известного VPN провайдера.
|
Вы, как индивидуум, скорее всего, никому не нужны. Подумайте чем вы отличаетесь от известного VPN провайдера.
|
||||||
VPN провайдер предоставляет _простую_ и _доступную_ услугу по обходу блокировок для масс.
|
VPN-провайдер предоставляет _простую_ и _доступную_ услугу по обходу блокировок для масс.
|
||||||
Этот факт делает его первоочередной целью блокировки. РКН направит уведомление, после отказа сотрудничать
|
Этот факт делает его первоочередной целью блокировки. РКН направит уведомление, после отказа сотрудничать
|
||||||
заблокирует VPN. Предоплаченная сумма пропадет.
|
заблокирует VPN. Предоплаченная сумма пропадет.
|
||||||
У регуляторов нет и никогда не будет ресурсов для тотальной проверки каждого сервера в сети.
|
У регуляторов нет и никогда не будет ресурсов для тотальной проверки каждого сервера в сети.
|
||||||
Возможен китайский расклад, при котором DPI выявляет vpn протоколы и динамически банит IP серверов,
|
Возможен китайский расклад, при котором DPI выявляет VPN-протоколы и динамически банит IP серверов,
|
||||||
предоставляющих нелицензированный VPN. Но имея знания, голову, вы всегда можете обфусцировать
|
предоставляющих нелицензированный VPN. Но имея знания, голову, вы всегда можете обфусцировать
|
||||||
vpn трафик или применить другие типы VPN, более устойчивые к анализу на DPI или просто менее широкоизвестные,
|
VPN трафик или применить другие типы VPN, более устойчивые к анализу на DPI, или просто менее широкоизвестные,
|
||||||
а следовательно с меньшей вероятностью обнаруживаемые регулятором.
|
а следовательно с меньшей вероятностью обнаруживаемые регулятором.
|
||||||
У вас есть свобода делать на вашем VPS все что вы захотите, адаптируясь к новым условиям.
|
У вас есть свобода делать на вашем VPS все что вы захотите, адаптируясь к новым условиям.
|
||||||
Да, это потребует знаний. Вам выбирать учиться и держать ситуацию под контролем, когда вам ничего запретить
|
Да, это потребует знаний. Вам выбирать учиться и держать ситуацию под контролем, когда вам ничего запретить
|
||||||
не могут, или покориться системе.
|
не могут, или покориться системе.
|
||||||
|
|
||||||
VPS можно прибрести в множестве мест. Существуют специализированные на поиске предложений VPS порталы.\
|
VPS можно приобрести в множестве мест. Существуют специализированные на поиске предложений VPS порталы.\
|
||||||
Например, [вот этот](https://vps.today).
|
Например, [вот этот](https://vps.today).
|
||||||
Для персонального VPN сервера обычно достаточно самой минимальной конфигурации, но с безлимитным трафиком или
|
Для персонального VPN сервера обычно достаточно самой минимальной конфигурации, но с безлимитным трафиком или
|
||||||
с большим лимитом по трафику (терабайты). Важен и тип VPS. Openvz подойдет для openvpn, но
|
с большим лимитом по трафику (терабайты). Важен и тип VPS. OpenVZ подойдёт для OpenVPN, но
|
||||||
вы не поднимете на нем wireguard, ipsec, то есть все, что требует kernel mode.
|
вы не поднимете на нем WireGuard, IPsec, то есть все, что требует kernel mode.
|
||||||
Для kernel mode требуется тип виртуализации, предполагающий запуск полноценного экземпляра ОС linux
|
Для kernel mode требуется тип виртуализации, предполагающий запуск полноценного экземпляра ОС linux
|
||||||
вместе с ядром. Подойдут kvm, xen, hyper-v, vmware.
|
вместе с ядром. Подойдут KVM, Xen, Hyper-V, VMware.
|
||||||
|
|
||||||
По цене можно найти предложения, которые будут дешевле готовой VPN услуги, но при этом вы сам хозяин в своей лавке
|
По цене можно найти предложения, которые будут дешевле готовой VPN услуги, но при этом вы сам хозяин в своей лавке
|
||||||
и не рискуете попасть под бан регулятора, разве что "заодно" под ковровую бомбардировку с баном миллионов IP.
|
и не рискуете попасть под бан регулятора, разве что «заодно» — под ковровую бомбардировку с баном миллионов IP.
|
||||||
Кроме того, если вам совсем все кажется сложным, прочитанное вызывает ступор и вы точно знаете, что ничего
|
Кроме того, если вам совсем все кажется сложным, прочитанное вызывает ступор и вы точно знаете, что ничего
|
||||||
из описанного сделать не сможете, то вы сможете хотя бы использовать динамическое перенаправление портов ssh
|
из описанного сделать не сможете, то вы сможете хотя бы использовать динамическое перенаправление портов SSH
|
||||||
для получения шифрованного socks proxy и прописать его в броузер. Знания linux не нужны совсем.
|
для получения шифрованного SOCKS-прокси и прописать его в браузер. Знания linux не нужны совсем.
|
||||||
Это вариант наименее напряжный для чайников, хотя и не самый удобный в использовании.
|
Это вариант наименее напряжный для чайников, хотя и не самый удобный в использовании.
|
||||||
|
|
||||||
## Поддержать разработчика
|
## Поддержать разработчика
|
||||||
|
|
||||||
<img src=https://cdn-icons-png.flaticon.com/16/14446/14446252.png alt="USDT" style="vertical-align: middle;"/> USDT
|
USDT `0x3d52Ce15B7Be734c53fc9526ECbAB8267b63d66E`
|
||||||
```
|
|
||||||
0x3d52Ce15B7Be734c53fc9526ECbAB8267b63d66E
|
|
||||||
```
|
|
||||||
|
|
||||||
<img src=https://cdn-icons-png.flaticon.com/16/5968/5968260.png alt="USDT" style="vertical-align: middle;"/> BTC
|
BTC `bc1qhqew3mrvp47uk2vevt5sctp7p2x9m7m5kkchve`
|
||||||
```
|
|
||||||
bc1qhqew3mrvp47uk2vevt5sctp7p2x9m7m5kkchve
|
ETH `0x3d52Ce15B7Be734c53fc9526ECbAB8267b63d66E`
|
||||||
```
|
|
||||||
|
BIN
files/fake/discord-ip-discovery-with-port.bin
Normal file
BIN
files/fake/discord-ip-discovery-with-port.bin
Normal file
Binary file not shown.
BIN
files/fake/discord-ip-discovery-without-port.bin
Normal file
BIN
files/fake/discord-ip-discovery-without-port.bin
Normal file
Binary file not shown.
BIN
files/fake/isakmp_initiator_request.bin
Normal file
BIN
files/fake/isakmp_initiator_request.bin
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
files/fake/stun.bin
Normal file
BIN
files/fake/stun.bin
Normal file
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
74
init.d/custom.d.examples.linux/50-nfqws-ipset
Normal file
74
init.d/custom.d.examples.linux/50-nfqws-ipset
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
# this custom script demonstrates how to launch extra nfqws instance limited by ipset. ipv4 only.
|
||||||
|
|
||||||
|
# can override in config :
|
||||||
|
NFQWS_OPT_DESYNC_NFQWS_MY1="${NFQWS_OPT_DESYNC_NFQWS_MY1:---dpi-desync=fake --dpi-desync-repeats=6 --dpi-desync-any-protocol}"
|
||||||
|
NFQWS_MY1_PORTS=${NFQWS_MY1_PORTS:-6000-6009}
|
||||||
|
NFQWS_MY1_SUBNETS="${NFQWS_MY1_SUBNETS:-34.0.48.0/21 34.0.56.0/23 34.0.59.0/24 34.0.60.0/24 34.0.62.0/23}"
|
||||||
|
|
||||||
|
alloc_dnum DNUM_NFQWS_MY1
|
||||||
|
alloc_qnum QNUM_NFQWS_MY1
|
||||||
|
NFQWS_MY1_SET_NAME=my1nfqws4
|
||||||
|
|
||||||
|
zapret_custom_daemons()
|
||||||
|
{
|
||||||
|
# $1 - 1 - run, 0 - stop
|
||||||
|
|
||||||
|
local opt="--qnum=$QNUM_NFQWS_MY1 $NFQWS_OPT_DESYNC_NFQWS_MY1"
|
||||||
|
do_nfqws $1 $DNUM_NFQWS_MY1 "$opt"
|
||||||
|
}
|
||||||
|
|
||||||
|
zapret_custom_firewall()
|
||||||
|
{
|
||||||
|
# $1 - 1 - run, 0 - stop
|
||||||
|
|
||||||
|
local f
|
||||||
|
local first_packets_only="$ipt_connbytes 1:3"
|
||||||
|
local NFQWS_MY1_PORTS_IPT=$(replace_char - : $NFQWS_MY1_PORTS)
|
||||||
|
local dest_set="-m set --match-set $NFQWS_MY1_SET_NAME dst"
|
||||||
|
local subnet
|
||||||
|
|
||||||
|
local DISABLE_IPV6=1
|
||||||
|
|
||||||
|
[ "$1" = 1 ] && {
|
||||||
|
ipset create $NFQWS_MY1_SET_NAME hash:net hashsize 8192 maxelem 4096 2>/dev/null
|
||||||
|
ipset flush $NFQWS_MY1_SET_NAME
|
||||||
|
for subnet in $NFQWS_MY1_SUBNETS; do
|
||||||
|
echo add $NFQWS_MY1_SET_NAME $subnet
|
||||||
|
done | ipset -! restore
|
||||||
|
}
|
||||||
|
|
||||||
|
f="-p udp -m multiport --dports $NFQWS_MY1_PORTS_IPT"
|
||||||
|
fw_nfqws_post $1 "$f $first_packets_only $dest_set" "" $QNUM_NFQWS_MY1
|
||||||
|
|
||||||
|
[ "$1" = 1 ] || {
|
||||||
|
ipset destroy $NFQWS_MY1_SET_NAME 2>/dev/null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
zapret_custom_firewall_nft()
|
||||||
|
{
|
||||||
|
# stop logic is not required
|
||||||
|
|
||||||
|
local f
|
||||||
|
local first_packets_only="$nft_connbytes 1-3"
|
||||||
|
local dest_set="ip daddr @$NFQWS_MY1_SET_NAME"
|
||||||
|
local subnets
|
||||||
|
|
||||||
|
local DISABLE_IPV6=1
|
||||||
|
|
||||||
|
make_comma_list subnets $NFQWS_MY1_SUBNETS
|
||||||
|
nft_create_set $NFQWS_MY1_SET_NAME "type ipv4_addr; size 4096; auto-merge; flags interval;"
|
||||||
|
nft_flush_set $NFQWS_MY1_SET_NAME
|
||||||
|
nft_add_set_element $NFQWS_MY1_SET_NAME "$subnets"
|
||||||
|
|
||||||
|
f="udp dport {$NFQWS_MY1_PORTS}"
|
||||||
|
nft_fw_nfqws_post "$f $first_packets_only $dest_set" "" $QNUM_NFQWS_MY1
|
||||||
|
}
|
||||||
|
|
||||||
|
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_SET_NAME 2>/dev/null
|
||||||
|
}
|
@ -25,15 +25,8 @@ CUSTOM_DIR="$ZAPRET_RW/init.d/openwrt"
|
|||||||
|
|
||||||
TPWS_LOCALHOST4=127.0.0.127
|
TPWS_LOCALHOST4=127.0.0.127
|
||||||
|
|
||||||
# max wait time for the link local ipv6 on the LAN interface
|
|
||||||
LINKLOCAL_WAIT_SEC=5
|
|
||||||
|
|
||||||
IPSET_CR="$ZAPRET_BASE/ipset/create_ipset.sh"
|
IPSET_CR="$ZAPRET_BASE/ipset/create_ipset.sh"
|
||||||
|
|
||||||
IPSET_EXCLUDE="-m set ! --match-set nozapret"
|
|
||||||
IPSET_EXCLUDE6="-m set ! --match-set nozapret6"
|
|
||||||
|
|
||||||
|
|
||||||
# can be multiple ipv6 outgoing interfaces
|
# can be multiple ipv6 outgoing interfaces
|
||||||
# uplink from isp, tunnelbroker, vpn, ...
|
# uplink from isp, tunnelbroker, vpn, ...
|
||||||
# want them all. who knows what's the real one that blocks sites
|
# want them all. who knows what's the real one that blocks sites
|
||||||
|
65
init.d/systemd/nfqws@.service
Normal file
65
init.d/systemd/nfqws@.service
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
# Example systemd service unit for nfqws. Adjust for your installation.
|
||||||
|
|
||||||
|
# WARNING ! This unit requires to compile nfqws using `make systemd`
|
||||||
|
# WARNING ! This makefile target enabled special systemd notify support.
|
||||||
|
|
||||||
|
# PREPARE
|
||||||
|
# install build depends
|
||||||
|
# make -C /opt/zapret systemd
|
||||||
|
# cp nfqws@service /lib/systemd/system
|
||||||
|
# systemctl daemon-reload
|
||||||
|
|
||||||
|
# MANAGE INSTANCE
|
||||||
|
# prepare /etc/zapret/nfqws1.conf with nfqws parameters
|
||||||
|
# systemctl start nfqws@nfqws1
|
||||||
|
# systemctl status nfqws@nfqws1
|
||||||
|
# systemctl restart nfqws@nfqws1
|
||||||
|
# systemctl enable nfqws@nfqws1
|
||||||
|
# systemctl disable nfqws@nfqws1
|
||||||
|
# systemctl stop nfqws@nfqws1
|
||||||
|
|
||||||
|
# DELETE
|
||||||
|
# rm /lib/systemd/system/nfqws@.service
|
||||||
|
# systemctl daemon-reload
|
||||||
|
|
||||||
|
|
||||||
|
[Unit]
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=notify
|
||||||
|
Restart=on-failure
|
||||||
|
|
||||||
|
ExecSearchPath=/opt/zapret/binaries/my
|
||||||
|
ExecStart=nfqws @${CONFIG_DIR}/${INSTANCE}.conf
|
||||||
|
Environment=CONFIG_DIR=/etc/zapret
|
||||||
|
Environment=INSTANCE=%i
|
||||||
|
|
||||||
|
RestrictAddressFamilies=AF_NETLINK AF_UNIX AF_INET6 AF_INET
|
||||||
|
|
||||||
|
LockPersonality=true
|
||||||
|
MemoryDenyWriteExecute=true
|
||||||
|
PrivateDevices=true
|
||||||
|
PrivateMounts=true
|
||||||
|
PrivateTmp=true
|
||||||
|
ProcSubset=pid
|
||||||
|
ProtectClock=true
|
||||||
|
ProtectControlGroups=true
|
||||||
|
ProtectHome=true
|
||||||
|
ProtectHostname=true
|
||||||
|
ProtectKernelLogs=true
|
||||||
|
ProtectKernelModules=true
|
||||||
|
ProtectKernelTunables=true
|
||||||
|
ProtectProc=invisible
|
||||||
|
ProtectSystem=full
|
||||||
|
RemoveIPC=true
|
||||||
|
RestrictNamespaces=true
|
||||||
|
RestrictRealtime=true
|
||||||
|
RestrictSUIDSGID=true
|
||||||
|
SystemCallArchitectures=native
|
||||||
|
SystemCallFilter=@system-service
|
||||||
|
SystemCallFilter=~@resources
|
||||||
|
UMask=0077
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
63
init.d/systemd/tpws@.service
Normal file
63
init.d/systemd/tpws@.service
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
# Example systemd service unit for tpws. Adjust for your installation.
|
||||||
|
|
||||||
|
# WARNING ! This unit requires to compile tpws using `make systemd`
|
||||||
|
# WARNING ! This makefile target enabled special systemd notify support.
|
||||||
|
|
||||||
|
# PREPARE
|
||||||
|
# install build depends
|
||||||
|
# make -C /opt/zapret systemd
|
||||||
|
# cp tpws@service /lib/systemd/system
|
||||||
|
# systemctl daemon-reload
|
||||||
|
|
||||||
|
# MANAGE INSTANCE
|
||||||
|
# prepare /etc/zapret/tpws1.conf with tpws parameters
|
||||||
|
# systemctl start tpws@tpws1
|
||||||
|
# systemctl status tpws@tpws1
|
||||||
|
# systemctl restart tpws@tpws1
|
||||||
|
# systemctl enable tpws@tpws1
|
||||||
|
# systemctl disable tpws@tpws1
|
||||||
|
# systemctl stop tpws@tpws1
|
||||||
|
|
||||||
|
# DELETE
|
||||||
|
# rm /lib/systemd/system/tpws@.service
|
||||||
|
# systemctl daemon-reload
|
||||||
|
|
||||||
|
|
||||||
|
[Unit]
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=notify
|
||||||
|
Restart=on-failure
|
||||||
|
|
||||||
|
ExecSearchPath=/opt/zapret/binaries/my
|
||||||
|
ExecStart=tpws @${CONFIG_DIR}/${INSTANCE}.conf
|
||||||
|
Environment=CONFIG_DIR=/etc/zapret
|
||||||
|
Environment=INSTANCE=%i
|
||||||
|
|
||||||
|
RestrictAddressFamilies=AF_NETLINK AF_UNIX AF_INET6 AF_INET
|
||||||
|
|
||||||
|
LockPersonality=true
|
||||||
|
MemoryDenyWriteExecute=true
|
||||||
|
PrivateDevices=true
|
||||||
|
PrivateMounts=true
|
||||||
|
PrivateTmp=true
|
||||||
|
ProcSubset=pid
|
||||||
|
ProtectClock=true
|
||||||
|
ProtectControlGroups=true
|
||||||
|
ProtectHome=true
|
||||||
|
ProtectHostname=true
|
||||||
|
ProtectKernelLogs=true
|
||||||
|
ProtectKernelModules=true
|
||||||
|
ProtectProc=invisible
|
||||||
|
ProtectSystem=full
|
||||||
|
RemoveIPC=true
|
||||||
|
RestrictNamespaces=true
|
||||||
|
RestrictRealtime=true
|
||||||
|
RestrictSUIDSGID=true
|
||||||
|
SystemCallArchitectures=native
|
||||||
|
SystemCallFilter=@system-service
|
||||||
|
UMask=0077
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
@ -90,13 +90,6 @@ TPWS_WAIT_SOCKS6="$TPWS_WAIT --bind-wait-ip-linklocal=30"
|
|||||||
# first wait for lan to ifup, then wait for bind-wait-ip-linklocal seconds for link local address and bind-wait-ip for any ipv6 as the worst case
|
# first wait for lan to ifup, then wait for bind-wait-ip-linklocal seconds for link local address and bind-wait-ip for any ipv6 as the worst case
|
||||||
TPWS_OPT_BASE6_PRE="--bind-linklocal=prefer $TPWS_WAIT --bind-wait-ip-linklocal=3"
|
TPWS_OPT_BASE6_PRE="--bind-linklocal=prefer $TPWS_WAIT --bind-wait-ip-linklocal=3"
|
||||||
|
|
||||||
# max wait time for the link local ipv6 on the LAN interface
|
|
||||||
LINKLOCAL_WAIT_SEC=5
|
|
||||||
|
|
||||||
IPSET_EXCLUDE="-m set ! --match-set nozapret"
|
|
||||||
IPSET_EXCLUDE6="-m set ! --match-set nozapret6"
|
|
||||||
|
|
||||||
|
|
||||||
dnat6_target()
|
dnat6_target()
|
||||||
{
|
{
|
||||||
_dnat6_target "$@"
|
_dnat6_target "$@"
|
||||||
|
@ -74,8 +74,7 @@ case "$1" in
|
|||||||
;;
|
;;
|
||||||
|
|
||||||
*)
|
*)
|
||||||
N=/etc/init.d/$NAME
|
echo "Usage: $SCRIPT {start|stop|restart|start-fw|stop-fw|restart-fw|start-daemons|stop-daemons|restart-daemons|reload-ifsets|list-ifsets|list-table}" >&2
|
||||||
echo "Usage: $N {start|stop|restart|start-fw|stop-fw|restart-fw|start-daemons|stop-daemons|restart-daemons|reload-ifsets|list-ifsets|list-table}" >&2
|
|
||||||
exit 1
|
exit 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
@ -69,8 +69,15 @@ check_bins()
|
|||||||
echo found architecture "\"$arch\""
|
echo found architecture "\"$arch\""
|
||||||
elif [ -f "$EXEDIR/Makefile" ] && exists make; then
|
elif [ -f "$EXEDIR/Makefile" ] && exists make; then
|
||||||
echo trying to compile
|
echo trying to compile
|
||||||
[ "$SYSTEM" = "macos" ] && make_target=mac
|
case $SYSTEM in
|
||||||
make -C "$EXEDIR" $make_target || {
|
macos)
|
||||||
|
make_target=mac
|
||||||
|
;;
|
||||||
|
systemd)
|
||||||
|
make_target=systemd
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
CFLAGS="-march=native ${CFLAGS}" make -C "$EXEDIR" $make_target || {
|
||||||
echo could not compile
|
echo could not compile
|
||||||
make -C "$EXEDIR" clean
|
make -C "$EXEDIR" clean
|
||||||
exitp 8
|
exitp 8
|
||||||
@ -292,7 +299,7 @@ ask_config_tmpdir()
|
|||||||
echo default tmpfs has size of 50% RAM
|
echo default tmpfs has size of 50% RAM
|
||||||
echo "RAM : $(get_ram_mb) Mb"
|
echo "RAM : $(get_ram_mb) Mb"
|
||||||
echo "DISK : $(get_free_space_mb) Mb"
|
echo "DISK : $(get_free_space_mb) Mb"
|
||||||
echo select temp file location
|
echo select temp file location
|
||||||
[ -z "$TMPDIR" ] && TMPDIR=/tmp
|
[ -z "$TMPDIR" ] && TMPDIR=/tmp
|
||||||
ask_list TMPDIR "/tmp $EXEDIR/tmp" && {
|
ask_list TMPDIR "/tmp $EXEDIR/tmp" && {
|
||||||
[ "$TMPDIR" = "/tmp" ] && TMPDIR=
|
[ "$TMPDIR" = "/tmp" ] && TMPDIR=
|
||||||
@ -388,7 +395,7 @@ copy_openwrt()
|
|||||||
local ARCH="$(get_bin_arch)"
|
local ARCH="$(get_bin_arch)"
|
||||||
local BINDIR="$1/binaries/$ARCH"
|
local BINDIR="$1/binaries/$ARCH"
|
||||||
local file
|
local file
|
||||||
|
|
||||||
[ -d "$2" ] || mkdir -p "$2"
|
[ -d "$2" ] || mkdir -p "$2"
|
||||||
|
|
||||||
mkdir "$2/tpws" "$2/nfq" "$2/ip2net" "$2/mdig" "$2/binaries" "$2/binaries/$ARCH" "$2/init.d" "$2/tmp" "$2/files"
|
mkdir "$2/tpws" "$2/nfq" "$2/ip2net" "$2/mdig" "$2/binaries" "$2/binaries/$ARCH" "$2/init.d" "$2/tmp" "$2/files"
|
||||||
@ -482,7 +489,7 @@ _restore_settings()
|
|||||||
[ -z "$f" -o "$f" = "/" ] && continue
|
[ -z "$f" -o "$f" = "/" ] && continue
|
||||||
|
|
||||||
[ -f "/tmp/zapret-bkp-$i" ] && {
|
[ -f "/tmp/zapret-bkp-$i" ] && {
|
||||||
mv -f "/tmp/zapret-bkp-$i" "$ZAPRET_TARGET/$f" || rm -f "/tmp/zapret-bkp-$i"
|
mv -f "/tmp/zapret-bkp-$i" "$ZAPRET_TARGET/$f" || rm -f "/tmp/zapret-bkp-$i"
|
||||||
}
|
}
|
||||||
[ -d "/tmp/zapret-bkp-$i" ] && {
|
[ -d "/tmp/zapret-bkp-$i" ] && {
|
||||||
[ -d "$ZAPRET_TARGET/$f" ] && rm -r "$ZAPRET_TARGET/$f"
|
[ -d "$ZAPRET_TARGET/$f" ] && rm -r "$ZAPRET_TARGET/$f"
|
||||||
@ -724,7 +731,7 @@ install_linux()
|
|||||||
crontab_del_quiet
|
crontab_del_quiet
|
||||||
# desktop system. more likely up at daytime
|
# desktop system. more likely up at daytime
|
||||||
crontab_add 10 22
|
crontab_add 10 22
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo '!!! WARNING. YOUR SETUP IS INCOMPLETE !!!'
|
echo '!!! WARNING. YOUR SETUP IS INCOMPLETE !!!'
|
||||||
echo you must manually add to auto start : $INIT_SCRIPT_SRC start
|
echo you must manually add to auto start : $INIT_SCRIPT_SRC start
|
||||||
@ -772,7 +779,6 @@ deoffload_openwrt_firewall()
|
|||||||
else
|
else
|
||||||
echo system wide software flow offloading disabled. ok
|
echo system wide software flow offloading disabled. ok
|
||||||
fi
|
fi
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -11,6 +11,8 @@ all: ip2net
|
|||||||
ip2net: $(SRC_FILES)
|
ip2net: $(SRC_FILES)
|
||||||
$(CC) -s $(CFLAGS) -o ip2net $(SRC_FILES) $(LIBS) $(LDFLAGS)
|
$(CC) -s $(CFLAGS) -o ip2net $(SRC_FILES) $(LIBS) $(LDFLAGS)
|
||||||
|
|
||||||
|
systemd: ip2net
|
||||||
|
|
||||||
android: ip2net
|
android: ip2net
|
||||||
|
|
||||||
bsd: $(SRC_FILES)
|
bsd: $(SRC_FILES)
|
||||||
|
@ -225,6 +225,28 @@ static void exithelp(void)
|
|||||||
#define PRINT_VER printf("self-built version %s %s\n\n", __DATE__, __TIME__)
|
#define PRINT_VER printf("self-built version %s %s\n\n", __DATE__, __TIME__)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
enum opt_indices {
|
||||||
|
IDX_HELP,
|
||||||
|
IDX_H,
|
||||||
|
IDX_4,
|
||||||
|
IDX_6,
|
||||||
|
IDX_PREFIX_LENGTH,
|
||||||
|
IDX_V4_THRESHOLD,
|
||||||
|
IDX_V6_THRESHOLD,
|
||||||
|
IDX_LAST,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct option long_options[] = {
|
||||||
|
[IDX_HELP] = {"help", no_argument, 0, 0},
|
||||||
|
[IDX_H] = {"h", no_argument, 0, 0},
|
||||||
|
[IDX_4] = {"4", no_argument, 0, 0},
|
||||||
|
[IDX_6] = {"6", no_argument, 0, 0},
|
||||||
|
[IDX_PREFIX_LENGTH] = {"prefix-length", required_argument, 0, 0},
|
||||||
|
[IDX_V4_THRESHOLD] = {"v4-threshold", required_argument, 0, 0},
|
||||||
|
[IDX_V6_THRESHOLD] = {"v6-threshold", required_argument, 0, 0},
|
||||||
|
[IDX_LAST] = {NULL, 0, NULL, 0},
|
||||||
|
};
|
||||||
|
|
||||||
static void parse_params(int argc, char *argv[])
|
static void parse_params(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int option_index = 0;
|
int option_index = 0;
|
||||||
@ -236,33 +258,23 @@ static void parse_params(int argc, char *argv[])
|
|||||||
params.pctdiv = DEFAULT_PCTDIV;
|
params.pctdiv = DEFAULT_PCTDIV;
|
||||||
params.v6_threshold = DEFAULT_V6_THRESHOLD;
|
params.v6_threshold = DEFAULT_V6_THRESHOLD;
|
||||||
|
|
||||||
const struct option long_options[] = {
|
|
||||||
{ "help",no_argument,0,0 },// optidx=0
|
|
||||||
{ "h",no_argument,0,0 },// optidx=1
|
|
||||||
{ "4",no_argument,0,0 },// optidx=2
|
|
||||||
{ "6",no_argument,0,0 },// optidx=3
|
|
||||||
{ "prefix-length",required_argument,0,0 },// optidx=4
|
|
||||||
{ "v4-threshold",required_argument,0,0 },// optidx=5
|
|
||||||
{ "v6-threshold",required_argument,0,0 },// optidx=6
|
|
||||||
{ NULL,0,NULL,0 }
|
|
||||||
};
|
|
||||||
while ((v = getopt_long_only(argc, argv, "", long_options, &option_index)) != -1)
|
while ((v = getopt_long_only(argc, argv, "", long_options, &option_index)) != -1)
|
||||||
{
|
{
|
||||||
if (v) exithelp();
|
if (v) exithelp();
|
||||||
switch (option_index)
|
switch (option_index)
|
||||||
{
|
{
|
||||||
case 0:
|
case IDX_HELP:
|
||||||
case 1:
|
case IDX_H:
|
||||||
PRINT_VER;
|
PRINT_VER;
|
||||||
exithelp();
|
exithelp();
|
||||||
break;
|
break;
|
||||||
case 2:
|
case IDX_4:
|
||||||
params.ipv6 = false;
|
params.ipv6 = false;
|
||||||
break;
|
break;
|
||||||
case 3:
|
case IDX_6:
|
||||||
params.ipv6 = true;
|
params.ipv6 = true;
|
||||||
break;
|
break;
|
||||||
case 4:
|
case IDX_PREFIX_LENGTH:
|
||||||
i = sscanf(optarg,"%u-%u",&plen1,&plen2);
|
i = sscanf(optarg,"%u-%u",&plen1,&plen2);
|
||||||
if (i == 1) plen2 = plen1;
|
if (i == 1) plen2 = plen1;
|
||||||
if (i<=0 || plen2<plen1 || !plen1 || !plen2)
|
if (i<=0 || plen2<plen1 || !plen1 || !plen2)
|
||||||
@ -271,7 +283,7 @@ static void parse_params(int argc, char *argv[])
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 5:
|
case IDX_V4_THRESHOLD:
|
||||||
i = sscanf(optarg, "%u/%u", ¶ms.pctmult, ¶ms.pctdiv);
|
i = sscanf(optarg, "%u/%u", ¶ms.pctmult, ¶ms.pctdiv);
|
||||||
if (i!=2 || params.pctdiv<2 || params.pctmult<1 || params.pctmult>=params.pctdiv)
|
if (i!=2 || params.pctdiv<2 || params.pctmult<1 || params.pctmult>=params.pctdiv)
|
||||||
{
|
{
|
||||||
@ -279,7 +291,7 @@ static void parse_params(int argc, char *argv[])
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 6:
|
case IDX_V6_THRESHOLD:
|
||||||
i = sscanf(optarg, "%u", ¶ms.v6_threshold);
|
i = sscanf(optarg, "%u", ¶ms.v6_threshold);
|
||||||
if (i != 1 || params.v6_threshold<1)
|
if (i != 1 || params.v6_threshold<1)
|
||||||
{
|
{
|
||||||
|
@ -7,7 +7,7 @@ get_antifilter()
|
|||||||
[ "$DISABLE_IPV4" != "1" ] && {
|
[ "$DISABLE_IPV4" != "1" ] && {
|
||||||
curl --fail --max-time 150 --connect-timeout 20 --max-filesize 41943040 -k -L "$1" | cut_local >"$ZIPLISTTMP" &&
|
curl --fail --max-time 150 --connect-timeout 20 --max-filesize 41943040 -k -L "$1" | cut_local >"$ZIPLISTTMP" &&
|
||||||
{
|
{
|
||||||
dlsize=$(LANG=C wc -c "$ZIPLISTTMP" | xargs | cut -f 1 -d ' ')
|
dlsize=$(LC_ALL=C LANG=C wc -c "$ZIPLISTTMP" | xargs | cut -f 1 -d ' ')
|
||||||
if [ $dlsize -lt 102400 ]; then
|
if [ $dlsize -lt 102400 ]; then
|
||||||
echo list file is too small. can be bad.
|
echo list file is too small. can be bad.
|
||||||
exit 2
|
exit 2
|
||||||
|
28
ipset/def.sh
28
ipset/def.sh
@ -5,7 +5,7 @@ ZAPRET_RW=${ZAPRET_RW:-"$ZAPRET_BASE"}
|
|||||||
ZAPRET_CONFIG=${ZAPRET_CONFIG:-"$ZAPRET_RW/config"}
|
ZAPRET_CONFIG=${ZAPRET_CONFIG:-"$ZAPRET_RW/config"}
|
||||||
IPSET_RW_DIR="$ZAPRET_RW/ipset"
|
IPSET_RW_DIR="$ZAPRET_RW/ipset"
|
||||||
|
|
||||||
. "$ZAPRET_CONFIG"
|
[ -f "$ZAPRET_CONFIG" ] && . "$ZAPRET_CONFIG"
|
||||||
. "$ZAPRET_BASE/common/base.sh"
|
. "$ZAPRET_BASE/common/base.sh"
|
||||||
|
|
||||||
[ -z "$TMPDIR" ] && TMPDIR=/tmp
|
[ -z "$TMPDIR" ] && TMPDIR=/tmp
|
||||||
@ -141,6 +141,18 @@ zzsize()
|
|||||||
printf 0
|
printf 0
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
zzcopy()
|
||||||
|
{
|
||||||
|
local is_gz=0
|
||||||
|
zztest "$1" && is_gz=1
|
||||||
|
if [ "$GZIP_LISTS" = 1 -a $is_gz = 1 ]; then
|
||||||
|
cp "$1" "${2}.gz"
|
||||||
|
elif [ "$GZIP_LISTS" != 1 -a $is_gz != 1 ]; then
|
||||||
|
cp "$1" "$2"
|
||||||
|
else
|
||||||
|
zzcat "$1" | zz "$2"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
digger()
|
digger()
|
||||||
{
|
{
|
||||||
@ -255,3 +267,17 @@ getipban()
|
|||||||
_get_ipban
|
_get_ipban
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hup_zapret_daemons()
|
||||||
|
{
|
||||||
|
echo forcing zapret daemons to reload their hostlist
|
||||||
|
if exists killall; then
|
||||||
|
killall -HUP tpws nfqws dvtws 2>/dev/null
|
||||||
|
elif exists pkill; then
|
||||||
|
pkill -HUP ^tpws$
|
||||||
|
pkill -HUP ^nfqws$
|
||||||
|
pkill -HUP ^dvtws$
|
||||||
|
else
|
||||||
|
echo no mass killer available ! cant HUP zapret daemons
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
@ -21,7 +21,7 @@ curl -H "Accept-Encoding: gzip" -k --fail --max-time 600 --connect-timeout 5 --r
|
|||||||
exit 2
|
exit 2
|
||||||
}
|
}
|
||||||
|
|
||||||
dlsize=$(LANG=C wc -c "$ZDOM" | xargs | cut -f 1 -d ' ')
|
dlsize=$(LC_ALL=C LANG=C wc -c "$ZDOM" | xargs | cut -f 1 -d ' ')
|
||||||
if test $dlsize -lt 102400; then
|
if test $dlsize -lt 102400; then
|
||||||
echo list file is too small. can be bad.
|
echo list file is too small. can be bad.
|
||||||
exit 2
|
exit 2
|
||||||
@ -31,4 +31,6 @@ sort -u "$ZDOM" | zz "$ZHOSTLIST"
|
|||||||
|
|
||||||
rm -f "$ZDOM"
|
rm -f "$ZDOM"
|
||||||
|
|
||||||
|
hup_zapret_daemons
|
||||||
|
|
||||||
exit 0
|
exit 0
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
IPSET_DIR="$(dirname "$0")"
|
IPSET_DIR="$(dirname "$0")"
|
||||||
IPSET_DIR="$(cd "$IPSET_DIR"; pwd)"
|
IPSET_DIR="$(cd "$IPSET_DIR"; pwd)"
|
||||||
|
|
||||||
. "$IPSET_DIR/../config"
|
[ -f "$IPSET_DIR/../config" ] && . "$IPSET_DIR/../config"
|
||||||
|
|
||||||
[ -z "$GETLIST" ] && GETLIST=get_ipban.sh
|
[ -z "$GETLIST" ] && GETLIST=get_ipban.sh
|
||||||
[ -x "$IPSET_DIR/$GETLIST" ] && exec "$IPSET_DIR/$GETLIST"
|
[ -x "$IPSET_DIR/$GETLIST" ] && exec "$IPSET_DIR/$GETLIST"
|
||||||
|
@ -5,9 +5,9 @@ IPSET_DIR="$(cd "$IPSET_DIR"; pwd)"
|
|||||||
|
|
||||||
. "$IPSET_DIR/def.sh"
|
. "$IPSET_DIR/def.sh"
|
||||||
|
|
||||||
ZREESTR="$TMPDIR/zapret.txt"
|
ZREESTR="$TMPDIR/zapret.txt.gz"
|
||||||
IPB="$TMPDIR/ipb.txt"
|
IPB="$TMPDIR/ipb.txt"
|
||||||
ZURL_REESTR=https://raw.githubusercontent.com/zapret-info/z-i/master/dump.csv
|
ZURL_REESTR=https://raw.githubusercontent.com/zapret-info/z-i/master/dump.csv.gz
|
||||||
|
|
||||||
dl_checked()
|
dl_checked()
|
||||||
{
|
{
|
||||||
@ -21,7 +21,7 @@ dl_checked()
|
|||||||
echo list download failed : $1
|
echo list download failed : $1
|
||||||
return 2
|
return 2
|
||||||
}
|
}
|
||||||
dlsize=$(LANG=C wc -c "$2" | xargs | cut -f 1 -d ' ')
|
dlsize=$(LC_ALL=C LANG=C wc -c "$2" | xargs | cut -f 1 -d ' ')
|
||||||
if test $dlsize -lt $3; then
|
if test $dlsize -lt $3; then
|
||||||
echo list is too small : $dlsize bytes. can be bad.
|
echo list is too small : $dlsize bytes. can be bad.
|
||||||
return 2
|
return 2
|
||||||
@ -31,11 +31,11 @@ dl_checked()
|
|||||||
|
|
||||||
reestr_list()
|
reestr_list()
|
||||||
{
|
{
|
||||||
LANG=C cut -s -f2 -d';' "$ZREESTR" | LANG=C nice -n 5 sed -Ee 's/^\*\.(.+)$/\1/' -ne 's/^[a-z0-9A-Z._-]+$/&/p' | $AWK '{ print tolower($0) }'
|
LC_ALL=C LANG=C gunzip -c "$ZREESTR" | cut -s -f2 -d';' | LC_ALL=C LANG=C nice -n 5 sed -Ee 's/^\*\.(.+)$/\1/' -ne 's/^[a-z0-9A-Z._-]+$/&/p' | $AWK '{ print tolower($0) }'
|
||||||
}
|
}
|
||||||
reestr_extract_ip()
|
reestr_extract_ip()
|
||||||
{
|
{
|
||||||
LANG=C nice -n 5 $AWK -F ';' '($1 ~ /^([0-9]{1,3}\.){3}[0-9]{1,3}/) && (($2 == "" && $3 == "") || ($1 == $2)) {gsub(/ \| /, RS); print $1}' "$ZREESTR" | LANG=C $AWK '{split($1, a, /\|/); for (i in a) {print a[i]}}'
|
LC_ALL=C LANG=C gunzip -c | nice -n 5 $AWK -F ';' '($1 ~ /^([0-9]{1,3}\.){3}[0-9]{1,3}/) && (($2 == "" && $3 == "") || ($1 == $2)) {gsub(/ \| /, RS); print $1}' | LC_ALL=C LANG=C $AWK '{split($1, a, /\|/); for (i in a) {print a[i]}}'
|
||||||
}
|
}
|
||||||
|
|
||||||
ipban_fin()
|
ipban_fin()
|
||||||
@ -58,6 +58,8 @@ rm -f "$ZREESTR"
|
|||||||
[ "$DISABLE_IPV6" != "1" ] && $AWK '/^([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}($|(\/[0-9]{2,3}$))/' "$IPB" | cut_local6 | ip2net6 | zz "$ZIPLIST_IPBAN6"
|
[ "$DISABLE_IPV6" != "1" ] && $AWK '/^([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}($|(\/[0-9]{2,3}$))/' "$IPB" | cut_local6 | ip2net6 | zz "$ZIPLIST_IPBAN6"
|
||||||
rm -f "$IPB"
|
rm -f "$IPB"
|
||||||
|
|
||||||
|
hup_zapret_daemons
|
||||||
|
|
||||||
ipban_fin
|
ipban_fin
|
||||||
|
|
||||||
exit 0
|
exit 0
|
||||||
|
@ -24,12 +24,12 @@ dl()
|
|||||||
echo list download failed : $1
|
echo list download failed : $1
|
||||||
exit 2
|
exit 2
|
||||||
}
|
}
|
||||||
dlsize=$(LANG=C wc -c "$TMPLIST" | xargs | cut -f 1 -d ' ')
|
dlsize=$(LC_ALL=C LANG=C wc -c "$TMPLIST" | xargs | cut -f 1 -d ' ')
|
||||||
if test $dlsize -lt $3; then
|
if test $dlsize -lt $3; then
|
||||||
echo list is too small : $dlsize bytes. can be bad.
|
echo list is too small : $dlsize bytes. can be bad.
|
||||||
exit 2
|
exit 2
|
||||||
fi
|
fi
|
||||||
zzcat "$TMPLIST" | zz "$2"
|
zzcopy "$TMPLIST" "$2"
|
||||||
rm -f "$TMPLIST"
|
rm -f "$TMPLIST"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,12 +24,12 @@ dl()
|
|||||||
echo list download failed : $1
|
echo list download failed : $1
|
||||||
exit 2
|
exit 2
|
||||||
}
|
}
|
||||||
dlsize=$(LANG=C wc -c "$TMPLIST" | xargs | cut -f 1 -d ' ')
|
dlsize=$(LC_ALL=C LANG=C wc -c "$TMPLIST" | xargs | cut -f 1 -d ' ')
|
||||||
if test $dlsize -lt $3; then
|
if test $dlsize -lt $3; then
|
||||||
echo list is too small : $dlsize bytes. can be bad.
|
echo list is too small : $dlsize bytes. can be bad.
|
||||||
exit 2
|
exit 2
|
||||||
fi
|
fi
|
||||||
zzcat "$TMPLIST" | zz "$2"
|
zzcopy "$TMPLIST" "$2"
|
||||||
rm -f "$TMPLIST"
|
rm -f "$TMPLIST"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,17 +23,19 @@ dl()
|
|||||||
echo list download failed : $1
|
echo list download failed : $1
|
||||||
exit 2
|
exit 2
|
||||||
}
|
}
|
||||||
dlsize=$(LANG=C wc -c "$TMPLIST" | xargs | cut -f 1 -d ' ')
|
dlsize=$(LC_ALL=C LANG=C wc -c "$TMPLIST" | xargs | cut -f 1 -d ' ')
|
||||||
if test $dlsize -lt $3; then
|
if test $dlsize -lt $3; then
|
||||||
echo list is too small : $dlsize bytes. can be bad.
|
echo list is too small : $dlsize bytes. can be bad.
|
||||||
exit 2
|
exit 2
|
||||||
fi
|
fi
|
||||||
zzcat "$TMPLIST" | zz "$2"
|
zzcopy "$TMPLIST" "$2"
|
||||||
rm -f "$TMPLIST"
|
rm -f "$TMPLIST"
|
||||||
}
|
}
|
||||||
|
|
||||||
dl "$URL" "$ZHOSTLIST" 65536 67108864
|
dl "$URL" "$ZHOSTLIST" 65536 67108864
|
||||||
|
|
||||||
|
hup_zapret_daemons
|
||||||
|
|
||||||
[ "$DISABLE_IPV4" != "1" ] && dl "$IPB4" "$ZIPLIST_IPBAN" 8192 1048576
|
[ "$DISABLE_IPV4" != "1" ] && dl "$IPB4" "$ZIPLIST_IPBAN" 8192 1048576
|
||||||
[ "$DISABLE_IPV6" != "1" ] && dl "$IPB6" "$ZIPLIST_IPBAN6" 128 1048576
|
[ "$DISABLE_IPV6" != "1" ] && dl "$IPB6" "$ZIPLIST_IPBAN6" 128 1048576
|
||||||
|
|
||||||
|
@ -5,12 +5,12 @@ IPSET_DIR="$(cd "$IPSET_DIR"; pwd)"
|
|||||||
|
|
||||||
. "$IPSET_DIR/def.sh"
|
. "$IPSET_DIR/def.sh"
|
||||||
|
|
||||||
ZREESTR="$TMPDIR/zapret.txt"
|
ZREESTR="$TMPDIR/zapret.txt.gz"
|
||||||
ZDIG="$TMPDIR/zapret-dig.txt"
|
ZDIG="$TMPDIR/zapret-dig.txt"
|
||||||
IPB="$TMPDIR/ipb.txt"
|
IPB="$TMPDIR/ipb.txt"
|
||||||
ZIPLISTTMP="$TMPDIR/zapret-ip.txt"
|
ZIPLISTTMP="$TMPDIR/zapret-ip.txt"
|
||||||
#ZURL=https://reestr.rublacklist.net/api/current
|
#ZURL=https://reestr.rublacklist.net/api/current
|
||||||
ZURL_REESTR=https://raw.githubusercontent.com/zapret-info/z-i/master/dump.csv
|
ZURL_REESTR=https://raw.githubusercontent.com/zapret-info/z-i/master/dump.csv.gz
|
||||||
|
|
||||||
dl_checked()
|
dl_checked()
|
||||||
{
|
{
|
||||||
@ -24,7 +24,7 @@ dl_checked()
|
|||||||
echo list download failed : $1
|
echo list download failed : $1
|
||||||
return 2
|
return 2
|
||||||
}
|
}
|
||||||
dlsize=$(LANG=C wc -c "$2" | xargs | cut -f 1 -d ' ')
|
dlsize=$(LC_ALL=C LANG=C wc -c "$2" | xargs | cut -f 1 -d ' ')
|
||||||
if test $dlsize -lt $3; then
|
if test $dlsize -lt $3; then
|
||||||
echo list is too small : $dlsize bytes. can be bad.
|
echo list is too small : $dlsize bytes. can be bad.
|
||||||
return 2
|
return 2
|
||||||
@ -34,11 +34,11 @@ dl_checked()
|
|||||||
|
|
||||||
reestr_list()
|
reestr_list()
|
||||||
{
|
{
|
||||||
LANG=C cut -s -f2 -d';' "$ZREESTR" | LANG=C nice -n 5 sed -Ee 's/^\*\.(.+)$/\1/' -ne 's/^[a-z0-9A-Z._-]+$/&/p'
|
LC_ALL=C LANG=C gunzip -c "$ZREESTR" | cut -s -f2 -d';' | LC_ALL=C LANG=C nice -n 5 sed -Ee 's/^\*\.(.+)$/\1/' -ne 's/^[a-z0-9A-Z._-]+$/&/p' | $AWK '{ print tolower($0) }'
|
||||||
}
|
}
|
||||||
reestr_extract_ip()
|
reestr_extract_ip()
|
||||||
{
|
{
|
||||||
LANG=C nice -n 5 $AWK -F ';' '($1 ~ /^([0-9]{1,3}\.){3}[0-9]{1,3}/) && (($2 == "" && $3 == "") || ($1 == $2)) {gsub(/ \| /, RS); print $1}' "$ZREESTR" | LANG=C $AWK '{split($1, a, /\|/); for (i in a) {print a[i]}}'
|
LC_ALL=C LANG=C gunzip -c | nice -n 5 $AWK -F ';' '($1 ~ /^([0-9]{1,3}\.){3}[0-9]{1,3}/) && (($2 == "" && $3 == "") || ($1 == $2)) {gsub(/ \| /, RS); print $1}' | LC_ALL=C LANG=C $AWK '{split($1, a, /\|/); for (i in a) {print a[i]}}'
|
||||||
}
|
}
|
||||||
|
|
||||||
getuser && {
|
getuser && {
|
||||||
|
@ -20,12 +20,12 @@ dl()
|
|||||||
echo list download failed : $1
|
echo list download failed : $1
|
||||||
exit 2
|
exit 2
|
||||||
}
|
}
|
||||||
dlsize=$(LANG=C wc -c "$TMPLIST" | xargs | cut -f 1 -d ' ')
|
dlsize=$(LC_ALL=C LANG=C wc -c "$TMPLIST" | xargs | cut -f 1 -d ' ')
|
||||||
if test $dlsize -lt $3; then
|
if test $dlsize -lt $3; then
|
||||||
echo list is too small : $dlsize bytes. can be bad.
|
echo list is too small : $dlsize bytes. can be bad.
|
||||||
exit 2
|
exit 2
|
||||||
fi
|
fi
|
||||||
zzcat "$TMPLIST" | tr -d '\015' | zz "$2"
|
zzcopy "$TMPLIST" "$2"
|
||||||
rm -f "$TMPLIST"
|
rm -f "$TMPLIST"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,4 +37,6 @@ getipban || FAIL=1
|
|||||||
|
|
||||||
dl "$URL" "$ZHOSTLIST" 32768 4194304
|
dl "$URL" "$ZHOSTLIST" 32768 4194304
|
||||||
|
|
||||||
|
hup_zapret_daemons
|
||||||
|
|
||||||
exit 0
|
exit 0
|
||||||
|
@ -20,13 +20,12 @@ dl()
|
|||||||
echo list download failed : $1
|
echo list download failed : $1
|
||||||
exit 2
|
exit 2
|
||||||
}
|
}
|
||||||
dlsize=$(LANG=C wc -c "$TMPLIST" | xargs | cut -f 1 -d ' ')
|
dlsize=$(LC_ALL=C LANG=C wc -c "$TMPLIST" | xargs | cut -f 1 -d ' ')
|
||||||
if test $dlsize -lt $3; then
|
if test $dlsize -lt $3; then
|
||||||
echo list is too small : $dlsize bytes. can be bad.
|
echo list is too small : $dlsize bytes. can be bad.
|
||||||
exit 2
|
exit 2
|
||||||
fi
|
fi
|
||||||
# remove DOS EOL \r
|
zzcopy "$TMPLIST" "$2"
|
||||||
zzcat "$TMPLIST" | tr -d '\015' | zz "$2"
|
|
||||||
rm -f "$TMPLIST"
|
rm -f "$TMPLIST"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
|
127.0.0.0/8
|
||||||
10.0.0.0/8
|
10.0.0.0/8
|
||||||
172.16.0.0/12
|
172.16.0.0/12
|
||||||
192.168.0.0/16
|
192.168.0.0/16
|
||||||
169.254.0.0/16
|
169.254.0.0/16
|
||||||
|
::1
|
||||||
fc00::/7
|
fc00::/7
|
||||||
fe80::/10
|
fe80::/10
|
||||||
|
@ -12,6 +12,8 @@ all: mdig
|
|||||||
mdig: $(SRC_FILES)
|
mdig: $(SRC_FILES)
|
||||||
$(CC) -s $(CFLAGS) -o mdig $(SRC_FILES) $(LIBS) $(LDFLAGS)
|
$(CC) -s $(CFLAGS) -o mdig $(SRC_FILES) $(LIBS) $(LDFLAGS)
|
||||||
|
|
||||||
|
systemd: mdig
|
||||||
|
|
||||||
android: $(SRC_FILES)
|
android: $(SRC_FILES)
|
||||||
$(CC) -s $(CFLAGS) -o mdig $(SRC_FILES) $(LIBS_ANDROID) $(LDFLAGS)
|
$(CC) -s $(CFLAGS) -o mdig $(SRC_FILES) $(LIBS_ANDROID) $(LDFLAGS)
|
||||||
|
|
||||||
|
57
mdig/mdig.c
57
mdig/mdig.c
@ -467,25 +467,38 @@ static void exithelp(void)
|
|||||||
#define PRINT_VER printf("self-built version %s %s\n\n", __DATE__, __TIME__)
|
#define PRINT_VER printf("self-built version %s %s\n\n", __DATE__, __TIME__)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
enum opt_indices {
|
||||||
|
IDX_HELP,
|
||||||
|
IDX_THREADS,
|
||||||
|
IDX_FAMILY,
|
||||||
|
IDX_VERBOSE,
|
||||||
|
IDX_STATS,
|
||||||
|
IDX_LOG_RESOLVED,
|
||||||
|
IDX_LOG_FAILED,
|
||||||
|
IDX_DNS_MAKE_QUERY,
|
||||||
|
IDX_DNS_PARSE_QUERY,
|
||||||
|
IDX_LAST,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct option long_options[] = {
|
||||||
|
[IDX_HELP] = {"help", no_argument, 0, 0},
|
||||||
|
[IDX_THREADS] = {"threads", 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},
|
||||||
|
[IDX_LOG_RESOLVED] = {"log-resolved", required_argument, 0, 0},
|
||||||
|
[IDX_LOG_FAILED] = {"log-failed", required_argument, 0, 0},
|
||||||
|
[IDX_DNS_MAKE_QUERY] = {"dns-make-query", required_argument, 0, 0},
|
||||||
|
[IDX_DNS_PARSE_QUERY] = {"dns-parse-query", no_argument, 0, 0},
|
||||||
|
[IDX_LAST] = {NULL, 0, NULL, 0},
|
||||||
|
};
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int r, v, option_index = 0;
|
int r, v, option_index = 0;
|
||||||
char fn1[256],fn2[256];
|
char fn1[256],fn2[256];
|
||||||
char dom[256];
|
char dom[256];
|
||||||
|
|
||||||
static const struct option long_options[] = {
|
|
||||||
{"help",no_argument,0,0}, // optidx=0
|
|
||||||
{"threads",required_argument,0,0}, // optidx=1
|
|
||||||
{"family",required_argument,0,0}, // optidx=2
|
|
||||||
{"verbose",no_argument,0,0}, // optidx=3
|
|
||||||
{"stats",required_argument,0,0}, // optidx=4
|
|
||||||
{"log-resolved",required_argument,0,0}, // optidx=5
|
|
||||||
{"log-failed",required_argument,0,0}, // optidx=6
|
|
||||||
{"dns-make-query",required_argument,0,0}, // optidx=7
|
|
||||||
{"dns-parse-query",no_argument,0,0}, // optidx=8
|
|
||||||
{NULL,0,NULL,0}
|
|
||||||
};
|
|
||||||
|
|
||||||
memset(&glob, 0, sizeof(glob));
|
memset(&glob, 0, sizeof(glob));
|
||||||
*fn1 = *fn2 = *dom = 0;
|
*fn1 = *fn2 = *dom = 0;
|
||||||
glob.family = FAMILY4;
|
glob.family = FAMILY4;
|
||||||
@ -495,11 +508,11 @@ int main(int argc, char **argv)
|
|||||||
if (v) exithelp();
|
if (v) exithelp();
|
||||||
switch (option_index)
|
switch (option_index)
|
||||||
{
|
{
|
||||||
case 0: /* help */
|
case IDX_HELP:
|
||||||
PRINT_VER;
|
PRINT_VER;
|
||||||
exithelp();
|
exithelp();
|
||||||
break;
|
break;
|
||||||
case 1: /* threads */
|
case IDX_THREADS:
|
||||||
glob.threads = optarg ? atoi(optarg) : 0;
|
glob.threads = optarg ? atoi(optarg) : 0;
|
||||||
if (glob.threads <= 0 || glob.threads > 100)
|
if (glob.threads <= 0 || glob.threads > 100)
|
||||||
{
|
{
|
||||||
@ -507,7 +520,7 @@ int main(int argc, char **argv)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 2: /* family */
|
case IDX_FAMILY:
|
||||||
if (!strcmp(optarg, "4"))
|
if (!strcmp(optarg, "4"))
|
||||||
glob.family = FAMILY4;
|
glob.family = FAMILY4;
|
||||||
else if (!strcmp(optarg, "6"))
|
else if (!strcmp(optarg, "6"))
|
||||||
@ -520,25 +533,25 @@ int main(int argc, char **argv)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 3: /* verbose */
|
case IDX_VERBOSE:
|
||||||
glob.verbose = '\1';
|
glob.verbose = '\1';
|
||||||
break;
|
break;
|
||||||
case 4: /* stats */
|
case IDX_STATS:
|
||||||
glob.stats_every = optarg ? atoi(optarg) : 0;
|
glob.stats_every = optarg ? atoi(optarg) : 0;
|
||||||
break;
|
break;
|
||||||
case 5: /* log-resolved */
|
case IDX_LOG_RESOLVED:
|
||||||
strncpy(fn1,optarg,sizeof(fn1));
|
strncpy(fn1,optarg,sizeof(fn1));
|
||||||
fn1[sizeof(fn1)-1] = 0;
|
fn1[sizeof(fn1)-1] = 0;
|
||||||
break;
|
break;
|
||||||
case 6: /* log-failed */
|
case IDX_LOG_FAILED:
|
||||||
strncpy(fn2,optarg,sizeof(fn2));
|
strncpy(fn2,optarg,sizeof(fn2));
|
||||||
fn2[sizeof(fn2)-1] = 0;
|
fn2[sizeof(fn2)-1] = 0;
|
||||||
break;
|
break;
|
||||||
case 7: /* dns-make-query */
|
case IDX_DNS_MAKE_QUERY:
|
||||||
strncpy(dom,optarg,sizeof(dom));
|
strncpy(dom,optarg,sizeof(dom));
|
||||||
dom[sizeof(dom)-1] = 0;
|
dom[sizeof(dom)-1] = 0;
|
||||||
break;
|
break;
|
||||||
case 8: /* dns-parse-query */
|
case IDX_DNS_PARSE_QUERY:
|
||||||
return dns_parse_query();
|
return dns_parse_query();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
CC ?= gcc
|
CC ?= gcc
|
||||||
CFLAGS += -std=gnu99 -Os -flto=auto
|
CFLAGS += -std=gnu99 -Os -flto=auto
|
||||||
|
CFLAGS_SYSTEMD = -DUSE_SYSTEMD
|
||||||
CFLAGS_BSD = -Wno-address-of-packed-member
|
CFLAGS_BSD = -Wno-address-of-packed-member
|
||||||
CFLAGS_CYGWIN = -Wno-address-of-packed-member -static
|
CFLAGS_CYGWIN = -Wno-address-of-packed-member -static
|
||||||
LIBS_LINUX = -lnetfilter_queue -lnfnetlink -lz
|
LIBS_LINUX = -lnetfilter_queue -lnfnetlink -lz
|
||||||
|
LIBS_SYSTEMD = -lsystemd
|
||||||
LIBS_BSD = -lz
|
LIBS_BSD = -lz
|
||||||
LIBS_CYGWIN = -lz -Lwindows/windivert -Iwindows -lwlanapi -lole32 -loleaut32
|
LIBS_CYGWIN = -lz -Lwindows/windivert -Iwindows -lwlanapi -lole32 -loleaut32
|
||||||
LIBS_CYGWIN32 = -lwindivert32
|
LIBS_CYGWIN32 = -lwindivert32
|
||||||
@ -16,6 +18,9 @@ all: nfqws
|
|||||||
nfqws: $(SRC_FILES)
|
nfqws: $(SRC_FILES)
|
||||||
$(CC) -s $(CFLAGS) -o nfqws $(SRC_FILES) $(LIBS_LINUX) $(LDFLAGS)
|
$(CC) -s $(CFLAGS) -o nfqws $(SRC_FILES) $(LIBS_LINUX) $(LDFLAGS)
|
||||||
|
|
||||||
|
systemd: $(SRC_FILES)
|
||||||
|
$(CC) -s $(CFLAGS) $(CFLAGS_SYSTEMD) -o nfqws $(SRC_FILES) $(LIBS_LINUX) $(LIBS_SYSTEMD) $(LDFLAGS)
|
||||||
|
|
||||||
android: nfqws
|
android: nfqws
|
||||||
|
|
||||||
bsd: $(SRC_FILES)
|
bsd: $(SRC_FILES)
|
||||||
|
@ -27,11 +27,8 @@ static void connswap(const t_conn *c, t_conn *c2)
|
|||||||
|
|
||||||
void ConntrackClearHostname(t_ctrack *track)
|
void ConntrackClearHostname(t_ctrack *track)
|
||||||
{
|
{
|
||||||
if (track->hostname)
|
free(track->hostname);
|
||||||
{
|
track->hostname = NULL;
|
||||||
free(track->hostname);
|
|
||||||
track->hostname = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
static void ConntrackClearTrack(t_ctrack *track)
|
static void ConntrackClearTrack(t_ctrack *track)
|
||||||
{
|
{
|
||||||
@ -349,11 +346,8 @@ void ConntrackPoolDump(const t_conntrack *p)
|
|||||||
|
|
||||||
void ReasmClear(t_reassemble *reasm)
|
void ReasmClear(t_reassemble *reasm)
|
||||||
{
|
{
|
||||||
if (reasm->packet)
|
free(reasm->packet);
|
||||||
{
|
reasm->packet = NULL;
|
||||||
free(reasm->packet);
|
|
||||||
reasm->packet = NULL;
|
|
||||||
}
|
|
||||||
reasm->size = reasm->size_present = 0;
|
reasm->size = reasm->size_present = 0;
|
||||||
}
|
}
|
||||||
bool ReasmInit(t_reassemble *reasm, size_t size_requested, uint32_t seq_start)
|
bool ReasmInit(t_reassemble *reasm, size_t size_requested, uint32_t seq_start)
|
||||||
|
@ -1747,7 +1747,9 @@ nofix:
|
|||||||
bytes = sendto(sock, data, len, 0, (struct sockaddr*)&dst2, salen);
|
bytes = sendto(sock, data, len, 0, (struct sockaddr*)&dst2, salen);
|
||||||
if (bytes==-1)
|
if (bytes==-1)
|
||||||
{
|
{
|
||||||
DLOG_PERROR("rawsend: sendto");
|
char s[40];
|
||||||
|
snprintf(s,sizeof(s),"rawsend: sendto (%zu)",len);
|
||||||
|
DLOG_PERROR(s);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
521
nfq/desync.c
521
nfq/desync.c
@ -16,66 +16,148 @@ const char *fake_http_request_default = "GET / HTTP/1.1\r\nHost: www.iana.org\r\
|
|||||||
"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8\r\n"
|
"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8\r\n"
|
||||||
"Accept-Encoding: gzip, deflate, br\r\n\r\n";
|
"Accept-Encoding: gzip, deflate, br\r\n\r\n";
|
||||||
|
|
||||||
// random : +11 size 32
|
// SNI - www.microsoft.com
|
||||||
// random : +44 size 32
|
const uint8_t fake_tls_clienthello_default[680] = {
|
||||||
// sni : gatech.edu +125 size 11
|
0x16, 0x03, 0x01, 0x02, 0xa3, 0x01, 0x00, 0x02, 0x9f, 0x03, 0x03, 0x41,
|
||||||
const uint8_t fake_tls_clienthello_default[648] = {
|
0x88, 0x82, 0x2d, 0x4f, 0xfd, 0x81, 0x48, 0x9e, 0xe7, 0x90, 0x65, 0x1f,
|
||||||
0x16,0x03,0x01,0x02,0x83,0x01,0x00,0x02,0x7f,0x03,0x03,0x98,0xfb,0x69,0x1d,0x31,
|
0xba, 0x05, 0x7b, 0xff, 0xa7, 0x5a, 0xf9, 0x5b, 0x8a, 0x8f, 0x45, 0x8b,
|
||||||
0x66,0xc4,0xd8,0x07,0x25,0x2b,0x74,0x47,0x01,0x44,0x09,0x08,0xcf,0x13,0x67,0xe0,
|
0x41, 0xf0, 0x3d, 0x1b, 0xdd, 0xe3, 0xf8, 0x20, 0x9b, 0x23, 0xa5, 0xd2,
|
||||||
0x46,0x19,0x1f,0xcb,0xee,0xe6,0x8e,0x33,0xb9,0x91,0xa0,0x20,0xf2,0xed,0x56,0x73,
|
0x21, 0x1e, 0x9f, 0xe7, 0x85, 0x6c, 0xfc, 0x61, 0x80, 0x3a, 0x3f, 0xba,
|
||||||
0xa4,0x0a,0xce,0xa6,0xad,0xd2,0xfd,0x71,0xb8,0xb9,0xfd,0x06,0x0e,0xdd,0xf0,0x57,
|
0xb9, 0x60, 0xba, 0xb3, 0x0e, 0x98, 0x27, 0x6c, 0xf7, 0x38, 0x28, 0x65,
|
||||||
0x37,0x7d,0x96,0xb5,0x80,0x6e,0x54,0xe2,0x15,0xce,0x5f,0xff,0x00,0x22,0x13,0x01,
|
0x80, 0x5d, 0x40, 0x38, 0x00, 0x22, 0x13, 0x01, 0x13, 0x03, 0x13, 0x02,
|
||||||
0x13,0x03,0x13,0x02,0xc0,0x2b,0xc0,0x2f,0xcc,0xa9,0xcc,0xa8,0xc0,0x2c,0xc0,0x30,
|
0xc0, 0x2b, 0xc0, 0x2f, 0xcc, 0xa9, 0xcc, 0xa8, 0xc0, 0x2c, 0xc0, 0x30,
|
||||||
0xc0,0x0a,0xc0,0x09,0xc0,0x13,0xc0,0x14,0x00,0x9c,0x00,0x9d,0x00,0x2f,0x00,0x35,
|
0xc0, 0x0a, 0xc0, 0x09, 0xc0, 0x13, 0xc0, 0x14, 0x00, 0x9c, 0x00, 0x9d,
|
||||||
0x01,0x00,0x02,0x14,0x00,0x00,0x00,0x0f,0x00,0x0d,0x00,0x00,0x0a,0x67,0x61,0x74,
|
0x00, 0x2f, 0x00, 0x35, 0x01, 0x00, 0x02, 0x34, 0x00, 0x00, 0x00, 0x16,
|
||||||
0x65,0x63,0x68,0x2e,0x65,0x64,0x75,0x00,0x17,0x00,0x00,0xff,0x01,0x00,0x01,0x00,
|
0x00, 0x14, 0x00, 0x00, 0x11, 0x77, 0x77, 0x77, 0x2e, 0x6d, 0x69, 0x63,
|
||||||
0x00,0x0a,0x00,0x0e,0x00,0x0c,0x00,0x1d,0x00,0x17,0x00,0x18,0x00,0x19,0x01,0x00,
|
0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x00, 0x17,
|
||||||
0x01,0x01,0x00,0x0b,0x00,0x02,0x01,0x00,0x00,0x10,0x00,0x0e,0x00,0x0c,0x02,0x68,
|
0x00, 0x00, 0xff, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0a, 0x00, 0x0e, 0x00,
|
||||||
0x32,0x08,0x68,0x74,0x74,0x70,0x2f,0x31,0x2e,0x31,0x00,0x05,0x00,0x05,0x01,0x00,
|
0x0c, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19, 0x01, 0x00, 0x01,
|
||||||
0x00,0x00,0x00,0x00,0x22,0x00,0x0a,0x00,0x08,0x04,0x03,0x05,0x03,0x06,0x03,0x02,
|
0x01, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,
|
||||||
0x03,0x00,0x33,0x00,0x6b,0x00,0x69,0x00,0x1d,0x00,0x20,0x72,0xe5,0xce,0x58,0x31,
|
0x10, 0x00, 0x0e, 0x00, 0x0c, 0x02, 0x68, 0x32, 0x08, 0x68, 0x74, 0x74,
|
||||||
0x3c,0x08,0xaa,0x2f,0xa8,0x40,0xe7,0x7a,0xdf,0x46,0x5b,0x63,0x62,0xc7,0xfa,0x49,
|
0x70, 0x2f, 0x31, 0x2e, 0x31, 0x00, 0x05, 0x00, 0x05, 0x01, 0x00, 0x00,
|
||||||
0x18,0xac,0xa1,0x00,0x7c,0x42,0xc5,0x02,0x94,0x5c,0x44,0x00,0x17,0x00,0x41,0x04,
|
0x00, 0x00, 0x00, 0x22, 0x00, 0x0a, 0x00, 0x08, 0x04, 0x03, 0x05, 0x03,
|
||||||
0x8f,0x3e,0x5f,0xd4,0x7f,0x37,0x47,0xd3,0x33,0x70,0x38,0x7f,0x11,0x35,0xc1,0x55,
|
0x06, 0x03, 0x02, 0x03, 0x00, 0x12, 0x00, 0x00, 0x00, 0x33, 0x00, 0x6b,
|
||||||
0x8a,0x6c,0xc7,0x5a,0xd4,0xf7,0x31,0xbb,0x9e,0xee,0xd1,0x8f,0x74,0xdd,0x9b,0xbb,
|
0x00, 0x69, 0x00, 0x1d, 0x00, 0x20, 0x69, 0x15, 0x16, 0x29, 0x6d, 0xad,
|
||||||
0x91,0xa1,0x72,0xda,0xeb,0xf6,0xc6,0x82,0x84,0xfe,0xb7,0xfd,0x7b,0xe1,0x9f,0xd2,
|
0xd5, 0x68, 0x88, 0x27, 0x2f, 0xde, 0xaf, 0xac, 0x3c, 0x4c, 0xa4, 0xe4,
|
||||||
0xb9,0x3e,0x83,0xa6,0x9c,0xac,0x81,0xe2,0x00,0xd5,0x19,0x55,0x91,0xa7,0x0c,0x29,
|
0xd8, 0xc8, 0xfb, 0x41, 0x87, 0xf4, 0x76, 0x4e, 0x0e, 0xfa, 0x64, 0xc4,
|
||||||
0x00,0x2b,0x00,0x05,0x04,0x03,0x04,0x03,0x03,0x00,0x0d,0x00,0x18,0x00,0x16,0x04,
|
0xe9, 0x29, 0x00, 0x17, 0x00, 0x41, 0x04, 0xfe, 0x62, 0xb9, 0x08, 0xc8,
|
||||||
0x03,0x05,0x03,0x06,0x03,0x08,0x04,0x08,0x05,0x08,0x06,0x04,0x01,0x05,0x01,0x06,
|
0xc3, 0x2a, 0xb9, 0x87, 0x37, 0x84, 0x42, 0x6b, 0x5c, 0xcd, 0xc9, 0xca,
|
||||||
0x01,0x02,0x03,0x02,0x01,0x00,0x1c,0x00,0x02,0x40,0x01,0xfe,0x0d,0x01,0x19,0x00,
|
0x62, 0x38, 0xd3, 0xd9, 0x99, 0x8a, 0xc4, 0x2d, 0xc6, 0xd0, 0xa3, 0x60,
|
||||||
0x00,0x01,0x00,0x01,0xfe,0x00,0x20,0xae,0x8b,0x30,0x3c,0xf0,0xa9,0x0d,0xa1,0x69,
|
0xb2, 0x12, 0x54, 0x41, 0x8e, 0x52, 0x5e, 0xe3, 0xab, 0xf9, 0xc2, 0x07,
|
||||||
0x95,0xb8,0xe2,0xed,0x08,0x6d,0x48,0xdf,0xf7,0x5b,0x9d,0x66,0xef,0x15,0x97,0xbc,
|
0x81, 0xdc, 0xf8, 0xf2, 0x6a, 0x91, 0x40, 0x2f, 0xcb, 0xa4, 0xff, 0x6f,
|
||||||
0x2c,0x99,0x91,0x12,0x7a,0x35,0xd0,0x00,0xef,0xb1,0x8d,0xff,0x61,0x57,0x52,0xef,
|
0x24, 0xc7, 0x4d, 0x77, 0x77, 0x2d, 0x6f, 0xe0, 0x77, 0xaa, 0x92, 0x00,
|
||||||
0xd6,0xea,0xbf,0xf3,0x6d,0x78,0x14,0x38,0xff,0xeb,0x58,0xe8,0x9d,0x59,0x4b,0xd5,
|
0x2b, 0x00, 0x05, 0x04, 0x03, 0x04, 0x03, 0x03, 0x00, 0x0d, 0x00, 0x18,
|
||||||
0x9f,0x59,0x12,0xf9,0x03,0x9a,0x20,0x37,0x85,0x77,0xb1,0x4c,0xd8,0xef,0xa6,0xc8,
|
0x00, 0x16, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x08, 0x04, 0x08, 0x05,
|
||||||
0x54,0x8d,0x07,0x27,0x95,0xce,0xd5,0x37,0x4d,0x69,0x18,0xd4,0xfd,0x5e,0xdf,0x64,
|
0x08, 0x06, 0x04, 0x01, 0x05, 0x01, 0x06, 0x01, 0x02, 0x03, 0x02, 0x01,
|
||||||
0xcc,0x10,0x2f,0x7f,0x0e,0xc9,0xfd,0xd4,0xd0,0x18,0x61,0x1b,0x57,0x8f,0x41,0x7f,
|
0x00, 0x2d, 0x00, 0x02, 0x01, 0x01, 0x00, 0x1c, 0x00, 0x02, 0x40, 0x01,
|
||||||
0x6f,0x4f,0x5c,0xad,0x04,0xc6,0x5e,0x74,0x54,0x87,0xba,0x28,0xe6,0x11,0x0b,0x9d,
|
0x00, 0x1b, 0x00, 0x07, 0x06, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0xfe,
|
||||||
0x3f,0x0b,0x6d,0xf4,0x2d,0xfc,0x31,0x4e,0xfd,0x49,0xe7,0x15,0x96,0xaf,0xee,0x9a,
|
0x0d, 0x01, 0x19, 0x00, 0x00, 0x01, 0x00, 0x03, 0x21, 0x00, 0x20, 0x62,
|
||||||
0x48,0x1b,0xae,0x5e,0x7c,0x20,0xbe,0xb4,0xec,0x68,0xb6,0x74,0x22,0xa0,0xec,0xff,
|
0xe8, 0x83, 0xd8, 0x97, 0x05, 0x8a, 0xbe, 0xa1, 0xf2, 0x63, 0x4e, 0xce,
|
||||||
0x19,0x96,0xe4,0x10,0x8f,0x3c,0x91,0x88,0xa1,0xcc,0x78,0xef,0x4e,0x0e,0xe3,0xb6,
|
0x93, 0x84, 0x8e, 0xcf, 0xe7, 0xdd, 0xb2, 0xe4, 0x87, 0x06, 0xac, 0x11,
|
||||||
0x57,0x8c,0x33,0xef,0xaa,0xb0,0x1d,0x45,0x1c,0x02,0x4c,0xe2,0x80,0x30,0xe8,0x48,
|
0x19, 0xbe, 0x0e, 0x71, 0x87, 0xf1, 0xa6, 0x00, 0xef, 0xd8, 0x6b, 0x27,
|
||||||
0x7a,0x09,0x71,0x94,0x7c,0xb6,0x75,0x81,0x1c,0xae,0xe3,0x3f,0xde,0xea,0x2b,0x45,
|
0x5e, 0xc0, 0xa7, 0x5d, 0x42, 0x4e, 0x8c, 0xdc, 0xf3, 0x9f, 0x1c, 0x51,
|
||||||
0xcc,0xe3,0x64,0x09,0xf7,0x60,0x26,0x0c,0x7d,0xad,0x55,0x65,0xb6,0xf5,0x85,0x04,
|
0x62, 0xef, 0xff, 0x5b, 0xed, 0xc8, 0xfd, 0xee, 0x6f, 0xbb, 0x88, 0x9b,
|
||||||
0x64,0x2f,0x97,0xd0,0x6a,0x06,0x36,0xcd,0x25,0xda,0x51,0xab,0xd6,0xf7,0x5e,0xeb,
|
0xb1, 0x30, 0x9c, 0x66, 0x42, 0xab, 0x0f, 0x66, 0x89, 0x18, 0x8b, 0x11,
|
||||||
0xd4,0x03,0x39,0xa4,0xc4,0x2a,0x9c,0x17,0xe8,0xb0,0x9f,0xc0,0xd3,0x8c,0x76,0xdd,
|
0xc1, 0x6d, 0xe7, 0x2a, 0xeb, 0x96, 0x3b, 0x7f, 0x52, 0x78, 0xdb, 0xf8,
|
||||||
0xa1,0x0b,0x76,0x9f,0x23,0xfa,0xed,0xfb,0xd7,0x78,0x0f,0x00,0xf7,0x45,0x03,0x04,
|
0x6d, 0x04, 0xf7, 0x95, 0x1a, 0xa8, 0xf0, 0x64, 0x52, 0x07, 0x39, 0xf0,
|
||||||
0x84,0x66,0x6b,0xec,0xc7,0xed,0xbc,0xe4
|
0xa8, 0x1d, 0x0d, 0x16, 0x36, 0xb7, 0x18, 0x0e, 0xc8, 0x44, 0x27, 0xfe,
|
||||||
|
0xf3, 0x31, 0xf0, 0xde, 0x8c, 0x74, 0xf5, 0xa1, 0xd8, 0x8f, 0x6f, 0x45,
|
||||||
|
0x97, 0x69, 0x79, 0x5e, 0x2e, 0xd4, 0xb0, 0x2c, 0x0c, 0x1a, 0x6f, 0xcc,
|
||||||
|
0xce, 0x90, 0xc7, 0xdd, 0xc6, 0x60, 0x95, 0xf3, 0xc2, 0x19, 0xde, 0x50,
|
||||||
|
0x80, 0xbf, 0xde, 0xf2, 0x25, 0x63, 0x15, 0x26, 0x63, 0x09, 0x1f, 0xc5,
|
||||||
|
0xdf, 0x32, 0xf5, 0xea, 0x9c, 0xd2, 0xff, 0x99, 0x4e, 0x67, 0xa2, 0xe5,
|
||||||
|
0x1a, 0x94, 0x85, 0xe3, 0xdf, 0x36, 0xa5, 0x83, 0x4b, 0x0a, 0x1c, 0xaf,
|
||||||
|
0xd7, 0x48, 0xc9, 0x4b, 0x8a, 0x27, 0xdd, 0x58, 0x7f, 0x95, 0xf2, 0x6b,
|
||||||
|
0xde, 0x2b, 0x12, 0xd3, 0xec, 0x4d, 0x69, 0x37, 0x9c, 0x13, 0x9b, 0x16,
|
||||||
|
0xb0, 0x45, 0x52, 0x38, 0x77, 0x69, 0xef, 0xaa, 0x65, 0x19, 0xbc, 0xc2,
|
||||||
|
0x93, 0x4d, 0xb0, 0x1b, 0x7f, 0x5b, 0x41, 0xff, 0xaf, 0xba, 0x50, 0x51,
|
||||||
|
0xc3, 0xf1, 0x27, 0x09, 0x25, 0xf5, 0x60, 0x90, 0x09, 0xb1, 0xe5, 0xc0,
|
||||||
|
0xc7, 0x42, 0x78, 0x54, 0x3b, 0x23, 0x19, 0x7d, 0x8e, 0x72, 0x13, 0xb4,
|
||||||
|
0xd3, 0xcd, 0x63, 0xb6, 0xc4, 0x4a, 0x28, 0x3d, 0x45, 0x3e, 0x8b, 0xdb,
|
||||||
|
0x84, 0x4f, 0x78, 0x64, 0x30, 0x69, 0xe2, 0x1b
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char * tld[]={"com","org","net","edu","gov","biz"};
|
|
||||||
void randomize_default_tls_payload(uint8_t *p)
|
|
||||||
{
|
|
||||||
fill_random_bytes(p+11,32);
|
|
||||||
fill_random_bytes(p+44,32);
|
|
||||||
fill_random_az(p+125,1);
|
|
||||||
fill_random_az09(p+126,5);
|
|
||||||
memcpy(p+132,tld[random()%(sizeof(tld)/sizeof(*tld))],3);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define PKTDATA_MAXDUMP 32
|
#define PKTDATA_MAXDUMP 32
|
||||||
#define IP_MAXDUMP 80
|
#define IP_MAXDUMP 80
|
||||||
|
|
||||||
|
#define TCP_MAX_REASM 16384
|
||||||
|
#define UDP_MAX_REASM 16384
|
||||||
|
|
||||||
|
static void TLSDebugHandshake(const uint8_t *tls,size_t sz)
|
||||||
|
{
|
||||||
|
if (!params.debug) return;
|
||||||
|
|
||||||
|
if (sz<6) return;
|
||||||
|
|
||||||
|
const uint8_t *ext;
|
||||||
|
size_t len,len2;
|
||||||
|
|
||||||
|
uint16_t v_handshake=pntoh16(tls+4), v, v2;
|
||||||
|
DLOG("TLS handshake version : %s\n",TLSVersionStr(v_handshake));
|
||||||
|
|
||||||
|
if (TLSFindExtInHandshake(tls,sz,43,&ext,&len,false))
|
||||||
|
{
|
||||||
|
if (len)
|
||||||
|
{
|
||||||
|
len2 = ext[0];
|
||||||
|
if (len2<len)
|
||||||
|
{
|
||||||
|
for(ext++,len2&=~1 ; len2 ; len2-=2,ext+=2)
|
||||||
|
{
|
||||||
|
v = pntoh16(ext);
|
||||||
|
DLOG("TLS supported versions ext : %s\n",TLSVersionStr(v));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
DLOG("TLS supported versions ext : not present\n");
|
||||||
|
|
||||||
|
if (TLSFindExtInHandshake(tls,sz,16,&ext,&len,false))
|
||||||
|
{
|
||||||
|
if (len>=2)
|
||||||
|
{
|
||||||
|
len2 = pntoh16(ext);
|
||||||
|
if (len2<=(len-2))
|
||||||
|
{
|
||||||
|
char s[32];
|
||||||
|
for(ext+=2; len2 ;)
|
||||||
|
{
|
||||||
|
v = *ext; ext++; len2--;
|
||||||
|
if (v<=len2)
|
||||||
|
{
|
||||||
|
v2 = v<sizeof(s) ? v : sizeof(s)-1;
|
||||||
|
memcpy(s,ext,v2);
|
||||||
|
s[v2]=0;
|
||||||
|
DLOG("TLS ALPN ext : %s\n",s);
|
||||||
|
len2-=v;
|
||||||
|
ext+=v;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
DLOG("TLS ALPN ext : not present\n");
|
||||||
|
|
||||||
|
DLOG("TLS ECH ext : %s\n",TLSFindExtInHandshake(tls,sz,65037,NULL,NULL,false) ? "present" : "not present");
|
||||||
|
}
|
||||||
|
static void TLSDebug(const uint8_t *tls,size_t sz)
|
||||||
|
{
|
||||||
|
if (!params.debug) return;
|
||||||
|
|
||||||
|
if (sz<11) return;
|
||||||
|
|
||||||
|
DLOG("TLS record layer version : %s\n",TLSVersionStr(pntoh16(tls+1)));
|
||||||
|
|
||||||
|
size_t reclen=TLSRecordLen(tls);
|
||||||
|
if (reclen<sz) sz=reclen; // correct len if it has more data than the first tls record has
|
||||||
|
|
||||||
|
TLSDebugHandshake(tls+5,sz-5);
|
||||||
|
}
|
||||||
|
|
||||||
bool desync_valid_zero_stage(enum dpi_desync_mode mode)
|
bool desync_valid_zero_stage(enum dpi_desync_mode mode)
|
||||||
{
|
{
|
||||||
return mode==DESYNC_SYNACK || mode==DESYNC_SYNDATA;
|
return mode==DESYNC_SYNACK || mode==DESYNC_SYNDATA;
|
||||||
@ -357,17 +439,18 @@ static void auto_hostlist_failed(struct desync_profile *dp, const char *hostname
|
|||||||
{
|
{
|
||||||
DLOG("auto hostlist (profile %d) : adding %s to %s\n", dp->n, hostname, dp->hostlist_auto->filename);
|
DLOG("auto hostlist (profile %d) : adding %s to %s\n", dp->n, hostname, dp->hostlist_auto->filename);
|
||||||
HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : client %s : proto %s : adding to %s", hostname, dp->n, client_ip_port, l7proto_str(l7proto), dp->hostlist_auto->filename);
|
HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : client %s : proto %s : adding to %s", hostname, dp->n, client_ip_port, l7proto_str(l7proto), dp->hostlist_auto->filename);
|
||||||
if (!StrPoolAddStr(&dp->hostlist_auto->hostlist, hostname))
|
if (!HostlistPoolAddStr(&dp->hostlist_auto->hostlist, hostname, 0))
|
||||||
{
|
{
|
||||||
DLOG_ERR("StrPoolAddStr out of memory\n");
|
DLOG_ERR("StrPoolAddStr out of memory\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!append_to_list_file(dp->hostlist_auto->filename, hostname))
|
if (!append_to_list_file(dp->hostlist_auto->filename, hostname))
|
||||||
{
|
{
|
||||||
DLOG_PERROR("write to auto hostlist:");
|
DLOG_PERROR("write to auto hostlist");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dp->hostlist_auto->mod_time = file_mod_time(dp->hostlist_auto->filename);
|
if (!file_mod_signature(dp->hostlist_auto->filename, &dp->hostlist_auto->mod_sig))
|
||||||
|
DLOG_PERROR("file_mod_signature");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -612,6 +695,61 @@ static uint16_t IP4_IP_ID_FIX(const struct ip *ip)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// fake_mod buffer must at least sizeof(desync_profile->fake_tls)
|
||||||
|
// size does not change
|
||||||
|
// return : true - altered, false - not altered
|
||||||
|
static bool runtime_tls_mod(int fake_n,const struct fake_tls_mod_cache *modcache, const struct fake_tls_mod *tls_mod, const uint8_t *fake_data, size_t fake_data_size, const uint8_t *payload, size_t payload_len, uint8_t *fake_mod)
|
||||||
|
{
|
||||||
|
bool b=false;
|
||||||
|
if (modcache) // it's filled only if it's TLS
|
||||||
|
{
|
||||||
|
if (tls_mod->mod & FAKE_TLS_MOD_PADENCAP)
|
||||||
|
{
|
||||||
|
size_t sz_rec = pntoh16(fake_data+3) + payload_len;
|
||||||
|
size_t sz_handshake = pntoh24(fake_data+6) + payload_len;
|
||||||
|
size_t sz_ext = pntoh16(fake_data+modcache->extlen_offset) + payload_len;
|
||||||
|
size_t sz_pad = pntoh16(fake_data+modcache->padlen_offset) + payload_len;
|
||||||
|
if ((sz_rec & ~0xFFFF) || (sz_handshake & ~0xFFFFFF) || (sz_ext & ~0xFFFF) || (sz_pad & ~0xFFFF))
|
||||||
|
DLOG("fake[%d] cannot apply padencap tls mod. length overflow.\n", fake_n);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memcpy(fake_mod,fake_data,fake_data_size);
|
||||||
|
phton16(fake_mod+3,(uint16_t)sz_rec);
|
||||||
|
phton24(fake_mod+6,(uint32_t)sz_handshake);
|
||||||
|
phton16(fake_mod+modcache->extlen_offset,(uint16_t)sz_ext);
|
||||||
|
phton16(fake_mod+modcache->padlen_offset,(uint16_t)sz_pad);
|
||||||
|
b=true;
|
||||||
|
DLOG("fake[%d] applied padencap tls mod. sizes increased by %zu bytes.\n", fake_n, payload_len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (tls_mod->mod & FAKE_TLS_MOD_RND)
|
||||||
|
{
|
||||||
|
if (!b) memcpy(fake_mod,fake_data,fake_data_size);
|
||||||
|
fill_random_bytes(fake_mod+11,32); // random
|
||||||
|
fill_random_bytes(fake_mod+44,fake_mod[43]); // session id
|
||||||
|
b=true;
|
||||||
|
DLOG("fake[%d] applied rnd tls mod\n", fake_n);
|
||||||
|
}
|
||||||
|
if (tls_mod->mod & FAKE_TLS_MOD_DUP_SID)
|
||||||
|
{
|
||||||
|
if (payload_len<44)
|
||||||
|
DLOG("fake[%d] cannot apply dupsid tls mod. data payload is too short.\n",fake_n);
|
||||||
|
else if (fake_data[43]!=payload[43])
|
||||||
|
DLOG("fake[%d] cannot apply dupsid tls mod. fake and orig session id length mismatch.\n",fake_n);
|
||||||
|
else if (payload_len<(44+payload[43]))
|
||||||
|
DLOG("fake[%d] cannot apply dupsid tls mod. data payload is not valid.\n",fake_n);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!b) memcpy(fake_mod,fake_data,fake_data_size);
|
||||||
|
memcpy(fake_mod+44,payload+44,fake_mod[43]); // session id
|
||||||
|
b=true;
|
||||||
|
DLOG("fake[%d] applied dupsid tls mod\n", fake_n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint32_t fwmark, const char *ifout, struct dissect *dis)
|
static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint32_t fwmark, const char *ifout, struct dissect *dis)
|
||||||
{
|
{
|
||||||
uint8_t verdict=VERDICT_PASS;
|
uint8_t verdict=VERDICT_PASS;
|
||||||
@ -842,8 +980,8 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
|
|
||||||
if (!(dis->tcp->th_flags & TH_SYN) && dis->len_payload)
|
if (!(dis->tcp->th_flags & TH_SYN) && dis->len_payload)
|
||||||
{
|
{
|
||||||
const uint8_t *fake;
|
struct blob_collection_head *fake;
|
||||||
size_t fake_size;
|
|
||||||
char host[256];
|
char host[256];
|
||||||
bool bHaveHost=false;
|
bool bHaveHost=false;
|
||||||
uint8_t *p, *phost=NULL;
|
uint8_t *p, *phost=NULL;
|
||||||
@ -903,6 +1041,8 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
DLOG(bReqFull ? "packet contains full TLS ClientHello\n" : "packet contains partial TLS ClientHello\n");
|
DLOG(bReqFull ? "packet contains full TLS ClientHello\n" : "packet contains partial TLS ClientHello\n");
|
||||||
l7proto = TLS;
|
l7proto = TLS;
|
||||||
|
|
||||||
|
if (bReqFull) TLSDebug(rdata_payload,rlen_payload);
|
||||||
|
|
||||||
bHaveHost=TLSHelloExtractHost(rdata_payload,rlen_payload,host,sizeof(host),TLS_PARTIALS_ENABLE);
|
bHaveHost=TLSHelloExtractHost(rdata_payload,rlen_payload,host,sizeof(host),TLS_PARTIALS_ENABLE);
|
||||||
|
|
||||||
if (ctrack)
|
if (ctrack)
|
||||||
@ -913,7 +1053,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
!(ctrack->req_seq_finalized && seq_within(ctrack->seq_last, ctrack->req_seq_start, ctrack->req_seq_end)))
|
!(ctrack->req_seq_finalized && seq_within(ctrack->seq_last, ctrack->req_seq_start, ctrack->req_seq_end)))
|
||||||
{
|
{
|
||||||
// do not reconstruct unexpected large payload (they are feeding garbage ?)
|
// do not reconstruct unexpected large payload (they are feeding garbage ?)
|
||||||
if (!reasm_orig_start(ctrack,IPPROTO_TCP,TLSRecordLen(dis->data_payload),16384,dis->data_payload,dis->len_payload))
|
if (!reasm_orig_start(ctrack,IPPROTO_TCP,TLSRecordLen(dis->data_payload),TCP_MAX_REASM,dis->data_payload,dis->len_payload))
|
||||||
{
|
{
|
||||||
reasm_orig_cancel(ctrack);
|
reasm_orig_cancel(ctrack);
|
||||||
return verdict;
|
return verdict;
|
||||||
@ -1144,16 +1284,13 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
switch(l7proto)
|
switch(l7proto)
|
||||||
{
|
{
|
||||||
case HTTP:
|
case HTTP:
|
||||||
fake = dp->fake_http;
|
fake = &dp->fake_http;
|
||||||
fake_size = dp->fake_http_size;
|
|
||||||
break;
|
break;
|
||||||
case TLS:
|
case TLS:
|
||||||
fake = dp->fake_tls;
|
fake = &dp->fake_tls;
|
||||||
fake_size = dp->fake_tls_size;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fake = dp->fake_unknown;
|
fake = &dp->fake_unknown;
|
||||||
fake_size = dp->fake_unknown_size;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (dp->desync_mode==DESYNC_MULTISPLIT || dp->desync_mode==DESYNC_MULTIDISORDER || dp->desync_mode2==DESYNC_MULTISPLIT || dp->desync_mode2==DESYNC_MULTIDISORDER)
|
if (dp->desync_mode==DESYNC_MULTISPLIT || dp->desync_mode==DESYNC_MULTIDISORDER || dp->desync_mode2==DESYNC_MULTISPLIT || dp->desync_mode2==DESYNC_MULTIDISORDER)
|
||||||
@ -1234,13 +1371,8 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
else
|
else
|
||||||
seqovl_pos = 0;
|
seqovl_pos = 0;
|
||||||
|
|
||||||
// we do not need reasm buffer anymore
|
|
||||||
reasm_orig_cancel(ctrack);
|
|
||||||
rdata_payload=NULL;
|
|
||||||
|
|
||||||
uint32_t fooling_orig = FOOL_NONE;
|
uint32_t fooling_orig = FOOL_NONE;
|
||||||
bool bFake = false;
|
bool bFake = false;
|
||||||
pkt1_len = sizeof(pkt1);
|
|
||||||
switch(dp->desync_mode)
|
switch(dp->desync_mode)
|
||||||
{
|
{
|
||||||
case DESYNC_FAKE_KNOWN:
|
case DESYNC_FAKE_KNOWN:
|
||||||
@ -1252,28 +1384,69 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
}
|
}
|
||||||
case DESYNC_FAKE:
|
case DESYNC_FAKE:
|
||||||
if (reasm_offset) break;
|
if (reasm_offset) break;
|
||||||
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps,
|
|
||||||
ttl_fake,IP4_TOS(dis->ip),IP4_IP_ID_FIX(dis->ip),IP6_FLOW(dis->ip6),
|
|
||||||
dp->desync_fooling_mode,dp->desync_badseq_increment,dp->desync_badseq_ack_increment,
|
|
||||||
fake, fake_size, pkt1, &pkt1_len))
|
|
||||||
{
|
{
|
||||||
return verdict;
|
struct blob_item *fake_item;
|
||||||
|
uint8_t *fake_data;
|
||||||
|
uint8_t fake_data_buf[FAKE_MAX_TCP];
|
||||||
|
int n=0;
|
||||||
|
|
||||||
|
ip_id = IP4_IP_ID_FIX(dis->ip);
|
||||||
|
|
||||||
|
LIST_FOREACH(fake_item, fake, next)
|
||||||
|
{
|
||||||
|
n++;
|
||||||
|
switch(l7proto)
|
||||||
|
{
|
||||||
|
case TLS:
|
||||||
|
if ((fake_item->size <= sizeof(fake_data_buf)) &&
|
||||||
|
runtime_tls_mod(n,(struct fake_tls_mod_cache *)fake_item->extra,(struct fake_tls_mod *)fake_item->extra2, fake_item->data, fake_item->size, rdata_payload, rlen_payload, fake_data_buf))
|
||||||
|
{
|
||||||
|
fake_data = fake_data_buf;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
fake_data = fake_item->data;
|
||||||
|
}
|
||||||
|
pkt1_len = sizeof(pkt1);
|
||||||
|
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps,
|
||||||
|
ttl_fake,IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6),
|
||||||
|
dp->desync_fooling_mode,dp->desync_badseq_increment,dp->desync_badseq_ack_increment,
|
||||||
|
fake_data, fake_item->size, pkt1, &pkt1_len))
|
||||||
|
{
|
||||||
|
reasm_orig_cancel(ctrack);
|
||||||
|
return verdict;
|
||||||
|
}
|
||||||
|
DLOG("sending fake[%d] : ", n);
|
||||||
|
hexdump_limited_dlog(fake_data,fake_item->size,PKTDATA_MAXDUMP); DLOG("\n");
|
||||||
|
if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len))
|
||||||
|
{
|
||||||
|
reasm_orig_cancel(ctrack);
|
||||||
|
return verdict;
|
||||||
|
}
|
||||||
|
ip_id=IP4_IP_ID_NEXT(ip_id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
DLOG("sending fake : ");
|
|
||||||
hexdump_limited_dlog(fake,fake_size,PKTDATA_MAXDUMP); DLOG("\n");
|
|
||||||
bFake = true;
|
bFake = true;
|
||||||
break;
|
break;
|
||||||
case DESYNC_RST:
|
case DESYNC_RST:
|
||||||
case DESYNC_RSTACK:
|
case DESYNC_RSTACK:
|
||||||
if (reasm_offset) break;
|
if (reasm_offset) break;
|
||||||
|
pkt1_len = sizeof(pkt1);
|
||||||
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, TH_RST | (dp->desync_mode==DESYNC_RSTACK ? TH_ACK:0), dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps,
|
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, TH_RST | (dp->desync_mode==DESYNC_RSTACK ? TH_ACK:0), dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps,
|
||||||
ttl_fake,IP4_TOS(dis->ip),IP4_IP_ID_FIX(dis->ip),IP6_FLOW(dis->ip6),
|
ttl_fake,IP4_TOS(dis->ip),IP4_IP_ID_FIX(dis->ip),IP6_FLOW(dis->ip6),
|
||||||
dp->desync_fooling_mode,dp->desync_badseq_increment,dp->desync_badseq_ack_increment,
|
dp->desync_fooling_mode,dp->desync_badseq_increment,dp->desync_badseq_ack_increment,
|
||||||
NULL, 0, pkt1, &pkt1_len))
|
NULL, 0, pkt1, &pkt1_len))
|
||||||
{
|
{
|
||||||
|
reasm_orig_cancel(ctrack);
|
||||||
return verdict;
|
return verdict;
|
||||||
}
|
}
|
||||||
DLOG("sending fake RST/RSTACK\n");
|
DLOG("sending fake RST/RSTACK\n");
|
||||||
|
if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len))
|
||||||
|
{
|
||||||
|
reasm_orig_cancel(ctrack);
|
||||||
|
return verdict;
|
||||||
|
}
|
||||||
bFake = true;
|
bFake = true;
|
||||||
break;
|
break;
|
||||||
case DESYNC_HOPBYHOP:
|
case DESYNC_HOPBYHOP:
|
||||||
@ -1284,8 +1457,12 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
(!split_pos && (dp->desync_mode2==DESYNC_FAKEDSPLIT || dp->desync_mode2==DESYNC_FAKEDDISORDER)) ||
|
(!split_pos && (dp->desync_mode2==DESYNC_FAKEDSPLIT || dp->desync_mode2==DESYNC_FAKEDDISORDER)) ||
|
||||||
(!multisplit_count && (dp->desync_mode2==DESYNC_MULTISPLIT || dp->desync_mode2==DESYNC_MULTIDISORDER))))
|
(!multisplit_count && (dp->desync_mode2==DESYNC_MULTISPLIT || dp->desync_mode2==DESYNC_MULTIDISORDER))))
|
||||||
{
|
{
|
||||||
|
reasm_orig_cancel(ctrack);
|
||||||
|
rdata_payload=NULL;
|
||||||
|
|
||||||
|
pkt1_len = sizeof(pkt1);
|
||||||
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps,
|
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps,
|
||||||
ttl_orig,IP4_TOS(dis->ip),IP4_IP_ID_FIX(dis->ip),IP6_FLOW(dis->ip6),
|
ttl_orig,0,0,IP6_FLOW(dis->ip6),
|
||||||
fooling_orig,0,0,
|
fooling_orig,0,0,
|
||||||
dis->data_payload, dis->len_payload, pkt1, &pkt1_len))
|
dis->data_payload, dis->len_payload, pkt1, &pkt1_len))
|
||||||
{
|
{
|
||||||
@ -1302,11 +1479,9 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bFake)
|
// we do not need reasm buffer anymore
|
||||||
{
|
reasm_orig_cancel(ctrack);
|
||||||
if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len))
|
rdata_payload=NULL;
|
||||||
return verdict;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum dpi_desync_mode desync_mode = dp->desync_mode2==DESYNC_NONE ? dp->desync_mode : dp->desync_mode2;
|
enum dpi_desync_mode desync_mode = dp->desync_mode2==DESYNC_NONE ? dp->desync_mode : dp->desync_mode2;
|
||||||
switch(desync_mode)
|
switch(desync_mode)
|
||||||
@ -1327,7 +1502,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
// do seqovl only to the first packet
|
// do seqovl only to the first packet
|
||||||
// otherwise it's prone to race condition on server side
|
// otherwise it's prone to race condition on server side
|
||||||
// what happens first : server pushes socket buffer to process or another packet with seqovl arrives
|
// what happens first : server pushes socket buffer to process or another packet with seqovl arrives
|
||||||
seqovl = i==0 ? seqovl_pos : 0;
|
seqovl = (i==0 && reasm_offset==0) ? seqovl_pos : 0;
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
// only linux return error if MTU is exceeded
|
// only linux return error if MTU is exceeded
|
||||||
for(;;seqovl=0)
|
for(;;seqovl=0)
|
||||||
@ -1573,7 +1748,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , fakeseg, fakeseg_len))
|
if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , fakeseg, fakeseg_len))
|
||||||
return verdict;
|
return verdict;
|
||||||
|
|
||||||
unsigned int seqovl = seqovl_pos;
|
unsigned int seqovl = reasm_offset ? 0 : seqovl_pos;
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
// only linux return error if MTU is exceeded
|
// only linux return error if MTU is exceeded
|
||||||
for(;;seqovl=0)
|
for(;;seqovl=0)
|
||||||
@ -1836,8 +2011,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
|
|
||||||
if (dis->len_payload)
|
if (dis->len_payload)
|
||||||
{
|
{
|
||||||
const uint8_t *fake;
|
struct blob_collection_head *fake;
|
||||||
size_t fake_size;
|
|
||||||
char host[256];
|
char host[256];
|
||||||
bool bHaveHost=false;
|
bool bHaveHost=false;
|
||||||
uint16_t ip_id;
|
uint16_t ip_id;
|
||||||
@ -1878,29 +2052,84 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
return verdict; // cannot be first packet
|
return verdict; // cannot be first packet
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
uint8_t defrag[UDP_MAX_REASM];
|
||||||
uint8_t defrag[16384];
|
|
||||||
size_t hello_offset, hello_len, defrag_len = sizeof(defrag);
|
size_t hello_offset, hello_len, defrag_len = sizeof(defrag);
|
||||||
if (QUICDefragCrypto(pclean,clean_len,defrag,&defrag_len))
|
bool bFull;
|
||||||
|
if (QUICDefragCrypto(pclean,clean_len,defrag,&defrag_len,&bFull))
|
||||||
{
|
{
|
||||||
bool bIsHello = IsQUICCryptoHello(defrag, defrag_len, &hello_offset, &hello_len);
|
if (bFull)
|
||||||
bool bReqFull = bIsHello ? IsTLSHandshakeFull(defrag+hello_offset,hello_len) : false;
|
|
||||||
|
|
||||||
DLOG(bIsHello ? bReqFull ? "packet contains full TLS ClientHello\n" : "packet contains partial TLS ClientHello\n" : "packet does not contain TLS ClientHello\n");
|
|
||||||
|
|
||||||
if (ctrack)
|
|
||||||
{
|
{
|
||||||
if (bIsHello && !bReqFull && ReasmIsEmpty(&ctrack->reasm_orig))
|
DLOG("QUIC initial contains CRYPTO with full fragment coverage\n");
|
||||||
|
|
||||||
|
bool bIsHello = IsQUICCryptoHello(defrag, defrag_len, &hello_offset, &hello_len);
|
||||||
|
bool bReqFull = bIsHello ? IsTLSHandshakeFull(defrag+hello_offset,hello_len) : false;
|
||||||
|
|
||||||
|
DLOG(bIsHello ? bReqFull ? "packet contains full TLS ClientHello\n" : "packet contains partial TLS ClientHello\n" : "packet does not contain TLS ClientHello\n");
|
||||||
|
|
||||||
|
if (bReqFull) TLSDebugHandshake(defrag+hello_offset,hello_len);
|
||||||
|
|
||||||
|
if (ctrack)
|
||||||
{
|
{
|
||||||
// preallocate max buffer to avoid reallocs that cause memory copy
|
if (bIsHello && !bReqFull && ReasmIsEmpty(&ctrack->reasm_orig))
|
||||||
if (!reasm_orig_start(ctrack,IPPROTO_UDP,16384,16384,clean,clean_len))
|
{
|
||||||
|
// preallocate max buffer to avoid reallocs that cause memory copy
|
||||||
|
if (!reasm_orig_start(ctrack,IPPROTO_UDP,UDP_MAX_REASM,UDP_MAX_REASM,clean,clean_len))
|
||||||
|
{
|
||||||
|
reasm_orig_cancel(ctrack);
|
||||||
|
return verdict;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!ReasmIsEmpty(&ctrack->reasm_orig))
|
||||||
|
{
|
||||||
|
verdict_udp_csum_fix(verdict, dis->udp, dis->transport_len, dis->ip, dis->ip6);
|
||||||
|
if (rawpacket_queue(&ctrack->delayed, &dst, desync_fwmark, ifout, dis->data_pkt, dis->len_pkt, dis->len_payload))
|
||||||
|
{
|
||||||
|
DLOG("DELAY desync until reasm is complete (#%u)\n", rawpacket_queue_count(&ctrack->delayed));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DLOG_ERR("rawpacket_queue failed !\n");
|
||||||
|
reasm_orig_cancel(ctrack);
|
||||||
|
return verdict;
|
||||||
|
}
|
||||||
|
if (bReqFull)
|
||||||
|
{
|
||||||
|
replay_queue(&ctrack->delayed);
|
||||||
|
reasm_orig_fin(ctrack);
|
||||||
|
}
|
||||||
|
return ct_new_postnat_fix_udp(ctrack, dis->ip, dis->ip6, dis->udp, &dis->len_pkt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bIsHello)
|
||||||
|
{
|
||||||
|
bHaveHost = TLSHelloExtractHostFromHandshake(defrag + hello_offset, hello_len, host, sizeof(host), TLS_PARTIALS_ENABLE);
|
||||||
|
if (!bHaveHost && dp->desync_skip_nosni)
|
||||||
{
|
{
|
||||||
reasm_orig_cancel(ctrack);
|
reasm_orig_cancel(ctrack);
|
||||||
|
DLOG("not applying tampering to QUIC ClientHello without hostname in the SNI\n");
|
||||||
return verdict;
|
return verdict;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!ReasmIsEmpty(&ctrack->reasm_orig))
|
else
|
||||||
{
|
{
|
||||||
|
if (!quic_reasm_cancel(ctrack,"QUIC initial without ClientHello")) return verdict;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DLOG("QUIC initial contains CRYPTO with partial fragment coverage\n");
|
||||||
|
if (ctrack)
|
||||||
|
{
|
||||||
|
if (ReasmIsEmpty(&ctrack->reasm_orig))
|
||||||
|
{
|
||||||
|
// preallocate max buffer to avoid reallocs that cause memory copy
|
||||||
|
if (!reasm_orig_start(ctrack,IPPROTO_UDP,UDP_MAX_REASM,UDP_MAX_REASM,clean,clean_len))
|
||||||
|
{
|
||||||
|
reasm_orig_cancel(ctrack);
|
||||||
|
return verdict;
|
||||||
|
}
|
||||||
|
}
|
||||||
verdict_udp_csum_fix(verdict, dis->udp, dis->transport_len, dis->ip, dis->ip6);
|
verdict_udp_csum_fix(verdict, dis->udp, dis->transport_len, dis->ip, dis->ip6);
|
||||||
if (rawpacket_queue(&ctrack->delayed, &dst, desync_fwmark, ifout, dis->data_pkt, dis->len_pkt, dis->len_payload))
|
if (rawpacket_queue(&ctrack->delayed, &dst, desync_fwmark, ifout, dis->data_pkt, dis->len_pkt, dis->len_payload))
|
||||||
{
|
{
|
||||||
@ -1912,28 +2141,9 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
reasm_orig_cancel(ctrack);
|
reasm_orig_cancel(ctrack);
|
||||||
return verdict;
|
return verdict;
|
||||||
}
|
}
|
||||||
if (bReqFull)
|
|
||||||
{
|
|
||||||
replay_queue(&ctrack->delayed);
|
|
||||||
reasm_orig_fin(ctrack);
|
|
||||||
}
|
|
||||||
return ct_new_postnat_fix_udp(ctrack, dis->ip, dis->ip6, dis->udp, &dis->len_pkt);
|
return ct_new_postnat_fix_udp(ctrack, dis->ip, dis->ip6, dis->udp, &dis->len_pkt);
|
||||||
}
|
}
|
||||||
}
|
if (!quic_reasm_cancel(ctrack,"QUIC initial fragmented CRYPTO")) return verdict;
|
||||||
|
|
||||||
if (bIsHello)
|
|
||||||
{
|
|
||||||
bHaveHost = TLSHelloExtractHostFromHandshake(defrag + hello_offset, hello_len, host, sizeof(host), TLS_PARTIALS_ENABLE);
|
|
||||||
if (!bHaveHost && dp->desync_skip_nosni)
|
|
||||||
{
|
|
||||||
reasm_orig_cancel(ctrack);
|
|
||||||
DLOG("not applying tampering to QUIC ClientHello without hostname in the SNI\n");
|
|
||||||
return verdict;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!quic_reasm_cancel(ctrack,"QUIC initial without ClientHello")) return verdict;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -1952,7 +2162,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
{
|
{
|
||||||
// received payload without host. it means we are out of the request retransmission phase. stop counter
|
// received payload without host. it means we are out of the request retransmission phase. stop counter
|
||||||
ctrack_stop_retrans_counter(ctrack);
|
ctrack_stop_retrans_counter(ctrack);
|
||||||
|
|
||||||
reasm_orig_cancel(ctrack);
|
reasm_orig_cancel(ctrack);
|
||||||
|
|
||||||
if (IsWireguardHandshakeInitiation(dis->data_payload,dis->len_payload))
|
if (IsWireguardHandshakeInitiation(dis->data_payload,dis->len_payload))
|
||||||
@ -1967,6 +2177,18 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
l7proto = DHT;
|
l7proto = DHT;
|
||||||
if (ctrack && ctrack->l7proto==UNKNOWN) ctrack->l7proto = l7proto;
|
if (ctrack && ctrack->l7proto==UNKNOWN) ctrack->l7proto = l7proto;
|
||||||
}
|
}
|
||||||
|
else if (IsDiscordIpDiscoveryRequest(dis->data_payload,dis->len_payload))
|
||||||
|
{
|
||||||
|
DLOG("packet contains discord voice IP discovery\n");
|
||||||
|
l7proto = DISCORD;
|
||||||
|
if (ctrack && ctrack->l7proto==UNKNOWN) ctrack->l7proto = l7proto;
|
||||||
|
}
|
||||||
|
else if (IsStunMessage(dis->data_payload,dis->len_payload))
|
||||||
|
{
|
||||||
|
DLOG("packet contains STUN message\n");
|
||||||
|
l7proto = STUN;
|
||||||
|
if (ctrack && ctrack->l7proto==UNKNOWN) ctrack->l7proto = l7proto;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!dp->desync_any_proto)
|
if (!dp->desync_any_proto)
|
||||||
@ -2071,20 +2293,22 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
switch(l7proto)
|
switch(l7proto)
|
||||||
{
|
{
|
||||||
case QUIC:
|
case QUIC:
|
||||||
fake = dp->fake_quic;
|
fake = &dp->fake_quic;
|
||||||
fake_size = dp->fake_quic_size;
|
|
||||||
break;
|
break;
|
||||||
case WIREGUARD:
|
case WIREGUARD:
|
||||||
fake = dp->fake_wg;
|
fake = &dp->fake_wg;
|
||||||
fake_size = dp->fake_wg_size;
|
|
||||||
break;
|
break;
|
||||||
case DHT:
|
case DHT:
|
||||||
fake = dp->fake_dht;
|
fake = &dp->fake_dht;
|
||||||
fake_size = dp->fake_dht_size;
|
break;
|
||||||
|
case DISCORD:
|
||||||
|
fake = &dp->fake_discord;
|
||||||
|
break;
|
||||||
|
case STUN:
|
||||||
|
fake = &dp->fake_stun;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fake = dp->fake_unknown_udp;
|
fake = &dp->fake_unknown_udp;
|
||||||
fake_size = dp->fake_unknown_udp_size;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2101,7 +2325,6 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool bFake = false;
|
bool bFake = false;
|
||||||
pkt1_len = sizeof(pkt1);
|
|
||||||
switch(dp->desync_mode)
|
switch(dp->desync_mode)
|
||||||
{
|
{
|
||||||
case DESYNC_FAKE_KNOWN:
|
case DESYNC_FAKE_KNOWN:
|
||||||
@ -2111,12 +2334,30 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DESYNC_FAKE:
|
case DESYNC_FAKE:
|
||||||
if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, ttl_fake, IP4_TOS(dis->ip),IP4_IP_ID_FIX(dis->ip),IP6_FLOW(dis->ip6), dp->desync_fooling_mode, NULL, 0, 0, fake, fake_size, pkt1, &pkt1_len))
|
{
|
||||||
return verdict;
|
struct blob_item *fake_item;
|
||||||
DLOG("sending fake : ");
|
int n=0;
|
||||||
hexdump_limited_dlog(fake,fake_size,PKTDATA_MAXDUMP); DLOG("\n");
|
|
||||||
if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len))
|
ip_id = IP4_IP_ID_FIX(dis->ip);
|
||||||
return verdict;
|
|
||||||
|
LIST_FOREACH(fake_item, fake, next)
|
||||||
|
{
|
||||||
|
n++;
|
||||||
|
pkt1_len = sizeof(pkt1);
|
||||||
|
if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst,
|
||||||
|
ttl_fake, IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6),
|
||||||
|
dp->desync_fooling_mode, NULL, 0, 0,
|
||||||
|
fake_item->data, fake_item->size, pkt1, &pkt1_len))
|
||||||
|
{
|
||||||
|
return verdict;
|
||||||
|
}
|
||||||
|
DLOG("sending fake[%d] : ", n);
|
||||||
|
hexdump_limited_dlog(fake_item->data,fake_item->size,PKTDATA_MAXDUMP); DLOG("\n");
|
||||||
|
if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len))
|
||||||
|
return verdict;
|
||||||
|
ip_id=IP4_IP_ID_NEXT(ip_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
bFake = true;
|
bFake = true;
|
||||||
break;
|
break;
|
||||||
case DESYNC_HOPBYHOP:
|
case DESYNC_HOPBYHOP:
|
||||||
@ -2125,9 +2366,9 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
fooling_orig = (dp->desync_mode==DESYNC_HOPBYHOP) ? FOOL_HOPBYHOP : (dp->desync_mode==DESYNC_DESTOPT) ? FOOL_DESTOPT : FOOL_IPFRAG1;
|
fooling_orig = (dp->desync_mode==DESYNC_HOPBYHOP) ? FOOL_HOPBYHOP : (dp->desync_mode==DESYNC_DESTOPT) ? FOOL_DESTOPT : FOOL_IPFRAG1;
|
||||||
if (dis->ip6 && (dp->desync_mode2==DESYNC_NONE || !desync_valid_second_stage_udp(dp->desync_mode2)))
|
if (dis->ip6 && (dp->desync_mode2==DESYNC_NONE || !desync_valid_second_stage_udp(dp->desync_mode2)))
|
||||||
{
|
{
|
||||||
|
pkt1_len = sizeof(pkt1);
|
||||||
if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst,
|
if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst,
|
||||||
ttl_orig,IP4_TOS(dis->ip),IP4_IP_ID_FIX(dis->ip),IP6_FLOW(dis->ip6),
|
ttl_orig,0,0,IP6_FLOW(dis->ip6),fooling_orig,NULL,0,0,
|
||||||
fooling_orig,NULL,0,0,
|
|
||||||
dis->data_payload, dis->len_payload, pkt1, &pkt1_len))
|
dis->data_payload, dis->len_payload, pkt1, &pkt1_len))
|
||||||
{
|
{
|
||||||
return verdict;
|
return verdict;
|
||||||
|
@ -41,7 +41,7 @@ enum dpi_desync_mode {
|
|||||||
};
|
};
|
||||||
|
|
||||||
extern const char *fake_http_request_default;
|
extern const char *fake_http_request_default;
|
||||||
extern const uint8_t fake_tls_clienthello_default[648];
|
extern const uint8_t fake_tls_clienthello_default[680];
|
||||||
void randomize_default_tls_payload(uint8_t *p);
|
void randomize_default_tls_payload(uint8_t *p);
|
||||||
|
|
||||||
enum dpi_desync_mode desync_mode_from_string(const char *s);
|
enum dpi_desync_mode desync_mode_from_string(const char *s);
|
||||||
|
@ -65,11 +65,8 @@ int z_readfile(FILE *F, char **buf, size_t *size)
|
|||||||
|
|
||||||
zerr:
|
zerr:
|
||||||
inflateEnd(&zs);
|
inflateEnd(&zs);
|
||||||
if (*buf)
|
free(*buf);
|
||||||
{
|
*buf = NULL;
|
||||||
free(*buf);
|
|
||||||
*buf = NULL;
|
|
||||||
}
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <libgen.h>
|
#include <libgen.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
int unique_size_t(size_t *pu, int ct)
|
int unique_size_t(size_t *pu, int ct)
|
||||||
{
|
{
|
||||||
@ -300,6 +301,29 @@ time_t file_mod_time(const char *filename)
|
|||||||
struct stat st;
|
struct stat st;
|
||||||
return stat(filename,&st)==-1 ? 0 : st.st_mtime;
|
return stat(filename,&st)==-1 ? 0 : st.st_mtime;
|
||||||
}
|
}
|
||||||
|
bool file_mod_signature(const char *filename, file_mod_sig *ms)
|
||||||
|
{
|
||||||
|
struct stat st;
|
||||||
|
if (stat(filename,&st)==-1)
|
||||||
|
{
|
||||||
|
FILE_MOD_RESET(ms);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ms->mod_time=st.st_mtime;
|
||||||
|
ms->size=st.st_size;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool file_open_test(const char *filename, int flags)
|
||||||
|
{
|
||||||
|
int fd = open(filename,flags);
|
||||||
|
if (fd>=0)
|
||||||
|
{
|
||||||
|
close(fd);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool pf_in_range(uint16_t port, const port_filter *pf)
|
bool pf_in_range(uint16_t port, const port_filter *pf)
|
||||||
{
|
{
|
||||||
@ -367,6 +391,12 @@ void fill_random_az09(uint8_t *p,size_t sz)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_console_io_buffering(void)
|
||||||
|
{
|
||||||
|
setvbuf(stdout, NULL, _IOLBF, 0);
|
||||||
|
setvbuf(stderr, NULL, _IOLBF, 0);
|
||||||
|
}
|
||||||
|
|
||||||
bool set_env_exedir(const char *argv0)
|
bool set_env_exedir(const char *argv0)
|
||||||
{
|
{
|
||||||
char *s,*d;
|
char *s,*d;
|
||||||
|
@ -51,6 +51,14 @@ static inline void phton16(uint8_t *p, uint16_t v) {
|
|||||||
p[0] = (uint8_t)(v >> 8);
|
p[0] = (uint8_t)(v >> 8);
|
||||||
p[1] = v & 0xFF;
|
p[1] = v & 0xFF;
|
||||||
}
|
}
|
||||||
|
static inline uint32_t pntoh24(const uint8_t *p) {
|
||||||
|
return ((uint32_t)p[0] << 16) | ((uint32_t)p[1] << 8) | (uint32_t)p[2];
|
||||||
|
}
|
||||||
|
static inline void phton24(uint8_t *p, uint32_t v) {
|
||||||
|
p[0] = (uint8_t)(v>>16);
|
||||||
|
p[1] = (uint8_t)(v>>8);
|
||||||
|
p[2] = (uint8_t)v;
|
||||||
|
}
|
||||||
static inline uint32_t pntoh32(const uint8_t *p) {
|
static inline uint32_t pntoh32(const uint8_t *p) {
|
||||||
return ((uint32_t)p[0] << 24) | ((uint32_t)p[1] << 16) | ((uint32_t)p[2] << 8) | (uint32_t)p[3];
|
return ((uint32_t)p[0] << 24) | ((uint32_t)p[1] << 16) | ((uint32_t)p[2] << 8) | (uint32_t)p[3];
|
||||||
}
|
}
|
||||||
@ -60,7 +68,16 @@ void fill_pattern(uint8_t *buf,size_t bufsize,const void *pattern,size_t patsize
|
|||||||
|
|
||||||
int fprint_localtime(FILE *F);
|
int fprint_localtime(FILE *F);
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
time_t mod_time;
|
||||||
|
off_t size;
|
||||||
|
} file_mod_sig;
|
||||||
|
#define FILE_MOD_COMPARE(ms1,ms2) (((ms1)->mod_time==(ms2)->mod_time) && ((ms1)->size==(ms2)->size))
|
||||||
|
#define FILE_MOD_RESET(ms) memset(ms,0,sizeof(file_mod_sig))
|
||||||
|
bool file_mod_signature(const char *filename, file_mod_sig *ms);
|
||||||
time_t file_mod_time(const char *filename);
|
time_t file_mod_time(const char *filename);
|
||||||
|
bool file_open_test(const char *filename, int flags);
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
@ -75,6 +92,7 @@ void fill_random_bytes(uint8_t *p,size_t sz);
|
|||||||
void fill_random_az(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);
|
void fill_random_az09(uint8_t *p,size_t sz);
|
||||||
|
|
||||||
|
void set_console_io_buffering(void);
|
||||||
bool set_env_exedir(const char *argv0);
|
bool set_env_exedir(const char *argv0);
|
||||||
|
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
|
||||||
// inplace tolower() and add to pool
|
// inplace tolower() and add to pool
|
||||||
static bool addpool(strpool **hostlist, char **s, const char *end, int *ct)
|
static bool addpool(hostlist_pool **hostlist, char **s, const char *end, int *ct)
|
||||||
{
|
{
|
||||||
char *p=*s;
|
char *p=*s;
|
||||||
|
|
||||||
@ -17,10 +17,16 @@ static bool addpool(strpool **hostlist, char **s, const char *end, int *ct)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// advance until eol lowering all chars
|
// advance until eol lowering all chars
|
||||||
for (; p<end && *p && *p!='\r' && *p != '\n'; p++) *p=tolower(*p);
|
uint32_t flags = 0;
|
||||||
if (!StrPoolAddStrLen(hostlist, *s, p-*s))
|
if (*p=='^')
|
||||||
{
|
{
|
||||||
StrPoolDestroy(hostlist);
|
p = ++(*s);
|
||||||
|
flags |= HOSTLIST_POOL_FLAG_STRICT_MATCH;
|
||||||
|
}
|
||||||
|
for (; p<end && *p && *p!='\r' && *p != '\n'; p++) *p=tolower(*p);
|
||||||
|
if (!HostlistPoolAddStrLen(hostlist, *s, p-*s, flags))
|
||||||
|
{
|
||||||
|
HostlistPoolDestroy(hostlist);
|
||||||
*hostlist = NULL;
|
*hostlist = NULL;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -32,12 +38,12 @@ static bool addpool(strpool **hostlist, char **s, const char *end, int *ct)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AppendHostlistItem(strpool **hostlist, char *s)
|
bool AppendHostlistItem(hostlist_pool **hostlist, char *s)
|
||||||
{
|
{
|
||||||
return addpool(hostlist,&s,s+strlen(s),NULL);
|
return addpool(hostlist,&s,s+strlen(s),NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AppendHostList(strpool **hostlist, const char *filename)
|
bool AppendHostList(hostlist_pool **hostlist, const char *filename)
|
||||||
{
|
{
|
||||||
char *p, *e, s[256], *zbuf;
|
char *p, *e, s[256], *zbuf;
|
||||||
size_t zsize;
|
size_t zsize;
|
||||||
@ -105,21 +111,22 @@ static bool LoadHostList(struct hostlist_file *hfile)
|
|||||||
{
|
{
|
||||||
if (hfile->filename)
|
if (hfile->filename)
|
||||||
{
|
{
|
||||||
time_t t = file_mod_time(hfile->filename);
|
file_mod_sig fsig;
|
||||||
if (!t)
|
if (!file_mod_signature(hfile->filename, &fsig))
|
||||||
{
|
{
|
||||||
// stat() error
|
// stat() error
|
||||||
|
DLOG_PERROR("file_mod_signature");
|
||||||
DLOG_ERR("cannot access hostlist file '%s'. in-memory content remains unchanged.\n",hfile->filename);
|
DLOG_ERR("cannot access hostlist file '%s'. in-memory content remains unchanged.\n",hfile->filename);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (t==hfile->mod_time) return true; // up to date
|
if (FILE_MOD_COMPARE(&hfile->mod_sig,&fsig)) return true; // up to date
|
||||||
StrPoolDestroy(&hfile->hostlist);
|
HostlistPoolDestroy(&hfile->hostlist);
|
||||||
if (!AppendHostList(&hfile->hostlist, hfile->filename))
|
if (!AppendHostList(&hfile->hostlist, hfile->filename))
|
||||||
{
|
{
|
||||||
StrPoolDestroy(&hfile->hostlist);
|
HostlistPoolDestroy(&hfile->hostlist);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
hfile->mod_time=t;
|
hfile->mod_sig=fsig;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -137,10 +144,10 @@ static bool LoadHostLists(struct hostlist_files_head *list)
|
|||||||
return bres;
|
return bres;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NonEmptyHostlist(strpool **hostlist)
|
bool NonEmptyHostlist(hostlist_pool **hostlist)
|
||||||
{
|
{
|
||||||
// add impossible hostname if the list is empty
|
// add impossible hostname if the list is empty
|
||||||
return *hostlist ? true : StrPoolAddStrLen(hostlist, "@&()", 4);
|
return *hostlist ? true : HostlistPoolAddStrLen(hostlist, "@&()", 4, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void MakeAutolistsNonEmpty()
|
static void MakeAutolistsNonEmpty()
|
||||||
@ -163,19 +170,34 @@ bool LoadAllHostLists()
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static bool SearchHostList(strpool *hostlist, const char *host)
|
static bool SearchHostList(hostlist_pool *hostlist, const char *host)
|
||||||
{
|
{
|
||||||
if (hostlist)
|
if (hostlist)
|
||||||
{
|
{
|
||||||
const char *p = host;
|
const char *p = host;
|
||||||
bool bInHostList;
|
const struct hostlist_pool *hp;
|
||||||
|
bool bHostFull=true;
|
||||||
while (p)
|
while (p)
|
||||||
{
|
{
|
||||||
bInHostList = StrPoolCheckStr(hostlist, p);
|
DLOG("hostlist check for %s : ", p);
|
||||||
DLOG("hostlist check for %s : %s\n", p, bInHostList ? "positive" : "negative");
|
hp = HostlistPoolGetStr(hostlist, p);
|
||||||
if (bInHostList) return true;
|
if (hp)
|
||||||
|
{
|
||||||
|
if ((hp->flags & HOSTLIST_POOL_FLAG_STRICT_MATCH) && !bHostFull)
|
||||||
|
{
|
||||||
|
DLOG("negative : strict_mismatch : %s != %s\n", p, host);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DLOG("positive\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
DLOG("negative\n");
|
||||||
p = strchr(p, '.');
|
p = strchr(p, '.');
|
||||||
if (p) p++;
|
if (p) p++;
|
||||||
|
bHostFull = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -4,12 +4,14 @@
|
|||||||
#include "pools.h"
|
#include "pools.h"
|
||||||
#include "params.h"
|
#include "params.h"
|
||||||
|
|
||||||
bool AppendHostlistItem(strpool **hostlist, char *s);
|
bool AppendHostlistItem(hostlist_pool **hostlist, char *s);
|
||||||
bool AppendHostList(strpool **hostlist, const char *filename);
|
bool AppendHostList(hostlist_pool **hostlist, const char *filename);
|
||||||
bool LoadAllHostLists();
|
bool LoadAllHostLists();
|
||||||
bool NonEmptyHostlist(strpool **hostlist);
|
bool NonEmptyHostlist(hostlist_pool **hostlist);
|
||||||
// return : true = apply fooling, false = do not apply
|
// return : true = apply fooling, false = do not apply
|
||||||
bool HostlistCheck(const struct desync_profile *dp,const char *host, bool *excluded, bool bSkipReloadCheck);
|
bool HostlistCheck(const struct desync_profile *dp,const char *host, bool *excluded, bool bSkipReloadCheck);
|
||||||
struct hostlist_file *RegisterHostlist(struct desync_profile *dp, bool bExclude, const char *filename);
|
struct hostlist_file *RegisterHostlist(struct desync_profile *dp, bool bExclude, const char *filename);
|
||||||
bool HostlistsReloadCheckForProfile(const struct desync_profile *dp);
|
bool HostlistsReloadCheckForProfile(const struct desync_profile *dp);
|
||||||
void HostlistsDebug();
|
void HostlistsDebug();
|
||||||
|
|
||||||
|
#define ResetAllHostlistsModTime() hostlist_files_reset_modtime(¶ms.hostlists)
|
||||||
|
@ -126,21 +126,22 @@ static bool LoadIpset(struct ipset_file *hfile)
|
|||||||
{
|
{
|
||||||
if (hfile->filename)
|
if (hfile->filename)
|
||||||
{
|
{
|
||||||
time_t t = file_mod_time(hfile->filename);
|
file_mod_sig fsig;
|
||||||
if (!t)
|
if (!file_mod_signature(hfile->filename, &fsig))
|
||||||
{
|
{
|
||||||
// stat() error
|
// stat() error
|
||||||
|
DLOG_PERROR("file_mod_signature");
|
||||||
DLOG_ERR("cannot access ipset file '%s'. in-memory content remains unchanged.\n",hfile->filename);
|
DLOG_ERR("cannot access ipset file '%s'. in-memory content remains unchanged.\n",hfile->filename);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (t==hfile->mod_time) return true; // up to date
|
if (FILE_MOD_COMPARE(&hfile->mod_sig,&fsig)) return true; // up to date
|
||||||
ipsetDestroy(&hfile->ipset);
|
ipsetDestroy(&hfile->ipset);
|
||||||
if (!AppendIpset(&hfile->ipset, hfile->filename))
|
if (!AppendIpset(&hfile->ipset, hfile->filename))
|
||||||
{
|
{
|
||||||
ipsetDestroy(&hfile->ipset);
|
ipsetDestroy(&hfile->ipset);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
hfile->mod_time=t;
|
hfile->mod_sig=fsig;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -10,3 +10,5 @@ bool IpsetCheck(const struct desync_profile *dp, const struct in_addr *ipv4, con
|
|||||||
struct ipset_file *RegisterIpset(struct desync_profile *dp, bool bExclude, const char *filename);
|
struct ipset_file *RegisterIpset(struct desync_profile *dp, bool bExclude, const char *filename);
|
||||||
void IpsetsDebug();
|
void IpsetsDebug();
|
||||||
bool AppendIpsetItem(ipset *ips, char *ip);
|
bool AppendIpsetItem(ipset *ips, char *ip);
|
||||||
|
|
||||||
|
#define ResetAllIpsetModTime() ipset_files_reset_modtime(¶ms.ipsets)
|
||||||
|
891
nfq/nfqws.c
891
nfq/nfqws.c
File diff suppressed because it is too large
Load Diff
55
nfq/params.c
55
nfq/params.c
@ -65,6 +65,7 @@ static int DLOG_VA(const char *format, int syslog_priority, bool condup, va_list
|
|||||||
{
|
{
|
||||||
va_copy(args2,args);
|
va_copy(args2,args);
|
||||||
DLOG_CON(format,syslog_priority,args2);
|
DLOG_CON(format,syslog_priority,args2);
|
||||||
|
va_end(args2);
|
||||||
}
|
}
|
||||||
if (params.debug)
|
if (params.debug)
|
||||||
{
|
{
|
||||||
@ -184,18 +185,7 @@ void dp_init(struct desync_profile *dp)
|
|||||||
dp->desync_ipfrag_pos_udp = IPFRAG_UDP_DEFAULT;
|
dp->desync_ipfrag_pos_udp = IPFRAG_UDP_DEFAULT;
|
||||||
dp->desync_ipfrag_pos_tcp = IPFRAG_TCP_DEFAULT;
|
dp->desync_ipfrag_pos_tcp = IPFRAG_TCP_DEFAULT;
|
||||||
dp->desync_repeats = 1;
|
dp->desync_repeats = 1;
|
||||||
dp->fake_tls_size = sizeof(fake_tls_clienthello_default);
|
|
||||||
memcpy(dp->fake_tls,fake_tls_clienthello_default,dp->fake_tls_size);
|
|
||||||
randomize_default_tls_payload(dp->fake_tls);
|
|
||||||
dp->fake_http_size = strlen(fake_http_request_default);
|
|
||||||
memcpy(dp->fake_http,fake_http_request_default,dp->fake_http_size);
|
|
||||||
dp->fake_quic_size = 620; // must be 601+ for TSPU hack
|
|
||||||
dp->fake_quic[0] = 0x40; // russian TSPU QUIC short header fake
|
|
||||||
dp->fake_wg_size = 64;
|
|
||||||
dp->fake_dht_size = 64;
|
|
||||||
dp->fake_unknown_size = 256;
|
|
||||||
dp->fake_syndata_size = 16;
|
dp->fake_syndata_size = 16;
|
||||||
dp->fake_unknown_udp_size = 64;
|
|
||||||
dp->wscale=-1; // default - dont change scale factor (client)
|
dp->wscale=-1; // default - dont change scale factor (client)
|
||||||
dp->desync_ttl6 = 0xFF; // unused
|
dp->desync_ttl6 = 0xFF; // unused
|
||||||
dp->desync_badseq_increment = BADSEQ_INCREMENT_DEFAULT;
|
dp->desync_badseq_increment = BADSEQ_INCREMENT_DEFAULT;
|
||||||
@ -207,11 +197,50 @@ void dp_init(struct desync_profile *dp)
|
|||||||
dp->hostlist_auto_retrans_threshold = HOSTLIST_AUTO_RETRANS_THRESHOLD_DEFAULT;
|
dp->hostlist_auto_retrans_threshold = HOSTLIST_AUTO_RETRANS_THRESHOLD_DEFAULT;
|
||||||
dp->filter_ipv4 = dp->filter_ipv6 = true;
|
dp->filter_ipv4 = dp->filter_ipv6 = true;
|
||||||
}
|
}
|
||||||
|
bool dp_fake_defaults(struct desync_profile *dp)
|
||||||
|
{
|
||||||
|
struct blob_item *item;
|
||||||
|
if (blob_collection_empty(&dp->fake_http))
|
||||||
|
if (!blob_collection_add_blob(&dp->fake_http,fake_http_request_default,strlen(fake_http_request_default),0))
|
||||||
|
return false;
|
||||||
|
if (blob_collection_empty(&dp->fake_tls))
|
||||||
|
{
|
||||||
|
if (!(item=blob_collection_add_blob(&dp->fake_tls,fake_tls_clienthello_default,sizeof(fake_tls_clienthello_default),4+sizeof(((struct fake_tls_mod*)0)->sni))))
|
||||||
|
return false;
|
||||||
|
if (!(item->extra2 = malloc(sizeof(struct fake_tls_mod))))
|
||||||
|
return false;
|
||||||
|
*(struct fake_tls_mod*)item->extra2 = dp->tls_mod_last;
|
||||||
|
}
|
||||||
|
if (blob_collection_empty(&dp->fake_unknown))
|
||||||
|
{
|
||||||
|
if (!(item=blob_collection_add_blob(&dp->fake_unknown,NULL,256,0)))
|
||||||
|
return false;
|
||||||
|
memset(item->data,0,item->size);
|
||||||
|
}
|
||||||
|
if (blob_collection_empty(&dp->fake_quic))
|
||||||
|
{
|
||||||
|
if (!(item=blob_collection_add_blob(&dp->fake_quic,NULL,620,0)))
|
||||||
|
return false;
|
||||||
|
memset(item->data,0,item->size);
|
||||||
|
item->data[0] = 0x40;
|
||||||
|
}
|
||||||
|
struct blob_collection_head **fake,*fakes_z64[] = {&dp->fake_wg, &dp->fake_dht, &dp->fake_discord, &dp->fake_stun, &dp->fake_unknown_udp,NULL};
|
||||||
|
for(fake=fakes_z64;*fake;fake++)
|
||||||
|
{
|
||||||
|
if (blob_collection_empty(*fake))
|
||||||
|
{
|
||||||
|
if (!(item=blob_collection_add_blob(*fake,NULL,64,0)))
|
||||||
|
return false;
|
||||||
|
memset(item->data,0,item->size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
struct desync_profile_list *dp_list_add(struct desync_profile_list_head *head)
|
struct desync_profile_list *dp_list_add(struct desync_profile_list_head *head)
|
||||||
{
|
{
|
||||||
struct desync_profile_list *entry = calloc(1,sizeof(struct desync_profile_list));
|
struct desync_profile_list *entry = calloc(1,sizeof(struct desync_profile_list));
|
||||||
if (!entry) return NULL;
|
if (!entry) return NULL;
|
||||||
|
|
||||||
dp_init(&entry->dp);
|
dp_init(&entry->dp);
|
||||||
|
|
||||||
// add to the tail
|
// add to the tail
|
||||||
@ -235,6 +264,8 @@ static void dp_clear_dynamic(struct desync_profile *dp)
|
|||||||
port_filters_destroy(&dp->pf_tcp);
|
port_filters_destroy(&dp->pf_tcp);
|
||||||
port_filters_destroy(&dp->pf_udp);
|
port_filters_destroy(&dp->pf_udp);
|
||||||
HostFailPoolDestroy(&dp->hostlist_auto_fail_counters);
|
HostFailPoolDestroy(&dp->hostlist_auto_fail_counters);
|
||||||
|
struct blob_collection_head **fake,*fakes[] = {&dp->fake_http, &dp->fake_tls, &dp->fake_unknown, &dp->fake_unknown_udp, &dp->fake_quic, &dp->fake_wg, &dp->fake_dht, &dp->fake_discord, &dp->fake_stun, NULL};
|
||||||
|
for(fake=fakes;*fake;fake++) blob_collection_destroy(*fake);
|
||||||
}
|
}
|
||||||
void dp_clear(struct desync_profile *dp)
|
void dp_clear(struct desync_profile *dp)
|
||||||
{
|
{
|
||||||
|
34
nfq/params.h
34
nfq/params.h
@ -38,8 +38,30 @@
|
|||||||
|
|
||||||
#define MAX_SPLITS 64
|
#define MAX_SPLITS 64
|
||||||
|
|
||||||
|
#define FAKE_TLS_MOD_SAVE_MASK 0x0F
|
||||||
|
#define FAKE_TLS_MOD_SET 0x01
|
||||||
|
#define FAKE_TLS_MOD_CUSTOM_FAKE 0x02
|
||||||
|
#define FAKE_TLS_MOD_RND 0x10
|
||||||
|
#define FAKE_TLS_MOD_DUP_SID 0x20
|
||||||
|
#define FAKE_TLS_MOD_RND_SNI 0x40
|
||||||
|
#define FAKE_TLS_MOD_SNI 0x80
|
||||||
|
#define FAKE_TLS_MOD_PADENCAP 0x100
|
||||||
|
|
||||||
|
#define FAKE_MAX_TCP 1460
|
||||||
|
#define FAKE_MAX_UDP 1472
|
||||||
|
|
||||||
enum log_target { LOG_TARGET_CONSOLE=0, LOG_TARGET_FILE, LOG_TARGET_SYSLOG };
|
enum log_target { LOG_TARGET_CONSOLE=0, LOG_TARGET_FILE, LOG_TARGET_SYSLOG };
|
||||||
|
|
||||||
|
struct fake_tls_mod_cache
|
||||||
|
{
|
||||||
|
size_t extlen_offset, padlen_offset;
|
||||||
|
};
|
||||||
|
struct fake_tls_mod
|
||||||
|
{
|
||||||
|
char sni[64];
|
||||||
|
uint32_t mod;
|
||||||
|
};
|
||||||
|
|
||||||
struct desync_profile
|
struct desync_profile
|
||||||
{
|
{
|
||||||
int n; // number of the profile
|
int n; // number of the profile
|
||||||
@ -66,9 +88,14 @@ struct desync_profile
|
|||||||
autottl desync_autottl, desync_autottl6;
|
autottl desync_autottl, desync_autottl6;
|
||||||
uint32_t desync_fooling_mode;
|
uint32_t desync_fooling_mode;
|
||||||
uint32_t desync_badseq_increment, desync_badseq_ack_increment;
|
uint32_t desync_badseq_increment, desync_badseq_ack_increment;
|
||||||
uint8_t fake_http[1460],fake_tls[1460],fake_unknown[1460],fake_syndata[1460],seqovl_pattern[1460],fsplit_pattern[1460];
|
|
||||||
uint8_t fake_unknown_udp[1472],udplen_pattern[1472],fake_quic[1472],fake_wg[1472],fake_dht[1472];
|
struct blob_collection_head fake_http,fake_tls,fake_unknown,fake_unknown_udp,fake_quic,fake_wg,fake_dht,fake_discord,fake_stun;
|
||||||
size_t fake_http_size,fake_tls_size,fake_quic_size,fake_wg_size,fake_dht_size,fake_unknown_size,fake_syndata_size,fake_unknown_udp_size;
|
uint8_t fake_syndata[FAKE_MAX_TCP],seqovl_pattern[FAKE_MAX_TCP],fsplit_pattern[FAKE_MAX_TCP],udplen_pattern[FAKE_MAX_UDP];
|
||||||
|
size_t fake_syndata_size;
|
||||||
|
|
||||||
|
struct fake_tls_mod tls_mod_last;
|
||||||
|
struct blob_item *tls_fake_last;
|
||||||
|
|
||||||
int udplen_increment;
|
int udplen_increment;
|
||||||
|
|
||||||
bool filter_ipv4,filter_ipv6;
|
bool filter_ipv4,filter_ipv6;
|
||||||
@ -101,6 +128,7 @@ void dp_entry_destroy(struct desync_profile_list *entry);
|
|||||||
void dp_list_destroy(struct desync_profile_list_head *head);
|
void dp_list_destroy(struct desync_profile_list_head *head);
|
||||||
bool dp_list_have_autohostlist(struct desync_profile_list_head *head);
|
bool dp_list_have_autohostlist(struct desync_profile_list_head *head);
|
||||||
void dp_init(struct desync_profile *dp);
|
void dp_init(struct desync_profile *dp);
|
||||||
|
bool dp_fake_defaults(struct desync_profile *dp);
|
||||||
void dp_clear(struct desync_profile *dp);
|
void dp_clear(struct desync_profile *dp);
|
||||||
|
|
||||||
struct params_s
|
struct params_s
|
||||||
|
114
nfq/pools.c
114
nfq/pools.c
@ -31,6 +31,9 @@
|
|||||||
free(elem); \
|
free(elem); \
|
||||||
return false; \
|
return false; \
|
||||||
}
|
}
|
||||||
|
#define ADD_HOSTLIST_POOL(etype, ppool, keystr, keystr_len, flg) \
|
||||||
|
ADD_STR_POOL(etype,ppool,keystr,keystr_len); \
|
||||||
|
elem->flags = flg;
|
||||||
|
|
||||||
|
|
||||||
#undef uthash_nonfatal_oom
|
#undef uthash_nonfatal_oom
|
||||||
@ -42,27 +45,31 @@ static void ut_oom_recover(void *elem)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// for not zero terminated strings
|
// for not zero terminated strings
|
||||||
bool StrPoolAddStrLen(strpool **pp, const char *s, size_t slen)
|
bool HostlistPoolAddStrLen(hostlist_pool **pp, const char *s, size_t slen, uint32_t flags)
|
||||||
{
|
{
|
||||||
ADD_STR_POOL(strpool, pp, s, slen)
|
ADD_HOSTLIST_POOL(hostlist_pool, pp, s, slen, flags)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// for zero terminated strings
|
// for zero terminated strings
|
||||||
bool StrPoolAddStr(strpool **pp, const char *s)
|
bool HostlistPoolAddStr(hostlist_pool **pp, const char *s, uint32_t flags)
|
||||||
{
|
{
|
||||||
return StrPoolAddStrLen(pp, s, strlen(s));
|
return HostlistPoolAddStrLen(pp, s, strlen(s), flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StrPoolCheckStr(strpool *p, const char *s)
|
hostlist_pool *HostlistPoolGetStr(hostlist_pool *p, const char *s)
|
||||||
{
|
{
|
||||||
strpool *elem;
|
hostlist_pool *elem;
|
||||||
HASH_FIND_STR(p, s, elem);
|
HASH_FIND_STR(p, s, elem);
|
||||||
return elem != NULL;
|
return elem;
|
||||||
|
}
|
||||||
|
bool HostlistPoolCheckStr(hostlist_pool *p, const char *s)
|
||||||
|
{
|
||||||
|
return !!HostlistPoolGetStr(p,s);
|
||||||
}
|
}
|
||||||
|
|
||||||
void StrPoolDestroy(strpool **pp)
|
void HostlistPoolDestroy(hostlist_pool **pp)
|
||||||
{
|
{
|
||||||
DESTROY_STR_POOL(strpool, pp)
|
DESTROY_STR_POOL(hostlist_pool, pp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -139,7 +146,7 @@ bool strlist_add(struct str_list_head *head, const char *filename)
|
|||||||
}
|
}
|
||||||
static void strlist_entry_destroy(struct str_list *entry)
|
static void strlist_entry_destroy(struct str_list *entry)
|
||||||
{
|
{
|
||||||
if (entry->str) free(entry->str);
|
free(entry->str);
|
||||||
free(entry);
|
free(entry);
|
||||||
}
|
}
|
||||||
void strlist_destroy(struct str_list_head *head)
|
void strlist_destroy(struct str_list_head *head)
|
||||||
@ -154,7 +161,6 @@ void strlist_destroy(struct str_list_head *head)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct hostlist_file *hostlist_files_add(struct hostlist_files_head *head, const char *filename)
|
struct hostlist_file *hostlist_files_add(struct hostlist_files_head *head, const char *filename)
|
||||||
{
|
{
|
||||||
struct hostlist_file *entry = malloc(sizeof(struct hostlist_file));
|
struct hostlist_file *entry = malloc(sizeof(struct hostlist_file));
|
||||||
@ -170,7 +176,7 @@ struct hostlist_file *hostlist_files_add(struct hostlist_files_head *head, const
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
entry->filename = NULL;
|
entry->filename = NULL;
|
||||||
entry->mod_time = 0;
|
FILE_MOD_RESET(&entry->mod_sig);
|
||||||
entry->hostlist = NULL;
|
entry->hostlist = NULL;
|
||||||
LIST_INSERT_HEAD(head, entry, next);
|
LIST_INSERT_HEAD(head, entry, next);
|
||||||
}
|
}
|
||||||
@ -178,8 +184,8 @@ struct hostlist_file *hostlist_files_add(struct hostlist_files_head *head, const
|
|||||||
}
|
}
|
||||||
static void hostlist_files_entry_destroy(struct hostlist_file *entry)
|
static void hostlist_files_entry_destroy(struct hostlist_file *entry)
|
||||||
{
|
{
|
||||||
if (entry->filename) free(entry->filename);
|
free(entry->filename);
|
||||||
StrPoolDestroy(&entry->hostlist);
|
HostlistPoolDestroy(&entry->hostlist);
|
||||||
free(entry);
|
free(entry);
|
||||||
}
|
}
|
||||||
void hostlist_files_destroy(struct hostlist_files_head *head)
|
void hostlist_files_destroy(struct hostlist_files_head *head)
|
||||||
@ -202,6 +208,13 @@ struct hostlist_file *hostlist_files_search(struct hostlist_files_head *head, co
|
|||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
void hostlist_files_reset_modtime(struct hostlist_files_head *list)
|
||||||
|
{
|
||||||
|
struct hostlist_file *hfile;
|
||||||
|
|
||||||
|
LIST_FOREACH(hfile, list, next)
|
||||||
|
FILE_MOD_RESET(&hfile->mod_sig);
|
||||||
|
}
|
||||||
|
|
||||||
struct hostlist_item *hostlist_collection_add(struct hostlist_collection_head *head, struct hostlist_file *hfile)
|
struct hostlist_item *hostlist_collection_add(struct hostlist_collection_head *head, struct hostlist_file *hfile)
|
||||||
{
|
{
|
||||||
@ -384,7 +397,7 @@ struct ipset_file *ipset_files_add(struct ipset_files_head *head, const char *fi
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
entry->filename = NULL;
|
entry->filename = NULL;
|
||||||
entry->mod_time = 0;
|
FILE_MOD_RESET(&entry->mod_sig);
|
||||||
memset(&entry->ipset,0,sizeof(entry->ipset));
|
memset(&entry->ipset,0,sizeof(entry->ipset));
|
||||||
LIST_INSERT_HEAD(head, entry, next);
|
LIST_INSERT_HEAD(head, entry, next);
|
||||||
}
|
}
|
||||||
@ -392,7 +405,7 @@ struct ipset_file *ipset_files_add(struct ipset_files_head *head, const char *fi
|
|||||||
}
|
}
|
||||||
static void ipset_files_entry_destroy(struct ipset_file *entry)
|
static void ipset_files_entry_destroy(struct ipset_file *entry)
|
||||||
{
|
{
|
||||||
if (entry->filename) free(entry->filename);
|
free(entry->filename);
|
||||||
ipsetDestroy(&entry->ipset);
|
ipsetDestroy(&entry->ipset);
|
||||||
free(entry);
|
free(entry);
|
||||||
}
|
}
|
||||||
@ -416,6 +429,13 @@ struct ipset_file *ipset_files_search(struct ipset_files_head *head, const char
|
|||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
void ipset_files_reset_modtime(struct ipset_files_head *list)
|
||||||
|
{
|
||||||
|
struct ipset_file *hfile;
|
||||||
|
|
||||||
|
LIST_FOREACH(hfile, list, next)
|
||||||
|
FILE_MOD_RESET(&hfile->mod_sig);
|
||||||
|
}
|
||||||
|
|
||||||
struct ipset_item *ipset_collection_add(struct ipset_collection_head *head, struct ipset_file *hfile)
|
struct ipset_item *ipset_collection_add(struct ipset_collection_head *head, struct ipset_file *hfile)
|
||||||
{
|
{
|
||||||
@ -497,3 +517,65 @@ bool port_filters_deny_if_empty(struct port_filters_head *head)
|
|||||||
if (LIST_FIRST(head)) return true;
|
if (LIST_FIRST(head)) return true;
|
||||||
return pf_parse("0",&pf) && port_filter_add(head,&pf);
|
return pf_parse("0",&pf) && port_filter_add(head,&pf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
struct blob_item *blob_collection_add(struct blob_collection_head *head)
|
||||||
|
{
|
||||||
|
struct blob_item *entry = calloc(1,sizeof(struct blob_item));
|
||||||
|
if (entry)
|
||||||
|
{
|
||||||
|
// insert to the end
|
||||||
|
struct blob_item *itemc,*iteml=LIST_FIRST(head);
|
||||||
|
if (iteml)
|
||||||
|
{
|
||||||
|
while ((itemc=LIST_NEXT(iteml,next))) iteml = itemc;
|
||||||
|
LIST_INSERT_AFTER(iteml, entry, next);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LIST_INSERT_HEAD(head, entry, next);
|
||||||
|
}
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
struct blob_item *blob_collection_add_blob(struct blob_collection_head *head, const void *data, size_t size, size_t size_reserve)
|
||||||
|
{
|
||||||
|
struct blob_item *entry = calloc(1,sizeof(struct blob_item));
|
||||||
|
if (!entry) return NULL;
|
||||||
|
if (!(entry->data = malloc(size+size_reserve)))
|
||||||
|
{
|
||||||
|
free(entry);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (data) memcpy(entry->data,data,size);
|
||||||
|
entry->size = size;
|
||||||
|
entry->size_buf = size+size_reserve;
|
||||||
|
|
||||||
|
// insert to the end
|
||||||
|
struct blob_item *itemc,*iteml=LIST_FIRST(head);
|
||||||
|
if (iteml)
|
||||||
|
{
|
||||||
|
while ((itemc=LIST_NEXT(iteml,next))) iteml = itemc;
|
||||||
|
LIST_INSERT_AFTER(iteml, entry, next);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LIST_INSERT_HEAD(head, entry, next);
|
||||||
|
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
void blob_collection_destroy(struct blob_collection_head *head)
|
||||||
|
{
|
||||||
|
struct blob_item *entry;
|
||||||
|
while ((entry = LIST_FIRST(head)))
|
||||||
|
{
|
||||||
|
LIST_REMOVE(entry, next);
|
||||||
|
free(entry->extra);
|
||||||
|
free(entry->extra2);
|
||||||
|
free(entry->data);
|
||||||
|
free(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool blob_collection_empty(const struct blob_collection_head *head)
|
||||||
|
{
|
||||||
|
return !LIST_FIRST(head);
|
||||||
|
}
|
||||||
|
50
nfq/pools.h
50
nfq/pools.h
@ -12,15 +12,18 @@
|
|||||||
#define HASH_FUNCTION HASH_BER
|
#define HASH_FUNCTION HASH_BER
|
||||||
#include "uthash.h"
|
#include "uthash.h"
|
||||||
|
|
||||||
typedef struct strpool {
|
#define HOSTLIST_POOL_FLAG_STRICT_MATCH 1
|
||||||
char *str; /* key */
|
|
||||||
UT_hash_handle hh; /* makes this structure hashable */
|
|
||||||
} strpool;
|
|
||||||
|
|
||||||
void StrPoolDestroy(strpool **pp);
|
typedef struct hostlist_pool {
|
||||||
bool StrPoolAddStr(strpool **pp,const char *s);
|
char *str; /* key */
|
||||||
bool StrPoolAddStrLen(strpool **pp,const char *s,size_t slen);
|
uint32_t flags; /* custom data */
|
||||||
bool StrPoolCheckStr(strpool *p,const char *s);
|
UT_hash_handle hh; /* makes this structure hashable */
|
||||||
|
} hostlist_pool;
|
||||||
|
|
||||||
|
void HostlistPoolDestroy(hostlist_pool **pp);
|
||||||
|
bool HostlistPoolAddStr(hostlist_pool **pp, const char *s, uint32_t flags);
|
||||||
|
bool HostlistPoolAddStrLen(hostlist_pool **pp, const char *s, size_t slen, uint32_t flags);
|
||||||
|
hostlist_pool *HostlistPoolGetStr(hostlist_pool *p, const char *s);
|
||||||
|
|
||||||
struct str_list {
|
struct str_list {
|
||||||
char *str;
|
char *str;
|
||||||
@ -29,10 +32,10 @@ struct str_list {
|
|||||||
LIST_HEAD(str_list_head, str_list);
|
LIST_HEAD(str_list_head, str_list);
|
||||||
|
|
||||||
typedef struct hostfail_pool {
|
typedef struct hostfail_pool {
|
||||||
char *str; /* key */
|
char *str; /* key */
|
||||||
int counter; /* value */
|
int counter; /* value */
|
||||||
time_t expire; /* when to expire record (unixtime) */
|
time_t expire; /* when to expire record (unixtime) */
|
||||||
UT_hash_handle hh; /* makes this structure hashable */
|
UT_hash_handle hh; /* makes this structure hashable */
|
||||||
} hostfail_pool;
|
} hostfail_pool;
|
||||||
|
|
||||||
void HostFailPoolDestroy(hostfail_pool **pp);
|
void HostFailPoolDestroy(hostfail_pool **pp);
|
||||||
@ -50,8 +53,8 @@ void strlist_destroy(struct str_list_head *head);
|
|||||||
|
|
||||||
struct hostlist_file {
|
struct hostlist_file {
|
||||||
char *filename;
|
char *filename;
|
||||||
time_t mod_time;
|
file_mod_sig mod_sig;
|
||||||
strpool *hostlist;
|
hostlist_pool *hostlist;
|
||||||
LIST_ENTRY(hostlist_file) next;
|
LIST_ENTRY(hostlist_file) next;
|
||||||
};
|
};
|
||||||
LIST_HEAD(hostlist_files_head, hostlist_file);
|
LIST_HEAD(hostlist_files_head, hostlist_file);
|
||||||
@ -59,6 +62,7 @@ LIST_HEAD(hostlist_files_head, hostlist_file);
|
|||||||
struct hostlist_file *hostlist_files_add(struct hostlist_files_head *head, const char *filename);
|
struct hostlist_file *hostlist_files_add(struct hostlist_files_head *head, const char *filename);
|
||||||
void hostlist_files_destroy(struct hostlist_files_head *head);
|
void hostlist_files_destroy(struct hostlist_files_head *head);
|
||||||
struct hostlist_file *hostlist_files_search(struct hostlist_files_head *head, const char *filename);
|
struct hostlist_file *hostlist_files_search(struct hostlist_files_head *head, const char *filename);
|
||||||
|
void hostlist_files_reset_modtime(struct hostlist_files_head *list);
|
||||||
|
|
||||||
struct hostlist_item {
|
struct hostlist_item {
|
||||||
struct hostlist_file *hfile;
|
struct hostlist_file *hfile;
|
||||||
@ -111,7 +115,7 @@ void ipsetPrint(ipset *ipset);
|
|||||||
|
|
||||||
struct ipset_file {
|
struct ipset_file {
|
||||||
char *filename;
|
char *filename;
|
||||||
time_t mod_time;
|
file_mod_sig mod_sig;
|
||||||
ipset ipset;
|
ipset ipset;
|
||||||
LIST_ENTRY(ipset_file) next;
|
LIST_ENTRY(ipset_file) next;
|
||||||
};
|
};
|
||||||
@ -120,6 +124,7 @@ LIST_HEAD(ipset_files_head, ipset_file);
|
|||||||
struct ipset_file *ipset_files_add(struct ipset_files_head *head, const char *filename);
|
struct ipset_file *ipset_files_add(struct ipset_files_head *head, const char *filename);
|
||||||
void ipset_files_destroy(struct ipset_files_head *head);
|
void ipset_files_destroy(struct ipset_files_head *head);
|
||||||
struct ipset_file *ipset_files_search(struct ipset_files_head *head, const char *filename);
|
struct ipset_file *ipset_files_search(struct ipset_files_head *head, const char *filename);
|
||||||
|
void ipset_files_reset_modtime(struct ipset_files_head *list);
|
||||||
|
|
||||||
struct ipset_item {
|
struct ipset_item {
|
||||||
struct ipset_file *hfile;
|
struct ipset_file *hfile;
|
||||||
@ -141,3 +146,18 @@ bool port_filter_add(struct port_filters_head *head, const port_filter *pf);
|
|||||||
void port_filters_destroy(struct port_filters_head *head);
|
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_in_range(const struct port_filters_head *head, uint16_t port);
|
||||||
bool port_filters_deny_if_empty(struct port_filters_head *head);
|
bool port_filters_deny_if_empty(struct port_filters_head *head);
|
||||||
|
|
||||||
|
|
||||||
|
struct blob_item {
|
||||||
|
uint8_t *data; // main data blob
|
||||||
|
size_t size; // main data blob size
|
||||||
|
size_t size_buf;// main data blob allocated size
|
||||||
|
void *extra; // any data without size
|
||||||
|
void *extra2; // any data without size
|
||||||
|
LIST_ENTRY(blob_item) next;
|
||||||
|
};
|
||||||
|
LIST_HEAD(blob_collection_head, blob_item);
|
||||||
|
struct blob_item *blob_collection_add(struct blob_collection_head *head);
|
||||||
|
struct blob_item *blob_collection_add_blob(struct blob_collection_head *head, const void *data, size_t size, size_t size_reserve);
|
||||||
|
void blob_collection_destroy(struct blob_collection_head *head);
|
||||||
|
bool blob_collection_empty(const struct blob_collection_head *head);
|
||||||
|
134
nfq/protocol.c
134
nfq/protocol.c
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
#include "protocol.h"
|
#include "protocol.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
#include "params.h"
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
@ -33,6 +35,8 @@ const char *l7proto_str(t_l7proto l7)
|
|||||||
case QUIC: return "quic";
|
case QUIC: return "quic";
|
||||||
case WIREGUARD: return "wireguard";
|
case WIREGUARD: return "wireguard";
|
||||||
case DHT: return "dht";
|
case DHT: return "dht";
|
||||||
|
case DISCORD: return "discord";
|
||||||
|
case STUN: return "stun";
|
||||||
default: return "unknown";
|
default: return "unknown";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -43,7 +47,9 @@ bool l7_proto_match(t_l7proto l7proto, uint32_t filter_l7)
|
|||||||
(l7proto==TLS && (filter_l7 & L7_PROTO_TLS)) ||
|
(l7proto==TLS && (filter_l7 & L7_PROTO_TLS)) ||
|
||||||
(l7proto==QUIC && (filter_l7 & L7_PROTO_QUIC)) ||
|
(l7proto==QUIC && (filter_l7 & L7_PROTO_QUIC)) ||
|
||||||
(l7proto==WIREGUARD && (filter_l7 & L7_PROTO_WIREGUARD)) ||
|
(l7proto==WIREGUARD && (filter_l7 & L7_PROTO_WIREGUARD)) ||
|
||||||
(l7proto==DHT && (filter_l7 & L7_PROTO_DHT));
|
(l7proto==DHT && (filter_l7 & L7_PROTO_DHT)) ||
|
||||||
|
(l7proto==DISCORD && (filter_l7 & L7_PROTO_DISCORD)) ||
|
||||||
|
(l7proto==STUN && (filter_l7 & L7_PROTO_STUN));
|
||||||
}
|
}
|
||||||
|
|
||||||
#define PM_ABS 0
|
#define PM_ABS 0
|
||||||
@ -339,6 +345,19 @@ size_t HttpPos(uint8_t posmarker, int16_t pos, const uint8_t *data, size_t sz)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char *TLSVersionStr(uint16_t tlsver)
|
||||||
|
{
|
||||||
|
switch(tlsver)
|
||||||
|
{
|
||||||
|
case 0x0301: return "TLS 1.0";
|
||||||
|
case 0x0302: return "TLS 1.1";
|
||||||
|
case 0x0303: return "TLS 1.2";
|
||||||
|
case 0x0304: return "TLS 1.3";
|
||||||
|
default:
|
||||||
|
// 0x0a0a, 0x1a1a, ..., 0xfafa
|
||||||
|
return (((tlsver & 0x0F0F) == 0x0A0A) && ((tlsver>>12)==((tlsver>>4)&0xF))) ? "GREASE" : "UNKNOWN";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
uint16_t TLSRecordDataLen(const uint8_t *data)
|
uint16_t TLSRecordDataLen(const uint8_t *data)
|
||||||
{
|
{
|
||||||
@ -371,6 +390,46 @@ bool IsTLSHandshakeFull(const uint8_t *data, size_t len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool TLSFindExtLenOffsetInHandshake(const uint8_t *data, size_t len, size_t *off)
|
||||||
|
{
|
||||||
|
// +0
|
||||||
|
// u8 HandshakeType: ClientHello
|
||||||
|
// u24 Length
|
||||||
|
// u16 Version
|
||||||
|
// c[32] random
|
||||||
|
// u8 SessionIDLength
|
||||||
|
// <SessionID>
|
||||||
|
// u16 CipherSuitesLength
|
||||||
|
// <CipherSuites>
|
||||||
|
// u8 CompressionMethodsLength
|
||||||
|
// <CompressionMethods>
|
||||||
|
// u16 ExtensionsLength
|
||||||
|
|
||||||
|
size_t l;
|
||||||
|
|
||||||
|
l = 1 + 3 + 2 + 32;
|
||||||
|
// SessionIDLength
|
||||||
|
if (len < (l + 1)) return false;
|
||||||
|
l += data[l] + 1;
|
||||||
|
// CipherSuitesLength
|
||||||
|
if (len < (l + 2)) return false;
|
||||||
|
l += pntoh16(data + l) + 2;
|
||||||
|
// CompressionMethodsLength
|
||||||
|
if (len < (l + 1)) return false;
|
||||||
|
l += data[l] + 1;
|
||||||
|
// ExtensionsLength
|
||||||
|
if (len < (l + 2)) return false;
|
||||||
|
*off = l;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool TLSFindExtLen(const uint8_t *data, size_t len, size_t *off)
|
||||||
|
{
|
||||||
|
if (!TLSFindExtLenOffsetInHandshake(data+5,len-5,off))
|
||||||
|
return false;
|
||||||
|
*off+=5;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// bPartialIsOK=true - accept partial packets not containing the whole TLS message
|
// bPartialIsOK=true - accept partial packets not containing the whole TLS message
|
||||||
bool TLSFindExtInHandshake(const uint8_t *data, size_t len, uint16_t type, const uint8_t **ext, size_t *len_ext, bool bPartialIsOK)
|
bool TLSFindExtInHandshake(const uint8_t *data, size_t len, uint16_t type, const uint8_t **ext, size_t *len_ext, bool bPartialIsOK)
|
||||||
{
|
{
|
||||||
@ -391,18 +450,7 @@ bool TLSFindExtInHandshake(const uint8_t *data, size_t len, uint16_t type, const
|
|||||||
|
|
||||||
if (!bPartialIsOK && !IsTLSHandshakeFull(data,len)) return false;
|
if (!bPartialIsOK && !IsTLSHandshakeFull(data,len)) return false;
|
||||||
|
|
||||||
l = 1 + 3 + 2 + 32;
|
if (!TLSFindExtLenOffsetInHandshake(data,len,&l)) return false;
|
||||||
// SessionIDLength
|
|
||||||
if (len < (l + 1)) return false;
|
|
||||||
l += data[l] + 1;
|
|
||||||
// CipherSuitesLength
|
|
||||||
if (len < (l + 2)) return false;
|
|
||||||
l += pntoh16(data + l) + 2;
|
|
||||||
// CompressionMethodsLength
|
|
||||||
if (len < (l + 1)) return false;
|
|
||||||
l += data[l] + 1;
|
|
||||||
// ExtensionsLength
|
|
||||||
if (len < (l + 2)) return false;
|
|
||||||
|
|
||||||
data += l; len -= l;
|
data += l; len -= l;
|
||||||
l = pntoh16(data);
|
l = pntoh16(data);
|
||||||
@ -449,7 +497,7 @@ bool TLSFindExt(const uint8_t *data, size_t len, uint16_t type, const uint8_t **
|
|||||||
if (reclen<len) len=reclen; // correct len if it has more data than the first tls record has
|
if (reclen<len) len=reclen; // correct len if it has more data than the first tls record has
|
||||||
return TLSFindExtInHandshake(data + 5, len - 5, type, ext, len_ext, bPartialIsOK);
|
return TLSFindExtInHandshake(data + 5, len - 5, type, ext, len_ext, bPartialIsOK);
|
||||||
}
|
}
|
||||||
static bool TLSAdvanceToHostInSNI(const uint8_t **ext, size_t *elen, size_t *slen)
|
bool TLSAdvanceToHostInSNI(const uint8_t **ext, size_t *elen, size_t *slen)
|
||||||
{
|
{
|
||||||
// u16 data+0 - name list length
|
// u16 data+0 - name list length
|
||||||
// u8 data+2 - server name type. 0=host_name
|
// u8 data+2 - server name type. 0=host_name
|
||||||
@ -507,7 +555,7 @@ size_t TLSPos(uint8_t posmarker, int16_t pos, const uint8_t *data, size_t sz)
|
|||||||
case PM_HOST_MIDSLD:
|
case PM_HOST_MIDSLD:
|
||||||
case PM_HOST_ENDSLD:
|
case PM_HOST_ENDSLD:
|
||||||
case PM_SNI_EXT:
|
case PM_SNI_EXT:
|
||||||
if (TLSFindExt(data,sz,0,&ext,&elen,false))
|
if (TLSFindExt(data,sz,0,&ext,&elen,TLS_PARTIALS_ENABLE))
|
||||||
{
|
{
|
||||||
if (posmarker==PM_SNI_EXT)
|
if (posmarker==PM_SNI_EXT)
|
||||||
{
|
{
|
||||||
@ -813,7 +861,16 @@ bool QUICDecryptInitial(const uint8_t *data, size_t data_len, uint8_t *clean, si
|
|||||||
return !memcmp(data + pn_offset + pkn_len + cryptlen, atag, 16);
|
return !memcmp(data + pn_offset + pkn_len + cryptlen, atag, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,size_t *defrag_len)
|
struct range64
|
||||||
|
{
|
||||||
|
uint64_t offset,len;
|
||||||
|
};
|
||||||
|
#define MAX_DEFRAG_PIECES 128
|
||||||
|
static int cmp_range64(const void * a, const void * b)
|
||||||
|
{
|
||||||
|
return (((struct range64*)a)->offset < ((struct range64*)b)->offset) ? -1 : (((struct range64*)a)->offset > ((struct range64*)b)->offset) ? 1 : 0;
|
||||||
|
}
|
||||||
|
bool QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,size_t *defrag_len, bool *bFull)
|
||||||
{
|
{
|
||||||
// Crypto frame can be split into multiple chunks
|
// Crypto frame can be split into multiple chunks
|
||||||
// chromium randomly splits it and pads with zero/one bytes to force support the standard
|
// chromium randomly splits it and pads with zero/one bytes to force support the standard
|
||||||
@ -822,13 +879,15 @@ bool QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,siz
|
|||||||
if (*defrag_len<10) return false;
|
if (*defrag_len<10) return false;
|
||||||
uint8_t *defrag_data = defrag+10;
|
uint8_t *defrag_data = defrag+10;
|
||||||
size_t defrag_data_len = *defrag_len-10;
|
size_t defrag_data_len = *defrag_len-10;
|
||||||
|
|
||||||
uint8_t ft;
|
uint8_t ft;
|
||||||
uint64_t offset,sz,szmax=0,zeropos=0,pos=0;
|
uint64_t offset,sz,szmax=0,zeropos=0,pos=0;
|
||||||
bool found=false;
|
bool found=false;
|
||||||
|
struct range64 ranges[MAX_DEFRAG_PIECES];
|
||||||
|
int i,range=0;
|
||||||
|
|
||||||
while(pos<clean_len)
|
while(pos<clean_len)
|
||||||
{
|
{
|
||||||
|
// frame type
|
||||||
ft = clean[pos];
|
ft = clean[pos];
|
||||||
pos++;
|
pos++;
|
||||||
if (ft>1) // 00 - padding, 01 - ping
|
if (ft>1) // 00 - padding, 01 - ping
|
||||||
@ -836,6 +895,7 @@ bool QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,siz
|
|||||||
if (ft!=6) return false; // dont want to know all possible frame type formats
|
if (ft!=6) return false; // dont want to know all possible frame type formats
|
||||||
|
|
||||||
if (pos>=clean_len) return false;
|
if (pos>=clean_len) return false;
|
||||||
|
if (range>=MAX_DEFRAG_PIECES) return false;
|
||||||
|
|
||||||
if ((pos+tvb_get_size(clean[pos])>=clean_len)) return false;
|
if ((pos+tvb_get_size(clean[pos])>=clean_len)) return false;
|
||||||
pos += tvb_get_varint(clean+pos, &offset);
|
pos += tvb_get_varint(clean+pos, &offset);
|
||||||
@ -844,7 +904,7 @@ bool QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,siz
|
|||||||
pos += tvb_get_varint(clean+pos, &sz);
|
pos += tvb_get_varint(clean+pos, &sz);
|
||||||
if ((pos+sz)>clean_len) return false;
|
if ((pos+sz)>clean_len) return false;
|
||||||
|
|
||||||
if ((offset+sz)>defrag_data_len) return false;
|
if ((offset+sz)>defrag_data_len) return false; // defrag buf overflow
|
||||||
if (zeropos < offset)
|
if (zeropos < offset)
|
||||||
// make sure no uninitialized gaps exist in case of not full fragment coverage
|
// make sure no uninitialized gaps exist in case of not full fragment coverage
|
||||||
memset(defrag_data+zeropos,0,offset-zeropos);
|
memset(defrag_data+zeropos,0,offset-zeropos);
|
||||||
@ -855,6 +915,10 @@ bool QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,siz
|
|||||||
|
|
||||||
found=true;
|
found=true;
|
||||||
pos+=sz;
|
pos+=sz;
|
||||||
|
|
||||||
|
ranges[range].offset = offset;
|
||||||
|
ranges[range].len = sz;
|
||||||
|
range++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (found)
|
if (found)
|
||||||
@ -866,6 +930,23 @@ bool QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,siz
|
|||||||
phton64(defrag+2,szmax);
|
phton64(defrag+2,szmax);
|
||||||
defrag[2] |= 0xC0; // 64 bit value
|
defrag[2] |= 0xC0; // 64 bit value
|
||||||
*defrag_len = (size_t)(szmax+10);
|
*defrag_len = (size_t)(szmax+10);
|
||||||
|
|
||||||
|
qsort(ranges, range, sizeof(*ranges), cmp_range64);
|
||||||
|
|
||||||
|
//for(i=0 ; i<range ; i++)
|
||||||
|
// printf("RANGE %zu len %zu\n",ranges[i].offset,ranges[i].len);
|
||||||
|
|
||||||
|
for(i=0,offset=0,*bFull=true ; i<range ; i++)
|
||||||
|
{
|
||||||
|
if (ranges[i].offset!=offset)
|
||||||
|
{
|
||||||
|
*bFull = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
offset += ranges[i].len;
|
||||||
|
}
|
||||||
|
|
||||||
|
//printf("bFull=%u\n",*bFull);
|
||||||
}
|
}
|
||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
@ -936,9 +1017,24 @@ bool IsQUICInitial(const uint8_t *data, size_t len)
|
|||||||
|
|
||||||
bool IsWireguardHandshakeInitiation(const uint8_t *data, size_t len)
|
bool IsWireguardHandshakeInitiation(const uint8_t *data, size_t len)
|
||||||
{
|
{
|
||||||
return len==148 && data[0]==1 && data[1]==0 && data[2]==0 && data[3]==0;
|
return len==148 && data[0]==1;
|
||||||
}
|
}
|
||||||
bool IsDhtD1(const uint8_t *data, size_t len)
|
bool IsDhtD1(const uint8_t *data, size_t len)
|
||||||
{
|
{
|
||||||
return len>=7 && data[0]=='d' && data[1]=='1' && data[len-1]=='e';
|
return len>=7 && data[0]=='d' && data[1]=='1' && data[len-1]=='e';
|
||||||
}
|
}
|
||||||
|
bool IsDiscordIpDiscoveryRequest(const uint8_t *data, size_t len)
|
||||||
|
{
|
||||||
|
return len==74 &&
|
||||||
|
data[0]==0 && data[1]==1 &&
|
||||||
|
data[2]==0 && data[3]==70 &&
|
||||||
|
data[8]==0 && memcmp(&data[8],&data[9],63)==0; // address is not set in requests
|
||||||
|
}
|
||||||
|
bool IsStunMessage(const uint8_t *data, size_t len)
|
||||||
|
{
|
||||||
|
return len>=20 && // header size
|
||||||
|
(data[0]&0xC0)==0 && // 2 most significant bits must be zeroes
|
||||||
|
(data[3]&0b11)==0 && // length must be a multiple of 4
|
||||||
|
ntohl(*(uint32_t*)(&data[4]))==0x2112A442 && // magic cookie
|
||||||
|
ntohs(*(uint16_t*)(&data[2]))==len-20;
|
||||||
|
}
|
||||||
|
@ -7,12 +7,14 @@
|
|||||||
#include "crypto/aes-gcm.h"
|
#include "crypto/aes-gcm.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
|
||||||
typedef enum {UNKNOWN=0, HTTP, TLS, QUIC, WIREGUARD, DHT} t_l7proto;
|
typedef enum {UNKNOWN=0, HTTP, TLS, QUIC, WIREGUARD, DHT, DISCORD, STUN} t_l7proto;
|
||||||
#define L7_PROTO_HTTP 0x00000001
|
#define L7_PROTO_HTTP 0x00000001
|
||||||
#define L7_PROTO_TLS 0x00000002
|
#define L7_PROTO_TLS 0x00000002
|
||||||
#define L7_PROTO_QUIC 0x00000004
|
#define L7_PROTO_QUIC 0x00000004
|
||||||
#define L7_PROTO_WIREGUARD 0x00000008
|
#define L7_PROTO_WIREGUARD 0x00000008
|
||||||
#define L7_PROTO_DHT 0x00000010
|
#define L7_PROTO_DHT 0x00000010
|
||||||
|
#define L7_PROTO_DISCORD 0x00000020
|
||||||
|
#define L7_PROTO_STUN 0x00000040
|
||||||
#define L7_PROTO_UNKNOWN 0x80000000
|
#define L7_PROTO_UNKNOWN 0x80000000
|
||||||
const char *l7proto_str(t_l7proto l7);
|
const char *l7proto_str(t_l7proto l7);
|
||||||
bool l7_proto_match(t_l7proto l7proto, uint32_t filter_l7);
|
bool l7_proto_match(t_l7proto l7proto, uint32_t filter_l7);
|
||||||
@ -55,6 +57,7 @@ int HttpReplyCode(const uint8_t *data, size_t len);
|
|||||||
// must be pre-checked by IsHttpReply
|
// must be pre-checked by IsHttpReply
|
||||||
bool HttpReplyLooksLikeDPIRedirect(const uint8_t *data, size_t len, const char *host);
|
bool HttpReplyLooksLikeDPIRedirect(const uint8_t *data, size_t len, const char *host);
|
||||||
|
|
||||||
|
const char *TLSVersionStr(uint16_t tlsver);
|
||||||
uint16_t TLSRecordDataLen(const uint8_t *data);
|
uint16_t TLSRecordDataLen(const uint8_t *data);
|
||||||
size_t TLSRecordLen(const uint8_t *data);
|
size_t TLSRecordLen(const uint8_t *data);
|
||||||
bool IsTLSRecordFull(const uint8_t *data, size_t len);
|
bool IsTLSRecordFull(const uint8_t *data, size_t len);
|
||||||
@ -62,6 +65,9 @@ bool IsTLSClientHello(const uint8_t *data, size_t len, bool bPartialIsOK);
|
|||||||
size_t TLSHandshakeLen(const uint8_t *data);
|
size_t TLSHandshakeLen(const uint8_t *data);
|
||||||
bool IsTLSHandshakeClientHello(const uint8_t *data, size_t len);
|
bool IsTLSHandshakeClientHello(const uint8_t *data, size_t len);
|
||||||
bool IsTLSHandshakeFull(const uint8_t *data, size_t len);
|
bool IsTLSHandshakeFull(const uint8_t *data, size_t len);
|
||||||
|
bool TLSAdvanceToHostInSNI(const uint8_t **ext, size_t *elen, size_t *slen);
|
||||||
|
bool TLSFindExtLen(const uint8_t *data, size_t len, size_t *off);
|
||||||
|
bool TLSFindExtLenOffsetInHandshake(const uint8_t *data, size_t len, size_t *off);
|
||||||
bool TLSFindExt(const uint8_t *data, size_t len, uint16_t type, const uint8_t **ext, size_t *len_ext, bool bPartialIsOK);
|
bool TLSFindExt(const uint8_t *data, size_t len, uint16_t type, const uint8_t **ext, size_t *len_ext, bool bPartialIsOK);
|
||||||
bool TLSFindExtInHandshake(const uint8_t *data, size_t len, uint16_t type, const uint8_t **ext, size_t *len_ext, bool bPartialIsOK);
|
bool TLSFindExtInHandshake(const uint8_t *data, size_t len, uint16_t type, const uint8_t **ext, size_t *len_ext, bool bPartialIsOK);
|
||||||
bool TLSHelloExtractHost(const uint8_t *data, size_t len, char *host, size_t len_host, bool bPartialIsOK);
|
bool TLSHelloExtractHost(const uint8_t *data, size_t len, char *host, size_t len_host, bool bPartialIsOK);
|
||||||
@ -69,6 +75,8 @@ bool TLSHelloExtractHostFromHandshake(const uint8_t *data, size_t len, char *hos
|
|||||||
|
|
||||||
bool IsWireguardHandshakeInitiation(const uint8_t *data, size_t len);
|
bool IsWireguardHandshakeInitiation(const uint8_t *data, size_t len);
|
||||||
bool IsDhtD1(const uint8_t *data, size_t len);
|
bool IsDhtD1(const uint8_t *data, size_t len);
|
||||||
|
bool IsDiscordIpDiscoveryRequest(const uint8_t *data, size_t len);
|
||||||
|
bool IsStunMessage(const uint8_t *data, size_t len);
|
||||||
|
|
||||||
#define QUIC_MAX_CID_LENGTH 20
|
#define QUIC_MAX_CID_LENGTH 20
|
||||||
typedef struct quic_cid {
|
typedef struct quic_cid {
|
||||||
@ -84,5 +92,6 @@ uint8_t QUICDraftVersion(uint32_t version);
|
|||||||
bool QUICExtractDCID(const uint8_t *data, size_t len, quic_cid_t *cid);
|
bool QUICExtractDCID(const uint8_t *data, size_t len, quic_cid_t *cid);
|
||||||
|
|
||||||
bool QUICDecryptInitial(const uint8_t *data, size_t data_len, uint8_t *clean, size_t *clean_len);
|
bool QUICDecryptInitial(const uint8_t *data, size_t data_len, uint8_t *clean, size_t *clean_len);
|
||||||
bool QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,size_t *defrag_len);
|
// returns true if crypto frames were found . bFull = true if crypto frame fragments have full coverage
|
||||||
|
bool QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,size_t *defrag_len, bool *bFull);
|
||||||
//bool QUICExtractHostFromInitial(const uint8_t *data, size_t data_len, char *host, size_t len_host, bool *bDecryptOK, bool *bIsCryptoHello);
|
//bool QUICExtractHostFromInitial(const uint8_t *data, size_t data_len, char *host, size_t len_host, bool *bDecryptOK, bool *bIsCryptoHello);
|
||||||
|
@ -287,7 +287,7 @@ bool can_drop_root(void)
|
|||||||
{
|
{
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
// has some caps
|
// has some caps
|
||||||
return checkpcap((1<<CAP_SETUID)|(1<<CAP_SETGID)|(1<<CAP_SETPCAP));
|
return checkpcap((1<<CAP_SETUID)|(1<<CAP_SETGID));
|
||||||
#else
|
#else
|
||||||
// effective root
|
// effective root
|
||||||
return !geteuid();
|
return !geteuid();
|
||||||
@ -319,11 +319,7 @@ bool droproot(uid_t uid, gid_t gid)
|
|||||||
DLOG_PERROR("setuid");
|
DLOG_PERROR("setuid");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#ifdef __linux__
|
|
||||||
return dropcaps();
|
|
||||||
#else
|
|
||||||
return true;
|
return true;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_id(void)
|
void print_id(void)
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
CC ?= gcc
|
CC ?= gcc
|
||||||
CFLAGS += -std=gnu99 -Os -flto=auto
|
CFLAGS += -std=gnu99 -Os -flto=auto
|
||||||
|
CFLAGS_SYSTEMD = -DUSE_SYSTEMD
|
||||||
CFLAGS_BSD = -Wno-address-of-packed-member
|
CFLAGS_BSD = -Wno-address-of-packed-member
|
||||||
LIBS = -lz -lpthread
|
LIBS = -lz -lpthread
|
||||||
|
LIBS_SYSTEMD = -lsystemd
|
||||||
LIBS_ANDROID = -lz
|
LIBS_ANDROID = -lz
|
||||||
SRC_FILES = *.c
|
SRC_FILES = *.c
|
||||||
SRC_FILES_ANDROID = $(SRC_FILES) andr/*.c
|
SRC_FILES_ANDROID = $(SRC_FILES) andr/*.c
|
||||||
@ -11,6 +13,9 @@ all: tpws
|
|||||||
tpws: $(SRC_FILES)
|
tpws: $(SRC_FILES)
|
||||||
$(CC) -s $(CFLAGS) -o tpws $(SRC_FILES) $(LIBS) $(LDFLAGS)
|
$(CC) -s $(CFLAGS) -o tpws $(SRC_FILES) $(LIBS) $(LDFLAGS)
|
||||||
|
|
||||||
|
systemd: $(SRC_FILES)
|
||||||
|
$(CC) -s $(CFLAGS) $(CFLAGS_SYSTEMD) -o tpws $(SRC_FILES) $(LIBS) $(LIBS_SYSTEMD) $(LDFLAGS)
|
||||||
|
|
||||||
android: $(SRC_FILES)
|
android: $(SRC_FILES)
|
||||||
$(CC) -s $(CFLAGS) -o tpws $(SRC_FILES_ANDROID) $(LIBS_ANDROID) $(LDFLAGS)
|
$(CC) -s $(CFLAGS) -o tpws $(SRC_FILES_ANDROID) $(LIBS_ANDROID) $(LDFLAGS)
|
||||||
|
|
||||||
|
@ -65,11 +65,8 @@ int z_readfile(FILE *F, char **buf, size_t *size)
|
|||||||
|
|
||||||
zerr:
|
zerr:
|
||||||
inflateEnd(&zs);
|
inflateEnd(&zs);
|
||||||
if (*buf)
|
free(*buf);
|
||||||
{
|
*buf = NULL;
|
||||||
free(*buf);
|
|
||||||
*buf = NULL;
|
|
||||||
}
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <libgen.h>
|
#include <libgen.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
#ifdef __ANDROID__
|
#ifdef __ANDROID__
|
||||||
#include "andr/ifaddrs.h"
|
#include "andr/ifaddrs.h"
|
||||||
@ -77,6 +78,13 @@ char *strncasestr(const char *s, const char *find, size_t slen)
|
|||||||
return (char *)s;
|
return (char *)s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool str_ends_with(const char *s, const char *suffix)
|
||||||
|
{
|
||||||
|
size_t slen = strlen(s);
|
||||||
|
size_t suffix_len = strlen(suffix);
|
||||||
|
return suffix_len <= slen && !strcmp(s + slen - suffix_len, suffix);
|
||||||
|
}
|
||||||
|
|
||||||
bool load_file(const char *filename, void *buffer, size_t *buffer_size)
|
bool load_file(const char *filename, void *buffer, size_t *buffer_size)
|
||||||
{
|
{
|
||||||
FILE *F;
|
FILE *F;
|
||||||
@ -314,6 +322,29 @@ time_t file_mod_time(const char *filename)
|
|||||||
struct stat st;
|
struct stat st;
|
||||||
return stat(filename, &st) == -1 ? 0 : st.st_mtime;
|
return stat(filename, &st) == -1 ? 0 : st.st_mtime;
|
||||||
}
|
}
|
||||||
|
bool file_mod_signature(const char *filename, file_mod_sig *ms)
|
||||||
|
{
|
||||||
|
struct stat st;
|
||||||
|
if (stat(filename,&st)==-1)
|
||||||
|
{
|
||||||
|
FILE_MOD_RESET(ms);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ms->mod_time=st.st_mtime;
|
||||||
|
ms->size=st.st_size;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool file_open_test(const char *filename, int flags)
|
||||||
|
{
|
||||||
|
int fd = open(filename,flags);
|
||||||
|
if (fd>=0)
|
||||||
|
{
|
||||||
|
close(fd);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool pf_in_range(uint16_t port, const port_filter *pf)
|
bool pf_in_range(uint16_t port, const port_filter *pf)
|
||||||
{
|
{
|
||||||
@ -359,6 +390,11 @@ bool pf_is_empty(const port_filter *pf)
|
|||||||
return !pf->neg && !pf->from && !pf->to;
|
return !pf->neg && !pf->from && !pf->to;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_console_io_buffering(void)
|
||||||
|
{
|
||||||
|
setvbuf(stdout, NULL, _IOLBF, 0);
|
||||||
|
setvbuf(stderr, NULL, _IOLBF, 0);
|
||||||
|
}
|
||||||
|
|
||||||
bool set_env_exedir(const char *argv0)
|
bool set_env_exedir(const char *argv0)
|
||||||
{
|
{
|
||||||
@ -536,4 +572,20 @@ bool socket_wait_notsent(int sfd, unsigned int delay_ms, unsigned int *wasted_ms
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int is_wsl(void)
|
||||||
|
{
|
||||||
|
struct utsname buf;
|
||||||
|
if (uname(&buf) != 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (strcmp(buf.sysname, "Linux") != 0)
|
||||||
|
return 0;
|
||||||
|
if (str_ends_with(buf.release, "microsoft-standard-WSL2"))
|
||||||
|
return 2;
|
||||||
|
if (str_ends_with(buf.release, "-Microsoft"))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <sys/utsname.h>
|
||||||
|
|
||||||
// this saves memory. sockaddr_storage is larger than required. it can be 128 bytes. sockaddr_in6 is 28 bytes.
|
// this saves memory. sockaddr_storage is larger than required. it can be 128 bytes. sockaddr_in6 is 28 bytes.
|
||||||
typedef union
|
typedef union
|
||||||
@ -22,6 +23,8 @@ void rtrim(char *s);
|
|||||||
void replace_char(char *s, char from, char to);
|
void replace_char(char *s, char from, char to);
|
||||||
char *strncasestr(const char *s,const char *find, size_t slen);
|
char *strncasestr(const char *s,const char *find, size_t slen);
|
||||||
|
|
||||||
|
bool str_ends_with(const char *s, const char *suffix);
|
||||||
|
|
||||||
bool load_file(const char *filename,void *buffer,size_t *buffer_size);
|
bool load_file(const char *filename,void *buffer,size_t *buffer_size);
|
||||||
bool append_to_list_file(const char *filename, const char *s);
|
bool append_to_list_file(const char *filename, const char *s);
|
||||||
|
|
||||||
@ -62,7 +65,16 @@ static inline void phton16(uint8_t *p, uint16_t v) {
|
|||||||
|
|
||||||
int fprint_localtime(FILE *F);
|
int fprint_localtime(FILE *F);
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
time_t mod_time;
|
||||||
|
off_t size;
|
||||||
|
} file_mod_sig;
|
||||||
|
#define FILE_MOD_COMPARE(ms1,ms2) (((ms1)->mod_time==(ms2)->mod_time) && ((ms1)->size==(ms2)->size))
|
||||||
|
#define FILE_MOD_RESET(ms) memset(ms,0,sizeof(file_mod_sig))
|
||||||
|
bool file_mod_signature(const char *filename, file_mod_sig *ms);
|
||||||
time_t file_mod_time(const char *filename);
|
time_t file_mod_time(const char *filename);
|
||||||
|
bool file_open_test(const char *filename, int flags);
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
@ -73,6 +85,7 @@ bool pf_in_range(uint16_t port, const port_filter *pf);
|
|||||||
bool pf_parse(const char *s, port_filter *pf);
|
bool pf_parse(const char *s, port_filter *pf);
|
||||||
bool pf_is_empty(const port_filter *pf);
|
bool pf_is_empty(const port_filter *pf);
|
||||||
|
|
||||||
|
void set_console_io_buffering(void);
|
||||||
bool set_env_exedir(const char *argv0);
|
bool set_env_exedir(const char *argv0);
|
||||||
|
|
||||||
#ifndef IN_LOOPBACK
|
#ifndef IN_LOOPBACK
|
||||||
@ -123,4 +136,6 @@ void msleep(unsigned int ms);
|
|||||||
bool socket_supports_notsent();
|
bool socket_supports_notsent();
|
||||||
bool socket_has_notsent(int sfd);
|
bool socket_has_notsent(int sfd);
|
||||||
bool socket_wait_notsent(int sfd, unsigned int delay_ms, unsigned int *wasted_ms);
|
bool socket_wait_notsent(int sfd, unsigned int delay_ms, unsigned int *wasted_ms);
|
||||||
|
|
||||||
|
int is_wsl();
|
||||||
#endif
|
#endif
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
|
||||||
// inplace tolower() and add to pool
|
// inplace tolower() and add to pool
|
||||||
static bool addpool(strpool **hostlist, char **s, const char *end, int *ct)
|
static bool addpool(hostlist_pool **hostlist, char **s, const char *end, int *ct)
|
||||||
{
|
{
|
||||||
char *p=*s;
|
char *p=*s;
|
||||||
|
|
||||||
@ -17,10 +17,16 @@ static bool addpool(strpool **hostlist, char **s, const char *end, int *ct)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// advance until eol lowering all chars
|
// advance until eol lowering all chars
|
||||||
for (; p<end && *p && *p!='\r' && *p != '\n'; p++) *p=tolower(*p);
|
uint32_t flags = 0;
|
||||||
if (!StrPoolAddStrLen(hostlist, *s, p-*s))
|
if (*p=='^')
|
||||||
{
|
{
|
||||||
StrPoolDestroy(hostlist);
|
p = ++(*s);
|
||||||
|
flags |= HOSTLIST_POOL_FLAG_STRICT_MATCH;
|
||||||
|
}
|
||||||
|
for (; p<end && *p && *p!='\r' && *p != '\n'; p++) *p=tolower(*p);
|
||||||
|
if (!HostlistPoolAddStrLen(hostlist, *s, p-*s, flags))
|
||||||
|
{
|
||||||
|
HostlistPoolDestroy(hostlist);
|
||||||
*hostlist = NULL;
|
*hostlist = NULL;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -32,12 +38,12 @@ static bool addpool(strpool **hostlist, char **s, const char *end, int *ct)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AppendHostlistItem(strpool **hostlist, char *s)
|
bool AppendHostlistItem(hostlist_pool **hostlist, char *s)
|
||||||
{
|
{
|
||||||
return addpool(hostlist,&s,s+strlen(s),NULL);
|
return addpool(hostlist,&s,s+strlen(s),NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AppendHostList(strpool **hostlist, const char *filename)
|
bool AppendHostList(hostlist_pool **hostlist, const char *filename)
|
||||||
{
|
{
|
||||||
char *p, *e, s[256], *zbuf;
|
char *p, *e, s[256], *zbuf;
|
||||||
size_t zsize;
|
size_t zsize;
|
||||||
@ -105,21 +111,22 @@ static bool LoadHostList(struct hostlist_file *hfile)
|
|||||||
{
|
{
|
||||||
if (hfile->filename)
|
if (hfile->filename)
|
||||||
{
|
{
|
||||||
time_t t = file_mod_time(hfile->filename);
|
file_mod_sig fsig;
|
||||||
if (!t)
|
if (!file_mod_signature(hfile->filename, &fsig))
|
||||||
{
|
{
|
||||||
// stat() error
|
// stat() error
|
||||||
|
DLOG_PERROR("file_mod_signature");
|
||||||
DLOG_ERR("cannot access hostlist file '%s'. in-memory content remains unchanged.\n",hfile->filename);
|
DLOG_ERR("cannot access hostlist file '%s'. in-memory content remains unchanged.\n",hfile->filename);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (t==hfile->mod_time) return true; // up to date
|
if (FILE_MOD_COMPARE(&hfile->mod_sig,&fsig)) return true; // up to date
|
||||||
StrPoolDestroy(&hfile->hostlist);
|
HostlistPoolDestroy(&hfile->hostlist);
|
||||||
if (!AppendHostList(&hfile->hostlist, hfile->filename))
|
if (!AppendHostList(&hfile->hostlist, hfile->filename))
|
||||||
{
|
{
|
||||||
StrPoolDestroy(&hfile->hostlist);
|
HostlistPoolDestroy(&hfile->hostlist);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
hfile->mod_time=t;
|
hfile->mod_sig=fsig;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -137,10 +144,10 @@ static bool LoadHostLists(struct hostlist_files_head *list)
|
|||||||
return bres;
|
return bres;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NonEmptyHostlist(strpool **hostlist)
|
bool NonEmptyHostlist(hostlist_pool **hostlist)
|
||||||
{
|
{
|
||||||
// add impossible hostname if the list is empty
|
// add impossible hostname if the list is empty
|
||||||
return *hostlist ? true : StrPoolAddStrLen(hostlist, "@&()", 4);
|
return *hostlist ? true : HostlistPoolAddStrLen(hostlist, "@&()", 4, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void MakeAutolistsNonEmpty()
|
static void MakeAutolistsNonEmpty()
|
||||||
@ -163,19 +170,34 @@ bool LoadAllHostLists()
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static bool SearchHostList(strpool *hostlist, const char *host)
|
static bool SearchHostList(hostlist_pool *hostlist, const char *host)
|
||||||
{
|
{
|
||||||
if (hostlist)
|
if (hostlist)
|
||||||
{
|
{
|
||||||
const char *p = host;
|
const char *p = host;
|
||||||
bool bInHostList;
|
const struct hostlist_pool *hp;
|
||||||
|
bool bHostFull=true;
|
||||||
while (p)
|
while (p)
|
||||||
{
|
{
|
||||||
bInHostList = StrPoolCheckStr(hostlist, p);
|
VPRINT("hostlist check for %s : ", p);
|
||||||
VPRINT("hostlist check for %s : %s\n", p, bInHostList ? "positive" : "negative");
|
hp = HostlistPoolGetStr(hostlist, p);
|
||||||
if (bInHostList) return true;
|
if (hp)
|
||||||
|
{
|
||||||
|
if ((hp->flags & HOSTLIST_POOL_FLAG_STRICT_MATCH) && !bHostFull)
|
||||||
|
{
|
||||||
|
VPRINT("negative : strict_mismatch : %s != %s\n", p, host);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
VPRINT("positive\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
VPRINT("negative\n");
|
||||||
p = strchr(p, '.');
|
p = strchr(p, '.');
|
||||||
if (p) p++;
|
if (p) p++;
|
||||||
|
bHostFull = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -4,12 +4,14 @@
|
|||||||
#include "pools.h"
|
#include "pools.h"
|
||||||
#include "params.h"
|
#include "params.h"
|
||||||
|
|
||||||
bool AppendHostlistItem(strpool **hostlist, char *s);
|
bool AppendHostlistItem(hostlist_pool **hostlist, char *s);
|
||||||
bool AppendHostList(strpool **hostlist, const char *filename);
|
bool AppendHostList(hostlist_pool **hostlist, const char *filename);
|
||||||
bool LoadAllHostLists();
|
bool LoadAllHostLists();
|
||||||
bool NonEmptyHostlist(strpool **hostlist);
|
bool NonEmptyHostlist(hostlist_pool **hostlist);
|
||||||
// return : true = apply fooling, false = do not apply
|
// return : true = apply fooling, false = do not apply
|
||||||
bool HostlistCheck(const struct desync_profile *dp,const char *host, bool *excluded, bool bSkipReloadCheck);
|
bool HostlistCheck(const struct desync_profile *dp,const char *host, bool *excluded, bool bSkipReloadCheck);
|
||||||
struct hostlist_file *RegisterHostlist(struct desync_profile *dp, bool bExclude, const char *filename);
|
struct hostlist_file *RegisterHostlist(struct desync_profile *dp, bool bExclude, const char *filename);
|
||||||
bool HostlistsReloadCheckForProfile(const struct desync_profile *dp);
|
bool HostlistsReloadCheckForProfile(const struct desync_profile *dp);
|
||||||
void HostlistsDebug();
|
void HostlistsDebug();
|
||||||
|
|
||||||
|
#define ResetAllHostlistsModTime() hostlist_files_reset_modtime(¶ms.hostlists)
|
||||||
|
@ -126,21 +126,22 @@ static bool LoadIpset(struct ipset_file *hfile)
|
|||||||
{
|
{
|
||||||
if (hfile->filename)
|
if (hfile->filename)
|
||||||
{
|
{
|
||||||
time_t t = file_mod_time(hfile->filename);
|
file_mod_sig fsig;
|
||||||
if (!t)
|
if (!file_mod_signature(hfile->filename, &fsig))
|
||||||
{
|
{
|
||||||
// stat() error
|
// stat() error
|
||||||
|
DLOG_PERROR("file_mod_signature");
|
||||||
DLOG_ERR("cannot access ipset file '%s'. in-memory content remains unchanged.\n",hfile->filename);
|
DLOG_ERR("cannot access ipset file '%s'. in-memory content remains unchanged.\n",hfile->filename);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (t==hfile->mod_time) return true; // up to date
|
if (FILE_MOD_COMPARE(&hfile->mod_sig,&fsig)) return true; // up to date
|
||||||
ipsetDestroy(&hfile->ipset);
|
ipsetDestroy(&hfile->ipset);
|
||||||
if (!AppendIpset(&hfile->ipset, hfile->filename))
|
if (!AppendIpset(&hfile->ipset, hfile->filename))
|
||||||
{
|
{
|
||||||
ipsetDestroy(&hfile->ipset);
|
ipsetDestroy(&hfile->ipset);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
hfile->mod_time=t;
|
hfile->mod_sig=fsig;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -10,3 +10,5 @@ bool IpsetCheck(const struct desync_profile *dp, const struct in_addr *ipv4, con
|
|||||||
struct ipset_file *RegisterIpset(struct desync_profile *dp, bool bExclude, const char *filename);
|
struct ipset_file *RegisterIpset(struct desync_profile *dp, bool bExclude, const char *filename);
|
||||||
void IpsetsDebug();
|
void IpsetsDebug();
|
||||||
bool AppendIpsetItem(ipset *ips, char *ip);
|
bool AppendIpsetItem(ipset *ips, char *ip);
|
||||||
|
|
||||||
|
#define ResetAllIpsetModTime() ipset_files_reset_modtime(¶ms.ipsets)
|
||||||
|
@ -50,6 +50,7 @@ static int DLOG_VA(const char *format, int syslog_priority, bool condup, int lev
|
|||||||
{
|
{
|
||||||
va_copy(args2,args);
|
va_copy(args2,args);
|
||||||
DLOG_CON(format,syslog_priority,args2);
|
DLOG_CON(format,syslog_priority,args2);
|
||||||
|
va_end(args2);
|
||||||
}
|
}
|
||||||
if (params.debug>=level)
|
if (params.debug>=level)
|
||||||
{
|
{
|
||||||
|
51
tpws/pools.c
51
tpws/pools.c
@ -31,6 +31,9 @@
|
|||||||
free(elem); \
|
free(elem); \
|
||||||
return false; \
|
return false; \
|
||||||
}
|
}
|
||||||
|
#define ADD_HOSTLIST_POOL(etype, ppool, keystr, keystr_len, flg) \
|
||||||
|
ADD_STR_POOL(etype,ppool,keystr,keystr_len); \
|
||||||
|
elem->flags = flg;
|
||||||
|
|
||||||
|
|
||||||
#undef uthash_nonfatal_oom
|
#undef uthash_nonfatal_oom
|
||||||
@ -42,27 +45,31 @@ static void ut_oom_recover(void *elem)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// for not zero terminated strings
|
// for not zero terminated strings
|
||||||
bool StrPoolAddStrLen(strpool **pp, const char *s, size_t slen)
|
bool HostlistPoolAddStrLen(hostlist_pool **pp, const char *s, size_t slen, uint32_t flags)
|
||||||
{
|
{
|
||||||
ADD_STR_POOL(strpool, pp, s, slen)
|
ADD_HOSTLIST_POOL(hostlist_pool, pp, s, slen, flags)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// for zero terminated strings
|
// for zero terminated strings
|
||||||
bool StrPoolAddStr(strpool **pp, const char *s)
|
bool HostlistPoolAddStr(hostlist_pool **pp, const char *s, uint32_t flags)
|
||||||
{
|
{
|
||||||
return StrPoolAddStrLen(pp, s, strlen(s));
|
return HostlistPoolAddStrLen(pp, s, strlen(s), flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StrPoolCheckStr(strpool *p, const char *s)
|
hostlist_pool *HostlistPoolGetStr(hostlist_pool *p, const char *s)
|
||||||
{
|
{
|
||||||
strpool *elem;
|
hostlist_pool *elem;
|
||||||
HASH_FIND_STR(p, s, elem);
|
HASH_FIND_STR(p, s, elem);
|
||||||
return elem != NULL;
|
return elem;
|
||||||
|
}
|
||||||
|
bool HostlistPoolCheckStr(hostlist_pool *p, const char *s)
|
||||||
|
{
|
||||||
|
return !!HostlistPoolGetStr(p,s);
|
||||||
}
|
}
|
||||||
|
|
||||||
void StrPoolDestroy(strpool **pp)
|
void HostlistPoolDestroy(hostlist_pool **pp)
|
||||||
{
|
{
|
||||||
DESTROY_STR_POOL(strpool, pp)
|
DESTROY_STR_POOL(hostlist_pool, pp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -139,7 +146,7 @@ bool strlist_add(struct str_list_head *head, const char *filename)
|
|||||||
}
|
}
|
||||||
static void strlist_entry_destroy(struct str_list *entry)
|
static void strlist_entry_destroy(struct str_list *entry)
|
||||||
{
|
{
|
||||||
if (entry->str) free(entry->str);
|
free(entry->str);
|
||||||
free(entry);
|
free(entry);
|
||||||
}
|
}
|
||||||
void strlist_destroy(struct str_list_head *head)
|
void strlist_destroy(struct str_list_head *head)
|
||||||
@ -169,7 +176,7 @@ struct hostlist_file *hostlist_files_add(struct hostlist_files_head *head, const
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
entry->filename = NULL;
|
entry->filename = NULL;
|
||||||
entry->mod_time = 0;
|
FILE_MOD_RESET(&entry->mod_sig);
|
||||||
entry->hostlist = NULL;
|
entry->hostlist = NULL;
|
||||||
LIST_INSERT_HEAD(head, entry, next);
|
LIST_INSERT_HEAD(head, entry, next);
|
||||||
}
|
}
|
||||||
@ -177,8 +184,8 @@ struct hostlist_file *hostlist_files_add(struct hostlist_files_head *head, const
|
|||||||
}
|
}
|
||||||
static void hostlist_files_entry_destroy(struct hostlist_file *entry)
|
static void hostlist_files_entry_destroy(struct hostlist_file *entry)
|
||||||
{
|
{
|
||||||
if (entry->filename) free(entry->filename);
|
free(entry->filename);
|
||||||
StrPoolDestroy(&entry->hostlist);
|
HostlistPoolDestroy(&entry->hostlist);
|
||||||
free(entry);
|
free(entry);
|
||||||
}
|
}
|
||||||
void hostlist_files_destroy(struct hostlist_files_head *head)
|
void hostlist_files_destroy(struct hostlist_files_head *head)
|
||||||
@ -201,6 +208,13 @@ struct hostlist_file *hostlist_files_search(struct hostlist_files_head *head, co
|
|||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
void hostlist_files_reset_modtime(struct hostlist_files_head *list)
|
||||||
|
{
|
||||||
|
struct hostlist_file *hfile;
|
||||||
|
|
||||||
|
LIST_FOREACH(hfile, list, next)
|
||||||
|
FILE_MOD_RESET(&hfile->mod_sig);
|
||||||
|
}
|
||||||
|
|
||||||
struct hostlist_item *hostlist_collection_add(struct hostlist_collection_head *head, struct hostlist_file *hfile)
|
struct hostlist_item *hostlist_collection_add(struct hostlist_collection_head *head, struct hostlist_file *hfile)
|
||||||
{
|
{
|
||||||
@ -383,7 +397,7 @@ struct ipset_file *ipset_files_add(struct ipset_files_head *head, const char *fi
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
entry->filename = NULL;
|
entry->filename = NULL;
|
||||||
entry->mod_time = 0;
|
FILE_MOD_RESET(&entry->mod_sig);
|
||||||
memset(&entry->ipset,0,sizeof(entry->ipset));
|
memset(&entry->ipset,0,sizeof(entry->ipset));
|
||||||
LIST_INSERT_HEAD(head, entry, next);
|
LIST_INSERT_HEAD(head, entry, next);
|
||||||
}
|
}
|
||||||
@ -391,7 +405,7 @@ struct ipset_file *ipset_files_add(struct ipset_files_head *head, const char *fi
|
|||||||
}
|
}
|
||||||
static void ipset_files_entry_destroy(struct ipset_file *entry)
|
static void ipset_files_entry_destroy(struct ipset_file *entry)
|
||||||
{
|
{
|
||||||
if (entry->filename) free(entry->filename);
|
free(entry->filename);
|
||||||
ipsetDestroy(&entry->ipset);
|
ipsetDestroy(&entry->ipset);
|
||||||
free(entry);
|
free(entry);
|
||||||
}
|
}
|
||||||
@ -415,6 +429,13 @@ struct ipset_file *ipset_files_search(struct ipset_files_head *head, const char
|
|||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
void ipset_files_reset_modtime(struct ipset_files_head *list)
|
||||||
|
{
|
||||||
|
struct ipset_file *hfile;
|
||||||
|
|
||||||
|
LIST_FOREACH(hfile, list, next)
|
||||||
|
FILE_MOD_RESET(&hfile->mod_sig);
|
||||||
|
}
|
||||||
|
|
||||||
struct ipset_item *ipset_collection_add(struct ipset_collection_head *head, struct ipset_file *hfile)
|
struct ipset_item *ipset_collection_add(struct ipset_collection_head *head, struct ipset_file *hfile)
|
||||||
{
|
{
|
||||||
|
35
tpws/pools.h
35
tpws/pools.h
@ -12,15 +12,18 @@
|
|||||||
#define HASH_FUNCTION HASH_BER
|
#define HASH_FUNCTION HASH_BER
|
||||||
#include "uthash.h"
|
#include "uthash.h"
|
||||||
|
|
||||||
typedef struct strpool {
|
#define HOSTLIST_POOL_FLAG_STRICT_MATCH 1
|
||||||
char *str; /* key */
|
|
||||||
UT_hash_handle hh; /* makes this structure hashable */
|
|
||||||
} strpool;
|
|
||||||
|
|
||||||
void StrPoolDestroy(strpool **pp);
|
typedef struct hostlist_pool {
|
||||||
bool StrPoolAddStr(strpool **pp,const char *s);
|
char *str; /* key */
|
||||||
bool StrPoolAddStrLen(strpool **pp,const char *s,size_t slen);
|
uint32_t flags; /* custom data */
|
||||||
bool StrPoolCheckStr(strpool *p,const char *s);
|
UT_hash_handle hh; /* makes this structure hashable */
|
||||||
|
} hostlist_pool;
|
||||||
|
|
||||||
|
void HostlistPoolDestroy(hostlist_pool **pp);
|
||||||
|
bool HostlistPoolAddStr(hostlist_pool **pp, const char *s, uint32_t flags);
|
||||||
|
bool HostlistPoolAddStrLen(hostlist_pool **pp, const char *s, size_t slen, uint32_t flags);
|
||||||
|
hostlist_pool *HostlistPoolGetStr(hostlist_pool *p, const char *s);
|
||||||
|
|
||||||
struct str_list {
|
struct str_list {
|
||||||
char *str;
|
char *str;
|
||||||
@ -29,10 +32,10 @@ struct str_list {
|
|||||||
LIST_HEAD(str_list_head, str_list);
|
LIST_HEAD(str_list_head, str_list);
|
||||||
|
|
||||||
typedef struct hostfail_pool {
|
typedef struct hostfail_pool {
|
||||||
char *str; /* key */
|
char *str; /* key */
|
||||||
int counter; /* value */
|
int counter; /* value */
|
||||||
time_t expire; /* when to expire record (unixtime) */
|
time_t expire; /* when to expire record (unixtime) */
|
||||||
UT_hash_handle hh; /* makes this structure hashable */
|
UT_hash_handle hh; /* makes this structure hashable */
|
||||||
} hostfail_pool;
|
} hostfail_pool;
|
||||||
|
|
||||||
void HostFailPoolDestroy(hostfail_pool **pp);
|
void HostFailPoolDestroy(hostfail_pool **pp);
|
||||||
@ -50,8 +53,8 @@ void strlist_destroy(struct str_list_head *head);
|
|||||||
|
|
||||||
struct hostlist_file {
|
struct hostlist_file {
|
||||||
char *filename;
|
char *filename;
|
||||||
time_t mod_time;
|
file_mod_sig mod_sig;
|
||||||
strpool *hostlist;
|
hostlist_pool *hostlist;
|
||||||
LIST_ENTRY(hostlist_file) next;
|
LIST_ENTRY(hostlist_file) next;
|
||||||
};
|
};
|
||||||
LIST_HEAD(hostlist_files_head, hostlist_file);
|
LIST_HEAD(hostlist_files_head, hostlist_file);
|
||||||
@ -59,6 +62,7 @@ LIST_HEAD(hostlist_files_head, hostlist_file);
|
|||||||
struct hostlist_file *hostlist_files_add(struct hostlist_files_head *head, const char *filename);
|
struct hostlist_file *hostlist_files_add(struct hostlist_files_head *head, const char *filename);
|
||||||
void hostlist_files_destroy(struct hostlist_files_head *head);
|
void hostlist_files_destroy(struct hostlist_files_head *head);
|
||||||
struct hostlist_file *hostlist_files_search(struct hostlist_files_head *head, const char *filename);
|
struct hostlist_file *hostlist_files_search(struct hostlist_files_head *head, const char *filename);
|
||||||
|
void hostlist_files_reset_modtime(struct hostlist_files_head *list);
|
||||||
|
|
||||||
struct hostlist_item {
|
struct hostlist_item {
|
||||||
struct hostlist_file *hfile;
|
struct hostlist_file *hfile;
|
||||||
@ -111,7 +115,7 @@ void ipsetPrint(ipset *ipset);
|
|||||||
|
|
||||||
struct ipset_file {
|
struct ipset_file {
|
||||||
char *filename;
|
char *filename;
|
||||||
time_t mod_time;
|
file_mod_sig mod_sig;
|
||||||
ipset ipset;
|
ipset ipset;
|
||||||
LIST_ENTRY(ipset_file) next;
|
LIST_ENTRY(ipset_file) next;
|
||||||
};
|
};
|
||||||
@ -120,6 +124,7 @@ LIST_HEAD(ipset_files_head, ipset_file);
|
|||||||
struct ipset_file *ipset_files_add(struct ipset_files_head *head, const char *filename);
|
struct ipset_file *ipset_files_add(struct ipset_files_head *head, const char *filename);
|
||||||
void ipset_files_destroy(struct ipset_files_head *head);
|
void ipset_files_destroy(struct ipset_files_head *head);
|
||||||
struct ipset_file *ipset_files_search(struct ipset_files_head *head, const char *filename);
|
struct ipset_file *ipset_files_search(struct ipset_files_head *head, const char *filename);
|
||||||
|
void ipset_files_reset_modtime(struct ipset_files_head *list);
|
||||||
|
|
||||||
struct ipset_item {
|
struct ipset_item {
|
||||||
struct ipset_file *hfile;
|
struct ipset_file *hfile;
|
||||||
|
@ -339,6 +339,20 @@ size_t HttpPos(uint8_t posmarker, int16_t pos, const uint8_t *data, size_t sz)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const char *TLSVersionStr(uint16_t tlsver)
|
||||||
|
{
|
||||||
|
switch(tlsver)
|
||||||
|
{
|
||||||
|
case 0x0301: return "TLS 1.0";
|
||||||
|
case 0x0302: return "TLS 1.1";
|
||||||
|
case 0x0303: return "TLS 1.2";
|
||||||
|
case 0x0304: return "TLS 1.3";
|
||||||
|
default:
|
||||||
|
// 0x0a0a, 0x1a1a, ..., 0xfafa
|
||||||
|
return (((tlsver & 0x0F0F) == 0x0A0A) && ((tlsver>>12)==((tlsver>>4)&0xF))) ? "GREASE" : "UNKNOWN";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
uint16_t TLSRecordDataLen(const uint8_t *data)
|
uint16_t TLSRecordDataLen(const uint8_t *data)
|
||||||
{
|
{
|
||||||
return pntoh16(data + 3);
|
return pntoh16(data + 3);
|
||||||
|
@ -53,6 +53,7 @@ int HttpReplyCode(const uint8_t *data, size_t len);
|
|||||||
// must be pre-checked by IsHttpReply
|
// must be pre-checked by IsHttpReply
|
||||||
bool HttpReplyLooksLikeDPIRedirect(const uint8_t *data, size_t len, const char *host);
|
bool HttpReplyLooksLikeDPIRedirect(const uint8_t *data, size_t len, const char *host);
|
||||||
|
|
||||||
|
const char *TLSVersionStr(uint16_t tlsver);
|
||||||
uint16_t TLSRecordDataLen(const uint8_t *data);
|
uint16_t TLSRecordDataLen(const uint8_t *data);
|
||||||
size_t TLSRecordLen(const uint8_t *data);
|
size_t TLSRecordLen(const uint8_t *data);
|
||||||
bool IsTLSRecordFull(const uint8_t *data, size_t len);
|
bool IsTLSRecordFull(const uint8_t *data, size_t len);
|
||||||
|
@ -263,7 +263,7 @@ bool can_drop_root(void)
|
|||||||
{
|
{
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
// has some caps
|
// has some caps
|
||||||
return checkpcap((1<<CAP_SETUID)|(1<<CAP_SETGID)|(1<<CAP_SETPCAP));
|
return checkpcap((1<<CAP_SETUID)|(1<<CAP_SETGID));
|
||||||
#else
|
#else
|
||||||
// effective root
|
// effective root
|
||||||
return !geteuid();
|
return !geteuid();
|
||||||
@ -295,11 +295,7 @@ bool droproot(uid_t uid, gid_t gid)
|
|||||||
DLOG_PERROR("setuid");
|
DLOG_PERROR("setuid");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#ifdef __linux__
|
|
||||||
return dropcaps();
|
|
||||||
#else
|
|
||||||
return true;
|
return true;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_id(void)
|
void print_id(void)
|
||||||
|
@ -15,6 +15,81 @@ void packet_debug(const uint8_t *data, size_t sz)
|
|||||||
hexdump_limited_dlog(data, sz, PKTDATA_MAXDUMP); VPRINT("\n");
|
hexdump_limited_dlog(data, sz, PKTDATA_MAXDUMP); VPRINT("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void TLSDebugHandshake(const uint8_t *tls,size_t sz)
|
||||||
|
{
|
||||||
|
if (!params.debug) return;
|
||||||
|
|
||||||
|
if (sz<6) return;
|
||||||
|
|
||||||
|
const uint8_t *ext;
|
||||||
|
size_t len,len2;
|
||||||
|
|
||||||
|
uint16_t v_handshake=pntoh16(tls+4), v, v2;
|
||||||
|
VPRINT("TLS handshake version : %s\n",TLSVersionStr(v_handshake));
|
||||||
|
|
||||||
|
if (TLSFindExtInHandshake(tls,sz,43,&ext,&len,false))
|
||||||
|
{
|
||||||
|
if (len)
|
||||||
|
{
|
||||||
|
len2 = ext[0];
|
||||||
|
if (len2<len)
|
||||||
|
{
|
||||||
|
for(ext++,len2&=~1 ; len2 ; len2-=2,ext+=2)
|
||||||
|
{
|
||||||
|
v = pntoh16(ext);
|
||||||
|
VPRINT("TLS supported versions ext : %s\n",TLSVersionStr(v));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
VPRINT("TLS supported versions ext : not present\n");
|
||||||
|
|
||||||
|
if (TLSFindExtInHandshake(tls,sz,16,&ext,&len,false))
|
||||||
|
{
|
||||||
|
if (len>=2)
|
||||||
|
{
|
||||||
|
len2 = pntoh16(ext);
|
||||||
|
if (len2<=(len-2))
|
||||||
|
{
|
||||||
|
char s[32];
|
||||||
|
for(ext+=2; len2 ;)
|
||||||
|
{
|
||||||
|
v = *ext; ext++; len2--;
|
||||||
|
if (v<=len2)
|
||||||
|
{
|
||||||
|
v2 = v<sizeof(s) ? v : sizeof(s)-1;
|
||||||
|
memcpy(s,ext,v2);
|
||||||
|
s[v2]=0;
|
||||||
|
VPRINT("TLS ALPN ext : %s\n",s);
|
||||||
|
len2-=v;
|
||||||
|
ext+=v;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
VPRINT("TLS ALPN ext : not present\n");
|
||||||
|
|
||||||
|
VPRINT("TLS ECH ext : %s\n",TLSFindExtInHandshake(tls,sz,65037,NULL,NULL,false) ? "present" : "not present");
|
||||||
|
}
|
||||||
|
static void TLSDebug(const uint8_t *tls,size_t sz)
|
||||||
|
{
|
||||||
|
if (!params.debug) return;
|
||||||
|
|
||||||
|
if (sz<11) return;
|
||||||
|
|
||||||
|
VPRINT("TLS record layer version : %s\n",TLSVersionStr(pntoh16(tls+1)));
|
||||||
|
|
||||||
|
size_t reclen=TLSRecordLen(tls);
|
||||||
|
if (reclen<sz) sz=reclen; // correct len if it has more data than the first tls record has
|
||||||
|
|
||||||
|
TLSDebugHandshake(tls+5,sz-5);
|
||||||
|
}
|
||||||
|
|
||||||
static bool dp_match(struct desync_profile *dp, const struct sockaddr *dest, const char *hostname, t_l7proto l7proto)
|
static bool dp_match(struct desync_profile *dp, const struct sockaddr *dest, const char *hostname, t_l7proto l7proto)
|
||||||
{
|
{
|
||||||
bool bHostlistsEmpty;
|
bool bHostlistsEmpty;
|
||||||
@ -130,6 +205,7 @@ void tamper_out(t_ctrack *ctrack, const struct sockaddr *dest, uint8_t *segment,
|
|||||||
{
|
{
|
||||||
VPRINT("Data block contains TLS ClientHello\n");
|
VPRINT("Data block contains TLS ClientHello\n");
|
||||||
l7proto=TLS;
|
l7proto=TLS;
|
||||||
|
TLSDebug(segment,*size);
|
||||||
bHaveHost=TLSHelloExtractHost((uint8_t*)segment,*size,Host,sizeof(Host),false);
|
bHaveHost=TLSHelloExtractHost((uint8_t*)segment,*size,Host,sizeof(Host),false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -433,7 +509,7 @@ static void auto_hostlist_failed(struct desync_profile *dp, const char *hostname
|
|||||||
{
|
{
|
||||||
VPRINT("auto hostlist (profile %d) : adding %s to %s\n", dp->n, hostname, dp->hostlist_auto->filename);
|
VPRINT("auto hostlist (profile %d) : adding %s to %s\n", dp->n, hostname, dp->hostlist_auto->filename);
|
||||||
HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : client %s : proto %s : adding to %s", hostname, dp->n, client_ip_port, l7proto_str(l7proto), dp->hostlist_auto->filename);
|
HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : client %s : proto %s : adding to %s", hostname, dp->n, client_ip_port, l7proto_str(l7proto), dp->hostlist_auto->filename);
|
||||||
if (!StrPoolAddStr(&dp->hostlist_auto->hostlist, hostname))
|
if (!HostlistPoolAddStr(&dp->hostlist_auto->hostlist, hostname, 0))
|
||||||
{
|
{
|
||||||
DLOG_ERR("StrPoolAddStr out of memory\n");
|
DLOG_ERR("StrPoolAddStr out of memory\n");
|
||||||
return;
|
return;
|
||||||
@ -443,7 +519,8 @@ static void auto_hostlist_failed(struct desync_profile *dp, const char *hostname
|
|||||||
DLOG_PERROR("write to auto hostlist:");
|
DLOG_PERROR("write to auto hostlist:");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dp->hostlist_auto->mod_time = file_mod_time(dp->hostlist_auto->filename);
|
if (!file_mod_signature(dp->hostlist_auto->filename, &dp->hostlist_auto->mod_sig))
|
||||||
|
DLOG_PERROR("file_mod_signature");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
501
tpws/tpws.c
501
tpws/tpws.c
@ -50,10 +50,31 @@
|
|||||||
#define MAX_CONFIG_FILE_SIZE 16384
|
#define MAX_CONFIG_FILE_SIZE 16384
|
||||||
|
|
||||||
struct params_s params;
|
struct params_s params;
|
||||||
|
static bool bReload=false;
|
||||||
|
|
||||||
static void onhup(int sig)
|
static void onhup(int sig)
|
||||||
{
|
{
|
||||||
printf("HUP received !\n");
|
printf("HUP received ! Lists will be reloaded.\n");
|
||||||
|
bReload=true;
|
||||||
|
}
|
||||||
|
void ReloadCheck()
|
||||||
|
{
|
||||||
|
if (bReload)
|
||||||
|
{
|
||||||
|
ResetAllHostlistsModTime();
|
||||||
|
if (!LoadAllHostLists())
|
||||||
|
{
|
||||||
|
DLOG_ERR("hostlists load failed. this is fatal.\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
ResetAllIpsetModTime();
|
||||||
|
if (!LoadAllIpsets())
|
||||||
|
{
|
||||||
|
DLOG_ERR("ipset load failed. this is fatal.\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
bReload=false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void onusr2(int sig)
|
static void onusr2(int sig)
|
||||||
@ -95,6 +116,27 @@ static int8_t block_sigpipe(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool test_list_files()
|
||||||
|
{
|
||||||
|
struct hostlist_file *hfile;
|
||||||
|
struct ipset_file *ifile;
|
||||||
|
|
||||||
|
LIST_FOREACH(hfile, ¶ms.hostlists, next)
|
||||||
|
if (hfile->filename && !file_open_test(hfile->filename, O_RDONLY))
|
||||||
|
{
|
||||||
|
DLOG_PERROR("file_open_test");
|
||||||
|
DLOG_ERR("cannot access hostlist file '%s'\n",hfile->filename);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
LIST_FOREACH(ifile, ¶ms.ipsets, next)
|
||||||
|
if (ifile->filename && !file_open_test(ifile->filename, O_RDONLY))
|
||||||
|
{
|
||||||
|
DLOG_PERROR("file_open_test");
|
||||||
|
DLOG_ERR("cannot access ipset file '%s'\n",ifile->filename);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static bool is_interface_online(const char *ifname)
|
static bool is_interface_online(const char *ifname)
|
||||||
{
|
{
|
||||||
@ -176,6 +218,7 @@ static void exithelp(void)
|
|||||||
" --debug=0|1|2|syslog|@<filename>\t; 1 and 2 means log to console and set debug level. for other targets use --debug-level.\n"
|
" --debug=0|1|2|syslog|@<filename>\t; 1 and 2 means log to console and set debug level. for other targets use --debug-level.\n"
|
||||||
" --debug-level=0|1|2\t\t\t; specify debug level\n"
|
" --debug-level=0|1|2\t\t\t; specify debug level\n"
|
||||||
" --dry-run\t\t\t\t; verify parameters and exit with code 0 if successful\n"
|
" --dry-run\t\t\t\t; verify parameters and exit with code 0 if successful\n"
|
||||||
|
" --version\t\t\t\t; print version and exit\n"
|
||||||
" --comment=any_text\n"
|
" --comment=any_text\n"
|
||||||
"\nMULTI-STRATEGY:\n"
|
"\nMULTI-STRATEGY:\n"
|
||||||
" --new\t\t\t\t\t; begin new strategy\n"
|
" --new\t\t\t\t\t; begin new strategy\n"
|
||||||
@ -490,7 +533,7 @@ static bool parse_pf_list(char *opt, struct port_filters_head *pfl)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool parse_domain_list(char *opt, strpool **pp)
|
static bool parse_domain_list(char *opt, hostlist_pool **pp)
|
||||||
{
|
{
|
||||||
char *e,*p,c;
|
char *e,*p,c;
|
||||||
|
|
||||||
@ -567,6 +610,188 @@ static bool check_oob_disorder(const struct desync_profile *dp)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
enum opt_indices {
|
||||||
|
IDX_HELP,
|
||||||
|
IDX_H,
|
||||||
|
IDX_BIND_ADDR,
|
||||||
|
IDX_BIND_IFACE4,
|
||||||
|
IDX_BIND_IFACE6,
|
||||||
|
IDX_BIND_LINKLOCAL,
|
||||||
|
IDX_BIND_WAIT_IFUP,
|
||||||
|
IDX_BIND_WAIT_IP,
|
||||||
|
IDX_BIND_WAIT_IP_LINKLOCAL,
|
||||||
|
IDX_BIND_WAIT_ONLY,
|
||||||
|
IDX_PORT,
|
||||||
|
IDX_DAEMON,
|
||||||
|
IDX_USER,
|
||||||
|
IDX_UID,
|
||||||
|
IDX_MAXCONN,
|
||||||
|
IDX_MAXFILES,
|
||||||
|
IDX_MAX_ORPHAN_TIME,
|
||||||
|
IDX_HOSTCASE,
|
||||||
|
IDX_HOSTSPELL,
|
||||||
|
IDX_HOSTDOT,
|
||||||
|
IDX_HOSTNOSPACE,
|
||||||
|
IDX_HOSTPAD,
|
||||||
|
IDX_DOMCASE,
|
||||||
|
IDX_SPLIT_HTTP_REQ,
|
||||||
|
IDX_SPLIT_TLS,
|
||||||
|
IDX_SPLIT_POS,
|
||||||
|
IDX_SPLIT_ANY_PROTOCOL,
|
||||||
|
IDX_DISORDER,
|
||||||
|
IDX_OOB,
|
||||||
|
IDX_OOB_DATA,
|
||||||
|
IDX_METHODSPACE,
|
||||||
|
IDX_METHODEOL,
|
||||||
|
IDX_HOSTTAB,
|
||||||
|
IDX_UNIXEOL,
|
||||||
|
IDX_TLSREC,
|
||||||
|
IDX_TLSREC_POS,
|
||||||
|
IDX_HOSTLIST,
|
||||||
|
IDX_HOSTLIST_DOMAINS,
|
||||||
|
IDX_HOSTLIST_EXCLUDE,
|
||||||
|
IDX_HOSTLIST_EXCLUDE_DOMAINS,
|
||||||
|
IDX_HOSTLIST_AUTO,
|
||||||
|
IDX_HOSTLIST_AUTO_FAIL_THRESHOLD,
|
||||||
|
IDX_HOSTLIST_AUTO_FAIL_TIME,
|
||||||
|
IDX_HOSTLIST_AUTO_DEBUG,
|
||||||
|
IDX_PIDFILE,
|
||||||
|
IDX_DEBUG,
|
||||||
|
IDX_DEBUG_LEVEL,
|
||||||
|
IDX_DRY_RUN,
|
||||||
|
IDX_VERSION,
|
||||||
|
IDX_COMMENT,
|
||||||
|
IDX_LOCAL_RCVBUF,
|
||||||
|
IDX_LOCAL_SNDBUF,
|
||||||
|
IDX_REMOTE_RCVBUF,
|
||||||
|
IDX_REMOTE_SNDBUF,
|
||||||
|
IDX_SOCKS,
|
||||||
|
IDX_NO_RESOLVE,
|
||||||
|
IDX_RESOLVER_THREADS,
|
||||||
|
IDX_SKIP_NODELAY,
|
||||||
|
IDX_TAMPER_START,
|
||||||
|
IDX_TAMPER_CUTOFF,
|
||||||
|
IDX_CONNECT_BIND_ADDR,
|
||||||
|
|
||||||
|
IDX_NEW,
|
||||||
|
IDX_SKIP,
|
||||||
|
IDX_FILTER_L3,
|
||||||
|
IDX_FILTER_TCP,
|
||||||
|
IDX_FILTER_L7,
|
||||||
|
IDX_IPSET,
|
||||||
|
IDX_IPSET_IP,
|
||||||
|
IDX_IPSET_EXCLUDE,
|
||||||
|
IDX_IPSET_EXCLUDE_IP,
|
||||||
|
|
||||||
|
#if defined(__FreeBSD__)
|
||||||
|
IDX_ENABLE_PF,
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
IDX_LOCAL_TCP_USER_TIMEOUT,
|
||||||
|
IDX_REMOTE_TCP_USER_TIMEOUT,
|
||||||
|
#elif defined(__linux__)
|
||||||
|
IDX_LOCAL_TCP_USER_TIMEOUT,
|
||||||
|
IDX_REMOTE_TCP_USER_TIMEOUT,
|
||||||
|
IDX_MSS,
|
||||||
|
IDX_FIX_SEG,
|
||||||
|
#ifdef SPLICE_PRESENT
|
||||||
|
IDX_NOSPLICE,
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
IDX_HOSTLIST_AUTO_RETRANS_THRESHOLD, // ignored. for nfqws command line compatibility
|
||||||
|
IDX_LAST,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct option long_options[] = {
|
||||||
|
[IDX_HELP] = {"help", no_argument, 0, 0},
|
||||||
|
[IDX_H] = {"h", no_argument, 0, 0},
|
||||||
|
[IDX_BIND_ADDR] = {"bind-addr", required_argument, 0, 0},
|
||||||
|
[IDX_BIND_IFACE4] = {"bind-iface4", required_argument, 0, 0},
|
||||||
|
[IDX_BIND_IFACE6] = {"bind-iface6", required_argument, 0, 0},
|
||||||
|
[IDX_BIND_LINKLOCAL] = {"bind-linklocal", required_argument, 0, 0},
|
||||||
|
[IDX_BIND_WAIT_IFUP] = {"bind-wait-ifup", required_argument, 0, 0},
|
||||||
|
[IDX_BIND_WAIT_IP] = {"bind-wait-ip", required_argument, 0, 0},
|
||||||
|
[IDX_BIND_WAIT_IP_LINKLOCAL] = {"bind-wait-ip-linklocal", required_argument, 0, 0},
|
||||||
|
[IDX_BIND_WAIT_ONLY] = {"bind-wait-only", no_argument, 0, 0},
|
||||||
|
[IDX_PORT] = {"port", required_argument, 0, 0},
|
||||||
|
[IDX_DAEMON] = {"daemon", no_argument, 0, 0},
|
||||||
|
[IDX_USER] = {"user", required_argument, 0, 0},
|
||||||
|
[IDX_UID] = {"uid", required_argument, 0, 0},
|
||||||
|
[IDX_MAXCONN] = {"maxconn", required_argument, 0, 0},
|
||||||
|
[IDX_MAXFILES] = {"maxfiles", required_argument, 0, 0},
|
||||||
|
[IDX_MAX_ORPHAN_TIME] = {"max-orphan-time", required_argument, 0, 0},
|
||||||
|
[IDX_HOSTCASE] = {"hostcase", no_argument, 0, 0},
|
||||||
|
[IDX_HOSTSPELL] = {"hostspell", required_argument, 0, 0},
|
||||||
|
[IDX_HOSTDOT] = {"hostdot", no_argument, 0, 0},
|
||||||
|
[IDX_HOSTNOSPACE] = {"hostnospace", no_argument, 0, 0},
|
||||||
|
[IDX_HOSTPAD] = {"hostpad", required_argument, 0, 0},
|
||||||
|
[IDX_DOMCASE] = {"domcase", no_argument, 0, 0},
|
||||||
|
[IDX_SPLIT_HTTP_REQ] = {"split-http-req", required_argument, 0, 0},
|
||||||
|
[IDX_SPLIT_TLS] = {"split-tls", required_argument, 0, 0},
|
||||||
|
[IDX_SPLIT_POS] = {"split-pos", required_argument, 0, 0},
|
||||||
|
[IDX_SPLIT_ANY_PROTOCOL] = {"split-any-protocol", optional_argument, 0, 0},
|
||||||
|
[IDX_DISORDER] = {"disorder", optional_argument, 0, 0},
|
||||||
|
[IDX_OOB] = {"oob", optional_argument, 0, 0},
|
||||||
|
[IDX_OOB_DATA] = {"oob-data", required_argument, 0, 0},
|
||||||
|
[IDX_METHODSPACE] = {"methodspace", no_argument, 0, 0},
|
||||||
|
[IDX_METHODEOL] = {"methodeol", no_argument, 0, 0},
|
||||||
|
[IDX_HOSTTAB] = {"hosttab", no_argument, 0, 0},
|
||||||
|
[IDX_UNIXEOL] = {"unixeol", no_argument, 0, 0},
|
||||||
|
[IDX_TLSREC] = {"tlsrec", required_argument, 0, 0},
|
||||||
|
[IDX_TLSREC_POS] = {"tlsrec-pos", required_argument, 0, 0},
|
||||||
|
[IDX_HOSTLIST] = {"hostlist", required_argument, 0, 0},
|
||||||
|
[IDX_HOSTLIST_DOMAINS] = {"hostlist-domains", required_argument, 0, 0},
|
||||||
|
[IDX_HOSTLIST_EXCLUDE] = {"hostlist-exclude", required_argument, 0, 0},
|
||||||
|
[IDX_HOSTLIST_EXCLUDE_DOMAINS] = {"hostlist-exclude-domains", required_argument, 0, 0},
|
||||||
|
[IDX_HOSTLIST_AUTO] = {"hostlist-auto", required_argument, 0, 0},
|
||||||
|
[IDX_HOSTLIST_AUTO_FAIL_THRESHOLD] = {"hostlist-auto-fail-threshold", required_argument, 0, 0},
|
||||||
|
[IDX_HOSTLIST_AUTO_FAIL_TIME] = {"hostlist-auto-fail-time", required_argument, 0, 0},
|
||||||
|
[IDX_HOSTLIST_AUTO_DEBUG] = {"hostlist-auto-debug", required_argument, 0, 0},
|
||||||
|
[IDX_PIDFILE] = {"pidfile", required_argument, 0, 0},
|
||||||
|
[IDX_DEBUG] = {"debug", optional_argument, 0, 0},
|
||||||
|
[IDX_DEBUG_LEVEL] = {"debug-level", required_argument, 0, 0},
|
||||||
|
[IDX_DRY_RUN] = {"dry-run", no_argument, 0, 0},
|
||||||
|
[IDX_VERSION] = {"version", no_argument, 0, 0},
|
||||||
|
[IDX_COMMENT] = {"comment", optional_argument, 0, 0},
|
||||||
|
[IDX_LOCAL_RCVBUF] = {"local-rcvbuf", required_argument, 0, 0},
|
||||||
|
[IDX_LOCAL_SNDBUF] = {"local-sndbuf", required_argument, 0, 0},
|
||||||
|
[IDX_REMOTE_RCVBUF] = {"remote-rcvbuf", required_argument, 0, 0},
|
||||||
|
[IDX_REMOTE_SNDBUF] = {"remote-sndbuf", required_argument, 0, 0},
|
||||||
|
[IDX_SOCKS] = {"socks", no_argument, 0, 0},
|
||||||
|
[IDX_NO_RESOLVE] = {"no-resolve", no_argument, 0, 0},
|
||||||
|
[IDX_RESOLVER_THREADS] = {"resolver-threads", required_argument, 0, 0},
|
||||||
|
[IDX_SKIP_NODELAY] = {"skip-nodelay", no_argument, 0, 0},
|
||||||
|
[IDX_TAMPER_START] = {"tamper-start", required_argument, 0, 0},
|
||||||
|
[IDX_TAMPER_CUTOFF] = {"tamper-cutoff", required_argument, 0, 0},
|
||||||
|
[IDX_CONNECT_BIND_ADDR] = {"connect-bind-addr", required_argument, 0, 0},
|
||||||
|
|
||||||
|
[IDX_NEW] = {"new", no_argument, 0, 0},
|
||||||
|
[IDX_SKIP] = {"skip", no_argument, 0, 0},
|
||||||
|
[IDX_FILTER_L3] = {"filter-l3", required_argument, 0, 0},
|
||||||
|
[IDX_FILTER_TCP] = {"filter-tcp", required_argument, 0, 0},
|
||||||
|
[IDX_FILTER_L7] = {"filter-l7", required_argument, 0, 0},
|
||||||
|
[IDX_IPSET] = {"ipset", required_argument, 0, 0},
|
||||||
|
[IDX_IPSET_IP] = {"ipset-ip", required_argument, 0, 0},
|
||||||
|
[IDX_IPSET_EXCLUDE] = {"ipset-exclude", required_argument, 0, 0},
|
||||||
|
[IDX_IPSET_EXCLUDE_IP] = {"ipset-exclude-ip", required_argument, 0, 0},
|
||||||
|
|
||||||
|
#if defined(__FreeBSD__)
|
||||||
|
[IDX_ENABLE_PF] = {"enable-pf", no_argument, 0, 0},
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
[IDX_LOCAL_TCP_USER_TIMEOUT] = {"local-tcp-user-timeout", required_argument, 0, 0},
|
||||||
|
[IDX_REMOTE_TCP_USER_TIMEOUT] = {"remote-tcp-user-timeout", required_argument, 0, 0},
|
||||||
|
#elif defined(__linux__)
|
||||||
|
[IDX_LOCAL_TCP_USER_TIMEOUT] = {"local-tcp-user-timeout", required_argument, 0, 0},
|
||||||
|
[IDX_REMOTE_TCP_USER_TIMEOUT] = {"remote-tcp-user-timeout", required_argument, 0, 0},
|
||||||
|
[IDX_MSS] = {"mss", required_argument, 0, 0},
|
||||||
|
[IDX_FIX_SEG] = {"fix-seg", optional_argument, 0, 0},
|
||||||
|
#ifdef SPLICE_PRESENT
|
||||||
|
[IDX_NOSPLICE] = {"nosplice", no_argument, 0, 0},
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
[IDX_HOSTLIST_AUTO_RETRANS_THRESHOLD] = {"hostlist-auto-retrans-threshold", optional_argument, 0, 0},
|
||||||
|
[IDX_LAST] = {NULL, 0, NULL, 0},
|
||||||
|
};
|
||||||
|
|
||||||
void parse_params(int argc, char *argv[])
|
void parse_params(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int option_index = 0;
|
int option_index = 0;
|
||||||
@ -621,95 +846,6 @@ void parse_params(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const struct option long_options[] = {
|
|
||||||
{ "help",no_argument,0,0 },// optidx=0
|
|
||||||
{ "h",no_argument,0,0 },// optidx=1
|
|
||||||
{ "bind-addr",required_argument,0,0 },// optidx=2
|
|
||||||
{ "bind-iface4",required_argument,0,0 },// optidx=3
|
|
||||||
{ "bind-iface6",required_argument,0,0 },// optidx=4
|
|
||||||
{ "bind-linklocal",required_argument,0,0 },// optidx=5
|
|
||||||
{ "bind-wait-ifup",required_argument,0,0 },// optidx=6
|
|
||||||
{ "bind-wait-ip",required_argument,0,0 },// optidx=7
|
|
||||||
{ "bind-wait-ip-linklocal",required_argument,0,0 },// optidx=8
|
|
||||||
{ "bind-wait-only",no_argument,0,0 },// optidx=9
|
|
||||||
{ "port",required_argument,0,0 },// optidx=10
|
|
||||||
{ "daemon",no_argument,0,0 },// optidx=11
|
|
||||||
{ "user",required_argument,0,0 },// optidx=12
|
|
||||||
{ "uid",required_argument,0,0 },// optidx=13
|
|
||||||
{ "maxconn",required_argument,0,0 },// optidx=14
|
|
||||||
{ "maxfiles",required_argument,0,0 },// optidx=15
|
|
||||||
{ "max-orphan-time",required_argument,0,0 },// optidx=16
|
|
||||||
{ "hostcase",no_argument,0,0 },// optidx=17
|
|
||||||
{ "hostspell",required_argument,0,0 },// optidx=18
|
|
||||||
{ "hostdot",no_argument,0,0 },// optidx=19
|
|
||||||
{ "hostnospace",no_argument,0,0 },// optidx=20
|
|
||||||
{ "hostpad",required_argument,0,0 },// optidx=21
|
|
||||||
{ "domcase",no_argument,0,0 },// optidx=22
|
|
||||||
{ "split-http-req",required_argument,0,0 },// optidx=23
|
|
||||||
{ "split-tls",required_argument,0,0 },// optidx=24
|
|
||||||
{ "split-pos",required_argument,0,0 },// optidx=25
|
|
||||||
{ "split-any-protocol",optional_argument,0,0},// optidx=26
|
|
||||||
{ "disorder",optional_argument,0,0 },// optidx=27
|
|
||||||
{ "oob",optional_argument,0,0 },// optidx=28
|
|
||||||
{ "oob-data",required_argument,0,0 },// optidx=29
|
|
||||||
{ "methodspace",no_argument,0,0 },// optidx=30
|
|
||||||
{ "methodeol",no_argument,0,0 },// optidx=31
|
|
||||||
{ "hosttab",no_argument,0,0 },// optidx=32
|
|
||||||
{ "unixeol",no_argument,0,0 },// optidx=33
|
|
||||||
{ "tlsrec",required_argument,0,0 },// optidx=34
|
|
||||||
{ "tlsrec-pos",required_argument,0,0 },// optidx=35
|
|
||||||
{ "hostlist",required_argument,0,0 },// optidx=36
|
|
||||||
{ "hostlist-domains",required_argument,0,0 },// optidx=37
|
|
||||||
{ "hostlist-exclude",required_argument,0,0 },// optidx=38
|
|
||||||
{ "hostlist-exclude-domains",required_argument,0,0 },// optidx=39
|
|
||||||
{ "hostlist-auto",required_argument,0,0}, // optidx=40
|
|
||||||
{ "hostlist-auto-fail-threshold",required_argument,0,0}, // optidx=41
|
|
||||||
{ "hostlist-auto-fail-time",required_argument,0,0}, // optidx=42
|
|
||||||
{ "hostlist-auto-debug",required_argument,0,0}, // optidx=43
|
|
||||||
{ "pidfile",required_argument,0,0 },// optidx=44
|
|
||||||
{ "debug",optional_argument,0,0 },// optidx=45
|
|
||||||
{ "debug-level",required_argument,0,0 },// optidx=46
|
|
||||||
{ "dry-run",no_argument,0,0 },// optidx=47
|
|
||||||
{ "comment",optional_argument,0,0 },// optidx=48
|
|
||||||
{ "local-rcvbuf",required_argument,0,0 },// optidx=49
|
|
||||||
{ "local-sndbuf",required_argument,0,0 },// optidx=50
|
|
||||||
{ "remote-rcvbuf",required_argument,0,0 },// optidx=51
|
|
||||||
{ "remote-sndbuf",required_argument,0,0 },// optidx=52
|
|
||||||
{ "socks",no_argument,0,0 },// optidx=53
|
|
||||||
{ "no-resolve",no_argument,0,0 },// optidx=54
|
|
||||||
{ "resolver-threads",required_argument,0,0 },// optidx=55
|
|
||||||
{ "skip-nodelay",no_argument,0,0 },// optidx=56
|
|
||||||
{ "tamper-start",required_argument,0,0 },// optidx=57
|
|
||||||
{ "tamper-cutoff",required_argument,0,0 },// optidx=58
|
|
||||||
{ "connect-bind-addr",required_argument,0,0 },// optidx=59
|
|
||||||
|
|
||||||
{ "new",no_argument,0,0 }, // optidx=60
|
|
||||||
{ "skip",no_argument,0,0 }, // optidx=61
|
|
||||||
{ "filter-l3",required_argument,0,0 }, // optidx=62
|
|
||||||
{ "filter-tcp",required_argument,0,0 }, // optidx=63
|
|
||||||
{ "filter-l7",required_argument,0,0 }, // optidx=64
|
|
||||||
{ "ipset",required_argument,0,0 }, // optidx=65
|
|
||||||
{ "ipset-ip",required_argument,0,0 }, // optidx=66
|
|
||||||
{ "ipset-exclude",required_argument,0,0 }, // optidx=67
|
|
||||||
{ "ipset-exclude-ip",required_argument,0,0 }, // optidx=68
|
|
||||||
|
|
||||||
#if defined(__FreeBSD__)
|
|
||||||
{ "enable-pf",no_argument,0,0 },// optidx=69
|
|
||||||
#elif defined(__APPLE__)
|
|
||||||
{ "local-tcp-user-timeout",required_argument,0,0 }, // optidx=69
|
|
||||||
{ "remote-tcp-user-timeout",required_argument,0,0 }, // optidx=70
|
|
||||||
#elif defined(__linux__)
|
|
||||||
{ "local-tcp-user-timeout",required_argument,0,0 }, // optidx=69
|
|
||||||
{ "remote-tcp-user-timeout",required_argument,0,0 }, // optidx=70
|
|
||||||
{ "mss",required_argument,0,0 }, // optidx=71
|
|
||||||
{ "fix-seg",optional_argument,0,0 }, // optidx=72
|
|
||||||
#ifdef SPLICE_PRESENT
|
|
||||||
{ "nosplice",no_argument,0,0 }, // optidx=73
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
{ "hostlist-auto-retrans-threshold",optional_argument,0,0}, // ignored. for nfqws command line compatibility
|
|
||||||
{ NULL,0,NULL,0 }
|
|
||||||
};
|
|
||||||
while ((v = getopt_long_only(argc, argv, "", long_options, &option_index)) != -1)
|
while ((v = getopt_long_only(argc, argv, "", long_options, &option_index)) != -1)
|
||||||
{
|
{
|
||||||
if (v)
|
if (v)
|
||||||
@ -721,11 +857,11 @@ void parse_params(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
switch (option_index)
|
switch (option_index)
|
||||||
{
|
{
|
||||||
case 0:
|
case IDX_HELP:
|
||||||
case 1:
|
case IDX_H:
|
||||||
exithelp_clean();
|
exithelp_clean();
|
||||||
break;
|
break;
|
||||||
case 2: /* bind-addr */
|
case IDX_BIND_ADDR:
|
||||||
nextbind_clean();
|
nextbind_clean();
|
||||||
{
|
{
|
||||||
char *p = strchr(optarg,'%');
|
char *p = strchr(optarg,'%');
|
||||||
@ -738,19 +874,19 @@ void parse_params(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
params.binds[params.binds_last].bindaddr[sizeof(params.binds[params.binds_last].bindaddr) - 1] = 0;
|
params.binds[params.binds_last].bindaddr[sizeof(params.binds[params.binds_last].bindaddr) - 1] = 0;
|
||||||
break;
|
break;
|
||||||
case 3: /* bind-iface4 */
|
case IDX_BIND_IFACE4:
|
||||||
nextbind_clean();
|
nextbind_clean();
|
||||||
params.binds[params.binds_last].bind_if6=false;
|
params.binds[params.binds_last].bind_if6=false;
|
||||||
strncpy(params.binds[params.binds_last].bindiface, optarg, sizeof(params.binds[params.binds_last].bindiface));
|
strncpy(params.binds[params.binds_last].bindiface, optarg, sizeof(params.binds[params.binds_last].bindiface));
|
||||||
params.binds[params.binds_last].bindiface[sizeof(params.binds[params.binds_last].bindiface) - 1] = 0;
|
params.binds[params.binds_last].bindiface[sizeof(params.binds[params.binds_last].bindiface) - 1] = 0;
|
||||||
break;
|
break;
|
||||||
case 4: /* bind-iface6 */
|
case IDX_BIND_IFACE6:
|
||||||
nextbind_clean();
|
nextbind_clean();
|
||||||
params.binds[params.binds_last].bind_if6=true;
|
params.binds[params.binds_last].bind_if6=true;
|
||||||
strncpy(params.binds[params.binds_last].bindiface, optarg, sizeof(params.binds[params.binds_last].bindiface));
|
strncpy(params.binds[params.binds_last].bindiface, optarg, sizeof(params.binds[params.binds_last].bindiface));
|
||||||
params.binds[params.binds_last].bindiface[sizeof(params.binds[params.binds_last].bindiface) - 1] = 0;
|
params.binds[params.binds_last].bindiface[sizeof(params.binds[params.binds_last].bindiface) - 1] = 0;
|
||||||
break;
|
break;
|
||||||
case 5: /* bind-linklocal */
|
case IDX_BIND_LINKLOCAL:
|
||||||
checkbind_clean();
|
checkbind_clean();
|
||||||
params.binds[params.binds_last].bindll = true;
|
params.binds[params.binds_last].bindll = true;
|
||||||
if (!strcmp(optarg, "no"))
|
if (!strcmp(optarg, "no"))
|
||||||
@ -767,22 +903,22 @@ void parse_params(int argc, char *argv[])
|
|||||||
exit_clean(1);
|
exit_clean(1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 6: /* bind-wait-ifup */
|
case IDX_BIND_WAIT_IFUP:
|
||||||
checkbind_clean();
|
checkbind_clean();
|
||||||
params.binds[params.binds_last].bind_wait_ifup = atoi(optarg);
|
params.binds[params.binds_last].bind_wait_ifup = atoi(optarg);
|
||||||
break;
|
break;
|
||||||
case 7: /* bind-wait-ip */
|
case IDX_BIND_WAIT_IP:
|
||||||
checkbind_clean();
|
checkbind_clean();
|
||||||
params.binds[params.binds_last].bind_wait_ip = atoi(optarg);
|
params.binds[params.binds_last].bind_wait_ip = atoi(optarg);
|
||||||
break;
|
break;
|
||||||
case 8: /* bind-wait-ip-linklocal */
|
case IDX_BIND_WAIT_IP_LINKLOCAL:
|
||||||
checkbind_clean();
|
checkbind_clean();
|
||||||
params.binds[params.binds_last].bind_wait_ip_ll = atoi(optarg);
|
params.binds[params.binds_last].bind_wait_ip_ll = atoi(optarg);
|
||||||
break;
|
break;
|
||||||
case 9: /* bind-wait-only */
|
case IDX_BIND_WAIT_ONLY:
|
||||||
params.bind_wait_only = true;
|
params.bind_wait_only = true;
|
||||||
break;
|
break;
|
||||||
case 10: /* port */
|
case IDX_PORT:
|
||||||
i = atoi(optarg);
|
i = atoi(optarg);
|
||||||
if (i <= 0 || i > 65535)
|
if (i <= 0 || i > 65535)
|
||||||
{
|
{
|
||||||
@ -791,10 +927,10 @@ void parse_params(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
params.port = (uint16_t)i;
|
params.port = (uint16_t)i;
|
||||||
break;
|
break;
|
||||||
case 11: /* daemon */
|
case IDX_DAEMON:
|
||||||
params.daemon = true;
|
params.daemon = true;
|
||||||
break;
|
break;
|
||||||
case 12: /* user */
|
case IDX_USER:
|
||||||
{
|
{
|
||||||
struct passwd *pwd = getpwnam(optarg);
|
struct passwd *pwd = getpwnam(optarg);
|
||||||
if (!pwd)
|
if (!pwd)
|
||||||
@ -807,7 +943,7 @@ void parse_params(int argc, char *argv[])
|
|||||||
params.droproot = true;
|
params.droproot = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 13: /* uid */
|
case IDX_UID:
|
||||||
params.gid=0x7FFFFFFF; // default git. drop gid=0
|
params.gid=0x7FFFFFFF; // default git. drop gid=0
|
||||||
params.droproot = true;
|
params.droproot = true;
|
||||||
if (sscanf(optarg,"%u:%u",¶ms.uid,¶ms.gid)<1)
|
if (sscanf(optarg,"%u:%u",¶ms.uid,¶ms.gid)<1)
|
||||||
@ -816,7 +952,7 @@ void parse_params(int argc, char *argv[])
|
|||||||
exit_clean(1);
|
exit_clean(1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 14: /* maxconn */
|
case IDX_MAXCONN:
|
||||||
params.maxconn = atoi(optarg);
|
params.maxconn = atoi(optarg);
|
||||||
if (params.maxconn <= 0 || params.maxconn > 10000)
|
if (params.maxconn <= 0 || params.maxconn > 10000)
|
||||||
{
|
{
|
||||||
@ -824,7 +960,7 @@ void parse_params(int argc, char *argv[])
|
|||||||
exit_clean(1);
|
exit_clean(1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 15: /* maxfiles */
|
case IDX_MAXFILES:
|
||||||
params.maxfiles = atoi(optarg);
|
params.maxfiles = atoi(optarg);
|
||||||
if (params.maxfiles < 0)
|
if (params.maxfiles < 0)
|
||||||
{
|
{
|
||||||
@ -832,7 +968,7 @@ void parse_params(int argc, char *argv[])
|
|||||||
exit_clean(1);
|
exit_clean(1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 16: /* max-orphan-time */
|
case IDX_MAX_ORPHAN_TIME:
|
||||||
params.max_orphan_time = atoi(optarg);
|
params.max_orphan_time = atoi(optarg);
|
||||||
if (params.max_orphan_time < 0)
|
if (params.max_orphan_time < 0)
|
||||||
{
|
{
|
||||||
@ -840,11 +976,11 @@ void parse_params(int argc, char *argv[])
|
|||||||
exit_clean(1);
|
exit_clean(1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 17: /* hostcase */
|
case IDX_HOSTCASE:
|
||||||
dp->hostcase = true;
|
dp->hostcase = true;
|
||||||
params.tamper = true;
|
params.tamper = true;
|
||||||
break;
|
break;
|
||||||
case 18: /* hostspell */
|
case IDX_HOSTSPELL:
|
||||||
if (strlen(optarg) != 4)
|
if (strlen(optarg) != 4)
|
||||||
{
|
{
|
||||||
DLOG_ERR("hostspell must be exactly 4 chars long\n");
|
DLOG_ERR("hostspell must be exactly 4 chars long\n");
|
||||||
@ -854,23 +990,23 @@ void parse_params(int argc, char *argv[])
|
|||||||
memcpy(dp->hostspell, optarg, 4);
|
memcpy(dp->hostspell, optarg, 4);
|
||||||
params.tamper = true;
|
params.tamper = true;
|
||||||
break;
|
break;
|
||||||
case 19: /* hostdot */
|
case IDX_HOSTDOT:
|
||||||
dp->hostdot = true;
|
dp->hostdot = true;
|
||||||
params.tamper = true;
|
params.tamper = true;
|
||||||
break;
|
break;
|
||||||
case 20: /* hostnospace */
|
case IDX_HOSTNOSPACE:
|
||||||
dp->hostnospace = true;
|
dp->hostnospace = true;
|
||||||
params.tamper = true;
|
params.tamper = true;
|
||||||
break;
|
break;
|
||||||
case 21: /* hostpad */
|
case IDX_HOSTPAD:
|
||||||
dp->hostpad = atoi(optarg);
|
dp->hostpad = atoi(optarg);
|
||||||
params.tamper = true;
|
params.tamper = true;
|
||||||
break;
|
break;
|
||||||
case 22: /* domcase */
|
case IDX_DOMCASE:
|
||||||
dp->domcase = true;
|
dp->domcase = true;
|
||||||
params.tamper = true;
|
params.tamper = true;
|
||||||
break;
|
break;
|
||||||
case 23: /* split-http-req */
|
case IDX_SPLIT_HTTP_REQ:
|
||||||
DLOG_CONDUP("WARNING ! --split-http-req is deprecated. use --split-pos with markers.\n",MAX_SPLITS);
|
DLOG_CONDUP("WARNING ! --split-http-req is deprecated. use --split-pos with markers.\n",MAX_SPLITS);
|
||||||
if (dp->split_count>=MAX_SPLITS)
|
if (dp->split_count>=MAX_SPLITS)
|
||||||
{
|
{
|
||||||
@ -885,7 +1021,7 @@ void parse_params(int argc, char *argv[])
|
|||||||
dp->split_count++;
|
dp->split_count++;
|
||||||
params.tamper = true;
|
params.tamper = true;
|
||||||
break;
|
break;
|
||||||
case 24: /* split-tls */
|
case IDX_SPLIT_TLS:
|
||||||
// obsolete arg
|
// obsolete arg
|
||||||
DLOG_CONDUP("WARNING ! --split-tls is deprecated. use --split-pos with markers.\n",MAX_SPLITS);
|
DLOG_CONDUP("WARNING ! --split-tls is deprecated. use --split-pos with markers.\n",MAX_SPLITS);
|
||||||
if (dp->split_count>=MAX_SPLITS)
|
if (dp->split_count>=MAX_SPLITS)
|
||||||
@ -901,7 +1037,7 @@ void parse_params(int argc, char *argv[])
|
|||||||
dp->split_count++;
|
dp->split_count++;
|
||||||
params.tamper = true;
|
params.tamper = true;
|
||||||
break;
|
break;
|
||||||
case 25: /* split-pos */
|
case IDX_SPLIT_POS:
|
||||||
{
|
{
|
||||||
int ct;
|
int ct;
|
||||||
if (!parse_split_pos_list(optarg,dp->splits+dp->split_count,MAX_SPLITS-dp->split_count,&ct))
|
if (!parse_split_pos_list(optarg,dp->splits+dp->split_count,MAX_SPLITS-dp->split_count,&ct))
|
||||||
@ -913,10 +1049,10 @@ void parse_params(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
params.tamper = true;
|
params.tamper = true;
|
||||||
break;
|
break;
|
||||||
case 26: /* split-any-protocol */
|
case IDX_SPLIT_ANY_PROTOCOL:
|
||||||
dp->split_any_protocol = true;
|
dp->split_any_protocol = true;
|
||||||
break;
|
break;
|
||||||
case 27: /* disorder */
|
case IDX_DISORDER:
|
||||||
if (optarg)
|
if (optarg)
|
||||||
{
|
{
|
||||||
if (!strcmp(optarg,"http")) dp->disorder_http=true;
|
if (!strcmp(optarg,"http")) dp->disorder_http=true;
|
||||||
@ -937,7 +1073,7 @@ void parse_params(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
case 28: /* oob */
|
case IDX_OOB:
|
||||||
if (optarg)
|
if (optarg)
|
||||||
{
|
{
|
||||||
if (!strcmp(optarg,"http")) dp->oob_http=true;
|
if (!strcmp(optarg,"http")) dp->oob_http=true;
|
||||||
@ -958,7 +1094,7 @@ void parse_params(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
case 29: /* oob-data */
|
case IDX_OOB_DATA:
|
||||||
{
|
{
|
||||||
size_t l = strlen(optarg);
|
size_t l = strlen(optarg);
|
||||||
unsigned int bt;
|
unsigned int bt;
|
||||||
@ -971,23 +1107,23 @@ void parse_params(int argc, char *argv[])
|
|||||||
else dp->oob_byte = (uint8_t)bt;
|
else dp->oob_byte = (uint8_t)bt;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 30: /* methodspace */
|
case IDX_METHODSPACE:
|
||||||
dp->methodspace = true;
|
dp->methodspace = true;
|
||||||
params.tamper = true;
|
params.tamper = true;
|
||||||
break;
|
break;
|
||||||
case 31: /* methodeol */
|
case IDX_METHODEOL:
|
||||||
dp->methodeol = true;
|
dp->methodeol = true;
|
||||||
params.tamper = true;
|
params.tamper = true;
|
||||||
break;
|
break;
|
||||||
case 32: /* hosttab */
|
case IDX_HOSTTAB:
|
||||||
dp->hosttab = true;
|
dp->hosttab = true;
|
||||||
params.tamper = true;
|
params.tamper = true;
|
||||||
break;
|
break;
|
||||||
case 33: /* unixeol */
|
case IDX_UNIXEOL:
|
||||||
dp->unixeol = true;
|
dp->unixeol = true;
|
||||||
params.tamper = true;
|
params.tamper = true;
|
||||||
break;
|
break;
|
||||||
case 34: /* tlsrec */
|
case IDX_TLSREC:
|
||||||
if (!parse_split_pos(optarg, &dp->tlsrec) && !parse_tlspos(optarg, &dp->tlsrec))
|
if (!parse_split_pos(optarg, &dp->tlsrec) && !parse_tlspos(optarg, &dp->tlsrec))
|
||||||
{
|
{
|
||||||
DLOG_ERR("Invalid argument for tlsrec\n");
|
DLOG_ERR("Invalid argument for tlsrec\n");
|
||||||
@ -995,7 +1131,7 @@ void parse_params(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
params.tamper = true;
|
params.tamper = true;
|
||||||
break;
|
break;
|
||||||
case 35: /* tlsrec-pos */
|
case IDX_TLSREC_POS:
|
||||||
// obsolete arg
|
// obsolete arg
|
||||||
i = atoi(optarg);
|
i = atoi(optarg);
|
||||||
dp->tlsrec.marker = PM_ABS;
|
dp->tlsrec.marker = PM_ABS;
|
||||||
@ -1007,7 +1143,7 @@ void parse_params(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
params.tamper = true;
|
params.tamper = true;
|
||||||
break;
|
break;
|
||||||
case 36: /* hostlist */
|
case IDX_HOSTLIST:
|
||||||
if (bSkip) break;
|
if (bSkip) break;
|
||||||
if (!RegisterHostlist(dp, false, optarg))
|
if (!RegisterHostlist(dp, false, optarg))
|
||||||
{
|
{
|
||||||
@ -1016,7 +1152,7 @@ void parse_params(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
params.tamper = true;
|
params.tamper = true;
|
||||||
break;
|
break;
|
||||||
case 37: /* hostlist-domains */
|
case IDX_HOSTLIST_DOMAINS:
|
||||||
if (bSkip) break;
|
if (bSkip) break;
|
||||||
if (!anon_hl && !(anon_hl=RegisterHostlist(dp, false, NULL)))
|
if (!anon_hl && !(anon_hl=RegisterHostlist(dp, false, NULL)))
|
||||||
{
|
{
|
||||||
@ -1030,7 +1166,7 @@ void parse_params(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
params.tamper = true;
|
params.tamper = true;
|
||||||
break;
|
break;
|
||||||
case 38: /* hostlist-exclude */
|
case IDX_HOSTLIST_EXCLUDE:
|
||||||
if (bSkip) break;
|
if (bSkip) break;
|
||||||
if (!RegisterHostlist(dp, true, optarg))
|
if (!RegisterHostlist(dp, true, optarg))
|
||||||
{
|
{
|
||||||
@ -1039,7 +1175,7 @@ void parse_params(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
params.tamper = true;
|
params.tamper = true;
|
||||||
break;
|
break;
|
||||||
case 39: /* hostlist-exclude-domains */
|
case IDX_HOSTLIST_EXCLUDE_DOMAINS:
|
||||||
if (bSkip) break;
|
if (bSkip) break;
|
||||||
if (!anon_hl_exclude && !(anon_hl_exclude=RegisterHostlist(dp, true, NULL)))
|
if (!anon_hl_exclude && !(anon_hl_exclude=RegisterHostlist(dp, true, NULL)))
|
||||||
{
|
{
|
||||||
@ -1053,7 +1189,7 @@ void parse_params(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
params.tamper = true;
|
params.tamper = true;
|
||||||
break;
|
break;
|
||||||
case 40: /* hostlist-auto */
|
case IDX_HOSTLIST_AUTO:
|
||||||
if (bSkip) break;
|
if (bSkip) break;
|
||||||
if (dp->hostlist_auto)
|
if (dp->hostlist_auto)
|
||||||
{
|
{
|
||||||
@ -1082,7 +1218,7 @@ void parse_params(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
params.tamper = true; // need to detect blocks and update autohostlist. cannot just slice.
|
params.tamper = true; // need to detect blocks and update autohostlist. cannot just slice.
|
||||||
break;
|
break;
|
||||||
case 41: /* hostlist-auto-fail-threshold */
|
case IDX_HOSTLIST_AUTO_FAIL_THRESHOLD:
|
||||||
dp->hostlist_auto_fail_threshold = (uint8_t)atoi(optarg);
|
dp->hostlist_auto_fail_threshold = (uint8_t)atoi(optarg);
|
||||||
if (dp->hostlist_auto_fail_threshold<1 || dp->hostlist_auto_fail_threshold>20)
|
if (dp->hostlist_auto_fail_threshold<1 || dp->hostlist_auto_fail_threshold>20)
|
||||||
{
|
{
|
||||||
@ -1090,7 +1226,7 @@ void parse_params(int argc, char *argv[])
|
|||||||
exit_clean(1);
|
exit_clean(1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 42: /* hostlist-auto-fail-time */
|
case IDX_HOSTLIST_AUTO_FAIL_TIME:
|
||||||
dp->hostlist_auto_fail_time = (uint8_t)atoi(optarg);
|
dp->hostlist_auto_fail_time = (uint8_t)atoi(optarg);
|
||||||
if (dp->hostlist_auto_fail_time<1)
|
if (dp->hostlist_auto_fail_time<1)
|
||||||
{
|
{
|
||||||
@ -1098,7 +1234,7 @@ void parse_params(int argc, char *argv[])
|
|||||||
exit_clean(1);
|
exit_clean(1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 43: /* hostlist-auto-debug */
|
case IDX_HOSTLIST_AUTO_DEBUG:
|
||||||
{
|
{
|
||||||
FILE *F = fopen(optarg,"a+t");
|
FILE *F = fopen(optarg,"a+t");
|
||||||
if (!F)
|
if (!F)
|
||||||
@ -1111,11 +1247,11 @@ void parse_params(int argc, char *argv[])
|
|||||||
params.hostlist_auto_debuglog[sizeof(params.hostlist_auto_debuglog) - 1] = '\0';
|
params.hostlist_auto_debuglog[sizeof(params.hostlist_auto_debuglog) - 1] = '\0';
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 44: /* pidfile */
|
case IDX_PIDFILE:
|
||||||
strncpy(params.pidfile,optarg,sizeof(params.pidfile));
|
strncpy(params.pidfile,optarg,sizeof(params.pidfile));
|
||||||
params.pidfile[sizeof(params.pidfile)-1]='\0';
|
params.pidfile[sizeof(params.pidfile)-1]='\0';
|
||||||
break;
|
break;
|
||||||
case 45: /* debug */
|
case IDX_DEBUG:
|
||||||
if (optarg)
|
if (optarg)
|
||||||
{
|
{
|
||||||
if (*optarg=='@')
|
if (*optarg=='@')
|
||||||
@ -1149,49 +1285,52 @@ void parse_params(int argc, char *argv[])
|
|||||||
params.debug_target = LOG_TARGET_CONSOLE;
|
params.debug_target = LOG_TARGET_CONSOLE;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 46: /* debug-level */
|
case IDX_DEBUG_LEVEL:
|
||||||
params.debug = atoi(optarg);
|
params.debug = atoi(optarg);
|
||||||
break;
|
break;
|
||||||
case 47: /* dry-run */
|
case IDX_DRY_RUN:
|
||||||
bDry = true;
|
bDry = true;
|
||||||
break;
|
break;
|
||||||
case 48: /* comment */
|
case IDX_VERSION:
|
||||||
|
exit_clean(0);
|
||||||
break;
|
break;
|
||||||
case 49: /* local-rcvbuf */
|
case IDX_COMMENT:
|
||||||
|
break;
|
||||||
|
case IDX_LOCAL_RCVBUF:
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
params.local_rcvbuf = atoi(optarg)/2;
|
params.local_rcvbuf = atoi(optarg)/2;
|
||||||
#else
|
#else
|
||||||
params.local_rcvbuf = atoi(optarg);
|
params.local_rcvbuf = atoi(optarg);
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
case 50: /* local-sndbuf */
|
case IDX_LOCAL_SNDBUF:
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
params.local_sndbuf = atoi(optarg)/2;
|
params.local_sndbuf = atoi(optarg)/2;
|
||||||
#else
|
#else
|
||||||
params.local_sndbuf = atoi(optarg);
|
params.local_sndbuf = atoi(optarg);
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
case 51: /* remote-rcvbuf */
|
case IDX_REMOTE_RCVBUF:
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
params.remote_rcvbuf = atoi(optarg)/2;
|
params.remote_rcvbuf = atoi(optarg)/2;
|
||||||
#else
|
#else
|
||||||
params.remote_rcvbuf = atoi(optarg);
|
params.remote_rcvbuf = atoi(optarg);
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
case 52: /* remote-sndbuf */
|
case IDX_REMOTE_SNDBUF:
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
params.remote_sndbuf = atoi(optarg)/2;
|
params.remote_sndbuf = atoi(optarg)/2;
|
||||||
#else
|
#else
|
||||||
params.remote_sndbuf = atoi(optarg);
|
params.remote_sndbuf = atoi(optarg);
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
case 53: /* socks */
|
case IDX_SOCKS:
|
||||||
params.proxy_type = CONN_TYPE_SOCKS;
|
params.proxy_type = CONN_TYPE_SOCKS;
|
||||||
break;
|
break;
|
||||||
case 54: /* no-resolve */
|
case IDX_NO_RESOLVE:
|
||||||
params.no_resolve = true;
|
params.no_resolve = true;
|
||||||
break;
|
break;
|
||||||
case 55: /* resolver-threads */
|
case IDX_RESOLVER_THREADS:
|
||||||
params.resolver_threads = atoi(optarg);
|
params.resolver_threads = atoi(optarg);
|
||||||
if (params.resolver_threads<1 || params.resolver_threads>300)
|
if (params.resolver_threads<1 || params.resolver_threads>300)
|
||||||
{
|
{
|
||||||
@ -1199,10 +1338,10 @@ void parse_params(int argc, char *argv[])
|
|||||||
exit_clean(1);
|
exit_clean(1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 56: /* skip-nodelay */
|
case IDX_SKIP_NODELAY:
|
||||||
params.skip_nodelay = true;
|
params.skip_nodelay = true;
|
||||||
break;
|
break;
|
||||||
case 57: /* tamper-start */
|
case IDX_TAMPER_START:
|
||||||
{
|
{
|
||||||
const char *p=optarg;
|
const char *p=optarg;
|
||||||
if (*p=='n')
|
if (*p=='n')
|
||||||
@ -1216,7 +1355,7 @@ void parse_params(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
params.tamper_lim = true;
|
params.tamper_lim = true;
|
||||||
break;
|
break;
|
||||||
case 58: /* tamper-cutoff */
|
case IDX_TAMPER_CUTOFF:
|
||||||
{
|
{
|
||||||
const char *p=optarg;
|
const char *p=optarg;
|
||||||
if (*p=='n')
|
if (*p=='n')
|
||||||
@ -1230,7 +1369,7 @@ void parse_params(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
params.tamper_lim = true;
|
params.tamper_lim = true;
|
||||||
break;
|
break;
|
||||||
case 59: /* connect-bind-addr */
|
case IDX_CONNECT_BIND_ADDR:
|
||||||
{
|
{
|
||||||
char *p = strchr(optarg,'%');
|
char *p = strchr(optarg,'%');
|
||||||
if (p) *p++=0;
|
if (p) *p++=0;
|
||||||
@ -1258,7 +1397,7 @@ void parse_params(int argc, char *argv[])
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
case 60: /* new */
|
case IDX_NEW:
|
||||||
if (bSkip)
|
if (bSkip)
|
||||||
{
|
{
|
||||||
dp_clear(dp);
|
dp_clear(dp);
|
||||||
@ -1279,31 +1418,31 @@ void parse_params(int argc, char *argv[])
|
|||||||
anon_hl = anon_hl_exclude = NULL;
|
anon_hl = anon_hl_exclude = NULL;
|
||||||
anon_ips = anon_ips_exclude = NULL;
|
anon_ips = anon_ips_exclude = NULL;
|
||||||
break;
|
break;
|
||||||
case 61: /* skip */
|
case IDX_SKIP:
|
||||||
bSkip = true;
|
bSkip = true;
|
||||||
break;
|
break;
|
||||||
case 62: /* filter-l3 */
|
case IDX_FILTER_L3:
|
||||||
if (!wf_make_l3(optarg,&dp->filter_ipv4,&dp->filter_ipv6))
|
if (!wf_make_l3(optarg,&dp->filter_ipv4,&dp->filter_ipv6))
|
||||||
{
|
{
|
||||||
DLOG_ERR("bad value for --filter-l3\n");
|
DLOG_ERR("bad value for --filter-l3\n");
|
||||||
exit_clean(1);
|
exit_clean(1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 63: /* filter-tcp */
|
case IDX_FILTER_TCP:
|
||||||
if (!parse_pf_list(optarg,&dp->pf_tcp))
|
if (!parse_pf_list(optarg,&dp->pf_tcp))
|
||||||
{
|
{
|
||||||
DLOG_ERR("Invalid port filter : %s\n",optarg);
|
DLOG_ERR("Invalid port filter : %s\n",optarg);
|
||||||
exit_clean(1);
|
exit_clean(1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 64: /* filter-l7 */
|
case IDX_FILTER_L7:
|
||||||
if (!parse_l7_list(optarg,&dp->filter_l7))
|
if (!parse_l7_list(optarg,&dp->filter_l7))
|
||||||
{
|
{
|
||||||
DLOG_ERR("Invalid l7 filter : %s\n",optarg);
|
DLOG_ERR("Invalid l7 filter : %s\n",optarg);
|
||||||
exit_clean(1);
|
exit_clean(1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 65: /* ipset */
|
case IDX_IPSET:
|
||||||
if (bSkip) break;
|
if (bSkip) break;
|
||||||
if (!RegisterIpset(dp, false, optarg))
|
if (!RegisterIpset(dp, false, optarg))
|
||||||
{
|
{
|
||||||
@ -1312,7 +1451,7 @@ void parse_params(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
params.tamper = true;
|
params.tamper = true;
|
||||||
break;
|
break;
|
||||||
case 66: /* ipset-ip */
|
case IDX_IPSET_IP:
|
||||||
if (bSkip) break;
|
if (bSkip) break;
|
||||||
if (!anon_ips && !(anon_ips=RegisterIpset(dp, false, NULL)))
|
if (!anon_ips && !(anon_ips=RegisterIpset(dp, false, NULL)))
|
||||||
{
|
{
|
||||||
@ -1326,7 +1465,7 @@ void parse_params(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
params.tamper = true;
|
params.tamper = true;
|
||||||
break;
|
break;
|
||||||
case 67: /* ipset-exclude */
|
case IDX_IPSET_EXCLUDE:
|
||||||
if (bSkip) break;
|
if (bSkip) break;
|
||||||
if (!RegisterIpset(dp, true, optarg))
|
if (!RegisterIpset(dp, true, optarg))
|
||||||
{
|
{
|
||||||
@ -1335,7 +1474,7 @@ void parse_params(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
params.tamper = true;
|
params.tamper = true;
|
||||||
break;
|
break;
|
||||||
case 68: /* ipset-exclude-ip */
|
case IDX_IPSET_EXCLUDE_IP:
|
||||||
if (bSkip) break;
|
if (bSkip) break;
|
||||||
if (!anon_ips_exclude && !(anon_ips_exclude=RegisterIpset(dp, true, NULL)))
|
if (!anon_ips_exclude && !(anon_ips_exclude=RegisterIpset(dp, true, NULL)))
|
||||||
{
|
{
|
||||||
@ -1351,11 +1490,11 @@ void parse_params(int argc, char *argv[])
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
#if defined(__FreeBSD__)
|
#if defined(__FreeBSD__)
|
||||||
case 69: /* enable-pf */
|
case IDX_ENABLE_PF:
|
||||||
params.pf_enable = true;
|
params.pf_enable = true;
|
||||||
break;
|
break;
|
||||||
#elif defined(__linux__) || defined(__APPLE__)
|
#elif defined(__linux__) || defined(__APPLE__)
|
||||||
case 69: /* local-tcp-user-timeout */
|
case IDX_LOCAL_TCP_USER_TIMEOUT:
|
||||||
params.tcp_user_timeout_local = atoi(optarg);
|
params.tcp_user_timeout_local = atoi(optarg);
|
||||||
if (params.tcp_user_timeout_local<0 || params.tcp_user_timeout_local>86400)
|
if (params.tcp_user_timeout_local<0 || params.tcp_user_timeout_local>86400)
|
||||||
{
|
{
|
||||||
@ -1363,7 +1502,7 @@ void parse_params(int argc, char *argv[])
|
|||||||
exit_clean(1);
|
exit_clean(1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 70: /* remote-tcp-user-timeout */
|
case IDX_REMOTE_TCP_USER_TIMEOUT:
|
||||||
params.tcp_user_timeout_remote = atoi(optarg);
|
params.tcp_user_timeout_remote = atoi(optarg);
|
||||||
if (params.tcp_user_timeout_remote<0 || params.tcp_user_timeout_remote>86400)
|
if (params.tcp_user_timeout_remote<0 || params.tcp_user_timeout_remote>86400)
|
||||||
{
|
{
|
||||||
@ -1374,7 +1513,7 @@ void parse_params(int argc, char *argv[])
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__linux__)
|
#if defined(__linux__)
|
||||||
case 71: /* mss */
|
case IDX_MSS:
|
||||||
// this option does not work in any BSD and MacOS. OS may accept but it changes nothing
|
// this option does not work in any BSD and MacOS. OS may accept but it changes nothing
|
||||||
dp->mss = atoi(optarg);
|
dp->mss = atoi(optarg);
|
||||||
if (dp->mss<88 || dp->mss>32767)
|
if (dp->mss<88 || dp->mss>32767)
|
||||||
@ -1383,7 +1522,7 @@ void parse_params(int argc, char *argv[])
|
|||||||
exit_clean(1);
|
exit_clean(1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 72: /* fix-seg */
|
case IDX_FIX_SEG:
|
||||||
if (!params.fix_seg_avail)
|
if (!params.fix_seg_avail)
|
||||||
{
|
{
|
||||||
DLOG_ERR("--fix-seg is supported since kernel 4.6\n");
|
DLOG_ERR("--fix-seg is supported since kernel 4.6\n");
|
||||||
@ -1403,7 +1542,7 @@ void parse_params(int argc, char *argv[])
|
|||||||
params.fix_seg = FIX_SEG_DEFAULT_MAX_WAIT;
|
params.fix_seg = FIX_SEG_DEFAULT_MAX_WAIT;
|
||||||
break;
|
break;
|
||||||
#ifdef SPLICE_PRESENT
|
#ifdef SPLICE_PRESENT
|
||||||
case 73: /* nosplice */
|
case IDX_NOSPLICE:
|
||||||
params.nosplice = true;
|
params.nosplice = true;
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
@ -1427,7 +1566,7 @@ void parse_params(int argc, char *argv[])
|
|||||||
params.binds_last=0; // default bind to all
|
params.binds_last=0; // default bind to all
|
||||||
}
|
}
|
||||||
if (!params.resolver_threads) params.resolver_threads = 5 + params.maxconn/50;
|
if (!params.resolver_threads) params.resolver_threads = 5 + params.maxconn/50;
|
||||||
|
|
||||||
VPRINT("adding low-priority default empty desync profile\n");
|
VPRINT("adding low-priority default empty desync profile\n");
|
||||||
// add default empty profile
|
// add default empty profile
|
||||||
if (!(dpl = dp_list_add(¶ms.desync_profiles)))
|
if (!(dpl = dp_list_add(¶ms.desync_profiles)))
|
||||||
@ -1443,6 +1582,10 @@ void parse_params(int argc, char *argv[])
|
|||||||
fprintf(stderr, "could not chown %s. log file may not be writable after privilege drop\n", params.debug_logfile);
|
fprintf(stderr, "could not chown %s. log file may not be writable after privilege drop\n", params.debug_logfile);
|
||||||
if (params.droproot && *params.hostlist_auto_debuglog && chown(params.hostlist_auto_debuglog, params.uid, -1))
|
if (params.droproot && *params.hostlist_auto_debuglog && chown(params.hostlist_auto_debuglog, params.uid, -1))
|
||||||
DLOG_ERR("could not chown %s. auto hostlist debug log may not be writable after privilege drop\n", params.hostlist_auto_debuglog);
|
DLOG_ERR("could not chown %s. auto hostlist debug log may not be writable after privilege drop\n", params.hostlist_auto_debuglog);
|
||||||
|
|
||||||
|
#ifdef __linux__
|
||||||
|
bool bHasMSS=false, bHasOOB=false, bHasDisorder=false;
|
||||||
|
#endif
|
||||||
LIST_FOREACH(dpl, ¶ms.desync_profiles, next)
|
LIST_FOREACH(dpl, ¶ms.desync_profiles, next)
|
||||||
{
|
{
|
||||||
dp = &dpl->dp;
|
dp = &dpl->dp;
|
||||||
@ -1453,7 +1596,22 @@ void parse_params(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
if (params.droproot && dp->hostlist_auto && chown(dp->hostlist_auto->filename, params.uid, -1))
|
if (params.droproot && dp->hostlist_auto && chown(dp->hostlist_auto->filename, params.uid, -1))
|
||||||
DLOG_ERR("could not chown %s. auto hostlist file may not be writable after privilege drop\n", dp->hostlist_auto->filename);
|
DLOG_ERR("could not chown %s. auto hostlist file may not be writable after privilege drop\n", dp->hostlist_auto->filename);
|
||||||
|
#ifdef __linux__
|
||||||
|
if (dp->mss) bHasMSS=true;
|
||||||
|
if (dp->oob || dp->oob_http || dp->oob_tls) bHasOOB=true;
|
||||||
|
if (dp->disorder || dp->disorder_http || dp->disorder_tls) bHasDisorder=true;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
#ifdef __linux__
|
||||||
|
if (is_wsl()==1)
|
||||||
|
{
|
||||||
|
if (!params.nosplice) DLOG_CONDUP("WARNING ! WSL1 may have problems with splice. Consider using `--nosplice`.\n");
|
||||||
|
if (bHasMSS) DLOG_CONDUP("WARNING ! WSL1 does not support MSS socket option. MSS will likely fail.\n");
|
||||||
|
if (bHasOOB) DLOG_CONDUP("WARNING ! WSL1 does not support OOB. OOB will likely fail.\n");
|
||||||
|
if (bHasDisorder) DLOG_CONDUP("WARNING ! Windows retransmits whole TCP segment. Disorder will not function properly.\n");
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!LoadAllHostLists())
|
if (!LoadAllHostLists())
|
||||||
{
|
{
|
||||||
@ -1647,6 +1805,7 @@ int main(int argc, char *argv[])
|
|||||||
struct salisten_s list[MAX_BINDS];
|
struct salisten_s list[MAX_BINDS];
|
||||||
char ip_port[48];
|
char ip_port[48];
|
||||||
|
|
||||||
|
set_console_io_buffering();
|
||||||
set_env_exedir(argv[0]);
|
set_env_exedir(argv[0]);
|
||||||
srand(time(NULL));
|
srand(time(NULL));
|
||||||
mask_from_preflen6_prepare();
|
mask_from_preflen6_prepare();
|
||||||
@ -1897,10 +2056,16 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
set_ulimit();
|
set_ulimit();
|
||||||
sec_harden();
|
sec_harden();
|
||||||
|
|
||||||
if (params.droproot && !droproot(params.uid,params.gid))
|
if (params.droproot && !droproot(params.uid,params.gid))
|
||||||
goto exiterr;
|
goto exiterr;
|
||||||
|
#ifdef __linux__
|
||||||
|
if (!dropcaps())
|
||||||
|
goto exiterr;
|
||||||
|
#endif
|
||||||
print_id();
|
print_id();
|
||||||
|
if (params.droproot && !test_list_files())
|
||||||
|
goto exiterr;
|
||||||
|
|
||||||
//splice() causes the process to receive the SIGPIPE-signal if one part (for
|
//splice() causes the process to receive the SIGPIPE-signal if one part (for
|
||||||
//example a socket) is closed during splice(). I would rather have splice()
|
//example a socket) is closed during splice(). I would rather have splice()
|
||||||
//fail and return -1, so blocking SIGPIPE.
|
//fail and return -1, so blocking SIGPIPE.
|
||||||
|
@ -6,4 +6,4 @@
|
|||||||
|
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
|
|
||||||
void dohup(void);
|
void ReloadCheck();
|
||||||
|
@ -16,6 +16,10 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
|
|
||||||
|
#ifdef USE_SYSTEMD
|
||||||
|
#include <systemd/sd-daemon.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "tpws.h"
|
#include "tpws.h"
|
||||||
#include "tpws_conn.h"
|
#include "tpws_conn.h"
|
||||||
#include "redirect.h"
|
#include "redirect.h"
|
||||||
@ -25,6 +29,15 @@
|
|||||||
#include "hostlist.h"
|
#include "hostlist.h"
|
||||||
#include "linux_compat.h"
|
#include "linux_compat.h"
|
||||||
|
|
||||||
|
static void notify_ready(void)
|
||||||
|
{
|
||||||
|
#ifdef USE_SYSTEMD
|
||||||
|
int r = sd_notify(0, "READY=1");
|
||||||
|
if (r < 0)
|
||||||
|
DLOG_ERR("sd_notify: %s\n", strerror(-r));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
// keep separate legs counter. counting every time thousands of legs can consume cpu
|
// keep separate legs counter. counting every time thousands of legs can consume cpu
|
||||||
static int legs_local, legs_remote;
|
static int legs_local, legs_remote;
|
||||||
/*
|
/*
|
||||||
@ -169,11 +182,8 @@ static bool send_buffer_realloc(send_buffer_t *sb, size_t extra_bytes)
|
|||||||
|
|
||||||
static void send_buffer_free(send_buffer_t *sb)
|
static void send_buffer_free(send_buffer_t *sb)
|
||||||
{
|
{
|
||||||
if (sb->data)
|
free(sb->data);
|
||||||
{
|
sb->data = NULL;
|
||||||
free(sb->data);
|
|
||||||
sb->data = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
static void send_buffers_free(send_buffer_t *sb_array, int count)
|
static void send_buffers_free(send_buffer_t *sb_array, int count)
|
||||||
{
|
{
|
||||||
@ -520,7 +530,7 @@ static void free_conn(tproxy_conn_t *conn)
|
|||||||
}
|
}
|
||||||
conn_free_buffers(conn);
|
conn_free_buffers(conn);
|
||||||
if (conn->partner) conn->partner->partner=NULL;
|
if (conn->partner) conn->partner->partner=NULL;
|
||||||
if (conn->track.hostname) free(conn->track.hostname);
|
free(conn->track.hostname);
|
||||||
if (conn->socks_ri) conn->socks_ri->ptr = NULL; // detach conn
|
if (conn->socks_ri) conn->socks_ri->ptr = NULL; // detach conn
|
||||||
free(conn);
|
free(conn);
|
||||||
}
|
}
|
||||||
@ -1545,8 +1555,12 @@ int event_loop(const int *listen_fd, size_t listen_fd_ct)
|
|||||||
VPRINT("initialized multi threaded resolver with %d threads\n",resolver_thread_count());
|
VPRINT("initialized multi threaded resolver with %d threads\n",resolver_thread_count());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
notify_ready();
|
||||||
|
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
|
ReloadCheck();
|
||||||
|
|
||||||
DBGPRINT("epoll_wait\n");
|
DBGPRINT("epoll_wait\n");
|
||||||
|
|
||||||
if ((num_events = epoll_wait(efd, events, MAX_EPOLL_EVENTS, -1)) == -1)
|
if ((num_events = epoll_wait(efd, events, MAX_EPOLL_EVENTS, -1)) == -1)
|
||||||
@ -1756,13 +1770,11 @@ int event_loop(const int *listen_fd, size_t listen_fd_ct)
|
|||||||
// at least one leg was removed. recount legs
|
// at least one leg was removed. recount legs
|
||||||
print_legs();
|
print_legs();
|
||||||
}
|
}
|
||||||
|
|
||||||
fflush(stderr); fflush(stdout); // for console messages
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ex:
|
ex:
|
||||||
if (efd) close(efd);
|
if (efd) close(efd);
|
||||||
if (listen_conn) free(listen_conn);
|
free(listen_conn);
|
||||||
resolver_deinit();
|
resolver_deinit();
|
||||||
if (resolve_pipe[0]) close(resolve_pipe[0]);
|
if (resolve_pipe[0]) close(resolve_pipe[0]);
|
||||||
if (resolve_pipe[1]) close(resolve_pipe[1]);
|
if (resolve_pipe[1]) close(resolve_pipe[1]);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user