resolved-reset.sh 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. #!/usr/bin/env bash
  2. # net-ops :: linux/resolved-reset.sh
  3. # Reset systemd-resolved state when per-link DNS gets stuck (typical after
  4. # VPN disconnect leaves stale per-link DNS / domain settings).
  5. #
  6. # Defaults to DRY RUN — pass --apply to actually act.
  7. # Requires sudo for the apply path.
  8. set -eu
  9. APPLY=0
  10. for arg in "$@"; do
  11. case "$arg" in
  12. --apply) APPLY=1 ;;
  13. --help|-h)
  14. cat <<EOF
  15. Usage: $0 [--apply]
  16. Diagnoses and (with --apply) resets systemd-resolved per-link DNS state.
  17. --apply Flush caches and revert each link's DNS to NetworkManager/networkd defaults
  18. (default: dry-run, prints what would happen)
  19. EOF
  20. exit 0 ;;
  21. esac
  22. done
  23. if ! systemctl is-active systemd-resolved >/dev/null 2>&1; then
  24. echo "systemd-resolved is not active. This script only applies when it is."
  25. echo "On non-systemd-resolved systems, edit /etc/resolv.conf or NetworkManager config directly."
  26. exit 0
  27. fi
  28. echo "=== BEFORE ==="
  29. resolvectl status 2>/dev/null | head -60
  30. # Find links with non-empty per-link DNS (potential stale state)
  31. LINKS_WITH_DNS=$(resolvectl status 2>/dev/null | awk '
  32. /^Link [0-9]+ \(/{ split($0,a," \\("); split(a[2],b,")"); link=b[1]; ifn=a[1]; sub("Link ","",ifn); has=0 }
  33. /Current DNS Server:|DNS Servers:/{ if(NF>3){print ifn"|"link} }
  34. ' | sort -u)
  35. if [[ -z "$LINKS_WITH_DNS" ]]; then
  36. echo
  37. echo "No links have explicit DNS set. Nothing to reset."
  38. exit 0
  39. fi
  40. echo
  41. echo "=== LINKS WITH EXPLICIT DNS ==="
  42. echo "$LINKS_WITH_DNS" | while IFS='|' read -r idx name; do
  43. echo " Link $idx ($name)"
  44. done
  45. if [[ "$APPLY" -eq 0 ]]; then
  46. echo
  47. echo "DRY RUN — pass --apply to actually reset these links and flush caches."
  48. exit 0
  49. fi
  50. if [[ "$EUID" -ne 0 ]]; then
  51. echo "Need root. Re-running with sudo..."
  52. exec sudo "$0" --apply
  53. fi
  54. echo
  55. echo "=== RESETTING ==="
  56. echo "$LINKS_WITH_DNS" | while IFS='|' read -r idx name; do
  57. if resolvectl revert "$name" 2>/dev/null; then
  58. echo "[OK] reverted $name"
  59. else
  60. echo "[WARN] revert failed for $name (may be a VPN tunnel — manual cleanup may be needed)"
  61. fi
  62. done
  63. echo
  64. echo "=== FLUSHING CACHE ==="
  65. resolvectl flush-caches && echo " cache flushed"
  66. # Restart for good measure if user really wanted a reset
  67. systemctl restart systemd-resolved
  68. echo " systemd-resolved restarted"
  69. echo
  70. echo "=== VERIFICATION ==="
  71. if out=$(getent hosts google.com 2>&1) && [[ -n "$out" ]]; then
  72. echo "[PASS] getent hosts google.com -> $(echo "$out" | awk '{print $1}')"
  73. else
  74. echo "[FAIL] getent still failing. Check /etc/nsswitch.conf and /etc/resolv.conf."
  75. fi
  76. 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
  77. :
  78. else
  79. echo "[FAIL] HTTPS still broken."
  80. fi
  81. echo
  82. echo "=== AFTER ==="
  83. resolvectl status 2>/dev/null | head -40