Minor Release
This contains new features, security hardening and bug fixes.
Security
- Kept Active Directory lookups off Control D's public resolver. Queries under the machine's AD domain that go to the OS resolver no longer race the domain controller against Control D's public resolver in plaintext. This covers rule-matched queries, the DNS-intercept recovery bypass, and the OS-resolver retry after an explicit upstream fails. DC hostnames, DC-locator SRV names that carry the machine name, and WPAD no longer leave the LAN
- Redacted the provision code in the
intercept upgrade checkdebug line, soctrld start --cd-org <code>no longer prints a reusable enrollment code to the console with-v/-vvor into logs that keep debug lines - Retried a query once on fresh encrypted connections after a sleep or network change, before falling back to the OS resolver, so a stale connection no longer sends the query in plaintext on port 53
Added
- DNS service through Control D API maintenance. When the API is in hard maintenance, an endpoint that already has an API-provided configuration on disk starts from it and keeps resolving. It retries the API every 5–7 minutes until it gets an answer. Without such a configuration, ctrld stops with the new
API_MAINTENANCEcode (exit 37) instead of reportingAPI_UNREACHABLE. Maintenance never counts as a permanent rejection or a deleted device, so it cannot stop the service for good or trigger a self-uninstall. Deactivation is refused while the PIN cannot be verified - Default to DNS intercept mode for new desktop installations. When no intercept mode is selected by flag or config, a new install on macOS or a Windows desktop edition uses
dns. Windows Server, iOS and other platforms keep interface DNS mode. Existing Standard installs are not switched on upgrade, and an explicitoffstays final - Tailscale Split DNS and App Connector routing in macOS intercept mode. When Tailscale's resolver is discovered, ctrld reads its route list from the Tailscale LocalAPI (Tailscale v1.98.0 or later) and sends those suffixes to
100.100.100.100. A route is taken only when it cannot loop back through ctrld; otherwise it stays on Control D - Opt-in
ctrld log sendfor standard macOS users. An administrator enablesservice.allow_unprivileged_log_sendin the device's custom ctrld configuration in the Control D dashboard and restarts the service, so standard users can upload diagnostics withoutsudo. The socket accepts only a bodyless upload request. Every upload comes from checked, root-owned log files, and uploads share a one-minute cooldown.--fulland other privileged commands still need administrator rights - Full host metadata on managed startup. Each managed daemon start sends the full metadata snapshot, including hostname hints. Username discovery uses only an active login session. When nobody is logged in,
usernameis omitted, so the API keeps the stored value instead of a guess orunknown
Changed
- Renewed upstream connections after the host sleeps. Every query checks whether the host slept since the previous one, and renews the upstream connections first if it did. A wake also re-bootstraps the upstreams
- Re-read the OS nameservers on every network change, on all platforms and in both Standard and intercept mode. Recovery reads them again at 1s, 2s, 5s and then every 30s for networks that publish their resolvers late. NAT64 discovery (
ipv4only.arpa) gets no reply while the nameserver list is stale, so the host retries it instead of giving up - Moved the DoH HTTP/2 health check to the standard library's HTTP/2 configuration, and bumped
golang.org/x/netto v0.60.0 with Go 1.26
Fixed
- Fixed DNS on IPv6-only macOS networks without DHCPv4 or PREF64 in intercept mode. ctrld used to wait for CLAT evidence, which only DNS could produce. It now sets its DNS target once the network is confirmed IPv6-only: no IPv4 state, the IPv6 primary service is this device, and the interface holds only IPv6 addresses (or a self-assigned IPv4 link-local address). The evidence must hold for 15 seconds, so a dual-stack network whose DHCPv4 answer is still on the way is not mistaken for IPv6-only
- Rolled back
ctrld upgradewhen the new binary never becomes ready. The upgrade used to report success for a service that was running but had never finished starting - Recovered upstreams from a partial bootstrap lookup. When the bootstrap answer had only one address family (for example AAAA only), A queries failed with
empty addressesuntil a restart. ctrld now fills the missing family from Control D's direct IPs and looks it up again on the next re-bootstrap - Built Docker images by cross-compiling instead of under emulation. On hosts with an older qemu, a failed build could still produce an image that shipped without ctrld. The build now fails when the binary is missing