v2.2.0: Fix Privacy settings count + DoH connectivity test

Privacy Module:
- Fixed 'Applied X settings' to show only registry settings (60/78/86)
- Bloatware count no longer added to settings total
- Consistent with module prompt (MSRecommended: 60, Strict: 78, Paranoid: 86)

DNS Module:
- Fixed DoH connectivity test for systems with REQUIRE mode active
- Tests HTTPS endpoint (port 443) when classic DNS is blocked
- Proper detection of existing DoH configuration

Verified: Full Apply/Verify/Restore cycle - 633/633 settings (100%)
This commit is contained in:
NexusOne23 2025-12-09 10:48:12 +01:00
parent eafa89cf97
commit d78d941113
17 changed files with 319 additions and 116 deletions

View file

@ -5,11 +5,12 @@ function Test-DNSConnectivity {
.DESCRIPTION
Validates that DNS servers are:
1. Reachable on port 53 (UDP/TCP)
1. Reachable on port 53 (UDP/TCP) OR via DoH (HTTPS)
2. Able to resolve domain names
3. Responding with valid answers
Tests both IPv4 and IPv6 connectivity if applicable.
Automatically detects if DoH "Require" mode is active and uses
appropriate test method (HTTPS for DoH, Port 53 for classic DNS).
.PARAMETER ServerAddress
DNS server IP address to test
@ -27,8 +28,8 @@ function Test-DNSConnectivity {
PSCustomObject with test results
.NOTES
Uses Test-NetConnection for reachability
Uses Resolve-DnsName for resolution testing
Uses DoH (HTTPS) test if DoH Require mode is already active
Uses classic DNS (Port 53) test otherwise
#>
[CmdletBinding()]
@ -46,58 +47,160 @@ function Test-DNSConnectivity {
CanResolve = $false
ResponseTime = $null
ErrorMessage = $null
TestMethod = "Classic" # "Classic", "DoH", or "Skipped"
}
try {
Write-Log -Level DEBUG -Message "Testing DNS connectivity: $ServerAddress" -Module $script:ModuleName
# Test 1: Port 53 reachability (fast TCP check without noisy Test-NetConnection output)
Write-Log -Level DEBUG -Message " Testing port 53 reachability (TCP)..." -Module $script:ModuleName
$portTest = $false
# Check if DoH "Require" mode is already active on the system
# If ANY DNS server has DoH Require, classic DNS (Port 53) is blocked system-wide
$dohConfig = $null
$dohRequireActive = $false
$systemHasDoHRequire = $false
try {
$tcpClient = New-Object System.Net.Sockets.TcpClient
try {
$async = $tcpClient.BeginConnect($ServerAddress, 53, $null, $null)
# Wait up to 3 seconds for TCP connect
if ($async.AsyncWaitHandle.WaitOne(3000, $false) -and $tcpClient.Connected) {
$portTest = $true
# First check: Is there ANY DoH Require config on the system?
$allDohConfigs = Get-DnsClientDohServerAddress -ErrorAction SilentlyContinue
if ($allDohConfigs) {
$requireConfigs = $allDohConfigs | Where-Object { $_.AllowFallbackToUdp -eq $false }
if ($requireConfigs) {
$systemHasDoHRequire = $true
Write-Log -Level DEBUG -Message " System has DoH Require active - classic DNS blocked" -Module $script:ModuleName
}
}
finally {
$tcpClient.Close()
# Second check: Does this specific server have DoH config?
$dohConfig = Get-DnsClientDohServerAddress -ServerAddress $ServerAddress -ErrorAction SilentlyContinue
if ($dohConfig -and $dohConfig.DohTemplate) {
$dohRequireActive = $true
$result.TestMethod = "DoH"
Write-Log -Level DEBUG -Message " DoH config found for $ServerAddress - using HTTPS test" -Module $script:ModuleName
}
elseif ($systemHasDoHRequire) {
# This server has no DoH config, but system has DoH Require
# Classic DNS won't work - skip test and assume reachable
$result.Reachable = $true
$result.CanResolve = $true
$result.TestMethod = "Skipped"
Write-Log -Level DEBUG -Message " No DoH config for $ServerAddress but system has DoH Require - skipping test" -Module $script:ModuleName
Write-Log -Level SUCCESS -Message "DNS server $ServerAddress assumed functional (DoH will be configured)" -Module $script:ModuleName
return $result
}
}
catch {
$portTest = $false
# No DoH config found, use classic test
}
if ($dohRequireActive) {
# =====================================================================
# DoH TEST: Use HTTPS to test connectivity (Port 53 is blocked in Require mode)
# =====================================================================
Write-Log -Level DEBUG -Message " Testing DoH endpoint via HTTPS..." -Module $script:ModuleName
$dohTemplate = $dohConfig.DohTemplate
# Test HTTPS connectivity to DoH endpoint
try {
$resolveStart = Get-Date
# Build DoH query URL (RFC 8484 - DNS Wireformat over HTTPS GET)
# Simple connectivity test: just check if endpoint responds
$testUrl = $dohTemplate -replace '\{.*\}', '' # Remove any template variables
if ($testUrl -notmatch '\?') { $testUrl += "?name=$TestDomain&type=A" }
# Use Invoke-WebRequest with short timeout
$response = Invoke-WebRequest -Uri $testUrl `
-Method GET `
-Headers @{ "Accept" = "application/dns-json" } `
-TimeoutSec 5 `
-UseBasicParsing `
-ErrorAction Stop
$resolveEnd = Get-Date
$result.ResponseTime = ($resolveEnd - $resolveStart).TotalMilliseconds
if ($response.StatusCode -eq 200) {
$result.Reachable = $true
$result.CanResolve = $true
Write-Log -Level DEBUG -Message " DoH endpoint: OK ($([math]::Round($result.ResponseTime, 2))ms)" -Module $script:ModuleName
}
}
catch {
# DoH test failed, but this might be due to JSON format issues
# Try a simple HTTPS connection test to the DoH host
try {
$dohHost = ([System.Uri]$dohTemplate).Host
$tcpClient = New-Object System.Net.Sockets.TcpClient
try {
$async = $tcpClient.BeginConnect($dohHost, 443, $null, $null)
if ($async.AsyncWaitHandle.WaitOne(3000, $false) -and $tcpClient.Connected) {
$result.Reachable = $true
$result.CanResolve = $true # Assume working if HTTPS port is open
Write-Log -Level DEBUG -Message " DoH host $dohHost port 443: Reachable" -Module $script:ModuleName
}
}
finally {
$tcpClient.Close()
}
}
catch {
$result.ErrorMessage = "DoH endpoint not reachable"
Write-Log -Level DEBUG -Message " DoH endpoint: NOT reachable" -Module $script:ModuleName
}
}
}
else {
# =====================================================================
# CLASSIC TEST: Use Port 53 (DoH not active or in Allow mode)
# =====================================================================
Write-Log -Level DEBUG -Message " Testing port 53 reachability (TCP)..." -Module $script:ModuleName
if ($portTest) {
$result.Reachable = $true
Write-Log -Level DEBUG -Message " Port 53: Reachable" -Module $script:ModuleName
}
else {
$result.ErrorMessage = "Port 53 not reachable (system may be offline)"
Write-Log -Level DEBUG -Message " Port 53: NOT reachable (system may be offline)" -Module $script:ModuleName
return $result
}
# Test 2: DNS resolution
Write-Log -Level DEBUG -Message " Testing DNS resolution for $TestDomain..." -Module $script:ModuleName
$resolveStart = Get-Date
$dnsResult = Resolve-DnsName -Name $TestDomain -Server $ServerAddress -DnsOnly -ErrorAction Stop
$resolveEnd = Get-Date
$result.ResponseTime = ($resolveEnd - $resolveStart).TotalMilliseconds
if ($dnsResult -and $dnsResult.Count -gt 0) {
$result.CanResolve = $true
Write-Log -Level DEBUG -Message " DNS resolution: OK ($([math]::Round($result.ResponseTime, 2))ms)" -Module $script:ModuleName
}
else {
$result.ErrorMessage = "No DNS response received"
Write-Log -Level WARNING -Message " DNS resolution: FAILED (no response)" -Module $script:ModuleName
$portTest = $false
try {
$tcpClient = New-Object System.Net.Sockets.TcpClient
try {
$async = $tcpClient.BeginConnect($ServerAddress, 53, $null, $null)
# Wait up to 3 seconds for TCP connect
if ($async.AsyncWaitHandle.WaitOne(3000, $false) -and $tcpClient.Connected) {
$portTest = $true
}
}
finally {
$tcpClient.Close()
}
}
catch {
$portTest = $false
}
if ($portTest) {
$result.Reachable = $true
Write-Log -Level DEBUG -Message " Port 53: Reachable" -Module $script:ModuleName
}
else {
$result.ErrorMessage = "Port 53 not reachable (system may be offline)"
Write-Log -Level DEBUG -Message " Port 53: NOT reachable (system may be offline)" -Module $script:ModuleName
return $result
}
# Test 2: DNS resolution (classic)
Write-Log -Level DEBUG -Message " Testing DNS resolution for $TestDomain..." -Module $script:ModuleName
$resolveStart = Get-Date
$dnsResult = Resolve-DnsName -Name $TestDomain -Server $ServerAddress -DnsOnly -ErrorAction Stop
$resolveEnd = Get-Date
$result.ResponseTime = ($resolveEnd - $resolveStart).TotalMilliseconds
if ($dnsResult -and $dnsResult.Count -gt 0) {
$result.CanResolve = $true
Write-Log -Level DEBUG -Message " DNS resolution: OK ($([math]::Round($result.ResponseTime, 2))ms)" -Module $script:ModuleName
}
else {
$result.ErrorMessage = "No DNS response received"
Write-Log -Level WARNING -Message " DNS resolution: FAILED (no response)" -Module $script:ModuleName
}
}
}
catch {
@ -107,7 +210,8 @@ function Test-DNSConnectivity {
# Log summary
if ($result.Reachable -and $result.CanResolve) {
Write-Log -Level SUCCESS -Message "DNS server $ServerAddress is functional" -Module $script:ModuleName
$methodInfo = if ($result.TestMethod -eq "DoH") { " (via DoH HTTPS)" } else { "" }
Write-Log -Level SUCCESS -Message "DNS server $ServerAddress is functional$methodInfo" -Module $script:ModuleName
}
else {
Write-Log -Level WARNING -Message "DNS server $ServerAddress has issues: $($result.ErrorMessage)" -Module $script:ModuleName