#!/usr/bin/env bash # # dnssec_check - prüft für hinterlegte Domains, ob DNSSEC aktiviert und # gültig signiert ist. # # Zielsystem : Ubuntu 22.04 # Benötigt : dig (Paket: bind9-dnsutils bzw. dnsutils) # Installation: sudo apt install bind9-dnsutils # # Status-Bedeutung: # aktiv - Domain ist DNSSEC-signiert UND wurde erfolgreich validiert # (Antwort NOERROR mit gesetztem AD-Flag = Authenticated Data) # inaktiv - Domain ist NICHT signiert (kein DNSSEC vorhanden) # (Antwort NOERROR, aber KEIN AD-Flag) # fail - DNSSEC vorhanden, aber Validierung schlägt fehl / Fehler # (SERVFAIL vom validierenden Resolver o. ä.) # # Wichtig: Das Skript fragt einen *validierenden* Resolver ab (Default der # lokale BIND auf 127.0.0.1). Ohne validierenden Resolver ist die Prüfung # nicht aussagekräftig. # # Aufruf: # ./dnssec_check # nutzt die unten hinterlegte Liste # ./dnssec_check -r 192.168.1.1 # anderer Resolver # ./dnssec_check example.com # nur diese Domain(s) prüfen # set -u # ------------------------------------------------------------------ # Konfiguration # ------------------------------------------------------------------ # Validierender Resolver (z. B. der lokale BIND). Per -r überschreibbar. RESOLVER="127.0.0.1" # >>> Hier die zu prüfenden Domains eintragen <<< DOMAINS=( "isc.org" # signiert -> erwartet: aktiv "dnssec-failed.org" # kaputt -> erwartet: fail "maier3000.de" # signiert -> erwartet: aktiv "maierch.de" # signiert -> erwartet: aktiv "maierchr.de" # signiert -> erwartet: aktiv "citeq.de" # unsigniert-> erwartet: inaktiv ) # Abfragetyp und dig-Optionen (Timeout/Versuche) QTYPE="A" DIG_OPTS=(+time=3 +tries=2) # ------------------------------------------------------------------ # Ab hier nichts mehr ändern # ------------------------------------------------------------------ usage() { cat >&2 </dev/null 2>&1; then echo "Fehler: 'dig' nicht gefunden. Installieren mit: sudo apt install bind9-dnsutils" >&2 exit 2 fi # Farben nur, wenn Ausgabe ins Terminal geht if [[ -t 1 ]]; then C_GREEN=$'\033[32m'; C_YELLOW=$'\033[33m'; C_RED=$'\033[31m'; C_RST=$'\033[0m' else C_GREEN=""; C_YELLOW=""; C_RED=""; C_RST="" fi # Feld aus einer dig-Ausgabe ziehen ------------------------------------ get_status() { sed -n 's/.*status: \([A-Z]*\).*/\1/p' | head -n1; } get_flags() { sed -n 's/.*flags: \([a-z ]*\);.*/\1/p' | head -n1; } # Kernprüfung: liefert aktiv | inaktiv | fail ------------------------- check_domain() { local domain="$1" out status flags cdstatus out=$(dig "@$RESOLVER" "${DIG_OPTS[@]}" +dnssec "$domain" "$QTYPE" 2>/dev/null) if [[ -z "$out" ]]; then echo "fail"; return fi status=$(printf '%s\n' "$out" | get_status) flags=$(printf '%s\n' "$out" | get_flags) case "$status" in NOERROR|NXDOMAIN) # AD-Flag = vom Resolver erfolgreich validiert (= signiert) if [[ " $flags " == *" ad "* ]]; then echo "aktiv" else echo "inaktiv" fi ;; SERVFAIL) # Gegenprobe mit +cd (checking disabled): kommt dann eine # gültige Antwort, lag der SERVFAIL an der DNSSEC-Validierung. cdstatus=$(dig "@$RESOLVER" "${DIG_OPTS[@]}" +cd "$domain" "$QTYPE" 2>/dev/null | get_status) if [[ "$cdstatus" == "NOERROR" || "$cdstatus" == "NXDOMAIN" ]]; then echo "fail" # DNSSEC-Signatur/Kette ungültig else echo "fail" # sonstiger Auflösungsfehler fi ;; *) echo "fail" ;; esac } # Selbsttest: validiert der Resolver überhaupt? ---------------------- # Nutzt zwei Referenzdomains: # - eine absichtlich kaputt signierte (muss SERVFAIL liefern) # - eine korrekt signierte (muss AD-Flag liefern) # Rückgabe: 0 = validiert, 1 = validiert nicht, 2 = unklar/Netzfehler SELF_BAD_DOMAIN="dnssec-failed.org" # bewusst falsch signiert (Verisign) SELF_GOOD_DOMAIN="isc.org" # korrekt signiert self_check() { local bad_status cd_status good good_status good_flags bad_status=$(dig "@$RESOLVER" "${DIG_OPTS[@]}" +dnssec "$SELF_BAD_DOMAIN" A 2>/dev/null | get_status) cd_status=$( dig "@$RESOLVER" "${DIG_OPTS[@]}" +cd "$SELF_BAD_DOMAIN" A 2>/dev/null | get_status) good=$( dig "@$RESOLVER" "${DIG_OPTS[@]}" +dnssec "$SELF_GOOD_DOMAIN" A 2>/dev/null) good_status=$(printf '%s\n' "$good" | get_status) good_flags=$( printf '%s\n' "$good" | get_flags) # Netz-/Erreichbarkeitsproblem? if [[ -z "$bad_status" || -z "$good_status" ]]; then printf 'Resolver-Selbsttest: %sUNKLAR%s (Resolver %s nicht erreichbar?)\n' \ "$C_YELLOW" "$C_RST" "$RESOLVER" return 2 fi # Kriterien fuer "validiert": # kaputte Domain -> SERVFAIL, mit +cd aber aufloesbar # gute Domain -> NOERROR mit AD-Flag if [[ "$bad_status" == "SERVFAIL" && ( "$cd_status" == "NOERROR" || "$cd_status" == "NXDOMAIN" ) \ && "$good_status" == "NOERROR" && " $good_flags " == *" ad "* ]]; then printf 'Resolver-Selbsttest: %sVALIDIERT DNSSEC%s (%s=SERVFAIL, %s=AD)\n' \ "$C_GREEN" "$C_RST" "$SELF_BAD_DOMAIN" "$SELF_GOOD_DOMAIN" return 0 else printf 'Resolver-Selbsttest: %sKEINE VALIDIERUNG%s (%s=%s, +cd=%s, %s=%s flags:%s)\n' \ "$C_RED" "$C_RST" \ "$SELF_BAD_DOMAIN" "$bad_status" "$cd_status" \ "$SELF_GOOD_DOMAIN" "$good_status" "$good_flags" return 1 fi } # ------------------------------------------------------------------ # Ausgabe # ------------------------------------------------------------------ # Nur Selbsttest gewuenscht? if [[ "$SELF_ONLY" -eq 1 ]]; then printf 'Resolver: %s (%s)\n' "$RESOLVER" "$(date '+%Y-%m-%d %H:%M:%S')" self_check exit $? fi printf '%s\n' "DNSSEC-Prüfung über Resolver: $RESOLVER ($(date '+%Y-%m-%d %H:%M:%S'))" # Immer zuerst prüfen, ob der Resolver validiert – sonst sind die # Domain-Ergebnisse nicht aussagekräftig. self_check sc_rc=$? if [[ "$sc_rc" -ne 0 ]]; then printf '%sHinweis:%s Resolver validiert nicht/unklar – "aktiv/fail" unten sind nur eingeschränkt verlässlich.\n' \ "$C_YELLOW" "$C_RST" fi echo printf '%-40s %s\n' "DOMAIN" "STATUS" printf '%-40s %s\n' "----------------------------------------" "--------" rc=0 for d in "${DOMAINS[@]}"; do st=$(check_domain "$d") case "$st" in aktiv) col="$C_GREEN" ;; inaktiv) col="$C_YELLOW" ;; *) col="$C_RED"; rc=1 ;; esac printf '%-40s %s%s%s\n' "$d" "$col" "$st" "$C_RST" done # Exit-Code: 0 = kein fail, 1 = mindestens ein fail (nützlich für Monitoring/cron) exit $rc