mirror of
https://github.com/coredns/coredns.git
synced 2026-10-09 03:55:21 -04:00
plugin/autopath: Fixes a nil pointer dereference panic in autopath during search path walk (#8517)
* plugin/autopath: Fixes a nil pointer dereference panic in autopath during search path walk When a plugin later in the chain returns a ClientWrite rcode without writing a response (for example acl's drop action, which returns (dns.RcodeSuccess, nil) without calling WriteMsg), autopath dereferences a nil nw.Msg at nw.Msg.Rcode and panics. The final fallback w.WriteMsg(firstReply) can also receive a nil firstReply for the same reason. Skip search path elements that produced no message, and only write the first reply when it is non-nil. This mirrors the nil guards recently added in plugin/minimal (#8506), plugin/dns64 (#8511) and plugin/cache (#8512). Signed-off-by: zjncs <18910855655@163.com> * plugin/autopath: silence unused-parameter lint and assert no client write Address review feedback on #8517: rename the unused 'w' parameter in TestAutoPathNilMsgFromNext to '_w' so the revive unused-parameter check passes, and assert that the recorder receives no message so the intended drop/no-client-write behavior is explicit. Signed-off-by: zjncs <18910855655@163.com> --------- Signed-off-by: zjncs <18910855655@163.com>
This commit is contained in:
@@ -123,6 +123,10 @@ func (a *AutoPath) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Ms
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if nw.Msg == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if nw.Msg.Rcode == dns.RcodeNameError {
|
if nw.Msg.Rcode == dns.RcodeNameError {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -135,7 +139,7 @@ func (a *AutoPath) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Ms
|
|||||||
autoPathCount.WithLabelValues(metrics.WithServer(ctx)).Add(1)
|
autoPathCount.WithLabelValues(metrics.WithServer(ctx)).Add(1)
|
||||||
return rcode, err
|
return rcode, err
|
||||||
}
|
}
|
||||||
if plugin.ClientWrite(firstRcode) {
|
if plugin.ClientWrite(firstRcode) && firstReply != nil {
|
||||||
w.WriteMsg(firstReply)
|
w.WriteMsg(firstReply)
|
||||||
}
|
}
|
||||||
return firstRcode, firstErr
|
return firstRcode, firstErr
|
||||||
|
|||||||
@@ -106,6 +106,29 @@ func TestAutoPathNoAnswer(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAutoPathNilMsgFromNext(t *testing.T) {
|
||||||
|
ap := new(AutoPath)
|
||||||
|
ap.Zones = []string{"."}
|
||||||
|
// Simulate a plugin like acl's drop action that returns success
|
||||||
|
// without writing a response.
|
||||||
|
ap.Next = test.HandlerFunc(func(_ctx context.Context, _w dns.ResponseWriter, _r *dns.Msg) (int, error) {
|
||||||
|
return dns.RcodeSuccess, nil
|
||||||
|
})
|
||||||
|
ap.search = []string{"example.org.", "example.com.", "com.", ""}
|
||||||
|
|
||||||
|
m := new(dns.Msg)
|
||||||
|
m.SetQuestion("b.example.org.", dns.TypeA)
|
||||||
|
|
||||||
|
rec := dnstest.NewRecorder(&test.ResponseWriter{})
|
||||||
|
_, err := ap.ServeDNS(context.TODO(), rec, m)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Expected no error, got %v", err)
|
||||||
|
}
|
||||||
|
if rec.Msg != nil {
|
||||||
|
t.Fatalf("Expected no client write, but the recorder got a message")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// nextHandler returns a Handler that returns an answer for the question in the
|
// nextHandler returns a Handler that returns an answer for the question in the
|
||||||
// request per the domain->answer map. On success an RR will be returned: "qname 3600 IN A 127.0.0.53"
|
// request per the domain->answer map. On success an RR will be returned: "qname 3600 IN A 127.0.0.53"
|
||||||
func nextHandler(mm map[string]int) test.Handler {
|
func nextHandler(mm map[string]int) test.Handler {
|
||||||
|
|||||||
Reference in New Issue
Block a user