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