1
2
3
4
5 package dnsmessage
6
7 import (
8 "bytes"
9 "fmt"
10 "io/ioutil"
11 "path/filepath"
12 "reflect"
13 "strings"
14 "testing"
15 )
16
17 const (
18
19
20 privateUseType Type = 65362
21 )
22
23 func TestPrintPaddedUint8(t *testing.T) {
24 tests := []struct {
25 num uint8
26 want string
27 }{
28 {0, "000"},
29 {1, "001"},
30 {9, "009"},
31 {10, "010"},
32 {99, "099"},
33 {100, "100"},
34 {124, "124"},
35 {104, "104"},
36 {120, "120"},
37 {255, "255"},
38 }
39
40 for _, test := range tests {
41 if got := printPaddedUint8(test.num); got != test.want {
42 t.Errorf("got printPaddedUint8(%d) = %s, want = %s", test.num, got, test.want)
43 }
44 }
45 }
46
47 func TestPrintUint8Bytes(t *testing.T) {
48 tests := []uint8{
49 0,
50 1,
51 9,
52 10,
53 99,
54 100,
55 124,
56 104,
57 120,
58 255,
59 }
60
61 for _, test := range tests {
62 if got, want := string(printUint8Bytes(nil, test)), fmt.Sprint(test); got != want {
63 t.Errorf("got printUint8Bytes(%d) = %s, want = %s", test, got, want)
64 }
65 }
66 }
67
68 func TestPrintUint16(t *testing.T) {
69 tests := []uint16{
70 65535,
71 0,
72 1,
73 10,
74 100,
75 1000,
76 10000,
77 324,
78 304,
79 320,
80 }
81
82 for _, test := range tests {
83 if got, want := printUint16(test), fmt.Sprint(test); got != want {
84 t.Errorf("got printUint16(%d) = %s, want = %s", test, got, want)
85 }
86 }
87 }
88
89 func TestPrintUint32(t *testing.T) {
90 tests := []uint32{
91 4294967295,
92 65535,
93 0,
94 1,
95 10,
96 100,
97 1000,
98 10000,
99 100000,
100 1000000,
101 10000000,
102 100000000,
103 1000000000,
104 324,
105 304,
106 320,
107 }
108
109 for _, test := range tests {
110 if got, want := printUint32(test), fmt.Sprint(test); got != want {
111 t.Errorf("got printUint32(%d) = %s, want = %s", test, got, want)
112 }
113 }
114 }
115
116 func mustEDNS0ResourceHeader(l int, extrc RCode, do bool) ResourceHeader {
117 h := ResourceHeader{Class: ClassINET}
118 if err := h.SetEDNS0(l, extrc, do); err != nil {
119 panic(err)
120 }
121 return h
122 }
123
124 func (m *Message) String() string {
125 s := fmt.Sprintf("Message: %#v\n", &m.Header)
126 if len(m.Questions) > 0 {
127 s += "-- Questions\n"
128 for _, q := range m.Questions {
129 s += fmt.Sprintf("%#v\n", q)
130 }
131 }
132 if len(m.Answers) > 0 {
133 s += "-- Answers\n"
134 for _, a := range m.Answers {
135 s += fmt.Sprintf("%#v\n", a)
136 }
137 }
138 if len(m.Authorities) > 0 {
139 s += "-- Authorities\n"
140 for _, ns := range m.Authorities {
141 s += fmt.Sprintf("%#v\n", ns)
142 }
143 }
144 if len(m.Additionals) > 0 {
145 s += "-- Additionals\n"
146 for _, e := range m.Additionals {
147 s += fmt.Sprintf("%#v\n", e)
148 }
149 }
150 return s
151 }
152
153 func TestNameString(t *testing.T) {
154 want := "foo"
155 name := MustNewName(want)
156 if got := fmt.Sprint(name); got != want {
157 t.Errorf("got fmt.Sprint(%#v) = %s, want = %s", name, got, want)
158 }
159 }
160
161 func TestQuestionPackUnpack(t *testing.T) {
162 want := Question{
163 Name: MustNewName("."),
164 Type: TypeA,
165 Class: ClassINET,
166 }
167 buf, err := want.pack(make([]byte, 1, 50), map[string]uint16{}, 1)
168 if err != nil {
169 t.Fatal("Question.pack() =", err)
170 }
171 var p Parser
172 p.msg = buf
173 p.header.questions = 1
174 p.section = sectionQuestions
175 p.off = 1
176 got, err := p.Question()
177 if err != nil {
178 t.Fatalf("Parser{%q}.Question() = %v", string(buf[1:]), err)
179 }
180 if p.off != len(buf) {
181 t.Errorf("unpacked different amount than packed: got = %d, want = %d", p.off, len(buf))
182 }
183 if !reflect.DeepEqual(got, want) {
184 t.Errorf("got from Parser.Question() = %+v, want = %+v", got, want)
185 }
186 }
187
188 func TestName(t *testing.T) {
189 tests := []string{
190 "",
191 ".",
192 "google..com",
193 "google.com",
194 "google..com.",
195 "google.com.",
196 ".google.com.",
197 "www..google.com.",
198 "www.google.com.",
199 }
200
201 for _, test := range tests {
202 n, err := NewName(test)
203 if err != nil {
204 t.Errorf("NewName(%q) = %v", test, err)
205 continue
206 }
207 if ns := n.String(); ns != test {
208 t.Errorf("got %#v.String() = %q, want = %q", n, ns, test)
209 continue
210 }
211 }
212 }
213
214 func TestNameWithDotsUnpack(t *testing.T) {
215 name := []byte{3, 'w', '.', 'w', 2, 'g', 'o', 3, 'd', 'e', 'v', 0}
216 var n Name
217 _, err := n.unpack(name, 0)
218 if err != errInvalidName {
219 t.Fatalf("expected %v, got %v", errInvalidName, err)
220 }
221 }
222
223 func TestNamePackUnpack(t *testing.T) {
224 const suffix = ".go.dev."
225 var longDNSPrefix = strings.Repeat("verylongdomainlabel.", 20)
226
227 tests := []struct {
228 in string
229 err error
230 }{
231 {"", errNonCanonicalName},
232 {".", nil},
233 {"google..com", errNonCanonicalName},
234 {"google.com", errNonCanonicalName},
235 {"google..com.", errZeroSegLen},
236 {"google.com.", nil},
237 {".google.com.", errZeroSegLen},
238 {"www..google.com.", errZeroSegLen},
239 {"www.google.com.", nil},
240 {in: longDNSPrefix[:254-len(suffix)] + suffix},
241 {in: longDNSPrefix[:255-len(suffix)] + suffix, err: errNameTooLong},
242 }
243
244 for _, test := range tests {
245 in := MustNewName(test.in)
246 buf, err := in.pack(make([]byte, 0, 30), map[string]uint16{}, 0)
247 if err != test.err {
248 t.Errorf("got %q.pack() = %v, want = %v", test.in, err, test.err)
249 continue
250 }
251 if test.err != nil {
252 continue
253 }
254 var got Name
255 n, err := got.unpack(buf, 0)
256 if err != nil {
257 t.Errorf("%q.unpack() = %v", test.in, err)
258 continue
259 }
260 if n != len(buf) {
261 t.Errorf(
262 "unpacked different amount than packed for %q: got = %d, want = %d",
263 test.in,
264 n,
265 len(buf),
266 )
267 }
268 if got != in {
269 t.Errorf("unpacking packing of %q: got = %#v, want = %#v", test.in, got, in)
270 }
271 }
272 }
273
274 func TestNameUnpackTooLongName(t *testing.T) {
275 var suffix = []byte{2, 'g', 'o', 3, 'd', 'e', 'v', 0}
276
277 const label = "longdnslabel"
278 labelBinary := append([]byte{byte(len(label))}, []byte(label)...)
279 var longDNSPrefix = bytes.Repeat(labelBinary, 18)
280 longDNSPrefix = longDNSPrefix[:len(longDNSPrefix):len(longDNSPrefix)]
281
282 prepName := func(length int) []byte {
283 missing := length - (len(longDNSPrefix) + len(suffix) + 1)
284 name := append(longDNSPrefix, byte(missing))
285 name = append(name, bytes.Repeat([]byte{'a'}, missing)...)
286 return append(name, suffix...)
287 }
288
289 tests := []struct {
290 name []byte
291 err error
292 }{
293 {name: prepName(255)},
294 {name: prepName(256), err: errNameTooLong},
295 }
296
297 for i, test := range tests {
298 var got Name
299 _, err := got.unpack(test.name, 0)
300 if err != test.err {
301 t.Errorf("%v: %v: expected error: %v, got %v", i, test.name, test.err, err)
302 }
303 }
304 }
305
306 func checkErrorPrefix(err error, prefix string) bool {
307 e, ok := err.(*nestedError)
308 return ok && e.s == prefix
309 }
310
311 func TestHeaderUnpackError(t *testing.T) {
312 wants := []string{
313 "id",
314 "bits",
315 "questions",
316 "answers",
317 "authorities",
318 "additionals",
319 }
320 var buf []byte
321 var h header
322 for _, want := range wants {
323 n, err := h.unpack(buf, 0)
324 if n != 0 || !checkErrorPrefix(err, want) {
325 t.Errorf("got header.unpack([%d]byte, 0) = %d, %v, want = 0, %s", len(buf), n, err, want)
326 }
327 buf = append(buf, 0, 0)
328 }
329 }
330
331 func TestParserStart(t *testing.T) {
332 const want = "unpacking header"
333 var p Parser
334 for i := 0; i <= 1; i++ {
335 _, err := p.Start([]byte{})
336 if !checkErrorPrefix(err, want) {
337 t.Errorf("got Parser.Start(nil) = _, %v, want = _, %s", err, want)
338 }
339 }
340 }
341
342 func TestResourceNotStarted(t *testing.T) {
343 tests := []struct {
344 name string
345 fn func(*Parser) error
346 }{
347 {"CNAMEResource", func(p *Parser) error { _, err := p.CNAMEResource(); return err }},
348 {"MXResource", func(p *Parser) error { _, err := p.MXResource(); return err }},
349 {"NSResource", func(p *Parser) error { _, err := p.NSResource(); return err }},
350 {"PTRResource", func(p *Parser) error { _, err := p.PTRResource(); return err }},
351 {"SOAResource", func(p *Parser) error { _, err := p.SOAResource(); return err }},
352 {"TXTResource", func(p *Parser) error { _, err := p.TXTResource(); return err }},
353 {"SRVResource", func(p *Parser) error { _, err := p.SRVResource(); return err }},
354 {"AResource", func(p *Parser) error { _, err := p.AResource(); return err }},
355 {"AAAAResource", func(p *Parser) error { _, err := p.AAAAResource(); return err }},
356 {"UnknownResource", func(p *Parser) error { _, err := p.UnknownResource(); return err }},
357 }
358
359 for _, test := range tests {
360 if err := test.fn(&Parser{}); err != ErrNotStarted {
361 t.Errorf("got Parser.%s() = _ , %v, want = _, %v", test.name, err, ErrNotStarted)
362 }
363 }
364 }
365
366 func TestDNSPackUnpack(t *testing.T) {
367 wants := []Message{
368 {
369 Questions: []Question{
370 {
371 Name: MustNewName("."),
372 Type: TypeAAAA,
373 Class: ClassINET,
374 },
375 },
376 Answers: []Resource{},
377 Authorities: []Resource{},
378 Additionals: []Resource{},
379 },
380 largeTestMsg(),
381 }
382 for i, want := range wants {
383 b, err := want.Pack()
384 if err != nil {
385 t.Fatalf("%d: Message.Pack() = %v", i, err)
386 }
387 var got Message
388 err = got.Unpack(b)
389 if err != nil {
390 t.Fatalf("%d: Message.Unapck() = %v", i, err)
391 }
392 if !reflect.DeepEqual(got, want) {
393 t.Errorf("%d: Message.Pack/Unpack() roundtrip: got = %+v, want = %+v", i, &got, &want)
394 }
395 }
396 }
397
398 func TestDNSAppendPackUnpack(t *testing.T) {
399 wants := []Message{
400 {
401 Questions: []Question{
402 {
403 Name: MustNewName("."),
404 Type: TypeAAAA,
405 Class: ClassINET,
406 },
407 },
408 Answers: []Resource{},
409 Authorities: []Resource{},
410 Additionals: []Resource{},
411 },
412 largeTestMsg(),
413 }
414 for i, want := range wants {
415 b := make([]byte, 2, 514)
416 b, err := want.AppendPack(b)
417 if err != nil {
418 t.Fatalf("%d: Message.AppendPack() = %v", i, err)
419 }
420 b = b[2:]
421 var got Message
422 err = got.Unpack(b)
423 if err != nil {
424 t.Fatalf("%d: Message.Unapck() = %v", i, err)
425 }
426 if !reflect.DeepEqual(got, want) {
427 t.Errorf("%d: Message.AppendPack/Unpack() roundtrip: got = %+v, want = %+v", i, &got, &want)
428 }
429 }
430 }
431
432 func TestSkipAll(t *testing.T) {
433 msg := largeTestMsg()
434 buf, err := msg.Pack()
435 if err != nil {
436 t.Fatal("Message.Pack() =", err)
437 }
438 var p Parser
439 if _, err := p.Start(buf); err != nil {
440 t.Fatal("Parser.Start(non-nil) =", err)
441 }
442
443 tests := []struct {
444 name string
445 f func() error
446 }{
447 {"SkipAllQuestions", p.SkipAllQuestions},
448 {"SkipAllAnswers", p.SkipAllAnswers},
449 {"SkipAllAuthorities", p.SkipAllAuthorities},
450 {"SkipAllAdditionals", p.SkipAllAdditionals},
451 }
452 for _, test := range tests {
453 for i := 1; i <= 3; i++ {
454 if err := test.f(); err != nil {
455 t.Errorf("%d: Parser.%s() = %v", i, test.name, err)
456 }
457 }
458 }
459 }
460
461 func TestSkipEach(t *testing.T) {
462 msg := smallTestMsg()
463
464 buf, err := msg.Pack()
465 if err != nil {
466 t.Fatal("Message.Pack() =", err)
467 }
468 var p Parser
469 if _, err := p.Start(buf); err != nil {
470 t.Fatal("Parser.Start(non-nil) =", err)
471 }
472
473 tests := []struct {
474 name string
475 f func() error
476 }{
477 {"SkipQuestion", p.SkipQuestion},
478 {"SkipAnswer", p.SkipAnswer},
479 {"SkipAuthority", p.SkipAuthority},
480 {"SkipAdditional", p.SkipAdditional},
481 }
482 for _, test := range tests {
483 if err := test.f(); err != nil {
484 t.Errorf("first Parser.%s() = %v, want = nil", test.name, err)
485 }
486 if err := test.f(); err != ErrSectionDone {
487 t.Errorf("second Parser.%s() = %v, want = %v", test.name, err, ErrSectionDone)
488 }
489 }
490 }
491
492 func TestSkipAfterRead(t *testing.T) {
493 msg := smallTestMsg()
494
495 buf, err := msg.Pack()
496 if err != nil {
497 t.Fatal("Message.Pack() =", err)
498 }
499 var p Parser
500 if _, err := p.Start(buf); err != nil {
501 t.Fatal("Parser.Srart(non-nil) =", err)
502 }
503
504 tests := []struct {
505 name string
506 skip func() error
507 read func() error
508 }{
509 {"Question", p.SkipQuestion, func() error { _, err := p.Question(); return err }},
510 {"Answer", p.SkipAnswer, func() error { _, err := p.Answer(); return err }},
511 {"Authority", p.SkipAuthority, func() error { _, err := p.Authority(); return err }},
512 {"Additional", p.SkipAdditional, func() error { _, err := p.Additional(); return err }},
513 }
514 for _, test := range tests {
515 if err := test.read(); err != nil {
516 t.Errorf("got Parser.%s() = _, %v, want = _, nil", test.name, err)
517 }
518 if err := test.skip(); err != ErrSectionDone {
519 t.Errorf("got Parser.Skip%s() = %v, want = %v", test.name, err, ErrSectionDone)
520 }
521 }
522 }
523
524 func TestSkipNotStarted(t *testing.T) {
525 var p Parser
526
527 tests := []struct {
528 name string
529 f func() error
530 }{
531 {"SkipAllQuestions", p.SkipAllQuestions},
532 {"SkipAllAnswers", p.SkipAllAnswers},
533 {"SkipAllAuthorities", p.SkipAllAuthorities},
534 {"SkipAllAdditionals", p.SkipAllAdditionals},
535 }
536 for _, test := range tests {
537 if err := test.f(); err != ErrNotStarted {
538 t.Errorf("got Parser.%s() = %v, want = %v", test.name, err, ErrNotStarted)
539 }
540 }
541 }
542
543 func TestTooManyRecords(t *testing.T) {
544 const recs = int(^uint16(0)) + 1
545 tests := []struct {
546 name string
547 msg Message
548 want error
549 }{
550 {
551 "Questions",
552 Message{
553 Questions: make([]Question, recs),
554 },
555 errTooManyQuestions,
556 },
557 {
558 "Answers",
559 Message{
560 Answers: make([]Resource, recs),
561 },
562 errTooManyAnswers,
563 },
564 {
565 "Authorities",
566 Message{
567 Authorities: make([]Resource, recs),
568 },
569 errTooManyAuthorities,
570 },
571 {
572 "Additionals",
573 Message{
574 Additionals: make([]Resource, recs),
575 },
576 errTooManyAdditionals,
577 },
578 }
579
580 for _, test := range tests {
581 if _, got := test.msg.Pack(); got != test.want {
582 t.Errorf("got Message.Pack() for %d %s = %v, want = %v", recs, test.name, got, test.want)
583 }
584 }
585 }
586
587 func TestVeryLongTxt(t *testing.T) {
588 want := Resource{
589 ResourceHeader{
590 Name: MustNewName("foo.bar.example.com."),
591 Type: TypeTXT,
592 Class: ClassINET,
593 },
594 &TXTResource{[]string{
595 "",
596 "",
597 "foo bar",
598 "",
599 "www.example.com",
600 "www.example.com.",
601 strings.Repeat(".", 255),
602 }},
603 }
604 buf, err := want.pack(make([]byte, 0, 8000), map[string]uint16{}, 0)
605 if err != nil {
606 t.Fatal("Resource.pack() =", err)
607 }
608 var got Resource
609 off, err := got.Header.unpack(buf, 0)
610 if err != nil {
611 t.Fatal("ResourceHeader.unpack() =", err)
612 }
613 body, n, err := unpackResourceBody(buf, off, got.Header)
614 if err != nil {
615 t.Fatal("unpackResourceBody() =", err)
616 }
617 got.Body = body
618 if n != len(buf) {
619 t.Errorf("unpacked different amount than packed: got = %d, want = %d", n, len(buf))
620 }
621 if !reflect.DeepEqual(got, want) {
622 t.Errorf("Resource.pack/unpack() roundtrip: got = %#v, want = %#v", got, want)
623 }
624 }
625
626 func TestTooLongTxt(t *testing.T) {
627 rb := TXTResource{[]string{strings.Repeat(".", 256)}}
628 if _, err := rb.pack(make([]byte, 0, 8000), map[string]uint16{}, 0); err != errStringTooLong {
629 t.Errorf("packing TXTResource with 256 character string: got err = %v, want = %v", err, errStringTooLong)
630 }
631 }
632
633 func TestStartAppends(t *testing.T) {
634 buf := make([]byte, 2, 514)
635 wantBuf := []byte{4, 44}
636 copy(buf, wantBuf)
637
638 b := NewBuilder(buf, Header{})
639 b.EnableCompression()
640
641 buf, err := b.Finish()
642 if err != nil {
643 t.Fatal("Builder.Finish() =", err)
644 }
645 if got, want := len(buf), headerLen+2; got != want {
646 t.Errorf("got len(buf) = %d, want = %d", got, want)
647 }
648 if string(buf[:2]) != string(wantBuf) {
649 t.Errorf("original data not preserved, got = %#v, want = %#v", buf[:2], wantBuf)
650 }
651 }
652
653 func TestStartError(t *testing.T) {
654 tests := []struct {
655 name string
656 fn func(*Builder) error
657 }{
658 {"Questions", func(b *Builder) error { return b.StartQuestions() }},
659 {"Answers", func(b *Builder) error { return b.StartAnswers() }},
660 {"Authorities", func(b *Builder) error { return b.StartAuthorities() }},
661 {"Additionals", func(b *Builder) error { return b.StartAdditionals() }},
662 }
663
664 envs := []struct {
665 name string
666 fn func() *Builder
667 want error
668 }{
669 {"sectionNotStarted", func() *Builder { return &Builder{section: sectionNotStarted} }, ErrNotStarted},
670 {"sectionDone", func() *Builder { return &Builder{section: sectionDone} }, ErrSectionDone},
671 }
672
673 for _, env := range envs {
674 for _, test := range tests {
675 if got := test.fn(env.fn()); got != env.want {
676 t.Errorf("got Builder{%s}.Start%s() = %v, want = %v", env.name, test.name, got, env.want)
677 }
678 }
679 }
680 }
681
682 func TestBuilderResourceError(t *testing.T) {
683 tests := []struct {
684 name string
685 fn func(*Builder) error
686 }{
687 {"CNAMEResource", func(b *Builder) error { return b.CNAMEResource(ResourceHeader{}, CNAMEResource{}) }},
688 {"MXResource", func(b *Builder) error { return b.MXResource(ResourceHeader{}, MXResource{}) }},
689 {"NSResource", func(b *Builder) error { return b.NSResource(ResourceHeader{}, NSResource{}) }},
690 {"PTRResource", func(b *Builder) error { return b.PTRResource(ResourceHeader{}, PTRResource{}) }},
691 {"SOAResource", func(b *Builder) error { return b.SOAResource(ResourceHeader{}, SOAResource{}) }},
692 {"TXTResource", func(b *Builder) error { return b.TXTResource(ResourceHeader{}, TXTResource{}) }},
693 {"SRVResource", func(b *Builder) error { return b.SRVResource(ResourceHeader{}, SRVResource{}) }},
694 {"AResource", func(b *Builder) error { return b.AResource(ResourceHeader{}, AResource{}) }},
695 {"AAAAResource", func(b *Builder) error { return b.AAAAResource(ResourceHeader{}, AAAAResource{}) }},
696 {"OPTResource", func(b *Builder) error { return b.OPTResource(ResourceHeader{}, OPTResource{}) }},
697 {"UnknownResource", func(b *Builder) error { return b.UnknownResource(ResourceHeader{}, UnknownResource{}) }},
698 }
699
700 envs := []struct {
701 name string
702 fn func() *Builder
703 want error
704 }{
705 {"sectionNotStarted", func() *Builder { return &Builder{section: sectionNotStarted} }, ErrNotStarted},
706 {"sectionHeader", func() *Builder { return &Builder{section: sectionHeader} }, ErrNotStarted},
707 {"sectionQuestions", func() *Builder { return &Builder{section: sectionQuestions} }, ErrNotStarted},
708 {"sectionDone", func() *Builder { return &Builder{section: sectionDone} }, ErrSectionDone},
709 }
710
711 for _, env := range envs {
712 for _, test := range tests {
713 if got := test.fn(env.fn()); got != env.want {
714 t.Errorf("got Builder{%s}.%s() = %v, want = %v", env.name, test.name, got, env.want)
715 }
716 }
717 }
718 }
719
720 func TestFinishError(t *testing.T) {
721 var b Builder
722 want := ErrNotStarted
723 if _, got := b.Finish(); got != want {
724 t.Errorf("got Builder.Finish() = %v, want = %v", got, want)
725 }
726 }
727
728 func TestBuilder(t *testing.T) {
729 msg := largeTestMsg()
730 want, err := msg.Pack()
731 if err != nil {
732 t.Fatal("Message.Pack() =", err)
733 }
734
735 b := NewBuilder(nil, msg.Header)
736 b.EnableCompression()
737
738 if err := b.StartQuestions(); err != nil {
739 t.Fatal("Builder.StartQuestions() =", err)
740 }
741 for _, q := range msg.Questions {
742 if err := b.Question(q); err != nil {
743 t.Fatalf("Builder.Question(%#v) = %v", q, err)
744 }
745 }
746
747 if err := b.StartAnswers(); err != nil {
748 t.Fatal("Builder.StartAnswers() =", err)
749 }
750 for _, a := range msg.Answers {
751 switch a.Header.Type {
752 case TypeA:
753 if err := b.AResource(a.Header, *a.Body.(*AResource)); err != nil {
754 t.Fatalf("Builder.AResource(%#v) = %v", a, err)
755 }
756 case TypeNS:
757 if err := b.NSResource(a.Header, *a.Body.(*NSResource)); err != nil {
758 t.Fatalf("Builder.NSResource(%#v) = %v", a, err)
759 }
760 case TypeCNAME:
761 if err := b.CNAMEResource(a.Header, *a.Body.(*CNAMEResource)); err != nil {
762 t.Fatalf("Builder.CNAMEResource(%#v) = %v", a, err)
763 }
764 case TypeSOA:
765 if err := b.SOAResource(a.Header, *a.Body.(*SOAResource)); err != nil {
766 t.Fatalf("Builder.SOAResource(%#v) = %v", a, err)
767 }
768 case TypePTR:
769 if err := b.PTRResource(a.Header, *a.Body.(*PTRResource)); err != nil {
770 t.Fatalf("Builder.PTRResource(%#v) = %v", a, err)
771 }
772 case TypeMX:
773 if err := b.MXResource(a.Header, *a.Body.(*MXResource)); err != nil {
774 t.Fatalf("Builder.MXResource(%#v) = %v", a, err)
775 }
776 case TypeTXT:
777 if err := b.TXTResource(a.Header, *a.Body.(*TXTResource)); err != nil {
778 t.Fatalf("Builder.TXTResource(%#v) = %v", a, err)
779 }
780 case TypeAAAA:
781 if err := b.AAAAResource(a.Header, *a.Body.(*AAAAResource)); err != nil {
782 t.Fatalf("Builder.AAAAResource(%#v) = %v", a, err)
783 }
784 case TypeSRV:
785 if err := b.SRVResource(a.Header, *a.Body.(*SRVResource)); err != nil {
786 t.Fatalf("Builder.SRVResource(%#v) = %v", a, err)
787 }
788 case privateUseType:
789 if err := b.UnknownResource(a.Header, *a.Body.(*UnknownResource)); err != nil {
790 t.Fatalf("Builder.UnknownResource(%#v) = %v", a, err)
791 }
792 }
793 }
794
795 if err := b.StartAuthorities(); err != nil {
796 t.Fatal("Builder.StartAuthorities() =", err)
797 }
798 for _, a := range msg.Authorities {
799 if err := b.NSResource(a.Header, *a.Body.(*NSResource)); err != nil {
800 t.Fatalf("Builder.NSResource(%#v) = %v", a, err)
801 }
802 }
803
804 if err := b.StartAdditionals(); err != nil {
805 t.Fatal("Builder.StartAdditionals() =", err)
806 }
807 for _, a := range msg.Additionals {
808 switch a.Body.(type) {
809 case *TXTResource:
810 if err := b.TXTResource(a.Header, *a.Body.(*TXTResource)); err != nil {
811 t.Fatalf("Builder.TXTResource(%#v) = %v", a, err)
812 }
813 case *OPTResource:
814 if err := b.OPTResource(a.Header, *a.Body.(*OPTResource)); err != nil {
815 t.Fatalf("Builder.OPTResource(%#v) = %v", a, err)
816 }
817 }
818 }
819
820 got, err := b.Finish()
821 if err != nil {
822 t.Fatal("Builder.Finish() =", err)
823 }
824 if !bytes.Equal(got, want) {
825 t.Fatalf("got from Builder.Finish() = %#v\nwant = %#v", got, want)
826 }
827 }
828
829 func TestResourcePack(t *testing.T) {
830 for _, tt := range []struct {
831 m Message
832 err error
833 }{
834 {
835 Message{
836 Questions: []Question{
837 {
838 Name: MustNewName("."),
839 Type: TypeAAAA,
840 Class: ClassINET,
841 },
842 },
843 Answers: []Resource{{ResourceHeader{}, nil}},
844 },
845 &nestedError{"packing Answer", errNilResouceBody},
846 },
847 {
848 Message{
849 Questions: []Question{
850 {
851 Name: MustNewName("."),
852 Type: TypeAAAA,
853 Class: ClassINET,
854 },
855 },
856 Authorities: []Resource{{ResourceHeader{}, (*NSResource)(nil)}},
857 },
858 &nestedError{"packing Authority",
859 &nestedError{"ResourceHeader",
860 &nestedError{"Name", errNonCanonicalName},
861 },
862 },
863 },
864 {
865 Message{
866 Questions: []Question{
867 {
868 Name: MustNewName("."),
869 Type: TypeA,
870 Class: ClassINET,
871 },
872 },
873 Additionals: []Resource{{ResourceHeader{}, nil}},
874 },
875 &nestedError{"packing Additional", errNilResouceBody},
876 },
877 } {
878 _, err := tt.m.Pack()
879 if !reflect.DeepEqual(err, tt.err) {
880 t.Errorf("got Message{%v}.Pack() = %v, want %v", tt.m, err, tt.err)
881 }
882 }
883 }
884
885 func TestResourcePackLength(t *testing.T) {
886 r := Resource{
887 ResourceHeader{
888 Name: MustNewName("."),
889 Type: TypeA,
890 Class: ClassINET,
891 },
892 &AResource{[4]byte{127, 0, 0, 2}},
893 }
894
895 hb, _, err := r.Header.pack(nil, nil, 0)
896 if err != nil {
897 t.Fatal("ResourceHeader.pack() =", err)
898 }
899 buf := make([]byte, 0, len(hb))
900 buf, err = r.pack(buf, nil, 0)
901 if err != nil {
902 t.Fatal("Resource.pack() =", err)
903 }
904
905 var hdr ResourceHeader
906 if _, err := hdr.unpack(buf, 0); err != nil {
907 t.Fatal("ResourceHeader.unpack() =", err)
908 }
909
910 if got, want := int(hdr.Length), len(buf)-len(hb); got != want {
911 t.Errorf("got hdr.Length = %d, want = %d", got, want)
912 }
913 }
914
915 func TestOptionPackUnpack(t *testing.T) {
916 for _, tt := range []struct {
917 name string
918 w []byte
919 m Message
920 dnssecOK bool
921 extRCode RCode
922 }{
923 {
924 name: "without EDNS(0) options",
925 w: []byte{
926 0x00, 0x00, 0x29, 0x10, 0x00, 0xfe, 0x00, 0x80,
927 0x00, 0x00, 0x00,
928 },
929 m: Message{
930 Header: Header{RCode: RCodeFormatError},
931 Questions: []Question{
932 {
933 Name: MustNewName("."),
934 Type: TypeA,
935 Class: ClassINET,
936 },
937 },
938 Additionals: []Resource{
939 {
940 mustEDNS0ResourceHeader(4096, 0xfe0|RCodeFormatError, true),
941 &OPTResource{},
942 },
943 },
944 },
945 dnssecOK: true,
946 extRCode: 0xfe0 | RCodeFormatError,
947 },
948 {
949 name: "with EDNS(0) options",
950 w: []byte{
951 0x00, 0x00, 0x29, 0x10, 0x00, 0xff, 0x00, 0x00,
952 0x00, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x02, 0x00,
953 0x00, 0x00, 0x0b, 0x00, 0x02, 0x12, 0x34,
954 },
955 m: Message{
956 Header: Header{RCode: RCodeServerFailure},
957 Questions: []Question{
958 {
959 Name: MustNewName("."),
960 Type: TypeAAAA,
961 Class: ClassINET,
962 },
963 },
964 Additionals: []Resource{
965 {
966 mustEDNS0ResourceHeader(4096, 0xff0|RCodeServerFailure, false),
967 &OPTResource{
968 Options: []Option{
969 {
970 Code: 12,
971 Data: []byte{0x00, 0x00},
972 },
973 {
974 Code: 11,
975 Data: []byte{0x12, 0x34},
976 },
977 },
978 },
979 },
980 },
981 },
982 dnssecOK: false,
983 extRCode: 0xff0 | RCodeServerFailure,
984 },
985 {
986
987
988
989 name: "with multiple OPT resources",
990 w: []byte{
991 0x00, 0x00, 0x29, 0x10, 0x00, 0xff, 0x00, 0x00,
992 0x00, 0x00, 0x06, 0x00, 0x0b, 0x00, 0x02, 0x12,
993 0x34, 0x00, 0x00, 0x29, 0x10, 0x00, 0xff, 0x00,
994 0x00, 0x00, 0x00, 0x06, 0x00, 0x0c, 0x00, 0x02,
995 0x00, 0x00,
996 },
997 m: Message{
998 Header: Header{RCode: RCodeNameError},
999 Questions: []Question{
1000 {
1001 Name: MustNewName("."),
1002 Type: TypeAAAA,
1003 Class: ClassINET,
1004 },
1005 },
1006 Additionals: []Resource{
1007 {
1008 mustEDNS0ResourceHeader(4096, 0xff0|RCodeNameError, false),
1009 &OPTResource{
1010 Options: []Option{
1011 {
1012 Code: 11,
1013 Data: []byte{0x12, 0x34},
1014 },
1015 },
1016 },
1017 },
1018 {
1019 mustEDNS0ResourceHeader(4096, 0xff0|RCodeNameError, false),
1020 &OPTResource{
1021 Options: []Option{
1022 {
1023 Code: 12,
1024 Data: []byte{0x00, 0x00},
1025 },
1026 },
1027 },
1028 },
1029 },
1030 },
1031 },
1032 } {
1033 w, err := tt.m.Pack()
1034 if err != nil {
1035 t.Errorf("Message.Pack() for %s = %v", tt.name, err)
1036 continue
1037 }
1038 if !bytes.Equal(w[len(w)-len(tt.w):], tt.w) {
1039 t.Errorf("got Message.Pack() for %s = %#v, want %#v", tt.name, w[len(w)-len(tt.w):], tt.w)
1040 continue
1041 }
1042 var m Message
1043 if err := m.Unpack(w); err != nil {
1044 t.Errorf("Message.Unpack() for %s = %v", tt.name, err)
1045 continue
1046 }
1047 if !reflect.DeepEqual(m.Additionals, tt.m.Additionals) {
1048 t.Errorf("got Message.Pack/Unpack() roundtrip for %s = %+v, want %+v", tt.name, m, tt.m)
1049 continue
1050 }
1051 }
1052 }
1053
1054 func smallTestMsgWithUnknownResource() Message {
1055 return Message{
1056 Questions: []Question{},
1057 Answers: []Resource{
1058 {
1059 Header: ResourceHeader{
1060 Name: MustNewName("."),
1061 Type: privateUseType,
1062 Class: ClassINET,
1063 TTL: uint32(123),
1064 },
1065 Body: &UnknownResource{
1066
1067
1068
1069 Type: privateUseType,
1070 Data: []byte{42, 42, 42, 42},
1071 },
1072 },
1073 },
1074 }
1075 }
1076
1077 func TestUnknownPackUnpack(t *testing.T) {
1078 msg := smallTestMsgWithUnknownResource()
1079 packed, err := msg.Pack()
1080 if err != nil {
1081 t.Fatalf("Failed to pack UnknownResource: %v", err)
1082 }
1083
1084 var receivedMsg Message
1085 err = receivedMsg.Unpack(packed)
1086 if err != nil {
1087 t.Fatalf("Failed to unpack UnknownResource: %v", err)
1088 }
1089
1090 if len(receivedMsg.Answers) != 1 {
1091 t.Fatalf("Got %d answers, wanted 1", len(receivedMsg.Answers))
1092 }
1093
1094 unknownResource, ok := receivedMsg.Answers[0].Body.(*UnknownResource)
1095 if !ok {
1096 t.Fatalf("Parsed a %T, wanted an UnknownResource", receivedMsg.Answers[0].Body)
1097 }
1098
1099 wantBody := msg.Answers[0].Body
1100 if !reflect.DeepEqual(wantBody, unknownResource) {
1101 t.Fatalf("Unpacked resource does not match: %v vs %v", wantBody, unknownResource)
1102 }
1103 }
1104
1105 func TestParseUnknownResource(t *testing.T) {
1106 msg := smallTestMsgWithUnknownResource()
1107 packed, err := msg.Pack()
1108 if err != nil {
1109 t.Fatalf("Failed to pack UnknownResource: %v", err)
1110 }
1111
1112 var p Parser
1113 if _, err = p.Start(packed); err != nil {
1114 t.Fatalf("Parser failed to start: %s", err)
1115 }
1116 if _, err = p.AllQuestions(); err != nil {
1117 t.Fatalf("Failed to parse questions: %s", err)
1118 }
1119
1120 parsedHeader, err := p.AnswerHeader()
1121 if err != nil {
1122 t.Fatalf("Error reading answer header: %s", err)
1123 }
1124 wantHeader := msg.Answers[0].Header
1125 if !reflect.DeepEqual(wantHeader, parsedHeader) {
1126 t.Fatalf("Parsed header does not match: %v vs %v", wantHeader, wantHeader)
1127 }
1128
1129 parsedUnknownResource, err := p.UnknownResource()
1130 if err != nil {
1131 t.Fatalf("Failed to parse UnknownResource: %s", err)
1132 }
1133 wantBody := msg.Answers[0].Body
1134 if !reflect.DeepEqual(wantBody, &parsedUnknownResource) {
1135 t.Fatalf("Parsed resource does not match: %v vs %v", wantBody, &parsedUnknownResource)
1136 }
1137
1138
1139
1140 if _, err = p.AnswerHeader(); err != ErrSectionDone {
1141 t.Fatalf("Answer section should be fully parsed")
1142 }
1143 if _, err = p.AllAuthorities(); err != nil {
1144 t.Fatalf("Failed to parse authorities: %s", err)
1145 }
1146 if _, err = p.AllAdditionals(); err != nil {
1147 t.Fatalf("Failed to parse additionals: %s", err)
1148 }
1149 }
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159 func TestGoString(t *testing.T) {
1160 msg := Message{Header: Header{ID: 0, Response: true, OpCode: 0, Authoritative: true, Truncated: false, RecursionDesired: false, RecursionAvailable: false, RCode: RCodeSuccess}, Questions: []Question{Question{Name: MustNewName("foo.bar.example.com."), Type: TypeA, Class: ClassINET}}, Answers: []Resource{Resource{Header: ResourceHeader{Name: MustNewName("foo.bar.example.com."), Type: TypeA, Class: ClassINET, TTL: 0, Length: 0}, Body: &AResource{A: [4]byte{127, 0, 0, 1}}}, Resource{Header: ResourceHeader{Name: MustNewName("foo.bar.example.com."), Type: TypeA, Class: ClassINET, TTL: 0, Length: 0}, Body: &AResource{A: [4]byte{127, 0, 0, 2}}}, Resource{Header: ResourceHeader{Name: MustNewName("foo.bar.example.com."), Type: TypeAAAA, Class: ClassINET, TTL: 0, Length: 0}, Body: &AAAAResource{AAAA: [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}}}, Resource{Header: ResourceHeader{Name: MustNewName("foo.bar.example.com."), Type: TypeCNAME, Class: ClassINET, TTL: 0, Length: 0}, Body: &CNAMEResource{CNAME: MustNewName("alias.example.com.")}}, Resource{Header: ResourceHeader{Name: MustNewName("foo.bar.example.com."), Type: TypeSOA, Class: ClassINET, TTL: 0, Length: 0}, Body: &SOAResource{NS: MustNewName("ns1.example.com."), MBox: MustNewName("mb.example.com."), Serial: 1, Refresh: 2, Retry: 3, Expire: 4, MinTTL: 5}}, Resource{Header: ResourceHeader{Name: MustNewName("foo.bar.example.com."), Type: TypePTR, Class: ClassINET, TTL: 0, Length: 0}, Body: &PTRResource{PTR: MustNewName("ptr.example.com.")}}, Resource{Header: ResourceHeader{Name: MustNewName("foo.bar.example.com."), Type: TypeMX, Class: ClassINET, TTL: 0, Length: 0}, Body: &MXResource{Pref: 7, MX: MustNewName("mx.example.com.")}}, Resource{Header: ResourceHeader{Name: MustNewName("foo.bar.example.com."), Type: TypeSRV, Class: ClassINET, TTL: 0, Length: 0}, Body: &SRVResource{Priority: 8, Weight: 9, Port: 11, Target: MustNewName("srv.example.com.")}}, Resource{Header: ResourceHeader{Name: MustNewName("foo.bar.example.com."), Type: 65362, Class: ClassINET, TTL: 0, Length: 0}, Body: &UnknownResource{Type: 65362, Data: []byte{42, 0, 43, 44}}}}, Authorities: []Resource{Resource{Header: ResourceHeader{Name: MustNewName("foo.bar.example.com."), Type: TypeNS, Class: ClassINET, TTL: 0, Length: 0}, Body: &NSResource{NS: MustNewName("ns1.example.com.")}}, Resource{Header: ResourceHeader{Name: MustNewName("foo.bar.example.com."), Type: TypeNS, Class: ClassINET, TTL: 0, Length: 0}, Body: &NSResource{NS: MustNewName("ns2.example.com.")}}}, Additionals: []Resource{Resource{Header: ResourceHeader{Name: MustNewName("foo.bar.example.com."), Type: TypeTXT, Class: ClassINET, TTL: 0, Length: 0}, Body: &TXTResource{TXT: []string{"So Long\x2c and Thanks for All the Fish"}}}, Resource{Header: ResourceHeader{Name: MustNewName("foo.bar.example.com."), Type: TypeTXT, Class: ClassINET, TTL: 0, Length: 0}, Body: &TXTResource{TXT: []string{"Hamster Huey and the Gooey Kablooie"}}}, Resource{Header: ResourceHeader{Name: MustNewName("."), Type: TypeOPT, Class: 4096, TTL: 4261412864, Length: 0}, Body: &OPTResource{Options: []Option{Option{Code: 10, Data: []byte{1, 35, 69, 103, 137, 171, 205, 239}}}}}}}
1161
1162 if !reflect.DeepEqual(msg, largeTestMsg()) {
1163 t.Error("Message.GoString lost information or largeTestMsg changed: msg != largeTestMsg()")
1164 }
1165 got := msg.GoString()
1166 want := `dnsmessage.Message{Header: dnsmessage.Header{ID: 0, Response: true, OpCode: 0, Authoritative: true, Truncated: false, RecursionDesired: false, RecursionAvailable: false, AuthenticData: false, CheckingDisabled: false, RCode: dnsmessage.RCodeSuccess}, Questions: []dnsmessage.Question{dnsmessage.Question{Name: dnsmessage.MustNewName("foo.bar.example.com."), Type: dnsmessage.TypeA, Class: dnsmessage.ClassINET}}, Answers: []dnsmessage.Resource{dnsmessage.Resource{Header: dnsmessage.ResourceHeader{Name: dnsmessage.MustNewName("foo.bar.example.com."), Type: dnsmessage.TypeA, Class: dnsmessage.ClassINET, TTL: 0, Length: 0}, Body: &dnsmessage.AResource{A: [4]byte{127, 0, 0, 1}}}, dnsmessage.Resource{Header: dnsmessage.ResourceHeader{Name: dnsmessage.MustNewName("foo.bar.example.com."), Type: dnsmessage.TypeA, Class: dnsmessage.ClassINET, TTL: 0, Length: 0}, Body: &dnsmessage.AResource{A: [4]byte{127, 0, 0, 2}}}, dnsmessage.Resource{Header: dnsmessage.ResourceHeader{Name: dnsmessage.MustNewName("foo.bar.example.com."), Type: dnsmessage.TypeAAAA, Class: dnsmessage.ClassINET, TTL: 0, Length: 0}, Body: &dnsmessage.AAAAResource{AAAA: [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}}}, dnsmessage.Resource{Header: dnsmessage.ResourceHeader{Name: dnsmessage.MustNewName("foo.bar.example.com."), Type: dnsmessage.TypeCNAME, Class: dnsmessage.ClassINET, TTL: 0, Length: 0}, Body: &dnsmessage.CNAMEResource{CNAME: dnsmessage.MustNewName("alias.example.com.")}}, dnsmessage.Resource{Header: dnsmessage.ResourceHeader{Name: dnsmessage.MustNewName("foo.bar.example.com."), Type: dnsmessage.TypeSOA, Class: dnsmessage.ClassINET, TTL: 0, Length: 0}, Body: &dnsmessage.SOAResource{NS: dnsmessage.MustNewName("ns1.example.com."), MBox: dnsmessage.MustNewName("mb.example.com."), Serial: 1, Refresh: 2, Retry: 3, Expire: 4, MinTTL: 5}}, dnsmessage.Resource{Header: dnsmessage.ResourceHeader{Name: dnsmessage.MustNewName("foo.bar.example.com."), Type: dnsmessage.TypePTR, Class: dnsmessage.ClassINET, TTL: 0, Length: 0}, Body: &dnsmessage.PTRResource{PTR: dnsmessage.MustNewName("ptr.example.com.")}}, dnsmessage.Resource{Header: dnsmessage.ResourceHeader{Name: dnsmessage.MustNewName("foo.bar.example.com."), Type: dnsmessage.TypeMX, Class: dnsmessage.ClassINET, TTL: 0, Length: 0}, Body: &dnsmessage.MXResource{Pref: 7, MX: dnsmessage.MustNewName("mx.example.com.")}}, dnsmessage.Resource{Header: dnsmessage.ResourceHeader{Name: dnsmessage.MustNewName("foo.bar.example.com."), Type: dnsmessage.TypeSRV, Class: dnsmessage.ClassINET, TTL: 0, Length: 0}, Body: &dnsmessage.SRVResource{Priority: 8, Weight: 9, Port: 11, Target: dnsmessage.MustNewName("srv.example.com.")}}, dnsmessage.Resource{Header: dnsmessage.ResourceHeader{Name: dnsmessage.MustNewName("foo.bar.example.com."), Type: 65362, Class: dnsmessage.ClassINET, TTL: 0, Length: 0}, Body: &dnsmessage.UnknownResource{Type: 65362, Data: []byte{42, 0, 43, 44}}}}, Authorities: []dnsmessage.Resource{dnsmessage.Resource{Header: dnsmessage.ResourceHeader{Name: dnsmessage.MustNewName("foo.bar.example.com."), Type: dnsmessage.TypeNS, Class: dnsmessage.ClassINET, TTL: 0, Length: 0}, Body: &dnsmessage.NSResource{NS: dnsmessage.MustNewName("ns1.example.com.")}}, dnsmessage.Resource{Header: dnsmessage.ResourceHeader{Name: dnsmessage.MustNewName("foo.bar.example.com."), Type: dnsmessage.TypeNS, Class: dnsmessage.ClassINET, TTL: 0, Length: 0}, Body: &dnsmessage.NSResource{NS: dnsmessage.MustNewName("ns2.example.com.")}}}, Additionals: []dnsmessage.Resource{dnsmessage.Resource{Header: dnsmessage.ResourceHeader{Name: dnsmessage.MustNewName("foo.bar.example.com."), Type: dnsmessage.TypeTXT, Class: dnsmessage.ClassINET, TTL: 0, Length: 0}, Body: &dnsmessage.TXTResource{TXT: []string{"So Long\x2c and Thanks for All the Fish"}}}, dnsmessage.Resource{Header: dnsmessage.ResourceHeader{Name: dnsmessage.MustNewName("foo.bar.example.com."), Type: dnsmessage.TypeTXT, Class: dnsmessage.ClassINET, TTL: 0, Length: 0}, Body: &dnsmessage.TXTResource{TXT: []string{"Hamster Huey and the Gooey Kablooie"}}}, dnsmessage.Resource{Header: dnsmessage.ResourceHeader{Name: dnsmessage.MustNewName("."), Type: dnsmessage.TypeOPT, Class: 4096, TTL: 4261412864, Length: 0}, Body: &dnsmessage.OPTResource{Options: []dnsmessage.Option{dnsmessage.Option{Code: 10, Data: []byte{1, 35, 69, 103, 137, 171, 205, 239}}}}}}}`
1167
1168 if got != want {
1169 t.Errorf("got msg1.GoString() = %s\nwant = %s", got, want)
1170 }
1171 }
1172
1173 func benchmarkParsingSetup() ([]byte, error) {
1174 name := MustNewName("foo.bar.example.com.")
1175 msg := Message{
1176 Header: Header{Response: true, Authoritative: true},
1177 Questions: []Question{
1178 {
1179 Name: name,
1180 Type: TypeA,
1181 Class: ClassINET,
1182 },
1183 },
1184 Answers: []Resource{
1185 {
1186 ResourceHeader{
1187 Name: name,
1188 Class: ClassINET,
1189 },
1190 &AResource{[4]byte{}},
1191 },
1192 {
1193 ResourceHeader{
1194 Name: name,
1195 Class: ClassINET,
1196 },
1197 &AAAAResource{[16]byte{}},
1198 },
1199 {
1200 ResourceHeader{
1201 Name: name,
1202 Class: ClassINET,
1203 },
1204 &CNAMEResource{name},
1205 },
1206 {
1207 ResourceHeader{
1208 Name: name,
1209 Class: ClassINET,
1210 },
1211 &NSResource{name},
1212 },
1213 },
1214 }
1215
1216 buf, err := msg.Pack()
1217 if err != nil {
1218 return nil, fmt.Errorf("Message.Pack() = %v", err)
1219 }
1220 return buf, nil
1221 }
1222
1223 func benchmarkParsing(tb testing.TB, buf []byte) {
1224 var p Parser
1225 if _, err := p.Start(buf); err != nil {
1226 tb.Fatal("Parser.Start(non-nil) =", err)
1227 }
1228
1229 for {
1230 _, err := p.Question()
1231 if err == ErrSectionDone {
1232 break
1233 }
1234 if err != nil {
1235 tb.Fatal("Parser.Question() =", err)
1236 }
1237 }
1238
1239 for {
1240 h, err := p.AnswerHeader()
1241 if err == ErrSectionDone {
1242 break
1243 }
1244 if err != nil {
1245 tb.Fatal("Parser.AnswerHeader() =", err)
1246 }
1247
1248 switch h.Type {
1249 case TypeA:
1250 if _, err := p.AResource(); err != nil {
1251 tb.Fatal("Parser.AResource() =", err)
1252 }
1253 case TypeAAAA:
1254 if _, err := p.AAAAResource(); err != nil {
1255 tb.Fatal("Parser.AAAAResource() =", err)
1256 }
1257 case TypeCNAME:
1258 if _, err := p.CNAMEResource(); err != nil {
1259 tb.Fatal("Parser.CNAMEResource() =", err)
1260 }
1261 case TypeNS:
1262 if _, err := p.NSResource(); err != nil {
1263 tb.Fatal("Parser.NSResource() =", err)
1264 }
1265 case TypeOPT:
1266 if _, err := p.OPTResource(); err != nil {
1267 tb.Fatal("Parser.OPTResource() =", err)
1268 }
1269 default:
1270 tb.Fatalf("got unknown type: %T", h)
1271 }
1272 }
1273 }
1274
1275 func BenchmarkParsing(b *testing.B) {
1276 buf, err := benchmarkParsingSetup()
1277 if err != nil {
1278 b.Fatal(err)
1279 }
1280
1281 b.ReportAllocs()
1282 for i := 0; i < b.N; i++ {
1283 benchmarkParsing(b, buf)
1284 }
1285 }
1286
1287 func TestParsingAllocs(t *testing.T) {
1288 buf, err := benchmarkParsingSetup()
1289 if err != nil {
1290 t.Fatal(err)
1291 }
1292
1293 if allocs := testing.AllocsPerRun(100, func() { benchmarkParsing(t, buf) }); allocs > 0.5 {
1294 t.Errorf("allocations during parsing: got = %f, want ~0", allocs)
1295 }
1296 }
1297
1298 func benchmarkBuildingSetup() (Name, []byte) {
1299 name := MustNewName("foo.bar.example.com.")
1300 buf := make([]byte, 0, packStartingCap)
1301 return name, buf
1302 }
1303
1304 func benchmarkBuilding(tb testing.TB, name Name, buf []byte) {
1305 bld := NewBuilder(buf, Header{Response: true, Authoritative: true})
1306
1307 if err := bld.StartQuestions(); err != nil {
1308 tb.Fatal("Builder.StartQuestions() =", err)
1309 }
1310 q := Question{
1311 Name: name,
1312 Type: TypeA,
1313 Class: ClassINET,
1314 }
1315 if err := bld.Question(q); err != nil {
1316 tb.Fatalf("Builder.Question(%+v) = %v", q, err)
1317 }
1318
1319 hdr := ResourceHeader{
1320 Name: name,
1321 Class: ClassINET,
1322 }
1323 if err := bld.StartAnswers(); err != nil {
1324 tb.Fatal("Builder.StartQuestions() =", err)
1325 }
1326
1327 ar := AResource{[4]byte{}}
1328 if err := bld.AResource(hdr, ar); err != nil {
1329 tb.Fatalf("Builder.AResource(%+v, %+v) = %v", hdr, ar, err)
1330 }
1331
1332 aaar := AAAAResource{[16]byte{}}
1333 if err := bld.AAAAResource(hdr, aaar); err != nil {
1334 tb.Fatalf("Builder.AAAAResource(%+v, %+v) = %v", hdr, aaar, err)
1335 }
1336
1337 cnr := CNAMEResource{name}
1338 if err := bld.CNAMEResource(hdr, cnr); err != nil {
1339 tb.Fatalf("Builder.CNAMEResource(%+v, %+v) = %v", hdr, cnr, err)
1340 }
1341
1342 nsr := NSResource{name}
1343 if err := bld.NSResource(hdr, nsr); err != nil {
1344 tb.Fatalf("Builder.NSResource(%+v, %+v) = %v", hdr, nsr, err)
1345 }
1346
1347 extrc := 0xfe0 | RCodeNotImplemented
1348 if err := (&hdr).SetEDNS0(4096, extrc, true); err != nil {
1349 tb.Fatalf("ResourceHeader.SetEDNS0(4096, %#x, true) = %v", extrc, err)
1350 }
1351 optr := OPTResource{}
1352 if err := bld.OPTResource(hdr, optr); err != nil {
1353 tb.Fatalf("Builder.OPTResource(%+v, %+v) = %v", hdr, optr, err)
1354 }
1355
1356 if _, err := bld.Finish(); err != nil {
1357 tb.Fatal("Builder.Finish() =", err)
1358 }
1359 }
1360
1361 func BenchmarkBuilding(b *testing.B) {
1362 name, buf := benchmarkBuildingSetup()
1363 b.ReportAllocs()
1364 for i := 0; i < b.N; i++ {
1365 benchmarkBuilding(b, name, buf)
1366 }
1367 }
1368
1369 func TestBuildingAllocs(t *testing.T) {
1370 name, buf := benchmarkBuildingSetup()
1371 if allocs := testing.AllocsPerRun(100, func() { benchmarkBuilding(t, name, buf) }); allocs > 0.5 {
1372 t.Errorf("allocations during building: got = %f, want ~0", allocs)
1373 }
1374 }
1375
1376 func smallTestMsg() Message {
1377 name := MustNewName("example.com.")
1378 return Message{
1379 Header: Header{Response: true, Authoritative: true},
1380 Questions: []Question{
1381 {
1382 Name: name,
1383 Type: TypeA,
1384 Class: ClassINET,
1385 },
1386 },
1387 Answers: []Resource{
1388 {
1389 ResourceHeader{
1390 Name: name,
1391 Type: TypeA,
1392 Class: ClassINET,
1393 },
1394 &AResource{[4]byte{127, 0, 0, 1}},
1395 },
1396 },
1397 Authorities: []Resource{
1398 {
1399 ResourceHeader{
1400 Name: name,
1401 Type: TypeA,
1402 Class: ClassINET,
1403 },
1404 &AResource{[4]byte{127, 0, 0, 1}},
1405 },
1406 },
1407 Additionals: []Resource{
1408 {
1409 ResourceHeader{
1410 Name: name,
1411 Type: TypeA,
1412 Class: ClassINET,
1413 },
1414 &AResource{[4]byte{127, 0, 0, 1}},
1415 },
1416 },
1417 }
1418 }
1419
1420 func BenchmarkPack(b *testing.B) {
1421 msg := largeTestMsg()
1422
1423 b.ReportAllocs()
1424
1425 for i := 0; i < b.N; i++ {
1426 if _, err := msg.Pack(); err != nil {
1427 b.Fatal("Message.Pack() =", err)
1428 }
1429 }
1430 }
1431
1432 func BenchmarkAppendPack(b *testing.B) {
1433 msg := largeTestMsg()
1434 buf := make([]byte, 0, packStartingCap)
1435
1436 b.ReportAllocs()
1437
1438 for i := 0; i < b.N; i++ {
1439 if _, err := msg.AppendPack(buf[:0]); err != nil {
1440 b.Fatal("Message.AppendPack() = ", err)
1441 }
1442 }
1443 }
1444
1445 func largeTestMsg() Message {
1446 name := MustNewName("foo.bar.example.com.")
1447 return Message{
1448 Header: Header{Response: true, Authoritative: true},
1449 Questions: []Question{
1450 {
1451 Name: name,
1452 Type: TypeA,
1453 Class: ClassINET,
1454 },
1455 },
1456 Answers: []Resource{
1457 {
1458 ResourceHeader{
1459 Name: name,
1460 Type: TypeA,
1461 Class: ClassINET,
1462 },
1463 &AResource{[4]byte{127, 0, 0, 1}},
1464 },
1465 {
1466 ResourceHeader{
1467 Name: name,
1468 Type: TypeA,
1469 Class: ClassINET,
1470 },
1471 &AResource{[4]byte{127, 0, 0, 2}},
1472 },
1473 {
1474 ResourceHeader{
1475 Name: name,
1476 Type: TypeAAAA,
1477 Class: ClassINET,
1478 },
1479 &AAAAResource{[16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}},
1480 },
1481 {
1482 ResourceHeader{
1483 Name: name,
1484 Type: TypeCNAME,
1485 Class: ClassINET,
1486 },
1487 &CNAMEResource{MustNewName("alias.example.com.")},
1488 },
1489 {
1490 ResourceHeader{
1491 Name: name,
1492 Type: TypeSOA,
1493 Class: ClassINET,
1494 },
1495 &SOAResource{
1496 NS: MustNewName("ns1.example.com."),
1497 MBox: MustNewName("mb.example.com."),
1498 Serial: 1,
1499 Refresh: 2,
1500 Retry: 3,
1501 Expire: 4,
1502 MinTTL: 5,
1503 },
1504 },
1505 {
1506 ResourceHeader{
1507 Name: name,
1508 Type: TypePTR,
1509 Class: ClassINET,
1510 },
1511 &PTRResource{MustNewName("ptr.example.com.")},
1512 },
1513 {
1514 ResourceHeader{
1515 Name: name,
1516 Type: TypeMX,
1517 Class: ClassINET,
1518 },
1519 &MXResource{
1520 7,
1521 MustNewName("mx.example.com."),
1522 },
1523 },
1524 {
1525 ResourceHeader{
1526 Name: name,
1527 Type: TypeSRV,
1528 Class: ClassINET,
1529 },
1530 &SRVResource{
1531 8,
1532 9,
1533 11,
1534 MustNewName("srv.example.com."),
1535 },
1536 },
1537 {
1538 ResourceHeader{
1539 Name: name,
1540 Type: privateUseType,
1541 Class: ClassINET,
1542 },
1543 &UnknownResource{
1544 Type: privateUseType,
1545 Data: []byte{42, 0, 43, 44},
1546 },
1547 },
1548 },
1549 Authorities: []Resource{
1550 {
1551 ResourceHeader{
1552 Name: name,
1553 Type: TypeNS,
1554 Class: ClassINET,
1555 },
1556 &NSResource{MustNewName("ns1.example.com.")},
1557 },
1558 {
1559 ResourceHeader{
1560 Name: name,
1561 Type: TypeNS,
1562 Class: ClassINET,
1563 },
1564 &NSResource{MustNewName("ns2.example.com.")},
1565 },
1566 },
1567 Additionals: []Resource{
1568 {
1569 ResourceHeader{
1570 Name: name,
1571 Type: TypeTXT,
1572 Class: ClassINET,
1573 },
1574 &TXTResource{[]string{"So Long, and Thanks for All the Fish"}},
1575 },
1576 {
1577 ResourceHeader{
1578 Name: name,
1579 Type: TypeTXT,
1580 Class: ClassINET,
1581 },
1582 &TXTResource{[]string{"Hamster Huey and the Gooey Kablooie"}},
1583 },
1584 {
1585 mustEDNS0ResourceHeader(4096, 0xfe0|RCodeSuccess, false),
1586 &OPTResource{
1587 Options: []Option{
1588 {
1589 Code: 10,
1590 Data: []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef},
1591 },
1592 },
1593 },
1594 },
1595 },
1596 }
1597 }
1598
1599
1600
1601
1602 func TestNoFmt(t *testing.T) {
1603 files, err := filepath.Glob("*.go")
1604 if err != nil {
1605 t.Fatal(err)
1606 }
1607 for _, file := range files {
1608 if strings.HasSuffix(file, "_test.go") {
1609 continue
1610 }
1611
1612
1613
1614 data, err := ioutil.ReadFile(file)
1615 if err != nil {
1616 t.Fatal(err)
1617 }
1618 if bytes.Contains(data, []byte(`"fmt"`)) {
1619 t.Errorf(`%s: cannot import "fmt"`, file)
1620 }
1621 }
1622 }
1623
1624 func FuzzUnpackPack(f *testing.F) {
1625 for _, msg := range []Message{smallTestMsg(), largeTestMsg()} {
1626 bytes, _ := msg.Pack()
1627 f.Add(bytes)
1628 }
1629
1630 f.Fuzz(func(t *testing.T, msg []byte) {
1631 var m Message
1632 if err := m.Unpack(msg); err != nil {
1633 return
1634 }
1635
1636 msgPacked, err := m.Pack()
1637 if err != nil {
1638 t.Fatalf("failed to pack message that was succesfully unpacked: %v", err)
1639 }
1640
1641 var m2 Message
1642 if err := m2.Unpack(msgPacked); err != nil {
1643 t.Fatalf("failed to unpack message that was succesfully packed: %v", err)
1644 }
1645
1646 if !reflect.DeepEqual(m, m2) {
1647 t.Fatal("unpack(msg) is not deep equal to unpack(pack(unpack(msg)))")
1648 }
1649 })
1650 }
1651
1652 func TestParseResourceHeaderMultipleTimes(t *testing.T) {
1653 msg := Message{
1654 Header: Header{Response: true, Authoritative: true},
1655 Answers: []Resource{
1656 {
1657 ResourceHeader{
1658 Name: MustNewName("go.dev."),
1659 Type: TypeA,
1660 Class: ClassINET,
1661 },
1662 &AResource{[4]byte{127, 0, 0, 1}},
1663 },
1664 },
1665 Authorities: []Resource{
1666 {
1667 ResourceHeader{
1668 Name: MustNewName("go.dev."),
1669 Type: TypeA,
1670 Class: ClassINET,
1671 },
1672 &AResource{[4]byte{127, 0, 0, 1}},
1673 },
1674 },
1675 }
1676
1677 raw, err := msg.Pack()
1678 if err != nil {
1679 t.Fatal(err)
1680 }
1681
1682 var p Parser
1683
1684 if _, err := p.Start(raw); err != nil {
1685 t.Fatal(err)
1686 }
1687
1688 if err := p.SkipAllQuestions(); err != nil {
1689 t.Fatal(err)
1690 }
1691
1692 hdr1, err := p.AnswerHeader()
1693 if err != nil {
1694 t.Fatal(err)
1695 }
1696
1697 hdr2, err := p.AnswerHeader()
1698 if err != nil {
1699 t.Fatal(err)
1700 }
1701
1702 if hdr1 != hdr2 {
1703 t.Fatal("AnswerHeader called multiple times without parsing the RData returned different headers")
1704 }
1705
1706 if _, err := p.AResource(); err != nil {
1707 t.Fatal(err)
1708 }
1709
1710 if _, err := p.AnswerHeader(); err != ErrSectionDone {
1711 t.Fatalf("unexpected error: %v, want: %v", err, ErrSectionDone)
1712 }
1713
1714 hdr3, err := p.AuthorityHeader()
1715 if err != nil {
1716 t.Fatal(err)
1717 }
1718
1719 hdr4, err := p.AuthorityHeader()
1720 if err != nil {
1721 t.Fatal(err)
1722 }
1723
1724 if hdr3 != hdr4 {
1725 t.Fatal("AuthorityHeader called multiple times without parsing the RData returned different headers")
1726 }
1727
1728 if _, err := p.AResource(); err != nil {
1729 t.Fatal(err)
1730 }
1731
1732 if _, err := p.AuthorityHeader(); err != ErrSectionDone {
1733 t.Fatalf("unexpected error: %v, want: %v", err, ErrSectionDone)
1734 }
1735 }
1736
1737 func TestParseDifferentResourceHeadersWithoutParsingRData(t *testing.T) {
1738 msg := smallTestMsg()
1739 raw, err := msg.Pack()
1740 if err != nil {
1741 t.Fatal(err)
1742 }
1743
1744 var p Parser
1745 if _, err := p.Start(raw); err != nil {
1746 t.Fatal(err)
1747 }
1748
1749 if err := p.SkipAllQuestions(); err != nil {
1750 t.Fatal(err)
1751 }
1752
1753 if _, err := p.AnswerHeader(); err != nil {
1754 t.Fatal(err)
1755 }
1756
1757 if _, err := p.AdditionalHeader(); err == nil {
1758 t.Errorf("p.AdditionalHeader() unexpected success")
1759 }
1760
1761 if _, err := p.AuthorityHeader(); err == nil {
1762 t.Errorf("p.AuthorityHeader() unexpected success")
1763 }
1764 }
1765
1766 func TestParseWrongSection(t *testing.T) {
1767 msg := smallTestMsg()
1768 raw, err := msg.Pack()
1769 if err != nil {
1770 t.Fatal(err)
1771 }
1772
1773 var p Parser
1774 if _, err := p.Start(raw); err != nil {
1775 t.Fatal(err)
1776 }
1777
1778 if err := p.SkipAllQuestions(); err != nil {
1779 t.Fatalf("p.SkipAllQuestions() = %v", err)
1780 }
1781 if _, err := p.AnswerHeader(); err != nil {
1782 t.Fatalf("p.AnswerHeader() = %v", err)
1783 }
1784 if _, err := p.AuthorityHeader(); err == nil {
1785 t.Fatalf("p.AuthorityHeader(): unexpected success in Answer section")
1786 }
1787 if err := p.SkipAuthority(); err == nil {
1788 t.Fatalf("p.SkipAuthority(): unexpected success in Answer section")
1789 }
1790 if err := p.SkipAllAuthorities(); err == nil {
1791 t.Fatalf("p.SkipAllAuthorities(): unexpected success in Answer section")
1792 }
1793 }
1794
1795 func TestBuilderNameCompressionWithNonZeroedName(t *testing.T) {
1796 b := NewBuilder(nil, Header{})
1797 b.EnableCompression()
1798 if err := b.StartQuestions(); err != nil {
1799 t.Fatalf("b.StartQuestions() unexpected error: %v", err)
1800 }
1801
1802 name := MustNewName("go.dev.")
1803 if err := b.Question(Question{Name: name}); err != nil {
1804 t.Fatalf("b.Question() unexpected error: %v", err)
1805 }
1806
1807
1808
1809 name.Data[name.Length] = '1'
1810 if err := b.Question(Question{Name: name}); err != nil {
1811 t.Fatalf("b.Question() unexpected error: %v", err)
1812 }
1813
1814 msg, err := b.Finish()
1815 if err != nil {
1816 t.Fatalf("b.Finish() unexpected error: %v", err)
1817 }
1818
1819 expect := []byte{
1820 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0,
1821 2, 'g', 'o', 3, 'd', 'e', 'v', 0, 0, 0, 0, 0,
1822 0xC0, 12, 0, 0, 0, 0,
1823 }
1824 if !bytes.Equal(msg, expect) {
1825 t.Fatalf("b.Finish() = %v, want: %v", msg, expect)
1826 }
1827 }
1828
1829 func TestBuilderCompressionInAppendMode(t *testing.T) {
1830 maxPtr := int(^uint16(0) >> 2)
1831 b := NewBuilder(make([]byte, maxPtr, maxPtr+512), Header{})
1832 b.EnableCompression()
1833 if err := b.StartQuestions(); err != nil {
1834 t.Fatalf("b.StartQuestions() unexpected error: %v", err)
1835 }
1836 if err := b.Question(Question{Name: MustNewName("go.dev.")}); err != nil {
1837 t.Fatalf("b.Question() unexpected error: %v", err)
1838 }
1839 if err := b.Question(Question{Name: MustNewName("go.dev.")}); err != nil {
1840 t.Fatalf("b.Question() unexpected error: %v", err)
1841 }
1842 msg, err := b.Finish()
1843 if err != nil {
1844 t.Fatalf("b.Finish() unexpected error: %v", err)
1845 }
1846 expect := []byte{
1847 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0,
1848 2, 'g', 'o', 3, 'd', 'e', 'v', 0, 0, 0, 0, 0,
1849 0xC0, 12, 0, 0, 0, 0,
1850 }
1851 if !bytes.Equal(msg[maxPtr:], expect) {
1852 t.Fatalf("msg[maxPtr:] = %v, want: %v", msg[maxPtr:], expect)
1853 }
1854 }
1855
View as plain text