| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100 |
- #!/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 <<EOF
- Usage: $0 [--apply]
- Diagnoses and (with --apply) resets systemd-resolved per-link DNS state.
- --apply Flush caches and revert each link's DNS to NetworkManager/networkd defaults
- (default: dry-run, prints what would happen)
- EOF
- exit 0 ;;
- esac
- done
- if ! systemctl is-active systemd-resolved >/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
|