706 lines
25 KiB
Bash
706 lines
25 KiB
Bash
#!/data/data/com.termux/files/usr/bin/bash
|
||
# ══════════════════════════════════════════════════════
|
||
# WHITELIST PROBE v1.0
|
||
# Определяет доступные методы обхода whitelist
|
||
# Платформа: Termux (Android) / Linux
|
||
# Зависимости: curl, nc (ncat), openssl, nslookup
|
||
# ══════════════════════════════════════════════════════
|
||
|
||
set -o pipefail
|
||
|
||
# ── Конфигурация ──────────────────────────────────────
|
||
VPS_IP="194.87.245.138" # Ирландия (exit node)
|
||
MOSCOW_IP="94.141.253.12" # Москва (relay)
|
||
DNSTT_DOMAIN="t.chatsquad.ru"
|
||
DNSTT_NS="ns-t.chatsquad.ru"
|
||
TIMEOUT=3 # секунд на каждый тест
|
||
RESULT_DIR="./results"
|
||
TIMESTAMP=$(date '+%Y-%m-%d_%H-%M-%S')
|
||
RESULT_FILE="${RESULT_DIR}/probe_${TIMESTAMP}.txt"
|
||
JSON_FILE="${RESULT_DIR}/probe_${TIMESTAMP}.json"
|
||
|
||
# ── Цвета ─────────────────────────────────────────────
|
||
if [ -t 1 ]; then
|
||
G='\033[0;32m' # green
|
||
R='\033[0;31m' # red
|
||
Y='\033[0;33m' # yellow
|
||
C='\033[0;36m' # cyan
|
||
B='\033[1m' # bold
|
||
N='\033[0m' # reset
|
||
else
|
||
G='' R='' Y='' C='' B='' N=''
|
||
fi
|
||
|
||
# ── Счётчики ──────────────────────────────────────────
|
||
declare -A RESULTS
|
||
TOTAL=0
|
||
PASS=0
|
||
FAIL=0
|
||
|
||
# ── Утилиты ───────────────────────────────────────────
|
||
ok() { echo -e " ${G}✓${N} $1"; RESULTS["$2"]="ok"; ((PASS++)); ((TOTAL++)); }
|
||
fail() { echo -e " ${R}✗${N} $1"; RESULTS["$2"]="fail"; ((FAIL++)); ((TOTAL++)); }
|
||
skip() { echo -e " ${Y}—${N} $1"; RESULTS["$2"]="skip"; ((TOTAL++)); }
|
||
info() { echo -e " ${C}ℹ${N} $1"; }
|
||
hdr() { echo -e "\n${B}[$1]${N}"; }
|
||
|
||
# Ping с таймаутом
|
||
do_ping() {
|
||
local host=$1
|
||
local result
|
||
result=$(ping -c 1 -W $TIMEOUT "$host" 2>/dev/null | grep -oP 'time=\K[0-9.]+')
|
||
if [ -n "$result" ]; then
|
||
echo "${result}ms"
|
||
return 0
|
||
fi
|
||
return 1
|
||
}
|
||
|
||
# TCP connect
|
||
do_tcp() {
|
||
local host=$1 port=$2
|
||
timeout $TIMEOUT bash -c "echo >/dev/tcp/$host/$port" 2>/dev/null
|
||
return $?
|
||
}
|
||
|
||
# UDP test (отправить пакет, ждать ответ)
|
||
do_udp() {
|
||
local host=$1 port=$2
|
||
echo -n "test" | timeout $TIMEOUT nc -u -w $TIMEOUT "$host" "$port" 2>/dev/null
|
||
# UDP "успех" если nc не вернул ошибку (не гарантирует доставку)
|
||
return $?
|
||
}
|
||
|
||
# HTTPS test
|
||
do_https() {
|
||
local host=$1
|
||
local code
|
||
code=$(curl -s -o /dev/null -w '%{http_code}' --connect-timeout $TIMEOUT --max-time $((TIMEOUT+2)) "https://$host" 2>/dev/null)
|
||
if [ "$code" -ge 100 ] 2>/dev/null && [ "$code" -lt 600 ] 2>/dev/null; then
|
||
echo "$code"
|
||
return 0
|
||
fi
|
||
return 1
|
||
}
|
||
|
||
# DNS resolve
|
||
do_resolve() {
|
||
local domain=$1 server=$2
|
||
local result
|
||
if [ -n "$server" ]; then
|
||
result=$(nslookup "$domain" "$server" 2>/dev/null | grep -A1 "Name:" | grep "Address:" | head -1 | awk '{print $2}')
|
||
else
|
||
result=$(nslookup "$domain" 2>/dev/null | grep -A1 "Name:" | grep "Address:" | head -1 | awk '{print $2}')
|
||
fi
|
||
if [ -n "$result" ]; then
|
||
echo "$result"
|
||
return 0
|
||
fi
|
||
return 1
|
||
}
|
||
|
||
# TLS handshake с кастомным SNI
|
||
do_tls_sni() {
|
||
local ip=$1 port=$2 sni=$3
|
||
echo | timeout $TIMEOUT openssl s_client -connect "$ip:$port" -servername "$sni" 2>/dev/null | grep -q "BEGIN CERTIFICATE"
|
||
return $?
|
||
}
|
||
|
||
# HTTP/2 check
|
||
do_h2() {
|
||
local host=$1
|
||
local proto
|
||
proto=$(curl -s -o /dev/null -w '%{http_version}' --connect-timeout $TIMEOUT --max-time $((TIMEOUT+2)) "https://$host" 2>/dev/null)
|
||
echo "$proto"
|
||
[ "$proto" = "2" ] && return 0
|
||
return 1
|
||
}
|
||
|
||
# ══════════════════════════════════════════════════════
|
||
# УСТАНОВКА ЗАВИСИМОСТЕЙ
|
||
# ══════════════════════════════════════════════════════
|
||
install_deps() {
|
||
local missing=()
|
||
command -v curl >/dev/null || missing+=(curl)
|
||
command -v nc >/dev/null || missing+=(nmap)
|
||
command -v openssl >/dev/null || missing+=(openssl-tool)
|
||
command -v nslookup >/dev/null || { command -v host >/dev/null || missing+=(dnsutils); }
|
||
command -v ping >/dev/null || missing+=(inetutils)
|
||
|
||
if [ ${#missing[@]} -gt 0 ]; then
|
||
echo -e "${Y}Установка: ${missing[*]}${N}"
|
||
if command -v pkg >/dev/null; then
|
||
pkg install -y "${missing[@]}" 2>/dev/null
|
||
elif command -v apt-get >/dev/null; then
|
||
sudo apt-get install -y "${missing[@]}" 2>/dev/null
|
||
fi
|
||
fi
|
||
}
|
||
|
||
# ══════════════════════════════════════════════════════
|
||
# ТЕСТЫ
|
||
# ══════════════════════════════════════════════════════
|
||
|
||
test_provider() {
|
||
hdr "ПРОВАЙДЕР"
|
||
|
||
local ext_ip isp asn
|
||
ext_ip=$(curl -s --connect-timeout $TIMEOUT ifconfig.me 2>/dev/null)
|
||
if [ -z "$ext_ip" ]; then
|
||
ext_ip=$(curl -s --connect-timeout $TIMEOUT api.ipify.org 2>/dev/null)
|
||
fi
|
||
if [ -z "$ext_ip" ]; then
|
||
ext_ip=$(curl -s --connect-timeout $TIMEOUT ident.me 2>/dev/null)
|
||
fi
|
||
|
||
if [ -n "$ext_ip" ]; then
|
||
info "Внешний IP: ${B}$ext_ip${N}"
|
||
RESULTS["ext_ip"]="$ext_ip"
|
||
|
||
local ipinfo
|
||
ipinfo=$(curl -s --connect-timeout $TIMEOUT "http://ip-api.com/json/$ext_ip?fields=isp,as,country" 2>/dev/null)
|
||
if [ -n "$ipinfo" ]; then
|
||
isp=$(echo "$ipinfo" | grep -oP '"isp"\s*:\s*"\K[^"]+')
|
||
asn=$(echo "$ipinfo" | grep -oP '"as"\s*:\s*"\K[^"]+')
|
||
local country
|
||
country=$(echo "$ipinfo" | grep -oP '"country"\s*:\s*"\K[^"]+')
|
||
info "ISP: ${B}$isp${N}"
|
||
info "ASN: ${B}$asn${N}"
|
||
info "Страна: ${B}$country${N}"
|
||
RESULTS["isp"]="$isp"
|
||
RESULTS["asn"]="$asn"
|
||
fi
|
||
else
|
||
fail "Не удалось определить внешний IP" "ext_ip"
|
||
fi
|
||
}
|
||
|
||
test_icmp() {
|
||
hdr "ICMP (Ping)"
|
||
|
||
local -A targets=(
|
||
["VPS Ирландия"]="$VPS_IP"
|
||
["Москва relay"]="$MOSCOW_IP"
|
||
["yandex.ru"]="yandex.ru"
|
||
["ya.ru"]="ya.ru"
|
||
["vk.com"]="vk.com"
|
||
["mail.ru"]="mail.ru"
|
||
["ok.ru"]="ok.ru"
|
||
["sber.ru"]="sber.ru"
|
||
["gosuslugi.ru"]="gosuslugi.ru"
|
||
["mos.ru"]="mos.ru"
|
||
["Google 8.8.8.8"]="8.8.8.8"
|
||
["Cloudflare 1.1.1.1"]="1.1.1.1"
|
||
["Yandex DNS 77.88.8.8"]="77.88.8.8"
|
||
["Telegram"]="149.154.167.99"
|
||
)
|
||
|
||
local order=("yandex.ru" "ya.ru" "vk.com" "mail.ru" "ok.ru" "sber.ru" "gosuslugi.ru" "mos.ru" "Yandex DNS 77.88.8.8" "VPS Ирландия" "Москва relay" "Google 8.8.8.8" "Cloudflare 1.1.1.1" "Telegram")
|
||
|
||
for name in "${order[@]}"; do
|
||
local target="${targets[$name]}"
|
||
local t
|
||
t=$(do_ping "$target")
|
||
if [ $? -eq 0 ]; then
|
||
ok "$(printf '%-22s %s' "$name" "$t")" "icmp_$name"
|
||
else
|
||
fail "$(printf '%-22s' "$name")" "icmp_$name"
|
||
fi
|
||
done
|
||
}
|
||
|
||
test_dns() {
|
||
hdr "DNS RESOLUTION"
|
||
|
||
# Системный DNS
|
||
local r
|
||
r=$(do_resolve "yandex.ru")
|
||
if [ $? -eq 0 ]; then
|
||
ok "System DNS yandex.ru → $r" "dns_system"
|
||
else
|
||
fail "System DNS yandex.ru" "dns_system"
|
||
fi
|
||
|
||
# Через разные DNS-серверы
|
||
local -A dns_servers=(
|
||
["Yandex 77.88.8.8"]="77.88.8.8"
|
||
["Yandex 77.88.8.1"]="77.88.8.1"
|
||
["Google 8.8.8.8"]="8.8.8.8"
|
||
["Google 8.8.4.4"]="8.8.4.4"
|
||
["Cloudflare 1.1.1.1"]="1.1.1.1"
|
||
["Quad9 9.9.9.9"]="9.9.9.9"
|
||
)
|
||
|
||
local dns_order=("Yandex 77.88.8.8" "Yandex 77.88.8.1" "Google 8.8.8.8" "Google 8.8.4.4" "Cloudflare 1.1.1.1" "Quad9 9.9.9.9")
|
||
|
||
for name in "${dns_order[@]}"; do
|
||
local server="${dns_servers[$name]}"
|
||
r=$(do_resolve "yandex.ru" "$server")
|
||
if [ $? -eq 0 ]; then
|
||
ok "$(printf '%-22s yandex.ru → %s' "$name" "$r")" "dns_$name"
|
||
else
|
||
fail "$(printf '%-22s' "$name")" "dns_$name"
|
||
fi
|
||
done
|
||
|
||
# DNSTT домен
|
||
echo ""
|
||
r=$(do_resolve "$DNSTT_DOMAIN")
|
||
if [ $? -eq 0 ]; then
|
||
ok "DNSTT domain $DNSTT_DOMAIN → $r" "dns_dnstt"
|
||
else
|
||
# Попробуем NS запись
|
||
local ns_result
|
||
ns_result=$(nslookup -type=NS "$DNSTT_DOMAIN" 2>/dev/null | grep -i "nameserver" | head -1)
|
||
if [ -n "$ns_result" ]; then
|
||
ok "DNSTT domain (NS) $DNSTT_DOMAIN → delegated" "dns_dnstt"
|
||
else
|
||
fail "DNSTT domain $DNSTT_DOMAIN" "dns_dnstt"
|
||
fi
|
||
fi
|
||
|
||
r=$(do_resolve "$DNSTT_NS")
|
||
if [ $? -eq 0 ]; then
|
||
ok "DNSTT NS $DNSTT_NS → $r" "dns_dnstt_ns"
|
||
else
|
||
fail "DNSTT NS $DNSTT_NS" "dns_dnstt_ns"
|
||
fi
|
||
}
|
||
|
||
test_dns_tunnel() {
|
||
hdr "DNS TUNNEL VIABILITY"
|
||
|
||
# DoH (DNS over HTTPS) — через Яндекс
|
||
local r
|
||
r=$(curl -s --connect-timeout $TIMEOUT --max-time $((TIMEOUT+2)) \
|
||
-H 'Accept: application/dns-json' \
|
||
"https://dns.yandex.net/dns-query?name=example.com&type=A" 2>/dev/null)
|
||
if echo "$r" | grep -q "Answer\|Status"; then
|
||
ok "DoH Яндекс dns.yandex.net" "doh_yandex"
|
||
else
|
||
fail "DoH Яндекс dns.yandex.net" "doh_yandex"
|
||
fi
|
||
|
||
# DoH Google
|
||
r=$(curl -s --connect-timeout $TIMEOUT --max-time $((TIMEOUT+2)) \
|
||
"https://dns.google/resolve?name=example.com&type=A" 2>/dev/null)
|
||
if echo "$r" | grep -q "Answer\|Status"; then
|
||
ok "DoH Google dns.google" "doh_google"
|
||
else
|
||
fail "DoH Google dns.google" "doh_google"
|
||
fi
|
||
|
||
# DoH Cloudflare
|
||
r=$(curl -s --connect-timeout $TIMEOUT --max-time $((TIMEOUT+2)) \
|
||
-H 'Accept: application/dns-json' \
|
||
"https://cloudflare-dns.com/dns-query?name=example.com&type=A" 2>/dev/null)
|
||
if echo "$r" | grep -q "Answer\|Status"; then
|
||
ok "DoH Cloudflare cloudflare-dns.com" "doh_cf"
|
||
else
|
||
fail "DoH Cloudflare cloudflare-dns.com" "doh_cf"
|
||
fi
|
||
|
||
# DoT (DNS over TLS) — порт 853
|
||
echo ""
|
||
for name_server in "Yandex:77.88.8.8" "Google:8.8.8.8" "CF:1.1.1.1"; do
|
||
local label="${name_server%%:*}"
|
||
local ip="${name_server##*:}"
|
||
if do_tcp "$ip" 853; then
|
||
ok "DoT $label $ip:853" "dot_$label"
|
||
else
|
||
fail "DoT $label $ip:853" "dot_$label"
|
||
fi
|
||
done
|
||
}
|
||
|
||
test_tcp_our_servers() {
|
||
hdr "TCP — НАШИ СЕРВЕРЫ"
|
||
|
||
local -A ports=(
|
||
["VPS:443 (VLESS)"]="$VPS_IP:443"
|
||
["VPS:38246 (SS)"]="$VPS_IP:38246"
|
||
["VPS:8443 (Chisel)"]="$VPS_IP:8443"
|
||
["VPS:22 (SSH)"]="$VPS_IP:22"
|
||
["VPS:53 (DNS)"]="$VPS_IP:53"
|
||
["Moscow:2053 (relay)"]="$MOSCOW_IP:2053"
|
||
["Moscow:443 (HTTPS)"]="$MOSCOW_IP:443"
|
||
["Moscow:22 (SSH)"]="$MOSCOW_IP:22"
|
||
)
|
||
|
||
local order=("VPS:443 (VLESS)" "VPS:38246 (SS)" "VPS:8443 (Chisel)" "VPS:22 (SSH)" "VPS:53 (DNS)" "Moscow:2053 (relay)" "Moscow:443 (HTTPS)" "Moscow:22 (SSH)")
|
||
|
||
for name in "${order[@]}"; do
|
||
local hp="${ports[$name]}"
|
||
local host="${hp%%:*}"
|
||
local port="${hp##*:}"
|
||
if do_tcp "$host" "$port"; then
|
||
ok "$(printf '%-25s' "$name")" "tcp_$name"
|
||
else
|
||
fail "$(printf '%-25s' "$name")" "tcp_$name"
|
||
fi
|
||
done
|
||
}
|
||
|
||
test_udp() {
|
||
hdr "UDP"
|
||
|
||
local -A targets=(
|
||
["VPS:53 (DNSTT)"]="$VPS_IP:53"
|
||
["VPS:443 (QUIC)"]="$VPS_IP:443"
|
||
["VPS:43742 (WG)"]="$VPS_IP:43742"
|
||
["VPS:47426 (AWG)"]="$VPS_IP:47426"
|
||
["VPS:48253 (AWG2)"]="$VPS_IP:48253"
|
||
)
|
||
|
||
local order=("VPS:53 (DNSTT)" "VPS:443 (QUIC)" "VPS:43742 (WG)" "VPS:47426 (AWG)" "VPS:48253 (AWG2)")
|
||
|
||
info "UDP-тесты ненадёжны без ответа сервера"
|
||
for name in "${order[@]}"; do
|
||
local hp="${targets[$name]}"
|
||
local host="${hp%%:*}"
|
||
local port="${hp##*:}"
|
||
# Для DNS порта — отправляем реальный DNS запрос
|
||
if [ "$port" = "53" ]; then
|
||
local dns_r
|
||
dns_r=$(do_resolve "yandex.ru" "$host")
|
||
if [ $? -eq 0 ]; then
|
||
ok "$(printf '%-25s (DNS ответил: %s)' "$name" "$dns_r")" "udp_$name"
|
||
else
|
||
fail "$(printf '%-25s' "$name")" "udp_$name"
|
||
fi
|
||
else
|
||
if do_udp "$host" "$port"; then
|
||
skip "$(printf '%-25s (отправлено, ответ неизвестен)' "$name")" "udp_$name"
|
||
else
|
||
fail "$(printf '%-25s' "$name")" "udp_$name"
|
||
fi
|
||
fi
|
||
done
|
||
}
|
||
|
||
test_https() {
|
||
hdr "HTTPS / TLS"
|
||
|
||
local -A sites=(
|
||
# Российские
|
||
["yandex.ru"]="yandex.ru"
|
||
["ya.ru"]="ya.ru"
|
||
["vk.com"]="vk.com"
|
||
["mail.ru"]="mail.ru"
|
||
["ok.ru"]="ok.ru"
|
||
["sber.ru"]="sber.ru"
|
||
["gosuslugi.ru"]="gosuslugi.ru"
|
||
["mos.ru"]="mos.ru"
|
||
["rutube.ru"]="rutube.ru"
|
||
# Зарубежные
|
||
["google.com"]="google.com"
|
||
["cloudflare.com"]="cloudflare.com"
|
||
["microsoft.com"]="microsoft.com"
|
||
["apple.com"]="apple.com"
|
||
["github.com"]="github.com"
|
||
["telegram.org"]="telegram.org"
|
||
# CDN
|
||
["cdn.jsdelivr.net"]="cdn.jsdelivr.net"
|
||
["cdnjs.cloudflare.com"]="cdnjs.cloudflare.com"
|
||
["unpkg.com"]="unpkg.com"
|
||
# Облака
|
||
["cloud.yandex.ru"]="cloud.yandex.ru"
|
||
["functions.yandexcloud.net"]="functions.yandexcloud.net"
|
||
["cloud.vk.com"]="cloud.vk.com"
|
||
# DoH
|
||
["dns.yandex.net"]="dns.yandex.net"
|
||
)
|
||
|
||
local order=(
|
||
"yandex.ru" "ya.ru" "vk.com" "mail.ru" "ok.ru" "sber.ru" "gosuslugi.ru" "mos.ru" "rutube.ru"
|
||
"---РУ/Зарубеж---"
|
||
"google.com" "cloudflare.com" "microsoft.com" "apple.com" "github.com" "telegram.org"
|
||
"---CDN---"
|
||
"cdn.jsdelivr.net" "cdnjs.cloudflare.com" "unpkg.com"
|
||
"---Облака---"
|
||
"cloud.yandex.ru" "functions.yandexcloud.net" "cloud.vk.com" "dns.yandex.net"
|
||
)
|
||
|
||
for name in "${order[@]}"; do
|
||
if [[ "$name" == ---* ]]; then
|
||
echo ""
|
||
continue
|
||
fi
|
||
local target="${sites[$name]}"
|
||
local code
|
||
code=$(do_https "$target")
|
||
if [ $? -eq 0 ]; then
|
||
local h2
|
||
h2=$(do_h2 "$target")
|
||
local proto_tag=""
|
||
[ "$h2" = "2" ] && proto_tag=" HTTP/2" || proto_tag=" HTTP/$h2"
|
||
ok "$(printf '%-28s %s%s' "$name" "$code" "$proto_tag")" "https_$name"
|
||
else
|
||
fail "$(printf '%-28s' "$name")" "https_$name"
|
||
fi
|
||
done
|
||
}
|
||
|
||
test_sni() {
|
||
hdr "SNI FILTERING"
|
||
info "TLS handshake к VPS ($VPS_IP:443) с разными SNI"
|
||
|
||
local snis=("yandex.ru" "ya.ru" "vk.com" "mail.ru" "google.com" "$VPS_IP")
|
||
|
||
for sni in "${snis[@]}"; do
|
||
if do_tls_sni "$VPS_IP" 443 "$sni"; then
|
||
ok "$(printf 'SNI=%-20s → TLS OK' "$sni")" "sni_$sni"
|
||
else
|
||
fail "$(printf 'SNI=%-20s' "$sni")" "sni_$sni"
|
||
fi
|
||
done
|
||
|
||
echo ""
|
||
info "TLS handshake к Москве ($MOSCOW_IP:2053)"
|
||
for sni in "yandex.ru" "ya.ru"; do
|
||
if do_tls_sni "$MOSCOW_IP" 2053 "$sni"; then
|
||
ok "$(printf 'SNI=%-20s → TLS OK' "$sni")" "sni_moscow_$sni"
|
||
else
|
||
fail "$(printf 'SNI=%-20s' "$sni")" "sni_moscow_$sni"
|
||
fi
|
||
done
|
||
}
|
||
|
||
test_cdn() {
|
||
hdr "CDN REACHABILITY"
|
||
|
||
# Cloudflare IP ranges
|
||
local cf_ips=("104.16.0.1" "104.17.0.1" "172.64.0.1" "172.67.0.1")
|
||
info "Cloudflare IP ranges"
|
||
for ip in "${cf_ips[@]}"; do
|
||
if do_tcp "$ip" 443; then
|
||
ok "$(printf '%-22s TCP:443' "$ip")" "cdn_cf_$ip"
|
||
else
|
||
fail "$(printf '%-22s' "$ip")" "cdn_cf_$ip"
|
||
fi
|
||
done
|
||
|
||
echo ""
|
||
info "Yandex CDN"
|
||
local ycdn
|
||
ycdn=$(do_resolve "yastatic.net")
|
||
if [ $? -eq 0 ]; then
|
||
if do_tcp "$ycdn" 443; then
|
||
ok "yastatic.net $ycdn TCP:443" "cdn_yandex"
|
||
else
|
||
fail "yastatic.net $ycdn" "cdn_yandex"
|
||
fi
|
||
else
|
||
fail "yastatic.net (не резолвится)" "cdn_yandex"
|
||
fi
|
||
|
||
local vkcdn
|
||
vkcdn=$(do_resolve "st.vk.com")
|
||
if [ $? -eq 0 ]; then
|
||
if do_tcp "$vkcdn" 443; then
|
||
ok "st.vk.com $vkcdn TCP:443" "cdn_vk"
|
||
else
|
||
fail "st.vk.com $vkcdn" "cdn_vk"
|
||
fi
|
||
else
|
||
fail "st.vk.com (не резолвится)" "cdn_vk"
|
||
fi
|
||
}
|
||
|
||
test_advanced() {
|
||
hdr "ADVANCED"
|
||
|
||
# WebSocket upgrade test через доступные хосты
|
||
info "WebSocket upgrade"
|
||
local ws_code
|
||
ws_code=$(curl -s -o /dev/null -w '%{http_code}' --connect-timeout $TIMEOUT \
|
||
-H "Upgrade: websocket" -H "Connection: Upgrade" \
|
||
-H "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==" \
|
||
-H "Sec-WebSocket-Version: 13" \
|
||
"https://yandex.ru" 2>/dev/null)
|
||
if [ "$ws_code" = "101" ]; then
|
||
ok "WebSocket yandex.ru → 101 Switching" "ws_yandex"
|
||
else
|
||
fail "WebSocket yandex.ru → $ws_code (не поддерживает)" "ws_yandex"
|
||
fi
|
||
|
||
# QUIC / HTTP3
|
||
echo ""
|
||
info "QUIC (HTTP/3)"
|
||
local quic
|
||
quic=$(curl -s -o /dev/null -w '%{http_version}' --connect-timeout $TIMEOUT \
|
||
--http3-only "https://yandex.ru" 2>/dev/null)
|
||
if [ "$quic" = "3" ]; then
|
||
ok "HTTP/3 yandex.ru → работает" "quic_yandex"
|
||
else
|
||
skip "HTTP/3 yandex.ru → curl без HTTP/3 или заблокирован" "quic_yandex"
|
||
fi
|
||
|
||
# ECH support
|
||
echo ""
|
||
info "ECH (Encrypted Client Hello)"
|
||
local ech
|
||
ech=$(echo | timeout $TIMEOUT openssl s_client -connect cloudflare.com:443 \
|
||
-ech grease 2>&1 | grep -i "ech")
|
||
if [ -n "$ech" ]; then
|
||
ok "ECH → поддерживается" "ech"
|
||
else
|
||
skip "ECH → не поддерживается данной версией openssl" "ech"
|
||
fi
|
||
}
|
||
|
||
# ══════════════════════════════════════════════════════
|
||
# РЕКОМЕНДАЦИИ
|
||
# ══════════════════════════════════════════════════════
|
||
recommendations() {
|
||
hdr "РЕКОМЕНДАЦИИ"
|
||
echo ""
|
||
|
||
local rec=()
|
||
local rec_detail=()
|
||
|
||
# S-тир: CDN tunnel
|
||
if [ "${RESULTS[https_cloudflare.com]}" = "ok" ] || [ "${RESULTS[cdn_cf_104.16.0.1]}" = "ok" ]; then
|
||
rec+=("S")
|
||
rec_detail+=("${G}S-тир${N} │ VLESS + WebSocket + Cloudflare CDN │ CF доступен, быстро и надёжно")
|
||
fi
|
||
|
||
if [ "${RESULTS[https_cdn.jsdelivr.net]}" = "ok" ]; then
|
||
rec+=("S")
|
||
rec_detail+=("${G}S-тир${N} │ CDN-туннель через jsDelivr │ CDN доступен")
|
||
fi
|
||
|
||
# S-тир: Direct VLESS
|
||
if [ "${RESULTS[tcp_VPS:443 (VLESS)]}" = "ok" ]; then
|
||
rec+=("S")
|
||
rec_detail+=("${G}S-тир${N} │ VLESS + XHTTP + Reality (прямой) │ TCP к VPS:443 открыт")
|
||
fi
|
||
|
||
# A-тир: Moscow relay
|
||
if [ "${RESULTS[tcp_Moscow:2053 (relay)]}" = "ok" ]; then
|
||
rec+=("A")
|
||
rec_detail+=("${Y}A-тир${N} │ VLESS через Moscow relay │ TCP к Москве:2053 открыт")
|
||
fi
|
||
|
||
# A-тир: Hysteria2
|
||
if [ "${RESULTS[udp_VPS:443 (QUIC)]}" = "ok" ]; then
|
||
rec+=("A")
|
||
rec_detail+=("${Y}A-тир${N} │ Hysteria2 + Salamander (UDP) │ UDP к VPS работает")
|
||
fi
|
||
|
||
# B-тир: Yandex Cloud Functions
|
||
if [ "${RESULTS[https_functions.yandexcloud.net]}" = "ok" ]; then
|
||
rec+=("B")
|
||
rec_detail+=("${C}B-тир${N} │ Serverless proxy (YC Functions) │ Yandex Cloud доступен")
|
||
fi
|
||
|
||
# B-тир: DNSTT
|
||
if [ "${RESULTS[dns_dnstt]}" = "ok" ] || [ "${RESULTS[dns_system]}" = "ok" ]; then
|
||
rec+=("B")
|
||
rec_detail+=("${C}B-тир${N} │ DNSTT (DNS-туннель) │ DNS работает, ~50-100 Кбит/с")
|
||
fi
|
||
|
||
# B-тир: DoH tunnel
|
||
if [ "${RESULTS[doh_yandex]}" = "ok" ]; then
|
||
rec+=("B")
|
||
rec_detail+=("${C}B-тир${N} │ DoH tunnel (dns.yandex.net) │ DNS-over-HTTPS через Яндекс")
|
||
fi
|
||
|
||
# C-тир: ICMP tunnel
|
||
local icmp_to_vps="${RESULTS[icmp_VPS Ирландия]}"
|
||
local icmp_to_moscow="${RESULTS[icmp_Москва relay]}"
|
||
if [ "$icmp_to_vps" = "ok" ] || [ "$icmp_to_moscow" = "ok" ]; then
|
||
rec+=("C")
|
||
rec_detail+=("${R}C-тир${N} │ ICMP tunnel (ptunnel-ng) │ Ping к серверу работает, очень медленно")
|
||
fi
|
||
|
||
# Shadowsocks
|
||
if [ "${RESULTS[tcp_VPS:38246 (SS)]}" = "ok" ]; then
|
||
rec+=("A")
|
||
rec_detail+=("${Y}A-тир${N} │ Shadowsocks │ TCP к VPS:38246 открыт")
|
||
fi
|
||
|
||
# Chisel
|
||
if [ "${RESULTS[tcp_VPS:8443 (Chisel)]}" = "ok" ]; then
|
||
rec+=("B")
|
||
rec_detail+=("${C}B-тир${N} │ Chisel (HTTP tunnel) │ TCP к VPS:8443 открыт")
|
||
fi
|
||
|
||
# WireGuard / AmneziaWG
|
||
if [ "${RESULTS[udp_VPS:43742 (WG)]}" = "ok" ] || [ "${RESULTS[udp_VPS:47426 (AWG)]}" = "ok" ]; then
|
||
rec+=("B")
|
||
rec_detail+=("${C}B-тир${N} │ AmneziaWG / WireGuard │ UDP к VPS работает")
|
||
fi
|
||
|
||
if [ ${#rec_detail[@]} -eq 0 ]; then
|
||
echo -e " ${R}Ни один метод не определён как рабочий${N}"
|
||
echo -e " ${Y}Варианты:${N}"
|
||
echo " • Спутниковый интернет (Starlink)"
|
||
echo " • Физический доступ к незаблокированной сети"
|
||
echo " • Mesh-сети"
|
||
else
|
||
local i=0
|
||
for detail in "${rec_detail[@]}"; do
|
||
((i++))
|
||
echo -e " $i. $detail"
|
||
done
|
||
fi
|
||
}
|
||
|
||
# ══════════════════════════════════════════════════════
|
||
# СОХРАНЕНИЕ РЕЗУЛЬТАТОВ
|
||
# ══════════════════════════════════════════════════════
|
||
save_results() {
|
||
mkdir -p "$RESULT_DIR"
|
||
|
||
# JSON
|
||
echo "{" > "$JSON_FILE"
|
||
echo " \"timestamp\": \"$TIMESTAMP\"," >> "$JSON_FILE"
|
||
echo " \"results\": {" >> "$JSON_FILE"
|
||
local first=true
|
||
for key in $(echo "${!RESULTS[@]}" | tr ' ' '\n' | sort); do
|
||
if [ "$first" = true ]; then
|
||
first=false
|
||
else
|
||
echo "," >> "$JSON_FILE"
|
||
fi
|
||
printf ' "%s": "%s"' "$key" "${RESULTS[$key]}" >> "$JSON_FILE"
|
||
done
|
||
echo "" >> "$JSON_FILE"
|
||
echo " }" >> "$JSON_FILE"
|
||
echo "}" >> "$JSON_FILE"
|
||
|
||
info "Результаты: $JSON_FILE"
|
||
}
|
||
|
||
# ══════════════════════════════════════════════════════
|
||
# MAIN
|
||
# ══════════════════════════════════════════════════════
|
||
main() {
|
||
echo -e "${B}══════════════════════════════════════════${N}"
|
||
echo -e "${B} WHITELIST PROBE v1.0 — $(date '+%Y-%m-%d %H:%M')${N}"
|
||
echo -e "${B}══════════════════════════════════════════${N}"
|
||
|
||
install_deps
|
||
|
||
test_provider
|
||
test_icmp
|
||
test_dns
|
||
test_dns_tunnel
|
||
test_tcp_our_servers
|
||
test_udp
|
||
test_https
|
||
test_sni
|
||
test_cdn
|
||
test_advanced
|
||
recommendations
|
||
save_results
|
||
|
||
echo ""
|
||
echo -e "${B}══════════════════════════════════════════${N}"
|
||
echo -e " Тестов: $TOTAL ${G}✓ $PASS${N} ${R}✗ $FAIL${N}"
|
||
echo -e "${B}══════════════════════════════════════════${N}"
|
||
}
|
||
|
||
main "$@"
|