gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/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  	"gvisor.dev/gvisor/pkg/rand"
    25  	"gvisor.dev/gvisor/pkg/tcpip"
    26  	"gvisor.dev/gvisor/pkg/tcpip/header"
    27  	"gvisor.dev/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:   tcpip.AddrFrom16Slice([]byte("\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:   tcpip.AddrFrom16Slice([]byte("\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:   tcpip.AddrFrom16Slice([]byte("\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  			prefixID := test.prefix.ID()
   127  			h.Write(prefixID.AsSlice()[:header.IIDOffsetInIPv6Address])
   128  			h.Write([]byte(test.nicName))
   129  			h.Write([]byte{test.dadCounter})
   130  			if k := test.secretKey; k != nil {
   131  				h.Write(k)
   132  			}
   133  			var hashSum [sha256.Size]byte
   134  			h.Sum(hashSum[:0])
   135  			want := hashSum[:header.IIDSize]
   136  
   137  			// Passing a nil buffer should result in a new buffer returned with the
   138  			// IID.
   139  			if got := header.AppendOpaqueInterfaceIdentifier(nil, test.prefix, test.nicName, test.dadCounter, test.secretKey); !bytes.Equal(got, want) {
   140  				t.Errorf("got AppendOpaqueInterfaceIdentifier(nil, %s, %s, %d, %x) = %x, want = %x", test.prefix, test.nicName, test.dadCounter, test.secretKey, got, want)
   141  			}
   142  
   143  			// Passing a buffer with sufficient capacity for the IID should populate
   144  			// the buffer provided.
   145  			var iidBuf [header.IIDSize]byte
   146  			if got := header.AppendOpaqueInterfaceIdentifier(iidBuf[:0], test.prefix, test.nicName, test.dadCounter, test.secretKey); !bytes.Equal(got, want) {
   147  				t.Errorf("got AppendOpaqueInterfaceIdentifier(iidBuf[:0], %s, %s, %d, %x) = %x, want = %x", test.prefix, test.nicName, test.dadCounter, test.secretKey, got, want)
   148  			}
   149  			if got := iidBuf[:]; !bytes.Equal(got, want) {
   150  				t.Errorf("got iidBuf = %x, want = %x", got, want)
   151  			}
   152  		})
   153  	}
   154  }
   155  
   156  func TestLinkLocalAddrWithOpaqueIID(t *testing.T) {
   157  	var secretKeyBuf [header.OpaqueIIDSecretKeyMinBytes * 2]byte
   158  	if n, err := rand.Read(secretKeyBuf[:]); err != nil {
   159  		t.Fatalf("rand.Read(_): %s", err)
   160  	} else if want := header.OpaqueIIDSecretKeyMinBytes * 2; n != want {
   161  		t.Fatalf("expected rand.Read to read %d bytes, read %d bytes", want, n)
   162  	}
   163  
   164  	prefix := header.IPv6LinkLocalPrefix.Subnet()
   165  
   166  	tests := []struct {
   167  		name       string
   168  		prefix     tcpip.Subnet
   169  		nicName    string
   170  		dadCounter uint8
   171  		secretKey  []byte
   172  	}{
   173  		{
   174  			name:       "SecretKey of minimum size",
   175  			nicName:    "eth0",
   176  			dadCounter: 0,
   177  			secretKey:  secretKeyBuf[:header.OpaqueIIDSecretKeyMinBytes],
   178  		},
   179  		{
   180  			name:       "SecretKey of less than minimum size",
   181  			nicName:    "eth10",
   182  			dadCounter: 1,
   183  			secretKey:  secretKeyBuf[:header.OpaqueIIDSecretKeyMinBytes/2],
   184  		},
   185  		{
   186  			name:       "SecretKey of more than minimum size",
   187  			nicName:    "eth11",
   188  			dadCounter: 2,
   189  			secretKey:  secretKeyBuf[:header.OpaqueIIDSecretKeyMinBytes*2],
   190  		},
   191  		{
   192  			name:       "Nil SecretKey and empty nicName",
   193  			nicName:    "",
   194  			dadCounter: 3,
   195  			secretKey:  nil,
   196  		},
   197  	}
   198  
   199  	for _, test := range tests {
   200  		t.Run(test.name, func(t *testing.T) {
   201  			addrBytes := [header.IPv6AddressSize]byte{
   202  				0: 0xFE,
   203  				1: 0x80,
   204  			}
   205  
   206  			want := tcpip.AddrFromSlice(header.AppendOpaqueInterfaceIdentifier(
   207  				addrBytes[:header.IIDOffsetInIPv6Address],
   208  				prefix,
   209  				test.nicName,
   210  				test.dadCounter,
   211  				test.secretKey,
   212  			))
   213  
   214  			if got := header.LinkLocalAddrWithOpaqueIID(test.nicName, test.dadCounter, test.secretKey); got != want {
   215  				t.Errorf("got LinkLocalAddrWithOpaqueIID(%s, %d, %x) = %s, want = %s", test.nicName, test.dadCounter, test.secretKey, got, want)
   216  			}
   217  		})
   218  	}
   219  }
   220  
   221  func TestIsV6LinkLocalMulticastAddress(t *testing.T) {
   222  	tests := []struct {
   223  		name     string
   224  		addr     string
   225  		expected bool
   226  	}{
   227  		{
   228  			name:     "Valid Link Local Multicast",
   229  			addr:     string(linkLocalMulticastAddr.AsSlice()),
   230  			expected: true,
   231  		},
   232  		{
   233  			name:     "Valid Link Local Multicast with flags",
   234  			addr:     "\xff\xf2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",
   235  			expected: true,
   236  		},
   237  		{
   238  			name:     "Link Local Unicast",
   239  			addr:     string(linkLocalAddr.AsSlice()),
   240  			expected: false,
   241  		},
   242  		{
   243  			name:     "IPv4 Multicast",
   244  			addr:     "\xe0\x00\x00\x01",
   245  			expected: false,
   246  		},
   247  	}
   248  
   249  	for _, test := range tests {
   250  		t.Run(test.name, func(t *testing.T) {
   251  			if got := header.IsV6LinkLocalMulticastAddress(tcpip.AddrFromSlice([]byte(test.addr))); got != test.expected {
   252  				t.Errorf("got header.IsV6LinkLocalMulticastAddress(%s) = %t, want = %t", test.addr, got, test.expected)
   253  			}
   254  		})
   255  	}
   256  }
   257  
   258  func TestIsV6LinkLocalUnicastAddress(t *testing.T) {
   259  	tests := []struct {
   260  		name     string
   261  		addr     tcpip.Address
   262  		expected bool
   263  	}{
   264  		{
   265  			name:     "Valid Link Local Unicast",
   266  			addr:     linkLocalAddr,
   267  			expected: true,
   268  		},
   269  		{
   270  			name:     "Link Local Multicast",
   271  			addr:     linkLocalMulticastAddr,
   272  			expected: false,
   273  		},
   274  		{
   275  			name:     "Unique Local",
   276  			addr:     uniqueLocalAddr1,
   277  			expected: false,
   278  		},
   279  		{
   280  			name:     "Global",
   281  			addr:     globalAddr,
   282  			expected: false,
   283  		},
   284  		{
   285  			name:     "IPv4 Link Local",
   286  			addr:     tcpip.AddrFrom4Slice([]byte("\xa9\xfe\x00\x01")),
   287  			expected: false,
   288  		},
   289  	}
   290  
   291  	for _, test := range tests {
   292  		t.Run(test.name, func(t *testing.T) {
   293  			if got := header.IsV6LinkLocalUnicastAddress(test.addr); got != test.expected {
   294  				t.Errorf("got header.IsV6LinkLocalUnicastAddress(%s) = %t, want = %t", test.addr, got, test.expected)
   295  			}
   296  		})
   297  	}
   298  }
   299  
   300  func TestScopeForIPv6Address(t *testing.T) {
   301  	tests := []struct {
   302  		name  string
   303  		addr  tcpip.Address
   304  		scope header.IPv6AddressScope
   305  		err   tcpip.Error
   306  	}{
   307  		{
   308  			name:  "Unique Local",
   309  			addr:  uniqueLocalAddr1,
   310  			scope: header.GlobalScope,
   311  			err:   nil,
   312  		},
   313  		{
   314  			name:  "Link Local Unicast",
   315  			addr:  linkLocalAddr,
   316  			scope: header.LinkLocalScope,
   317  			err:   nil,
   318  		},
   319  		{
   320  			name:  "Link Local Multicast",
   321  			addr:  linkLocalMulticastAddr,
   322  			scope: header.LinkLocalScope,
   323  			err:   nil,
   324  		},
   325  		{
   326  			name:  "Global",
   327  			addr:  globalAddr,
   328  			scope: header.GlobalScope,
   329  			err:   nil,
   330  		},
   331  		{
   332  			name:  "IPv4",
   333  			addr:  tcpip.AddrFrom4Slice([]byte("\x01\x02\x03\x04")),
   334  			scope: header.GlobalScope,
   335  			err:   &tcpip.ErrBadAddress{},
   336  		},
   337  	}
   338  
   339  	for _, test := range tests {
   340  		t.Run(test.name, func(t *testing.T) {
   341  			got, err := header.ScopeForIPv6Address(test.addr)
   342  			if diff := cmp.Diff(test.err, err); diff != "" {
   343  				t.Errorf("unexpected error from header.IsV6UniqueLocalAddress(%s), (-want, +got):\n%s", test.addr, diff)
   344  			}
   345  			if got != test.scope {
   346  				t.Errorf("got header.IsV6UniqueLocalAddress(%s) = (%d, _), want = (%d, _)", test.addr, got, test.scope)
   347  			}
   348  		})
   349  	}
   350  }
   351  
   352  func TestSolicitedNodeAddr(t *testing.T) {
   353  	tests := []struct {
   354  		addr string
   355  		want string
   356  	}{
   357  		{
   358  			addr: "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\xa0",
   359  			want: "\xff\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xff\x0e\x0f\xa0",
   360  		},
   361  		{
   362  			addr: "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\xdd\x0e\x0f\xa0",
   363  			want: "\xff\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xff\x0e\x0f\xa0",
   364  		},
   365  		{
   366  			addr: "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\xdd\x01\x02\x03",
   367  			want: "\xff\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xff\x01\x02\x03",
   368  		},
   369  	}
   370  
   371  	for _, test := range tests {
   372  		t.Run(fmt.Sprintf("%s", test.addr), func(t *testing.T) {
   373  			if got := header.SolicitedNodeAddr(tcpip.AddrFrom16Slice([]byte(test.addr))); got != tcpip.AddrFrom16Slice([]byte(test.want)) {
   374  				t.Fatalf("got header.SolicitedNodeAddr(%s) = %s, want = %s", test.addr, got, test.want)
   375  			}
   376  		})
   377  	}
   378  }
   379  
   380  func TestV6MulticastScope(t *testing.T) {
   381  	tests := []struct {
   382  		addr string
   383  		want header.IPv6MulticastScope
   384  	}{
   385  		{
   386  			addr: "\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",
   387  			want: header.IPv6Reserved0MulticastScope,
   388  		},
   389  		{
   390  			addr: "\xff\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",
   391  			want: header.IPv6InterfaceLocalMulticastScope,
   392  		},
   393  		{
   394  			addr: "\xff\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",
   395  			want: header.IPv6LinkLocalMulticastScope,
   396  		},
   397  		{
   398  			addr: "\xff\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",
   399  			want: header.IPv6RealmLocalMulticastScope,
   400  		},
   401  		{
   402  			addr: "\xff\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",
   403  			want: header.IPv6AdminLocalMulticastScope,
   404  		},
   405  		{
   406  			addr: "\xff\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",
   407  			want: header.IPv6SiteLocalMulticastScope,
   408  		},
   409  		{
   410  			addr: "\xff\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",
   411  			want: header.IPv6MulticastScope(6),
   412  		},
   413  		{
   414  			addr: "\xff\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",
   415  			want: header.IPv6MulticastScope(7),
   416  		},
   417  		{
   418  			addr: "\xff\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",
   419  			want: header.IPv6OrganizationLocalMulticastScope,
   420  		},
   421  		{
   422  			addr: "\xff\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",
   423  			want: header.IPv6MulticastScope(9),
   424  		},
   425  		{
   426  			addr: "\xff\x0a\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",
   427  			want: header.IPv6MulticastScope(10),
   428  		},
   429  		{
   430  			addr: "\xff\x0b\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",
   431  			want: header.IPv6MulticastScope(11),
   432  		},
   433  		{
   434  			addr: "\xff\x0c\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",
   435  			want: header.IPv6MulticastScope(12),
   436  		},
   437  		{
   438  			addr: "\xff\x0d\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",
   439  			want: header.IPv6MulticastScope(13),
   440  		},
   441  		{
   442  			addr: "\xff\x0e\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",
   443  			want: header.IPv6GlobalMulticastScope,
   444  		},
   445  		{
   446  			addr: "\xff\x0f\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",
   447  			want: header.IPv6ReservedFMulticastScope,
   448  		},
   449  	}
   450  
   451  	for _, test := range tests {
   452  		t.Run(fmt.Sprintf("%s", test.addr), func(t *testing.T) {
   453  			if got := header.V6MulticastScope(tcpip.AddrFrom16Slice([]byte(test.addr))); got != test.want {
   454  				t.Fatalf("got header.V6MulticastScope(%s) = %d, want = %d", test.addr, got, test.want)
   455  			}
   456  		})
   457  	}
   458  }