github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/net/dns/dnsmessage/message_test.go (about)

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