#!/bin/bash # dns-rescue.sh — emergency DNS recovery on a machine where AdGuard Home is the # sole local resolver (systemd-resolved is masked). If AGH fails to start, this # machine has no DNS until you intervene. Run this script from a TTY login. # # Author: Justin Moore # Version: 0.1.0 set -u RESOLV=/etc/resolv.conf FALLBACK=1.1.1.1 require_root() { if [[ $EUID -ne 0 ]]; then echo "Re-running with sudo..." exec sudo -E "$0" "$@" fi } show_status() { echo "=== /etc/resolv.conf ===" cat "$RESOLV" 2>/dev/null || echo "(missing!)" echo echo "=== AdGuard Home service ===" systemctl is-active adguardhome 2>&1 | head -1 systemctl is-enabled adguardhome 2>&1 | head -1 echo echo "=== Last 15 AGH log lines (this boot) ===" journalctl -u adguardhome -b --no-pager -n 15 2>&1 | tail -15 echo echo "=== Port 53 listeners ===" ss -lntu 2>/dev/null | awk '/:53 /{print}' | head -5 echo echo "=== Masked resolved units ===" systemctl is-enabled systemd-resolved.service systemd-resolved-varlink.socket systemd-resolved-monitor.socket 2>&1 | paste -d' ' - - - - } add_fallback_dns() { if grep -q "nameserver $FALLBACK" "$RESOLV" 2>/dev/null; then echo "$FALLBACK is already in $RESOLV — nothing to do." return fi echo "nameserver $FALLBACK" >> "$RESOLV" echo "Added fallback nameserver $FALLBACK to $RESOLV." echo "Test:" getent hosts archlinux.org && echo " DNS now resolves." } restart_agh() { systemctl restart adguardhome sleep 1 systemctl is-active adguardhome journalctl -u adguardhome -b --no-pager -n 10 | tail -10 } unmask_resolved() { cat < " choice case "$choice" in 1) show_status ;; 2) add_fallback_dns ;; 3) restart_agh ;; 4) unmask_resolved ;; 5) "${EDITOR:-vi}" "$RESOLV" ;; q|Q) exit 0 ;; *) echo "Unknown choice." ;; esac } require_root "$@" if [[ $# -gt 0 ]]; then case "$1" in status) show_status ;; fallback) add_fallback_dns ;; restart) restart_agh ;; unmask) unmask_resolved ;; *) echo "Usage: $0 [status|fallback|restart|unmask] (no arg = interactive menu)"; exit 2 ;; esac exit 0 fi show_status while true; do menu; done