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 }