# dnsleak-guard Страж системного DNS для macOS. Автоматически возвращает DNS на `127.0.0.1`, если сторонняя программа (например, Clash Verge Rev) его перезаписывает. ## 📖 Зачем это нужно **Clash Verge Rev** при запуске в режиме TUN принудительно прописывает `114.114.114.114` (китайский публичный DNS) в системные настройки macOS. Это приводит к: - **Утечке DNS** — провайдер перехватывает запросы к `114.114.114.114` и подставляет свои резолверы. - **Рассинхрону** — часть DNS-запросов идёт через Clash TUN, часть — мимо. `dnsleak-guard` решает проблему: LaunchDaemon раз в 10 секунд проверяет системный DNS и возвращает его на `127.0.0.1`, где его перехватывает Clash TUN. ## 📂 Состав | Файл | Назначение | |---|---| | `ensure_dns.sh` | Основной скрипт-страж. Работает от root, бесконечный цикл | | `com.user.dnsleak-guard.plist` | LaunchDaemon для автозапуска при загрузке | | `install.sh` | Скрипт автоустановки | ## 🔧 Требования - macOS 11+ (Big Sur и новее) - **Clash Verge Rev** или другой клиент в режиме TUN - `dns.listen` в конфиге Clash должен слушать порт **53** (например, `0.0.0.0:53`) - Права root (для `networksetup -setdnsservers`) ## 📥 Установка ### Автоматическая ```bash WIP ``` ### Ручная ```bash # 1. Скрипт sudo cp ensure_dns.sh /usr/local/bin/ensure_dns.sh sudo chmod +x /usr/local/bin/ensure_dns.sh sudo chown root:wheel /usr/local/bin/ensure_dns.sh # 2. LaunchDaemon sudo cp com.user.dnsleak-guard.plist /Library/LaunchDaemons/ sudo chown root:wheel /Library/LaunchDaemons/com.user.dnsleak-guard.plist sudo chmod 644 /Library/LaunchDaemons/com.user.dnsleak-guard.plist # 3. Загрузить sudo launchctl load /Library/LaunchDaemons/com.user.dnsleak-guard.plist # 4. Проверить sudo launchctl list | grep dnsleak-guard ``` ## 🚀 Использование После установки демон работает автоматически: - Запускается при загрузке системы (до логина пользователя). - Каждые 10 секунд проверяет DNS на всех активных сетевых сервисах. - Если DNS отличается от `127.0.0.1` — сбрасывает его и очищает DNS-кэш macOS. - Пишет события в `/tmp/dnsleak-guard.log`. ### Проверка состояния ```bash # Демон запущен? sudo launchctl list | grep dnsleak-guard # Текущий системный DNS scutil --dns | grep nameserver # Должно быть: nameserver[0] : 127.0.0.1 # Логи работы tail -20 /tmp/dnsleak-guard.log ``` ### Ожидаемые логи ``` [2026-09-14 18:30:01] dnsleak-guard started [2026-09-14 18:30:05] [Wi-Fi] DNS reset: '114.114.114.114' -> 127.0.0.1 [2026-09-14 18:30:05] DNS cache flushed ``` Если в логах только `dnsleak-guard started` — значит, Clash не перезаписывает DNS, и страж просто ждёт. ## 🛑 Управление ```bash # Остановить sudo launchctl unload /Library/LaunchDaemons/com.user.dnsleak-guard.plist # Запустить sudo launchctl load /Library/LaunchDaemons/com.user.dnsleak-guard.plist # Перезапустить (после правки скрипта) sudo launchctl unload /Library/LaunchDaemons/com.user.dnsleak-guard.plist sudo launchctl load /Library/LaunchDaemons/com.user.dnsleak-guard.plist ``` ### Полное удаление ```bash sudo launchctl unload /Library/LaunchDaemons/com.user.dnsleak-guard.plist sudo rm /Library/LaunchDaemons/com.user.dnsleak-guard.plist sudo rm /usr/local/bin/ensure_dns.sh sudo rm -f /tmp/dnsleak-guard.log /tmp/dnsleak-guard.out /tmp/dnsleak-guard.err # Вернуть автоматический DNS sudo networksetup -setdnsservers Wi-Fi "Empty" sudo networksetup -setdnsservers Ethernet "Empty" 2>/dev/null sudo dscacheutil -flushcache sudo killall -HUP mDNSResponder ``` ## ⚙️ Конфигурация Параметры задаются в начале `ensure_dns.sh`: ```bash DNS_SERVER="127.0.0.1" # Целевой DNS-сервер LOG_FILE="/tmp/dnsleak-guard.log" # Путь к логу sleep 10 # Интервал проверки (в конце скрипта) ``` ### Изменить интервал | Значение | Эффект | |---|---| | `sleep 5` | Быстрее реагирует, больше нагрузки | | `sleep 10` | Компромисс (по умолчанию) | | `sleep 30` | Реже проверяет, тише логи | | `sleep 60` | Минимальная нагрузка | ## 🐛 Решение проблем ### Демон не запускается ```bash sudo launchctl list | grep dnsleak-guard cat /tmp/dnsleak-guard.err ``` Если пусто — загрузите принудительно: ```bash sudo launchctl load -w /Library/LaunchDaemons/com.user.dnsleak-guard.plist ``` ### Логи переполнены ошибками «X is not a recognized network service» Это псевдо-сервисы (Thunderbolt Bridge и т.д.). Убедитесь, что в скрипте используется `while IFS= read -r service`, а не `for service in $(...)`. Обновите скрипт: ```bash git pull sudo cp ensure_dns.sh /usr/local/bin/ensure_dns.sh sudo launchctl unload /Library/LaunchDaemons/com.user.dnsleak-guard.plist sudo launchctl load /Library/LaunchDaemons/com.user.dnsleak-guard.plist ``` ### DNS всё равно утекает **1. Проверьте, что Clash слушает порт 53:** ```bash sudo lsof -iTCP:53 -iUDP:53 | grep -iE "clash|mihomo" ``` Если пусто — в конфиге Clash замените `dns.listen` на `0.0.0.0:53`. **2. Отключите DoH в браузерах:** - Chrome: `chrome://settings/security` → «Использовать безопасный DNS» → **ВЫКЛ** - Firefox: `about:preferences#privacy` → «Enable DNS over HTTPS» → **ВЫКЛ** **3. Сбросьте DNS-кэш:** ```bash sudo dscacheutil -flushcache sudo killall -HUP mDNSResponder ``` **4. Проверьте через `dnsleaktest.com` → Extended Test.** Должен быть только IP вашего VPS. ### Интернет пропадает после установки Скорее всего, **Clash не слушает порт 53**, а системный DNS указывает на `127.0.0.1`, где никто не отвечает. **Быстрое восстановление:** ```bash sudo networksetup -setdnsservers Wi-Fi "Empty" sudo dscacheutil -flushcache sudo killall -HUP mDNSResponder ``` Затем исправьте `dns.listen` в Clash. ## 📊 Как это работает ``` ┌─────────────────────────────────────────────────────────┐ │ macOS │ │ ┌───────────────────────────────────────────────────┐ │ │ │ Системный DNS = 127.0.0.1 │ │ │ └──────────────────┬────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌───────────────────────────────────────────────────┐ │ │ │ Clash TUN (utun) слушает 53 │ │ │ │ dns-hijack: any:53 │ │ │ └──────────────────┬────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌───────────────────────────────────────────────────┐ │ │ │ DNS → VLESS-туннель → VPS → CoreDNS │ │ │ └───────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────┘ ┌─────────────────────────────────────────────────────────┐ │ LaunchDaemon com.user.dnsleak-guard │ │ ├── Каждые 10 сек: проверяет DNS на всех сервисах │ │ ├── Если DNS ≠ 127.0.0.1: │ │ │ ├── networksetup -setdnsservers │ │ │ └── dscacheutil -flushcache + killall mDNSResponder│ │ └── Логи в /tmp/dnsleak-guard.log │ └─────────────────────────────────────────────────────────┘ ``` ## 🔐 Безопасность - Работает **от root** — необходимо для `networksetup -setdnsservers`. - Не принимает внешних команд, только меняет DNS на заранее заданный `127.0.0.1`. - Не передаёт данные наружу — вся работа локальная. - Логи содержат только имена сервисов и их DNS — никакой чувствительной информации. ## 📝 Лицензия MIT. ## 🤝 Вклад Pull request'ы приветствуются. Особенно интересны: - Уведомления через Telegram / macOS Notification Center при сбросе DNS. - Ротация логов. - Совместимость с другими клиентами (ClashX Pro, sing-box, Stash).