Compare commits

..

36 Commits

Author SHA1 Message Date
NewUse
5fe319e65c
Merge branch 'bol-van:master' into tpws-minimal 2024-10-15 20:24:21 +03:00
bol-van
97a36f3c18 readme: add get_refilter*.sh info 2024-10-15 15:18:58 +03:00
bol-van
0b2796c6da ipset: refilter scripts 2024-10-15 14:55:16 +03:00
bol-van
4628e65917 tpws: move l7proto defs to one place 2024-10-15 13:29:16 +03:00
bol-van
389b8337dc tpws: move l7proto defs to one place 2024-10-15 13:28:38 +03:00
bol-van
59c143ece5 tpws: autohostlist debug log write client and proto info 2024-10-15 11:23:37 +03:00
bol-van
f0957efc57 tpws: fix MSS apply in transparent mode 2024-10-15 10:35:27 +03:00
bol-van
2eb6080cd0 tpws: save some memory by using sockaddr_in64 2024-10-14 22:34:22 +03:00
bol-van
cf4814df57 readme: mark filter is mandatory to avoid deadlocks 2024-10-14 19:56:33 +03:00
bol-van
378f33d613 list-youtube update 2024-10-14 15:24:39 +03:00
bol-van
96f6f86787 list-youtube update 2024-10-14 15:23:03 +03:00
bol-van
bf82344e3b tpws: fix regression 2024-10-14 15:01:53 +03:00
bol-van
f9e24fa0a0 tpws: ipset support 2024-10-14 14:58:31 +03:00
bol-van
ab43cf14cb winws: update ru presets 2024-10-14 09:48:45 +03:00
bol-van
952902dc17 init.d: 50-dht4all,50-quic4all fix wrong QNUM var name 2024-10-13 19:39:45 +03:00
bol-van
d9bd668f6e tpws,nfqws: fix 100% cpu hang on gzipped hostlist with comments 2024-10-13 17:26:25 +03:00
bol-van
e6c918b8a6 init.d: 50-discord adjust port range to 50000-50019 2024-10-13 16:10:55 +03:00
bol-van
4e1d93bf2c init.d: 50-discord zapret_custom_firewall_nft_flush, ports 50000-50019 2024-10-13 13:54:20 +03:00
bol-van
e1ecd8ecb0 init.d: zapret_custom_firewall_nft_flush 2024-10-13 13:51:20 +03:00
bol-van
7b3adeac82 ipt.sh : print_opt adding => inserting 2024-10-13 13:29:55 +03:00
bol-van
6c8e67faab init.d: ignore dirs in custom.d 2024-10-13 13:25:19 +03:00
bol-van
d760093f52
Merge pull request #583 from SashaXser/master
Фиксы от CodeQL
2024-10-12 22:00:29 +03:00
bol-van
d3f540a62b docs/nftables.txt : add mark filter 2024-10-12 21:55:18 +03:00
bol-van
755915a3ba init.d: number pools. FW_EXTRA. nft insert. customs reorder 2024-10-12 21:28:51 +03:00
SashaXser
e64a6bc9a4
Merge pull request #2 from SashaXser/alert-autofix-2
Fix code scanning alert no. 2: Incorrect return-value check for a 'scanf'-like function
2024-10-12 20:49:39 +04:00
SashaXser
fc200ac629
Merge pull request #1 from SashaXser/alert-autofix-1
Fix code scanning alert no. 1: Multiplication result converted to larger type
2024-10-12 20:49:21 +04:00
SashaXser
81ae646c5a
Fix code scanning alert no. 2: Incorrect return-value check for a 'scanf'-like function
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
2024-10-12 20:48:24 +04:00
SashaXser
2f46aec2be
Fix code scanning alert no. 1: Multiplication result converted to larger type
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
2024-10-12 20:47:39 +04:00
bol-van
ebcb86844e readme: multiple custom docs 2024-10-12 13:17:56 +03:00
bol-van
ff85cd8c0c readme: multiple custom docs 2024-10-12 13:17:35 +03:00
bol-van
38fda46b74 discord custom : connbytes 3=>1 2024-10-12 12:52:36 +03:00
bol-van
e8012ee67f init.d: multiple customs 2024-10-12 12:33:06 +03:00
bol-van
bd80daad97 ipset: add missing ZAPRET_RW enabled scripts 2024-10-12 12:26:09 +03:00
bol-van
916895e281 install_bin: write error messages to stderr 2024-10-12 11:58:42 +03:00
bol-van
7ff4214b5b nfqws: fix cutoff limiter 2024-10-12 09:33:01 +03:00
bol-van
2cd6db3ba5 blockcheck: output *WS_EXTRA in summary 2024-10-08 19:27:39 +03:00
71 changed files with 1684 additions and 677 deletions

View File

@ -1,3 +1,13 @@
googlevideo.com googlevideo.com
youtubei.googleapis.com youtubei.googleapis.com
i.ytimg.com ytimg.com
yt3.ggpht.com
yt4.ggpht.com
youtube.com
youtubeembeddedplayer.googleapis.com
ytimg.l.google.com
jnn-pa.googleapis.com
youtube-nocookie.com
youtube-ui.l.google.com
yt-video-upload.l.google.com
wide-youtube.l.google.com

View File

@ -3,5 +3,5 @@ start "zapret: http,https,quic" /min "%~dp0winws.exe" ^
--filter-udp=443 --hostlist="%~dp0list-youtube.txt" --dpi-desync=fake --dpi-desync-repeats=11 --dpi-desync-fake-quic="%~dp0quic_initial_www_google_com.bin" --new ^ --filter-udp=443 --hostlist="%~dp0list-youtube.txt" --dpi-desync=fake --dpi-desync-repeats=11 --dpi-desync-fake-quic="%~dp0quic_initial_www_google_com.bin" --new ^
--filter-udp=443 --dpi-desync=fake --dpi-desync-repeats=11 --new ^ --filter-udp=443 --dpi-desync=fake --dpi-desync-repeats=11 --new ^
--filter-tcp=80 --dpi-desync=fake,split2 --dpi-desync-autottl=2 --dpi-desync-fooling=md5sig --new ^ --filter-tcp=80 --dpi-desync=fake,split2 --dpi-desync-autottl=2 --dpi-desync-fooling=md5sig --new ^
--filter-tcp=443 --hostlist="%~dp0list-youtube.txt" --dpi-desync=fake,split2 --dpi-desync-autottl=2 --dpi-desync-fooling=md5sig --dpi-desync-fake-tls="%~dp0tls_clienthello_www_google_com.bin" --new ^ --filter-tcp=443 --hostlist="%~dp0list-youtube.txt" --dpi-desync=fake,split2 --dpi-desync-repeats=11 --dpi-desync-autottl=2 --dpi-desync-fooling=md5sig --dpi-desync-fake-tls="%~dp0tls_clienthello_www_google_com.bin" --new ^
--dpi-desync=fake,disorder2 --dpi-desync-autottl=2 --dpi-desync-fooling=md5sig --dpi-desync=fake,disorder2 --dpi-desync-autottl=2 --dpi-desync-fooling=md5sig

View File

@ -3,5 +3,5 @@ start "zapret: http,https,quic" /min "%~dp0winws.exe" ^
--filter-udp=443 --hostlist="%~dp0list-youtube.txt" --dpi-desync=fake --dpi-desync-repeats=11 --dpi-desync-fake-quic="%~dp0quic_initial_www_google_com.bin" --new ^ --filter-udp=443 --hostlist="%~dp0list-youtube.txt" --dpi-desync=fake --dpi-desync-repeats=11 --dpi-desync-fake-quic="%~dp0quic_initial_www_google_com.bin" --new ^
--filter-udp=443 --dpi-desync=fake --dpi-desync-repeats=11 --new ^ --filter-udp=443 --dpi-desync=fake --dpi-desync-repeats=11 --new ^
--filter-tcp=80 --dpi-desync=fake,split2 --dpi-desync-autottl=2 --dpi-desync-fooling=md5sig --hostlist-auto="%~dp0autohostlist.txt" --new ^ --filter-tcp=80 --dpi-desync=fake,split2 --dpi-desync-autottl=2 --dpi-desync-fooling=md5sig --hostlist-auto="%~dp0autohostlist.txt" --new ^
--filter-tcp=443 --hostlist="%~dp0list-youtube.txt" --dpi-desync=fake,split2 --dpi-desync-autottl=2 --dpi-desync-fooling=md5sig --dpi-desync-fake-tls="%~dp0tls_clienthello_www_google_com.bin" --new ^ --filter-tcp=443 --hostlist="%~dp0list-youtube.txt" --dpi-desync=fake,split2 --dpi-desync-repeats=11 --dpi-desync-autottl=2 --dpi-desync-fooling=md5sig --dpi-desync-fake-tls="%~dp0tls_clienthello_www_google_com.bin" --new ^
--dpi-desync=fake,disorder2 --dpi-desync-autottl=2 --dpi-desync-fooling=md5sig --hostlist-auto="%~dp0autohostlist.txt" --dpi-desync=fake,disorder2 --dpi-desync-autottl=2 --dpi-desync-fooling=md5sig --hostlist-auto="%~dp0autohostlist.txt"

View File

@ -964,6 +964,8 @@ report_strategy()
# $3 - daemon # $3 - daemon
echo echo
if [ -n "$strategy" ]; then if [ -n "$strategy" ]; then
# trim spaces at the end
strategy="$(echo "$strategy" | xargs)"
echo "!!!!! $1: working strategy found for ipv${IPV} $2 : $3 $strategy !!!!!" echo "!!!!! $1: working strategy found for ipv${IPV} $2 : $3 $strategy !!!!!"
echo echo
report_append "ipv${IPV} $2 $1 : $3 ${WF:+$WF }$strategy" report_append "ipv${IPV} $2 $1 : $3 ${WF:+$WF }$strategy"
@ -1171,6 +1173,7 @@ pktws_check_domain_http_bypass()
local strategy local strategy
pktws_check_domain_http_bypass_ "$@" pktws_check_domain_http_bypass_ "$@"
strategy="${strategy:+$strategy $PKTWS_EXTRA $PKTWS_EXTRA_1 $PKTWS_EXTRA_2 $PKTWS_EXTRA_3 $PKTWS_EXTRA_4 $PKTWS_EXTRA_5 $PKTWS_EXTRA_6 $PKTWS_EXTRA_7 $PKTWS_EXTRA_8 $PKTWS_EXTRA_9}"
report_strategy $1 $3 $PKTWSD report_strategy $1 $3 $PKTWSD
} }
@ -1215,6 +1218,7 @@ pktws_check_domain_http3_bypass()
local strategy local strategy
pktws_check_domain_http3_bypass_ "$@" pktws_check_domain_http3_bypass_ "$@"
strategy="${strategy:+$strategy $PKTWS_EXTRA $PKTWS_EXTRA_1 $PKTWS_EXTRA_2 $PKTWS_EXTRA_3 $PKTWS_EXTRA_4 $PKTWS_EXTRA_5 $PKTWS_EXTRA_6 $PKTWS_EXTRA_7 $PKTWS_EXTRA_8 $PKTWS_EXTRA_9}"
report_strategy $1 $2 $PKTWSD report_strategy $1 $2 $PKTWSD
} }
warn_mss() warn_mss()
@ -1284,6 +1288,7 @@ tpws_check_domain_http_bypass()
local strategy local strategy
tpws_check_domain_http_bypass_ "$@" tpws_check_domain_http_bypass_ "$@"
strategy="${strategy:+$strategy $TPWS_EXTRA $TPWS_EXTRA_1 $TPWS_EXTRA_2 $TPWS_EXTRA_3 $TPWS_EXTRA_4 $TPWS_EXTRA_5 $TPWS_EXTRA_6 $TPWS_EXTRA_7 $TPWS_EXTRA_8 $TPWS_EXTRA_9}"
report_strategy $1 $3 tpws report_strategy $1 $3 tpws
} }

View File

@ -329,6 +329,25 @@ win_process_exists()
tasklist /NH /FI "IMAGENAME eq ${1}.exe" | grep -q "^${1}.exe" tasklist /NH /FI "IMAGENAME eq ${1}.exe" | grep -q "^${1}.exe"
} }
alloc_num()
{
# $1 - source var name
# $2 - target var name
# $3 - min
# $4 - max
local v
eval v="\$$2"
# do not replace existing value
[ -n "$v" ] && return
eval v="\$$1"
[ -n "$v" ] || v=$3
eval $2="$v"
v=$((v + 1))
[ $v -gt $4 ] && v=$3
eval $1="$v"
}
std_ports() std_ports()
{ {
HTTP_PORTS=${HTTP_PORTS:-80} HTTP_PORTS=${HTTP_PORTS:-80}

43
common/custom.sh Normal file
View File

@ -0,0 +1,43 @@
custom_runner()
{
# $1 - function name
# $2+ - params
local n script FUNC=$1
shift
[ -f "$CUSTOM_DIR/custom" ] && {
unset -f $FUNC
. "$CUSTOM_DIR/custom"
existf $FUNC && $FUNC "$@"
}
[ -d "$CUSTOM_DIR/custom.d" ] && {
n=$(ls "$CUSTOM_DIR/custom.d" | wc -c | xargs)
[ "$n" = 0 ] || {
for script in "$CUSTOM_DIR/custom.d/"*; do
[ -f "$script" ] || continue
unset -f $FUNC
. "$script"
existf $FUNC && $FUNC "$@"
done
}
}
}
alloc_tpws_port()
{
# $1 - target var name
alloc_num NUMPOOL_TPWS_PORT $1 910 979
}
alloc_qnum()
{
# $1 - target var name
alloc_num NUMPOOL_QNUM $1 65400 65499
}
alloc_dnum()
{
# alloc daemon number
# $1 - target var name
alloc_num NUMPOOL_DNUM $1 1000 1999
}

View File

@ -3,15 +3,15 @@ readonly ipt_connbytes="-m connbytes --connbytes-dir=original --connbytes-mode=p
ipt() ipt()
{ {
iptables -C "$@" >/dev/null 2>/dev/null || iptables -I "$@" iptables $FW_EXTRA_PRE -C "$@" $FW_EXTRA_POST >/dev/null 2>/dev/null || iptables $FW_EXTRA_PRE -I "$@" $FW_EXTRA_POST
} }
ipta() ipta()
{ {
iptables -C "$@" >/dev/null 2>/dev/null || iptables -A "$@" iptables $FW_EXTRA_PRE -C "$@" $FW_EXTRA_POST >/dev/null 2>/dev/null || iptables $FW_EXTRA_PRE -A "$@" $FW_EXTRA_POST
} }
ipt_del() ipt_del()
{ {
iptables -C "$@" >/dev/null 2>/dev/null && iptables -D "$@" iptables $FW_EXTRA_PRE -C "$@" $FW_EXTRA_POST >/dev/null 2>/dev/null && iptables $FW_EXTRA_PRE -D "$@" $FW_EXTRA_POST
} }
ipt_add_del() ipt_add_del()
{ {
@ -134,7 +134,7 @@ unprepare_tpws_fw()
ipt_print_op() ipt_print_op()
{ {
if [ "$1" = "1" ]; then if [ "$1" = "1" ]; then
echo "Adding ip$4tables rule for $3 : $2" echo "Inserting ip$4tables rule for $3 : $2"
else else
echo "Deleting ip$4tables rule for $3 : $2" echo "Deleting ip$4tables rule for $3 : $2"
fi fi
@ -437,7 +437,7 @@ zapret_do_firewall_rules_ipt()
fi fi
;; ;;
custom) custom)
existf zapret_custom_firewall && zapret_custom_firewall $1 custom_runner zapret_custom_firewall $1
;; ;;
esac esac
} }

View File

@ -199,7 +199,15 @@ nft_add_rule()
# $2,$3,... - rule(s) # $2,$3,... - rule(s)
local chain="$1" local chain="$1"
shift shift
nft add rule inet $ZAPRET_NFT_TABLE $chain "$@" nft add rule inet $ZAPRET_NFT_TABLE $chain $FW_EXTRA_PRE "$@"
}
nft_insert_rule()
{
# $1 - chain
# $2,$3,... - rule(s)
local chain="$1"
shift
nft insert rule inet $ZAPRET_NFT_TABLE $chain $FW_EXTRA_PRE "$@"
} }
nft_add_set_element() nft_add_set_element()
{ {
@ -227,6 +235,7 @@ nft_clean_nfqws_rule()
nft_add_nfqws_flow_exempt_rule() nft_add_nfqws_flow_exempt_rule()
{ {
# $1 - rule (must be all filters in one var) # $1 - rule (must be all filters in one var)
local FW_EXTRA_POST= FW_EXTRA_PRE=
nft_add_rule flow_offload $(nft_clean_nfqws_rule $1) return comment \"direct flow offloading exemption\" nft_add_rule flow_offload $(nft_clean_nfqws_rule $1) return comment \"direct flow offloading exemption\"
# do not need this because of oifname @wanif/@wanif6 filter in forward chain # do not need this because of oifname @wanif/@wanif6 filter in forward chain
#nft_add_rule flow_offload $(nft_reverse_nfqws_rule $1) return comment \"reverse flow offloading exemption\" #nft_add_rule flow_offload $(nft_reverse_nfqws_rule $1) return comment \"reverse flow offloading exemption\"
@ -236,6 +245,7 @@ nft_add_flow_offload_exemption()
# "$1" - rule for ipv4 # "$1" - rule for ipv4
# "$2" - rule for ipv6 # "$2" - rule for ipv6
# "$3" - comment # "$3" - comment
local FW_EXTRA_POST= FW_EXTRA_PRE=
[ "$DISABLE_IPV4" = "1" -o -z "$1" ] || nft_add_rule flow_offload oifname @wanif $1 ip daddr != @nozapret return comment \"$3\" [ "$DISABLE_IPV4" = "1" -o -z "$1" ] || nft_add_rule flow_offload oifname @wanif $1 ip daddr != @nozapret return comment \"$3\"
[ "$DISABLE_IPV6" = "1" -o -z "$2" ] || nft_add_rule flow_offload oifname @wanif6 $2 ip6 daddr != @nozapret6 return comment \"$3\" [ "$DISABLE_IPV6" = "1" -o -z "$2" ] || nft_add_rule flow_offload oifname @wanif6 $2 ip6 daddr != @nozapret6 return comment \"$3\"
} }
@ -399,7 +409,7 @@ nft_only()
nft_print_op() nft_print_op()
{ {
echo "Adding nftables ipv$3 rule for $2 : $1" echo "Inserting nftables ipv$3 rule for $2 : $1"
} }
_nft_fw_tpws4() _nft_fw_tpws4()
{ {
@ -410,8 +420,8 @@ _nft_fw_tpws4()
[ "$DISABLE_IPV4" = "1" -o -z "$1" ] || { [ "$DISABLE_IPV4" = "1" -o -z "$1" ] || {
local filter="$1" port="$2" local filter="$1" port="$2"
nft_print_op "$filter" "tpws (port $2)" 4 nft_print_op "$filter" "tpws (port $2)" 4
nft_add_rule dnat_output skuid != $WS_USER ${3:+oifname @wanif }$filter ip daddr != @nozapret dnat ip to $TPWS_LOCALHOST4:$port nft_insert_rule dnat_output skuid != $WS_USER ${3:+oifname @wanif }$filter ip daddr != @nozapret $FW_EXTRA_POST dnat ip to $TPWS_LOCALHOST4:$port
nft_add_rule dnat_pre iifname @lanif $filter ip daddr != @nozapret dnat ip to $TPWS_LOCALHOST4:$port nft_insert_rule dnat_pre iifname @lanif $filter ip daddr != @nozapret $FW_EXTRA_POST dnat ip to $TPWS_LOCALHOST4:$port
prepare_route_localnet prepare_route_localnet
} }
} }
@ -425,9 +435,9 @@ _nft_fw_tpws6()
[ "$DISABLE_IPV6" = "1" -o -z "$1" ] || { [ "$DISABLE_IPV6" = "1" -o -z "$1" ] || {
local filter="$1" port="$2" DNAT6 i local filter="$1" port="$2" DNAT6 i
nft_print_op "$filter" "tpws (port $port)" 6 nft_print_op "$filter" "tpws (port $port)" 6
nft_add_rule dnat_output skuid != $WS_USER ${4:+oifname @wanif6 }$filter ip6 daddr != @nozapret6 dnat ip6 to [::1]:$port nft_insert_rule dnat_output skuid != $WS_USER ${4:+oifname @wanif6 }$filter ip6 daddr != @nozapret6 $FW_EXTRA_POST dnat ip6 to [::1]:$port
[ -n "$3" ] && { [ -n "$3" ] && {
nft_add_rule dnat_pre $filter ip6 daddr != @nozapret6 dnat ip6 to iifname map @link_local:$port nft_insert_rule dnat_pre $filter ip6 daddr != @nozapret6 $FW_EXTRA_POST dnat ip6 to iifname map @link_local:$port
for i in $3; do for i in $3; do
_dnat6_target $i DNAT6 _dnat6_target $i DNAT6
# can be multiple tpws processes on different ports # can be multiple tpws processes on different ports
@ -476,7 +486,7 @@ _nft_fw_nfqws_post4()
nft_print_op "$filter" "nfqws postrouting (qnum $port)" 4 nft_print_op "$filter" "nfqws postrouting (qnum $port)" 4
rule="${3:+oifname @wanif }$filter ip daddr != @nozapret" rule="${3:+oifname @wanif }$filter ip daddr != @nozapret"
is_postnat && setmark="meta mark set meta mark or $DESYNC_MARK_POSTNAT" is_postnat && setmark="meta mark set meta mark or $DESYNC_MARK_POSTNAT"
nft_add_rule $chain $rule $setmark queue num $port bypass nft_insert_rule $chain $rule $setmark $FW_EXTRA_POST queue num $port bypass
nft_add_nfqws_flow_exempt_rule "$rule" nft_add_nfqws_flow_exempt_rule "$rule"
} }
} }
@ -491,7 +501,7 @@ _nft_fw_nfqws_post6()
nft_print_op "$filter" "nfqws postrouting (qnum $port)" 6 nft_print_op "$filter" "nfqws postrouting (qnum $port)" 6
rule="${3:+oifname @wanif6 }$filter ip6 daddr != @nozapret6" rule="${3:+oifname @wanif6 }$filter ip6 daddr != @nozapret6"
is_postnat && setmark="meta mark set meta mark or $DESYNC_MARK_POSTNAT" is_postnat && setmark="meta mark set meta mark or $DESYNC_MARK_POSTNAT"
nft_add_rule $chain $rule $setmark queue num $port bypass nft_insert_rule $chain $rule $setmark $FW_EXTRA_POST queue num $port bypass
nft_add_nfqws_flow_exempt_rule "$rule" nft_add_nfqws_flow_exempt_rule "$rule"
} }
} }
@ -515,7 +525,7 @@ _nft_fw_nfqws_pre4()
local filter="$1" port="$2" rule local filter="$1" port="$2" rule
nft_print_op "$filter" "nfqws prerouting (qnum $port)" 4 nft_print_op "$filter" "nfqws prerouting (qnum $port)" 4
rule="${3:+iifname @wanif }$filter ip saddr != @nozapret" rule="${3:+iifname @wanif }$filter ip saddr != @nozapret"
nft_add_rule $(get_prechain) $rule queue num $port bypass nft_insert_rule $(get_prechain) $rule $FW_EXTRA_POST queue num $port bypass
} }
} }
_nft_fw_nfqws_pre6() _nft_fw_nfqws_pre6()
@ -528,7 +538,7 @@ _nft_fw_nfqws_pre6()
local filter="$1" port="$2" rule local filter="$1" port="$2" rule
nft_print_op "$filter" "nfqws prerouting (qnum $port)" 6 nft_print_op "$filter" "nfqws prerouting (qnum $port)" 6
rule="${3:+iifname @wanif6 }$filter ip6 saddr != @nozapret6" rule="${3:+iifname @wanif6 }$filter ip6 saddr != @nozapret6"
nft_add_rule $(get_prechain) $rule queue num $port bypass nft_insert_rule $(get_prechain) $rule $FW_EXTRA_POST queue num $port bypass
} }
} }
nft_fw_nfqws_pre() nft_fw_nfqws_pre()
@ -705,7 +715,7 @@ zapret_apply_firewall_rules_nft()
POSTNAT=$POSTNAT_SAVE POSTNAT=$POSTNAT_SAVE
;; ;;
custom) custom)
existf zapret_custom_firewall_nft && zapret_custom_firewall_nft custom_runner zapret_custom_firewall_nft
;; ;;
esac esac
} }
@ -734,6 +744,7 @@ zapret_unapply_firewall_nft()
unprepare_route_localnet unprepare_route_localnet
nft_del_firewall nft_del_firewall
[ "$MODE" = custom ] && custom_runner zapret_custom_firewall_nft_flush
return 0 return 0
} }
zapret_do_firewall_nft() zapret_do_firewall_nft()

View File

@ -106,6 +106,12 @@ pf_anchor_zapret_tables()
eval $tblv="\"\$_tbl\"" eval $tblv="\"\$_tbl\""
} }
pf_nat_reorder_rules()
{
# this is dirty hack to move rdr above route-to
# use only first word as a key and preserve order within a single key
sort -srfk 1,1
}
pf_anchor_port_target() pf_anchor_port_target()
{ {
if [ "$MODE_HTTP" = "1" ] && [ "$MODE_HTTPS" = "1" ]; then if [ "$MODE_HTTP" = "1" ] && [ "$MODE_HTTPS" = "1" ]; then
@ -119,9 +125,17 @@ pf_anchor_port_target()
pf_anchor_zapret_v4_tpws() pf_anchor_zapret_v4_tpws()
{ {
# $1 - port # $1 - tpws listen port
# $2 - rdr ports. defaults are used if empty
local rule port
if [ -n "$2" ]; then
port="{$2}"
else
port=$(pf_anchor_port_target)
fi
local rule port=$(pf_anchor_port_target)
for lan in $IFACE_LAN; do for lan in $IFACE_LAN; do
for t in $tbl; do for t in $tbl; do
echo "rdr on $lan inet proto tcp from any to $t port $port -> 127.0.0.1 port $1" echo "rdr on $lan inet proto tcp from any to $t port $port -> 127.0.0.1 port $1"
@ -144,7 +158,7 @@ pf_anchor_zapret_v4()
{ {
local tbl port local tbl port
[ "$DISABLE_IPV4" = "1" ] || { [ "$DISABLE_IPV4" = "1" ] || {
case $MODE in case "${MODE_OVERRIDE:-$MODE}" in
tpws) tpws)
[ ! "$MODE_HTTP" = "1" ] && [ ! "$MODE_HTTPS" = "1" ] && return [ ! "$MODE_HTTP" = "1" ] && [ ! "$MODE_HTTPS" = "1" ] && return
pf_anchor_zapret_tables tbl zapret-user "$ZIPLIST_USER" zapret "$ZIPLIST" pf_anchor_zapret_tables tbl zapret-user "$ZIPLIST_USER" zapret "$ZIPLIST"
@ -152,16 +166,24 @@ pf_anchor_zapret_v4()
;; ;;
custom) custom)
pf_anchor_zapret_tables tbl zapret-user "$ZIPLIST_USER" zapret "$ZIPLIST" pf_anchor_zapret_tables tbl zapret-user "$ZIPLIST_USER" zapret "$ZIPLIST"
existf zapret_custom_firewall_v4 && zapret_custom_firewall_v4 custom_runner zapret_custom_firewall_v4 | pf_nat_reorder_rules
;; ;;
esac esac
} }
} }
pf_anchor_zapret_v6_tpws() pf_anchor_zapret_v6_tpws()
{ {
# $1 - port # $1 - tpws listen port
# $2 - rdr ports. defaults are used if empty
local rule LL_LAN port
if [ -n "$2" ]; then
port="{$2}"
else
port=$(pf_anchor_port_target)
fi
local LL_LAN rule port=$(pf_anchor_port_target)
# LAN link local is only for router # LAN link local is only for router
for lan in $IFACE_LAN; do for lan in $IFACE_LAN; do
LL_LAN=$(get_ipv6_linklocal $lan) LL_LAN=$(get_ipv6_linklocal $lan)
@ -188,7 +210,7 @@ pf_anchor_zapret_v6()
local tbl port local tbl port
[ "$DISABLE_IPV6" = "1" ] || { [ "$DISABLE_IPV6" = "1" ] || {
case $MODE in case "${MODE_OVERRIDE:-$MODE}" in
tpws) tpws)
[ ! "$MODE_HTTP" = "1" ] && [ ! "$MODE_HTTPS" = "1" ] && return [ ! "$MODE_HTTP" = "1" ] && [ ! "$MODE_HTTPS" = "1" ] && return
pf_anchor_zapret_tables tbl zapret6-user "$ZIPLIST_USER6" zapret6 "$ZIPLIST6" pf_anchor_zapret_tables tbl zapret6-user "$ZIPLIST_USER6" zapret6 "$ZIPLIST6"
@ -196,7 +218,7 @@ pf_anchor_zapret_v6()
;; ;;
custom) custom)
pf_anchor_zapret_tables tbl zapret6-user "$ZIPLIST_USER6" zapret6 "$ZIPLIST6" pf_anchor_zapret_tables tbl zapret6-user "$ZIPLIST_USER6" zapret6 "$ZIPLIST6"
existf zapret_custom_firewall_v6 && zapret_custom_firewall_v6 custom_runner zapret_custom_firewall_v6 | pf_nat_reorder_rules
;; ;;
esac esac
} }

View File

@ -317,3 +317,15 @@ nfqws: multi-strategy
v63: v63:
tpws: multi-strategy tpws: multi-strategy
v64:
blockcheck: warn if dpi bypass software is already running
blockcheck: TPWS_EXTRA, NFQWS_EXTRA
init.d: multiple custom scripts
v65:
init.d: dynamic number allocation for dnum,tpws_port,qnum
init.d: FW_EXTRA_PRE, FW_EXTRA_POST
init.d: zapret_custom_firewall_nft_flush

View File

@ -19,8 +19,8 @@ For dpi desync attack :
nft delete table inet ztest nft delete table inet ztest
nft create table inet ztest nft create table inet ztest
nft add chain inet ztest post "{type filter hook postrouting priority mangle;}" nft add chain inet ztest post "{type filter hook postrouting priority mangle;}"
nft add rule inet ztest post tcp dport "{80,443}" ct original packets 1-12 queue num 200 bypass nft add rule inet ztest post meta mark and 0x40000000 == 0 tcp dport "{80,443}" ct original packets 1-12 queue num 200 bypass
nft add rule inet ztest post udp dport 443 ct original packets 1-4 queue num 200 bypass nft add rule inet ztest post meta mark and 0x40000000 == 0 udp dport 443 ct original packets 1-4 queue num 200 bypass
# auto hostlist with avoiding wrong ACK numbers in RST,ACK packets sent by russian DPI # auto hostlist with avoiding wrong ACK numbers in RST,ACK packets sent by russian DPI
sysctl net.netfilter.nf_conntrack_tcp_be_liberal=1 sysctl net.netfilter.nf_conntrack_tcp_be_liberal=1

View File

@ -97,7 +97,8 @@ Then we can reduce CPU load, refusing to process unnecessary packets.
`iptables -t mangle -I POSTROUTING -o <external_interface> -p tcp --dport 80 -m connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes 1:6 -m mark ! --mark 0x40000000/0x40000000 -m set --match-set zapret dst -j NFQUEUE --queue-num 200 --queue-bypass` `iptables -t mangle -I POSTROUTING -o <external_interface> -p tcp --dport 80 -m connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes 1:6 -m mark ! --mark 0x40000000/0x40000000 -m set --match-set zapret dst -j NFQUEUE --queue-num 200 --queue-bypass`
Mark filter does not allow nfqws-generated packets to enter the queue again. Mark filter does not allow nfqws-generated packets to enter the queue again.
Its necessary to use this filter when also using `connbytes 1:6`. Without it packet ordering can be changed breaking the whole idea. Its necessary to use this filter when also using `connbytes`. Without it packet ordering can be changed breaking the whole idea.
Also if there's huge packet send from nfqws it may deadlock without mark filter.
Some attacks require redirection of incoming packets : Some attacks require redirection of incoming packets :

View File

@ -1,4 +1,4 @@
zapret v.63 zapret v.64
English English
------- -------
@ -464,8 +464,8 @@ mark нужен, чтобы сгенерированный поддельный
чтобы не допустить изменения порядка следования пакетов. Процессинг очереди - процесс отложенный. чтобы не допустить изменения порядка следования пакетов. Процессинг очереди - процесс отложенный.
Если ядро имеет пакеты на отсылку вне очереди - оно их отправляет незамедлительно. Если ядро имеет пакеты на отсылку вне очереди - оно их отправляет незамедлительно.
Изменение правильного порядка следования пакетов при десинхронизации ломает всю идею. Изменение правильного порядка следования пакетов при десинхронизации ломает всю идею.
При отсутствии ограничения на connbytes, атака будет работать и без фильтра по mark. Так же были замечены дедлоки при достаточно большой отсылке пакетов из nfqws и отсутствии mark фильтра.
Но лучше его все же оставить для увеличения скорости. Процесс может зависнуть. Поэтому наличие фильтра по mark в ip/nf tables можно считать обязательным.
Почему --connbytes 1:6 : Почему --connbytes 1:6 :
1 - для работы методов десинхронизации 0-й фазы и wssize 1 - для работы методов десинхронизации 0-й фазы и wssize
@ -981,10 +981,13 @@ Cкрипты с названием get_antifilter_* оперируют спис
9) ipset/get_antifilter_allyouneed.sh. получает лист https://antifilter.download/list/allyouneed.lst. 9) ipset/get_antifilter_allyouneed.sh. получает лист https://antifilter.download/list/allyouneed.lst.
Суммарный список префиксов, созданный из ipsum.lst и subnet.lst. Суммарный список префиксов, созданный из ipsum.lst и subnet.lst.
Все варианты рассмотренных скриптов автоматически создают и заполняют ipset. 10) ipset/get_refilter_ipsum.sh.
Варианты 2-9 дополнительно вызывают вариант 1. Список берется отсюда : https://github.com/1andrevich/Re-filter-lists
10) ipset/get_config.sh. этот скрипт вызывает то, что прописано в переменной GETLIST из файла config Все варианты рассмотренных скриптов автоматически создают и заполняют ipset.
Варианты 2-10 дополнительно вызывают вариант 1.
11) ipset/get_config.sh. этот скрипт вызывает то, что прописано в переменной GETLIST из файла config
Если переменная не определена, то ресолвятся лишь листы для ipset nozapret/nozapret6. Если переменная не определена, то ресолвятся лишь листы для ipset nozapret/nozapret6.
Листы РКН все время изменяются. Возникают новые тенденции. Требования к RAM могут меняться. Листы РКН все время изменяются. Возникают новые тенденции. Требования к RAM могут меняться.
@ -1111,7 +1114,11 @@ ipset/zapret-hosts-users-exclude.txt.gz или ipset/zapret-hosts-users-exclude.
Поддомены учитываются автоматически. Например, строчка "ru" вносит в список "*.ru". Строчка "*.ru" в списке не сработает. Поддомены учитываются автоматически. Например, строчка "ru" вносит в список "*.ru". Строчка "*.ru" в списке не сработает.
Список доменов РКН может быть получен скриптами ipset/get_reestr_hostlist.sh или ipset/get_antizapret_domains.sh Список доменов РКН может быть получен скриптами
ipset/get_reestr_hostlist.sh
ipset/get_antizapret_domains.sh
ipset/get_reestr_resolvable_domains.sh
ipset/get_refilter_domains.sh
- кладется в ipset/zapret-hosts.txt.gz. - кладется в ipset/zapret-hosts.txt.gz.
Чтобы обновить списки, перезапускать nfqws или tpws не нужно. Обновляете файлы, затем даете сигнал HUP. Чтобы обновить списки, перезапускать nfqws или tpws не нужно. Обновляете файлы, затем даете сигнал HUP.
@ -1572,35 +1579,76 @@ nfset-ы принадлежат только одной таблице, след
Вариант custom Вариант custom
-------------- --------------
custom код вынесен в отдельный shell include custom код вынесен в отдельные shell includes.
Поддерживается старый вариант в
/opt/zapret/init.d/sysv/custom /opt/zapret/init.d/sysv/custom
или
/opt/zapret/init.d/openwrt/custom /opt/zapret/init.d/openwrt/custom
/opt/zapret/init.d/macos/custom
Он считается устаревшим. Актуальный вариант - помещать отдельные скрипты там же, но в директорию "custom.d".
Она будет просканирована стандартным образом, т.е. в алфавитном порядке, и каждый скрипт будет применен.
Рядом имеется "custom.d.examples". Это готовые скрипты, которые можно копировать в "custom.d".
Особо стоит отметить "10-inherit-*". Они наследуют стандартные режимы nfqws/tpws/tpws-socks.
Полезно, чтобы не писать код заново. Достаточно лишь скопировать соответствующий файл.
Можно наследовать и более сложным образом.
"10-inherit-tpws4http-nfqws4https" наследует для http tpws, а для https и quic - nfqws.
Нужно свой код вписать в функции : Для linux пишется код в функции
zapret_custom_daemons zapret_custom_daemons
zapret_custom_firewall zapret_custom_firewall
zapret_custom_firewall_nft zapret_custom_firewall_nft
zapret_custom_firewall_nft_flush
В файле custom пишите ваш код, пользуясь хелперами из "functions" или "zapret". Для macos
Смотрите как там сделано добавление iptables или запуск демонов. zapret_custom_daemons
zapret_custom_firewall_v4
zapret_custom_firewall_v6
zapret_custom_daemons поднимает демоны nfqws/tpws в нужном вам количестве и с нужными вам параметрами.
Для систем традиционного linux (sysv) и MacOS в первом параметре передается код операции : 1 = запуск, 0 = останов.
Для openwrt логика останова отсутствует за ненадобностью.
Схема запуска демонов в openwrt отличается - используется procd.
zapret_custom_firewall поднимает и убирает правила iptables.
В первом параметре передается код операции : 1 = запуск, 0 = останов.
zapret_custom_firewall_nft поднимает правила nftables.
Логика останова отсутствует за ненадобностью. Стандартные цепочки zapret удаляются автоматически.
Однако, sets и правила из ваших собственных цепочек не удаляются.
Их нужно подчистить в zapret_custom_firewall_nft_flush.
Если set-ов и собственных цепочек у вас нет, функцию можно не определять или оставить пустой.
Если вам не нужны iptables или nftables - можете не писать соответствующую функцию.
В linux можно использовать локальные переменные FW_EXTRA_PRE и FW_EXTRA_POST.
FW_EXTRA_PRE добавляет код к правилам ip/nf tables до кода, генерируемого функциями-хелперами.
FW_EXTRA_POST добавляет код после.
В linux функции-хелперы добавляют правило в начало цепочек, то есть перед уже имеющимися.
Поэтому специализации должны идти после более общих вариантов.
Поэтому наследования идут с префиксом 10, а остальные custom скрипты с префиксом 50.
Допустим, у вас есть особые правила для IP подсети youtube. Порты те же самые.
Включен и общий обход. Чтобы youtube пошел приоритетом, скрипт должен применяться после
общего обхода.
Для macos правило обратное. Там правила добавляются в конец. Поэтому inherit скрипты
имеют префикс 90.
В macos firewall-функции ничего сами никуда не заносят. Их задача - лишь выдать текст в stdout,
содержащий правила для pf-якоря. Остальное сделает обертка.
Особо обратите внимание на номер демона в функциях "run_daemon" и "do_daemon", номера портов tpws
и очередей nfqueue.
Они должны быть уникальными во всех скриптах. При накладке будет ошибка.
Поэтому используйте функции динамического получения этих значений из пула.
custom скрипты могут использовать переменные из config. Можно помещать в config свои переменные
и задействовать их в скриптах.
Можно использовать функции-хелперы. Они являются частью общего пространства функций shell.
Полезные функции можно взять из примеров скриптов. Так же смотрите "common/*.sh".
Используя хелпер функции, вы избавитесь от необходимости учитывать все возможные случаи Используя хелпер функции, вы избавитесь от необходимости учитывать все возможные случаи
типа наличия/отсутствия ipv6, является ли система роутером, имена интерфейсов, ... типа наличия/отсутствия ipv6, является ли система роутером, имена интерфейсов, ...
Хелперы это учитывают, вам нужно сосредоточиться лишь на фильтрах {ip,nf}tables и Хелперы это учитывают, вам нужно сосредоточиться лишь на фильтрах {ip,nf}tables и
параметрах демонов. параметрах демонов.
Код для openwrt и sysv немного отличается. В sysv нужно обрабатывать и запуск, и остановку демонов.
Запуск это или остановка передается в параметре $1 (0 или 1).
В openwrt за остановку отвечает procd.
Для фаервола кастом пишется отдельно для iptables и nftables. Все очень похоже, но отличается
написание фильтров и названия процедур хелперов. Если вам не нужны iptables или nftables -
можете не писать соответствующую функцию.
Готовый custom скрипт custom-tpws4http-nfqws4https позволяет применить дурение
tpws к http и nfqws к https. При этом поддерживаются установки из config.
Его можно использовать как стартовую точку для написания своих скриптов.
Простая установка Простая установка
----------------- -----------------

View File

@ -1,26 +0,0 @@
# this script is an example describing how to run tpws on a custom port
TPPORT_MY=987
zapret_custom_daemons()
{
# $1 - 1 - run, 0 - stop
local opt="--user=root --port=$TPPORT_MY"
tpws_apply_binds opt
opt="$opt $TPWS_OPT"
filter_apply_hostlist_target opt
filter_apply_suffix opt "$TPWS_OPT_SUFFIX"
do_daemon $1 1 "$TPWS" "$opt"
}
# custom firewall functions echo rules for zapret-v4 and zapret-v6 anchors
# they come after automated table definitions. so you can use <zapret> <zapret6> <zapret-user> ...
zapret_custom_firewall_v4()
{
pf_anchor_zapret_v4_tpws $TPPORT_MY
}
zapret_custom_firewall_v6()
{
pf_anchor_zapret_v6_tpws $TPPORT_MY
}

View File

@ -0,0 +1,31 @@
# this script is an example describing how to run tpws on a custom port
TPWS_OPT_EXTRA=${TPWS_OPT_EXTRA:---split-pos=2}
TPWS_OPT_SUFFIX_EXTRA="${TPWS_OPT_SUFFIX_EXTRA:-}"
DPORTS_EXTRA=${DPORTS_EXTRA:-20443,20444,30000-30009}
alloc_dnum DNUM_EXTRA_TPWS
alloc_tpws_port TPPORT_EXTRA_TPWS
zapret_custom_daemons()
{
# $1 - 1 - run, 0 - stop
local opt="--user=root --port=$TPPORT_EXTRA_TPWS"
tpws_apply_binds opt
opt="$opt $TPWS_OPT_EXTRA"
filter_apply_hostlist_target opt
filter_apply_suffix opt "$TPWS_OPT_SUFFIX_EXTRA"
do_daemon $1 $DNUM_EXTRA_TPWS "$TPWS" "$opt"
}
# custom firewall functions echo rules for zapret-v4 and zapret-v6 anchors
# they come after automated table definitions. so you can use <zapret> <zapret6> <zapret-user> ...
zapret_custom_firewall_v4()
{
pf_anchor_zapret_v4_tpws $TPPORT_EXTRA_TPWS $(replace_char - : $DPORTS_EXTRA)
}
zapret_custom_firewall_v6()
{
pf_anchor_zapret_v6_tpws $TPPORT_EXTRA_TPWS $(replace_char - : $DPORTS_EXTRA)
}

View File

@ -0,0 +1,18 @@
# this custom script applies tpws mode as it would be with MODE=tpws
OVERRIDE=tpws
zapret_custom_daemons()
{
# $1 - 1 - run, 0 - stop
MODE_OVERRIDE=$OVERRIDE zapret_do_daemons $1
}
zapret_custom_firewall_v4()
{
MODE_OVERRIDE=$OVERRIDE pf_anchor_zapret_v4
}
zapret_custom_firewall_v6()
{
MODE_OVERRIDE=$OVERRIDE pf_anchor_zapret_v6
}

View File

@ -0,0 +1,18 @@
# this custom script applies tpws-socks mode as it would be with MODE=tpws-socks
OVERRIDE=tpws-socks
zapret_custom_daemons()
{
# $1 - 1 - run, 0 - stop
MODE_OVERRIDE=$OVERRIDE zapret_do_daemons $1
}
zapret_custom_firewall_v4()
{
MODE_OVERRIDE=$OVERRIDE pf_anchor_zapret_v4
}
zapret_custom_firewall_v6()
{
MODE_OVERRIDE=$OVERRIDE pf_anchor_zapret_v6
}

View File

View File

@ -1,21 +0,0 @@
# this script contain your special code to launch daemons and configure firewall
# use helpers from "functions" file
# in case of upgrade keep this file only, do not modify others
zapret_custom_daemons()
{
# $1 - 1 - run, 0 - stop
:
}
# custom firewall functions echo rules for zapret-v4 and zapret-v6 anchors
# they come after automated table definitions. so you can use <zapret> <zapret6> <zapret-user> ...
zapret_custom_firewall_v4()
{
:
}
zapret_custom_firewall_v6()
{
:
}

View File

@ -7,6 +7,8 @@ ZAPRET_CONFIG=${ZAPRET_CONFIG:-"$ZAPRET_RW/config"}
. "$ZAPRET_BASE/common/base.sh" . "$ZAPRET_BASE/common/base.sh"
. "$ZAPRET_BASE/common/pf.sh" . "$ZAPRET_BASE/common/pf.sh"
. "$ZAPRET_BASE/common/list.sh" . "$ZAPRET_BASE/common/list.sh"
. "$ZAPRET_BASE/common/custom.sh"
CUSTOM_DIR="$ZAPRET_RW/init.d/macos"
IPSET_DIR=$ZAPRET_BASE/ipset IPSET_DIR=$ZAPRET_BASE/ipset
. "$IPSET_DIR/def.sh" . "$IPSET_DIR/def.sh"
@ -184,7 +186,7 @@ zapret_do_daemons()
filter) filter)
;; ;;
custom) custom)
existf zapret_custom_daemons && zapret_custom_daemons $1 custom_runner zapret_custom_daemons $1
;; ;;
*) *)
echo "unsupported MODE=$MODE" echo "unsupported MODE=$MODE"

View File

@ -1,47 +0,0 @@
# this custom script demonstrates how to reuse built-in modes and add something from yourself
MY_TPPORT=$(($TPPORT + 1))
MY_TPWS_OPT="--methodeol --hostcase"
MY_DPORT=81
zapret_custom_daemons()
{
# stop logic is managed by procd
local MODE_OVERRIDE=tpws
local opt
start_daemons_procd
opt="--port=$MY_TPPORT $MY_TPWS_OPT"
filter_apply_hostlist_target opt
run_tpws 100 "$opt"
}
zapret_custom_firewall()
{
# $1 - 1 - run, 0 - stop
local MODE_OVERRIDE=tpws
local f4 f6
zapret_do_firewall_rules_ipt $1
f4="-p tcp --dport $MY_DPORT"
f6=$f4
filter_apply_ipset_target f4 f6
fw_tpws $1 "$f4" "$f6" $MY_TPPORT
}
zapret_custom_firewall_nft()
{
# stop logic is not required
local MODE_OVERRIDE=tpws
local f4 f6
zapret_apply_firewall_rules_nft
f4="tcp dport $MY_DPORT"
f6=$f4
nft_filter_apply_ipset_target f4 f6
nft_fw_tpws "$f4" "$f6" $MY_TPPORT
}

View File

@ -1,69 +0,0 @@
# this custom script demonstrates how to apply tpws to http and nfqws to https
# it preserves config settings : MODE_HTTP, MODE_HTTPS, MODE_FILTER, TPWS_OPT, NFQWS_OPT_DESYNC, NFQWS_OPT_DESYNC_HTTPS
zapret_custom_daemons()
{
# stop logic is managed by procd
local opt
[ "$MODE_HTTP" = "1" ] && {
opt="--port=$TPPORT $TPWS_OPT"
filter_apply_hostlist_target opt
filter_apply_suffix opt "$TPWS_OPT_SUFFIX"
run_tpws 1 "$opt"
}
[ "$MODE_HTTPS" = "1" ] && {
opt="--qnum=$QNUM $NFQWS_OPT_BASE $NFQWS_OPT_DESYNC_HTTPS"
filter_apply_hostlist_target opt
filter_apply_suffix opt "$NFQWS_OPT_DESYNC_HTTPS_SUFFIX"
run_daemon 2 $NFQWS "$opt"
}
}
zapret_custom_firewall()
{
# $1 - 1 - run, 0 - stop
local f4 f6
local first_packet_only="$ipt_connbytes 1:$(first_packets_for_mode)"
local desync="-m mark ! --mark $DESYNC_MARK/$DESYNC_MARK"
[ "$MODE_HTTP" = "1" ] && {
f4="-p tcp -m multiport --dports $HTTP_PORTS_IPT"
f6=$f4
filter_apply_ipset_target f4 f6
fw_tpws $1 "$f4" "$f6" $TPPORT
}
[ "$MODE_HTTPS" = "1" ] && {
f4="-p tcp -m multiport --dports $HTTPS_PORTS_IPT $first_packet_only"
f6=$f4
filter_apply_ipset_target f4 f6
fw_nfqws_post $1 "$f4 $desync" "$f6 $desync" $QNUM
}
}
zapret_custom_firewall_nft()
{
# stop logic is not required
local f4 f6
local first_packet_only="$nft_connbytes 1-$(first_packets_for_mode)"
local desync="mark and $DESYNC_MARK == 0"
[ "$MODE_HTTP" = "1" ] && {
f4="tcp dport {$HTTP_PORTS}"
f6=$f4
nft_filter_apply_ipset_target f4 f6
nft_fw_tpws "$f4" "$f6" $TPPORT
}
[ "$MODE_HTTPS" = "1" ] && {
f4="tcp dport {$HTTPS_PORTS} $first_packet_only"
f6=$f4
nft_filter_apply_ipset_target f4 f6
nft_fw_nfqws_post "$f4 $desync" "$f6 $desync" $QNUM
# for modes that require incoming traffic
nft_fw_reverse_nfqws_rule "$f4" "$f6" $QNUM
}
}

View File

@ -0,0 +1,22 @@
# this custom script applies nfqws mode as it would be with MODE=nfqws
OVERRIDE=nfqws
zapret_custom_daemons()
{
# stop logic is managed by procd
MODE_OVERRIDE=$OVERRIDE start_daemons_procd
}
zapret_custom_firewall()
{
# $1 - 1 - run, 0 - stop
MODE_OVERRIDE=$OVERRIDE zapret_do_firewall_rules_ipt $1
}
zapret_custom_firewall_nft()
{
# stop logic is not required
MODE_OVERRIDE=$OVERRIDE zapret_apply_firewall_rules_nft
}

View File

@ -0,0 +1,22 @@
# this custom script applies tpws mode as it would be with MODE=tpws
OVERRIDE=tpws
zapret_custom_daemons()
{
# stop logic is managed by procd
MODE_OVERRIDE=$OVERRIDE start_daemons_procd
}
zapret_custom_firewall()
{
# $1 - 1 - run, 0 - stop
MODE_OVERRIDE=$OVERRIDE zapret_do_firewall_rules_ipt $1
}
zapret_custom_firewall_nft()
{
# stop logic is not required
MODE_OVERRIDE=$OVERRIDE zapret_apply_firewall_rules_nft
}

View File

@ -0,0 +1,22 @@
# this custom script applies tpws-socks mode as it would be with MODE=tpws-socks
OVERRIDE=tpws-socks
zapret_custom_daemons()
{
# stop logic is managed by procd
MODE_OVERRIDE=$OVERRIDE start_daemons_procd
}
zapret_custom_firewall()
{
# $1 - 1 - run, 0 - stop
MODE_OVERRIDE=$OVERRIDE zapret_do_firewall_rules_ipt $1
}
zapret_custom_firewall_nft()
{
# stop logic is not required
MODE_OVERRIDE=$OVERRIDE zapret_apply_firewall_rules_nft
}

View File

@ -0,0 +1,35 @@
# this custom script demonstrates how to apply tpws to http and nfqws to https and quic
# it's desired that inherited basic rules are low priority to allow specializations and exceptions in other custom scripts
nfqws_tpws_inheritor()
{
# $1 - inherited function
# $2 - 1 - run, 0 - stop
[ "$MODE_HTTP" = "1" ] && {
MODE_OVERRIDE=tpws MODE_HTTPS=0 MODE_QUIC=0 $1 $2
}
[ "$MODE_HTTPS" = "1" -o "$MODE_QUIC" = "1" ] && {
MODE_OVERRIDE=nfqws MODE_HTTP=0 $1 $2
}
}
zapret_custom_daemons()
{
# stop logic is managed by procd
nfqws_tpws_inheritor start_daemons_procd
}
zapret_custom_firewall()
{
# $1 - 1 - run, 0 - stop
nfqws_tpws_inheritor zapret_do_firewall_rules_ipt $1
}
zapret_custom_firewall_nft()
{
# stop logic is not required
nfqws_tpws_inheritor zapret_apply_firewall_rules_nft
}

View File

@ -1,47 +1,38 @@
# this custom script in addition to MODE=nfqws runs desync to DHT packets with udp payload length 101..399 , without ipset/hostlist filtering # this custom script runs desync to DHT packets with udp payload length 101..399 , without ipset/hostlist filtering
# need to add to config : NFQWS_OPT_DESYNC_DHT="--dpi-desync=fake --dpi-desync-ttl=5" # need to add to config : NFQWS_OPT_DESYNC_DHT="--dpi-desync=fake --dpi-desync-ttl=5"
QNUM2=$(($QNUM+20)) alloc_dnum DNUM_DHT4ALL
alloc_qnum QNUM_DHT4ALL
zapret_custom_daemons() zapret_custom_daemons()
{ {
# stop logic is managed by procd # stop logic is managed by procd
local MODE_OVERRIDE=nfqws local opt="--qnum=$QNUM_DHT4ALL $NFQWS_OPT_BASE $NFQWS_OPT_DESYNC_DHT"
local opt run_daemon $DNUM_DHT4ALL $NFQWS "$opt"
start_daemons_procd
opt="--qnum=$QNUM2 $NFQWS_OPT_BASE $NFQWS_OPT_DESYNC_DHT"
run_daemon 100 $NFQWS "$opt"
} }
zapret_custom_firewall() zapret_custom_firewall()
{ {
# $1 - 1 - run, 0 - stop # $1 - 1 - run, 0 - stop
local MODE_OVERRIDE=nfqws
local f uf4 uf6 local f uf4 uf6
local first_packet_only="$ipt_connbytes 1:1" local first_packet_only="$ipt_connbytes 1:1"
local desync="-m mark ! --mark $DESYNC_MARK/$DESYNC_MARK" local desync="-m mark ! --mark $DESYNC_MARK/$DESYNC_MARK"
zapret_do_firewall_rules_ipt $1
f='-p udp -m length --length 109:407 -m u32 --u32' f='-p udp -m length --length 109:407 -m u32 --u32'
uf4='0>>22&0x3C@8>>16=0x6431' uf4='0>>22&0x3C@8>>16=0x6431'
uf6='48>>16=0x6431' uf6='48>>16=0x6431'
fw_nfqws_post $1 "$f $uf4 $desync $first_packet_only" "$f $uf6 $desync $first_packet_only" $QNUM2 fw_nfqws_post $1 "$f $uf4 $desync $first_packet_only" "$f $uf6 $desync $first_packet_only" $QNUM_DHT4ALL
} }
zapret_custom_firewall_nft() zapret_custom_firewall_nft()
{ {
# stop logic is not required # stop logic is not required
local MODE_OVERRIDE=nfqws
local f local f
local first_packet_only="$nft_connbytes 1" local first_packet_only="$nft_connbytes 1"
local desync="mark and $DESYNC_MARK == 0" local desync="mark and $DESYNC_MARK == 0"
zapret_apply_firewall_rules_nft
f="meta length 109-407 meta l4proto udp @th,64,16 0x6431" f="meta length 109-407 meta l4proto udp @th,64,16 0x6431"
nft_fw_nfqws_post "$f $desync $first_packet_only" "$f $desync $first_packet_only" $QNUM2 nft_fw_nfqws_post "$f $desync $first_packet_only" "$f $desync $first_packet_only" $QNUM_DHT4ALL
} }

File diff suppressed because one or more lines are too long

View File

@ -1,47 +1,37 @@
# this custom script in addition to MODE=nfqws runs desync to all QUIC initial packets, without ipset/hostlist filtering # this custom script runs desync to all QUIC initial packets, without ipset/hostlist filtering
# need to add to config : NFQWS_OPT_DESYNC_QUIC="--dpi-desync=fake" # need to add to config : NFQWS_OPT_DESYNC_QUIC="--dpi-desync=fake"
# NOTE : do not use TTL fooling. chromium QUIC engine breaks sessions if TTL expired in transit received # NOTE : do not use TTL fooling. chromium QUIC engine breaks sessions if TTL expired in transit received
QNUM2=$(($QNUM+10)) alloc_dnum DNUM_QUIC4ALL
alloc_qnum QNUM_QUIC4ALL
zapret_custom_daemons() zapret_custom_daemons()
{ {
# $1 - 1 - run, 0 - stop # $1 - 1 - run, 0 - stop
local MODE_OVERRIDE=nfqws local opt="--qnum=$QNUM_QUIC4ALL $NFQWS_OPT_BASE $NFQWS_OPT_DESYNC_QUIC"
local opt run_daemon $DNUM_QUIC4ALL $NFQWS "$opt"
zapret_do_daemons $1
opt="--qnum=$QNUM2 $NFQWS_OPT_BASE $NFQWS_OPT_DESYNC_QUIC"
do_nfqws $1 100 "$opt"
} }
zapret_custom_firewall() zapret_custom_firewall()
{ {
# $1 - 1 - run, 0 - stop # $1 - 1 - run, 0 - stop
local MODE_OVERRIDE=nfqws
local f local f
local first_packets_only="$ipt_connbytes 1:3" local first_packets_only="$ipt_connbytes 1:3"
local desync="-m mark ! --mark $DESYNC_MARK/$DESYNC_MARK" local desync="-m mark ! --mark $DESYNC_MARK/$DESYNC_MARK"
zapret_do_firewall_rules_ipt $1
f="-p udp -m multiport --dports $QUIC_PORTS_IPT" f="-p udp -m multiport --dports $QUIC_PORTS_IPT"
fw_nfqws_post $1 "$f $desync $first_packets_only" "$f $desync $first_packets_only" $QNUM2 fw_nfqws_post $1 "$f $desync $first_packets_only" "$f $desync $first_packets_only" $QNUM_QUIC4ALL
} }
zapret_custom_firewall_nft() zapret_custom_firewall_nft()
{ {
# stop logic is not required # stop logic is not required
local MODE_OVERRIDE=nfqws
local f local f
local first_packets_only="$nft_connbytes 1-3" local first_packets_only="$nft_connbytes 1-3"
local desync="mark and $DESYNC_MARK == 0" local desync="mark and $DESYNC_MARK == 0"
zapret_apply_firewall_rules_nft
f="udp dport {$QUIC_PORTS}" f="udp dport {$QUIC_PORTS}"
nft_fw_nfqws_post "$f $desync $first_packets_only" "$f $desync $first_packets_only" $QNUM2 nft_fw_nfqws_post "$f $desync $first_packets_only" "$f $desync $first_packets_only" $QNUM_QUIC4ALL
} }

View File

View File

@ -1,33 +0,0 @@
# this script contain your special code to launch daemons and configure firewall
# use helpers from "functions" file and "zapret" init script
# in case of upgrade keep this file only, do not modify others
zapret_custom_daemons()
{
# stop logic is managed by procd
# PLACEHOLDER
echo !!! NEED ATTENTION !!!
echo Start daemon\(s\)
echo Study how other sections work
run_daemon 1 /bin/sleep 20
}
zapret_custom_firewall()
{
# $1 - 1 - run, 0 - stop
# PLACEHOLDER
echo !!! NEED ATTENTION !!!
echo Configure iptables for required actions
echo Study how other sections work
}
zapret_custom_firewall_nft()
{
# stop logic is not required
# PLACEHOLDER
echo !!! NEED ATTENTION !!!
echo Configure nftables for required actions
echo Study how other sections work
}

View File

@ -12,6 +12,8 @@ ZAPRET_CONFIG=${ZAPRET_CONFIG:-"$ZAPRET_RW/config"}
. "$ZAPRET_BASE/common/nft.sh" . "$ZAPRET_BASE/common/nft.sh"
. "$ZAPRET_BASE/common/linux_fw.sh" . "$ZAPRET_BASE/common/linux_fw.sh"
. "$ZAPRET_BASE/common/list.sh" . "$ZAPRET_BASE/common/list.sh"
. "$ZAPRET_BASE/common/custom.sh"
CUSTOM_DIR="$ZAPRET_RW/init.d/openwrt"
[ -n "$QNUM" ] || QNUM=200 [ -n "$QNUM" ] || QNUM=200
[ -n "$TPPORT" ] || TPPORT=988 [ -n "$TPPORT" ] || TPPORT=988
@ -27,9 +29,6 @@ LINKLOCAL_WAIT_SEC=5
IPSET_CR="$ZAPRET_BASE/ipset/create_ipset.sh" IPSET_CR="$ZAPRET_BASE/ipset/create_ipset.sh"
CUSTOM_SCRIPT="$ZAPRET_BASE/init.d/openwrt/custom"
[ -f "$CUSTOM_SCRIPT" ] && . "$CUSTOM_SCRIPT"
IPSET_EXCLUDE="-m set ! --match-set nozapret" IPSET_EXCLUDE="-m set ! --match-set nozapret"
IPSET_EXCLUDE6="-m set ! --match-set nozapret6" IPSET_EXCLUDE6="-m set ! --match-set nozapret6"

View File

@ -173,7 +173,7 @@ start_daemons_procd()
} }
;; ;;
custom) custom)
existf zapret_custom_daemons && zapret_custom_daemons $1 custom_runner zapret_custom_daemons $1
;; ;;
esac esac

View File

@ -1,47 +0,0 @@
# this custom script demonstrates how to reuse built-in modes and add something from yourself
MY_TPPORT=$(($TPPORT + 1))
MY_TPWS_OPT="--methodeol --hostcase"
MY_DPORT=81
zapret_custom_daemons()
{
# $1 - 1 - run, 0 - stop
local MODE_OVERRIDE=tpws
local opt
zapret_do_daemons $1
opt="--port=$MY_TPPORT $MY_TPWS_OPT"
filter_apply_hostlist_target opt
do_tpws $1 100 "$opt"
}
zapret_custom_firewall()
{
# $1 - 1 - run, 0 - stop
local MODE_OVERRIDE=tpws
local f4 f6
zapret_do_firewall_rules_ipt $1
f4="-p tcp --dport $MY_DPORT"
f6=$f4
filter_apply_ipset_target f4 f6
fw_tpws $1 "$f4" "$f6" $MY_TPPORT
}
zapret_custom_firewall_nft()
{
# stop logic is not required
local MODE_OVERRIDE=tpws
local f4 f6
zapret_apply_firewall_rules_nft
f4="tcp dport $MY_DPORT"
f6=$f4
nft_filter_apply_ipset_target f4 f6
nft_fw_tpws "$f4" "$f6" $MY_TPPORT
}

View File

@ -1,71 +0,0 @@
# this custom script demonstrates how to apply tpws to http and nfqws to https
# it preserves config settings : MODE_HTTP, MODE_HTTPS, MODE_FILTER, TPWS_OPT, NFQWS_OPT_DESYNC, NFQWS_OPT_DESYNC_HTTPS
zapret_custom_daemons()
{
# $1 - 1 - run, 0 - stop
local opt
[ "$MODE_HTTP" = "1" ] && {
opt="--port=$TPPORT $TPWS_OPT"
filter_apply_hostlist_target opt
filter_apply_suffix opt "$TPWS_OPT_SUFFIX"
do_tpws $1 1 "$opt"
}
[ "$MODE_HTTPS" = "1" ] && {
opt="--qnum=$QNUM $NFQWS_OPT_DESYNC_HTTPS"
filter_apply_hostlist_target opt
filter_apply_suffix opt "$NFQWS_OPT_DESYNC_HTTPS_SUFFIX"
do_nfqws $1 2 "$opt"
}
}
zapret_custom_firewall()
{
# $1 - 1 - run, 0 - stop
local f4 f6
local first_packet_only="$ipt_connbytes 1:$(first_packets_for_mode)"
local desync="-m mark ! --mark $DESYNC_MARK/$DESYNC_MARK"
[ "$MODE_HTTP" = "1" ] && {
f4="-p tcp -m multiport --dports $HTTP_PORTS_IPT"
f6=$f4
filter_apply_ipset_target f4 f6
fw_tpws $1 "$f4" "$f6" $TPPORT
}
[ "$MODE_HTTPS" = "1" ] && {
f4="-p tcp -m multiport --dports $HTTPS_PORTS_IPT $first_packet_only"
f6=$f4
filter_apply_ipset_target f4 f6
fw_nfqws_post $1 "$f4 $desync" "$f6 $desync" $QNUM
# for modes that require incoming traffic
fw_reverse_nfqws_rule $1 "$f4" "$f6" $QNUM
}
}
zapret_custom_firewall_nft()
{
# stop logic is not required
local f4 f6
local first_packet_only="$nft_connbytes 1-$(first_packets_for_mode)"
local desync="mark and $DESYNC_MARK == 0"
[ "$MODE_HTTP" = "1" ] && {
f4="tcp dport {$HTTP_PORTS}"
f6=$f4
nft_filter_apply_ipset_target f4 f6
nft_fw_tpws "$f4" "$f6" $TPPORT
}
[ "$MODE_HTTPS" = "1" ] && {
f4="tcp dport {$HTTPS_PORTS} $first_packet_only"
f6=$f4
nft_filter_apply_ipset_target f4 f6
nft_fw_nfqws_post "$f4 $desync" "$f6 $desync" $QNUM
# for modes that require incoming traffic
nft_fw_reverse_nfqws_rule "$f4" "$f6" $QNUM
}
}

View File

@ -0,0 +1,22 @@
# this custom script applies nfqws mode as it would be with MODE=nfqws
OVERRIDE=nfqws
zapret_custom_daemons()
{
# $1 - 1 - run, 0 - stop
MODE_OVERRIDE=$OVERRIDE zapret_do_daemons $1
}
zapret_custom_firewall()
{
# $1 - 1 - run, 0 - stop
MODE_OVERRIDE=$OVERRIDE zapret_do_firewall_rules_ipt $1
}
zapret_custom_firewall_nft()
{
# stop logic is not required
MODE_OVERRIDE=$OVERRIDE zapret_apply_firewall_rules_nft
}

View File

@ -0,0 +1,22 @@
# this custom script applies tpws mode as it would be with MODE=tpws
OVERRIDE=tpws
zapret_custom_daemons()
{
# $1 - 1 - run, 0 - stop
MODE_OVERRIDE=$OVERRIDE zapret_do_daemons $1
}
zapret_custom_firewall()
{
# $1 - 1 - run, 0 - stop
MODE_OVERRIDE=$OVERRIDE zapret_do_firewall_rules_ipt $1
}
zapret_custom_firewall_nft()
{
# stop logic is not required
MODE_OVERRIDE=$OVERRIDE zapret_apply_firewall_rules_nft
}

View File

@ -0,0 +1,22 @@
# this custom script applies tpws-socks mode as it would be with MODE=tpws-socks
OVERRIDE=tpws-socks
zapret_custom_daemons()
{
# $1 - 1 - run, 0 - stop
MODE_OVERRIDE=$OVERRIDE zapret_do_daemons $1
}
zapret_custom_firewall()
{
# $1 - 1 - run, 0 - stop
MODE_OVERRIDE=$OVERRIDE zapret_do_firewall_rules_ipt $1
}
zapret_custom_firewall_nft()
{
# stop logic is not required
MODE_OVERRIDE=$OVERRIDE zapret_apply_firewall_rules_nft
}

View File

@ -0,0 +1,35 @@
# this custom script demonstrates how to apply tpws to http and nfqws to https and quic
# it's desired that inherited basic rules are low priority to allow specializations and exceptions in other custom scripts
nfqws_tpws_inheritor()
{
# $1 - inherited function
# $2 - 1 - run, 0 - stop
[ "$MODE_HTTP" = "1" ] && {
MODE_OVERRIDE=tpws MODE_HTTPS=0 MODE_QUIC=0 $1 $2
}
[ "$MODE_HTTPS" = "1" -o "$MODE_QUIC" = "1" ] && {
MODE_OVERRIDE=nfqws MODE_HTTP=0 $1 $2
}
}
zapret_custom_daemons()
{
# $1 - 1 - run, 0 - stop
nfqws_tpws_inheritor zapret_do_daemons $1
}
zapret_custom_firewall()
{
# $1 - 1 - run, 0 - stop
nfqws_tpws_inheritor zapret_do_firewall_rules_ipt $1
}
zapret_custom_firewall_nft()
{
# stop logic is not required
nfqws_tpws_inheritor zapret_apply_firewall_rules_nft
}

View File

@ -1,49 +1,39 @@
# this custom script in addition to MODE=nfqws runs desync to DHT packets with udp payload length 101..399 , without ipset/hostlist filtering # this custom script runs desync to DHT packets with udp payload length 101..399 , without ipset/hostlist filtering
# need to add to config : NFQWS_OPT_DESYNC_DHT="--dpi-desync=fake --dpi-desync-ttl=5" # need to add to config : NFQWS_OPT_DESYNC_DHT="--dpi-desync=fake --dpi-desync-ttl=5"
QNUM2=$(($QNUM+20)) alloc_dnum DNUM_DHT4ALL
alloc_qnum QNUM_DHT4ALL
zapret_custom_daemons() zapret_custom_daemons()
{ {
# stop logic is managed by procd # stop logic is managed by procd
local MODE_OVERRIDE=nfqws local opt="--qnum=$QNUM_DHT4ALL $NFQWS_OPT_BASE $NFQWS_OPT_DESYNC_DHT"
local opt do_nfqws $1 $DNUM_DHT4ALL "$opt"
zapret_do_daemons $1
opt="--qnum=$QNUM2 $NFQWS_OPT_BASE $NFQWS_OPT_DESYNC_DHT"
do_nfqws $1 100 "$opt"
} }
zapret_custom_firewall() zapret_custom_firewall()
{ {
# $1 - 1 - run, 0 - stop # $1 - 1 - run, 0 - stop
local MODE_OVERRIDE=nfqws
local f uf4 uf6 local f uf4 uf6
local first_packet_only="$ipt_connbytes 1:1" local first_packet_only="$ipt_connbytes 1:1"
local desync="-m mark ! --mark $DESYNC_MARK/$DESYNC_MARK" local desync="-m mark ! --mark $DESYNC_MARK/$DESYNC_MARK"
zapret_do_firewall_rules_ipt $1
f='-p udp -m length --length 109:407 -m u32 --u32' f='-p udp -m length --length 109:407 -m u32 --u32'
uf4='0>>22&0x3C@8>>16=0x6431' uf4='0>>22&0x3C@8>>16=0x6431'
uf6='48>>16=0x6431' uf6='48>>16=0x6431'
fw_nfqws_post $1 "$f $uf4 $desync $first_packet_only" "$f $uf6 $desync $first_packet_only" $QNUM2 fw_nfqws_post $1 "$f $uf4 $desync $first_packet_only" "$f $uf6 $desync $first_packet_only" $QNUM_DHT4ALL
} }
zapret_custom_firewall_nft() zapret_custom_firewall_nft()
{ {
# stop logic is not required # stop logic is not required
local MODE_OVERRIDE=nfqws
local f local f
local first_packet_only="$nft_connbytes 1" local first_packet_only="$nft_connbytes 1"
local desync="mark and $DESYNC_MARK == 0" local desync="mark and $DESYNC_MARK == 0"
zapret_apply_firewall_rules_nft
f="meta length 109-407 meta l4proto udp @th,64,16 0x6431" f="meta length 109-407 meta l4proto udp @th,64,16 0x6431"
nft_fw_nfqws_post "$f $desync $first_packet_only" "$f $desync $first_packet_only" $QNUM2 nft_fw_nfqws_post "$f $desync $first_packet_only" "$f $desync $first_packet_only" $QNUM_DHT4ALL
} }

File diff suppressed because one or more lines are too long

View File

@ -1,47 +1,37 @@
# this custom script in addition to MODE=nfqws runs desync to all QUIC initial packets, without ipset/hostlist filtering # this custom script runs desync to all QUIC initial packets, without ipset/hostlist filtering
# need to add to config : NFQWS_OPT_DESYNC_QUIC="--dpi-desync=fake" # need to add to config : NFQWS_OPT_DESYNC_QUIC="--dpi-desync=fake"
# NOTE : do not use TTL fooling. chromium QUIC engine breaks sessions if TTL expired in transit received # NOTE : do not use TTL fooling. chromium QUIC engine breaks sessions if TTL expired in transit received
QNUM2=$(($QNUM+10)) alloc_dnum DNUM_QUIC4ALL
alloc_qnum QNUM_QUIC4ALL
zapret_custom_daemons() zapret_custom_daemons()
{ {
# stop logic is managed by procd # $1 - 1 - run, 0 - stop
local MODE_OVERRIDE=nfqws local opt="--qnum=$QNUM_QUIC4ALL $NFQWS_OPT_BASE $NFQWS_OPT_DESYNC_QUIC"
local opt do_nfqws $1 $DNUM_QUIC4ALL "$opt"
start_daemons_procd
opt="--qnum=$QNUM2 $NFQWS_OPT_BASE $NFQWS_OPT_DESYNC_QUIC"
run_daemon 100 $NFQWS "$opt"
} }
zapret_custom_firewall() zapret_custom_firewall()
{ {
# $1 - 1 - run, 0 - stop # $1 - 1 - run, 0 - stop
local MODE_OVERRIDE=nfqws
local f local f
local first_packets_only="$ipt_connbytes 1:3" local first_packets_only="$ipt_connbytes 1:3"
local desync="-m mark ! --mark $DESYNC_MARK/$DESYNC_MARK" local desync="-m mark ! --mark $DESYNC_MARK/$DESYNC_MARK"
zapret_do_firewall_rules_ipt $1
f="-p udp -m multiport --dports $QUIC_PORTS_IPT" f="-p udp -m multiport --dports $QUIC_PORTS_IPT"
fw_nfqws_post $1 "$f $desync $first_packets_only" "$f $desync $first_packets_only" $QNUM2 fw_nfqws_post $1 "$f $desync $first_packets_only" "$f $desync $first_packets_only" $QNUM_QUIC4ALL
} }
zapret_custom_firewall_nft() zapret_custom_firewall_nft()
{ {
# stop logic is not required # stop logic is not required
local MODE_OVERRIDE=nfqws
local f local f
local first_packets_only="$nft_connbytes 1-3" local first_packets_only="$nft_connbytes 1-3"
local desync="mark and $DESYNC_MARK == 0" local desync="mark and $DESYNC_MARK == 0"
zapret_apply_firewall_rules_nft
f="udp dport {$QUIC_PORTS}" f="udp dport {$QUIC_PORTS}"
nft_fw_nfqws_post "$f $desync $first_packets_only" "$f $desync $first_packets_only" $QNUM2 nft_fw_nfqws_post "$f $desync $first_packets_only" "$f $desync $first_packets_only" $QNUM_QUIC4ALL
} }

View File

View File

@ -1,34 +0,0 @@
# this script contain your special code to launch daemons and configure firewall
# use helpers from "functions" file
# in case of upgrade keep this file only, do not modify others
zapret_custom_daemons()
{
# $1 - 1 - run, 0 - stop
# PLACEHOLDER
echo !!! NEED ATTENTION !!!
echo Start daemon\(s\)
echo Study how other sections work
do_daemon $1 1 /bin/sleep 20
}
zapret_custom_firewall()
{
# $1 - 1 - run, 0 - stop
# PLACEHOLDER
echo !!! NEED ATTENTION !!!
echo Configure iptables for required actions
echo Study how other sections work
}
zapret_custom_firewall_nft()
{
# stop logic is not required
# PLACEHOLDER
echo !!! NEED ATTENTION !!!
echo Configure nftables for required actions
echo Study how other sections work
}

View File

@ -12,6 +12,8 @@ ZAPRET_CONFIG=${ZAPRET_CONFIG:-"$ZAPRET_RW/config"}
. "$ZAPRET_BASE/common/nft.sh" . "$ZAPRET_BASE/common/nft.sh"
. "$ZAPRET_BASE/common/linux_fw.sh" . "$ZAPRET_BASE/common/linux_fw.sh"
. "$ZAPRET_BASE/common/list.sh" . "$ZAPRET_BASE/common/list.sh"
. "$ZAPRET_BASE/common/custom.sh"
CUSTOM_DIR="$ZAPRET_RW/init.d/sysv"
user_exists() user_exists()
@ -91,9 +93,6 @@ TPWS_OPT_BASE6_PRE="--bind-linklocal=prefer $TPWS_WAIT --bind-wait-ip-linklocal=
# max wait time for the link local ipv6 on the LAN interface # max wait time for the link local ipv6 on the LAN interface
LINKLOCAL_WAIT_SEC=5 LINKLOCAL_WAIT_SEC=5
CUSTOM_SCRIPT="$ZAPRET_BASE/init.d/sysv/custom"
[ -f "$CUSTOM_SCRIPT" ] && . "$CUSTOM_SCRIPT"
IPSET_EXCLUDE="-m set ! --match-set nozapret" IPSET_EXCLUDE="-m set ! --match-set nozapret"
IPSET_EXCLUDE6="-m set ! --match-set nozapret6" IPSET_EXCLUDE6="-m set ! --match-set nozapret6"
@ -341,7 +340,7 @@ zapret_do_daemons()
} }
;; ;;
custom) custom)
existf zapret_custom_daemons && zapret_custom_daemons $1 custom_runner zapret_custom_daemons $1
;; ;;
esac esac

View File

@ -29,11 +29,11 @@ check_dir()
fi fi
[ -n "$out" ] [ -n "$out" ]
else else
echo "$exe is not executable. set proper chmod." echo >&2 "$exe is not executable. set proper chmod."
return 1 return 1
fi fi
else else
echo "$exe is absent" echo >&2 "$exe is absent"
return 2 return 2
fi fi
} }

View File

@ -138,6 +138,15 @@ select_mode_mode()
echo ..edited.. echo ..edited..
done done
} }
[ "$MODE" = custom ] && {
echo
echo "current custom scripts :"
[ -f "$CUSTOM_DIR/custom" ] && echo "legacy custom script $CUSTOM_DIR/custom"
echo "$CUSTOM_DIR/custom.d :"
[ -d "$CUSTOM_DIR/custom.d" ] && ls "$CUSTOM_DIR/custom.d"
echo "Make sure this is ok"
echo
}
} }
select_mode_http() select_mode_http()
{ {
@ -210,10 +219,10 @@ select_getlist()
echo echo
if ask_yes_no $D "do you want to auto download ip/host list"; then if ask_yes_no $D "do you want to auto download ip/host list"; then
if [ "$MODE_FILTER" = "hostlist" ] ; then if [ "$MODE_FILTER" = "hostlist" ] ; then
GETLISTS="get_antizapret_domains.sh get_reestr_resolvable_domains.sh get_reestr_hostlist.sh" GETLISTS="get_refilter_domains.sh get_antizapret_domains.sh get_reestr_resolvable_domains.sh get_reestr_hostlist.sh"
GETLIST_DEF="get_antizapret_domains.sh" GETLIST_DEF="get_antizapret_domains.sh"
else else
GETLISTS="get_user.sh get_antifilter_ip.sh get_antifilter_ipsmart.sh get_antifilter_ipsum.sh get_antifilter_ipresolve.sh get_antifilter_allyouneed.sh get_reestr_resolve.sh get_reestr_preresolved.sh get_reestr_preresolved_smart.sh" GETLISTS="get_user.sh get_refilter_ipsum.sh get_antifilter_ip.sh get_antifilter_ipsmart.sh get_antifilter_ipsum.sh get_antifilter_ipresolve.sh get_antifilter_allyouneed.sh get_reestr_resolve.sh get_reestr_preresolved.sh get_reestr_preresolved_smart.sh"
GETLIST_DEF="get_antifilter_allyouneed.sh" GETLIST_DEF="get_antifilter_allyouneed.sh"
fi fi
ask_list GETLIST "$GETLISTS" "$GETLIST_DEF" && write_config_var GETLIST ask_list GETLIST "$GETLISTS" "$GETLIST_DEF" && write_config_var GETLIST
@ -393,7 +402,7 @@ default_files()
for dir in openwrt sysv macos; do for dir in openwrt sysv macos; do
[ -d "$1/init.d/$dir" ] && { [ -d "$1/init.d/$dir" ] && {
[ -d "$2/init.d/$dir" ] || mkdir -p "$2/init.d/$dir" [ -d "$2/init.d/$dir" ] || mkdir -p "$2/init.d/$dir"
[ -f "$2/init.d/$dir/custom" ] || cp "$1/init.d/$dir/custom.default" "$2/init.d/$dir/custom" [ -d "$2/init.d/$dir/custom.d" ] || mkdir -p "$2/init.d/$dir/custom.d"
} }
done done
} }
@ -453,6 +462,8 @@ files/huawei/E8372/zapret \
files/huawei/E8372/run-zapret-ip \ files/huawei/E8372/run-zapret-ip \
ipset/get_exclude.sh \ ipset/get_exclude.sh \
ipset/clear_lists.sh \ ipset/clear_lists.sh \
ipset/get_refilter_domains.sh \
ipset/get_refilter_ipsum.sh \
ipset/get_antifilter_ipresolve.sh \ ipset/get_antifilter_ipresolve.sh \
ipset/get_reestr_resolvable_domains.sh \ ipset/get_reestr_resolvable_domains.sh \
ipset/get_config.sh \ ipset/get_config.sh \
@ -484,7 +495,11 @@ _backup_settings()
{ {
local i=0 local i=0
for f in "$@"; do for f in "$@"; do
# safety check
[ -z "$f" -o "$f" = "/" ] && continue
[ -f "$ZAPRET_TARGET/$f" ] && cp -f "$ZAPRET_TARGET/$f" "/tmp/zapret-bkp-$i" [ -f "$ZAPRET_TARGET/$f" ] && cp -f "$ZAPRET_TARGET/$f" "/tmp/zapret-bkp-$i"
[ -d "$ZAPRET_TARGET/$f" ] && cp -rf "$ZAPRET_TARGET/$f" "/tmp/zapret-bkp-$i"
i=$(($i+1)) i=$(($i+1))
done done
} }
@ -492,7 +507,14 @@ _restore_settings()
{ {
local i=0 local i=0
for f in "$@"; do for f in "$@"; do
# safety check
[ -z "$f" -o "$f" = "/" ] && continue
[ -f "/tmp/zapret-bkp-$i" ] && mv -f "/tmp/zapret-bkp-$i" "$ZAPRET_TARGET/$f" || rm -f "/tmp/zapret-bkp-$i" [ -f "/tmp/zapret-bkp-$i" ] && mv -f "/tmp/zapret-bkp-$i" "$ZAPRET_TARGET/$f" || rm -f "/tmp/zapret-bkp-$i"
[ -d "/tmp/zapret-bkp-$i" ] && {
[ -d "$ZAPRET_TARGET/$f" ] && rm -r "$ZAPRET_TARGET/$f"
mv -f "/tmp/zapret-bkp-$i" "$ZAPRET_TARGET/$f" || rm -r "/tmp/zapret-bkp-$i"
}
i=$(($i+1)) i=$(($i+1))
done done
} }
@ -500,7 +522,7 @@ backup_restore_settings()
{ {
# $1 - 1 - backup, 0 - restore # $1 - 1 - backup, 0 - restore
local mode=$1 local mode=$1
on_off_function _backup_settings _restore_settings $mode "config" "init.d/sysv/custom" "init.d/openwrt/custom" "init.d/macos/custom" "ipset/zapret-hosts-user.txt" "ipset/zapret-hosts-user-exclude.txt" "ipset/zapret-hosts-user-ipban.txt" "ipset/zapret-hosts-auto.txt" on_off_function _backup_settings _restore_settings $mode "config" "init.d/sysv/custom" "init.d/sysv/custom.d" "init.d/openwrt/custom" "init.d/openwrt/custom.d" "init.d/macos/custom" "init.d/macos/custom.d" "ipset/zapret-hosts-user.txt" "ipset/zapret-hosts-user-exclude.txt" "ipset/zapret-hosts-user-ipban.txt" "ipset/zapret-hosts-auto.txt"
} }
check_location() check_location()
@ -623,6 +645,7 @@ check_dns()
install_systemd() install_systemd()
{ {
INIT_SCRIPT_SRC="$EXEDIR/init.d/sysv/zapret" INIT_SCRIPT_SRC="$EXEDIR/init.d/sysv/zapret"
CUSTOM_DIR="$ZAPRET_RW/init.d/sysv"
check_bins check_bins
require_root require_root
@ -650,6 +673,8 @@ _install_sysv()
{ {
# $1 - install init script # $1 - install init script
CUSTOM_DIR="$ZAPRET_RW/init.d/sysv"
check_bins check_bins
require_root require_root
check_readonly_system check_readonly_system
@ -687,6 +712,7 @@ install_openrc()
install_linux() install_linux()
{ {
INIT_SCRIPT_SRC="$EXEDIR/init.d/sysv/zapret" INIT_SCRIPT_SRC="$EXEDIR/init.d/sysv/zapret"
CUSTOM_DIR="$ZAPRET_RW/init.d/sysv"
check_bins check_bins
require_root require_root
@ -757,6 +783,7 @@ deoffload_openwrt_firewall()
install_openwrt() install_openwrt()
{ {
INIT_SCRIPT_SRC="$EXEDIR/init.d/openwrt/zapret" INIT_SCRIPT_SRC="$EXEDIR/init.d/openwrt/zapret"
CUSTOM_DIR="$ZAPRET_RW/init.d/openwrt"
FW_SCRIPT_SRC="$EXEDIR/init.d/openwrt/firewall.zapret" FW_SCRIPT_SRC="$EXEDIR/init.d/openwrt/firewall.zapret"
OPENWRT_FW_INCLUDE=/etc/firewall.zapret OPENWRT_FW_INCLUDE=/etc/firewall.zapret
OPENWRT_IFACE_HOOK="$EXEDIR/init.d/openwrt/90-zapret" OPENWRT_IFACE_HOOK="$EXEDIR/init.d/openwrt/90-zapret"
@ -829,6 +856,7 @@ macos_fw_reload_trigger_set()
install_macos() install_macos()
{ {
INIT_SCRIPT_SRC="$EXEDIR/init.d/macos/zapret" INIT_SCRIPT_SRC="$EXEDIR/init.d/macos/zapret"
CUSTOM_DIR="$ZAPRET_RW/init.d/macos"
# compile before root # compile before root
check_bins check_bins

View File

@ -4,12 +4,12 @@
# $1=no-update - do not update ipset, only create if its absent # $1=no-update - do not update ipset, only create if its absent
# $1=clear - clear ipset # $1=clear - clear ipset
IPSET_DIR="$(dirname "$0")" EXEDIR="$(dirname "$0")"
IPSET_DIR="$(cd "$IPSET_DIR"; pwd)" EXEDIR="$(cd "$EXEDIR"; pwd)"
. "$IPSET_DIR/def.sh" . "$EXEDIR/def.sh"
. "$IPSET_DIR/../common/fwtype.sh" . "$ZAPRET_BASE/common/fwtype.sh"
. "$IPSET_DIR/../common/nft.sh" . "$ZAPRET_BASE/common/nft.sh"
IPSET_CMD="$TMPDIR/ipset_cmd.txt" IPSET_CMD="$TMPDIR/ipset_cmd.txt"
IPSET_SAVERAM_CHUNK_SIZE=20000 IPSET_SAVERAM_CHUNK_SIZE=20000
@ -119,13 +119,12 @@ nfset_get_script_multi()
local set=$1 nonempty N=1 f local set=$1 nonempty N=1 f
shift shift
# first we need to make sure at least one element exists or nft will fail # first we need to make sure at least one element exists or nft will fail
while : while :
do do
eval f=\$$N eval f=\$$N
[ -n "$f" ] || break [ -n "$f" ] || break
nonempty=$(zzexist "$f" && zzcat "$f" | head -n 1) nonempty=$(zzexist "$f" && zzcat "$f" 2>/dev/null | head -n 1)
[ -n "$nonempty" ] && break [ -n "$nonempty" ] && break
N=$(($N+1)) N=$(($N+1))
done done

View File

@ -1,10 +1,12 @@
[ -n "$IPSET_DIR" ] || { EXEDIR="$(dirname "$0")"
IPSET_DIR="$(dirname "$0")" EXEDIR="$(cd "$EXEDIR"; pwd)"
IPSET_DIR="$(cd "$IPSET_DIR"; pwd)" ZAPRET_BASE=${ZAPRET_BASE:-"$(cd "$EXEDIR/.."; pwd)"}
} ZAPRET_RW=${ZAPRET_RW:-"$ZAPRET_BASE"}
ZAPRET_CONFIG=${ZAPRET_CONFIG:-"$ZAPRET_RW/config"}
IPSET_RW_DIR="$ZAPRET_RW/ipset"
. "$IPSET_DIR/../config" . "$ZAPRET_CONFIG"
. "$IPSET_DIR/../common/base.sh" . "$ZAPRET_BASE/common/base.sh"
[ -z "$TMPDIR" ] && TMPDIR=/tmp [ -z "$TMPDIR" ] && TMPDIR=/tmp
[ -z "$GZIP_LISTS" ] && GZIP_LISTS=1 [ -z "$GZIP_LISTS" ] && GZIP_LISTS=1
@ -21,27 +23,27 @@ ZIPSET=zapret
ZIPSET6=zapret6 ZIPSET6=zapret6
ZIPSET_EXCLUDE=nozapret ZIPSET_EXCLUDE=nozapret
ZIPSET_EXCLUDE6=nozapret6 ZIPSET_EXCLUDE6=nozapret6
ZIPLIST="$IPSET_DIR/zapret-ip.txt" ZIPLIST="$IPSET_RW_DIR/zapret-ip.txt"
ZIPLIST6="$IPSET_DIR/zapret-ip6.txt" ZIPLIST6="$IPSET_RW_DIR/zapret-ip6.txt"
ZIPLIST_EXCLUDE="$IPSET_DIR/zapret-ip-exclude.txt" ZIPLIST_EXCLUDE="$IPSET_RW_DIR/zapret-ip-exclude.txt"
ZIPLIST_EXCLUDE6="$IPSET_DIR/zapret-ip-exclude6.txt" ZIPLIST_EXCLUDE6="$IPSET_RW_DIR/zapret-ip-exclude6.txt"
ZIPLIST_USER="$IPSET_DIR/zapret-ip-user.txt" ZIPLIST_USER="$IPSET_RW_DIR/zapret-ip-user.txt"
ZIPLIST_USER6="$IPSET_DIR/zapret-ip-user6.txt" ZIPLIST_USER6="$IPSET_RW_DIR/zapret-ip-user6.txt"
ZUSERLIST="$IPSET_DIR/zapret-hosts-user.txt" ZUSERLIST="$IPSET_RW_DIR/zapret-hosts-user.txt"
ZHOSTLIST="$IPSET_DIR/zapret-hosts.txt" ZHOSTLIST="$IPSET_RW_DIR/zapret-hosts.txt"
ZIPSET_IPBAN=ipban ZIPSET_IPBAN=ipban
ZIPSET_IPBAN6=ipban6 ZIPSET_IPBAN6=ipban6
ZIPLIST_IPBAN="$IPSET_DIR/zapret-ip-ipban.txt" ZIPLIST_IPBAN="$IPSET_RW_DIR/zapret-ip-ipban.txt"
ZIPLIST_IPBAN6="$IPSET_DIR/zapret-ip-ipban6.txt" ZIPLIST_IPBAN6="$IPSET_RW_DIR/zapret-ip-ipban6.txt"
ZIPLIST_USER_IPBAN="$IPSET_DIR/zapret-ip-user-ipban.txt" ZIPLIST_USER_IPBAN="$IPSET_RW_DIR/zapret-ip-user-ipban.txt"
ZIPLIST_USER_IPBAN6="$IPSET_DIR/zapret-ip-user-ipban6.txt" ZIPLIST_USER_IPBAN6="$IPSET_RW_DIR/zapret-ip-user-ipban6.txt"
ZUSERLIST_IPBAN="$IPSET_DIR/zapret-hosts-user-ipban.txt" ZUSERLIST_IPBAN="$IPSET_RW_DIR/zapret-hosts-user-ipban.txt"
ZUSERLIST_EXCLUDE="$IPSET_DIR/zapret-hosts-user-exclude.txt" ZUSERLIST_EXCLUDE="$IPSET_RW_DIR/zapret-hosts-user-exclude.txt"
[ -n "$IP2NET" ] || IP2NET="$IPSET_DIR/../ip2net/ip2net" [ -n "$IP2NET" ] || IP2NET="$ZAPRET_BASE/ip2net/ip2net"
[ -n "$MDIG" ] || MDIG="$IPSET_DIR/../mdig/mdig" [ -n "$MDIG" ] || MDIG="$ZAPRET_BASE/mdig/mdig"
[ -z "$MDIG_THREADS" ] && MDIG_THREADS=30 [ -z "$MDIG_THREADS" ] && MDIG_THREADS=30

42
ipset/get_refilter_domains.sh Executable file
View File

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

39
ipset/get_refilter_ipsum.sh Executable file
View File

@ -0,0 +1,39 @@
#!/bin/sh
IPSET_DIR="$(dirname "$0")"
IPSET_DIR="$(cd "$IPSET_DIR"; pwd)"
. "$IPSET_DIR/def.sh"
TMPLIST="$TMPDIR/list.txt"
URL="https://github.com/1andrevich/Re-filter-lists/releases/latest/download/ipsum.lst"
dl()
{
# $1 - url
# $2 - file
# $3 - minsize
# $4 - maxsize
curl -L -H "Accept-Encoding: gzip" -k --fail --max-time 60 --connect-timeout 10 --retry 4 --max-filesize $4 -o "$TMPLIST" "$1" ||
{
echo list download failed : $1
exit 2
}
dlsize=$(LANG=C wc -c "$TMPLIST" | xargs | cut -f 1 -d ' ')
if test $dlsize -lt $3; then
echo list is too small : $dlsize bytes. can be bad.
exit 2
fi
# remove DOS EOL \r
zzcat "$TMPLIST" | tr -d '\015' | zz "$2"
rm -f "$TMPLIST"
}
getuser && {
[ "$DISABLE_IPV4" != "1" ] && {
dl "$URL" "$ZIPLIST" 32768 4194304
}
}
"$IPSET_DIR/create_ipset.sh"

View File

@ -630,7 +630,6 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
{ {
dp = ctrack->dp; dp = ctrack->dp;
ctrack_replay = ctrack; ctrack_replay = ctrack;
maybe_cutoff(ctrack, IPPROTO_TCP);
} }
if (dp) if (dp)
DLOG("using cached desync profile %d\n",dp->n); DLOG("using cached desync profile %d\n",dp->n);
@ -648,6 +647,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
DLOG("matching desync profile not found\n"); DLOG("matching desync profile not found\n");
return verdict; return verdict;
} }
maybe_cutoff(ctrack, IPPROTO_TCP);
HostFailPoolPurgeRateLimited(&dp->hostlist_auto_fail_counters); HostFailPoolPurgeRateLimited(&dp->hostlist_auto_fail_counters);
@ -1435,7 +1435,6 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
{ {
dp = ctrack->dp; dp = ctrack->dp;
ctrack_replay = ctrack; ctrack_replay = ctrack;
maybe_cutoff(ctrack, IPPROTO_UDP);
} }
if (dp) if (dp)
DLOG("using cached desync profile %d\n",dp->n); DLOG("using cached desync profile %d\n",dp->n);
@ -1453,6 +1452,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
DLOG("matching desync profile not found\n"); DLOG("matching desync profile not found\n");
return verdict; return verdict;
} }
maybe_cutoff(ctrack, IPPROTO_UDP);
HostFailPoolPurgeRateLimited(&dp->hostlist_auto_fail_counters); HostFailPoolPurgeRateLimited(&dp->hostlist_auto_fail_counters);
//ConntrackPoolDump(&params.conntrack); //ConntrackPoolDump(&params.conntrack);

View File

@ -4,17 +4,27 @@
#include "helpers.h" #include "helpers.h"
// inplace tolower() and add to pool // inplace tolower() and add to pool
static bool addpool(strpool **hostlist, char **s, const char *end) static bool addpool(strpool **hostlist, char **s, const char *end, int *ct)
{ {
char *p; char *p=*s;
// advance until eol lowering all chars // comment line
for (p = *s; p<end && *p && *p!='\r' && *p != '\n'; p++) *p=tolower(*p); if ( *p == '#' || *p == ';' || *p == '/' || *p == '\r' || *p == '\n')
if (!StrPoolAddStrLen(hostlist, *s, p-*s))
{ {
StrPoolDestroy(hostlist); // advance until eol
*hostlist = NULL; for (; p<end && *p && *p!='\r' && *p != '\n'; p++);
return false; }
else
{
// advance until eol lowering all chars
for (; p<end && *p && *p!='\r' && *p != '\n'; p++) *p=tolower(*p);
if (!StrPoolAddStrLen(hostlist, *s, p-*s))
{
StrPoolDestroy(hostlist);
*hostlist = NULL;
return false;
}
(*ct)++;
} }
// advance to the next line // advance to the next line
for (; p<end && (!*p || *p=='\r' || *p=='\n') ; p++); for (; p<end && (!*p || *p=='\r' || *p=='\n') ; p++);
@ -22,7 +32,7 @@ static bool addpool(strpool **hostlist, char **s, const char *end)
return true; return true;
} }
bool AppendHostList(strpool **hostlist, char *filename) bool AppendHostList(strpool **hostlist, const char *filename)
{ {
char *p, *e, s[256], *zbuf; char *p, *e, s[256], *zbuf;
size_t zsize; size_t zsize;
@ -50,14 +60,12 @@ bool AppendHostList(strpool **hostlist, char *filename)
e = zbuf + zsize; e = zbuf + zsize;
while(p<e) while(p<e)
{ {
if ( *p == '#' || *p == ';' || *p == '/' || *p == '\n' ) continue; if (!addpool(hostlist,&p,e,&ct))
if (!addpool(hostlist,&p,e))
{ {
DLOG_ERR("Not enough memory to store host list : %s\n", filename); DLOG_ERR("Not enough memory to store host list : %s\n", filename);
free(zbuf); free(zbuf);
return false; return false;
} }
ct++;
} }
free(zbuf); free(zbuf);
} }
@ -71,17 +79,15 @@ bool AppendHostList(strpool **hostlist, char *filename)
{ {
DLOG_CONDUP("loading plain text list\n"); DLOG_CONDUP("loading plain text list\n");
while (fgets(s, 256, F)) while (fgets(s, sizeof(s), F))
{ {
p = s; p = s;
if ( *p == '#' || *p == ';' || *p == '/' || *p == '\n' ) continue; if (!addpool(hostlist,&p,p+strlen(p),&ct))
if (!addpool(hostlist,&p,p+strlen(p)))
{ {
DLOG_ERR("Not enough memory to store host list : %s\n", filename); DLOG_ERR("Not enough memory to store host list : %s\n", filename);
fclose(F); fclose(F);
return false; return false;
} }
ct++;
} }
fclose(F); fclose(F);
} }

View File

@ -4,7 +4,7 @@
#include "pools.h" #include "pools.h"
#include "params.h" #include "params.h"
bool AppendHostList(strpool **hostlist, char *filename); bool AppendHostList(strpool **hostlist, const char *filename);
bool LoadHostLists(strpool **hostlist, struct str_list_head *file_list); bool LoadHostLists(strpool **hostlist, struct str_list_head *file_list);
bool LoadIncludeHostLists(); bool LoadIncludeHostLists();
bool LoadExcludeHostLists(); bool LoadExcludeHostLists();

View File

@ -11,6 +11,12 @@
#include <time.h> #include <time.h>
#include <sys/stat.h> #include <sys/stat.h>
void rtrim(char *s)
{
if (s)
for (char *p = s + strlen(s) - 1; p >= s && (*p == '\n' || *p == '\r'); p--) *p = '\0';
}
char *strncasestr(const char *s,const char *find, size_t slen) char *strncasestr(const char *s,const char *find, size_t slen)
{ {
char c, sc; char c, sc;
@ -81,7 +87,6 @@ void print_sockaddr(const struct sockaddr *sa)
printf("%s",ip_port); printf("%s",ip_port);
} }
// -1 = error, 0 = not local, 1 = local // -1 = error, 0 = not local, 1 = local
bool check_local_ip(const struct sockaddr *saddr) bool check_local_ip(const struct sockaddr *saddr)
{ {
@ -178,6 +183,10 @@ void sacopy(struct sockaddr_storage *sa_dest, const struct sockaddr *sa)
sa_dest->ss_family = 0; sa_dest->ss_family = 0;
} }
} }
void sa46copy(sockaddr_in46 *sa_dest, const struct sockaddr *sa)
{
sacopy((struct sockaddr_storage*)sa_dest, sa);
}
bool is_localnet(const struct sockaddr *a) bool is_localnet(const struct sockaddr *a)
{ {
@ -287,3 +296,101 @@ bool pf_is_empty(const port_filter *pf)
{ {
return !pf->neg && !pf->from && !pf->to; return !pf->neg && !pf->from && !pf->to;
} }
static void mask_from_preflen6_make(uint8_t plen, struct in6_addr *a)
{
if (plen >= 128)
memset(a->s6_addr,0xFF,16);
else
{
uint8_t n = plen >> 3;
memset(a->s6_addr,0xFF,n);
memset(a->s6_addr+n,0x00,16-n);
a->s6_addr[n] = (uint8_t)(0xFF00 >> (plen & 7));
}
}
struct in6_addr ip6_mask[129];
void mask_from_preflen6_prepare(void)
{
for (int plen=0;plen<=128;plen++) mask_from_preflen6_make(plen, ip6_mask+plen);
}
#if defined(__GNUC__) && !defined(__llvm__)
__attribute__((optimize ("no-strict-aliasing")))
#endif
void ip6_and(const struct in6_addr * restrict a, const struct in6_addr * restrict b, struct in6_addr * restrict result)
{
#ifdef __SIZEOF_INT128__
// gcc and clang have 128 bit int types on some 64-bit archs. take some advantage
*((unsigned __int128*)result->s6_addr) = *((unsigned __int128*)a->s6_addr) & *((unsigned __int128*)b->s6_addr);
#else
((uint64_t*)result->s6_addr)[0] = ((uint64_t*)a->s6_addr)[0] & ((uint64_t*)b->s6_addr)[0];
((uint64_t*)result->s6_addr)[1] = ((uint64_t*)a->s6_addr)[1] & ((uint64_t*)b->s6_addr)[1];
#endif
}
void str_cidr4(char *s, size_t s_len, const struct cidr4 *cidr)
{
char s_ip[16];
*s_ip=0;
inet_ntop(AF_INET, &cidr->addr, s_ip, sizeof(s_ip));
snprintf(s,s_len,cidr->preflen<32 ? "%s/%u" : "%s", s_ip, cidr->preflen);
}
void print_cidr4(const struct cidr4 *cidr)
{
char s[19];
str_cidr4(s,sizeof(s),cidr);
printf("%s",s);
}
void str_cidr6(char *s, size_t s_len, const struct cidr6 *cidr)
{
char s_ip[40];
*s_ip=0;
inet_ntop(AF_INET6, &cidr->addr, s_ip, sizeof(s_ip));
snprintf(s,s_len,cidr->preflen<128 ? "%s/%u" : "%s", s_ip, cidr->preflen);
}
void print_cidr6(const struct cidr6 *cidr)
{
char s[44];
str_cidr6(s,sizeof(s),cidr);
printf("%s",s);
}
bool parse_cidr4(char *s, struct cidr4 *cidr)
{
char *p,d;
bool b;
unsigned int plen;
if ((p = strchr(s, '/')))
{
if (sscanf(p + 1, "%u", &plen)!=1 || plen>32)
return false;
cidr->preflen = (uint8_t)plen;
d=*p; *p=0; // backup char
}
else
cidr->preflen = 32;
b = (inet_pton(AF_INET, s, &cidr->addr)==1);
if (p) *p=d; // restore char
return b;
}
bool parse_cidr6(char *s, struct cidr6 *cidr)
{
char *p,d;
bool b;
unsigned int plen;
if ((p = strchr(s, '/')))
{
if (sscanf(p + 1, "%u", &plen)!=1 || plen>128)
return false;
cidr->preflen = (uint8_t)plen;
d=*p; *p=0; // backup char
}
else
cidr->preflen = 128;
b = (inet_pton(AF_INET6, s, &cidr->addr)==1);
if (p) *p=d; // restore char
return b;
}

View File

@ -8,6 +8,15 @@
#include <stdio.h> #include <stdio.h>
#include <time.h> #include <time.h>
// this saves memory. sockaddr_storage is larger than required. it can be 128 bytes. sockaddr_in6 is 28 bytes.
typedef union
{
struct sockaddr_in sa4; // size 16
struct sockaddr_in6 sa6; // size 28
char _align[32]; // force 16-byte alignment for ip6_and int128 ops
} sockaddr_in46;
void rtrim(char *s);
char *strncasestr(const char *s,const char *find, size_t slen); char *strncasestr(const char *s,const char *find, size_t slen);
bool append_to_list_file(const char *filename, const char *s); bool append_to_list_file(const char *filename, const char *s);
@ -26,6 +35,7 @@ uint16_t saport(const struct sockaddr *sa);
bool saconvmapped(struct sockaddr_storage *a); bool saconvmapped(struct sockaddr_storage *a);
void sacopy(struct sockaddr_storage *sa_dest, const struct sockaddr *sa); void sacopy(struct sockaddr_storage *sa_dest, const struct sockaddr *sa);
void sa46copy(sockaddr_in46 *sa_dest, const struct sockaddr *sa);
bool is_localnet(const struct sockaddr *a); bool is_localnet(const struct sockaddr *a);
bool is_linklocal(const struct sockaddr_in6* a); bool is_linklocal(const struct sockaddr_in6* a);
@ -71,3 +81,33 @@ bool pf_is_empty(const port_filter *pf);
#else #else
#define IN6_EXTRACT_MAP4(a) (((const uint32_t *) (a))[3]) #define IN6_EXTRACT_MAP4(a) (((const uint32_t *) (a))[3])
#endif #endif
struct cidr4
{
struct in_addr addr;
uint8_t preflen;
};
struct cidr6
{
struct in6_addr addr;
uint8_t preflen;
};
void str_cidr4(char *s, size_t s_len, const struct cidr4 *cidr);
void print_cidr4(const struct cidr4 *cidr);
void str_cidr6(char *s, size_t s_len, const struct cidr6 *cidr);
void print_cidr6(const struct cidr6 *cidr);
bool parse_cidr4(char *s, struct cidr4 *cidr);
bool parse_cidr6(char *s, struct cidr6 *cidr);
static inline uint32_t mask_from_preflen(uint32_t preflen)
{
return preflen ? preflen<32 ? ~((1 << (32-preflen)) - 1) : 0xFFFFFFFF : 0;
}
void ip6_and(const struct in6_addr * restrict a, const struct in6_addr * restrict b, struct in6_addr * restrict result);
extern struct in6_addr ip6_mask[129];
void mask_from_preflen6_prepare(void);
static inline const struct in6_addr *mask_from_preflen6(uint8_t preflen)
{
return ip6_mask+preflen;
}

View File

@ -5,17 +5,27 @@
#include "helpers.h" #include "helpers.h"
// inplace tolower() and add to pool // inplace tolower() and add to pool
static bool addpool(strpool **hostlist, char **s, const char *end) static bool addpool(strpool **hostlist, char **s, const char *end, int *ct)
{ {
char *p; char *p=*s;
// advance until eol lowering all chars // comment line
for (p = *s; p<end && *p && *p!='\r' && *p != '\n'; p++) *p=tolower(*p); if ( *p == '#' || *p == ';' || *p == '/' || *p == '\r' || *p == '\n')
if (!StrPoolAddStrLen(hostlist, *s, p-*s))
{ {
StrPoolDestroy(hostlist); // advance until eol
*hostlist = NULL; for (; p<end && *p && *p!='\r' && *p != '\n'; p++);
return false; }
else
{
// advance until eol lowering all chars
for (; p<end && *p && *p!='\r' && *p != '\n'; p++) *p=tolower(*p);
if (!StrPoolAddStrLen(hostlist, *s, p-*s))
{
StrPoolDestroy(hostlist);
*hostlist = NULL;
return false;
}
(*ct)++;
} }
// advance to the next line // advance to the next line
for (; p<end && (!*p || *p=='\r' || *p=='\n') ; p++); for (; p<end && (!*p || *p=='\r' || *p=='\n') ; p++);
@ -23,7 +33,7 @@ static bool addpool(strpool **hostlist, char **s, const char *end)
return true; return true;
} }
bool AppendHostList(strpool **hostlist, char *filename) bool AppendHostList(strpool **hostlist, const char *filename)
{ {
char *p, *e, s[256], *zbuf; char *p, *e, s[256], *zbuf;
size_t zsize; size_t zsize;
@ -51,14 +61,12 @@ bool AppendHostList(strpool **hostlist, char *filename)
e = zbuf + zsize; e = zbuf + zsize;
while(p<e) while(p<e)
{ {
if ( *p == '#' || *p == ';' || *p == '/' || *p == '\n' ) continue; if (!addpool(hostlist,&p,e,&ct))
if (!addpool(hostlist,&p,e))
{ {
DLOG_ERR("Not enough memory to store host list : %s\n", filename); DLOG_ERR("Not enough memory to store host list : %s\n", filename);
free(zbuf); free(zbuf);
return false; return false;
} }
ct++;
} }
free(zbuf); free(zbuf);
} }
@ -72,17 +80,15 @@ bool AppendHostList(strpool **hostlist, char *filename)
{ {
DLOG_CONDUP("loading plain text list\n"); DLOG_CONDUP("loading plain text list\n");
while (fgets(s, 256, F)) while (fgets(s, sizeof(s), F))
{ {
p = s; p = s;
if ( *p == '#' || *p == ';' || *p == '/' || *p == '\n' ) continue; if (!addpool(hostlist,&p,p+strlen(p),&ct))
if (!addpool(hostlist,&p,p+strlen(p)))
{ {
DLOG_ERR("Not enough memory to store host list : %s\n", filename); DLOG_ERR("Not enough memory to store host list : %s\n", filename);
fclose(F); fclose(F);
return false; return false;
} }
ct++;
} }
fclose(F); fclose(F);
} }
@ -166,10 +172,9 @@ static bool LoadIncludeHostListsForProfile(struct desync_profile *dp)
return true; return true;
} }
// return : true = apply fooling, false = do not apply
bool HostlistCheck(struct desync_profile *dp, const char *host, bool *excluded) bool HostlistCheck(struct desync_profile *dp, const char *host, bool *excluded)
{ {
VPRINT("* Hostlist check for profile %d\n",dp->n); VPRINT("* hostlist check for profile %d\n",dp->n);
if (*dp->hostlist_auto_filename) if (*dp->hostlist_auto_filename)
{ {
time_t t = file_mod_time(dp->hostlist_auto_filename); time_t t = file_mod_time(dp->hostlist_auto_filename);

View File

@ -4,7 +4,7 @@
#include "pools.h" #include "pools.h"
#include "params.h" #include "params.h"
bool AppendHostList(strpool **hostlist, char *filename); bool AppendHostList(strpool **hostlist, const char *filename);
bool LoadHostLists(strpool **hostlist, struct str_list_head *file_list); bool LoadHostLists(strpool **hostlist, struct str_list_head *file_list);
bool LoadIncludeHostLists(); bool LoadIncludeHostLists();
bool LoadExcludeHostLists(); bool LoadExcludeHostLists();

195
tpws/ipset.c Normal file
View File

@ -0,0 +1,195 @@
#include <stdio.h>
#include "ipset.h"
#include "gzip.h"
#include "helpers.h"
// inplace tolower() and add to pool
static bool addpool(ipset *ips, char **s, const char *end, int *ct)
{
char *p, cidr[128];
size_t l;
struct cidr4 c4;
struct cidr6 c6;
// advance until eol
for (p=*s; p<end && *p && *p!='\r' && *p != '\n'; p++);
// comment line
if (!(**s == '#' || **s == ';' || **s == '/' || **s == '\r' || **s == '\n' ))
{
l = p-*s;
if (l>=sizeof(cidr)) l=sizeof(cidr)-1;
memcpy(cidr,*s,l);
cidr[l]=0;
rtrim(cidr);
if (parse_cidr4(cidr,&c4))
{
if (!ipset4AddCidr(&ips->ips4, &c4))
{
ipsetDestroy(ips);
return false;
}
(*ct)++;
}
else if (parse_cidr6(cidr,&c6))
{
if (!ipset6AddCidr(&ips->ips6, &c6))
{
ipsetDestroy(ips);
return false;
}
(*ct)++;
}
else
DLOG_ERR("bad ip or subnet : %s\n",cidr);
}
// advance to the next line
for (; p<end && (!*p || *p=='\r' || *p=='\n') ; p++);
*s = p;
return true;
}
static bool AppendIpset(ipset *ips, const char *filename)
{
char *p, *e, s[256], *zbuf;
size_t zsize;
int ct = 0;
FILE *F;
int r;
DLOG_CONDUP("Loading ipset %s\n",filename);
if (!(F = fopen(filename, "rb")))
{
DLOG_ERR("Could not open %s\n", filename);
return false;
}
if (is_gzip(F))
{
r = z_readfile(F,&zbuf,&zsize);
fclose(F);
if (r==Z_OK)
{
DLOG_CONDUP("zlib compression detected. uncompressed size : %zu\n", zsize);
p = zbuf;
e = zbuf + zsize;
while(p<e)
{
if (!addpool(ips,&p,e,&ct))
{
DLOG_ERR("Not enough memory to store ipset : %s\n", filename);
free(zbuf);
return false;
}
}
free(zbuf);
}
else
{
DLOG_ERR("zlib decompression failed : result %d\n",r);
return false;
}
}
else
{
DLOG_CONDUP("loading plain text list\n");
while (fgets(s, sizeof(s)-1, F))
{
p = s;
if (!addpool(ips,&p,p+strlen(p),&ct))
{
DLOG_ERR("Not enough memory to store ipset : %s\n", filename);
fclose(F);
return false;
}
}
fclose(F);
}
DLOG_CONDUP("Loaded %d ip/subnets from %s\n", ct, filename);
return true;
}
static bool LoadIpsets(ipset *ips, struct str_list_head *file_list)
{
struct str_list *file;
ipsetDestroy(ips);
LIST_FOREACH(file, file_list, next)
{
if (!AppendIpset(ips, file->str)) return false;
}
return true;
}
bool LoadIncludeIpsets()
{
struct desync_profile_list *dpl;
LIST_FOREACH(dpl, &params.desync_profiles, next)
if (!LoadIpsets(&dpl->dp.ips, &dpl->dp.ipset_files))
return false;
return true;
}
bool LoadExcludeIpsets()
{
struct desync_profile_list *dpl;
LIST_FOREACH(dpl, &params.desync_profiles, next)
if (!LoadIpsets(&dpl->dp.ips_exclude, &dpl->dp.ipset_exclude_files))
return false;
return true;
}
bool SearchIpset(const ipset *ips, const struct in_addr *ipv4, const struct in6_addr *ipv6)
{
char s_ip[40];
bool bInSet=false;
if (!!ipv4 != !!ipv6)
{
*s_ip=0;
if (ipv4)
{
if (params.debug) inet_ntop(AF_INET, ipv4, s_ip, sizeof(s_ip));
if (ips->ips4) bInSet = ipset4Check(ips->ips4, ipv4, 32);
}
if (ipv6)
{
if (params.debug) inet_ntop(AF_INET6, ipv6, s_ip, sizeof(s_ip));
if (ips->ips6) bInSet = ipset6Check(ips->ips6, ipv6, 128);
}
VPRINT("ipset check for %s : %s\n", s_ip, bInSet ? "positive" : "negative");
}
else
// ipv4 and ipv6 are both empty or non-empty
VPRINT("ipset check error !!!!!!!! ipv4=%p ipv6=%p\n",ipv4,ipv6);
return bInSet;
}
static bool IpsetCheck_(const ipset *ips, const ipset *ips_exclude, const struct in_addr *ipv4, const struct in6_addr *ipv6)
{
if (!IPSET_EMPTY(ips_exclude))
{
VPRINT("exclude ");
if (SearchIpset(ips_exclude, ipv4, ipv6))
return false;
}
if (!IPSET_EMPTY(ips))
{
VPRINT("include ");
return SearchIpset(ips, ipv4, ipv6);
}
return true;
}
bool IpsetCheck(struct desync_profile *dp, const struct in_addr *ipv4, const struct in6_addr *ipv6)
{
if (!PROFILE_IPSETS_EMPTY(dp)) VPRINT("* ipset check for profile %d\n",dp->n);
return IpsetCheck_(&dp->ips,&dp->ips_exclude,ipv4,ipv6);
}

11
tpws/ipset.h Normal file
View File

@ -0,0 +1,11 @@
#pragma once
#include <stdbool.h>
#include <arpa/inet.h>
#include "params.h"
#include "pools.h"
bool LoadIncludeIpsets();
bool LoadExcludeIpsets();
bool SearchIpset(const ipset *ips, const struct in_addr *ipv4, const struct in6_addr *ipv6);
bool IpsetCheck(struct desync_profile *dp, const struct in_addr *ipv4, const struct in6_addr *ipv6);

View File

@ -169,8 +169,12 @@ static void dp_entry_destroy(struct desync_profile_list *entry)
{ {
strlist_destroy(&entry->dp.hostlist_files); strlist_destroy(&entry->dp.hostlist_files);
strlist_destroy(&entry->dp.hostlist_exclude_files); strlist_destroy(&entry->dp.hostlist_exclude_files);
strlist_destroy(&entry->dp.ipset_files);
strlist_destroy(&entry->dp.ipset_exclude_files);
StrPoolDestroy(&entry->dp.hostlist_exclude); StrPoolDestroy(&entry->dp.hostlist_exclude);
StrPoolDestroy(&entry->dp.hostlist); StrPoolDestroy(&entry->dp.hostlist);
ipsetDestroy(&entry->dp.ips);
ipsetDestroy(&entry->dp.ips_exclude);
HostFailPoolDestroy(&entry->dp.hostlist_auto_fail_counters); HostFailPoolDestroy(&entry->dp.hostlist_auto_fail_counters);
free(entry); free(entry);
} }

View File

@ -51,6 +51,9 @@ struct desync_profile
bool filter_ipv4,filter_ipv6; bool filter_ipv4,filter_ipv6;
port_filter pf_tcp; port_filter pf_tcp;
uint32_t filter_l7; // L7_PROTO_* bits
ipset ips,ips_exclude;
struct str_list_head ipset_files, ipset_exclude_files;
strpool *hostlist, *hostlist_exclude; strpool *hostlist, *hostlist_exclude;
struct str_list_head hostlist_files, hostlist_exclude_files; struct str_list_head hostlist_files, hostlist_exclude_files;
@ -60,6 +63,8 @@ struct desync_profile
hostfail_pool *hostlist_auto_fail_counters; hostfail_pool *hostlist_auto_fail_counters;
}; };
#define PROFILE_IPSETS_EMPTY(dp) (IPSET_EMPTY(&dp->ips) && IPSET_EMPTY(&dp->ips_exclude))
struct desync_profile_list { struct desync_profile_list {
struct desync_profile dp; struct desync_profile dp;
LIST_ENTRY(desync_profile_list) next; LIST_ENTRY(desync_profile_list) next;

View File

@ -52,6 +52,12 @@ bool StrPoolAddStr(strpool **pp, const char *s)
{ {
return StrPoolAddStrLen(pp, s, strlen(s)); return StrPoolAddStrLen(pp, s, strlen(s));
} }
bool StrPoolAddUniqueStr(strpool **pp,const char *s)
{
if (StrPoolCheckStr(*pp,s))
return true;
return StrPoolAddStr(pp,s);
}
bool StrPoolCheckStr(strpool *p, const char *s) bool StrPoolCheckStr(strpool *p, const char *s)
{ {
@ -151,3 +157,127 @@ void strlist_destroy(struct str_list_head *head)
strlist_entry_destroy(entry); strlist_entry_destroy(entry);
} }
} }
void ipset4Destroy(ipset4 **ipset)
{
ipset4 *elem, *tmp;
HASH_ITER(hh, *ipset, elem, tmp)
{
HASH_DEL(*ipset, elem);
free(elem);
}
}
bool ipset4Check(ipset4 *ipset, const struct in_addr *a, uint8_t preflen)
{
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;
}
bool ipset4Add(ipset4 **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;
}
void ipset4Print(ipset4 *ipset)
{
ipset4 *ips, *tmp;
HASH_ITER(hh, ipset , ips, tmp)
{
print_cidr4(&ips->cidr);
printf("\n");
}
}
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;
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);
printf("\n");
}
}
void ipsetDestroy(ipset *ipset)
{
ipset4Destroy(&ipset->ips4);
ipset6Destroy(&ipset->ips6);
}
void ipsetPrint(ipset *ipset)
{
ipset4Print(ipset->ips4);
ipset6Print(ipset->ips6);
}

View File

@ -5,6 +5,8 @@
#include <sys/queue.h> #include <sys/queue.h>
#include <time.h> #include <time.h>
#include "helpers.h"
//#define HASH_BLOOM 20 //#define HASH_BLOOM 20
#define HASH_NONFATAL_OOM 1 #define HASH_NONFATAL_OOM 1
#define HASH_FUNCTION HASH_BER #define HASH_FUNCTION HASH_BER
@ -17,6 +19,7 @@ typedef struct strpool {
void StrPoolDestroy(strpool **pp); void StrPoolDestroy(strpool **pp);
bool StrPoolAddStr(strpool **pp,const char *s); bool StrPoolAddStr(strpool **pp,const char *s);
bool StrPoolAddUniqueStr(strpool **pp,const char *s);
bool StrPoolAddStrLen(strpool **pp,const char *s,size_t slen); bool StrPoolAddStrLen(strpool **pp,const char *s,size_t slen);
bool StrPoolCheckStr(strpool *p,const char *s); bool StrPoolCheckStr(strpool *p,const char *s);
@ -44,3 +47,41 @@ void HostFailPoolDump(hostfail_pool *p);
bool strlist_add(struct str_list_head *head, const char *filename); bool strlist_add(struct str_list_head *head, const char *filename);
void strlist_destroy(struct str_list_head *head); void strlist_destroy(struct str_list_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;
// combined ipset ipv4 and ipv6
typedef struct ipset {
ipset4 *ips4;
ipset6 *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)
{
return ipset4Add(ipset,&cidr->addr,cidr->preflen);
}
bool ipset4Check(ipset4 *ipset, const struct in_addr *a, uint8_t preflen);
void ipset4Print(ipset4 *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)
{
return ipset6Add(ipset,&cidr->addr,cidr->preflen);
}
bool ipset6Check(ipset6 *ipset, const struct in6_addr *a, uint8_t preflen);
void ipset6Print(ipset6 *ipset);
void ipsetDestroy(ipset *ipset);
void ipsetPrint(ipset *ipset);

View File

@ -103,7 +103,13 @@ static void *resolver_thread(void *arg)
ri->ga_res = getaddrinfo(ri->dom,sport,&hints,&ai); ri->ga_res = getaddrinfo(ri->dom,sport,&hints,&ai);
if (!ri->ga_res) if (!ri->ga_res)
{ {
memcpy(&ri->ss, ai->ai_addr, ai->ai_addrlen); if (ai->ai_addrlen>sizeof(ri->ss))
{
DLOG_ERR("getaddrinfo returned too large address\n");
ri->ga_res = EAI_FAIL;
}
else
memcpy(&ri->ss, ai->ai_addr, ai->ai_addrlen);
freeaddrinfo(ai); freeaddrinfo(ai);
} }
//printf("THREAD %d END JOB %s FIRST=%p\n", syscall(SYS_gettid), ri->dom, TAILQ_FIRST(&resolver.resolve_list)); //printf("THREAD %d END JOB %s FIRST=%p\n", syscall(SYS_gettid), ri->dom, TAILQ_FIRST(&resolver.resolve_list));

View File

@ -6,10 +6,12 @@
#include <sys/socket.h> #include <sys/socket.h>
#include <netdb.h> #include <netdb.h>
#include "helpers.h"
struct resolve_item struct resolve_item
{ {
char dom[256]; // request dom char dom[256]; // request dom
struct sockaddr_storage ss; // resolve result sockaddr_in46 ss; // resolve result
int ga_res; // getaddrinfo result code int ga_res; // getaddrinfo result code
uint16_t port; // request port uint16_t port; // request port
void *ptr; void *ptr;

View File

@ -1,22 +1,50 @@
#define _GNU_SOURCE #define _GNU_SOURCE
#include "tamper.h"
#include "hostlist.h"
#include "protocol.h"
#include "helpers.h"
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include "tamper.h"
#include "hostlist.h"
#include "ipset.h"
#include "protocol.h"
#include "helpers.h"
static bool dp_match_l3l4(struct desync_profile *dp, bool ipv6, uint16_t tcp_port) const char *l7proto_str(t_l7proto l7)
{ {
return \ switch(l7)
((!ipv6 && dp->filter_ipv4) || (ipv6 && dp->filter_ipv6)) &&
(!tcp_port || pf_in_range(tcp_port,&dp->pf_tcp));
}
static bool dp_match(struct desync_profile *dp, bool ipv6, uint16_t tcp_port, const char *hostname)
{
if (dp_match_l3l4(dp,ipv6,tcp_port))
{ {
case HTTP: return "http";
case TLS: return "tls";
default: return "unknown";
}
}
static bool l7_proto_match(t_l7proto l7proto, uint32_t filter_l7)
{
return (l7proto==UNKNOWN && (filter_l7 & L7_PROTO_UNKNOWN)) ||
(l7proto==HTTP && (filter_l7 & L7_PROTO_HTTP)) ||
(l7proto==TLS && (filter_l7 & L7_PROTO_TLS));
}
static bool dp_match_l3l4(struct desync_profile *dp, const struct sockaddr *dest)
{
return ((dest->sa_family==AF_INET && dp->filter_ipv4) || (dest->sa_family==AF_INET6 && dp->filter_ipv6)) &&
pf_in_range(saport(dest), &dp->pf_tcp) &&
IpsetCheck(dp, dest->sa_family==AF_INET ? &((struct sockaddr_in*)dest)->sin_addr : NULL, dest->sa_family==AF_INET6 ? &((struct sockaddr_in6*)dest)->sin6_addr : NULL);
}
static bool dp_impossible(struct desync_profile *dp, const char *hostname, t_l7proto l7proto)
{
return !PROFILE_IPSETS_EMPTY(dp) &&
((dp->filter_l7 && !l7_proto_match(l7proto, dp->filter_l7)) || (!*dp->hostlist_auto_filename && !hostname && (dp->hostlist || dp->hostlist_exclude)));
}
static bool dp_match(struct desync_profile *dp, const struct sockaddr *dest, const char *hostname, t_l7proto l7proto)
{
// impossible case, hard filter
// impossible check avoids relatively slow ipset search
if (!dp_impossible(dp,hostname,l7proto) && dp_match_l3l4(dp,dest))
{
// soft filter
if (dp->filter_l7 && !l7_proto_match(l7proto, dp->filter_l7))
return false;
// autohostlist profile matching l3/l4 filter always win // autohostlist profile matching l3/l4 filter always win
if (*dp->hostlist_auto_filename) return true; if (*dp->hostlist_auto_filename) return true;
@ -32,13 +60,18 @@ static bool dp_match(struct desync_profile *dp, bool ipv6, uint16_t tcp_port, co
} }
return false; return false;
} }
static struct desync_profile *dp_find(struct desync_profile_list_head *head, bool ipv6, uint16_t tcp_port, const char *hostname) static struct desync_profile *dp_find(struct desync_profile_list_head *head, const struct sockaddr *dest, const char *hostname, t_l7proto l7proto)
{ {
struct desync_profile_list *dpl; struct desync_profile_list *dpl;
VPRINT("desync profile search for hostname='%s' ipv6=%u tcp_port=%u\n", hostname ? hostname : "", ipv6, tcp_port); if (params.debug)
{
char ip_port[48];
ntop46_port(dest, ip_port,sizeof(ip_port));
VPRINT("desync profile search for tcp target=%s l7proto=%s hostname='%s'\n", ip_port, l7proto_str(l7proto), hostname ? hostname : "");
}
LIST_FOREACH(dpl, head, next) LIST_FOREACH(dpl, head, next)
{ {
if (dp_match(&dpl->dp,ipv6,tcp_port,hostname)) if (dp_match(&dpl->dp,dest,hostname,l7proto))
{ {
VPRINT("desync profile %d matches\n",dpl->dp.n); VPRINT("desync profile %d matches\n",dpl->dp.n);
return &dpl->dp; return &dpl->dp;
@ -49,7 +82,7 @@ static struct desync_profile *dp_find(struct desync_profile_list_head *head, boo
} }
void apply_desync_profile(t_ctrack *ctrack, const struct sockaddr *dest) void apply_desync_profile(t_ctrack *ctrack, const struct sockaddr *dest)
{ {
ctrack->dp = dp_find(&params.desync_profiles, dest->sa_family==AF_INET6, saport(dest), ctrack->hostname); ctrack->dp = dp_find(&params.desync_profiles, dest, ctrack->hostname, ctrack->l7proto);
} }
@ -114,38 +147,54 @@ void tamper_out(t_ctrack *ctrack, const struct sockaddr *dest, uint8_t *segment,
l7proto = UNKNOWN; l7proto = UNKNOWN;
} }
if (ctrack->l7proto==UNKNOWN) ctrack->l7proto=l7proto;
if (bHaveHost) if (bHaveHost)
{
VPRINT("request hostname: %s\n", Host); VPRINT("request hostname: %s\n", Host);
if (!ctrack->hostname) if (ctrack->b_not_act)
{ {
if (!(ctrack->hostname=strdup(Host))) VPRINT("Not acting on this request\n");
{ return;
DLOG_ERR("strdup hostname : out of memory\n"); }
return;
}
struct desync_profile *dp_prev = ctrack->dp; bool bDiscoveredL7 = ctrack->l7proto==UNKNOWN && l7proto!=UNKNOWN;
apply_desync_profile(ctrack, dest); if (bDiscoveredL7)
if (ctrack->dp!=dp_prev) {
VPRINT("desync profile changed by revealed hostname !\n"); VPRINT("discovered l7 protocol\n");
else if (*ctrack->dp->hostlist_auto_filename) ctrack->l7proto=l7proto;
{ }
bool bHostExcluded;
if (!HostlistCheck(ctrack->dp, Host, &bHostExcluded)) bool bDiscoveredHostname = bHaveHost && !ctrack->hostname;
{ if (bDiscoveredHostname)
ctrack->b_ah_check = !bHostExcluded; {
VPRINT("Not acting on this request\n"); VPRINT("discovered hostname\n");
return; if (!(ctrack->hostname=strdup(Host)))
} {
} DLOG_ERR("strdup hostname : out of memory\n");
return;
} }
} }
if (!ctrack->dp) return;
if (bDiscoveredL7 || bDiscoveredHostname)
{
struct desync_profile *dp_prev = ctrack->dp;
apply_desync_profile(ctrack, dest);
if (ctrack->dp!=dp_prev)
VPRINT("desync profile changed by revealed l7 protocol or hostname !\n");
}
if (bDiscoveredHostname && *ctrack->dp->hostlist_auto_filename)
{
bool bHostExcluded;
if (!HostlistCheck(ctrack->dp, Host, &bHostExcluded))
{
ctrack->b_ah_check = !bHostExcluded;
VPRINT("Not acting on this request\n");
ctrack->b_not_act = true;
return;
}
}
if (!ctrack->dp) return;
switch(l7proto) switch(l7proto)
{ {
case HTTP: case HTTP:
@ -326,7 +375,7 @@ void tamper_out(t_ctrack *ctrack, const struct sockaddr *dest, uint8_t *segment,
if (ctrack->dp->oob) *split_flags |= SPLIT_FLAG_OOB; if (ctrack->dp->oob) *split_flags |= SPLIT_FLAG_OOB;
} }
static void auto_hostlist_reset_fail_counter(struct desync_profile *dp, const char *hostname) static void auto_hostlist_reset_fail_counter(struct desync_profile *dp, const char *hostname, const char *client_ip_port, t_l7proto l7proto)
{ {
if (hostname) if (hostname)
{ {
@ -337,12 +386,12 @@ static void auto_hostlist_reset_fail_counter(struct desync_profile *dp, const ch
{ {
HostFailPoolDel(&dp->hostlist_auto_fail_counters, fail_counter); HostFailPoolDel(&dp->hostlist_auto_fail_counters, fail_counter);
VPRINT("auto hostlist (profile %d) : %s : fail counter reset. website is working.\n", dp->n, hostname); VPRINT("auto hostlist (profile %d) : %s : fail counter reset. website is working.\n", dp->n, hostname);
HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : fail counter reset. website is working.", hostname, dp->n); HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : client %s : proto %s : fail counter reset. website is working.", hostname, dp->n, client_ip_port, l7proto_str(l7proto));
} }
} }
} }
static void auto_hostlist_failed(struct desync_profile *dp, const char *hostname) static void auto_hostlist_failed(struct desync_profile *dp, const char *hostname, const char *client_ip_port, t_l7proto l7proto)
{ {
hostfail_pool *fail_counter; hostfail_pool *fail_counter;
@ -358,7 +407,7 @@ static void auto_hostlist_failed(struct desync_profile *dp, const char *hostname
} }
fail_counter->counter++; fail_counter->counter++;
VPRINT("auto hostlist (profile %d) : %s : fail counter %d/%d\n", dp->n , hostname, fail_counter->counter, dp->hostlist_auto_fail_threshold); VPRINT("auto hostlist (profile %d) : %s : fail counter %d/%d\n", dp->n , hostname, fail_counter->counter, dp->hostlist_auto_fail_threshold);
HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : fail counter %d/%d", hostname, dp->n, fail_counter->counter, dp->hostlist_auto_fail_threshold); HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : client %s : proto %s : fail counter %d/%d", hostname, dp->n, client_ip_port, l7proto_str(l7proto), fail_counter->counter, dp->hostlist_auto_fail_threshold);
if (fail_counter->counter >= dp->hostlist_auto_fail_threshold) if (fail_counter->counter >= dp->hostlist_auto_fail_threshold)
{ {
VPRINT("auto hostlist (profile %d) : fail threshold reached. adding %s to auto hostlist\n", dp->n , hostname); VPRINT("auto hostlist (profile %d) : fail threshold reached. adding %s to auto hostlist\n", dp->n , hostname);
@ -369,7 +418,7 @@ static void auto_hostlist_failed(struct desync_profile *dp, const char *hostname
if (!HostlistCheck(dp, hostname, &bExcluded) && !bExcluded) if (!HostlistCheck(dp, hostname, &bExcluded) && !bExcluded)
{ {
VPRINT("auto hostlist (profile %d) : adding %s to %s\n", dp->n, hostname, dp->hostlist_auto_filename); VPRINT("auto hostlist (profile %d) : adding %s to %s\n", dp->n, hostname, dp->hostlist_auto_filename);
HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : adding to %s", hostname, dp->n, dp->hostlist_auto_filename); HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : client %s : proto %s : adding to %s", hostname, dp->n, client_ip_port, l7proto_str(l7proto), dp->hostlist_auto_filename);
if (!StrPoolAddStr(&dp->hostlist, hostname)) if (!StrPoolAddStr(&dp->hostlist, hostname))
{ {
DLOG_ERR("StrPoolAddStr out of memory\n"); DLOG_ERR("StrPoolAddStr out of memory\n");
@ -385,16 +434,22 @@ static void auto_hostlist_failed(struct desync_profile *dp, const char *hostname
else else
{ {
VPRINT("auto hostlist (profile %d) : NOT adding %s\n", dp->n, hostname); VPRINT("auto hostlist (profile %d) : NOT adding %s\n", dp->n, hostname);
HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : NOT adding, duplicate detected", hostname, dp->n); HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : client %s : proto %s : NOT adding, duplicate detected", hostname, dp->n, client_ip_port, l7proto_str(l7proto));
} }
} }
} }
void tamper_in(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,size_t *size) void tamper_in(t_ctrack *ctrack, const struct sockaddr *client, uint8_t *segment,size_t segment_buffer_size,size_t *size)
{ {
DBGPRINT("tamper_in hostname=%s\n", ctrack->hostname);
bool bFail=false; bool bFail=false;
DBGPRINT("tamper_in hostname=%s\n", ctrack->hostname); char client_ip_port[48];
if (*params.hostlist_auto_debuglog)
ntop46_port((struct sockaddr*)client,client_ip_port,sizeof(client_ip_port));
else
*client_ip_port=0;
if (ctrack->dp && ctrack->b_ah_check) if (ctrack->dp && ctrack->b_ah_check)
{ {
@ -409,7 +464,7 @@ void tamper_in(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,siz
if (bFail) if (bFail)
{ {
VPRINT("redirect to another domain detected. possibly DPI redirect.\n"); VPRINT("redirect to another domain detected. possibly DPI redirect.\n");
HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : redirect to another domain", ctrack->hostname, ctrack->dp->n); HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : client %s : proto %s : redirect to another domain", ctrack->hostname, ctrack->dp->n, client_ip_port, l7proto_str(ctrack->l7proto));
} }
else else
VPRINT("local or in-domain redirect detected. it's not a DPI redirect.\n"); VPRINT("local or in-domain redirect detected. it's not a DPI redirect.\n");
@ -419,17 +474,23 @@ void tamper_in(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,siz
// received not http reply. do not monitor this connection anymore // received not http reply. do not monitor this connection anymore
VPRINT("incoming unknown HTTP data detected for hostname %s\n", ctrack->hostname); VPRINT("incoming unknown HTTP data detected for hostname %s\n", ctrack->hostname);
} }
if (bFail) auto_hostlist_failed(ctrack->dp, ctrack->hostname); if (bFail) auto_hostlist_failed(ctrack->dp, ctrack->hostname, client_ip_port, ctrack->l7proto);
} }
if (!bFail) auto_hostlist_reset_fail_counter(ctrack->dp, ctrack->hostname); if (!bFail) auto_hostlist_reset_fail_counter(ctrack->dp, ctrack->hostname, client_ip_port, ctrack->l7proto);
} }
ctrack->bTamperInCutoff = true; ctrack->bTamperInCutoff = true;
} }
void rst_in(t_ctrack *ctrack) void rst_in(t_ctrack *ctrack, const struct sockaddr *client)
{ {
DBGPRINT("rst_in hostname=%s\n", ctrack->hostname); DBGPRINT("rst_in hostname=%s\n", ctrack->hostname);
char client_ip_port[48];
if (*params.hostlist_auto_debuglog)
ntop46_port((struct sockaddr*)client,client_ip_port,sizeof(client_ip_port));
else
*client_ip_port=0;
if (ctrack->dp && ctrack->b_ah_check) if (ctrack->dp && ctrack->b_ah_check)
{ {
HostFailPoolPurgeRateLimited(&ctrack->dp->hostlist_auto_fail_counters); HostFailPoolPurgeRateLimited(&ctrack->dp->hostlist_auto_fail_counters);
@ -437,15 +498,21 @@ void rst_in(t_ctrack *ctrack)
if (!ctrack->bTamperInCutoff && ctrack->hostname) if (!ctrack->bTamperInCutoff && ctrack->hostname)
{ {
VPRINT("incoming RST detected for hostname %s\n", ctrack->hostname); VPRINT("incoming RST detected for hostname %s\n", ctrack->hostname);
HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : incoming RST", ctrack->hostname, ctrack->dp->n); 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); auto_hostlist_failed(ctrack->dp, ctrack->hostname, client_ip_port, ctrack->l7proto);
} }
} }
} }
void hup_out(t_ctrack *ctrack) void hup_out(t_ctrack *ctrack, const struct sockaddr *client)
{ {
DBGPRINT("hup_out hostname=%s\n", ctrack->hostname); DBGPRINT("hup_out hostname=%s\n", ctrack->hostname);
char client_ip_port[48];
if (*params.hostlist_auto_debuglog)
ntop46_port((struct sockaddr*)client,client_ip_port,sizeof(client_ip_port));
else
*client_ip_port=0;
if (ctrack->dp && ctrack->b_ah_check) if (ctrack->dp && ctrack->b_ah_check)
{ {
HostFailPoolPurgeRateLimited(&ctrack->dp->hostlist_auto_fail_counters); HostFailPoolPurgeRateLimited(&ctrack->dp->hostlist_auto_fail_counters);
@ -454,8 +521,8 @@ void hup_out(t_ctrack *ctrack)
{ {
// local leg dropped connection after first request. probably due to timeout. // local leg dropped connection after first request. probably due to timeout.
VPRINT("local leg closed connection after first request (timeout ?). hostname: %s\n", ctrack->hostname); VPRINT("local leg closed connection after first request (timeout ?). hostname: %s\n", ctrack->hostname);
HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : client closed connection without server reply", ctrack->hostname, ctrack->dp->n); 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); auto_hostlist_failed(ctrack->dp, ctrack->hostname, client_ip_port, ctrack->l7proto);
} }
} }
} }

View File

@ -10,13 +10,18 @@
#define SPLIT_FLAG_OOB 0x02 #define SPLIT_FLAG_OOB 0x02
typedef enum {UNKNOWN=0, HTTP, TLS} t_l7proto; typedef enum {UNKNOWN=0, HTTP, TLS} t_l7proto;
#define L7_PROTO_HTTP 1
#define L7_PROTO_TLS 2
#define L7_PROTO_UNKNOWN 0x80000000
const char *l7proto_str(t_l7proto l7);
typedef struct typedef struct
{ {
// common state // common state
t_l7proto l7proto; t_l7proto l7proto;
bool bFirstReplyChecked;
bool bTamperInCutoff; bool bTamperInCutoff;
bool b_ah_check; bool b_ah_check;
bool b_not_act;
char *hostname; char *hostname;
struct desync_profile *dp; // desync profile cache struct desync_profile *dp; // desync profile cache
} t_ctrack; } t_ctrack;
@ -24,8 +29,8 @@ typedef struct
void apply_desync_profile(t_ctrack *ctrack, const struct sockaddr *dest); void apply_desync_profile(t_ctrack *ctrack, const struct sockaddr *dest);
void tamper_out(t_ctrack *ctrack, const struct sockaddr *dest, uint8_t *segment,size_t segment_buffer_size,size_t *size, size_t *split_pos, uint8_t *split_flags); void tamper_out(t_ctrack *ctrack, const struct sockaddr *dest, uint8_t *segment,size_t segment_buffer_size,size_t *size, size_t *split_pos, uint8_t *split_flags);
void tamper_in(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,size_t *size); void tamper_in(t_ctrack *ctrack, const struct sockaddr *client, uint8_t *segment,size_t segment_buffer_size,size_t *size);
// connection reset by remote leg // connection reset by remote leg
void rst_in(t_ctrack *ctrack); void rst_in(t_ctrack *ctrack, const struct sockaddr *client);
// local leg closed connection (timeout waiting response ?) // local leg closed connection (timeout waiting response ?)
void hup_out(t_ctrack *ctrack); void hup_out(t_ctrack *ctrack, const struct sockaddr *client);

View File

@ -33,6 +33,7 @@
#include "tpws_conn.h" #include "tpws_conn.h"
#include "hostlist.h" #include "hostlist.h"
#include "ipset.h"
#include "params.h" #include "params.h"
#include "sec.h" #include "sec.h"
#include "redirect.h" #include "redirect.h"
@ -46,7 +47,7 @@ bool bHup = false;
static void onhup(int sig) static void onhup(int sig)
{ {
printf("HUP received !\n"); printf("HUP received !\n");
printf("Will reload hostlist on next request (if any)\n"); printf("Will reload hostlists and ipsets on next request (if any)\n");
bHup = true; bHup = true;
} }
// should be called in normal execution // should be called in normal execution
@ -54,9 +55,9 @@ void dohup(void)
{ {
if (bHup) if (bHup)
{ {
if (!LoadIncludeHostLists() || !LoadExcludeHostLists()) if (!LoadIncludeHostLists() || !LoadExcludeHostLists() || !LoadIncludeIpsets() || !LoadExcludeIpsets())
{ {
// what will we do without hostlist ?? sure, gonna die // what will we do without hostlist or ipset ?? sure, gonna die
exit(1); exit(1);
} }
bHup = false; bHup = false;
@ -180,6 +181,9 @@ static void exithelp(void)
" --new\t\t\t\t\t; begin new strategy\n" " --new\t\t\t\t\t; begin new strategy\n"
" --filter-l3=ipv4|ipv6\t\t\t; L3 protocol filter. multiple comma separated values allowed.\n" " --filter-l3=ipv4|ipv6\t\t\t; L3 protocol filter. multiple comma separated values allowed.\n"
" --filter-tcp=[~]port1[-port2]\t\t; TCP port filter. ~ means negation\n" " --filter-tcp=[~]port1[-port2]\t\t; TCP port filter. ~ means negation\n"
" --filter-l7=[http|tls|unknown]\t\t; L6-L7 protocol filter. multiple comma separated values allowed.\n"
" --ipset=<filename>\t\t\t; ipset include filter (one ip/CIDR per line, ipv4 and ipv6 accepted, gzip supported, multiple ipsets allowed)\n"
" --ipset-exclude=<filename>\t\t; ipset exclude filter (one ip/CIDR per line, ipv4 and ipv6 accepted, gzip supported, multiple ipsets allowed)\n"
"\nHOSTLIST FILTER:\n" "\nHOSTLIST FILTER:\n"
" --hostlist=<filename>\t\t\t; only act on hosts in the list (one host per line, subdomains auto apply, gzip supported, multiple hostlists allowed)\n" " --hostlist=<filename>\t\t\t; only act on hosts in the list (one host per line, subdomains auto apply, gzip supported, multiple hostlists allowed)\n"
" --hostlist-exclude=<filename>\t\t; do not act on hosts in the list (one host per line, subdomains auto apply, gzip supported, multiple hostlists allowed)\n" " --hostlist-exclude=<filename>\t\t; do not act on hosts in the list (one host per line, subdomains auto apply, gzip supported, multiple hostlists allowed)\n"
@ -317,6 +321,35 @@ static bool wf_make_l3(char *opt, bool *ipv4, bool *ipv6)
return true; return true;
} }
static bool parse_l7_list(char *opt, uint32_t *l7)
{
char *e,*p,c;
for (p=opt,*l7=0 ; p ; )
{
if ((e = strchr(p,',')))
{
c=*e;
*e=0;
}
if (!strcmp(p,"http"))
*l7 |= L7_PROTO_HTTP;
else if (!strcmp(p,"tls"))
*l7 |= L7_PROTO_TLS;
else if (!strcmp(p,"unknown"))
*l7 |= L7_PROTO_UNKNOWN;
else return false;
if (e)
{
*e++=c;
}
p = e;
}
return true;
}
void parse_params(int argc, char *argv[]) void parse_params(int argc, char *argv[])
{ {
int option_index = 0; int option_index = 0;
@ -409,21 +442,24 @@ void parse_params(int argc, char *argv[])
{ "tamper-cutoff",required_argument,0,0 },// optidx=54 { "tamper-cutoff",required_argument,0,0 },// optidx=54
{ "connect-bind-addr",required_argument,0,0 },// optidx=55 { "connect-bind-addr",required_argument,0,0 },// optidx=55
{ "new",no_argument,0,0 }, // optidx=56 { "new",no_argument,0,0 }, // optidx=56
{ "filter-l3",required_argument,0,0 }, // optidx=57 { "filter-l3",required_argument,0,0 }, // optidx=57
{ "filter-tcp",required_argument,0,0 }, // optidx=58 { "filter-tcp",required_argument,0,0 }, // optidx=58
{ "filter-l7",required_argument,0,0 }, // optidx=59
{ "ipset",required_argument,0,0 }, // optidx=60
{ "ipset-exclude",required_argument,0,0 }, // optidx=61
#if defined(__FreeBSD__) #if defined(__FreeBSD__)
{ "enable-pf",no_argument,0,0 },// optidx=59 { "enable-pf",no_argument,0,0 },// optidx=62
#elif defined(__APPLE__) #elif defined(__APPLE__)
{ "local-tcp-user-timeout",required_argument,0,0 },// optidx=59 { "local-tcp-user-timeout",required_argument,0,0 }, // optidx=62
{ "remote-tcp-user-timeout",required_argument,0,0 },// optidx=60 { "remote-tcp-user-timeout",required_argument,0,0 }, // optidx=63
#elif defined(__linux__) #elif defined(__linux__)
{ "local-tcp-user-timeout",required_argument,0,0 },// optidx=59 { "local-tcp-user-timeout",required_argument,0,0 }, // optidx=62
{ "remote-tcp-user-timeout",required_argument,0,0 },// optidx=60 { "remote-tcp-user-timeout",required_argument,0,0 }, // optidx=63
{ "mss",required_argument,0,0 },// optidx=61 { "mss",required_argument,0,0 }, // optidx=64
#ifdef SPLICE_PRESENT #ifdef SPLICE_PRESENT
{ "nosplice",no_argument,0,0 },// optidx=62 { "nosplice",no_argument,0,0 }, // optidx=65
#endif #endif
#endif #endif
{ "hostlist-auto-retrans-threshold",optional_argument,0,0}, // ignored. for nfqws command line compatibility { "hostlist-auto-retrans-threshold",optional_argument,0,0}, // ignored. for nfqws command line compatibility
@ -935,13 +971,36 @@ void parse_params(int argc, char *argv[])
exit_clean(1); exit_clean(1);
} }
break; break;
case 59: /* filter-l7 */
if (!parse_l7_list(optarg,&dp->filter_l7))
{
DLOG_ERR("Invalid l7 filter : %s\n",optarg);
exit_clean(1);
}
break;
case 60: /* ipset */
if (!strlist_add(&dp->ipset_files, optarg))
{
DLOG_ERR("strlist_add failed\n");
exit_clean(1);
}
params.tamper = true;
break;
case 61: /* ipset-exclude */
if (!strlist_add(&dp->ipset_exclude_files, optarg))
{
DLOG_ERR("strlist_add failed\n");
exit_clean(1);
}
params.tamper = true;
break;
#if defined(__FreeBSD__) #if defined(__FreeBSD__)
case 59: /* enable-pf */ case 62: /* enable-pf */
params.pf_enable = true; params.pf_enable = true;
break; break;
#elif defined(__linux__) || defined(__APPLE__) #elif defined(__linux__) || defined(__APPLE__)
case 59: /* local-tcp-user-timeout */ case 62: /* local-tcp-user-timeout */
params.tcp_user_timeout_local = atoi(optarg); params.tcp_user_timeout_local = atoi(optarg);
if (params.tcp_user_timeout_local<0 || params.tcp_user_timeout_local>86400) if (params.tcp_user_timeout_local<0 || params.tcp_user_timeout_local>86400)
{ {
@ -949,7 +1008,7 @@ void parse_params(int argc, char *argv[])
exit_clean(1); exit_clean(1);
} }
break; break;
case 60: /* remote-tcp-user-timeout */ case 63: /* remote-tcp-user-timeout */
params.tcp_user_timeout_remote = atoi(optarg); params.tcp_user_timeout_remote = atoi(optarg);
if (params.tcp_user_timeout_remote<0 || params.tcp_user_timeout_remote>86400) if (params.tcp_user_timeout_remote<0 || params.tcp_user_timeout_remote>86400)
{ {
@ -960,7 +1019,7 @@ void parse_params(int argc, char *argv[])
#endif #endif
#if defined(__linux__) #if defined(__linux__)
case 61: /* mss */ case 64: /* mss */
// this option does not work in any BSD and MacOS. OS may accept but it changes nothing // this option does not work in any BSD and MacOS. OS may accept but it changes nothing
dp->mss = atoi(optarg); dp->mss = atoi(optarg);
if (dp->mss<88 || dp->mss>32767) if (dp->mss<88 || dp->mss>32767)
@ -970,7 +1029,7 @@ void parse_params(int argc, char *argv[])
} }
break; break;
#ifdef SPLICE_PRESENT #ifdef SPLICE_PRESENT
case 62: /* nosplice */ case 65: /* nosplice */
params.nosplice = true; params.nosplice = true;
break; break;
#endif #endif
@ -1021,6 +1080,16 @@ void parse_params(int argc, char *argv[])
DLOG_ERR("Exclude hostlist load failed\n"); DLOG_ERR("Exclude hostlist load failed\n");
exit_clean(1); exit_clean(1);
} }
if (!LoadIncludeIpsets())
{
DLOG_ERR("Include ipset load failed\n");
exit_clean(1);
}
if (!LoadExcludeIpsets())
{
DLOG_ERR("Exclude ipset load failed\n");
exit_clean(1);
}
} }
@ -1087,7 +1156,7 @@ static bool read_system_maxfiles(rlim_t *maxfile)
return false; return false;
n=fscanf(F,"%ju",&um); n=fscanf(F,"%ju",&um);
fclose(F); fclose(F);
if (!n) return false; if (n != 1) return false;
*maxfile = (rlim_t)um; *maxfile = (rlim_t)um;
return true; return true;
#elif defined(BSD) #elif defined(BSD)
@ -1132,7 +1201,7 @@ static bool set_ulimit(void)
// additional 1/2 for unpaired remote legs sending buffers // additional 1/2 for unpaired remote legs sending buffers
// 16 for listen_fd, epoll, hostlist, ... // 16 for listen_fd, epoll, hostlist, ...
#ifdef SPLICE_PRESENT #ifdef SPLICE_PRESENT
fdmax = (params.nosplice ? 2 : (params.tamper && !params.tamper_lim ? 4 : 6)) * params.maxconn; fdmax = (rlim_t)(params.nosplice ? 2 : (params.tamper && !params.tamper_lim ? 4 : 6)) * (rlim_t)params.maxconn;
#else #else
fdmax = 2 * params.maxconn; fdmax = 2 * params.maxconn;
#endif #endif
@ -1177,6 +1246,8 @@ int main(int argc, char *argv[])
char ip_port[48]; char ip_port[48];
srand(time(NULL)); srand(time(NULL));
mask_from_preflen6_prepare();
parse_params(argc, argv); parse_params(argc, argv);
if (params.daemon) daemonize(); if (params.daemon) daemonize();

View File

@ -569,7 +569,6 @@ static tproxy_conn_t* add_tcp_connection(int efd, struct tailhead *conn_list,int
{ {
struct sockaddr_storage orig_dst; struct sockaddr_storage orig_dst;
tproxy_conn_t *conn; tproxy_conn_t *conn;
int remote_fd=0;
if (proxy_type==CONN_TYPE_TRANSPARENT) if (proxy_type==CONN_TYPE_TRANSPARENT)
{ {
@ -597,19 +596,8 @@ static tproxy_conn_t* add_tcp_connection(int efd, struct tailhead *conn_list,int
return 0; return 0;
} }
if (proxy_type==CONN_TYPE_TRANSPARENT)
{
if ((remote_fd = connect_remote((struct sockaddr *)&orig_dst, 0)) < 0)
{
DLOG_ERR("Failed to connect\n");
close(local_fd);
return NULL;
}
}
if(!(conn = new_conn(local_fd, false))) if(!(conn = new_conn(local_fd, false)))
{ {
if (remote_fd) close(remote_fd);
close(local_fd); close(local_fd);
return NULL; return NULL;
} }
@ -617,18 +605,33 @@ static tproxy_conn_t* add_tcp_connection(int efd, struct tailhead *conn_list,int
conn->state = CONN_AVAILABLE; // accepted connection is immediately available conn->state = CONN_AVAILABLE; // accepted connection is immediately available
conn->efd = efd; conn->efd = efd;
socklen_t salen=sizeof(conn->client);
getpeername(conn->fd,(struct sockaddr *)&conn->client,&salen);
if (proxy_type==CONN_TYPE_TRANSPARENT) if (proxy_type==CONN_TYPE_TRANSPARENT)
{ {
sacopy(&conn->dest, (struct sockaddr *)&orig_dst); sa46copy(&conn->dest, (struct sockaddr *)&orig_dst);
if(!(conn->partner = new_conn(remote_fd, true))) if(!(conn->partner = new_conn(0, true)))
{ {
free_conn(conn); free_conn(conn);
close(remote_fd);
return NULL; return NULL;
} }
conn->partner->partner = conn; conn->partner->partner = conn;
conn->partner->efd = efd; conn->partner->efd = efd;
conn->partner->client = conn->client;
conn->partner->dest = conn->dest;
apply_desync_profile(&conn->track, (struct sockaddr *)&conn->dest);
if ((conn->partner->fd = connect_remote((struct sockaddr *)&orig_dst, conn->track.dp ? conn->track.dp->mss : 0)) < 0)
{
DLOG_ERR("Failed to connect\n");
free_conn(conn->partner);
free_conn(conn);
return NULL;
}
//remote_fd is connecting. Non-blocking connects are signaled as done by //remote_fd is connecting. Non-blocking connects are signaled as done by
//socket being marked as ready for writing //socket being marked as ready for writing
@ -662,9 +665,6 @@ static tproxy_conn_t* add_tcp_connection(int efd, struct tailhead *conn_list,int
TAILQ_INSERT_HEAD(conn_list, conn->partner, conn_ptrs); TAILQ_INSERT_HEAD(conn_list, conn->partner, conn_ptrs);
legs_remote++; legs_remote++;
} }
if (proxy_type==CONN_TYPE_TRANSPARENT)
apply_desync_profile(&conn->track, (struct sockaddr *)&conn->dest);
return conn; return conn;
} }
@ -693,7 +693,7 @@ static bool check_connection_attempt(tproxy_conn_t *conn, int efd)
{ {
if (params.debug>=1) if (params.debug>=1)
{ {
struct sockaddr_storage sa; sockaddr_in46 sa;
socklen_t salen=sizeof(sa); socklen_t salen=sizeof(sa);
char ip_port[48]; char ip_port[48];
@ -815,6 +815,8 @@ static bool proxy_mode_connect_remote(tproxy_conn_t *conn, struct tailhead *conn
} }
conn->partner->partner = conn; conn->partner->partner = conn;
conn->partner->efd = conn->efd; conn->partner->efd = conn->efd;
conn->partner->client = conn->client;
conn->partner->dest = conn->dest;
if (!epoll_set(conn->partner, EPOLLOUT)) if (!epoll_set(conn->partner, EPOLLOUT))
{ {
DLOG_ERR("socks epoll_set error %d\n", errno); DLOG_ERR("socks epoll_set error %d\n", errno);
@ -920,7 +922,7 @@ static bool handle_proxy_mode(tproxy_conn_t *conn, struct tailhead *conn_list)
socks4_send_rep(conn->fd, S4_REP_FAILED); socks4_send_rep(conn->fd, S4_REP_FAILED);
return false; return false;
} }
conn->dest.ss_family = AF_INET; ((struct sockaddr_in*)&conn->dest)->sin_family = AF_INET;
((struct sockaddr_in*)&conn->dest)->sin_port = m->port; ((struct sockaddr_in*)&conn->dest)->sin_port = m->port;
((struct sockaddr_in*)&conn->dest)->sin_addr.s_addr = m->ip; ((struct sockaddr_in*)&conn->dest)->sin_addr.s_addr = m->ip;
return proxy_mode_connect_remote(conn, conn_list); return proxy_mode_connect_remote(conn, conn_list);
@ -952,12 +954,12 @@ static bool handle_proxy_mode(tproxy_conn_t *conn, struct tailhead *conn_list)
switch(m->atyp) switch(m->atyp)
{ {
case S5_ATYP_IP4: case S5_ATYP_IP4:
conn->dest.ss_family = AF_INET; ((struct sockaddr_in*)&conn->dest)->sin_family = AF_INET;
((struct sockaddr_in*)&conn->dest)->sin_port = m->d4.port; ((struct sockaddr_in*)&conn->dest)->sin_port = m->d4.port;
((struct sockaddr_in*)&conn->dest)->sin_addr = m->d4.addr; ((struct sockaddr_in*)&conn->dest)->sin_addr = m->d4.addr;
break; break;
case S5_ATYP_IP6: case S5_ATYP_IP6:
conn->dest.ss_family = AF_INET6; ((struct sockaddr_in6*)&conn->dest)->sin6_family = AF_INET6;
((struct sockaddr_in6*)&conn->dest)->sin6_port = m->d6.port; ((struct sockaddr_in6*)&conn->dest)->sin6_port = m->d6.port;
((struct sockaddr_in6*)&conn->dest)->sin6_addr = m->d6.addr; ((struct sockaddr_in6*)&conn->dest)->sin6_addr = m->d6.addr;
((struct sockaddr_in6*)&conn->dest)->sin6_flowinfo = 0; ((struct sockaddr_in6*)&conn->dest)->sin6_flowinfo = 0;
@ -1037,7 +1039,7 @@ static bool resolve_complete(struct resolve_item *ri, struct tailhead *conn_list
DBGPRINT("resolve_complete put hostname : %s\n", ri->dom); DBGPRINT("resolve_complete put hostname : %s\n", ri->dom);
conn->track.hostname = strdup(ri->dom); conn->track.hostname = strdup(ri->dom);
} }
sacopy(&conn->dest, (struct sockaddr *)&ri->ss); sa46copy(&conn->dest, (struct sockaddr *)&ri->ss);
return proxy_mode_connect_remote(conn,conn_list); return proxy_mode_connect_remote(conn,conn_list);
} }
} }
@ -1074,7 +1076,7 @@ static void tamper(tproxy_conn_t *conn, uint8_t *segment, size_t segment_buffer_
if (conn->remote) if (conn->remote)
{ {
if (conn_partner_alive(conn) && !conn->partner->track.bTamperInCutoff) if (conn_partner_alive(conn) && !conn->partner->track.bTamperInCutoff)
tamper_in(&conn->partner->track,segment,segment_buffer_size,segment_size); tamper_in(&conn->partner->track,(struct sockaddr*)&conn->partner->client,segment,segment_buffer_size,segment_size);
} }
else else
{ {
@ -1524,18 +1526,11 @@ int event_loop(const int *listen_fd, size_t listen_fd_ct)
else else
{ {
print_legs(); print_legs();
if (params.debug>=1) if (params.debug>=1)
{ {
struct sockaddr_storage sa;
socklen_t salen=sizeof(sa);
char ip_port[48]; char ip_port[48];
ntop46_port((struct sockaddr*)&conn->client,ip_port,sizeof(ip_port));
if (getpeername(conn->fd,(struct sockaddr *)&sa,&salen))
*ip_port=0;
else
ntop46_port((struct sockaddr*)&sa,ip_port,sizeof(ip_port));
VPRINT("Socket fd=%d (local) connected from %s\n", conn->fd, ip_port); VPRINT("Socket fd=%d (local) connected from %s\n", conn->fd, ip_port);
} }
set_user_timeout(conn->fd, params.tcp_user_timeout_local); set_user_timeout(conn->fd, params.tcp_user_timeout_local);
@ -1563,7 +1558,7 @@ int event_loop(const int *listen_fd, size_t listen_fd_ct)
read_all_and_buffer(conn,3); read_all_and_buffer(conn,3);
if (errn==ECONNRESET && conn_partner_alive(conn)) if (errn==ECONNRESET && conn_partner_alive(conn))
{ {
if (conn->remote && params.tamper) rst_in(&conn->partner->track); if (conn->remote && params.tamper) rst_in(&conn->partner->track,(struct sockaddr*)&conn->partner->client);
struct linger lin; struct linger lin;
lin.l_onoff=1; lin.l_onoff=1;
@ -1588,7 +1583,7 @@ int event_loop(const int *listen_fd, size_t listen_fd_ct)
{ {
DBGPRINT("EPOLLRDHUP\n"); DBGPRINT("EPOLLRDHUP\n");
read_all_and_buffer(conn,2); read_all_and_buffer(conn,2);
if (!conn->remote && params.tamper) hup_out(&conn->track); if (!conn->remote && params.tamper) hup_out(&conn->track,(struct sockaddr*)&conn->client);
conn->state = CONN_RDHUP; // only writes. do not receive RDHUP anymore conn->state = CONN_RDHUP; // only writes. do not receive RDHUP anymore
if (conn_has_unsent(conn)) if (conn_has_unsent(conn))

View File

@ -54,7 +54,7 @@ struct tproxy_conn
int splice_pipe[2]; int splice_pipe[2];
conn_state_t state; conn_state_t state;
conn_type_t conn_type; conn_type_t conn_type;
struct sockaddr_storage dest; sockaddr_in46 client, dest; // ip:port of client, ip:port of target
struct tproxy_conn *partner; // other leg struct tproxy_conn *partner; // other leg
time_t orphan_since; time_t orphan_since;