2021-12-08 15:20:44 +03:00
#!/bin/sh
EXEDIR = " $( dirname " $0 " ) "
EXEDIR = " $( cd " $EXEDIR " ; pwd ) "
ZAPRET_BASE = " $EXEDIR "
2022-02-15 17:15:36 +03:00
[ -f " $ZAPRET_BASE /config " ] && . " $ZAPRET_BASE /config "
. " $ZAPRET_BASE /common/base.sh "
. " $ZAPRET_BASE /common/dialog.sh "
. " $ZAPRET_BASE /common/elevate.sh "
. " $ZAPRET_BASE /common/fwtype.sh "
2022-04-13 11:47:14 +03:00
. " $ZAPRET_BASE /common/virt.sh "
2022-02-15 17:15:36 +03:00
2021-12-08 15:20:44 +03:00
[ -n " $QNUM " ] || QNUM = 59780
2024-03-14 16:44:08 +03:00
[ -n " $SOCKS_PORT " ] || SOCKS_PORT = 1993
2022-02-04 20:58:25 +03:00
[ -n " $TPWS_UID " ] || TPWS_UID = 1
[ -n " $TPWS_GID " ] || TPWS_GID = 3003
2021-12-08 15:20:44 +03:00
[ -n " $NFQWS " ] || NFQWS = " $ZAPRET_BASE /nfq/nfqws "
2021-12-12 16:03:07 +03:00
[ -n " $DVTWS " ] || DVTWS = " $ZAPRET_BASE /nfq/dvtws "
2021-12-09 20:05:15 +03:00
[ -n " $TPWS " ] || TPWS = " $ZAPRET_BASE /tpws/tpws "
2021-12-08 15:20:44 +03:00
[ -n " $MDIG " ] || MDIG = " $ZAPRET_BASE /mdig/mdig "
2024-03-10 21:22:16 +03:00
DESYNC_MARK = 0x10000000
2021-12-13 10:38:00 +03:00
[ -n " $IPFW_RULE_NUM " ] || IPFW_RULE_NUM = 1
[ -n " $IPFW_DIVERT_PORT " ] || IPFW_DIVERT_PORT = 59780
2021-12-24 17:26:59 +03:00
[ -n " $DOMAINS " ] || DOMAINS = rutracker.org
2023-11-02 10:40:54 +03:00
[ -n " $CURL_MAX_TIME " ] || CURL_MAX_TIME = 3
2021-12-13 10:38:00 +03:00
[ -n " $MIN_TTL " ] || MIN_TTL = 1
[ -n " $MAX_TTL " ] || MAX_TTL = 12
2022-03-12 14:08:14 +03:00
[ -n " $USER_AGENT " ] || USER_AGENT = "Mozilla"
2021-12-13 10:38:00 +03:00
2021-12-08 15:20:44 +03:00
HDRTEMP = /tmp/zapret-hdr.txt
2022-02-10 22:30:50 +03:00
NFT_TABLE = blockcheck
2022-01-10 10:44:00 +03:00
[ -n " $DNSCHECK_DNS " ] || DNSCHECK_DNS = "8.8.8.8 1.1.1.1 77.88.8.1"
2023-10-31 11:47:35 +03:00
[ -n " $DNSCHECK_DOM " ] || DNSCHECK_DOM = "pornhub.com putinhuylo.com rutracker.org www.torproject.org bbc.com"
2021-12-08 15:20:44 +03:00
DNSCHECK_DIG1 = /tmp/dig1.txt
DNSCHECK_DIG2 = /tmp/dig2.txt
DNSCHECK_DIGS = /tmp/digs.txt
2024-03-11 19:00:22 +03:00
unset PF_STATUS
PF_RULES_SAVE = /tmp/pf-zapret-save.conf
2021-12-08 15:20:44 +03:00
2024-03-14 16:44:08 +03:00
unset ALL_PROXY
2024-03-11 20:49:11 +03:00
2021-12-08 15:20:44 +03:00
killwait( )
{
# $1 - signal (-9, -2, ...)
# $2 - pid
kill $1 $2
# suppress job kill message
wait $2 2>/dev/null
}
exitp( )
{
local A
echo
echo press enter to continue
read A
exit $1
}
2024-03-11 19:00:22 +03:00
pf_is_avail( )
{
[ -c /dev/pf ]
}
pf_status( )
{
pfctl -qsi | sed -nre " s/^Status: ([^ ]+).* $/\1/p "
}
pf_is_enabled( )
{
[ " $( pf_status) " = Enabled ]
}
pf_save( )
{
PF_STATUS = 0
pf_is_enabled && PF_STATUS = 1
2024-03-11 20:49:11 +03:00
[ " $UNAME " = "OpenBSD" ] && pfctl -sr >" $PF_RULES_SAVE "
2024-03-11 19:00:22 +03:00
}
pf_restore( )
{
[ -n " $PF_STATUS " ] || return
2024-03-11 20:49:11 +03:00
case " $UNAME " in
OpenBSD)
if [ -f " $PF_RULES_SAVE " ] ; then
pfctl -qf " $PF_RULES_SAVE "
else
echo | pfctl -qf -
fi
; ;
Darwin)
# it's not possible to save all rules in the right order. hard to reorder. if not ordered pf will refuse to load conf.
pfctl -qf /etc/pf.conf
; ;
esac
2024-03-11 19:00:22 +03:00
if [ " $PF_STATUS " = 1 ] ; then
pfctl -qe
else
pfctl -qd
fi
}
pf_clean( )
{
rm -f " $PF_RULES_SAVE "
}
opf_dvtws_anchor( )
{
2024-03-14 23:59:58 +03:00
# $1 - tcp/udp
# $2 - port
2024-03-11 20:49:11 +03:00
local family = inet
[ " $IPV " = 6 ] && family = inet6
2024-03-11 19:00:22 +03:00
echo "set reassemble no"
2024-03-14 23:59:58 +03:00
[ " $1 " = tcp ] && echo " pass in quick $family proto $1 from port $2 flags SA/SA divert-packet port $IPFW_DIVERT_PORT no state "
echo " pass in quick $family proto $1 from port $2 no state "
echo " pass out quick $family proto $1 to port $2 divert-packet port $IPFW_DIVERT_PORT no state "
2024-03-11 19:00:22 +03:00
echo "pass"
}
opf_prepare_dvtws( )
{
2024-03-14 23:59:58 +03:00
# $1 - tcp/udp
# $2 - port
opf_dvtws_anchor $1 $2 | pfctl -qf -
2024-03-11 20:49:11 +03:00
pfctl -qe
}
2024-03-11 19:00:22 +03:00
cleanup( )
{
case " $UNAME " in
OpenBSD)
pf_clean
; ;
esac
}
2021-12-08 15:20:44 +03:00
IPT( )
{
$IPTABLES -C " $@ " >/dev/null 2>/dev/null || $IPTABLES -I " $@ "
}
IPT_DEL( )
{
$IPTABLES -C " $@ " >/dev/null 2>/dev/null && $IPTABLES -D " $@ "
}
2024-03-15 14:49:59 +03:00
IPT_ADD_DEL( )
{
on_off_function IPT IPT_DEL " $@ "
}
2021-12-12 16:03:07 +03:00
IPFW_ADD( )
{
ipfw -qf add $IPFW_RULE_NUM " $@ "
}
IPFW_DEL( )
{
2022-02-05 22:27:15 +03:00
ipfw -qf delete $IPFW_RULE_NUM 2>/dev/null
2021-12-12 16:03:07 +03:00
}
2022-01-04 00:11:10 +03:00
ipt6_has_raw( )
{
2022-01-11 00:28:44 +03:00
ip6tables -nL -t raw >/dev/null 2>/dev/null
}
2022-02-05 22:19:17 +03:00
ipt6_has_frag( )
{
ip6tables -A OUTPUT -m frag 2>/dev/null || return 1
ip6tables -D OUTPUT -m frag 2>/dev/null
}
2022-01-11 00:28:44 +03:00
ipt_has_nfq( )
{
# cannot just check /proc/net/ip_tables_targets because of iptables-nft or modules not loaded yet
2022-10-20 16:31:07 +03:00
iptables -A OUTPUT -t mangle -p 255 -j NFQUEUE --queue-num $QNUM --queue-bypass 2>/dev/null || return 1
iptables -D OUTPUT -t mangle -p 255 -j NFQUEUE --queue-num $QNUM --queue-bypass 2>/dev/null
2022-01-11 00:28:44 +03:00
return 0
2022-01-04 00:11:10 +03:00
}
2022-02-10 22:30:50 +03:00
nft_has_nfq( )
{
local res = 1
nft delete table ${ NFT_TABLE } _test 2>/dev/null
nft add table ${ NFT_TABLE } _test 2>/dev/null && {
nft add chain ${ NFT_TABLE } _test test
nft add rule ${ NFT_TABLE } _test test queue num $QNUM bypass 2>/dev/null && res = 0
nft delete table ${ NFT_TABLE } _test
}
return $res
}
2021-12-08 15:20:44 +03:00
2024-03-14 16:44:08 +03:00
mdig_resolve( )
{
# $1 - ip version 4/6
# $2 - hostname
echo " $2 " | " $MDIG " --family= $1 | head -n 1
}
2021-12-08 15:20:44 +03:00
check_system( )
{
echo \* checking system
2021-12-12 16:03:07 +03:00
UNAME = $( uname)
2022-01-10 10:44:00 +03:00
SUBSYS =
2022-04-06 10:55:33 +03:00
local s
2022-01-10 10:44:00 +03:00
2022-02-11 10:24:35 +03:00
# can be passed FWTYPE=iptables to override default nftables preference
2021-12-12 16:03:07 +03:00
case " $UNAME " in
Linux)
PKTWS = " $NFQWS "
PKTWSD = nfqws
2022-02-15 17:15:36 +03:00
linux_fwtype
[ " $FWTYPE " = iptables -o " $FWTYPE " = nftables ] || {
echo firewall type $FWTYPE not supported in $UNAME
exitp 5
}
2021-12-12 16:03:07 +03:00
; ;
FreeBSD)
PKTWS = " $DVTWS "
PKTWSD = dvtws
2022-02-10 22:30:50 +03:00
FWTYPE = ipfw
2022-04-06 10:55:33 +03:00
[ -f /etc/platform ] && read SUBSYS </etc/platform
2021-12-12 16:03:07 +03:00
; ;
2024-03-11 19:00:22 +03:00
OpenBSD)
PKTWS = " $DVTWS "
PKTWSD = dvtws
FWTYPE = opf
2024-03-11 20:49:11 +03:00
; ;
Darwin)
PKTWS = " $DVTWS "
PKTWSD = dvtws
FWTYPE = mpf
2024-03-11 19:00:22 +03:00
; ;
2021-12-12 16:03:07 +03:00
*)
echo $UNAME not supported
exitp 5
esac
2022-01-10 10:44:00 +03:00
echo $UNAME ${ SUBSYS : +/ $SUBSYS } detected
2022-02-10 22:30:50 +03:00
echo firewall type is $FWTYPE
2021-12-12 16:03:07 +03:00
}
freebsd_module_loaded( )
{
# $1 - module name
2022-01-12 22:41:25 +03:00
kldstat -qm " ${ 1 } "
2021-12-12 16:03:07 +03:00
}
freebsd_modules_loaded( )
{
# $1,$2,$3, ... - module names
while [ -n " $1 " ] ; do
freebsd_module_loaded $1 || return 1
shift
done
return 0
2021-12-08 15:20:44 +03:00
}
check_prerequisites( )
{
echo \* checking prerequisites
2021-12-12 16:03:07 +03:00
2024-03-11 20:49:11 +03:00
[ " $UNAME " = Darwin -o -x " $PKTWS " ] && [ -x " $TPWS " ] && [ -x " $MDIG " ] || {
2024-03-14 18:20:13 +03:00
local target
case $UNAME in
Darwin)
target = "mac"
; ;
OpenBSD)
target = "bsd"
; ;
esac
echo $PKTWS or $TPWS or $MDIG is not available. run \" $ZAPRET_BASE /install_bin.sh\" or \` make -C \" $ZAPRET_BASE \" $target \`
2021-12-08 15:20:44 +03:00
exitp 6
}
2022-01-11 00:46:32 +03:00
local prog progs = 'curl'
2021-12-12 16:03:07 +03:00
case " $UNAME " in
Linux)
2022-02-10 22:30:50 +03:00
case " $FWTYPE " in
iptables)
progs = " $progs iptables ip6tables "
ipt_has_nfq || {
echo NFQUEUE iptables or ip6tables target is missing. pls install modules.
exitp 6
}
; ;
nftables)
nft_has_nfq || {
echo nftables queue support is not available. pls install modules.
exitp 6
}
; ;
esac
2021-12-12 16:03:07 +03:00
; ;
FreeBSD)
progs = " $progs ipfw "
freebsd_modules_loaded ipfw ipdivert || {
echo ipfw or ipdivert kernel module not loaded
exitp 6
}
2021-12-12 23:34:04 +03:00
[ " $( sysctl -qn net.inet.ip.fw.enable) " = 0 -o " $( sysctl -qn net.inet6.ip6.fw.enable) " = 0 ] && {
echo ipfw is disabled. use : ipfw enable firewall
exitp 6
}
2024-03-14 17:51:41 +03:00
pf_is_avail && {
pf_save
[ " $SUBSYS " = "pfSense" ] && {
# pfsense's ipfw may not work without these workarounds
sysctl net.inet.ip.pfil.outbound= ipfw,pf 2>/dev/null
sysctl net.inet.ip.pfil.inbound= ipfw,pf 2>/dev/null
sysctl net.inet6.ip6.pfil.outbound= ipfw,pf 2>/dev/null
sysctl net.inet6.ip6.pfil.inbound= ipfw,pf 2>/dev/null
pfctl -qd
pfctl -qe
pf_restore
}
}
2021-12-12 16:03:07 +03:00
; ;
2024-03-11 20:49:11 +03:00
OpenBSD| Darwin)
2024-03-11 19:00:22 +03:00
progs = " $progs pfctl "
pf_is_avail || {
echo pf is not available
exitp 6
}
2024-03-11 20:49:11 +03:00
# no divert sockets in MacOS
[ " $UNAME " = "Darwin" ] && SKIP_PKTWS = 1
2024-03-11 19:00:22 +03:00
pf_save
; ;
2021-12-12 16:03:07 +03:00
esac
for prog in $progs ; do
2021-12-08 15:20:44 +03:00
exists $prog || {
echo $prog does not exist. please install
exitp 6
}
done
2021-12-12 16:03:07 +03:00
if exists nslookup; then
LOOKUP = nslookup
elif exists host; then
LOOKUP = host
else
echo nslookup or host does not exist. please install
exitp 6
fi
2021-12-08 15:20:44 +03:00
}
2021-12-25 12:22:47 +03:00
curl_translate_code( )
{
# $1 - code
2022-02-15 20:51:45 +03:00
printf $1
2021-12-25 12:22:47 +03:00
case $1 in
2022-02-15 20:51:45 +03:00
0) printf ": ok"
2021-12-25 12:22:47 +03:00
; ;
2022-02-15 20:51:45 +03:00
1) printf ": unsupported protocol"
2021-12-25 12:22:47 +03:00
; ;
2022-02-15 20:51:45 +03:00
2) printf ": early initialization code failed"
2021-12-25 12:22:47 +03:00
; ;
2022-02-15 20:51:45 +03:00
3) printf ": the URL was not properly formatted"
2021-12-25 12:22:47 +03:00
; ;
2022-02-15 20:51:45 +03:00
4) printf ": feature not supported by libcurl"
2021-12-25 12:22:47 +03:00
; ;
2022-02-15 20:51:45 +03:00
5) printf ": could not resolve proxy"
2021-12-25 12:22:47 +03:00
; ;
2022-02-15 20:51:45 +03:00
6) printf ": could not resolve host"
2021-12-25 12:22:47 +03:00
; ;
2022-02-15 20:51:45 +03:00
7) printf ": could not connect"
2021-12-25 12:22:47 +03:00
; ;
2022-02-15 20:51:45 +03:00
8) printf ": invalid server reply"
2021-12-25 12:22:47 +03:00
; ;
2022-02-15 20:51:45 +03:00
9) printf ": remote access denied"
2021-12-25 12:22:47 +03:00
; ;
2022-02-15 20:51:45 +03:00
27) printf ": out of memory"
2021-12-25 12:22:47 +03:00
; ;
2022-02-15 20:51:45 +03:00
28) printf ": operation timed out"
2021-12-25 12:41:57 +03:00
; ;
2022-02-15 20:51:45 +03:00
35) printf ": SSL connect error"
2021-12-25 12:41:57 +03:00
; ;
2021-12-25 12:22:47 +03:00
esac
}
2021-12-10 11:18:25 +03:00
curl_supports_tls13( )
{
2023-10-16 18:28:04 +03:00
local r
2024-03-14 17:22:30 +03:00
curl --tlsv1.3 -Is -o /dev/null --max-time 1 http://127.0.0.1:65535 2>/dev/null
2021-12-10 11:18:25 +03:00
# return code 2 = init failed. likely bad command line options
2021-12-11 11:27:37 +03:00
[ $? = 2 ] && return 1
# curl can have tlsv1.3 key present but ssl library without TLS 1.3 support
# this is online test because there's no other way to trigger library incompatibility case
2022-01-22 18:16:38 +03:00
curl --tlsv1.3 --max-time $CURL_MAX_TIME -Is -o /dev/null https://w3.org 2>/dev/null
2023-10-16 18:28:04 +03:00
r = $?
[ $r != 4 -a $r != 35 ]
2021-12-10 11:18:25 +03:00
}
2021-12-08 15:20:44 +03:00
2023-03-26 12:52:30 +03:00
curl_supports_tlsmax( )
{
# supported only in OpenSSL and LibreSSL
curl --version | grep -Fq -e OpenSSL -e LibreSSL -e GnuTLS || return 1
# supported since curl 7.54
2024-03-14 17:22:30 +03:00
curl --tls-max 1.2 -Is -o /dev/null --max-time 1 http://127.0.0.1:65535 2>/dev/null
2023-03-26 12:52:30 +03:00
# return code 2 = init failed. likely bad command line options
[ $? != 2 ]
}
2024-03-14 16:44:08 +03:00
curl_supports_connect_to( )
{
2024-03-14 17:22:30 +03:00
curl --connect-to 127.0.0.1:: -o /dev/null --max-time 1 http://127.0.0.1:65535 2>/dev/null
2024-03-14 16:44:08 +03:00
[ " $? " != 2 ]
}
2024-03-14 23:59:58 +03:00
curl_supports_http3( )
{
# if it has http3 : curl: (3) HTTP/3 requested for non-HTTPS URL
# otherwise : curl: (2) option --http3-only: is unknown
curl --connect-to 127.0.0.1:: -o /dev/null --max-time 1 --http3-only http://127.0.0.1:65535 2>/dev/null
[ " $? " != 2 ]
}
2021-12-08 15:20:44 +03:00
hdrfile_http_code( )
{
# $1 - hdr file
sed -nre '1,1 s/^HTTP\/1\.[0,1] ([0-9]+) .*$/\1/p' " $1 "
}
hdrfile_location( )
{
# $1 - hdr file
# some DPIs return CRLF line ending
2022-01-22 18:08:05 +03:00
tr -d '\015' <" $1 " | sed -nre 's/^[Ll][Oo][Cc][Aa][Tt][Ii][Oo][Nn]:[ ]*([^ ]*)[ ]*$/\1/p'
2021-12-08 15:20:44 +03:00
}
2024-03-14 16:44:08 +03:00
curl_connect_to( )
{
# $1 - ip version : 4/6
# $2 - domain name
local ip = $( mdig_resolve $1 $2 )
[ -n " $ip " ] && echo " --connect-to $2 ::[ $ip ] "
}
curl_with_dig( )
{
# $1 - ip version : 4/6
# $2 - domain name
# $3+ - curl params
local connect_to = $( curl_connect_to $1 $2 )
[ -n " $connect_to " ] || {
echo " could not resolve ipv $1 $2 "
return 6
}
shift ; shift
ALL_PROXY = " $ALL_PROXY " curl $connect_to " $@ "
}
2021-12-08 15:20:44 +03:00
curl_test_http( )
{
# $1 - ip version : 4/6
# $2 - domain name
local code loc
2024-03-14 18:56:29 +03:00
curl_with_dig $1 $2 -SsD " $HDRTEMP " -A " $USER_AGENT " --max-time $CURL_MAX_TIME $CURL_OPT " http:// $2 " -o /dev/null 2>& 1 || {
2021-12-08 15:20:44 +03:00
code = $?
rm -f " $HDRTEMP "
return $code
}
code = $( hdrfile_http_code " $HDRTEMP " )
[ " $code " = 301 -o " $code " = 302 -o " $code " = 307 -o " $code " = 308 ] && {
loc = $( hdrfile_location " $HDRTEMP " )
2021-12-08 17:11:00 +03:00
echo " $loc " | grep -qE " ^https?://.* $2 (/| $) " ||
echo " $loc " | grep -vqE '^https?://' || {
2022-01-25 14:10:33 +03:00
echo suspicious redirection $code to : $loc
2021-12-08 15:20:44 +03:00
rm -f " $HDRTEMP "
return 254
}
}
rm -f " $HDRTEMP "
2023-11-02 10:40:54 +03:00
[ " $code " = 400 ] && {
# this can often happen if the server receives fake packets it should not receive
echo http code $code . likely the server receives fakes.
return 254
}
2021-12-08 15:20:44 +03:00
return 0
}
2021-12-10 11:18:25 +03:00
curl_test_https_tls12( )
2021-12-08 15:20:44 +03:00
{
# $1 - ip version : 4/6
# $2 - domain name
2021-12-10 11:18:25 +03:00
# do not use tls 1.3 to make sure server certificate is not encrypted
2024-03-19 13:47:36 +03:00
curl_with_dig $1 $2 -ISs -A " $USER_AGENT " --max-time $CURL_MAX_TIME $CURL_OPT --tlsv1.2 $TLSMAX12 " https:// $2 " -o /dev/null 2>& 1
2021-12-10 11:18:25 +03:00
}
curl_test_https_tls13( )
{
# $1 - ip version : 4/6
# $2 - domain name
# force TLS1.3 mode
2024-03-19 13:47:36 +03:00
curl_with_dig $1 $2 -ISs -A " $USER_AGENT " --max-time $CURL_MAX_TIME $CURL_OPT --tlsv1.3 $TLSMAX13 " https:// $2 " -o /dev/null 2>& 1
2024-03-14 23:59:58 +03:00
}
curl_test_http3( )
{
# $1 - ip version : 4/6
# $2 - domain name
2024-03-19 13:47:36 +03:00
# force TLS1.3 mode
curl_with_dig $1 $2 -ISs -A " $USER_AGENT " --max-time $CURL_MAX_TIME --http3-only $CURL_OPT " https:// $2 " -o /dev/null 2>& 1
2021-12-08 15:20:44 +03:00
}
2024-03-15 14:49:59 +03:00
ipt_scheme( )
2021-12-08 15:20:44 +03:00
{
2024-03-15 14:49:59 +03:00
# $1 - 1 - add , 0 - del
# $2 - tcp/udp
# $3 - port
IPT_ADD_DEL $1 OUTPUT -t mangle -p $2 --dport $3 -m mark ! --mark $DESYNC_MARK /$DESYNC_MARK -j NFQUEUE --queue-num $QNUM
# to avoid possible INVALID state drop
[ " $2 " = tcp ] && IPT_ADD_DEL $1 INPUT -p $2 --sport $3 ! --syn -j ACCEPT
# for strategies with incoming packets involved (autottl)
IPT_ADD_DEL $1 OUTPUT -p $2 --dport $3 -m conntrack --ctstate INVALID -j ACCEPT
if [ " $IPV " = 6 -a -n " $IP6_DEFRAG_DISABLE " ] ; then
# the only way to reliable disable ipv6 defrag. works only in 4.16+ kernels
IPT_ADD_DEL $1 OUTPUT -t raw -p $2 -m frag -j CT --notrack
elif [ " $IPV " = 4 ] ; then
# enable fragments
IPT_ADD_DEL $1 OUTPUT -f -j ACCEPT
fi
# enable everything generated by nfqws (works only in OUTPUT, not in FORWARD)
# raw table may not be present
IPT_ADD_DEL $1 OUTPUT -t raw -m mark --mark $DESYNC_MARK /$DESYNC_MARK -j CT --notrack
}
nft_scheme( )
{
# $1 - tcp/udp
# $2 - port
nft add table inet $NFT_TABLE
nft " add chain inet $NFT_TABLE postnat { type filter hook output priority 102; } "
nft " add rule inet $NFT_TABLE postnat meta nfproto ipv ${ IPV } $1 dport $2 mark and $DESYNC_MARK != $DESYNC_MARK queue num $QNUM "
# for strategies with incoming packets involved (autottl)
nft " add chain inet $NFT_TABLE prenat { type filter hook prerouting priority -102; } "
# enable everything generated by nfqws (works only in OUTPUT, not in FORWARD)
nft " add chain inet $NFT_TABLE predefrag { type filter hook output priority -402; } "
nft " add rule inet $NFT_TABLE predefrag meta nfproto ipv ${ IPV } mark and $DESYNC_MARK !=0 notrack "
}
pktws_ipt_prepare( )
{
# $1 - tcp/udp
# $2 - port
2022-02-10 22:30:50 +03:00
case " $FWTYPE " in
iptables)
2024-03-15 14:49:59 +03:00
ipt_scheme 1 $1 $2
2021-12-12 16:03:07 +03:00
; ;
2022-02-10 22:30:50 +03:00
nftables)
2024-03-15 14:49:59 +03:00
nft_scheme $1 $2
2022-02-10 22:30:50 +03:00
; ;
ipfw)
2024-03-14 17:51:41 +03:00
# disable PF to avoid interferences
pf_is_avail && pfctl -qd
2024-03-15 14:49:59 +03:00
IPFW_ADD divert $IPFW_DIVERT_PORT $1 from me to any $2 proto ip${ IPV } out not diverted not sockarg
2021-12-12 16:03:07 +03:00
; ;
2024-03-11 19:00:22 +03:00
opf)
2024-03-15 14:49:59 +03:00
opf_prepare_dvtws $1 $2
2024-03-11 19:00:22 +03:00
; ;
2021-12-12 16:03:07 +03:00
esac
2021-12-08 15:20:44 +03:00
}
2024-03-15 14:49:59 +03:00
pktws_ipt_unprepare( )
2021-12-08 15:20:44 +03:00
{
2024-03-15 14:49:59 +03:00
# $1 - tcp/udp
# $2 - port
2022-02-10 22:30:50 +03:00
case " $FWTYPE " in
iptables)
2024-03-15 14:49:59 +03:00
ipt_scheme 0 $1 $2
2021-12-12 16:03:07 +03:00
; ;
2022-02-10 22:30:50 +03:00
nftables)
nft delete table inet $NFT_TABLE 2>/dev/null
; ;
ipfw)
2021-12-12 16:03:07 +03:00
IPFW_DEL
2024-03-14 17:51:41 +03:00
pf_is_avail && pf_restore
2021-12-12 16:03:07 +03:00
; ;
2024-03-11 19:00:22 +03:00
opf)
pf_restore
; ;
2021-12-12 16:03:07 +03:00
esac
2021-12-08 15:20:44 +03:00
}
2024-03-15 14:49:59 +03:00
pktws_ipt_prepare_tcp( )
2024-03-14 23:59:58 +03:00
{
# $1 - port
2024-03-15 14:49:59 +03:00
pktws_ipt_prepare tcp $1
2024-03-14 23:59:58 +03:00
case " $FWTYPE " in
iptables)
2024-03-15 14:49:59 +03:00
# for autottl
IPT INPUT -t mangle -p tcp --sport $1 -m connbytes --connbytes-dir= original --connbytes-mode= packets --connbytes 1:1 -j NFQUEUE --queue-num $QNUM
2024-03-14 23:59:58 +03:00
; ;
nftables)
2024-03-15 14:49:59 +03:00
# for autottl
nft " add rule inet $NFT_TABLE prenat meta nfproto ipv ${ IPV } tcp sport $1 ct original packets 1 queue num $QNUM "
2024-03-14 23:59:58 +03:00
; ;
ipfw)
2024-03-15 14:49:59 +03:00
# for autottl mode
IPFW_ADD divert $IPFW_DIVERT_PORT tcp from any $1 to me proto ip${ IPV } tcpflags syn,ack in not diverted not sockarg
2024-03-14 23:59:58 +03:00
; ;
esac
}
2024-03-15 14:49:59 +03:00
pktws_ipt_unprepare_tcp( )
2024-03-14 23:59:58 +03:00
{
# $1 - port
2024-03-15 14:49:59 +03:00
pktws_ipt_unprepare tcp $1
2024-03-14 23:59:58 +03:00
case " $FWTYPE " in
iptables)
2024-03-15 14:49:59 +03:00
IPT_DEL INPUT -t mangle -p tcp --sport $1 -m connbytes --connbytes-dir= original --connbytes-mode= packets --connbytes 1:1 -j NFQUEUE --queue-num $QNUM
2024-03-14 23:59:58 +03:00
; ;
esac
}
2024-03-15 14:49:59 +03:00
pktws_ipt_prepare_udp( )
{
# $1 - port
pktws_ipt_prepare udp $1
}
pktws_ipt_unprepare_udp( )
{
# $1 - port
pktws_ipt_unprepare udp $1
}
2024-03-14 23:59:58 +03:00
2021-12-12 16:03:07 +03:00
pktws_start( )
{
case " $UNAME " in
Linux)
2023-04-15 18:48:48 +03:00
" $NFQWS " --uid $TPWS_UID :$TPWS_GID --dpi-desync-fwmark= $DESYNC_MARK --qnum= $QNUM " $@ " >/dev/null &
2021-12-12 16:03:07 +03:00
; ;
2024-03-11 19:00:22 +03:00
FreeBSD| OpenBSD)
2021-12-12 16:03:07 +03:00
" $DVTWS " --port= $IPFW_DIVERT_PORT " $@ " >/dev/null &
; ;
esac
2021-12-09 20:13:38 +03:00
PID = $!
2023-10-31 12:21:19 +03:00
# give some time to initialize
minsleep
2021-12-08 15:20:44 +03:00
}
2021-12-09 20:05:15 +03:00
tpws_start( )
{
2024-03-14 16:44:08 +03:00
" $TPWS " --uid $TPWS_UID :$TPWS_GID --socks --bind-addr= 127.0.0.1 --port= $SOCKS_PORT " $@ " >/dev/null &
2021-12-09 20:13:38 +03:00
PID = $!
# give some time to initialize
2023-10-31 11:47:35 +03:00
minsleep
2021-12-09 20:05:15 +03:00
}
2021-12-10 11:18:25 +03:00
ws_kill( )
{
[ -z " $PID " ] || {
killwait -9 $PID 2>/dev/null
PID =
}
}
2021-12-08 15:20:44 +03:00
curl_test( )
{
# $1 - test function
# $2 - domain
2021-12-22 12:31:45 +03:00
local code = 0 n = 0
while [ $n -lt $REPEATS ] ; do
n = $(( $n + 1 ))
2022-02-15 20:51:45 +03:00
[ $REPEATS -gt 1 ] && printf " [attempt $n ] "
2022-01-04 12:59:12 +03:00
$1 " $IPV " $2 && {
2021-12-22 12:31:45 +03:00
[ $REPEATS -gt 1 ] && echo 'AVAILABLE'
continue
}
code = $?
done
2021-12-08 15:20:44 +03:00
if [ $code = 254 ] ; then
2021-12-22 12:31:45 +03:00
echo "UNAVAILABLE"
elif [ $code = 0 ] ; then
echo '!!!!! AVAILABLE !!!!!'
2021-12-08 15:20:44 +03:00
else
2021-12-22 12:31:45 +03:00
echo " UNAVAILABLE code= $code "
2021-12-08 15:20:44 +03:00
fi
return $code
}
2021-12-09 20:05:15 +03:00
ws_curl_test( )
2021-12-08 15:20:44 +03:00
{
2021-12-09 20:05:15 +03:00
# $1 - ws start function
# $2 - test function
# $3 - domain
# $4,$5,$6, ... - ws params
2021-12-09 20:13:38 +03:00
local code ws_start = $1 testf = $2 dom = $3
2021-12-09 20:05:15 +03:00
shift
2021-12-08 15:20:44 +03:00
shift
shift
2021-12-09 20:05:15 +03:00
$ws_start " $@ "
2021-12-08 15:20:44 +03:00
curl_test $testf $dom
code = $?
2021-12-10 11:18:25 +03:00
ws_kill
2021-12-08 15:20:44 +03:00
return $code
}
2021-12-09 20:05:15 +03:00
tpws_curl_test( )
{
# $1 - test function
# $2 - domain
# $3,$4,$5, ... - tpws params
echo - checking tpws $3 $4 $5 $6 $7 $8 $9
2024-03-14 16:44:08 +03:00
local ALL_PROXY = " socks5://127.0.0.1: $SOCKS_PORT "
2021-12-09 20:05:15 +03:00
ws_curl_test tpws_start " $@ "
}
2021-12-12 16:03:07 +03:00
pktws_curl_test( )
2021-12-09 20:05:15 +03:00
{
# $1 - test function
# $2 - domain
2021-12-12 16:03:07 +03:00
# $3,$4,$5, ... - nfqws/dvtws params
echo - checking $PKTWSD $3 $4 $5 $6 $7 $8 $9
ws_curl_test pktws_start " $@ "
2021-12-09 20:05:15 +03:00
}
2021-12-23 19:12:09 +03:00
xxxws_curl_test_update( )
{
# $1 - xxx_curl_test function
# $2 - test function
# $3 - domain
# $4,$5,$6, ... - nfqws/dvtws params
local code xxxf = $1 testf = $2 dom = $3
shift
shift
shift
$xxxf $testf $dom " $@ "
code = $?
[ $code = 0 ] && strategy = " ${ strategy :- $@ } "
return $code
}
pktws_curl_test_update( )
{
xxxws_curl_test_update pktws_curl_test " $@ "
}
tpws_curl_test_update( )
{
xxxws_curl_test_update tpws_curl_test " $@ "
}
2021-12-25 12:22:47 +03:00
report_append( )
{
NREPORT = ${ NREPORT :- 0 }
eval REPORT_${ NREPORT } = \" $@ \"
NREPORT = $(( $NREPORT + 1 ))
}
report_print( )
{
local n = 0 s
NREPORT = ${ NREPORT :- 0 }
while [ $n -lt $NREPORT ] ; do
eval s = \" \$ { REPORT_$n } \"
echo $s
n = $(( $n + 1 ))
done
}
2021-12-24 19:24:01 +03:00
report_strategy( )
{
2021-12-25 12:22:47 +03:00
# $1 - test function
# $2 - domain
# $3 - daemon
2021-12-24 19:24:01 +03:00
echo
if [ -n " $strategy " ] ; then
2021-12-25 12:22:47 +03:00
echo " !!!!! $1 : working strategy found for ipv ${ IPV } $2 : $3 $strategy !!!!! "
2021-12-24 19:24:01 +03:00
echo
2021-12-25 12:22:47 +03:00
report_append " ipv ${ IPV } $2 $1 : $3 $strategy "
2021-12-24 19:24:01 +03:00
return 0
else
2021-12-25 12:22:47 +03:00
echo " $1 : $3 strategy for ipv ${ IPV } $2 not found "
2021-12-24 19:24:01 +03:00
echo
2021-12-25 12:22:47 +03:00
report_append " ipv ${ IPV } $2 $1 : $3 not working "
2021-12-24 19:24:01 +03:00
return 1
fi
}
2024-02-08 16:05:43 +03:00
test_has_split( )
{
contains " $1 " split || contains " $1 " disorder
}
2024-03-02 17:53:37 +03:00
warn_fool( )
2024-02-08 16:05:43 +03:00
{
2024-03-02 17:53:37 +03:00
case " $1 " in
md5sig) echo 'WARNING ! although md5sig fooling worked it will not work on all sites. it typically works only on linux servers.' ; ;
2024-03-05 17:31:43 +03:00
datanoack) echo 'WARNING ! although datanoack fooling worked it may break NAT and may only work with external IP. Additionally it may require nftables to work correctly.' ; ;
2024-03-02 17:53:37 +03:00
esac
2024-02-08 16:05:43 +03:00
}
2024-03-14 23:59:58 +03:00
pktws_check_domain_http_bypass( )
2021-12-08 15:20:44 +03:00
{
# $1 - test function
2021-12-09 16:38:02 +03:00
# $2 - encrypted test : 1/0
# $3 - domain
2024-03-02 22:31:02 +03:00
local strategy tests = 'fake' ret ok ttls s f e desync pos fooling frag sec = " $2 " delta
2021-12-08 15:20:44 +03:00
2021-12-09 16:38:02 +03:00
[ " $sec " = 0 ] && {
2021-12-09 20:05:15 +03:00
for s in '--hostcase' '--hostspell=hoSt' '--hostnospace' '--domcase' ; do
2021-12-23 19:12:09 +03:00
pktws_curl_test_update $1 $3 $s
2021-12-09 16:54:12 +03:00
done
2021-12-09 16:38:02 +03:00
}
2021-12-08 15:20:44 +03:00
2021-12-09 16:38:02 +03:00
s = "--dpi-desync=split2"
2023-04-13 14:01:37 +03:00
ok = 0
2022-02-09 10:16:28 +03:00
pktws_curl_test_update $1 $3 $s
2023-04-13 14:01:37 +03:00
ret = $?
[ " $ret " = 0 ] && ok = 1
[ " $ret " != 0 -o " $FORCE " = 1 ] && {
2021-12-23 19:12:09 +03:00
[ " $sec " = 0 ] && pktws_curl_test_update $1 $3 $s --hostcase
2021-12-22 11:21:47 +03:00
for pos in 1 3 4 5 10 50 100; do
2021-12-09 20:05:15 +03:00
s = " --dpi-desync=split2 --dpi-desync-split-pos= $pos "
2021-12-23 19:12:09 +03:00
if pktws_curl_test_update $1 $3 $s ; then
2023-04-13 14:01:37 +03:00
ok = 1
2021-12-09 20:05:15 +03:00
break
2021-12-13 22:41:12 +03:00
elif [ " $sec " = 0 ] ; then
2021-12-23 19:12:09 +03:00
pktws_curl_test_update $1 $3 $s --hostcase
2021-12-09 20:05:15 +03:00
fi
done
2021-12-23 19:12:09 +03:00
}
2024-02-08 16:05:43 +03:00
[ " $ok " = 1 -a " $FORCE " != 1 ] || tests = " $tests split fake,split2 fake,split "
2021-12-09 16:38:02 +03:00
2022-02-09 10:06:01 +03:00
pktws_curl_test_update $1 $3 --dpi-desync= disorder2
2024-02-08 16:05:43 +03:00
ret = $?
[ " $ret " != 0 -o " $FORCE " = 1 ] && {
pktws_curl_test_update $1 $3 --dpi-desync= disorder2 --dpi-desync-split-pos= 1
ret = $?
}
[ " $ret " != 0 -o " $FORCE " = 1 ] && tests = " $tests disorder fake,disorder2 fake,disorder "
2021-12-08 15:20:44 +03:00
2021-12-08 16:30:21 +03:00
ttls = $( seq -s ' ' $MIN_TTL $MAX_TTL )
2021-12-13 17:01:50 +03:00
for e in '' '--wssize 1:6' ; do
[ -n " $e " ] && {
2021-12-23 19:12:09 +03:00
pktws_curl_test_update $1 $3 $e
2021-12-13 17:01:50 +03:00
for desync in split2 disorder2; do
2021-12-23 19:12:09 +03:00
pktws_curl_test_update $1 $3 --dpi-desync= $desync $e
2021-12-13 17:01:50 +03:00
done
}
for desync in $tests ; do
2021-12-23 19:12:09 +03:00
s = " --dpi-desync= $desync "
2021-12-09 16:38:02 +03:00
for ttl in $ttls ; do
2021-12-23 19:12:09 +03:00
pktws_curl_test_update $1 $3 $s --dpi-desync-ttl= $ttl $e && break
2024-02-08 16:05:43 +03:00
test_has_split $desync && pktws_curl_test_update $1 $3 $s --dpi-desync-split-pos= 1 --dpi-desync-ttl= $ttl $e && break
2021-12-09 16:38:02 +03:00
done
2024-03-05 17:31:43 +03:00
for delta in 1 2 3 4 5; do
2024-03-02 22:28:49 +03:00
pktws_curl_test_update $1 $3 $s --dpi-desync-ttl= 1 --dpi-desync-autottl= $delta $e || {
test_has_split $desync && pktws_curl_test_update $1 $3 $s --dpi-desync-split-pos= 1 --dpi-desync-ttl= 1 --dpi-desync-autottl= $delta $e
}
done
2024-03-11 19:00:22 +03:00
f =
[ " $UNAME " = "OpenBSD" ] || f = "badsum"
f = " $f badseq md5sig datanoack "
2022-02-01 20:35:52 +03:00
[ " $IPV " = 6 ] && f = " $f hopbyhop hopbyhop2 "
for fooling in $f ; do
2024-03-02 17:53:37 +03:00
pktws_curl_test_update $1 $3 $s --dpi-desync-fooling= $fooling $e && warn_fool $fooling
test_has_split $desync && pktws_curl_test_update $1 $3 $s --dpi-desync-split-pos= 1 --dpi-desync-fooling= $fooling $e && warn_fool $fooling
2021-12-13 17:01:50 +03:00
done
2021-12-09 16:50:31 +03:00
done
2022-02-02 15:18:35 +03:00
[ " $IPV " = 6 ] && {
2022-02-05 22:19:17 +03:00
f = "hopbyhop hopbyhop,split2 hopbyhop,disorder2 destopt destopt,split2 destopt,disorder2"
[ -n " $IP6_DEFRAG_DISABLE " ] && f = " $f ipfrag1 ipfrag1,split2 ipfrag1,disorder2 "
for desync in $f ; do
2022-02-02 15:18:35 +03:00
pktws_curl_test_update $1 $3 --dpi-desync= $desync $e
2024-02-08 16:05:43 +03:00
test_has_split $desync && pktws_curl_test_update $1 $3 --dpi-desync-split-pos= 1 --dpi-desync= $desync $e
2022-02-02 15:18:35 +03:00
done
}
2021-12-13 17:01:50 +03:00
# do not do wssize test for http. it's useless
[ " $sec " = 1 ] || break
2021-12-08 15:20:44 +03:00
done
2022-01-03 22:17:39 +03:00
2024-03-19 13:47:36 +03:00
pktws_curl_test_update $1 $3 --dpi-desync= syndata
2024-03-11 19:00:22 +03:00
# OpenBSD has checksum issues with fragmented packets
2024-03-15 18:01:53 +03:00
[ " $UNAME " != "OpenBSD" ] && [ " $IPV " = 4 -o -n " $IP6_DEFRAG_DISABLE " ] && {
for frag in 24 32 40 64 80 104; do
tests = "ipfrag2"
[ " $IPV " = 6 ] && tests = " $tests hopbyhop,ipfrag2 destopt,ipfrag2 "
for desync in $tests ; do
pktws_curl_test_update $1 $3 --dpi-desync= $desync --dpi-desync-ipfrag-pos-tcp= $frag
2022-02-02 15:18:35 +03:00
done
2024-03-15 18:01:53 +03:00
done
}
2022-01-03 22:17:39 +03:00
2021-12-25 12:22:47 +03:00
report_strategy $1 $3 $PKTWSD
2021-12-08 15:20:44 +03:00
}
2024-03-14 23:59:58 +03:00
pktws_check_domain_http3_bypass( )
{
# $1 - test function
# $2 - domain
local f desync frag tests
pktws_curl_test_update $1 $2 --dpi-desync= fake
2024-03-15 14:49:59 +03:00
2024-03-14 23:59:58 +03:00
[ " $IPV " = 6 ] && {
f = "hopbyhop destopt"
2024-03-15 14:49:59 +03:00
[ -n " $IP6_DEFRAG_DISABLE " ] && f = " $f ipfrag1 "
2024-03-14 23:59:58 +03:00
for desync in $f ; do
pktws_curl_test_update $1 $2 --dpi-desync= $desync
done
}
2024-03-15 18:01:53 +03:00
# OpenBSD has checksum issues with fragmented packets
[ " $UNAME " != "OpenBSD" ] && [ " $IPV " = 4 -o -n " $IP6_DEFRAG_DISABLE " ] && {
2024-03-15 14:49:59 +03:00
for frag in 8 16 24 32 40 64; do
tests = "ipfrag2"
[ " $IPV " = 6 ] && tests = " $tests hopbyhop,ipfrag2 destopt,ipfrag2 "
for desync in $tests ; do
pktws_curl_test_update $1 $2 --dpi-desync= $desync --dpi-desync-ipfrag-pos-udp= $frag
done
done
}
2024-03-14 23:59:58 +03:00
report_strategy $1 $2 $PKTWSD
}
tpws_check_domain_http_bypass( )
2021-12-09 20:05:15 +03:00
{
# $1 - test function
# $2 - encrypted test : 1/0
# $3 - domain
2023-07-03 15:28:42 +03:00
local s s2 pos strategy sec = " $2 "
2021-12-09 20:05:15 +03:00
if [ " $sec " = 0 ] ; then
2023-07-03 15:28:42 +03:00
for s in '--hostcase' '--hostspell=hoSt' '--hostdot' '--hosttab' '--hostnospace' '--methodspace' '--methodeol' '--unixeol' \
'--hostpad=1024' '--hostpad=2048' '--hostpad=4096' '--hostpad=8192' '--hostpad=16384' ; do
2021-12-23 19:12:09 +03:00
tpws_curl_test_update $1 $3 $s
2021-12-09 20:05:15 +03:00
done
2024-03-02 17:53:37 +03:00
for s2 in '' '--disorder' '--oob' ; do
2023-07-03 15:28:42 +03:00
for s in '--split-http-req=method' '--split-http-req=method --hostcase' '--split-http-req=host' '--split-http-req=host --hostcase' ; do
tpws_curl_test_update $1 $3 $s $s2
done
done
2021-12-09 20:05:15 +03:00
else
2024-03-02 17:53:37 +03:00
for s2 in '' '--disorder' '--oob' ; do
2023-07-03 15:28:42 +03:00
for pos in 1 2 3 4 5 10 50 100; do
s = " --split-pos= $pos "
tpws_curl_test_update $1 $3 $s $s2 && break
done
2021-12-09 20:05:15 +03:00
done
2024-03-02 17:53:37 +03:00
for s2 in '--tlsrec=sni' '--tlsrec=sni --split-pos=10' '--tlsrec=sni --split-pos=10 --disorder' '--tlsrec=sni --split-pos=10 --oob' ; do
2023-10-12 12:35:06 +03:00
tpws_curl_test_update $1 $3 $s2 && [ " $FORCE " != 1 ] && break
done
2021-12-09 20:05:15 +03:00
fi
2021-12-25 12:22:47 +03:00
report_strategy $1 $3 tpws
2021-12-09 20:05:15 +03:00
}
2021-12-08 15:20:44 +03:00
2024-03-14 23:59:58 +03:00
curl_has_reason_to_continue( )
{
# $1 - curl return code
for c in 1 2 3 4 6 27 ; do
[ $1 = $c ] && return 1
done
return 0
}
check_domain_http_tcp( )
2021-12-08 15:20:44 +03:00
{
# $1 - test function
# $2 - port
2021-12-09 16:38:02 +03:00
# $3 - encrypted test : 1/0
# $4 - domain
2021-12-08 15:20:44 +03:00
2022-01-11 00:46:32 +03:00
local code c
2021-12-08 21:23:06 +03:00
2021-12-08 15:20:44 +03:00
echo
2021-12-24 17:26:59 +03:00
echo \* $1 ipv$IPV $4
2021-12-08 15:20:44 +03:00
# in case was interrupted before
2024-03-14 23:59:58 +03:00
pktws_ipt_unprepare_tcp $2
2021-12-10 11:18:25 +03:00
ws_kill
2021-12-08 15:20:44 +03:00
echo "- checking without DPI bypass"
2021-12-25 12:22:47 +03:00
curl_test $1 $4 && {
report_append " ipv ${ IPV } $4 $1 : working without bypass "
2022-02-09 10:06:01 +03:00
[ " $FORCE " = 1 ] || return
2021-12-25 12:22:47 +03:00
}
2021-12-08 21:23:06 +03:00
code = $?
2024-03-14 23:59:58 +03:00
curl_has_reason_to_continue $code || {
report_append " ipv ${ IPV } $4 $1 : test aborted, no reason to continue. curl code $( curl_translate_code $code ) "
return
}
2021-12-08 15:20:44 +03:00
2022-04-06 10:57:14 +03:00
echo
2024-03-14 16:44:08 +03:00
if [ " $SKIP_TPWS " != 1 ] ; then
2024-03-14 23:59:58 +03:00
tpws_check_domain_http_bypass $1 $3 $4
2022-04-06 10:55:33 +03:00
fi
2021-12-09 20:05:15 +03:00
echo
2024-03-11 20:49:11 +03:00
[ " $SKIP_PKTWS " = 1 ] || {
echo preparing $PKTWSD redirection
2024-03-14 23:59:58 +03:00
pktws_ipt_prepare_tcp $2
pktws_check_domain_http_bypass $1 $3 $4
echo clearing $PKTWSD redirection
pktws_ipt_unprepare_tcp $2
}
}
check_domain_http_udp( )
{
# $1 - test function
# $2 - port
# $3 - domain
local code c
echo
echo \* $1 ipv$IPV $3
# in case was interrupted before
pktws_ipt_unprepare_udp $2
ws_kill
echo "- checking without DPI bypass"
curl_test $1 $3 && {
report_append " ipv ${ IPV } $3 $1 : working without bypass "
[ " $FORCE " = 1 ] || return
}
code = $?
curl_has_reason_to_continue $code || {
report_append " ipv ${ IPV } $3 $1 : test aborted, no reason to continue. curl code $( curl_translate_code $code ) "
return
}
echo
[ " $SKIP_PKTWS " = 1 ] || {
echo preparing $PKTWSD redirection
pktws_ipt_prepare_udp $2
2021-12-08 15:20:44 +03:00
2024-03-14 23:59:58 +03:00
pktws_check_domain_http3_bypass $1 $3
2021-12-08 15:20:44 +03:00
2024-03-11 20:49:11 +03:00
echo clearing $PKTWSD redirection
2024-03-14 23:59:58 +03:00
pktws_ipt_unprepare_udp $2
2024-03-11 20:49:11 +03:00
}
2021-12-08 15:20:44 +03:00
}
2024-03-14 23:59:58 +03:00
2021-12-08 15:20:44 +03:00
check_domain_http( )
{
# $1 - domain
2024-03-14 23:59:58 +03:00
check_domain_http_tcp curl_test_http 80 0 $1
2021-12-08 15:20:44 +03:00
}
2021-12-10 11:18:25 +03:00
check_domain_https_tls12( )
{
# $1 - domain
2024-03-14 23:59:58 +03:00
check_domain_http_tcp curl_test_https_tls12 443 1 $1
2021-12-10 11:18:25 +03:00
}
check_domain_https_tls13( )
2021-12-08 15:20:44 +03:00
{
# $1 - domain
2024-03-14 23:59:58 +03:00
check_domain_http_tcp curl_test_https_tls13 443 1 $1
}
check_domain_http3( )
{
# $1 - domain
check_domain_http_udp curl_test_http3 443 $1
2021-12-08 15:20:44 +03:00
}
2021-12-09 20:22:28 +03:00
configure_ip_version( )
{
if [ " $IPV " = 6 ] ; then
2021-12-09 20:24:41 +03:00
LOCALHOST = ::1
2022-02-10 22:30:50 +03:00
LOCALHOST_IPT = [ ${ LOCALHOST } ]
IPVV = 6
2021-12-09 20:22:28 +03:00
else
IPTABLES = iptables
LOCALHOST = 127.0.0.1
2022-02-10 22:30:50 +03:00
LOCALHOST_IPT = $LOCALHOST
IPVV =
2021-12-09 20:22:28 +03:00
fi
2022-02-10 22:30:50 +03:00
IPTABLES = ip${ IPVV } tables
2021-12-09 20:22:28 +03:00
}
2021-12-11 11:52:53 +03:00
configure_curl_opt( )
{
2023-03-26 12:52:30 +03:00
# wolfssl : --tlsv1.x mandates exact ssl version, tls-max not supported
# openssl : --tlsv1.x means "version equal or greater", tls-max supported
TLSMAX12 =
TLSMAX13 =
curl_supports_tlsmax && {
TLSMAX12 = "--tls-max 1.2"
TLSMAX13 = "--tls-max 1.3"
}
2021-12-11 11:52:53 +03:00
TLS13 =
curl_supports_tls13 && TLS13 = 1
2024-03-14 23:59:58 +03:00
HTTP3 =
curl_supports_http3 && HTTP3 = 1
2021-12-11 11:52:53 +03:00
}
2021-12-09 20:22:28 +03:00
2022-02-10 22:30:50 +03:00
linux_ipv6_defrag_can_be_disabled( )
{
2022-02-15 17:15:36 +03:00
linux_min_version 4 16
2022-02-10 22:30:50 +03:00
}
2022-02-09 10:43:18 +03:00
configure_defrag( )
2022-02-09 10:06:01 +03:00
{
2022-02-10 22:30:50 +03:00
IP6_DEFRAG_DISABLE =
[ " $IPVS " = 4 ] && return
[ " $UNAME " = "Linux" ] && {
linux_ipv6_defrag_can_be_disabled || {
echo "WARNING ! ipv6 defrag can only be effectively disabled in linux kernel 4.16+"
echo "WARNING ! ipv6 ipfrag tests are disabled"
echo
return
}
}
case " $FWTYPE " in
iptables)
if ipt6_has_raw ; then
if ipt6_has_frag; then
IP6_DEFRAG_DISABLE = 1
2022-02-09 10:06:01 +03:00
else
2022-02-10 22:30:50 +03:00
echo "WARNING ! ip6tables does not have '-m frag' module, ipv6 ipfrag tests are disabled"
2022-02-09 10:06:01 +03:00
echo
fi
2022-02-10 22:30:50 +03:00
else
echo "WARNING ! ip6tables raw table is not available, ipv6 ipfrag tests are disabled"
echo
fi
[ -n " $IP6_DEFRAG_DISABLE " ] && {
local ipexe = " $( readlink -f $( whichq ip6tables) ) "
2022-02-15 17:15:36 +03:00
if contains " $ipexe " nft; then
2022-02-10 22:30:50 +03:00
echo " WARNING ! ipv6 ipfrag tests may have no effect if ip6tables-nft is used. current ip6tables point to : $ipexe "
else
echo "WARNING ! ipv6 ipfrag tests may have no effect if ip6table_raw kernel module is not loaded with parameter : raw_before_defrag=1"
fi
echo
2022-02-09 10:06:01 +03:00
}
; ;
*)
IP6_DEFRAG_DISABLE = 1
; ;
esac
}
2021-12-08 15:20:44 +03:00
ask_params( )
{
echo
echo NOTE ! this test should be run with zapret or any other bypass software disabled, without VPN
2021-12-24 17:26:59 +03:00
echo
2024-03-14 16:44:08 +03:00
curl_supports_connect_to || {
echo "installed curl does not support --connect-to option. pls install at least curl 7.49"
echo "current curl version:"
curl --version
exitp 1
}
2021-12-08 15:20:44 +03:00
2021-12-24 17:26:59 +03:00
echo "specify domain(s) to test. multiple domains are space separated."
2022-02-15 20:51:45 +03:00
printf " domain(s) (default: $DOMAINS ) : "
2021-12-08 15:20:44 +03:00
local dom
read dom
2021-12-24 17:26:59 +03:00
[ -n " $dom " ] && DOMAINS = " $dom "
2021-12-08 15:20:44 +03:00
2022-02-15 20:51:45 +03:00
printf "ip protocol version(s) - 4, 6 or 46 for both (default: 4) : "
2021-12-24 17:26:59 +03:00
read IPVS
[ -n " $IPVS " ] || IPVS = 4
[ " $IPVS " = 4 -o " $IPVS " = 6 -o " $IPVS " = 46 ] || {
echo 'invalid ip version(s). should be 4, 6 or 46.'
2021-12-08 15:20:44 +03:00
exitp 1
}
2021-12-24 17:26:59 +03:00
[ " $IPVS " = 46 ] && IPVS = "4 6"
2021-12-11 11:52:53 +03:00
configure_curl_opt
2021-12-08 15:20:44 +03:00
ENABLE_HTTP = 1
2024-03-14 23:59:58 +03:00
echo
2021-12-08 15:20:44 +03:00
ask_yes_no_var ENABLE_HTTP "check http"
2021-12-10 11:18:25 +03:00
ENABLE_HTTPS_TLS12 = 1
2024-03-14 23:59:58 +03:00
echo
2021-12-10 11:18:25 +03:00
ask_yes_no_var ENABLE_HTTPS_TLS12 "check https tls 1.2"
ENABLE_HTTPS_TLS13 = 0
2021-12-10 15:26:05 +03:00
echo
2021-12-11 11:52:53 +03:00
if [ -n " $TLS13 " ] ; then
2021-12-10 11:18:25 +03:00
echo "TLS 1.3 is the new standard for encrypted communications over TCP"
2021-12-10 15:16:02 +03:00
echo "its the most important feature for DPI bypass is encrypted TLS ServerHello"
2021-12-10 11:18:25 +03:00
echo "more and more sites enable TLS 1.3 but still there're many sites with only TLS 1.2 support"
2021-12-10 11:22:42 +03:00
echo "with TLS 1.3 more DPI bypass strategies can work but they may not apply to all sites"
2021-12-10 11:18:25 +03:00
echo "if a strategy works with TLS 1.2 it will also work with TLS 1.3"
echo "if nothing works with TLS 1.2 this test may find TLS1.3 only strategies"
2021-12-24 19:13:23 +03:00
echo " make sure that $DOMAINS support TLS 1.3 otherwise all test will return an error "
2021-12-10 11:18:25 +03:00
ask_yes_no_var ENABLE_HTTPS_TLS13 "check https tls 1.3"
else
echo "installed curl version does not support TLS 1.3 . tests disabled."
fi
2021-12-08 15:20:44 +03:00
2024-03-14 23:59:58 +03:00
ENABLE_HTTP3 = 0
echo
if [ -n " $HTTP3 " ] ; then
ENABLE_HTTP3 = 1
ask_yes_no_var ENABLE_HTTP3 "check http3 QUIC"
else
echo "installed curl version does not support http3 QUIC. tests disabled."
fi
2021-12-08 15:20:44 +03:00
IGNORE_CA = 0
CURL_OPT =
2021-12-10 11:18:25 +03:00
[ $ENABLE_HTTPS_TLS13 = 1 -o $ENABLE_HTTPS_TLS12 = 1 ] && {
echo
2021-12-22 12:31:45 +03:00
echo "on limited systems like openwrt CA certificates might not be installed to preserve space"
echo "in such a case curl cannot verify server certificate and you should either install ca-bundle or disable verification"
echo "however disabling verification will break https check if ISP does MitM attack and substitutes server certificate"
2021-12-08 15:20:44 +03:00
ask_yes_no_var IGNORE_CA "do not verify server certificate"
[ " $IGNORE_CA " = 1 ] && CURL_OPT = -k
}
2021-12-22 12:31:45 +03:00
echo
echo "sometimes ISPs use multiple DPIs or load balancing. bypass strategies may work unstable."
2022-02-15 20:51:45 +03:00
printf "how many times to repeat each test (default: 1) : "
2021-12-22 12:31:45 +03:00
read REPEATS
REPEATS = $(( 0 + ${ REPEATS :- 1 } ))
[ " $REPEATS " = 0 ] && {
echo invalid repeat count
exitp 1
}
2021-12-13 17:01:50 +03:00
echo
2022-02-09 10:06:01 +03:00
FORCE = 0
ask_yes_no_var FORCE "do all tests despite of result ?"
2022-01-04 00:11:10 +03:00
2022-02-09 10:06:01 +03:00
echo
2022-02-09 10:43:18 +03:00
configure_defrag
2021-12-08 15:20:44 +03:00
}
pingtest( )
{
2024-03-11 19:00:22 +03:00
case " $UNAME " in
OpenBSD)
ping -c 1 -w 1 $1 >/dev/null
; ;
*)
ping -c 1 -W 1 $1 >/dev/null
; ;
esac
2021-12-08 15:20:44 +03:00
}
dnstest( )
{
# $1 - dns server. empty for system resolver
2021-12-12 16:03:07 +03:00
" $LOOKUP " w3.org $1 >/dev/null 2>/dev/null
2021-12-08 15:20:44 +03:00
}
find_working_public_dns( )
{
2022-01-11 00:46:32 +03:00
local dns
2021-12-08 15:20:44 +03:00
for dns in $DNSCHECK_DNS ; do
pingtest $dns && dnstest $dns && {
PUBDNS = $dns
return 0
}
done
return 1
}
2021-12-12 16:03:07 +03:00
lookup4( )
{
# $1 - domain
# $2 - DNS
case " $LOOKUP " in
nslookup)
nslookup $1 $2 | sed -n '/Name:/,$p' | grep ^Address | grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}'
; ;
host)
host -t A $1 $2 | grep "has address" | grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}'
; ;
esac
}
2021-12-08 15:20:44 +03:00
check_dns_spoof( )
{
# $1 - domain
# $2 - public DNS
2021-12-12 16:03:07 +03:00
echo $1 | " $MDIG " --family= 4 >" $DNSCHECK_DIG1 "
lookup4 $1 $2 >" $DNSCHECK_DIG2 "
2021-12-08 15:20:44 +03:00
# check whether system resolver returns anything other than public DNS
grep -qvFf " $DNSCHECK_DIG2 " " $DNSCHECK_DIG1 "
}
check_dns_cleanup( )
{
rm -f " $DNSCHECK_DIG1 " " $DNSCHECK_DIG2 " " $DNSCHECK_DIGS " 2>/dev/null
}
check_dns( )
{
2022-01-11 00:46:32 +03:00
local C1 C2 dom
2021-12-08 15:20:44 +03:00
echo \* checking DNS
[ -f " $DNSCHECK_DIGS " ] && rm -f " $DNSCHECK_DIGS "
dnstest || {
echo -- DNS is not working. It's either misconfigured or blocked or you don' t have inet access.
return 1
}
echo system DNS is working
if find_working_public_dns ; then
echo comparing system resolver to public DNS : $PUBDNS
for dom in $DNSCHECK_DOM ; do
if check_dns_spoof $dom $PUBDNS ; then
echo $dom : MISMATCH
echo -- system resolver :
cat " $DNSCHECK_DIG1 "
echo -- $PUBDNS :
cat " $DNSCHECK_DIG2 "
check_dns_cleanup
echo -- POSSIBLE DNS HIJACK DETECTED. ZAPRET WILL NOT HELP YOU IN CASE DNS IS SPOOFED !!!
echo -- DNS CHANGE OR DNSCRYPT MAY BE REQUIRED
return 1
else
echo $dom : OK
cat " $DNSCHECK_DIG1 " >>" $DNSCHECK_DIGS "
fi
done
else
echo no working public DNS was found. looks like public DNS blocked.
2021-12-12 16:03:07 +03:00
for dom in $DNSCHECK_DOM ; do echo $dom ; done | " $MDIG " --threads= 10 --family= 4 >" $DNSCHECK_DIGS "
2021-12-08 15:20:44 +03:00
fi
echo checking resolved IP uniqueness for : $DNSCHECK_DOM
echo censor\' s DNS can return equal result for multiple blocked domains.
C1 = $( wc -l <" $DNSCHECK_DIGS " )
C2 = $( sort -u " $DNSCHECK_DIGS " | wc -l)
[ " $C1 " -eq 0 ] &&
{
echo -- DNS is not working. It's either misconfigured or blocked or you don' t have inet access.
check_dns_cleanup
return 1
}
[ " $C1 " = " $C2 " ] ||
{
echo system dns resolver has returned equal IPs for some domains checked above \( $C1 total, $C2 unique\)
echo non-unique IPs :
sort " $DNSCHECK_DIGS " | uniq -d
echo -- POSSIBLE DNS HIJACK DETECTED. ZAPRET WILL NOT HELP YOU IN CASE DNS IS SPOOFED !!!
echo -- DNSCRYPT MAY BE REQUIRED
check_dns_cleanup
return 1
}
echo all resolved IPs are unique
echo -- DNS looks good
echo -- NOTE this check is Russia targeted. In your country other domains may be blocked.
check_dns_cleanup
return 0
}
2021-12-24 13:19:52 +03:00
unprepare_all( )
2021-12-08 15:20:44 +03:00
{
2021-12-24 13:21:08 +03:00
# make sure we are not in a middle state that impacts connectivity
2021-12-24 17:32:35 +03:00
rm -f " $HDRTEMP "
2021-12-09 20:22:28 +03:00
[ -n " $IPV " ] && {
2024-03-14 23:59:58 +03:00
pktws_ipt_unprepare_tcp 80
pktws_ipt_unprepare_tcp 443
pktws_ipt_unprepare_udp 443
2021-12-09 20:22:28 +03:00
}
2021-12-10 11:18:25 +03:00
ws_kill
2024-03-11 19:00:22 +03:00
cleanup
2021-12-24 13:19:52 +03:00
}
sigint( )
{
echo
echo terminating...
unprepare_all
2021-12-08 17:18:14 +03:00
exitp 1
2021-12-08 15:20:44 +03:00
}
2024-03-11 19:00:22 +03:00
sigint_cleanup( )
{
cleanup
exit 1
}
2021-12-24 13:19:52 +03:00
sigpipe( )
{
# must not write anything here to stdout
unprepare_all
exit 1
}
2021-12-08 15:20:44 +03:00
2023-10-31 11:47:35 +03:00
fsleep_setup
2022-03-27 18:58:47 +03:00
fix_sbin_path
2021-12-08 15:20:44 +03:00
check_system
require_root
2022-03-27 18:58:47 +03:00
check_prerequisites
2024-03-11 19:00:22 +03:00
trap sigint_cleanup INT
2021-12-08 15:20:44 +03:00
check_dns
2022-04-13 11:47:14 +03:00
check_virt
2021-12-08 15:20:44 +03:00
ask_params
2024-03-11 19:00:22 +03:00
trap - INT
2021-12-08 15:20:44 +03:00
2021-12-10 11:18:25 +03:00
PID =
2021-12-25 12:22:47 +03:00
NREPORT =
2021-12-24 13:19:52 +03:00
trap sigint INT
trap sigpipe PIPE
2021-12-24 17:26:59 +03:00
for dom in $DOMAINS ; do
for IPV in $IPVS ; do
configure_ip_version
[ " $ENABLE_HTTP " = 1 ] && check_domain_http $dom
[ " $ENABLE_HTTPS_TLS12 " = 1 ] && check_domain_https_tls12 $dom
[ " $ENABLE_HTTPS_TLS13 " = 1 ] && check_domain_https_tls13 $dom
2024-03-14 23:59:58 +03:00
[ " $ENABLE_HTTP3 " = 1 ] && check_domain_http3 $dom
2021-12-24 17:26:59 +03:00
done
done
2021-12-24 13:19:52 +03:00
trap - PIPE
trap - INT
2021-12-08 21:12:41 +03:00
2024-03-11 19:00:22 +03:00
cleanup
2021-12-25 12:22:47 +03:00
echo
echo \* SUMMARY
report_print
2021-12-08 21:12:41 +03:00
exitp 0