package dns import ( "encoding/base32" "encoding/base64" "encoding/binary" "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"} } a := append(make(net.IP, 0, net.IPv4len), msg[off:off+net.IPv4len]...) 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) { case net.IPv4len, net.IPv6len: copy(msg[off:], a.To4()) 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"} } aaaa := append(make(net.IP, 0, net.IPv6len), msg[off:off+net.IPv6len]...) 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: copy(msg[off:], aaaa) 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"} } return binary.BigEndian.Uint16(msg[off:]), off + 2, nil } 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"} } binary.BigEndian.PutUint16(msg[off:], i) 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"} } return binary.BigEndian.Uint32(msg[off:]), off + 4, nil } 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"} } binary.BigEndian.PutUint32(msg[off:], i) 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"} } return binary.BigEndian.Uint64(msg[off:]), off + 8, nil } 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"} } binary.BigEndian.PutUint64(msg[off:], i) 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) case '\t', '\r', '\n': s = append(s, b) 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 } 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 }