Fix NODATA/NXDOMAIN for unknown types in etcd (#113)
* Finish the nodata stuff. See issue #9 * middleware/etc: add response to SOA queries * Remove and add a few TODOs
This commit is contained in:
parent
25cf16af0e
commit
a441f93e0c
5 changed files with 47 additions and 24 deletions
|
@ -2,7 +2,6 @@ package etcd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/miekg/coredns/middleware"
|
"github.com/miekg/coredns/middleware"
|
||||||
|
|
||||||
|
@ -22,8 +21,7 @@ func (e Etcd) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (i
|
||||||
name := state.Name()
|
name := state.Name()
|
||||||
if e.Stubmap != nil && len(*e.Stubmap) > 0 {
|
if e.Stubmap != nil && len(*e.Stubmap) > 0 {
|
||||||
for zone, _ := range *e.Stubmap {
|
for zone, _ := range *e.Stubmap {
|
||||||
// TODO(miek): use the Match function.
|
if middleware.Name(zone).Matches(name) {
|
||||||
if strings.HasSuffix(name, zone) {
|
|
||||||
stub := Stub{Etcd: e, Zone: zone}
|
stub := Stub{Etcd: e, Zone: zone}
|
||||||
return stub.ServeDNS(ctx, w, r)
|
return stub.ServeDNS(ctx, w, r)
|
||||||
}
|
}
|
||||||
|
@ -56,15 +54,15 @@ func (e Etcd) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (i
|
||||||
records, extra, err = e.MX(zone, state)
|
records, extra, err = e.MX(zone, state)
|
||||||
case "SRV":
|
case "SRV":
|
||||||
records, extra, err = e.SRV(zone, state)
|
records, extra, err = e.SRV(zone, state)
|
||||||
|
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)
|
||||||
default:
|
default:
|
||||||
// For SOA and NS we might still want this
|
// Do a fake A lookup, so we can distinguish betwen NODATA and NXDOMAIN
|
||||||
// and use dns.<zones> as the name to put these
|
_, err = e.A(zone, state, nil)
|
||||||
// also for stub
|
|
||||||
// rwrite and return
|
|
||||||
// Nodata response
|
|
||||||
// also catch other types, so that they return NODATA
|
|
||||||
// TODO(miek) nodata function see below
|
|
||||||
return 0, nil
|
|
||||||
}
|
}
|
||||||
if isEtcdNameError(err) {
|
if isEtcdNameError(err) {
|
||||||
return e.Err(zone, dns.RcodeNameError, state)
|
return e.Err(zone, dns.RcodeNameError, state)
|
||||||
|
|
|
@ -3,6 +3,7 @@ package etcd
|
||||||
import (
|
import (
|
||||||
"math"
|
"math"
|
||||||
"net"
|
"net"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/miekg/coredns/middleware"
|
"github.com/miekg/coredns/middleware"
|
||||||
"github.com/miekg/coredns/middleware/etcd/msg"
|
"github.com/miekg/coredns/middleware/etcd/msg"
|
||||||
|
@ -29,9 +30,8 @@ func (e Etcd) A(zone string, state middleware.State, previousRecords []dns.RR) (
|
||||||
ip := net.ParseIP(serv.Host)
|
ip := net.ParseIP(serv.Host)
|
||||||
switch {
|
switch {
|
||||||
case ip == nil:
|
case ip == nil:
|
||||||
// Try to resolve as CNAME if it's not an IP, but only if we don't create loops.
|
// TODO(miek): lowercasing? Should lowercase in everything see #85
|
||||||
// TODO(miek): lowercasing, use Match in middleware?
|
if middleware.Name(state.Name()).Matches(dns.Fqdn(serv.Host)) {
|
||||||
if state.Name() == dns.Fqdn(serv.Host) {
|
|
||||||
// x CNAME x is a direct loop, don't add those
|
// x CNAME x is a direct loop, don't add those
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -90,8 +90,7 @@ func (e Etcd) AAAA(zone string, state middleware.State, previousRecords []dns.RR
|
||||||
switch {
|
switch {
|
||||||
case ip == nil:
|
case ip == nil:
|
||||||
// Try to resolve as CNAME if it's not an IP, but only if we don't create loops.
|
// Try to resolve as CNAME if it's not an IP, but only if we don't create loops.
|
||||||
// TODO(miek): lowercasing, use Match in middleware/
|
if middleware.Name(state.Name()).Matches(dns.Fqdn(serv.Host)) {
|
||||||
if state.Name() == dns.Fqdn(serv.Host) {
|
|
||||||
// x CNAME x is a direct loop, don't add those
|
// x CNAME x is a direct loop, don't add those
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -111,7 +110,6 @@ func (e Etcd) AAAA(zone string, state middleware.State, previousRecords []dns.RR
|
||||||
if err == nil {
|
if err == nil {
|
||||||
// Not only have we found something we should add the CNAME and the IP addresses.
|
// Not only have we found something we should add the CNAME and the IP addresses.
|
||||||
if len(nextRecords) > 0 {
|
if len(nextRecords) > 0 {
|
||||||
// TODO(miek): sorting here?
|
|
||||||
records = append(records, newRecord)
|
records = append(records, newRecord)
|
||||||
records = append(records, nextRecords...)
|
records = append(records, nextRecords...)
|
||||||
}
|
}
|
||||||
|
@ -314,15 +312,21 @@ func (e Etcd) TXT(zone string, state middleware.State) (records []dns.RR, err er
|
||||||
return records, nil
|
return records, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// synthesis a SOA Record.
|
// SOA Record returns a SOA record.
|
||||||
// TODO(miek): finish
|
|
||||||
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}
|
||||||
return &dns.SOA{Hdr: header, Mbox: "hostmaster." + zone, Ns: "ns.dns." + zone}
|
return &dns.SOA{Hdr: header,
|
||||||
|
Mbox: "hostmaster." + zone,
|
||||||
|
Ns: "ns.dns." + zone,
|
||||||
|
Serial: uint32(time.Now().Unix()),
|
||||||
|
Refresh: 14400,
|
||||||
|
Retry: 3600,
|
||||||
|
Expire: 604800,
|
||||||
|
Minttl: 60,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(miek): NS records, DS and DNSKEY ones...? prolly so that the signing will
|
// TODO(miek): DNSKEY and friends... intercepted by the DNSSEC middleware?
|
||||||
// work...
|
|
||||||
|
|
||||||
func isDuplicateCNAME(r *dns.CNAME, records []dns.RR) bool {
|
func isDuplicateCNAME(r *dns.CNAME, records []dns.RR) bool {
|
||||||
for _, rec := range records {
|
for _, rec := range records {
|
||||||
|
|
|
@ -156,4 +156,26 @@ var dnsTestCases = []test.Case{
|
||||||
Qname: "a.server1.dev.region1.skydns.test.", Qtype: dns.TypeTXT,
|
Qname: "a.server1.dev.region1.skydns.test.", Qtype: dns.TypeTXT,
|
||||||
Ns: []dns.RR{test.SOA("skydns.test. 300 SOA ns.dns.skydns.test. hostmaster.skydns.test. 0 0 0 0 0")},
|
Ns: []dns.RR{test.SOA("skydns.test. 300 SOA ns.dns.skydns.test. hostmaster.skydns.test. 0 0 0 0 0")},
|
||||||
},
|
},
|
||||||
|
// NODATA Test
|
||||||
|
{
|
||||||
|
Qname: "a.server1.dev.region1.skydns.test.", Qtype: dns.TypeHINFO,
|
||||||
|
Ns: []dns.RR{test.SOA("skydns.test. 300 SOA ns.dns.skydns.test. hostmaster.skydns.test. 0 0 0 0 0")},
|
||||||
|
},
|
||||||
|
// NXDOMAIN Test
|
||||||
|
{
|
||||||
|
Qname: "a.server1.nonexistent.region1.skydns.test.", Qtype: dns.TypeHINFO, Rcode: dns.RcodeNameError,
|
||||||
|
Ns: []dns.RR{test.SOA("skydns.test. 300 SOA ns.dns.skydns.test. hostmaster.skydns.test. 0 0 0 0 0")},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
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,
|
||||||
|
// },
|
||||||
|
{
|
||||||
|
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")},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ func init() {
|
||||||
PathPrefix: "skydns",
|
PathPrefix: "skydns",
|
||||||
Ctx: context.Background(),
|
Ctx: context.Background(),
|
||||||
Inflight: &singleflight.Group{},
|
Inflight: &singleflight.Group{},
|
||||||
Zones: []string{"skydns.test."},
|
Zones: []string{"skydns.test.", "skydns_extra.test."},
|
||||||
Client: etcdc.NewKeysAPI(cli),
|
Client: etcdc.NewKeysAPI(cli),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,7 +58,6 @@ func NewReplacer(r *dns.Msg, rr *ResponseRecorder, emptyValue string) Replacer {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Header placeholders (case-insensitive)
|
// Header placeholders (case-insensitive)
|
||||||
// TODO(miek): syntax for flags and document it
|
|
||||||
rep.replacements[headerReplacer+"id}"] = strconv.Itoa(int(r.Id))
|
rep.replacements[headerReplacer+"id}"] = strconv.Itoa(int(r.Id))
|
||||||
rep.replacements[headerReplacer+"opcode}"] = strconv.Itoa(int(r.Opcode))
|
rep.replacements[headerReplacer+"opcode}"] = strconv.Itoa(int(r.Opcode))
|
||||||
rep.replacements[headerReplacer+"do}"] = boolToString(state.Do())
|
rep.replacements[headerReplacer+"do}"] = boolToString(state.Do())
|
||||||
|
|
Loading…
Add table
Reference in a new issue