mirror of
https://github.com/coredns/coredns.git
synced 2026-08-20 23:08:28 -04:00
externalLookup, which resolves the chase for ordinary CNAME, wildcard CNAME, and DNAME answers, returned a nil additional section. So a chased SRV/MX/SVCB/HTTPS answer with an in-bailiwick target was missing the target's A/AAAA glue, unlike the direct path. Run additionalProcessing at externalLookup's return points so all three callers add the glue, and add ordinary-CNAME, wildcard-CNAME, and DNAME regression cases. Fixes #6628 Signed-off-by: Saleh <root@lr0.org>
560 lines
16 KiB
Go
560 lines
16 KiB
Go
package file
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/coredns/coredns/plugin/pkg/dnstest"
|
|
"github.com/coredns/coredns/plugin/pkg/fall"
|
|
"github.com/coredns/coredns/plugin/test"
|
|
"github.com/coredns/coredns/request"
|
|
|
|
"github.com/miekg/dns"
|
|
)
|
|
|
|
var dnsTestCases = []test.Case{
|
|
{
|
|
Qname: "www.miek.nl.", Qtype: dns.TypeA,
|
|
Answer: []dns.RR{
|
|
test.A("a.miek.nl. 1800 IN A 139.162.196.78"),
|
|
test.CNAME("www.miek.nl. 1800 IN CNAME a.miek.nl."),
|
|
},
|
|
Ns: miekAuth,
|
|
},
|
|
{
|
|
Qname: "www.miek.nl.", Qtype: dns.TypeAAAA,
|
|
Answer: []dns.RR{
|
|
test.AAAA("a.miek.nl. 1800 IN AAAA 2a01:7e00::f03c:91ff:fef1:6735"),
|
|
test.CNAME("www.miek.nl. 1800 IN CNAME a.miek.nl."),
|
|
},
|
|
Ns: miekAuth,
|
|
},
|
|
{
|
|
Qname: "miek.nl.", Qtype: dns.TypeSOA,
|
|
Answer: []dns.RR{
|
|
test.SOA("miek.nl. 1800 IN SOA linode.atoom.net. miek.miek.nl. 1282630057 14400 3600 604800 14400"),
|
|
},
|
|
Ns: miekAuth,
|
|
},
|
|
{
|
|
Qname: "miek.nl.", Qtype: dns.TypeAAAA,
|
|
Answer: []dns.RR{
|
|
test.AAAA("miek.nl. 1800 IN AAAA 2a01:7e00::f03c:91ff:fef1:6735"),
|
|
},
|
|
Ns: miekAuth,
|
|
},
|
|
{
|
|
Qname: "mIeK.NL.", Qtype: dns.TypeAAAA,
|
|
Answer: []dns.RR{
|
|
test.AAAA("miek.nl. 1800 IN AAAA 2a01:7e00::f03c:91ff:fef1:6735"),
|
|
},
|
|
Ns: miekAuth,
|
|
},
|
|
{
|
|
Qname: "miek.nl.", Qtype: dns.TypeMX,
|
|
Answer: []dns.RR{
|
|
test.MX("miek.nl. 1800 IN MX 1 aspmx.l.google.com."),
|
|
test.MX("miek.nl. 1800 IN MX 10 aspmx2.googlemail.com."),
|
|
test.MX("miek.nl. 1800 IN MX 10 aspmx3.googlemail.com."),
|
|
test.MX("miek.nl. 1800 IN MX 5 alt1.aspmx.l.google.com."),
|
|
test.MX("miek.nl. 1800 IN MX 5 alt2.aspmx.l.google.com."),
|
|
},
|
|
Ns: miekAuth,
|
|
},
|
|
{
|
|
Qname: "a.miek.nl.", Qtype: dns.TypeSRV,
|
|
Ns: []dns.RR{
|
|
test.SOA("miek.nl. 1800 IN SOA linode.atoom.net. miek.miek.nl. 1282630057 14400 3600 604800 14400"),
|
|
},
|
|
},
|
|
{
|
|
Qname: "b.miek.nl.", Qtype: dns.TypeA,
|
|
Rcode: dns.RcodeNameError,
|
|
Ns: []dns.RR{
|
|
test.SOA("miek.nl. 1800 IN SOA linode.atoom.net. miek.miek.nl. 1282630057 14400 3600 604800 14400"),
|
|
},
|
|
},
|
|
{
|
|
Qname: "srv.miek.nl.", Qtype: dns.TypeSRV,
|
|
Answer: []dns.RR{
|
|
test.SRV("srv.miek.nl. 1800 IN SRV 10 10 8080 a.miek.nl."),
|
|
},
|
|
Extra: []dns.RR{
|
|
test.A("a.miek.nl. 1800 IN A 139.162.196.78"),
|
|
test.AAAA("a.miek.nl. 1800 IN AAAA 2a01:7e00::f03c:91ff:fef1:6735"),
|
|
},
|
|
Ns: miekAuth,
|
|
},
|
|
{
|
|
Qname: "mx.miek.nl.", Qtype: dns.TypeMX,
|
|
Answer: []dns.RR{
|
|
test.MX("mx.miek.nl. 1800 IN MX 10 a.miek.nl."),
|
|
},
|
|
Extra: []dns.RR{
|
|
test.A("a.miek.nl. 1800 IN A 139.162.196.78"),
|
|
test.AAAA("a.miek.nl. 1800 IN AAAA 2a01:7e00::f03c:91ff:fef1:6735"),
|
|
},
|
|
Ns: miekAuth,
|
|
},
|
|
{
|
|
Qname: "asterisk.x.miek.nl.", Qtype: dns.TypeCNAME,
|
|
Answer: []dns.RR{
|
|
test.CNAME("asterisk.x.miek.nl. 1800 IN CNAME www.miek.nl."),
|
|
},
|
|
Ns: miekAuth,
|
|
},
|
|
{
|
|
Qname: "a.b.x.miek.nl.", Qtype: dns.TypeCNAME,
|
|
Rcode: dns.RcodeNameError,
|
|
Ns: []dns.RR{
|
|
test.SOA("miek.nl. 1800 IN SOA linode.atoom.net. miek.miek.nl. 1282630057 14400 3600 604800 14400"),
|
|
},
|
|
},
|
|
{
|
|
Qname: "asterisk.y.miek.nl.", Qtype: dns.TypeA,
|
|
Answer: []dns.RR{
|
|
test.A("asterisk.y.miek.nl. 1800 IN A 139.162.196.78"),
|
|
},
|
|
Ns: miekAuth,
|
|
},
|
|
{
|
|
Qname: "foo.dname.miek.nl.", Qtype: dns.TypeCNAME,
|
|
Answer: []dns.RR{
|
|
test.DNAME("dname.miek.nl. 1800 IN DNAME x.miek.nl."),
|
|
test.CNAME("foo.dname.miek.nl. 1800 IN CNAME foo.x.miek.nl."),
|
|
},
|
|
Ns: miekAuth,
|
|
},
|
|
{
|
|
Qname: "ext-cname.miek.nl.", Qtype: dns.TypeA,
|
|
Answer: []dns.RR{
|
|
test.CNAME("ext-cname.miek.nl. 1800 IN CNAME example.com."),
|
|
},
|
|
Rcode: dns.RcodeServerFailure,
|
|
Ns: miekAuth,
|
|
},
|
|
{
|
|
Qname: "txt.miek.nl.", Qtype: dns.TypeTXT,
|
|
Answer: []dns.RR{
|
|
test.TXT(`txt.miek.nl. 1800 IN TXT "v=spf1 a mx ~all"`),
|
|
},
|
|
Ns: miekAuth,
|
|
},
|
|
{
|
|
Qname: "caa.miek.nl.", Qtype: dns.TypeCAA,
|
|
Answer: []dns.RR{
|
|
test.CAA(`caa.miek.nl. 1800 IN CAA 0 issue letsencrypt.org`),
|
|
},
|
|
Ns: miekAuth,
|
|
},
|
|
}
|
|
|
|
const (
|
|
testzone = "miek.nl."
|
|
testzone1 = "dnssex.nl."
|
|
)
|
|
|
|
func TestLookup(t *testing.T) {
|
|
zone, err := Parse(strings.NewReader(dbMiekNL), testzone, "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{testzone: zone}, Names: []string{testzone}}}
|
|
ctx := context.TODO()
|
|
|
|
for _, tc := range dnsTestCases {
|
|
m := tc.Msg()
|
|
|
|
rec := dnstest.NewRecorder(&test.ResponseWriter{})
|
|
_, err := fm.ServeDNS(ctx, rec, m)
|
|
if err != nil {
|
|
t.Errorf("Expected no error, got %v", err)
|
|
return
|
|
}
|
|
|
|
resp := rec.Msg
|
|
if err := test.SortAndCheck(resp, tc); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestLookupNil(_t *testing.T) {
|
|
fm := File{Next: test.ErrorHandler(), Zones: Zones{Z: map[string]*Zone{testzone: nil}, Names: []string{testzone}}}
|
|
ctx := context.TODO()
|
|
|
|
m := dnsTestCases[0].Msg()
|
|
rec := dnstest.NewRecorder(&test.ResponseWriter{})
|
|
fm.ServeDNS(ctx, rec, m)
|
|
}
|
|
|
|
func TestLookUpNoDataResult(t *testing.T) {
|
|
zone, err := Parse(strings.NewReader(dbMiekNL), testzone, "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{testzone: zone}, Names: []string{testzone}}}
|
|
ctx := context.TODO()
|
|
var noDataTestCases = []test.Case{
|
|
{
|
|
Qname: "a.miek.nl.", Qtype: dns.TypeMX,
|
|
},
|
|
{
|
|
Qname: "wildcard.nodata.miek.nl.", Qtype: dns.TypeMX,
|
|
},
|
|
}
|
|
|
|
for _, tc := range noDataTestCases {
|
|
m := tc.Msg()
|
|
state := request.Request{W: &test.ResponseWriter{}, Req: m}
|
|
_, _, _, result := fm.Z[testzone].Lookup(ctx, state, tc.Qname)
|
|
if result != NoData {
|
|
t.Errorf("Expected result == 3 but result == %v ", result)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestLookupFallthrough(t *testing.T) {
|
|
zone, err := Parse(strings.NewReader(dbMiekNL), testzone, "stdin", 0)
|
|
if err != nil {
|
|
t.Fatalf("Expected no error when reading zone, got %q", err)
|
|
}
|
|
|
|
type FallWithTestCases struct {
|
|
Fall fall.F
|
|
Cases []test.Case
|
|
}
|
|
var fallsWithTestCases = []FallWithTestCases{
|
|
{
|
|
Fall: fall.Root,
|
|
Cases: []test.Case{
|
|
{
|
|
Qname: "doesnotexist.miek.nl.", Qtype: dns.TypeA,
|
|
Rcode: dns.RcodeServerFailure,
|
|
},
|
|
{
|
|
Qname: "x.miek.nl.", Qtype: dns.TypeA,
|
|
Rcode: dns.RcodeServerFailure,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Fall: fall.F{Zones: []string{"a.miek.nl."}},
|
|
Cases: []test.Case{
|
|
{
|
|
Qname: "a.miek.nl.", Qtype: dns.TypeA,
|
|
Rcode: dns.RcodeSuccess,
|
|
},
|
|
{
|
|
Qname: "doesnotexist.miek.nl.", Qtype: dns.TypeA,
|
|
Rcode: dns.RcodeNameError,
|
|
},
|
|
{
|
|
Qname: "passthrough.a.miek.nl.", Qtype: dns.TypeA,
|
|
Rcode: dns.RcodeServerFailure,
|
|
Answer: []dns.RR{},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Fall: fall.F{Zones: []string{"x.miek.nl."}},
|
|
Cases: []test.Case{
|
|
{
|
|
Qname: "x.miek.nl.", Qtype: dns.TypeA,
|
|
Rcode: dns.RcodeServerFailure,
|
|
},
|
|
{
|
|
Qname: "wildcard.x.miek.nl.", Qtype: dns.TypeA,
|
|
Rcode: dns.RcodeSuccess,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, fallWithTestCases := range fallsWithTestCases {
|
|
fm := File{Next: test.ErrorHandler(), Zones: Zones{Z: map[string]*Zone{testzone: zone}, Names: []string{testzone}}, Fall: fallWithTestCases.Fall}
|
|
ctx := context.TODO()
|
|
|
|
for _, tc := range fallWithTestCases.Cases {
|
|
m := tc.Msg()
|
|
|
|
rec := dnstest.NewRecorder(&test.ResponseWriter{})
|
|
_, err := fm.ServeDNS(ctx, rec, m)
|
|
if err != nil {
|
|
t.Errorf("Expected no error, got %v", err)
|
|
return
|
|
}
|
|
|
|
if rec.Msg.Rcode != tc.Rcode {
|
|
t.Errorf("rcode is %q, expected %q", dns.RcodeToString[rec.Msg.Rcode], dns.RcodeToString[tc.Rcode])
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func BenchmarkFileLookup(b *testing.B) {
|
|
zone, err := Parse(strings.NewReader(dbMiekNL), testzone, "stdin", 0)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
fm := File{Next: test.ErrorHandler(), Zones: Zones{Z: map[string]*Zone{testzone: zone}, Names: []string{testzone}}}
|
|
ctx := context.TODO()
|
|
rec := dnstest.NewRecorder(&test.ResponseWriter{})
|
|
|
|
tc := test.Case{
|
|
Qname: "www.miek.nl.", Qtype: dns.TypeA,
|
|
Answer: []dns.RR{
|
|
test.CNAME("www.miek.nl. 1800 IN CNAME a.miek.nl."),
|
|
test.A("a.miek.nl. 1800 IN A 139.162.196.78"),
|
|
},
|
|
}
|
|
|
|
m := tc.Msg()
|
|
|
|
for b.Loop() {
|
|
fm.ServeDNS(ctx, rec, m)
|
|
}
|
|
}
|
|
|
|
const dbMiekNL = `
|
|
$TTL 30M
|
|
$ORIGIN miek.nl.
|
|
@ IN SOA linode.atoom.net. miek.miek.nl. (
|
|
1282630057 ; Serial
|
|
4H ; Refresh
|
|
1H ; Retry
|
|
7D ; Expire
|
|
4H ) ; Negative Cache TTL
|
|
IN NS linode.atoom.net.
|
|
IN NS ns-ext.nlnetlabs.nl.
|
|
IN NS omval.tednet.nl.
|
|
IN NS ext.ns.whyscream.net.
|
|
|
|
IN MX 1 aspmx.l.google.com.
|
|
IN MX 5 alt1.aspmx.l.google.com.
|
|
IN MX 5 alt2.aspmx.l.google.com.
|
|
IN MX 10 aspmx2.googlemail.com.
|
|
IN MX 10 aspmx3.googlemail.com.
|
|
|
|
IN A 139.162.196.78
|
|
IN AAAA 2a01:7e00::f03c:91ff:fef1:6735
|
|
|
|
a IN A 139.162.196.78
|
|
IN AAAA 2a01:7e00::f03c:91ff:fef1:6735
|
|
www IN CNAME a
|
|
archive IN CNAME a
|
|
*.x IN CNAME www
|
|
b.x IN CNAME a
|
|
*.y IN A 139.162.196.78
|
|
dname IN DNAME x
|
|
|
|
srv IN SRV 10 10 8080 a.miek.nl.
|
|
mx IN MX 10 a.miek.nl.
|
|
|
|
txt IN TXT "v=spf1 a mx ~all"
|
|
caa IN CAA 0 issue letsencrypt.org
|
|
*.nodata IN A 139.162.196.79
|
|
ext-cname IN CNAME example.com.`
|
|
|
|
var additionalAuth = []dns.RR{
|
|
test.NS("example.org. 1800 IN NS ns.example.org."),
|
|
}
|
|
|
|
var additionalTestCases = []test.Case{
|
|
{
|
|
// Two MX records that only differ in preference share a target. Its addresses
|
|
// belong in the additional section once.
|
|
Qname: "mx.example.org.", Qtype: dns.TypeMX,
|
|
Answer: []dns.RR{
|
|
test.MX("mx.example.org. 1800 IN MX 10 host.example.org."),
|
|
test.MX("mx.example.org. 1800 IN MX 20 host.example.org."),
|
|
},
|
|
Ns: additionalAuth,
|
|
Extra: []dns.RR{
|
|
test.A("host.example.org. 1800 IN A 192.0.2.10"),
|
|
test.AAAA("host.example.org. 1800 IN AAAA 2001:db8::10"),
|
|
},
|
|
},
|
|
{
|
|
// SRV runs through the same additional processing.
|
|
Qname: "srv.example.org.", Qtype: dns.TypeSRV,
|
|
Answer: []dns.RR{
|
|
test.SRV("srv.example.org. 1800 IN SRV 10 50 8080 host.example.org."),
|
|
test.SRV("srv.example.org. 1800 IN SRV 20 50 8080 host.example.org."),
|
|
},
|
|
Ns: additionalAuth,
|
|
Extra: []dns.RR{
|
|
test.A("host.example.org. 1800 IN A 192.0.2.10"),
|
|
test.AAAA("host.example.org. 1800 IN AAAA 2001:db8::10"),
|
|
},
|
|
},
|
|
{
|
|
// Distinct targets must each still be resolved.
|
|
Qname: "two.example.org.", Qtype: dns.TypeMX,
|
|
Answer: []dns.RR{
|
|
test.MX("two.example.org. 1800 IN MX 10 host.example.org."),
|
|
test.MX("two.example.org. 1800 IN MX 20 other.example.org."),
|
|
},
|
|
Ns: additionalAuth,
|
|
Extra: []dns.RR{
|
|
test.A("host.example.org. 1800 IN A 192.0.2.10"),
|
|
test.AAAA("host.example.org. 1800 IN AAAA 2001:db8::10"),
|
|
test.A("other.example.org. 1800 IN A 192.0.2.20"),
|
|
test.AAAA("other.example.org. 1800 IN AAAA 2001:db8::20"),
|
|
},
|
|
},
|
|
{
|
|
// An ordinary CNAME chased to an SRV still needs the target's glue (#6628).
|
|
Qname: "cname-srv.example.org.", Qtype: dns.TypeSRV,
|
|
Answer: []dns.RR{
|
|
test.CNAME("cname-srv.example.org. 1800 IN CNAME srv.example.org."),
|
|
test.SRV("srv.example.org. 1800 IN SRV 10 50 8080 host.example.org."),
|
|
test.SRV("srv.example.org. 1800 IN SRV 20 50 8080 host.example.org."),
|
|
},
|
|
Ns: additionalAuth,
|
|
Extra: []dns.RR{
|
|
test.A("host.example.org. 1800 IN A 192.0.2.10"),
|
|
test.AAAA("host.example.org. 1800 IN AAAA 2001:db8::10"),
|
|
},
|
|
},
|
|
{
|
|
// A wildcard CNAME chased to an SRV.
|
|
Qname: "foo.wild.example.org.", Qtype: dns.TypeSRV,
|
|
Answer: []dns.RR{
|
|
test.CNAME("foo.wild.example.org. 1800 IN CNAME srv.example.org."),
|
|
test.SRV("srv.example.org. 1800 IN SRV 10 50 8080 host.example.org."),
|
|
test.SRV("srv.example.org. 1800 IN SRV 20 50 8080 host.example.org."),
|
|
},
|
|
Ns: additionalAuth,
|
|
Extra: []dns.RR{
|
|
test.A("host.example.org. 1800 IN A 192.0.2.10"),
|
|
test.AAAA("host.example.org. 1800 IN AAAA 2001:db8::10"),
|
|
},
|
|
},
|
|
{
|
|
// A DNAME substitution landing on an SRV (#6628).
|
|
Qname: "srv.dname.example.org.", Qtype: dns.TypeSRV,
|
|
Answer: []dns.RR{
|
|
test.DNAME("dname.example.org. 1800 IN DNAME dsub.example.org."),
|
|
test.CNAME("srv.dname.example.org. 1800 IN CNAME srv.dsub.example.org."),
|
|
test.SRV("srv.dsub.example.org. 1800 IN SRV 10 50 8080 host.example.org."),
|
|
},
|
|
Ns: additionalAuth,
|
|
Extra: []dns.RR{
|
|
test.A("host.example.org. 1800 IN A 192.0.2.10"),
|
|
test.AAAA("host.example.org. 1800 IN AAAA 2001:db8::10"),
|
|
},
|
|
},
|
|
}
|
|
|
|
func TestAdditionalSectionDeduplication(t *testing.T) {
|
|
zone, err := Parse(strings.NewReader(dbAdditionalExample), testAdditionalOrigin, "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{testAdditionalOrigin: zone}, Names: []string{testAdditionalOrigin}}}
|
|
ctx := context.TODO()
|
|
|
|
for _, tc := range additionalTestCases {
|
|
m := tc.Msg()
|
|
|
|
rec := dnstest.NewRecorder(&test.ResponseWriter{})
|
|
_, err := fm.ServeDNS(ctx, rec, m)
|
|
if err != nil {
|
|
t.Errorf("Expected no error for %q/%d, got %v", tc.Qname, tc.Qtype, err)
|
|
continue
|
|
}
|
|
|
|
resp := rec.Msg
|
|
if err := test.SortAndCheck(resp, tc); err != nil {
|
|
t.Errorf("Test %q/%d: %v", tc.Qname, tc.Qtype, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestAdditionalSectionDeduplicationMixedCase(t *testing.T) {
|
|
// SRV targets are not lowercased on insert, so one target can reach additional
|
|
// processing under two spellings. The zone's tree matches names case-insensitively,
|
|
// so both resolve to the same addresses and those belong in the response once.
|
|
zone, err := Parse(strings.NewReader(dbAdditionalExample), testAdditionalOrigin, "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{testAdditionalOrigin: zone}, Names: []string{testAdditionalOrigin}}}
|
|
ctx := context.TODO()
|
|
|
|
m := new(dns.Msg)
|
|
m.SetQuestion("mixed.example.org.", dns.TypeSRV)
|
|
|
|
rec := dnstest.NewRecorder(&test.ResponseWriter{})
|
|
if _, err := fm.ServeDNS(ctx, rec, m); err != nil {
|
|
t.Fatalf("Expected no error, got %v", err)
|
|
}
|
|
|
|
resp := rec.Msg
|
|
if len(resp.Answer) != 2 {
|
|
t.Fatalf("Expected 2 answers, got %d", len(resp.Answer))
|
|
}
|
|
if len(resp.Extra) != 2 {
|
|
t.Errorf("Expected 2 additional records (one A, one AAAA), got %d: %v", len(resp.Extra), resp.Extra)
|
|
}
|
|
}
|
|
|
|
const testAdditionalOrigin = "example.org."
|
|
|
|
const dbAdditionalExample = `
|
|
$TTL 30M
|
|
$ORIGIN example.org.
|
|
@ IN SOA ns.example.org. admin.example.org. (
|
|
2024010100 ; serial
|
|
14400 ; refresh (4 hours)
|
|
3600 ; retry (1 hour)
|
|
604800 ; expire (1 week)
|
|
14400 ; minimum (4 hours)
|
|
)
|
|
IN NS ns.example.org.
|
|
|
|
ns IN A 192.0.2.1
|
|
|
|
; The target shared by the records below.
|
|
host IN A 192.0.2.10
|
|
IN AAAA 2001:db8::10
|
|
|
|
; A second, distinct target.
|
|
other IN A 192.0.2.20
|
|
IN AAAA 2001:db8::20
|
|
|
|
; Two MX records differing only in preference, pointing at one target.
|
|
mx IN MX 10 host.example.org.
|
|
IN MX 20 host.example.org.
|
|
|
|
; Two SRV records pointing at one target.
|
|
srv IN SRV 10 50 8080 host.example.org.
|
|
IN SRV 20 50 8080 host.example.org.
|
|
|
|
; The same target, spelled differently. SRV targets are not normalized on insert.
|
|
mixed IN SRV 10 50 8080 host.example.org.
|
|
IN SRV 20 50 8080 HOST.EXAMPLE.ORG.
|
|
|
|
; Two MX records with distinct targets.
|
|
two IN MX 10 host.example.org.
|
|
IN MX 20 other.example.org.
|
|
|
|
; A CNAME resolving to an SRV: the ordinary-CNAME chase must still add glue.
|
|
cname-srv IN CNAME srv.example.org.
|
|
|
|
; A wildcard CNAME resolving to an SRV.
|
|
*.wild IN CNAME srv.example.org.
|
|
|
|
; A DNAME whose subtree holds an SRV: the DNAME chase must add glue too.
|
|
dname IN DNAME dsub.example.org.
|
|
srv.dsub IN SRV 10 50 8080 host.example.org.
|
|
`
|