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