Use an interface method for parsing zone file records (#886)
* Eliminate Variable bool from parserFunc Instead we now check whether the last token read from the zlexer was a zNewline or zEOF. The error check above should be tripped for any record that ends prematurely. * Use an interface method for parsing zone file records * Prevent panic in TestOmittedTTL if no regexp match * Move slurpRemainder into fixed length parse functions This is consistent with the original logic in setRR and avoids potential edge cases. * Parse synthetic records according to RFC 3597 These records lack a presentation format and cannot be parsed otherwise. This behaviour is consistent with how this previously operated.
This commit is contained in:
parent
44a8c5f8ba
commit
db3d0ce13b
9
dns.go
9
dns.go
|
@ -50,6 +50,11 @@ type RR interface {
|
||||||
// This will only be called on a new and empty RR type with only the header populated. It
|
// This will only be called on a new and empty RR type with only the header populated. It
|
||||||
// will only be called if the record's RDATA is non-empty.
|
// will only be called if the record's RDATA is non-empty.
|
||||||
unpack(msg []byte, off int) (off1 int, err error)
|
unpack(msg []byte, off int) (off1 int, err error)
|
||||||
|
|
||||||
|
// parse parses an RR from zone file format.
|
||||||
|
//
|
||||||
|
// This will only be called on a new and empty RR type with only the header populated.
|
||||||
|
parse(c *zlexer, origin, file string) *ParseError
|
||||||
}
|
}
|
||||||
|
|
||||||
// RR_Header is the header all DNS resource records share.
|
// RR_Header is the header all DNS resource records share.
|
||||||
|
@ -97,6 +102,10 @@ func (h *RR_Header) unpack(msg []byte, off int) (int, error) {
|
||||||
panic("dns: internal error: unpack should never be called on RR_Header")
|
panic("dns: internal error: unpack should never be called on RR_Header")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *RR_Header) parse(c *zlexer, origin, file string) *ParseError {
|
||||||
|
panic("dns: internal error: parse should never be called on RR_Header")
|
||||||
|
}
|
||||||
|
|
||||||
// ToRFC3597 converts a known RR to the unknown RR representation from RFC 3597.
|
// ToRFC3597 converts a known RR to the unknown RR representation from RFC 3597.
|
||||||
func (rr *RFC3597) ToRFC3597(r RR) error {
|
func (rr *RFC3597) ToRFC3597(r RR) error {
|
||||||
buf := make([]byte, Len(r)*2)
|
buf := make([]byte, Len(r)*2)
|
||||||
|
|
4
edns.go
4
edns.go
|
@ -88,6 +88,10 @@ func (rr *OPT) len(off int, compression map[string]struct{}) int {
|
||||||
return l
|
return l
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (rr *OPT) parse(c *zlexer, origin, file string) *ParseError {
|
||||||
|
panic("dns: internal error: parse should never be called on OPT")
|
||||||
|
}
|
||||||
|
|
||||||
// return the old value -> delete SetVersion?
|
// return the old value -> delete SetVersion?
|
||||||
|
|
||||||
// Version returns the EDNS version used. Only zero is defined.
|
// Version returns the EDNS version used. Only zero is defined.
|
||||||
|
|
|
@ -341,7 +341,7 @@ func TestParseDirectiveMisc(t *testing.T) {
|
||||||
|
|
||||||
func TestNSEC(t *testing.T) {
|
func TestNSEC(t *testing.T) {
|
||||||
nsectests := map[string]string{
|
nsectests := map[string]string{
|
||||||
"nl. IN NSEC3PARAM 1 0 5 30923C44C6CBBB8F": "nl.\t3600\tIN\tNSEC3PARAM\t1 0 5 30923C44C6CBBB8F",
|
"nl. IN NSEC3PARAM 1 0 5 30923C44C6CBBB8F": "nl.\t3600\tIN\tNSEC3PARAM\t1 0 5 30923C44C6CBBB8F",
|
||||||
"p2209hipbpnm681knjnu0m1febshlv4e.nl. IN NSEC3 1 1 5 30923C44C6CBBB8F P90DG1KE8QEAN0B01613LHQDG0SOJ0TA NS SOA TXT RRSIG DNSKEY NSEC3PARAM": "p2209hipbpnm681knjnu0m1febshlv4e.nl.\t3600\tIN\tNSEC3\t1 1 5 30923C44C6CBBB8F P90DG1KE8QEAN0B01613LHQDG0SOJ0TA NS SOA TXT RRSIG DNSKEY NSEC3PARAM",
|
"p2209hipbpnm681knjnu0m1febshlv4e.nl. IN NSEC3 1 1 5 30923C44C6CBBB8F P90DG1KE8QEAN0B01613LHQDG0SOJ0TA NS SOA TXT RRSIG DNSKEY NSEC3PARAM": "p2209hipbpnm681knjnu0m1febshlv4e.nl.\t3600\tIN\tNSEC3\t1 1 5 30923C44C6CBBB8F P90DG1KE8QEAN0B01613LHQDG0SOJ0TA NS SOA TXT RRSIG DNSKEY NSEC3PARAM",
|
||||||
"localhost.dnssex.nl. IN NSEC www.dnssex.nl. A RRSIG NSEC": "localhost.dnssex.nl.\t3600\tIN\tNSEC\twww.dnssex.nl. A RRSIG NSEC",
|
"localhost.dnssex.nl. IN NSEC www.dnssex.nl. A RRSIG NSEC": "localhost.dnssex.nl.\t3600\tIN\tNSEC\twww.dnssex.nl. A RRSIG NSEC",
|
||||||
"localhost.dnssex.nl. IN NSEC www.dnssex.nl. A RRSIG NSEC TYPE65534": "localhost.dnssex.nl.\t3600\tIN\tNSEC\twww.dnssex.nl. A RRSIG NSEC TYPE65534",
|
"localhost.dnssex.nl. IN NSEC www.dnssex.nl. A RRSIG NSEC TYPE65534": "localhost.dnssex.nl.\t3600\tIN\tNSEC\twww.dnssex.nl. A RRSIG NSEC TYPE65534",
|
||||||
|
@ -398,16 +398,16 @@ func TestQuotes(t *testing.T) {
|
||||||
`t.example.com. IN TXT "a bc"`: "t.example.com.\t3600\tIN\tTXT\t\"a bc\"",
|
`t.example.com. IN TXT "a bc"`: "t.example.com.\t3600\tIN\tTXT\t\"a bc\"",
|
||||||
`t.example.com. IN TXT "a
|
`t.example.com. IN TXT "a
|
||||||
bc"`: "t.example.com.\t3600\tIN\tTXT\t\"a\\010 bc\"",
|
bc"`: "t.example.com.\t3600\tIN\tTXT\t\"a\\010 bc\"",
|
||||||
`t.example.com. IN TXT ""`: "t.example.com.\t3600\tIN\tTXT\t\"\"",
|
`t.example.com. IN TXT ""`: "t.example.com.\t3600\tIN\tTXT\t\"\"",
|
||||||
`t.example.com. IN TXT "a"`: "t.example.com.\t3600\tIN\tTXT\t\"a\"",
|
`t.example.com. IN TXT "a"`: "t.example.com.\t3600\tIN\tTXT\t\"a\"",
|
||||||
`t.example.com. IN TXT "aa"`: "t.example.com.\t3600\tIN\tTXT\t\"aa\"",
|
`t.example.com. IN TXT "aa"`: "t.example.com.\t3600\tIN\tTXT\t\"aa\"",
|
||||||
`t.example.com. IN TXT "aaa" ;`: "t.example.com.\t3600\tIN\tTXT\t\"aaa\"",
|
`t.example.com. IN TXT "aaa" ;`: "t.example.com.\t3600\tIN\tTXT\t\"aaa\"",
|
||||||
`t.example.com. IN TXT "abc" "DEF"`: "t.example.com.\t3600\tIN\tTXT\t\"abc\" \"DEF\"",
|
`t.example.com. IN TXT "abc" "DEF"`: "t.example.com.\t3600\tIN\tTXT\t\"abc\" \"DEF\"",
|
||||||
`t.example.com. IN TXT "abc" ( "DEF" )`: "t.example.com.\t3600\tIN\tTXT\t\"abc\" \"DEF\"",
|
`t.example.com. IN TXT "abc" ( "DEF" )`: "t.example.com.\t3600\tIN\tTXT\t\"abc\" \"DEF\"",
|
||||||
`t.example.com. IN TXT aaa ;`: "t.example.com.\t3600\tIN\tTXT\t\"aaa\"",
|
`t.example.com. IN TXT aaa ;`: "t.example.com.\t3600\tIN\tTXT\t\"aaa\"",
|
||||||
`t.example.com. IN TXT aaa aaa;`: "t.example.com.\t3600\tIN\tTXT\t\"aaa\" \"aaa\"",
|
`t.example.com. IN TXT aaa aaa;`: "t.example.com.\t3600\tIN\tTXT\t\"aaa\" \"aaa\"",
|
||||||
`t.example.com. IN TXT aaa aaa`: "t.example.com.\t3600\tIN\tTXT\t\"aaa\" \"aaa\"",
|
`t.example.com. IN TXT aaa aaa`: "t.example.com.\t3600\tIN\tTXT\t\"aaa\" \"aaa\"",
|
||||||
`t.example.com. IN TXT aaa`: "t.example.com.\t3600\tIN\tTXT\t\"aaa\"",
|
`t.example.com. IN TXT aaa`: "t.example.com.\t3600\tIN\tTXT\t\"aaa\"",
|
||||||
"cid.urn.arpa. NAPTR 100 50 \"s\" \"z3950+I2L+I2C\" \"\" _z3950._tcp.gatech.edu.": "cid.urn.arpa.\t3600\tIN\tNAPTR\t100 50 \"s\" \"z3950+I2L+I2C\" \"\" _z3950._tcp.gatech.edu.",
|
"cid.urn.arpa. NAPTR 100 50 \"s\" \"z3950+I2L+I2C\" \"\" _z3950._tcp.gatech.edu.": "cid.urn.arpa.\t3600\tIN\tNAPTR\t100 50 \"s\" \"z3950+I2L+I2C\" \"\" _z3950._tcp.gatech.edu.",
|
||||||
"cid.urn.arpa. NAPTR 100 50 \"s\" \"rcds+I2C\" \"\" _rcds._udp.gatech.edu.": "cid.urn.arpa.\t3600\tIN\tNAPTR\t100 50 \"s\" \"rcds+I2C\" \"\" _rcds._udp.gatech.edu.",
|
"cid.urn.arpa. NAPTR 100 50 \"s\" \"rcds+I2C\" \"\" _rcds._udp.gatech.edu.": "cid.urn.arpa.\t3600\tIN\tNAPTR\t100 50 \"s\" \"rcds+I2C\" \"\" _rcds._udp.gatech.edu.",
|
||||||
"cid.urn.arpa. NAPTR 100 50 \"s\" \"http+I2L+I2C+I2R\" \"\" _http._tcp.gatech.edu.": "cid.urn.arpa.\t3600\tIN\tNAPTR\t100 50 \"s\" \"http+I2L+I2C+I2R\" \"\" _http._tcp.gatech.edu.",
|
"cid.urn.arpa. NAPTR 100 50 \"s\" \"http+I2L+I2C+I2R\" \"\" _http._tcp.gatech.edu.": "cid.urn.arpa.\t3600\tIN\tNAPTR\t100 50 \"s\" \"http+I2L+I2C+I2R\" \"\" _http._tcp.gatech.edu.",
|
||||||
|
@ -543,6 +543,10 @@ example.com. DNAME 10 ; TTL=314 after second $TTL
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
expected := reCaseFromComment.FindStringSubmatch(record.Comment)
|
expected := reCaseFromComment.FindStringSubmatch(record.Comment)
|
||||||
|
if len(expected) != 3 {
|
||||||
|
t.Errorf("regexp didn't match for record %d", i)
|
||||||
|
continue
|
||||||
|
}
|
||||||
expectedTTL, _ := strconv.ParseUint(expected[1], 10, 32)
|
expectedTTL, _ := strconv.ParseUint(expected[1], 10, 32)
|
||||||
ttl := record.RR.Header().Ttl
|
ttl := record.RR.Header().Ttl
|
||||||
if ttl != uint32(expectedTTL) {
|
if ttl != uint32(expectedTTL) {
|
||||||
|
|
52
privaterr.go
52
privaterr.go
|
@ -86,6 +86,29 @@ func (r *PrivateRR) unpack(msg []byte, off int) (int, error) {
|
||||||
return off, err
|
return off, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *PrivateRR) parse(c *zlexer, origin, file string) *ParseError {
|
||||||
|
var l lex
|
||||||
|
text := make([]string, 0, 2) // could be 0..N elements, median is probably 1
|
||||||
|
Fetch:
|
||||||
|
for {
|
||||||
|
// TODO(miek): we could also be returning _QUOTE, this might or might not
|
||||||
|
// be an issue (basically parsing TXT becomes hard)
|
||||||
|
switch l, _ = c.Next(); l.value {
|
||||||
|
case zNewline, zEOF:
|
||||||
|
break Fetch
|
||||||
|
case zString:
|
||||||
|
text = append(text, l.token)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err := r.Data.Parse(text)
|
||||||
|
if err != nil {
|
||||||
|
return &ParseError{file, err.Error(), l}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// PrivateHandle registers a private resource record type. It requires
|
// PrivateHandle registers a private resource record type. It requires
|
||||||
// string and numeric representation of private RR type and generator function as argument.
|
// string and numeric representation of private RR type and generator function as argument.
|
||||||
func PrivateHandle(rtypestr string, rtype uint16, generator func() PrivateRdata) {
|
func PrivateHandle(rtypestr string, rtype uint16, generator func() PrivateRdata) {
|
||||||
|
@ -94,34 +117,6 @@ func PrivateHandle(rtypestr string, rtype uint16, generator func() PrivateRdata)
|
||||||
TypeToRR[rtype] = func() RR { return &PrivateRR{RR_Header{}, generator()} }
|
TypeToRR[rtype] = func() RR { return &PrivateRR{RR_Header{}, generator()} }
|
||||||
TypeToString[rtype] = rtypestr
|
TypeToString[rtype] = rtypestr
|
||||||
StringToType[rtypestr] = rtype
|
StringToType[rtypestr] = rtype
|
||||||
|
|
||||||
setPrivateRR := func(h RR_Header, c *zlexer, o, f string) (RR, *ParseError) {
|
|
||||||
rr := mkPrivateRR(h.Rrtype)
|
|
||||||
rr.Hdr = h
|
|
||||||
|
|
||||||
var l lex
|
|
||||||
text := make([]string, 0, 2) // could be 0..N elements, median is probably 1
|
|
||||||
Fetch:
|
|
||||||
for {
|
|
||||||
// TODO(miek): we could also be returning _QUOTE, this might or might not
|
|
||||||
// be an issue (basically parsing TXT becomes hard)
|
|
||||||
switch l, _ = c.Next(); l.value {
|
|
||||||
case zNewline, zEOF:
|
|
||||||
break Fetch
|
|
||||||
case zString:
|
|
||||||
text = append(text, l.token)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
err := rr.Data.Parse(text)
|
|
||||||
if err != nil {
|
|
||||||
return nil, &ParseError{f, err.Error(), l}
|
|
||||||
}
|
|
||||||
|
|
||||||
return rr, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
typeToparserFunc[rtype] = parserFunc{setPrivateRR, true}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrivateHandleRemove removes definitions required to support private RR type.
|
// PrivateHandleRemove removes definitions required to support private RR type.
|
||||||
|
@ -130,7 +125,6 @@ func PrivateHandleRemove(rtype uint16) {
|
||||||
if ok {
|
if ok {
|
||||||
delete(TypeToRR, rtype)
|
delete(TypeToRR, rtype)
|
||||||
delete(TypeToString, rtype)
|
delete(TypeToString, rtype)
|
||||||
delete(typeToparserFunc, rtype)
|
|
||||||
delete(StringToType, rtypestr)
|
delete(StringToType, rtypestr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
1051
scan_rr.go
1051
scan_rr.go
File diff suppressed because it is too large
Load Diff
4
tsig.go
4
tsig.go
|
@ -54,6 +54,10 @@ func (rr *TSIG) String() string {
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (rr *TSIG) parse(c *zlexer, origin, file string) *ParseError {
|
||||||
|
panic("dns: internal error: parse should never be called on TSIG")
|
||||||
|
}
|
||||||
|
|
||||||
// The following values must be put in wireformat, so that the MAC can be calculated.
|
// The following values must be put in wireformat, so that the MAC can be calculated.
|
||||||
// RFC 2845, section 3.4.2. TSIG Variables.
|
// RFC 2845, section 3.4.2. TSIG Variables.
|
||||||
type tsigWireFmt struct {
|
type tsigWireFmt struct {
|
||||||
|
|
8
types.go
8
types.go
|
@ -238,6 +238,10 @@ type ANY struct {
|
||||||
|
|
||||||
func (rr *ANY) String() string { return rr.Hdr.String() }
|
func (rr *ANY) String() string { return rr.Hdr.String() }
|
||||||
|
|
||||||
|
func (rr *ANY) parse(c *zlexer, origin, file string) *ParseError {
|
||||||
|
panic("dns: internal error: parse should never be called on ANY")
|
||||||
|
}
|
||||||
|
|
||||||
// NULL RR. See RFC 1035.
|
// NULL RR. See RFC 1035.
|
||||||
type NULL struct {
|
type NULL struct {
|
||||||
Hdr RR_Header
|
Hdr RR_Header
|
||||||
|
@ -249,6 +253,10 @@ func (rr *NULL) String() string {
|
||||||
return ";" + rr.Hdr.String() + rr.Data
|
return ";" + rr.Hdr.String() + rr.Data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (rr *NULL) parse(c *zlexer, origin, file string) *ParseError {
|
||||||
|
panic("dns: internal error: parse should never be called on NULL")
|
||||||
|
}
|
||||||
|
|
||||||
// CNAME RR. See RFC 1034.
|
// CNAME RR. See RFC 1034.
|
||||||
type CNAME struct {
|
type CNAME struct {
|
||||||
Hdr RR_Header
|
Hdr RR_Header
|
||||||
|
|
Loading…
Reference in New Issue