diff --git a/plugin/kubernetes/handler.go b/plugin/kubernetes/handler.go index 4d70279b7..e829a5f78 100644 --- a/plugin/kubernetes/handler.go +++ b/plugin/kubernetes/handler.go @@ -18,11 +18,12 @@ func (k Kubernetes) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.M m.SetReply(r) m.Authoritative = true - zone := plugin.Zones(k.Zones).Matches(state.Name()) + qname := state.QName() + zone := plugin.Zones(k.Zones).Matches(qname) if zone == "" { return plugin.NextOrFailure(k.Name(), k.Next, ctx, w, r) } - + zone = qname[len(qname)-len(zone):] // maintain case of original query state.Zone = zone var ( diff --git a/plugin/kubernetes/handler_case_test.go b/plugin/kubernetes/handler_case_test.go new file mode 100644 index 000000000..e59f21166 --- /dev/null +++ b/plugin/kubernetes/handler_case_test.go @@ -0,0 +1,71 @@ +package kubernetes + +import ( + "context" + "testing" + + "github.com/coredns/coredns/plugin/pkg/dnstest" + "github.com/coredns/coredns/plugin/test" + + "github.com/miekg/dns" +) + +var dnsPreserveCaseCases = []test.Case{ + // Negative response + { + Qname: "not-a-service.testns.svc.ClUsTeR.lOcAl.", Qtype: dns.TypeA, + Rcode: dns.RcodeNameError, + Ns: []dns.RR{ + test.SOA("ClUsTeR.lOcAl. 30 IN SOA ns.dns.ClUsTeR.lOcAl. hostmaster.ClUsTeR.lOcAl. 1499347823 7200 1800 86400 60"), + }, + }, + // A Service + { + Qname: "SvC1.TeStNs.SvC.cLuStEr.LoCaL.", Qtype: dns.TypeA, + Rcode: dns.RcodeSuccess, + Answer: []dns.RR{ + test.A("SvC1.TeStNs.SvC.cLuStEr.LoCaL. 5 IN A 10.0.0.1"), + }, + }, + // SRV Service + { + Qname: "_HtTp._TcP.sVc1.TeStNs.SvC.cLuStEr.LoCaL.", Qtype: dns.TypeSRV, + Rcode: dns.RcodeSuccess, + Answer: []dns.RR{ + test.SRV("_HtTp._TcP.sVc1.TeStNs.SvC.cLuStEr.LoCaL. 5 IN SRV 0 100 80 svc1.testns.svc.cLuStEr.LoCaL."), + }, + Extra: []dns.RR{ + test.A("svc1.testns.svc.cLuStEr.LoCaL. 5 IN A 10.0.0.1"), + }, + }, +} + +func TestPreserveCase(t *testing.T) { + k := New([]string{"cluster.local."}) + k.APIConn = &APIConnServeTest{} + k.opts.ignoreEmptyService = true + k.Next = test.NextHandler(dns.RcodeSuccess, nil) + ctx := context.TODO() + + for i, tc := range dnsPreserveCaseCases { + r := tc.Msg() + + w := dnstest.NewRecorder(&test.ResponseWriter{}) + + _, err := k.ServeDNS(ctx, w, r) + if err != tc.Error { + t.Errorf("Test %d expected no error, got %v", i, err) + return + } + if tc.Error != nil { + continue + } + + resp := w.Msg + if resp == nil { + t.Fatalf("Test %d, got nil message and no error for %q", i, r.Question[0].Name) + } + + test.SortAndCheck(t, resp, tc) + } +} diff --git a/plugin/normalize.go b/plugin/normalize.go index dc295ce01..6402bf8d9 100644 --- a/plugin/normalize.go +++ b/plugin/normalize.go @@ -15,8 +15,8 @@ import ( // Zones respresents a lists of zone names. type Zones []string -// Matches checks is qname is a subdomain of any of the zones in z. The match -// will return the most specific zones that matches other. The empty string +// Matches checks if qname is a subdomain of any of the zones in z. The match +// will return the most specific zones that matches. The empty string // signals a not found condition. func (z Zones) Matches(qname string) string { zone := ""