mirror of
https://github.com/coredns/coredns.git
synced 2026-08-27 23:27:05 -04:00
plugin/rewrite: apply rcode rewrites to responses with no records (#8421)
* plugin/rewrite: apply rcode rewrites to record-less responses An rcode rewrite rewrites the message-level RCODE, but the reverter only ran response rules from inside the per-record loops in WriteMsg. When a response carries no answer, authority or additional records - for example a bare SERVFAIL that a downstream plugin returns to a non-EDNS client - none of the loops iterate, so the rcode rewrite was silently skipped and the client received the original RCODE. Apply message-level response rules once when the response has no records, using a small marker interface that mirrors the existing requestExtraRevertRule pattern. This fixes the plugin's documented SERVFAIL-to-NOERROR use case for responses without records. Signed-off-by: Sueun Cho <sueun.dev@gmail.com> * plugin/rewrite: apply fallback rcode rewrites for continue Signed-off-by: Sueun Cho <sueun.dev@gmail.com> --------- Signed-off-by: Sueun Cho <sueun.dev@gmail.com>
This commit is contained in:
@@ -49,6 +49,14 @@ type requestExtraRevertRule interface {
|
||||
revertRequestExtra()
|
||||
}
|
||||
|
||||
// msgResponseRule is a ResponseRule that rewrites message-level fields, which
|
||||
// are independent of any resource record (for example the RCODE). Such a rule
|
||||
// must still be applied when the response carries no records.
|
||||
type msgResponseRule interface {
|
||||
ResponseRule
|
||||
rewriteMsg()
|
||||
}
|
||||
|
||||
// ResponseRules describes an ordered list of response rules to apply
|
||||
// after a name rewrite
|
||||
type ResponseRules = []ResponseRule
|
||||
@@ -96,6 +104,13 @@ func (r *ResponseReverter) WriteMsg(res1 *dns.Msg) error {
|
||||
for _, rr := range res.Extra {
|
||||
r.rewriteResourceRecord(res, rr)
|
||||
}
|
||||
// Message-level response rules (e.g. rcode) rewrite header fields that
|
||||
// are independent of any resource record. The per-record loops above
|
||||
// never run them when the response carries no records (e.g. a bare
|
||||
// SERVFAIL from a downstream plugin), so apply them once here.
|
||||
if len(res.Ns) == 0 && len(res.Answer) == 0 && len(res.Extra) == 0 {
|
||||
r.rewriteMsg(res)
|
||||
}
|
||||
}
|
||||
return r.writeWithRevertedRequestExtra(res)
|
||||
}
|
||||
@@ -146,6 +161,19 @@ func (r *ResponseReverter) rewriteResourceRecord(res *dns.Msg, rr dns.RR) {
|
||||
}
|
||||
}
|
||||
|
||||
// rewriteMsg applies the message-level response rules once, in reversed order.
|
||||
// It is used for responses that carry no resource records, where the per-record
|
||||
// loops in WriteMsg would otherwise never apply them.
|
||||
func (r *ResponseReverter) rewriteMsg(res *dns.Msg) {
|
||||
// The reverting rules need to be done in reversed order.
|
||||
for i := len(r.ResponseRules) - 1; i >= 0; i-- {
|
||||
if _, ok := r.ResponseRules[i].(msgResponseRule); !ok {
|
||||
continue
|
||||
}
|
||||
r.ResponseRules[i].RewriteResponse(res, nil)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *ResponseReverter) rewriteRequestExtra(req *dns.Msg, rr dns.RR) {
|
||||
// The reverting rules need to be done in reversed order.
|
||||
for i := len(r.ResponseRules) - 1; i >= 0; i-- {
|
||||
|
||||
Reference in New Issue
Block a user