From c56e672600805fefc71f016dea616892584a3a09 Mon Sep 17 00:00:00 2001 From: bol-van Date: Fri, 15 Nov 2024 18:43:25 +0300 Subject: [PATCH] blockcheck: update for new strategies. nfqws check order reworked. --- blockcheck.sh | 283 ++++++++++++++++++++++++-------------------- common/base.sh | 13 +- common/installer.sh | 4 +- 3 files changed, 167 insertions(+), 133 deletions(-) diff --git a/blockcheck.sh b/blockcheck.sh index 9ee3184..c3e54fc 100755 --- a/blockcheck.sh +++ b/blockcheck.sh @@ -45,7 +45,6 @@ HTTP_PORT=${HTTP_PORT:-80} HTTPS_PORT=${HTTPS_PORT:-443} QUIC_PORT=${QUIC_PORT:-443} UNBLOCKED_DOM=${UNBLOCKED_DOM:-iana.org} -[ "$CURL_VERBOSE" = 1 ] && CURL_CMD=1 HDRTEMP=/tmp/zapret-hdr.txt @@ -792,7 +791,7 @@ pktws_ipt_prepare() # disable PF to avoid interferences pf_is_avail && pfctl -qd for ip in $3; do - IPFW_ADD divert $IPFW_DIVERT_PORT $1 from me to $ip $2 proto ip${IPV} out not diverted not sockarg + IPFW_ADD divert $IPFW_DIVERT_PORT $1 from me to $ip $2 proto ip${IPV} out not diverted done ;; opf) @@ -867,7 +866,7 @@ pktws_ipt_prepare_tcp() ;; ipfw) for ip in $2; do - IPFW_ADD divert $IPFW_DIVERT_PORT tcp from $ip $1 to me proto ip${IPV} tcpflags syn,ack in not diverted not sockarg + IPFW_ADD divert $IPFW_DIVERT_PORT tcp from $ip $1 to me proto ip${IPV} tcpflags syn,ack in not diverted done ;; esac @@ -994,7 +993,6 @@ ws_curl_test() # $2 - test function # $3 - domain # $4,$5,$6, ... - ws params - local code ws_start=$1 testf=$2 dom=$3 shift shift @@ -1088,7 +1086,7 @@ test_has_split() } test_has_fake() { - contains "$1" fake + [ "$1" = fake ] || starts_with "$1" fake, } warn_fool() { @@ -1105,25 +1103,34 @@ pktws_curl_test_update_vary() # $4 - desync mode # $5,$6,... - strategy - local testf=$1 sec=$2 domain=$3 desync=$4 zerofake split fake + local testf=$1 sec=$2 domain=$3 desync=$4 proto zerofake= splits= pos fake ret=1 shift; shift; shift; shift - zerofake=http - [ "$sec" = 0 ] || zerofake=tls - zerofake="--dpi-desync-fake-$zerofake=0x00000000" - + proto=http + [ "$sec" = 0 ] || proto=tls + test_has_fake $desync && zerofake="--dpi-desync-fake-$proto=0x00000000" + test_has_split $desync && { + splits="method+2 midsld" + [ "$sec" = 0 ] || splits="1 midsld 1,midsld" + } for fake in '' $zerofake ; do - for split in '' '--dpi-desync-split-pos=1' ; do - pktws_curl_test_update $testf $domain --dpi-desync=$desync "$@" $fake $split && return 0 - # split-pos=1 is meaningful for DPIs searching for 16 03 in TLS. no reason to apply to http - [ "$sec" = 1 ] || break - test_has_split $desync || break - done - test_has_fake $desync || break + if [ -n "$splits" ]; then + for pos in $splits ; do + pktws_curl_test_update $testf $domain --dpi-desync=$desync "$@" --dpi-desync-split-pos=$pos $fake && { + [ "$SCANLEVEL" = force ] || return 0 + ret=0 + } + done + else + pktws_curl_test_update $testf $domain --dpi-desync=$desync "$@" $fake && { + [ "$SCANLEVEL" = force ] || return 0 + ret=0 + } + fi done - return 1 + return $ret } pktws_check_domain_http_bypass_() @@ -1132,7 +1139,10 @@ pktws_check_domain_http_bypass_() # $2 - encrypted test : 0 = plain, 1 - encrypted with server reply risk, 2 - encrypted without server reply risk # $3 - domain - local tests='fake' ret ok ttls s f e desync pos fooling frag sec="$2" delta hostcase + local ok ttls s f f2 e desync pos fooling frag sec="$2" delta splits + local need_split need_disorder need_fakedsplit need_fakeddisorder need_fake need_wssize + local splits_http='method+2 midsld method+2,midsld' + local splits_tls='2 1 sniext+1 host+1 midsld 1,midsld 1,sniext+1,host+1,midsld-2,midsld,midsld+2,endhost-1' [ "$sec" = 0 ] && { for s in '--hostcase' '--hostspell=hoSt' '--hostnospace' '--domcase'; do @@ -1140,74 +1150,62 @@ pktws_check_domain_http_bypass_() done } - s="--dpi-desync=split2" - ok=0 - pktws_curl_test_update $1 $3 $s - ret=$? - [ "$ret" = 0 ] && { - [ "$SCANLEVEL" = quick ] && return - ok=1 - } - [ "$ret" != 0 -o "$SCANLEVEL" = force ] && { - if [ "$sec" = 0 ]; then - pktws_curl_test_update $1 $3 $s --hostcase && { - [ "$SCANLEVEL" = quick ] && return - ok=1 - } - for pos in method host; do - for hostcase in '' '--hostcase'; do - pktws_curl_test_update $1 $3 $s --dpi-desync-split-http-req=$pos $hostcase && { - [ "$SCANLEVEL" = quick ] && return - ok=1 - } - done - done - else - for pos in sni sniext; do - pktws_curl_test_update $1 $3 $s --dpi-desync-split-tls=$pos && { - [ "$SCANLEVEL" = quick ] && return - ok=1 - } - done - fi - for pos in 1 3 4 5 10 50; do - s="--dpi-desync=split2 --dpi-desync-split-pos=$pos" - if pktws_curl_test_update $1 $3 $s; then - [ "$SCANLEVEL" = quick ] && return - ok=1 - [ "$SCANLEVEL" = force ] || break - elif [ "$sec" = 0 ]; then - pktws_curl_test_update $1 $3 $s --hostcase && [ "$SCANLEVEL" = quick ] && return - fi - done - } - [ "$ok" = 1 -a "$SCANLEVEL" != force ] || tests="$tests split fake,split2 fake,split" - - pktws_curl_test_update $1 $3 --dpi-desync=disorder2 - ret=$? - [ "$ret" = 0 -a "$SCANLEVEL" = quick ] && return - [ "$ret" != 0 -o "$SCANLEVEL" = force ] && { - pktws_curl_test_update $1 $3 --dpi-desync=disorder2 --dpi-desync-split-pos=1 - ret=$? - [ "$ret" = 0 -a "$SCANLEVEL" = quick ] && return - } - [ "$ret" != 0 -o "$SCANLEVEL" = force ] && tests="$tests disorder fake,disorder2 fake,disorder" - ttls=$(seq -s ' ' $MIN_TTL $MAX_TTL) + need_wssize=1 for e in '' '--wssize 1:6'; do + need_split= + need_disorder= + [ -n "$e" ] && { pktws_curl_test_update $1 $3 $e && [ "$SCANLEVEL" = quick ] && return - for desync in split2 disorder2; do - pktws_curl_test_update_vary $1 $2 $3 $desync $e && [ "$SCANLEVEL" = quick ] && return - done } - for desync in $tests; do + + for desync in multisplit multidisorder; do + ok=0 + splits="$splits_http" + [ "$sec" = 0 ] || splits="$splits_tls" + for pos in $splits; do + pktws_curl_test_update $1 $3 --dpi-desync=$desync --dpi-desync-split-pos=$pos $e && { + [ "$SCANLEVEL" = quick ] && return + ok=1 + need_wssize=0 + [ "$SCANLEVEL" = force ] || break + } + done + [ "$ok" = 1 -a "$SCANLEVEL" != force ] || { + case $desync in + multisplit) + need_split=1 + ;; + multidisorder) + need_disorder=1 + ;; + esac + } + done + + need_fakedsplit=1 + need_fakeddisorder=1 + need_fake=1 + for desync in fake ${need_split:+fakedsplit fake,multisplit fake,fakedsplit} ${need_disorder:+fakeddisorder fake,multidisorder fake,fakeddisorder}; do + [ "$need_fake" = 0 ] && test_has_fake "$desync" && continue + [ "$need_fakedsplit" = 0 ] && contains "$desync" fakedsplit && continue + [ "$need_fakeddisorder" = 0 ] && contains "$desync" fakeddisorder && continue + ok=0 for ttl in $ttls; do pktws_curl_test_update_vary $1 $2 $3 $desync --dpi-desync-ttl=$ttl $e && { [ "$SCANLEVEL" = quick ] && return + ok=1 + need_wssize=0 break } done + # only skip tests if TTL succeeded. do not skip if TTL failed but fooling succeeded + [ $ok = 1 -a "$SCANLEVEL" != force ] && { + [ "$desync" = fake ] && need_fake=0 + [ "$desync" = fakedsplit ] && need_fakedsplit=0 + [ "$desync" = fakeddisorder ] && need_fakeddisorder=0 + } f= [ "$UNAME" = "OpenBSD" ] || f="badsum" f="$f badseq datanoack md5sig" @@ -1216,37 +1214,62 @@ pktws_check_domain_http_bypass_() pktws_curl_test_update_vary $1 $2 $3 $desync --dpi-desync-fooling=$fooling $e && { warn_fool $fooling [ "$SCANLEVEL" = quick ] && return + need_wssize=0 } done done + [ "$IPV" = 6 ] && { - f="hopbyhop hopbyhop,split2 hopbyhop,disorder2 destopt destopt,split2 destopt,disorder2" - [ -n "$IP6_DEFRAG_DISABLE" ] && f="$f ipfrag1 ipfrag1,split2 ipfrag1,disorder2" + f="hopbyhop ${need_split:+hopbyhop,multisplit} ${need_disorder:+hopbyhop,multidisorder} destopt ${need_split:+destopt,multisplit} ${need_disorder:+destopt,multidisorder}" + [ -n "$IP6_DEFRAG_DISABLE" ] && f="$f ipfrag1 ${need_split:+ ipfrag1,multisplit} ${need_disorder:+ ipfrag1,multidisorder}" for desync in $f; do - pktws_curl_test_update_vary $1 $2 $3 $desync $e && [ "$SCANLEVEL" = quick ] && return + pktws_curl_test_update_vary $1 $2 $3 $desync $e && { + [ "$SCANLEVEL" = quick ] && return + need_wssize=0 + } done } - for desync in split2 disorder2; do - s="--dpi-desync=$desync" + [ "$need_split" = 1 ] && { + f="method+2 midsld method+2,midsld" + [ "$sec" = 0 ] || f="1 midsld sniext+1 1,midsld" + for pos in $f; do + pktws_curl_test_update $1 $3 --dpi-desync=multisplit --dpi-desync-split-pos=$pos --dpi-desync-split-seqovl=1 $e && { + [ "$SCANLEVEL" = quick ] && return + need_wssize=0 + } + done + [ "$sec" != 0 ] && pktws_curl_test_update $1 $3 --dpi-desync=multisplit --dpi-desync-split-pos=2 --dpi-desync-split-seqovl=336 --dpi-desync-split-seqovl-pattern="$ZAPRET_BASE/files/fake/tls_clienthello_iana_org.bin" $e && [ "$SCANLEVEL" = quick ] && return + } + [ "$need_disorder" = 1 ] && { if [ "$sec" = 0 ]; then - for pos in method host; do - pktws_curl_test_update $1 $3 $s --dpi-desync-split-seqovl=1 --dpi-desync-split-http-req=$pos $e && [ "$SCANLEVEL" = quick ] && return + for pos in 'method+1 method+2' 'midsld-1 midsld' 'method+1 method+2,midsld'; do + f="$(extract_arg 1 $pos)" + f2="$(extract_arg 2 $pos)" + pktws_curl_test_update $1 $3 --dpi-desync=multidisorder --dpi-desync-split-pos=$f2 --dpi-desync-split-seqovl=$f $e && { + [ "$SCANLEVEL" = quick ] && return + need_wssize=0 + } done else - for pos in sni sniext; do - pktws_curl_test_update $1 $3 $s --dpi-desync-split-seqovl=1 --dpi-desync-split-tls=$pos $e && [ "$SCANLEVEL" = quick ] && return + for pos in '1 2' 'sniext sniext+1' 'midsld-1 midsld' '1 2,midsld'; do + f=$(extract_arg 1 $pos) + f2=$(extract_arg 2 $pos) + pktws_curl_test_update $1 $3 --dpi-desync=multidisorder --dpi-desync-split-pos=$f2 --dpi-desync-split-seqovl=$f $e && { + [ "$SCANLEVEL" = quick ] && return + need_wssize=0 + } done fi - for pos in 2 3 4 5 10 50; do - pktws_curl_test_update $1 $3 $s --dpi-desync-split-seqovl=$(($pos - 1)) --dpi-desync-split-pos=$pos $e && [ "$SCANLEVEL" = quick ] && return - done - [ "$sec" != 0 -a $desync = split2 ] && { - pktws_curl_test_update $1 $3 $s --dpi-desync-split-seqovl=336 --dpi-desync-split-seqovl-pattern="$ZAPRET_BASE/files/fake/tls_clienthello_iana_org.bin" $e && [ "$SCANLEVEL" = quick ] && return - } - done + } - for desync in $tests; do + need_fakedsplit=1 + need_fakeddisorder=1 + need_fake=1 + for desync in fake ${need_split:+fakedsplit fake,multisplit fake,fakedsplit} ${need_disorder:+fakeddisorder fake,multidisorder fake,fakeddisorder}; do + [ "$need_fake" = 0 ] && test_has_fake "$desync" && continue + [ "$need_fakedsplit" = 0 ] && contains "$desync" fakedsplit && continue + [ "$need_fakeddisorder" = 0 ] && contains "$desync" fakeddisorder && continue ok=0 for delta in 1 2 3 4 5; do pktws_curl_test_update_vary $1 $2 $3 $desync --dpi-desync-ttl=1 --dpi-desync-autottl=$delta $e && ok=1 @@ -1256,18 +1279,25 @@ pktws_check_domain_http_bypass_() echo "WARNING ! although autottl worked it requires testing on multiple domains to find out reliable delta" echo "WARNING ! if a reliable delta cannot be found it's a good idea not to use autottl" [ "$SCANLEVEL" = quick ] && return + need_wssize=0 + [ "$SCANLEVEL" = force ] || { + [ "$desync" = fake ] && need_fake=0 + [ "$desync" = fakedsplit ] && need_fakedsplit=0 + [ "$desync" = fakeddisorder ] && need_fakeddisorder=0 + } } done s="http_iana_org.bin" [ "$sec" = 0 ] || s="tls_clienthello_iana_org.bin" - for desync in syndata syndata,split2 syndata,disorder2 ; do + for desync in syndata ${need_split:+syndata,multisplit} ${need_disorder:+syndata,multidisorder} ; do pktws_curl_test_update_vary $1 $2 $3 $desync $e && [ "$SCANLEVEL" = quick ] && return pktws_curl_test_update_vary $1 $2 $3 $desync --dpi-desync-fake-syndata="$ZAPRET_BASE/files/fake/$s" $e && [ "$SCANLEVEL" = quick ] && return done # do not do wssize test for http and TLS 1.3. it's useless [ "$sec" = 1 ] || break + [ "$SCANLEVEL" = force -o "$need_wssize" = 1 ] || break done } pktws_check_domain_http_bypass() @@ -1338,15 +1368,28 @@ tpws_check_domain_http_bypass_() # $2 - encrypted test : 0 = plain, 1 - encrypted with server reply risk, 2 - encrypted without server reply risk # $3 - domain - local s mss s2 s3 pos sec="$2" + local s mss s2 s3 oobdis pos sec="$2" + local splits_tls='2 1 sniext+1 host+1 midsld 1,midsld 1,sniext+1,host+1,midsld,endhost-1' + local splits_http='method+2 midsld method+2,midsld' + + # simulteneous oob and disorder works properly only in linux. other systems retransmit oob byte without URG tcp flag and poison tcp stream. + [ "$UNAME" = Linux ] && oobdis='--oob --disorder' if [ "$sec" = 0 ]; then - for s in '--hostcase' '--hostspell=hoSt' '--hostdot' '--hosttab' '--hostnospace' '--domcase' \ - '--hostpad=1024' '--hostpad=2048' '--hostpad=4096' '--hostpad=8192' '--hostpad=16384' ; do + for s in '--hostcase' '--hostspell=hoSt' '--hostdot' '--hosttab' '--hostnospace' '--domcase' ; do tpws_curl_test_update $1 $3 $s && [ "$SCANLEVEL" = quick ] && return done - for s2 in '' '--oob' '--disorder' '--oob --disorder'; do - 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 && [ "$SCANLEVEL" = quick ] && return + for s in 1024 2048 4096 8192 16384 ; do + tpws_curl_test_update $1 $3 --hostpad=$s && [ "$SCANLEVEL" != force ] && { + [ "$SCANLEVEL" = quick ] && return + break + } + done + for s2 in '' '--hostcase' '--oob' '--disorder' ${oobdis:+"$oobdis"}; do + for s in $splits_http ; do + tpws_curl_test_update $1 $3 --split-pos=$s $s2 && [ "$SCANLEVEL" != force ] && { + [ "$SCANLEVEL" = quick ] && return + break + } done done for s in '--methodspace' '--unixeol' '--methodeol'; do @@ -1355,30 +1398,21 @@ tpws_check_domain_http_bypass_() else for mss in '' 88; do s3=${mss:+--mss=$mss} - for s2 in '' '--oob' '--disorder' '--oob --disorder'; do - for pos in sni sniext; do - s="--split-tls=$pos" - tpws_curl_test_update $1 $3 $s $s2 $s3 && warn_mss $s3 && [ "$SCANLEVEL" != force ] && { - [ "$SCANLEVEL" = quick ] && return - break - } - done - for pos in 1 2 3 4 5 10 50; do - s="--split-pos=$pos" - tpws_curl_test_update $1 $3 $s $s2 $s3 && warn_mss $s3 && [ "$SCANLEVEL" != force ] && { + for s2 in '' '--oob' '--disorder' ${oobdis:+"$oobdis"}; do + for pos in $splits_tls; do + tpws_curl_test_update $1 $3 --split-pos=$pos $s2 $s3 && warn_mss $s3 && [ "$SCANLEVEL" != force ] && { [ "$SCANLEVEL" = quick ] && return break } done done - for s2 in '--tlsrec=sni' '--tlsrec=sni --split-tls=sni' '--tlsrec=sni --split-tls=sni --oob' \ - '--tlsrec=sni --split-tls=sni --disorder' '--tlsrec=sni --split-tls=sni --oob --disorder' \ - '--tlsrec=sni --split-pos=1' '--tlsrec=sni --split-pos=1 --oob' '--tlsrec=sni --split-pos=1 --disorder' \ - '--tlsrec=sni --split-pos=1 --oob --disorder'; do - tpws_curl_test_update $1 $3 $s2 $s3 && warn_mss $s3 && [ "$SCANLEVEL" != force ] && { - [ "$SCANLEVEL" = quick ] && return - break - } + for s in '' '--oob' '--disorder' ${oobdis:+"$oobdis"}; do + for s2 in '--tlsrec=midsld' '--tlsrec=sniext+1 --split-pos=midsld' '--tlsrec=sniext+1 --split-pos=1,midsld' ; do + tpws_curl_test_update $1 $3 $s2 $s $s3 && warn_mss $s3 && [ "$SCANLEVEL" != force ] && { + [ "$SCANLEVEL" = quick ] && return + break + } + done done # only linux supports mss [ "$UNAME" = Linux -a "$sec" = 1 ] || break @@ -1682,17 +1716,6 @@ ask_params() echo "installed curl version does not support http3 QUIC. tests disabled." fi - IGNORE_CA=0 - CURL_OPT= - [ $ENABLE_HTTPS_TLS13 = 1 -o $ENABLE_HTTPS_TLS12 = 1 ] && { - echo - 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" - ask_yes_no_var IGNORE_CA "do not verify server certificate" - [ "$IGNORE_CA" = 1 ] && CURL_OPT=-k - } - echo echo "sometimes ISPs use multiple DPIs or load balancing. bypass strategies may work unstable." printf "how many times to repeat each test (default: 1) : " diff --git a/common/base.sh b/common/base.sh index 8d466cc..c8e4be9 100644 --- a/common/base.sh +++ b/common/base.sh @@ -60,11 +60,22 @@ starts_with() esac return 1 } +extract_arg() +{ + # $1 - arg number + # $2,$3,... - args + local n=$1 + while [ -n "$1" ]; do + shift + [ $n -eq 1 ] && { echo "$1"; return 0; } + n=$(($n-1)) + done + return 1 +} find_str_in_list() { # $1 - string # $2 - space separated values - local v [ -n "$1" ] && { for v in $2; do diff --git a/common/installer.sh b/common/installer.sh index 2f3a3b6..9948cd2 100644 --- a/common/installer.sh +++ b/common/installer.sh @@ -221,7 +221,7 @@ check_system() else echo system is not either systemd, openrc or openwrt based echo easy installer can set up config settings but can\'t configure auto start - echo you have to do it manually. check readme.txt for manual setup info. + echo you have to do it manually. check readme.md for manual setup info. if [ -n "$1" ] || ask_yes_no N "do you want to continue"; then SYSTEM=linux else @@ -232,7 +232,7 @@ check_system() elif [ "$UNAME" = "Darwin" ]; then SYSTEM=macos else - echo easy installer only supports Linux and MacOS. check readme.txt for supported systems and manual setup info. + echo easy installer only supports Linux and MacOS. check readme.md for supported systems and manual setup info. exitp 5 fi echo system is based on $SYSTEM