Coverage Report

Created: 2024-02-25 06:29

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