gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/tcpip/header/ipv4.go (about)

     1  // Copyright 2021 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  	"fmt"
    20  	"time"
    21  
    22  	"gvisor.dev/gvisor/pkg/tcpip"
    23  	"gvisor.dev/gvisor/pkg/tcpip/checksum"
    24  )
    25  
    26  // RFC 971 defines the fields of the IPv4 header on page 11 using the following
    27  // diagram: ("Figure 4")
    28  //
    29  //	 0                   1                   2                   3
    30  //	 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    31  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    32  //	|Version|  IHL  |Type of Service|          Total Length         |
    33  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    34  //	|         Identification        |Flags|      Fragment Offset    |
    35  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    36  //	|  Time to Live |    Protocol   |         Header Checksum       |
    37  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    38  //	|                       Source Address                          |
    39  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    40  //	|                    Destination Address                        |
    41  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    42  //	|                    Options                    |    Padding    |
    43  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    44  const (
    45  	versIHL = 0
    46  	tos     = 1
    47  	// IPv4TotalLenOffset is the offset of the total length field in the
    48  	// IPv4 header.
    49  	IPv4TotalLenOffset = 2
    50  	id                 = 4
    51  	flagsFO            = 6
    52  	ttl                = 8
    53  	protocol           = 9
    54  	xsum               = 10
    55  	srcAddr            = 12
    56  	dstAddr            = 16
    57  	options            = 20
    58  )
    59  
    60  // IPv4Fields contains the fields of an IPv4 packet. It is used to describe the
    61  // fields of a packet that needs to be encoded. The IHL field is not here as
    62  // it is totally defined by the size of the options.
    63  type IPv4Fields struct {
    64  	// TOS is the "type of service" field of an IPv4 packet.
    65  	TOS uint8
    66  
    67  	// TotalLength is the "total length" field of an IPv4 packet.
    68  	TotalLength uint16
    69  
    70  	// ID is the "identification" field of an IPv4 packet.
    71  	ID uint16
    72  
    73  	// Flags is the "flags" field of an IPv4 packet.
    74  	Flags uint8
    75  
    76  	// FragmentOffset is the "fragment offset" field of an IPv4 packet.
    77  	FragmentOffset uint16
    78  
    79  	// TTL is the "time to live" field of an IPv4 packet.
    80  	TTL uint8
    81  
    82  	// Protocol is the "protocol" field of an IPv4 packet.
    83  	Protocol uint8
    84  
    85  	// Checksum is the "checksum" field of an IPv4 packet.
    86  	Checksum uint16
    87  
    88  	// SrcAddr is the "source ip address" of an IPv4 packet.
    89  	SrcAddr tcpip.Address
    90  
    91  	// DstAddr is the "destination ip address" of an IPv4 packet.
    92  	DstAddr tcpip.Address
    93  
    94  	// Options must be 40 bytes or less as they must fit along with the
    95  	// rest of the IPv4 header into the maximum size describable in the
    96  	// IHL field. RFC 791 section 3.1 says:
    97  	//    IHL:  4 bits
    98  	//
    99  	//    Internet Header Length is the length of the internet header in 32
   100  	//    bit words, and thus points to the beginning of the data.  Note that
   101  	//    the minimum value for a correct header is 5.
   102  	//
   103  	// That leaves ten 32 bit (4 byte) fields for options. An attempt to encode
   104  	// more will fail.
   105  	Options IPv4OptionsSerializer
   106  }
   107  
   108  // IPv4 is an IPv4 header.
   109  // Most of the methods of IPv4 access to the underlying slice without
   110  // checking the boundaries and could panic because of 'index out of range'.
   111  // Always call IsValid() to validate an instance of IPv4 before using other
   112  // methods.
   113  type IPv4 []byte
   114  
   115  const (
   116  	// IPv4MinimumSize is the minimum size of a valid IPv4 packet;
   117  	// i.e. a packet header with no options.
   118  	IPv4MinimumSize = 20
   119  
   120  	// IPv4MaximumHeaderSize is the maximum size of an IPv4 header. Given
   121  	// that there are only 4 bits (max 0xF (15)) to represent the header length
   122  	// in 32-bit (4 byte) units, the header cannot exceed 15*4 = 60 bytes.
   123  	IPv4MaximumHeaderSize = 60
   124  
   125  	// IPv4MaximumOptionsSize is the largest size the IPv4 options can be.
   126  	IPv4MaximumOptionsSize = IPv4MaximumHeaderSize - IPv4MinimumSize
   127  
   128  	// IPv4MaximumPayloadSize is the maximum size of a valid IPv4 payload.
   129  	//
   130  	// Linux limits this to 65,515 octets (the max IP datagram size - the IPv4
   131  	// header size). But RFC 791 section 3.2 discusses the design of the IPv4
   132  	// fragment "allows 2**13 = 8192 fragments of 8 octets each for a total of
   133  	// 65,536 octets. Note that this is consistent with the datagram total
   134  	// length field (of course, the header is counted in the total length and not
   135  	// in the fragments)."
   136  	IPv4MaximumPayloadSize = 65536
   137  
   138  	// MinIPFragmentPayloadSize is the minimum number of payload bytes that
   139  	// the first fragment must carry when an IPv4 packet is fragmented.
   140  	MinIPFragmentPayloadSize = 8
   141  
   142  	// IPv4AddressSize is the size, in bytes, of an IPv4 address.
   143  	IPv4AddressSize = 4
   144  
   145  	// IPv4AddressSizeBits is the size, in bits, of an IPv4 address.
   146  	IPv4AddressSizeBits = 32
   147  
   148  	// IPv4ProtocolNumber is IPv4's network protocol number.
   149  	IPv4ProtocolNumber tcpip.NetworkProtocolNumber = 0x0800
   150  
   151  	// IPv4Version is the version of the IPv4 protocol.
   152  	IPv4Version = 4
   153  
   154  	// IPv4MinimumProcessableDatagramSize is the minimum size of an IP
   155  	// packet that every IPv4 capable host must be able to
   156  	// process/reassemble.
   157  	IPv4MinimumProcessableDatagramSize = 576
   158  
   159  	// IPv4MinimumMTU is the minimum MTU required by IPv4, per RFC 791,
   160  	// section 3.2:
   161  	//   Every internet module must be able to forward a datagram of 68 octets
   162  	//   without further fragmentation.  This is because an internet header may be
   163  	//   up to 60 octets, and the minimum fragment is 8 octets.
   164  	IPv4MinimumMTU = 68
   165  )
   166  
   167  var (
   168  	// IPv4AllSystems is the all systems IPv4 multicast address as per
   169  	// IANA's IPv4 Multicast Address Space Registry. See
   170  	// https://www.iana.org/assignments/multicast-addresses/multicast-addresses.xhtml.
   171  	IPv4AllSystems = tcpip.AddrFrom4([4]byte{0xe0, 0x00, 0x00, 0x01})
   172  
   173  	// IPv4Broadcast is the broadcast address of the IPv4 procotol.
   174  	IPv4Broadcast = tcpip.AddrFrom4([4]byte{0xff, 0xff, 0xff, 0xff})
   175  
   176  	// IPv4Any is the non-routable IPv4 "any" meta address.
   177  	IPv4Any = tcpip.AddrFrom4([4]byte{0x00, 0x00, 0x00, 0x00})
   178  
   179  	// IPv4AllRoutersGroup is a multicast address for all routers.
   180  	IPv4AllRoutersGroup = tcpip.AddrFrom4([4]byte{0xe0, 0x00, 0x00, 0x02})
   181  )
   182  
   183  // Flags that may be set in an IPv4 packet.
   184  const (
   185  	IPv4FlagMoreFragments = 1 << iota
   186  	IPv4FlagDontFragment
   187  )
   188  
   189  // ipv4LinkLocalUnicastSubnet is the IPv4 link local unicast subnet as defined
   190  // by RFC 3927 section 1.
   191  var ipv4LinkLocalUnicastSubnet = func() tcpip.Subnet {
   192  	subnet, err := tcpip.NewSubnet(tcpip.AddrFrom4([4]byte{0xa9, 0xfe, 0x00, 0x00}), tcpip.MaskFrom("\xff\xff\x00\x00"))
   193  	if err != nil {
   194  		panic(err)
   195  	}
   196  	return subnet
   197  }()
   198  
   199  // ipv4LinkLocalMulticastSubnet is the IPv4 link local multicast subnet as
   200  // defined by RFC 5771 section 4.
   201  var ipv4LinkLocalMulticastSubnet = func() tcpip.Subnet {
   202  	subnet, err := tcpip.NewSubnet(tcpip.AddrFrom4([4]byte{0xe0, 0x00, 0x00, 0x00}), tcpip.MaskFrom("\xff\xff\xff\x00"))
   203  	if err != nil {
   204  		panic(err)
   205  	}
   206  	return subnet
   207  }()
   208  
   209  // IPv4EmptySubnet is the empty IPv4 subnet.
   210  var IPv4EmptySubnet = func() tcpip.Subnet {
   211  	subnet, err := tcpip.NewSubnet(IPv4Any, tcpip.MaskFrom("\x00\x00\x00\x00"))
   212  	if err != nil {
   213  		panic(err)
   214  	}
   215  	return subnet
   216  }()
   217  
   218  // IPv4CurrentNetworkSubnet is the subnet of addresses for the current network,
   219  // per RFC 6890 section 2.2.2,
   220  //
   221  //	+----------------------+----------------------------+
   222  //	| Attribute            | Value                      |
   223  //	+----------------------+----------------------------+
   224  //	| Address Block        | 0.0.0.0/8                  |
   225  //	| Name                 | "This host on this network"|
   226  //	| RFC                  | [RFC1122], Section 3.2.1.3 |
   227  //	| Allocation Date      | September 1981             |
   228  //	| Termination Date     | N/A                        |
   229  //	| Source               | True                       |
   230  //	| Destination          | False                      |
   231  //	| Forwardable          | False                      |
   232  //	| Global               | False                      |
   233  //	| Reserved-by-Protocol | True                       |
   234  //	+----------------------+----------------------------+
   235  var IPv4CurrentNetworkSubnet = func() tcpip.Subnet {
   236  	subnet, err := tcpip.NewSubnet(IPv4Any, tcpip.MaskFrom("\xff\x00\x00\x00"))
   237  	if err != nil {
   238  		panic(err)
   239  	}
   240  	return subnet
   241  }()
   242  
   243  // IPv4LoopbackSubnet is the loopback subnet for IPv4.
   244  var IPv4LoopbackSubnet = func() tcpip.Subnet {
   245  	subnet, err := tcpip.NewSubnet(tcpip.AddrFrom4([4]byte{0x7f, 0x00, 0x00, 0x00}), tcpip.MaskFrom("\xff\x00\x00\x00"))
   246  	if err != nil {
   247  		panic(err)
   248  	}
   249  	return subnet
   250  }()
   251  
   252  // IPVersion returns the version of IP used in the given packet. It returns -1
   253  // if the packet is not large enough to contain the version field.
   254  func IPVersion(b []byte) int {
   255  	// Length must be at least offset+length of version field.
   256  	if len(b) < versIHL+1 {
   257  		return -1
   258  	}
   259  	return int(b[versIHL] >> ipVersionShift)
   260  }
   261  
   262  // RFC 791 page 11 shows the header length (IHL) is in the lower 4 bits
   263  // of the first byte, and is counted in multiples of 4 bytes.
   264  //
   265  //	 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   266  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   267  //	|Version|  IHL  |Type of Service|          Total Length         |
   268  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   269  //	  (...)
   270  //	 Version:  4 bits
   271  //	   The Version field indicates the format of the internet header.  This
   272  //	   document describes version 4.
   273  //
   274  //	 IHL:  4 bits
   275  //	   Internet Header Length is the length of the internet header in 32
   276  //	   bit words, and thus points to the beginning of the data.  Note that
   277  //	   the minimum value for a correct header is 5.
   278  const (
   279  	ipVersionShift = 4
   280  	ipIHLMask      = 0x0f
   281  	IPv4IHLStride  = 4
   282  )
   283  
   284  // HeaderLength returns the value of the "header length" field of the IPv4
   285  // header. The length returned is in bytes.
   286  func (b IPv4) HeaderLength() uint8 {
   287  	return (b[versIHL] & ipIHLMask) * IPv4IHLStride
   288  }
   289  
   290  // SetHeaderLength sets the value of the "Internet Header Length" field.
   291  func (b IPv4) SetHeaderLength(hdrLen uint8) {
   292  	if hdrLen > IPv4MaximumHeaderSize {
   293  		panic(fmt.Sprintf("got IPv4 Header size = %d, want <= %d", hdrLen, IPv4MaximumHeaderSize))
   294  	}
   295  	b[versIHL] = (IPv4Version << ipVersionShift) | ((hdrLen / IPv4IHLStride) & ipIHLMask)
   296  }
   297  
   298  // ID returns the value of the identifier field of the IPv4 header.
   299  func (b IPv4) ID() uint16 {
   300  	return binary.BigEndian.Uint16(b[id:])
   301  }
   302  
   303  // Protocol returns the value of the protocol field of the IPv4 header.
   304  func (b IPv4) Protocol() uint8 {
   305  	return b[protocol]
   306  }
   307  
   308  // Flags returns the "flags" field of the IPv4 header.
   309  func (b IPv4) Flags() uint8 {
   310  	return uint8(binary.BigEndian.Uint16(b[flagsFO:]) >> 13)
   311  }
   312  
   313  // More returns whether the more fragments flag is set.
   314  func (b IPv4) More() bool {
   315  	return b.Flags()&IPv4FlagMoreFragments != 0
   316  }
   317  
   318  // TTL returns the "TTL" field of the IPv4 header.
   319  func (b IPv4) TTL() uint8 {
   320  	return b[ttl]
   321  }
   322  
   323  // FragmentOffset returns the "fragment offset" field of the IPv4 header.
   324  func (b IPv4) FragmentOffset() uint16 {
   325  	return binary.BigEndian.Uint16(b[flagsFO:]) << 3
   326  }
   327  
   328  // TotalLength returns the "total length" field of the IPv4 header.
   329  func (b IPv4) TotalLength() uint16 {
   330  	return binary.BigEndian.Uint16(b[IPv4TotalLenOffset:])
   331  }
   332  
   333  // Checksum returns the checksum field of the IPv4 header.
   334  func (b IPv4) Checksum() uint16 {
   335  	return binary.BigEndian.Uint16(b[xsum:])
   336  }
   337  
   338  // SourceAddress returns the "source address" field of the IPv4 header.
   339  func (b IPv4) SourceAddress() tcpip.Address {
   340  	return tcpip.AddrFrom4([4]byte(b[srcAddr : srcAddr+IPv4AddressSize]))
   341  }
   342  
   343  // DestinationAddress returns the "destination address" field of the IPv4
   344  // header.
   345  func (b IPv4) DestinationAddress() tcpip.Address {
   346  	return tcpip.AddrFrom4([4]byte(b[dstAddr : dstAddr+IPv4AddressSize]))
   347  }
   348  
   349  // SourceAddressSlice returns the "source address" field of the IPv4 header as a
   350  // byte slice.
   351  func (b IPv4) SourceAddressSlice() []byte {
   352  	return []byte(b[srcAddr : srcAddr+IPv4AddressSize])
   353  }
   354  
   355  // DestinationAddressSlice returns the "destination address" field of the IPv4
   356  // header as a byte slice.
   357  func (b IPv4) DestinationAddressSlice() []byte {
   358  	return []byte(b[dstAddr : dstAddr+IPv4AddressSize])
   359  }
   360  
   361  // SetSourceAddressWithChecksumUpdate implements ChecksummableNetwork.
   362  func (b IPv4) SetSourceAddressWithChecksumUpdate(new tcpip.Address) {
   363  	b.SetChecksum(^checksumUpdate2ByteAlignedAddress(^b.Checksum(), b.SourceAddress(), new))
   364  	b.SetSourceAddress(new)
   365  }
   366  
   367  // SetDestinationAddressWithChecksumUpdate implements ChecksummableNetwork.
   368  func (b IPv4) SetDestinationAddressWithChecksumUpdate(new tcpip.Address) {
   369  	b.SetChecksum(^checksumUpdate2ByteAlignedAddress(^b.Checksum(), b.DestinationAddress(), new))
   370  	b.SetDestinationAddress(new)
   371  }
   372  
   373  // padIPv4OptionsLength returns the total length for IPv4 options of length l
   374  // after applying padding according to RFC 791:
   375  //
   376  //	The internet header padding is used to ensure that the internet
   377  //	header ends on a 32 bit boundary.
   378  func padIPv4OptionsLength(length uint8) uint8 {
   379  	return (length + IPv4IHLStride - 1) & ^uint8(IPv4IHLStride-1)
   380  }
   381  
   382  // IPv4Options is a buffer that holds all the raw IP options.
   383  type IPv4Options []byte
   384  
   385  // Options returns a buffer holding the options.
   386  func (b IPv4) Options() IPv4Options {
   387  	hdrLen := b.HeaderLength()
   388  	return IPv4Options(b[options:hdrLen:hdrLen])
   389  }
   390  
   391  // TransportProtocol implements Network.TransportProtocol.
   392  func (b IPv4) TransportProtocol() tcpip.TransportProtocolNumber {
   393  	return tcpip.TransportProtocolNumber(b.Protocol())
   394  }
   395  
   396  // Payload implements Network.Payload.
   397  func (b IPv4) Payload() []byte {
   398  	return b[b.HeaderLength():][:b.PayloadLength()]
   399  }
   400  
   401  // PayloadLength returns the length of the payload portion of the IPv4 packet.
   402  func (b IPv4) PayloadLength() uint16 {
   403  	return b.TotalLength() - uint16(b.HeaderLength())
   404  }
   405  
   406  // TOS returns the "type of service" field of the IPv4 header.
   407  func (b IPv4) TOS() (uint8, uint32) {
   408  	return b[tos], 0
   409  }
   410  
   411  // SetTOS sets the "type of service" field of the IPv4 header.
   412  func (b IPv4) SetTOS(v uint8, _ uint32) {
   413  	b[tos] = v
   414  }
   415  
   416  // SetTTL sets the "Time to Live" field of the IPv4 header.
   417  func (b IPv4) SetTTL(v byte) {
   418  	b[ttl] = v
   419  }
   420  
   421  // SetTotalLength sets the "total length" field of the IPv4 header.
   422  func (b IPv4) SetTotalLength(totalLength uint16) {
   423  	binary.BigEndian.PutUint16(b[IPv4TotalLenOffset:], totalLength)
   424  }
   425  
   426  // SetChecksum sets the checksum field of the IPv4 header.
   427  func (b IPv4) SetChecksum(v uint16) {
   428  	checksum.Put(b[xsum:], v)
   429  }
   430  
   431  // SetFlagsFragmentOffset sets the "flags" and "fragment offset" fields of the
   432  // IPv4 header.
   433  func (b IPv4) SetFlagsFragmentOffset(flags uint8, offset uint16) {
   434  	v := (uint16(flags) << 13) | (offset >> 3)
   435  	binary.BigEndian.PutUint16(b[flagsFO:], v)
   436  }
   437  
   438  // SetID sets the identification field.
   439  func (b IPv4) SetID(v uint16) {
   440  	binary.BigEndian.PutUint16(b[id:], v)
   441  }
   442  
   443  // SetSourceAddress sets the "source address" field of the IPv4 header.
   444  func (b IPv4) SetSourceAddress(addr tcpip.Address) {
   445  	copy(b[srcAddr:srcAddr+IPv4AddressSize], addr.AsSlice())
   446  }
   447  
   448  // SetDestinationAddress sets the "destination address" field of the IPv4
   449  // header.
   450  func (b IPv4) SetDestinationAddress(addr tcpip.Address) {
   451  	copy(b[dstAddr:dstAddr+IPv4AddressSize], addr.AsSlice())
   452  }
   453  
   454  // CalculateChecksum calculates the checksum of the IPv4 header.
   455  func (b IPv4) CalculateChecksum() uint16 {
   456  	return checksum.Checksum(b[:b.HeaderLength()], 0)
   457  }
   458  
   459  // Encode encodes all the fields of the IPv4 header.
   460  func (b IPv4) Encode(i *IPv4Fields) {
   461  	// The size of the options defines the size of the whole header and thus the
   462  	// IHL field. Options are rare and this is a heavily used function so it is
   463  	// worth a bit of optimisation here to keep the serializer out of the fast
   464  	// path.
   465  	hdrLen := uint8(IPv4MinimumSize)
   466  	if len(i.Options) != 0 {
   467  		hdrLen += i.Options.Serialize(b[options:])
   468  	}
   469  	if hdrLen > IPv4MaximumHeaderSize {
   470  		panic(fmt.Sprintf("%d is larger than maximum IPv4 header size of %d", hdrLen, IPv4MaximumHeaderSize))
   471  	}
   472  	b.SetHeaderLength(hdrLen)
   473  	b[tos] = i.TOS
   474  	b.SetTotalLength(i.TotalLength)
   475  	binary.BigEndian.PutUint16(b[id:], i.ID)
   476  	b.SetFlagsFragmentOffset(i.Flags, i.FragmentOffset)
   477  	b[ttl] = i.TTL
   478  	b[protocol] = i.Protocol
   479  	b.SetChecksum(i.Checksum)
   480  	copy(b[srcAddr:srcAddr+IPv4AddressSize], i.SrcAddr.AsSlice())
   481  	copy(b[dstAddr:dstAddr+IPv4AddressSize], i.DstAddr.AsSlice())
   482  }
   483  
   484  // EncodePartial updates the total length and checksum fields of IPv4 header,
   485  // taking in the partial checksum, which is the checksum of the header without
   486  // the total length and checksum fields. It is useful in cases when similar
   487  // packets are produced.
   488  func (b IPv4) EncodePartial(partialChecksum, totalLength uint16) {
   489  	b.SetTotalLength(totalLength)
   490  	xsum := checksum.Checksum(b[IPv4TotalLenOffset:IPv4TotalLenOffset+2], partialChecksum)
   491  	b.SetChecksum(^xsum)
   492  }
   493  
   494  // IsValid performs basic validation on the packet.
   495  func (b IPv4) IsValid(pktSize int) bool {
   496  	if len(b) < IPv4MinimumSize {
   497  		return false
   498  	}
   499  
   500  	hlen := int(b.HeaderLength())
   501  	tlen := int(b.TotalLength())
   502  	if hlen < IPv4MinimumSize || hlen > tlen || tlen > pktSize {
   503  		return false
   504  	}
   505  
   506  	if IPVersion(b) != IPv4Version {
   507  		return false
   508  	}
   509  
   510  	return true
   511  }
   512  
   513  // IsV4LinkLocalUnicastAddress determines if the provided address is an IPv4
   514  // link-local unicast address.
   515  func IsV4LinkLocalUnicastAddress(addr tcpip.Address) bool {
   516  	return ipv4LinkLocalUnicastSubnet.Contains(addr)
   517  }
   518  
   519  // IsV4LinkLocalMulticastAddress determines if the provided address is an IPv4
   520  // link-local multicast address.
   521  func IsV4LinkLocalMulticastAddress(addr tcpip.Address) bool {
   522  	return ipv4LinkLocalMulticastSubnet.Contains(addr)
   523  }
   524  
   525  // IsChecksumValid returns true iff the IPv4 header's checksum is valid.
   526  func (b IPv4) IsChecksumValid() bool {
   527  	// There has been some confusion regarding verifying checksums. We need
   528  	// just look for negative 0 (0xffff) as the checksum, as it's not possible to
   529  	// get positive 0 (0) for the checksum. Some bad implementations could get it
   530  	// when doing entry replacement in the early days of the Internet,
   531  	// however the lore that one needs to check for both persists.
   532  	//
   533  	// RFC 1624 section 1 describes the source of this confusion as:
   534  	//     [the partial recalculation method described in RFC 1071] computes a
   535  	//     result for certain cases that differs from the one obtained from
   536  	//     scratch (one's complement of one's complement sum of the original
   537  	//     fields).
   538  	//
   539  	// However RFC 1624 section 5 clarifies that if using the verification method
   540  	// "recommended by RFC 1071, it does not matter if an intermediate system
   541  	// generated a -0 instead of +0".
   542  	//
   543  	// RFC1071 page 1 specifies the verification method as:
   544  	//	  (3)  To check a checksum, the 1's complement sum is computed over the
   545  	//        same set of octets, including the checksum field.  If the result
   546  	//        is all 1 bits (-0 in 1's complement arithmetic), the check
   547  	//        succeeds.
   548  	return b.CalculateChecksum() == 0xffff
   549  }
   550  
   551  // IsV4MulticastAddress determines if the provided address is an IPv4 multicast
   552  // address (range 224.0.0.0 to 239.255.255.255). The four most significant bits
   553  // will be 1110 = 0xe0.
   554  func IsV4MulticastAddress(addr tcpip.Address) bool {
   555  	if addr.BitLen() != IPv4AddressSizeBits {
   556  		return false
   557  	}
   558  	addrBytes := addr.As4()
   559  	return (addrBytes[0] & 0xf0) == 0xe0
   560  }
   561  
   562  // IsV4LoopbackAddress determines if the provided address is an IPv4 loopback
   563  // address (belongs to 127.0.0.0/8 subnet). See RFC 1122 section 3.2.1.3.
   564  func IsV4LoopbackAddress(addr tcpip.Address) bool {
   565  	if addr.BitLen() != IPv4AddressSizeBits {
   566  		return false
   567  	}
   568  	addrBytes := addr.As4()
   569  	return addrBytes[0] == 0x7f
   570  }
   571  
   572  // ========================= Options ==========================
   573  
   574  // An IPv4OptionType can hold the value for the Type in an IPv4 option.
   575  type IPv4OptionType byte
   576  
   577  // These constants are needed to identify individual options in the option list.
   578  // While RFC 791 (page 31) says "Every internet module must be able to act on
   579  // every option." This has not generally been adhered to and some options have
   580  // very low rates of support. We do not support options other than those shown
   581  // below.
   582  
   583  const (
   584  	// IPv4OptionListEndType is the option type for the End Of Option List
   585  	// option. Anything following is ignored.
   586  	IPv4OptionListEndType IPv4OptionType = 0
   587  
   588  	// IPv4OptionNOPType is the No-Operation option. May appear between other
   589  	// options and may appear multiple times.
   590  	IPv4OptionNOPType IPv4OptionType = 1
   591  
   592  	// IPv4OptionRouterAlertType is the option type for the Router Alert option,
   593  	// defined in RFC 2113 Section 2.1.
   594  	IPv4OptionRouterAlertType IPv4OptionType = 20 | 0x80
   595  
   596  	// IPv4OptionRecordRouteType is used by each router on the path of the packet
   597  	// to record its path. It is carried over to an Echo Reply.
   598  	IPv4OptionRecordRouteType IPv4OptionType = 7
   599  
   600  	// IPv4OptionTimestampType is the option type for the Timestamp option.
   601  	IPv4OptionTimestampType IPv4OptionType = 68
   602  
   603  	// ipv4OptionTypeOffset is the offset in an option of its type field.
   604  	ipv4OptionTypeOffset = 0
   605  
   606  	// IPv4OptionLengthOffset is the offset in an option of its length field.
   607  	IPv4OptionLengthOffset = 1
   608  )
   609  
   610  // IPv4OptParameterProblem indicates that a Parameter Problem message
   611  // should be generated, and gives the offset in the current entity
   612  // that should be used in that packet.
   613  type IPv4OptParameterProblem struct {
   614  	Pointer  uint8
   615  	NeedICMP bool
   616  }
   617  
   618  // IPv4Option is an interface representing various option types.
   619  type IPv4Option interface {
   620  	// Type returns the type identifier of the option.
   621  	Type() IPv4OptionType
   622  
   623  	// Size returns the size of the option in bytes.
   624  	Size() uint8
   625  
   626  	// Contents returns a slice holding the contents of the option.
   627  	Contents() []byte
   628  }
   629  
   630  var _ IPv4Option = (*IPv4OptionGeneric)(nil)
   631  
   632  // IPv4OptionGeneric is an IPv4 Option of unknown type.
   633  type IPv4OptionGeneric []byte
   634  
   635  // Type implements IPv4Option.
   636  func (o *IPv4OptionGeneric) Type() IPv4OptionType {
   637  	return IPv4OptionType((*o)[ipv4OptionTypeOffset])
   638  }
   639  
   640  // Size implements IPv4Option.
   641  func (o *IPv4OptionGeneric) Size() uint8 { return uint8(len(*o)) }
   642  
   643  // Contents implements IPv4Option.
   644  func (o *IPv4OptionGeneric) Contents() []byte { return *o }
   645  
   646  // IPv4OptionIterator is an iterator pointing to a specific IP option
   647  // at any point of time. It also holds information as to a new options buffer
   648  // that we are building up to hand back to the caller.
   649  // TODO(https://gvisor.dev/issues/5513): Add unit tests for IPv4OptionIterator.
   650  type IPv4OptionIterator struct {
   651  	options IPv4Options
   652  	// ErrCursor is where we are while parsing options. It is exported as any
   653  	// resulting ICMP packet is supposed to have a pointer to the byte within
   654  	// the IP packet where the error was detected.
   655  	ErrCursor     uint8
   656  	nextErrCursor uint8
   657  	newOptions    [IPv4MaximumOptionsSize]byte
   658  	writePoint    int
   659  }
   660  
   661  // MakeIterator sets up and returns an iterator of options. It also sets up the
   662  // building of a new option set.
   663  func (o IPv4Options) MakeIterator() IPv4OptionIterator {
   664  	return IPv4OptionIterator{
   665  		options:       o,
   666  		nextErrCursor: IPv4MinimumSize,
   667  	}
   668  }
   669  
   670  // InitReplacement copies the option into the new option buffer.
   671  func (i *IPv4OptionIterator) InitReplacement(option IPv4Option) IPv4Options {
   672  	replacementOption := i.RemainingBuffer()[:option.Size()]
   673  	if copied := copy(replacementOption, option.Contents()); copied != len(replacementOption) {
   674  		panic(fmt.Sprintf("copied %d bytes in the replacement option buffer, expected %d bytes", copied, len(replacementOption)))
   675  	}
   676  	return replacementOption
   677  }
   678  
   679  // RemainingBuffer returns the remaining (unused) part of the new option buffer,
   680  // into which a new option may be written.
   681  func (i *IPv4OptionIterator) RemainingBuffer() IPv4Options {
   682  	return i.newOptions[i.writePoint:]
   683  }
   684  
   685  // ConsumeBuffer marks a portion of the new buffer as used.
   686  func (i *IPv4OptionIterator) ConsumeBuffer(size int) {
   687  	i.writePoint += size
   688  }
   689  
   690  // PushNOPOrEnd puts one of the single byte options onto the new options.
   691  // Only values 0 or 1 (ListEnd or NOP) are valid input.
   692  func (i *IPv4OptionIterator) PushNOPOrEnd(val IPv4OptionType) {
   693  	if val > IPv4OptionNOPType {
   694  		panic(fmt.Sprintf("invalid option type %d pushed onto option build buffer", val))
   695  	}
   696  	i.newOptions[i.writePoint] = byte(val)
   697  	i.writePoint++
   698  }
   699  
   700  // Finalize returns the completed replacement options buffer padded
   701  // as needed.
   702  func (i *IPv4OptionIterator) Finalize() IPv4Options {
   703  	// RFC 791 page 31 says:
   704  	//     The options might not end on a 32-bit boundary.  The internet header
   705  	//     must be filled out with octets of zeros.  The first of these would
   706  	//     be interpreted as the end-of-options option, and the remainder as
   707  	//     internet header padding.
   708  	// Since the buffer is already zero filled we just need to step the write
   709  	// pointer up to the next multiple of 4.
   710  	options := IPv4Options(i.newOptions[:(i.writePoint+0x3) & ^0x3])
   711  	// Poison the write pointer.
   712  	i.writePoint = len(i.newOptions)
   713  	return options
   714  }
   715  
   716  // Next returns the next IP option in the buffer/list of IP options.
   717  // It returns
   718  //   - A slice of bytes holding the next option or nil if there is error.
   719  //   - A boolean which is true if parsing of all the options is complete.
   720  //     Undefined in the case of error.
   721  //   - An error indication which is non-nil if an error condition was found.
   722  func (i *IPv4OptionIterator) Next() (IPv4Option, bool, *IPv4OptParameterProblem) {
   723  	// The opts slice gets shorter as we process the options. When we have no
   724  	// bytes left we are done.
   725  	if len(i.options) == 0 {
   726  		return nil, true, nil
   727  	}
   728  
   729  	i.ErrCursor = i.nextErrCursor
   730  
   731  	optType := IPv4OptionType(i.options[ipv4OptionTypeOffset])
   732  
   733  	if optType == IPv4OptionNOPType || optType == IPv4OptionListEndType {
   734  		optionBody := i.options[:1]
   735  		i.options = i.options[1:]
   736  		i.nextErrCursor = i.ErrCursor + 1
   737  		retval := IPv4OptionGeneric(optionBody)
   738  		return &retval, false, nil
   739  	}
   740  
   741  	// There are no more single byte options defined.  All the rest have a length
   742  	// field so we need to sanity check it.
   743  	if len(i.options) == 1 {
   744  		return nil, false, &IPv4OptParameterProblem{
   745  			Pointer:  i.ErrCursor,
   746  			NeedICMP: true,
   747  		}
   748  	}
   749  
   750  	optLen := i.options[IPv4OptionLengthOffset]
   751  
   752  	if optLen <= IPv4OptionLengthOffset || optLen > uint8(len(i.options)) {
   753  		// The actual error is in the length (2nd byte of the option) but we
   754  		// return the start of the option for compatibility with Linux.
   755  
   756  		return nil, false, &IPv4OptParameterProblem{
   757  			Pointer:  i.ErrCursor,
   758  			NeedICMP: true,
   759  		}
   760  	}
   761  
   762  	optionBody := i.options[:optLen]
   763  	i.nextErrCursor = i.ErrCursor + optLen
   764  	i.options = i.options[optLen:]
   765  
   766  	// Check the length of some option types that we know.
   767  	switch optType {
   768  	case IPv4OptionTimestampType:
   769  		if optLen < IPv4OptionTimestampHdrLength {
   770  			i.ErrCursor++
   771  			return nil, false, &IPv4OptParameterProblem{
   772  				Pointer:  i.ErrCursor,
   773  				NeedICMP: true,
   774  			}
   775  		}
   776  		retval := IPv4OptionTimestamp(optionBody)
   777  		return &retval, false, nil
   778  
   779  	case IPv4OptionRecordRouteType:
   780  		if optLen < IPv4OptionRecordRouteHdrLength {
   781  			i.ErrCursor++
   782  			return nil, false, &IPv4OptParameterProblem{
   783  				Pointer:  i.ErrCursor,
   784  				NeedICMP: true,
   785  			}
   786  		}
   787  		retval := IPv4OptionRecordRoute(optionBody)
   788  		return &retval, false, nil
   789  
   790  	case IPv4OptionRouterAlertType:
   791  		if optLen != IPv4OptionRouterAlertLength {
   792  			i.ErrCursor++
   793  			return nil, false, &IPv4OptParameterProblem{
   794  				Pointer:  i.ErrCursor,
   795  				NeedICMP: true,
   796  			}
   797  		}
   798  		retval := IPv4OptionRouterAlert(optionBody)
   799  		return &retval, false, nil
   800  	}
   801  	retval := IPv4OptionGeneric(optionBody)
   802  	return &retval, false, nil
   803  }
   804  
   805  //
   806  // IP Timestamp option - RFC 791 page 22.
   807  // +--------+--------+--------+--------+
   808  // |01000100| length | pointer|oflw|flg|
   809  // +--------+--------+--------+--------+
   810  // |         internet address          |
   811  // +--------+--------+--------+--------+
   812  // |             timestamp             |
   813  // +--------+--------+--------+--------+
   814  // |                ...                |
   815  //
   816  // Type = 68
   817  //
   818  // The Option Length is the number of octets in the option counting
   819  // the type, length, pointer, and overflow/flag octets (maximum
   820  // length 40).
   821  //
   822  // The Pointer is the number of octets from the beginning of this
   823  // option to the end of timestamps plus one (i.e., it points to the
   824  // octet beginning the space for next timestamp).  The smallest
   825  // legal value is 5.  The timestamp area is full when the pointer
   826  // is greater than the length.
   827  //
   828  // The Overflow (oflw) [4 bits] is the number of IP modules that
   829  // cannot register timestamps due to lack of space.
   830  //
   831  // The Flag (flg) [4 bits] values are
   832  //
   833  //   0 -- time stamps only, stored in consecutive 32-bit words,
   834  //
   835  //   1 -- each timestamp is preceded with internet address of the
   836  //        registering entity,
   837  //
   838  //   3 -- the internet address fields are prespecified.  An IP
   839  //        module only registers its timestamp if it matches its own
   840  //        address with the next specified internet address.
   841  //
   842  // Timestamps are defined in RFC 791 page 22 as milliseconds since midnight UTC.
   843  //
   844  //        The Timestamp is a right-justified, 32-bit timestamp in
   845  //        milliseconds since midnight UT.  If the time is not available in
   846  //        milliseconds or cannot be provided with respect to midnight UT
   847  //        then any time may be inserted as a timestamp provided the high
   848  //        order bit of the timestamp field is set to one to indicate the
   849  //        use of a non-standard value.
   850  
   851  // IPv4OptTSFlags sefines the values expected in the Timestamp
   852  // option Flags field.
   853  type IPv4OptTSFlags uint8
   854  
   855  // Timestamp option specific related constants.
   856  const (
   857  	// IPv4OptionTimestampHdrLength is the length of the timestamp option header.
   858  	IPv4OptionTimestampHdrLength = 4
   859  
   860  	// IPv4OptionTimestampSize is the size of an IP timestamp.
   861  	IPv4OptionTimestampSize = 4
   862  
   863  	// IPv4OptionTimestampWithAddrSize is the size of an IP timestamp + Address.
   864  	IPv4OptionTimestampWithAddrSize = IPv4AddressSize + IPv4OptionTimestampSize
   865  
   866  	// IPv4OptionTimestampMaxSize is limited by space for options
   867  	IPv4OptionTimestampMaxSize = IPv4MaximumOptionsSize
   868  
   869  	// IPv4OptionTimestampOnlyFlag is a flag indicating that only timestamp
   870  	// is present.
   871  	IPv4OptionTimestampOnlyFlag IPv4OptTSFlags = 0
   872  
   873  	// IPv4OptionTimestampWithIPFlag is a flag indicating that both timestamps and
   874  	// IP are present.
   875  	IPv4OptionTimestampWithIPFlag IPv4OptTSFlags = 1
   876  
   877  	// IPv4OptionTimestampWithPredefinedIPFlag is a flag indicating that
   878  	// predefined IP is present.
   879  	IPv4OptionTimestampWithPredefinedIPFlag IPv4OptTSFlags = 3
   880  )
   881  
   882  // ipv4TimestampTime provides the current time as specified in RFC 791.
   883  func ipv4TimestampTime(clock tcpip.Clock) uint32 {
   884  	// Per RFC 791 page 21:
   885  	//   The Timestamp is a right-justified, 32-bit timestamp in
   886  	//   milliseconds since midnight UT.
   887  	now := clock.Now().UTC()
   888  	midnight := now.Truncate(24 * time.Hour)
   889  	return uint32(now.Sub(midnight).Milliseconds())
   890  }
   891  
   892  // IP Timestamp option fields.
   893  const (
   894  	// IPv4OptTSPointerOffset is the offset of the Timestamp pointer field.
   895  	IPv4OptTSPointerOffset = 2
   896  
   897  	// IPv4OptTSPointerOffset is the offset of the combined Flag and Overflow
   898  	// fields, (each being 4 bits).
   899  	IPv4OptTSOFLWAndFLGOffset = 3
   900  	// These constants define the sub byte fields of the Flag and OverFlow field.
   901  	ipv4OptionTimestampOverflowshift      = 4
   902  	ipv4OptionTimestampFlagsMask     byte = 0x0f
   903  )
   904  
   905  var _ IPv4Option = (*IPv4OptionTimestamp)(nil)
   906  
   907  // IPv4OptionTimestamp is a Timestamp option from RFC 791.
   908  type IPv4OptionTimestamp []byte
   909  
   910  // Type implements IPv4Option.Type().
   911  func (ts *IPv4OptionTimestamp) Type() IPv4OptionType { return IPv4OptionTimestampType }
   912  
   913  // Size implements IPv4Option.
   914  func (ts *IPv4OptionTimestamp) Size() uint8 { return uint8(len(*ts)) }
   915  
   916  // Contents implements IPv4Option.
   917  func (ts *IPv4OptionTimestamp) Contents() []byte { return *ts }
   918  
   919  // Pointer returns the pointer field in the IP Timestamp option.
   920  func (ts *IPv4OptionTimestamp) Pointer() uint8 {
   921  	return (*ts)[IPv4OptTSPointerOffset]
   922  }
   923  
   924  // Flags returns the flags field in the IP Timestamp option.
   925  func (ts *IPv4OptionTimestamp) Flags() IPv4OptTSFlags {
   926  	return IPv4OptTSFlags((*ts)[IPv4OptTSOFLWAndFLGOffset] & ipv4OptionTimestampFlagsMask)
   927  }
   928  
   929  // Overflow returns the Overflow field in the IP Timestamp option.
   930  func (ts *IPv4OptionTimestamp) Overflow() uint8 {
   931  	return (*ts)[IPv4OptTSOFLWAndFLGOffset] >> ipv4OptionTimestampOverflowshift
   932  }
   933  
   934  // IncOverflow increments the Overflow field in the IP Timestamp option. It
   935  // returns the incremented value. If the return value is 0 then the field
   936  // overflowed.
   937  func (ts *IPv4OptionTimestamp) IncOverflow() uint8 {
   938  	(*ts)[IPv4OptTSOFLWAndFLGOffset] += 1 << ipv4OptionTimestampOverflowshift
   939  	return ts.Overflow()
   940  }
   941  
   942  // UpdateTimestamp updates the fields of the next free timestamp slot.
   943  func (ts *IPv4OptionTimestamp) UpdateTimestamp(addr tcpip.Address, clock tcpip.Clock) {
   944  	slot := (*ts)[ts.Pointer()-1:]
   945  
   946  	switch ts.Flags() {
   947  	case IPv4OptionTimestampOnlyFlag:
   948  		binary.BigEndian.PutUint32(slot, ipv4TimestampTime(clock))
   949  		(*ts)[IPv4OptTSPointerOffset] += IPv4OptionTimestampSize
   950  	case IPv4OptionTimestampWithIPFlag:
   951  		if n := copy(slot, addr.AsSlice()); n != IPv4AddressSize {
   952  			panic(fmt.Sprintf("copied %d bytes, expected %d bytes", n, IPv4AddressSize))
   953  		}
   954  		binary.BigEndian.PutUint32(slot[IPv4AddressSize:], ipv4TimestampTime(clock))
   955  		(*ts)[IPv4OptTSPointerOffset] += IPv4OptionTimestampWithAddrSize
   956  	case IPv4OptionTimestampWithPredefinedIPFlag:
   957  		if tcpip.AddrFrom4([4]byte(slot[:IPv4AddressSize])) == addr {
   958  			binary.BigEndian.PutUint32(slot[IPv4AddressSize:], ipv4TimestampTime(clock))
   959  			(*ts)[IPv4OptTSPointerOffset] += IPv4OptionTimestampWithAddrSize
   960  		}
   961  	}
   962  }
   963  
   964  // RecordRoute option specific related constants.
   965  //
   966  // from RFC 791 page 20:
   967  //
   968  //	Record Route
   969  //
   970  //	      +--------+--------+--------+---------//--------+
   971  //	      |00000111| length | pointer|     route data    |
   972  //	      +--------+--------+--------+---------//--------+
   973  //	        Type=7
   974  //
   975  //	      The record route option provides a means to record the route of
   976  //	      an internet datagram.
   977  //
   978  //	      The option begins with the option type code.  The second octet
   979  //	      is the option length which includes the option type code and the
   980  //	      length octet, the pointer octet, and length-3 octets of route
   981  //	      data.  The third octet is the pointer into the route data
   982  //	      indicating the octet which begins the next area to store a route
   983  //	      address.  The pointer is relative to this option, and the
   984  //	      smallest legal value for the pointer is 4.
   985  const (
   986  	// IPv4OptionRecordRouteHdrLength is the length of the Record Route option
   987  	// header.
   988  	IPv4OptionRecordRouteHdrLength = 3
   989  
   990  	// IPv4OptRRPointerOffset is the offset to the pointer field in an RR
   991  	// option, which points to the next free slot in the list of addresses.
   992  	IPv4OptRRPointerOffset = 2
   993  )
   994  
   995  var _ IPv4Option = (*IPv4OptionRecordRoute)(nil)
   996  
   997  // IPv4OptionRecordRoute is an IPv4 RecordRoute option defined by RFC 791.
   998  type IPv4OptionRecordRoute []byte
   999  
  1000  // Pointer returns the pointer field in the IP RecordRoute option.
  1001  func (rr *IPv4OptionRecordRoute) Pointer() uint8 {
  1002  	return (*rr)[IPv4OptRRPointerOffset]
  1003  }
  1004  
  1005  // StoreAddress stores the given IPv4 address into the next free slot.
  1006  func (rr *IPv4OptionRecordRoute) StoreAddress(addr tcpip.Address) {
  1007  	start := rr.Pointer() - 1 // A one based number.
  1008  	// start and room checked by caller.
  1009  	if n := copy((*rr)[start:], addr.AsSlice()); n != IPv4AddressSize {
  1010  		panic(fmt.Sprintf("copied %d bytes, expected %d bytes", n, IPv4AddressSize))
  1011  	}
  1012  	(*rr)[IPv4OptRRPointerOffset] += IPv4AddressSize
  1013  }
  1014  
  1015  // Type implements IPv4Option.
  1016  func (rr *IPv4OptionRecordRoute) Type() IPv4OptionType { return IPv4OptionRecordRouteType }
  1017  
  1018  // Size implements IPv4Option.
  1019  func (rr *IPv4OptionRecordRoute) Size() uint8 { return uint8(len(*rr)) }
  1020  
  1021  // Contents implements IPv4Option.
  1022  func (rr *IPv4OptionRecordRoute) Contents() []byte { return *rr }
  1023  
  1024  // Router Alert option specific related constants.
  1025  //
  1026  // from RFC 2113 section 2.1:
  1027  //
  1028  //	+--------+--------+--------+--------+
  1029  //	|10010100|00000100|  2 octet value  |
  1030  //	+--------+--------+--------+--------+
  1031  //
  1032  //	Type:
  1033  //	Copied flag:  1 (all fragments must carry the option)
  1034  //	Option class: 0 (control)
  1035  //	Option number: 20 (decimal)
  1036  //
  1037  //	Length: 4
  1038  //
  1039  //	Value:  A two octet code with the following values:
  1040  //	0 - Router shall examine packet
  1041  //	1-65535 - Reserved
  1042  const (
  1043  	// IPv4OptionRouterAlertLength is the length of a Router Alert option.
  1044  	IPv4OptionRouterAlertLength = 4
  1045  
  1046  	// IPv4OptionRouterAlertValue is the only permissible value of the 16 bit
  1047  	// payload of the router alert option.
  1048  	IPv4OptionRouterAlertValue = 0
  1049  
  1050  	// IPv4OptionRouterAlertValueOffset is the offset for the value of a
  1051  	// RouterAlert option.
  1052  	IPv4OptionRouterAlertValueOffset = 2
  1053  )
  1054  
  1055  var _ IPv4Option = (*IPv4OptionRouterAlert)(nil)
  1056  
  1057  // IPv4OptionRouterAlert is an IPv4 RouterAlert option defined by RFC 2113.
  1058  type IPv4OptionRouterAlert []byte
  1059  
  1060  // Type implements IPv4Option.
  1061  func (*IPv4OptionRouterAlert) Type() IPv4OptionType { return IPv4OptionRouterAlertType }
  1062  
  1063  // Size implements IPv4Option.
  1064  func (ra *IPv4OptionRouterAlert) Size() uint8 { return uint8(len(*ra)) }
  1065  
  1066  // Contents implements IPv4Option.
  1067  func (ra *IPv4OptionRouterAlert) Contents() []byte { return *ra }
  1068  
  1069  // Value returns the value of the IPv4OptionRouterAlert.
  1070  func (ra *IPv4OptionRouterAlert) Value() uint16 {
  1071  	return binary.BigEndian.Uint16(ra.Contents()[IPv4OptionRouterAlertValueOffset:])
  1072  }
  1073  
  1074  // IPv4SerializableOption is an interface to represent serializable IPv4 option
  1075  // types.
  1076  type IPv4SerializableOption interface {
  1077  	// optionType returns the type identifier of the option.
  1078  	optionType() IPv4OptionType
  1079  }
  1080  
  1081  // IPv4SerializableOptionPayload is an interface providing serialization of the
  1082  // payload of an IPv4 option.
  1083  type IPv4SerializableOptionPayload interface {
  1084  	// length returns the size of the payload.
  1085  	length() uint8
  1086  
  1087  	// serializeInto serializes the payload into the provided byte buffer.
  1088  	//
  1089  	// Note, the caller MUST provide a byte buffer with size of at least
  1090  	// Length. Implementers of this function may assume that the byte buffer
  1091  	// is of sufficient size. serializeInto MUST panic if the provided byte
  1092  	// buffer is not of sufficient size.
  1093  	//
  1094  	// serializeInto will return the number of bytes that was used to
  1095  	// serialize the receiver. Implementers must only use the number of
  1096  	// bytes required to serialize the receiver. Callers MAY provide a
  1097  	// larger buffer than required to serialize into.
  1098  	serializeInto(buffer []byte) uint8
  1099  }
  1100  
  1101  // IPv4OptionsSerializer is a serializer for IPv4 options.
  1102  type IPv4OptionsSerializer []IPv4SerializableOption
  1103  
  1104  // Length returns the total number of bytes required to serialize the options.
  1105  func (s IPv4OptionsSerializer) Length() uint8 {
  1106  	var total uint8
  1107  	for _, opt := range s {
  1108  		total++
  1109  		if withPayload, ok := opt.(IPv4SerializableOptionPayload); ok {
  1110  			// Add 1 to reported length to account for the length byte.
  1111  			total += 1 + withPayload.length()
  1112  		}
  1113  	}
  1114  	return padIPv4OptionsLength(total)
  1115  }
  1116  
  1117  // Serialize serializes the provided list of IPV4 options into b.
  1118  //
  1119  // Note, b must be of sufficient size to hold all the options in s. See
  1120  // IPv4OptionsSerializer.Length for details on the getting the total size
  1121  // of a serialized IPv4OptionsSerializer.
  1122  //
  1123  // Serialize panics if b is not of sufficient size to hold all the options in s.
  1124  func (s IPv4OptionsSerializer) Serialize(b []byte) uint8 {
  1125  	var total uint8
  1126  	for _, opt := range s {
  1127  		ty := opt.optionType()
  1128  		if withPayload, ok := opt.(IPv4SerializableOptionPayload); ok {
  1129  			// Serialize first to reduce bounds checks.
  1130  			l := 2 + withPayload.serializeInto(b[2:])
  1131  			b[0] = byte(ty)
  1132  			b[1] = l
  1133  			b = b[l:]
  1134  			total += l
  1135  			continue
  1136  		}
  1137  		// Options without payload consist only of the type field.
  1138  		//
  1139  		// NB: Repeating code from the branch above is intentional to minimize
  1140  		// bounds checks.
  1141  		b[0] = byte(ty)
  1142  		b = b[1:]
  1143  		total++
  1144  	}
  1145  
  1146  	// According to RFC 791:
  1147  	//
  1148  	//  The internet header padding is used to ensure that the internet
  1149  	//  header ends on a 32 bit boundary. The padding is zero.
  1150  	padded := padIPv4OptionsLength(total)
  1151  	b = b[:padded-total]
  1152  	clear(b)
  1153  	return padded
  1154  }
  1155  
  1156  var _ IPv4SerializableOptionPayload = (*IPv4SerializableRouterAlertOption)(nil)
  1157  var _ IPv4SerializableOption = (*IPv4SerializableRouterAlertOption)(nil)
  1158  
  1159  // IPv4SerializableRouterAlertOption provides serialization of the Router Alert
  1160  // IPv4 option according to RFC 2113.
  1161  type IPv4SerializableRouterAlertOption struct{}
  1162  
  1163  // Type implements IPv4SerializableOption.
  1164  func (*IPv4SerializableRouterAlertOption) optionType() IPv4OptionType {
  1165  	return IPv4OptionRouterAlertType
  1166  }
  1167  
  1168  // Length implements IPv4SerializableOption.
  1169  func (*IPv4SerializableRouterAlertOption) length() uint8 {
  1170  	return IPv4OptionRouterAlertLength - IPv4OptionRouterAlertValueOffset
  1171  }
  1172  
  1173  // SerializeInto implements IPv4SerializableOption.
  1174  func (o *IPv4SerializableRouterAlertOption) serializeInto(buffer []byte) uint8 {
  1175  	binary.BigEndian.PutUint16(buffer, IPv4OptionRouterAlertValue)
  1176  	return o.length()
  1177  }
  1178  
  1179  var _ IPv4SerializableOption = (*IPv4SerializableNOPOption)(nil)
  1180  
  1181  // IPv4SerializableNOPOption provides serialization for the IPv4 no-op option.
  1182  type IPv4SerializableNOPOption struct{}
  1183  
  1184  // Type implements IPv4SerializableOption.
  1185  func (*IPv4SerializableNOPOption) optionType() IPv4OptionType {
  1186  	return IPv4OptionNOPType
  1187  }
  1188  
  1189  var _ IPv4SerializableOption = (*IPv4SerializableListEndOption)(nil)
  1190  
  1191  // IPv4SerializableListEndOption provides serialization for the IPv4 List End
  1192  // option.
  1193  type IPv4SerializableListEndOption struct{}
  1194  
  1195  // Type implements IPv4SerializableOption.
  1196  func (*IPv4SerializableListEndOption) optionType() IPv4OptionType {
  1197  	return IPv4OptionListEndType
  1198  }