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