Compare commits

...

46 Commits

Author SHA1 Message Date
bol-van
5c63cb43e7 readme: update vps section 2025-05-06 09:58:03 +03:00
bol-van
7f24f82002 readme: update vps section 2025-05-06 09:51:53 +03:00
bol-van
b0c7af789a init: remove autohostlist touch, not needed anymore 2025-05-04 22:02:36 +03:00
bol-van
a426ea6dad nfqws,tpws: check list files accessibility after all params are parsed 2025-05-04 22:01:00 +03:00
bol-van
bda4226162 init: create autohostlist file if not exists 2025-05-04 21:47:26 +03:00
bol-van
dc1dc5c876 drop time exceeded icmp for nfqws-related connections 2025-05-04 18:21:43 +03:00
bol-van
3ca682e25a drop time exceeded icmp for nfqws-related connections 2025-05-04 18:15:33 +03:00
bol-van
9629ce5cb7 tpws: ipcache 2025-05-04 10:57:23 +03:00
bol-van
c626d88f54 nfqws: minor changes 2025-05-04 10:42:27 +03:00
bol-van
c91ddf4a54 nfqws: do not use interface name for ip->hostname 2025-05-03 22:06:14 +03:00
bol-van
6f1286b5b9 nfqws: fix mem leak 2025-05-03 21:59:43 +03:00
bol-van
c96bc62d3b nfqws: ip->hostname cache 2025-05-03 20:25:53 +03:00
bol-van
8432388b37 nfqws: debug autottl cache lifetime 2025-05-03 15:15:26 +03:00
bol-van
7efa83e61e init.d: remove --ipset prohibition 2025-05-03 13:03:33 +03:00
bol-van
abe91a4bfa nfqws: ipcache destroy in cleanup_params 2025-05-03 12:50:53 +03:00
bol-van
43173e6396 nfqws: return autottl path len check 2025-05-03 12:28:49 +03:00
bol-van
5cc888cd2c nfqws: autottl cache, --dup-autottl, --orig-autottl 2025-05-03 12:11:16 +03:00
bol-van
5b625fa709 update nftables.txt,iptables.txt 2025-05-03 10:54:59 +03:00
bol-van
0a8135b2de update config defaults 2025-05-03 10:52:20 +03:00
bol-van
d21175b4a3 nfqws: prepare for +- autottl 2025-04-29 17:45:34 +03:00
bol-van
68a538daed nfqws: conntrack: do not reset entry on dup SA 2025-04-29 16:31:37 +03:00
bol-van
d2c9ff50cd nfqws: copy DF ip flag 2025-04-29 13:36:05 +03:00
bol-van
50539d6cbf nfqws: windows fixes for recent changes 2025-04-29 12:25:23 +03:00
bol-van
8b5dfcfae1 nfqws: dup,orig_mod 2025-04-26 19:48:35 +03:00
bol-van
ccc60b5f07 init.d: fix missing - sign in 50-nfqws-ipset 2025-04-22 19:28:14 +03:00
bol-van
7f94f42b1d init.d: fix local var name 2025-04-22 19:07:26 +03:00
bol-van
1c1f259b39 init.d: improve nfqws ipset example 2025-04-22 19:03:18 +03:00
bol-van
6ef6c8ee5a nfqws: do not use overlapping memcmp 2025-04-21 15:54:06 +03:00
bol-van
581badfb73 nfqws: --dpi-desync-fake-tls=! 2025-04-21 14:52:51 +03:00
bol-van
8fce75daa4 hardware offload: be closer to fw4 in interface names 2025-04-20 11:26:07 +03:00
bol-van
c1e2e56576 hardware offload: be closer to fw4 in interface names 2025-04-20 11:24:55 +03:00
bol-van
e16ec69922 nfqws: fix unitialized use of host buffer (udp) 2025-04-20 08:49:50 +03:00
bol-van
63256a142f nfqws: fix unitialized use of host buffer 2025-04-19 19:59:42 +03:00
bol-van
4a9a8bd48e typo 2025-04-19 19:41:40 +03:00
bol-van
b996abd5ce nfqws,tpws: use tls record length in TLSDebug 2025-04-14 12:18:07 +03:00
bol-van
12461de3b0 nfqws,tpws: optimize tls debug, show quic 2025-04-14 11:21:16 +03:00
bol-van
7dab497b57 nfqws,tpws: optimize tls debug, show quic 2025-04-14 11:20:20 +03:00
bol-van
41dbba1c4c nfqws,tpws: debug alpn and ech 2025-04-13 18:07:46 +03:00
bol-van
d19f6c19a4 nfqws,tpws: debug tls version 2025-04-13 15:27:50 +03:00
bol-van
b12b1a5a17 winws build fix 2025-04-08 17:33:14 +03:00
bol-van
8022e2576d nfqws: BSD/clang build fix 2025-04-08 17:23:15 +03:00
bol-van
f4ea264ba9 minor var spelling fix 2025-04-08 17:02:33 +03:00
bol-van
061acb27e4
Merge pull request #1334 from tie/master
use enum for option indices
2025-04-08 17:00:53 +03:00
Ivan Trubach
8eb830d304 use enum for option indices 2025-04-08 16:56:17 +03:00
bol-van
2fb93c6add blockcheck: test tpws exists 2025-04-08 16:17:40 +03:00
bol-van
ad5c246629 blockcheck: test whether tpws supports fix-seg 2025-04-08 16:15:06 +03:00
41 changed files with 2941 additions and 919 deletions

View File

@ -341,6 +341,12 @@ 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() check_system()
{ {
echo \* checking system echo \* checking system
@ -355,7 +361,14 @@ check_system()
Linux) Linux)
PKTWS="$NFQWS" PKTWS="$NFQWS"
PKTWSD=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' FIX_SEG='--fix-seg'
else
echo tpws does not support --fix-seg on this system
fi
fi
linux_fwtype linux_fwtype
[ "$FWTYPE" = iptables -o "$FWTYPE" = nftables ] || { [ "$FWTYPE" = iptables -o "$FWTYPE" = nftables ] || {
echo firewall type $FWTYPE not supported in $UNAME echo firewall type $FWTYPE not supported in $UNAME
@ -722,6 +735,11 @@ ipt_aux_scheme()
# to avoid possible INVALID state drop # to avoid possible INVALID state drop
[ "$2" = tcp ] && IPT_ADD_DEL $1 INPUT -p $2 --sport $3 ! --syn -j ACCEPT [ "$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) # for strategies with incoming packets involved (autottl)
IPT_ADD_DEL $1 OUTPUT -p $2 --dport $3 -m conntrack --ctstate INVALID -j ACCEPT IPT_ADD_DEL $1 OUTPUT -p $2 --dport $3 -m conntrack --ctstate INVALID -j ACCEPT
if [ "$IPV" = 6 -a -n "$IP6_DEFRAG_DISABLE" ]; then if [ "$IPV" = 6 -a -n "$IP6_DEFRAG_DISABLE" ]; then
@ -753,6 +771,7 @@ ipt_scheme()
$IPTABLES -t mangle -A blockcheck_output -p $1 ! --dport $2 -j RETURN $IPTABLES -t mangle -A blockcheck_output -p $1 ! --dport $2 -j RETURN
for ip in $3; do 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 $IPTABLES -t mangle -A blockcheck_output -d $ip -j NFQUEUE --queue-num $QNUM
done done
@ -770,12 +789,20 @@ nft_scheme()
nft add table inet $NFT_TABLE nft add table inet $NFT_TABLE
nft "add chain inet $NFT_TABLE postnat { type filter hook output priority 102; }" 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) # for strategies with incoming packets involved (autottl)
nft "add chain inet $NFT_TABLE prenat { type filter hook prerouting priority -102; }" 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) # 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 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" 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() pktws_ipt_prepare()

View File

@ -405,14 +405,14 @@ std_ports()
has_bad_ws_options() has_bad_ws_options()
{ {
# $1 - nfqws/tpws opts # $1 - nfqws/tpws opts
# ПРИМЕЧАНИЕ ДЛЯ РАСПРОСТРАНИТЕЛЕЙ КОПИПАСТЫ
# ЭТОТ КОД СДЕЛАН СПЕЦИАЛЬНО ДЛЯ ВАС, ЧТОБЫ ВЫ НЕ ПОСТИЛИ В СЕТЬ ПЛОХИЕ РЕЦЕПТЫ # kernel or user mode ipset usage should be wise
# ЕСЛИ ВАМ ХОЧЕТСЯ ЕГО УДАЛИТЬ И НАПИСАТЬ ИНСТРУКЦИЮ КАК ЕГО УДАЛЯТЬ, ВЫ ДЕЛАЕТЕ ХРЕНОВУЮ УСЛУГУ. НАПИШИТЕ ЛУЧШЕ custom script. # if all traffic is already intercepted it would be OK to use ip-based specialized profiles
# custom script - ЭТО ФАЙЛИК, КОТОРЫЙ ДОСТАТОЧНО СКОПИРОВАТЬ В НУЖНУЮ ДИРЕКТОРИЮ, ЧТОБЫ ОН СДЕЛАЛ ТОЖЕ САМОЕ, НО ЭФФЕКТИВНО. # but if all traffic is intercepted only to filter a group of ip its BAD. kernel ipset should be used.
# ФИЛЬТРАЦИЯ ПО IPSET В ЯДРЕ НЕСРАВНИМО ЭФФЕКТИВНЕЕ, ЧЕМ ПЕРЕКИДЫВАТЬ ВСЕ ПАКЕТЫ В nfqws И ТАМ ФИЛЬТРОВАТЬ # I cannot insert brain to copy-pasters, I know they will misuse. But it's their problem.
# --ipset СУЩЕСТВУЕТ ТОЛЬКО ДЛЯ ВИНДЫ И LINUX СИСТЕМ БЕЗ ipset (НАПРИМЕР, Android). # zapret is not made for newbies
# И ТОЛЬКО ПО ЭТОЙ ПРИЧИНЕ ОНО НЕ ВЫКИНУТО ПОЛНОСТЬЮ ИЗ LINUX ВЕРСИИ #contains "$1" "--ipset"
contains "$1" "--ipset" return 1
} }
check_bad_ws_options() check_bad_ws_options()
{ {

View File

@ -391,6 +391,27 @@ zapret_do_firewall_rules_ipt()
zapret_do_firewall_standard_rules_ipt $1 zapret_do_firewall_standard_rules_ipt $1
custom_runner zapret_custom_firewall $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() zapret_do_firewall_ipt()

View File

@ -111,6 +111,14 @@ unprepare_route_localnet()
set_route_localnet 0 "$@" 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() resolve_lower_devices()
{ {
# $1 - bridge interface name # $1 - bridge interface name

View File

@ -106,7 +106,7 @@ cat << EOF | nft -f -
flush chain inet $ZAPRET_NFT_TABLE predefrag_nfqws 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 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 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 exthdr frag exists notrack comment "ipfrag"
add rule inet $ZAPRET_NFT_TABLE predefrag_nfqws tcp flags ! syn,rst,ack notrack comment "datanoack" 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; } add set inet $ZAPRET_NFT_TABLE lanif { type ifname; }
@ -119,6 +119,20 @@ EOF
nft_flush_chain predefrag_nfqws nft_flush_chain predefrag_nfqws
nft_add_rule predefrag_nfqws notrack comment \"do not track nfqws generated packets to avoid nat tampering and defragmentation\" 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() nft_del_chains()
{ {
@ -320,7 +334,7 @@ nft_fill_ifsets()
# $5 - space separated wan physical interface names (optional) # $5 - space separated wan physical interface names (optional)
# $6 - space separated wan6 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 # if large sets exist nft works very ineffectively
# looks like it analyzes the whole table blob to find required data pieces # 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 nft_create_or_update_flowtable 'offload' 2>/dev/null
# then add elements. some of them can cause error because unsupported # then add elements. some of them can cause error because unsupported
for i in $ALLDEVS; do 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 # 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 # some members may not support hw offload. example : lan1 lan2 lan3 support, wlan0 wlan1 - not
b=
devs=$(resolve_lower_devices $i) devs=$(resolve_lower_devices $i)
for j in $devs; do for j in $devs; do
# do not display error if addition failed # 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 done
[ -n "$b" ] || {
# no lower devices added ? try to add interface itself
nft_create_or_update_flowtable 'offload' $i 2>/dev/null
}
done done
;; ;;
esac esac
@ -453,7 +470,7 @@ _nft_fw_nfqws_post4()
nft_print_op "$filter" "nfqws postrouting (qnum $port)" 4 nft_print_op "$filter" "nfqws postrouting (qnum $port)" 4
rule="${3:+oifname @wanif }$filter ip daddr != @nozapret" rule="${3:+oifname @wanif }$filter ip daddr != @nozapret"
is_postnat && setmark="meta mark set meta mark or $DESYNC_MARK_POSTNAT" is_postnat && setmark="meta mark set meta mark or $DESYNC_MARK_POSTNAT"
nft_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" nft_add_nfqws_flow_exempt_rule "$rule"
} }
} }
@ -468,7 +485,7 @@ _nft_fw_nfqws_post6()
nft_print_op "$filter" "nfqws postrouting (qnum $port)" 6 nft_print_op "$filter" "nfqws postrouting (qnum $port)" 6
rule="${3:+oifname @wanif6 }$filter ip6 daddr != @nozapret6" rule="${3:+oifname @wanif6 }$filter ip6 daddr != @nozapret6"
is_postnat && setmark="meta mark set meta mark or $DESYNC_MARK_POSTNAT" is_postnat && setmark="meta mark set meta mark or $DESYNC_MARK_POSTNAT"
nft_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" nft_add_nfqws_flow_exempt_rule "$rule"
} }
} }
@ -492,7 +509,7 @@ _nft_fw_nfqws_pre4()
local filter="$1" port="$2" rule local filter="$1" port="$2" rule
nft_print_op "$filter" "nfqws prerouting (qnum $port)" 4 nft_print_op "$filter" "nfqws prerouting (qnum $port)" 4
rule="${3:+iifname @wanif }$filter ip saddr != @nozapret" rule="${3:+iifname @wanif }$filter ip saddr != @nozapret"
nft_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() _nft_fw_nfqws_pre6()
@ -505,7 +522,7 @@ _nft_fw_nfqws_pre6()
local filter="$1" port="$2" rule local filter="$1" port="$2" rule
nft_print_op "$filter" "nfqws prerouting (qnum $port)" 6 nft_print_op "$filter" "nfqws prerouting (qnum $port)" 6
rule="${3:+iifname @wanif6 }$filter ip6 saddr != @nozapret6" rule="${3:+iifname @wanif6 }$filter ip6 saddr != @nozapret6"
nft_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() nft_fw_nfqws_pre()
@ -683,3 +700,7 @@ zapret_do_firewall_nft()
return 0 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"

View File

@ -129,6 +129,11 @@ INIT_APPLY_FW=1
# do not work with ipv6 # do not work with ipv6
DISABLE_IPV6=1 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 # 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 # possible values : get_user.sh get_antizapret.sh get_combined.sh get_reestr.sh get_hostlist.sh
# comment if not required # comment if not required

View File

@ -481,3 +481,15 @@ nfqws: update default TLS ClientHello fake. firefox 136.0.4 finger, no kyber, SN
nfqws: multiple mods for multiple TLS fakes nfqws: multiple mods for multiple TLS fakes
init.d: remove 50-discord init.d: remove 50-discord
blockcheck: use tpws --fix-seg on linux for multiple splits 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

View File

@ -1,4 +1,4 @@
# zapret v70.6 # zapret v70.7
# SCAMMER WARNING # SCAMMER WARNING
@ -173,7 +173,7 @@ nfqws takes the following parameters:
--dpi-desync-badack-increment=<int|0xHEX> ; badseq fooling ackseq signed increment. default -66000 --dpi-desync-badack-increment=<int|0xHEX> ; badseq fooling ackseq signed increment. default -66000
--dpi-desync-any-protocol=0|1 ; 0(default)=desync only http and tls 1=desync any nonempty data packet --dpi-desync-any-protocol=0|1 ; 0(default)=desync only http and tls 1=desync any nonempty data packet
--dpi-desync-fake-http=<filename>|0xHEX ; file containing fake http request --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=<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-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-unknown=<filename>|0xHEX ; file containing unknown protocol fake payload
--dpi-desync-fake-syndata=<filename>|0xHEX ; file containing SYN data payload --dpi-desync-fake-syndata=<filename>|0xHEX ; file containing SYN data payload

View File

@ -1,4 +1,4 @@
# zapret v70.6 # zapret v70.7
# ВНИМАНИЕ, остерегайтесь мошенников # ВНИМАНИЕ, остерегайтесь мошенников
@ -195,7 +195,7 @@ dvtws, собираемый из тех же исходников (см. [док
--dpi-desync-badack-increment=<int|0xHEX> ; инкремент ack sequence number для badseq. по умолчанию -66000 --dpi-desync-badack-increment=<int|0xHEX> ; инкремент ack sequence number для badseq. по умолчанию -66000
--dpi-desync-any-protocol=0|1 ; 0(default)=работать только по http request и tls clienthello 1=по всем непустым пакетам данных --dpi-desync-any-protocol=0|1 ; 0(default)=работать только по http request и tls clienthello 1=по всем непустым пакетам данных
--dpi-desync-fake-http=<filename>|0xHEX ; файл, содержащий фейковый http запрос для dpi-desync=fake, на замену стандартному www.iana.org --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=<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-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-unknown=<filename>|0xHEX ; файл, содержащий фейковый пейлоад неизвестного протокола для dpi-desync=fake, на замену стандартным нулям 256 байт
--dpi-desync-fake-syndata=<filename>|0xHEX ; файл, содержащий фейковый пейлоад пакета SYN для режима десинхронизации syndata --dpi-desync-fake-syndata=<filename>|0xHEX ; файл, содержащий фейковый пейлоад пакета SYN для режима десинхронизации syndata
@ -2334,38 +2334,32 @@ OpenWrt является одной из немногих относительн
VPS — это виртуальный сервер. Существует огромное множество датацентров, предлагающих данную услугу. VPS — это виртуальный сервер. Существует огромное множество датацентров, предлагающих данную услугу.
На VPS могут выполняться какие угодно задачи. От простого веб-сайта до навороченной системы собственной разработки. На VPS могут выполняться какие угодно задачи. От простого веб-сайта до навороченной системы собственной разработки.
Можно использовать VPS и для поднятия собственного VPN или прокси. Можно использовать VPS и для поднятия собственного VPN или прокси.
Сама широта возможных способов применения и распространенность услуги сводят к минимуму возможности Сама широта возможных способов применения и распространенность услуги ограничивают возможности регуляторов
регуляторов по бану сервисов такого типа. Да, если введут белые списки, то решение загнется, но это будет уже другая по бану сервисов такого типа. Да, если введут белые списки, то решение загнется, но это будет уже другая
реальность, в которой придется изобретать иные решения. реальность, в которой придется изобретать иные решения.
Пока этого не сделали, никто не будет банить хостинги просто потому, что они предоставляют хостинг услуги. Пока этого не сделали. Однако, уже наблюдаются попытки гасить некоторые протоколы на диапазонах VPS провайдеров.
Вы, как индивидуум, скорее всего, никому не нужны. Подумайте чем вы отличаетесь от известного VPN провайдера. Вплоть до TLS. Как следствие не работают ни средства обхода типа VLESS, ни обычные сайты.
Пока это делается еще точечно, не на всех провайдерах. Не стоит сразу оплачивать VPS надолго. Сначала проверьте
все ли работает из того, что вам нужно. Или может быть стоит найти другой VPS.
VPS имеет преимущество над VPN провайдером.
VPN-провайдер предоставляет _простую_ и оступную_ услугу по обходу блокировок для масс. VPN-провайдер предоставляет _простую_ и оступную_ услугу по обходу блокировок для масс.
Этот факт делает его первоочередной целью блокировки. РКН направит уведомление, после отказа сотрудничать Все, что просто и доступно, первым делом идет под блок.
заблокирует VPN. Предоплаченная сумма пропадет.
У регуляторов нет и никогда не будет ресурсов для тотальной проверки каждого сервера в сети.
Возможен китайский расклад, при котором DPI выявляет VPN-протоколы и динамически банит IP серверов, Возможен китайский расклад, при котором DPI выявляет VPN-протоколы и динамически банит IP серверов,
предоставляющих нелицензированный VPN. Но имея знания, голову, вы всегда можете обфусцировать предоставляющих нелицензированный VPN. Но имея знания, голову, вы всегда можете обфусцировать
VPN трафик или применить другие типы VPN, более устойчивые к анализу на DPI, или просто менее широкоизвестные, VPN трафик или применить другие типы VPN, более устойчивые к анализу на DPI, или просто менее широкоизвестные,
а следовательно с меньшей вероятностью обнаруживаемые регулятором. а следовательно с меньшей вероятностью обнаруживаемые регулятором.
У вас есть свобода делать на вашем VPS все что вы захотите, адаптируясь к новым условиям. У вас есть свобода делать на вашем VPS все что вы захотите, адаптируясь к новым условиям.
Да, это потребует знаний. Вам выбирать учиться и держать ситуацию под контролем, когда вам ничего запретить Да, это потребует знаний. Вам выбирать учиться и держать ситуацию под контролем, когда вам ничего запретить
не могут, или покориться системе. не могут, или покориться системе. Порог необходимых знаний и возможностей для самостоятельного входа в обход блокировок будет только возрастать.
VPS можно приобрести в множестве мест. Существуют специализированные на поиске предложений VPS порталы.\ VPS можно приобрести в множестве мест. Существуют специализированные на поиске предложений VPS порталы.\
Например, [вот этот](https://vps.today). Например, [вот этот](https://vps.today). Для персонального VPN сервера обычно достаточно самой минимальной конфигурации, но с безлимитным трафиком или
Для персонального VPN сервера обычно достаточно самой минимальной конфигурации, но с безлимитным трафиком или
с большим лимитом по трафику (терабайты). Важен и тип VPS. OpenVZ подойдёт для OpenVPN, но с большим лимитом по трафику (терабайты). Важен и тип VPS. OpenVZ подойдёт для OpenVPN, но
вы не поднимете на нем WireGuard, IPsec, то есть все, что требует kernel mode. вы не поднимете на нем WireGuard, IPsec, то есть все, что требует kernel mode.
Для kernel mode требуется тип виртуализации, предполагающий запуск полноценного экземпляра ОС linux Для kernel mode требуется тип виртуализации, предполагающий запуск полноценного экземпляра ОС linux
вместе с ядром. Подойдут KVM, Xen, Hyper-V, VMware. вместе с ядром. Подойдут KVM, Xen, Hyper-V, VMware.
По цене можно найти предложения, которые будут дешевле готовой VPN услуги, но при этом вы сам хозяин в своей лавке
и не рискуете попасть под бан регулятора, разве что «заодно» — под ковровую бомбардировку с баном миллионов IP.
Кроме того, если вам совсем все кажется сложным, прочитанное вызывает ступор и вы точно знаете, что ничего
из описанного сделать не сможете, то вы сможете хотя бы использовать динамическое перенаправление портов SSH
для получения шифрованного SOCKS-прокси и прописать его в браузер. Знания linux не нужны совсем.
Это вариант наименее напряжный для чайников, хотя и не самый удобный в использовании.
## Поддержать разработчика ## Поддержать разработчика
USDT `0x3d52Ce15B7Be734c53fc9526ECbAB8267b63d66E` USDT `0x3d52Ce15B7Be734c53fc9526ECbAB8267b63d66E`

View File

@ -1,19 +1,29 @@
# this custom script demonstrates how to launch extra nfqws instance limited by ipset. ipv4 only. # this custom script demonstrates how to launch extra nfqws instance limited by ipset
# can override in config : # can override in config :
NFQWS_OPT_DESYNC_NFQWS_MY1="${NFQWS_OPT_DESYNC_NFQWS_MY1:---dpi-desync=fake --dpi-desync-repeats=6 --dpi-desync-any-protocol}" 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_PORTS=${NFQWS_MY1_PORTS:-6000-6009} 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_SUBNETS="${NFQWS_MY1_SUBNETS:-34.0.48.0/21 34.0.56.0/23 34.0.59.0/24 34.0.60.0/24 34.0.62.0/23}" 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_dnum DNUM_NFQWS_MY1
alloc_qnum QNUM_NFQWS_MY1 alloc_qnum QNUM_NFQWS_MY1
NFQWS_MY1_SET_NAME=my1nfqws4 NFQWS_MY1_NAME4=my1nfqws4
NFQWS_MY1_NAME6=my1nfqws6
zapret_custom_daemons() zapret_custom_daemons()
{ {
# $1 - 1 - run, 0 - stop # $1 - 1 - run, 0 - stop
local opt="--qnum=$QNUM_NFQWS_MY1 $NFQWS_OPT_DESYNC_NFQWS_MY1" local opt="--qnum=$QNUM_NFQWS_MY1 $NFQWS_MY1_OPT"
do_nfqws $1 $DNUM_NFQWS_MY1 "$opt" do_nfqws $1 $DNUM_NFQWS_MY1 "$opt"
} }
@ -21,54 +31,114 @@ zapret_custom_firewall()
{ {
# $1 - 1 - run, 0 - stop # $1 - 1 - run, 0 - stop
local f local f4 f6 subnet
local first_packets_only="$ipt_connbytes 1:3" local NFQWS_MY1_PORTS_TCP=$(replace_char - : $NFQWS_MY1_PORTS_TCP)
local NFQWS_MY1_PORTS_IPT=$(replace_char - : $NFQWS_MY1_PORTS) local NFQWS_MY1_PORTS_UDP=$(replace_char - : $NFQWS_MY1_PORTS_UDP)
local dest_set="-m set --match-set $NFQWS_MY1_SET_NAME dst"
local subnet
local DISABLE_IPV6=1 [ "$1" = 1 -a "$DISABLE_IPV4" != 1 ] && {
ipset create $NFQWS_MY1_NAME4 $NFQWS_MY1_IPSET_OPT family inet 2>/dev/null
[ "$1" = 1 ] && { ipset flush $NFQWS_MY1_NAME4
ipset create $NFQWS_MY1_SET_NAME hash:net hashsize 8192 maxelem 4096 2>/dev/null for subnet in $NFQWS_MY1_SUBNETS4; do
ipset flush $NFQWS_MY1_SET_NAME echo add $NFQWS_MY1_NAME4 $subnet
for subnet in $NFQWS_MY1_SUBNETS; do done | ipset -! restore
echo add $NFQWS_MY1_SET_NAME $subnet }
[ "$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 done | ipset -! restore
} }
f="-p udp -m multiport --dports $NFQWS_MY1_PORTS_IPT" [ -n "$NFQWS_MY1_PORTS_TCP" ] && {
fw_nfqws_post $1 "$f $first_packets_only $dest_set" "" $QNUM_NFQWS_MY1 [ -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 ] || { [ "$1" = 1 ] || {
ipset destroy $NFQWS_MY1_SET_NAME 2>/dev/null ipset destroy $NFQWS_MY1_NAME4 2>/dev/null
ipset destroy $NFQWS_MY1_NAME6 2>/dev/null
} }
} }
zapret_custom_firewall_nft() zapret_custom_firewall_nft()
{ {
# stop logic is not required local f4 f6 subnets
local first_packets_only="$nft_connbytes 1-$NFQWS_MY1_PKT_OUT"
local f [ "$DISABLE_IPV4" != 1 ] && {
local first_packets_only="$nft_connbytes 1-3" make_comma_list subnets $NFQWS_MY1_SUBNETS4
local dest_set="ip daddr @$NFQWS_MY1_SET_NAME" nft_create_set $NFQWS_MY1_NAME4 "type ipv4_addr; size $NFQWS_MY1_IPSET_SIZE; auto-merge; flags interval;"
local subnets nft_flush_set $NFQWS_MY1_NAME4
nft_add_set_element $NFQWS_MY1_NAME4 "$subnets"
local DISABLE_IPV6=1
make_comma_list subnets $NFQWS_MY1_SUBNETS
nft_create_set $NFQWS_MY1_SET_NAME "type ipv4_addr; size 4096; auto-merge; flags interval;"
nft_flush_set $NFQWS_MY1_SET_NAME
nft_add_set_element $NFQWS_MY1_SET_NAME "$subnets"
f="udp dport {$NFQWS_MY1_PORTS}"
nft_fw_nfqws_post "$f $first_packets_only $dest_set" "" $QNUM_NFQWS_MY1
} }
[ "$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() zapret_custom_firewall_nft_flush()
{ {
# this function is called after all nft fw rules are deleted # this function is called after all nft fw rules are deleted
# however sets are not deleted. it's desired to clear sets here. # however sets are not deleted. it's desired to clear sets here.
nft_del_set $NFQWS_MY1_SET_NAME 2>/dev/null nft_del_set $NFQWS_MY1_NAME4 2>/dev/null
nft_del_set $NFQWS_MY1_NAME6 2>/dev/null
} }

View File

@ -28,7 +28,6 @@ zapret_custom_firewall()
local f4 f6 subnet local f4 f6 subnet
local PORTS_IPT=$(replace_char - : $TPWS_MY1_PORTS) 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 ] && { [ "$1" = 1 -a "$DISABLE_IPV4" != 1 ] && {
ipset create $TPWS_MY1_NAME4 $TPWS_MY1_IPSET_OPT family inet 2>/dev/null 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() zapret_custom_firewall_nft()
{ {
local f4 f6 subnet local f4 f6 subnets
[ "$DISABLE_IPV4" != 1 ] && { [ "$DISABLE_IPV4" != 1 ] && {
make_comma_list subnets $TPWS_MY1_SUBNETS4 make_comma_list subnets $TPWS_MY1_SUBNETS4

View File

@ -1,7 +1,7 @@
# Example systemd service unit for nfqws. Adjust for your installation. # Example systemd service unit for nfqws. Adjust for your installation.
# WARNING ! This unit requires to compile nfqws using `make systemd` # 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 # PREPARE
# install build depends # install build depends

View File

@ -1,7 +1,7 @@
# Example systemd service unit for tpws. Adjust for your installation. # Example systemd service unit for tpws. Adjust for your installation.
# WARNING ! This unit requires to compile tpws using `make systemd` # 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 # PREPARE
# install build depends # install build depends

View File

@ -225,6 +225,28 @@ static void exithelp(void)
#define PRINT_VER printf("self-built version %s %s\n\n", __DATE__, __TIME__) #define PRINT_VER printf("self-built version %s %s\n\n", __DATE__, __TIME__)
#endif #endif
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[]) static void parse_params(int argc, char *argv[])
{ {
int option_index = 0; int option_index = 0;
@ -236,33 +258,23 @@ static void parse_params(int argc, char *argv[])
params.pctdiv = DEFAULT_PCTDIV; params.pctdiv = DEFAULT_PCTDIV;
params.v6_threshold = DEFAULT_V6_THRESHOLD; 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) while ((v = getopt_long_only(argc, argv, "", long_options, &option_index)) != -1)
{ {
if (v) exithelp(); if (v) exithelp();
switch (option_index) switch (option_index)
{ {
case 0: case IDX_HELP:
case 1: case IDX_H:
PRINT_VER; PRINT_VER;
exithelp(); exithelp();
break; break;
case 2: case IDX_4:
params.ipv6 = false; params.ipv6 = false;
break; break;
case 3: case IDX_6:
params.ipv6 = true; params.ipv6 = true;
break; break;
case 4: case IDX_PREFIX_LENGTH:
i = sscanf(optarg,"%u-%u",&plen1,&plen2); i = sscanf(optarg,"%u-%u",&plen1,&plen2);
if (i == 1) plen2 = plen1; if (i == 1) plen2 = plen1;
if (i<=0 || plen2<plen1 || !plen1 || !plen2) if (i<=0 || plen2<plen1 || !plen1 || !plen2)
@ -271,7 +283,7 @@ static void parse_params(int argc, char *argv[])
exit(1); exit(1);
} }
break; break;
case 5: case IDX_V4_THRESHOLD:
i = sscanf(optarg, "%u/%u", &params.pctmult, &params.pctdiv); i = sscanf(optarg, "%u/%u", &params.pctmult, &params.pctdiv);
if (i!=2 || params.pctdiv<2 || params.pctmult<1 || params.pctmult>=params.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); exit(1);
} }
break; break;
case 6: case IDX_V6_THRESHOLD:
i = sscanf(optarg, "%u", &params.v6_threshold); i = sscanf(optarg, "%u", &params.v6_threshold);
if (i != 1 || params.v6_threshold<1) if (i != 1 || params.v6_threshold<1)
{ {

View File

@ -467,25 +467,38 @@ static void exithelp(void)
#define PRINT_VER printf("self-built version %s %s\n\n", __DATE__, __TIME__) #define PRINT_VER printf("self-built version %s %s\n\n", __DATE__, __TIME__)
#endif #endif
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 main(int argc, char **argv)
{ {
int r, v, option_index = 0; int r, v, option_index = 0;
char fn1[256],fn2[256]; char fn1[256],fn2[256];
char dom[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)); memset(&glob, 0, sizeof(glob));
*fn1 = *fn2 = *dom = 0; *fn1 = *fn2 = *dom = 0;
glob.family = FAMILY4; glob.family = FAMILY4;
@ -495,11 +508,11 @@ int main(int argc, char **argv)
if (v) exithelp(); if (v) exithelp();
switch (option_index) switch (option_index)
{ {
case 0: /* help */ case IDX_HELP:
PRINT_VER; PRINT_VER;
exithelp(); exithelp();
break; break;
case 1: /* threads */ case IDX_THREADS:
glob.threads = optarg ? atoi(optarg) : 0; glob.threads = optarg ? atoi(optarg) : 0;
if (glob.threads <= 0 || glob.threads > 100) if (glob.threads <= 0 || glob.threads > 100)
{ {
@ -507,7 +520,7 @@ int main(int argc, char **argv)
return 1; return 1;
} }
break; break;
case 2: /* family */ case IDX_FAMILY:
if (!strcmp(optarg, "4")) if (!strcmp(optarg, "4"))
glob.family = FAMILY4; glob.family = FAMILY4;
else if (!strcmp(optarg, "6")) else if (!strcmp(optarg, "6"))
@ -520,25 +533,25 @@ int main(int argc, char **argv)
return 1; return 1;
} }
break; break;
case 3: /* verbose */ case IDX_VERBOSE:
glob.verbose = '\1'; glob.verbose = '\1';
break; break;
case 4: /* stats */ case IDX_STATS:
glob.stats_every = optarg ? atoi(optarg) : 0; glob.stats_every = optarg ? atoi(optarg) : 0;
break; break;
case 5: /* log-resolved */ case IDX_LOG_RESOLVED:
strncpy(fn1,optarg,sizeof(fn1)); strncpy(fn1,optarg,sizeof(fn1));
fn1[sizeof(fn1)-1] = 0; fn1[sizeof(fn1)-1] = 0;
break; break;
case 6: /* log-failed */ case IDX_LOG_FAILED:
strncpy(fn2,optarg,sizeof(fn2)); strncpy(fn2,optarg,sizeof(fn2));
fn2[sizeof(fn2)-1] = 0; fn2[sizeof(fn2)-1] = 0;
break; break;
case 7: /* dns-make-query */ case IDX_DNS_MAKE_QUERY:
strncpy(dom,optarg,sizeof(dom)); strncpy(dom,optarg,sizeof(dom));
dom[sizeof(dom)-1] = 0; dom[sizeof(dom)-1] = 0;
break; break;
case 8: /* dns-parse-query */ case IDX_DNS_PARSE_QUERY:
return dns_parse_query(); return dns_parse_query();
} }
} }

View File

@ -143,8 +143,11 @@ static void ConntrackFeedPacket(t_ctrack *t, bool bReverse, const struct tcphdr
} }
else if (tcp_synack_segment(tcphdr)) else if (tcp_synack_segment(tcphdr))
{ {
if (t->state!=SYN) ConntrackReInitTrack(t); // erase current entry // ignore SA dups
if (!t->seq0) t->seq0 = ntohl(tcphdr->th_ack)-1; 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); t->ack0 = ntohl(tcphdr->th_seq);
} }
else if (tcphdr->th_flags & (TH_FIN|TH_RST)) 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", printf("rseq=%u pos_orig=%u rack=%u pos_reply=%u",
t->track.seq_last, t->track.pos_orig, t->track.seq_last, t->track.pos_orig,
t->track.ack_last, t->track.pos_reply); 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", 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.hostname, l7proto_str(t->track.l7proto)); 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));
}; };
} }

View File

@ -77,14 +77,16 @@ typedef struct
bool req_seq_present,req_seq_finalized,req_seq_abandoned; 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) 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_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; t_l7proto l7proto;
bool l7proto_discovered; bool l7proto_discovered;
char *hostname; char *hostname;
bool hostname_discovered;
bool hostname_ah_check; // should perform autohostlist checks bool hostname_ah_check; // should perform autohostlist checks
t_reassemble reasm_orig; t_reassemble reasm_orig;

View File

@ -38,6 +38,11 @@ uint32_t net16_add(uint16_t netorder_value, uint16_t cpuorder_increment)
return htons(ntohs(netorder_value)+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 *tcp_find_option(struct tcphdr *tcp, uint8_t kind)
{ {
uint8_t *t = (uint8_t*)(tcp+1); 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); opt = tcp_find_option((struct tcphdr*)tcp, 254);
return opt && opt[1]>=4 && opt[2]==0xF9 && opt[3]==0x89; 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 // n prefix (nsport, nwsize) means network byte order
static void fill_tcphdr( static void fill_tcphdr(
struct tcphdr *tcp, uint32_t fooling, uint8_t tcp_flags, struct tcphdr *tcp, uint32_t fooling, uint8_t tcp_flags,
bool sack,
uint16_t nmss,
uint32_t nseq, uint32_t nack_seq, uint32_t nseq, uint32_t nack_seq,
uint16_t nsport, uint16_t ndport, uint16_t nsport, uint16_t ndport,
uint16_t nwsize, uint8_t scale_factor, uint16_t nwsize, uint8_t scale_factor,
@ -116,15 +133,27 @@ static void fill_tcphdr(
tcp_flags &= ~TH_ACK; tcp_flags &= ~TH_ACK;
*((uint8_t*)tcp+13)= tcp_flags; *((uint8_t*)tcp+13)= tcp_flags;
tcp->th_win = nwsize; 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) if (fooling & FOOL_MD5SIG)
{ {
tcpopt[0] = 19; // kind tcpopt[t] = 19; // kind
tcpopt[1] = 18; // len tcpopt[t+1] = 18; // len
*(uint32_t*)(tcpopt+2)=random(); *(uint32_t*)(tcpopt+t+2)=random();
*(uint32_t*)(tcpopt+6)=random(); *(uint32_t*)(tcpopt+t+6)=random();
*(uint32_t*)(tcpopt+10)=random(); *(uint32_t*)(tcpopt+t+10)=random();
*(uint32_t*)(tcpopt+14)=random(); *(uint32_t*)(tcpopt+t+14)=random();
t=18; t+=18;
} }
if (timestamps || (fooling & FOOL_TS)) if (timestamps || (fooling & FOOL_TS))
{ {
@ -145,10 +174,12 @@ static void fill_tcphdr(
tcp->th_off += t>>2; tcp->th_off += t>>2;
tcp->th_sum = 0; 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; 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 ((fooling & FOOL_TS) || timestamps) t+=10;
if (scale_factor!=SCALE_NONE) t+=3; if (scale_factor!=SCALE_NONE) t+=3;
return (t+3)&~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; 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_tos = tos;
ip->ip_sum = 0; ip->ip_sum = 0;
ip->ip_off = 0; ip->ip_off = DF ? htons(IP_DF) : 0;
ip->ip_v = 4; ip->ip_v = 4;
ip->ip_hl = 5; ip->ip_hl = 5;
ip->ip_len = htons(pktlen); 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( bool prepare_tcp_segment4(
const struct sockaddr_in *src, const struct sockaddr_in *dst, const struct sockaddr_in *src, const struct sockaddr_in *dst,
uint8_t tcp_flags, uint8_t tcp_flags,
bool sack,
uint16_t nmss,
uint32_t nseq, uint32_t nack_seq, uint32_t nseq, uint32_t nack_seq,
uint16_t nwsize, uint16_t nwsize,
uint8_t scale_factor, uint8_t scale_factor,
uint32_t *timestamps, uint32_t *timestamps,
bool DF,
uint8_t ttl, uint8_t ttl,
uint8_t tos, uint8_t tos,
uint16_t ip_id, uint16_t ip_id,
@ -203,7 +237,7 @@ bool prepare_tcp_segment4(
const void *data, uint16_t len, const void *data, uint16_t len,
uint8_t *buf, size_t *buflen) 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 ip_payload_len = sizeof(struct tcphdr) + tcpoptlen + len;
uint16_t pktlen = sizeof(struct ip) + ip_payload_len; uint16_t pktlen = sizeof(struct ip) + ip_payload_len;
if (pktlen>*buflen) return false; if (pktlen>*buflen) return false;
@ -212,12 +246,12 @@ bool prepare_tcp_segment4(
struct tcphdr *tcp = (struct tcphdr*)(ip+1); struct tcphdr *tcp = (struct tcphdr*)(ip+1);
uint8_t *payload = (uint8_t*)(tcp+1)+tcpoptlen; uint8_t *payload = (uint8_t*)(tcp+1)+tcpoptlen;
fill_iphdr(ip, &src->sin_addr, &dst->sin_addr, pktlen, IPPROTO_TCP, ttl, tos, ip_id); fill_iphdr(ip, &src->sin_addr, &dst->sin_addr, pktlen, IPPROTO_TCP, DF, ttl, tos, ip_id);
fill_tcphdr(tcp,fooling,tcp_flags,nseq,nack_seq,src->sin_port,dst->sin_port,nwsize,scale_factor,timestamps,badseq_increment,badseq_ack_increment,len); fill_tcphdr(tcp,fooling,tcp_flags,sack,nmss,nseq,nack_seq,src->sin_port,dst->sin_port,nwsize,scale_factor,timestamps,badseq_increment,badseq_ack_increment,len);
memcpy(payload,data,len); memcpy(payload,data,len);
tcp4_fix_checksum(tcp,ip_payload_len,&ip->ip_src,&ip->ip_dst); tcp4_fix_checksum(tcp,ip_payload_len,&ip->ip_src,&ip->ip_dst);
if (fooling & FOOL_BADSUM) tcp->th_sum^=htons(0xBEAF); if (fooling & FOOL_BADSUM) tcp->th_sum^=(uint16_t)(1+random()%0xFFFF);
*buflen = pktlen; *buflen = pktlen;
return true; return true;
@ -226,6 +260,8 @@ bool prepare_tcp_segment4(
bool prepare_tcp_segment6( bool prepare_tcp_segment6(
const struct sockaddr_in6 *src, const struct sockaddr_in6 *dst, const struct sockaddr_in6 *src, const struct sockaddr_in6 *dst,
uint8_t tcp_flags, uint8_t tcp_flags,
bool sack,
uint16_t nmss,
uint32_t nseq, uint32_t nack_seq, uint32_t nseq, uint32_t nack_seq,
uint16_t nwsize, uint16_t nwsize,
uint8_t scale_factor, uint8_t scale_factor,
@ -238,7 +274,7 @@ bool prepare_tcp_segment6(
const void *data, uint16_t len, const void *data, uint16_t len,
uint8_t *buf, size_t *buflen) 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 transport_payload_len = sizeof(struct tcphdr) + tcpoptlen + len;
uint16_t ip_payload_len = transport_payload_len + uint16_t ip_payload_len = transport_payload_len +
8*!!((fooling & (FOOL_HOPBYHOP|FOOL_HOPBYHOP2))==FOOL_HOPBYHOP) + 8*!!((fooling & (FOOL_HOPBYHOP|FOOL_HOPBYHOP2))==FOOL_HOPBYHOP) +
@ -297,11 +333,11 @@ bool prepare_tcp_segment6(
uint8_t *payload = (uint8_t*)(tcp+1)+tcpoptlen; uint8_t *payload = (uint8_t*)(tcp+1)+tcpoptlen;
fill_ip6hdr(ip6, &src->sin6_addr, &dst->sin6_addr, ip_payload_len, proto, ttl, flow_label); fill_ip6hdr(ip6, &src->sin6_addr, &dst->sin6_addr, ip_payload_len, proto, ttl, flow_label);
fill_tcphdr(tcp,fooling,tcp_flags,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); memcpy(payload,data,len);
tcp6_fix_checksum(tcp,transport_payload_len,&ip6->ip6_src,&ip6->ip6_dst); tcp6_fix_checksum(tcp,transport_payload_len,&ip6->ip6_src,&ip6->ip6_dst);
if (fooling & FOOL_BADSUM) tcp->th_sum^=htons(0xBEAF); if (fooling & FOOL_BADSUM) tcp->th_sum^=(1+random()%0xFFFF);
*buflen = pktlen; *buflen = pktlen;
return true; return true;
@ -310,10 +346,13 @@ bool prepare_tcp_segment6(
bool prepare_tcp_segment( bool prepare_tcp_segment(
const struct sockaddr *src, const struct sockaddr *dst, const struct sockaddr *src, const struct sockaddr *dst,
uint8_t tcp_flags, uint8_t tcp_flags,
bool sack,
uint16_t nmss,
uint32_t nseq, uint32_t nack_seq, uint32_t nseq, uint32_t nack_seq,
uint16_t nwsize, uint16_t nwsize,
uint8_t scale_factor, uint8_t scale_factor,
uint32_t *timestamps, uint32_t *timestamps,
bool DF,
uint8_t ttl, uint8_t ttl,
uint8_t tos, uint8_t tos,
uint16_t ip_id, uint16_t ip_id,
@ -325,9 +364,9 @@ bool prepare_tcp_segment(
uint8_t *buf, size_t *buflen) uint8_t *buf, size_t *buflen)
{ {
return (src->sa_family==AF_INET && dst->sa_family==AF_INET) ? return (src->sa_family==AF_INET && dst->sa_family==AF_INET) ?
prepare_tcp_segment4((struct sockaddr_in *)src,(struct sockaddr_in *)dst,tcp_flags,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) ? (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; false;
} }
@ -335,6 +374,7 @@ bool prepare_tcp_segment(
// padlen<0 means payload shrinking // padlen<0 means payload shrinking
bool prepare_udp_segment4( bool prepare_udp_segment4(
const struct sockaddr_in *src, const struct sockaddr_in *dst, const struct sockaddr_in *src, const struct sockaddr_in *dst,
bool DF,
uint8_t ttl, uint8_t ttl,
uint8_t tos, uint8_t tos,
uint16_t ip_id, uint16_t ip_id,
@ -361,7 +401,7 @@ bool prepare_udp_segment4(
uint8_t *payload = (uint8_t*)(udp+1); 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); fill_udphdr(udp, src->sin_port, dst->sin_port, datalen);
memcpy(payload,data,len); memcpy(payload,data,len);
@ -370,7 +410,7 @@ bool prepare_udp_segment4(
else else
memset(payload+len,0,padlen); memset(payload+len,0,padlen);
udp4_fix_checksum(udp,ip_payload_len,&ip->ip_src,&ip->ip_dst); 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; *buflen = pktlen;
return true; return true;
@ -459,13 +499,14 @@ bool prepare_udp_segment6(
else else
memset(payload+len,0,padlen); memset(payload+len,0,padlen);
udp6_fix_checksum(udp,transport_payload_len,&ip6->ip6_src,&ip6->ip6_dst); 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; *buflen = pktlen;
return true; return true;
} }
bool prepare_udp_segment( bool prepare_udp_segment(
const struct sockaddr *src, const struct sockaddr *dst, const struct sockaddr *src, const struct sockaddr *dst,
bool DF,
uint8_t ttl, uint8_t ttl,
uint8_t tos, uint8_t tos,
uint16_t ip_id, uint16_t ip_id,
@ -477,7 +518,7 @@ bool prepare_udp_segment(
uint8_t *buf, size_t *buflen) uint8_t *buf, size_t *buflen)
{ {
return (src->sa_family==AF_INET && dst->sa_family==AF_INET) ? return (src->sa_family==AF_INET && dst->sa_family==AF_INET) ?
prepare_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) ? (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) : prepare_udp_segment6((struct sockaddr_in6 *)src,(struct sockaddr_in6 *)dst,ttl,flow_label,fooling,padding,padding_size,padlen,data,len,buf,buflen) :
false; false;
@ -601,10 +642,29 @@ bool ip_frag(
return false; 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 (ttl)
if (ip6) ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim = 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 uint8_t hop_count_guess(uint8_t ttl)
// ttl = TTL of incoming packet
uint8_t autottl_guess(uint8_t ttl, const autottl *attl)
{ {
uint8_t orig, path, fake;
// 18.65.168.125 ( cloudfront ) 255 // 18.65.168.125 ( cloudfront ) 255
// 157.254.246.178 128 // 157.254.246.178 128
// 1.1.1.1 64 // 1.1.1.1 64
// guess original ttl. consider path lengths less than 32 hops // guess original ttl. consider path lengths less than 32 hops
uint8_t orig;
if (ttl>223) if (ttl>223)
orig=255; orig=255;
else if (ttl<128 && ttl>96) else if (ttl<128 && ttl>96)
@ -1791,13 +1850,21 @@ uint8_t autottl_guess(uint8_t ttl, const autottl *attl)
else else
return 0; 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; d = (int)hop_count + attl->delta;
if (fake<attl->min) fake=attl->min; if (d<attl->min) fake=attl->min;
else if (fake>attl->max) fake=attl->max; 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; return fake;
} }
@ -1849,15 +1916,15 @@ void verdict_tcp_csum_fix(uint8_t verdict, struct tcphdr *tcphdr, size_t transpo
{ {
if (!(verdict & VERDICT_NOCSUM)) if (!(verdict & VERDICT_NOCSUM))
{ {
#ifdef __CYGWIN__
// always fix csum for windivert. original can be partial or bad // always fix csum for windivert. original can be partial or bad
#ifndef __CYGWIN__ if ((verdict & VERDICT_MASK)!=VERDICT_DROP)
#ifdef __FreeBSD__ #elif defined(__FreeBSD__)
// FreeBSD tend to pass ipv6 frames with wrong checksum // FreeBSD tend to pass ipv6 frames with wrong checksum
if ((verdict & VERDICT_MASK)==VERDICT_MODIFY || ip6hdr) if ((verdict & VERDICT_MASK)==VERDICT_MODIFY || ip6hdr)
#else #else
// if original packet was tampered earlier it needs checksum fixed // if original packet was tampered earlier it needs checksum fixed
if ((verdict & VERDICT_MASK)==VERDICT_MODIFY) if ((verdict & VERDICT_MASK)==VERDICT_MODIFY)
#endif
#endif #endif
tcp_fix_checksum(tcphdr,transport_len,ip,ip6hdr); 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)) if (!(verdict & VERDICT_NOCSUM))
{ {
#ifdef __CYGWIN__
// always fix csum for windivert. original can be partial or bad // always fix csum for windivert. original can be partial or bad
#ifndef __CYGWIN__ if ((verdict & VERDICT_MASK)!=VERDICT_DROP)
#ifdef __FreeBSD__ #elif defined(__FreeBSD__)
// FreeBSD tend to pass ipv6 frames with wrong checksum // FreeBSD tend to pass ipv6 frames with wrong checksum
if ((verdict & VERDICT_MASK)==VERDICT_MODIFY || ip6hdr) if ((verdict & VERDICT_MASK)==VERDICT_MODIFY || ip6hdr)
#else #else
// if original packet was tampered earlier it needs checksum fixed // if original packet was tampered earlier it needs checksum fixed
if ((verdict & VERDICT_MASK)==VERDICT_MODIFY) if ((verdict & VERDICT_MASK)==VERDICT_MODIFY)
#endif
#endif #endif
udp_fix_checksum(udphdr,transport_len,ip,ip6hdr); udp_fix_checksum(udphdr,transport_len,ip,ip6hdr);
} }

View File

@ -59,6 +59,7 @@ uint32_t net16_add(uint16_t netorder_value, uint16_t cpuorder_increment);
#define VERDICT_DROP 2 #define VERDICT_DROP 2
#define VERDICT_MASK 3 #define VERDICT_MASK 3
#define VERDICT_NOCSUM 4 #define VERDICT_NOCSUM 4
#define VERDICT_GARBAGE 8
#define IP4_TOS(ip_header) (ip_header ? ip_header->ip_tos : 0) #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) #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( bool prepare_tcp_segment4(
const struct sockaddr_in *src, const struct sockaddr_in *dst, const struct sockaddr_in *src, const struct sockaddr_in *dst,
uint8_t tcp_flags, uint8_t tcp_flags,
bool sack,
uint16_t nmss,
uint32_t nseq, uint32_t nack_seq, uint32_t nseq, uint32_t nack_seq,
uint16_t nwsize, uint16_t nwsize,
uint8_t scale_factor, uint8_t scale_factor,
uint32_t *timestamps, uint32_t *timestamps,
bool DF,
uint8_t ttl, uint8_t ttl,
uint8_t tos, uint8_t tos,
uint16_t ip_id, uint16_t ip_id,
@ -83,6 +87,8 @@ bool prepare_tcp_segment4(
bool prepare_tcp_segment6( bool prepare_tcp_segment6(
const struct sockaddr_in6 *src, const struct sockaddr_in6 *dst, const struct sockaddr_in6 *src, const struct sockaddr_in6 *dst,
uint8_t tcp_flags, uint8_t tcp_flags,
bool sack,
uint16_t nmss,
uint32_t nseq, uint32_t nack_seq, uint32_t nseq, uint32_t nack_seq,
uint16_t nwsize, uint16_t nwsize,
uint8_t scale_factor, uint8_t scale_factor,
@ -97,10 +103,13 @@ bool prepare_tcp_segment6(
bool prepare_tcp_segment( bool prepare_tcp_segment(
const struct sockaddr *src, const struct sockaddr *dst, const struct sockaddr *src, const struct sockaddr *dst,
uint8_t tcp_flags, uint8_t tcp_flags,
bool sack,
uint16_t nmss,
uint32_t nseq, uint32_t nack_seq, uint32_t nseq, uint32_t nack_seq,
uint16_t nwsize, uint16_t nwsize,
uint8_t scale_factor, uint8_t scale_factor,
uint32_t *timestamps, uint32_t *timestamps,
bool DF,
uint8_t ttl, uint8_t ttl,
uint8_t tos, uint8_t tos,
uint16_t ip_id, uint16_t ip_id,
@ -114,6 +123,7 @@ bool prepare_tcp_segment(
bool prepare_udp_segment4( bool prepare_udp_segment4(
const struct sockaddr_in *src, const struct sockaddr_in *dst, const struct sockaddr_in *src, const struct sockaddr_in *dst,
bool DF,
uint8_t ttl, uint8_t ttl,
uint8_t tos, uint8_t tos,
uint16_t ip_id, uint16_t ip_id,
@ -133,6 +143,7 @@ bool prepare_udp_segment6(
uint8_t *buf, size_t *buflen); uint8_t *buf, size_t *buflen);
bool prepare_udp_segment( bool prepare_udp_segment(
const struct sockaddr *src, const struct sockaddr *dst, const struct sockaddr *src, const struct sockaddr *dst,
bool DF,
uint8_t ttl, uint8_t ttl,
uint8_t tos, uint8_t tos,
uint16_t ip_id, uint16_t ip_id,
@ -162,15 +173,20 @@ bool ip_frag(
uint8_t *pkt1, size_t *pkt1_size, uint8_t *pkt1, size_t *pkt1_size,
uint8_t *pkt2, size_t *pkt2_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_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); 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); uint8_t *tcp_find_option(struct tcphdr *tcp, uint8_t kind);
uint32_t *tcp_find_timestamps(struct tcphdr *tcp); uint32_t *tcp_find_timestamps(struct tcphdr *tcp);
uint8_t tcp_find_scale_factor(const 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 tcp_has_fastopen(const struct tcphdr *tcp);
bool ip_has_df(const struct ip *ip);
#ifdef __CYGWIN__ #ifdef __CYGWIN__
extern uint32_t w_win32_error; 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 typedef struct
{ {
uint8_t delta, min, max; int8_t delta;
uint8_t min, max;
} autottl; } autottl;
#define AUTOTTL_DEFAULT_DELTA 1
#define AUTOTTL_DEFAULT_MIN 3
#define AUTOTTL_DEFAULT_MAX 20
#define AUTOTTL_ENABLED(a) (!!(a).delta) #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 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); void verdict_tcp_csum_fix(uint8_t verdict, struct tcphdr *tcphdr, size_t transport_len, struct ip *ip, struct ip6_hdr *ip6hdr);

File diff suppressed because it is too large Load Diff

View File

@ -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_tcp(enum dpi_desync_mode mode);
bool desync_valid_second_stage_udp(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);

View File

@ -9,6 +9,8 @@
#include <stdio.h> #include <stdio.h>
#include <time.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. // this saves memory. sockaddr_storage is larger than required. it can be 128 bytes. sockaddr_in6 is 28 bytes.
typedef union typedef union
{ {

View File

@ -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) struct hostlist_file *RegisterHostlist(struct desync_profile *dp, bool bExclude, const char *filename)
{ {
/*
if (filename && !file_mod_time(filename)) if (filename && !file_mod_time(filename))
{ {
DLOG_ERR("cannot access hostlist file '%s'\n",filename); DLOG_ERR("cannot access hostlist file '%s'\n",filename);
return NULL; return NULL;
} }
*/
return RegisterHostlist_( return RegisterHostlist_(
&params.hostlists, &params.hostlists,
bExclude ? &dp->hl_collection_exclude : &dp->hl_collection, bExclude ? &dp->hl_collection_exclude : &dp->hl_collection,

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdio.h>
#include "packet_queue.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); 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)); struct rawpacket *rp = malloc(sizeof(struct rawpacket));
if (!rp) return NULL; if (!rp) return NULL;
@ -39,13 +40,14 @@ struct rawpacket *rawpacket_queue(struct rawpacket_tailhead *q,const struct sock
rp->dst = *dst; rp->dst = *dst;
rp->fwmark = fwmark; rp->fwmark = fwmark;
if (ifout) if (ifin)
{ snprintf(rp->ifin,sizeof(rp->ifin),"%s",ifin);
strncpy(rp->ifout,ifout,sizeof(rp->ifout));
rp->ifout[sizeof(rp->ifout)-1]=0;
}
else 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); memcpy(rp->packet,data,len);
rp->len=len; rp->len=len;
rp->len_payload=len_payload; rp->len_payload=len_payload;

View File

@ -9,7 +9,7 @@
struct rawpacket struct rawpacket
{ {
struct sockaddr_storage dst; struct sockaddr_storage dst;
char ifout[IFNAMSIZ+1]; char ifin[IFNAMSIZ], ifout[IFNAMSIZ];
uint32_t fwmark; uint32_t fwmark;
size_t len, len_payload; size_t len, len_payload;
uint8_t *packet; uint8_t *packet;
@ -21,6 +21,6 @@ void rawpacket_queue_init(struct rawpacket_tailhead *q);
void rawpacket_queue_destroy(struct rawpacket_tailhead *q); void rawpacket_queue_destroy(struct rawpacket_tailhead *q);
bool rawpacket_queue_empty(const struct rawpacket_tailhead *q); bool rawpacket_queue_empty(const struct rawpacket_tailhead *q);
unsigned int rawpacket_queue_count(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); struct rawpacket *rawpacket_dequeue(struct rawpacket_tailhead *q);
void rawpacket_free(struct rawpacket *rp); void rawpacket_free(struct rawpacket *rp);

View File

@ -187,10 +187,10 @@ void dp_init(struct desync_profile *dp)
dp->desync_repeats = 1; dp->desync_repeats = 1;
dp->fake_syndata_size = 16; dp->fake_syndata_size = 16;
dp->wscale=-1; // default - dont change scale factor (client) dp->wscale=-1; // default - dont change scale factor (client)
dp->desync_ttl6 = 0xFF; // unused dp->desync_ttl6 = dp->dup_ttl6 = dp->orig_mod_ttl6 = 0xFF; // unused
dp->desync_badseq_increment = BADSEQ_INCREMENT_DEFAULT; dp->desync_badseq_increment = dp->dup_badseq_increment = BADSEQ_INCREMENT_DEFAULT;
dp->desync_badseq_ack_increment = BADSEQ_ACK_INCREMENT_DEFAULT; dp->desync_badseq_ack_increment = dp->dup_badseq_ack_increment = BADSEQ_ACK_INCREMENT_DEFAULT;
dp->wssize_cutoff_mode = dp->desync_start_mode = dp->desync_cutoff_mode = 'n'; // packet number by default dp->wssize_cutoff_mode = dp->desync_start_mode = dp->desync_cutoff_mode = dp->dup_start_mode = dp->dup_cutoff_mode = dp->orig_mod_start_mode = dp->orig_mod_cutoff_mode = 'n'; // packet number by default
dp->udplen_increment = UDPLEN_INCREMENT_DEFAULT; dp->udplen_increment = UDPLEN_INCREMENT_DEFAULT;
dp->hostlist_auto_fail_threshold = HOSTLIST_AUTO_FAIL_THRESHOLD_DEFAULT; dp->hostlist_auto_fail_threshold = HOSTLIST_AUTO_FAIL_THRESHOLD_DEFAULT;
dp->hostlist_auto_fail_time = HOSTLIST_AUTO_FAIL_TIME_DEFAULT; dp->hostlist_auto_fail_time = HOSTLIST_AUTO_FAIL_TIME_DEFAULT;
@ -294,3 +294,12 @@ bool dp_list_have_autohostlist(struct desync_profile_list_head *head)
return true; return true;
return false; 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;
}

View File

@ -36,6 +36,19 @@
#define HOSTLIST_AUTO_FAIL_TIME_DEFAULT 60 #define HOSTLIST_AUTO_FAIL_TIME_DEFAULT 60
#define HOSTLIST_AUTO_RETRANS_THRESHOLD_DEFAULT 3 #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 MAX_SPLITS 64
#define FAKE_TLS_MOD_SAVE_MASK 0x0F #define FAKE_TLS_MOD_SAVE_MASK 0x0F
@ -82,6 +95,20 @@ struct desync_profile
int split_count; int split_count;
struct proto_pos seqovl; 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 char desync_start_mode, desync_cutoff_mode; // n - packets, d - data packets, s - relative sequence
unsigned int desync_start, desync_cutoff; unsigned int desync_start, desync_cutoff;
uint8_t desync_ttl, desync_ttl6; uint8_t desync_ttl, desync_ttl6;
@ -114,9 +141,10 @@ struct desync_profile
hostfail_pool *hostlist_auto_fail_counters; 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_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_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_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_list {
struct desync_profile dp; struct desync_profile dp;
@ -127,6 +155,7 @@ struct desync_profile_list *dp_list_add(struct desync_profile_list_head *head);
void dp_entry_destroy(struct desync_profile_list *entry); void dp_entry_destroy(struct desync_profile_list *entry);
void dp_list_destroy(struct desync_profile_list_head *head); void dp_list_destroy(struct desync_profile_list_head *head);
bool dp_list_have_autohostlist(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); void dp_init(struct desync_profile *dp);
bool dp_fake_defaults(struct desync_profile *dp); bool dp_fake_defaults(struct desync_profile *dp);
void dp_clear(struct desync_profile *dp); void dp_clear(struct desync_profile *dp);
@ -168,6 +197,10 @@ struct params_s
unsigned int ctrack_t_syn, ctrack_t_est, ctrack_t_fin, ctrack_t_udp; unsigned int ctrack_t_syn, ctrack_t_est, ctrack_t_fin, ctrack_t_udp;
t_conntrack conntrack; t_conntrack conntrack;
unsigned int ipcache_lifetime;
bool autottl_present,cache_hostname;
ip_cache ipcache;
}; };
extern struct params_s params; extern struct params_s params;

View File

@ -3,6 +3,7 @@
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <arpa/inet.h>
#define DESTROY_STR_POOL(etype, ppool) \ #define DESTROY_STR_POOL(etype, ppool) \
etype *elem, *tmp; \ etype *elem, *tmp; \
@ -579,3 +580,219 @@ bool blob_collection_empty(const struct blob_collection_head *head)
{ {
return !LIST_FIRST(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;
}
}

View File

@ -3,6 +3,7 @@
#include <stdbool.h> #include <stdbool.h>
#include <ctype.h> #include <ctype.h>
#include <sys/queue.h> #include <sys/queue.h>
#include <net/if.h>
#include <time.h> #include <time.h>
#include "helpers.h" #include "helpers.h"
@ -161,3 +162,43 @@ 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); 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); void blob_collection_destroy(struct blob_collection_head *head);
bool blob_collection_empty(const 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);

View File

@ -345,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) uint16_t TLSRecordDataLen(const uint8_t *data)
{ {
@ -1015,7 +1028,8 @@ bool IsDiscordIpDiscoveryRequest(const uint8_t *data, size_t len)
return len==74 && return len==74 &&
data[0]==0 && data[1]==1 && data[0]==0 && data[1]==1 &&
data[2]==0 && data[3]==70 && data[2]==0 && data[3]==70 &&
data[8]==0 && memcmp(&data[8],&data[9],63)==0; // address is not set in requests !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) bool IsStunMessage(const uint8_t *data, size_t len)
{ {

View File

@ -57,6 +57,7 @@ int HttpReplyCode(const uint8_t *data, size_t len);
// must be pre-checked by IsHttpReply // must be pre-checked by IsHttpReply
bool HttpReplyLooksLikeDPIRedirect(const uint8_t *data, size_t len, const char *host); 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); uint16_t TLSRecordDataLen(const uint8_t *data);
size_t TLSRecordLen(const uint8_t *data); size_t TLSRecordLen(const uint8_t *data);
bool IsTLSRecordFull(const uint8_t *data, size_t len); bool IsTLSRecordFull(const uint8_t *data, size_t len);

View File

@ -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) struct hostlist_file *RegisterHostlist(struct desync_profile *dp, bool bExclude, const char *filename)
{ {
/*
if (filename && !file_mod_time(filename)) if (filename && !file_mod_time(filename))
{ {
DLOG_ERR("cannot access hostlist file '%s'\n",filename); DLOG_ERR("cannot access hostlist file '%s'\n",filename);
return NULL; return NULL;
} }
*/
return RegisterHostlist_( return RegisterHostlist_(
&params.hostlists, &params.hostlists,
bExclude ? &dp->hl_collection_exclude : &dp->hl_collection, bExclude ? &dp->hl_collection_exclude : &dp->hl_collection,

View File

@ -20,6 +20,8 @@
#define FIX_SEG_DEFAULT_MAX_WAIT 50 #define FIX_SEG_DEFAULT_MAX_WAIT 50
#define IPCACHE_LIFETIME 7200
enum bindll { unwanted=0, no, prefer, force }; enum bindll { unwanted=0, no, prefer, force };
#define MAX_BINDS 32 #define MAX_BINDS 32
@ -140,6 +142,10 @@ struct params_s
bool tamper; // any tamper option is set bool tamper; // any tamper option is set
bool tamper_lim; // tamper-start or tamper-cutoff set in any profile bool tamper_lim; // tamper-start or tamper-cutoff set in any profile
struct desync_profile_list_head desync_profiles; struct desync_profile_list_head desync_profiles;
unsigned int ipcache_lifetime;
bool cache_hostname;
ip_cache ipcache;
}; };
extern struct params_s params; extern struct params_s params;

View File

@ -3,6 +3,7 @@
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <arpa/inet.h>
#define DESTROY_STR_POOL(etype, ppool) \ #define DESTROY_STR_POOL(etype, ppool) \
etype *elem, *tmp; \ etype *elem, *tmp; \
@ -517,3 +518,277 @@ bool port_filters_deny_if_empty(struct port_filters_head *head)
if (LIST_FIRST(head)) return true; if (LIST_FIRST(head)) return true;
return pf_parse("0",&pf) && port_filter_add(head,&pf); 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;
}
}

View File

@ -3,6 +3,7 @@
#include <stdbool.h> #include <stdbool.h>
#include <ctype.h> #include <ctype.h>
#include <sys/queue.h> #include <sys/queue.h>
#include <net/if.h>
#include <time.h> #include <time.h>
#include "helpers.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); 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_in_range(const struct port_filters_head *head, uint16_t port);
bool port_filters_deny_if_empty(struct port_filters_head *head); 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);

View File

@ -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) uint16_t TLSRecordDataLen(const uint8_t *data)
{ {
return pntoh16(data + 3); return pntoh16(data + 3);

View File

@ -53,6 +53,7 @@ int HttpReplyCode(const uint8_t *data, size_t len);
// must be pre-checked by IsHttpReply // must be pre-checked by IsHttpReply
bool HttpReplyLooksLikeDPIRedirect(const uint8_t *data, size_t len, const char *host); 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); uint16_t TLSRecordDataLen(const uint8_t *data);
size_t TLSRecordLen(const uint8_t *data); size_t TLSRecordLen(const uint8_t *data);
bool IsTLSRecordFull(const uint8_t *data, size_t len); bool IsTLSRecordFull(const uint8_t *data, size_t len);

View File

@ -7,6 +7,7 @@
#include "ipset.h" #include "ipset.h"
#include "protocol.h" #include "protocol.h"
#include "helpers.h" #include "helpers.h"
#include "pools.h"
#define PKTDATA_MAXDUMP 32 #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"); 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(&params.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(&params.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) static bool dp_match(struct desync_profile *dp, const struct sockaddr *dest, const char *hostname, t_l7proto l7proto)
{ {
bool bHostlistsEmpty; 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"); VPRINT("desync profile not found\n");
return NULL; return NULL;
} }
void apply_desync_profile(t_ctrack *ctrack, const struct sockaddr *dest) void apply_desync_profile(t_ctrack *ctrack, const struct sockaddr *dest)
{ {
ipcachePurgeRateLimited(&params.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(&params.desync_profiles, dest, ctrack->hostname, ctrack->l7proto); ctrack->dp = dp_find(&params.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"); VPRINT("Data block contains TLS ClientHello\n");
l7proto=TLS; l7proto=TLS;
TLSDebug(segment,*size);
bHaveHost=TLSHelloExtractHost((uint8_t*)segment,*size,Host,sizeof(Host),false); bHaveHost=TLSHelloExtractHost((uint8_t*)segment,*size,Host,sizeof(Host),false);
} }
else else
@ -139,7 +267,11 @@ void tamper_out(t_ctrack *ctrack, const struct sockaddr *dest, uint8_t *segment,
} }
if (bHaveHost) if (bHaveHost)
{
VPRINT("request hostname: %s\n", Host); VPRINT("request hostname: %s\n", Host);
if (!ipcache_put_hostname(dest->sa_family==AF_INET ? &((struct sockaddr_in*)dest)->sin_addr : NULL, dest->sa_family==AF_INET6 ? &((struct sockaddr_in6*)dest)->sin6_addr : NULL , Host))
DLOG_ERR("ipcache_put_hostname: out of memory");
}
bool bDiscoveredL7 = ctrack->l7proto==UNKNOWN && l7proto!=UNKNOWN; bool bDiscoveredL7 = ctrack->l7proto==UNKNOWN && l7proto!=UNKNOWN;
if (bDiscoveredL7) if (bDiscoveredL7)
@ -148,15 +280,17 @@ void tamper_out(t_ctrack *ctrack, const struct sockaddr *dest, uint8_t *segment,
ctrack->l7proto=l7proto; ctrack->l7proto=l7proto;
} }
bool bDiscoveredHostname = bHaveHost && !ctrack->hostname; bool bDiscoveredHostname = bHaveHost && !ctrack->hostname_discovered;
if (bDiscoveredHostname) if (bDiscoveredHostname)
{ {
VPRINT("discovered hostname\n"); VPRINT("discovered hostname\n");
free(ctrack->hostname);
if (!(ctrack->hostname=strdup(Host))) if (!(ctrack->hostname=strdup(Host)))
{ {
DLOG_ERR("strdup hostname : out of memory\n"); DLOG_ERR("strdup hostname : out of memory\n");
return; return;
} }
ctrack->hostname_discovered = true;
} }
if (bDiscoveredL7 || bDiscoveredHostname) if (bDiscoveredL7 || bDiscoveredHostname)

View File

@ -15,6 +15,7 @@ typedef struct
t_l7proto l7proto; t_l7proto l7proto;
bool bTamperInCutoff; bool bTamperInCutoff;
bool b_host_checked,b_host_matches,b_ah_check; bool b_host_checked,b_host_matches,b_ah_check;
bool hostname_discovered;
char *hostname; char *hostname;
struct desync_profile *dp; // desync profile cache struct desync_profile *dp; // desync profile cache
} t_ctrack; } t_ctrack;

View File

@ -88,6 +88,12 @@ static void onusr2(int sig)
HostFailPoolDump(dpl->dp.hostlist_auto_fail_counters); HostFailPoolDump(dpl->dp.hostlist_auto_fail_counters);
} }
if (params.cache_hostname)
{
printf("\nIPCACHE\n");
ipcachePrint(&params.ipcache);
}
printf("\n"); printf("\n");
} }
@ -215,6 +221,8 @@ static void exithelp(void)
#if defined(__linux__) #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" " --fix-seg=<int>\t\t\t; fix segmentation failures at the cost of possible slowdown. wait up to N msec (default %u)\n"
#endif #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=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" " --debug-level=0|1|2\t\t\t; specify debug level\n"
" --dry-run\t\t\t\t; verify parameters and exit with code 0 if successful\n" " --dry-run\t\t\t\t; verify parameters and exit with code 0 if successful\n"
@ -272,6 +280,7 @@ static void exithelp(void)
#ifdef __linux__ #ifdef __linux__
FIX_SEG_DEFAULT_MAX_WAIT, FIX_SEG_DEFAULT_MAX_WAIT,
#endif #endif
IPCACHE_LIFETIME,
HOSTLIST_AUTO_FAIL_THRESHOLD_DEFAULT, HOSTLIST_AUTO_FAIL_TIME_DEFAULT HOSTLIST_AUTO_FAIL_THRESHOLD_DEFAULT, HOSTLIST_AUTO_FAIL_TIME_DEFAULT
); );
exit(1); exit(1);
@ -292,6 +301,7 @@ static void cleanup_params(void)
hostlist_files_destroy(&params.hostlists); hostlist_files_destroy(&params.hostlists);
ipset_files_destroy(&params.ipsets); ipset_files_destroy(&params.ipsets);
ipcacheDestroy(&params.ipcache);
} }
static void exithelp_clean(void) static void exithelp_clean(void)
{ {
@ -610,6 +620,192 @@ static bool check_oob_disorder(const struct desync_profile *dp)
} }
#endif #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[]) void parse_params(int argc, char *argv[])
{ {
int option_index = 0; int option_index = 0;
@ -622,6 +818,7 @@ void parse_params(int argc, char *argv[])
params.maxconn = DEFAULT_MAX_CONN; params.maxconn = DEFAULT_MAX_CONN;
params.max_orphan_time = DEFAULT_MAX_ORPHAN_TIME; params.max_orphan_time = DEFAULT_MAX_ORPHAN_TIME;
params.binds_last = -1; params.binds_last = -1;
params.ipcache_lifetime = IPCACHE_LIFETIME;
#if defined(__linux__) || defined(__APPLE__) #if defined(__linux__) || defined(__APPLE__)
params.tcp_user_timeout_local = DEFAULT_TCP_USER_TIMEOUT_LOCAL; params.tcp_user_timeout_local = DEFAULT_TCP_USER_TIMEOUT_LOCAL;
params.tcp_user_timeout_remote = DEFAULT_TCP_USER_TIMEOUT_REMOTE; params.tcp_user_timeout_remote = DEFAULT_TCP_USER_TIMEOUT_REMOTE;
@ -664,96 +861,6 @@ void parse_params(int argc, char *argv[])
} }
#endif #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) while ((v = getopt_long_only(argc, argv, "", long_options, &option_index)) != -1)
{ {
if (v) if (v)
@ -765,11 +872,11 @@ void parse_params(int argc, char *argv[])
} }
switch (option_index) switch (option_index)
{ {
case 0: case IDX_HELP:
case 1: case IDX_H:
exithelp_clean(); exithelp_clean();
break; break;
case 2: /* bind-addr */ case IDX_BIND_ADDR:
nextbind_clean(); nextbind_clean();
{ {
char *p = strchr(optarg,'%'); 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; params.binds[params.binds_last].bindaddr[sizeof(params.binds[params.binds_last].bindaddr) - 1] = 0;
break; break;
case 3: /* bind-iface4 */ case IDX_BIND_IFACE4:
nextbind_clean(); nextbind_clean();
params.binds[params.binds_last].bind_if6=false; params.binds[params.binds_last].bind_if6=false;
strncpy(params.binds[params.binds_last].bindiface, optarg, sizeof(params.binds[params.binds_last].bindiface)); 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; params.binds[params.binds_last].bindiface[sizeof(params.binds[params.binds_last].bindiface) - 1] = 0;
break; break;
case 4: /* bind-iface6 */ case IDX_BIND_IFACE6:
nextbind_clean(); nextbind_clean();
params.binds[params.binds_last].bind_if6=true; params.binds[params.binds_last].bind_if6=true;
strncpy(params.binds[params.binds_last].bindiface, optarg, sizeof(params.binds[params.binds_last].bindiface)); 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; params.binds[params.binds_last].bindiface[sizeof(params.binds[params.binds_last].bindiface) - 1] = 0;
break; break;
case 5: /* bind-linklocal */ case IDX_BIND_LINKLOCAL:
checkbind_clean(); checkbind_clean();
params.binds[params.binds_last].bindll = true; params.binds[params.binds_last].bindll = true;
if (!strcmp(optarg, "no")) if (!strcmp(optarg, "no"))
@ -811,22 +918,22 @@ void parse_params(int argc, char *argv[])
exit_clean(1); exit_clean(1);
} }
break; break;
case 6: /* bind-wait-ifup */ case IDX_BIND_WAIT_IFUP:
checkbind_clean(); checkbind_clean();
params.binds[params.binds_last].bind_wait_ifup = atoi(optarg); params.binds[params.binds_last].bind_wait_ifup = atoi(optarg);
break; break;
case 7: /* bind-wait-ip */ case IDX_BIND_WAIT_IP:
checkbind_clean(); checkbind_clean();
params.binds[params.binds_last].bind_wait_ip = atoi(optarg); params.binds[params.binds_last].bind_wait_ip = atoi(optarg);
break; break;
case 8: /* bind-wait-ip-linklocal */ case IDX_BIND_WAIT_IP_LINKLOCAL:
checkbind_clean(); checkbind_clean();
params.binds[params.binds_last].bind_wait_ip_ll = atoi(optarg); params.binds[params.binds_last].bind_wait_ip_ll = atoi(optarg);
break; break;
case 9: /* bind-wait-only */ case IDX_BIND_WAIT_ONLY:
params.bind_wait_only = true; params.bind_wait_only = true;
break; break;
case 10: /* port */ case IDX_PORT:
i = atoi(optarg); i = atoi(optarg);
if (i <= 0 || i > 65535) if (i <= 0 || i > 65535)
{ {
@ -835,10 +942,10 @@ void parse_params(int argc, char *argv[])
} }
params.port = (uint16_t)i; params.port = (uint16_t)i;
break; break;
case 11: /* daemon */ case IDX_DAEMON:
params.daemon = true; params.daemon = true;
break; break;
case 12: /* user */ case IDX_USER:
{ {
struct passwd *pwd = getpwnam(optarg); struct passwd *pwd = getpwnam(optarg);
if (!pwd) if (!pwd)
@ -851,7 +958,7 @@ void parse_params(int argc, char *argv[])
params.droproot = true; params.droproot = true;
break; break;
} }
case 13: /* uid */ case IDX_UID:
params.gid=0x7FFFFFFF; // default git. drop gid=0 params.gid=0x7FFFFFFF; // default git. drop gid=0
params.droproot = true; params.droproot = true;
if (sscanf(optarg,"%u:%u",&params.uid,&params.gid)<1) if (sscanf(optarg,"%u:%u",&params.uid,&params.gid)<1)
@ -860,7 +967,7 @@ void parse_params(int argc, char *argv[])
exit_clean(1); exit_clean(1);
} }
break; break;
case 14: /* maxconn */ case IDX_MAXCONN:
params.maxconn = atoi(optarg); params.maxconn = atoi(optarg);
if (params.maxconn <= 0 || params.maxconn > 10000) if (params.maxconn <= 0 || params.maxconn > 10000)
{ {
@ -868,7 +975,7 @@ void parse_params(int argc, char *argv[])
exit_clean(1); exit_clean(1);
} }
break; break;
case 15: /* maxfiles */ case IDX_MAXFILES:
params.maxfiles = atoi(optarg); params.maxfiles = atoi(optarg);
if (params.maxfiles < 0) if (params.maxfiles < 0)
{ {
@ -876,7 +983,7 @@ void parse_params(int argc, char *argv[])
exit_clean(1); exit_clean(1);
} }
break; break;
case 16: /* max-orphan-time */ case IDX_MAX_ORPHAN_TIME:
params.max_orphan_time = atoi(optarg); params.max_orphan_time = atoi(optarg);
if (params.max_orphan_time < 0) if (params.max_orphan_time < 0)
{ {
@ -884,11 +991,21 @@ void parse_params(int argc, char *argv[])
exit_clean(1); exit_clean(1);
} }
break; break;
case 17: /* hostcase */ case IDX_IPCACHE_LIFETIME:
if (sscanf(optarg, "%u", &params.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; dp->hostcase = true;
params.tamper = true; params.tamper = true;
break; break;
case 18: /* hostspell */ case IDX_HOSTSPELL:
if (strlen(optarg) != 4) if (strlen(optarg) != 4)
{ {
DLOG_ERR("hostspell must be exactly 4 chars long\n"); 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); memcpy(dp->hostspell, optarg, 4);
params.tamper = true; params.tamper = true;
break; break;
case 19: /* hostdot */ case IDX_HOSTDOT:
dp->hostdot = true; dp->hostdot = true;
params.tamper = true; params.tamper = true;
break; break;
case 20: /* hostnospace */ case IDX_HOSTNOSPACE:
dp->hostnospace = true; dp->hostnospace = true;
params.tamper = true; params.tamper = true;
break; break;
case 21: /* hostpad */ case IDX_HOSTPAD:
dp->hostpad = atoi(optarg); dp->hostpad = atoi(optarg);
params.tamper = true; params.tamper = true;
break; break;
case 22: /* domcase */ case IDX_DOMCASE:
dp->domcase = true; dp->domcase = true;
params.tamper = true; params.tamper = true;
break; 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); DLOG_CONDUP("WARNING ! --split-http-req is deprecated. use --split-pos with markers.\n",MAX_SPLITS);
if (dp->split_count>=MAX_SPLITS) if (dp->split_count>=MAX_SPLITS)
{ {
@ -929,7 +1046,7 @@ void parse_params(int argc, char *argv[])
dp->split_count++; dp->split_count++;
params.tamper = true; params.tamper = true;
break; break;
case 24: /* split-tls */ case IDX_SPLIT_TLS:
// obsolete arg // obsolete arg
DLOG_CONDUP("WARNING ! --split-tls is deprecated. use --split-pos with markers.\n",MAX_SPLITS); DLOG_CONDUP("WARNING ! --split-tls is deprecated. use --split-pos with markers.\n",MAX_SPLITS);
if (dp->split_count>=MAX_SPLITS) if (dp->split_count>=MAX_SPLITS)
@ -945,7 +1062,7 @@ void parse_params(int argc, char *argv[])
dp->split_count++; dp->split_count++;
params.tamper = true; params.tamper = true;
break; break;
case 25: /* split-pos */ case IDX_SPLIT_POS:
{ {
int ct; int ct;
if (!parse_split_pos_list(optarg,dp->splits+dp->split_count,MAX_SPLITS-dp->split_count,&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; params.tamper = true;
break; break;
case 26: /* split-any-protocol */ case IDX_SPLIT_ANY_PROTOCOL:
dp->split_any_protocol = true; dp->split_any_protocol = true;
break; break;
case 27: /* disorder */ case IDX_DISORDER:
if (optarg) if (optarg)
{ {
if (!strcmp(optarg,"http")) dp->disorder_http=true; if (!strcmp(optarg,"http")) dp->disorder_http=true;
@ -981,7 +1098,7 @@ void parse_params(int argc, char *argv[])
} }
#endif #endif
break; break;
case 28: /* oob */ case IDX_OOB:
if (optarg) if (optarg)
{ {
if (!strcmp(optarg,"http")) dp->oob_http=true; if (!strcmp(optarg,"http")) dp->oob_http=true;
@ -1002,7 +1119,7 @@ void parse_params(int argc, char *argv[])
} }
#endif #endif
break; break;
case 29: /* oob-data */ case IDX_OOB_DATA:
{ {
size_t l = strlen(optarg); size_t l = strlen(optarg);
unsigned int bt; unsigned int bt;
@ -1015,23 +1132,23 @@ void parse_params(int argc, char *argv[])
else dp->oob_byte = (uint8_t)bt; else dp->oob_byte = (uint8_t)bt;
} }
break; break;
case 30: /* methodspace */ case IDX_METHODSPACE:
dp->methodspace = true; dp->methodspace = true;
params.tamper = true; params.tamper = true;
break; break;
case 31: /* methodeol */ case IDX_METHODEOL:
dp->methodeol = true; dp->methodeol = true;
params.tamper = true; params.tamper = true;
break; break;
case 32: /* hosttab */ case IDX_HOSTTAB:
dp->hosttab = true; dp->hosttab = true;
params.tamper = true; params.tamper = true;
break; break;
case 33: /* unixeol */ case IDX_UNIXEOL:
dp->unixeol = true; dp->unixeol = true;
params.tamper = true; params.tamper = true;
break; break;
case 34: /* tlsrec */ case IDX_TLSREC:
if (!parse_split_pos(optarg, &dp->tlsrec) && !parse_tlspos(optarg, &dp->tlsrec)) if (!parse_split_pos(optarg, &dp->tlsrec) && !parse_tlspos(optarg, &dp->tlsrec))
{ {
DLOG_ERR("Invalid argument for tlsrec\n"); DLOG_ERR("Invalid argument for tlsrec\n");
@ -1039,7 +1156,7 @@ void parse_params(int argc, char *argv[])
} }
params.tamper = true; params.tamper = true;
break; break;
case 35: /* tlsrec-pos */ case IDX_TLSREC_POS:
// obsolete arg // obsolete arg
i = atoi(optarg); i = atoi(optarg);
dp->tlsrec.marker = PM_ABS; dp->tlsrec.marker = PM_ABS;
@ -1051,7 +1168,7 @@ void parse_params(int argc, char *argv[])
} }
params.tamper = true; params.tamper = true;
break; break;
case 36: /* hostlist */ case IDX_HOSTLIST:
if (bSkip) break; if (bSkip) break;
if (!RegisterHostlist(dp, false, optarg)) if (!RegisterHostlist(dp, false, optarg))
{ {
@ -1060,7 +1177,7 @@ void parse_params(int argc, char *argv[])
} }
params.tamper = true; params.tamper = true;
break; break;
case 37: /* hostlist-domains */ case IDX_HOSTLIST_DOMAINS:
if (bSkip) break; if (bSkip) break;
if (!anon_hl && !(anon_hl=RegisterHostlist(dp, false, NULL))) if (!anon_hl && !(anon_hl=RegisterHostlist(dp, false, NULL)))
{ {
@ -1074,7 +1191,7 @@ void parse_params(int argc, char *argv[])
} }
params.tamper = true; params.tamper = true;
break; break;
case 38: /* hostlist-exclude */ case IDX_HOSTLIST_EXCLUDE:
if (bSkip) break; if (bSkip) break;
if (!RegisterHostlist(dp, true, optarg)) if (!RegisterHostlist(dp, true, optarg))
{ {
@ -1083,7 +1200,7 @@ void parse_params(int argc, char *argv[])
} }
params.tamper = true; params.tamper = true;
break; break;
case 39: /* hostlist-exclude-domains */ case IDX_HOSTLIST_EXCLUDE_DOMAINS:
if (bSkip) break; if (bSkip) break;
if (!anon_hl_exclude && !(anon_hl_exclude=RegisterHostlist(dp, true, NULL))) 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; params.tamper = true;
break; break;
case 40: /* hostlist-auto */ case IDX_HOSTLIST_AUTO:
if (bSkip) break; if (bSkip) break;
if (dp->hostlist_auto) 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. params.tamper = true; // need to detect blocks and update autohostlist. cannot just slice.
break; break;
case 41: /* hostlist-auto-fail-threshold */ case IDX_HOSTLIST_AUTO_FAIL_THRESHOLD:
dp->hostlist_auto_fail_threshold = (uint8_t)atoi(optarg); dp->hostlist_auto_fail_threshold = (uint8_t)atoi(optarg);
if (dp->hostlist_auto_fail_threshold<1 || dp->hostlist_auto_fail_threshold>20) 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); exit_clean(1);
} }
break; break;
case 42: /* hostlist-auto-fail-time */ case IDX_HOSTLIST_AUTO_FAIL_TIME:
dp->hostlist_auto_fail_time = (uint8_t)atoi(optarg); dp->hostlist_auto_fail_time = (uint8_t)atoi(optarg);
if (dp->hostlist_auto_fail_time<1) if (dp->hostlist_auto_fail_time<1)
{ {
@ -1142,7 +1259,7 @@ void parse_params(int argc, char *argv[])
exit_clean(1); exit_clean(1);
} }
break; break;
case 43: /* hostlist-auto-debug */ case IDX_HOSTLIST_AUTO_DEBUG:
{ {
FILE *F = fopen(optarg,"a+t"); FILE *F = fopen(optarg,"a+t");
if (!F) if (!F)
@ -1155,11 +1272,11 @@ void parse_params(int argc, char *argv[])
params.hostlist_auto_debuglog[sizeof(params.hostlist_auto_debuglog) - 1] = '\0'; params.hostlist_auto_debuglog[sizeof(params.hostlist_auto_debuglog) - 1] = '\0';
} }
break; break;
case 44: /* pidfile */ case IDX_PIDFILE:
strncpy(params.pidfile,optarg,sizeof(params.pidfile)); strncpy(params.pidfile,optarg,sizeof(params.pidfile));
params.pidfile[sizeof(params.pidfile)-1]='\0'; params.pidfile[sizeof(params.pidfile)-1]='\0';
break; break;
case 45: /* debug */ case IDX_DEBUG:
if (optarg) if (optarg)
{ {
if (*optarg=='@') if (*optarg=='@')
@ -1193,52 +1310,52 @@ void parse_params(int argc, char *argv[])
params.debug_target = LOG_TARGET_CONSOLE; params.debug_target = LOG_TARGET_CONSOLE;
} }
break; break;
case 46: /* debug-level */ case IDX_DEBUG_LEVEL:
params.debug = atoi(optarg); params.debug = atoi(optarg);
break; break;
case 47: /* dry-run */ case IDX_DRY_RUN:
bDry = true; bDry = true;
break; break;
case 48: /* version */ case IDX_VERSION:
exit_clean(0); exit_clean(0);
break; break;
case 49: /* comment */ case IDX_COMMENT:
break; break;
case 50: /* local-rcvbuf */ case IDX_LOCAL_RCVBUF:
#ifdef __linux__ #ifdef __linux__
params.local_rcvbuf = atoi(optarg)/2; params.local_rcvbuf = atoi(optarg)/2;
#else #else
params.local_rcvbuf = atoi(optarg); params.local_rcvbuf = atoi(optarg);
#endif #endif
break; break;
case 51: /* local-sndbuf */ case IDX_LOCAL_SNDBUF:
#ifdef __linux__ #ifdef __linux__
params.local_sndbuf = atoi(optarg)/2; params.local_sndbuf = atoi(optarg)/2;
#else #else
params.local_sndbuf = atoi(optarg); params.local_sndbuf = atoi(optarg);
#endif #endif
break; break;
case 52: /* remote-rcvbuf */ case IDX_REMOTE_RCVBUF:
#ifdef __linux__ #ifdef __linux__
params.remote_rcvbuf = atoi(optarg)/2; params.remote_rcvbuf = atoi(optarg)/2;
#else #else
params.remote_rcvbuf = atoi(optarg); params.remote_rcvbuf = atoi(optarg);
#endif #endif
break; break;
case 53: /* remote-sndbuf */ case IDX_REMOTE_SNDBUF:
#ifdef __linux__ #ifdef __linux__
params.remote_sndbuf = atoi(optarg)/2; params.remote_sndbuf = atoi(optarg)/2;
#else #else
params.remote_sndbuf = atoi(optarg); params.remote_sndbuf = atoi(optarg);
#endif #endif
break; break;
case 54: /* socks */ case IDX_SOCKS:
params.proxy_type = CONN_TYPE_SOCKS; params.proxy_type = CONN_TYPE_SOCKS;
break; break;
case 55: /* no-resolve */ case IDX_NO_RESOLVE:
params.no_resolve = true; params.no_resolve = true;
break; break;
case 56: /* resolver-threads */ case IDX_RESOLVER_THREADS:
params.resolver_threads = atoi(optarg); params.resolver_threads = atoi(optarg);
if (params.resolver_threads<1 || params.resolver_threads>300) if (params.resolver_threads<1 || params.resolver_threads>300)
{ {
@ -1246,10 +1363,10 @@ void parse_params(int argc, char *argv[])
exit_clean(1); exit_clean(1);
} }
break; break;
case 57: /* skip-nodelay */ case IDX_SKIP_NODELAY:
params.skip_nodelay = true; params.skip_nodelay = true;
break; break;
case 58: /* tamper-start */ case IDX_TAMPER_START:
{ {
const char *p=optarg; const char *p=optarg;
if (*p=='n') if (*p=='n')
@ -1263,7 +1380,7 @@ void parse_params(int argc, char *argv[])
} }
params.tamper_lim = true; params.tamper_lim = true;
break; break;
case 59: /* tamper-cutoff */ case IDX_TAMPER_CUTOFF:
{ {
const char *p=optarg; const char *p=optarg;
if (*p=='n') if (*p=='n')
@ -1277,7 +1394,7 @@ void parse_params(int argc, char *argv[])
} }
params.tamper_lim = true; params.tamper_lim = true;
break; break;
case 60: /* connect-bind-addr */ case IDX_CONNECT_BIND_ADDR:
{ {
char *p = strchr(optarg,'%'); char *p = strchr(optarg,'%');
if (p) *p++=0; if (p) *p++=0;
@ -1305,7 +1422,7 @@ void parse_params(int argc, char *argv[])
break; break;
case 61: /* new */ case IDX_NEW:
if (bSkip) if (bSkip)
{ {
dp_clear(dp); dp_clear(dp);
@ -1326,31 +1443,31 @@ void parse_params(int argc, char *argv[])
anon_hl = anon_hl_exclude = NULL; anon_hl = anon_hl_exclude = NULL;
anon_ips = anon_ips_exclude = NULL; anon_ips = anon_ips_exclude = NULL;
break; break;
case 62: /* skip */ case IDX_SKIP:
bSkip = true; bSkip = true;
break; break;
case 63: /* filter-l3 */ case IDX_FILTER_L3:
if (!wf_make_l3(optarg,&dp->filter_ipv4,&dp->filter_ipv6)) if (!wf_make_l3(optarg,&dp->filter_ipv4,&dp->filter_ipv6))
{ {
DLOG_ERR("bad value for --filter-l3\n"); DLOG_ERR("bad value for --filter-l3\n");
exit_clean(1); exit_clean(1);
} }
break; break;
case 64: /* filter-tcp */ case IDX_FILTER_TCP:
if (!parse_pf_list(optarg,&dp->pf_tcp)) if (!parse_pf_list(optarg,&dp->pf_tcp))
{ {
DLOG_ERR("Invalid port filter : %s\n",optarg); DLOG_ERR("Invalid port filter : %s\n",optarg);
exit_clean(1); exit_clean(1);
} }
break; break;
case 65: /* filter-l7 */ case IDX_FILTER_L7:
if (!parse_l7_list(optarg,&dp->filter_l7)) if (!parse_l7_list(optarg,&dp->filter_l7))
{ {
DLOG_ERR("Invalid l7 filter : %s\n",optarg); DLOG_ERR("Invalid l7 filter : %s\n",optarg);
exit_clean(1); exit_clean(1);
} }
break; break;
case 66: /* ipset */ case IDX_IPSET:
if (bSkip) break; if (bSkip) break;
if (!RegisterIpset(dp, false, optarg)) if (!RegisterIpset(dp, false, optarg))
{ {
@ -1359,7 +1476,7 @@ void parse_params(int argc, char *argv[])
} }
params.tamper = true; params.tamper = true;
break; break;
case 67: /* ipset-ip */ case IDX_IPSET_IP:
if (bSkip) break; if (bSkip) break;
if (!anon_ips && !(anon_ips=RegisterIpset(dp, false, NULL))) if (!anon_ips && !(anon_ips=RegisterIpset(dp, false, NULL)))
{ {
@ -1373,7 +1490,7 @@ void parse_params(int argc, char *argv[])
} }
params.tamper = true; params.tamper = true;
break; break;
case 68: /* ipset-exclude */ case IDX_IPSET_EXCLUDE:
if (bSkip) break; if (bSkip) break;
if (!RegisterIpset(dp, true, optarg)) if (!RegisterIpset(dp, true, optarg))
{ {
@ -1382,7 +1499,7 @@ void parse_params(int argc, char *argv[])
} }
params.tamper = true; params.tamper = true;
break; break;
case 69: /* ipset-exclude-ip */ case IDX_IPSET_EXCLUDE_IP:
if (bSkip) break; if (bSkip) break;
if (!anon_ips_exclude && !(anon_ips_exclude=RegisterIpset(dp, true, NULL))) if (!anon_ips_exclude && !(anon_ips_exclude=RegisterIpset(dp, true, NULL)))
{ {
@ -1398,11 +1515,11 @@ void parse_params(int argc, char *argv[])
break; break;
#if defined(__FreeBSD__) #if defined(__FreeBSD__)
case 70: /* enable-pf */ case IDX_ENABLE_PF:
params.pf_enable = true; params.pf_enable = true;
break; break;
#elif defined(__linux__) || defined(__APPLE__) #elif defined(__linux__) || defined(__APPLE__)
case 70: /* local-tcp-user-timeout */ case IDX_LOCAL_TCP_USER_TIMEOUT:
params.tcp_user_timeout_local = atoi(optarg); params.tcp_user_timeout_local = atoi(optarg);
if (params.tcp_user_timeout_local<0 || params.tcp_user_timeout_local>86400) if (params.tcp_user_timeout_local<0 || params.tcp_user_timeout_local>86400)
{ {
@ -1410,7 +1527,7 @@ void parse_params(int argc, char *argv[])
exit_clean(1); exit_clean(1);
} }
break; break;
case 71: /* remote-tcp-user-timeout */ case IDX_REMOTE_TCP_USER_TIMEOUT:
params.tcp_user_timeout_remote = atoi(optarg); params.tcp_user_timeout_remote = atoi(optarg);
if (params.tcp_user_timeout_remote<0 || params.tcp_user_timeout_remote>86400) if (params.tcp_user_timeout_remote<0 || params.tcp_user_timeout_remote>86400)
{ {
@ -1421,7 +1538,7 @@ void parse_params(int argc, char *argv[])
#endif #endif
#if defined(__linux__) #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 // this option does not work in any BSD and MacOS. OS may accept but it changes nothing
dp->mss = atoi(optarg); dp->mss = atoi(optarg);
if (dp->mss<88 || dp->mss>32767) if (dp->mss<88 || dp->mss>32767)
@ -1430,7 +1547,7 @@ void parse_params(int argc, char *argv[])
exit_clean(1); exit_clean(1);
} }
break; break;
case 73: /* fix-seg */ case IDX_FIX_SEG:
if (!params.fix_seg_avail) if (!params.fix_seg_avail)
{ {
DLOG_ERR("--fix-seg is supported since kernel 4.6\n"); 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; params.fix_seg = FIX_SEG_DEFAULT_MAX_WAIT;
break; break;
#ifdef SPLICE_PRESENT #ifdef SPLICE_PRESENT
case 74: /* nosplice */ case IDX_NOSPLICE:
params.nosplice = true; params.nosplice = true;
break; break;
#endif #endif
@ -1521,6 +1638,9 @@ void parse_params(int argc, char *argv[])
} }
#endif #endif
if (!test_list_files())
exit_clean(1);
if (!LoadAllHostLists()) if (!LoadAllHostLists())
{ {
DLOG_ERR("hostlists load failed\n"); DLOG_ERR("hostlists load failed\n");
@ -1723,14 +1843,6 @@ int main(int argc, char *argv[])
parse_params(argc, argv); parse_params(argc, argv);
argv=NULL; argc=0; 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)); memset(&list, 0, sizeof(list));
for(i=0;i<=params.binds_last;i++) listen_fd[i]=-1; 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(); set_ulimit();
sec_harden(); sec_harden();
if (params.droproot && !droproot(params.uid,params.gid)) if (params.droproot && !droproot(params.uid,params.gid))
@ -1982,9 +2106,6 @@ int main(int argc, char *argv[])
goto exiterr; 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(SIGHUP, onhup);
signal(SIGUSR2, onusr2); signal(SIGUSR2, onusr2);