mirror of
https://github.com/coredns/coredns.git
synced 2026-08-26 22:57:13 -04:00
plugin/cache: add prefer_positive stale policy (#8378)
* 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
This commit is contained in:
17
plugin/cache/item.go
vendored
17
plugin/cache/item.go
vendored
@@ -22,6 +22,8 @@ type item struct {
|
||||
Ns []dns.RR
|
||||
Extra []dns.RR
|
||||
wildcard string
|
||||
answering bool // immutable result of validating that this item answers its question.
|
||||
lastKnownGood *item // answering item retained when a non-answer overwrites this success-cache key.
|
||||
|
||||
origTTL uint32
|
||||
stored time.Time
|
||||
@@ -59,6 +61,7 @@ func newItem(m *dns.Msg, now time.Time, d time.Duration) *item {
|
||||
j++
|
||||
}
|
||||
i.Extra = i.Extra[:j]
|
||||
i.answering = answersQuestion(m)
|
||||
|
||||
i.origTTL = uint32(d.Seconds())
|
||||
// Keep the monotonic clock reading so TTL expiry is unaffected by wall
|
||||
@@ -119,6 +122,20 @@ func (i *item) matches(state request.Request) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (i *item) answersQuestion(state request.Request) bool {
|
||||
return i.answering && i.matches(state)
|
||||
}
|
||||
|
||||
func (i *item) answeringItem(state request.Request) *item {
|
||||
if i.answersQuestion(state) {
|
||||
return i
|
||||
}
|
||||
if i.lastKnownGood != nil && i.lastKnownGood.answersQuestion(state) {
|
||||
return i.lastKnownGood
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *item) beginRefresh(now time.Time, failureRecheck time.Duration) bool {
|
||||
if failureRecheck > 0 {
|
||||
if retryAfter := i.retryAfter.Load(); retryAfter != nil && now.Before(*retryAfter) {
|
||||
|
||||
Reference in New Issue
Block a user