mirror of
https://github.com/coredns/coredns.git
synced 2026-09-01 09:37:05 -04:00
273 lines
7.4 KiB
Go
273 lines
7.4 KiB
Go
|
|
package file
|
||
|
|
|
||
|
|
import (
|
||
|
|
"context"
|
||
|
|
"strings"
|
||
|
|
"testing"
|
||
|
|
|
||
|
|
"github.com/coredns/coredns/plugin/pkg/dnstest"
|
||
|
|
"github.com/coredns/coredns/plugin/test"
|
||
|
|
|
||
|
|
"github.com/miekg/dns"
|
||
|
|
)
|
||
|
|
|
||
|
|
func TestAliasToDelegation(t *testing.T) {
|
||
|
|
zone, err := Parse(strings.NewReader(dbAliasDelegation), "example.org.", "stdin", 0)
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("Expected no error when reading zone, got %q", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
fm := File{
|
||
|
|
Next: test.ErrorHandler(),
|
||
|
|
Zones: Zones{
|
||
|
|
Z: map[string]*Zone{"example.org.": zone},
|
||
|
|
Names: []string{"example.org."},
|
||
|
|
},
|
||
|
|
}
|
||
|
|
|
||
|
|
tests := []struct {
|
||
|
|
name string
|
||
|
|
qname string
|
||
|
|
qtype uint16
|
||
|
|
authoritative bool
|
||
|
|
answer []dns.RR
|
||
|
|
authority []dns.RR
|
||
|
|
additional []dns.RR
|
||
|
|
}{
|
||
|
|
{
|
||
|
|
name: "CNAME to delegated child",
|
||
|
|
qname: "alias.example.org.",
|
||
|
|
qtype: dns.TypeA,
|
||
|
|
authoritative: true,
|
||
|
|
answer: []dns.RR{
|
||
|
|
test.CNAME("alias.example.org. 300 IN CNAME host.child.example.org."),
|
||
|
|
},
|
||
|
|
authority: []dns.RR{
|
||
|
|
test.NS("child.example.org. 300 IN NS ns.child.example.org."),
|
||
|
|
},
|
||
|
|
additional: []dns.RR{
|
||
|
|
test.A("ns.child.example.org. 300 IN A 192.0.2.2"),
|
||
|
|
test.AAAA("ns.child.example.org. 300 IN AAAA 2001:db8::2"),
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: "CNAME chain to delegated child",
|
||
|
|
qname: "chain.example.org.",
|
||
|
|
qtype: dns.TypeA,
|
||
|
|
authoritative: true,
|
||
|
|
answer: []dns.RR{
|
||
|
|
test.CNAME("alias.example.org. 300 IN CNAME host.child.example.org."),
|
||
|
|
test.CNAME("chain.example.org. 300 IN CNAME alias.example.org."),
|
||
|
|
},
|
||
|
|
authority: []dns.RR{
|
||
|
|
test.NS("child.example.org. 300 IN NS ns.child.example.org."),
|
||
|
|
},
|
||
|
|
additional: []dns.RR{
|
||
|
|
test.A("ns.child.example.org. 300 IN A 192.0.2.2"),
|
||
|
|
test.AAAA("ns.child.example.org. 300 IN AAAA 2001:db8::2"),
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: "wildcard CNAME to delegated child",
|
||
|
|
qname: "name.wild.example.org.",
|
||
|
|
qtype: dns.TypeA,
|
||
|
|
authoritative: true,
|
||
|
|
answer: []dns.RR{
|
||
|
|
test.CNAME("name.wild.example.org. 300 IN CNAME host.child.example.org."),
|
||
|
|
},
|
||
|
|
authority: []dns.RR{
|
||
|
|
test.NS("child.example.org. 300 IN NS ns.child.example.org."),
|
||
|
|
},
|
||
|
|
additional: []dns.RR{
|
||
|
|
test.A("ns.child.example.org. 300 IN A 192.0.2.2"),
|
||
|
|
test.AAAA("ns.child.example.org. 300 IN AAAA 2001:db8::2"),
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: "DNAME to delegated child",
|
||
|
|
qname: "host.mapped.example.org.",
|
||
|
|
qtype: dns.TypeA,
|
||
|
|
authoritative: true,
|
||
|
|
answer: []dns.RR{
|
||
|
|
test.CNAME("host.mapped.example.org. 300 IN CNAME host.example.org."),
|
||
|
|
test.DNAME("mapped.example.org. 300 IN DNAME example.org."),
|
||
|
|
},
|
||
|
|
authority: []dns.RR{
|
||
|
|
test.NS("host.example.org. 300 IN NS ns.host.example.org."),
|
||
|
|
},
|
||
|
|
additional: []dns.RR{
|
||
|
|
test.A("ns.host.example.org. 300 IN A 192.0.2.3"),
|
||
|
|
test.AAAA("ns.host.example.org. 300 IN AAAA 2001:db8::3"),
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: "DNAME NS query to delegated child",
|
||
|
|
qname: "host.mapped.example.org.",
|
||
|
|
qtype: dns.TypeNS,
|
||
|
|
authoritative: true,
|
||
|
|
answer: []dns.RR{
|
||
|
|
test.CNAME("host.mapped.example.org. 300 IN CNAME host.example.org."),
|
||
|
|
test.DNAME("mapped.example.org. 300 IN DNAME example.org."),
|
||
|
|
},
|
||
|
|
authority: []dns.RR{
|
||
|
|
test.NS("host.example.org. 300 IN NS ns.host.example.org."),
|
||
|
|
},
|
||
|
|
additional: []dns.RR{
|
||
|
|
test.A("ns.host.example.org. 300 IN A 192.0.2.3"),
|
||
|
|
test.AAAA("ns.host.example.org. 300 IN AAAA 2001:db8::3"),
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: "direct delegated child",
|
||
|
|
qname: "host.child.example.org.",
|
||
|
|
qtype: dns.TypeA,
|
||
|
|
authoritative: false,
|
||
|
|
authority: []dns.RR{
|
||
|
|
test.NS("child.example.org. 300 IN NS ns.child.example.org."),
|
||
|
|
},
|
||
|
|
additional: []dns.RR{
|
||
|
|
test.A("ns.child.example.org. 300 IN A 192.0.2.2"),
|
||
|
|
test.AAAA("ns.child.example.org. 300 IN AAAA 2001:db8::2"),
|
||
|
|
},
|
||
|
|
},
|
||
|
|
}
|
||
|
|
|
||
|
|
for _, tc := range tests {
|
||
|
|
t.Run(tc.name, func(t *testing.T) {
|
||
|
|
req := new(dns.Msg)
|
||
|
|
req.SetQuestion(tc.qname, tc.qtype)
|
||
|
|
rec := dnstest.NewRecorder(&test.ResponseWriter{})
|
||
|
|
|
||
|
|
if _, err := fm.ServeDNS(context.Background(), rec, req); err != nil {
|
||
|
|
t.Fatalf("ServeDNS() error = %v", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
want := test.Case{
|
||
|
|
Qname: tc.qname,
|
||
|
|
Qtype: tc.qtype,
|
||
|
|
Answer: tc.answer,
|
||
|
|
Ns: tc.authority,
|
||
|
|
Extra: tc.additional,
|
||
|
|
}
|
||
|
|
if err := test.SortAndCheck(rec.Msg, want); err != nil {
|
||
|
|
t.Error(err)
|
||
|
|
}
|
||
|
|
if rec.Msg.Authoritative != tc.authoritative {
|
||
|
|
t.Errorf("Authoritative = %t, want %t", rec.Msg.Authoritative, tc.authoritative)
|
||
|
|
}
|
||
|
|
})
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
const dbAliasDelegation = `
|
||
|
|
$TTL 300
|
||
|
|
$ORIGIN example.org.
|
||
|
|
@ IN SOA ns.example.org. admin.example.org. 1 3600 600 86400 300
|
||
|
|
IN NS ns.example.org.
|
||
|
|
ns IN A 192.0.2.1
|
||
|
|
|
||
|
|
alias IN CNAME host.child.example.org.
|
||
|
|
chain IN CNAME alias.example.org.
|
||
|
|
*.wild IN CNAME host.child.example.org.
|
||
|
|
child IN NS ns.child.example.org.
|
||
|
|
ns.child IN A 192.0.2.2
|
||
|
|
IN AAAA 2001:db8::2
|
||
|
|
|
||
|
|
mapped IN DNAME example.org.
|
||
|
|
host IN NS ns.host.example.org.
|
||
|
|
ns.host IN A 192.0.2.3
|
||
|
|
IN AAAA 2001:db8::3
|
||
|
|
`
|
||
|
|
|
||
|
|
func TestSignedAliasToDelegation(t *testing.T) {
|
||
|
|
zone, err := Parse(strings.NewReader(exampleOrgSigned), "example.org.", "stdin", 0)
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("Expected no error when reading zone, got %q", err)
|
||
|
|
}
|
||
|
|
if err := zone.Insert(test.CNAME("alias.example.org. 1800 IN CNAME a.delegated.example.org.")); err != nil {
|
||
|
|
t.Fatalf("Insert() error = %v", err)
|
||
|
|
}
|
||
|
|
if err := zone.Insert(test.CNAME("ds-alias.example.org. 1800 IN CNAME delegated.example.org.")); err != nil {
|
||
|
|
t.Fatalf("Insert() error = %v", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
fm := File{
|
||
|
|
Next: test.ErrorHandler(),
|
||
|
|
Zones: Zones{
|
||
|
|
Z: map[string]*Zone{"example.org.": zone},
|
||
|
|
Names: []string{"example.org."},
|
||
|
|
},
|
||
|
|
}
|
||
|
|
|
||
|
|
referral := secureDelegationCase(t, "a.delegated.example.org.", dns.TypeTXT)
|
||
|
|
dsAtCut := secureDelegationCase(t, "delegated.example.org.", dns.TypeDS)
|
||
|
|
tests := []struct {
|
||
|
|
name string
|
||
|
|
qname string
|
||
|
|
qtype uint16
|
||
|
|
answer []dns.RR
|
||
|
|
authority []dns.RR
|
||
|
|
additional []dns.RR
|
||
|
|
}{
|
||
|
|
{
|
||
|
|
name: "signed partial referral",
|
||
|
|
qname: "alias.example.org.",
|
||
|
|
qtype: dns.TypeA,
|
||
|
|
answer: []dns.RR{
|
||
|
|
test.CNAME("alias.example.org. 1800 IN CNAME a.delegated.example.org."),
|
||
|
|
},
|
||
|
|
authority: referral.Ns,
|
||
|
|
additional: referral.Extra,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: "DS at zone cut remains authoritative",
|
||
|
|
qname: "ds-alias.example.org.",
|
||
|
|
qtype: dns.TypeDS,
|
||
|
|
answer: append(
|
||
|
|
append([]dns.RR{}, dsAtCut.Answer...),
|
||
|
|
test.CNAME("ds-alias.example.org. 1800 IN CNAME delegated.example.org."),
|
||
|
|
),
|
||
|
|
authority: dsAtCut.Ns,
|
||
|
|
},
|
||
|
|
}
|
||
|
|
|
||
|
|
for _, tc := range tests {
|
||
|
|
t.Run(tc.name, func(t *testing.T) {
|
||
|
|
req := new(dns.Msg)
|
||
|
|
req.SetQuestion(tc.qname, tc.qtype)
|
||
|
|
req.SetEdns0(4096, true)
|
||
|
|
rec := dnstest.NewRecorder(&test.ResponseWriter{})
|
||
|
|
|
||
|
|
if _, err := fm.ServeDNS(context.Background(), rec, req); err != nil {
|
||
|
|
t.Fatalf("ServeDNS() error = %v", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
want := test.Case{
|
||
|
|
Qname: tc.qname,
|
||
|
|
Qtype: tc.qtype,
|
||
|
|
Do: true,
|
||
|
|
Answer: tc.answer,
|
||
|
|
Ns: tc.authority,
|
||
|
|
Extra: tc.additional,
|
||
|
|
}
|
||
|
|
if err := test.SortAndCheck(rec.Msg, want); err != nil {
|
||
|
|
t.Error(err)
|
||
|
|
}
|
||
|
|
if !rec.Msg.Authoritative {
|
||
|
|
t.Error("Authoritative = false, want true")
|
||
|
|
}
|
||
|
|
})
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func secureDelegationCase(t *testing.T, qname string, qtype uint16) test.Case {
|
||
|
|
t.Helper()
|
||
|
|
for _, tc := range secureDelegationTestCases {
|
||
|
|
if tc.Qname == qname && tc.Qtype == qtype {
|
||
|
|
return tc
|
||
|
|
}
|
||
|
|
}
|
||
|
|
t.Fatalf("secure delegation fixture has no %s/%s case", qname, dns.TypeToString[qtype])
|
||
|
|
return test.Case{}
|
||
|
|
}
|