ipv6.go raw

   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  	"gvisor.dev/gvisor/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  // SourceAddressSlice returns the "source address" field of the ipv6 header as a
 229  // byte slice.
 230  func (b IPv6) SourceAddressSlice() []byte {
 231  	return []byte(b[v6SrcAddr:][:IPv6AddressSize])
 232  }
 233  
 234  // DestinationAddressSlice returns the "destination address" field of the ipv6
 235  // header as a byte slice.
 236  func (b IPv6) DestinationAddressSlice() []byte {
 237  	return []byte(b[v6DstAddr:][:IPv6AddressSize])
 238  }
 239  
 240  // Checksum implements Network.Checksum. Given that IPv6 doesn't have a
 241  // checksum, it just returns 0.
 242  func (IPv6) Checksum() uint16 {
 243  	return 0
 244  }
 245  
 246  // TOS returns the "traffic class" and "flow label" fields of the ipv6 header.
 247  func (b IPv6) TOS() (uint8, uint32) {
 248  	v := binary.BigEndian.Uint32(b[versTCFL:])
 249  	return uint8(v >> 20), v & 0xfffff
 250  }
 251  
 252  // SetTOS sets the "traffic class" and "flow label" fields of the ipv6 header.
 253  func (b IPv6) SetTOS(t uint8, l uint32) {
 254  	vtf := (6 << 28) | (uint32(t) << 20) | (l & 0xfffff)
 255  	binary.BigEndian.PutUint32(b[versTCFL:], vtf)
 256  }
 257  
 258  // SetPayloadLength sets the "payload length" field of the ipv6 header.
 259  func (b IPv6) SetPayloadLength(payloadLength uint16) {
 260  	binary.BigEndian.PutUint16(b[IPv6PayloadLenOffset:], payloadLength)
 261  }
 262  
 263  // SetSourceAddress sets the "source address" field of the ipv6 header.
 264  func (b IPv6) SetSourceAddress(addr tcpip.Address) {
 265  	copy(b[v6SrcAddr:][:IPv6AddressSize], addr.AsSlice())
 266  }
 267  
 268  // SetDestinationAddress sets the "destination address" field of the ipv6
 269  // header.
 270  func (b IPv6) SetDestinationAddress(addr tcpip.Address) {
 271  	copy(b[v6DstAddr:][:IPv6AddressSize], addr.AsSlice())
 272  }
 273  
 274  // SetHopLimit sets the value of the "Hop Limit" field.
 275  func (b IPv6) SetHopLimit(v uint8) {
 276  	b[hopLimit] = v
 277  }
 278  
 279  // SetNextHeader sets the value of the "next header" field of the ipv6 header.
 280  func (b IPv6) SetNextHeader(v uint8) {
 281  	b[IPv6NextHeaderOffset] = v
 282  }
 283  
 284  // SetChecksum implements Network.SetChecksum. Given that IPv6 doesn't have a
 285  // checksum, it is empty.
 286  func (IPv6) SetChecksum(uint16) {
 287  }
 288  
 289  // Encode encodes all the fields of the ipv6 header.
 290  func (b IPv6) Encode(i *IPv6Fields) {
 291  	extHdr := b[IPv6MinimumSize:]
 292  	b.SetTOS(i.TrafficClass, i.FlowLabel)
 293  	b.SetPayloadLength(i.PayloadLength)
 294  	b[hopLimit] = i.HopLimit
 295  	b.SetSourceAddress(i.SrcAddr)
 296  	b.SetDestinationAddress(i.DstAddr)
 297  	nextHeader, _ := i.ExtensionHeaders.Serialize(i.TransportProtocol, extHdr)
 298  	b[IPv6NextHeaderOffset] = nextHeader
 299  }
 300  
 301  // IsValid performs basic validation on the packet.
 302  func (b IPv6) IsValid(pktSize int) bool {
 303  	if len(b) < IPv6MinimumSize {
 304  		return false
 305  	}
 306  
 307  	dlen := int(b.PayloadLength())
 308  	if dlen > pktSize-IPv6MinimumSize {
 309  		return false
 310  	}
 311  
 312  	if IPVersion(b) != IPv6Version {
 313  		return false
 314  	}
 315  
 316  	return true
 317  }
 318  
 319  // IsV4MappedAddress determines if the provided address is an IPv4 mapped
 320  // address by checking if its prefix is 0:0:0:0:0:ffff::/96.
 321  func IsV4MappedAddress(addr tcpip.Address) bool {
 322  	if addr.BitLen() != IPv6AddressSizeBits {
 323  		return false
 324  	}
 325  
 326  	return IPv4MappedIPv6Subnet.Contains(addr)
 327  }
 328  
 329  // IsV6MulticastAddress determines if the provided address is an IPv6
 330  // multicast address (anything starting with FF).
 331  func IsV6MulticastAddress(addr tcpip.Address) bool {
 332  	if addr.BitLen() != IPv6AddressSizeBits {
 333  		return false
 334  	}
 335  	return addr.As16()[0] == 0xff
 336  }
 337  
 338  // IsV6UnicastAddress determines if the provided address is a valid IPv6
 339  // unicast (and specified) address. That is, IsV6UnicastAddress returns
 340  // true if addr contains IPv6AddressSize bytes, is not the unspecified
 341  // address and is not a multicast address.
 342  func IsV6UnicastAddress(addr tcpip.Address) bool {
 343  	if addr.BitLen() != IPv6AddressSizeBits {
 344  		return false
 345  	}
 346  
 347  	// Must not be unspecified
 348  	if addr == IPv6Any {
 349  		return false
 350  	}
 351  
 352  	// Return if not a multicast.
 353  	return addr.As16()[0] != 0xff
 354  }
 355  
 356  var solicitedNodeMulticastPrefix = [13]byte{0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff}
 357  
 358  // SolicitedNodeAddr computes the solicited-node multicast address. This is
 359  // used for NDP. Described in RFC 4291. The argument must be a full-length IPv6
 360  // address.
 361  func SolicitedNodeAddr(addr tcpip.Address) tcpip.Address {
 362  	addrBytes := addr.As16()
 363  	return tcpip.AddrFrom16([16]byte(append(solicitedNodeMulticastPrefix[:], addrBytes[len(addrBytes)-3:]...)))
 364  }
 365  
 366  // IsSolicitedNodeAddr determines whether the address is a solicited-node
 367  // multicast address.
 368  func IsSolicitedNodeAddr(addr tcpip.Address) bool {
 369  	addrBytes := addr.As16()
 370  	return solicitedNodeMulticastPrefix == [13]byte(addrBytes[:len(addrBytes)-3])
 371  }
 372  
 373  // EthernetAdddressToModifiedEUI64IntoBuf populates buf with a modified EUI-64
 374  // from a 48-bit Ethernet/MAC address, as per RFC 4291 section 2.5.1.
 375  //
 376  // buf MUST be at least 8 bytes.
 377  func EthernetAdddressToModifiedEUI64IntoBuf(linkAddr tcpip.LinkAddress, buf []byte) {
 378  	buf[0] = linkAddr[0] ^ 2
 379  	buf[1] = linkAddr[1]
 380  	buf[2] = linkAddr[2]
 381  	buf[3] = 0xFF
 382  	buf[4] = 0xFE
 383  	buf[5] = linkAddr[3]
 384  	buf[6] = linkAddr[4]
 385  	buf[7] = linkAddr[5]
 386  }
 387  
 388  // EthernetAddressToModifiedEUI64 computes a modified EUI-64 from a 48-bit
 389  // Ethernet/MAC address, as per RFC 4291 section 2.5.1.
 390  func EthernetAddressToModifiedEUI64(linkAddr tcpip.LinkAddress) [IIDSize]byte {
 391  	var buf [IIDSize]byte
 392  	EthernetAdddressToModifiedEUI64IntoBuf(linkAddr, buf[:])
 393  	return buf
 394  }
 395  
 396  // LinkLocalAddr computes the default IPv6 link-local address from a link-layer
 397  // (MAC) address.
 398  func LinkLocalAddr(linkAddr tcpip.LinkAddress) tcpip.Address {
 399  	// Convert a 48-bit MAC to a modified EUI-64 and then prepend the
 400  	// link-local header, FE80::.
 401  	//
 402  	// The conversion is very nearly:
 403  	//	aa:bb:cc:dd:ee:ff => FE80::Aabb:ccFF:FEdd:eeff
 404  	// Note the capital A. The conversion aa->Aa involves a bit flip.
 405  	lladdrb := [IPv6AddressSize]byte{
 406  		0: 0xFE,
 407  		1: 0x80,
 408  	}
 409  	EthernetAdddressToModifiedEUI64IntoBuf(linkAddr, lladdrb[IIDOffsetInIPv6Address:])
 410  	return tcpip.AddrFrom16(lladdrb)
 411  }
 412  
 413  // IsV6LinkLocalUnicastAddress returns true iff the provided address is an IPv6
 414  // link-local unicast address, as defined by RFC 4291 section 2.5.6.
 415  func IsV6LinkLocalUnicastAddress(addr tcpip.Address) bool {
 416  	if addr.BitLen() != IPv6AddressSizeBits {
 417  		return false
 418  	}
 419  	addrBytes := addr.As16()
 420  	return addrBytes[0] == 0xfe && (addrBytes[1]&0xc0) == 0x80
 421  }
 422  
 423  // IsV6LoopbackAddress returns true iff the provided address is an IPv6 loopback
 424  // address, as defined by RFC 4291 section 2.5.3.
 425  func IsV6LoopbackAddress(addr tcpip.Address) bool {
 426  	return addr == IPv6Loopback
 427  }
 428  
 429  // IsV6LinkLocalMulticastAddress returns true iff the provided address is an
 430  // IPv6 link-local multicast address, as defined by RFC 4291 section 2.7.
 431  func IsV6LinkLocalMulticastAddress(addr tcpip.Address) bool {
 432  	return IsV6MulticastAddress(addr) && V6MulticastScope(addr) == IPv6LinkLocalMulticastScope
 433  }
 434  
 435  // AppendOpaqueInterfaceIdentifier appends a 64 bit opaque interface identifier
 436  // (IID) to buf as outlined by RFC 7217 and returns the extended buffer.
 437  //
 438  // The opaque IID is generated from the cryptographic hash of the concatenation
 439  // of the prefix, NIC's name, DAD counter (DAD retry counter) and the secret
 440  // key. The secret key SHOULD be at least OpaqueIIDSecretKeyMinBytes bytes and
 441  // MUST be generated to a pseudo-random number. See RFC 4086 for randomness
 442  // requirements for security.
 443  //
 444  // If buf has enough capacity for the IID (IIDSize bytes), a new underlying
 445  // array for the buffer will not be allocated.
 446  func AppendOpaqueInterfaceIdentifier(buf []byte, prefix tcpip.Subnet, nicName string, dadCounter uint8, secretKey []byte) []byte {
 447  	// As per RFC 7217 section 5, the opaque identifier can be generated as a
 448  	// cryptographic hash of the concatenation of each of the function parameters.
 449  	// Note, we omit the optional Network_ID field.
 450  	h := sha256.New()
 451  	// h.Write never returns an error.
 452  	prefixID := prefix.ID()
 453  	h.Write([]byte(prefixID.AsSlice()[:IIDOffsetInIPv6Address]))
 454  	h.Write([]byte(nicName))
 455  	h.Write([]byte{dadCounter})
 456  	h.Write(secretKey)
 457  
 458  	var sumBuf [sha256.Size]byte
 459  	sum := h.Sum(sumBuf[:0])
 460  
 461  	return append(buf, sum[:IIDSize]...)
 462  }
 463  
 464  // LinkLocalAddrWithOpaqueIID computes the default IPv6 link-local address with
 465  // an opaque IID.
 466  func LinkLocalAddrWithOpaqueIID(nicName string, dadCounter uint8, secretKey []byte) tcpip.Address {
 467  	lladdrb := [IPv6AddressSize]byte{
 468  		0: 0xFE,
 469  		1: 0x80,
 470  	}
 471  
 472  	return tcpip.AddrFrom16([16]byte(AppendOpaqueInterfaceIdentifier(lladdrb[:IIDOffsetInIPv6Address], IPv6LinkLocalPrefix.Subnet(), nicName, dadCounter, secretKey)))
 473  }
 474  
 475  // IPv6AddressScope is the scope of an IPv6 address.
 476  type IPv6AddressScope int
 477  
 478  const (
 479  	// LinkLocalScope indicates a link-local address.
 480  	LinkLocalScope IPv6AddressScope = iota
 481  
 482  	// GlobalScope indicates a global address.
 483  	GlobalScope
 484  )
 485  
 486  // ScopeForIPv6Address returns the scope for an IPv6 address.
 487  func ScopeForIPv6Address(addr tcpip.Address) (IPv6AddressScope, tcpip.Error) {
 488  	if addr.BitLen() != IPv6AddressSizeBits {
 489  		return GlobalScope, &tcpip.ErrBadAddress{}
 490  	}
 491  
 492  	switch {
 493  	case IsV6LinkLocalMulticastAddress(addr):
 494  		return LinkLocalScope, nil
 495  
 496  	case IsV6LinkLocalUnicastAddress(addr):
 497  		return LinkLocalScope, nil
 498  
 499  	default:
 500  		return GlobalScope, nil
 501  	}
 502  }
 503  
 504  // InitialTempIID generates the initial temporary IID history value to generate
 505  // temporary SLAAC addresses with.
 506  //
 507  // Panics if initialTempIIDHistory is not at least IIDSize bytes.
 508  func InitialTempIID(initialTempIIDHistory []byte, seed []byte, nicID tcpip.NICID) {
 509  	h := sha256.New()
 510  	// h.Write never returns an error.
 511  	h.Write(seed)
 512  	var nicIDBuf [4]byte
 513  	binary.BigEndian.PutUint32(nicIDBuf[:], uint32(nicID))
 514  	h.Write(nicIDBuf[:])
 515  
 516  	var sumBuf [sha256.Size]byte
 517  	sum := h.Sum(sumBuf[:0])
 518  
 519  	if n := copy(initialTempIIDHistory, sum[sha256.Size-IIDSize:]); n != IIDSize {
 520  		panic(fmt.Sprintf("copied %d bytes, expected %d bytes", n, IIDSize))
 521  	}
 522  }
 523  
 524  // GenerateTempIPv6SLAACAddr generates a temporary SLAAC IPv6 address for an
 525  // associated stable/permanent SLAAC address.
 526  //
 527  // GenerateTempIPv6SLAACAddr will update the temporary IID history value to be
 528  // used when generating a new temporary IID.
 529  //
 530  // Panics if tempIIDHistory is not at least IIDSize bytes.
 531  func GenerateTempIPv6SLAACAddr(tempIIDHistory []byte, stableAddr tcpip.Address) tcpip.AddressWithPrefix {
 532  	addrBytes := stableAddr.As16()
 533  	h := sha256.New()
 534  	h.Write(tempIIDHistory)
 535  	h.Write(addrBytes[IIDOffsetInIPv6Address:])
 536  	var sumBuf [sha256.Size]byte
 537  	sum := h.Sum(sumBuf[:0])
 538  
 539  	// The rightmost 64 bits of sum are saved for the next iteration.
 540  	if n := copy(tempIIDHistory, sum[sha256.Size-IIDSize:]); n != IIDSize {
 541  		panic(fmt.Sprintf("copied %d bytes, expected %d bytes", n, IIDSize))
 542  	}
 543  
 544  	// The leftmost 64 bits of sum is used as the IID.
 545  	if n := copy(addrBytes[IIDOffsetInIPv6Address:], sum); n != IIDSize {
 546  		panic(fmt.Sprintf("copied %d IID bytes, expected %d bytes", n, IIDSize))
 547  	}
 548  
 549  	return tcpip.AddressWithPrefix{
 550  		Address:   tcpip.AddrFrom16(addrBytes),
 551  		PrefixLen: IIDOffsetInIPv6Address * 8,
 552  	}
 553  }
 554  
 555  // IPv6MulticastScope is the scope of a multicast IPv6 address, as defined by
 556  // RFC 7346 section 2.
 557  type IPv6MulticastScope uint8
 558  
 559  // The various values for IPv6 multicast scopes, as per RFC 7346 section 2:
 560  //
 561  //	+------+--------------------------+-------------------------+
 562  //	| scop | NAME                     | REFERENCE               |
 563  //	+------+--------------------------+-------------------------+
 564  //	|  0   | Reserved                 | [RFC4291], RFC 7346     |
 565  //	|  1   | Interface-Local scope    | [RFC4291], RFC 7346     |
 566  //	|  2   | Link-Local scope         | [RFC4291], RFC 7346     |
 567  //	|  3   | Realm-Local scope        | [RFC4291], RFC 7346     |
 568  //	|  4   | Admin-Local scope        | [RFC4291], RFC 7346     |
 569  //	|  5   | Site-Local scope         | [RFC4291], RFC 7346     |
 570  //	|  6   | Unassigned               |                         |
 571  //	|  7   | Unassigned               |                         |
 572  //	|  8   | Organization-Local scope | [RFC4291], RFC 7346     |
 573  //	|  9   | Unassigned               |                         |
 574  //	|  A   | Unassigned               |                         |
 575  //	|  B   | Unassigned               |                         |
 576  //	|  C   | Unassigned               |                         |
 577  //	|  D   | Unassigned               |                         |
 578  //	|  E   | Global scope             | [RFC4291], RFC 7346     |
 579  //	|  F   | Reserved                 | [RFC4291], RFC 7346     |
 580  //	+------+--------------------------+-------------------------+
 581  const (
 582  	IPv6Reserved0MulticastScope         = IPv6MulticastScope(0x0)
 583  	IPv6InterfaceLocalMulticastScope    = IPv6MulticastScope(0x1)
 584  	IPv6LinkLocalMulticastScope         = IPv6MulticastScope(0x2)
 585  	IPv6RealmLocalMulticastScope        = IPv6MulticastScope(0x3)
 586  	IPv6AdminLocalMulticastScope        = IPv6MulticastScope(0x4)
 587  	IPv6SiteLocalMulticastScope         = IPv6MulticastScope(0x5)
 588  	IPv6OrganizationLocalMulticastScope = IPv6MulticastScope(0x8)
 589  	IPv6GlobalMulticastScope            = IPv6MulticastScope(0xE)
 590  	IPv6ReservedFMulticastScope         = IPv6MulticastScope(0xF)
 591  )
 592  
 593  // V6MulticastScope returns the scope of a multicast address.
 594  func V6MulticastScope(addr tcpip.Address) IPv6MulticastScope {
 595  	addrBytes := addr.As16()
 596  	return IPv6MulticastScope(addrBytes[ipv6MulticastAddressScopeByteIdx] & ipv6MulticastAddressScopeMask)
 597  }
 598