12 // helper functions called from the generated zmsg.go
14 // These function are named after the tag to help pack/unpack, if there is no tag it is the name
15 // of the type they pack/unpack (string, int, etc). We prefix all with unpackData or packData, so packDataA or
16 // packDataDomainName.
18 func unpackDataA(msg []byte, off int) (net.IP, int, error) {
19 if off+net.IPv4len > len(msg) {
20 return nil, len(msg), &Error{err: "overflow unpacking a"}
22 a := append(make(net.IP, 0, net.IPv4len), msg[off:off+net.IPv4len]...)
27 func packDataA(a net.IP, msg []byte, off int) (int, error) {
28 // It must be a slice of 4, even if it is 16, we encode only the first 4
29 if off+net.IPv4len > len(msg) {
30 return len(msg), &Error{err: "overflow packing a"}
33 case net.IPv4len, net.IPv6len:
34 copy(msg[off:], a.To4())
37 // Allowed, for dynamic updates.
39 return len(msg), &Error{err: "overflow packing a"}
44 func unpackDataAAAA(msg []byte, off int) (net.IP, int, error) {
45 if off+net.IPv6len > len(msg) {
46 return nil, len(msg), &Error{err: "overflow unpacking aaaa"}
48 aaaa := append(make(net.IP, 0, net.IPv6len), msg[off:off+net.IPv6len]...)
53 func packDataAAAA(aaaa net.IP, msg []byte, off int) (int, error) {
54 if off+net.IPv6len > len(msg) {
55 return len(msg), &Error{err: "overflow packing aaaa"}
63 // Allowed, dynamic updates.
65 return len(msg), &Error{err: "overflow packing aaaa"}
70 // unpackHeader unpacks an RR header, returning the offset to the end of the header and a
71 // re-sliced msg according to the expected length of the RR.
72 func unpackHeader(msg []byte, off int) (rr RR_Header, off1 int, truncmsg []byte, err error) {
75 return hdr, off, msg, nil
78 hdr.Name, off, err = UnpackDomainName(msg, off)
80 return hdr, len(msg), msg, err
82 hdr.Rrtype, off, err = unpackUint16(msg, off)
84 return hdr, len(msg), msg, err
86 hdr.Class, off, err = unpackUint16(msg, off)
88 return hdr, len(msg), msg, err
90 hdr.Ttl, off, err = unpackUint32(msg, off)
92 return hdr, len(msg), msg, err
94 hdr.Rdlength, off, err = unpackUint16(msg, off)
96 return hdr, len(msg), msg, err
98 msg, err = truncateMsgFromRdlength(msg, off, hdr.Rdlength)
99 return hdr, off, msg, err
102 // packHeader packs an RR header, returning the offset to the end of the header.
103 // See PackDomainName for documentation about the compression.
104 func (hdr RR_Header) packHeader(msg []byte, off int, compression compressionMap, compress bool) (int, error) {
109 off, err := packDomainName(hdr.Name, msg, off, compression, compress)
113 off, err = packUint16(hdr.Rrtype, msg, off)
117 off, err = packUint16(hdr.Class, msg, off)
121 off, err = packUint32(hdr.Ttl, msg, off)
125 off, err = packUint16(0, msg, off) // The RDLENGTH field will be set later in packRR.
132 // helper helper functions.
134 // truncateMsgFromRdLength truncates msg to match the expected length of the RR.
135 // Returns an error if msg is smaller than the expected size.
136 func truncateMsgFromRdlength(msg []byte, off int, rdlength uint16) (truncmsg []byte, err error) {
137 lenrd := off + int(rdlength)
138 if lenrd > len(msg) {
139 return msg, &Error{err: "overflowing header size"}
141 return msg[:lenrd], nil
144 var base32HexNoPadEncoding = base32.HexEncoding
146 func fromBase32(s []byte) (buf []byte, err error) {
147 for i, b := range s {
148 if b >= 'a' && b <= 'z' {
152 buflen := base32HexNoPadEncoding.DecodedLen(len(s))
153 buf = make([]byte, buflen)
154 n, err := base32HexNoPadEncoding.Decode(buf, s)
159 func toBase32(b []byte) string {
160 return base32HexNoPadEncoding.EncodeToString(b)
163 func fromBase64(s []byte) (buf []byte, err error) {
164 buflen := base64.StdEncoding.DecodedLen(len(s))
165 buf = make([]byte, buflen)
166 n, err := base64.StdEncoding.Decode(buf, s)
171 func toBase64(b []byte) string { return base64.StdEncoding.EncodeToString(b) }
173 // dynamicUpdate returns true if the Rdlength is zero.
174 func noRdata(h RR_Header) bool { return h.Rdlength == 0 }
176 func unpackUint8(msg []byte, off int) (i uint8, off1 int, err error) {
177 if off+1 > len(msg) {
178 return 0, len(msg), &Error{err: "overflow unpacking uint8"}
180 return msg[off], off + 1, nil
183 func packUint8(i uint8, msg []byte, off int) (off1 int, err error) {
184 if off+1 > len(msg) {
185 return len(msg), &Error{err: "overflow packing uint8"}
191 func unpackUint16(msg []byte, off int) (i uint16, off1 int, err error) {
192 if off+2 > len(msg) {
193 return 0, len(msg), &Error{err: "overflow unpacking uint16"}
195 return binary.BigEndian.Uint16(msg[off:]), off + 2, nil
198 func packUint16(i uint16, msg []byte, off int) (off1 int, err error) {
199 if off+2 > len(msg) {
200 return len(msg), &Error{err: "overflow packing uint16"}
202 binary.BigEndian.PutUint16(msg[off:], i)
206 func unpackUint32(msg []byte, off int) (i uint32, off1 int, err error) {
207 if off+4 > len(msg) {
208 return 0, len(msg), &Error{err: "overflow unpacking uint32"}
210 return binary.BigEndian.Uint32(msg[off:]), off + 4, nil
213 func packUint32(i uint32, msg []byte, off int) (off1 int, err error) {
214 if off+4 > len(msg) {
215 return len(msg), &Error{err: "overflow packing uint32"}
217 binary.BigEndian.PutUint32(msg[off:], i)
221 func unpackUint48(msg []byte, off int) (i uint64, off1 int, err error) {
222 if off+6 > len(msg) {
223 return 0, len(msg), &Error{err: "overflow unpacking uint64 as uint48"}
225 // Used in TSIG where the last 48 bits are occupied, so for now, assume a uint48 (6 bytes)
226 i = uint64(msg[off])<<40 | uint64(msg[off+1])<<32 | uint64(msg[off+2])<<24 | uint64(msg[off+3])<<16 |
227 uint64(msg[off+4])<<8 | uint64(msg[off+5])
232 func packUint48(i uint64, msg []byte, off int) (off1 int, err error) {
233 if off+6 > len(msg) {
234 return len(msg), &Error{err: "overflow packing uint64 as uint48"}
236 msg[off] = byte(i >> 40)
237 msg[off+1] = byte(i >> 32)
238 msg[off+2] = byte(i >> 24)
239 msg[off+3] = byte(i >> 16)
240 msg[off+4] = byte(i >> 8)
246 func unpackUint64(msg []byte, off int) (i uint64, off1 int, err error) {
247 if off+8 > len(msg) {
248 return 0, len(msg), &Error{err: "overflow unpacking uint64"}
250 return binary.BigEndian.Uint64(msg[off:]), off + 8, nil
253 func packUint64(i uint64, msg []byte, off int) (off1 int, err error) {
254 if off+8 > len(msg) {
255 return len(msg), &Error{err: "overflow packing uint64"}
257 binary.BigEndian.PutUint64(msg[off:], i)
262 func unpackString(msg []byte, off int) (string, int, error) {
263 if off+1 > len(msg) {
264 return "", off, &Error{err: "overflow unpacking txt"}
267 if off+l+1 > len(msg) {
268 return "", off, &Error{err: "overflow unpacking txt"}
272 for _, b := range msg[off+1 : off+1+l] {
274 case b == '"' || b == '\\':
277 case b < ' ' || b > '~': // unprintable
278 s.WriteString(escapeByte(b))
284 return s.String(), off, nil
287 func packString(s string, msg []byte, off int) (int, error) {
288 txtTmp := make([]byte, 256*4+1)
289 off, err := packTxtString(s, msg, off, txtTmp)
296 func unpackStringBase32(msg []byte, off, end int) (string, int, error) {
298 return "", len(msg), &Error{err: "overflow unpacking base32"}
300 s := toBase32(msg[off:end])
304 func packStringBase32(s string, msg []byte, off int) (int, error) {
305 b32, err := fromBase32([]byte(s))
309 if off+len(b32) > len(msg) {
310 return len(msg), &Error{err: "overflow packing base32"}
312 copy(msg[off:off+len(b32)], b32)
317 func unpackStringBase64(msg []byte, off, end int) (string, int, error) {
318 // Rest of the RR is base64 encoded value, so we don't need an explicit length
319 // to be set. Thus far all RR's that have base64 encoded fields have those as their
320 // last one. What we do need is the end of the RR!
322 return "", len(msg), &Error{err: "overflow unpacking base64"}
324 s := toBase64(msg[off:end])
328 func packStringBase64(s string, msg []byte, off int) (int, error) {
329 b64, err := fromBase64([]byte(s))
333 if off+len(b64) > len(msg) {
334 return len(msg), &Error{err: "overflow packing base64"}
336 copy(msg[off:off+len(b64)], b64)
341 func unpackStringHex(msg []byte, off, end int) (string, int, error) {
342 // Rest of the RR is hex encoded value, so we don't need an explicit length
343 // to be set. NSEC and TSIG have hex fields with a length field.
344 // What we do need is the end of the RR!
346 return "", len(msg), &Error{err: "overflow unpacking hex"}
349 s := hex.EncodeToString(msg[off:end])
353 func packStringHex(s string, msg []byte, off int) (int, error) {
354 h, err := hex.DecodeString(s)
358 if off+len(h) > len(msg) {
359 return len(msg), &Error{err: "overflow packing hex"}
361 copy(msg[off:off+len(h)], h)
366 func unpackStringAny(msg []byte, off, end int) (string, int, error) {
368 return "", len(msg), &Error{err: "overflow unpacking anything"}
370 return string(msg[off:end]), end, nil
373 func packStringAny(s string, msg []byte, off int) (int, error) {
374 if off+len(s) > len(msg) {
375 return len(msg), &Error{err: "overflow packing anything"}
377 copy(msg[off:off+len(s)], s)
382 func unpackStringTxt(msg []byte, off int) ([]string, int, error) {
383 txt, off, err := unpackTxt(msg, off)
385 return nil, len(msg), err
390 func packStringTxt(s []string, msg []byte, off int) (int, error) {
391 txtTmp := make([]byte, 256*4+1) // If the whole string consists out of \DDD we need this many.
392 off, err := packTxt(s, msg, off, txtTmp)
399 func unpackDataOpt(msg []byte, off int) ([]EDNS0, int, error) {
403 if off+4 > len(msg) {
404 return nil, len(msg), &Error{err: "overflow unpacking opt"}
406 code = binary.BigEndian.Uint16(msg[off:])
408 optlen := binary.BigEndian.Uint16(msg[off:])
410 if off+int(optlen) > len(msg) {
411 return nil, len(msg), &Error{err: "overflow unpacking opt"}
416 if err := e.unpack(msg[off : off+int(optlen)]); err != nil {
417 return nil, len(msg), err
419 edns = append(edns, e)
422 e := new(EDNS0_SUBNET)
423 if err := e.unpack(msg[off : off+int(optlen)]); err != nil {
424 return nil, len(msg), err
426 edns = append(edns, e)
429 e := new(EDNS0_COOKIE)
430 if err := e.unpack(msg[off : off+int(optlen)]); err != nil {
431 return nil, len(msg), err
433 edns = append(edns, e)
437 if err := e.unpack(msg[off : off+int(optlen)]); err != nil {
438 return nil, len(msg), err
440 edns = append(edns, e)
444 if err := e.unpack(msg[off : off+int(optlen)]); err != nil {
445 return nil, len(msg), err
447 edns = append(edns, e)
451 if err := e.unpack(msg[off : off+int(optlen)]); err != nil {
452 return nil, len(msg), err
454 edns = append(edns, e)
458 if err := e.unpack(msg[off : off+int(optlen)]); err != nil {
459 return nil, len(msg), err
461 edns = append(edns, e)
465 if err := e.unpack(msg[off : off+int(optlen)]); err != nil {
466 return nil, len(msg), err
468 edns = append(edns, e)
471 e := new(EDNS0_PADDING)
472 if err := e.unpack(msg[off : off+int(optlen)]); err != nil {
473 return nil, len(msg), err
475 edns = append(edns, e)
478 e := new(EDNS0_LOCAL)
480 if err := e.unpack(msg[off : off+int(optlen)]); err != nil {
481 return nil, len(msg), err
483 edns = append(edns, e)
491 return edns, off, nil
494 func packDataOpt(options []EDNS0, msg []byte, off int) (int, error) {
495 for _, el := range options {
497 if err != nil || off+3 > len(msg) {
498 return len(msg), &Error{err: "overflow packing opt"}
500 binary.BigEndian.PutUint16(msg[off:], el.Option()) // Option code
501 binary.BigEndian.PutUint16(msg[off+2:], uint16(len(b))) // Length
503 if off+len(b) > len(msg) {
509 copy(msg[off:off+len(b)], b)
515 func unpackStringOctet(msg []byte, off int) (string, int, error) {
516 s := string(msg[off:])
517 return s, len(msg), nil
520 func packStringOctet(s string, msg []byte, off int) (int, error) {
521 txtTmp := make([]byte, 256*4+1)
522 off, err := packOctetString(s, msg, off, txtTmp)
529 func unpackDataNsec(msg []byte, off int) ([]uint16, int, error) {
531 length, window, lastwindow := 0, 0, -1
533 if off+2 > len(msg) {
534 return nsec, len(msg), &Error{err: "overflow unpacking nsecx"}
536 window = int(msg[off])
537 length = int(msg[off+1])
539 if window <= lastwindow {
540 // RFC 4034: Blocks are present in the NSEC RR RDATA in
541 // increasing numerical order.
542 return nsec, len(msg), &Error{err: "out of order NSEC block"}
545 // RFC 4034: Blocks with no types present MUST NOT be included.
546 return nsec, len(msg), &Error{err: "empty NSEC block"}
549 return nsec, len(msg), &Error{err: "NSEC block too long"}
551 if off+length > len(msg) {
552 return nsec, len(msg), &Error{err: "overflowing NSEC block"}
555 // Walk the bytes in the window and extract the type bits
556 for j := 0; j < length; j++ {
558 // Check the bits one by one, and set the type
560 nsec = append(nsec, uint16(window*256+j*8+0))
563 nsec = append(nsec, uint16(window*256+j*8+1))
566 nsec = append(nsec, uint16(window*256+j*8+2))
569 nsec = append(nsec, uint16(window*256+j*8+3))
572 nsec = append(nsec, uint16(window*256+j*8+4))
575 nsec = append(nsec, uint16(window*256+j*8+5))
578 nsec = append(nsec, uint16(window*256+j*8+6))
581 nsec = append(nsec, uint16(window*256+j*8+7))
587 return nsec, off, nil
590 func packDataNsec(bitmap []uint16, msg []byte, off int) (int, error) {
591 if len(bitmap) == 0 {
594 var lastwindow, lastlength uint16
595 for j := 0; j < len(bitmap); j++ {
598 length := (t-window*256)/8 + 1
599 if window > lastwindow && lastlength != 0 { // New window, jump to the new offset
600 off += int(lastlength) + 2
603 if window < lastwindow || length < lastlength {
604 return len(msg), &Error{err: "nsec bits out of order"}
606 if off+2+int(length) > len(msg) {
607 return len(msg), &Error{err: "overflow packing nsec"}
609 // Setting the window #
610 msg[off] = byte(window)
611 // Setting the octets length
612 msg[off+1] = byte(length)
613 // Setting the bit value for the type in the right octet
614 msg[off+1+int(length)] |= byte(1 << (7 - t%8))
615 lastwindow, lastlength = window, length
617 off += int(lastlength) + 2
621 func unpackDataDomainNames(msg []byte, off, end int) ([]string, int, error) {
628 return nil, len(msg), &Error{err: "overflow unpacking domain names"}
631 s, off, err = UnpackDomainName(msg, off)
633 return servers, len(msg), err
635 servers = append(servers, s)
637 return servers, off, nil
640 func packDataDomainNames(names []string, msg []byte, off int, compression compressionMap, compress bool) (int, error) {
642 for j := 0; j < len(names); j++ {
643 off, err = packDomainName(names[j], msg, off, compression, compress)