golang.org/x/net@v0.25.1-0.20240516223405-c87a5b62e243/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]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}, // 254B name, with ending dot. 241 {in: longDNSPrefix[:255-len(suffix)] + suffix, err: errNameTooLong}, // 255B name, with ending dot. 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 // wire format of m.Additionals 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, // see RFC 7828 971 Data: []byte{0x00, 0x00}, 972 }, 973 { 974 Code: 11, // see RFC 7830 975 Data: []byte{0x12, 0x34}, 976 }, 977 }, 978 }, 979 }, 980 }, 981 }, 982 dnssecOK: false, 983 extRCode: 0xff0 | RCodeServerFailure, 984 }, 985 { 986 // Containing multiple OPT resources in a 987 // message is invalid, but it's necessary for 988 // protocol conformance testing. 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, // see RFC 7830 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, // see RFC 7828 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 // The realType() method is called, when 1067 // packing, so Type must match the type 1068 // claimed by the Header above. 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 // Finish parsing the rest of the message to ensure that 1139 // (*Parser).UnknownResource() leaves the parser in a consistent state. 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 // TestGoString tests that Message.GoString produces Go code that compiles to 1152 // reproduce the Message. 1153 // 1154 // This test was produced as follows: 1155 // 1. Run (*Message).GoString on largeTestMsg(). 1156 // 2. Remove "dnsmessage." from the output. 1157 // 3. Paste the result in the test to store it in msg. 1158 // 4. Also put the original output in the test to store in want. 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, // see RFC 7873 1590 Data: []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}, 1591 }, 1592 }, 1593 }, 1594 }, 1595 }, 1596 } 1597 } 1598 1599 // This package is imported by the standard library net package 1600 // and therefore must not use fmt. We'll catch a mistake when vendored 1601 // into the standard library, but this test catches the mistake earlier. 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 // Could use something complex like go/build or x/tools/go/packages, 1612 // but there's no reason for "fmt" to appear (in quotes) in the source 1613 // otherwise, so just use a simple substring search. 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 successfully 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 // Character that is not part of the name (name.Data[:name.Length]), 1808 // shouldn't affect the compression algorithm. 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, // header 1821 2, 'g', 'o', 3, 'd', 'e', 'v', 0, 0, 0, 0, 0, // question 1 1822 0xC0, 12, 0, 0, 0, 0, // question 2 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, // header 1848 2, 'g', 'o', 3, 'd', 'e', 'v', 0, 0, 0, 0, 0, // question 1 1849 0xC0, 12, 0, 0, 0, 0, // question 2 1850 } 1851 if !bytes.Equal(msg[maxPtr:], expect) { 1852 t.Fatalf("msg[maxPtr:] = %v, want: %v", msg[maxPtr:], expect) 1853 } 1854 }