diff --git a/blockcheck.sh b/blockcheck.sh index f6b8719..699c561 100755 --- a/blockcheck.sh +++ b/blockcheck.sh @@ -58,6 +58,8 @@ DNSCHECK_DIG1=/tmp/dig1.txt DNSCHECK_DIG2=/tmp/dig2.txt DNSCHECK_DIGS=/tmp/digs.txt +IPSET_FILE=/tmp/blockcheck_ipset.txt + unset PF_STATUS PF_RULES_SAVE=/tmp/pf-zapret-save.conf @@ -130,19 +132,22 @@ opf_dvtws_anchor() { # $1 - tcp/udp # $2 - port - local family=inet + # $3 - ip list + local iplist family=inet [ "$IPV" = 6 ] && family=inet6 + make_comma_list iplist "$3" echo "set reassemble no" - [ "$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" + [ "$1" = tcp ] && echo "pass in quick $family proto $1 from {$iplist} port $2 flags SA/SA divert-packet port $IPFW_DIVERT_PORT no state" + echo "pass in quick $family proto $1 from {$iplist} port $2 no state" + echo "pass out quick $family proto $1 to {$iplist} port $2 divert-packet port $IPFW_DIVERT_PORT no state" echo "pass" } opf_prepare_dvtws() { # $1 - tcp/udp # $2 - port - opf_dvtws_anchor $1 $2 | pfctl -qf - + # $3 - ip list + opf_dvtws_anchor $1 $2 "$3" | pfctl -qf - pfctl -qe } @@ -700,13 +705,12 @@ curl_test_http3() curl_with_dig $1 $2 $QUIC_PORT -ISs -A "$USER_AGENT" --max-time $CURL_MAX_TIME_QUIC --http3-only $CURL_OPT "https://$2" -o /dev/null 2>&1 } -ipt_scheme() +ipt_aux_scheme() { # $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) @@ -722,13 +726,42 @@ ipt_scheme() # raw table may not be present IPT_ADD_DEL $1 OUTPUT -t raw -m mark --mark $DESYNC_MARK/$DESYNC_MARK -j CT --notrack } +ipt_scheme() +{ + # $1 - tcp/udp + # $2 - port + # $3 - ip list + + local ip + + $IPTABLES -t mangle -N blockcheck_output 2>/dev/null + $IPTABLES -t mangle -F blockcheck_output + IPT OUTPUT -t mangle -j blockcheck_output + + # prevent loop + $IPTABLES -t mangle -A blockcheck_output -m mark --mark $DESYNC_MARK/$DESYNC_MARK -j RETURN + $IPTABLES -t mangle -A blockcheck_output ! -p $1 -j RETURN + $IPTABLES -t mangle -A blockcheck_output -p $1 ! --dport $2 -j RETURN + + for ip in $3; do + $IPTABLES -t mangle -A blockcheck_output -d $ip -j NFQUEUE --queue-num $QNUM + done + + ipt_aux_scheme 1 $1 $2 +} nft_scheme() { # $1 - tcp/udp # $2 - port + # $3 - ip list + + local iplist ipver=$IPV + [ "$IPV" = 6 ] || ipver= + make_comma_list iplist $3 + 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" + 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" # 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) @@ -740,23 +773,33 @@ pktws_ipt_prepare() { # $1 - tcp/udp # $2 - port + # $3 - ip list + + local ip + case "$FWTYPE" in iptables) - ipt_scheme 1 $1 $2 + ipt_scheme $1 $2 "$3" ;; nftables) - nft_scheme $1 $2 + nft_scheme $1 $2 "$3" ;; ipfw) # disable PF to avoid interferences pf_is_avail && pfctl -qd - IPFW_ADD divert $IPFW_DIVERT_PORT $1 from me to any $2 proto ip${IPV} out not diverted not sockarg + 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 + done ;; opf) - opf_prepare_dvtws $1 $2 + opf_prepare_dvtws $1 $2 "$3" ;; windivert) WF="--wf-l3=ipv${IPV} --wf-${1}=$2" + rm -f "$IPSET_FILE" + for ip in $3; do + echo $ip >>"$IPSET_FILE" + done ;; esac @@ -765,9 +808,13 @@ pktws_ipt_unprepare() { # $1 - tcp/udp # $2 - port + case "$FWTYPE" in iptables) - ipt_scheme 0 $1 $2 + ipt_aux_scheme 0 $1 $2 + IPT_DEL OUTPUT -t mangle -j blockcheck_output + $IPTABLES -t mangle -F blockcheck_output 2>/dev/null + $IPTABLES -t mangle -X blockcheck_output 2>/dev/null ;; nftables) nft delete table inet $NFT_TABLE 2>/dev/null @@ -781,6 +828,7 @@ pktws_ipt_unprepare() ;; windivert) unset WF + rm -f "$IPSET_FILE" ;; esac } @@ -788,21 +836,37 @@ pktws_ipt_unprepare() pktws_ipt_prepare_tcp() { # $1 - port + # $2 - ip list - pktws_ipt_prepare tcp $1 + local ip iplist ipver + + pktws_ipt_prepare tcp $1 "$2" case "$FWTYPE" in iptables) # 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 + $IPTABLES -N blockcheck_input -t mangle 2>/dev/null + $IPTABLES -F blockcheck_input -t mangle 2>/dev/null + IPT INPUT -t mangle -j blockcheck_input + $IPTABLES -t mangle -A blockcheck_input ! -p tcp -j RETURN + $IPTABLES -t mangle -A blockcheck_input -p tcp ! --sport $1 -j RETURN + $IPTABLES -t mangle -A blockcheck_input -m connbytes --connbytes-dir=reply --connbytes-mode=packets ! --connbytes 1 -j RETURN + for ip in $2; do + $IPTABLES -A blockcheck_input -t mangle -s $ip -j NFQUEUE --queue-num $QNUM + done ;; nftables) + ipver=$IPV + [ "$IPV" = 6 ] || ipver= # for autottl - nft "add rule inet $NFT_TABLE prenat meta nfproto ipv${IPV} tcp sport $1 ct original packets 1 queue num $QNUM" + make_comma_list iplist $2 + nft "add rule inet $NFT_TABLE prenat meta nfproto ipv${IPV} tcp sport $1 ip${ipver} saddr {$iplist} ct original packets 1 queue num $QNUM" ;; ipfw) # 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 + 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 + done ;; esac } @@ -814,15 +878,18 @@ pktws_ipt_unprepare_tcp() case "$FWTYPE" in iptables) - 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 + IPT_DEL INPUT -t mangle -j blockcheck_input + $IPTABLES -t mangle -F blockcheck_input 2>/dev/null + $IPTABLES -t mangle -X blockcheck_input 2>/dev/null ;; esac } pktws_ipt_prepare_udp() { # $1 - port + # $2 - ip list - pktws_ipt_prepare udp $1 + pktws_ipt_prepare udp $1 "$2" } pktws_ipt_unprepare_udp() { @@ -841,7 +908,7 @@ pktws_start() "$DVTWS" --port=$IPFW_DIVERT_PORT "$@" >/dev/null & ;; CYGWIN) - "$WINWS" $WF "$@" >/dev/null & + "$WINWS" $WF --ipset="$IPSET_FILE" "$@" >/dev/null & ;; esac PID=$! @@ -1215,7 +1282,7 @@ pktws_check_domain_http3_bypass_() { # $1 - test function # $2 - domain - + local f desync frag tests rep for rep in '' 2 5 10 20; do @@ -1413,7 +1480,7 @@ check_domain_http_tcp() [ "$SKIP_PKTWS" = 1 ] || { echo echo preparing $PKTWSD redirection - pktws_ipt_prepare_tcp $2 + pktws_ipt_prepare_tcp $2 "$(mdig_resolve_all $IPV $4)" pktws_check_domain_http_bypass $1 $3 $4 @@ -1436,7 +1503,7 @@ check_domain_http_udp() [ "$SKIP_PKTWS" = 1 ] || { echo echo preparing $PKTWSD redirection - pktws_ipt_prepare_udp $2 + pktws_ipt_prepare_udp $2 "$(mdig_resolve_all $IPV $3)" pktws_check_domain_http3_bypass $1 $3 @@ -1756,7 +1823,7 @@ check_dns_cleanup() { rm -f "$DNSCHECK_DIG1" "$DNSCHECK_DIG2" "$DNSCHECK_DIGS" 2>/dev/null } -check_dns() +check_dns_() { local C1 C2 dom @@ -1799,8 +1866,8 @@ check_dns() for dom in $DNSCHECK_DOM; do echo $dom; done | "$MDIG" --threads=10 --family=4 >"$DNSCHECK_DIGS" fi - echo checking resolved IP uniqueness for : $DNSCHECK_DOM - echo censor\'s DNS can return equal result for multiple blocked domains. + 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 ] && @@ -1828,6 +1895,14 @@ check_dns() return 0 } +check_dns() +{ + local r + check_dns_ + r=$? + [ "$SECURE_DNS" = 1 ] && doh_find_working + return $r +} unprepare_all() { @@ -1860,6 +1935,7 @@ sigsilent() exit 1 } + fsleep_setup fix_sbin_path check_system @@ -1868,7 +1944,6 @@ check_already check_prerequisites trap sigint_cleanup INT check_dns -[ "$SECURE_DNS" = 1 ] && doh_find_working check_virt ask_params trap - INT