1// DNS packet assembly, see RFC 1035. Converting from - Unpack() -
2// and to - Pack() - wire format.
3// All the packers and unpackers take a (msg []byte, off int)
4// and return (off1 int, ok bool).  If they return ok==false, they
5// also return off1==len(msg), so that the next unpacker will
6// also fail.  This lets us avoid checks of ok until the end of a
7// packing sequence.
8
9package dns
10
11//go:generate go run msg_generate.go
12
13import (
14	"crypto/rand"
15	"encoding/binary"
16	"fmt"
17	"math/big"
18	"strconv"
19	"strings"
20)
21
22const (
23	maxCompressionOffset    = 2 << 13 // We have 14 bits for the compression pointer
24	maxDomainNameWireOctets = 255     // See RFC 1035 section 2.3.4
25
26	// This is the maximum number of compression pointers that should occur in a
27	// semantically valid message. Each label in a domain name must be at least one
28	// octet and is separated by a period. The root label won't be represented by a
29	// compression pointer to a compression pointer, hence the -2 to exclude the
30	// smallest valid root label.
31	//
32	// It is possible to construct a valid message that has more compression pointers
33	// than this, and still doesn't loop, by pointing to a previous pointer. This is
34	// not something a well written implementation should ever do, so we leave them
35	// to trip the maximum compression pointer check.
36	maxCompressionPointers = (maxDomainNameWireOctets+1)/2 - 2
37
38	// This is the maximum length of a domain name in presentation format. The
39	// maximum wire length of a domain name is 255 octets (see above), with the
40	// maximum label length being 63. The wire format requires one extra byte over
41	// the presentation format, reducing the number of octets by 1. Each label in
42	// the name will be separated by a single period, with each octet in the label
43	// expanding to at most 4 bytes (\DDD). If all other labels are of the maximum
44	// length, then the final label can only be 61 octets long to not exceed the
45	// maximum allowed wire length.
46	maxDomainNamePresentationLength = 61*4 + 1 + 63*4 + 1 + 63*4 + 1 + 63*4 + 1
47)
48
49// Errors defined in this package.
50var (
51	ErrAlg           error = &Error{err: "bad algorithm"}                  // ErrAlg indicates an error with the (DNSSEC) algorithm.
52	ErrAuth          error = &Error{err: "bad authentication"}             // ErrAuth indicates an error in the TSIG authentication.
53	ErrBuf           error = &Error{err: "buffer size too small"}          // ErrBuf indicates that the buffer used is too small for the message.
54	ErrConnEmpty     error = &Error{err: "conn has no connection"}         // ErrConnEmpty indicates a connection is being used before it is initialized.
55	ErrExtendedRcode error = &Error{err: "bad extended rcode"}             // ErrExtendedRcode ...
56	ErrFqdn          error = &Error{err: "domain must be fully qualified"} // ErrFqdn indicates that a domain name does not have a closing dot.
57	ErrId            error = &Error{err: "id mismatch"}                    // ErrId indicates there is a mismatch with the message's ID.
58	ErrKeyAlg        error = &Error{err: "bad key algorithm"}              // ErrKeyAlg indicates that the algorithm in the key is not valid.
59	ErrKey           error = &Error{err: "bad key"}
60	ErrKeySize       error = &Error{err: "bad key size"}
61	ErrLongDomain    error = &Error{err: fmt.Sprintf("domain name exceeded %d wire-format octets", maxDomainNameWireOctets)}
62	ErrNoSig         error = &Error{err: "no signature found"}
63	ErrPrivKey       error = &Error{err: "bad private key"}
64	ErrRcode         error = &Error{err: "bad rcode"}
65	ErrRdata         error = &Error{err: "bad rdata"}
66	ErrRRset         error = &Error{err: "bad rrset"}
67	ErrSecret        error = &Error{err: "no secrets defined"}
68	ErrShortRead     error = &Error{err: "short read"}
69	ErrSig           error = &Error{err: "bad signature"} // ErrSig indicates that a signature can not be cryptographically validated.
70	ErrSoa           error = &Error{err: "no SOA"}        // ErrSOA indicates that no SOA RR was seen when doing zone transfers.
71	ErrTime          error = &Error{err: "bad time"}      // ErrTime indicates a timing error in TSIG authentication.
72)
73
74// Id by default returns a 16-bit random number to be used as a message id. The
75// number is drawn from a cryptographically secure random number generator.
76// This being a variable the function can be reassigned to a custom function.
77// For instance, to make it return a static value for testing:
78//
79//	dns.Id = func() uint16 { return 3 }
80var Id = id
81
82// id returns a 16 bits random number to be used as a
83// message id. The random provided should be good enough.
84func id() uint16 {
85	var output uint16
86	err := binary.Read(rand.Reader, binary.BigEndian, &output)
87	if err != nil {
88		panic("dns: reading random id failed: " + err.Error())
89	}
90	return output
91}
92
93// MsgHdr is a a manually-unpacked version of (id, bits).
94type MsgHdr struct {
95	Id                 uint16
96	Response           bool
97	Opcode             int
98	Authoritative      bool
99	Truncated          bool
100	RecursionDesired   bool
101	RecursionAvailable bool
102	Zero               bool
103	AuthenticatedData  bool
104	CheckingDisabled   bool
105	Rcode              int
106}
107
108// Msg contains the layout of a DNS message.
109type Msg struct {
110	MsgHdr
111	Compress bool       `json:"-"` // If true, the message will be compressed when converted to wire format.
112	Question []Question // Holds the RR(s) of the question section.
113	Answer   []RR       // Holds the RR(s) of the answer section.
114	Ns       []RR       // Holds the RR(s) of the authority section.
115	Extra    []RR       // Holds the RR(s) of the additional section.
116}
117
118// ClassToString is a maps Classes to strings for each CLASS wire type.
119var ClassToString = map[uint16]string{
120	ClassINET:   "IN",
121	ClassCSNET:  "CS",
122	ClassCHAOS:  "CH",
123	ClassHESIOD: "HS",
124	ClassNONE:   "NONE",
125	ClassANY:    "ANY",
126}
127
128// OpcodeToString maps Opcodes to strings.
129var OpcodeToString = map[int]string{
130	OpcodeQuery:  "QUERY",
131	OpcodeIQuery: "IQUERY",
132	OpcodeStatus: "STATUS",
133	OpcodeNotify: "NOTIFY",
134	OpcodeUpdate: "UPDATE",
135}
136
137// RcodeToString maps Rcodes to strings.
138var RcodeToString = map[int]string{
139	RcodeSuccess:        "NOERROR",
140	RcodeFormatError:    "FORMERR",
141	RcodeServerFailure:  "SERVFAIL",
142	RcodeNameError:      "NXDOMAIN",
143	RcodeNotImplemented: "NOTIMP",
144	RcodeRefused:        "REFUSED",
145	RcodeYXDomain:       "YXDOMAIN", // See RFC 2136
146	RcodeYXRrset:        "YXRRSET",
147	RcodeNXRrset:        "NXRRSET",
148	RcodeNotAuth:        "NOTAUTH",
149	RcodeNotZone:        "NOTZONE",
150	RcodeBadSig:         "BADSIG", // Also known as RcodeBadVers, see RFC 6891
151	//	RcodeBadVers:        "BADVERS",
152	RcodeBadKey:    "BADKEY",
153	RcodeBadTime:   "BADTIME",
154	RcodeBadMode:   "BADMODE",
155	RcodeBadName:   "BADNAME",
156	RcodeBadAlg:    "BADALG",
157	RcodeBadTrunc:  "BADTRUNC",
158	RcodeBadCookie: "BADCOOKIE",
159}
160
161// compressionMap is used to allow a more efficient compression map
162// to be used for internal packDomainName calls without changing the
163// signature or functionality of public API.
164//
165// In particular, map[string]uint16 uses 25% less per-entry memory
166// than does map[string]int.
167type compressionMap struct {
168	ext map[string]int    // external callers
169	int map[string]uint16 // internal callers
170}
171
172func (m compressionMap) valid() bool {
173	return m.int != nil || m.ext != nil
174}
175
176func (m compressionMap) insert(s string, pos int) {
177	if m.ext != nil {
178		m.ext[s] = pos
179	} else {
180		m.int[s] = uint16(pos)
181	}
182}
183
184func (m compressionMap) find(s string) (int, bool) {
185	if m.ext != nil {
186		pos, ok := m.ext[s]
187		return pos, ok
188	}
189
190	pos, ok := m.int[s]
191	return int(pos), ok
192}
193
194// Domain names are a sequence of counted strings
195// split at the dots. They end with a zero-length string.
196
197// PackDomainName packs a domain name s into msg[off:].
198// If compression is wanted compress must be true and the compression
199// map needs to hold a mapping between domain names and offsets
200// pointing into msg.
201func PackDomainName(s string, msg []byte, off int, compression map[string]int, compress bool) (off1 int, err error) {
202	return packDomainName(s, msg, off, compressionMap{ext: compression}, compress)
203}
204
205func packDomainName(s string, msg []byte, off int, compression compressionMap, compress bool) (off1 int, err error) {
206	// XXX: A logical copy of this function exists in IsDomainName and
207	// should be kept in sync with this function.
208
209	ls := len(s)
210	if ls == 0 { // Ok, for instance when dealing with update RR without any rdata.
211		return off, nil
212	}
213
214	// If not fully qualified, error out.
215	if !IsFqdn(s) {
216		return len(msg), ErrFqdn
217	}
218
219	// Each dot ends a segment of the name.
220	// We trade each dot byte for a length byte.
221	// Except for escaped dots (\.), which are normal dots.
222	// There is also a trailing zero.
223
224	// Compression
225	pointer := -1
226
227	// Emit sequence of counted strings, chopping at dots.
228	var (
229		begin     int
230		compBegin int
231		compOff   int
232		bs        []byte
233		wasDot    bool
234	)
235loop:
236	for i := 0; i < ls; i++ {
237		var c byte
238		if bs == nil {
239			c = s[i]
240		} else {
241			c = bs[i]
242		}
243
244		switch c {
245		case '\\':
246			if off+1 > len(msg) {
247				return len(msg), ErrBuf
248			}
249
250			if bs == nil {
251				bs = []byte(s)
252			}
253
254			// check for \DDD
255			if i+3 < ls && isDigit(bs[i+1]) && isDigit(bs[i+2]) && isDigit(bs[i+3]) {
256				bs[i] = dddToByte(bs[i+1:])
257				copy(bs[i+1:ls-3], bs[i+4:])
258				ls -= 3
259				compOff += 3
260			} else {
261				copy(bs[i:ls-1], bs[i+1:])
262				ls--
263				compOff++
264			}
265
266			wasDot = false
267		case '.':
268			if wasDot {
269				// two dots back to back is not legal
270				return len(msg), ErrRdata
271			}
272			wasDot = true
273
274			labelLen := i - begin
275			if labelLen >= 1<<6 { // top two bits of length must be clear
276				return len(msg), ErrRdata
277			}
278
279			// off can already (we're in a loop) be bigger than len(msg)
280			// this happens when a name isn't fully qualified
281			if off+1+labelLen > len(msg) {
282				return len(msg), ErrBuf
283			}
284
285			// Don't try to compress '.'
286			// We should only compress when compress is true, but we should also still pick
287			// up names that can be used for *future* compression(s).
288			if compression.valid() && !isRootLabel(s, bs, begin, ls) {
289				if p, ok := compression.find(s[compBegin:]); ok {
290					// The first hit is the longest matching dname
291					// keep the pointer offset we get back and store
292					// the offset of the current name, because that's
293					// where we need to insert the pointer later
294
295					// If compress is true, we're allowed to compress this dname
296					if compress {
297						pointer = p // Where to point to
298						break loop
299					}
300				} else if off < maxCompressionOffset {
301					// Only offsets smaller than maxCompressionOffset can be used.
302					compression.insert(s[compBegin:], off)
303				}
304			}
305
306			// The following is covered by the length check above.
307			msg[off] = byte(labelLen)
308
309			if bs == nil {
310				copy(msg[off+1:], s[begin:i])
311			} else {
312				copy(msg[off+1:], bs[begin:i])
313			}
314			off += 1 + labelLen
315
316			begin = i + 1
317			compBegin = begin + compOff
318		default:
319			wasDot = false
320		}
321	}
322
323	// Root label is special
324	if isRootLabel(s, bs, 0, ls) {
325		return off, nil
326	}
327
328	// If we did compression and we find something add the pointer here
329	if pointer != -1 {
330		// We have two bytes (14 bits) to put the pointer in
331		binary.BigEndian.PutUint16(msg[off:], uint16(pointer^0xC000))
332		return off + 2, nil
333	}
334
335	if off < len(msg) {
336		msg[off] = 0
337	}
338
339	return off + 1, nil
340}
341
342// isRootLabel returns whether s or bs, from off to end, is the root
343// label ".".
344//
345// If bs is nil, s will be checked, otherwise bs will be checked.
346func isRootLabel(s string, bs []byte, off, end int) bool {
347	if bs == nil {
348		return s[off:end] == "."
349	}
350
351	return end-off == 1 && bs[off] == '.'
352}
353
354// Unpack a domain name.
355// In addition to the simple sequences of counted strings above,
356// domain names are allowed to refer to strings elsewhere in the
357// packet, to avoid repeating common suffixes when returning
358// many entries in a single domain.  The pointers are marked
359// by a length byte with the top two bits set.  Ignoring those
360// two bits, that byte and the next give a 14 bit offset from msg[0]
361// where we should pick up the trail.
362// Note that if we jump elsewhere in the packet,
363// we return off1 == the offset after the first pointer we found,
364// which is where the next record will start.
365// In theory, the pointers are only allowed to jump backward.
366// We let them jump anywhere and stop jumping after a while.
367
368// UnpackDomainName unpacks a domain name into a string. It returns
369// the name, the new offset into msg and any error that occurred.
370//
371// When an error is encountered, the unpacked name will be discarded
372// and len(msg) will be returned as the offset.
373func UnpackDomainName(msg []byte, off int) (string, int, error) {
374	s := make([]byte, 0, maxDomainNamePresentationLength)
375	off1 := 0
376	lenmsg := len(msg)
377	budget := maxDomainNameWireOctets
378	ptr := 0 // number of pointers followed
379Loop:
380	for {
381		if off >= lenmsg {
382			return "", lenmsg, ErrBuf
383		}
384		c := int(msg[off])
385		off++
386		switch c & 0xC0 {
387		case 0x00:
388			if c == 0x00 {
389				// end of name
390				break Loop
391			}
392			// literal string
393			if off+c > lenmsg {
394				return "", lenmsg, ErrBuf
395			}
396			budget -= c + 1 // +1 for the label separator
397			if budget <= 0 {
398				return "", lenmsg, ErrLongDomain
399			}
400			for _, b := range msg[off : off+c] {
401				if isDomainNameLabelSpecial(b) {
402					s = append(s, '\\', b)
403				} else if b < ' ' || b > '~' {
404					s = append(s, escapeByte(b)...)
405				} else {
406					s = append(s, b)
407				}
408			}
409			s = append(s, '.')
410			off += c
411		case 0xC0:
412			// pointer to somewhere else in msg.
413			// remember location after first ptr,
414			// since that's how many bytes we consumed.
415			// also, don't follow too many pointers --
416			// maybe there's a loop.
417			if off >= lenmsg {
418				return "", lenmsg, ErrBuf
419			}
420			c1 := msg[off]
421			off++
422			if ptr == 0 {
423				off1 = off
424			}
425			if ptr++; ptr > maxCompressionPointers {
426				return "", lenmsg, &Error{err: "too many compression pointers"}
427			}
428			// pointer should guarantee that it advances and points forwards at least
429			// but the condition on previous three lines guarantees that it's
430			// at least loop-free
431			off = (c^0xC0)<<8 | int(c1)
432		default:
433			// 0x80 and 0x40 are reserved
434			return "", lenmsg, ErrRdata
435		}
436	}
437	if ptr == 0 {
438		off1 = off
439	}
440	if len(s) == 0 {
441		return ".", off1, nil
442	}
443	return string(s), off1, nil
444}
445
446func packTxt(txt []string, msg []byte, offset int, tmp []byte) (int, error) {
447	if len(txt) == 0 {
448		if offset >= len(msg) {
449			return offset, ErrBuf
450		}
451		msg[offset] = 0
452		return offset, nil
453	}
454	var err error
455	for _, s := range txt {
456		if len(s) > len(tmp) {
457			return offset, ErrBuf
458		}
459		offset, err = packTxtString(s, msg, offset, tmp)
460		if err != nil {
461			return offset, err
462		}
463	}
464	return offset, nil
465}
466
467func packTxtString(s string, msg []byte, offset int, tmp []byte) (int, error) {
468	lenByteOffset := offset
469	if offset >= len(msg) || len(s) > len(tmp) {
470		return offset, ErrBuf
471	}
472	offset++
473	bs := tmp[:len(s)]
474	copy(bs, s)
475	for i := 0; i < len(bs); i++ {
476		if len(msg) <= offset {
477			return offset, ErrBuf
478		}
479		if bs[i] == '\\' {
480			i++
481			if i == len(bs) {
482				break
483			}
484			// check for \DDD
485			if i+2 < len(bs) && isDigit(bs[i]) && isDigit(bs[i+1]) && isDigit(bs[i+2]) {
486				msg[offset] = dddToByte(bs[i:])
487				i += 2
488			} else {
489				msg[offset] = bs[i]
490			}
491		} else {
492			msg[offset] = bs[i]
493		}
494		offset++
495	}
496	l := offset - lenByteOffset - 1
497	if l > 255 {
498		return offset, &Error{err: "string exceeded 255 bytes in txt"}
499	}
500	msg[lenByteOffset] = byte(l)
501	return offset, nil
502}
503
504func packOctetString(s string, msg []byte, offset int, tmp []byte) (int, error) {
505	if offset >= len(msg) || len(s) > len(tmp) {
506		return offset, ErrBuf
507	}
508	bs := tmp[:len(s)]
509	copy(bs, s)
510	for i := 0; i < len(bs); i++ {
511		if len(msg) <= offset {
512			return offset, ErrBuf
513		}
514		if bs[i] == '\\' {
515			i++
516			if i == len(bs) {
517				break
518			}
519			// check for \DDD
520			if i+2 < len(bs) && isDigit(bs[i]) && isDigit(bs[i+1]) && isDigit(bs[i+2]) {
521				msg[offset] = dddToByte(bs[i:])
522				i += 2
523			} else {
524				msg[offset] = bs[i]
525			}
526		} else {
527			msg[offset] = bs[i]
528		}
529		offset++
530	}
531	return offset, nil
532}
533
534func unpackTxt(msg []byte, off0 int) (ss []string, off int, err error) {
535	off = off0
536	var s string
537	for off < len(msg) && err == nil {
538		s, off, err = unpackString(msg, off)
539		if err == nil {
540			ss = append(ss, s)
541		}
542	}
543	return
544}
545
546// Helpers for dealing with escaped bytes
547func isDigit(b byte) bool { return b >= '0' && b <= '9' }
548
549func dddToByte(s []byte) byte {
550	_ = s[2] // bounds check hint to compiler; see golang.org/issue/14808
551	return byte((s[0]-'0')*100 + (s[1]-'0')*10 + (s[2] - '0'))
552}
553
554func dddStringToByte(s string) byte {
555	_ = s[2] // bounds check hint to compiler; see golang.org/issue/14808
556	return byte((s[0]-'0')*100 + (s[1]-'0')*10 + (s[2] - '0'))
557}
558
559// Helper function for packing and unpacking
560func intToBytes(i *big.Int, length int) []byte {
561	buf := i.Bytes()
562	if len(buf) < length {
563		b := make([]byte, length)
564		copy(b[length-len(buf):], buf)
565		return b
566	}
567	return buf
568}
569
570// PackRR packs a resource record rr into msg[off:].
571// See PackDomainName for documentation about the compression.
572func PackRR(rr RR, msg []byte, off int, compression map[string]int, compress bool) (off1 int, err error) {
573	headerEnd, off1, err := packRR(rr, msg, off, compressionMap{ext: compression}, compress)
574	if err == nil {
575		// packRR no longer sets the Rdlength field on the rr, but
576		// callers might be expecting it so we set it here.
577		rr.Header().Rdlength = uint16(off1 - headerEnd)
578	}
579	return off1, err
580}
581
582func packRR(rr RR, msg []byte, off int, compression compressionMap, compress bool) (headerEnd int, off1 int, err error) {
583	if rr == nil {
584		return len(msg), len(msg), &Error{err: "nil rr"}
585	}
586
587	headerEnd, err = rr.Header().packHeader(msg, off, compression, compress)
588	if err != nil {
589		return headerEnd, len(msg), err
590	}
591
592	off1, err = rr.pack(msg, headerEnd, compression, compress)
593	if err != nil {
594		return headerEnd, len(msg), err
595	}
596
597	rdlength := off1 - headerEnd
598	if int(uint16(rdlength)) != rdlength { // overflow
599		return headerEnd, len(msg), ErrRdata
600	}
601
602	// The RDLENGTH field is the last field in the header and we set it here.
603	binary.BigEndian.PutUint16(msg[headerEnd-2:], uint16(rdlength))
604	return headerEnd, off1, nil
605}
606
607// UnpackRR unpacks msg[off:] into an RR.
608func UnpackRR(msg []byte, off int) (rr RR, off1 int, err error) {
609	h, off, msg, err := unpackHeader(msg, off)
610	if err != nil {
611		return nil, len(msg), err
612	}
613
614	return UnpackRRWithHeader(h, msg, off)
615}
616
617// UnpackRRWithHeader unpacks the record type specific payload given an existing
618// RR_Header.
619func UnpackRRWithHeader(h RR_Header, msg []byte, off int) (rr RR, off1 int, err error) {
620	if newFn, ok := TypeToRR[h.Rrtype]; ok {
621		rr = newFn()
622		*rr.Header() = h
623	} else {
624		rr = &RFC3597{Hdr: h}
625	}
626
627	if off < 0 || off > len(msg) {
628		return &h, off, &Error{err: "bad off"}
629	}
630
631	end := off + int(h.Rdlength)
632	if end < off || end > len(msg) {
633		return &h, end, &Error{err: "bad rdlength"}
634	}
635
636	if noRdata(h) {
637		return rr, off, nil
638	}
639
640	off, err = rr.unpack(msg, off)
641	if err != nil {
642		return nil, end, err
643	}
644	if off != end {
645		return &h, end, &Error{err: "bad rdlength"}
646	}
647
648	return rr, off, nil
649}
650
651// unpackRRslice unpacks msg[off:] into an []RR.
652// If we cannot unpack the whole array, then it will return nil
653func unpackRRslice(l int, msg []byte, off int) (dst1 []RR, off1 int, err error) {
654	var r RR
655	// Don't pre-allocate, l may be under attacker control
656	var dst []RR
657	for i := 0; i < l; i++ {
658		off1 := off
659		r, off, err = UnpackRR(msg, off)
660		if err != nil {
661			off = len(msg)
662			break
663		}
664		// If offset does not increase anymore, l is a lie
665		if off1 == off {
666			break
667		}
668		dst = append(dst, r)
669	}
670	if err != nil && off == len(msg) {
671		dst = nil
672	}
673	return dst, off, err
674}
675
676// Convert a MsgHdr to a string, with dig-like headers:
677//
678//;; opcode: QUERY, status: NOERROR, id: 48404
679//
680//;; flags: qr aa rd ra;
681func (h *MsgHdr) String() string {
682	if h == nil {
683		return "<nil> MsgHdr"
684	}
685
686	s := ";; opcode: " + OpcodeToString[h.Opcode]
687	s += ", status: " + RcodeToString[h.Rcode]
688	s += ", id: " + strconv.Itoa(int(h.Id)) + "\n"
689
690	s += ";; flags:"
691	if h.Response {
692		s += " qr"
693	}
694	if h.Authoritative {
695		s += " aa"
696	}
697	if h.Truncated {
698		s += " tc"
699	}
700	if h.RecursionDesired {
701		s += " rd"
702	}
703	if h.RecursionAvailable {
704		s += " ra"
705	}
706	if h.Zero { // Hmm
707		s += " z"
708	}
709	if h.AuthenticatedData {
710		s += " ad"
711	}
712	if h.CheckingDisabled {
713		s += " cd"
714	}
715
716	s += ";"
717	return s
718}
719
720// Pack packs a Msg: it is converted to to wire format.
721// If the dns.Compress is true the message will be in compressed wire format.
722func (dns *Msg) Pack() (msg []byte, err error) {
723	return dns.PackBuffer(nil)
724}
725
726// PackBuffer packs a Msg, using the given buffer buf. If buf is too small a new buffer is allocated.
727func (dns *Msg) PackBuffer(buf []byte) (msg []byte, err error) {
728	// If this message can't be compressed, avoid filling the
729	// compression map and creating garbage.
730	if dns.Compress && dns.isCompressible() {
731		compression := make(map[string]uint16) // Compression pointer mappings.
732		return dns.packBufferWithCompressionMap(buf, compressionMap{int: compression}, true)
733	}
734
735	return dns.packBufferWithCompressionMap(buf, compressionMap{}, false)
736}
737
738// packBufferWithCompressionMap packs a Msg, using the given buffer buf.
739func (dns *Msg) packBufferWithCompressionMap(buf []byte, compression compressionMap, compress bool) (msg []byte, err error) {
740	if dns.Rcode < 0 || dns.Rcode > 0xFFF {
741		return nil, ErrRcode
742	}
743
744	// Set extended rcode unconditionally if we have an opt, this will allow
745	// resetting the extended rcode bits if they need to.
746	if opt := dns.IsEdns0(); opt != nil {
747		opt.SetExtendedRcode(uint16(dns.Rcode))
748	} else if dns.Rcode > 0xF {
749		// If Rcode is an extended one and opt is nil, error out.
750		return nil, ErrExtendedRcode
751	}
752
753	// Convert convenient Msg into wire-like Header.
754	var dh Header
755	dh.Id = dns.Id
756	dh.Bits = uint16(dns.Opcode)<<11 | uint16(dns.Rcode&0xF)
757	if dns.Response {
758		dh.Bits |= _QR
759	}
760	if dns.Authoritative {
761		dh.Bits |= _AA
762	}
763	if dns.Truncated {
764		dh.Bits |= _TC
765	}
766	if dns.RecursionDesired {
767		dh.Bits |= _RD
768	}
769	if dns.RecursionAvailable {
770		dh.Bits |= _RA
771	}
772	if dns.Zero {
773		dh.Bits |= _Z
774	}
775	if dns.AuthenticatedData {
776		dh.Bits |= _AD
777	}
778	if dns.CheckingDisabled {
779		dh.Bits |= _CD
780	}
781
782	dh.Qdcount = uint16(len(dns.Question))
783	dh.Ancount = uint16(len(dns.Answer))
784	dh.Nscount = uint16(len(dns.Ns))
785	dh.Arcount = uint16(len(dns.Extra))
786
787	// We need the uncompressed length here, because we first pack it and then compress it.
788	msg = buf
789	uncompressedLen := msgLenWithCompressionMap(dns, nil)
790	if packLen := uncompressedLen + 1; len(msg) < packLen {
791		msg = make([]byte, packLen)
792	}
793
794	// Pack it in: header and then the pieces.
795	off := 0
796	off, err = dh.pack(msg, off, compression, compress)
797	if err != nil {
798		return nil, err
799	}
800	for _, r := range dns.Question {
801		off, err = r.pack(msg, off, compression, compress)
802		if err != nil {
803			return nil, err
804		}
805	}
806	for _, r := range dns.Answer {
807		_, off, err = packRR(r, msg, off, compression, compress)
808		if err != nil {
809			return nil, err
810		}
811	}
812	for _, r := range dns.Ns {
813		_, off, err = packRR(r, msg, off, compression, compress)
814		if err != nil {
815			return nil, err
816		}
817	}
818	for _, r := range dns.Extra {
819		_, off, err = packRR(r, msg, off, compression, compress)
820		if err != nil {
821			return nil, err
822		}
823	}
824	return msg[:off], nil
825}
826
827func (dns *Msg) unpack(dh Header, msg []byte, off int) (err error) {
828	// If we are at the end of the message we should return *just* the
829	// header. This can still be useful to the caller. 9.9.9.9 sends these
830	// when responding with REFUSED for instance.
831	if off == len(msg) {
832		// reset sections before returning
833		dns.Question, dns.Answer, dns.Ns, dns.Extra = nil, nil, nil, nil
834		return nil
835	}
836
837	// Qdcount, Ancount, Nscount, Arcount can't be trusted, as they are
838	// attacker controlled. This means we can't use them to pre-allocate
839	// slices.
840	dns.Question = nil
841	for i := 0; i < int(dh.Qdcount); i++ {
842		off1 := off
843		var q Question
844		q, off, err = unpackQuestion(msg, off)
845		if err != nil {
846			return err
847		}
848		if off1 == off { // Offset does not increase anymore, dh.Qdcount is a lie!
849			dh.Qdcount = uint16(i)
850			break
851		}
852		dns.Question = append(dns.Question, q)
853	}
854
855	dns.Answer, off, err = unpackRRslice(int(dh.Ancount), msg, off)
856	// The header counts might have been wrong so we need to update it
857	dh.Ancount = uint16(len(dns.Answer))
858	if err == nil {
859		dns.Ns, off, err = unpackRRslice(int(dh.Nscount), msg, off)
860	}
861	// The header counts might have been wrong so we need to update it
862	dh.Nscount = uint16(len(dns.Ns))
863	if err == nil {
864		dns.Extra, off, err = unpackRRslice(int(dh.Arcount), msg, off)
865	}
866	// The header counts might have been wrong so we need to update it
867	dh.Arcount = uint16(len(dns.Extra))
868
869	// Set extended Rcode
870	if opt := dns.IsEdns0(); opt != nil {
871		dns.Rcode |= opt.ExtendedRcode()
872	}
873
874	if off != len(msg) {
875		// TODO(miek) make this an error?
876		// use PackOpt to let people tell how detailed the error reporting should be?
877		// println("dns: extra bytes in dns packet", off, "<", len(msg))
878	}
879	return err
880
881}
882
883// Unpack unpacks a binary message to a Msg structure.
884func (dns *Msg) Unpack(msg []byte) (err error) {
885	dh, off, err := unpackMsgHdr(msg, 0)
886	if err != nil {
887		return err
888	}
889
890	dns.setHdr(dh)
891	return dns.unpack(dh, msg, off)
892}
893
894// Convert a complete message to a string with dig-like output.
895func (dns *Msg) String() string {
896	if dns == nil {
897		return "<nil> MsgHdr"
898	}
899	s := dns.MsgHdr.String() + " "
900	s += "QUERY: " + strconv.Itoa(len(dns.Question)) + ", "
901	s += "ANSWER: " + strconv.Itoa(len(dns.Answer)) + ", "
902	s += "AUTHORITY: " + strconv.Itoa(len(dns.Ns)) + ", "
903	s += "ADDITIONAL: " + strconv.Itoa(len(dns.Extra)) + "\n"
904	if len(dns.Question) > 0 {
905		s += "\n;; QUESTION SECTION:\n"
906		for _, r := range dns.Question {
907			s += r.String() + "\n"
908		}
909	}
910	if len(dns.Answer) > 0 {
911		s += "\n;; ANSWER SECTION:\n"
912		for _, r := range dns.Answer {
913			if r != nil {
914				s += r.String() + "\n"
915			}
916		}
917	}
918	if len(dns.Ns) > 0 {
919		s += "\n;; AUTHORITY SECTION:\n"
920		for _, r := range dns.Ns {
921			if r != nil {
922				s += r.String() + "\n"
923			}
924		}
925	}
926	if len(dns.Extra) > 0 {
927		s += "\n;; ADDITIONAL SECTION:\n"
928		for _, r := range dns.Extra {
929			if r != nil {
930				s += r.String() + "\n"
931			}
932		}
933	}
934	return s
935}
936
937// isCompressible returns whether the msg may be compressible.
938func (dns *Msg) isCompressible() bool {
939	// If we only have one question, there is nothing we can ever compress.
940	return len(dns.Question) > 1 || len(dns.Answer) > 0 ||
941		len(dns.Ns) > 0 || len(dns.Extra) > 0
942}
943
944// Len returns the message length when in (un)compressed wire format.
945// If dns.Compress is true compression it is taken into account. Len()
946// is provided to be a faster way to get the size of the resulting packet,
947// than packing it, measuring the size and discarding the buffer.
948func (dns *Msg) Len() int {
949	// If this message can't be compressed, avoid filling the
950	// compression map and creating garbage.
951	if dns.Compress && dns.isCompressible() {
952		compression := make(map[string]struct{})
953		return msgLenWithCompressionMap(dns, compression)
954	}
955
956	return msgLenWithCompressionMap(dns, nil)
957}
958
959func msgLenWithCompressionMap(dns *Msg, compression map[string]struct{}) int {
960	l := headerSize
961
962	for _, r := range dns.Question {
963		l += r.len(l, compression)
964	}
965	for _, r := range dns.Answer {
966		if r != nil {
967			l += r.len(l, compression)
968		}
969	}
970	for _, r := range dns.Ns {
971		if r != nil {
972			l += r.len(l, compression)
973		}
974	}
975	for _, r := range dns.Extra {
976		if r != nil {
977			l += r.len(l, compression)
978		}
979	}
980
981	return l
982}
983
984func domainNameLen(s string, off int, compression map[string]struct{}, compress bool) int {
985	if s == "" || s == "." {
986		return 1
987	}
988
989	escaped := strings.Contains(s, "\\")
990
991	if compression != nil && (compress || off < maxCompressionOffset) {
992		// compressionLenSearch will insert the entry into the compression
993		// map if it doesn't contain it.
994		if l, ok := compressionLenSearch(compression, s, off); ok && compress {
995			if escaped {
996				return escapedNameLen(s[:l]) + 2
997			}
998
999			return l + 2
1000		}
1001	}
1002
1003	if escaped {
1004		return escapedNameLen(s) + 1
1005	}
1006
1007	return len(s) + 1
1008}
1009
1010func escapedNameLen(s string) int {
1011	nameLen := len(s)
1012	for i := 0; i < len(s); i++ {
1013		if s[i] != '\\' {
1014			continue
1015		}
1016
1017		if i+3 < len(s) && isDigit(s[i+1]) && isDigit(s[i+2]) && isDigit(s[i+3]) {
1018			nameLen -= 3
1019			i += 3
1020		} else {
1021			nameLen--
1022			i++
1023		}
1024	}
1025
1026	return nameLen
1027}
1028
1029func compressionLenSearch(c map[string]struct{}, s string, msgOff int) (int, bool) {
1030	for off, end := 0, false; !end; off, end = NextLabel(s, off) {
1031		if _, ok := c[s[off:]]; ok {
1032			return off, true
1033		}
1034
1035		if msgOff+off < maxCompressionOffset {
1036			c[s[off:]] = struct{}{}
1037		}
1038	}
1039
1040	return 0, false
1041}
1042
1043// Copy returns a new RR which is a deep-copy of r.
1044func Copy(r RR) RR { return r.copy() }
1045
1046// Len returns the length (in octets) of the uncompressed RR in wire format.
1047func Len(r RR) int { return r.len(0, nil) }
1048
1049// Copy returns a new *Msg which is a deep-copy of dns.
1050func (dns *Msg) Copy() *Msg { return dns.CopyTo(new(Msg)) }
1051
1052// CopyTo copies the contents to the provided message using a deep-copy and returns the copy.
1053func (dns *Msg) CopyTo(r1 *Msg) *Msg {
1054	r1.MsgHdr = dns.MsgHdr
1055	r1.Compress = dns.Compress
1056
1057	if len(dns.Question) > 0 {
1058		r1.Question = make([]Question, len(dns.Question))
1059		copy(r1.Question, dns.Question) // TODO(miek): Question is an immutable value, ok to do a shallow-copy
1060	}
1061
1062	rrArr := make([]RR, len(dns.Answer)+len(dns.Ns)+len(dns.Extra))
1063	r1.Answer, rrArr = rrArr[:0:len(dns.Answer)], rrArr[len(dns.Answer):]
1064	r1.Ns, rrArr = rrArr[:0:len(dns.Ns)], rrArr[len(dns.Ns):]
1065	r1.Extra = rrArr[:0:len(dns.Extra)]
1066
1067	for _, r := range dns.Answer {
1068		r1.Answer = append(r1.Answer, r.copy())
1069	}
1070
1071	for _, r := range dns.Ns {
1072		r1.Ns = append(r1.Ns, r.copy())
1073	}
1074
1075	for _, r := range dns.Extra {
1076		r1.Extra = append(r1.Extra, r.copy())
1077	}
1078
1079	return r1
1080}
1081
1082func (q *Question) pack(msg []byte, off int, compression compressionMap, compress bool) (int, error) {
1083	off, err := packDomainName(q.Name, msg, off, compression, compress)
1084	if err != nil {
1085		return off, err
1086	}
1087	off, err = packUint16(q.Qtype, msg, off)
1088	if err != nil {
1089		return off, err
1090	}
1091	off, err = packUint16(q.Qclass, msg, off)
1092	if err != nil {
1093		return off, err
1094	}
1095	return off, nil
1096}
1097
1098func unpackQuestion(msg []byte, off int) (Question, int, error) {
1099	var (
1100		q   Question
1101		err error
1102	)
1103	q.Name, off, err = UnpackDomainName(msg, off)
1104	if err != nil {
1105		return q, off, err
1106	}
1107	if off == len(msg) {
1108		return q, off, nil
1109	}
1110	q.Qtype, off, err = unpackUint16(msg, off)
1111	if err != nil {
1112		return q, off, err
1113	}
1114	if off == len(msg) {
1115		return q, off, nil
1116	}
1117	q.Qclass, off, err = unpackUint16(msg, off)
1118	if off == len(msg) {
1119		return q, off, nil
1120	}
1121	return q, off, err
1122}
1123
1124func (dh *Header) pack(msg []byte, off int, compression compressionMap, compress bool) (int, error) {
1125	off, err := packUint16(dh.Id, msg, off)
1126	if err != nil {
1127		return off, err
1128	}
1129	off, err = packUint16(dh.Bits, msg, off)
1130	if err != nil {
1131		return off, err
1132	}
1133	off, err = packUint16(dh.Qdcount, msg, off)
1134	if err != nil {
1135		return off, err
1136	}
1137	off, err = packUint16(dh.Ancount, msg, off)
1138	if err != nil {
1139		return off, err
1140	}
1141	off, err = packUint16(dh.Nscount, msg, off)
1142	if err != nil {
1143		return off, err
1144	}
1145	off, err = packUint16(dh.Arcount, msg, off)
1146	if err != nil {
1147		return off, err
1148	}
1149	return off, nil
1150}
1151
1152func unpackMsgHdr(msg []byte, off int) (Header, int, error) {
1153	var (
1154		dh  Header
1155		err error
1156	)
1157	dh.Id, off, err = unpackUint16(msg, off)
1158	if err != nil {
1159		return dh, off, err
1160	}
1161	dh.Bits, off, err = unpackUint16(msg, off)
1162	if err != nil {
1163		return dh, off, err
1164	}
1165	dh.Qdcount, off, err = unpackUint16(msg, off)
1166	if err != nil {
1167		return dh, off, err
1168	}
1169	dh.Ancount, off, err = unpackUint16(msg, off)
1170	if err != nil {
1171		return dh, off, err
1172	}
1173	dh.Nscount, off, err = unpackUint16(msg, off)
1174	if err != nil {
1175		return dh, off, err
1176	}
1177	dh.Arcount, off, err = unpackUint16(msg, off)
1178	if err != nil {
1179		return dh, off, err
1180	}
1181	return dh, off, nil
1182}
1183
1184// setHdr set the header in the dns using the binary data in dh.
1185func (dns *Msg) setHdr(dh Header) {
1186	dns.Id = dh.Id
1187	dns.Response = dh.Bits&_QR != 0
1188	dns.Opcode = int(dh.Bits>>11) & 0xF
1189	dns.Authoritative = dh.Bits&_AA != 0
1190	dns.Truncated = dh.Bits&_TC != 0
1191	dns.RecursionDesired = dh.Bits&_RD != 0
1192	dns.RecursionAvailable = dh.Bits&_RA != 0
1193	dns.Zero = dh.Bits&_Z != 0 // _Z covers the zero bit, which should be zero; not sure why we set it to the opposite.
1194	dns.AuthenticatedData = dh.Bits&_AD != 0
1195	dns.CheckingDisabled = dh.Bits&_CD != 0
1196	dns.Rcode = int(dh.Bits & 0xF)
1197}
1198