github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/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  	"bufio"
    19  	"bytes"
    20  	"encoding/binary"
    21  	"errors"
    22  	"fmt"
    23  	"io"
    24  	"math"
    25  
    26  	"github.com/SagerNet/gvisor/pkg/tcpip"
    27  	"github.com/SagerNet/gvisor/pkg/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  }