Fixes: debug RR and header bits (#151)

Always set the auth and rd bits in the reply. And reverse the
ownername of debug queries so that manual matching is much easier.
This commit is contained in:
Miek Gieben 2016-05-23 09:16:57 +01:00
parent c30671f4c0
commit 446eaa957d
9 changed files with 31 additions and 31 deletions

View file

@ -113,8 +113,8 @@ var dnsTestCasesDebug = []test.Case{
test.A("dom.skydns.test. 300 IN A 127.0.0.2"), test.A("dom.skydns.test. 300 IN A 127.0.0.2"),
}, },
Extra: []dns.RR{ Extra: []dns.RR{
test.TXT(`skydns.test.skydns.dom.a. 300 CH TXT "127.0.0.1:0(10,0,,false)[0,]"`), test.TXT(`a.dom.skydns.test. 300 CH TXT "127.0.0.1:0(10,0,,false)[0,]"`),
test.TXT(`skydns.test.skydns.dom.sub.b. 300 CH TXT "127.0.0.2:0(10,0,,false)[0,]"`), test.TXT(`b.sub.dom.skydns.test. 300 CH TXT "127.0.0.2:0(10,0,,false)[0,]"`),
}, },
}, },
{ {
@ -123,8 +123,8 @@ var dnsTestCasesDebug = []test.Case{
test.SOA("skydns.test. 300 IN SOA ns.dns.skydns.test. hostmaster.skydns.test. 1463943291 7200 1800 86400 60"), test.SOA("skydns.test. 300 IN SOA ns.dns.skydns.test. hostmaster.skydns.test. 1463943291 7200 1800 86400 60"),
}, },
Extra: []dns.RR{ Extra: []dns.RR{
test.TXT(`skydns.test.skydns.dom.a. 300 CH TXT "127.0.0.1:0(10,0,,false)[0,]"`), test.TXT(`a.dom.skydns.test. 300 CH TXT "127.0.0.1:0(10,0,,false)[0,]"`),
test.TXT(`skydns.test.skydns.dom.sub.b. 300 CH TXT "127.0.0.2:0(10,0,,false)[0,]"`), test.TXT(`b.sub.dom.skydns.test. 300 CH TXT "127.0.0.2:0(10,0,,false)[0,]"`),
}, },
}, },
} }

View file

@ -32,12 +32,12 @@ type Etcd struct {
// this name. This is used when find matches when completing SRV lookups // this name. This is used when find matches when completing SRV lookups
// for instance. // for instance.
func (g Etcd) Records(name string, exact bool) ([]msg.Service, error) { func (g Etcd) Records(name string, exact bool) ([]msg.Service, error) {
path, star := g.PathWithWildcard(name) path, star := msg.PathWithWildcard(name, g.PathPrefix)
r, err := g.Get(path, true) r, err := g.Get(path, true)
if err != nil { if err != nil {
return nil, err return nil, err
} }
segments := strings.Split(g.Path(name), "/") segments := strings.Split(msg.Path(name, g.PathPrefix), "/")
switch { switch {
case exact && r.Node.Dir: case exact && r.Node.Dir:
return nil, nil return nil, nil

View file

@ -76,7 +76,7 @@ func (e Etcd) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (i
} }
if e.debug != "" { if e.debug != "" {
// substitute this name with the original when we return the request. // Substitute this name with the original when we return the request.
state.Clear() state.Clear()
state.Req.Question[0].Name = e.debug state.Req.Question[0].Name = e.debug
} }
@ -112,6 +112,7 @@ func (e Etcd) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (i
func (e Etcd) Err(zone string, rcode int, state middleware.State, debug []msg.Service) (int, error) { func (e Etcd) Err(zone string, rcode int, state middleware.State, debug []msg.Service) (int, error) {
m := new(dns.Msg) m := new(dns.Msg)
m.SetRcode(state.Req, rcode) m.SetRcode(state.Req, rcode)
m.Authoritative, m.RecursionAvailable, m.Compress = true, true, true
m.Ns, _, _ = e.SOA(zone, state) m.Ns, _, _ = e.SOA(zone, state)
m.Extra = servicesToTxt(debug) m.Extra = servicesToTxt(debug)
state.SizeAndDo(m) state.SizeAndDo(m)

View file

@ -213,13 +213,13 @@ func (e Etcd) SRV(zone string, state middleware.State) (records, extra []dns.RR,
} }
// e.AAA(zone, state1, nil) as well...? // e.AAA(zone, state1, nil) as well...?
case ip.To4() != nil: case ip.To4() != nil:
serv.Host = e.Domain(serv.Key) serv.Host = msg.Domain(serv.Key)
srv := serv.NewSRV(state.QName(), weight) srv := serv.NewSRV(state.QName(), weight)
records = append(records, srv) records = append(records, srv)
extra = append(extra, serv.NewA(srv.Target, ip.To4())) extra = append(extra, serv.NewA(srv.Target, ip.To4()))
case ip.To4() == nil: case ip.To4() == nil:
serv.Host = e.Domain(serv.Key) serv.Host = msg.Domain(serv.Key)
srv := serv.NewSRV(state.QName(), weight) srv := serv.NewSRV(state.QName(), weight)
records = append(records, srv) records = append(records, srv)
@ -278,11 +278,11 @@ func (e Etcd) MX(zone string, state middleware.State) (records, extra []dns.RR,
} }
// e.AAAA as well // e.AAAA as well
case ip.To4() != nil: case ip.To4() != nil:
serv.Host = e.Domain(serv.Key) serv.Host = msg.Domain(serv.Key)
records = append(records, serv.NewMX(state.QName())) records = append(records, serv.NewMX(state.QName()))
extra = append(extra, serv.NewA(serv.Host, ip.To4())) extra = append(extra, serv.NewA(serv.Host, ip.To4()))
case ip.To4() == nil: case ip.To4() == nil:
serv.Host = e.Domain(serv.Key) serv.Host = msg.Domain(serv.Key)
records = append(records, serv.NewMX(state.QName())) records = append(records, serv.NewMX(state.QName()))
extra = append(extra, serv.NewAAAA(serv.Host, ip.To16())) extra = append(extra, serv.NewAAAA(serv.Host, ip.To16()))
} }
@ -340,11 +340,11 @@ func (e Etcd) NS(zone string, state middleware.State) (records, extra []dns.RR,
case ip == nil: case ip == nil:
return nil, nil, debug, fmt.Errorf("NS record must be an IP address: %s", serv.Host) return nil, nil, debug, fmt.Errorf("NS record must be an IP address: %s", serv.Host)
case ip.To4() != nil: case ip.To4() != nil:
serv.Host = e.Domain(serv.Key) serv.Host = msg.Domain(serv.Key)
records = append(records, serv.NewNS(state.QName())) records = append(records, serv.NewNS(state.QName()))
extra = append(extra, serv.NewA(serv.Host, ip.To4())) extra = append(extra, serv.NewA(serv.Host, ip.To4()))
case ip.To4() == nil: case ip.To4() == nil:
serv.Host = e.Domain(serv.Key) serv.Host = msg.Domain(serv.Key)
records = append(records, serv.NewNS(state.QName())) records = append(records, serv.NewNS(state.QName()))
extra = append(extra, serv.NewAAAA(serv.Host, ip.To16())) extra = append(extra, serv.NewAAAA(serv.Host, ip.To16()))
} }

View file

@ -1,4 +1,4 @@
package etcd package msg
import ( import (
"path" "path"
@ -9,16 +9,16 @@ import (
// Path converts a domainname to an etcd path. If s looks like service.staging.skydns.local., // Path converts a domainname to an etcd path. If s looks like service.staging.skydns.local.,
// the resulting key will be /skydns/local/skydns/staging/service . // the resulting key will be /skydns/local/skydns/staging/service .
func (e Etcd) Path(s string) string { func Path(s, prefix string) string {
l := dns.SplitDomainName(s) l := dns.SplitDomainName(s)
for i, j := 0, len(l)-1; i < j; i, j = i+1, j-1 { for i, j := 0, len(l)-1; i < j; i, j = i+1, j-1 {
l[i], l[j] = l[j], l[i] l[i], l[j] = l[j], l[i]
} }
return path.Join(append([]string{"/" + e.PathPrefix + "/"}, l...)...) return path.Join(append([]string{"/" + prefix + "/"}, l...)...)
} }
// Domain is the opposite of Path. // Domain is the opposite of Path.
func (e Etcd) Domain(s string) string { func Domain(s string) string {
l := strings.Split(s, "/") l := strings.Split(s, "/")
// start with 1, to strip /skydns // start with 1, to strip /skydns
for i, j := 1, len(l)-1; i < j; i, j = i+1, j-1 { for i, j := 1, len(l)-1; i < j; i, j = i+1, j-1 {
@ -32,15 +32,15 @@ func (e Etcd) Domain(s string) string {
// later find the matching names. So service.*.skydns.local, will look for all // later find the matching names. So service.*.skydns.local, will look for all
// services under skydns.local and will later check for names that match // services under skydns.local and will later check for names that match
// service.*.skydns.local. If a wildcard is found the returned bool is true. // service.*.skydns.local. If a wildcard is found the returned bool is true.
func (e Etcd) PathWithWildcard(s string) (string, bool) { func PathWithWildcard(s, prefix string) (string, bool) {
l := dns.SplitDomainName(s) l := dns.SplitDomainName(s)
for i, j := 0, len(l)-1; i < j; i, j = i+1, j-1 { for i, j := 0, len(l)-1; i < j; i, j = i+1, j-1 {
l[i], l[j] = l[j], l[i] l[i], l[j] = l[j], l[i]
} }
for i, k := range l { for i, k := range l {
if k == "*" || k == "any" { if k == "*" || k == "any" {
return path.Join(append([]string{"/" + e.PathPrefix + "/"}, l[:i]...)...), true return path.Join(append([]string{"/" + prefix + "/"}, l[:i]...)...), true
} }
} }
return path.Join(append([]string{"/" + e.PathPrefix + "/"}, l...)...), false return path.Join(append([]string{"/" + prefix + "/"}, l...)...), false
} }

View file

@ -1,11 +1,10 @@
package etcd package msg
import "testing" import "testing"
func TestPath(t *testing.T) { func TestPath(t *testing.T) {
for _, path := range []string{"mydns", "skydns"} { for _, path := range []string{"mydns", "skydns"} {
e := Etcd{PathPrefix: path} result := Path("service.staging.skydns.local.", path)
result := e.Path("service.staging.skydns.local.")
if result != "/"+path+"/local/skydns/staging/service" { if result != "/"+path+"/local/skydns/staging/service" {
t.Errorf("Failure to get domain's path with prefix: %s", result) t.Errorf("Failure to get domain's path with prefix: %s", result)
} }

View file

@ -39,13 +39,13 @@ type Service struct {
// RR returns an RR representation of s. It is in a condensed form to minimize space // RR returns an RR representation of s. It is in a condensed form to minimize space
// when this is returned in a DNS message. // when this is returned in a DNS message.
// The RR will look like: // The RR will look like:
// skydns.local.skydns.east.production.rails.1. 300 CH TXT "service1.example.com:8080(10,0,,false)[0,]" // 1.rails.production.east.skydns.local. 300 CH TXT "service1.example.com:8080(10,0,,false)[0,]"
// etcd Key Ttl Host:Port < see below > // etcd Key Ttl Host:Port < see below >
// between parens: (Priority, Weight, Text (only first 200 bytes!), Mail) // between parens: (Priority, Weight, Text (only first 200 bytes!), Mail)
// between blockquotes: [TargetStrip,Group] // between blockquotes: [TargetStrip,Group]
// If the record is synthesised by CoreDNS (i.e. no lookup in etcd happened): // If the record is synthesised by CoreDNS (i.e. no lookup in etcd happened):
// //
// skydns.local.skydns.east.production.rails.1. 300 CH TXT "service1.example.com:8080(10,0,,false)[0,]" // TODO(miek): what to put here?
// //
func (s *Service) RR() *dns.TXT { func (s *Service) RR() *dns.TXT {
l := len(s.Text) l := len(s.Text)
@ -56,8 +56,7 @@ func (s *Service) RR() *dns.TXT {
t.Hdr.Class = dns.ClassCHAOS t.Hdr.Class = dns.ClassCHAOS
t.Hdr.Ttl = s.Ttl t.Hdr.Ttl = s.Ttl
t.Hdr.Rrtype = dns.TypeTXT t.Hdr.Rrtype = dns.TypeTXT
// TODO(miek): key guaranteerd to be > 1? t.Hdr.Name = Domain(s.Key)
t.Hdr.Name = strings.Replace(s.Key[1:], "/", ".", -1) + "." // TODO(miek): slightly more like etcd.Domain()
t.Txt = make([]string, 1) t.Txt = make([]string, 1)
t.Txt[0] = fmt.Sprintf("%s:%d(%d,%d,%s,%t)[%d,%s]", t.Txt[0] = fmt.Sprintf("%s:%d(%d,%d,%s,%t)[%d,%s]",

View file

@ -47,12 +47,12 @@ func set(t *testing.T, e Etcd, k string, ttl time.Duration, m *msg.Service) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
path, _ := e.PathWithWildcard(k) path, _ := msg.PathWithWildcard(k, e.PathPrefix)
e.Client.Set(ctx, path, string(b), &etcdc.SetOptions{TTL: ttl}) e.Client.Set(ctx, path, string(b), &etcdc.SetOptions{TTL: ttl})
} }
func delete(t *testing.T, e Etcd, k string) { func delete(t *testing.T, e Etcd, k string) {
path, _ := e.PathWithWildcard(k) path, _ := msg.PathWithWildcard(k, e.PathPrefix)
e.Client.Delete(ctx, path, &etcdc.DeleteOptions{Recursive: false}) e.Client.Delete(ctx, path, &etcdc.DeleteOptions{Recursive: false})
} }

View file

@ -7,6 +7,7 @@ import (
"strings" "strings"
"time" "time"
"github.com/miekg/coredns/middleware/etcd/msg"
"github.com/miekg/coredns/middleware/proxy" "github.com/miekg/coredns/middleware/proxy"
"github.com/miekg/dns" "github.com/miekg/dns"
@ -46,7 +47,7 @@ func (e *Etcd) updateStubZones() {
continue continue
} }
domain := e.Domain(serv.Key) domain := msg.Domain(serv.Key)
labels := dns.SplitDomainName(domain) labels := dns.SplitDomainName(domain)
// If the remaining name equals any of the zones we have, we ignore it. // If the remaining name equals any of the zones we have, we ignore it.