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