gitee.com/ks-custle/core-gm@v0.0.0-20230922171213-b83bdd97b62c/net/dns/dnsmessage/message_test.go (about) 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. 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 // This type was selected randomly from the IANA-assigned private use 19 // range of RR TYPEs. 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]int{}, 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 TestNamePackUnpack(t *testing.T) { 215 tests := []struct { 216 in string 217 want string 218 err error 219 }{ 220 {"", "", errNonCanonicalName}, 221 {".", ".", nil}, 222 {"google..com", "", errNonCanonicalName}, 223 {"google.com", "", errNonCanonicalName}, 224 {"google..com.", "", errZeroSegLen}, 225 {"google.com.", "google.com.", nil}, 226 {".google.com.", "", errZeroSegLen}, 227 {"www..google.com.", "", errZeroSegLen}, 228 {"www.google.com.", "www.google.com.", nil}, 229 } 230 231 for _, test := range tests { 232 in := MustNewName(test.in) 233 want := MustNewName(test.want) 234 buf, err := in.pack(make([]byte, 0, 30), map[string]int{}, 0) 235 if err != test.err { 236 t.Errorf("got %q.pack() = %v, want = %v", test.in, err, test.err) 237 continue 238 } 239 if test.err != nil { 240 continue 241 } 242 var got Name 243 n, err := got.unpack(buf, 0) 244 if err != nil { 245 t.Errorf("%q.unpack() = %v", test.in, err) 246 continue 247 } 248 if n != len(buf) { 249 t.Errorf( 250 "unpacked different amount than packed for %q: got = %d, want = %d", 251 test.in, 252 n, 253 len(buf), 254 ) 255 } 256 if got != want { 257 t.Errorf("unpacking packing of %q: got = %#v, want = %#v", test.in, got, want) 258 } 259 } 260 } 261 262 func TestIncompressibleName(t *testing.T) { 263 name := MustNewName("example.com.") 264 compression := map[string]int{} 265 buf, err := name.pack(make([]byte, 0, 100), compression, 0) 266 if err != nil { 267 t.Fatal("first Name.pack() =", err) 268 } 269 buf, err = name.pack(buf, compression, 0) 270 if err != nil { 271 t.Fatal("second Name.pack() =", err) 272 } 273 var n1 Name 274 off, err := n1.unpackCompressed(buf, 0, false /* allowCompression */) 275 if err != nil { 276 t.Fatal("unpacking incompressible name without pointers failed:", err) 277 } 278 var n2 Name 279 if _, err := n2.unpackCompressed(buf, off, false /* allowCompression */); err != errCompressedSRV { 280 t.Errorf("unpacking compressed incompressible name with pointers: got %v, want = %v", err, errCompressedSRV) 281 } 282 } 283 284 func checkErrorPrefix(err error, prefix string) bool { 285 e, ok := err.(*nestedError) 286 return ok && e.s == prefix 287 } 288 289 func TestHeaderUnpackError(t *testing.T) { 290 wants := []string{ 291 "id", 292 "bits", 293 "questions", 294 "answers", 295 "authorities", 296 "additionals", 297 } 298 var buf []byte 299 var h header 300 for _, want := range wants { 301 n, err := h.unpack(buf, 0) 302 if n != 0 || !checkErrorPrefix(err, want) { 303 t.Errorf("got header.unpack([%d]byte, 0) = %d, %v, want = 0, %s", len(buf), n, err, want) 304 } 305 buf = append(buf, 0, 0) 306 } 307 } 308 309 func TestParserStart(t *testing.T) { 310 const want = "unpacking header" 311 var p Parser 312 for i := 0; i <= 1; i++ { 313 _, err := p.Start([]byte{}) 314 if !checkErrorPrefix(err, want) { 315 t.Errorf("got Parser.Start(nil) = _, %v, want = _, %s", err, want) 316 } 317 } 318 } 319 320 func TestResourceNotStarted(t *testing.T) { 321 tests := []struct { 322 name string 323 fn func(*Parser) error 324 }{ 325 {"CNAMEResource", func(p *Parser) error { _, err := p.CNAMEResource(); return err }}, 326 {"MXResource", func(p *Parser) error { _, err := p.MXResource(); return err }}, 327 {"NSResource", func(p *Parser) error { _, err := p.NSResource(); return err }}, 328 {"PTRResource", func(p *Parser) error { _, err := p.PTRResource(); return err }}, 329 {"SOAResource", func(p *Parser) error { _, err := p.SOAResource(); return err }}, 330 {"TXTResource", func(p *Parser) error { _, err := p.TXTResource(); return err }}, 331 {"SRVResource", func(p *Parser) error { _, err := p.SRVResource(); return err }}, 332 {"AResource", func(p *Parser) error { _, err := p.AResource(); return err }}, 333 {"AAAAResource", func(p *Parser) error { _, err := p.AAAAResource(); return err }}, 334 {"UnknownResource", func(p *Parser) error { _, err := p.UnknownResource(); return err }}, 335 } 336 337 for _, test := range tests { 338 if err := test.fn(&Parser{}); err != ErrNotStarted { 339 t.Errorf("got Parser.%s() = _ , %v, want = _, %v", test.name, err, ErrNotStarted) 340 } 341 } 342 } 343 344 func TestDNSPackUnpack(t *testing.T) { 345 wants := []Message{ 346 { 347 Questions: []Question{ 348 { 349 Name: MustNewName("."), 350 Type: TypeAAAA, 351 Class: ClassINET, 352 }, 353 }, 354 Answers: []Resource{}, 355 Authorities: []Resource{}, 356 Additionals: []Resource{}, 357 }, 358 largeTestMsg(), 359 } 360 for i, want := range wants { 361 b, err := want.Pack() 362 if err != nil { 363 t.Fatalf("%d: Message.Pack() = %v", i, err) 364 } 365 var got Message 366 err = got.Unpack(b) 367 if err != nil { 368 t.Fatalf("%d: Message.Unapck() = %v", i, err) 369 } 370 if !reflect.DeepEqual(got, want) { 371 t.Errorf("%d: Message.Pack/Unpack() roundtrip: got = %+v, want = %+v", i, &got, &want) 372 } 373 } 374 } 375 376 func TestDNSAppendPackUnpack(t *testing.T) { 377 wants := []Message{ 378 { 379 Questions: []Question{ 380 { 381 Name: MustNewName("."), 382 Type: TypeAAAA, 383 Class: ClassINET, 384 }, 385 }, 386 Answers: []Resource{}, 387 Authorities: []Resource{}, 388 Additionals: []Resource{}, 389 }, 390 largeTestMsg(), 391 } 392 for i, want := range wants { 393 b := make([]byte, 2, 514) 394 b, err := want.AppendPack(b) 395 if err != nil { 396 t.Fatalf("%d: Message.AppendPack() = %v", i, err) 397 } 398 b = b[2:] 399 var got Message 400 err = got.Unpack(b) 401 if err != nil { 402 t.Fatalf("%d: Message.Unapck() = %v", i, err) 403 } 404 if !reflect.DeepEqual(got, want) { 405 t.Errorf("%d: Message.AppendPack/Unpack() roundtrip: got = %+v, want = %+v", i, &got, &want) 406 } 407 } 408 } 409 410 func TestSkipAll(t *testing.T) { 411 msg := largeTestMsg() 412 buf, err := msg.Pack() 413 if err != nil { 414 t.Fatal("Message.Pack() =", err) 415 } 416 var p Parser 417 if _, err := p.Start(buf); err != nil { 418 t.Fatal("Parser.Start(non-nil) =", err) 419 } 420 421 tests := []struct { 422 name string 423 f func() error 424 }{ 425 {"SkipAllQuestions", p.SkipAllQuestions}, 426 {"SkipAllAnswers", p.SkipAllAnswers}, 427 {"SkipAllAuthorities", p.SkipAllAuthorities}, 428 {"SkipAllAdditionals", p.SkipAllAdditionals}, 429 } 430 for _, test := range tests { 431 for i := 1; i <= 3; i++ { 432 if err := test.f(); err != nil { 433 t.Errorf("%d: Parser.%s() = %v", i, test.name, err) 434 } 435 } 436 } 437 } 438 439 func TestSkipEach(t *testing.T) { 440 msg := smallTestMsg() 441 442 buf, err := msg.Pack() 443 if err != nil { 444 t.Fatal("Message.Pack() =", err) 445 } 446 var p Parser 447 if _, err := p.Start(buf); err != nil { 448 t.Fatal("Parser.Start(non-nil) =", err) 449 } 450 451 tests := []struct { 452 name string 453 f func() error 454 }{ 455 {"SkipQuestion", p.SkipQuestion}, 456 {"SkipAnswer", p.SkipAnswer}, 457 {"SkipAuthority", p.SkipAuthority}, 458 {"SkipAdditional", p.SkipAdditional}, 459 } 460 for _, test := range tests { 461 if err := test.f(); err != nil { 462 t.Errorf("first Parser.%s() = %v, want = nil", test.name, err) 463 } 464 if err := test.f(); err != ErrSectionDone { 465 t.Errorf("second Parser.%s() = %v, want = %v", test.name, err, ErrSectionDone) 466 } 467 } 468 } 469 470 func TestSkipAfterRead(t *testing.T) { 471 msg := smallTestMsg() 472 473 buf, err := msg.Pack() 474 if err != nil { 475 t.Fatal("Message.Pack() =", err) 476 } 477 var p Parser 478 if _, err := p.Start(buf); err != nil { 479 t.Fatal("Parser.Srart(non-nil) =", err) 480 } 481 482 tests := []struct { 483 name string 484 skip func() error 485 read func() error 486 }{ 487 {"Question", p.SkipQuestion, func() error { _, err := p.Question(); return err }}, 488 {"Answer", p.SkipAnswer, func() error { _, err := p.Answer(); return err }}, 489 {"Authority", p.SkipAuthority, func() error { _, err := p.Authority(); return err }}, 490 {"Additional", p.SkipAdditional, func() error { _, err := p.Additional(); return err }}, 491 } 492 for _, test := range tests { 493 if err := test.read(); err != nil { 494 t.Errorf("got Parser.%s() = _, %v, want = _, nil", test.name, err) 495 } 496 if err := test.skip(); err != ErrSectionDone { 497 t.Errorf("got Parser.Skip%s() = %v, want = %v", test.name, err, ErrSectionDone) 498 } 499 } 500 } 501 502 func TestSkipNotStarted(t *testing.T) { 503 var p Parser 504 505 tests := []struct { 506 name string 507 f func() error 508 }{ 509 {"SkipAllQuestions", p.SkipAllQuestions}, 510 {"SkipAllAnswers", p.SkipAllAnswers}, 511 {"SkipAllAuthorities", p.SkipAllAuthorities}, 512 {"SkipAllAdditionals", p.SkipAllAdditionals}, 513 } 514 for _, test := range tests { 515 if err := test.f(); err != ErrNotStarted { 516 t.Errorf("got Parser.%s() = %v, want = %v", test.name, err, ErrNotStarted) 517 } 518 } 519 } 520 521 func TestTooManyRecords(t *testing.T) { 522 const recs = int(^uint16(0)) + 1 523 tests := []struct { 524 name string 525 msg Message 526 want error 527 }{ 528 { 529 "Questions", 530 Message{ 531 Questions: make([]Question, recs), 532 }, 533 errTooManyQuestions, 534 }, 535 { 536 "Answers", 537 Message{ 538 Answers: make([]Resource, recs), 539 }, 540 errTooManyAnswers, 541 }, 542 { 543 "Authorities", 544 Message{ 545 Authorities: make([]Resource, recs), 546 }, 547 errTooManyAuthorities, 548 }, 549 { 550 "Additionals", 551 Message{ 552 Additionals: make([]Resource, recs), 553 }, 554 errTooManyAdditionals, 555 }, 556 } 557 558 for _, test := range tests { 559 if _, got := test.msg.Pack(); got != test.want { 560 t.Errorf("got Message.Pack() for %d %s = %v, want = %v", recs, test.name, got, test.want) 561 } 562 } 563 } 564 565 func TestVeryLongTxt(t *testing.T) { 566 want := Resource{ 567 ResourceHeader{ 568 Name: MustNewName("foo.bar.example.com."), 569 Type: TypeTXT, 570 Class: ClassINET, 571 }, 572 &TXTResource{[]string{ 573 "", 574 "", 575 "foo bar", 576 "", 577 "www.example.com", 578 "www.example.com.", 579 strings.Repeat(".", 255), 580 }}, 581 } 582 buf, err := want.pack(make([]byte, 0, 8000), map[string]int{}, 0) 583 if err != nil { 584 t.Fatal("Resource.pack() =", err) 585 } 586 var got Resource 587 off, err := got.Header.unpack(buf, 0) 588 if err != nil { 589 t.Fatal("ResourceHeader.unpack() =", err) 590 } 591 body, n, err := unpackResourceBody(buf, off, got.Header) 592 if err != nil { 593 t.Fatal("unpackResourceBody() =", err) 594 } 595 got.Body = body 596 if n != len(buf) { 597 t.Errorf("unpacked different amount than packed: got = %d, want = %d", n, len(buf)) 598 } 599 if !reflect.DeepEqual(got, want) { 600 t.Errorf("Resource.pack/unpack() roundtrip: got = %#v, want = %#v", got, want) 601 } 602 } 603 604 func TestTooLongTxt(t *testing.T) { 605 rb := TXTResource{[]string{strings.Repeat(".", 256)}} 606 if _, err := rb.pack(make([]byte, 0, 8000), map[string]int{}, 0); err != errStringTooLong { 607 t.Errorf("packing TXTResource with 256 character string: got err = %v, want = %v", err, errStringTooLong) 608 } 609 } 610 611 func TestStartAppends(t *testing.T) { 612 buf := make([]byte, 2, 514) 613 wantBuf := []byte{4, 44} 614 copy(buf, wantBuf) 615 616 b := NewBuilder(buf, Header{}) 617 b.EnableCompression() 618 619 buf, err := b.Finish() 620 if err != nil { 621 t.Fatal("Builder.Finish() =", err) 622 } 623 if got, want := len(buf), headerLen+2; got != want { 624 t.Errorf("got len(buf) = %d, want = %d", got, want) 625 } 626 if string(buf[:2]) != string(wantBuf) { 627 t.Errorf("original data not preserved, got = %#v, want = %#v", buf[:2], wantBuf) 628 } 629 } 630 631 func TestStartError(t *testing.T) { 632 tests := []struct { 633 name string 634 fn func(*Builder) error 635 }{ 636 {"Questions", func(b *Builder) error { return b.StartQuestions() }}, 637 {"Answers", func(b *Builder) error { return b.StartAnswers() }}, 638 {"Authorities", func(b *Builder) error { return b.StartAuthorities() }}, 639 {"Additionals", func(b *Builder) error { return b.StartAdditionals() }}, 640 } 641 642 envs := []struct { 643 name string 644 fn func() *Builder 645 want error 646 }{ 647 {"sectionNotStarted", func() *Builder { return &Builder{section: sectionNotStarted} }, ErrNotStarted}, 648 {"sectionDone", func() *Builder { return &Builder{section: sectionDone} }, ErrSectionDone}, 649 } 650 651 for _, env := range envs { 652 for _, test := range tests { 653 if got := test.fn(env.fn()); got != env.want { 654 t.Errorf("got Builder{%s}.Start%s() = %v, want = %v", env.name, test.name, got, env.want) 655 } 656 } 657 } 658 } 659 660 func TestBuilderResourceError(t *testing.T) { 661 tests := []struct { 662 name string 663 fn func(*Builder) error 664 }{ 665 {"CNAMEResource", func(b *Builder) error { return b.CNAMEResource(ResourceHeader{}, CNAMEResource{}) }}, 666 {"MXResource", func(b *Builder) error { return b.MXResource(ResourceHeader{}, MXResource{}) }}, 667 {"NSResource", func(b *Builder) error { return b.NSResource(ResourceHeader{}, NSResource{}) }}, 668 {"PTRResource", func(b *Builder) error { return b.PTRResource(ResourceHeader{}, PTRResource{}) }}, 669 {"SOAResource", func(b *Builder) error { return b.SOAResource(ResourceHeader{}, SOAResource{}) }}, 670 {"TXTResource", func(b *Builder) error { return b.TXTResource(ResourceHeader{}, TXTResource{}) }}, 671 {"SRVResource", func(b *Builder) error { return b.SRVResource(ResourceHeader{}, SRVResource{}) }}, 672 {"AResource", func(b *Builder) error { return b.AResource(ResourceHeader{}, AResource{}) }}, 673 {"AAAAResource", func(b *Builder) error { return b.AAAAResource(ResourceHeader{}, AAAAResource{}) }}, 674 {"OPTResource", func(b *Builder) error { return b.OPTResource(ResourceHeader{}, OPTResource{}) }}, 675 {"UnknownResource", func(b *Builder) error { return b.UnknownResource(ResourceHeader{}, UnknownResource{}) }}, 676 } 677 678 envs := []struct { 679 name string 680 fn func() *Builder 681 want error 682 }{ 683 {"sectionNotStarted", func() *Builder { return &Builder{section: sectionNotStarted} }, ErrNotStarted}, 684 {"sectionHeader", func() *Builder { return &Builder{section: sectionHeader} }, ErrNotStarted}, 685 {"sectionQuestions", func() *Builder { return &Builder{section: sectionQuestions} }, ErrNotStarted}, 686 {"sectionDone", func() *Builder { return &Builder{section: sectionDone} }, ErrSectionDone}, 687 } 688 689 for _, env := range envs { 690 for _, test := range tests { 691 if got := test.fn(env.fn()); got != env.want { 692 t.Errorf("got Builder{%s}.%s() = %v, want = %v", env.name, test.name, got, env.want) 693 } 694 } 695 } 696 } 697 698 func TestFinishError(t *testing.T) { 699 var b Builder 700 want := ErrNotStarted 701 if _, got := b.Finish(); got != want { 702 t.Errorf("got Builder.Finish() = %v, want = %v", got, want) 703 } 704 } 705 706 func TestBuilder(t *testing.T) { 707 msg := largeTestMsg() 708 want, err := msg.Pack() 709 if err != nil { 710 t.Fatal("Message.Pack() =", err) 711 } 712 713 b := NewBuilder(nil, msg.Header) 714 b.EnableCompression() 715 716 if err := b.StartQuestions(); err != nil { 717 t.Fatal("Builder.StartQuestions() =", err) 718 } 719 for _, q := range msg.Questions { 720 if err := b.Question(q); err != nil { 721 t.Fatalf("Builder.Question(%#v) = %v", q, err) 722 } 723 } 724 725 if err := b.StartAnswers(); err != nil { 726 t.Fatal("Builder.StartAnswers() =", err) 727 } 728 for _, a := range msg.Answers { 729 switch a.Header.Type { 730 case TypeA: 731 if err := b.AResource(a.Header, *a.Body.(*AResource)); err != nil { 732 t.Fatalf("Builder.AResource(%#v) = %v", a, err) 733 } 734 case TypeNS: 735 if err := b.NSResource(a.Header, *a.Body.(*NSResource)); err != nil { 736 t.Fatalf("Builder.NSResource(%#v) = %v", a, err) 737 } 738 case TypeCNAME: 739 if err := b.CNAMEResource(a.Header, *a.Body.(*CNAMEResource)); err != nil { 740 t.Fatalf("Builder.CNAMEResource(%#v) = %v", a, err) 741 } 742 case TypeSOA: 743 if err := b.SOAResource(a.Header, *a.Body.(*SOAResource)); err != nil { 744 t.Fatalf("Builder.SOAResource(%#v) = %v", a, err) 745 } 746 case TypePTR: 747 if err := b.PTRResource(a.Header, *a.Body.(*PTRResource)); err != nil { 748 t.Fatalf("Builder.PTRResource(%#v) = %v", a, err) 749 } 750 case TypeMX: 751 if err := b.MXResource(a.Header, *a.Body.(*MXResource)); err != nil { 752 t.Fatalf("Builder.MXResource(%#v) = %v", a, err) 753 } 754 case TypeTXT: 755 if err := b.TXTResource(a.Header, *a.Body.(*TXTResource)); err != nil { 756 t.Fatalf("Builder.TXTResource(%#v) = %v", a, err) 757 } 758 case TypeAAAA: 759 if err := b.AAAAResource(a.Header, *a.Body.(*AAAAResource)); err != nil { 760 t.Fatalf("Builder.AAAAResource(%#v) = %v", a, err) 761 } 762 case TypeSRV: 763 if err := b.SRVResource(a.Header, *a.Body.(*SRVResource)); err != nil { 764 t.Fatalf("Builder.SRVResource(%#v) = %v", a, err) 765 } 766 case privateUseType: 767 if err := b.UnknownResource(a.Header, *a.Body.(*UnknownResource)); err != nil { 768 t.Fatalf("Builder.UnknownResource(%#v) = %v", a, err) 769 } 770 } 771 } 772 773 if err := b.StartAuthorities(); err != nil { 774 t.Fatal("Builder.StartAuthorities() =", err) 775 } 776 for _, a := range msg.Authorities { 777 if err := b.NSResource(a.Header, *a.Body.(*NSResource)); err != nil { 778 t.Fatalf("Builder.NSResource(%#v) = %v", a, err) 779 } 780 } 781 782 if err := b.StartAdditionals(); err != nil { 783 t.Fatal("Builder.StartAdditionals() =", err) 784 } 785 for _, a := range msg.Additionals { 786 switch a.Body.(type) { 787 case *TXTResource: 788 if err := b.TXTResource(a.Header, *a.Body.(*TXTResource)); err != nil { 789 t.Fatalf("Builder.TXTResource(%#v) = %v", a, err) 790 } 791 case *OPTResource: 792 if err := b.OPTResource(a.Header, *a.Body.(*OPTResource)); err != nil { 793 t.Fatalf("Builder.OPTResource(%#v) = %v", a, err) 794 } 795 } 796 } 797 798 got, err := b.Finish() 799 if err != nil { 800 t.Fatal("Builder.Finish() =", err) 801 } 802 if !bytes.Equal(got, want) { 803 t.Fatalf("got from Builder.Finish() = %#v\nwant = %#v", got, want) 804 } 805 } 806 807 func TestResourcePack(t *testing.T) { 808 for _, tt := range []struct { 809 m Message 810 err error 811 }{ 812 { 813 Message{ 814 Questions: []Question{ 815 { 816 Name: MustNewName("."), 817 Type: TypeAAAA, 818 Class: ClassINET, 819 }, 820 }, 821 Answers: []Resource{{ResourceHeader{}, nil}}, 822 }, 823 &nestedError{"packing Answer", errNilResouceBody}, 824 }, 825 { 826 Message{ 827 Questions: []Question{ 828 { 829 Name: MustNewName("."), 830 Type: TypeAAAA, 831 Class: ClassINET, 832 }, 833 }, 834 Authorities: []Resource{{ResourceHeader{}, (*NSResource)(nil)}}, 835 }, 836 &nestedError{"packing Authority", 837 &nestedError{"ResourceHeader", 838 &nestedError{"Name", errNonCanonicalName}, 839 }, 840 }, 841 }, 842 { 843 Message{ 844 Questions: []Question{ 845 { 846 Name: MustNewName("."), 847 Type: TypeA, 848 Class: ClassINET, 849 }, 850 }, 851 Additionals: []Resource{{ResourceHeader{}, nil}}, 852 }, 853 &nestedError{"packing Additional", errNilResouceBody}, 854 }, 855 } { 856 _, err := tt.m.Pack() 857 if !reflect.DeepEqual(err, tt.err) { 858 t.Errorf("got Message{%v}.Pack() = %v, want %v", tt.m, err, tt.err) 859 } 860 } 861 } 862 863 func TestResourcePackLength(t *testing.T) { 864 r := Resource{ 865 ResourceHeader{ 866 Name: MustNewName("."), 867 Type: TypeA, 868 Class: ClassINET, 869 }, 870 &AResource{[4]byte{127, 0, 0, 2}}, 871 } 872 873 hb, _, err := r.Header.pack(nil, nil, 0) 874 if err != nil { 875 t.Fatal("ResourceHeader.pack() =", err) 876 } 877 buf := make([]byte, 0, len(hb)) 878 buf, err = r.pack(buf, nil, 0) 879 if err != nil { 880 t.Fatal("Resource.pack() =", err) 881 } 882 883 var hdr ResourceHeader 884 if _, err := hdr.unpack(buf, 0); err != nil { 885 t.Fatal("ResourceHeader.unpack() =", err) 886 } 887 888 if got, want := int(hdr.Length), len(buf)-len(hb); got != want { 889 t.Errorf("got hdr.Length = %d, want = %d", got, want) 890 } 891 } 892 893 func TestOptionPackUnpack(t *testing.T) { 894 for _, tt := range []struct { 895 name string 896 w []byte // wire format of m.Additionals 897 m Message 898 dnssecOK bool 899 extRCode RCode 900 }{ 901 { 902 name: "without EDNS(0) options", 903 w: []byte{ 904 0x00, 0x00, 0x29, 0x10, 0x00, 0xfe, 0x00, 0x80, 905 0x00, 0x00, 0x00, 906 }, 907 m: Message{ 908 Header: Header{RCode: RCodeFormatError}, 909 Questions: []Question{ 910 { 911 Name: MustNewName("."), 912 Type: TypeA, 913 Class: ClassINET, 914 }, 915 }, 916 Additionals: []Resource{ 917 { 918 mustEDNS0ResourceHeader(4096, 0xfe0|RCodeFormatError, true), 919 &OPTResource{}, 920 }, 921 }, 922 }, 923 dnssecOK: true, 924 extRCode: 0xfe0 | RCodeFormatError, 925 }, 926 { 927 name: "with EDNS(0) options", 928 w: []byte{ 929 0x00, 0x00, 0x29, 0x10, 0x00, 0xff, 0x00, 0x00, 930 0x00, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x02, 0x00, 931 0x00, 0x00, 0x0b, 0x00, 0x02, 0x12, 0x34, 932 }, 933 m: Message{ 934 Header: Header{RCode: RCodeServerFailure}, 935 Questions: []Question{ 936 { 937 Name: MustNewName("."), 938 Type: TypeAAAA, 939 Class: ClassINET, 940 }, 941 }, 942 Additionals: []Resource{ 943 { 944 mustEDNS0ResourceHeader(4096, 0xff0|RCodeServerFailure, false), 945 &OPTResource{ 946 Options: []Option{ 947 { 948 Code: 12, // see RFC 7828 949 Data: []byte{0x00, 0x00}, 950 }, 951 { 952 Code: 11, // see RFC 7830 953 Data: []byte{0x12, 0x34}, 954 }, 955 }, 956 }, 957 }, 958 }, 959 }, 960 dnssecOK: false, 961 extRCode: 0xff0 | RCodeServerFailure, 962 }, 963 { 964 // Containing multiple OPT resources in a 965 // message is invalid, but it's necessary for 966 // protocol conformance testing. 967 name: "with multiple OPT resources", 968 w: []byte{ 969 0x00, 0x00, 0x29, 0x10, 0x00, 0xff, 0x00, 0x00, 970 0x00, 0x00, 0x06, 0x00, 0x0b, 0x00, 0x02, 0x12, 971 0x34, 0x00, 0x00, 0x29, 0x10, 0x00, 0xff, 0x00, 972 0x00, 0x00, 0x00, 0x06, 0x00, 0x0c, 0x00, 0x02, 973 0x00, 0x00, 974 }, 975 m: Message{ 976 Header: Header{RCode: RCodeNameError}, 977 Questions: []Question{ 978 { 979 Name: MustNewName("."), 980 Type: TypeAAAA, 981 Class: ClassINET, 982 }, 983 }, 984 Additionals: []Resource{ 985 { 986 mustEDNS0ResourceHeader(4096, 0xff0|RCodeNameError, false), 987 &OPTResource{ 988 Options: []Option{ 989 { 990 Code: 11, // see RFC 7830 991 Data: []byte{0x12, 0x34}, 992 }, 993 }, 994 }, 995 }, 996 { 997 mustEDNS0ResourceHeader(4096, 0xff0|RCodeNameError, false), 998 &OPTResource{ 999 Options: []Option{ 1000 { 1001 Code: 12, // see RFC 7828 1002 Data: []byte{0x00, 0x00}, 1003 }, 1004 }, 1005 }, 1006 }, 1007 }, 1008 }, 1009 }, 1010 } { 1011 w, err := tt.m.Pack() 1012 if err != nil { 1013 t.Errorf("Message.Pack() for %s = %v", tt.name, err) 1014 continue 1015 } 1016 if !bytes.Equal(w[len(w)-len(tt.w):], tt.w) { 1017 t.Errorf("got Message.Pack() for %s = %#v, want %#v", tt.name, w[len(w)-len(tt.w):], tt.w) 1018 continue 1019 } 1020 var m Message 1021 if err := m.Unpack(w); err != nil { 1022 t.Errorf("Message.Unpack() for %s = %v", tt.name, err) 1023 continue 1024 } 1025 if !reflect.DeepEqual(m.Additionals, tt.m.Additionals) { 1026 t.Errorf("got Message.Pack/Unpack() roundtrip for %s = %+v, want %+v", tt.name, m, tt.m) 1027 continue 1028 } 1029 } 1030 } 1031 1032 func smallTestMsgWithUnknownResource() Message { 1033 return Message{ 1034 Questions: []Question{}, 1035 Answers: []Resource{ 1036 { 1037 Header: ResourceHeader{ 1038 Name: MustNewName("."), 1039 Type: privateUseType, 1040 Class: ClassINET, 1041 TTL: uint32(123), 1042 }, 1043 Body: &UnknownResource{ 1044 // The realType() method is called, when 1045 // packing, so Type must match the type 1046 // claimed by the Header above. 1047 Type: privateUseType, 1048 Data: []byte{42, 42, 42, 42}, 1049 }, 1050 }, 1051 }, 1052 } 1053 } 1054 1055 func TestUnknownPackUnpack(t *testing.T) { 1056 msg := smallTestMsgWithUnknownResource() 1057 packed, err := msg.Pack() 1058 if err != nil { 1059 t.Fatalf("Failed to pack UnknownResource: %v", err) 1060 } 1061 1062 var receivedMsg Message 1063 err = receivedMsg.Unpack(packed) 1064 if err != nil { 1065 t.Fatalf("Failed to unpack UnknownResource: %v", err) 1066 } 1067 1068 if len(receivedMsg.Answers) != 1 { 1069 t.Fatalf("Got %d answers, wanted 1", len(receivedMsg.Answers)) 1070 } 1071 1072 unknownResource, ok := receivedMsg.Answers[0].Body.(*UnknownResource) 1073 if !ok { 1074 t.Fatalf("Parsed a %T, wanted an UnknownResource", receivedMsg.Answers[0].Body) 1075 } 1076 1077 wantBody := msg.Answers[0].Body 1078 if !reflect.DeepEqual(wantBody, unknownResource) { 1079 t.Fatalf("Unpacked resource does not match: %v vs %v", wantBody, unknownResource) 1080 } 1081 } 1082 1083 func TestParseUnknownResource(t *testing.T) { 1084 msg := smallTestMsgWithUnknownResource() 1085 packed, err := msg.Pack() 1086 if err != nil { 1087 t.Fatalf("Failed to pack UnknownResource: %v", err) 1088 } 1089 1090 var p Parser 1091 if _, err = p.Start(packed); err != nil { 1092 t.Fatalf("Parser failed to start: %s", err) 1093 } 1094 if _, err = p.AllQuestions(); err != nil { 1095 t.Fatalf("Failed to parse questions: %s", err) 1096 } 1097 1098 parsedHeader, err := p.AnswerHeader() 1099 if err != nil { 1100 t.Fatalf("Error reading answer header: %s", err) 1101 } 1102 wantHeader := msg.Answers[0].Header 1103 if !reflect.DeepEqual(wantHeader, parsedHeader) { 1104 t.Fatalf("Parsed header does not match: %v vs %v", wantHeader, wantHeader) 1105 } 1106 1107 parsedUnknownResource, err := p.UnknownResource() 1108 if err != nil { 1109 t.Fatalf("Failed to parse UnknownResource: %s", err) 1110 } 1111 wantBody := msg.Answers[0].Body 1112 if !reflect.DeepEqual(wantBody, &parsedUnknownResource) { 1113 t.Fatalf("Parsed resource does not match: %v vs %v", wantBody, &parsedUnknownResource) 1114 } 1115 1116 // Finish parsing the rest of the message to ensure that 1117 // (*Parser).UnknownResource() leaves the parser in a consistent state. 1118 if _, err = p.AnswerHeader(); err != ErrSectionDone { 1119 t.Fatalf("Answer section should be fully parsed") 1120 } 1121 if _, err = p.AllAuthorities(); err != nil { 1122 t.Fatalf("Failed to parse authorities: %s", err) 1123 } 1124 if _, err = p.AllAdditionals(); err != nil { 1125 t.Fatalf("Failed to parse additionals: %s", err) 1126 } 1127 } 1128 1129 // TestGoString tests that Message.GoString produces Go code that compiles to 1130 // reproduce the Message. 1131 // 1132 // This test was produced as follows: 1133 // 1. Run (*Message).GoString on largeTestMsg(). 1134 // 2. Remove "dnsmessage." from the output. 1135 // 3. Paste the result in the test to store it in msg. 1136 // 4. Also put the original output in the test to store in want. 1137 func TestGoString(t *testing.T) { 1138 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}}}}}}} 1139 1140 if !reflect.DeepEqual(msg, largeTestMsg()) { 1141 t.Error("Message.GoString lost information or largeTestMsg changed: msg != largeTestMsg()") 1142 } 1143 got := msg.GoString() 1144 1145 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.")}}, 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}}}}}}}` 1146 1147 if got != want { 1148 t.Errorf("got msg1.GoString() = %s\nwant = %s", got, want) 1149 } 1150 } 1151 1152 func benchmarkParsingSetup() ([]byte, error) { 1153 name := MustNewName("foo.bar.example.com.") 1154 msg := Message{ 1155 Header: Header{Response: true, Authoritative: true}, 1156 Questions: []Question{ 1157 { 1158 Name: name, 1159 Type: TypeA, 1160 Class: ClassINET, 1161 }, 1162 }, 1163 Answers: []Resource{ 1164 { 1165 ResourceHeader{ 1166 Name: name, 1167 Class: ClassINET, 1168 }, 1169 &AResource{[4]byte{}}, 1170 }, 1171 { 1172 ResourceHeader{ 1173 Name: name, 1174 Class: ClassINET, 1175 }, 1176 &AAAAResource{[16]byte{}}, 1177 }, 1178 { 1179 ResourceHeader{ 1180 Name: name, 1181 Class: ClassINET, 1182 }, 1183 &CNAMEResource{name}, 1184 }, 1185 { 1186 ResourceHeader{ 1187 Name: name, 1188 Class: ClassINET, 1189 }, 1190 &NSResource{name}, 1191 }, 1192 }, 1193 } 1194 1195 buf, err := msg.Pack() 1196 if err != nil { 1197 return nil, fmt.Errorf("Message.Pack() = %v", err) 1198 } 1199 return buf, nil 1200 } 1201 1202 func benchmarkParsing(tb testing.TB, buf []byte) { 1203 var p Parser 1204 if _, err := p.Start(buf); err != nil { 1205 tb.Fatal("Parser.Start(non-nil) =", err) 1206 } 1207 1208 for { 1209 _, err := p.Question() 1210 if err == ErrSectionDone { 1211 break 1212 } 1213 if err != nil { 1214 tb.Fatal("Parser.Question() =", err) 1215 } 1216 } 1217 1218 for { 1219 h, err := p.AnswerHeader() 1220 if err == ErrSectionDone { 1221 break 1222 } 1223 if err != nil { 1224 tb.Fatal("Parser.AnswerHeader() =", err) 1225 } 1226 1227 switch h.Type { 1228 case TypeA: 1229 if _, err := p.AResource(); err != nil { 1230 tb.Fatal("Parser.AResource() =", err) 1231 } 1232 case TypeAAAA: 1233 if _, err := p.AAAAResource(); err != nil { 1234 tb.Fatal("Parser.AAAAResource() =", err) 1235 } 1236 case TypeCNAME: 1237 if _, err := p.CNAMEResource(); err != nil { 1238 tb.Fatal("Parser.CNAMEResource() =", err) 1239 } 1240 case TypeNS: 1241 if _, err := p.NSResource(); err != nil { 1242 tb.Fatal("Parser.NSResource() =", err) 1243 } 1244 case TypeOPT: 1245 if _, err := p.OPTResource(); err != nil { 1246 tb.Fatal("Parser.OPTResource() =", err) 1247 } 1248 default: 1249 tb.Fatalf("got unknown type: %T", h) 1250 } 1251 } 1252 } 1253 1254 func BenchmarkParsing(b *testing.B) { 1255 buf, err := benchmarkParsingSetup() 1256 if err != nil { 1257 b.Fatal(err) 1258 } 1259 1260 b.ReportAllocs() 1261 for i := 0; i < b.N; i++ { 1262 benchmarkParsing(b, buf) 1263 } 1264 } 1265 1266 func TestParsingAllocs(t *testing.T) { 1267 buf, err := benchmarkParsingSetup() 1268 if err != nil { 1269 t.Fatal(err) 1270 } 1271 1272 if allocs := testing.AllocsPerRun(100, func() { benchmarkParsing(t, buf) }); allocs > 0.5 { 1273 t.Errorf("allocations during parsing: got = %f, want ~0", allocs) 1274 } 1275 } 1276 1277 func benchmarkBuildingSetup() (Name, []byte) { 1278 name := MustNewName("foo.bar.example.com.") 1279 buf := make([]byte, 0, packStartingCap) 1280 return name, buf 1281 } 1282 1283 func benchmarkBuilding(tb testing.TB, name Name, buf []byte) { 1284 bld := NewBuilder(buf, Header{Response: true, Authoritative: true}) 1285 1286 if err := bld.StartQuestions(); err != nil { 1287 tb.Fatal("Builder.StartQuestions() =", err) 1288 } 1289 q := Question{ 1290 Name: name, 1291 Type: TypeA, 1292 Class: ClassINET, 1293 } 1294 if err := bld.Question(q); err != nil { 1295 tb.Fatalf("Builder.Question(%+v) = %v", q, err) 1296 } 1297 1298 hdr := ResourceHeader{ 1299 Name: name, 1300 Class: ClassINET, 1301 } 1302 if err := bld.StartAnswers(); err != nil { 1303 tb.Fatal("Builder.StartQuestions() =", err) 1304 } 1305 1306 ar := AResource{[4]byte{}} 1307 if err := bld.AResource(hdr, ar); err != nil { 1308 tb.Fatalf("Builder.AResource(%+v, %+v) = %v", hdr, ar, err) 1309 } 1310 1311 aaar := AAAAResource{[16]byte{}} 1312 if err := bld.AAAAResource(hdr, aaar); err != nil { 1313 tb.Fatalf("Builder.AAAAResource(%+v, %+v) = %v", hdr, aaar, err) 1314 } 1315 1316 cnr := CNAMEResource{name} 1317 if err := bld.CNAMEResource(hdr, cnr); err != nil { 1318 tb.Fatalf("Builder.CNAMEResource(%+v, %+v) = %v", hdr, cnr, err) 1319 } 1320 1321 nsr := NSResource{name} 1322 if err := bld.NSResource(hdr, nsr); err != nil { 1323 tb.Fatalf("Builder.NSResource(%+v, %+v) = %v", hdr, nsr, err) 1324 } 1325 1326 extrc := 0xfe0 | RCodeNotImplemented 1327 if err := (&hdr).SetEDNS0(4096, extrc, true); err != nil { 1328 tb.Fatalf("ResourceHeader.SetEDNS0(4096, %#x, true) = %v", extrc, err) 1329 } 1330 optr := OPTResource{} 1331 if err := bld.OPTResource(hdr, optr); err != nil { 1332 tb.Fatalf("Builder.OPTResource(%+v, %+v) = %v", hdr, optr, err) 1333 } 1334 1335 if _, err := bld.Finish(); err != nil { 1336 tb.Fatal("Builder.Finish() =", err) 1337 } 1338 } 1339 1340 func BenchmarkBuilding(b *testing.B) { 1341 name, buf := benchmarkBuildingSetup() 1342 b.ReportAllocs() 1343 for i := 0; i < b.N; i++ { 1344 benchmarkBuilding(b, name, buf) 1345 } 1346 } 1347 1348 func TestBuildingAllocs(t *testing.T) { 1349 name, buf := benchmarkBuildingSetup() 1350 if allocs := testing.AllocsPerRun(100, func() { benchmarkBuilding(t, name, buf) }); allocs > 0.5 { 1351 t.Errorf("allocations during building: got = %f, want ~0", allocs) 1352 } 1353 } 1354 1355 func smallTestMsg() Message { 1356 name := MustNewName("example.com.") 1357 return Message{ 1358 Header: Header{Response: true, Authoritative: true}, 1359 Questions: []Question{ 1360 { 1361 Name: name, 1362 Type: TypeA, 1363 Class: ClassINET, 1364 }, 1365 }, 1366 Answers: []Resource{ 1367 { 1368 ResourceHeader{ 1369 Name: name, 1370 Type: TypeA, 1371 Class: ClassINET, 1372 }, 1373 &AResource{[4]byte{127, 0, 0, 1}}, 1374 }, 1375 }, 1376 Authorities: []Resource{ 1377 { 1378 ResourceHeader{ 1379 Name: name, 1380 Type: TypeA, 1381 Class: ClassINET, 1382 }, 1383 &AResource{[4]byte{127, 0, 0, 1}}, 1384 }, 1385 }, 1386 Additionals: []Resource{ 1387 { 1388 ResourceHeader{ 1389 Name: name, 1390 Type: TypeA, 1391 Class: ClassINET, 1392 }, 1393 &AResource{[4]byte{127, 0, 0, 1}}, 1394 }, 1395 }, 1396 } 1397 } 1398 1399 func BenchmarkPack(b *testing.B) { 1400 msg := largeTestMsg() 1401 1402 b.ReportAllocs() 1403 1404 for i := 0; i < b.N; i++ { 1405 if _, err := msg.Pack(); err != nil { 1406 b.Fatal("Message.Pack() =", err) 1407 } 1408 } 1409 } 1410 1411 func BenchmarkAppendPack(b *testing.B) { 1412 msg := largeTestMsg() 1413 buf := make([]byte, 0, packStartingCap) 1414 1415 b.ReportAllocs() 1416 1417 for i := 0; i < b.N; i++ { 1418 if _, err := msg.AppendPack(buf[:0]); err != nil { 1419 b.Fatal("Message.AppendPack() = ", err) 1420 } 1421 } 1422 } 1423 1424 func largeTestMsg() Message { 1425 name := MustNewName("foo.bar.example.com.") 1426 return Message{ 1427 Header: Header{Response: true, Authoritative: true}, 1428 Questions: []Question{ 1429 { 1430 Name: name, 1431 Type: TypeA, 1432 Class: ClassINET, 1433 }, 1434 }, 1435 Answers: []Resource{ 1436 { 1437 ResourceHeader{ 1438 Name: name, 1439 Type: TypeA, 1440 Class: ClassINET, 1441 }, 1442 &AResource{[4]byte{127, 0, 0, 1}}, 1443 }, 1444 { 1445 ResourceHeader{ 1446 Name: name, 1447 Type: TypeA, 1448 Class: ClassINET, 1449 }, 1450 &AResource{[4]byte{127, 0, 0, 2}}, 1451 }, 1452 { 1453 ResourceHeader{ 1454 Name: name, 1455 Type: TypeAAAA, 1456 Class: ClassINET, 1457 }, 1458 &AAAAResource{[16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}}, 1459 }, 1460 { 1461 ResourceHeader{ 1462 Name: name, 1463 Type: TypeCNAME, 1464 Class: ClassINET, 1465 }, 1466 &CNAMEResource{MustNewName("alias.example.com.")}, 1467 }, 1468 { 1469 ResourceHeader{ 1470 Name: name, 1471 Type: TypeSOA, 1472 Class: ClassINET, 1473 }, 1474 &SOAResource{ 1475 NS: MustNewName("ns1.example.com."), 1476 MBox: MustNewName("mb.example.com."), 1477 Serial: 1, 1478 Refresh: 2, 1479 Retry: 3, 1480 Expire: 4, 1481 MinTTL: 5, 1482 }, 1483 }, 1484 { 1485 ResourceHeader{ 1486 Name: name, 1487 Type: TypePTR, 1488 Class: ClassINET, 1489 }, 1490 &PTRResource{MustNewName("ptr.example.com.")}, 1491 }, 1492 { 1493 ResourceHeader{ 1494 Name: name, 1495 Type: TypeMX, 1496 Class: ClassINET, 1497 }, 1498 &MXResource{ 1499 7, 1500 MustNewName("mx.example.com."), 1501 }, 1502 }, 1503 { 1504 ResourceHeader{ 1505 Name: name, 1506 Type: TypeSRV, 1507 Class: ClassINET, 1508 }, 1509 &SRVResource{ 1510 8, 1511 9, 1512 11, 1513 MustNewName("srv.example.com."), 1514 }, 1515 }, 1516 { 1517 ResourceHeader{ 1518 Name: name, 1519 Type: privateUseType, 1520 Class: ClassINET, 1521 }, 1522 &UnknownResource{ 1523 Type: privateUseType, 1524 Data: []byte{42, 0, 43, 44}, 1525 }, 1526 }, 1527 }, 1528 Authorities: []Resource{ 1529 { 1530 ResourceHeader{ 1531 Name: name, 1532 Type: TypeNS, 1533 Class: ClassINET, 1534 }, 1535 &NSResource{MustNewName("ns1.example.com.")}, 1536 }, 1537 { 1538 ResourceHeader{ 1539 Name: name, 1540 Type: TypeNS, 1541 Class: ClassINET, 1542 }, 1543 &NSResource{MustNewName("ns2.example.com.")}, 1544 }, 1545 }, 1546 Additionals: []Resource{ 1547 { 1548 ResourceHeader{ 1549 Name: name, 1550 Type: TypeTXT, 1551 Class: ClassINET, 1552 }, 1553 &TXTResource{[]string{"So Long, and Thanks for All the Fish"}}, 1554 }, 1555 { 1556 ResourceHeader{ 1557 Name: name, 1558 Type: TypeTXT, 1559 Class: ClassINET, 1560 }, 1561 &TXTResource{[]string{"Hamster Huey and the Gooey Kablooie"}}, 1562 }, 1563 { 1564 mustEDNS0ResourceHeader(4096, 0xfe0|RCodeSuccess, false), 1565 &OPTResource{ 1566 Options: []Option{ 1567 { 1568 Code: 10, // see RFC 7873 1569 Data: []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}, 1570 }, 1571 }, 1572 }, 1573 }, 1574 }, 1575 } 1576 } 1577 1578 // This package is imported by the standard library net package 1579 // and therefore must not use fmt. We'll catch a mistake when vendored 1580 // into the standard library, but this test catches the mistake earlier. 1581 func TestNoFmt(t *testing.T) { 1582 files, err := filepath.Glob("*.go") 1583 if err != nil { 1584 t.Fatal(err) 1585 } 1586 for _, file := range files { 1587 if strings.HasSuffix(file, "_test.go") { 1588 continue 1589 } 1590 // Could use something complex like go/build or x/tools/go/packages, 1591 // but there's no reason for "fmt" to appear (in quotes) in the source 1592 // otherwise, so just use a simple substring search. 1593 data, err := ioutil.ReadFile(file) 1594 if err != nil { 1595 t.Fatal(err) 1596 } 1597 if bytes.Contains(data, []byte(`"fmt"`)) { 1598 t.Errorf(`%s: cannot import "fmt"`, file) 1599 } 1600 } 1601 }