github.com/nicocha30/gvisor-ligolo@v0.0.0-20230726075806-989fa2c0a413/pkg/tcpip/header/ipv6_extension_headers.go (about)

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