Source file src/pkg/net/dnsmsg.go
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
23 package net
24
25 // Packet formats
26
27 // Wire constants.
28 const (
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.
73 type 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.
86 type dnsHeader struct {
87 Id uint16
88 Bits uint16
89 Qdcount, Ancount, Nscount, Arcount uint16
90 }
91
92 func (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
101 const (
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.
111 type dnsQuestion struct {
112 Name string `net:"domain-name"` // `net:"domain-name"` specifies encoding; see packers below
113 Qtype uint16
114 Qclass uint16
115 }
116
117 func (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.
126 type 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
134 func (h *dnsRR_Header) Header() *dnsRR_Header {
135 return h
136 }
137
138 func (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
146 type dnsRR interface {
147 dnsStruct
148 Header() *dnsRR_Header
149 }
150
151 // Specific DNS RR formats for each query type.
152
153 type dnsRR_CNAME struct {
154 Hdr dnsRR_Header
155 Cname string `net:"domain-name"`
156 }
157
158 func (rr *dnsRR_CNAME) Header() *dnsRR_Header {
159 return &rr.Hdr
160 }
161
162 func (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
166 type dnsRR_HINFO struct {
167 Hdr dnsRR_Header
168 Cpu string
169 Os string
170 }
171
172 func (rr *dnsRR_HINFO) Header() *dnsRR_Header {
173 return &rr.Hdr
174 }
175
176 func (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
180 type dnsRR_MB struct {
181 Hdr dnsRR_Header
182 Mb string `net:"domain-name"`
183 }
184
185 func (rr *dnsRR_MB) Header() *dnsRR_Header {
186 return &rr.Hdr
187 }
188
189 func (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
193 type dnsRR_MG struct {
194 Hdr dnsRR_Header
195 Mg string `net:"domain-name"`
196 }
197
198 func (rr *dnsRR_MG) Header() *dnsRR_Header {
199 return &rr.Hdr
200 }
201
202 func (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
206 type dnsRR_MINFO struct {
207 Hdr dnsRR_Header
208 Rmail string `net:"domain-name"`
209 Email string `net:"domain-name"`
210 }
211
212 func (rr *dnsRR_MINFO) Header() *dnsRR_Header {
213 return &rr.Hdr
214 }
215
216 func (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
220 type dnsRR_MR struct {
221 Hdr dnsRR_Header
222 Mr string `net:"domain-name"`
223 }
224
225 func (rr *dnsRR_MR) Header() *dnsRR_Header {
226 return &rr.Hdr
227 }
228
229 func (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
233 type dnsRR_MX struct {
234 Hdr dnsRR_Header
235 Pref uint16
236 Mx string `net:"domain-name"`
237 }
238
239 func (rr *dnsRR_MX) Header() *dnsRR_Header {
240 return &rr.Hdr
241 }
242
243 func (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
247 type dnsRR_NS struct {
248 Hdr dnsRR_Header
249 Ns string `net:"domain-name"`
250 }
251
252 func (rr *dnsRR_NS) Header() *dnsRR_Header {
253 return &rr.Hdr
254 }
255
256 func (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
260 type dnsRR_PTR struct {
261 Hdr dnsRR_Header
262 Ptr string `net:"domain-name"`
263 }
264
265 func (rr *dnsRR_PTR) Header() *dnsRR_Header {
266 return &rr.Hdr
267 }
268
269 func (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
273 type 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
284 func (rr *dnsRR_SOA) Header() *dnsRR_Header {
285 return &rr.Hdr
286 }
287
288 func (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
299 type dnsRR_TXT struct {
300 Hdr dnsRR_Header
301 Txt string // not domain name
302 }
303
304 func (rr *dnsRR_TXT) Header() *dnsRR_Header {
305 return &rr.Hdr
306 }
307
308 func (rr *dnsRR_TXT) Walk(f func(v interface{}, name, tag string) bool) bool {
309 return rr.Hdr.Walk(f) && f(&rr.Txt, "Txt", "")
310 }
311
312 type dnsRR_SRV struct {
313 Hdr dnsRR_Header
314 Priority uint16
315 Weight uint16
316 Port uint16
317 Target string `net:"domain-name"`
318 }
319
320 func (rr *dnsRR_SRV) Header() *dnsRR_Header {
321 return &rr.Hdr
322 }
323
324 func (rr *dnsRR_SRV) Walk(f func(v interface{}, name, tag string) bool) bool {
325 return rr.Hdr.Walk(f) &&
326 f(&rr.Priority, "Priority", "") &&
327 f(&rr.Weight, "Weight", "") &&
328 f(&rr.Port, "Port", "") &&
329 f(&rr.Target, "Target", "domain")
330 }
331
332 type dnsRR_A struct {
333 Hdr dnsRR_Header
334 A uint32 `net:"ipv4"`
335 }
336
337 func (rr *dnsRR_A) Header() *dnsRR_Header {
338 return &rr.Hdr
339 }
340
341 func (rr *dnsRR_A) Walk(f func(v interface{}, name, tag string) bool) bool {
342 return rr.Hdr.Walk(f) && f(&rr.A, "A", "ipv4")
343 }
344
345 type dnsRR_AAAA struct {
346 Hdr dnsRR_Header
347 AAAA [16]byte `net:"ipv6"`
348 }
349
350 func (rr *dnsRR_AAAA) Header() *dnsRR_Header {
351 return &rr.Hdr
352 }
353
354 func (rr *dnsRR_AAAA) Walk(f func(v interface{}, name, tag string) bool) bool {
355 return rr.Hdr.Walk(f) && f(rr.AAAA[:], "AAAA", "ipv6")
356 }
357
358 // Packing and unpacking.
359 //
360 // All the packers and unpackers take a (msg []byte, off int)
361 // and return (off1 int, ok bool). If they return ok==false, they
362 // also return off1==len(msg), so that the next unpacker will
363 // also fail. This lets us avoid checks of ok until the end of a
364 // packing sequence.
365
366 // Map of constructors for each RR wire type.
367 var rr_mk = map[int]func() dnsRR{
368 dnsTypeCNAME: func() dnsRR { return new(dnsRR_CNAME) },
369 dnsTypeHINFO: func() dnsRR { return new(dnsRR_HINFO) },
370 dnsTypeMB: func() dnsRR { return new(dnsRR_MB) },
371 dnsTypeMG: func() dnsRR { return new(dnsRR_MG) },
372 dnsTypeMINFO: func() dnsRR { return new(dnsRR_MINFO) },
373 dnsTypeMR: func() dnsRR { return new(dnsRR_MR) },
374 dnsTypeMX: func() dnsRR { return new(dnsRR_MX) },
375 dnsTypeNS: func() dnsRR { return new(dnsRR_NS) },
376 dnsTypePTR: func() dnsRR { return new(dnsRR_PTR) },
377 dnsTypeSOA: func() dnsRR { return new(dnsRR_SOA) },
378 dnsTypeTXT: func() dnsRR { return new(dnsRR_TXT) },
379 dnsTypeSRV: func() dnsRR { return new(dnsRR_SRV) },
380 dnsTypeA: func() dnsRR { return new(dnsRR_A) },
381 dnsTypeAAAA: func() dnsRR { return new(dnsRR_AAAA) },
382 }
383
384 // Pack a domain name s into msg[off:].
385 // Domain names are a sequence of counted strings
386 // split at the dots. They end with a zero-length string.
387 func packDomainName(s string, msg []byte, off int) (off1 int, ok bool) {
388 // Add trailing dot to canonicalize name.
389 if n := len(s); n == 0 || s[n-1] != '.' {
390 s += "."
391 }
392
393 // Each dot ends a segment of the name.
394 // We trade each dot byte for a length byte.
395 // There is also a trailing zero.
396 // Check that we have all the space we need.
397 tot := len(s) + 1
398 if off+tot > len(msg) {
399 return len(msg), false
400 }
401
402 // Emit sequence of counted strings, chopping at dots.
403 begin := 0
404 for i := 0; i < len(s); i++ {
405 if s[i] == '.' {
406 if i-begin >= 1<<6 { // top two bits of length must be clear
407 return len(msg), false
408 }
409 msg[off] = byte(i - begin)
410 off++
411 for j := begin; j < i; j++ {
412 msg[off] = s[j]
413 off++
414 }
415 begin = i + 1
416 }
417 }
418 msg[off] = 0
419 off++
420 return off, true
421 }
422
423 // Unpack a domain name.
424 // In addition to the simple sequences of counted strings above,
425 // domain names are allowed to refer to strings elsewhere in the
426 // packet, to avoid repeating common suffixes when returning
427 // many entries in a single domain. The pointers are marked
428 // by a length byte with the top two bits set. Ignoring those
429 // two bits, that byte and the next give a 14 bit offset from msg[0]
430 // where we should pick up the trail.
431 // Note that if we jump elsewhere in the packet,
432 // we return off1 == the offset after the first pointer we found,
433 // which is where the next record will start.
434 // In theory, the pointers are only allowed to jump backward.
435 // We let them jump anywhere and stop jumping after a while.
436 func unpackDomainName(msg []byte, off int) (s string, off1 int, ok bool) {
437 s = ""
438 ptr := 0 // number of pointers followed
439 Loop:
440 for {
441 if off >= len(msg) {
442 return "", len(msg), false
443 }
444 c := int(msg[off])
445 off++
446 switch c & 0xC0 {
447 case 0x00:
448 if c == 0x00 {
449 // end of name
450 break Loop
451 }
452 // literal string
453 if off+c > len(msg) {
454 return "", len(msg), false
455 }
456 s += string(msg[off:off+c]) + "."
457 off += c
458 case 0xC0:
459 // pointer to somewhere else in msg.
460 // remember location after first ptr,
461 // since that's how many bytes we consumed.
462 // also, don't follow too many pointers --
463 // maybe there's a loop.
464 if off >= len(msg) {
465 return "", len(msg), false
466 }
467 c1 := msg[off]
468 off++
469 if ptr == 0 {
470 off1 = off
471 }
472 if ptr++; ptr > 10 {
473 return "", len(msg), false
474 }
475 off = (c^0xC0)<<8 | int(c1)
476 default:
477 // 0x80 and 0x40 are reserved
478 return "", len(msg), false
479 }
480 }
481 if ptr == 0 {
482 off1 = off
483 }
484 return s, off1, true
485 }
486
487 // packStruct packs a structure into msg at specified offset off, and
488 // returns off1 such that msg[off:off1] is the encoded data.
489 func packStruct(any dnsStruct, msg []byte, off int) (off1 int, ok bool) {
490 ok = any.Walk(func(field interface{}, name, tag string) bool {
491 switch fv := field.(type) {
492 default:
493 println("net: dns: unknown packing type")
494 return false
495 case *uint16:
496 i := *fv
497 if off+2 > len(msg) {
498 return false
499 }
500 msg[off] = byte(i >> 8)
501 msg[off+1] = byte(i)
502 off += 2
503 case *uint32:
504 i := *fv
505 msg[off] = byte(i >> 24)
506 msg[off+1] = byte(i >> 16)
507 msg[off+2] = byte(i >> 8)
508 msg[off+3] = byte(i)
509 off += 4
510 case []byte:
511 n := len(fv)
512 if off+n > len(msg) {
513 return false
514 }
515 copy(msg[off:off+n], fv)
516 off += n
517 case *string:
518 s := *fv
519 switch tag {
520 default:
521 println("net: dns: unknown string tag", tag)
522 return false
523 case "domain":
524 off, ok = packDomainName(s, msg, off)
525 if !ok {
526 return false
527 }
528 case "":
529 // Counted string: 1 byte length.
530 if len(s) > 255 || off+1+len(s) > len(msg) {
531 return false
532 }
533 msg[off] = byte(len(s))
534 off++
535 off += copy(msg[off:], s)
536 }
537 }
538 return true
539 })
540 if !ok {
541 return len(msg), false
542 }
543 return off, true
544 }
545
546 // unpackStruct decodes msg[off:] into the given structure, and
547 // returns off1 such that msg[off:off1] is the encoded data.
548 func unpackStruct(any dnsStruct, msg []byte, off int) (off1 int, ok bool) {
549 ok = any.Walk(func(field interface{}, name, tag string) bool {
550 switch fv := field.(type) {
551 default:
552 println("net: dns: unknown packing type")
553 return false
554 case *uint16:
555 if off+2 > len(msg) {
556 return false
557 }
558 *fv = uint16(msg[off])<<8 | uint16(msg[off+1])
559 off += 2
560 case *uint32:
561 if off+4 > len(msg) {
562 return false
563 }
564 *fv = uint32(msg[off])<<24 | uint32(msg[off+1])<<16 |
565 uint32(msg[off+2])<<8 | uint32(msg[off+3])
566 off += 4
567 case []byte:
568 n := len(fv)
569 if off+n > len(msg) {
570 return false
571 }
572 copy(fv, msg[off:off+n])
573 off += n
574 case *string:
575 var s string
576 switch tag {
577 default:
578 println("net: dns: unknown string tag", tag)
579 return false
580 case "domain":
581 s, off, ok = unpackDomainName(msg, off)
582 if !ok {
583 return false
584 }
585 case "":
586 if off >= len(msg) || off+1+int(msg[off]) > len(msg) {
587 return false
588 }
589 n := int(msg[off])
590 off++
591 b := make([]byte, n)
592 for i := 0; i < n; i++ {
593 b[i] = msg[off+i]
594 }
595 off += n
596 s = string(b)
597 }
598 *fv = s
599 }
600 return true
601 })
602 if !ok {
603 return len(msg), false
604 }
605 return off, true
606 }
607
608 // Generic struct printer. Prints fields with tag "ipv4" or "ipv6"
609 // as IP addresses.
610 func printStruct(any dnsStruct) string {
611 s := "{"
612 i := 0
613 any.Walk(func(val interface{}, name, tag string) bool {
614 i++
615 if i > 1 {
616 s += ", "
617 }
618 s += name + "="
619 switch tag {
620 case "ipv4":
621 i := val.(uint32)
622 s += IPv4(byte(i>>24), byte(i>>16), byte(i>>8), byte(i)).String()
623 case "ipv6":
624 i := val.([]byte)
625 s += IP(i).String()
626 default:
627 var i int64
628 switch v := val.(type) {
629 default:
630 // can't really happen.
631 s += "<unknown type>"
632 return true
633 case *string:
634 s += *v
635 return true
636 case []byte:
637 s += string(v)
638 return true
639 case *bool:
640 if *v {
641 s += "true"
642 } else {
643 s += "false"
644 }
645 return true
646 case *int:
647 i = int64(*v)
648 case *uint:
649 i = int64(*v)
650 case *uint8:
651 i = int64(*v)
652 case *uint16:
653 i = int64(*v)
654 case *uint32:
655 i = int64(*v)
656 case *uint64:
657 i = int64(*v)
658 case *uintptr:
659 i = int64(*v)
660 }
661 s += itoa(int(i))
662 }
663 return true
664 })
665 s += "}"
666 return s
667 }
668
669 // Resource record packer.
670 func packRR(rr dnsRR, msg []byte, off int) (off2 int, ok bool) {
671 var off1 int
672 // pack twice, once to find end of header
673 // and again to find end of packet.
674 // a bit inefficient but this doesn't need to be fast.
675 // off1 is end of header
676 // off2 is end of rr
677 off1, ok = packStruct(rr.Header(), msg, off)
678 off2, ok = packStruct(rr, msg, off)
679 if !ok {
680 return len(msg), false
681 }
682 // pack a third time; redo header with correct data length
683 rr.Header().Rdlength = uint16(off2 - off1)
684 packStruct(rr.Header(), msg, off)
685 return off2, true
686 }
687
688 // Resource record unpacker.
689 func unpackRR(msg []byte, off int) (rr dnsRR, off1 int, ok bool) {
690 // unpack just the header, to find the rr type and length
691 var h dnsRR_Header
692 off0 := off
693 if off, ok = unpackStruct(&h, msg, off); !ok {
694 return nil, len(msg), false
695 }
696 end := off + int(h.Rdlength)
697
698 // make an rr of that type and re-unpack.
699 // again inefficient but doesn't need to be fast.
700 mk, known := rr_mk[int(h.Rrtype)]
701 if !known {
702 return &h, end, true
703 }
704 rr = mk()
705 off, ok = unpackStruct(rr, msg, off0)
706 if off != end {
707 return &h, end, true
708 }
709 return rr, off, ok
710 }
711
712 // Usable representation of a DNS packet.
713
714 // A manually-unpacked version of (id, bits).
715 // This is in its own struct for easy printing.
716 type dnsMsgHdr struct {
717 id uint16
718 response bool
719 opcode int
720 authoritative bool
721 truncated bool
722 recursion_desired bool
723 recursion_available bool
724 rcode int
725 }
726
727 func (h *dnsMsgHdr) Walk(f func(v interface{}, name, tag string) bool) bool {
728 return f(&h.id, "id", "") &&
729 f(&h.response, "response", "") &&
730 f(&h.opcode, "opcode", "") &&
731 f(&h.authoritative, "authoritative", "") &&
732 f(&h.truncated, "truncated", "") &&
733 f(&h.recursion_desired, "recursion_desired", "") &&
734 f(&h.recursion_available, "recursion_available", "") &&
735 f(&h.rcode, "rcode", "")
736 }
737
738 type dnsMsg struct {
739 dnsMsgHdr
740 question []dnsQuestion
741 answer []dnsRR
742 ns []dnsRR
743 extra []dnsRR
744 }
745
746 func (dns *dnsMsg) Pack() (msg []byte, ok bool) {
747 var dh dnsHeader
748
749 // Convert convenient dnsMsg into wire-like dnsHeader.
750 dh.Id = dns.id
751 dh.Bits = uint16(dns.opcode)<<11 | uint16(dns.rcode)
752 if dns.recursion_available {
753 dh.Bits |= _RA
754 }
755 if dns.recursion_desired {
756 dh.Bits |= _RD
757 }
758 if dns.truncated {
759 dh.Bits |= _TC
760 }
761 if dns.authoritative {
762 dh.Bits |= _AA
763 }
764 if dns.response {
765 dh.Bits |= _QR
766 }
767
768 // Prepare variable sized arrays.
769 question := dns.question
770 answer := dns.answer
771 ns := dns.ns
772 extra := dns.extra
773
774 dh.Qdcount = uint16(len(question))
775 dh.Ancount = uint16(len(answer))
776 dh.Nscount = uint16(len(ns))
777 dh.Arcount = uint16(len(extra))
778
779 // Could work harder to calculate message size,
780 // but this is far more than we need and not
781 // big enough to hurt the allocator.
782 msg = make([]byte, 2000)
783
784 // Pack it in: header and then the pieces.
785 off := 0
786 off, ok = packStruct(&dh, msg, off)
787 for i := 0; i < len(question); i++ {
788 off, ok = packStruct(&question[i], msg, off)
789 }
790 for i := 0; i < len(answer); i++ {
791 off, ok = packRR(answer[i], msg, off)
792 }
793 for i := 0; i < len(ns); i++ {
794 off, ok = packRR(ns[i], msg, off)
795 }
796 for i := 0; i < len(extra); i++ {
797 off, ok = packRR(extra[i], msg, off)
798 }
799 if !ok {
800 return nil, false
801 }
802 return msg[0:off], true
803 }
804
805 func (dns *dnsMsg) Unpack(msg []byte) bool {
806 // Header.
807 var dh dnsHeader
808 off := 0
809 var ok bool
810 if off, ok = unpackStruct(&dh, msg, off); !ok {
811 return false
812 }
813 dns.id = dh.Id
814 dns.response = (dh.Bits & _QR) != 0
815 dns.opcode = int(dh.Bits>>11) & 0xF
816 dns.authoritative = (dh.Bits & _AA) != 0
817 dns.truncated = (dh.Bits & _TC) != 0
818 dns.recursion_desired = (dh.Bits & _RD) != 0
819 dns.recursion_available = (dh.Bits & _RA) != 0
820 dns.rcode = int(dh.Bits & 0xF)
821
822 // Arrays.
823 dns.question = make([]dnsQuestion, dh.Qdcount)
824 dns.answer = make([]dnsRR, 0, dh.Ancount)
825 dns.ns = make([]dnsRR, 0, dh.Nscount)
826 dns.extra = make([]dnsRR, 0, dh.Arcount)
827
828 var rec dnsRR
829
830 for i := 0; i < len(dns.question); i++ {
831 off, ok = unpackStruct(&dns.question[i], msg, off)
832 }
833 for i := 0; i < int(dh.Ancount); i++ {
834 rec, off, ok = unpackRR(msg, off)
835 if !ok {
836 return false
837 }
838 dns.answer = append(dns.answer, rec)
839 }
840 for i := 0; i < int(dh.Nscount); i++ {
841 rec, off, ok = unpackRR(msg, off)
842 if !ok {
843 return false
844 }
845 dns.ns = append(dns.ns, rec)
846 }
847 for i := 0; i < int(dh.Arcount); i++ {
848 rec, off, ok = unpackRR(msg, off)
849 if !ok {
850 return false
851 }
852 dns.extra = append(dns.extra, rec)
853 }
854 // if off != len(msg) {
855 // println("extra bytes in dns packet", off, "<", len(msg));
856 // }
857 return true
858 }
859
860 func (dns *dnsMsg) String() string {
861 s := "DNS: " + printStruct(&dns.dnsMsgHdr) + "\n"
862 if len(dns.question) > 0 {
863 s += "-- Questions\n"
864 for i := 0; i < len(dns.question); i++ {
865 s += printStruct(&dns.question[i]) + "\n"
866 }
867 }
868 if len(dns.answer) > 0 {
869 s += "-- Answers\n"
870 for i := 0; i < len(dns.answer); i++ {
871 s += printStruct(dns.answer[i]) + "\n"
872 }
873 }
874 if len(dns.ns) > 0 {
875 s += "-- Name servers\n"
876 for i := 0; i < len(dns.ns); i++ {
877 s += printStruct(dns.ns[i]) + "\n"
878 }
879 }
880 if len(dns.extra) > 0 {
881 s += "-- Extra\n"
882 for i := 0; i < len(dns.extra); i++ {
883 s += printStruct(dns.extra[i]) + "\n"
884 }
885 }
886 return s
887 }