~push-gopher/golang/tip

« back to all changes in this revision

Viewing changes to src/cmd/fix/testdata/reflect.dnsmsg.go.in

  • Committer: Push Gopher
  • Author(s): Mikio Hara
  • Date: 2013-07-22 11:08:58 UTC
  • Revision ID: push-gopher@niemeyer.net-20130722110858-qu0mq7ulldmjybbt
net: remove unnecessary bit masking

R=dave
CC=golang-dev
https://codereview.appspot.com/11537044
HG=17349:5c948e69f885

Show diffs side-by-side

added added

removed removed

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