Minor Release
This contains new features, security hardening and bug fixes.
Security
- Stopped DNS64-synthesized AAAA answers from claiming DNSSEC authentication. The AD bit is set only for DO clients, and only when both the AAAA denial and the A answer were authenticated upstream. DO and non-DO results are cached separately, and requests with CD set are never synthesized
- Kept Internal Domain resolver addresses and operator-defined upstream keys out of the retained log journal. The upstream loop-check probe and recovery-skip events now report a redacted
upstream.custominstead
Added
- DNS64 synthesis for IPv6-only networks without CLAT. When the network has no IPv4 and no CLAT interface, ctrld discovers the NAT64 prefix (RFC 7050) and maps A records into it for AAAA queries that the policy already allowed. IPv4-only destinations stay reachable on these networks. Blocked answers are never synthesized
- Organization Internal Domains from managed config. ctrld reads
resolver.split_dnsand routes each domain and its subdomains to the OS resolver, or to the configured resolvers when some are given. Explicit resolvers are exclusive: when all of them fail, the query returns SERVFAIL instead of falling back to the OS resolver - A log journal on disk.
ctrld-journal.logsits next toctrld.logand keeps all warnings, errors, and the network state of the host with each change of that state (interfaces, routes, resolvers, recoveries). The journal survives a service start and a self-upgrade, so support can read one file to see what happened around an incident. Each log file and eachlog sendupload starts with a header line, and uploads are limited to about 16 MB ctrld diagfor provisioning support. It collects the client version, MDM-managed preferences (macOS), the last provisioning result, the service state and API reachability in one copy-paste-safe report, with--jsonfor a machine-readable copy. It never prints the provisioning token- More provisioning failure codes. Invalid
--cd-org,--custom-hostname,--intercept-modeand conflicting flags now fail before any network call with input-stage codes (exit 20–29). Rejected provisioning codes reportTOKEN_INVALID,TOKEN_EXPIRED,TOKEN_LIMIT_REACHEDorTOKEN_DISABLED. Other terminal failures that used to crash with nothing to read now recordUNCLASSIFIED. The macOS package reports its own pre-flight failures (for example a missingProvisionToken) in the installer log - Support for Zscaler Private Access on macOS DNS intercept. ctrld resolves Zscaler's
dnsechotest.zscaler.comhealth-check name through the OS resolver and does not cache it, so Client Connector can validate its DNS path and enable Private Access. Every other name stays filtered by Control D, and--intercept-mode hardopts out - Recognition of every NextDNS endpoint under
nextdns.io, such as the ultralow and anycast variants, so these upstreams send client info too. Based on the change proposed by @mike406 (#335)
Changed
- Limited OS-triggered recovery to real outages. An OS-only resolver failure no longer starts global recovery while a configured upstream is still healthy. ctrld refreshes its OS resolver list in memory instead. When every configured upstream is down, recovery probes those upstreams rather than waiting only for OS DNS
- Made the macOS interception probe tell a real interception failure apart from a probe that could not run. Only a query that was sent but never reached ctrld triggers a pf reload. A missing target or a helper failure is now reported as
indeterminateand no longer reloads pf - Improved recovery and DNS-target diagnostics. Network transitions, recoveries, probe results and DNS-target decision failures now carry correlation IDs and outcomes. Repeated identical failures are suppressed
Fixed
- Fixed DNS on IPv6-only macOS networks with native CLAT, such as an iPhone hotspot or USB tethering. When DHCPv4 is unavailable and macOS confirms CLAT on the current primary service, ctrld now installs its DNS target. USB CLAT targets use the
networksetupservice name. An unknown or unreadable native state still leaves DNS unchanged - Made DNS target ownership on macOS safer. Ownership is saved before a target is installed, and a target that someone else cleared or edited is no longer reinstalled. A failed cleanup keeps its record, so a later sweep does not restore an outdated static DNS backup
- Chose the most specific VPN split-DNS zone, so a parent VPN domain can no longer take queries for a child zone that another VPN serves. The Linux
~.catch-all is no longer treated as a split-DNS route - Kept link-local IPv6 resolver zones from
scutil, and stopped binding scoped resolvers to the default interface's source address - Closed losing DoT and DoQ/HTTP/3 dials, and fully retired replaced DoT pools and HTTP/3 transports, so reloads and network changes no longer leak connections or sockets
- Released runtime resources on startup failure and shutdown. Network-change callbacks and recoveries are drained before host DNS is restored, and host DNS is restored while the listeners are still serving
- Serialized mobile controller teardown, so a restart can no longer overlap a session that is still stopping
- Stopped a failed Windows NRPT handback from writing ctrld's rule next to the administrator's Group Policy catch-all rule
- Skipped DNS restoration quietly for an interface that is gone, such as an unplugged adapter or a disconnected tether, instead of logging an error after a successful upgrade. Other restore failures are still logged as errors
- Bounded the DNS loop-check probe by the configured upstream timeout, instead of a fixed 2s wait for each unreachable local upstream (most visible on Windows)
- Retried
log senduploads to the API's direct IP with the full body, and moved the log to the API-configuredlog_pathwithout losing earlier lines - Skipped UniFi client discovery quietly when the
mongoexecutable is not available on the router