Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion config/tweaks.json
Original file line number Diff line number Diff line change
Expand Up @@ -1852,7 +1852,7 @@
"category": "z__Advanced Tweaks - CAUTION",
"panel": "1",
"Type": "Combobox",
"ComboItems": "Default DHCP Google Cloudflare Cloudflare_Malware Cloudflare_Malware_Adult Open_DNS Quad9 AdGuard_Ads_Trackers AdGuard_Ads_Trackers_Malware_Adult",
"ComboItems": "Default DHCP Fastest Google Cloudflare Cloudflare_Malware Cloudflare_Malware_Adult Open_DNS Quad9 AdGuard_Ads_Trackers AdGuard_Ads_Trackers_Malware_Adult",
"link": "https://winutil.christitus.com/code-reference/tweaks/z--advanced-tweaks---caution/changedns"
},
"WPFAddUltPerf": {
Expand Down
85 changes: 85 additions & 0 deletions functions/private/Get-WinUtilDNSBenchmark.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
function Get-WinUtilDNSBenchmark {
<#

.SYNOPSIS
Benchmarks neutral DNS providers by measuring TCP port 53 latency (RTT in ms) to determine the fastest DNS server.

.PARAMETER TimeoutMs
Maximum timeout in milliseconds for each connection test. Default is 1500ms.

.OUTPUTS
Array of PSCustomObjects containing Provider, PrimaryIP, and LatencyMs sorted by lowest latency.

.EXAMPLE
$results = Get-WinUtilDNSBenchmark
$fastest = $results[0]

#>
[CmdletBinding()]
param(
[int]$TimeoutMs = 1500
)

Write-WinUtilLog -Component "DNS" -Message "Starting DNS latency benchmark scan (TCP port 53)..."

$dnsConfigs = $sync.configs.dns
if ($null -eq $dnsConfigs) {
Write-Warning "DNS configurations not found in `$sync.configs.dns."
Write-WinUtilLog -Level "ERROR" -Component "DNS" -Message "DNS configurations not found in `$sync.configs.dns."
return @()
}

$results = [System.Collections.Generic.List[PSObject]]::new()

foreach ($prop in $dnsConfigs.PSObject.Properties) {
$providerName = $prop.Name
$primaryIp = $prop.Value.Primary
Comment on lines +34 to +36

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Do not let Fastest select filtering resolvers

Because this benchmarks every entry in config/dns.json, choosing Fastest can silently configure a policy/filtering resolver such as Cloudflare_Malware_Adult or AdGuard_Ads_Trackers_Malware_Adult whenever that primary IP has the lowest TCP latency. In that scenario a speed choice unexpectedly enables content blocking/rewriting behavior, so the auto-selection should be restricted to neutral providers or otherwise require an explicit filtering choice.

Useful? React with 👍 / 👎.

if (-not $primaryIp) { continue }

# Skip specialized policy/filtering variants (e.g. Malware, Adult, Family) for neutral auto-selection
if ($providerName -like "*Malware*" -or $providerName -like "*Adult*" -or $providerName -like "*Family*") {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Exclude all filtering DNS providers from Fastest

Fresh evidence in this update is that the new exclusion condition only skips Malware/Adult/Family, so Fastest still benchmarks and can select configured filtering providers like AdGuard_Ads_Trackers and Quad9 when their primary IP has the lowest TCP/53 latency. In that scenario a user choosing the speed-only option silently gets system-wide DNS content filtering they did not select; use an explicit neutral allow-list or provider metadata instead of this partial name filter.

AGENTS.md reference: AGENTS.md:L86-L86

Useful? React with 👍 / 👎.

continue
}

$latency = 9999
$client = [System.Net.Sockets.TcpClient]::new()
try {
$stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
$asyncResult = $client.BeginConnect($primaryIp, 53, $null, $null)
$success = $asyncResult.AsyncWaitHandle.WaitOne($TimeoutMs, $false)
$stopwatch.Stop()

if ($success -and $client.Connected) {
try {
$client.EndConnect($asyncResult)
} catch { }
$latency = [int]$stopwatch.ElapsedMilliseconds
} else {
$latency = 9999
}
} catch {
$latency = 9999
} finally {
if ($null -ne $client) {
try { $client.Close() } catch { }
try { $client.Dispose() } catch { }
}
}

$results.Add([PSCustomObject]@{
Provider = $providerName
PrimaryIP = $primaryIp
LatencyMs = $latency
})
}

$sortedResults = @($results | Sort-Object LatencyMs)
if ($sortedResults.Count -gt 0 -and $sortedResults[0].LatencyMs -lt 9999) {
$fastest = $sortedResults[0]
Write-WinUtilLog -Component "DNS" -Message "DNS Benchmark completed. Fastest neutral provider: $($fastest.Provider) ($($fastest.LatencyMs) ms)"
} else {
Write-WinUtilLog -Component "DNS" -Message "DNS Benchmark completed. Could not determine latency for providers."
}

return $sortedResults
}
15 changes: 15 additions & 0 deletions functions/private/Set-WinUtilDNS.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,21 @@ function Set-WinUtilDNS {
return
}

if($DNSProvider -eq "Fastest") {
Write-WinUtilLog -Component "DNS" -Message "Auto-detecting fastest DNS provider via latency benchmark..."
$benchmark = Get-WinUtilDNSBenchmark
$validFastest = $benchmark | Where-Object { $_.LatencyMs -lt 9999 } | Select-Object -First 1
if ($validFastest) {
$DNSProvider = $validFastest.Provider
Write-Host "Auto-selected fastest DNS provider: $DNSProvider ($($validFastest.LatencyMs) ms)"
Write-WinUtilLog -Component "DNS" -Message "Auto-selected fastest DNS provider: $DNSProvider ($($validFastest.LatencyMs) ms)"
} else {
Write-Warning "Could not measure DNS latency to any provider; keeping current network adapter DNS settings."
Write-WinUtilLog -Component "DNS" -Message "Benchmark timeout or all probes failed; aborting DNS change to preserve existing settings."
return
}
}

try {
$Adapters = Get-NetAdapter | Where-Object {$_.Status -eq "Up"}
Write-Host "Ensuring DNS is set to $DNSProvider on the following interfaces:"
Expand Down