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  }