github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/tcpip/header/ipv6_test.go (about)

     1  // Copyright 2019 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package header_test
    16  
    17  import (
    18  	"bytes"
    19  	"crypto/sha256"
    20  	"fmt"
    21  	"testing"
    22  
    23  	"github.com/google/go-cmp/cmp"
    24  	"github.com/SagerNet/gvisor/pkg/rand"
    25  	"github.com/SagerNet/gvisor/pkg/tcpip"
    26  	"github.com/SagerNet/gvisor/pkg/tcpip/header"
    27  	"github.com/SagerNet/gvisor/pkg/tcpip/testutil"
    28  )
    29  
    30  const linkAddr = tcpip.LinkAddress("\x02\x02\x03\x04\x05\x06")
    31  
    32  var (
    33  	linkLocalAddr          = testutil.MustParse6("fe80::1")
    34  	linkLocalMulticastAddr = testutil.MustParse6("ff02::1")
    35  	uniqueLocalAddr1       = testutil.MustParse6("fc00::1")
    36  	uniqueLocalAddr2       = testutil.MustParse6("fd00::2")
    37  	globalAddr             = testutil.MustParse6("a000::1")
    38  )
    39  
    40  func TestEthernetAdddressToModifiedEUI64(t *testing.T) {
    41  	expectedIID := [header.IIDSize]byte{0, 2, 3, 255, 254, 4, 5, 6}
    42  
    43  	if diff := cmp.Diff(expectedIID, header.EthernetAddressToModifiedEUI64(linkAddr)); diff != "" {
    44  		t.Errorf("EthernetAddressToModifiedEUI64(%s) mismatch (-want +got):\n%s", linkAddr, diff)
    45  	}
    46  
    47  	var buf [header.IIDSize]byte
    48  	header.EthernetAdddressToModifiedEUI64IntoBuf(linkAddr, buf[:])
    49  	if diff := cmp.Diff(expectedIID, buf); diff != "" {
    50  		t.Errorf("EthernetAddressToModifiedEUI64IntoBuf(%s, _) mismatch (-want +got):\n%s", linkAddr, diff)
    51  	}
    52  }
    53  
    54  func TestLinkLocalAddr(t *testing.T) {
    55  	if got, want := header.LinkLocalAddr(linkAddr), testutil.MustParse6("fe80::2:3ff:fe04:506"); got != want {
    56  		t.Errorf("got LinkLocalAddr(%s) = %s, want = %s", linkAddr, got, want)
    57  	}
    58  }
    59  
    60  func TestAppendOpaqueInterfaceIdentifier(t *testing.T) {
    61  	var secretKeyBuf [header.OpaqueIIDSecretKeyMinBytes * 2]byte
    62  	if n, err := rand.Read(secretKeyBuf[:]); err != nil {
    63  		t.Fatalf("rand.Read(_): %s", err)
    64  	} else if want := header.OpaqueIIDSecretKeyMinBytes * 2; n != want {
    65  		t.Fatalf("expected rand.Read to read %d bytes, read %d bytes", want, n)
    66  	}
    67  
    68  	tests := []struct {
    69  		name       string
    70  		prefix     tcpip.Subnet
    71  		nicName    string
    72  		dadCounter uint8
    73  		secretKey  []byte
    74  	}{
    75  		{
    76  			name:       "SecretKey of minimum size",
    77  			prefix:     header.IPv6LinkLocalPrefix.Subnet(),
    78  			nicName:    "eth0",
    79  			dadCounter: 0,
    80  			secretKey:  secretKeyBuf[:header.OpaqueIIDSecretKeyMinBytes],
    81  		},
    82  		{
    83  			name: "SecretKey of less than minimum size",
    84  			prefix: func() tcpip.Subnet {
    85  				addrWithPrefix := tcpip.AddressWithPrefix{
    86  					Address:   "\x01\x02\x03\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
    87  					PrefixLen: header.IIDOffsetInIPv6Address * 8,
    88  				}
    89  				return addrWithPrefix.Subnet()
    90  			}(),
    91  			nicName:    "eth10",
    92  			dadCounter: 1,
    93  			secretKey:  secretKeyBuf[:header.OpaqueIIDSecretKeyMinBytes/2],
    94  		},
    95  		{
    96  			name: "SecretKey of more than minimum size",
    97  			prefix: func() tcpip.Subnet {
    98  				addrWithPrefix := tcpip.AddressWithPrefix{
    99  					Address:   "\x01\x02\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
   100  					PrefixLen: header.IIDOffsetInIPv6Address * 8,
   101  				}
   102  				return addrWithPrefix.Subnet()
   103  			}(),
   104  			nicName:    "eth11",
   105  			dadCounter: 2,
   106  			secretKey:  secretKeyBuf[:header.OpaqueIIDSecretKeyMinBytes*2],
   107  		},
   108  		{
   109  			name: "Nil SecretKey and empty nicName",
   110  			prefix: func() tcpip.Subnet {
   111  				addrWithPrefix := tcpip.AddressWithPrefix{
   112  					Address:   "\x01\x02\x03\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
   113  					PrefixLen: header.IIDOffsetInIPv6Address * 8,
   114  				}
   115  				return addrWithPrefix.Subnet()
   116  			}(),
   117  			nicName:    "",
   118  			dadCounter: 3,
   119  			secretKey:  nil,
   120  		},
   121  	}
   122  
   123  	for _, test := range tests {
   124  		t.Run(test.name, func(t *testing.T) {
   125  			h := sha256.New()
   126  			h.Write([]byte(test.prefix.ID()[:header.IIDOffsetInIPv6Address]))
   127  			h.Write([]byte(test.nicName))
   128  			h.Write([]byte{test.dadCounter})
   129  			if k := test.secretKey; k != nil {
   130  				h.Write(k)
   131  			}
   132  			var hashSum [sha256.Size]byte
   133  			h.Sum(hashSum[:0])
   134  			want := hashSum[:header.IIDSize]
   135  
   136  			// Passing a nil buffer should result in a new buffer returned with the
   137  			// IID.
   138  			if got := header.AppendOpaqueInterfaceIdentifier(nil, test.prefix, test.nicName, test.dadCounter, test.secretKey); !bytes.Equal(got, want) {
   139  				t.Errorf("got AppendOpaqueInterfaceIdentifier(nil, %s, %s, %d, %x) = %x, want = %x", test.prefix, test.nicName, test.dadCounter, test.secretKey, got, want)
   140  			}
   141  
   142  			// Passing a buffer with sufficient capacity for the IID should populate
   143  			// the buffer provided.
   144  			var iidBuf [header.IIDSize]byte
   145  			if got := header.AppendOpaqueInterfaceIdentifier(iidBuf[:0], test.prefix, test.nicName, test.dadCounter, test.secretKey); !bytes.Equal(got, want) {
   146  				t.Errorf("got AppendOpaqueInterfaceIdentifier(iidBuf[:0], %s, %s, %d, %x) = %x, want = %x", test.prefix, test.nicName, test.dadCounter, test.secretKey, got, want)
   147  			}
   148  			if got := iidBuf[:]; !bytes.Equal(got, want) {
   149  				t.Errorf("got iidBuf = %x, want = %x", got, want)
   150  			}
   151  		})
   152  	}
   153  }
   154  
   155  func TestLinkLocalAddrWithOpaqueIID(t *testing.T) {
   156  	var secretKeyBuf [header.OpaqueIIDSecretKeyMinBytes * 2]byte
   157  	if n, err := rand.Read(secretKeyBuf[:]); err != nil {
   158  		t.Fatalf("rand.Read(_): %s", err)
   159  	} else if want := header.OpaqueIIDSecretKeyMinBytes * 2; n != want {
   160  		t.Fatalf("expected rand.Read to read %d bytes, read %d bytes", want, n)
   161  	}
   162  
   163  	prefix := header.IPv6LinkLocalPrefix.Subnet()
   164  
   165  	tests := []struct {
   166  		name       string
   167  		prefix     tcpip.Subnet
   168  		nicName    string
   169  		dadCounter uint8
   170  		secretKey  []byte
   171  	}{
   172  		{
   173  			name:       "SecretKey of minimum size",
   174  			nicName:    "eth0",
   175  			dadCounter: 0,
   176  			secretKey:  secretKeyBuf[:header.OpaqueIIDSecretKeyMinBytes],
   177  		},
   178  		{
   179  			name:       "SecretKey of less than minimum size",
   180  			nicName:    "eth10",
   181  			dadCounter: 1,
   182  			secretKey:  secretKeyBuf[:header.OpaqueIIDSecretKeyMinBytes/2],
   183  		},
   184  		{
   185  			name:       "SecretKey of more than minimum size",
   186  			nicName:    "eth11",
   187  			dadCounter: 2,
   188  			secretKey:  secretKeyBuf[:header.OpaqueIIDSecretKeyMinBytes*2],
   189  		},
   190  		{
   191  			name:       "Nil SecretKey and empty nicName",
   192  			nicName:    "",
   193  			dadCounter: 3,
   194  			secretKey:  nil,
   195  		},
   196  	}
   197  
   198  	for _, test := range tests {
   199  		t.Run(test.name, func(t *testing.T) {
   200  			addrBytes := [header.IPv6AddressSize]byte{
   201  				0: 0xFE,
   202  				1: 0x80,
   203  			}
   204  
   205  			want := tcpip.Address(header.AppendOpaqueInterfaceIdentifier(
   206  				addrBytes[:header.IIDOffsetInIPv6Address],
   207  				prefix,
   208  				test.nicName,
   209  				test.dadCounter,
   210  				test.secretKey,
   211  			))
   212  
   213  			if got := header.LinkLocalAddrWithOpaqueIID(test.nicName, test.dadCounter, test.secretKey); got != want {
   214  				t.Errorf("got LinkLocalAddrWithOpaqueIID(%s, %d, %x) = %s, want = %s", test.nicName, test.dadCounter, test.secretKey, got, want)
   215  			}
   216  		})
   217  	}
   218  }
   219  
   220  func TestIsV6LinkLocalMulticastAddress(t *testing.T) {
   221  	tests := []struct {
   222  		name     string
   223  		addr     tcpip.Address
   224  		expected bool
   225  	}{
   226  		{
   227  			name:     "Valid Link Local Multicast",
   228  			addr:     linkLocalMulticastAddr,
   229  			expected: true,
   230  		},
   231  		{
   232  			name:     "Valid Link Local Multicast with flags",
   233  			addr:     "\xff\xf2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",
   234  			expected: true,
   235  		},
   236  		{
   237  			name:     "Link Local Unicast",
   238  			addr:     linkLocalAddr,
   239  			expected: false,
   240  		},
   241  		{
   242  			name:     "IPv4 Multicast",
   243  			addr:     "\xe0\x00\x00\x01",
   244  			expected: false,
   245  		},
   246  	}
   247  
   248  	for _, test := range tests {
   249  		t.Run(test.name, func(t *testing.T) {
   250  			if got := header.IsV6LinkLocalMulticastAddress(test.addr); got != test.expected {
   251  				t.Errorf("got header.IsV6LinkLocalMulticastAddress(%s) = %t, want = %t", test.addr, got, test.expected)
   252  			}
   253  		})
   254  	}
   255  }
   256  
   257  func TestIsV6LinkLocalUnicastAddress(t *testing.T) {
   258  	tests := []struct {
   259  		name     string
   260  		addr     tcpip.Address
   261  		expected bool
   262  	}{
   263  		{
   264  			name:     "Valid Link Local Unicast",
   265  			addr:     linkLocalAddr,
   266  			expected: true,
   267  		},
   268  		{
   269  			name:     "Link Local Multicast",
   270  			addr:     linkLocalMulticastAddr,
   271  			expected: false,
   272  		},
   273  		{
   274  			name:     "Unique Local",
   275  			addr:     uniqueLocalAddr1,
   276  			expected: false,
   277  		},
   278  		{
   279  			name:     "Global",
   280  			addr:     globalAddr,
   281  			expected: false,
   282  		},
   283  		{
   284  			name:     "IPv4 Link Local",
   285  			addr:     "\xa9\xfe\x00\x01",
   286  			expected: false,
   287  		},
   288  	}
   289  
   290  	for _, test := range tests {
   291  		t.Run(test.name, func(t *testing.T) {
   292  			if got := header.IsV6LinkLocalUnicastAddress(test.addr); got != test.expected {
   293  				t.Errorf("got header.IsV6LinkLocalUnicastAddress(%s) = %t, want = %t", test.addr, got, test.expected)
   294  			}
   295  		})
   296  	}
   297  }
   298  
   299  func TestScopeForIPv6Address(t *testing.T) {
   300  	tests := []struct {
   301  		name  string
   302  		addr  tcpip.Address
   303  		scope header.IPv6AddressScope
   304  		err   tcpip.Error
   305  	}{
   306  		{
   307  			name:  "Unique Local",
   308  			addr:  uniqueLocalAddr1,
   309  			scope: header.GlobalScope,
   310  			err:   nil,
   311  		},
   312  		{
   313  			name:  "Link Local Unicast",
   314  			addr:  linkLocalAddr,
   315  			scope: header.LinkLocalScope,
   316  			err:   nil,
   317  		},
   318  		{
   319  			name:  "Link Local Multicast",
   320  			addr:  linkLocalMulticastAddr,
   321  			scope: header.LinkLocalScope,
   322  			err:   nil,
   323  		},
   324  		{
   325  			name:  "Global",
   326  			addr:  globalAddr,
   327  			scope: header.GlobalScope,
   328  			err:   nil,
   329  		},
   330  		{
   331  			name:  "IPv4",
   332  			addr:  "\x01\x02\x03\x04",
   333  			scope: header.GlobalScope,
   334  			err:   &tcpip.ErrBadAddress{},
   335  		},
   336  	}
   337  
   338  	for _, test := range tests {
   339  		t.Run(test.name, func(t *testing.T) {
   340  			got, err := header.ScopeForIPv6Address(test.addr)
   341  			if diff := cmp.Diff(test.err, err); diff != "" {
   342  				t.Errorf("unexpected error from header.IsV6UniqueLocalAddress(%s), (-want, +got):\n%s", test.addr, diff)
   343  			}
   344  			if got != test.scope {
   345  				t.Errorf("got header.IsV6UniqueLocalAddress(%s) = (%d, _), want = (%d, _)", test.addr, got, test.scope)
   346  			}
   347  		})
   348  	}
   349  }
   350  
   351  func TestSolicitedNodeAddr(t *testing.T) {
   352  	tests := []struct {
   353  		addr tcpip.Address
   354  		want tcpip.Address
   355  	}{
   356  		{
   357  			addr: "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\xa0",
   358  			want: "\xff\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xff\x0e\x0f\xa0",
   359  		},
   360  		{
   361  			addr: "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\xdd\x0e\x0f\xa0",
   362  			want: "\xff\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xff\x0e\x0f\xa0",
   363  		},
   364  		{
   365  			addr: "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\xdd\x01\x02\x03",
   366  			want: "\xff\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xff\x01\x02\x03",
   367  		},
   368  	}
   369  
   370  	for _, test := range tests {
   371  		t.Run(fmt.Sprintf("%s", test.addr), func(t *testing.T) {
   372  			if got := header.SolicitedNodeAddr(test.addr); got != test.want {
   373  				t.Fatalf("got header.SolicitedNodeAddr(%s) = %s, want = %s", test.addr, got, test.want)
   374  			}
   375  		})
   376  	}
   377  }
   378  
   379  func TestV6MulticastScope(t *testing.T) {
   380  	tests := []struct {
   381  		addr tcpip.Address
   382  		want header.IPv6MulticastScope
   383  	}{
   384  		{
   385  			addr: "\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",
   386  			want: header.IPv6Reserved0MulticastScope,
   387  		},
   388  		{
   389  			addr: "\xff\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",
   390  			want: header.IPv6InterfaceLocalMulticastScope,
   391  		},
   392  		{
   393  			addr: "\xff\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",
   394  			want: header.IPv6LinkLocalMulticastScope,
   395  		},
   396  		{
   397  			addr: "\xff\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",
   398  			want: header.IPv6RealmLocalMulticastScope,
   399  		},
   400  		{
   401  			addr: "\xff\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",
   402  			want: header.IPv6AdminLocalMulticastScope,
   403  		},
   404  		{
   405  			addr: "\xff\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",
   406  			want: header.IPv6SiteLocalMulticastScope,
   407  		},
   408  		{
   409  			addr: "\xff\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",
   410  			want: header.IPv6MulticastScope(6),
   411  		},
   412  		{
   413  			addr: "\xff\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",
   414  			want: header.IPv6MulticastScope(7),
   415  		},
   416  		{
   417  			addr: "\xff\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",
   418  			want: header.IPv6OrganizationLocalMulticastScope,
   419  		},
   420  		{
   421  			addr: "\xff\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",
   422  			want: header.IPv6MulticastScope(9),
   423  		},
   424  		{
   425  			addr: "\xff\x0a\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",
   426  			want: header.IPv6MulticastScope(10),
   427  		},
   428  		{
   429  			addr: "\xff\x0b\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",
   430  			want: header.IPv6MulticastScope(11),
   431  		},
   432  		{
   433  			addr: "\xff\x0c\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",
   434  			want: header.IPv6MulticastScope(12),
   435  		},
   436  		{
   437  			addr: "\xff\x0d\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",
   438  			want: header.IPv6MulticastScope(13),
   439  		},
   440  		{
   441  			addr: "\xff\x0e\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",
   442  			want: header.IPv6GlobalMulticastScope,
   443  		},
   444  		{
   445  			addr: "\xff\x0f\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",
   446  			want: header.IPv6ReservedFMulticastScope,
   447  		},
   448  	}
   449  
   450  	for _, test := range tests {
   451  		t.Run(fmt.Sprintf("%s", test.addr), func(t *testing.T) {
   452  			if got := header.V6MulticastScope(test.addr); got != test.want {
   453  				t.Fatalf("got header.V6MulticastScope(%s) = %d, want = %d", test.addr, got, test.want)
   454  			}
   455  		})
   456  	}
   457  }