1// Copyright 2009 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// DNS packet assembly.  See RFC 1035.
6//
7// This is intended to support name resolution during Dial.
8// It doesn't have to be blazing fast.
9//
10// Each message structure has a Walk method that is used by
11// a generic pack/unpack routine. Thus, if in the future we need
12// to define new message structs, no new pack/unpack/printing code
13// needs to be written.
14//
15// The first half of this file defines the DNS message formats.
16// The second half implements the conversion to and from wire format.
17// A few of the structure elements have string tags to aid the
18// generic pack/unpack routines.
19//
20// TODO(rsc):  There are enough names defined in this file that they're all
21// prefixed with dns.  Perhaps put this in its own package later.
22
23package net
24
25// Packet formats
26
27// Wire constants.
28const (
29	// valid dnsRR_Header.Rrtype and dnsQuestion.qtype
30	dnsTypeA     = 1
31	dnsTypeNS    = 2
32	dnsTypeMD    = 3
33	dnsTypeMF    = 4
34	dnsTypeCNAME = 5
35	dnsTypeSOA   = 6
36	dnsTypeMB    = 7
37	dnsTypeMG    = 8
38	dnsTypeMR    = 9
39	dnsTypeNULL  = 10
40	dnsTypeWKS   = 11
41	dnsTypePTR   = 12
42	dnsTypeHINFO = 13
43	dnsTypeMINFO = 14
44	dnsTypeMX    = 15
45	dnsTypeTXT   = 16
46	dnsTypeAAAA  = 28
47	dnsTypeSRV   = 33
48
49	// valid dnsQuestion.qtype only
50	dnsTypeAXFR  = 252
51	dnsTypeMAILB = 253
52	dnsTypeMAILA = 254
53	dnsTypeALL   = 255
54
55	// valid dnsQuestion.qclass
56	dnsClassINET   = 1
57	dnsClassCSNET  = 2
58	dnsClassCHAOS  = 3
59	dnsClassHESIOD = 4
60	dnsClassANY    = 255
61
62	// dnsMsg.rcode
63	dnsRcodeSuccess        = 0
64	dnsRcodeFormatError    = 1
65	dnsRcodeServerFailure  = 2
66	dnsRcodeNameError      = 3
67	dnsRcodeNotImplemented = 4
68	dnsRcodeRefused        = 5
69)
70
71// A dnsStruct describes how to iterate over its fields to emulate
72// reflective marshalling.
73type dnsStruct interface {
74	// Walk iterates over fields of a structure and calls f
75	// with a reference to that field, the name of the field
76	// and a tag ("", "domain", "ipv4", "ipv6") specifying
77	// particular encodings. Possible concrete types
78	// for v are *uint16, *uint32, *string, or []byte, and
79	// *int, *bool in the case of dnsMsgHdr.
80	// Whenever f returns false, Walk must stop and return
81	// false, and otherwise return true.
82	Walk(f func(v interface{}, name, tag string) (ok bool)) (ok bool)
83}
84
85// The wire format for the DNS packet header.
86type dnsHeader struct {
87	Id                                 uint16
88	Bits                               uint16
89	Qdcount, Ancount, Nscount, Arcount uint16
90}
91
92func (h *dnsHeader) Walk(f func(v interface{}, name, tag string) bool) bool {
93	return f(&h.Id, "Id", "") &&
94		f(&h.Bits, "Bits", "") &&
95		f(&h.Qdcount, "Qdcount", "") &&
96		f(&h.Ancount, "Ancount", "") &&
97		f(&h.Nscount, "Nscount", "") &&
98		f(&h.Arcount, "Arcount", "")
99}
100
101const (
102	// dnsHeader.Bits
103	_QR = 1 << 15 // query/response (response=1)
104	_AA = 1 << 10 // authoritative
105	_TC = 1 << 9  // truncated
106	_RD = 1 << 8  // recursion desired
107	_RA = 1 << 7  // recursion available
108)
109
110// DNS queries.
111type dnsQuestion struct {
112	Name   string `net:"domain-name"` // `net:"domain-name"` specifies encoding; see packers below
113	Qtype  uint16
114	Qclass uint16
115}
116
117func (q *dnsQuestion) Walk(f func(v interface{}, name, tag string) bool) bool {
118	return f(&q.Name, "Name", "domain") &&
119		f(&q.Qtype, "Qtype", "") &&
120		f(&q.Qclass, "Qclass", "")
121}
122
123// DNS responses (resource records).
124// There are many types of messages,
125// but they all share the same header.
126type dnsRR_Header struct {
127	Name     string `net:"domain-name"`
128	Rrtype   uint16
129	Class    uint16
130	Ttl      uint32
131	Rdlength uint16 // length of data after header
132}
133
134func (h *dnsRR_Header) Header() *dnsRR_Header {
135	return h
136}
137
138func (h *dnsRR_Header) Walk(f func(v interface{}, name, tag string) bool) bool {
139	return f(&h.Name, "Name", "domain") &&
140		f(&h.Rrtype, "Rrtype", "") &&
141		f(&h.Class, "Class", "") &&
142		f(&h.Ttl, "Ttl", "") &&
143		f(&h.Rdlength, "Rdlength", "")
144}
145
146type dnsRR interface {
147	dnsStruct
148	Header() *dnsRR_Header
149}
150
151// Specific DNS RR formats for each query type.
152
153type dnsRR_CNAME struct {
154	Hdr   dnsRR_Header
155	Cname string `net:"domain-name"`
156}
157
158func (rr *dnsRR_CNAME) Header() *dnsRR_Header {
159	return &rr.Hdr
160}
161
162func (rr *dnsRR_CNAME) Walk(f func(v interface{}, name, tag string) bool) bool {
163	return rr.Hdr.Walk(f) && f(&rr.Cname, "Cname", "domain")
164}
165
166type dnsRR_HINFO struct {
167	Hdr dnsRR_Header
168	Cpu string
169	Os  string
170}
171
172func (rr *dnsRR_HINFO) Header() *dnsRR_Header {
173	return &rr.Hdr
174}
175
176func (rr *dnsRR_HINFO) Walk(f func(v interface{}, name, tag string) bool) bool {
177	return rr.Hdr.Walk(f) && f(&rr.Cpu, "Cpu", "") && f(&rr.Os, "Os", "")
178}
179
180type dnsRR_MB struct {
181	Hdr dnsRR_Header
182	Mb  string `net:"domain-name"`
183}
184
185func (rr *dnsRR_MB) Header() *dnsRR_Header {
186	return &rr.Hdr
187}
188
189func (rr *dnsRR_MB) Walk(f func(v interface{}, name, tag string) bool) bool {
190	return rr.Hdr.Walk(f) && f(&rr.Mb, "Mb", "domain")
191}
192
193type dnsRR_MG struct {
194	Hdr dnsRR_Header
195	Mg  string `net:"domain-name"`
196}
197
198func (rr *dnsRR_MG) Header() *dnsRR_Header {
199	return &rr.Hdr
200}
201
202func (rr *dnsRR_MG) Walk(f func(v interface{}, name, tag string) bool) bool {
203	return rr.Hdr.Walk(f) && f(&rr.Mg, "Mg", "domain")
204}
205
206type dnsRR_MINFO struct {
207	Hdr   dnsRR_Header
208	Rmail string `net:"domain-name"`
209	Email string `net:"domain-name"`
210}
211
212func (rr *dnsRR_MINFO) Header() *dnsRR_Header {
213	return &rr.Hdr
214}
215
216func (rr *dnsRR_MINFO) Walk(f func(v interface{}, name, tag string) bool) bool {
217	return rr.Hdr.Walk(f) && f(&rr.Rmail, "Rmail", "domain") && f(&rr.Email, "Email", "domain")
218}
219
220type dnsRR_MR struct {
221	Hdr dnsRR_Header
222	Mr  string `net:"domain-name"`
223}
224
225func (rr *dnsRR_MR) Header() *dnsRR_Header {
226	return &rr.Hdr
227}
228
229func (rr *dnsRR_MR) Walk(f func(v interface{}, name, tag string) bool) bool {
230	return rr.Hdr.Walk(f) && f(&rr.Mr, "Mr", "domain")
231}
232
233type dnsRR_MX struct {
234	Hdr  dnsRR_Header
235	Pref uint16
236	Mx   string `net:"domain-name"`
237}
238
239func (rr *dnsRR_MX) Header() *dnsRR_Header {
240	return &rr.Hdr
241}
242
243func (rr *dnsRR_MX) Walk(f func(v interface{}, name, tag string) bool) bool {
244	return rr.Hdr.Walk(f) && f(&rr.Pref, "Pref", "") && f(&rr.Mx, "Mx", "domain")
245}
246
247type dnsRR_NS struct {
248	Hdr dnsRR_Header
249	Ns  string `net:"domain-name"`
250}
251
252func (rr *dnsRR_NS) Header() *dnsRR_Header {
253	return &rr.Hdr
254}
255
256func (rr *dnsRR_NS) Walk(f func(v interface{}, name, tag string) bool) bool {
257	return rr.Hdr.Walk(f) && f(&rr.Ns, "Ns", "domain")
258}
259
260type dnsRR_PTR struct {
261	Hdr dnsRR_Header
262	Ptr string `net:"domain-name"`
263}
264
265func (rr *dnsRR_PTR) Header() *dnsRR_Header {
266	return &rr.Hdr
267}
268
269func (rr *dnsRR_PTR) Walk(f func(v interface{}, name, tag string) bool) bool {
270	return rr.Hdr.Walk(f) && f(&rr.Ptr, "Ptr", "domain")
271}
272
273type dnsRR_SOA struct {
274	Hdr     dnsRR_Header
275	Ns      string `net:"domain-name"`
276	Mbox    string `net:"domain-name"`
277	Serial  uint32
278	Refresh uint32
279	Retry   uint32
280	Expire  uint32
281	Minttl  uint32
282}
283
284func (rr *dnsRR_SOA) Header() *dnsRR_Header {
285	return &rr.Hdr
286}
287
288func (rr *dnsRR_SOA) Walk(f func(v interface{}, name, tag string) bool) bool {
289	return rr.Hdr.Walk(f) &&
290		f(&rr.Ns, "Ns", "domain") &&
291		f(&rr.Mbox, "Mbox", "domain") &&
292		f(&rr.Serial, "Serial", "") &&
293		f(&rr.Refresh, "Refresh", "") &&
294		f(&rr.Retry, "Retry", "") &&
295		f(&rr.Expire, "Expire", "") &&
296		f(&rr.Minttl, "Minttl", "")
297}
298
299type dnsRR_TXT struct {
300	Hdr dnsRR_Header
301	Txt string // not domain name
302}
303
304func (rr *dnsRR_TXT) Header() *dnsRR_Header {
305	return &rr.Hdr
306}
307
308func (rr *dnsRR_TXT) Walk(f func(v interface{}, name, tag string) bool) bool {
309	if !rr.Hdr.Walk(f) {
310		return false
311	}
312	var n uint16 = 0
313	for n < rr.Hdr.Rdlength {
314		var txt string
315		if !f(&txt, "Txt", "") {
316			return false
317		}
318		// more bytes than rr.Hdr.Rdlength said there woudld be
319		if rr.Hdr.Rdlength-n < uint16(len(txt))+1 {
320			return false
321		}
322		n += uint16(len(txt)) + 1
323		rr.Txt += txt
324	}
325	return true
326}
327
328type dnsRR_SRV struct {
329	Hdr      dnsRR_Header
330	Priority uint16
331	Weight   uint16
332	Port     uint16
333	Target   string `net:"domain-name"`
334}
335
336func (rr *dnsRR_SRV) Header() *dnsRR_Header {
337	return &rr.Hdr
338}
339
340func (rr *dnsRR_SRV) Walk(f func(v interface{}, name, tag string) bool) bool {
341	return rr.Hdr.Walk(f) &&
342		f(&rr.Priority, "Priority", "") &&
343		f(&rr.Weight, "Weight", "") &&
344		f(&rr.Port, "Port", "") &&
345		f(&rr.Target, "Target", "domain")
346}
347
348type dnsRR_A struct {
349	Hdr dnsRR_Header
350	A   uint32 `net:"ipv4"`
351}
352
353func (rr *dnsRR_A) Header() *dnsRR_Header {
354	return &rr.Hdr
355}
356
357func (rr *dnsRR_A) Walk(f func(v interface{}, name, tag string) bool) bool {
358	return rr.Hdr.Walk(f) && f(&rr.A, "A", "ipv4")
359}
360
361type dnsRR_AAAA struct {
362	Hdr  dnsRR_Header
363	AAAA [16]byte `net:"ipv6"`
364}
365
366func (rr *dnsRR_AAAA) Header() *dnsRR_Header {
367	return &rr.Hdr
368}
369
370func (rr *dnsRR_AAAA) Walk(f func(v interface{}, name, tag string) bool) bool {
371	return rr.Hdr.Walk(f) && f(rr.AAAA[:], "AAAA", "ipv6")
372}
373
374// Packing and unpacking.
375//
376// All the packers and unpackers take a (msg []byte, off int)
377// and return (off1 int, ok bool).  If they return ok==false, they
378// also return off1==len(msg), so that the next unpacker will
379// also fail.  This lets us avoid checks of ok until the end of a
380// packing sequence.
381
382// Map of constructors for each RR wire type.
383var rr_mk = map[int]func() dnsRR{
384	dnsTypeCNAME: func() dnsRR { return new(dnsRR_CNAME) },
385	dnsTypeHINFO: func() dnsRR { return new(dnsRR_HINFO) },
386	dnsTypeMB:    func() dnsRR { return new(dnsRR_MB) },
387	dnsTypeMG:    func() dnsRR { return new(dnsRR_MG) },
388	dnsTypeMINFO: func() dnsRR { return new(dnsRR_MINFO) },
389	dnsTypeMR:    func() dnsRR { return new(dnsRR_MR) },
390	dnsTypeMX:    func() dnsRR { return new(dnsRR_MX) },
391	dnsTypeNS:    func() dnsRR { return new(dnsRR_NS) },
392	dnsTypePTR:   func() dnsRR { return new(dnsRR_PTR) },
393	dnsTypeSOA:   func() dnsRR { return new(dnsRR_SOA) },
394	dnsTypeTXT:   func() dnsRR { return new(dnsRR_TXT) },
395	dnsTypeSRV:   func() dnsRR { return new(dnsRR_SRV) },
396	dnsTypeA:     func() dnsRR { return new(dnsRR_A) },
397	dnsTypeAAAA:  func() dnsRR { return new(dnsRR_AAAA) },
398}
399
400// Pack a domain name s into msg[off:].
401// Domain names are a sequence of counted strings
402// split at the dots.  They end with a zero-length string.
403func packDomainName(s string, msg []byte, off int) (off1 int, ok bool) {
404	// Add trailing dot to canonicalize name.
405	if n := len(s); n == 0 || s[n-1] != '.' {
406		s += "."
407	}
408
409	// Each dot ends a segment of the name.
410	// We trade each dot byte for a length byte.
411	// There is also a trailing zero.
412	// Check that we have all the space we need.
413	tot := len(s) + 1
414	if off+tot > len(msg) {
415		return len(msg), false
416	}
417
418	// Emit sequence of counted strings, chopping at dots.
419	begin := 0
420	for i := 0; i < len(s); i++ {
421		if s[i] == '.' {
422			if i-begin >= 1<<6 { // top two bits of length must be clear
423				return len(msg), false
424			}
425			msg[off] = byte(i - begin)
426			off++
427			for j := begin; j < i; j++ {
428				msg[off] = s[j]
429				off++
430			}
431			begin = i + 1
432		}
433	}
434	msg[off] = 0
435	off++
436	return off, true
437}
438
439// Unpack a domain name.
440// In addition to the simple sequences of counted strings above,
441// domain names are allowed to refer to strings elsewhere in the
442// packet, to avoid repeating common suffixes when returning
443// many entries in a single domain.  The pointers are marked
444// by a length byte with the top two bits set.  Ignoring those
445// two bits, that byte and the next give a 14 bit offset from msg[0]
446// where we should pick up the trail.
447// Note that if we jump elsewhere in the packet,
448// we return off1 == the offset after the first pointer we found,
449// which is where the next record will start.
450// In theory, the pointers are only allowed to jump backward.
451// We let them jump anywhere and stop jumping after a while.
452func unpackDomainName(msg []byte, off int) (s string, off1 int, ok bool) {
453	s = ""
454	ptr := 0 // number of pointers followed
455Loop:
456	for {
457		if off >= len(msg) {
458			return "", len(msg), false
459		}
460		c := int(msg[off])
461		off++
462		switch c & 0xC0 {
463		case 0x00:
464			if c == 0x00 {
465				// end of name
466				break Loop
467			}
468			// literal string
469			if off+c > len(msg) {
470				return "", len(msg), false
471			}
472			s += string(msg[off:off+c]) + "."
473			off += c
474		case 0xC0:
475			// pointer to somewhere else in msg.
476			// remember location after first ptr,
477			// since that's how many bytes we consumed.
478			// also, don't follow too many pointers --
479			// maybe there's a loop.
480			if off >= len(msg) {
481				return "", len(msg), false
482			}
483			c1 := msg[off]
484			off++
485			if ptr == 0 {
486				off1 = off
487			}
488			if ptr++; ptr > 10 {
489				return "", len(msg), false
490			}
491			off = (c^0xC0)<<8 | int(c1)
492		default:
493			// 0x80 and 0x40 are reserved
494			return "", len(msg), false
495		}
496	}
497	if ptr == 0 {
498		off1 = off
499	}
500	return s, off1, true
501}
502
503// packStruct packs a structure into msg at specified offset off, and
504// returns off1 such that msg[off:off1] is the encoded data.
505func packStruct(any dnsStruct, msg []byte, off int) (off1 int, ok bool) {
506	ok = any.Walk(func(field interface{}, name, tag string) bool {
507		switch fv := field.(type) {
508		default:
509			println("net: dns: unknown packing type")
510			return false
511		case *uint16:
512			i := *fv
513			if off+2 > len(msg) {
514				return false
515			}
516			msg[off] = byte(i >> 8)
517			msg[off+1] = byte(i)
518			off += 2
519		case *uint32:
520			i := *fv
521			msg[off] = byte(i >> 24)
522			msg[off+1] = byte(i >> 16)
523			msg[off+2] = byte(i >> 8)
524			msg[off+3] = byte(i)
525			off += 4
526		case []byte:
527			n := len(fv)
528			if off+n > len(msg) {
529				return false
530			}
531			copy(msg[off:off+n], fv)
532			off += n
533		case *string:
534			s := *fv
535			switch tag {
536			default:
537				println("net: dns: unknown string tag", tag)
538				return false
539			case "domain":
540				off, ok = packDomainName(s, msg, off)
541				if !ok {
542					return false
543				}
544			case "":
545				// Counted string: 1 byte length.
546				if len(s) > 255 || off+1+len(s) > len(msg) {
547					return false
548				}
549				msg[off] = byte(len(s))
550				off++
551				off += copy(msg[off:], s)
552			}
553		}
554		return true
555	})
556	if !ok {
557		return len(msg), false
558	}
559	return off, true
560}
561
562// unpackStruct decodes msg[off:] into the given structure, and
563// returns off1 such that msg[off:off1] is the encoded data.
564func unpackStruct(any dnsStruct, msg []byte, off int) (off1 int, ok bool) {
565	ok = any.Walk(func(field interface{}, name, tag string) bool {
566		switch fv := field.(type) {
567		default:
568			println("net: dns: unknown packing type")
569			return false
570		case *uint16:
571			if off+2 > len(msg) {
572				return false
573			}
574			*fv = uint16(msg[off])<<8 | uint16(msg[off+1])
575			off += 2
576		case *uint32:
577			if off+4 > len(msg) {
578				return false
579			}
580			*fv = uint32(msg[off])<<24 | uint32(msg[off+1])<<16 |
581				uint32(msg[off+2])<<8 | uint32(msg[off+3])
582			off += 4
583		case []byte:
584			n := len(fv)
585			if off+n > len(msg) {
586				return false
587			}
588			copy(fv, msg[off:off+n])
589			off += n
590		case *string:
591			var s string
592			switch tag {
593			default:
594				println("net: dns: unknown string tag", tag)
595				return false
596			case "domain":
597				s, off, ok = unpackDomainName(msg, off)
598				if !ok {
599					return false
600				}
601			case "":
602				if off >= len(msg) || off+1+int(msg[off]) > len(msg) {
603					return false
604				}
605				n := int(msg[off])
606				off++
607				b := make([]byte, n)
608				for i := 0; i < n; i++ {
609					b[i] = msg[off+i]
610				}
611				off += n
612				s = string(b)
613			}
614			*fv = s
615		}
616		return true
617	})
618	if !ok {
619		return len(msg), false
620	}
621	return off, true
622}
623
624// Generic struct printer. Prints fields with tag "ipv4" or "ipv6"
625// as IP addresses.
626func printStruct(any dnsStruct) string {
627	s := "{"
628	i := 0
629	any.Walk(func(val interface{}, name, tag string) bool {
630		i++
631		if i > 1 {
632			s += ", "
633		}
634		s += name + "="
635		switch tag {
636		case "ipv4":
637			i := *val.(*uint32)
638			s += IPv4(byte(i>>24), byte(i>>16), byte(i>>8), byte(i)).String()
639		case "ipv6":
640			i := val.([]byte)
641			s += IP(i).String()
642		default:
643			var i int64
644			switch v := val.(type) {
645			default:
646				// can't really happen.
647				s += "<unknown type>"
648				return true
649			case *string:
650				s += *v
651				return true
652			case []byte:
653				s += string(v)
654				return true
655			case *bool:
656				if *v {
657					s += "true"
658				} else {
659					s += "false"
660				}
661				return true
662			case *int:
663				i = int64(*v)
664			case *uint:
665				i = int64(*v)
666			case *uint8:
667				i = int64(*v)
668			case *uint16:
669				i = int64(*v)
670			case *uint32:
671				i = int64(*v)
672			case *uint64:
673				i = int64(*v)
674			case *uintptr:
675				i = int64(*v)
676			}
677			s += itoa(int(i))
678		}
679		return true
680	})
681	s += "}"
682	return s
683}
684
685// Resource record packer.
686func packRR(rr dnsRR, msg []byte, off int) (off2 int, ok bool) {
687	var off1 int
688	// pack twice, once to find end of header
689	// and again to find end of packet.
690	// a bit inefficient but this doesn't need to be fast.
691	// off1 is end of header
692	// off2 is end of rr
693	off1, ok = packStruct(rr.Header(), msg, off)
694	if !ok {
695		return len(msg), false
696	}
697	off2, ok = packStruct(rr, msg, off)
698	if !ok {
699		return len(msg), false
700	}
701	// pack a third time; redo header with correct data length
702	rr.Header().Rdlength = uint16(off2 - off1)
703	packStruct(rr.Header(), msg, off)
704	return off2, true
705}
706
707// Resource record unpacker.
708func unpackRR(msg []byte, off int) (rr dnsRR, off1 int, ok bool) {
709	// unpack just the header, to find the rr type and length
710	var h dnsRR_Header
711	off0 := off
712	if off, ok = unpackStruct(&h, msg, off); !ok {
713		return nil, len(msg), false
714	}
715	end := off + int(h.Rdlength)
716
717	// make an rr of that type and re-unpack.
718	// again inefficient but doesn't need to be fast.
719	mk, known := rr_mk[int(h.Rrtype)]
720	if !known {
721		return &h, end, true
722	}
723	rr = mk()
724	off, ok = unpackStruct(rr, msg, off0)
725	if off != end {
726		return &h, end, true
727	}
728	return rr, off, ok
729}
730
731// Usable representation of a DNS packet.
732
733// A manually-unpacked version of (id, bits).
734// This is in its own struct for easy printing.
735type dnsMsgHdr struct {
736	id                  uint16
737	response            bool
738	opcode              int
739	authoritative       bool
740	truncated           bool
741	recursion_desired   bool
742	recursion_available bool
743	rcode               int
744}
745
746func (h *dnsMsgHdr) Walk(f func(v interface{}, name, tag string) bool) bool {
747	return f(&h.id, "id", "") &&
748		f(&h.response, "response", "") &&
749		f(&h.opcode, "opcode", "") &&
750		f(&h.authoritative, "authoritative", "") &&
751		f(&h.truncated, "truncated", "") &&
752		f(&h.recursion_desired, "recursion_desired", "") &&
753		f(&h.recursion_available, "recursion_available", "") &&
754		f(&h.rcode, "rcode", "")
755}
756
757type dnsMsg struct {
758	dnsMsgHdr
759	question []dnsQuestion
760	answer   []dnsRR
761	ns       []dnsRR
762	extra    []dnsRR
763}
764
765func (dns *dnsMsg) Pack() (msg []byte, ok bool) {
766	var dh dnsHeader
767
768	// Convert convenient dnsMsg into wire-like dnsHeader.
769	dh.Id = dns.id
770	dh.Bits = uint16(dns.opcode)<<11 | uint16(dns.rcode)
771	if dns.recursion_available {
772		dh.Bits |= _RA
773	}
774	if dns.recursion_desired {
775		dh.Bits |= _RD
776	}
777	if dns.truncated {
778		dh.Bits |= _TC
779	}
780	if dns.authoritative {
781		dh.Bits |= _AA
782	}
783	if dns.response {
784		dh.Bits |= _QR
785	}
786
787	// Prepare variable sized arrays.
788	question := dns.question
789	answer := dns.answer
790	ns := dns.ns
791	extra := dns.extra
792
793	dh.Qdcount = uint16(len(question))
794	dh.Ancount = uint16(len(answer))
795	dh.Nscount = uint16(len(ns))
796	dh.Arcount = uint16(len(extra))
797
798	// Could work harder to calculate message size,
799	// but this is far more than we need and not
800	// big enough to hurt the allocator.
801	msg = make([]byte, 2000)
802
803	// Pack it in: header and then the pieces.
804	off := 0
805	off, ok = packStruct(&dh, msg, off)
806	for i := 0; i < len(question); i++ {
807		off, ok = packStruct(&question[i], msg, off)
808	}
809	for i := 0; i < len(answer); i++ {
810		off, ok = packRR(answer[i], msg, off)
811	}
812	for i := 0; i < len(ns); i++ {
813		off, ok = packRR(ns[i], msg, off)
814	}
815	for i := 0; i < len(extra); i++ {
816		off, ok = packRR(extra[i], msg, off)
817	}
818	if !ok {
819		return nil, false
820	}
821	return msg[0:off], true
822}
823
824func (dns *dnsMsg) Unpack(msg []byte) bool {
825	// Header.
826	var dh dnsHeader
827	off := 0
828	var ok bool
829	if off, ok = unpackStruct(&dh, msg, off); !ok {
830		return false
831	}
832	dns.id = dh.Id
833	dns.response = (dh.Bits & _QR) != 0
834	dns.opcode = int(dh.Bits>>11) & 0xF
835	dns.authoritative = (dh.Bits & _AA) != 0
836	dns.truncated = (dh.Bits & _TC) != 0
837	dns.recursion_desired = (dh.Bits & _RD) != 0
838	dns.recursion_available = (dh.Bits & _RA) != 0
839	dns.rcode = int(dh.Bits & 0xF)
840
841	// Arrays.
842	dns.question = make([]dnsQuestion, dh.Qdcount)
843	dns.answer = make([]dnsRR, 0, dh.Ancount)
844	dns.ns = make([]dnsRR, 0, dh.Nscount)
845	dns.extra = make([]dnsRR, 0, dh.Arcount)
846
847	var rec dnsRR
848
849	for i := 0; i < len(dns.question); i++ {
850		off, ok = unpackStruct(&dns.question[i], msg, off)
851	}
852	for i := 0; i < int(dh.Ancount); i++ {
853		rec, off, ok = unpackRR(msg, off)
854		if !ok {
855			return false
856		}
857		dns.answer = append(dns.answer, rec)
858	}
859	for i := 0; i < int(dh.Nscount); i++ {
860		rec, off, ok = unpackRR(msg, off)
861		if !ok {
862			return false
863		}
864		dns.ns = append(dns.ns, rec)
865	}
866	for i := 0; i < int(dh.Arcount); i++ {
867		rec, off, ok = unpackRR(msg, off)
868		if !ok {
869			return false
870		}
871		dns.extra = append(dns.extra, rec)
872	}
873	//	if off != len(msg) {
874	//		println("extra bytes in dns packet", off, "<", len(msg));
875	//	}
876	return true
877}
878
879func (dns *dnsMsg) String() string {
880	s := "DNS: " + printStruct(&dns.dnsMsgHdr) + "\n"
881	if len(dns.question) > 0 {
882		s += "-- Questions\n"
883		for i := 0; i < len(dns.question); i++ {
884			s += printStruct(&dns.question[i]) + "\n"
885		}
886	}
887	if len(dns.answer) > 0 {
888		s += "-- Answers\n"
889		for i := 0; i < len(dns.answer); i++ {
890			s += printStruct(dns.answer[i]) + "\n"
891		}
892	}
893	if len(dns.ns) > 0 {
894		s += "-- Name servers\n"
895		for i := 0; i < len(dns.ns); i++ {
896			s += printStruct(dns.ns[i]) + "\n"
897		}
898	}
899	if len(dns.extra) > 0 {
900		s += "-- Extra\n"
901		for i := 0; i < len(dns.extra); i++ {
902			s += printStruct(dns.extra[i]) + "\n"
903		}
904	}
905	return s
906}
907