mirror of
https://github.com/bol-van/zapret.git
synced 2025-05-24 22:32:58 +03:00
Compare commits
101 Commits
v70.4
...
b0c7af789a
Author | SHA1 | Date | |
---|---|---|---|
|
b0c7af789a | ||
|
a426ea6dad | ||
|
bda4226162 | ||
|
dc1dc5c876 | ||
|
3ca682e25a | ||
|
9629ce5cb7 | ||
|
c626d88f54 | ||
|
c91ddf4a54 | ||
|
6f1286b5b9 | ||
|
c96bc62d3b | ||
|
8432388b37 | ||
|
7efa83e61e | ||
|
abe91a4bfa | ||
|
43173e6396 | ||
|
5cc888cd2c | ||
|
5b625fa709 | ||
|
0a8135b2de | ||
|
d21175b4a3 | ||
|
68a538daed | ||
|
d2c9ff50cd | ||
|
50539d6cbf | ||
|
8b5dfcfae1 | ||
|
ccc60b5f07 | ||
|
7f94f42b1d | ||
|
1c1f259b39 | ||
|
6ef6c8ee5a | ||
|
581badfb73 | ||
|
8fce75daa4 | ||
|
c1e2e56576 | ||
|
e16ec69922 | ||
|
63256a142f | ||
|
4a9a8bd48e | ||
|
b996abd5ce | ||
|
12461de3b0 | ||
|
7dab497b57 | ||
|
41dbba1c4c | ||
|
d19f6c19a4 | ||
|
b12b1a5a17 | ||
|
8022e2576d | ||
|
f4ea264ba9 | ||
|
061acb27e4 | ||
|
8eb830d304 | ||
|
2fb93c6add | ||
|
ad5c246629 | ||
|
58e73d0331 | ||
|
9ebeff621a | ||
|
69df271a16 | ||
|
e285b2401d | ||
|
6e1e7e43bc | ||
|
d04419a60c | ||
|
fc1bf47e82 | ||
|
929df3f094 | ||
|
7272b243cb | ||
|
72d48d957a | ||
|
f4069d484a | ||
|
1c82b0a6af | ||
|
c08e69aa65 | ||
|
8097f08020 | ||
|
4cae291e6f | ||
|
82ad5508dc | ||
|
fa8ddcfc79 | ||
|
b560e32e18 | ||
|
67e1aee8a8 | ||
|
1d8385a9b4 | ||
|
340dec62a7 | ||
|
db4585c02f | ||
|
e792ca67ef | ||
|
e5e53db6b8 | ||
|
e14ee9d1fe | ||
|
360506ba4e | ||
|
aa769e05c6 | ||
|
6b0bc7a96b | ||
|
93bdfdb6be | ||
|
6d95eada2b | ||
|
e452ee8688 | ||
|
6e746f94cd | ||
|
9fd61e5d38 | ||
|
0c0fba4461 | ||
|
056e4c588a | ||
|
4b288643ac | ||
|
cbdee74e5f | ||
|
743eb5a4a2 | ||
|
4e8e3a9ed9 | ||
|
b9b91a0e68 | ||
|
9de7b66eef | ||
|
a2ffa3455d | ||
|
60b97dbed0 | ||
|
e56e4f5f35 | ||
|
5305ea83c8 | ||
|
14b3dd459b | ||
|
66fda2c33d | ||
|
77df43b9cb | ||
|
85f2b37c88 | ||
|
e2d600fcc6 | ||
|
37eda0ad98 | ||
|
770be21e1c | ||
|
1b880d42f9 | ||
|
6387315c0b | ||
|
3d4b395bfe | ||
|
55950ed7d0 | ||
|
f2b0341484 |
1
.github/workflows/build.yml
vendored
1
.github/workflows/build.yml
vendored
@@ -401,6 +401,7 @@ jobs:
|
||||
uses: crazy-max/ghaction-upx@v3
|
||||
with:
|
||||
install-only: true
|
||||
version: v4.2.4
|
||||
|
||||
- name: Prepare binaries
|
||||
shell: bash
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@@ -4,6 +4,7 @@ mdig/mdig
|
||||
nfq/dvtws
|
||||
nfq/nfqws
|
||||
nfq/winws.exe
|
||||
nfq/WinDivert*
|
||||
tpws/tpws
|
||||
binaries/my/
|
||||
ipset/zapret-ip*.txt
|
||||
|
@@ -341,12 +341,19 @@ netcat_test()
|
||||
}
|
||||
}
|
||||
|
||||
tpws_can_fix_seg()
|
||||
{
|
||||
# fix-seg requires kernel 4.6+
|
||||
"$TPWS" --port 1 --dry-run --fix-seg >/dev/null 2>/dev/null
|
||||
}
|
||||
|
||||
check_system()
|
||||
{
|
||||
echo \* checking system
|
||||
|
||||
UNAME=$(uname)
|
||||
SUBSYS=
|
||||
FIX_SEG=
|
||||
local s
|
||||
|
||||
# can be passed FWTYPE=iptables to override default nftables preference
|
||||
@@ -354,6 +361,14 @@ check_system()
|
||||
Linux)
|
||||
PKTWS="$NFQWS"
|
||||
PKTWSD=nfqws
|
||||
if [ -x "$TPWS" ] ; then
|
||||
if tpws_can_fix_seg ; then
|
||||
echo tpws supports --fix-seg on this system
|
||||
FIX_SEG='--fix-seg'
|
||||
else
|
||||
echo tpws does not support --fix-seg on this system
|
||||
fi
|
||||
fi
|
||||
linux_fwtype
|
||||
[ "$FWTYPE" = iptables -o "$FWTYPE" = nftables ] || {
|
||||
echo firewall type $FWTYPE not supported in $UNAME
|
||||
@@ -720,6 +735,11 @@ ipt_aux_scheme()
|
||||
|
||||
# to avoid possible INVALID state drop
|
||||
[ "$2" = tcp ] && IPT_ADD_DEL $1 INPUT -p $2 --sport $3 ! --syn -j ACCEPT
|
||||
|
||||
local icmp_filter="-p icmp -m icmp --icmp-type"
|
||||
[ "$IPV" = 6 ] && icmp_filter="-p icmpv6 -m icmp6 --icmpv6-type"
|
||||
IPT_ADD_DEL $1 INPUT $icmp_filter time-exceeded -m connmark --mark $DESYNC_MARK/$DESYNC_MARK -j DROP
|
||||
|
||||
# for strategies with incoming packets involved (autottl)
|
||||
IPT_ADD_DEL $1 OUTPUT -p $2 --dport $3 -m conntrack --ctstate INVALID -j ACCEPT
|
||||
if [ "$IPV" = 6 -a -n "$IP6_DEFRAG_DISABLE" ]; then
|
||||
@@ -751,6 +771,7 @@ ipt_scheme()
|
||||
$IPTABLES -t mangle -A blockcheck_output -p $1 ! --dport $2 -j RETURN
|
||||
|
||||
for ip in $3; do
|
||||
$IPTABLES -t mangle -A blockcheck_output -d $ip -j CONNMARK --or-mark $DESYNC_MARK
|
||||
$IPTABLES -t mangle -A blockcheck_output -d $ip -j NFQUEUE --queue-num $QNUM
|
||||
done
|
||||
|
||||
@@ -768,12 +789,20 @@ nft_scheme()
|
||||
|
||||
nft add table inet $NFT_TABLE
|
||||
nft "add chain inet $NFT_TABLE postnat { type filter hook output priority 102; }"
|
||||
nft "add rule inet $NFT_TABLE postnat meta nfproto ipv${IPV} $1 dport $2 mark and $DESYNC_MARK != $DESYNC_MARK ip${ipver} daddr {$iplist} queue num $QNUM"
|
||||
nft "add rule inet $NFT_TABLE postnat meta nfproto ipv${IPV} $1 dport $2 mark and $DESYNC_MARK == 0 ip${ipver} daddr {$iplist} ct mark set ct mark or $DESYNC_MARK queue num $QNUM"
|
||||
# for strategies with incoming packets involved (autottl)
|
||||
nft "add chain inet $NFT_TABLE prenat { type filter hook prerouting priority -102; }"
|
||||
# enable everything generated by nfqws (works only in OUTPUT, not in FORWARD)
|
||||
nft "add chain inet $NFT_TABLE predefrag { type filter hook output priority -402; }"
|
||||
nft "add rule inet $NFT_TABLE predefrag meta nfproto ipv${IPV} mark and $DESYNC_MARK !=0 notrack"
|
||||
[ "$IPV" = 4 ] && {
|
||||
nft "add rule inet $NFT_TABLE prenat icmp type time-exceeded ct mark and $DESYNC_MARK != 0 drop"
|
||||
nft "add rule inet $NFT_TABLE prenat icmp type time-exceeded ct state invalid drop"
|
||||
}
|
||||
[ "$IPV" = 6 ] && {
|
||||
nft "add rule inet $NFT_TABLE prenat icmpv6 type time-exceeded ct mark and $DESYNC_MARK != 0 drop"
|
||||
nft "add rule inet $NFT_TABLE prenat icmpv6 type time-exceeded ct state invalid drop"
|
||||
}
|
||||
}
|
||||
|
||||
pktws_ipt_prepare()
|
||||
@@ -1168,7 +1197,7 @@ pktws_curl_test_update_vary()
|
||||
[ "$sec" = 0 ] || proto=tls
|
||||
test_has_fake $desync && {
|
||||
zerofake="--dpi-desync-fake-$proto=0x00000000"
|
||||
[ "$sec" = 0 ] || tlsmod="--dpi-desync-fake-tls-mod=rnd,rndsni,padencap"
|
||||
[ "$sec" = 0 ] || tlsmod="--dpi-desync-fake-tls-mod=rnd,dupsid,rndsni,padencap"
|
||||
}
|
||||
if test_has_fakedsplit $desync ; then
|
||||
splits="method+2 midsld"
|
||||
@@ -1430,6 +1459,11 @@ warn_mss()
|
||||
[ -n "$1" ] && echo 'WARNING ! although mss worked it may not work on all sites and will likely cause significant slowdown. it may only be required for TLS1.2, not TLS1.3'
|
||||
return 0
|
||||
}
|
||||
fix_seg()
|
||||
{
|
||||
# $1 - split-pos
|
||||
[ -n "$FIX_SEG" ] && contains "$1" , && echo "$FIX_SEG"
|
||||
}
|
||||
|
||||
tpws_check_domain_http_bypass_()
|
||||
{
|
||||
@@ -1455,7 +1489,7 @@ tpws_check_domain_http_bypass_()
|
||||
done
|
||||
for s2 in '' '--hostcase' '--oob' '--disorder' ${oobdis:+"$oobdis"}; do
|
||||
for s in $splits_http ; do
|
||||
tpws_curl_test_update $1 $3 --split-pos=$s $s2 && [ "$SCANLEVEL" != force ] && {
|
||||
tpws_curl_test_update $1 $3 --split-pos=$s $(fix_seg $s) $s2 && [ "$SCANLEVEL" != force ] && {
|
||||
[ "$SCANLEVEL" = quick ] && return
|
||||
break
|
||||
}
|
||||
@@ -1470,7 +1504,7 @@ tpws_check_domain_http_bypass_()
|
||||
s3=${mss:+--mss=$mss}
|
||||
for s2 in '' '--oob' '--disorder' ${oobdis:+"$oobdis"}; do
|
||||
for pos in $splits_tls; do
|
||||
tpws_curl_test_update $1 $3 --split-pos=$pos $s2 $s3 && warn_mss $s3 && [ "$SCANLEVEL" != force ] && {
|
||||
tpws_curl_test_update $1 $3 --split-pos=$pos $(fix_seg $pos) $s2 $s3 && warn_mss $s3 && [ "$SCANLEVEL" != force ] && {
|
||||
[ "$SCANLEVEL" = quick ] && return
|
||||
need_mss=0
|
||||
break
|
||||
@@ -1478,7 +1512,7 @@ tpws_check_domain_http_bypass_()
|
||||
done
|
||||
done
|
||||
for s in '' '--oob' '--disorder' ${oobdis:+"$oobdis"}; do
|
||||
for s2 in '--tlsrec=midsld' '--tlsrec=sniext+1 --split-pos=midsld' '--tlsrec=sniext+4 --split-pos=midsld' '--tlsrec=sniext+1 --split-pos=1,midsld' '--tlsrec=sniext+4 --split-pos=1,midsld' ; do
|
||||
for s2 in '--tlsrec=midsld' '--tlsrec=sniext+1 --split-pos=midsld' '--tlsrec=sniext+4 --split-pos=midsld' "--tlsrec=sniext+1 --split-pos=1,midsld $FIX_SEG" "--tlsrec=sniext+4 --split-pos=1,midsld $FIX_SEG" ; do
|
||||
tpws_curl_test_update $1 $3 $s2 $s $s3 && warn_mss $s3 && [ "$SCANLEVEL" != force ] && {
|
||||
[ "$SCANLEVEL" = quick ] && return
|
||||
need_mss=0
|
||||
|
@@ -405,14 +405,14 @@ std_ports()
|
||||
has_bad_ws_options()
|
||||
{
|
||||
# $1 - nfqws/tpws opts
|
||||
# ПРИМЕЧАНИЕ ДЛЯ РАСПРОСТРАНИТЕЛЕЙ КОПИПАСТЫ
|
||||
# ЭТОТ КОД СДЕЛАН СПЕЦИАЛЬНО ДЛЯ ВАС, ЧТОБЫ ВЫ НЕ ПОСТИЛИ В СЕТЬ ПЛОХИЕ РЕЦЕПТЫ
|
||||
# ЕСЛИ ВАМ ХОЧЕТСЯ ЕГО УДАЛИТЬ И НАПИСАТЬ ИНСТРУКЦИЮ КАК ЕГО УДАЛЯТЬ, ВЫ ДЕЛАЕТЕ ХРЕНОВУЮ УСЛУГУ. НАПИШИТЕ ЛУЧШЕ custom script.
|
||||
# custom script - ЭТО ФАЙЛИК, КОТОРЫЙ ДОСТАТОЧНО СКОПИРОВАТЬ В НУЖНУЮ ДИРЕКТОРИЮ, ЧТОБЫ ОН СДЕЛАЛ ТОЖЕ САМОЕ, НО ЭФФЕКТИВНО.
|
||||
# ФИЛЬТРАЦИЯ ПО IPSET В ЯДРЕ НЕСРАВНИМО ЭФФЕКТИВНЕЕ, ЧЕМ ПЕРЕКИДЫВАТЬ ВСЕ ПАКЕТЫ В nfqws И ТАМ ФИЛЬТРОВАТЬ
|
||||
# --ipset СУЩЕСТВУЕТ ТОЛЬКО ДЛЯ ВИНДЫ И LINUX СИСТЕМ БЕЗ ipset (НАПРИМЕР, Android).
|
||||
# И ТОЛЬКО ПО ЭТОЙ ПРИЧИНЕ ОНО НЕ ВЫКИНУТО ПОЛНОСТЬЮ ИЗ LINUX ВЕРСИИ
|
||||
contains "$1" "--ipset"
|
||||
|
||||
# kernel or user mode ipset usage should be wise
|
||||
# if all traffic is already intercepted it would be OK to use ip-based specialized profiles
|
||||
# but if all traffic is intercepted only to filter a group of ip its BAD. kernel ipset should be used.
|
||||
# I cannot insert brain to copy-pasters, I know they will misuse. But it's their problem.
|
||||
# zapret is not made for newbies
|
||||
#contains "$1" "--ipset"
|
||||
return 1
|
||||
}
|
||||
check_bad_ws_options()
|
||||
{
|
||||
|
@@ -391,6 +391,27 @@ zapret_do_firewall_rules_ipt()
|
||||
|
||||
zapret_do_firewall_standard_rules_ipt $1
|
||||
custom_runner zapret_custom_firewall $1
|
||||
zapret_do_icmp_filter $1
|
||||
}
|
||||
|
||||
zapret_do_icmp_filter()
|
||||
{
|
||||
# $1 - 1 - add, 0 - del
|
||||
|
||||
local FW_EXTRA_PRE= FW_EXTRA_POST=
|
||||
|
||||
[ "$FILTER_TTL_EXPIRED_ICMP" = 1 ] && {
|
||||
[ "$DISABLE_IPV4" = 1 ] || {
|
||||
ipt_add_del $1 POSTROUTING -t mangle -m mark --mark $DESYNC_MARK/$DESYNC_MARK -j CONNMARK --or-mark $DESYNC_MARK
|
||||
ipt_add_del $1 INPUT -p icmp -m icmp --icmp-type time-exceeded -m connmark --mark $DESYNC_MARK/$DESYNC_MARK -j DROP
|
||||
ipt_add_del $1 FORWARD -p icmp -m icmp --icmp-type time-exceeded -m connmark --mark $DESYNC_MARK/$DESYNC_MARK -j DROP
|
||||
}
|
||||
[ "$DISABLE_IPV6" = 1 ] || {
|
||||
ipt6_add_del $1 POSTROUTING -t mangle -m mark --mark $DESYNC_MARK/$DESYNC_MARK -j CONNMARK --or-mark $DESYNC_MARK
|
||||
ipt6_add_del $1 INPUT -p icmpv6 -m icmp6 --icmpv6-type time-exceeded -m connmark --mark $DESYNC_MARK/$DESYNC_MARK -j DROP
|
||||
ipt6_add_del $1 FORWARD -p icmpv6 -m icmp6 --icmpv6-type time-exceeded -m connmark --mark $DESYNC_MARK/$DESYNC_MARK -j DROP
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
zapret_do_firewall_ipt()
|
||||
|
@@ -111,6 +111,14 @@ unprepare_route_localnet()
|
||||
set_route_localnet 0 "$@"
|
||||
}
|
||||
|
||||
get_uevent_devtype()
|
||||
{
|
||||
local DEVTYPE INTERFACE IFINDEX OF_NAME OF_FULLNAME OF_COMPATIBLE_N
|
||||
[ -f "/sys/class/net/$1/uevent" ] && {
|
||||
. "/sys/class/net/$1/uevent"
|
||||
echo -n $DEVTYPE
|
||||
}
|
||||
}
|
||||
resolve_lower_devices()
|
||||
{
|
||||
# $1 - bridge interface name
|
||||
|
@@ -106,7 +106,7 @@ cat << EOF | nft -f -
|
||||
flush chain inet $ZAPRET_NFT_TABLE predefrag_nfqws
|
||||
add rule inet $ZAPRET_NFT_TABLE predefrag mark and $DESYNC_MARK !=0 jump predefrag_nfqws comment "nfqws generated : avoid drop by INVALID conntrack state"
|
||||
add rule inet $ZAPRET_NFT_TABLE predefrag_nfqws mark and $DESYNC_MARK_POSTNAT !=0 notrack comment "postnat traffic"
|
||||
add rule inet $ZAPRET_NFT_TABLE predefrag_nfqws ip frag-off != 0 notrack comment "ipfrag"
|
||||
add rule inet $ZAPRET_NFT_TABLE predefrag_nfqws ip frag-off & 0x1fff != 0 notrack comment "ipfrag"
|
||||
add rule inet $ZAPRET_NFT_TABLE predefrag_nfqws exthdr frag exists notrack comment "ipfrag"
|
||||
add rule inet $ZAPRET_NFT_TABLE predefrag_nfqws tcp flags ! syn,rst,ack notrack comment "datanoack"
|
||||
add set inet $ZAPRET_NFT_TABLE lanif { type ifname; }
|
||||
@@ -119,6 +119,20 @@ EOF
|
||||
nft_flush_chain predefrag_nfqws
|
||||
nft_add_rule predefrag_nfqws notrack comment \"do not track nfqws generated packets to avoid nat tampering and defragmentation\"
|
||||
}
|
||||
[ "$FILTER_TTL_EXPIRED_ICMP" = 1 ] && {
|
||||
if is_postnat; then
|
||||
# can be caused by untracked nfqws-generated packets
|
||||
nft_add_rule prerouting icmp type time-exceeded ct state invalid drop
|
||||
else
|
||||
nft_add_rule postrouting_hook mark and $DESYNC_MARK != 0 ct mark set ct mark or $DESYNC_MARK comment \"nfqws related : prevent ttl expired socket errors\"
|
||||
fi
|
||||
[ "$DISABLE_IPV4" = "1" ] || {
|
||||
nft_add_rule prerouting icmp type time-exceeded ct mark and $DESYNC_MARK != 0 drop comment \"nfqws related : prevent ttl expired socket errors\"
|
||||
}
|
||||
[ "$DISABLE_IPV6" = "1" ] || {
|
||||
nft_add_rule prerouting icmpv6 type time-exceeded ct mark and $DESYNC_MARK != 0 drop comment \"nfqws related : prevent ttl expired socket errors\"
|
||||
}
|
||||
}
|
||||
}
|
||||
nft_del_chains()
|
||||
{
|
||||
@@ -320,7 +334,7 @@ nft_fill_ifsets()
|
||||
# $5 - space separated wan physical interface names (optional)
|
||||
# $6 - space separated wan6 physical interface names (optional)
|
||||
|
||||
local script i j ALLDEVS devs
|
||||
local script i j ALLDEVS devs b
|
||||
|
||||
# if large sets exist nft works very ineffectively
|
||||
# looks like it analyzes the whole table blob to find required data pieces
|
||||
@@ -348,15 +362,18 @@ flush set inet $ZAPRET_NFT_TABLE lanif"
|
||||
nft_create_or_update_flowtable 'offload' 2>/dev/null
|
||||
# then add elements. some of them can cause error because unsupported
|
||||
for i in $ALLDEVS; do
|
||||
# first try to add interface itself
|
||||
nft_create_or_update_flowtable 'offload' $i 2>/dev/null
|
||||
# bridge members must be added instead of the bridge itself
|
||||
# some members may not support hw offload. example : lan1 lan2 lan3 support, wlan0 wlan1 - not
|
||||
b=
|
||||
devs=$(resolve_lower_devices $i)
|
||||
for j in $devs; do
|
||||
# do not display error if addition failed
|
||||
nft_create_or_update_flowtable 'offload' $j 2>/dev/null
|
||||
nft_create_or_update_flowtable 'offload' $j && b=1 2>/dev/null
|
||||
done
|
||||
[ -n "$b" ] || {
|
||||
# no lower devices added ? try to add interface itself
|
||||
nft_create_or_update_flowtable 'offload' $i 2>/dev/null
|
||||
}
|
||||
done
|
||||
;;
|
||||
esac
|
||||
@@ -453,7 +470,7 @@ _nft_fw_nfqws_post4()
|
||||
nft_print_op "$filter" "nfqws postrouting (qnum $port)" 4
|
||||
rule="${3:+oifname @wanif }$filter ip daddr != @nozapret"
|
||||
is_postnat && setmark="meta mark set meta mark or $DESYNC_MARK_POSTNAT"
|
||||
nft_insert_rule $chain $rule $setmark $FW_EXTRA_POST queue num $port bypass
|
||||
nft_insert_rule $chain $rule $setmark $CONNMARKER $FW_EXTRA_POST queue num $port bypass
|
||||
nft_add_nfqws_flow_exempt_rule "$rule"
|
||||
}
|
||||
}
|
||||
@@ -468,7 +485,7 @@ _nft_fw_nfqws_post6()
|
||||
nft_print_op "$filter" "nfqws postrouting (qnum $port)" 6
|
||||
rule="${3:+oifname @wanif6 }$filter ip6 daddr != @nozapret6"
|
||||
is_postnat && setmark="meta mark set meta mark or $DESYNC_MARK_POSTNAT"
|
||||
nft_insert_rule $chain $rule $setmark $FW_EXTRA_POST queue num $port bypass
|
||||
nft_insert_rule $chain $rule $setmark $CONNMARKER $FW_EXTRA_POST queue num $port bypass
|
||||
nft_add_nfqws_flow_exempt_rule "$rule"
|
||||
}
|
||||
}
|
||||
@@ -492,7 +509,7 @@ _nft_fw_nfqws_pre4()
|
||||
local filter="$1" port="$2" rule
|
||||
nft_print_op "$filter" "nfqws prerouting (qnum $port)" 4
|
||||
rule="${3:+iifname @wanif }$filter ip saddr != @nozapret"
|
||||
nft_insert_rule $(get_prechain) $rule $FW_EXTRA_POST queue num $port bypass
|
||||
nft_insert_rule $(get_prechain) $rule $CONNMARKER $FW_EXTRA_POST queue num $port bypass
|
||||
}
|
||||
}
|
||||
_nft_fw_nfqws_pre6()
|
||||
@@ -505,7 +522,7 @@ _nft_fw_nfqws_pre6()
|
||||
local filter="$1" port="$2" rule
|
||||
nft_print_op "$filter" "nfqws prerouting (qnum $port)" 6
|
||||
rule="${3:+iifname @wanif6 }$filter ip6 saddr != @nozapret6"
|
||||
nft_insert_rule $(get_prechain) $rule $FW_EXTRA_POST queue num $port bypass
|
||||
nft_insert_rule $(get_prechain) $rule $CONNMARKER $FW_EXTRA_POST queue num $port bypass
|
||||
}
|
||||
}
|
||||
nft_fw_nfqws_pre()
|
||||
@@ -683,3 +700,7 @@ zapret_do_firewall_nft()
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# ctmark is not available in POSTNAT mode
|
||||
CONNMARKER=
|
||||
[ "$FILTER_TTL_EXPIRED_ICMP" = 1 ] && is_postnat && CONNMARKER="ct mark set ct mark or $DESYNC_MARK"
|
||||
|
@@ -129,6 +129,11 @@ INIT_APPLY_FW=1
|
||||
# do not work with ipv6
|
||||
DISABLE_IPV6=1
|
||||
|
||||
# drop icmp time exceeded messages for nfqws tampered connections
|
||||
# in POSTNAT mode this can interfere with default mtr/traceroute in tcp or udp mode. use source port not redirected to nfqws
|
||||
# set to 0 if you are not expecting connection breakage due to icmp in response to TCP SYN or UDP
|
||||
FILTER_TTL_EXPIRED_ICMP=1
|
||||
|
||||
# select which init script will be used to get ip or host list
|
||||
# possible values : get_user.sh get_antizapret.sh get_combined.sh get_reestr.sh get_hostlist.sh
|
||||
# comment if not required
|
||||
|
@@ -466,3 +466,30 @@ nfqws,tpws: optional systemd notify support. compile using 'make systemd'
|
||||
nfqws,tpws: systemd instance templates for nfqws and tpws
|
||||
nfqws,tpws: separate droproot from dropcaps
|
||||
tpws: detect WSL 1 and warn about non-working options
|
||||
|
||||
v70.5
|
||||
|
||||
nfqws: multiple --dpi-desync-fake-xxx
|
||||
nfqws: support of inter-packet fragmented QUIC CRYPTO
|
||||
|
||||
v70.6
|
||||
|
||||
nfqws: detect Discord Voice IP discovery packets
|
||||
nfqws: detect STUN message packets
|
||||
nfqws: change SNI to specified value tls mod : --dpi-desync-fake-tls-mod sni=<sni>
|
||||
nfqws: update default TLS ClientHello fake. firefox 136.0.4 finger, no kyber, SNI=microsoft.com
|
||||
nfqws: multiple mods for multiple TLS fakes
|
||||
init.d: remove 50-discord
|
||||
blockcheck: use tpws --fix-seg on linux for multiple splits
|
||||
|
||||
v71
|
||||
|
||||
nfqws,tpws: debug tls version, alpn, ech
|
||||
nfqws: --dpi-desync-fake-tls=! means default tls fake
|
||||
nfqws: --dup*
|
||||
nfqws: --orig*
|
||||
nfqws: ipcache of hop count and host names
|
||||
tpws: ipcache of host names
|
||||
nfqws,tpws: set 1024 repeat limit to fakes and dups
|
||||
init.d: remove --ipset parameter prohibition
|
||||
init.d, blockcheck: drop time exceeded icmp for nfqws-related connections
|
||||
|
@@ -12,10 +12,10 @@ Other packages may be required on your distribution. Look for the errors.
|
||||
|
||||
examples :
|
||||
|
||||
curl -o - https://downloads.openwrt.org/releases/23.05.5/targets/x86/64/openwrt-sdk-23.05.5-x86-64_gcc-12.3.0_musl.Linux-x86_64.tar.xz | tar -Jxvf -
|
||||
curl -o - https://downloads.openwrt.org/releases/23.05.5/targets/x86/64/openwrt-sdk-23.05.5-x86-64_gcc-12.3.0_musl.Linux-x86_64.tar.xz | tar -Jxv
|
||||
cd openwrt-sdk-23.05.5-x86-64_gcc-12.3.0_musl.Linux-x86_64
|
||||
|
||||
curl -o - https://downloads.openwrt.org/snapshots/targets/x86/64/openwrt-sdk-x86-64_gcc-13.3.0_musl.Linux-x86_64.tar.zst | tar --zstd -xvf -
|
||||
curl -o - https://downloads.openwrt.org/snapshots/targets/x86/64/openwrt-sdk-x86-64_gcc-13.3.0_musl.Linux-x86_64.tar.zst | tar --zstd -xv
|
||||
cd openwrt-sdk-x86-64_gcc-13.3.0_musl.Linux-x86_64
|
||||
|
||||
3) Install required libs
|
||||
@@ -48,7 +48,7 @@ static build : make CFLAGS=-static package/{tpws,nfqws,mdig,ip2net}/compile
|
||||
executables only : build_dir/target/<progname>
|
||||
ipk or apk packages : bin/packages/*/base
|
||||
|
||||
8) Installating to openwrt to use with zapret
|
||||
8) Installing to openwrt to use with zapret
|
||||
|
||||
zapret with or without binaries should be already installed in /opt/zapret.
|
||||
Install ipk's or apk's with all compiled progs using opkg or apk.
|
||||
|
@@ -1,7 +1,7 @@
|
||||
debian,ubuntu :
|
||||
|
||||
apt install make gcc zlib1g-dev libcap-dev libnetfilter-queue-dev
|
||||
make -C /opt/zapret
|
||||
apt install make gcc zlib1g-dev libcap-dev libnetfilter-queue-dev libsystemd-dev
|
||||
make -C /opt/zapret systemd
|
||||
|
||||
FreeBSD :
|
||||
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# zapret v70.4
|
||||
# zapret v70.7
|
||||
|
||||
# SCAMMER WARNING
|
||||
|
||||
@@ -173,13 +173,15 @@ nfqws takes the following parameters:
|
||||
--dpi-desync-badack-increment=<int|0xHEX> ; badseq fooling ackseq signed increment. default -66000
|
||||
--dpi-desync-any-protocol=0|1 ; 0(default)=desync only http and tls 1=desync any nonempty data packet
|
||||
--dpi-desync-fake-http=<filename>|0xHEX ; file containing fake http request
|
||||
--dpi-desync-fake-tls=<filename>|0xHEX ; file containing fake TLS ClientHello (for https)
|
||||
--dpi-desync-fake-tls-mod=mod[,mod] ; comma separated list of TLS fake mods. available mods : none,rnd,rndsni,dupsid,padencap
|
||||
--dpi-desync-fake-tls=<filename>|0xHEX|! ; file containing fake TLS ClientHello (for https). '!' = standard fake
|
||||
--dpi-desync-fake-tls-mod=mod[,mod] ; comma separated list of TLS fake mods. available mods : none,rnd,rndsni,sni=<sni>,dupsid,padencap
|
||||
--dpi-desync-fake-unknown=<filename>|0xHEX ; file containing unknown protocol fake payload
|
||||
--dpi-desync-fake-syndata=<filename>|0xHEX ; file containing SYN data payload
|
||||
--dpi-desync-fake-quic=<filename>|0xHEX ; file containing fake QUIC Initial
|
||||
--dpi-desync-fake-wireguard=<filename>|0xHEX ; file containing fake wireguard handshake initiation
|
||||
--dpi-desync-fake-dht=<filename>|0xHEX ; file containing fake DHT (d1..e)
|
||||
--dpi-desync-fake-discord=<filename>|0xHEX ; file containing fake Discord voice connection initiation packet (IP Discovery)
|
||||
--dpi-desync-fake-stun=<filename>|0xHEX ; file containing fake STUN message
|
||||
--dpi-desync-fake-unknown-udp=<filename>|0xHEX ; file containing unknown udp protocol fake payload
|
||||
--dpi-desync-udplen-increment=<int> ; increase or decrease udp packet length by N bytes (default 2). negative values decrease length.
|
||||
--dpi-desync-udplen-pattern=<filename>|0xHEX ; udp tail fill pattern
|
||||
@@ -199,7 +201,7 @@ nfqws takes the following parameters:
|
||||
--filter-l3=ipv4|ipv6 ; L3 protocol filter. multiple comma separated values allowed.
|
||||
--filter-tcp=[~]port1[-port2]|* ; TCP port filter. ~ means negation. setting tcp and not setting udp filter denies udp. comma separated list supported.
|
||||
--filter-udp=[~]port1[-port2]|* ; UDP port filter. ~ means negation. setting udp and not setting tcp filter denies tcp. comma separated list supported.
|
||||
--filter-l7=[http|tls|quic|wireguard|dht|unknown] ; L6-L7 protocol filter. multiple comma separated values allowed.
|
||||
--filter-l7=<proto> ; L6-L7 protocol filter. multiple comma separated values allowed. proto: http tls quic wireguard dht discord stun unknown
|
||||
--ipset=<filename> ; ipset include filter (one ip/CIDR per line, ipv4 and ipv6 accepted, gzip supported, multiple ipsets allowed)
|
||||
--ipset-ip=<ip_list> ; comma separated fixed subnet list
|
||||
--ipset-exclude=<filename> ; ipset exclude filter (one ip/CIDR per line, ipv4 and ipv6 accepted, gzip supported, multiple ipsets allowed)
|
||||
@@ -265,6 +267,12 @@ Fakes are separate generated by nfqws packets carrying false information for DPI
|
||||
|
||||
`--dpi-desync-fooling` takes multiple comma separated values.
|
||||
|
||||
|
||||
Multiple parameters `--dpi-desync-fake-???` are supported except for the `--dpi-desync-fake-syndata`.
|
||||
Fakes are sent in the specified order. `--dpi-desync-repeats` resends each fake.
|
||||
Resulting order would be : `fake1 fake1 fake1 fake2 fake2 fake2 fake3 fake3 fake3 .....`
|
||||
|
||||
|
||||
### FAKE mods
|
||||
|
||||
**nfqws** has built-in TLS fake. It can be customized with `--dpi-desync-fake-tls` option.
|
||||
@@ -277,11 +285,20 @@ It's possible to use TLS Client Hello with any fingerprint and any SNI.
|
||||
* `rnd`. Randomize `random` and `session id` fields. Applied on every request.
|
||||
* `rndsni`. Randomize SNI. If SNI >=7 symbols random SLD is applied with known TLD. Otherwise filled with random symbols. Applied only once at startup.
|
||||
* `dupsid`. Copy `session ID` from original TLS Client Hello. Takes precedence over `rnd`. Applied on every request.
|
||||
* `sni=<sni>`. Set specified SNI value. Changes TLS fake length, fixes lengths in TLS structure. Applied once at startup before `rndsni`.
|
||||
* `padencap`. Padding extension is extended by original TLS Client Hello size (including multi packet variation with kyber). Padding extension is added to the end if not present, otherwise it must be the last extension. All lengths are increased. Fake size is not changed. Can be useful if DPI does not analyze sequence numbers properly. Applied on every request.
|
||||
|
||||
By default if custom fake is not defined `rnd,rndsni,dupsid` mods are applied. If defined - `none`.
|
||||
This behaviour is compatible with previous versions with addition of `dupsid`.
|
||||
|
||||
If multiple TLS fakes are present each one takes the last mod.
|
||||
If a mod is specified after fake it replaces previous mod.
|
||||
This way it's possible to use different mods for every TLS fake.
|
||||
|
||||
If a mod is set to non-TLS fake it causes error. Use `--dpi-desync-fake-tls-mod=none'.
|
||||
|
||||
Example : `--dpi-desync-fake-tls=iana_org.bin --dpi-desync-fake-tls-mod=rndsni --dpi-desync-fake-tls=0xaabbccdd --dpi-desync-fake-tls-mod=none'
|
||||
|
||||
### TCP segmentation
|
||||
|
||||
* `multisplit`. split request at specified in `--dpi-desync-split-pos` positions
|
||||
@@ -464,7 +481,7 @@ This option can resist DPIs that track outgoing UDP packet sizes.
|
||||
Requires that application protocol does not depend on udp payload size.
|
||||
|
||||
QUIC initial packets are recognized. Decryption and hostname extraction is supported so `--hostlist` parameter will work.
|
||||
Wireguard handshake initiation and DHT packets are also recognized.
|
||||
Wireguard handshake initiation, DHT, STUN and [Discord Voice IP Discovery](https://discord.com/developers/docs/topics/voice-connections#ip-discovery) packets are also recognized.
|
||||
For other protocols desync use `--dpi-desync-any-protocol`.
|
||||
|
||||
Conntrack supports udp. `--dpi-desync-cutoff` will work. UDP conntrack timeout can be set in the 4th parameter of `--ctrack-timeouts`.
|
||||
@@ -1434,12 +1451,8 @@ If this is the case then run another script in background and add some delay the
|
||||
|
||||
Are welcome here :
|
||||
|
||||
<img src=https://cdn-icons-png.flaticon.com/16/14446/14446252.png alt="USDT" style="vertical-align: middle;"/> USDT
|
||||
```
|
||||
0x3d52Ce15B7Be734c53fc9526ECbAB8267b63d66E
|
||||
```
|
||||
USDT `0x3d52Ce15B7Be734c53fc9526ECbAB8267b63d66E`
|
||||
|
||||
<img src=https://cdn-icons-png.flaticon.com/16/5968/5968260.png alt="USDT" style="vertical-align: middle;"/> BTC
|
||||
```
|
||||
bc1qhqew3mrvp47uk2vevt5sctp7p2x9m7m5kkchve
|
||||
```
|
||||
BTC `bc1qhqew3mrvp47uk2vevt5sctp7p2x9m7m5kkchve`
|
||||
|
||||
ETH `0x3d52Ce15B7Be734c53fc9526ECbAB8267b63d66E`
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# zapret v70.4
|
||||
# zapret v70.7
|
||||
|
||||
# ВНИМАНИЕ, остерегайтесь мошенников
|
||||
|
||||
@@ -195,12 +195,14 @@ dvtws, собираемый из тех же исходников (см. [док
|
||||
--dpi-desync-badack-increment=<int|0xHEX> ; инкремент ack sequence number для badseq. по умолчанию -66000
|
||||
--dpi-desync-any-protocol=0|1 ; 0(default)=работать только по http request и tls clienthello 1=по всем непустым пакетам данных
|
||||
--dpi-desync-fake-http=<filename>|0xHEX ; файл, содержащий фейковый http запрос для dpi-desync=fake, на замену стандартному www.iana.org
|
||||
--dpi-desync-fake-tls=<filename>|0xHEX ; файл, содержащий фейковый tls clienthello для dpi-desync=fake, на замену стандартному
|
||||
--dpi-desync-fake-tls-mod=mod[,mod] ; список через запятую режимов runtime модификации фейков : none,rnd,rndsni,dupsid,padencap
|
||||
--dpi-desync-fake-tls=<filename>|0xHEX|! ; файл, содержащий фейковый tls clienthello для dpi-desync=fake, на замену стандартному. '!' = стандартный фейк
|
||||
--dpi-desync-fake-tls-mod=mod[,mod] ; список через запятую режимов runtime модификации фейков : none,rnd,rndsni,sni=<sni>,dupsid,padencap
|
||||
--dpi-desync-fake-unknown=<filename>|0xHEX ; файл, содержащий фейковый пейлоад неизвестного протокола для dpi-desync=fake, на замену стандартным нулям 256 байт
|
||||
--dpi-desync-fake-syndata=<filename>|0xHEX ; файл, содержащий фейковый пейлоад пакета SYN для режима десинхронизации syndata
|
||||
--dpi-desync-fake-quic=<filename>|0xHEX ; файл, содержащий фейковый QUIC Initial
|
||||
--dpi-desync-fake-dht=<filename>|0xHEX ; файл, содержащий фейковый пейлоад DHT протокола для dpi-desync=fake, на замену стандартным нулям 64 байт
|
||||
--dpi-desync-fake-discord=<filename>|0xHEX ; файл, содержащий фейковый пейлоад Discord протокола нахождения IP адреса для голосовых чатов для dpi-desync=fake, на замену стандартным нулям 64 байт
|
||||
--dpi-desync-fake-stun=<filename>|0xHEX ; файл, содержащий фейковый пейлоад STUN протокола для dpi-desync=fake, на замену стандартным нулям 64 байт
|
||||
--dpi-desync-fake-unknown-udp=<filename>|0xHEX ; файл, содержащий фейковый пейлоад неизвестного udp протокола для dpi-desync=fake, на замену стандартным нулям 64 байт
|
||||
--dpi-desync-udplen-increment=<int> ; насколько увеличивать длину udp пейлоада в режиме udplen
|
||||
--dpi-desync-udplen-pattern=<filename>|0xHEX ; чем добивать udp пакет в режиме udplen. по умолчанию - нули
|
||||
@@ -226,7 +228,7 @@ dvtws, собираемый из тех же исходников (см. [док
|
||||
--filter-l3=ipv4|ipv6 ; фильтр версии ip для текущей стратегии
|
||||
--filter-tcp=[~]port1[-port2]|* ; фильтр портов tcp для текущей стратегии. ~ означает инверсию. установка фильтра tcp и неустановка фильтра udp запрещает udp. поддерживается список через запятую.
|
||||
--filter-udp=[~]port1[-port2]|* ; фильтр портов udp для текущей стратегии. ~ означает инверсию. установка фильтра udp и неустановка фильтра tcp запрещает tcp. поддерживается список через запятую.
|
||||
--filter-l7=[http|tls|quic|wireguard|dht|unknown] ; фильтр протокола L6-L7. поддерживается несколько значений через запятую.
|
||||
--filter-l7=<proto> ; фильтр протокола L6-L7. поддерживается несколько значений через запятую. proto : http tls quic wireguard dht discord stun unknown
|
||||
--ipset=<filename> ; включающий ip list. на каждой строчке ip или cidr ipv4 или ipv6. поддерживается множество листов и gzip. перечитка автоматическая.
|
||||
--ipset-ip=<ip_list> ; фиксированный список подсетей через запятую. можно использовать # в начале для комментирования отдельных подсетей.
|
||||
--ipset-exclude=<filename> ; исключающий ip list. на каждой строчке ip или cidr ipv4 или ipv6. поддерживается множество листов и gzip. перечитка автоматическая.
|
||||
@@ -320,6 +322,10 @@ dvtws, собираемый из тех же исходников (см. [док
|
||||
|
||||
Режимы дурения могут сочетаться в любых комбинациях. `--dpi-desync-fooling` берет множество значений через запятую.
|
||||
|
||||
Возможно задание множества фейков через повторение парамеров `--dpi-desync-fake-???`, кроме `--dpi-desync-fake-syndata`.
|
||||
Фейки будут отосланы в указанном порядке. `--dpi-desync-repeats` повторяет каждый отосланный фейк.
|
||||
Итоговый порядок будет такой : `fake1 fake1 fake1 fake2 fake2 fake2 fake3 fake3 fake3 .....`
|
||||
|
||||
### МОДИФИКАЦИЯ ФЕЙКОВ
|
||||
|
||||
В nfqws зашит базовый вариант фейка для TLS. Его можно переопределить опцией `--dpi-desync-fake-tls`.
|
||||
@@ -334,11 +340,22 @@ dvtws, собираемый из тех же исходников (см. [док
|
||||
* `rnd`. Рандомизировать поля `random` и `session id`. Выполняется на каждый запрос.
|
||||
* `dupsid`. Копировать `session ID` из передаваемого TLS Client Hello. Имеет приоритет над `rnd`. Выполняется на каждый запрос.
|
||||
* `rndsni`. Рандомизировать SNI. Если SNI >=7 символов, применяется случайный домен 2 уровня с известным TLD, иначе заполняется случайными символами без точки. Выполняется один раз при старте.
|
||||
* `sni=<sni>`. Заменить sni на указанное значение. Макс длина SNI - 63 байта. Общая длина TLS фейка и длины в структуре TLS Client Hello меняются. Выполняется один раз при старте. Если сочетается с `rndsni`, выполняется до него.
|
||||
* `padencap`. Расширяется padding extension на размер передаваемого TLS Client Hello (включая многопакетный вариант с kyber). Если padding отсутствует, он добавляется в конец. Если присутствует - требуется, чтобы padding шел последним extension. Правятся все длины, чтобы создать видимость включения передаваемого TLS Client Hello в padding extension. Размер фейка не изменяется. Расчет идет на DPI, который не анализирует sequence numbers должным образом. Выполняется на каждый запрос.
|
||||
|
||||
По умолчанию если не задан собственный фейк для TLS используются модификации `rnd,rndsni,dupsid`. Если фейк задан, используется `none`.
|
||||
Это соответствует поведению программы более старых версий с добавлением функции `dupsid`.
|
||||
|
||||
Если задан режим модификации и имеется множество TLS фейков, к каждому из них применяется последний режим модификации.
|
||||
Если режим модификации задан после фейка, то он замещает предыдущий режим.
|
||||
Таким образом можно использовать разные режимы модификации для разных фейков.
|
||||
При невозможности модифицировать фейк на этапе запуска программа завершается с ошибкой.
|
||||
|
||||
Если сначала идет TLS фейк, для него задан режим однократной модификации, затем идет не TLS фейк, то будет ошибка.
|
||||
Нужно использовать `--dpi-desync-fake-tls-mod=none'.
|
||||
|
||||
Пример : `--dpi-desync-fake-tls=iana_org.bin --dpi-desync-fake-tls-mod=rndsni --dpi-desync-fake-tls=0xaabbccdd --dpi-desync-fake-tls-mod=none'
|
||||
|
||||
### TCP СЕГМЕНТАЦИЯ
|
||||
|
||||
* `multisplit`. нарезаем запрос на указанных в `--dpi-desync-split-pos` позициях.
|
||||
@@ -568,7 +585,8 @@ chrome рандомизирует фингерпринт TLS. SNI может о
|
||||
На текущий момент работает только с DHT.
|
||||
Поддерживается определение пакетов QUIC Initial с расшифровкой содержимого и имени хоста, то есть параметр
|
||||
`--hostlist` будет работать.
|
||||
Определяются пакеты wireguard handshake initiation и DHT (начинается с 'd1', кончается 'e').
|
||||
Определяются пакеты wireguard handshake initiation, DHT (начинается с 'd1', кончается 'e'), STUN и
|
||||
[Discord Voice IP Discovery](https://discord.com/developers/docs/topics/voice-connections#ip-discovery).
|
||||
Для десинхронизации других протоколов обязательно указывать `--dpi-desync-any-protocol`.
|
||||
Реализован conntrack для udp. Можно пользоваться --dpi-desync-cutoff. Таймаут conntrack для udp
|
||||
можно изменить 4-м параметром в `--ctrack-timeouts`.
|
||||
@@ -2350,12 +2368,8 @@ VPS можно приобрести в множестве мест. Сущест
|
||||
|
||||
## Поддержать разработчика
|
||||
|
||||
<img src=https://cdn-icons-png.flaticon.com/16/14446/14446252.png alt="USDT" style="vertical-align: middle;"/> USDT
|
||||
```
|
||||
0x3d52Ce15B7Be734c53fc9526ECbAB8267b63d66E
|
||||
```
|
||||
USDT `0x3d52Ce15B7Be734c53fc9526ECbAB8267b63d66E`
|
||||
|
||||
<img src=https://cdn-icons-png.flaticon.com/16/5968/5968260.png alt="USDT" style="vertical-align: middle;"/> BTC
|
||||
```
|
||||
bc1qhqew3mrvp47uk2vevt5sctp7p2x9m7m5kkchve
|
||||
```
|
||||
BTC `bc1qhqew3mrvp47uk2vevt5sctp7p2x9m7m5kkchve`
|
||||
|
||||
ETH `0x3d52Ce15B7Be734c53fc9526ECbAB8267b63d66E`
|
||||
|
BIN
files/fake/discord-ip-discovery-with-port.bin
Normal file
BIN
files/fake/discord-ip-discovery-with-port.bin
Normal file
Binary file not shown.
BIN
files/fake/discord-ip-discovery-without-port.bin
Normal file
BIN
files/fake/discord-ip-discovery-without-port.bin
Normal file
Binary file not shown.
BIN
files/fake/isakmp_initiator_request.bin
Normal file
BIN
files/fake/isakmp_initiator_request.bin
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
files/fake/stun.bin
Normal file
BIN
files/fake/stun.bin
Normal file
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
144
init.d/custom.d.examples.linux/50-nfqws-ipset
Normal file
144
init.d/custom.d.examples.linux/50-nfqws-ipset
Normal file
@@ -0,0 +1,144 @@
|
||||
# this custom script demonstrates how to launch extra nfqws instance limited by ipset
|
||||
|
||||
# can override in config :
|
||||
NFQWS_MY1_OPT="${NFQWS_MY1_OPT:---filter-udp=* --dpi-desync=fake --dpi-desync-repeats=6 --dpi-desync-any-protocol --new --filter-tcp=* --dpi-desync=multisplit}"
|
||||
NFQWS_MY1_SUBNETS4="${NFQWS_MY1_SUBNETS4:-173.194.0.0/16 108.177.0.0/17 74.125.0.0/16 64.233.160.0/19 172.217.0.0/16}"
|
||||
NFQWS_MY1_SUBNETS6="${NFQWS_MY1_SUBNETS6:-2a00:1450::/29}"
|
||||
NFQWS_MY1_PORTS_TCP=${NFQWS_MY1_PORTS_TCP:-$NFQWS_PORTS_TCP}
|
||||
NFQWS_MY1_PORTS_UDP=${NFQWS_MY1_PORTS_UDP:-$NFQWS_PORTS_UDP}
|
||||
NFQWS_MY1_TCP_PKT_OUT=${NFQWS_MY1_TCP_PKT_OUT:-$NFQWS_TCP_PKT_OUT}
|
||||
NFQWS_MY1_UDP_PKT_OUT=${NFQWS_MY1_UDP_PKT_OUT:-$NFQWS_UDP_PKT_OUT}
|
||||
NFQWS_MY1_TCP_PKT_IN=${NFQWS_MY1_TCP_PKT_IN:-$NFQWS_TCP_PKT_IN}
|
||||
NFQWS_MY1_UDP_PKT_IN=${NFQWS_MY1_UDP_PKT_IN:-$NFQWS_UDP_PKT_IN}
|
||||
|
||||
NFQWS_MY1_IPSET_SIZE=${NFQWS_MY1_IPSET_SIZE:-4096}
|
||||
NFQWS_MY1_IPSET_OPT="${NFQWS_MY1_IPSET_OPT:-hash:net hashsize 8192 maxelem $NFQWS_MY1_IPSET_SIZE}"
|
||||
|
||||
alloc_dnum DNUM_NFQWS_MY1
|
||||
alloc_qnum QNUM_NFQWS_MY1
|
||||
NFQWS_MY1_NAME4=my1nfqws4
|
||||
NFQWS_MY1_NAME6=my1nfqws6
|
||||
|
||||
zapret_custom_daemons()
|
||||
{
|
||||
# $1 - 1 - run, 0 - stop
|
||||
|
||||
local opt="--qnum=$QNUM_NFQWS_MY1 $NFQWS_MY1_OPT"
|
||||
do_nfqws $1 $DNUM_NFQWS_MY1 "$opt"
|
||||
}
|
||||
|
||||
zapret_custom_firewall()
|
||||
{
|
||||
# $1 - 1 - run, 0 - stop
|
||||
|
||||
local f4 f6 subnet
|
||||
local NFQWS_MY1_PORTS_TCP=$(replace_char - : $NFQWS_MY1_PORTS_TCP)
|
||||
local NFQWS_MY1_PORTS_UDP=$(replace_char - : $NFQWS_MY1_PORTS_UDP)
|
||||
|
||||
[ "$1" = 1 -a "$DISABLE_IPV4" != 1 ] && {
|
||||
ipset create $NFQWS_MY1_NAME4 $NFQWS_MY1_IPSET_OPT family inet 2>/dev/null
|
||||
ipset flush $NFQWS_MY1_NAME4
|
||||
for subnet in $NFQWS_MY1_SUBNETS4; do
|
||||
echo add $NFQWS_MY1_NAME4 $subnet
|
||||
done | ipset -! restore
|
||||
}
|
||||
[ "$1" = 1 -a "$DISABLE_IPV6" != 1 ] && {
|
||||
ipset create $NFQWS_MY1_NAME6 $NFQWS_MY1_IPSET_OPT family inet6 2>/dev/null
|
||||
ipset flush $NFQWS_MY1_NAME6
|
||||
for subnet in $NFQWS_MY1_SUBNETS6; do
|
||||
echo add $NFQWS_MY1_NAME6 $subnet
|
||||
done | ipset -! restore
|
||||
}
|
||||
|
||||
[ -n "$NFQWS_MY1_PORTS_TCP" ] && {
|
||||
[ -n "$NFQWS_MY1_TCP_PKT_OUT" -a "$NFQWS_MY1_TCP_PKT_OUT" != 0 ] && {
|
||||
f4="-p tcp -m multiport --dports $NFQWS_MY1_PORTS_TCP $ipt_connbytes 1:$NFQWS_MY1_TCP_PKT_OUT -m set --match-set"
|
||||
f6="$f4 $NFQWS_MY1_NAME6 dst"
|
||||
f4="$f4 $NFQWS_MY1_NAME4 dst"
|
||||
fw_nfqws_post $1 "$f4" "$f6" $QNUM_NFQWS_MY1
|
||||
}
|
||||
[ -n "$NFQWS_MY1_TCP_PKT_IN" -a "$NFQWS_MY1_TCP_PKT_IN" != 0 ] && {
|
||||
f4="-p tcp -m multiport --sports $NFQWS_MY1_PORTS_TCP $ipt_connbytes 1:$NFQWS_MY1_TCP_PKT_IN -m set --match-set"
|
||||
f6="$f4 $NFQWS_MY1_NAME6 src"
|
||||
f4="$f4 $NFQWS_MY1_NAME4 src"
|
||||
fw_nfqws_pre $1 "$f4" "$f6" $QNUM_NFQWS_MY1
|
||||
}
|
||||
}
|
||||
[ -n "$NFQWS_MY1_PORTS_UDP" ] && {
|
||||
[ -n "$NFQWS_MY1_UDP_PKT_OUT" -a "$NFQWS_MY1_UDP_PKT_OUT" != 0 ] && {
|
||||
f4="-p udp -m multiport --dports $NFQWS_MY1_PORTS_UDP $ipt_connbytes 1:$NFQWS_MY1_UDP_PKT_OUT -m set --match-set"
|
||||
f6="$f4 $NFQWS_MY1_NAME6 dst"
|
||||
f4="$f4 $NFQWS_MY1_NAME4 dst"
|
||||
fw_nfqws_post $1 "$f4" "$f6" $QNUM_NFQWS_MY1
|
||||
}
|
||||
[ -n "$NFQWS_MY1_UDP_PKT_IN" -a "$NFQWS_MY1_UDP_PKT_IN" != 0 ] && {
|
||||
f4="-p udp -m multiport --sports $NFQWS_MY1_PORTS_UDP $ipt_connbytes 1:$NFQWS_MY1_UDP_PKT_IN -m set --match-set"
|
||||
f6="$f4 $NFQWS_MY1_NAME6 src"
|
||||
f4="$f4 $NFQWS_MY1_NAME4 src"
|
||||
fw_nfqws_pre $1 "$f4" "$f6" $QNUM_NFQWS_MY1
|
||||
}
|
||||
}
|
||||
|
||||
[ "$1" = 1 ] || {
|
||||
ipset destroy $NFQWS_MY1_NAME4 2>/dev/null
|
||||
ipset destroy $NFQWS_MY1_NAME6 2>/dev/null
|
||||
}
|
||||
}
|
||||
|
||||
zapret_custom_firewall_nft()
|
||||
{
|
||||
local f4 f6 subnets
|
||||
local first_packets_only="$nft_connbytes 1-$NFQWS_MY1_PKT_OUT"
|
||||
|
||||
[ "$DISABLE_IPV4" != 1 ] && {
|
||||
make_comma_list subnets $NFQWS_MY1_SUBNETS4
|
||||
nft_create_set $NFQWS_MY1_NAME4 "type ipv4_addr; size $NFQWS_MY1_IPSET_SIZE; auto-merge; flags interval;"
|
||||
nft_flush_set $NFQWS_MY1_NAME4
|
||||
nft_add_set_element $NFQWS_MY1_NAME4 "$subnets"
|
||||
}
|
||||
[ "$DISABLE_IPV6" != 1 ] && {
|
||||
make_comma_list subnets $NFQWS_MY1_SUBNETS6
|
||||
nft_create_set $NFQWS_MY1_NAME6 "type ipv6_addr; size $NFQWS_MY1_IPSET_SIZE; auto-merge; flags interval;"
|
||||
nft_flush_set $NFQWS_MY1_NAME6
|
||||
nft_add_set_element $NFQWS_MY1_NAME6 "$subnets"
|
||||
}
|
||||
|
||||
[ -n "$NFQWS_MY1_PORTS_TCP" ] && {
|
||||
[ -n "$NFQWS_MY1_TCP_PKT_OUT" -a "$NFQWS_MY1_TCP_PKT_OUT" != 0 ] && {
|
||||
f4="tcp dport {$NFQWS_MY1_PORTS_TCP} $(nft_first_packets $NFQWS_MY1_TCP_PKT_OUT)"
|
||||
f6="$f4 ip6 daddr @$NFQWS_MY1_NAME6"
|
||||
f4="$f4 ip daddr @$NFQWS_MY1_NAME4"
|
||||
nft_fw_nfqws_post $1 "$f4" "$f6" $QNUM_NFQWS_MY1
|
||||
}
|
||||
[ -n "$NFQWS_MY1_TCP_PKT_IN" -a "$NFQWS_MY1_TCP_PKT_IN" != 0 ] && {
|
||||
f4="tcp sport {$NFQWS_MY1_PORTS_TCP} $(nft_first_packets $NFQWS_MY1_TCP_PKT_IN)"
|
||||
f6="$f4 ip6 saddr @$NFQWS_MY1_NAME6"
|
||||
f4="$f4 ip saddr @$NFQWS_MY1_NAME4"
|
||||
nft_fw_nfqws_pre $1 "$f4" "$f6" $QNUM_NFQWS_MY1
|
||||
}
|
||||
}
|
||||
[ -n "$NFQWS_MY1_PORTS_UDP" ] && {
|
||||
[ -n "$NFQWS_MY1_UDP_PKT_OUT" -a "$NFQWS_MY1_UDP_PKT_OUT" != 0 ] && {
|
||||
f4="udp dport {$NFQWS_MY1_PORTS_UDP} $(nft_first_packets $NFQWS_MY1_UDP_PKT_OUT)"
|
||||
f6="$f4 ip6 daddr @$NFQWS_MY1_NAME6"
|
||||
f4="$f4 ip daddr @$NFQWS_MY1_NAME4"
|
||||
nft_fw_nfqws_post $1 "$f4" "$f6" $QNUM_NFQWS_MY1
|
||||
}
|
||||
[ -n "$NFQWS_MY1_UDP_PKT_IN" -a "$NFQWS_MY1_UDP_PKT_IN" != 0 ] && {
|
||||
f4="udp sport {$NFQWS_MY1_PORTS_UDP} $(nft_first_packets $NFQWS_MY1_UDP_PKT_IN)"
|
||||
f6="$f4 ip6 saddr @$NFQWS_MY1_NAME6"
|
||||
f4="$f4 ip saddr @$NFQWS_MY1_NAME4"
|
||||
nft_fw_nfqws_pre $1 "$f4" "$f6" $QNUM_NFQWS_MY1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
zapret_custom_firewall_nft_flush()
|
||||
{
|
||||
# this function is called after all nft fw rules are deleted
|
||||
# however sets are not deleted. it's desired to clear sets here.
|
||||
|
||||
nft_del_set $NFQWS_MY1_NAME4 2>/dev/null
|
||||
nft_del_set $NFQWS_MY1_NAME6 2>/dev/null
|
||||
}
|
@@ -28,7 +28,6 @@ zapret_custom_firewall()
|
||||
|
||||
local f4 f6 subnet
|
||||
local PORTS_IPT=$(replace_char - : $TPWS_MY1_PORTS)
|
||||
local dest_set="-m set --match-set $TPWS_MY1_NAME4 dst"
|
||||
|
||||
[ "$1" = 1 -a "$DISABLE_IPV4" != 1 ] && {
|
||||
ipset create $TPWS_MY1_NAME4 $TPWS_MY1_IPSET_OPT family inet 2>/dev/null
|
||||
@@ -58,7 +57,7 @@ zapret_custom_firewall()
|
||||
|
||||
zapret_custom_firewall_nft()
|
||||
{
|
||||
local f4 f6 subnet
|
||||
local f4 f6 subnets
|
||||
|
||||
[ "$DISABLE_IPV4" != 1 ] && {
|
||||
make_comma_list subnets $TPWS_MY1_SUBNETS4
|
||||
|
@@ -1,7 +1,7 @@
|
||||
# Example systemd service unit for nfqws. Adjust for your installation.
|
||||
|
||||
# WARNING ! This unit requires to compile nfqws using `make systemd`
|
||||
# WARNING ! This makefile target enabled special systemd notify support.
|
||||
# WARNING ! This makefile target enables special systemd notify support.
|
||||
|
||||
# PREPARE
|
||||
# install build depends
|
||||
|
@@ -1,7 +1,7 @@
|
||||
# Example systemd service unit for tpws. Adjust for your installation.
|
||||
|
||||
# WARNING ! This unit requires to compile tpws using `make systemd`
|
||||
# WARNING ! This makefile target enabled special systemd notify support.
|
||||
# WARNING ! This makefile target enables special systemd notify support.
|
||||
|
||||
# PREPARE
|
||||
# install build depends
|
||||
|
@@ -225,6 +225,28 @@ static void exithelp(void)
|
||||
#define PRINT_VER printf("self-built version %s %s\n\n", __DATE__, __TIME__)
|
||||
#endif
|
||||
|
||||
enum opt_indices {
|
||||
IDX_HELP,
|
||||
IDX_H,
|
||||
IDX_4,
|
||||
IDX_6,
|
||||
IDX_PREFIX_LENGTH,
|
||||
IDX_V4_THRESHOLD,
|
||||
IDX_V6_THRESHOLD,
|
||||
IDX_LAST,
|
||||
};
|
||||
|
||||
static const struct option long_options[] = {
|
||||
[IDX_HELP] = {"help", no_argument, 0, 0},
|
||||
[IDX_H] = {"h", no_argument, 0, 0},
|
||||
[IDX_4] = {"4", no_argument, 0, 0},
|
||||
[IDX_6] = {"6", no_argument, 0, 0},
|
||||
[IDX_PREFIX_LENGTH] = {"prefix-length", required_argument, 0, 0},
|
||||
[IDX_V4_THRESHOLD] = {"v4-threshold", required_argument, 0, 0},
|
||||
[IDX_V6_THRESHOLD] = {"v6-threshold", required_argument, 0, 0},
|
||||
[IDX_LAST] = {NULL, 0, NULL, 0},
|
||||
};
|
||||
|
||||
static void parse_params(int argc, char *argv[])
|
||||
{
|
||||
int option_index = 0;
|
||||
@@ -236,33 +258,23 @@ static void parse_params(int argc, char *argv[])
|
||||
params.pctdiv = DEFAULT_PCTDIV;
|
||||
params.v6_threshold = DEFAULT_V6_THRESHOLD;
|
||||
|
||||
const struct option long_options[] = {
|
||||
{ "help",no_argument,0,0 },// optidx=0
|
||||
{ "h",no_argument,0,0 },// optidx=1
|
||||
{ "4",no_argument,0,0 },// optidx=2
|
||||
{ "6",no_argument,0,0 },// optidx=3
|
||||
{ "prefix-length",required_argument,0,0 },// optidx=4
|
||||
{ "v4-threshold",required_argument,0,0 },// optidx=5
|
||||
{ "v6-threshold",required_argument,0,0 },// optidx=6
|
||||
{ NULL,0,NULL,0 }
|
||||
};
|
||||
while ((v = getopt_long_only(argc, argv, "", long_options, &option_index)) != -1)
|
||||
{
|
||||
if (v) exithelp();
|
||||
switch (option_index)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case IDX_HELP:
|
||||
case IDX_H:
|
||||
PRINT_VER;
|
||||
exithelp();
|
||||
break;
|
||||
case 2:
|
||||
case IDX_4:
|
||||
params.ipv6 = false;
|
||||
break;
|
||||
case 3:
|
||||
case IDX_6:
|
||||
params.ipv6 = true;
|
||||
break;
|
||||
case 4:
|
||||
case IDX_PREFIX_LENGTH:
|
||||
i = sscanf(optarg,"%u-%u",&plen1,&plen2);
|
||||
if (i == 1) plen2 = plen1;
|
||||
if (i<=0 || plen2<plen1 || !plen1 || !plen2)
|
||||
@@ -271,7 +283,7 @@ static void parse_params(int argc, char *argv[])
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
case IDX_V4_THRESHOLD:
|
||||
i = sscanf(optarg, "%u/%u", ¶ms.pctmult, ¶ms.pctdiv);
|
||||
if (i!=2 || params.pctdiv<2 || params.pctmult<1 || params.pctmult>=params.pctdiv)
|
||||
{
|
||||
@@ -279,7 +291,7 @@ static void parse_params(int argc, char *argv[])
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
case IDX_V6_THRESHOLD:
|
||||
i = sscanf(optarg, "%u", ¶ms.v6_threshold);
|
||||
if (i != 1 || params.v6_threshold<1)
|
||||
{
|
||||
|
@@ -274,7 +274,9 @@ hup_zapret_daemons()
|
||||
if exists killall; then
|
||||
killall -HUP tpws nfqws dvtws 2>/dev/null
|
||||
elif exists pkill; then
|
||||
pkill -HUP ^tpws$ ^nfqws$ ^dvtws$
|
||||
pkill -HUP ^tpws$
|
||||
pkill -HUP ^nfqws$
|
||||
pkill -HUP ^dvtws$
|
||||
else
|
||||
echo no mass killer available ! cant HUP zapret daemons
|
||||
fi
|
||||
|
57
mdig/mdig.c
57
mdig/mdig.c
@@ -467,25 +467,38 @@ static void exithelp(void)
|
||||
#define PRINT_VER printf("self-built version %s %s\n\n", __DATE__, __TIME__)
|
||||
#endif
|
||||
|
||||
enum opt_indices {
|
||||
IDX_HELP,
|
||||
IDX_THREADS,
|
||||
IDX_FAMILY,
|
||||
IDX_VERBOSE,
|
||||
IDX_STATS,
|
||||
IDX_LOG_RESOLVED,
|
||||
IDX_LOG_FAILED,
|
||||
IDX_DNS_MAKE_QUERY,
|
||||
IDX_DNS_PARSE_QUERY,
|
||||
IDX_LAST,
|
||||
};
|
||||
|
||||
static const struct option long_options[] = {
|
||||
[IDX_HELP] = {"help", no_argument, 0, 0},
|
||||
[IDX_THREADS] = {"threads", required_argument, 0, 0},
|
||||
[IDX_FAMILY] = {"family", required_argument, 0, 0},
|
||||
[IDX_VERBOSE] = {"verbose", no_argument, 0, 0},
|
||||
[IDX_STATS] = {"stats", required_argument, 0, 0},
|
||||
[IDX_LOG_RESOLVED] = {"log-resolved", required_argument, 0, 0},
|
||||
[IDX_LOG_FAILED] = {"log-failed", required_argument, 0, 0},
|
||||
[IDX_DNS_MAKE_QUERY] = {"dns-make-query", required_argument, 0, 0},
|
||||
[IDX_DNS_PARSE_QUERY] = {"dns-parse-query", no_argument, 0, 0},
|
||||
[IDX_LAST] = {NULL, 0, NULL, 0},
|
||||
};
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int r, v, option_index = 0;
|
||||
char fn1[256],fn2[256];
|
||||
char dom[256];
|
||||
|
||||
static const struct option long_options[] = {
|
||||
{"help",no_argument,0,0}, // optidx=0
|
||||
{"threads",required_argument,0,0}, // optidx=1
|
||||
{"family",required_argument,0,0}, // optidx=2
|
||||
{"verbose",no_argument,0,0}, // optidx=3
|
||||
{"stats",required_argument,0,0}, // optidx=4
|
||||
{"log-resolved",required_argument,0,0}, // optidx=5
|
||||
{"log-failed",required_argument,0,0}, // optidx=6
|
||||
{"dns-make-query",required_argument,0,0}, // optidx=7
|
||||
{"dns-parse-query",no_argument,0,0}, // optidx=8
|
||||
{NULL,0,NULL,0}
|
||||
};
|
||||
|
||||
memset(&glob, 0, sizeof(glob));
|
||||
*fn1 = *fn2 = *dom = 0;
|
||||
glob.family = FAMILY4;
|
||||
@@ -495,11 +508,11 @@ int main(int argc, char **argv)
|
||||
if (v) exithelp();
|
||||
switch (option_index)
|
||||
{
|
||||
case 0: /* help */
|
||||
case IDX_HELP:
|
||||
PRINT_VER;
|
||||
exithelp();
|
||||
break;
|
||||
case 1: /* threads */
|
||||
case IDX_THREADS:
|
||||
glob.threads = optarg ? atoi(optarg) : 0;
|
||||
if (glob.threads <= 0 || glob.threads > 100)
|
||||
{
|
||||
@@ -507,7 +520,7 @@ int main(int argc, char **argv)
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case 2: /* family */
|
||||
case IDX_FAMILY:
|
||||
if (!strcmp(optarg, "4"))
|
||||
glob.family = FAMILY4;
|
||||
else if (!strcmp(optarg, "6"))
|
||||
@@ -520,25 +533,25 @@ int main(int argc, char **argv)
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case 3: /* verbose */
|
||||
case IDX_VERBOSE:
|
||||
glob.verbose = '\1';
|
||||
break;
|
||||
case 4: /* stats */
|
||||
case IDX_STATS:
|
||||
glob.stats_every = optarg ? atoi(optarg) : 0;
|
||||
break;
|
||||
case 5: /* log-resolved */
|
||||
case IDX_LOG_RESOLVED:
|
||||
strncpy(fn1,optarg,sizeof(fn1));
|
||||
fn1[sizeof(fn1)-1] = 0;
|
||||
break;
|
||||
case 6: /* log-failed */
|
||||
case IDX_LOG_FAILED:
|
||||
strncpy(fn2,optarg,sizeof(fn2));
|
||||
fn2[sizeof(fn2)-1] = 0;
|
||||
break;
|
||||
case 7: /* dns-make-query */
|
||||
case IDX_DNS_MAKE_QUERY:
|
||||
strncpy(dom,optarg,sizeof(dom));
|
||||
dom[sizeof(dom)-1] = 0;
|
||||
break;
|
||||
case 8: /* dns-parse-query */
|
||||
case IDX_DNS_PARSE_QUERY:
|
||||
return dns_parse_query();
|
||||
}
|
||||
}
|
||||
|
Binary file not shown.
Binary file not shown.
@@ -143,8 +143,11 @@ static void ConntrackFeedPacket(t_ctrack *t, bool bReverse, const struct tcphdr
|
||||
}
|
||||
else if (tcp_synack_segment(tcphdr))
|
||||
{
|
||||
if (t->state!=SYN) ConntrackReInitTrack(t); // erase current entry
|
||||
if (!t->seq0) t->seq0 = ntohl(tcphdr->th_ack)-1;
|
||||
// ignore SA dups
|
||||
uint32_t seq0 = ntohl(tcphdr->th_ack)-1;
|
||||
if (t->state!=SYN && t->seq0!=seq0)
|
||||
ConntrackReInitTrack(t); // erase current entry
|
||||
if (!t->seq0) t->seq0 = seq0;
|
||||
t->ack0 = ntohl(tcphdr->th_seq);
|
||||
}
|
||||
else if (tcphdr->th_flags & (TH_FIN|TH_RST))
|
||||
@@ -338,8 +341,8 @@ void ConntrackPoolDump(const t_conntrack *p)
|
||||
printf("rseq=%u pos_orig=%u rack=%u pos_reply=%u",
|
||||
t->track.seq_last, t->track.pos_orig,
|
||||
t->track.ack_last, t->track.pos_reply);
|
||||
printf(" req_retrans=%u cutoff=%u wss_cutoff=%u d_cutoff=%u hostname=%s l7proto=%s\n",
|
||||
t->track.req_retrans_counter, t->track.b_cutoff, t->track.b_wssize_cutoff, t->track.b_desync_cutoff, t->track.hostname, l7proto_str(t->track.l7proto));
|
||||
printf(" req_retrans=%u cutoff=%u wss_cutoff=%u desync_cutoff=%u dup_cutoff=%u orig_cutoff=%u hostname=%s l7proto=%s\n",
|
||||
t->track.req_retrans_counter, t->track.b_cutoff, t->track.b_wssize_cutoff, t->track.b_desync_cutoff, t->track.b_dup_cutoff, t->track.b_orig_mod_cutoff, t->track.hostname, l7proto_str(t->track.l7proto));
|
||||
};
|
||||
}
|
||||
|
||||
|
@@ -77,14 +77,16 @@ typedef struct
|
||||
bool req_seq_present,req_seq_finalized,req_seq_abandoned;
|
||||
uint32_t req_seq_start,req_seq_end; // sequence interval of the request (to track retransmissions)
|
||||
|
||||
uint8_t incoming_ttl, autottl;
|
||||
uint8_t incoming_ttl, desync_autottl, orig_autottl, dup_autottl;
|
||||
bool b_autottl_discovered;
|
||||
|
||||
bool b_cutoff; // mark for deletion
|
||||
bool b_wssize_cutoff, b_desync_cutoff;
|
||||
bool b_wssize_cutoff, b_desync_cutoff, b_dup_cutoff, b_orig_mod_cutoff;
|
||||
|
||||
t_l7proto l7proto;
|
||||
bool l7proto_discovered;
|
||||
char *hostname;
|
||||
bool hostname_discovered;
|
||||
bool hostname_ah_check; // should perform autohostlist checks
|
||||
|
||||
t_reassemble reasm_orig;
|
||||
|
153
nfq/darkmagic.c
153
nfq/darkmagic.c
@@ -38,6 +38,11 @@ uint32_t net16_add(uint16_t netorder_value, uint16_t cpuorder_increment)
|
||||
return htons(ntohs(netorder_value)+cpuorder_increment);
|
||||
}
|
||||
|
||||
bool ip_has_df(const struct ip *ip)
|
||||
{
|
||||
return ip && !!(ntohs(ip->ip_off) & IP_DF);
|
||||
}
|
||||
|
||||
uint8_t *tcp_find_option(struct tcphdr *tcp, uint8_t kind)
|
||||
{
|
||||
uint8_t *t = (uint8_t*)(tcp+1);
|
||||
@@ -83,10 +88,22 @@ bool tcp_has_fastopen(const struct tcphdr *tcp)
|
||||
opt = tcp_find_option((struct tcphdr*)tcp, 254);
|
||||
return opt && opt[1]>=4 && opt[2]==0xF9 && opt[3]==0x89;
|
||||
}
|
||||
uint16_t tcp_find_mss(struct tcphdr *tcp)
|
||||
{
|
||||
uint8_t *t = tcp_find_option(tcp,2);
|
||||
return (t && t[1]==4) ? *(uint16_t*)(t+2) : 0;
|
||||
}
|
||||
bool tcp_has_sack(struct tcphdr *tcp)
|
||||
{
|
||||
uint8_t *t = tcp_find_option(tcp,4);
|
||||
return !!t;
|
||||
}
|
||||
|
||||
// n prefix (nsport, nwsize) means network byte order
|
||||
static void fill_tcphdr(
|
||||
struct tcphdr *tcp, uint32_t fooling, uint8_t tcp_flags,
|
||||
bool sack,
|
||||
uint16_t nmss,
|
||||
uint32_t nseq, uint32_t nack_seq,
|
||||
uint16_t nsport, uint16_t ndport,
|
||||
uint16_t nwsize, uint8_t scale_factor,
|
||||
@@ -116,15 +133,27 @@ static void fill_tcphdr(
|
||||
tcp_flags &= ~TH_ACK;
|
||||
*((uint8_t*)tcp+13)= tcp_flags;
|
||||
tcp->th_win = nwsize;
|
||||
if (nmss)
|
||||
{
|
||||
tcpopt[t++] = 2; // kind
|
||||
tcpopt[t++] = 4; // len
|
||||
*(uint16_t*)(tcpopt+t) = nmss;
|
||||
t+=2;
|
||||
}
|
||||
if (sack)
|
||||
{
|
||||
tcpopt[t++] = 4; // kind
|
||||
tcpopt[t++] = 2; // len
|
||||
}
|
||||
if (fooling & FOOL_MD5SIG)
|
||||
{
|
||||
tcpopt[0] = 19; // kind
|
||||
tcpopt[1] = 18; // len
|
||||
*(uint32_t*)(tcpopt+2)=random();
|
||||
*(uint32_t*)(tcpopt+6)=random();
|
||||
*(uint32_t*)(tcpopt+10)=random();
|
||||
*(uint32_t*)(tcpopt+14)=random();
|
||||
t=18;
|
||||
tcpopt[t] = 19; // kind
|
||||
tcpopt[t+1] = 18; // len
|
||||
*(uint32_t*)(tcpopt+t+2)=random();
|
||||
*(uint32_t*)(tcpopt+t+6)=random();
|
||||
*(uint32_t*)(tcpopt+t+10)=random();
|
||||
*(uint32_t*)(tcpopt+t+14)=random();
|
||||
t+=18;
|
||||
}
|
||||
if (timestamps || (fooling & FOOL_TS))
|
||||
{
|
||||
@@ -145,10 +174,12 @@ static void fill_tcphdr(
|
||||
tcp->th_off += t>>2;
|
||||
tcp->th_sum = 0;
|
||||
}
|
||||
static uint16_t tcpopt_len(uint32_t fooling, const uint32_t *timestamps, uint8_t scale_factor)
|
||||
static uint16_t tcpopt_len(bool sack, bool mss, uint32_t fooling, const uint32_t *timestamps, uint8_t scale_factor)
|
||||
{
|
||||
uint16_t t=0;
|
||||
if (fooling & FOOL_MD5SIG) t=18;
|
||||
if (sack) t+=2;
|
||||
if (mss) t+=4;
|
||||
if (fooling & FOOL_MD5SIG) t+=18;
|
||||
if ((fooling & FOOL_TS) || timestamps) t+=10;
|
||||
if (scale_factor!=SCALE_NONE) t+=3;
|
||||
return (t+3)&~3;
|
||||
@@ -163,11 +194,11 @@ static void fill_udphdr(struct udphdr *udp, uint16_t nsport, uint16_t ndport, ui
|
||||
udp->uh_sum = 0;
|
||||
}
|
||||
|
||||
static void fill_iphdr(struct ip *ip, const struct in_addr *src, const struct in_addr *dst, uint16_t pktlen, uint8_t proto, uint8_t ttl, uint8_t tos, uint16_t ip_id)
|
||||
static void fill_iphdr(struct ip *ip, const struct in_addr *src, const struct in_addr *dst, uint16_t pktlen, uint8_t proto, bool DF, uint8_t ttl, uint8_t tos, uint16_t ip_id)
|
||||
{
|
||||
ip->ip_tos = tos;
|
||||
ip->ip_sum = 0;
|
||||
ip->ip_off = 0;
|
||||
ip->ip_off = DF ? htons(IP_DF) : 0;
|
||||
ip->ip_v = 4;
|
||||
ip->ip_hl = 5;
|
||||
ip->ip_len = htons(pktlen);
|
||||
@@ -190,10 +221,13 @@ static void fill_ip6hdr(struct ip6_hdr *ip6, const struct in6_addr *src, const s
|
||||
bool prepare_tcp_segment4(
|
||||
const struct sockaddr_in *src, const struct sockaddr_in *dst,
|
||||
uint8_t tcp_flags,
|
||||
bool sack,
|
||||
uint16_t nmss,
|
||||
uint32_t nseq, uint32_t nack_seq,
|
||||
uint16_t nwsize,
|
||||
uint8_t scale_factor,
|
||||
uint32_t *timestamps,
|
||||
bool DF,
|
||||
uint8_t ttl,
|
||||
uint8_t tos,
|
||||
uint16_t ip_id,
|
||||
@@ -203,7 +237,7 @@ bool prepare_tcp_segment4(
|
||||
const void *data, uint16_t len,
|
||||
uint8_t *buf, size_t *buflen)
|
||||
{
|
||||
uint16_t tcpoptlen = tcpopt_len(fooling,timestamps,scale_factor);
|
||||
uint16_t tcpoptlen = tcpopt_len(sack,!!nmss,fooling,timestamps,scale_factor);
|
||||
uint16_t ip_payload_len = sizeof(struct tcphdr) + tcpoptlen + len;
|
||||
uint16_t pktlen = sizeof(struct ip) + ip_payload_len;
|
||||
if (pktlen>*buflen) return false;
|
||||
@@ -212,12 +246,12 @@ bool prepare_tcp_segment4(
|
||||
struct tcphdr *tcp = (struct tcphdr*)(ip+1);
|
||||
uint8_t *payload = (uint8_t*)(tcp+1)+tcpoptlen;
|
||||
|
||||
fill_iphdr(ip, &src->sin_addr, &dst->sin_addr, pktlen, IPPROTO_TCP, ttl, tos, ip_id);
|
||||
fill_tcphdr(tcp,fooling,tcp_flags,nseq,nack_seq,src->sin_port,dst->sin_port,nwsize,scale_factor,timestamps,badseq_increment,badseq_ack_increment,len);
|
||||
fill_iphdr(ip, &src->sin_addr, &dst->sin_addr, pktlen, IPPROTO_TCP, DF, ttl, tos, ip_id);
|
||||
fill_tcphdr(tcp,fooling,tcp_flags,sack,nmss,nseq,nack_seq,src->sin_port,dst->sin_port,nwsize,scale_factor,timestamps,badseq_increment,badseq_ack_increment,len);
|
||||
|
||||
memcpy(payload,data,len);
|
||||
tcp4_fix_checksum(tcp,ip_payload_len,&ip->ip_src,&ip->ip_dst);
|
||||
if (fooling & FOOL_BADSUM) tcp->th_sum^=htons(0xBEAF);
|
||||
if (fooling & FOOL_BADSUM) tcp->th_sum^=(uint16_t)(1+random()%0xFFFF);
|
||||
|
||||
*buflen = pktlen;
|
||||
return true;
|
||||
@@ -226,6 +260,8 @@ bool prepare_tcp_segment4(
|
||||
bool prepare_tcp_segment6(
|
||||
const struct sockaddr_in6 *src, const struct sockaddr_in6 *dst,
|
||||
uint8_t tcp_flags,
|
||||
bool sack,
|
||||
uint16_t nmss,
|
||||
uint32_t nseq, uint32_t nack_seq,
|
||||
uint16_t nwsize,
|
||||
uint8_t scale_factor,
|
||||
@@ -238,7 +274,7 @@ bool prepare_tcp_segment6(
|
||||
const void *data, uint16_t len,
|
||||
uint8_t *buf, size_t *buflen)
|
||||
{
|
||||
uint16_t tcpoptlen = tcpopt_len(fooling,timestamps,scale_factor);
|
||||
uint16_t tcpoptlen = tcpopt_len(sack,!!nmss,fooling,timestamps,scale_factor);
|
||||
uint16_t transport_payload_len = sizeof(struct tcphdr) + tcpoptlen + len;
|
||||
uint16_t ip_payload_len = transport_payload_len +
|
||||
8*!!((fooling & (FOOL_HOPBYHOP|FOOL_HOPBYHOP2))==FOOL_HOPBYHOP) +
|
||||
@@ -297,11 +333,11 @@ bool prepare_tcp_segment6(
|
||||
uint8_t *payload = (uint8_t*)(tcp+1)+tcpoptlen;
|
||||
|
||||
fill_ip6hdr(ip6, &src->sin6_addr, &dst->sin6_addr, ip_payload_len, proto, ttl, flow_label);
|
||||
fill_tcphdr(tcp,fooling,tcp_flags,nseq,nack_seq,src->sin6_port,dst->sin6_port,nwsize,scale_factor,timestamps,badseq_increment,badseq_ack_increment,len);
|
||||
fill_tcphdr(tcp,fooling,tcp_flags,sack,nmss,nseq,nack_seq,src->sin6_port,dst->sin6_port,nwsize,scale_factor,timestamps,badseq_increment,badseq_ack_increment,len);
|
||||
|
||||
memcpy(payload,data,len);
|
||||
tcp6_fix_checksum(tcp,transport_payload_len,&ip6->ip6_src,&ip6->ip6_dst);
|
||||
if (fooling & FOOL_BADSUM) tcp->th_sum^=htons(0xBEAF);
|
||||
if (fooling & FOOL_BADSUM) tcp->th_sum^=(1+random()%0xFFFF);
|
||||
|
||||
*buflen = pktlen;
|
||||
return true;
|
||||
@@ -310,10 +346,13 @@ bool prepare_tcp_segment6(
|
||||
bool prepare_tcp_segment(
|
||||
const struct sockaddr *src, const struct sockaddr *dst,
|
||||
uint8_t tcp_flags,
|
||||
bool sack,
|
||||
uint16_t nmss,
|
||||
uint32_t nseq, uint32_t nack_seq,
|
||||
uint16_t nwsize,
|
||||
uint8_t scale_factor,
|
||||
uint32_t *timestamps,
|
||||
bool DF,
|
||||
uint8_t ttl,
|
||||
uint8_t tos,
|
||||
uint16_t ip_id,
|
||||
@@ -325,9 +364,9 @@ bool prepare_tcp_segment(
|
||||
uint8_t *buf, size_t *buflen)
|
||||
{
|
||||
return (src->sa_family==AF_INET && dst->sa_family==AF_INET) ?
|
||||
prepare_tcp_segment4((struct sockaddr_in *)src,(struct sockaddr_in *)dst,tcp_flags,nseq,nack_seq,nwsize,scale_factor,timestamps,ttl,tos,ip_id,fooling,badseq_increment,badseq_ack_increment,data,len,buf,buflen) :
|
||||
prepare_tcp_segment4((struct sockaddr_in *)src,(struct sockaddr_in *)dst,tcp_flags,sack,nmss,nseq,nack_seq,nwsize,scale_factor,timestamps,DF,ttl,tos,ip_id,fooling,badseq_increment,badseq_ack_increment,data,len,buf,buflen) :
|
||||
(src->sa_family==AF_INET6 && dst->sa_family==AF_INET6) ?
|
||||
prepare_tcp_segment6((struct sockaddr_in6 *)src,(struct sockaddr_in6 *)dst,tcp_flags,nseq,nack_seq,nwsize,scale_factor,timestamps,ttl,flow_label,fooling,badseq_increment,badseq_ack_increment,data,len,buf,buflen) :
|
||||
prepare_tcp_segment6((struct sockaddr_in6 *)src,(struct sockaddr_in6 *)dst,tcp_flags,sack,nmss,nseq,nack_seq,nwsize,scale_factor,timestamps,ttl,flow_label,fooling,badseq_increment,badseq_ack_increment,data,len,buf,buflen) :
|
||||
false;
|
||||
}
|
||||
|
||||
@@ -335,6 +374,7 @@ bool prepare_tcp_segment(
|
||||
// padlen<0 means payload shrinking
|
||||
bool prepare_udp_segment4(
|
||||
const struct sockaddr_in *src, const struct sockaddr_in *dst,
|
||||
bool DF,
|
||||
uint8_t ttl,
|
||||
uint8_t tos,
|
||||
uint16_t ip_id,
|
||||
@@ -361,7 +401,7 @@ bool prepare_udp_segment4(
|
||||
uint8_t *payload = (uint8_t*)(udp+1);
|
||||
|
||||
|
||||
fill_iphdr(ip, &src->sin_addr, &dst->sin_addr, pktlen, IPPROTO_UDP, ttl, tos, ip_id);
|
||||
fill_iphdr(ip, &src->sin_addr, &dst->sin_addr, pktlen, IPPROTO_UDP, DF, ttl, tos, ip_id);
|
||||
fill_udphdr(udp, src->sin_port, dst->sin_port, datalen);
|
||||
|
||||
memcpy(payload,data,len);
|
||||
@@ -370,7 +410,7 @@ bool prepare_udp_segment4(
|
||||
else
|
||||
memset(payload+len,0,padlen);
|
||||
udp4_fix_checksum(udp,ip_payload_len,&ip->ip_src,&ip->ip_dst);
|
||||
if (fooling & FOOL_BADSUM) udp->uh_sum^=htons(0xBEAF);
|
||||
if (fooling & FOOL_BADSUM) udp->uh_sum^=(1+random()%0xFFFF);
|
||||
|
||||
*buflen = pktlen;
|
||||
return true;
|
||||
@@ -459,13 +499,14 @@ bool prepare_udp_segment6(
|
||||
else
|
||||
memset(payload+len,0,padlen);
|
||||
udp6_fix_checksum(udp,transport_payload_len,&ip6->ip6_src,&ip6->ip6_dst);
|
||||
if (fooling & FOOL_BADSUM) udp->uh_sum^=htons(0xBEAF);
|
||||
if (fooling & FOOL_BADSUM) udp->uh_sum^=(1+random()%0xFFFF);
|
||||
|
||||
*buflen = pktlen;
|
||||
return true;
|
||||
}
|
||||
bool prepare_udp_segment(
|
||||
const struct sockaddr *src, const struct sockaddr *dst,
|
||||
bool DF,
|
||||
uint8_t ttl,
|
||||
uint8_t tos,
|
||||
uint16_t ip_id,
|
||||
@@ -477,7 +518,7 @@ bool prepare_udp_segment(
|
||||
uint8_t *buf, size_t *buflen)
|
||||
{
|
||||
return (src->sa_family==AF_INET && dst->sa_family==AF_INET) ?
|
||||
prepare_udp_segment4((struct sockaddr_in *)src,(struct sockaddr_in *)dst,ttl,tos,ip_id,fooling,padding,padding_size,padlen,data,len,buf,buflen) :
|
||||
prepare_udp_segment4((struct sockaddr_in *)src,(struct sockaddr_in *)dst,DF,ttl,tos,ip_id,fooling,padding,padding_size,padlen,data,len,buf,buflen) :
|
||||
(src->sa_family==AF_INET6 && dst->sa_family==AF_INET6) ?
|
||||
prepare_udp_segment6((struct sockaddr_in6 *)src,(struct sockaddr_in6 *)dst,ttl,flow_label,fooling,padding,padding_size,padlen,data,len,buf,buflen) :
|
||||
false;
|
||||
@@ -601,10 +642,29 @@ bool ip_frag(
|
||||
return false;
|
||||
}
|
||||
|
||||
void rewrite_ttl(struct ip *ip, struct ip6_hdr *ip6, uint8_t ttl)
|
||||
bool rewrite_ttl(struct ip *ip, struct ip6_hdr *ip6, uint8_t ttl)
|
||||
{
|
||||
if (ip) ip->ip_ttl = ttl;
|
||||
if (ip6) ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim = ttl;
|
||||
if (ttl)
|
||||
{
|
||||
if (ip)
|
||||
{
|
||||
if (ip->ip_ttl!=ttl)
|
||||
{
|
||||
ip->ip_ttl = ttl;
|
||||
ip4_fix_checksum(ip);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (ip6)
|
||||
{
|
||||
if (ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim!=ttl)
|
||||
{
|
||||
ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim = ttl;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -1772,16 +1832,15 @@ bool rawsend_queue(struct rawpacket_tailhead *q)
|
||||
}
|
||||
|
||||
|
||||
// return guessed fake ttl value. 0 means unsuccessfull, should not perform autottl fooling
|
||||
// ttl = TTL of incoming packet
|
||||
uint8_t autottl_guess(uint8_t ttl, const autottl *attl)
|
||||
uint8_t hop_count_guess(uint8_t ttl)
|
||||
{
|
||||
uint8_t orig, path, fake;
|
||||
|
||||
// 18.65.168.125 ( cloudfront ) 255
|
||||
// 157.254.246.178 128
|
||||
// 1.1.1.1 64
|
||||
// guess original ttl. consider path lengths less than 32 hops
|
||||
|
||||
uint8_t orig;
|
||||
|
||||
if (ttl>223)
|
||||
orig=255;
|
||||
else if (ttl<128 && ttl>96)
|
||||
@@ -1791,13 +1850,21 @@ uint8_t autottl_guess(uint8_t ttl, const autottl *attl)
|
||||
else
|
||||
return 0;
|
||||
|
||||
path = orig - ttl;
|
||||
return orig - ttl;
|
||||
}
|
||||
// return guessed fake ttl value. 0 means unsuccessfull, should not perform autottl fooling
|
||||
uint8_t autottl_eval(uint8_t hop_count, const autottl *attl)
|
||||
{
|
||||
uint8_t fake;
|
||||
int d;
|
||||
|
||||
fake = path > attl->delta ? path - attl->delta : attl->min;
|
||||
if (fake<attl->min) fake=attl->min;
|
||||
else if (fake>attl->max) fake=attl->max;
|
||||
d = (int)hop_count + attl->delta;
|
||||
if (d<attl->min) fake=attl->min;
|
||||
else if (d>attl->max) fake=attl->max;
|
||||
else fake=(uint8_t)d;
|
||||
|
||||
if (fake>=path) return 0;
|
||||
if (attl->delta<0 && fake>=hop_count || attl->delta>=0 && fake<hop_count)
|
||||
return 0;
|
||||
|
||||
return fake;
|
||||
}
|
||||
@@ -1849,15 +1916,15 @@ void verdict_tcp_csum_fix(uint8_t verdict, struct tcphdr *tcphdr, size_t transpo
|
||||
{
|
||||
if (!(verdict & VERDICT_NOCSUM))
|
||||
{
|
||||
#ifdef __CYGWIN__
|
||||
// always fix csum for windivert. original can be partial or bad
|
||||
#ifndef __CYGWIN__
|
||||
#ifdef __FreeBSD__
|
||||
if ((verdict & VERDICT_MASK)!=VERDICT_DROP)
|
||||
#elif defined(__FreeBSD__)
|
||||
// FreeBSD tend to pass ipv6 frames with wrong checksum
|
||||
if ((verdict & VERDICT_MASK)==VERDICT_MODIFY || ip6hdr)
|
||||
#else
|
||||
// if original packet was tampered earlier it needs checksum fixed
|
||||
if ((verdict & VERDICT_MASK)==VERDICT_MODIFY)
|
||||
#endif
|
||||
#endif
|
||||
tcp_fix_checksum(tcphdr,transport_len,ip,ip6hdr);
|
||||
}
|
||||
@@ -1866,15 +1933,15 @@ void verdict_udp_csum_fix(uint8_t verdict, struct udphdr *udphdr, size_t transpo
|
||||
{
|
||||
if (!(verdict & VERDICT_NOCSUM))
|
||||
{
|
||||
#ifdef __CYGWIN__
|
||||
// always fix csum for windivert. original can be partial or bad
|
||||
#ifndef __CYGWIN__
|
||||
#ifdef __FreeBSD__
|
||||
if ((verdict & VERDICT_MASK)!=VERDICT_DROP)
|
||||
#elif defined(__FreeBSD__)
|
||||
// FreeBSD tend to pass ipv6 frames with wrong checksum
|
||||
if ((verdict & VERDICT_MASK)==VERDICT_MODIFY || ip6hdr)
|
||||
#else
|
||||
// if original packet was tampered earlier it needs checksum fixed
|
||||
if ((verdict & VERDICT_MASK)==VERDICT_MODIFY)
|
||||
#endif
|
||||
#endif
|
||||
udp_fix_checksum(udphdr,transport_len,ip,ip6hdr);
|
||||
}
|
||||
|
@@ -59,6 +59,7 @@ uint32_t net16_add(uint16_t netorder_value, uint16_t cpuorder_increment);
|
||||
#define VERDICT_DROP 2
|
||||
#define VERDICT_MASK 3
|
||||
#define VERDICT_NOCSUM 4
|
||||
#define VERDICT_GARBAGE 8
|
||||
|
||||
#define IP4_TOS(ip_header) (ip_header ? ip_header->ip_tos : 0)
|
||||
#define IP4_IP_ID(ip_header) (ip_header ? ip_header->ip_id : 0)
|
||||
@@ -68,10 +69,13 @@ uint32_t net16_add(uint16_t netorder_value, uint16_t cpuorder_increment);
|
||||
bool prepare_tcp_segment4(
|
||||
const struct sockaddr_in *src, const struct sockaddr_in *dst,
|
||||
uint8_t tcp_flags,
|
||||
bool sack,
|
||||
uint16_t nmss,
|
||||
uint32_t nseq, uint32_t nack_seq,
|
||||
uint16_t nwsize,
|
||||
uint8_t scale_factor,
|
||||
uint32_t *timestamps,
|
||||
bool DF,
|
||||
uint8_t ttl,
|
||||
uint8_t tos,
|
||||
uint16_t ip_id,
|
||||
@@ -83,6 +87,8 @@ bool prepare_tcp_segment4(
|
||||
bool prepare_tcp_segment6(
|
||||
const struct sockaddr_in6 *src, const struct sockaddr_in6 *dst,
|
||||
uint8_t tcp_flags,
|
||||
bool sack,
|
||||
uint16_t nmss,
|
||||
uint32_t nseq, uint32_t nack_seq,
|
||||
uint16_t nwsize,
|
||||
uint8_t scale_factor,
|
||||
@@ -97,10 +103,13 @@ bool prepare_tcp_segment6(
|
||||
bool prepare_tcp_segment(
|
||||
const struct sockaddr *src, const struct sockaddr *dst,
|
||||
uint8_t tcp_flags,
|
||||
bool sack,
|
||||
uint16_t nmss,
|
||||
uint32_t nseq, uint32_t nack_seq,
|
||||
uint16_t nwsize,
|
||||
uint8_t scale_factor,
|
||||
uint32_t *timestamps,
|
||||
bool DF,
|
||||
uint8_t ttl,
|
||||
uint8_t tos,
|
||||
uint16_t ip_id,
|
||||
@@ -114,6 +123,7 @@ bool prepare_tcp_segment(
|
||||
|
||||
bool prepare_udp_segment4(
|
||||
const struct sockaddr_in *src, const struct sockaddr_in *dst,
|
||||
bool DF,
|
||||
uint8_t ttl,
|
||||
uint8_t tos,
|
||||
uint16_t ip_id,
|
||||
@@ -133,6 +143,7 @@ bool prepare_udp_segment6(
|
||||
uint8_t *buf, size_t *buflen);
|
||||
bool prepare_udp_segment(
|
||||
const struct sockaddr *src, const struct sockaddr *dst,
|
||||
bool DF,
|
||||
uint8_t ttl,
|
||||
uint8_t tos,
|
||||
uint16_t ip_id,
|
||||
@@ -162,15 +173,20 @@ bool ip_frag(
|
||||
uint8_t *pkt1, size_t *pkt1_size,
|
||||
uint8_t *pkt2, size_t *pkt2_size);
|
||||
|
||||
void rewrite_ttl(struct ip *ip, struct ip6_hdr *ip6, uint8_t ttl);
|
||||
bool rewrite_ttl(struct ip *ip, struct ip6_hdr *ip6, uint8_t ttl);
|
||||
|
||||
void extract_ports(const struct tcphdr *tcphdr, const struct udphdr *udphdr, uint8_t *proto, uint16_t *sport, uint16_t *dport);
|
||||
void extract_endpoints(const struct ip *ip,const struct ip6_hdr *ip6hdr,const struct tcphdr *tcphdr,const struct udphdr *udphdr, struct sockaddr_storage *src, struct sockaddr_storage *dst);
|
||||
uint8_t *tcp_find_option(struct tcphdr *tcp, uint8_t kind);
|
||||
uint32_t *tcp_find_timestamps(struct tcphdr *tcp);
|
||||
uint8_t tcp_find_scale_factor(const struct tcphdr *tcp);
|
||||
uint16_t tcp_find_mss(struct tcphdr *tcp);
|
||||
bool tcp_has_sack(struct tcphdr *tcp);
|
||||
|
||||
bool tcp_has_fastopen(const struct tcphdr *tcp);
|
||||
|
||||
bool ip_has_df(const struct ip *ip);
|
||||
|
||||
#ifdef __CYGWIN__
|
||||
extern uint32_t w_win32_error;
|
||||
|
||||
@@ -242,15 +258,13 @@ void tcp_rewrite_winsize(struct tcphdr *tcp, uint16_t winsize, uint8_t scale_fac
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t delta, min, max;
|
||||
int8_t delta;
|
||||
uint8_t min, max;
|
||||
} autottl;
|
||||
#define AUTOTTL_DEFAULT_DELTA 1
|
||||
#define AUTOTTL_DEFAULT_MIN 3
|
||||
#define AUTOTTL_DEFAULT_MAX 20
|
||||
#define AUTOTTL_ENABLED(a) (!!(a).delta)
|
||||
#define AUTOTTL_SET_DEFAULT(a) {(a).delta=AUTOTTL_DEFAULT_DELTA; (a).min=AUTOTTL_DEFAULT_MIN; (a).max=AUTOTTL_DEFAULT_MAX;}
|
||||
|
||||
uint8_t autottl_guess(uint8_t ttl, const autottl *attl);
|
||||
uint8_t hop_count_guess(uint8_t ttl);
|
||||
uint8_t autottl_eval(uint8_t hop_count, const autottl *attl);
|
||||
void do_nat(bool bOutbound, struct ip *ip, struct ip6_hdr *ip6, struct tcphdr *tcphdr, struct udphdr *udphdr, const struct sockaddr_in *target4, const struct sockaddr_in6 *target6);
|
||||
|
||||
void verdict_tcp_csum_fix(uint8_t verdict, struct tcphdr *tcphdr, size_t transport_len, struct ip *ip, struct ip6_hdr *ip6hdr);
|
||||
|
1216
nfq/desync.c
1216
nfq/desync.c
File diff suppressed because it is too large
Load Diff
@@ -41,7 +41,7 @@ enum dpi_desync_mode {
|
||||
};
|
||||
|
||||
extern const char *fake_http_request_default;
|
||||
extern const uint8_t fake_tls_clienthello_default[648];
|
||||
extern const uint8_t fake_tls_clienthello_default[680];
|
||||
void randomize_default_tls_payload(uint8_t *p);
|
||||
|
||||
enum dpi_desync_mode desync_mode_from_string(const char *s);
|
||||
@@ -52,4 +52,4 @@ bool desync_valid_second_stage(enum dpi_desync_mode mode);
|
||||
bool desync_valid_second_stage_tcp(enum dpi_desync_mode mode);
|
||||
bool desync_valid_second_stage_udp(enum dpi_desync_mode mode);
|
||||
|
||||
uint8_t dpi_desync_packet(uint32_t fwmark, const char *ifout, uint8_t *data_pkt, size_t *len_pkt);
|
||||
uint8_t dpi_desync_packet(uint32_t fwmark, const char *ifin, const char *ifout, uint8_t *data_pkt, size_t *len_pkt);
|
||||
|
@@ -9,6 +9,8 @@
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
|
||||
#define UNARY_PLUS(v) (v>0 ? "+" : "")
|
||||
|
||||
// this saves memory. sockaddr_storage is larger than required. it can be 128 bytes. sockaddr_in6 is 28 bytes.
|
||||
typedef union
|
||||
{
|
||||
|
@@ -287,11 +287,13 @@ static struct hostlist_file *RegisterHostlist_(struct hostlist_files_head *hostl
|
||||
}
|
||||
struct hostlist_file *RegisterHostlist(struct desync_profile *dp, bool bExclude, const char *filename)
|
||||
{
|
||||
/*
|
||||
if (filename && !file_mod_time(filename))
|
||||
{
|
||||
DLOG_ERR("cannot access hostlist file '%s'\n",filename);
|
||||
return NULL;
|
||||
}
|
||||
*/
|
||||
return RegisterHostlist_(
|
||||
¶ms.hostlists,
|
||||
bExclude ? &dp->hl_collection_exclude : &dp->hl_collection,
|
||||
|
1268
nfq/nfqws.c
1268
nfq/nfqws.c
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,6 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "packet_queue.h"
|
||||
|
||||
@@ -25,7 +26,7 @@ void rawpacket_queue_destroy(struct rawpacket_tailhead *q)
|
||||
while((rp = rawpacket_dequeue(q))) rawpacket_free(rp);
|
||||
}
|
||||
|
||||
struct rawpacket *rawpacket_queue(struct rawpacket_tailhead *q,const struct sockaddr_storage* dst,uint32_t fwmark,const char *ifout,const void *data,size_t len,size_t len_payload)
|
||||
struct rawpacket *rawpacket_queue(struct rawpacket_tailhead *q,const struct sockaddr_storage* dst,uint32_t fwmark,const char *ifin,const char *ifout,const void *data,size_t len,size_t len_payload)
|
||||
{
|
||||
struct rawpacket *rp = malloc(sizeof(struct rawpacket));
|
||||
if (!rp) return NULL;
|
||||
@@ -39,13 +40,14 @@ struct rawpacket *rawpacket_queue(struct rawpacket_tailhead *q,const struct sock
|
||||
|
||||
rp->dst = *dst;
|
||||
rp->fwmark = fwmark;
|
||||
if (ifout)
|
||||
{
|
||||
strncpy(rp->ifout,ifout,sizeof(rp->ifout));
|
||||
rp->ifout[sizeof(rp->ifout)-1]=0;
|
||||
}
|
||||
if (ifin)
|
||||
snprintf(rp->ifin,sizeof(rp->ifin),"%s",ifin);
|
||||
else
|
||||
rp->ifout[0]=0;
|
||||
*rp->ifin = 0;
|
||||
if (ifout)
|
||||
snprintf(rp->ifout,sizeof(rp->ifout),"%s",ifout);
|
||||
else
|
||||
*rp->ifout = 0;
|
||||
memcpy(rp->packet,data,len);
|
||||
rp->len=len;
|
||||
rp->len_payload=len_payload;
|
||||
|
@@ -9,7 +9,7 @@
|
||||
struct rawpacket
|
||||
{
|
||||
struct sockaddr_storage dst;
|
||||
char ifout[IFNAMSIZ+1];
|
||||
char ifin[IFNAMSIZ], ifout[IFNAMSIZ];
|
||||
uint32_t fwmark;
|
||||
size_t len, len_payload;
|
||||
uint8_t *packet;
|
||||
@@ -21,6 +21,6 @@ void rawpacket_queue_init(struct rawpacket_tailhead *q);
|
||||
void rawpacket_queue_destroy(struct rawpacket_tailhead *q);
|
||||
bool rawpacket_queue_empty(const struct rawpacket_tailhead *q);
|
||||
unsigned int rawpacket_queue_count(const struct rawpacket_tailhead *q);
|
||||
struct rawpacket *rawpacket_queue(struct rawpacket_tailhead *q,const struct sockaddr_storage* dst,uint32_t fwmark,const char *ifout,const void *data,size_t len,size_t len_payload);
|
||||
struct rawpacket *rawpacket_queue(struct rawpacket_tailhead *q,const struct sockaddr_storage* dst,uint32_t fwmark,const char *ifin,const char *ifout,const void *data,size_t len,size_t len_payload);
|
||||
struct rawpacket *rawpacket_dequeue(struct rawpacket_tailhead *q);
|
||||
void rawpacket_free(struct rawpacket *rp);
|
||||
|
70
nfq/params.c
70
nfq/params.c
@@ -65,6 +65,7 @@ static int DLOG_VA(const char *format, int syslog_priority, bool condup, va_list
|
||||
{
|
||||
va_copy(args2,args);
|
||||
DLOG_CON(format,syslog_priority,args2);
|
||||
va_end(args2);
|
||||
}
|
||||
if (params.debug)
|
||||
{
|
||||
@@ -184,29 +185,57 @@ void dp_init(struct desync_profile *dp)
|
||||
dp->desync_ipfrag_pos_udp = IPFRAG_UDP_DEFAULT;
|
||||
dp->desync_ipfrag_pos_tcp = IPFRAG_TCP_DEFAULT;
|
||||
dp->desync_repeats = 1;
|
||||
dp->fake_tls_size = sizeof(fake_tls_clienthello_default);
|
||||
memcpy(dp->fake_tls,fake_tls_clienthello_default,dp->fake_tls_size);
|
||||
dp->fake_tls_mod = 0;
|
||||
dp->fake_http_size = strlen(fake_http_request_default);
|
||||
memcpy(dp->fake_http,fake_http_request_default,dp->fake_http_size);
|
||||
dp->fake_quic_size = 620; // must be 601+ for TSPU hack
|
||||
dp->fake_quic[0] = 0x40; // russian TSPU QUIC short header fake
|
||||
dp->fake_wg_size = 64;
|
||||
dp->fake_dht_size = 64;
|
||||
dp->fake_unknown_size = 256;
|
||||
dp->fake_syndata_size = 16;
|
||||
dp->fake_unknown_udp_size = 64;
|
||||
dp->wscale=-1; // default - dont change scale factor (client)
|
||||
dp->desync_ttl6 = 0xFF; // unused
|
||||
dp->desync_badseq_increment = BADSEQ_INCREMENT_DEFAULT;
|
||||
dp->desync_badseq_ack_increment = BADSEQ_ACK_INCREMENT_DEFAULT;
|
||||
dp->wssize_cutoff_mode = dp->desync_start_mode = dp->desync_cutoff_mode = 'n'; // packet number by default
|
||||
dp->desync_ttl6 = dp->dup_ttl6 = dp->orig_mod_ttl6 = 0xFF; // unused
|
||||
dp->desync_badseq_increment = dp->dup_badseq_increment = BADSEQ_INCREMENT_DEFAULT;
|
||||
dp->desync_badseq_ack_increment = dp->dup_badseq_ack_increment = BADSEQ_ACK_INCREMENT_DEFAULT;
|
||||
dp->wssize_cutoff_mode = dp->desync_start_mode = dp->desync_cutoff_mode = dp->dup_start_mode = dp->dup_cutoff_mode = dp->orig_mod_start_mode = dp->orig_mod_cutoff_mode = 'n'; // packet number by default
|
||||
dp->udplen_increment = UDPLEN_INCREMENT_DEFAULT;
|
||||
dp->hostlist_auto_fail_threshold = HOSTLIST_AUTO_FAIL_THRESHOLD_DEFAULT;
|
||||
dp->hostlist_auto_fail_time = HOSTLIST_AUTO_FAIL_TIME_DEFAULT;
|
||||
dp->hostlist_auto_retrans_threshold = HOSTLIST_AUTO_RETRANS_THRESHOLD_DEFAULT;
|
||||
dp->filter_ipv4 = dp->filter_ipv6 = true;
|
||||
}
|
||||
bool dp_fake_defaults(struct desync_profile *dp)
|
||||
{
|
||||
struct blob_item *item;
|
||||
if (blob_collection_empty(&dp->fake_http))
|
||||
if (!blob_collection_add_blob(&dp->fake_http,fake_http_request_default,strlen(fake_http_request_default),0))
|
||||
return false;
|
||||
if (blob_collection_empty(&dp->fake_tls))
|
||||
{
|
||||
if (!(item=blob_collection_add_blob(&dp->fake_tls,fake_tls_clienthello_default,sizeof(fake_tls_clienthello_default),4+sizeof(((struct fake_tls_mod*)0)->sni))))
|
||||
return false;
|
||||
if (!(item->extra2 = malloc(sizeof(struct fake_tls_mod))))
|
||||
return false;
|
||||
*(struct fake_tls_mod*)item->extra2 = dp->tls_mod_last;
|
||||
}
|
||||
if (blob_collection_empty(&dp->fake_unknown))
|
||||
{
|
||||
if (!(item=blob_collection_add_blob(&dp->fake_unknown,NULL,256,0)))
|
||||
return false;
|
||||
memset(item->data,0,item->size);
|
||||
}
|
||||
if (blob_collection_empty(&dp->fake_quic))
|
||||
{
|
||||
if (!(item=blob_collection_add_blob(&dp->fake_quic,NULL,620,0)))
|
||||
return false;
|
||||
memset(item->data,0,item->size);
|
||||
item->data[0] = 0x40;
|
||||
}
|
||||
struct blob_collection_head **fake,*fakes_z64[] = {&dp->fake_wg, &dp->fake_dht, &dp->fake_discord, &dp->fake_stun, &dp->fake_unknown_udp,NULL};
|
||||
for(fake=fakes_z64;*fake;fake++)
|
||||
{
|
||||
if (blob_collection_empty(*fake))
|
||||
{
|
||||
if (!(item=blob_collection_add_blob(*fake,NULL,64,0)))
|
||||
return false;
|
||||
memset(item->data,0,item->size);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
struct desync_profile_list *dp_list_add(struct desync_profile_list_head *head)
|
||||
{
|
||||
struct desync_profile_list *entry = calloc(1,sizeof(struct desync_profile_list));
|
||||
@@ -235,6 +264,8 @@ static void dp_clear_dynamic(struct desync_profile *dp)
|
||||
port_filters_destroy(&dp->pf_tcp);
|
||||
port_filters_destroy(&dp->pf_udp);
|
||||
HostFailPoolDestroy(&dp->hostlist_auto_fail_counters);
|
||||
struct blob_collection_head **fake,*fakes[] = {&dp->fake_http, &dp->fake_tls, &dp->fake_unknown, &dp->fake_unknown_udp, &dp->fake_quic, &dp->fake_wg, &dp->fake_dht, &dp->fake_discord, &dp->fake_stun, NULL};
|
||||
for(fake=fakes;*fake;fake++) blob_collection_destroy(*fake);
|
||||
}
|
||||
void dp_clear(struct desync_profile *dp)
|
||||
{
|
||||
@@ -263,3 +294,12 @@ bool dp_list_have_autohostlist(struct desync_profile_list_head *head)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
// check if we need empty outgoing ACK
|
||||
bool dp_list_need_all_out(struct desync_profile_list_head *head)
|
||||
{
|
||||
struct desync_profile_list *dpl;
|
||||
LIST_FOREACH(dpl, head, next)
|
||||
if (dpl->dp.dup_repeats || PROFILE_HAS_ORIG_MOD(&dpl->dp))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
67
nfq/params.h
67
nfq/params.h
@@ -36,6 +36,19 @@
|
||||
#define HOSTLIST_AUTO_FAIL_TIME_DEFAULT 60
|
||||
#define HOSTLIST_AUTO_RETRANS_THRESHOLD_DEFAULT 3
|
||||
|
||||
#define IPCACHE_LIFETIME 7200
|
||||
|
||||
#define AUTOTTL_DEFAULT_DESYNC_DELTA -1
|
||||
#define AUTOTTL_DEFAULT_DESYNC_MIN 3
|
||||
#define AUTOTTL_DEFAULT_DESYNC_MAX 20
|
||||
#define AUTOTTL_DEFAULT_ORIG_DELTA +5
|
||||
#define AUTOTTL_DEFAULT_ORIG_MIN 3
|
||||
#define AUTOTTL_DEFAULT_ORIG_MAX 64
|
||||
#define AUTOTTL_DEFAULT_DUP_DELTA -1
|
||||
#define AUTOTTL_DEFAULT_DUP_MIN 3
|
||||
#define AUTOTTL_DEFAULT_DUP_MAX 64
|
||||
|
||||
|
||||
#define MAX_SPLITS 64
|
||||
|
||||
#define FAKE_TLS_MOD_SAVE_MASK 0x0F
|
||||
@@ -44,10 +57,24 @@
|
||||
#define FAKE_TLS_MOD_RND 0x10
|
||||
#define FAKE_TLS_MOD_DUP_SID 0x20
|
||||
#define FAKE_TLS_MOD_RND_SNI 0x40
|
||||
#define FAKE_TLS_MOD_PADENCAP 0x80
|
||||
#define FAKE_TLS_MOD_SNI 0x80
|
||||
#define FAKE_TLS_MOD_PADENCAP 0x100
|
||||
|
||||
#define FAKE_MAX_TCP 1460
|
||||
#define FAKE_MAX_UDP 1472
|
||||
|
||||
enum log_target { LOG_TARGET_CONSOLE=0, LOG_TARGET_FILE, LOG_TARGET_SYSLOG };
|
||||
|
||||
struct fake_tls_mod_cache
|
||||
{
|
||||
size_t extlen_offset, padlen_offset;
|
||||
};
|
||||
struct fake_tls_mod
|
||||
{
|
||||
char sni[64];
|
||||
uint32_t mod;
|
||||
};
|
||||
|
||||
struct desync_profile
|
||||
{
|
||||
int n; // number of the profile
|
||||
@@ -68,18 +95,33 @@ struct desync_profile
|
||||
int split_count;
|
||||
struct proto_pos seqovl;
|
||||
|
||||
char dup_start_mode, dup_cutoff_mode; // n - packets, d - data packets, s - relative sequence
|
||||
bool dup_replace;
|
||||
unsigned int dup_start, dup_cutoff;
|
||||
unsigned int dup_repeats;
|
||||
uint8_t dup_ttl, dup_ttl6;
|
||||
uint32_t dup_fooling_mode;
|
||||
uint32_t dup_badseq_increment, dup_badseq_ack_increment;
|
||||
autottl dup_autottl, dup_autottl6;
|
||||
|
||||
char orig_mod_start_mode, orig_mod_cutoff_mode; // n - packets, d - data packets, s - relative sequence
|
||||
unsigned int orig_mod_start, orig_mod_cutoff;
|
||||
uint8_t orig_mod_ttl, orig_mod_ttl6;
|
||||
autottl orig_autottl, orig_autottl6;
|
||||
|
||||
char desync_start_mode, desync_cutoff_mode; // n - packets, d - data packets, s - relative sequence
|
||||
unsigned int desync_start, desync_cutoff;
|
||||
uint8_t desync_ttl, desync_ttl6;
|
||||
autottl desync_autottl, desync_autottl6;
|
||||
uint32_t desync_fooling_mode;
|
||||
uint32_t desync_badseq_increment, desync_badseq_ack_increment;
|
||||
uint8_t fake_http[1460],fake_unknown[1460],fake_syndata[1460],seqovl_pattern[1460],fsplit_pattern[1460];
|
||||
uint8_t fake_unknown_udp[1472],udplen_pattern[1472],fake_quic[1472],fake_wg[1472],fake_dht[1472];
|
||||
size_t fake_http_size,fake_quic_size,fake_wg_size,fake_dht_size,fake_unknown_size,fake_syndata_size,fake_unknown_udp_size;
|
||||
|
||||
uint8_t fake_tls[1460],fake_tls_mod;
|
||||
size_t fake_tls_size, fake_tls_extlen_offset, fake_tls_padlen_offset;
|
||||
struct blob_collection_head fake_http,fake_tls,fake_unknown,fake_unknown_udp,fake_quic,fake_wg,fake_dht,fake_discord,fake_stun;
|
||||
uint8_t fake_syndata[FAKE_MAX_TCP],seqovl_pattern[FAKE_MAX_TCP],fsplit_pattern[FAKE_MAX_TCP],udplen_pattern[FAKE_MAX_UDP];
|
||||
size_t fake_syndata_size;
|
||||
|
||||
struct fake_tls_mod tls_mod_last;
|
||||
struct blob_item *tls_fake_last;
|
||||
|
||||
int udplen_increment;
|
||||
|
||||
@@ -99,9 +141,10 @@ struct desync_profile
|
||||
hostfail_pool *hostlist_auto_fail_counters;
|
||||
};
|
||||
|
||||
#define PROFILE_IPSETS_ABSENT(dp) (!LIST_FIRST(&dp->ips_collection) && !LIST_FIRST(&dp->ips_collection_exclude))
|
||||
#define PROFILE_IPSETS_EMPTY(dp) (ipset_collection_is_empty(&dp->ips_collection) && ipset_collection_is_empty(&dp->ips_collection_exclude))
|
||||
#define PROFILE_HOSTLISTS_EMPTY(dp) (hostlist_collection_is_empty(&dp->hl_collection) && hostlist_collection_is_empty(&dp->hl_collection_exclude))
|
||||
#define PROFILE_IPSETS_ABSENT(dp) (!LIST_FIRST(&(dp)->ips_collection) && !LIST_FIRST(&(dp)->ips_collection_exclude))
|
||||
#define PROFILE_IPSETS_EMPTY(dp) (ipset_collection_is_empty(&(dp)->ips_collection) && ipset_collection_is_empty(&(dp)->ips_collection_exclude))
|
||||
#define PROFILE_HOSTLISTS_EMPTY(dp) (hostlist_collection_is_empty(&(dp)->hl_collection) && hostlist_collection_is_empty(&(dp)->hl_collection_exclude))
|
||||
#define PROFILE_HAS_ORIG_MOD(dp) ((dp)->orig_mod_ttl || (dp)->orig_mod_ttl6)
|
||||
|
||||
struct desync_profile_list {
|
||||
struct desync_profile dp;
|
||||
@@ -112,7 +155,9 @@ struct desync_profile_list *dp_list_add(struct desync_profile_list_head *head);
|
||||
void dp_entry_destroy(struct desync_profile_list *entry);
|
||||
void dp_list_destroy(struct desync_profile_list_head *head);
|
||||
bool dp_list_have_autohostlist(struct desync_profile_list_head *head);
|
||||
bool dp_list_need_all_out(struct desync_profile_list_head *head);
|
||||
void dp_init(struct desync_profile *dp);
|
||||
bool dp_fake_defaults(struct desync_profile *dp);
|
||||
void dp_clear(struct desync_profile *dp);
|
||||
|
||||
struct params_s
|
||||
@@ -152,6 +197,10 @@ struct params_s
|
||||
|
||||
unsigned int ctrack_t_syn, ctrack_t_est, ctrack_t_fin, ctrack_t_udp;
|
||||
t_conntrack conntrack;
|
||||
|
||||
unsigned int ipcache_lifetime;
|
||||
bool autottl_present,cache_hostname;
|
||||
ip_cache ipcache;
|
||||
};
|
||||
|
||||
extern struct params_s params;
|
||||
|
279
nfq/pools.c
279
nfq/pools.c
@@ -3,6 +3,7 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#define DESTROY_STR_POOL(etype, ppool) \
|
||||
etype *elem, *tmp; \
|
||||
@@ -517,3 +518,281 @@ bool port_filters_deny_if_empty(struct port_filters_head *head)
|
||||
if (LIST_FIRST(head)) return true;
|
||||
return pf_parse("0",&pf) && port_filter_add(head,&pf);
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct blob_item *blob_collection_add(struct blob_collection_head *head)
|
||||
{
|
||||
struct blob_item *entry = calloc(1,sizeof(struct blob_item));
|
||||
if (entry)
|
||||
{
|
||||
// insert to the end
|
||||
struct blob_item *itemc,*iteml=LIST_FIRST(head);
|
||||
if (iteml)
|
||||
{
|
||||
while ((itemc=LIST_NEXT(iteml,next))) iteml = itemc;
|
||||
LIST_INSERT_AFTER(iteml, entry, next);
|
||||
}
|
||||
else
|
||||
LIST_INSERT_HEAD(head, entry, next);
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
struct blob_item *blob_collection_add_blob(struct blob_collection_head *head, const void *data, size_t size, size_t size_reserve)
|
||||
{
|
||||
struct blob_item *entry = calloc(1,sizeof(struct blob_item));
|
||||
if (!entry) return NULL;
|
||||
if (!(entry->data = malloc(size+size_reserve)))
|
||||
{
|
||||
free(entry);
|
||||
return NULL;
|
||||
}
|
||||
if (data) memcpy(entry->data,data,size);
|
||||
entry->size = size;
|
||||
entry->size_buf = size+size_reserve;
|
||||
|
||||
// insert to the end
|
||||
struct blob_item *itemc,*iteml=LIST_FIRST(head);
|
||||
if (iteml)
|
||||
{
|
||||
while ((itemc=LIST_NEXT(iteml,next))) iteml = itemc;
|
||||
LIST_INSERT_AFTER(iteml, entry, next);
|
||||
}
|
||||
else
|
||||
LIST_INSERT_HEAD(head, entry, next);
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
void blob_collection_destroy(struct blob_collection_head *head)
|
||||
{
|
||||
struct blob_item *entry;
|
||||
while ((entry = LIST_FIRST(head)))
|
||||
{
|
||||
LIST_REMOVE(entry, next);
|
||||
free(entry->extra);
|
||||
free(entry->extra2);
|
||||
free(entry->data);
|
||||
free(entry);
|
||||
}
|
||||
}
|
||||
bool blob_collection_empty(const struct blob_collection_head *head)
|
||||
{
|
||||
return !LIST_FIRST(head);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void ipcache_item_touch(ip_cache_item *item)
|
||||
{
|
||||
time(&item->last);
|
||||
}
|
||||
static void ipcache_item_init(ip_cache_item *item)
|
||||
{
|
||||
ipcache_item_touch(item);
|
||||
item->hostname = NULL;
|
||||
item->hops = 0;
|
||||
}
|
||||
static void ipcache_item_destroy(ip_cache_item *item)
|
||||
{
|
||||
free(item->hostname);
|
||||
}
|
||||
|
||||
static void ipcache4Destroy(ip_cache4 **ipcache)
|
||||
{
|
||||
ip_cache4 *elem, *tmp;
|
||||
HASH_ITER(hh, *ipcache, elem, tmp)
|
||||
{
|
||||
HASH_DEL(*ipcache, elem);
|
||||
ipcache_item_destroy(&elem->data);
|
||||
free(elem);
|
||||
}
|
||||
}
|
||||
static void ipcache4Key(ip4if *key, const struct in_addr *a, const char *iface)
|
||||
{
|
||||
memset(key,0,sizeof(*key)); // make sure everything is zero
|
||||
key->addr = *a;
|
||||
if (iface) snprintf(key->iface,sizeof(key->iface),"%s",iface);
|
||||
}
|
||||
static ip_cache4 *ipcache4Find(ip_cache4 *ipcache, const struct in_addr *a, const char *iface)
|
||||
{
|
||||
ip_cache4 *entry;
|
||||
struct ip4if key;
|
||||
|
||||
ipcache4Key(&key,a,iface);
|
||||
HASH_FIND(hh, ipcache, &key, sizeof(key), entry);
|
||||
return entry;
|
||||
}
|
||||
static ip_cache4 *ipcache4Add(ip_cache4 **ipcache, const struct in_addr *a, const char *iface)
|
||||
{
|
||||
// avoid dups
|
||||
ip_cache4 *entry = ipcache4Find(*ipcache,a,iface);
|
||||
if (entry) return entry; // already included
|
||||
|
||||
entry = malloc(sizeof(ip_cache4));
|
||||
if (!entry) return NULL;
|
||||
ipcache4Key(&entry->key,a,iface);
|
||||
|
||||
oom = false;
|
||||
HASH_ADD(hh, *ipcache, key, sizeof(entry->key), entry);
|
||||
if (oom) { free(entry); return NULL; }
|
||||
|
||||
ipcache_item_init(&entry->data);
|
||||
|
||||
return entry;
|
||||
}
|
||||
static void ipcache4Print(ip_cache4 *ipcache)
|
||||
{
|
||||
char s_ip[16];
|
||||
time_t now;
|
||||
ip_cache4 *ipc, *tmp;
|
||||
|
||||
time(&now);
|
||||
HASH_ITER(hh, ipcache , ipc, tmp)
|
||||
{
|
||||
*s_ip=0;
|
||||
inet_ntop(AF_INET, &ipc->key.addr, s_ip, sizeof(s_ip));
|
||||
printf("%s iface=%s : hops %u hostname=%s now=last+%llu\n", s_ip, ipc->key.iface, ipc->data.hops, ipc->data.hostname ? ipc->data.hostname : "", (unsigned long long)(now-ipc->data.last));
|
||||
}
|
||||
}
|
||||
|
||||
static void ipcache6Destroy(ip_cache6 **ipcache)
|
||||
{
|
||||
ip_cache6 *elem, *tmp;
|
||||
HASH_ITER(hh, *ipcache, elem, tmp)
|
||||
{
|
||||
HASH_DEL(*ipcache, elem);
|
||||
ipcache_item_destroy(&elem->data);
|
||||
free(elem);
|
||||
}
|
||||
}
|
||||
static void ipcache6Key(ip6if *key, const struct in6_addr *a, const char *iface)
|
||||
{
|
||||
memset(key,0,sizeof(*key)); // make sure everything is zero
|
||||
key->addr = *a;
|
||||
if (iface) snprintf(key->iface,sizeof(key->iface),"%s",iface);
|
||||
}
|
||||
static ip_cache6 *ipcache6Find(ip_cache6 *ipcache, const struct in6_addr *a, const char *iface)
|
||||
{
|
||||
ip_cache6 *entry;
|
||||
ip6if key;
|
||||
|
||||
ipcache6Key(&key,a,iface);
|
||||
HASH_FIND(hh, ipcache, &key, sizeof(key), entry);
|
||||
return entry;
|
||||
}
|
||||
static ip_cache6 *ipcache6Add(ip_cache6 **ipcache, const struct in6_addr *a, const char *iface)
|
||||
{
|
||||
// avoid dups
|
||||
ip_cache6 *entry = ipcache6Find(*ipcache,a,iface);
|
||||
if (entry) return entry; // already included
|
||||
|
||||
entry = malloc(sizeof(ip_cache6));
|
||||
if (!entry) return NULL;
|
||||
ipcache6Key(&entry->key,a,iface);
|
||||
|
||||
oom = false;
|
||||
HASH_ADD(hh, *ipcache, key, sizeof(entry->key), entry);
|
||||
if (oom) { free(entry); return NULL; }
|
||||
|
||||
ipcache_item_init(&entry->data);
|
||||
|
||||
return entry;
|
||||
}
|
||||
static void ipcache6Print(ip_cache6 *ipcache)
|
||||
{
|
||||
char s_ip[40];
|
||||
time_t now;
|
||||
ip_cache6 *ipc, *tmp;
|
||||
|
||||
time(&now);
|
||||
HASH_ITER(hh, ipcache , ipc, tmp)
|
||||
{
|
||||
*s_ip=0;
|
||||
inet_ntop(AF_INET6, &ipc->key.addr, s_ip, sizeof(s_ip));
|
||||
printf("%s iface=%s : hops %u hostname=%s now=last+%llu\n", s_ip, ipc->key.iface, ipc->data.hops, ipc->data.hostname ? ipc->data.hostname : "", (unsigned long long)(now-ipc->data.last));
|
||||
}
|
||||
}
|
||||
|
||||
void ipcacheDestroy(ip_cache *ipcache)
|
||||
{
|
||||
ipcache4Destroy(&ipcache->ipcache4);
|
||||
ipcache6Destroy(&ipcache->ipcache6);
|
||||
}
|
||||
void ipcachePrint(ip_cache *ipcache)
|
||||
{
|
||||
ipcache4Print(ipcache->ipcache4);
|
||||
ipcache6Print(ipcache->ipcache6);
|
||||
}
|
||||
|
||||
ip_cache_item *ipcacheTouch(ip_cache *ipcache, const struct in_addr *a4, const struct in6_addr *a6, const char *iface)
|
||||
{
|
||||
ip_cache4 *ipcache4;
|
||||
ip_cache6 *ipcache6;
|
||||
if (a4)
|
||||
{
|
||||
if ((ipcache4 = ipcache4Add(&ipcache->ipcache4,a4,iface)))
|
||||
{
|
||||
ipcache_item_touch(&ipcache4->data);
|
||||
return &ipcache4->data;
|
||||
}
|
||||
}
|
||||
else if (a6)
|
||||
{
|
||||
if ((ipcache6 = ipcache6Add(&ipcache->ipcache6,a6,iface)))
|
||||
{
|
||||
ipcache_item_touch(&ipcache6->data);
|
||||
return &ipcache6->data;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void ipcache4_purge(ip_cache4 **ipcache, time_t lifetime)
|
||||
{
|
||||
ip_cache4 *elem, *tmp;
|
||||
time_t now = time(NULL);
|
||||
HASH_ITER(hh, *ipcache, elem, tmp)
|
||||
{
|
||||
if (now >= (elem->data.last + lifetime))
|
||||
{
|
||||
HASH_DEL(*ipcache, elem);
|
||||
ipcache_item_destroy(&elem->data);
|
||||
free(elem);
|
||||
}
|
||||
}
|
||||
}
|
||||
static void ipcache6_purge(ip_cache6 **ipcache, time_t lifetime)
|
||||
{
|
||||
ip_cache6 *elem, *tmp;
|
||||
time_t now = time(NULL);
|
||||
HASH_ITER(hh, *ipcache, elem, tmp)
|
||||
{
|
||||
if (now >= (elem->data.last + lifetime))
|
||||
{
|
||||
HASH_DEL(*ipcache, elem);
|
||||
ipcache_item_destroy(&elem->data);
|
||||
free(elem);
|
||||
}
|
||||
}
|
||||
}
|
||||
static void ipcache_purge(ip_cache *ipcache, time_t lifetime)
|
||||
{
|
||||
if (lifetime) // 0 = no expire
|
||||
{
|
||||
ipcache4_purge(&ipcache->ipcache4, lifetime);
|
||||
ipcache6_purge(&ipcache->ipcache6, lifetime);
|
||||
}
|
||||
}
|
||||
static time_t ipcache_purge_prev=0;
|
||||
void ipcachePurgeRateLimited(ip_cache *ipcache, time_t lifetime)
|
||||
{
|
||||
time_t now = time(NULL);
|
||||
// do not purge too often to save resources
|
||||
if (ipcache_purge_prev != now)
|
||||
{
|
||||
ipcache_purge(ipcache, lifetime);
|
||||
ipcache_purge_prev = now;
|
||||
}
|
||||
}
|
||||
|
||||
|
56
nfq/pools.h
56
nfq/pools.h
@@ -3,6 +3,7 @@
|
||||
#include <stdbool.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/queue.h>
|
||||
#include <net/if.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "helpers.h"
|
||||
@@ -146,3 +147,58 @@ bool port_filter_add(struct port_filters_head *head, const port_filter *pf);
|
||||
void port_filters_destroy(struct port_filters_head *head);
|
||||
bool port_filters_in_range(const struct port_filters_head *head, uint16_t port);
|
||||
bool port_filters_deny_if_empty(struct port_filters_head *head);
|
||||
|
||||
|
||||
struct blob_item {
|
||||
uint8_t *data; // main data blob
|
||||
size_t size; // main data blob size
|
||||
size_t size_buf;// main data blob allocated size
|
||||
void *extra; // any data without size
|
||||
void *extra2; // any data without size
|
||||
LIST_ENTRY(blob_item) next;
|
||||
};
|
||||
LIST_HEAD(blob_collection_head, blob_item);
|
||||
struct blob_item *blob_collection_add(struct blob_collection_head *head);
|
||||
struct blob_item *blob_collection_add_blob(struct blob_collection_head *head, const void *data, size_t size, size_t size_reserve);
|
||||
void blob_collection_destroy(struct blob_collection_head *head);
|
||||
bool blob_collection_empty(const struct blob_collection_head *head);
|
||||
|
||||
|
||||
typedef struct ip4if
|
||||
{
|
||||
char iface[IFNAMSIZ];
|
||||
struct in_addr addr;
|
||||
} ip4if;
|
||||
typedef struct ip6if
|
||||
{
|
||||
char iface[IFNAMSIZ];
|
||||
struct in6_addr addr;
|
||||
} ip6if;
|
||||
typedef struct ip_cache_item
|
||||
{
|
||||
time_t last;
|
||||
char *hostname;
|
||||
uint8_t hops;
|
||||
} ip_cache_item;
|
||||
typedef struct ip_cache4
|
||||
{
|
||||
ip4if key;
|
||||
ip_cache_item data;
|
||||
UT_hash_handle hh; /* makes this structure hashable */
|
||||
} ip_cache4;
|
||||
typedef struct ip_cache6
|
||||
{
|
||||
ip6if key;
|
||||
ip_cache_item data;
|
||||
UT_hash_handle hh; /* makes this structure hashable */
|
||||
} ip_cache6;
|
||||
typedef struct ip_cache
|
||||
{
|
||||
ip_cache4 *ipcache4;
|
||||
ip_cache6 *ipcache6;
|
||||
} ip_cache;
|
||||
|
||||
ip_cache_item *ipcacheTouch(ip_cache *ipcache, const struct in_addr *a4, const struct in6_addr *a6, const char *iface);
|
||||
void ipcachePurgeRateLimited(ip_cache *ipcache, time_t lifetime);
|
||||
void ipcacheDestroy(ip_cache *ipcache);
|
||||
void ipcachePrint(ip_cache *ipcache);
|
||||
|
@@ -35,6 +35,8 @@ const char *l7proto_str(t_l7proto l7)
|
||||
case QUIC: return "quic";
|
||||
case WIREGUARD: return "wireguard";
|
||||
case DHT: return "dht";
|
||||
case DISCORD: return "discord";
|
||||
case STUN: return "stun";
|
||||
default: return "unknown";
|
||||
}
|
||||
}
|
||||
@@ -45,7 +47,9 @@ bool l7_proto_match(t_l7proto l7proto, uint32_t filter_l7)
|
||||
(l7proto==TLS && (filter_l7 & L7_PROTO_TLS)) ||
|
||||
(l7proto==QUIC && (filter_l7 & L7_PROTO_QUIC)) ||
|
||||
(l7proto==WIREGUARD && (filter_l7 & L7_PROTO_WIREGUARD)) ||
|
||||
(l7proto==DHT && (filter_l7 & L7_PROTO_DHT));
|
||||
(l7proto==DHT && (filter_l7 & L7_PROTO_DHT)) ||
|
||||
(l7proto==DISCORD && (filter_l7 & L7_PROTO_DISCORD)) ||
|
||||
(l7proto==STUN && (filter_l7 & L7_PROTO_STUN));
|
||||
}
|
||||
|
||||
#define PM_ABS 0
|
||||
@@ -341,6 +345,19 @@ size_t HttpPos(uint8_t posmarker, int16_t pos, const uint8_t *data, size_t sz)
|
||||
}
|
||||
|
||||
|
||||
const char *TLSVersionStr(uint16_t tlsver)
|
||||
{
|
||||
switch(tlsver)
|
||||
{
|
||||
case 0x0301: return "TLS 1.0";
|
||||
case 0x0302: return "TLS 1.1";
|
||||
case 0x0303: return "TLS 1.2";
|
||||
case 0x0304: return "TLS 1.3";
|
||||
default:
|
||||
// 0x0a0a, 0x1a1a, ..., 0xfafa
|
||||
return (((tlsver & 0x0F0F) == 0x0A0A) && ((tlsver>>12)==((tlsver>>4)&0xF))) ? "GREASE" : "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t TLSRecordDataLen(const uint8_t *data)
|
||||
{
|
||||
@@ -844,7 +861,16 @@ bool QUICDecryptInitial(const uint8_t *data, size_t data_len, uint8_t *clean, si
|
||||
return !memcmp(data + pn_offset + pkn_len + cryptlen, atag, 16);
|
||||
}
|
||||
|
||||
bool QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,size_t *defrag_len)
|
||||
struct range64
|
||||
{
|
||||
uint64_t offset,len;
|
||||
};
|
||||
#define MAX_DEFRAG_PIECES 128
|
||||
static int cmp_range64(const void * a, const void * b)
|
||||
{
|
||||
return (((struct range64*)a)->offset < ((struct range64*)b)->offset) ? -1 : (((struct range64*)a)->offset > ((struct range64*)b)->offset) ? 1 : 0;
|
||||
}
|
||||
bool QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,size_t *defrag_len, bool *bFull)
|
||||
{
|
||||
// Crypto frame can be split into multiple chunks
|
||||
// chromium randomly splits it and pads with zero/one bytes to force support the standard
|
||||
@@ -853,13 +879,15 @@ bool QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,siz
|
||||
if (*defrag_len<10) return false;
|
||||
uint8_t *defrag_data = defrag+10;
|
||||
size_t defrag_data_len = *defrag_len-10;
|
||||
|
||||
uint8_t ft;
|
||||
uint64_t offset,sz,szmax=0,zeropos=0,pos=0;
|
||||
bool found=false;
|
||||
struct range64 ranges[MAX_DEFRAG_PIECES];
|
||||
int i,range=0;
|
||||
|
||||
while(pos<clean_len)
|
||||
{
|
||||
// frame type
|
||||
ft = clean[pos];
|
||||
pos++;
|
||||
if (ft>1) // 00 - padding, 01 - ping
|
||||
@@ -867,6 +895,7 @@ bool QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,siz
|
||||
if (ft!=6) return false; // dont want to know all possible frame type formats
|
||||
|
||||
if (pos>=clean_len) return false;
|
||||
if (range>=MAX_DEFRAG_PIECES) return false;
|
||||
|
||||
if ((pos+tvb_get_size(clean[pos])>=clean_len)) return false;
|
||||
pos += tvb_get_varint(clean+pos, &offset);
|
||||
@@ -875,7 +904,7 @@ bool QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,siz
|
||||
pos += tvb_get_varint(clean+pos, &sz);
|
||||
if ((pos+sz)>clean_len) return false;
|
||||
|
||||
if ((offset+sz)>defrag_data_len) return false;
|
||||
if ((offset+sz)>defrag_data_len) return false; // defrag buf overflow
|
||||
if (zeropos < offset)
|
||||
// make sure no uninitialized gaps exist in case of not full fragment coverage
|
||||
memset(defrag_data+zeropos,0,offset-zeropos);
|
||||
@@ -886,6 +915,10 @@ bool QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,siz
|
||||
|
||||
found=true;
|
||||
pos+=sz;
|
||||
|
||||
ranges[range].offset = offset;
|
||||
ranges[range].len = sz;
|
||||
range++;
|
||||
}
|
||||
}
|
||||
if (found)
|
||||
@@ -897,6 +930,23 @@ bool QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,siz
|
||||
phton64(defrag+2,szmax);
|
||||
defrag[2] |= 0xC0; // 64 bit value
|
||||
*defrag_len = (size_t)(szmax+10);
|
||||
|
||||
qsort(ranges, range, sizeof(*ranges), cmp_range64);
|
||||
|
||||
//for(i=0 ; i<range ; i++)
|
||||
// printf("RANGE %zu len %zu\n",ranges[i].offset,ranges[i].len);
|
||||
|
||||
for(i=0,offset=0,*bFull=true ; i<range ; i++)
|
||||
{
|
||||
if (ranges[i].offset!=offset)
|
||||
{
|
||||
*bFull = false;
|
||||
break;
|
||||
}
|
||||
offset += ranges[i].len;
|
||||
}
|
||||
|
||||
//printf("bFull=%u\n",*bFull);
|
||||
}
|
||||
return found;
|
||||
}
|
||||
@@ -973,3 +1023,19 @@ bool IsDhtD1(const uint8_t *data, size_t len)
|
||||
{
|
||||
return len>=7 && data[0]=='d' && data[1]=='1' && data[len-1]=='e';
|
||||
}
|
||||
bool IsDiscordIpDiscoveryRequest(const uint8_t *data, size_t len)
|
||||
{
|
||||
return len==74 &&
|
||||
data[0]==0 && data[1]==1 &&
|
||||
data[2]==0 && data[3]==70 &&
|
||||
!memcmp(data+8,"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",64);
|
||||
// address is not set in request
|
||||
}
|
||||
bool IsStunMessage(const uint8_t *data, size_t len)
|
||||
{
|
||||
return len>=20 && // header size
|
||||
(data[0]&0xC0)==0 && // 2 most significant bits must be zeroes
|
||||
(data[3]&0b11)==0 && // length must be a multiple of 4
|
||||
ntohl(*(uint32_t*)(&data[4]))==0x2112A442 && // magic cookie
|
||||
ntohs(*(uint16_t*)(&data[2]))==len-20;
|
||||
}
|
||||
|
@@ -7,12 +7,14 @@
|
||||
#include "crypto/aes-gcm.h"
|
||||
#include "helpers.h"
|
||||
|
||||
typedef enum {UNKNOWN=0, HTTP, TLS, QUIC, WIREGUARD, DHT} t_l7proto;
|
||||
typedef enum {UNKNOWN=0, HTTP, TLS, QUIC, WIREGUARD, DHT, DISCORD, STUN} t_l7proto;
|
||||
#define L7_PROTO_HTTP 0x00000001
|
||||
#define L7_PROTO_TLS 0x00000002
|
||||
#define L7_PROTO_QUIC 0x00000004
|
||||
#define L7_PROTO_WIREGUARD 0x00000008
|
||||
#define L7_PROTO_DHT 0x00000010
|
||||
#define L7_PROTO_DISCORD 0x00000020
|
||||
#define L7_PROTO_STUN 0x00000040
|
||||
#define L7_PROTO_UNKNOWN 0x80000000
|
||||
const char *l7proto_str(t_l7proto l7);
|
||||
bool l7_proto_match(t_l7proto l7proto, uint32_t filter_l7);
|
||||
@@ -55,6 +57,7 @@ int HttpReplyCode(const uint8_t *data, size_t len);
|
||||
// must be pre-checked by IsHttpReply
|
||||
bool HttpReplyLooksLikeDPIRedirect(const uint8_t *data, size_t len, const char *host);
|
||||
|
||||
const char *TLSVersionStr(uint16_t tlsver);
|
||||
uint16_t TLSRecordDataLen(const uint8_t *data);
|
||||
size_t TLSRecordLen(const uint8_t *data);
|
||||
bool IsTLSRecordFull(const uint8_t *data, size_t len);
|
||||
@@ -72,6 +75,8 @@ bool TLSHelloExtractHostFromHandshake(const uint8_t *data, size_t len, char *hos
|
||||
|
||||
bool IsWireguardHandshakeInitiation(const uint8_t *data, size_t len);
|
||||
bool IsDhtD1(const uint8_t *data, size_t len);
|
||||
bool IsDiscordIpDiscoveryRequest(const uint8_t *data, size_t len);
|
||||
bool IsStunMessage(const uint8_t *data, size_t len);
|
||||
|
||||
#define QUIC_MAX_CID_LENGTH 20
|
||||
typedef struct quic_cid {
|
||||
@@ -87,5 +92,6 @@ uint8_t QUICDraftVersion(uint32_t version);
|
||||
bool QUICExtractDCID(const uint8_t *data, size_t len, quic_cid_t *cid);
|
||||
|
||||
bool QUICDecryptInitial(const uint8_t *data, size_t data_len, uint8_t *clean, size_t *clean_len);
|
||||
bool QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,size_t *defrag_len);
|
||||
// returns true if crypto frames were found . bFull = true if crypto frame fragments have full coverage
|
||||
bool QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,size_t *defrag_len, bool *bFull);
|
||||
//bool QUICExtractHostFromInitial(const uint8_t *data, size_t data_len, char *host, size_t len_host, bool *bDecryptOK, bool *bIsCryptoHello);
|
||||
|
@@ -3,7 +3,7 @@ CFLAGS += -std=gnu99 -Os -flto=auto
|
||||
CFLAGS_SYSTEMD = -DUSE_SYSTEMD
|
||||
CFLAGS_BSD = -Wno-address-of-packed-member
|
||||
LIBS = -lz -lpthread
|
||||
LIBS_SYSTEMD = -lz -lsystemd
|
||||
LIBS_SYSTEMD = -lsystemd
|
||||
LIBS_ANDROID = -lz
|
||||
SRC_FILES = *.c
|
||||
SRC_FILES_ANDROID = $(SRC_FILES) andr/*.c
|
||||
@@ -14,7 +14,7 @@ tpws: $(SRC_FILES)
|
||||
$(CC) -s $(CFLAGS) -o tpws $(SRC_FILES) $(LIBS) $(LDFLAGS)
|
||||
|
||||
systemd: $(SRC_FILES)
|
||||
$(CC) -s $(CFLAGS) $(CFLAGS_SYSTEMD) -o tpws $(SRC_FILES) $(LIBS_SYSTEMD) $(LDFLAGS)
|
||||
$(CC) -s $(CFLAGS) $(CFLAGS_SYSTEMD) -o tpws $(SRC_FILES) $(LIBS) $(LIBS_SYSTEMD) $(LDFLAGS)
|
||||
|
||||
android: $(SRC_FILES)
|
||||
$(CC) -s $(CFLAGS) -o tpws $(SRC_FILES_ANDROID) $(LIBS_ANDROID) $(LDFLAGS)
|
||||
|
@@ -287,11 +287,13 @@ static struct hostlist_file *RegisterHostlist_(struct hostlist_files_head *hostl
|
||||
}
|
||||
struct hostlist_file *RegisterHostlist(struct desync_profile *dp, bool bExclude, const char *filename)
|
||||
{
|
||||
/*
|
||||
if (filename && !file_mod_time(filename))
|
||||
{
|
||||
DLOG_ERR("cannot access hostlist file '%s'\n",filename);
|
||||
return NULL;
|
||||
}
|
||||
*/
|
||||
return RegisterHostlist_(
|
||||
¶ms.hostlists,
|
||||
bExclude ? &dp->hl_collection_exclude : &dp->hl_collection,
|
||||
|
@@ -50,6 +50,7 @@ static int DLOG_VA(const char *format, int syslog_priority, bool condup, int lev
|
||||
{
|
||||
va_copy(args2,args);
|
||||
DLOG_CON(format,syslog_priority,args2);
|
||||
va_end(args2);
|
||||
}
|
||||
if (params.debug>=level)
|
||||
{
|
||||
|
@@ -20,6 +20,8 @@
|
||||
|
||||
#define FIX_SEG_DEFAULT_MAX_WAIT 50
|
||||
|
||||
#define IPCACHE_LIFETIME 7200
|
||||
|
||||
enum bindll { unwanted=0, no, prefer, force };
|
||||
|
||||
#define MAX_BINDS 32
|
||||
@@ -140,6 +142,10 @@ struct params_s
|
||||
bool tamper; // any tamper option is set
|
||||
bool tamper_lim; // tamper-start or tamper-cutoff set in any profile
|
||||
struct desync_profile_list_head desync_profiles;
|
||||
|
||||
unsigned int ipcache_lifetime;
|
||||
bool cache_hostname;
|
||||
ip_cache ipcache;
|
||||
};
|
||||
|
||||
extern struct params_s params;
|
||||
|
275
tpws/pools.c
275
tpws/pools.c
@@ -3,6 +3,7 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#define DESTROY_STR_POOL(etype, ppool) \
|
||||
etype *elem, *tmp; \
|
||||
@@ -517,3 +518,277 @@ bool port_filters_deny_if_empty(struct port_filters_head *head)
|
||||
if (LIST_FIRST(head)) return true;
|
||||
return pf_parse("0",&pf) && port_filter_add(head,&pf);
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct blob_item *blob_collection_add(struct blob_collection_head *head)
|
||||
{
|
||||
struct blob_item *entry = calloc(1,sizeof(struct blob_item));
|
||||
if (entry)
|
||||
{
|
||||
// insert to the end
|
||||
struct blob_item *itemc,*iteml=LIST_FIRST(head);
|
||||
if (iteml)
|
||||
{
|
||||
while ((itemc=LIST_NEXT(iteml,next))) iteml = itemc;
|
||||
LIST_INSERT_AFTER(iteml, entry, next);
|
||||
}
|
||||
else
|
||||
LIST_INSERT_HEAD(head, entry, next);
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
struct blob_item *blob_collection_add_blob(struct blob_collection_head *head, const void *data, size_t size, size_t size_reserve)
|
||||
{
|
||||
struct blob_item *entry = calloc(1,sizeof(struct blob_item));
|
||||
if (!entry) return NULL;
|
||||
if (!(entry->data = malloc(size+size_reserve)))
|
||||
{
|
||||
free(entry);
|
||||
return NULL;
|
||||
}
|
||||
if (data) memcpy(entry->data,data,size);
|
||||
entry->size = size;
|
||||
entry->size_buf = size+size_reserve;
|
||||
|
||||
// insert to the end
|
||||
struct blob_item *itemc,*iteml=LIST_FIRST(head);
|
||||
if (iteml)
|
||||
{
|
||||
while ((itemc=LIST_NEXT(iteml,next))) iteml = itemc;
|
||||
LIST_INSERT_AFTER(iteml, entry, next);
|
||||
}
|
||||
else
|
||||
LIST_INSERT_HEAD(head, entry, next);
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
void blob_collection_destroy(struct blob_collection_head *head)
|
||||
{
|
||||
struct blob_item *entry;
|
||||
while ((entry = LIST_FIRST(head)))
|
||||
{
|
||||
LIST_REMOVE(entry, next);
|
||||
free(entry->extra);
|
||||
free(entry->extra2);
|
||||
free(entry->data);
|
||||
free(entry);
|
||||
}
|
||||
}
|
||||
bool blob_collection_empty(const struct blob_collection_head *head)
|
||||
{
|
||||
return !LIST_FIRST(head);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void ipcache_item_touch(ip_cache_item *item)
|
||||
{
|
||||
time(&item->last);
|
||||
}
|
||||
static void ipcache_item_init(ip_cache_item *item)
|
||||
{
|
||||
ipcache_item_touch(item);
|
||||
item->hostname = NULL;
|
||||
}
|
||||
static void ipcache_item_destroy(ip_cache_item *item)
|
||||
{
|
||||
free(item->hostname);
|
||||
}
|
||||
|
||||
static void ipcache4Destroy(ip_cache4 **ipcache)
|
||||
{
|
||||
ip_cache4 *elem, *tmp;
|
||||
HASH_ITER(hh, *ipcache, elem, tmp)
|
||||
{
|
||||
HASH_DEL(*ipcache, elem);
|
||||
ipcache_item_destroy(&elem->data);
|
||||
free(elem);
|
||||
}
|
||||
}
|
||||
static void ipcache4Key(ip4if *key, const struct in_addr *a)
|
||||
{
|
||||
memset(key,0,sizeof(*key)); // make sure everything is zero
|
||||
key->addr = *a;
|
||||
}
|
||||
static ip_cache4 *ipcache4Find(ip_cache4 *ipcache, const struct in_addr *a)
|
||||
{
|
||||
ip_cache4 *entry;
|
||||
struct ip4if key;
|
||||
|
||||
ipcache4Key(&key,a);
|
||||
HASH_FIND(hh, ipcache, &key, sizeof(key), entry);
|
||||
return entry;
|
||||
}
|
||||
static ip_cache4 *ipcache4Add(ip_cache4 **ipcache, const struct in_addr *a)
|
||||
{
|
||||
// avoid dups
|
||||
ip_cache4 *entry = ipcache4Find(*ipcache,a);
|
||||
if (entry) return entry; // already included
|
||||
|
||||
entry = malloc(sizeof(ip_cache4));
|
||||
if (!entry) return NULL;
|
||||
ipcache4Key(&entry->key,a);
|
||||
|
||||
oom = false;
|
||||
HASH_ADD(hh, *ipcache, key, sizeof(entry->key), entry);
|
||||
if (oom) { free(entry); return NULL; }
|
||||
|
||||
ipcache_item_init(&entry->data);
|
||||
|
||||
return entry;
|
||||
}
|
||||
static void ipcache4Print(ip_cache4 *ipcache)
|
||||
{
|
||||
char s_ip[16];
|
||||
time_t now;
|
||||
ip_cache4 *ipc, *tmp;
|
||||
|
||||
time(&now);
|
||||
HASH_ITER(hh, ipcache , ipc, tmp)
|
||||
{
|
||||
*s_ip=0;
|
||||
inet_ntop(AF_INET, &ipc->key.addr, s_ip, sizeof(s_ip));
|
||||
printf("%s : hostname=%s now=last+%llu\n", s_ip, ipc->data.hostname ? ipc->data.hostname : "", (unsigned long long)(now-ipc->data.last));
|
||||
}
|
||||
}
|
||||
|
||||
static void ipcache6Destroy(ip_cache6 **ipcache)
|
||||
{
|
||||
ip_cache6 *elem, *tmp;
|
||||
HASH_ITER(hh, *ipcache, elem, tmp)
|
||||
{
|
||||
HASH_DEL(*ipcache, elem);
|
||||
ipcache_item_destroy(&elem->data);
|
||||
free(elem);
|
||||
}
|
||||
}
|
||||
static void ipcache6Key(ip6if *key, const struct in6_addr *a)
|
||||
{
|
||||
memset(key,0,sizeof(*key)); // make sure everything is zero
|
||||
key->addr = *a;
|
||||
}
|
||||
static ip_cache6 *ipcache6Find(ip_cache6 *ipcache, const struct in6_addr *a)
|
||||
{
|
||||
ip_cache6 *entry;
|
||||
ip6if key;
|
||||
|
||||
ipcache6Key(&key,a);
|
||||
HASH_FIND(hh, ipcache, &key, sizeof(key), entry);
|
||||
return entry;
|
||||
}
|
||||
static ip_cache6 *ipcache6Add(ip_cache6 **ipcache, const struct in6_addr *a)
|
||||
{
|
||||
// avoid dups
|
||||
ip_cache6 *entry = ipcache6Find(*ipcache,a);
|
||||
if (entry) return entry; // already included
|
||||
|
||||
entry = malloc(sizeof(ip_cache6));
|
||||
if (!entry) return NULL;
|
||||
ipcache6Key(&entry->key,a);
|
||||
|
||||
oom = false;
|
||||
HASH_ADD(hh, *ipcache, key, sizeof(entry->key), entry);
|
||||
if (oom) { free(entry); return NULL; }
|
||||
|
||||
ipcache_item_init(&entry->data);
|
||||
|
||||
return entry;
|
||||
}
|
||||
static void ipcache6Print(ip_cache6 *ipcache)
|
||||
{
|
||||
char s_ip[40];
|
||||
time_t now;
|
||||
ip_cache6 *ipc, *tmp;
|
||||
|
||||
time(&now);
|
||||
HASH_ITER(hh, ipcache , ipc, tmp)
|
||||
{
|
||||
*s_ip=0;
|
||||
inet_ntop(AF_INET6, &ipc->key.addr, s_ip, sizeof(s_ip));
|
||||
printf("%s : hostname=%s now=last+%llu\n", s_ip, ipc->data.hostname ? ipc->data.hostname : "", (unsigned long long)(now-ipc->data.last));
|
||||
}
|
||||
}
|
||||
|
||||
void ipcacheDestroy(ip_cache *ipcache)
|
||||
{
|
||||
ipcache4Destroy(&ipcache->ipcache4);
|
||||
ipcache6Destroy(&ipcache->ipcache6);
|
||||
}
|
||||
void ipcachePrint(ip_cache *ipcache)
|
||||
{
|
||||
ipcache4Print(ipcache->ipcache4);
|
||||
ipcache6Print(ipcache->ipcache6);
|
||||
}
|
||||
|
||||
ip_cache_item *ipcacheTouch(ip_cache *ipcache, const struct in_addr *a4, const struct in6_addr *a6)
|
||||
{
|
||||
ip_cache4 *ipcache4;
|
||||
ip_cache6 *ipcache6;
|
||||
if (a4)
|
||||
{
|
||||
if ((ipcache4 = ipcache4Add(&ipcache->ipcache4,a4)))
|
||||
{
|
||||
ipcache_item_touch(&ipcache4->data);
|
||||
return &ipcache4->data;
|
||||
}
|
||||
}
|
||||
else if (a6)
|
||||
{
|
||||
if ((ipcache6 = ipcache6Add(&ipcache->ipcache6,a6)))
|
||||
{
|
||||
ipcache_item_touch(&ipcache6->data);
|
||||
return &ipcache6->data;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void ipcache4_purge(ip_cache4 **ipcache, time_t lifetime)
|
||||
{
|
||||
ip_cache4 *elem, *tmp;
|
||||
time_t now = time(NULL);
|
||||
HASH_ITER(hh, *ipcache, elem, tmp)
|
||||
{
|
||||
if (now >= (elem->data.last + lifetime))
|
||||
{
|
||||
HASH_DEL(*ipcache, elem);
|
||||
ipcache_item_destroy(&elem->data);
|
||||
free(elem);
|
||||
}
|
||||
}
|
||||
}
|
||||
static void ipcache6_purge(ip_cache6 **ipcache, time_t lifetime)
|
||||
{
|
||||
ip_cache6 *elem, *tmp;
|
||||
time_t now = time(NULL);
|
||||
HASH_ITER(hh, *ipcache, elem, tmp)
|
||||
{
|
||||
if (now >= (elem->data.last + lifetime))
|
||||
{
|
||||
HASH_DEL(*ipcache, elem);
|
||||
ipcache_item_destroy(&elem->data);
|
||||
free(elem);
|
||||
}
|
||||
}
|
||||
}
|
||||
static void ipcache_purge(ip_cache *ipcache, time_t lifetime)
|
||||
{
|
||||
if (lifetime) // 0 = no expire
|
||||
{
|
||||
ipcache4_purge(&ipcache->ipcache4, lifetime);
|
||||
ipcache6_purge(&ipcache->ipcache6, lifetime);
|
||||
}
|
||||
}
|
||||
static time_t ipcache_purge_prev=0;
|
||||
void ipcachePurgeRateLimited(ip_cache *ipcache, time_t lifetime)
|
||||
{
|
||||
time_t now = time(NULL);
|
||||
// do not purge too often to save resources
|
||||
if (ipcache_purge_prev != now)
|
||||
{
|
||||
ipcache_purge(ipcache, lifetime);
|
||||
ipcache_purge_prev = now;
|
||||
}
|
||||
}
|
||||
|
53
tpws/pools.h
53
tpws/pools.h
@@ -3,6 +3,7 @@
|
||||
#include <stdbool.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/queue.h>
|
||||
#include <net/if.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "helpers.h"
|
||||
@@ -146,3 +147,55 @@ bool port_filter_add(struct port_filters_head *head, const port_filter *pf);
|
||||
void port_filters_destroy(struct port_filters_head *head);
|
||||
bool port_filters_in_range(const struct port_filters_head *head, uint16_t port);
|
||||
bool port_filters_deny_if_empty(struct port_filters_head *head);
|
||||
|
||||
|
||||
struct blob_item {
|
||||
uint8_t *data; // main data blob
|
||||
size_t size; // main data blob size
|
||||
size_t size_buf;// main data blob allocated size
|
||||
void *extra; // any data without size
|
||||
void *extra2; // any data without size
|
||||
LIST_ENTRY(blob_item) next;
|
||||
};
|
||||
LIST_HEAD(blob_collection_head, blob_item);
|
||||
struct blob_item *blob_collection_add(struct blob_collection_head *head);
|
||||
struct blob_item *blob_collection_add_blob(struct blob_collection_head *head, const void *data, size_t size, size_t size_reserve);
|
||||
void blob_collection_destroy(struct blob_collection_head *head);
|
||||
bool blob_collection_empty(const struct blob_collection_head *head);
|
||||
|
||||
|
||||
typedef struct ip4if
|
||||
{
|
||||
struct in_addr addr;
|
||||
} ip4if;
|
||||
typedef struct ip6if
|
||||
{
|
||||
struct in6_addr addr;
|
||||
} ip6if;
|
||||
typedef struct ip_cache_item
|
||||
{
|
||||
time_t last;
|
||||
char *hostname;
|
||||
} ip_cache_item;
|
||||
typedef struct ip_cache4
|
||||
{
|
||||
ip4if key;
|
||||
ip_cache_item data;
|
||||
UT_hash_handle hh; /* makes this structure hashable */
|
||||
} ip_cache4;
|
||||
typedef struct ip_cache6
|
||||
{
|
||||
ip6if key;
|
||||
ip_cache_item data;
|
||||
UT_hash_handle hh; /* makes this structure hashable */
|
||||
} ip_cache6;
|
||||
typedef struct ip_cache
|
||||
{
|
||||
ip_cache4 *ipcache4;
|
||||
ip_cache6 *ipcache6;
|
||||
} ip_cache;
|
||||
|
||||
ip_cache_item *ipcacheTouch(ip_cache *ipcache, const struct in_addr *a4, const struct in6_addr *a6);
|
||||
void ipcachePurgeRateLimited(ip_cache *ipcache, time_t lifetime);
|
||||
void ipcacheDestroy(ip_cache *ipcache);
|
||||
void ipcachePrint(ip_cache *ipcache);
|
||||
|
@@ -339,6 +339,20 @@ size_t HttpPos(uint8_t posmarker, int16_t pos, const uint8_t *data, size_t sz)
|
||||
|
||||
|
||||
|
||||
const char *TLSVersionStr(uint16_t tlsver)
|
||||
{
|
||||
switch(tlsver)
|
||||
{
|
||||
case 0x0301: return "TLS 1.0";
|
||||
case 0x0302: return "TLS 1.1";
|
||||
case 0x0303: return "TLS 1.2";
|
||||
case 0x0304: return "TLS 1.3";
|
||||
default:
|
||||
// 0x0a0a, 0x1a1a, ..., 0xfafa
|
||||
return (((tlsver & 0x0F0F) == 0x0A0A) && ((tlsver>>12)==((tlsver>>4)&0xF))) ? "GREASE" : "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t TLSRecordDataLen(const uint8_t *data)
|
||||
{
|
||||
return pntoh16(data + 3);
|
||||
|
@@ -53,6 +53,7 @@ int HttpReplyCode(const uint8_t *data, size_t len);
|
||||
// must be pre-checked by IsHttpReply
|
||||
bool HttpReplyLooksLikeDPIRedirect(const uint8_t *data, size_t len, const char *host);
|
||||
|
||||
const char *TLSVersionStr(uint16_t tlsver);
|
||||
uint16_t TLSRecordDataLen(const uint8_t *data);
|
||||
size_t TLSRecordLen(const uint8_t *data);
|
||||
bool IsTLSRecordFull(const uint8_t *data, size_t len);
|
||||
|
136
tpws/tamper.c
136
tpws/tamper.c
@@ -7,6 +7,7 @@
|
||||
#include "ipset.h"
|
||||
#include "protocol.h"
|
||||
#include "helpers.h"
|
||||
#include "pools.h"
|
||||
|
||||
#define PKTDATA_MAXDUMP 32
|
||||
|
||||
@@ -15,6 +16,123 @@ void packet_debug(const uint8_t *data, size_t sz)
|
||||
hexdump_limited_dlog(data, sz, PKTDATA_MAXDUMP); VPRINT("\n");
|
||||
}
|
||||
|
||||
static void TLSDebugHandshake(const uint8_t *tls,size_t sz)
|
||||
{
|
||||
if (!params.debug) return;
|
||||
|
||||
if (sz<6) return;
|
||||
|
||||
const uint8_t *ext;
|
||||
size_t len,len2;
|
||||
|
||||
uint16_t v_handshake=pntoh16(tls+4), v, v2;
|
||||
VPRINT("TLS handshake version : %s\n",TLSVersionStr(v_handshake));
|
||||
|
||||
if (TLSFindExtInHandshake(tls,sz,43,&ext,&len,false))
|
||||
{
|
||||
if (len)
|
||||
{
|
||||
len2 = ext[0];
|
||||
if (len2<len)
|
||||
{
|
||||
for(ext++,len2&=~1 ; len2 ; len2-=2,ext+=2)
|
||||
{
|
||||
v = pntoh16(ext);
|
||||
VPRINT("TLS supported versions ext : %s\n",TLSVersionStr(v));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
VPRINT("TLS supported versions ext : not present\n");
|
||||
|
||||
if (TLSFindExtInHandshake(tls,sz,16,&ext,&len,false))
|
||||
{
|
||||
if (len>=2)
|
||||
{
|
||||
len2 = pntoh16(ext);
|
||||
if (len2<=(len-2))
|
||||
{
|
||||
char s[32];
|
||||
for(ext+=2; len2 ;)
|
||||
{
|
||||
v = *ext; ext++; len2--;
|
||||
if (v<=len2)
|
||||
{
|
||||
v2 = v<sizeof(s) ? v : sizeof(s)-1;
|
||||
memcpy(s,ext,v2);
|
||||
s[v2]=0;
|
||||
VPRINT("TLS ALPN ext : %s\n",s);
|
||||
len2-=v;
|
||||
ext+=v;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
VPRINT("TLS ALPN ext : not present\n");
|
||||
|
||||
VPRINT("TLS ECH ext : %s\n",TLSFindExtInHandshake(tls,sz,65037,NULL,NULL,false) ? "present" : "not present");
|
||||
}
|
||||
static void TLSDebug(const uint8_t *tls,size_t sz)
|
||||
{
|
||||
if (!params.debug) return;
|
||||
|
||||
if (sz<11) return;
|
||||
|
||||
VPRINT("TLS record layer version : %s\n",TLSVersionStr(pntoh16(tls+1)));
|
||||
|
||||
size_t reclen=TLSRecordLen(tls);
|
||||
if (reclen<sz) sz=reclen; // correct len if it has more data than the first tls record has
|
||||
|
||||
TLSDebugHandshake(tls+5,sz-5);
|
||||
}
|
||||
|
||||
static bool ipcache_put_hostname(const struct in_addr *a4, const struct in6_addr *a6, const char *hostname)
|
||||
{
|
||||
if (!params.cache_hostname) return true;
|
||||
|
||||
ip_cache_item *ipc = ipcacheTouch(¶ms.ipcache,a4,a6);
|
||||
if (!ipc)
|
||||
{
|
||||
DLOG_ERR("ipcache_put_hostname: out of memory\n");
|
||||
return false;
|
||||
}
|
||||
free(ipc->hostname);
|
||||
if (!(ipc->hostname = strdup(hostname)))
|
||||
{
|
||||
DLOG_ERR("ipcache_put_hostname: out of memory\n");
|
||||
return false;
|
||||
}
|
||||
VPRINT("hostname cached: %s\n", hostname);
|
||||
return true;
|
||||
}
|
||||
static bool ipcache_get_hostname(const struct in_addr *a4, const struct in6_addr *a6, char *hostname, size_t hostname_buf_len)
|
||||
{
|
||||
if (!params.cache_hostname)
|
||||
{
|
||||
*hostname = 0;
|
||||
return true;
|
||||
}
|
||||
ip_cache_item *ipc = ipcacheTouch(¶ms.ipcache,a4,a6);
|
||||
if (!ipc)
|
||||
{
|
||||
DLOG_ERR("ipcache_get_hostname: out of memory\n");
|
||||
return false;
|
||||
}
|
||||
if (ipc->hostname)
|
||||
{
|
||||
VPRINT("got cached hostname: %s\n", ipc->hostname);
|
||||
snprintf(hostname,hostname_buf_len,"%s",ipc->hostname);
|
||||
}
|
||||
else
|
||||
*hostname = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool dp_match(struct desync_profile *dp, const struct sockaddr *dest, const char *hostname, t_l7proto l7proto)
|
||||
{
|
||||
bool bHostlistsEmpty;
|
||||
@@ -70,8 +188,17 @@ static struct desync_profile *dp_find(struct desync_profile_list_head *head, con
|
||||
VPRINT("desync profile not found\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void apply_desync_profile(t_ctrack *ctrack, const struct sockaddr *dest)
|
||||
{
|
||||
ipcachePurgeRateLimited(¶ms.ipcache, params.ipcache_lifetime);
|
||||
if (!ctrack->hostname)
|
||||
{
|
||||
char host[256];
|
||||
if (ipcache_get_hostname(dest->sa_family==AF_INET ? &((struct sockaddr_in*)dest)->sin_addr : NULL, dest->sa_family==AF_INET6 ? &((struct sockaddr_in6*)dest)->sin6_addr : NULL , host, sizeof(host)) && *host)
|
||||
if (!(ctrack->hostname=strdup(host)))
|
||||
DLOG_ERR("hostname dup : out of memory");
|
||||
}
|
||||
ctrack->dp = dp_find(¶ms.desync_profiles, dest, ctrack->hostname, ctrack->l7proto);
|
||||
}
|
||||
|
||||
@@ -130,6 +257,7 @@ void tamper_out(t_ctrack *ctrack, const struct sockaddr *dest, uint8_t *segment,
|
||||
{
|
||||
VPRINT("Data block contains TLS ClientHello\n");
|
||||
l7proto=TLS;
|
||||
TLSDebug(segment,*size);
|
||||
bHaveHost=TLSHelloExtractHost((uint8_t*)segment,*size,Host,sizeof(Host),false);
|
||||
}
|
||||
else
|
||||
@@ -139,7 +267,11 @@ void tamper_out(t_ctrack *ctrack, const struct sockaddr *dest, uint8_t *segment,
|
||||
}
|
||||
|
||||
if (bHaveHost)
|
||||
{
|
||||
VPRINT("request hostname: %s\n", Host);
|
||||
if (!ipcache_put_hostname(dest->sa_family==AF_INET ? &((struct sockaddr_in*)dest)->sin_addr : NULL, dest->sa_family==AF_INET6 ? &((struct sockaddr_in6*)dest)->sin6_addr : NULL , Host))
|
||||
DLOG_ERR("ipcache_put_hostname: out of memory");
|
||||
}
|
||||
|
||||
bool bDiscoveredL7 = ctrack->l7proto==UNKNOWN && l7proto!=UNKNOWN;
|
||||
if (bDiscoveredL7)
|
||||
@@ -148,15 +280,17 @@ void tamper_out(t_ctrack *ctrack, const struct sockaddr *dest, uint8_t *segment,
|
||||
ctrack->l7proto=l7proto;
|
||||
}
|
||||
|
||||
bool bDiscoveredHostname = bHaveHost && !ctrack->hostname;
|
||||
bool bDiscoveredHostname = bHaveHost && !ctrack->hostname_discovered;
|
||||
if (bDiscoveredHostname)
|
||||
{
|
||||
VPRINT("discovered hostname\n");
|
||||
free(ctrack->hostname);
|
||||
if (!(ctrack->hostname=strdup(Host)))
|
||||
{
|
||||
DLOG_ERR("strdup hostname : out of memory\n");
|
||||
return;
|
||||
}
|
||||
ctrack->hostname_discovered = true;
|
||||
}
|
||||
|
||||
if (bDiscoveredL7 || bDiscoveredHostname)
|
||||
|
@@ -15,6 +15,7 @@ typedef struct
|
||||
t_l7proto l7proto;
|
||||
bool bTamperInCutoff;
|
||||
bool b_host_checked,b_host_matches,b_ah_check;
|
||||
bool hostname_discovered;
|
||||
char *hostname;
|
||||
struct desync_profile *dp; // desync profile cache
|
||||
} t_ctrack;
|
||||
|
475
tpws/tpws.c
475
tpws/tpws.c
@@ -88,6 +88,12 @@ static void onusr2(int sig)
|
||||
HostFailPoolDump(dpl->dp.hostlist_auto_fail_counters);
|
||||
}
|
||||
|
||||
if (params.cache_hostname)
|
||||
{
|
||||
printf("\nIPCACHE\n");
|
||||
ipcachePrint(¶ms.ipcache);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
@@ -215,6 +221,8 @@ static void exithelp(void)
|
||||
#if defined(__linux__)
|
||||
" --fix-seg=<int>\t\t\t; fix segmentation failures at the cost of possible slowdown. wait up to N msec (default %u)\n"
|
||||
#endif
|
||||
" --ipcache-lifetime=<int>\t\t; time in seconds to keep cached domain name (default %u). 0 = no expiration\n"
|
||||
" --ipcache-hostname=[0|1]\t\t; 1 or no argument enables ip->hostname caching\n"
|
||||
" --debug=0|1|2|syslog|@<filename>\t; 1 and 2 means log to console and set debug level. for other targets use --debug-level.\n"
|
||||
" --debug-level=0|1|2\t\t\t; specify debug level\n"
|
||||
" --dry-run\t\t\t\t; verify parameters and exit with code 0 if successful\n"
|
||||
@@ -272,6 +280,7 @@ static void exithelp(void)
|
||||
#ifdef __linux__
|
||||
FIX_SEG_DEFAULT_MAX_WAIT,
|
||||
#endif
|
||||
IPCACHE_LIFETIME,
|
||||
HOSTLIST_AUTO_FAIL_THRESHOLD_DEFAULT, HOSTLIST_AUTO_FAIL_TIME_DEFAULT
|
||||
);
|
||||
exit(1);
|
||||
@@ -292,6 +301,7 @@ static void cleanup_params(void)
|
||||
|
||||
hostlist_files_destroy(¶ms.hostlists);
|
||||
ipset_files_destroy(¶ms.ipsets);
|
||||
ipcacheDestroy(¶ms.ipcache);
|
||||
}
|
||||
static void exithelp_clean(void)
|
||||
{
|
||||
@@ -610,6 +620,192 @@ static bool check_oob_disorder(const struct desync_profile *dp)
|
||||
}
|
||||
#endif
|
||||
|
||||
enum opt_indices {
|
||||
IDX_HELP,
|
||||
IDX_H,
|
||||
IDX_BIND_ADDR,
|
||||
IDX_BIND_IFACE4,
|
||||
IDX_BIND_IFACE6,
|
||||
IDX_BIND_LINKLOCAL,
|
||||
IDX_BIND_WAIT_IFUP,
|
||||
IDX_BIND_WAIT_IP,
|
||||
IDX_BIND_WAIT_IP_LINKLOCAL,
|
||||
IDX_BIND_WAIT_ONLY,
|
||||
IDX_PORT,
|
||||
IDX_DAEMON,
|
||||
IDX_USER,
|
||||
IDX_UID,
|
||||
IDX_MAXCONN,
|
||||
IDX_MAXFILES,
|
||||
IDX_MAX_ORPHAN_TIME,
|
||||
IDX_IPCACHE_LIFETIME,
|
||||
IDX_IPCACHE_HOSTNAME,
|
||||
IDX_HOSTCASE,
|
||||
IDX_HOSTSPELL,
|
||||
IDX_HOSTDOT,
|
||||
IDX_HOSTNOSPACE,
|
||||
IDX_HOSTPAD,
|
||||
IDX_DOMCASE,
|
||||
IDX_SPLIT_HTTP_REQ,
|
||||
IDX_SPLIT_TLS,
|
||||
IDX_SPLIT_POS,
|
||||
IDX_SPLIT_ANY_PROTOCOL,
|
||||
IDX_DISORDER,
|
||||
IDX_OOB,
|
||||
IDX_OOB_DATA,
|
||||
IDX_METHODSPACE,
|
||||
IDX_METHODEOL,
|
||||
IDX_HOSTTAB,
|
||||
IDX_UNIXEOL,
|
||||
IDX_TLSREC,
|
||||
IDX_TLSREC_POS,
|
||||
IDX_HOSTLIST,
|
||||
IDX_HOSTLIST_DOMAINS,
|
||||
IDX_HOSTLIST_EXCLUDE,
|
||||
IDX_HOSTLIST_EXCLUDE_DOMAINS,
|
||||
IDX_HOSTLIST_AUTO,
|
||||
IDX_HOSTLIST_AUTO_FAIL_THRESHOLD,
|
||||
IDX_HOSTLIST_AUTO_FAIL_TIME,
|
||||
IDX_HOSTLIST_AUTO_DEBUG,
|
||||
IDX_PIDFILE,
|
||||
IDX_DEBUG,
|
||||
IDX_DEBUG_LEVEL,
|
||||
IDX_DRY_RUN,
|
||||
IDX_VERSION,
|
||||
IDX_COMMENT,
|
||||
IDX_LOCAL_RCVBUF,
|
||||
IDX_LOCAL_SNDBUF,
|
||||
IDX_REMOTE_RCVBUF,
|
||||
IDX_REMOTE_SNDBUF,
|
||||
IDX_SOCKS,
|
||||
IDX_NO_RESOLVE,
|
||||
IDX_RESOLVER_THREADS,
|
||||
IDX_SKIP_NODELAY,
|
||||
IDX_TAMPER_START,
|
||||
IDX_TAMPER_CUTOFF,
|
||||
IDX_CONNECT_BIND_ADDR,
|
||||
|
||||
IDX_NEW,
|
||||
IDX_SKIP,
|
||||
IDX_FILTER_L3,
|
||||
IDX_FILTER_TCP,
|
||||
IDX_FILTER_L7,
|
||||
IDX_IPSET,
|
||||
IDX_IPSET_IP,
|
||||
IDX_IPSET_EXCLUDE,
|
||||
IDX_IPSET_EXCLUDE_IP,
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
IDX_ENABLE_PF,
|
||||
#elif defined(__APPLE__)
|
||||
IDX_LOCAL_TCP_USER_TIMEOUT,
|
||||
IDX_REMOTE_TCP_USER_TIMEOUT,
|
||||
#elif defined(__linux__)
|
||||
IDX_LOCAL_TCP_USER_TIMEOUT,
|
||||
IDX_REMOTE_TCP_USER_TIMEOUT,
|
||||
IDX_MSS,
|
||||
IDX_FIX_SEG,
|
||||
#ifdef SPLICE_PRESENT
|
||||
IDX_NOSPLICE,
|
||||
#endif
|
||||
#endif
|
||||
IDX_HOSTLIST_AUTO_RETRANS_THRESHOLD, // ignored. for nfqws command line compatibility
|
||||
IDX_LAST,
|
||||
};
|
||||
|
||||
static const struct option long_options[] = {
|
||||
[IDX_HELP] = {"help", no_argument, 0, 0},
|
||||
[IDX_H] = {"h", no_argument, 0, 0},
|
||||
[IDX_BIND_ADDR] = {"bind-addr", required_argument, 0, 0},
|
||||
[IDX_BIND_IFACE4] = {"bind-iface4", required_argument, 0, 0},
|
||||
[IDX_BIND_IFACE6] = {"bind-iface6", required_argument, 0, 0},
|
||||
[IDX_BIND_LINKLOCAL] = {"bind-linklocal", required_argument, 0, 0},
|
||||
[IDX_BIND_WAIT_IFUP] = {"bind-wait-ifup", required_argument, 0, 0},
|
||||
[IDX_BIND_WAIT_IP] = {"bind-wait-ip", required_argument, 0, 0},
|
||||
[IDX_BIND_WAIT_IP_LINKLOCAL] = {"bind-wait-ip-linklocal", required_argument, 0, 0},
|
||||
[IDX_BIND_WAIT_ONLY] = {"bind-wait-only", no_argument, 0, 0},
|
||||
[IDX_PORT] = {"port", required_argument, 0, 0},
|
||||
[IDX_DAEMON] = {"daemon", no_argument, 0, 0},
|
||||
[IDX_USER] = {"user", required_argument, 0, 0},
|
||||
[IDX_UID] = {"uid", required_argument, 0, 0},
|
||||
[IDX_MAXCONN] = {"maxconn", required_argument, 0, 0},
|
||||
[IDX_MAXFILES] = {"maxfiles", required_argument, 0, 0},
|
||||
[IDX_IPCACHE_LIFETIME] = {"ipcache-lifetime", required_argument, 0, 0},
|
||||
[IDX_IPCACHE_HOSTNAME] = {"ipcache-hostname", optional_argument, 0, 0},
|
||||
[IDX_MAX_ORPHAN_TIME] = {"max-orphan-time", required_argument, 0, 0},
|
||||
[IDX_HOSTCASE] = {"hostcase", no_argument, 0, 0},
|
||||
[IDX_HOSTSPELL] = {"hostspell", required_argument, 0, 0},
|
||||
[IDX_HOSTDOT] = {"hostdot", no_argument, 0, 0},
|
||||
[IDX_HOSTNOSPACE] = {"hostnospace", no_argument, 0, 0},
|
||||
[IDX_HOSTPAD] = {"hostpad", required_argument, 0, 0},
|
||||
[IDX_DOMCASE] = {"domcase", no_argument, 0, 0},
|
||||
[IDX_SPLIT_HTTP_REQ] = {"split-http-req", required_argument, 0, 0},
|
||||
[IDX_SPLIT_TLS] = {"split-tls", required_argument, 0, 0},
|
||||
[IDX_SPLIT_POS] = {"split-pos", required_argument, 0, 0},
|
||||
[IDX_SPLIT_ANY_PROTOCOL] = {"split-any-protocol", optional_argument, 0, 0},
|
||||
[IDX_DISORDER] = {"disorder", optional_argument, 0, 0},
|
||||
[IDX_OOB] = {"oob", optional_argument, 0, 0},
|
||||
[IDX_OOB_DATA] = {"oob-data", required_argument, 0, 0},
|
||||
[IDX_METHODSPACE] = {"methodspace", no_argument, 0, 0},
|
||||
[IDX_METHODEOL] = {"methodeol", no_argument, 0, 0},
|
||||
[IDX_HOSTTAB] = {"hosttab", no_argument, 0, 0},
|
||||
[IDX_UNIXEOL] = {"unixeol", no_argument, 0, 0},
|
||||
[IDX_TLSREC] = {"tlsrec", required_argument, 0, 0},
|
||||
[IDX_TLSREC_POS] = {"tlsrec-pos", required_argument, 0, 0},
|
||||
[IDX_HOSTLIST] = {"hostlist", required_argument, 0, 0},
|
||||
[IDX_HOSTLIST_DOMAINS] = {"hostlist-domains", required_argument, 0, 0},
|
||||
[IDX_HOSTLIST_EXCLUDE] = {"hostlist-exclude", required_argument, 0, 0},
|
||||
[IDX_HOSTLIST_EXCLUDE_DOMAINS] = {"hostlist-exclude-domains", required_argument, 0, 0},
|
||||
[IDX_HOSTLIST_AUTO] = {"hostlist-auto", required_argument, 0, 0},
|
||||
[IDX_HOSTLIST_AUTO_FAIL_THRESHOLD] = {"hostlist-auto-fail-threshold", required_argument, 0, 0},
|
||||
[IDX_HOSTLIST_AUTO_FAIL_TIME] = {"hostlist-auto-fail-time", required_argument, 0, 0},
|
||||
[IDX_HOSTLIST_AUTO_DEBUG] = {"hostlist-auto-debug", required_argument, 0, 0},
|
||||
[IDX_PIDFILE] = {"pidfile", required_argument, 0, 0},
|
||||
[IDX_DEBUG] = {"debug", optional_argument, 0, 0},
|
||||
[IDX_DEBUG_LEVEL] = {"debug-level", required_argument, 0, 0},
|
||||
[IDX_DRY_RUN] = {"dry-run", no_argument, 0, 0},
|
||||
[IDX_VERSION] = {"version", no_argument, 0, 0},
|
||||
[IDX_COMMENT] = {"comment", optional_argument, 0, 0},
|
||||
[IDX_LOCAL_RCVBUF] = {"local-rcvbuf", required_argument, 0, 0},
|
||||
[IDX_LOCAL_SNDBUF] = {"local-sndbuf", required_argument, 0, 0},
|
||||
[IDX_REMOTE_RCVBUF] = {"remote-rcvbuf", required_argument, 0, 0},
|
||||
[IDX_REMOTE_SNDBUF] = {"remote-sndbuf", required_argument, 0, 0},
|
||||
[IDX_SOCKS] = {"socks", no_argument, 0, 0},
|
||||
[IDX_NO_RESOLVE] = {"no-resolve", no_argument, 0, 0},
|
||||
[IDX_RESOLVER_THREADS] = {"resolver-threads", required_argument, 0, 0},
|
||||
[IDX_SKIP_NODELAY] = {"skip-nodelay", no_argument, 0, 0},
|
||||
[IDX_TAMPER_START] = {"tamper-start", required_argument, 0, 0},
|
||||
[IDX_TAMPER_CUTOFF] = {"tamper-cutoff", required_argument, 0, 0},
|
||||
[IDX_CONNECT_BIND_ADDR] = {"connect-bind-addr", required_argument, 0, 0},
|
||||
|
||||
[IDX_NEW] = {"new", no_argument, 0, 0},
|
||||
[IDX_SKIP] = {"skip", no_argument, 0, 0},
|
||||
[IDX_FILTER_L3] = {"filter-l3", required_argument, 0, 0},
|
||||
[IDX_FILTER_TCP] = {"filter-tcp", required_argument, 0, 0},
|
||||
[IDX_FILTER_L7] = {"filter-l7", required_argument, 0, 0},
|
||||
[IDX_IPSET] = {"ipset", required_argument, 0, 0},
|
||||
[IDX_IPSET_IP] = {"ipset-ip", required_argument, 0, 0},
|
||||
[IDX_IPSET_EXCLUDE] = {"ipset-exclude", required_argument, 0, 0},
|
||||
[IDX_IPSET_EXCLUDE_IP] = {"ipset-exclude-ip", required_argument, 0, 0},
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
[IDX_ENABLE_PF] = {"enable-pf", no_argument, 0, 0},
|
||||
#elif defined(__APPLE__)
|
||||
[IDX_LOCAL_TCP_USER_TIMEOUT] = {"local-tcp-user-timeout", required_argument, 0, 0},
|
||||
[IDX_REMOTE_TCP_USER_TIMEOUT] = {"remote-tcp-user-timeout", required_argument, 0, 0},
|
||||
#elif defined(__linux__)
|
||||
[IDX_LOCAL_TCP_USER_TIMEOUT] = {"local-tcp-user-timeout", required_argument, 0, 0},
|
||||
[IDX_REMOTE_TCP_USER_TIMEOUT] = {"remote-tcp-user-timeout", required_argument, 0, 0},
|
||||
[IDX_MSS] = {"mss", required_argument, 0, 0},
|
||||
[IDX_FIX_SEG] = {"fix-seg", optional_argument, 0, 0},
|
||||
#ifdef SPLICE_PRESENT
|
||||
[IDX_NOSPLICE] = {"nosplice", no_argument, 0, 0},
|
||||
#endif
|
||||
#endif
|
||||
[IDX_HOSTLIST_AUTO_RETRANS_THRESHOLD] = {"hostlist-auto-retrans-threshold", optional_argument, 0, 0},
|
||||
[IDX_LAST] = {NULL, 0, NULL, 0},
|
||||
};
|
||||
|
||||
void parse_params(int argc, char *argv[])
|
||||
{
|
||||
int option_index = 0;
|
||||
@@ -622,6 +818,7 @@ void parse_params(int argc, char *argv[])
|
||||
params.maxconn = DEFAULT_MAX_CONN;
|
||||
params.max_orphan_time = DEFAULT_MAX_ORPHAN_TIME;
|
||||
params.binds_last = -1;
|
||||
params.ipcache_lifetime = IPCACHE_LIFETIME;
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
params.tcp_user_timeout_local = DEFAULT_TCP_USER_TIMEOUT_LOCAL;
|
||||
params.tcp_user_timeout_remote = DEFAULT_TCP_USER_TIMEOUT_REMOTE;
|
||||
@@ -664,96 +861,6 @@ void parse_params(int argc, char *argv[])
|
||||
}
|
||||
#endif
|
||||
|
||||
const struct option long_options[] = {
|
||||
{ "help",no_argument,0,0 },// optidx=0
|
||||
{ "h",no_argument,0,0 },// optidx=1
|
||||
{ "bind-addr",required_argument,0,0 },// optidx=2
|
||||
{ "bind-iface4",required_argument,0,0 },// optidx=3
|
||||
{ "bind-iface6",required_argument,0,0 },// optidx=4
|
||||
{ "bind-linklocal",required_argument,0,0 },// optidx=5
|
||||
{ "bind-wait-ifup",required_argument,0,0 },// optidx=6
|
||||
{ "bind-wait-ip",required_argument,0,0 },// optidx=7
|
||||
{ "bind-wait-ip-linklocal",required_argument,0,0 },// optidx=8
|
||||
{ "bind-wait-only",no_argument,0,0 },// optidx=9
|
||||
{ "port",required_argument,0,0 },// optidx=10
|
||||
{ "daemon",no_argument,0,0 },// optidx=11
|
||||
{ "user",required_argument,0,0 },// optidx=12
|
||||
{ "uid",required_argument,0,0 },// optidx=13
|
||||
{ "maxconn",required_argument,0,0 },// optidx=14
|
||||
{ "maxfiles",required_argument,0,0 },// optidx=15
|
||||
{ "max-orphan-time",required_argument,0,0 },// optidx=16
|
||||
{ "hostcase",no_argument,0,0 },// optidx=17
|
||||
{ "hostspell",required_argument,0,0 },// optidx=18
|
||||
{ "hostdot",no_argument,0,0 },// optidx=19
|
||||
{ "hostnospace",no_argument,0,0 },// optidx=20
|
||||
{ "hostpad",required_argument,0,0 },// optidx=21
|
||||
{ "domcase",no_argument,0,0 },// optidx=22
|
||||
{ "split-http-req",required_argument,0,0 },// optidx=23
|
||||
{ "split-tls",required_argument,0,0 },// optidx=24
|
||||
{ "split-pos",required_argument,0,0 },// optidx=25
|
||||
{ "split-any-protocol",optional_argument,0,0},// optidx=26
|
||||
{ "disorder",optional_argument,0,0 },// optidx=27
|
||||
{ "oob",optional_argument,0,0 },// optidx=28
|
||||
{ "oob-data",required_argument,0,0 },// optidx=29
|
||||
{ "methodspace",no_argument,0,0 },// optidx=30
|
||||
{ "methodeol",no_argument,0,0 },// optidx=31
|
||||
{ "hosttab",no_argument,0,0 },// optidx=32
|
||||
{ "unixeol",no_argument,0,0 },// optidx=33
|
||||
{ "tlsrec",required_argument,0,0 },// optidx=34
|
||||
{ "tlsrec-pos",required_argument,0,0 },// optidx=35
|
||||
{ "hostlist",required_argument,0,0 },// optidx=36
|
||||
{ "hostlist-domains",required_argument,0,0 },// optidx=37
|
||||
{ "hostlist-exclude",required_argument,0,0 },// optidx=38
|
||||
{ "hostlist-exclude-domains",required_argument,0,0 },// optidx=39
|
||||
{ "hostlist-auto",required_argument,0,0}, // optidx=40
|
||||
{ "hostlist-auto-fail-threshold",required_argument,0,0}, // optidx=41
|
||||
{ "hostlist-auto-fail-time",required_argument,0,0}, // optidx=42
|
||||
{ "hostlist-auto-debug",required_argument,0,0}, // optidx=43
|
||||
{ "pidfile",required_argument,0,0 },// optidx=44
|
||||
{ "debug",optional_argument,0,0 },// optidx=45
|
||||
{ "debug-level",required_argument,0,0 },// optidx=46
|
||||
{ "dry-run",no_argument,0,0 },// optidx=47
|
||||
{ "version",no_argument,0,0 },// optidx=48
|
||||
{ "comment",optional_argument,0,0 },// optidx=49
|
||||
{ "local-rcvbuf",required_argument,0,0 },// optidx=50
|
||||
{ "local-sndbuf",required_argument,0,0 },// optidx=51
|
||||
{ "remote-rcvbuf",required_argument,0,0 },// optidx=52
|
||||
{ "remote-sndbuf",required_argument,0,0 },// optidx=53
|
||||
{ "socks",no_argument,0,0 },// optidx=54
|
||||
{ "no-resolve",no_argument,0,0 },// optidx=55
|
||||
{ "resolver-threads",required_argument,0,0 },// optidx=56
|
||||
{ "skip-nodelay",no_argument,0,0 },// optidx=57
|
||||
{ "tamper-start",required_argument,0,0 },// optidx=58
|
||||
{ "tamper-cutoff",required_argument,0,0 },// optidx=59
|
||||
{ "connect-bind-addr",required_argument,0,0 },// optidx=60
|
||||
|
||||
{ "new",no_argument,0,0 }, // optidx=61
|
||||
{ "skip",no_argument,0,0 }, // optidx=62
|
||||
{ "filter-l3",required_argument,0,0 }, // optidx=63
|
||||
{ "filter-tcp",required_argument,0,0 }, // optidx=64
|
||||
{ "filter-l7",required_argument,0,0 }, // optidx=65
|
||||
{ "ipset",required_argument,0,0 }, // optidx=66
|
||||
{ "ipset-ip",required_argument,0,0 }, // optidx=67
|
||||
{ "ipset-exclude",required_argument,0,0 }, // optidx=68
|
||||
{ "ipset-exclude-ip",required_argument,0,0 }, // optidx=69
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
{ "enable-pf",no_argument,0,0 },// optidx=69
|
||||
#elif defined(__APPLE__)
|
||||
{ "local-tcp-user-timeout",required_argument,0,0 }, // optidx=79
|
||||
{ "remote-tcp-user-timeout",required_argument,0,0 }, // optidx=71
|
||||
#elif defined(__linux__)
|
||||
{ "local-tcp-user-timeout",required_argument,0,0 }, // optidx=70
|
||||
{ "remote-tcp-user-timeout",required_argument,0,0 }, // optidx=71
|
||||
{ "mss",required_argument,0,0 }, // optidx=72
|
||||
{ "fix-seg",optional_argument,0,0 }, // optidx=73
|
||||
#ifdef SPLICE_PRESENT
|
||||
{ "nosplice",no_argument,0,0 }, // optidx=74
|
||||
#endif
|
||||
#endif
|
||||
{ "hostlist-auto-retrans-threshold",optional_argument,0,0}, // ignored. for nfqws command line compatibility
|
||||
{ NULL,0,NULL,0 }
|
||||
};
|
||||
while ((v = getopt_long_only(argc, argv, "", long_options, &option_index)) != -1)
|
||||
{
|
||||
if (v)
|
||||
@@ -765,11 +872,11 @@ void parse_params(int argc, char *argv[])
|
||||
}
|
||||
switch (option_index)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case IDX_HELP:
|
||||
case IDX_H:
|
||||
exithelp_clean();
|
||||
break;
|
||||
case 2: /* bind-addr */
|
||||
case IDX_BIND_ADDR:
|
||||
nextbind_clean();
|
||||
{
|
||||
char *p = strchr(optarg,'%');
|
||||
@@ -782,19 +889,19 @@ void parse_params(int argc, char *argv[])
|
||||
}
|
||||
params.binds[params.binds_last].bindaddr[sizeof(params.binds[params.binds_last].bindaddr) - 1] = 0;
|
||||
break;
|
||||
case 3: /* bind-iface4 */
|
||||
case IDX_BIND_IFACE4:
|
||||
nextbind_clean();
|
||||
params.binds[params.binds_last].bind_if6=false;
|
||||
strncpy(params.binds[params.binds_last].bindiface, optarg, sizeof(params.binds[params.binds_last].bindiface));
|
||||
params.binds[params.binds_last].bindiface[sizeof(params.binds[params.binds_last].bindiface) - 1] = 0;
|
||||
break;
|
||||
case 4: /* bind-iface6 */
|
||||
case IDX_BIND_IFACE6:
|
||||
nextbind_clean();
|
||||
params.binds[params.binds_last].bind_if6=true;
|
||||
strncpy(params.binds[params.binds_last].bindiface, optarg, sizeof(params.binds[params.binds_last].bindiface));
|
||||
params.binds[params.binds_last].bindiface[sizeof(params.binds[params.binds_last].bindiface) - 1] = 0;
|
||||
break;
|
||||
case 5: /* bind-linklocal */
|
||||
case IDX_BIND_LINKLOCAL:
|
||||
checkbind_clean();
|
||||
params.binds[params.binds_last].bindll = true;
|
||||
if (!strcmp(optarg, "no"))
|
||||
@@ -811,22 +918,22 @@ void parse_params(int argc, char *argv[])
|
||||
exit_clean(1);
|
||||
}
|
||||
break;
|
||||
case 6: /* bind-wait-ifup */
|
||||
case IDX_BIND_WAIT_IFUP:
|
||||
checkbind_clean();
|
||||
params.binds[params.binds_last].bind_wait_ifup = atoi(optarg);
|
||||
break;
|
||||
case 7: /* bind-wait-ip */
|
||||
case IDX_BIND_WAIT_IP:
|
||||
checkbind_clean();
|
||||
params.binds[params.binds_last].bind_wait_ip = atoi(optarg);
|
||||
break;
|
||||
case 8: /* bind-wait-ip-linklocal */
|
||||
case IDX_BIND_WAIT_IP_LINKLOCAL:
|
||||
checkbind_clean();
|
||||
params.binds[params.binds_last].bind_wait_ip_ll = atoi(optarg);
|
||||
break;
|
||||
case 9: /* bind-wait-only */
|
||||
case IDX_BIND_WAIT_ONLY:
|
||||
params.bind_wait_only = true;
|
||||
break;
|
||||
case 10: /* port */
|
||||
case IDX_PORT:
|
||||
i = atoi(optarg);
|
||||
if (i <= 0 || i > 65535)
|
||||
{
|
||||
@@ -835,10 +942,10 @@ void parse_params(int argc, char *argv[])
|
||||
}
|
||||
params.port = (uint16_t)i;
|
||||
break;
|
||||
case 11: /* daemon */
|
||||
case IDX_DAEMON:
|
||||
params.daemon = true;
|
||||
break;
|
||||
case 12: /* user */
|
||||
case IDX_USER:
|
||||
{
|
||||
struct passwd *pwd = getpwnam(optarg);
|
||||
if (!pwd)
|
||||
@@ -851,7 +958,7 @@ void parse_params(int argc, char *argv[])
|
||||
params.droproot = true;
|
||||
break;
|
||||
}
|
||||
case 13: /* uid */
|
||||
case IDX_UID:
|
||||
params.gid=0x7FFFFFFF; // default git. drop gid=0
|
||||
params.droproot = true;
|
||||
if (sscanf(optarg,"%u:%u",¶ms.uid,¶ms.gid)<1)
|
||||
@@ -860,7 +967,7 @@ void parse_params(int argc, char *argv[])
|
||||
exit_clean(1);
|
||||
}
|
||||
break;
|
||||
case 14: /* maxconn */
|
||||
case IDX_MAXCONN:
|
||||
params.maxconn = atoi(optarg);
|
||||
if (params.maxconn <= 0 || params.maxconn > 10000)
|
||||
{
|
||||
@@ -868,7 +975,7 @@ void parse_params(int argc, char *argv[])
|
||||
exit_clean(1);
|
||||
}
|
||||
break;
|
||||
case 15: /* maxfiles */
|
||||
case IDX_MAXFILES:
|
||||
params.maxfiles = atoi(optarg);
|
||||
if (params.maxfiles < 0)
|
||||
{
|
||||
@@ -876,7 +983,7 @@ void parse_params(int argc, char *argv[])
|
||||
exit_clean(1);
|
||||
}
|
||||
break;
|
||||
case 16: /* max-orphan-time */
|
||||
case IDX_MAX_ORPHAN_TIME:
|
||||
params.max_orphan_time = atoi(optarg);
|
||||
if (params.max_orphan_time < 0)
|
||||
{
|
||||
@@ -884,11 +991,21 @@ void parse_params(int argc, char *argv[])
|
||||
exit_clean(1);
|
||||
}
|
||||
break;
|
||||
case 17: /* hostcase */
|
||||
case IDX_IPCACHE_LIFETIME:
|
||||
if (sscanf(optarg, "%u", ¶ms.ipcache_lifetime)!=1)
|
||||
{
|
||||
DLOG_ERR("invalid ipcache-lifetime value\n");
|
||||
exit_clean(1);
|
||||
}
|
||||
break;
|
||||
case IDX_IPCACHE_HOSTNAME:
|
||||
params.cache_hostname = !optarg || !!atoi(optarg);
|
||||
break;
|
||||
case IDX_HOSTCASE:
|
||||
dp->hostcase = true;
|
||||
params.tamper = true;
|
||||
break;
|
||||
case 18: /* hostspell */
|
||||
case IDX_HOSTSPELL:
|
||||
if (strlen(optarg) != 4)
|
||||
{
|
||||
DLOG_ERR("hostspell must be exactly 4 chars long\n");
|
||||
@@ -898,23 +1015,23 @@ void parse_params(int argc, char *argv[])
|
||||
memcpy(dp->hostspell, optarg, 4);
|
||||
params.tamper = true;
|
||||
break;
|
||||
case 19: /* hostdot */
|
||||
case IDX_HOSTDOT:
|
||||
dp->hostdot = true;
|
||||
params.tamper = true;
|
||||
break;
|
||||
case 20: /* hostnospace */
|
||||
case IDX_HOSTNOSPACE:
|
||||
dp->hostnospace = true;
|
||||
params.tamper = true;
|
||||
break;
|
||||
case 21: /* hostpad */
|
||||
case IDX_HOSTPAD:
|
||||
dp->hostpad = atoi(optarg);
|
||||
params.tamper = true;
|
||||
break;
|
||||
case 22: /* domcase */
|
||||
case IDX_DOMCASE:
|
||||
dp->domcase = true;
|
||||
params.tamper = true;
|
||||
break;
|
||||
case 23: /* split-http-req */
|
||||
case IDX_SPLIT_HTTP_REQ:
|
||||
DLOG_CONDUP("WARNING ! --split-http-req is deprecated. use --split-pos with markers.\n",MAX_SPLITS);
|
||||
if (dp->split_count>=MAX_SPLITS)
|
||||
{
|
||||
@@ -929,7 +1046,7 @@ void parse_params(int argc, char *argv[])
|
||||
dp->split_count++;
|
||||
params.tamper = true;
|
||||
break;
|
||||
case 24: /* split-tls */
|
||||
case IDX_SPLIT_TLS:
|
||||
// obsolete arg
|
||||
DLOG_CONDUP("WARNING ! --split-tls is deprecated. use --split-pos with markers.\n",MAX_SPLITS);
|
||||
if (dp->split_count>=MAX_SPLITS)
|
||||
@@ -945,7 +1062,7 @@ void parse_params(int argc, char *argv[])
|
||||
dp->split_count++;
|
||||
params.tamper = true;
|
||||
break;
|
||||
case 25: /* split-pos */
|
||||
case IDX_SPLIT_POS:
|
||||
{
|
||||
int ct;
|
||||
if (!parse_split_pos_list(optarg,dp->splits+dp->split_count,MAX_SPLITS-dp->split_count,&ct))
|
||||
@@ -957,10 +1074,10 @@ void parse_params(int argc, char *argv[])
|
||||
}
|
||||
params.tamper = true;
|
||||
break;
|
||||
case 26: /* split-any-protocol */
|
||||
case IDX_SPLIT_ANY_PROTOCOL:
|
||||
dp->split_any_protocol = true;
|
||||
break;
|
||||
case 27: /* disorder */
|
||||
case IDX_DISORDER:
|
||||
if (optarg)
|
||||
{
|
||||
if (!strcmp(optarg,"http")) dp->disorder_http=true;
|
||||
@@ -981,7 +1098,7 @@ void parse_params(int argc, char *argv[])
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case 28: /* oob */
|
||||
case IDX_OOB:
|
||||
if (optarg)
|
||||
{
|
||||
if (!strcmp(optarg,"http")) dp->oob_http=true;
|
||||
@@ -1002,7 +1119,7 @@ void parse_params(int argc, char *argv[])
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case 29: /* oob-data */
|
||||
case IDX_OOB_DATA:
|
||||
{
|
||||
size_t l = strlen(optarg);
|
||||
unsigned int bt;
|
||||
@@ -1015,23 +1132,23 @@ void parse_params(int argc, char *argv[])
|
||||
else dp->oob_byte = (uint8_t)bt;
|
||||
}
|
||||
break;
|
||||
case 30: /* methodspace */
|
||||
case IDX_METHODSPACE:
|
||||
dp->methodspace = true;
|
||||
params.tamper = true;
|
||||
break;
|
||||
case 31: /* methodeol */
|
||||
case IDX_METHODEOL:
|
||||
dp->methodeol = true;
|
||||
params.tamper = true;
|
||||
break;
|
||||
case 32: /* hosttab */
|
||||
case IDX_HOSTTAB:
|
||||
dp->hosttab = true;
|
||||
params.tamper = true;
|
||||
break;
|
||||
case 33: /* unixeol */
|
||||
case IDX_UNIXEOL:
|
||||
dp->unixeol = true;
|
||||
params.tamper = true;
|
||||
break;
|
||||
case 34: /* tlsrec */
|
||||
case IDX_TLSREC:
|
||||
if (!parse_split_pos(optarg, &dp->tlsrec) && !parse_tlspos(optarg, &dp->tlsrec))
|
||||
{
|
||||
DLOG_ERR("Invalid argument for tlsrec\n");
|
||||
@@ -1039,7 +1156,7 @@ void parse_params(int argc, char *argv[])
|
||||
}
|
||||
params.tamper = true;
|
||||
break;
|
||||
case 35: /* tlsrec-pos */
|
||||
case IDX_TLSREC_POS:
|
||||
// obsolete arg
|
||||
i = atoi(optarg);
|
||||
dp->tlsrec.marker = PM_ABS;
|
||||
@@ -1051,7 +1168,7 @@ void parse_params(int argc, char *argv[])
|
||||
}
|
||||
params.tamper = true;
|
||||
break;
|
||||
case 36: /* hostlist */
|
||||
case IDX_HOSTLIST:
|
||||
if (bSkip) break;
|
||||
if (!RegisterHostlist(dp, false, optarg))
|
||||
{
|
||||
@@ -1060,7 +1177,7 @@ void parse_params(int argc, char *argv[])
|
||||
}
|
||||
params.tamper = true;
|
||||
break;
|
||||
case 37: /* hostlist-domains */
|
||||
case IDX_HOSTLIST_DOMAINS:
|
||||
if (bSkip) break;
|
||||
if (!anon_hl && !(anon_hl=RegisterHostlist(dp, false, NULL)))
|
||||
{
|
||||
@@ -1074,7 +1191,7 @@ void parse_params(int argc, char *argv[])
|
||||
}
|
||||
params.tamper = true;
|
||||
break;
|
||||
case 38: /* hostlist-exclude */
|
||||
case IDX_HOSTLIST_EXCLUDE:
|
||||
if (bSkip) break;
|
||||
if (!RegisterHostlist(dp, true, optarg))
|
||||
{
|
||||
@@ -1083,7 +1200,7 @@ void parse_params(int argc, char *argv[])
|
||||
}
|
||||
params.tamper = true;
|
||||
break;
|
||||
case 39: /* hostlist-exclude-domains */
|
||||
case IDX_HOSTLIST_EXCLUDE_DOMAINS:
|
||||
if (bSkip) break;
|
||||
if (!anon_hl_exclude && !(anon_hl_exclude=RegisterHostlist(dp, true, NULL)))
|
||||
{
|
||||
@@ -1097,7 +1214,7 @@ void parse_params(int argc, char *argv[])
|
||||
}
|
||||
params.tamper = true;
|
||||
break;
|
||||
case 40: /* hostlist-auto */
|
||||
case IDX_HOSTLIST_AUTO:
|
||||
if (bSkip) break;
|
||||
if (dp->hostlist_auto)
|
||||
{
|
||||
@@ -1126,7 +1243,7 @@ void parse_params(int argc, char *argv[])
|
||||
}
|
||||
params.tamper = true; // need to detect blocks and update autohostlist. cannot just slice.
|
||||
break;
|
||||
case 41: /* hostlist-auto-fail-threshold */
|
||||
case IDX_HOSTLIST_AUTO_FAIL_THRESHOLD:
|
||||
dp->hostlist_auto_fail_threshold = (uint8_t)atoi(optarg);
|
||||
if (dp->hostlist_auto_fail_threshold<1 || dp->hostlist_auto_fail_threshold>20)
|
||||
{
|
||||
@@ -1134,7 +1251,7 @@ void parse_params(int argc, char *argv[])
|
||||
exit_clean(1);
|
||||
}
|
||||
break;
|
||||
case 42: /* hostlist-auto-fail-time */
|
||||
case IDX_HOSTLIST_AUTO_FAIL_TIME:
|
||||
dp->hostlist_auto_fail_time = (uint8_t)atoi(optarg);
|
||||
if (dp->hostlist_auto_fail_time<1)
|
||||
{
|
||||
@@ -1142,7 +1259,7 @@ void parse_params(int argc, char *argv[])
|
||||
exit_clean(1);
|
||||
}
|
||||
break;
|
||||
case 43: /* hostlist-auto-debug */
|
||||
case IDX_HOSTLIST_AUTO_DEBUG:
|
||||
{
|
||||
FILE *F = fopen(optarg,"a+t");
|
||||
if (!F)
|
||||
@@ -1155,11 +1272,11 @@ void parse_params(int argc, char *argv[])
|
||||
params.hostlist_auto_debuglog[sizeof(params.hostlist_auto_debuglog) - 1] = '\0';
|
||||
}
|
||||
break;
|
||||
case 44: /* pidfile */
|
||||
case IDX_PIDFILE:
|
||||
strncpy(params.pidfile,optarg,sizeof(params.pidfile));
|
||||
params.pidfile[sizeof(params.pidfile)-1]='\0';
|
||||
break;
|
||||
case 45: /* debug */
|
||||
case IDX_DEBUG:
|
||||
if (optarg)
|
||||
{
|
||||
if (*optarg=='@')
|
||||
@@ -1193,52 +1310,52 @@ void parse_params(int argc, char *argv[])
|
||||
params.debug_target = LOG_TARGET_CONSOLE;
|
||||
}
|
||||
break;
|
||||
case 46: /* debug-level */
|
||||
case IDX_DEBUG_LEVEL:
|
||||
params.debug = atoi(optarg);
|
||||
break;
|
||||
case 47: /* dry-run */
|
||||
case IDX_DRY_RUN:
|
||||
bDry = true;
|
||||
break;
|
||||
case 48: /* version */
|
||||
case IDX_VERSION:
|
||||
exit_clean(0);
|
||||
break;
|
||||
case 49: /* comment */
|
||||
case IDX_COMMENT:
|
||||
break;
|
||||
case 50: /* local-rcvbuf */
|
||||
case IDX_LOCAL_RCVBUF:
|
||||
#ifdef __linux__
|
||||
params.local_rcvbuf = atoi(optarg)/2;
|
||||
#else
|
||||
params.local_rcvbuf = atoi(optarg);
|
||||
#endif
|
||||
break;
|
||||
case 51: /* local-sndbuf */
|
||||
case IDX_LOCAL_SNDBUF:
|
||||
#ifdef __linux__
|
||||
params.local_sndbuf = atoi(optarg)/2;
|
||||
#else
|
||||
params.local_sndbuf = atoi(optarg);
|
||||
#endif
|
||||
break;
|
||||
case 52: /* remote-rcvbuf */
|
||||
case IDX_REMOTE_RCVBUF:
|
||||
#ifdef __linux__
|
||||
params.remote_rcvbuf = atoi(optarg)/2;
|
||||
#else
|
||||
params.remote_rcvbuf = atoi(optarg);
|
||||
#endif
|
||||
break;
|
||||
case 53: /* remote-sndbuf */
|
||||
case IDX_REMOTE_SNDBUF:
|
||||
#ifdef __linux__
|
||||
params.remote_sndbuf = atoi(optarg)/2;
|
||||
#else
|
||||
params.remote_sndbuf = atoi(optarg);
|
||||
#endif
|
||||
break;
|
||||
case 54: /* socks */
|
||||
case IDX_SOCKS:
|
||||
params.proxy_type = CONN_TYPE_SOCKS;
|
||||
break;
|
||||
case 55: /* no-resolve */
|
||||
case IDX_NO_RESOLVE:
|
||||
params.no_resolve = true;
|
||||
break;
|
||||
case 56: /* resolver-threads */
|
||||
case IDX_RESOLVER_THREADS:
|
||||
params.resolver_threads = atoi(optarg);
|
||||
if (params.resolver_threads<1 || params.resolver_threads>300)
|
||||
{
|
||||
@@ -1246,10 +1363,10 @@ void parse_params(int argc, char *argv[])
|
||||
exit_clean(1);
|
||||
}
|
||||
break;
|
||||
case 57: /* skip-nodelay */
|
||||
case IDX_SKIP_NODELAY:
|
||||
params.skip_nodelay = true;
|
||||
break;
|
||||
case 58: /* tamper-start */
|
||||
case IDX_TAMPER_START:
|
||||
{
|
||||
const char *p=optarg;
|
||||
if (*p=='n')
|
||||
@@ -1263,7 +1380,7 @@ void parse_params(int argc, char *argv[])
|
||||
}
|
||||
params.tamper_lim = true;
|
||||
break;
|
||||
case 59: /* tamper-cutoff */
|
||||
case IDX_TAMPER_CUTOFF:
|
||||
{
|
||||
const char *p=optarg;
|
||||
if (*p=='n')
|
||||
@@ -1277,7 +1394,7 @@ void parse_params(int argc, char *argv[])
|
||||
}
|
||||
params.tamper_lim = true;
|
||||
break;
|
||||
case 60: /* connect-bind-addr */
|
||||
case IDX_CONNECT_BIND_ADDR:
|
||||
{
|
||||
char *p = strchr(optarg,'%');
|
||||
if (p) *p++=0;
|
||||
@@ -1305,7 +1422,7 @@ void parse_params(int argc, char *argv[])
|
||||
break;
|
||||
|
||||
|
||||
case 61: /* new */
|
||||
case IDX_NEW:
|
||||
if (bSkip)
|
||||
{
|
||||
dp_clear(dp);
|
||||
@@ -1326,31 +1443,31 @@ void parse_params(int argc, char *argv[])
|
||||
anon_hl = anon_hl_exclude = NULL;
|
||||
anon_ips = anon_ips_exclude = NULL;
|
||||
break;
|
||||
case 62: /* skip */
|
||||
case IDX_SKIP:
|
||||
bSkip = true;
|
||||
break;
|
||||
case 63: /* filter-l3 */
|
||||
case IDX_FILTER_L3:
|
||||
if (!wf_make_l3(optarg,&dp->filter_ipv4,&dp->filter_ipv6))
|
||||
{
|
||||
DLOG_ERR("bad value for --filter-l3\n");
|
||||
exit_clean(1);
|
||||
}
|
||||
break;
|
||||
case 64: /* filter-tcp */
|
||||
case IDX_FILTER_TCP:
|
||||
if (!parse_pf_list(optarg,&dp->pf_tcp))
|
||||
{
|
||||
DLOG_ERR("Invalid port filter : %s\n",optarg);
|
||||
exit_clean(1);
|
||||
}
|
||||
break;
|
||||
case 65: /* filter-l7 */
|
||||
case IDX_FILTER_L7:
|
||||
if (!parse_l7_list(optarg,&dp->filter_l7))
|
||||
{
|
||||
DLOG_ERR("Invalid l7 filter : %s\n",optarg);
|
||||
exit_clean(1);
|
||||
}
|
||||
break;
|
||||
case 66: /* ipset */
|
||||
case IDX_IPSET:
|
||||
if (bSkip) break;
|
||||
if (!RegisterIpset(dp, false, optarg))
|
||||
{
|
||||
@@ -1359,7 +1476,7 @@ void parse_params(int argc, char *argv[])
|
||||
}
|
||||
params.tamper = true;
|
||||
break;
|
||||
case 67: /* ipset-ip */
|
||||
case IDX_IPSET_IP:
|
||||
if (bSkip) break;
|
||||
if (!anon_ips && !(anon_ips=RegisterIpset(dp, false, NULL)))
|
||||
{
|
||||
@@ -1373,7 +1490,7 @@ void parse_params(int argc, char *argv[])
|
||||
}
|
||||
params.tamper = true;
|
||||
break;
|
||||
case 68: /* ipset-exclude */
|
||||
case IDX_IPSET_EXCLUDE:
|
||||
if (bSkip) break;
|
||||
if (!RegisterIpset(dp, true, optarg))
|
||||
{
|
||||
@@ -1382,7 +1499,7 @@ void parse_params(int argc, char *argv[])
|
||||
}
|
||||
params.tamper = true;
|
||||
break;
|
||||
case 69: /* ipset-exclude-ip */
|
||||
case IDX_IPSET_EXCLUDE_IP:
|
||||
if (bSkip) break;
|
||||
if (!anon_ips_exclude && !(anon_ips_exclude=RegisterIpset(dp, true, NULL)))
|
||||
{
|
||||
@@ -1398,11 +1515,11 @@ void parse_params(int argc, char *argv[])
|
||||
break;
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
case 70: /* enable-pf */
|
||||
case IDX_ENABLE_PF:
|
||||
params.pf_enable = true;
|
||||
break;
|
||||
#elif defined(__linux__) || defined(__APPLE__)
|
||||
case 70: /* local-tcp-user-timeout */
|
||||
case IDX_LOCAL_TCP_USER_TIMEOUT:
|
||||
params.tcp_user_timeout_local = atoi(optarg);
|
||||
if (params.tcp_user_timeout_local<0 || params.tcp_user_timeout_local>86400)
|
||||
{
|
||||
@@ -1410,7 +1527,7 @@ void parse_params(int argc, char *argv[])
|
||||
exit_clean(1);
|
||||
}
|
||||
break;
|
||||
case 71: /* remote-tcp-user-timeout */
|
||||
case IDX_REMOTE_TCP_USER_TIMEOUT:
|
||||
params.tcp_user_timeout_remote = atoi(optarg);
|
||||
if (params.tcp_user_timeout_remote<0 || params.tcp_user_timeout_remote>86400)
|
||||
{
|
||||
@@ -1421,7 +1538,7 @@ void parse_params(int argc, char *argv[])
|
||||
#endif
|
||||
|
||||
#if defined(__linux__)
|
||||
case 72: /* mss */
|
||||
case IDX_MSS:
|
||||
// this option does not work in any BSD and MacOS. OS may accept but it changes nothing
|
||||
dp->mss = atoi(optarg);
|
||||
if (dp->mss<88 || dp->mss>32767)
|
||||
@@ -1430,7 +1547,7 @@ void parse_params(int argc, char *argv[])
|
||||
exit_clean(1);
|
||||
}
|
||||
break;
|
||||
case 73: /* fix-seg */
|
||||
case IDX_FIX_SEG:
|
||||
if (!params.fix_seg_avail)
|
||||
{
|
||||
DLOG_ERR("--fix-seg is supported since kernel 4.6\n");
|
||||
@@ -1450,7 +1567,7 @@ void parse_params(int argc, char *argv[])
|
||||
params.fix_seg = FIX_SEG_DEFAULT_MAX_WAIT;
|
||||
break;
|
||||
#ifdef SPLICE_PRESENT
|
||||
case 74: /* nosplice */
|
||||
case IDX_NOSPLICE:
|
||||
params.nosplice = true;
|
||||
break;
|
||||
#endif
|
||||
@@ -1521,6 +1638,9 @@ void parse_params(int argc, char *argv[])
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!test_list_files())
|
||||
exit_clean(1);
|
||||
|
||||
if (!LoadAllHostLists())
|
||||
{
|
||||
DLOG_ERR("hostlists load failed\n");
|
||||
@@ -1723,14 +1843,6 @@ int main(int argc, char *argv[])
|
||||
parse_params(argc, argv);
|
||||
argv=NULL; argc=0;
|
||||
|
||||
if (params.daemon) daemonize();
|
||||
|
||||
if (*params.pidfile && !writepid(params.pidfile))
|
||||
{
|
||||
DLOG_ERR("could not write pidfile\n");
|
||||
goto exiterr;
|
||||
}
|
||||
|
||||
memset(&list, 0, sizeof(list));
|
||||
for(i=0;i<=params.binds_last;i++) listen_fd[i]=-1;
|
||||
|
||||
@@ -1962,6 +2074,18 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
if (params.cache_hostname) VPRINT("ipcache lifetime %us\n", params.ipcache_lifetime);
|
||||
DLOG_CONDUP(params.proxy_type==CONN_TYPE_SOCKS ? "socks mode\n" : "transparent proxy mode\n");
|
||||
if (!params.tamper) DLOG_CONDUP("TCP proxy mode (no tampering)\n");
|
||||
|
||||
if (params.daemon) daemonize();
|
||||
|
||||
if (*params.pidfile && !writepid(params.pidfile))
|
||||
{
|
||||
DLOG_ERR("could not write pidfile\n");
|
||||
goto exiterr;
|
||||
}
|
||||
|
||||
set_ulimit();
|
||||
sec_harden();
|
||||
if (params.droproot && !droproot(params.uid,params.gid))
|
||||
@@ -1982,9 +2106,6 @@ int main(int argc, char *argv[])
|
||||
goto exiterr;
|
||||
}
|
||||
|
||||
DLOG_CONDUP(params.proxy_type==CONN_TYPE_SOCKS ? "socks mode\n" : "transparent proxy mode\n");
|
||||
if (!params.tamper) DLOG_CONDUP("TCP proxy mode (no tampering)\n");
|
||||
|
||||
signal(SIGHUP, onhup);
|
||||
signal(SIGUSR2, onusr2);
|
||||
|
||||
|
Reference in New Issue
Block a user