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"