gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/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  	"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  }