github.com/nicocha30/gvisor-ligolo@v0.0.0-20230726075806-989fa2c0a413/pkg/tcpip/header/ipv6.go (about) 1 // Copyright 2018 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 16 17 import ( 18 "crypto/sha256" 19 "encoding/binary" 20 "fmt" 21 22 "github.com/nicocha30/gvisor-ligolo/pkg/tcpip" 23 ) 24 25 const ( 26 versTCFL = 0 27 // IPv6PayloadLenOffset is the offset of the PayloadLength field in 28 // IPv6 header. 29 IPv6PayloadLenOffset = 4 30 // IPv6NextHeaderOffset is the offset of the NextHeader field in 31 // IPv6 header. 32 IPv6NextHeaderOffset = 6 33 hopLimit = 7 34 v6SrcAddr = 8 35 v6DstAddr = v6SrcAddr + IPv6AddressSize 36 37 // IPv6FixedHeaderSize is the size of the fixed header. 38 IPv6FixedHeaderSize = v6DstAddr + IPv6AddressSize 39 ) 40 41 // IPv6Fields contains the fields of an IPv6 packet. It is used to describe the 42 // fields of a packet that needs to be encoded. 43 type IPv6Fields struct { 44 // TrafficClass is the "traffic class" field of an IPv6 packet. 45 TrafficClass uint8 46 47 // FlowLabel is the "flow label" field of an IPv6 packet. 48 FlowLabel uint32 49 50 // PayloadLength is the "payload length" field of an IPv6 packet, including 51 // the length of all extension headers. 52 PayloadLength uint16 53 54 // TransportProtocol is the transport layer protocol number. Serialized in the 55 // last "next header" field of the IPv6 header + extension headers. 56 TransportProtocol tcpip.TransportProtocolNumber 57 58 // HopLimit is the "Hop Limit" field of an IPv6 packet. 59 HopLimit uint8 60 61 // SrcAddr is the "source ip address" of an IPv6 packet. 62 SrcAddr tcpip.Address 63 64 // DstAddr is the "destination ip address" of an IPv6 packet. 65 DstAddr tcpip.Address 66 67 // ExtensionHeaders are the extension headers following the IPv6 header. 68 ExtensionHeaders IPv6ExtHdrSerializer 69 } 70 71 // IPv6 represents an ipv6 header stored in a byte array. 72 // Most of the methods of IPv6 access to the underlying slice without 73 // checking the boundaries and could panic because of 'index out of range'. 74 // Always call IsValid() to validate an instance of IPv6 before using other methods. 75 type IPv6 []byte 76 77 const ( 78 // IPv6MinimumSize is the minimum size of a valid IPv6 packet. 79 IPv6MinimumSize = IPv6FixedHeaderSize 80 81 // IPv6AddressSize is the size, in bytes, of an IPv6 address. 82 IPv6AddressSize = 16 83 84 // IPv6AddressSizeBits is the size, in bits, of an IPv6 address. 85 IPv6AddressSizeBits = 128 86 87 // IPv6MaximumPayloadSize is the maximum size of a valid IPv6 payload per 88 // RFC 8200 Section 4.5. 89 IPv6MaximumPayloadSize = 65535 90 91 // IPv6ProtocolNumber is IPv6's network protocol number. 92 IPv6ProtocolNumber tcpip.NetworkProtocolNumber = 0x86dd 93 94 // IPv6Version is the version of the ipv6 protocol. 95 IPv6Version = 6 96 97 // IIDSize is the size of an interface identifier (IID), in bytes, as 98 // defined by RFC 4291 section 2.5.1. 99 IIDSize = 8 100 101 // IPv6MinimumMTU is the minimum MTU required by IPv6, per RFC 8200, 102 // section 5: 103 // IPv6 requires that every link in the Internet have an MTU of 1280 octets 104 // or greater. This is known as the IPv6 minimum link MTU. 105 IPv6MinimumMTU = 1280 106 107 // IIDOffsetInIPv6Address is the offset, in bytes, from the start 108 // of an IPv6 address to the beginning of the interface identifier 109 // (IID) for auto-generated addresses. That is, all bytes before 110 // the IIDOffsetInIPv6Address-th byte are the prefix bytes, and all 111 // bytes including and after the IIDOffsetInIPv6Address-th byte are 112 // for the IID. 113 IIDOffsetInIPv6Address = 8 114 115 // OpaqueIIDSecretKeyMinBytes is the recommended minimum number of bytes 116 // for the secret key used to generate an opaque interface identifier as 117 // outlined by RFC 7217. 118 OpaqueIIDSecretKeyMinBytes = 16 119 120 // ipv6MulticastAddressScopeByteIdx is the byte where the scope (scop) field 121 // is located within a multicast IPv6 address, as per RFC 4291 section 2.7. 122 ipv6MulticastAddressScopeByteIdx = 1 123 124 // ipv6MulticastAddressScopeMask is the mask for the scope (scop) field, 125 // within the byte holding the field, as per RFC 4291 section 2.7. 126 ipv6MulticastAddressScopeMask = 0xF 127 ) 128 129 var ( 130 // IPv6AllNodesMulticastAddress is a link-local multicast group that 131 // all IPv6 nodes MUST join, as per RFC 4291, section 2.8. Packets 132 // destined to this address will reach all nodes on a link. 133 // 134 // The address is ff02::1. 135 IPv6AllNodesMulticastAddress = tcpip.AddrFrom16([16]byte{0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}) 136 137 // IPv6AllRoutersInterfaceLocalMulticastAddress is an interface-local 138 // multicast group that all IPv6 routers MUST join, as per RFC 4291, section 139 // 2.8. Packets destined to this address will reach the router on an 140 // interface. 141 // 142 // The address is ff01::2. 143 IPv6AllRoutersInterfaceLocalMulticastAddress = tcpip.AddrFrom16([16]byte{0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}) 144 145 // IPv6AllRoutersLinkLocalMulticastAddress is a link-local multicast group 146 // that all IPv6 routers MUST join, as per RFC 4291, section 2.8. Packets 147 // destined to this address will reach all routers on a link. 148 // 149 // The address is ff02::2. 150 IPv6AllRoutersLinkLocalMulticastAddress = tcpip.AddrFrom16([16]byte{0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}) 151 152 // IPv6AllRoutersSiteLocalMulticastAddress is a site-local multicast group 153 // that all IPv6 routers MUST join, as per RFC 4291, section 2.8. Packets 154 // destined to this address will reach all routers in a site. 155 // 156 // The address is ff05::2. 157 IPv6AllRoutersSiteLocalMulticastAddress = tcpip.AddrFrom16([16]byte{0xff, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}) 158 159 // IPv6Loopback is the IPv6 Loopback address. 160 IPv6Loopback = tcpip.AddrFrom16([16]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}) 161 162 // IPv6Any is the non-routable IPv6 "any" meta address. It is also 163 // known as the unspecified address. 164 IPv6Any = tcpip.AddrFrom16([16]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}) 165 ) 166 167 // IPv6EmptySubnet is the empty IPv6 subnet. It may also be known as the 168 // catch-all or wildcard subnet. That is, all IPv6 addresses are considered to 169 // be contained within this subnet. 170 var IPv6EmptySubnet = tcpip.AddressWithPrefix{ 171 Address: IPv6Any, 172 PrefixLen: 0, 173 }.Subnet() 174 175 // IPv4MappedIPv6Subnet is the prefix for an IPv4 mapped IPv6 address as defined 176 // by RFC 4291 section 2.5.5. 177 var IPv4MappedIPv6Subnet = tcpip.AddressWithPrefix{ 178 Address: tcpip.AddrFrom16([16]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00}), 179 PrefixLen: 96, 180 }.Subnet() 181 182 // IPv6LinkLocalPrefix is the prefix for IPv6 link-local addresses, as defined 183 // by RFC 4291 section 2.5.6. 184 // 185 // The prefix is fe80::/64 186 var IPv6LinkLocalPrefix = tcpip.AddressWithPrefix{ 187 Address: tcpip.AddrFrom16([16]byte{0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), 188 PrefixLen: 64, 189 } 190 191 // PayloadLength returns the value of the "payload length" field of the ipv6 192 // header. 193 func (b IPv6) PayloadLength() uint16 { 194 return binary.BigEndian.Uint16(b[IPv6PayloadLenOffset:]) 195 } 196 197 // HopLimit returns the value of the "Hop Limit" field of the ipv6 header. 198 func (b IPv6) HopLimit() uint8 { 199 return b[hopLimit] 200 } 201 202 // NextHeader returns the value of the "next header" field of the ipv6 header. 203 func (b IPv6) NextHeader() uint8 { 204 return b[IPv6NextHeaderOffset] 205 } 206 207 // TransportProtocol implements Network.TransportProtocol. 208 func (b IPv6) TransportProtocol() tcpip.TransportProtocolNumber { 209 return tcpip.TransportProtocolNumber(b.NextHeader()) 210 } 211 212 // Payload implements Network.Payload. 213 func (b IPv6) Payload() []byte { 214 return b[IPv6MinimumSize:][:b.PayloadLength()] 215 } 216 217 // SourceAddress returns the "source address" field of the ipv6 header. 218 func (b IPv6) SourceAddress() tcpip.Address { 219 return tcpip.AddrFrom16([16]byte(b[v6SrcAddr:][:IPv6AddressSize])) 220 } 221 222 // DestinationAddress returns the "destination address" field of the ipv6 223 // header. 224 func (b IPv6) DestinationAddress() tcpip.Address { 225 return tcpip.AddrFrom16([16]byte(b[v6DstAddr:][:IPv6AddressSize])) 226 } 227 228 // Checksum implements Network.Checksum. Given that IPv6 doesn't have a 229 // checksum, it just returns 0. 230 func (IPv6) Checksum() uint16 { 231 return 0 232 } 233 234 // TOS returns the "traffic class" and "flow label" fields of the ipv6 header. 235 func (b IPv6) TOS() (uint8, uint32) { 236 v := binary.BigEndian.Uint32(b[versTCFL:]) 237 return uint8(v >> 20), v & 0xfffff 238 } 239 240 // SetTOS sets the "traffic class" and "flow label" fields of the ipv6 header. 241 func (b IPv6) SetTOS(t uint8, l uint32) { 242 vtf := (6 << 28) | (uint32(t) << 20) | (l & 0xfffff) 243 binary.BigEndian.PutUint32(b[versTCFL:], vtf) 244 } 245 246 // SetPayloadLength sets the "payload length" field of the ipv6 header. 247 func (b IPv6) SetPayloadLength(payloadLength uint16) { 248 binary.BigEndian.PutUint16(b[IPv6PayloadLenOffset:], payloadLength) 249 } 250 251 // SetSourceAddress sets the "source address" field of the ipv6 header. 252 func (b IPv6) SetSourceAddress(addr tcpip.Address) { 253 copy(b[v6SrcAddr:][:IPv6AddressSize], addr.AsSlice()) 254 } 255 256 // SetDestinationAddress sets the "destination address" field of the ipv6 257 // header. 258 func (b IPv6) SetDestinationAddress(addr tcpip.Address) { 259 copy(b[v6DstAddr:][:IPv6AddressSize], addr.AsSlice()) 260 } 261 262 // SetHopLimit sets the value of the "Hop Limit" field. 263 func (b IPv6) SetHopLimit(v uint8) { 264 b[hopLimit] = v 265 } 266 267 // SetNextHeader sets the value of the "next header" field of the ipv6 header. 268 func (b IPv6) SetNextHeader(v uint8) { 269 b[IPv6NextHeaderOffset] = v 270 } 271 272 // SetChecksum implements Network.SetChecksum. Given that IPv6 doesn't have a 273 // checksum, it is empty. 274 func (IPv6) SetChecksum(uint16) { 275 } 276 277 // Encode encodes all the fields of the ipv6 header. 278 func (b IPv6) Encode(i *IPv6Fields) { 279 extHdr := b[IPv6MinimumSize:] 280 b.SetTOS(i.TrafficClass, i.FlowLabel) 281 b.SetPayloadLength(i.PayloadLength) 282 b[hopLimit] = i.HopLimit 283 b.SetSourceAddress(i.SrcAddr) 284 b.SetDestinationAddress(i.DstAddr) 285 nextHeader, _ := i.ExtensionHeaders.Serialize(i.TransportProtocol, extHdr) 286 b[IPv6NextHeaderOffset] = nextHeader 287 } 288 289 // IsValid performs basic validation on the packet. 290 func (b IPv6) IsValid(pktSize int) bool { 291 if len(b) < IPv6MinimumSize { 292 return false 293 } 294 295 dlen := int(b.PayloadLength()) 296 if dlen > pktSize-IPv6MinimumSize { 297 return false 298 } 299 300 if IPVersion(b) != IPv6Version { 301 return false 302 } 303 304 return true 305 } 306 307 // IsV4MappedAddress determines if the provided address is an IPv4 mapped 308 // address by checking if its prefix is 0:0:0:0:0:ffff::/96. 309 func IsV4MappedAddress(addr tcpip.Address) bool { 310 if addr.BitLen() != IPv6AddressSizeBits { 311 return false 312 } 313 314 return IPv4MappedIPv6Subnet.Contains(addr) 315 } 316 317 // IsV6MulticastAddress determines if the provided address is an IPv6 318 // multicast address (anything starting with FF). 319 func IsV6MulticastAddress(addr tcpip.Address) bool { 320 if addr.BitLen() != IPv6AddressSizeBits { 321 return false 322 } 323 return addr.As16()[0] == 0xff 324 } 325 326 // IsV6UnicastAddress determines if the provided address is a valid IPv6 327 // unicast (and specified) address. That is, IsV6UnicastAddress returns 328 // true if addr contains IPv6AddressSize bytes, is not the unspecified 329 // address and is not a multicast address. 330 func IsV6UnicastAddress(addr tcpip.Address) bool { 331 if addr.BitLen() != IPv6AddressSizeBits { 332 return false 333 } 334 335 // Must not be unspecified 336 if addr == IPv6Any { 337 return false 338 } 339 340 // Return if not a multicast. 341 return addr.As16()[0] != 0xff 342 } 343 344 var solicitedNodeMulticastPrefix = [13]byte{0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff} 345 346 // SolicitedNodeAddr computes the solicited-node multicast address. This is 347 // used for NDP. Described in RFC 4291. The argument must be a full-length IPv6 348 // address. 349 func SolicitedNodeAddr(addr tcpip.Address) tcpip.Address { 350 addrBytes := addr.As16() 351 return tcpip.AddrFrom16([16]byte(append(solicitedNodeMulticastPrefix[:], addrBytes[len(addrBytes)-3:]...))) 352 } 353 354 // IsSolicitedNodeAddr determines whether the address is a solicited-node 355 // multicast address. 356 func IsSolicitedNodeAddr(addr tcpip.Address) bool { 357 addrBytes := addr.As16() 358 return solicitedNodeMulticastPrefix == [13]byte(addrBytes[:len(addrBytes)-3]) 359 } 360 361 // EthernetAdddressToModifiedEUI64IntoBuf populates buf with a modified EUI-64 362 // from a 48-bit Ethernet/MAC address, as per RFC 4291 section 2.5.1. 363 // 364 // buf MUST be at least 8 bytes. 365 func EthernetAdddressToModifiedEUI64IntoBuf(linkAddr tcpip.LinkAddress, buf []byte) { 366 buf[0] = linkAddr[0] ^ 2 367 buf[1] = linkAddr[1] 368 buf[2] = linkAddr[2] 369 buf[3] = 0xFF 370 buf[4] = 0xFE 371 buf[5] = linkAddr[3] 372 buf[6] = linkAddr[4] 373 buf[7] = linkAddr[5] 374 } 375 376 // EthernetAddressToModifiedEUI64 computes a modified EUI-64 from a 48-bit 377 // Ethernet/MAC address, as per RFC 4291 section 2.5.1. 378 func EthernetAddressToModifiedEUI64(linkAddr tcpip.LinkAddress) [IIDSize]byte { 379 var buf [IIDSize]byte 380 EthernetAdddressToModifiedEUI64IntoBuf(linkAddr, buf[:]) 381 return buf 382 } 383 384 // LinkLocalAddr computes the default IPv6 link-local address from a link-layer 385 // (MAC) address. 386 func LinkLocalAddr(linkAddr tcpip.LinkAddress) tcpip.Address { 387 // Convert a 48-bit MAC to a modified EUI-64 and then prepend the 388 // link-local header, FE80::. 389 // 390 // The conversion is very nearly: 391 // aa:bb:cc:dd:ee:ff => FE80::Aabb:ccFF:FEdd:eeff 392 // Note the capital A. The conversion aa->Aa involves a bit flip. 393 lladdrb := [IPv6AddressSize]byte{ 394 0: 0xFE, 395 1: 0x80, 396 } 397 EthernetAdddressToModifiedEUI64IntoBuf(linkAddr, lladdrb[IIDOffsetInIPv6Address:]) 398 return tcpip.AddrFrom16(lladdrb) 399 } 400 401 // IsV6LinkLocalUnicastAddress returns true iff the provided address is an IPv6 402 // link-local unicast address, as defined by RFC 4291 section 2.5.6. 403 func IsV6LinkLocalUnicastAddress(addr tcpip.Address) bool { 404 if addr.BitLen() != IPv6AddressSizeBits { 405 return false 406 } 407 addrBytes := addr.As16() 408 return addrBytes[0] == 0xfe && (addrBytes[1]&0xc0) == 0x80 409 } 410 411 // IsV6LoopbackAddress returns true iff the provided address is an IPv6 loopback 412 // address, as defined by RFC 4291 section 2.5.3. 413 func IsV6LoopbackAddress(addr tcpip.Address) bool { 414 return addr == IPv6Loopback 415 } 416 417 // IsV6LinkLocalMulticastAddress returns true iff the provided address is an 418 // IPv6 link-local multicast address, as defined by RFC 4291 section 2.7. 419 func IsV6LinkLocalMulticastAddress(addr tcpip.Address) bool { 420 return IsV6MulticastAddress(addr) && V6MulticastScope(addr) == IPv6LinkLocalMulticastScope 421 } 422 423 // AppendOpaqueInterfaceIdentifier appends a 64 bit opaque interface identifier 424 // (IID) to buf as outlined by RFC 7217 and returns the extended buffer. 425 // 426 // The opaque IID is generated from the cryptographic hash of the concatenation 427 // of the prefix, NIC's name, DAD counter (DAD retry counter) and the secret 428 // key. The secret key SHOULD be at least OpaqueIIDSecretKeyMinBytes bytes and 429 // MUST be generated to a pseudo-random number. See RFC 4086 for randomness 430 // requirements for security. 431 // 432 // If buf has enough capacity for the IID (IIDSize bytes), a new underlying 433 // array for the buffer will not be allocated. 434 func AppendOpaqueInterfaceIdentifier(buf []byte, prefix tcpip.Subnet, nicName string, dadCounter uint8, secretKey []byte) []byte { 435 // As per RFC 7217 section 5, the opaque identifier can be generated as a 436 // cryptographic hash of the concatenation of each of the function parameters. 437 // Note, we omit the optional Network_ID field. 438 h := sha256.New() 439 // h.Write never returns an error. 440 prefixID := prefix.ID() 441 h.Write([]byte(prefixID.AsSlice()[:IIDOffsetInIPv6Address])) 442 h.Write([]byte(nicName)) 443 h.Write([]byte{dadCounter}) 444 h.Write(secretKey) 445 446 var sumBuf [sha256.Size]byte 447 sum := h.Sum(sumBuf[:0]) 448 449 return append(buf, sum[:IIDSize]...) 450 } 451 452 // LinkLocalAddrWithOpaqueIID computes the default IPv6 link-local address with 453 // an opaque IID. 454 func LinkLocalAddrWithOpaqueIID(nicName string, dadCounter uint8, secretKey []byte) tcpip.Address { 455 lladdrb := [IPv6AddressSize]byte{ 456 0: 0xFE, 457 1: 0x80, 458 } 459 460 return tcpip.AddrFrom16([16]byte(AppendOpaqueInterfaceIdentifier(lladdrb[:IIDOffsetInIPv6Address], IPv6LinkLocalPrefix.Subnet(), nicName, dadCounter, secretKey))) 461 } 462 463 // IPv6AddressScope is the scope of an IPv6 address. 464 type IPv6AddressScope int 465 466 const ( 467 // LinkLocalScope indicates a link-local address. 468 LinkLocalScope IPv6AddressScope = iota 469 470 // GlobalScope indicates a global address. 471 GlobalScope 472 ) 473 474 // ScopeForIPv6Address returns the scope for an IPv6 address. 475 func ScopeForIPv6Address(addr tcpip.Address) (IPv6AddressScope, tcpip.Error) { 476 if addr.BitLen() != IPv6AddressSizeBits { 477 return GlobalScope, &tcpip.ErrBadAddress{} 478 } 479 480 switch { 481 case IsV6LinkLocalMulticastAddress(addr): 482 return LinkLocalScope, nil 483 484 case IsV6LinkLocalUnicastAddress(addr): 485 return LinkLocalScope, nil 486 487 default: 488 return GlobalScope, nil 489 } 490 } 491 492 // InitialTempIID generates the initial temporary IID history value to generate 493 // temporary SLAAC addresses with. 494 // 495 // Panics if initialTempIIDHistory is not at least IIDSize bytes. 496 func InitialTempIID(initialTempIIDHistory []byte, seed []byte, nicID tcpip.NICID) { 497 h := sha256.New() 498 // h.Write never returns an error. 499 h.Write(seed) 500 var nicIDBuf [4]byte 501 binary.BigEndian.PutUint32(nicIDBuf[:], uint32(nicID)) 502 h.Write(nicIDBuf[:]) 503 504 var sumBuf [sha256.Size]byte 505 sum := h.Sum(sumBuf[:0]) 506 507 if n := copy(initialTempIIDHistory, sum[sha256.Size-IIDSize:]); n != IIDSize { 508 panic(fmt.Sprintf("copied %d bytes, expected %d bytes", n, IIDSize)) 509 } 510 } 511 512 // GenerateTempIPv6SLAACAddr generates a temporary SLAAC IPv6 address for an 513 // associated stable/permanent SLAAC address. 514 // 515 // GenerateTempIPv6SLAACAddr will update the temporary IID history value to be 516 // used when generating a new temporary IID. 517 // 518 // Panics if tempIIDHistory is not at least IIDSize bytes. 519 func GenerateTempIPv6SLAACAddr(tempIIDHistory []byte, stableAddr tcpip.Address) tcpip.AddressWithPrefix { 520 addrBytes := stableAddr.As16() 521 h := sha256.New() 522 h.Write(tempIIDHistory) 523 h.Write(addrBytes[IIDOffsetInIPv6Address:]) 524 var sumBuf [sha256.Size]byte 525 sum := h.Sum(sumBuf[:0]) 526 527 // The rightmost 64 bits of sum are saved for the next iteration. 528 if n := copy(tempIIDHistory, sum[sha256.Size-IIDSize:]); n != IIDSize { 529 panic(fmt.Sprintf("copied %d bytes, expected %d bytes", n, IIDSize)) 530 } 531 532 // The leftmost 64 bits of sum is used as the IID. 533 if n := copy(addrBytes[IIDOffsetInIPv6Address:], sum); n != IIDSize { 534 panic(fmt.Sprintf("copied %d IID bytes, expected %d bytes", n, IIDSize)) 535 } 536 537 return tcpip.AddressWithPrefix{ 538 Address: tcpip.AddrFrom16(addrBytes), 539 PrefixLen: IIDOffsetInIPv6Address * 8, 540 } 541 } 542 543 // IPv6MulticastScope is the scope of a multicast IPv6 address, as defined by 544 // RFC 7346 section 2. 545 type IPv6MulticastScope uint8 546 547 // The various values for IPv6 multicast scopes, as per RFC 7346 section 2: 548 // 549 // +------+--------------------------+-------------------------+ 550 // | scop | NAME | REFERENCE | 551 // +------+--------------------------+-------------------------+ 552 // | 0 | Reserved | [RFC4291], RFC 7346 | 553 // | 1 | Interface-Local scope | [RFC4291], RFC 7346 | 554 // | 2 | Link-Local scope | [RFC4291], RFC 7346 | 555 // | 3 | Realm-Local scope | [RFC4291], RFC 7346 | 556 // | 4 | Admin-Local scope | [RFC4291], RFC 7346 | 557 // | 5 | Site-Local scope | [RFC4291], RFC 7346 | 558 // | 6 | Unassigned | | 559 // | 7 | Unassigned | | 560 // | 8 | Organization-Local scope | [RFC4291], RFC 7346 | 561 // | 9 | Unassigned | | 562 // | A | Unassigned | | 563 // | B | Unassigned | | 564 // | C | Unassigned | | 565 // | D | Unassigned | | 566 // | E | Global scope | [RFC4291], RFC 7346 | 567 // | F | Reserved | [RFC4291], RFC 7346 | 568 // +------+--------------------------+-------------------------+ 569 const ( 570 IPv6Reserved0MulticastScope = IPv6MulticastScope(0x0) 571 IPv6InterfaceLocalMulticastScope = IPv6MulticastScope(0x1) 572 IPv6LinkLocalMulticastScope = IPv6MulticastScope(0x2) 573 IPv6RealmLocalMulticastScope = IPv6MulticastScope(0x3) 574 IPv6AdminLocalMulticastScope = IPv6MulticastScope(0x4) 575 IPv6SiteLocalMulticastScope = IPv6MulticastScope(0x5) 576 IPv6OrganizationLocalMulticastScope = IPv6MulticastScope(0x8) 577 IPv6GlobalMulticastScope = IPv6MulticastScope(0xE) 578 IPv6ReservedFMulticastScope = IPv6MulticastScope(0xF) 579 ) 580 581 // V6MulticastScope returns the scope of a multicast address. 582 func V6MulticastScope(addr tcpip.Address) IPv6MulticastScope { 583 addrBytes := addr.As16() 584 return IPv6MulticastScope(addrBytes[ipv6MulticastAddressScopeByteIdx] & ipv6MulticastAddressScopeMask) 585 }