DoH / main.py
Sk0lovek's picture
Update main.py
917ac41 verified
Raw
History Blame Contribute Delete
6.52 kB
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: Нет рабочих прокси.")