Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.
 
 
 

1452 wiersze
40 KiB

  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. package dnsmessage
  5. import (
  6. "bytes"
  7. "fmt"
  8. "reflect"
  9. "strings"
  10. "testing"
  11. )
  12. func TestPrintPaddedUint8(t *testing.T) {
  13. tests := []struct {
  14. num uint8
  15. want string
  16. }{
  17. {0, "000"},
  18. {1, "001"},
  19. {9, "009"},
  20. {10, "010"},
  21. {99, "099"},
  22. {100, "100"},
  23. {124, "124"},
  24. {104, "104"},
  25. {120, "120"},
  26. {255, "255"},
  27. }
  28. for _, test := range tests {
  29. if got := printPaddedUint8(test.num); got != test.want {
  30. t.Errorf("got printPaddedUint8(%d) = %s, want = %s", test.num, got, test.want)
  31. }
  32. }
  33. }
  34. func TestPrintUint8Bytes(t *testing.T) {
  35. tests := []uint8{
  36. 0,
  37. 1,
  38. 9,
  39. 10,
  40. 99,
  41. 100,
  42. 124,
  43. 104,
  44. 120,
  45. 255,
  46. }
  47. for _, test := range tests {
  48. if got, want := string(printUint8Bytes(nil, test)), fmt.Sprint(test); got != want {
  49. t.Errorf("got printUint8Bytes(%d) = %s, want = %s", test, got, want)
  50. }
  51. }
  52. }
  53. func TestPrintUint16(t *testing.T) {
  54. tests := []uint16{
  55. 65535,
  56. 0,
  57. 1,
  58. 10,
  59. 100,
  60. 1000,
  61. 10000,
  62. 324,
  63. 304,
  64. 320,
  65. }
  66. for _, test := range tests {
  67. if got, want := printUint16(test), fmt.Sprint(test); got != want {
  68. t.Errorf("got printUint16(%d) = %s, want = %s", test, got, want)
  69. }
  70. }
  71. }
  72. func TestPrintUint32(t *testing.T) {
  73. tests := []uint32{
  74. 4294967295,
  75. 65535,
  76. 0,
  77. 1,
  78. 10,
  79. 100,
  80. 1000,
  81. 10000,
  82. 100000,
  83. 1000000,
  84. 10000000,
  85. 100000000,
  86. 1000000000,
  87. 324,
  88. 304,
  89. 320,
  90. }
  91. for _, test := range tests {
  92. if got, want := printUint32(test), fmt.Sprint(test); got != want {
  93. t.Errorf("got printUint32(%d) = %s, want = %s", test, got, want)
  94. }
  95. }
  96. }
  97. func mustEDNS0ResourceHeader(l int, extrc RCode, do bool) ResourceHeader {
  98. h := ResourceHeader{Class: ClassINET}
  99. if err := h.SetEDNS0(l, extrc, do); err != nil {
  100. panic(err)
  101. }
  102. return h
  103. }
  104. func (m *Message) String() string {
  105. s := fmt.Sprintf("Message: %#v\n", &m.Header)
  106. if len(m.Questions) > 0 {
  107. s += "-- Questions\n"
  108. for _, q := range m.Questions {
  109. s += fmt.Sprintf("%#v\n", q)
  110. }
  111. }
  112. if len(m.Answers) > 0 {
  113. s += "-- Answers\n"
  114. for _, a := range m.Answers {
  115. s += fmt.Sprintf("%#v\n", a)
  116. }
  117. }
  118. if len(m.Authorities) > 0 {
  119. s += "-- Authorities\n"
  120. for _, ns := range m.Authorities {
  121. s += fmt.Sprintf("%#v\n", ns)
  122. }
  123. }
  124. if len(m.Additionals) > 0 {
  125. s += "-- Additionals\n"
  126. for _, e := range m.Additionals {
  127. s += fmt.Sprintf("%#v\n", e)
  128. }
  129. }
  130. return s
  131. }
  132. func TestNameString(t *testing.T) {
  133. want := "foo"
  134. name := MustNewName(want)
  135. if got := fmt.Sprint(name); got != want {
  136. t.Errorf("got fmt.Sprint(%#v) = %s, want = %s", name, got, want)
  137. }
  138. }
  139. func TestQuestionPackUnpack(t *testing.T) {
  140. want := Question{
  141. Name: MustNewName("."),
  142. Type: TypeA,
  143. Class: ClassINET,
  144. }
  145. buf, err := want.pack(make([]byte, 1, 50), map[string]int{}, 1)
  146. if err != nil {
  147. t.Fatal("Question.pack() =", err)
  148. }
  149. var p Parser
  150. p.msg = buf
  151. p.header.questions = 1
  152. p.section = sectionQuestions
  153. p.off = 1
  154. got, err := p.Question()
  155. if err != nil {
  156. t.Fatalf("Parser{%q}.Question() = %v", string(buf[1:]), err)
  157. }
  158. if p.off != len(buf) {
  159. t.Errorf("unpacked different amount than packed: got = %d, want = %d", p.off, len(buf))
  160. }
  161. if !reflect.DeepEqual(got, want) {
  162. t.Errorf("got from Parser.Question() = %+v, want = %+v", got, want)
  163. }
  164. }
  165. func TestName(t *testing.T) {
  166. tests := []string{
  167. "",
  168. ".",
  169. "google..com",
  170. "google.com",
  171. "google..com.",
  172. "google.com.",
  173. ".google.com.",
  174. "www..google.com.",
  175. "www.google.com.",
  176. }
  177. for _, test := range tests {
  178. n, err := NewName(test)
  179. if err != nil {
  180. t.Errorf("NewName(%q) = %v", test, err)
  181. continue
  182. }
  183. if ns := n.String(); ns != test {
  184. t.Errorf("got %#v.String() = %q, want = %q", n, ns, test)
  185. continue
  186. }
  187. }
  188. }
  189. func TestNamePackUnpack(t *testing.T) {
  190. tests := []struct {
  191. in string
  192. want string
  193. err error
  194. }{
  195. {"", "", errNonCanonicalName},
  196. {".", ".", nil},
  197. {"google..com", "", errNonCanonicalName},
  198. {"google.com", "", errNonCanonicalName},
  199. {"google..com.", "", errZeroSegLen},
  200. {"google.com.", "google.com.", nil},
  201. {".google.com.", "", errZeroSegLen},
  202. {"www..google.com.", "", errZeroSegLen},
  203. {"www.google.com.", "www.google.com.", nil},
  204. }
  205. for _, test := range tests {
  206. in := MustNewName(test.in)
  207. want := MustNewName(test.want)
  208. buf, err := in.pack(make([]byte, 0, 30), map[string]int{}, 0)
  209. if err != test.err {
  210. t.Errorf("got %q.pack() = %v, want = %v", test.in, err, test.err)
  211. continue
  212. }
  213. if test.err != nil {
  214. continue
  215. }
  216. var got Name
  217. n, err := got.unpack(buf, 0)
  218. if err != nil {
  219. t.Errorf("%q.unpack() = %v", test.in, err)
  220. continue
  221. }
  222. if n != len(buf) {
  223. t.Errorf(
  224. "unpacked different amount than packed for %q: got = %d, want = %d",
  225. test.in,
  226. n,
  227. len(buf),
  228. )
  229. }
  230. if got != want {
  231. t.Errorf("unpacking packing of %q: got = %#v, want = %#v", test.in, got, want)
  232. }
  233. }
  234. }
  235. func TestIncompressibleName(t *testing.T) {
  236. name := MustNewName("example.com.")
  237. compression := map[string]int{}
  238. buf, err := name.pack(make([]byte, 0, 100), compression, 0)
  239. if err != nil {
  240. t.Fatal("first Name.pack() =", err)
  241. }
  242. buf, err = name.pack(buf, compression, 0)
  243. if err != nil {
  244. t.Fatal("second Name.pack() =", err)
  245. }
  246. var n1 Name
  247. off, err := n1.unpackCompressed(buf, 0, false /* allowCompression */)
  248. if err != nil {
  249. t.Fatal("unpacking incompressible name without pointers failed:", err)
  250. }
  251. var n2 Name
  252. if _, err := n2.unpackCompressed(buf, off, false /* allowCompression */); err != errCompressedSRV {
  253. t.Errorf("unpacking compressed incompressible name with pointers: got %v, want = %v", err, errCompressedSRV)
  254. }
  255. }
  256. func checkErrorPrefix(err error, prefix string) bool {
  257. e, ok := err.(*nestedError)
  258. return ok && e.s == prefix
  259. }
  260. func TestHeaderUnpackError(t *testing.T) {
  261. wants := []string{
  262. "id",
  263. "bits",
  264. "questions",
  265. "answers",
  266. "authorities",
  267. "additionals",
  268. }
  269. var buf []byte
  270. var h header
  271. for _, want := range wants {
  272. n, err := h.unpack(buf, 0)
  273. if n != 0 || !checkErrorPrefix(err, want) {
  274. t.Errorf("got header.unpack([%d]byte, 0) = %d, %v, want = 0, %s", len(buf), n, err, want)
  275. }
  276. buf = append(buf, 0, 0)
  277. }
  278. }
  279. func TestParserStart(t *testing.T) {
  280. const want = "unpacking header"
  281. var p Parser
  282. for i := 0; i <= 1; i++ {
  283. _, err := p.Start([]byte{})
  284. if !checkErrorPrefix(err, want) {
  285. t.Errorf("got Parser.Start(nil) = _, %v, want = _, %s", err, want)
  286. }
  287. }
  288. }
  289. func TestResourceNotStarted(t *testing.T) {
  290. tests := []struct {
  291. name string
  292. fn func(*Parser) error
  293. }{
  294. {"CNAMEResource", func(p *Parser) error { _, err := p.CNAMEResource(); return err }},
  295. {"MXResource", func(p *Parser) error { _, err := p.MXResource(); return err }},
  296. {"NSResource", func(p *Parser) error { _, err := p.NSResource(); return err }},
  297. {"PTRResource", func(p *Parser) error { _, err := p.PTRResource(); return err }},
  298. {"SOAResource", func(p *Parser) error { _, err := p.SOAResource(); return err }},
  299. {"TXTResource", func(p *Parser) error { _, err := p.TXTResource(); return err }},
  300. {"SRVResource", func(p *Parser) error { _, err := p.SRVResource(); return err }},
  301. {"AResource", func(p *Parser) error { _, err := p.AResource(); return err }},
  302. {"AAAAResource", func(p *Parser) error { _, err := p.AAAAResource(); return err }},
  303. }
  304. for _, test := range tests {
  305. if err := test.fn(&Parser{}); err != ErrNotStarted {
  306. t.Errorf("got Parser.%s() = _ , %v, want = _, %v", test.name, err, ErrNotStarted)
  307. }
  308. }
  309. }
  310. func TestDNSPackUnpack(t *testing.T) {
  311. wants := []Message{
  312. {
  313. Questions: []Question{
  314. {
  315. Name: MustNewName("."),
  316. Type: TypeAAAA,
  317. Class: ClassINET,
  318. },
  319. },
  320. Answers: []Resource{},
  321. Authorities: []Resource{},
  322. Additionals: []Resource{},
  323. },
  324. largeTestMsg(),
  325. }
  326. for i, want := range wants {
  327. b, err := want.Pack()
  328. if err != nil {
  329. t.Fatalf("%d: Message.Pack() = %v", i, err)
  330. }
  331. var got Message
  332. err = got.Unpack(b)
  333. if err != nil {
  334. t.Fatalf("%d: Message.Unapck() = %v", i, err)
  335. }
  336. if !reflect.DeepEqual(got, want) {
  337. t.Errorf("%d: Message.Pack/Unpack() roundtrip: got = %+v, want = %+v", i, &got, &want)
  338. }
  339. }
  340. }
  341. func TestDNSAppendPackUnpack(t *testing.T) {
  342. wants := []Message{
  343. {
  344. Questions: []Question{
  345. {
  346. Name: MustNewName("."),
  347. Type: TypeAAAA,
  348. Class: ClassINET,
  349. },
  350. },
  351. Answers: []Resource{},
  352. Authorities: []Resource{},
  353. Additionals: []Resource{},
  354. },
  355. largeTestMsg(),
  356. }
  357. for i, want := range wants {
  358. b := make([]byte, 2, 514)
  359. b, err := want.AppendPack(b)
  360. if err != nil {
  361. t.Fatalf("%d: Message.AppendPack() = %v", i, err)
  362. }
  363. b = b[2:]
  364. var got Message
  365. err = got.Unpack(b)
  366. if err != nil {
  367. t.Fatalf("%d: Message.Unapck() = %v", i, err)
  368. }
  369. if !reflect.DeepEqual(got, want) {
  370. t.Errorf("%d: Message.AppendPack/Unpack() roundtrip: got = %+v, want = %+v", i, &got, &want)
  371. }
  372. }
  373. }
  374. func TestSkipAll(t *testing.T) {
  375. msg := largeTestMsg()
  376. buf, err := msg.Pack()
  377. if err != nil {
  378. t.Fatal("Message.Pack() =", err)
  379. }
  380. var p Parser
  381. if _, err := p.Start(buf); err != nil {
  382. t.Fatal("Parser.Start(non-nil) =", err)
  383. }
  384. tests := []struct {
  385. name string
  386. f func() error
  387. }{
  388. {"SkipAllQuestions", p.SkipAllQuestions},
  389. {"SkipAllAnswers", p.SkipAllAnswers},
  390. {"SkipAllAuthorities", p.SkipAllAuthorities},
  391. {"SkipAllAdditionals", p.SkipAllAdditionals},
  392. }
  393. for _, test := range tests {
  394. for i := 1; i <= 3; i++ {
  395. if err := test.f(); err != nil {
  396. t.Errorf("%d: Parser.%s() = %v", i, test.name, err)
  397. }
  398. }
  399. }
  400. }
  401. func TestSkipEach(t *testing.T) {
  402. msg := smallTestMsg()
  403. buf, err := msg.Pack()
  404. if err != nil {
  405. t.Fatal("Message.Pack() =", err)
  406. }
  407. var p Parser
  408. if _, err := p.Start(buf); err != nil {
  409. t.Fatal("Parser.Start(non-nil) =", err)
  410. }
  411. tests := []struct {
  412. name string
  413. f func() error
  414. }{
  415. {"SkipQuestion", p.SkipQuestion},
  416. {"SkipAnswer", p.SkipAnswer},
  417. {"SkipAuthority", p.SkipAuthority},
  418. {"SkipAdditional", p.SkipAdditional},
  419. }
  420. for _, test := range tests {
  421. if err := test.f(); err != nil {
  422. t.Errorf("first Parser.%s() = %v, want = nil", test.name, err)
  423. }
  424. if err := test.f(); err != ErrSectionDone {
  425. t.Errorf("second Parser.%s() = %v, want = %v", test.name, err, ErrSectionDone)
  426. }
  427. }
  428. }
  429. func TestSkipAfterRead(t *testing.T) {
  430. msg := smallTestMsg()
  431. buf, err := msg.Pack()
  432. if err != nil {
  433. t.Fatal("Message.Pack() =", err)
  434. }
  435. var p Parser
  436. if _, err := p.Start(buf); err != nil {
  437. t.Fatal("Parser.Srart(non-nil) =", err)
  438. }
  439. tests := []struct {
  440. name string
  441. skip func() error
  442. read func() error
  443. }{
  444. {"Question", p.SkipQuestion, func() error { _, err := p.Question(); return err }},
  445. {"Answer", p.SkipAnswer, func() error { _, err := p.Answer(); return err }},
  446. {"Authority", p.SkipAuthority, func() error { _, err := p.Authority(); return err }},
  447. {"Additional", p.SkipAdditional, func() error { _, err := p.Additional(); return err }},
  448. }
  449. for _, test := range tests {
  450. if err := test.read(); err != nil {
  451. t.Errorf("got Parser.%s() = _, %v, want = _, nil", test.name, err)
  452. }
  453. if err := test.skip(); err != ErrSectionDone {
  454. t.Errorf("got Parser.Skip%s() = %v, want = %v", test.name, err, ErrSectionDone)
  455. }
  456. }
  457. }
  458. func TestSkipNotStarted(t *testing.T) {
  459. var p Parser
  460. tests := []struct {
  461. name string
  462. f func() error
  463. }{
  464. {"SkipAllQuestions", p.SkipAllQuestions},
  465. {"SkipAllAnswers", p.SkipAllAnswers},
  466. {"SkipAllAuthorities", p.SkipAllAuthorities},
  467. {"SkipAllAdditionals", p.SkipAllAdditionals},
  468. }
  469. for _, test := range tests {
  470. if err := test.f(); err != ErrNotStarted {
  471. t.Errorf("got Parser.%s() = %v, want = %v", test.name, err, ErrNotStarted)
  472. }
  473. }
  474. }
  475. func TestTooManyRecords(t *testing.T) {
  476. const recs = int(^uint16(0)) + 1
  477. tests := []struct {
  478. name string
  479. msg Message
  480. want error
  481. }{
  482. {
  483. "Questions",
  484. Message{
  485. Questions: make([]Question, recs),
  486. },
  487. errTooManyQuestions,
  488. },
  489. {
  490. "Answers",
  491. Message{
  492. Answers: make([]Resource, recs),
  493. },
  494. errTooManyAnswers,
  495. },
  496. {
  497. "Authorities",
  498. Message{
  499. Authorities: make([]Resource, recs),
  500. },
  501. errTooManyAuthorities,
  502. },
  503. {
  504. "Additionals",
  505. Message{
  506. Additionals: make([]Resource, recs),
  507. },
  508. errTooManyAdditionals,
  509. },
  510. }
  511. for _, test := range tests {
  512. if _, got := test.msg.Pack(); got != test.want {
  513. t.Errorf("got Message.Pack() for %d %s = %v, want = %v", recs, test.name, got, test.want)
  514. }
  515. }
  516. }
  517. func TestVeryLongTxt(t *testing.T) {
  518. want := Resource{
  519. ResourceHeader{
  520. Name: MustNewName("foo.bar.example.com."),
  521. Type: TypeTXT,
  522. Class: ClassINET,
  523. },
  524. &TXTResource{[]string{
  525. "",
  526. "",
  527. "foo bar",
  528. "",
  529. "www.example.com",
  530. "www.example.com.",
  531. strings.Repeat(".", 255),
  532. }},
  533. }
  534. buf, err := want.pack(make([]byte, 0, 8000), map[string]int{}, 0)
  535. if err != nil {
  536. t.Fatal("Resource.pack() =", err)
  537. }
  538. var got Resource
  539. off, err := got.Header.unpack(buf, 0)
  540. if err != nil {
  541. t.Fatal("ResourceHeader.unpack() =", err)
  542. }
  543. body, n, err := unpackResourceBody(buf, off, got.Header)
  544. if err != nil {
  545. t.Fatal("unpackResourceBody() =", err)
  546. }
  547. got.Body = body
  548. if n != len(buf) {
  549. t.Errorf("unpacked different amount than packed: got = %d, want = %d", n, len(buf))
  550. }
  551. if !reflect.DeepEqual(got, want) {
  552. t.Errorf("Resource.pack/unpack() roundtrip: got = %#v, want = %#v", got, want)
  553. }
  554. }
  555. func TestTooLongTxt(t *testing.T) {
  556. rb := TXTResource{[]string{strings.Repeat(".", 256)}}
  557. if _, err := rb.pack(make([]byte, 0, 8000), map[string]int{}, 0); err != errStringTooLong {
  558. t.Errorf("packing TXTResource with 256 character string: got err = %v, want = %v", err, errStringTooLong)
  559. }
  560. }
  561. func TestStartAppends(t *testing.T) {
  562. buf := make([]byte, 2, 514)
  563. wantBuf := []byte{4, 44}
  564. copy(buf, wantBuf)
  565. b := NewBuilder(buf, Header{})
  566. b.EnableCompression()
  567. buf, err := b.Finish()
  568. if err != nil {
  569. t.Fatal("Builder.Finish() =", err)
  570. }
  571. if got, want := len(buf), headerLen+2; got != want {
  572. t.Errorf("got len(buf) = %d, want = %d", got, want)
  573. }
  574. if string(buf[:2]) != string(wantBuf) {
  575. t.Errorf("original data not preserved, got = %#v, want = %#v", buf[:2], wantBuf)
  576. }
  577. }
  578. func TestStartError(t *testing.T) {
  579. tests := []struct {
  580. name string
  581. fn func(*Builder) error
  582. }{
  583. {"Questions", func(b *Builder) error { return b.StartQuestions() }},
  584. {"Answers", func(b *Builder) error { return b.StartAnswers() }},
  585. {"Authorities", func(b *Builder) error { return b.StartAuthorities() }},
  586. {"Additionals", func(b *Builder) error { return b.StartAdditionals() }},
  587. }
  588. envs := []struct {
  589. name string
  590. fn func() *Builder
  591. want error
  592. }{
  593. {"sectionNotStarted", func() *Builder { return &Builder{section: sectionNotStarted} }, ErrNotStarted},
  594. {"sectionDone", func() *Builder { return &Builder{section: sectionDone} }, ErrSectionDone},
  595. }
  596. for _, env := range envs {
  597. for _, test := range tests {
  598. if got := test.fn(env.fn()); got != env.want {
  599. t.Errorf("got Builder{%s}.Start%s() = %v, want = %v", env.name, test.name, got, env.want)
  600. }
  601. }
  602. }
  603. }
  604. func TestBuilderResourceError(t *testing.T) {
  605. tests := []struct {
  606. name string
  607. fn func(*Builder) error
  608. }{
  609. {"CNAMEResource", func(b *Builder) error { return b.CNAMEResource(ResourceHeader{}, CNAMEResource{}) }},
  610. {"MXResource", func(b *Builder) error { return b.MXResource(ResourceHeader{}, MXResource{}) }},
  611. {"NSResource", func(b *Builder) error { return b.NSResource(ResourceHeader{}, NSResource{}) }},
  612. {"PTRResource", func(b *Builder) error { return b.PTRResource(ResourceHeader{}, PTRResource{}) }},
  613. {"SOAResource", func(b *Builder) error { return b.SOAResource(ResourceHeader{}, SOAResource{}) }},
  614. {"TXTResource", func(b *Builder) error { return b.TXTResource(ResourceHeader{}, TXTResource{}) }},
  615. {"SRVResource", func(b *Builder) error { return b.SRVResource(ResourceHeader{}, SRVResource{}) }},
  616. {"AResource", func(b *Builder) error { return b.AResource(ResourceHeader{}, AResource{}) }},
  617. {"AAAAResource", func(b *Builder) error { return b.AAAAResource(ResourceHeader{}, AAAAResource{}) }},
  618. {"OPTResource", func(b *Builder) error { return b.OPTResource(ResourceHeader{}, OPTResource{}) }},
  619. }
  620. envs := []struct {
  621. name string
  622. fn func() *Builder
  623. want error
  624. }{
  625. {"sectionNotStarted", func() *Builder { return &Builder{section: sectionNotStarted} }, ErrNotStarted},
  626. {"sectionHeader", func() *Builder { return &Builder{section: sectionHeader} }, ErrNotStarted},
  627. {"sectionQuestions", func() *Builder { return &Builder{section: sectionQuestions} }, ErrNotStarted},
  628. {"sectionDone", func() *Builder { return &Builder{section: sectionDone} }, ErrSectionDone},
  629. }
  630. for _, env := range envs {
  631. for _, test := range tests {
  632. if got := test.fn(env.fn()); got != env.want {
  633. t.Errorf("got Builder{%s}.%s() = %v, want = %v", env.name, test.name, got, env.want)
  634. }
  635. }
  636. }
  637. }
  638. func TestFinishError(t *testing.T) {
  639. var b Builder
  640. want := ErrNotStarted
  641. if _, got := b.Finish(); got != want {
  642. t.Errorf("got Builder.Finish() = %v, want = %v", got, want)
  643. }
  644. }
  645. func TestBuilder(t *testing.T) {
  646. msg := largeTestMsg()
  647. want, err := msg.Pack()
  648. if err != nil {
  649. t.Fatal("Message.Pack() =", err)
  650. }
  651. b := NewBuilder(nil, msg.Header)
  652. b.EnableCompression()
  653. if err := b.StartQuestions(); err != nil {
  654. t.Fatal("Builder.StartQuestions() =", err)
  655. }
  656. for _, q := range msg.Questions {
  657. if err := b.Question(q); err != nil {
  658. t.Fatalf("Builder.Question(%#v) = %v", q, err)
  659. }
  660. }
  661. if err := b.StartAnswers(); err != nil {
  662. t.Fatal("Builder.StartAnswers() =", err)
  663. }
  664. for _, a := range msg.Answers {
  665. switch a.Header.Type {
  666. case TypeA:
  667. if err := b.AResource(a.Header, *a.Body.(*AResource)); err != nil {
  668. t.Fatalf("Builder.AResource(%#v) = %v", a, err)
  669. }
  670. case TypeNS:
  671. if err := b.NSResource(a.Header, *a.Body.(*NSResource)); err != nil {
  672. t.Fatalf("Builder.NSResource(%#v) = %v", a, err)
  673. }
  674. case TypeCNAME:
  675. if err := b.CNAMEResource(a.Header, *a.Body.(*CNAMEResource)); err != nil {
  676. t.Fatalf("Builder.CNAMEResource(%#v) = %v", a, err)
  677. }
  678. case TypeSOA:
  679. if err := b.SOAResource(a.Header, *a.Body.(*SOAResource)); err != nil {
  680. t.Fatalf("Builder.SOAResource(%#v) = %v", a, err)
  681. }
  682. case TypePTR:
  683. if err := b.PTRResource(a.Header, *a.Body.(*PTRResource)); err != nil {
  684. t.Fatalf("Builder.PTRResource(%#v) = %v", a, err)
  685. }
  686. case TypeMX:
  687. if err := b.MXResource(a.Header, *a.Body.(*MXResource)); err != nil {
  688. t.Fatalf("Builder.MXResource(%#v) = %v", a, err)
  689. }
  690. case TypeTXT:
  691. if err := b.TXTResource(a.Header, *a.Body.(*TXTResource)); err != nil {
  692. t.Fatalf("Builder.TXTResource(%#v) = %v", a, err)
  693. }
  694. case TypeAAAA:
  695. if err := b.AAAAResource(a.Header, *a.Body.(*AAAAResource)); err != nil {
  696. t.Fatalf("Builder.AAAAResource(%#v) = %v", a, err)
  697. }
  698. case TypeSRV:
  699. if err := b.SRVResource(a.Header, *a.Body.(*SRVResource)); err != nil {
  700. t.Fatalf("Builder.SRVResource(%#v) = %v", a, err)
  701. }
  702. }
  703. }
  704. if err := b.StartAuthorities(); err != nil {
  705. t.Fatal("Builder.StartAuthorities() =", err)
  706. }
  707. for _, a := range msg.Authorities {
  708. if err := b.NSResource(a.Header, *a.Body.(*NSResource)); err != nil {
  709. t.Fatalf("Builder.NSResource(%#v) = %v", a, err)
  710. }
  711. }
  712. if err := b.StartAdditionals(); err != nil {
  713. t.Fatal("Builder.StartAdditionals() =", err)
  714. }
  715. for _, a := range msg.Additionals {
  716. switch a.Body.(type) {
  717. case *TXTResource:
  718. if err := b.TXTResource(a.Header, *a.Body.(*TXTResource)); err != nil {
  719. t.Fatalf("Builder.TXTResource(%#v) = %v", a, err)
  720. }
  721. case *OPTResource:
  722. if err := b.OPTResource(a.Header, *a.Body.(*OPTResource)); err != nil {
  723. t.Fatalf("Builder.OPTResource(%#v) = %v", a, err)
  724. }
  725. }
  726. }
  727. got, err := b.Finish()
  728. if err != nil {
  729. t.Fatal("Builder.Finish() =", err)
  730. }
  731. if !bytes.Equal(got, want) {
  732. t.Fatalf("got from Builder.Finish() = %#v\nwant = %#v", got, want)
  733. }
  734. }
  735. func TestResourcePack(t *testing.T) {
  736. for _, tt := range []struct {
  737. m Message
  738. err error
  739. }{
  740. {
  741. Message{
  742. Questions: []Question{
  743. {
  744. Name: MustNewName("."),
  745. Type: TypeAAAA,
  746. Class: ClassINET,
  747. },
  748. },
  749. Answers: []Resource{{ResourceHeader{}, nil}},
  750. },
  751. &nestedError{"packing Answer", errNilResouceBody},
  752. },
  753. {
  754. Message{
  755. Questions: []Question{
  756. {
  757. Name: MustNewName("."),
  758. Type: TypeAAAA,
  759. Class: ClassINET,
  760. },
  761. },
  762. Authorities: []Resource{{ResourceHeader{}, (*NSResource)(nil)}},
  763. },
  764. &nestedError{"packing Authority",
  765. &nestedError{"ResourceHeader",
  766. &nestedError{"Name", errNonCanonicalName},
  767. },
  768. },
  769. },
  770. {
  771. Message{
  772. Questions: []Question{
  773. {
  774. Name: MustNewName("."),
  775. Type: TypeA,
  776. Class: ClassINET,
  777. },
  778. },
  779. Additionals: []Resource{{ResourceHeader{}, nil}},
  780. },
  781. &nestedError{"packing Additional", errNilResouceBody},
  782. },
  783. } {
  784. _, err := tt.m.Pack()
  785. if !reflect.DeepEqual(err, tt.err) {
  786. t.Errorf("got Message{%v}.Pack() = %v, want %v", tt.m, err, tt.err)
  787. }
  788. }
  789. }
  790. func TestResourcePackLength(t *testing.T) {
  791. r := Resource{
  792. ResourceHeader{
  793. Name: MustNewName("."),
  794. Type: TypeA,
  795. Class: ClassINET,
  796. },
  797. &AResource{[4]byte{127, 0, 0, 2}},
  798. }
  799. hb, _, err := r.Header.pack(nil, nil, 0)
  800. if err != nil {
  801. t.Fatal("ResourceHeader.pack() =", err)
  802. }
  803. buf := make([]byte, 0, len(hb))
  804. buf, err = r.pack(buf, nil, 0)
  805. if err != nil {
  806. t.Fatal("Resource.pack() =", err)
  807. }
  808. var hdr ResourceHeader
  809. if _, err := hdr.unpack(buf, 0); err != nil {
  810. t.Fatal("ResourceHeader.unpack() =", err)
  811. }
  812. if got, want := int(hdr.Length), len(buf)-len(hb); got != want {
  813. t.Errorf("got hdr.Length = %d, want = %d", got, want)
  814. }
  815. }
  816. func TestOptionPackUnpack(t *testing.T) {
  817. for _, tt := range []struct {
  818. name string
  819. w []byte // wire format of m.Additionals
  820. m Message
  821. dnssecOK bool
  822. extRCode RCode
  823. }{
  824. {
  825. name: "without EDNS(0) options",
  826. w: []byte{
  827. 0x00, 0x00, 0x29, 0x10, 0x00, 0xfe, 0x00, 0x80,
  828. 0x00, 0x00, 0x00,
  829. },
  830. m: Message{
  831. Header: Header{RCode: RCodeFormatError},
  832. Questions: []Question{
  833. {
  834. Name: MustNewName("."),
  835. Type: TypeA,
  836. Class: ClassINET,
  837. },
  838. },
  839. Additionals: []Resource{
  840. {
  841. mustEDNS0ResourceHeader(4096, 0xfe0|RCodeFormatError, true),
  842. &OPTResource{},
  843. },
  844. },
  845. },
  846. dnssecOK: true,
  847. extRCode: 0xfe0 | RCodeFormatError,
  848. },
  849. {
  850. name: "with EDNS(0) options",
  851. w: []byte{
  852. 0x00, 0x00, 0x29, 0x10, 0x00, 0xff, 0x00, 0x00,
  853. 0x00, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x02, 0x00,
  854. 0x00, 0x00, 0x0b, 0x00, 0x02, 0x12, 0x34,
  855. },
  856. m: Message{
  857. Header: Header{RCode: RCodeServerFailure},
  858. Questions: []Question{
  859. {
  860. Name: MustNewName("."),
  861. Type: TypeAAAA,
  862. Class: ClassINET,
  863. },
  864. },
  865. Additionals: []Resource{
  866. {
  867. mustEDNS0ResourceHeader(4096, 0xff0|RCodeServerFailure, false),
  868. &OPTResource{
  869. Options: []Option{
  870. {
  871. Code: 12, // see RFC 7828
  872. Data: []byte{0x00, 0x00},
  873. },
  874. {
  875. Code: 11, // see RFC 7830
  876. Data: []byte{0x12, 0x34},
  877. },
  878. },
  879. },
  880. },
  881. },
  882. },
  883. dnssecOK: false,
  884. extRCode: 0xff0 | RCodeServerFailure,
  885. },
  886. {
  887. // Containing multiple OPT resources in a
  888. // message is invalid, but it's necessary for
  889. // protocol conformance testing.
  890. name: "with multiple OPT resources",
  891. w: []byte{
  892. 0x00, 0x00, 0x29, 0x10, 0x00, 0xff, 0x00, 0x00,
  893. 0x00, 0x00, 0x06, 0x00, 0x0b, 0x00, 0x02, 0x12,
  894. 0x34, 0x00, 0x00, 0x29, 0x10, 0x00, 0xff, 0x00,
  895. 0x00, 0x00, 0x00, 0x06, 0x00, 0x0c, 0x00, 0x02,
  896. 0x00, 0x00,
  897. },
  898. m: Message{
  899. Header: Header{RCode: RCodeNameError},
  900. Questions: []Question{
  901. {
  902. Name: MustNewName("."),
  903. Type: TypeAAAA,
  904. Class: ClassINET,
  905. },
  906. },
  907. Additionals: []Resource{
  908. {
  909. mustEDNS0ResourceHeader(4096, 0xff0|RCodeNameError, false),
  910. &OPTResource{
  911. Options: []Option{
  912. {
  913. Code: 11, // see RFC 7830
  914. Data: []byte{0x12, 0x34},
  915. },
  916. },
  917. },
  918. },
  919. {
  920. mustEDNS0ResourceHeader(4096, 0xff0|RCodeNameError, false),
  921. &OPTResource{
  922. Options: []Option{
  923. {
  924. Code: 12, // see RFC 7828
  925. Data: []byte{0x00, 0x00},
  926. },
  927. },
  928. },
  929. },
  930. },
  931. },
  932. },
  933. } {
  934. w, err := tt.m.Pack()
  935. if err != nil {
  936. t.Errorf("Message.Pack() for %s = %v", tt.name, err)
  937. continue
  938. }
  939. if !bytes.Equal(w[len(w)-len(tt.w):], tt.w) {
  940. t.Errorf("got Message.Pack() for %s = %#v, want %#v", tt.name, w[len(w)-len(tt.w):], tt.w)
  941. continue
  942. }
  943. var m Message
  944. if err := m.Unpack(w); err != nil {
  945. t.Errorf("Message.Unpack() for %s = %v", tt.name, err)
  946. continue
  947. }
  948. if !reflect.DeepEqual(m.Additionals, tt.m.Additionals) {
  949. t.Errorf("got Message.Pack/Unpack() roundtrip for %s = %+v, want %+v", tt.name, m, tt.m)
  950. continue
  951. }
  952. }
  953. }
  954. // TestGoString tests that Message.GoString produces Go code that compiles to
  955. // reproduce the Message.
  956. //
  957. // This test was produced as follows:
  958. // 1. Run (*Message).GoString on largeTestMsg().
  959. // 2. Remove "dnsmessage." from the output.
  960. // 3. Paste the result in the test to store it in msg.
  961. // 4. Also put the original output in the test to store in want.
  962. func TestGoString(t *testing.T) {
  963. msg := Message{Header: Header{ID: 0, Response: true, OpCode: 0, Authoritative: true, Truncated: false, RecursionDesired: false, RecursionAvailable: false, RCode: RCodeSuccess}, Questions: []Question{{Name: MustNewName("foo.bar.example.com."), Type: TypeA, Class: ClassINET}}, Answers: []Resource{{Header: ResourceHeader{Name: MustNewName("foo.bar.example.com."), Type: TypeA, Class: ClassINET, TTL: 0, Length: 0}, Body: &AResource{A: [4]byte{127, 0, 0, 1}}}, {Header: ResourceHeader{Name: MustNewName("foo.bar.example.com."), Type: TypeA, Class: ClassINET, TTL: 0, Length: 0}, Body: &AResource{A: [4]byte{127, 0, 0, 2}}}, {Header: ResourceHeader{Name: MustNewName("foo.bar.example.com."), Type: TypeAAAA, Class: ClassINET, TTL: 0, Length: 0}, Body: &AAAAResource{AAAA: [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}}}, {Header: ResourceHeader{Name: MustNewName("foo.bar.example.com."), Type: TypeCNAME, Class: ClassINET, TTL: 0, Length: 0}, Body: &CNAMEResource{CNAME: MustNewName("alias.example.com.")}}, {Header: ResourceHeader{Name: MustNewName("foo.bar.example.com."), Type: TypeSOA, Class: ClassINET, TTL: 0, Length: 0}, Body: &SOAResource{NS: MustNewName("ns1.example.com."), MBox: MustNewName("mb.example.com."), Serial: 1, Refresh: 2, Retry: 3, Expire: 4, MinTTL: 5}}, {Header: ResourceHeader{Name: MustNewName("foo.bar.example.com."), Type: TypePTR, Class: ClassINET, TTL: 0, Length: 0}, Body: &PTRResource{PTR: MustNewName("ptr.example.com.")}}, {Header: ResourceHeader{Name: MustNewName("foo.bar.example.com."), Type: TypeMX, Class: ClassINET, TTL: 0, Length: 0}, Body: &MXResource{Pref: 7, MX: MustNewName("mx.example.com.")}}, {Header: ResourceHeader{Name: MustNewName("foo.bar.example.com."), Type: TypeSRV, Class: ClassINET, TTL: 0, Length: 0}, Body: &SRVResource{Priority: 8, Weight: 9, Port: 11, Target: MustNewName("srv.example.com.")}}}, Authorities: []Resource{{Header: ResourceHeader{Name: MustNewName("foo.bar.example.com."), Type: TypeNS, Class: ClassINET, TTL: 0, Length: 0}, Body: &NSResource{NS: MustNewName("ns1.example.com.")}}, {Header: ResourceHeader{Name: MustNewName("foo.bar.example.com."), Type: TypeNS, Class: ClassINET, TTL: 0, Length: 0}, Body: &NSResource{NS: MustNewName("ns2.example.com.")}}}, Additionals: []Resource{{Header: ResourceHeader{Name: MustNewName("foo.bar.example.com."), Type: TypeTXT, Class: ClassINET, TTL: 0, Length: 0}, Body: &TXTResource{TXT: []string{"So Long\x2c and Thanks for All the Fish"}}}, {Header: ResourceHeader{Name: MustNewName("foo.bar.example.com."), Type: TypeTXT, Class: ClassINET, TTL: 0, Length: 0}, Body: &TXTResource{TXT: []string{"Hamster Huey and the Gooey Kablooie"}}}, {Header: ResourceHeader{Name: MustNewName("."), Type: TypeOPT, Class: 4096, TTL: 4261412864, Length: 0}, Body: &OPTResource{Options: []Option{{Code: 10, Data: []byte{1, 35, 69, 103, 137, 171, 205, 239}}}}}}}
  964. if !reflect.DeepEqual(msg, largeTestMsg()) {
  965. t.Error("Message.GoString lost information or largeTestMsg changed: msg != largeTestMsg()")
  966. }
  967. got := msg.GoString()
  968. want := `dnsmessage.Message{Header: dnsmessage.Header{ID: 0, Response: true, OpCode: 0, Authoritative: true, Truncated: false, RecursionDesired: false, RecursionAvailable: false, RCode: dnsmessage.RCodeSuccess}, Questions: []dnsmessage.Question{dnsmessage.Question{Name: dnsmessage.MustNewName("foo.bar.example.com."), Type: dnsmessage.TypeA, Class: dnsmessage.ClassINET}}, Answers: []dnsmessage.Resource{dnsmessage.Resource{Header: dnsmessage.ResourceHeader{Name: dnsmessage.MustNewName("foo.bar.example.com."), Type: dnsmessage.TypeA, Class: dnsmessage.ClassINET, TTL: 0, Length: 0}, Body: &dnsmessage.AResource{A: [4]byte{127, 0, 0, 1}}}, dnsmessage.Resource{Header: dnsmessage.ResourceHeader{Name: dnsmessage.MustNewName("foo.bar.example.com."), Type: dnsmessage.TypeA, Class: dnsmessage.ClassINET, TTL: 0, Length: 0}, Body: &dnsmessage.AResource{A: [4]byte{127, 0, 0, 2}}}, dnsmessage.Resource{Header: dnsmessage.ResourceHeader{Name: dnsmessage.MustNewName("foo.bar.example.com."), Type: dnsmessage.TypeAAAA, Class: dnsmessage.ClassINET, TTL: 0, Length: 0}, Body: &dnsmessage.AAAAResource{AAAA: [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}}}, dnsmessage.Resource{Header: dnsmessage.ResourceHeader{Name: dnsmessage.MustNewName("foo.bar.example.com."), Type: dnsmessage.TypeCNAME, Class: dnsmessage.ClassINET, TTL: 0, Length: 0}, Body: &dnsmessage.CNAMEResource{CNAME: dnsmessage.MustNewName("alias.example.com.")}}, dnsmessage.Resource{Header: dnsmessage.ResourceHeader{Name: dnsmessage.MustNewName("foo.bar.example.com."), Type: dnsmessage.TypeSOA, Class: dnsmessage.ClassINET, TTL: 0, Length: 0}, Body: &dnsmessage.SOAResource{NS: dnsmessage.MustNewName("ns1.example.com."), MBox: dnsmessage.MustNewName("mb.example.com."), Serial: 1, Refresh: 2, Retry: 3, Expire: 4, MinTTL: 5}}, dnsmessage.Resource{Header: dnsmessage.ResourceHeader{Name: dnsmessage.MustNewName("foo.bar.example.com."), Type: dnsmessage.TypePTR, Class: dnsmessage.ClassINET, TTL: 0, Length: 0}, Body: &dnsmessage.PTRResource{PTR: dnsmessage.MustNewName("ptr.example.com.")}}, dnsmessage.Resource{Header: dnsmessage.ResourceHeader{Name: dnsmessage.MustNewName("foo.bar.example.com."), Type: dnsmessage.TypeMX, Class: dnsmessage.ClassINET, TTL: 0, Length: 0}, Body: &dnsmessage.MXResource{Pref: 7, MX: dnsmessage.MustNewName("mx.example.com.")}}, dnsmessage.Resource{Header: dnsmessage.ResourceHeader{Name: dnsmessage.MustNewName("foo.bar.example.com."), Type: dnsmessage.TypeSRV, Class: dnsmessage.ClassINET, TTL: 0, Length: 0}, Body: &dnsmessage.SRVResource{Priority: 8, Weight: 9, Port: 11, Target: dnsmessage.MustNewName("srv.example.com.")}}}, Authorities: []dnsmessage.Resource{dnsmessage.Resource{Header: dnsmessage.ResourceHeader{Name: dnsmessage.MustNewName("foo.bar.example.com."), Type: dnsmessage.TypeNS, Class: dnsmessage.ClassINET, TTL: 0, Length: 0}, Body: &dnsmessage.NSResource{NS: dnsmessage.MustNewName("ns1.example.com.")}}, dnsmessage.Resource{Header: dnsmessage.ResourceHeader{Name: dnsmessage.MustNewName("foo.bar.example.com."), Type: dnsmessage.TypeNS, Class: dnsmessage.ClassINET, TTL: 0, Length: 0}, Body: &dnsmessage.NSResource{NS: dnsmessage.MustNewName("ns2.example.com.")}}}, Additionals: []dnsmessage.Resource{dnsmessage.Resource{Header: dnsmessage.ResourceHeader{Name: dnsmessage.MustNewName("foo.bar.example.com."), Type: dnsmessage.TypeTXT, Class: dnsmessage.ClassINET, TTL: 0, Length: 0}, Body: &dnsmessage.TXTResource{TXT: []string{"So Long\x2c and Thanks for All the Fish"}}}, dnsmessage.Resource{Header: dnsmessage.ResourceHeader{Name: dnsmessage.MustNewName("foo.bar.example.com."), Type: dnsmessage.TypeTXT, Class: dnsmessage.ClassINET, TTL: 0, Length: 0}, Body: &dnsmessage.TXTResource{TXT: []string{"Hamster Huey and the Gooey Kablooie"}}}, dnsmessage.Resource{Header: dnsmessage.ResourceHeader{Name: dnsmessage.MustNewName("."), Type: dnsmessage.TypeOPT, Class: 4096, TTL: 4261412864, Length: 0}, Body: &dnsmessage.OPTResource{Options: []dnsmessage.Option{dnsmessage.Option{Code: 10, Data: []byte{1, 35, 69, 103, 137, 171, 205, 239}}}}}}}`
  969. if got != want {
  970. t.Errorf("got msg1.GoString() = %s\nwant = %s", got, want)
  971. }
  972. }
  973. func benchmarkParsingSetup() ([]byte, error) {
  974. name := MustNewName("foo.bar.example.com.")
  975. msg := Message{
  976. Header: Header{Response: true, Authoritative: true},
  977. Questions: []Question{
  978. {
  979. Name: name,
  980. Type: TypeA,
  981. Class: ClassINET,
  982. },
  983. },
  984. Answers: []Resource{
  985. {
  986. ResourceHeader{
  987. Name: name,
  988. Class: ClassINET,
  989. },
  990. &AResource{[4]byte{}},
  991. },
  992. {
  993. ResourceHeader{
  994. Name: name,
  995. Class: ClassINET,
  996. },
  997. &AAAAResource{[16]byte{}},
  998. },
  999. {
  1000. ResourceHeader{
  1001. Name: name,
  1002. Class: ClassINET,
  1003. },
  1004. &CNAMEResource{name},
  1005. },
  1006. {
  1007. ResourceHeader{
  1008. Name: name,
  1009. Class: ClassINET,
  1010. },
  1011. &NSResource{name},
  1012. },
  1013. },
  1014. }
  1015. buf, err := msg.Pack()
  1016. if err != nil {
  1017. return nil, fmt.Errorf("Message.Pack() = %v", err)
  1018. }
  1019. return buf, nil
  1020. }
  1021. func benchmarkParsing(tb testing.TB, buf []byte) {
  1022. var p Parser
  1023. if _, err := p.Start(buf); err != nil {
  1024. tb.Fatal("Parser.Start(non-nil) =", err)
  1025. }
  1026. for {
  1027. _, err := p.Question()
  1028. if err == ErrSectionDone {
  1029. break
  1030. }
  1031. if err != nil {
  1032. tb.Fatal("Parser.Question() =", err)
  1033. }
  1034. }
  1035. for {
  1036. h, err := p.AnswerHeader()
  1037. if err == ErrSectionDone {
  1038. break
  1039. }
  1040. if err != nil {
  1041. tb.Fatal("Parser.AnswerHeader() =", err)
  1042. }
  1043. switch h.Type {
  1044. case TypeA:
  1045. if _, err := p.AResource(); err != nil {
  1046. tb.Fatal("Parser.AResource() =", err)
  1047. }
  1048. case TypeAAAA:
  1049. if _, err := p.AAAAResource(); err != nil {
  1050. tb.Fatal("Parser.AAAAResource() =", err)
  1051. }
  1052. case TypeCNAME:
  1053. if _, err := p.CNAMEResource(); err != nil {
  1054. tb.Fatal("Parser.CNAMEResource() =", err)
  1055. }
  1056. case TypeNS:
  1057. if _, err := p.NSResource(); err != nil {
  1058. tb.Fatal("Parser.NSResource() =", err)
  1059. }
  1060. case TypeOPT:
  1061. if _, err := p.OPTResource(); err != nil {
  1062. tb.Fatal("Parser.OPTResource() =", err)
  1063. }
  1064. default:
  1065. tb.Fatalf("got unknown type: %T", h)
  1066. }
  1067. }
  1068. }
  1069. func BenchmarkParsing(b *testing.B) {
  1070. buf, err := benchmarkParsingSetup()
  1071. if err != nil {
  1072. b.Fatal(err)
  1073. }
  1074. b.ReportAllocs()
  1075. for i := 0; i < b.N; i++ {
  1076. benchmarkParsing(b, buf)
  1077. }
  1078. }
  1079. func TestParsingAllocs(t *testing.T) {
  1080. buf, err := benchmarkParsingSetup()
  1081. if err != nil {
  1082. t.Fatal(err)
  1083. }
  1084. if allocs := testing.AllocsPerRun(100, func() { benchmarkParsing(t, buf) }); allocs > 0.5 {
  1085. t.Errorf("allocations during parsing: got = %f, want ~0", allocs)
  1086. }
  1087. }
  1088. func benchmarkBuildingSetup() (Name, []byte) {
  1089. name := MustNewName("foo.bar.example.com.")
  1090. buf := make([]byte, 0, packStartingCap)
  1091. return name, buf
  1092. }
  1093. func benchmarkBuilding(tb testing.TB, name Name, buf []byte) {
  1094. bld := NewBuilder(buf, Header{Response: true, Authoritative: true})
  1095. if err := bld.StartQuestions(); err != nil {
  1096. tb.Fatal("Builder.StartQuestions() =", err)
  1097. }
  1098. q := Question{
  1099. Name: name,
  1100. Type: TypeA,
  1101. Class: ClassINET,
  1102. }
  1103. if err := bld.Question(q); err != nil {
  1104. tb.Fatalf("Builder.Question(%+v) = %v", q, err)
  1105. }
  1106. hdr := ResourceHeader{
  1107. Name: name,
  1108. Class: ClassINET,
  1109. }
  1110. if err := bld.StartAnswers(); err != nil {
  1111. tb.Fatal("Builder.StartQuestions() =", err)
  1112. }
  1113. ar := AResource{[4]byte{}}
  1114. if err := bld.AResource(hdr, ar); err != nil {
  1115. tb.Fatalf("Builder.AResource(%+v, %+v) = %v", hdr, ar, err)
  1116. }
  1117. aaar := AAAAResource{[16]byte{}}
  1118. if err := bld.AAAAResource(hdr, aaar); err != nil {
  1119. tb.Fatalf("Builder.AAAAResource(%+v, %+v) = %v", hdr, aaar, err)
  1120. }
  1121. cnr := CNAMEResource{name}
  1122. if err := bld.CNAMEResource(hdr, cnr); err != nil {
  1123. tb.Fatalf("Builder.CNAMEResource(%+v, %+v) = %v", hdr, cnr, err)
  1124. }
  1125. nsr := NSResource{name}
  1126. if err := bld.NSResource(hdr, nsr); err != nil {
  1127. tb.Fatalf("Builder.NSResource(%+v, %+v) = %v", hdr, nsr, err)
  1128. }
  1129. extrc := 0xfe0 | RCodeNotImplemented
  1130. if err := (&hdr).SetEDNS0(4096, extrc, true); err != nil {
  1131. tb.Fatalf("ResourceHeader.SetEDNS0(4096, %#x, true) = %v", extrc, err)
  1132. }
  1133. optr := OPTResource{}
  1134. if err := bld.OPTResource(hdr, optr); err != nil {
  1135. tb.Fatalf("Builder.OPTResource(%+v, %+v) = %v", hdr, optr, err)
  1136. }
  1137. if _, err := bld.Finish(); err != nil {
  1138. tb.Fatal("Builder.Finish() =", err)
  1139. }
  1140. }
  1141. func BenchmarkBuilding(b *testing.B) {
  1142. name, buf := benchmarkBuildingSetup()
  1143. b.ReportAllocs()
  1144. for i := 0; i < b.N; i++ {
  1145. benchmarkBuilding(b, name, buf)
  1146. }
  1147. }
  1148. func TestBuildingAllocs(t *testing.T) {
  1149. name, buf := benchmarkBuildingSetup()
  1150. if allocs := testing.AllocsPerRun(100, func() { benchmarkBuilding(t, name, buf) }); allocs > 0.5 {
  1151. t.Errorf("allocations during building: got = %f, want ~0", allocs)
  1152. }
  1153. }
  1154. func smallTestMsg() Message {
  1155. name := MustNewName("example.com.")
  1156. return Message{
  1157. Header: Header{Response: true, Authoritative: true},
  1158. Questions: []Question{
  1159. {
  1160. Name: name,
  1161. Type: TypeA,
  1162. Class: ClassINET,
  1163. },
  1164. },
  1165. Answers: []Resource{
  1166. {
  1167. ResourceHeader{
  1168. Name: name,
  1169. Type: TypeA,
  1170. Class: ClassINET,
  1171. },
  1172. &AResource{[4]byte{127, 0, 0, 1}},
  1173. },
  1174. },
  1175. Authorities: []Resource{
  1176. {
  1177. ResourceHeader{
  1178. Name: name,
  1179. Type: TypeA,
  1180. Class: ClassINET,
  1181. },
  1182. &AResource{[4]byte{127, 0, 0, 1}},
  1183. },
  1184. },
  1185. Additionals: []Resource{
  1186. {
  1187. ResourceHeader{
  1188. Name: name,
  1189. Type: TypeA,
  1190. Class: ClassINET,
  1191. },
  1192. &AResource{[4]byte{127, 0, 0, 1}},
  1193. },
  1194. },
  1195. }
  1196. }
  1197. func BenchmarkPack(b *testing.B) {
  1198. msg := largeTestMsg()
  1199. b.ReportAllocs()
  1200. for i := 0; i < b.N; i++ {
  1201. if _, err := msg.Pack(); err != nil {
  1202. b.Fatal("Message.Pack() =", err)
  1203. }
  1204. }
  1205. }
  1206. func BenchmarkAppendPack(b *testing.B) {
  1207. msg := largeTestMsg()
  1208. buf := make([]byte, 0, packStartingCap)
  1209. b.ReportAllocs()
  1210. for i := 0; i < b.N; i++ {
  1211. if _, err := msg.AppendPack(buf[:0]); err != nil {
  1212. b.Fatal("Message.AppendPack() = ", err)
  1213. }
  1214. }
  1215. }
  1216. func largeTestMsg() Message {
  1217. name := MustNewName("foo.bar.example.com.")
  1218. return Message{
  1219. Header: Header{Response: true, Authoritative: true},
  1220. Questions: []Question{
  1221. {
  1222. Name: name,
  1223. Type: TypeA,
  1224. Class: ClassINET,
  1225. },
  1226. },
  1227. Answers: []Resource{
  1228. {
  1229. ResourceHeader{
  1230. Name: name,
  1231. Type: TypeA,
  1232. Class: ClassINET,
  1233. },
  1234. &AResource{[4]byte{127, 0, 0, 1}},
  1235. },
  1236. {
  1237. ResourceHeader{
  1238. Name: name,
  1239. Type: TypeA,
  1240. Class: ClassINET,
  1241. },
  1242. &AResource{[4]byte{127, 0, 0, 2}},
  1243. },
  1244. {
  1245. ResourceHeader{
  1246. Name: name,
  1247. Type: TypeAAAA,
  1248. Class: ClassINET,
  1249. },
  1250. &AAAAResource{[16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}},
  1251. },
  1252. {
  1253. ResourceHeader{
  1254. Name: name,
  1255. Type: TypeCNAME,
  1256. Class: ClassINET,
  1257. },
  1258. &CNAMEResource{MustNewName("alias.example.com.")},
  1259. },
  1260. {
  1261. ResourceHeader{
  1262. Name: name,
  1263. Type: TypeSOA,
  1264. Class: ClassINET,
  1265. },
  1266. &SOAResource{
  1267. NS: MustNewName("ns1.example.com."),
  1268. MBox: MustNewName("mb.example.com."),
  1269. Serial: 1,
  1270. Refresh: 2,
  1271. Retry: 3,
  1272. Expire: 4,
  1273. MinTTL: 5,
  1274. },
  1275. },
  1276. {
  1277. ResourceHeader{
  1278. Name: name,
  1279. Type: TypePTR,
  1280. Class: ClassINET,
  1281. },
  1282. &PTRResource{MustNewName("ptr.example.com.")},
  1283. },
  1284. {
  1285. ResourceHeader{
  1286. Name: name,
  1287. Type: TypeMX,
  1288. Class: ClassINET,
  1289. },
  1290. &MXResource{
  1291. 7,
  1292. MustNewName("mx.example.com."),
  1293. },
  1294. },
  1295. {
  1296. ResourceHeader{
  1297. Name: name,
  1298. Type: TypeSRV,
  1299. Class: ClassINET,
  1300. },
  1301. &SRVResource{
  1302. 8,
  1303. 9,
  1304. 11,
  1305. MustNewName("srv.example.com."),
  1306. },
  1307. },
  1308. },
  1309. Authorities: []Resource{
  1310. {
  1311. ResourceHeader{
  1312. Name: name,
  1313. Type: TypeNS,
  1314. Class: ClassINET,
  1315. },
  1316. &NSResource{MustNewName("ns1.example.com.")},
  1317. },
  1318. {
  1319. ResourceHeader{
  1320. Name: name,
  1321. Type: TypeNS,
  1322. Class: ClassINET,
  1323. },
  1324. &NSResource{MustNewName("ns2.example.com.")},
  1325. },
  1326. },
  1327. Additionals: []Resource{
  1328. {
  1329. ResourceHeader{
  1330. Name: name,
  1331. Type: TypeTXT,
  1332. Class: ClassINET,
  1333. },
  1334. &TXTResource{[]string{"So Long, and Thanks for All the Fish"}},
  1335. },
  1336. {
  1337. ResourceHeader{
  1338. Name: name,
  1339. Type: TypeTXT,
  1340. Class: ClassINET,
  1341. },
  1342. &TXTResource{[]string{"Hamster Huey and the Gooey Kablooie"}},
  1343. },
  1344. {
  1345. mustEDNS0ResourceHeader(4096, 0xfe0|RCodeSuccess, false),
  1346. &OPTResource{
  1347. Options: []Option{
  1348. {
  1349. Code: 10, // see RFC 7873
  1350. Data: []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef},
  1351. },
  1352. },
  1353. },
  1354. },
  1355. },
  1356. }
  1357. }