mirror of
https://github.com/coredns/coredns.git
synced 2026-07-15 04:00:11 -04:00
plugin/rewrite: Fix nil-pointer panic in EDNS0 response reversion with no OPT record (#8190)
* plugin/rewrite: Fix nil-pointer panic in EDNS0 response reversion with no OPT record This PR fix a nil-pointer panic in EDNS0 response reversion when downstream responses do not contain an OPT record, Signed-off-by: Yong Tang <yong.tang.github@outlook.com> * Fix Signed-off-by: Yong Tang <yong.tang.github@outlook.com> --------- Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
This commit is contained in:
@@ -46,6 +46,9 @@ type edns0SetResponseRule struct {
|
|||||||
|
|
||||||
func (r *edns0SetResponseRule) RewriteResponse(res *dns.Msg, _ dns.RR) {
|
func (r *edns0SetResponseRule) RewriteResponse(res *dns.Msg, _ dns.RR) {
|
||||||
ednsOpt := res.IsEdns0()
|
ednsOpt := res.IsEdns0()
|
||||||
|
if ednsOpt == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
for idx, opt := range ednsOpt.Option {
|
for idx, opt := range ednsOpt.Option {
|
||||||
if opt.Option() == r.code {
|
if opt.Option() == r.code {
|
||||||
ednsOpt.Option = append(ednsOpt.Option[:idx], ednsOpt.Option[idx+1:]...)
|
ednsOpt.Option = append(ednsOpt.Option[:idx], ednsOpt.Option[idx+1:]...)
|
||||||
@@ -61,6 +64,9 @@ type edns0ReplaceResponseRule[T dns.EDNS0] struct {
|
|||||||
|
|
||||||
func (r *edns0ReplaceResponseRule[T]) RewriteResponse(res *dns.Msg, _ dns.RR) {
|
func (r *edns0ReplaceResponseRule[T]) RewriteResponse(res *dns.Msg, _ dns.RR) {
|
||||||
ednsOpt := res.IsEdns0()
|
ednsOpt := res.IsEdns0()
|
||||||
|
if ednsOpt == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
for idx, opt := range ednsOpt.Option {
|
for idx, opt := range ednsOpt.Option {
|
||||||
if opt.Option() == r.code {
|
if opt.Option() == r.code {
|
||||||
ednsOpt.Option[idx] = r.source
|
ednsOpt.Option[idx] = r.source
|
||||||
|
|||||||
@@ -195,3 +195,116 @@ func doValueReverterTests(t *testing.T, name string, rules []Rule) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var edns0NoOPTRevertTests = []struct {
|
||||||
|
name string
|
||||||
|
args []string
|
||||||
|
req func() *dns.Msg
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "local_set_revert",
|
||||||
|
args: []string{
|
||||||
|
"edns0", "local", "set",
|
||||||
|
"0xffee", "0xabcdef",
|
||||||
|
"revert",
|
||||||
|
},
|
||||||
|
req: func() *dns.Msg {
|
||||||
|
m := new(dns.Msg)
|
||||||
|
m.SetQuestion("example.org.", dns.TypeA)
|
||||||
|
m.Question[0].Qclass = dns.ClassINET
|
||||||
|
return m
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "local_replace_revert",
|
||||||
|
args: []string{
|
||||||
|
"edns0", "local", "replace",
|
||||||
|
"0xffee", "0x222222",
|
||||||
|
"revert",
|
||||||
|
},
|
||||||
|
req: func() *dns.Msg {
|
||||||
|
m := new(dns.Msg)
|
||||||
|
m.SetQuestion("example.org.", dns.TypeA)
|
||||||
|
m.Question[0].Qclass = dns.ClassINET
|
||||||
|
|
||||||
|
opt := new(dns.OPT)
|
||||||
|
opt.Hdr.Name = "."
|
||||||
|
opt.Hdr.Rrtype = dns.TypeOPT
|
||||||
|
|
||||||
|
opt.Option = append(opt.Option,
|
||||||
|
&dns.EDNS0_LOCAL{
|
||||||
|
Code: 0xffee,
|
||||||
|
Data: []byte{0x11, 0x11, 0x11},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
m.Extra = append(m.Extra, opt)
|
||||||
|
|
||||||
|
return m
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEDNS0ResponseReverterNoOPT(t *testing.T) {
|
||||||
|
ctx := context.TODO()
|
||||||
|
|
||||||
|
for _, tc := range edns0NoOPTRevertTests {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
r, err := newRule(tc.args...)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("cannot parse rule: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
rw := Rewrite{
|
||||||
|
Next: plugin.HandlerFunc(noOPTMsgPrinter),
|
||||||
|
Rules: []Rule{r},
|
||||||
|
RevertPolicy: NewRevertPolicy(false, false),
|
||||||
|
}
|
||||||
|
|
||||||
|
rec := dnstest.NewRecorder(&test.ResponseWriter{})
|
||||||
|
|
||||||
|
rw.ServeDNS(ctx, rec, tc.req())
|
||||||
|
|
||||||
|
resp := rec.Msg
|
||||||
|
if resp == nil {
|
||||||
|
t.Fatal("expected response")
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.Rcode != dns.RcodeSuccess {
|
||||||
|
t.Fatalf(
|
||||||
|
"expected rcode %d got %d",
|
||||||
|
dns.RcodeSuccess,
|
||||||
|
resp.Rcode,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(resp.Answer) != 1 {
|
||||||
|
t.Fatalf(
|
||||||
|
"expected 1 answer got %d",
|
||||||
|
len(resp.Answer),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.IsEdns0() != nil {
|
||||||
|
t.Fatalf("expected response without OPT record")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func noOPTMsgPrinter(_ context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) {
|
||||||
|
m := new(dns.Msg)
|
||||||
|
m.SetReply(r)
|
||||||
|
|
||||||
|
m.Answer = []dns.RR{
|
||||||
|
test.A("example.org. 60 IN A 127.0.0.1"),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deliberately do NOT add an OPT RR.
|
||||||
|
|
||||||
|
if err := w.WriteMsg(m); err != nil {
|
||||||
|
return dns.RcodeServerFailure, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return dns.RcodeSuccess, nil
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user