mirror of https://github.com/bol-van/zapret/
3 changed files with 458 additions and 4 deletions
@ -0,0 +1,452 @@ |
|||||
|
#!/bin/sh |
||||
|
|
||||
|
EXEDIR="$(dirname "$0")" |
||||
|
EXEDIR="$(cd "$EXEDIR"; pwd)" |
||||
|
ZAPRET_BASE="$EXEDIR" |
||||
|
|
||||
|
[ -n "$QNUM" ] || QNUM=59780 |
||||
|
[ -n "$NFQWS" ] || NFQWS="$ZAPRET_BASE/nfq/nfqws" |
||||
|
[ -n "$MDIG" ] || MDIG="$ZAPRET_BASE/mdig/mdig" |
||||
|
[ -n "$DESYNC_MARK" ] || DESYNC_MARK=0x40000000 |
||||
|
DOMAIN=rutracker.org |
||||
|
CURL_MAX_TIME=5 |
||||
|
MIN_TTL=1 |
||||
|
MAX_TTL=12 |
||||
|
HDRTEMP=/tmp/zapret-hdr.txt |
||||
|
ECHON="echo -n" |
||||
|
|
||||
|
DNSCHECK_DNS="8.8.8.8 1.1.1.1 77.88.8.8" |
||||
|
DNSCHECK_DOM="pornhub.com putinhuylo.com rutracker.org nnmclub.to protonmail.com" |
||||
|
DNSCHECK_DIG1=/tmp/dig1.txt |
||||
|
DNSCHECK_DIG2=/tmp/dig2.txt |
||||
|
DNSCHECK_DIGS=/tmp/digs.txt |
||||
|
|
||||
|
|
||||
|
exists() |
||||
|
{ |
||||
|
which $1 >/dev/null 2>/dev/null |
||||
|
} |
||||
|
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 |
||||
|
} |
||||
|
|
||||
|
read_yes_no() |
||||
|
{ |
||||
|
# $1 - default (Y/N) |
||||
|
local A |
||||
|
read A |
||||
|
[ -z "$A" ] || ([ "$A" != "Y" ] && [ "$A" != "y" ] && [ "$A" != "N" ] && [ "$A" != "n" ]) && A=$1 |
||||
|
[ "$A" = "Y" ] || [ "$A" = "y" ] || [ "$A" = "1" ] |
||||
|
} |
||||
|
ask_yes_no() |
||||
|
{ |
||||
|
# $1 - default (Y/N or 0/1) |
||||
|
# $2 - text |
||||
|
local DEFAULT=$1 |
||||
|
[ "$1" = "1" ] && DEFAULT=Y |
||||
|
[ "$1" = "0" ] && DEFAULT=N |
||||
|
[ -z "$DEFAULT" ] && DEFAULT=N |
||||
|
$ECHON "$2 (default : $DEFAULT) (Y/N) ? " |
||||
|
read_yes_no $DEFAULT |
||||
|
} |
||||
|
ask_yes_no_var() |
||||
|
{ |
||||
|
# $1 - variable name for answer : 0/1 |
||||
|
# $2 - text |
||||
|
local DEFAULT |
||||
|
eval DEFAULT="\$$1" |
||||
|
if ask_yes_no "$DEFAULT" "$2"; then |
||||
|
eval $1=1 |
||||
|
else |
||||
|
eval $1=0 |
||||
|
fi |
||||
|
} |
||||
|
|
||||
|
|
||||
|
require_root() |
||||
|
{ |
||||
|
echo \* checking privileges |
||||
|
[ $(id -u) -ne "0" ] && { |
||||
|
echo root is required |
||||
|
exists sudo && exec sudo "$0" |
||||
|
exists su && exec su -c "$0" |
||||
|
echo su or sudo not found |
||||
|
exitp 2 |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
IPT() |
||||
|
{ |
||||
|
$IPTABLES -C "$@" >/dev/null 2>/dev/null || $IPTABLES -I "$@" |
||||
|
} |
||||
|
IPT_DEL() |
||||
|
{ |
||||
|
$IPTABLES -C "$@" >/dev/null 2>/dev/null && $IPTABLES -D "$@" |
||||
|
} |
||||
|
|
||||
|
|
||||
|
check_system() |
||||
|
{ |
||||
|
echo \* checking system |
||||
|
|
||||
|
local UNAME=$(uname) |
||||
|
[ "$UNAME" = "Linux" ] || { |
||||
|
echo not supported |
||||
|
exitp 5 |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
check_prerequisites() |
||||
|
{ |
||||
|
echo \* checking prerequisites |
||||
|
|
||||
|
[ -x "$NFQWS" ] && [ -x "$MDIG" ] || { |
||||
|
echo $NFQWS or $MDIG is not available. run $ZAPRET_BASE/install_bin.sh |
||||
|
exitp 6 |
||||
|
} |
||||
|
|
||||
|
for prog in iptables ip6tables curl; do |
||||
|
exists $prog || { |
||||
|
echo $prog does not exist. please install |
||||
|
exitp 6 |
||||
|
} |
||||
|
done |
||||
|
} |
||||
|
|
||||
|
|
||||
|
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 |
||||
|
tr -d '\015' <"$1" | sed -nre 's/^[L|l][O|o][C|c][A|a][T|t][I|i][O|o][N|n]:[ \t]*([^ \t]*)[ \t]*$/\1/p' |
||||
|
} |
||||
|
curl_test_http() |
||||
|
{ |
||||
|
# $1 - ip version : 4/6 |
||||
|
# $2 - domain name |
||||
|
local code loc |
||||
|
curl -${1}SsD "$HDRTEMP" --max-time $CURL_MAX_TIME $CURL_OPT "http://$2" -o /dev/null 2>&1 || { |
||||
|
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") |
||||
|
[ "${loc#*$2}" = "$loc" ] && { |
||||
|
echo suspicious redirection to : $loc |
||||
|
rm -f "$HDRTEMP" |
||||
|
return 254 |
||||
|
} |
||||
|
} |
||||
|
rm -f "$HDRTEMP" |
||||
|
return 0 |
||||
|
} |
||||
|
curl_test_https() |
||||
|
{ |
||||
|
# $1 - ip version : 4/6 |
||||
|
# $2 - domain name |
||||
|
|
||||
|
# prevent using QUIC if available in curl |
||||
|
curl -${1}Ss --max-time $CURL_MAX_TIME $CURL_OPT --http1.1 "https://$2" -o /dev/null 2>&1 |
||||
|
} |
||||
|
|
||||
|
nfqws_ipt_prepare() |
||||
|
{ |
||||
|
# $1 - port |
||||
|
IPT POSTROUTING -t mangle -p tcp --dport $1 -m mark ! --mark $DESYNC_MARK/$DESYNC_MARK -j NFQUEUE --queue-num $QNUM |
||||
|
} |
||||
|
nfqws_ipt_unprepare() |
||||
|
{ |
||||
|
# $1 - port |
||||
|
IPT_DEL POSTROUTING -t mangle -p tcp --dport $1 -m mark ! --mark $DESYNC_MARK/$DESYNC_MARK -j NFQUEUE --queue-num $QNUM |
||||
|
} |
||||
|
nfqws_start() |
||||
|
{ |
||||
|
"$NFQWS" --dpi-desync-fwmark=$DESYNC_MARK --qnum=$QNUM "$@" >/dev/null & |
||||
|
} |
||||
|
|
||||
|
curl_test() |
||||
|
{ |
||||
|
# $1 - test function |
||||
|
# $2 - domain |
||||
|
$1 $IPV $2 && { |
||||
|
echo '!!!!! AVAILABLE !!!!!' |
||||
|
return 0 |
||||
|
} |
||||
|
local code=$? |
||||
|
if [ $code = 254 ]; then |
||||
|
echo UNAVAILABLE |
||||
|
else |
||||
|
echo UNAVAILABLE code=$code |
||||
|
fi |
||||
|
return $code |
||||
|
} |
||||
|
nfqws_curl_test() |
||||
|
{ |
||||
|
# $1 - test function |
||||
|
# $2 - domain |
||||
|
# $3,$4,$5, ... - nfqws params |
||||
|
local code pid testf=$1 dom=$2 |
||||
|
shift |
||||
|
shift |
||||
|
echo - checking nfqws "$@" |
||||
|
nfqws_start "$@" |
||||
|
pid=$! |
||||
|
curl_test $testf $dom |
||||
|
code=$? |
||||
|
killwait -9 $pid |
||||
|
return $code |
||||
|
} |
||||
|
check_domain_bypass() |
||||
|
{ |
||||
|
# $1 - test function |
||||
|
# $2 - domain |
||||
|
|
||||
|
local pid strategy tests='fake' |
||||
|
|
||||
|
if nfqws_curl_test $1 $2 --dpi-desync=split2; then |
||||
|
strategy='--dpi-desync=split2' |
||||
|
else |
||||
|
tests="$tests split fake,split" |
||||
|
fi |
||||
|
if nfqws_curl_test $1 $2 --dpi-desync=disorder2; then |
||||
|
[ -n "$strategy" ] || strategy='--dpi-desync=disorder2' |
||||
|
else |
||||
|
tests="$tests disorder fake,disorder" |
||||
|
fi |
||||
|
|
||||
|
local ttls=$(seq -s ' ' $MIN_TTL $MAX_TTL) |
||||
|
for desync in $tests; do |
||||
|
for ttl in $ttls; do |
||||
|
nfqws_curl_test $1 $2 --dpi-desync=$desync --dpi-desync-ttl=$ttl && { |
||||
|
[ -n "$strategy" ] || strategy="--dpi-desync=$desync --dpi-desync-ttl=$ttl" |
||||
|
break |
||||
|
} |
||||
|
done |
||||
|
done |
||||
|
|
||||
|
echo |
||||
|
if [ -n "$strategy" ]; then |
||||
|
echo "!!!!! working strategy found : nfqws $strategy !!!!!" |
||||
|
return 0 |
||||
|
else |
||||
|
echo 'working strategy not found' |
||||
|
return 1 |
||||
|
fi |
||||
|
} |
||||
|
|
||||
|
check_domain() |
||||
|
{ |
||||
|
# $1 - test function |
||||
|
# $2 - port |
||||
|
# $3 - domain |
||||
|
|
||||
|
echo |
||||
|
echo \* $1 $3 |
||||
|
|
||||
|
# in case was interrupted before |
||||
|
nfqws_ipt_unprepare $2 |
||||
|
killall nfqws 2>/dev/null |
||||
|
|
||||
|
echo "- checking without DPI bypass" |
||||
|
curl_test $1 $3 && return 0 |
||||
|
|
||||
|
echo preparing nfqws redirection |
||||
|
nfqws_ipt_prepare $2 |
||||
|
|
||||
|
check_domain_bypass $1 $3 |
||||
|
|
||||
|
echo clearing nfqws redirection |
||||
|
nfqws_ipt_unprepare $2 |
||||
|
} |
||||
|
check_domain_http() |
||||
|
{ |
||||
|
# $1 - domain |
||||
|
check_domain curl_test_http 80 $1 |
||||
|
} |
||||
|
check_domain_https() |
||||
|
{ |
||||
|
# $1 - domain |
||||
|
check_domain curl_test_https 443 $1 |
||||
|
} |
||||
|
|
||||
|
ask_params() |
||||
|
{ |
||||
|
echo |
||||
|
echo NOTE ! this test should be run with zapret or any other bypass software disabled, without VPN |
||||
|
echo NOTE ! this test will kill all nfqws processes. if you have already set up zapret you will need to restart it after test is complete. |
||||
|
|
||||
|
$ECHON "test this domain [ $DOMAIN ] : " |
||||
|
local dom |
||||
|
read dom |
||||
|
[ -n "$dom" ] && DOMAIN=$dom |
||||
|
|
||||
|
$ECHON "ip protocol version [ 4 ] : " |
||||
|
read IPV |
||||
|
[ -n "$IPV" ] || IPV=4 |
||||
|
[ "$IPV" = 4 -o "$IPV" = 6 ] || { |
||||
|
echo invalid ip version. should be 4 or 6. |
||||
|
exitp 1 |
||||
|
} |
||||
|
IPTABLES=iptables |
||||
|
[ "$IPV" = 6 ] && IPTABLES=ip6tables |
||||
|
|
||||
|
ENABLE_HTTP=1 |
||||
|
ask_yes_no_var ENABLE_HTTP "check http" |
||||
|
|
||||
|
ENABLE_HTTPS=1 |
||||
|
ask_yes_no_var ENABLE_HTTPS "check https" |
||||
|
|
||||
|
IGNORE_CA=0 |
||||
|
CURL_OPT= |
||||
|
[ "$ENABLE_HTTPS" = "1" ] && { |
||||
|
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 |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
pingtest() |
||||
|
{ |
||||
|
ping -c 1 -W 1 $1 >/dev/null |
||||
|
} |
||||
|
dnstest() |
||||
|
{ |
||||
|
# $1 - dns server. empty for system resolver |
||||
|
nslookup w3.org $1 >/dev/null 2>/dev/null |
||||
|
} |
||||
|
find_working_public_dns() |
||||
|
{ |
||||
|
for dns in $DNSCHECK_DNS; do |
||||
|
pingtest $dns && dnstest $dns && { |
||||
|
PUBDNS=$dns |
||||
|
return 0 |
||||
|
} |
||||
|
done |
||||
|
return 1 |
||||
|
} |
||||
|
check_dns_spoof() |
||||
|
{ |
||||
|
# $1 - domain |
||||
|
# $2 - public DNS |
||||
|
echo $1 | "$EXEDIR/mdig/mdig" --family=4 >"$DNSCHECK_DIG1" |
||||
|
nslookup $1 $2 | sed -n '/Name:/,$p' | grep ^Address | grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' >"$DNSCHECK_DIG2" |
||||
|
# 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() |
||||
|
{ |
||||
|
local C1 C2 |
||||
|
|
||||
|
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. |
||||
|
for dom in $DNSCHECK_DOM; do echo $dom; done | "$EXEDIR/mdig/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. |
||||
|
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 |
||||
|
} |
||||
|
|
||||
|
|
||||
|
sigint() |
||||
|
{ |
||||
|
# make sure we are not in a middle state that impacts connectivity |
||||
|
echo |
||||
|
echo terminating... |
||||
|
nfqws_ipt_unprepare 80 |
||||
|
nfqws_ipt_unprepare 443 |
||||
|
killall nfqws 2>/dev/null |
||||
|
exit 1 |
||||
|
} |
||||
|
|
||||
|
trap 'sigint' 2 |
||||
|
|
||||
|
check_system |
||||
|
check_prerequisites |
||||
|
require_root |
||||
|
check_dns |
||||
|
ask_params |
||||
|
|
||||
|
[ "$ENABLE_HTTP" = 1 ] && check_domain_http $DOMAIN |
||||
|
[ "$ENABLE_HTTPS" = 1 ] && check_domain_https $DOMAIN |
Loading…
Reference in new issue