diff --git a/plugin/kubernetes/kubernetes.go b/plugin/kubernetes/kubernetes.go index df9d67060..4e214e6bc 100644 --- a/plugin/kubernetes/kubernetes.go +++ b/plugin/kubernetes/kubernetes.go @@ -112,10 +112,18 @@ func (k *Kubernetes) Services(ctx context.Context, state request.Request, exact return []msg.Service{svc}, nil } - if state.QType() == dns.TypeA && isDefaultNS(state.Name(), state.Zone) { + if isDefaultNS(state.Name(), state.Zone) { + ns := k.nsAddr() + + isIPv4 := ns.A.To4() != nil + + if !((state.QType() == dns.TypeA && isIPv4) || (state.QType() == dns.TypeAAAA && !isIPv4)) { + // NODATA + return nil, nil + } + // If this is an A request for "ns.dns", respond with a "fake" record for coredns. // SOA records always use this hardcoded name - ns := k.nsAddr() svc := msg.Service{Host: ns.A.String(), Key: msg.Path(state.QName(), coredns), TTL: k.ttl} return []msg.Service{svc}, nil } diff --git a/plugin/kubernetes/kubernetes_test.go b/plugin/kubernetes/kubernetes_test.go index 6d078f67e..c04574e8c 100644 --- a/plugin/kubernetes/kubernetes_test.go +++ b/plugin/kubernetes/kubernetes_test.go @@ -2,6 +2,7 @@ package kubernetes import ( "context" + "net" "testing" "github.com/coredns/coredns/plugin" @@ -254,7 +255,6 @@ func (APIConnServiceTest) GetNamespaceByName(name string) (*api.Namespace, error } func TestServices(t *testing.T) { - k := New([]string{"interwebs.test."}) k.APIConn = &APIConnServiceTest{} @@ -301,6 +301,61 @@ func TestServices(t *testing.T) { } } +func TestServicesAuthority(t *testing.T) { + k := New([]string{"interwebs.test."}) + k.APIConn = &APIConnServiceTest{} + + type svcAns struct { + host string + key string + } + type svcTest struct { + interfaceAddrs func() net.IP + qname string + qtype uint16 + answer *svcAns + } + tests := []svcTest{ + {interfaceAddrs: func() net.IP { return net.ParseIP("127.0.0.1") }, qname: "ns.dns.interwebs.test.", qtype: dns.TypeA, answer: &svcAns{host: "127.0.0.1", key: "/" + coredns + "/test/interwebs/dns/ns"}}, + {interfaceAddrs: func() net.IP { return net.ParseIP("127.0.0.1") }, qname: "ns.dns.interwebs.test.", qtype: dns.TypeAAAA}, + {interfaceAddrs: func() net.IP { return net.ParseIP("::1") }, qname: "ns.dns.interwebs.test.", qtype: dns.TypeA}, + {interfaceAddrs: func() net.IP { return net.ParseIP("::1") }, qname: "ns.dns.interwebs.test.", qtype: dns.TypeAAAA, answer: &svcAns{host: "::1", key: "/" + coredns + "/test/interwebs/dns/ns"}}, + } + + for i, test := range tests { + k.interfaceAddrsFunc = test.interfaceAddrs + + state := request.Request{ + Req: &dns.Msg{Question: []dns.Question{{Name: test.qname, Qtype: test.qtype}}}, + Zone: "interwebs.test.", // must match from k.Zones[0] + } + svcs, e := k.Services(context.TODO(), state, false, plugin.Options{}) + if e != nil { + t.Errorf("Test %d: got error '%v'", i, e) + continue + } + if test.answer != nil && len(svcs) != 1 { + t.Errorf("Test %d, expected 1 answer, got %v", i, len(svcs)) + continue + } + if test.answer == nil && len(svcs) != 0 { + t.Errorf("Test %d, expected no answer, got %v", i, len(svcs)) + continue + } + + if test.answer == nil && len(svcs) == 0 { + continue + } + + if test.answer.host != svcs[0].Host { + t.Errorf("Test %d, expected host '%v', got '%v'", i, test.answer.host, svcs[0].Host) + } + if test.answer.key != svcs[0].Key { + t.Errorf("Test %d, expected key '%v', got '%v'", i, test.answer.key, svcs[0].Key) + } + } +} + func TestServiceFQDN(t *testing.T) { fqdn := serviceFQDN( &object.Service{