Rebase.
[official-gcc.git] / libgo / go / net / dnsmsg.go
blob161afb2a55675eaaa855c4840c97b4c9af3c2e18
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.
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.
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.
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.
23 package net
25 // Packet formats
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
49 // valid dnsQuestion.qtype only
50 dnsTypeAXFR = 252
51 dnsTypeMAILB = 253
52 dnsTypeMAILA = 254
53 dnsTypeALL = 255
55 // valid dnsQuestion.qclass
56 dnsClassINET = 1
57 dnsClassCSNET = 2
58 dnsClassCHAOS = 3
59 dnsClassHESIOD = 4
60 dnsClassANY = 255
62 // dnsMsg.rcode
63 dnsRcodeSuccess = 0
64 dnsRcodeFormatError = 1
65 dnsRcodeServerFailure = 2
66 dnsRcodeNameError = 3
67 dnsRcodeNotImplemented = 4
68 dnsRcodeRefused = 5
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)
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
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", "")
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
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
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", "")
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
134 func (h *dnsRR_Header) Header() *dnsRR_Header {
135 return h
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", "")
146 type dnsRR interface {
147 dnsStruct
148 Header() *dnsRR_Header
151 // Specific DNS RR formats for each query type.
153 type dnsRR_CNAME struct {
154 Hdr dnsRR_Header
155 Cname string `net:"domain-name"`
158 func (rr *dnsRR_CNAME) Header() *dnsRR_Header {
159 return &rr.Hdr
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")
166 type dnsRR_HINFO struct {
167 Hdr dnsRR_Header
168 Cpu string
169 Os string
172 func (rr *dnsRR_HINFO) Header() *dnsRR_Header {
173 return &rr.Hdr
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", "")
180 type dnsRR_MB struct {
181 Hdr dnsRR_Header
182 Mb string `net:"domain-name"`
185 func (rr *dnsRR_MB) Header() *dnsRR_Header {
186 return &rr.Hdr
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")
193 type dnsRR_MG struct {
194 Hdr dnsRR_Header
195 Mg string `net:"domain-name"`
198 func (rr *dnsRR_MG) Header() *dnsRR_Header {
199 return &rr.Hdr
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")
206 type dnsRR_MINFO struct {
207 Hdr dnsRR_Header
208 Rmail string `net:"domain-name"`
209 Email string `net:"domain-name"`
212 func (rr *dnsRR_MINFO) Header() *dnsRR_Header {
213 return &rr.Hdr
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")
220 type dnsRR_MR struct {
221 Hdr dnsRR_Header
222 Mr string `net:"domain-name"`
225 func (rr *dnsRR_MR) Header() *dnsRR_Header {
226 return &rr.Hdr
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")
233 type dnsRR_MX struct {
234 Hdr dnsRR_Header
235 Pref uint16
236 Mx string `net:"domain-name"`
239 func (rr *dnsRR_MX) Header() *dnsRR_Header {
240 return &rr.Hdr
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")
247 type dnsRR_NS struct {
248 Hdr dnsRR_Header
249 Ns string `net:"domain-name"`
252 func (rr *dnsRR_NS) Header() *dnsRR_Header {
253 return &rr.Hdr
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")
260 type dnsRR_PTR struct {
261 Hdr dnsRR_Header
262 Ptr string `net:"domain-name"`
265 func (rr *dnsRR_PTR) Header() *dnsRR_Header {
266 return &rr.Hdr
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")
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
284 func (rr *dnsRR_SOA) Header() *dnsRR_Header {
285 return &rr.Hdr
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", "")
299 type dnsRR_TXT struct {
300 Hdr dnsRR_Header
301 Txt string // not domain name
304 func (rr *dnsRR_TXT) Header() *dnsRR_Header {
305 return &rr.Hdr
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", "")
312 type dnsRR_SRV struct {
313 Hdr dnsRR_Header
314 Priority uint16
315 Weight uint16
316 Port uint16
317 Target string `net:"domain-name"`
320 func (rr *dnsRR_SRV) Header() *dnsRR_Header {
321 return &rr.Hdr
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")
332 type dnsRR_A struct {
333 Hdr dnsRR_Header
334 A uint32 `net:"ipv4"`
337 func (rr *dnsRR_A) Header() *dnsRR_Header {
338 return &rr.Hdr
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")
345 type dnsRR_AAAA struct {
346 Hdr dnsRR_Header
347 AAAA [16]byte `net:"ipv6"`
350 func (rr *dnsRR_AAAA) Header() *dnsRR_Header {
351 return &rr.Hdr
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")
358 // Packing and unpacking.
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.
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) },
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 += "."
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
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
409 msg[off] = byte(i - begin)
410 off++
411 for j := begin; j < i; j++ {
412 msg[off] = s[j]
413 off++
415 begin = i + 1
418 msg[off] = 0
419 off++
420 return off, true
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
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
452 // literal string
453 if off+c > len(msg) {
454 return "", len(msg), false
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
467 c1 := msg[off]
468 off++
469 if ptr == 0 {
470 off1 = off
472 if ptr++; ptr > 10 {
473 return "", len(msg), false
475 off = (c^0xC0)<<8 | int(c1)
476 default:
477 // 0x80 and 0x40 are reserved
478 return "", len(msg), false
481 if ptr == 0 {
482 off1 = off
484 return s, off1, true
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
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
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
528 case "":
529 // Counted string: 1 byte length.
530 if len(s) > 255 || off+1+len(s) > len(msg) {
531 return false
533 msg[off] = byte(len(s))
534 off++
535 off += copy(msg[off:], s)
538 return true
540 if !ok {
541 return len(msg), false
543 return off, true
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
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
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
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
585 case "":
586 if off >= len(msg) || off+1+int(msg[off]) > len(msg) {
587 return false
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]
595 off += n
596 s = string(b)
598 *fv = s
600 return true
602 if !ok {
603 return len(msg), false
605 return off, true
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 {
615 if i > 1 {
616 s += ", "
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"
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)
661 s += itoa(int(i))
663 return true
665 s += "}"
666 return s
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
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
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
696 end := off + int(h.Rdlength)
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
704 rr = mk()
705 off, ok = unpackStruct(rr, msg, off0)
706 if off != end {
707 return &h, end, true
709 return rr, off, ok
712 // Usable representation of a DNS packet.
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
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", "")
738 type dnsMsg struct {
739 dnsMsgHdr
740 question []dnsQuestion
741 answer []dnsRR
742 ns []dnsRR
743 extra []dnsRR
746 func (dns *dnsMsg) Pack() (msg []byte, ok bool) {
747 var dh dnsHeader
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
755 if dns.recursion_desired {
756 dh.Bits |= _RD
758 if dns.truncated {
759 dh.Bits |= _TC
761 if dns.authoritative {
762 dh.Bits |= _AA
764 if dns.response {
765 dh.Bits |= _QR
768 // Prepare variable sized arrays.
769 question := dns.question
770 answer := dns.answer
771 ns := dns.ns
772 extra := dns.extra
774 dh.Qdcount = uint16(len(question))
775 dh.Ancount = uint16(len(answer))
776 dh.Nscount = uint16(len(ns))
777 dh.Arcount = uint16(len(extra))
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)
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)
790 for i := 0; i < len(answer); i++ {
791 off, ok = packRR(answer[i], msg, off)
793 for i := 0; i < len(ns); i++ {
794 off, ok = packRR(ns[i], msg, off)
796 for i := 0; i < len(extra); i++ {
797 off, ok = packRR(extra[i], msg, off)
799 if !ok {
800 return nil, false
802 return msg[0:off], true
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
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)
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)
828 var rec dnsRR
830 for i := 0; i < len(dns.question); i++ {
831 off, ok = unpackStruct(&dns.question[i], msg, off)
833 for i := 0; i < int(dh.Ancount); i++ {
834 rec, off, ok = unpackRR(msg, off)
835 if !ok {
836 return false
838 dns.answer = append(dns.answer, rec)
840 for i := 0; i < int(dh.Nscount); i++ {
841 rec, off, ok = unpackRR(msg, off)
842 if !ok {
843 return false
845 dns.ns = append(dns.ns, rec)
847 for i := 0; i < int(dh.Arcount); i++ {
848 rec, off, ok = unpackRR(msg, off)
849 if !ok {
850 return false
852 dns.extra = append(dns.extra, rec)
854 // if off != len(msg) {
855 // println("extra bytes in dns packet", off, "<", len(msg));
856 // }
857 return true
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"
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"
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"
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"
886 return s