diff --git a/plugin/rewrite/reverter.go b/plugin/rewrite/reverter.go index 4aa6f8a5e..3204263ff 100644 --- a/plugin/rewrite/reverter.go +++ b/plugin/rewrite/reverter.go @@ -73,7 +73,11 @@ func (r *ResponseReverter) WriteMsg(res1 *dns.Msg) error { res := res1.Copy() if r.revertPolicy.DoQuestionRestore() { - res.Question[0] = r.originalQuestion + if len(res.Question) == 0 { + res.Question = []dns.Question{r.originalQuestion} + } else { + res.Question[0] = r.originalQuestion + } } if len(r.ResponseRules) > 0 { for _, rr := range res.Ns { diff --git a/plugin/rewrite/reverter_test.go b/plugin/rewrite/reverter_test.go index 59cebf714..b235fed3c 100644 --- a/plugin/rewrite/reverter_test.go +++ b/plugin/rewrite/reverter_test.go @@ -292,6 +292,55 @@ func TestEDNS0ResponseReverterNoOPT(t *testing.T) { } } +func TestResponseReverterRestoresMissingQuestion(t *testing.T) { + ctx := context.TODO() + + r, err := newNameRule("stop", "suffix", ".example.org", ".example.net", "answer", "auto") + if err != nil { + t.Fatalf("cannot parse rule: %s", err) + } + + req := new(dns.Msg) + req.SetQuestion("service.example.org.", dns.TypeA) + req.Question[0].Qclass = dns.ClassINET + + rw := Rewrite{ + Next: plugin.HandlerFunc(noQuestionMsgPrinter), + Rules: []Rule{r}, + RevertPolicy: NewRevertPolicy(false, false), + } + + rec := dnstest.NewRecorder(&test.ResponseWriter{}) + if _, err := rw.ServeDNS(ctx, rec, req); err != nil { + t.Fatalf("ServeDNS returned error: %v", err) + } + + resp := rec.Msg + if resp == nil { + t.Fatal("expected response") + } + + if len(resp.Question) != 1 { + t.Fatalf("expected 1 question got %d", len(resp.Question)) + } + + if got := resp.Question[0].Name; got != "service.example.org." { + t.Fatalf("question name = %q, want %q", got, "service.example.org.") + } + + if got := resp.Question[0].Qtype; got != dns.TypeA { + t.Fatalf("question type = %d, want %d", got, dns.TypeA) + } + + if len(resp.Answer) != 1 { + t.Fatalf("expected 1 answer got %d", len(resp.Answer)) + } + + if got := resp.Answer[0].Header().Name; got != "service.example.org." { + t.Fatalf("answer name = %q, want %q", got, "service.example.org.") + } +} + func noOPTMsgPrinter(_ context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { m := new(dns.Msg) m.SetReply(r) @@ -308,3 +357,16 @@ func noOPTMsgPrinter(_ context.Context, w dns.ResponseWriter, r *dns.Msg) (int, return dns.RcodeSuccess, nil } + +func noQuestionMsgPrinter(_ context.Context, w dns.ResponseWriter, _ *dns.Msg) (int, error) { + m := new(dns.Msg) + m.Answer = []dns.RR{ + test.A("service.example.net. 60 IN A 127.0.0.1"), + } + + if err := w.WriteMsg(m); err != nil { + return dns.RcodeServerFailure, err + } + + return dns.RcodeSuccess, nil +}