src/pkg/net/dnsmsg.go - The Go Programming Language

Golang

Source file src/pkg/net/dnsmsg.go

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