diff options
author | 2016-04-13 08:03:56 +0100 | |
---|---|---|
committer | 2016-04-13 08:03:56 +0100 | |
commit | e979acba1bd0966813850492fde3adafa3278a98 (patch) | |
tree | 03edb19d78c3ce43f4478d01cef94b445a0781ae | |
parent | a441f93e0c941c2b99119e02272b414cfa3091a3 (diff) | |
download | coredns-e979acba1bd0966813850492fde3adafa3278a98.tar.gz coredns-e979acba1bd0966813850492fde3adafa3278a98.tar.zst coredns-e979acba1bd0966813850492fde3adafa3278a98.zip |
Implement NS queries to Etcd middleware
Copy and port the NS record stuff from SkyDNS. Slightly cleaner
implementation.
-rw-r--r-- | middleware/etcd/handler.go | 8 | ||||
-rw-r--r-- | middleware/etcd/lookup.go | 32 | ||||
-rw-r--r-- | middleware/etcd/lookup_test.go | 32 | ||||
-rw-r--r-- | middleware/etcd/msg/service.go | 6 | ||||
-rw-r--r-- | middleware/etcd/setup_test.go | 3 |
5 files changed, 73 insertions, 8 deletions
diff --git a/middleware/etcd/handler.go b/middleware/etcd/handler.go index bcc4d582b..8e15c1b1a 100644 --- a/middleware/etcd/handler.go +++ b/middleware/etcd/handler.go @@ -57,9 +57,11 @@ func (e Etcd) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (i case "SOA": records = []dns.RR{e.SOA(zone, state)} case "NS": - //TODO(miek): skydns had a thing that you specify this, should look for - //records otherwise synthesise them. - //records = e.NS(zone, state) + if state.Name() == zone { + records, extra, err = e.NS(zone, state) + break + } + fallthrough default: // Do a fake A lookup, so we can distinguish betwen NODATA and NXDOMAIN _, err = e.A(zone, state, nil) diff --git a/middleware/etcd/lookup.go b/middleware/etcd/lookup.go index 403cb4e3b..db8f02906 100644 --- a/middleware/etcd/lookup.go +++ b/middleware/etcd/lookup.go @@ -1,6 +1,7 @@ package etcd import ( + "fmt" "math" "net" "time" @@ -312,6 +313,35 @@ func (e Etcd) TXT(zone string, state middleware.State) (records []dns.RR, err er return records, nil } +func (e Etcd) NS(zone string, state middleware.State) (records, extra []dns.RR, err error) { + // NS record for this zone live in a special place, ns.dns.<zone>. Fake our lookup. + // only a tad bit fishy... + old := state.QName() + state.Req.Question[0].Name = "ns.dns." + zone + services, err := e.records(state, false) + if err != nil { + return nil, nil, err + } + state.Req.Question[0].Name = old + + for _, serv := range services { + ip := net.ParseIP(serv.Host) + switch { + case ip == nil: + return nil, nil, fmt.Errorf("NS record must be an IP address: %s", serv.Host) + case ip.To4() != nil: + serv.Host = e.Domain(serv.Key) + records = append(records, serv.NewNS(state.QName())) + extra = append(extra, serv.NewA(serv.Host, ip.To4())) + case ip.To4() == nil: + serv.Host = e.Domain(serv.Key) + records = append(records, serv.NewNS(state.QName())) + extra = append(extra, serv.NewAAAA(serv.Host, ip.To16())) + } + } + return records, extra, nil +} + // SOA Record returns a SOA record. func (e Etcd) SOA(zone string, state middleware.State) *dns.SOA { header := dns.RR_Header{Name: zone, Rrtype: dns.TypeSOA, Ttl: 300, Class: dns.ClassINET} @@ -326,6 +356,8 @@ func (e Etcd) SOA(zone string, state middleware.State) *dns.SOA { } } +// NS returns the NS records from etcd. + // TODO(miek): DNSKEY and friends... intercepted by the DNSSEC middleware? func isDuplicateCNAME(r *dns.CNAME, records []dns.RR) bool { diff --git a/middleware/etcd/lookup_test.go b/middleware/etcd/lookup_test.go index c1c990254..578c59aad 100644 --- a/middleware/etcd/lookup_test.go +++ b/middleware/etcd/lookup_test.go @@ -30,6 +30,9 @@ var services = []*msg.Service{ // Cname loop {Host: "a.cname.skydns.test", Key: "b.cname.skydns.test."}, {Host: "b.cname.skydns.test", Key: "a.cname.skydns.test."}, + // Nameservers. + {Host: "10.0.0.2", Key: "a.ns.dns.skydns.test."}, + {Host: "10.0.0.3", Key: "b.ns.dns.skydns.test."}, } var dnsTestCases = []test.Case{ @@ -170,10 +173,31 @@ var dnsTestCases = []test.Case{ Qname: "skydns.test.", Qtype: dns.TypeSOA, Answer: []dns.RR{test.SOA("skydns.test. 300 IN SOA ns.dns.skydns.test. hostmaster.skydns.test. 1460498836 14400 3600 604800 60")}, }, - // TODO(miek) - // { - // Qname: "skydns.test.", Qtype: dns.TypeNS, - // }, + // NS Record Test + { + Qname: "skydns.test.", Qtype: dns.TypeNS, + Answer: []dns.RR{ + test.NS("skydns.test. 300 NS a.ns.dns.skydns.test."), + test.NS("skydns.test. 300 NS b.ns.dns.skydns.test."), + }, + Extra: []dns.RR{ + test.A("a.ns.dns.skydns.test. 300 A 10.0.0.2"), + test.A("b.ns.dns.skydns.test. 300 A 10.0.0.3"), + }, + }, + // NS Record Test + { + Qname: "a.skydns.test.", Qtype: dns.TypeNS, Rcode: dns.RcodeNameError, + Ns: []dns.RR{test.SOA("skydns.test. 300 IN SOA ns.dns.skydns.test. hostmaster.skydns.test. 1460498836 14400 3600 604800 60")}, + }, + // A Record For NS Record Test + { + Qname: "ns.dns.skydns.test.", Qtype: dns.TypeA, + Answer: []dns.RR{ + test.A("ns.dns.skydns.test. 300 A 10.0.0.2"), + test.A("ns.dns.skydns.test. 300 A 10.0.0.3"), + }, + }, { Qname: "skydns_extra.test.", Qtype: dns.TypeSOA, Answer: []dns.RR{test.SOA("skydns_extra.test. 300 IN SOA ns.dns.skydns_extra.test. hostmaster.skydns_extra.test. 1460498836 14400 3600 604800 60")}, diff --git a/middleware/etcd/msg/service.go b/middleware/etcd/msg/service.go index 0164633e3..588e7b33c 100644 --- a/middleware/etcd/msg/service.go +++ b/middleware/etcd/msg/service.go @@ -71,6 +71,12 @@ func (s *Service) NewTXT(name string) *dns.TXT { return &dns.TXT{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: s.Ttl}, Txt: split255(s.Text)} } +// NewNS returns a new NS record based on the Service. +func (s *Service) NewNS(name string) *dns.NS { + host := targetStrip(dns.Fqdn(s.Host), s.TargetStrip) + return &dns.NS{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeNS, Class: dns.ClassINET, Ttl: s.Ttl}, Ns: host} +} + // Group checks the services in sx, it looks for a Group attribute on the shortest // keys. If there are multiple shortest keys *and* the group attribute disagrees (and // is not empty), we don't consider it a group. diff --git a/middleware/etcd/setup_test.go b/middleware/etcd/setup_test.go index 0836f053e..d61680541 100644 --- a/middleware/etcd/setup_test.go +++ b/middleware/etcd/setup_test.go @@ -16,6 +16,7 @@ import ( "github.com/miekg/coredns/middleware/etcd/singleflight" "github.com/miekg/coredns/middleware/proxy" "github.com/miekg/coredns/middleware/test" + "github.com/miekg/dns" etcdc "github.com/coreos/etcd/client" "golang.org/x/net/context" @@ -69,7 +70,7 @@ func TestLookup(t *testing.T) { rec := middleware.NewResponseRecorder(&test.ResponseWriter{}) _, err := etc.ServeDNS(ctx, rec, m) if err != nil { - t.Errorf("expected no error, got %v\n", err) + t.Errorf("expected no error, got: %v for %s %s\n", err, m.Question[0].Name, dns.Type(m.Question[0].Qtype)) return } resp := rec.Msg() |