Merge branch 'master' of github.com:miekg/dns

This commit is contained in:
Miek Gieben 2021-01-30 14:06:35 +01:00
commit a1362108be
8 changed files with 129 additions and 42 deletions

25
dns.go
View File

@ -1,6 +1,9 @@
package dns
import "strconv"
import (
"encoding/hex"
"strconv"
)
const (
year68 = 1 << 31 // For RFC1982 (Serial Arithmetic) calculations in 32 bits.
@ -111,7 +114,7 @@ func (h *RR_Header) parse(c *zlexer, origin string) *ParseError {
// ToRFC3597 converts a known RR to the unknown RR representation from RFC 3597.
func (rr *RFC3597) ToRFC3597(r RR) error {
buf := make([]byte, Len(r)*2)
buf := make([]byte, Len(r))
headerEnd, off, err := packRR(r, buf, 0, compressionMap{}, false)
if err != nil {
return err
@ -126,9 +129,25 @@ func (rr *RFC3597) ToRFC3597(r RR) error {
}
_, err = rr.unpack(buf, headerEnd)
return err
}
// fromRFC3597 converts an unknown RR representation from RFC 3597 to the known RR type.
func (rr *RFC3597) fromRFC3597(r RR) error {
*r.Header() = rr.Hdr
if len(rr.Rdata) == 0 {
// 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)
if err != nil {
return err
}
return nil
_, err = r.unpack(msg, 0)
return err
}

View File

@ -88,8 +88,8 @@ func (rr *OPT) len(off int, compression map[string]struct{}) int {
return l
}
func (rr *OPT) parse(c *zlexer, origin string) *ParseError {
panic("dns: internal error: parse should never be called on OPT")
func (*OPT) parse(c *zlexer, origin string) *ParseError {
return &ParseError{err: "OPT records do not have a presentation format"}
}
func (r1 *OPT) isDuplicate(r2 RR) bool { return false }

View File

@ -1208,8 +1208,8 @@ func TestTypeXXXX(t *testing.T) {
t.Errorf("this should not work, for TYPE655341")
}
_, err = NewRR("example.com IN TYPE1 \\# 4 0a000001")
if err == nil {
t.Errorf("this should not work")
if err != nil {
t.Errorf("failed to parse TYPE1 RR: %v", err)
}
}

51
scan.go
View File

@ -577,10 +577,23 @@ func (zp *ZoneParser) Next() (RR, bool) {
st = zExpectRdata
case zExpectRdata:
var rr RR
if newFn, ok := TypeToRR[h.Rrtype]; ok && canParseAsRR(h.Rrtype) {
var (
rr RR
parseAsRFC3597 bool
)
if newFn, ok := TypeToRR[h.Rrtype]; ok {
rr = newFn()
*rr.Header() = *h
// We may be parsing a known RR type using the RFC3597 format.
// If so, we handle that here in a generic way.
//
// This is also true for PrivateRR types which will have the
// RFC3597 parsing done for them and the Unpack method called
// to populate the RR instead of simply deferring to Parse.
if zp.c.Peek().token == "\\#" {
parseAsRFC3597 = true
}
} else {
rr = &RFC3597{Hdr: *h}
}
@ -600,13 +613,18 @@ func (zp *ZoneParser) Next() (RR, bool) {
return zp.setParseError("unexpected newline", l)
}
if err := rr.parse(zp.c, zp.origin); err != nil {
parseAsRR := rr
if parseAsRFC3597 {
parseAsRR = &RFC3597{Hdr: *h}
}
if err := parseAsRR.parse(zp.c, zp.origin); err != nil {
// err is a concrete *ParseError without the file field set.
// The setParseError call below will construct a new
// *ParseError with file set to zp.file.
// If err.lex is nil than we have encounter an unknown RR type
// in that case we substitute our current lex token.
// err.lex may be nil in which case we substitute our current
// lex token.
if err.lex == (lex{}) {
return zp.setParseError(err.err, l)
}
@ -614,6 +632,13 @@ func (zp *ZoneParser) Next() (RR, bool) {
return zp.setParseError(err.err, err.lex)
}
if parseAsRFC3597 {
err := parseAsRR.(*RFC3597).fromRFC3597(rr)
if err != nil {
return zp.setParseError(err.Error(), l)
}
}
return rr, true
}
}
@ -623,18 +648,6 @@ func (zp *ZoneParser) Next() (RR, bool) {
return nil, false
}
// canParseAsRR returns true if the record type can be parsed as a
// concrete RR. It blacklists certain record types that must be parsed
// according to RFC 3597 because they lack a presentation format.
func canParseAsRR(rrtype uint16) bool {
switch rrtype {
case TypeANY, TypeNULL, TypeOPT, TypeTSIG:
return false
default:
return true
}
}
type zlexer struct {
br io.ByteReader
@ -1290,7 +1303,7 @@ func appendOrigin(name, origin string) string {
// LOC record helper function
func locCheckNorth(token string, latitude uint32) (uint32, bool) {
if latitude > 90 * 1000 * 60 * 60 {
if latitude > 90*1000*60*60 {
return latitude, false
}
switch token {
@ -1304,7 +1317,7 @@ func locCheckNorth(token string, latitude uint32) (uint32, bool) {
// LOC record helper function
func locCheckEast(token string, longitude uint32) (uint32, bool) {
if longitude > 180 * 1000 * 60 * 60 {
if longitude > 180*1000*60*60 {
return longitude, false
}
switch token {

View File

@ -145,10 +145,10 @@ func TestZoneParserAddressAAAA(t *testing.T) {
}
aaaa, ok := got.(*AAAA)
if !ok {
t.Fatalf("expected *AAAA RR, but got %T", aaaa)
t.Fatalf("expected *AAAA RR, but got %T", got)
}
if g, w := aaaa.AAAA, tc.want.AAAA; !g.Equal(w) {
t.Fatalf("expected AAAA with IP %v, but got %v", g, w)
if !aaaa.AAAA.Equal(tc.want.AAAA) {
t.Fatalf("expected AAAA with IP %v, but got %v", tc.want.AAAA, aaaa.AAAA)
}
}
}
@ -229,6 +229,48 @@ example.com. 60 PX (
}
}
func TestParseKnownRRAsRFC3597(t *testing.T) {
t.Run("with RDATA", func(t *testing.T) {
rr, err := NewRR("example. 3600 CLASS1 TYPE1 \\# 4 7f000001")
if err != nil {
t.Fatalf("failed to parse RFC3579 format: %v", err)
}
if rr.Header().Rrtype != TypeA {
t.Errorf("expected TypeA (1) Rrtype, but got %v", rr.Header().Rrtype)
}
a, ok := rr.(*A)
if !ok {
t.Fatalf("expected *A RR, but got %T", rr)
}
localhost := net.IPv4(127, 0, 0, 1)
if !a.A.Equal(localhost) {
t.Fatalf("expected A with IP %v, but got %v", localhost, a.A)
}
})
t.Run("without RDATA", func(t *testing.T) {
rr, err := NewRR("example. 3600 CLASS1 TYPE1 \\# 0")
if err != nil {
t.Fatalf("failed to parse RFC3579 format: %v", err)
}
if rr.Header().Rrtype != TypeA {
t.Errorf("expected TypeA (1) Rrtype, but got %v", rr.Header().Rrtype)
}
a, ok := rr.(*A)
if !ok {
t.Fatalf("expected *A RR, but got %T", rr)
}
if len(a.A) != 0 {
t.Fatalf("expected A with empty IP, but got %v", a.A)
}
})
}
func BenchmarkNewRR(b *testing.B) {
const name1 = "12345678901234567890123456789012345.12345678.123."
const s = name1 + " 3600 IN MX 10 " + name1

View File

@ -106,8 +106,8 @@ func (rr *TSIG) String() string {
return s
}
func (rr *TSIG) parse(c *zlexer, origin string) *ParseError {
panic("dns: internal error: parse should never be called on TSIG")
func (*TSIG) parse(c *zlexer, origin string) *ParseError {
return &ParseError{err: "TSIG records do not have a presentation format"}
}
// The following values must be put in wireformat, so that the MAC can be calculated.

View File

@ -245,8 +245,8 @@ type ANY struct {
func (rr *ANY) String() string { return rr.Hdr.String() }
func (rr *ANY) parse(c *zlexer, origin string) *ParseError {
panic("dns: internal error: parse should never be called on ANY")
func (*ANY) parse(c *zlexer, origin string) *ParseError {
return &ParseError{err: "ANY records do not have a presentation format"}
}
// NULL RR. See RFC 1035.
@ -260,8 +260,8 @@ func (rr *NULL) String() string {
return ";" + rr.Hdr.String() + rr.Data
}
func (rr *NULL) parse(c *zlexer, origin string) *ParseError {
panic("dns: internal error: parse should never be called on NULL")
func (*NULL) parse(c *zlexer, origin string) *ParseError {
return &ParseError{err: "NULL records do not have a presentation format"}
}
// CNAME RR. See RFC 1034.

View File

@ -6,15 +6,28 @@ import (
)
func TestDynamicUpdateParsing(t *testing.T) {
prefix := "example.com. IN "
for _, typ := range TypeToString {
if typ == "OPT" || typ == "AXFR" || typ == "IXFR" || typ == "ANY" || typ == "TKEY" ||
typ == "TSIG" || typ == "ISDN" || typ == "UNSPEC" || typ == "NULL" || typ == "ATMA" ||
typ == "Reserved" || typ == "None" || typ == "NXT" || typ == "MAILB" || typ == "MAILA" {
const prefix = "example.com. IN "
for typ, name := range TypeToString {
switch typ {
case TypeNone, TypeReserved:
continue
case TypeANY:
// ANY is ambiguous here and ends up parsed as a CLASS.
//
// TODO(tmthrgd): Using TYPE255 here doesn't seem to work and also
// seems to fail for some other record types. Investigate.
continue
}
if _, err := NewRR(prefix + typ); err != nil {
t.Errorf("failure to parse: %s %s: %v", prefix, typ, err)
s := prefix + name
if _, err := NewRR(s); err != nil {
t.Errorf("failure to parse: %s: %v", s, err)
}
s += " \\# 0"
if _, err := NewRR(s); err != nil {
t.Errorf("failure to parse: %s: %v", s, err)
}
}
}