gitscope
← awesome-scripts / Diff · 4b825dc → 735f165
Changes 4b825dc..735f165
Patch commit
diff --git a/dnsleak-guard/LICENSE b/dnsleak-guard/LICENSE
new file mode 100644
index 0000000..898af02
--- /dev/null
+++ b/dnsleak-guard/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2026 KronoZ
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/dnsleak-guard/README.md b/dnsleak-guard/README.md
new file mode 100644
index 0000000..0eb926c
--- /dev/null
+++ b/dnsleak-guard/README.md
@@ -0,0 +1,250 @@
+# 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).
diff --git a/dnsleak-guard/com.user.dnsleak-guard.plist b/dnsleak-guard/com.user.dnsleak-guard.plist
new file mode 100644
index 0000000..12176c3
--- /dev/null
+++ b/dnsleak-guard/com.user.dnsleak-guard.plist
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>Label</key>
+ <string>com.user.dnsleak-guard</string>
+ <key>ProgramArguments</key>
+ <array>
+ <string>/usr/local/bin/ensure_dns.sh</string>
+ </array>
+ <key>RunAtLoad</key>
+ <true/>
+ <key>KeepAlive</key>
+ <true/>
+ <key>StandardOutPath</key>
+ <string>/tmp/dnsleak-guard.out</string>
+ <key>StandardErrorPath</key>
+ <string>/tmp/dnsleak-guard.err</string>
+</dict>
+</plist>
diff --git a/dnsleak-guard/ensure_dns.sh b/dnsleak-guard/ensure_dns.sh
new file mode 100644
index 0000000..b9862ee
--- /dev/null
+++ b/dnsleak-guard/ensure_dns.sh
@@ -0,0 +1,47 @@
+#!/bin/bash
+DNS_SERVER="127.0.0.1"
+LOG_FILE="/tmp/dnsleak-guard.log"
+
+exec 2>>"$LOG_FILE"
+
+if [ "$EUID" -ne 0 ]; then
+ echo "[$(date)] ERROR: must run as root" >> "$LOG_FILE"
+ exit 1
+fi
+
+log() {
+ echo "[$(date)] $1" >> "$LOG_FILE"
+}
+
+log "dnsleak-guard started"
+
+while true; do
+ CHANGED=0
+
+ while IFS= read -r service; do
+ [[ "$service" == "An asterisk"* ]] && continue
+ [[ -z "$service" ]] && continue
+ [[ "$service" == "*"* ]] && continue
+
+ current=$(networksetup -getdnsservers "$service" 2>/dev/null)
+ [ -z "$current" ] && continue
+ [[ "$current" == *"aren't any"* ]] && continue
+
+ current_flat=$(echo "$current" | tr '\n' ' ' | sed 's/[[:space:]]*$//')
+
+ if [ "$current_flat" != "$DNS_SERVER" ]; then
+ if networksetup -setdnsservers "$service" "$DNS_SERVER" 2>/dev/null; then
+ CHANGED=1
+ log "[$service] DNS reset: '$current_flat' -> $DNS_SERVER"
+ fi
+ fi
+ done < <(networksetup -listallnetworkservices 2>/dev/null)
+
+ if [ "$CHANGED" -eq 1 ]; then
+ dscacheutil -flushcache 2>/dev/null
+ killall -HUP mDNSResponder 2>/dev/null
+ log "DNS cache flushed"
+ fi
+
+ sleep 10
+done
diff --git a/dnsleak-guard/install.sh b/dnsleak-guard/install.sh
new file mode 100644
index 0000000..d01804d
--- /dev/null
+++ b/dnsleak-guard/install.sh
@@ -0,0 +1,35 @@
+#!/bin/bash
+set -e
+
+# Проверка root
+if [ "$EUID" -ne 0 ]; then
+ echo "ERROR: run with sudo"
+ exit 1
+fi
+
+SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
+
+echo "[1/4] Installing script to /usr/local/bin/ensure_dns.sh"
+cp "$SCRIPT_DIR/ensure_dns.sh" /usr/local/bin/ensure_dns.sh
+chmod +x /usr/local/bin/ensure_dns.sh
+chown root:wheel /usr/local/bin/ensure_dns.sh
+
+echo "[2/4] Installing LaunchDaemon"
+cp "$SCRIPT_DIR/com.user.dnsleak-guard.plist" /Library/LaunchDaemons/
+chown root:wheel /Library/LaunchDaemons/com.user.dnsleak-guard.plist
+chmod 644 /Library/LaunchDaemons/com.user.dnsleak-guard.plist
+
+echo "[3/4] Loading LaunchDaemon"
+launchctl unload /Library/LaunchDaemons/com.user.dnsleak-guard.plist 2>/dev/null || true
+launchctl load /Library/LaunchDaemons/com.user.dnsleak-guard.plist
+
+echo "[4/4] Verifying"
+sleep 2
+if launchctl list | grep -q "com.user.dnsleak-guard"; then
+ echo "✅ dnsleak-guard installed and running"
+ echo " Logs: /tmp/dnsleak-guard.log"
+ echo " Stop: sudo launchctl unload /Library/LaunchDaemons/com.user.dnsleak-guard.plist"
+else
+ echo "❌ Failed to load daemon. Check /tmp/dnsleak-guard.err"
+ exit 1
+fi