diff --git a/dns-rescue.sh b/dns-rescue.sh new file mode 100755 index 0000000..4e4e8bd --- /dev/null +++ b/dns-rescue.sh @@ -0,0 +1,114 @@ +#!/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