60 Commits

Author SHA1 Message Date
Lorekin
06e364a2ef Merge 92ba6b439e into 8324c04a41 2024-12-04 11:45:15 +03:00
bol-van
8324c04a41 Update windows.md 2024-12-04 10:59:57 +03:00
bol-van
166847ba92 Update windows.en.md 2024-12-04 10:59:22 +03:00
bol-van
1904f01cf4 Update windows.en.md 2024-12-04 10:58:25 +03:00
bol-van
4ae1ad053d Update windows.md 2024-12-04 10:57:09 +03:00
bol-van
7d9946b007 update docs 2024-12-03 18:23:13 +03:00
bol-van
86462f4cee update docs 2024-12-03 18:20:46 +03:00
bol-van
669182c133 install_easy: trim trailing space in editor 2024-12-03 17:33:02 +03:00
bol-van
f81bb51f4a install_easy: validate daemon options 2024-12-03 17:22:16 +03:00
bol-van
d4ff423add tpws: --dry-run 2024-12-03 15:57:21 +03:00
bol-van
b14ff9b647 nfqws: --dry-run 2024-12-03 15:56:37 +03:00
bol-van
277c5f9e00 update docs 2024-12-02 21:06:05 +03:00
bol-van
f016e5a4dc nfqws: customize fakedsplit pattern 2024-12-02 20:03:52 +03:00
bol-van
fc3912b4fe nfqws: improve fakedsplit/fakeddisorder with more fakes 2024-12-02 13:14:01 +03:00
bol-van
c01a764e1f init.d: sysv fix route_localnet with multiple IFACE_LAN 2024-12-01 21:21:08 +03:00
Lorekin
92ba6b439e Add script to get antifilter domains 2024-11-27 23:58:54 +03:00
bol-van
4ecb40e03b Merge pull request #891 from spvkgn/fix-actions
github: minor
2024-11-27 16:28:16 +03:00
spvkgn
be9c300cb3 github: minor 2024-11-27 18:10:56 +05:00
bol-van
839c720f60 Merge pull request #888 from spvkgn/fix-actions
github: fix optimization for size
2024-11-27 14:51:12 +03:00
spvkgn
127bec2f14 github: fix optimization for size 2024-11-27 15:34:46 +05:00
spvkgn
15879c82f6 github: minor 2024-11-27 12:02:13 +05:00
bol-van
9d188840c1 blockcheck: eliminate multipos in fakedsplit and fakeddisorder 2024-11-25 18:16:16 +03:00
bol-van
35a28f4efe blockcheck: old dash compat 2024-11-25 12:39:12 +03:00
bol-van
78ea379e0f quick_start: light release notice 2024-11-24 18:00:01 +03:00
bol-van
007cbe600b update docs 2024-11-24 17:10:01 +03:00
bol-van
d1a8e276b5 update docs 2024-11-24 17:06:23 +03:00
bol-van
eb2f5b5f45 nfqws,tpws: ip->subnet in help text 2024-11-24 17:06:04 +03:00
bol-van
a623cef95d nfqws: fixed lists 2024-11-24 16:48:14 +03:00
bol-van
f00b45a28e tpws: fixed list fixes 2024-11-24 16:47:51 +03:00
bol-van
422faaa29c tpws: fixed ipset and hostlist 2024-11-24 16:03:13 +03:00
bol-van
16a9e3f9c9 github: sha256sum, remove tpws_wsl.tgz in openwrt ver 2024-11-24 13:27:57 +03:00
bol-van
7c5869bc29 display versions 2024-11-24 11:51:49 +03:00
bol-van
feb3dd4d73 issue_template warnings 2024-11-24 10:28:04 +03:00
bol-van
b4204ca2ba github: remote Makefile in light ver 2024-11-23 21:20:03 +03:00
bol-van
89a67e6952 github: tar releases with root owner 2024-11-23 21:17:19 +03:00
bol-van
34199b151c github: separate embedded linux archive 2024-11-23 20:26:58 +03:00
bol-van
c6962f575e install_bin: search win64 and win32 in CYGWIN 2024-11-23 20:07:26 +03:00
bol-van
9c8662b25e nfqws,tpws: fix crash 2024-11-23 14:14:12 +03:00
bol-van
fedb62df66 update docs 2024-11-23 13:28:34 +03:00
bol-van
44c19c1743 blockcheck: --methodeol test for nfqws 2024-11-23 13:20:02 +03:00
bol-van
56aa481226 nfqws: warn if cannot do hostnospace 2024-11-23 13:17:34 +03:00
bol-van
9184317549 nfqws: --methodeol 2024-11-23 13:14:02 +03:00
bol-van
a3048ae120 nfqws: --skip 2024-11-23 12:55:14 +03:00
bol-van
fc44d74f2b fix lto in nfqws makefile 2024-11-23 12:33:15 +03:00
bol-van
1779cfad30 tpws: --skip 2024-11-23 12:17:49 +03:00
bol-van
4856be4ef1 init.d: do not use pgrep for firmwares compatibility 2024-11-23 10:58:46 +03:00
bol-van
033043bdc0 tpws: remote duplicate if 2024-11-22 13:04:06 +03:00
bol-van
46284938ce tpws: fix socks-hostname hostlist checks 2024-11-22 12:42:33 +03:00
bol-van
09378553b9 keenetic script check disable ipv4 2024-11-21 20:35:27 +03:00
bol-van
6b85884cdf update keentic fix script 2024-11-21 20:30:23 +03:00
bol-van
1b14a8210c readme: more precise marker definition 2024-11-21 15:44:18 +03:00
bol-van
182fe850db makefiles: use lto 2024-11-21 15:25:19 +03:00
bol-van
62b081e9fb doc works 2024-11-21 10:47:11 +03:00
bol-van
e3e7449d74 doc works 2024-11-21 10:44:52 +03:00
bol-van
669f1978a3 doc works 2024-11-21 10:02:32 +03:00
bol-van
57c4b1a2b2 fix grep in default_route_interfaces6 2024-11-20 17:21:16 +03:00
bol-van
ac7385391e 10-keenetic-udp-fix: auto discover wan interfaces 2024-11-19 22:09:40 +03:00
bol-van
50a52d79ec default_route_interfaces helpers 2024-11-19 22:08:48 +03:00
bol-van
d77a1c8cd6 init.d: keenetic udp fix script 2024-11-19 19:54:21 +03:00
bol-van
395b9480c5 nfqws: fix wrong printf format 2024-11-19 19:27:36 +03:00
43 changed files with 1528 additions and 684 deletions

10
.github/issue_template.md vendored Normal file
View File

@@ -0,0 +1,10 @@
1. Здесь не место для вопросов, касающихся компьютерной грамотности и навыков использования ОС
2. Здесь не место для вопросов "у меня не работает" без технических подробностей
3. Здесь не место для вопросов "как мне открыть ютуб" или "что писать в ..."
4. Здесь не место для обсуждения сборок
5. Вирусов здесь нет. У вас либо чья-то сборка, либо ваш антивирус давно пора отправить на покой. Не согласны - удаляйте софт.
Все означенное обсуждать в дискуссиях или на форумах.
При нарушении будет закрываться или конвертироваться в дискуссии.
Issue только для обсуждения проблем самого софта. Неработа стратегии или ваше неумение настроить - это ваша проблема, а не проблема софта.

View File

@@ -82,10 +82,6 @@ jobs:
export STRIP=$TARGET-strip
export PKG_CONFIG_PATH=$DEPS_DIR/lib/pkgconfig
# optimize for size
export CFLAGS="-Os -flto=auto"
export LDFLAGS="-Os"
# 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/libmnl/libmnl-1.0.5.tar.bz2 | tar -xj
@@ -94,6 +90,7 @@ jobs:
for i in libmnl libnfnetlink libnetfilter_queue ; do
(
cd $i-*
CFLAGS="-Os -flto=auto" \
./configure --prefix= --host=$TARGET --enable-static --disable-shared --disable-dependency-tracking
make install -j$(nproc) DESTDIR=$DEPS_DIR
)
@@ -105,6 +102,7 @@ jobs:
xargs -I{} wget -qO- https://github.com/madler/zlib/archive/refs/tags/{}.tar.gz | tar -xz
(
cd zlib-*
CFLAGS="-Os -flto=auto" \
./configure --prefix= --static
make install -j$(nproc) DESTDIR=$DEPS_DIR
)
@@ -115,8 +113,8 @@ jobs:
install -Dm644 -t $DEPS_DIR/include/sys /usr/include/x86_64-linux-gnu/sys/queue.h /usr/include/sys/capability.h
# zapret
CFLAGS="$CFLAGS -static-libgcc -static -I$DEPS_DIR/include" \
LDFLAGS="$LDFLAGS -L$DEPS_DIR/lib" \
CFLAGS="-DZAPRET_GH_VER=${{ github.ref_name }} -DZAPRET_GH_HASH=${{ github.sha }} -static-libgcc -static -I$DEPS_DIR/include" \
LDFLAGS="-L$DEPS_DIR/lib" \
make -C zapret -j$(nproc)
tar -C zapret/binaries/my -cJf zapret-linux-$ARCH.tar.xz .
@@ -136,6 +134,7 @@ jobs:
- name: Build zapret
run: |
export CFLAGS="-DZAPRET_GH_VER=${{ github.ref_name }} -DZAPRET_GH_HASH=${{ github.sha }}"
make mac -j$(sysctl -n hw.logicalcpu)
tar -C binaries/my -cJf zapret-mac-x64.tar.xz .
@@ -170,7 +169,8 @@ jobs:
TARGET: ${{ matrix.target }}
ARCH: ${{ matrix.arch }}
run: |
settarget $TARGET-freebsd11 make bsd -j$(nproc) || exit 1
export CFLAGS="-DZAPRET_GH_VER=${{ github.ref_name }} -DZAPRET_GH_HASH=${{ github.sha }}"
settarget $TARGET-freebsd11 make bsd -j$(nproc)
tar -C binaries/my -cJf zapret-freebsd-$ARCH.tar.xz .
- name: Upload artifacts
@@ -203,6 +203,7 @@ jobs:
- name: Build ip2net, mdig
shell: msys2 {0}
run: |
export CFLAGS="-DZAPRET_GH_VER=${{ github.ref_name }} -DZAPRET_GH_HASH=${{ github.sha }}"
mkdir -p output
cd zapret
mingw32-make -C ip2net win
@@ -259,6 +260,7 @@ jobs:
shell: C:\cygwin\bin\bash.exe -eo pipefail '{0}'
run: >-
export MAKEFLAGS=-j$(nproc) &&
export CFLAGS="-DZAPRET_GH_VER=${{ github.ref_name }} -DZAPRET_GH_HASH=${{ github.sha }}" &&
cd zapret &&
make -C nfq ${TARGET} &&
cp -a nfq/winws.exe ../output
@@ -317,10 +319,6 @@ jobs:
export STRIP=$TOOLCHAIN/bin/llvm-strip
export PKG_CONFIG_PATH=$DEPS_DIR/lib/pkgconfig
# optimize for size
export CFLAGS="-Os -flto=auto"
export LDFLAGS="-Os"
# 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/libmnl/libmnl-1.0.5.tar.bz2 | tar -xj
@@ -330,7 +328,7 @@ jobs:
for i in libmnl libnfnetlink libnetfilter_queue ; do
(
cd $i-*
CFLAGS="$CFLAGS -Wno-implicit-function-declaration" \
CFLAGS="-Os -flto=auto -Wno-implicit-function-declaration" \
./configure --prefix= --host=$TARGET --enable-static --disable-shared --disable-dependency-tracking
make install -j$(nproc) DESTDIR=$DEPS_DIR
)
@@ -338,7 +336,8 @@ jobs:
done
# zapret
CFLAGS="$CFLAGS -I$DEPS_DIR/include" LDFLAGS="$LDFLAGS -L$DEPS_DIR/lib" \
CFLAGS="-DZAPRET_GH_VER=${{ github.ref_name }} -DZAPRET_GH_HASH=${{ github.sha }} -I$DEPS_DIR/include" \
LDFLAGS="-L$DEPS_DIR/lib" \
make -C zapret android -j$(nproc)
zip zapret-android-$ABI.zip -j zapret/binaries/my/*
@@ -434,8 +433,16 @@ jobs:
- name: Create release bundles
run: |
rm -rf ${{ env.repo_dir }}/.git*
tar -czf ${{ env.repo_dir }}.tar.gz ${{ env.repo_dir }}
find ${{ env.repo_dir }}/binaries -type f -exec sha256sum {} \; >sha256sum.txt
tar --owner=0 --group=0 -czf ${{ env.repo_dir }}.tar.gz ${{ env.repo_dir }}
zip -qr ${{ env.repo_dir }}.zip ${{ env.repo_dir }}
(
cd ${{ env.repo_dir }}
rm -rf binaries/{android*,freebsd*,mac*,win*,x86_64/tpws_wsl.tgz} \
init.d/{openrc,macos,pfsense,runit,s6,systemd} \
tpws nfq ip2net mdig docs files/huawei Makefile
)
tar --owner=0 --group=0 -czf ${{ env.repo_dir }}-openwrt-embedded.tar.gz ${{ env.repo_dir }}
- name: Upload release assets
uses: softprops/action-gh-release@v2
@@ -448,3 +455,4 @@ jobs:
files: |
zapret*.tar.gz
zapret*.zip
sha256sum.txt

View File

@@ -1011,11 +1011,10 @@ tpws_curl_test()
echo - checking tpws $3 $4 $5 $6 $7 $8 $9${TPWS_EXTRA:+ $TPWS_EXTRA}${TPWS_EXTRA_1:+ "$TPWS_EXTRA_1"}${TPWS_EXTRA_2:+ "$TPWS_EXTRA_2"}${TPWS_EXTRA_3:+ "$TPWS_EXTRA_3"}${TPWS_EXTRA_4:+ "$TPWS_EXTRA_4"}${TPWS_EXTRA_5:+ "$TPWS_EXTRA_5"}${TPWS_EXTRA_6:+ "$TPWS_EXTRA_6"}${TPWS_EXTRA_7:+ "$TPWS_EXTRA_7"}${TPWS_EXTRA_8:+ "$TPWS_EXTRA_8"}${TPWS_EXTRA_9:+ "$TPWS_EXTRA_9"}
local ALL_PROXY="socks5://127.0.0.1:$SOCKS_PORT"
ws_curl_test tpws_start "$@"${TPWS_EXTRA:+ $TPWS_EXTRA}${TPWS_EXTRA_1:+ "$TPWS_EXTRA_1"}${TPWS_EXTRA_2:+ "$TPWS_EXTRA_2"}${TPWS_EXTRA_3:+ "$TPWS_EXTRA_3"}${TPWS_EXTRA_4:+ "$TPWS_EXTRA_4"}${TPWS_EXTRA_5:+ "$TPWS_EXTRA_5"}${TPWS_EXTRA_6:+ "$TPWS_EXTRA_6"}${TPWS_EXTRA_7:+ "$TPWS_EXTRA_7"}${TPWS_EXTRA_8:+ "$TPWS_EXTRA_8"}${TPWS_EXTRA_9:+ "$TPWS_EXTRA_9"}
local code=$?
local testf=$1 dom=$2 strategy code=$?
[ "$code" = 0 ] && {
local testf=$1 dom=$2
shift; shift;
local strategy="$@"
strategy="$@"
strategy_append_extra_tpws
report_append "ipv${IPV} $dom $testf : tpws ${WF:+$WF }$strategy"
}
@@ -1028,11 +1027,10 @@ pktws_curl_test()
# $3,$4,$5, ... - nfqws/dvtws params
echo - checking $PKTWSD ${WF:+$WF }$3 $4 $5 $6 $7 $8 $9${PKTWS_EXTRA:+ $PKTWS_EXTRA}${PKTWS_EXTRA_1:+ "$PKTWS_EXTRA_1"}${PKTWS_EXTRA_2:+ "$PKTWS_EXTRA_2"}${PKTWS_EXTRA_3:+ "$PKTWS_EXTRA_3"}${PKTWS_EXTRA_4:+ "$PKTWS_EXTRA_4"}${PKTWS_EXTRA_5:+ "$PKTWS_EXTRA_5"}${PKTWS_EXTRA_6:+ "$PKTWS_EXTRA_6"}${PKTWS_EXTRA_7:+ "$PKTWS_EXTRA_7"}${PKTWS_EXTRA_8:+ "$PKTWS_EXTRA_8"}${PKTWS_EXTRA_9:+ "$PKTWS_EXTRA_9"}
ws_curl_test pktws_start "$@"${PKTWS_EXTRA:+ $PKTWS_EXTRA}${PKTWS_EXTRA_1:+ "$PKTWS_EXTRA_1"}${PKTWS_EXTRA_2:+ "$PKTWS_EXTRA_2"}${PKTWS_EXTRA_3:+ "$PKTWS_EXTRA_3"}${PKTWS_EXTRA_4:+ "$PKTWS_EXTRA_4"}${PKTWS_EXTRA_5:+ "$PKTWS_EXTRA_5"}${PKTWS_EXTRA_6:+ "$PKTWS_EXTRA_6"}${PKTWS_EXTRA_7:+ "$PKTWS_EXTRA_7"}${PKTWS_EXTRA_8:+ "$PKTWS_EXTRA_8"}${PKTWS_EXTRA_9:+ "$PKTWS_EXTRA_9"}
local code=$?
local testf=$1 dom=$2 strategy code=$?
[ "$code" = 0 ] && {
local testf=$1 dom=$2
shift; shift;
local strategy="$@"
strategy="$@"
strategy_append_extra_pktws
report_append "ipv${IPV} $dom $testf : $PKTWSD ${WF:+$WF }$strategy"
}
@@ -1112,6 +1110,10 @@ test_has_split()
{
contains "$1" split || contains "$1" disorder
}
test_has_fakedsplit()
{
contains "$1" fakedsplit || contains "$1" fakeddisorder
}
test_has_fake()
{
[ "$1" = fake ] || starts_with "$1" fake,
@@ -1138,10 +1140,13 @@ pktws_curl_test_update_vary()
proto=http
[ "$sec" = 0 ] || proto=tls
test_has_fake $desync && zerofake="--dpi-desync-fake-$proto=0x00000000"
test_has_split $desync && {
if test_has_fakedsplit $desync ; then
splits="method+2 midsld"
[ "$sec" = 0 ] || splits="1 midsld"
elif test_has_split $desync ; then
splits="method+2 midsld"
[ "$sec" = 0 ] || splits="1 midsld 1,midsld"
}
fi
for fake in '' $zerofake ; do
if [ -n "$splits" ]; then
for pos in $splits ; do
@@ -1173,7 +1178,7 @@ pktws_check_domain_http_bypass_()
local splits_tls='2 1 sniext+1 sniext+4 host+1 midsld 1,midsld 1,sniext+1,host+1,midsld-2,midsld,midsld+2,endhost-1'
[ "$sec" = 0 ] && {
for s in '--hostcase' '--hostspell=hoSt' '--hostnospace' '--domcase'; do
for s in '--hostcase' '--hostspell=hoSt' '--hostnospace' '--domcase' '--methodeol'; do
pktws_curl_test_update $1 $3 $s
done
}

View File

@@ -140,7 +140,7 @@ echo_var()
eval v="\$$1"
if find_str_in_list $1 "$EDITVAR_NEWLINE_VARS"; then
echo "$1=\""
echo "$v\"" | sed "s/$EDITVAR_NEWLINE_DELIMETER /$EDITVAR_NEWLINE_DELIMETER\n/g"
echo "$v\"" | tr '\n' ' ' | tr -d '\r' | sed -e 's/^ *//' -e 's/ *$//' -e "s/$EDITVAR_NEWLINE_DELIMETER /$EDITVAR_NEWLINE_DELIMETER\n/g"
else
if contains "$v" " "; then
echo $1=\"$v\"
@@ -170,6 +170,7 @@ list_vars()
echo_var $1
shift
done
echo
}
openrc_test()
@@ -837,3 +838,37 @@ select_fwtype()
echo select firewall type :
ask_list FWTYPE "iptables nftables" "$FWTYPE" && write_config_var FWTYPE
}
dry_run_tpws_()
{
local TPWS="$ZAPRET_BASE/tpws/tpws"
echo verifying tpws options
"$TPWS" --dry-run "$@"
}
dry_run_nfqws_()
{
local NFQWS="$ZAPRET_BASE/nfq/nfqws"
echo verifying nfqws options
"$NFQWS" --dry-run "$@"
}
dry_run_tpws()
{
[ "$TPWS_ENABLE" = 1 ] || return 0
local opt="$TPWS_OPT" port=${TPPORT_SOCKS:-988}
filter_apply_hostlist_target opt
dry_run_tpws_ --port=$port $opt
}
dry_run_tpws_socks()
{
[ "$TPWS_SOCKS_ENABLE" = 1 ] || return 0
local opt="$TPWS_SOCKS_OPT" port=${TPPORT:-987}
filter_apply_hostlist_target opt
dry_run_tpws_ --port=$port --socks $opt
}
dry_run_nfqws()
{
[ "$NFQWS_ENABLE" = 1 ] || return 0
local opt="$NFQWS_OPT" qn=${QNUM:-200}
filter_apply_hostlist_target opt
dry_run_nfqws_ --qnum=$qn $opt
}

View File

@@ -125,3 +125,13 @@ resolve_lower_devices()
}
}
}
default_route_interfaces6()
{
sed -nre 's/^00000000000000000000000000000000 00 [0-9a-f]{32} [0-9a-f]{2} [0-9a-f]{32} [0-9a-f]{8} [0-9a-f]{8} [0-9a-f]{8} [0-9a-f]{8} +(.*)$/\1/p' /proc/net/ipv6_route | grep -v '^lo$' | sort -u | xargs
}
default_route_interfaces4()
{
sed -nre 's/^([^\t]+)\t00000000\t[0-9A-F]{8}\t[0-9A-F]{4}\t[0-9]+\t[0-9]+\t[0-9]+\t00000000.*$/\1/p' /proc/net/route | sort -u | xargs
}

View File

@@ -389,3 +389,31 @@ blockcheck: added CURL_OPT
blockcheck: new strategies support
blockcheck: test sequence rework
blockcheck: view all working strategies in summary
v69.1:
init.d: keenetic udp fix custom
tpws: fixed incorrect hostlist checks
v69.2:
nfqws,tpws: --skip
nfqws: --methodeol
init.d: do not use pgrep in sysv for busybox compat
v69.3
nfqws,tpws: fixed ipsets and hostlists
all progs: version numbers for github, build date/time for self built
repo: light release for openwrt and embedded systems
repo: sha256sum
v69.4
nfqws: fakedsplit/fakeddisorder fakes for both split segments
nfqws: --dpi-desync-fakedsplit-pattern
v69.5
nfqws,tpws: --dry-run
install_easy: check tpws and nfqws options validity

View File

@@ -50,6 +50,8 @@
> образ `squashfs` с помощью `image builder` и перешить этим вариантом роутер.
1. Скачайте последний [tar.gz релиз](https://github.com/bol-van/zapret/releases) в /tmp, распакуйте его, затем удалите архив.
Для openwrt и прошивок используйте вариант `openwrt-embedded`.
Для экономия места в /tmp можно качать через curl в stdout и сразу распаковывать.
2. Убедитесь, что у вас отключены все средства обхода блокировок, в том числе и
сам zapret. Гарантированно уберет zapret скрипт `uninstall_easy.sh`.

View File

@@ -1,4 +1,4 @@
# zapret v.69
# zapret v69.5
# SCAMMER WARNING
@@ -131,6 +131,7 @@ nfqws takes the following parameters:
@<config_file> ; read file for options. must be the only argument. other options are ignored.
--debug=0|1
--dry-run ; verify parameters and exit with code 0 if successful
--qnum=<nfqueue_number>
--daemon ; daemonize
--pidfile=<filename> ; write pid to file
@@ -146,6 +147,7 @@ nfqws takes the following parameters:
--hostspell ; exact spelling of "Host" header. must be 4 chars. default is "host"
--hostnospace ; remove space after Host: and add it to User-Agent: to preserve packet size
--domcase ; mix domain case : Host: TeSt.cOm
--methodeol ; add '\n' before method and remove space after Host:
--dpi-desync=[<mode0>,]<mode>[,<mode2>] ; try to desync dpi state. modes : synack fake fakeknown rst rstack hopbyhop destopt ipfrag1 multisplit multidisorder fakedsplit fakeddisorder ipfrag2 udplen tamper
--dpi-desync-fwmark=<int|0xHEX> ; override fwmark for desync packet. default = 0x40000000 (1073741824)
--dpi-desync-ttl=<int> ; set ttl for desync packet
@@ -161,6 +163,7 @@ nfqws takes the following parameters:
; fakedsplit/fakeddisorder use first l7-protocol-compatible parameter if present, first abs value otherwise
--dpi-desync-split-seqovl=N|-N|marker+N|marker-N ; use sequence overlap before first sent original split segment
--dpi-desync-split-seqovl-pattern=<filename>|0xHEX ; pattern for the fake part of overlap
--dpi-desync-fakedsplit-pattern=<filename>|0xHEX ; fake pattern for fakedsplit/fakeddisorder
--dpi-desync-ipfrag-pos-tcp=<8..9216> ; ip frag position starting from the transport header. multiple of 8, default 8.
--dpi-desync-ipfrag-pos-udp=<8..9216> ; ip frag position starting from the transport header. multiple of 8, default 32.
--dpi-desync-badseq-increment=<int|0xHEX> ; badseq fooling seq signed increment. default -10000
@@ -179,19 +182,24 @@ nfqws takes the following parameters:
--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
--hostlist=<filename> ; apply dpi desync only to the listed hosts (one host per line, subdomains auto apply, gzip supported, multiple hostlists allowed)
--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-domains=<domain_list> ; comma separated fixed domain list
--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-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-debug=<logfile> ; debug auto hostlist positives
--new ; begin new strategy
--new ; begin new strategy (new profile)
--skip ; do not use this profile
--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-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.
--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-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
```
### DPI desync attack
@@ -256,8 +264,8 @@ Fakes are separate generated by nfqws packets carrying false information for DPI
* `multisplit`. split request at specified in `--dpi-desync-split-pos` positions
* `multidisorder`. same as `multisplit` but send in reverse order
* `fakedsplit`. split request into 2 segments adding fakes in the middle of them : fake 1st segment, 1st segment, fake 1st segment, 2nd segment
* `fakeddisorder`. same as `fakedsplit` but with another order : 2nd segment, fake 1st segment, 1st segment, fake 1st segment
* `fakedsplit`. split request into 2 segments adding fakes in the middle of them : fake 1st segment, 1st segment, fake 1st segment, fake 2nd segment, 2nd segment, fake 2nd segment
* `fakeddisorder`. same as `fakedsplit` but with another order : fake 2nd segment, 2nd segment, fake 2nd segment, fake 1st segment, 1st segment, fake 1st segment
Positions are defined by markers.
@@ -267,7 +275,7 @@ Positions are defined by markers.
Relative positions :
* **method** - HTTP method start ('GET', 'POST', 'HEAD', ...). Method is usually always at position 0 but also supported `--methodeol` fooling by **tpws**. If fooled position can become 1 or 2.
* **method** - HTTP method start ('GET', 'POST', 'HEAD', ...). Method is usually always at position 0 but can shift because of `--methodeol` fooling. If fooled position can become 1 or 2.
* **host** - hostname start in a known protocol (http, TLS)
* **endhost** - the byte next to the last hostname's byte
* **sld** - second level domain start in the hostname
@@ -632,6 +640,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-level=0|1|2 ; specify debug level for syslog and @<filename>
--dry-run ; verify parameters and exit with code 0 if successful
--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-iface6=<interface_name> ; bind to the first ipv6 addr of interface
@@ -663,15 +672,20 @@ tpws is transparent proxy.
; its worth to make a reserve with 1.5 multiplier. by default maxfiles is (X*connections)*1.5+16
--max-orphan-time=<sec> ; if local leg sends something and closes and remote leg is still connecting then cancel connection attempt after N seconds
--new ; begin new strategy
--new ; begin new strategy (new profile)
--skip ; do not use this profile
--filter-l3=ipv4|ipv6 ; L3 protocol filter. multiple comma separated values allowed.
--filter-tcp=[~]port1[-port2]|* ; TCP port filter. ~ means negation. comma separated list supported.
--filter-l7=[http|tls|unknown] ; L6-L7 protocol filter. multiple comma separated values 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-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
--hostlist=<filename> ; only act on hosts in the list (one host per line, subdomains auto apply, gzip supported, multiple hostlists allowed)
--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-domains=<domain_list> ; comma separated fixed domain list
--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-time=<int> ; all failed attemps must be within these seconds (default : 60)
@@ -701,7 +715,7 @@ tpws is transparent proxy.
--daemon ; daemonize
--pidfile=<filename> ; write pid to file
--user=<username> ; drop root privs
--uid=uid[:gid] ; drop root privs
--uid=uid[:gid] ; drop root privs
```
### TCP segmentation in tpws

View File

@@ -1,4 +1,4 @@
# zapret v.69
# zapret v69.5
# ВНИМАНИЕ, остерегайтесь мошенников
@@ -159,70 +159,78 @@ DPI. Все больше становится внереестровых бло
dvtws, собираемый из тех же исходников (см. [документация BSD](./bsd.md)).
```
@<config_file>|$<config_file> ; читать конфигурацию из файла. опция должна быть первой. остальные опции игнорируются.
@<config_file>|$<config_file> ; читать конфигурацию из файла. опция должна быть первой. остальные опции игнорируются.
--debug=0|1 ; 1=выводить отладочные сообщения
--daemon ; демонизировать прогу
--pidfile=<file> ; сохранить PID в файл
--user=<username> ; менять uid процесса
--uid=uid[:gid] ; менять uid процесса
--qnum=N ; номер очереди N
--bind-fix4 ; пытаться решить проблему неверного выбора исходящего интерфейса для сгенерированных ipv4 пакетов
--bind-fix6 ; пытаться решить проблему неверного выбора исходящего интерфейса для сгенерированных ipv6 пакетов
--wsize=<winsize>[:<scale_factor>] ; менять tcp window size на указанный размер в SYN,ACK. если не задан scale_factor, то он не меняется (устарело !)
--wssize=<winsize>[:<scale_factor>] ; менять tcp window size на указанный размер в исходящих пакетах. scale_factor по умолчанию 0. (см. conntrack !)
--wssize-cutoff=[n|d|s]N ; изменять server window size в исходящих пакетах (n), пакетах данных (d), относительных sequence (s) по номеру меньше N
--ctrack-timeouts=S:E:F[:U] ; таймауты внутреннего conntrack в состояниях SYN, ESTABLISHED, FIN, таймаут udp. по умолчанию 60:300:60:60
--hostcase ; менять регистр заголовка "Host:" по умолчанию на "host:".
--hostnospace ; убрать пробел после "Host:" и переместить его в конец значения "User-Agent:" для сохранения длины пакета
--hostspell=HoST ; точное написание заголовка Host (можно "HOST" или "HoSt"). автоматом включает --hostcase
--domcase ; домен после Host: сделать таким : TeSt.cOm
--dpi-desync=[<mode0>,]<mode>[,<mode2] ; атака по десинхронизации DPI. mode : synack syndata fake fakeknown rst rstack hopbyhop destopt ipfrag1 multisplit multidisorder fakedsplit fakeddisorder ipfrag2 udplen tamper
--dpi-desync-fwmark=<int|0xHEX> ; бит fwmark для пометки десинхронизирующих пакетов, чтобы они повторно не падали в очередь. default = 0x40000000
--dpi-desync-ttl=<int> ; установить ttl для десинхронизирующих пакетов
--dpi-desync-ttl6=<int> ; установить ipv6 hop limit для десинхронизирующих пакетов. если не указано, используется значение ttl
--dpi-desync-autottl=[<delta>[:<min>[-<max>]]] ; режим auto ttl для ipv4 и ipv6. по умолчанию: 1:3-20. delta=0 отключает функцию.
--dpi-desync-autottl6=[<delta>[:<min>[-<max>]]] ; переопределение предыдущего параметра для ipv6
--dpi-desync-fooling=<fooling> ; дополнительные методики как сделать, чтобы фейковый пакет не дошел до сервера. none md5sig badseq badsum datanoack hopbyhop hopbyhop2
--dpi-desync-repeats=<N> ; посылать каждый генерируемый в nfqws пакет N раз (не влияет на остальные пакеты)
--dpi-desync-skip-nosni=0|1 ; 1(default)=не применять dpi desync для запросов без hostname в SNI, в частности для ESNI
--dpi-desync-split-pos=N|-N|marker+N|marker-N ; список через запятую маркеров для tcp сегментации в режимах split и disorder
--dpi-desync-split-seqovl=N|-N|marker+N|marker-N ; единичный маркер, определяющий величину перекрытия sequence в режимах split и disorder. для split поддерживается только положительное число.
--debug=0|1 ; 1=выводить отладочные сообщения
--dry-run ; проверить опции командной строки и выйти. код 0 - успешная проверка.
--daemon ; демонизировать прогу
--pidfile=<file> ; сохранить PID в файл
--user=<username> ; менять uid процесса
--uid=uid[:gid] ; менять uid процесса
--qnum=N ; номер очереди N
--bind-fix4 ; пытаться решить проблему неверного выбора исходящего интерфейса для сгенерированных ipv4 пакетов
--bind-fix6 ; пытаться решить проблему неверного выбора исходящего интерфейса для сгенерированных ipv6 пакетов
--wsize=<winsize>[:<scale_factor>] ; менять tcp window size на указанный размер в SYN,ACK. если не задан scale_factor, то он не меняется (устарело !)
--wssize=<winsize>[:<scale_factor>] ; менять tcp window size на указанный размер в исходящих пакетах. scale_factor по умолчанию 0. (см. conntrack !)
--wssize-cutoff=[n|d|s]N ; изменять server window size в исходящих пакетах (n), пакетах данных (d), относительных sequence (s) по номеру меньше N
--ctrack-timeouts=S:E:F[:U] ; таймауты внутреннего conntrack в состояниях SYN, ESTABLISHED, FIN, таймаут udp. по умолчанию 60:300:60:60
--hostcase ; менять регистр заголовка "Host:" по умолчанию на "host:".
--hostnospace ; убрать пробел после "Host:" и переместить его в конец значения "User-Agent:" для сохранения длины пакета
--methodeol ; добавить перевод строки в unix стиле ('\n') перед методом и убрать пробел из Host: : "GET / ... Host: domain.com" => "\nGET / ... Host:domain.com"
--hostspell=HoST ; точное написание заголовка Host (можно "HOST" или "HoSt"). автоматом включает --hostcase
--domcase ; домен после Host: сделать таким : TeSt.cOm
--dpi-desync=[<mode0>,]<mode>[,<mode2] ; атака по десинхронизации DPI. mode : synack syndata fake fakeknown rst rstack hopbyhop destopt ipfrag1 multisplit multidisorder fakedsplit fakeddisorder ipfrag2 udplen tamper
--dpi-desync-fwmark=<int|0xHEX> ; бит fwmark для пометки десинхронизирующих пакетов, чтобы они повторно не падали в очередь. default = 0x40000000
--dpi-desync-ttl=<int> ; установить ttl для десинхронизирующих пакетов
--dpi-desync-ttl6=<int> ; установить ipv6 hop limit для десинхронизирующих пакетов. если не указано, используется значение ttl
--dpi-desync-autottl=[<delta>[:<min>[-<max>]]] ; режим auto ttl для ipv4 и ipv6. по умолчанию: 1:3-20. delta=0 отключает функцию.
--dpi-desync-autottl6=[<delta>[:<min>[-<max>]]] ; переопределение предыдущего параметра для ipv6
--dpi-desync-fooling=<fooling> ; дополнительные методики как сделать, чтобы фейковый пакет не дошел до сервера. none md5sig badseq badsum datanoack hopbyhop hopbyhop2
--dpi-desync-repeats=<N> ; посылать каждый генерируемый в nfqws пакет N раз (не влияет на остальные пакеты)
--dpi-desync-skip-nosni=0|1 ; 1(default)=не применять dpi desync для запросов без hostname в SNI, в частности для ESNI
--dpi-desync-split-pos=N|-N|marker+N|marker-N ; список через запятую маркеров для tcp сегментации в режимах split и disorder
--dpi-desync-split-seqovl=N|-N|marker+N|marker-N ; единичный маркер, определяющий величину перекрытия sequence в режимах split и disorder. для split поддерживается только положительное число.
--dpi-desync-split-seqovl-pattern=<filename>|0xHEX ; чем заполнять фейковую часть overlap
--dpi-desync-badseq-increment=<int|0xHEX> ; инкремент sequence number для badseq. по умолчанию -10000
--dpi-desync-badack-increment=<int|0xHEX> ; инкремент ack sequence number для badseq. по умолчанию -66000
--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-tls=<filename>|0xHEX ; файл, содержащий фейковый tls clienthello для dpi-desync=fake, на замену стандартному
--dpi-desync-fake-unknown=<filename>|0xHEX ; файл, содержащий фейковый пейлоад неизвестного протокола для dpi-desync=fake, на замену стандартным нулям 256 байт
--dpi-desync-fake-syndata=<filename>|0xHEX ; файл, содержащий фейковый пейлоад пакета SYN для режима десинхронизации syndata
--dpi-desync-fake-quic=<filename>|0xHEX ; файл, содержащий фейковый QUIC Initial
--dpi-desync-fake-dht=<filename>|0xHEX ; файл, содержащий фейковый пейлоад DHT протокола для 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-pattern=<filename>|0xHEX ; чем добивать udp пакет в режиме udplen. по умолчанию - нули
--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
--hostlist=<filename> ; действовать только над доменами, входящими в список из filename. поддомены автоматически учитываются.
; в файле должен быть хост на каждой строке.
; список читается при старте и хранится в памяти в виде иерархической структуры для быстрого поиска.
; при изменении времени модификации файла он перечитывается автоматически по необходимости
; список может быть запакован в gzip. формат автоматически распознается и разжимается
; списков может быть множество. пустой общий лист = его отсутствие
; хосты извлекаются из Host: хедера обычных http запросов и из SNI в TLS ClientHello.
--hostlist-exclude=<filename> ; не применять дурение к доменам из листа. может быть множество листов. схема аналогична include листам.
--hostlist-auto=<filename> ; обнаруживать автоматически блокировки и заполнять автоматический hostlist (требует перенаправления входящего трафика)
--hostlist-auto-fail-threshold=<int> ; сколько раз нужно обнаружить ситуацию, похожую на блокировку, чтобы добавить хост в лист (по умолчанию: 3)
--hostlist-auto-fail-time=<int> ; все эти ситуации должны быть в пределах указанного количества секунд (по умолчанию: 60)
--hostlist-auto-retrans-threshold=<int> ; сколько ретрансмиссий запроса считать блокировкой (по умолчанию: 3)
--hostlist-auto-debug=<logfile> ; лог положительных решений по autohostlist. позволяет разобраться почему там появляются хосты.
--new ; начало новой стратегии (новый профиль)
--filter-l3=ipv4|ipv6 ; фильтр версии ip для текущей стратегии
--filter-tcp=[~]port1[-port2]|* ; фильтр портов tcp для текущей стратегии. ~ означает инверсию. установка фильтра tcp и неустановка фильтра udp запрещает udp. поддерживается список через запятую.
--filter-udp=[~]port1[-port2]|* ; фильтр портов udp для текущей стратегии. ~ означает инверсию. установка фильтра udp и неустановка фильтра tcp запрещает tcp. поддерживается список через запятую.
--filter-l7=[http|tls|quic|wireguard|dht|unknown] ; фильтр протокола L6-L7. поддерживается несколько значений через запятую.
--ipset=<filename> ; включающий ip list. на каждой строчке ip или cidr ipv4 или ipv6. поддерживается множество листов и gzip. перечитка автоматическая.
--ipset-exclude=<filename> ; исключающий ip list. на каждой строчке ip или cidr ipv4 или ipv6. поддерживается множество листов и gzip. перечитка автоматическая.
--dpi-desync-fakedsplit-pattern=<filename>|0xHEX ; чем заполнять фейки в fakedsplit/fakeddisorder
--dpi-desync-badseq-increment=<int|0xHEX> ; инкремент sequence number для badseq. по умолчанию -10000
--dpi-desync-badack-increment=<int|0xHEX> ; инкремент ack sequence number для badseq. по умолчанию -66000
--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-tls=<filename>|0xHEX ; файл, содержащий фейковый tls clienthello для dpi-desync=fake, на замену стандартному
--dpi-desync-fake-unknown=<filename>|0xHEX ; файл, содержащий фейковый пейлоад неизвестного протокола для dpi-desync=fake, на замену стандартным нулям 256 байт
--dpi-desync-fake-syndata=<filename>|0xHEX ; файл, содержащий фейковый пейлоад пакета SYN для режима десинхронизации syndata
--dpi-desync-fake-quic=<filename>|0xHEX ; файл, содержащий фейковый QUIC Initial
--dpi-desync-fake-dht=<filename>|0xHEX ; файл, содержащий фейковый пейлоад DHT протокола для 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-pattern=<filename>|0xHEX ; чем добивать udp пакет в режиме udplen. по умолчанию - нули
--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
--hostlist=<filename> ; действовать только над доменами, входящими в список из filename. поддомены автоматически учитываются.
; в файле должен быть хост на каждой строке.
; список читается при старте и хранится в памяти в виде иерархической структуры для быстрого поиска.
; при изменении времени модификации файла он перечитывается автоматически по необходимости
; список может быть запакован в gzip. формат автоматически распознается и разжимается
; списков может быть множество. пустой общий лист = его отсутствие
; хосты извлекаются из Host: хедера обычных http запросов и из SNI в TLS ClientHello.
--hostlist-domains=<domain_list> ; фиксированный список доменов через зяпятую. можно использовать # в начале для комментирования отдельных доменов.
--hostlist-exclude=<filename> ; не применять дурение к доменам из листа. может быть множество листов. схема аналогична include листам.
--hostlist-exclude-domains=<domain_list> ; фиксированный список доменов через зяпятую. можно использовать # в начале для комментирования отдельных доменов.
--hostlist-auto=<filename> ; обнаруживать автоматически блокировки и заполнять автоматический hostlist (требует перенаправления входящего трафика)
--hostlist-auto-fail-threshold=<int> ; сколько раз нужно обнаружить ситуацию, похожую на блокировку, чтобы добавить хост в лист (по умолчанию: 3)
--hostlist-auto-fail-time=<int> ; все эти ситуации должны быть в пределах указанного количества секунд (по умолчанию: 60)
--hostlist-auto-retrans-threshold=<int> ; сколько ретрансмиссий запроса считать блокировкой (по умолчанию: 3)
--hostlist-auto-debug=<logfile> ; лог положительных решений по autohostlist. позволяет разобраться почему там появляются хосты.
--new ; начало новой стратегии (новый профиль)
--skip ; не использовать этот профиль . полезно для временной деактивации профиля без удаления параметров.
--filter-l3=ipv4|ipv6 ; фильтр версии ip для текущей стратегии
--filter-tcp=[~]port1[-port2]|* ; фильтр портов tcp для текущей стратегии. ~ означает инверсию. установка фильтра tcp и неустановка фильтра udp запрещает udp. поддерживается список через запятую.
--filter-udp=[~]port1[-port2]|* ; фильтр портов udp для текущей стратегии. ~ означает инверсию. установка фильтра udp и неустановка фильтра tcp запрещает tcp. поддерживается список через запятую.
--filter-l7=[http|tls|quic|wireguard|dht|unknown] ; фильтр протокола L6-L7. поддерживается несколько значений через запятую.
--ipset=<filename> ; включающий ip list. на каждой строчке ip или cidr ipv4 или ipv6. поддерживается множество листов и gzip. перечитка автоматическая.
--ipset-ip=<ip_list> ; фиксированный список подсетей через запятую. можно использовать # в начале для комментирования отдельных подсетей.
--ipset-exclude=<filename> ; исключающий ip list. на каждой строчке ip или cidr ipv4 или ipv6. поддерживается множество листов и gzip. перечитка автоматическая.
--ipset-exclude-ip=<ip_list> ; фиксированный список подсетей через запятую. можно использовать # в начале для комментирования отдельных подсетей.
```
`--debug` позволяет выводить подробный лог действий на консоль, в syslog или в файл. Может быть важен порядок следования
@@ -312,8 +320,13 @@ dvtws, собираемый из тех же исходников (см. [док
* `multisplit`. нарезаем запрос на указанных в `--dpi-desync-split-pos` позициях.
* `multidisorder`. нарезаем запрос на указанных в `--dpi-desync-split-pos` позициях и отправляем в обратном порядке.
* `fakedsplit`. нарезаем запрос на 2 части, обрамляя его фейками : фейк 1-й части, 1 часть, фейк 1-й части, 2 часть
* `fakeddisorder`. нарезаем запрос на 2 части, обрамляя его фейками : 2 часть, фейк 1-й части, 1 часть, фейк 1 части.
* `fakedsplit`. нарезаем запрос на 2 части, обрамляя каждую часть фейками : фейк 1-й части, 1 часть, фейк 1-й части, фейк 2-й части, 2 часть, фейк 2-й части
* `fakeddisorder`. аналогично `fakedsplit`, только в обратном порядке : фейк 2-й части, 2 часть, фейк 2-й части, фейк 1-й части, 1 часть, фейк 1 части.
Содержимое фейков в `fakedsplit`/`fakeddisorder` определяется параметром `--dpi-desync-fakedsplit-pattern` (по умолчанию 0x00).
Данные фейков берутся из паттерна со смещением, соответствующим смещению отсылаемых частей.
Размеры фейков соответствуют длинам отсылаемых частей.
Цель этих режимов - максимально усложнить выявление оригинальных данных среди фейков.
Для определения позиций нарезки используются маркеры.
@@ -323,11 +336,11 @@ dvtws, собираемый из тех же исходников (см. [док
Относительные позиции :
* **method** - начало метода HTTP ('GET', 'POST', 'HEAD', ...). Метод обычно всегда находится на позиции 0, но поддерживается и нахождение метода после дурение методом `--methodeol` от tpws. Тогда позиция может стать 1 или 2.
* **method** - начало метода HTTP ('GET', 'POST', 'HEAD', ...). Метод обычно всегда находится на позиции 0, но может сместиться из-за `--methodeol`. Тогда позиция может стать 1 или 2.
* **host** - начало имени хоста в известном протоколе (http, TLS)
* **endhost** - конец имени хоста
* **endhost** - байт, следующий за последним байтом имени хоста
* **sld** - начало домена 2 уровня в имени хоста
* **endsld** - конец домена 2 уровня в имени хоста
* **endsld** - байт, следующий за последним байтом домена 2 уровня в имени хоста
* **midsld** - середина домена 2 уровня в имени хоста
* **sniext** - начало поля данных SNI extension в TLS. Любой extension состоит из 2-байтовых полей type и length, за ними идет поле данных.
@@ -381,7 +394,7 @@ Windows оставляет старые данные, поэтому disorder с
### СПЕЦИФИЧЕСКИЕ РЕЖИМЫ IPV6
Режимы десинхронизации `hopbyhop`, `destopt` и `ipfrag1` (не путать с fooling !) относятся только к `ipv6` и заключается
Режимы десинхронизации `hopbyhop`, `destopt` и `ipfrag1` (не путать с fooling !) относятся только к ipv6 и заключается
в добавлении хедера `hop-by-hop options`, `destination options` или `fragment` во все пакеты, попадающие под десинхронизацию.
Здесь надо обязательно понимать, что добавление хедера увеличивает размер пакета, потому не может быть применено
к пакетам максимального размера. Это имеет место при передаче больших сообщений.
@@ -398,7 +411,7 @@ extension хедерам в поисках транспортного хедер
В параметре dpi-desync можно указать до 3 режимов через запятую.
* 0 фаза - предполагает работу на этапе установления соединения : `synack`, `syndata` `--wsize`, `--wssize`. На эту фазу не действуют фильтры по [hostlist](((#множественные-стратегии))).
* 0 фаза - предполагает работу на этапе установления соединения : `synack`, `syndata`, `--wsize`, `--wssize`. На эту фазу не действуют фильтры по [hostlist](#множественные-стратегии).
* 1 фаза - отсылка чего-либо до оригинального пакета данных : `fake`, `rst`, `rstack`.
* 2 фаза - отсылка в модифицированном виде оригинального пакета данных (например, `fakedsplit` или `ipfrag2`).
@@ -424,29 +437,10 @@ DPI может отстать от потока, если ClientHello его у
В документации по geneva это называется "TCB turnaround". Попытка ввести DPI в заблуждение относительно
ролей клиента и сервера.
!!! Поскольку режим нарушает работу NAT, техника может сработать только если между атакующим устройством
Поскольку режим нарушает работу NAT, техника может сработать только если между атакующим устройством
и DPI нет NAT. Атака не сработает через NAT роутер, но может сработать с него.
Для реализации атаки в linux обязательно требуется отключить стандартное правило firewall,
дропающее инвалидные пакеты в цепочке OUTPUT. Например : `-A OUTPUT -m state --state INVALID -j DROP`
В openwrt можно отключить drop INVALID в OUTPUT и FORWARD через опцию в /etc/config/firewall:
```
config zone
option name 'wan'
.........
option masq_allow_invalid '1'
```
К сожалению, отключить только в OUTPUT таким образом нельзя. Но можно сделать иначе. Вписать в `/etc/firewall.user`:
```
iptables -D zone_wan_output -m comment --comment '!fw3' -j zone_wan_dest_ACCEPT
ip6tables -D zone_wan_output -m comment --comment '!fw3' -j zone_wan_dest_ACCEPT
```
Лучше делать так, потому что отсутствие дропа INVALID в FORWARD может привести к нежелательным утечкам пакетов из LAN.
Если не принять эти меры, отсылка SYN,ACK сегмента вызовет ошибку и операция будет прервана.
Остальные режимы тоже не сработают. Если поймете, что вам synack не нужен, обязательно верните правило дропа INVALID.
Для реализации атаки на проходящий трафик требуются nftables и схема [POSTNAT](#nftables-для-nfqws).
### РЕЖИМ SYNDATA
@@ -480,7 +474,7 @@ conntrack - простенький, он не писался с учетом в
`--wssize` позволяет изменить с клиента размер tcp window для сервера, чтобы он послал следующие ответы разбитыми на части.
Чтобы это подействовало на все серверные ОС, необходимо менять window size в каждом исходящем с клиента пакете до отсылки сообщения,
ответ на который должен быть разбит (например, TLS ClientHello). Именно поэтому и необходим conntrack, чтобы
ответ на которое должен быть разбит (например, TLS ClientHello). Именно поэтому и необходим conntrack, чтобы
знать когда надо остановиться. Если не остановиться и все время устанавливать низкий wssize, скорость упадет катастрофически.
В linux это может быть купировано через connbytes, но в BSD системах такой возможности нет.
В случае http(s) останавливаемся сразу после отсылки первого http запроса или TLS ClientHello.
@@ -521,7 +515,7 @@ nfqws поддерживает реассемблинг некоторых ви
На текущий момент это TLS и QUIC ClientHello. Они бывает длинными, если в chrome включить пост-квантовую
криптографию tls-kyber, и занимают как правило 2 или 3 пакета. kyber включен по умолчанию, начиная с chromium 124.
chrome рандомизирует фингерпринт TLS. SNI может оказаться как в начале, так и в конце, то есть
попасть любой пакет. stateful DPI обычно реассемблирует запрос целиком, и только потом
попасть в любой пакет. stateful DPI обычно реассемблирует запрос целиком, и только потом
принимает решение о блокировке.
В случае получения TLS или QUIC пакета с частичным ClientHello начинается процесс сборки, а пакеты
задерживаются и не отсылаются до ее окончания. По окончании сборки пакеты проходит через десинхронизацию
@@ -761,95 +755,101 @@ iptables target `FLOWOFFLOAD` - это проприетарное изобрет
tpws - это transparent proxy.
```
@<config_file>|$<config_file> ; читать конфигурацию из файла. опция должна быть первой. остальные опции игнорируются.
@<config_file>|$<config_file> ; читать конфигурацию из файла. опция должна быть первой. остальные опции игнорируются.
--debug=0|1|2|syslog|@<filename> ; 0,1,2 = логирование на косоль : 0=тихо, 1(default)=подробно, 2=отладка.
--debug-level=0|1|2 ; указать уровень логирования для syslog и @<filename>
--daemon ; демонизировать прогу
--pidfile=<file> ; сохранить PID в файл
--user=<username> ; менять uid процесса
--uid=uid[:gid] ; менять uid процесса
--bind-addr ; на каком адресе слушать. может быть ipv4 или ipv6 адрес
; если указан ipv6 link local, то требуется указать с какого он интерфейса : fe80::1%br-lan
--bind-linklocal=no|unwanted|prefer|force
; no : биндаться только на global ipv6
; unwanted (default) : предпочтительно global, если нет - LL
; prefer : предпочтительно LL, если нет - global
; force : биндаться только на LL
--bind-iface4=<iface> ; слушать на первом ipv4 интерфейса iface
--bind-iface6=<iface> ; слушать на первом ipv6 интерфейса iface
--bind-wait-ifup=<sec ; ждать до N секунд появления и поднятия интерфейса
--bind-wait-ip=<sec> ; ждать до N секунд получения IP адреса (если задан --bind-wait-ifup - время идет после поднятия интерфейса)
--debug=0|1|2|syslog|@<filename> ; 0,1,2 = логирование на косоль : 0=тихо, 1(default)=подробно, 2=отладка.
--debug-level=0|1|2 ; указать уровень логирования для syslog и @<filename>
--dry-run ; проверить опции командной строки и выйти. код 0 - успешная проверка.
--daemon ; демонизировать прогу
--pidfile=<file> ; сохранить PID в файл
--user=<username> ; менять uid процесса
--uid=uid[:gid] ; менять uid процесса
--bind-addr ; на каком адресе слушать. может быть ipv4 или ipv6 адрес
; если указан ipv6 link local, то требуется указать с какого он интерфейса : fe80::1%br-lan
--bind-linklocal=no|unwanted|prefer|force ; no : биндаться только на global ipv6
; unwanted (default) : предпочтительно global, если нет - LL
; prefer : предпочтительно LL, если нет - global
; force : биндаться только на LL
--bind-iface4=<iface> ; слушать на первом ipv4 интерфейса iface
--bind-iface6=<iface> ; слушать на первом ipv6 интерфейса iface
--bind-wait-ifup=<sec> ; ждать до N секунд появления и поднятия интерфейса
--bind-wait-ip=<sec> ; ждать до N секунд получения IP адреса (если задан --bind-wait-ifup - время идет после поднятия интерфейса)
--bind-wait-ip-linklocal=<sec>
; имеет смысл только при задании --bind-wait-ip
; --bind-linklocal=unwanted : согласиться на LL после N секунд
; --bind-linklocal=prefer : согласиться на global address после N секунд
--bind-wait-only ; подождать все бинды и выйти. результат 0 в случае успеха, иначе не 0.
--connect-bind-addr ; с какого адреса подключаться во внешнюю сеть. может быть ipv4 или ipv6 адрес
; если указан ipv6 link local, то требуется указать с какого он интерфейса : fe80::1%br-lan
; опция может повторяться для v4 и v6 адресов
; опция не отменяет правил маршрутизации ! выбор интерфейса определяется лишь правилами маршрутизации, кроме случая v6 link local.
--socks ; вместо прозрачного прокси реализовать socks4/5 proxy
--no-resolve ; запретить ресолвинг имен через socks5
--resolve-threads ; количество потоков ресолвера
--port=<port> ; на каком порту слушать
--maxconn=<max_connections> ; максимальное количество соединений от клиентов к прокси
--maxfiles=<max_open_files> ; макс количество файловых дескрипторов (setrlimit). мин требование (X*connections+16), где X=6 в tcp proxy mode, X=4 в режиме тамперинга.
; стоит сделать запас с коэффициентом как минимум 1.5. по умолчанию maxfiles (X*connections)*1.5+16
--max-orphan-time=<sec> ; если вы запускаете через tpws торрент-клиент с множеством раздач, он пытается установить очень много исходящих соединений,
; большая часть из которых отваливается по таймауту (юзера сидят за NAT, firewall, ...)
; установление соединения в linux может длиться очень долго. локальный конец отвалился, перед этим послав блок данных,
; tpws ждет подключения удаленного конца, чтобы отослать ему этот блок, и зависает надолго.
; настройка позволяет сбрасывать такие подключения через N секунд, теряя блок данных. по умолчанию 5 сек. 0 означает отключить функцию
; эта функция не действует на успешно подключенные ранее соединения
; имеет смысл только при задании --bind-wait-ip
; --bind-linklocal=unwanted : согласиться на LL после N секунд
; --bind-linklocal=prefer : согласиться на global address после N секунд
--bind-wait-only ; подождать все бинды и выйти. результат 0 в случае успеха, иначе не 0.
--connect-bind-addr ; с какого адреса подключаться во внешнюю сеть. может быть ipv4 или ipv6 адрес
; если указан ipv6 link local, то требуется указать с какого он интерфейса : fe80::1%br-lan
; опция может повторяться для v4 и v6 адресов
; опция не отменяет правил маршрутизации ! выбор интерфейса определяется лишь правилами маршрутизации, кроме случая v6 link local.
--socks ; вместо прозрачного прокси реализовать socks4/5 proxy
--no-resolve ; запретить ресолвинг имен через socks5
--resolve-threads ; количество потоков ресолвера
--port=<port> ; на каком порту слушать
--maxconn=<max_connections> ; максимальное количество соединений от клиентов к прокси
--maxfiles=<max_open_files> ; макс количество файловых дескрипторов (setrlimit). мин требование (X*connections+16), где X=6 в tcp proxy mode, X=4 в режиме тамперинга.
; стоит сделать запас с коэффициентом как минимум 1.5. по умолчанию maxfiles (X*connections)*1.5+16
--max-orphan-time=<sec> ; если вы запускаете через tpws торрент-клиент с множеством раздач, он пытается установить очень много исходящих соединений,
; большая часть из которых отваливается по таймауту (юзера сидят за NAT, firewall, ...)
; установление соединения в linux может длиться очень долго. локальный конец отвалился, перед этим послав блок данных,
; tpws ждет подключения удаленного конца, чтобы отослать ему этот блок, и зависает надолго.
; настройка позволяет сбрасывать такие подключения через N секунд, теряя блок данных. по умолчанию 5 сек. 0 означает отключить функцию
; эта функция не действует на успешно подключенные ранее соединения
--local-rcvbuf=<bytes> ; SO_RCVBUF для соединений client-proxy
--local-sndbuf=<bytes> ; SO_SNDBUF для соединений client-proxy
--remote-rcvbuf=<bytes> ; SO_RCVBUF для соединений proxy-target
--remote-sndbuf=<bytes> ; SO_SNDBUF для соединений proxy-target
--nosplice ; не использовать splice на linux системах
--skip-nodelay ; не устанавливать в исходящих соединения TCP_NODELAY. несовместимо со split.
--local-tcp-user-timeout=<seconds> ; таймаут соединений client-proxy (по умолчанию : 10 сек, 0 = оставить системное значение)
--remote-tcp-user-timeout=<seconds> ; таймаут соединений proxy-target (по умолчанию : 20 сек, 0 = оставить системное значение)
--fix-seg=<int> ; исправлять неудачи tcp сегментации ценой задержек для всех клиентов и замедления. ждать до N мс. по умолчанию 30 мс.
--local-rcvbuf=<bytes> ; SO_RCVBUF для соединений client-proxy
--local-sndbuf=<bytes> ; SO_SNDBUF для соединений client-proxy
--remote-rcvbuf=<bytes> ; SO_RCVBUF для соединений proxy-target
--remote-sndbuf=<bytes> ; SO_SNDBUF для соединений proxy-target
--nosplice ; не использовать splice на linux системах
--skip-nodelay ; не устанавливать в исходящих соединения TCP_NODELAY. несовместимо со split.
--local-tcp-user-timeout=<seconds> ; таймаут соединений client-proxy (по умолчанию : 10 сек, 0 = оставить системное значение)
--remote-tcp-user-timeout=<seconds> ; таймаут соединений proxy-target (по умолчанию : 20 сек, 0 = оставить системное значение)
--fix-seg=<int> ; исправлять неудачи tcp сегментации ценой задержек для всех клиентов и замедления. ждать до N мс. по умолчанию 30 мс.
--split-pos=N|-N|marker+N|marker-N ; список через запятую маркеров для tcp сегментации
--split-any-protocol ; применять сегментацию к любым пакетам. по умолчанию - только к известным протоколам (http, TLS)
--disorder[=http|tls] ; путем манипуляций с сокетом вынуждает отправлять первым второй сегмент разделенного запроса
--oob[=http|tls] ; отправить байт out-of-band data (OOB) в конце первой части сплита
--oob-data=<char>|0xHEX ; переопределить байт OOB. по умолчанию 0x00.
--hostcase ; менять регистр заголовка "Host:". по умолчанию на "host:".
--hostspell=HoST ; точное написание заголовка Host (можно "HOST" или "HoSt"). автоматом включает --hostcase
--hostdot ; добавление точки после имени хоста : "Host: kinozal.tv."
--hosttab ; добавление табуляции после имени хоста : "Host: kinozal.tv\t"
--hostnospace ; убрать пробел после "Host:"
--hostpad=<bytes> ; добавить паддинг-хедеров общей длиной <bytes> перед Host:
--domcase ; домен после Host: сделать таким : TeSt.cOm
--methodspace ; добавить пробел после метода : "GET /" => "GET /"
--methodeol ; добавить перевод строки перед методом : "GET /" => "\r\nGET /"
--unixeol ; конвертировать 0D0A в 0A и использовать везде 0A
--tlsrec=N|-N|marker+N|marker-N ; разбивка TLS ClientHello на 2 TLS records на указанной позиции. Минимальное смещение - 6.
--mss=<int> ; установить MSS для клиента. может заставить сервер разбивать ответы, но существенно снижает скорость
--tamper-start=[n]<pos> ; начинать дурение только с указанной байтовой позиции или номера блока исходяшего потока (считается позиция начала принятого блока)
--tamper-cutoff=[n]<pos> ; закончить дурение на указанной байтовой позиции или номере блока исходящего потока (считается позиция начала принятого блока)
--hostlist=<filename> ; действовать только над доменами, входящими в список из filename. поддомены автоматически учитываются.
; в файле должен быть хост на каждой строке.
; список читается при старте и хранится в памяти в виде иерархической структуры для быстрого поиска.
; при изменении времени модификации файла он перечитывается автоматически по необходимости
; список может быть запакован в gzip. формат автоматически распознается и разжимается
; списков может быть множество. пустой общий лист = его отсутствие
; хосты извлекаются из Host: хедера обычных http запросов и из SNI в TLS ClientHello.
--hostlist-exclude=<filename> ; не применять дурение к доменам из листа. может быть множество листов. схема аналогична include листам.
--hostlist-auto=<filename> ; обнаруживать автоматически блокировки и заполнять автоматический hostlist (требует перенаправления входящего трафика)
--hostlist-auto-fail-threshold=<int> ; сколько раз нужно обнаружить ситуацию, похожую на блокировку, чтобы добавить хост в лист (по умолчанию: 3)
--hostlist-auto-fail-time=<int> ; все эти ситуации должны быть в пределах указанного количества секунд (по умолчанию: 60)
--hostlist-auto-debug=<logfile> ; лог положительных решений по autohostlist. позволяет разобраться почему там появляются хосты.
--new ; начало новой стратегии (новый профиль)
--filter-l3=ipv4|ipv6 ; фильтр версии ip для текущей стратегии
--filter-tcp=[~]port1[-port2]|* ; фильтр портов tcp для текущей стратегии. ~ означает инверсию. поддерживается список через запятую.
--split-pos=N|-N|marker+N|marker-N ; список через запятую маркеров для tcp сегментации
--split-any-protocol ; применять сегментацию к любым пакетам. по умолчанию - только к известным протоколам (http, TLS)
--disorder[=http|tls] ; путем манипуляций с сокетом вынуждает отправлять первым второй сегмент разделенного запроса
--oob[=http|tls] ; отправить байт out-of-band data (OOB) в конце первой части сплита
--oob-data=<char>|0xHEX ; переопределить байт OOB. по умолчанию 0x00.
--hostcase ; менять регистр заголовка "Host:". по умолчанию на "host:".
--hostspell=HoST ; точное написание заголовка Host (можно "HOST" или "HoSt"). автоматом включает --hostcase
--hostdot ; добавление точки после имени хоста : "Host: kinozal.tv."
--hosttab ; добавление табуляции после имени хоста : "Host: kinozal.tv\t"
--hostnospace ; убрать пробел после "Host:"
--hostpad=<bytes> ; добавить паддинг-хедеров общей длиной <bytes> перед Host:
--domcase ; домен после Host: сделать таким : TeSt.cOm
--methodspace ; добавить пробел после метода : "GET /" => "GET /"
--methodeol ; добавить перевод строки перед методом : "GET /" => "\r\nGET /"
--unixeol ; конвертировать 0D0A в 0A и использовать везде 0A
--tlsrec=N|-N|marker+N|marker-N ; разбивка TLS ClientHello на 2 TLS records на указанной позиции. Минимальное смещение - 6.
--mss=<int> ; установить MSS для клиента. может заставить сервер разбивать ответы, но существенно снижает скорость
--tamper-start=[n]<pos> ; начинать дурение только с указанной байтовой позиции или номера блока исходяшего потока (считается позиция начала принятого блока)
--tamper-cutoff=[n]<pos> ; закончить дурение на указанной байтовой позиции или номере блока исходящего потока (считается позиция начала принятого блока)
--hostlist=<filename> ; действовать только над доменами, входящими в список из filename. поддомены автоматически учитываются.
; в файле должен быть хост на каждой строке.
; список читается при старте и хранится в памяти в виде иерархической структуры для быстрого поиска.
; при изменении времени модификации файла он перечитывается автоматически по необходимости
; список может быть запакован в gzip. формат автоматически распознается и разжимается
; списков может быть множество. пустой общий лист = его отсутствие
; хосты извлекаются из Host: хедера обычных http запросов и из SNI в TLS ClientHello.
--hostlist-domains=<domain_list> ; фиксированный список доменов через зяпятую. можно использовать # в начале для комментирования отдельных доменов.
--hostlist-exclude=<filename> ; не применять дурение к доменам из листа. может быть множество листов. схема аналогична include листам.
--hostlist-exclude-domains=<domain_list> ; фиксированный список доменов через зяпятую. можно использовать # в начале для комментирования отдельных доменов.
--hostlist-auto=<filename> ; обнаруживать автоматически блокировки и заполнять автоматический hostlist (требует перенаправления входящего трафика)
--hostlist-auto-fail-threshold=<int> ; сколько раз нужно обнаружить ситуацию, похожую на блокировку, чтобы добавить хост в лист (по умолчанию: 3)
--hostlist-auto-fail-time=<int> ; все эти ситуации должны быть в пределах указанного количества секунд (по умолчанию: 60)
--hostlist-auto-debug=<logfile> ; лог положительных решений по autohostlist. позволяет разобраться почему там появляются хосты.
--new ; начало новой стратегии (новый профиль)
--skip ; не использовать этот профиль . полезно для временной деактивации профиля без удаления параметров.
--filter-l3=ipv4|ipv6 ; фильтр версии ip для текущей стратегии
--filter-tcp=[~]port1[-port2]|* ; фильтр портов tcp для текущей стратегии. ~ означает инверсию. поддерживается список через запятую.
--filter-l7=[http|tls|quic|wireguard|dht|unknown] ; фильтр протокола L6-L7. поддерживается несколько значений через запятую.
--ipset=<filename> ; включающий ip list. на каждой строчке ip или cidr ipv4 или ipv6. поддерживается множество листов и gzip. перечитка автоматическая.
--ipset-exclude=<filename> ; исключающий ip list. на каждой строчке ip или cidr ipv4 или ipv6. поддерживается множество листов и gzip. перечитка автоматическая.
--ipset=<filename> ; включающий ip list. на каждой строчке ip или cidr ipv4 или ipv6. поддерживается множество листов и gzip. перечитка автоматическая.
--ipset-ip=<ip_list> ; фиксированный список подсетей через запятую. можно использовать # в начале для комментирования отдельных подсетей.
--ipset-exclude=<filename> ; исключающий ip list. на каждой строчке ip или cidr ipv4 или ipv6. поддерживается множество листов и gzip. перечитка автоматическая.
--ipset-exclude-ip=<ip_list> ; фиксированный список подсетей через запятую. можно использовать # в начале для комментирования отдельных подсетей.
```
### TCP СЕГМЕНТАЦИЯ В TPWS

View File

@@ -101,10 +101,11 @@ There are several options :
Replace these 2 files in every location they are present.
In `zapret-win-bundle` they are in `zapret-winws` и `blockcheck/zapret/nfq` folders.
However this option still requires 10+ year old patch that enables SHA256 signatures.
If you're using win bundle you can simply run `win7\install_win7.cmd`
2. [Hack ESU](https://hackandpwn.com/windows-7-esu-patching)
3. [Hack ESU](https://hackandpwn.com/windows-7-esu-patching)
3. Use `UpdatePack7R2` from simplix : https://blog.simplix.info
4. Use `UpdatePack7R2` from simplix : https://blog.simplix.info
If you are in Russia or Belarus temporary change region in Control Panel.
### blockcheck

View File

@@ -159,6 +159,7 @@ _windivert 2.2.2-A_, который идет в поставке zapret.
и заменить эти 2 файла.
В [zapret-win-bundle](https://github.com/bol-van/zapret-win-bundle) есть отдельных 2 места, где находится **winws** : [_zapret-winws_](https://github.com/bol-van/zapret-win-bundle/tree/master/zapret-winws) и [_blockcheck/zapret/nfq_](https://github.com/bol-van/zapret-win-bundle/tree/master/blockcheck).
Надо менять в обоих местах.
Альтернативный вариант при использовании win bundle - запустить `win7\install_win7.cmd`
> [!NOTE]
> Этот вариант проверен и должен работать. Тем не менее патч 10 летней давности, который включает SHA256 сигнатуры, все еще необходим.

View File

@@ -0,0 +1,22 @@
# This script fixes keenetic issue with nfqws generated udp packets
# Keenetic uses proprietary ndmmark and does not masquerade without this mark
# If not masqueraded packets go to WAN with LAN IP and get dropped by ISP
# It's advised to set IFACE_WAN in config
zapret_custom_firewall()
{
# $1 - 1 - add, 0 - stop
local wan wanif rule
[ "$DISABLE_IPV4" = "1" ] || {
# use IFACE_WAN if defined. if not - search for interfaces with default route.
wanif=${IFACE_WAN:-$(sed -nre 's/^([^\t]+)\t00000000\t[0-9A-F]{8}\t[0-9A-F]{4}\t[0-9]+\t[0-9]+\t[0-9]+\t00000000.*$/\1/p' /proc/net/route | sort -u | xargs)}
for wan in $wanif; do
rule="-o $wan -p udp -m mark --mark $DESYNC_MARK/$DESYNC_MARK"
ipt_print_op $1 "$rule" "keenetic udp fix"
ipt_add_del $1 POSTROUTING -t nat $rule -j MASQUERADE
done
}
}

View File

@@ -102,7 +102,7 @@ dnat6_target()
}
set_route_localnet()
{
_set_route_localnet $1 "$IFACE_LAN"
_set_route_localnet $1 $IFACE_LAN
}
fw_nfqws_post4()
@@ -167,9 +167,15 @@ run_daemon()
# use $PIDDIR/$DAEMONBASE$1.pid as pidfile
local DAEMONBASE="$(basename "$2")"
local PIDFILE=$PIDDIR/$DAEMONBASE$1.pid
local PID= PIDFILE=$PIDDIR/$DAEMONBASE$1.pid
echo "Starting daemon $1: $2 $3"
if [ -f "$PIDFILE" ] && pgrep -F "$PIDFILE" "$DAEMONBASE" >/dev/null; then
[ -f "$PIDFILE" ] && {
read PID <"$PIDFILE"
[ -d "/proc/$PID" ] || PID=
}
if [ -n "$PID" ]; then
echo already running
else
"$2" $3 >/dev/null &
@@ -188,18 +194,14 @@ stop_daemon()
# $2 - daemon
# use $PIDDIR/$DAEMONBASE$1.pid as pidfile
local DAEMONBASE="$(basename "$2")"
local PIDFILE=$PIDDIR/$DAEMONBASE$1.pid
local PID PIDFILE=$PIDDIR/$DAEMONBASE$1.pid
echo "Stopping daemon $1: $2"
if exists start-stop-daemon ; then
start-stop-daemon -K -p "$PIDFILE" -x "$2"
if [ -f "$PIDFILE" ]; then
read PID <"$PIDFILE"
kill $PID
rm -f "$PIDFILE"
else
if [ -f "$PIDFILE" ]; then
read PID <"$PIDFILE"
kill $PID
rm -f "$PIDFILE"
else
echo no pidfile : $PIDFILE
fi
echo no pidfile : $PIDFILE
fi
}
do_daemon()

View File

@@ -68,7 +68,7 @@ case $UNAME in
;;
CYGWIN*)
UNAME=CYGWIN
ARCHLIST="win64"
ARCHLIST="win64 win32"
PKTWS=winws
;;
*)

View File

@@ -26,6 +26,7 @@ IPSET_DIR="$ZAPRET_BASE/ipset"
. "$ZAPRET_BASE/common/ipt.sh"
. "$ZAPRET_BASE/common/installer.sh"
. "$ZAPRET_BASE/common/virt.sh"
. "$ZAPRET_BASE/common/list.sh"
GET_LIST="$IPSET_DIR/get_config.sh"
@@ -115,6 +116,30 @@ ws_opt_validate()
}
return 0
}
tpws_opt_validate()
{
ws_opt_validate "$1" || return 1
dry_run_tpws || {
echo invalid tpws options
return 1
}
}
tpws_socks_opt_validate()
{
# --ipset allowed here
dry_run_tpws_socks || {
echo invalid tpws options
return 1
}
}
nfqws_opt_validate()
{
ws_opt_validate "$1" || return 1
dry_run_nfqws || {
echo invalid nfqws options
return 1
}
}
select_mode_group()
{
@@ -162,18 +187,17 @@ select_mode_group()
select_mode_tpws_socks()
{
local EDITVAR_NEWLINE_DELIMETER="--new" EDITVAR_NEWLINE_VARS="TPWS_SOCKS_OPT"
# --ipset allowed here
select_mode_group TPWS_SOCKS_ENABLE "enable tpws socks mode on port $TPPORT_SOCKS ?" "TPPORT_SOCKS TPWS_SOCKS_OPT"
select_mode_group TPWS_SOCKS_ENABLE "enable tpws socks mode on port $TPPORT_SOCKS ?" "TPPORT_SOCKS TPWS_SOCKS_OPT" tpws_socks_opt_validate TPWS_SOCKS_OPT
}
select_mode_tpws()
{
local EDITVAR_NEWLINE_DELIMETER="--new" EDITVAR_NEWLINE_VARS="TPWS_OPT"
select_mode_group TPWS_ENABLE "enable tpws transparent mode ?" "TPWS_PORTS TPWS_OPT" ws_opt_validate TPWS_OPT
select_mode_group TPWS_ENABLE "enable tpws transparent mode ?" "TPWS_PORTS TPWS_OPT" tpws_opt_validate TPWS_OPT
}
select_mode_nfqws()
{
local EDITVAR_NEWLINE_DELIMETER="--new" EDITVAR_NEWLINE_VARS="NFQWS_OPT"
select_mode_group NFQWS_ENABLE "enable nfqws ?" "NFQWS_PORTS_TCP NFQWS_PORTS_UDP NFQWS_TCP_PKT_OUT NFQWS_TCP_PKT_IN NFQWS_UDP_PKT_OUT NFQWS_UDP_PKT_IN NFQWS_PORTS_TCP_KEEPALIVE NFQWS_PORTS_UDP_KEEPALIVE NFQWS_OPT" ws_opt_validate NFQWS_OPT
select_mode_group NFQWS_ENABLE "enable nfqws ?" "NFQWS_PORTS_TCP NFQWS_PORTS_UDP NFQWS_TCP_PKT_OUT NFQWS_TCP_PKT_IN NFQWS_UDP_PKT_OUT NFQWS_UDP_PKT_IN NFQWS_PORTS_TCP_KEEPALIVE NFQWS_PORTS_UDP_KEEPALIVE NFQWS_OPT" nfqws_opt_validate NFQWS_OPT
}
select_mode_mode()

View File

@@ -1,5 +1,5 @@
CC ?= gcc
CFLAGS += -std=gnu99 -Os
CFLAGS += -std=gnu99 -Os -flto=auto
CFLAGS_BSD = -Wno-address-of-packed-member
CFLAGS_WIN = -static
LIBS =

View File

@@ -192,7 +192,7 @@ static void ip6_and(const struct in6_addr * restrict a, const struct in6_addr *
static void rtrim(char *s)
{
if (s)
for (char *p = s + strlen(s) - 1; p >= s && (*p == '\n' || *p == '\r'); p--) *p = '\0';
for (char *p = s + strlen(s) - 1; p >= s && (*p == '\n' || *p == '\r' || *p == ' ' || *p == '\t'); p--) *p = '\0';
}
@@ -217,6 +217,14 @@ static void exithelp(void)
exit(1);
}
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
#if defined(ZAPRET_GH_VER) || defined (ZAPRET_GH_HASH)
#define PRINT_VER printf("github version %s (%s)\n\n", TOSTRING(ZAPRET_GH_VER), TOSTRING(ZAPRET_GH_HASH))
#else
#define PRINT_VER printf("self-built version %s %s\n\n", __DATE__, __TIME__)
#endif
static void parse_params(int argc, char *argv[])
{
int option_index = 0;
@@ -245,6 +253,7 @@ static void parse_params(int argc, char *argv[])
{
case 0:
case 1:
PRINT_VER;
exithelp();
break;
case 2:

View File

@@ -0,0 +1,40 @@
#!/bin/sh
IPSET_DIR="$(dirname "$0")"
IPSET_DIR="$(cd "$IPSET_DIR"; pwd)"
. "$IPSET_DIR/def.sh"
TMPLIST="$TMPDIR/list.txt"
URL="https://antifilter.download/list/domains.lst"
dl()
{
# $1 - url
# $2 - file
# $3 - minsize
# $4 - maxsize
curl -L -H "Accept-Encoding: gzip" -k --fail --max-time 60 --connect-timeout 10 --retry 4 --max-filesize 251658240 -o "$TMPLIST" "$1" ||
{
echo list download failed : $1
exit 2
}
dlsize=$(LANG=C wc -c "$TMPLIST" | xargs | cut -f 1 -d ' ')
if test $dlsize -lt $3; then
echo list is too small : $dlsize bytes. can be bad.
exit 2
fi
zzcat "$TMPLIST" | tr -d '\015' | zz "$2"
rm -f "$TMPLIST"
}
# useful in case ipban set is used in custom scripts
FAIL=
getipban || FAIL=1
"$IPSET_DIR/create_ipset.sh"
[ -n "$FAIL" ] && exit
dl "$URL" "$ZHOSTLIST" 32768 4194304
exit 0

View File

@@ -35,7 +35,7 @@
static void trimstr(char *s)
{
char *p;
for (p = s + strlen(s) - 1; p >= s && (*p == '\n' || *p == '\r'); p--) *p = '\0';
for (p = s + strlen(s) - 1; p >= s && (*p == '\n' || *p == '\r' || *p == ' ' || *p == '\t'); p--) *p = '\0';
}
static const char* eai_str(int r)
@@ -458,6 +458,15 @@ static void exithelp(void)
);
exit(1);
}
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
#if defined(ZAPRET_GH_VER) || defined (ZAPRET_GH_HASH)
#define PRINT_VER printf("github version %s (%s)\n\n", TOSTRING(ZAPRET_GH_VER), TOSTRING(ZAPRET_GH_HASH))
#else
#define PRINT_VER printf("self-built version %s %s\n\n", __DATE__, __TIME__)
#endif
int main(int argc, char **argv)
{
int r, v, option_index = 0;
@@ -487,6 +496,7 @@ int main(int argc, char **argv)
switch (option_index)
{
case 0: /* help */
PRINT_VER;
exithelp();
break;
case 1: /* threads */

View File

@@ -1,5 +1,5 @@
CC ?= cc
CFLAGS += -std=gnu99 -s -Os -Wno-address-of-packed-member
CFLAGS += -std=gnu99 -s -Os -Wno-address-of-packed-member -flto=auto
LIBS = -lz
SRC_FILES = *.c crypto/*.c

View File

@@ -1,7 +1,6 @@
CC ?= gcc
CFLAGS += -std=gnu99 -Os
CFLAGS += -std=gnu99 -Os -flto=auto
CFLAGS_BSD = -Wno-address-of-packed-member
CFLAGS_MAC = -mmacosx-version-min=10.8
CFLAGS_CYGWIN = -Wno-address-of-packed-member -static
LIBS_LINUX = -lnetfilter_queue -lnfnetlink -lz
LIBS_BSD = -lz

View File

@@ -1082,7 +1082,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
}
ttl_fake = (ctrack_replay && ctrack_replay->autottl) ? ctrack_replay->autottl : (dis->ip6 ? (dp->desync_ttl6 ? dp->desync_ttl6 : ttl_orig) : (dp->desync_ttl ? dp->desync_ttl : ttl_orig));
if ((l7proto == HTTP) && (dp->hostcase || dp->hostnospace || dp->domcase) && HttpFindHost(&phost,dis->data_payload,dis->len_payload))
if ((l7proto == HTTP) && (dp->hostcase || dp->hostnospace || dp->domcase || dp->methodeol) && HttpFindHost(&phost,dis->data_payload,dis->len_payload))
{
if (dp->hostcase)
{
@@ -1098,23 +1098,40 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
verdict=VERDICT_MODIFY;
}
uint8_t *pua;
if (dp->hostnospace &&
(pua = (uint8_t*)memmem(dis->data_payload, dis->len_payload, "\r\nUser-Agent: ", 14)) &&
(pua = (uint8_t*)memmem(pua + 1, dis->len_payload - (pua - dis->data_payload) - 1, "\r\n", 2)))
if (dp->hostnospace)
{
DLOG("removing space after Host: and adding it to User-Agent:\n");
if (pua > phost)
if ((pua = (uint8_t*)memmem(dis->data_payload, dis->len_payload, "\r\nUser-Agent: ", 14)) &&
(pua = (uint8_t*)memmem(pua + 1, dis->len_payload - (pua - dis->data_payload) - 1, "\r\n", 2)))
{
memmove(phost + 5, phost + 6, pua - phost - 6);
pua[-1]=' ';
DLOG("removing space after Host: and adding it to User-Agent:\n");
if (pua > phost)
{
memmove(phost + 5, phost + 6, pua - phost - 6);
pua[-1]=' ';
}
else
{
memmove(pua + 1, pua, phost - pua + 5);
*pua = ' ';
}
verdict=VERDICT_MODIFY;
}
else
{
memmove(pua + 1, pua, phost - pua + 5);
*pua = ' ';
}
verdict=VERDICT_MODIFY;
DLOG("cannot do hostnospace because valid User-Agent: not found\n");
}
else if (dp->methodeol)
{
if (phost[5]==' ' || phost[5]=='\t')
{
DLOG("removing space after Host: and adding '\\n' before method\n");
memmove(dis->data_payload+1,dis->data_payload,phost-dis->data_payload+5);
dis->data_payload[0]='\n';
verdict=VERDICT_MODIFY;
}
else
DLOG("cannot do methodeol because there's no space or tab after Host:\n");
}
}
if (dp->desync_mode==DESYNC_NONE)
@@ -1395,7 +1412,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
if (i==0)
{
if (seqovl_pos>=from)
DLOG("seqovl>=split_pos (%u>=%zu). cancelling seqovl for part %d.\n",seqovl,from,i+2);
DLOG("seqovl>=split_pos (%zu>=%zu). cancelling seqovl for part %d.\n",seqovl,from,i+2);
else
{
seqovl = seqovl_pos;
@@ -1432,15 +1449,22 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
case DESYNC_FAKEDDISORDER:
if (split_pos)
{
uint8_t fakeseg[DPI_DESYNC_MAX_FAKE_LEN+100], *seg;
size_t seg_len;
uint8_t fakeseg[DPI_DESYNC_MAX_FAKE_LEN+100], fakeseg2[DPI_DESYNC_MAX_FAKE_LEN+100], pat[DPI_DESYNC_MAX_FAKE_LEN], *seg;
size_t seg_len,fakeseg2_len;
unsigned int seqovl;
if (dis->len_payload > sizeof(pat))
{
DLOG("packet is too large\n");
return verdict;
}
fill_pattern(pat,dis->len_payload,dp->fsplit_pattern,sizeof(dp->fsplit_pattern));
ip_id = IP4_IP_ID_FIX(dis->ip);
if (seqovl_pos>=split_pos)
{
DLOG("seqovl>=split_pos (%u>=%zu). cancelling seqovl.\n",seqovl_pos,split_pos);
DLOG("seqovl>=split_pos (%zu>=%zu). cancelling seqovl.\n",seqovl_pos,split_pos);
seqovl = 0;
}
else
@@ -1463,6 +1487,19 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
seg = dis->data_payload+split_pos;
seg_len = dis->len_payload-split_pos;
}
fakeseg2_len = sizeof(fakeseg2);
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, net32_add(dis->tcp->th_seq,split_pos), 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,
pat+split_pos, dis->len_payload-split_pos, fakeseg2, &fakeseg2_len))
return verdict;
ip_id=IP4_IP_ID_PREV(ip_id);
DLOG("sending fake(1) 2nd out-of-order tcp segment %zu-%zu len=%zu : ",split_pos,dis->len_payload-1, dis->len_payload-split_pos);
hexdump_limited_dlog(pat+split_pos,dis->len_payload-split_pos,PKTDATA_MAXDUMP); DLOG("\n");
if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , fakeseg2, fakeseg2_len))
return verdict;
pkt1_len = sizeof(pkt1);
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, net32_add(dis->tcp->th_seq , split_pos - seqovl), dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps,
ttl_orig,IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6),
@@ -1475,15 +1512,23 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len))
return verdict;
if (dis->ip) ((struct ip*)fakeseg2)->ip_id = ip_id;
ip_id=IP4_IP_ID_PREV(ip_id);
DLOG("sending fake(2) 2nd out-of-order tcp segment %zu-%zu len=%zu : ",split_pos,dis->len_payload-1, dis->len_payload-split_pos);
hexdump_limited_dlog(pat+split_pos,dis->len_payload-split_pos,PKTDATA_MAXDUMP); DLOG("\n");
if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , fakeseg2, fakeseg2_len))
return verdict;
seg_len = sizeof(fakeseg);
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,
zeropkt, split_pos, fakeseg, &seg_len))
pat, split_pos, fakeseg, &seg_len))
return verdict;
ip_id=IP4_IP_ID_PREV(ip_id);
DLOG("sending fake(1) 1st out-of-order tcp segment 0-%zu len=%zu : ",split_pos-1, split_pos);
hexdump_limited_dlog(zeropkt,split_pos,PKTDATA_MAXDUMP); DLOG("\n");
hexdump_limited_dlog(pat,split_pos,PKTDATA_MAXDUMP); DLOG("\n");
if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , fakeseg, seg_len))
return verdict;
@@ -1501,7 +1546,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
if (dis->ip) ((struct ip*)fakeseg)->ip_id = ip_id;
DLOG("sending fake(2) 1st out-of-order tcp segment 0-%zu len=%zu : ",split_pos-1, split_pos);
hexdump_limited_dlog(zeropkt,split_pos,PKTDATA_MAXDUMP); DLOG("\n");
hexdump_limited_dlog(pat,split_pos,PKTDATA_MAXDUMP); DLOG("\n");
if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , fakeseg, seg_len))
return verdict;
@@ -1511,20 +1556,27 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
case DESYNC_FAKEDSPLIT:
if (split_pos)
{
uint8_t fakeseg[DPI_DESYNC_MAX_FAKE_LEN+100],ovlseg[DPI_DESYNC_MAX_FAKE_LEN+100], *seg;
uint8_t fakeseg[DPI_DESYNC_MAX_FAKE_LEN+100],ovlseg[DPI_DESYNC_MAX_FAKE_LEN+100],pat[DPI_DESYNC_MAX_FAKE_LEN], *seg;
size_t fakeseg_len,seg_len;
if (dis->len_payload > sizeof(pat))
{
DLOG("packet is too large\n");
return verdict;
}
fill_pattern(pat,dis->len_payload,dp->fsplit_pattern,sizeof(dp->fsplit_pattern));
ip_id = IP4_IP_ID_FIX(dis->ip);
fakeseg_len = sizeof(fakeseg);
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,
zeropkt, split_pos, fakeseg, &fakeseg_len))
pat, split_pos, fakeseg, &fakeseg_len))
return verdict;
ip_id=IP4_IP_ID_NEXT(ip_id);
DLOG("sending fake(1) 1st tcp segment 0-%zu len=%zu : ",split_pos-1, split_pos);
hexdump_limited_dlog(zeropkt,split_pos,PKTDATA_MAXDUMP); DLOG("\n");
hexdump_limited_dlog(pat,split_pos,PKTDATA_MAXDUMP); DLOG("\n");
if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , fakeseg, fakeseg_len))
return verdict;
@@ -1579,7 +1631,19 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
if (dis->ip) ((struct ip*)fakeseg)->ip_id = ip_id;
ip_id=IP4_IP_ID_NEXT(ip_id);
DLOG("sending fake(2) 1st tcp segment 0-%zu len=%zu : ",split_pos-1, split_pos);
hexdump_limited_dlog(zeropkt,split_pos,PKTDATA_MAXDUMP); DLOG("\n");
hexdump_limited_dlog(pat,split_pos,PKTDATA_MAXDUMP); DLOG("\n");
if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , fakeseg, fakeseg_len))
return verdict;
fakeseg_len = sizeof(fakeseg);
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, net32_add(dis->tcp->th_seq,split_pos), 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,
pat+split_pos, dis->len_payload-split_pos, fakeseg, &fakeseg_len))
return verdict;
ip_id=IP4_IP_ID_NEXT(ip_id);
DLOG("sending fake(1) 2nd tcp segment %zu-%zu len=%zu : ",split_pos,dis->len_payload-1, dis->len_payload-split_pos);
hexdump_limited_dlog(pat+split_pos,dis->len_payload-split_pos,PKTDATA_MAXDUMP); DLOG("\n");
if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , fakeseg, fakeseg_len))
return verdict;
@@ -1589,11 +1653,19 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
fooling_orig,dp->desync_badseq_increment,dp->desync_badseq_ack_increment,
dis->data_payload+split_pos, dis->len_payload-split_pos, pkt1, &pkt1_len))
return verdict;
ip_id=IP4_IP_ID_NEXT(ip_id);
DLOG("sending 2nd tcp segment %zu-%zu len=%zu : ",split_pos,dis->len_payload-1, dis->len_payload-split_pos);
hexdump_limited_dlog(dis->data_payload+split_pos,dis->len_payload-split_pos,PKTDATA_MAXDUMP); DLOG("\n");
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len))
return verdict;
if (dis->ip) ((struct ip*)fakeseg)->ip_id = ip_id;
DLOG("sending fake(2) 2nd tcp segment %zu-%zu len=%zu : ",split_pos,dis->len_payload-1, dis->len_payload-split_pos);
hexdump_limited_dlog(pat+split_pos,dis->len_payload-split_pos,PKTDATA_MAXDUMP); DLOG("\n");
if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , fakeseg, fakeseg_len))
return verdict;
return VERDICT_DROP;
}
break;

View File

@@ -24,7 +24,7 @@ static bool addpool(strpool **hostlist, char **s, const char *end, int *ct)
*hostlist = NULL;
return false;
}
(*ct)++;
if (ct) (*ct)++;
}
// advance to the next line
for (; p<end && (!*p || *p=='\r' || *p=='\n') ; p++);
@@ -32,6 +32,11 @@ static bool addpool(strpool **hostlist, char **s, const char *end, int *ct)
return true;
}
bool AppendHostlistItem(strpool **hostlist, char *s)
{
return addpool(hostlist,&s,s+strlen(s),NULL);
}
bool AppendHostList(strpool **hostlist, const char *filename)
{
char *p, *e, s[256], *zbuf;
@@ -98,21 +103,24 @@ bool AppendHostList(strpool **hostlist, const char *filename)
static bool LoadHostList(struct hostlist_file *hfile)
{
time_t t = file_mod_time(hfile->filename);
if (!t)
{
// stat() error
DLOG_ERR("cannot access hostlist file '%s'. in-memory content remains unchanged.\n",hfile->filename);
return true;
}
if (t==hfile->mod_time) return true; // up to date
StrPoolDestroy(&hfile->hostlist);
if (!AppendHostList(&hfile->hostlist, hfile->filename))
if (hfile->filename)
{
time_t t = file_mod_time(hfile->filename);
if (!t)
{
// stat() error
DLOG_ERR("cannot access hostlist file '%s'. in-memory content remains unchanged.\n",hfile->filename);
return true;
}
if (t==hfile->mod_time) return true; // up to date
StrPoolDestroy(&hfile->hostlist);
return false;
if (!AppendHostList(&hfile->hostlist, hfile->filename))
{
StrPoolDestroy(&hfile->hostlist);
return false;
}
hfile->mod_time=t;
}
hfile->mod_time=t;
return true;
}
static bool LoadHostLists(struct hostlist_files_head *list)
@@ -202,7 +210,7 @@ static bool HostlistCheck_(const struct hostlist_collection_head *hostlists, con
LIST_FOREACH(item, hostlists_exclude, next)
{
DLOG("[%s] exclude ", item->hfile->filename);
DLOG("[%s] exclude ", item->hfile->filename ? item->hfile->filename : "fixed");
if (SearchHostList(item->hfile->hostlist, host))
{
if (excluded) *excluded = true;
@@ -214,7 +222,7 @@ static bool HostlistCheck_(const struct hostlist_collection_head *hostlists, con
{
LIST_FOREACH(item, hostlists, next)
{
DLOG("[%s] include ", item->hfile->filename);
DLOG("[%s] include ", item->hfile->filename ? item->hfile->filename : "fixed");
if (SearchHostList(item->hfile->hostlist, host))
return true;
}
@@ -235,17 +243,29 @@ bool HostlistCheck(const struct desync_profile *dp, const char *host, bool *excl
static struct hostlist_file *RegisterHostlist_(struct hostlist_files_head *hostlists, struct hostlist_collection_head *hl_collection, const char *filename)
{
struct hostlist_file *hfile;
if (!(hfile=hostlist_files_search(hostlists, filename)))
if (!(hfile=hostlist_files_add(hostlists, filename)))
if (filename)
{
if (!(hfile=hostlist_files_search(hostlists, filename)))
if (!(hfile=hostlist_files_add(hostlists, filename)))
return NULL;
if (!hostlist_collection_search(hl_collection, filename))
if (!hostlist_collection_add(hl_collection, hfile))
return NULL;
}
else
{
if (!(hfile=hostlist_files_add(hostlists, NULL)))
return NULL;
if (!hostlist_collection_search(hl_collection, filename))
if (!hostlist_collection_add(hl_collection, hfile))
return NULL;
}
return hfile;
}
struct hostlist_file *RegisterHostlist(struct desync_profile *dp, bool bExclude, const char *filename)
{
if (!file_mod_time(filename))
if (filename && !file_mod_time(filename))
{
DLOG_ERR("cannot access hostlist file '%s'\n",filename);
return NULL;
@@ -265,15 +285,30 @@ void HostlistsDebug()
struct hostlist_item *hl_item;
LIST_FOREACH(hfile, &params.hostlists, next)
DLOG("hostlist file %s%s\n",hfile->filename,hfile->hostlist ? "" : " (empty)");
{
if (hfile->filename)
DLOG("hostlist file %s%s\n",hfile->filename,hfile->hostlist ? "" : " (empty)");
else
DLOG("hostlist fixed%s\n",hfile->hostlist ? "" : " (empty)");
}
LIST_FOREACH(dpl, &params.desync_profiles, next)
{
LIST_FOREACH(hl_item, &dpl->dp.hl_collection, next)
if (hl_item->hfile!=dpl->dp.hostlist_auto)
DLOG("profile %d include hostlist %s%s\n",dpl->dp.n, hl_item->hfile->filename,hl_item->hfile->hostlist ? "" : " (empty)");
{
if (hl_item->hfile->filename)
DLOG("profile %d include hostlist %s%s\n",dpl->dp.n, hl_item->hfile->filename,hl_item->hfile->hostlist ? "" : " (empty)");
else
DLOG("profile %d include fixed hostlist%s\n",dpl->dp.n, hl_item->hfile->hostlist ? "" : " (empty)");
}
LIST_FOREACH(hl_item, &dpl->dp.hl_collection_exclude, next)
DLOG("profile %d exclude hostlist %s%s\n",dpl->dp.n,hl_item->hfile->filename,hl_item->hfile->hostlist ? "" : " (empty)");
{
if (hl_item->hfile->filename)
DLOG("profile %d exclude hostlist %s%s\n",dpl->dp.n,hl_item->hfile->filename,hl_item->hfile->hostlist ? "" : " (empty)");
else
DLOG("profile %d exclude fixed hostlist%s\n",dpl->dp.n,hl_item->hfile->hostlist ? "" : " (empty)");
}
if (dpl->dp.hostlist_auto)
DLOG("profile %d auto hostlist %s%s\n",dpl->dp.n,dpl->dp.hostlist_auto->filename,dpl->dp.hostlist_auto->hostlist ? "" : " (empty)");
}

View File

@@ -4,6 +4,7 @@
#include "pools.h"
#include "params.h"
bool AppendHostlistItem(strpool **hostlist, char *s);
bool AppendHostList(strpool **hostlist, const char *filename);
bool LoadAllHostLists();
bool NonEmptyHostlist(strpool **hostlist);

View File

@@ -31,7 +31,7 @@ static bool addpool(ipset *ips, char **s, const char *end, int *ct)
ipsetDestroy(ips);
return false;
}
(*ct)++;
if (ct) (*ct)++;
}
else if (parse_cidr6(cidr,&c6))
{
@@ -40,7 +40,7 @@ static bool addpool(ipset *ips, char **s, const char *end, int *ct)
ipsetDestroy(ips);
return false;
}
(*ct)++;
if (ct) (*ct)++;
}
else
DLOG_ERR("bad ip or subnet : %s\n",cidr);
@@ -53,6 +53,11 @@ static bool addpool(ipset *ips, char **s, const char *end, int *ct)
}
bool AppendIpsetItem(ipset *ips, char *ip)
{
return addpool(ips,&ip,ip+strlen(ip),NULL);
}
static bool AppendIpset(ipset *ips, const char *filename)
{
char *p, *e, s[256], *zbuf;
@@ -119,21 +124,24 @@ static bool AppendIpset(ipset *ips, const char *filename)
static bool LoadIpset(struct ipset_file *hfile)
{
time_t t = file_mod_time(hfile->filename);
if (!t)
{
// stat() error
DLOG_ERR("cannot access ipset file '%s'. in-memory content remains unchanged.\n",hfile->filename);
return true;
}
if (t==hfile->mod_time) return true; // up to date
ipsetDestroy(&hfile->ipset);
if (!AppendIpset(&hfile->ipset, hfile->filename))
if (hfile->filename)
{
time_t t = file_mod_time(hfile->filename);
if (!t)
{
// stat() error
DLOG_ERR("cannot access ipset file '%s'. in-memory content remains unchanged.\n",hfile->filename);
return true;
}
if (t==hfile->mod_time) return true; // up to date
ipsetDestroy(&hfile->ipset);
return false;
if (!AppendIpset(&hfile->ipset, hfile->filename))
{
ipsetDestroy(&hfile->ipset);
return false;
}
hfile->mod_time=t;
}
hfile->mod_time=t;
return true;
}
static bool LoadIpsets(struct ipset_files_head *list)
@@ -205,7 +213,7 @@ static bool IpsetCheck_(const struct ipset_collection_head *ips, const struct ip
LIST_FOREACH(item, ips_exclude, next)
{
DLOG("[%s] exclude ",item->hfile->filename);
DLOG("[%s] exclude ",item->hfile->filename ? item->hfile->filename : "fixed");
if (SearchIpset(&item->hfile->ipset, ipv4, ipv6))
return false;
}
@@ -214,7 +222,7 @@ static bool IpsetCheck_(const struct ipset_collection_head *ips, const struct ip
{
LIST_FOREACH(item, ips, next)
{
DLOG("[%s] include ",item->hfile->filename);
DLOG("[%s] include ",item->hfile->filename ? item->hfile->filename : "fixed");
if (SearchIpset(&item->hfile->ipset, ipv4, ipv6))
return true;
}
@@ -234,17 +242,27 @@ bool IpsetCheck(const struct desync_profile *dp, const struct in_addr *ipv4, con
static struct ipset_file *RegisterIpset_(struct ipset_files_head *ipsets, struct ipset_collection_head *ips_collection, const char *filename)
{
struct ipset_file *hfile;
if (!(hfile=ipset_files_search(ipsets, filename)))
if (!(hfile=ipset_files_add(ipsets, filename)))
if (filename)
{
if (!(hfile=ipset_files_search(ipsets, filename)))
if (!(hfile=ipset_files_add(ipsets, filename)))
return NULL;
if (!ipset_collection_search(ips_collection, filename))
if (!ipset_collection_add(ips_collection, hfile))
return NULL;
}
else
{
if (!(hfile=ipset_files_add(ipsets, NULL)))
return NULL;
if (!ipset_collection_search(ips_collection, filename))
if (!ipset_collection_add(ips_collection, hfile))
return NULL;
}
return hfile;
}
struct ipset_file *RegisterIpset(struct desync_profile *dp, bool bExclude, const char *filename)
{
if (!file_mod_time(filename))
if (filename && !file_mod_time(filename))
{
DLOG_ERR("cannot access ipset file '%s'\n",filename);
return NULL;
@@ -277,13 +295,24 @@ void IpsetsDebug()
struct ipset_item *ips_item;
LIST_FOREACH(hfile, &params.ipsets, next)
DLOG("ipset file %s (%s)\n",hfile->filename,dbg_ipset_fill(&hfile->ipset));
{
if (hfile->filename)
DLOG("ipset file %s (%s)\n",hfile->filename,dbg_ipset_fill(&hfile->ipset));
else
DLOG("ipset fixed (%s)\n",dbg_ipset_fill(&hfile->ipset));
}
LIST_FOREACH(dpl, &params.desync_profiles, next)
{
LIST_FOREACH(ips_item, &dpl->dp.ips_collection, next)
DLOG("profile %d include ipset %s (%s)\n",dpl->dp.n,ips_item->hfile->filename,dbg_ipset_fill(&ips_item->hfile->ipset));
if (ips_item->hfile->filename)
DLOG("profile %d include ipset %s (%s)\n",dpl->dp.n,ips_item->hfile->filename,dbg_ipset_fill(&ips_item->hfile->ipset));
else
DLOG("profile %d include fixed ipset (%s)\n",dpl->dp.n,dbg_ipset_fill(&ips_item->hfile->ipset));
LIST_FOREACH(ips_item, &dpl->dp.ips_collection_exclude, next)
DLOG("profile %d exclude ipset %s (%s)\n",dpl->dp.n,ips_item->hfile->filename,dbg_ipset_fill(&ips_item->hfile->ipset));
if (ips_item->hfile->filename)
DLOG("profile %d exclude ipset %s (%s)\n",dpl->dp.n,ips_item->hfile->filename,dbg_ipset_fill(&ips_item->hfile->ipset));
else
DLOG("profile %d exclude fixed ipset (%s)\n",dpl->dp.n,dbg_ipset_fill(&ips_item->hfile->ipset));
}
}

View File

@@ -9,3 +9,4 @@ bool LoadAllIpsets();
bool IpsetCheck(const struct desync_profile *dp, const struct in_addr *ipv4, const struct in6_addr *ipv6);
struct ipset_file *RegisterIpset(struct desync_profile *dp, bool bExclude, const char *filename);
void IpsetsDebug();
bool AppendIpsetItem(ipset *ips, char *ip);

View File

@@ -836,6 +836,47 @@ static bool parse_split_pos_list(char *opt, struct proto_pos *splits, int splits
if (p) return false; // too much splits
return true;
}
static bool parse_domain_list(char *opt, strpool **pp)
{
char *e,*p,c;
for (p=opt ; p ; )
{
if ((e = strchr(p,',')))
{
c=*e;
*e=0;
}
if (*p && !AppendHostlistItem(pp,p)) return false;
if (e) *e++=c;
p = e;
}
return true;
}
static bool parse_ip_list(char *opt, ipset *pp)
{
char *e,*p,c;
for (p=opt ; p ; )
{
if ((e = strchr(p,',')))
{
c=*e;
*e=0;
}
if (*p && !AppendIpsetItem(pp,p)) return false;
if (e) *e++=c;
p = e;
}
return true;
}
static void split_compat(struct desync_profile *dp)
{
if (!dp->split_count)
@@ -989,6 +1030,7 @@ static void exithelp(void)
" @<config_file>|$<config_file>\t\t\t; read file for options. must be the only argument. other options are ignored.\n\n"
#endif
" --debug=0|1|syslog|@<filename>\n"
" --dry-run\t\t\t\t\t; verify parameters and exit with code 0 if successful\n"
#ifdef __linux__
" --qnum=<nfqueue_number>\n"
#elif defined(BSD)
@@ -1020,15 +1062,20 @@ static void exithelp(void)
#endif
"\nMULTI-STRATEGY:\n"
" --new\t\t\t\t\t\t; begin new strategy\n"
" --skip\t\t\t\t\t\t; do not use this strategy\n"
" --filter-l3=ipv4|ipv6\t\t\t\t; L3 protocol filter. multiple comma separated values allowed.\n"
" --filter-tcp=[~]port1[-port2]|*\t\t; TCP port filter. ~ means negation. setting tcp and not setting udp filter denies udp. comma separated list allowed.\n"
" --filter-udp=[~]port1[-port2]|*\t\t; UDP port filter. ~ means negation. setting udp and not setting tcp filter denies tcp. comma separated list allowed.\n"
" --filter-l7=[http|tls|quic|wireguard|dht|unknown] ; L6-L7 protocol filter. multiple comma separated values allowed.\n"
" --ipset=<filename>\t\t\t\t; ipset include filter (one ip/CIDR per line, ipv4 and ipv6 accepted, gzip supported, multiple ipsets allowed)\n"
" --ipset-ip=<ip_list>\t\t\t\t; comma separated fixed subnet list\n"
" --ipset-exclude=<filename>\t\t\t; ipset exclude filter (one ip/CIDR per line, ipv4 and ipv6 accepted, gzip supported, multiple ipsets allowed)\n"
" --ipset-exclude-ip=<ip_list>\t\t\t; comma separated fixed subnet list\n"
"\nHOSTLIST FILTER:\n"
" --hostlist=<filename>\t\t\t\t; apply dpi desync only to the listed hosts (one host per line, subdomains auto apply, gzip supported, multiple hostlists allowed)\n"
" --hostlist-domains=<domain_list>\t\t; comma separated fixed domain list\n"
" --hostlist-exclude=<filename>\t\t\t; do not apply dpi desync to the listed hosts (one host per line, subdomains auto apply, gzip supported, multiple hostlists allowed)\n"
" --hostlist-exclude-domains=<domain_list>\t; comma separated fixed domain list\n"
" --hostlist-auto=<filename>\t\t\t; detect DPI blocks and build hostlist automatically\n"
" --hostlist-auto-fail-threshold=<int>\t\t; how many failed attempts cause hostname to be added to auto hostlist (default : %d)\n"
" --hostlist-auto-fail-time=<int>\t\t; all failed attemps must be within these seconds (default : %d)\n"
@@ -1042,6 +1089,7 @@ static void exithelp(void)
" --hostspell\t\t\t\t\t; exact spelling of \"Host\" header. must be 4 chars. default is \"host\"\n"
" --hostnospace\t\t\t\t\t; remove space after Host: and add it to User-Agent: to preserve packet size\n"
" --domcase\t\t\t\t\t; mix domain case : Host: TeSt.cOm\n"
" --methodeol\t\t\t\t\t; add '\\n' before method and remove space from Host:\n"
" --dpi-desync=[<mode0>,]<mode>[,<mode2>]\t; try to desync dpi state. modes :\n"
"\t\t\t\t\t\t; synack syndata fake fakeknown rst rstack hopbyhop destopt ipfrag1\n"
"\t\t\t\t\t\t; multisplit multidisorder fakedsplit fakeddisorder ipfrag2 udplen tamper\n"
@@ -1063,6 +1111,7 @@ static void exithelp(void)
"\t\t\t\t\t\t; fakedsplit/fakeddisorder use first l7-protocol-compatible parameter if present, first abs value otherwise\n"
" --dpi-desync-split-seqovl=N|-N|marker+N|marker-N ; use sequence overlap before first sent original split segment\n"
" --dpi-desync-split-seqovl-pattern=<filename>|0xHEX ; pattern for the fake part of overlap\n"
" --dpi-desync-fakedsplit-pattern=<filename>|0xHEX ; fake pattern for fakedsplit/fakeddisorder\n"
" --dpi-desync-ipfrag-pos-tcp=<8..%u>\t\t; ip frag position starting from the transport header. multiple of 8, default %u.\n"
" --dpi-desync-ipfrag-pos-udp=<8..%u>\t\t; ip frag position starting from the transport header. multiple of 8, default %u.\n"
" --dpi-desync-badseq-increment=<int|0xHEX>\t; badseq fooling seq signed increment. default %d\n"
@@ -1126,6 +1175,14 @@ void config_from_file(const char *filename)
}
#endif
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
#if defined(ZAPRET_GH_VER) || defined (ZAPRET_GH_HASH)
#define PRINT_VER printf("github version %s (%s)\n\n", TOSTRING(ZAPRET_GH_VER), TOSTRING(ZAPRET_GH_HASH))
#else
#define PRINT_VER printf("self-built version %s %s\n\n", __DATE__, __TIME__)
#endif
int main(int argc, char **argv)
{
set_env_exedir(argv[0]);
@@ -1139,8 +1196,10 @@ int main(int argc, char **argv)
#endif
int result, v;
int option_index = 0;
bool daemon = false;
bool daemon = false, bSkip = false, bDry = false;
char pidfile[256];
struct hostlist_file *anon_hl = NULL, *anon_hl_exclude = NULL;
struct ipset_file *anon_ips = NULL, *anon_ips_exclude = NULL;
#ifdef __CYGWIN__
char windivert_filter[8192], wf_pf_tcp_src[256], wf_pf_tcp_dst[256], wf_pf_udp_src[256], wf_pf_udp_dst[256], wf_save_file[256];
bool wf_ipv4=true, wf_ipv6=true;
@@ -1152,6 +1211,8 @@ int main(int argc, char **argv)
srandom(time(NULL));
mask_from_preflen6_prepare();
PRINT_VER;
memset(&params, 0, sizeof(params));
*pidfile = 0;
@@ -1203,101 +1264,113 @@ int main(int argc, char **argv)
const struct option long_options[] = {
{"debug",optional_argument,0,0}, // optidx=0
{"dry-run",no_argument,0,0}, // optidx=1
#ifdef __linux__
{"qnum",required_argument,0,0}, // optidx=1
{"qnum",required_argument,0,0}, // optidx=2
#elif defined(BSD)
{"port",required_argument,0,0}, // optidx=1
{"port",required_argument,0,0}, // optidx=2
#else
{"disabled_argument_1",no_argument,0,0},// optidx=1
{"disabled_argument_1",no_argument,0,0},// optidx=2
#endif
{"daemon",no_argument,0,0}, // optidx=2
{"pidfile",required_argument,0,0}, // optidx=3
{"daemon",no_argument,0,0}, // optidx=3
{"pidfile",required_argument,0,0}, // optidx=4
#ifndef __CYGWIN__
{"user",required_argument,0,0 }, // optidx=4
{"uid",required_argument,0,0 }, // optidx=5
{"user",required_argument,0,0 }, // optidx=5
{"uid",required_argument,0,0 }, // optidx=6
#else
{"disabled_argument_2",no_argument,0,0}, // optidx=4
{"disabled_argument_3",no_argument,0,0}, // optidx=5
{"disabled_argument_2",no_argument,0,0}, // optidx=5
{"disabled_argument_3",no_argument,0,0}, // optidx=6
#endif
{"wsize",required_argument,0,0}, // optidx=6
{"wssize",required_argument,0,0}, // optidx=7
{"wssize-cutoff",required_argument,0,0},// optidx=8
{"ctrack-timeouts",required_argument,0,0},// optidx=9
{"hostcase",no_argument,0,0}, // optidx=10
{"hostspell",required_argument,0,0}, // optidx=11
{"hostnospace",no_argument,0,0}, // optidx=12
{"domcase",no_argument,0,0 }, // optidx=13
{"dpi-desync",required_argument,0,0}, // optidx=14
{"wsize",required_argument,0,0}, // optidx=7
{"wssize",required_argument,0,0}, // optidx=8
{"wssize-cutoff",required_argument,0,0},// optidx=9
{"ctrack-timeouts",required_argument,0,0},// optidx=10
{"hostcase",no_argument,0,0}, // optidx=11
{"hostspell",required_argument,0,0}, // optidx=12
{"hostnospace",no_argument,0,0}, // optidx=13
{"domcase",no_argument,0,0 }, // optidx=14
{"methodeol",no_argument,0,0 }, // optidx=15
{"dpi-desync",required_argument,0,0}, // optidx=17
#ifdef __linux__
{"dpi-desync-fwmark",required_argument,0,0}, // optidx=15
{"dpi-desync-fwmark",required_argument,0,0}, // optidx=17
#elif defined(SO_USER_COOKIE)
{"dpi-desync-sockarg",required_argument,0,0}, // optidx=15
{"dpi-desync-sockarg",required_argument,0,0}, // optidx=17
#else
{"disabled_argument_4",no_argument,0,0}, // optidx=15
{"disabled_argument_4",no_argument,0,0}, // optidx=17
#endif
{"dpi-desync-ttl",required_argument,0,0}, // optidx=16
{"dpi-desync-ttl6",required_argument,0,0}, // optidx=17
{"dpi-desync-autottl",optional_argument,0,0}, // optidx=18
{"dpi-desync-autottl6",optional_argument,0,0}, // optidx=19
{"dpi-desync-fooling",required_argument,0,0}, // optidx=20
{"dpi-desync-repeats",required_argument,0,0}, // optidx=21
{"dpi-desync-skip-nosni",optional_argument,0,0},// optidx=22
{"dpi-desync-split-pos",required_argument,0,0},// optidx=23
{"dpi-desync-split-http-req",required_argument,0,0 },// optidx=24
{"dpi-desync-split-tls",required_argument,0,0 },// optidx=25
{"dpi-desync-split-seqovl",required_argument,0,0 },// optidx=26
{"dpi-desync-split-seqovl-pattern",required_argument,0,0 },// optidx=27
{"dpi-desync-ipfrag-pos-tcp",required_argument,0,0},// optidx=28
{"dpi-desync-ipfrag-pos-udp",required_argument,0,0},// optidx=29
{"dpi-desync-badseq-increment",required_argument,0,0},// optidx=30
{"dpi-desync-badack-increment",required_argument,0,0},// optidx=31
{"dpi-desync-any-protocol",optional_argument,0,0},// optidx=32
{"dpi-desync-fake-http",required_argument,0,0},// optidx=33
{"dpi-desync-fake-tls",required_argument,0,0},// optidx=34
{"dpi-desync-fake-unknown",required_argument,0,0},// optidx=35
{"dpi-desync-fake-syndata",required_argument,0,0},// optidx=36
{"dpi-desync-fake-quic",required_argument,0,0},// optidx=37
{"dpi-desync-fake-wireguard",required_argument,0,0},// optidx=38
{"dpi-desync-fake-dht",required_argument,0,0},// optidx=39
{"dpi-desync-fake-unknown-udp",required_argument,0,0},// optidx=40
{"dpi-desync-udplen-increment",required_argument,0,0},// optidx=41
{"dpi-desync-udplen-pattern",required_argument,0,0},// optidx=42
{"dpi-desync-cutoff",required_argument,0,0},// optidx=43
{"dpi-desync-start",required_argument,0,0},// optidx=43
{"hostlist",required_argument,0,0}, // optidx=44
{"hostlist-exclude",required_argument,0,0}, // optidx=45
{"hostlist-auto",required_argument,0,0}, // optidx=46
{"hostlist-auto-fail-threshold",required_argument,0,0}, // optidx=48
{"hostlist-auto-fail-time",required_argument,0,0}, // optidx=49
{"hostlist-auto-retrans-threshold",required_argument,0,0}, // optidx=50
{"hostlist-auto-debug",required_argument,0,0}, // optidx=51
{"new",no_argument,0,0}, // optidx=52
{"filter-l3",required_argument,0,0}, // optidx=53
{"filter-tcp",required_argument,0,0}, // optidx=54
{"filter-udp",required_argument,0,0}, // optidx=55
{"filter-l7",required_argument,0,0}, // optidx=56
{"ipset",required_argument,0,0}, // optidx=57
{"ipset-exclude",required_argument,0,0},// optidx=58
{"dpi-desync-ttl",required_argument,0,0}, // optidx=18
{"dpi-desync-ttl6",required_argument,0,0}, // optidx=19
{"dpi-desync-autottl",optional_argument,0,0}, // optidx=20
{"dpi-desync-autottl6",optional_argument,0,0}, // optidx=21
{"dpi-desync-fooling",required_argument,0,0}, // optidx=22
{"dpi-desync-repeats",required_argument,0,0}, // optidx=23
{"dpi-desync-skip-nosni",optional_argument,0,0},// optidx=24
{"dpi-desync-split-pos",required_argument,0,0},// optidx=25
{"dpi-desync-split-http-req",required_argument,0,0 },// optidx=26
{"dpi-desync-split-tls",required_argument,0,0 },// optidx=27
{"dpi-desync-split-seqovl",required_argument,0,0 },// optidx=28
{"dpi-desync-split-seqovl-pattern",required_argument,0,0 },// optidx=29
{"dpi-desync-fakedsplit-pattern",required_argument,0,0 },// optidx=30
{"dpi-desync-ipfrag-pos-tcp",required_argument,0,0},// optidx=31
{"dpi-desync-ipfrag-pos-udp",required_argument,0,0},// optidx=32
{"dpi-desync-badseq-increment",required_argument,0,0},// optidx=33
{"dpi-desync-badack-increment",required_argument,0,0},// optidx=34
{"dpi-desync-any-protocol",optional_argument,0,0},// optidx=35
{"dpi-desync-fake-http",required_argument,0,0},// optidx=36
{"dpi-desync-fake-tls",required_argument,0,0},// optidx=37
{"dpi-desync-fake-unknown",required_argument,0,0},// optidx=38
{"dpi-desync-fake-syndata",required_argument,0,0},// optidx=39
{"dpi-desync-fake-quic",required_argument,0,0},// optidx=40
{"dpi-desync-fake-wireguard",required_argument,0,0},// optidx=41
{"dpi-desync-fake-dht",required_argument,0,0},// optidx=42
{"dpi-desync-fake-unknown-udp",required_argument,0,0},// optidx=43
{"dpi-desync-udplen-increment",required_argument,0,0},// optidx=44
{"dpi-desync-udplen-pattern",required_argument,0,0},// optidx=45
{"dpi-desync-cutoff",required_argument,0,0},// optidx=46
{"dpi-desync-start",required_argument,0,0},// optidx=47
{"hostlist",required_argument,0,0}, // optidx=48
{"hostlist-domains",required_argument,0,0},// optidx=49
{"hostlist-exclude",required_argument,0,0}, // optidx=50
{"hostlist-exclude-domains",required_argument,0,0},// optidx=51
{"hostlist-auto",required_argument,0,0}, // optidx=52
{"hostlist-auto-fail-threshold",required_argument,0,0}, // optidx=53
{"hostlist-auto-fail-time",required_argument,0,0}, // optidx=54
{"hostlist-auto-retrans-threshold",required_argument,0,0}, // optidx=55
{"hostlist-auto-debug",required_argument,0,0}, // optidx=56
{"new",no_argument,0,0}, // optidx=57
{"skip",no_argument,0,0}, // optidx=58
{"filter-l3",required_argument,0,0}, // optidx=59
{"filter-tcp",required_argument,0,0}, // optidx=60
{"filter-udp",required_argument,0,0}, // optidx=61
{"filter-l7",required_argument,0,0}, // optidx=62
{"ipset",required_argument,0,0}, // optidx=63
{"ipset-ip",required_argument,0,0}, // optidx=64
{"ipset-exclude",required_argument,0,0},// optidx=65
{"ipset-exclude-ip",required_argument,0,0}, // optidx=66
#ifdef __linux__
{"bind-fix4",no_argument,0,0}, // optidx=59
{"bind-fix6",no_argument,0,0}, // optidx=60
{"bind-fix4",no_argument,0,0}, // optidx=67
{"bind-fix6",no_argument,0,0}, // optidx=68
#elif defined(__CYGWIN__)
{"wf-iface",required_argument,0,0}, // optidx=59
{"wf-l3",required_argument,0,0}, // optidx=60
{"wf-tcp",required_argument,0,0}, // optidx=61
{"wf-udp",required_argument,0,0}, // optidx=62
{"wf-raw",required_argument,0,0}, // optidx=63
{"wf-save",required_argument,0,0}, // optidx=64
{"ssid-filter",required_argument,0,0}, // optidx=65
{"nlm-filter",required_argument,0,0}, // optidx=66
{"nlm-list",optional_argument,0,0}, // optidx=67
{"wf-iface",required_argument,0,0}, // optidx=67
{"wf-l3",required_argument,0,0}, // optidx=68
{"wf-tcp",required_argument,0,0}, // optidx=69
{"wf-udp",required_argument,0,0}, // optidx=70
{"wf-raw",required_argument,0,0}, // optidx=71
{"wf-save",required_argument,0,0}, // optidx=72
{"ssid-filter",required_argument,0,0}, // optidx=73
{"nlm-filter",required_argument,0,0}, // optidx=74
{"nlm-list",optional_argument,0,0}, // optidx=75
#endif
{NULL,0,NULL,0}
};
if (argc < 2) exithelp();
if (argc < 2) exithelp_clean();
while ((v = getopt_long_only(argc, argv, "", long_options, &option_index)) != -1)
{
if (v) exithelp();
if (v)
if (bDry)
exit_clean(1);
else
exithelp_clean();
switch (option_index)
{
case 0: /* debug */
@@ -1335,7 +1408,10 @@ int main(int argc, char **argv)
}
break;
#ifndef __CYGWIN__
case 1: /* qnum or port */
case 1: /* dry-run */
bDry=true;
break;
case 2: /* qnum or port */
#ifdef __linux__
params.qnum = atoi(optarg);
if (params.qnum < 0 || params.qnum>65535)
@@ -1356,15 +1432,15 @@ int main(int argc, char **argv)
#endif
break;
#endif
case 2: /* daemon */
case 3: /* daemon */
daemon = true;
break;
case 3: /* pidfile */
case 4: /* pidfile */
strncpy(pidfile, optarg, sizeof(pidfile));
pidfile[sizeof(pidfile) - 1] = '\0';
break;
#ifndef __CYGWIN__
case 4: /* user */
case 5: /* user */
{
struct passwd *pwd = getpwnam(optarg);
if (!pwd)
@@ -1377,7 +1453,7 @@ int main(int argc, char **argv)
params.droproot = true;
break;
}
case 5: /* uid */
case 6: /* uid */
params.gid = 0x7FFFFFFF; // default gid. drop gid=0
params.droproot = true;
if (sscanf(optarg, "%u:%u", &params.uid, &params.gid)<1)
@@ -1387,32 +1463,32 @@ int main(int argc, char **argv)
}
break;
#endif
case 6: /* wsize */
case 7: /* wsize */
if (!parse_ws_scale_factor(optarg,&dp->wsize,&dp->wscale))
exit_clean(1);
break;
case 7: /* wssize */
case 8: /* wssize */
if (!parse_ws_scale_factor(optarg,&dp->wssize,&dp->wsscale))
exit_clean(1);
break;
case 8: /* wssize-cutoff */
case 9: /* wssize-cutoff */
if (!parse_cutoff(optarg, &dp->wssize_cutoff, &dp->wssize_cutoff_mode))
{
DLOG_ERR("invalid wssize-cutoff value\n");
exit_clean(1);
}
break;
case 9: /* ctrack-timeouts */
case 10: /* ctrack-timeouts */
if (sscanf(optarg, "%u:%u:%u:%u", &params.ctrack_t_syn, &params.ctrack_t_est, &params.ctrack_t_fin, &params.ctrack_t_udp)<3)
{
DLOG_ERR("invalid ctrack-timeouts value\n");
exit_clean(1);
}
break;
case 10: /* hostcase */
case 11: /* hostcase */
dp->hostcase = true;
break;
case 11: /* hostspell */
case 12: /* hostspell */
if (strlen(optarg) != 4)
{
DLOG_ERR("hostspell must be exactly 4 chars long\n");
@@ -1421,13 +1497,26 @@ int main(int argc, char **argv)
dp->hostcase = true;
memcpy(dp->hostspell, optarg, 4);
break;
case 12: /* hostnospace */
case 13: /* hostnospace */
if (dp->methodeol)
{
DLOG_ERR("--hostnospace and --methodeol are incompatible\n");
exit_clean(1);
}
dp->hostnospace = true;
break;
case 13: /* domcase */
case 14: /* domcase */
dp->domcase = true;
break;
case 14: /* dpi-desync */
case 15: /* methodeol */
if (dp->hostnospace)
{
DLOG_ERR("--hostnospace and --methodeol are incompatible\n");
exit_clean(1);
}
dp->methodeol = true;
break;
case 16: /* dpi-desync */
{
char *mode=optarg,*mode2,*mode3;
mode2 = mode ? strchr(mode,',') : NULL;
@@ -1473,7 +1562,7 @@ int main(int argc, char **argv)
}
break;
#ifndef __CYGWIN__
case 15: /* dpi-desync-fwmark/dpi-desync-sockarg */
case 17: /* dpi-desync-fwmark/dpi-desync-sockarg */
#if defined(__linux__) || defined(SO_USER_COOKIE)
params.desync_fwmark = 0;
if (sscanf(optarg, "0x%X", &params.desync_fwmark)<=0) sscanf(optarg, "%u", &params.desync_fwmark);
@@ -1488,27 +1577,27 @@ int main(int argc, char **argv)
#endif
break;
#endif
case 16: /* dpi-desync-ttl */
case 18: /* dpi-desync-ttl */
dp->desync_ttl = (uint8_t)atoi(optarg);
break;
case 17: /* dpi-desync-ttl6 */
case 19: /* dpi-desync-ttl6 */
dp->desync_ttl6 = (uint8_t)atoi(optarg);
break;
case 18: /* dpi-desync-autottl */
case 20: /* dpi-desync-autottl */
if (!parse_autottl(optarg, &dp->desync_autottl))
{
DLOG_ERR("dpi-desync-autottl value error\n");
exit_clean(1);
}
break;
case 19: /* dpi-desync-autottl6 */
case 21: /* dpi-desync-autottl6 */
if (!parse_autottl(optarg, &dp->desync_autottl6))
{
DLOG_ERR("dpi-desync-autottl6 value error\n");
exit_clean(1);
}
break;
case 20: /* dpi-desync-fooling */
case 22: /* dpi-desync-fooling */
{
char *e,*p = optarg;
while (p)
@@ -1543,17 +1632,17 @@ int main(int argc, char **argv)
}
}
break;
case 21: /* dpi-desync-repeats */
case 23: /* dpi-desync-repeats */
if (sscanf(optarg,"%u",&dp->desync_repeats)<1 || !dp->desync_repeats || dp->desync_repeats>20)
{
DLOG_ERR("dpi-desync-repeats must be within 1..20\n");
exit_clean(1);
}
break;
case 22: /* dpi-desync-skip-nosni */
case 24: /* dpi-desync-skip-nosni */
dp->desync_skip_nosni = !optarg || atoi(optarg);
break;
case 23: /* dpi-desync-split-pos */
case 25: /* dpi-desync-split-pos */
{
int ct;
if (!parse_split_pos_list(optarg,dp->splits+dp->split_count,MAX_SPLITS-dp->split_count,&ct))
@@ -1564,7 +1653,7 @@ int main(int argc, char **argv)
dp->split_count += ct;
}
break;
case 24: /* dpi-desync-split-http-req */
case 26: /* dpi-desync-split-http-req */
// obsolete arg
DLOG_CONDUP("WARNING ! --dpi-desync-split-http-req is deprecated. use --dpi-desync-split-pos with markers.\n",MAX_SPLITS);
if (dp->split_count>=MAX_SPLITS)
@@ -1579,7 +1668,7 @@ int main(int argc, char **argv)
}
dp->split_count++;
break;
case 25: /* dpi-desync-split-tls */
case 27: /* dpi-desync-split-tls */
// obsolete arg
DLOG_CONDUP("WARNING ! --dpi-desync-split-tls is deprecated. use --dpi-desync-split-pos with markers.\n",MAX_SPLITS);
if (dp->split_count>=MAX_SPLITS)
@@ -1594,7 +1683,7 @@ int main(int argc, char **argv)
}
dp->split_count++;
break;
case 26: /* dpi-desync-split-seqovl */
case 28: /* dpi-desync-split-seqovl */
if (!strcmp(optarg,"0"))
{
// allow zero = disable seqovl
@@ -1607,7 +1696,7 @@ int main(int argc, char **argv)
exit_clean(1);
}
break;
case 27: /* dpi-desync-split-seqovl-pattern */
case 29: /* dpi-desync-split-seqovl-pattern */
{
char buf[sizeof(dp->seqovl_pattern)];
size_t sz=sizeof(buf);
@@ -1615,7 +1704,15 @@ int main(int argc, char **argv)
fill_pattern(dp->seqovl_pattern,sizeof(dp->seqovl_pattern),buf,sz);
}
break;
case 28: /* dpi-desync-ipfrag-pos-tcp */
case 30: /* dpi-desync-fakedsplit-pattern */
{
char buf[sizeof(dp->fsplit_pattern)];
size_t sz=sizeof(buf);
load_file_or_exit(optarg,buf,&sz);
fill_pattern(dp->fsplit_pattern,sizeof(dp->fsplit_pattern),buf,sz);
}
break;
case 31: /* dpi-desync-ipfrag-pos-tcp */
if (sscanf(optarg,"%u",&dp->desync_ipfrag_pos_tcp)<1 || dp->desync_ipfrag_pos_tcp<1 || dp->desync_ipfrag_pos_tcp>DPI_DESYNC_MAX_FAKE_LEN)
{
DLOG_ERR("dpi-desync-ipfrag-pos-tcp must be within 1..%u range\n",DPI_DESYNC_MAX_FAKE_LEN);
@@ -1627,7 +1724,7 @@ int main(int argc, char **argv)
exit_clean(1);
}
break;
case 29: /* dpi-desync-ipfrag-pos-udp */
case 32: /* dpi-desync-ipfrag-pos-udp */
if (sscanf(optarg,"%u",&dp->desync_ipfrag_pos_udp)<1 || dp->desync_ipfrag_pos_udp<1 || dp->desync_ipfrag_pos_udp>DPI_DESYNC_MAX_FAKE_LEN)
{
DLOG_ERR("dpi-desync-ipfrag-pos-udp must be within 1..%u range\n",DPI_DESYNC_MAX_FAKE_LEN);
@@ -1639,63 +1736,63 @@ int main(int argc, char **argv)
exit_clean(1);
}
break;
case 30: /* dpi-desync-badseq-increments */
case 33: /* dpi-desync-badseq-increments */
if (!parse_badseq_increment(optarg,&dp->desync_badseq_increment))
{
DLOG_ERR("dpi-desync-badseq-increment should be signed decimal or signed 0xHEX\n");
exit_clean(1);
}
break;
case 31: /* dpi-desync-badack-increment */
case 34: /* dpi-desync-badack-increment */
if (!parse_badseq_increment(optarg,&dp->desync_badseq_ack_increment))
{
DLOG_ERR("dpi-desync-badack-increment should be signed decimal or signed 0xHEX\n");
exit_clean(1);
}
break;
case 32: /* dpi-desync-any-protocol */
case 35: /* dpi-desync-any-protocol */
dp->desync_any_proto = !optarg || atoi(optarg);
break;
case 33: /* dpi-desync-fake-http */
case 36: /* dpi-desync-fake-http */
dp->fake_http_size = sizeof(dp->fake_http);
load_file_or_exit(optarg,dp->fake_http,&dp->fake_http_size);
break;
case 34: /* dpi-desync-fake-tls */
case 37: /* dpi-desync-fake-tls */
dp->fake_tls_size = sizeof(dp->fake_tls);
load_file_or_exit(optarg,dp->fake_tls,&dp->fake_tls_size);
break;
case 35: /* dpi-desync-fake-unknown */
case 38: /* dpi-desync-fake-unknown */
dp->fake_unknown_size = sizeof(dp->fake_unknown);
load_file_or_exit(optarg,dp->fake_unknown,&dp->fake_unknown_size);
break;
case 36: /* dpi-desync-fake-syndata */
case 39: /* dpi-desync-fake-syndata */
dp->fake_syndata_size = sizeof(dp->fake_syndata);
load_file_or_exit(optarg,dp->fake_syndata,&dp->fake_syndata_size);
break;
case 37: /* dpi-desync-fake-quic */
case 40: /* dpi-desync-fake-quic */
dp->fake_quic_size = sizeof(dp->fake_quic);
load_file_or_exit(optarg,dp->fake_quic,&dp->fake_quic_size);
break;
case 38: /* dpi-desync-fake-wireguard */
case 41: /* dpi-desync-fake-wireguard */
dp->fake_wg_size = sizeof(dp->fake_wg);
load_file_or_exit(optarg,dp->fake_wg,&dp->fake_wg_size);
break;
case 39: /* dpi-desync-fake-dht */
case 42: /* dpi-desync-fake-dht */
dp->fake_dht_size = sizeof(dp->fake_dht);
load_file_or_exit(optarg,dp->fake_dht,&dp->fake_dht_size);
break;
case 40: /* dpi-desync-fake-unknown-udp */
case 43: /* dpi-desync-fake-unknown-udp */
dp->fake_unknown_udp_size = sizeof(dp->fake_unknown_udp);
load_file_or_exit(optarg,dp->fake_unknown_udp,&dp->fake_unknown_udp_size);
break;
case 41: /* dpi-desync-udplen-increment */
case 44: /* dpi-desync-udplen-increment */
if (sscanf(optarg,"%d",&dp->udplen_increment)<1 || dp->udplen_increment>0x7FFF || dp->udplen_increment<-0x8000)
{
DLOG_ERR("dpi-desync-udplen-increment must be integer within -32768..32767 range\n");
exit_clean(1);
}
break;
case 42: /* dpi-desync-udplen-pattern */
case 45: /* dpi-desync-udplen-pattern */
{
char buf[sizeof(dp->udplen_pattern)];
size_t sz=sizeof(buf);
@@ -1703,35 +1800,64 @@ int main(int argc, char **argv)
fill_pattern(dp->udplen_pattern,sizeof(dp->udplen_pattern),buf,sz);
}
break;
case 43: /* desync-cutoff */
case 46: /* desync-cutoff */
if (!parse_cutoff(optarg, &dp->desync_cutoff, &dp->desync_cutoff_mode))
{
DLOG_ERR("invalid desync-cutoff value\n");
exit_clean(1);
}
break;
case 44: /* desync-start */
case 47: /* desync-start */
if (!parse_cutoff(optarg, &dp->desync_start, &dp->desync_start_mode))
{
DLOG_ERR("invalid desync-start value\n");
exit_clean(1);
}
break;
case 45: /* hostlist */
case 48: /* hostlist */
if (bSkip) break;
if (!RegisterHostlist(dp, false, optarg))
{
DLOG_ERR("failed to register hostlist '%s'\n", optarg);
exit_clean(1);
}
break;
case 46: /* hostlist-exclude */
case 49: /* hostlist-domains */
if (bSkip) break;
if (!anon_hl && !(anon_hl=RegisterHostlist(dp, false, NULL)))
{
DLOG_ERR("failed to register anonymous hostlist\n");
exit_clean(1);
}
if (!parse_domain_list(optarg, &anon_hl->hostlist))
{
DLOG_ERR("failed to add domains to anonymous hostlist\n");
exit_clean(1);
}
break;
case 50: /* hostlist-exclude */
if (bSkip) break;
if (!RegisterHostlist(dp, true, optarg))
{
DLOG_ERR("failed to register hostlist '%s'\n", optarg);
exit_clean(1);
}
break;
case 47: /* hostlist-auto */
case 51: /* hostlist-exclude-domains */
if (bSkip) break;
if (!anon_hl_exclude && !(anon_hl_exclude=RegisterHostlist(dp, true, NULL)))
{
DLOG_ERR("failed to register anonymous hostlist\n");
exit_clean(1);
}
if (!parse_domain_list(optarg, &anon_hl_exclude->hostlist))
{
DLOG_ERR("failed to add domains to anonymous hostlist\n");
exit_clean(1);
}
break;
case 52: /* hostlist-auto */
if (bSkip) break;
if (dp->hostlist_auto)
{
DLOG_ERR("only one auto hostlist per profile is supported\n");
@@ -1758,7 +1884,7 @@ int main(int argc, char **argv)
exit_clean(1);
}
break;
case 48: /* hostlist-auto-fail-threshold */
case 53: /* hostlist-auto-fail-threshold */
dp->hostlist_auto_fail_threshold = (uint8_t)atoi(optarg);
if (dp->hostlist_auto_fail_threshold<1 || dp->hostlist_auto_fail_threshold>20)
{
@@ -1766,7 +1892,7 @@ int main(int argc, char **argv)
exit_clean(1);
}
break;
case 49: /* hostlist-auto-fail-time */
case 54: /* hostlist-auto-fail-time */
dp->hostlist_auto_fail_time = (uint8_t)atoi(optarg);
if (dp->hostlist_auto_fail_time<1)
{
@@ -1774,7 +1900,7 @@ int main(int argc, char **argv)
exit_clean(1);
}
break;
case 50: /* hostlist-auto-retrans-threshold */
case 55: /* hostlist-auto-retrans-threshold */
dp->hostlist_auto_retrans_threshold = (uint8_t)atoi(optarg);
if (dp->hostlist_auto_retrans_threshold<2 || dp->hostlist_auto_retrans_threshold>10)
{
@@ -1782,7 +1908,7 @@ int main(int argc, char **argv)
exit_clean(1);
}
break;
case 51: /* hostlist-auto-debug */
case 56: /* hostlist-auto-debug */
{
FILE *F = fopen(optarg,"a+t");
if (!F)
@@ -1796,23 +1922,39 @@ int main(int argc, char **argv)
}
break;
case 52: /* new */
if (!(dpl = dp_list_add(&params.desync_profiles)))
case 57: /* new */
if (bSkip)
{
DLOG_ERR("desync_profile_add: out of memory\n");
exit_clean(1);
dp_clear(dp);
dp_init(dp);
dp->n = desync_profile_count;
bSkip = false;
}
dp = &dpl->dp;
dp->n = ++desync_profile_count;
else
{
if (!(dpl = dp_list_add(&params.desync_profiles)))
{
DLOG_ERR("desync_profile_add: out of memory\n");
exit_clean(1);
}
dp = &dpl->dp;
dp->n = ++desync_profile_count;
}
anon_hl = anon_hl_exclude = NULL;
anon_ips = anon_ips_exclude = NULL;
break;
case 53: /* filter-l3 */
case 58: /* skip */
bSkip = true;
break;
case 59: /* filter-l3 */
if (!wf_make_l3(optarg,&dp->filter_ipv4,&dp->filter_ipv6))
{
DLOG_ERR("bad value for --filter-l3\n");
exit_clean(1);
}
break;
case 54: /* filter-tcp */
case 60: /* filter-tcp */
if (!parse_pf_list(optarg,&dp->pf_tcp))
{
DLOG_ERR("Invalid port filter : %s\n",optarg);
@@ -1822,7 +1964,7 @@ int main(int argc, char **argv)
if (!port_filters_deny_if_empty(&dp->pf_udp))
exit_clean(1);
break;
case 55: /* filter-udp */
case 61: /* filter-udp */
if (!parse_pf_list(optarg,&dp->pf_udp))
{
DLOG_ERR("Invalid port filter : %s\n",optarg);
@@ -1832,53 +1974,80 @@ int main(int argc, char **argv)
if (!port_filters_deny_if_empty(&dp->pf_tcp))
exit_clean(1);
break;
case 56: /* filter-l7 */
case 62: /* filter-l7 */
if (!parse_l7_list(optarg,&dp->filter_l7))
{
DLOG_ERR("Invalid l7 filter : %s\n",optarg);
exit_clean(1);
}
break;
case 57: /* ipset */
case 63: /* ipset */
if (bSkip) break;
if (!RegisterIpset(dp, false, optarg))
{
DLOG_ERR("failed to register ipset '%s'\n", optarg);
exit_clean(1);
}
break;
case 58: /* ipset-exclude */
case 64: /* ipset-ip */
if (bSkip) break;
if (!anon_ips && !(anon_ips=RegisterIpset(dp, false, NULL)))
{
DLOG_ERR("failed to register anonymous ipset\n");
exit_clean(1);
}
if (!parse_ip_list(optarg, &anon_ips->ipset))
{
DLOG_ERR("failed to add subnets to anonymous ipset\n");
exit_clean(1);
}
break;
case 65: /* ipset-exclude */
if (bSkip) break;
if (!RegisterIpset(dp, true, optarg))
{
DLOG_ERR("failed to register ipset '%s'\n", optarg);
exit_clean(1);
}
break;
case 66: /* ipset-exclude-ip */
if (bSkip) break;
if (!anon_ips_exclude && !(anon_ips_exclude=RegisterIpset(dp, true, NULL)))
{
DLOG_ERR("failed to register anonymous ipset\n");
exit_clean(1);
}
if (!parse_ip_list(optarg, &anon_ips_exclude->ipset))
{
DLOG_ERR("failed to add subnets to anonymous ipset\n");
exit_clean(1);
}
break;
#ifdef __linux__
case 59: /* bind-fix4 */
case 67: /* bind-fix4 */
params.bind_fix4 = true;
break;
case 60: /* bind-fix6 */
case 68: /* bind-fix6 */
params.bind_fix6 = true;
break;
#elif defined(__CYGWIN__)
case 59: /* wf-iface */
case 67: /* wf-iface */
if (!sscanf(optarg,"%u.%u",&IfIdx,&SubIfIdx))
{
DLOG_ERR("bad value for --wf-iface\n");
exit_clean(1);
}
break;
case 60: /* wf-l3 */
case 68: /* wf-l3 */
if (!wf_make_l3(optarg,&wf_ipv4,&wf_ipv6))
{
DLOG_ERR("bad value for --wf-l3\n");
exit_clean(1);
}
break;
case 61: /* wf-tcp */
case 69: /* wf-tcp */
hash_wf_tcp=hash_jen(optarg,strlen(optarg));
if (!wf_make_pf(optarg,"tcp","SrcPort",wf_pf_tcp_src,sizeof(wf_pf_tcp_src)) ||
!wf_make_pf(optarg,"tcp","DstPort",wf_pf_tcp_dst,sizeof(wf_pf_tcp_dst)))
@@ -1887,7 +2056,7 @@ int main(int argc, char **argv)
exit_clean(1);
}
break;
case 62: /* wf-udp */
case 70: /* wf-udp */
hash_wf_udp=hash_jen(optarg,strlen(optarg));
if (!wf_make_pf(optarg,"udp","SrcPort",wf_pf_udp_src,sizeof(wf_pf_udp_src)) ||
!wf_make_pf(optarg,"udp","DstPort",wf_pf_udp_dst,sizeof(wf_pf_udp_dst)))
@@ -1896,7 +2065,7 @@ int main(int argc, char **argv)
exit_clean(1);
}
break;
case 63: /* wf-raw */
case 71: /* wf-raw */
hash_wf_raw=hash_jen(optarg,strlen(optarg));
if (optarg[0]=='@')
{
@@ -1910,11 +2079,11 @@ int main(int argc, char **argv)
windivert_filter[sizeof(windivert_filter) - 1] = '\0';
}
break;
case 64: /* wf-save */
case 72: /* wf-save */
strncpy(wf_save_file, optarg, sizeof(wf_save_file));
wf_save_file[sizeof(wf_save_file) - 1] = '\0';
break;
case 65: /* ssid-filter */
case 73: /* ssid-filter */
hash_ssid_filter=hash_jen(optarg,strlen(optarg));
{
char *e,*p = optarg;
@@ -1932,7 +2101,7 @@ int main(int argc, char **argv)
}
}
break;
case 66: /* nlm-filter */
case 74: /* nlm-filter */
hash_nlm_filter=hash_jen(optarg,strlen(optarg));
{
char *e,*p = optarg;
@@ -1950,7 +2119,7 @@ int main(int argc, char **argv)
}
}
break;
case 67: /* nlm-list */
case 75: /* nlm-list */
if (!nlm_list(optarg && !strcmp(optarg,"all")))
{
DLOG_ERR("could not get list of NLM networks\n");
@@ -1961,6 +2130,12 @@ int main(int argc, char **argv)
#endif
}
}
if (bSkip)
{
LIST_REMOVE(dpl,next);
dp_entry_destroy(dpl);
desync_profile_count--;
}
// do not need args from file anymore
#if !defined( __OpenBSD__) && !defined(__ANDROID__)
@@ -2076,6 +2251,12 @@ int main(int argc, char **argv)
SplitDebug();
DLOG("\n");
if (bDry)
{
DLOG_CONDUP("command line parameters verified\n");
exit_clean(0);
}
if (daemon) daemonize();
if (*pidfile && !writepid(pidfile))

View File

@@ -170,45 +170,49 @@ void hexdump_limited_dlog(const uint8_t *data, size_t size, size_t limit)
if (bcut) DLOG(" ...");
}
void dp_init(struct desync_profile *dp)
{
LIST_INIT(&dp->hl_collection);
LIST_INIT(&dp->hl_collection_exclude);
LIST_INIT(&dp->ips_collection);
LIST_INIT(&dp->ips_collection_exclude);
LIST_INIT(&dp->pf_tcp);
LIST_INIT(&dp->pf_udp);
memcpy(dp->hostspell, "host", 4); // default hostspell
dp->desync_skip_nosni = true;
dp->desync_ipfrag_pos_udp = IPFRAG_UDP_DEFAULT;
dp->desync_ipfrag_pos_tcp = IPFRAG_TCP_DEFAULT;
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_unknown_udp_size = 64;
dp->wscale=-1; // default - dont change scale factor (client)
dp->desync_ttl6 = 0xFF; // unused
dp->desync_badseq_increment = BADSEQ_INCREMENT_DEFAULT;
dp->desync_badseq_ack_increment = BADSEQ_ACK_INCREMENT_DEFAULT;
dp->wssize_cutoff_mode = dp->desync_start_mode = dp->desync_cutoff_mode = 'n'; // packet number by default
dp->udplen_increment = UDPLEN_INCREMENT_DEFAULT;
dp->hostlist_auto_fail_threshold = HOSTLIST_AUTO_FAIL_THRESHOLD_DEFAULT;
dp->hostlist_auto_fail_time = HOSTLIST_AUTO_FAIL_TIME_DEFAULT;
dp->hostlist_auto_retrans_threshold = HOSTLIST_AUTO_RETRANS_THRESHOLD_DEFAULT;
dp->filter_ipv4 = dp->filter_ipv6 = true;
}
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));
if (!entry) return NULL;
LIST_INIT(&entry->dp.hl_collection);
LIST_INIT(&entry->dp.hl_collection_exclude);
LIST_INIT(&entry->dp.ips_collection);
LIST_INIT(&entry->dp.ips_collection_exclude);
LIST_INIT(&entry->dp.pf_tcp);
LIST_INIT(&entry->dp.pf_udp);
memcpy(entry->dp.hostspell, "host", 4); // default hostspell
entry->dp.desync_skip_nosni = true;
entry->dp.desync_ipfrag_pos_udp = IPFRAG_UDP_DEFAULT;
entry->dp.desync_ipfrag_pos_tcp = IPFRAG_TCP_DEFAULT;
entry->dp.desync_repeats = 1;
entry->dp.fake_tls_size = sizeof(fake_tls_clienthello_default);
memcpy(entry->dp.fake_tls,fake_tls_clienthello_default,entry->dp.fake_tls_size);
randomize_default_tls_payload(entry->dp.fake_tls);
entry->dp.fake_http_size = strlen(fake_http_request_default);
memcpy(entry->dp.fake_http,fake_http_request_default,entry->dp.fake_http_size);
entry->dp.fake_quic_size = 620; // must be 601+ for TSPU hack
entry->dp.fake_quic[0] = 0x40; // russian TSPU QUIC short header fake
entry->dp.fake_wg_size = 64;
entry->dp.fake_dht_size = 64;
entry->dp.fake_unknown_size = 256;
entry->dp.fake_syndata_size = 16;
entry->dp.fake_unknown_udp_size = 64;
entry->dp.wscale=-1; // default - dont change scale factor (client)
entry->dp.desync_ttl6 = 0xFF; // unused
entry->dp.desync_badseq_increment = BADSEQ_INCREMENT_DEFAULT;
entry->dp.desync_badseq_ack_increment = BADSEQ_ACK_INCREMENT_DEFAULT;
entry->dp.wssize_cutoff_mode = entry->dp.desync_start_mode = entry->dp.desync_cutoff_mode = 'n'; // packet number by default
entry->dp.udplen_increment = UDPLEN_INCREMENT_DEFAULT;
entry->dp.hostlist_auto_fail_threshold = HOSTLIST_AUTO_FAIL_THRESHOLD_DEFAULT;
entry->dp.hostlist_auto_fail_time = HOSTLIST_AUTO_FAIL_TIME_DEFAULT;
entry->dp.hostlist_auto_retrans_threshold = HOSTLIST_AUTO_RETRANS_THRESHOLD_DEFAULT;
entry->dp.filter_ipv4 = entry->dp.filter_ipv6 = true;
dp_init(&entry->dp);
// add to the tail
struct desync_profile_list *dpn,*dpl=LIST_FIRST(&params.desync_profiles);
@@ -222,15 +226,24 @@ struct desync_profile_list *dp_list_add(struct desync_profile_list_head *head)
return entry;
}
static void dp_entry_destroy(struct desync_profile_list *entry)
static void dp_clear_dynamic(struct desync_profile *dp)
{
hostlist_collection_destroy(&entry->dp.hl_collection);
hostlist_collection_destroy(&entry->dp.hl_collection_exclude);
ipset_collection_destroy(&entry->dp.ips_collection);
ipset_collection_destroy(&entry->dp.ips_collection_exclude);
port_filters_destroy(&entry->dp.pf_tcp);
port_filters_destroy(&entry->dp.pf_udp);
HostFailPoolDestroy(&entry->dp.hostlist_auto_fail_counters);
hostlist_collection_destroy(&dp->hl_collection);
hostlist_collection_destroy(&dp->hl_collection_exclude);
ipset_collection_destroy(&dp->ips_collection);
ipset_collection_destroy(&dp->ips_collection_exclude);
port_filters_destroy(&dp->pf_tcp);
port_filters_destroy(&dp->pf_udp);
HostFailPoolDestroy(&dp->hostlist_auto_fail_counters);
}
void dp_clear(struct desync_profile *dp)
{
dp_clear_dynamic(dp);
memset(dp,0,sizeof(*dp));
}
void dp_entry_destroy(struct desync_profile_list *entry)
{
dp_clear_dynamic(&entry->dp);
free(entry);
}
void dp_list_destroy(struct desync_profile_list_head *head)

View File

@@ -51,7 +51,7 @@ struct desync_profile
char wssize_cutoff_mode; // n - packets, d - data packets, s - relative sequence
unsigned int wssize_cutoff;
bool hostcase, hostnospace, domcase;
bool hostcase, hostnospace, domcase, methodeol;
char hostspell[4];
enum dpi_desync_mode desync_mode0,desync_mode,desync_mode2;
bool desync_retrans,desync_skip_nosni,desync_any_proto;
@@ -68,7 +68,7 @@ struct desync_profile
autottl desync_autottl, desync_autottl6;
uint32_t desync_fooling_mode;
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];
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];
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;
int udplen_increment;
@@ -99,8 +99,11 @@ struct desync_profile_list {
};
LIST_HEAD(desync_profile_list_head, desync_profile_list);
struct desync_profile_list *dp_list_add(struct desync_profile_list_head *head);
void dp_entry_destroy(struct desync_profile_list *entry);
void dp_list_destroy(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_clear(struct desync_profile *dp);
struct params_s
{

View File

@@ -160,12 +160,17 @@ struct hostlist_file *hostlist_files_add(struct hostlist_files_head *head, const
struct hostlist_file *entry = malloc(sizeof(struct hostlist_file));
if (entry)
{
if (!(entry->filename = strdup(filename)))
if (filename)
{
free(entry);
return false;
if (!(entry->filename = strdup(filename)))
{
free(entry);
return false;
}
}
entry->mod_time=0;
else
entry->filename = NULL;
entry->mod_time = 0;
entry->hostlist = NULL;
LIST_INSERT_HEAD(head, entry, next);
}
@@ -192,7 +197,7 @@ struct hostlist_file *hostlist_files_search(struct hostlist_files_head *head, co
LIST_FOREACH(hfile, head, next)
{
if (!strcmp(hfile->filename,filename))
if (hfile->filename && !strcmp(hfile->filename,filename))
return hfile;
}
return NULL;
@@ -223,7 +228,7 @@ struct hostlist_item *hostlist_collection_search(struct hostlist_collection_head
LIST_FOREACH(item, head, next)
{
if (!strcmp(item->hfile->filename,filename))
if (item->hfile->filename && !strcmp(item->hfile->filename,filename))
return item;
}
return NULL;
@@ -369,12 +374,17 @@ struct ipset_file *ipset_files_add(struct ipset_files_head *head, const char *fi
struct ipset_file *entry = malloc(sizeof(struct ipset_file));
if (entry)
{
if (!(entry->filename = strdup(filename)))
if (filename)
{
free(entry);
return false;
if (!(entry->filename = strdup(filename)))
{
free(entry);
return false;
}
}
entry->mod_time=0;
else
entry->filename = NULL;
entry->mod_time = 0;
memset(&entry->ipset,0,sizeof(entry->ipset));
LIST_INSERT_HEAD(head, entry, next);
}
@@ -401,7 +411,7 @@ struct ipset_file *ipset_files_search(struct ipset_files_head *head, const char
LIST_FOREACH(hfile, head, next)
{
if (!strcmp(hfile->filename,filename))
if (hfile->filename && !strcmp(hfile->filename,filename))
return hfile;
}
return NULL;
@@ -432,7 +442,7 @@ struct ipset_item *ipset_collection_search(struct ipset_collection_head *head, c
LIST_FOREACH(item, head, next)
{
if (!strcmp(item->hfile->filename,filename))
if (item->hfile->filename && !strcmp(item->hfile->filename,filename))
return item;
}
return NULL;

View File

@@ -1,5 +1,5 @@
CC ?= cc
CFLAGS += -std=gnu99 -s -Os
CFLAGS += -std=gnu99 -s -Os -flto=auto
LIBS = -lz -lpthread
SRC_FILES = *.c

View File

@@ -1,5 +1,5 @@
CC ?= gcc
CFLAGS += -std=gnu99 -Os
CFLAGS += -std=gnu99 -Os -flto=auto
CFLAGS_BSD = -Wno-address-of-packed-member
LIBS = -lz -lpthread
LIBS_ANDROID = -lz

View File

@@ -24,7 +24,7 @@ static bool addpool(strpool **hostlist, char **s, const char *end, int *ct)
*hostlist = NULL;
return false;
}
(*ct)++;
if (ct) (*ct)++;
}
// advance to the next line
for (; p<end && (!*p || *p=='\r' || *p=='\n') ; p++);
@@ -32,6 +32,11 @@ static bool addpool(strpool **hostlist, char **s, const char *end, int *ct)
return true;
}
bool AppendHostlistItem(strpool **hostlist, char *s)
{
return addpool(hostlist,&s,s+strlen(s),NULL);
}
bool AppendHostList(strpool **hostlist, const char *filename)
{
char *p, *e, s[256], *zbuf;
@@ -98,21 +103,24 @@ bool AppendHostList(strpool **hostlist, const char *filename)
static bool LoadHostList(struct hostlist_file *hfile)
{
time_t t = file_mod_time(hfile->filename);
if (!t)
{
// stat() error
DLOG_ERR("cannot access hostlist file '%s'. in-memory content remains unchanged.\n",hfile->filename);
return true;
}
if (t==hfile->mod_time) return true; // up to date
StrPoolDestroy(&hfile->hostlist);
if (!AppendHostList(&hfile->hostlist, hfile->filename))
if (hfile->filename)
{
time_t t = file_mod_time(hfile->filename);
if (!t)
{
// stat() error
DLOG_ERR("cannot access hostlist file '%s'. in-memory content remains unchanged.\n",hfile->filename);
return true;
}
if (t==hfile->mod_time) return true; // up to date
StrPoolDestroy(&hfile->hostlist);
return false;
if (!AppendHostList(&hfile->hostlist, hfile->filename))
{
StrPoolDestroy(&hfile->hostlist);
return false;
}
hfile->mod_time=t;
}
hfile->mod_time=t;
return true;
}
static bool LoadHostLists(struct hostlist_files_head *list)
@@ -202,7 +210,7 @@ static bool HostlistCheck_(const struct hostlist_collection_head *hostlists, con
LIST_FOREACH(item, hostlists_exclude, next)
{
VPRINT("[%s] exclude ", item->hfile->filename);
VPRINT("[%s] exclude ", item->hfile->filename ? item->hfile->filename : "fixed");
if (SearchHostList(item->hfile->hostlist, host))
{
if (excluded) *excluded = true;
@@ -214,7 +222,7 @@ static bool HostlistCheck_(const struct hostlist_collection_head *hostlists, con
{
LIST_FOREACH(item, hostlists, next)
{
VPRINT("[%s] include ", item->hfile->filename);
VPRINT("[%s] include ", item->hfile->filename ? item->hfile->filename : "fixed");
if (SearchHostList(item->hfile->hostlist, host))
return true;
}
@@ -235,17 +243,29 @@ bool HostlistCheck(const struct desync_profile *dp, const char *host, bool *excl
static struct hostlist_file *RegisterHostlist_(struct hostlist_files_head *hostlists, struct hostlist_collection_head *hl_collection, const char *filename)
{
struct hostlist_file *hfile;
if (!(hfile=hostlist_files_search(hostlists, filename)))
if (!(hfile=hostlist_files_add(hostlists, filename)))
if (filename)
{
if (!(hfile=hostlist_files_search(hostlists, filename)))
if (!(hfile=hostlist_files_add(hostlists, filename)))
return NULL;
if (!hostlist_collection_search(hl_collection, filename))
if (!hostlist_collection_add(hl_collection, hfile))
return NULL;
}
else
{
if (!(hfile=hostlist_files_add(hostlists, NULL)))
return NULL;
if (!hostlist_collection_search(hl_collection, filename))
if (!hostlist_collection_add(hl_collection, hfile))
return NULL;
}
return hfile;
}
struct hostlist_file *RegisterHostlist(struct desync_profile *dp, bool bExclude, const char *filename)
{
if (!file_mod_time(filename))
if (filename && !file_mod_time(filename))
{
DLOG_ERR("cannot access hostlist file '%s'\n",filename);
return NULL;
@@ -265,15 +285,30 @@ void HostlistsDebug()
struct hostlist_item *hl_item;
LIST_FOREACH(hfile, &params.hostlists, next)
VPRINT("hostlist file %s%s\n",hfile->filename,hfile->hostlist ? "" : " (empty)");
{
if (hfile->filename)
VPRINT("hostlist file %s%s\n",hfile->filename,hfile->hostlist ? "" : " (empty)");
else
VPRINT("hostlist fixed%s\n",hfile->hostlist ? "" : " (empty)");
}
LIST_FOREACH(dpl, &params.desync_profiles, next)
{
LIST_FOREACH(hl_item, &dpl->dp.hl_collection, next)
if (hl_item->hfile!=dpl->dp.hostlist_auto)
VPRINT("profile %d include hostlist %s%s\n",dpl->dp.n, hl_item->hfile->filename,hl_item->hfile->hostlist ? "" : " (empty)");
{
if (hl_item->hfile->filename)
VPRINT("profile %d include hostlist %s%s\n",dpl->dp.n, hl_item->hfile->filename,hl_item->hfile->hostlist ? "" : " (empty)");
else
VPRINT("profile %d include fixed hostlist%s\n",dpl->dp.n, hl_item->hfile->hostlist ? "" : " (empty)");
}
LIST_FOREACH(hl_item, &dpl->dp.hl_collection_exclude, next)
VPRINT("profile %d exclude hostlist %s%s\n",dpl->dp.n,hl_item->hfile->filename,hl_item->hfile->hostlist ? "" : " (empty)");
{
if (hl_item->hfile->filename)
VPRINT("profile %d exclude hostlist %s%s\n",dpl->dp.n,hl_item->hfile->filename,hl_item->hfile->hostlist ? "" : " (empty)");
else
VPRINT("profile %d exclude fixed hostlist%s\n",dpl->dp.n,hl_item->hfile->hostlist ? "" : " (empty)");
}
if (dpl->dp.hostlist_auto)
VPRINT("profile %d auto hostlist %s%s\n",dpl->dp.n,dpl->dp.hostlist_auto->filename,dpl->dp.hostlist_auto->hostlist ? "" : " (empty)");
}

View File

@@ -4,6 +4,7 @@
#include "pools.h"
#include "params.h"
bool AppendHostlistItem(strpool **hostlist, char *s);
bool AppendHostList(strpool **hostlist, const char *filename);
bool LoadAllHostLists();
bool NonEmptyHostlist(strpool **hostlist);

View File

@@ -31,7 +31,7 @@ static bool addpool(ipset *ips, char **s, const char *end, int *ct)
ipsetDestroy(ips);
return false;
}
(*ct)++;
if (ct) (*ct)++;
}
else if (parse_cidr6(cidr,&c6))
{
@@ -40,7 +40,7 @@ static bool addpool(ipset *ips, char **s, const char *end, int *ct)
ipsetDestroy(ips);
return false;
}
(*ct)++;
if (ct) (*ct)++;
}
else
DLOG_ERR("bad ip or subnet : %s\n",cidr);
@@ -53,6 +53,11 @@ static bool addpool(ipset *ips, char **s, const char *end, int *ct)
}
bool AppendIpsetItem(ipset *ips, char *ip)
{
return addpool(ips,&ip,ip+strlen(ip),NULL);
}
static bool AppendIpset(ipset *ips, const char *filename)
{
char *p, *e, s[256], *zbuf;
@@ -119,21 +124,24 @@ static bool AppendIpset(ipset *ips, const char *filename)
static bool LoadIpset(struct ipset_file *hfile)
{
time_t t = file_mod_time(hfile->filename);
if (!t)
{
// stat() error
DLOG_ERR("cannot access ipset file '%s'. in-memory content remains unchanged.\n",hfile->filename);
return true;
}
if (t==hfile->mod_time) return true; // up to date
ipsetDestroy(&hfile->ipset);
if (!AppendIpset(&hfile->ipset, hfile->filename))
if (hfile->filename)
{
time_t t = file_mod_time(hfile->filename);
if (!t)
{
// stat() error
DLOG_ERR("cannot access ipset file '%s'. in-memory content remains unchanged.\n",hfile->filename);
return true;
}
if (t==hfile->mod_time) return true; // up to date
ipsetDestroy(&hfile->ipset);
return false;
if (!AppendIpset(&hfile->ipset, hfile->filename))
{
ipsetDestroy(&hfile->ipset);
return false;
}
hfile->mod_time=t;
}
hfile->mod_time=t;
return true;
}
static bool LoadIpsets(struct ipset_files_head *list)
@@ -205,7 +213,7 @@ static bool IpsetCheck_(const struct ipset_collection_head *ips, const struct ip
LIST_FOREACH(item, ips_exclude, next)
{
VPRINT("[%s] exclude ",item->hfile->filename);
VPRINT("[%s] exclude ",item->hfile->filename ? item->hfile->filename : "fixed");
if (SearchIpset(&item->hfile->ipset, ipv4, ipv6))
return false;
}
@@ -214,7 +222,7 @@ static bool IpsetCheck_(const struct ipset_collection_head *ips, const struct ip
{
LIST_FOREACH(item, ips, next)
{
VPRINT("[%s] include ",item->hfile->filename);
VPRINT("[%s] include ",item->hfile->filename ? item->hfile->filename : "fixed");
if (SearchIpset(&item->hfile->ipset, ipv4, ipv6))
return true;
}
@@ -234,17 +242,27 @@ bool IpsetCheck(const struct desync_profile *dp, const struct in_addr *ipv4, con
static struct ipset_file *RegisterIpset_(struct ipset_files_head *ipsets, struct ipset_collection_head *ips_collection, const char *filename)
{
struct ipset_file *hfile;
if (!(hfile=ipset_files_search(ipsets, filename)))
if (!(hfile=ipset_files_add(ipsets, filename)))
if (filename)
{
if (!(hfile=ipset_files_search(ipsets, filename)))
if (!(hfile=ipset_files_add(ipsets, filename)))
return NULL;
if (!ipset_collection_search(ips_collection, filename))
if (!ipset_collection_add(ips_collection, hfile))
return NULL;
}
else
{
if (!(hfile=ipset_files_add(ipsets, NULL)))
return NULL;
if (!ipset_collection_search(ips_collection, filename))
if (!ipset_collection_add(ips_collection, hfile))
return NULL;
}
return hfile;
}
struct ipset_file *RegisterIpset(struct desync_profile *dp, bool bExclude, const char *filename)
{
if (!file_mod_time(filename))
if (filename && !file_mod_time(filename))
{
DLOG_ERR("cannot access ipset file '%s'\n",filename);
return NULL;
@@ -277,13 +295,24 @@ void IpsetsDebug()
struct ipset_item *ips_item;
LIST_FOREACH(hfile, &params.ipsets, next)
VPRINT("ipset file %s (%s)\n",hfile->filename,dbg_ipset_fill(&hfile->ipset));
{
if (hfile->filename)
VPRINT("ipset file %s (%s)\n",hfile->filename,dbg_ipset_fill(&hfile->ipset));
else
VPRINT("ipset fixed (%s)\n",dbg_ipset_fill(&hfile->ipset));
}
LIST_FOREACH(dpl, &params.desync_profiles, next)
{
LIST_FOREACH(ips_item, &dpl->dp.ips_collection, next)
VPRINT("profile %d include ipset %s (%s)\n",dpl->dp.n,ips_item->hfile->filename,dbg_ipset_fill(&ips_item->hfile->ipset));
if (ips_item->hfile->filename)
VPRINT("profile %d include ipset %s (%s)\n",dpl->dp.n,ips_item->hfile->filename,dbg_ipset_fill(&ips_item->hfile->ipset));
else
VPRINT("profile %d include fixed ipset (%s)\n",dpl->dp.n,dbg_ipset_fill(&ips_item->hfile->ipset));
LIST_FOREACH(ips_item, &dpl->dp.ips_collection_exclude, next)
VPRINT("profile %d exclude ipset %s (%s)\n",dpl->dp.n,ips_item->hfile->filename,dbg_ipset_fill(&ips_item->hfile->ipset));
if (ips_item->hfile->filename)
VPRINT("profile %d exclude ipset %s (%s)\n",dpl->dp.n,ips_item->hfile->filename,dbg_ipset_fill(&ips_item->hfile->ipset));
else
VPRINT("profile %d exclude fixed ipset (%s)\n",dpl->dp.n,dbg_ipset_fill(&ips_item->hfile->ipset));
}
}

View File

@@ -9,3 +9,4 @@ bool LoadAllIpsets();
bool IpsetCheck(const struct desync_profile *dp, const struct in_addr *ipv4, const struct in6_addr *ipv6);
struct ipset_file *RegisterIpset(struct desync_profile *dp, bool bExclude, const char *filename);
void IpsetsDebug();
bool AppendIpsetItem(ipset *ips, char *ip);

View File

@@ -155,22 +155,26 @@ void hexdump_limited_dlog(const uint8_t *data, size_t size, size_t limit)
if (bcut) VPRINT(" ...");
}
void dp_init(struct desync_profile *dp)
{
LIST_INIT(&dp->hl_collection);
LIST_INIT(&dp->hl_collection_exclude);
LIST_INIT(&dp->ips_collection);
LIST_INIT(&dp->ips_collection_exclude);
LIST_INIT(&dp->pf_tcp);
dp->filter_ipv4 = dp->filter_ipv6 = true;
memcpy(dp->hostspell, "host", 4); // default hostspell
dp->hostlist_auto_fail_threshold = HOSTLIST_AUTO_FAIL_THRESHOLD_DEFAULT;
dp->hostlist_auto_fail_time = HOSTLIST_AUTO_FAIL_TIME_DEFAULT;
}
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));
if (!entry) return NULL;
LIST_INIT(&entry->dp.hl_collection);
LIST_INIT(&entry->dp.hl_collection_exclude);
LIST_INIT(&entry->dp.ips_collection);
LIST_INIT(&entry->dp.ips_collection_exclude);
LIST_INIT(&entry->dp.pf_tcp);
entry->dp.filter_ipv4 = entry->dp.filter_ipv6 = true;
memcpy(entry->dp.hostspell, "host", 4); // default hostspell
entry->dp.hostlist_auto_fail_threshold = HOSTLIST_AUTO_FAIL_THRESHOLD_DEFAULT;
entry->dp.hostlist_auto_fail_time = HOSTLIST_AUTO_FAIL_TIME_DEFAULT;
dp_init(&entry->dp);
// add to the tail
struct desync_profile_list *dpn,*dpl=LIST_FIRST(&params.desync_profiles);
@@ -184,14 +188,23 @@ struct desync_profile_list *dp_list_add(struct desync_profile_list_head *head)
return entry;
}
static void dp_entry_destroy(struct desync_profile_list *entry)
static void dp_clear_dynamic(struct desync_profile *dp)
{
hostlist_collection_destroy(&entry->dp.hl_collection);
hostlist_collection_destroy(&entry->dp.hl_collection_exclude);
ipset_collection_destroy(&entry->dp.ips_collection);
ipset_collection_destroy(&entry->dp.ips_collection_exclude);
port_filters_destroy(&entry->dp.pf_tcp);
HostFailPoolDestroy(&entry->dp.hostlist_auto_fail_counters);
hostlist_collection_destroy(&dp->hl_collection);
hostlist_collection_destroy(&dp->hl_collection_exclude);
ipset_collection_destroy(&dp->ips_collection);
ipset_collection_destroy(&dp->ips_collection_exclude);
port_filters_destroy(&dp->pf_tcp);
HostFailPoolDestroy(&dp->hostlist_auto_fail_counters);
}
void dp_clear(struct desync_profile *dp)
{
dp_clear_dynamic(dp);
memset(dp,0,sizeof(*dp));
}
void dp_entry_destroy(struct desync_profile_list *entry)
{
dp_clear_dynamic(&entry->dp);
free(entry);
}
void dp_list_destroy(struct desync_profile_list_head *head)

View File

@@ -83,7 +83,10 @@ struct desync_profile_list {
};
LIST_HEAD(desync_profile_list_head, desync_profile_list);
struct desync_profile_list *dp_list_add(struct desync_profile_list_head *head);
void dp_entry_destroy(struct desync_profile_list *entry);
void dp_list_destroy(struct desync_profile_list_head *head);
void dp_init(struct desync_profile *dp);
void dp_clear(struct desync_profile *dp);
struct params_s
{

View File

@@ -154,18 +154,22 @@ 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 *entry = malloc(sizeof(struct hostlist_file));
if (entry)
{
if (!(entry->filename = strdup(filename)))
if (filename)
{
free(entry);
return false;
if (!(entry->filename = strdup(filename)))
{
free(entry);
return false;
}
}
entry->mod_time=0;
else
entry->filename = NULL;
entry->mod_time = 0;
entry->hostlist = NULL;
LIST_INSERT_HEAD(head, entry, next);
}
@@ -192,7 +196,7 @@ struct hostlist_file *hostlist_files_search(struct hostlist_files_head *head, co
LIST_FOREACH(hfile, head, next)
{
if (!strcmp(hfile->filename,filename))
if (hfile->filename && !strcmp(hfile->filename,filename))
return hfile;
}
return NULL;
@@ -223,7 +227,7 @@ struct hostlist_item *hostlist_collection_search(struct hostlist_collection_head
LIST_FOREACH(item, head, next)
{
if (!strcmp(item->hfile->filename,filename))
if (item->hfile->filename && !strcmp(item->hfile->filename,filename))
return item;
}
return NULL;
@@ -369,12 +373,17 @@ struct ipset_file *ipset_files_add(struct ipset_files_head *head, const char *fi
struct ipset_file *entry = malloc(sizeof(struct ipset_file));
if (entry)
{
if (!(entry->filename = strdup(filename)))
if (filename)
{
free(entry);
return false;
if (!(entry->filename = strdup(filename)))
{
free(entry);
return false;
}
}
entry->mod_time=0;
else
entry->filename = NULL;
entry->mod_time = 0;
memset(&entry->ipset,0,sizeof(entry->ipset));
LIST_INSERT_HEAD(head, entry, next);
}
@@ -401,7 +410,7 @@ struct ipset_file *ipset_files_search(struct ipset_files_head *head, const char
LIST_FOREACH(hfile, head, next)
{
if (!strcmp(hfile->filename,filename))
if (hfile->filename && !strcmp(hfile->filename,filename))
return hfile;
}
return NULL;
@@ -432,7 +441,7 @@ struct ipset_item *ipset_collection_search(struct ipset_collection_head *head, c
LIST_FOREACH(item, head, next)
{
if (!strcmp(item->hfile->filename,filename))
if (item->hfile->filename && !strcmp(item->hfile->filename,filename))
return item;
}
return NULL;

View File

@@ -140,11 +140,6 @@ void tamper_out(t_ctrack *ctrack, const struct sockaddr *dest, uint8_t *segment,
if (bHaveHost)
VPRINT("request hostname: %s\n", Host);
if (ctrack->b_not_act)
{
VPRINT("Not acting on this request\n");
return;
}
bool bDiscoveredL7 = ctrack->l7proto==UNKNOWN && l7proto!=UNKNOWN;
if (bDiscoveredL7)
@@ -169,17 +164,25 @@ void tamper_out(t_ctrack *ctrack, const struct sockaddr *dest, uint8_t *segment,
struct desync_profile *dp_prev = ctrack->dp;
apply_desync_profile(ctrack, dest);
if (ctrack->dp!=dp_prev)
{
VPRINT("desync profile changed by revealed l7 protocol or hostname !\n");
ctrack->b_host_checked = ctrack->b_ah_check = false;
}
}
if (bDiscoveredHostname && ctrack->dp->hostlist_auto)
if (l7proto!=UNKNOWN && ctrack->dp->hostlist_auto)
{
bool bHostExcluded;
if (!HostlistCheck(ctrack->dp, Host, &bHostExcluded, false))
if (bHaveHost && !ctrack->b_host_checked)
{
bool bHostExcluded;
ctrack->b_host_matches = HostlistCheck(ctrack->dp, Host, &bHostExcluded, false);
ctrack->b_host_checked = true;
if (!ctrack->b_host_matches)
ctrack->b_ah_check = !bHostExcluded;
}
if (!ctrack->b_host_matches)
{
ctrack->b_ah_check = !bHostExcluded;
VPRINT("Not acting on this request\n");
ctrack->b_not_act = true;
return;
}
}

View File

@@ -14,8 +14,7 @@ typedef struct
// common state
t_l7proto l7proto;
bool bTamperInCutoff;
bool b_ah_check;
bool b_not_act;
bool b_host_checked,b_host_matches,b_ah_check;
char *hostname;
struct desync_profile *dp; // desync profile cache
} t_ctrack;

View File

@@ -175,16 +175,22 @@ static void exithelp(void)
#endif
" --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"
" --dry-run\t\t\t\t; verify parameters and exit with code 0 if successful\n"
"\nMULTI-STRATEGY:\n"
" --new\t\t\t\t\t; begin new strategy\n"
" --skip\t\t\t\t\t; do not use this strategy\n"
" --filter-l3=ipv4|ipv6\t\t\t; L3 protocol filter. multiple comma separated values allowed.\n"
" --filter-tcp=[~]port1[-port2]|*\t; TCP port filter. ~ means negation. multiple comma separated values allowed.\n"
" --filter-l7=[http|tls|unknown]\t\t; L6-L7 protocol filter. multiple comma separated values allowed.\n"
" --ipset=<filename>\t\t\t; ipset include filter (one ip/CIDR per line, ipv4 and ipv6 accepted, gzip supported, multiple ipsets allowed)\n"
" --ipset-ip=<ip_list>\t\t\t; comma separated fixed subnet list\n"
" --ipset-exclude=<filename>\t\t; ipset exclude filter (one ip/CIDR per line, ipv4 and ipv6 accepted, gzip supported, multiple ipsets allowed)\n"
" --ipset-exclude-ip=<ip_list>\t\t; comma separated fixed subnet list\n"
"\nHOSTLIST FILTER:\n"
" --hostlist=<filename>\t\t\t; only act on hosts in the list (one host per line, subdomains auto apply, gzip supported, multiple hostlists allowed)\n"
" --hostlist-domains=<domain_list>\t; comma separated fixed domain list\n"
" --hostlist-exclude=<filename>\t\t; do not act on hosts in the list (one host per line, subdomains auto apply, gzip supported, multiple hostlists allowed)\n"
" --hostlist-exclude-domains=<domain_list> ; comma separated fixed domain list\n"
" --hostlist-auto=<filename>\t\t; detect DPI blocks and build hostlist automatically\n"
" --hostlist-auto-fail-threshold=<int>\t; how many failed attempts cause hostname to be added to auto hostlist (default : %d)\n"
" --hostlist-auto-fail-time=<int>\t; all failed attemps must be within these seconds (default : %d)\n"
@@ -483,6 +489,46 @@ static bool parse_pf_list(char *opt, struct port_filters_head *pfl)
return true;
}
static bool parse_domain_list(char *opt, strpool **pp)
{
char *e,*p,c;
for (p=opt ; p ; )
{
if ((e = strchr(p,',')))
{
c=*e;
*e=0;
}
if (*p && !AppendHostlistItem(pp,p)) return false;
if (e) *e++=c;
p = e;
}
return true;
}
static bool parse_ip_list(char *opt, ipset *pp)
{
char *e,*p,c;
for (p=opt ; p ; )
{
if ((e = strchr(p,',')))
{
c=*e;
*e=0;
}
if (*p && !AppendIpsetItem(pp,p)) return false;
if (e) *e++=c;
p = e;
}
return true;
}
#if !defined( __OpenBSD__) && !defined(__ANDROID__)
// no static to not allow optimizer to inline this func (save stack)
void config_from_file(const char *filename)
@@ -524,6 +570,9 @@ void parse_params(int argc, char *argv[])
{
int option_index = 0;
int v, i;
bool bSkip=false, bDry=false;
struct hostlist_file *anon_hl = NULL, *anon_hl_exclude = NULL;
struct ipset_file *anon_ips = NULL, *anon_ips_exclude = NULL;
memset(&params, 0, sizeof(params));
params.maxconn = DEFAULT_MAX_CONN;
@@ -609,45 +658,51 @@ void parse_params(int argc, char *argv[])
{ "tlsrec",required_argument,0,0 },// optidx=34
{ "tlsrec-pos",required_argument,0,0 },// optidx=35
{ "hostlist",required_argument,0,0 },// optidx=36
{ "hostlist-exclude",required_argument,0,0 },// optidx=37
{ "hostlist-auto",required_argument,0,0}, // optidx=38
{ "hostlist-auto-fail-threshold",required_argument,0,0}, // optidx=39
{ "hostlist-auto-fail-time",required_argument,0,0}, // optidx=40
{ "hostlist-auto-debug",required_argument,0,0}, // optidx=41
{ "pidfile",required_argument,0,0 },// optidx=42
{ "debug",optional_argument,0,0 },// optidx=43
{ "debug-level",required_argument,0,0 },// optidx=44
{ "local-rcvbuf",required_argument,0,0 },// optidx=45
{ "local-sndbuf",required_argument,0,0 },// optidx=46
{ "remote-rcvbuf",required_argument,0,0 },// optidx=47
{ "remote-sndbuf",required_argument,0,0 },// optidx=48
{ "socks",no_argument,0,0 },// optidx=40
{ "no-resolve",no_argument,0,0 },// optidx=50
{ "resolver-threads",required_argument,0,0 },// optidx=51
{ "skip-nodelay",no_argument,0,0 },// optidx=52
{ "tamper-start",required_argument,0,0 },// optidx=53
{ "tamper-cutoff",required_argument,0,0 },// optidx=54
{ "connect-bind-addr",required_argument,0,0 },// optidx=55
{ "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
{ "local-rcvbuf",required_argument,0,0 },// optidx=48
{ "local-sndbuf",required_argument,0,0 },// optidx=49
{ "remote-rcvbuf",required_argument,0,0 },// optidx=50
{ "remote-sndbuf",required_argument,0,0 },// optidx=51
{ "socks",no_argument,0,0 },// optidx=52
{ "no-resolve",no_argument,0,0 },// optidx=53
{ "resolver-threads",required_argument,0,0 },// optidx=54
{ "skip-nodelay",no_argument,0,0 },// optidx=55
{ "tamper-start",required_argument,0,0 },// optidx=56
{ "tamper-cutoff",required_argument,0,0 },// optidx=57
{ "connect-bind-addr",required_argument,0,0 },// optidx=58
{ "new",no_argument,0,0 }, // optidx=56
{ "filter-l3",required_argument,0,0 }, // optidx=57
{ "filter-tcp",required_argument,0,0 }, // optidx=58
{ "filter-l7",required_argument,0,0 }, // optidx=59
{ "ipset",required_argument,0,0 }, // optidx=60
{ "ipset-exclude",required_argument,0,0 }, // optidx=61
{ "new",no_argument,0,0 }, // optidx=59
{ "skip",no_argument,0,0 }, // optidx=60
{ "filter-l3",required_argument,0,0 }, // optidx=61
{ "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=62
{ "enable-pf",no_argument,0,0 },// optidx=68
#elif defined(__APPLE__)
{ "local-tcp-user-timeout",required_argument,0,0 }, // optidx=62
{ "remote-tcp-user-timeout",required_argument,0,0 }, // optidx=63
{ "local-tcp-user-timeout",required_argument,0,0 }, // optidx=68
{ "remote-tcp-user-timeout",required_argument,0,0 }, // optidx=69
#elif defined(__linux__)
{ "local-tcp-user-timeout",required_argument,0,0 }, // optidx=62
{ "remote-tcp-user-timeout",required_argument,0,0 }, // optidx=63
{ "mss",required_argument,0,0 }, // optidx=64
{ "fix-seg",optional_argument,0,0 }, // optidx=65
{ "local-tcp-user-timeout",required_argument,0,0 }, // optidx=68
{ "remote-tcp-user-timeout",required_argument,0,0 }, // optidx=69
{ "mss",required_argument,0,0 }, // optidx=70
{ "fix-seg",optional_argument,0,0 }, // optidx=71
#ifdef SPLICE_PRESENT
{ "nosplice",no_argument,0,0 }, // optidx=66
{ "nosplice",no_argument,0,0 }, // optidx=72
#endif
#endif
{ "hostlist-auto-retrans-threshold",optional_argument,0,0}, // ignored. for nfqws command line compatibility
@@ -655,7 +710,11 @@ void parse_params(int argc, char *argv[])
};
while ((v = getopt_long_only(argc, argv, "", long_options, &option_index)) != -1)
{
if (v) exithelp_clean();
if (v)
if (bDry)
exit_clean(1);
else
exithelp_clean();
switch (option_index)
{
case 0:
@@ -945,6 +1004,7 @@ void parse_params(int argc, char *argv[])
params.tamper = true;
break;
case 36: /* hostlist */
if (bSkip) break;
if (!RegisterHostlist(dp, false, optarg))
{
DLOG_ERR("failed to register hostlist '%s'\n", optarg);
@@ -952,7 +1012,22 @@ void parse_params(int argc, char *argv[])
}
params.tamper = true;
break;
case 37: /* hostlist-exclude */
case 37: /* hostlist-domains */
if (bSkip) break;
if (!anon_hl && !(anon_hl=RegisterHostlist(dp, false, NULL)))
{
DLOG_ERR("failed to register anonymous hostlist\n");
exit_clean(1);
}
if (!parse_domain_list(optarg, &anon_hl->hostlist))
{
DLOG_ERR("failed to add domains to anonymous hostlist\n");
exit_clean(1);
}
params.tamper = true;
break;
case 38: /* hostlist-exclude */
if (bSkip) break;
if (!RegisterHostlist(dp, true, optarg))
{
DLOG_ERR("failed to register hostlist '%s'\n", optarg);
@@ -960,7 +1035,22 @@ void parse_params(int argc, char *argv[])
}
params.tamper = true;
break;
case 38: /* hostlist-auto */
case 39: /* hostlist-exclude-domains */
if (bSkip) break;
if (!anon_hl_exclude && !(anon_hl_exclude=RegisterHostlist(dp, true, NULL)))
{
DLOG_ERR("failed to register anonymous hostlist\n");
exit_clean(1);
}
if (!parse_domain_list(optarg, &anon_hl_exclude->hostlist))
{
DLOG_ERR("failed to add domains to anonymous hostlist\n");
exit_clean(1);
}
params.tamper = true;
break;
case 40: /* hostlist-auto */
if (bSkip) break;
if (dp->hostlist_auto)
{
DLOG_ERR("only one auto hostlist per profile is supported\n");
@@ -988,7 +1078,7 @@ void parse_params(int argc, char *argv[])
}
params.tamper = true; // need to detect blocks and update autohostlist. cannot just slice.
break;
case 39: /* hostlist-auto-fail-threshold */
case 41: /* hostlist-auto-fail-threshold */
dp->hostlist_auto_fail_threshold = (uint8_t)atoi(optarg);
if (dp->hostlist_auto_fail_threshold<1 || dp->hostlist_auto_fail_threshold>20)
{
@@ -996,7 +1086,7 @@ void parse_params(int argc, char *argv[])
exit_clean(1);
}
break;
case 40: /* hostlist-auto-fail-time */
case 42: /* hostlist-auto-fail-time */
dp->hostlist_auto_fail_time = (uint8_t)atoi(optarg);
if (dp->hostlist_auto_fail_time<1)
{
@@ -1004,7 +1094,7 @@ void parse_params(int argc, char *argv[])
exit_clean(1);
}
break;
case 41: /* hostlist-auto-debug */
case 43: /* hostlist-auto-debug */
{
FILE *F = fopen(optarg,"a+t");
if (!F)
@@ -1017,11 +1107,11 @@ void parse_params(int argc, char *argv[])
params.hostlist_auto_debuglog[sizeof(params.hostlist_auto_debuglog) - 1] = '\0';
}
break;
case 42: /* pidfile */
case 44: /* pidfile */
strncpy(params.pidfile,optarg,sizeof(params.pidfile));
params.pidfile[sizeof(params.pidfile)-1]='\0';
break;
case 43: /* debug */
case 45: /* debug */
if (optarg)
{
if (*optarg=='@')
@@ -1055,44 +1145,47 @@ void parse_params(int argc, char *argv[])
params.debug_target = LOG_TARGET_CONSOLE;
}
break;
case 44: /* debug-level */
case 46: /* debug-level */
params.debug = atoi(optarg);
break;
case 45: /* local-rcvbuf */
case 47: /* dry-run */
bDry = true;
break;
case 48: /* local-rcvbuf */
#ifdef __linux__
params.local_rcvbuf = atoi(optarg)/2;
#else
params.local_rcvbuf = atoi(optarg);
#endif
break;
case 46: /* local-sndbuf */
case 49: /* local-sndbuf */
#ifdef __linux__
params.local_sndbuf = atoi(optarg)/2;
#else
params.local_sndbuf = atoi(optarg);
#endif
break;
case 47: /* remote-rcvbuf */
case 50: /* remote-rcvbuf */
#ifdef __linux__
params.remote_rcvbuf = atoi(optarg)/2;
#else
params.remote_rcvbuf = atoi(optarg);
#endif
break;
case 48: /* remote-sndbuf */
case 51: /* remote-sndbuf */
#ifdef __linux__
params.remote_sndbuf = atoi(optarg)/2;
#else
params.remote_sndbuf = atoi(optarg);
#endif
break;
case 49: /* socks */
case 52: /* socks */
params.proxy_type = CONN_TYPE_SOCKS;
break;
case 50: /* no-resolve */
case 53: /* no-resolve */
params.no_resolve = true;
break;
case 51: /* resolver-threads */
case 54: /* resolver-threads */
params.resolver_threads = atoi(optarg);
if (params.resolver_threads<1 || params.resolver_threads>300)
{
@@ -1100,10 +1193,10 @@ void parse_params(int argc, char *argv[])
exit_clean(1);
}
break;
case 52: /* skip-nodelay */
case 55: /* skip-nodelay */
params.skip_nodelay = true;
break;
case 53: /* tamper-start */
case 56: /* tamper-start */
{
const char *p=optarg;
if (*p=='n')
@@ -1117,7 +1210,7 @@ void parse_params(int argc, char *argv[])
}
params.tamper_lim = true;
break;
case 54: /* tamper-cutoff */
case 57: /* tamper-cutoff */
{
const char *p=optarg;
if (*p=='n')
@@ -1131,7 +1224,7 @@ void parse_params(int argc, char *argv[])
}
params.tamper_lim = true;
break;
case 55: /* connect-bind-addr */
case 58: /* connect-bind-addr */
{
char *p = strchr(optarg,'%');
if (p) *p++=0;
@@ -1159,37 +1252,53 @@ void parse_params(int argc, char *argv[])
break;
case 56: /* new */
if (!(dpl = dp_list_add(&params.desync_profiles)))
case 59: /* new */
if (bSkip)
{
DLOG_ERR("desync_profile_add: out of memory\n");
exit_clean(1);
dp_clear(dp);
dp_init(dp);
dp->n = desync_profile_count;
bSkip = false;
}
dp = &dpl->dp;
dp->n = ++desync_profile_count;
else
{
if (!(dpl = dp_list_add(&params.desync_profiles)))
{
DLOG_ERR("desync_profile_add: out of memory\n");
exit_clean(1);
}
dp = &dpl->dp;
dp->n = ++desync_profile_count;
}
anon_hl = anon_hl_exclude = NULL;
anon_ips = anon_ips_exclude = NULL;
break;
case 57: /* filter-l3 */
case 60: /* skip */
bSkip = true;
break;
case 61: /* filter-l3 */
if (!wf_make_l3(optarg,&dp->filter_ipv4,&dp->filter_ipv6))
{
DLOG_ERR("bad value for --filter-l3\n");
exit_clean(1);
}
break;
case 58: /* filter-tcp */
case 62: /* filter-tcp */
if (!parse_pf_list(optarg,&dp->pf_tcp))
{
DLOG_ERR("Invalid port filter : %s\n",optarg);
exit_clean(1);
}
break;
case 59: /* filter-l7 */
case 63: /* filter-l7 */
if (!parse_l7_list(optarg,&dp->filter_l7))
{
DLOG_ERR("Invalid l7 filter : %s\n",optarg);
exit_clean(1);
}
break;
case 60: /* ipset */
case 64: /* ipset */
if (bSkip) break;
if (!RegisterIpset(dp, false, optarg))
{
DLOG_ERR("failed to register ipset '%s'\n", optarg);
@@ -1197,7 +1306,22 @@ void parse_params(int argc, char *argv[])
}
params.tamper = true;
break;
case 61: /* ipset-exclude */
case 65: /* ipset-ip */
if (bSkip) break;
if (!anon_ips && !(anon_ips=RegisterIpset(dp, false, NULL)))
{
DLOG_ERR("failed to register anonymous ipset\n");
exit_clean(1);
}
if (!parse_ip_list(optarg, &anon_ips->ipset))
{
DLOG_ERR("failed to add subnets to anonymous ipset\n");
exit_clean(1);
}
params.tamper = true;
break;
case 66: /* ipset-exclude */
if (bSkip) break;
if (!RegisterIpset(dp, true, optarg))
{
DLOG_ERR("failed to register ipset '%s'\n", optarg);
@@ -1205,13 +1329,27 @@ void parse_params(int argc, char *argv[])
}
params.tamper = true;
break;
case 67: /* ipset-exclude-ip */
if (bSkip) break;
if (!anon_ips_exclude && !(anon_ips_exclude=RegisterIpset(dp, true, NULL)))
{
DLOG_ERR("failed to register anonymous ipset\n");
exit_clean(1);
}
if (!parse_ip_list(optarg, &anon_ips_exclude->ipset))
{
DLOG_ERR("failed to add subnets to anonymous ipset\n");
exit_clean(1);
}
params.tamper = true;
break;
#if defined(__FreeBSD__)
case 62: /* enable-pf */
case 68: /* enable-pf */
params.pf_enable = true;
break;
#elif defined(__linux__) || defined(__APPLE__)
case 62: /* local-tcp-user-timeout */
case 68: /* local-tcp-user-timeout */
params.tcp_user_timeout_local = atoi(optarg);
if (params.tcp_user_timeout_local<0 || params.tcp_user_timeout_local>86400)
{
@@ -1219,7 +1357,7 @@ void parse_params(int argc, char *argv[])
exit_clean(1);
}
break;
case 63: /* remote-tcp-user-timeout */
case 69: /* remote-tcp-user-timeout */
params.tcp_user_timeout_remote = atoi(optarg);
if (params.tcp_user_timeout_remote<0 || params.tcp_user_timeout_remote>86400)
{
@@ -1230,7 +1368,7 @@ void parse_params(int argc, char *argv[])
#endif
#if defined(__linux__)
case 64: /* mss */
case 70: /* mss */
// this option does not work in any BSD and MacOS. OS may accept but it changes nothing
dp->mss = atoi(optarg);
if (dp->mss<88 || dp->mss>32767)
@@ -1239,7 +1377,7 @@ void parse_params(int argc, char *argv[])
exit_clean(1);
}
break;
case 65: /* fix-seg */
case 71: /* fix-seg */
if (!params.fix_seg_avail)
{
DLOG_ERR("--fix-seg is supported since kernel 4.6\n");
@@ -1259,13 +1397,20 @@ void parse_params(int argc, char *argv[])
params.fix_seg = FIX_SEG_DEFAULT_MAX_WAIT;
break;
#ifdef SPLICE_PRESENT
case 66: /* nosplice */
case 72: /* nosplice */
params.nosplice = true;
break;
#endif
#endif
}
}
if (bSkip)
{
LIST_REMOVE(dpl,next);
dp_entry_destroy(dpl);
desync_profile_count--;
}
if (!params.bind_wait_only && !params.port)
{
DLOG_ERR("Need port number\n");
@@ -1327,6 +1472,11 @@ void parse_params(int argc, char *argv[])
// do not need args from file anymore
cleanup_args();
#endif
if (bDry)
{
DLOG_CONDUP("command line parameters verified\n");
exit_clean(0);
}
}
@@ -1476,6 +1626,15 @@ struct salisten_s
int bind_wait_ip_left; // how much seconds left from bind_wait_ip
};
static const char *bindll_s[] = { "unwanted","no","prefer","force" };
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
#if defined(ZAPRET_GH_VER) || defined (ZAPRET_GH_HASH)
#define PRINT_VER printf("github version %s (%s)\n\n", TOSTRING(ZAPRET_GH_VER), TOSTRING(ZAPRET_GH_HASH))
#else
#define PRINT_VER printf("self-built version %s %s\n\n", __DATE__, __TIME__)
#endif
int main(int argc, char *argv[])
{
int i, listen_fd[MAX_BINDS], yes = 1, retval = 0, if_index, exit_v=EXIT_FAILURE;
@@ -1486,6 +1645,8 @@ int main(int argc, char *argv[])
srand(time(NULL));
mask_from_preflen6_prepare();
PRINT_VER;
parse_params(argc, argv);
argv=NULL; argc=0;

View File

@@ -479,6 +479,33 @@ static int connect_remote(const struct sockaddr *remote_addr, int mss)
return remote_fd;
}
static bool connect_remote_conn(tproxy_conn_t *conn)
{
int mss=0;
apply_desync_profile(&conn->track, (struct sockaddr *)&conn->dest);
if (conn->track.dp && conn->track.dp->mss)
{
mss = conn->track.dp->mss;
if (conn->track.dp->hostlist_auto)
{
if (conn->track.hostname)
{
bool bHostExcluded;
conn->track.b_host_matches = HostlistCheck(conn->track.dp, conn->track.hostname, &bHostExcluded, false);
conn->track.b_host_checked = true;
if (!conn->track.b_host_matches)
{
conn->track.b_ah_check = !bHostExcluded;
mss = 0;
}
}
}
}
return (conn->partner->fd = connect_remote((struct sockaddr *)&conn->dest, mss))>=0;
}
//Free resources occupied by this connection
static void free_conn(tproxy_conn_t *conn)
@@ -636,9 +663,7 @@ static tproxy_conn_t* add_tcp_connection(int efd, struct tailhead *conn_list,int
conn->partner->client = conn->client;
conn->partner->dest = conn->dest;
apply_desync_profile(&conn->track, (struct sockaddr *)&conn->dest);
if ((conn->partner->fd = connect_remote((struct sockaddr *)&orig_dst, conn->track.dp ? conn->track.dp->mss : 0)) < 0)
if (!connect_remote_conn(conn))
{
DLOG_ERR("Failed to connect\n");
free_conn(conn->partner);
@@ -811,14 +836,6 @@ static bool proxy_mode_connect_remote(tproxy_conn_t *conn, struct tailhead *conn
return false;
}
apply_desync_profile(&conn->track, (struct sockaddr *)&conn->dest);
if ((remote_fd = connect_remote((struct sockaddr *)&conn->dest, conn->track.dp ? conn->track.dp->mss : 0)) < 0)
{
DLOG_ERR("socks failed to connect (1) errno=%d\n", errno);
socks_send_rep_errno(conn->socks_ver, conn->fd, errno);
return false;
}
if (!(conn->partner = new_conn(remote_fd, true)))
{
close(remote_fd);
@@ -830,6 +847,15 @@ static bool proxy_mode_connect_remote(tproxy_conn_t *conn, struct tailhead *conn
conn->partner->efd = conn->efd;
conn->partner->client = conn->client;
conn->partner->dest = conn->dest;
if (!connect_remote_conn(conn))
{
free_conn(conn->partner); conn->partner = NULL;
DLOG_ERR("socks failed to connect (1) errno=%d\n", errno);
socks_send_rep_errno(conn->socks_ver, conn->fd, errno);
return false;
}
if (!epoll_set(conn->partner, EPOLLOUT))
{
DLOG_ERR("socks epoll_set error %d\n", errno);
@@ -1652,7 +1678,6 @@ int event_loop(const int *listen_fd, size_t listen_fd_ct)
}
else
{
DBGPRINT("conn fd=%d has no unsent\n", conn->fd);
conn->bFlowIn = false;
epoll_update_flow(conn);