mirror of
https://github.com/coredns/coredns.git
synced 2026-10-08 19:45:21 -04:00
plugin/k8s_external: Fixes a nil pointer dereference panic when upstream lookup returns no response (#8518)
* plugin/k8s_external: Fixes a nil pointer dereference panic when upstream lookup returns no response When a CNAME-hosted service is resolved, k8s_external performs internal upstream lookups for the target name. Upstream.Lookup can return a nil message with a nil error when the internal self-query's plugin chain returns a ClientWrite rcode without writing a response (for example acl's drop action), and the a/aaaa/srv handlers then dereference resp.Answer on a nil resp and panic. Guard all four lookups with err == nil && resp != nil, matching the nil checks already used in plugin/backend_lookup.go and the guard recently added to plugin/dns64 (#8511). Signed-off-by: zjncs <18910855655@163.com> * plugin/k8s_external: silence unused-parameter lint in nil upstream test The CI lint flagged the test handler's unused 'w' parameter. Rename it to '_' so golangci-lint (revive unused-parameter) passes. No behavior change. Signed-off-by: zjncs <18910855655@163.com> --------- Signed-off-by: zjncs <18910855655@163.com>
This commit is contained in:
@@ -4,9 +4,12 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/coredns/coredns/core/dnsserver"
|
||||||
|
"github.com/coredns/coredns/plugin"
|
||||||
"github.com/coredns/coredns/plugin/kubernetes"
|
"github.com/coredns/coredns/plugin/kubernetes"
|
||||||
"github.com/coredns/coredns/plugin/kubernetes/object"
|
"github.com/coredns/coredns/plugin/kubernetes/object"
|
||||||
"github.com/coredns/coredns/plugin/pkg/dnstest"
|
"github.com/coredns/coredns/plugin/pkg/dnstest"
|
||||||
|
"github.com/coredns/coredns/plugin/pkg/upstream"
|
||||||
"github.com/coredns/coredns/plugin/test"
|
"github.com/coredns/coredns/plugin/test"
|
||||||
"github.com/coredns/coredns/request"
|
"github.com/coredns/coredns/request"
|
||||||
|
|
||||||
@@ -55,6 +58,49 @@ func TestExternal(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestExternalCNAMENilUpstreamResponse checks that a CNAME-hosted service does not
|
||||||
|
// panic when the internal upstream lookup returns no response, e.g. when a plugin
|
||||||
|
// like acl's drop action returns success without writing.
|
||||||
|
func TestExternalCNAMENilUpstreamResponse(t *testing.T) {
|
||||||
|
k := kubernetes.New([]string{"cluster.local."})
|
||||||
|
k.Namespaces = map[string]struct{}{"testns": {}}
|
||||||
|
k.APIConn = &external{}
|
||||||
|
|
||||||
|
cfg := &dnsserver.Config{
|
||||||
|
Zone: ".",
|
||||||
|
Plugin: []plugin.Plugin{
|
||||||
|
func(plugin.Handler) plugin.Handler {
|
||||||
|
return plugin.HandlerFunc(func(_ context.Context, _ dns.ResponseWriter, _ *dns.Msg) (int, error) {
|
||||||
|
return dns.RcodeSuccess, nil
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
srv, err := dnsserver.NewServer("", []*dnsserver.Config{cfg})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
ctx := context.WithValue(context.Background(), dnsserver.Key{}, srv)
|
||||||
|
|
||||||
|
e := New()
|
||||||
|
e.Zones = []string{"example.com."}
|
||||||
|
e.headless = true
|
||||||
|
e.Next = test.NextHandler(dns.RcodeSuccess, nil)
|
||||||
|
e.externalFunc = k.External
|
||||||
|
e.externalAddrFunc = externalAddress
|
||||||
|
e.externalSerialFunc = externalSerial
|
||||||
|
e.upstream = upstream.New()
|
||||||
|
|
||||||
|
m := new(dns.Msg)
|
||||||
|
m.SetQuestion("svc12.testns.example.com.", dns.TypeA)
|
||||||
|
w := dnstest.NewRecorder(&test.ResponseWriter{})
|
||||||
|
|
||||||
|
_, err = e.ServeDNS(ctx, w, m)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Expected no error, got %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var tests = []test.Case{
|
var tests = []test.Case{
|
||||||
// PTR reverse lookup
|
// PTR reverse lookup
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ func (e *External) a(ctx context.Context, services []msg.Service, state request.
|
|||||||
case dns.TypeCNAME:
|
case dns.TypeCNAME:
|
||||||
rr := s.NewCNAME(state.QName(), s.Host)
|
rr := s.NewCNAME(state.QName(), s.Host)
|
||||||
records = append(records, rr)
|
records = append(records, rr)
|
||||||
if resp, err := e.upstream.Lookup(ctx, state, dns.Fqdn(s.Host), dns.TypeA); err == nil {
|
if resp, err := e.upstream.Lookup(ctx, state, dns.Fqdn(s.Host), dns.TypeA); err == nil && resp != nil {
|
||||||
records = append(records, resp.Answer...)
|
records = append(records, resp.Answer...)
|
||||||
if resp.Truncated {
|
if resp.Truncated {
|
||||||
truncated = true
|
truncated = true
|
||||||
@@ -53,7 +53,7 @@ func (e *External) aaaa(ctx context.Context, services []msg.Service, state reque
|
|||||||
case dns.TypeCNAME:
|
case dns.TypeCNAME:
|
||||||
rr := s.NewCNAME(state.QName(), s.Host)
|
rr := s.NewCNAME(state.QName(), s.Host)
|
||||||
records = append(records, rr)
|
records = append(records, rr)
|
||||||
if resp, err := e.upstream.Lookup(ctx, state, dns.Fqdn(s.Host), dns.TypeAAAA); err == nil {
|
if resp, err := e.upstream.Lookup(ctx, state, dns.Fqdn(s.Host), dns.TypeAAAA); err == nil && resp != nil {
|
||||||
records = append(records, resp.Answer...)
|
records = append(records, resp.Answer...)
|
||||||
if resp.Truncated {
|
if resp.Truncated {
|
||||||
truncated = true
|
truncated = true
|
||||||
@@ -132,10 +132,10 @@ func (e *External) srv(ctx context.Context, services []msg.Service, state reques
|
|||||||
records = append(records, srv)
|
records = append(records, srv)
|
||||||
}
|
}
|
||||||
if ok := isDuplicate(dup, srv.Target, addr, 0); !ok {
|
if ok := isDuplicate(dup, srv.Target, addr, 0); !ok {
|
||||||
if resp, err := e.upstream.Lookup(ctx, state, addr, dns.TypeA); err == nil {
|
if resp, err := e.upstream.Lookup(ctx, state, addr, dns.TypeA); err == nil && resp != nil {
|
||||||
extra = append(extra, resp.Answer...)
|
extra = append(extra, resp.Answer...)
|
||||||
}
|
}
|
||||||
if resp, err := e.upstream.Lookup(ctx, state, addr, dns.TypeAAAA); err == nil {
|
if resp, err := e.upstream.Lookup(ctx, state, addr, dns.TypeAAAA); err == nil && resp != nil {
|
||||||
extra = append(extra, resp.Answer...)
|
extra = append(extra, resp.Answer...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user