#!/usr/bin/env bash # net-ops :: linux/resolved-reset.sh # Reset systemd-resolved state when per-link DNS gets stuck (typical after # VPN disconnect leaves stale per-link DNS / domain settings). # # Defaults to DRY RUN — pass --apply to actually act. # Requires sudo for the apply path. set -eu APPLY=0 for arg in "$@"; do case "$arg" in --apply) APPLY=1 ;; --help|-h) cat </dev/null 2>&1; then echo "systemd-resolved is not active. This script only applies when it is." echo "On non-systemd-resolved systems, edit /etc/resolv.conf or NetworkManager config directly." exit 0 fi echo "=== BEFORE ===" resolvectl status 2>/dev/null | head -60 # Find links with non-empty per-link DNS (potential stale state) LINKS_WITH_DNS=$(resolvectl status 2>/dev/null | awk ' /^Link [0-9]+ \(/{ split($0,a," \\("); split(a[2],b,")"); link=b[1]; ifn=a[1]; sub("Link ","",ifn); has=0 } /Current DNS Server:|DNS Servers:/{ if(NF>3){print ifn"|"link} } ' | sort -u) if [[ -z "$LINKS_WITH_DNS" ]]; then echo echo "No links have explicit DNS set. Nothing to reset." exit 0 fi echo echo "=== LINKS WITH EXPLICIT DNS ===" echo "$LINKS_WITH_DNS" | while IFS='|' read -r idx name; do echo " Link $idx ($name)" done if [[ "$APPLY" -eq 0 ]]; then echo echo "DRY RUN — pass --apply to actually reset these links and flush caches." exit 0 fi if [[ "$EUID" -ne 0 ]]; then echo "Need root. Re-running with sudo..." exec sudo "$0" --apply fi echo echo "=== RESETTING ===" echo "$LINKS_WITH_DNS" | while IFS='|' read -r idx name; do if resolvectl revert "$name" 2>/dev/null; then echo "[OK] reverted $name" else echo "[WARN] revert failed for $name (may be a VPN tunnel — manual cleanup may be needed)" fi done echo echo "=== FLUSHING CACHE ===" resolvectl flush-caches && echo " cache flushed" # Restart for good measure if user really wanted a reset systemctl restart systemd-resolved echo " systemd-resolved restarted" echo echo "=== VERIFICATION ===" if out=$(getent hosts google.com 2>&1) && [[ -n "$out" ]]; then echo "[PASS] getent hosts google.com -> $(echo "$out" | awk '{print $1}')" else echo "[FAIL] getent still failing. Check /etc/nsswitch.conf and /etc/resolv.conf." fi if curl -sS -o /dev/null -w "[PASS] HTTPS google.com -> HTTP %{http_code}\n" --max-time 8 https://www.google.com 2>&1; then : else echo "[FAIL] HTTPS still broken." fi echo echo "=== AFTER ===" resolvectl status 2>/dev/null | head -40