Imported Upstream version 4.7.2
[platform/upstream/gcc48.git] / libgo / go / 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 }