Coverage Report

Created: 2026-10-17 07:09

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