Implement NS queries to Etcd middleware
Copy and port the NS record stuff from SkyDNS. Slightly cleaner implementation.
This commit is contained in:
parent
a441f93e0c
commit
e979acba1b
5 changed files with 73 additions and 8 deletions
|
@ -57,9 +57,11 @@ func (e Etcd) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (i
|
||||||
case "SOA":
|
case "SOA":
|
||||||
records = []dns.RR{e.SOA(zone, state)}
|
records = []dns.RR{e.SOA(zone, state)}
|
||||||
case "NS":
|
case "NS":
|
||||||
//TODO(miek): skydns had a thing that you specify this, should look for
|
if state.Name() == zone {
|
||||||
//records otherwise synthesise them.
|
records, extra, err = e.NS(zone, state)
|
||||||
//records = e.NS(zone, state)
|
break
|
||||||
|
}
|
||||||
|
fallthrough
|
||||||
default:
|
default:
|
||||||
// Do a fake A lookup, so we can distinguish betwen NODATA and NXDOMAIN
|
// Do a fake A lookup, so we can distinguish betwen NODATA and NXDOMAIN
|
||||||
_, err = e.A(zone, state, nil)
|
_, err = e.A(zone, state, nil)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package etcd
|
package etcd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"net"
|
"net"
|
||||||
"time"
|
"time"
|
||||||
|
@ -312,6 +313,35 @@ func (e Etcd) TXT(zone string, state middleware.State) (records []dns.RR, err er
|
||||||
return records, nil
|
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.
|
// SOA Record returns a SOA record.
|
||||||
func (e Etcd) SOA(zone string, state middleware.State) *dns.SOA {
|
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}
|
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?
|
// TODO(miek): DNSKEY and friends... intercepted by the DNSSEC middleware?
|
||||||
|
|
||||||
func isDuplicateCNAME(r *dns.CNAME, records []dns.RR) bool {
|
func isDuplicateCNAME(r *dns.CNAME, records []dns.RR) bool {
|
||||||
|
|
|
@ -30,6 +30,9 @@ var services = []*msg.Service{
|
||||||
// Cname loop
|
// Cname loop
|
||||||
{Host: "a.cname.skydns.test", Key: "b.cname.skydns.test."},
|
{Host: "a.cname.skydns.test", Key: "b.cname.skydns.test."},
|
||||||
{Host: "b.cname.skydns.test", Key: "a.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{
|
var dnsTestCases = []test.Case{
|
||||||
|
@ -170,10 +173,31 @@ var dnsTestCases = []test.Case{
|
||||||
Qname: "skydns.test.", Qtype: dns.TypeSOA,
|
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")},
|
Answer: []dns.RR{test.SOA("skydns.test. 300 IN SOA ns.dns.skydns.test. hostmaster.skydns.test. 1460498836 14400 3600 604800 60")},
|
||||||
},
|
},
|
||||||
// TODO(miek)
|
// NS Record Test
|
||||||
// {
|
{
|
||||||
// Qname: "skydns.test.", Qtype: dns.TypeNS,
|
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,
|
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")},
|
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")},
|
||||||
|
|
|
@ -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)}
|
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
|
// 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
|
// keys. If there are multiple shortest keys *and* the group attribute disagrees (and
|
||||||
// is not empty), we don't consider it a group.
|
// is not empty), we don't consider it a group.
|
||||||
|
|
|
@ -16,6 +16,7 @@ import (
|
||||||
"github.com/miekg/coredns/middleware/etcd/singleflight"
|
"github.com/miekg/coredns/middleware/etcd/singleflight"
|
||||||
"github.com/miekg/coredns/middleware/proxy"
|
"github.com/miekg/coredns/middleware/proxy"
|
||||||
"github.com/miekg/coredns/middleware/test"
|
"github.com/miekg/coredns/middleware/test"
|
||||||
|
"github.com/miekg/dns"
|
||||||
|
|
||||||
etcdc "github.com/coreos/etcd/client"
|
etcdc "github.com/coreos/etcd/client"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
|
@ -69,7 +70,7 @@ func TestLookup(t *testing.T) {
|
||||||
rec := middleware.NewResponseRecorder(&test.ResponseWriter{})
|
rec := middleware.NewResponseRecorder(&test.ResponseWriter{})
|
||||||
_, err := etc.ServeDNS(ctx, rec, m)
|
_, err := etc.ServeDNS(ctx, rec, m)
|
||||||
if err != nil {
|
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
|
return
|
||||||
}
|
}
|
||||||
resp := rec.Msg()
|
resp := rec.Msg()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue