Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
73 changes: 73 additions & 0 deletions functions/private/Get-WinUtilDNSBenchmark.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
function Get-WinUtilDNSBenchmark {
<#

.SYNOPSIS
Benchmarks configured 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 }

$latency = 9999
$stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
try {
$client = New-Object System.Net.Sockets.TcpClient
$asyncResult = $client.BeginConnect($primaryIp, 53, $null, $null)
$success = $asyncResult.AsyncWaitHandle.WaitOne($TimeoutMs, $false)
$stopwatch.Stop()
if ($success -and $client.Connected) {
$latency = [int]$stopwatch.ElapsedMilliseconds
$client.Close()
} else {
$latency = 9999
if ($client) { $client.Close() }
}
} catch {
$latency = 9999
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated

$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: $($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 {
$DNSProvider = "Cloudflare"
Write-Warning "Could not measure DNS latency; defaulting to Cloudflare."
Write-WinUtilLog -Component "DNS" -Message "Benchmark timeout; defaulting to Cloudflare."

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 Avoid changing DNS when no benchmark succeeds

When Fastest is selected on networks where outbound TCP/53 is blocked or every benchmark probe times out, this branch still rewrites the adapter DNS to Cloudflare even though no provider was measured as reachable. That can replace a working DHCP/corporate resolver with a public resolver the network may block and leave the machine without DNS; in the no-result case, keep the current settings or abort instead of applying an unverified fallback.

AGENTS.md reference: AGENTS.md:L84-L91

Useful? React with 👍 / 👎.

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 Avoid changing DNS when no benchmark succeeds

When Fastest is selected on networks where outbound TCP/53 is blocked or every benchmark probe times out, this branch still rewrites the adapter DNS to Cloudflare even though no provider was measured as reachable. That can replace a working DHCP/corporate resolver with a public resolver the network may block and leave the machine without DNS; in the no-result case, keep the current settings or abort instead of applying an unverified fallback.

Useful? React with 👍 / 👎.

}
}

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