Patch release for 1.6.3. Major focus on RFC 5011 trust-anchor correctness, DNSSEC validation hardening, and listener lifecycle. Also closes a build-tag bug that prevented 1.6.4 from releasing on FreeBSD/NetBSD/OpenBSD/DragonFly.
Note: 1.6.4 was tagged but never published — the goreleaser pipeline failed on
freebsd_amd64because of thereuseport_*build constraint bug fixed in this release. 1.6.5 is the first available shipping point that includes the trust-anchor work below.
What's Changed
Trust Anchors (RFC 5011)
A full pass over middleware/resolver/auto_trust_anchor.go to bring the resolver into alignment with RFC 5011 §2 / §4 and to harden persistence against partial failures. Highlights:
verifyFetchedKeysis now correct under KSK rollover. At-least-one-trusted-anchor RRSIG semantics with a narrow revoked-bootstrap carve-out (RFC 5011 §2.1: a revoked key may authenticate the RRset that contains it, but only for the purpose of validating its own revocation). Returns a split-mode flag so a revoked-only proof can tombstone the matching key but cannot seed AddPend or mark other anchors missing.- Revocation requires a self-signed RRSIG and key-material match, not just key-tag arithmetic. Defends against 16-bit tag collisions where an unrelated self-signed key could otherwise be admitted as a revocation of the real anchor.
- Tombstones moved out of
kskCurrentinto a material-keyed store with its own state file. Tag collisions with future legitimate KSKs can no longer suppress them. - Missing keys remain valid trust-point keys until the remove hold-down expires (§4.2). Missing→Valid restoration on KeyPres. AddPend reset on KeyRem (the hold-down aborts cleanly instead of drifting through Missing). Missing-aged-out simply deletes (§2.4.2 is bookkeeping); only RevBit revocations tombstone permanently.
- Configured-merge uses an immutable
cfg.RootKeyssnapshot taken at startup, honours tombstones by key material, filters seeded entries on load, and refuses to resurrect a stale admin-config anchor that the root has revoked. - Atomic gob writes (CreateTemp + fsync + rename + parent dirsync) with tombstones-first ordering. New revocations dual-write to a
StateRevokedmarker so a tombstone-write failure survives across retries; selective fail-closed only when an actual contraction would otherwise be lost on disk. - New
errTrustAnchorsUnavailablegatesanswer/authority/validateDelegationand the two delegation-cacheSetsites, so an empty trust set fails closed with SERVFAIL instead of slipping into the "unsigned delegation" branch. AutoTA's own DNSKEY query runs CD=true so it doesn't depend onr.rootKeys.
Bug Fixes
- Build reuseport file on all BSDs, not just darwin. The file was named
reuseport_darwin.go, which Go treats as an implicit GOOS=darwin build constraint. The explicit//go:build darwin || freebsd || netbsd || openbsd || dragonflywas ANDed against that, so freebsd/netbsd/openbsd/dragonfly all failed to link withundefined: defaultUDPWorkers / kernelLoadBalances / reusePortControl. Renamed toreuseport_bsds.goso the explicit tag governs. - Windows compatibility for AutoTA persistence. Split the post-rename directory fsync into platform-specific helpers (POSIX does it; Windows is a no-op since FlushFileBuffers on a directory handle requires GENERIC_WRITE which
os.Opendoesn't grant). Tombstones-file open errors now distinguish Windows sharing violations from real corruption — only decode failures fail closed. - DNSSEC validation hardening + DNAME correctness. SERVFAIL when a signed zone omits RRSIG. Multiple correctness fixes around DNAME synthesis and parallel lookup paths.
- Five correctness bugs in the parallel lookup path.
- Listener lifecycle: explicit fail-fast binds. Listener startup now fails immediately if a bind cannot be established, instead of silently degrading.
Performance
- Pool
net.Dialerand bypassDialContexton UDP upstream. Per-query allocation cut on the recursive hot path. - Pre-build hostsfile answer RRs at load time instead of constructing them per query.
Refactor / Naming
- Package
authcache→authority(split intoserver.go+cache.go). Type renames:AuthServer/AuthServers→Server/Servers;NSCache→Cache;NS→Delegation;DSRR→DSSet;Version→IPVersion. parentDSRR/parentdsrr→parentDS.accesslist.AccessList→accesslist.List;accesslog.AccessLog→accesslog.Log(config field names preserved).r.ncache→r.delegations;nameserversmap type →hostSet;nameserverInfo→delegationInfowithhostsfield.rootservers/rootkeys(smashed lowercase) →rootServers/rootKeys.ipv4cache/ipv6cache→glueV4/glueV6.- Internal sub-pipeline now flows through the
Queryerinterface;util.ExchangeInternalretired.
Dependencies
github.com/semihalev/zlog/v2→ v2.0.6.k8s.io/apimachinery→ 0.36.0.k8s.io/client-go→ 0.36.0.codecov/codecov-action→ v6.
Full Changelog: v1.6.3...v1.6.5