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