Skip to content

Security Audit - Third-party DNS: detect ControlD by asking for A, not CNAME - #1330

Merged
tvancott42 merged 1 commit into
Ozark-Connect:devfrom
truffshuff:bugfix/controld-gateway-probe
Oct 31, 2026
Merged

tvancott42 merged 1 commit into
Ozark-Connect:devfrom
truffshuff:bugfix/controld-gateway-probe

Conversation

@truffshuff

Copy link
Copy Markdown

Summary

The ControlD probe from #817 queries verify.controld.com with QueryType.CNAME, which never matches. The name has no public record (Cloudflare DoH returns NODATA), and ControlD's resolvers synthesize the CNAME api.controld.com only for an A query. A CNAME-type query comes back NODATA even through ctrld. That's why the debug logs in #948 show no ControlD record via 10.140.1.1 (CNAMEs: [none], A: [none]) for every gateway, while dig verify.controld.com (type A) on the same gateway returns the chain.

This changes the query to QueryType.A. The existing check already reads the CNAME (and the 147.185.34.x A record) out of the answer chain, so nothing else changes. With detection working, the existing gateway path from #817 sets HasThirdPartyDns and the DoH finding gets ControlD's neutral treatment.

Closes #948

Checklist

A first PR that doesn't reference an issue is closed automatically; see CONTRIBUTING.md.

  • The approach was agreed in the linked issue (this keeps the Detect on-gateway NextDNS CLI and ControlD; expand public DNS provider IPs #817 verify.controld.com approach and only fixes the query type)
  • This PR makes one change
  • It targets dev (fix for a released version) or the active release/X.Y branch (feature), not main
  • It is rebased on the latest target branch
  • dotnet build has zero warnings, and tests for the change pass
  • No unrequested UI, styling, or copy changes
  • No new dependencies, project references, or InfluxDB measurements without agreement in the issue

Testing

  • Added ProbeGatewayDnsAsync_RealControlDProbe_DetectsOnlyWhenResolverChainsToControlD. It runs the real probe (no override) through WithDialer against a loopback DNS-over-TCP resolver that behaves like ControlD: the A query returns the CNAME + A chain, and everything else, including a CNAME-type query, returns NODATA. It covers both a ControlD resolver (detected) and a plain one (not detected). Both cases fail with the old QueryType.CNAME and pass with the fix.
  • Full NetworkOptimizer.Audit.Tests suite passes (4001), built with the .NET 10 SDK with 0 warnings.
  • Manual: confirmed verify.controld.com is NODATA over Cloudflare DoH, and resolves to api.controld.com / 147.185.34.1 (type A) through ctrld on a UniFi Cloud Gateway Fiber. I haven't yet run the patched build against that gateway end to end.

🤖 Generated with Claude Code

…t CNAME

verify.controld.com has no public record; ControlD's resolvers synthesize the
CNAME to api.controld.com, but only for an A query. A CNAME-type query comes
back NODATA even through ControlD, so the probe never saw the chain and ctrld
on the gateway was never detected (no DoH credit). Query A and read the CNAME
out of the returned chain.

Refs Ozark-Connect#948

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@truffshuff

Copy link
Copy Markdown
Author

Tested the patched build against my Cloud Gateway Fiber (UniFi OS 5.1.33, Network 10.6.109, ctrld v1.5.8) running ctrld with DoH:

ControlD probe: detected via verify.controld.com CNAME through 10.140.1.1
Detected ControlD (curled) on gateway 10.140.1.1
ControlD detected on gateway across 7 network(s)

Before this change every gateway logged "no ControlD record ... (CNAMEs: [none], A: [none])".

before after

@tvancott42

Copy link
Copy Markdown
Collaborator

@truffshuff very nice! Yeah I don't run ControlD on any of my sites, so this one had me a little stumped. I'm glad you figured this out. I'll get this worked into 2.11.0-preview and the next patch release.

@tvancott42
tvancott42 merged commit 4c15c02 into Ozark-Connect:dev Oct 31, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants