Qualify relative RDATA names in the zone-file parser
A domain name in the RDATA section written without a trailing dot is relative to the zone origin (RFC 1035 §5.1), so "www CNAME host" in example.com. means host.example.com. The qualifier ran on the record after dns.NewRR had already resolved every RDATA name against the root, which turns "host" into "host." and makes the two indistinguishable -- relative() saw the trailing dot and left it alone. Every relative CNAME, NS, MX, PTR, SRV, NAPTR, SOA and SVCB target therefore pointed at the DNS root, which showed up as a local zone answering a CNAME with "host." and the alias target holding no local answer. Qualification now happens in assemble on the token stream, before the record is built, using a table of the RDATA positions that hold a name per type; names that already end in a dot stay absolute, so the RPZ targets "." and "rpz-drop." and the null MX targets are unaffected. Fix three wrong expectations in the localzone tests while here. The loop fixture was built with dns.NewRR on "alias.example.com", which cannot parse because the RR library wants a TTL and class column, so the expected record now spells them out. The origin-derivation fixture used "a" as an owner name, and a leading token that names an RR type reads as an omitted owner, which has no previous owner to inherit on the first line of a file; the owner is now a word. The merge test counted the SOA, but it is zone metadata rather than a queryable record, so two files contribute three records. The holder race test also looked up a name from the base zone while the holder was serving a store compiled from other.test., which no answer could satisfy; it now accepts either store's data.
This commit is contained in:
1 parent
ad9989b28c
commit
a5e54c09df
4 files changed
+1043
-49
No files matched your search
@@ -609,6 +609,62 @@ func TestParseOriginDirective(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
// A domain name in the RDATA section that is written without a trailing dot is
|
||||
// relative to the zone origin (RFC 1035 §5.1). The qualification has to happen
|
||||
// on the token stream, before dns.NewRR: the library resolves RDATA names
|
||||
// against the root, so afterwards "host" and "host." are indistinguishable and
|
||||
// a relative CNAME target would silently point at the root instead.
|
||||
func TestParseRelativeRdata(t *testing.T) {
|
||||
// The owners are deliberately not RR type names: a leading token that names
|
||||
// a type reads as an omitted owner, as assemble documents.
|
||||
z := mustParse(t, `$ORIGIN example.com.
|
||||
cn 300 IN CNAME host
|
||||
ns1sub 300 IN NS ns1.sub
|
||||
ptral 300 IN PTR host
|
||||
mail 300 IN MX 10 mailhost
|
||||
srvone 300 IN SRV 0 1 5060 sip
|
||||
napone 300 IN NAPTR 100 50 "s" "http+I2R" "" _http._tcp
|
||||
svcone 300 IN SVCB 1 _sip._tcp
|
||||
zone1 300 IN SOA ns1 hostmaster 1 3600 600 604800 300
|
||||
abs 300 IN CNAME host.other.test.
|
||||
nullmx 300 IN MX 10 .
|
||||
txtone 300 IN TXT "host"
|
||||
`, Options{Origin: "example.com."})
|
||||
checkSummary(t, z, []string{
|
||||
`2 cn.example.com. 300 IN CNAME host.example.com.`,
|
||||
`3 ns1sub.example.com. 300 IN NS ns1.sub.example.com.`,
|
||||
`4 ptral.example.com. 300 IN PTR host.example.com.`,
|
||||
`5 mail.example.com. 300 IN MX 10 mailhost.example.com.`,
|
||||
`6 srvone.example.com. 300 IN SRV 0 1 5060 sip.example.com.`,
|
||||
`7 napone.example.com. 300 IN NAPTR 100 50 "s" "http+I2R" "" _http._tcp.example.com.`,
|
||||
`8 svcone.example.com. 300 IN SVCB 1 _sip._tcp.example.com.`,
|
||||
`9 zone1.example.com. 300 IN SOA ns1.example.com. hostmaster.example.com. 1 3600 600 604800 300`,
|
||||
`10 abs.example.com. 300 IN CNAME host.other.test.`,
|
||||
`11 nullmx.example.com. 300 IN MX 10 .`,
|
||||
`12 txtone.example.com. 300 IN TXT "host"`,
|
||||
})
|
||||
}
|
||||
|
||||
// Each line is assembled on its own and fold continues a statement only while
|
||||
// parentheses are open, so a record never swallows the line after it -- whatever
|
||||
// its token count is.
|
||||
func TestParseRecordsDoNotRunTogether(t *testing.T) {
|
||||
z := mustParse(t, `$ORIGIN example.com.
|
||||
ns1 A 192.0.2.53
|
||||
note TXT "hello world"
|
||||
@ IN SOA ns1 hostmaster 1 3600 600 604800 300
|
||||
mail MX 10 mxhost
|
||||
`, Options{})
|
||||
if got, want := summaryNoTTL(t, z), []string{
|
||||
`2 ns1.example.com. IN A 192.0.2.53`,
|
||||
`3 note.example.com. IN TXT "hello world"`,
|
||||
`4 example.com. IN SOA ns1.example.com. hostmaster.example.com. 1 3600 600 604800 300`,
|
||||
`5 mail.example.com. IN MX 10 mxhost.example.com.`,
|
||||
}; !slices.Equal(got, want) {
|
||||
t.Errorf("records mismatch\n got: %q\nwant: %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseClassHandling(t *testing.T) {
|
||||
z := mustParse(t, `one IN A 192.0.2.1
|
||||
two in A 192.0.2.2
|
||||
|
||||
Reference in new issue
Block a user