* plugin/cache: add prefer_positive stale policy
Add an opt-in serve_stale_policy that prefers an eligible success-cache
answer over denial-cache entries while serve_stale is enabled. Preserve the
existing ncache-first behavior when the policy is absent.
Also classify SOA-backed CNAME NODATA responses in the cache so incomplete
answers cannot be selected as positive stale responses.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 25da81ab-92dd-4663-b480-efd6262090c6
Signed-off-by: Nitin Nizhawan <nnizhawan@microsoft.com>
* plugin/cache: retain last-known-good positive answers
Keep an answering success-cache item reachable when a later NOERROR or
referral response overwrites the visible cache key without answering the
question. This lets prefer_positive survive empty responses, referrals, and
additional-only data while leaving policy-off lookup behavior unchanged.
Return the exact accepted verify refresh item instead of re-reading an
ambiguous cache key, avoiding expired TTL wraparound for uncacheable replies.
Add regression coverage for non-answer refreshes, NODATA, SERVFAIL, NOTIMP,
stale-window expiry, and bounded verify reply shaping.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 25da81ab-92dd-4663-b480-efd6262090c6
Signed-off-by: Nitin Nizhawan <nnizhawan@microsoft.com>
* plugin/cache: validate preferred stale answers
Reject truncated, DNSSEC-expired, mismatched-class, unrelated ANY, and ambiguous CNAME refreshes before replacing a stale last-known-good answer. Precompute answer eligibility when cache items are created so prefer_positive hits avoid repeated CNAME walks.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 25da81ab-92dd-4663-b480-efd6262090c6
Signed-off-by: Nitin Nizhawan <nnizhawan@microsoft.com>
---------
Signed-off-by: Nitin Nizhawan <nnizhawan@microsoft.com>
Co-authored-by: Nitin Nizhawan <nnizhawan@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 25da81ab-92dd-4663-b480-efd6262090c6
* plugin/cache: do not cache SOA-less NODATA responses
An upstream may return NOERROR with a non-empty answer that still does not
resolve the question and without an SOA record to bound a negative TTL: a
CNAME chain that does not terminate in a record of the queried type at the
chain's terminal name (an incomplete recursion result from a forwarder).
Because the answer section is non-empty, response.Typify classifies it as
NoError (positive), so the cache plugin stores it keyed on <qname,qtype> and
replays the non-answer to clients until the TTL expires.
Per RFC 2308 section 5, negative responses without an SOA record SHOULD NOT be
cached. Following RFC 1034 section 3.6.2 and RFC 2308 sections 1 and 2.2, the
effective owner name is the target at the end of the CNAME chain, and the
response is NODATA unless it carries the queried type at that terminal name;
this holds for every query type, not just A/AAAA. Skip caching such a response
(mirroring the existing NameError && !hasSOA guard) and let the next query be
resolved upstream again.
An empty answer section is deliberately left cacheable: it is indistinguishable
from a legitimate NOERROR positive response that carries its data outside the
answer section (for example the whoami plugin).
Refs coredns#6958, coredns#5077, coredns#4987.
Signed-off-by: Nitin Nizhawan <nitin.nizhawan@gmail.com>
* plugin/cache: fail closed on malformed CNAME chains in isNODATA
canonicalName now returns a validity flag and rejects chains that are not a
single unambiguous path to a terminal name: an owner with more than one
distinct CNAME target (RFC 2181 section 10.1) and a revisited owner / CNAME
loop (RFC 1034 section 3.6.2). isNODATA treats an invalid chain as a
non-answer, so a SOA-less response with such a chain is not cached. This makes
the classification order-independent (previously the first CNAME per owner
won, so a two-target owner was cacheable or not depending on wire order) and
closes the loop-with-co-located-record case. Duplicate CNAME records naming
the same target are still tolerated.
Adds regression tests for the two-distinct-targets case in both orders, the
CNAME loop with a co-located A, and the tolerated duplicate-identical-CNAME
case.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d59b4564-a9df-425f-858e-aadee0f35581
Signed-off-by: Nitin Nizhawan <nitin.nizhawan@gmail.com>
* plugin/cache: split canonicalName into self-documenting helpers
Extract the per-owner CNAME lookup into uniqueCNAMETarget and loop detection
into a small case-insensitive nameSet type, leaving canonicalName as a short
driver. Signature and algorithm are unchanged.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d59b4564-a9df-425f-858e-aadee0f35581
Signed-off-by: Nitin Nizhawan <nitin.nizhawan@gmail.com>
---------
Signed-off-by: Nitin Nizhawan <nitin.nizhawan@gmail.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d59b4564-a9df-425f-858e-aadee0f35581
Keep cache timestamps and TTL calculations on the time values returned by the cache clock. Converting them with UTC strips Go's monotonic clock reading and can extend cached entries when the wall clock moves backward.
Add a regression test that verifies new cache items retain the original monotonic timestamp.
Fixes#5478.
Signed-off-by: houyuwushang <liuluoqianqiu@outlook.com>
The cache key is hashed on qname, qtype, DO and CD, but deliberately not on the AD bit, so a single entry serves both AD- and non-AD-requesting clients. The AD bit returned must therefore be derived per request from the cached answer's authentication status, not frozen from the query that populated the entry.
This pins both orderings (noad-then-ad and ad-then-noad) so the historical asymmetry reported in #6642 cannot regress.
Signed-off-by: baltasarblanco <baltablanco9008@gmail.com>
When serve_stale is enabled, a cached SERVFAIL in ncache shadows a valid
positive entry in pcache because ncache is always checked first. SERVFAIL
is transient and should not mask a known-good answer.
When the ncache hit is a SERVFAIL, check pcache for a valid entry before
returning the SERVFAIL. NXDOMAIN and NODATA are unaffected and still
follow the existing ncache-first lookup per RFC 2308.
Fixes#7956
Signed-off-by: umut-polat <52835619+umut-polat@users.noreply.github.com>
- Added nolint to plugin/auto/walk.go to avoid a symlink/TOCTOU
warning, as it needs to follow symlink.
- Replaced a few flagged integer conversions with safe equivalents in
cache hashing, reuseport socket setup, and TLS arg handling
- Preallocated response rule slices in plugin/rewrite/name.go
- Replaced WriteString(fmt.Sprintf/Sprintln(...)) with direct
fmt.Fprint* calls
- Removed stale nolint directives from code and tests that are no
longer needed
Signed-off-by: Ville Vesilehto <ville@vesilehto.fi>
This commit removes superfluous allocations of the Answer, Ns, and Extra
slices when copying a cached a dns.Msg. The allocations are superfluous
because we immediately overwrite the newly copied slices with
filterRRSlice. It also updates filterRRSlice to pre-calculate the size
of the slice being copied into.
Benchmark results:
goos: darwin
goarch: arm64
pkg: github.com/coredns/coredns/plugin/cache
cpu: Apple M4 Pro
│ base.10.txt │ new.10.txt │
│ sec/op │ sec/op vs base │
CacheResponse-14 471.1n ± 0% 462.9n ± 2% -1.74% (p=0.009 n=10)
│ base.10.txt │ new.10.txt │
│ B/op │ B/op vs base │
CacheResponse-14 672.0 ± 0% 656.0 ± 0% -2.38% (p=0.000 n=10)
│ base.10.txt │ new.10.txt │
│ allocs/op │ allocs/op vs base │
CacheResponse-14 13.00 ± 0% 12.00 ± 0% -7.69% (p=0.000 n=10)
Signed-off-by: Charlie Vieth <charlie.vieth@gmail.com>
Wrap doPrefetch with a fresh metadata context to prevent concurrent
writes to the request-scoped metadata map during background prefetch.
Add a new integration test configuring a plugin chain, triggering
the issue seen here. Hammers concurrent queries while log reads
metadata fields repeatedly.
Signed-off-by: Ville Vesilehto <ville@vesilehto.fi>
Enable intrange linter to enforce modern Go range syntax over
traditional for loops, by converting:
for i := 0; i < n; i++
to:
for i := range n
Adding type conversions where needed for compatibility
with existing uint64 parameters.
Signed-off-by: Ville Vesilehto <ville@vesilehto.fi>
* plugin/cache: key cache on Checking Disabled (CD) bit
Key the cache on CD bit, which effectively separates the entries for
queries with CD disabled or enabled.
Signed-off-by: Grant Spence <gspence@redhat.com>
* introduce new interface "dnsserver.Viewer", that allows a plugin implementing it to decide if a query should be routed into its server block.
* add new plugin "view", that uses the new interface to enable a user to define expression based conditions that must be met for a query to be routed to its server block.
Signed-off-by: Chris O'Haver <cohaver@infoblox.com>
For responses synthesized by known wildcard records, publish metadata containing the wildcard record name
Signed-off-by: Chris O'Haver <cohaver@infoblox.com>
This PR adds an optional REFRESH_MODE parameter on the serve_stale configuration directive of the
cache plugin, which verifies that the upstream is still unavailable before returning stale entries.
Signed-off-by: Antoine Tollenaere <atollena@gmail.com>