Coverage Report

Created: 2025-07-11 07:47

/src/PcapPlusPlus/Packet++/header/IPv4Layer.h
Line
Count
Source (jump to first uncovered line)
1
#pragma once
2
3
#include "Layer.h"
4
#include "TLVData.h"
5
#include "IpAddress.h"
6
#include "IPLayer.h"
7
#include <string.h>
8
#include <vector>
9
10
/// @file
11
12
/// @namespace pcpp
13
/// @brief The main namespace for the PcapPlusPlus lib
14
namespace pcpp
15
{
16
  /// @struct iphdr
17
  /// Represents an IPv4 protocol header
18
#pragma pack(push, 1)
19
  struct iphdr
20
  {
21
#if (BYTE_ORDER == LITTLE_ENDIAN)
22
    /// IP header length, has the value of 5 for IPv4
23
    uint8_t internetHeaderLength : 4,
24
        /// IP version number, has the value of 4 for IPv4
25
        ipVersion : 4;
26
#else
27
    /// IP version number, has the value of 4 for IPv4
28
    uint8_t ipVersion : 4,
29
        /// IP header length, has the value of 5 for IPv4
30
        internetHeaderLength : 4;
31
#endif
32
    /// type of service, same as Differentiated Services Code Point (DSCP)
33
    uint8_t typeOfService;
34
    /// Entire packet (fragment) size, including header and data, in bytes
35
    uint16_t totalLength;
36
    /// Identification field. Primarily used for uniquely identifying the group of fragments of a single IP
37
    /// datagram
38
    uint16_t ipId;
39
    /// Fragment offset field, measured in units of eight-byte blocks (64 bits)
40
    uint16_t fragmentOffset;
41
    /// An eight-bit time to live field helps prevent datagrams from persisting (e.g. going in circles) on an
42
    /// internet.  In practice, the field has become a hop count
43
    uint8_t timeToLive;
44
    /// Defines the protocol used in the data portion of the IP datagram. Must be one of ::IPProtocolTypes
45
    uint8_t protocol;
46
    /// Error-checking of the header
47
    uint16_t headerChecksum;
48
    /// IPv4 address of the sender of the packet
49
    uint32_t ipSrc;
50
    /// IPv4 address of the receiver of the packet
51
    uint32_t ipDst;
52
    // The options start here.
53
  };
54
#pragma pack(pop)
55
  static_assert(sizeof(iphdr) == 20, "iphdr size is not 20 bytes");
56
57
  /// An enum for all possible IPv4 and IPv6 protocol types
58
  enum IPProtocolTypes
59
  {
60
    /// Dummy protocol for TCP
61
    PACKETPP_IPPROTO_IP = 0,
62
    /// IPv6 Hop-by-Hop options
63
    PACKETPP_IPPROTO_HOPOPTS = 0,
64
    /// Internet Control Message Protocol
65
    PACKETPP_IPPROTO_ICMP = 1,
66
    /// Internet Gateway Management Protocol
67
    PACKETPP_IPPROTO_IGMP = 2,
68
    /// IPIP tunnels (older KA9Q tunnels use 94)
69
    PACKETPP_IPPROTO_IPIP = 4,
70
    /// Transmission Control Protocol
71
    PACKETPP_IPPROTO_TCP = 6,
72
    /// Exterior Gateway Protocol
73
    PACKETPP_IPPROTO_EGP = 8,
74
    /// PUP protocol
75
    PACKETPP_IPPROTO_PUP = 12,
76
    /// User Datagram Protocol
77
    PACKETPP_IPPROTO_UDP = 17,
78
    /// XNS IDP protocol
79
    PACKETPP_IPPROTO_IDP = 22,
80
    /// IPv6 header
81
    PACKETPP_IPPROTO_IPV6 = 41,
82
    /// IPv6 Routing header
83
    PACKETPP_IPPROTO_ROUTING = 43,
84
    /// IPv6 fragmentation header
85
    PACKETPP_IPPROTO_FRAGMENT = 44,
86
    /// GRE protocol
87
    PACKETPP_IPPROTO_GRE = 47,
88
    /// encapsulating security payload
89
    PACKETPP_IPPROTO_ESP = 50,
90
    /// authentication header
91
    PACKETPP_IPPROTO_AH = 51,
92
    /// ICMPv6
93
    PACKETPP_IPPROTO_ICMPV6 = 58,
94
    /// IPv6 no next header
95
    PACKETPP_IPPROTO_NONE = 59,
96
    /// IPv6 Destination options
97
    PACKETPP_IPPROTO_DSTOPTS = 60,
98
    /// VRRP protocol
99
    PACKETPP_IPPROTO_VRRP = 112,
100
    /// Raw IP packets
101
    PACKETPP_IPPROTO_RAW = 255,
102
    /// Maximum value
103
    PACKETPP_IPPROTO_MAX
104
  };
105
106
  /// An enum for supported IPv4 option types
107
  enum IPv4OptionTypes
108
  {
109
    /// End of Options List
110
    IPV4OPT_EndOfOptionsList = 0,
111
    /// No Operation
112
    IPV4OPT_NOP = 1,
113
    /// Record Route
114
    IPV4OPT_RecordRoute = 7,
115
    /// MTU Probe
116
    IPV4OPT_MTUProbe = 11,
117
    /// MTU Reply
118
    IPV4OPT_MTUReply = 12,
119
    /// Quick-Start
120
    IPV4OPT_QuickStart = 25,
121
    /// Timestamp
122
    IPV4OPT_Timestamp = 68,
123
    /// Traceroute
124
    IPV4OPT_Traceroute = 82,
125
    /// Security
126
    IPV4OPT_Security = 130,
127
    /// Loose Source Route
128
    IPV4OPT_LooseSourceRoute = 131,
129
    /// Extended Security
130
    IPV4OPT_ExtendedSecurity = 133,
131
    /// Commercial Security
132
    IPV4OPT_CommercialSecurity = 134,
133
    /// Stream ID
134
    IPV4OPT_StreamID = 136,
135
    /// Strict Source Route
136
    IPV4OPT_StrictSourceRoute = 137,
137
    /// Extended Internet Protocol
138
    IPV4OPT_ExtendedInternetProtocol = 145,
139
    /// Address Extension
140
    IPV4OPT_AddressExtension = 147,
141
    /// Router Alert
142
    IPV4OPT_RouterAlert = 148,
143
    /// Selective Directed Broadcast
144
    IPV4OPT_SelectiveDirectedBroadcast = 149,
145
    /// Dynamic Packet State
146
    IPV4OPT_DynamicPacketState = 151,
147
    /// Upstream Multicast Pkt.
148
    IPV4OPT_UpstreamMulticastPkt = 152,
149
    /// Unknown IPv4 option
150
    IPV4OPT_Unknown
151
  };
152
153
#define PCPP_IP_DONT_FRAGMENT 0x40
154
417k
#define PCPP_IP_MORE_FRAGMENTS 0x20
155
156
  /// @struct IPv4TimestampOptionValue
157
  /// A struct representing a parsed value of the IPv4 timestamp option. This struct is used returned in
158
  /// IPv4OptionData#getTimestampOptionValue() method
159
  struct IPv4TimestampOptionValue
160
  {
161
    /// An enum for IPv4 timestamp option types
162
    enum TimestampType
163
    {
164
      /// Value containing only timestamps
165
      TimestampOnly = 0,
166
      /// Value containing both timestamps and IPv4 addresses
167
      TimestampAndIP = 1,
168
      /// The IPv4 addresses are prespecified
169
      TimestampsForPrespecifiedIPs = 2,
170
      /// Invalid or unknown value type
171
      Unknown = 3
172
    };
173
174
    /// The timestamp value type
175
    TimestampType type;
176
177
    /// A list of timestamps parsed from the IPv4 timestamp option value
178
    std::vector<uint32_t> timestamps;
179
180
    /// A list of IPv4 addresses parsed from the IPv4 timestamp option value
181
    std::vector<IPv4Address> ipAddresses;
182
183
    /// The default constructor
184
    IPv4TimestampOptionValue() : type(IPv4TimestampOptionValue::Unknown)
185
0
    {}
186
187
    /// Clear the structure. Clean the timestamps and IP addresses vectors and set the type as
188
    /// IPv4TimestampOptionValue#Unknown
189
    void clear()
190
0
    {
191
0
      type = IPv4TimestampOptionValue::Unknown;
192
0
      timestamps.clear();
193
0
      ipAddresses.clear();
194
0
    }
195
  };
196
197
  /// @class IPv4Option
198
  /// A wrapper class for IPv4 options. This class does not create or modify IPv4 option records, but rather
199
  /// serves as a wrapper and provides useful methods for retrieving data from them
200
  class IPv4Option : public TLVRecord<uint8_t, uint8_t>
201
  {
202
  public:
203
    /// A c'tor for this class that gets a pointer to the option raw data (byte array)
204
    /// @param[in] optionRawData A pointer to the IPv4 option raw data
205
    explicit IPv4Option(uint8_t* optionRawData) : TLVRecord(optionRawData)
206
0
    {}
207
208
    /// A d'tor for this class, currently does nothing
209
    ~IPv4Option() override = default;
210
211
    /// A method for parsing the IPv4 option value as a list of IPv4 addresses. This method is relevant only for
212
    /// certain types of IPv4 options which their value is a list of IPv4 addresses such as ::IPV4OPT_RecordRoute,
213
    /// ::IPV4OPT_StrictSourceRoute, ::IPV4OPT_LooseSourceRoute, etc. This method returns a vector of the IPv4
214
    /// addresses. Blank IP addresses (meaning zeroed addresses - 0.0.0.0) will not be added to the returned list.
215
    /// If some error occurs during the parsing or the value is invalid an empty vector is returned
216
    /// @return A vector of IPv4 addresses parsed from the IPv4 option value
217
    std::vector<IPv4Address> getValueAsIpList() const
218
0
    {
219
0
      std::vector<IPv4Address> res;
220
0
221
0
      if (m_Data == nullptr)
222
0
        return res;
223
0
224
0
      size_t dataSize = getDataSize();
225
0
      if (dataSize < 2)
226
0
        return res;
227
0
228
0
      uint8_t valueOffset = static_cast<uint8_t>(1);
229
0
230
0
      while (static_cast<size_t>(valueOffset) < dataSize)
231
0
      {
232
0
        uint32_t curValue;
233
0
        memcpy(&curValue, m_Data->recordValue + valueOffset, sizeof(uint32_t));
234
0
        if (curValue == 0)
235
0
          break;
236
0
237
0
        res.push_back(IPv4Address(curValue));
238
0
239
0
        valueOffset += static_cast<uint8_t>(4);
240
0
      }
241
0
242
0
      return res;
243
0
    }
244
245
    /// A method for parsing the IPv4 timestamp option value. This method is relevant only for IPv4 timestamp
246
    /// option. For other option types an empty result will be returned. The returned structure contains the
247
    /// timestamp value type (timestamp only, timestamp + IP addresses, etc.) as well as 2 vectors containing the
248
    /// list of timestamps and the list of IP addresses (if applicable for the timestamp value type). Blank
249
    /// timestamps or IP addresses (meaning zeroed values - timestamp=0 or IP address=0.0.0.0) will not be added to
250
    /// the lists. If some error occurs during the parsing or the value is invalid an empty result is returned
251
    /// @return A structured containing the IPv4 timestamp value
252
    IPv4TimestampOptionValue getTimestampOptionValue() const
253
0
    {
254
0
      IPv4TimestampOptionValue res;
255
0
      res.clear();
256
0
257
0
      if (m_Data == nullptr)
258
0
        return res;
259
0
260
0
      if (getIPv4OptionType() != IPV4OPT_Timestamp)
261
0
        return res;
262
0
263
0
      size_t dataSize = getDataSize();
264
0
      if (dataSize < 2)
265
0
        return res;
266
0
267
0
      res.type = static_cast<IPv4TimestampOptionValue::TimestampType>(m_Data->recordValue[1]);
268
0
269
0
      uint8_t valueOffset = static_cast<uint8_t>(2);
270
0
      bool readIPAddr = (res.type == IPv4TimestampOptionValue::TimestampAndIP);
271
0
272
0
      while (static_cast<size_t>(valueOffset) < dataSize)
273
0
      {
274
0
        uint32_t curValue;
275
0
        memcpy(&curValue, m_Data->recordValue + valueOffset, sizeof(uint32_t));
276
0
        if (curValue == 0)
277
0
          break;
278
0
279
0
        if (readIPAddr)
280
0
          res.ipAddresses.push_back(IPv4Address(curValue));
281
0
        else
282
0
          res.timestamps.push_back(curValue);
283
0
284
0
        if (res.type == IPv4TimestampOptionValue::TimestampAndIP)
285
0
          readIPAddr = !readIPAddr;
286
0
287
0
        valueOffset += static_cast<uint8_t>(4);
288
0
      }
289
0
290
0
      return res;
291
0
    }
292
293
    /// @return IPv4 option type casted as pcpp::IPv4OptionTypes enum
294
    IPv4OptionTypes getIPv4OptionType() const
295
0
    {
296
0
      return getIPv4OptionType(m_Data);
297
0
    }
298
299
    /// Check if a pointer can be assigned to the TLV record data
300
    /// @param[in] recordRawData A pointer to the TLV record raw data
301
    /// @param[in] tlvDataLen The size of the TLV record raw data
302
    /// @return True if data is valid and can be assigned
303
    static bool canAssign(const uint8_t* recordRawData, size_t tlvDataLen)
304
0
    {
305
0
      auto data = reinterpret_cast<TLVRawData const*>(recordRawData);
306
0
      if (data == nullptr)
307
0
        return false;
308
0
309
0
      if (tlvDataLen < sizeof(TLVRawData::recordType))
310
0
        return false;
311
0
312
0
      if (getIPv4OptionType(data) == static_cast<uint8_t>(IPV4OPT_EndOfOptionsList) ||
313
0
          data->recordType == static_cast<uint8_t>(IPV4OPT_NOP))
314
0
        return true;
315
0
316
0
      return TLVRecord<uint8_t, uint8_t>::canAssign(recordRawData, tlvDataLen);
317
0
    }
318
319
    // implement abstract methods
320
321
    size_t getTotalSize() const override
322
0
    {
323
0
      if (m_Data == nullptr)
324
0
        return 0;
325
0
326
0
      if (getIPv4OptionType() == static_cast<uint8_t>(IPV4OPT_EndOfOptionsList) ||
327
0
          m_Data->recordType == static_cast<uint8_t>(IPV4OPT_NOP))
328
0
        return sizeof(uint8_t);
329
0
330
0
      return static_cast<size_t>(m_Data->recordLen);
331
0
    }
332
333
    size_t getDataSize() const override
334
0
    {
335
0
      if (m_Data == nullptr)
336
0
        return 0;
337
0
338
0
      if (getIPv4OptionType() == static_cast<uint8_t>(IPV4OPT_EndOfOptionsList) ||
339
0
          m_Data->recordType == static_cast<uint8_t>(IPV4OPT_NOP))
340
0
        return 0;
341
0
342
0
      return static_cast<size_t>(m_Data->recordLen) - (2 * sizeof(uint8_t));
343
0
    }
344
345
  private:
346
    /// @return IPv4 option type casted as pcpp::IPv4OptionTypes enum
347
    static IPv4OptionTypes getIPv4OptionType(const TLVRawData* data)
348
0
    {
349
0
      if (data == nullptr)
350
0
        return IPV4OPT_Unknown;
351
0
352
0
      return static_cast<IPv4OptionTypes>(data->recordType);
353
0
    }
354
  };
355
356
  /// @class IPv4OptionBuilder
357
  /// A class for building IPv4 option records. This builder receives the IPv4 option parameters in its c'tor,
358
  /// builds the IPv4 option raw buffer and provides a build() method to get a IPv4Option object out of it
359
  class IPv4OptionBuilder : public TLVRecordBuilder
360
  {
361
  private:
362
    bool m_BuilderParamsValid;
363
364
  public:
365
    /// A c'tor for building IPv4 options which their value is a byte array. The IPv4Option object can be later
366
    /// retrieved by calling build()
367
    /// @param[in] optionType IPv4 option type
368
    /// @param[in] optionValue A buffer containing the option value. This buffer is read-only and isn't modified in
369
    /// any way. For option types ::IPV4OPT_NOP and ::IPV4OPT_EndOfOptionsList this parameter is ignored (expected
370
    /// to be nullptr) as these option types don't contain any data
371
    /// @param[in] optionValueLen Option value length in bytes
372
    IPv4OptionBuilder(IPv4OptionTypes optionType, const uint8_t* optionValue, uint8_t optionValueLen)
373
        : TLVRecordBuilder((uint8_t)optionType, optionValue, optionValueLen)
374
0
    {
375
0
      m_BuilderParamsValid = true;
376
0
    }
377
378
    /// A c'tor for building IPv4 options which have a 2-byte value. The IPv4Option object can be later retrieved
379
    /// by calling build()
380
    /// @param[in] optionType IPv4 option type
381
    /// @param[in] optionValue A 2-byte option value
382
    IPv4OptionBuilder(IPv4OptionTypes optionType, uint16_t optionValue)
383
        : TLVRecordBuilder((uint8_t)optionType, optionValue)
384
0
    {
385
0
      m_BuilderParamsValid = true;
386
0
    }
387
388
    /// A c'tor for building IPv4 options which their value is a list of IPv4 addresses, for example:
389
    /// ::IPV4OPT_RecordRoute, ::IPV4OPT_StrictSourceRoute, ::IPV4OPT_LooseSourceRoute. The IPv4Option object can be
390
    /// later retrieved by calling build()
391
    /// @param[in] optionType IPv4 option type
392
    /// @param[in] ipList A vector of IPv4 addresses that will be used as the option value
393
    IPv4OptionBuilder(IPv4OptionTypes optionType, const std::vector<IPv4Address>& ipList);
394
395
    /// A c'tor for building IPv4 timestamp option (::IPV4OPT_Timestamp). The IPv4Option object can be later
396
    /// retrieved by calling build()
397
    /// @param[in] timestampValue The timestamp value to build the IPv4 option with
398
    explicit IPv4OptionBuilder(const IPv4TimestampOptionValue& timestampValue);
399
400
    /// Build the IPv4Option object out of the parameters defined in the c'tor
401
    /// @return The IPv4Option object
402
    IPv4Option build() const;
403
  };
404
405
  /// @class IPv4Layer
406
  /// Represents an IPv4 protocol layer
407
  class IPv4Layer : public Layer, public IPLayer
408
  {
409
  public:
410
    /// A constructor that creates the layer from an existing packet raw data
411
    /// @param[in] data A pointer to the raw data (will be casted to @ref iphdr)
412
    /// @param[in] dataLen Size of the data in bytes
413
    /// @param[in] prevLayer A pointer to the previous layer
414
    /// @param[in] packet A pointer to the Packet instance where layer will be stored in
415
    IPv4Layer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet);
416
417
    /// A constructor that creates the layer from an existing packet raw data
418
    /// @param[in] data A pointer to the raw data (will be casted to @ref iphdr)
419
    /// @param[in] dataLen Size of the data in bytes
420
    /// @param[in] prevLayer A pointer to the previous layer
421
    /// @param[in] packet A pointer to the Packet instance where layer will be stored in
422
    /// @param[in] setTotalLenAsDataLen When setting this value to "true" or when using the other c'tor, the layer
423
    /// data length is calculated from iphdr#totalLength field. When setting to "false" the data length is set as
424
    /// the value of dataLen parameter. Please notice that if iphdr#totalLength is equal to zero (which can happen
425
    /// in TCP Segmentation Offloading), this flag is ignored and the layer data length is calculated by the actual
426
    /// data captured on the wire
427
    IPv4Layer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet, bool setTotalLenAsDataLen);
428
429
    /// A constructor that allocates a new IPv4 header with empty fields
430
    IPv4Layer();
431
432
    /// A constructor that allocates a new IPv4 header with source and destination IPv4 addresses
433
    /// @param[in] srcIP Source IPv4 address
434
    /// @param[in] dstIP Destination IPv4 address
435
    IPv4Layer(const IPv4Address& srcIP, const IPv4Address& dstIP);
436
437
    /// A copy constructor that copy the entire header from the other IPv4Layer (including IPv4 options)
438
    IPv4Layer(const IPv4Layer& other);
439
440
    /// An assignment operator that first delete all data from current layer and then copy the entire header from
441
    /// the other IPv4Layer (including IPv4 options)
442
    IPv4Layer& operator=(const IPv4Layer& other);
443
444
    /// Get a pointer to the IPv4 header. Notice this points directly to the data, so every change will change the
445
    /// actual packet data
446
    /// @return A pointer to the @ref iphdr
447
    iphdr* getIPv4Header() const
448
2.31M
    {
449
2.31M
      return reinterpret_cast<iphdr*>(m_Data);
450
2.31M
    }
451
452
    /// Get the source IP address in the form of IPAddress. This method is very similar to getSrcIPv4Address(),
453
    /// but adds a level of abstraction because IPAddress can be used for both IPv4 and IPv6 addresses
454
    /// @return An IPAddress containing the source address
455
    IPAddress getSrcIPAddress() const override
456
1.02k
    {
457
1.02k
      return getSrcIPv4Address();
458
1.02k
    }
459
460
    /// Get the source IP address in the form of IPv4Address
461
    /// @return An IPv4Address containing the source address
462
    IPv4Address getSrcIPv4Address() const
463
155k
    {
464
155k
      return getIPv4Header()->ipSrc;
465
155k
    }
466
467
    /// Set the source IP address
468
    /// @param[in] ipAddr The IP address to set
469
    void setSrcIPv4Address(const IPv4Address& ipAddr)
470
0
    {
471
0
      getIPv4Header()->ipSrc = ipAddr.toInt();
472
0
    }
473
474
    /// Get the destination IP address in the form of IPAddress. This method is very similar to getDstIPv4Address(),
475
    /// but adds a level of abstraction because IPAddress can be used for both IPv4 and IPv6 addresses
476
    /// @return An IPAddress containing the destination address
477
    IPAddress getDstIPAddress() const override
478
1.02k
    {
479
1.02k
      return getDstIPv4Address();
480
1.02k
    }
481
482
    /// Get the destination IP address in the form of IPv4Address
483
    /// @return An IPv4Address containing the destination address
484
    IPv4Address getDstIPv4Address() const
485
155k
    {
486
155k
      return getIPv4Header()->ipDst;
487
155k
    }
488
489
    /// Set the dest IP address
490
    /// @param[in] ipAddr The IP address to set
491
    void setDstIPv4Address(const IPv4Address& ipAddr)
492
0
    {
493
0
      getIPv4Header()->ipDst = ipAddr.toInt();
494
0
    }
495
496
    /// @return True if this packet is a fragment (in sense of IP fragmentation), false otherwise
497
    bool isFragment() const;
498
499
    /// @return True if this packet is a fragment (in sense of IP fragmentation) and is the first fragment
500
    /// (which usually contains the L4 header). Return false otherwise (not a fragment or not the first fragment)
501
    bool isFirstFragment() const;
502
503
    /// @return True if this packet is a fragment (in sense of IP fragmentation) and is the last fragment.
504
    /// Return false otherwise (not a fragment or not the last fragment)
505
    bool isLastFragment() const;
506
507
    /// @return A bitmask containing the fragmentation flags (e.g IP_DONT_FRAGMENT or IP_MORE_FRAGMENTS)
508
    uint8_t getFragmentFlags() const;
509
510
    /// @return The fragment offset in case this packet is a fragment, 0 otherwise
511
    uint16_t getFragmentOffset() const;
512
513
    /// Get an IPv4 option by type.
514
    /// @param[in] option IPv4 option type
515
    /// @return An IPv4Option object that contains the first option that matches this type, or logical null
516
    /// (IPv4Option#isNull() == true) if no such option found
517
    IPv4Option getOption(IPv4OptionTypes option) const;
518
519
    /// @return The first IPv4 option in the packet. If the current layer contains no options the returned value
520
    /// will contain a logical null (IPv4Option#isNull() == true)
521
    IPv4Option getFirstOption() const;
522
523
    /// Get the IPv4 option that comes after a given option. If the given option was the last one, the
524
    /// returned value will contain a logical null (IPv4Option#isNull() == true)
525
    /// @param[in] option An IPv4 option object that exists in the current layer
526
    /// @return A IPv4Option object that contains the IPv4 option data that comes next, or logical null if the
527
    /// given IPv4 option: (1) was the last one; or (2) contains a logical null; or (3) doesn't belong to this
528
    /// packet
529
    IPv4Option getNextOption(IPv4Option& option) const;
530
531
    /// @return The number of IPv4 options in this layer
532
    size_t getOptionCount() const;
533
534
    /// Add a new IPv4 option at the end of the layer (after the last IPv4 option)
535
    /// @param[in] optionBuilder An IPv4OptionBuilder object that contains the IPv4 option data to be added
536
    /// @return A IPv4Option object that contains the newly added IPv4 option data or logical null
537
    /// (IPv4Option#isNull() == true) if addition failed. In case of a failure a corresponding error message will be
538
    /// printed to log
539
    IPv4Option addOption(const IPv4OptionBuilder& optionBuilder);
540
541
    /// Add a new IPv4 option after an existing one
542
    /// @param[in] optionBuilder An IPv4OptionBuilder object that contains the requested IPv4 option data to be
543
    /// added
544
    /// @param[in] prevOptionType The IPv4 option which the newly added option should come after. This is an
545
    /// optional parameter which gets a default value of ::IPV4OPT_Unknown if omitted, which means the new option
546
    /// will be added as the first option in the layer
547
    /// @return A IPv4Option object containing the newly added IPv4 option data or logical null
548
    /// (IPv4Option#isNull() == true) if addition failed. In case of a failure a corresponding error message will be
549
    /// printed to log
550
    IPv4Option addOptionAfter(const IPv4OptionBuilder& optionBuilder,
551
                              IPv4OptionTypes prevOptionType = IPV4OPT_Unknown);
552
553
    /// Remove an IPv4 option
554
    /// @param[in] option The option type to remove
555
    /// @return True if option was removed successfully or false if option type wasn't found or failed to shorten
556
    /// the layer. If an option appears twice in the layer, its first instance will be removed
557
    bool removeOption(IPv4OptionTypes option);
558
559
    /// Remove all IPv4 options from the layer
560
    /// @return True if options removed successfully or false if some error occurred (an appropriate error message
561
    /// will be printed to log)
562
    bool removeAllOptions();
563
564
    // implement abstract methods
565
566
    /// Currently identifies the following next layers:
567
    /// - UdpLayer
568
    /// - TcpLayer
569
    /// - IcmpLayer
570
    /// - IPv4Layer (IP-in-IP)
571
    /// - IPv6Layer (IP-in-IP)
572
    /// - GreLayer
573
    /// - IgmpLayer
574
    /// - AuthenticationHeaderLayer (IPSec)
575
    /// - ESPLayer (IPSec)
576
    ///
577
    /// Otherwise sets PayloadLayer
578
    void parseNextLayer() override;
579
580
    /// @return Size of IPv4 header (including IPv4 options if exist)
581
    size_t getHeaderLen() const override
582
496k
    {
583
496k
      return static_cast<size_t>(static_cast<uint16_t>(getIPv4Header()->internetHeaderLength) * 4) +
584
496k
             m_TempHeaderExtension;
585
496k
    }
586
587
    /// Calculate the following fields:
588
    /// - iphdr#ipVersion = 4;
589
    /// - iphdr#totalLength = total packet length
590
    /// - iphdr#headerChecksum = calculated
591
    /// - iphdr#protocol = calculated if next layer is known: ::PACKETPP_IPPROTO_TCP for TCP, ::PACKETPP_IPPROTO_UDP
592
    /// for UDP, ::PACKETPP_IPPROTO_ICMP for ICMP
593
    void computeCalculateFields() override;
594
595
    std::string toString() const override;
596
597
    OsiModelLayer getOsiModelLayer() const override
598
54.6k
    {
599
54.6k
      return OsiModelNetworkLayer;
600
54.6k
    }
601
602
    /// A static method that validates the input data
603
    /// @param[in] data The pointer to the beginning of a byte stream of IP packet
604
    /// @param[in] dataLen The length of the byte stream
605
    /// @return True if the data is valid and can represent an IPv4 packet
606
    static inline bool isDataValid(const uint8_t* data, size_t dataLen);
607
608
  private:
609
    int m_NumOfTrailingBytes;
610
    int m_TempHeaderExtension;
611
    TLVRecordReader<IPv4Option> m_OptionReader;
612
613
    void copyLayerData(const IPv4Layer& other);
614
    uint8_t* getOptionsBasePtr() const
615
0
    {
616
0
      return m_Data + sizeof(iphdr);
617
0
    }
618
    IPv4Option addOptionAt(const IPv4OptionBuilder& optionBuilder, int offset);
619
    void adjustOptionsTrailer(size_t totalOptSize);
620
    void initLayer();
621
    void initLayerInPacket(bool setTotalLenAsDataLen);
622
  };
623
624
  // implementation of inline methods
625
626
  bool IPv4Layer::isDataValid(const uint8_t* data, size_t dataLen)
627
310k
  {
628
310k
    const iphdr* hdr = reinterpret_cast<const iphdr*>(data);
629
310k
    return canReinterpretAs<iphdr>(data, dataLen) && hdr->ipVersion == 4 && hdr->internetHeaderLength >= 5;
630
310k
  }
631
632
}  // namespace pcpp