github Control-D-Inc/ctrld v1.5.5
Release v1.5.5

3 hours ago

Minor Release

This contains security hardening and bug fixes.

Security

  • Bumped golang.org/x/text to v0.40.0 to address GO-2026-5970
  • Discarded upstream answers whose question does not echo the request - defense in depth against cache poisoning. A compromised or misbehaving upstream could return an answer for a different name (e.g. records for attacker.example in response to a query for victim.example), which would be cached under the legitimate request key and served to later queries. The answer is now validated against the request's question (case-insensitive name plus Qtype/Qclass, per RFC 1035 §4.1.2) before it is served or cached; a mismatch is logged at debug level and the upstream is skipped, failing safe to the next upstream or SERVFAIL

Fixed

  • Partitioned the DNS cache by EDNS Client Subnet (ECS). With cache_enable = true, one cache entry was shared by every client asking the same name against the same upstream, so a response tailored for subnet A could be served to subnet B (returning the wrong CDN/policy answer, per RFC 7871 §7.3). Both cache paths are now keyed by a canonical ECS tuple so different subnets never share an entry, while same-subnet queries still share one
  • Fixed the DoQ resolver corrupting upstream responses by calling SetReply on the already-unpacked answer, which forced the RCODE to NOERROR and overwrote the Question section. This masked upstream failures from the proxy's failover logic (a SERVFAIL looked like a successful empty response) and corrupted the Question served to clients. Only the downstream transaction ID is now restored, preserving the upstream RCODE, Question, and answers - matching the DoH and DoT resolvers
  • Treated the 464XLAT CLAT source range as local rather than WAN. On IPv6-only cellular carriers and iPhone hotspots, local DNS queries can arrive with a source in the RFC 7335 IPv4 Service Continuity Prefix (192.0.0.0/29), which was classified as a WAN client and refused when allow_wan_clients was unset (the default), breaking DNS resolution on the affected connection. The 192.0.0.0/29 range is now recognized as local
  • Preserved the fallback listener port across config reload in macOS DNS-intercept mode. When mDNSResponder owns *:53, ctrld falls back to 127.0.0.1:5354, but an hourly CD config reload reverted the in-memory port to 53 while the listener stayed on 5354, causing an endless watchdog "force reload" loop and dig timeouts. The actual bound listener IP/port is now restored into the in-memory config after reload
  • Skipped internal logging in --silent mode. In cd mode, --silent still created and grew a log file and reset the global log level back to debug, overriding the level --silent had set. ctrld now neither creates the internal log file nor writes debug logs when silent is set
  • Restored system DNS during an invalid-device uninstall, so DNS is no longer left pointing at the stopped listener when uninstalling with an invalid device

Don't miss a new ctrld release

NewReleases is sending notifications on new releases.