2017-07-18 François Dumont <fdumont@gcc.gnu.org>
[official-gcc.git] / libgo / go / net / dnsmsg.go
blob8f6c7b6350cb646b80e0071b28415cf123d2ef0d
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 marshaling.
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
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
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
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_MX struct {
167 Hdr dnsRR_Header
168 Pref uint16
169 Mx string
172 func (rr *dnsRR_MX) Header() *dnsRR_Header {
173 return &rr.Hdr
176 func (rr *dnsRR_MX) Walk(f func(v interface{}, name, tag string) bool) bool {
177 return rr.Hdr.Walk(f) && f(&rr.Pref, "Pref", "") && f(&rr.Mx, "Mx", "domain")
180 type dnsRR_NS struct {
181 Hdr dnsRR_Header
182 Ns string
185 func (rr *dnsRR_NS) Header() *dnsRR_Header {
186 return &rr.Hdr
189 func (rr *dnsRR_NS) Walk(f func(v interface{}, name, tag string) bool) bool {
190 return rr.Hdr.Walk(f) && f(&rr.Ns, "Ns", "domain")
193 type dnsRR_PTR struct {
194 Hdr dnsRR_Header
195 Ptr string
198 func (rr *dnsRR_PTR) Header() *dnsRR_Header {
199 return &rr.Hdr
202 func (rr *dnsRR_PTR) Walk(f func(v interface{}, name, tag string) bool) bool {
203 return rr.Hdr.Walk(f) && f(&rr.Ptr, "Ptr", "domain")
206 type dnsRR_SOA struct {
207 Hdr dnsRR_Header
208 Ns string
209 Mbox string
210 Serial uint32
211 Refresh uint32
212 Retry uint32
213 Expire uint32
214 Minttl uint32
217 func (rr *dnsRR_SOA) Header() *dnsRR_Header {
218 return &rr.Hdr
221 func (rr *dnsRR_SOA) Walk(f func(v interface{}, name, tag string) bool) bool {
222 return rr.Hdr.Walk(f) &&
223 f(&rr.Ns, "Ns", "domain") &&
224 f(&rr.Mbox, "Mbox", "domain") &&
225 f(&rr.Serial, "Serial", "") &&
226 f(&rr.Refresh, "Refresh", "") &&
227 f(&rr.Retry, "Retry", "") &&
228 f(&rr.Expire, "Expire", "") &&
229 f(&rr.Minttl, "Minttl", "")
232 type dnsRR_TXT struct {
233 Hdr dnsRR_Header
234 Txt string // not domain name
237 func (rr *dnsRR_TXT) Header() *dnsRR_Header {
238 return &rr.Hdr
241 func (rr *dnsRR_TXT) Walk(f func(v interface{}, name, tag string) bool) bool {
242 if !rr.Hdr.Walk(f) {
243 return false
245 var n uint16 = 0
246 for n < rr.Hdr.Rdlength {
247 var txt string
248 if !f(&txt, "Txt", "") {
249 return false
251 // more bytes than rr.Hdr.Rdlength said there would be
252 if rr.Hdr.Rdlength-n < uint16(len(txt))+1 {
253 return false
255 n += uint16(len(txt)) + 1
256 rr.Txt += txt
258 return true
261 type dnsRR_SRV struct {
262 Hdr dnsRR_Header
263 Priority uint16
264 Weight uint16
265 Port uint16
266 Target string
269 func (rr *dnsRR_SRV) Header() *dnsRR_Header {
270 return &rr.Hdr
273 func (rr *dnsRR_SRV) Walk(f func(v interface{}, name, tag string) bool) bool {
274 return rr.Hdr.Walk(f) &&
275 f(&rr.Priority, "Priority", "") &&
276 f(&rr.Weight, "Weight", "") &&
277 f(&rr.Port, "Port", "") &&
278 f(&rr.Target, "Target", "domain")
281 type dnsRR_A struct {
282 Hdr dnsRR_Header
283 A uint32
286 func (rr *dnsRR_A) Header() *dnsRR_Header {
287 return &rr.Hdr
290 func (rr *dnsRR_A) Walk(f func(v interface{}, name, tag string) bool) bool {
291 return rr.Hdr.Walk(f) && f(&rr.A, "A", "ipv4")
294 type dnsRR_AAAA struct {
295 Hdr dnsRR_Header
296 AAAA [16]byte
299 func (rr *dnsRR_AAAA) Header() *dnsRR_Header {
300 return &rr.Hdr
303 func (rr *dnsRR_AAAA) Walk(f func(v interface{}, name, tag string) bool) bool {
304 return rr.Hdr.Walk(f) && f(rr.AAAA[:], "AAAA", "ipv6")
307 // Packing and unpacking.
309 // All the packers and unpackers take a (msg []byte, off int)
310 // and return (off1 int, ok bool). If they return ok==false, they
311 // also return off1==len(msg), so that the next unpacker will
312 // also fail. This lets us avoid checks of ok until the end of a
313 // packing sequence.
315 // Map of constructors for each RR wire type.
316 var rr_mk = map[int]func() dnsRR{
317 dnsTypeCNAME: func() dnsRR { return new(dnsRR_CNAME) },
318 dnsTypeMX: func() dnsRR { return new(dnsRR_MX) },
319 dnsTypeNS: func() dnsRR { return new(dnsRR_NS) },
320 dnsTypePTR: func() dnsRR { return new(dnsRR_PTR) },
321 dnsTypeSOA: func() dnsRR { return new(dnsRR_SOA) },
322 dnsTypeTXT: func() dnsRR { return new(dnsRR_TXT) },
323 dnsTypeSRV: func() dnsRR { return new(dnsRR_SRV) },
324 dnsTypeA: func() dnsRR { return new(dnsRR_A) },
325 dnsTypeAAAA: func() dnsRR { return new(dnsRR_AAAA) },
328 // Pack a domain name s into msg[off:].
329 // Domain names are a sequence of counted strings
330 // split at the dots. They end with a zero-length string.
331 func packDomainName(s string, msg []byte, off int) (off1 int, ok bool) {
332 // Add trailing dot to canonicalize name.
333 if n := len(s); n == 0 || s[n-1] != '.' {
334 s += "."
337 // Allow root domain.
338 if s == "." {
339 msg[off] = 0
340 off++
341 return off, true
344 // Each dot ends a segment of the name.
345 // We trade each dot byte for a length byte.
346 // There is also a trailing zero.
347 // Check that we have all the space we need.
348 tot := len(s) + 1
349 if off+tot > len(msg) {
350 return len(msg), false
353 // Emit sequence of counted strings, chopping at dots.
354 begin := 0
355 for i := 0; i < len(s); i++ {
356 if s[i] == '.' {
357 if i-begin >= 1<<6 { // top two bits of length must be clear
358 return len(msg), false
360 if i-begin == 0 {
361 return len(msg), false
364 msg[off] = byte(i - begin)
365 off++
367 for j := begin; j < i; j++ {
368 msg[off] = s[j]
369 off++
371 begin = i + 1
374 msg[off] = 0
375 off++
376 return off, true
379 // Unpack a domain name.
380 // In addition to the simple sequences of counted strings above,
381 // domain names are allowed to refer to strings elsewhere in the
382 // packet, to avoid repeating common suffixes when returning
383 // many entries in a single domain. The pointers are marked
384 // by a length byte with the top two bits set. Ignoring those
385 // two bits, that byte and the next give a 14 bit offset from msg[0]
386 // where we should pick up the trail.
387 // Note that if we jump elsewhere in the packet,
388 // we return off1 == the offset after the first pointer we found,
389 // which is where the next record will start.
390 // In theory, the pointers are only allowed to jump backward.
391 // We let them jump anywhere and stop jumping after a while.
392 func unpackDomainName(msg []byte, off int) (s string, off1 int, ok bool) {
393 s = ""
394 ptr := 0 // number of pointers followed
395 Loop:
396 for {
397 if off >= len(msg) {
398 return "", len(msg), false
400 c := int(msg[off])
401 off++
402 switch c & 0xC0 {
403 case 0x00:
404 if c == 0x00 {
405 // end of name
406 break Loop
408 // literal string
409 if off+c > len(msg) {
410 return "", len(msg), false
412 s += string(msg[off:off+c]) + "."
413 off += c
414 case 0xC0:
415 // pointer to somewhere else in msg.
416 // remember location after first ptr,
417 // since that's how many bytes we consumed.
418 // also, don't follow too many pointers --
419 // maybe there's a loop.
420 if off >= len(msg) {
421 return "", len(msg), false
423 c1 := msg[off]
424 off++
425 if ptr == 0 {
426 off1 = off
428 if ptr++; ptr > 10 {
429 return "", len(msg), false
431 off = (c^0xC0)<<8 | int(c1)
432 default:
433 // 0x80 and 0x40 are reserved
434 return "", len(msg), false
437 if len(s) == 0 {
438 s = "."
440 if ptr == 0 {
441 off1 = off
443 return s, off1, true
446 // packStruct packs a structure into msg at specified offset off, and
447 // returns off1 such that msg[off:off1] is the encoded data.
448 func packStruct(any dnsStruct, msg []byte, off int) (off1 int, ok bool) {
449 ok = any.Walk(func(field interface{}, name, tag string) bool {
450 switch fv := field.(type) {
451 default:
452 println("net: dns: unknown packing type")
453 return false
454 case *uint16:
455 i := *fv
456 if off+2 > len(msg) {
457 return false
459 msg[off] = byte(i >> 8)
460 msg[off+1] = byte(i)
461 off += 2
462 case *uint32:
463 i := *fv
464 msg[off] = byte(i >> 24)
465 msg[off+1] = byte(i >> 16)
466 msg[off+2] = byte(i >> 8)
467 msg[off+3] = byte(i)
468 off += 4
469 case []byte:
470 n := len(fv)
471 if off+n > len(msg) {
472 return false
474 copy(msg[off:off+n], fv)
475 off += n
476 case *string:
477 s := *fv
478 switch tag {
479 default:
480 println("net: dns: unknown string tag", tag)
481 return false
482 case "domain":
483 off, ok = packDomainName(s, msg, off)
484 if !ok {
485 return false
487 case "":
488 // Counted string: 1 byte length.
489 if len(s) > 255 || off+1+len(s) > len(msg) {
490 return false
492 msg[off] = byte(len(s))
493 off++
494 off += copy(msg[off:], s)
497 return true
499 if !ok {
500 return len(msg), false
502 return off, true
505 // unpackStruct decodes msg[off:] into the given structure, and
506 // returns off1 such that msg[off:off1] is the encoded data.
507 func unpackStruct(any dnsStruct, msg []byte, off int) (off1 int, ok bool) {
508 ok = any.Walk(func(field interface{}, name, tag string) bool {
509 switch fv := field.(type) {
510 default:
511 println("net: dns: unknown packing type")
512 return false
513 case *uint16:
514 if off+2 > len(msg) {
515 return false
517 *fv = uint16(msg[off])<<8 | uint16(msg[off+1])
518 off += 2
519 case *uint32:
520 if off+4 > len(msg) {
521 return false
523 *fv = uint32(msg[off])<<24 | uint32(msg[off+1])<<16 |
524 uint32(msg[off+2])<<8 | uint32(msg[off+3])
525 off += 4
526 case []byte:
527 n := len(fv)
528 if off+n > len(msg) {
529 return false
531 copy(fv, msg[off:off+n])
532 off += n
533 case *string:
534 var s string
535 switch tag {
536 default:
537 println("net: dns: unknown string tag", tag)
538 return false
539 case "domain":
540 s, off, ok = unpackDomainName(msg, off)
541 if !ok {
542 return false
544 case "":
545 if off >= len(msg) || off+1+int(msg[off]) > len(msg) {
546 return false
548 n := int(msg[off])
549 off++
550 b := make([]byte, n)
551 for i := 0; i < n; i++ {
552 b[i] = msg[off+i]
554 off += n
555 s = string(b)
557 *fv = s
559 return true
561 if !ok {
562 return len(msg), false
564 return off, true
567 // Generic struct printer. Prints fields with tag "ipv4" or "ipv6"
568 // as IP addresses.
569 func printStruct(any dnsStruct) string {
570 s := "{"
571 i := 0
572 any.Walk(func(val interface{}, name, tag string) bool {
574 if i > 1 {
575 s += ", "
577 s += name + "="
578 switch tag {
579 case "ipv4":
580 i := *val.(*uint32)
581 s += IPv4(byte(i>>24), byte(i>>16), byte(i>>8), byte(i)).String()
582 case "ipv6":
583 i := val.([]byte)
584 s += IP(i).String()
585 default:
586 var i int64
587 switch v := val.(type) {
588 default:
589 // can't really happen.
590 s += "<unknown type>"
591 return true
592 case *string:
593 s += *v
594 return true
595 case []byte:
596 s += string(v)
597 return true
598 case *bool:
599 if *v {
600 s += "true"
601 } else {
602 s += "false"
604 return true
605 case *int:
606 i = int64(*v)
607 case *uint:
608 i = int64(*v)
609 case *uint8:
610 i = int64(*v)
611 case *uint16:
612 i = int64(*v)
613 case *uint32:
614 i = int64(*v)
615 case *uint64:
616 i = int64(*v)
617 case *uintptr:
618 i = int64(*v)
620 s += itoa(int(i))
622 return true
624 s += "}"
625 return s
628 // Resource record packer.
629 func packRR(rr dnsRR, msg []byte, off int) (off2 int, ok bool) {
630 var off1 int
631 // pack twice, once to find end of header
632 // and again to find end of packet.
633 // a bit inefficient but this doesn't need to be fast.
634 // off1 is end of header
635 // off2 is end of rr
636 off1, ok = packStruct(rr.Header(), msg, off)
637 if !ok {
638 return len(msg), false
640 off2, ok = packStruct(rr, msg, off)
641 if !ok {
642 return len(msg), false
644 // pack a third time; redo header with correct data length
645 rr.Header().Rdlength = uint16(off2 - off1)
646 packStruct(rr.Header(), msg, off)
647 return off2, true
650 // Resource record unpacker.
651 func unpackRR(msg []byte, off int) (rr dnsRR, off1 int, ok bool) {
652 // unpack just the header, to find the rr type and length
653 var h dnsRR_Header
654 off0 := off
655 if off, ok = unpackStruct(&h, msg, off); !ok {
656 return nil, len(msg), false
658 end := off + int(h.Rdlength)
660 // make an rr of that type and re-unpack.
661 // again inefficient but doesn't need to be fast.
662 mk, known := rr_mk[int(h.Rrtype)]
663 if !known {
664 return &h, end, true
666 rr = mk()
667 off, ok = unpackStruct(rr, msg, off0)
668 if off != end {
669 return &h, end, true
671 return rr, off, ok
674 // Usable representation of a DNS packet.
676 // A manually-unpacked version of (id, bits).
677 // This is in its own struct for easy printing.
678 type dnsMsgHdr struct {
679 id uint16
680 response bool
681 opcode int
682 authoritative bool
683 truncated bool
684 recursion_desired bool
685 recursion_available bool
686 rcode int
689 func (h *dnsMsgHdr) Walk(f func(v interface{}, name, tag string) bool) bool {
690 return f(&h.id, "id", "") &&
691 f(&h.response, "response", "") &&
692 f(&h.opcode, "opcode", "") &&
693 f(&h.authoritative, "authoritative", "") &&
694 f(&h.truncated, "truncated", "") &&
695 f(&h.recursion_desired, "recursion_desired", "") &&
696 f(&h.recursion_available, "recursion_available", "") &&
697 f(&h.rcode, "rcode", "")
700 type dnsMsg struct {
701 dnsMsgHdr
702 question []dnsQuestion
703 answer []dnsRR
704 ns []dnsRR
705 extra []dnsRR
708 func (dns *dnsMsg) Pack() (msg []byte, ok bool) {
709 var dh dnsHeader
711 // Convert convenient dnsMsg into wire-like dnsHeader.
712 dh.Id = dns.id
713 dh.Bits = uint16(dns.opcode)<<11 | uint16(dns.rcode)
714 if dns.recursion_available {
715 dh.Bits |= _RA
717 if dns.recursion_desired {
718 dh.Bits |= _RD
720 if dns.truncated {
721 dh.Bits |= _TC
723 if dns.authoritative {
724 dh.Bits |= _AA
726 if dns.response {
727 dh.Bits |= _QR
730 // Prepare variable sized arrays.
731 question := dns.question
732 answer := dns.answer
733 ns := dns.ns
734 extra := dns.extra
736 dh.Qdcount = uint16(len(question))
737 dh.Ancount = uint16(len(answer))
738 dh.Nscount = uint16(len(ns))
739 dh.Arcount = uint16(len(extra))
741 // Could work harder to calculate message size,
742 // but this is far more than we need and not
743 // big enough to hurt the allocator.
744 msg = make([]byte, 2000)
746 // Pack it in: header and then the pieces.
747 off := 0
748 off, ok = packStruct(&dh, msg, off)
749 if !ok {
750 return nil, false
752 for i := 0; i < len(question); i++ {
753 off, ok = packStruct(&question[i], msg, off)
754 if !ok {
755 return nil, false
758 for i := 0; i < len(answer); i++ {
759 off, ok = packRR(answer[i], msg, off)
760 if !ok {
761 return nil, false
764 for i := 0; i < len(ns); i++ {
765 off, ok = packRR(ns[i], msg, off)
766 if !ok {
767 return nil, false
770 for i := 0; i < len(extra); i++ {
771 off, ok = packRR(extra[i], msg, off)
772 if !ok {
773 return nil, false
776 return msg[0:off], true
779 func (dns *dnsMsg) Unpack(msg []byte) bool {
780 // Header.
781 var dh dnsHeader
782 off := 0
783 var ok bool
784 if off, ok = unpackStruct(&dh, msg, off); !ok {
785 return false
787 dns.id = dh.Id
788 dns.response = (dh.Bits & _QR) != 0
789 dns.opcode = int(dh.Bits>>11) & 0xF
790 dns.authoritative = (dh.Bits & _AA) != 0
791 dns.truncated = (dh.Bits & _TC) != 0
792 dns.recursion_desired = (dh.Bits & _RD) != 0
793 dns.recursion_available = (dh.Bits & _RA) != 0
794 dns.rcode = int(dh.Bits & 0xF)
796 // Arrays.
797 dns.question = make([]dnsQuestion, dh.Qdcount)
798 dns.answer = make([]dnsRR, 0, dh.Ancount)
799 dns.ns = make([]dnsRR, 0, dh.Nscount)
800 dns.extra = make([]dnsRR, 0, dh.Arcount)
802 var rec dnsRR
804 for i := 0; i < len(dns.question); i++ {
805 off, ok = unpackStruct(&dns.question[i], msg, off)
806 if !ok {
807 return false
810 for i := 0; i < int(dh.Ancount); i++ {
811 rec, off, ok = unpackRR(msg, off)
812 if !ok {
813 return false
815 dns.answer = append(dns.answer, rec)
817 for i := 0; i < int(dh.Nscount); i++ {
818 rec, off, ok = unpackRR(msg, off)
819 if !ok {
820 return false
822 dns.ns = append(dns.ns, rec)
824 for i := 0; i < int(dh.Arcount); i++ {
825 rec, off, ok = unpackRR(msg, off)
826 if !ok {
827 return false
829 dns.extra = append(dns.extra, rec)
831 // if off != len(msg) {
832 // println("extra bytes in dns packet", off, "<", len(msg));
833 // }
834 return true
837 func (dns *dnsMsg) String() string {
838 s := "DNS: " + printStruct(&dns.dnsMsgHdr) + "\n"
839 if len(dns.question) > 0 {
840 s += "-- Questions\n"
841 for i := 0; i < len(dns.question); i++ {
842 s += printStruct(&dns.question[i]) + "\n"
845 if len(dns.answer) > 0 {
846 s += "-- Answers\n"
847 for i := 0; i < len(dns.answer); i++ {
848 s += printStruct(dns.answer[i]) + "\n"
851 if len(dns.ns) > 0 {
852 s += "-- Name servers\n"
853 for i := 0; i < len(dns.ns); i++ {
854 s += printStruct(dns.ns[i]) + "\n"
857 if len(dns.extra) > 0 {
858 s += "-- Extra\n"
859 for i := 0; i < len(dns.extra); i++ {
860 s += printStruct(dns.extra[i]) + "\n"
863 return s
866 // IsResponseTo reports whether m is an acceptable response to query.
867 func (m *dnsMsg) IsResponseTo(query *dnsMsg) bool {
868 if !m.response {
869 return false
871 if m.id != query.id {
872 return false
874 if len(m.question) != len(query.question) {
875 return false
877 for i, q := range m.question {
878 q2 := query.question[i]
879 if !equalASCIILabel(q.Name, q2.Name) || q.Qtype != q2.Qtype || q.Qclass != q2.Qclass {
880 return false
883 return true