Skip to content

Commit

Permalink
Merge branch 'master' of github.com:miekg/dns
Browse files Browse the repository at this point in the history
  • Loading branch information
miekg committed Jan 30, 2021
2 parents a25c26b + 13238cb commit a136210
Show file tree
Hide file tree
Showing 8 changed files with 129 additions and 42 deletions.
25 changes: 22 additions & 3 deletions dns.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package dns

import "strconv"
import (
"encoding/hex"
"strconv"
)

const (
year68 = 1 << 31 // For RFC1982 (Serial Arithmetic) calculations in 32 bits.
Expand Down Expand Up @@ -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
Expand All @@ -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
}
4 changes: 2 additions & 2 deletions edns.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand Down
4 changes: 2 additions & 2 deletions parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}

Expand Down
51 changes: 32 additions & 19 deletions scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -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}
}
Expand All @@ -600,20 +613,32 @@ 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)
}

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
}
}
Expand All @@ -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

Expand Down Expand Up @@ -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 {
Expand All @@ -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 {
Expand Down
48 changes: 45 additions & 3 deletions scan_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
}
Expand Down Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions tsig.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
8 changes: 4 additions & 4 deletions types.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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.
Expand Down
27 changes: 20 additions & 7 deletions update_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
}
Expand Down

0 comments on commit a136210

Please sign in to comment.