Skip to content

Commit

Permalink
dns/dnsmessage: correctly handle multiple and >255 byte TXT records
Browse files Browse the repository at this point in the history
Previously, we only accepted a single string for TXT records and then
chunked it into 255 byte segments. This is wrong. TXT records are a
sequence of strings, each up to 255 bytes.

Updates golang/go#24288

Change-Id: Ib2c085ec127ccecf0c7bda930100b667cabc1f4b
Reviewed-on: https://go-review.googlesource.com/100196
Reviewed-by: Matthew Dempsky <[email protected]>
Run-TryBot: Brad Fitzpatrick <[email protected]>
TryBot-Result: Gobot Gobot <[email protected]>
  • Loading branch information
iangudger authored and bradfitz committed Mar 13, 2018
1 parent 803fdb9 commit 892bf7b
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 153 deletions.
64 changes: 45 additions & 19 deletions dns/dnsmessage/message.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ var (
errTooManyAuthorities = errors.New("too many Authorities to pack (>65535)")
errTooManyAdditionals = errors.New("too many Additionals to pack (>65535)")
errNonCanonicalName = errors.New("name is not in canonical format (it must end with a .)")
errStringTooLong = errors.New("character string exceeds maximum length (255)")
)

// Internal constants.
Expand Down Expand Up @@ -218,6 +219,7 @@ func (h *header) count(sec section) uint16 {
return 0
}

// pack appends the wire format of the header to msg.
func (h *header) pack(msg []byte) []byte {
msg = packUint16(msg, h.id)
msg = packUint16(msg, h.bits)
Expand Down Expand Up @@ -280,6 +282,7 @@ type ResourceBody interface {
realType() Type
}

// pack appends the wire format of the Resource to msg.
func (r *Resource) pack(msg []byte, compression map[string]int, compressionOff int) ([]byte, error) {
if r.Body == nil {
return msg, errNilResouceBody
Expand Down Expand Up @@ -1311,9 +1314,10 @@ type ResourceHeader struct {
Length uint16
}

// pack packs all of the fields in a ResourceHeader except for the length. The
// length bytes are returned as a slice so they can be filled in after the rest
// of the Resource has been packed.
// pack appends the wire format of the ResourceHeader to oldMsg.
//
// The bytes where length was packed are returned as a slice so they can be
// updated after the rest of the Resource has been packed.
func (h *ResourceHeader) pack(oldMsg []byte, compression map[string]int, compressionOff int) (msg []byte, length []byte, err error) {
msg = oldMsg
if msg, err = h.Name.pack(msg, compression, compressionOff); err != nil {
Expand Down Expand Up @@ -1385,6 +1389,7 @@ func skipResource(msg []byte, off int) (int, error) {
return newOff, nil
}

// packUint16 appends the wire format of field to msg.
func packUint16(msg []byte, field uint16) []byte {
return append(msg, byte(field>>8), byte(field))
}
Expand All @@ -1403,6 +1408,7 @@ func skipUint16(msg []byte, off int) (int, error) {
return off + uint16Len, nil
}

// packType appends the wire format of field to msg.
func packType(msg []byte, field Type) []byte {
return packUint16(msg, uint16(field))
}
Expand All @@ -1416,6 +1422,7 @@ func skipType(msg []byte, off int) (int, error) {
return skipUint16(msg, off)
}

// packClass appends the wire format of field to msg.
func packClass(msg []byte, field Class) []byte {
return packUint16(msg, uint16(field))
}
Expand All @@ -1429,6 +1436,7 @@ func skipClass(msg []byte, off int) (int, error) {
return skipUint16(msg, off)
}

// packUint32 appends the wire format of field to msg.
func packUint32(msg []byte, field uint32) []byte {
return append(
msg,
Expand All @@ -1454,17 +1462,16 @@ func skipUint32(msg []byte, off int) (int, error) {
return off + uint32Len, nil
}

func packText(msg []byte, field string) []byte {
for len(field) > 0 {
l := len(field)
if l > 255 {
l = 255
}
msg = append(msg, byte(l))
msg = append(msg, field[:l]...)
field = field[l:]
// packText appends the wire format of field to msg.
func packText(msg []byte, field string) ([]byte, error) {
l := len(field)
if l > 255 {
return nil, errStringTooLong
}
return msg
msg = append(msg, byte(l))
msg = append(msg, field...)

return msg, nil
}

func unpackText(msg []byte, off int) (string, int, error) {
Expand All @@ -1490,6 +1497,7 @@ func skipText(msg []byte, off int) (int, error) {
return endOff, nil
}

// packBytes appends the wire format of field to msg.
func packBytes(msg []byte, field []byte) []byte {
return append(msg, field...)
}
Expand Down Expand Up @@ -1534,7 +1542,7 @@ func (n Name) String() string {
return string(n.Data[:n.Length])
}

// pack packs a domain name.
// pack appends the wire format of the Name to msg.
//
// Domain names are a sequence of counted strings split at the dots. They end
// with a zero-length string. Compression can be used to reuse domain suffixes.
Expand Down Expand Up @@ -1716,6 +1724,7 @@ type Question struct {
Class Class
}

// pack appends the wire format of the Question to msg.
func (q *Question) pack(msg []byte, compression map[string]int, compressionOff int) ([]byte, error) {
msg, err := q.Name.pack(msg, compression, compressionOff)
if err != nil {
Expand Down Expand Up @@ -1796,6 +1805,7 @@ func (r *CNAMEResource) realType() Type {
return TypeCNAME
}

// pack appends the wire format of the CNAMEResource to msg.
func (r *CNAMEResource) pack(msg []byte, compression map[string]int, compressionOff int) ([]byte, error) {
return r.CNAME.pack(msg, compression, compressionOff)
}
Expand All @@ -1818,6 +1828,7 @@ func (r *MXResource) realType() Type {
return TypeMX
}

// pack appends the wire format of the MXResource to msg.
func (r *MXResource) pack(msg []byte, compression map[string]int, compressionOff int) ([]byte, error) {
oldMsg := msg
msg = packUint16(msg, r.Pref)
Expand Down Expand Up @@ -1849,6 +1860,7 @@ func (r *NSResource) realType() Type {
return TypeNS
}

// pack appends the wire format of the NSResource to msg.
func (r *NSResource) pack(msg []byte, compression map[string]int, compressionOff int) ([]byte, error) {
return r.NS.pack(msg, compression, compressionOff)
}
Expand All @@ -1870,6 +1882,7 @@ func (r *PTRResource) realType() Type {
return TypePTR
}

// pack appends the wire format of the PTRResource to msg.
func (r *PTRResource) pack(msg []byte, compression map[string]int, compressionOff int) ([]byte, error) {
return r.PTR.pack(msg, compression, compressionOff)
}
Expand Down Expand Up @@ -1901,6 +1914,7 @@ func (r *SOAResource) realType() Type {
return TypeSOA
}

// pack appends the wire format of the SOAResource to msg.
func (r *SOAResource) pack(msg []byte, compression map[string]int, compressionOff int) ([]byte, error) {
oldMsg := msg
msg, err := r.NS.pack(msg, compression, compressionOff)
Expand Down Expand Up @@ -1953,19 +1967,28 @@ func unpackSOAResource(msg []byte, off int) (SOAResource, error) {

// A TXTResource is a TXT Resource record.
type TXTResource struct {
Txt string // Not a domain name.
TXT []string
}

func (r *TXTResource) realType() Type {
return TypeTXT
}

// pack appends the wire format of the TXTResource to msg.
func (r *TXTResource) pack(msg []byte, compression map[string]int, compressionOff int) ([]byte, error) {
return packText(msg, r.Txt), nil
oldMsg := msg
for _, s := range r.TXT {
var err error
msg, err = packText(msg, s)
if err != nil {
return oldMsg, err
}
}
return msg, nil
}

func unpackTXTResource(msg []byte, off int, length uint16) (TXTResource, error) {
var txt string
txts := make([]string, 0, 1)
for n := uint16(0); n < length; {
var t string
var err error
Expand All @@ -1977,9 +2000,9 @@ func unpackTXTResource(msg []byte, off int, length uint16) (TXTResource, error)
return TXTResource{}, errCalcLen
}
n += uint16(len(t)) + 1
txt += t
txts = append(txts, t)
}
return TXTResource{txt}, nil
return TXTResource{txts}, nil
}

// An SRVResource is an SRV Resource record.
Expand All @@ -1994,6 +2017,7 @@ func (r *SRVResource) realType() Type {
return TypeSRV
}

// pack appends the wire format of the SRVResource to msg.
func (r *SRVResource) pack(msg []byte, compression map[string]int, compressionOff int) ([]byte, error) {
oldMsg := msg
msg = packUint16(msg, r.Priority)
Expand Down Expand Up @@ -2035,6 +2059,7 @@ func (r *AResource) realType() Type {
return TypeA
}

// pack appends the wire format of the AResource to msg.
func (r *AResource) pack(msg []byte, compression map[string]int, compressionOff int) ([]byte, error) {
return packBytes(msg, r.A[:]), nil
}
Expand All @@ -2056,6 +2081,7 @@ func (r *AAAAResource) realType() Type {
return TypeAAAA
}

// pack appends the wire format of the AAAAResource to msg.
func (r *AAAAResource) pack(msg []byte, compression map[string]int, compressionOff int) ([]byte, error) {
return packBytes(msg, r.AAAA[:]), nil
}
Expand Down
Loading

0 comments on commit 892bf7b

Please sign in to comment.