mirror of
https://github.com/coredns/coredns.git
synced 2025-11-01 02:33:14 -04:00
Allow debug queries to etcd middleware (#150)
With this you can retreive the raw data that the etcd middleware used to create the reply. The debug data is put in TXT records that are stuffed in the CH classs. This is only enabled if you specify `debug` in the etcd stanza. You can retrieve it by prefixing your query with 'o-o.debug.' For instance: ; <<>> DiG 9.10.3-P4-Ubuntu <<>> @localhost -p 1053 SRV o-o.debug.production.*.skydns.local ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 47798 ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 3 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 4096 ;; QUESTION SECTION: ;o-o.debug.production.*.skydns.local. IN SRV ;; ANSWER SECTION: production.*.skydns.local. 154 IN SRV 10 50 8080 service1.example.com. production.*.skydns.local. 154 IN SRV 10 50 8080 service2.example.com. ;; ADDITIONAL SECTION: skydns.local.skydns.east.production.rails.1. 154 CH TXT "service1.example.com:8080(10,0,,false)[0,]" skydns.local.skydns.west.production.rails.2. 154 CH TXT "service2.example.com:8080(10,0,,false)[0,]"
This commit is contained in:
@@ -12,19 +12,22 @@ import (
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
func (e Etcd) records(state middleware.State, exact bool) ([]msg.Service, error) {
|
||||
services, err := e.Records(state.Name(), exact)
|
||||
func (e Etcd) records(state middleware.State, exact bool) (services, debug []msg.Service, err error) {
|
||||
services, err = e.Records(state.Name(), exact)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return
|
||||
}
|
||||
if e.debug != "" {
|
||||
debug = services
|
||||
}
|
||||
services = msg.Group(services)
|
||||
return services, nil
|
||||
return
|
||||
}
|
||||
|
||||
func (e Etcd) A(zone string, state middleware.State, previousRecords []dns.RR) (records []dns.RR, err error) {
|
||||
services, err := e.records(state, false)
|
||||
func (e Etcd) A(zone string, state middleware.State, previousRecords []dns.RR) (records []dns.RR, debug []msg.Service, err error) {
|
||||
services, debug, err := e.records(state, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, debug, err
|
||||
}
|
||||
|
||||
for _, serv := range services {
|
||||
@@ -47,13 +50,14 @@ func (e Etcd) A(zone string, state middleware.State, previousRecords []dns.RR) (
|
||||
}
|
||||
|
||||
state1 := copyState(state, serv.Host, state.QType())
|
||||
nextRecords, err := e.A(zone, state1, append(previousRecords, newRecord))
|
||||
nextRecords, nextDebug, err := e.A(zone, state1, append(previousRecords, newRecord))
|
||||
|
||||
if err == nil {
|
||||
// Not only have we found something we should add the CNAME and the IP addresses.
|
||||
if len(nextRecords) > 0 {
|
||||
records = append(records, newRecord)
|
||||
records = append(records, nextRecords...)
|
||||
debug = append(debug, nextDebug...)
|
||||
}
|
||||
continue
|
||||
}
|
||||
@@ -77,13 +81,13 @@ func (e Etcd) A(zone string, state middleware.State, previousRecords []dns.RR) (
|
||||
// nodata?
|
||||
}
|
||||
}
|
||||
return records, nil
|
||||
return records, debug, nil
|
||||
}
|
||||
|
||||
func (e Etcd) AAAA(zone string, state middleware.State, previousRecords []dns.RR) (records []dns.RR, err error) {
|
||||
services, err := e.records(state, false)
|
||||
func (e Etcd) AAAA(zone string, state middleware.State, previousRecords []dns.RR) (records []dns.RR, debug []msg.Service, err error) {
|
||||
services, debug, err := e.records(state, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, debug, err
|
||||
}
|
||||
|
||||
for _, serv := range services {
|
||||
@@ -106,13 +110,14 @@ func (e Etcd) AAAA(zone string, state middleware.State, previousRecords []dns.RR
|
||||
}
|
||||
|
||||
state1 := copyState(state, serv.Host, state.QType())
|
||||
nextRecords, err := e.AAAA(zone, state1, append(previousRecords, newRecord))
|
||||
nextRecords, nextDebug, err := e.AAAA(zone, state1, append(previousRecords, newRecord))
|
||||
|
||||
if err == nil {
|
||||
// Not only have we found something we should add the CNAME and the IP addresses.
|
||||
if len(nextRecords) > 0 {
|
||||
records = append(records, newRecord)
|
||||
records = append(records, nextRecords...)
|
||||
debug = append(debug, nextDebug...)
|
||||
}
|
||||
continue
|
||||
}
|
||||
@@ -137,15 +142,15 @@ func (e Etcd) AAAA(zone string, state middleware.State, previousRecords []dns.RR
|
||||
records = append(records, serv.NewAAAA(state.QName(), ip.To16()))
|
||||
}
|
||||
}
|
||||
return records, nil
|
||||
return records, debug, nil
|
||||
}
|
||||
|
||||
// SRV returns SRV records from etcd.
|
||||
// If the Target is not a name but an IP address, a name is created on the fly.
|
||||
func (e Etcd) SRV(zone string, state middleware.State) (records []dns.RR, extra []dns.RR, err error) {
|
||||
services, err := e.records(state, false)
|
||||
func (e Etcd) SRV(zone string, state middleware.State) (records, extra []dns.RR, debug []msg.Service, err error) {
|
||||
services, debug, err := e.records(state, false)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
// Looping twice to get the right weight vs priority
|
||||
@@ -201,9 +206,10 @@ func (e Etcd) SRV(zone string, state middleware.State) (records []dns.RR, extra
|
||||
// Internal name, we should have some info on them, either v4 or v6
|
||||
// Clients expect a complete answer, because we are a recursor in their view.
|
||||
state1 := copyState(state, srv.Target, dns.TypeA)
|
||||
addr, e1 := e.A(zone, state1, nil)
|
||||
addr, debugAddr, e1 := e.A(zone, state1, nil)
|
||||
if e1 == nil {
|
||||
extra = append(extra, addr...)
|
||||
debug = append(debug, debugAddr...)
|
||||
}
|
||||
// e.AAA(zone, state1, nil) as well...?
|
||||
case ip.To4() != nil:
|
||||
@@ -220,15 +226,15 @@ func (e Etcd) SRV(zone string, state middleware.State) (records []dns.RR, extra
|
||||
extra = append(extra, serv.NewAAAA(srv.Target, ip.To16()))
|
||||
}
|
||||
}
|
||||
return records, extra, nil
|
||||
return records, extra, debug, nil
|
||||
}
|
||||
|
||||
// MX returns MX records from etcd.
|
||||
// If the Target is not a name but an IP address, a name is created on the fly.
|
||||
func (e Etcd) MX(zone string, state middleware.State) (records []dns.RR, extra []dns.RR, err error) {
|
||||
services, err := e.records(state, false)
|
||||
func (e Etcd) MX(zone string, state middleware.State) (records, extra []dns.RR, debug []msg.Service, err error) {
|
||||
services, debug, err := e.records(state, false)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, nil, debug, err
|
||||
}
|
||||
|
||||
lookup := make(map[string]bool)
|
||||
@@ -265,9 +271,10 @@ func (e Etcd) MX(zone string, state middleware.State) (records []dns.RR, extra [
|
||||
}
|
||||
// Internal name
|
||||
state1 := copyState(state, mx.Mx, dns.TypeA)
|
||||
addr, e1 := e.A(zone, state1, nil)
|
||||
addr, debugAddr, e1 := e.A(zone, state1, nil)
|
||||
if e1 == nil {
|
||||
extra = append(extra, addr...)
|
||||
debug = append(debug, debugAddr...)
|
||||
}
|
||||
// e.AAAA as well
|
||||
case ip.To4() != nil:
|
||||
@@ -280,13 +287,13 @@ func (e Etcd) MX(zone string, state middleware.State) (records []dns.RR, extra [
|
||||
extra = append(extra, serv.NewAAAA(serv.Host, ip.To16()))
|
||||
}
|
||||
}
|
||||
return records, extra, nil
|
||||
return records, extra, debug, nil
|
||||
}
|
||||
|
||||
func (e Etcd) CNAME(zone string, state middleware.State) (records []dns.RR, err error) {
|
||||
services, err := e.records(state, true)
|
||||
func (e Etcd) CNAME(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, err
|
||||
return nil, debug, err
|
||||
}
|
||||
|
||||
if len(services) > 0 {
|
||||
@@ -295,13 +302,13 @@ func (e Etcd) CNAME(zone string, state middleware.State) (records []dns.RR, err
|
||||
records = append(records, serv.NewCNAME(state.QName(), serv.Host))
|
||||
}
|
||||
}
|
||||
return records, nil
|
||||
return records, debug, nil
|
||||
}
|
||||
|
||||
func (e Etcd) TXT(zone string, state middleware.State) (records []dns.RR, err error) {
|
||||
services, err := e.records(state, false)
|
||||
func (e Etcd) TXT(zone string, state middleware.State) (records []dns.RR, debug []msg.Service, err error) {
|
||||
services, debug, err := e.records(state, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, debug, err
|
||||
}
|
||||
|
||||
for _, serv := range services {
|
||||
@@ -310,19 +317,19 @@ func (e Etcd) TXT(zone string, state middleware.State) (records []dns.RR, err er
|
||||
}
|
||||
records = append(records, serv.NewTXT(state.QName()))
|
||||
}
|
||||
return records, nil
|
||||
return records, debug, nil
|
||||
}
|
||||
|
||||
func (e Etcd) NS(zone string, state middleware.State) (records, extra []dns.RR, err error) {
|
||||
func (e Etcd) NS(zone string, state middleware.State) (records, extra []dns.RR, debug []msg.Service, 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.Clear()
|
||||
state.Req.Question[0].Name = "ns.dns." + zone
|
||||
services, err := e.records(state, false)
|
||||
services, debug, err := e.records(state, false)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, nil, debug, err
|
||||
}
|
||||
// ... and reset
|
||||
state.Req.Question[0].Name = old
|
||||
@@ -331,7 +338,7 @@ func (e Etcd) NS(zone string, state middleware.State) (records, extra []dns.RR,
|
||||
ip := net.ParseIP(serv.Host)
|
||||
switch {
|
||||
case ip == nil:
|
||||
return nil, nil, 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:
|
||||
serv.Host = e.Domain(serv.Key)
|
||||
records = append(records, serv.NewNS(state.QName()))
|
||||
@@ -342,13 +349,14 @@ func (e Etcd) NS(zone string, state middleware.State) (records, extra []dns.RR,
|
||||
extra = append(extra, serv.NewAAAA(serv.Host, ip.To16()))
|
||||
}
|
||||
}
|
||||
return records, extra, nil
|
||||
return records, extra, debug, nil
|
||||
}
|
||||
|
||||
// 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.RR, []msg.Service, error) {
|
||||
header := dns.RR_Header{Name: zone, Rrtype: dns.TypeSOA, Ttl: 300, Class: dns.ClassINET}
|
||||
return &dns.SOA{Hdr: header,
|
||||
|
||||
soa := &dns.SOA{Hdr: header,
|
||||
Mbox: "hostmaster." + zone,
|
||||
Ns: "ns.dns." + zone,
|
||||
Serial: uint32(time.Now().Unix()),
|
||||
@@ -357,10 +365,10 @@ func (e Etcd) SOA(zone string, state middleware.State) *dns.SOA {
|
||||
Expire: 86400,
|
||||
Minttl: 60,
|
||||
}
|
||||
// TODO(miek): fake some msg.Service here when returning.
|
||||
return []dns.RR{soa}, nil, nil
|
||||
}
|
||||
|
||||
// TODO(miek): DNSKEY and friends... intercepted by the DNSSEC middleware?
|
||||
|
||||
func isDuplicateCNAME(r *dns.CNAME, records []dns.RR) bool {
|
||||
for _, rec := range records {
|
||||
if v, ok := rec.(*dns.CNAME); ok {
|
||||
@@ -372,6 +380,7 @@ func isDuplicateCNAME(r *dns.CNAME, records []dns.RR) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// TODO(miek): Move to middleware?
|
||||
func copyState(state middleware.State, target string, typ uint16) middleware.State {
|
||||
state1 := middleware.State{W: state.W, Req: state.Req.Copy()}
|
||||
state1.Req.Question[0] = dns.Question{dns.Fqdn(target), dns.ClassINET, typ}
|
||||
|
||||
Reference in New Issue
Block a user