Skip to content

feat(dns): Add real-time DNS speed benchmark and 'Fastest' auto-selection option - #4935

Open
MADHACKER85 wants to merge 3 commits into
ChrisTitusTech:mainfrom
MADHACKER85:feat/dns-benchmark
Open

feat(dns): Add real-time DNS speed benchmark and 'Fastest' auto-selection option#4935
MADHACKER85 wants to merge 3 commits into
ChrisTitusTech:mainfrom
MADHACKER85:feat/dns-benchmark

Conversation

@MADHACKER85

Copy link
Copy Markdown

Summary

Users frequently set custom DNS in WinUtil without knowing which provider offers the lowest latency for their local connection/ISP. This PR adds a lightweight, firewall-safe TCP port 53 latency benchmark (Get-WinUtilDNSBenchmark) and adds a Fastest option to the DNS dropdown (WPFchangedns).

Key Changes

  1. Get-WinUtilDNSBenchmark.ps1: Uses non-blocking TCP port 53 socket handshakes (System.Net.Sockets.TcpClient) to measure sub-second RTT latency to all configured DNS providers.
  2. Set-WinUtilDNS.ps1: Added support for -DNSProvider 'Fastest'. When selected, WinUtil benchmarks latency across all providers, logs results, and automatically configures the lowest-ping DNS provider.
  3. config/tweaks.json: Added Fastest option to WPFchangedns Combobox.

Verification

Tested in PowerShell 5.1 / 7+ environment across 8 DNS providers:

  • Measured latency accurately (e.g. OpenDNS 37ms, Cloudflare 41ms, Quad9 51ms, Google 65ms).
  • Completed full benchmark scan in under 1 second.
  • Tested Compile.ps1 build output cleanly.

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added a Fastest DNS option that benchmarks available providers and selects the quickest one.
    • Added DNS connection performance testing with configurable timeout handling.
  • Bug Fixes

    • Improved handling of unavailable providers, connection failures, and timeouts.
    • Existing DNS settings are preserved when no provider can be measured successfully.

Walkthrough

Adds a Fastest DNS option to WPFchangedns. Adds Get-WinUtilDNSBenchmark to measure configured DNS provider latency. Updates Set-WinUtilDNS to select a valid provider or preserve existing adapter DNS settings.

Changes

DNS fastest-provider selection

Layer / File(s) Summary
DNS provider benchmarking
functions/private/Get-WinUtilDNSBenchmark.ps1, .biomeignore
Measures TCP port 53 latency for configured DNS providers, records failures as 9999, sorts results, and returns provider data. Adds JSON ignore rules for Biome.
Fastest DNS provider integration
config/tweaks.json, functions/private/Set-WinUtilDNS.ps1
Adds Fastest to the DNS combobox. The DNS setter selects the first valid benchmark result. If measurement fails, it preserves existing adapter DNS settings.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant WPFchangedns
  participant SetWinUtilDNS
  participant GetWinUtilDNSBenchmark
  participant DNSProvider
  WPFchangedns->>SetWinUtilDNS: Select Fastest
  SetWinUtilDNS->>GetWinUtilDNSBenchmark: Benchmark configured providers
  GetWinUtilDNSBenchmark->>DNSProvider: Test TCP port 53
  DNSProvider-->>GetWinUtilDNSBenchmark: Return latency or failure
  GetWinUtilDNSBenchmark-->>SetWinUtilDNS: Return sorted results
  SetWinUtilDNS-->>WPFchangedns: Apply selected provider or preserve adapter DNS settings
Loading

Possibly related PRs

Suggested labels: new feature

Suggested reviewers: christitustech

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the DNS benchmarking feature and the new Fastest auto-selection option.
Description check ✅ Passed The description directly explains the DNS benchmark, Fastest provider selection, configuration change, and verification.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot added the new feature New feature or request label Aug 7, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a3df14ad33

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread functions/private/Set-WinUtilDNS.ps1 Outdated
Comment on lines +30 to +32
$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 👍 / 👎.

Comment thread functions/private/Set-WinUtilDNS.ps1 Outdated
Comment on lines +30 to +32
$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.

Useful? React with 👍 / 👎.

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

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 👍 / 👎.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@functions/private/Get-WinUtilDNSBenchmark.ps1`:
- Around line 42-55: Update the TCP probe around the visible $client and
$asyncResult operations to use try/finally cleanup: after a successful wait,
call $asyncResult.EndConnect() and ensure $client is closed or disposed on every
success, timeout, and exception path. Preserve the 9999 fallback latency, and do
not dispose $asyncResult.AsyncWaitHandle.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 16975faa-5874-48d4-93ce-bfa656774f1e

📥 Commits

Reviewing files that changed from the base of the PR and between 8d3adb5 and a3df14a.

📒 Files selected for processing (3)
  • config/tweaks.json
  • functions/private/Get-WinUtilDNSBenchmark.ps1
  • functions/private/Set-WinUtilDNS.ps1

Comment thread functions/private/Get-WinUtilDNSBenchmark.ps1 Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.biomeignore:
- Line 4: Remove the broad *.json rule from .biomeignore so JSON files under
docs, including package-lock.json, package.json, and tsconfig.json, remain
included; retain the existing config-specific ignore rules.
- Around line 1-4: Remove the inert .biomeignore file and move its JSON
exclusion patterns into a supported Biome ignore mechanism, preferably the
excludes configuration in biome.json; preserve coverage for config/*.json,
nested config/*.json, and all *.json files.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 14808587-468d-44cb-b543-75eed0159b70

📥 Commits

Reviewing files that changed from the base of the PR and between a3df14a and f2b8e0f.

📒 Files selected for processing (3)
  • .biomeignore
  • functions/private/Get-WinUtilDNSBenchmark.ps1
  • functions/private/Set-WinUtilDNS.ps1
🚧 Files skipped from review as they are similar to previous changes (2)
  • functions/private/Set-WinUtilDNS.ps1
  • functions/private/Get-WinUtilDNSBenchmark.ps1

Comment thread .biomeignore Outdated
Comment thread .biomeignore Outdated
# Biome ignore rules for PowerShell JSON config files
config/*.json
**/config/*.json
*.json

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

unexpected=0
while IFS= read -r file; do
  case "$file" in
    config/*.json|*/config/*.json) ;;
    *) printf 'JSON file outside config/: %s\n' "$file"; unexpected=1 ;;
  esac
done < <(git ls-files -- '*.json')

exit "$unexpected"

Repository: ChrisTitusTech/winutil

Length of output: 213


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

echo "== .biomeignore =="
if [ -f .biomeignore ]; then
  cat -n .biomeignore
else
  echo "MISSING .biomeignore"
fi

echo
echo "== tracked top-level JSON files =="
git ls-files '*.json' | sed -n '1,120p'
echo
echo "== tracked JSON files outside config paths =="
git ls-files '*.json' | grep -Ev '(^|/)config/' || true

echo
echo "== Biomignore config JSON exclusions in package =="
git ls-files '*biome*' 'biome*' '.*biome*' | sort | sed -n '1,120p'

Repository: ChrisTitusTech/winutil

Length of output: 728


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

python3 - <<'PY'
import subprocess

files = subprocess.check_output(['git', 'ls-files', '*.json'], text=True).splitlines()
config_files = [f for f in files if f.startswith('config/') or '/config/' in f or f in ('config', 'configs')]
outside = [f for f in files if f not in config_files]

print('total tracked JSON:', len(files))
print('config-path JSON:', len(config_files))
print('non-config JSON:', len(outside))
for f in outside[:120]:
    print(f)
PY

Repository: ChrisTitusTech/winutil

Length of output: 282


Scope the Biome ignore rule to keep docs JSON files included.

*.json also excludes docs/package-lock.json, docs/package.json, and docs/tsconfig.json, while the config/ rules already cover the configuration JSON files. Remove line [4] unless every repository JSON file should be ignored.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.biomeignore at line 4, Remove the broad *.json rule from .biomeignore so
JSON files under docs, including package-lock.json, package.json, and
tsconfig.json, remain included; retain the existing config-specific ignore
rules.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 614cb6b21c

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

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 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

new feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant