Commit 713f10f6 authored by Miek Gieben's avatar Miek Gieben

middleware/etcd: reverse addresses (#162)

* middleware/etcd: reverse addresses

Implement reverse (PTR) addresses. Update the documentation on how to
configure test. Added tests as well.

Fixes: #157 #159

* Cleanup readme a little
parent 3165084a
...@@ -72,3 +72,48 @@ This is the default SkyDNS setup, with everying specified in full: ...@@ -72,3 +72,48 @@ This is the default SkyDNS setup, with everying specified in full:
proxy . 8.8.8.8:53 8.8.4.4:53 proxy . 8.8.8.8:53 8.8.4.4:53
} }
~~~ ~~~
### Reverse zones
Reverse zones are supported. You need to make CoreDNS aware of the fact that you are also
authoritative for the reverse. For instance if you want to add the reverse for 10.0.0.0/24, you'll
need to add the zone `10.in-addr.arpa` to the list of zones (the fun starts with reverse IPv6 zones
in the ip6.arpa domain). Showing a snippet of a Corefile:
~~~
etcd skydns.local 10.in-addr.arpa {
stubzones
...
~~~
Next you'll need to populate the zone with reverse records, here we add a reverse for
10.0.0.127 pointing to reverse.skydns.local.
~~~
% curl -XPUT http://127.0.0.1:4001/v2/keys/skydns/arpa/in-addr/10/0/0/127 \
-d value='{"host":"reverse.skydns.local."}'
~~~
Querying with dig:
~~~
% dig @localhost -x 10.0.0.127 +short
reverse.atoom.net.
~~~
Or with *debug* queries enabled:
~~~
% dig @localhost -p 1053 o-o.debug.127.0.0.10.in-addr.arpa. PTR
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;o-o.debug.127.0.0.10.in-addr.arpa. IN PTR
;; ANSWER SECTION:
127.0.0.10.in-addr.arpa. 300 IN PTR reverse.atoom.net.
;; ADDITIONAL SECTION:
127.0.0.10.in-addr.arpa. 300 CH TXT "reverse.atoom.net.:0(10,0,,false)[0,]"
~~~
...@@ -58,6 +58,8 @@ func (e Etcd) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (i ...@@ -58,6 +58,8 @@ func (e Etcd) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (i
records, debug, err = e.TXT(zone, state) records, debug, err = e.TXT(zone, state)
case "CNAME": case "CNAME":
records, debug, err = e.CNAME(zone, state) records, debug, err = e.CNAME(zone, state)
case "PTR":
records, debug, err = e.PTR(zone, state)
case "MX": case "MX":
records, extra, debug, err = e.MX(zone, state) records, extra, debug, err = e.MX(zone, state)
case "SRV": case "SRV":
......
...@@ -305,6 +305,21 @@ func (e Etcd) CNAME(zone string, state middleware.State) (records []dns.RR, debu ...@@ -305,6 +305,21 @@ func (e Etcd) CNAME(zone string, state middleware.State) (records []dns.RR, debu
return records, debug, nil return records, debug, nil
} }
// PTR returns the PTR records, only services that have a domain name as host are included.
func (e Etcd) PTR(zone string, state middleware.State) (records []dns.RR, debug []msg.Service, err error) {
services, debug, err := e.records(state, true)
if err != nil {
return nil, debug, err
}
for _, serv := range services {
if ip := net.ParseIP(serv.Host); ip == nil {
records = append(records, serv.NewPTR(state.QName(), serv.Host))
}
}
return records, debug, nil
}
func (e Etcd) TXT(zone string, state middleware.State) (records []dns.RR, debug []msg.Service, err error) { func (e Etcd) TXT(zone string, state middleware.State) (records []dns.RR, debug []msg.Service, err error) {
services, debug, err := e.records(state, false) services, debug, err := e.records(state, false)
if err != nil { if err != nil {
......
...@@ -15,20 +15,22 @@ var services = []*msg.Service{ ...@@ -15,20 +15,22 @@ var services = []*msg.Service{
{Host: "10.0.0.1", Port: 8080, Key: "a.server1.prod.region1.skydns.test."}, {Host: "10.0.0.1", Port: 8080, Key: "a.server1.prod.region1.skydns.test."},
{Host: "10.0.0.2", Port: 8080, Key: "b.server1.prod.region1.skydns.test."}, {Host: "10.0.0.2", Port: 8080, Key: "b.server1.prod.region1.skydns.test."},
{Host: "::1", Port: 8080, Key: "b.server6.prod.region1.skydns.test."}, {Host: "::1", Port: 8080, Key: "b.server6.prod.region1.skydns.test."},
// Unresolvable internal name // Unresolvable internal name.
{Host: "unresolvable.skydns.test", Key: "cname.prod.region1.skydns.test."}, {Host: "unresolvable.skydns.test", Key: "cname.prod.region1.skydns.test."},
// priority // Priority.
{Host: "priority.server1", Priority: 333, Port: 8080, Key: "priority.skydns.test."}, {Host: "priority.server1", Priority: 333, Port: 8080, Key: "priority.skydns.test."},
// Subdomain // Subdomain.
{Host: "sub.server1", Port: 0, Key: "a.sub.region1.skydns.test."}, {Host: "sub.server1", Port: 0, Key: "a.sub.region1.skydns.test."},
{Host: "sub.server2", Port: 80, Key: "b.sub.region1.skydns.test."}, {Host: "sub.server2", Port: 80, Key: "b.sub.region1.skydns.test."},
{Host: "10.0.0.1", Port: 8080, Key: "c.sub.region1.skydns.test."}, {Host: "10.0.0.1", Port: 8080, Key: "c.sub.region1.skydns.test."},
// 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. // Nameservers.
{Host: "10.0.0.2", Key: "a.ns.dns.skydns.test."}, {Host: "10.0.0.2", Key: "a.ns.dns.skydns.test."},
{Host: "10.0.0.3", Key: "b.ns.dns.skydns.test."}, {Host: "10.0.0.3", Key: "b.ns.dns.skydns.test."},
// Reverse.
{Host: "reverse.example.com", Key: "1.0.0.10.in-addr.arpa."}, // 10.0.0.1
} }
var dnsTestCases = []test.Case{ var dnsTestCases = []test.Case{
...@@ -198,4 +200,9 @@ var dnsTestCases = []test.Case{ ...@@ -198,4 +200,9 @@ var dnsTestCases = []test.Case{
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")},
}, },
// Reverse lookup
{
Qname: "1.0.0.10.in-addr.arpa.", Qtype: dns.TypePTR,
Answer: []dns.RR{test.PTR("1.0.0.10.in-addr.arpa. 300 PTR reverse.example.com.")},
},
} }
...@@ -102,6 +102,11 @@ func (s *Service) NewTXT(name string) *dns.TXT { ...@@ -102,6 +102,11 @@ 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)}
} }
// NewPTR returns a new PTR record based on the Service.
func (s *Service) NewPTR(name string, target string) *dns.PTR {
return &dns.PTR{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypePTR, Class: dns.ClassINET, Ttl: s.Ttl}, Ptr: dns.Fqdn(target)}
}
// NewNS returns a new NS record based on the Service. // NewNS returns a new NS record based on the Service.
func (s *Service) NewNS(name string) *dns.NS { func (s *Service) NewNS(name string) *dns.NS {
host := targetStrip(dns.Fqdn(s.Host), s.TargetStrip) host := targetStrip(dns.Fqdn(s.Host), s.TargetStrip)
......
...@@ -37,7 +37,7 @@ func init() { ...@@ -37,7 +37,7 @@ func init() {
PathPrefix: "skydns", PathPrefix: "skydns",
Ctx: context.Background(), Ctx: context.Background(),
Inflight: &singleflight.Group{}, Inflight: &singleflight.Group{},
Zones: []string{"skydns.test.", "skydns_extra.test."}, Zones: []string{"skydns.test.", "skydns_extra.test.", "in-addr.arpa."},
Client: etcdc.NewKeysAPI(cli), Client: etcdc.NewKeysAPI(cli),
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment