middleware/etcd: Return json parsing errors (#158)

When coredns unmarshals a json value and it fails it will put the error
in the returned message iff the query was a debug query
(o-o.debug.<REST>).
This commit is contained in:
Miek Gieben
2016-06-07 20:57:45 +01:00
parent d04abdf422
commit 3110306296
4 changed files with 41 additions and 8 deletions

View File

@@ -39,7 +39,7 @@ etcd [zones...] {
pointing to external names. If you want CoreDNS to act as a proxy for clients you'll need to add
the proxy middleware.
* `tls` followed the cert, key and the CA's cert filenames.
* `debug` allow debug queries. Prefix the name with `o-o.debug.` to reveive extra information in the
* `debug` allow debug queries. Prefix the name with `o-o.debug.` to retrieve extra information in the
additional section of the reply in the form of text records:
skydns.test.skydns.dom.a. 300 CH TXT "127.0.0.1:0(10,0,,false)[0,]"
@@ -47,6 +47,13 @@ etcd [zones...] {
This shows the complete key as the owername, the rdata of the TXT record has:
`host:port(priority,weight,txt content,mail)[targetstrip,group]`.
Any errors seen doing parsing will show up like this:
. 0 CH TXT "/skydns/local/skydns/r/a: invalid character '.' after object key:value pair"
which shows `a.r.skydns.local.` has a json encoding problem.
## Examples
This is the default SkyDNS setup, with everying specified in full:

View File

@@ -36,3 +36,21 @@ func servicesToTxt(debug []msg.Service) []dns.RR {
}
return rr
}
func errorToTxt(err error) dns.RR {
if err == nil {
return nil
}
msg := err.Error()
if len(msg) > 255 {
msg = msg[:255]
}
t := new(dns.TXT)
t.Hdr.Class = dns.ClassCHAOS
t.Hdr.Ttl = 0
t.Hdr.Rrtype = dns.TypeTXT
t.Hdr.Name = "."
t.Txt = []string{msg}
return t
}

View File

@@ -3,6 +3,7 @@ package etcd
import (
"encoding/json"
"fmt"
"strings"
"time"
@@ -104,7 +105,7 @@ Nodes:
}
serv := new(msg.Service)
if err := json.Unmarshal([]byte(n.Value), serv); err != nil {
return nil, err
return nil, fmt.Errorf("%s: %s", n.Key, err.Error())
}
b := msg.Service{Host: serv.Host, Port: serv.Port, Priority: serv.Priority, Weight: serv.Weight, Text: serv.Text, Key: n.Key}
if _, ok := bx[b]; ok {

View File

@@ -82,14 +82,14 @@ func (e Etcd) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (i
}
if isEtcdNameError(err) {
return e.Err(zone, dns.RcodeNameError, state, debug)
return e.Err(zone, dns.RcodeNameError, state, debug, err)
}
if err != nil {
return dns.RcodeServerFailure, err
return e.Err(zone, dns.RcodeServerFailure, state, debug, err)
}
if len(records) == 0 {
return e.Err(zone, dns.RcodeSuccess, state, debug)
return e.Err(zone, dns.RcodeSuccess, state, debug, err)
}
m := new(dns.Msg)
@@ -109,15 +109,22 @@ func (e Etcd) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (i
}
// Err write an error response to the client.
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, err error) (int, error) {
m := new(dns.Msg)
m.SetRcode(state.Req, rcode)
m.Authoritative, m.RecursionAvailable, m.Compress = true, true, true
m.Ns, _, _ = e.SOA(zone, state)
m.Extra = servicesToTxt(debug)
if e.debug != "" {
m.Extra = servicesToTxt(debug)
txt := errorToTxt(err)
if txt != nil {
m.Extra = append(m.Extra, errorToTxt(err))
}
}
state.SizeAndDo(m)
state.W.WriteMsg(m)
return rcode, nil
// Return success as the rcode to signal we have written to the client.
return dns.RcodeSuccess, nil
}
func dedup(m *dns.Msg) *dns.Msg {