https://dev.kronoz.win/r/awesome-scripts.git
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)
📥 Установка
Автоматическая
WIP
Ручная
# 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.
Проверка состояния
# Демон запущен?
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, и страж просто ждёт.
🛑 Управление
# Остановить
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
Полное удаление
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:
DNS_SERVER="127.0.0.1" # Целевой DNS-сервер
LOG_FILE="/tmp/dnsleak-guard.log" # Путь к логу
sleep 10 # Интервал проверки (в конце скрипта)
Изменить интервал
| Значение | Эффект |
|---|---|
sleep 5 |
Быстрее реагирует, больше нагрузки |
sleep 10 |
Компромисс (по умолчанию) |
sleep 30 |
Реже проверяет, тише логи |
sleep 60 |
Минимальная нагрузка |
🐛 Решение проблем
Демон не запускается
sudo launchctl list | grep dnsleak-guard
cat /tmp/dnsleak-guard.err
Если пусто — загрузите принудительно:
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 $(...). Обновите скрипт:
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:
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-кэш:
sudo dscacheutil -flushcache
sudo killall -HUP mDNSResponder
4. Проверьте через dnsleaktest.com → Extended Test. Должен быть только IP вашего VPS.
Интернет пропадает после установки
Скорее всего, Clash не слушает порт 53, а системный DNS указывает на 127.0.0.1, где никто не отвечает.
Быстрое восстановление:
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).