129 Commits

Author SHA1 Message Date
bol-van
56456c1e0c nfqws,tpws: fix possible crashes or high memory usage if hostlist has duplicate hostnames 2025-08-08 11:35:13 +03:00
bol-van
d6a8d1dc33 lame issue warning in english 2025-08-06 08:25:23 +03:00
bol-van
04b3b6abcb update issue warning 2025-08-04 10:59:41 +03:00
bol-van
fd58ecf8a5 update issue warning 2025-08-04 10:58:41 +03:00
bol-van
a560e251a1 update changes.txt 2025-08-01 13:28:19 +03:00
bol-van
2ff0f9c0ff tpws: minor update 2025-08-01 13:23:05 +03:00
bol-van
4dbd673eaa update changes.txt 2025-08-01 12:52:06 +03:00
bol-van
497810ab4e tpws: special case for ip looking hostnames 2025-08-01 12:48:16 +03:00
bol-van
4cfed1db7e nfqws: print hostname_is_ip in ipv6 ipcache 2025-08-01 12:12:24 +03:00
bol-van
fd6b7a2b7f nfqws: optimize code 2025-08-01 12:03:53 +03:00
bol-van
6d865ad790 nfqws: comment 2025-08-01 11:31:48 +03:00
bol-van
dfe36aee4c nfqws: special case for ip looking hostnames 2025-08-01 11:21:23 +03:00
bol-van
2d704a859d blockcheck: display timestamp enable message 2025-07-31 13:57:13 +03:00
bol-van
8026d11f71 blockcheck: test ts fooling, silently enable timestamps in windows 2025-07-31 13:49:30 +03:00
bol-van
2f77cec863 doc works 2025-07-31 13:11:18 +03:00
bol-van
ba7954f068 doc works 2025-07-31 13:09:44 +03:00
bol-van
8b5c951451 nfqws: ts fooling 2025-07-31 12:51:31 +03:00
bol-van
84e75b0f28 doc works 2025-07-30 15:08:09 +03:00
bol-van
c4e5db309f doc works 2025-07-30 15:06:24 +03:00
bol-van
769f7b60c8 doc works 2025-07-30 15:02:08 +03:00
bol-van
b0578c5e9f doc works 2025-07-30 15:00:41 +03:00
bol-van
40362bfb5b doc works 2025-07-30 15:00:05 +03:00
bol-van
10eb9050a1 doc works 2025-07-30 14:59:28 +03:00
bol-van
b63e598085 FILTER_MARK support 2025-07-30 14:42:30 +03:00
bol-van
c60f9c9027 doc update ver 2025-07-08 10:01:58 +03:00
bol-van
951c980bec typo 2025-07-07 17:33:36 +03:00
bol-van
5eaec085dd install_easy: warn about --ipset 2025-07-07 15:53:46 +03:00
bol-van
721b353776 doc works 2025-07-07 15:38:51 +03:00
bol-van
e6d2051c87 doc works 2025-07-07 15:37:40 +03:00
bol-van
e665794ac4 doc works 2025-07-07 15:33:41 +03:00
bol-van
7db14a07c5 tpws: openbsd no more inits /dev/pf by default 2025-07-07 15:33:02 +03:00
bol-van
c14554c1f3 Merge pull request #1585 from artur-intech/patch-1
Fix filename
2025-06-30 07:46:10 +03:00
Artur
ced1682003 Fix filename 2025-06-29 21:45:50 +03:00
Artur
4701f27372 Fix filename
It is `zapret-hosts-user.txt`, not `*-users*`.
2025-06-29 20:18:37 +03:00
bol-van
a1699067b3 Merge pull request #1575 from dass79zh/ipv6less-curl-fix
Support curl compiled without IPv6 support.
2025-06-27 21:57:08 +03:00
Andrew Danshin
643fc0c456 Support curl compiled without IPv6 support.
modified:   blockcheck.sh
2025-06-27 21:07:32 +03:00
bol-van
09c07f6d21 winws: decrease wf-save buf 2025-06-23 08:17:52 +03:00
bol-van
dd72c68ae6 winws: increase windivert filter buffers 2025-06-23 08:14:36 +03:00
bol-van
9c1a3e77cc Makefiles: CC=cc 2025-06-22 21:39:27 +03:00
bol-van
ae957e9a73 doc fix 2025-06-22 19:27:20 +03:00
bol-van
bc47a13ba4 install_bin: no help text if getarch 2025-06-16 09:13:40 +03:00
bol-van
20b69cb63d install_bin: minor improve help text 2025-06-16 07:15:08 +03:00
bol-van
ef4f8a2b86 install_bin: display help text if no bins found 2025-06-16 07:11:59 +03:00
bol-van
d00d341505 blockcheck: display kernel ver 2025-06-15 16:22:38 +03:00
bol-van
0738d3980f blockcheck: curl version display 2025-06-15 15:56:25 +03:00
bol-van
34ff4630bf blockcheck: curl version display 2025-06-15 15:55:03 +03:00
bol-van
f8b5f602a4 nfqws: allow desync of replayed udp with reasm offset !=0 2025-06-15 09:18:25 +03:00
bol-van
8dacb57a86 OPTIMIZE in makefiles 2025-06-13 22:17:32 +03:00
bol-van
9776d5d8a9 nfqws: old gcc 4.x compat 2025-06-13 11:44:11 +03:00
bol-van
f88c9a662d nfqws: allow linux build without ssid 2025-06-13 11:31:50 +03:00
bol-van
97bcb9740d update docs 2025-06-13 11:12:37 +03:00
bol-van
b6e9fa3434 nfqws: check wext ssid len not zero 2025-06-12 13:22:54 +03:00
bol-van
32cfee705a nfqws: optimize wext 2025-06-12 11:58:20 +03:00
bol-van
1303bf0fef update changes.txt 2025-06-12 11:46:34 +03:00
bol-van
2417d4ee76 nfqws: use wireless ext in case nl80211 does not return ssid 2025-06-12 11:45:14 +03:00
bol-van
64280cbf3d doc works 2025-06-12 09:08:21 +03:00
bol-van
54dd06056e doc works 2025-06-12 09:06:06 +03:00
bol-van
0be4cbf8a4 rename windows bin dirs 2025-06-11 21:28:18 +03:00
bol-van
acf888c493 rename android bin dir 2025-06-11 21:26:32 +03:00
bol-van
f3d90d4e00 rename freebsd bin dir 2025-06-11 21:25:14 +03:00
bol-van
ceec80a8ed openwrt makefile -lmnl 2025-06-11 20:52:12 +03:00
bol-van
e876096072 rename bin dirs 2025-06-11 20:49:46 +03:00
bol-van
796e4a40b6 rename bin dirs 2025-06-11 20:48:51 +03:00
bol-van
5b7c4a4318 rename bin dirs 2025-06-11 20:46:53 +03:00
bol-van
f09d918b40 nfqws,tpws: use initgroups() if --user specified 2025-06-11 20:15:43 +03:00
bol-van
f3d48b7160 nfqws: debug wlan info init 2025-06-04 10:05:42 +03:00
bol-van
58d306b552 nfqws: --filter-ssid (linux only) 2025-06-04 09:26:38 +03:00
bol-van
30a947b42b install_bin.sh : minor bug 2025-06-01 19:16:37 +03:00
bol-van
9fe26c92a5 install_bin: remove quarantine xattr on macos 2025-06-01 15:30:51 +03:00
bol-van
ab0d16f4e1 install_easy: fix broken compile on mac 2025-06-01 09:11:33 +03:00
bol-van
c37c39996d static 2025-05-31 13:42:36 +03:00
bol-van
87a0cf0797 nfqws,tpws: --debug=android for NDK builds 2025-05-31 10:34:03 +03:00
bol-van
893a133f86 install_easy: rephrase 2025-05-30 10:54:20 +03:00
bol-van
fa9e3c09f1 install_easy: ask MODE_FILTER before daemon test 2025-05-29 19:14:35 +03:00
bol-van
2edf6bee34 install_easy: minor fix 2025-05-29 19:05:50 +03:00
bol-van
468d293b46 install_easy: run daemon test under proper user 2025-05-29 19:02:50 +03:00
bol-van
fd698d801b nfqws,tpws: check list files accessibility with dropped privs in --dry-run mode 2025-05-29 15:43:27 +03:00
bol-van
38a3833351 install_bin: do exec test after elf test 2025-05-28 23:06:12 +03:00
bol-van
6c9ff2010b install_bin: fix TEST=run 2025-05-28 22:46:55 +03:00
bol-van
06f57e27ed install_bin: fix minor problems 2025-05-28 20:40:26 +03:00
bol-van
06921bdbee install_bin: read elf detection method 2025-05-28 20:27:34 +03:00
bol-van
3999e0b350 install_bin: read elf detection method 2025-05-28 20:22:09 +03:00
bol-van
1301aca25b Upx 5.0.1 still has bugs on mips
This reverts commit f0a8a35c12.
2025-05-28 19:37:57 +03:00
bol-van
bf4244809f install_easy: stop if running embedded release on traditional linux 2025-05-28 14:37:32 +03:00
bol-van
99b5406905 redsocks: shell /bin/false 2025-05-27 22:24:58 +03:00
bol-van
ebd01868ee redsocks: no bash for su 2025-05-27 22:20:46 +03:00
bol-van
c451addd86 redsocks: shadow-su 2025-05-27 21:53:44 +03:00
bol-van
4c8ea084d7 redsocks.txt: remove obsolete 2025-05-27 21:46:46 +03:00
bol-van
02badb3c4c nfqws,tpws: move --ipset to kavl 2025-05-27 16:03:28 +03:00
bol-van
323307cbfa Merge pull request #1464 from Dronatar/patch-1
Omission fix in readme.md
2025-05-26 09:38:57 +03:00
Dronatar
00560719bd Omission fix in readme.md 2025-05-26 06:15:29 +02:00
bol-van
56c96df47b remove seccomp from systemd units 2025-05-25 20:07:52 +03:00
bol-van
f0a8a35c12 They fixed problems
This reverts commit 58e73d0331.
2025-05-25 09:49:01 +03:00
bol-van
d566f48f94 blockcheck: display ip version every test 2025-05-24 13:35:11 +03:00
bol-van
3513cbb65e winws: fix trash flood warning message 2025-05-24 10:51:01 +03:00
bol-van
20f91cb7ab doc works 2025-05-24 09:58:41 +03:00
bol-van
4becc07572 update changes 2025-05-22 11:01:34 +03:00
bol-van
a39c18737b nfqws: - disables autottl 2025-05-22 11:00:11 +03:00
bol-van
ed7b743fe2 update changes.txt 2025-05-22 10:44:26 +03:00
bol-van
d3b0b3e0b1 nfqws,tpws: display android in version string 2025-05-22 10:19:30 +03:00
bol-van
ba040769a7 doc works 2025-05-21 17:40:46 +03:00
bol-van
0ced50e393 doc works 2025-05-21 17:39:50 +03:00
bol-van
f3abd6815a doc works 2025-05-20 19:07:42 +03:00
bol-van
4572799750 doc works 2025-05-20 19:06:48 +03:00
bol-van
696167509a doc works 2025-05-20 19:03:47 +03:00
bol-van
2374df6d74 doc works 2025-05-20 19:02:22 +03:00
bol-van
ab06d6b640 doc works 2025-05-20 19:01:14 +03:00
bol-van
60efab1cc6 doc works 2025-05-20 18:57:46 +03:00
bol-van
71aebbb4d3 nfqws: allow zero autottl 2025-05-20 18:06:56 +03:00
bol-van
c993f117a2 blockcheck: test http3 google fake 2025-05-20 12:05:43 +03:00
bol-van
b2f0c46388 update changes.txt 2025-05-20 11:32:58 +03:00
bol-van
2b095f863f blockcheck: report test function and domain every test 2025-05-20 11:32:08 +03:00
bol-van
a141dff374 nfqws: warn dup trash flood 2025-05-20 10:30:37 +03:00
bol-van
b34bfda8b5 blockcheck: tls multi fake test 2025-05-10 18:12:51 +03:00
bol-van
c1046a20db nfqws,tpws: sec_harden after daemonize 2025-05-10 16:57:04 +03:00
bol-van
24b93cca7e blockcheck: some dup and orig-autottl mods 2025-05-10 15:58:36 +03:00
bol-van
4f0fdb24f2 nfqws,tpws: support multiple gids in --uid 2025-05-10 11:11:56 +03:00
bol-van
6d52b49b98 nfqws: do not reconstruct synack-split in syn mode 2025-05-10 09:41:26 +03:00
bol-van
4b632313e2 nfqws: improve --synack-split 2025-05-09 20:57:14 +03:00
bol-van
22f3ecaec1 doc works 2025-05-09 20:41:02 +03:00
bol-van
2a23bc99f6 nfqws: --synack-split select syn or ack first 2025-05-09 20:20:55 +03:00
bol-van
8a1d7c7abd doc works 2025-05-09 17:21:08 +03:00
bol-van
ba712f308d doc works 2025-05-09 17:19:46 +03:00
bol-van
9ace0328ad doc works 2025-05-09 17:18:44 +03:00
bol-van
5c6f79799a doc works 2025-05-09 16:45:00 +03:00
bol-van
a84d015b1e doc works 2025-05-09 16:44:08 +03:00
bol-van
2d90a28dbc Revert "doc works"
This reverts commit 3c77bab002.
2025-05-09 16:42:17 +03:00
bol-van
3c77bab002 doc works 2025-05-09 16:22:21 +03:00
bol-van
8f27725d6a nfqws: --synack-split 2025-05-09 16:20:28 +03:00
62 changed files with 3160 additions and 770 deletions

View File

@@ -7,13 +7,19 @@ assignees: ''
--- ---
1. Здесь не место для вопросов, касающихся компьютерной грамотности и навыков использования ОС Issues - это место для обращений к разработчику.
2. Здесь не место для вопросов "у меня не работает" без технических подробностей Discussions - место для обсуждения вопросов между пользователями.
3. Здесь не место для вопросов "как мне открыть ютуб", "что писать в ...", "перестало открываться". Не тратье время разработчика на ерунду. Вам не будут здесь обьяснять как скопировать, что "писать в", почему сразу же закрывается окно, почему не открывается сайт или госуслуги. Здесь не место обсуждению любых шаманств , т.е. манипуляций без понимания, в стиле 4pda.
4. Здесь не место для обсуждения сборок Пишите только конкретные проблемы на техническом уровне в оригинальном zapret (не в сборках), которые вы заметили, и которые являются или могут являться багами в софте.
5. Вирусов здесь нет. У вас либо чья-то сборка, либо ваш антивирус давно пора отправить на покой. Антивирусы в основном жалуются на upx и windivert, которые убраны НЕ будут. upx - это паковщик для сокращения требуемого места на openwrt, windivert - замена iptables для windows, потенциальный инструмент хакера или компонент зловредной программы, но сам по себе вирусом не является. Не согласны - удаляйте софт. За агрессивные наезды "почему автор распространяет вирусы" молча схватите бан. Или если вы считаете, что ваше обращение обосновано, технически грамотно и по адресу.
Все, что будет нарушать эти критерии, может быть молча удалено, закрыто или перенесено в дискуссии на усмотрение разработчика.
Если сомневаетесь - пишите лучше сразу в дискуссии.
Все означенное обсуждать в дискуссиях или на форумах. Прочитайте для начала docs/quick_start.md или docs/quick_start_windows.md.
При нарушении будет закрываться или конвертироваться в дискуссии. Там обьясняется для кого этот софт, какие требуются знания, почему это не простая волшебная таблетка.
Issue только для обсуждения проблем самого софта. Неработа стратегии или ваше неумение настроить - это ваша проблема, а не проблема софта.
Однокнопочные решения дают только сборщики, поэтому "открытие сайта" не является функцией программы, и нет смысла жаловаться, что он не открывается. Но можно это обсудить в дискуссиях. Не захламляйте issues ! Вирусов здесь нет. У вас либо чья-то сборка, либо ваш антивирус давно пора отправить на покой. Антивирусы в основном жалуются на upx и windivert, которые убраны НЕ будут. upx - это паковщик для сокращения требуемого места на openwrt, windivert - замена iptables для windows, потенциальный инструмент хакера или компонент зловредной программы, но сам по себе вирусом не является. Не согласны - удаляйте софт. За агрессивные наезды "почему автор распространяет вирусы" молча схватите бан.
Here is the place for bugs only. All questions, especially user-like questions (non-technical) go to Discussions.
There're also no viruses here. All virus claims and everyting non-technical and non-bugs will be instantly deleted, closed or moved to Discussions.

View File

@@ -427,7 +427,6 @@ jobs:
unzip $f -d $dir && rm $f unzip $f -d $dir && rm $f
if [[ $dir =~ win ]]; then if [[ $dir =~ win ]]; then
chmod -x $dir/* chmod -x $dir/*
run_upx --force $dir/cygwin1.dll
fi fi
;; ;;
esac esac
@@ -438,23 +437,23 @@ jobs:
if [ -d $dir ]; then if [ -d $dir ]; then
echo "Processing $dir" echo "Processing $dir"
case $dir in case $dir in
*-android-arm64-v8a ) run_dir android-aarch64 ;; *-android-arm64-v8a ) run_dir android-arm64 ;;
*-android-armeabi-v7a ) run_dir android-arm ;; *-android-armeabi-v7a ) run_dir android-arm ;;
*-android-x86 ) run_dir android-x86 ;; *-android-x86 ) run_dir android-x86 ;;
*-android-x86_64 ) run_dir android-x86_64 ;; *-android-x86_64 ) run_dir android-x86_64 ;;
*-freebsd-x86_64 ) run_dir freebsd-x64 ;; *-freebsd-x86_64 ) run_dir freebsd-x86_64 ;;
*-linux-arm ) run_dir arm ;; *-linux-arm ) run_dir linux-arm ;;
*-linux-arm64 ) run_dir aarch64 ;; *-linux-arm64 ) run_dir linux-arm64 ;;
*-linux-mips64 ) run_dir mips64r2-msb ;; *-linux-mips64 ) run_dir linux-mips64 ;;
*-linux-mipselsf ) run_dir mips32r1-lsb ;; *-linux-mipselsf ) run_dir linux-mipsel ;;
*-linux-mipssf ) run_dir mips32r1-msb ;; *-linux-mipssf ) run_dir linux-mips ;;
*-linux-ppc ) run_dir ppc ;; *-linux-ppc ) run_dir linux-ppc ;;
*-linux-x86 ) run_dir x86 ;; *-linux-x86 ) run_dir linux-x86 ;;
*-linux-x86_64 ) run_dir x86_64 ;; *-linux-x86_64 ) run_dir linux-x86_64 ;;
*-linux-lexra ) run_dir lexra ;; *-linux-lexra ) run_dir linux-lexra ;;
*-mac-x64 ) run_dir mac64 ;; *-mac-x64 ) run_dir mac64 ;;
*-win-x86 ) run_dir win32 ;; *-win-x86 ) run_dir windows-x86 ;;
*-win-x86_64 ) run_dir win64 ;; *-win-x86_64 ) run_dir windows-x86_64 ;;
esac esac
fi fi
done done

View File

@@ -396,13 +396,24 @@ check_system()
PKTWS="$WINWS" PKTWS="$WINWS"
PKTWSD=winws PKTWSD=winws
FWTYPE=windivert FWTYPE=windivert
# ts fooling requires timestamps. they are disabled by default in windows.
echo enabling tcp timestamps
netsh interface tcp set global timestamps=enabled >/dev/null
;; ;;
*) *)
echo $UNAME not supported echo $UNAME not supported
exitp 5 exitp 5
esac esac
echo $UNAME${SUBSYS:+/$SUBSYS} detected echo $UNAME${SUBSYS:+/$SUBSYS} detected
echo -n 'kernel: '
if [ -f "/proc/version" ]; then
cat /proc/version
else
uname -a
fi
echo firewall type is $FWTYPE echo firewall type is $FWTYPE
echo CURL=$CURL
$CURL --version
} }
zp_already_running() zp_already_running()
@@ -627,7 +638,11 @@ curl_with_subst_ip()
# $2 - port # $2 - port
# $3 - ip # $3 - ip
# $4+ - curl params # $4+ - curl params
local connect_to="--connect-to $1::[$3]${2:+:$2}" arg local ip="$3"
case "$ip" in
*:*) ip="[$ip]" ;;
esac
local connect_to="--connect-to $1::$ip${2:+:$2}" arg
shift ; shift ; shift shift ; shift ; shift
[ "$CURL_VERBOSE" = 1 ] && arg="-v" [ "$CURL_VERBOSE" = 1 ] && arg="-v"
[ "$CURL_CMD" = 1 ] && echo $CURL ${arg:+$arg }$connect_to "$@" [ "$CURL_CMD" = 1 ] && echo $CURL ${arg:+$arg }$connect_to "$@"
@@ -1042,6 +1057,7 @@ curl_test()
} }
ws_curl_test() ws_curl_test()
{ {
# $1 - ws start function # $1 - ws start function
# $2 - test function # $2 - test function
# $3 - domain # $3 - domain
@@ -1061,7 +1077,7 @@ tpws_curl_test()
# $1 - test function # $1 - test function
# $2 - domain # $2 - domain
# $3,$4,$5, ... - tpws params # $3,$4,$5, ... - tpws params
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"} echo - $1 ipv$IPV $2 : 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" 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"} 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 testf=$1 dom=$2 strategy code=$? local testf=$1 dom=$2 strategy code=$?
@@ -1078,11 +1094,14 @@ pktws_curl_test()
# $1 - test function # $1 - test function
# $2 - domain # $2 - domain
# $3,$4,$5, ... - nfqws/dvtws params # $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"} local testf=$1 dom=$2 strategy code
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 testf=$1 dom=$2 strategy code=$? shift; shift;
echo - $testf ipv$IPV $dom : $PKTWSD ${WF:+$WF }${PKTWS_EXTRA_PRE:+$PKTWS_EXTRA_PRE }${PKTWS_EXTRA_PRE_1:+"$PKTWS_EXTRA_PRE_1" }${PKTWS_EXTRA_PRE_2:+"$PKTWS_EXTRA_PRE_2" }${PKTWS_EXTRA_PRE_3:+"$PKTWS_EXTRA_PRE_3" }${PKTWS_EXTRA_PRE_4:+"$PKTWS_EXTRA_PRE_4" }${PKTWS_EXTRA_PRE_5:+"$PKTWS_EXTRA_PRE_5" }${PKTWS_EXTRA_PRE_6:+"$PKTWS_EXTRA_PRE_6" }${PKTWS_EXTRA_PRE_7:+"$PKTWS_EXTRA_PRE_7" }${PKTWS_EXTRA_PRE_8:+"$PKTWS_EXTRA_PRE_8" }${PKTWS_EXTRA_PRE_9:+"$PKTWS_EXTRA_PRE_9" }$@${PKTWS_EXTRA:+ $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 $testf $dom ${PKTWS_EXTRA_PRE:+$PKTWS_EXTRA_PRE }${PKTWS_EXTRA_PRE_1:+"$PKTWS_EXTRA_PRE_1" }${PKTWS_EXTRA_PRE_2:+"$PKTWS_EXTRA_PRE_2" }${PKTWS_EXTRA_PRE_3:+"$PKTWS_EXTRA_PRE_3" }${PKTWS_EXTRA_PRE_4:+"$PKTWS_EXTRA_PRE_4" }${PKTWS_EXTRA_PRE_5:+"$PKTWS_EXTRA_PRE_5" }${PKTWS_EXTRA_PRE_6:+"$PKTWS_EXTRA_PRE_6" }${PKTWS_EXTRA_PRE_7:+"$PKTWS_EXTRA_PRE_7" }${PKTWS_EXTRA_PRE_8:+"$PKTWS_EXTRA_PRE_8" }${PKTWS_EXTRA_PRE_9:+"$PKTWS_EXTRA_PRE_9" }"$@"${PKTWS_EXTRA:+ $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"}
code=$?
[ "$code" = 0 ] && { [ "$code" = 0 ] && {
shift; shift;
strategy="$@" strategy="$@"
strategy_append_extra_pktws strategy_append_extra_pktws
report_append "ipv${IPV} $dom $testf : $PKTWSD ${WF:+$WF }$strategy" report_append "ipv${IPV} $dom $testf : $PKTWSD ${WF:+$WF }$strategy"
@@ -1092,11 +1111,11 @@ pktws_curl_test()
strategy_append_extra_pktws() strategy_append_extra_pktws()
{ {
strategy="${strategy:+$strategy${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"}}" strategy="${strategy:+${PKTWS_EXTRA_PRE:+$PKTWS_EXTRA_PRE }${PKTWS_EXTRA_PRE_1:+"$PKTWS_EXTRA_PRE_1" }${PKTWS_EXTRA_PRE_2:+"$PKTWS_EXTRA_PRE_2" }${PKTWS_EXTRA_PRE_3:+"$PKTWS_EXTRA_PRE_3" }${PKTWS_EXTRA_PRE_4:+"$PKTWS_EXTRA_PRE_4" }${PKTWS_EXTRA_PRE_5:+"$PKTWS_EXTRA_PRE_5" }${PKTWS_EXTRA_PRE_6:+"$PKTWS_EXTRA_PRE_6" }${PKTWS_EXTRA_PRE_7:+"$PKTWS_EXTRA_PRE_7" }${PKTWS_EXTRA_PRE_8:+"$PKTWS_EXTRA_PRE_8" }${PKTWS_EXTRA_PRE_9:+"$PKTWS_EXTRA_PRE_9" }$strategy${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"}}"
} }
strategy_append_extra_tpws() strategy_append_extra_tpws()
{ {
strategy="${strategy:+$strategy${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"}}" strategy="${strategy:+${PKTWS_EXTRA_PRE:+$PKTWS_EXTRA_PRE }${PKTWS_EXTRA_PRE_1:+"$PKTWS_EXTRA_PRE_1" }${PKTWS_EXTRA_PRE_2:+"$PKTWS_EXTRA_PRE_2" }${PKTWS_EXTRA_PRE_3:+"$PKTWS_EXTRA_PRE_3" }${PKTWS_EXTRA_PRE_4:+"$PKTWS_EXTRA_PRE_4" }${PKTWS_EXTRA_PRE_5:+"$PKTWS_EXTRA_PRE_5" }${PKTWS_EXTRA_PRE_6:+"$PKTWS_EXTRA_PRE_6" }${PKTWS_EXTRA_PRE_7:+"$PKTWS_EXTRA_PRE_7" }${PKTWS_EXTRA_PRE_8:+"$PKTWS_EXTRA_PRE_8" }${PKTWS_EXTRA_PRE_9:+"$PKTWS_EXTRA_PRE_9" }$strategy${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"}}"
} }
xxxws_curl_test_update() xxxws_curl_test_update()
@@ -1179,6 +1198,7 @@ warn_fool()
echo "WARNING ! fakedsplit/fakeddisorder with md5sig fooling and low split position causes MTU overflow with multi-segment TLS (kyber)" echo "WARNING ! fakedsplit/fakeddisorder with md5sig fooling and low split position causes MTU overflow with multi-segment TLS (kyber)"
;; ;;
datanoack) echo 'WARNING ! although datanoack fooling worked it may break NAT and may only work with external IP. Additionally it may require nftables to work correctly.' ;; datanoack) echo 'WARNING ! although datanoack fooling worked it may break NAT and may only work with external IP. Additionally it may require nftables to work correctly.' ;;
ts) echo 'WARNING ! although ts fooling worked it will not work without timestamps being enabled in the client OS. In windows timestamps are DISABLED by default.'
esac esac
} }
pktws_curl_test_update_vary() pktws_curl_test_update_vary()
@@ -1189,15 +1209,19 @@ pktws_curl_test_update_vary()
# $4 - desync mode # $4 - desync mode
# $5,$6,... - strategy # $5,$6,... - strategy
local testf=$1 sec=$2 domain=$3 desync=$4 proto zerofake= tlsmod= splits= pos fake ret=1 local testf=$1 sec=$2 domain=$3 desync=$4 proto splits= pos fake ret=1
local fake1=- fake2=- fake3=-
shift; shift; shift; shift shift; shift; shift; shift
proto=http proto=http
[ "$sec" = 0 ] || proto=tls [ "$sec" = 0 ] || proto=tls
test_has_fake $desync && { test_has_fake $desync && {
zerofake="--dpi-desync-fake-$proto=0x00000000" fake1="--dpi-desync-fake-$proto=0x00000000"
[ "$sec" = 0 ] || tlsmod="--dpi-desync-fake-tls-mod=rnd,dupsid,rndsni,padencap" [ "$sec" = 0 ] || {
fake2="--dpi-desync-fake-tls=0x00000000 --dpi-desync-fake-tls=! --dpi-desync-fake-tls-mod=rnd,rndsni,dupsid"
fake3="--dpi-desync-fake-tls-mod=rnd,dupsid,rndsni,padencap"
}
} }
if test_has_fakedsplit $desync ; then if test_has_fakedsplit $desync ; then
splits="method+2 midsld" splits="method+2 midsld"
@@ -1206,7 +1230,8 @@ pktws_curl_test_update_vary()
splits="method+2 midsld" splits="method+2 midsld"
[ "$sec" = 0 ] || splits="1 midsld 1,midsld" [ "$sec" = 0 ] || splits="1 midsld 1,midsld"
fi fi
for fake in '' $zerofake $tlsmod ; do for fake in '' "$fake1" "$fake2" "$fake3" ; do
[ "$fake" = "-" ] && continue
if [ -n "$splits" ]; then if [ -n "$splits" ]; then
for pos in $splits ; do for pos in $splits ; do
pktws_curl_test_update $testf $domain --dpi-desync=$desync "$@" --dpi-desync-split-pos=$pos $fake && { pktws_curl_test_update $testf $domain --dpi-desync=$desync "$@" --dpi-desync-split-pos=$pos $fake && {
@@ -1231,14 +1256,14 @@ pktws_check_domain_http_bypass_()
# $2 - encrypted test : 0 = plain, 1 - encrypted with server reply risk, 2 - encrypted without server reply risk # $2 - encrypted test : 0 = plain, 1 - encrypted with server reply risk, 2 - encrypted without server reply risk
# $3 - domain # $3 - domain
local ok ttls s f f2 e desync pos fooling frag sec="$2" delta splits local ok ttls s f f2 e desync pos fooling frag sec="$2" delta orig splits
local need_split need_disorder need_fakedsplit need_fakeddisorder need_fake need_wssize local need_split need_disorder need_fakedsplit need_fakeddisorder need_fake need_wssize
local splits_http='method+2 midsld method+2,midsld' local splits_http='method+2 midsld method+2,midsld'
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' 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 ] && { [ "$sec" = 0 ] && {
for s in '--hostcase' '--hostspell=hoSt' '--hostnospace' '--domcase' '--methodeol'; do for s in '--hostcase' '--hostspell=hoSt' '--hostnospace' '--domcase' '--methodeol'; do
pktws_curl_test_update $1 $3 $s pktws_curl_test_update $1 $3 $s && [ "$SCANLEVEL" = quick ] && return
done done
} }
@@ -1300,13 +1325,24 @@ pktws_check_domain_http_bypass_()
} }
f= f=
[ "$UNAME" = "OpenBSD" ] || f="badsum" [ "$UNAME" = "OpenBSD" ] || f="badsum"
f="$f badseq datanoack md5sig" f="$f badseq datanoack ts md5sig"
[ "$IPV" = 6 ] && f="$f hopbyhop hopbyhop2" [ "$IPV" = 6 ] && f="$f hopbyhop hopbyhop2"
for fooling in $f; do for fooling in $f; do
ok=0
pktws_curl_test_update_vary $1 $2 $3 $desync --dpi-desync-fooling=$fooling $e && { pktws_curl_test_update_vary $1 $2 $3 $desync --dpi-desync-fooling=$fooling $e && {
warn_fool $fooling $desync warn_fool $fooling $desync
[ "$SCANLEVEL" = quick ] && return [ "$SCANLEVEL" = quick ] && return
need_wssize=0 need_wssize=0
ok=1
}
[ "$fooling" = md5sig ] && {
[ "$ok" = 1 -a "$SCANLEVEL" != force ] && continue
pktws_curl_test_update_vary $1 $2 $3 $desync --dpi-desync-fooling=$fooling --dup=1 --dup-cutoff=n2 --dup-fooling=md5sig $e && {
warn_fool $fooling $desync
echo "HINT ! To avoid possible 1 sec server response delay use --dup-ttl or --dup-autottl and block ICMP time exceeded"
[ "$SCANLEVEL" = quick ] && return
need_wssize=0
}
} }
done done
done done
@@ -1369,8 +1405,11 @@ pktws_check_domain_http_bypass_()
[ "$need_fakedsplit" = 0 ] && contains "$desync" fakedsplit && continue [ "$need_fakedsplit" = 0 ] && contains "$desync" fakedsplit && continue
[ "$need_fakeddisorder" = 0 ] && contains "$desync" fakeddisorder && continue [ "$need_fakeddisorder" = 0 ] && contains "$desync" fakeddisorder && continue
ok=0 ok=0
for delta in 1 2 3 4 5; do for orig in '' 1 2 3; do
pktws_curl_test_update_vary $1 $2 $3 $desync --dpi-desync-ttl=1 --dpi-desync-autottl=$delta $e && ok=1 for delta in 1 2 3 4 5; do
pktws_curl_test_update_vary $1 $2 $3 $desync ${orig:+--orig-autottl=+$orig} --dpi-desync-ttl=1 --dpi-desync-autottl=-$delta $e && ok=1
done
[ "$ok" = 1 -a "$SCANLEVEL" != force ] && break
done done
[ "$ok" = 1 ] && [ "$ok" = 1 ] &&
{ {
@@ -1415,13 +1454,15 @@ pktws_check_domain_http3_bypass_()
# $1 - test function # $1 - test function
# $2 - domain # $2 - domain
local f desync frag tests rep local f desync frag tests rep fake
for rep in '' 2 5 10 20; do for fake in '' "--dpi-desync-fake-quic=$ZAPRET_BASE/files/fake/quic_initial_www_google_com.bin"; do
pktws_curl_test_update $1 $2 --dpi-desync=fake ${rep:+--dpi-desync-repeats=$rep} && [ "$SCANLEVEL" != force ] && { for rep in '' 2 5 10 20; do
[ "$SCANLEVEL" = quick ] && return pktws_curl_test_update $1 $2 --dpi-desync=fake ${fake:+$fake }${rep:+--dpi-desync-repeats=$rep} && [ "$SCANLEVEL" != force ] && {
break [ "$SCANLEVEL" = quick ] && return
} break
}
done
done done
[ "$IPV" = 6 ] && { [ "$IPV" = 6 ] && {

View File

@@ -406,12 +406,15 @@ has_bad_ws_options()
{ {
# $1 - nfqws/tpws opts # $1 - nfqws/tpws opts
# kernel or user mode ipset usage should be wise contains "$1" "--ipset" && {
# if all traffic is already intercepted it would be OK to use ip-based specialized profiles echo
# but if all traffic is intercepted only to filter a group of ip its BAD. kernel ipset should be used. echo "WARNING !!! --ipset parameter is present"
# I cannot insert brain to copy-pasters, I know they will misuse. But it's their problem. echo "It's OK if you only specialize already redirected traffic and also process the rest."
# zapret is not made for newbies echo "If you redirect port X to process several IPs from the list and do nothing with the rest - IT'S VERY INEFFECTIVE !"
#contains "$1" "--ipset" echo "Kernel ipsets should be used instead. Write custom scripts and filter IPs in kernel."
echo
}
return 1 return 1
} }
check_bad_ws_options() check_bad_ws_options()
@@ -428,8 +431,5 @@ check_bad_ws_options()
} }
help_bad_ws_options() help_bad_ws_options()
{ {
echo "WARNING ! you have specified --ipset option" echo "WARNING ! BAD options detected"
echo "WARNING ! it would work but on ${UNAME:-$(uname)} it's not the best option"
echo "WARNING ! you should use kernel mode sets. they are much more efficient."
echo "WARNING ! to use ipsets you have to write your own custom script"
} }

View File

@@ -187,7 +187,7 @@ check_system()
SYSTEM= SYSTEM=
SUBSYS= SUBSYS=
SYSTEMCTL=$(whichq systemctl) SYSTEMCTL="$(whichq systemctl)"
get_fwtype get_fwtype
OPENWRT_FW3= OPENWRT_FW3=
@@ -203,6 +203,7 @@ check_system()
# some distros include systemctl without systemd # some distros include systemctl without systemd
if [ -d "$SYSTEMD_DIR" ] && [ -x "$SYSTEMCTL" ] && [ "$INIT" = "systemd" ]; then if [ -d "$SYSTEMD_DIR" ] && [ -x "$SYSTEMCTL" ] && [ "$INIT" = "systemd" ]; then
SYSTEM=systemd SYSTEM=systemd
[ -f "$EXEDIR/init.d/sysv/functions" ] && . "$EXEDIR/init.d/sysv/functions"
elif [ -f "/etc/openwrt_release" ] && exists opkg || exists apk && exists uci && [ "$INIT" = "procd" ] ; then elif [ -f "/etc/openwrt_release" ] && exists opkg || exists apk && exists uci && [ "$INIT" = "procd" ] ; then
SYSTEM=openwrt SYSTEM=openwrt
OPENWRT_PACKAGER=opkg OPENWRT_PACKAGER=opkg
@@ -226,8 +227,10 @@ check_system()
OPENWRT_FW4=1 OPENWRT_FW4=1
info="${info}firewall fw4. flow offloading requires nftables." info="${info}firewall fw4. flow offloading requires nftables."
fi fi
[ -f "$EXEDIR/init.d/openwrt/functions" ] && . "$EXEDIR/init.d/openwrt/functions"
elif openrc_test; then elif openrc_test; then
SYSTEM=openrc SYSTEM=openrc
[ -f "$EXEDIR/init.d/sysv/functions" ] && . "$EXEDIR/init.d/sysv/functions"
else else
echo system is not either systemd, openrc or openwrt based echo system is not either systemd, openrc or openwrt based
echo easy installer can set up config settings but can\'t configure auto start echo easy installer can set up config settings but can\'t configure auto start
@@ -237,10 +240,12 @@ check_system()
else else
exitp 5 exitp 5
fi fi
[ -f "$EXEDIR/init.d/sysv/functions" ] && . "$EXEDIR/init.d/sysv/functions"
fi fi
linux_get_subsys linux_get_subsys
elif [ "$UNAME" = "Darwin" ]; then elif [ "$UNAME" = "Darwin" ]; then
SYSTEM=macos SYSTEM=macos
[ -f "$EXEDIR/init.d/macos/functions" ] && . "$EXEDIR/init.d/macos/functions"
else else
echo easy installer only supports Linux and MacOS. check readme.md for supported systems and manual setup info. echo easy installer only supports Linux and MacOS. check readme.md for supported systems and manual setup info.
exitp 5 exitp 5
@@ -834,13 +839,13 @@ dry_run_tpws_()
{ {
local TPWS="$ZAPRET_BASE/tpws/tpws" local TPWS="$ZAPRET_BASE/tpws/tpws"
echo verifying tpws options echo verifying tpws options
"$TPWS" --dry-run "$@" "$TPWS" --dry-run ${WS_USER:+--user=$WS_USER} "$@"
} }
dry_run_nfqws_() dry_run_nfqws_()
{ {
local NFQWS="$ZAPRET_BASE/nfq/nfqws" local NFQWS="$ZAPRET_BASE/nfq/nfqws"
echo verifying nfqws options echo verifying nfqws options
"$NFQWS" --dry-run "$@" "$NFQWS" --dry-run ${WS_USER:+--user=$WS_USER} "$@"
} }
dry_run_tpws() dry_run_tpws()
{ {

View File

@@ -112,6 +112,10 @@ unprepare_tpws_fw()
unprepare_tpws_fw4 unprepare_tpws_fw4
} }
ipt_mark_filter()
{
[ -n "$FILTER_MARK" ] && echo "-m mark --mark $FILTER_MARK/$FILTER_MARK"
}
ipt_print_op() ipt_print_op()
{ {
@@ -136,7 +140,7 @@ _fw_tpws4()
ipt_print_op $1 "$2" "tpws (port $3)" ipt_print_op $1 "$2" "tpws (port $3)"
rule="$2 $IPSET_EXCLUDE dst $IPBAN_EXCLUDE dst -j DNAT --to $TPWS_LOCALHOST4:$3" rule="$(ipt_mark_filter) $2 $IPSET_EXCLUDE dst $IPBAN_EXCLUDE dst -j DNAT --to $TPWS_LOCALHOST4:$3"
for i in $4 ; do for i in $4 ; do
ipt_add_del $1 PREROUTING -t nat -i $i $rule ipt_add_del $1 PREROUTING -t nat -i $i $rule
done done
@@ -164,7 +168,7 @@ _fw_tpws6()
ipt_print_op $1 "$2" "tpws (port $3)" 6 ipt_print_op $1 "$2" "tpws (port $3)" 6
rule="$2 $IPSET_EXCLUDE6 dst $IPBAN_EXCLUDE6 dst" rule="$(ipt_mark_filter) $2 $IPSET_EXCLUDE6 dst $IPBAN_EXCLUDE6 dst"
for i in $4 ; do for i in $4 ; do
_dnat6_target $i DNAT6 _dnat6_target $i DNAT6
[ -n "$DNAT6" -a "$DNAT6" != "-" ] && ipt6_add_del $1 PREROUTING -t nat -i $i $rule -j DNAT --to [$DNAT6]:$3 [ -n "$DNAT6" -a "$DNAT6" != "-" ] && ipt6_add_del $1 PREROUTING -t nat -i $i $rule -j DNAT --to [$DNAT6]:$3
@@ -202,7 +206,7 @@ _fw_nfqws_post4()
ipt_print_op $1 "$2" "nfqws postrouting (qnum $3)" ipt_print_op $1 "$2" "nfqws postrouting (qnum $3)"
rule="-m mark ! --mark $DESYNC_MARK/$DESYNC_MARK $2 $IPSET_EXCLUDE dst -j NFQUEUE --queue-num $3 --queue-bypass" rule="$(ipt_mark_filter) -m mark ! --mark $DESYNC_MARK/$DESYNC_MARK $2 $IPSET_EXCLUDE dst -j NFQUEUE --queue-num $3 --queue-bypass"
if [ -n "$4" ] ; then if [ -n "$4" ] ; then
for i in $4; do for i in $4; do
ipt_add_del $1 POSTROUTING -t mangle -o $i $rule ipt_add_del $1 POSTROUTING -t mangle -o $i $rule
@@ -223,7 +227,7 @@ _fw_nfqws_post6()
ipt_print_op $1 "$2" "nfqws postrouting (qnum $3)" 6 ipt_print_op $1 "$2" "nfqws postrouting (qnum $3)" 6
rule="-m mark ! --mark $DESYNC_MARK/$DESYNC_MARK $2 $IPSET_EXCLUDE6 dst -j NFQUEUE --queue-num $3 --queue-bypass" rule="$(ipt_mark_filter) -m mark ! --mark $DESYNC_MARK/$DESYNC_MARK $2 $IPSET_EXCLUDE6 dst -j NFQUEUE --queue-num $3 --queue-bypass"
if [ -n "$4" ] ; then if [ -n "$4" ] ; then
for i in $4; do for i in $4; do
ipt6_add_del $1 POSTROUTING -t mangle -o $i $rule ipt6_add_del $1 POSTROUTING -t mangle -o $i $rule

View File

@@ -312,6 +312,10 @@ nft_filter_apply_ipset_target()
nft_filter_apply_ipset_target6 $2 nft_filter_apply_ipset_target6 $2
} }
nft_mark_filter()
{
[ -n "$FILTER_MARK" ] && echo "mark and $FILTER_MARK != 0"
}
nft_script_add_ifset_element() nft_script_add_ifset_element()
{ {
@@ -403,9 +407,10 @@ _nft_fw_tpws4()
[ "$DISABLE_IPV4" = "1" -o -z "$1" ] || { [ "$DISABLE_IPV4" = "1" -o -z "$1" ] || {
local filter="$1" port="$2" local filter="$1" port="$2"
local mark_filter=$(nft_mark_filter)
nft_print_op "$filter" "tpws (port $2)" 4 nft_print_op "$filter" "tpws (port $2)" 4
nft_insert_rule dnat_output skuid != $WS_USER ${3:+oifname @wanif }$filter ip daddr != @nozapret ip daddr != @ipban $FW_EXTRA_POST dnat ip to $TPWS_LOCALHOST4:$port nft_insert_rule dnat_output skuid != $WS_USER ${3:+oifname @wanif} $mark_filter $filter ip daddr != @nozapret ip daddr != @ipban $FW_EXTRA_POST dnat ip to $TPWS_LOCALHOST4:$port
nft_insert_rule dnat_pre iifname @lanif $filter ip daddr != @nozapret ip daddr != @ipban $FW_EXTRA_POST dnat ip to $TPWS_LOCALHOST4:$port nft_insert_rule dnat_pre iifname @lanif $mark_filter $filter ip daddr != @nozapret ip daddr != @ipban $FW_EXTRA_POST dnat ip to $TPWS_LOCALHOST4:$port
prepare_route_localnet prepare_route_localnet
} }
} }
@@ -418,10 +423,11 @@ _nft_fw_tpws6()
[ "$DISABLE_IPV6" = "1" -o -z "$1" ] || { [ "$DISABLE_IPV6" = "1" -o -z "$1" ] || {
local filter="$1" port="$2" DNAT6 i local filter="$1" port="$2" DNAT6 i
local mark_filter=$(nft_mark_filter)
nft_print_op "$filter" "tpws (port $port)" 6 nft_print_op "$filter" "tpws (port $port)" 6
nft_insert_rule dnat_output skuid != $WS_USER ${4:+oifname @wanif6 }$filter ip6 daddr != @nozapret6 ip6 daddr != @ipban6 $FW_EXTRA_POST dnat ip6 to [::1]:$port nft_insert_rule dnat_output skuid != $WS_USER ${4:+oifname @wanif6} $mark_filter $filter ip6 daddr != @nozapret6 ip6 daddr != @ipban6 $FW_EXTRA_POST dnat ip6 to [::1]:$port
[ -n "$3" ] && { [ -n "$3" ] && {
nft_insert_rule dnat_pre $filter ip6 daddr != @nozapret6 ip6 daddr != @ipban6 $FW_EXTRA_POST dnat ip6 to iifname map @link_local:$port nft_insert_rule dnat_pre $mark_filter $filter ip6 daddr != @nozapret6 ip6 daddr != @ipban6 $FW_EXTRA_POST dnat ip6 to iifname map @link_local:$port
for i in $3; do for i in $3; do
_dnat6_target $i DNAT6 _dnat6_target $i DNAT6
# can be multiple tpws processes on different ports # can be multiple tpws processes on different ports
@@ -468,7 +474,7 @@ _nft_fw_nfqws_post4()
[ "$DISABLE_IPV4" = "1" -o -z "$1" ] || { [ "$DISABLE_IPV4" = "1" -o -z "$1" ] || {
local filter="$1" port="$2" rule chain=$(get_postchain) setmark local filter="$1" port="$2" rule chain=$(get_postchain) setmark
nft_print_op "$filter" "nfqws postrouting (qnum $port)" 4 nft_print_op "$filter" "nfqws postrouting (qnum $port)" 4
rule="${3:+oifname @wanif }$filter ip daddr != @nozapret" rule="${3:+oifname @wanif} $(nft_mark_filter) $filter ip daddr != @nozapret"
is_postnat && setmark="meta mark set meta mark or $DESYNC_MARK_POSTNAT" is_postnat && setmark="meta mark set meta mark or $DESYNC_MARK_POSTNAT"
nft_insert_rule $chain $rule $setmark $CONNMARKER $FW_EXTRA_POST queue num $port bypass nft_insert_rule $chain $rule $setmark $CONNMARKER $FW_EXTRA_POST queue num $port bypass
nft_add_nfqws_flow_exempt_rule "$rule" nft_add_nfqws_flow_exempt_rule "$rule"
@@ -483,7 +489,7 @@ _nft_fw_nfqws_post6()
[ "$DISABLE_IPV6" = "1" -o -z "$1" ] || { [ "$DISABLE_IPV6" = "1" -o -z "$1" ] || {
local filter="$1" port="$2" rule chain=$(get_postchain) setmark local filter="$1" port="$2" rule chain=$(get_postchain) setmark
nft_print_op "$filter" "nfqws postrouting (qnum $port)" 6 nft_print_op "$filter" "nfqws postrouting (qnum $port)" 6
rule="${3:+oifname @wanif6 }$filter ip6 daddr != @nozapret6" rule="${3:+oifname @wanif6} $(nft_mark_filter) $filter ip6 daddr != @nozapret6"
is_postnat && setmark="meta mark set meta mark or $DESYNC_MARK_POSTNAT" is_postnat && setmark="meta mark set meta mark or $DESYNC_MARK_POSTNAT"
nft_insert_rule $chain $rule $setmark $CONNMARKER $FW_EXTRA_POST queue num $port bypass nft_insert_rule $chain $rule $setmark $CONNMARKER $FW_EXTRA_POST queue num $port bypass
nft_add_nfqws_flow_exempt_rule "$rule" nft_add_nfqws_flow_exempt_rule "$rule"
@@ -508,7 +514,7 @@ _nft_fw_nfqws_pre4()
[ "$DISABLE_IPV4" = "1" -o -z "$1" ] || { [ "$DISABLE_IPV4" = "1" -o -z "$1" ] || {
local filter="$1" port="$2" rule local filter="$1" port="$2" rule
nft_print_op "$filter" "nfqws prerouting (qnum $port)" 4 nft_print_op "$filter" "nfqws prerouting (qnum $port)" 4
rule="${3:+iifname @wanif }$filter ip saddr != @nozapret" rule="${3:+iifname @wanif} $filter ip saddr != @nozapret"
nft_insert_rule $(get_prechain) $rule $CONNMARKER $FW_EXTRA_POST queue num $port bypass nft_insert_rule $(get_prechain) $rule $CONNMARKER $FW_EXTRA_POST queue num $port bypass
} }
} }
@@ -521,7 +527,7 @@ _nft_fw_nfqws_pre6()
[ "$DISABLE_IPV6" = "1" -o -z "$1" ] || { [ "$DISABLE_IPV6" = "1" -o -z "$1" ] || {
local filter="$1" port="$2" rule local filter="$1" port="$2" rule
nft_print_op "$filter" "nfqws prerouting (qnum $port)" 6 nft_print_op "$filter" "nfqws prerouting (qnum $port)" 6
rule="${3:+iifname @wanif6 }$filter ip6 saddr != @nozapret6" rule="${3:+iifname @wanif6} $filter ip6 saddr != @nozapret6"
nft_insert_rule $(get_prechain) $rule $CONNMARKER $FW_EXTRA_POST queue num $port bypass nft_insert_rule $(get_prechain) $rule $CONNMARKER $FW_EXTRA_POST queue num $port bypass
} }
} }

View File

@@ -47,6 +47,12 @@ GZIP_LISTS=1
DESYNC_MARK=0x40000000 DESYNC_MARK=0x40000000
DESYNC_MARK_POSTNAT=0x20000000 DESYNC_MARK_POSTNAT=0x20000000
# do not pass outgoing traffic to tpws/nfqws not marked with this bit
# this setting allows to write your own rules to limit traffic that should be fooled
# for example based on source IP or incoming interface name
# no filter if not defined
#FILTER_MARK=0x10000000
TPWS_SOCKS_ENABLE=0 TPWS_SOCKS_ENABLE=0
# tpws socks listens on this port on localhost and LAN interfaces # tpws socks listens on this port on localhost and LAN interfaces
TPPORT_SOCKS=987 TPPORT_SOCKS=987

View File

@@ -312,7 +312,7 @@ In OpenBSD default `tpws` bind is ipv6 only. To bind to ipv4 specify
Use `--bind-addr=0.0.0.0 --bind-addr=::` to achieve the same default bind as in Use `--bind-addr=0.0.0.0 --bind-addr=::` to achieve the same default bind as in
others OSes. others OSes.
`tpws` for forwarded traffic only : `tpws` for forwarded traffic only (OLDER OS versions):
`/etc/pf.conf`: `/etc/pf.conf`:
``` ```
@@ -323,13 +323,31 @@ pass in quick on em1 inet6 proto tcp to port {80,443} rdr-to ::1 port 988
Then: Then:
``` ```
pfctl -f /etc/pf.conf pfctl -f /etc/pf.conf
tpws --port=988 --user=daemon --bind-addr=::1 --bind-addr=127.0.0.1 tpws --port=988 --user=daemon --bind-addr=::1 --bind-addr=127.0.0.1 --enable-pf
``` ```
Its not clear how to do rdr-to outgoing traffic. I could not make route-to Its not clear how to do rdr-to outgoing traffic. I could not make route-to
scheme work. rdr-to support is done using /dev/pf, that's why transparent mode scheme work. rdr-to support is done using /dev/pf, that's why transparent mode
requires root. requires root.
`tpws` for forwarded traffic only (NEWER OS versions):
```
pass on em1 inet proto tcp to port {80,443} divert-to 127.0.0.1 port 989
pass on em1 inet6 proto tcp to port {80,443} divert-to ::1 port 989
```
Then:
```
pfctl -f /etc/pf.conf
tpws --port=988 --user=daemon --bind-addr=::1 --bind-addr=127.0.0.1
```
tpws must be bound exactly to diverted IPs, not `0.0.0.0` or `::`.
It's also not clear how to divert connections from local system.
`dvtws` for all traffic: `dvtws` for all traffic:
`/etc/pf.conf`: `/etc/pf.conf`:

View File

@@ -19,7 +19,8 @@
* [pfsense](#pfsense) * [pfsense](#pfsense)
* [OpenBSD](#openbsd) * [OpenBSD](#openbsd)
* [tpws bind на ipv4](#tpws-bind-на-ipv4) * [tpws bind на ipv4](#tpws-bind-на-ipv4)
* [tpws для проходящего трафика](#tpws-для-проходящего-трафика) * [tpws для проходящего трафика (старые системы)](#tpws-для-проходящего-трафика-старая-схема-не-работает-в-новых-версиях))
* [tpws для проходящего трафика (новые системы)](#tpws-для-проходящего-трафика-новые-системы))
* [Запуск dvtws](#запуск-dvtws) * [Запуск dvtws](#запуск-dvtws)
* [Проблемы с badsum](#проблемы-с-badsum) * [Проблемы с badsum](#проблемы-с-badsum)
* [Особенность отправки fake пакетов](#особенность-отправки-fake-пакетов) * [Особенность отправки fake пакетов](#особенность-отправки-fake-пакетов)
@@ -392,7 +393,11 @@ rdr pass on em1 inet6 proto tcp from any to any port = https -> fe80::20c:29ff:5
Но лучше все же так не делать, а сажать на определенные внутренние адреса или интерфейсы. Но лучше все же так не делать, а сажать на определенные внутренние адреса или интерфейсы.
### tpws для проходящего трафика ### tpws для проходящего трафика (старая схема не работает в новых версиях)
В этом варианте tpws обращается явно к редиректору pf и пытается от него получить оригинальный адрес назначения.
Как показывает практика, это не работает на новых версиях OpenBSD. Возвращается ошибка ioctl.
Последняя проверенная версия, где это работает, - 6.8 . Между 6.8 и 7.4 разработчики сломали этот механизм.
`/etc/pf.conf`: `/etc/pf.conf`:
``` ```
@@ -402,15 +407,35 @@ pass in quick on em1 inet6 proto tcp to port {80,443} rdr-to ::1 port 988
```sh ```sh
$ pfctl -f /etc/pf.conf $ pfctl -f /etc/pf.conf
$ tpws --port=988 --user=daemon --bind-addr=::1 --bind-addr=127.0.0.1 $ tpws --port=988 --user=daemon --bind-addr=::1 --bind-addr=127.0.0.1 --enable-pf
``` ```
> [!NOTE] > [!NOTE]
> В PF не выходит делать rdr-to с той же системы, где работает proxy. > В PF не выходит делать rdr-to с той же системы, где работает proxy.
> Вариант с route-to не сохраняет мета информацию. Адрес назначения теряется. > Вариант с route-to не сохраняет мета информацию. Адрес назначения теряется.
> Поэтому этот вариант годится для squid, берущего адрес из протокола прикладного уровня, но не годится для tpws, полагающегося на метаданные ОС. > Поэтому этот вариант годится для squid, берущего адрес из протокола прикладного уровня, но не годится для tpws, полагающегося на метаданные ОС.
> Поддержка rdr-to реализована через `/dev/pf`, поэтому прозрачный режим **требует root**. > Поддержка rdr-to реализована через `/dev/pf`, поэтому прозрачный режим **требует root**.
### tpws для проходящего трафика (новые системы)
В новых версиях предлагается использовать divert-to вместо rdr-to.
Минимально проверенная версия, где это работает, 7.4. Может работать или не работать на более старых - исследование не проводилось.
`/etc/pf.conf`:
```
pass on em1 inet proto tcp to port {80,443} divert-to 127.0.0.1 port 989
pass on em1 inet6 proto tcp to port {80,443} divert-to ::1 port 989
```
tpws должен иметь бинд на точно такой адрес, который указан в правилах pf. `0.0.0.0` или `::` не работает.
```sh
$ pfctl -f /etc/pf.conf
$ tpws --port=988 --user=daemon --bind-addr=::1 --bind-addr=127.0.0.1
```
> [!NOTE]
> Так же не понятно как делать divert с самой системы, где работает tpws.
### Запуск dvtws ### Запуск dvtws

View File

@@ -56,14 +56,27 @@ sysctl net.inet6.ip6.forwarding=1
OpenBSD PF : OpenBSD PF :
(OLD OpenBSD versions)
; dont know how to rdr-to from local system. doesn't seem to work. only works for routed traffic. ; dont know how to rdr-to from local system. doesn't seem to work. only works for routed traffic.
/etc/pf.conf /etc/pf.conf
pass in quick on em1 inet proto tcp to port {80,443} rdr-to 127.0.0.1 port 988 pass in quick on em1 inet proto tcp to port {80,443} rdr-to 127.0.0.1 port 988
pass in quick on em1 inet6 proto tcp to port {80,443} rdr-to ::1 port 988 pass in quick on em1 inet6 proto tcp to port {80,443} rdr-to ::1 port 988
pfctl -f /etc/pf.conf pfctl -f /etc/pf.conf
/opt/zapret/tpws/tpws --port=988 --user=daemon --bind-addr=::1 --bind-addr=127.0.0.1 --enable-pf
(NEW OpenBSD versions)
; dont know how to divert-to from local system
/etc/pf.conf
pass on em1 inet proto tcp to port {80,443} divert-to 127.0.0.1 port 989
pass on em1 inet6 proto tcp to port {80,443} divert-to ::1 port 989
pfctl -f /etc/pf.conf
/opt/zapret/tpws/tpws --port=988 --user=daemon --bind-addr=::1 --bind-addr=127.0.0.1 /opt/zapret/tpws/tpws --port=988 --user=daemon --bind-addr=::1 --bind-addr=127.0.0.1
; dvtws works both for routed and local ; dvtws works both for routed and local
pass in quick on em0 proto tcp from port {80,443} flags SA/SA divert-packet port 989 no state pass in quick on em0 proto tcp from port {80,443} flags SA/SA divert-packet port 989 no state

View File

@@ -490,8 +490,51 @@ nfqws: --dup*
nfqws: --orig* nfqws: --orig*
nfqws: ipcache of hop count and host names nfqws: ipcache of hop count and host names
nfqws: --ctrack-disable nfqws: --ctrack-disable
nfqws: --synack-split
nfqws: --autottl=- or --autottl=0:0-0 disable autottl. previous "0" does not work anymore.
tpws: ipcache of host names tpws: ipcache of host names
nfqws,tpws: set 1024 repeat limit to fakes and dups nfqws,tpws: set 1024 repeat limit to fakes and dups
nfqws,tpws: do more before daemonize nfqws,tpws: do more before daemonize
nfqws,tpws: accept multiple gids in --gid
nfqws,tpws: display "android" in version string if built for android
init.d: remove --ipset parameter prohibition init.d: remove --ipset parameter prohibition
init.d, blockcheck: drop time exceeded icmp for nfqws-related connections init.d, blockcheck: drop time exceeded icmp for nfqws-related connections
blockcheck: some dup and orig-ttl mods
blockcheck: PKTWS_EXTRA_PRE
blockcheck: report test function and domain every test
v71.1
nfqws,tpws: much faster ipset implementation. move from hash to avl tree
nfqws,tpws: check list files accessibility with dropped privs in --dry-run mode
nfqws,tpws: --debug=android for NDK builds
nfqws,tpws: use initgroups instead of setgroups if --user specified
nfqws: --filter-ssid (linux-only)
install_easy: stop if running embedded release on traditional linux system (some files missing)
install_bin: add "read elf" arch detection method
binaries: renamed arch dirs in binaries
v71.1.1
nfqws: use wireless ext in case nl80211 does not return SSID
v71.2
nfqws: apply udp desync to replayed packets with non-zero reasm offset (except fake)
blockcheck: display curl version and kernel version
install_bin: stop if no binaries found. display help text.
winws: increase buffers for port filter
tpws: tpws no more opens /dev/pf in OpenBSD by default. requires --enable-pf like in FreeBSD. this is migration from rdr-to to divert-to redirection scheme.
install_easy: warn if --ipset parameter is specified
v71.3
init.d: FILTER_MARK
nfqws: ts fooling
blockcheck: test ts fooling
blockcheck: auto enable tcp timestamps in windows
tpws,nfqws: special handling of IP-like hostnames. strip :port from hostname:port
v71.4
nfqws,tpws: fix possible crashes or high memory usage if hostlist has duplicate hostnames

View File

@@ -1,6 +1,6 @@
debian,ubuntu : debian,ubuntu :
apt install make gcc zlib1g-dev libcap-dev libnetfilter-queue-dev libsystemd-dev apt install make gcc zlib1g-dev libcap-dev libnetfilter-queue-dev libmnl-dev libsystemd-dev
make -C /opt/zapret systemd make -C /opt/zapret systemd
FreeBSD : FreeBSD :

View File

@@ -12,7 +12,7 @@ define Package/nfqws
CATEGORY:=Network CATEGORY:=Network
TITLE:=nfqws TITLE:=nfqws
SUBMENU:=Zapret SUBMENU:=Zapret
DEPENDS:=+libnetfilter-queue +libcap +zlib DEPENDS:=+libnetfilter-queue +lmnl +libcap +zlib
endef endef
define Build/Prepare define Build/Prepare

View File

@@ -1,9 +1,10 @@
# zapret v70.7 # zapret v71.3
# SCAMMER WARNING # SCAMMER WARNING
This software is free and open source under [MIT license](./LICENSE.txt). This software is free and open source under [MIT license](./LICENSE.txt).
If anyone demands you to download this software only from their webpage, telegram channel, forces you to delete links, videos, makes copyright claims, you are dealing with scammers. If anyone demands you to download this software only from their webpage, telegram channel, forces you to delete links, videos, makes copyright claims, you are dealing with scammers.
However, [donations](#donations) are welcome.
# Multilanguage/Мультиязычный README # Multilanguage/Мультиязычный README
___ ___
@@ -23,17 +24,23 @@ ___
- [TCP segmentation](#tcp-segmentation) - [TCP segmentation](#tcp-segmentation)
- [Sequence numbers overlap](#sequence-numbers-overlap) - [Sequence numbers overlap](#sequence-numbers-overlap)
- [ipv6 specific modes](#ipv6-specific-modes) - [ipv6 specific modes](#ipv6-specific-modes)
- [Original modding](#original-modding)
- [Duplicates](#duplicates)
- [Server reply reaction](#server-reply-reaction) - [Server reply reaction](#server-reply-reaction)
- [SYNDATA mode](#syndata-mode) - [SYNDATA mode](#syndata-mode)
- [DPI desync combos](#dpi-desync-combos) - [DPI desync combos](#dpi-desync-combos)
- [IP cache](#ip-cache)
- [CONNTRACK](#conntrack) - [CONNTRACK](#conntrack)
- [Reassemble](#reassemble) - [Reassemble](#reassemble)
- [UDP support](#udp-support) - [UDP support](#udp-support)
- [IP fragmentation](#ip-fragmentation) - [IP fragmentation](#ip-fragmentation)
- [Multiple strategies](#multiple-strategies) - [Multiple strategies](#multiple-strategies)
- [WIFI filtering](#wifi-filtering)
- [Virtual machines](#virtual-machines) - [Virtual machines](#virtual-machines)
- [IPTABLES for nfqws](#iptables-for-nfqws) - [IPTABLES for nfqws](#iptables-for-nfqws)
- [NFTABLES for nfqws](#nftables-for-nfqws) - [NFTABLES for nfqws](#nftables-for-nfqws)
- [Flow offloading](#flow-offloading)
- [Server side fooling](#server-side-fooling)
- [tpws](#tpws) - [tpws](#tpws)
- [TCP segmentation in tpws](#tcp-segmentation-in-tpws) - [TCP segmentation in tpws](#tcp-segmentation-in-tpws)
- [TLSREC](#tlsrec) - [TLSREC](#tlsrec)
@@ -139,24 +146,46 @@ nfqws takes the following parameters:
--daemon ; daemonize --daemon ; daemonize
--pidfile=<filename> ; write pid to file --pidfile=<filename> ; write pid to file
--user=<username> ; drop root privs --user=<username> ; drop root privs
--uid=uid[:gid] ; drop root privs --uid=uid[:gid1,gid2,...] ; drop root privs
--bind-fix4 ; apply outgoing interface selection fix for generated ipv4 packets --bind-fix4 ; apply outgoing interface selection fix for generated ipv4 packets
--bind-fix6 ; apply outgoing interface selection fix for generated ipv6 packets --bind-fix6 ; apply outgoing interface selection fix for generated ipv6 packets
--wsize=<window_size>[:<scale_factor>] ; set window size. 0 = do not modify. OBSOLETE ! --wsize=<window_size>[:<scale_factor>] ; set window size. 0 = do not modify. OBSOLETE !
--wssize=<window_size>[:<scale_factor>] ; set window size for server. 0 = do not modify. default scale_factor = 0. --wssize=<window_size>[:<scale_factor>] ; set window size for server. 0 = do not modify. default scale_factor = 0.
--wssize-cutoff=[n|d|s]N ; apply server wsize only to packet numbers (n, default), data packet numbers (d), relative sequence (s) less than N --wssize-cutoff=[n|d|s]N ; apply server wsize only to packet numbers (n, default), data packet numbers (d), relative sequence (s) less than N
--ctrack-timeouts=S:E:F[:U] ; internal conntrack timeouts for TCP SYN, ESTABLISHED, FIN stages, UDP timeout. default 60:300:60:60 --ctrack-timeouts=S:E:F[:U] ; internal conntrack timeouts for TCP SYN, ESTABLISHED, FIN stages, UDP timeout. default 60:300:60:60
--ctrack-disable=[0|1] ; 1 or no argument disables conntrack
--ipcache-lifetime=<int> ; time in seconds to keep cached hop count and domain name (default 7200). 0 = no expiration
--ipcache-hostname=[0|1] ; 1 or no argument enables ip->hostname caching
--hostcase ; change Host: => host: --hostcase ; change Host: => host:
--hostspell ; exact spelling of "Host" header. must be 4 chars. default is "host" --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 --hostnospace ; remove space after Host: and add it to User-Agent: to preserve packet size
--domcase ; mix domain case : Host: TeSt.cOm --domcase ; mix domain case : Host: TeSt.cOm
--methodeol ; add '\n' before method and remove space after Host: --methodeol ; add '\n' before method and remove space after Host:
--synack-split=[syn|synack|acksyn] ; perform TCP split handshake : send SYN only, SYN+ACK or ACK+SYN
--orig-ttl=<int> ; set TTL for original packets
--orig-ttl6=<int> ; set ipv6 hop limit for original packets. by default ttl value is used
--orig-autottl=[<delta>[:<min>[-<max>]]|-] ; auto ttl mode for both ipv4 and ipv6. default: +5:3-64. "0:0-0" or "-" disables autottl.
--orig-autottl6=[<delta>[:<min>[-<max>]]|-] ; overrides --orig-autottl for ipv6 only
--orig-mod-start=[n|d|s]N ; apply orig TTL mod to packet numbers (n, default), data packet numbers (d), relative sequence (s) greater or equal than N
--orig-mod-cutoff=[n|d|s]N ; apply orig TTL mod to packet numbers (n, default), data packet numbers (d), relative sequence (s) less than N
--dup=<int> ; duplicate original packets. send N dups before original.
--dup-replace=[0|1] ; 1 or no argument means do not send original, only dups
--dup-ttl=<int> ; set TTL for dups
--dup-ttl6=<int> ; set ipv6 hop limit for dups. by default ttl value is used
--dup-autottl=[<delta>[:<min>[-<max>]]|-] ; auto ttl mode for both ipv4 and ipv6. default: -1:3-64. "0:0-0" or "-" disables autottl.
--dup-autottl6=[<delta>[:<min>[-<max>]]|-] ; overrides --dup-autottl for ipv6 only
--dup-fooling=<mode>[,<mode>] ; can use multiple comma separated values. modes : none md5sig badseq badsum datanoack hopbyhop hopbyhop2
--dup-ts-increment=<int|0xHEX> ; ts fooling TSval signed increment for dup. default -600000
--dup-badseq-increment=<int|0xHEX> ; badseq fooling seq signed increment for dup. default -10000
--dup-badack-increment=<int|0xHEX> ; badseq fooling ackseq signed increment for dup. default -66000
--dup-start=[n|d|s]N ; apply dup to packet numbers (n, default), data packet numbers (d), relative sequence (s) greater or equal than N
--dup-cutoff=[n|d|s]N ; apply dup to packet numbers (n, default), data packet numbers (d), relative sequence (s) less than N
--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=[<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-fwmark=<int|0xHEX> ; override fwmark for desync packet. default = 0x40000000 (1073741824)
--dpi-desync-ttl=<int> ; set ttl for desync packet --dpi-desync-ttl=<int> ; set ttl for desync packet
--dpi-desync-ttl6=<int> ; set ipv6 hop limit for desync packet. by default ttl value is used. --dpi-desync-ttl6=<int> ; set ipv6 hop limit for desync packet. by default ttl value is used.
--dpi-desync-autottl=[<delta>[:<min>[-<max>]]] ; auto ttl mode for both ipv4 and ipv6. default: 1:3-20 --dpi-desync-autottl=[<delta>[:<min>[-<max>]]|-] ; auto ttl mode for both ipv4 and ipv6. default: -1:3-20. "0:0-0" or "-" disables autottl.
--dpi-desync-autottl6=[<delta>[:<min>[-<max>]]] ; overrides --dpi-desync-autottl for ipv6 only --dpi-desync-autottl6=[<delta>[:<min>[-<max>]]|-] ; overrides --dpi-desync-autottl for ipv6 only
--dpi-desync-fooling=<mode>[,<mode>] ; can use multiple comma separated values. modes : none md5sig ts badseq badsum datanoack hopbyhop hopbyhop2 --dpi-desync-fooling=<mode>[,<mode>] ; can use multiple comma separated values. modes : none md5sig ts badseq badsum datanoack hopbyhop hopbyhop2
--dpi-desync-repeats=<N> ; send every desync packet N times --dpi-desync-repeats=<N> ; send every desync packet N times
--dpi-desync-skip-nosni=0|1 ; 1(default)=do not act on ClientHello without SNI (ESNI ?) --dpi-desync-skip-nosni=0|1 ; 1(default)=do not act on ClientHello without SNI (ESNI ?)
@@ -169,6 +198,7 @@ nfqws takes the following parameters:
--dpi-desync-fakedsplit-pattern=<filename>|0xHEX ; fake pattern for fakedsplit/fakeddisorder --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-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-ipfrag-pos-udp=<8..9216> ; ip frag position starting from the transport header. multiple of 8, default 32.
--dpi-desync-ts-increment=<int|0xHEX> ; ts fooling TSval signed increment. default -600000
--dpi-desync-badseq-increment=<int|0xHEX> ; badseq fooling seq signed increment. default -10000 --dpi-desync-badseq-increment=<int|0xHEX> ; badseq fooling seq signed increment. default -10000
--dpi-desync-badack-increment=<int|0xHEX> ; badseq fooling ackseq signed increment. default -66000 --dpi-desync-badack-increment=<int|0xHEX> ; badseq fooling ackseq signed increment. default -66000
--dpi-desync-any-protocol=0|1 ; 0(default)=desync only http and tls 1=desync any nonempty data packet --dpi-desync-any-protocol=0|1 ; 0(default)=desync only http and tls 1=desync any nonempty data packet
@@ -202,6 +232,7 @@ nfqws takes the following parameters:
--filter-tcp=[~]port1[-port2]|* ; TCP port filter. ~ means negation. setting tcp and not setting udp filter denies udp. comma separated list supported. --filter-tcp=[~]port1[-port2]|* ; TCP port filter. ~ means negation. setting tcp and not setting udp filter denies udp. comma separated list supported.
--filter-udp=[~]port1[-port2]|* ; UDP port filter. ~ means negation. setting udp and not setting tcp filter denies tcp. comma separated list supported. --filter-udp=[~]port1[-port2]|* ; UDP port filter. ~ means negation. setting udp and not setting tcp filter denies tcp. comma separated list supported.
--filter-l7=<proto> ; L6-L7 protocol filter. multiple comma separated values allowed. proto: http tls quic wireguard dht discord stun unknown --filter-l7=<proto> ; L6-L7 protocol filter. multiple comma separated values allowed. proto: http tls quic wireguard dht discord stun unknown
--filter-ssid=ssid1[,ssid2,ssid3,...] ; per profile wifi SSID filter
--ipset=<filename> ; ipset include filter (one ip/CIDR per line, ipv4 and ipv6 accepted, gzip supported, multiple ipsets allowed) --ipset=<filename> ; ipset include filter (one ip/CIDR per line, ipv4 and ipv6 accepted, gzip supported, multiple ipsets allowed)
--ipset-ip=<ip_list> ; comma separated fixed subnet list --ipset-ip=<ip_list> ; comma separated fixed subnet list
--ipset-exclude=<filename> ; ipset exclude filter (one ip/CIDR per line, ipv4 and ipv6 accepted, gzip supported, multiple ipsets allowed) --ipset-exclude=<filename> ; ipset exclude filter (one ip/CIDR per line, ipv4 and ipv6 accepted, gzip supported, multiple ipsets allowed)
@@ -257,10 +288,19 @@ Fakes are separate generated by nfqws packets carrying false information for DPI
* **datanoack** sends tcp fakes without ACK flag. Servers do not accept this but DPI may accept. * **datanoack** sends tcp fakes without ACK flag. Servers do not accept this but DPI may accept.
This mode may break NAT and may not work with iptables if masquerade is used, even from the router itself. This mode may break NAT and may not work with iptables if masquerade is used, even from the router itself.
Works with nftables properly. Likely requires external IP address (some ISPs pass these packets through their NAT). Works with nftables properly. Likely requires external IP address (some ISPs pass these packets through their NAT).
* **autottl** tries to automatically guess TTL value that allows DPI to receive fakes and does not allow them to reach the server. * **ts** adds to TSval ts increment value (-600000 by default). Servers discard packets with TSval in some range.
This tech relies on well known TTL values used by OS : 64,128,255. nfqws takes first incoming packet (YES, you need to redirect it too), Practical tests suggest increment between -100 and -0x80000000.
guesses path length and decreases by `delta` value (default 1). If resulting value is outside the range (min,max - default 3,20) Timestamps are generated by client OS. In linux timestamps are enabled by default. In windows by default timestamps are disabled.
then its normalized to min or max. If the path shorter than the value then autottl fails and falls back to the fixed value. They can be enabled with this command : `netsh interface tcp set global timestamps=enabled` .
ts fooling requires that timestamps are enabled. They must be enabled on every client OS.
TSecr is left unmodified.
* **autottl** tries to automatically guess hop count to the server and compute TTL by adding some delta value that can be positive or negative.
Positive deltas must be preceeded by unary `+` sign. Deltas without any unary sign are treated negative for old versions compatibility reasons.
This tech relies on well known TTL default values used by OS : 64,128,255.
nfqws needs first incoming packet to see it's TTL. You must redirect it too.
If resulting value TTL is outside the range (min,max) then its normalized to min or max.
If delta is negative and TTL is longer than guessed hop count or delta is positive and TTL is shorter than guessed hop count
then autottl fails and falls back to the fixed value.
This can help if multiple DPIs exists on backbone channels, not just near the ISP. This can help if multiple DPIs exists on backbone channels, not just near the ISP.
Can fail if inbound and outbound paths are not symmetric. Can fail if inbound and outbound paths are not symmetric.
@@ -356,6 +396,44 @@ For example, `hopbyhop,multisplit` means split original tcp packet into several
With `hopbyhop,ipfrag2` header sequence will be : `ipv6,hop-by-hop,fragment,tcp/udp`. With `hopbyhop,ipfrag2` header sequence will be : `ipv6,hop-by-hop,fragment,tcp/udp`.
`ipfrag1` mode may not always work without special preparations. See "IP Fragmentation" notices. `ipfrag1` mode may not always work without special preparations. See "IP Fragmentation" notices.
### Original modding
Parameters `--orig-ttl` and `--orig-ttl6` allow to set TTL on original packets.
All further packet manipulations, e.g. segmentation, take modded original as data source and inherit modded TTL.
`--orig-autottl` and `--orig-autottl6` work the same way as `dpi-desync-autottl`, but on original packets.
Delta should have unary `+` sign to produce TTL longer than guessed hop count. Otherwise nothing will reach the server.
Example : `--orig-autottl=+5:3-64`.
`--orig-mod-start` and `--orig-mod-cutoff` specify start and end conditions for original modding. The work the same way as
`--dpi-desync-start` and `--dpi-desync-cutoff`.
This function can be useful when DPI hunts for fakes and blocks suspicious connections.
DPI can compute TTL difference between packets and fire block trigger if it exceedes some threshold.
### Duplicates
Duplicates are copies of original packets which are sent before them. Duplicates are enabled by `--dup=N`, where N is dup count.
`--dup-replace` disables sending of original.
Dups are sent only when original would also be sent without reconstruction.
For example, if TCP segmentation happens, original is actually dropped and is being replaced by artificially constructed new packets.
Dups are not sent in this case.
All dup fooling modes are available : `--dup-ttl`. `--dup-ttl6`, `--dup-fooling`.
You decide whether these packets need to reach the server and in what form, according to the intended strategy.
`--dup-autottl` and `--dup-autottl6` work the same way as `dpi-desync-autottl`.
Delta can be preceeded by unary `+` or `-` sign.
Example : `--dup-autottl=-2:3-64`.
`--dup-start` and `--dup-cutoff` specify start and end conditions for dupping. The work the same way as
`--dpi-desync-start` and `--dpi-desync-cutoff`.
This function can help if DPI compares some characteristics of fake and original packets and block connection if they differ some way.
Fooled duplicates can convince DPI that the whole session has an anomaly.
For example, all connection is protected by MD5 signature, not individual packets.
### Server reply reaction ### Server reply reaction
There are DPIs that analyze responses from the server, particularly the certificate from the ServerHello that contain domain name(s). The ClientHello delivery confirmation is an ACK packet from the server with ACK sequence number corresponding to the length of the ClientHello+1. There are DPIs that analyze responses from the server, particularly the certificate from the ServerHello that contain domain name(s). The ClientHello delivery confirmation is an ACK packet from the server with ACK sequence number corresponding to the length of the ClientHello+1.
@@ -377,12 +455,26 @@ Without extra parameter payload is 16 zero bytes.
`--dpi-desync` takes up to 3 comma separated modes. `--dpi-desync` takes up to 3 comma separated modes.
* 0 phase modes work during the connection establishement : `synack`, `syndata` `--wsize`, `--wssize`. [hostlist](((#multiple-strategies))) filters are not applicable. * 0 phase modes work during the connection establishement : `synack`, `syndata` `--wsize`, `--wssize`. [hostlist](#multiple-strategies) filters are applicable only if [`--ipcache-hostname`](#ip-cache) is enabled.
* In the 1st phase fakes are sent before original data : `fake`, `rst`, `rstack`. * In the 1st phase fakes are sent before original data : `fake`, `rst`, `rstack`.
* In the 2nd phase original data is sent in a modified way (for example `fakedsplit` or `ipfrag2`). * In the 2nd phase original data is sent in a modified way (for example `fakedsplit` or `ipfrag2`).
Modes must be specified in phase ascending order. Modes must be specified in phase ascending order.
### IP cache
`ipcache` is the structure in the process memory that stores some information by IP address and interface name key.
This information can be used as missing data. Currently it's used in the following cases :
1. IP,interface => hop count . This is used to apply autottl at 0 phase since the first session packet. If the record is absent autottl will not be applied immediately. Second time it will be applied immediately using cached hop count.
2. IP => hostname . Hostname is cached to be used in 0 phase strategies. Mode is disabled by default and can be enabled by `ipcache-hostname` parameter.
This tech is experimental. There's no one-to-one correspondence between IP and domain name. Multiple domains can resolve to the same IP.
If collision happens hostname is replaced. On CDNs a domain can resolve to different IPs over time. `--ipcache-lifetime` limits how long cached record is valid. It's 2 hours by default.
Be prepared for unexpected results that can be explained only by reading debug logs.
SIGUSR2 forces process to output it's ipcache to stdout.
### CONNTRACK ### CONNTRACK
nfqws is equipped with minimalistic connection tracking system (conntrack) nfqws is equipped with minimalistic connection tracking system (conntrack)
@@ -472,9 +564,9 @@ There is special support for all tcp split options for multi segment TLS. Split
### UDP support ### UDP support
UDP attacks are limited. Its not possible to fragment UDP on transport level, only on network (ip) level. UDP attacks are limited. Its not possible to fragment UDP on transport level, only on network (ip) level.
Only desync modes `fake`,`hopbyhop`,`destopt`,`ipfrag1` and `ipfrag2` are applicable. Only desync modes `fake`,`fakeknown`,`hopbyhop`,`destopt`,`ipfrag1`,`ipfrag2`,`udplen` and `tamper` are applicable.
`fake`,`hopbyhop`,`destopt` can be used in combo with `ipfrag2`. `fake`,`fakeknown`,`hopbyhop`,`destopt`,`ipfrag1` are 1st phase modes, others - 2nd phase.
`fake` can be used in combo with `udplen` and `tamper`. As always it's possible to combine one mode from 1st phase with one mode from 2nd phase but not possible to mix same phase modes.
`udplen` increases udp payload size by `--dpi-desync-udplen-increment` bytes. Padding is filled with zeroes by default but can be overriden with a pattern. `udplen` increases udp payload size by `--dpi-desync-udplen-increment` bytes. Padding is filled with zeroes by default but can be overriden with a pattern.
This option can resist DPIs that track outgoing UDP packet sizes. This option can resist DPIs that track outgoing UDP packet sizes.
@@ -577,6 +669,30 @@ This way you may never unblock all resources and only confuse yourself.
IMPORTANT : user-mode ipset implementation was not designed as a kernel version replacement. Kernel version is much more effective. IMPORTANT : user-mode ipset implementation was not designed as a kernel version replacement. Kernel version is much more effective.
It's for the systems that lack ipset support : Windows and Linux without nftables and ipset kernel modules (Android, for example). It's for the systems that lack ipset support : Windows and Linux without nftables and ipset kernel modules (Android, for example).
### WIFI filtering
Wifi interface name is not related to connected SSID.
It's possible to connect interface to different SSIDs.
They may require different strategies. How to solve this problem ?
You can run and stop nfqws instances manually. But you can also automate this.
Windows version `winws` has global filter `--ssid-filter`.
It connects or disconnects `winws` depending on connected SSIDs.
Routing is not take into account. This approach is possible because windivert can have multiple handlers with intersecting filter.
If SSID changes one `winws` connects and others disconnect.
`winws` solution is hard to implement in Linux because one nfqueue can have only one handler and it's impossible to pass same traffic to multiple queues.
One must connect when others have already disconnected.
Instead, `nfqws` has per-profile `--filter-ssid` parameter. Like `--ssid-filter` it takes comma separated SSID list.
`nfqws` maintains ifname->SSID list which is updated not faster than once a second.
When a packet comes incoming or outgoing interface name is matched to the SSID and then used in profile selection algorithm.
SSID info is taken the same way as `iw dev <ifname> info` does (nl80211).
Unfortunately it's broken since kernel 5.19 and still unfixed in 6.14.
In the latter case `iwgetid` way is used (wireless extensions).
Wireless extensions are deprecated. Some kernels can be built without wext support.
Before using `--filter-ssid` check that any of the mentioned commands can return SSID.
### Virtual machines ### Virtual machines
Most of nfqws packet magic does not work from VMs powered by virtualbox and vmware when network is NATed. Most of nfqws packet magic does not work from VMs powered by virtualbox and vmware when network is NATed.
@@ -669,6 +785,31 @@ In `iptables` flow offloading is controlled by openwrt proprietary extension `FL
Flow offloading does not interfere with **tpws** and `OUTPUT` traffic. It only breaks nfqws that fools `FORWARD` traffic. Flow offloading does not interfere with **tpws** and `OUTPUT` traffic. It only breaks nfqws that fools `FORWARD` traffic.
### Server side fooling
It's also possible.
nfqws is intended for client side attacks. That's why it recognizes direct and reply traffic based on role in connection establishement.
If it sees SYN then source IP is client IP. If it sees SYN,ACK then source ip is server IP.
For UDP client address is considered as source IP of the first seen packet of src_ip,src_port,dst_ip,dst_port tuple.
This does not work correctly on the server side. Client traffic is reply traffic, server traffic is direct traffic.
`--wsize` works in any case. It can be used on both client and server.
Other techs work only if nfqws treats traffic as direct traffic.
To apply them to server originated traffic disable conntrack by `--ctrack-disable` parameter.
If a packet is not found in conntrack it's treated as direct and techs like `multidisorder` will be applied.
Most of the protocols will not be recognized because protocol recognition system only reacts to client packets.
To make things working use `--dpi-desync-any-protocol` with connbytes or packet payload limiter.
start/cutoff are unavailable because they are conntrack based.
`--synack-split` removes standard SYN,ACK packet and replaces it with one SYN packet, SYN then ACK separate packets or ACK then SYN separate packets.
Client sends SYN,ACK in reply which usually only server does.
This makes some DPI's to treat connection establishement roles wrong. They stop to block.
See [split handshake](https://nmap.org/misc/split-handshake.pdf).
On server side traffic should be redirected to nfqws using source port numbers and original connbytes direction.
## tpws ## tpws
@@ -705,6 +846,8 @@ tpws is transparent proxy.
--local-tcp-user-timeout=<seconds> ; set tcp user timeout for local leg (default : 10, 0 = system default) --local-tcp-user-timeout=<seconds> ; set tcp user timeout for local leg (default : 10, 0 = system default)
--remote-tcp-user-timeout=<seconds> ; set tcp user timeout for remote leg (default : 20, 0 = system default) --remote-tcp-user-timeout=<seconds> ; set tcp user timeout for remote leg (default : 20, 0 = system default)
--fix-seg=<int> ; recover failed TCP segmentation at the cost of slowdown. wait up to N msec. --fix-seg=<int> ; recover failed TCP segmentation at the cost of slowdown. wait up to N msec.
--ipcache-lifetime=<int> ; time in seconds to keep cached domain name (default 7200). 0 = no expiration
--ipcache-hostname=[0|1] ; 1 or no argument enables ip->hostname caching
--no-resolve ; disable socks5 remote dns --no-resolve ; disable socks5 remote dns
--resolver-threads=<int> ; number of resolver worker threads --resolver-threads=<int> ; number of resolver worker threads
--maxconn=<max_connections> ; max number of local legs --maxconn=<max_connections> ; max number of local legs
@@ -755,7 +898,7 @@ tpws is transparent proxy.
--daemon ; daemonize --daemon ; daemonize
--pidfile=<filename> ; write pid to file --pidfile=<filename> ; write pid to file
--user=<username> ; drop root privs --user=<username> ; drop root privs
--uid=uid[:gid] ; drop root privs --uid=uid[:gid1,gid2,...] ; drop root privs
``` ```
### TCP segmentation in tpws ### TCP segmentation in tpws
@@ -789,7 +932,7 @@ If you're attempting to split massive transmission with `--split-any-protocol` o
`--mss` sets TCP_MAXSEG socket option. Client sets this value in MSS TCP option in the SYN packet. `--mss` sets TCP_MAXSEG socket option. Client sets this value in MSS TCP option in the SYN packet.
Server replies with it's own MSS in SYN,ACK packet. Usually servers lower their packet sizes but they still don't fit to supplied MSS. The greater MSS client sets the bigger server's packets will be. Server replies with it's own MSS in SYN,ACK packet. Usually servers lower their packet sizes but they still don't fit to supplied MSS. The greater MSS client sets the bigger server's packets will be.
If it's enough to split TLS 1.2 ServerHello, it may fool DPI that checks certificate domain name. If it's enough to split TLS 1.2 ServerHello, it may fool DPI that checks certificate domain name.
This scheme may significantly lower speed. Hostlist filter is possible only in socks mode if client uses remote resolving (firefox `network.proxy.socks_remote_dns`). This scheme may significantly lower speed. Hostlist filter is possible only in socks mode if client uses remote resolving (firefox `network.proxy.socks_remote_dns`) or if `ipcache-hostname` is enabled.
`--mss` is not required for TLS1.3. If TLS1.3 is negotiable then MSS make things only worse. Use only if nothing better is available. Works only in Linux, not BSD or MacOS. `--mss` is not required for TLS1.3. If TLS1.3 is negotiable then MSS make things only worse. Use only if nothing better is available. Works only in Linux, not BSD or MacOS.
### Other tamper options ### Other tamper options
@@ -1090,6 +1233,23 @@ Don't use `<HOSTLIST>` in highly specialized profiles. Use your own filter or ho
`<HOSTLIST_NOAUTO>` marker uses standard autohostlist as usual hostlist thus disabling auto additions in this profile. `<HOSTLIST_NOAUTO>` marker uses standard autohostlist as usual hostlist thus disabling auto additions in this profile.
If any other profile adds something this profile accepts the change automatically. If any other profile adds something this profile accepts the change automatically.
Change loop prevention mark bit
`DESYNC_MARK=0x40000000`
Change postnat scheme mark bit
`DESYNC_MARK_POSTNAT=0x20000000`
If uncommented pass to zapret only packets marked with this bit
`#FILTER_MARK_POSTNAT=0x10000000`
Bit must be set in your own rules.
* iptables - in mangle PREROUTING and mangle OUTPUT before zapret rules (iptables -I _after_ zapret rules application).
* nftables - in output and prerouting hooks with priority -102 or lower.
Mark criterias can be any. For example, source IP or source interface name.
**tpws** socks proxy mode switch **tpws** socks proxy mode switch
@@ -1270,6 +1430,10 @@ With other values or if the parameter is commented out, the rules will not be ap
This is useful if you have a firewall management system, in the settings of which you should tie the rules. This is useful if you have a firewall management system, in the settings of which you should tie the rules.
Not applicable to `OpenWRT` if used with `firewall3+iptables`. Not applicable to `OpenWRT` if used with `firewall3+iptables`.
`FILTER_TTL_EXPIRED_ICMP=1` blocks icmp time exceeded messages in response to connections handled by nfqws.
Linux closes socket if it receives this icmp in response to SYN packet. Similar mechanism exists for datagram sockets.
It's better to disable this if you do not expect problems caused by icmp.
The following settings are not relevant for openwrt : The following settings are not relevant for openwrt :
If your system works as a router, then you need to enter the names of the internal and external interfaces: If your system works as a router, then you need to enter the names of the internal and external interfaces:

View File

@@ -1,9 +1,10 @@
# zapret v71 # zapret v71.3
# ВНИМАНИЕ, остерегайтесь мошенников # ВНИМАНИЕ, остерегайтесь мошенников
zapret является свободным и open source. zapret является свободным и open source.
Всякий, кто понуждает вас скачивать zapret только с его ресурса, требует удалить ссылки, видео, файлы, обосновывая эти требования авторскими правами, сам нарушает [лицензию](./LICENSE.txt). Всякий, кто понуждает вас скачивать zapret только с его ресурса, требует удалить ссылки, видео, файлы, обосновывая эти требования авторскими правами, сам нарушает [лицензию](./LICENSE.txt).
Однако, это не исключает [добровольные пожертвования](#поддержать-разработчика).
# Multilanguage README # Multilanguage README
@@ -38,9 +39,11 @@ zapret является свободным и open source.
- [ПОДДЕРЖКА UDP](#поддержка-udp) - [ПОДДЕРЖКА UDP](#поддержка-udp)
- [IP ФРАГМЕНТАЦИЯ](#ip-фрагментация) - [IP ФРАГМЕНТАЦИЯ](#ip-фрагментация)
- [МНОЖЕСТВЕННЫЕ СТРАТЕГИИ](#множественные-стратегии) - [МНОЖЕСТВЕННЫЕ СТРАТЕГИИ](#множественные-стратегии)
- [ФИЛЬТРАЦИЯ ПО WIFI](#фильтрация-по-wifi)
- [IPTABLES ДЛЯ NFQWS](#iptables-для-nfqws) - [IPTABLES ДЛЯ NFQWS](#iptables-для-nfqws)
- [NFTABLES ДЛЯ NFQWS](#nftables-для-nfqws) - [NFTABLES ДЛЯ NFQWS](#nftables-для-nfqws)
- [FLOW OFFLOADING](#flow-offloading) - [FLOW OFFLOADING](#flow-offloading)
- [ДУРЕНИЕ СО СТОРОНЫ СЕРВЕРА](#дурение-со-стороны-сервера)
- [tpws](#tpws) - [tpws](#tpws)
- [TCP СЕГМЕНТАЦИЯ В TPWS](#tcp-сегментация-в-tpws) - [TCP СЕГМЕНТАЦИЯ В TPWS](#tcp-сегментация-в-tpws)
- [TLSREC](#tlsrec) - [TLSREC](#tlsrec)
@@ -179,19 +182,21 @@ dvtws, собираемый из тех же исходников (см. [док
--wsize=<winsize>[:<scale_factor>] ; менять tcp window size на указанный размер в SYN,ACK. если не задан scale_factor, то он не меняется (устарело !) --wsize=<winsize>[:<scale_factor>] ; менять tcp window size на указанный размер в SYN,ACK. если не задан scale_factor, то он не меняется (устарело !)
--wssize=<winsize>[:<scale_factor>] ; менять tcp window size на указанный размер в исходящих пакетах. scale_factor по умолчанию 0. (см. conntrack !) --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 --wssize-cutoff=[n|d|s]N ; изменять server window size в исходящих пакетах (n), пакетах данных (d), относительных sequence (s) по номеру меньше N
--synack-split=[syn|synack|acksyn] ; выполнить tcp split handshake. вместо SYN,ACK отсылать только SYN, SYN+ACK или ACK+SYN
--orig-ttl=<int> ; модифицировать TTL оригинального пакета --orig-ttl=<int> ; модифицировать TTL оригинального пакета
--orig-ttl6=<int> ; модифицировать ipv6 hop limit оригинальных пакетов. если не указано, используется значение --orig-ttl --orig-ttl6=<int> ; модифицировать ipv6 hop limit оригинальных пакетов. если не указано, используется значение --orig-ttl
--orig-autottl=[<delta>[:<min>[-<max>]]] ; режим auto ttl для ipv4 и ipv6. по умолчанию: +5:3-64. delta=0 отключает функцию --orig-autottl=[<delta>[:<min>[-<max>]]|-] ; режим auto ttl для ipv4 и ipv6. по умолчанию: +5:3-64. "0:0-0" или "-" отключает функцию
--orig-autottl6=[<delta>[:<min>[-<max>]]] ; переопределение предыдущего параметра для ipv6 --orig-autottl6=[<delta>[:<min>[-<max>]]|-] ; переопределение предыдущего параметра для ipv6
--orig-mod-start=[n|d|s]N ; применять orig-mod только в исходящих пакетах (n), пакетах данных (d), относительных sequence (s) по номеру больше или равно N --orig-mod-start=[n|d|s]N ; применять orig-mod только в исходящих пакетах (n), пакетах данных (d), относительных sequence (s) по номеру больше или равно N
--orig-mod-cutoff=[n|d|s]N ; применять orig-mod только в исходящих пакетах (n), пакетах данных (d), относительных sequence (s) по номеру меньше N --orig-mod-cutoff=[n|d|s]N ; применять orig-mod только в исходящих пакетах (n), пакетах данных (d), относительных sequence (s) по номеру меньше N
--dup=<int> ; высылать N дубликатов до оригинала --dup=<int> ; высылать N дубликатов до оригинала
--dup-replace=[0|1] ; 1 или отсутствие аргумента блокирует отправку оригинала. отправляются только дубликаты. --dup-replace=[0|1] ; 1 или отсутствие аргумента блокирует отправку оригинала. отправляются только дубликаты.
--dup-ttl=<int> ; модифицировать TTL дубликатов --dup-ttl=<int> ; модифицировать TTL дубликатов
--dup-ttl6=<int> ; модифицировать ipv6 hop limit дубликатов. если не указано, используется значение --dup-ttl --dup-ttl6=<int> ; модифицировать ipv6 hop limit дубликатов. если не указано, используется значение --dup-ttl
--dup-autottl=[<delta>[:<min>[-<max>]]] ; режим auto ttl для ipv4 и ipv6. по умолчанию: +1:3-64. delta=0 отключает функцию --dup-autottl=[<delta>[:<min>[-<max>]]|-] ; режим auto ttl для ipv4 и ipv6. по умолчанию: +1:3-64. "0:0-0" или "-" отключает функцию
--dup-autottl6=[<delta>[:<min>[-<max>]]] ; переопределение предыдущего параметра для ipv6 --dup-autottl6=[<delta>[:<min>[-<max>]]|-] ; переопределение предыдущего параметра для ipv6
--dup-fooling=<fooling> ; дополнительные методики как сделать, чтобы дубликат не дошел до сервера. none md5sig badseq badsum datanoack hopbyhop hopbyhop2 --dup-fooling=<fooling> ; дополнительные методики как сделать, чтобы дубликат не дошел до сервера. none md5sig badseq badsum datanoack ts hopbyhop hopbyhop2
--dup-ts-increment=<int|0xHEX> ; инкремент TSval для ts. по умолчанию -600000
--dup-badseq-increment=<int|0xHEX> ; инкремент sequence number для badseq. по умолчанию -10000 --dup-badseq-increment=<int|0xHEX> ; инкремент sequence number для badseq. по умолчанию -10000
--dup-badack-increment=<int|0xHEX> ; инкремент ack sequence number для badseq. по умолчанию -66000 --dup-badack-increment=<int|0xHEX> ; инкремент ack sequence number для badseq. по умолчанию -66000
--dup-start=[n|d|s]N ; применять dup только в исходящих пакетах (n), пакетах данных (d), относительных sequence (s) по номеру больше или равно N --dup-start=[n|d|s]N ; применять dup только в исходящих пакетах (n), пакетах данных (d), относительных sequence (s) по номеру больше или равно N
@@ -205,15 +210,16 @@ dvtws, собираемый из тех же исходников (см. [док
--dpi-desync-fwmark=<int|0xHEX> ; бит fwmark для пометки десинхронизирующих пакетов, чтобы они повторно не падали в очередь. default = 0x40000000 --dpi-desync-fwmark=<int|0xHEX> ; бит fwmark для пометки десинхронизирующих пакетов, чтобы они повторно не падали в очередь. default = 0x40000000
--dpi-desync-ttl=<int> ; установить ttl для десинхронизирующих пакетов --dpi-desync-ttl=<int> ; установить ttl для десинхронизирующих пакетов
--dpi-desync-ttl6=<int> ; установить ipv6 hop limit для десинхронизирующих пакетов. если не указано, используется значение --dpi-desync-ttl --dpi-desync-ttl6=<int> ; установить ipv6 hop limit для десинхронизирующих пакетов. если не указано, используется значение --dpi-desync-ttl
--dpi-desync-autottl=[<delta>[:<min>[-<max>]]] ; режим auto ttl для ipv4 и ipv6. по умолчанию: 1:3-20. delta=0 отключает функцию. --dpi-desync-autottl=[<delta>[:<min>[-<max>]]|-] ; режим auto ttl для ipv4 и ipv6. по умолчанию: 1:3-20. "0:0-0" или "-" отключает функцию
--dpi-desync-autottl6=[<delta>[:<min>[-<max>]]] ; переопределение предыдущего параметра для ipv6 --dpi-desync-autottl6=[<delta>[:<min>[-<max>]]|-] ; переопределение предыдущего параметра для ipv6
--dpi-desync-fooling=<fooling> ; дополнительные методики как сделать, чтобы фейковый пакет не дошел до сервера. none md5sig badseq badsum datanoack hopbyhop hopbyhop2 --dpi-desync-fooling=<fooling> ; дополнительные методики как сделать, чтобы фейковый пакет не дошел до сервера. none md5sig badseq badsum datanoack ts hopbyhop hopbyhop2
--dpi-desync-repeats=<N> ; посылать каждый генерируемый в nfqws пакет N раз (не влияет на остальные пакеты) --dpi-desync-repeats=<N> ; посылать каждый генерируемый в nfqws пакет N раз (не влияет на остальные пакеты)
--dpi-desync-skip-nosni=0|1 ; 1(default)=не применять dpi desync для запросов без hostname в SNI, в частности для ESNI --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-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=N|-N|marker+N|marker-N ; единичный маркер, определяющий величину перекрытия sequence в режимах split и disorder. для split поддерживается только положительное число.
--dpi-desync-split-seqovl-pattern=<filename>|0xHEX ; чем заполнять фейковую часть overlap --dpi-desync-split-seqovl-pattern=<filename>|0xHEX ; чем заполнять фейковую часть overlap
--dpi-desync-fakedsplit-pattern=<filename>|0xHEX ; чем заполнять фейки в fakedsplit/fakeddisorder --dpi-desync-fakedsplit-pattern=<filename>|0xHEX ; чем заполнять фейки в fakedsplit/fakeddisorder
--dpi-desync-ts-increment=<int|0xHEX> ; инкремент TSval для ts. по умолчанию -600000
--dpi-desync-badseq-increment=<int|0xHEX> ; инкремент sequence number для badseq. по умолчанию -10000 --dpi-desync-badseq-increment=<int|0xHEX> ; инкремент sequence number для badseq. по умолчанию -10000
--dpi-desync-badack-increment=<int|0xHEX> ; инкремент ack sequence number для badseq. по умолчанию -66000 --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-any-protocol=0|1 ; 0(default)=работать только по http request и tls clienthello 1=по всем непустым пакетам данных
@@ -223,6 +229,7 @@ dvtws, собираемый из тех же исходников (см. [док
--dpi-desync-fake-unknown=<filename>|0xHEX ; файл, содержащий фейковый пейлоад неизвестного протокола для dpi-desync=fake, на замену стандартным нулям 256 байт --dpi-desync-fake-unknown=<filename>|0xHEX ; файл, содержащий фейковый пейлоад неизвестного протокола для dpi-desync=fake, на замену стандартным нулям 256 байт
--dpi-desync-fake-syndata=<filename>|0xHEX ; файл, содержащий фейковый пейлоад пакета SYN для режима десинхронизации syndata --dpi-desync-fake-syndata=<filename>|0xHEX ; файл, содержащий фейковый пейлоад пакета SYN для режима десинхронизации syndata
--dpi-desync-fake-quic=<filename>|0xHEX ; файл, содержащий фейковый QUIC Initial --dpi-desync-fake-quic=<filename>|0xHEX ; файл, содержащий фейковый QUIC Initial
--dpi-desync-fake-wireguard=<filename>|0xHEX ; файл, содержащий фейковый wireguard handshake initiation
--dpi-desync-fake-dht=<filename>|0xHEX ; файл, содержащий фейковый пейлоад DHT протокола для dpi-desync=fake, на замену стандартным нулям 64 байт --dpi-desync-fake-dht=<filename>|0xHEX ; файл, содержащий фейковый пейлоад DHT протокола для dpi-desync=fake, на замену стандартным нулям 64 байт
--dpi-desync-fake-discord=<filename>|0xHEX ; файл, содержащий фейковый пейлоад Discord протокола нахождения IP адреса для голосовых чатов для dpi-desync=fake, на замену стандартным нулям 64 байт --dpi-desync-fake-discord=<filename>|0xHEX ; файл, содержащий фейковый пейлоад Discord протокола нахождения IP адреса для голосовых чатов для dpi-desync=fake, на замену стандартным нулям 64 байт
--dpi-desync-fake-stun=<filename>|0xHEX ; файл, содержащий фейковый пейлоад STUN протокола для dpi-desync=fake, на замену стандартным нулям 64 байт --dpi-desync-fake-stun=<filename>|0xHEX ; файл, содержащий фейковый пейлоад STUN протокола для dpi-desync=fake, на замену стандартным нулям 64 байт
@@ -252,6 +259,7 @@ dvtws, собираемый из тех же исходников (см. [док
--filter-tcp=[~]port1[-port2]|* ; фильтр портов tcp для текущей стратегии. ~ означает инверсию. установка фильтра tcp и неустановка фильтра udp запрещает udp. поддерживается список через запятую. --filter-tcp=[~]port1[-port2]|* ; фильтр портов tcp для текущей стратегии. ~ означает инверсию. установка фильтра tcp и неустановка фильтра udp запрещает udp. поддерживается список через запятую.
--filter-udp=[~]port1[-port2]|* ; фильтр портов udp для текущей стратегии. ~ означает инверсию. установка фильтра udp и неустановка фильтра tcp запрещает tcp. поддерживается список через запятую. --filter-udp=[~]port1[-port2]|* ; фильтр портов udp для текущей стратегии. ~ означает инверсию. установка фильтра udp и неустановка фильтра tcp запрещает tcp. поддерживается список через запятую.
--filter-l7=<proto> ; фильтр протокола L6-L7. поддерживается несколько значений через запятую. proto : http tls quic wireguard dht discord stun unknown --filter-l7=<proto> ; фильтр протокола L6-L7. поддерживается несколько значений через запятую. proto : http tls quic wireguard dht discord stun unknown
--filter-ssid=ssid1[,ssid2,ssid3,...] ; фильтр по имени wifi сети (только для linux)
--ipset=<filename> ; включающий ip list. на каждой строчке ip или cidr ipv4 или ipv6. поддерживается множество листов и gzip. перечитка автоматическая. --ipset=<filename> ; включающий ip list. на каждой строчке ip или cidr ipv4 или ipv6. поддерживается множество листов и gzip. перечитка автоматическая.
--ipset-ip=<ip_list> ; фиксированный список подсетей через запятую. можно использовать # в начале для комментирования отдельных подсетей. --ipset-ip=<ip_list> ; фиксированный список подсетей через запятую. можно использовать # в начале для комментирования отдельных подсетей.
--ipset-exclude=<filename> ; исключающий ip list. на каждой строчке ip или cidr ipv4 или ipv6. поддерживается множество листов и gzip. перечитка автоматическая. --ipset-exclude=<filename> ; исключающий ip list. на каждой строчке ip или cidr ipv4 или ipv6. поддерживается множество листов и gzip. перечитка автоматическая.
@@ -333,6 +341,12 @@ dvtws, собираемый из тех же исходников (см. [док
выяснено, что многие провайдерские NAT не отбрасывают эти пакеты, потому работает даже с внутренним провайдерским IP. выяснено, что многие провайдерские NAT не отбрасывают эти пакеты, потому работает даже с внутренним провайдерским IP.
Но linux NAT оно не пройдет, так что за домашним роутером эта техника скорее всего не сработает, но может сработать с него. Но linux NAT оно не пройдет, так что за домашним роутером эта техника скорее всего не сработает, но может сработать с него.
Может сработать и через роутер, если подключение по проводу, и на роутере включено аппаратное ускорение. Может сработать и через роутер, если подключение по проводу, и на роутере включено аппаратное ускорение.
* `ts` прибавляет к значению TSval таймштампа tcp значение ts increment (по умолчанию -600000). Сервера отбрасывают пакеты
с TSval в определенных пределах. По практическим тестам инкремент должен быть где-то от -100 до -0x80000000.
timestamps генерирует клиентская ОС. В linux таймштампы включены по умолчанию, в windows выключены по умолчанию.
Можно включить через команду `netsh interface tcp set global timestamps=enabled`.
ts fooling требует, чтобы таймштампы были включены, иначе работать не будет. Включать надо на каждом клиентском устройстве.
TSecr оставляется без изменений. Так же требуется, чтобы сервер понимал timestamps, но это в большинстве случаев так.
* `autottl`. Суть режима в автоматическом определении TTL, чтобы пакет почти наверняка прошел DPI и немного не дошел до * `autottl`. Суть режима в автоматическом определении TTL, чтобы пакет почти наверняка прошел DPI и немного не дошел до
сервера (`--dpi-desync-autottl`). Или наоборот - TTL едва хватило, чтобы он все-таки дошел до сервера (см `--dup-autottl`, `--orig-autottl`). сервера (`--dpi-desync-autottl`). Или наоборот - TTL едва хватило, чтобы он все-таки дошел до сервера (см `--dup-autottl`, `--orig-autottl`).
Берутся базовые значения TTL 64,128,255, смотрится входящий пакет (да, требуется направить первый входящий пакет на nfqws !). Берутся базовые значения TTL 64,128,255, смотрится входящий пакет (да, требуется направить первый входящий пакет на nfqws !).
@@ -656,8 +670,11 @@ chrome рандомизирует фингерпринт TLS. SNI может о
### ПОДДЕРЖКА UDP ### ПОДДЕРЖКА UDP
Атаки на udp более ограничены в возможностях. udp нельзя фрагментировать иначе, чем на уровне ip. Атаки на udp более ограничены в возможностях. udp нельзя фрагментировать иначе, чем на уровне ip.
Для UDP действуют только режимы десинхронизации `fake`, `hopbyhop`, `destopt`, `ipfrag1`, `ipfrag2`, `udplen`, `tamper`.
Возможно сочетание `fake`, `hopbyhop`, `destopt` с `ipfrag2`, `fake`, `fakeknown` с udplen и tamper. Для UDP действуют только режимы десинхронизации `fake`, `fakeknown`, `hopbyhop`, `destopt`, `ipfrag1`, `ipfrag2`, `udplen`, `tamper`.
Режимами первой фазы являются `fake`, `fakeknown`, `hopbyhop`, `destopt`, `ipfrag1`. Второй фазы - `ipfrag2`, `udplen`, `tamper`.
Как обычно, возможно сочетание режимов первой и второй фазы, но не двух режимов одной фазы.
`udplen` увеличивает размер udp пакета на указанное в `--dpi-desync-udplen-increment` количество байтов. `udplen` увеличивает размер udp пакета на указанное в `--dpi-desync-udplen-increment` количество байтов.
Паддинг заполняется нулями по умолчанию, но можно задать свой паттерн. Паддинг заполняется нулями по умолчанию, но можно задать свой паттерн.
Предназначено для обмана DPI, ориентирующегося на размеры пакетов. Предназначено для обмана DPI, ориентирующегося на размеры пакетов.
@@ -768,6 +785,36 @@ L7 протокол становится известен обычно посл
> Вариант в ядре работает гораздо эффективнее. Это создавалось для систем без подд3ержки ipset в ядре. > Вариант в ядре работает гораздо эффективнее. Это создавалось для систем без подд3ержки ipset в ядре.
> Конкретно - Windows и ядра Linux, собранные без nftables и ipset модулей ядра. Например, в android нет ipset. > Конкретно - Windows и ядра Linux, собранные без nftables и ipset модулей ядра. Например, в android нет ipset.
### ФИЛЬТРАЦИЯ ПО WIFI
Имя wifi сети никак не связано с сетевым интерфейсом адаптера wifi.
Интерфейс один, подключиться можно к любой сети. Для разных сетей разные стратегии.
Стратегия от сети A не работает или ломает сеть B. Что делать ?
Можно вручную запускать и снимать инстансы nfqws. Но можно поступить иначе.
В windows версии winws есть глобальный фильтр `--ssid-filter`.
Он включает или отключает инстанс winws в зависимости от подключенности любого адаптера к конкретной wifi сети.
При этом не учитывается маршрутизация. Такой подход возможен потому, что к windivert можно прицепить несколько инстансов winws на пересекающихся фильтрах.
При смене wifi сети одни будут включаться, другие выключаться.
Для linux применяется иное решение. Фильтр `--filter-ssid` относится к конкретному профилю.
Невозможно повесить несколько инстансов nfqws на одну и ту же очередь или направить один и тот же трафик на несколько очередей.
Подключение и отключение от очереди разных инстансов сопряжено со сложностями синхронизации между ними.
Поэтому обрабатывать трафик должен один инстанс, и он должен уметь работать с разными wifi сетями.
Это и реализовано в параметре `--filter-ssid`. Он берет список имен wifi сетей (SSID) через запятую аналогично `--ssid-filter` для winws.
При выборе профиля имеет значение куда идет конкретный обрабатываемый пакет. На какой интерфейс. Или с какого интерфейса пакет пришел, если он считается входящим.
Поэтому даже если у вас часть трафика идет на одну сеть, часть на другую, а часть вообще не идет по wifi, то все это можно настроить.
Информация о подключенных сетях берется способом, используемым командой `iw dev <ifname> info` (nl80211).
К сожалению, на ядрах с 5.19 до самых последних (6.14 не работает) этот способ сломан.
В этом случае используется способ iwgetid (wireless extensions).
wireless extensions считаются deprecated и на новых ядрах реализованы как прослойка совместимости.
Некоторые ядра могут быть собраны без wireless extensions.
Перед использованием `--filter-ssid` удостоверьтесь, что любая из этих команд возвращает SSID.
Сканируются все wifi интерфейсы, составляется список interface->SSID. Он обновляется по мере поступления
пакетов, но не чаще 1 раза в секунду.
### IPTABLES ДЛЯ NFQWS ### IPTABLES ДЛЯ NFQWS
iptables для задействования атаки на первые пакеты данных в tcp соединении : iptables для задействования атаки на первые пакеты данных в tcp соединении :
@@ -884,6 +931,32 @@ iptables target `FLOWOFFLOAD` - это проприетарное изобрет
Управление offload в nftables реализовано в базовом ядре linux без патчей. Управление offload в nftables реализовано в базовом ядре linux без патчей.
nftables - единственный способ включения offload на классическом Linux. nftables - единственный способ включения offload на классическом Linux.
### ДУРЕНИЕ СО СТОРОНЫ СЕРВЕРА
Это тоже возможно.
nfqws рассчитан на атаку со стороны клиента, поэтому он распознает прямой и обратный трафик на основании роли в установлении tcp соединения.
Если проходит SYN, то source IP - это клиент. Если проходит SYN,ACK , то source IP - это сервер.
Для UDP клиентом считается source IP первого прошедшего пакета по двум связкам ip-port.
На сервере трафиком клиента будет считаться принятый трафик, а трафиком сервера - исходящий.
`--wsize` работает в любом случае, он может использоваться как на клиенте, так и на сервере.
Остальные техники работают только если nfqws считает трафик трафиком клиента.
Поэтому для их применения по исходящему с сервера трафику conntrack нужно выключить параметром `--ctrack-disable`.
Если пакет не найден в conntrack, по нему идет работа как по пакету клиента.
Большинство протоколов опознаваться не будет, потому что система их опознавания рассчитана на содержание пакетов от клиента.
Чтобы задействовать техники типа `fake` или `multisplit` нужно использовать `--dpi-desync-any-protocol` с ограничителем connbytes или
с ограничителем на основании содержания пакета или его заголовков.
start/cutoff недоступны, поскольку завязаны на conntrack.
Техника `synack-split` позволяет разбить tcp сегмент SYN,ACK на отдельные части с SYN и с ACK.
В ответ на это клиент шлет SYN,ACK , что обычно характеризует сервер.
У некоторых DPI от этого может ломаться алгоритм, и они перестают блокировать запрещенный контент.
Здесь [подробное описание](https://nmap.org/misc/split-handshake.pdf) что есть split handshake.
Перенаправление трафика обычно идет по номеру source портов и направлению original.
original - это исходящий с системы трафик, reply - входящий.
## tpws ## tpws
@@ -1429,7 +1502,7 @@ LISTS_RELOAD=- отключает перезагрузку листов.
`ipset/zapret-hosts-users.txt.gz` или `ipset/zapret-hosts-users.txt`, `ipset/zapret-hosts-users.txt.gz` или `ipset/zapret-hosts-users.txt`,
`ipset/zapret-hosts.txt.gz` или `ipset/zapret-hosts.txt` `ipset/zapret-hosts.txt.gz` или `ipset/zapret-hosts.txt`
и 1 exclude список и 1 exclude список
`ipset/zapret-hosts-users-exclude.txt.gz` или `ipset/zapret-hosts-users-exclude.txt` `ipset/zapret-hosts-user-exclude.txt.gz` или `ipset/zapret-hosts-user-exclude.txt`
При режимах фильтрации `MODE_FILTER=hostlist` или `MODE_FILTER=autohostlist` система запуска передает **nfqws** или **tpws** все листы, файлы которых присутствуют. При режимах фильтрации `MODE_FILTER=hostlist` или `MODE_FILTER=autohostlist` система запуска передает **nfqws** или **tpws** все листы, файлы которых присутствуют.
Передача происходит через замену маркеров `<HOSTLIST>` и `<HOSTLIST_NOAUTO>` на реальные параметры `--hostlist`, `--hostlist-exclude`, `--hostlist-auto`. Передача происходит через замену маркеров `<HOSTLIST>` и `<HOSTLIST_NOAUTO>` на реальные параметры `--hostlist`, `--hostlist-exclude`, `--hostlist-auto`.
@@ -1592,8 +1665,10 @@ SKIP_DNSCHECK=1 - отказ от проверки DNS
SKIP_IPBLOCK=1 - отказ от тестов блокировки по порту или IP SKIP_IPBLOCK=1 - отказ от тестов блокировки по порту или IP
SKIP_TPWS=1 - отказ от тестов tpws SKIP_TPWS=1 - отказ от тестов tpws
SKIP_PKTWS=1 - отказ от тестов nfqws/dvtws/winws SKIP_PKTWS=1 - отказ от тестов nfqws/dvtws/winws
PKTWS_EXTRA, TPWS_EXTRA - дополнительные параметры nfqws/dvtws/winws и tpws PKTWS_EXTRA, TPWS_EXTRA - дополнительные параметры nfqws/dvtws/winws и tpws, указываемые после основной стратегии
PKTWS_EXTRA_1 .. PKTWS_EXTRA_9, TPWS_EXTRA_1 .. TPWS_EXTRA_9 - отдельно дополнительные параметры, содержащие пробелы PKTWS_EXTRA_1 .. PKTWS_EXTRA_9, TPWS_EXTRA_1 .. TPWS_EXTRA_9 - отдельно дополнительные параметры, содержащие пробелы
PKTWS_EXTRA_PRE - дополнительные параметры для nfqws/dvtws/winws, указываемые перед основной стратегией
PKTWS_EXTRA_PRE_1 .. PKTWS_EXTRA_PRE_9 - отдельно дополнительные параметры, содержащие пробелы
SECURE_DNS=0|1 - принудительно выключить или включить DoH SECURE_DNS=0|1 - принудительно выключить или включить DoH
DOH_SERVERS - список URL DoH через пробел для автоматического выбора работающего сервера DOH_SERVERS - список URL DoH через пробел для автоматического выбора работающего сервера
DOH_SERVER - конкретный DoH URL, отказ от поиска DOH_SERVER - конкретный DoH URL, отказ от поиска
@@ -1766,6 +1841,21 @@ nfqws начнет получать адреса пакетов из локал
То есть на этом профиле не происходит автоматическое добавление заблокированных доменов. То есть на этом профиле не происходит автоматическое добавление заблокированных доменов.
Но если на другом профиле что-то будет добавлено, то этот профиль примет изменения автоматически. Но если на другом профиле что-то будет добавлено, то этот профиль примет изменения автоматически.
***Изменение бита mark для предотвращения зацикливания***\
`DESYNC_MARK=0x40000000`
***Изменение бита mark для пометки пакетов, проходящих по POSTNAT схеме (только nftables)***\
`DESYNC_MARK_POSTNAT=0x20000000`
***Если раскоментировано, пометка пакетов, которые должны быть обработаны zapret.***\
`#FILTER_MARK_POSTNAT=0x10000000`
Бит должен быть установлен вашими собственными правилами.
* Для iptables - в цепочках mangle PREROUTING и mangle OUTPUT перед правилами zapret (iptables -I _после_ применения правил zapret).
* Для nftables - в хуках output и prerouting с приоритетом -102 или ниже.
Критерии пометки любые. Например, IP адрес или интерфейс источника. Это ответ на вопрос "как мне сделать, чтобы телик не ходил через zapret или чтобы через него ходил только мой комп".
***Включение стандартной опции tpws в режиме socks***\ ***Включение стандартной опции tpws в режиме socks***\
`TPWS_SOCKS_ENABLE=0` `TPWS_SOCKS_ENABLE=0`
@@ -2255,7 +2345,7 @@ chcon u:object_r:system_file:s0 /data/local/tmp/zapret/tpws
Если компа нет, то развертка chroot - единственный вариант, хотя и неудобный. Если компа нет, то развертка chroot - единственный вариант, хотя и неудобный.
Подойдет что-то легковесное, например, alpine или даже OpenWrt. Подойдет что-то легковесное, например, alpine или даже OpenWrt.
Если это не эмулятор android, то универсальная архитектура - arm (любой вариант). Если это не эмулятор android, то универсальная архитектура - arm (любой вариант).
Если вы точно знаете, что ОС у вас 64-разрядная, то лучше вместо arm - aarch64. Если вы точно знаете, что ОС у вас 64-разрядная, то лучше вместо arm - arm64.
Выяснить архитектуру можно командой `uname -a`. Выяснить архитектуру можно командой `uname -a`.
``` ```

View File

@@ -24,17 +24,15 @@ Tor поддерживает "из коробки" режим transparent proxy.
Устанавливать их нужно с опцией opkg --force-overwrite, поскольку они перепишут ssh клиент от dropbear. Устанавливать их нужно с опцией opkg --force-overwrite, поскольку они перепишут ssh клиент от dropbear.
После установки пакетов расслабим неоправданно жестокие права : chmod 755 /etc/ssh. После установки пакетов расслабим неоправданно жестокие права : chmod 755 /etc/ssh.
Следует создать пользователя, под которым будем крутить ssh client. Допустим, это будет 'proxy'. Следует создать пользователя, под которым будем крутить ssh client. Допустим, это будет 'proxy'.
Сначала установить пакет shadow-useradd. Сначала установить пакеты shadow-useradd и shadow-su.
------------------ ------------------
useradd -d /home/proxy proxy useradd -s /bin/false -d /home/proxy proxy
mkdir -p /home/proxy mkdir -p /home/proxy
chown proxy:proxy /home/proxy chown proxy:proxy /home/proxy
------------------ ------------------
Openssh ловит разные глюки, если у него нет доступа к /dev/tty. Сгенерируем ключ RSA для доступа к ssh серверу.
Добавим в /etc/rc.local строчку : "chmod 666 /dev/tty"
Сгенерируем для него ключ RSA для доступа к ssh серверу.
------------------ ------------------
su proxy su -s /bin/ash proxy
cd cd
mkdir -m 700 .ssh mkdir -m 700 .ssh
cd .ssh cd .ssh

View File

@@ -83,7 +83,7 @@ You must choose to install `curl`. To compile from sources install `gcc-core`,`m
Make from directory `nfq` using `make cygwin64` or `make cygwin32` for 64 and 32 bit versions. Make from directory `nfq` using `make cygwin64` or `make cygwin32` for 64 and 32 bit versions.
`winws` requires `cygwin1.dll`, `windivert.dll`, `windivert64.sys` or `windivert32.sys`. `winws` requires `cygwin1.dll`, `windivert.dll`, `windivert64.sys` or `windivert32.sys`.
You can take them from `binaries/win64` or `binaries/win32`. You can take them from `binaries/windows-x86_64` or `binaries/windows-x86`.
There's no `arm64` signed `windivert` driver and no `cygwin`. There's no `arm64` signed `windivert` driver and no `cygwin`.
But it's possible to use unsigned driver version in test mode and user mode components with x64 emulation. But it's possible to use unsigned driver version in test mode and user mode components with x64 emulation.
@@ -128,19 +128,6 @@ If you want to run `winws` from `cygwin` delete, rename or move `cygwin1.dll`.
To simplify things it's advised to use `zapret-win-bundle`. To simplify things it's advised to use `zapret-win-bundle`.
### auto start
To start `winws` with windows use windows task scheduler. There are `task_*.cmd` batch files in `binaries/win64/zapret-winws`.
They create, remove, start and stop scheduled task `winws1`. They must be run as administrator.
Edit `task_create.cmd` and write your `winws` parameters to `%WINWS1%` variable. If you need multiple `winws` instances
clone the code in all cmd files to support multiple tasks `winws1,winws2,winws3,...`.
Tasks can also be controlled from GUI `taskschd.msc`.
Also you can use windows services the same way with `service_*.cmd`.
### zapret-win-bundle ### zapret-win-bundle
To make your life easier there's ready to use [bundle](https://github.com/bol-van/zapret-win-bundle) with `cygwin`,`blockcheck` and `winws`. To make your life easier there's ready to use [bundle](https://github.com/bol-van/zapret-win-bundle) with `cygwin`,`blockcheck` and `winws`.
@@ -166,3 +153,15 @@ unix2dos winws.log
`winws.log` will be in `cygwin/home/<username>`. `unix2dos` helps with `windows 7` notepad. It's not necessary in `Windows 10` and later. `winws.log` will be in `cygwin/home/<username>`. `unix2dos` helps with `windows 7` notepad. It's not necessary in `Windows 10` and later.
Because 32-bit systems are rare nowadays `zapret-win-bundle` exists only for `Windows x64/arm64`. Because 32-bit systems are rare nowadays `zapret-win-bundle` exists only for `Windows x64/arm64`.
### auto start
To start `winws` with windows use windows task scheduler. There are `task_*.cmd` batch files in `binaries/windows-x86-64/zapret-winws`.
They create, remove, start and stop scheduled task `winws1`. They must be run as administrator.
Edit `task_create.cmd` and write your `winws` parameters to `%WINWS1%` variable. If you need multiple `winws` instances
clone the code in all cmd files to support multiple tasks `winws1,winws2,winws3,...`.
Tasks can also be controlled from GUI `taskschd.msc`.
Also you can use windows services the same way with `service_*.cmd`.

View File

@@ -84,7 +84,7 @@ SubInterface используется windivert, но практически в
autottl и autohostlist. При включении autohostlist так же перенаправляются пакеты данных с http redirect с кодами 302 и 307. autottl и autohostlist. При включении autohostlist так же перенаправляются пакеты данных с http redirect с кодами 302 и 307.
Всегда добавляется фильтр на исключение не-интернет адресов ipv4 и ipv6. Всегда добавляется фильтр на исключение не-интернет адресов ipv4 и ipv6.
Для сложных нестандартных сценариев могут потребоваться свои фильтры. Логично будет начать со стандартного шаблона, Для сложных нестандартных сценариев могут потребоваться свои фильтры. Логично будет начать со стандартного шаблона,
сохраненного через `--wf-save`. Нужно править файл и подсовывать его в параметре `--wf-raw`. Максимальный размер фильтра - **8 Kb**. сохраненного через `--wf-save`. Нужно править файл и подсовывать его в параметре `--wf-raw`. Максимальный размер фильтра - **16 Kb**.
Можно запускать несколько процессов **winws** с разными стратегиями. Однако, не следует делать пересекающиеся фильтры. Можно запускать несколько процессов **winws** с разными стратегиями. Однако, не следует делать пересекающиеся фильтры.
@@ -125,7 +125,7 @@ network locations в win10/11. Кое-что есть в **powershell**.
Существует неочевидный момент, каcаемый запуска **winws** из cygwin shell\`а. Если в директории, где находится winws, находится Существует неочевидный момент, каcаемый запуска **winws** из cygwin shell\`а. Если в директории, где находится winws, находится
копия `cygwin1.dll`, **winws** не запустится. копия `cygwin1.dll`, **winws** не запустится.
Если нужен запуск под cygwin, то следует удалить или переместить `cygwin1.dll` из `binaries/win64`. Это нужно для работы blockcheck. Если нужен запуск под cygwin, то следует удалить или переместить `cygwin1.dll` из `binaries/windows-x86_64`. Это нужно для работы blockcheck.
Из cygwin шелла можно посылать winws сигналы через `kill` точно так же, как в `*nix`. Из cygwin шелла можно посылать winws сигналы через `kill` точно так же, как в `*nix`.
Как получить совместимый с windows 7 и winws cygwin : Как получить совместимый с windows 7 и winws cygwin :
@@ -203,22 +203,6 @@ _cygwin_ для обычной работы **winws** не нужен.
Однако, хотя такой способ и работает, использование **winws** сильно облегчает [zapret-win-bundle](https://github.com/bol-van/zapret-win-bundle). Однако, хотя такой способ и работает, использование **winws** сильно облегчает [zapret-win-bundle](https://github.com/bol-van/zapret-win-bundle).
Там нет проблемы с `cygwin.dll`. Там нет проблемы с `cygwin.dll`.
## Автозапуск winws
Для запуска **winws** вместе с windows есть 2 варианта. Планировщик задач или службы windows.
Можно создавать задачи и управлять ими через консольную программу schtasks.
В директории `binaries/win64/winws` подготовлены файлы `task_*.cmd` .
В них реализовано создание, удаление, старт и стоп одной копии процесса winws с параметрами из переменной `%WINWS1%`.
Исправьте параметры на нужную вам стратегию. Если для разных фильтров применяется разная стратегия, размножьте код
для задач _winws1_,_winws2_,_winws3_,_..._
Аналогично настраивается вариант запуска через службы windows. Смотрите `service_*.cmd`.
Все батники требуется запускать от имени администратора.
Управлять задачами можно так же из графической программы управления планировщиком `taskschd.msc`
## Zapret-win-bundle ## Zapret-win-bundle
Можно не возиться с _cygwin_, а взять готовый пакет, включающий в себя _cygwin_ и _blockcheck_ : https://github.com/bol-van/zapret-win-bundle Можно не возиться с _cygwin_, а взять готовый пакет, включающий в себя _cygwin_ и _blockcheck_ : https://github.com/bol-van/zapret-win-bundle
@@ -257,3 +241,19 @@ _zapret-winws_ - это отдельный комплект для повсед
> [!CAUTION] > [!CAUTION]
> Поскольку 32-битные windows мало востребованы, _zapret-win-bundle_ существует только в варианте для windows _x64/arm64_. > Поскольку 32-битные windows мало востребованы, _zapret-win-bundle_ существует только в варианте для windows _x64/arm64_.
## Автозапуск winws
Для запуска **winws** вместе с windows есть 2 варианта. Планировщик задач или службы windows.
Можно создавать задачи и управлять ими через консольную программу schtasks.
В директории `binaries/windows-x86_64/winws` подготовлены файлы `task_*.cmd` .
В них реализовано создание, удаление, старт и стоп одной копии процесса winws с параметрами из переменной `%WINWS1%`.
Исправьте параметры на нужную вам стратегию. Если для разных фильтров применяется разная стратегия, размножьте код
для задач _winws1_,_winws2_,_winws3_,_..._
Аналогично настраивается вариант запуска через службы windows. Смотрите `service_*.cmd`.
Все батники требуется запускать от имени администратора.
Управлять задачами можно так же из графической программы управления планировщиком `taskschd.msc`

View File

@@ -56,9 +56,6 @@ RemoveIPC=true
RestrictNamespaces=true RestrictNamespaces=true
RestrictRealtime=true RestrictRealtime=true
RestrictSUIDSGID=true RestrictSUIDSGID=true
SystemCallArchitectures=native
SystemCallFilter=@system-service
SystemCallFilter=~@resources
UMask=0077 UMask=0077
[Install] [Install]

View File

@@ -55,8 +55,6 @@ RemoveIPC=true
RestrictNamespaces=true RestrictNamespaces=true
RestrictRealtime=true RestrictRealtime=true
RestrictSUIDSGID=true RestrictSUIDSGID=true
SystemCallArchitectures=native
SystemCallFilter=@system-service
UMask=0077 UMask=0077
[Install] [Install]

View File

@@ -8,6 +8,68 @@ BINDIR="$EXEDIR/$BINS"
ZAPRET_BASE=${ZAPRET_BASE:-"$EXEDIR"} ZAPRET_BASE=${ZAPRET_BASE:-"$EXEDIR"}
. "$ZAPRET_BASE/common/base.sh" . "$ZAPRET_BASE/common/base.sh"
read_elf_arch()
{
# $1 - elf file
local arch=$(dd if="$1" count=2 bs=1 skip=18 2>/dev/null | hexdump -e '2/1 "%02x"')
local bit=$(dd if="$1" count=1 bs=1 skip=4 2>/dev/null | hexdump -e '1/1 "%02x"')
echo $bit$arch
}
select_test_method()
{
local f ELF
TEST=run
# ash and dash try to execute invalid executables as a script. they interpret binary garbage with possible negative consequences
# bash and zsh do not do this
if exists bash; then
TEST=bash
elif exists zsh && [ "$UNAME" != CYGWIN ] ; then
TEST=zsh
elif [ "$UNAME" != Darwin -a "$UNAME" != CYGWIN ]; then
if exists hexdump and exists dd; then
# macos does not use ELF
TEST=elf
ELF=
ELF_ARCH=
for f in /bin/sh /system/bin/sh; do
[ -x "$f" ] && {
ELF=$f
break
}
done
[ -n "$ELF" ] && ELF_ARCH=$(read_elf_arch "$ELF")
[ -n "$ELF_ARCH" ] && return
fi
# find does not use its own shell exec
# it uses execvp(). in musl libc it does not call shell, in glibc it DOES call /bin/sh
# that's why prefer bash or zsh if present. otherwise it's our last chance
if exists find; then
TEST=find
FIND=find
elif exists busybox; then
busybox find /jGHUa3fh1A 2>/dev/null
# 127 - command not found
[ "$?" = 127 ] || {
TEST=find
FIND="busybox find"
}
fi
fi
}
disable_antivirus()
{
# $1 - dir
[ "$UNAME" = Darwin ] && find "$1" -maxdepth 1 -type f -perm +111 -exec xattr -d com.apple.quarantine {} \; 2>/dev/null
}
check_dir() check_dir()
{ {
local dir="$BINDIR/$1" local dir="$BINDIR/$1"
@@ -15,23 +77,36 @@ check_dir()
local out local out
if [ -f "$exe" ]; then if [ -f "$exe" ]; then
if [ -x "$exe" ]; then if [ -x "$exe" ]; then
# ash and dash try to execute invalid executables as a script. they interpret binary garbage with possible negative consequences disable_antivirus "$dir"
# bash and zsh do not do this case $TEST in
if exists bash; then bash)
out=$(echo 0.0.0.0 | bash -c "\"$exe"\" 2>/dev/null) out=$(echo 0.0.0.0 | bash -c "\"$exe"\" 2>/dev/null)
elif exists zsh; then [ -n "$out" ]
out=$(echo 0.0.0.0 | zsh -c "\"$exe\"" 2>/dev/null) ;;
else zsh)
# find does not use its own shell exec out=$(echo 0.0.0.0 | zsh -c "\"$exe\"" 2>/dev/null)
# it uses execvp(). in musl libc it does not call shell, in glibc it DOES call /bin/sh [ -n "$out" ]
# that's why prefer bash or zsh if present. otherwise it's our last chance ;;
local FIND=find elf)
if ! exists find && exists busybox; then out=$(read_elf_arch "$exe")
FIND="busybox find" [ "$ELF_ARCH" = "$out" ] && {
fi # exec test to verify it actually works. no illegal instruction or crash.
out=$(echo 0.0.0.0 | $FIND "$dir" -maxdepth 1 -name ip2net -exec {} \; 2>/dev/null) out=$(echo 0.0.0.0 | "$exe" 2>/dev/null)
fi [ -n "$out" ]
[ -n "$out" ] }
;;
find)
out=$(echo 0.0.0.0 | $FIND "$dir" -maxdepth 1 -name ip2net -exec {} \; 2>/dev/null)
[ -n "$out" ]
;;
run)
out=$(echo 0.0.0.0 | "$exe" 2>/dev/null)
[ -n "$out" ]
;;
*)
false
;;
esac
else else
echo >&2 "$exe is not executable. set proper chmod." echo >&2 "$exe is not executable. set proper chmod."
return 1 return 1
@@ -52,29 +127,65 @@ ccp()
#cp -f "../$BINS/$1" "$ZAPRET_BASE/$2" && echo copying : "../$BINS/$1" =\> "$ZAPRET_BASE/$2" #cp -f "../$BINS/$1" "$ZAPRET_BASE/$2" && echo copying : "../$BINS/$1" =\> "$ZAPRET_BASE/$2"
} }
UNAME=$(uname) UNAME=$(uname)
[ "$1" = getarch ] ||
if [ ! -d "$BINDIR" ] || ! dir_is_not_empty "$BINDIR" ]; then
echo "no binaries found"
case $UNAME in
Linux)
echo "you need to download release from github or build binaries from source"
echo "building from source requires debian/ubuntu packages : make gcc zlib1g-dev libcap-dev libnetfilter-queue-dev libmnl-dev libsystemd-dev"
echo "libsystemd-dev required only on systemd based systems"
echo "on distributions with other package manager find dev package analogs"
echo "to compile on systems with systemd : make systemd"
echo "to compile on other systems : make"
;;
Darwin)
echo "you need to download release from github or build binaries from source"
echo "to compile : make mac"
;;
FreeBSD)
echo "you need to download release from github or build binaries from source"
echo "to compile : make"
;;
OpenBSD)
echo "to compile : make bsd"
;;
CYGWIN*)
echo "you need to download release from github or build binaries from source"
echo "to compile : read docs"
echo "to make things easier use zapret-win-bundle"
;;
esac
exit 1
fi
unset PKTWS unset PKTWS
case $UNAME in case $UNAME in
Linux) Linux)
ARCHLIST="my x86_64 x86 aarch64 arm mips64r2-msb mips32r1-lsb mips32r1-msb lexra ppc" ARCHLIST="my linux-x86_64 linux-x86 linux-arm64 linux-arm linux-mips64 linux-mipsel linux-mips linux-lexra linux-ppc"
PKTWS=nfqws PKTWS=nfqws
;; ;;
Darwin) Darwin)
ARCHLIST="my mac64" ARCHLIST="my mac64"
;; ;;
FreeBSD) FreeBSD)
ARCHLIST="my freebsd-x64" ARCHLIST="my freebsd-x86_64"
PKTWS=dvtws PKTWS=dvtws
;; ;;
CYGWIN*) CYGWIN*)
UNAME=CYGWIN UNAME=CYGWIN
ARCHLIST="win64 win32" ARCHLIST="windows-x86_64 windows-x86"
PKTWS=winws PKTWS=winws
;; ;;
*) *)
ARCHLIST="my" ARCHLIST="my"
esac esac
select_test_method
if [ "$1" = "getarch" ]; then if [ "$1" = "getarch" ]; then
for arch in $ARCHLIST for arch in $ARCHLIST
do do
@@ -85,6 +196,8 @@ if [ "$1" = "getarch" ]; then
fi fi
done done
else else
echo "using arch detect method : $TEST${ELF_ARCH:+ $ELF_ARCH}"
for arch in $ARCHLIST for arch in $ARCHLIST
do do
[ -d "$BINDIR/$arch" ] || continue [ -d "$BINDIR/$arch" ] || continue

View File

@@ -50,6 +50,29 @@ check_readonly_system()
} }
} }
check_source()
{
local bad=0
echo \* checking source files
case $SYSTEM in
systemd)
[ -f "$EXEDIR/init.d/systemd/zapret.service" ] || bad=1
;;
openrc)
[ -f "$EXEDIR/init.d/openrc/zapret" ] || bad=1
;;
macos)
[ -f "$EXEDIR/init.d/macos/zapret" ] || bad=1
;;
esac
[ "$bad" = 1 ] && {
echo 'some critical files are missing'
echo 'are you sure you are not using embedded release ? you need full version for traditional systems'
exitp 5
}
}
check_bins() check_bins()
{ {
echo \* checking executables echo \* checking executables
@@ -57,6 +80,7 @@ check_bins()
fix_perms_bin_test "$EXEDIR" fix_perms_bin_test "$EXEDIR"
local arch="$(get_bin_arch)" local arch="$(get_bin_arch)"
local make_target local make_target
local cf="-march=native"
[ "$FORCE_BUILD" = "1" ] && { [ "$FORCE_BUILD" = "1" ] && {
echo forced build mode echo forced build mode
if [ "$arch" = "my" ]; then if [ "$arch" = "my" ]; then
@@ -72,12 +96,13 @@ check_bins()
case $SYSTEM in case $SYSTEM in
macos) macos)
make_target=mac make_target=mac
cf=
;; ;;
systemd) systemd)
make_target=systemd make_target=systemd
;; ;;
esac esac
CFLAGS="-march=native ${CFLAGS}" make -C "$EXEDIR" $make_target || { CFLAGS="${cf:+$cf }${CFLAGS}" OPTIMIZE=-O2 make -C "$EXEDIR" $make_target || {
echo could not compile echo could not compile
make -C "$EXEDIR" clean make -C "$EXEDIR" clean
exitp 8 exitp 8
@@ -230,9 +255,9 @@ select_mode_filter()
select_mode() select_mode()
{ {
select_mode_filter
select_mode_mode select_mode_mode
select_mode_iface select_mode_iface
select_mode_filter
} }
select_getlist() select_getlist()
@@ -883,8 +908,7 @@ umask 0022
fix_sbin_path fix_sbin_path
fsleep_setup fsleep_setup
check_system check_system
check_source
[ "$SYSTEM" = "macos" ] && . "$EXEDIR/init.d/macos/functions"
case $SYSTEM in case $SYSTEM in
systemd) systemd)

View File

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

View File

@@ -1,5 +1,6 @@
CC ?= gcc CC ?= cc
CFLAGS += -std=gnu99 -Os OPTIMIZE ?= -Os
CFLAGS += -std=gnu99 $(OPTIMIZE)
CFLAGS_BSD = -Wno-address-of-packed-member CFLAGS_BSD = -Wno-address-of-packed-member
CFLAGS_WIN = -static CFLAGS_WIN = -static
LIBS = -lpthread LIBS = -lpthread

View File

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

View File

@@ -1,9 +1,11 @@
CC ?= gcc CC ?= cc
CFLAGS += -std=gnu99 -Os -flto=auto OPTIMIZE ?= -Os
CFLAGS += -std=gnu99 $(OPTIMIZE) -flto=auto
CFLAGS_SYSTEMD = -DUSE_SYSTEMD CFLAGS_SYSTEMD = -DUSE_SYSTEMD
CFLAGS_BSD = -Wno-address-of-packed-member CFLAGS_BSD = -Wno-address-of-packed-member
CFLAGS_CYGWIN = -Wno-address-of-packed-member -static CFLAGS_CYGWIN = -Wno-address-of-packed-member -static
LIBS_LINUX = -lnetfilter_queue -lnfnetlink -lz LDFLAGS_ANDROID = -llog
LIBS_LINUX = -lz -lnetfilter_queue -lnfnetlink -lmnl
LIBS_SYSTEMD = -lsystemd LIBS_SYSTEMD = -lsystemd
LIBS_BSD = -lz LIBS_BSD = -lz
LIBS_CYGWIN = -lz -Lwindows/windivert -Iwindows -lwlanapi -lole32 -loleaut32 LIBS_CYGWIN = -lz -Lwindows/windivert -Iwindows -lwlanapi -lole32 -loleaut32
@@ -21,7 +23,8 @@ nfqws: $(SRC_FILES)
systemd: $(SRC_FILES) systemd: $(SRC_FILES)
$(CC) -s $(CFLAGS) $(CFLAGS_SYSTEMD) -o nfqws $(SRC_FILES) $(LIBS_LINUX) $(LIBS_SYSTEMD) $(LDFLAGS) $(CC) -s $(CFLAGS) $(CFLAGS_SYSTEMD) -o nfqws $(SRC_FILES) $(LIBS_LINUX) $(LIBS_SYSTEMD) $(LDFLAGS)
android: nfqws android: $(SRC_FILES)
$(CC) -s $(CFLAGS) -o nfqws $(SRC_FILES) $(LIBS_LINUX) $(LDFLAGS) $(LDFLAGS_ANDROID)
bsd: $(SRC_FILES) bsd: $(SRC_FILES)
$(CC) -s $(CFLAGS) $(CFLAGS_BSD) -o dvtws $(SRC_FILES) $(LIBS_BSD) $(LDFLAGS) $(CC) -s $(CFLAGS) $(CFLAGS_BSD) -o dvtws $(SRC_FILES) $(LIBS_BSD) $(LDFLAGS)

View File

@@ -29,6 +29,7 @@ void ConntrackClearHostname(t_ctrack *track)
{ {
free(track->hostname); free(track->hostname);
track->hostname = NULL; track->hostname = NULL;
track->hostname_is_ip = false;
} }
static void ConntrackClearTrack(t_ctrack *track) static void ConntrackClearTrack(t_ctrack *track)
{ {

View File

@@ -86,6 +86,7 @@ typedef struct
t_l7proto l7proto; t_l7proto l7proto;
bool l7proto_discovered; bool l7proto_discovered;
char *hostname; char *hostname;
bool hostname_is_ip;
bool hostname_discovered; bool hostname_discovered;
bool hostname_ah_check; // should perform autohostlist checks bool hostname_ah_check; // should perform autohostlist checks

View File

@@ -29,6 +29,16 @@
#endif #endif
#ifdef __linux__
#include <linux/nl80211.h>
#include <linux/genetlink.h>
#include <libmnl/libmnl.h>
#include <net/if.h>
#define _LINUX_IF_H // prevent conflict between linux/if.h and net/if.h in old gcc 4.x
#include <linux/wireless.h>
#include <sys/ioctl.h>
#endif
uint32_t net32_add(uint32_t netorder_value, uint32_t cpuorder_increment) uint32_t net32_add(uint32_t netorder_value, uint32_t cpuorder_increment)
{ {
return htonl(ntohl(netorder_value)+cpuorder_increment); return htonl(ntohl(netorder_value)+cpuorder_increment);
@@ -108,6 +118,7 @@ static void fill_tcphdr(
uint16_t nsport, uint16_t ndport, uint16_t nsport, uint16_t ndport,
uint16_t nwsize, uint8_t scale_factor, uint16_t nwsize, uint8_t scale_factor,
uint32_t *timestamps, uint32_t *timestamps,
uint32_t ts_increment,
uint32_t badseq_increment, uint32_t badseq_increment,
uint32_t badseq_ack_increment, uint32_t badseq_ack_increment,
uint16_t data_len) uint16_t data_len)
@@ -155,13 +166,13 @@ static void fill_tcphdr(
*(uint32_t*)(tcpopt+t+14)=random(); *(uint32_t*)(tcpopt+t+14)=random();
t+=18; t+=18;
} }
if (timestamps || (fooling & FOOL_TS)) if (timestamps)
{ {
tcpopt[t] = 8; // kind tcpopt[t] = 8; // kind
tcpopt[t+1] = 10; // len tcpopt[t+1] = 10; // len
// forge only TSecr if orig timestamp is present memcpy(tcpopt+t+2,timestamps,8);
*(uint32_t*)(tcpopt+t+2) = timestamps ? timestamps[0] : -1; // forge TSval, keep TSecr
*(uint32_t*)(tcpopt+t+6) = (timestamps && !(fooling & FOOL_TS)) ? timestamps[1] : -1; if (fooling & FOOL_TS) *(uint32_t*)(tcpopt+t+2) = net32_add(*(uint32_t*)(tcpopt+t+2),ts_increment);
t+=10; t+=10;
} }
if (scale_factor!=SCALE_NONE) if (scale_factor!=SCALE_NONE)
@@ -232,6 +243,7 @@ bool prepare_tcp_segment4(
uint8_t tos, uint8_t tos,
uint16_t ip_id, uint16_t ip_id,
uint32_t fooling, uint32_t fooling,
uint32_t ts_increment,
uint32_t badseq_increment, uint32_t badseq_increment,
uint32_t badseq_ack_increment, uint32_t badseq_ack_increment,
const void *data, uint16_t len, const void *data, uint16_t len,
@@ -247,7 +259,7 @@ bool prepare_tcp_segment4(
uint8_t *payload = (uint8_t*)(tcp+1)+tcpoptlen; uint8_t *payload = (uint8_t*)(tcp+1)+tcpoptlen;
fill_iphdr(ip, &src->sin_addr, &dst->sin_addr, pktlen, IPPROTO_TCP, DF, ttl, tos, ip_id); fill_iphdr(ip, &src->sin_addr, &dst->sin_addr, pktlen, IPPROTO_TCP, DF, ttl, tos, ip_id);
fill_tcphdr(tcp,fooling,tcp_flags,sack,nmss,nseq,nack_seq,src->sin_port,dst->sin_port,nwsize,scale_factor,timestamps,badseq_increment,badseq_ack_increment,len); fill_tcphdr(tcp,fooling,tcp_flags,sack,nmss,nseq,nack_seq,src->sin_port,dst->sin_port,nwsize,scale_factor,timestamps,ts_increment,badseq_increment,badseq_ack_increment,len);
memcpy(payload,data,len); memcpy(payload,data,len);
tcp4_fix_checksum(tcp,ip_payload_len,&ip->ip_src,&ip->ip_dst); tcp4_fix_checksum(tcp,ip_payload_len,&ip->ip_src,&ip->ip_dst);
@@ -269,6 +281,7 @@ bool prepare_tcp_segment6(
uint8_t ttl, uint8_t ttl,
uint32_t flow_label, uint32_t flow_label,
uint32_t fooling, uint32_t fooling,
uint32_t ts_increment,
uint32_t badseq_increment, uint32_t badseq_increment,
uint32_t badseq_ack_increment, uint32_t badseq_ack_increment,
const void *data, uint16_t len, const void *data, uint16_t len,
@@ -333,7 +346,7 @@ bool prepare_tcp_segment6(
uint8_t *payload = (uint8_t*)(tcp+1)+tcpoptlen; uint8_t *payload = (uint8_t*)(tcp+1)+tcpoptlen;
fill_ip6hdr(ip6, &src->sin6_addr, &dst->sin6_addr, ip_payload_len, proto, ttl, flow_label); fill_ip6hdr(ip6, &src->sin6_addr, &dst->sin6_addr, ip_payload_len, proto, ttl, flow_label);
fill_tcphdr(tcp,fooling,tcp_flags,sack,nmss,nseq,nack_seq,src->sin6_port,dst->sin6_port,nwsize,scale_factor,timestamps,badseq_increment,badseq_ack_increment,len); fill_tcphdr(tcp,fooling,tcp_flags,sack,nmss,nseq,nack_seq,src->sin6_port,dst->sin6_port,nwsize,scale_factor,timestamps,ts_increment,badseq_increment,badseq_ack_increment,len);
memcpy(payload,data,len); memcpy(payload,data,len);
tcp6_fix_checksum(tcp,transport_payload_len,&ip6->ip6_src,&ip6->ip6_dst); tcp6_fix_checksum(tcp,transport_payload_len,&ip6->ip6_src,&ip6->ip6_dst);
@@ -358,15 +371,16 @@ bool prepare_tcp_segment(
uint16_t ip_id, uint16_t ip_id,
uint32_t flow_label, uint32_t flow_label,
uint32_t fooling, uint32_t fooling,
uint32_t ts_increment,
uint32_t badseq_increment, uint32_t badseq_increment,
uint32_t badseq_ack_increment, uint32_t badseq_ack_increment,
const void *data, uint16_t len, const void *data, uint16_t len,
uint8_t *buf, size_t *buflen) uint8_t *buf, size_t *buflen)
{ {
return (src->sa_family==AF_INET && dst->sa_family==AF_INET) ? return (src->sa_family==AF_INET && dst->sa_family==AF_INET) ?
prepare_tcp_segment4((struct sockaddr_in *)src,(struct sockaddr_in *)dst,tcp_flags,sack,nmss,nseq,nack_seq,nwsize,scale_factor,timestamps,DF,ttl,tos,ip_id,fooling,badseq_increment,badseq_ack_increment,data,len,buf,buflen) : prepare_tcp_segment4((struct sockaddr_in *)src,(struct sockaddr_in *)dst,tcp_flags,sack,nmss,nseq,nack_seq,nwsize,scale_factor,timestamps,DF,ttl,tos,ip_id,fooling,ts_increment,badseq_increment,badseq_ack_increment,data,len,buf,buflen) :
(src->sa_family==AF_INET6 && dst->sa_family==AF_INET6) ? (src->sa_family==AF_INET6 && dst->sa_family==AF_INET6) ?
prepare_tcp_segment6((struct sockaddr_in6 *)src,(struct sockaddr_in6 *)dst,tcp_flags,sack,nmss,nseq,nack_seq,nwsize,scale_factor,timestamps,ttl,flow_label,fooling,badseq_increment,badseq_ack_increment,data,len,buf,buflen) : prepare_tcp_segment6((struct sockaddr_in6 *)src,(struct sockaddr_in6 *)dst,tcp_flags,sack,nmss,nseq,nack_seq,nwsize,scale_factor,timestamps,ttl,flow_label,fooling,ts_increment,badseq_increment,badseq_ack_increment,data,len,buf,buflen) :
false; false;
} }
@@ -1832,6 +1846,259 @@ bool rawsend_queue(struct rawpacket_tailhead *q)
} }
#if defined(HAS_FILTER_SSID) && defined(__linux__)
// linux-specific wlan retrieval implementation
typedef void netlink_prepare_nlh_cb_t(struct nlmsghdr *nlh);
static bool netlink_genl_simple_transact(struct mnl_socket* nl, uint16_t type, uint16_t flags, uint8_t cmd, uint8_t version, netlink_prepare_nlh_cb_t cb_prepare_nlh, mnl_cb_t cb_data, void *data)
{
char buf[MNL_SOCKET_BUFFER_SIZE];
struct nlmsghdr *nlh;
struct genlmsghdr *genl;
ssize_t rd;
nlh = mnl_nlmsg_put_header(buf);
nlh->nlmsg_type = type;
nlh->nlmsg_flags = flags;
genl = mnl_nlmsg_put_extra_header(nlh, sizeof(struct genlmsghdr));
genl->cmd = cmd;
genl->version = version;
if (cb_prepare_nlh) cb_prepare_nlh(nlh);
if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0)
{
DLOG_PERROR("mnl_socket_sendto");
return false;
}
while ((rd=mnl_socket_recvfrom(nl, buf, sizeof(buf))) > 0)
{
switch(mnl_cb_run(buf, rd, 0, 0, cb_data, data))
{
case MNL_CB_STOP:
return true;
case MNL_CB_OK:
break;
default:
return false;
}
}
return false;
}
static void wlan_id_prepare(struct nlmsghdr *nlh)
{
mnl_attr_put_strz(nlh, CTRL_ATTR_FAMILY_NAME, "nl80211");
}
static int wlan_id_attr_cb(const struct nlattr *attr, void *data)
{
if (mnl_attr_type_valid(attr, CTRL_ATTR_MAX) < 0)
{
DLOG_PERROR("mnl_attr_type_valid");
return MNL_CB_ERROR;
}
switch(mnl_attr_get_type(attr))
{
case CTRL_ATTR_FAMILY_ID:
if (mnl_attr_validate(attr, MNL_TYPE_U16) < 0)
{
DLOG_PERROR("mnl_attr_validate(family_id)");
return MNL_CB_ERROR;
}
*((uint16_t*)data) = mnl_attr_get_u16(attr);
break;
}
return MNL_CB_OK;
}
static int wlan_id_cb(const struct nlmsghdr *nlh, void *data)
{
return mnl_attr_parse(nlh, sizeof(struct genlmsghdr), wlan_id_attr_cb, data);
}
static uint16_t wlan_get_family_id(struct mnl_socket* nl)
{
uint16_t id;
return netlink_genl_simple_transact(nl, GENL_ID_CTRL, NLM_F_REQUEST | NLM_F_ACK, CTRL_CMD_GETFAMILY, 1, wlan_id_prepare, wlan_id_cb, &id) ? id : 0;
}
static int wlan_info_attr_cb(const struct nlattr *attr, void *data)
{
struct wlan_interface *wlan = (struct wlan_interface *)data;
switch(mnl_attr_get_type(attr))
{
case NL80211_ATTR_IFINDEX:
if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
{
DLOG_PERROR("mnl_attr_validate(ifindex)");
return MNL_CB_ERROR;
}
wlan->ifindex = mnl_attr_get_u32(attr);
break;
case NL80211_ATTR_SSID:
if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
{
DLOG_PERROR("mnl_attr_validate(ssid)");
return MNL_CB_ERROR;
}
snprintf(wlan->ssid,sizeof(wlan->ssid),"%s",mnl_attr_get_str(attr));
break;
case NL80211_ATTR_IFNAME:
if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
{
DLOG_PERROR("mnl_attr_validate(ifname)");
return MNL_CB_ERROR;
}
snprintf(wlan->ifname,sizeof(wlan->ifname),"%s",mnl_attr_get_str(attr));
break;
}
return MNL_CB_OK;
}
static int wlan_info_cb(const struct nlmsghdr *nlh, void *data)
{
int ret;
struct wlan_interface_collection *wc = (struct wlan_interface_collection*)data;
if (wc->count>=WLAN_INTERFACE_MAX) return MNL_CB_OK;
memset(wc->wlan+wc->count,0,sizeof(wc->wlan[0]));
ret = mnl_attr_parse(nlh, sizeof(struct genlmsghdr), wlan_info_attr_cb, wc->wlan+wc->count);
if (ret>=0 && *wc->wlan[wc->count].ifname && wc->wlan[wc->count].ifindex)
{
if (*wc->wlan[wc->count].ssid)
wc->count++;
else
{
// sometimes nl80211 does not return SSID but wireless ext does
int wext_fd = socket(AF_INET, SOCK_DGRAM, 0);
if (wext_fd!=-1)
{
struct iwreq req;
snprintf(req.ifr_ifrn.ifrn_name,sizeof(req.ifr_ifrn.ifrn_name),"%s",wc->wlan[wc->count].ifname);
req.u.essid.pointer = wc->wlan[wc->count].ssid;
req.u.essid.length = sizeof(wc->wlan[wc->count].ssid);
req.u.essid.flags = 0;
if (ioctl(wext_fd, SIOCGIWESSID, &req)!=-1)
if (*wc->wlan[wc->count].ssid)
wc->count++;
close(wext_fd);
}
}
}
return ret;
}
static bool wlan_info(struct mnl_socket* nl, uint16_t wlan_family_id, struct wlan_interface_collection* w)
{
return netlink_genl_simple_transact(nl, wlan_family_id, NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP, NL80211_CMD_GET_INTERFACE, 0, NULL, wlan_info_cb, w);
}
static bool wlan_init80211(struct mnl_socket** nl)
{
if (!(*nl = mnl_socket_open(NETLINK_GENERIC)))
{
DLOG_PERROR("mnl_socket_open");
return false;
}
if (mnl_socket_bind(*nl, 0, MNL_SOCKET_AUTOPID))
{
DLOG_PERROR("mnl_socket_bind");
return false;
}
return true;
}
static void wlan_deinit80211(struct mnl_socket** nl)
{
if (*nl)
{
mnl_socket_close(*nl);
*nl = NULL;
}
}
static time_t wlan_info_last = 0;
static bool wlan_info_rate_limited(struct mnl_socket* nl, uint16_t wlan_family_id, struct wlan_interface_collection* w)
{
bool bres = true;
time_t now = time(NULL);
// do not purge too often to save resources
if (wlan_info_last != now)
{
bres = wlan_info(nl,wlan_family_id,w);
wlan_info_last = now;
}
return bres;
}
static struct mnl_socket* nl_wifi = NULL;
static uint16_t id_nl80211;
struct wlan_interface_collection wlans = { .count = 0 };
void wlan_info_deinit(void)
{
wlan_deinit80211(&nl_wifi);
}
bool wlan_info_init(void)
{
wlan_info_deinit();
if (!wlan_init80211(&nl_wifi)) return false;
if (!(id_nl80211 = wlan_get_family_id(nl_wifi)))
{
wlan_info_deinit();
return false;
}
return true;
}
bool wlan_info_get(void)
{
return wlan_info(nl_wifi, id_nl80211, &wlans);
}
bool wlan_info_get_rate_limited(void)
{
return wlan_info_rate_limited(nl_wifi, id_nl80211, &wlans);
}
#endif
#ifdef HAS_FILTER_SSID
const char *wlan_ifname2ssid(const struct wlan_interface_collection *w, const char *ifname)
{
int i;
if (ifname)
{
for (i=0;i<w->count;i++)
if (!strcmp(w->wlan[i].ifname,ifname))
return w->wlan[i].ssid;
}
return NULL;
}
const char *wlan_ifidx2ssid(const struct wlan_interface_collection *w,int ifidx)
{
int i;
for (i=0;i<w->count;i++)
if (w->wlan[i].ifindex == ifidx)
return w->wlan[i].ssid;
return NULL;
}
const char *wlan_ssid_search_ifname(const char *ifname)
{
return wlan_ifname2ssid(&wlans,ifname);
}
const char *wlan_ssid_search_ifidx(int ifidx)
{
return wlan_ifidx2ssid(&wlans,ifidx);
}
#endif
uint8_t hop_count_guess(uint8_t ttl) uint8_t hop_count_guess(uint8_t ttl)
{ {
// 18.65.168.125 ( cloudfront ) 255 // 18.65.168.125 ( cloudfront ) 255

View File

@@ -1,5 +1,6 @@
#pragma once #pragma once
#include "nfqws.h"
#include "checksum.h" #include "checksum.h"
#include "packet_queue.h" #include "packet_queue.h"
#include "pools.h" #include "pools.h"
@@ -80,6 +81,7 @@ bool prepare_tcp_segment4(
uint8_t tos, uint8_t tos,
uint16_t ip_id, uint16_t ip_id,
uint32_t fooling, uint32_t fooling,
uint32_t ts_increment,
uint32_t badseq_increment, uint32_t badseq_increment,
uint32_t badseq_ack_increment, uint32_t badseq_ack_increment,
const void *data, uint16_t len, const void *data, uint16_t len,
@@ -96,6 +98,7 @@ bool prepare_tcp_segment6(
uint8_t ttl, uint8_t ttl,
uint32_t flow_label, uint32_t flow_label,
uint32_t fooling, uint32_t fooling,
uint32_t ts_increment,
uint32_t badseq_increment, uint32_t badseq_increment,
uint32_t badseq_ack_increment, uint32_t badseq_ack_increment,
const void *data, uint16_t len, const void *data, uint16_t len,
@@ -115,6 +118,7 @@ bool prepare_tcp_segment(
uint16_t ip_id, uint16_t ip_id,
uint32_t flow_label, uint32_t flow_label,
uint32_t fooling, uint32_t fooling,
uint32_t ts_increment,
uint32_t badseq_increment, uint32_t badseq_increment,
uint32_t badseq_ack_increment, uint32_t badseq_ack_increment,
const void *data, uint16_t len, const void *data, uint16_t len,
@@ -261,7 +265,7 @@ typedef struct
int8_t delta; int8_t delta;
uint8_t min, max; uint8_t min, max;
} autottl; } autottl;
#define AUTOTTL_ENABLED(a) (!!(a).delta) #define AUTOTTL_ENABLED(a) ((a).delta || (a).min || (a).max)
uint8_t hop_count_guess(uint8_t ttl); uint8_t hop_count_guess(uint8_t ttl);
uint8_t autottl_eval(uint8_t hop_count, const autottl *attl); uint8_t autottl_eval(uint8_t hop_count, const autottl *attl);
@@ -272,3 +276,29 @@ void verdict_udp_csum_fix(uint8_t verdict, struct udphdr *udphdr, size_t transpo
void dbgprint_socket_buffers(int fd); void dbgprint_socket_buffers(int fd);
bool set_socket_buffers(int fd, int rcvbuf, int sndbuf); bool set_socket_buffers(int fd, int rcvbuf, int sndbuf);
#ifdef HAS_FILTER_SSID
struct wlan_interface
{
int ifindex;
char ifname[IFNAMSIZ], ssid[33];
};
#define WLAN_INTERFACE_MAX 16
struct wlan_interface_collection
{
int count;
struct wlan_interface wlan[WLAN_INTERFACE_MAX];
};
extern struct wlan_interface_collection wlans;
void wlan_info_deinit(void);
bool wlan_info_init(void);
bool wlan_info_get(void);
bool wlan_info_get_rate_limited(void);
const char *wlan_ssid_search_ifname(const char *ifname);
const char *wlan_ssid_search_ifidx(int ifidx);
#endif

View File

@@ -223,7 +223,7 @@ enum dpi_desync_mode desync_mode_from_string(const char *s)
static bool dp_match( static bool dp_match(
struct desync_profile *dp, struct desync_profile *dp,
uint8_t l3proto, const struct sockaddr *dest, const char *hostname, t_l7proto l7proto, uint8_t l3proto, const struct sockaddr *dest, const char *hostname, bool bNoSubdom, t_l7proto l7proto, const char *ssid,
bool *bCheckDone, bool *bCheckResult, bool *bExcluded) bool *bCheckDone, bool *bCheckResult, bool *bExcluded)
{ {
bool bHostlistsEmpty; bool bHostlistsEmpty;
@@ -241,6 +241,11 @@ static bool dp_match(
if (dp->filter_l7 && !l7_proto_match(l7proto, dp->filter_l7)) if (dp->filter_l7 && !l7_proto_match(l7proto, dp->filter_l7))
// L7 filter does not match // L7 filter does not match
return false; return false;
#ifdef HAS_FILTER_SSID
if (!LIST_EMPTY(&dp->filter_ssid) && !strlist_search(&dp->filter_ssid,ssid))
return false;
#endif
bHostlistsEmpty = PROFILE_HOSTLISTS_EMPTY(dp); bHostlistsEmpty = PROFILE_HOSTLISTS_EMPTY(dp);
if (!dp->hostlist_auto && !hostname && !bHostlistsEmpty) if (!dp->hostlist_auto && !hostname && !bHostlistsEmpty)
// avoid cpu consuming ipset check. profile cannot win if regular hostlists are present without auto hostlist and hostname is unknown. // avoid cpu consuming ipset check. profile cannot win if regular hostlists are present without auto hostlist and hostname is unknown.
@@ -262,7 +267,7 @@ static bool dp_match(
{ {
if (bCheckDone) *bCheckDone = true; if (bCheckDone) *bCheckDone = true;
bool b; bool b;
b = HostlistCheck(dp, hostname, bExcluded, true); b = HostlistCheck(dp, hostname, bNoSubdom, bExcluded, true);
if (bCheckResult) *bCheckResult = b; if (bCheckResult) *bCheckResult = b;
return b; return b;
} }
@@ -271,7 +276,7 @@ static bool dp_match(
} }
static struct desync_profile *dp_find( static struct desync_profile *dp_find(
struct desync_profile_list_head *head, struct desync_profile_list_head *head,
uint8_t l3proto, const struct sockaddr *dest, const char *hostname, t_l7proto l7proto, uint8_t l3proto, const struct sockaddr *dest, const char *hostname, bool bNoSubdom, t_l7proto l7proto, const char *ssid,
bool *bCheckDone, bool *bCheckResult, bool *bExcluded) bool *bCheckDone, bool *bCheckResult, bool *bExcluded)
{ {
struct desync_profile_list *dpl; struct desync_profile_list *dpl;
@@ -279,12 +284,12 @@ static struct desync_profile *dp_find(
{ {
char ip_port[48]; char ip_port[48];
ntop46_port(dest, ip_port,sizeof(ip_port)); ntop46_port(dest, ip_port,sizeof(ip_port));
DLOG("desync profile search for %s target=%s l7proto=%s hostname='%s'\n", proto_name(l3proto), ip_port, l7proto_str(l7proto), hostname ? hostname : ""); DLOG("desync profile search for %s target=%s l7proto=%s ssid='%s' hostname='%s'\n", proto_name(l3proto), ip_port, l7proto_str(l7proto), ssid ? ssid : "", hostname ? hostname : "");
} }
if (bCheckDone) *bCheckDone = false; if (bCheckDone) *bCheckDone = false;
LIST_FOREACH(dpl, head, next) LIST_FOREACH(dpl, head, next)
{ {
if (dp_match(&dpl->dp,l3proto,dest,hostname,l7proto,bCheckDone,bCheckResult,bExcluded)) if (dp_match(&dpl->dp,l3proto,dest,hostname,bNoSubdom,l7proto,ssid,bCheckDone,bCheckResult,bExcluded))
{ {
DLOG("desync profile %d matches\n",dpl->dp.n); DLOG("desync profile %d matches\n",dpl->dp.n);
return &dpl->dp; return &dpl->dp;
@@ -413,7 +418,7 @@ static bool auto_hostlist_retrans(t_ctrack *ctrack, uint8_t l4proto, int thresho
} }
return false; return false;
} }
static void auto_hostlist_failed(struct desync_profile *dp, const char *hostname, const char *client_ip_port, t_l7proto l7proto) static void auto_hostlist_failed(struct desync_profile *dp, const char *hostname, bool bNoSubdom, const char *client_ip_port, t_l7proto l7proto)
{ {
hostfail_pool *fail_counter; hostfail_pool *fail_counter;
@@ -437,7 +442,7 @@ static void auto_hostlist_failed(struct desync_profile *dp, const char *hostname
DLOG("auto hostlist (profile %d) : rechecking %s to avoid duplicates\n", dp->n, hostname); DLOG("auto hostlist (profile %d) : rechecking %s to avoid duplicates\n", dp->n, hostname);
bool bExcluded=false; bool bExcluded=false;
if (!HostlistCheck(dp, hostname, &bExcluded, false) && !bExcluded) if (!HostlistCheck(dp, hostname, bNoSubdom, &bExcluded, false) && !bExcluded)
{ {
DLOG("auto hostlist (profile %d) : adding %s to %s\n", dp->n, hostname, dp->hostlist_auto->filename); DLOG("auto hostlist (profile %d) : adding %s to %s\n", dp->n, hostname, dp->hostlist_auto->filename);
HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : client %s : proto %s : adding to %s", hostname, dp->n, client_ip_port, l7proto_str(l7proto), dp->hostlist_auto->filename); HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : client %s : proto %s : adding to %s", hostname, dp->n, client_ip_port, l7proto_str(l7proto), dp->hostlist_auto->filename);
@@ -472,7 +477,7 @@ static void process_retrans_fail(t_ctrack *ctrack, uint8_t proto, const struct s
if (ctrack && ctrack->dp && ctrack->hostname && auto_hostlist_retrans(ctrack, proto, ctrack->dp->hostlist_auto_retrans_threshold, client_ip_port, ctrack->l7proto)) if (ctrack && ctrack->dp && ctrack->hostname && auto_hostlist_retrans(ctrack, proto, ctrack->dp->hostlist_auto_retrans_threshold, client_ip_port, ctrack->l7proto))
{ {
HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : client %s : proto %s : retrans threshold reached", ctrack->hostname, ctrack->dp->n, client_ip_port, l7proto_str(ctrack->l7proto)); HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : client %s : proto %s : retrans threshold reached", ctrack->hostname, ctrack->dp->n, client_ip_port, l7proto_str(ctrack->l7proto));
auto_hostlist_failed(ctrack->dp, ctrack->hostname, client_ip_port, ctrack->l7proto); auto_hostlist_failed(ctrack->dp, ctrack->hostname, ctrack->hostname_is_ip, client_ip_port, ctrack->l7proto);
} }
} }
@@ -778,7 +783,7 @@ static void autottl_rediscover(t_ctrack *ctrack, const struct in_addr *a4, const
} }
} }
static bool ipcache_put_hostname(const struct in_addr *a4, const struct in6_addr *a6, const char *hostname) static bool ipcache_put_hostname(const struct in_addr *a4, const struct in6_addr *a6, const char *hostname, bool hostname_is_ip)
{ {
if (!params.cache_hostname) return true; if (!params.cache_hostname) return true;
@@ -796,11 +801,12 @@ static bool ipcache_put_hostname(const struct in_addr *a4, const struct in6_addr
DLOG_ERR("ipcache_put_hostname: out of memory\n"); DLOG_ERR("ipcache_put_hostname: out of memory\n");
return false; return false;
} }
DLOG("hostname cached: %s\n", hostname); ipc->hostname_is_ip = hostname_is_ip;
DLOG("hostname cached (is_ip=%u): %s\n", hostname_is_ip, hostname);
} }
return true; return true;
} }
static bool ipcache_get_hostname(const struct in_addr *a4, const struct in6_addr *a6, char *hostname, size_t hostname_buf_len) static bool ipcache_get_hostname(const struct in_addr *a4, const struct in6_addr *a6, char *hostname, size_t hostname_buf_len, bool *hostname_is_ip)
{ {
if (!params.cache_hostname) if (!params.cache_hostname)
{ {
@@ -815,8 +821,9 @@ static bool ipcache_get_hostname(const struct in_addr *a4, const struct in6_addr
} }
if (ipc->hostname) if (ipc->hostname)
{ {
DLOG("got cached hostname: %s\n", ipc->hostname); DLOG("got cached hostname (is_ip=%u): %s\n", ipc->hostname_is_ip, ipc->hostname);
snprintf(hostname,hostname_buf_len,"%s",ipc->hostname); snprintf(hostname,hostname_buf_len,"%s",ipc->hostname);
if (hostname_is_ip) *hostname_is_ip = ipc->hostname_is_ip;
} }
else else
*hostname = 0; *hostname = 0;
@@ -976,7 +983,7 @@ static bool tcp_orig_send(uint8_t verdict, uint32_t fwmark, const char *ifout, c
flags_orig, sack, nmss, flags_orig, sack, nmss,
dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps,
ip_has_df(dis->ip),ttl_fake,IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6), ip_has_df(dis->ip),ttl_fake,IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6),
dp->dup_fooling_mode,dp->dup_badseq_increment,dp->dup_badseq_ack_increment, dp->dup_fooling_mode,dp->dup_ts_increment,dp->dup_badseq_increment,dp->dup_badseq_ack_increment,
dis->data_payload, dis->len_payload, pkt, &len)) dis->data_payload, dis->len_payload, pkt, &len))
{ {
DLOG_ERR("dup: packet reconstruct failed\n"); DLOG_ERR("dup: packet reconstruct failed\n");
@@ -1107,9 +1114,13 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
bool bSack,DF; bool bSack,DF;
uint16_t nmss; uint16_t nmss;
char host[256]; char host[256];
const char *ifname = NULL, *ssid = NULL;
uint32_t desync_fwmark = fwmark | params.desync_fwmark; uint32_t desync_fwmark = fwmark | params.desync_fwmark;
extract_endpoints(dis->ip, dis->ip6, dis->tcp, NULL, &src, &dst); extract_endpoints(dis->ip, dis->ip6, dis->tcp, NULL, &src, &dst);
timestamps = tcp_find_timestamps(dis->tcp);
DF = ip_has_df(dis->ip);
ttl_orig = dis->ip ? dis->ip->ip_ttl : dis->ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim;
if (replay) if (replay)
{ {
@@ -1119,6 +1130,11 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
if (!ConntrackPoolDoubleSearch(&params.conntrack, dis->ip, dis->ip6, dis->tcp, NULL, &ctrack_replay, &bReverse) || bReverse) if (!ConntrackPoolDoubleSearch(&params.conntrack, dis->ip, dis->ip6, dis->tcp, NULL, &ctrack_replay, &bReverse) || bReverse)
return verdict; return verdict;
ifname = bReverse ? ifin : ifout;
#ifdef HAS_FILTER_SSID
ssid = wlan_ssid_search_ifname(ifname);
if (ssid) DLOG("found ssid for %s : %s\n",ifname,ssid);
#endif
dp = ctrack_replay->dp; dp = ctrack_replay->dp;
if (dp) if (dp)
DLOG("using cached desync profile %d\n",dp->n); DLOG("using cached desync profile %d\n",dp->n);
@@ -1126,11 +1142,11 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
{ {
if (!ctrack_replay->hostname && !bReverse) if (!ctrack_replay->hostname && !bReverse)
{ {
if (ipcache_get_hostname(dis->ip ? &dis->ip->ip_dst : NULL,dis->ip6 ? &dis->ip6->ip6_dst : NULL , host, sizeof(host)) && *host) if (ipcache_get_hostname(dis->ip ? &dis->ip->ip_dst : NULL,dis->ip6 ? &dis->ip6->ip6_dst : NULL , host, sizeof(host), &ctrack_replay->hostname_is_ip) && *host)
if (!(ctrack_replay->hostname = strdup(host))) if (!(ctrack_replay->hostname = strdup(host)))
DLOG_ERR("strdup(host): out of memory\n"); DLOG_ERR("strdup(host): out of memory\n");
} }
dp = ctrack_replay->dp = dp_find(&params.desync_profiles, IPPROTO_TCP, (struct sockaddr *)&dst, ctrack_replay->hostname, ctrack_replay->l7proto, NULL, NULL, NULL); dp = ctrack_replay->dp = dp_find(&params.desync_profiles, IPPROTO_TCP, (struct sockaddr *)&dst, ctrack_replay->hostname, ctrack_replay->hostname_is_ip, ctrack_replay->l7proto, ssid, NULL, NULL, NULL);
ctrack_replay->dp_search_complete = true; ctrack_replay->dp_search_complete = true;
} }
if (!dp) if (!dp)
@@ -1152,22 +1168,29 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
ctrack_replay = ctrack; ctrack_replay = ctrack;
} }
} }
ifname = bReverse ? ifin : ifout;
#ifdef HAS_FILTER_SSID
ssid = wlan_ssid_search_ifname(ifname);
if (ssid) DLOG("found ssid for %s : %s\n",ifname,ssid);
#endif
if (dp) if (dp)
DLOG("using cached desync profile %d\n",dp->n); DLOG("using cached desync profile %d\n",dp->n);
else if (!ctrack || !ctrack->dp_search_complete) else if (!ctrack || !ctrack->dp_search_complete)
{ {
const char *hostname = NULL; const char *hostname = NULL;
bool hostname_is_ip = false;
if (ctrack) if (ctrack)
{ {
hostname = ctrack->hostname; hostname = ctrack->hostname;
hostname_is_ip = ctrack->hostname_is_ip;
if (!hostname && !bReverse) if (!hostname && !bReverse)
{ {
if (ipcache_get_hostname(dis->ip ? &dis->ip->ip_dst : NULL,dis->ip6 ? &dis->ip6->ip6_dst : NULL , host, sizeof(host)) && *host) if (ipcache_get_hostname(dis->ip ? &dis->ip->ip_dst : NULL,dis->ip6 ? &dis->ip6->ip6_dst : NULL , host, sizeof(host), &hostname_is_ip) && *host)
if (!(hostname = ctrack_replay->hostname = strdup(host))) if (!(hostname = ctrack_replay->hostname = strdup(host)))
DLOG_ERR("strdup(host): out of memory\n"); DLOG_ERR("strdup(host): out of memory\n");
} }
} }
dp = dp_find(&params.desync_profiles, IPPROTO_TCP, (struct sockaddr *)&dst, hostname, ctrack ? ctrack->l7proto : UNKNOWN, NULL, NULL, NULL); dp = dp_find(&params.desync_profiles, IPPROTO_TCP, (struct sockaddr *)&dst, hostname, hostname_is_ip, ctrack ? ctrack->l7proto : UNKNOWN, ssid, NULL, NULL, NULL);
if (ctrack) if (ctrack)
{ {
ctrack->dp = dp; ctrack->dp = dp;
@@ -1185,23 +1208,28 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
//ConntrackPoolDump(&params.conntrack); //ConntrackPoolDump(&params.conntrack);
if (dp->wsize && tcp_synack_segment(dis->tcp)) if (tcp_synack_segment(dis->tcp))
{ {
tcp_rewrite_winsize(dis->tcp, dp->wsize, dp->wscale); if (dp->wsize)
verdict=VERDICT_MODIFY; {
tcp_rewrite_winsize(dis->tcp, dp->wsize, dp->wscale);
verdict=VERDICT_MODIFY;
}
if (dp->synack_split==SS_SYN)
{
DLOG("split SYNACK : clearing ACK bit\n");
dis->tcp->th_flags &= ~TH_ACK;
verdict=VERDICT_MODIFY;
}
} }
if (bReverse) if (bReverse)
{ {
if (ctrack) if (ctrack && !ctrack->incoming_ttl)
{ {
ttl_orig = dis->ip ? dis->ip->ip_ttl : dis->ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim; ctrack->incoming_ttl = ttl_orig;
if (!ctrack->incoming_ttl) DLOG("incoming TTL %u\n",ttl_orig);
{ autottl_rediscover(ctrack,dis->ip ? &dis->ip->ip_src : NULL,dis->ip6 ? &dis->ip6->ip6_src : NULL , ifin);
ctrack->incoming_ttl = ttl_orig;
DLOG("incoming TTL %u\n",ttl_orig);
autottl_rediscover(ctrack,dis->ip ? &dis->ip->ip_src : NULL,dis->ip6 ? &dis->ip6->ip6_src : NULL , ifin);
}
} }
// process reply packets for auto hostlist mode // process reply packets for auto hostlist mode
@@ -1244,7 +1272,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
} }
} }
if (bFail) if (bFail)
auto_hostlist_failed(dp, ctrack->hostname, client_ip_port, ctrack->l7proto); auto_hostlist_failed(dp, ctrack->hostname, ctrack->hostname_is_ip, client_ip_port, ctrack->l7proto);
else else
if (dis->len_payload) if (dis->len_payload)
auto_hostlist_reset_fail_counter(dp, ctrack->hostname, client_ip_port, ctrack->l7proto); auto_hostlist_reset_fail_counter(dp, ctrack->hostname, client_ip_port, ctrack->l7proto);
@@ -1281,6 +1309,51 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
} }
} }
if ((dp->synack_split==SS_SYNACK || dp->synack_split==SS_ACKSYN) && tcp_synack_segment(dis->tcp))
{
// reconstruct required
dis->tcp->th_flags &= ~TH_ACK;
tcp_fix_checksum(dis->tcp,dis->transport_len, dis->ip, dis->ip6);
char ss[2],i;
if (dp->synack_split==SS_SYNACK)
{
ss[0] = 'S';
ss[1] = 'A';
}
else
{
ss[0] = 'A';
ss[1] = 'S';
}
pkt1_len = sizeof(pkt1);
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, TH_ACK, false, 0, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, SCALE_NONE, timestamps,
DF,ttl_orig,IP4_TOS(dis->ip),IP4_IP_ID_FIX(dis->ip),IP6_FLOW(dis->ip6),
FOOL_NONE,0,0,0,NULL, 0, pkt1, &pkt1_len))
{
DLOG_ERR("cannot prepare split SYNACK ACK part\n");
goto send_orig;
}
for (int i=0;i<2;i++)
{
switch(ss[i])
{
case 'S':
DLOG("split SYNACK : SYN\n");
if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , dis->data_pkt, dis->len_pkt))
goto send_orig;
break;
case 'A':
DLOG("split SYNACK : ACK\n");
if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len))
goto send_orig;
break;
}
}
return VERDICT_DROP;
}
// start and cutoff limiters // start and cutoff limiters
if (!process_desync_interval(dp, ctrack)) goto send_orig; if (!process_desync_interval(dp, ctrack)) goto send_orig;
} // !replay } // !replay
@@ -1289,10 +1362,8 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
ttl_fake = (ctrack_replay && ctrack_replay->desync_autottl) ? ctrack_replay->desync_autottl : (dis->ip6 ? (dp->desync_ttl6 ? dp->desync_ttl6 : ttl_orig) : (dp->desync_ttl ? dp->desync_ttl : ttl_orig)); ttl_fake = (ctrack_replay && ctrack_replay->desync_autottl) ? ctrack_replay->desync_autottl : (dis->ip6 ? (dp->desync_ttl6 ? dp->desync_ttl6 : ttl_orig) : (dp->desync_ttl ? dp->desync_ttl : ttl_orig));
flags_orig = *((uint8_t*)dis->tcp+13); flags_orig = *((uint8_t*)dis->tcp+13);
scale_factor = tcp_find_scale_factor(dis->tcp); scale_factor = tcp_find_scale_factor(dis->tcp);
timestamps = tcp_find_timestamps(dis->tcp);
bSack = tcp_has_sack(dis->tcp); bSack = tcp_has_sack(dis->tcp);
nmss = tcp_find_mss(dis->tcp); nmss = tcp_find_mss(dis->tcp);
DF = ip_has_df(dis->ip);
if (!replay) if (!replay)
{ {
@@ -1304,7 +1375,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
pkt1_len = sizeof(pkt1); pkt1_len = sizeof(pkt1);
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, TH_SYN|TH_ACK, false, 0, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, TH_SYN|TH_ACK, false, 0, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps,
DF,ttl_fake,IP4_TOS(dis->ip),IP4_IP_ID_FIX(dis->ip),IP6_FLOW(dis->ip6), DF,ttl_fake,IP4_TOS(dis->ip),IP4_IP_ID_FIX(dis->ip),IP6_FLOW(dis->ip6),
dp->desync_fooling_mode,dp->desync_badseq_increment,dp->desync_badseq_ack_increment, dp->desync_fooling_mode,dp->desync_ts_increment,dp->desync_badseq_increment,dp->desync_badseq_ack_increment,
NULL, 0, pkt1, &pkt1_len)) NULL, 0, pkt1, &pkt1_len))
{ {
goto send_orig; goto send_orig;
@@ -1328,7 +1399,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
pkt1_len = sizeof(pkt1); pkt1_len = sizeof(pkt1);
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, bSack, nmss, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, bSack, nmss, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps,
DF,ttl_orig,IP4_TOS(dis->ip),IP4_IP_ID_FIX(dis->ip),IP6_FLOW(dis->ip6), DF,ttl_orig,IP4_TOS(dis->ip),IP4_IP_ID_FIX(dis->ip),IP6_FLOW(dis->ip6),
0,0,0, dp->fake_syndata,dp->fake_syndata_size, pkt1,&pkt1_len)) 0,0,0,0, dp->fake_syndata,dp->fake_syndata_size, pkt1,&pkt1_len))
{ {
goto send_orig; goto send_orig;
} }
@@ -1359,7 +1430,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
int multisplit_count; int multisplit_count;
int i; int i;
uint16_t ip_id; uint16_t ip_id;
bool bHaveHost=false; bool bHaveHost=false, bHostIsIp=false;
t_l7proto l7proto = UNKNOWN; t_l7proto l7proto = UNKNOWN;
if (replay) if (replay)
@@ -1480,7 +1551,11 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
if (dseq>=0x1000000 && !(dseq & 0x80000000)) ctrack->req_seq_abandoned=true; if (dseq>=0x1000000 && !(dseq & 0x80000000)) ctrack->req_seq_abandoned=true;
} }
if (bHaveHost) DLOG("hostname: %s\n",host); if (bHaveHost)
{
bHostIsIp=strip_host_to_ip(host);
DLOG("hostname: %s\n",host);
}
bool bDiscoveredL7; bool bDiscoveredL7;
if (ctrack_replay) if (ctrack_replay)
@@ -1500,6 +1575,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
{ {
free(ctrack_replay->hostname); free(ctrack_replay->hostname);
ctrack_replay->hostname=strdup(host); ctrack_replay->hostname=strdup(host);
ctrack_replay->hostname_is_ip=bHostIsIp;
if (!ctrack_replay->hostname) if (!ctrack_replay->hostname)
{ {
DLOG_ERR("hostname dup : out of memory"); DLOG_ERR("hostname dup : out of memory");
@@ -1507,7 +1583,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
goto send_orig; goto send_orig;
} }
ctrack_replay->hostname_discovered=true; ctrack_replay->hostname_discovered=true;
if (!ipcache_put_hostname(dis->ip ? &dis->ip->ip_dst : NULL,dis->ip6 ? &dis->ip6->ip6_dst : NULL , host)) if (!ipcache_put_hostname(dis->ip ? &dis->ip->ip_dst : NULL,dis->ip6 ? &dis->ip6->ip6_dst : NULL , host, bHostIsIp))
{ {
reasm_orig_cancel(ctrack); reasm_orig_cancel(ctrack);
goto send_orig; goto send_orig;
@@ -1523,7 +1599,8 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
dp = dp_find(&params.desync_profiles, IPPROTO_TCP, (struct sockaddr *)&dst, dp = dp_find(&params.desync_profiles, IPPROTO_TCP, (struct sockaddr *)&dst,
ctrack_replay ? ctrack_replay->hostname : bHaveHost ? host : NULL, ctrack_replay ? ctrack_replay->hostname : bHaveHost ? host : NULL,
ctrack_replay ? ctrack_replay->l7proto : l7proto, ctrack_replay ? ctrack_replay->hostname_is_ip : bHostIsIp,
ctrack_replay ? ctrack_replay->l7proto : l7proto, ssid,
&bCheckDone, &bCheckResult, &bCheckExcluded); &bCheckDone, &bCheckResult, &bCheckExcluded);
if (ctrack_replay) if (ctrack_replay)
{ {
@@ -1571,7 +1648,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
if (bHaveHost && !PROFILE_HOSTLISTS_EMPTY(dp)) if (bHaveHost && !PROFILE_HOSTLISTS_EMPTY(dp))
{ {
if (!bCheckDone) if (!bCheckDone)
bCheckResult = HostlistCheck(dp, host, &bCheckExcluded, false); bCheckResult = HostlistCheck(dp, host, bHostIsIp, &bCheckExcluded, false);
if (bCheckResult) if (bCheckResult)
ctrack_stop_retrans_counter(ctrack_replay); ctrack_stop_retrans_counter(ctrack_replay);
else else
@@ -1795,7 +1872,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
pkt1_len = sizeof(pkt1); pkt1_len = sizeof(pkt1);
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, false, 0, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, false, 0, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps,
DF,ttl_fake,IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6), DF,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, dp->desync_fooling_mode,dp->desync_ts_increment,dp->desync_badseq_increment,dp->desync_badseq_ack_increment,
fake_data, fake_item->size, pkt1, &pkt1_len)) fake_data, fake_item->size, pkt1, &pkt1_len))
{ {
reasm_orig_cancel(ctrack); reasm_orig_cancel(ctrack);
@@ -1819,7 +1896,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
pkt1_len = sizeof(pkt1); pkt1_len = sizeof(pkt1);
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, TH_RST | (dp->desync_mode==DESYNC_RSTACK ? TH_ACK:0), false, 0, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, TH_RST | (dp->desync_mode==DESYNC_RSTACK ? TH_ACK:0), false, 0, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps,
DF,ttl_fake,IP4_TOS(dis->ip),IP4_IP_ID_FIX(dis->ip),IP6_FLOW(dis->ip6), DF,ttl_fake,IP4_TOS(dis->ip),IP4_IP_ID_FIX(dis->ip),IP6_FLOW(dis->ip6),
dp->desync_fooling_mode,dp->desync_badseq_increment,dp->desync_badseq_ack_increment, dp->desync_fooling_mode,dp->desync_ts_increment,dp->desync_badseq_increment,dp->desync_badseq_ack_increment,
NULL, 0, pkt1, &pkt1_len)) NULL, 0, pkt1, &pkt1_len))
{ {
reasm_orig_cancel(ctrack); reasm_orig_cancel(ctrack);
@@ -1847,7 +1924,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
pkt1_len = sizeof(pkt1); pkt1_len = sizeof(pkt1);
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, false, 0, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, false, 0, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps,
DF,ttl_orig,0,0,IP6_FLOW(dis->ip6), DF,ttl_orig,0,0,IP6_FLOW(dis->ip6),
fooling_orig,0,0, fooling_orig,0,0,0,
dis->data_payload, dis->len_payload, pkt1, &pkt1_len)) dis->data_payload, dis->len_payload, pkt1, &pkt1_len))
{ {
goto send_orig; goto send_orig;
@@ -1916,7 +1993,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
net32_add(dis->tcp->th_seq,from-seqovl), dis->tcp->th_ack, net32_add(dis->tcp->th_seq,from-seqovl), dis->tcp->th_ack,
dis->tcp->th_win, scale_factor, timestamps, dis->tcp->th_win, scale_factor, timestamps,
DF,ttl_orig,IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6), DF,ttl_orig,IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6),
fooling_orig,0,0, fooling_orig,0,0,0,
seg, seg_len, pkt1, &pkt1_len)) seg, seg_len, pkt1, &pkt1_len))
goto send_orig; goto send_orig;
ip_id=IP4_IP_ID_NEXT(ip_id); ip_id=IP4_IP_ID_NEXT(ip_id);
@@ -1986,7 +2063,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
net32_add(dis->tcp->th_seq,from-seqovl), dis->tcp->th_ack, net32_add(dis->tcp->th_seq,from-seqovl), dis->tcp->th_ack,
dis->tcp->th_win, scale_factor, timestamps, dis->tcp->th_win, scale_factor, timestamps,
DF,ttl_orig,IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6), DF,ttl_orig,IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6),
fooling_orig,0,0, fooling_orig,0,0,0,
seg, seg_len, pkt1, &pkt1_len)) seg, seg_len, pkt1, &pkt1_len))
goto send_orig; goto send_orig;
ip_id=IP4_IP_ID_PREV(ip_id); ip_id=IP4_IP_ID_PREV(ip_id);
@@ -2045,7 +2122,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
fakeseg2_len = sizeof(fakeseg2); fakeseg2_len = sizeof(fakeseg2);
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, false, 0, net32_add(dis->tcp->th_seq,split_pos), dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, false, 0, net32_add(dis->tcp->th_seq,split_pos), dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps,
DF,ttl_fake,IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6), DF,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, dp->desync_fooling_mode,dp->desync_ts_increment,dp->desync_badseq_increment,dp->desync_badseq_ack_increment,
pat+split_pos, dis->len_payload-split_pos, fakeseg2, &fakeseg2_len)) pat+split_pos, dis->len_payload-split_pos, fakeseg2, &fakeseg2_len))
goto send_orig; goto send_orig;
ip_id=IP4_IP_ID_PREV(ip_id); ip_id=IP4_IP_ID_PREV(ip_id);
@@ -2057,7 +2134,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
pkt1_len = sizeof(pkt1); pkt1_len = sizeof(pkt1);
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, false, 0, net32_add(dis->tcp->th_seq , split_pos - seqovl), dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, false, 0, net32_add(dis->tcp->th_seq , split_pos - seqovl), dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps,
DF,ttl_orig,IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6), DF,ttl_orig,IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6),
fooling_orig,dp->desync_badseq_increment,dp->desync_badseq_ack_increment, fooling_orig,dp->desync_ts_increment,dp->desync_badseq_increment,dp->desync_badseq_ack_increment,
seg, seg_len, pkt1, &pkt1_len)) seg, seg_len, pkt1, &pkt1_len))
goto send_orig; goto send_orig;
ip_id=IP4_IP_ID_PREV(ip_id); ip_id=IP4_IP_ID_PREV(ip_id);
@@ -2077,7 +2154,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
seg_len = sizeof(fakeseg); seg_len = sizeof(fakeseg);
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, false, 0, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, false, 0, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps,
DF,ttl_fake,IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6), DF,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, dp->desync_fooling_mode,dp->desync_ts_increment,dp->desync_badseq_increment,dp->desync_badseq_ack_increment,
pat, split_pos, fakeseg, &seg_len)) pat, split_pos, fakeseg, &seg_len))
goto send_orig; goto send_orig;
ip_id=IP4_IP_ID_PREV(ip_id); ip_id=IP4_IP_ID_PREV(ip_id);
@@ -2089,7 +2166,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
pkt1_len = sizeof(pkt1); pkt1_len = sizeof(pkt1);
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, false, 0, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, false, 0, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps,
DF,ttl_orig,IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6), DF,ttl_orig,IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6),
fooling_orig,dp->desync_badseq_increment,dp->desync_badseq_ack_increment, fooling_orig,dp->desync_ts_increment,dp->desync_badseq_increment,dp->desync_badseq_ack_increment,
dis->data_payload, split_pos, pkt1, &pkt1_len)) dis->data_payload, split_pos, pkt1, &pkt1_len))
goto send_orig; goto send_orig;
ip_id=IP4_IP_ID_PREV(ip_id); ip_id=IP4_IP_ID_PREV(ip_id);
@@ -2125,7 +2202,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
fakeseg_len = sizeof(fakeseg); fakeseg_len = sizeof(fakeseg);
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, false, 0, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, false, 0, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps,
DF,ttl_fake,IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6), DF,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, dp->desync_fooling_mode,dp->desync_ts_increment,dp->desync_badseq_increment,dp->desync_badseq_ack_increment,
pat, split_pos, fakeseg, &fakeseg_len)) pat, split_pos, fakeseg, &fakeseg_len))
goto send_orig; goto send_orig;
ip_id=IP4_IP_ID_NEXT(ip_id); ip_id=IP4_IP_ID_NEXT(ip_id);
@@ -2161,7 +2238,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
pkt1_len = sizeof(pkt1); pkt1_len = sizeof(pkt1);
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, false, 0, net32_add(dis->tcp->th_seq,-seqovl), dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, false, 0, net32_add(dis->tcp->th_seq,-seqovl), dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps,
DF,ttl_orig,IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6), DF,ttl_orig,IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6),
fooling_orig,dp->desync_badseq_increment,dp->desync_badseq_ack_increment, fooling_orig,dp->desync_ts_increment,dp->desync_badseq_increment,dp->desync_badseq_ack_increment,
seg, seg_len, pkt1, &pkt1_len)) seg, seg_len, pkt1, &pkt1_len))
goto send_orig; goto send_orig;
ip_id=IP4_IP_ID_NEXT(ip_id); ip_id=IP4_IP_ID_NEXT(ip_id);
@@ -2192,7 +2269,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
fakeseg_len = sizeof(fakeseg); fakeseg_len = sizeof(fakeseg);
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, false, 0, net32_add(dis->tcp->th_seq,split_pos), dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, false, 0, net32_add(dis->tcp->th_seq,split_pos), dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps,
DF,ttl_fake,IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6), DF,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, dp->desync_fooling_mode,dp->desync_ts_increment,dp->desync_badseq_increment,dp->desync_badseq_ack_increment,
pat+split_pos, dis->len_payload-split_pos, fakeseg, &fakeseg_len)) pat+split_pos, dis->len_payload-split_pos, fakeseg, &fakeseg_len))
goto send_orig; goto send_orig;
ip_id=IP4_IP_ID_NEXT(ip_id); ip_id=IP4_IP_ID_NEXT(ip_id);
@@ -2204,7 +2281,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
pkt1_len = sizeof(pkt1); pkt1_len = sizeof(pkt1);
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, false, 0, net32_add(dis->tcp->th_seq,split_pos), dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, false, 0, net32_add(dis->tcp->th_seq,split_pos), dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps,
DF,ttl_orig,IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6), DF,ttl_orig,IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6),
fooling_orig,dp->desync_badseq_increment,dp->desync_badseq_ack_increment, fooling_orig,dp->desync_ts_increment,dp->desync_badseq_increment,dp->desync_badseq_ack_increment,
dis->data_payload+split_pos, dis->len_payload-split_pos, pkt1, &pkt1_len)) dis->data_payload+split_pos, dis->len_payload-split_pos, pkt1, &pkt1_len))
goto send_orig; goto send_orig;
ip_id=IP4_IP_ID_NEXT(ip_id); ip_id=IP4_IP_ID_NEXT(ip_id);
@@ -2317,6 +2394,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
bool DF; bool DF;
char host[256]; char host[256];
t_l7proto l7proto = UNKNOWN; t_l7proto l7proto = UNKNOWN;
const char *ifname = NULL, *ssid = NULL;
extract_endpoints(dis->ip, dis->ip6, NULL, dis->udp, &src, &dst); extract_endpoints(dis->ip, dis->ip6, NULL, dis->udp, &src, &dst);
@@ -2328,6 +2406,12 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
if (!ConntrackPoolDoubleSearch(&params.conntrack, dis->ip, dis->ip6, NULL, dis->udp, &ctrack_replay, &bReverse) || bReverse) if (!ConntrackPoolDoubleSearch(&params.conntrack, dis->ip, dis->ip6, NULL, dis->udp, &ctrack_replay, &bReverse) || bReverse)
return verdict; return verdict;
ifname = bReverse ? ifin : ifout;
#ifdef HAS_FILTER_SSID
ssid = wlan_ssid_search_ifname(ifname);
if (ssid) DLOG("found ssid for %s : %s\n",ifname,ssid);
#endif
dp = ctrack_replay->dp; dp = ctrack_replay->dp;
if (dp) if (dp)
DLOG("using cached desync profile %d\n",dp->n); DLOG("using cached desync profile %d\n",dp->n);
@@ -2335,11 +2419,11 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
{ {
if (!ctrack_replay->hostname && !bReverse) if (!ctrack_replay->hostname && !bReverse)
{ {
if (ipcache_get_hostname(dis->ip ? &dis->ip->ip_dst : NULL,dis->ip6 ? &dis->ip6->ip6_dst : NULL , host, sizeof(host)) && *host) if (ipcache_get_hostname(dis->ip ? &dis->ip->ip_dst : NULL,dis->ip6 ? &dis->ip6->ip6_dst : NULL , host, sizeof(host), &ctrack_replay->hostname_is_ip) && *host)
if (!(ctrack_replay->hostname = strdup(host))) if (!(ctrack_replay->hostname = strdup(host)))
DLOG_ERR("strdup(host): out of memory\n"); DLOG_ERR("strdup(host): out of memory\n");
} }
dp = ctrack_replay->dp = dp_find(&params.desync_profiles, IPPROTO_UDP, (struct sockaddr *)&dst, ctrack_replay->hostname, ctrack_replay->l7proto, NULL, NULL, NULL); dp = ctrack_replay->dp = dp_find(&params.desync_profiles, IPPROTO_UDP, (struct sockaddr *)&dst, ctrack_replay->hostname, ctrack_replay->hostname_is_ip, ctrack_replay->l7proto, ssid, NULL, NULL, NULL);
ctrack_replay->dp_search_complete = true; ctrack_replay->dp_search_complete = true;
} }
if (!dp) if (!dp)
@@ -2347,9 +2431,6 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
DLOG("matching desync profile not found\n"); DLOG("matching desync profile not found\n");
return verdict; return verdict;
} }
// no need to desync middle packets in reasm session
if (reasm_offset) goto send_orig;
} }
else else
{ {
@@ -2364,22 +2445,29 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
ctrack_replay = ctrack; ctrack_replay = ctrack;
} }
} }
ifname = bReverse ? ifin : ifout;
#ifdef HAS_FILTER_SSID
ssid = wlan_ssid_search_ifname(ifname);
if (ssid) DLOG("found ssid for %s : %s\n",ifname,ssid);
#endif
if (dp) if (dp)
DLOG("using cached desync profile %d\n",dp->n); DLOG("using cached desync profile %d\n",dp->n);
else if (!ctrack || !ctrack->dp_search_complete) else if (!ctrack || !ctrack->dp_search_complete)
{ {
const char *hostname = NULL; const char *hostname = NULL;
bool hostname_is_ip = false;
if (ctrack) if (ctrack)
{ {
hostname = ctrack->hostname; hostname = ctrack->hostname;
hostname_is_ip = ctrack->hostname_is_ip;
if (!hostname && !bReverse) if (!hostname && !bReverse)
{ {
if (ipcache_get_hostname(dis->ip ? &dis->ip->ip_dst : NULL,dis->ip6 ? &dis->ip6->ip6_dst : NULL , host, sizeof(host)) && *host) if (ipcache_get_hostname(dis->ip ? &dis->ip->ip_dst : NULL,dis->ip6 ? &dis->ip6->ip6_dst : NULL , host, sizeof(host), &hostname_is_ip) && *host)
if (!(hostname = ctrack_replay->hostname = strdup(host))) if (!(hostname = ctrack_replay->hostname = strdup(host)))
DLOG_ERR("strdup(host): out of memory\n"); DLOG_ERR("strdup(host): out of memory\n");
} }
} }
dp = dp_find(&params.desync_profiles, IPPROTO_UDP, (struct sockaddr *)&dst, hostname, ctrack ? ctrack->l7proto : UNKNOWN, NULL, NULL, NULL); dp = dp_find(&params.desync_profiles, IPPROTO_UDP, (struct sockaddr *)&dst, hostname, hostname_is_ip, ctrack ? ctrack->l7proto : UNKNOWN, ssid, NULL, NULL, NULL);
if (ctrack) if (ctrack)
{ {
ctrack->dp = dp; ctrack->dp = dp;
@@ -2427,7 +2515,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
if (dis->len_payload) if (dis->len_payload)
{ {
struct blob_collection_head *fake; struct blob_collection_head *fake;
bool bHaveHost=false; bool bHaveHost=false, bHostIsIp=false;
uint16_t ip_id; uint16_t ip_id;
if (IsQUICInitial(dis->data_payload,dis->len_payload)) if (IsQUICInitial(dis->data_payload,dis->len_payload))
@@ -2614,7 +2702,11 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
} }
} }
if (bHaveHost) DLOG("hostname: %s\n",host); if (bHaveHost)
{
bHostIsIp=strip_host_to_ip(host);
DLOG("hostname: %s\n",host);
}
bool bDiscoveredL7; bool bDiscoveredL7;
if (ctrack_replay) if (ctrack_replay)
@@ -2635,12 +2727,13 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
ctrack_replay->hostname_discovered=true; ctrack_replay->hostname_discovered=true;
free(ctrack_replay->hostname); free(ctrack_replay->hostname);
ctrack_replay->hostname=strdup(host); ctrack_replay->hostname=strdup(host);
ctrack_replay->hostname_is_ip = bHostIsIp;
if (!ctrack_replay->hostname) if (!ctrack_replay->hostname)
{ {
DLOG_ERR("hostname dup : out of memory"); DLOG_ERR("hostname dup : out of memory");
goto send_orig; goto send_orig;
} }
if (!ipcache_put_hostname(dis->ip ? &dis->ip->ip_dst : NULL,dis->ip6 ? &dis->ip6->ip6_dst : NULL , host)) if (!ipcache_put_hostname(dis->ip ? &dis->ip->ip_dst : NULL,dis->ip6 ? &dis->ip6->ip6_dst : NULL , host, bHostIsIp))
goto send_orig; goto send_orig;
} }
} }
@@ -2652,7 +2745,8 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
dp = dp_find(&params.desync_profiles, IPPROTO_UDP, (struct sockaddr *)&dst, dp = dp_find(&params.desync_profiles, IPPROTO_UDP, (struct sockaddr *)&dst,
ctrack_replay ? ctrack_replay->hostname : bHaveHost ? host : NULL, ctrack_replay ? ctrack_replay->hostname : bHaveHost ? host : NULL,
ctrack_replay ? ctrack_replay->l7proto : l7proto, ctrack_replay ? ctrack_replay->hostname_is_ip : bHostIsIp,
ctrack_replay ? ctrack_replay->l7proto : l7proto, ssid,
&bCheckDone, &bCheckResult, &bCheckExcluded); &bCheckDone, &bCheckResult, &bCheckExcluded);
if (ctrack_replay) if (ctrack_replay)
{ {
@@ -2696,7 +2790,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
if (bHaveHost && !PROFILE_HOSTLISTS_EMPTY(dp)) if (bHaveHost && !PROFILE_HOSTLISTS_EMPTY(dp))
{ {
if (!bCheckDone) if (!bCheckDone)
bCheckResult = HostlistCheck(dp, host, &bCheckExcluded, false); bCheckResult = HostlistCheck(dp, host, bHostIsIp, &bCheckExcluded, false);
if (bCheckResult) if (bCheckResult)
ctrack_stop_retrans_counter(ctrack_replay); ctrack_stop_retrans_counter(ctrack_replay);
else else
@@ -2760,6 +2854,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
break; break;
} }
case DESYNC_FAKE: case DESYNC_FAKE:
if (!reasm_offset)
{ {
struct blob_item *fake_item; struct blob_item *fake_item;
int n=0; int n=0;
@@ -2783,8 +2878,8 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
goto send_orig; goto send_orig;
ip_id=IP4_IP_ID_NEXT(ip_id); ip_id=IP4_IP_ID_NEXT(ip_id);
} }
bFake = true;
} }
bFake = true;
break; break;
case DESYNC_HOPBYHOP: case DESYNC_HOPBYHOP:
case DESYNC_DESTOPT: case DESYNC_DESTOPT:

View File

@@ -113,6 +113,71 @@ bool append_to_list_file(const char *filename, const char *s)
return bOK; return bOK;
} }
void expand_bits(void *target, const void *source, unsigned int source_bitlen, unsigned int target_bytelen)
{
unsigned int target_bitlen = target_bytelen<<3;
unsigned int bitlen = target_bitlen<source_bitlen ? target_bitlen : source_bitlen;
unsigned int bytelen = bitlen>>3;
if ((target_bytelen-bytelen)>=1) memset(target+bytelen,0,target_bytelen-bytelen);
memcpy(target,source,bytelen);
if ((bitlen &= 7)) ((uint8_t*)target)[bytelen] = ((uint8_t*)source)[bytelen] & (~((1 << (8-bitlen)) - 1));
}
// " [fd00::1]" => "fd00::1"
// "[fd00::1]:8000" => "fd00::1"
// "127.0.0.1" => "127.0.0.1"
// " 127.0.0.1:8000" => "127.0.0.1"
// " vk.com:8000" => "vk.com"
// return value: true - host is ip addr
bool strip_host_to_ip(char *host)
{
size_t l;
char *h,*p;
uint8_t addr[16];
for (h = host ; *h==' ' || *h=='\t' ; h++);
l = strlen(h);
if (l>=2)
{
if (*h=='[')
{
// ipv6 ?
for (p=++h ; *p && *p!=']' ; p++);
if (*p==']')
{
l = p-h;
memmove(host,h,l);
host[l]=0;
return inet_pton(AF_INET6, host, addr)>0;
}
}
else
{
if (inet_pton(AF_INET6, h, addr)>0)
{
// ipv6 ?
if (host!=h)
{
l = strlen(h);
memmove(host,h,l);
host[l]=0;
}
return true;
}
else
{
// ipv4 ?
for (p=h ; *p && *p!=':' ; p++);
l = p-h;
if (host!=h) memmove(host,h,l);
host[l]=0;
return inet_pton(AF_INET, host, addr)>0;
}
}
}
return false;
}
void ntop46(const struct sockaddr *sa, char *str, size_t len) void ntop46(const struct sockaddr *sa, char *str, size_t len)
{ {

View File

@@ -31,6 +31,10 @@ bool load_file_nonempty(const char *filename,void *buffer,size_t *buffer_size);
bool save_file(const char *filename, const void *buffer, size_t buffer_size); bool save_file(const char *filename, const void *buffer, size_t buffer_size);
bool append_to_list_file(const char *filename, const char *s); bool append_to_list_file(const char *filename, const char *s);
void expand_bits(void *target, const void *source, unsigned int source_bitlen, unsigned int target_bytelen);
bool strip_host_to_ip(char *host);
void print_sockaddr(const struct sockaddr *sa); void print_sockaddr(const struct sockaddr *sa);
void ntop46(const struct sockaddr *sa, char *str, size_t len); void ntop46(const struct sockaddr *sa, char *str, size_t len);
void ntop46_port(const struct sockaddr *sa, char *str, size_t len); void ntop46_port(const struct sockaddr *sa, char *str, size_t len);

View File

@@ -170,7 +170,7 @@ bool LoadAllHostLists()
static bool SearchHostList(hostlist_pool *hostlist, const char *host) static bool SearchHostList(hostlist_pool *hostlist, const char *host, bool no_match_subdomains)
{ {
if (hostlist) if (hostlist)
{ {
@@ -195,6 +195,7 @@ static bool SearchHostList(hostlist_pool *hostlist, const char *host)
} }
else else
DLOG("negative\n"); DLOG("negative\n");
if (no_match_subdomains) break;
p = strchr(p, '.'); p = strchr(p, '.');
if (p) p++; if (p) p++;
bHostFull = false; bHostFull = false;
@@ -220,7 +221,7 @@ bool HostlistsReloadCheckForProfile(const struct desync_profile *dp)
return HostlistsReloadCheck(&dp->hl_collection) && HostlistsReloadCheck(&dp->hl_collection_exclude); return HostlistsReloadCheck(&dp->hl_collection) && HostlistsReloadCheck(&dp->hl_collection_exclude);
} }
// return : true = apply fooling, false = do not apply // return : true = apply fooling, false = do not apply
static bool HostlistCheck_(const struct hostlist_collection_head *hostlists, const struct hostlist_collection_head *hostlists_exclude, const char *host, bool *excluded, bool bSkipReloadCheck) static bool HostlistCheck_(const struct hostlist_collection_head *hostlists, const struct hostlist_collection_head *hostlists_exclude, const char *host, bool no_match_subdomains, bool *excluded, bool bSkipReloadCheck)
{ {
struct hostlist_item *item; struct hostlist_item *item;
@@ -233,7 +234,7 @@ static bool HostlistCheck_(const struct hostlist_collection_head *hostlists, con
LIST_FOREACH(item, hostlists_exclude, next) LIST_FOREACH(item, hostlists_exclude, next)
{ {
DLOG("[%s] exclude ", item->hfile->filename ? item->hfile->filename : "fixed"); DLOG("[%s] exclude ", item->hfile->filename ? item->hfile->filename : "fixed");
if (SearchHostList(item->hfile->hostlist, host)) if (SearchHostList(item->hfile->hostlist, host, no_match_subdomains))
{ {
if (excluded) *excluded = true; if (excluded) *excluded = true;
return false; return false;
@@ -245,7 +246,7 @@ static bool HostlistCheck_(const struct hostlist_collection_head *hostlists, con
LIST_FOREACH(item, hostlists, next) LIST_FOREACH(item, hostlists, next)
{ {
DLOG("[%s] include ", item->hfile->filename ? item->hfile->filename : "fixed"); DLOG("[%s] include ", item->hfile->filename ? item->hfile->filename : "fixed");
if (SearchHostList(item->hfile->hostlist, host)) if (SearchHostList(item->hfile->hostlist, host, no_match_subdomains))
return true; return true;
} }
return false; return false;
@@ -255,10 +256,10 @@ static bool HostlistCheck_(const struct hostlist_collection_head *hostlists, con
// return : true = apply fooling, false = do not apply // return : true = apply fooling, false = do not apply
bool HostlistCheck(const struct desync_profile *dp, const char *host, bool *excluded, bool bSkipReloadCheck) bool HostlistCheck(const struct desync_profile *dp, const char *host, bool no_match_subdomains, bool *excluded, bool bSkipReloadCheck)
{ {
DLOG("* hostlist check for profile %d\n",dp->n); DLOG("* hostlist check for profile %d\n",dp->n);
return HostlistCheck_(&dp->hl_collection, &dp->hl_collection_exclude, host, excluded, bSkipReloadCheck); return HostlistCheck_(&dp->hl_collection, &dp->hl_collection_exclude, host, no_match_subdomains, excluded, bSkipReloadCheck);
} }

View File

@@ -9,7 +9,7 @@ bool AppendHostList(hostlist_pool **hostlist, const char *filename);
bool LoadAllHostLists(); bool LoadAllHostLists();
bool NonEmptyHostlist(hostlist_pool **hostlist); bool NonEmptyHostlist(hostlist_pool **hostlist);
// return : true = apply fooling, false = do not apply // return : true = apply fooling, false = do not apply
bool HostlistCheck(const struct desync_profile *dp,const char *host, bool *excluded, bool bSkipReloadCheck); bool HostlistCheck(const struct desync_profile *dp,const char *host, bool no_match_subdomains, bool *excluded, bool bSkipReloadCheck);
struct hostlist_file *RegisterHostlist(struct desync_profile *dp, bool bExclude, const char *filename); struct hostlist_file *RegisterHostlist(struct desync_profile *dp, bool bExclude, const char *filename);
bool HostlistsReloadCheckForProfile(const struct desync_profile *dp); bool HostlistsReloadCheckForProfile(const struct desync_profile *dp);
void HostlistsDebug(); void HostlistsDebug();

400
nfq/kavl.h Normal file
View File

@@ -0,0 +1,400 @@
/* The MIT License
Copyright (c) 2018 by Attractive Chaos <attractor@live.co.uk>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/* An example:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "kavl.h"
struct my_node {
char key;
KAVL_HEAD(struct my_node) head;
};
#define my_cmp(p, q) (((q)->key < (p)->key) - ((p)->key < (q)->key))
KAVL_INIT(my, struct my_node, head, my_cmp)
int main(void) {
const char *str = "MNOLKQOPHIA"; // from wiki, except a duplicate
struct my_node *root = 0;
int i, l = strlen(str);
for (i = 0; i < l; ++i) { // insert in the input order
struct my_node *q, *p = malloc(sizeof(*p));
p->key = str[i];
q = kavl_insert(my, &root, p, 0);
if (p != q) free(p); // if already present, free
}
kavl_itr_t(my) itr;
kavl_itr_first(my, root, &itr); // place at first
do { // traverse
const struct my_node *p = kavl_at(&itr);
putchar(p->key);
free((void*)p); // free node
} while (kavl_itr_next(my, &itr));
putchar('\n');
return 0;
}
*/
#ifndef KAVL_H
#define KAVL_H
#ifdef __STRICT_ANSI__
#define inline __inline__
#endif
#define KAVL_MAX_DEPTH 64
#define kavl_size(head, p) ((p)? (p)->head.size : 0)
#define kavl_size_child(head, q, i) ((q)->head.p[(i)]? (q)->head.p[(i)]->head.size : 0)
#define KAVL_HEAD(__type) \
struct { \
__type *p[2]; \
signed char balance; /* balance factor */ \
unsigned size; /* #elements in subtree */ \
}
#define __KAVL_FIND(suf, __scope, __type, __head, __cmp) \
__scope __type *kavl_find_##suf(const __type *root, const __type *x, unsigned *cnt_) { \
const __type *p = root; \
unsigned cnt = 0; \
while (p != 0) { \
int cmp; \
cmp = __cmp(x, p); \
if (cmp >= 0) cnt += kavl_size_child(__head, p, 0) + 1; \
if (cmp < 0) p = p->__head.p[0]; \
else if (cmp > 0) p = p->__head.p[1]; \
else break; \
} \
if (cnt_) *cnt_ = cnt; \
return (__type*)p; \
}
#define __KAVL_ROTATE(suf, __type, __head) \
/* one rotation: (a,(b,c)q)p => ((a,b)p,c)q */ \
static inline __type *kavl_rotate1_##suf(__type *p, int dir) { /* dir=0 to left; dir=1 to right */ \
int opp = 1 - dir; /* opposite direction */ \
__type *q = p->__head.p[opp]; \
unsigned size_p = p->__head.size; \
p->__head.size -= q->__head.size - kavl_size_child(__head, q, dir); \
q->__head.size = size_p; \
p->__head.p[opp] = q->__head.p[dir]; \
q->__head.p[dir] = p; \
return q; \
} \
/* two consecutive rotations: (a,((b,c)r,d)q)p => ((a,b)p,(c,d)q)r */ \
static inline __type *kavl_rotate2_##suf(__type *p, int dir) { \
int b1, opp = 1 - dir; \
__type *q = p->__head.p[opp], *r = q->__head.p[dir]; \
unsigned size_x_dir = kavl_size_child(__head, r, dir); \
r->__head.size = p->__head.size; \
p->__head.size -= q->__head.size - size_x_dir; \
q->__head.size -= size_x_dir + 1; \
p->__head.p[opp] = r->__head.p[dir]; \
r->__head.p[dir] = p; \
q->__head.p[dir] = r->__head.p[opp]; \
r->__head.p[opp] = q; \
b1 = dir == 0? +1 : -1; \
if (r->__head.balance == b1) q->__head.balance = 0, p->__head.balance = -b1; \
else if (r->__head.balance == 0) q->__head.balance = p->__head.balance = 0; \
else q->__head.balance = b1, p->__head.balance = 0; \
r->__head.balance = 0; \
return r; \
}
#define __KAVL_INSERT(suf, __scope, __type, __head, __cmp) \
__scope __type *kavl_insert_##suf(__type **root_, __type *x, unsigned *cnt_) { \
unsigned char stack[KAVL_MAX_DEPTH]; \
__type *path[KAVL_MAX_DEPTH]; \
__type *bp, *bq; \
__type *p, *q, *r = 0; /* _r_ is potentially the new root */ \
int i, which = 0, top, b1, path_len; \
unsigned cnt = 0; \
bp = *root_, bq = 0; \
/* find the insertion location */ \
for (p = bp, q = bq, top = path_len = 0; p; q = p, p = p->__head.p[which]) { \
int cmp; \
cmp = __cmp(x, p); \
if (cmp >= 0) cnt += kavl_size_child(__head, p, 0) + 1; \
if (cmp == 0) { \
if (cnt_) *cnt_ = cnt; \
return p; \
} \
if (p->__head.balance != 0) \
bq = q, bp = p, top = 0; \
stack[top++] = which = (cmp > 0); \
path[path_len++] = p; \
} \
if (cnt_) *cnt_ = cnt; \
x->__head.balance = 0, x->__head.size = 1, x->__head.p[0] = x->__head.p[1] = 0; \
if (q == 0) *root_ = x; \
else q->__head.p[which] = x; \
if (bp == 0) return x; \
for (i = 0; i < path_len; ++i) ++path[i]->__head.size; \
for (p = bp, top = 0; p != x; p = p->__head.p[stack[top]], ++top) /* update balance factors */ \
if (stack[top] == 0) --p->__head.balance; \
else ++p->__head.balance; \
if (bp->__head.balance > -2 && bp->__head.balance < 2) return x; /* no re-balance needed */ \
/* re-balance */ \
which = (bp->__head.balance < 0); \
b1 = which == 0? +1 : -1; \
q = bp->__head.p[1 - which]; \
if (q->__head.balance == b1) { \
r = kavl_rotate1_##suf(bp, which); \
q->__head.balance = bp->__head.balance = 0; \
} else r = kavl_rotate2_##suf(bp, which); \
if (bq == 0) *root_ = r; \
else bq->__head.p[bp != bq->__head.p[0]] = r; \
return x; \
}
#define __KAVL_ERASE(suf, __scope, __type, __head, __cmp) \
__scope __type *kavl_erase_##suf(__type **root_, const __type *x, unsigned *cnt_) { \
__type *p, *path[KAVL_MAX_DEPTH], fake; \
unsigned char dir[KAVL_MAX_DEPTH]; \
int i, d = 0, cmp; \
unsigned cnt = 0; \
fake.__head.p[0] = *root_, fake.__head.p[1] = 0; \
if (cnt_) *cnt_ = 0; \
if (x) { \
for (cmp = -1, p = &fake; cmp; cmp = __cmp(x, p)) { \
int which = (cmp > 0); \
if (cmp > 0) cnt += kavl_size_child(__head, p, 0) + 1; \
dir[d] = which; \
path[d++] = p; \
p = p->__head.p[which]; \
if (p == 0) { \
if (cnt_) *cnt_ = 0; \
return 0; \
} \
} \
cnt += kavl_size_child(__head, p, 0) + 1; /* because p==x is not counted */ \
} else { \
for (p = &fake, cnt = 1; p; p = p->__head.p[0]) \
dir[d] = 0, path[d++] = p; \
p = path[--d]; \
} \
if (cnt_) *cnt_ = cnt; \
for (i = 1; i < d; ++i) --path[i]->__head.size; \
if (p->__head.p[1] == 0) { /* ((1,.)2,3)4 => (1,3)4; p=2 */ \
path[d-1]->__head.p[dir[d-1]] = p->__head.p[0]; \
} else { \
__type *q = p->__head.p[1]; \
if (q->__head.p[0] == 0) { /* ((1,2)3,4)5 => ((1)2,4)5; p=3 */ \
q->__head.p[0] = p->__head.p[0]; \
q->__head.balance = p->__head.balance; \
path[d-1]->__head.p[dir[d-1]] = q; \
path[d] = q, dir[d++] = 1; \
q->__head.size = p->__head.size - 1; \
} else { /* ((1,((.,2)3,4)5)6,7)8 => ((1,(2,4)5)3,7)8; p=6 */ \
__type *r; \
int e = d++; /* backup _d_ */\
for (;;) { \
dir[d] = 0; \
path[d++] = q; \
r = q->__head.p[0]; \
if (r->__head.p[0] == 0) break; \
q = r; \
} \
r->__head.p[0] = p->__head.p[0]; \
q->__head.p[0] = r->__head.p[1]; \
r->__head.p[1] = p->__head.p[1]; \
r->__head.balance = p->__head.balance; \
path[e-1]->__head.p[dir[e-1]] = r; \
path[e] = r, dir[e] = 1; \
for (i = e + 1; i < d; ++i) --path[i]->__head.size; \
r->__head.size = p->__head.size - 1; \
} \
} \
while (--d > 0) { \
__type *q = path[d]; \
int which, other, b1 = 1, b2 = 2; \
which = dir[d], other = 1 - which; \
if (which) b1 = -b1, b2 = -b2; \
q->__head.balance += b1; \
if (q->__head.balance == b1) break; \
else if (q->__head.balance == b2) { \
__type *r = q->__head.p[other]; \
if (r->__head.balance == -b1) { \
path[d-1]->__head.p[dir[d-1]] = kavl_rotate2_##suf(q, which); \
} else { \
path[d-1]->__head.p[dir[d-1]] = kavl_rotate1_##suf(q, which); \
if (r->__head.balance == 0) { \
r->__head.balance = -b1; \
q->__head.balance = b1; \
break; \
} else r->__head.balance = q->__head.balance = 0; \
} \
} \
} \
*root_ = fake.__head.p[0]; \
return p; \
}
#define kavl_free(__type, __head, __root, __free) do { \
__type *_p, *_q; \
for (_p = __root; _p; _p = _q) { \
if (_p->__head.p[0] == 0) { \
_q = _p->__head.p[1]; \
__free(_p); \
} else { \
_q = _p->__head.p[0]; \
_p->__head.p[0] = _q->__head.p[1]; \
_q->__head.p[1] = _p; \
} \
} \
} while (0)
#define __KAVL_ITR(suf, __scope, __type, __head, __cmp) \
struct kavl_itr_##suf { \
const __type *stack[KAVL_MAX_DEPTH], **top, *right; /* _right_ points to the right child of *top */ \
}; \
__scope void kavl_itr_first_##suf(const __type *root, struct kavl_itr_##suf *itr) { \
const __type *p; \
for (itr->top = itr->stack - 1, p = root; p; p = p->__head.p[0]) \
*++itr->top = p; \
itr->right = (*itr->top)->__head.p[1]; \
} \
__scope int kavl_itr_find_##suf(const __type *root, const __type *x, struct kavl_itr_##suf *itr) { \
const __type *p = root; \
itr->top = itr->stack - 1; \
while (p != 0) { \
int cmp; \
cmp = __cmp(x, p); \
if (cmp < 0) *++itr->top = p, p = p->__head.p[0]; \
else if (cmp > 0) p = p->__head.p[1]; \
else break; \
} \
if (p) { \
*++itr->top = p; \
itr->right = p->__head.p[1]; \
return 1; \
} else if (itr->top >= itr->stack) { \
itr->right = (*itr->top)->__head.p[1]; \
return 0; \
} else return 0; \
} \
__scope int kavl_itr_next_##suf(struct kavl_itr_##suf *itr) { \
for (;;) { \
const __type *p; \
for (p = itr->right, --itr->top; p; p = p->__head.p[0]) \
*++itr->top = p; \
if (itr->top < itr->stack) return 0; \
itr->right = (*itr->top)->__head.p[1]; \
return 1; \
} \
}
/**
* Insert a node to the tree
*
* @param suf name suffix used in KAVL_INIT()
* @param proot pointer to the root of the tree (in/out: root may change)
* @param x node to insert (in)
* @param cnt number of nodes smaller than or equal to _x_; can be NULL (out)
*
* @return _x_ if not present in the tree, or the node equal to x.
*/
#define kavl_insert(suf, proot, x, cnt) kavl_insert_##suf(proot, x, cnt)
/**
* Find a node in the tree
*
* @param suf name suffix used in KAVL_INIT()
* @param root root of the tree
* @param x node value to find (in)
* @param cnt number of nodes smaller than or equal to _x_; can be NULL (out)
*
* @return node equal to _x_ if present, or NULL if absent
*/
#define kavl_find(suf, root, x, cnt) kavl_find_##suf(root, x, cnt)
/**
* Delete a node from the tree
*
* @param suf name suffix used in KAVL_INIT()
* @param proot pointer to the root of the tree (in/out: root may change)
* @param x node value to delete; if NULL, delete the first node (in)
*
* @return node removed from the tree if present, or NULL if absent
*/
#define kavl_erase(suf, proot, x, cnt) kavl_erase_##suf(proot, x, cnt)
#define kavl_erase_first(suf, proot) kavl_erase_##suf(proot, 0, 0)
#define kavl_itr_t(suf) struct kavl_itr_##suf
/**
* Place the iterator at the smallest object
*
* @param suf name suffix used in KAVL_INIT()
* @param root root of the tree
* @param itr iterator
*/
#define kavl_itr_first(suf, root, itr) kavl_itr_first_##suf(root, itr)
/**
* Place the iterator at the object equal to or greater than the query
*
* @param suf name suffix used in KAVL_INIT()
* @param root root of the tree
* @param x query (in)
* @param itr iterator (out)
*
* @return 1 if find; 0 otherwise. kavl_at(itr) is NULL if and only if query is
* larger than all objects in the tree
*/
#define kavl_itr_find(suf, root, x, itr) kavl_itr_find_##suf(root, x, itr)
/**
* Move to the next object in order
*
* @param itr iterator (modified)
*
* @return 1 if there is a next object; 0 otherwise
*/
#define kavl_itr_next(suf, itr) kavl_itr_next_##suf(itr)
/**
* Return the pointer at the iterator
*
* @param itr iterator
*
* @return pointer if present; NULL otherwise
*/
#define kavl_at(itr) ((itr)->top < (itr)->stack? 0 : *(itr)->top)
#define KAVL_INIT2(suf, __scope, __type, __head, __cmp) \
__KAVL_FIND(suf, __scope, __type, __head, __cmp) \
__KAVL_ROTATE(suf, __type, __head) \
__KAVL_INSERT(suf, __scope, __type, __head, __cmp) \
__KAVL_ERASE(suf, __scope, __type, __head, __cmp) \
__KAVL_ITR(suf, __scope, __type, __head, __cmp)
#define KAVL_INIT(suf, __type, __head, __cmp) \
KAVL_INIT2(suf,, __type, __head, __cmp)
#endif

View File

@@ -30,6 +30,7 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <syslog.h> #include <syslog.h>
#include <grp.h>
#ifdef __CYGWIN__ #ifdef __CYGWIN__
#include "win.h" #include "win.h"
@@ -296,8 +297,7 @@ static int nfq_main(void)
return 1; return 1;
} }
sec_harden(); if (params.droproot && !droproot(params.uid, params.user, params.gid, params.gid_count) || !dropcaps())
if (params.droproot && !droproot(params.uid, params.gid) || !dropcaps())
goto err; goto err;
print_id(); print_id();
if (params.droproot && !test_list_files()) if (params.droproot && !test_list_files())
@@ -306,8 +306,22 @@ static int nfq_main(void)
if (!nfq_init(&h,&qh)) if (!nfq_init(&h,&qh))
goto err; goto err;
#ifdef HAS_FILTER_SSID
if (params.filter_ssid_present)
{
if (!wlan_info_init())
{
DLOG_ERR("cannot initialize wlan info capture\n");
goto err;
}
DLOG("wlan info capture initialized\n");
}
#endif
if (params.daemon) daemonize(); if (params.daemon) daemonize();
sec_harden();
if (Fpid) if (Fpid)
{ {
if (fprintf(Fpid, "%d", getpid())<=0) if (fprintf(Fpid, "%d", getpid())<=0)
@@ -328,6 +342,11 @@ static int nfq_main(void)
while ((rd = recv(fd, buf, sizeof(buf), 0)) >= 0) while ((rd = recv(fd, buf, sizeof(buf), 0)) >= 0)
{ {
ReloadCheck(); ReloadCheck();
#ifdef HAS_FILTER_SSID
if (params.filter_ssid_present)
if (!wlan_info_get_rate_limited())
DLOG_ERR("cannot get wlan info\n");
#endif
if (rd) if (rd)
{ {
int r = nfq_handle_packet(h, (char *)buf, (int)rd); int r = nfq_handle_packet(h, (char *)buf, (int)rd);
@@ -344,9 +363,16 @@ static int nfq_main(void)
} while(e==ENOBUFS); } while(e==ENOBUFS);
nfq_deinit(&h,&qh); nfq_deinit(&h,&qh);
#ifdef HAS_FILTER_SSID
wlan_info_deinit();
#endif
return 0; return 0;
err: err:
if (Fpid) fclose(Fpid); if (Fpid) fclose(Fpid);
nfq_deinit(&h,&qh);
#ifdef HAS_FILTER_SSID
wlan_info_deinit();
#endif
return 1; return 1;
} }
@@ -421,7 +447,7 @@ static int dvt_main(void)
goto exiterr; goto exiterr;
if (params.droproot && !droproot(params.uid, params.gid)) if (params.droproot && !droproot(params.uid, params.user, params.gid, params.gid_count))
goto exiterr; goto exiterr;
print_id(); print_id();
if (params.droproot && !test_list_files()) if (params.droproot && !test_list_files())
@@ -527,13 +553,7 @@ static int win_main(const char *windivert_filter)
WINDIVERT_ADDRESS wa; WINDIVERT_ADDRESS wa;
char ifname[IFNAMSIZ]; char ifname[IFNAMSIZ];
if (params.daemon) if (params.daemon) daemonize();
{
// cygwin loses current dir
char *cwd = get_current_dir_name();
daemonize();
chdir(cwd);
}
if (*params.pidfile && !writepid(params.pidfile)) if (*params.pidfile && !writepid(params.pidfile))
{ {
@@ -648,6 +668,42 @@ static int win_main(const char *windivert_filter)
static void exit_clean(int code)
{
cleanup_params(&params);
exit(code);
}
static bool parse_uid(const char *opt, uid_t *uid, gid_t *gid, int *gid_count, int max_gids)
{
unsigned int u;
char c, *p, *e;
*gid_count=0;
if ((e = strchr(optarg,':'))) *e++=0;
if (sscanf(opt,"%u",&u)!=1) return false;
*uid = (uid_t)u;
for (p=e ; p ; )
{
if ((e = strchr(p,',')))
{
c=*e;
*e=0;
}
if (p)
{
if (sscanf(p,"%u",&u)!=1) return false;
if (*gid_count>=max_gids) return false;
gid[(*gid_count)++] = (gid_t)u;
}
if (e) *e++=c;
p = e;
}
return true;
}
static bool parse_ws_scale_factor(char *s, uint16_t *wsize, uint8_t *wscale) static bool parse_ws_scale_factor(char *s, uint16_t *wsize, uint8_t *wscale)
{ {
int v; int v;
@@ -674,45 +730,12 @@ static bool parse_ws_scale_factor(char *s, uint16_t *wsize, uint8_t *wscale)
return true; return true;
} }
#if !defined( __OpenBSD__) && !defined(__ANDROID__)
static void cleanup_args()
{
wordfree(&params.wexp);
}
#endif
static void cleanup_params(void)
{
#if !defined( __OpenBSD__) && !defined(__ANDROID__)
cleanup_args();
#endif
ConntrackPoolDestroy(&params.conntrack);
dp_list_destroy(&params.desync_profiles);
hostlist_files_destroy(&params.hostlists);
ipset_files_destroy(&params.ipsets);
ipcacheDestroy(&params.ipcache);
#ifdef __CYGWIN__
strlist_destroy(&params.ssid_filter);
strlist_destroy(&params.nlm_filter);
#endif
}
static void exit_clean(int code)
{
cleanup_params();
exit(code);
}
static bool parse_cutoff(const char *opt, unsigned int *value, char *mode) static bool parse_cutoff(const char *opt, unsigned int *value, char *mode)
{ {
*mode = (*opt=='n' || *opt=='d' || *opt=='s') ? *opt++ : 'n'; *mode = (*opt=='n' || *opt=='d' || *opt=='s') ? *opt++ : 'n';
return sscanf(opt, "%u", value)>0; return sscanf(opt, "%u", value)>0;
} }
static bool parse_badseq_increment(const char *opt, uint32_t *value) static bool parse_net32_signed(const char *opt, uint32_t *value)
{ {
if (((opt[0]=='0' && opt[1]=='x') || (opt[0]=='-' && opt[1]=='0' && opt[2]=='x')) && sscanf(opt+2+(opt[0]=='-'), "%X", (int32_t*)value)>0) if (((opt[0]=='0' && opt[1]=='x') || (opt[0]=='-' && opt[1]=='0' && opt[2]=='x')) && sscanf(opt+2+(opt[0]=='-'), "%X", (int32_t*)value)>0)
{ {
@@ -756,27 +779,33 @@ static bool parse_autottl(const char *s, autottl *t, int8_t def_delta, uint8_t d
t->max = def_max; t->max = def_max;
if (s) if (s)
{ {
max = t->max; // "-" means disable
if (*s=='+') if (s[0]=='-' && s[1]==0)
memset(t,0,sizeof(*t));
else
{ {
neg=false; max = t->max;
s++; if (*s=='+')
} else if (*s=='-') {
s++; neg=false;
switch (sscanf(s,"%u:%u-%u",&delta,&min,&max)) s++;
{ } else if (*s=='-')
case 3: s++;
if ((delta && !max) || max>255) return false; switch (sscanf(s,"%u:%u-%u",&delta,&min,&max))
t->max=(uint8_t)max; {
case 2: case 3:
if ((delta && !min) || min>255 || min>max) return false; if ((delta && !max) || max>255) return false;
t->min=(uint8_t)min; t->max=(uint8_t)max;
case 1: case 2:
if (delta>127) return false; if ((delta && !min) || min>255 || min>max) return false;
t->delta=(int8_t)(neg ? -delta : delta); t->min=(uint8_t)min;
break; case 1:
default: if (delta>127) return false;
return false; t->delta=(int8_t)(neg ? -delta : delta);
break;
default:
return false;
}
} }
} }
return true; return true;
@@ -1097,6 +1126,20 @@ static bool parse_fooling(char *opt, unsigned int *fooling_mode)
return true; return true;
} }
static bool parse_strlist(char *opt, struct str_list_head *list)
{
char *e,*p = optarg;
while (p)
{
e = strchr(p,',');
if (e) *e++=0;
if (*p && !strlist_add(list, p))
return false;
p = e;
}
return true;
}
static void split_compat(struct desync_profile *dp) static void split_compat(struct desync_profile *dp)
{ {
if (!dp->split_count) if (!dp->split_count)
@@ -1406,7 +1449,7 @@ static bool wf_make_filter(
const char *pf_tcp_src, const char *pf_tcp_dst, const char *pf_tcp_src, const char *pf_tcp_dst,
const char *pf_udp_src, const char *pf_udp_dst) const char *pf_udp_src, const char *pf_udp_dst)
{ {
char pf_dst_buf[512],iface[64]; char pf_dst_buf[8192],iface[64];
const char *pf_dst; const char *pf_dst;
const char *f_tcpin = *pf_tcp_src ? dp_list_have_autohostlist(&params.desync_profiles) ? "(" DIVERT_TCP_INBOUNDS " or (" DIVERT_HTTP_REDIRECT "))" : DIVERT_TCP_INBOUNDS : ""; const char *f_tcpin = *pf_tcp_src ? dp_list_have_autohostlist(&params.desync_profiles) ? "(" DIVERT_TCP_INBOUNDS " or (" DIVERT_HTTP_REDIRECT "))" : DIVERT_TCP_INBOUNDS : "";
const char *f_tcp_not_empty = (*pf_tcp_src && !dp_list_need_all_out(&params.desync_profiles)) ? DIVERT_TCP_NOT_EMPTY " and " : ""; const char *f_tcp_not_empty = (*pf_tcp_src && !dp_list_need_all_out(&params.desync_profiles)) ? DIVERT_TCP_NOT_EMPTY " and " : "";
@@ -1455,7 +1498,11 @@ static void exithelp(void)
#if !defined( __OpenBSD__) && !defined(__ANDROID__) #if !defined( __OpenBSD__) && !defined(__ANDROID__)
" @<config_file>|$<config_file>\t\t\t; read file for options. must be the only argument. other options are ignored.\n\n" " @<config_file>|$<config_file>\t\t\t; read file for options. must be the only argument. other options are ignored.\n\n"
#endif #endif
#ifdef __ANDROID__
" --debug=0|1|syslog|android|@<filename>\n"
#else
" --debug=0|1|syslog|@<filename>\n" " --debug=0|1|syslog|@<filename>\n"
#endif
" --version\t\t\t\t\t; print version and exit\n" " --version\t\t\t\t\t; print version and exit\n"
" --dry-run\t\t\t\t\t; verify parameters and exit with code 0 if successful\n" " --dry-run\t\t\t\t\t; verify parameters and exit with code 0 if successful\n"
" --comment=any_text\n" " --comment=any_text\n"
@@ -1468,7 +1515,7 @@ static void exithelp(void)
" --pidfile=<filename>\t\t\t\t; write pid to file\n" " --pidfile=<filename>\t\t\t\t; write pid to file\n"
#ifndef __CYGWIN__ #ifndef __CYGWIN__
" --user=<username>\t\t\t\t; drop root privs\n" " --user=<username>\t\t\t\t; drop root privs\n"
" --uid=uid[:gid]\t\t\t\t; drop root privs\n" " --uid=uid[:gid1,gid2,...]\t\t\t; drop root privs\n"
#endif #endif
#ifdef __linux__ #ifdef __linux__
" --bind-fix4\t\t\t\t\t; apply outgoing interface selection fix for generated ipv4 packets\n" " --bind-fix4\t\t\t\t\t; apply outgoing interface selection fix for generated ipv4 packets\n"
@@ -1498,6 +1545,9 @@ static void exithelp(void)
" --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-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-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|discord|stun|unknown] ; L6-L7 protocol filter. multiple comma separated values allowed.\n" " --filter-l7=[http|tls|quic|wireguard|dht|discord|stun|unknown] ; L6-L7 protocol filter. multiple comma separated values allowed.\n"
#ifdef HAS_FILTER_SSID
" --filter-ssid=ssid1[,ssid2,ssid3,...]\t\t; per profile wifi SSID filter\n"
#endif
" --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=<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-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=<filename>\t\t\t; ipset exclude filter (one ip/CIDR per line, ipv4 and ipv6 accepted, gzip supported, multiple ipsets allowed)\n"
@@ -1516,19 +1566,21 @@ static void exithelp(void)
" --wsize=<window_size>[:<scale_factor>]\t\t; set window size. 0 = do not modify. OBSOLETE !\n" " --wsize=<window_size>[:<scale_factor>]\t\t; set window size. 0 = do not modify. OBSOLETE !\n"
" --wssize=<window_size>[:<scale_factor>]\t; set window size for server. 0 = do not modify. default scale_factor = 0.\n" " --wssize=<window_size>[:<scale_factor>]\t; set window size for server. 0 = do not modify. default scale_factor = 0.\n"
" --wssize-cutoff=[n|d|s]N\t\t\t; apply server wsize only to packet numbers (n, default), data packet numbers (d), relative sequence (s) less than N\n" " --wssize-cutoff=[n|d|s]N\t\t\t; apply server wsize only to packet numbers (n, default), data packet numbers (d), relative sequence (s) less than N\n"
" --synack-split=[syn|synack|acksyn]\t\t; perform TCP split handshake : send SYN only, SYN+ACK or ACK+SYN\n"
" --orig-ttl=<int>\t\t\t\t; set TTL for original packets\n" " --orig-ttl=<int>\t\t\t\t; set TTL for original packets\n"
" --orig-ttl6=<int>\t\t\t\t; set ipv6 hop limit for original packets. by default ttl value is used\n" " --orig-ttl6=<int>\t\t\t\t; set ipv6 hop limit for original packets. by default ttl value is used\n"
" --orig-autottl=[<delta>[:<min>[-<max>]]]\t; auto ttl mode for both ipv4 and ipv6. default: +%d:%u-%u\n" " --orig-autottl=[<delta>[:<min>[-<max>]]|-]\t; auto ttl mode for both ipv4 and ipv6. default: +%d:%u-%u\n"
" --orig-autottl6=[<delta>[:<min>[-<max>]]]\t; overrides --orig-autottl for ipv6 only\n" " --orig-autottl6=[<delta>[:<min>[-<max>]]|-]\t; overrides --orig-autottl for ipv6 only\n"
" --orig-mod-start=[n|d|s]N\t\t\t; apply orig TTL mod to packet numbers (n, default), data packet numbers (d), relative sequence (s) greater or equal than N\n" " --orig-mod-start=[n|d|s]N\t\t\t; apply orig TTL mod to packet numbers (n, default), data packet numbers (d), relative sequence (s) greater or equal than N\n"
" --orig-mod-cutoff=[n|d|s]N\t\t\t; apply orig TTL mod to packet numbers (n, default), data packet numbers (d), relative sequence (s) less than N\n" " --orig-mod-cutoff=[n|d|s]N\t\t\t; apply orig TTL mod to packet numbers (n, default), data packet numbers (d), relative sequence (s) less than N\n"
" --dup=<int>\t\t\t\t\t; duplicate original packets. send N dups before original.\n" " --dup=<int>\t\t\t\t\t; duplicate original packets. send N dups before original.\n"
" --dup-replace=[0|1]\t\t\t\t; 1 or no argument means do not send original, only dups\n" " --dup-replace=[0|1]\t\t\t\t; 1 or no argument means do not send original, only dups\n"
" --dup-ttl=<int>\t\t\t\t; set TTL for dups\n" " --dup-ttl=<int>\t\t\t\t; set TTL for dups\n"
" --dup-ttl6=<int>\t\t\t\t; set ipv6 hop limit for dups. by default ttl value is used\n" " --dup-ttl6=<int>\t\t\t\t; set ipv6 hop limit for dups. by default ttl value is used\n"
" --dup-autottl=[<delta>[:<min>[-<max>]]]\t; auto ttl mode for both ipv4 and ipv6. default: %d:%u-%u\n" " --dup-autottl=[<delta>[:<min>[-<max>]]|-]\t; auto ttl mode for both ipv4 and ipv6. default: %d:%u-%u\n"
" --dup-autottl6=[<delta>[:<min>[-<max>]]]\t; overrides --dup-autottl for ipv6 only\n" " --dup-autottl6=[<delta>[:<min>[-<max>]]|-]\t; overrides --dup-autottl for ipv6 only\n"
" --dup-fooling=<mode>[,<mode>]\t\t\t; can use multiple comma separated values. modes : none md5sig badseq badsum datanoack hopbyhop hopbyhop2\n" " --dup-fooling=<mode>[,<mode>]\t\t\t; can use multiple comma separated values. modes : none md5sig badseq badsum datanoack ts hopbyhop hopbyhop2\n"
" --dup-ts-increment=<int|0xHEX>\t\t\t; ts fooling TSval signed increment for dup. default %d\n"
" --dup-badseq-increment=<int|0xHEX>\t\t; badseq fooling seq signed increment for dup. default %d\n" " --dup-badseq-increment=<int|0xHEX>\t\t; badseq fooling seq signed increment for dup. default %d\n"
" --dup-badack-increment=<int|0xHEX>\t\t; badseq fooling ackseq signed increment for dup. default %d\n" " --dup-badack-increment=<int|0xHEX>\t\t; badseq fooling ackseq signed increment for dup. default %d\n"
" --dup-start=[n|d|s]N\t\t\t\t; apply dup to packet numbers (n, default), data packet numbers (d), relative sequence (s) greater or equal than N\n" " --dup-start=[n|d|s]N\t\t\t\t; apply dup to packet numbers (n, default), data packet numbers (d), relative sequence (s) greater or equal than N\n"
@@ -1548,9 +1600,9 @@ static void exithelp(void)
#endif #endif
" --dpi-desync-ttl=<int>\t\t\t\t; set ttl for fakes packets\n" " --dpi-desync-ttl=<int>\t\t\t\t; set ttl for fakes packets\n"
" --dpi-desync-ttl6=<int>\t\t\t; set ipv6 hop limit for fake packet. by default --dpi-desync-ttl value is used.\n" " --dpi-desync-ttl6=<int>\t\t\t; set ipv6 hop limit for fake packet. by default --dpi-desync-ttl value is used.\n"
" --dpi-desync-autottl=[<delta>[:<min>[-<max>]]]\t; auto ttl mode for both ipv4 and ipv6. default: %d:%u-%u\n" " --dpi-desync-autottl=[<delta>[:<min>[-<max>]]|-] ; auto ttl mode for both ipv4 and ipv6. default: %d:%u-%u\n"
" --dpi-desync-autottl6=[<delta>[:<min>[-<max>]]] ; overrides --dpi-desync-autottl for ipv6 only\n" " --dpi-desync-autottl6=[<delta>[:<min>[-<max>]]|-] ; overrides --dpi-desync-autottl for ipv6 only\n"
" --dpi-desync-fooling=<mode>[,<mode>]\t\t; can use multiple comma separated values. modes : none md5sig badseq badsum datanoack hopbyhop hopbyhop2\n" " --dpi-desync-fooling=<mode>[,<mode>]\t\t; can use multiple comma separated values. modes : none md5sig badseq badsum datanoack ts hopbyhop hopbyhop2\n"
" --dpi-desync-repeats=<N>\t\t\t; send every desync packet N times\n" " --dpi-desync-repeats=<N>\t\t\t; send every desync packet N times\n"
" --dpi-desync-skip-nosni=0|1\t\t\t; 1(default)=do not act on ClientHello without SNI\n" " --dpi-desync-skip-nosni=0|1\t\t\t; 1(default)=do not act on ClientHello without SNI\n"
" --dpi-desync-split-pos=N|-N|marker+N|marker-N\t; comma separated list of split positions\n" " --dpi-desync-split-pos=N|-N|marker+N|marker-N\t; comma separated list of split positions\n"
@@ -1562,6 +1614,7 @@ static void exithelp(void)
" --dpi-desync-fakedsplit-pattern=<filename>|0xHEX ; fake pattern for fakedsplit/fakeddisorder\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-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-ipfrag-pos-udp=<8..%u>\t\t; ip frag position starting from the transport header. multiple of 8, default %u.\n"
" --dpi-desync-ts-increment=<int|0xHEX>\t\t; ts fooling TSval signed increment. default %d\n"
" --dpi-desync-badseq-increment=<int|0xHEX>\t; badseq fooling seq signed increment. default %d\n" " --dpi-desync-badseq-increment=<int|0xHEX>\t; badseq fooling seq signed increment. default %d\n"
" --dpi-desync-badack-increment=<int|0xHEX>\t; badseq fooling ackseq signed increment. default %d\n" " --dpi-desync-badack-increment=<int|0xHEX>\t; badseq fooling ackseq signed increment. default %d\n"
" --dpi-desync-any-protocol=0|1\t\t\t; 0(default)=desync only http and tls 1=desync any nonempty data packet\n" " --dpi-desync-any-protocol=0|1\t\t\t; 0(default)=desync only http and tls 1=desync any nonempty data packet\n"
@@ -1585,21 +1638,21 @@ static void exithelp(void)
HOSTLIST_AUTO_FAIL_THRESHOLD_DEFAULT, HOSTLIST_AUTO_FAIL_TIME_DEFAULT, HOSTLIST_AUTO_RETRANS_THRESHOLD_DEFAULT, HOSTLIST_AUTO_FAIL_THRESHOLD_DEFAULT, HOSTLIST_AUTO_FAIL_TIME_DEFAULT, HOSTLIST_AUTO_RETRANS_THRESHOLD_DEFAULT,
AUTOTTL_DEFAULT_ORIG_DELTA,AUTOTTL_DEFAULT_ORIG_MIN,AUTOTTL_DEFAULT_ORIG_MAX, AUTOTTL_DEFAULT_ORIG_DELTA,AUTOTTL_DEFAULT_ORIG_MIN,AUTOTTL_DEFAULT_ORIG_MAX,
AUTOTTL_DEFAULT_DUP_DELTA,AUTOTTL_DEFAULT_DUP_MIN,AUTOTTL_DEFAULT_DUP_MAX, AUTOTTL_DEFAULT_DUP_DELTA,AUTOTTL_DEFAULT_DUP_MIN,AUTOTTL_DEFAULT_DUP_MAX,
BADSEQ_INCREMENT_DEFAULT, BADSEQ_ACK_INCREMENT_DEFAULT, TS_INCREMENT_DEFAULT, BADSEQ_INCREMENT_DEFAULT, BADSEQ_ACK_INCREMENT_DEFAULT,
#if defined(__linux__) || defined(SO_USER_COOKIE) #if defined(__linux__) || defined(SO_USER_COOKIE)
DPI_DESYNC_FWMARK_DEFAULT,DPI_DESYNC_FWMARK_DEFAULT, DPI_DESYNC_FWMARK_DEFAULT,DPI_DESYNC_FWMARK_DEFAULT,
#endif #endif
AUTOTTL_DEFAULT_DESYNC_DELTA,AUTOTTL_DEFAULT_DESYNC_MIN,AUTOTTL_DEFAULT_DESYNC_MAX, AUTOTTL_DEFAULT_DESYNC_DELTA,AUTOTTL_DEFAULT_DESYNC_MIN,AUTOTTL_DEFAULT_DESYNC_MAX,
DPI_DESYNC_MAX_FAKE_LEN, IPFRAG_UDP_DEFAULT, DPI_DESYNC_MAX_FAKE_LEN, IPFRAG_UDP_DEFAULT,
DPI_DESYNC_MAX_FAKE_LEN, IPFRAG_TCP_DEFAULT, DPI_DESYNC_MAX_FAKE_LEN, IPFRAG_TCP_DEFAULT,
BADSEQ_INCREMENT_DEFAULT, BADSEQ_ACK_INCREMENT_DEFAULT, TS_INCREMENT_DEFAULT, BADSEQ_INCREMENT_DEFAULT, BADSEQ_ACK_INCREMENT_DEFAULT,
UDPLEN_INCREMENT_DEFAULT UDPLEN_INCREMENT_DEFAULT
); );
exit(1); exit(1);
} }
static void exithelp_clean(void) static void exithelp_clean(void)
{ {
cleanup_params(); cleanup_params(&params);
exithelp(); exithelp();
} }
@@ -1633,16 +1686,19 @@ void config_from_file(const char *filename)
void check_dp(const struct desync_profile *dp) void check_dp(const struct desync_profile *dp)
{ {
// only linux has connbytes limiter // only linux has connbytes limiter
if (dp->desync_any_proto && !dp->desync_cutoff && if ((dp->desync_any_proto && !dp->desync_cutoff &&
(dp->desync_mode==DESYNC_FAKE || dp->desync_mode==DESYNC_RST || dp->desync_mode==DESYNC_RSTACK || (dp->desync_mode==DESYNC_FAKE || dp->desync_mode==DESYNC_RST || dp->desync_mode==DESYNC_RSTACK ||
dp->desync_mode==DESYNC_FAKEDSPLIT || dp->desync_mode==DESYNC_FAKEDDISORDER || dp->desync_mode2==DESYNC_FAKEDSPLIT || dp->desync_mode2==DESYNC_FAKEDDISORDER)) dp->desync_mode==DESYNC_FAKEDSPLIT || dp->desync_mode==DESYNC_FAKEDDISORDER || dp->desync_mode2==DESYNC_FAKEDSPLIT || dp->desync_mode2==DESYNC_FAKEDDISORDER))
||
dp->dup_repeats && !dp->dup_cutoff)
{ {
#ifdef __linux__ #ifdef __linux__
DLOG_CONDUP("WARNING !!! in profile %d you are using --dpi-desync-any-protocol without --dpi-desync-cutoff\n", dp->n); DLOG_CONDUP("WARNING !!! in profile %d you are using --dpi-desync-any-protocol without --dpi-desync-cutoff or --dup without --dup-cutoff\n", dp->n);
DLOG_CONDUP("WARNING !!! it's completely ok if connbytes or payload based ip/nf tables limiter is applied. Make sure it exists.\n"); DLOG_CONDUP("WARNING !!! it's completely ok if connbytes or payload based ip/nf tables limiter is applied. Make sure it exists.\n");
#else #else
DLOG_CONDUP("WARNING !!! possible TRASH FLOOD configuration detected in profile %d\n", dp->n); DLOG_CONDUP("WARNING !!! possible TRASH FLOOD configuration detected in profile %d\n", dp->n);
DLOG_CONDUP("WARNING !!! it's highly recommended to use --dpi-desync-cutoff limiter or fakes will be sent on every processed packet\n"); DLOG_CONDUP("WARNING !!! in profile %d you are using --dpi-desync-any-protocol without --dpi-desync-cutoff or --dup without --dup-cutoff\n", dp->n);
DLOG_CONDUP("WARNING !!! fakes or dups will be sent on every processed packet\n");
DLOG_CONDUP("WARNING !!! make sure it's really what you want\n"); DLOG_CONDUP("WARNING !!! make sure it's really what you want\n");
#ifdef __CYGWIN__ #ifdef __CYGWIN__
DLOG_CONDUP("WARNING !!! in most cases this is acceptable only with custom payload based windivert filter (--wf-raw)\n"); DLOG_CONDUP("WARNING !!! in most cases this is acceptable only with custom payload based windivert filter (--wf-raw)\n");
@@ -1654,10 +1710,18 @@ void check_dp(const struct desync_profile *dp)
#define STRINGIFY(x) #x #define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x) #define TOSTRING(x) STRINGIFY(x)
#if defined(ZAPRET_GH_VER) || defined (ZAPRET_GH_HASH) #if defined(ZAPRET_GH_VER) || defined (ZAPRET_GH_HASH)
#ifdef __ANDROID__
#define PRINT_VER printf("github android version %s (%s)\n\n", TOSTRING(ZAPRET_GH_VER), TOSTRING(ZAPRET_GH_HASH))
#else
#define PRINT_VER printf("github version %s (%s)\n\n", TOSTRING(ZAPRET_GH_VER), TOSTRING(ZAPRET_GH_HASH)) #define PRINT_VER printf("github version %s (%s)\n\n", TOSTRING(ZAPRET_GH_VER), TOSTRING(ZAPRET_GH_HASH))
#endif
#else
#ifdef __ANDROID__
#define PRINT_VER printf("self-built android version %s %s\n\n", __DATE__, __TIME__)
#else #else
#define PRINT_VER printf("self-built version %s %s\n\n", __DATE__, __TIME__) #define PRINT_VER printf("self-built version %s %s\n\n", __DATE__, __TIME__)
#endif #endif
#endif
enum opt_indices { enum opt_indices {
IDX_DEBUG, IDX_DEBUG,
@@ -1678,6 +1742,7 @@ enum opt_indices {
IDX_WSIZE, IDX_WSIZE,
IDX_WSSIZE, IDX_WSSIZE,
IDX_WSSIZE_CUTOFF, IDX_WSSIZE_CUTOFF,
IDX_SYNACK_SPLIT,
IDX_CTRACK_TIMEOUTS, IDX_CTRACK_TIMEOUTS,
IDX_CTRACK_DISABLE, IDX_CTRACK_DISABLE,
IDX_IPCACHE_LIFETIME, IDX_IPCACHE_LIFETIME,
@@ -1699,6 +1764,7 @@ enum opt_indices {
IDX_DUP_AUTOTTL, IDX_DUP_AUTOTTL,
IDX_DUP_AUTOTTL6, IDX_DUP_AUTOTTL6,
IDX_DUP_FOOLING, IDX_DUP_FOOLING,
IDX_DUP_TS_INCREMENT,
IDX_DUP_BADSEQ_INCREMENT, IDX_DUP_BADSEQ_INCREMENT,
IDX_DUP_BADACK_INCREMENT, IDX_DUP_BADACK_INCREMENT,
IDX_DUP_REPLACE, IDX_DUP_REPLACE,
@@ -1725,6 +1791,7 @@ enum opt_indices {
IDX_DPI_DESYNC_FAKEDSPLIT_PATTERN, IDX_DPI_DESYNC_FAKEDSPLIT_PATTERN,
IDX_DPI_DESYNC_IPFRAG_POS_TCP, IDX_DPI_DESYNC_IPFRAG_POS_TCP,
IDX_DPI_DESYNC_IPFRAG_POS_UDP, IDX_DPI_DESYNC_IPFRAG_POS_UDP,
IDX_DPI_DESYNC_TS_INCREMENT,
IDX_DPI_DESYNC_BADSEQ_INCREMENT, IDX_DPI_DESYNC_BADSEQ_INCREMENT,
IDX_DPI_DESYNC_BADACK_INCREMENT, IDX_DPI_DESYNC_BADACK_INCREMENT,
IDX_DPI_DESYNC_ANY_PROTOCOL, IDX_DPI_DESYNC_ANY_PROTOCOL,
@@ -1758,6 +1825,9 @@ enum opt_indices {
IDX_FILTER_TCP, IDX_FILTER_TCP,
IDX_FILTER_UDP, IDX_FILTER_UDP,
IDX_FILTER_L7, IDX_FILTER_L7,
#ifdef HAS_FILTER_SSID
IDX_FILTER_SSID,
#endif
IDX_IPSET, IDX_IPSET,
IDX_IPSET_IP, IDX_IPSET_IP,
IDX_IPSET_EXCLUDE, IDX_IPSET_EXCLUDE,
@@ -1798,6 +1868,7 @@ static const struct option long_options[] = {
[IDX_WSIZE] = {"wsize", required_argument, 0, 0}, [IDX_WSIZE] = {"wsize", required_argument, 0, 0},
[IDX_WSSIZE] = {"wssize", required_argument, 0, 0}, [IDX_WSSIZE] = {"wssize", required_argument, 0, 0},
[IDX_WSSIZE_CUTOFF] = {"wssize-cutoff", required_argument, 0, 0}, [IDX_WSSIZE_CUTOFF] = {"wssize-cutoff", required_argument, 0, 0},
[IDX_SYNACK_SPLIT] = {"synack-split", optional_argument, 0, 0},
[IDX_CTRACK_TIMEOUTS] = {"ctrack-timeouts", required_argument, 0, 0}, [IDX_CTRACK_TIMEOUTS] = {"ctrack-timeouts", required_argument, 0, 0},
[IDX_CTRACK_DISABLE] = {"ctrack-disable", optional_argument, 0, 0}, [IDX_CTRACK_DISABLE] = {"ctrack-disable", optional_argument, 0, 0},
[IDX_IPCACHE_LIFETIME] = {"ipcache-lifetime", required_argument, 0, 0}, [IDX_IPCACHE_LIFETIME] = {"ipcache-lifetime", required_argument, 0, 0},
@@ -1819,6 +1890,7 @@ static const struct option long_options[] = {
[IDX_DUP_AUTOTTL] = {"dup-autottl", optional_argument, 0, 0}, [IDX_DUP_AUTOTTL] = {"dup-autottl", optional_argument, 0, 0},
[IDX_DUP_AUTOTTL6] = {"dup-autottl6", optional_argument, 0, 0}, [IDX_DUP_AUTOTTL6] = {"dup-autottl6", optional_argument, 0, 0},
[IDX_DUP_FOOLING] = {"dup-fooling", required_argument, 0, 0}, [IDX_DUP_FOOLING] = {"dup-fooling", required_argument, 0, 0},
[IDX_DUP_TS_INCREMENT] = {"dup-ts-increment", required_argument, 0, 0},
[IDX_DUP_BADSEQ_INCREMENT] = {"dup-badseq-increment", required_argument, 0, 0}, [IDX_DUP_BADSEQ_INCREMENT] = {"dup-badseq-increment", required_argument, 0, 0},
[IDX_DUP_BADACK_INCREMENT] = {"dup-badack-increment", required_argument, 0, 0}, [IDX_DUP_BADACK_INCREMENT] = {"dup-badack-increment", required_argument, 0, 0},
[IDX_DUP_REPLACE] = {"dup-replace", optional_argument, 0, 0}, [IDX_DUP_REPLACE] = {"dup-replace", optional_argument, 0, 0},
@@ -1845,6 +1917,7 @@ static const struct option long_options[] = {
[IDX_DPI_DESYNC_FAKEDSPLIT_PATTERN] = {"dpi-desync-fakedsplit-pattern", required_argument, 0, 0}, [IDX_DPI_DESYNC_FAKEDSPLIT_PATTERN] = {"dpi-desync-fakedsplit-pattern", required_argument, 0, 0},
[IDX_DPI_DESYNC_IPFRAG_POS_TCP] = {"dpi-desync-ipfrag-pos-tcp", required_argument, 0, 0}, [IDX_DPI_DESYNC_IPFRAG_POS_TCP] = {"dpi-desync-ipfrag-pos-tcp", required_argument, 0, 0},
[IDX_DPI_DESYNC_IPFRAG_POS_UDP] = {"dpi-desync-ipfrag-pos-udp", required_argument, 0, 0}, [IDX_DPI_DESYNC_IPFRAG_POS_UDP] = {"dpi-desync-ipfrag-pos-udp", required_argument, 0, 0},
[IDX_DPI_DESYNC_TS_INCREMENT] = {"dpi-desync-ts-increment", required_argument, 0, 0},
[IDX_DPI_DESYNC_BADSEQ_INCREMENT] = {"dpi-desync-badseq-increment", required_argument, 0, 0}, [IDX_DPI_DESYNC_BADSEQ_INCREMENT] = {"dpi-desync-badseq-increment", required_argument, 0, 0},
[IDX_DPI_DESYNC_BADACK_INCREMENT] = {"dpi-desync-badack-increment", required_argument, 0, 0}, [IDX_DPI_DESYNC_BADACK_INCREMENT] = {"dpi-desync-badack-increment", required_argument, 0, 0},
[IDX_DPI_DESYNC_ANY_PROTOCOL] = {"dpi-desync-any-protocol", optional_argument, 0, 0}, [IDX_DPI_DESYNC_ANY_PROTOCOL] = {"dpi-desync-any-protocol", optional_argument, 0, 0},
@@ -1878,6 +1951,9 @@ static const struct option long_options[] = {
[IDX_FILTER_TCP] = {"filter-tcp", required_argument, 0, 0}, [IDX_FILTER_TCP] = {"filter-tcp", required_argument, 0, 0},
[IDX_FILTER_UDP] = {"filter-udp", required_argument, 0, 0}, [IDX_FILTER_UDP] = {"filter-udp", required_argument, 0, 0},
[IDX_FILTER_L7] = {"filter-l7", required_argument, 0, 0}, [IDX_FILTER_L7] = {"filter-l7", required_argument, 0, 0},
#ifdef HAS_FILTER_SSID
[IDX_FILTER_SSID] = {"filter-ssid", required_argument, 0, 0},
#endif
[IDX_IPSET] = {"ipset", required_argument, 0, 0}, [IDX_IPSET] = {"ipset", required_argument, 0, 0},
[IDX_IPSET_IP] = {"ipset-ip", required_argument, 0, 0}, [IDX_IPSET_IP] = {"ipset-ip", required_argument, 0, 0},
[IDX_IPSET_EXCLUDE] = {"ipset-exclude", required_argument, 0, 0}, [IDX_IPSET_EXCLUDE] = {"ipset-exclude", required_argument, 0, 0},
@@ -1917,7 +1993,7 @@ int main(int argc, char **argv)
struct hostlist_file *anon_hl = NULL, *anon_hl_exclude = NULL; struct hostlist_file *anon_hl = NULL, *anon_hl_exclude = NULL;
struct ipset_file *anon_ips = NULL, *anon_ips_exclude = NULL; struct ipset_file *anon_ips = NULL, *anon_ips_exclude = NULL;
#ifdef __CYGWIN__ #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]; char windivert_filter[16384], wf_pf_tcp_src[4096], wf_pf_tcp_dst[4096], wf_pf_udp_src[4096], wf_pf_udp_dst[4096], wf_save_file[256];
bool wf_ipv4=true, wf_ipv6=true; bool wf_ipv4=true, wf_ipv6=true;
unsigned int IfIdx=0, SubIfIdx=0; unsigned int IfIdx=0, SubIfIdx=0;
unsigned int hash_wf_tcp=0,hash_wf_udp=0,hash_wf_raw=0,hash_ssid_filter=0,hash_nlm_filter=0; unsigned int hash_wf_tcp=0,hash_wf_udp=0,hash_wf_raw=0,hash_ssid_filter=0,hash_nlm_filter=0;
@@ -1962,9 +2038,10 @@ int main(int argc, char **argv)
LIST_INIT(&params.ssid_filter); LIST_INIT(&params.ssid_filter);
LIST_INIT(&params.nlm_filter); LIST_INIT(&params.nlm_filter);
#else #else
if (can_drop_root()) // are we root ? if (can_drop_root())
{ {
params.uid = params.gid = 0x7FFFFFFF; // default uid:gid params.uid = params.gid[0] = 0x7FFFFFFF; // default uid:gid
params.gid_count = 1;
params.droproot = true; params.droproot = true;
} }
#endif #endif
@@ -2012,10 +2089,22 @@ int main(int argc, char **argv)
params.debug_target = LOG_TARGET_SYSLOG; params.debug_target = LOG_TARGET_SYSLOG;
openlog(progname,LOG_PID,LOG_USER); openlog(progname,LOG_PID,LOG_USER);
} }
#ifdef __ANDROID__
else if (!strcmp(optarg,"android"))
{
if (!params.debug) params.debug = 1;
params.debug_target = LOG_TARGET_ANDROID;
}
#endif
else if (optarg[0]>='0' && optarg[0]<='1')
{
params.debug = atoi(optarg);
params.debug_target = LOG_TARGET_CONSOLE;
}
else else
{ {
params.debug = !!atoi(optarg); fprintf(stderr, "invalid debug mode : %s\n", optarg);
params.debug_target = LOG_TARGET_CONSOLE; exit_clean(1);
} }
} }
else else
@@ -2062,26 +2151,38 @@ int main(int argc, char **argv)
break; break;
#ifndef __CYGWIN__ #ifndef __CYGWIN__
case IDX_USER: case IDX_USER:
{
free(params.user); params.user=NULL;
struct passwd *pwd = getpwnam(optarg);
if (!pwd)
{ {
struct passwd *pwd = getpwnam(optarg); DLOG_ERR("non-existent username supplied\n");
if (!pwd)
{
DLOG_ERR("non-existent username supplied\n");
exit_clean(1);
}
params.uid = pwd->pw_uid;
params.gid = pwd->pw_gid;
params.droproot = true;
}
break;
case IDX_UID:
params.gid = 0x7FFFFFFF; // default gid. drop gid=0
params.droproot = true;
if (sscanf(optarg, "%u:%u", &params.uid, &params.gid)<1)
{
DLOG_ERR("--uid should be : uid[:gid]\n");
exit_clean(1); exit_clean(1);
} }
params.uid = pwd->pw_uid;
params.gid[0]=pwd->pw_gid;
params.gid_count=1;
if (!(params.user=strdup(optarg)))
{
DLOG_ERR("strdup: out of memory\n");
exit_clean(1);
}
params.droproot = true;
break;
}
case IDX_UID:
free(params.user); params.user=NULL;
if (!parse_uid(optarg,&params.uid,params.gid,&params.gid_count,MAX_GIDS))
{
DLOG_ERR("--uid should be : uid[:gid,gid,...]\n");
exit_clean(1);
}
if (!params.gid_count)
{
params.gid[0] = 0x7FFFFFFF;
params.gid_count = 1;
}
params.droproot = true;
break; break;
#endif #endif
case IDX_WSIZE: case IDX_WSIZE:
@@ -2099,6 +2200,21 @@ int main(int argc, char **argv)
exit_clean(1); exit_clean(1);
} }
break; break;
case IDX_SYNACK_SPLIT:
dp->synack_split = SS_SYN;
if (optarg)
{
if (!strcmp(optarg,"synack"))
dp->synack_split = SS_SYNACK;
else if (!strcmp(optarg,"acksyn"))
dp->synack_split = SS_ACKSYN;
else if (strcmp(optarg,"syn"))
{
DLOG_ERR("invalid synack-split value\n");
exit_clean(1);
}
}
break;
case IDX_CTRACK_TIMEOUTS: case IDX_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) if (sscanf(optarg, "%u:%u:%u:%u", &params.ctrack_t_syn, &params.ctrack_t_est, &params.ctrack_t_fin, &params.ctrack_t_udp)<3)
{ {
@@ -2250,15 +2366,22 @@ int main(int argc, char **argv)
exit_clean(1); exit_clean(1);
} }
break; break;
case IDX_DUP_TS_INCREMENT:
if (!parse_net32_signed(optarg,&dp->dup_ts_increment))
{
DLOG_ERR("dup-ts-increment should be signed decimal or signed 0xHEX\n");
exit_clean(1);
}
break;
case IDX_DUP_BADSEQ_INCREMENT: case IDX_DUP_BADSEQ_INCREMENT:
if (!parse_badseq_increment(optarg,&dp->dup_badseq_increment)) if (!parse_net32_signed(optarg,&dp->dup_badseq_increment))
{ {
DLOG_ERR("dup-badseq-increment should be signed decimal or signed 0xHEX\n"); DLOG_ERR("dup-badseq-increment should be signed decimal or signed 0xHEX\n");
exit_clean(1); exit_clean(1);
} }
break; break;
case IDX_DUP_BADACK_INCREMENT: case IDX_DUP_BADACK_INCREMENT:
if (!parse_badseq_increment(optarg,&dp->dup_badseq_ack_increment)) if (!parse_net32_signed(optarg,&dp->dup_badseq_ack_increment))
{ {
DLOG_ERR("dup-badack-increment should be signed decimal or signed 0xHEX\n"); DLOG_ERR("dup-badack-increment should be signed decimal or signed 0xHEX\n");
exit_clean(1); exit_clean(1);
@@ -2449,15 +2572,22 @@ int main(int argc, char **argv)
exit_clean(1); exit_clean(1);
} }
break; break;
case IDX_DPI_DESYNC_TS_INCREMENT:
if (!parse_net32_signed(optarg,&dp->desync_ts_increment))
{
DLOG_ERR("dpi-desync-ts-increment should be signed decimal or signed 0xHEX\n");
exit_clean(1);
}
break;
case IDX_DPI_DESYNC_BADSEQ_INCREMENT: case IDX_DPI_DESYNC_BADSEQ_INCREMENT:
if (!parse_badseq_increment(optarg,&dp->desync_badseq_increment)) if (!parse_net32_signed(optarg,&dp->desync_badseq_increment))
{ {
DLOG_ERR("dpi-desync-badseq-increment should be signed decimal or signed 0xHEX\n"); DLOG_ERR("dpi-desync-badseq-increment should be signed decimal or signed 0xHEX\n");
exit_clean(1); exit_clean(1);
} }
break; break;
case IDX_DPI_DESYNC_BADACK_INCREMENT: case IDX_DPI_DESYNC_BADACK_INCREMENT:
if (!parse_badseq_increment(optarg,&dp->desync_badseq_ack_increment)) if (!parse_net32_signed(optarg,&dp->desync_badseq_ack_increment))
{ {
DLOG_ERR("dpi-desync-badack-increment should be signed decimal or signed 0xHEX\n"); DLOG_ERR("dpi-desync-badack-increment should be signed decimal or signed 0xHEX\n");
exit_clean(1); exit_clean(1);
@@ -2715,6 +2845,16 @@ int main(int argc, char **argv)
exit_clean(1); exit_clean(1);
} }
break; break;
#ifdef HAS_FILTER_SSID
case IDX_FILTER_SSID:
if (!parse_strlist(optarg,&dp->filter_ssid))
{
DLOG_ERR("strlist_add failed\n");
exit_clean(1);
}
params.filter_ssid_present = true;
break;
#endif
case IDX_IPSET: case IDX_IPSET:
if (bSkip) break; if (bSkip) break;
if (!RegisterIpset(dp, false, optarg)) if (!RegisterIpset(dp, false, optarg))
@@ -2819,38 +2959,18 @@ int main(int argc, char **argv)
break; break;
case IDX_SSID_FILTER: case IDX_SSID_FILTER:
hash_ssid_filter=hash_jen(optarg,strlen(optarg)); hash_ssid_filter=hash_jen(optarg,strlen(optarg));
if (!parse_strlist(optarg,&params.ssid_filter))
{ {
char *e,*p = optarg; DLOG_ERR("strlist_add failed\n");
while (p) exit_clean(1);
{
e = strchr(p,',');
if (e) *e++=0;
if (*p && !strlist_add(&params.ssid_filter, p))
{
DLOG_ERR("strlist_add failed\n");
exit_clean(1);
}
p = e;
}
} }
break; break;
case IDX_NLM_FILTER: case IDX_NLM_FILTER:
hash_nlm_filter=hash_jen(optarg,strlen(optarg)); hash_nlm_filter=hash_jen(optarg,strlen(optarg));
if (!parse_strlist(optarg,&params.nlm_filter))
{ {
char *e,*p = optarg; DLOG_ERR("strlist_add failed\n");
while (p) exit_clean(1);
{
e = strchr(p,',');
if (e) *e++=0;
if (*p && !strlist_add(&params.nlm_filter, p))
{
DLOG_ERR("strlist_add failed\n");
exit_clean(1);
}
p = e;
}
} }
break; break;
case IDX_NLM_LIST: case IDX_NLM_LIST:
@@ -2875,7 +2995,7 @@ int main(int argc, char **argv)
// do not need args from file anymore // do not need args from file anymore
#if !defined( __OpenBSD__) && !defined(__ANDROID__) #if !defined( __OpenBSD__) && !defined(__ANDROID__)
cleanup_args(); cleanup_args(&params);
#endif #endif
argv=NULL; argc=0; argv=NULL; argc=0;
@@ -3015,6 +3135,20 @@ int main(int argc, char **argv)
if (bDry) if (bDry)
{ {
#ifndef __CYGWIN__
if (params.droproot)
{
if (!droproot(params.uid,params.user,params.gid,params.gid_count))
exit_clean(1);
#ifdef __linux__
if (!dropcaps())
exit_clean(1);
#endif
print_id();
if (!test_list_files())
exit_clean(1);
}
#endif
DLOG_CONDUP("command line parameters verified\n"); DLOG_CONDUP("command line parameters verified\n");
exit_clean(0); exit_clean(0);
} }
@@ -3039,7 +3173,7 @@ int main(int argc, char **argv)
#endif #endif
ex: ex:
rawsend_cleanup(); rawsend_cleanup();
cleanup_params(); cleanup_params(&params);
#ifdef __CYGWIN__ #ifdef __CYGWIN__
if (hMutexArg) if (hMutexArg)
{ {

View File

@@ -2,6 +2,10 @@
#include <stdbool.h> #include <stdbool.h>
#ifdef __linux__
#define HAS_FILTER_SSID 1
#endif
#ifdef __CYGWIN__ #ifdef __CYGWIN__
extern bool bQuit; extern bool bQuit;
#endif #endif

View File

@@ -3,6 +3,9 @@
#include <stdarg.h> #include <stdarg.h>
#include <syslog.h> #include <syslog.h>
#include <errno.h> #include <errno.h>
#ifdef __ANDROID__
#include <android/log.h>
#endif
#include "pools.h" #include "pools.h"
#include "desync.h" #include "desync.h"
@@ -40,18 +43,47 @@ int DLOG_FILENAME(const char *filename, const char *format, va_list args)
return r; return r;
} }
static char syslog_buf[1024]; typedef void (*f_log_function)(int priority, const char *line);
static size_t syslog_buf_sz=0;
static void syslog_buffered(int priority, const char *format, va_list args) static char log_buf[1024];
static size_t log_buf_sz=0;
static void syslog_log_function(int priority, const char *line)
{ {
if (vsnprintf(syslog_buf+syslog_buf_sz,sizeof(syslog_buf)-syslog_buf_sz,format,args)>0) syslog(priority,"%s",log_buf);
}
#ifdef __ANDROID__
static enum android_LogPriority syslog_priority_to_android(int priority)
{
enum android_LogPriority ap;
switch(priority)
{ {
syslog_buf_sz=strlen(syslog_buf); case LOG_INFO:
case LOG_NOTICE: ap=ANDROID_LOG_INFO; break;
case LOG_ERR: ap=ANDROID_LOG_ERROR; break;
case LOG_WARNING: ap=ANDROID_LOG_WARN; break;
case LOG_EMERG:
case LOG_ALERT:
case LOG_CRIT: ap=ANDROID_LOG_FATAL; break;
case LOG_DEBUG: ap=ANDROID_LOG_DEBUG; break;
default: ap=ANDROID_LOG_UNKNOWN;
}
return ap;
}
static void android_log_function(int priority, const char *line)
{
__android_log_print(syslog_priority_to_android(priority), progname, "%s", line);
}
#endif
static void log_buffered(f_log_function log_function, int syslog_priority, const char *format, va_list args)
{
if (vsnprintf(log_buf+log_buf_sz,sizeof(log_buf)-log_buf_sz,format,args)>0)
{
log_buf_sz=strlen(log_buf);
// log when buffer is full or buffer ends with \n // log when buffer is full or buffer ends with \n
if (syslog_buf_sz>=(sizeof(syslog_buf)-1) || (syslog_buf_sz && syslog_buf[syslog_buf_sz-1]=='\n')) if (log_buf_sz>=(sizeof(log_buf)-1) || (log_buf_sz && log_buf[log_buf_sz-1]=='\n'))
{ {
syslog(priority,"%s",syslog_buf); log_function(syslog_priority,log_buf);
syslog_buf_sz = 0; log_buf_sz = 0;
} }
} }
} }
@@ -79,9 +111,16 @@ static int DLOG_VA(const char *format, int syslog_priority, bool condup, va_list
break; break;
case LOG_TARGET_SYSLOG: case LOG_TARGET_SYSLOG:
// skip newlines // skip newlines
syslog_buffered(syslog_priority,format,args); log_buffered(syslog_log_function,syslog_priority,format,args);
r = 1; r = 1;
break; break;
#ifdef __ANDROID__
case LOG_TARGET_ANDROID:
// skip newlines
log_buffered(android_log_function,syslog_priority,format,args);
r = 1;
break;
#endif
default: default:
break; break;
} }
@@ -188,6 +227,7 @@ void dp_init(struct desync_profile *dp)
dp->fake_syndata_size = 16; dp->fake_syndata_size = 16;
dp->wscale=-1; // default - dont change scale factor (client) dp->wscale=-1; // default - dont change scale factor (client)
dp->desync_ttl6 = dp->dup_ttl6 = dp->orig_mod_ttl6 = 0xFF; // unused dp->desync_ttl6 = dp->dup_ttl6 = dp->orig_mod_ttl6 = 0xFF; // unused
dp->desync_ts_increment = dp->dup_ts_increment = TS_INCREMENT_DEFAULT;
dp->desync_badseq_increment = dp->dup_badseq_increment = BADSEQ_INCREMENT_DEFAULT; dp->desync_badseq_increment = dp->dup_badseq_increment = BADSEQ_INCREMENT_DEFAULT;
dp->desync_badseq_ack_increment = dp->dup_badseq_ack_increment = BADSEQ_ACK_INCREMENT_DEFAULT; dp->desync_badseq_ack_increment = dp->dup_badseq_ack_increment = BADSEQ_ACK_INCREMENT_DEFAULT;
dp->wssize_cutoff_mode = dp->desync_start_mode = dp->desync_cutoff_mode = dp->dup_start_mode = dp->dup_cutoff_mode = dp->orig_mod_start_mode = dp->orig_mod_cutoff_mode = 'n'; // packet number by default dp->wssize_cutoff_mode = dp->desync_start_mode = dp->desync_cutoff_mode = dp->dup_start_mode = dp->dup_cutoff_mode = dp->orig_mod_start_mode = dp->orig_mod_cutoff_mode = 'n'; // packet number by default
@@ -263,6 +303,9 @@ static void dp_clear_dynamic(struct desync_profile *dp)
ipset_collection_destroy(&dp->ips_collection_exclude); ipset_collection_destroy(&dp->ips_collection_exclude);
port_filters_destroy(&dp->pf_tcp); port_filters_destroy(&dp->pf_tcp);
port_filters_destroy(&dp->pf_udp); port_filters_destroy(&dp->pf_udp);
#ifdef HAS_FILTER_SSID
strlist_destroy(&dp->filter_ssid);
#endif
HostFailPoolDestroy(&dp->hostlist_auto_fail_counters); HostFailPoolDestroy(&dp->hostlist_auto_fail_counters);
struct blob_collection_head **fake,*fakes[] = {&dp->fake_http, &dp->fake_tls, &dp->fake_unknown, &dp->fake_unknown_udp, &dp->fake_quic, &dp->fake_wg, &dp->fake_dht, &dp->fake_discord, &dp->fake_stun, NULL}; struct blob_collection_head **fake,*fakes[] = {&dp->fake_http, &dp->fake_tls, &dp->fake_unknown, &dp->fake_unknown_udp, &dp->fake_quic, &dp->fake_wg, &dp->fake_dht, &dp->fake_discord, &dp->fake_stun, NULL};
for(fake=fakes;*fake;fake++) blob_collection_destroy(*fake); for(fake=fakes;*fake;fake++) blob_collection_destroy(*fake);
@@ -303,3 +346,32 @@ bool dp_list_need_all_out(struct desync_profile_list_head *head)
return true; return true;
return false; return false;
} }
#if !defined( __OpenBSD__) && !defined(__ANDROID__)
void cleanup_args(struct params_s *params)
{
wordfree(&params->wexp);
}
#endif
void cleanup_params(struct params_s *params)
{
#if !defined( __OpenBSD__) && !defined(__ANDROID__)
cleanup_args(params);
#endif
ConntrackPoolDestroy(&params->conntrack);
dp_list_destroy(&params->desync_profiles);
hostlist_files_destroy(&params->hostlists);
ipset_files_destroy(&params->ipsets);
ipcacheDestroy(&params->ipcache);
#ifdef __CYGWIN__
strlist_destroy(&params->ssid_filter);
strlist_destroy(&params->nlm_filter);
#else
free(params->user); params->user=NULL;
#endif
}

View File

@@ -1,5 +1,6 @@
#pragma once #pragma once
#include "nfqws.h"
#include "pools.h" #include "pools.h"
#include "conntrack.h" #include "conntrack.h"
#include "desync.h" #include "desync.h"
@@ -27,6 +28,8 @@
#define BADSEQ_INCREMENT_DEFAULT -10000 #define BADSEQ_INCREMENT_DEFAULT -10000
#define BADSEQ_ACK_INCREMENT_DEFAULT -66000 #define BADSEQ_ACK_INCREMENT_DEFAULT -66000
#define TS_INCREMENT_DEFAULT -600000
#define IPFRAG_UDP_DEFAULT 8 #define IPFRAG_UDP_DEFAULT 8
#define IPFRAG_TCP_DEFAULT 32 #define IPFRAG_TCP_DEFAULT 32
@@ -63,7 +66,9 @@
#define FAKE_MAX_TCP 1460 #define FAKE_MAX_TCP 1460
#define FAKE_MAX_UDP 1472 #define FAKE_MAX_UDP 1472
enum log_target { LOG_TARGET_CONSOLE=0, LOG_TARGET_FILE, LOG_TARGET_SYSLOG }; #define MAX_GIDS 64
enum log_target { LOG_TARGET_CONSOLE=0, LOG_TARGET_FILE, LOG_TARGET_SYSLOG, LOG_TARGET_ANDROID };
struct fake_tls_mod_cache struct fake_tls_mod_cache
{ {
@@ -75,6 +80,8 @@ struct fake_tls_mod
uint32_t mod; uint32_t mod;
}; };
typedef enum {SS_NONE=0,SS_SYN,SS_SYNACK,SS_ACKSYN} t_synack_split;
struct desync_profile struct desync_profile
{ {
int n; // number of the profile int n; // number of the profile
@@ -84,6 +91,8 @@ struct desync_profile
char wssize_cutoff_mode; // n - packets, d - data packets, s - relative sequence char wssize_cutoff_mode; // n - packets, d - data packets, s - relative sequence
unsigned int wssize_cutoff; unsigned int wssize_cutoff;
t_synack_split synack_split;
bool hostcase, hostnospace, domcase, methodeol; bool hostcase, hostnospace, domcase, methodeol;
char hostspell[4]; char hostspell[4];
enum dpi_desync_mode desync_mode0,desync_mode,desync_mode2; enum dpi_desync_mode desync_mode0,desync_mode,desync_mode2;
@@ -101,7 +110,7 @@ struct desync_profile
unsigned int dup_repeats; unsigned int dup_repeats;
uint8_t dup_ttl, dup_ttl6; uint8_t dup_ttl, dup_ttl6;
uint32_t dup_fooling_mode; uint32_t dup_fooling_mode;
uint32_t dup_badseq_increment, dup_badseq_ack_increment; uint32_t dup_ts_increment, dup_badseq_increment, dup_badseq_ack_increment;
autottl dup_autottl, dup_autottl6; autottl dup_autottl, dup_autottl6;
char orig_mod_start_mode, orig_mod_cutoff_mode; // n - packets, d - data packets, s - relative sequence char orig_mod_start_mode, orig_mod_cutoff_mode; // n - packets, d - data packets, s - relative sequence
@@ -114,7 +123,7 @@ struct desync_profile
uint8_t desync_ttl, desync_ttl6; uint8_t desync_ttl, desync_ttl6;
autottl desync_autottl, desync_autottl6; autottl desync_autottl, desync_autottl6;
uint32_t desync_fooling_mode; uint32_t desync_fooling_mode;
uint32_t desync_badseq_increment, desync_badseq_ack_increment; uint32_t desync_ts_increment, desync_badseq_increment, desync_badseq_ack_increment;
struct blob_collection_head fake_http,fake_tls,fake_unknown,fake_unknown_udp,fake_quic,fake_wg,fake_dht,fake_discord,fake_stun; struct blob_collection_head fake_http,fake_tls,fake_unknown,fake_unknown_udp,fake_quic,fake_wg,fake_dht,fake_discord,fake_stun;
uint8_t fake_syndata[FAKE_MAX_TCP],seqovl_pattern[FAKE_MAX_TCP],fsplit_pattern[FAKE_MAX_TCP],udplen_pattern[FAKE_MAX_UDP]; uint8_t fake_syndata[FAKE_MAX_TCP],seqovl_pattern[FAKE_MAX_TCP],fsplit_pattern[FAKE_MAX_TCP],udplen_pattern[FAKE_MAX_UDP];
@@ -129,6 +138,13 @@ struct desync_profile
struct port_filters_head pf_tcp,pf_udp; struct port_filters_head pf_tcp,pf_udp;
uint32_t filter_l7; // L7_PROTO_* bits uint32_t filter_l7; // L7_PROTO_* bits
#ifdef HAS_FILTER_SSID
// per profile ssid filter
// annot use global filter because it's not possible to bind multiple instances to a single queue
// it's possible to run multiple winws instances on the same windivert filter, but it's not the case for linux
struct str_list_head filter_ssid;
#endif
// list of pointers to ipsets // list of pointers to ipsets
struct ipset_collection_head ips_collection, ips_collection_exclude; struct ipset_collection_head ips_collection, ips_collection_exclude;
@@ -186,8 +202,10 @@ struct params_s
struct str_list_head ssid_filter,nlm_filter; struct str_list_head ssid_filter,nlm_filter;
#else #else
bool droproot; bool droproot;
char *user;
uid_t uid; uid_t uid;
gid_t gid; gid_t gid[MAX_GIDS];
int gid_count;
#endif #endif
char pidfile[PATH_MAX]; char pidfile[PATH_MAX];
@@ -202,13 +220,22 @@ struct params_s
t_conntrack conntrack; t_conntrack conntrack;
bool ctrack_disable; bool ctrack_disable;
bool autottl_present,cache_hostname; bool autottl_present;
#ifdef HAS_FILTER_SSID
bool filter_ssid_present;
#endif
bool cache_hostname;
unsigned int ipcache_lifetime; unsigned int ipcache_lifetime;
ip_cache ipcache; ip_cache ipcache;
}; };
extern struct params_s params; extern struct params_s params;
extern const char *progname; extern const char *progname;
#if !defined( __OpenBSD__) && !defined(__ANDROID__)
void cleanup_args(struct params_s *params);
#endif
void cleanup_params(struct params_s *params);
int DLOG(const char *format, ...); int DLOG(const char *format, ...);
int DLOG_ERR(const char *format, ...); int DLOG_ERR(const char *format, ...);

View File

@@ -12,7 +12,7 @@
HASH_DEL(*ppool, elem); \ HASH_DEL(*ppool, elem); \
free(elem); \ free(elem); \
} }
#define ADD_STR_POOL(etype, ppool, keystr, keystr_len) \ #define ADD_STR_POOL(etype, ppool, keystr, keystr_len) \
etype *elem; \ etype *elem; \
if (!(elem = (etype*)malloc(sizeof(etype)))) \ if (!(elem = (etype*)malloc(sizeof(etype)))) \
@@ -25,7 +25,7 @@
memcpy(elem->str, keystr, keystr_len); \ memcpy(elem->str, keystr, keystr_len); \
elem->str[keystr_len] = 0; \ elem->str[keystr_len] = 0; \
oom = false; \ oom = false; \
HASH_ADD_KEYPTR(hh, *ppool, elem->str, strlen(elem->str), elem); \ HASH_ADD_KEYPTR(hh, *ppool, elem->str, keystr_len, elem); \
if (oom) \ if (oom) \
{ \ { \
free(elem->str); \ free(elem->str); \
@@ -33,9 +33,12 @@
return false; \ return false; \
} }
#define ADD_HOSTLIST_POOL(etype, ppool, keystr, keystr_len, flg) \ #define ADD_HOSTLIST_POOL(etype, ppool, keystr, keystr_len, flg) \
ADD_STR_POOL(etype,ppool,keystr,keystr_len); \ etype *elem_find; \
elem->flags = flg; HASH_FIND(hh, *ppool, keystr, keystr_len, elem_find); \
if (!elem_find) { \
ADD_STR_POOL(etype,ppool,keystr,keystr_len); \
elem->flags = flg; \
}
#undef uthash_nonfatal_oom #undef uthash_nonfatal_oom
#define uthash_nonfatal_oom(elt) ut_oom_recover(elt) #define uthash_nonfatal_oom(elt) ut_oom_recover(elt)
@@ -159,6 +162,19 @@ void strlist_destroy(struct str_list_head *head)
strlist_entry_destroy(entry); strlist_entry_destroy(entry);
} }
} }
bool strlist_search(const struct str_list_head *head, const char *str)
{
struct str_list *entry;
if (str)
{
LIST_FOREACH(entry, head, next)
{
if (!strcmp(entry->str, str))
return true;
}
}
return false;
}
@@ -260,121 +276,146 @@ bool hostlist_collection_is_empty(const struct hostlist_collection_head *head)
} }
void ipset4Destroy(ipset4 **ipset) static int kavl_bit_cmp(const struct kavl_bit_elem *p, const struct kavl_bit_elem *q)
{ {
ipset4 *elem, *tmp; unsigned int bitlen = q->bitlen < p->bitlen ? q->bitlen : p->bitlen;
HASH_ITER(hh, *ipset, elem, tmp) unsigned int df = bitlen & 7, bytes = bitlen >> 3;
int cmp = memcmp(p->data, q->data, bytes);
if (cmp || !df) return cmp;
uint8_t c1 = p->data[bytes] >> (8 - df);
uint8_t c2 = q->data[bytes] >> (8 - df);
return c1<c2 ? -1 : c1==c2 ? 0 : 1;
}
KAVL_INIT(kavl_bit, struct kavl_bit_elem, head, kavl_bit_cmp)
static void kavl_bit_destroy_elem(struct kavl_bit_elem *e)
{
if (e)
{ {
HASH_DEL(*ipset, elem); free(e->data);
free(elem); free(e);
} }
} }
bool ipset4Check(ipset4 *ipset, const struct in_addr *a, uint8_t preflen) void kavl_bit_delete(struct kavl_bit_elem **hdr, const void *data, unsigned int bitlen)
{ {
uint32_t ip = ntohl(a->s_addr); struct kavl_bit_elem temp = {
struct cidr4 cidr; .bitlen = bitlen, .data = (uint8_t*)data
ipset4 *ips_found; };
kavl_bit_destroy_elem(kavl_erase(kavl_bit, hdr, &temp, 0));
// zero alignment bytes
memset(&cidr,0,sizeof(cidr));
cidr.preflen = preflen+1;
do
{
cidr.preflen--;
cidr.addr.s_addr = htonl(ip & mask_from_preflen(cidr.preflen));
HASH_FIND(hh, ipset, &cidr, sizeof(cidr), ips_found);
if (ips_found) return true;
} while(cidr.preflen);
return false;
} }
bool ipset4Add(ipset4 **ipset, const struct in_addr *a, uint8_t preflen) void kavl_bit_destroy(struct kavl_bit_elem **hdr)
{
while (*hdr)
{
struct kavl_bit_elem *e = kavl_erase_first(kavl_bit, hdr);
if (!e) break;
kavl_bit_destroy_elem(e);
}
free(*hdr);
}
struct kavl_bit_elem *kavl_bit_add(struct kavl_bit_elem **hdr, void *data, unsigned int bitlen, size_t struct_size)
{
if (!struct_size) struct_size=sizeof(struct kavl_bit_elem);
struct kavl_bit_elem *v, *e = calloc(1, struct_size);
if (!e) return 0;
e->bitlen = bitlen;
e->data = data;
v = kavl_insert(kavl_bit, hdr, e, 0);
while (e != v && e->bitlen < v->bitlen)
{
kavl_bit_delete(hdr, v->data, v->bitlen);
v = kavl_insert(kavl_bit, hdr, e, 0);
}
if (e != v) kavl_bit_destroy_elem(e);
return v;
}
struct kavl_bit_elem *kavl_bit_get(const struct kavl_bit_elem *hdr, const void *data, unsigned int bitlen)
{
struct kavl_bit_elem temp = {
.bitlen = bitlen, .data = (uint8_t*)data
};
return kavl_find(kavl_bit, hdr, &temp, 0);
}
static bool ipset_kavl_add(struct kavl_bit_elem **ipset, const void *a, uint8_t preflen)
{
uint8_t bytelen = (preflen+7)>>3;
uint8_t *abuf = malloc(bytelen);
if (!abuf) return false;
memcpy(abuf,a,bytelen);
if (!kavl_bit_add(ipset,abuf,preflen,0))
{
free(abuf);
return false;
}
return true;
}
bool ipset4Check(const struct kavl_bit_elem *ipset, const struct in_addr *a, uint8_t preflen)
{
return !!kavl_bit_get(ipset,a,preflen);
}
bool ipset4Add(struct kavl_bit_elem **ipset, const struct in_addr *a, uint8_t preflen)
{ {
if (preflen>32) return false; if (preflen>32) return false;
return ipset_kavl_add(ipset,a,preflen);
// avoid dups
if (ipset4Check(*ipset, a, preflen)) return true; // already included
struct ipset4 *entry = calloc(1,sizeof(ipset4));
if (!entry) return false;
entry->cidr.addr.s_addr = htonl(ntohl(a->s_addr) & mask_from_preflen(preflen));
entry->cidr.preflen = preflen;
oom = false;
HASH_ADD(hh, *ipset, cidr, sizeof(entry->cidr), entry);
if (oom) { free(entry); return false; }
return true;
} }
void ipset4Print(ipset4 *ipset) void ipset4Print(struct kavl_bit_elem *ipset)
{ {
ipset4 *ips, *tmp; if (!ipset) return;
HASH_ITER(hh, ipset , ips, tmp)
{
print_cidr4(&ips->cidr);
printf("\n");
}
}
void ipset6Destroy(ipset6 **ipset) struct cidr4 c;
{ const struct kavl_bit_elem *elem;
ipset6 *elem, *tmp; kavl_itr_t(kavl_bit) itr;
HASH_ITER(hh, *ipset, elem, tmp) kavl_itr_first(kavl_bit, ipset, &itr);
{
HASH_DEL(*ipset, elem);
free(elem);
}
}
bool ipset6Check(ipset6 *ipset, const struct in6_addr *a, uint8_t preflen)
{
struct cidr6 cidr;
ipset6 *ips_found;
// zero alignment bytes
memset(&cidr,0,sizeof(cidr));
cidr.preflen = preflen+1;
do do
{ {
cidr.preflen--; elem = kavl_at(&itr);
ip6_and(a, mask_from_preflen6(cidr.preflen), &cidr.addr); c.preflen = elem->bitlen;
HASH_FIND(hh, ipset, &cidr, sizeof(cidr), ips_found); expand_bits(&c.addr, elem->data, elem->bitlen, sizeof(c.addr));
if (ips_found) return true; print_cidr4(&c);
} while(cidr.preflen);
return false;
}
bool ipset6Add(ipset6 **ipset, const struct in6_addr *a, uint8_t preflen)
{
if (preflen>128) return false;
// avoid dups
if (ipset6Check(*ipset, a, preflen)) return true; // already included
struct ipset6 *entry = calloc(1,sizeof(ipset6));
if (!entry) return false;
ip6_and(a, mask_from_preflen6(preflen), &entry->cidr.addr);
entry->cidr.preflen = preflen;
oom = false;
HASH_ADD(hh, *ipset, cidr, sizeof(entry->cidr), entry);
if (oom) { free(entry); return false; }
return true;
}
void ipset6Print(ipset6 *ipset)
{
ipset6 *ips, *tmp;
HASH_ITER(hh, ipset , ips, tmp)
{
print_cidr6(&ips->cidr);
printf("\n"); printf("\n");
} }
while (kavl_itr_next(kavl_bit, &itr));
}
bool ipset6Check(const struct kavl_bit_elem *ipset, const struct in6_addr *a, uint8_t preflen)
{
return !!kavl_bit_get(ipset,a,preflen);
}
bool ipset6Add(struct kavl_bit_elem **ipset, const struct in6_addr *a, uint8_t preflen)
{
if (preflen>128) return false;
return ipset_kavl_add(ipset,a,preflen);
}
void ipset6Print(struct kavl_bit_elem *ipset)
{
if (!ipset) return;
struct cidr6 c;
const struct kavl_bit_elem *elem;
kavl_itr_t(kavl_bit) itr;
kavl_itr_first(kavl_bit, ipset, &itr);
do
{
elem = kavl_at(&itr);
c.preflen = elem->bitlen;
expand_bits(&c.addr, elem->data, elem->bitlen, sizeof(c.addr));
print_cidr6(&c);
printf("\n");
}
while (kavl_itr_next(kavl_bit, &itr));
} }
void ipsetDestroy(ipset *ipset) void ipsetDestroy(ipset *ipset)
{ {
ipset4Destroy(&ipset->ips4); kavl_bit_destroy(&ipset->ips4);
ipset6Destroy(&ipset->ips6); kavl_bit_destroy(&ipset->ips6);
} }
void ipsetPrint(ipset *ipset) void ipsetPrint(ipset *ipset)
{ {
@@ -591,6 +632,7 @@ static void ipcache_item_init(ip_cache_item *item)
{ {
ipcache_item_touch(item); ipcache_item_touch(item);
item->hostname = NULL; item->hostname = NULL;
item->hostname_is_ip = false;
item->hops = 0; item->hops = 0;
} }
static void ipcache_item_destroy(ip_cache_item *item) static void ipcache_item_destroy(ip_cache_item *item)
@@ -652,7 +694,7 @@ static void ipcache4Print(ip_cache4 *ipcache)
{ {
*s_ip=0; *s_ip=0;
inet_ntop(AF_INET, &ipc->key.addr, s_ip, sizeof(s_ip)); inet_ntop(AF_INET, &ipc->key.addr, s_ip, sizeof(s_ip));
printf("%s iface=%s : hops %u hostname=%s now=last+%llu\n", s_ip, ipc->key.iface, ipc->data.hops, ipc->data.hostname ? ipc->data.hostname : "", (unsigned long long)(now-ipc->data.last)); printf("%s iface=%s : hops %u hostname=%s hostname_is_ip=%u now=last+%llu\n", s_ip, ipc->key.iface, ipc->data.hops, ipc->data.hostname ? ipc->data.hostname : "", ipc->data.hostname_is_ip, (unsigned long long)(now-ipc->data.last));
} }
} }
@@ -710,7 +752,7 @@ static void ipcache6Print(ip_cache6 *ipcache)
{ {
*s_ip=0; *s_ip=0;
inet_ntop(AF_INET6, &ipc->key.addr, s_ip, sizeof(s_ip)); inet_ntop(AF_INET6, &ipc->key.addr, s_ip, sizeof(s_ip));
printf("%s iface=%s : hops %u hostname=%s now=last+%llu\n", s_ip, ipc->key.iface, ipc->data.hops, ipc->data.hostname ? ipc->data.hostname : "", (unsigned long long)(now-ipc->data.last)); printf("%s iface=%s : hops %u hostname=%s hostname_is_ip=%u now=last+%llu\n", s_ip, ipc->key.iface, ipc->data.hops, ipc->data.hostname ? ipc->data.hostname : "", ipc->data.hostname_is_ip, (unsigned long long)(now-ipc->data.last));
} }
} }

View File

@@ -13,6 +13,8 @@
#define HASH_FUNCTION HASH_BER #define HASH_FUNCTION HASH_BER
#include "uthash.h" #include "uthash.h"
#include "kavl.h"
#define HOSTLIST_POOL_FLAG_STRICT_MATCH 1 #define HOSTLIST_POOL_FLAG_STRICT_MATCH 1
typedef struct hostlist_pool { typedef struct hostlist_pool {
@@ -32,6 +34,11 @@ struct str_list {
}; };
LIST_HEAD(str_list_head, str_list); LIST_HEAD(str_list_head, str_list);
bool strlist_add(struct str_list_head *head, const char *filename);
void strlist_destroy(struct str_list_head *head);
bool strlist_search(const struct str_list_head *head, const char *str);
typedef struct hostfail_pool { typedef struct hostfail_pool {
char *str; /* key */ char *str; /* key */
int counter; /* value */ int counter; /* value */
@@ -47,10 +54,6 @@ void HostFailPoolPurge(hostfail_pool **pp);
void HostFailPoolPurgeRateLimited(hostfail_pool **pp); void HostFailPoolPurgeRateLimited(hostfail_pool **pp);
void HostFailPoolDump(hostfail_pool *p); void HostFailPoolDump(hostfail_pool *p);
bool strlist_add(struct str_list_head *head, const char *filename);
void strlist_destroy(struct str_list_head *head);
struct hostlist_file { struct hostlist_file {
char *filename; char *filename;
@@ -76,39 +79,40 @@ struct hostlist_item *hostlist_collection_search(struct hostlist_collection_head
bool hostlist_collection_is_empty(const struct hostlist_collection_head *head); bool hostlist_collection_is_empty(const struct hostlist_collection_head *head);
typedef struct ipset4 { struct kavl_bit_elem
struct cidr4 cidr; /* key */ {
UT_hash_handle hh; /* makes this structure hashable */ unsigned int bitlen;
} ipset4; uint8_t *data;
typedef struct ipset6 { KAVL_HEAD(struct kavl_bit_elem) head;
struct cidr6 cidr; /* key */ };
UT_hash_handle hh; /* makes this structure hashable */
} ipset6; struct kavl_bit_elem *kavl_bit_get(const struct kavl_bit_elem *hdr, const void *data, unsigned int bitlen);
struct kavl_bit_elem *kavl_bit_add(struct kavl_bit_elem **hdr, void *data, unsigned int bitlen, size_t struct_size);
void kavl_bit_delete(struct kavl_bit_elem **hdr, const void *data, unsigned int bitlen);
void kavl_bit_destroy(struct kavl_bit_elem **hdr);
// combined ipset ipv4 and ipv6 // combined ipset ipv4 and ipv6
typedef struct ipset { typedef struct ipset {
ipset4 *ips4; struct kavl_bit_elem *ips4,*ips6;
ipset6 *ips6;
} ipset; } ipset;
#define IPSET_EMPTY(ips) (!(ips)->ips4 && !(ips)->ips6) #define IPSET_EMPTY(ips) (!(ips)->ips4 && !(ips)->ips6)
void ipset4Destroy(ipset4 **ipset); bool ipset4Add(struct kavl_bit_elem **ipset, const struct in_addr *a, uint8_t preflen);
bool ipset4Add(ipset4 **ipset, const struct in_addr *a, uint8_t preflen); static inline bool ipset4AddCidr(struct kavl_bit_elem **ipset, const struct cidr4 *cidr)
static inline bool ipset4AddCidr(ipset4 **ipset, const struct cidr4 *cidr)
{ {
return ipset4Add(ipset,&cidr->addr,cidr->preflen); return ipset4Add(ipset,&cidr->addr,cidr->preflen);
} }
bool ipset4Check(ipset4 *ipset, const struct in_addr *a, uint8_t preflen); bool ipset4Check(const struct kavl_bit_elem *ipset, const struct in_addr *a, uint8_t preflen);
void ipset4Print(ipset4 *ipset); void ipset4Print(struct kavl_bit_elem *ipset);
void ipset6Destroy(ipset6 **ipset); bool ipset6Add(struct kavl_bit_elem **ipset, const struct in6_addr *a, uint8_t preflen);
bool ipset6Add(ipset6 **ipset, const struct in6_addr *a, uint8_t preflen); static inline bool ipset6AddCidr(struct kavl_bit_elem **ipset, const struct cidr6 *cidr)
static inline bool ipset6AddCidr(ipset6 **ipset, const struct cidr6 *cidr)
{ {
return ipset6Add(ipset,&cidr->addr,cidr->preflen); return ipset6Add(ipset,&cidr->addr,cidr->preflen);
} }
bool ipset6Check(ipset6 *ipset, const struct in6_addr *a, uint8_t preflen); bool ipset6Check(const struct kavl_bit_elem *ipset, const struct in6_addr *a, uint8_t preflen);
void ipset6Print(ipset6 *ipset); void ipset6Print(struct kavl_bit_elem *ipset);
void ipsetDestroy(ipset *ipset); void ipsetDestroy(ipset *ipset);
void ipsetPrint(ipset *ipset); void ipsetPrint(ipset *ipset);
@@ -178,6 +182,7 @@ typedef struct ip_cache_item
{ {
time_t last; time_t last;
char *hostname; char *hostname;
bool hostname_is_ip;
uint8_t hops; uint8_t hops;
} ip_cache_item; } ip_cache_item;
typedef struct ip_cache4 typedef struct ip_cache4

View File

@@ -295,8 +295,13 @@ bool can_drop_root(void)
#endif #endif
} }
bool droproot(uid_t uid, gid_t gid) bool droproot(uid_t uid, const char *user, const gid_t *gid, int gid_count)
{ {
if (gid_count<1)
{
DLOG_ERR("droproot: no groups specified");
return false;
}
#ifdef __linux__ #ifdef __linux__
if (prctl(PR_SET_KEEPCAPS, 1L)) if (prctl(PR_SET_KEEPCAPS, 1L))
{ {
@@ -304,13 +309,25 @@ bool droproot(uid_t uid, gid_t gid)
return false; return false;
} }
#endif #endif
// drop all SGIDs if (user)
if (setgroups(0,NULL))
{ {
DLOG_PERROR("setgroups"); // macos has strange supp gid handling. they cache only 16 groups and fail setgroups if more than 16 gids specified.
return false; // better to leave it to the os
if (initgroups(user,gid[0]))
{
DLOG_PERROR("initgroups");
return false;
}
} }
if (setgid(gid)) else
{
if (setgroups(gid_count,gid))
{
DLOG_PERROR("setgroups");
return false;
}
}
if (setgid(gid[0]))
{ {
DLOG_PERROR("setgid"); DLOG_PERROR("setgid");
return false; return false;
@@ -343,9 +360,13 @@ void print_id(void)
#endif #endif
void daemonize(void) void daemonize(void)
{ {
int pid; int pid;
#ifdef __CYGWIN__
char *cwd = get_current_dir_name();
#endif
pid = fork(); pid = fork();
if (pid == -1) if (pid == -1)
@@ -356,6 +377,10 @@ void daemonize(void)
else if (pid != 0) else if (pid != 0)
exit(0); exit(0);
#ifdef __CYGWIN__
chdir(get_current_dir_name());
#endif
if (setsid() == -1) if (setsid() == -1)
exit(2); exit(2);
if (chdir("/") == -1) if (chdir("/") == -1)

View File

@@ -84,7 +84,7 @@ bool dropcaps(void);
#ifndef __CYGWIN__ #ifndef __CYGWIN__
bool sec_harden(void); bool sec_harden(void);
bool can_drop_root(void); bool can_drop_root(void);
bool droproot(uid_t uid, gid_t gid); bool droproot(uid_t uid, const char *user, const gid_t *gid, int gid_count);
void print_id(void); void print_id(void);
#endif #endif

View File

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

View File

@@ -1,7 +1,9 @@
CC ?= gcc CC ?= cc
CFLAGS += -std=gnu99 -Os -flto=auto OPTIMIZE ?= -Os
CFLAGS += -std=gnu99 $(OPTIMIZE) -flto=auto
CFLAGS_SYSTEMD = -DUSE_SYSTEMD CFLAGS_SYSTEMD = -DUSE_SYSTEMD
CFLAGS_BSD = -Wno-address-of-packed-member CFLAGS_BSD = -Wno-address-of-packed-member
LDFLAGS_ANDROID = -llog
LIBS = -lz -lpthread LIBS = -lz -lpthread
LIBS_SYSTEMD = -lsystemd LIBS_SYSTEMD = -lsystemd
LIBS_ANDROID = -lz LIBS_ANDROID = -lz
@@ -17,7 +19,7 @@ systemd: $(SRC_FILES)
$(CC) -s $(CFLAGS) $(CFLAGS_SYSTEMD) -o tpws $(SRC_FILES) $(LIBS) $(LIBS_SYSTEMD) $(LDFLAGS) $(CC) -s $(CFLAGS) $(CFLAGS_SYSTEMD) -o tpws $(SRC_FILES) $(LIBS) $(LIBS_SYSTEMD) $(LDFLAGS)
android: $(SRC_FILES) android: $(SRC_FILES)
$(CC) -s $(CFLAGS) -o tpws $(SRC_FILES_ANDROID) $(LIBS_ANDROID) $(LDFLAGS) $(CC) -s $(CFLAGS) -o tpws $(SRC_FILES_ANDROID) $(LIBS_ANDROID) $(LDFLAGS) $(LDFLAGS_ANDROID)
bsd: $(SRC_FILES) bsd: $(SRC_FILES)
$(CC) -s $(CFLAGS) $(CFLAGS_BSD) -Iepoll-shim/include -o tpws $(SRC_FILES) epoll-shim/src/*.c $(LIBS) $(LDFLAGS) $(CC) -s $(CFLAGS) $(CFLAGS_BSD) -Iepoll-shim/include -o tpws $(SRC_FILES) epoll-shim/src/*.c $(LIBS) $(LDFLAGS)

View File

@@ -112,6 +112,72 @@ bool append_to_list_file(const char *filename, const char *s)
return bOK; return bOK;
} }
void expand_bits(void *target, const void *source, unsigned int source_bitlen, unsigned int target_bytelen)
{
unsigned int target_bitlen = target_bytelen<<3;
unsigned int bitlen = target_bitlen<source_bitlen ? target_bitlen : source_bitlen;
unsigned int bytelen = bitlen>>3;
if ((target_bytelen-bytelen)>=1) memset(target+bytelen,0,target_bytelen-bytelen);
memcpy(target,source,bytelen);
if ((bitlen &= 7)) ((uint8_t*)target)[bytelen] = ((uint8_t*)source)[bytelen] & (~((1 << (8-bitlen)) - 1));
}
// " [fd00::1]" => "fd00::1"
// "[fd00::1]:8000" => "fd00::1"
// "127.0.0.1" => "127.0.0.1"
// " 127.0.0.1:8000" => "127.0.0.1"
// " vk.com:8000" => "vk.com"
// return value: true - host is ip addr
bool strip_host_to_ip(char *host)
{
size_t l;
char *h,*p;
uint8_t addr[16];
for (h = host ; *h==' ' || *h=='\t' ; h++);
l = strlen(h);
if (l>=2)
{
if (*h=='[')
{
// ipv6 ?
for (p=++h ; *p && *p!=']' ; p++);
if (*p==']')
{
l = p-h;
memmove(host,h,l);
host[l]=0;
return inet_pton(AF_INET6, host, addr)>0;
}
}
else
{
if (inet_pton(AF_INET6, h, addr)>0)
{
// ipv6 ?
if (host!=h)
{
l = strlen(h);
memmove(host,h,l);
host[l]=0;
}
return true;
}
else
{
// ipv4 ?
for (p=h ; *p && *p!=':' ; p++);
l = p-h;
if (host!=h) memmove(host,h,l);
host[l]=0;
return inet_pton(AF_INET, host, addr)>0;
}
}
}
return false;
}
void ntop46(const struct sockaddr *sa, char *str, size_t len) void ntop46(const struct sockaddr *sa, char *str, size_t len)
{ {
if (!len) return; if (!len) return;

View File

@@ -29,6 +29,10 @@ bool str_ends_with(const char *s, const char *suffix);
bool load_file(const char *filename,void *buffer,size_t *buffer_size); bool load_file(const char *filename,void *buffer,size_t *buffer_size);
bool append_to_list_file(const char *filename, const char *s); bool append_to_list_file(const char *filename, const char *s);
void expand_bits(void *target, const void *source, unsigned int source_bitlen, unsigned int target_bytelen);
bool strip_host_to_ip(char *host);
void ntop46(const struct sockaddr *sa, char *str, size_t len); void ntop46(const struct sockaddr *sa, char *str, size_t len);
void ntop46_port(const struct sockaddr *sa, char *str, size_t len); void ntop46_port(const struct sockaddr *sa, char *str, size_t len);
void print_sockaddr(const struct sockaddr *sa); void print_sockaddr(const struct sockaddr *sa);

View File

@@ -170,7 +170,7 @@ bool LoadAllHostLists()
static bool SearchHostList(hostlist_pool *hostlist, const char *host) static bool SearchHostList(hostlist_pool *hostlist, const char *host, bool no_match_subdomains)
{ {
if (hostlist) if (hostlist)
{ {
@@ -195,6 +195,7 @@ static bool SearchHostList(hostlist_pool *hostlist, const char *host)
} }
else else
VPRINT("negative\n"); VPRINT("negative\n");
if (no_match_subdomains) break;
p = strchr(p, '.'); p = strchr(p, '.');
if (p) p++; if (p) p++;
bHostFull = false; bHostFull = false;
@@ -220,7 +221,7 @@ bool HostlistsReloadCheckForProfile(const struct desync_profile *dp)
return HostlistsReloadCheck(&dp->hl_collection) && HostlistsReloadCheck(&dp->hl_collection_exclude); return HostlistsReloadCheck(&dp->hl_collection) && HostlistsReloadCheck(&dp->hl_collection_exclude);
} }
// return : true = apply fooling, false = do not apply // return : true = apply fooling, false = do not apply
static bool HostlistCheck_(const struct hostlist_collection_head *hostlists, const struct hostlist_collection_head *hostlists_exclude, const char *host, bool *excluded, bool bSkipReloadCheck) static bool HostlistCheck_(const struct hostlist_collection_head *hostlists, const struct hostlist_collection_head *hostlists_exclude, const char *host, bool no_match_subdomains, bool *excluded, bool bSkipReloadCheck)
{ {
struct hostlist_item *item; struct hostlist_item *item;
@@ -233,7 +234,7 @@ static bool HostlistCheck_(const struct hostlist_collection_head *hostlists, con
LIST_FOREACH(item, hostlists_exclude, next) LIST_FOREACH(item, hostlists_exclude, next)
{ {
VPRINT("[%s] exclude ", item->hfile->filename ? item->hfile->filename : "fixed"); VPRINT("[%s] exclude ", item->hfile->filename ? item->hfile->filename : "fixed");
if (SearchHostList(item->hfile->hostlist, host)) if (SearchHostList(item->hfile->hostlist, host, no_match_subdomains))
{ {
if (excluded) *excluded = true; if (excluded) *excluded = true;
return false; return false;
@@ -245,7 +246,7 @@ static bool HostlistCheck_(const struct hostlist_collection_head *hostlists, con
LIST_FOREACH(item, hostlists, next) LIST_FOREACH(item, hostlists, next)
{ {
VPRINT("[%s] include ", item->hfile->filename ? item->hfile->filename : "fixed"); VPRINT("[%s] include ", item->hfile->filename ? item->hfile->filename : "fixed");
if (SearchHostList(item->hfile->hostlist, host)) if (SearchHostList(item->hfile->hostlist, host, no_match_subdomains))
return true; return true;
} }
return false; return false;
@@ -255,10 +256,10 @@ static bool HostlistCheck_(const struct hostlist_collection_head *hostlists, con
// return : true = apply fooling, false = do not apply // return : true = apply fooling, false = do not apply
bool HostlistCheck(const struct desync_profile *dp, const char *host, bool *excluded, bool bSkipReloadCheck) bool HostlistCheck(const struct desync_profile *dp, const char *host, bool no_match_subdomains, bool *excluded, bool bSkipReloadCheck)
{ {
VPRINT("* hostlist check for profile %d\n",dp->n); VPRINT("* hostlist check for profile %d\n",dp->n);
return HostlistCheck_(&dp->hl_collection, &dp->hl_collection_exclude, host, excluded, bSkipReloadCheck); return HostlistCheck_(&dp->hl_collection, &dp->hl_collection_exclude, host, no_match_subdomains, excluded, bSkipReloadCheck);
} }

View File

@@ -9,7 +9,7 @@ bool AppendHostList(hostlist_pool **hostlist, const char *filename);
bool LoadAllHostLists(); bool LoadAllHostLists();
bool NonEmptyHostlist(hostlist_pool **hostlist); bool NonEmptyHostlist(hostlist_pool **hostlist);
// return : true = apply fooling, false = do not apply // return : true = apply fooling, false = do not apply
bool HostlistCheck(const struct desync_profile *dp,const char *host, bool *excluded, bool bSkipReloadCheck); bool HostlistCheck(const struct desync_profile *dp,const char *host, bool no_match_subdomains, bool *excluded, bool bSkipReloadCheck);
struct hostlist_file *RegisterHostlist(struct desync_profile *dp, bool bExclude, const char *filename); struct hostlist_file *RegisterHostlist(struct desync_profile *dp, bool bExclude, const char *filename);
bool HostlistsReloadCheckForProfile(const struct desync_profile *dp); bool HostlistsReloadCheckForProfile(const struct desync_profile *dp);
void HostlistsDebug(); void HostlistsDebug();

400
tpws/kavl.h Normal file
View File

@@ -0,0 +1,400 @@
/* The MIT License
Copyright (c) 2018 by Attractive Chaos <attractor@live.co.uk>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/* An example:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "kavl.h"
struct my_node {
char key;
KAVL_HEAD(struct my_node) head;
};
#define my_cmp(p, q) (((q)->key < (p)->key) - ((p)->key < (q)->key))
KAVL_INIT(my, struct my_node, head, my_cmp)
int main(void) {
const char *str = "MNOLKQOPHIA"; // from wiki, except a duplicate
struct my_node *root = 0;
int i, l = strlen(str);
for (i = 0; i < l; ++i) { // insert in the input order
struct my_node *q, *p = malloc(sizeof(*p));
p->key = str[i];
q = kavl_insert(my, &root, p, 0);
if (p != q) free(p); // if already present, free
}
kavl_itr_t(my) itr;
kavl_itr_first(my, root, &itr); // place at first
do { // traverse
const struct my_node *p = kavl_at(&itr);
putchar(p->key);
free((void*)p); // free node
} while (kavl_itr_next(my, &itr));
putchar('\n');
return 0;
}
*/
#ifndef KAVL_H
#define KAVL_H
#ifdef __STRICT_ANSI__
#define inline __inline__
#endif
#define KAVL_MAX_DEPTH 64
#define kavl_size(head, p) ((p)? (p)->head.size : 0)
#define kavl_size_child(head, q, i) ((q)->head.p[(i)]? (q)->head.p[(i)]->head.size : 0)
#define KAVL_HEAD(__type) \
struct { \
__type *p[2]; \
signed char balance; /* balance factor */ \
unsigned size; /* #elements in subtree */ \
}
#define __KAVL_FIND(suf, __scope, __type, __head, __cmp) \
__scope __type *kavl_find_##suf(const __type *root, const __type *x, unsigned *cnt_) { \
const __type *p = root; \
unsigned cnt = 0; \
while (p != 0) { \
int cmp; \
cmp = __cmp(x, p); \
if (cmp >= 0) cnt += kavl_size_child(__head, p, 0) + 1; \
if (cmp < 0) p = p->__head.p[0]; \
else if (cmp > 0) p = p->__head.p[1]; \
else break; \
} \
if (cnt_) *cnt_ = cnt; \
return (__type*)p; \
}
#define __KAVL_ROTATE(suf, __type, __head) \
/* one rotation: (a,(b,c)q)p => ((a,b)p,c)q */ \
static inline __type *kavl_rotate1_##suf(__type *p, int dir) { /* dir=0 to left; dir=1 to right */ \
int opp = 1 - dir; /* opposite direction */ \
__type *q = p->__head.p[opp]; \
unsigned size_p = p->__head.size; \
p->__head.size -= q->__head.size - kavl_size_child(__head, q, dir); \
q->__head.size = size_p; \
p->__head.p[opp] = q->__head.p[dir]; \
q->__head.p[dir] = p; \
return q; \
} \
/* two consecutive rotations: (a,((b,c)r,d)q)p => ((a,b)p,(c,d)q)r */ \
static inline __type *kavl_rotate2_##suf(__type *p, int dir) { \
int b1, opp = 1 - dir; \
__type *q = p->__head.p[opp], *r = q->__head.p[dir]; \
unsigned size_x_dir = kavl_size_child(__head, r, dir); \
r->__head.size = p->__head.size; \
p->__head.size -= q->__head.size - size_x_dir; \
q->__head.size -= size_x_dir + 1; \
p->__head.p[opp] = r->__head.p[dir]; \
r->__head.p[dir] = p; \
q->__head.p[dir] = r->__head.p[opp]; \
r->__head.p[opp] = q; \
b1 = dir == 0? +1 : -1; \
if (r->__head.balance == b1) q->__head.balance = 0, p->__head.balance = -b1; \
else if (r->__head.balance == 0) q->__head.balance = p->__head.balance = 0; \
else q->__head.balance = b1, p->__head.balance = 0; \
r->__head.balance = 0; \
return r; \
}
#define __KAVL_INSERT(suf, __scope, __type, __head, __cmp) \
__scope __type *kavl_insert_##suf(__type **root_, __type *x, unsigned *cnt_) { \
unsigned char stack[KAVL_MAX_DEPTH]; \
__type *path[KAVL_MAX_DEPTH]; \
__type *bp, *bq; \
__type *p, *q, *r = 0; /* _r_ is potentially the new root */ \
int i, which = 0, top, b1, path_len; \
unsigned cnt = 0; \
bp = *root_, bq = 0; \
/* find the insertion location */ \
for (p = bp, q = bq, top = path_len = 0; p; q = p, p = p->__head.p[which]) { \
int cmp; \
cmp = __cmp(x, p); \
if (cmp >= 0) cnt += kavl_size_child(__head, p, 0) + 1; \
if (cmp == 0) { \
if (cnt_) *cnt_ = cnt; \
return p; \
} \
if (p->__head.balance != 0) \
bq = q, bp = p, top = 0; \
stack[top++] = which = (cmp > 0); \
path[path_len++] = p; \
} \
if (cnt_) *cnt_ = cnt; \
x->__head.balance = 0, x->__head.size = 1, x->__head.p[0] = x->__head.p[1] = 0; \
if (q == 0) *root_ = x; \
else q->__head.p[which] = x; \
if (bp == 0) return x; \
for (i = 0; i < path_len; ++i) ++path[i]->__head.size; \
for (p = bp, top = 0; p != x; p = p->__head.p[stack[top]], ++top) /* update balance factors */ \
if (stack[top] == 0) --p->__head.balance; \
else ++p->__head.balance; \
if (bp->__head.balance > -2 && bp->__head.balance < 2) return x; /* no re-balance needed */ \
/* re-balance */ \
which = (bp->__head.balance < 0); \
b1 = which == 0? +1 : -1; \
q = bp->__head.p[1 - which]; \
if (q->__head.balance == b1) { \
r = kavl_rotate1_##suf(bp, which); \
q->__head.balance = bp->__head.balance = 0; \
} else r = kavl_rotate2_##suf(bp, which); \
if (bq == 0) *root_ = r; \
else bq->__head.p[bp != bq->__head.p[0]] = r; \
return x; \
}
#define __KAVL_ERASE(suf, __scope, __type, __head, __cmp) \
__scope __type *kavl_erase_##suf(__type **root_, const __type *x, unsigned *cnt_) { \
__type *p, *path[KAVL_MAX_DEPTH], fake; \
unsigned char dir[KAVL_MAX_DEPTH]; \
int i, d = 0, cmp; \
unsigned cnt = 0; \
fake.__head.p[0] = *root_, fake.__head.p[1] = 0; \
if (cnt_) *cnt_ = 0; \
if (x) { \
for (cmp = -1, p = &fake; cmp; cmp = __cmp(x, p)) { \
int which = (cmp > 0); \
if (cmp > 0) cnt += kavl_size_child(__head, p, 0) + 1; \
dir[d] = which; \
path[d++] = p; \
p = p->__head.p[which]; \
if (p == 0) { \
if (cnt_) *cnt_ = 0; \
return 0; \
} \
} \
cnt += kavl_size_child(__head, p, 0) + 1; /* because p==x is not counted */ \
} else { \
for (p = &fake, cnt = 1; p; p = p->__head.p[0]) \
dir[d] = 0, path[d++] = p; \
p = path[--d]; \
} \
if (cnt_) *cnt_ = cnt; \
for (i = 1; i < d; ++i) --path[i]->__head.size; \
if (p->__head.p[1] == 0) { /* ((1,.)2,3)4 => (1,3)4; p=2 */ \
path[d-1]->__head.p[dir[d-1]] = p->__head.p[0]; \
} else { \
__type *q = p->__head.p[1]; \
if (q->__head.p[0] == 0) { /* ((1,2)3,4)5 => ((1)2,4)5; p=3 */ \
q->__head.p[0] = p->__head.p[0]; \
q->__head.balance = p->__head.balance; \
path[d-1]->__head.p[dir[d-1]] = q; \
path[d] = q, dir[d++] = 1; \
q->__head.size = p->__head.size - 1; \
} else { /* ((1,((.,2)3,4)5)6,7)8 => ((1,(2,4)5)3,7)8; p=6 */ \
__type *r; \
int e = d++; /* backup _d_ */\
for (;;) { \
dir[d] = 0; \
path[d++] = q; \
r = q->__head.p[0]; \
if (r->__head.p[0] == 0) break; \
q = r; \
} \
r->__head.p[0] = p->__head.p[0]; \
q->__head.p[0] = r->__head.p[1]; \
r->__head.p[1] = p->__head.p[1]; \
r->__head.balance = p->__head.balance; \
path[e-1]->__head.p[dir[e-1]] = r; \
path[e] = r, dir[e] = 1; \
for (i = e + 1; i < d; ++i) --path[i]->__head.size; \
r->__head.size = p->__head.size - 1; \
} \
} \
while (--d > 0) { \
__type *q = path[d]; \
int which, other, b1 = 1, b2 = 2; \
which = dir[d], other = 1 - which; \
if (which) b1 = -b1, b2 = -b2; \
q->__head.balance += b1; \
if (q->__head.balance == b1) break; \
else if (q->__head.balance == b2) { \
__type *r = q->__head.p[other]; \
if (r->__head.balance == -b1) { \
path[d-1]->__head.p[dir[d-1]] = kavl_rotate2_##suf(q, which); \
} else { \
path[d-1]->__head.p[dir[d-1]] = kavl_rotate1_##suf(q, which); \
if (r->__head.balance == 0) { \
r->__head.balance = -b1; \
q->__head.balance = b1; \
break; \
} else r->__head.balance = q->__head.balance = 0; \
} \
} \
} \
*root_ = fake.__head.p[0]; \
return p; \
}
#define kavl_free(__type, __head, __root, __free) do { \
__type *_p, *_q; \
for (_p = __root; _p; _p = _q) { \
if (_p->__head.p[0] == 0) { \
_q = _p->__head.p[1]; \
__free(_p); \
} else { \
_q = _p->__head.p[0]; \
_p->__head.p[0] = _q->__head.p[1]; \
_q->__head.p[1] = _p; \
} \
} \
} while (0)
#define __KAVL_ITR(suf, __scope, __type, __head, __cmp) \
struct kavl_itr_##suf { \
const __type *stack[KAVL_MAX_DEPTH], **top, *right; /* _right_ points to the right child of *top */ \
}; \
__scope void kavl_itr_first_##suf(const __type *root, struct kavl_itr_##suf *itr) { \
const __type *p; \
for (itr->top = itr->stack - 1, p = root; p; p = p->__head.p[0]) \
*++itr->top = p; \
itr->right = (*itr->top)->__head.p[1]; \
} \
__scope int kavl_itr_find_##suf(const __type *root, const __type *x, struct kavl_itr_##suf *itr) { \
const __type *p = root; \
itr->top = itr->stack - 1; \
while (p != 0) { \
int cmp; \
cmp = __cmp(x, p); \
if (cmp < 0) *++itr->top = p, p = p->__head.p[0]; \
else if (cmp > 0) p = p->__head.p[1]; \
else break; \
} \
if (p) { \
*++itr->top = p; \
itr->right = p->__head.p[1]; \
return 1; \
} else if (itr->top >= itr->stack) { \
itr->right = (*itr->top)->__head.p[1]; \
return 0; \
} else return 0; \
} \
__scope int kavl_itr_next_##suf(struct kavl_itr_##suf *itr) { \
for (;;) { \
const __type *p; \
for (p = itr->right, --itr->top; p; p = p->__head.p[0]) \
*++itr->top = p; \
if (itr->top < itr->stack) return 0; \
itr->right = (*itr->top)->__head.p[1]; \
return 1; \
} \
}
/**
* Insert a node to the tree
*
* @param suf name suffix used in KAVL_INIT()
* @param proot pointer to the root of the tree (in/out: root may change)
* @param x node to insert (in)
* @param cnt number of nodes smaller than or equal to _x_; can be NULL (out)
*
* @return _x_ if not present in the tree, or the node equal to x.
*/
#define kavl_insert(suf, proot, x, cnt) kavl_insert_##suf(proot, x, cnt)
/**
* Find a node in the tree
*
* @param suf name suffix used in KAVL_INIT()
* @param root root of the tree
* @param x node value to find (in)
* @param cnt number of nodes smaller than or equal to _x_; can be NULL (out)
*
* @return node equal to _x_ if present, or NULL if absent
*/
#define kavl_find(suf, root, x, cnt) kavl_find_##suf(root, x, cnt)
/**
* Delete a node from the tree
*
* @param suf name suffix used in KAVL_INIT()
* @param proot pointer to the root of the tree (in/out: root may change)
* @param x node value to delete; if NULL, delete the first node (in)
*
* @return node removed from the tree if present, or NULL if absent
*/
#define kavl_erase(suf, proot, x, cnt) kavl_erase_##suf(proot, x, cnt)
#define kavl_erase_first(suf, proot) kavl_erase_##suf(proot, 0, 0)
#define kavl_itr_t(suf) struct kavl_itr_##suf
/**
* Place the iterator at the smallest object
*
* @param suf name suffix used in KAVL_INIT()
* @param root root of the tree
* @param itr iterator
*/
#define kavl_itr_first(suf, root, itr) kavl_itr_first_##suf(root, itr)
/**
* Place the iterator at the object equal to or greater than the query
*
* @param suf name suffix used in KAVL_INIT()
* @param root root of the tree
* @param x query (in)
* @param itr iterator (out)
*
* @return 1 if find; 0 otherwise. kavl_at(itr) is NULL if and only if query is
* larger than all objects in the tree
*/
#define kavl_itr_find(suf, root, x, itr) kavl_itr_find_##suf(root, x, itr)
/**
* Move to the next object in order
*
* @param itr iterator (modified)
*
* @return 1 if there is a next object; 0 otherwise
*/
#define kavl_itr_next(suf, itr) kavl_itr_next_##suf(itr)
/**
* Return the pointer at the iterator
*
* @param itr iterator
*
* @return pointer if present; NULL otherwise
*/
#define kavl_at(itr) ((itr)->top < (itr)->stack? 0 : *(itr)->top)
#define KAVL_INIT2(suf, __scope, __type, __head, __cmp) \
__KAVL_FIND(suf, __scope, __type, __head, __cmp) \
__KAVL_ROTATE(suf, __type, __head) \
__KAVL_INSERT(suf, __scope, __type, __head, __cmp) \
__KAVL_ERASE(suf, __scope, __type, __head, __cmp) \
__KAVL_ITR(suf, __scope, __type, __head, __cmp)
#define KAVL_INIT(suf, __type, __head, __cmp) \
KAVL_INIT2(suf,, __type, __head, __cmp)
#endif

View File

@@ -2,6 +2,11 @@
#include <stdarg.h> #include <stdarg.h>
#include <syslog.h> #include <syslog.h>
#include <errno.h> #include <errno.h>
#ifdef __ANDROID__
#include <android/log.h>
#endif
const char *progname = "tpws";
int DLOG_FILE(FILE *F, const char *format, va_list args) int DLOG_FILE(FILE *F, const char *format, va_list args)
{ {
@@ -25,18 +30,47 @@ int DLOG_FILENAME(const char *filename, const char *format, va_list args)
return r; return r;
} }
static char syslog_buf[1024]; typedef void (*f_log_function)(int priority, const char *line);
static size_t syslog_buf_sz=0;
static void syslog_buffered(int priority, const char *format, va_list args) static char log_buf[1024];
static size_t log_buf_sz=0;
static void syslog_log_function(int priority, const char *line)
{ {
if (vsnprintf(syslog_buf+syslog_buf_sz,sizeof(syslog_buf)-syslog_buf_sz,format,args)>0) syslog(priority,"%s",log_buf);
}
#ifdef __ANDROID__
static enum android_LogPriority syslog_priority_to_android(int priority)
{
enum android_LogPriority ap;
switch(priority)
{ {
syslog_buf_sz=strlen(syslog_buf); case LOG_INFO:
case LOG_NOTICE: ap=ANDROID_LOG_INFO; break;
case LOG_ERR: ap=ANDROID_LOG_ERROR; break;
case LOG_WARNING: ap=ANDROID_LOG_WARN; break;
case LOG_EMERG:
case LOG_ALERT:
case LOG_CRIT: ap=ANDROID_LOG_FATAL; break;
case LOG_DEBUG: ap=ANDROID_LOG_DEBUG; break;
default: ap=ANDROID_LOG_UNKNOWN;
}
return ap;
}
static void android_log_function(int priority, const char *line)
{
__android_log_print(syslog_priority_to_android(priority), progname, "%s", line);
}
#endif
static void log_buffered(f_log_function log_function, int syslog_priority, const char *format, va_list args)
{
if (vsnprintf(log_buf+log_buf_sz,sizeof(log_buf)-log_buf_sz,format,args)>0)
{
log_buf_sz=strlen(log_buf);
// log when buffer is full or buffer ends with \n // log when buffer is full or buffer ends with \n
if (syslog_buf_sz>=(sizeof(syslog_buf)-1) || (syslog_buf_sz && syslog_buf[syslog_buf_sz-1]=='\n')) if (log_buf_sz>=(sizeof(log_buf)-1) || (log_buf_sz && log_buf[log_buf_sz-1]=='\n'))
{ {
syslog(priority,"%s",syslog_buf); log_function(syslog_priority,log_buf);
syslog_buf_sz = 0; log_buf_sz = 0;
} }
} }
} }
@@ -64,9 +98,16 @@ static int DLOG_VA(const char *format, int syslog_priority, bool condup, int lev
break; break;
case LOG_TARGET_SYSLOG: case LOG_TARGET_SYSLOG:
// skip newlines // skip newlines
syslog_buffered(syslog_priority,format,args); log_buffered(syslog_log_function,syslog_priority,format,args);
r = 1; r = 1;
break; break;
#ifdef __ANDROID__
case LOG_TARGET_ANDROID:
// skip newlines
log_buffered(android_log_function,syslog_priority,format,args);
r = 1;
break;
#endif
default: default:
break; break;
} }
@@ -217,3 +258,24 @@ void dp_list_destroy(struct desync_profile_list_head *head)
dp_entry_destroy(entry); dp_entry_destroy(entry);
} }
} }
#if !defined( __OpenBSD__) && !defined(__ANDROID__)
void cleanup_args(struct params_s *params)
{
wordfree(&params->wexp);
}
#endif
void cleanup_params(struct params_s *params)
{
#if !defined( __OpenBSD__) && !defined(__ANDROID__)
cleanup_args(params);
#endif
dp_list_destroy(&params->desync_profiles);
hostlist_files_destroy(&params->hostlists);
ipset_files_destroy(&params->ipsets);
ipcacheDestroy(&params->ipcache);
free(params->user); params->user=NULL;
}

View File

@@ -4,12 +4,14 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <sys/param.h> #include <sys/param.h>
#include <sys/types.h>
#include <sys/queue.h> #include <sys/queue.h>
#include <time.h> #include <time.h>
#if !defined( __OpenBSD__) && !defined(__ANDROID__) #if !defined( __OpenBSD__) && !defined(__ANDROID__)
#include <wordexp.h> #include <wordexp.h>
#endif #endif
#include "tpws.h" #include "tpws.h"
#include "pools.h" #include "pools.h"
#include "helpers.h" #include "helpers.h"
@@ -18,13 +20,15 @@
#define HOSTLIST_AUTO_FAIL_THRESHOLD_DEFAULT 3 #define HOSTLIST_AUTO_FAIL_THRESHOLD_DEFAULT 3
#define HOSTLIST_AUTO_FAIL_TIME_DEFAULT 60 #define HOSTLIST_AUTO_FAIL_TIME_DEFAULT 60
#define FIX_SEG_DEFAULT_MAX_WAIT 50 #define FIX_SEG_DEFAULT_MAX_WAIT 50
#define IPCACHE_LIFETIME 7200 #define IPCACHE_LIFETIME 7200
#define MAX_GIDS 64
enum bindll { unwanted=0, no, prefer, force }; enum bindll { unwanted=0, no, prefer, force };
#define MAX_BINDS 32 #define MAX_BINDS 32
struct bind_s struct bind_s
{ {
char bindaddr[64],bindiface[IF_NAMESIZE]; char bindaddr[64],bindiface[IF_NAMESIZE];
@@ -33,9 +37,9 @@ struct bind_s
int bind_wait_ifup,bind_wait_ip,bind_wait_ip_ll; int bind_wait_ifup,bind_wait_ip,bind_wait_ip_ll;
}; };
#define MAX_SPLITS 16 #define MAX_SPLITS 16
enum log_target { LOG_TARGET_CONSOLE=0, LOG_TARGET_FILE, LOG_TARGET_SYSLOG }; enum log_target { LOG_TARGET_CONSOLE=0, LOG_TARGET_FILE, LOG_TARGET_SYSLOG, LOG_TARGET_ANDROID };
struct desync_profile struct desync_profile
{ {
@@ -113,11 +117,13 @@ struct params_s
bool fix_seg_avail; bool fix_seg_avail;
bool no_resolve; bool no_resolve;
bool skip_nodelay; bool skip_nodelay;
bool droproot;
bool daemon; bool daemon;
bool droproot;
char *user;
uid_t uid; uid_t uid;
gid_t gid; gid_t gid[MAX_GIDS];
char pidfile[256]; int gid_count;
char pidfile[PATH_MAX];
int maxconn,resolver_threads,maxfiles,max_orphan_time; int maxconn,resolver_threads,maxfiles,max_orphan_time;
int local_rcvbuf,local_sndbuf,remote_rcvbuf,remote_sndbuf; int local_rcvbuf,local_sndbuf,remote_rcvbuf,remote_sndbuf;
#if defined(__linux__) || defined(__APPLE__) #if defined(__linux__) || defined(__APPLE__)
@@ -149,6 +155,11 @@ struct params_s
}; };
extern struct params_s params; extern struct params_s params;
extern const char *progname;
#if !defined( __OpenBSD__) && !defined(__ANDROID__)
void cleanup_args(struct params_s *params);
#endif
void cleanup_params(struct params_s *params);
int DLOG(const char *format, int level, ...); int DLOG(const char *format, int level, ...);
int DLOG_CONDUP(const char *format, ...); int DLOG_CONDUP(const char *format, ...);

View File

@@ -25,7 +25,7 @@
memcpy(elem->str, keystr, keystr_len); \ memcpy(elem->str, keystr, keystr_len); \
elem->str[keystr_len] = 0; \ elem->str[keystr_len] = 0; \
oom = false; \ oom = false; \
HASH_ADD_KEYPTR(hh, *ppool, elem->str, strlen(elem->str), elem); \ HASH_ADD_KEYPTR(hh, *ppool, elem->str, keystr_len, elem); \
if (oom) \ if (oom) \
{ \ { \
free(elem->str); \ free(elem->str); \
@@ -33,9 +33,12 @@
return false; \ return false; \
} }
#define ADD_HOSTLIST_POOL(etype, ppool, keystr, keystr_len, flg) \ #define ADD_HOSTLIST_POOL(etype, ppool, keystr, keystr_len, flg) \
ADD_STR_POOL(etype,ppool,keystr,keystr_len); \ etype *elem_find; \
elem->flags = flg; HASH_FIND(hh, *ppool, keystr, keystr_len, elem_find); \
if (!elem_find) { \
ADD_STR_POOL(etype,ppool,keystr,keystr_len); \
elem->flags = flg; \
}
#undef uthash_nonfatal_oom #undef uthash_nonfatal_oom
#define uthash_nonfatal_oom(elt) ut_oom_recover(elt) #define uthash_nonfatal_oom(elt) ut_oom_recover(elt)
@@ -260,121 +263,146 @@ bool hostlist_collection_is_empty(const struct hostlist_collection_head *head)
} }
void ipset4Destroy(ipset4 **ipset) static int kavl_bit_cmp(const struct kavl_bit_elem *p, const struct kavl_bit_elem *q)
{ {
ipset4 *elem, *tmp; unsigned int bitlen = q->bitlen < p->bitlen ? q->bitlen : p->bitlen;
HASH_ITER(hh, *ipset, elem, tmp) unsigned int df = bitlen & 7, bytes = bitlen >> 3;
int cmp = memcmp(p->data, q->data, bytes);
if (cmp || !df) return cmp;
uint8_t c1 = p->data[bytes] >> (8 - df);
uint8_t c2 = q->data[bytes] >> (8 - df);
return c1<c2 ? -1 : c1==c2 ? 0 : 1;
}
KAVL_INIT(kavl_bit, struct kavl_bit_elem, head, kavl_bit_cmp)
static void kavl_bit_destroy_elem(struct kavl_bit_elem *e)
{
if (e)
{ {
HASH_DEL(*ipset, elem); free(e->data);
free(elem); free(e);
} }
} }
bool ipset4Check(ipset4 *ipset, const struct in_addr *a, uint8_t preflen) void kavl_bit_delete(struct kavl_bit_elem **hdr, const void *data, unsigned int bitlen)
{ {
uint32_t ip = ntohl(a->s_addr); struct kavl_bit_elem temp = {
struct cidr4 cidr; .bitlen = bitlen, .data = (uint8_t*)data
ipset4 *ips_found; };
kavl_bit_destroy_elem(kavl_erase(kavl_bit, hdr, &temp, 0));
// zero alignment bytes
memset(&cidr,0,sizeof(cidr));
cidr.preflen = preflen+1;
do
{
cidr.preflen--;
cidr.addr.s_addr = htonl(ip & mask_from_preflen(cidr.preflen));
HASH_FIND(hh, ipset, &cidr, sizeof(cidr), ips_found);
if (ips_found) return true;
} while(cidr.preflen);
return false;
} }
bool ipset4Add(ipset4 **ipset, const struct in_addr *a, uint8_t preflen) void kavl_bit_destroy(struct kavl_bit_elem **hdr)
{
while (*hdr)
{
struct kavl_bit_elem *e = kavl_erase_first(kavl_bit, hdr);
if (!e) break;
kavl_bit_destroy_elem(e);
}
free(*hdr);
}
struct kavl_bit_elem *kavl_bit_add(struct kavl_bit_elem **hdr, void *data, unsigned int bitlen, size_t struct_size)
{
if (!struct_size) struct_size=sizeof(struct kavl_bit_elem);
struct kavl_bit_elem *v, *e = calloc(1, struct_size);
if (!e) return 0;
e->bitlen = bitlen;
e->data = data;
v = kavl_insert(kavl_bit, hdr, e, 0);
while (e != v && e->bitlen < v->bitlen)
{
kavl_bit_delete(hdr, v->data, v->bitlen);
v = kavl_insert(kavl_bit, hdr, e, 0);
}
if (e != v) kavl_bit_destroy_elem(e);
return v;
}
struct kavl_bit_elem *kavl_bit_get(const struct kavl_bit_elem *hdr, const void *data, unsigned int bitlen)
{
struct kavl_bit_elem temp = {
.bitlen = bitlen, .data = (uint8_t*)data
};
return kavl_find(kavl_bit, hdr, &temp, 0);
}
static bool ipset_kavl_add(struct kavl_bit_elem **ipset, const void *a, uint8_t preflen)
{
uint8_t bytelen = (preflen+7)>>3;
uint8_t *abuf = malloc(bytelen);
if (!abuf) return false;
memcpy(abuf,a,bytelen);
if (!kavl_bit_add(ipset,abuf,preflen,0))
{
free(abuf);
return false;
}
return true;
}
bool ipset4Check(const struct kavl_bit_elem *ipset, const struct in_addr *a, uint8_t preflen)
{
return !!kavl_bit_get(ipset,a,preflen);
}
bool ipset4Add(struct kavl_bit_elem **ipset, const struct in_addr *a, uint8_t preflen)
{ {
if (preflen>32) return false; if (preflen>32) return false;
return ipset_kavl_add(ipset,a,preflen);
// avoid dups
if (ipset4Check(*ipset, a, preflen)) return true; // already included
struct ipset4 *entry = calloc(1,sizeof(ipset4));
if (!entry) return false;
entry->cidr.addr.s_addr = htonl(ntohl(a->s_addr) & mask_from_preflen(preflen));
entry->cidr.preflen = preflen;
oom = false;
HASH_ADD(hh, *ipset, cidr, sizeof(entry->cidr), entry);
if (oom) { free(entry); return false; }
return true;
} }
void ipset4Print(ipset4 *ipset) void ipset4Print(struct kavl_bit_elem *ipset)
{ {
ipset4 *ips, *tmp; if (!ipset) return;
HASH_ITER(hh, ipset , ips, tmp)
{
print_cidr4(&ips->cidr);
printf("\n");
}
}
void ipset6Destroy(ipset6 **ipset) struct cidr4 c;
{ const struct kavl_bit_elem *elem;
ipset6 *elem, *tmp; kavl_itr_t(kavl_bit) itr;
HASH_ITER(hh, *ipset, elem, tmp) kavl_itr_first(kavl_bit, ipset, &itr);
{
HASH_DEL(*ipset, elem);
free(elem);
}
}
bool ipset6Check(ipset6 *ipset, const struct in6_addr *a, uint8_t preflen)
{
struct cidr6 cidr;
ipset6 *ips_found;
// zero alignment bytes
memset(&cidr,0,sizeof(cidr));
cidr.preflen = preflen+1;
do do
{ {
cidr.preflen--; elem = kavl_at(&itr);
ip6_and(a, mask_from_preflen6(cidr.preflen), &cidr.addr); c.preflen = elem->bitlen;
HASH_FIND(hh, ipset, &cidr, sizeof(cidr), ips_found); expand_bits(&c.addr, elem->data, elem->bitlen, sizeof(c.addr));
if (ips_found) return true; print_cidr4(&c);
} while(cidr.preflen);
return false;
}
bool ipset6Add(ipset6 **ipset, const struct in6_addr *a, uint8_t preflen)
{
if (preflen>128) return false;
// avoid dups
if (ipset6Check(*ipset, a, preflen)) return true; // already included
struct ipset6 *entry = calloc(1,sizeof(ipset6));
if (!entry) return false;
ip6_and(a, mask_from_preflen6(preflen), &entry->cidr.addr);
entry->cidr.preflen = preflen;
oom = false;
HASH_ADD(hh, *ipset, cidr, sizeof(entry->cidr), entry);
if (oom) { free(entry); return false; }
return true;
}
void ipset6Print(ipset6 *ipset)
{
ipset6 *ips, *tmp;
HASH_ITER(hh, ipset , ips, tmp)
{
print_cidr6(&ips->cidr);
printf("\n"); printf("\n");
} }
while (kavl_itr_next(kavl_bit, &itr));
}
bool ipset6Check(const struct kavl_bit_elem *ipset, const struct in6_addr *a, uint8_t preflen)
{
return !!kavl_bit_get(ipset,a,preflen);
}
bool ipset6Add(struct kavl_bit_elem **ipset, const struct in6_addr *a, uint8_t preflen)
{
if (preflen>128) return false;
return ipset_kavl_add(ipset,a,preflen);
}
void ipset6Print(struct kavl_bit_elem *ipset)
{
if (!ipset) return;
struct cidr6 c;
const struct kavl_bit_elem *elem;
kavl_itr_t(kavl_bit) itr;
kavl_itr_first(kavl_bit, ipset, &itr);
do
{
elem = kavl_at(&itr);
c.preflen = elem->bitlen;
expand_bits(&c.addr, elem->data, elem->bitlen, sizeof(c.addr));
print_cidr6(&c);
printf("\n");
}
while (kavl_itr_next(kavl_bit, &itr));
} }
void ipsetDestroy(ipset *ipset) void ipsetDestroy(ipset *ipset)
{ {
ipset4Destroy(&ipset->ips4); kavl_bit_destroy(&ipset->ips4);
ipset6Destroy(&ipset->ips6); kavl_bit_destroy(&ipset->ips6);
} }
void ipsetPrint(ipset *ipset) void ipsetPrint(ipset *ipset)
{ {
@@ -520,7 +548,7 @@ bool port_filters_deny_if_empty(struct port_filters_head *head)
} }
struct blob_item *blob_collection_add(struct blob_collection_head *head) struct blob_item *blob_collection_add(struct blob_collection_head *head)
{ {
struct blob_item *entry = calloc(1,sizeof(struct blob_item)); struct blob_item *entry = calloc(1,sizeof(struct blob_item));
@@ -591,6 +619,7 @@ static void ipcache_item_init(ip_cache_item *item)
{ {
ipcache_item_touch(item); ipcache_item_touch(item);
item->hostname = NULL; item->hostname = NULL;
item->hostname_is_ip = false;
} }
static void ipcache_item_destroy(ip_cache_item *item) static void ipcache_item_destroy(ip_cache_item *item)
{ {
@@ -650,7 +679,7 @@ static void ipcache4Print(ip_cache4 *ipcache)
{ {
*s_ip=0; *s_ip=0;
inet_ntop(AF_INET, &ipc->key.addr, s_ip, sizeof(s_ip)); inet_ntop(AF_INET, &ipc->key.addr, s_ip, sizeof(s_ip));
printf("%s : hostname=%s now=last+%llu\n", s_ip, ipc->data.hostname ? ipc->data.hostname : "", (unsigned long long)(now-ipc->data.last)); printf("%s : hostname=%s hostname_is_ip=%u now=last+%llu\n", s_ip, ipc->data.hostname ? ipc->data.hostname : "", ipc->data.hostname_is_ip, (unsigned long long)(now-ipc->data.last));
} }
} }
@@ -707,7 +736,7 @@ static void ipcache6Print(ip_cache6 *ipcache)
{ {
*s_ip=0; *s_ip=0;
inet_ntop(AF_INET6, &ipc->key.addr, s_ip, sizeof(s_ip)); inet_ntop(AF_INET6, &ipc->key.addr, s_ip, sizeof(s_ip));
printf("%s : hostname=%s now=last+%llu\n", s_ip, ipc->data.hostname ? ipc->data.hostname : "", (unsigned long long)(now-ipc->data.last)); printf("%s : hostname=%s hostname_is_ip=%u now=last+%llu\n", s_ip, ipc->data.hostname ? ipc->data.hostname : "", ipc->data.hostname_is_ip, (unsigned long long)(now-ipc->data.last));
} }
} }

View File

@@ -13,6 +13,8 @@
#define HASH_FUNCTION HASH_BER #define HASH_FUNCTION HASH_BER
#include "uthash.h" #include "uthash.h"
#include "kavl.h"
#define HOSTLIST_POOL_FLAG_STRICT_MATCH 1 #define HOSTLIST_POOL_FLAG_STRICT_MATCH 1
typedef struct hostlist_pool { typedef struct hostlist_pool {
@@ -76,39 +78,40 @@ struct hostlist_item *hostlist_collection_search(struct hostlist_collection_head
bool hostlist_collection_is_empty(const struct hostlist_collection_head *head); bool hostlist_collection_is_empty(const struct hostlist_collection_head *head);
typedef struct ipset4 { struct kavl_bit_elem
struct cidr4 cidr; /* key */ {
UT_hash_handle hh; /* makes this structure hashable */ unsigned int bitlen;
} ipset4; uint8_t *data;
typedef struct ipset6 { KAVL_HEAD(struct kavl_bit_elem) head;
struct cidr6 cidr; /* key */ };
UT_hash_handle hh; /* makes this structure hashable */
} ipset6; struct kavl_bit_elem *kavl_bit_get(const struct kavl_bit_elem *hdr, const void *data, unsigned int bitlen);
struct kavl_bit_elem *kavl_bit_add(struct kavl_bit_elem **hdr, void *data, unsigned int bitlen, size_t struct_size);
void kavl_bit_delete(struct kavl_bit_elem **hdr, const void *data, unsigned int bitlen);
void kavl_bit_destroy(struct kavl_bit_elem **hdr);
// combined ipset ipv4 and ipv6 // combined ipset ipv4 and ipv6
typedef struct ipset { typedef struct ipset {
ipset4 *ips4; struct kavl_bit_elem *ips4,*ips6;
ipset6 *ips6;
} ipset; } ipset;
#define IPSET_EMPTY(ips) (!(ips)->ips4 && !(ips)->ips6) #define IPSET_EMPTY(ips) (!(ips)->ips4 && !(ips)->ips6)
void ipset4Destroy(ipset4 **ipset); bool ipset4Add(struct kavl_bit_elem **ipset, const struct in_addr *a, uint8_t preflen);
bool ipset4Add(ipset4 **ipset, const struct in_addr *a, uint8_t preflen); static inline bool ipset4AddCidr(struct kavl_bit_elem **ipset, const struct cidr4 *cidr)
static inline bool ipset4AddCidr(ipset4 **ipset, const struct cidr4 *cidr)
{ {
return ipset4Add(ipset,&cidr->addr,cidr->preflen); return ipset4Add(ipset,&cidr->addr,cidr->preflen);
} }
bool ipset4Check(ipset4 *ipset, const struct in_addr *a, uint8_t preflen); bool ipset4Check(const struct kavl_bit_elem *ipset, const struct in_addr *a, uint8_t preflen);
void ipset4Print(ipset4 *ipset); void ipset4Print(struct kavl_bit_elem *ipset);
void ipset6Destroy(ipset6 **ipset); bool ipset6Add(struct kavl_bit_elem **ipset, const struct in6_addr *a, uint8_t preflen);
bool ipset6Add(ipset6 **ipset, const struct in6_addr *a, uint8_t preflen); static inline bool ipset6AddCidr(struct kavl_bit_elem **ipset, const struct cidr6 *cidr)
static inline bool ipset6AddCidr(ipset6 **ipset, const struct cidr6 *cidr)
{ {
return ipset6Add(ipset,&cidr->addr,cidr->preflen); return ipset6Add(ipset,&cidr->addr,cidr->preflen);
} }
bool ipset6Check(ipset6 *ipset, const struct in6_addr *a, uint8_t preflen); bool ipset6Check(const struct kavl_bit_elem *ipset, const struct in6_addr *a, uint8_t preflen);
void ipset6Print(ipset6 *ipset); void ipset6Print(struct kavl_bit_elem *ipset);
void ipsetDestroy(ipset *ipset); void ipsetDestroy(ipset *ipset);
void ipsetPrint(ipset *ipset); void ipsetPrint(ipset *ipset);
@@ -176,6 +179,7 @@ typedef struct ip_cache_item
{ {
time_t last; time_t last;
char *hostname; char *hostname;
bool hostname_is_ip;
} ip_cache_item; } ip_cache_item;
typedef struct ip_cache4 typedef struct ip_cache4
{ {

View File

@@ -169,25 +169,24 @@ static bool set_seccomp(void)
bool sec_harden(void) bool sec_harden(void)
{ {
bool bRes = true;
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0))
{ {
DLOG_PERROR("PR_SET_NO_NEW_PRIVS(prctl)"); DLOG_PERROR("PR_SET_NO_NEW_PRIVS(prctl)");
return false; bRes = false;
} }
#if ARCH_NR!=0 #if ARCH_NR!=0
if (!set_seccomp()) if (!set_seccomp())
{ {
DLOG_PERROR("seccomp"); DLOG_PERROR("seccomp");
if (errno==EINVAL) DLOG_ERR("seccomp: this can be safely ignored if kernel does not support seccomp\n"); if (errno==EINVAL) DLOG_ERR("seccomp: this can be safely ignored if kernel does not support seccomp\n");
return false; bRes = false;
} }
#endif #endif
return true; return bRes;
} }
bool checkpcap(uint64_t caps) bool checkpcap(uint64_t caps)
{ {
if (!caps) return true; // no special caps reqd if (!caps) return true; // no special caps reqd
@@ -270,8 +269,13 @@ bool can_drop_root(void)
#endif #endif
} }
bool droproot(uid_t uid, gid_t gid) bool droproot(uid_t uid, const char *user, const gid_t *gid, int gid_count)
{ {
if (gid_count<1)
{
DLOG_ERR("droproot: no groups specified");
return false;
}
#ifdef __linux__ #ifdef __linux__
if (prctl(PR_SET_KEEPCAPS, 1L)) if (prctl(PR_SET_KEEPCAPS, 1L))
{ {
@@ -279,13 +283,25 @@ bool droproot(uid_t uid, gid_t gid)
return false; return false;
} }
#endif #endif
// drop all SGIDs if (user)
if (setgroups(0,NULL))
{ {
DLOG_PERROR("setgroups"); // macos has strange supp gid handling. they cache only 16 groups and fail setgroups if more than 16 gids specified.
return false; // better to leave it to the os
if (initgroups(user,gid[0]))
{
DLOG_PERROR("initgroups");
return false;
}
} }
if (setgid(gid)) else
{
if (setgroups(gid_count,gid))
{
DLOG_PERROR("setgroups");
return false;
}
}
if (setgid(gid[0]))
{ {
DLOG_PERROR("setgid"); DLOG_PERROR("setgid");
return false; return false;

View File

@@ -84,7 +84,7 @@ bool dropcaps(void);
bool sec_harden(void); bool sec_harden(void);
bool can_drop_root(); bool can_drop_root();
bool droproot(uid_t uid, gid_t gid); bool droproot(uid_t uid, const char *user, const gid_t *gid, int gid_count);
void print_id(void); void print_id(void);
void daemonize(void); void daemonize(void);
bool writepid(const char *filename); bool writepid(const char *filename);

View File

@@ -91,7 +91,7 @@ static void TLSDebug(const uint8_t *tls,size_t sz)
TLSDebugHandshake(tls+5,sz-5); TLSDebugHandshake(tls+5,sz-5);
} }
bool ipcache_put_hostname(const struct in_addr *a4, const struct in6_addr *a6, const char *hostname) bool ipcache_put_hostname(const struct in_addr *a4, const struct in6_addr *a6, const char *hostname, bool hostname_is_ip)
{ {
if (!params.cache_hostname) return true; if (!params.cache_hostname) return true;
@@ -109,11 +109,12 @@ bool ipcache_put_hostname(const struct in_addr *a4, const struct in6_addr *a6, c
DLOG_ERR("ipcache_put_hostname: out of memory\n"); DLOG_ERR("ipcache_put_hostname: out of memory\n");
return false; return false;
} }
VPRINT("hostname cached: %s\n", hostname); ipc->hostname_is_ip = hostname_is_ip;
VPRINT("hostname cached (is_ip=%u): %s\n", hostname_is_ip, hostname);
} }
return true; return true;
} }
static bool ipcache_get_hostname(const struct in_addr *a4, const struct in6_addr *a6, char *hostname, size_t hostname_buf_len) static bool ipcache_get_hostname(const struct in_addr *a4, const struct in6_addr *a6, char *hostname, size_t hostname_buf_len, bool *hostname_is_ip)
{ {
if (!params.cache_hostname) if (!params.cache_hostname)
{ {
@@ -128,15 +129,16 @@ static bool ipcache_get_hostname(const struct in_addr *a4, const struct in6_addr
} }
if (ipc->hostname) if (ipc->hostname)
{ {
VPRINT("got cached hostname: %s\n", ipc->hostname); VPRINT("got cached hostname (is_ip=%u): %s\n", ipc->hostname_is_ip, ipc->hostname);
snprintf(hostname,hostname_buf_len,"%s",ipc->hostname); snprintf(hostname,hostname_buf_len,"%s",ipc->hostname);
if (hostname_is_ip) *hostname_is_ip = ipc->hostname_is_ip;
} }
else else
*hostname = 0; *hostname = 0;
return true; return true;
} }
static bool dp_match(struct desync_profile *dp, const struct sockaddr *dest, const char *hostname, t_l7proto l7proto) static bool dp_match(struct desync_profile *dp, const struct sockaddr *dest, const char *hostname, bool bNoSubdom, t_l7proto l7proto)
{ {
bool bHostlistsEmpty; bool bHostlistsEmpty;
@@ -167,11 +169,11 @@ static bool dp_match(struct desync_profile *dp, const struct sockaddr *dest, con
return true; return true;
else if (hostname) else if (hostname)
// if hostlists are present profile matches only if hostname is known and satisfy profile hostlists // if hostlists are present profile matches only if hostname is known and satisfy profile hostlists
return HostlistCheck(dp, hostname, NULL, true); return HostlistCheck(dp, hostname, bNoSubdom, NULL, true);
return false; return false;
} }
static struct desync_profile *dp_find(struct desync_profile_list_head *head, const struct sockaddr *dest, const char *hostname, t_l7proto l7proto) static struct desync_profile *dp_find(struct desync_profile_list_head *head, const struct sockaddr *dest, const char *hostname, bool bNoSubdom, t_l7proto l7proto)
{ {
struct desync_profile_list *dpl; struct desync_profile_list *dpl;
if (params.debug) if (params.debug)
@@ -182,7 +184,7 @@ static struct desync_profile *dp_find(struct desync_profile_list_head *head, con
} }
LIST_FOREACH(dpl, head, next) LIST_FOREACH(dpl, head, next)
{ {
if (dp_match(&dpl->dp,dest,hostname,l7proto)) if (dp_match(&dpl->dp,dest,hostname,bNoSubdom,l7proto))
{ {
VPRINT("desync profile %d matches\n",dpl->dp.n); VPRINT("desync profile %d matches\n",dpl->dp.n);
return &dpl->dp; return &dpl->dp;
@@ -198,11 +200,11 @@ void apply_desync_profile(t_ctrack *ctrack, const struct sockaddr *dest)
if (!ctrack->hostname) if (!ctrack->hostname)
{ {
char host[256]; char host[256];
if (ipcache_get_hostname(dest->sa_family==AF_INET ? &((struct sockaddr_in*)dest)->sin_addr : NULL, dest->sa_family==AF_INET6 ? &((struct sockaddr_in6*)dest)->sin6_addr : NULL , host, sizeof(host)) && *host) if (ipcache_get_hostname(dest->sa_family==AF_INET ? &((struct sockaddr_in*)dest)->sin_addr : NULL, dest->sa_family==AF_INET6 ? &((struct sockaddr_in6*)dest)->sin6_addr : NULL , host, sizeof(host), &ctrack->hostname_is_ip) && *host)
if (!(ctrack->hostname=strdup(host))) if (!(ctrack->hostname=strdup(host)))
DLOG_ERR("hostname dup : out of memory"); DLOG_ERR("hostname dup : out of memory");
} }
ctrack->dp = dp_find(&params.desync_profiles, dest, ctrack->hostname, ctrack->l7proto); ctrack->dp = dp_find(&params.desync_profiles, dest, ctrack->hostname, ctrack->hostname_is_ip, ctrack->l7proto);
} }
@@ -213,7 +215,7 @@ void tamper_out(t_ctrack *ctrack, const struct sockaddr *dest, uint8_t *segment,
uint8_t *p, *pp, *pHost = NULL; uint8_t *p, *pp, *pHost = NULL;
size_t method_len = 0, pos, tpos, orig_size=*size; size_t method_len = 0, pos, tpos, orig_size=*size;
const char *method; const char *method;
bool bHaveHost = false; bool bHaveHost = false, bHostIsIp = false;
char *pc, Host[256]; char *pc, Host[256];
t_l7proto l7proto; t_l7proto l7proto;
@@ -271,8 +273,9 @@ void tamper_out(t_ctrack *ctrack, const struct sockaddr *dest, uint8_t *segment,
if (bHaveHost) if (bHaveHost)
{ {
bHostIsIp = strip_host_to_ip(Host);
VPRINT("request hostname: %s\n", Host); VPRINT("request hostname: %s\n", Host);
if (!ipcache_put_hostname(dest->sa_family==AF_INET ? &((struct sockaddr_in*)dest)->sin_addr : NULL, dest->sa_family==AF_INET6 ? &((struct sockaddr_in6*)dest)->sin6_addr : NULL , Host)) if (!ipcache_put_hostname(dest->sa_family==AF_INET ? &((struct sockaddr_in*)dest)->sin_addr : NULL, dest->sa_family==AF_INET6 ? &((struct sockaddr_in6*)dest)->sin6_addr : NULL , Host, bHostIsIp))
DLOG_ERR("ipcache_put_hostname: out of memory"); DLOG_ERR("ipcache_put_hostname: out of memory");
} }
@@ -293,6 +296,7 @@ void tamper_out(t_ctrack *ctrack, const struct sockaddr *dest, uint8_t *segment,
DLOG_ERR("strdup hostname : out of memory\n"); DLOG_ERR("strdup hostname : out of memory\n");
return; return;
} }
ctrack->hostname_is_ip = bHostIsIp;
ctrack->hostname_discovered = true; ctrack->hostname_discovered = true;
} }
@@ -312,7 +316,7 @@ void tamper_out(t_ctrack *ctrack, const struct sockaddr *dest, uint8_t *segment,
if (bHaveHost && !ctrack->b_host_checked) if (bHaveHost && !ctrack->b_host_checked)
{ {
bool bHostExcluded; bool bHostExcluded;
ctrack->b_host_matches = HostlistCheck(ctrack->dp, Host, &bHostExcluded, false); ctrack->b_host_matches = HostlistCheck(ctrack->dp, Host, bHostIsIp, &bHostExcluded, false);
ctrack->b_host_checked = true; ctrack->b_host_checked = true;
if (!ctrack->b_host_matches) if (!ctrack->b_host_matches)
ctrack->b_ah_check = !bHostExcluded; ctrack->b_ah_check = !bHostExcluded;
@@ -542,7 +546,7 @@ static void auto_hostlist_reset_fail_counter(struct desync_profile *dp, const ch
} }
} }
static void auto_hostlist_failed(struct desync_profile *dp, const char *hostname, const char *client_ip_port, t_l7proto l7proto) static void auto_hostlist_failed(struct desync_profile *dp, const char *hostname, bool bNoSubdom, const char *client_ip_port, t_l7proto l7proto)
{ {
hostfail_pool *fail_counter; hostfail_pool *fail_counter;
@@ -566,7 +570,7 @@ static void auto_hostlist_failed(struct desync_profile *dp, const char *hostname
VPRINT("auto hostlist (profile %d) : rechecking %s to avoid duplicates\n", dp->n, hostname); VPRINT("auto hostlist (profile %d) : rechecking %s to avoid duplicates\n", dp->n, hostname);
bool bExcluded=false; bool bExcluded=false;
if (!HostlistCheck(dp, hostname, &bExcluded, false) && !bExcluded) if (!HostlistCheck(dp, hostname, bNoSubdom, &bExcluded, false) && !bExcluded)
{ {
VPRINT("auto hostlist (profile %d) : adding %s to %s\n", dp->n, hostname, dp->hostlist_auto->filename); VPRINT("auto hostlist (profile %d) : adding %s to %s\n", dp->n, hostname, dp->hostlist_auto->filename);
HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : client %s : proto %s : adding to %s", hostname, dp->n, client_ip_port, l7proto_str(l7proto), dp->hostlist_auto->filename); HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : client %s : proto %s : adding to %s", hostname, dp->n, client_ip_port, l7proto_str(l7proto), dp->hostlist_auto->filename);
@@ -626,7 +630,7 @@ void tamper_in(t_ctrack *ctrack, const struct sockaddr *client, uint8_t *segment
// received not http reply. do not monitor this connection anymore // received not http reply. do not monitor this connection anymore
VPRINT("incoming unknown HTTP data detected for hostname %s\n", ctrack->hostname); VPRINT("incoming unknown HTTP data detected for hostname %s\n", ctrack->hostname);
} }
if (bFail) auto_hostlist_failed(ctrack->dp, ctrack->hostname, client_ip_port, ctrack->l7proto); if (bFail) auto_hostlist_failed(ctrack->dp, ctrack->hostname, ctrack->hostname_is_ip, client_ip_port, ctrack->l7proto);
} }
if (!bFail) auto_hostlist_reset_fail_counter(ctrack->dp, ctrack->hostname, client_ip_port, ctrack->l7proto); if (!bFail) auto_hostlist_reset_fail_counter(ctrack->dp, ctrack->hostname, client_ip_port, ctrack->l7proto);
} }
@@ -651,7 +655,7 @@ void rst_in(t_ctrack *ctrack, const struct sockaddr *client)
{ {
VPRINT("incoming RST detected for hostname %s\n", ctrack->hostname); VPRINT("incoming RST detected for hostname %s\n", ctrack->hostname);
HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : client %s : proto %s : incoming RST", ctrack->hostname, ctrack->dp->n, client_ip_port, l7proto_str(ctrack->l7proto)); HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : client %s : proto %s : incoming RST", ctrack->hostname, ctrack->dp->n, client_ip_port, l7proto_str(ctrack->l7proto));
auto_hostlist_failed(ctrack->dp, ctrack->hostname, client_ip_port, ctrack->l7proto); auto_hostlist_failed(ctrack->dp, ctrack->hostname, ctrack->hostname_is_ip, client_ip_port, ctrack->l7proto);
} }
} }
} }
@@ -674,7 +678,7 @@ void hup_out(t_ctrack *ctrack, const struct sockaddr *client)
// local leg dropped connection after first request. probably due to timeout. // local leg dropped connection after first request. probably due to timeout.
VPRINT("local leg closed connection after first request (timeout ?). hostname: %s\n", ctrack->hostname); VPRINT("local leg closed connection after first request (timeout ?). hostname: %s\n", ctrack->hostname);
HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : client %s : proto %s : client closed connection without server reply", ctrack->hostname, ctrack->dp->n, client_ip_port, l7proto_str(ctrack->l7proto)); HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : client %s : proto %s : client closed connection without server reply", ctrack->hostname, ctrack->dp->n, client_ip_port, l7proto_str(ctrack->l7proto));
auto_hostlist_failed(ctrack->dp, ctrack->hostname, client_ip_port, ctrack->l7proto); auto_hostlist_failed(ctrack->dp, ctrack->hostname, ctrack->hostname_is_ip, client_ip_port, ctrack->l7proto);
} }
} }
} }

View File

@@ -16,12 +16,13 @@ typedef struct
bool bTamperInCutoff; bool bTamperInCutoff;
bool b_host_checked,b_host_matches,b_ah_check; bool b_host_checked,b_host_matches,b_ah_check;
bool hostname_discovered; bool hostname_discovered;
bool hostname_is_ip;
char *hostname; char *hostname;
struct desync_profile *dp; // desync profile cache struct desync_profile *dp; // desync profile cache
} t_ctrack; } t_ctrack;
void apply_desync_profile(t_ctrack *ctrack, const struct sockaddr *dest); void apply_desync_profile(t_ctrack *ctrack, const struct sockaddr *dest);
bool ipcache_put_hostname(const struct in_addr *a4, const struct in6_addr *a6, const char *hostname); bool ipcache_put_hostname(const struct in_addr *a4, const struct in6_addr *a6, const char *hostname, bool hostname_is_ip);
void tamper_out(t_ctrack *ctrack, const struct sockaddr *dest, uint8_t *segment,size_t segment_buffer_size,size_t *size, size_t *multisplit_pos, int *multisplit_count, uint8_t *split_flags); void tamper_out(t_ctrack *ctrack, const struct sockaddr *dest, uint8_t *segment,size_t segment_buffer_size,size_t *size, size_t *multisplit_pos, int *multisplit_count, uint8_t *split_flags);
void tamper_in(t_ctrack *ctrack, const struct sockaddr *client, uint8_t *segment,size_t segment_buffer_size,size_t *size); void tamper_in(t_ctrack *ctrack, const struct sockaddr *client, uint8_t *segment,size_t segment_buffer_size,size_t *size);

View File

@@ -23,6 +23,7 @@
#include <sys/resource.h> #include <sys/resource.h>
#include <time.h> #include <time.h>
#include <syslog.h> #include <syslog.h>
#include <grp.h>
#ifdef __ANDROID__ #ifdef __ANDROID__
#include "andr/ifaddrs.h" #include "andr/ifaddrs.h"
@@ -214,8 +215,8 @@ static void exithelp(void)
" --daemon\t\t\t\t; daemonize\n" " --daemon\t\t\t\t; daemonize\n"
" --pidfile=<filename>\t\t\t; write pid to file\n" " --pidfile=<filename>\t\t\t; write pid to file\n"
" --user=<username>\t\t\t; drop root privs\n" " --user=<username>\t\t\t; drop root privs\n"
" --uid=uid[:gid]\t\t\t; drop root privs\n" " --uid=uid[:gid1,gid2,...]\t\t; drop root privs\n"
#if defined(__FreeBSD__) #if defined(__FreeBSD__) || defined(__OpenBSD__)
" --enable-pf\t\t\t\t; enable PF redirector support. required in FreeBSD when used with PF firewall.\n" " --enable-pf\t\t\t\t; enable PF redirector support. required in FreeBSD when used with PF firewall.\n"
#endif #endif
#if defined(__linux__) #if defined(__linux__)
@@ -223,7 +224,11 @@ static void exithelp(void)
#endif #endif
" --ipcache-lifetime=<int>\t\t; time in seconds to keep cached domain name (default %u). 0 = no expiration\n" " --ipcache-lifetime=<int>\t\t; time in seconds to keep cached domain name (default %u). 0 = no expiration\n"
" --ipcache-hostname=[0|1]\t\t; 1 or no argument enables ip->hostname caching\n" " --ipcache-hostname=[0|1]\t\t; 1 or no argument enables ip->hostname caching\n"
#ifdef __ANDROID__
" --debug=0|1|2|syslog|android|@<filename> ; 1 and 2 means log to console and set debug level. for other targets use --debug-level.\n"
#else
" --debug=0|1|2|syslog|@<filename>\t; 1 and 2 means log to console and set debug level. for other targets use --debug-level.\n" " --debug=0|1|2|syslog|@<filename>\t; 1 and 2 means log to console and set debug level. for other targets use --debug-level.\n"
#endif
" --debug-level=0|1|2\t\t\t; specify debug level\n" " --debug-level=0|1|2\t\t\t; specify debug level\n"
" --dry-run\t\t\t\t; verify parameters and exit with code 0 if successful\n" " --dry-run\t\t\t\t; verify parameters and exit with code 0 if successful\n"
" --version\t\t\t\t; print version and exit\n" " --version\t\t\t\t; print version and exit\n"
@@ -285,32 +290,14 @@ static void exithelp(void)
); );
exit(1); exit(1);
} }
#if !defined( __OpenBSD__) && !defined(__ANDROID__)
static void cleanup_args()
{
wordfree(&params.wexp);
}
#endif
static void cleanup_params(void)
{
#if !defined( __OpenBSD__) && !defined(__ANDROID__)
cleanup_args();
#endif
dp_list_destroy(&params.desync_profiles);
hostlist_files_destroy(&params.hostlists);
ipset_files_destroy(&params.ipsets);
ipcacheDestroy(&params.ipcache);
}
static void exithelp_clean(void) static void exithelp_clean(void)
{ {
cleanup_params(); cleanup_params(&params);
exithelp(); exithelp();
} }
static void exit_clean(int code) static void exit_clean(int code)
{ {
cleanup_params(); cleanup_params(&params);
exit(code); exit(code);
} }
static void nextbind_clean(void) static void nextbind_clean(void)
@@ -583,6 +570,35 @@ static bool parse_ip_list(char *opt, ipset *pp)
return true; return true;
} }
static bool parse_uid(const char *opt, uid_t *uid, gid_t *gid, int *gid_count, int max_gids)
{
unsigned int u;
char c, *p, *e;
*gid_count=0;
if ((e = strchr(optarg,':'))) *e++=0;
if (sscanf(opt,"%u",&u)!=1) return false;
*uid = (uid_t)u;
for (p=e ; p ; )
{
if ((e = strchr(p,',')))
{
c=*e;
*e=0;
}
if (p)
{
if (sscanf(p,"%u",&u)!=1) return false;
if (*gid_count>=max_gids) return false;
gid[(*gid_count)++] = (gid_t)u;
}
if (e) *e++=c;
p = e;
}
return true;
}
#if !defined( __OpenBSD__) && !defined(__ANDROID__) #if !defined( __OpenBSD__) && !defined(__ANDROID__)
// no static to not allow optimizer to inline this func (save stack) // no static to not allow optimizer to inline this func (save stack)
void config_from_file(const char *filename) void config_from_file(const char *filename)
@@ -695,7 +711,7 @@ enum opt_indices {
IDX_IPSET_EXCLUDE, IDX_IPSET_EXCLUDE,
IDX_IPSET_EXCLUDE_IP, IDX_IPSET_EXCLUDE_IP,
#if defined(__FreeBSD__) #if defined(__FreeBSD__) || defined(__OpenBSD__)
IDX_ENABLE_PF, IDX_ENABLE_PF,
#elif defined(__APPLE__) #elif defined(__APPLE__)
IDX_LOCAL_TCP_USER_TIMEOUT, IDX_LOCAL_TCP_USER_TIMEOUT,
@@ -788,7 +804,7 @@ static const struct option long_options[] = {
[IDX_IPSET_EXCLUDE] = {"ipset-exclude", required_argument, 0, 0}, [IDX_IPSET_EXCLUDE] = {"ipset-exclude", required_argument, 0, 0},
[IDX_IPSET_EXCLUDE_IP] = {"ipset-exclude-ip", required_argument, 0, 0}, [IDX_IPSET_EXCLUDE_IP] = {"ipset-exclude-ip", required_argument, 0, 0},
#if defined(__FreeBSD__) #if defined(__FreeBSD__) || defined(__OpenBSD__)
[IDX_ENABLE_PF] = {"enable-pf", no_argument, 0, 0}, [IDX_ENABLE_PF] = {"enable-pf", no_argument, 0, 0},
#elif defined(__APPLE__) #elif defined(__APPLE__)
[IDX_LOCAL_TCP_USER_TIMEOUT] = {"local-tcp-user-timeout", required_argument, 0, 0}, [IDX_LOCAL_TCP_USER_TIMEOUT] = {"local-tcp-user-timeout", required_argument, 0, 0},
@@ -824,7 +840,7 @@ void parse_params(int argc, char *argv[])
params.tcp_user_timeout_remote = DEFAULT_TCP_USER_TIMEOUT_REMOTE; params.tcp_user_timeout_remote = DEFAULT_TCP_USER_TIMEOUT_REMOTE;
#endif #endif
#if defined(__OpenBSD__) || defined(__APPLE__) #if defined(__APPLE__)
params.pf_enable = true; // OpenBSD and MacOS have no other choice params.pf_enable = true; // OpenBSD and MacOS have no other choice
#endif #endif
@@ -837,8 +853,9 @@ void parse_params(int argc, char *argv[])
if (can_drop_root()) if (can_drop_root())
{ {
params.uid = params.gid = 0x7FFFFFFF; // default uid:gid params.uid = params.gid[0] = 0x7FFFFFFF; // default uid:gid
params.droproot = true; params.gid_count = 1;
params.droproot = true;
} }
struct desync_profile_list *dpl; struct desync_profile_list *dpl;
@@ -947,6 +964,7 @@ void parse_params(int argc, char *argv[])
break; break;
case IDX_USER: case IDX_USER:
{ {
free(params.user); params.user=NULL;
struct passwd *pwd = getpwnam(optarg); struct passwd *pwd = getpwnam(optarg);
if (!pwd) if (!pwd)
{ {
@@ -954,18 +972,29 @@ void parse_params(int argc, char *argv[])
exit_clean(1); exit_clean(1);
} }
params.uid = pwd->pw_uid; params.uid = pwd->pw_uid;
params.gid = pwd->pw_gid; params.gid[0]=pwd->pw_gid;
params.gid_count=1;
if (!(params.user=strdup(optarg)))
{
DLOG_ERR("strdup: out of memory\n");
exit_clean(1);
}
params.droproot = true; params.droproot = true;
break; break;
} }
case IDX_UID: case IDX_UID:
params.gid=0x7FFFFFFF; // default git. drop gid=0 free(params.user); params.user=NULL;
params.droproot = true; if (!parse_uid(optarg,&params.uid,params.gid,&params.gid_count,MAX_GIDS))
if (sscanf(optarg,"%u:%u",&params.uid,&params.gid)<1)
{ {
DLOG_ERR("--uid should be : uid[:gid]\n"); DLOG_ERR("--uid should be : uid[:gid,gid,...]\n");
exit_clean(1); exit_clean(1);
} }
if (!params.gid_count)
{
params.gid[0] = 0x7FFFFFFF;
params.gid_count = 1;
}
params.droproot = true;
break; break;
case IDX_MAXCONN: case IDX_MAXCONN:
params.maxconn = atoi(optarg); params.maxconn = atoi(optarg);
@@ -1273,8 +1302,7 @@ void parse_params(int argc, char *argv[])
} }
break; break;
case IDX_PIDFILE: case IDX_PIDFILE:
strncpy(params.pidfile,optarg,sizeof(params.pidfile)); snprintf(params.pidfile,sizeof(params.pidfile),"%s",optarg);
params.pidfile[sizeof(params.pidfile)-1]='\0';
break; break;
case IDX_DEBUG: case IDX_DEBUG:
if (optarg) if (optarg)
@@ -1296,13 +1324,25 @@ void parse_params(int argc, char *argv[])
{ {
if (!params.debug) params.debug = 1; if (!params.debug) params.debug = 1;
params.debug_target = LOG_TARGET_SYSLOG; params.debug_target = LOG_TARGET_SYSLOG;
openlog("tpws",LOG_PID,LOG_USER); openlog(progname,LOG_PID,LOG_USER);
} }
else #ifdef __ANDROID__
else if (!strcmp(optarg,"android"))
{
if (!params.debug) params.debug = 1;
params.debug_target = LOG_TARGET_ANDROID;
}
#endif
else if (optarg[0]>='0' && optarg[0]<='2')
{ {
params.debug = atoi(optarg); params.debug = atoi(optarg);
params.debug_target = LOG_TARGET_CONSOLE; params.debug_target = LOG_TARGET_CONSOLE;
} }
else
{
fprintf(stderr, "invalid debug mode : %s\n", optarg);
exit_clean(1);
}
} }
else else
{ {
@@ -1514,7 +1554,7 @@ void parse_params(int argc, char *argv[])
params.tamper = true; params.tamper = true;
break; break;
#if defined(__FreeBSD__) #if defined(__FreeBSD__) || defined(__OpenBSD__)
case IDX_ENABLE_PF: case IDX_ENABLE_PF:
params.pf_enable = true; params.pf_enable = true;
break; break;
@@ -1662,10 +1702,22 @@ void parse_params(int argc, char *argv[])
#if !defined( __OpenBSD__) && !defined(__ANDROID__) #if !defined( __OpenBSD__) && !defined(__ANDROID__)
// do not need args from file anymore // do not need args from file anymore
cleanup_args(); cleanup_args(&params);
#endif #endif
if (bDry) if (bDry)
{ {
if (params.droproot)
{
if (!droproot(params.uid,params.user,params.gid,params.gid_count))
exit_clean(1);
#ifdef __linux__
if (!dropcaps())
exit_clean(1);
#endif
print_id();
if (!test_list_files())
exit_clean(1);
}
DLOG_CONDUP("command line parameters verified\n"); DLOG_CONDUP("command line parameters verified\n");
exit_clean(0); exit_clean(0);
} }
@@ -1822,10 +1874,18 @@ static const char *bindll_s[] = { "unwanted","no","prefer","force" };
#define STRINGIFY(x) #x #define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x) #define TOSTRING(x) STRINGIFY(x)
#if defined(ZAPRET_GH_VER) || defined (ZAPRET_GH_HASH) #if defined(ZAPRET_GH_VER) || defined (ZAPRET_GH_HASH)
#ifdef __ANDROID__
#define PRINT_VER printf("github android version %s (%s)\n\n", TOSTRING(ZAPRET_GH_VER), TOSTRING(ZAPRET_GH_HASH))
#else
#define PRINT_VER printf("github version %s (%s)\n\n", TOSTRING(ZAPRET_GH_VER), TOSTRING(ZAPRET_GH_HASH)) #define PRINT_VER printf("github version %s (%s)\n\n", TOSTRING(ZAPRET_GH_VER), TOSTRING(ZAPRET_GH_HASH))
#endif
#else
#ifdef __ANDROID__
#define PRINT_VER printf("self-built android version %s %s\n\n", __DATE__, __TIME__)
#else #else
#define PRINT_VER printf("self-built version %s %s\n\n", __DATE__, __TIME__) #define PRINT_VER printf("self-built version %s %s\n\n", __DATE__, __TIME__)
#endif #endif
#endif
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
@@ -2086,8 +2146,7 @@ int main(int argc, char *argv[])
} }
set_ulimit(); set_ulimit();
sec_harden(); if (params.droproot && !droproot(params.uid,params.user,params.gid,params.gid_count))
if (params.droproot && !droproot(params.uid,params.gid))
goto exiterr; goto exiterr;
#ifdef __linux__ #ifdef __linux__
if (!dropcaps()) if (!dropcaps())
@@ -2099,6 +2158,8 @@ int main(int argc, char *argv[])
if (params.daemon) daemonize(); if (params.daemon) daemonize();
sec_harden();
if (Fpid) if (Fpid)
{ {
if (fprintf(Fpid, "%d", getpid())<=0) if (fprintf(Fpid, "%d", getpid())<=0)
@@ -2129,6 +2190,6 @@ exiterr:
if (Fpid) fclose(Fpid); if (Fpid) fclose(Fpid);
redir_close(); redir_close();
for(i=0;i<=params.binds_last;i++) if (listen_fd[i]!=-1) close(listen_fd[i]); for(i=0;i<=params.binds_last;i++) if (listen_fd[i]!=-1) close(listen_fd[i]);
cleanup_params(); cleanup_params(&params);
return exit_v; return exit_v;
} }

View File

@@ -495,7 +495,7 @@ static bool connect_remote_conn(tproxy_conn_t *conn)
int mss=0; int mss=0;
if (conn->track.hostname) if (conn->track.hostname)
if (!ipcache_put_hostname(conn->dest.sa_family==AF_INET ? &((struct sockaddr_in*)&conn->dest)->sin_addr : NULL, conn->dest.sa_family==AF_INET6 ? &((struct sockaddr_in6*)&conn->dest)->sin6_addr : NULL , conn->track.hostname)) if (!ipcache_put_hostname(conn->dest.sa_family==AF_INET ? &((struct sockaddr_in*)&conn->dest)->sin_addr : NULL, conn->dest.sa_family==AF_INET6 ? &((struct sockaddr_in6*)&conn->dest)->sin6_addr : NULL , conn->track.hostname, conn->track.hostname_is_ip))
DLOG_ERR("ipcache_put_hostname: out of memory"); DLOG_ERR("ipcache_put_hostname: out of memory");
apply_desync_profile(&conn->track, (struct sockaddr *)&conn->dest); apply_desync_profile(&conn->track, (struct sockaddr *)&conn->dest);
@@ -507,7 +507,7 @@ static bool connect_remote_conn(tproxy_conn_t *conn)
if (conn->track.hostname) if (conn->track.hostname)
{ {
bool bHostExcluded; bool bHostExcluded;
conn->track.b_host_matches = HostlistCheck(conn->track.dp, conn->track.hostname, &bHostExcluded, false); conn->track.b_host_matches = HostlistCheck(conn->track.dp, conn->track.hostname, conn->track.hostname_is_ip, &bHostExcluded, false);
conn->track.b_host_checked = true; conn->track.b_host_checked = true;
if (!conn->track.b_host_matches) if (!conn->track.b_host_matches)
{ {