Skip to content

Commit

Permalink
Support CNAMEs and the ANY query type
Browse files Browse the repository at this point in the history
Add support for CNAMEs both inside and outside of the zones set by this plugin.

Add support for the ANY question type.

CNAME support is robust against excessive stack depth and loops.

Includes tests for all changes.

Signed-off-by: Dan Fuhry <[email protected]>
  • Loading branch information
fuhry committed Mar 8, 2023
1 parent e8b4cfd commit f70b873
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 2 deletions.
36 changes: 35 additions & 1 deletion records.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import (
"github.com/miekg/dns"
)

const maxCnameStackDepth = 10

// Records is the plugin handler.
type Records struct {
origins []string // for easy matching, these strings are the index in the map m.
Expand All @@ -34,15 +36,38 @@ func (re *Records) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Ms

nxdomain := true
var soa dns.RR
cnameStack := make(map[string]struct{}, 0)

resolveLoop:
for _, r := range re.m[zone] {
if _, ok := cnameStack[qname]; ok {
log.Errorf("detected loop in CNAME chain, name [%s] already processed", qname)
goto servfail
}
if len(cnameStack) > maxCnameStackDepth {
log.Errorf("maximum CNAME stack depth of %d exceeded", maxCnameStackDepth)
goto servfail
}

if r.Header().Rrtype == dns.TypeSOA && soa == nil {
soa = r
}
if r.Header().Name == qname {
nxdomain = false
if r.Header().Rrtype == state.QType() {
if r.Header().Rrtype == state.QType() || r.Header().Rrtype == dns.TypeCNAME || state.QType() == dns.TypeANY {
m.Answer = append(m.Answer, r)
}
if r.Header().Rrtype == dns.TypeCNAME {
cnameStack[qname] = struct{}{}
qname = r.(*dns.CNAME).Target
if plugin.Zones(re.origins).Matches(qname) == "" {
// if the CNAME target isn't a record in this zone, break and return.
// The administrator can configure the `finalize` plugin (https://coredns.io/explugins/finalize/)
// to complete resolution of these names.
break resolveLoop
}
goto resolveLoop
}
}
}

Expand All @@ -64,6 +89,15 @@ func (re *Records) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Ms

w.WriteMsg(m)
return dns.RcodeSuccess, nil

servfail:
m.Rcode = dns.RcodeServerFailure
m.Answer = nil
if soa != nil {
m.Ns = []dns.RR{soa}
}
w.WriteMsg(m)
return dns.RcodeServerFailure, nil
}

// Name implements the plugin.Handle interface.
Expand Down
49 changes: 48 additions & 1 deletion records_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"github.com/coredns/coredns/plugin/pkg/dnstest"
"github.com/coredns/coredns/plugin/test"

"github.com/caddyserver/caddy"
"github.com/coredns/caddy"
"github.com/miekg/dns"
)

Expand Down Expand Up @@ -76,6 +76,25 @@ func TestLookupNoSOA(t *testing.T) {
records {
example.org. 60 IN MX 10 mx.example.org.
mx.example.org. 60 IN A 127.0.0.1
cname.example.org. 60 IN CNAME mx.example.org.
dualstack.example.org. 60 IN A 127.0.0.1
dualstack.example.org. 60 IN AAAA ::1
cnameloop1.example.org. 60 IN CNAME cnameloop2.example.org.
cnameloop2.example.org. 60 IN CNAME cnameloop1.example.org.
cnameext.example.org. 60 IN CNAME mx.example.net.
cnamedepth.example.org. 60 IN CNAME cnamedepth1.example.org.
cnamedepth1.example.org. 60 IN CNAME cnamedepth2.example.org.
cnamedepth2.example.org. 60 IN CNAME cnamedepth3.example.org.
cnamedepth3.example.org. 60 IN CNAME cnamedepth4.example.org.
cnamedepth4.example.org. 60 IN CNAME cnamedepth5.example.org.
cnamedepth5.example.org. 60 IN CNAME cnamedepth6.example.org.
cnamedepth6.example.org. 60 IN CNAME cnamedepth7.example.org.
cnamedepth7.example.org. 60 IN CNAME cnamedepth8.example.org.
cnamedepth8.example.org. 60 IN CNAME cnamedepth9.example.org.
cnamedepth9.example.org. 60 IN CNAME cnamedepth10.example.org.
cnamedepth10.example.org. 60 IN CNAME cnamedepth11.example.org.
cnamedepth11.example.org. 60 IN A 127.0.0.1
}
`

Expand Down Expand Up @@ -122,6 +141,34 @@ var testCasesNoSOA = []test.Case{
{
Qname: "mx.example.org.", Qtype: dns.TypeAAAA,
},
{
Qname: "dualstack.example.org.", Qtype: dns.TypeANY,
Answer: []dns.RR{
test.A("dualstack.example.org. 60 IN A 127.0.0.1"),
test.AAAA("dualstack.example.org. 60 IN AAAA ::1"),
},
},
{
Qname: "cname.example.org.", Qtype: dns.TypeA,
Answer: []dns.RR{
test.CNAME("cname.example.org. 60 IN CNAME mx.example.org."),
test.A("mx.example.org. 60 IN A 127.0.0.1"),
},
},
{
Qname: "cnameext.example.org.", Qtype: dns.TypeA,
Answer: []dns.RR{
test.CNAME("cnameext.example.org. 60 IN CNAME mx.example.net."),
},
},
{
Rcode: dns.RcodeServerFailure,
Qname: "cnameloop1.example.org.", Qtype: dns.TypeA,
},
{
Rcode: dns.RcodeServerFailure,
Qname: "cnamedepth.example.org.", Qtype: dns.TypeA,
},
}

func TestLookupMultipleOrigins(t *testing.T) {
Expand Down

0 comments on commit f70b873

Please sign in to comment.