import os import requests import json import subprocess import time import socket import base64 from flask import Flask, request, Response # Ссылка на файл PROXY_LIST_URL = "https://raw.githubusercontent.com/igareck/vpn-configs-for-russia/refs/heads/main/BLACK_SS%2BAll_RUS.txt" # Проверочный URL TEST_URL = "https://www.google.com" app = Flask(__name__) def safe_base64_decode(s): padding = 4 - (len(s) % 4) if padding != 4: s += "=" * padding return base64.urlsafe_b64decode(s).decode('utf-8') def parse_ss(ss_link): try: link = ss_link.replace("ss://", "") if "#" in link: link = link.split("#")[0] if "@" not in link: return None user_info_b64, host_port = link.split("@", 1) try: user_info = safe_base64_decode(user_info_b64) except: user_info = user_info_b64 method, password = user_info.split(":", 1) host_str, port_str = host_port.rsplit(":", 1) port = int(port_str.split("?")[0]) return { "address": host_str, "port": port, "method": method, "password": password, "uot": False # Отключаем UDP over TCP, будем использовать чистый TCP } except: return None # --- СОЗДАНИЕ КОНФИГА XRAY (ТОЛЬКО TCP) --- def create_config(server_obj): config = { "log": {"loglevel": "warning"}, "inbounds": [ # Вход для DoH (ТЕПЕРЬ TCP!) # Мы пересылаем трафик на 8.8.8.8:53, но строго по TCP { "port": 5353, "protocol": "dokodemo-door", "settings": {"network": "tcp", "address": "8.8.8.8", "port": 53}, "tag": "dns-in" }, # Вход для ПРОВЕРКИ (SOCKS5 TCP) { "port": 10808, "protocol": "socks", "settings": {"auth": "noauth", "udp": False}, "tag": "check-in" } ], "outbounds": [ { "protocol": "shadowsocks", "settings": {"servers": [server_obj]}, "tag": "proxy" }, {"protocol": "freedom", "tag": "direct"} ], "routing": { "rules": [ {"type": "field", "inboundTag": ["dns-in", "check-in"], "outboundTag": "proxy"} ] } } with open("config.json", "w") as f: json.dump(config, f, indent=4) # --- ПРОВЕРКА ПРОКСИ --- def check_proxy(): print("Проверка соединения через прокси...") proxies = { 'http': 'socks5h://127.0.0.1:10808', 'https': 'socks5h://127.0.0.1:10808' } try: r = requests.get(TEST_URL, proxies=proxies, timeout=5) if r.status_code == 200: return True except Exception as e: print(f"Тест провален: {e}") return False # --- ПОИСК РАБОЧЕГО КЛЮЧА --- def find_working_proxy(): print("Скачивание списка...") try: r = requests.get(PROXY_LIST_URL) lines = r.text.splitlines() except: print("Ошибка сети при скачивании листа") return False candidates = [] for line in lines: if line.strip().startswith("ss://"): parsed = parse_ss(line.strip()) if parsed: candidates.append(parsed) print(f"Найдено {len(candidates)} ключей Shadowsocks. Начинаем перебор...") xray_process = None # Лимит проверок, чтобы не зависнуть навсегда (проверим первые 20) for i, server in enumerate(candidates[:20]): print(f"[{i+1}] Тестируем: {server['address']}...") create_config(server) if xray_process: xray_process.terminate() xray_process.wait() xray_process = subprocess.Popen(["/usr/local/bin/xray", "run", "-c", "config.json"]) time.sleep(2) if check_proxy(): print(f"✅ УСПЕХ! Рабочий сервер найден: {server['address']}") return True else: print("❌ Не работает.") if xray_process: xray_process.terminate() return False # --- FLASK (TCP DNS) --- @app.route("/dns-query", methods=["GET", "POST"]) def dns_query(): # 1. Получаем сырые байты запроса if request.method == "POST": dns_msg = request.data else: dns_base64 = request.args.get("dns") if not dns_base64: return "Error", 400 padding = 4 - (len(dns_base64) % 4) if padding != 4: dns_base64 += "=" * padding try: dns_msg = base64.urlsafe_b64decode(dns_base64) except: return "Invalid B64", 400 # 2. Отправляем в Xray по TCP (RFC 1035 требует 2 байта длины перед пакетом) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeout(5) try: sock.connect(("127.0.0.1", 5353)) # Добавляем длину пакета (2 байта Big Endian) length_bytes = len(dns_msg).to_bytes(2, byteorder='big') sock.sendall(length_bytes + dns_msg) # Читаем длину ответа (первые 2 байта) resp_len_bytes = sock.recv(2) if not resp_len_bytes: return "Empty response from DNS", 502 resp_len = int.from_bytes(resp_len_bytes, byteorder='big') # Читаем сам ответ response_data = b"" while len(response_data) < resp_len: chunk = sock.recv(resp_len - len(response_data)) if not chunk: break response_data += chunk return Response(response_data, mimetype="application/dns-message") except Exception as e: return f"DNS TCP Error: {e}", 502 finally: sock.close() @app.route("/") def index(): return "DoH Server (TCP Mode) Running." if __name__ == "__main__": if find_working_proxy(): app.run(host="0.0.0.0", port=7860) else: print("FATAL: Нет рабочих прокси.")