Add CC0 COPYING file.
[dnstt.git] / dns / dns.go
blob45b75ee3ae3cefd8486817fb89049e74521b78cc
1 // Package dns deals with encoding and decoding DNS wire format.
2 package dns
4 import (
5 "bytes"
6 "encoding/binary"
7 "errors"
8 "fmt"
9 "io"
10 "strings"
13 // The maximum number of DNS name compression pointers we are willing to follow.
14 // Without something like this, infinite loops are possible.
15 const compressionPointerLimit = 10
17 var (
18 // ErrZeroLengthLabel is the error returned for names that contain a
19 // zero-length label, like "example..com".
20 ErrZeroLengthLabel = errors.New("name contains a zero-length label")
22 // ErrLabelTooLong is the error returned for labels that are longer than
23 // 63 octets.
24 ErrLabelTooLong = errors.New("name contains a label longer than 63 octets")
26 // ErrNameTooLong is the error returned for names whose encoded
27 // representation is longer than 255 octets.
28 ErrNameTooLong = errors.New("name is longer than 255 octets")
30 // ErrReservedLabelType is the error returned when reading a label type
31 // prefix whose two most significant bits are not 00 or 11.
32 ErrReservedLabelType = errors.New("reserved label type")
34 // ErrTooManyPointers is the error returned when reading a compressed
35 // name that has too many compression pointers.
36 ErrTooManyPointers = errors.New("too many compression pointers")
38 // ErrTrailingBytes is the error returned when bytes remain in the parse
39 // buffer after parsing a message.
40 ErrTrailingBytes = errors.New("trailing bytes after message")
42 // ErrIntegerOverflow is the error returned when trying to encode an
43 // integer greater than 65535 into a 16-bit field.
44 ErrIntegerOverflow = errors.New("integer overflow")
47 const (
48 // https://tools.ietf.org/html/rfc1035#section-3.2.2
49 RRTypeTXT = 16
50 // https://tools.ietf.org/html/rfc6891#section-6.1.1
51 RRTypeOPT = 41
53 // https://tools.ietf.org/html/rfc1035#section-3.2.4
54 ClassIN = 1
56 // https://tools.ietf.org/html/rfc1035#section-4.1.1
57 RcodeNoError = 0 // a.k.a. NOERROR
58 RcodeFormatError = 1 // a.k.a. FORMERR
59 RcodeNameError = 3 // a.k.a. NXDOMAIN
60 RcodeNotImplemented = 4 // a.k.a. NOTIMPL
61 // https://tools.ietf.org/html/rfc6891#section-9
62 ExtendedRcodeBadVers = 16 // a.k.a. BADVERS
65 // Name represents a domain name, a sequence of labels each of which is 63
66 // octets or less in length.
68 // https://tools.ietf.org/html/rfc1035#section-3.1
69 type Name [][]byte
71 // NewName returns a Name from a slice of labels, after checking the labels for
72 // validity. Does not include a zero-length label at the end of the slice.
73 func NewName(labels [][]byte) (Name, error) {
74 name := Name(labels)
75 // https://tools.ietf.org/html/rfc1035#section-2.3.4
76 // Various objects and parameters in the DNS have size limits.
77 // labels 63 octets or less
78 // names 255 octets or less
79 for _, label := range labels {
80 if len(label) == 0 {
81 return nil, ErrZeroLengthLabel
83 if len(label) > 63 {
84 return nil, ErrLabelTooLong
87 // Check the total length.
88 builder := newMessageBuilder()
89 builder.WriteName(name)
90 if len(builder.Bytes()) > 255 {
91 return nil, ErrNameTooLong
93 return name, nil
96 // ParseName returns a new Name from a string of labels separated by dots, after
97 // checking the name for validity. A single dot at the end of the string is
98 // ignored.
99 func ParseName(s string) (Name, error) {
100 b := bytes.TrimSuffix([]byte(s), []byte("."))
101 if len(b) == 0 {
102 // bytes.Split(b, ".") would return [""] in this case
103 return NewName([][]byte{})
104 } else {
105 return NewName(bytes.Split(b, []byte(".")))
109 // String returns a reversible string representation of name. Labels are
110 // separated by dots, and any bytes in a label that are outside the set
111 // [0-9A-Za-z-] are replaced with a \xXX hex escape sequence.
112 func (name Name) String() string {
113 if len(name) == 0 {
114 return "."
117 var buf strings.Builder
118 for i, label := range name {
119 if i > 0 {
120 buf.WriteByte('.')
122 for _, b := range label {
123 if b == '-' ||
124 ('0' <= b && b <= '9') ||
125 ('A' <= b && b <= 'Z') ||
126 ('a' <= b && b <= 'z') {
127 buf.WriteByte(b)
128 } else {
129 fmt.Fprintf(&buf, "\\x%02x", b)
133 return buf.String()
136 // TrimSuffix returns a Name with the given suffix removed, if it was present.
137 // The second return value indicates whether the suffix was present. If the
138 // suffix was not present, the first return value is nil.
139 func (name Name) TrimSuffix(suffix Name) (Name, bool) {
140 if len(name) < len(suffix) {
141 return nil, false
143 split := len(name) - len(suffix)
144 fore, aft := name[:split], name[split:]
145 for i := 0; i < len(aft); i++ {
146 if !bytes.Equal(bytes.ToLower(aft[i]), bytes.ToLower(suffix[i])) {
147 return nil, false
150 return fore, true
153 // Message represents a DNS message.
155 // https://tools.ietf.org/html/rfc1035#section-4.1
156 type Message struct {
157 ID uint16
158 Flags uint16
160 Question []Question
161 Answer []RR
162 Authority []RR
163 Additional []RR
166 // Opcode extracts the OPCODE part of the Flags field.
168 // https://tools.ietf.org/html/rfc1035#section-4.1.1
169 func (message *Message) Opcode() uint16 {
170 return (message.Flags >> 11) & 0xf
173 // Rcode extracts the RCODE part of the Flags field.
175 // https://tools.ietf.org/html/rfc1035#section-4.1.1
176 func (message *Message) Rcode() uint16 {
177 return message.Flags & 0x000f
180 // Question represents an entry in the question section of a message.
182 // https://tools.ietf.org/html/rfc1035#section-4.1.2
183 type Question struct {
184 Name Name
185 Type uint16
186 Class uint16
189 // RR represents a resource record.
191 // https://tools.ietf.org/html/rfc1035#section-4.1.3
192 type RR struct {
193 Name Name
194 Type uint16
195 Class uint16
196 TTL uint32
197 Data []byte
200 // readName parses a DNS name from r. It leaves r positioned just after the
201 // parsed name.
202 func readName(r io.ReadSeeker) (Name, error) {
203 var labels [][]byte
204 // We limit the number of compression pointers we are willing to follow.
205 numPointers := 0
206 // If we followed any compression pointers, we must finally seek to just
207 // past the first pointer.
208 var seekTo int64
209 loop:
210 for {
211 var labelType byte
212 err := binary.Read(r, binary.BigEndian, &labelType)
213 if err != nil {
214 return nil, err
217 switch labelType & 0xc0 {
218 case 0x00:
219 // This is an ordinary label.
220 // https://tools.ietf.org/html/rfc1035#section-3.1
221 length := int(labelType & 0x3f)
222 if length == 0 {
223 break loop
225 label := make([]byte, length)
226 _, err := io.ReadFull(r, label)
227 if err != nil {
228 return nil, err
230 labels = append(labels, label)
231 case 0xc0:
232 // This is a compression pointer.
233 // https://tools.ietf.org/html/rfc1035#section-4.1.4
234 upper := labelType & 0x3f
235 var lower byte
236 err := binary.Read(r, binary.BigEndian, &lower)
237 if err != nil {
238 return nil, err
240 offset := (uint16(upper) << 8) | uint16(lower)
242 if numPointers == 0 {
243 // The first time we encounter a pointer,
244 // remember our position so we can seek back to
245 // it when done.
246 seekTo, err = r.Seek(0, io.SeekCurrent)
247 if err != nil {
248 return nil, err
251 numPointers++
252 if numPointers > compressionPointerLimit {
253 return nil, ErrTooManyPointers
256 // Follow the pointer and continue.
257 _, err = r.Seek(int64(offset), io.SeekStart)
258 if err != nil {
259 return nil, err
261 default:
262 // "The 10 and 01 combinations are reserved for future
263 // use."
264 return nil, ErrReservedLabelType
267 // If we followed any pointers, then seek back to just after the first
268 // one.
269 if numPointers > 0 {
270 _, err := r.Seek(seekTo, io.SeekStart)
271 if err != nil {
272 return nil, err
275 return NewName(labels)
278 // readQuestion parses one entry from the Question section. It leaves r
279 // positioned just after the parsed entry.
281 // https://tools.ietf.org/html/rfc1035#section-4.1.2
282 func readQuestion(r io.ReadSeeker) (Question, error) {
283 var question Question
284 var err error
285 question.Name, err = readName(r)
286 if err != nil {
287 return question, err
289 for _, ptr := range []*uint16{&question.Type, &question.Class} {
290 err := binary.Read(r, binary.BigEndian, ptr)
291 if err != nil {
292 return question, err
296 return question, nil
299 // readRR parses one resource record. It leaves r positioned just after the
300 // parsed resource record.
302 // https://tools.ietf.org/html/rfc1035#section-4.1.3
303 func readRR(r io.ReadSeeker) (RR, error) {
304 var rr RR
305 var err error
306 rr.Name, err = readName(r)
307 if err != nil {
308 return rr, err
310 for _, ptr := range []*uint16{&rr.Type, &rr.Class} {
311 err := binary.Read(r, binary.BigEndian, ptr)
312 if err != nil {
313 return rr, err
316 err = binary.Read(r, binary.BigEndian, &rr.TTL)
317 if err != nil {
318 return rr, err
320 var rdLength uint16
321 err = binary.Read(r, binary.BigEndian, &rdLength)
322 if err != nil {
323 return rr, err
325 rr.Data = make([]byte, rdLength)
326 _, err = io.ReadFull(r, rr.Data)
327 if err != nil {
328 return rr, err
331 return rr, nil
334 // readMessage parses a complete DNS message. It leaves r positioned just after
335 // the parsed message.
336 func readMessage(r io.ReadSeeker) (Message, error) {
337 var message Message
339 // Header section
340 // https://tools.ietf.org/html/rfc1035#section-4.1.1
341 var qdCount, anCount, nsCount, arCount uint16
342 for _, ptr := range []*uint16{
343 &message.ID, &message.Flags,
344 &qdCount, &anCount, &nsCount, &arCount,
346 err := binary.Read(r, binary.BigEndian, ptr)
347 if err != nil {
348 return message, err
352 // Question section
353 // https://tools.ietf.org/html/rfc1035#section-4.1.2
354 for i := 0; i < int(qdCount); i++ {
355 question, err := readQuestion(r)
356 if err != nil {
357 return message, err
359 message.Question = append(message.Question, question)
362 // Answer, Authority, and Additional sections
363 // https://tools.ietf.org/html/rfc1035#section-4.1.3
364 for _, rec := range []struct {
365 ptr *[]RR
366 count uint16
368 {&message.Answer, anCount},
369 {&message.Authority, nsCount},
370 {&message.Additional, arCount},
372 for i := 0; i < int(rec.count); i++ {
373 rr, err := readRR(r)
374 if err != nil {
375 return message, err
377 *rec.ptr = append(*rec.ptr, rr)
381 return message, nil
384 // MessageFromWireFormat parses a message from buf and returns a Message object.
385 // It returns ErrTrailingBytes if there are bytes remaining in buf after parsing
386 // is done.
387 func MessageFromWireFormat(buf []byte) (Message, error) {
388 r := bytes.NewReader(buf)
389 message, err := readMessage(r)
390 if err == io.EOF {
391 err = io.ErrUnexpectedEOF
392 } else if err == nil {
393 // Check for trailing bytes.
394 _, err = r.ReadByte()
395 if err == io.EOF {
396 err = nil
397 } else if err == nil {
398 err = ErrTrailingBytes
401 return message, err
404 // messageBuilder manages the state of serializing a DNS message. Its main
405 // function is to keep track of names already written for the purpose of name
406 // compression.
407 type messageBuilder struct {
408 w bytes.Buffer
409 nameCache map[string]int
412 // newMessageBuilder creates a new messageBuilder with an empty name cache.
413 func newMessageBuilder() *messageBuilder {
414 return &messageBuilder{
415 nameCache: make(map[string]int),
419 // Bytes returns the serialized DNS message as a slice of bytes.
420 func (builder *messageBuilder) Bytes() []byte {
421 return builder.w.Bytes()
424 // WriteName appends name to the in-progress messageBuilder, employing
425 // compression pointers to previously written names if possible.
426 func (builder *messageBuilder) WriteName(name Name) {
427 // https://tools.ietf.org/html/rfc1035#section-3.1
428 for i := range name {
429 // Has this suffix already been encoded in the message?
430 if ptr, ok := builder.nameCache[name[i:].String()]; ok && ptr&0x3fff == ptr {
431 // If so, we can write a compression pointer.
432 binary.Write(&builder.w, binary.BigEndian, uint16(0xc000|ptr))
433 return
435 // Not cached; we must encode this label verbatim. Store a cache
436 // entry pointing to the beginning of it.
437 builder.nameCache[name[i:].String()] = builder.w.Len()
438 length := len(name[i])
439 if length == 0 || length > 63 {
440 panic(length)
442 builder.w.WriteByte(byte(length))
443 builder.w.Write(name[i])
445 builder.w.WriteByte(0)
448 // WriteQuestion appends a Question section entry to the in-progress
449 // messageBuilder.
450 func (builder *messageBuilder) WriteQuestion(question *Question) {
451 // https://tools.ietf.org/html/rfc1035#section-4.1.2
452 builder.WriteName(question.Name)
453 binary.Write(&builder.w, binary.BigEndian, question.Type)
454 binary.Write(&builder.w, binary.BigEndian, question.Class)
457 // WriteRR appends a resource record to the in-progress messageBuilder. It
458 // returns ErrIntegerOverflow if the length of rr.Data does not fit in 16 bits.
459 func (builder *messageBuilder) WriteRR(rr *RR) error {
460 // https://tools.ietf.org/html/rfc1035#section-4.1.3
461 builder.WriteName(rr.Name)
462 binary.Write(&builder.w, binary.BigEndian, rr.Type)
463 binary.Write(&builder.w, binary.BigEndian, rr.Class)
464 binary.Write(&builder.w, binary.BigEndian, rr.TTL)
465 rdLength := uint16(len(rr.Data))
466 if int(rdLength) != len(rr.Data) {
467 return ErrIntegerOverflow
469 binary.Write(&builder.w, binary.BigEndian, rdLength)
470 builder.w.Write(rr.Data)
471 return nil
474 // WriteMessage appends a complete DNS message to the in-progress
475 // messageBuilder. It returns ErrIntegerOverflow if the number of entries in any
476 // section, or the length of the data in any resource record, does not fit in 16
477 // bits.
478 func (builder *messageBuilder) WriteMessage(message *Message) error {
479 // Header section
480 // https://tools.ietf.org/html/rfc1035#section-4.1.1
481 binary.Write(&builder.w, binary.BigEndian, message.ID)
482 binary.Write(&builder.w, binary.BigEndian, message.Flags)
483 for _, count := range []int{
484 len(message.Question),
485 len(message.Answer),
486 len(message.Authority),
487 len(message.Additional),
489 count16 := uint16(count)
490 if int(count16) != count {
491 return ErrIntegerOverflow
493 binary.Write(&builder.w, binary.BigEndian, count16)
496 // Question section
497 // https://tools.ietf.org/html/rfc1035#section-4.1.2
498 for _, question := range message.Question {
499 builder.WriteQuestion(&question)
502 // Answer, Authority, and Additional sections
503 // https://tools.ietf.org/html/rfc1035#section-4.1.3
504 for _, rrs := range [][]RR{message.Answer, message.Authority, message.Additional} {
505 for _, rr := range rrs {
506 err := builder.WriteRR(&rr)
507 if err != nil {
508 return err
513 return nil
516 // WireFormat encodes a Message as a slice of bytes in DNS wire format. It
517 // returns ErrIntegerOverflow if the number of entries in any section, or the
518 // length of the data in any resource record, does not fit in 16 bits.
519 func (message *Message) WireFormat() ([]byte, error) {
520 builder := newMessageBuilder()
521 err := builder.WriteMessage(message)
522 if err != nil {
523 return nil, err
525 return builder.Bytes(), nil
528 // DecodeRDataTXT decodes TXT-DATA (as found in the RDATA for a resource record
529 // with TYPE=TXT) as a raw byte slice, by concatenating all the
530 // <character-string>s it contains.
532 // https://tools.ietf.org/html/rfc1035#section-3.3.14
533 func DecodeRDataTXT(p []byte) ([]byte, error) {
534 var buf bytes.Buffer
535 for {
536 if len(p) == 0 {
537 return nil, io.ErrUnexpectedEOF
539 n := int(p[0])
540 p = p[1:]
541 if len(p) < n {
542 return nil, io.ErrUnexpectedEOF
544 buf.Write(p[:n])
545 p = p[n:]
546 if len(p) == 0 {
547 break
550 return buf.Bytes(), nil
553 // EncodeRDataTXT encodes a slice of bytes as TXT-DATA, as appropriate for the
554 // RDATA of a resource record with TYPE=TXT. No length restriction is enforced
555 // here; that must be checked at a higher level.
557 // https://tools.ietf.org/html/rfc1035#section-3.3.14
558 func EncodeRDataTXT(p []byte) []byte {
559 // https://tools.ietf.org/html/rfc1035#section-3.3
560 // https://tools.ietf.org/html/rfc1035#section-3.3.14
561 // TXT data is a sequence of one or more <character-string>s, where
562 // <character-string> is a length octet followed by that number of
563 // octets.
564 var buf bytes.Buffer
565 for len(p) > 255 {
566 buf.WriteByte(255)
567 buf.Write(p[:255])
568 p = p[255:]
570 // Must write here, even if len(p) == 0, because it's "*one or more*
571 // <character-string>s".
572 buf.WriteByte(byte(len(p)))
573 buf.Write(p)
574 return buf.Bytes()