commit 36625bc115759e5561cefbd5934bf0f4bad53f12 Author: aedes Date: Sun Mar 22 16:23:45 2026 +0300 probe v1.0: whitelist bypass detection for Termux diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fbca225 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +results/ diff --git a/probe.sh b/probe.sh new file mode 100644 index 0000000..dbf5bd8 --- /dev/null +++ b/probe.sh @@ -0,0 +1,705 @@ +#!/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-ncat) + command -v openssl >/dev/null || missing+=(openssl-tool) + command -v nslookup >/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 "$@"