1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
15 func TestPrintPaddedUint8(t *testing.T) {
32 for _, test := range tests {
33 if got := printPaddedUint8(test.num); got != test.want {
34 t.Errorf("got printPaddedUint8(%d) = %s, want = %s", test.num, got, test.want)
39 func TestPrintUint8Bytes(t *testing.T) {
53 for _, test := range tests {
54 if got, want := string(printUint8Bytes(nil, test)), fmt.Sprint(test); got != want {
55 t.Errorf("got printUint8Bytes(%d) = %s, want = %s", test, got, want)
60 func TestPrintUint16(t *testing.T) {
74 for _, test := range tests {
75 if got, want := printUint16(test), fmt.Sprint(test); got != want {
76 t.Errorf("got printUint16(%d) = %s, want = %s", test, got, want)
81 func TestPrintUint32(t *testing.T) {
101 for _, test := range tests {
102 if got, want := printUint32(test), fmt.Sprint(test); got != want {
103 t.Errorf("got printUint32(%d) = %s, want = %s", test, got, want)
108 func mustEDNS0ResourceHeader(l int, extrc RCode, do bool) ResourceHeader {
109 h := ResourceHeader{Class: ClassINET}
110 if err := h.SetEDNS0(l, extrc, do); err != nil {
116 func (m *Message) String() string {
117 s := fmt.Sprintf("Message: %#v\n", &m.Header)
118 if len(m.Questions) > 0 {
119 s += "-- Questions\n"
120 for _, q := range m.Questions {
121 s += fmt.Sprintf("%#v\n", q)
124 if len(m.Answers) > 0 {
126 for _, a := range m.Answers {
127 s += fmt.Sprintf("%#v\n", a)
130 if len(m.Authorities) > 0 {
131 s += "-- Authorities\n"
132 for _, ns := range m.Authorities {
133 s += fmt.Sprintf("%#v\n", ns)
136 if len(m.Additionals) > 0 {
137 s += "-- Additionals\n"
138 for _, e := range m.Additionals {
139 s += fmt.Sprintf("%#v\n", e)
145 func TestNameString(t *testing.T) {
147 name := MustNewName(want)
148 if got := fmt.Sprint(name); got != want {
149 t.Errorf("got fmt.Sprint(%#v) = %s, want = %s", name, got, want)
153 func TestQuestionPackUnpack(t *testing.T) {
155 Name: MustNewName("."),
159 buf, err := want.pack(make([]byte, 1, 50), map[string]int{}, 1)
161 t.Fatal("Question.pack() =", err)
165 p.header.questions = 1
166 p.section = sectionQuestions
168 got, err := p.Question()
170 t.Fatalf("Parser{%q}.Question() = %v", string(buf[1:]), err)
172 if p.off != len(buf) {
173 t.Errorf("unpacked different amount than packed: got = %d, want = %d", p.off, len(buf))
175 if !reflect.DeepEqual(got, want) {
176 t.Errorf("got from Parser.Question() = %+v, want = %+v", got, want)
180 func TestName(t *testing.T) {
193 for _, test := range tests {
194 n, err := NewName(test)
196 t.Errorf("NewName(%q) = %v", test, err)
199 if ns := n.String(); ns != test {
200 t.Errorf("got %#v.String() = %q, want = %q", n, ns, test)
206 func TestNamePackUnpack(t *testing.T) {
212 {"", "", errNonCanonicalName},
214 {"google..com", "", errNonCanonicalName},
215 {"google.com", "", errNonCanonicalName},
216 {"google..com.", "", errZeroSegLen},
217 {"google.com.", "google.com.", nil},
218 {".google.com.", "", errZeroSegLen},
219 {"www..google.com.", "", errZeroSegLen},
220 {"www.google.com.", "www.google.com.", nil},
223 for _, test := range tests {
224 in := MustNewName(test.in)
225 want := MustNewName(test.want)
226 buf, err := in.pack(make([]byte, 0, 30), map[string]int{}, 0)
228 t.Errorf("got %q.pack() = %v, want = %v", test.in, err, test.err)
235 n, err := got.unpack(buf, 0)
237 t.Errorf("%q.unpack() = %v", test.in, err)
242 "unpacked different amount than packed for %q: got = %d, want = %d",
249 t.Errorf("unpacking packing of %q: got = %#v, want = %#v", test.in, got, want)
254 func TestIncompressibleName(t *testing.T) {
255 name := MustNewName("example.com.")
256 compression := map[string]int{}
257 buf, err := name.pack(make([]byte, 0, 100), compression, 0)
259 t.Fatal("first Name.pack() =", err)
261 buf, err = name.pack(buf, compression, 0)
263 t.Fatal("second Name.pack() =", err)
266 off, err := n1.unpackCompressed(buf, 0, false /* allowCompression */)
268 t.Fatal("unpacking incompressible name without pointers failed:", err)
271 if _, err := n2.unpackCompressed(buf, off, false /* allowCompression */); err != errCompressedSRV {
272 t.Errorf("unpacking compressed incompressible name with pointers: got %v, want = %v", err, errCompressedSRV)
276 func checkErrorPrefix(err error, prefix string) bool {
277 e, ok := err.(*nestedError)
278 return ok && e.s == prefix
281 func TestHeaderUnpackError(t *testing.T) {
292 for _, want := range wants {
293 n, err := h.unpack(buf, 0)
294 if n != 0 || !checkErrorPrefix(err, want) {
295 t.Errorf("got header.unpack([%d]byte, 0) = %d, %v, want = 0, %s", len(buf), n, err, want)
297 buf = append(buf, 0, 0)
301 func TestParserStart(t *testing.T) {
302 const want = "unpacking header"
304 for i := 0; i <= 1; i++ {
305 _, err := p.Start([]byte{})
306 if !checkErrorPrefix(err, want) {
307 t.Errorf("got Parser.Start(nil) = _, %v, want = _, %s", err, want)
312 func TestResourceNotStarted(t *testing.T) {
315 fn func(*Parser) error
317 {"CNAMEResource", func(p *Parser) error { _, err := p.CNAMEResource(); return err }},
318 {"MXResource", func(p *Parser) error { _, err := p.MXResource(); return err }},
319 {"NSResource", func(p *Parser) error { _, err := p.NSResource(); return err }},
320 {"PTRResource", func(p *Parser) error { _, err := p.PTRResource(); return err }},
321 {"SOAResource", func(p *Parser) error { _, err := p.SOAResource(); return err }},
322 {"TXTResource", func(p *Parser) error { _, err := p.TXTResource(); return err }},
323 {"SRVResource", func(p *Parser) error { _, err := p.SRVResource(); return err }},
324 {"AResource", func(p *Parser) error { _, err := p.AResource(); return err }},
325 {"AAAAResource", func(p *Parser) error { _, err := p.AAAAResource(); return err }},
328 for _, test := range tests {
329 if err := test.fn(&Parser{}); err != ErrNotStarted {
330 t.Errorf("got Parser.%s() = _ , %v, want = _, %v", test.name, err, ErrNotStarted)
335 func TestDNSPackUnpack(t *testing.T) {
338 Questions: []Question{
340 Name: MustNewName("."),
345 Answers: []Resource{},
346 Authorities: []Resource{},
347 Additionals: []Resource{},
351 for i, want := range wants {
352 b, err := want.Pack()
354 t.Fatalf("%d: Message.Pack() = %v", i, err)
359 t.Fatalf("%d: Message.Unapck() = %v", i, err)
361 if !reflect.DeepEqual(got, want) {
362 t.Errorf("%d: Message.Pack/Unpack() roundtrip: got = %+v, want = %+v", i, &got, &want)
367 func TestDNSAppendPackUnpack(t *testing.T) {
370 Questions: []Question{
372 Name: MustNewName("."),
377 Answers: []Resource{},
378 Authorities: []Resource{},
379 Additionals: []Resource{},
383 for i, want := range wants {
384 b := make([]byte, 2, 514)
385 b, err := want.AppendPack(b)
387 t.Fatalf("%d: Message.AppendPack() = %v", i, err)
393 t.Fatalf("%d: Message.Unapck() = %v", i, err)
395 if !reflect.DeepEqual(got, want) {
396 t.Errorf("%d: Message.AppendPack/Unpack() roundtrip: got = %+v, want = %+v", i, &got, &want)
401 func TestSkipAll(t *testing.T) {
402 msg := largeTestMsg()
403 buf, err := msg.Pack()
405 t.Fatal("Message.Pack() =", err)
408 if _, err := p.Start(buf); err != nil {
409 t.Fatal("Parser.Start(non-nil) =", err)
416 {"SkipAllQuestions", p.SkipAllQuestions},
417 {"SkipAllAnswers", p.SkipAllAnswers},
418 {"SkipAllAuthorities", p.SkipAllAuthorities},
419 {"SkipAllAdditionals", p.SkipAllAdditionals},
421 for _, test := range tests {
422 for i := 1; i <= 3; i++ {
423 if err := test.f(); err != nil {
424 t.Errorf("%d: Parser.%s() = %v", i, test.name, err)
430 func TestSkipEach(t *testing.T) {
431 msg := smallTestMsg()
433 buf, err := msg.Pack()
435 t.Fatal("Message.Pack() =", err)
438 if _, err := p.Start(buf); err != nil {
439 t.Fatal("Parser.Start(non-nil) =", err)
446 {"SkipQuestion", p.SkipQuestion},
447 {"SkipAnswer", p.SkipAnswer},
448 {"SkipAuthority", p.SkipAuthority},
449 {"SkipAdditional", p.SkipAdditional},
451 for _, test := range tests {
452 if err := test.f(); err != nil {
453 t.Errorf("first Parser.%s() = %v, want = nil", test.name, err)
455 if err := test.f(); err != ErrSectionDone {
456 t.Errorf("second Parser.%s() = %v, want = %v", test.name, err, ErrSectionDone)
461 func TestSkipAfterRead(t *testing.T) {
462 msg := smallTestMsg()
464 buf, err := msg.Pack()
466 t.Fatal("Message.Pack() =", err)
469 if _, err := p.Start(buf); err != nil {
470 t.Fatal("Parser.Srart(non-nil) =", err)
478 {"Question", p.SkipQuestion, func() error { _, err := p.Question(); return err }},
479 {"Answer", p.SkipAnswer, func() error { _, err := p.Answer(); return err }},
480 {"Authority", p.SkipAuthority, func() error { _, err := p.Authority(); return err }},
481 {"Additional", p.SkipAdditional, func() error { _, err := p.Additional(); return err }},
483 for _, test := range tests {
484 if err := test.read(); err != nil {
485 t.Errorf("got Parser.%s() = _, %v, want = _, nil", test.name, err)
487 if err := test.skip(); err != ErrSectionDone {
488 t.Errorf("got Parser.Skip%s() = %v, want = %v", test.name, err, ErrSectionDone)
493 func TestSkipNotStarted(t *testing.T) {
500 {"SkipAllQuestions", p.SkipAllQuestions},
501 {"SkipAllAnswers", p.SkipAllAnswers},
502 {"SkipAllAuthorities", p.SkipAllAuthorities},
503 {"SkipAllAdditionals", p.SkipAllAdditionals},
505 for _, test := range tests {
506 if err := test.f(); err != ErrNotStarted {
507 t.Errorf("got Parser.%s() = %v, want = %v", test.name, err, ErrNotStarted)
512 func TestTooManyRecords(t *testing.T) {
513 const recs = int(^uint16(0)) + 1
522 Questions: make([]Question, recs),
529 Answers: make([]Resource, recs),
536 Authorities: make([]Resource, recs),
538 errTooManyAuthorities,
543 Additionals: make([]Resource, recs),
545 errTooManyAdditionals,
549 for _, test := range tests {
550 if _, got := test.msg.Pack(); got != test.want {
551 t.Errorf("got Message.Pack() for %d %s = %v, want = %v", recs, test.name, got, test.want)
556 func TestVeryLongTxt(t *testing.T) {
559 Name: MustNewName("foo.bar.example.com."),
563 &TXTResource{[]string{
570 strings.Repeat(".", 255),
573 buf, err := want.pack(make([]byte, 0, 8000), map[string]int{}, 0)
575 t.Fatal("Resource.pack() =", err)
578 off, err := got.Header.unpack(buf, 0)
580 t.Fatal("ResourceHeader.unpack() =", err)
582 body, n, err := unpackResourceBody(buf, off, got.Header)
584 t.Fatal("unpackResourceBody() =", err)
588 t.Errorf("unpacked different amount than packed: got = %d, want = %d", n, len(buf))
590 if !reflect.DeepEqual(got, want) {
591 t.Errorf("Resource.pack/unpack() roundtrip: got = %#v, want = %#v", got, want)
595 func TestTooLongTxt(t *testing.T) {
596 rb := TXTResource{[]string{strings.Repeat(".", 256)}}
597 if _, err := rb.pack(make([]byte, 0, 8000), map[string]int{}, 0); err != errStringTooLong {
598 t.Errorf("packing TXTResource with 256 character string: got err = %v, want = %v", err, errStringTooLong)
602 func TestStartAppends(t *testing.T) {
603 buf := make([]byte, 2, 514)
604 wantBuf := []byte{4, 44}
607 b := NewBuilder(buf, Header{})
608 b.EnableCompression()
610 buf, err := b.Finish()
612 t.Fatal("Builder.Finish() =", err)
614 if got, want := len(buf), headerLen+2; got != want {
615 t.Errorf("got len(buf) = %d, want = %d", got, want)
617 if string(buf[:2]) != string(wantBuf) {
618 t.Errorf("original data not preserved, got = %#v, want = %#v", buf[:2], wantBuf)
622 func TestStartError(t *testing.T) {
625 fn func(*Builder) error
627 {"Questions", func(b *Builder) error { return b.StartQuestions() }},
628 {"Answers", func(b *Builder) error { return b.StartAnswers() }},
629 {"Authorities", func(b *Builder) error { return b.StartAuthorities() }},
630 {"Additionals", func(b *Builder) error { return b.StartAdditionals() }},
638 {"sectionNotStarted", func() *Builder { return &Builder{section: sectionNotStarted} }, ErrNotStarted},
639 {"sectionDone", func() *Builder { return &Builder{section: sectionDone} }, ErrSectionDone},
642 for _, env := range envs {
643 for _, test := range tests {
644 if got := test.fn(env.fn()); got != env.want {
645 t.Errorf("got Builder{%s}.Start%s() = %v, want = %v", env.name, test.name, got, env.want)
651 func TestBuilderResourceError(t *testing.T) {
654 fn func(*Builder) error
656 {"CNAMEResource", func(b *Builder) error { return b.CNAMEResource(ResourceHeader{}, CNAMEResource{}) }},
657 {"MXResource", func(b *Builder) error { return b.MXResource(ResourceHeader{}, MXResource{}) }},
658 {"NSResource", func(b *Builder) error { return b.NSResource(ResourceHeader{}, NSResource{}) }},
659 {"PTRResource", func(b *Builder) error { return b.PTRResource(ResourceHeader{}, PTRResource{}) }},
660 {"SOAResource", func(b *Builder) error { return b.SOAResource(ResourceHeader{}, SOAResource{}) }},
661 {"TXTResource", func(b *Builder) error { return b.TXTResource(ResourceHeader{}, TXTResource{}) }},
662 {"SRVResource", func(b *Builder) error { return b.SRVResource(ResourceHeader{}, SRVResource{}) }},
663 {"AResource", func(b *Builder) error { return b.AResource(ResourceHeader{}, AResource{}) }},
664 {"AAAAResource", func(b *Builder) error { return b.AAAAResource(ResourceHeader{}, AAAAResource{}) }},
665 {"OPTResource", func(b *Builder) error { return b.OPTResource(ResourceHeader{}, OPTResource{}) }},
673 {"sectionNotStarted", func() *Builder { return &Builder{section: sectionNotStarted} }, ErrNotStarted},
674 {"sectionHeader", func() *Builder { return &Builder{section: sectionHeader} }, ErrNotStarted},
675 {"sectionQuestions", func() *Builder { return &Builder{section: sectionQuestions} }, ErrNotStarted},
676 {"sectionDone", func() *Builder { return &Builder{section: sectionDone} }, ErrSectionDone},
679 for _, env := range envs {
680 for _, test := range tests {
681 if got := test.fn(env.fn()); got != env.want {
682 t.Errorf("got Builder{%s}.%s() = %v, want = %v", env.name, test.name, got, env.want)
688 func TestFinishError(t *testing.T) {
690 want := ErrNotStarted
691 if _, got := b.Finish(); got != want {
692 t.Errorf("got Builder.Finish() = %v, want = %v", got, want)
696 func TestBuilder(t *testing.T) {
697 msg := largeTestMsg()
698 want, err := msg.Pack()
700 t.Fatal("Message.Pack() =", err)
703 b := NewBuilder(nil, msg.Header)
704 b.EnableCompression()
706 if err := b.StartQuestions(); err != nil {
707 t.Fatal("Builder.StartQuestions() =", err)
709 for _, q := range msg.Questions {
710 if err := b.Question(q); err != nil {
711 t.Fatalf("Builder.Question(%#v) = %v", q, err)
715 if err := b.StartAnswers(); err != nil {
716 t.Fatal("Builder.StartAnswers() =", err)
718 for _, a := range msg.Answers {
719 switch a.Header.Type {
721 if err := b.AResource(a.Header, *a.Body.(*AResource)); err != nil {
722 t.Fatalf("Builder.AResource(%#v) = %v", a, err)
725 if err := b.NSResource(a.Header, *a.Body.(*NSResource)); err != nil {
726 t.Fatalf("Builder.NSResource(%#v) = %v", a, err)
729 if err := b.CNAMEResource(a.Header, *a.Body.(*CNAMEResource)); err != nil {
730 t.Fatalf("Builder.CNAMEResource(%#v) = %v", a, err)
733 if err := b.SOAResource(a.Header, *a.Body.(*SOAResource)); err != nil {
734 t.Fatalf("Builder.SOAResource(%#v) = %v", a, err)
737 if err := b.PTRResource(a.Header, *a.Body.(*PTRResource)); err != nil {
738 t.Fatalf("Builder.PTRResource(%#v) = %v", a, err)
741 if err := b.MXResource(a.Header, *a.Body.(*MXResource)); err != nil {
742 t.Fatalf("Builder.MXResource(%#v) = %v", a, err)
745 if err := b.TXTResource(a.Header, *a.Body.(*TXTResource)); err != nil {
746 t.Fatalf("Builder.TXTResource(%#v) = %v", a, err)
749 if err := b.AAAAResource(a.Header, *a.Body.(*AAAAResource)); err != nil {
750 t.Fatalf("Builder.AAAAResource(%#v) = %v", a, err)
753 if err := b.SRVResource(a.Header, *a.Body.(*SRVResource)); err != nil {
754 t.Fatalf("Builder.SRVResource(%#v) = %v", a, err)
759 if err := b.StartAuthorities(); err != nil {
760 t.Fatal("Builder.StartAuthorities() =", err)
762 for _, a := range msg.Authorities {
763 if err := b.NSResource(a.Header, *a.Body.(*NSResource)); err != nil {
764 t.Fatalf("Builder.NSResource(%#v) = %v", a, err)
768 if err := b.StartAdditionals(); err != nil {
769 t.Fatal("Builder.StartAdditionals() =", err)
771 for _, a := range msg.Additionals {
772 switch a.Body.(type) {
774 if err := b.TXTResource(a.Header, *a.Body.(*TXTResource)); err != nil {
775 t.Fatalf("Builder.TXTResource(%#v) = %v", a, err)
778 if err := b.OPTResource(a.Header, *a.Body.(*OPTResource)); err != nil {
779 t.Fatalf("Builder.OPTResource(%#v) = %v", a, err)
784 got, err := b.Finish()
786 t.Fatal("Builder.Finish() =", err)
788 if !bytes.Equal(got, want) {
789 t.Fatalf("got from Builder.Finish() = %#v\nwant = %#v", got, want)
793 func TestResourcePack(t *testing.T) {
794 for _, tt := range []struct {
800 Questions: []Question{
802 Name: MustNewName("."),
807 Answers: []Resource{{ResourceHeader{}, nil}},
809 &nestedError{"packing Answer", errNilResouceBody},
813 Questions: []Question{
815 Name: MustNewName("."),
820 Authorities: []Resource{{ResourceHeader{}, (*NSResource)(nil)}},
822 &nestedError{"packing Authority",
823 &nestedError{"ResourceHeader",
824 &nestedError{"Name", errNonCanonicalName},
830 Questions: []Question{
832 Name: MustNewName("."),
837 Additionals: []Resource{{ResourceHeader{}, nil}},
839 &nestedError{"packing Additional", errNilResouceBody},
842 _, err := tt.m.Pack()
843 if !reflect.DeepEqual(err, tt.err) {
844 t.Errorf("got Message{%v}.Pack() = %v, want %v", tt.m, err, tt.err)
849 func TestResourcePackLength(t *testing.T) {
852 Name: MustNewName("."),
856 &AResource{[4]byte{127, 0, 0, 2}},
859 hb, _, err := r.Header.pack(nil, nil, 0)
861 t.Fatal("ResourceHeader.pack() =", err)
863 buf := make([]byte, 0, len(hb))
864 buf, err = r.pack(buf, nil, 0)
866 t.Fatal("Resource.pack() =", err)
869 var hdr ResourceHeader
870 if _, err := hdr.unpack(buf, 0); err != nil {
871 t.Fatal("ResourceHeader.unpack() =", err)
874 if got, want := int(hdr.Length), len(buf)-len(hb); got != want {
875 t.Errorf("got hdr.Length = %d, want = %d", got, want)
879 func TestOptionPackUnpack(t *testing.T) {
880 for _, tt := range []struct {
882 w []byte // wire format of m.Additionals
888 name: "without EDNS(0) options",
890 0x00, 0x00, 0x29, 0x10, 0x00, 0xfe, 0x00, 0x80,
894 Header: Header{RCode: RCodeFormatError},
895 Questions: []Question{
897 Name: MustNewName("."),
902 Additionals: []Resource{
904 mustEDNS0ResourceHeader(4096, 0xfe0|RCodeFormatError, true),
910 extRCode: 0xfe0 | RCodeFormatError,
913 name: "with EDNS(0) options",
915 0x00, 0x00, 0x29, 0x10, 0x00, 0xff, 0x00, 0x00,
916 0x00, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x02, 0x00,
917 0x00, 0x00, 0x0b, 0x00, 0x02, 0x12, 0x34,
920 Header: Header{RCode: RCodeServerFailure},
921 Questions: []Question{
923 Name: MustNewName("."),
928 Additionals: []Resource{
930 mustEDNS0ResourceHeader(4096, 0xff0|RCodeServerFailure, false),
934 Code: 12, // see RFC 7828
935 Data: []byte{0x00, 0x00},
938 Code: 11, // see RFC 7830
939 Data: []byte{0x12, 0x34},
947 extRCode: 0xff0 | RCodeServerFailure,
950 // Containing multiple OPT resources in a
951 // message is invalid, but it's necessary for
952 // protocol conformance testing.
953 name: "with multiple OPT resources",
955 0x00, 0x00, 0x29, 0x10, 0x00, 0xff, 0x00, 0x00,
956 0x00, 0x00, 0x06, 0x00, 0x0b, 0x00, 0x02, 0x12,
957 0x34, 0x00, 0x00, 0x29, 0x10, 0x00, 0xff, 0x00,
958 0x00, 0x00, 0x00, 0x06, 0x00, 0x0c, 0x00, 0x02,
962 Header: Header{RCode: RCodeNameError},
963 Questions: []Question{
965 Name: MustNewName("."),
970 Additionals: []Resource{
972 mustEDNS0ResourceHeader(4096, 0xff0|RCodeNameError, false),
976 Code: 11, // see RFC 7830
977 Data: []byte{0x12, 0x34},
983 mustEDNS0ResourceHeader(4096, 0xff0|RCodeNameError, false),
987 Code: 12, // see RFC 7828
988 Data: []byte{0x00, 0x00},
997 w, err := tt.m.Pack()
999 t.Errorf("Message.Pack() for %s = %v", tt.name, err)
1002 if !bytes.Equal(w[len(w)-len(tt.w):], tt.w) {
1003 t.Errorf("got Message.Pack() for %s = %#v, want %#v", tt.name, w[len(w)-len(tt.w):], tt.w)
1007 if err := m.Unpack(w); err != nil {
1008 t.Errorf("Message.Unpack() for %s = %v", tt.name, err)
1011 if !reflect.DeepEqual(m.Additionals, tt.m.Additionals) {
1012 t.Errorf("got Message.Pack/Unpack() roundtrip for %s = %+v, want %+v", tt.name, m, tt.m)
1018 // TestGoString tests that Message.GoString produces Go code that compiles to
1019 // reproduce the Message.
1021 // This test was produced as follows:
1022 // 1. Run (*Message).GoString on largeTestMsg().
1023 // 2. Remove "dnsmessage." from the output.
1024 // 3. Paste the result in the test to store it in msg.
1025 // 4. Also put the original output in the test to store in want.
1026 func TestGoString(t *testing.T) {
1027 msg := Message{Header: Header{ID: 0, Response: true, OpCode: 0, Authoritative: true, Truncated: false, RecursionDesired: false, RecursionAvailable: false, RCode: RCodeSuccess}, Questions: []Question{{Name: MustNewName("foo.bar.example.com."), Type: TypeA, Class: ClassINET}}, Answers: []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}}}, {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}}}, {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}}}, {Header: ResourceHeader{Name: MustNewName("foo.bar.example.com."), Type: TypeCNAME, Class: ClassINET, TTL: 0, Length: 0}, Body: &CNAMEResource{CNAME: MustNewName("alias.example.com.")}}, {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}}, {Header: ResourceHeader{Name: MustNewName("foo.bar.example.com."), Type: TypePTR, Class: ClassINET, TTL: 0, Length: 0}, Body: &PTRResource{PTR: MustNewName("ptr.example.com.")}}, {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.")}}, {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.")}}}, Authorities: []Resource{{Header: ResourceHeader{Name: MustNewName("foo.bar.example.com."), Type: TypeNS, Class: ClassINET, TTL: 0, Length: 0}, Body: &NSResource{NS: MustNewName("ns1.example.com.")}}, {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{{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"}}}, {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"}}}, {Header: ResourceHeader{Name: MustNewName("."), Type: TypeOPT, Class: 4096, TTL: 4261412864, Length: 0}, Body: &OPTResource{Options: []Option{{Code: 10, Data: []byte{1, 35, 69, 103, 137, 171, 205, 239}}}}}}}
1028 if !reflect.DeepEqual(msg, largeTestMsg()) {
1029 t.Error("Message.GoString lost information or largeTestMsg changed: msg != largeTestMsg()")
1031 got := msg.GoString()
1032 want := `dnsmessage.Message{Header: dnsmessage.Header{ID: 0, Response: true, OpCode: 0, Authoritative: true, Truncated: false, RecursionDesired: false, RecursionAvailable: 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.")}}}, 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}}}}}}}`
1034 t.Errorf("got msg1.GoString() = %s\nwant = %s", got, want)
1038 func benchmarkParsingSetup() ([]byte, error) {
1039 name := MustNewName("foo.bar.example.com.")
1041 Header: Header{Response: true, Authoritative: true},
1042 Questions: []Question{
1049 Answers: []Resource{
1055 &AResource{[4]byte{}},
1062 &AAAAResource{[16]byte{}},
1069 &CNAMEResource{name},
1081 buf, err := msg.Pack()
1083 return nil, fmt.Errorf("Message.Pack() = %v", err)
1088 func benchmarkParsing(tb testing.TB, buf []byte) {
1090 if _, err := p.Start(buf); err != nil {
1091 tb.Fatal("Parser.Start(non-nil) =", err)
1095 _, err := p.Question()
1096 if err == ErrSectionDone {
1100 tb.Fatal("Parser.Question() =", err)
1105 h, err := p.AnswerHeader()
1106 if err == ErrSectionDone {
1110 tb.Fatal("Parser.AnswerHeader() =", err)
1115 if _, err := p.AResource(); err != nil {
1116 tb.Fatal("Parser.AResource() =", err)
1119 if _, err := p.AAAAResource(); err != nil {
1120 tb.Fatal("Parser.AAAAResource() =", err)
1123 if _, err := p.CNAMEResource(); err != nil {
1124 tb.Fatal("Parser.CNAMEResource() =", err)
1127 if _, err := p.NSResource(); err != nil {
1128 tb.Fatal("Parser.NSResource() =", err)
1131 if _, err := p.OPTResource(); err != nil {
1132 tb.Fatal("Parser.OPTResource() =", err)
1135 tb.Fatalf("got unknown type: %T", h)
1140 func BenchmarkParsing(b *testing.B) {
1141 buf, err := benchmarkParsingSetup()
1147 for i := 0; i < b.N; i++ {
1148 benchmarkParsing(b, buf)
1152 func TestParsingAllocs(t *testing.T) {
1153 buf, err := benchmarkParsingSetup()
1158 if allocs := testing.AllocsPerRun(100, func() { benchmarkParsing(t, buf) }); allocs > 0.5 {
1159 t.Errorf("allocations during parsing: got = %f, want ~0", allocs)
1163 func benchmarkBuildingSetup() (Name, []byte) {
1164 name := MustNewName("foo.bar.example.com.")
1165 buf := make([]byte, 0, packStartingCap)
1169 func benchmarkBuilding(tb testing.TB, name Name, buf []byte) {
1170 bld := NewBuilder(buf, Header{Response: true, Authoritative: true})
1172 if err := bld.StartQuestions(); err != nil {
1173 tb.Fatal("Builder.StartQuestions() =", err)
1180 if err := bld.Question(q); err != nil {
1181 tb.Fatalf("Builder.Question(%+v) = %v", q, err)
1184 hdr := ResourceHeader{
1188 if err := bld.StartAnswers(); err != nil {
1189 tb.Fatal("Builder.StartQuestions() =", err)
1192 ar := AResource{[4]byte{}}
1193 if err := bld.AResource(hdr, ar); err != nil {
1194 tb.Fatalf("Builder.AResource(%+v, %+v) = %v", hdr, ar, err)
1197 aaar := AAAAResource{[16]byte{}}
1198 if err := bld.AAAAResource(hdr, aaar); err != nil {
1199 tb.Fatalf("Builder.AAAAResource(%+v, %+v) = %v", hdr, aaar, err)
1202 cnr := CNAMEResource{name}
1203 if err := bld.CNAMEResource(hdr, cnr); err != nil {
1204 tb.Fatalf("Builder.CNAMEResource(%+v, %+v) = %v", hdr, cnr, err)
1207 nsr := NSResource{name}
1208 if err := bld.NSResource(hdr, nsr); err != nil {
1209 tb.Fatalf("Builder.NSResource(%+v, %+v) = %v", hdr, nsr, err)
1212 extrc := 0xfe0 | RCodeNotImplemented
1213 if err := (&hdr).SetEDNS0(4096, extrc, true); err != nil {
1214 tb.Fatalf("ResourceHeader.SetEDNS0(4096, %#x, true) = %v", extrc, err)
1216 optr := OPTResource{}
1217 if err := bld.OPTResource(hdr, optr); err != nil {
1218 tb.Fatalf("Builder.OPTResource(%+v, %+v) = %v", hdr, optr, err)
1221 if _, err := bld.Finish(); err != nil {
1222 tb.Fatal("Builder.Finish() =", err)
1226 func BenchmarkBuilding(b *testing.B) {
1227 name, buf := benchmarkBuildingSetup()
1229 for i := 0; i < b.N; i++ {
1230 benchmarkBuilding(b, name, buf)
1234 func TestBuildingAllocs(t *testing.T) {
1235 name, buf := benchmarkBuildingSetup()
1236 if allocs := testing.AllocsPerRun(100, func() { benchmarkBuilding(t, name, buf) }); allocs > 0.5 {
1237 t.Errorf("allocations during building: got = %f, want ~0", allocs)
1241 func smallTestMsg() Message {
1242 name := MustNewName("example.com.")
1244 Header: Header{Response: true, Authoritative: true},
1245 Questions: []Question{
1252 Answers: []Resource{
1259 &AResource{[4]byte{127, 0, 0, 1}},
1262 Authorities: []Resource{
1269 &AResource{[4]byte{127, 0, 0, 1}},
1272 Additionals: []Resource{
1279 &AResource{[4]byte{127, 0, 0, 1}},
1285 func BenchmarkPack(b *testing.B) {
1286 msg := largeTestMsg()
1290 for i := 0; i < b.N; i++ {
1291 if _, err := msg.Pack(); err != nil {
1292 b.Fatal("Message.Pack() =", err)
1297 func BenchmarkAppendPack(b *testing.B) {
1298 msg := largeTestMsg()
1299 buf := make([]byte, 0, packStartingCap)
1303 for i := 0; i < b.N; i++ {
1304 if _, err := msg.AppendPack(buf[:0]); err != nil {
1305 b.Fatal("Message.AppendPack() = ", err)
1310 func largeTestMsg() Message {
1311 name := MustNewName("foo.bar.example.com.")
1313 Header: Header{Response: true, Authoritative: true},
1314 Questions: []Question{
1321 Answers: []Resource{
1328 &AResource{[4]byte{127, 0, 0, 1}},
1336 &AResource{[4]byte{127, 0, 0, 2}},
1344 &AAAAResource{[16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}},
1352 &CNAMEResource{MustNewName("alias.example.com.")},
1361 NS: MustNewName("ns1.example.com."),
1362 MBox: MustNewName("mb.example.com."),
1376 &PTRResource{MustNewName("ptr.example.com.")},
1386 MustNewName("mx.example.com."),
1399 MustNewName("srv.example.com."),
1403 Authorities: []Resource{
1410 &NSResource{MustNewName("ns1.example.com.")},
1418 &NSResource{MustNewName("ns2.example.com.")},
1421 Additionals: []Resource{
1428 &TXTResource{[]string{"So Long, and Thanks for All the Fish"}},
1436 &TXTResource{[]string{"Hamster Huey and the Gooey Kablooie"}},
1439 mustEDNS0ResourceHeader(4096, 0xfe0|RCodeSuccess, false),
1443 Code: 10, // see RFC 7873
1444 Data: []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef},