Implement external lookups for CNAMEs

This commit is contained in:
Miek Gieben 2016-11-10 07:48:47 +00:00
parent 0919216d3c
commit d383f279a0
7 changed files with 39 additions and 16 deletions

View file

@ -34,7 +34,7 @@ type (
// In the future this should be something like ZoneMeta that contains all this stuff. // In the future this should be something like ZoneMeta that contains all this stuff.
transferTo []string transferTo []string
noReload bool noReload bool
Proxy proxy.Proxy // Proxy for looking up names during the resolution process proxy proxy.Proxy // Proxy for looking up names during the resolution process
duration time.Duration duration time.Duration
} }

View file

@ -155,7 +155,7 @@ func autoParse(c *caddy.Controller) (Auto, error) {
args[i] = h + ":53" args[i] = h + ":53"
} }
} }
a.loader.Proxy = proxy.New(args) a.loader.proxy = proxy.New(args)
default: default:
t, _, e := file.TransferParse(c, false) t, _, e := file.TransferParse(c, false)

View file

@ -51,6 +51,7 @@ func (a Auto) Walk() error {
} }
zo.NoReload = a.loader.noReload zo.NoReload = a.loader.noReload
zo.Proxy = a.loader.proxy
zo.TransferTo = a.loader.transferTo zo.TransferTo = a.loader.transferTo
a.Zones.Add(zo, origin) a.Zones.Add(zo, origin)

View file

@ -93,7 +93,7 @@ func TestLookupCNAMEExternal(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Expected no error when reading zone, got %q", err) t.Fatalf("Expected no error when reading zone, got %q", err)
} }
zone.Proxy = proxy.New([]string{"8.8.8.8:53"}) // TODO(point to local instance) zone.Proxy = proxy.New([]string{"8.8.8.8:53"}) // TODO(miek): point to local instance
fm := File{Next: test.ErrorHandler(), Zones: Zones{Z: map[string]*Zone{name: zone}, Names: []string{name}}} fm := File{Next: test.ErrorHandler(), Zones: Zones{Z: map[string]*Zone{name: zone}, Names: []string{name}}}
ctx := context.TODO() ctx := context.TODO()

View file

@ -84,7 +84,7 @@ func (f File) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (i
return xfr.ServeDNS(ctx, w, r) return xfr.ServeDNS(ctx, w, r)
} }
answer, ns, extra, result := z.Lookup(qname, state.QType(), state.Do()) answer, ns, extra, result := z.Lookup(state, qname)
m := new(dns.Msg) m := new(dns.Msg)
m.SetReply(r) m.SetReply(r)

View file

@ -25,7 +25,11 @@ const (
// Lookup looks up qname and qtype in the zone. When do is true DNSSEC records are included. // Lookup looks up qname and qtype in the zone. When do is true DNSSEC records are included.
// Three sets of records are returned, one for the answer, one for authority and one for the additional section. // Three sets of records are returned, one for the answer, one for authority and one for the additional section.
func (z *Zone) Lookup(qname string, qtype uint16, do bool) ([]dns.RR, []dns.RR, []dns.RR, Result) { func (z *Zone) Lookup(state request.Request, qname string) ([]dns.RR, []dns.RR, []dns.RR, Result) {
qtype := state.QType()
do := state.Do()
if !z.NoReload { if !z.NoReload {
z.reloadMu.RLock() z.reloadMu.RLock()
} }
@ -121,7 +125,7 @@ func (z *Zone) Lookup(qname string, qtype uint16, do bool) ([]dns.RR, []dns.RR,
// DNAME...? // DNAME...?
if rrs := elem.Types(dns.TypeCNAME); len(rrs) > 0 && qtype != dns.TypeCNAME { if rrs := elem.Types(dns.TypeCNAME); len(rrs) > 0 && qtype != dns.TypeCNAME {
return z.searchCNAME(elem, rrs, qtype, do) return z.searchCNAME(state, elem, rrs)
} }
rrs := elem.Types(qtype, qname) rrs := elem.Types(qtype, qname)
@ -153,7 +157,7 @@ func (z *Zone) Lookup(qname string, qtype uint16, do bool) ([]dns.RR, []dns.RR,
auth := []dns.RR{} auth := []dns.RR{}
if rrs := wildElem.Types(dns.TypeCNAME, qname); len(rrs) > 0 { if rrs := wildElem.Types(dns.TypeCNAME, qname); len(rrs) > 0 {
return z.searchCNAME(wildElem, rrs, qtype, do) return z.searchCNAME(state, wildElem, rrs)
} }
rrs := wildElem.Types(qtype, qname) rrs := wildElem.Types(qtype, qname)
@ -252,7 +256,11 @@ func (z *Zone) ns(do bool) []dns.RR {
return z.Apex.NS return z.Apex.NS
} }
func (z *Zone) searchCNAME(elem *tree.Elem, rrs []dns.RR, qtype uint16, do bool) ([]dns.RR, []dns.RR, []dns.RR, Result) { func (z *Zone) searchCNAME(state request.Request, elem *tree.Elem, rrs []dns.RR) ([]dns.RR, []dns.RR, []dns.RR, Result) {
qtype := state.QType()
do := state.Do()
if do { if do {
sigs := elem.Types(dns.TypeRRSIG) sigs := elem.Types(dns.TypeRRSIG)
sigs = signatureForSubType(sigs, dns.TypeCNAME) sigs = signatureForSubType(sigs, dns.TypeCNAME)
@ -263,14 +271,10 @@ func (z *Zone) searchCNAME(elem *tree.Elem, rrs []dns.RR, qtype uint16, do bool)
targetName := rrs[0].(*dns.CNAME).Target targetName := rrs[0].(*dns.CNAME).Target
elem, _ = z.Tree.Search(targetName) elem, _ = z.Tree.Search(targetName)
println(targetName)
if elem == nil { if elem == nil {
if !dns.IsSubDomain(z.origin, targetName) { if !dns.IsSubDomain(z.origin, targetName) {
println(targetName, "is not a child of", z.origin) rrs = append(rrs, z.externalLookup(state, targetName, qtype)...)
} }
st := request.Request{}
z.Proxy.Lookup(st, targetName, qtype)
return rrs, nil, nil, Success return rrs, nil, nil, Success
} }
@ -292,7 +296,9 @@ Redo:
elem, _ = z.Tree.Search(targetName) elem, _ = z.Tree.Search(targetName)
if elem == nil { if elem == nil {
if !dns.IsSubDomain(z.origin, targetName) { if !dns.IsSubDomain(z.origin, targetName) {
println(targetName, "is not a child of", z.origin) if !dns.IsSubDomain(z.origin, targetName) {
rrs = append(rrs, z.externalLookup(state, targetName, qtype)...)
}
} }
return rrs, nil, nil, Success return rrs, nil, nil, Success
} }
@ -331,6 +337,15 @@ func cnameForType(targets []dns.RR, origQtype uint16) []dns.RR {
return ret return ret
} }
func (z *Zone) externalLookup(state request.Request, target string, qtype uint16) []dns.RR {
m, e := z.Proxy.Lookup(state, target, qtype)
if e != nil || m == nil {
// TODO(miek): debugMsg for this as well? Log?
return nil
}
return m.Answer
}
// signatureForSubType range through the signature and return the correct ones for the subtype. // signatureForSubType range through the signature and return the correct ones for the subtype.
func signatureForSubType(rrs []dns.RR, subtype uint16) []dns.RR { func signatureForSubType(rrs []dns.RR, subtype uint16) []dns.RR {
sigs := []dns.RR{} sigs := []dns.RR{}

View file

@ -8,6 +8,7 @@ import (
"time" "time"
"github.com/miekg/coredns/middleware/test" "github.com/miekg/coredns/middleware/test"
"github.com/miekg/coredns/request"
"github.com/miekg/dns" "github.com/miekg/dns"
) )
@ -31,11 +32,17 @@ func TestZoneReload(t *testing.T) {
z.Reload() z.Reload()
if _, _, _, res := z.Lookup("miek.nl.", dns.TypeSOA, false); res != Success { r := new(dns.Msg)
r.SetQuestion("miek.nl", dns.TypeSOA)
state := request.Request{W: &test.ResponseWriter{}, Req: r}
if _, _, _, res := z.Lookup(state, "miek.nl."); res != Success {
t.Fatalf("failed to lookup, got %d", res) t.Fatalf("failed to lookup, got %d", res)
} }
if _, _, _, res := z.Lookup("miek.nl.", dns.TypeNS, false); res != Success { r = new(dns.Msg)
r.SetQuestion("miek.nl", dns.TypeNS)
state = request.Request{W: &test.ResponseWriter{}, Req: r}
if _, _, _, res := z.Lookup(state, "miek.nl."); res != Success {
t.Fatalf("failed to lookup, got %d", res) t.Fatalf("failed to lookup, got %d", res)
} }