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 }