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