2016-05-14 16:56:20 +00:00
|
|
|
package dns
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/base32"
|
|
|
|
"encoding/base64"
|
2016-06-08 15:38:42 +00:00
|
|
|
"encoding/binary"
|
2016-05-14 16:56:20 +00:00
|
|
|
"encoding/hex"
|
|
|
|
"net"
|
|
|
|
"strconv"
|
|
|
|
)
|
|
|
|
|
|
|
|
// helper functions called from the generated zmsg.go
|
|
|
|
|
|
|
|
// These function are named after the tag to help pack/unpack, if there is no tag it is the name
|
|
|
|
// of the type they pack/unpack (string, int, etc). We prefix all with unpackData or packData, so packDataA or
|
|
|
|
// packDataDomainName.
|
|
|
|
|
|
|
|
func unpackDataA(msg []byte, off int) (net.IP, int, error) {
|
|
|
|
if off+net.IPv4len > len(msg) {
|
|
|
|
return nil, len(msg), &Error{err: "overflow unpacking a"}
|
|
|
|
}
|
2016-06-08 16:10:03 +00:00
|
|
|
a := append(make(net.IP, 0, net.IPv4len), msg[off:off+net.IPv4len]...)
|
2016-05-14 16:56:20 +00:00
|
|
|
off += net.IPv4len
|
|
|
|
return a, off, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func packDataA(a net.IP, msg []byte, off int) (int, error) {
|
|
|
|
// It must be a slice of 4, even if it is 16, we encode only the first 4
|
|
|
|
if off+net.IPv4len > len(msg) {
|
|
|
|
return len(msg), &Error{err: "overflow packing a"}
|
|
|
|
}
|
|
|
|
switch len(a) {
|
2016-06-08 16:10:03 +00:00
|
|
|
case net.IPv4len, net.IPv6len:
|
|
|
|
copy(msg[off:], a.To4())
|
2016-05-14 16:56:20 +00:00
|
|
|
off += net.IPv4len
|
|
|
|
case 0:
|
|
|
|
// Allowed, for dynamic updates.
|
|
|
|
default:
|
|
|
|
return len(msg), &Error{err: "overflow packing a"}
|
|
|
|
}
|
|
|
|
return off, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func unpackDataAAAA(msg []byte, off int) (net.IP, int, error) {
|
|
|
|
if off+net.IPv6len > len(msg) {
|
|
|
|
return nil, len(msg), &Error{err: "overflow unpacking aaaa"}
|
|
|
|
}
|
2016-06-08 16:10:03 +00:00
|
|
|
aaaa := append(make(net.IP, 0, net.IPv6len), msg[off:off+net.IPv6len]...)
|
2016-05-14 16:56:20 +00:00
|
|
|
off += net.IPv6len
|
|
|
|
return aaaa, off, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func packDataAAAA(aaaa net.IP, msg []byte, off int) (int, error) {
|
|
|
|
if off+net.IPv6len > len(msg) {
|
|
|
|
return len(msg), &Error{err: "overflow packing aaaa"}
|
|
|
|
}
|
|
|
|
|
|
|
|
switch len(aaaa) {
|
|
|
|
case net.IPv6len:
|
2016-06-08 16:10:03 +00:00
|
|
|
copy(msg[off:], aaaa)
|
2016-05-14 16:56:20 +00:00
|
|
|
off += net.IPv6len
|
|
|
|
case 0:
|
|
|
|
// Allowed, dynamic updates.
|
|
|
|
default:
|
|
|
|
return len(msg), &Error{err: "overflow packing aaaa"}
|
|
|
|
}
|
|
|
|
return off, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// unpackHeader unpacks an RR header, returning the offset to the end of the header and a
|
|
|
|
// re-sliced msg according to the expected length of the RR.
|
|
|
|
func unpackHeader(msg []byte, off int) (rr RR_Header, off1 int, truncmsg []byte, err error) {
|
|
|
|
hdr := RR_Header{}
|
|
|
|
if off == len(msg) {
|
|
|
|
return hdr, off, msg, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
hdr.Name, off, err = UnpackDomainName(msg, off)
|
|
|
|
if err != nil {
|
|
|
|
return hdr, len(msg), msg, err
|
|
|
|
}
|
|
|
|
hdr.Rrtype, off, err = unpackUint16(msg, off)
|
|
|
|
if err != nil {
|
|
|
|
return hdr, len(msg), msg, err
|
|
|
|
}
|
|
|
|
hdr.Class, off, err = unpackUint16(msg, off)
|
|
|
|
if err != nil {
|
|
|
|
return hdr, len(msg), msg, err
|
|
|
|
}
|
|
|
|
hdr.Ttl, off, err = unpackUint32(msg, off)
|
|
|
|
if err != nil {
|
|
|
|
return hdr, len(msg), msg, err
|
|
|
|
}
|
|
|
|
hdr.Rdlength, off, err = unpackUint16(msg, off)
|
|
|
|
if err != nil {
|
|
|
|
return hdr, len(msg), msg, err
|
|
|
|
}
|
|
|
|
msg, err = truncateMsgFromRdlength(msg, off, hdr.Rdlength)
|
|
|
|
return hdr, off, msg, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// pack packs an RR header, returning the offset to the end of the header.
|
|
|
|
// See PackDomainName for documentation about the compression.
|
|
|
|
func (hdr RR_Header) pack(msg []byte, off int, compression map[string]int, compress bool) (off1 int, err error) {
|
|
|
|
if off == len(msg) {
|
|
|
|
return off, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
off, err = PackDomainName(hdr.Name, msg, off, compression, compress)
|
|
|
|
if err != nil {
|
|
|
|
return len(msg), err
|
|
|
|
}
|
|
|
|
off, err = packUint16(hdr.Rrtype, msg, off)
|
|
|
|
if err != nil {
|
|
|
|
return len(msg), err
|
|
|
|
}
|
|
|
|
off, err = packUint16(hdr.Class, msg, off)
|
|
|
|
if err != nil {
|
|
|
|
return len(msg), err
|
|
|
|
}
|
|
|
|
off, err = packUint32(hdr.Ttl, msg, off)
|
|
|
|
if err != nil {
|
|
|
|
return len(msg), err
|
|
|
|
}
|
|
|
|
off, err = packUint16(hdr.Rdlength, msg, off)
|
|
|
|
if err != nil {
|
|
|
|
return len(msg), err
|
|
|
|
}
|
|
|
|
return off, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// helper helper functions.
|
|
|
|
|
|
|
|
// truncateMsgFromRdLength truncates msg to match the expected length of the RR.
|
|
|
|
// Returns an error if msg is smaller than the expected size.
|
|
|
|
func truncateMsgFromRdlength(msg []byte, off int, rdlength uint16) (truncmsg []byte, err error) {
|
|
|
|
lenrd := off + int(rdlength)
|
|
|
|
if lenrd > len(msg) {
|
|
|
|
return msg, &Error{err: "overflowing header size"}
|
|
|
|
}
|
|
|
|
return msg[:lenrd], nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func fromBase32(s []byte) (buf []byte, err error) {
|
|
|
|
buflen := base32.HexEncoding.DecodedLen(len(s))
|
|
|
|
buf = make([]byte, buflen)
|
|
|
|
n, err := base32.HexEncoding.Decode(buf, s)
|
|
|
|
buf = buf[:n]
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func toBase32(b []byte) string { return base32.HexEncoding.EncodeToString(b) }
|
|
|
|
|
|
|
|
func fromBase64(s []byte) (buf []byte, err error) {
|
|
|
|
buflen := base64.StdEncoding.DecodedLen(len(s))
|
|
|
|
buf = make([]byte, buflen)
|
|
|
|
n, err := base64.StdEncoding.Decode(buf, s)
|
|
|
|
buf = buf[:n]
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func toBase64(b []byte) string { return base64.StdEncoding.EncodeToString(b) }
|
|
|
|
|
|
|
|
// dynamicUpdate returns true if the Rdlength is zero.
|
|
|
|
func noRdata(h RR_Header) bool { return h.Rdlength == 0 }
|
|
|
|
|
|
|
|
func unpackUint8(msg []byte, off int) (i uint8, off1 int, err error) {
|
|
|
|
if off+1 > len(msg) {
|
|
|
|
return 0, len(msg), &Error{err: "overflow unpacking uint8"}
|
|
|
|
}
|
|
|
|
return uint8(msg[off]), off + 1, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func packUint8(i uint8, msg []byte, off int) (off1 int, err error) {
|
|
|
|
if off+1 > len(msg) {
|
|
|
|
return len(msg), &Error{err: "overflow packing uint8"}
|
|
|
|
}
|
|
|
|
msg[off] = byte(i)
|
|
|
|
return off + 1, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func unpackUint16(msg []byte, off int) (i uint16, off1 int, err error) {
|
|
|
|
if off+2 > len(msg) {
|
|
|
|
return 0, len(msg), &Error{err: "overflow unpacking uint16"}
|
|
|
|
}
|
2016-06-08 15:38:42 +00:00
|
|
|
return binary.BigEndian.Uint16(msg[off:]), off + 2, nil
|
2016-05-14 16:56:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func packUint16(i uint16, msg []byte, off int) (off1 int, err error) {
|
|
|
|
if off+2 > len(msg) {
|
|
|
|
return len(msg), &Error{err: "overflow packing uint16"}
|
|
|
|
}
|
2016-06-08 15:38:42 +00:00
|
|
|
binary.BigEndian.PutUint16(msg[off:], i)
|
2016-05-14 16:56:20 +00:00
|
|
|
return off + 2, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func unpackUint32(msg []byte, off int) (i uint32, off1 int, err error) {
|
|
|
|
if off+4 > len(msg) {
|
|
|
|
return 0, len(msg), &Error{err: "overflow unpacking uint32"}
|
|
|
|
}
|
2016-06-08 15:38:42 +00:00
|
|
|
return binary.BigEndian.Uint32(msg[off:]), off + 4, nil
|
2016-05-14 16:56:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func packUint32(i uint32, msg []byte, off int) (off1 int, err error) {
|
|
|
|
if off+4 > len(msg) {
|
|
|
|
return len(msg), &Error{err: "overflow packing uint32"}
|
|
|
|
}
|
2016-06-08 15:38:42 +00:00
|
|
|
binary.BigEndian.PutUint32(msg[off:], i)
|
2016-05-14 16:56:20 +00:00
|
|
|
return off + 4, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func unpackUint48(msg []byte, off int) (i uint64, off1 int, err error) {
|
|
|
|
if off+6 > len(msg) {
|
|
|
|
return 0, len(msg), &Error{err: "overflow unpacking uint64 as uint48"}
|
|
|
|
}
|
|
|
|
// Used in TSIG where the last 48 bits are occupied, so for now, assume a uint48 (6 bytes)
|
|
|
|
i = (uint64(uint64(msg[off])<<40 | uint64(msg[off+1])<<32 | uint64(msg[off+2])<<24 | uint64(msg[off+3])<<16 |
|
|
|
|
uint64(msg[off+4])<<8 | uint64(msg[off+5])))
|
|
|
|
off += 6
|
|
|
|
return i, off, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func packUint48(i uint64, msg []byte, off int) (off1 int, err error) {
|
|
|
|
if off+6 > len(msg) {
|
|
|
|
return len(msg), &Error{err: "overflow packing uint64 as uint48"}
|
|
|
|
}
|
|
|
|
msg[off] = byte(i >> 40)
|
|
|
|
msg[off+1] = byte(i >> 32)
|
|
|
|
msg[off+2] = byte(i >> 24)
|
|
|
|
msg[off+3] = byte(i >> 16)
|
|
|
|
msg[off+4] = byte(i >> 8)
|
|
|
|
msg[off+5] = byte(i)
|
|
|
|
off += 6
|
|
|
|
return off, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func unpackUint64(msg []byte, off int) (i uint64, off1 int, err error) {
|
|
|
|
if off+8 > len(msg) {
|
|
|
|
return 0, len(msg), &Error{err: "overflow unpacking uint64"}
|
|
|
|
}
|
2016-06-08 15:38:42 +00:00
|
|
|
return binary.BigEndian.Uint64(msg[off:]), off + 8, nil
|
2016-05-14 16:56:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func packUint64(i uint64, msg []byte, off int) (off1 int, err error) {
|
|
|
|
if off+8 > len(msg) {
|
|
|
|
return len(msg), &Error{err: "overflow packing uint64"}
|
|
|
|
}
|
2016-06-08 15:38:42 +00:00
|
|
|
binary.BigEndian.PutUint64(msg[off:], i)
|
2016-05-14 16:56:20 +00:00
|
|
|
off += 8
|
|
|
|
return off, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func unpackString(msg []byte, off int) (string, int, error) {
|
|
|
|
if off+1 > len(msg) {
|
|
|
|
return "", off, &Error{err: "overflow unpacking txt"}
|
|
|
|
}
|
|
|
|
l := int(msg[off])
|
|
|
|
if off+l+1 > len(msg) {
|
|
|
|
return "", off, &Error{err: "overflow unpacking txt"}
|
|
|
|
}
|
|
|
|
s := make([]byte, 0, l)
|
|
|
|
for _, b := range msg[off+1 : off+1+l] {
|
|
|
|
switch b {
|
|
|
|
case '"', '\\':
|
|
|
|
s = append(s, '\\', b)
|
2016-06-08 16:10:03 +00:00
|
|
|
case '\t', '\r', '\n':
|
|
|
|
s = append(s, b)
|
2016-05-14 16:56:20 +00:00
|
|
|
default:
|
|
|
|
if b < 32 || b > 127 { // unprintable
|
|
|
|
var buf [3]byte
|
|
|
|
bufs := strconv.AppendInt(buf[:0], int64(b), 10)
|
|
|
|
s = append(s, '\\')
|
|
|
|
for i := 0; i < 3-len(bufs); i++ {
|
|
|
|
s = append(s, '0')
|
|
|
|
}
|
|
|
|
for _, r := range bufs {
|
|
|
|
s = append(s, r)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
s = append(s, b)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
off += 1 + l
|
|
|
|
return string(s), off, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func packString(s string, msg []byte, off int) (int, error) {
|
|
|
|
txtTmp := make([]byte, 256*4+1)
|
|
|
|
off, err := packTxtString(s, msg, off, txtTmp)
|
|
|
|
if err != nil {
|
|
|
|
return len(msg), err
|
|
|
|
}
|
|
|
|
return off, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func unpackStringBase64(msg []byte, off, end int) (string, int, error) {
|
|
|
|
// Rest of the RR is base64 encoded value, so we don't need an explicit length
|
|
|
|
// to be set. Thus far all RR's that have base64 encoded fields have those as their
|
|
|
|
// last one. What we do need is the end of the RR!
|
|
|
|
if end > len(msg) {
|
|
|
|
return "", len(msg), &Error{err: "overflow unpacking base64"}
|
|
|
|
}
|
|
|
|
s := toBase64(msg[off:end])
|
|
|
|
return s, end, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func packStringBase64(s string, msg []byte, off int) (int, error) {
|
|
|
|
b64, e := fromBase64([]byte(s))
|
|
|
|
if e != nil {
|
|
|
|
return len(msg), e
|
|
|
|
}
|
|
|
|
if off+len(b64) > len(msg) {
|
|
|
|
return len(msg), &Error{err: "overflow packing base64"}
|
|
|
|
}
|
|
|
|
copy(msg[off:off+len(b64)], b64)
|
|
|
|
off += len(b64)
|
|
|
|
return off, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func unpackStringHex(msg []byte, off, end int) (string, int, error) {
|
|
|
|
// Rest of the RR is hex encoded value, so we don't need an explicit length
|
|
|
|
// to be set. NSEC and TSIG have hex fields with a length field.
|
|
|
|
// What we do need is the end of the RR!
|
|
|
|
if end > len(msg) {
|
|
|
|
return "", len(msg), &Error{err: "overflow unpacking hex"}
|
|
|
|
}
|
|
|
|
|
|
|
|
s := hex.EncodeToString(msg[off:end])
|
|
|
|
return s, end, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func packStringHex(s string, msg []byte, off int) (int, error) {
|
|
|
|
h, e := hex.DecodeString(s)
|
|
|
|
if e != nil {
|
|
|
|
return len(msg), e
|
|
|
|
}
|
|
|
|
if off+(len(h)) > len(msg) {
|
|
|
|
return len(msg), &Error{err: "overflow packing hex"}
|
|
|
|
}
|
|
|
|
copy(msg[off:off+len(h)], h)
|
|
|
|
off += len(h)
|
|
|
|
return off, nil
|
|
|
|
}
|
2016-06-05 06:53:12 +00:00
|
|
|
|
|
|
|
func unpackStringTxt(msg []byte, off int) ([]string, int, error) {
|
|
|
|
txt, off, err := unpackTxt(msg, off)
|
|
|
|
if err != nil {
|
|
|
|
return nil, len(msg), err
|
|
|
|
}
|
|
|
|
return txt, off, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func packStringTxt(s []string, msg []byte, off int) (int, error) {
|
|
|
|
txtTmp := make([]byte, 256*4+1) // If the whole string consists out of \DDD we need this many.
|
|
|
|
off, err := packTxt(s, msg, off, txtTmp)
|
|
|
|
if err != nil {
|
|
|
|
return len(msg), err
|
|
|
|
}
|
|
|
|
return off, nil
|
|
|
|
}
|