Source file src/net/netip/netip_test.go

     1  // Copyright 2020 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 netip_test
     6  
     7  import (
     8  	"bytes"
     9  	"encoding/json"
    10  	"flag"
    11  	"fmt"
    12  	"internal/intern"
    13  	"internal/testenv"
    14  	"net"
    15  	. "net/netip"
    16  	"reflect"
    17  	"slices"
    18  	"sort"
    19  	"strings"
    20  	"testing"
    21  )
    22  
    23  var long = flag.Bool("long", false, "run long tests")
    24  
    25  type uint128 = Uint128
    26  
    27  var (
    28  	mustPrefix = MustParsePrefix
    29  	mustIP     = MustParseAddr
    30  	mustIPPort = MustParseAddrPort
    31  )
    32  
    33  func TestParseAddr(t *testing.T) {
    34  	var validIPs = []struct {
    35  		in      string
    36  		ip      Addr   // output of ParseAddr()
    37  		str     string // output of String(). If "", use in.
    38  		wantErr string
    39  	}{
    40  		// Basic zero IPv4 address.
    41  		{
    42  			in: "0.0.0.0",
    43  			ip: MkAddr(Mk128(0, 0xffff00000000), Z4),
    44  		},
    45  		// Basic non-zero IPv4 address.
    46  		{
    47  			in: "192.168.140.255",
    48  			ip: MkAddr(Mk128(0, 0xffffc0a88cff), Z4),
    49  		},
    50  		// IPv4 address in windows-style "print all the digits" form.
    51  		{
    52  			in:      "010.000.015.001",
    53  			wantErr: `ParseAddr("010.000.015.001"): IPv4 field has octet with leading zero`,
    54  		},
    55  		// IPv4 address with a silly amount of leading zeros.
    56  		{
    57  			in:      "000001.00000002.00000003.000000004",
    58  			wantErr: `ParseAddr("000001.00000002.00000003.000000004"): IPv4 field has octet with leading zero`,
    59  		},
    60  		// 4-in-6 with octet with leading zero
    61  		{
    62  			in:      "::ffff:1.2.03.4",
    63  			wantErr: `ParseAddr("::ffff:1.2.03.4"): ParseAddr("1.2.03.4"): IPv4 field has octet with leading zero (at "1.2.03.4")`,
    64  		},
    65  		// Basic zero IPv6 address.
    66  		{
    67  			in: "::",
    68  			ip: MkAddr(Mk128(0, 0), Z6noz),
    69  		},
    70  		// Localhost IPv6.
    71  		{
    72  			in: "::1",
    73  			ip: MkAddr(Mk128(0, 1), Z6noz),
    74  		},
    75  		// Fully expanded IPv6 address.
    76  		{
    77  			in: "fd7a:115c:a1e0:ab12:4843:cd96:626b:430b",
    78  			ip: MkAddr(Mk128(0xfd7a115ca1e0ab12, 0x4843cd96626b430b), Z6noz),
    79  		},
    80  		// IPv6 with elided fields in the middle.
    81  		{
    82  			in: "fd7a:115c::626b:430b",
    83  			ip: MkAddr(Mk128(0xfd7a115c00000000, 0x00000000626b430b), Z6noz),
    84  		},
    85  		// IPv6 with elided fields at the end.
    86  		{
    87  			in: "fd7a:115c:a1e0:ab12:4843:cd96::",
    88  			ip: MkAddr(Mk128(0xfd7a115ca1e0ab12, 0x4843cd9600000000), Z6noz),
    89  		},
    90  		// IPv6 with single elided field at the end.
    91  		{
    92  			in:  "fd7a:115c:a1e0:ab12:4843:cd96:626b::",
    93  			ip:  MkAddr(Mk128(0xfd7a115ca1e0ab12, 0x4843cd96626b0000), Z6noz),
    94  			str: "fd7a:115c:a1e0:ab12:4843:cd96:626b:0",
    95  		},
    96  		// IPv6 with single elided field in the middle.
    97  		{
    98  			in:  "fd7a:115c:a1e0::4843:cd96:626b:430b",
    99  			ip:  MkAddr(Mk128(0xfd7a115ca1e00000, 0x4843cd96626b430b), Z6noz),
   100  			str: "fd7a:115c:a1e0:0:4843:cd96:626b:430b",
   101  		},
   102  		// IPv6 with the trailing 32 bits written as IPv4 dotted decimal. (4in6)
   103  		{
   104  			in:  "::ffff:192.168.140.255",
   105  			ip:  MkAddr(Mk128(0, 0x0000ffffc0a88cff), Z6noz),
   106  			str: "::ffff:192.168.140.255",
   107  		},
   108  		// IPv6 with a zone specifier.
   109  		{
   110  			in: "fd7a:115c:a1e0:ab12:4843:cd96:626b:430b%eth0",
   111  			ip: MkAddr(Mk128(0xfd7a115ca1e0ab12, 0x4843cd96626b430b), intern.Get("eth0")),
   112  		},
   113  		// IPv6 with dotted decimal and zone specifier.
   114  		{
   115  			in:  "1:2::ffff:192.168.140.255%eth1",
   116  			ip:  MkAddr(Mk128(0x0001000200000000, 0x0000ffffc0a88cff), intern.Get("eth1")),
   117  			str: "1:2::ffff:c0a8:8cff%eth1",
   118  		},
   119  		// 4-in-6 with zone
   120  		{
   121  			in:  "::ffff:192.168.140.255%eth1",
   122  			ip:  MkAddr(Mk128(0, 0x0000ffffc0a88cff), intern.Get("eth1")),
   123  			str: "::ffff:192.168.140.255%eth1",
   124  		},
   125  		// IPv6 with capital letters.
   126  		{
   127  			in:  "FD9E:1A04:F01D::1",
   128  			ip:  MkAddr(Mk128(0xfd9e1a04f01d0000, 0x1), Z6noz),
   129  			str: "fd9e:1a04:f01d::1",
   130  		},
   131  	}
   132  
   133  	for _, test := range validIPs {
   134  		t.Run(test.in, func(t *testing.T) {
   135  			got, err := ParseAddr(test.in)
   136  			if err != nil {
   137  				if err.Error() == test.wantErr {
   138  					return
   139  				}
   140  				t.Fatal(err)
   141  			}
   142  			if test.wantErr != "" {
   143  				t.Fatalf("wanted error %q; got none", test.wantErr)
   144  			}
   145  			if got != test.ip {
   146  				t.Errorf("got %#v, want %#v", got, test.ip)
   147  			}
   148  
   149  			// Check that ParseAddr is a pure function.
   150  			got2, err := ParseAddr(test.in)
   151  			if err != nil {
   152  				t.Fatal(err)
   153  			}
   154  			if got != got2 {
   155  				t.Errorf("ParseAddr(%q) got 2 different results: %#v, %#v", test.in, got, got2)
   156  			}
   157  
   158  			// Check that ParseAddr(ip.String()) is the identity function.
   159  			s := got.String()
   160  			got3, err := ParseAddr(s)
   161  			if err != nil {
   162  				t.Fatal(err)
   163  			}
   164  			if got != got3 {
   165  				t.Errorf("ParseAddr(%q) != ParseAddr(ParseIP(%q).String()). Got %#v, want %#v", test.in, test.in, got3, got)
   166  			}
   167  
   168  			// Check that the slow-but-readable parser produces the same result.
   169  			slow, err := parseIPSlow(test.in)
   170  			if err != nil {
   171  				t.Fatal(err)
   172  			}
   173  			if got != slow {
   174  				t.Errorf("ParseAddr(%q) = %#v, parseIPSlow(%q) = %#v", test.in, got, test.in, slow)
   175  			}
   176  
   177  			// Check that the parsed IP formats as expected.
   178  			s = got.String()
   179  			wants := test.str
   180  			if wants == "" {
   181  				wants = test.in
   182  			}
   183  			if s != wants {
   184  				t.Errorf("ParseAddr(%q).String() got %q, want %q", test.in, s, wants)
   185  			}
   186  
   187  			// Check that AppendTo matches MarshalText.
   188  			TestAppendToMarshal(t, got)
   189  
   190  			// Check that MarshalText/UnmarshalText work similarly to
   191  			// ParseAddr/String (see TestIPMarshalUnmarshal for
   192  			// marshal-specific behavior that's not common with
   193  			// ParseAddr/String).
   194  			js := `"` + test.in + `"`
   195  			var jsgot Addr
   196  			if err := json.Unmarshal([]byte(js), &jsgot); err != nil {
   197  				t.Fatal(err)
   198  			}
   199  			if jsgot != got {
   200  				t.Errorf("json.Unmarshal(%q) = %#v, want %#v", test.in, jsgot, got)
   201  			}
   202  			jsb, err := json.Marshal(jsgot)
   203  			if err != nil {
   204  				t.Fatal(err)
   205  			}
   206  			jswant := `"` + wants + `"`
   207  			jsback := string(jsb)
   208  			if jsback != jswant {
   209  				t.Errorf("Marshal(Unmarshal(%q)) = %s, want %s", test.in, jsback, jswant)
   210  			}
   211  		})
   212  	}
   213  
   214  	var invalidIPs = []string{
   215  		// Empty string
   216  		"",
   217  		// Garbage non-IP
   218  		"bad",
   219  		// Single number. Some parsers accept this as an IPv4 address in
   220  		// big-endian uint32 form, but we don't.
   221  		"1234",
   222  		// IPv4 with a zone specifier
   223  		"1.2.3.4%eth0",
   224  		// IPv4 field must have at least one digit
   225  		".1.2.3",
   226  		"1.2.3.",
   227  		"1..2.3",
   228  		// IPv4 address too long
   229  		"1.2.3.4.5",
   230  		// IPv4 in dotted octal form
   231  		"0300.0250.0214.0377",
   232  		// IPv4 in dotted hex form
   233  		"0xc0.0xa8.0x8c.0xff",
   234  		// IPv4 in class B form
   235  		"192.168.12345",
   236  		// IPv4 in class B form, with a small enough number to be
   237  		// parseable as a regular dotted decimal field.
   238  		"127.0.1",
   239  		// IPv4 in class A form
   240  		"192.1234567",
   241  		// IPv4 in class A form, with a small enough number to be
   242  		// parseable as a regular dotted decimal field.
   243  		"127.1",
   244  		// IPv4 field has value >255
   245  		"192.168.300.1",
   246  		// IPv4 with too many fields
   247  		"192.168.0.1.5.6",
   248  		// IPv6 with not enough fields
   249  		"1:2:3:4:5:6:7",
   250  		// IPv6 with too many fields
   251  		"1:2:3:4:5:6:7:8:9",
   252  		// IPv6 with 8 fields and a :: expander
   253  		"1:2:3:4::5:6:7:8",
   254  		// IPv6 with a field bigger than 2b
   255  		"fe801::1",
   256  		// IPv6 with non-hex values in field
   257  		"fe80:tail:scal:e::",
   258  		// IPv6 with a zone delimiter but no zone.
   259  		"fe80::1%",
   260  		// IPv6 (without ellipsis) with too many fields for trailing embedded IPv4.
   261  		"ffff:ffff:ffff:ffff:ffff:ffff:ffff:192.168.140.255",
   262  		// IPv6 (with ellipsis) with too many fields for trailing embedded IPv4.
   263  		"ffff::ffff:ffff:ffff:ffff:ffff:ffff:192.168.140.255",
   264  		// IPv6 with invalid embedded IPv4.
   265  		"::ffff:192.168.140.bad",
   266  		// IPv6 with multiple ellipsis ::.
   267  		"fe80::1::1",
   268  		// IPv6 with invalid non hex/colon character.
   269  		"fe80:1?:1",
   270  		// IPv6 with truncated bytes after single colon.
   271  		"fe80:",
   272  	}
   273  
   274  	for _, s := range invalidIPs {
   275  		t.Run(s, func(t *testing.T) {
   276  			got, err := ParseAddr(s)
   277  			if err == nil {
   278  				t.Errorf("ParseAddr(%q) = %#v, want error", s, got)
   279  			}
   280  
   281  			slow, err := parseIPSlow(s)
   282  			if err == nil {
   283  				t.Errorf("parseIPSlow(%q) = %#v, want error", s, slow)
   284  			}
   285  
   286  			std := net.ParseIP(s)
   287  			if std != nil {
   288  				t.Errorf("net.ParseIP(%q) = %#v, want error", s, std)
   289  			}
   290  
   291  			if s == "" {
   292  				// Don't test unmarshaling of "" here, do it in
   293  				// IPMarshalUnmarshal.
   294  				return
   295  			}
   296  			var jsgot Addr
   297  			js := []byte(`"` + s + `"`)
   298  			if err := json.Unmarshal(js, &jsgot); err == nil {
   299  				t.Errorf("json.Unmarshal(%q) = %#v, want error", s, jsgot)
   300  			}
   301  		})
   302  	}
   303  }
   304  
   305  func TestAddrFromSlice(t *testing.T) {
   306  	tests := []struct {
   307  		ip       []byte
   308  		wantAddr Addr
   309  		wantOK   bool
   310  	}{
   311  		{
   312  			ip:       []byte{10, 0, 0, 1},
   313  			wantAddr: mustIP("10.0.0.1"),
   314  			wantOK:   true,
   315  		},
   316  		{
   317  			ip:       []byte{0xfe, 0x80, 15: 0x01},
   318  			wantAddr: mustIP("fe80::01"),
   319  			wantOK:   true,
   320  		},
   321  		{
   322  			ip:       []byte{0, 1, 2},
   323  			wantAddr: Addr{},
   324  			wantOK:   false,
   325  		},
   326  		{
   327  			ip:       nil,
   328  			wantAddr: Addr{},
   329  			wantOK:   false,
   330  		},
   331  	}
   332  	for _, tt := range tests {
   333  		addr, ok := AddrFromSlice(tt.ip)
   334  		if ok != tt.wantOK || addr != tt.wantAddr {
   335  			t.Errorf("AddrFromSlice(%#v) = %#v, %v, want %#v, %v", tt.ip, addr, ok, tt.wantAddr, tt.wantOK)
   336  		}
   337  	}
   338  }
   339  
   340  func TestIPv4Constructors(t *testing.T) {
   341  	if AddrFrom4([4]byte{1, 2, 3, 4}) != MustParseAddr("1.2.3.4") {
   342  		t.Errorf("don't match")
   343  	}
   344  }
   345  
   346  func TestAddrMarshalUnmarshalBinary(t *testing.T) {
   347  	tests := []struct {
   348  		ip       string
   349  		wantSize int
   350  	}{
   351  		{"", 0}, // zero IP
   352  		{"1.2.3.4", 4},
   353  		{"fd7a:115c:a1e0:ab12:4843:cd96:626b:430b", 16},
   354  		{"::ffff:c000:0280", 16},
   355  		{"::ffff:c000:0280%eth0", 20},
   356  	}
   357  	for _, tc := range tests {
   358  		var ip Addr
   359  		if len(tc.ip) > 0 {
   360  			ip = mustIP(tc.ip)
   361  		}
   362  		b, err := ip.MarshalBinary()
   363  		if err != nil {
   364  			t.Fatal(err)
   365  		}
   366  		if len(b) != tc.wantSize {
   367  			t.Fatalf("%q encoded to size %d; want %d", tc.ip, len(b), tc.wantSize)
   368  		}
   369  		var ip2 Addr
   370  		if err := ip2.UnmarshalBinary(b); err != nil {
   371  			t.Fatal(err)
   372  		}
   373  		if ip != ip2 {
   374  			t.Fatalf("got %v; want %v", ip2, ip)
   375  		}
   376  	}
   377  
   378  	// Cannot unmarshal from unexpected IP length.
   379  	for _, n := range []int{3, 5} {
   380  		var ip2 Addr
   381  		if err := ip2.UnmarshalBinary(bytes.Repeat([]byte{1}, n)); err == nil {
   382  			t.Fatalf("unmarshaled from unexpected IP length %d", n)
   383  		}
   384  	}
   385  }
   386  
   387  func TestAddrPortMarshalTextString(t *testing.T) {
   388  	tests := []struct {
   389  		in   AddrPort
   390  		want string
   391  	}{
   392  		{mustIPPort("1.2.3.4:80"), "1.2.3.4:80"},
   393  		{mustIPPort("[::]:80"), "[::]:80"},
   394  		{mustIPPort("[1::CAFE]:80"), "[1::cafe]:80"},
   395  		{mustIPPort("[1::CAFE%en0]:80"), "[1::cafe%en0]:80"},
   396  		{mustIPPort("[::FFFF:192.168.140.255]:80"), "[::ffff:192.168.140.255]:80"},
   397  		{mustIPPort("[::FFFF:192.168.140.255%en0]:80"), "[::ffff:192.168.140.255%en0]:80"},
   398  	}
   399  	for i, tt := range tests {
   400  		if got := tt.in.String(); got != tt.want {
   401  			t.Errorf("%d. for (%v, %v) String = %q; want %q", i, tt.in.Addr(), tt.in.Port(), got, tt.want)
   402  		}
   403  		mt, err := tt.in.MarshalText()
   404  		if err != nil {
   405  			t.Errorf("%d. for (%v, %v) MarshalText error: %v", i, tt.in.Addr(), tt.in.Port(), err)
   406  			continue
   407  		}
   408  		if string(mt) != tt.want {
   409  			t.Errorf("%d. for (%v, %v) MarshalText = %q; want %q", i, tt.in.Addr(), tt.in.Port(), mt, tt.want)
   410  		}
   411  	}
   412  }
   413  
   414  func TestAddrPortMarshalUnmarshalBinary(t *testing.T) {
   415  	tests := []struct {
   416  		ipport   string
   417  		wantSize int
   418  	}{
   419  		{"1.2.3.4:51820", 4 + 2},
   420  		{"[fd7a:115c:a1e0:ab12:4843:cd96:626b:430b]:80", 16 + 2},
   421  		{"[::ffff:c000:0280]:65535", 16 + 2},
   422  		{"[::ffff:c000:0280%eth0]:1", 20 + 2},
   423  	}
   424  	for _, tc := range tests {
   425  		var ipport AddrPort
   426  		if len(tc.ipport) > 0 {
   427  			ipport = mustIPPort(tc.ipport)
   428  		}
   429  		b, err := ipport.MarshalBinary()
   430  		if err != nil {
   431  			t.Fatal(err)
   432  		}
   433  		if len(b) != tc.wantSize {
   434  			t.Fatalf("%q encoded to size %d; want %d", tc.ipport, len(b), tc.wantSize)
   435  		}
   436  		var ipport2 AddrPort
   437  		if err := ipport2.UnmarshalBinary(b); err != nil {
   438  			t.Fatal(err)
   439  		}
   440  		if ipport != ipport2 {
   441  			t.Fatalf("got %v; want %v", ipport2, ipport)
   442  		}
   443  	}
   444  
   445  	// Cannot unmarshal from unexpected lengths.
   446  	for _, n := range []int{3, 7} {
   447  		var ipport2 AddrPort
   448  		if err := ipport2.UnmarshalBinary(bytes.Repeat([]byte{1}, n)); err == nil {
   449  			t.Fatalf("unmarshaled from unexpected length %d", n)
   450  		}
   451  	}
   452  }
   453  
   454  func TestPrefixMarshalTextString(t *testing.T) {
   455  	tests := []struct {
   456  		in   Prefix
   457  		want string
   458  	}{
   459  		{mustPrefix("1.2.3.4/24"), "1.2.3.4/24"},
   460  		{mustPrefix("fd7a:115c:a1e0:ab12:4843:cd96:626b:430b/118"), "fd7a:115c:a1e0:ab12:4843:cd96:626b:430b/118"},
   461  		{mustPrefix("::ffff:c000:0280/96"), "::ffff:192.0.2.128/96"},
   462  		{mustPrefix("::ffff:192.168.140.255/8"), "::ffff:192.168.140.255/8"},
   463  		{PrefixFrom(mustIP("::ffff:c000:0280").WithZone("eth0"), 37), "::ffff:192.0.2.128/37"}, // Zone should be stripped
   464  	}
   465  	for i, tt := range tests {
   466  		if got := tt.in.String(); got != tt.want {
   467  			t.Errorf("%d. for %v String = %q; want %q", i, tt.in, got, tt.want)
   468  		}
   469  		mt, err := tt.in.MarshalText()
   470  		if err != nil {
   471  			t.Errorf("%d. for %v MarshalText error: %v", i, tt.in, err)
   472  			continue
   473  		}
   474  		if string(mt) != tt.want {
   475  			t.Errorf("%d. for %v MarshalText = %q; want %q", i, tt.in, mt, tt.want)
   476  		}
   477  	}
   478  }
   479  
   480  func TestPrefixMarshalUnmarshalBinary(t *testing.T) {
   481  	type testCase struct {
   482  		prefix   Prefix
   483  		wantSize int
   484  	}
   485  	tests := []testCase{
   486  		{mustPrefix("1.2.3.4/24"), 4 + 1},
   487  		{mustPrefix("fd7a:115c:a1e0:ab12:4843:cd96:626b:430b/118"), 16 + 1},
   488  		{mustPrefix("::ffff:c000:0280/96"), 16 + 1},
   489  		{PrefixFrom(mustIP("::ffff:c000:0280").WithZone("eth0"), 37), 16 + 1}, // Zone should be stripped
   490  	}
   491  	tests = append(tests,
   492  		testCase{PrefixFrom(tests[0].prefix.Addr(), 33), tests[0].wantSize},
   493  		testCase{PrefixFrom(tests[1].prefix.Addr(), 129), tests[1].wantSize})
   494  	for _, tc := range tests {
   495  		prefix := tc.prefix
   496  		b, err := prefix.MarshalBinary()
   497  		if err != nil {
   498  			t.Fatal(err)
   499  		}
   500  		if len(b) != tc.wantSize {
   501  			t.Fatalf("%q encoded to size %d; want %d", tc.prefix, len(b), tc.wantSize)
   502  		}
   503  		var prefix2 Prefix
   504  		if err := prefix2.UnmarshalBinary(b); err != nil {
   505  			t.Fatal(err)
   506  		}
   507  		if prefix != prefix2 {
   508  			t.Fatalf("got %v; want %v", prefix2, prefix)
   509  		}
   510  	}
   511  
   512  	// Cannot unmarshal from unexpected lengths.
   513  	for _, n := range []int{3, 6} {
   514  		var prefix2 Prefix
   515  		if err := prefix2.UnmarshalBinary(bytes.Repeat([]byte{1}, n)); err == nil {
   516  			t.Fatalf("unmarshaled from unexpected length %d", n)
   517  		}
   518  	}
   519  }
   520  
   521  func TestAddrMarshalUnmarshal(t *testing.T) {
   522  	// This only tests the cases where Marshal/Unmarshal diverges from
   523  	// the behavior of ParseAddr/String. For the rest of the test cases,
   524  	// see TestParseAddr above.
   525  	orig := `""`
   526  	var ip Addr
   527  	if err := json.Unmarshal([]byte(orig), &ip); err != nil {
   528  		t.Fatalf("Unmarshal(%q) got error %v", orig, err)
   529  	}
   530  	if ip != (Addr{}) {
   531  		t.Errorf("Unmarshal(%q) is not the zero Addr", orig)
   532  	}
   533  
   534  	jsb, err := json.Marshal(ip)
   535  	if err != nil {
   536  		t.Fatalf("Marshal(%v) got error %v", ip, err)
   537  	}
   538  	back := string(jsb)
   539  	if back != orig {
   540  		t.Errorf("Marshal(Unmarshal(%q)) got %q, want %q", orig, back, orig)
   541  	}
   542  }
   543  
   544  func TestAddrFrom16(t *testing.T) {
   545  	tests := []struct {
   546  		name string
   547  		in   [16]byte
   548  		want Addr
   549  	}{
   550  		{
   551  			name: "v6-raw",
   552  			in:   [...]byte{15: 1},
   553  			want: MkAddr(Mk128(0, 1), Z6noz),
   554  		},
   555  		{
   556  			name: "v4-raw",
   557  			in:   [...]byte{10: 0xff, 11: 0xff, 12: 1, 13: 2, 14: 3, 15: 4},
   558  			want: MkAddr(Mk128(0, 0xffff01020304), Z6noz),
   559  		},
   560  	}
   561  	for _, tt := range tests {
   562  		t.Run(tt.name, func(t *testing.T) {
   563  			got := AddrFrom16(tt.in)
   564  			if got != tt.want {
   565  				t.Errorf("got %#v; want %#v", got, tt.want)
   566  			}
   567  		})
   568  	}
   569  }
   570  
   571  func TestIPProperties(t *testing.T) {
   572  	var (
   573  		nilIP Addr
   574  
   575  		unicast4           = mustIP("192.0.2.1")
   576  		unicast6           = mustIP("2001:db8::1")
   577  		unicastZone6       = mustIP("2001:db8::1%eth0")
   578  		unicast6Unassigned = mustIP("4000::1") // not in 2000::/3.
   579  
   580  		multicast4     = mustIP("224.0.0.1")
   581  		multicast6     = mustIP("ff02::1")
   582  		multicastZone6 = mustIP("ff02::1%eth0")
   583  
   584  		llu4     = mustIP("169.254.0.1")
   585  		llu6     = mustIP("fe80::1")
   586  		llu6Last = mustIP("febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff")
   587  		lluZone6 = mustIP("fe80::1%eth0")
   588  
   589  		loopback4 = mustIP("127.0.0.1")
   590  
   591  		ilm6     = mustIP("ff01::1")
   592  		ilmZone6 = mustIP("ff01::1%eth0")
   593  
   594  		private4a = mustIP("10.0.0.1")
   595  		private4b = mustIP("172.16.0.1")
   596  		private4c = mustIP("192.168.1.1")
   597  		private6  = mustIP("fd00::1")
   598  	)
   599  
   600  	tests := []struct {
   601  		name                    string
   602  		ip                      Addr
   603  		globalUnicast           bool
   604  		interfaceLocalMulticast bool
   605  		linkLocalMulticast      bool
   606  		linkLocalUnicast        bool
   607  		loopback                bool
   608  		multicast               bool
   609  		private                 bool
   610  		unspecified             bool
   611  	}{
   612  		{
   613  			name: "nil",
   614  			ip:   nilIP,
   615  		},
   616  		{
   617  			name:          "unicast v4Addr",
   618  			ip:            unicast4,
   619  			globalUnicast: true,
   620  		},
   621  		{
   622  			name:          "unicast v6Addr",
   623  			ip:            unicast6,
   624  			globalUnicast: true,
   625  		},
   626  		{
   627  			name:          "unicast v6AddrZone",
   628  			ip:            unicastZone6,
   629  			globalUnicast: true,
   630  		},
   631  		{
   632  			name:          "unicast v6Addr unassigned",
   633  			ip:            unicast6Unassigned,
   634  			globalUnicast: true,
   635  		},
   636  		{
   637  			name:               "multicast v4Addr",
   638  			ip:                 multicast4,
   639  			linkLocalMulticast: true,
   640  			multicast:          true,
   641  		},
   642  		{
   643  			name:               "multicast v6Addr",
   644  			ip:                 multicast6,
   645  			linkLocalMulticast: true,
   646  			multicast:          true,
   647  		},
   648  		{
   649  			name:               "multicast v6AddrZone",
   650  			ip:                 multicastZone6,
   651  			linkLocalMulticast: true,
   652  			multicast:          true,
   653  		},
   654  		{
   655  			name:             "link-local unicast v4Addr",
   656  			ip:               llu4,
   657  			linkLocalUnicast: true,
   658  		},
   659  		{
   660  			name:             "link-local unicast v6Addr",
   661  			ip:               llu6,
   662  			linkLocalUnicast: true,
   663  		},
   664  		{
   665  			name:             "link-local unicast v6Addr upper bound",
   666  			ip:               llu6Last,
   667  			linkLocalUnicast: true,
   668  		},
   669  		{
   670  			name:             "link-local unicast v6AddrZone",
   671  			ip:               lluZone6,
   672  			linkLocalUnicast: true,
   673  		},
   674  		{
   675  			name:     "loopback v4Addr",
   676  			ip:       loopback4,
   677  			loopback: true,
   678  		},
   679  		{
   680  			name:     "loopback v6Addr",
   681  			ip:       IPv6Loopback(),
   682  			loopback: true,
   683  		},
   684  		{
   685  			name:                    "interface-local multicast v6Addr",
   686  			ip:                      ilm6,
   687  			interfaceLocalMulticast: true,
   688  			multicast:               true,
   689  		},
   690  		{
   691  			name:                    "interface-local multicast v6AddrZone",
   692  			ip:                      ilmZone6,
   693  			interfaceLocalMulticast: true,
   694  			multicast:               true,
   695  		},
   696  		{
   697  			name:          "private v4Addr 10/8",
   698  			ip:            private4a,
   699  			globalUnicast: true,
   700  			private:       true,
   701  		},
   702  		{
   703  			name:          "private v4Addr 172.16/12",
   704  			ip:            private4b,
   705  			globalUnicast: true,
   706  			private:       true,
   707  		},
   708  		{
   709  			name:          "private v4Addr 192.168/16",
   710  			ip:            private4c,
   711  			globalUnicast: true,
   712  			private:       true,
   713  		},
   714  		{
   715  			name:          "private v6Addr",
   716  			ip:            private6,
   717  			globalUnicast: true,
   718  			private:       true,
   719  		},
   720  		{
   721  			name:        "unspecified v4Addr",
   722  			ip:          IPv4Unspecified(),
   723  			unspecified: true,
   724  		},
   725  		{
   726  			name:        "unspecified v6Addr",
   727  			ip:          IPv6Unspecified(),
   728  			unspecified: true,
   729  		},
   730  	}
   731  
   732  	for _, tt := range tests {
   733  		t.Run(tt.name, func(t *testing.T) {
   734  			gu := tt.ip.IsGlobalUnicast()
   735  			if gu != tt.globalUnicast {
   736  				t.Errorf("IsGlobalUnicast(%v) = %v; want %v", tt.ip, gu, tt.globalUnicast)
   737  			}
   738  
   739  			ilm := tt.ip.IsInterfaceLocalMulticast()
   740  			if ilm != tt.interfaceLocalMulticast {
   741  				t.Errorf("IsInterfaceLocalMulticast(%v) = %v; want %v", tt.ip, ilm, tt.interfaceLocalMulticast)
   742  			}
   743  
   744  			llu := tt.ip.IsLinkLocalUnicast()
   745  			if llu != tt.linkLocalUnicast {
   746  				t.Errorf("IsLinkLocalUnicast(%v) = %v; want %v", tt.ip, llu, tt.linkLocalUnicast)
   747  			}
   748  
   749  			llm := tt.ip.IsLinkLocalMulticast()
   750  			if llm != tt.linkLocalMulticast {
   751  				t.Errorf("IsLinkLocalMulticast(%v) = %v; want %v", tt.ip, llm, tt.linkLocalMulticast)
   752  			}
   753  
   754  			lo := tt.ip.IsLoopback()
   755  			if lo != tt.loopback {
   756  				t.Errorf("IsLoopback(%v) = %v; want %v", tt.ip, lo, tt.loopback)
   757  			}
   758  
   759  			multicast := tt.ip.IsMulticast()
   760  			if multicast != tt.multicast {
   761  				t.Errorf("IsMulticast(%v) = %v; want %v", tt.ip, multicast, tt.multicast)
   762  			}
   763  
   764  			private := tt.ip.IsPrivate()
   765  			if private != tt.private {
   766  				t.Errorf("IsPrivate(%v) = %v; want %v", tt.ip, private, tt.private)
   767  			}
   768  
   769  			unspecified := tt.ip.IsUnspecified()
   770  			if unspecified != tt.unspecified {
   771  				t.Errorf("IsUnspecified(%v) = %v; want %v", tt.ip, unspecified, tt.unspecified)
   772  			}
   773  		})
   774  	}
   775  }
   776  
   777  func TestAddrWellKnown(t *testing.T) {
   778  	tests := []struct {
   779  		name string
   780  		ip   Addr
   781  		std  net.IP
   782  	}{
   783  		{
   784  			name: "IPv6 link-local all nodes",
   785  			ip:   IPv6LinkLocalAllNodes(),
   786  			std:  net.IPv6linklocalallnodes,
   787  		},
   788  		{
   789  			name: "IPv6 link-local all routers",
   790  			ip:   IPv6LinkLocalAllRouters(),
   791  			std:  net.IPv6linklocalallrouters,
   792  		},
   793  		{
   794  			name: "IPv6 loopback",
   795  			ip:   IPv6Loopback(),
   796  			std:  net.IPv6loopback,
   797  		},
   798  		{
   799  			name: "IPv6 unspecified",
   800  			ip:   IPv6Unspecified(),
   801  			std:  net.IPv6unspecified,
   802  		},
   803  	}
   804  
   805  	for _, tt := range tests {
   806  		t.Run(tt.name, func(t *testing.T) {
   807  			want := tt.std.String()
   808  			got := tt.ip.String()
   809  
   810  			if got != want {
   811  				t.Fatalf("got %s, want %s", got, want)
   812  			}
   813  		})
   814  	}
   815  }
   816  
   817  func TestAddrLessCompare(t *testing.T) {
   818  	tests := []struct {
   819  		a, b Addr
   820  		want bool
   821  	}{
   822  		{Addr{}, Addr{}, false},
   823  		{Addr{}, mustIP("1.2.3.4"), true},
   824  		{mustIP("1.2.3.4"), Addr{}, false},
   825  
   826  		{mustIP("1.2.3.4"), mustIP("0102:0304::0"), true},
   827  		{mustIP("0102:0304::0"), mustIP("1.2.3.4"), false},
   828  		{mustIP("1.2.3.4"), mustIP("1.2.3.4"), false},
   829  
   830  		{mustIP("::1"), mustIP("::2"), true},
   831  		{mustIP("::1"), mustIP("::1%foo"), true},
   832  		{mustIP("::1%foo"), mustIP("::2"), true},
   833  		{mustIP("::2"), mustIP("::3"), true},
   834  
   835  		{mustIP("::"), mustIP("0.0.0.0"), false},
   836  		{mustIP("0.0.0.0"), mustIP("::"), true},
   837  
   838  		{mustIP("::1%a"), mustIP("::1%b"), true},
   839  		{mustIP("::1%a"), mustIP("::1%a"), false},
   840  		{mustIP("::1%b"), mustIP("::1%a"), false},
   841  	}
   842  	for _, tt := range tests {
   843  		got := tt.a.Less(tt.b)
   844  		if got != tt.want {
   845  			t.Errorf("Less(%q, %q) = %v; want %v", tt.a, tt.b, got, tt.want)
   846  		}
   847  		cmp := tt.a.Compare(tt.b)
   848  		if got && cmp != -1 {
   849  			t.Errorf("Less(%q, %q) = true, but Compare = %v (not -1)", tt.a, tt.b, cmp)
   850  		}
   851  		if cmp < -1 || cmp > 1 {
   852  			t.Errorf("bogus Compare return value %v", cmp)
   853  		}
   854  		if cmp == 0 && tt.a != tt.b {
   855  			t.Errorf("Compare(%q, %q) = 0; but not equal", tt.a, tt.b)
   856  		}
   857  		if cmp == 1 && !tt.b.Less(tt.a) {
   858  			t.Errorf("Compare(%q, %q) = 1; but b.Less(a) isn't true", tt.a, tt.b)
   859  		}
   860  
   861  		// Also check inverse.
   862  		if got == tt.want && got {
   863  			got2 := tt.b.Less(tt.a)
   864  			if got2 {
   865  				t.Errorf("Less(%q, %q) was correctly %v, but so was Less(%q, %q)", tt.a, tt.b, got, tt.b, tt.a)
   866  			}
   867  		}
   868  	}
   869  
   870  	// And just sort.
   871  	values := []Addr{
   872  		mustIP("::1"),
   873  		mustIP("::2"),
   874  		Addr{},
   875  		mustIP("1.2.3.4"),
   876  		mustIP("8.8.8.8"),
   877  		mustIP("::1%foo"),
   878  	}
   879  	sort.Slice(values, func(i, j int) bool { return values[i].Less(values[j]) })
   880  	got := fmt.Sprintf("%s", values)
   881  	want := `[invalid IP 1.2.3.4 8.8.8.8 ::1 ::1%foo ::2]`
   882  	if got != want {
   883  		t.Errorf("unexpected sort\n got: %s\nwant: %s\n", got, want)
   884  	}
   885  }
   886  
   887  func TestAddrPortCompare(t *testing.T) {
   888  	tests := []struct {
   889  		a, b AddrPort
   890  		want int
   891  	}{
   892  		{AddrPort{}, AddrPort{}, 0},
   893  		{AddrPort{}, mustIPPort("1.2.3.4:80"), -1},
   894  
   895  		{mustIPPort("1.2.3.4:80"), mustIPPort("1.2.3.4:80"), 0},
   896  		{mustIPPort("[::1]:80"), mustIPPort("[::1]:80"), 0},
   897  
   898  		{mustIPPort("1.2.3.4:80"), mustIPPort("2.3.4.5:22"), -1},
   899  		{mustIPPort("[::1]:80"), mustIPPort("[::2]:22"), -1},
   900  
   901  		{mustIPPort("1.2.3.4:80"), mustIPPort("1.2.3.4:443"), -1},
   902  		{mustIPPort("[::1]:80"), mustIPPort("[::1]:443"), -1},
   903  
   904  		{mustIPPort("1.2.3.4:80"), mustIPPort("[0102:0304::0]:80"), -1},
   905  	}
   906  	for _, tt := range tests {
   907  		got := tt.a.Compare(tt.b)
   908  		if got != tt.want {
   909  			t.Errorf("Compare(%q, %q) = %v; want %v", tt.a, tt.b, got, tt.want)
   910  		}
   911  
   912  		// Also check inverse.
   913  		if got == tt.want {
   914  			got2 := tt.b.Compare(tt.a)
   915  			if want2 := -1 * tt.want; got2 != want2 {
   916  				t.Errorf("Compare(%q, %q) was correctly %v, but Compare(%q, %q) was %v", tt.a, tt.b, got, tt.b, tt.a, got2)
   917  			}
   918  		}
   919  	}
   920  
   921  	// And just sort.
   922  	values := []AddrPort{
   923  		mustIPPort("[::1]:80"),
   924  		mustIPPort("[::2]:80"),
   925  		AddrPort{},
   926  		mustIPPort("1.2.3.4:443"),
   927  		mustIPPort("8.8.8.8:8080"),
   928  		mustIPPort("[::1%foo]:1024"),
   929  	}
   930  	slices.SortFunc(values, func(a, b AddrPort) int { return a.Compare(b) })
   931  	got := fmt.Sprintf("%s", values)
   932  	want := `[invalid AddrPort 1.2.3.4:443 8.8.8.8:8080 [::1]:80 [::1%foo]:1024 [::2]:80]`
   933  	if got != want {
   934  		t.Errorf("unexpected sort\n got: %s\nwant: %s\n", got, want)
   935  	}
   936  }
   937  
   938  func TestPrefixCompare(t *testing.T) {
   939  	tests := []struct {
   940  		a, b Prefix
   941  		want int
   942  	}{
   943  		{Prefix{}, Prefix{}, 0},
   944  		{Prefix{}, mustPrefix("1.2.3.0/24"), -1},
   945  
   946  		{mustPrefix("1.2.3.0/24"), mustPrefix("1.2.3.0/24"), 0},
   947  		{mustPrefix("fe80::/64"), mustPrefix("fe80::/64"), 0},
   948  
   949  		{mustPrefix("1.2.3.0/24"), mustPrefix("1.2.4.0/24"), -1},
   950  		{mustPrefix("fe80::/64"), mustPrefix("fe90::/64"), -1},
   951  
   952  		{mustPrefix("1.2.0.0/16"), mustPrefix("1.2.0.0/24"), -1},
   953  		{mustPrefix("fe80::/48"), mustPrefix("fe80::/64"), -1},
   954  
   955  		{mustPrefix("1.2.3.0/24"), mustPrefix("fe80::/8"), -1},
   956  	}
   957  	for _, tt := range tests {
   958  		got := tt.a.Compare(tt.b)
   959  		if got != tt.want {
   960  			t.Errorf("Compare(%q, %q) = %v; want %v", tt.a, tt.b, got, tt.want)
   961  		}
   962  
   963  		// Also check inverse.
   964  		if got == tt.want {
   965  			got2 := tt.b.Compare(tt.a)
   966  			if want2 := -1 * tt.want; got2 != want2 {
   967  				t.Errorf("Compare(%q, %q) was correctly %v, but Compare(%q, %q) was %v", tt.a, tt.b, got, tt.b, tt.a, got2)
   968  			}
   969  		}
   970  	}
   971  
   972  	// And just sort.
   973  	values := []Prefix{
   974  		mustPrefix("1.2.3.0/24"),
   975  		mustPrefix("fe90::/64"),
   976  		mustPrefix("fe80::/64"),
   977  		mustPrefix("1.2.0.0/16"),
   978  		Prefix{},
   979  		mustPrefix("fe80::/48"),
   980  		mustPrefix("1.2.0.0/24"),
   981  	}
   982  	slices.SortFunc(values, func(a, b Prefix) int { return a.Compare(b) })
   983  	got := fmt.Sprintf("%s", values)
   984  	want := `[invalid Prefix 1.2.0.0/16 1.2.0.0/24 1.2.3.0/24 fe80::/48 fe80::/64 fe90::/64]`
   985  	if got != want {
   986  		t.Errorf("unexpected sort\n got: %s\nwant: %s\n", got, want)
   987  	}
   988  }
   989  
   990  func TestIPStringExpanded(t *testing.T) {
   991  	tests := []struct {
   992  		ip Addr
   993  		s  string
   994  	}{
   995  		{
   996  			ip: Addr{},
   997  			s:  "invalid IP",
   998  		},
   999  		{
  1000  			ip: mustIP("192.0.2.1"),
  1001  			s:  "192.0.2.1",
  1002  		},
  1003  		{
  1004  			ip: mustIP("::ffff:192.0.2.1"),
  1005  			s:  "0000:0000:0000:0000:0000:ffff:c000:0201",
  1006  		},
  1007  		{
  1008  			ip: mustIP("2001:db8::1"),
  1009  			s:  "2001:0db8:0000:0000:0000:0000:0000:0001",
  1010  		},
  1011  		{
  1012  			ip: mustIP("2001:db8::1%eth0"),
  1013  			s:  "2001:0db8:0000:0000:0000:0000:0000:0001%eth0",
  1014  		},
  1015  	}
  1016  
  1017  	for _, tt := range tests {
  1018  		t.Run(tt.ip.String(), func(t *testing.T) {
  1019  			want := tt.s
  1020  			got := tt.ip.StringExpanded()
  1021  
  1022  			if got != want {
  1023  				t.Fatalf("got %s, want %s", got, want)
  1024  			}
  1025  		})
  1026  	}
  1027  }
  1028  
  1029  func TestPrefixMasking(t *testing.T) {
  1030  	type subtest struct {
  1031  		ip   Addr
  1032  		bits uint8
  1033  		p    Prefix
  1034  		ok   bool
  1035  	}
  1036  
  1037  	// makeIPv6 produces a set of IPv6 subtests with an optional zone identifier.
  1038  	makeIPv6 := func(zone string) []subtest {
  1039  		if zone != "" {
  1040  			zone = "%" + zone
  1041  		}
  1042  
  1043  		return []subtest{
  1044  			{
  1045  				ip:   mustIP(fmt.Sprintf("2001:db8::1%s", zone)),
  1046  				bits: 255,
  1047  			},
  1048  			{
  1049  				ip:   mustIP(fmt.Sprintf("2001:db8::1%s", zone)),
  1050  				bits: 32,
  1051  				p:    mustPrefix("2001:db8::/32"),
  1052  				ok:   true,
  1053  			},
  1054  			{
  1055  				ip:   mustIP(fmt.Sprintf("fe80::dead:beef:dead:beef%s", zone)),
  1056  				bits: 96,
  1057  				p:    mustPrefix("fe80::dead:beef:0:0/96"),
  1058  				ok:   true,
  1059  			},
  1060  			{
  1061  				ip:   mustIP(fmt.Sprintf("aaaa::%s", zone)),
  1062  				bits: 4,
  1063  				p:    mustPrefix("a000::/4"),
  1064  				ok:   true,
  1065  			},
  1066  			{
  1067  				ip:   mustIP(fmt.Sprintf("::%s", zone)),
  1068  				bits: 63,
  1069  				p:    mustPrefix("::/63"),
  1070  				ok:   true,
  1071  			},
  1072  		}
  1073  	}
  1074  
  1075  	tests := []struct {
  1076  		family   string
  1077  		subtests []subtest
  1078  	}{
  1079  		{
  1080  			family: "nil",
  1081  			subtests: []subtest{
  1082  				{
  1083  					bits: 255,
  1084  					ok:   true,
  1085  				},
  1086  				{
  1087  					bits: 16,
  1088  					ok:   true,
  1089  				},
  1090  			},
  1091  		},
  1092  		{
  1093  			family: "IPv4",
  1094  			subtests: []subtest{
  1095  				{
  1096  					ip:   mustIP("192.0.2.0"),
  1097  					bits: 255,
  1098  				},
  1099  				{
  1100  					ip:   mustIP("192.0.2.0"),
  1101  					bits: 16,
  1102  					p:    mustPrefix("192.0.0.0/16"),
  1103  					ok:   true,
  1104  				},
  1105  				{
  1106  					ip:   mustIP("255.255.255.255"),
  1107  					bits: 20,
  1108  					p:    mustPrefix("255.255.240.0/20"),
  1109  					ok:   true,
  1110  				},
  1111  				{
  1112  					// Partially masking one byte that contains both
  1113  					// 1s and 0s on either side of the mask limit.
  1114  					ip:   mustIP("100.98.156.66"),
  1115  					bits: 10,
  1116  					p:    mustPrefix("100.64.0.0/10"),
  1117  					ok:   true,
  1118  				},
  1119  			},
  1120  		},
  1121  		{
  1122  			family:   "IPv6",
  1123  			subtests: makeIPv6(""),
  1124  		},
  1125  		{
  1126  			family:   "IPv6 zone",
  1127  			subtests: makeIPv6("eth0"),
  1128  		},
  1129  	}
  1130  
  1131  	for _, tt := range tests {
  1132  		t.Run(tt.family, func(t *testing.T) {
  1133  			for _, st := range tt.subtests {
  1134  				t.Run(st.p.String(), func(t *testing.T) {
  1135  					// Ensure st.ip is not mutated.
  1136  					orig := st.ip.String()
  1137  
  1138  					p, err := st.ip.Prefix(int(st.bits))
  1139  					if st.ok && err != nil {
  1140  						t.Fatalf("failed to produce prefix: %v", err)
  1141  					}
  1142  					if !st.ok && err == nil {
  1143  						t.Fatal("expected an error, but none occurred")
  1144  					}
  1145  					if err != nil {
  1146  						t.Logf("err: %v", err)
  1147  						return
  1148  					}
  1149  
  1150  					if !reflect.DeepEqual(p, st.p) {
  1151  						t.Errorf("prefix = %q, want %q", p, st.p)
  1152  					}
  1153  
  1154  					if got := st.ip.String(); got != orig {
  1155  						t.Errorf("IP was mutated: %q, want %q", got, orig)
  1156  					}
  1157  				})
  1158  			}
  1159  		})
  1160  	}
  1161  }
  1162  
  1163  func TestPrefixMarshalUnmarshal(t *testing.T) {
  1164  	tests := []string{
  1165  		"",
  1166  		"1.2.3.4/32",
  1167  		"0.0.0.0/0",
  1168  		"::/0",
  1169  		"::1/128",
  1170  		"2001:db8::/32",
  1171  	}
  1172  
  1173  	for _, s := range tests {
  1174  		t.Run(s, func(t *testing.T) {
  1175  			// Ensure that JSON  (and by extension, text) marshaling is
  1176  			// sane by entering quoted input.
  1177  			orig := `"` + s + `"`
  1178  
  1179  			var p Prefix
  1180  			if err := json.Unmarshal([]byte(orig), &p); err != nil {
  1181  				t.Fatalf("failed to unmarshal: %v", err)
  1182  			}
  1183  
  1184  			pb, err := json.Marshal(p)
  1185  			if err != nil {
  1186  				t.Fatalf("failed to marshal: %v", err)
  1187  			}
  1188  
  1189  			back := string(pb)
  1190  			if orig != back {
  1191  				t.Errorf("Marshal = %q; want %q", back, orig)
  1192  			}
  1193  		})
  1194  	}
  1195  }
  1196  
  1197  func TestPrefixUnmarshalTextNonZero(t *testing.T) {
  1198  	ip := mustPrefix("fe80::/64")
  1199  	if err := ip.UnmarshalText([]byte("xxx")); err == nil {
  1200  		t.Fatal("unmarshaled into non-empty Prefix")
  1201  	}
  1202  }
  1203  
  1204  func TestIs4AndIs6(t *testing.T) {
  1205  	tests := []struct {
  1206  		ip  Addr
  1207  		is4 bool
  1208  		is6 bool
  1209  	}{
  1210  		{Addr{}, false, false},
  1211  		{mustIP("1.2.3.4"), true, false},
  1212  		{mustIP("127.0.0.2"), true, false},
  1213  		{mustIP("::1"), false, true},
  1214  		{mustIP("::ffff:192.0.2.128"), false, true},
  1215  		{mustIP("::fffe:c000:0280"), false, true},
  1216  		{mustIP("::1%eth0"), false, true},
  1217  	}
  1218  	for _, tt := range tests {
  1219  		got4 := tt.ip.Is4()
  1220  		if got4 != tt.is4 {
  1221  			t.Errorf("Is4(%q) = %v; want %v", tt.ip, got4, tt.is4)
  1222  		}
  1223  
  1224  		got6 := tt.ip.Is6()
  1225  		if got6 != tt.is6 {
  1226  			t.Errorf("Is6(%q) = %v; want %v", tt.ip, got6, tt.is6)
  1227  		}
  1228  	}
  1229  }
  1230  
  1231  func TestIs4In6(t *testing.T) {
  1232  	tests := []struct {
  1233  		ip        Addr
  1234  		want      bool
  1235  		wantUnmap Addr
  1236  	}{
  1237  		{Addr{}, false, Addr{}},
  1238  		{mustIP("::ffff:c000:0280"), true, mustIP("192.0.2.128")},
  1239  		{mustIP("::ffff:192.0.2.128"), true, mustIP("192.0.2.128")},
  1240  		{mustIP("::ffff:192.0.2.128%eth0"), true, mustIP("192.0.2.128")},
  1241  		{mustIP("::fffe:c000:0280"), false, mustIP("::fffe:c000:0280")},
  1242  		{mustIP("::ffff:127.1.2.3"), true, mustIP("127.1.2.3")},
  1243  		{mustIP("::ffff:7f01:0203"), true, mustIP("127.1.2.3")},
  1244  		{mustIP("0:0:0:0:0000:ffff:127.1.2.3"), true, mustIP("127.1.2.3")},
  1245  		{mustIP("0:0:0:0:000000:ffff:127.1.2.3"), true, mustIP("127.1.2.3")},
  1246  		{mustIP("0:0:0:0::ffff:127.1.2.3"), true, mustIP("127.1.2.3")},
  1247  		{mustIP("::1"), false, mustIP("::1")},
  1248  		{mustIP("1.2.3.4"), false, mustIP("1.2.3.4")},
  1249  	}
  1250  	for _, tt := range tests {
  1251  		got := tt.ip.Is4In6()
  1252  		if got != tt.want {
  1253  			t.Errorf("Is4In6(%q) = %v; want %v", tt.ip, got, tt.want)
  1254  		}
  1255  		u := tt.ip.Unmap()
  1256  		if u != tt.wantUnmap {
  1257  			t.Errorf("Unmap(%q) = %v; want %v", tt.ip, u, tt.wantUnmap)
  1258  		}
  1259  	}
  1260  }
  1261  
  1262  func TestPrefixMasked(t *testing.T) {
  1263  	tests := []struct {
  1264  		prefix Prefix
  1265  		masked Prefix
  1266  	}{
  1267  		{
  1268  			prefix: mustPrefix("192.168.0.255/24"),
  1269  			masked: mustPrefix("192.168.0.0/24"),
  1270  		},
  1271  		{
  1272  			prefix: mustPrefix("2100::/3"),
  1273  			masked: mustPrefix("2000::/3"),
  1274  		},
  1275  		{
  1276  			prefix: PrefixFrom(mustIP("2000::"), 129),
  1277  			masked: Prefix{},
  1278  		},
  1279  		{
  1280  			prefix: PrefixFrom(mustIP("1.2.3.4"), 33),
  1281  			masked: Prefix{},
  1282  		},
  1283  	}
  1284  	for _, test := range tests {
  1285  		t.Run(test.prefix.String(), func(t *testing.T) {
  1286  			got := test.prefix.Masked()
  1287  			if got != test.masked {
  1288  				t.Errorf("Masked=%s, want %s", got, test.masked)
  1289  			}
  1290  		})
  1291  	}
  1292  }
  1293  
  1294  func TestPrefix(t *testing.T) {
  1295  	tests := []struct {
  1296  		prefix      string
  1297  		ip          Addr
  1298  		bits        int
  1299  		str         string
  1300  		contains    []Addr
  1301  		notContains []Addr
  1302  	}{
  1303  		{
  1304  			prefix:      "192.168.0.0/24",
  1305  			ip:          mustIP("192.168.0.0"),
  1306  			bits:        24,
  1307  			contains:    mustIPs("192.168.0.1", "192.168.0.55"),
  1308  			notContains: mustIPs("192.168.1.1", "1.1.1.1"),
  1309  		},
  1310  		{
  1311  			prefix:      "192.168.1.1/32",
  1312  			ip:          mustIP("192.168.1.1"),
  1313  			bits:        32,
  1314  			contains:    mustIPs("192.168.1.1"),
  1315  			notContains: mustIPs("192.168.1.2"),
  1316  		},
  1317  		{
  1318  			prefix:      "100.64.0.0/10", // CGNAT range; prefix not multiple of 8
  1319  			ip:          mustIP("100.64.0.0"),
  1320  			bits:        10,
  1321  			contains:    mustIPs("100.64.0.0", "100.64.0.1", "100.81.251.94", "100.100.100.100", "100.127.255.254", "100.127.255.255"),
  1322  			notContains: mustIPs("100.63.255.255", "100.128.0.0"),
  1323  		},
  1324  		{
  1325  			prefix:      "2001:db8::/96",
  1326  			ip:          mustIP("2001:db8::"),
  1327  			bits:        96,
  1328  			contains:    mustIPs("2001:db8::aaaa:bbbb", "2001:db8::1"),
  1329  			notContains: mustIPs("2001:db8::1:aaaa:bbbb", "2001:db9::"),
  1330  		},
  1331  		{
  1332  			prefix:      "0.0.0.0/0",
  1333  			ip:          mustIP("0.0.0.0"),
  1334  			bits:        0,
  1335  			contains:    mustIPs("192.168.0.1", "1.1.1.1"),
  1336  			notContains: append(mustIPs("2001:db8::1"), Addr{}),
  1337  		},
  1338  		{
  1339  			prefix:      "::/0",
  1340  			ip:          mustIP("::"),
  1341  			bits:        0,
  1342  			contains:    mustIPs("::1", "2001:db8::1"),
  1343  			notContains: mustIPs("192.0.2.1"),
  1344  		},
  1345  		{
  1346  			prefix:      "2000::/3",
  1347  			ip:          mustIP("2000::"),
  1348  			bits:        3,
  1349  			contains:    mustIPs("2001:db8::1"),
  1350  			notContains: mustIPs("fe80::1"),
  1351  		},
  1352  	}
  1353  	for _, test := range tests {
  1354  		t.Run(test.prefix, func(t *testing.T) {
  1355  			prefix, err := ParsePrefix(test.prefix)
  1356  			if err != nil {
  1357  				t.Fatal(err)
  1358  			}
  1359  			if prefix.Addr() != test.ip {
  1360  				t.Errorf("IP=%s, want %s", prefix.Addr(), test.ip)
  1361  			}
  1362  			if prefix.Bits() != test.bits {
  1363  				t.Errorf("bits=%d, want %d", prefix.Bits(), test.bits)
  1364  			}
  1365  			for _, ip := range test.contains {
  1366  				if !prefix.Contains(ip) {
  1367  					t.Errorf("does not contain %s", ip)
  1368  				}
  1369  			}
  1370  			for _, ip := range test.notContains {
  1371  				if prefix.Contains(ip) {
  1372  					t.Errorf("contains %s", ip)
  1373  				}
  1374  			}
  1375  			want := test.str
  1376  			if want == "" {
  1377  				want = test.prefix
  1378  			}
  1379  			if got := prefix.String(); got != want {
  1380  				t.Errorf("prefix.String()=%q, want %q", got, want)
  1381  			}
  1382  
  1383  			TestAppendToMarshal(t, prefix)
  1384  		})
  1385  	}
  1386  }
  1387  
  1388  func TestPrefixFromInvalidBits(t *testing.T) {
  1389  	v4 := MustParseAddr("1.2.3.4")
  1390  	v6 := MustParseAddr("66::66")
  1391  	tests := []struct {
  1392  		ip       Addr
  1393  		in, want int
  1394  	}{
  1395  		{v4, 0, 0},
  1396  		{v6, 0, 0},
  1397  		{v4, 1, 1},
  1398  		{v4, 33, -1},
  1399  		{v6, 33, 33},
  1400  		{v6, 127, 127},
  1401  		{v6, 128, 128},
  1402  		{v4, 254, -1},
  1403  		{v4, 255, -1},
  1404  		{v4, -1, -1},
  1405  		{v6, -1, -1},
  1406  		{v4, -5, -1},
  1407  		{v6, -5, -1},
  1408  	}
  1409  	for _, tt := range tests {
  1410  		p := PrefixFrom(tt.ip, tt.in)
  1411  		if got := p.Bits(); got != tt.want {
  1412  			t.Errorf("for (%v, %v), Bits out = %v; want %v", tt.ip, tt.in, got, tt.want)
  1413  		}
  1414  	}
  1415  }
  1416  
  1417  func TestParsePrefixAllocs(t *testing.T) {
  1418  	tests := []struct {
  1419  		ip    string
  1420  		slash string
  1421  	}{
  1422  		{"192.168.1.0", "/24"},
  1423  		{"aaaa:bbbb:cccc::", "/24"},
  1424  	}
  1425  	for _, test := range tests {
  1426  		prefix := test.ip + test.slash
  1427  		t.Run(prefix, func(t *testing.T) {
  1428  			ipAllocs := int(testing.AllocsPerRun(5, func() {
  1429  				ParseAddr(test.ip)
  1430  			}))
  1431  			prefixAllocs := int(testing.AllocsPerRun(5, func() {
  1432  				ParsePrefix(prefix)
  1433  			}))
  1434  			if got := prefixAllocs - ipAllocs; got != 0 {
  1435  				t.Errorf("allocs=%d, want 0", got)
  1436  			}
  1437  		})
  1438  	}
  1439  }
  1440  
  1441  func TestParsePrefixError(t *testing.T) {
  1442  	tests := []struct {
  1443  		prefix string
  1444  		errstr string
  1445  	}{
  1446  		{
  1447  			prefix: "192.168.0.0",
  1448  			errstr: "no '/'",
  1449  		},
  1450  		{
  1451  			prefix: "1.257.1.1/24",
  1452  			errstr: "value >255",
  1453  		},
  1454  		{
  1455  			prefix: "1.1.1.0/q",
  1456  			errstr: "bad bits",
  1457  		},
  1458  		{
  1459  			prefix: "1.1.1.0/-1",
  1460  			errstr: "bad bits",
  1461  		},
  1462  		{
  1463  			prefix: "1.1.1.0/33",
  1464  			errstr: "out of range",
  1465  		},
  1466  		{
  1467  			prefix: "2001::/129",
  1468  			errstr: "out of range",
  1469  		},
  1470  		// Zones are not allowed: https://go.dev/issue/51899
  1471  		{
  1472  			prefix: "1.1.1.0%a/24",
  1473  			errstr: "unexpected character",
  1474  		},
  1475  		{
  1476  			prefix: "2001:db8::%a/32",
  1477  			errstr: "zones cannot be present",
  1478  		},
  1479  		{
  1480  			prefix: "1.1.1.0/+32",
  1481  			errstr: "bad bits",
  1482  		},
  1483  		{
  1484  			prefix: "1.1.1.0/-32",
  1485  			errstr: "bad bits",
  1486  		},
  1487  		{
  1488  			prefix: "1.1.1.0/032",
  1489  			errstr: "bad bits",
  1490  		},
  1491  		{
  1492  			prefix: "1.1.1.0/0032",
  1493  			errstr: "bad bits",
  1494  		},
  1495  	}
  1496  	for _, test := range tests {
  1497  		t.Run(test.prefix, func(t *testing.T) {
  1498  			_, err := ParsePrefix(test.prefix)
  1499  			if err == nil {
  1500  				t.Fatal("no error")
  1501  			}
  1502  			if got := err.Error(); !strings.Contains(got, test.errstr) {
  1503  				t.Errorf("error is missing substring %q: %s", test.errstr, got)
  1504  			}
  1505  		})
  1506  	}
  1507  }
  1508  
  1509  func TestPrefixIsSingleIP(t *testing.T) {
  1510  	tests := []struct {
  1511  		ipp  Prefix
  1512  		want bool
  1513  	}{
  1514  		{ipp: mustPrefix("127.0.0.1/32"), want: true},
  1515  		{ipp: mustPrefix("127.0.0.1/31"), want: false},
  1516  		{ipp: mustPrefix("127.0.0.1/0"), want: false},
  1517  		{ipp: mustPrefix("::1/128"), want: true},
  1518  		{ipp: mustPrefix("::1/127"), want: false},
  1519  		{ipp: mustPrefix("::1/0"), want: false},
  1520  		{ipp: Prefix{}, want: false},
  1521  	}
  1522  	for _, tt := range tests {
  1523  		got := tt.ipp.IsSingleIP()
  1524  		if got != tt.want {
  1525  			t.Errorf("IsSingleIP(%v) = %v want %v", tt.ipp, got, tt.want)
  1526  		}
  1527  	}
  1528  }
  1529  
  1530  func mustIPs(strs ...string) []Addr {
  1531  	var res []Addr
  1532  	for _, s := range strs {
  1533  		res = append(res, mustIP(s))
  1534  	}
  1535  	return res
  1536  }
  1537  
  1538  func BenchmarkBinaryMarshalRoundTrip(b *testing.B) {
  1539  	b.ReportAllocs()
  1540  	tests := []struct {
  1541  		name string
  1542  		ip   string
  1543  	}{
  1544  		{"ipv4", "1.2.3.4"},
  1545  		{"ipv6", "2001:db8::1"},
  1546  		{"ipv6+zone", "2001:db8::1%eth0"},
  1547  	}
  1548  	for _, tc := range tests {
  1549  		b.Run(tc.name, func(b *testing.B) {
  1550  			ip := mustIP(tc.ip)
  1551  			for i := 0; i < b.N; i++ {
  1552  				bt, err := ip.MarshalBinary()
  1553  				if err != nil {
  1554  					b.Fatal(err)
  1555  				}
  1556  				var ip2 Addr
  1557  				if err := ip2.UnmarshalBinary(bt); err != nil {
  1558  					b.Fatal(err)
  1559  				}
  1560  			}
  1561  		})
  1562  	}
  1563  }
  1564  
  1565  func BenchmarkStdIPv4(b *testing.B) {
  1566  	b.ReportAllocs()
  1567  	ips := []net.IP{}
  1568  	for i := 0; i < b.N; i++ {
  1569  		ip := net.IPv4(8, 8, 8, 8)
  1570  		ips = ips[:0]
  1571  		for i := 0; i < 100; i++ {
  1572  			ips = append(ips, ip)
  1573  		}
  1574  	}
  1575  }
  1576  
  1577  func BenchmarkIPv4(b *testing.B) {
  1578  	b.ReportAllocs()
  1579  	ips := []Addr{}
  1580  	for i := 0; i < b.N; i++ {
  1581  		ip := IPv4(8, 8, 8, 8)
  1582  		ips = ips[:0]
  1583  		for i := 0; i < 100; i++ {
  1584  			ips = append(ips, ip)
  1585  		}
  1586  	}
  1587  }
  1588  
  1589  // ip4i was one of the possible representations of IP that came up in
  1590  // discussions, inlining IPv4 addresses, but having an "overflow"
  1591  // interface for IPv6 or IPv6 + zone. This is here for benchmarking.
  1592  type ip4i struct {
  1593  	ip4    [4]byte
  1594  	flags1 byte
  1595  	flags2 byte
  1596  	flags3 byte
  1597  	flags4 byte
  1598  	ipv6   any
  1599  }
  1600  
  1601  func newip4i_v4(a, b, c, d byte) ip4i {
  1602  	return ip4i{ip4: [4]byte{a, b, c, d}}
  1603  }
  1604  
  1605  // BenchmarkIPv4_inline benchmarks the candidate representation, ip4i.
  1606  func BenchmarkIPv4_inline(b *testing.B) {
  1607  	b.ReportAllocs()
  1608  	ips := []ip4i{}
  1609  	for i := 0; i < b.N; i++ {
  1610  		ip := newip4i_v4(8, 8, 8, 8)
  1611  		ips = ips[:0]
  1612  		for i := 0; i < 100; i++ {
  1613  			ips = append(ips, ip)
  1614  		}
  1615  	}
  1616  }
  1617  
  1618  func BenchmarkStdIPv6(b *testing.B) {
  1619  	b.ReportAllocs()
  1620  	ips := []net.IP{}
  1621  	for i := 0; i < b.N; i++ {
  1622  		ip := net.ParseIP("2001:db8::1")
  1623  		ips = ips[:0]
  1624  		for i := 0; i < 100; i++ {
  1625  			ips = append(ips, ip)
  1626  		}
  1627  	}
  1628  }
  1629  
  1630  func BenchmarkIPv6(b *testing.B) {
  1631  	b.ReportAllocs()
  1632  	ips := []Addr{}
  1633  	for i := 0; i < b.N; i++ {
  1634  		ip := mustIP("2001:db8::1")
  1635  		ips = ips[:0]
  1636  		for i := 0; i < 100; i++ {
  1637  			ips = append(ips, ip)
  1638  		}
  1639  	}
  1640  }
  1641  
  1642  func BenchmarkIPv4Contains(b *testing.B) {
  1643  	b.ReportAllocs()
  1644  	prefix := PrefixFrom(IPv4(192, 168, 1, 0), 24)
  1645  	ip := IPv4(192, 168, 1, 1)
  1646  	for i := 0; i < b.N; i++ {
  1647  		prefix.Contains(ip)
  1648  	}
  1649  }
  1650  
  1651  func BenchmarkIPv6Contains(b *testing.B) {
  1652  	b.ReportAllocs()
  1653  	prefix := MustParsePrefix("::1/128")
  1654  	ip := MustParseAddr("::1")
  1655  	for i := 0; i < b.N; i++ {
  1656  		prefix.Contains(ip)
  1657  	}
  1658  }
  1659  
  1660  var parseBenchInputs = []struct {
  1661  	name string
  1662  	ip   string
  1663  }{
  1664  	{"v4", "192.168.1.1"},
  1665  	{"v6", "fd7a:115c:a1e0:ab12:4843:cd96:626b:430b"},
  1666  	{"v6_ellipsis", "fd7a:115c::626b:430b"},
  1667  	{"v6_v4", "::ffff:192.168.140.255"},
  1668  	{"v6_zone", "1:2::ffff:192.168.140.255%eth1"},
  1669  }
  1670  
  1671  func BenchmarkParseAddr(b *testing.B) {
  1672  	sinkInternValue = intern.Get("eth1") // Pin to not benchmark the intern package
  1673  	for _, test := range parseBenchInputs {
  1674  		b.Run(test.name, func(b *testing.B) {
  1675  			b.ReportAllocs()
  1676  			for i := 0; i < b.N; i++ {
  1677  				sinkIP, _ = ParseAddr(test.ip)
  1678  			}
  1679  		})
  1680  	}
  1681  }
  1682  
  1683  func BenchmarkStdParseIP(b *testing.B) {
  1684  	for _, test := range parseBenchInputs {
  1685  		b.Run(test.name, func(b *testing.B) {
  1686  			b.ReportAllocs()
  1687  			for i := 0; i < b.N; i++ {
  1688  				sinkStdIP = net.ParseIP(test.ip)
  1689  			}
  1690  		})
  1691  	}
  1692  }
  1693  
  1694  func BenchmarkIPString(b *testing.B) {
  1695  	for _, test := range parseBenchInputs {
  1696  		ip := MustParseAddr(test.ip)
  1697  		b.Run(test.name, func(b *testing.B) {
  1698  			b.ReportAllocs()
  1699  			for i := 0; i < b.N; i++ {
  1700  				sinkString = ip.String()
  1701  			}
  1702  		})
  1703  	}
  1704  }
  1705  
  1706  func BenchmarkIPStringExpanded(b *testing.B) {
  1707  	for _, test := range parseBenchInputs {
  1708  		ip := MustParseAddr(test.ip)
  1709  		b.Run(test.name, func(b *testing.B) {
  1710  			b.ReportAllocs()
  1711  			for i := 0; i < b.N; i++ {
  1712  				sinkString = ip.StringExpanded()
  1713  			}
  1714  		})
  1715  	}
  1716  }
  1717  
  1718  func BenchmarkIPMarshalText(b *testing.B) {
  1719  	b.ReportAllocs()
  1720  	ip := MustParseAddr("66.55.44.33")
  1721  	for i := 0; i < b.N; i++ {
  1722  		sinkBytes, _ = ip.MarshalText()
  1723  	}
  1724  }
  1725  
  1726  func BenchmarkAddrPortString(b *testing.B) {
  1727  	for _, test := range parseBenchInputs {
  1728  		ip := MustParseAddr(test.ip)
  1729  		ipp := AddrPortFrom(ip, 60000)
  1730  		b.Run(test.name, func(b *testing.B) {
  1731  			b.ReportAllocs()
  1732  			for i := 0; i < b.N; i++ {
  1733  				sinkString = ipp.String()
  1734  			}
  1735  		})
  1736  	}
  1737  }
  1738  
  1739  func BenchmarkAddrPortMarshalText(b *testing.B) {
  1740  	for _, test := range parseBenchInputs {
  1741  		ip := MustParseAddr(test.ip)
  1742  		ipp := AddrPortFrom(ip, 60000)
  1743  		b.Run(test.name, func(b *testing.B) {
  1744  			b.ReportAllocs()
  1745  			for i := 0; i < b.N; i++ {
  1746  				sinkBytes, _ = ipp.MarshalText()
  1747  			}
  1748  		})
  1749  	}
  1750  }
  1751  
  1752  func BenchmarkPrefixMasking(b *testing.B) {
  1753  	tests := []struct {
  1754  		name string
  1755  		ip   Addr
  1756  		bits int
  1757  	}{
  1758  		{
  1759  			name: "IPv4 /32",
  1760  			ip:   IPv4(192, 0, 2, 0),
  1761  			bits: 32,
  1762  		},
  1763  		{
  1764  			name: "IPv4 /17",
  1765  			ip:   IPv4(192, 0, 2, 0),
  1766  			bits: 17,
  1767  		},
  1768  		{
  1769  			name: "IPv4 /0",
  1770  			ip:   IPv4(192, 0, 2, 0),
  1771  			bits: 0,
  1772  		},
  1773  		{
  1774  			name: "IPv6 /128",
  1775  			ip:   mustIP("2001:db8::1"),
  1776  			bits: 128,
  1777  		},
  1778  		{
  1779  			name: "IPv6 /65",
  1780  			ip:   mustIP("2001:db8::1"),
  1781  			bits: 65,
  1782  		},
  1783  		{
  1784  			name: "IPv6 /0",
  1785  			ip:   mustIP("2001:db8::1"),
  1786  			bits: 0,
  1787  		},
  1788  		{
  1789  			name: "IPv6 zone /128",
  1790  			ip:   mustIP("2001:db8::1%eth0"),
  1791  			bits: 128,
  1792  		},
  1793  		{
  1794  			name: "IPv6 zone /65",
  1795  			ip:   mustIP("2001:db8::1%eth0"),
  1796  			bits: 65,
  1797  		},
  1798  		{
  1799  			name: "IPv6 zone /0",
  1800  			ip:   mustIP("2001:db8::1%eth0"),
  1801  			bits: 0,
  1802  		},
  1803  	}
  1804  
  1805  	for _, tt := range tests {
  1806  		b.Run(tt.name, func(b *testing.B) {
  1807  			b.ReportAllocs()
  1808  
  1809  			for i := 0; i < b.N; i++ {
  1810  				sinkPrefix, _ = tt.ip.Prefix(tt.bits)
  1811  			}
  1812  		})
  1813  	}
  1814  }
  1815  
  1816  func BenchmarkPrefixMarshalText(b *testing.B) {
  1817  	b.ReportAllocs()
  1818  	ipp := MustParsePrefix("66.55.44.33/22")
  1819  	for i := 0; i < b.N; i++ {
  1820  		sinkBytes, _ = ipp.MarshalText()
  1821  	}
  1822  }
  1823  
  1824  func BenchmarkParseAddrPort(b *testing.B) {
  1825  	for _, test := range parseBenchInputs {
  1826  		var ipp string
  1827  		if strings.HasPrefix(test.name, "v6") {
  1828  			ipp = fmt.Sprintf("[%s]:1234", test.ip)
  1829  		} else {
  1830  			ipp = fmt.Sprintf("%s:1234", test.ip)
  1831  		}
  1832  		b.Run(test.name, func(b *testing.B) {
  1833  			b.ReportAllocs()
  1834  
  1835  			for i := 0; i < b.N; i++ {
  1836  				sinkAddrPort, _ = ParseAddrPort(ipp)
  1837  			}
  1838  		})
  1839  	}
  1840  }
  1841  
  1842  func TestAs4(t *testing.T) {
  1843  	tests := []struct {
  1844  		ip        Addr
  1845  		want      [4]byte
  1846  		wantPanic bool
  1847  	}{
  1848  		{
  1849  			ip:   mustIP("1.2.3.4"),
  1850  			want: [4]byte{1, 2, 3, 4},
  1851  		},
  1852  		{
  1853  			ip:   AddrFrom16(mustIP("1.2.3.4").As16()), // IPv4-in-IPv6
  1854  			want: [4]byte{1, 2, 3, 4},
  1855  		},
  1856  		{
  1857  			ip:   mustIP("0.0.0.0"),
  1858  			want: [4]byte{0, 0, 0, 0},
  1859  		},
  1860  		{
  1861  			ip:        Addr{},
  1862  			wantPanic: true,
  1863  		},
  1864  		{
  1865  			ip:        mustIP("::1"),
  1866  			wantPanic: true,
  1867  		},
  1868  	}
  1869  	as4 := func(ip Addr) (v [4]byte, gotPanic bool) {
  1870  		defer func() {
  1871  			if recover() != nil {
  1872  				gotPanic = true
  1873  				return
  1874  			}
  1875  		}()
  1876  		v = ip.As4()
  1877  		return
  1878  	}
  1879  	for i, tt := range tests {
  1880  		got, gotPanic := as4(tt.ip)
  1881  		if gotPanic != tt.wantPanic {
  1882  			t.Errorf("%d. panic on %v = %v; want %v", i, tt.ip, gotPanic, tt.wantPanic)
  1883  			continue
  1884  		}
  1885  		if got != tt.want {
  1886  			t.Errorf("%d. %v = %v; want %v", i, tt.ip, got, tt.want)
  1887  		}
  1888  	}
  1889  }
  1890  
  1891  func TestPrefixOverlaps(t *testing.T) {
  1892  	pfx := mustPrefix
  1893  	tests := []struct {
  1894  		a, b Prefix
  1895  		want bool
  1896  	}{
  1897  		{Prefix{}, pfx("1.2.0.0/16"), false},    // first zero
  1898  		{pfx("1.2.0.0/16"), Prefix{}, false},    // second zero
  1899  		{pfx("::0/3"), pfx("0.0.0.0/3"), false}, // different families
  1900  
  1901  		{pfx("1.2.0.0/16"), pfx("1.2.0.0/16"), true}, // equal
  1902  
  1903  		{pfx("1.2.0.0/16"), pfx("1.2.3.0/24"), true},
  1904  		{pfx("1.2.3.0/24"), pfx("1.2.0.0/16"), true},
  1905  
  1906  		{pfx("1.2.0.0/16"), pfx("1.2.3.0/32"), true},
  1907  		{pfx("1.2.3.0/32"), pfx("1.2.0.0/16"), true},
  1908  
  1909  		// Match /0 either order
  1910  		{pfx("1.2.3.0/32"), pfx("0.0.0.0/0"), true},
  1911  		{pfx("0.0.0.0/0"), pfx("1.2.3.0/32"), true},
  1912  
  1913  		{pfx("1.2.3.0/32"), pfx("5.5.5.5/0"), true}, // normalization not required; /0 means true
  1914  
  1915  		// IPv6 overlapping
  1916  		{pfx("5::1/128"), pfx("5::0/8"), true},
  1917  		{pfx("5::0/8"), pfx("5::1/128"), true},
  1918  
  1919  		// IPv6 not overlapping
  1920  		{pfx("1::1/128"), pfx("2::2/128"), false},
  1921  		{pfx("0100::0/8"), pfx("::1/128"), false},
  1922  
  1923  		// IPv4-mapped IPv6 addresses should not overlap with IPv4.
  1924  		{PrefixFrom(AddrFrom16(mustIP("1.2.0.0").As16()), 16), pfx("1.2.3.0/24"), false},
  1925  
  1926  		// Invalid prefixes
  1927  		{PrefixFrom(mustIP("1.2.3.4"), 33), pfx("1.2.3.0/24"), false},
  1928  		{PrefixFrom(mustIP("2000::"), 129), pfx("2000::/64"), false},
  1929  	}
  1930  	for i, tt := range tests {
  1931  		if got := tt.a.Overlaps(tt.b); got != tt.want {
  1932  			t.Errorf("%d. (%v).Overlaps(%v) = %v; want %v", i, tt.a, tt.b, got, tt.want)
  1933  		}
  1934  		// Overlaps is commutative
  1935  		if got := tt.b.Overlaps(tt.a); got != tt.want {
  1936  			t.Errorf("%d. (%v).Overlaps(%v) = %v; want %v", i, tt.b, tt.a, got, tt.want)
  1937  		}
  1938  	}
  1939  }
  1940  
  1941  // Sink variables are here to force the compiler to not elide
  1942  // seemingly useless work in benchmarks and allocation tests. If you
  1943  // were to just `_ = foo()` within a test function, the compiler could
  1944  // correctly deduce that foo() does nothing and doesn't need to be
  1945  // called. By writing results to a global variable, we hide that fact
  1946  // from the compiler and force it to keep the code under test.
  1947  var (
  1948  	sinkIP          Addr
  1949  	sinkStdIP       net.IP
  1950  	sinkAddrPort    AddrPort
  1951  	sinkPrefix      Prefix
  1952  	sinkPrefixSlice []Prefix
  1953  	sinkInternValue *intern.Value
  1954  	sinkIP16        [16]byte
  1955  	sinkIP4         [4]byte
  1956  	sinkBool        bool
  1957  	sinkString      string
  1958  	sinkBytes       []byte
  1959  	sinkUDPAddr     = &net.UDPAddr{IP: make(net.IP, 0, 16)}
  1960  )
  1961  
  1962  func TestNoAllocs(t *testing.T) {
  1963  	// Wrappers that panic on error, to prove that our alloc-free
  1964  	// methods are returning successfully.
  1965  	panicIP := func(ip Addr, err error) Addr {
  1966  		if err != nil {
  1967  			panic(err)
  1968  		}
  1969  		return ip
  1970  	}
  1971  	panicPfx := func(pfx Prefix, err error) Prefix {
  1972  		if err != nil {
  1973  			panic(err)
  1974  		}
  1975  		return pfx
  1976  	}
  1977  	panicIPP := func(ipp AddrPort, err error) AddrPort {
  1978  		if err != nil {
  1979  			panic(err)
  1980  		}
  1981  		return ipp
  1982  	}
  1983  	test := func(name string, f func()) {
  1984  		t.Run(name, func(t *testing.T) {
  1985  			n := testing.AllocsPerRun(1000, f)
  1986  			if n != 0 {
  1987  				t.Fatalf("allocs = %d; want 0", int(n))
  1988  			}
  1989  		})
  1990  	}
  1991  
  1992  	// Addr constructors
  1993  	test("IPv4", func() { sinkIP = IPv4(1, 2, 3, 4) })
  1994  	test("AddrFrom4", func() { sinkIP = AddrFrom4([4]byte{1, 2, 3, 4}) })
  1995  	test("AddrFrom16", func() { sinkIP = AddrFrom16([16]byte{}) })
  1996  	test("ParseAddr/4", func() { sinkIP = panicIP(ParseAddr("1.2.3.4")) })
  1997  	test("ParseAddr/6", func() { sinkIP = panicIP(ParseAddr("::1")) })
  1998  	test("MustParseAddr", func() { sinkIP = MustParseAddr("1.2.3.4") })
  1999  	test("IPv6LinkLocalAllNodes", func() { sinkIP = IPv6LinkLocalAllNodes() })
  2000  	test("IPv6LinkLocalAllRouters", func() { sinkIP = IPv6LinkLocalAllRouters() })
  2001  	test("IPv6Loopback", func() { sinkIP = IPv6Loopback() })
  2002  	test("IPv6Unspecified", func() { sinkIP = IPv6Unspecified() })
  2003  
  2004  	// Addr methods
  2005  	test("Addr.IsZero", func() { sinkBool = MustParseAddr("1.2.3.4").IsZero() })
  2006  	test("Addr.BitLen", func() { sinkBool = MustParseAddr("1.2.3.4").BitLen() == 8 })
  2007  	test("Addr.Zone/4", func() { sinkBool = MustParseAddr("1.2.3.4").Zone() == "" })
  2008  	test("Addr.Zone/6", func() { sinkBool = MustParseAddr("fe80::1").Zone() == "" })
  2009  	test("Addr.Zone/6zone", func() { sinkBool = MustParseAddr("fe80::1%zone").Zone() == "" })
  2010  	test("Addr.Compare", func() {
  2011  		a := MustParseAddr("1.2.3.4")
  2012  		b := MustParseAddr("2.3.4.5")
  2013  		sinkBool = a.Compare(b) == 0
  2014  	})
  2015  	test("Addr.Less", func() {
  2016  		a := MustParseAddr("1.2.3.4")
  2017  		b := MustParseAddr("2.3.4.5")
  2018  		sinkBool = a.Less(b)
  2019  	})
  2020  	test("Addr.Is4", func() { sinkBool = MustParseAddr("1.2.3.4").Is4() })
  2021  	test("Addr.Is6", func() { sinkBool = MustParseAddr("fe80::1").Is6() })
  2022  	test("Addr.Is4In6", func() { sinkBool = MustParseAddr("fe80::1").Is4In6() })
  2023  	test("Addr.Unmap", func() { sinkIP = MustParseAddr("ffff::2.3.4.5").Unmap() })
  2024  	test("Addr.WithZone", func() { sinkIP = MustParseAddr("fe80::1").WithZone("") })
  2025  	test("Addr.IsGlobalUnicast", func() { sinkBool = MustParseAddr("2001:db8::1").IsGlobalUnicast() })
  2026  	test("Addr.IsInterfaceLocalMulticast", func() { sinkBool = MustParseAddr("fe80::1").IsInterfaceLocalMulticast() })
  2027  	test("Addr.IsLinkLocalMulticast", func() { sinkBool = MustParseAddr("fe80::1").IsLinkLocalMulticast() })
  2028  	test("Addr.IsLinkLocalUnicast", func() { sinkBool = MustParseAddr("fe80::1").IsLinkLocalUnicast() })
  2029  	test("Addr.IsLoopback", func() { sinkBool = MustParseAddr("fe80::1").IsLoopback() })
  2030  	test("Addr.IsMulticast", func() { sinkBool = MustParseAddr("fe80::1").IsMulticast() })
  2031  	test("Addr.IsPrivate", func() { sinkBool = MustParseAddr("fd00::1").IsPrivate() })
  2032  	test("Addr.IsUnspecified", func() { sinkBool = IPv6Unspecified().IsUnspecified() })
  2033  	test("Addr.Prefix/4", func() { sinkPrefix = panicPfx(MustParseAddr("1.2.3.4").Prefix(20)) })
  2034  	test("Addr.Prefix/6", func() { sinkPrefix = panicPfx(MustParseAddr("fe80::1").Prefix(64)) })
  2035  	test("Addr.As16", func() { sinkIP16 = MustParseAddr("1.2.3.4").As16() })
  2036  	test("Addr.As4", func() { sinkIP4 = MustParseAddr("1.2.3.4").As4() })
  2037  	test("Addr.Next", func() { sinkIP = MustParseAddr("1.2.3.4").Next() })
  2038  	test("Addr.Prev", func() { sinkIP = MustParseAddr("1.2.3.4").Prev() })
  2039  
  2040  	// AddrPort constructors
  2041  	test("AddrPortFrom", func() { sinkAddrPort = AddrPortFrom(IPv4(1, 2, 3, 4), 22) })
  2042  	test("ParseAddrPort", func() { sinkAddrPort = panicIPP(ParseAddrPort("[::1]:1234")) })
  2043  	test("MustParseAddrPort", func() { sinkAddrPort = MustParseAddrPort("[::1]:1234") })
  2044  
  2045  	// Prefix constructors
  2046  	test("PrefixFrom", func() { sinkPrefix = PrefixFrom(IPv4(1, 2, 3, 4), 32) })
  2047  	test("ParsePrefix/4", func() { sinkPrefix = panicPfx(ParsePrefix("1.2.3.4/20")) })
  2048  	test("ParsePrefix/6", func() { sinkPrefix = panicPfx(ParsePrefix("fe80::1/64")) })
  2049  	test("MustParsePrefix", func() { sinkPrefix = MustParsePrefix("1.2.3.4/20") })
  2050  
  2051  	// Prefix methods
  2052  	test("Prefix.Contains", func() { sinkBool = MustParsePrefix("1.2.3.0/24").Contains(MustParseAddr("1.2.3.4")) })
  2053  	test("Prefix.Overlaps", func() {
  2054  		a, b := MustParsePrefix("1.2.3.0/24"), MustParsePrefix("1.2.0.0/16")
  2055  		sinkBool = a.Overlaps(b)
  2056  	})
  2057  	test("Prefix.IsZero", func() { sinkBool = MustParsePrefix("1.2.0.0/16").IsZero() })
  2058  	test("Prefix.IsSingleIP", func() { sinkBool = MustParsePrefix("1.2.3.4/32").IsSingleIP() })
  2059  	test("Prefix.Masked", func() { sinkPrefix = MustParsePrefix("1.2.3.4/16").Masked() })
  2060  }
  2061  
  2062  func TestAddrStringAllocs(t *testing.T) {
  2063  	tests := []struct {
  2064  		name       string
  2065  		ip         Addr
  2066  		wantAllocs int
  2067  	}{
  2068  		{"zero", Addr{}, 0},
  2069  		{"ipv4", MustParseAddr("192.168.1.1"), 1},
  2070  		{"ipv6", MustParseAddr("2001:db8::1"), 1},
  2071  		{"ipv6+zone", MustParseAddr("2001:db8::1%eth0"), 1},
  2072  		{"ipv4-in-ipv6", MustParseAddr("::ffff:192.168.1.1"), 1},
  2073  		{"ipv4-in-ipv6+zone", MustParseAddr("::ffff:192.168.1.1%eth0"), 1},
  2074  	}
  2075  	optimizationOff := testenv.OptimizationOff()
  2076  	for _, tc := range tests {
  2077  		t.Run(tc.name, func(t *testing.T) {
  2078  			if optimizationOff && strings.HasPrefix(tc.name, "ipv4-in-ipv6") {
  2079  				// Optimizations are required to remove some allocs.
  2080  				t.Skipf("skipping on %v", testenv.Builder())
  2081  			}
  2082  			allocs := int(testing.AllocsPerRun(1000, func() {
  2083  				sinkString = tc.ip.String()
  2084  			}))
  2085  			if allocs != tc.wantAllocs {
  2086  				t.Errorf("allocs=%d, want %d", allocs, tc.wantAllocs)
  2087  			}
  2088  		})
  2089  	}
  2090  }
  2091  
  2092  func TestPrefixString(t *testing.T) {
  2093  	tests := []struct {
  2094  		ipp  Prefix
  2095  		want string
  2096  	}{
  2097  		{Prefix{}, "invalid Prefix"},
  2098  		{PrefixFrom(Addr{}, 8), "invalid Prefix"},
  2099  		{PrefixFrom(MustParseAddr("1.2.3.4"), 88), "invalid Prefix"},
  2100  	}
  2101  
  2102  	for _, tt := range tests {
  2103  		if got := tt.ipp.String(); got != tt.want {
  2104  			t.Errorf("(%#v).String() = %q want %q", tt.ipp, got, tt.want)
  2105  		}
  2106  	}
  2107  }
  2108  
  2109  func TestInvalidAddrPortString(t *testing.T) {
  2110  	tests := []struct {
  2111  		ipp  AddrPort
  2112  		want string
  2113  	}{
  2114  		{AddrPort{}, "invalid AddrPort"},
  2115  		{AddrPortFrom(Addr{}, 80), "invalid AddrPort"},
  2116  	}
  2117  
  2118  	for _, tt := range tests {
  2119  		if got := tt.ipp.String(); got != tt.want {
  2120  			t.Errorf("(%#v).String() = %q want %q", tt.ipp, got, tt.want)
  2121  		}
  2122  	}
  2123  }
  2124  
  2125  func TestAsSlice(t *testing.T) {
  2126  	tests := []struct {
  2127  		in   Addr
  2128  		want []byte
  2129  	}{
  2130  		{in: Addr{}, want: nil},
  2131  		{in: mustIP("1.2.3.4"), want: []byte{1, 2, 3, 4}},
  2132  		{in: mustIP("ffff::1"), want: []byte{0xff, 0xff, 15: 1}},
  2133  	}
  2134  
  2135  	for _, test := range tests {
  2136  		got := test.in.AsSlice()
  2137  		if !bytes.Equal(got, test.want) {
  2138  			t.Errorf("%v.AsSlice() = %v want %v", test.in, got, test.want)
  2139  		}
  2140  	}
  2141  }
  2142  
  2143  var sink16 [16]byte
  2144  
  2145  func BenchmarkAs16(b *testing.B) {
  2146  	addr := MustParseAddr("1::10")
  2147  	for i := 0; i < b.N; i++ {
  2148  		sink16 = addr.As16()
  2149  	}
  2150  }
  2151  

View as plain text