64138831a8
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>
211 lines
7.2 KiB
PowerShell
211 lines
7.2 KiB
PowerShell
#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
|