mirror of
https://github.com/bol-van/zapret.git
synced 2025-08-10 01:02:03 +03:00
Compare commits
96 Commits
ba040769a7
...
v71.3
Author | SHA1 | Date | |
---|---|---|---|
|
a560e251a1 | ||
|
2ff0f9c0ff | ||
|
4dbd673eaa | ||
|
497810ab4e | ||
|
4cfed1db7e | ||
|
fd6b7a2b7f | ||
|
6d865ad790 | ||
|
dfe36aee4c | ||
|
2d704a859d | ||
|
8026d11f71 | ||
|
2f77cec863 | ||
|
ba7954f068 | ||
|
8b5c951451 | ||
|
84e75b0f28 | ||
|
c4e5db309f | ||
|
769f7b60c8 | ||
|
b0578c5e9f | ||
|
40362bfb5b | ||
|
10eb9050a1 | ||
|
b63e598085 | ||
|
c60f9c9027 | ||
|
951c980bec | ||
|
5eaec085dd | ||
|
721b353776 | ||
|
e6d2051c87 | ||
|
e665794ac4 | ||
|
7db14a07c5 | ||
|
c14554c1f3 | ||
|
ced1682003 | ||
|
4701f27372 | ||
|
a1699067b3 | ||
|
643fc0c456 | ||
|
09c07f6d21 | ||
|
dd72c68ae6 | ||
|
9c1a3e77cc | ||
|
ae957e9a73 | ||
|
bc47a13ba4 | ||
|
20b69cb63d | ||
|
ef4f8a2b86 | ||
|
d00d341505 | ||
|
0738d3980f | ||
|
34ff4630bf | ||
|
f8b5f602a4 | ||
|
8dacb57a86 | ||
|
9776d5d8a9 | ||
|
f88c9a662d | ||
|
97bcb9740d | ||
|
b6e9fa3434 | ||
|
32cfee705a | ||
|
1303bf0fef | ||
|
2417d4ee76 | ||
|
64280cbf3d | ||
|
54dd06056e | ||
|
0be4cbf8a4 | ||
|
acf888c493 | ||
|
f3d90d4e00 | ||
|
ceec80a8ed | ||
|
e876096072 | ||
|
796e4a40b6 | ||
|
5b7c4a4318 | ||
|
f09d918b40 | ||
|
f3d48b7160 | ||
|
58d306b552 | ||
|
30a947b42b | ||
|
9fe26c92a5 | ||
|
ab0d16f4e1 | ||
|
c37c39996d | ||
|
87a0cf0797 | ||
|
893a133f86 | ||
|
fa9e3c09f1 | ||
|
2edf6bee34 | ||
|
468d293b46 | ||
|
fd698d801b | ||
|
38a3833351 | ||
|
6c9ff2010b | ||
|
06f57e27ed | ||
|
06921bdbee | ||
|
3999e0b350 | ||
|
1301aca25b | ||
|
bf4244809f | ||
|
99b5406905 | ||
|
ebd01868ee | ||
|
c451addd86 | ||
|
4c8ea084d7 | ||
|
02badb3c4c | ||
|
323307cbfa | ||
|
00560719bd | ||
|
56c96df47b | ||
|
f0a8a35c12 | ||
|
d566f48f94 | ||
|
3513cbb65e | ||
|
20f91cb7ab | ||
|
4becc07572 | ||
|
a39c18737b | ||
|
ed7b743fe2 | ||
|
d3b0b3e0b1 |
27
.github/workflows/build.yml
vendored
27
.github/workflows/build.yml
vendored
@@ -427,7 +427,6 @@ jobs:
|
||||
unzip $f -d $dir && rm $f
|
||||
if [[ $dir =~ win ]]; then
|
||||
chmod -x $dir/*
|
||||
run_upx --force $dir/cygwin1.dll
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
@@ -438,23 +437,23 @@ jobs:
|
||||
if [ -d $dir ]; then
|
||||
echo "Processing $dir"
|
||||
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-x86 ) run_dir android-x86 ;;
|
||||
*-android-x86_64 ) run_dir android-x86_64 ;;
|
||||
*-freebsd-x86_64 ) run_dir freebsd-x64 ;;
|
||||
*-linux-arm ) run_dir arm ;;
|
||||
*-linux-arm64 ) run_dir aarch64 ;;
|
||||
*-linux-mips64 ) run_dir mips64r2-msb ;;
|
||||
*-linux-mipselsf ) run_dir mips32r1-lsb ;;
|
||||
*-linux-mipssf ) run_dir mips32r1-msb ;;
|
||||
*-linux-ppc ) run_dir ppc ;;
|
||||
*-linux-x86 ) run_dir x86 ;;
|
||||
*-linux-x86_64 ) run_dir x86_64 ;;
|
||||
*-linux-lexra ) run_dir lexra ;;
|
||||
*-freebsd-x86_64 ) run_dir freebsd-x86_64 ;;
|
||||
*-linux-arm ) run_dir linux-arm ;;
|
||||
*-linux-arm64 ) run_dir linux-arm64 ;;
|
||||
*-linux-mips64 ) run_dir linux-mips64 ;;
|
||||
*-linux-mipselsf ) run_dir linux-mipsel ;;
|
||||
*-linux-mipssf ) run_dir linux-mips ;;
|
||||
*-linux-ppc ) run_dir linux-ppc ;;
|
||||
*-linux-x86 ) run_dir linux-x86 ;;
|
||||
*-linux-x86_64 ) run_dir linux-x86_64 ;;
|
||||
*-linux-lexra ) run_dir linux-lexra ;;
|
||||
*-mac-x64 ) run_dir mac64 ;;
|
||||
*-win-x86 ) run_dir win32 ;;
|
||||
*-win-x86_64 ) run_dir win64 ;;
|
||||
*-win-x86 ) run_dir windows-x86 ;;
|
||||
*-win-x86_64 ) run_dir windows-x86_64 ;;
|
||||
esac
|
||||
fi
|
||||
done
|
||||
|
@@ -396,13 +396,24 @@ check_system()
|
||||
PKTWS="$WINWS"
|
||||
PKTWSD=winws
|
||||
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
|
||||
exitp 5
|
||||
esac
|
||||
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 CURL=$CURL
|
||||
$CURL --version
|
||||
}
|
||||
|
||||
zp_already_running()
|
||||
@@ -627,7 +638,11 @@ curl_with_subst_ip()
|
||||
# $2 - port
|
||||
# $3 - ip
|
||||
# $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
|
||||
[ "$CURL_VERBOSE" = 1 ] && arg="-v"
|
||||
[ "$CURL_CMD" = 1 ] && echo $CURL ${arg:+$arg }$connect_to "$@"
|
||||
@@ -1062,7 +1077,7 @@ tpws_curl_test()
|
||||
# $1 - test function
|
||||
# $2 - domain
|
||||
# $3,$4,$5, ... - tpws params
|
||||
echo - $1 $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"}
|
||||
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"
|
||||
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=$?
|
||||
@@ -1082,7 +1097,7 @@ pktws_curl_test()
|
||||
local testf=$1 dom=$2 strategy code
|
||||
|
||||
shift; shift;
|
||||
echo - $testf $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"}
|
||||
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=$?
|
||||
@@ -1183,6 +1198,7 @@ warn_fool()
|
||||
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.' ;;
|
||||
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
|
||||
}
|
||||
pktws_curl_test_update_vary()
|
||||
@@ -1309,7 +1325,7 @@ pktws_check_domain_http_bypass_()
|
||||
}
|
||||
f=
|
||||
[ "$UNAME" = "OpenBSD" ] || f="badsum"
|
||||
f="$f badseq datanoack md5sig"
|
||||
f="$f badseq datanoack ts md5sig"
|
||||
[ "$IPV" = 6 ] && f="$f hopbyhop hopbyhop2"
|
||||
for fooling in $f; do
|
||||
ok=0
|
||||
|
@@ -406,12 +406,15 @@ has_bad_ws_options()
|
||||
{
|
||||
# $1 - nfqws/tpws opts
|
||||
|
||||
# kernel or user mode ipset usage should be wise
|
||||
# if all traffic is already intercepted it would be OK to use ip-based specialized profiles
|
||||
# but if all traffic is intercepted only to filter a group of ip its BAD. kernel ipset should be used.
|
||||
# I cannot insert brain to copy-pasters, I know they will misuse. But it's their problem.
|
||||
# zapret is not made for newbies
|
||||
#contains "$1" "--ipset"
|
||||
contains "$1" "--ipset" && {
|
||||
echo
|
||||
echo "WARNING !!! --ipset parameter is present"
|
||||
echo "It's OK if you only specialize already redirected traffic and also process the rest."
|
||||
echo "If you redirect port X to process several IPs from the list and do nothing with the rest - IT'S VERY INEFFECTIVE !"
|
||||
echo "Kernel ipsets should be used instead. Write custom scripts and filter IPs in kernel."
|
||||
echo
|
||||
}
|
||||
|
||||
return 1
|
||||
}
|
||||
check_bad_ws_options()
|
||||
@@ -428,8 +431,5 @@ check_bad_ws_options()
|
||||
}
|
||||
help_bad_ws_options()
|
||||
{
|
||||
echo "WARNING ! you have specified --ipset option"
|
||||
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"
|
||||
echo "WARNING ! BAD options detected"
|
||||
}
|
||||
|
@@ -187,7 +187,7 @@ check_system()
|
||||
|
||||
SYSTEM=
|
||||
SUBSYS=
|
||||
SYSTEMCTL=$(whichq systemctl)
|
||||
SYSTEMCTL="$(whichq systemctl)"
|
||||
|
||||
get_fwtype
|
||||
OPENWRT_FW3=
|
||||
@@ -203,6 +203,7 @@ check_system()
|
||||
# some distros include systemctl without systemd
|
||||
if [ -d "$SYSTEMD_DIR" ] && [ -x "$SYSTEMCTL" ] && [ "$INIT" = "systemd" ]; then
|
||||
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
|
||||
SYSTEM=openwrt
|
||||
OPENWRT_PACKAGER=opkg
|
||||
@@ -226,8 +227,10 @@ check_system()
|
||||
OPENWRT_FW4=1
|
||||
info="${info}firewall fw4. flow offloading requires nftables."
|
||||
fi
|
||||
[ -f "$EXEDIR/init.d/openwrt/functions" ] && . "$EXEDIR/init.d/openwrt/functions"
|
||||
elif openrc_test; then
|
||||
SYSTEM=openrc
|
||||
[ -f "$EXEDIR/init.d/sysv/functions" ] && . "$EXEDIR/init.d/sysv/functions"
|
||||
else
|
||||
echo system is not either systemd, openrc or openwrt based
|
||||
echo easy installer can set up config settings but can\'t configure auto start
|
||||
@@ -237,10 +240,12 @@ check_system()
|
||||
else
|
||||
exitp 5
|
||||
fi
|
||||
[ -f "$EXEDIR/init.d/sysv/functions" ] && . "$EXEDIR/init.d/sysv/functions"
|
||||
fi
|
||||
linux_get_subsys
|
||||
elif [ "$UNAME" = "Darwin" ]; then
|
||||
SYSTEM=macos
|
||||
[ -f "$EXEDIR/init.d/macos/functions" ] && . "$EXEDIR/init.d/macos/functions"
|
||||
else
|
||||
echo easy installer only supports Linux and MacOS. check readme.md for supported systems and manual setup info.
|
||||
exitp 5
|
||||
@@ -834,13 +839,13 @@ dry_run_tpws_()
|
||||
{
|
||||
local TPWS="$ZAPRET_BASE/tpws/tpws"
|
||||
echo verifying tpws options
|
||||
"$TPWS" --dry-run "$@"
|
||||
"$TPWS" --dry-run ${WS_USER:+--user=$WS_USER} "$@"
|
||||
}
|
||||
dry_run_nfqws_()
|
||||
{
|
||||
local NFQWS="$ZAPRET_BASE/nfq/nfqws"
|
||||
echo verifying nfqws options
|
||||
"$NFQWS" --dry-run "$@"
|
||||
"$NFQWS" --dry-run ${WS_USER:+--user=$WS_USER} "$@"
|
||||
}
|
||||
dry_run_tpws()
|
||||
{
|
||||
|
@@ -112,6 +112,10 @@ unprepare_tpws_fw()
|
||||
unprepare_tpws_fw4
|
||||
}
|
||||
|
||||
ipt_mark_filter()
|
||||
{
|
||||
[ -n "$FILTER_MARK" ] && echo "-m mark --mark $FILTER_MARK/$FILTER_MARK"
|
||||
}
|
||||
|
||||
ipt_print_op()
|
||||
{
|
||||
@@ -136,7 +140,7 @@ _fw_tpws4()
|
||||
|
||||
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
|
||||
ipt_add_del $1 PREROUTING -t nat -i $i $rule
|
||||
done
|
||||
@@ -164,7 +168,7 @@ _fw_tpws6()
|
||||
|
||||
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
|
||||
_dnat6_target $i DNAT6
|
||||
[ -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)"
|
||||
|
||||
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
|
||||
for i in $4; do
|
||||
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
|
||||
|
||||
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
|
||||
for i in $4; do
|
||||
ipt6_add_del $1 POSTROUTING -t mangle -o $i $rule
|
||||
|
@@ -312,6 +312,10 @@ nft_filter_apply_ipset_target()
|
||||
nft_filter_apply_ipset_target6 $2
|
||||
}
|
||||
|
||||
nft_mark_filter()
|
||||
{
|
||||
[ -n "$FILTER_MARK" ] && echo "mark and $FILTER_MARK != 0"
|
||||
}
|
||||
|
||||
nft_script_add_ifset_element()
|
||||
{
|
||||
@@ -403,9 +407,10 @@ _nft_fw_tpws4()
|
||||
|
||||
[ "$DISABLE_IPV4" = "1" -o -z "$1" ] || {
|
||||
local filter="$1" port="$2"
|
||||
local mark_filter=$(nft_mark_filter)
|
||||
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_pre iifname @lanif $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 $mark_filter $filter ip daddr != @nozapret ip daddr != @ipban $FW_EXTRA_POST dnat ip to $TPWS_LOCALHOST4:$port
|
||||
prepare_route_localnet
|
||||
}
|
||||
}
|
||||
@@ -418,10 +423,11 @@ _nft_fw_tpws6()
|
||||
|
||||
[ "$DISABLE_IPV6" = "1" -o -z "$1" ] || {
|
||||
local filter="$1" port="$2" DNAT6 i
|
||||
local mark_filter=$(nft_mark_filter)
|
||||
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" ] && {
|
||||
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
|
||||
_dnat6_target $i DNAT6
|
||||
# can be multiple tpws processes on different ports
|
||||
@@ -468,7 +474,7 @@ _nft_fw_nfqws_post4()
|
||||
[ "$DISABLE_IPV4" = "1" -o -z "$1" ] || {
|
||||
local filter="$1" port="$2" rule chain=$(get_postchain) setmark
|
||||
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"
|
||||
nft_insert_rule $chain $rule $setmark $CONNMARKER $FW_EXTRA_POST queue num $port bypass
|
||||
nft_add_nfqws_flow_exempt_rule "$rule"
|
||||
@@ -483,7 +489,7 @@ _nft_fw_nfqws_post6()
|
||||
[ "$DISABLE_IPV6" = "1" -o -z "$1" ] || {
|
||||
local filter="$1" port="$2" rule chain=$(get_postchain) setmark
|
||||
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"
|
||||
nft_insert_rule $chain $rule $setmark $CONNMARKER $FW_EXTRA_POST queue num $port bypass
|
||||
nft_add_nfqws_flow_exempt_rule "$rule"
|
||||
@@ -508,7 +514,7 @@ _nft_fw_nfqws_pre4()
|
||||
[ "$DISABLE_IPV4" = "1" -o -z "$1" ] || {
|
||||
local filter="$1" port="$2" rule
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -521,7 +527,7 @@ _nft_fw_nfqws_pre6()
|
||||
[ "$DISABLE_IPV6" = "1" -o -z "$1" ] || {
|
||||
local filter="$1" port="$2" rule
|
||||
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
|
||||
}
|
||||
}
|
||||
|
@@ -47,6 +47,12 @@ GZIP_LISTS=1
|
||||
DESYNC_MARK=0x40000000
|
||||
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 listens on this port on localhost and LAN interfaces
|
||||
TPPORT_SOCKS=987
|
||||
|
@@ -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
|
||||
others OSes.
|
||||
|
||||
`tpws` for forwarded traffic only :
|
||||
`tpws` for forwarded traffic only (OLDER OS versions):
|
||||
|
||||
`/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:
|
||||
```
|
||||
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
|
||||
scheme work. rdr-to support is done using /dev/pf, that's why transparent mode
|
||||
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:
|
||||
|
||||
`/etc/pf.conf`:
|
||||
|
33
docs/bsd.md
33
docs/bsd.md
@@ -19,7 +19,8 @@
|
||||
* [pfsense](#pfsense)
|
||||
* [OpenBSD](#openbsd)
|
||||
* [tpws bind на ipv4](#tpws-bind-на-ipv4)
|
||||
* [tpws для проходящего трафика](#tpws-для-проходящего-трафика)
|
||||
* [tpws для проходящего трафика (старые системы)](#tpws-для-проходящего-трафика-старая-схема-не-работает-в-новых-версиях))
|
||||
* [tpws для проходящего трафика (новые системы)](#tpws-для-проходящего-трафика-новые-системы))
|
||||
* [Запуск dvtws](#запуск-dvtws)
|
||||
* [Проблемы с badsum](#проблемы-с-badsum)
|
||||
* [Особенность отправки 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`:
|
||||
```
|
||||
@@ -402,15 +407,35 @@ pass in quick on em1 inet6 proto tcp to port {80,443} rdr-to ::1 port 988
|
||||
|
||||
```sh
|
||||
$ 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.
|
||||
> Вариант с route-to не сохраняет мета информацию. Адрес назначения теряется.
|
||||
> Поэтому этот вариант годится для squid, берущего адрес из протокола прикладного уровня, но не годится для tpws, полагающегося на метаданные ОС.
|
||||
> Поддержка 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
|
||||
|
||||
|
@@ -56,14 +56,27 @@ sysctl net.inet6.ip6.forwarding=1
|
||||
|
||||
OpenBSD PF :
|
||||
|
||||
(OLD OpenBSD versions)
|
||||
|
||||
; dont know how to rdr-to from local system. doesn't seem to work. only works for routed traffic.
|
||||
|
||||
/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 inet6 proto tcp to port {80,443} rdr-to ::1 port 988
|
||||
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
|
||||
|
||||
|
||||
; 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
|
||||
|
@@ -491,12 +491,46 @@ nfqws: --orig*
|
||||
nfqws: ipcache of hop count and host names
|
||||
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
|
||||
nfqws,tpws: set 1024 repeat limit to fakes and dups
|
||||
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, 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
|
||||
|
@@ -1,6 +1,6 @@
|
||||
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
|
||||
|
||||
FreeBSD :
|
||||
|
@@ -12,7 +12,7 @@ define Package/nfqws
|
||||
CATEGORY:=Network
|
||||
TITLE:=nfqws
|
||||
SUBMENU:=Zapret
|
||||
DEPENDS:=+libnetfilter-queue +libcap +zlib
|
||||
DEPENDS:=+libnetfilter-queue +lmnl +libcap +zlib
|
||||
endef
|
||||
|
||||
define Build/Prepare
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# zapret v71
|
||||
# zapret v71.3
|
||||
|
||||
# SCAMMER WARNING
|
||||
|
||||
@@ -35,6 +35,7 @@ ___
|
||||
- [UDP support](#udp-support)
|
||||
- [IP fragmentation](#ip-fragmentation)
|
||||
- [Multiple strategies](#multiple-strategies)
|
||||
- [WIFI filtering](#wifi-filtering)
|
||||
- [Virtual machines](#virtual-machines)
|
||||
- [IPTABLES for nfqws](#iptables-for-nfqws)
|
||||
- [NFTABLES for nfqws](#nftables-for-nfqws)
|
||||
@@ -163,17 +164,18 @@ nfqws takes the following parameters:
|
||||
--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
|
||||
--orig-autottl6=[<delta>[:<min>[-<max>]]] ; overrides --orig-autottl for ipv6 only
|
||||
--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
|
||||
--dup-autottl6=[<delta>[:<min>[-<max>]]] ; overrides --dup-autottl for ipv6 only
|
||||
--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
|
||||
@@ -182,8 +184,8 @@ nfqws takes the following parameters:
|
||||
--dpi-desync-fwmark=<int|0xHEX> ; override fwmark for desync packet. default = 0x40000000 (1073741824)
|
||||
--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-autottl=[<delta>[:<min>[-<max>]]] ; auto ttl mode for both ipv4 and ipv6. default: -1:3-20
|
||||
--dpi-desync-autottl6=[<delta>[:<min>[-<max>]]] ; overrides --dpi-desync-autottl for ipv6 only
|
||||
--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-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-skip-nosni=0|1 ; 1(default)=do not act on ClientHello without SNI (ESNI ?)
|
||||
@@ -196,6 +198,7 @@ nfqws takes the following parameters:
|
||||
--dpi-desync-fakedsplit-pattern=<filename>|0xHEX ; fake pattern for fakedsplit/fakeddisorder
|
||||
--dpi-desync-ipfrag-pos-tcp=<8..9216> ; ip frag position starting from the transport header. multiple of 8, default 8.
|
||||
--dpi-desync-ipfrag-pos-udp=<8..9216> ; ip frag position starting from the transport header. multiple of 8, default 32.
|
||||
--dpi-desync-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-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
|
||||
@@ -229,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-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-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-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)
|
||||
@@ -284,6 +288,12 @@ 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.
|
||||
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).
|
||||
* **ts** adds to TSval ts increment value (-600000 by default). Servers discard packets with TSval in some range.
|
||||
Practical tests suggest increment between -100 and -0x80000000.
|
||||
Timestamps are generated by client OS. In linux timestamps are enabled by default. In windows by default timestamps are disabled.
|
||||
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.
|
||||
@@ -554,9 +564,9 @@ There is special support for all tcp split options for multi segment TLS. Split
|
||||
### UDP support
|
||||
|
||||
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.
|
||||
`fake`,`hopbyhop`,`destopt` can be used in combo with `ipfrag2`.
|
||||
`fake` can be used in combo with `udplen` and `tamper`.
|
||||
Only desync modes `fake`,`fakeknown`,`hopbyhop`,`destopt`,`ipfrag1`,`ipfrag2`,`udplen` and `tamper` are applicable.
|
||||
`fake`,`fakeknown`,`hopbyhop`,`destopt`,`ipfrag1` are 1st phase modes, others - 2nd phase.
|
||||
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.
|
||||
This option can resist DPIs that track outgoing UDP packet sizes.
|
||||
@@ -659,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.
|
||||
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
|
||||
|
||||
Most of nfqws packet magic does not work from VMs powered by virtualbox and vmware when network is NATed.
|
||||
@@ -1199,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.
|
||||
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
|
||||
|
||||
@@ -1379,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.
|
||||
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 :
|
||||
|
||||
If your system works as a router, then you need to enter the names of the internal and external interfaces:
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# zapret v71
|
||||
# zapret v71.3
|
||||
|
||||
# ВНИМАНИЕ, остерегайтесь мошенников
|
||||
|
||||
@@ -39,6 +39,7 @@ zapret является свободным и open source.
|
||||
- [ПОДДЕРЖКА UDP](#поддержка-udp)
|
||||
- [IP ФРАГМЕНТАЦИЯ](#ip-фрагментация)
|
||||
- [МНОЖЕСТВЕННЫЕ СТРАТЕГИИ](#множественные-стратегии)
|
||||
- [ФИЛЬТРАЦИЯ ПО WIFI](#фильтрация-по-wifi)
|
||||
- [IPTABLES ДЛЯ NFQWS](#iptables-для-nfqws)
|
||||
- [NFTABLES ДЛЯ NFQWS](#nftables-для-nfqws)
|
||||
- [FLOW OFFLOADING](#flow-offloading)
|
||||
@@ -184,17 +185,18 @@ dvtws, собираемый из тех же исходников (см. [док
|
||||
--synack-split=[syn|synack|acksyn] ; выполнить tcp split handshake. вместо SYN,ACK отсылать только SYN, SYN+ACK или ACK+SYN
|
||||
--orig-ttl=<int> ; модифицировать TTL оригинального пакета
|
||||
--orig-ttl6=<int> ; модифицировать ipv6 hop limit оригинальных пакетов. если не указано, используется значение --orig-ttl
|
||||
--orig-autottl=[<delta>[:<min>[-<max>]]] ; режим auto ttl для ipv4 и ipv6. по умолчанию: +5:3-64. delta=0 отключает функцию
|
||||
--orig-autottl6=[<delta>[:<min>[-<max>]]] ; переопределение предыдущего параметра для ipv6
|
||||
--orig-autottl=[<delta>[:<min>[-<max>]]|-] ; режим auto ttl для ipv4 и ipv6. по умолчанию: +5:3-64. "0:0-0" или "-" отключает функцию
|
||||
--orig-autottl6=[<delta>[:<min>[-<max>]]|-] ; переопределение предыдущего параметра для ipv6
|
||||
--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
|
||||
--dup=<int> ; высылать N дубликатов до оригинала
|
||||
--dup-replace=[0|1] ; 1 или отсутствие аргумента блокирует отправку оригинала. отправляются только дубликаты.
|
||||
--dup-ttl=<int> ; модифицировать TTL дубликатов
|
||||
--dup-ttl6=<int> ; модифицировать ipv6 hop limit дубликатов. если не указано, используется значение --dup-ttl
|
||||
--dup-autottl=[<delta>[:<min>[-<max>]]] ; режим auto ttl для ipv4 и ipv6. по умолчанию: +1:3-64. delta=0 отключает функцию
|
||||
--dup-autottl6=[<delta>[:<min>[-<max>]]] ; переопределение предыдущего параметра для ipv6
|
||||
--dup-fooling=<fooling> ; дополнительные методики как сделать, чтобы дубликат не дошел до сервера. none md5sig badseq badsum datanoack hopbyhop hopbyhop2
|
||||
--dup-autottl=[<delta>[:<min>[-<max>]]|-] ; режим auto ttl для ipv4 и ipv6. по умолчанию: +1:3-64. "0:0-0" или "-" отключает функцию
|
||||
--dup-autottl6=[<delta>[:<min>[-<max>]]|-] ; переопределение предыдущего параметра для ipv6
|
||||
--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-badack-increment=<int|0xHEX> ; инкремент ack sequence number для badseq. по умолчанию -66000
|
||||
--dup-start=[n|d|s]N ; применять dup только в исходящих пакетах (n), пакетах данных (d), относительных sequence (s) по номеру больше или равно N
|
||||
@@ -208,15 +210,16 @@ dvtws, собираемый из тех же исходников (см. [док
|
||||
--dpi-desync-fwmark=<int|0xHEX> ; бит fwmark для пометки десинхронизирующих пакетов, чтобы они повторно не падали в очередь. default = 0x40000000
|
||||
--dpi-desync-ttl=<int> ; установить 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-autottl6=[<delta>[:<min>[-<max>]]] ; переопределение предыдущего параметра для ipv6
|
||||
--dpi-desync-fooling=<fooling> ; дополнительные методики как сделать, чтобы фейковый пакет не дошел до сервера. none md5sig badseq badsum datanoack hopbyhop hopbyhop2
|
||||
--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-fooling=<fooling> ; дополнительные методики как сделать, чтобы фейковый пакет не дошел до сервера. none md5sig badseq badsum datanoack ts hopbyhop hopbyhop2
|
||||
--dpi-desync-repeats=<N> ; посылать каждый генерируемый в nfqws пакет N раз (не влияет на остальные пакеты)
|
||||
--dpi-desync-skip-nosni=0|1 ; 1(default)=не применять dpi desync для запросов без hostname в SNI, в частности для ESNI
|
||||
--dpi-desync-split-pos=N|-N|marker+N|marker-N ; список через запятую маркеров для tcp сегментации в режимах split и disorder
|
||||
--dpi-desync-split-seqovl=N|-N|marker+N|marker-N ; единичный маркер, определяющий величину перекрытия sequence в режимах split и disorder. для split поддерживается только положительное число.
|
||||
--dpi-desync-split-seqovl-pattern=<filename>|0xHEX ; чем заполнять фейковую часть overlap
|
||||
--dpi-desync-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-badack-increment=<int|0xHEX> ; инкремент ack sequence number для badseq. по умолчанию -66000
|
||||
--dpi-desync-any-protocol=0|1 ; 0(default)=работать только по http request и tls clienthello 1=по всем непустым пакетам данных
|
||||
@@ -226,6 +229,7 @@ dvtws, собираемый из тех же исходников (см. [док
|
||||
--dpi-desync-fake-unknown=<filename>|0xHEX ; файл, содержащий фейковый пейлоад неизвестного протокола для dpi-desync=fake, на замену стандартным нулям 256 байт
|
||||
--dpi-desync-fake-syndata=<filename>|0xHEX ; файл, содержащий фейковый пейлоад пакета SYN для режима десинхронизации syndata
|
||||
--dpi-desync-fake-quic=<filename>|0xHEX ; файл, содержащий фейковый QUIC Initial
|
||||
--dpi-desync-fake-wireguard=<filename>|0xHEX ; файл, содержащий фейковый wireguard handshake initiation
|
||||
--dpi-desync-fake-dht=<filename>|0xHEX ; файл, содержащий фейковый пейлоад DHT протокола для dpi-desync=fake, на замену стандартным нулям 64 байт
|
||||
--dpi-desync-fake-discord=<filename>|0xHEX ; файл, содержащий фейковый пейлоад Discord протокола нахождения IP адреса для голосовых чатов для dpi-desync=fake, на замену стандартным нулям 64 байт
|
||||
--dpi-desync-fake-stun=<filename>|0xHEX ; файл, содержащий фейковый пейлоад STUN протокола для dpi-desync=fake, на замену стандартным нулям 64 байт
|
||||
@@ -255,6 +259,7 @@ dvtws, собираемый из тех же исходников (см. [док
|
||||
--filter-tcp=[~]port1[-port2]|* ; фильтр портов tcp для текущей стратегии. ~ означает инверсию. установка фильтра tcp и неустановка фильтра udp запрещает udp. поддерживается список через запятую.
|
||||
--filter-udp=[~]port1[-port2]|* ; фильтр портов udp для текущей стратегии. ~ означает инверсию. установка фильтра udp и неустановка фильтра tcp запрещает tcp. поддерживается список через запятую.
|
||||
--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-ip=<ip_list> ; фиксированный список подсетей через запятую. можно использовать # в начале для комментирования отдельных подсетей.
|
||||
--ipset-exclude=<filename> ; исключающий ip list. на каждой строчке ip или cidr ipv4 или ipv6. поддерживается множество листов и gzip. перечитка автоматическая.
|
||||
@@ -336,6 +341,12 @@ dvtws, собираемый из тех же исходников (см. [док
|
||||
выяснено, что многие провайдерские NAT не отбрасывают эти пакеты, потому работает даже с внутренним провайдерским IP.
|
||||
Но 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 и немного не дошел до
|
||||
сервера (`--dpi-desync-autottl`). Или наоборот - TTL едва хватило, чтобы он все-таки дошел до сервера (см `--dup-autottl`, `--orig-autottl`).
|
||||
Берутся базовые значения TTL 64,128,255, смотрится входящий пакет (да, требуется направить первый входящий пакет на nfqws !).
|
||||
@@ -659,8 +670,11 @@ chrome рандомизирует фингерпринт TLS. SNI может о
|
||||
### ПОДДЕРЖКА UDP
|
||||
|
||||
Атаки на 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` количество байтов.
|
||||
Паддинг заполняется нулями по умолчанию, но можно задать свой паттерн.
|
||||
Предназначено для обмана DPI, ориентирующегося на размеры пакетов.
|
||||
@@ -771,6 +785,36 @@ L7 протокол становится известен обычно посл
|
||||
> Вариант в ядре работает гораздо эффективнее. Это создавалось для систем без подд3ержки 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 для задействования атаки на первые пакеты данных в tcp соединении :
|
||||
@@ -1458,7 +1502,7 @@ LISTS_RELOAD=- отключает перезагрузку листов.
|
||||
`ipset/zapret-hosts-users.txt.gz` или `ipset/zapret-hosts-users.txt`,
|
||||
`ipset/zapret-hosts.txt.gz` или `ipset/zapret-hosts.txt`
|
||||
и 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** все листы, файлы которых присутствуют.
|
||||
Передача происходит через замену маркеров `<HOSTLIST>` и `<HOSTLIST_NOAUTO>` на реальные параметры `--hostlist`, `--hostlist-exclude`, `--hostlist-auto`.
|
||||
@@ -1797,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_ENABLE=0`
|
||||
|
||||
@@ -2286,7 +2345,7 @@ chcon u:object_r:system_file:s0 /data/local/tmp/zapret/tpws
|
||||
Если компа нет, то развертка chroot - единственный вариант, хотя и неудобный.
|
||||
Подойдет что-то легковесное, например, alpine или даже OpenWrt.
|
||||
Если это не эмулятор android, то универсальная архитектура - arm (любой вариант).
|
||||
Если вы точно знаете, что ОС у вас 64-разрядная, то лучше вместо arm - aarch64.
|
||||
Если вы точно знаете, что ОС у вас 64-разрядная, то лучше вместо arm - arm64.
|
||||
Выяснить архитектуру можно командой `uname -a`.
|
||||
|
||||
```
|
||||
|
@@ -24,17 +24,15 @@ Tor поддерживает "из коробки" режим transparent proxy.
|
||||
Устанавливать их нужно с опцией opkg --force-overwrite, поскольку они перепишут ssh клиент от dropbear.
|
||||
После установки пакетов расслабим неоправданно жестокие права : chmod 755 /etc/ssh.
|
||||
Следует создать пользователя, под которым будем крутить 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
|
||||
chown proxy:proxy /home/proxy
|
||||
------------------
|
||||
Openssh ловит разные глюки, если у него нет доступа к /dev/tty.
|
||||
Добавим в /etc/rc.local строчку : "chmod 666 /dev/tty"
|
||||
Сгенерируем для него ключ RSA для доступа к ssh серверу.
|
||||
Сгенерируем ключ RSA для доступа к ssh серверу.
|
||||
------------------
|
||||
su proxy
|
||||
su -s /bin/ash proxy
|
||||
cd
|
||||
mkdir -m 700 .ssh
|
||||
cd .ssh
|
||||
|
@@ -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.
|
||||
|
||||
`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`.
|
||||
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`.
|
||||
|
||||
### 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
|
||||
|
||||
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.
|
||||
|
||||
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`.
|
||||
|
@@ -84,7 +84,7 @@ SubInterface используется windivert, но практически в
|
||||
autottl и autohostlist. При включении autohostlist так же перенаправляются пакеты данных с http redirect с кодами 302 и 307.
|
||||
Всегда добавляется фильтр на исключение не-интернет адресов ipv4 и ipv6.
|
||||
Для сложных нестандартных сценариев могут потребоваться свои фильтры. Логично будет начать со стандартного шаблона,
|
||||
сохраненного через `--wf-save`. Нужно править файл и подсовывать его в параметре `--wf-raw`. Максимальный размер фильтра - **8 Kb**.
|
||||
сохраненного через `--wf-save`. Нужно править файл и подсовывать его в параметре `--wf-raw`. Максимальный размер фильтра - **16 Kb**.
|
||||
|
||||
Можно запускать несколько процессов **winws** с разными стратегиями. Однако, не следует делать пересекающиеся фильтры.
|
||||
|
||||
@@ -125,7 +125,7 @@ network locations в win10/11. Кое-что есть в **powershell**.
|
||||
|
||||
Существует неочевидный момент, каcаемый запуска **winws** из cygwin shell\`а. Если в директории, где находится winws, находится
|
||||
копия `cygwin1.dll`, **winws** не запустится.
|
||||
Если нужен запуск под cygwin, то следует удалить или переместить `cygwin1.dll` из `binaries/win64`. Это нужно для работы blockcheck.
|
||||
Если нужен запуск под cygwin, то следует удалить или переместить `cygwin1.dll` из `binaries/windows-x86_64`. Это нужно для работы blockcheck.
|
||||
Из cygwin шелла можно посылать winws сигналы через `kill` точно так же, как в `*nix`.
|
||||
|
||||
Как получить совместимый с windows 7 и winws cygwin :
|
||||
@@ -203,22 +203,6 @@ _cygwin_ для обычной работы **winws** не нужен.
|
||||
Однако, хотя такой способ и работает, использование **winws** сильно облегчает [zapret-win-bundle](https://github.com/bol-van/zapret-win-bundle).
|
||||
Там нет проблемы с `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
|
||||
|
||||
Можно не возиться с _cygwin_, а взять готовый пакет, включающий в себя _cygwin_ и _blockcheck_ : https://github.com/bol-van/zapret-win-bundle
|
||||
@@ -257,3 +241,19 @@ _zapret-winws_ - это отдельный комплект для повсед
|
||||
|
||||
> [!CAUTION]
|
||||
> Поскольку 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`
|
||||
|
@@ -56,9 +56,6 @@ RemoveIPC=true
|
||||
RestrictNamespaces=true
|
||||
RestrictRealtime=true
|
||||
RestrictSUIDSGID=true
|
||||
SystemCallArchitectures=native
|
||||
SystemCallFilter=@system-service
|
||||
SystemCallFilter=~@resources
|
||||
UMask=0077
|
||||
|
||||
[Install]
|
||||
|
@@ -55,8 +55,6 @@ RemoveIPC=true
|
||||
RestrictNamespaces=true
|
||||
RestrictRealtime=true
|
||||
RestrictSUIDSGID=true
|
||||
SystemCallArchitectures=native
|
||||
SystemCallFilter=@system-service
|
||||
UMask=0077
|
||||
|
||||
[Install]
|
||||
|
153
install_bin.sh
153
install_bin.sh
@@ -8,6 +8,68 @@ BINDIR="$EXEDIR/$BINS"
|
||||
ZAPRET_BASE=${ZAPRET_BASE:-"$EXEDIR"}
|
||||
. "$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()
|
||||
{
|
||||
local dir="$BINDIR/$1"
|
||||
@@ -15,23 +77,36 @@ check_dir()
|
||||
local out
|
||||
if [ -f "$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
|
||||
# bash and zsh do not do this
|
||||
if exists bash; then
|
||||
out=$(echo 0.0.0.0 | bash -c "\"$exe"\" 2>/dev/null)
|
||||
elif exists zsh; then
|
||||
out=$(echo 0.0.0.0 | zsh -c "\"$exe\"" 2>/dev/null)
|
||||
else
|
||||
# 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
|
||||
local FIND=find
|
||||
if ! exists find && exists busybox; then
|
||||
FIND="busybox find"
|
||||
fi
|
||||
out=$(echo 0.0.0.0 | $FIND "$dir" -maxdepth 1 -name ip2net -exec {} \; 2>/dev/null)
|
||||
fi
|
||||
[ -n "$out" ]
|
||||
disable_antivirus "$dir"
|
||||
case $TEST in
|
||||
bash)
|
||||
out=$(echo 0.0.0.0 | bash -c "\"$exe"\" 2>/dev/null)
|
||||
[ -n "$out" ]
|
||||
;;
|
||||
zsh)
|
||||
out=$(echo 0.0.0.0 | zsh -c "\"$exe\"" 2>/dev/null)
|
||||
[ -n "$out" ]
|
||||
;;
|
||||
elf)
|
||||
out=$(read_elf_arch "$exe")
|
||||
[ "$ELF_ARCH" = "$out" ] && {
|
||||
# exec test to verify it actually works. no illegal instruction or crash.
|
||||
out=$(echo 0.0.0.0 | "$exe" 2>/dev/null)
|
||||
[ -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
|
||||
echo >&2 "$exe is not executable. set proper chmod."
|
||||
return 1
|
||||
@@ -52,29 +127,65 @@ ccp()
|
||||
#cp -f "../$BINS/$1" "$ZAPRET_BASE/$2" && echo copying : "../$BINS/$1" =\> "$ZAPRET_BASE/$2"
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
case $UNAME in
|
||||
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
|
||||
;;
|
||||
Darwin)
|
||||
ARCHLIST="my mac64"
|
||||
;;
|
||||
FreeBSD)
|
||||
ARCHLIST="my freebsd-x64"
|
||||
ARCHLIST="my freebsd-x86_64"
|
||||
PKTWS=dvtws
|
||||
;;
|
||||
CYGWIN*)
|
||||
UNAME=CYGWIN
|
||||
ARCHLIST="win64 win32"
|
||||
ARCHLIST="windows-x86_64 windows-x86"
|
||||
PKTWS=winws
|
||||
;;
|
||||
*)
|
||||
ARCHLIST="my"
|
||||
esac
|
||||
|
||||
select_test_method
|
||||
|
||||
if [ "$1" = "getarch" ]; then
|
||||
for arch in $ARCHLIST
|
||||
do
|
||||
@@ -85,6 +196,8 @@ if [ "$1" = "getarch" ]; then
|
||||
fi
|
||||
done
|
||||
else
|
||||
echo "using arch detect method : $TEST${ELF_ARCH:+ $ELF_ARCH}"
|
||||
|
||||
for arch in $ARCHLIST
|
||||
do
|
||||
[ -d "$BINDIR/$arch" ] || continue
|
||||
|
@@ -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()
|
||||
{
|
||||
echo \* checking executables
|
||||
@@ -57,6 +80,7 @@ check_bins()
|
||||
fix_perms_bin_test "$EXEDIR"
|
||||
local arch="$(get_bin_arch)"
|
||||
local make_target
|
||||
local cf="-march=native"
|
||||
[ "$FORCE_BUILD" = "1" ] && {
|
||||
echo forced build mode
|
||||
if [ "$arch" = "my" ]; then
|
||||
@@ -72,12 +96,13 @@ check_bins()
|
||||
case $SYSTEM in
|
||||
macos)
|
||||
make_target=mac
|
||||
cf=
|
||||
;;
|
||||
systemd)
|
||||
make_target=systemd
|
||||
;;
|
||||
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
|
||||
make -C "$EXEDIR" clean
|
||||
exitp 8
|
||||
@@ -230,9 +255,9 @@ select_mode_filter()
|
||||
|
||||
select_mode()
|
||||
{
|
||||
select_mode_filter
|
||||
select_mode_mode
|
||||
select_mode_iface
|
||||
select_mode_filter
|
||||
}
|
||||
|
||||
select_getlist()
|
||||
@@ -883,8 +908,7 @@ umask 0022
|
||||
fix_sbin_path
|
||||
fsleep_setup
|
||||
check_system
|
||||
|
||||
[ "$SYSTEM" = "macos" ] && . "$EXEDIR/init.d/macos/functions"
|
||||
check_source
|
||||
|
||||
case $SYSTEM in
|
||||
systemd)
|
||||
|
@@ -1,5 +1,6 @@
|
||||
CC ?= gcc
|
||||
CFLAGS += -std=gnu99 -Os -flto=auto
|
||||
CC ?= cc
|
||||
OPTIMIZE ?= -Os
|
||||
CFLAGS += -std=gnu99 $(OPTIMIZE) -flto=auto
|
||||
CFLAGS_BSD = -Wno-address-of-packed-member
|
||||
CFLAGS_WIN = -static
|
||||
LIBS =
|
||||
|
@@ -1,5 +1,6 @@
|
||||
CC ?= gcc
|
||||
CFLAGS += -std=gnu99 -Os
|
||||
CC ?= cc
|
||||
OPTIMIZE ?= -Os
|
||||
CFLAGS += -std=gnu99 $(OPTIMIZE)
|
||||
CFLAGS_BSD = -Wno-address-of-packed-member
|
||||
CFLAGS_WIN = -static
|
||||
LIBS = -lpthread
|
||||
|
@@ -1,5 +1,6 @@
|
||||
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
|
||||
SRC_FILES = *.c crypto/*.c
|
||||
|
||||
|
11
nfq/Makefile
11
nfq/Makefile
@@ -1,9 +1,11 @@
|
||||
CC ?= gcc
|
||||
CFLAGS += -std=gnu99 -Os -flto=auto
|
||||
CC ?= cc
|
||||
OPTIMIZE ?= -Os
|
||||
CFLAGS += -std=gnu99 $(OPTIMIZE) -flto=auto
|
||||
CFLAGS_SYSTEMD = -DUSE_SYSTEMD
|
||||
CFLAGS_BSD = -Wno-address-of-packed-member
|
||||
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_BSD = -lz
|
||||
LIBS_CYGWIN = -lz -Lwindows/windivert -Iwindows -lwlanapi -lole32 -loleaut32
|
||||
@@ -21,7 +23,8 @@ nfqws: $(SRC_FILES)
|
||||
systemd: $(SRC_FILES)
|
||||
$(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)
|
||||
$(CC) -s $(CFLAGS) $(CFLAGS_BSD) -o dvtws $(SRC_FILES) $(LIBS_BSD) $(LDFLAGS)
|
||||
|
@@ -29,6 +29,7 @@ void ConntrackClearHostname(t_ctrack *track)
|
||||
{
|
||||
free(track->hostname);
|
||||
track->hostname = NULL;
|
||||
track->hostname_is_ip = false;
|
||||
}
|
||||
static void ConntrackClearTrack(t_ctrack *track)
|
||||
{
|
||||
|
@@ -86,6 +86,7 @@ typedef struct
|
||||
t_l7proto l7proto;
|
||||
bool l7proto_discovered;
|
||||
char *hostname;
|
||||
bool hostname_is_ip;
|
||||
bool hostname_discovered;
|
||||
bool hostname_ah_check; // should perform autohostlist checks
|
||||
|
||||
|
283
nfq/darkmagic.c
283
nfq/darkmagic.c
@@ -29,6 +29,16 @@
|
||||
|
||||
#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)
|
||||
{
|
||||
return htonl(ntohl(netorder_value)+cpuorder_increment);
|
||||
@@ -108,6 +118,7 @@ static void fill_tcphdr(
|
||||
uint16_t nsport, uint16_t ndport,
|
||||
uint16_t nwsize, uint8_t scale_factor,
|
||||
uint32_t *timestamps,
|
||||
uint32_t ts_increment,
|
||||
uint32_t badseq_increment,
|
||||
uint32_t badseq_ack_increment,
|
||||
uint16_t data_len)
|
||||
@@ -155,13 +166,13 @@ static void fill_tcphdr(
|
||||
*(uint32_t*)(tcpopt+t+14)=random();
|
||||
t+=18;
|
||||
}
|
||||
if (timestamps || (fooling & FOOL_TS))
|
||||
if (timestamps)
|
||||
{
|
||||
tcpopt[t] = 8; // kind
|
||||
tcpopt[t+1] = 10; // len
|
||||
// forge only TSecr if orig timestamp is present
|
||||
*(uint32_t*)(tcpopt+t+2) = timestamps ? timestamps[0] : -1;
|
||||
*(uint32_t*)(tcpopt+t+6) = (timestamps && !(fooling & FOOL_TS)) ? timestamps[1] : -1;
|
||||
memcpy(tcpopt+t+2,timestamps,8);
|
||||
// forge TSval, keep TSecr
|
||||
if (fooling & FOOL_TS) *(uint32_t*)(tcpopt+t+2) = net32_add(*(uint32_t*)(tcpopt+t+2),ts_increment);
|
||||
t+=10;
|
||||
}
|
||||
if (scale_factor!=SCALE_NONE)
|
||||
@@ -232,6 +243,7 @@ bool prepare_tcp_segment4(
|
||||
uint8_t tos,
|
||||
uint16_t ip_id,
|
||||
uint32_t fooling,
|
||||
uint32_t ts_increment,
|
||||
uint32_t badseq_increment,
|
||||
uint32_t badseq_ack_increment,
|
||||
const void *data, uint16_t len,
|
||||
@@ -247,7 +259,7 @@ bool prepare_tcp_segment4(
|
||||
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_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);
|
||||
tcp4_fix_checksum(tcp,ip_payload_len,&ip->ip_src,&ip->ip_dst);
|
||||
@@ -269,6 +281,7 @@ bool prepare_tcp_segment6(
|
||||
uint8_t ttl,
|
||||
uint32_t flow_label,
|
||||
uint32_t fooling,
|
||||
uint32_t ts_increment,
|
||||
uint32_t badseq_increment,
|
||||
uint32_t badseq_ack_increment,
|
||||
const void *data, uint16_t len,
|
||||
@@ -333,7 +346,7 @@ bool prepare_tcp_segment6(
|
||||
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_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);
|
||||
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,
|
||||
uint32_t flow_label,
|
||||
uint32_t fooling,
|
||||
uint32_t ts_increment,
|
||||
uint32_t badseq_increment,
|
||||
uint32_t badseq_ack_increment,
|
||||
const void *data, uint16_t len,
|
||||
uint8_t *buf, size_t *buflen)
|
||||
{
|
||||
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) ?
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
// 18.65.168.125 ( cloudfront ) 255
|
||||
|
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "nfqws.h"
|
||||
#include "checksum.h"
|
||||
#include "packet_queue.h"
|
||||
#include "pools.h"
|
||||
@@ -80,6 +81,7 @@ bool prepare_tcp_segment4(
|
||||
uint8_t tos,
|
||||
uint16_t ip_id,
|
||||
uint32_t fooling,
|
||||
uint32_t ts_increment,
|
||||
uint32_t badseq_increment,
|
||||
uint32_t badseq_ack_increment,
|
||||
const void *data, uint16_t len,
|
||||
@@ -96,6 +98,7 @@ bool prepare_tcp_segment6(
|
||||
uint8_t ttl,
|
||||
uint32_t flow_label,
|
||||
uint32_t fooling,
|
||||
uint32_t ts_increment,
|
||||
uint32_t badseq_increment,
|
||||
uint32_t badseq_ack_increment,
|
||||
const void *data, uint16_t len,
|
||||
@@ -115,6 +118,7 @@ bool prepare_tcp_segment(
|
||||
uint16_t ip_id,
|
||||
uint32_t flow_label,
|
||||
uint32_t fooling,
|
||||
uint32_t ts_increment,
|
||||
uint32_t badseq_increment,
|
||||
uint32_t badseq_ack_increment,
|
||||
const void *data, uint16_t len,
|
||||
@@ -272,3 +276,29 @@ void verdict_udp_csum_fix(uint8_t verdict, struct udphdr *udphdr, size_t transpo
|
||||
|
||||
void dbgprint_socket_buffers(int fd);
|
||||
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
|
||||
|
148
nfq/desync.c
148
nfq/desync.c
@@ -223,7 +223,7 @@ enum dpi_desync_mode desync_mode_from_string(const char *s)
|
||||
|
||||
static bool dp_match(
|
||||
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 bHostlistsEmpty;
|
||||
@@ -241,6 +241,11 @@ static bool dp_match(
|
||||
if (dp->filter_l7 && !l7_proto_match(l7proto, dp->filter_l7))
|
||||
// L7 filter does not match
|
||||
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);
|
||||
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.
|
||||
@@ -262,7 +267,7 @@ static bool dp_match(
|
||||
{
|
||||
if (bCheckDone) *bCheckDone = true;
|
||||
bool b;
|
||||
b = HostlistCheck(dp, hostname, bExcluded, true);
|
||||
b = HostlistCheck(dp, hostname, bNoSubdom, bExcluded, true);
|
||||
if (bCheckResult) *bCheckResult = b;
|
||||
return b;
|
||||
}
|
||||
@@ -271,7 +276,7 @@ static bool dp_match(
|
||||
}
|
||||
static struct desync_profile *dp_find(
|
||||
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)
|
||||
{
|
||||
struct desync_profile_list *dpl;
|
||||
@@ -279,12 +284,12 @@ static struct desync_profile *dp_find(
|
||||
{
|
||||
char ip_port[48];
|
||||
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;
|
||||
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);
|
||||
return &dpl->dp;
|
||||
@@ -413,7 +418,7 @@ static bool auto_hostlist_retrans(t_ctrack *ctrack, uint8_t l4proto, int thresho
|
||||
}
|
||||
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;
|
||||
|
||||
@@ -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);
|
||||
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);
|
||||
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))
|
||||
{
|
||||
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;
|
||||
|
||||
@@ -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");
|
||||
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;
|
||||
}
|
||||
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)
|
||||
{
|
||||
@@ -815,8 +821,9 @@ static bool ipcache_get_hostname(const struct in_addr *a4, const struct in6_addr
|
||||
}
|
||||
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);
|
||||
if (hostname_is_ip) *hostname_is_ip = ipc->hostname_is_ip;
|
||||
}
|
||||
else
|
||||
*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,
|
||||
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),
|
||||
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))
|
||||
{
|
||||
DLOG_ERR("dup: packet reconstruct failed\n");
|
||||
@@ -1107,6 +1114,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
||||
bool bSack,DF;
|
||||
uint16_t nmss;
|
||||
char host[256];
|
||||
const char *ifname = NULL, *ssid = NULL;
|
||||
|
||||
uint32_t desync_fwmark = fwmark | params.desync_fwmark;
|
||||
extract_endpoints(dis->ip, dis->ip6, dis->tcp, NULL, &src, &dst);
|
||||
@@ -1122,6 +1130,11 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
||||
if (!ConntrackPoolDoubleSearch(¶ms.conntrack, dis->ip, dis->ip6, dis->tcp, NULL, &ctrack_replay, &bReverse) || bReverse)
|
||||
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;
|
||||
if (dp)
|
||||
DLOG("using cached desync profile %d\n",dp->n);
|
||||
@@ -1129,11 +1142,11 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
||||
{
|
||||
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)))
|
||||
DLOG_ERR("strdup(host): out of memory\n");
|
||||
}
|
||||
dp = ctrack_replay->dp = dp_find(¶ms.desync_profiles, IPPROTO_TCP, (struct sockaddr *)&dst, ctrack_replay->hostname, ctrack_replay->l7proto, NULL, NULL, NULL);
|
||||
dp = ctrack_replay->dp = dp_find(¶ms.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;
|
||||
}
|
||||
if (!dp)
|
||||
@@ -1155,22 +1168,29 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
||||
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)
|
||||
DLOG("using cached desync profile %d\n",dp->n);
|
||||
else if (!ctrack || !ctrack->dp_search_complete)
|
||||
{
|
||||
const char *hostname = NULL;
|
||||
bool hostname_is_ip = false;
|
||||
if (ctrack)
|
||||
{
|
||||
hostname = ctrack->hostname;
|
||||
hostname_is_ip = ctrack->hostname_is_ip;
|
||||
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)))
|
||||
DLOG_ERR("strdup(host): out of memory\n");
|
||||
}
|
||||
}
|
||||
dp = dp_find(¶ms.desync_profiles, IPPROTO_TCP, (struct sockaddr *)&dst, hostname, ctrack ? ctrack->l7proto : UNKNOWN, NULL, NULL, NULL);
|
||||
dp = dp_find(¶ms.desync_profiles, IPPROTO_TCP, (struct sockaddr *)&dst, hostname, hostname_is_ip, ctrack ? ctrack->l7proto : UNKNOWN, ssid, NULL, NULL, NULL);
|
||||
if (ctrack)
|
||||
{
|
||||
ctrack->dp = dp;
|
||||
@@ -1252,7 +1272,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
||||
}
|
||||
}
|
||||
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
|
||||
if (dis->len_payload)
|
||||
auto_hostlist_reset_fail_counter(dp, ctrack->hostname, client_ip_port, ctrack->l7proto);
|
||||
@@ -1310,7 +1330,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
||||
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,NULL, 0, pkt1, &pkt1_len))
|
||||
FOOL_NONE,0,0,0,NULL, 0, pkt1, &pkt1_len))
|
||||
{
|
||||
DLOG_ERR("cannot prepare split SYNACK ACK part\n");
|
||||
goto send_orig;
|
||||
@@ -1355,7 +1375,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
||||
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,
|
||||
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))
|
||||
{
|
||||
goto send_orig;
|
||||
@@ -1379,7 +1399,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
||||
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,
|
||||
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;
|
||||
}
|
||||
@@ -1410,7 +1430,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
||||
int multisplit_count;
|
||||
int i;
|
||||
uint16_t ip_id;
|
||||
bool bHaveHost=false;
|
||||
bool bHaveHost=false, bHostIsIp=false;
|
||||
t_l7proto l7proto = UNKNOWN;
|
||||
|
||||
if (replay)
|
||||
@@ -1531,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 (bHaveHost) DLOG("hostname: %s\n",host);
|
||||
if (bHaveHost)
|
||||
{
|
||||
bHostIsIp=strip_host_to_ip(host);
|
||||
DLOG("hostname: %s\n",host);
|
||||
}
|
||||
|
||||
bool bDiscoveredL7;
|
||||
if (ctrack_replay)
|
||||
@@ -1551,6 +1575,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
||||
{
|
||||
free(ctrack_replay->hostname);
|
||||
ctrack_replay->hostname=strdup(host);
|
||||
ctrack_replay->hostname_is_ip=bHostIsIp;
|
||||
if (!ctrack_replay->hostname)
|
||||
{
|
||||
DLOG_ERR("hostname dup : out of memory");
|
||||
@@ -1558,7 +1583,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
||||
goto send_orig;
|
||||
}
|
||||
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);
|
||||
goto send_orig;
|
||||
@@ -1574,7 +1599,8 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
||||
|
||||
dp = dp_find(¶ms.desync_profiles, IPPROTO_TCP, (struct sockaddr *)&dst,
|
||||
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);
|
||||
if (ctrack_replay)
|
||||
{
|
||||
@@ -1622,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 (!bCheckDone)
|
||||
bCheckResult = HostlistCheck(dp, host, &bCheckExcluded, false);
|
||||
bCheckResult = HostlistCheck(dp, host, bHostIsIp, &bCheckExcluded, false);
|
||||
if (bCheckResult)
|
||||
ctrack_stop_retrans_counter(ctrack_replay);
|
||||
else
|
||||
@@ -1846,7 +1872,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
||||
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,
|
||||
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))
|
||||
{
|
||||
reasm_orig_cancel(ctrack);
|
||||
@@ -1870,7 +1896,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
||||
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,
|
||||
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))
|
||||
{
|
||||
reasm_orig_cancel(ctrack);
|
||||
@@ -1898,7 +1924,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
||||
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,
|
||||
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))
|
||||
{
|
||||
goto send_orig;
|
||||
@@ -1967,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,
|
||||
dis->tcp->th_win, scale_factor, timestamps,
|
||||
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))
|
||||
goto send_orig;
|
||||
ip_id=IP4_IP_ID_NEXT(ip_id);
|
||||
@@ -2037,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,
|
||||
dis->tcp->th_win, scale_factor, timestamps,
|
||||
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))
|
||||
goto send_orig;
|
||||
ip_id=IP4_IP_ID_PREV(ip_id);
|
||||
@@ -2096,7 +2122,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
||||
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,
|
||||
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))
|
||||
goto send_orig;
|
||||
ip_id=IP4_IP_ID_PREV(ip_id);
|
||||
@@ -2108,7 +2134,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
||||
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,
|
||||
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))
|
||||
goto send_orig;
|
||||
ip_id=IP4_IP_ID_PREV(ip_id);
|
||||
@@ -2128,7 +2154,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
||||
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,
|
||||
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))
|
||||
goto send_orig;
|
||||
ip_id=IP4_IP_ID_PREV(ip_id);
|
||||
@@ -2140,7 +2166,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
||||
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,
|
||||
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))
|
||||
goto send_orig;
|
||||
ip_id=IP4_IP_ID_PREV(ip_id);
|
||||
@@ -2176,7 +2202,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
||||
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,
|
||||
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))
|
||||
goto send_orig;
|
||||
ip_id=IP4_IP_ID_NEXT(ip_id);
|
||||
@@ -2212,7 +2238,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
||||
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,
|
||||
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))
|
||||
goto send_orig;
|
||||
ip_id=IP4_IP_ID_NEXT(ip_id);
|
||||
@@ -2243,7 +2269,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
||||
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,
|
||||
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))
|
||||
goto send_orig;
|
||||
ip_id=IP4_IP_ID_NEXT(ip_id);
|
||||
@@ -2255,7 +2281,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
||||
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,
|
||||
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))
|
||||
goto send_orig;
|
||||
ip_id=IP4_IP_ID_NEXT(ip_id);
|
||||
@@ -2368,6 +2394,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
|
||||
bool DF;
|
||||
char host[256];
|
||||
t_l7proto l7proto = UNKNOWN;
|
||||
const char *ifname = NULL, *ssid = NULL;
|
||||
|
||||
extract_endpoints(dis->ip, dis->ip6, NULL, dis->udp, &src, &dst);
|
||||
|
||||
@@ -2379,6 +2406,12 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
|
||||
if (!ConntrackPoolDoubleSearch(¶ms.conntrack, dis->ip, dis->ip6, NULL, dis->udp, &ctrack_replay, &bReverse) || bReverse)
|
||||
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;
|
||||
if (dp)
|
||||
DLOG("using cached desync profile %d\n",dp->n);
|
||||
@@ -2386,11 +2419,11 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
|
||||
{
|
||||
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)))
|
||||
DLOG_ERR("strdup(host): out of memory\n");
|
||||
}
|
||||
dp = ctrack_replay->dp = dp_find(¶ms.desync_profiles, IPPROTO_UDP, (struct sockaddr *)&dst, ctrack_replay->hostname, ctrack_replay->l7proto, NULL, NULL, NULL);
|
||||
dp = ctrack_replay->dp = dp_find(¶ms.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;
|
||||
}
|
||||
if (!dp)
|
||||
@@ -2398,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");
|
||||
return verdict;
|
||||
}
|
||||
|
||||
// no need to desync middle packets in reasm session
|
||||
if (reasm_offset) goto send_orig;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2415,22 +2445,29 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
|
||||
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)
|
||||
DLOG("using cached desync profile %d\n",dp->n);
|
||||
else if (!ctrack || !ctrack->dp_search_complete)
|
||||
{
|
||||
const char *hostname = NULL;
|
||||
bool hostname_is_ip = false;
|
||||
if (ctrack)
|
||||
{
|
||||
hostname = ctrack->hostname;
|
||||
hostname_is_ip = ctrack->hostname_is_ip;
|
||||
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)))
|
||||
DLOG_ERR("strdup(host): out of memory\n");
|
||||
}
|
||||
}
|
||||
dp = dp_find(¶ms.desync_profiles, IPPROTO_UDP, (struct sockaddr *)&dst, hostname, ctrack ? ctrack->l7proto : UNKNOWN, NULL, NULL, NULL);
|
||||
dp = dp_find(¶ms.desync_profiles, IPPROTO_UDP, (struct sockaddr *)&dst, hostname, hostname_is_ip, ctrack ? ctrack->l7proto : UNKNOWN, ssid, NULL, NULL, NULL);
|
||||
if (ctrack)
|
||||
{
|
||||
ctrack->dp = dp;
|
||||
@@ -2478,7 +2515,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
|
||||
if (dis->len_payload)
|
||||
{
|
||||
struct blob_collection_head *fake;
|
||||
bool bHaveHost=false;
|
||||
bool bHaveHost=false, bHostIsIp=false;
|
||||
uint16_t ip_id;
|
||||
|
||||
if (IsQUICInitial(dis->data_payload,dis->len_payload))
|
||||
@@ -2665,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;
|
||||
if (ctrack_replay)
|
||||
@@ -2686,12 +2727,13 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
|
||||
ctrack_replay->hostname_discovered=true;
|
||||
free(ctrack_replay->hostname);
|
||||
ctrack_replay->hostname=strdup(host);
|
||||
ctrack_replay->hostname_is_ip = bHostIsIp;
|
||||
if (!ctrack_replay->hostname)
|
||||
{
|
||||
DLOG_ERR("hostname dup : out of memory");
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -2703,7 +2745,8 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
|
||||
|
||||
dp = dp_find(¶ms.desync_profiles, IPPROTO_UDP, (struct sockaddr *)&dst,
|
||||
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);
|
||||
if (ctrack_replay)
|
||||
{
|
||||
@@ -2747,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 (!bCheckDone)
|
||||
bCheckResult = HostlistCheck(dp, host, &bCheckExcluded, false);
|
||||
bCheckResult = HostlistCheck(dp, host, bHostIsIp, &bCheckExcluded, false);
|
||||
if (bCheckResult)
|
||||
ctrack_stop_retrans_counter(ctrack_replay);
|
||||
else
|
||||
@@ -2811,6 +2854,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
|
||||
break;
|
||||
}
|
||||
case DESYNC_FAKE:
|
||||
if (!reasm_offset)
|
||||
{
|
||||
struct blob_item *fake_item;
|
||||
int n=0;
|
||||
@@ -2834,8 +2878,8 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
|
||||
goto send_orig;
|
||||
ip_id=IP4_IP_ID_NEXT(ip_id);
|
||||
}
|
||||
bFake = true;
|
||||
}
|
||||
bFake = true;
|
||||
break;
|
||||
case DESYNC_HOPBYHOP:
|
||||
case DESYNC_DESTOPT:
|
||||
|
@@ -113,6 +113,71 @@ bool append_to_list_file(const char *filename, const char *s)
|
||||
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)
|
||||
{
|
||||
|
@@ -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 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 ntop46(const struct sockaddr *sa, char *str, size_t len);
|
||||
void ntop46_port(const struct sockaddr *sa, char *str, size_t len);
|
||||
|
@@ -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)
|
||||
{
|
||||
@@ -195,6 +195,7 @@ static bool SearchHostList(hostlist_pool *hostlist, const char *host)
|
||||
}
|
||||
else
|
||||
DLOG("negative\n");
|
||||
if (no_match_subdomains) break;
|
||||
p = strchr(p, '.');
|
||||
if (p) p++;
|
||||
bHostFull = false;
|
||||
@@ -220,7 +221,7 @@ bool HostlistsReloadCheckForProfile(const struct desync_profile *dp)
|
||||
return HostlistsReloadCheck(&dp->hl_collection) && HostlistsReloadCheck(&dp->hl_collection_exclude);
|
||||
}
|
||||
// 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;
|
||||
|
||||
@@ -233,7 +234,7 @@ static bool HostlistCheck_(const struct hostlist_collection_head *hostlists, con
|
||||
LIST_FOREACH(item, hostlists_exclude, next)
|
||||
{
|
||||
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;
|
||||
return false;
|
||||
@@ -245,7 +246,7 @@ static bool HostlistCheck_(const struct hostlist_collection_head *hostlists, con
|
||||
LIST_FOREACH(item, hostlists, next)
|
||||
{
|
||||
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 false;
|
||||
@@ -255,10 +256,10 @@ static bool HostlistCheck_(const struct hostlist_collection_head *hostlists, con
|
||||
|
||||
|
||||
// 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);
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
@@ -9,7 +9,7 @@ bool AppendHostList(hostlist_pool **hostlist, const char *filename);
|
||||
bool LoadAllHostLists();
|
||||
bool NonEmptyHostlist(hostlist_pool **hostlist);
|
||||
// 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);
|
||||
bool HostlistsReloadCheckForProfile(const struct desync_profile *dp);
|
||||
void HostlistsDebug();
|
||||
|
400
nfq/kavl.h
Normal file
400
nfq/kavl.h
Normal 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
|
292
nfq/nfqws.c
292
nfq/nfqws.c
@@ -297,7 +297,7 @@ static int nfq_main(void)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (params.droproot && !droproot(params.uid, params.gid, params.gid_count) || !dropcaps())
|
||||
if (params.droproot && !droproot(params.uid, params.user, params.gid, params.gid_count) || !dropcaps())
|
||||
goto err;
|
||||
print_id();
|
||||
if (params.droproot && !test_list_files())
|
||||
@@ -306,6 +306,18 @@ static int nfq_main(void)
|
||||
if (!nfq_init(&h,&qh))
|
||||
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();
|
||||
|
||||
sec_harden();
|
||||
@@ -330,6 +342,11 @@ static int nfq_main(void)
|
||||
while ((rd = recv(fd, buf, sizeof(buf), 0)) >= 0)
|
||||
{
|
||||
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)
|
||||
{
|
||||
int r = nfq_handle_packet(h, (char *)buf, (int)rd);
|
||||
@@ -346,9 +363,16 @@ static int nfq_main(void)
|
||||
} while(e==ENOBUFS);
|
||||
|
||||
nfq_deinit(&h,&qh);
|
||||
#ifdef HAS_FILTER_SSID
|
||||
wlan_info_deinit();
|
||||
#endif
|
||||
return 0;
|
||||
err:
|
||||
if (Fpid) fclose(Fpid);
|
||||
nfq_deinit(&h,&qh);
|
||||
#ifdef HAS_FILTER_SSID
|
||||
wlan_info_deinit();
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -423,7 +447,7 @@ static int dvt_main(void)
|
||||
goto exiterr;
|
||||
|
||||
|
||||
if (params.droproot && !droproot(params.uid, params.gid, params.gid_count))
|
||||
if (params.droproot && !droproot(params.uid, params.user, params.gid, params.gid_count))
|
||||
goto exiterr;
|
||||
print_id();
|
||||
if (params.droproot && !test_list_files())
|
||||
@@ -645,34 +669,9 @@ static int win_main(const char *windivert_filter)
|
||||
|
||||
|
||||
|
||||
#if !defined( __OpenBSD__) && !defined(__ANDROID__)
|
||||
static void cleanup_args()
|
||||
{
|
||||
wordfree(¶ms.wexp);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void cleanup_params(void)
|
||||
{
|
||||
#if !defined( __OpenBSD__) && !defined(__ANDROID__)
|
||||
cleanup_args();
|
||||
#endif
|
||||
|
||||
ConntrackPoolDestroy(¶ms.conntrack);
|
||||
|
||||
dp_list_destroy(¶ms.desync_profiles);
|
||||
|
||||
hostlist_files_destroy(¶ms.hostlists);
|
||||
ipset_files_destroy(¶ms.ipsets);
|
||||
ipcacheDestroy(¶ms.ipcache);
|
||||
#ifdef __CYGWIN__
|
||||
strlist_destroy(¶ms.ssid_filter);
|
||||
strlist_destroy(¶ms.nlm_filter);
|
||||
#endif
|
||||
}
|
||||
static void exit_clean(int code)
|
||||
{
|
||||
cleanup_params();
|
||||
cleanup_params(¶ms);
|
||||
exit(code);
|
||||
}
|
||||
|
||||
@@ -736,7 +735,7 @@ static bool parse_cutoff(const char *opt, unsigned int *value, char *mode)
|
||||
*mode = (*opt=='n' || *opt=='d' || *opt=='s') ? *opt++ : 'n';
|
||||
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)
|
||||
{
|
||||
@@ -780,27 +779,33 @@ static bool parse_autottl(const char *s, autottl *t, int8_t def_delta, uint8_t d
|
||||
t->max = def_max;
|
||||
if (s)
|
||||
{
|
||||
max = t->max;
|
||||
if (*s=='+')
|
||||
// "-" means disable
|
||||
if (s[0]=='-' && s[1]==0)
|
||||
memset(t,0,sizeof(*t));
|
||||
else
|
||||
{
|
||||
neg=false;
|
||||
s++;
|
||||
} else if (*s=='-')
|
||||
s++;
|
||||
switch (sscanf(s,"%u:%u-%u",&delta,&min,&max))
|
||||
{
|
||||
case 3:
|
||||
if ((delta && !max) || max>255) return false;
|
||||
t->max=(uint8_t)max;
|
||||
case 2:
|
||||
if ((delta && !min) || min>255 || min>max) return false;
|
||||
t->min=(uint8_t)min;
|
||||
case 1:
|
||||
if (delta>127) return false;
|
||||
t->delta=(int8_t)(neg ? -delta : delta);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
max = t->max;
|
||||
if (*s=='+')
|
||||
{
|
||||
neg=false;
|
||||
s++;
|
||||
} else if (*s=='-')
|
||||
s++;
|
||||
switch (sscanf(s,"%u:%u-%u",&delta,&min,&max))
|
||||
{
|
||||
case 3:
|
||||
if ((delta && !max) || max>255) return false;
|
||||
t->max=(uint8_t)max;
|
||||
case 2:
|
||||
if ((delta && !min) || min>255 || min>max) return false;
|
||||
t->min=(uint8_t)min;
|
||||
case 1:
|
||||
if (delta>127) return false;
|
||||
t->delta=(int8_t)(neg ? -delta : delta);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@@ -1121,6 +1126,20 @@ static bool parse_fooling(char *opt, unsigned int *fooling_mode)
|
||||
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)
|
||||
{
|
||||
if (!dp->split_count)
|
||||
@@ -1430,7 +1449,7 @@ static bool wf_make_filter(
|
||||
const char *pf_tcp_src, const char *pf_tcp_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 *f_tcpin = *pf_tcp_src ? dp_list_have_autohostlist(¶ms.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(¶ms.desync_profiles)) ? DIVERT_TCP_NOT_EMPTY " and " : "";
|
||||
@@ -1479,7 +1498,11 @@ static void exithelp(void)
|
||||
#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"
|
||||
#endif
|
||||
#ifdef __ANDROID__
|
||||
" --debug=0|1|syslog|android|@<filename>\n"
|
||||
#else
|
||||
" --debug=0|1|syslog|@<filename>\n"
|
||||
#endif
|
||||
" --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"
|
||||
" --comment=any_text\n"
|
||||
@@ -1522,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-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"
|
||||
#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-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"
|
||||
@@ -1543,17 +1569,18 @@ static void exithelp(void)
|
||||
" --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-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-autottl6=[<delta>[:<min>[-<max>]]]\t; overrides --orig-autottl for ipv6 only\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-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"
|
||||
" --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-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-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-fooling=<mode>[,<mode>]\t\t\t; can use multiple comma separated values. modes : none md5sig badseq badsum datanoack hopbyhop hopbyhop2\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-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-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"
|
||||
@@ -1573,9 +1600,9 @@ static void exithelp(void)
|
||||
#endif
|
||||
" --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-autottl=[<delta>[:<min>[-<max>]]]\t; 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-fooling=<mode>[,<mode>]\t\t; can use multiple comma separated values. modes : none md5sig badseq badsum datanoack hopbyhop hopbyhop2\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-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-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"
|
||||
@@ -1587,6 +1614,7 @@ static void exithelp(void)
|
||||
" --dpi-desync-fakedsplit-pattern=<filename>|0xHEX ; fake pattern for fakedsplit/fakeddisorder\n"
|
||||
" --dpi-desync-ipfrag-pos-tcp=<8..%u>\t\t; ip frag position starting from the transport header. multiple of 8, default %u.\n"
|
||||
" --dpi-desync-ipfrag-pos-udp=<8..%u>\t\t; ip frag position starting from the transport header. multiple of 8, default %u.\n"
|
||||
" --dpi-desync-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-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"
|
||||
@@ -1610,21 +1638,21 @@ static void exithelp(void)
|
||||
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_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)
|
||||
DPI_DESYNC_FWMARK_DEFAULT,DPI_DESYNC_FWMARK_DEFAULT,
|
||||
#endif
|
||||
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_TCP_DEFAULT,
|
||||
BADSEQ_INCREMENT_DEFAULT, BADSEQ_ACK_INCREMENT_DEFAULT,
|
||||
TS_INCREMENT_DEFAULT, BADSEQ_INCREMENT_DEFAULT, BADSEQ_ACK_INCREMENT_DEFAULT,
|
||||
UDPLEN_INCREMENT_DEFAULT
|
||||
);
|
||||
exit(1);
|
||||
}
|
||||
static void exithelp_clean(void)
|
||||
{
|
||||
cleanup_params();
|
||||
cleanup_params(¶ms);
|
||||
exithelp();
|
||||
}
|
||||
|
||||
@@ -1669,7 +1697,8 @@ void check_dp(const struct desync_profile *dp)
|
||||
DLOG_CONDUP("WARNING !!! it's completely ok if connbytes or payload based ip/nf tables limiter is applied. Make sure it exists.\n");
|
||||
#else
|
||||
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");
|
||||
#ifdef __CYGWIN__
|
||||
DLOG_CONDUP("WARNING !!! in most cases this is acceptable only with custom payload based windivert filter (--wf-raw)\n");
|
||||
@@ -1681,10 +1710,18 @@ void check_dp(const struct desync_profile *dp)
|
||||
#define STRINGIFY(x) #x
|
||||
#define TOSTRING(x) STRINGIFY(x)
|
||||
#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))
|
||||
#endif
|
||||
#else
|
||||
#ifdef __ANDROID__
|
||||
#define PRINT_VER printf("self-built android version %s %s\n\n", __DATE__, __TIME__)
|
||||
#else
|
||||
#define PRINT_VER printf("self-built version %s %s\n\n", __DATE__, __TIME__)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
enum opt_indices {
|
||||
IDX_DEBUG,
|
||||
@@ -1727,6 +1764,7 @@ enum opt_indices {
|
||||
IDX_DUP_AUTOTTL,
|
||||
IDX_DUP_AUTOTTL6,
|
||||
IDX_DUP_FOOLING,
|
||||
IDX_DUP_TS_INCREMENT,
|
||||
IDX_DUP_BADSEQ_INCREMENT,
|
||||
IDX_DUP_BADACK_INCREMENT,
|
||||
IDX_DUP_REPLACE,
|
||||
@@ -1753,6 +1791,7 @@ enum opt_indices {
|
||||
IDX_DPI_DESYNC_FAKEDSPLIT_PATTERN,
|
||||
IDX_DPI_DESYNC_IPFRAG_POS_TCP,
|
||||
IDX_DPI_DESYNC_IPFRAG_POS_UDP,
|
||||
IDX_DPI_DESYNC_TS_INCREMENT,
|
||||
IDX_DPI_DESYNC_BADSEQ_INCREMENT,
|
||||
IDX_DPI_DESYNC_BADACK_INCREMENT,
|
||||
IDX_DPI_DESYNC_ANY_PROTOCOL,
|
||||
@@ -1786,6 +1825,9 @@ enum opt_indices {
|
||||
IDX_FILTER_TCP,
|
||||
IDX_FILTER_UDP,
|
||||
IDX_FILTER_L7,
|
||||
#ifdef HAS_FILTER_SSID
|
||||
IDX_FILTER_SSID,
|
||||
#endif
|
||||
IDX_IPSET,
|
||||
IDX_IPSET_IP,
|
||||
IDX_IPSET_EXCLUDE,
|
||||
@@ -1848,6 +1890,7 @@ static const struct option long_options[] = {
|
||||
[IDX_DUP_AUTOTTL] = {"dup-autottl", optional_argument, 0, 0},
|
||||
[IDX_DUP_AUTOTTL6] = {"dup-autottl6", optional_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_BADACK_INCREMENT] = {"dup-badack-increment", required_argument, 0, 0},
|
||||
[IDX_DUP_REPLACE] = {"dup-replace", optional_argument, 0, 0},
|
||||
@@ -1874,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_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_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_BADACK_INCREMENT] = {"dpi-desync-badack-increment", required_argument, 0, 0},
|
||||
[IDX_DPI_DESYNC_ANY_PROTOCOL] = {"dpi-desync-any-protocol", optional_argument, 0, 0},
|
||||
@@ -1907,6 +1951,9 @@ static const struct option long_options[] = {
|
||||
[IDX_FILTER_TCP] = {"filter-tcp", required_argument, 0, 0},
|
||||
[IDX_FILTER_UDP] = {"filter-udp", 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_IP] = {"ipset-ip", required_argument, 0, 0},
|
||||
[IDX_IPSET_EXCLUDE] = {"ipset-exclude", required_argument, 0, 0},
|
||||
@@ -1946,7 +1993,7 @@ int main(int argc, char **argv)
|
||||
struct hostlist_file *anon_hl = NULL, *anon_hl_exclude = NULL;
|
||||
struct ipset_file *anon_ips = NULL, *anon_ips_exclude = NULL;
|
||||
#ifdef __CYGWIN__
|
||||
char windivert_filter[8192], wf_pf_tcp_src[256], wf_pf_tcp_dst[256], wf_pf_udp_src[256], wf_pf_udp_dst[256], wf_save_file[256];
|
||||
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;
|
||||
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;
|
||||
@@ -2042,10 +2089,22 @@ int main(int argc, char **argv)
|
||||
params.debug_target = LOG_TARGET_SYSLOG;
|
||||
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
|
||||
{
|
||||
params.debug = !!atoi(optarg);
|
||||
params.debug_target = LOG_TARGET_CONSOLE;
|
||||
fprintf(stderr, "invalid debug mode : %s\n", optarg);
|
||||
exit_clean(1);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -2093,6 +2152,7 @@ int main(int argc, char **argv)
|
||||
#ifndef __CYGWIN__
|
||||
case IDX_USER:
|
||||
{
|
||||
free(params.user); params.user=NULL;
|
||||
struct passwd *pwd = getpwnam(optarg);
|
||||
if (!pwd)
|
||||
{
|
||||
@@ -2100,27 +2160,18 @@ int main(int argc, char **argv)
|
||||
exit_clean(1);
|
||||
}
|
||||
params.uid = pwd->pw_uid;
|
||||
params.gid_count=MAX_GIDS;
|
||||
#ifdef __APPLE__
|
||||
// silence warning
|
||||
if (getgrouplist(optarg,pwd->pw_gid,(int*)params.gid,¶ms.gid_count)<0)
|
||||
#else
|
||||
if (getgrouplist(optarg,pwd->pw_gid,params.gid,¶ms.gid_count)<0)
|
||||
#endif
|
||||
params.gid[0]=pwd->pw_gid;
|
||||
params.gid_count=1;
|
||||
if (!(params.user=strdup(optarg)))
|
||||
{
|
||||
DLOG_ERR("getgrouplist failed. too much groups ?\n");
|
||||
DLOG_ERR("strdup: out of memory\n");
|
||||
exit_clean(1);
|
||||
}
|
||||
if (!params.gid_count)
|
||||
{
|
||||
params.gid[0] = pwd->pw_gid;
|
||||
params.gid_count = 1;
|
||||
}
|
||||
params.droproot = true;
|
||||
break;
|
||||
}
|
||||
case IDX_UID:
|
||||
params.droproot = true;
|
||||
free(params.user); params.user=NULL;
|
||||
if (!parse_uid(optarg,¶ms.uid,params.gid,¶ms.gid_count,MAX_GIDS))
|
||||
{
|
||||
DLOG_ERR("--uid should be : uid[:gid,gid,...]\n");
|
||||
@@ -2131,6 +2182,7 @@ int main(int argc, char **argv)
|
||||
params.gid[0] = 0x7FFFFFFF;
|
||||
params.gid_count = 1;
|
||||
}
|
||||
params.droproot = true;
|
||||
break;
|
||||
#endif
|
||||
case IDX_WSIZE:
|
||||
@@ -2314,15 +2366,22 @@ int main(int argc, char **argv)
|
||||
exit_clean(1);
|
||||
}
|
||||
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:
|
||||
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");
|
||||
exit_clean(1);
|
||||
}
|
||||
break;
|
||||
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");
|
||||
exit_clean(1);
|
||||
@@ -2513,15 +2572,22 @@ int main(int argc, char **argv)
|
||||
exit_clean(1);
|
||||
}
|
||||
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:
|
||||
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");
|
||||
exit_clean(1);
|
||||
}
|
||||
break;
|
||||
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");
|
||||
exit_clean(1);
|
||||
@@ -2779,6 +2845,16 @@ int main(int argc, char **argv)
|
||||
exit_clean(1);
|
||||
}
|
||||
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:
|
||||
if (bSkip) break;
|
||||
if (!RegisterIpset(dp, false, optarg))
|
||||
@@ -2883,38 +2959,18 @@ int main(int argc, char **argv)
|
||||
break;
|
||||
case IDX_SSID_FILTER:
|
||||
hash_ssid_filter=hash_jen(optarg,strlen(optarg));
|
||||
if (!parse_strlist(optarg,¶ms.ssid_filter))
|
||||
{
|
||||
char *e,*p = optarg;
|
||||
while (p)
|
||||
{
|
||||
e = strchr(p,',');
|
||||
if (e) *e++=0;
|
||||
if (*p && !strlist_add(¶ms.ssid_filter, p))
|
||||
{
|
||||
DLOG_ERR("strlist_add failed\n");
|
||||
exit_clean(1);
|
||||
}
|
||||
p = e;
|
||||
|
||||
}
|
||||
DLOG_ERR("strlist_add failed\n");
|
||||
exit_clean(1);
|
||||
}
|
||||
break;
|
||||
case IDX_NLM_FILTER:
|
||||
hash_nlm_filter=hash_jen(optarg,strlen(optarg));
|
||||
if (!parse_strlist(optarg,¶ms.nlm_filter))
|
||||
{
|
||||
char *e,*p = optarg;
|
||||
while (p)
|
||||
{
|
||||
e = strchr(p,',');
|
||||
if (e) *e++=0;
|
||||
if (*p && !strlist_add(¶ms.nlm_filter, p))
|
||||
{
|
||||
DLOG_ERR("strlist_add failed\n");
|
||||
exit_clean(1);
|
||||
}
|
||||
p = e;
|
||||
|
||||
}
|
||||
DLOG_ERR("strlist_add failed\n");
|
||||
exit_clean(1);
|
||||
}
|
||||
break;
|
||||
case IDX_NLM_LIST:
|
||||
@@ -2939,7 +2995,7 @@ int main(int argc, char **argv)
|
||||
|
||||
// do not need args from file anymore
|
||||
#if !defined( __OpenBSD__) && !defined(__ANDROID__)
|
||||
cleanup_args();
|
||||
cleanup_args(¶ms);
|
||||
#endif
|
||||
argv=NULL; argc=0;
|
||||
|
||||
@@ -3079,6 +3135,20 @@ int main(int argc, char **argv)
|
||||
|
||||
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");
|
||||
exit_clean(0);
|
||||
}
|
||||
@@ -3103,7 +3173,7 @@ int main(int argc, char **argv)
|
||||
#endif
|
||||
ex:
|
||||
rawsend_cleanup();
|
||||
cleanup_params();
|
||||
cleanup_params(¶ms);
|
||||
#ifdef __CYGWIN__
|
||||
if (hMutexArg)
|
||||
{
|
||||
|
@@ -2,6 +2,10 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __linux__
|
||||
#define HAS_FILTER_SSID 1
|
||||
#endif
|
||||
|
||||
#ifdef __CYGWIN__
|
||||
extern bool bQuit;
|
||||
#endif
|
||||
|
90
nfq/params.c
90
nfq/params.c
@@ -3,6 +3,9 @@
|
||||
#include <stdarg.h>
|
||||
#include <syslog.h>
|
||||
#include <errno.h>
|
||||
#ifdef __ANDROID__
|
||||
#include <android/log.h>
|
||||
#endif
|
||||
|
||||
#include "pools.h"
|
||||
#include "desync.h"
|
||||
@@ -40,18 +43,47 @@ int DLOG_FILENAME(const char *filename, const char *format, va_list args)
|
||||
return r;
|
||||
}
|
||||
|
||||
static char syslog_buf[1024];
|
||||
static size_t syslog_buf_sz=0;
|
||||
static void syslog_buffered(int priority, const char *format, va_list args)
|
||||
typedef void (*f_log_function)(int priority, const char *line);
|
||||
|
||||
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
|
||||
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);
|
||||
syslog_buf_sz = 0;
|
||||
log_function(syslog_priority,log_buf);
|
||||
log_buf_sz = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -79,9 +111,16 @@ static int DLOG_VA(const char *format, int syslog_priority, bool condup, va_list
|
||||
break;
|
||||
case LOG_TARGET_SYSLOG:
|
||||
// skip newlines
|
||||
syslog_buffered(syslog_priority,format,args);
|
||||
log_buffered(syslog_log_function,syslog_priority,format,args);
|
||||
r = 1;
|
||||
break;
|
||||
#ifdef __ANDROID__
|
||||
case LOG_TARGET_ANDROID:
|
||||
// skip newlines
|
||||
log_buffered(android_log_function,syslog_priority,format,args);
|
||||
r = 1;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -188,6 +227,7 @@ void dp_init(struct desync_profile *dp)
|
||||
dp->fake_syndata_size = 16;
|
||||
dp->wscale=-1; // default - dont change scale factor (client)
|
||||
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_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
|
||||
@@ -263,6 +303,9 @@ static void dp_clear_dynamic(struct desync_profile *dp)
|
||||
ipset_collection_destroy(&dp->ips_collection_exclude);
|
||||
port_filters_destroy(&dp->pf_tcp);
|
||||
port_filters_destroy(&dp->pf_udp);
|
||||
#ifdef HAS_FILTER_SSID
|
||||
strlist_destroy(&dp->filter_ssid);
|
||||
#endif
|
||||
HostFailPoolDestroy(&dp->hostlist_auto_fail_counters);
|
||||
struct blob_collection_head **fake,*fakes[] = {&dp->fake_http, &dp->fake_tls, &dp->fake_unknown, &dp->fake_unknown_udp, &dp->fake_quic, &dp->fake_wg, &dp->fake_dht, &dp->fake_discord, &dp->fake_stun, NULL};
|
||||
for(fake=fakes;*fake;fake++) blob_collection_destroy(*fake);
|
||||
@@ -303,3 +346,32 @@ bool dp_list_need_all_out(struct desync_profile_list_head *head)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
#if !defined( __OpenBSD__) && !defined(__ANDROID__)
|
||||
void cleanup_args(struct params_s *params)
|
||||
{
|
||||
wordfree(¶ms->wexp);
|
||||
}
|
||||
#endif
|
||||
|
||||
void cleanup_params(struct params_s *params)
|
||||
{
|
||||
#if !defined( __OpenBSD__) && !defined(__ANDROID__)
|
||||
cleanup_args(params);
|
||||
#endif
|
||||
|
||||
ConntrackPoolDestroy(¶ms->conntrack);
|
||||
|
||||
dp_list_destroy(¶ms->desync_profiles);
|
||||
|
||||
hostlist_files_destroy(¶ms->hostlists);
|
||||
ipset_files_destroy(¶ms->ipsets);
|
||||
ipcacheDestroy(¶ms->ipcache);
|
||||
#ifdef __CYGWIN__
|
||||
strlist_destroy(¶ms->ssid_filter);
|
||||
strlist_destroy(¶ms->nlm_filter);
|
||||
#else
|
||||
free(params->user); params->user=NULL;
|
||||
#endif
|
||||
}
|
||||
|
28
nfq/params.h
28
nfq/params.h
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "nfqws.h"
|
||||
#include "pools.h"
|
||||
#include "conntrack.h"
|
||||
#include "desync.h"
|
||||
@@ -27,6 +28,8 @@
|
||||
#define BADSEQ_INCREMENT_DEFAULT -10000
|
||||
#define BADSEQ_ACK_INCREMENT_DEFAULT -66000
|
||||
|
||||
#define TS_INCREMENT_DEFAULT -600000
|
||||
|
||||
#define IPFRAG_UDP_DEFAULT 8
|
||||
#define IPFRAG_TCP_DEFAULT 32
|
||||
|
||||
@@ -65,7 +68,7 @@
|
||||
|
||||
#define MAX_GIDS 64
|
||||
|
||||
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 fake_tls_mod_cache
|
||||
{
|
||||
@@ -107,7 +110,7 @@ struct desync_profile
|
||||
unsigned int dup_repeats;
|
||||
uint8_t dup_ttl, dup_ttl6;
|
||||
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;
|
||||
|
||||
char orig_mod_start_mode, orig_mod_cutoff_mode; // n - packets, d - data packets, s - relative sequence
|
||||
@@ -120,7 +123,7 @@ struct desync_profile
|
||||
uint8_t desync_ttl, desync_ttl6;
|
||||
autottl desync_autottl, desync_autottl6;
|
||||
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;
|
||||
uint8_t fake_syndata[FAKE_MAX_TCP],seqovl_pattern[FAKE_MAX_TCP],fsplit_pattern[FAKE_MAX_TCP],udplen_pattern[FAKE_MAX_UDP];
|
||||
@@ -135,6 +138,13 @@ struct desync_profile
|
||||
struct port_filters_head pf_tcp,pf_udp;
|
||||
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
|
||||
struct ipset_collection_head ips_collection, ips_collection_exclude;
|
||||
|
||||
@@ -192,6 +202,7 @@ struct params_s
|
||||
struct str_list_head ssid_filter,nlm_filter;
|
||||
#else
|
||||
bool droproot;
|
||||
char *user;
|
||||
uid_t uid;
|
||||
gid_t gid[MAX_GIDS];
|
||||
int gid_count;
|
||||
@@ -209,13 +220,22 @@ struct params_s
|
||||
t_conntrack conntrack;
|
||||
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;
|
||||
ip_cache ipcache;
|
||||
};
|
||||
|
||||
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 DLOG_ERR(const char *format, ...);
|
||||
|
235
nfq/pools.c
235
nfq/pools.c
@@ -159,6 +159,19 @@ void strlist_destroy(struct str_list_head *head)
|
||||
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 +273,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;
|
||||
HASH_ITER(hh, *ipset, elem, tmp)
|
||||
unsigned int bitlen = q->bitlen < p->bitlen ? q->bitlen : p->bitlen;
|
||||
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(elem);
|
||||
free(e->data);
|
||||
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 cidr4 cidr;
|
||||
ipset4 *ips_found;
|
||||
|
||||
// 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;
|
||||
struct kavl_bit_elem temp = {
|
||||
.bitlen = bitlen, .data = (uint8_t*)data
|
||||
};
|
||||
kavl_bit_destroy_elem(kavl_erase(kavl_bit, hdr, &temp, 0));
|
||||
}
|
||||
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;
|
||||
|
||||
// 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;
|
||||
return ipset_kavl_add(ipset,a,preflen);
|
||||
}
|
||||
void ipset4Print(ipset4 *ipset)
|
||||
void ipset4Print(struct kavl_bit_elem *ipset)
|
||||
{
|
||||
ipset4 *ips, *tmp;
|
||||
HASH_ITER(hh, ipset , ips, tmp)
|
||||
{
|
||||
print_cidr4(&ips->cidr);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
if (!ipset) return;
|
||||
|
||||
void ipset6Destroy(ipset6 **ipset)
|
||||
{
|
||||
ipset6 *elem, *tmp;
|
||||
HASH_ITER(hh, *ipset, elem, tmp)
|
||||
{
|
||||
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;
|
||||
struct cidr4 c;
|
||||
const struct kavl_bit_elem *elem;
|
||||
kavl_itr_t(kavl_bit) itr;
|
||||
kavl_itr_first(kavl_bit, ipset, &itr);
|
||||
do
|
||||
{
|
||||
cidr.preflen--;
|
||||
ip6_and(a, mask_from_preflen6(cidr.preflen), &cidr.addr);
|
||||
HASH_FIND(hh, ipset, &cidr, sizeof(cidr), ips_found);
|
||||
if (ips_found) return true;
|
||||
} 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);
|
||||
elem = kavl_at(&itr);
|
||||
c.preflen = elem->bitlen;
|
||||
expand_bits(&c.addr, elem->data, elem->bitlen, sizeof(c.addr));
|
||||
print_cidr4(&c);
|
||||
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)
|
||||
{
|
||||
ipset4Destroy(&ipset->ips4);
|
||||
ipset6Destroy(&ipset->ips6);
|
||||
kavl_bit_destroy(&ipset->ips4);
|
||||
kavl_bit_destroy(&ipset->ips6);
|
||||
}
|
||||
void ipsetPrint(ipset *ipset)
|
||||
{
|
||||
@@ -591,6 +629,7 @@ static void ipcache_item_init(ip_cache_item *item)
|
||||
{
|
||||
ipcache_item_touch(item);
|
||||
item->hostname = NULL;
|
||||
item->hostname_is_ip = false;
|
||||
item->hops = 0;
|
||||
}
|
||||
static void ipcache_item_destroy(ip_cache_item *item)
|
||||
@@ -652,7 +691,7 @@ static void ipcache4Print(ip_cache4 *ipcache)
|
||||
{
|
||||
*s_ip=0;
|
||||
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 +749,7 @@ static void ipcache6Print(ip_cache6 *ipcache)
|
||||
{
|
||||
*s_ip=0;
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
|
53
nfq/pools.h
53
nfq/pools.h
@@ -13,6 +13,8 @@
|
||||
#define HASH_FUNCTION HASH_BER
|
||||
#include "uthash.h"
|
||||
|
||||
#include "kavl.h"
|
||||
|
||||
#define HOSTLIST_POOL_FLAG_STRICT_MATCH 1
|
||||
|
||||
typedef struct hostlist_pool {
|
||||
@@ -32,6 +34,11 @@ struct 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 {
|
||||
char *str; /* key */
|
||||
int counter; /* value */
|
||||
@@ -47,10 +54,6 @@ void HostFailPoolPurge(hostfail_pool **pp);
|
||||
void HostFailPoolPurgeRateLimited(hostfail_pool **pp);
|
||||
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 {
|
||||
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);
|
||||
|
||||
|
||||
typedef struct ipset4 {
|
||||
struct cidr4 cidr; /* key */
|
||||
UT_hash_handle hh; /* makes this structure hashable */
|
||||
} ipset4;
|
||||
typedef struct ipset6 {
|
||||
struct cidr6 cidr; /* key */
|
||||
UT_hash_handle hh; /* makes this structure hashable */
|
||||
} ipset6;
|
||||
struct kavl_bit_elem
|
||||
{
|
||||
unsigned int bitlen;
|
||||
uint8_t *data;
|
||||
KAVL_HEAD(struct kavl_bit_elem) head;
|
||||
};
|
||||
|
||||
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
|
||||
typedef struct ipset {
|
||||
ipset4 *ips4;
|
||||
ipset6 *ips6;
|
||||
struct kavl_bit_elem *ips4,*ips6;
|
||||
} ipset;
|
||||
|
||||
#define IPSET_EMPTY(ips) (!(ips)->ips4 && !(ips)->ips6)
|
||||
|
||||
void ipset4Destroy(ipset4 **ipset);
|
||||
bool ipset4Add(ipset4 **ipset, const struct in_addr *a, uint8_t preflen);
|
||||
static inline bool ipset4AddCidr(ipset4 **ipset, const struct cidr4 *cidr)
|
||||
bool ipset4Add(struct kavl_bit_elem **ipset, const struct in_addr *a, uint8_t preflen);
|
||||
static inline bool ipset4AddCidr(struct kavl_bit_elem **ipset, const struct cidr4 *cidr)
|
||||
{
|
||||
return ipset4Add(ipset,&cidr->addr,cidr->preflen);
|
||||
}
|
||||
bool ipset4Check(ipset4 *ipset, const struct in_addr *a, uint8_t preflen);
|
||||
void ipset4Print(ipset4 *ipset);
|
||||
bool ipset4Check(const struct kavl_bit_elem *ipset, const struct in_addr *a, uint8_t preflen);
|
||||
void ipset4Print(struct kavl_bit_elem *ipset);
|
||||
|
||||
void ipset6Destroy(ipset6 **ipset);
|
||||
bool ipset6Add(ipset6 **ipset, const struct in6_addr *a, uint8_t preflen);
|
||||
static inline bool ipset6AddCidr(ipset6 **ipset, const struct cidr6 *cidr)
|
||||
bool ipset6Add(struct kavl_bit_elem **ipset, const struct in6_addr *a, uint8_t preflen);
|
||||
static inline bool ipset6AddCidr(struct kavl_bit_elem **ipset, const struct cidr6 *cidr)
|
||||
{
|
||||
return ipset6Add(ipset,&cidr->addr,cidr->preflen);
|
||||
}
|
||||
bool ipset6Check(ipset6 *ipset, const struct in6_addr *a, uint8_t preflen);
|
||||
void ipset6Print(ipset6 *ipset);
|
||||
bool ipset6Check(const struct kavl_bit_elem *ipset, const struct in6_addr *a, uint8_t preflen);
|
||||
void ipset6Print(struct kavl_bit_elem *ipset);
|
||||
|
||||
void ipsetDestroy(ipset *ipset);
|
||||
void ipsetPrint(ipset *ipset);
|
||||
@@ -178,6 +182,7 @@ typedef struct ip_cache_item
|
||||
{
|
||||
time_t last;
|
||||
char *hostname;
|
||||
bool hostname_is_ip;
|
||||
uint8_t hops;
|
||||
} ip_cache_item;
|
||||
typedef struct ip_cache4
|
||||
|
22
nfq/sec.c
22
nfq/sec.c
@@ -295,7 +295,7 @@ bool can_drop_root(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
bool droproot(uid_t uid, gid_t *gid, int gid_count)
|
||||
bool droproot(uid_t uid, const char *user, const gid_t *gid, int gid_count)
|
||||
{
|
||||
if (gid_count<1)
|
||||
{
|
||||
@@ -309,11 +309,23 @@ bool droproot(uid_t uid, gid_t *gid, int gid_count)
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
// drop all SGIDs
|
||||
if (setgroups(gid_count,gid))
|
||||
if (user)
|
||||
{
|
||||
DLOG_PERROR("setgroups");
|
||||
return false;
|
||||
// macos has strange supp gid handling. they cache only 16 groups and fail setgroups if more than 16 gids specified.
|
||||
// better to leave it to the os
|
||||
if (initgroups(user,gid[0]))
|
||||
{
|
||||
DLOG_PERROR("initgroups");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (setgroups(gid_count,gid))
|
||||
{
|
||||
DLOG_PERROR("setgroups");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (setgid(gid[0]))
|
||||
{
|
||||
|
@@ -84,7 +84,7 @@ bool dropcaps(void);
|
||||
#ifndef __CYGWIN__
|
||||
bool sec_harden(void);
|
||||
bool can_drop_root(void);
|
||||
bool droproot(uid_t uid, gid_t *gid, int gid_count);
|
||||
bool droproot(uid_t uid, const char *user, const gid_t *gid, int gid_count);
|
||||
void print_id(void);
|
||||
#endif
|
||||
|
||||
|
@@ -1,5 +1,6 @@
|
||||
CC ?= cc
|
||||
CFLAGS += -std=gnu99 -s -Os -flto=auto
|
||||
OPTIMIZE ?= -Os
|
||||
CFLAGS += -std=gnu99 -s $(OPTIMIZE) -flto=auto
|
||||
LIBS = -lz -lpthread
|
||||
SRC_FILES = *.c
|
||||
|
||||
|
@@ -1,7 +1,9 @@
|
||||
CC ?= gcc
|
||||
CFLAGS += -std=gnu99 -Os -flto=auto
|
||||
CC ?= cc
|
||||
OPTIMIZE ?= -Os
|
||||
CFLAGS += -std=gnu99 $(OPTIMIZE) -flto=auto
|
||||
CFLAGS_SYSTEMD = -DUSE_SYSTEMD
|
||||
CFLAGS_BSD = -Wno-address-of-packed-member
|
||||
LDFLAGS_ANDROID = -llog
|
||||
LIBS = -lz -lpthread
|
||||
LIBS_SYSTEMD = -lsystemd
|
||||
LIBS_ANDROID = -lz
|
||||
@@ -17,7 +19,7 @@ systemd: $(SRC_FILES)
|
||||
$(CC) -s $(CFLAGS) $(CFLAGS_SYSTEMD) -o tpws $(SRC_FILES) $(LIBS) $(LIBS_SYSTEMD) $(LDFLAGS)
|
||||
|
||||
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)
|
||||
$(CC) -s $(CFLAGS) $(CFLAGS_BSD) -Iepoll-shim/include -o tpws $(SRC_FILES) epoll-shim/src/*.c $(LIBS) $(LDFLAGS)
|
||||
|
@@ -112,6 +112,72 @@ bool append_to_list_file(const char *filename, const char *s)
|
||||
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)
|
||||
{
|
||||
if (!len) return;
|
||||
|
@@ -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 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_port(const struct sockaddr *sa, char *str, size_t len);
|
||||
void print_sockaddr(const struct sockaddr *sa);
|
||||
|
@@ -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)
|
||||
{
|
||||
@@ -195,6 +195,7 @@ static bool SearchHostList(hostlist_pool *hostlist, const char *host)
|
||||
}
|
||||
else
|
||||
VPRINT("negative\n");
|
||||
if (no_match_subdomains) break;
|
||||
p = strchr(p, '.');
|
||||
if (p) p++;
|
||||
bHostFull = false;
|
||||
@@ -220,7 +221,7 @@ bool HostlistsReloadCheckForProfile(const struct desync_profile *dp)
|
||||
return HostlistsReloadCheck(&dp->hl_collection) && HostlistsReloadCheck(&dp->hl_collection_exclude);
|
||||
}
|
||||
// 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;
|
||||
|
||||
@@ -233,7 +234,7 @@ static bool HostlistCheck_(const struct hostlist_collection_head *hostlists, con
|
||||
LIST_FOREACH(item, hostlists_exclude, next)
|
||||
{
|
||||
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;
|
||||
return false;
|
||||
@@ -245,7 +246,7 @@ static bool HostlistCheck_(const struct hostlist_collection_head *hostlists, con
|
||||
LIST_FOREACH(item, hostlists, next)
|
||||
{
|
||||
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 false;
|
||||
@@ -255,10 +256,10 @@ static bool HostlistCheck_(const struct hostlist_collection_head *hostlists, con
|
||||
|
||||
|
||||
// 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);
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
@@ -9,7 +9,7 @@ bool AppendHostList(hostlist_pool **hostlist, const char *filename);
|
||||
bool LoadAllHostLists();
|
||||
bool NonEmptyHostlist(hostlist_pool **hostlist);
|
||||
// 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);
|
||||
bool HostlistsReloadCheckForProfile(const struct desync_profile *dp);
|
||||
void HostlistsDebug();
|
||||
|
400
tpws/kavl.h
Normal file
400
tpws/kavl.h
Normal 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
|
@@ -2,6 +2,11 @@
|
||||
#include <stdarg.h>
|
||||
#include <syslog.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)
|
||||
{
|
||||
@@ -25,18 +30,47 @@ int DLOG_FILENAME(const char *filename, const char *format, va_list args)
|
||||
return r;
|
||||
}
|
||||
|
||||
static char syslog_buf[1024];
|
||||
static size_t syslog_buf_sz=0;
|
||||
static void syslog_buffered(int priority, const char *format, va_list args)
|
||||
typedef void (*f_log_function)(int priority, const char *line);
|
||||
|
||||
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
|
||||
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);
|
||||
syslog_buf_sz = 0;
|
||||
log_function(syslog_priority,log_buf);
|
||||
log_buf_sz = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -64,9 +98,16 @@ static int DLOG_VA(const char *format, int syslog_priority, bool condup, int lev
|
||||
break;
|
||||
case LOG_TARGET_SYSLOG:
|
||||
// skip newlines
|
||||
syslog_buffered(syslog_priority,format,args);
|
||||
log_buffered(syslog_log_function,syslog_priority,format,args);
|
||||
r = 1;
|
||||
break;
|
||||
#ifdef __ANDROID__
|
||||
case LOG_TARGET_ANDROID:
|
||||
// skip newlines
|
||||
log_buffered(android_log_function,syslog_priority,format,args);
|
||||
r = 1;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -217,3 +258,24 @@ void dp_list_destroy(struct desync_profile_list_head *head)
|
||||
dp_entry_destroy(entry);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if !defined( __OpenBSD__) && !defined(__ANDROID__)
|
||||
void cleanup_args(struct params_s *params)
|
||||
{
|
||||
wordfree(¶ms->wexp);
|
||||
}
|
||||
#endif
|
||||
void cleanup_params(struct params_s *params)
|
||||
{
|
||||
#if !defined( __OpenBSD__) && !defined(__ANDROID__)
|
||||
cleanup_args(params);
|
||||
#endif
|
||||
|
||||
dp_list_destroy(¶ms->desync_profiles);
|
||||
|
||||
hostlist_files_destroy(¶ms->hostlists);
|
||||
ipset_files_destroy(¶ms->ipsets);
|
||||
ipcacheDestroy(¶ms->ipcache);
|
||||
free(params->user); params->user=NULL;
|
||||
}
|
||||
|
@@ -11,6 +11,7 @@
|
||||
#include <wordexp.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "tpws.h"
|
||||
#include "pools.h"
|
||||
#include "helpers.h"
|
||||
@@ -38,7 +39,7 @@ struct bind_s
|
||||
|
||||
#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
|
||||
{
|
||||
@@ -116,8 +117,9 @@ struct params_s
|
||||
bool fix_seg_avail;
|
||||
bool no_resolve;
|
||||
bool skip_nodelay;
|
||||
bool droproot;
|
||||
bool daemon;
|
||||
bool droproot;
|
||||
char *user;
|
||||
uid_t uid;
|
||||
gid_t gid[MAX_GIDS];
|
||||
int gid_count;
|
||||
@@ -153,6 +155,11 @@ struct params_s
|
||||
};
|
||||
|
||||
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_CONDUP(const char *format, ...);
|
||||
|
224
tpws/pools.c
224
tpws/pools.c
@@ -260,121 +260,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;
|
||||
HASH_ITER(hh, *ipset, elem, tmp)
|
||||
unsigned int bitlen = q->bitlen < p->bitlen ? q->bitlen : p->bitlen;
|
||||
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(elem);
|
||||
free(e->data);
|
||||
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 cidr4 cidr;
|
||||
ipset4 *ips_found;
|
||||
|
||||
// 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;
|
||||
struct kavl_bit_elem temp = {
|
||||
.bitlen = bitlen, .data = (uint8_t*)data
|
||||
};
|
||||
kavl_bit_destroy_elem(kavl_erase(kavl_bit, hdr, &temp, 0));
|
||||
}
|
||||
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;
|
||||
|
||||
// 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;
|
||||
return ipset_kavl_add(ipset,a,preflen);
|
||||
}
|
||||
void ipset4Print(ipset4 *ipset)
|
||||
void ipset4Print(struct kavl_bit_elem *ipset)
|
||||
{
|
||||
ipset4 *ips, *tmp;
|
||||
HASH_ITER(hh, ipset , ips, tmp)
|
||||
{
|
||||
print_cidr4(&ips->cidr);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
if (!ipset) return;
|
||||
|
||||
void ipset6Destroy(ipset6 **ipset)
|
||||
{
|
||||
ipset6 *elem, *tmp;
|
||||
HASH_ITER(hh, *ipset, elem, tmp)
|
||||
{
|
||||
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;
|
||||
struct cidr4 c;
|
||||
const struct kavl_bit_elem *elem;
|
||||
kavl_itr_t(kavl_bit) itr;
|
||||
kavl_itr_first(kavl_bit, ipset, &itr);
|
||||
do
|
||||
{
|
||||
cidr.preflen--;
|
||||
ip6_and(a, mask_from_preflen6(cidr.preflen), &cidr.addr);
|
||||
HASH_FIND(hh, ipset, &cidr, sizeof(cidr), ips_found);
|
||||
if (ips_found) return true;
|
||||
} 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);
|
||||
elem = kavl_at(&itr);
|
||||
c.preflen = elem->bitlen;
|
||||
expand_bits(&c.addr, elem->data, elem->bitlen, sizeof(c.addr));
|
||||
print_cidr4(&c);
|
||||
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)
|
||||
{
|
||||
ipset4Destroy(&ipset->ips4);
|
||||
ipset6Destroy(&ipset->ips6);
|
||||
kavl_bit_destroy(&ipset->ips4);
|
||||
kavl_bit_destroy(&ipset->ips6);
|
||||
}
|
||||
void ipsetPrint(ipset *ipset)
|
||||
{
|
||||
@@ -520,7 +545,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 *entry = calloc(1,sizeof(struct blob_item));
|
||||
@@ -591,6 +616,7 @@ static void ipcache_item_init(ip_cache_item *item)
|
||||
{
|
||||
ipcache_item_touch(item);
|
||||
item->hostname = NULL;
|
||||
item->hostname_is_ip = false;
|
||||
}
|
||||
static void ipcache_item_destroy(ip_cache_item *item)
|
||||
{
|
||||
@@ -650,7 +676,7 @@ static void ipcache4Print(ip_cache4 *ipcache)
|
||||
{
|
||||
*s_ip=0;
|
||||
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 +733,7 @@ static void ipcache6Print(ip_cache6 *ipcache)
|
||||
{
|
||||
*s_ip=0;
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
|
44
tpws/pools.h
44
tpws/pools.h
@@ -13,6 +13,8 @@
|
||||
#define HASH_FUNCTION HASH_BER
|
||||
#include "uthash.h"
|
||||
|
||||
#include "kavl.h"
|
||||
|
||||
#define HOSTLIST_POOL_FLAG_STRICT_MATCH 1
|
||||
|
||||
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);
|
||||
|
||||
|
||||
typedef struct ipset4 {
|
||||
struct cidr4 cidr; /* key */
|
||||
UT_hash_handle hh; /* makes this structure hashable */
|
||||
} ipset4;
|
||||
typedef struct ipset6 {
|
||||
struct cidr6 cidr; /* key */
|
||||
UT_hash_handle hh; /* makes this structure hashable */
|
||||
} ipset6;
|
||||
struct kavl_bit_elem
|
||||
{
|
||||
unsigned int bitlen;
|
||||
uint8_t *data;
|
||||
KAVL_HEAD(struct kavl_bit_elem) head;
|
||||
};
|
||||
|
||||
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
|
||||
typedef struct ipset {
|
||||
ipset4 *ips4;
|
||||
ipset6 *ips6;
|
||||
struct kavl_bit_elem *ips4,*ips6;
|
||||
} ipset;
|
||||
|
||||
#define IPSET_EMPTY(ips) (!(ips)->ips4 && !(ips)->ips6)
|
||||
|
||||
void ipset4Destroy(ipset4 **ipset);
|
||||
bool ipset4Add(ipset4 **ipset, const struct in_addr *a, uint8_t preflen);
|
||||
static inline bool ipset4AddCidr(ipset4 **ipset, const struct cidr4 *cidr)
|
||||
bool ipset4Add(struct kavl_bit_elem **ipset, const struct in_addr *a, uint8_t preflen);
|
||||
static inline bool ipset4AddCidr(struct kavl_bit_elem **ipset, const struct cidr4 *cidr)
|
||||
{
|
||||
return ipset4Add(ipset,&cidr->addr,cidr->preflen);
|
||||
}
|
||||
bool ipset4Check(ipset4 *ipset, const struct in_addr *a, uint8_t preflen);
|
||||
void ipset4Print(ipset4 *ipset);
|
||||
bool ipset4Check(const struct kavl_bit_elem *ipset, const struct in_addr *a, uint8_t preflen);
|
||||
void ipset4Print(struct kavl_bit_elem *ipset);
|
||||
|
||||
void ipset6Destroy(ipset6 **ipset);
|
||||
bool ipset6Add(ipset6 **ipset, const struct in6_addr *a, uint8_t preflen);
|
||||
static inline bool ipset6AddCidr(ipset6 **ipset, const struct cidr6 *cidr)
|
||||
bool ipset6Add(struct kavl_bit_elem **ipset, const struct in6_addr *a, uint8_t preflen);
|
||||
static inline bool ipset6AddCidr(struct kavl_bit_elem **ipset, const struct cidr6 *cidr)
|
||||
{
|
||||
return ipset6Add(ipset,&cidr->addr,cidr->preflen);
|
||||
}
|
||||
bool ipset6Check(ipset6 *ipset, const struct in6_addr *a, uint8_t preflen);
|
||||
void ipset6Print(ipset6 *ipset);
|
||||
bool ipset6Check(const struct kavl_bit_elem *ipset, const struct in6_addr *a, uint8_t preflen);
|
||||
void ipset6Print(struct kavl_bit_elem *ipset);
|
||||
|
||||
void ipsetDestroy(ipset *ipset);
|
||||
void ipsetPrint(ipset *ipset);
|
||||
@@ -176,6 +179,7 @@ typedef struct ip_cache_item
|
||||
{
|
||||
time_t last;
|
||||
char *hostname;
|
||||
bool hostname_is_ip;
|
||||
} ip_cache_item;
|
||||
typedef struct ip_cache4
|
||||
{
|
||||
|
22
tpws/sec.c
22
tpws/sec.c
@@ -269,7 +269,7 @@ bool can_drop_root(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
bool droproot(uid_t uid, gid_t *gid, int gid_count)
|
||||
bool droproot(uid_t uid, const char *user, const gid_t *gid, int gid_count)
|
||||
{
|
||||
if (gid_count<1)
|
||||
{
|
||||
@@ -283,11 +283,23 @@ bool droproot(uid_t uid, gid_t *gid, int gid_count)
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
// drop all SGIDs
|
||||
if (setgroups(gid_count,gid))
|
||||
if (user)
|
||||
{
|
||||
DLOG_PERROR("setgroups");
|
||||
return false;
|
||||
// macos has strange supp gid handling. they cache only 16 groups and fail setgroups if more than 16 gids specified.
|
||||
// better to leave it to the os
|
||||
if (initgroups(user,gid[0]))
|
||||
{
|
||||
DLOG_PERROR("initgroups");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (setgroups(gid_count,gid))
|
||||
{
|
||||
DLOG_PERROR("setgroups");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (setgid(gid[0]))
|
||||
{
|
||||
|
@@ -84,7 +84,7 @@ bool dropcaps(void);
|
||||
|
||||
bool sec_harden(void);
|
||||
bool can_drop_root();
|
||||
bool droproot(uid_t uid, gid_t *gid, int gid_count);
|
||||
bool droproot(uid_t uid, const char *user, const gid_t *gid, int gid_count);
|
||||
void print_id(void);
|
||||
void daemonize(void);
|
||||
bool writepid(const char *filename);
|
||||
|
@@ -91,7 +91,7 @@ static void TLSDebug(const uint8_t *tls,size_t sz)
|
||||
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;
|
||||
|
||||
@@ -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");
|
||||
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;
|
||||
}
|
||||
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)
|
||||
{
|
||||
@@ -128,15 +129,16 @@ static bool ipcache_get_hostname(const struct in_addr *a4, const struct in6_addr
|
||||
}
|
||||
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);
|
||||
if (hostname_is_ip) *hostname_is_ip = ipc->hostname_is_ip;
|
||||
}
|
||||
else
|
||||
*hostname = 0;
|
||||
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;
|
||||
|
||||
@@ -167,11 +169,11 @@ static bool dp_match(struct desync_profile *dp, const struct sockaddr *dest, con
|
||||
return true;
|
||||
else if (hostname)
|
||||
// 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;
|
||||
}
|
||||
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;
|
||||
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)
|
||||
{
|
||||
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);
|
||||
return &dpl->dp;
|
||||
@@ -198,11 +200,11 @@ void apply_desync_profile(t_ctrack *ctrack, const struct sockaddr *dest)
|
||||
if (!ctrack->hostname)
|
||||
{
|
||||
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)))
|
||||
DLOG_ERR("hostname dup : out of memory");
|
||||
}
|
||||
ctrack->dp = dp_find(¶ms.desync_profiles, dest, ctrack->hostname, ctrack->l7proto);
|
||||
ctrack->dp = dp_find(¶ms.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;
|
||||
size_t method_len = 0, pos, tpos, orig_size=*size;
|
||||
const char *method;
|
||||
bool bHaveHost = false;
|
||||
bool bHaveHost = false, bHostIsIp = false;
|
||||
char *pc, Host[256];
|
||||
t_l7proto l7proto;
|
||||
|
||||
@@ -271,8 +273,9 @@ void tamper_out(t_ctrack *ctrack, const struct sockaddr *dest, uint8_t *segment,
|
||||
|
||||
if (bHaveHost)
|
||||
{
|
||||
bHostIsIp = strip_host_to_ip(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");
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
return;
|
||||
}
|
||||
ctrack->hostname_is_ip = bHostIsIp;
|
||||
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)
|
||||
{
|
||||
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;
|
||||
if (!ctrack->b_host_matches)
|
||||
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;
|
||||
|
||||
@@ -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);
|
||||
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);
|
||||
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
|
||||
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);
|
||||
}
|
||||
@@ -651,7 +655,7 @@ void rst_in(t_ctrack *ctrack, const struct sockaddr *client)
|
||||
{
|
||||
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));
|
||||
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.
|
||||
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));
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -16,12 +16,13 @@ typedef struct
|
||||
bool bTamperInCutoff;
|
||||
bool b_host_checked,b_host_matches,b_ah_check;
|
||||
bool hostname_discovered;
|
||||
bool hostname_is_ip;
|
||||
char *hostname;
|
||||
struct desync_profile *dp; // desync profile cache
|
||||
} t_ctrack;
|
||||
|
||||
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_in(t_ctrack *ctrack, const struct sockaddr *client, uint8_t *segment,size_t segment_buffer_size,size_t *size);
|
||||
|
99
tpws/tpws.c
99
tpws/tpws.c
@@ -216,7 +216,7 @@ static void exithelp(void)
|
||||
" --pidfile=<filename>\t\t\t; write pid to file\n"
|
||||
" --user=<username>\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"
|
||||
#endif
|
||||
#if defined(__linux__)
|
||||
@@ -224,7 +224,11 @@ static void exithelp(void)
|
||||
#endif
|
||||
" --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"
|
||||
#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"
|
||||
#endif
|
||||
" --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"
|
||||
" --version\t\t\t\t; print version and exit\n"
|
||||
@@ -286,32 +290,14 @@ static void exithelp(void)
|
||||
);
|
||||
exit(1);
|
||||
}
|
||||
#if !defined( __OpenBSD__) && !defined(__ANDROID__)
|
||||
static void cleanup_args()
|
||||
{
|
||||
wordfree(¶ms.wexp);
|
||||
}
|
||||
#endif
|
||||
static void cleanup_params(void)
|
||||
{
|
||||
#if !defined( __OpenBSD__) && !defined(__ANDROID__)
|
||||
cleanup_args();
|
||||
#endif
|
||||
|
||||
dp_list_destroy(¶ms.desync_profiles);
|
||||
|
||||
hostlist_files_destroy(¶ms.hostlists);
|
||||
ipset_files_destroy(¶ms.ipsets);
|
||||
ipcacheDestroy(¶ms.ipcache);
|
||||
}
|
||||
static void exithelp_clean(void)
|
||||
{
|
||||
cleanup_params();
|
||||
cleanup_params(¶ms);
|
||||
exithelp();
|
||||
}
|
||||
static void exit_clean(int code)
|
||||
{
|
||||
cleanup_params();
|
||||
cleanup_params(¶ms);
|
||||
exit(code);
|
||||
}
|
||||
static void nextbind_clean(void)
|
||||
@@ -725,7 +711,7 @@ enum opt_indices {
|
||||
IDX_IPSET_EXCLUDE,
|
||||
IDX_IPSET_EXCLUDE_IP,
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
#if defined(__FreeBSD__) || defined(__OpenBSD__)
|
||||
IDX_ENABLE_PF,
|
||||
#elif defined(__APPLE__)
|
||||
IDX_LOCAL_TCP_USER_TIMEOUT,
|
||||
@@ -818,7 +804,7 @@ static const struct option long_options[] = {
|
||||
[IDX_IPSET_EXCLUDE] = {"ipset-exclude", 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},
|
||||
#elif defined(__APPLE__)
|
||||
[IDX_LOCAL_TCP_USER_TIMEOUT] = {"local-tcp-user-timeout", required_argument, 0, 0},
|
||||
@@ -854,7 +840,7 @@ void parse_params(int argc, char *argv[])
|
||||
params.tcp_user_timeout_remote = DEFAULT_TCP_USER_TIMEOUT_REMOTE;
|
||||
#endif
|
||||
|
||||
#if defined(__OpenBSD__) || defined(__APPLE__)
|
||||
#if defined(__APPLE__)
|
||||
params.pf_enable = true; // OpenBSD and MacOS have no other choice
|
||||
#endif
|
||||
|
||||
@@ -978,6 +964,7 @@ void parse_params(int argc, char *argv[])
|
||||
break;
|
||||
case IDX_USER:
|
||||
{
|
||||
free(params.user); params.user=NULL;
|
||||
struct passwd *pwd = getpwnam(optarg);
|
||||
if (!pwd)
|
||||
{
|
||||
@@ -985,27 +972,18 @@ void parse_params(int argc, char *argv[])
|
||||
exit_clean(1);
|
||||
}
|
||||
params.uid = pwd->pw_uid;
|
||||
params.gid_count=MAX_GIDS;
|
||||
#ifdef __APPLE__
|
||||
// silence warning
|
||||
if (getgrouplist(optarg,pwd->pw_gid,(int*)params.gid,¶ms.gid_count)<0)
|
||||
#else
|
||||
if (getgrouplist(optarg,pwd->pw_gid,params.gid,¶ms.gid_count)<0)
|
||||
#endif
|
||||
params.gid[0]=pwd->pw_gid;
|
||||
params.gid_count=1;
|
||||
if (!(params.user=strdup(optarg)))
|
||||
{
|
||||
DLOG_ERR("getgrouplist failed. too much groups ?\n");
|
||||
DLOG_ERR("strdup: out of memory\n");
|
||||
exit_clean(1);
|
||||
}
|
||||
if (!params.gid_count)
|
||||
{
|
||||
params.gid[0] = pwd->pw_gid;
|
||||
params.gid_count = 1;
|
||||
}
|
||||
params.droproot = true;
|
||||
break;
|
||||
}
|
||||
case IDX_UID:
|
||||
params.droproot = true;
|
||||
free(params.user); params.user=NULL;
|
||||
if (!parse_uid(optarg,¶ms.uid,params.gid,¶ms.gid_count,MAX_GIDS))
|
||||
{
|
||||
DLOG_ERR("--uid should be : uid[:gid,gid,...]\n");
|
||||
@@ -1016,6 +994,7 @@ void parse_params(int argc, char *argv[])
|
||||
params.gid[0] = 0x7FFFFFFF;
|
||||
params.gid_count = 1;
|
||||
}
|
||||
params.droproot = true;
|
||||
break;
|
||||
case IDX_MAXCONN:
|
||||
params.maxconn = atoi(optarg);
|
||||
@@ -1345,13 +1324,25 @@ void parse_params(int argc, char *argv[])
|
||||
{
|
||||
if (!params.debug) params.debug = 1;
|
||||
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_target = LOG_TARGET_CONSOLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "invalid debug mode : %s\n", optarg);
|
||||
exit_clean(1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1563,7 +1554,7 @@ void parse_params(int argc, char *argv[])
|
||||
params.tamper = true;
|
||||
break;
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
#if defined(__FreeBSD__) || defined(__OpenBSD__)
|
||||
case IDX_ENABLE_PF:
|
||||
params.pf_enable = true;
|
||||
break;
|
||||
@@ -1711,10 +1702,22 @@ void parse_params(int argc, char *argv[])
|
||||
|
||||
#if !defined( __OpenBSD__) && !defined(__ANDROID__)
|
||||
// do not need args from file anymore
|
||||
cleanup_args();
|
||||
cleanup_args(¶ms);
|
||||
#endif
|
||||
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");
|
||||
exit_clean(0);
|
||||
}
|
||||
@@ -1871,10 +1874,18 @@ static const char *bindll_s[] = { "unwanted","no","prefer","force" };
|
||||
#define STRINGIFY(x) #x
|
||||
#define TOSTRING(x) STRINGIFY(x)
|
||||
#if defined(ZAPRET_GH_VER) || defined (ZAPRET_GH_HASH)
|
||||
#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))
|
||||
#endif
|
||||
#else
|
||||
#ifdef __ANDROID__
|
||||
#define PRINT_VER printf("self-built android version %s %s\n\n", __DATE__, __TIME__)
|
||||
#else
|
||||
#define PRINT_VER printf("self-built version %s %s\n\n", __DATE__, __TIME__)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
@@ -2135,7 +2146,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
set_ulimit();
|
||||
if (params.droproot && !droproot(params.uid,params.gid,params.gid_count))
|
||||
if (params.droproot && !droproot(params.uid,params.user,params.gid,params.gid_count))
|
||||
goto exiterr;
|
||||
#ifdef __linux__
|
||||
if (!dropcaps())
|
||||
@@ -2179,6 +2190,6 @@ exiterr:
|
||||
if (Fpid) fclose(Fpid);
|
||||
redir_close();
|
||||
for(i=0;i<=params.binds_last;i++) if (listen_fd[i]!=-1) close(listen_fd[i]);
|
||||
cleanup_params();
|
||||
cleanup_params(¶ms);
|
||||
return exit_v;
|
||||
}
|
||||
|
@@ -495,7 +495,7 @@ static bool connect_remote_conn(tproxy_conn_t *conn)
|
||||
int mss=0;
|
||||
|
||||
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");
|
||||
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)
|
||||
{
|
||||
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;
|
||||
if (!conn->track.b_host_matches)
|
||||
{
|
||||
|
Reference in New Issue
Block a user