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:
@@ -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