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:
Sueun Cho
2026-08-18 12:12:32 +09:00
committed by GitHub
parent 897b4ce643
commit 9a623cdeed
5 changed files with 99 additions and 13 deletions

View File

@@ -26,9 +26,18 @@ func serveEdns0Rewrite(t *testing.T, rule Rule, next plugin.Handler, req *dns.Ms
rec := dnstest.NewRecorder(&test.ResponseWriter{})
// The server wraps the client writer in a ScrubWriter; reproduce that here.
sw := request.NewScrubWriter(req, rec)
if _, err := rw.ServeDNS(context.Background(), sw, req); err != nil {
rcode, err := rw.ServeDNS(context.Background(), sw, req)
if err != nil {
t.Fatal(err)
}
if !plugin.ClientWrite(rcode) {
state := request.Request{W: sw, Req: req}
resp := new(dns.Msg).SetRcode(req, rcode)
state.SizeAndDo(resp)
if err := sw.WriteMsg(resp); err != nil {
t.Fatal(err)
}
}
return rec.Msg
}