gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/tcpip/header/ipv6_extension_headers.go (about) 1 // Copyright 2020 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 "encoding/binary" 19 "errors" 20 "fmt" 21 "io" 22 "math" 23 24 "gvisor.dev/gvisor/pkg/buffer" 25 "gvisor.dev/gvisor/pkg/tcpip" 26 ) 27 28 // IPv6ExtensionHeaderIdentifier is an IPv6 extension header identifier. 29 type IPv6ExtensionHeaderIdentifier uint8 30 31 const ( 32 // IPv6HopByHopOptionsExtHdrIdentifier is the header identifier of a Hop by 33 // Hop Options extension header, as per RFC 8200 section 4.3. 34 IPv6HopByHopOptionsExtHdrIdentifier IPv6ExtensionHeaderIdentifier = 0 35 36 // IPv6RoutingExtHdrIdentifier is the header identifier of a Routing extension 37 // header, as per RFC 8200 section 4.4. 38 IPv6RoutingExtHdrIdentifier IPv6ExtensionHeaderIdentifier = 43 39 40 // IPv6FragmentExtHdrIdentifier is the header identifier of a Fragment 41 // extension header, as per RFC 8200 section 4.5. 42 IPv6FragmentExtHdrIdentifier IPv6ExtensionHeaderIdentifier = 44 43 44 // IPv6DestinationOptionsExtHdrIdentifier is the header identifier of a 45 // Destination Options extension header, as per RFC 8200 section 4.6. 46 IPv6DestinationOptionsExtHdrIdentifier IPv6ExtensionHeaderIdentifier = 60 47 48 // IPv6NoNextHeaderIdentifier is the header identifier used to signify the end 49 // of an IPv6 payload, as per RFC 8200 section 4.7. 50 IPv6NoNextHeaderIdentifier IPv6ExtensionHeaderIdentifier = 59 51 52 // IPv6UnknownExtHdrIdentifier is reserved by IANA. 53 // https://www.iana.org/assignments/ipv6-parameters/ipv6-parameters.xhtml#extension-header 54 // "254 Use for experimentation and testing [RFC3692][RFC4727]" 55 IPv6UnknownExtHdrIdentifier IPv6ExtensionHeaderIdentifier = 254 56 ) 57 58 const ( 59 // ipv6UnknownExtHdrOptionActionMask is the mask of the action to take when 60 // a node encounters an unrecognized option. 61 ipv6UnknownExtHdrOptionActionMask = 192 62 63 // ipv6UnknownExtHdrOptionActionShift is the least significant bits to discard 64 // from the action value for an unrecognized option identifier. 65 ipv6UnknownExtHdrOptionActionShift = 6 66 67 // ipv6RoutingExtHdrSegmentsLeftIdx is the index to the Segments Left field 68 // within an IPv6RoutingExtHdr. 69 ipv6RoutingExtHdrSegmentsLeftIdx = 1 70 71 // IPv6FragmentExtHdrLength is the length of an IPv6 extension header, in 72 // bytes. 73 IPv6FragmentExtHdrLength = 8 74 75 // ipv6FragmentExtHdrFragmentOffsetOffset is the offset to the start of the 76 // Fragment Offset field within an IPv6FragmentExtHdr. 77 ipv6FragmentExtHdrFragmentOffsetOffset = 0 78 79 // ipv6FragmentExtHdrFragmentOffsetShift is the bit offset of the Fragment 80 // Offset field within an IPv6FragmentExtHdr. 81 ipv6FragmentExtHdrFragmentOffsetShift = 3 82 83 // ipv6FragmentExtHdrFlagsIdx is the index to the flags field within an 84 // IPv6FragmentExtHdr. 85 ipv6FragmentExtHdrFlagsIdx = 1 86 87 // ipv6FragmentExtHdrMFlagMask is the mask of the More (M) flag within the 88 // flags field of an IPv6FragmentExtHdr. 89 ipv6FragmentExtHdrMFlagMask = 1 90 91 // ipv6FragmentExtHdrIdentificationOffset is the offset to the Identification 92 // field within an IPv6FragmentExtHdr. 93 ipv6FragmentExtHdrIdentificationOffset = 2 94 95 // ipv6ExtHdrLenBytesPerUnit is the unit size of an extension header's length 96 // field. That is, given a Length field of 2, the extension header expects 97 // 16 bytes following the first 8 bytes (see ipv6ExtHdrLenBytesExcluded for 98 // details about the first 8 bytes' exclusion from the Length field). 99 ipv6ExtHdrLenBytesPerUnit = 8 100 101 // ipv6ExtHdrLenBytesExcluded is the number of bytes excluded from an 102 // extension header's Length field following the Length field. 103 // 104 // The Length field excludes the first 8 bytes, but the Next Header and Length 105 // field take up the first 2 of the 8 bytes so we expect (at minimum) 6 bytes 106 // after the Length field. 107 // 108 // This ensures that every extension header is at least 8 bytes. 109 ipv6ExtHdrLenBytesExcluded = 6 110 111 // IPv6FragmentExtHdrFragmentOffsetBytesPerUnit is the unit size of a Fragment 112 // extension header's Fragment Offset field. That is, given a Fragment Offset 113 // of 2, the extension header is indicating that the fragment's payload 114 // starts at the 16th byte in the reassembled packet. 115 IPv6FragmentExtHdrFragmentOffsetBytesPerUnit = 8 116 ) 117 118 // padIPv6OptionsLength returns the total length for IPv6 options of length l 119 // considering the 8-octet alignment as stated in RFC 8200 Section 4.2. 120 func padIPv6OptionsLength(length int) int { 121 return (length + ipv6ExtHdrLenBytesPerUnit - 1) & ^(ipv6ExtHdrLenBytesPerUnit - 1) 122 } 123 124 // padIPv6Option fills b with the appropriate padding options depending on its 125 // length. 126 func padIPv6Option(b []byte) { 127 switch len(b) { 128 case 0: // No padding needed. 129 case 1: // Pad with Pad1. 130 b[ipv6ExtHdrOptionTypeOffset] = uint8(ipv6Pad1ExtHdrOptionIdentifier) 131 default: // Pad with PadN. 132 s := b[ipv6ExtHdrOptionPayloadOffset:] 133 clear(s) 134 b[ipv6ExtHdrOptionTypeOffset] = uint8(ipv6PadNExtHdrOptionIdentifier) 135 b[ipv6ExtHdrOptionLengthOffset] = uint8(len(s)) 136 } 137 } 138 139 // ipv6OptionsAlignmentPadding returns the number of padding bytes needed to 140 // serialize an option at headerOffset with alignment requirements 141 // [align]n + alignOffset. 142 func ipv6OptionsAlignmentPadding(headerOffset int, align int, alignOffset int) int { 143 padLen := headerOffset - alignOffset 144 return ((padLen + align - 1) & ^(align - 1)) - padLen 145 } 146 147 // IPv6PayloadHeader is implemented by the various headers that can be found 148 // in an IPv6 payload. 149 // 150 // These headers include IPv6 extension headers or upper layer data. 151 type IPv6PayloadHeader interface { 152 isIPv6PayloadHeader() 153 154 // Release frees all resources held by the header. 155 Release() 156 } 157 158 // IPv6RawPayloadHeader the remainder of an IPv6 payload after an iterator 159 // encounters a Next Header field it does not recognize as an IPv6 extension 160 // header. The caller is responsible for releasing the underlying buffer after 161 // it's no longer needed. 162 type IPv6RawPayloadHeader struct { 163 Identifier IPv6ExtensionHeaderIdentifier 164 Buf buffer.Buffer 165 } 166 167 // isIPv6PayloadHeader implements IPv6PayloadHeader.isIPv6PayloadHeader. 168 func (IPv6RawPayloadHeader) isIPv6PayloadHeader() {} 169 170 // Release implements IPv6PayloadHeader.Release. 171 func (i IPv6RawPayloadHeader) Release() { 172 i.Buf.Release() 173 } 174 175 // ipv6OptionsExtHdr is an IPv6 extension header that holds options. 176 type ipv6OptionsExtHdr struct { 177 buf *buffer.View 178 } 179 180 // Release implements IPv6PayloadHeader.Release. 181 func (i ipv6OptionsExtHdr) Release() { 182 if i.buf != nil { 183 i.buf.Release() 184 } 185 } 186 187 // Iter returns an iterator over the IPv6 extension header options held in b. 188 func (i ipv6OptionsExtHdr) Iter() IPv6OptionsExtHdrOptionsIterator { 189 it := IPv6OptionsExtHdrOptionsIterator{} 190 it.reader = i.buf 191 return it 192 } 193 194 // IPv6OptionsExtHdrOptionsIterator is an iterator over IPv6 extension header 195 // options. 196 // 197 // Note, between when an IPv6OptionsExtHdrOptionsIterator is obtained and last 198 // used, no changes to the underlying buffer may happen. Doing so may cause 199 // undefined and unexpected behaviour. It is fine to obtain an 200 // IPv6OptionsExtHdrOptionsIterator, iterate over the first few options then 201 // modify the backing payload so long as the IPv6OptionsExtHdrOptionsIterator 202 // obtained before modification is no longer used. 203 type IPv6OptionsExtHdrOptionsIterator struct { 204 reader *buffer.View 205 206 // optionOffset is the number of bytes from the first byte of the 207 // options field to the beginning of the current option. 208 optionOffset uint32 209 210 // nextOptionOffset is the offset of the next option. 211 nextOptionOffset uint32 212 } 213 214 // OptionOffset returns the number of bytes parsed while processing the 215 // option field of the current Extension Header. 216 func (i *IPv6OptionsExtHdrOptionsIterator) OptionOffset() uint32 { 217 return i.optionOffset 218 } 219 220 // IPv6OptionUnknownAction is the action that must be taken if the processing 221 // IPv6 node does not recognize the option, as outlined in RFC 8200 section 4.2. 222 type IPv6OptionUnknownAction int 223 224 const ( 225 // IPv6OptionUnknownActionSkip indicates that the unrecognized option must 226 // be skipped and the node should continue processing the header. 227 IPv6OptionUnknownActionSkip IPv6OptionUnknownAction = 0 228 229 // IPv6OptionUnknownActionDiscard indicates that the packet must be silently 230 // discarded. 231 IPv6OptionUnknownActionDiscard IPv6OptionUnknownAction = 1 232 233 // IPv6OptionUnknownActionDiscardSendICMP indicates that the packet must be 234 // discarded and the node must send an ICMP Parameter Problem, Code 2, message 235 // to the packet's source, regardless of whether or not the packet's 236 // Destination was a multicast address. 237 IPv6OptionUnknownActionDiscardSendICMP IPv6OptionUnknownAction = 2 238 239 // IPv6OptionUnknownActionDiscardSendICMPNoMulticastDest indicates that the 240 // packet must be discarded and the node must send an ICMP Parameter Problem, 241 // Code 2, message to the packet's source only if the packet's Destination was 242 // not a multicast address. 243 IPv6OptionUnknownActionDiscardSendICMPNoMulticastDest IPv6OptionUnknownAction = 3 244 ) 245 246 // IPv6ExtHdrOption is implemented by the various IPv6 extension header options. 247 type IPv6ExtHdrOption interface { 248 // UnknownAction returns the action to take in response to an unrecognized 249 // option. 250 UnknownAction() IPv6OptionUnknownAction 251 252 // isIPv6ExtHdrOption is used to "lock" this interface so it is not 253 // implemented by other packages. 254 isIPv6ExtHdrOption() 255 } 256 257 // IPv6ExtHdrOptionIdentifier is an IPv6 extension header option identifier. 258 type IPv6ExtHdrOptionIdentifier uint8 259 260 const ( 261 // ipv6Pad1ExtHdrOptionIdentifier is the identifier for a padding option that 262 // provides 1 byte padding, as outlined in RFC 8200 section 4.2. 263 ipv6Pad1ExtHdrOptionIdentifier IPv6ExtHdrOptionIdentifier = 0 264 265 // ipv6PadNExtHdrOptionIdentifier is the identifier for a padding option that 266 // provides variable length byte padding, as outlined in RFC 8200 section 4.2. 267 ipv6PadNExtHdrOptionIdentifier IPv6ExtHdrOptionIdentifier = 1 268 269 // ipv6RouterAlertHopByHopOptionIdentifier is the identifier for the Router 270 // Alert Hop by Hop option as defined in RFC 2711 section 2.1. 271 ipv6RouterAlertHopByHopOptionIdentifier IPv6ExtHdrOptionIdentifier = 5 272 273 // ipv6ExtHdrOptionTypeOffset is the option type offset in an extension header 274 // option as defined in RFC 8200 section 4.2. 275 ipv6ExtHdrOptionTypeOffset = 0 276 277 // ipv6ExtHdrOptionLengthOffset is the option length offset in an extension 278 // header option as defined in RFC 8200 section 4.2. 279 ipv6ExtHdrOptionLengthOffset = 1 280 281 // ipv6ExtHdrOptionPayloadOffset is the option payload offset in an extension 282 // header option as defined in RFC 8200 section 4.2. 283 ipv6ExtHdrOptionPayloadOffset = 2 284 ) 285 286 // ipv6UnknownActionFromIdentifier maps an extension header option's 287 // identifier's high bits to the action to take when the identifier is unknown. 288 func ipv6UnknownActionFromIdentifier(id IPv6ExtHdrOptionIdentifier) IPv6OptionUnknownAction { 289 return IPv6OptionUnknownAction((id & ipv6UnknownExtHdrOptionActionMask) >> ipv6UnknownExtHdrOptionActionShift) 290 } 291 292 // ErrMalformedIPv6ExtHdrOption indicates that an IPv6 extension header option 293 // is malformed. 294 var ErrMalformedIPv6ExtHdrOption = errors.New("malformed IPv6 extension header option") 295 296 // IPv6UnknownExtHdrOption holds the identifier and data for an IPv6 extension 297 // header option that is unknown by the parsing utilities. 298 type IPv6UnknownExtHdrOption struct { 299 Identifier IPv6ExtHdrOptionIdentifier 300 Data *buffer.View 301 } 302 303 // UnknownAction implements IPv6OptionUnknownAction.UnknownAction. 304 func (o *IPv6UnknownExtHdrOption) UnknownAction() IPv6OptionUnknownAction { 305 return ipv6UnknownActionFromIdentifier(o.Identifier) 306 } 307 308 // isIPv6ExtHdrOption implements IPv6ExtHdrOption.isIPv6ExtHdrOption. 309 func (*IPv6UnknownExtHdrOption) isIPv6ExtHdrOption() {} 310 311 // Next returns the next option in the options data. 312 // 313 // If the next item is not a known extension header option, 314 // IPv6UnknownExtHdrOption will be returned with the option identifier and data. 315 // 316 // The return is of the format (option, done, error). done will be true when 317 // Next is unable to return anything because the iterator has reached the end of 318 // the options data, or an error occurred. 319 func (i *IPv6OptionsExtHdrOptionsIterator) Next() (IPv6ExtHdrOption, bool, error) { 320 for { 321 i.optionOffset = i.nextOptionOffset 322 temp, err := i.reader.ReadByte() 323 if err != nil { 324 // If we can't read the first byte of a new option, then we know the 325 // options buffer has been exhausted and we are done iterating. 326 return nil, true, nil 327 } 328 id := IPv6ExtHdrOptionIdentifier(temp) 329 330 // If the option identifier indicates the option is a Pad1 option, then we 331 // know the option does not have Length and Data fields. End processing of 332 // the Pad1 option and continue processing the buffer as a new option. 333 if id == ipv6Pad1ExtHdrOptionIdentifier { 334 i.nextOptionOffset = i.optionOffset + 1 335 continue 336 } 337 338 length, err := i.reader.ReadByte() 339 if err != nil { 340 if err != io.EOF { 341 // ReadByte should only ever return nil or io.EOF. 342 panic(fmt.Sprintf("unexpected error when reading the option's Length field for option with id = %d: %s", id, err)) 343 } 344 345 // We use io.ErrUnexpectedEOF as exhausting the buffer is unexpected once 346 // we start parsing an option; we expect the reader to contain enough 347 // bytes for the whole option. 348 return nil, true, fmt.Errorf("error when reading the option's Length field for option with id = %d: %w", id, io.ErrUnexpectedEOF) 349 } 350 351 // Do we have enough bytes in the reader for the next option? 352 if n := i.reader.Size(); n < int(length) { 353 // Consume the remaining buffer. 354 i.reader.TrimFront(i.reader.Size()) 355 356 // We return the same error as if we failed to read a non-padding option 357 // so consumers of this iterator don't need to differentiate between 358 // padding and non-padding options. 359 return nil, true, fmt.Errorf("read %d out of %d option data bytes for option with id = %d: %w", n, length, id, io.ErrUnexpectedEOF) 360 } 361 362 i.nextOptionOffset = i.optionOffset + uint32(length) + 1 /* option ID */ + 1 /* length byte */ 363 364 switch id { 365 case ipv6PadNExtHdrOptionIdentifier: 366 // Special-case the variable length padding option to avoid a copy. 367 i.reader.TrimFront(int(length)) 368 continue 369 case ipv6RouterAlertHopByHopOptionIdentifier: 370 var routerAlertValue [ipv6RouterAlertPayloadLength]byte 371 if n, err := io.ReadFull(i.reader, routerAlertValue[:]); err != nil { 372 switch err { 373 case io.EOF, io.ErrUnexpectedEOF: 374 return nil, true, fmt.Errorf("got invalid length (%d) for router alert option (want = %d): %w", length, ipv6RouterAlertPayloadLength, ErrMalformedIPv6ExtHdrOption) 375 default: 376 return nil, true, fmt.Errorf("read %d out of %d option data bytes for router alert option: %w", n, ipv6RouterAlertPayloadLength, err) 377 } 378 } else if n != int(length) { 379 return nil, true, fmt.Errorf("got invalid length (%d) for router alert option (want = %d): %w", length, ipv6RouterAlertPayloadLength, ErrMalformedIPv6ExtHdrOption) 380 } 381 return &IPv6RouterAlertOption{Value: IPv6RouterAlertValue(binary.BigEndian.Uint16(routerAlertValue[:]))}, false, nil 382 default: 383 bytes := buffer.NewView(int(length)) 384 if n, err := io.CopyN(bytes, i.reader, int64(length)); err != nil { 385 if err == io.EOF { 386 err = io.ErrUnexpectedEOF 387 } 388 389 return nil, true, fmt.Errorf("read %d out of %d option data bytes for option with id = %d: %w", n, length, id, err) 390 } 391 return &IPv6UnknownExtHdrOption{Identifier: id, Data: bytes}, false, nil 392 } 393 } 394 } 395 396 // IPv6HopByHopOptionsExtHdr is a buffer holding the Hop By Hop Options 397 // extension header. 398 type IPv6HopByHopOptionsExtHdr struct { 399 ipv6OptionsExtHdr 400 } 401 402 // isIPv6PayloadHeader implements IPv6PayloadHeader.isIPv6PayloadHeader. 403 func (IPv6HopByHopOptionsExtHdr) isIPv6PayloadHeader() {} 404 405 // IPv6DestinationOptionsExtHdr is a buffer holding the Destination Options 406 // extension header. 407 type IPv6DestinationOptionsExtHdr struct { 408 ipv6OptionsExtHdr 409 } 410 411 // isIPv6PayloadHeader implements IPv6PayloadHeader.isIPv6PayloadHeader. 412 func (IPv6DestinationOptionsExtHdr) isIPv6PayloadHeader() {} 413 414 // IPv6RoutingExtHdr is a buffer holding the Routing extension header specific 415 // data as outlined in RFC 8200 section 4.4. 416 type IPv6RoutingExtHdr struct { 417 Buf *buffer.View 418 } 419 420 // isIPv6PayloadHeader implements IPv6PayloadHeader.isIPv6PayloadHeader. 421 func (IPv6RoutingExtHdr) isIPv6PayloadHeader() {} 422 423 // Release implements IPv6PayloadHeader.Release. 424 func (b IPv6RoutingExtHdr) Release() { 425 b.Buf.Release() 426 } 427 428 // SegmentsLeft returns the Segments Left field. 429 func (b IPv6RoutingExtHdr) SegmentsLeft() uint8 { 430 return b.Buf.AsSlice()[ipv6RoutingExtHdrSegmentsLeftIdx] 431 } 432 433 // IPv6FragmentExtHdr is a buffer holding the Fragment extension header specific 434 // data as outlined in RFC 8200 section 4.5. 435 // 436 // Note, the buffer does not include the Next Header and Reserved fields. 437 type IPv6FragmentExtHdr [6]byte 438 439 // isIPv6PayloadHeader implements IPv6PayloadHeader.isIPv6PayloadHeader. 440 func (IPv6FragmentExtHdr) isIPv6PayloadHeader() {} 441 442 // Release implements IPv6PayloadHeader.Release. 443 func (IPv6FragmentExtHdr) Release() {} 444 445 // FragmentOffset returns the Fragment Offset field. 446 // 447 // This value indicates where the buffer following the Fragment extension header 448 // starts in the target (reassembled) packet. 449 func (b IPv6FragmentExtHdr) FragmentOffset() uint16 { 450 return binary.BigEndian.Uint16(b[ipv6FragmentExtHdrFragmentOffsetOffset:]) >> ipv6FragmentExtHdrFragmentOffsetShift 451 } 452 453 // More returns the More (M) flag. 454 // 455 // This indicates whether any fragments are expected to succeed b. 456 func (b IPv6FragmentExtHdr) More() bool { 457 return b[ipv6FragmentExtHdrFlagsIdx]&ipv6FragmentExtHdrMFlagMask != 0 458 } 459 460 // ID returns the Identification field. 461 // 462 // This value is used to uniquely identify the packet, between a 463 // source and destination. 464 func (b IPv6FragmentExtHdr) ID() uint32 { 465 return binary.BigEndian.Uint32(b[ipv6FragmentExtHdrIdentificationOffset:]) 466 } 467 468 // IsAtomic returns whether the fragment header indicates an atomic fragment. An 469 // atomic fragment is a fragment that contains all the data required to 470 // reassemble a full packet. 471 func (b IPv6FragmentExtHdr) IsAtomic() bool { 472 return !b.More() && b.FragmentOffset() == 0 473 } 474 475 // IPv6PayloadIterator is an iterator over the contents of an IPv6 payload. 476 // 477 // The IPv6 payload may contain IPv6 extension headers before any upper layer 478 // data. 479 // 480 // Note, between when an IPv6PayloadIterator is obtained and last used, no 481 // changes to the payload may happen. Doing so may cause undefined and 482 // unexpected behaviour. It is fine to obtain an IPv6PayloadIterator, iterate 483 // over the first few headers then modify the backing payload so long as the 484 // IPv6PayloadIterator obtained before modification is no longer used. 485 type IPv6PayloadIterator struct { 486 // The identifier of the next header to parse. 487 nextHdrIdentifier IPv6ExtensionHeaderIdentifier 488 489 payload buffer.Buffer 490 491 // Indicates to the iterator that it should return the remaining payload as a 492 // raw payload on the next call to Next. 493 forceRaw bool 494 495 // headerOffset is the offset of the beginning of the current extension 496 // header starting from the beginning of the fixed header. 497 headerOffset uint32 498 499 // parseOffset is the byte offset into the current extension header of the 500 // field we are currently examining. It can be added to the header offset 501 // if the absolute offset within the packet is required. 502 parseOffset uint32 503 504 // nextOffset is the offset of the next header. 505 nextOffset uint32 506 } 507 508 // HeaderOffset returns the offset to the start of the extension 509 // header most recently processed. 510 func (i IPv6PayloadIterator) HeaderOffset() uint32 { 511 return i.headerOffset 512 } 513 514 // ParseOffset returns the number of bytes successfully parsed. 515 func (i IPv6PayloadIterator) ParseOffset() uint32 { 516 return i.headerOffset + i.parseOffset 517 } 518 519 // MakeIPv6PayloadIterator returns an iterator over the IPv6 payload containing 520 // extension headers, or a raw payload if the payload cannot be parsed. The 521 // iterator takes ownership of the payload. 522 func MakeIPv6PayloadIterator(nextHdrIdentifier IPv6ExtensionHeaderIdentifier, payload buffer.Buffer) IPv6PayloadIterator { 523 return IPv6PayloadIterator{ 524 nextHdrIdentifier: nextHdrIdentifier, 525 payload: payload, 526 nextOffset: IPv6FixedHeaderSize, 527 } 528 } 529 530 // Release frees the resources owned by the iterator. 531 func (i *IPv6PayloadIterator) Release() { 532 i.payload.Release() 533 } 534 535 // AsRawHeader returns the remaining payload of i as a raw header and 536 // optionally consumes the iterator. 537 // 538 // If consume is true, calls to Next after calling AsRawHeader on i will 539 // indicate that the iterator is done. The returned header takes ownership of 540 // its payload. 541 func (i *IPv6PayloadIterator) AsRawHeader(consume bool) IPv6RawPayloadHeader { 542 identifier := i.nextHdrIdentifier 543 544 var buf buffer.Buffer 545 if consume { 546 // Since we consume the iterator, we return the payload as is. 547 buf = i.payload 548 549 // Mark i as done, but keep track of where we were for error reporting. 550 *i = IPv6PayloadIterator{ 551 nextHdrIdentifier: IPv6NoNextHeaderIdentifier, 552 headerOffset: i.headerOffset, 553 nextOffset: i.nextOffset, 554 } 555 } else { 556 buf = i.payload.Clone() 557 } 558 559 return IPv6RawPayloadHeader{Identifier: identifier, Buf: buf} 560 } 561 562 // Next returns the next item in the payload. 563 // 564 // If the next item is not a known IPv6 extension header, IPv6RawPayloadHeader 565 // will be returned with the remaining bytes and next header identifier. 566 // 567 // The return is of the format (header, done, error). done will be true when 568 // Next is unable to return anything because the iterator has reached the end of 569 // the payload, or an error occurred. 570 func (i *IPv6PayloadIterator) Next() (IPv6PayloadHeader, bool, error) { 571 i.headerOffset = i.nextOffset 572 i.parseOffset = 0 573 // We could be forced to return i as a raw header when the previous header was 574 // a fragment extension header as the data following the fragment extension 575 // header may not be complete. 576 if i.forceRaw { 577 return i.AsRawHeader(true /* consume */), false, nil 578 } 579 580 // Is the header we are parsing a known extension header? 581 switch i.nextHdrIdentifier { 582 case IPv6HopByHopOptionsExtHdrIdentifier: 583 nextHdrIdentifier, view, err := i.nextHeaderData(false /* fragmentHdr */, nil) 584 if err != nil { 585 return nil, true, err 586 } 587 588 i.nextHdrIdentifier = nextHdrIdentifier 589 return IPv6HopByHopOptionsExtHdr{ipv6OptionsExtHdr{view}}, false, nil 590 case IPv6RoutingExtHdrIdentifier: 591 nextHdrIdentifier, view, err := i.nextHeaderData(false /* fragmentHdr */, nil) 592 if err != nil { 593 return nil, true, err 594 } 595 596 i.nextHdrIdentifier = nextHdrIdentifier 597 return IPv6RoutingExtHdr{view}, false, nil 598 case IPv6FragmentExtHdrIdentifier: 599 var data [6]byte 600 // We ignore the returned bytes because we know the fragment extension 601 // header specific data will fit in data. 602 nextHdrIdentifier, _, err := i.nextHeaderData(true /* fragmentHdr */, data[:]) 603 if err != nil { 604 return nil, true, err 605 } 606 607 fragmentExtHdr := IPv6FragmentExtHdr(data) 608 609 // If the packet is not the first fragment, do not attempt to parse anything 610 // after the fragment extension header as the payload following the fragment 611 // extension header should not contain any headers; the first fragment must 612 // hold all the headers up to and including any upper layer headers, as per 613 // RFC 8200 section 4.5. 614 if fragmentExtHdr.FragmentOffset() != 0 { 615 i.forceRaw = true 616 } 617 618 i.nextHdrIdentifier = nextHdrIdentifier 619 return fragmentExtHdr, false, nil 620 case IPv6DestinationOptionsExtHdrIdentifier: 621 nextHdrIdentifier, view, err := i.nextHeaderData(false /* fragmentHdr */, nil) 622 if err != nil { 623 return nil, true, err 624 } 625 626 i.nextHdrIdentifier = nextHdrIdentifier 627 return IPv6DestinationOptionsExtHdr{ipv6OptionsExtHdr{view}}, false, nil 628 case IPv6NoNextHeaderIdentifier: 629 // This indicates the end of the IPv6 payload. 630 return nil, true, nil 631 632 default: 633 // The header we are parsing is not a known extension header. Return the 634 // raw payload. 635 return i.AsRawHeader(true /* consume */), false, nil 636 } 637 } 638 639 // NextHeaderIdentifier returns the identifier of the header next returned by 640 // it.Next(). 641 func (i *IPv6PayloadIterator) NextHeaderIdentifier() IPv6ExtensionHeaderIdentifier { 642 return i.nextHdrIdentifier 643 } 644 645 // nextHeaderData returns the extension header's Next Header field and raw data. 646 // 647 // fragmentHdr indicates that the extension header being parsed is the Fragment 648 // extension header so the Length field should be ignored as it is Reserved 649 // for the Fragment extension header. 650 // 651 // If bytes is not nil, extension header specific data will be read into bytes 652 // if it has enough capacity. If bytes is provided but does not have enough 653 // capacity for the data, nextHeaderData will panic. 654 func (i *IPv6PayloadIterator) nextHeaderData(fragmentHdr bool, bytes []byte) (IPv6ExtensionHeaderIdentifier, *buffer.View, error) { 655 // We ignore the number of bytes read because we know we will only ever read 656 // at max 1 bytes since rune has a length of 1. If we read 0 bytes, the Read 657 // would return io.EOF to indicate that io.Reader has reached the end of the 658 // payload. 659 rdr := i.payload.AsBufferReader() 660 nextHdrIdentifier, err := rdr.ReadByte() 661 if err != nil { 662 return 0, nil, fmt.Errorf("error when reading the Next Header field for extension header with id = %d: %w", i.nextHdrIdentifier, err) 663 } 664 i.parseOffset++ 665 666 var length uint8 667 length, err = rdr.ReadByte() 668 669 if err != nil { 670 if fragmentHdr { 671 return 0, nil, fmt.Errorf("error when reading the Length field for extension header with id = %d: %w", i.nextHdrIdentifier, err) 672 } 673 674 return 0, nil, fmt.Errorf("error when reading the Reserved field for extension header with id = %d: %w", i.nextHdrIdentifier, err) 675 } 676 if fragmentHdr { 677 length = 0 678 } 679 680 // Make parseOffset point to the first byte of the Extension Header 681 // specific data. 682 i.parseOffset++ 683 684 // length is in 8 byte chunks but doesn't include the first one. 685 // See RFC 8200 for each header type, sections 4.3-4.6 and the requirement 686 // in section 4.8 for new extension headers at the top of page 24. 687 // [ Hdr Ext Len ] ... Length of the Destination Options header in 8-octet 688 // units, not including the first 8 octets. 689 i.nextOffset += uint32((length + 1) * ipv6ExtHdrLenBytesPerUnit) 690 691 bytesLen := int(length)*ipv6ExtHdrLenBytesPerUnit + ipv6ExtHdrLenBytesExcluded 692 if fragmentHdr { 693 if n := len(bytes); n < bytesLen { 694 panic(fmt.Sprintf("bytes only has space for %d bytes but need space for %d bytes (length = %d) for extension header with id = %d", n, bytesLen, length, i.nextHdrIdentifier)) 695 } 696 if n, err := io.ReadFull(&rdr, bytes); err != nil { 697 return 0, nil, fmt.Errorf("read %d out of %d extension header data bytes (length = %d) for header with id = %d: %w", n, bytesLen, length, i.nextHdrIdentifier, err) 698 } 699 return IPv6ExtensionHeaderIdentifier(nextHdrIdentifier), nil, nil 700 } 701 v := buffer.NewView(bytesLen) 702 if n, err := io.CopyN(v, &rdr, int64(bytesLen)); err != nil { 703 if err == io.EOF { 704 err = io.ErrUnexpectedEOF 705 } 706 v.Release() 707 return 0, nil, fmt.Errorf("read %d out of %d extension header data bytes (length = %d) for header with id = %d: %w", n, bytesLen, length, i.nextHdrIdentifier, err) 708 } 709 return IPv6ExtensionHeaderIdentifier(nextHdrIdentifier), v, nil 710 } 711 712 // IPv6SerializableExtHdr provides serialization for IPv6 extension 713 // headers. 714 type IPv6SerializableExtHdr interface { 715 // identifier returns the assigned IPv6 header identifier for this extension 716 // header. 717 identifier() IPv6ExtensionHeaderIdentifier 718 719 // length returns the total serialized length in bytes of this extension 720 // header, including the common next header and length fields. 721 length() int 722 723 // serializeInto serializes the receiver into the provided byte 724 // buffer and with the provided nextHeader value. 725 // 726 // Note, the caller MUST provide a byte buffer with size of at least 727 // length. Implementers of this function may assume that the byte buffer 728 // is of sufficient size. serializeInto MAY panic if the provided byte 729 // buffer is not of sufficient size. 730 // 731 // serializeInto returns the number of bytes that was used to serialize the 732 // receiver. Implementers must only use the number of bytes required to 733 // serialize the receiver. Callers MAY provide a larger buffer than required 734 // to serialize into. 735 serializeInto(nextHeader uint8, b []byte) int 736 } 737 738 var _ IPv6SerializableExtHdr = (*IPv6SerializableHopByHopExtHdr)(nil) 739 740 // IPv6SerializableHopByHopExtHdr implements serialization of the Hop by Hop 741 // options extension header. 742 type IPv6SerializableHopByHopExtHdr []IPv6SerializableHopByHopOption 743 744 const ( 745 // ipv6HopByHopExtHdrNextHeaderOffset is the offset of the next header field 746 // in a hop by hop extension header as defined in RFC 8200 section 4.3. 747 ipv6HopByHopExtHdrNextHeaderOffset = 0 748 749 // ipv6HopByHopExtHdrLengthOffset is the offset of the length field in a hop 750 // by hop extension header as defined in RFC 8200 section 4.3. 751 ipv6HopByHopExtHdrLengthOffset = 1 752 753 // ipv6HopByHopExtHdrPayloadOffset is the offset of the options in a hop by 754 // hop extension header as defined in RFC 8200 section 4.3. 755 ipv6HopByHopExtHdrOptionsOffset = 2 756 757 // ipv6HopByHopExtHdrUnaccountedLenWords is the implicit number of 8-octet 758 // words in a hop by hop extension header's length field, as stated in RFC 759 // 8200 section 4.3: 760 // Length of the Hop-by-Hop Options header in 8-octet units, 761 // not including the first 8 octets. 762 ipv6HopByHopExtHdrUnaccountedLenWords = 1 763 ) 764 765 // identifier implements IPv6SerializableExtHdr. 766 func (IPv6SerializableHopByHopExtHdr) identifier() IPv6ExtensionHeaderIdentifier { 767 return IPv6HopByHopOptionsExtHdrIdentifier 768 } 769 770 // length implements IPv6SerializableExtHdr. 771 func (h IPv6SerializableHopByHopExtHdr) length() int { 772 var total int 773 for _, opt := range h { 774 align, alignOffset := opt.alignment() 775 total += ipv6OptionsAlignmentPadding(total, align, alignOffset) 776 total += ipv6ExtHdrOptionPayloadOffset + int(opt.length()) 777 } 778 // Account for next header and total length fields and add padding. 779 return padIPv6OptionsLength(ipv6HopByHopExtHdrOptionsOffset + total) 780 } 781 782 // serializeInto implements IPv6SerializableExtHdr. 783 func (h IPv6SerializableHopByHopExtHdr) serializeInto(nextHeader uint8, b []byte) int { 784 optBuffer := b[ipv6HopByHopExtHdrOptionsOffset:] 785 totalLength := ipv6HopByHopExtHdrOptionsOffset 786 for _, opt := range h { 787 // Calculate alignment requirements and pad buffer if necessary. 788 align, alignOffset := opt.alignment() 789 padLen := ipv6OptionsAlignmentPadding(totalLength, align, alignOffset) 790 if padLen != 0 { 791 padIPv6Option(optBuffer[:padLen]) 792 totalLength += padLen 793 optBuffer = optBuffer[padLen:] 794 } 795 796 l := opt.serializeInto(optBuffer[ipv6ExtHdrOptionPayloadOffset:]) 797 optBuffer[ipv6ExtHdrOptionTypeOffset] = uint8(opt.identifier()) 798 optBuffer[ipv6ExtHdrOptionLengthOffset] = l 799 l += ipv6ExtHdrOptionPayloadOffset 800 totalLength += int(l) 801 optBuffer = optBuffer[l:] 802 } 803 padded := padIPv6OptionsLength(totalLength) 804 if padded != totalLength { 805 padIPv6Option(optBuffer[:padded-totalLength]) 806 totalLength = padded 807 } 808 wordsLen := totalLength/ipv6ExtHdrLenBytesPerUnit - ipv6HopByHopExtHdrUnaccountedLenWords 809 if wordsLen > math.MaxUint8 { 810 panic(fmt.Sprintf("IPv6 hop by hop options too large: %d+1 64-bit words", wordsLen)) 811 } 812 b[ipv6HopByHopExtHdrNextHeaderOffset] = nextHeader 813 b[ipv6HopByHopExtHdrLengthOffset] = uint8(wordsLen) 814 return totalLength 815 } 816 817 // IPv6SerializableHopByHopOption provides serialization for hop by hop options. 818 type IPv6SerializableHopByHopOption interface { 819 // identifier returns the option identifier of this Hop by Hop option. 820 identifier() IPv6ExtHdrOptionIdentifier 821 822 // length returns the *payload* size of the option (not considering the type 823 // and length fields). 824 length() uint8 825 826 // alignment returns the alignment requirements from this option. 827 // 828 // Alignment requirements take the form [align]n + offset as specified in 829 // RFC 8200 section 4.2. The alignment requirement is on the offset between 830 // the option type byte and the start of the hop by hop header. 831 // 832 // align must be a power of 2. 833 alignment() (align int, offset int) 834 835 // serializeInto serializes the receiver into the provided byte 836 // buffer. 837 // 838 // Note, the caller MUST provide a byte buffer with size of at least 839 // length. Implementers of this function may assume that the byte buffer 840 // is of sufficient size. serializeInto MAY panic if the provided byte 841 // buffer is not of sufficient size. 842 // 843 // serializeInto will return the number of bytes that was used to 844 // serialize the receiver. Implementers must only use the number of 845 // bytes required to serialize the receiver. Callers MAY provide a 846 // larger buffer than required to serialize into. 847 serializeInto([]byte) uint8 848 } 849 850 var _ IPv6SerializableHopByHopOption = (*IPv6RouterAlertOption)(nil) 851 852 // IPv6RouterAlertOption is the IPv6 Router alert Hop by Hop option defined in 853 // RFC 2711 section 2.1. 854 type IPv6RouterAlertOption struct { 855 Value IPv6RouterAlertValue 856 } 857 858 // IPv6RouterAlertValue is the payload of an IPv6 Router Alert option. 859 type IPv6RouterAlertValue uint16 860 861 const ( 862 // IPv6RouterAlertMLD indicates a datagram containing a Multicast Listener 863 // Discovery message as defined in RFC 2711 section 2.1. 864 IPv6RouterAlertMLD IPv6RouterAlertValue = 0 865 // IPv6RouterAlertRSVP indicates a datagram containing an RSVP message as 866 // defined in RFC 2711 section 2.1. 867 IPv6RouterAlertRSVP IPv6RouterAlertValue = 1 868 // IPv6RouterAlertActiveNetworks indicates a datagram containing an Active 869 // Networks message as defined in RFC 2711 section 2.1. 870 IPv6RouterAlertActiveNetworks IPv6RouterAlertValue = 2 871 872 // ipv6RouterAlertPayloadLength is the length of the Router Alert payload 873 // as defined in RFC 2711. 874 ipv6RouterAlertPayloadLength = 2 875 876 // ipv6RouterAlertAlignmentRequirement is the alignment requirement for the 877 // Router Alert option defined as 2n+0 in RFC 2711. 878 ipv6RouterAlertAlignmentRequirement = 2 879 880 // ipv6RouterAlertAlignmentOffsetRequirement is the alignment offset 881 // requirement for the Router Alert option defined as 2n+0 in RFC 2711 section 882 // 2.1. 883 ipv6RouterAlertAlignmentOffsetRequirement = 0 884 ) 885 886 // UnknownAction implements IPv6ExtHdrOption. 887 func (*IPv6RouterAlertOption) UnknownAction() IPv6OptionUnknownAction { 888 return ipv6UnknownActionFromIdentifier(ipv6RouterAlertHopByHopOptionIdentifier) 889 } 890 891 // isIPv6ExtHdrOption implements IPv6ExtHdrOption. 892 func (*IPv6RouterAlertOption) isIPv6ExtHdrOption() {} 893 894 // identifier implements IPv6SerializableHopByHopOption. 895 func (*IPv6RouterAlertOption) identifier() IPv6ExtHdrOptionIdentifier { 896 return ipv6RouterAlertHopByHopOptionIdentifier 897 } 898 899 // length implements IPv6SerializableHopByHopOption. 900 func (*IPv6RouterAlertOption) length() uint8 { 901 return ipv6RouterAlertPayloadLength 902 } 903 904 // alignment implements IPv6SerializableHopByHopOption. 905 func (*IPv6RouterAlertOption) alignment() (int, int) { 906 // From RFC 2711 section 2.1: 907 // Alignment requirement: 2n+0. 908 return ipv6RouterAlertAlignmentRequirement, ipv6RouterAlertAlignmentOffsetRequirement 909 } 910 911 // serializeInto implements IPv6SerializableHopByHopOption. 912 func (o *IPv6RouterAlertOption) serializeInto(b []byte) uint8 { 913 binary.BigEndian.PutUint16(b, uint16(o.Value)) 914 return ipv6RouterAlertPayloadLength 915 } 916 917 // IPv6ExtHdrSerializer provides serialization of IPv6 extension headers. 918 type IPv6ExtHdrSerializer []IPv6SerializableExtHdr 919 920 // Serialize serializes the provided list of IPv6 extension headers into b. 921 // 922 // Note, b must be of sufficient size to hold all the headers in s. See 923 // IPv6ExtHdrSerializer.Length for details on the getting the total size of a 924 // serialized IPv6ExtHdrSerializer. 925 // 926 // Serialize may panic if b is not of sufficient size to hold all the options 927 // in s. 928 // 929 // Serialize takes the transportProtocol value to be used as the last extension 930 // header's Next Header value and returns the header identifier of the first 931 // serialized extension header and the total serialized length. 932 func (s IPv6ExtHdrSerializer) Serialize(transportProtocol tcpip.TransportProtocolNumber, b []byte) (uint8, int) { 933 nextHeader := uint8(transportProtocol) 934 if len(s) == 0 { 935 return nextHeader, 0 936 } 937 var totalLength int 938 for i, h := range s[:len(s)-1] { 939 length := h.serializeInto(uint8(s[i+1].identifier()), b) 940 b = b[length:] 941 totalLength += length 942 } 943 totalLength += s[len(s)-1].serializeInto(nextHeader, b) 944 return uint8(s[0].identifier()), totalLength 945 } 946 947 // Length returns the total number of bytes required to serialize the extension 948 // headers. 949 func (s IPv6ExtHdrSerializer) Length() int { 950 var totalLength int 951 for _, h := range s { 952 totalLength += h.length() 953 } 954 return totalLength 955 }