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.
7 // This is intended to support name resolution during Dial.
8 // It doesn't have to be blazing fast.
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.
29 // valid dnsRR_Header.Rrtype and dnsQuestion.qtype
49 // valid dnsQuestion.qtype only
55 // valid dnsQuestion.qclass
64 dnsRcodeFormatError = 1
65 dnsRcodeServerFailure = 2
67 dnsRcodeNotImplemented = 4
71 // A dnsStruct describes how to iterate over its fields to emulate
72 // reflective marshalling.
73 type dnsStruct interface {
74 // Walk iterates over fields of a structure and calls f
75 // with a reference to that field, the name of the field
76 // and a tag ("", "domain", "ipv4", "ipv6") specifying
77 // particular encodings. Possible concrete types
78 // for v are *uint16, *uint32, *string, or []byte, and
79 // *int, *bool in the case of dnsMsgHdr.
80 // Whenever f returns false, Walk must stop and return
81 // false, and otherwise return true.
82 Walk(f func(v interface{}, name, tag string) (ok bool)) (ok bool)
85 // The wire format for the DNS packet header.
86 type dnsHeader struct {
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", "")
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
111 type dnsQuestion struct {
112 Name string `net:"domain-name"` // `net:"domain-name"` specifies encoding; see packers below
117 func (q *dnsQuestion) Walk(f func(v interface{}, name, tag string) bool) bool {
118 return f(&q.Name, "Name", "domain") &&
119 f(&q.Qtype, "Qtype", "") &&
120 f(&q.Qclass, "Qclass", "")
123 // DNS responses (resource records).
124 // There are many types of messages,
125 // but they all share the same header.
126 type dnsRR_Header struct {
127 Name string `net:"domain-name"`
131 Rdlength uint16 // length of data after header
134 func (h *dnsRR_Header) Header() *dnsRR_Header {
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 {
148 Header() *dnsRR_Header
151 // Specific DNS RR formats for each query type.
153 type dnsRR_CNAME struct {
155 Cname string `net:"domain-name"`
158 func (rr *dnsRR_CNAME) Header() *dnsRR_Header {
162 func (rr *dnsRR_CNAME) Walk(f func(v interface{}, name, tag string) bool) bool {
163 return rr.Hdr.Walk(f) && f(&rr.Cname, "Cname", "domain")
166 type dnsRR_HINFO struct {
172 func (rr *dnsRR_HINFO) Header() *dnsRR_Header {
176 func (rr *dnsRR_HINFO) Walk(f func(v interface{}, name, tag string) bool) bool {
177 return rr.Hdr.Walk(f) && f(&rr.Cpu, "Cpu", "") && f(&rr.Os, "Os", "")
180 type dnsRR_MB struct {
182 Mb string `net:"domain-name"`
185 func (rr *dnsRR_MB) Header() *dnsRR_Header {
189 func (rr *dnsRR_MB) Walk(f func(v interface{}, name, tag string) bool) bool {
190 return rr.Hdr.Walk(f) && f(&rr.Mb, "Mb", "domain")
193 type dnsRR_MG struct {
195 Mg string `net:"domain-name"`
198 func (rr *dnsRR_MG) Header() *dnsRR_Header {
202 func (rr *dnsRR_MG) Walk(f func(v interface{}, name, tag string) bool) bool {
203 return rr.Hdr.Walk(f) && f(&rr.Mg, "Mg", "domain")
206 type dnsRR_MINFO struct {
208 Rmail string `net:"domain-name"`
209 Email string `net:"domain-name"`
212 func (rr *dnsRR_MINFO) Header() *dnsRR_Header {
216 func (rr *dnsRR_MINFO) Walk(f func(v interface{}, name, tag string) bool) bool {
217 return rr.Hdr.Walk(f) && f(&rr.Rmail, "Rmail", "domain") && f(&rr.Email, "Email", "domain")
220 type dnsRR_MR struct {
222 Mr string `net:"domain-name"`
225 func (rr *dnsRR_MR) Header() *dnsRR_Header {
229 func (rr *dnsRR_MR) Walk(f func(v interface{}, name, tag string) bool) bool {
230 return rr.Hdr.Walk(f) && f(&rr.Mr, "Mr", "domain")
233 type dnsRR_MX struct {
236 Mx string `net:"domain-name"`
239 func (rr *dnsRR_MX) Header() *dnsRR_Header {
243 func (rr *dnsRR_MX) Walk(f func(v interface{}, name, tag string) bool) bool {
244 return rr.Hdr.Walk(f) && f(&rr.Pref, "Pref", "") && f(&rr.Mx, "Mx", "domain")
247 type dnsRR_NS struct {
249 Ns string `net:"domain-name"`
252 func (rr *dnsRR_NS) Header() *dnsRR_Header {
256 func (rr *dnsRR_NS) Walk(f func(v interface{}, name, tag string) bool) bool {
257 return rr.Hdr.Walk(f) && f(&rr.Ns, "Ns", "domain")
260 type dnsRR_PTR struct {
262 Ptr string `net:"domain-name"`
265 func (rr *dnsRR_PTR) Header() *dnsRR_Header {
269 func (rr *dnsRR_PTR) Walk(f func(v interface{}, name, tag string) bool) bool {
270 return rr.Hdr.Walk(f) && f(&rr.Ptr, "Ptr", "domain")
273 type dnsRR_SOA struct {
275 Ns string `net:"domain-name"`
276 Mbox string `net:"domain-name"`
284 func (rr *dnsRR_SOA) Header() *dnsRR_Header {
288 func (rr *dnsRR_SOA) Walk(f func(v interface{}, name, tag string) bool) bool {
289 return rr.Hdr.Walk(f) &&
290 f(&rr.Ns, "Ns", "domain") &&
291 f(&rr.Mbox, "Mbox", "domain") &&
292 f(&rr.Serial, "Serial", "") &&
293 f(&rr.Refresh, "Refresh", "") &&
294 f(&rr.Retry, "Retry", "") &&
295 f(&rr.Expire, "Expire", "") &&
296 f(&rr.Minttl, "Minttl", "")
299 type dnsRR_TXT struct {
301 Txt string // not domain name
304 func (rr *dnsRR_TXT) Header() *dnsRR_Header {
308 func (rr *dnsRR_TXT) Walk(f func(v interface{}, name, tag string) bool) bool {
309 return rr.Hdr.Walk(f) && f(&rr.Txt, "Txt", "")
312 type dnsRR_SRV struct {
317 Target string `net:"domain-name"`
320 func (rr *dnsRR_SRV) Header() *dnsRR_Header {
324 func (rr *dnsRR_SRV) Walk(f func(v interface{}, name, tag string) bool) bool {
325 return rr.Hdr.Walk(f) &&
326 f(&rr.Priority, "Priority", "") &&
327 f(&rr.Weight, "Weight", "") &&
328 f(&rr.Port, "Port", "") &&
329 f(&rr.Target, "Target", "domain")
332 type dnsRR_A struct {
334 A uint32 `net:"ipv4"`
337 func (rr *dnsRR_A) Header() *dnsRR_Header {
341 func (rr *dnsRR_A) Walk(f func(v interface{}, name, tag string) bool) bool {
342 return rr.Hdr.Walk(f) && f(&rr.A, "A", "ipv4")
345 type dnsRR_AAAA struct {
347 AAAA [16]byte `net:"ipv6"`
350 func (rr *dnsRR_AAAA) Header() *dnsRR_Header {
354 func (rr *dnsRR_AAAA) Walk(f func(v interface{}, name, tag string) bool) bool {
355 return rr.Hdr.Walk(f) && f(rr.AAAA[:], "AAAA", "ipv6")
358 // Packing and unpacking.
360 // All the packers and unpackers take a (msg []byte, off int)
361 // and return (off1 int, ok bool). If they return ok==false, they
362 // also return off1==len(msg), so that the next unpacker will
363 // also fail. This lets us avoid checks of ok until the end of a
366 // Map of constructors for each RR wire type.
367 var rr_mk = map[int]func() dnsRR{
368 dnsTypeCNAME: func() dnsRR { return new(dnsRR_CNAME) },
369 dnsTypeHINFO: func() dnsRR { return new(dnsRR_HINFO) },
370 dnsTypeMB: func() dnsRR { return new(dnsRR_MB) },
371 dnsTypeMG: func() dnsRR { return new(dnsRR_MG) },
372 dnsTypeMINFO: func() dnsRR { return new(dnsRR_MINFO) },
373 dnsTypeMR: func() dnsRR { return new(dnsRR_MR) },
374 dnsTypeMX: func() dnsRR { return new(dnsRR_MX) },
375 dnsTypeNS: func() dnsRR { return new(dnsRR_NS) },
376 dnsTypePTR: func() dnsRR { return new(dnsRR_PTR) },
377 dnsTypeSOA: func() dnsRR { return new(dnsRR_SOA) },
378 dnsTypeTXT: func() dnsRR { return new(dnsRR_TXT) },
379 dnsTypeSRV: func() dnsRR { return new(dnsRR_SRV) },
380 dnsTypeA: func() dnsRR { return new(dnsRR_A) },
381 dnsTypeAAAA: func() dnsRR { return new(dnsRR_AAAA) },
384 // Pack a domain name s into msg[off:].
385 // Domain names are a sequence of counted strings
386 // split at the dots. They end with a zero-length string.
387 func packDomainName(s string, msg []byte, off int) (off1 int, ok bool) {
388 // Add trailing dot to canonicalize name.
389 if n := len(s); n == 0 || s[n-1] != '.' {
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.
398 if off+tot > len(msg) {
399 return len(msg), false
402 // Emit sequence of counted strings, chopping at dots.
404 for i := 0; i < len(s); i++ {
406 if i-begin >= 1<<6 { // top two bits of length must be clear
407 return len(msg), false
409 msg[off] = byte(i - begin)
411 for j := begin; j < i; j++ {
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) {
438 ptr := 0 // number of pointers followed
442 return "", len(msg), false
453 if off+c > len(msg) {
454 return "", len(msg), false
456 s += string(msg[off:off+c]) + "."
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.
465 return "", len(msg), false
473 return "", len(msg), false
475 off = (c^0xC0)<<8 | int(c1)
477 // 0x80 and 0x40 are reserved
478 return "", len(msg), false
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) {
493 println("net: dns: unknown packing type")
497 if off+2 > len(msg) {
500 msg[off] = byte(i >> 8)
505 msg[off] = byte(i >> 24)
506 msg[off+1] = byte(i >> 16)
507 msg[off+2] = byte(i >> 8)
512 if off+n > len(msg) {
515 copy(msg[off:off+n], fv)
521 println("net: dns: unknown string tag", tag)
524 off, ok = packDomainName(s, msg, off)
529 // Counted string: 1 byte length.
530 if len(s) > 255 || off+1+len(s) > len(msg) {
533 msg[off] = byte(len(s))
535 off += copy(msg[off:], s)
541 return len(msg), false
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) {
552 println("net: dns: unknown packing type")
555 if off+2 > len(msg) {
558 *fv = uint16(msg[off])<<8 | uint16(msg[off+1])
561 if off+4 > len(msg) {
564 *fv = uint32(msg[off])<<24 | uint32(msg[off+1])<<16 |
565 uint32(msg[off+2])<<8 | uint32(msg[off+3])
569 if off+n > len(msg) {
572 copy(fv, msg[off:off+n])
578 println("net: dns: unknown string tag", tag)
581 s, off, ok = unpackDomainName(msg, off)
586 if off >= len(msg) || off+1+int(msg[off]) > len(msg) {
592 for i := 0; i < n; i++ {
603 return len(msg), false
608 // Generic struct printer. Prints fields with tag "ipv4" or "ipv6"
610 func printStruct(any dnsStruct) string {
613 any.Walk(func(val interface{}, name, tag string) bool {
622 s += IPv4(byte(i>>24), byte(i>>16), byte(i>>8), byte(i)).String()
628 switch v := val.(type) {
630 // can't really happen.
631 s += "<unknown type>"
669 // Resource record packer.
670 func packRR(rr dnsRR, msg []byte, off int) (off2 int, ok bool) {
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
677 off1, ok = packStruct(rr.Header(), msg, off)
678 off2, ok = packStruct(rr, msg, off)
680 return len(msg), false
682 // pack a third time; redo header with correct data length
683 rr.Header().Rdlength = uint16(off2 - off1)
684 packStruct(rr.Header(), msg, off)
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
693 if off, ok = unpackStruct(&h, msg, off); !ok {
694 return nil, len(msg), false
696 end := off + int(h.Rdlength)
698 // make an rr of that type and re-unpack.
699 // again inefficient but doesn't need to be fast.
700 mk, known := rr_mk[int(h.Rrtype)]
705 off, ok = unpackStruct(rr, msg, off0)
712 // Usable representation of a DNS packet.
714 // A manually-unpacked version of (id, bits).
715 // This is in its own struct for easy printing.
716 type dnsMsgHdr struct {
722 recursion_desired bool
723 recursion_available bool
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", "")
740 question []dnsQuestion
746 func (dns *dnsMsg) Pack() (msg []byte, ok bool) {
749 // Convert convenient dnsMsg into wire-like dnsHeader.
751 dh.Bits = uint16(dns.opcode)<<11 | uint16(dns.rcode)
752 if dns.recursion_available {
755 if dns.recursion_desired {
761 if dns.authoritative {
768 // Prepare variable sized arrays.
769 question := dns.question
774 dh.Qdcount = uint16(len(question))
775 dh.Ancount = uint16(len(answer))
776 dh.Nscount = uint16(len(ns))
777 dh.Arcount = uint16(len(extra))
779 // Could work harder to calculate message size,
780 // but this is far more than we need and not
781 // big enough to hurt the allocator.
782 msg = make([]byte, 2000)
784 // Pack it in: header and then the pieces.
786 off, ok = packStruct(&dh, msg, off)
787 for i := 0; i < len(question); i++ {
788 off, ok = packStruct(&question[i], msg, off)
790 for i := 0; i < len(answer); i++ {
791 off, ok = packRR(answer[i], msg, off)
793 for i := 0; i < len(ns); i++ {
794 off, ok = packRR(ns[i], msg, off)
796 for i := 0; i < len(extra); i++ {
797 off, ok = packRR(extra[i], msg, off)
802 return msg[0:off], true
805 func (dns *dnsMsg) Unpack(msg []byte) bool {
810 if off, ok = unpackStruct(&dh, msg, off); !ok {
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)
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)
830 for i := 0; i < len(dns.question); i++ {
831 off, ok = unpackStruct(&dns.question[i], msg, off)
833 for i := 0; i < int(dh.Ancount); i++ {
834 rec, off, ok = unpackRR(msg, off)
838 dns.answer = append(dns.answer, rec)
840 for i := 0; i < int(dh.Nscount); i++ {
841 rec, off, ok = unpackRR(msg, off)
845 dns.ns = append(dns.ns, rec)
847 for i := 0; i < int(dh.Arcount); i++ {
848 rec, off, ok = unpackRR(msg, off)
852 dns.extra = append(dns.extra, rec)
854 // if off != len(msg) {
855 // println("extra bytes in dns packet", off, "<", len(msg));
860 func (dns *dnsMsg) String() string {
861 s := "DNS: " + printStruct(&dns.dnsMsgHdr) + "\n"
862 if len(dns.question) > 0 {
863 s += "-- Questions\n"
864 for i := 0; i < len(dns.question); i++ {
865 s += printStruct(&dns.question[i]) + "\n"
868 if len(dns.answer) > 0 {
870 for i := 0; i < len(dns.answer); i++ {
871 s += printStruct(dns.answer[i]) + "\n"
875 s += "-- Name servers\n"
876 for i := 0; i < len(dns.ns); i++ {
877 s += printStruct(dns.ns[i]) + "\n"
880 if len(dns.extra) > 0 {
882 for i := 0; i < len(dns.extra); i++ {
883 s += printStruct(dns.extra[i]) + "\n"