2010-12-30 12:42:52 +00:00
|
|
|
package dns
|
|
|
|
|
Support parsing known RR types in RFC 3597 format (#1211)
* Support parsing known RR types in RFC 3597 format
This is the format used for "Unknown DNS Resource Records", but it's
also useful to support parsing known RR types in this way.
RFC 3597 says:
An implementation MAY also choose to represent some RRs of known type
using the above generic representations for the type, class and/or
RDATA, which carries the benefit of making the resulting master file
portable to servers where these types are unknown. Using the generic
representation for the RDATA of an RR of known type can also be
useful in the case of an RR type where the text format varies
depending on a version, protocol, or similar field (or several)
embedded in the RDATA when such a field has a value for which no text
format is known, e.g., a LOC RR [RFC1876] with a VERSION other than
0.
Even though an RR of known type represented in the \# format is
effectively treated as an unknown type for the purpose of parsing the
RDATA text representation, all further processing by the server MUST
treat it as a known type and take into account any applicable type-
specific rules regarding compression, canonicalization, etc.
* Correct mistakes in TestZoneParserAddressAAAA
This was spotted when writing TestParseKnownRRAsRFC3597.
* Eliminate canParseAsRR
This has the advantage that concrete types will now be returned for
parsed ANY, NULL, OPT and TSIG records.
* Expand TestDynamicUpdateParsing for RFC 3597
This ensures we're properly handling empty RDATA for RFC 3597 parsed
records.
2021-01-30 13:05:25 +00:00
|
|
|
import (
|
|
|
|
"encoding/hex"
|
|
|
|
"strconv"
|
|
|
|
)
|
2010-12-30 12:42:52 +00:00
|
|
|
|
2011-02-28 09:42:03 +00:00
|
|
|
const (
|
2016-06-13 18:44:38 +00:00
|
|
|
year68 = 1 << 31 // For RFC1982 (Serial Arithmetic) calculations in 32 bits.
|
|
|
|
defaultTtl = 3600 // Default internal TTL.
|
|
|
|
|
2017-11-03 16:15:35 +00:00
|
|
|
// DefaultMsgSize is the standard default for messages larger than 512 bytes.
|
|
|
|
DefaultMsgSize = 4096
|
|
|
|
// MinMsgSize is the minimal size of a DNS packet.
|
|
|
|
MinMsgSize = 512
|
|
|
|
// MaxMsgSize is the largest possible DNS packet.
|
|
|
|
MaxMsgSize = 65535
|
2011-02-28 09:42:03 +00:00
|
|
|
)
|
2010-12-30 12:42:52 +00:00
|
|
|
|
2016-06-13 18:44:38 +00:00
|
|
|
// Error represents a DNS error.
|
2013-06-20 06:25:29 +00:00
|
|
|
type Error struct{ err string }
|
2011-01-01 17:47:38 +00:00
|
|
|
|
2011-11-02 22:06:54 +00:00
|
|
|
func (e *Error) Error() string {
|
2011-01-14 10:57:28 +00:00
|
|
|
if e == nil {
|
2012-04-18 12:06:10 +00:00
|
|
|
return "dns: <nil>"
|
2011-01-14 10:57:28 +00:00
|
|
|
}
|
2013-06-20 06:25:29 +00:00
|
|
|
return "dns: " + e.err
|
2011-01-01 17:47:38 +00:00
|
|
|
}
|
|
|
|
|
2012-02-15 22:34:41 +00:00
|
|
|
// An RR represents a resource record.
|
2010-12-30 12:42:52 +00:00
|
|
|
type RR interface {
|
2012-02-19 17:36:59 +00:00
|
|
|
// Header returns the header of an resource record. The header contains
|
|
|
|
// everything up to the rdata.
|
2010-12-30 19:50:31 +00:00
|
|
|
Header() *RR_Header
|
2012-02-19 17:36:59 +00:00
|
|
|
// String returns the text representation of the resource record.
|
2010-12-30 19:50:31 +00:00
|
|
|
String() string
|
2016-06-13 18:44:38 +00:00
|
|
|
|
2013-02-09 07:35:17 +00:00
|
|
|
// copy returns a copy of the RR
|
|
|
|
copy() RR
|
2018-11-29 23:33:41 +00:00
|
|
|
|
|
|
|
// len returns the length (in octets) of the compressed or uncompressed RR in wire format.
|
|
|
|
//
|
|
|
|
// If compression is nil, the uncompressed size will be returned, otherwise the compressed
|
|
|
|
// size will be returned and domain names will be added to the map for future compression.
|
|
|
|
len(off int, compression map[string]struct{}) int
|
|
|
|
|
2019-01-03 23:39:14 +00:00
|
|
|
// pack packs the records RDATA into wire format. The header will
|
|
|
|
// already have been packed into msg.
|
|
|
|
pack(msg []byte, off int, compression compressionMap, compress bool) (off1 int, err error)
|
2019-01-03 16:35:32 +00:00
|
|
|
|
|
|
|
// unpack unpacks an RR from wire format.
|
|
|
|
//
|
|
|
|
// 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.
|
|
|
|
unpack(msg []byte, off int) (off1 int, err error)
|
2019-01-06 04:06:16 +00:00
|
|
|
|
|
|
|
// 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.
|
2019-06-10 06:38:54 +00:00
|
|
|
parse(c *zlexer, origin string) *ParseError
|
2019-01-06 04:12:38 +00:00
|
|
|
|
|
|
|
// isDuplicate returns whether the two RRs are duplicates.
|
|
|
|
isDuplicate(r2 RR) bool
|
2010-12-30 12:42:52 +00:00
|
|
|
}
|
|
|
|
|
2015-08-23 07:03:13 +00:00
|
|
|
// RR_Header is the header all DNS resource records share.
|
2010-12-30 12:42:52 +00:00
|
|
|
type RR_Header struct {
|
2012-04-29 19:55:29 +00:00
|
|
|
Name string `dns:"cdomain-name"`
|
2010-12-30 19:50:31 +00:00
|
|
|
Rrtype uint16
|
|
|
|
Class uint16
|
|
|
|
Ttl uint32
|
2016-06-13 18:44:38 +00:00
|
|
|
Rdlength uint16 // Length of data after header.
|
2010-12-30 12:42:52 +00:00
|
|
|
}
|
|
|
|
|
2016-06-13 18:44:38 +00:00
|
|
|
// Header returns itself. This is here to make RR_Header implements the RR interface.
|
2012-11-30 12:25:01 +00:00
|
|
|
func (h *RR_Header) Header() *RR_Header { return h }
|
|
|
|
|
2016-06-04 07:11:36 +00:00
|
|
|
// Just to implement the RR interface.
|
2013-02-09 07:35:17 +00:00
|
|
|
func (h *RR_Header) copy() RR { return nil }
|
2010-12-30 12:42:52 +00:00
|
|
|
|
|
|
|
func (h *RR_Header) String() string {
|
2010-12-30 19:50:31 +00:00
|
|
|
var s string
|
2010-12-30 12:42:52 +00:00
|
|
|
|
2010-12-30 19:50:31 +00:00
|
|
|
if h.Rrtype == TypeOPT {
|
|
|
|
s = ";"
|
|
|
|
// and maybe other things
|
|
|
|
}
|
2010-12-30 12:42:52 +00:00
|
|
|
|
2014-04-23 20:06:17 +00:00
|
|
|
s += sprintName(h.Name) + "\t"
|
2013-06-08 13:24:20 +00:00
|
|
|
s += strconv.FormatInt(int64(h.Ttl), 10) + "\t"
|
|
|
|
s += Class(h.Class).String() + "\t"
|
|
|
|
s += Type(h.Rrtype).String() + "\t"
|
2010-12-30 19:50:31 +00:00
|
|
|
return s
|
2010-12-30 12:42:52 +00:00
|
|
|
}
|
2011-07-31 07:53:54 +00:00
|
|
|
|
2018-11-29 23:33:41 +00:00
|
|
|
func (h *RR_Header) len(off int, compression map[string]struct{}) int {
|
|
|
|
l := domainNameLen(h.Name, off, compression, true)
|
2012-01-12 22:17:34 +00:00
|
|
|
l += 10 // rrtype(2) + class(2) + ttl(4) + rdlength(2)
|
|
|
|
return l
|
2012-01-10 09:43:28 +00:00
|
|
|
}
|
|
|
|
|
2019-01-03 23:39:14 +00:00
|
|
|
func (h *RR_Header) pack(msg []byte, off int, compression compressionMap, compress bool) (off1 int, err error) {
|
|
|
|
// RR_Header has no RDATA to pack.
|
|
|
|
return off, nil
|
|
|
|
}
|
|
|
|
|
2019-01-03 16:35:32 +00:00
|
|
|
func (h *RR_Header) unpack(msg []byte, off int) (int, error) {
|
|
|
|
panic("dns: internal error: unpack should never be called on RR_Header")
|
|
|
|
}
|
|
|
|
|
2019-06-10 06:38:54 +00:00
|
|
|
func (h *RR_Header) parse(c *zlexer, origin string) *ParseError {
|
2019-01-06 04:06:16 +00:00
|
|
|
panic("dns: internal error: parse should never be called on RR_Header")
|
|
|
|
}
|
|
|
|
|
2016-06-12 20:06:46 +00:00
|
|
|
// ToRFC3597 converts a known RR to the unknown RR representation from RFC 3597.
|
2013-01-31 08:52:34 +00:00
|
|
|
func (rr *RFC3597) ToRFC3597(r RR) error {
|
Support parsing known RR types in RFC 3597 format (#1211)
* Support parsing known RR types in RFC 3597 format
This is the format used for "Unknown DNS Resource Records", but it's
also useful to support parsing known RR types in this way.
RFC 3597 says:
An implementation MAY also choose to represent some RRs of known type
using the above generic representations for the type, class and/or
RDATA, which carries the benefit of making the resulting master file
portable to servers where these types are unknown. Using the generic
representation for the RDATA of an RR of known type can also be
useful in the case of an RR type where the text format varies
depending on a version, protocol, or similar field (or several)
embedded in the RDATA when such a field has a value for which no text
format is known, e.g., a LOC RR [RFC1876] with a VERSION other than
0.
Even though an RR of known type represented in the \# format is
effectively treated as an unknown type for the purpose of parsing the
RDATA text representation, all further processing by the server MUST
treat it as a known type and take into account any applicable type-
specific rules regarding compression, canonicalization, etc.
* Correct mistakes in TestZoneParserAddressAAAA
This was spotted when writing TestParseKnownRRAsRFC3597.
* Eliminate canParseAsRR
This has the advantage that concrete types will now be returned for
parsed ANY, NULL, OPT and TSIG records.
* Expand TestDynamicUpdateParsing for RFC 3597
This ensures we're properly handling empty RDATA for RFC 3597 parsed
records.
2021-01-30 13:05:25 +00:00
|
|
|
buf := make([]byte, Len(r))
|
2018-12-02 08:23:35 +00:00
|
|
|
headerEnd, off, err := packRR(r, buf, 0, compressionMap{}, false)
|
2013-01-30 14:55:50 +00:00
|
|
|
if err != nil {
|
2013-01-31 08:52:34 +00:00
|
|
|
return err
|
2013-01-30 14:55:50 +00:00
|
|
|
}
|
|
|
|
buf = buf[:off]
|
2016-06-12 20:06:46 +00:00
|
|
|
|
2019-01-03 16:35:32 +00:00
|
|
|
*rr = RFC3597{Hdr: *r.Header()}
|
|
|
|
rr.Hdr.Rdlength = uint16(off - headerEnd)
|
|
|
|
|
|
|
|
if noRdata(rr.Hdr) {
|
|
|
|
return nil
|
|
|
|
}
|
2018-12-02 08:23:35 +00:00
|
|
|
|
2019-01-03 16:35:32 +00:00
|
|
|
_, err = rr.unpack(buf, headerEnd)
|
Support parsing known RR types in RFC 3597 format (#1211)
* Support parsing known RR types in RFC 3597 format
This is the format used for "Unknown DNS Resource Records", but it's
also useful to support parsing known RR types in this way.
RFC 3597 says:
An implementation MAY also choose to represent some RRs of known type
using the above generic representations for the type, class and/or
RDATA, which carries the benefit of making the resulting master file
portable to servers where these types are unknown. Using the generic
representation for the RDATA of an RR of known type can also be
useful in the case of an RR type where the text format varies
depending on a version, protocol, or similar field (or several)
embedded in the RDATA when such a field has a value for which no text
format is known, e.g., a LOC RR [RFC1876] with a VERSION other than
0.
Even though an RR of known type represented in the \# format is
effectively treated as an unknown type for the purpose of parsing the
RDATA text representation, all further processing by the server MUST
treat it as a known type and take into account any applicable type-
specific rules regarding compression, canonicalization, etc.
* Correct mistakes in TestZoneParserAddressAAAA
This was spotted when writing TestParseKnownRRAsRFC3597.
* Eliminate canParseAsRR
This has the advantage that concrete types will now be returned for
parsed ANY, NULL, OPT and TSIG records.
* Expand TestDynamicUpdateParsing for RFC 3597
This ensures we're properly handling empty RDATA for RFC 3597 parsed
records.
2021-01-30 13:05:25 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// fromRFC3597 converts an unknown RR representation from RFC 3597 to the known RR type.
|
|
|
|
func (rr *RFC3597) fromRFC3597(r RR) error {
|
2021-02-01 08:10:38 +00:00
|
|
|
hdr := r.Header()
|
|
|
|
*hdr = rr.Hdr
|
Support parsing known RR types in RFC 3597 format (#1211)
* Support parsing known RR types in RFC 3597 format
This is the format used for "Unknown DNS Resource Records", but it's
also useful to support parsing known RR types in this way.
RFC 3597 says:
An implementation MAY also choose to represent some RRs of known type
using the above generic representations for the type, class and/or
RDATA, which carries the benefit of making the resulting master file
portable to servers where these types are unknown. Using the generic
representation for the RDATA of an RR of known type can also be
useful in the case of an RR type where the text format varies
depending on a version, protocol, or similar field (or several)
embedded in the RDATA when such a field has a value for which no text
format is known, e.g., a LOC RR [RFC1876] with a VERSION other than
0.
Even though an RR of known type represented in the \# format is
effectively treated as an unknown type for the purpose of parsing the
RDATA text representation, all further processing by the server MUST
treat it as a known type and take into account any applicable type-
specific rules regarding compression, canonicalization, etc.
* Correct mistakes in TestZoneParserAddressAAAA
This was spotted when writing TestParseKnownRRAsRFC3597.
* Eliminate canParseAsRR
This has the advantage that concrete types will now be returned for
parsed ANY, NULL, OPT and TSIG records.
* Expand TestDynamicUpdateParsing for RFC 3597
This ensures we're properly handling empty RDATA for RFC 3597 parsed
records.
2021-01-30 13:05:25 +00:00
|
|
|
|
2021-02-01 08:10:38 +00:00
|
|
|
// Can't overflow uint16 as the length of Rdata is validated in (*RFC3597).parse.
|
|
|
|
// We can only get here when rr was constructed with that method.
|
|
|
|
hdr.Rdlength = uint16(hex.DecodedLen(len(rr.Rdata)))
|
|
|
|
|
|
|
|
if noRdata(*hdr) {
|
Support parsing known RR types in RFC 3597 format (#1211)
* Support parsing known RR types in RFC 3597 format
This is the format used for "Unknown DNS Resource Records", but it's
also useful to support parsing known RR types in this way.
RFC 3597 says:
An implementation MAY also choose to represent some RRs of known type
using the above generic representations for the type, class and/or
RDATA, which carries the benefit of making the resulting master file
portable to servers where these types are unknown. Using the generic
representation for the RDATA of an RR of known type can also be
useful in the case of an RR type where the text format varies
depending on a version, protocol, or similar field (or several)
embedded in the RDATA when such a field has a value for which no text
format is known, e.g., a LOC RR [RFC1876] with a VERSION other than
0.
Even though an RR of known type represented in the \# format is
effectively treated as an unknown type for the purpose of parsing the
RDATA text representation, all further processing by the server MUST
treat it as a known type and take into account any applicable type-
specific rules regarding compression, canonicalization, etc.
* Correct mistakes in TestZoneParserAddressAAAA
This was spotted when writing TestParseKnownRRAsRFC3597.
* Eliminate canParseAsRR
This has the advantage that concrete types will now be returned for
parsed ANY, NULL, OPT and TSIG records.
* Expand TestDynamicUpdateParsing for RFC 3597
This ensures we're properly handling empty RDATA for RFC 3597 parsed
records.
2021-01-30 13:05:25 +00:00
|
|
|
// Dynamic update.
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// rr.pack requires an extra allocation and a copy so we just decode Rdata
|
|
|
|
// manually, it's simpler anyway.
|
|
|
|
msg, err := hex.DecodeString(rr.Rdata)
|
2013-01-30 14:55:50 +00:00
|
|
|
if err != nil {
|
2013-01-31 08:52:34 +00:00
|
|
|
return err
|
2013-01-30 14:55:50 +00:00
|
|
|
}
|
2018-12-02 08:23:35 +00:00
|
|
|
|
Support parsing known RR types in RFC 3597 format (#1211)
* Support parsing known RR types in RFC 3597 format
This is the format used for "Unknown DNS Resource Records", but it's
also useful to support parsing known RR types in this way.
RFC 3597 says:
An implementation MAY also choose to represent some RRs of known type
using the above generic representations for the type, class and/or
RDATA, which carries the benefit of making the resulting master file
portable to servers where these types are unknown. Using the generic
representation for the RDATA of an RR of known type can also be
useful in the case of an RR type where the text format varies
depending on a version, protocol, or similar field (or several)
embedded in the RDATA when such a field has a value for which no text
format is known, e.g., a LOC RR [RFC1876] with a VERSION other than
0.
Even though an RR of known type represented in the \# format is
effectively treated as an unknown type for the purpose of parsing the
RDATA text representation, all further processing by the server MUST
treat it as a known type and take into account any applicable type-
specific rules regarding compression, canonicalization, etc.
* Correct mistakes in TestZoneParserAddressAAAA
This was spotted when writing TestParseKnownRRAsRFC3597.
* Eliminate canParseAsRR
This has the advantage that concrete types will now be returned for
parsed ANY, NULL, OPT and TSIG records.
* Expand TestDynamicUpdateParsing for RFC 3597
This ensures we're properly handling empty RDATA for RFC 3597 parsed
records.
2021-01-30 13:05:25 +00:00
|
|
|
_, err = r.unpack(msg, 0)
|
|
|
|
return err
|
2013-01-30 14:55:50 +00:00
|
|
|
}
|