1// Copyright 2014 Google, Inc. All rights reserved.
2//
3// Use of this source code is governed by a BSD-style license
4// that can be found in the LICENSE file in the root of the source
5// tree.
6
7package layers
8
9import (
10	"encoding/binary"
11	"errors"
12	"fmt"
13	"net"
14
15	"github.com/google/gopacket"
16)
17
18// DNSClass defines the class associated with a request/response.  Different DNS
19// classes can be thought of as an array of parallel namespace trees.
20type DNSClass uint16
21
22// DNSClass known values.
23const (
24	DNSClassIN  DNSClass = 1   // Internet
25	DNSClassCS  DNSClass = 2   // the CSNET class (Obsolete)
26	DNSClassCH  DNSClass = 3   // the CHAOS class
27	DNSClassHS  DNSClass = 4   // Hesiod [Dyer 87]
28	DNSClassAny DNSClass = 255 // AnyClass
29)
30
31func (dc DNSClass) String() string {
32	switch dc {
33	default:
34		return "Unknown"
35	case DNSClassIN:
36		return "IN"
37	case DNSClassCS:
38		return "CS"
39	case DNSClassCH:
40		return "CH"
41	case DNSClassHS:
42		return "HS"
43	case DNSClassAny:
44		return "Any"
45	}
46}
47
48// DNSType defines the type of data being requested/returned in a
49// question/answer.
50type DNSType uint16
51
52// DNSType known values.
53const (
54	DNSTypeA     DNSType = 1  // a host address
55	DNSTypeNS    DNSType = 2  // an authoritative name server
56	DNSTypeMD    DNSType = 3  // a mail destination (Obsolete - use MX)
57	DNSTypeMF    DNSType = 4  // a mail forwarder (Obsolete - use MX)
58	DNSTypeCNAME DNSType = 5  // the canonical name for an alias
59	DNSTypeSOA   DNSType = 6  // marks the start of a zone of authority
60	DNSTypeMB    DNSType = 7  // a mailbox domain name (EXPERIMENTAL)
61	DNSTypeMG    DNSType = 8  // a mail group member (EXPERIMENTAL)
62	DNSTypeMR    DNSType = 9  // a mail rename domain name (EXPERIMENTAL)
63	DNSTypeNULL  DNSType = 10 // a null RR (EXPERIMENTAL)
64	DNSTypeWKS   DNSType = 11 // a well known service description
65	DNSTypePTR   DNSType = 12 // a domain name pointer
66	DNSTypeHINFO DNSType = 13 // host information
67	DNSTypeMINFO DNSType = 14 // mailbox or mail list information
68	DNSTypeMX    DNSType = 15 // mail exchange
69	DNSTypeTXT   DNSType = 16 // text strings
70	DNSTypeAAAA  DNSType = 28 // a IPv6 host address [RFC3596]
71	DNSTypeSRV   DNSType = 33 // server discovery [RFC2782] [RFC6195]
72)
73
74func (dt DNSType) String() string {
75	switch dt {
76	default:
77		return "Unknown"
78	case DNSTypeA:
79		return "A"
80	case DNSTypeNS:
81		return "NS"
82	case DNSTypeMD:
83		return "MD"
84	case DNSTypeMF:
85		return "MF"
86	case DNSTypeCNAME:
87		return "CNAME"
88	case DNSTypeSOA:
89		return "SOA"
90	case DNSTypeMB:
91		return "MB"
92	case DNSTypeMG:
93		return "MG"
94	case DNSTypeMR:
95		return "MR"
96	case DNSTypeNULL:
97		return "NULL"
98	case DNSTypeWKS:
99		return "WKS"
100	case DNSTypePTR:
101		return "PTR"
102	case DNSTypeHINFO:
103		return "HINFO"
104	case DNSTypeMINFO:
105		return "MINFO"
106	case DNSTypeMX:
107		return "MX"
108	case DNSTypeTXT:
109		return "TXT"
110	case DNSTypeAAAA:
111		return "AAAA"
112	case DNSTypeSRV:
113		return "SRV"
114	}
115}
116
117// DNSResponseCode provides response codes for question answers.
118type DNSResponseCode uint8
119
120// DNSResponseCode known values.
121const (
122	DNSResponseCodeNoErr    DNSResponseCode = 0  // No error
123	DNSResponseCodeFormErr  DNSResponseCode = 1  // Format Error                       [RFC1035]
124	DNSResponseCodeServFail DNSResponseCode = 2  // Server Failure                     [RFC1035]
125	DNSResponseCodeNXDomain DNSResponseCode = 3  // Non-Existent Domain                [RFC1035]
126	DNSResponseCodeNotImp   DNSResponseCode = 4  // Not Implemented                    [RFC1035]
127	DNSResponseCodeRefused  DNSResponseCode = 5  // Query Refused                      [RFC1035]
128	DNSResponseCodeYXDomain DNSResponseCode = 6  // Name Exists when it should not     [RFC2136]
129	DNSResponseCodeYXRRSet  DNSResponseCode = 7  // RR Set Exists when it should not   [RFC2136]
130	DNSResponseCodeNXRRSet  DNSResponseCode = 8  // RR Set that should exist does not  [RFC2136]
131	DNSResponseCodeNotAuth  DNSResponseCode = 9  // Server Not Authoritative for zone  [RFC2136]
132	DNSResponseCodeNotZone  DNSResponseCode = 10 // Name not contained in zone         [RFC2136]
133	DNSResponseCodeBadVers  DNSResponseCode = 16 // Bad OPT Version                    [RFC2671]
134	DNSResponseCodeBadSig   DNSResponseCode = 16 // TSIG Signature Failure             [RFC2845]
135	DNSResponseCodeBadKey   DNSResponseCode = 17 // Key not recognized                 [RFC2845]
136	DNSResponseCodeBadTime  DNSResponseCode = 18 // Signature out of time window       [RFC2845]
137	DNSResponseCodeBadMode  DNSResponseCode = 19 // Bad TKEY Mode                      [RFC2930]
138	DNSResponseCodeBadName  DNSResponseCode = 20 // Duplicate key name                 [RFC2930]
139	DNSResponseCodeBadAlg   DNSResponseCode = 21 // Algorithm not supported            [RFC2930]
140	DNSResponseCodeBadTruc  DNSResponseCode = 22 // Bad Truncation                     [RFC4635]
141)
142
143func (drc DNSResponseCode) String() string {
144	switch drc {
145	default:
146		return "Unknown"
147	case DNSResponseCodeNoErr:
148		return "No Error"
149	case DNSResponseCodeFormErr:
150		return "Format Error"
151	case DNSResponseCodeServFail:
152		return "Server Failure "
153	case DNSResponseCodeNXDomain:
154		return "Non-Existent Domain"
155	case DNSResponseCodeNotImp:
156		return "Not Implemented"
157	case DNSResponseCodeRefused:
158		return "Query Refused"
159	case DNSResponseCodeYXDomain:
160		return "Name Exists when it should not"
161	case DNSResponseCodeYXRRSet:
162		return "RR Set Exists when it should not"
163	case DNSResponseCodeNXRRSet:
164		return "RR Set that should exist does not"
165	case DNSResponseCodeNotAuth:
166		return "Server Not Authoritative for zone"
167	case DNSResponseCodeNotZone:
168		return "Name not contained in zone"
169	case DNSResponseCodeBadVers:
170		return "Bad OPT Version"
171	case DNSResponseCodeBadKey:
172		return "Key not recognized"
173	case DNSResponseCodeBadTime:
174		return "Signature out of time window"
175	case DNSResponseCodeBadMode:
176		return "Bad TKEY Mode"
177	case DNSResponseCodeBadName:
178		return "Duplicate key name"
179	case DNSResponseCodeBadAlg:
180		return "Algorithm not supported"
181	case DNSResponseCodeBadTruc:
182		return "Bad Truncation"
183	}
184}
185
186// DNSOpCode defines a set of different operation types.
187type DNSOpCode uint8
188
189// DNSOpCode known values.
190const (
191	DNSOpCodeQuery  DNSOpCode = 0 // Query                  [RFC1035]
192	DNSOpCodeIQuery DNSOpCode = 1 // Inverse Query Obsolete [RFC3425]
193	DNSOpCodeStatus DNSOpCode = 2 // Status                 [RFC1035]
194	DNSOpCodeNotify DNSOpCode = 4 // Notify                 [RFC1996]
195	DNSOpCodeUpdate DNSOpCode = 5 // Update                 [RFC2136]
196)
197
198func (doc DNSOpCode) String() string {
199	switch doc {
200	default:
201		return "Unknown"
202	case DNSOpCodeQuery:
203		return "Query"
204	case DNSOpCodeIQuery:
205		return "Inverse Query"
206	case DNSOpCodeStatus:
207		return "Status"
208	case DNSOpCodeNotify:
209		return "Notify"
210	case DNSOpCodeUpdate:
211		return "Update"
212	}
213}
214
215// DNS is specified in RFC 1034 / RFC 1035
216// +---------------------+
217// |        Header       |
218// +---------------------+
219// |       Question      | the question for the name server
220// +---------------------+
221// |        Answer       | RRs answering the question
222// +---------------------+
223// |      Authority      | RRs pointing toward an authority
224// +---------------------+
225// |      Additional     | RRs holding additional information
226// +---------------------+
227//
228//  DNS Header
229//  0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
230//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
231//  |                      ID                       |
232//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
233//  |QR|   Opcode  |AA|TC|RD|RA|   Z    |   RCODE   |
234//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
235//  |                    QDCOUNT                    |
236//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
237//  |                    ANCOUNT                    |
238//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
239//  |                    NSCOUNT                    |
240//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
241//  |                    ARCOUNT                    |
242//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
243
244// DNS contains data from a single Domain Name Service packet.
245type DNS struct {
246	BaseLayer
247
248	// Header fields
249	ID     uint16
250	QR     bool
251	OpCode DNSOpCode
252
253	AA bool  // Authoritative answer
254	TC bool  // Truncated
255	RD bool  // Recursion desired
256	RA bool  // Recursion available
257	Z  uint8 // Reserved for future use
258
259	ResponseCode DNSResponseCode
260	QDCount      uint16 // Number of questions to expect
261	ANCount      uint16 // Number of answers to expect
262	NSCount      uint16 // Number of authorities to expect
263	ARCount      uint16 // Number of additional records to expect
264
265	// Entries
266	Questions   []DNSQuestion
267	Answers     []DNSResourceRecord
268	Authorities []DNSResourceRecord
269	Additionals []DNSResourceRecord
270
271	// buffer for doing name decoding.  We use a single reusable buffer to avoid
272	// name decoding on a single object via multiple DecodeFromBytes calls
273	// requiring constant allocation of small byte slices.
274	buffer []byte
275}
276
277// LayerType returns gopacket.LayerTypeDNS.
278func (d *DNS) LayerType() gopacket.LayerType { return LayerTypeDNS }
279
280// decodeDNS decodes the byte slice into a DNS type. It also
281// setups the application Layer in PacketBuilder.
282func decodeDNS(data []byte, p gopacket.PacketBuilder) error {
283	d := &DNS{}
284	err := d.DecodeFromBytes(data, p)
285	if err != nil {
286		return err
287	}
288	p.AddLayer(d)
289	p.SetApplicationLayer(d)
290	return nil
291}
292
293// DecodeFromBytes decodes the slice into the DNS struct.
294func (d *DNS) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
295	d.buffer = d.buffer[:0]
296
297	if len(data) < 12 {
298		df.SetTruncated()
299		return errDNSPacketTooShort
300	}
301
302	// since there are no further layers, the baselayer's content is
303	// pointing to this layer
304	d.BaseLayer = BaseLayer{Contents: data[:len(data)]}
305	d.ID = binary.BigEndian.Uint16(data[:2])
306	d.QR = data[2]&0x80 != 0
307	d.OpCode = DNSOpCode(data[2]>>3) & 0x0F
308	d.AA = data[2]&0x04 != 0
309	d.TC = data[2]&0x02 != 0
310	d.RD = data[2]&0x01 != 0
311	d.RA = data[3]&0x80 != 0
312	d.Z = uint8(data[3]>>4) & 0x7
313	d.ResponseCode = DNSResponseCode(data[3] & 0xF)
314	d.QDCount = binary.BigEndian.Uint16(data[4:6])
315	d.ANCount = binary.BigEndian.Uint16(data[6:8])
316	d.NSCount = binary.BigEndian.Uint16(data[8:10])
317	d.ARCount = binary.BigEndian.Uint16(data[10:12])
318
319	d.Questions = d.Questions[:0]
320	d.Answers = d.Answers[:0]
321	d.Authorities = d.Authorities[:0]
322	d.Additionals = d.Additionals[:0]
323
324	offset := 12
325	var err error
326	for i := 0; i < int(d.QDCount); i++ {
327		var q DNSQuestion
328		if offset, err = q.decode(data, offset, df, &d.buffer); err != nil {
329			return err
330		}
331		d.Questions = append(d.Questions, q)
332	}
333
334	// For some horrible reason, if we do the obvious thing in this loop:
335	//   var r DNSResourceRecord
336	//   if blah := r.decode(blah); err != nil {
337	//     return err
338	//   }
339	//   d.Foo = append(d.Foo, r)
340	// the Go compiler thinks that 'r' escapes to the heap, causing a malloc for
341	// every Answer, Authority, and Additional.  To get around this, we do
342	// something really silly:  we append an empty resource record to our slice,
343	// then use the last value in the slice to call decode.  Since the value is
344	// already in the slice, there's no WAY it can escape... on the other hand our
345	// code is MUCH uglier :(
346	for i := 0; i < int(d.ANCount); i++ {
347		d.Answers = append(d.Answers, DNSResourceRecord{})
348		if offset, err = d.Answers[i].decode(data, offset, df, &d.buffer); err != nil {
349			d.Answers = d.Answers[:i] // strip off erroneous value
350			return err
351		}
352	}
353	for i := 0; i < int(d.NSCount); i++ {
354		d.Authorities = append(d.Authorities, DNSResourceRecord{})
355		if offset, err = d.Authorities[i].decode(data, offset, df, &d.buffer); err != nil {
356			d.Authorities = d.Authorities[:i] // strip off erroneous value
357			return err
358		}
359	}
360	for i := 0; i < int(d.ARCount); i++ {
361		d.Additionals = append(d.Additionals, DNSResourceRecord{})
362		if offset, err = d.Additionals[i].decode(data, offset, df, &d.buffer); err != nil {
363			d.Additionals = d.Additionals[:i] // strip off erroneous value
364			return err
365		}
366	}
367
368	if uint16(len(d.Questions)) != d.QDCount {
369		return errDecodeQueryBadQDCount
370	} else if uint16(len(d.Answers)) != d.ANCount {
371		return errDecodeQueryBadANCount
372	} else if uint16(len(d.Authorities)) != d.NSCount {
373		return errDecodeQueryBadNSCount
374	} else if uint16(len(d.Additionals)) != d.ARCount {
375		return errDecodeQueryBadARCount
376	}
377	return nil
378}
379
380// CanDecode implements gopacket.DecodingLayer.
381func (d *DNS) CanDecode() gopacket.LayerClass {
382	return LayerTypeDNS
383}
384
385// NextLayerType implements gopacket.DecodingLayer.
386func (d *DNS) NextLayerType() gopacket.LayerType {
387	return gopacket.LayerTypePayload
388}
389
390// Payload returns nil.
391func (d *DNS) Payload() []byte {
392	return nil
393}
394
395func b2i(b bool) int {
396	if b {
397		return 1
398	}
399	return 0
400}
401
402func recSize(rr *DNSResourceRecord) int {
403	switch rr.Type {
404	case DNSTypeA:
405		return 4
406	case DNSTypeAAAA:
407		return 16
408	case DNSTypeNS:
409		return len(rr.NS) + 2
410	case DNSTypeCNAME:
411		return len(rr.CNAME) + 2
412	case DNSTypePTR:
413		return len(rr.PTR) + 2
414	case DNSTypeSOA:
415		return len(rr.SOA.MName) + 2 + len(rr.SOA.RName) + 2 + 20
416	case DNSTypeMX:
417		return 2 + len(rr.MX.Name) + 2
418	case DNSTypeTXT:
419		l := len(rr.TXTs)
420		for _, txt := range rr.TXTs {
421			l += len(txt)
422		}
423		return l
424	case DNSTypeSRV:
425		return 6 + len(rr.SRV.Name) + 2
426	}
427
428	return 0
429}
430
431func computeSize(recs []DNSResourceRecord) int {
432	sz := 0
433	for _, rr := range recs {
434		sz += len(rr.Name) + 12
435		sz += recSize(&rr)
436	}
437	return sz
438}
439
440// SerializeTo writes the serialized form of this layer into the
441// SerializationBuffer, implementing gopacket.SerializableLayer.
442func (d *DNS) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
443	dsz := 0
444	for _, q := range d.Questions {
445		dsz += len(q.Name) + 6
446	}
447	dsz += computeSize(d.Answers)
448	dsz += computeSize(d.Authorities)
449	dsz += computeSize(d.Additionals)
450
451	bytes, err := b.PrependBytes(12 + dsz)
452	if err != nil {
453		return err
454	}
455	binary.BigEndian.PutUint16(bytes, d.ID)
456	bytes[2] = byte((b2i(d.QR) << 7) | (int(d.OpCode) << 3) | (b2i(d.AA) << 2) | (b2i(d.TC) << 1) | b2i(d.RD))
457	bytes[3] = byte((b2i(d.RA) << 7) | (int(d.Z) << 4) | int(d.ResponseCode))
458
459	if opts.FixLengths {
460		d.QDCount = uint16(len(d.Questions))
461		d.ANCount = uint16(len(d.Answers))
462		d.NSCount = uint16(len(d.Authorities))
463		d.ARCount = uint16(len(d.Additionals))
464	}
465	binary.BigEndian.PutUint16(bytes[4:], d.QDCount)
466	binary.BigEndian.PutUint16(bytes[6:], d.ANCount)
467	binary.BigEndian.PutUint16(bytes[8:], d.NSCount)
468	binary.BigEndian.PutUint16(bytes[10:], d.ARCount)
469
470	off := 12
471	for _, qd := range d.Questions {
472		n := qd.encode(bytes, off)
473		off += n
474	}
475
476	for i := range d.Answers {
477		// done this way so we can modify DNSResourceRecord to fix
478		// lengths if requested
479		qa := &d.Answers[i]
480		n, err := qa.encode(bytes, off, opts)
481		if err != nil {
482			return err
483		}
484		off += n
485	}
486
487	for i := range d.Authorities {
488		qa := &d.Authorities[i]
489		n, err := qa.encode(bytes, off, opts)
490		if err != nil {
491			return err
492		}
493		off += n
494	}
495	for i := range d.Additionals {
496		qa := &d.Additionals[i]
497		n, err := qa.encode(bytes, off, opts)
498		if err != nil {
499			return err
500		}
501		off += n
502	}
503
504	return nil
505}
506
507const maxRecursionLevel = 255
508
509func decodeName(data []byte, offset int, buffer *[]byte, level int) ([]byte, int, error) {
510	if level > maxRecursionLevel {
511		return nil, 0, errMaxRecursion
512	} else if offset >= len(data) {
513		return nil, 0, errDNSNameOffsetTooHigh
514	} else if offset < 0 {
515		return nil, 0, errDNSNameOffsetNegative
516	}
517	start := len(*buffer)
518	index := offset
519	if data[index] == 0x00 {
520		return nil, index + 1, nil
521	}
522loop:
523	for data[index] != 0x00 {
524		switch data[index] & 0xc0 {
525		default:
526			/* RFC 1035
527			   A domain name represented as a sequence of labels, where
528			   each label consists of a length octet followed by that
529			   number of octets.  The domain name terminates with the
530			   zero length octet for the null label of the root.  Note
531			   that this field may be an odd number of octets; no
532			   padding is used.
533			*/
534			index2 := index + int(data[index]) + 1
535			if index2-offset > 255 {
536				return nil, 0, errDNSNameTooLong
537			} else if index2 < index+1 || index2 > len(data) {
538				return nil, 0, errDNSNameInvalidIndex
539			}
540			*buffer = append(*buffer, '.')
541			*buffer = append(*buffer, data[index+1:index2]...)
542			index = index2
543
544		case 0xc0:
545			/* RFC 1035
546			   The pointer takes the form of a two octet sequence.
547
548			   The first two bits are ones.  This allows a pointer to
549			   be distinguished from a label, since the label must
550			   begin with two zero bits because labels are restricted
551			   to 63 octets or less.  (The 10 and 01 combinations are
552			   reserved for future use.)  The OFFSET field specifies
553			   an offset from the start of the message (i.e., the
554			   first octet of the ID field in the domain header).  A
555			   zero offset specifies the first byte of the ID field,
556			   etc.
557
558			   The compression scheme allows a domain name in a message to be
559			   represented as either:
560			      - a sequence of labels ending in a zero octet
561			      - a pointer
562			      - a sequence of labels ending with a pointer
563			*/
564			if index+2 > len(data) {
565				return nil, 0, errDNSPointerOffsetTooHigh
566			}
567			offsetp := int(binary.BigEndian.Uint16(data[index:index+2]) & 0x3fff)
568			if offsetp > len(data) {
569				return nil, 0, errDNSPointerOffsetTooHigh
570			}
571			// This looks a little tricky, but actually isn't.  Because of how
572			// decodeName is written, calling it appends the decoded name to the
573			// current buffer.  We already have the start of the buffer, then, so
574			// once this call is done buffer[start:] will contain our full name.
575			_, _, err := decodeName(data, offsetp, buffer, level+1)
576			if err != nil {
577				return nil, 0, err
578			}
579			index++ // pointer is two bytes, so add an extra byte here.
580			break loop
581		/* EDNS, or other DNS option ? */
582		case 0x40: // RFC 2673
583			return nil, 0, fmt.Errorf("qname '0x40' - RFC 2673 unsupported yet (data=%x index=%d)",
584				data[index], index)
585
586		case 0x80:
587			return nil, 0, fmt.Errorf("qname '0x80' unsupported yet (data=%x index=%d)",
588				data[index], index)
589		}
590		if index >= len(data) {
591			return nil, 0, errDNSIndexOutOfRange
592		}
593	}
594	if len(*buffer) <= start {
595		return nil, 0, errDNSNameHasNoData
596	}
597	return (*buffer)[start+1:], index + 1, nil
598}
599
600// DNSQuestion wraps a single request (question) within a DNS query.
601type DNSQuestion struct {
602	Name  []byte
603	Type  DNSType
604	Class DNSClass
605}
606
607func (q *DNSQuestion) decode(data []byte, offset int, df gopacket.DecodeFeedback, buffer *[]byte) (int, error) {
608	name, endq, err := decodeName(data, offset, buffer, 1)
609	if err != nil {
610		return 0, err
611	}
612
613	q.Name = name
614	q.Type = DNSType(binary.BigEndian.Uint16(data[endq : endq+2]))
615	q.Class = DNSClass(binary.BigEndian.Uint16(data[endq+2 : endq+4]))
616
617	return endq + 4, nil
618}
619
620func (q *DNSQuestion) encode(data []byte, offset int) int {
621	noff := encodeName(q.Name, data, offset)
622	binary.BigEndian.PutUint16(data[noff:], uint16(q.Type))
623	binary.BigEndian.PutUint16(data[noff+2:], uint16(q.Class))
624	return len(q.Name) + 6
625}
626
627//  DNSResourceRecord
628//  0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
629//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
630//  |                                               |
631//  /                                               /
632//  /                      NAME                     /
633//  |                                               |
634//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
635//  |                      TYPE                     |
636//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
637//  |                     CLASS                     |
638//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
639//  |                      TTL                      |
640//  |                                               |
641//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
642//  |                   RDLENGTH                    |
643//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
644//  /                     RDATA                     /
645//  /                                               /
646//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
647
648// DNSResourceRecord wraps the data from a single DNS resource within a
649// response.
650type DNSResourceRecord struct {
651	// Header
652	Name  []byte
653	Type  DNSType
654	Class DNSClass
655	TTL   uint32
656
657	// RDATA Raw Values
658	DataLength uint16
659	Data       []byte
660
661	// RDATA Decoded Values
662	IP             net.IP
663	NS, CNAME, PTR []byte
664	TXTs           [][]byte
665	SOA            DNSSOA
666	SRV            DNSSRV
667	MX             DNSMX
668
669	// Undecoded TXT for backward compatibility
670	TXT []byte
671}
672
673// decode decodes the resource record, returning the total length of the record.
674func (rr *DNSResourceRecord) decode(data []byte, offset int, df gopacket.DecodeFeedback, buffer *[]byte) (int, error) {
675	name, endq, err := decodeName(data, offset, buffer, 1)
676	if err != nil {
677		return 0, err
678	}
679
680	rr.Name = name
681	rr.Type = DNSType(binary.BigEndian.Uint16(data[endq : endq+2]))
682	rr.Class = DNSClass(binary.BigEndian.Uint16(data[endq+2 : endq+4]))
683	rr.TTL = binary.BigEndian.Uint32(data[endq+4 : endq+8])
684	rr.DataLength = binary.BigEndian.Uint16(data[endq+8 : endq+10])
685	end := endq + 10 + int(rr.DataLength)
686	if end > len(data) {
687		return 0, errDecodeRecordLength
688	}
689	rr.Data = data[endq+10 : end]
690
691	if err = rr.decodeRData(data, endq+10, buffer); err != nil {
692		return 0, err
693	}
694
695	return endq + 10 + int(rr.DataLength), nil
696}
697
698func encodeName(name []byte, data []byte, offset int) int {
699	l := 0
700	for i := range name {
701		if name[i] == '.' {
702			data[offset+i-l] = byte(l)
703			l = 0
704		} else {
705			// skip one to write the length
706			data[offset+i+1] = name[i]
707			l++
708		}
709	}
710	// length for final portion
711	data[offset+len(name)-l] = byte(l)
712	data[offset+len(name)+1] = 0x00 // terminal
713	return offset + len(name) + 2
714}
715
716func (rr *DNSResourceRecord) encode(data []byte, offset int, opts gopacket.SerializeOptions) (int, error) {
717
718	noff := encodeName(rr.Name, data, offset)
719
720	binary.BigEndian.PutUint16(data[noff:], uint16(rr.Type))
721	binary.BigEndian.PutUint16(data[noff+2:], uint16(rr.Class))
722	binary.BigEndian.PutUint32(data[noff+4:], uint32(rr.TTL))
723
724	switch rr.Type {
725	case DNSTypeA:
726		copy(data[noff+10:], rr.IP.To4())
727	case DNSTypeAAAA:
728		copy(data[noff+10:], rr.IP)
729	case DNSTypeNS:
730		encodeName(rr.NS, data, noff+10)
731	case DNSTypeCNAME:
732		encodeName(rr.CNAME, data, noff+10)
733	case DNSTypePTR:
734		encodeName(rr.PTR, data, noff+10)
735	case DNSTypeSOA:
736		noff2 := encodeName(rr.SOA.MName, data, noff+10)
737		noff2 = encodeName(rr.SOA.RName, data, noff2)
738		binary.BigEndian.PutUint32(data[noff2:], rr.SOA.Serial)
739		binary.BigEndian.PutUint32(data[noff2+4:], rr.SOA.Refresh)
740		binary.BigEndian.PutUint32(data[noff2+8:], rr.SOA.Retry)
741		binary.BigEndian.PutUint32(data[noff2+12:], rr.SOA.Expire)
742		binary.BigEndian.PutUint32(data[noff2+16:], rr.SOA.Minimum)
743	case DNSTypeMX:
744		binary.BigEndian.PutUint16(data[noff+10:], rr.MX.Preference)
745		encodeName(rr.MX.Name, data, noff+12)
746	case DNSTypeTXT:
747		noff2 := noff + 10
748		for _, txt := range rr.TXTs {
749			data[noff2] = byte(len(txt))
750			copy(data[noff2+1:], txt)
751			noff2 += 1 + len(txt)
752		}
753	case DNSTypeSRV:
754		binary.BigEndian.PutUint16(data[noff+10:], rr.SRV.Priority)
755		binary.BigEndian.PutUint16(data[noff+12:], rr.SRV.Weight)
756		binary.BigEndian.PutUint16(data[noff+14:], rr.SRV.Port)
757		encodeName(rr.SRV.Name, data, noff+16)
758	default:
759		return 0, fmt.Errorf("serializing resource record of type %v not supported", rr.Type)
760	}
761
762	// DataLength
763	dSz := recSize(rr)
764	binary.BigEndian.PutUint16(data[noff+8:], uint16(dSz))
765
766	if opts.FixLengths {
767		rr.DataLength = uint16(dSz)
768	}
769
770	return len(rr.Name) + 1 + 11 + dSz, nil
771}
772
773func (rr *DNSResourceRecord) String() string {
774
775	if rr.Class == DNSClassIN {
776		switch rr.Type {
777		case DNSTypeA, DNSTypeAAAA:
778			return rr.IP.String()
779		case DNSTypeNS:
780			return "NS " + string(rr.NS)
781		case DNSTypeCNAME:
782			return "CNAME " + string(rr.CNAME)
783		case DNSTypePTR:
784			return "PTR " + string(rr.PTR)
785		case DNSTypeTXT:
786			return "TXT " + string(rr.TXT)
787		}
788	}
789
790	return fmt.Sprintf("<%v, %v>", rr.Class, rr.Type)
791}
792
793func decodeCharacterStrings(data []byte) ([][]byte, error) {
794	strings := make([][]byte, 0, 1)
795	end := len(data)
796	for index, index2 := 0, 0; index != end; index = index2 {
797		index2 = index + 1 + int(data[index]) // index increases by 1..256 and does not overflow
798		if index2 > end {
799			return nil, errCharStringMissData
800		}
801		strings = append(strings, data[index+1:index2])
802	}
803	return strings, nil
804}
805
806func (rr *DNSResourceRecord) decodeRData(data []byte, offset int, buffer *[]byte) error {
807	switch rr.Type {
808	case DNSTypeA:
809		rr.IP = rr.Data
810	case DNSTypeAAAA:
811		rr.IP = rr.Data
812	case DNSTypeTXT, DNSTypeHINFO:
813		rr.TXT = rr.Data
814		txts, err := decodeCharacterStrings(rr.Data)
815		if err != nil {
816			return err
817		}
818		rr.TXTs = txts
819	case DNSTypeNS:
820		name, _, err := decodeName(data, offset, buffer, 1)
821		if err != nil {
822			return err
823		}
824		rr.NS = name
825	case DNSTypeCNAME:
826		name, _, err := decodeName(data, offset, buffer, 1)
827		if err != nil {
828			return err
829		}
830		rr.CNAME = name
831	case DNSTypePTR:
832		name, _, err := decodeName(data, offset, buffer, 1)
833		if err != nil {
834			return err
835		}
836		rr.PTR = name
837	case DNSTypeSOA:
838		name, endq, err := decodeName(data, offset, buffer, 1)
839		if err != nil {
840			return err
841		}
842		rr.SOA.MName = name
843		name, endq, err = decodeName(data, endq, buffer, 1)
844		if err != nil {
845			return err
846		}
847		rr.SOA.RName = name
848		rr.SOA.Serial = binary.BigEndian.Uint32(data[endq : endq+4])
849		rr.SOA.Refresh = binary.BigEndian.Uint32(data[endq+4 : endq+8])
850		rr.SOA.Retry = binary.BigEndian.Uint32(data[endq+8 : endq+12])
851		rr.SOA.Expire = binary.BigEndian.Uint32(data[endq+12 : endq+16])
852		rr.SOA.Minimum = binary.BigEndian.Uint32(data[endq+16 : endq+20])
853	case DNSTypeMX:
854		rr.MX.Preference = binary.BigEndian.Uint16(data[offset : offset+2])
855		name, _, err := decodeName(data, offset+2, buffer, 1)
856		if err != nil {
857			return err
858		}
859		rr.MX.Name = name
860	case DNSTypeSRV:
861		rr.SRV.Priority = binary.BigEndian.Uint16(data[offset : offset+2])
862		rr.SRV.Weight = binary.BigEndian.Uint16(data[offset+2 : offset+4])
863		rr.SRV.Port = binary.BigEndian.Uint16(data[offset+4 : offset+6])
864		name, _, err := decodeName(data, offset+6, buffer, 1)
865		if err != nil {
866			return err
867		}
868		rr.SRV.Name = name
869	}
870	return nil
871}
872
873// DNSSOA is a Start of Authority record.  Each domain requires a SOA record at
874// the cutover where a domain is delegated from its parent.
875type DNSSOA struct {
876	MName, RName                            []byte
877	Serial, Refresh, Retry, Expire, Minimum uint32
878}
879
880// DNSSRV is a Service record, defining a location (hostname/port) of a
881// server/service.
882type DNSSRV struct {
883	Priority, Weight, Port uint16
884	Name                   []byte
885}
886
887// DNSMX is a mail exchange record, defining a mail server for a recipient's
888// domain.
889type DNSMX struct {
890	Preference uint16
891	Name       []byte
892}
893
894var (
895	errMaxRecursion = errors.New("max DNS recursion level hit")
896
897	errDNSNameOffsetTooHigh    = errors.New("dns name offset too high")
898	errDNSNameOffsetNegative   = errors.New("dns name offset is negative")
899	errDNSPacketTooShort       = errors.New("DNS packet too short")
900	errDNSNameTooLong          = errors.New("dns name is too long")
901	errDNSNameInvalidIndex     = errors.New("dns name uncomputable: invalid index")
902	errDNSPointerOffsetTooHigh = errors.New("dns offset pointer too high")
903	errDNSIndexOutOfRange      = errors.New("dns index walked out of range")
904	errDNSNameHasNoData        = errors.New("no dns data found for name")
905
906	errCharStringMissData = errors.New("Insufficient data for a <character-string>")
907
908	errDecodeRecordLength = errors.New("resource record length exceeds data")
909
910	errDecodeQueryBadQDCount = errors.New("Invalid query decoding, not the right number of questions")
911	errDecodeQueryBadANCount = errors.New("Invalid query decoding, not the right number of answers")
912	errDecodeQueryBadNSCount = errors.New("Invalid query decoding, not the right number of authorities")
913	errDecodeQueryBadARCount = errors.New("Invalid query decoding, not the right number of additionals info")
914)
915