Загрузка данных


import os
import sys
import ctypes
import subprocess
import json
import socket
import customtkinter as ctk

# Имя файла для сохранения настроек
CONFIG_FILE = "dns_settings.json"

class FerrariDNS(ctk.CTk):
    def __init__(self):
        super().__init__()
        
        # Настройка окна
        self.title("Ferrari Private DNS Control")
        self.geometry("450x520")
        ctk.set_appearance_mode("dark")

        # Загрузка конфига
        self.config = self.load_config()

        # Заголовок
        self.label = ctk.CTkLabel(self, text="PRIVATE DNS (WIN 11)", font=("Arial", 22, "bold"))
        self.label.pack(pady=20)

        # Поле ввода
        self.dns_input = ctk.CTkEntry(self, width=350, placeholder_text="Например: dns.comss.one")
        self.dns_input.pack(pady=10)
        self.dns_input.insert(0, self.config.get("dns_url", "dns.comss.one"))

        # Статус
        self.status_label = ctk.CTkLabel(self, text=f"Статус: {self.config.get('status', 'Ожидание')}", text_color="gray")
        self.status_label.pack(pady=5)

        # Кнопки
        self.btn_on = ctk.CTkButton(self, text="ВКЛЮЧИТЬ (DOH)", fg_color="#28a745", hover_color="#218838", command=self.activate)
        self.btn_on.pack(pady=12)

        self.btn_off = ctk.CTkButton(self, text="СБРОСИТЬ НА АВТО", fg_color="#dc3545", hover_color="#c82333", command=self.reset)
        self.btn_off.pack(pady=12)

        # Автозагрузка
        self.auto_run_var = ctk.BooleanVar(value=self.config.get("auto_run", False))
        self.check_auto = ctk.CTkCheckBox(self, text="Запускать вместе с Windows", variable=self.auto_run_var, command=self.toggle_autorun)
        self.check_auto.pack(pady=25)

    def load_config(self):
        if os.path.exists(CONFIG_FILE):
            try:
                with open(CONFIG_FILE, "r") as f:
                    return json.load(f)
            except:
                pass
        return {"dns_url": "dns.comss.one", "status": "Отключено", "auto_run": False}

    def save_config(self, status):
        config_data = {
            "dns_url": self.dns_input.get(),
            "status": status,
            "auto_run": self.auto_run_var.get()
        }
        with open(CONFIG_FILE, "w") as f:
            json.dump(config_data, f)

    def get_adapter_name(self):
        try:
            # Магия PowerShell для поиска активного интернета
            cmd = 'powershell "(Get-NetAdapter | Where-Object {$_.Status -eq \'Up\'} | Select-Object -First 1).Name"'
            name = subprocess.check_output(cmd, shell=True).decode('cp866').strip()
            return name if name else "Ethernet"
        except:
            return "Ethernet"

    def activate(self):
        raw_dns = self.dns_input.get().strip()
        adapter = self.get_adapter_name()
        self.status_label.configure(text="Применяем настройки...", text_color="yellow")
        
        try:
            # 1. Готовим данные
            host = raw_dns.replace("https://", "").split("/")[0]
            ip = socket.gethostbyname(host)
            doh_url = raw_dns if "://" in raw_dns else f"https://{raw_dns}/dns-query"

            # 2. Прописываем IP в систему
            subprocess.run(f'powershell "Set-DnsClientServerAddress -InterfaceAlias \'{adapter}\' -ServerAddresses {ip}"', shell=True)

            # 3. Регистрируем DoH сервер (чтобы Windows знала этот шаблон)
            subprocess.run(f'powershell "Add-DnsClientDohServerAddress -ServerAddress {ip} -DohTemplate \'{doh_url}\' -AllowFallbackToUdp $false -ErrorAction SilentlyContinue"', shell=True)

            # 4. ФОРСИРУЕМ ШИФРОВАНИЕ ЧЕРЕЗ РЕЕСТР (Для Win 11 это 100% метод)
            # EnableAutoDoh = 2 заставляет Windows использовать только зашифрованный DNS
            reg_path = r"HKLM\SYSTEM\CurrentControlSet\Services\Dnscache\Parameters"
            subprocess.run(f'reg add "{reg_path}" /v EnableAutoDoh /t REG_DWORD /d 2 /f', shell=True)

            # Очистка кэша
            subprocess.run('ipconfig /flushdns', shell=True)
            
            self.status_label.configure(text=f"АКТИВНО: {host}", text_color="#28a745")
            self.save_config("Активно")
        except Exception as e:
            self.status_label.configure(text=f"Ошибка: {str(e)[:30]}...", text_color="#dc3545")

    def reset(self):
        adapter = self.get_adapter_name()
        try:
            subprocess.run(f'powershell "Set-DnsClientServerAddress -InterfaceAlias \'{adapter}\' -ResetServerAddresses"', shell=True)
            
            # Возвращаем стандартное поведение DNS (шифрование по возможности или выключено)
            reg_path = r"HKLM\SYSTEM\CurrentControlSet\Services\Dnscache\Parameters"
            subprocess.run(f'reg add "{reg_path}" /v EnableAutoDoh /t REG_DWORD /d 0 /f', shell=True)
            
            subprocess.run('ipconfig /flushdns', shell=True)
            self.status_label.configure(text="Статус: Сброшено", text_color="white")
            self.save_config("Отключено")
        except:
            self.status_label.configure(text="Ошибка сброса", text_color="#dc3545")

    def toggle_autorun(self):
        path = os.path.realpath(sys.argv[0])
        key = r"Software\Microsoft\Windows\CurrentVersion\Run"
        if self.auto_run_var.get():
            subprocess.run(f'reg add "HKEY_CURRENT_USER\\{key}" /v "FerrariDNS" /t REG_SZ /d "{path}" /f', shell=True)
        else:
            subprocess.run(f'reg delete "HKEY_CURRENT_USER\\{key}" /v "FerrariDNS" /f', shell=True)
        self.save_config(self.config.get("status", "Отключено"))

# ТОТ САМЫЙ БЛОК С ПОДЧЕРКИВАНИЯМИ - ПРОВЕРЬ ИХ!
if __name__ == "__main__":
    # Если запущен не от админа - перезапускаем с правами
    if not ctypes.windll.shell32.IsUserAnAdmin():
        ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, f'"{__file__}"', None, 1)
    else:
        app = FerrariDNS()
        app.mainloop()