dnssec_check: DNSSEC-Status-Pruefung fuer Bash und PowerShell
Neue Skripte dnssec_check (Bash, dig) und dnssec_check.ps1 (PowerShell, Resolve-DnsName): pruefen fuer hinterlegbare Domains den DNSSEC-Status (aktiv/inaktiv/fail) inkl. Resolver-Selbsttest. README erweitert. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -121,3 +121,64 @@ powershell -ExecutionPolicy Bypass -File C:\Tools\dig.ps1 example.com MX
|
|||||||
- Das Skript benötigt das Modul `DnsClient` (`Resolve-DnsName`), das unter Windows standardmäßig vorhanden ist.
|
- Das Skript benötigt das Modul `DnsClient` (`Resolve-DnsName`), das unter Windows standardmäßig vorhanden ist.
|
||||||
- Die Standardausgabe orientiert sich am `dig`-Format mit `QUESTION`- und `ANSWER SECTION`.
|
- Die Standardausgabe orientiert sich am `dig`-Format mit `QUESTION`- und `ANSWER SECTION`.
|
||||||
- Mit `+short` werden nur die reinen Antwortwerte ausgegeben (eine pro Zeile).
|
- Mit `+short` werden nur die reinen Antwortwerte ausgegeben (eine pro Zeile).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# dnssec_check — DNSSEC-Status prüfen
|
||||||
|
|
||||||
|
Prüft für eine hinterlegbare Liste von Domains, ob **DNSSEC aktiviert und gültig
|
||||||
|
signiert** ist, und testet vorab, ob der abgefragte Resolver überhaupt validiert.
|
||||||
|
Es gibt zwei funktionsgleiche Varianten:
|
||||||
|
|
||||||
|
| Datei | Plattform | Werkzeug |
|
||||||
|
|-------|-----------|----------|
|
||||||
|
| `dnssec_check` | Linux/macOS (Bash) | `dig` (Paket `bind9-dnsutils`) |
|
||||||
|
| `dnssec_check.ps1` | Windows (PowerShell 5.1+) | `Resolve-DnsName` (Modul `DnsClient`) |
|
||||||
|
|
||||||
|
## Status-Werte
|
||||||
|
|
||||||
|
| Status | Bedeutung |
|
||||||
|
|--------|-----------|
|
||||||
|
| `aktiv` | Domain ist DNSSEC-signiert und wird vom validierenden Resolver korrekt ausgeliefert |
|
||||||
|
| `inaktiv` | Domain ist **nicht** signiert (kein DNSSEC) |
|
||||||
|
| `fail` | DNSSEC vorhanden, aber Validierung schlägt fehl (SERVFAIL) |
|
||||||
|
|
||||||
|
Der Test ist nur aussagekräftig gegen einen **validierenden** Resolver (z. B. der
|
||||||
|
interne BIND mit `dnssec-validation auto;`). Beide Skripte führen daher zuerst
|
||||||
|
einen **Selbsttest** aus: `dnssec-failed.org` muss scheitern, `isc.org` muss
|
||||||
|
signiert auflösen. Schlägt der Selbsttest fehl, wird gewarnt.
|
||||||
|
|
||||||
|
## Bash (Linux/macOS)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo apt install bind9-dnsutils # falls dig fehlt
|
||||||
|
chmod +x dnssec_check
|
||||||
|
./dnssec_check # hinterlegte Liste, Resolver 127.0.0.1
|
||||||
|
./dnssec_check -r 192.168.1.10 # anderer Resolver
|
||||||
|
./dnssec_check --self-check # nur Resolver-Validierung prüfen
|
||||||
|
./dnssec_check isc.org citeq.de # nur diese Domains
|
||||||
|
```
|
||||||
|
|
||||||
|
## PowerShell (Windows)
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
.\dnssec_check.ps1 # hinterlegte Liste, Resolver 127.0.0.1
|
||||||
|
.\dnssec_check.ps1 -Resolver 192.168.1.10
|
||||||
|
.\dnssec_check.ps1 -SelfCheck # nur Resolver-Validierung prüfen
|
||||||
|
.\dnssec_check.ps1 isc.org citeq.de # nur diese Domains
|
||||||
|
```
|
||||||
|
|
||||||
|
> Hinweis: `Resolve-DnsName` liefert das AD-Header-Flag nicht zurück. Die
|
||||||
|
> PowerShell-Variante wertet daher das Vorhandensein von **RRSIG-Records** aus.
|
||||||
|
> Ob der Resolver wirklich validiert, klärt der Selbsttest.
|
||||||
|
|
||||||
|
## Domains hinterlegen
|
||||||
|
|
||||||
|
Die zu prüfenden Domains stehen direkt im Skript:
|
||||||
|
- Bash: Array `DOMAINS=( … )` im Kopf
|
||||||
|
- PowerShell: `$DefaultDomains = @( … )` im Kopf
|
||||||
|
|
||||||
|
## Exit-Code (für Monitoring / cron / Scheduled Task)
|
||||||
|
|
||||||
|
`0` = kein `fail`, `1` = mindestens eine Domain `fail`. Der reine Selbsttest gibt
|
||||||
|
`0` (validiert), `1` (validiert nicht) bzw. `2` (Resolver nicht erreichbar) zurück.
|
||||||
|
|||||||
Executable
+228
@@ -0,0 +1,228 @@
|
|||||||
|
#!/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 <<EOF
|
||||||
|
Aufruf: $0 [-r resolver] [-t qtype] [-s|--self-check] [domain ...]
|
||||||
|
-r resolver DNS-Resolver, der geprüft wird (Default: $RESOLVER)
|
||||||
|
-t qtype Abfragetyp (Default: $QTYPE)
|
||||||
|
-s, --self-check nur prüfen, ob der Resolver DNSSEC validiert (keine Domainliste)
|
||||||
|
EOF
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
SELF_ONLY=0
|
||||||
|
|
||||||
|
# Lange Option --self-check auf -s abbilden
|
||||||
|
# (Guard fuer leere Argumentliste wegen bash 3.2 unter macOS + 'set -u')
|
||||||
|
if [[ $# -gt 0 ]]; then
|
||||||
|
args=()
|
||||||
|
for a in "$@"; do
|
||||||
|
case "$a" in
|
||||||
|
--self-check) args+=("-s") ;;
|
||||||
|
*) args+=("$a") ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
set -- "${args[@]}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
while getopts ":r:t:sh" opt; do
|
||||||
|
case "$opt" in
|
||||||
|
r) RESOLVER="$OPTARG" ;;
|
||||||
|
t) QTYPE="$OPTARG" ;;
|
||||||
|
s) SELF_ONLY=1 ;;
|
||||||
|
h) usage ;;
|
||||||
|
*) usage ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
shift $((OPTIND - 1))
|
||||||
|
|
||||||
|
# Domains von der Kommandozeile überschreiben die Liste
|
||||||
|
if [[ $# -gt 0 ]]; then
|
||||||
|
DOMAINS=("$@")
|
||||||
|
fi
|
||||||
|
|
||||||
|
# dig vorhanden?
|
||||||
|
if ! command -v dig >/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
|
||||||
@@ -0,0 +1,210 @@
|
|||||||
|
#Requires -Version 5.1
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
dnssec_check.ps1 - prueft fuer hinterlegte Domains, ob DNSSEC aktiviert
|
||||||
|
und gueltig signiert ist. (Windows-Pendant zum
|
||||||
|
Bash-Skript dnssec_check.)
|
||||||
|
|
||||||
|
.DESCRIPTION
|
||||||
|
Zielsystem : Windows 10/11 / Windows Server (Windows PowerShell 5.1 oder
|
||||||
|
PowerShell 7+). Nutzt das native Cmdlet Resolve-DnsName
|
||||||
|
(Modul DnsClient) - kein dig noetig.
|
||||||
|
|
||||||
|
Status-Bedeutung:
|
||||||
|
aktiv - Domain ist DNSSEC-signiert UND wurde vom Resolver ausgeliefert
|
||||||
|
(Antwort erhalten + RRSIG-Records vorhanden)
|
||||||
|
inaktiv - Domain ist NICHT signiert (Antwort erhalten, keine RRSIG)
|
||||||
|
fail - DNSSEC vorhanden, aber Validierung schlaegt fehl / Fehler
|
||||||
|
(Abfrage scheitert; Gegenprobe mit -DnssecCd bestaetigt DNSSEC)
|
||||||
|
|
||||||
|
Hinweis: Resolve-DnsName liefert das AD-Header-Flag nicht zurueck. Statt
|
||||||
|
des AD-Flags wird das Vorhandensein von RRSIG-Records ausgewertet. Ob der
|
||||||
|
Resolver *wirklich* validiert, klaert der Selbsttest (kaputte Domain muss
|
||||||
|
scheitern). Ohne validierenden Resolver ist die Pruefung nicht aussagekraeftig.
|
||||||
|
|
||||||
|
.PARAMETER Resolver
|
||||||
|
DNS-Resolver, der geprueft wird (Default: 127.0.0.1 = lokaler DNS).
|
||||||
|
|
||||||
|
.PARAMETER QType
|
||||||
|
Abfragetyp (Default: A).
|
||||||
|
|
||||||
|
.PARAMETER SelfCheck
|
||||||
|
Nur pruefen, ob der Resolver DNSSEC validiert (keine Domainliste).
|
||||||
|
|
||||||
|
.PARAMETER Domains
|
||||||
|
Optional: Domains, die statt der hinterlegten Liste geprueft werden.
|
||||||
|
|
||||||
|
.EXAMPLE
|
||||||
|
.\dnssec_check.ps1
|
||||||
|
.EXAMPLE
|
||||||
|
.\dnssec_check.ps1 -Resolver 192.168.1.10
|
||||||
|
.EXAMPLE
|
||||||
|
.\dnssec_check.ps1 -SelfCheck
|
||||||
|
.EXAMPLE
|
||||||
|
.\dnssec_check.ps1 isc.org dnssec-failed.org
|
||||||
|
#>
|
||||||
|
|
||||||
|
[CmdletBinding()]
|
||||||
|
param(
|
||||||
|
[string] $Resolver = "127.0.0.1",
|
||||||
|
[string] $QType = "A",
|
||||||
|
[switch] $SelfCheck,
|
||||||
|
[Parameter(ValueFromRemainingArguments = $true)]
|
||||||
|
[string[]] $Domains
|
||||||
|
)
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
# Konfiguration
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
|
||||||
|
# >>> Hier die zu pruefenden Domains eintragen <<<
|
||||||
|
$DefaultDomains = @(
|
||||||
|
"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
|
||||||
|
)
|
||||||
|
|
||||||
|
# Referenzdomains fuer den Selbsttest
|
||||||
|
$SelfBadDomain = "dnssec-failed.org" # bewusst falsch signiert (Verisign)
|
||||||
|
$SelfGoodDomain = "isc.org" # korrekt signiert
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
# Ab hier nichts mehr aendern
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
|
||||||
|
if (-not $Domains -or $Domains.Count -eq 0) {
|
||||||
|
$Domains = $DefaultDomains
|
||||||
|
}
|
||||||
|
|
||||||
|
# Cmdlet vorhanden?
|
||||||
|
if (-not (Get-Command Resolve-DnsName -ErrorAction SilentlyContinue)) {
|
||||||
|
Write-Error "Resolve-DnsName nicht gefunden. Benoetigt Windows PowerShell 5.1+ mit dem Modul DnsClient (Windows)."
|
||||||
|
exit 2
|
||||||
|
}
|
||||||
|
|
||||||
|
# Eine DNSSEC-fuehrende Abfrage; gibt die Records zurueck oder wirft.
|
||||||
|
function Invoke-DnsQuery {
|
||||||
|
param(
|
||||||
|
[string] $Name,
|
||||||
|
[string] $Type,
|
||||||
|
[switch] $Cd # -DnssecCd statt -DnssecOk (checking disabled)
|
||||||
|
)
|
||||||
|
$common = @{
|
||||||
|
Name = $Name
|
||||||
|
Type = $Type
|
||||||
|
Server = $Resolver
|
||||||
|
QuickTimeout = $true
|
||||||
|
DnsOnly = $true
|
||||||
|
ErrorAction = 'Stop'
|
||||||
|
}
|
||||||
|
if ($Cd) { Resolve-DnsName @common -DnssecCd }
|
||||||
|
else { Resolve-DnsName @common -DnssecOk }
|
||||||
|
}
|
||||||
|
|
||||||
|
# Kernpruefung: liefert 'aktiv' | 'inaktiv' | 'fail'
|
||||||
|
function Test-Domain {
|
||||||
|
param([string] $Domain)
|
||||||
|
|
||||||
|
try {
|
||||||
|
$ans = Invoke-DnsQuery -Name $Domain -Type $QType
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
# Fehler (SERVFAIL / NXDOMAIN / Timeout). Gegenprobe mit +cd:
|
||||||
|
# kommt MIT checking-disabled eine Antwort, lag es an der Validierung.
|
||||||
|
try { Invoke-DnsQuery -Name $Domain -Type $QType -Cd | Out-Null; return 'fail' }
|
||||||
|
catch { return 'fail' }
|
||||||
|
}
|
||||||
|
|
||||||
|
# Antwort erhalten -> signiert, wenn RRSIG-Records dabei sind
|
||||||
|
$hasRRSIG = @($ans | Where-Object { $_.Type -eq 'RRSIG' }).Count -gt 0
|
||||||
|
if ($hasRRSIG) { return 'aktiv' } else { return 'inaktiv' }
|
||||||
|
}
|
||||||
|
|
||||||
|
# Selbsttest: validiert der Resolver ueberhaupt?
|
||||||
|
# Rueckgabe (ueber die Pipeline): 0 = validiert, 1 = nein, 2 = unklar/Netzfehler
|
||||||
|
function Invoke-SelfCheck {
|
||||||
|
# 1) kaputte Domain: OHNE cd muss sie scheitern
|
||||||
|
$badFails = $false
|
||||||
|
try { Invoke-DnsQuery -Name $SelfBadDomain -Type A | Out-Null; $badFails = $false }
|
||||||
|
catch { $badFails = $true }
|
||||||
|
|
||||||
|
# 2) kaputte Domain MIT cd sollte aufloesbar sein
|
||||||
|
$cdOk = $false
|
||||||
|
try { Invoke-DnsQuery -Name $SelfBadDomain -Type A -Cd | Out-Null; $cdOk = $true }
|
||||||
|
catch { $cdOk = $false }
|
||||||
|
|
||||||
|
# 3) gute Domain muss aufloesen und signiert sein
|
||||||
|
$goodOk = $false; $goodSigned = $false
|
||||||
|
try {
|
||||||
|
$g = Invoke-DnsQuery -Name $SelfGoodDomain -Type A
|
||||||
|
$goodOk = $true
|
||||||
|
$goodSigned = @($g | Where-Object { $_.Type -eq 'RRSIG' }).Count -gt 0
|
||||||
|
} catch { $goodOk = $false }
|
||||||
|
|
||||||
|
# Erreichbarkeitsproblem? (nichts geht durch)
|
||||||
|
if (-not $cdOk -and -not $goodOk) {
|
||||||
|
Write-Host "Resolver-Selbsttest: " -NoNewline
|
||||||
|
Write-Host "UNKLAR" -ForegroundColor Yellow -NoNewline
|
||||||
|
Write-Host " (Resolver $Resolver nicht erreichbar?)"
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($badFails -and $cdOk -and $goodOk -and $goodSigned) {
|
||||||
|
Write-Host "Resolver-Selbsttest: " -NoNewline
|
||||||
|
Write-Host "VALIDIERT DNSSEC" -ForegroundColor Green -NoNewline
|
||||||
|
Write-Host " ($SelfBadDomain scheitert, $SelfGoodDomain signiert+aufgeloest)"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Write-Host "Resolver-Selbsttest: " -NoNewline
|
||||||
|
Write-Host "KEINE VALIDIERUNG" -ForegroundColor Red -NoNewline
|
||||||
|
Write-Host (" (bad_fails={0}, cd_ok={1}, good_ok={2}, good_signed={3})" -f `
|
||||||
|
$badFails, $cdOk, $goodOk, $goodSigned)
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
# Ausgabe
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
|
||||||
|
$stamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
|
||||||
|
|
||||||
|
# Nur Selbsttest gewuenscht?
|
||||||
|
if ($SelfCheck) {
|
||||||
|
Write-Host "Resolver: $Resolver ($stamp)"
|
||||||
|
$rc = Invoke-SelfCheck
|
||||||
|
exit $rc
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "DNSSEC-Pruefung ueber Resolver: $Resolver ($stamp)"
|
||||||
|
|
||||||
|
# Zuerst pruefen, ob der Resolver validiert - sonst sind die Ergebnisse
|
||||||
|
# darunter nur eingeschraenkt aussagekraeftig.
|
||||||
|
$scRc = Invoke-SelfCheck
|
||||||
|
if ($scRc -ne 0) {
|
||||||
|
Write-Host "Hinweis: " -ForegroundColor Yellow -NoNewline
|
||||||
|
Write-Host 'Resolver validiert nicht/unklar - "aktiv/fail" unten sind nur eingeschraenkt verlaesslich.'
|
||||||
|
}
|
||||||
|
Write-Host ""
|
||||||
|
|
||||||
|
"{0,-40} {1}" -f "DOMAIN", "STATUS" | Write-Host
|
||||||
|
"{0,-40} {1}" -f ("-" * 40), "--------" | Write-Host
|
||||||
|
|
||||||
|
$exit = 0
|
||||||
|
foreach ($d in $Domains) {
|
||||||
|
$st = Test-Domain -Domain $d
|
||||||
|
switch ($st) {
|
||||||
|
'aktiv' { $col = 'Green' }
|
||||||
|
'inaktiv' { $col = 'Yellow' }
|
||||||
|
default { $col = 'Red'; $exit = 1 }
|
||||||
|
}
|
||||||
|
Write-Host ("{0,-40} " -f $d) -NoNewline
|
||||||
|
Write-Host $st -ForegroundColor $col
|
||||||
|
}
|
||||||
|
|
||||||
|
# Exit-Code: 0 = kein fail, 1 = mindestens ein fail (fuer Monitoring/Scheduled Task)
|
||||||
|
exit $exit
|
||||||
Reference in New Issue
Block a user