#!/data/data/com.termux/files/usr/bin/bash # ══════════════════════════════════════════════════════ # WHITELIST PROBE v1.1 # Определяет доступные методы обхода whitelist # Платформа: Termux (Android) / Linux # Зависимости: curl, nc (ncat), openssl, dig/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=5 # секунд на каждый тест RESULT_DIR="./results" TIMESTAMP=$(date '+%Y-%m-%d_%H-%M-%S') 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 W='\033[0;37m' # white/dim N='\033[0m' # reset else G='' R='' Y='' C='' B='' W='' N='' fi # ── Счётчики ────────────────────────────────────────── declare -A RESULTS TOTAL=0 PASS=0 FAIL=0 SKIP=0 # Список SNI, по которым обнаружена фильтрация declare -a FILTERED_SNIS=() # ── Утилиты ─────────────────────────────────────────── ok() { echo -e " ${G}✓${N} $1"; RESULTS["$2"]="ok"; ((PASS++)); ((TOTAL++)); } fail() { echo -e " ${R}✗${N} $1"; RESULTS["$2"]="fail"; ((FAIL++)); ((TOTAL++)); } warn() { echo -e " ${Y}▲${N} $1"; RESULTS["$2"]="warn"; ((TOTAL++)); } skip() { echo -e " ${Y}—${N} $1"; RESULTS["$2"]="skip"; ((SKIP++)); ((TOTAL++)); } info() { echo -e " ${C}ℹ${N} $1"; } hdr() { echo -e "\n${B}[$1]${N}"; } # Ping с таймаутом (2 попытки, успех если хотя бы одна прошла) do_ping() { local host=$1 local result result=$(ping -c 2 -W $TIMEOUT "$host" 2>/dev/null | grep -oP 'time=\K[0-9.]+' | tail -1) 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 — отправка WireGuard handshake initiation (тип 1) # WG отвечает cookie reply на невалидный handshake, что позволяет # подтвердить прохождение UDP-пакетов do_udp_wg() { local host=$1 port=$2 # WG handshake initiation: type=1(LE32), sender=0x12345678, rest zeros (148 байт) # Генерируем бинарный пакет через printf напрямую в pipe (без переменных — bash не хранит \x00) { printf '\x01\x00\x00\x00\x78\x56\x34\x12' dd if=/dev/zero bs=1 count=140 2>/dev/null } | timeout $TIMEOUT nc -u -w 2 "$host" "$port" 2>/dev/null | head -c 1 | grep -qP '.' 2>/dev/null return $? } # HTTPS test — один запрос, возвращает "код HTTP/версия" do_https() { local host=$1 local raw raw=$(curl -s -o /dev/null -w '%{http_code} %{http_version}' \ --connect-timeout $TIMEOUT --max-time $((TIMEOUT+2)) \ "https://$host" 2>/dev/null) local code="${raw%% *}" local ver="${raw##* }" if [ "$code" -ge 100 ] 2>/dev/null && [ "$code" -lt 600 ] 2>/dev/null; then echo "$code HTTP/$ver" return 0 fi return 1 } # DNS resolve — предпочитает dig, фолбэк на nslookup do_resolve() { local domain=$1 server=$2 local result if command -v dig >/dev/null 2>&1; then if [ -n "$server" ]; then result=$(dig +short +time=$TIMEOUT +tries=1 "$domain" A "@$server" 2>/dev/null | grep -oP '^[0-9.]+' | head -1) else result=$(dig +short +time=$TIMEOUT +tries=1 "$domain" A 2>/dev/null | grep -oP '^[0-9.]+' | head -1) fi else if [ -n "$server" ]; then result=$(nslookup "$domain" "$server" 2>/dev/null | awk '/^Address:/{a=$2} /Name:/{found=1} found && /Address:/{print $2; exit}') else result=$(nslookup "$domain" 2>/dev/null | awk '/^Address:/{a=$2} /Name:/{found=1} found && /Address:/{print $2; exit}') fi 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 $? } # ══════════════════════════════════════════════════════ # УСТАНОВКА ЗАВИСИМОСТЕЙ # ══════════════════════════════════════════════════════ 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 ping >/dev/null || missing+=(inetutils) # dig предпочтителен, но nslookup тоже подойдёт if ! command -v dig >/dev/null 2>&1; then command -v nslookup >/dev/null || missing+=(dnsutils) fi 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)" info "2 попытки на хост, таймаут ${TIMEOUT}с" 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" 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 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 echo "" r=$(do_resolve "$DNSTT_DOMAIN") if [ $? -eq 0 ]; then ok "DNSTT domain $DNSTT_DOMAIN → $r" "dns_dnstt" else local ns_result if command -v dig >/dev/null 2>&1; then ns_result=$(dig +short +time=$TIMEOUT NS "$DNSTT_DOMAIN" 2>/dev/null) else ns_result=$(nslookup -type=NS "$DNSTT_DOMAIN" 2>/dev/null | grep -i "nameserver" | head -1) fi 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" local r # DoH Яндекс 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:553 (OVPNCloak)"]="$VPS_IP:553" ["VPS:38246 (SS)"]="$VPS_IP:38246" ["VPS:43781 (SOCKS5)"]="$VPS_IP:43781" ["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:553 (OVPNCloak)" "VPS:38246 (SS)" "VPS:43781 (SOCKS5)" "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" # DNS (порт 53) — реальный DNS-запрос info "DNS-запрос к VPS:53" local dns_r dns_r=$(do_resolve "yandex.ru" "$VPS_IP") if [ $? -eq 0 ]; then ok "$(printf '%-25s (DNS ответил: %s)' "VPS:53 (DNSTT)" "$dns_r")" "udp_VPS:53 (DNSTT)" else fail "$(printf '%-25s' "VPS:53 (DNSTT)")" "udp_VPS:53 (DNSTT)" fi # QUIC (порт 443) — через curl --http3 если поддерживается info "QUIC к VPS:443" local quic_ver quic_ver=$(curl -s -o /dev/null -w '%{http_version}' \ --connect-timeout $TIMEOUT --max-time $((TIMEOUT+2)) \ --http3-only "https://$VPS_IP" 2>/dev/null) if [ "$quic_ver" = "3" ]; then ok "$(printf '%-25s HTTP/3 работает' "VPS:443 (QUIC)")" "udp_VPS:443 (QUIC)" else # Фолбэк: отправляем UDP-пакет, проверяем что nc не получил ICMP unreachable echo -n "test" | timeout 2 nc -u -w 1 "$VPS_IP" 443 >/dev/null 2>&1 skip "$(printf '%-25s (curl без HTTP/3, UDP отправлен)' "VPS:443 (QUIC)")" "udp_VPS:443 (QUIC)" fi # WireGuard / AmneziaWG — отправляем WG handshake init info "WireGuard handshake init" local -A wg_ports=( ["VPS:43742 (WG)"]="43742" ["VPS:47426 (AWG)"]="47426" ["VPS:48253 (AWG2)"]="48253" ) local wg_order=("VPS:43742 (WG)" "VPS:47426 (AWG)" "VPS:48253 (AWG2)") for name in "${wg_order[@]}"; do local port="${wg_ports[$name]}" if do_udp_wg "$VPS_IP" "$port"; then ok "$(printf '%-25s (WG ответил)' "$name")" "udp_$name" else # nc не получил ICMP port unreachable — пакет, вероятно, дошёл echo -n "test" | timeout 2 nc -u -w 1 "$VPS_IP" "$port" >/dev/null 2>&1 local nc_rc=$? if [ $nc_rc -eq 0 ]; then skip "$(printf '%-25s (отправлено, нет ответа)' "$name")" "udp_$name" else fail "$(printf '%-25s (UDP заблокирован)' "$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.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 result result=$(do_https "$target") if [ $? -eq 0 ]; then ok "$(printf '%-28s %s' "$name" "$result")" "https_$name" else fail "$(printf '%-28s' "$name")" "https_$name" fi done } # Кросс-валидация: ICMP ✗ но HTTPS ✓ → предупредить test_icmp_crosscheck() { hdr "ICMP КРОСС-ВАЛИДАЦИЯ" info "Сайты с ICMP ✗ но HTTPS ✓ (блокируют ping, но работают)" local found=0 local icmp_sites=("yandex.ru" "ya.ru" "vk.com" "mail.ru" "ok.ru" "sber.ru" "gosuslugi.ru" "mos.ru") for name in "${icmp_sites[@]}"; do if [ "${RESULTS[icmp_$name]}" = "fail" ] && [ "${RESULTS[https_$name]}" = "ok" ]; then warn "$(printf '%-22s ICMP блокирован сервером, HTTPS работает' "$name")" "crosscheck_$name" found=1 fi done if [ "$found" -eq 0 ]; then info "Расхождений не найдено" fi } 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" "cloudflare.com" "telegram.org" "$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 → DPI фильтрует!' "$sni")" "sni_$sni" FILTERED_SNIS+=("$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 → DPI фильтрует!' "$sni")" "sni_moscow_$sni" FILTERED_SNIS+=("$sni") fi done if [ ${#FILTERED_SNIS[@]} -gt 0 ]; then echo "" info "${Y}⚠ Обнаружена SNI-фильтрация: ${FILTERED_SNIS[*]}${N}" info "DPI провайдера блокирует TLS к чужим IP с этими SNI" info "Для Reality/VLESS избегайте этих доменов как маскировочных" fi } 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") local cf_ok=0 local cf_total=${#cf_ips[@]} 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" ((cf_ok++)) else fail "$(printf '%-22s' "$ip")" "cdn_cf_$ip" fi done if [ "$cf_ok" -gt 0 ] && [ "$cf_ok" -lt "$cf_total" ]; then info "${Y}⚠ Частичная блокировка Cloudflare: $cf_ok/$cf_total диапазонов доступны${N}" RESULTS["cf_partial_block"]="true" fi 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 — тестируем к VPS, а не к Яндексу info "WebSocket upgrade к VPS ($VPS_IP:443)" local ws_code ws_code=$(curl -s -o /dev/null -w '%{http_code}' --connect-timeout $TIMEOUT -k \ -H "Upgrade: websocket" -H "Connection: Upgrade" \ -H "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==" \ -H "Sec-WebSocket-Version: 13" \ "https://$VPS_IP" 2>/dev/null) if [ "$ws_code" = "101" ]; then ok "WebSocket VPS → 101 Switching Protocols" "ws_vps" elif [ "$ws_code" -ge 100 ] 2>/dev/null && [ "$ws_code" -lt 600 ] 2>/dev/null; then warn "WebSocket VPS → $ws_code (сервер не поддерживает WS upgrade)" "ws_vps" else fail "WebSocket VPS → нет ответа (DPI или сервер)" "ws_vps" 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_out ech_out=$(echo | timeout $TIMEOUT openssl s_client -connect cloudflare.com:443 \ -ech grease 2>&1) if echo "$ech_out" | grep -qi "ech.*accepted\|ECH.*status.*success"; then ok "ECH → принят сервером" "ech" elif echo "$ech_out" | grep -qi "ech"; then warn "ECH → openssl знает ECH, но GREASE (не настоящий ECH)" "ech" else skip "ECH → openssl не поддерживает ECH" "ech" fi } # ══════════════════════════════════════════════════════ # РЕКОМЕНДАЦИИ # ══════════════════════════════════════════════════════ recommendations() { hdr "РЕКОМЕНДАЦИИ" echo "" local rec_detail=() local warnings=() # Собираем предупреждения if [ "${RESULTS[cf_partial_block]}" = "true" ]; then warnings+=("⚠ Cloudflare частично заблокирован — CDN-туннели могут быть нестабильны") fi if [ ${#FILTERED_SNIS[@]} -gt 0 ]; then warnings+=("⚠ SNI-фильтрация: ${FILTERED_SNIS[*]} — Reality должен использовать безопасные SNI") fi # Определяем безопасные SNI для Reality local safe_sni_note="" if [ ${#FILTERED_SNIS[@]} -gt 0 ]; then local safe_snis=() for sni in "yandex.ru" "ya.ru" "mail.ru" "google.com" "cloudflare.com"; do local filtered=0 for f in "${FILTERED_SNIS[@]}"; do [ "$sni" = "$f" ] && filtered=1 && break done [ "$filtered" -eq 0 ] && [ "${RESULTS[sni_$sni]}" = "ok" ] && safe_snis+=("$sni") done if [ ${#safe_snis[@]} -gt 0 ]; then safe_sni_note=" (безопасные SNI: ${safe_snis[*]})" fi fi # S-тир: CDN tunnel через Cloudflare if [ "${RESULTS[https_cloudflare.com]}" = "ok" ] || [ "${RESULTS[cdn_cf_104.16.0.1]}" = "ok" ]; then local cf_note="CF доступен, быстро и надёжно" [ "${RESULTS[cf_partial_block]}" = "true" ] && cf_note="CF частично доступен, возможна нестабильность" rec_detail+=("${G}S-тир${N} │ VLESS + WebSocket + Cloudflare CDN │ $cf_note") fi # S-тир: CDN через jsDelivr if [ "${RESULTS[https_cdn.jsdelivr.net]}" = "ok" ]; then rec_detail+=("${G}S-тир${N} │ CDN-туннель через jsDelivr │ CDN доступен") fi # S-тир: Direct VLESS + Reality if [ "${RESULTS[tcp_VPS:443 (VLESS)]}" = "ok" ]; then rec_detail+=("${G}S-тир${N} │ VLESS + XHTTP + Reality (прямой) │ TCP к VPS:443 открыт${safe_sni_note}") fi # A-тир: Moscow relay if [ "${RESULTS[tcp_Moscow:2053 (relay)]}" = "ok" ]; then rec_detail+=("${Y}A-тир${N} │ VLESS через Moscow relay │ TCP к Москве:2053 открыт") fi # A-тир: Shadowsocks if [ "${RESULTS[tcp_VPS:38246 (SS)]}" = "ok" ]; then rec_detail+=("${Y}A-тир${N} │ Shadowsocks │ TCP к VPS:38246 открыт") fi # A-тир: OpenVPN + Cloak if [ "${RESULTS[tcp_VPS:553 (OVPNCloak)]}" = "ok" ]; then rec_detail+=("${Y}A-тир${N} │ OpenVPN + Cloak │ TCP к VPS:553 открыт") fi # B-тир: SOCKS5 proxy (без обфускации, легко детектится DPI) if [ "${RESULTS[tcp_VPS:43781 (SOCKS5)]}" = "ok" ]; then rec_detail+=("${C}B-тир${N} │ SOCKS5 proxy (без обфускации) │ TCP к VPS:43781 открыт") fi # A-тир: Hysteria2 / QUIC if [ "${RESULTS[udp_VPS:443 (QUIC)]}" = "ok" ]; then rec_detail+=("${Y}A-тир${N} │ Hysteria2 + Salamander (UDP) │ UDP QUIC к VPS работает") fi # B-тир: WireGuard / AmneziaWG if [ "${RESULTS[udp_VPS:43742 (WG)]}" = "ok" ] || [ "${RESULTS[udp_VPS:47426 (AWG)]}" = "ok" ] || [ "${RESULTS[udp_VPS:48253 (AWG2)]}" = "ok" ]; then rec_detail+=("${C}B-тир${N} │ AmneziaWG / WireGuard │ UDP к VPS работает") fi # B-тир: Chisel if [ "${RESULTS[tcp_VPS:8443 (Chisel)]}" = "ok" ]; then rec_detail+=("${C}B-тир${N} │ Chisel (HTTP tunnel) │ TCP к VPS:8443 открыт") fi # B-тир: Yandex Cloud Functions if [ "${RESULTS[https_functions.yandexcloud.net]}" = "ok" ]; then 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_detail+=("${C}B-тир${N} │ DNSTT (DNS-туннель) │ DNS работает, ~50-100 Кбит/с") fi # C-тир: ICMP tunnel if [ "${RESULTS[icmp_VPS Ирландия]}" = "ok" ] || [ "${RESULTS[icmp_Москва relay]}" = "ok" ]; then rec_detail+=("${R}C-тир${N} │ ICMP tunnel (ptunnel-ng) │ Ping к серверу, очень медленно") fi # Вывод предупреждений if [ ${#warnings[@]} -gt 0 ]; then for w in "${warnings[@]}"; do echo -e " ${Y}$w${N}" done echo "" 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 } # ══════════════════════════════════════════════════════ # СОХРАНЕНИЕ РЕЗУЛЬТАТОВ (безопасный JSON) # ══════════════════════════════════════════════════════ save_results() { mkdir -p "$RESULT_DIR" # Экранирование для JSON json_escape() { local s="$1" s="${s//\\/\\\\}" s="${s//\"/\\\"}" s="${s//$'\n'/\\n}" s="${s//$'\t'/\\t}" echo -n "$s" } { echo "{" echo " \"version\": \"1.1\"," echo " \"timestamp\": \"$TIMESTAMP\"," echo " \"filtered_snis\": [$(printf '"%s",' "${FILTERED_SNIS[@]}" | sed 's/,$//' )]," echo " \"results\": {" local first=true for key in $(echo "${!RESULTS[@]}" | tr ' ' '\n' | sort); do if [ "$first" = true ]; then first=false else echo "," fi printf ' "%s": "%s"' "$(json_escape "$key")" "$(json_escape "${RESULTS[$key]}")" done echo "" echo " }" echo "}" } > "$JSON_FILE" info "Результаты: $JSON_FILE" } # ══════════════════════════════════════════════════════ # MAIN # ══════════════════════════════════════════════════════ main() { echo -e "${B}══════════════════════════════════════════${N}" echo -e "${B} WHITELIST PROBE v1.1 — $(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_icmp_crosscheck test_sni test_cdn test_advanced recommendations save_results echo "" echo -e "${B}══════════════════════════════════════════${N}" echo -e " Тестов: $TOTAL ${G}✓ $PASS${N} ${R}✗ $FAIL${N} ${Y}— $SKIP${N}" echo -e "${B}══════════════════════════════════════════${N}" } main "$@"