Coverage Report

Created: 2026-01-09 07:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/PcapPlusPlus/Packet++/src/IPv4Layer.cpp
Line
Count
Source
1
0
#define LOG_MODULE PacketLogModuleIPv4Layer
2
3
#include "IPv4Layer.h"
4
#include "IPv6Layer.h"
5
#include "PayloadLayer.h"
6
#include "UdpLayer.h"
7
#include "TcpLayer.h"
8
#include "IcmpLayer.h"
9
#include "GreLayer.h"
10
#include "IgmpLayer.h"
11
#include "IPSecLayer.h"
12
#include "VrrpLayer.h"
13
#include "PacketUtils.h"
14
#include <sstream>
15
#include "Logger.h"
16
#include "EndianPortable.h"
17
18
namespace pcpp
19
{
20
21
0
#define IPV4OPT_DUMMY 0xff
22
0
#define IPV4_MAX_OPT_SIZE 40
23
24
  /// ~~~~~~~~~~~~~~~~~
25
  /// IPv4OptionBuilder
26
  /// ~~~~~~~~~~~~~~~~~
27
28
  IPv4OptionBuilder::IPv4OptionBuilder(IPv4OptionTypes optionType, const std::vector<IPv4Address>& ipList)
29
0
  {
30
0
    m_RecType = (uint8_t)optionType;
31
0
    m_RecValueLen = ipList.size() * sizeof(uint32_t) + sizeof(uint8_t);
32
0
    m_RecValue = new uint8_t[m_RecValueLen];
33
34
0
    size_t curOffset = 0;
35
0
    m_RecValue[curOffset++] = 0;  // init pointer value
36
37
0
    bool firstZero = false;
38
0
    for (const auto& ipAddr : ipList)
39
0
    {
40
0
      uint32_t ipAddrAsInt = ipAddr.toInt();
41
42
0
      if (!firstZero)
43
0
        m_RecValue[0] += (uint8_t)4;
44
45
0
      if (!firstZero && ipAddrAsInt == 0)
46
0
        firstZero = true;
47
48
0
      memcpy(m_RecValue + curOffset, &ipAddrAsInt, sizeof(uint32_t));
49
0
      curOffset += sizeof(uint32_t);
50
0
    }
51
52
0
    m_BuilderParamsValid = true;
53
0
  }
54
55
  IPv4OptionBuilder::IPv4OptionBuilder(const IPv4TimestampOptionValue& timestampValue)
56
0
  {
57
0
    m_RecType = (uint8_t)IPV4OPT_Timestamp;
58
0
    m_RecValueLen = 0;
59
0
    m_RecValue = nullptr;
60
61
0
    if (timestampValue.type == IPv4TimestampOptionValue::Unknown)
62
0
    {
63
0
      PCPP_LOG_ERROR("Cannot build timestamp option of type IPv4TimestampOptionValue::Unknown");
64
0
      m_BuilderParamsValid = false;
65
0
      return;
66
0
    }
67
68
0
    if (timestampValue.type == IPv4TimestampOptionValue::TimestampsForPrespecifiedIPs)
69
0
    {
70
0
      PCPP_LOG_ERROR(
71
0
          "Cannot build timestamp option of type IPv4TimestampOptionValue::TimestampsForPrespecifiedIPs - this type is not supported");
72
0
      m_BuilderParamsValid = false;
73
0
      return;
74
0
    }
75
76
0
    if (timestampValue.type == IPv4TimestampOptionValue::TimestampAndIP &&
77
0
        timestampValue.timestamps.size() != timestampValue.ipAddresses.size())
78
0
    {
79
0
      PCPP_LOG_ERROR(
80
0
          "Cannot build timestamp option of type IPv4TimestampOptionValue::TimestampAndIP because number of timestamps and IP addresses is not equal");
81
0
      m_BuilderParamsValid = false;
82
0
      return;
83
0
    }
84
85
0
    m_RecValueLen = timestampValue.timestamps.size() * sizeof(uint32_t) + 2 * sizeof(uint8_t);
86
87
0
    if (timestampValue.type == IPv4TimestampOptionValue::TimestampAndIP)
88
0
    {
89
0
      m_RecValueLen += timestampValue.timestamps.size() * sizeof(uint32_t);
90
0
    }
91
92
0
    m_RecValue = new uint8_t[m_RecValueLen];
93
94
0
    size_t curOffset = 0;
95
0
    m_RecValue[curOffset++] = 1;  // pointer default value is 1 - means there are no empty timestamps
96
0
    m_RecValue[curOffset++] = (uint8_t)timestampValue.type;  // timestamp type
97
98
0
    int firstZero = -1;
99
0
    for (int i = 0; i < (int)timestampValue.timestamps.size(); i++)
100
0
    {
101
0
      uint32_t timestamp = htobe32(timestampValue.timestamps.at(i));
102
103
      // for pointer calculation - find the first timestamp equals to 0
104
0
      if (timestamp == 0 && firstZero == -1)
105
0
        firstZero = i;
106
107
0
      if (timestampValue.type == IPv4TimestampOptionValue::TimestampAndIP)
108
0
      {
109
0
        uint32_t ipAddrAsInt = timestampValue.ipAddresses.at(i).toInt();
110
0
        memcpy(m_RecValue + curOffset, &ipAddrAsInt, sizeof(uint32_t));
111
0
        curOffset += sizeof(uint32_t);
112
0
      }
113
114
0
      memcpy(m_RecValue + curOffset, &timestamp, sizeof(uint32_t));
115
0
      curOffset += sizeof(uint32_t);
116
0
    }
117
118
    // calculate pointer field
119
0
    if (firstZero > -1)
120
0
    {
121
0
      uint8_t pointerVal = (uint8_t)(4 * sizeof(uint8_t) + firstZero * sizeof(uint32_t) + 1);
122
0
      if (timestampValue.type == IPv4TimestampOptionValue::TimestampAndIP)
123
0
        pointerVal += (uint8_t)(firstZero * sizeof(uint32_t));
124
125
0
      m_RecValue[0] = pointerVal;
126
0
    }
127
128
0
    m_BuilderParamsValid = true;
129
0
  }
130
131
  IPv4Option IPv4OptionBuilder::build() const
132
0
  {
133
0
    if (!m_BuilderParamsValid)
134
0
      return IPv4Option(nullptr);
135
136
0
    size_t optionSize = m_RecValueLen + 2 * sizeof(uint8_t);
137
138
0
    uint8_t recType = static_cast<uint8_t>(m_RecType);
139
0
    if ((recType == (uint8_t)IPV4OPT_NOP || recType == (uint8_t)IPV4OPT_EndOfOptionsList))
140
0
    {
141
0
      if (m_RecValueLen != 0)
142
0
      {
143
0
        PCPP_LOG_ERROR(
144
0
            "Can't set IPv4 NOP option or IPv4 End-of-options option with size different than 0, tried to set size "
145
0
            << (int)m_RecValueLen);
146
0
        return IPv4Option(nullptr);
147
0
      }
148
149
0
      optionSize = sizeof(uint8_t);
150
0
    }
151
152
0
    uint8_t* recordBuffer = new uint8_t[optionSize];
153
0
    memset(recordBuffer, 0, optionSize);
154
0
    recordBuffer[0] = recType;
155
0
    if (optionSize > 1)
156
0
    {
157
0
      recordBuffer[1] = static_cast<uint8_t>(optionSize);
158
0
      if (optionSize > 2 && m_RecValue != nullptr)
159
0
        memcpy(recordBuffer + 2, m_RecValue, m_RecValueLen);
160
0
    }
161
162
0
    return IPv4Option(recordBuffer);
163
0
  }
164
165
  /// ~~~~~~~~~
166
  /// IPv4Layer
167
  /// ~~~~~~~~~
168
169
  void IPv4Layer::initLayer()
170
0
  {
171
0
    const size_t headerLen = sizeof(iphdr);
172
0
    m_DataLen = headerLen;
173
0
    m_Data = new uint8_t[headerLen];
174
0
    m_Protocol = IPv4;
175
0
    memset(m_Data, 0, headerLen);
176
0
    iphdr* ipHdr = getIPv4Header();
177
0
    ipHdr->internetHeaderLength = (5 & 0xf);
178
0
    m_NumOfTrailingBytes = 0;
179
0
    m_TempHeaderExtension = 0;
180
0
  }
181
182
  void IPv4Layer::initLayerInPacket(bool setTotalLenAsDataLen)
183
0
  {
184
0
    m_Protocol = IPv4;
185
0
    m_NumOfTrailingBytes = 0;
186
0
    m_TempHeaderExtension = 0;
187
0
    if (setTotalLenAsDataLen)
188
0
    {
189
0
      size_t totalLen = be16toh(getIPv4Header()->totalLength);
190
      // if totalLen == 0 this usually means TCP Segmentation Offload (TSO). In this case we should ignore the
191
      // value of totalLen and look at the data captured on the wire
192
0
      if ((totalLen < m_DataLen) && (totalLen != 0))
193
0
      {
194
0
        auto headerLen = getHeaderLen();
195
        // Make sure totalLen is larger than header len, otherwise it's a malformed packet
196
0
        m_DataLen = totalLen > headerLen ? totalLen : headerLen;
197
0
      }
198
0
    }
199
0
  }
200
201
  void IPv4Layer::copyLayerData(const IPv4Layer& other)
202
0
  {
203
0
    m_OptionReader = other.m_OptionReader;
204
0
    m_NumOfTrailingBytes = other.m_NumOfTrailingBytes;
205
0
    m_TempHeaderExtension = other.m_TempHeaderExtension;
206
0
  }
207
208
  IPv4Layer::IPv4Layer()
209
0
  {
210
0
    initLayer();
211
0
  }
212
213
  IPv4Layer::IPv4Layer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet, bool setTotalLenAsDataLen)
214
0
      : Layer(data, dataLen, prevLayer, packet)
215
0
  {
216
0
    initLayerInPacket(setTotalLenAsDataLen);
217
0
  }
218
219
  IPv4Layer::IPv4Layer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
220
0
      : Layer(data, dataLen, prevLayer, packet)
221
0
  {
222
0
    initLayerInPacket(true);
223
0
  }
224
225
  IPv4Layer::IPv4Layer(const IPv4Address& srcIP, const IPv4Address& dstIP)
226
0
  {
227
0
    initLayer();
228
0
    iphdr* ipHdr = getIPv4Header();
229
0
    ipHdr->ipSrc = srcIP.toInt();
230
0
    ipHdr->ipDst = dstIP.toInt();
231
0
  }
232
233
0
  IPv4Layer::IPv4Layer(const IPv4Layer& other) : Layer(other)
234
0
  {
235
0
    copyLayerData(other);
236
0
  }
237
238
  IPv4Layer& IPv4Layer::operator=(const IPv4Layer& other)
239
0
  {
240
0
    Layer::operator=(other);
241
242
0
    copyLayerData(other);
243
244
0
    return *this;
245
0
  }
246
247
  void IPv4Layer::parseNextLayer()
248
0
  {
249
0
    size_t hdrLen = getHeaderLen();
250
0
    if (m_DataLen <= hdrLen || hdrLen == 0)
251
0
      return;
252
253
0
    iphdr* ipHdr = getIPv4Header();
254
255
0
    uint8_t* payload = m_Data + hdrLen;
256
0
    size_t payloadLen = m_DataLen - hdrLen;
257
258
    // If it's a fragment don't parse upper layers, unless if it's the first fragment
259
    // TODO: assuming first fragment contains at least L4 header, what if it's not true?
260
0
    if (isFragment())
261
0
    {
262
0
      constructNextLayer<PayloadLayer>(payload, payloadLen, m_Packet);
263
0
      return;
264
0
    }
265
266
0
    switch (ipHdr->protocol)
267
0
    {
268
0
    case PACKETPP_IPPROTO_UDP:
269
0
      tryConstructNextLayerWithFallback<UdpLayer, PayloadLayer>(payload, payloadLen, m_Packet);
270
0
      break;
271
0
    case PACKETPP_IPPROTO_TCP:
272
0
      tryConstructNextLayerWithFallback<TcpLayer, PayloadLayer>(payload, payloadLen, m_Packet);
273
0
      break;
274
0
    case PACKETPP_IPPROTO_ICMP:
275
0
      tryConstructNextLayerWithFallback<IcmpLayer, PayloadLayer>(payload, payloadLen, m_Packet);
276
0
      break;
277
0
    case PACKETPP_IPPROTO_IPIP:
278
0
    {
279
      // todo: no tests for this case
280
0
      switch (IPLayer::getIPVersion(payload, payloadLen))
281
0
      {
282
0
      case IPv4:
283
0
        tryConstructNextLayerWithFallback<IPv4Layer, PayloadLayer>(payload, payloadLen, m_Packet);
284
0
        break;
285
0
      case IPv6:
286
0
        tryConstructNextLayerWithFallback<IPv6Layer, PayloadLayer>(payload, payloadLen, m_Packet);
287
0
        break;
288
0
      default:
289
0
        constructNextLayer<PayloadLayer>(payload, payloadLen, m_Packet);
290
0
        break;
291
0
      }
292
0
      break;
293
0
    }
294
0
    case PACKETPP_IPPROTO_GRE:
295
0
    {
296
0
      switch (GreLayer::getGREVersion(payload, payloadLen))
297
0
      {
298
0
      case GREv0:
299
0
        tryConstructNextLayerWithFallback<GREv0Layer, PayloadLayer>(payload, payloadLen, m_Packet);
300
0
        break;
301
0
      case GREv1:
302
0
        tryConstructNextLayerWithFallback<GREv1Layer, PayloadLayer>(payload, payloadLen, m_Packet);
303
0
        break;
304
0
      default:
305
0
        constructNextLayer<PayloadLayer>(payload, payloadLen, m_Packet);
306
0
        break;
307
0
      };
308
0
      break;
309
0
    }
310
0
    case PACKETPP_IPPROTO_IGMP:
311
0
    {
312
0
      bool igmpQuery = false;
313
0
      ProtocolType igmpVer = IgmpLayer::getIGMPVerFromData(
314
0
          payload, std::min<size_t>(payloadLen, be16toh(getIPv4Header()->totalLength) - hdrLen), igmpQuery);
315
316
0
      switch (igmpVer)
317
0
      {
318
0
      case IGMPv1:
319
0
        tryConstructNextLayerWithFallback<IgmpV1Layer, PayloadLayer>(payload, payloadLen, m_Packet);
320
0
        break;
321
0
      case IGMPv2:
322
0
        tryConstructNextLayerWithFallback<IgmpV2Layer, PayloadLayer>(payload, payloadLen, m_Packet);
323
0
        break;
324
0
      case IGMPv3:
325
0
      {
326
0
        if (igmpQuery)
327
0
          tryConstructNextLayerWithFallback<IgmpV3QueryLayer, PayloadLayer>(payload, payloadLen, m_Packet);
328
0
        else
329
0
          tryConstructNextLayerWithFallback<IgmpV3ReportLayer, PayloadLayer>(payload, payloadLen, m_Packet);
330
0
        break;
331
0
      }
332
0
      default:
333
0
        constructNextLayer<PayloadLayer>(payload, payloadLen, m_Packet);
334
0
        break;
335
0
      }
336
0
      break;
337
0
    }
338
0
    case PACKETPP_IPPROTO_AH:
339
0
      tryConstructNextLayerWithFallback<AuthenticationHeaderLayer, PayloadLayer>(payload, payloadLen, m_Packet);
340
0
      break;
341
0
    case PACKETPP_IPPROTO_ESP:
342
0
      tryConstructNextLayerWithFallback<ESPLayer, PayloadLayer>(payload, payloadLen, m_Packet);
343
0
      break;
344
0
    case PACKETPP_IPPROTO_IPV6:
345
0
      tryConstructNextLayerWithFallback<IPv6Layer, PayloadLayer>(payload, payloadLen, m_Packet);
346
0
      break;
347
0
    case PACKETPP_IPPROTO_VRRP:
348
0
    {
349
0
      switch (VrrpLayer::getVersionFromData(payload, payloadLen))
350
0
      {
351
0
      case VRRPv2:
352
0
        tryConstructNextLayerWithFallback<VrrpV2Layer, PayloadLayer>(payload, payloadLen, m_Packet);
353
0
        break;
354
0
      case VRRPv3:
355
0
        tryConstructNextLayerWithFallback<VrrpV3Layer, PayloadLayer>(payload, payloadLen, m_Packet,
356
0
                                                                     IPAddress::IPv4AddressType);
357
0
        break;
358
0
      default:
359
0
        constructNextLayer<PayloadLayer>(payload, payloadLen, m_Packet);
360
0
        break;
361
0
      }
362
0
      break;
363
0
    }
364
0
    }
365
366
    // If no next layer was constructed, assume it's a payload layer
367
0
    if (!hasNextLayer())
368
0
      constructNextLayer<PayloadLayer>(payload, payloadLen, m_Packet);
369
0
  }
370
371
  void IPv4Layer::computeCalculateFields()
372
0
  {
373
0
    iphdr* ipHdr = getIPv4Header();
374
0
    ipHdr->ipVersion = (4 & 0x0f);
375
0
    ipHdr->totalLength = htobe16(m_DataLen);
376
0
    ipHdr->headerChecksum = 0;
377
378
0
    if (m_NextLayer != nullptr)
379
0
    {
380
0
      switch (m_NextLayer->getProtocol())
381
0
      {
382
0
      case TCP:
383
0
        ipHdr->protocol = PACKETPP_IPPROTO_TCP;
384
0
        break;
385
0
      case UDP:
386
0
        ipHdr->protocol = PACKETPP_IPPROTO_UDP;
387
0
        break;
388
0
      case ICMP:
389
0
        ipHdr->protocol = PACKETPP_IPPROTO_ICMP;
390
0
        break;
391
0
      case GREv0:
392
0
      case GREv1:
393
0
        ipHdr->protocol = PACKETPP_IPPROTO_GRE;
394
0
        break;
395
0
      case IGMPv1:
396
0
      case IGMPv2:
397
0
      case IGMPv3:
398
0
        ipHdr->protocol = PACKETPP_IPPROTO_IGMP;
399
0
        break;
400
0
      case VRRPv2:
401
0
      case VRRPv3:
402
0
        ipHdr->protocol = PACKETPP_IPPROTO_VRRP;
403
0
        break;
404
0
      default:
405
0
        break;
406
0
      }
407
0
    }
408
409
0
    ScalarBuffer<uint16_t> scalar = { (uint16_t*)ipHdr, (size_t)(ipHdr->internetHeaderLength * 4) };
410
0
    ipHdr->headerChecksum = htobe16(computeChecksum(&scalar, 1));
411
0
  }
412
413
  bool IPv4Layer::isFragment() const
414
0
  {
415
0
    return ((getFragmentFlags() & PCPP_IP_MORE_FRAGMENTS) != 0 || getFragmentOffset() != 0);
416
0
  }
417
418
  bool IPv4Layer::isFirstFragment() const
419
0
  {
420
0
    return isFragment() && (getFragmentOffset() == 0);
421
0
  }
422
423
  bool IPv4Layer::isLastFragment() const
424
0
  {
425
0
    return isFragment() && ((getFragmentFlags() & PCPP_IP_MORE_FRAGMENTS) == 0);
426
0
  }
427
428
  uint8_t IPv4Layer::getFragmentFlags() const
429
0
  {
430
0
    return getIPv4Header()->fragmentOffset & 0xE0;
431
0
  }
432
433
  uint16_t IPv4Layer::getFragmentOffset() const
434
0
  {
435
0
    return be16toh(getIPv4Header()->fragmentOffset & (uint16_t)0xFF1F) * 8;
436
0
  }
437
438
  std::string IPv4Layer::toString() const
439
0
  {
440
0
    std::string fragment = "";
441
0
    if (isFragment())
442
0
    {
443
0
      if (isFirstFragment())
444
0
        fragment = "First fragment";
445
0
      else if (isLastFragment())
446
0
        fragment = "Last fragment";
447
0
      else
448
0
        fragment = "Fragment";
449
450
0
      std::stringstream sstm;
451
0
      sstm << fragment << " [offset= " << getFragmentOffset() << "], ";
452
0
      fragment = sstm.str();
453
0
    }
454
455
0
    return "IPv4 Layer, " + fragment + "Src: " + getSrcIPv4Address().toString() +
456
0
           ", Dst: " + getDstIPv4Address().toString();
457
0
  }
458
459
  IPv4Option IPv4Layer::getOption(IPv4OptionTypes option) const
460
0
  {
461
0
    return m_OptionReader.getTLVRecord((uint8_t)option, getOptionsBasePtr(), getHeaderLen() - sizeof(iphdr));
462
0
  }
463
464
  IPv4Option IPv4Layer::getFirstOption() const
465
0
  {
466
0
    return m_OptionReader.getFirstTLVRecord(getOptionsBasePtr(), getHeaderLen() - sizeof(iphdr));
467
0
  }
468
469
  IPv4Option IPv4Layer::getNextOption(IPv4Option& option) const
470
0
  {
471
0
    return m_OptionReader.getNextTLVRecord(option, getOptionsBasePtr(), getHeaderLen() - sizeof(iphdr));
472
0
  }
473
474
  size_t IPv4Layer::getOptionCount() const
475
0
  {
476
0
    return m_OptionReader.getTLVRecordCount(getOptionsBasePtr(), getHeaderLen() - sizeof(iphdr));
477
0
  }
478
479
  void IPv4Layer::adjustOptionsTrailer(size_t totalOptSize)
480
0
  {
481
0
    size_t ipHdrSize = sizeof(iphdr);
482
483
0
    int newNumberOfTrailingBytes = 0;
484
0
    while ((totalOptSize + newNumberOfTrailingBytes) % 4 != 0)
485
0
      newNumberOfTrailingBytes++;
486
487
0
    if (newNumberOfTrailingBytes < m_NumOfTrailingBytes)
488
0
      shortenLayer(ipHdrSize + totalOptSize, m_NumOfTrailingBytes - newNumberOfTrailingBytes);
489
0
    else if (newNumberOfTrailingBytes > m_NumOfTrailingBytes)
490
0
      extendLayer(ipHdrSize + totalOptSize, newNumberOfTrailingBytes - m_NumOfTrailingBytes);
491
492
0
    m_NumOfTrailingBytes = newNumberOfTrailingBytes;
493
494
0
    for (int i = 0; i < m_NumOfTrailingBytes; i++)
495
0
      m_Data[ipHdrSize + totalOptSize + i] = IPV4OPT_DUMMY;
496
497
0
    m_TempHeaderExtension = 0;
498
0
    getIPv4Header()->internetHeaderLength = ((ipHdrSize + totalOptSize + m_NumOfTrailingBytes) / 4 & 0x0f);
499
0
  }
500
501
  IPv4Option IPv4Layer::addOptionAt(const IPv4OptionBuilder& optionBuilder, int offset)
502
0
  {
503
0
    IPv4Option newOption = optionBuilder.build();
504
0
    if (newOption.isNull())
505
0
      return newOption;
506
507
0
    size_t sizeToExtend = newOption.getTotalSize();
508
509
0
    size_t totalOptSize = getHeaderLen() - sizeof(iphdr) - m_NumOfTrailingBytes + sizeToExtend;
510
511
0
    if (totalOptSize > IPV4_MAX_OPT_SIZE)
512
0
    {
513
0
      PCPP_LOG_ERROR("Cannot add option - adding this option will exceed IPv4 total option size which is "
514
0
                     << IPV4_MAX_OPT_SIZE);
515
0
      newOption.purgeRecordData();
516
0
      return IPv4Option(nullptr);
517
0
    }
518
519
0
    if (!extendLayer(offset, sizeToExtend))
520
0
    {
521
0
      PCPP_LOG_ERROR("Could not extend IPv4Layer in [" << sizeToExtend << "] bytes");
522
0
      newOption.purgeRecordData();
523
0
      return IPv4Option(nullptr);
524
0
    }
525
526
0
    memcpy(m_Data + offset, newOption.getRecordBasePtr(), newOption.getTotalSize());
527
528
0
    newOption.purgeRecordData();
529
530
    // setting this m_TempHeaderExtension because adjustOptionsTrailer() may extend or shorten the layer and the
531
    // extend or shorten methods need to know the accurate current size of the header. m_TempHeaderExtension will be
532
    // added to the length extracted from getIPv4Header()->internetHeaderLength as the temp new size
533
0
    m_TempHeaderExtension = sizeToExtend;
534
0
    adjustOptionsTrailer(totalOptSize);
535
    // the adjustOptionsTrailer() adds or removed the trailing bytes and sets getIPv4Header()->internetHeaderLength
536
    // to the correct size, so the m_TempHeaderExtension isn't needed anymore
537
0
    m_TempHeaderExtension = 0;
538
539
0
    m_OptionReader.changeTLVRecordCount(1);
540
541
0
    uint8_t* newOptPtr = m_Data + offset;
542
543
0
    return IPv4Option(newOptPtr);
544
0
  }
545
546
  IPv4Option IPv4Layer::addOption(const IPv4OptionBuilder& optionBuilder)
547
0
  {
548
0
    return addOptionAt(optionBuilder, getHeaderLen() - m_NumOfTrailingBytes);
549
0
  }
550
551
  IPv4Option IPv4Layer::addOptionAfter(const IPv4OptionBuilder& optionBuilder, IPv4OptionTypes prevOptionType)
552
0
  {
553
0
    int offset = 0;
554
555
0
    IPv4Option prevOpt = getOption(prevOptionType);
556
557
0
    if (prevOpt.isNull())
558
0
    {
559
0
      offset = sizeof(iphdr);
560
0
    }
561
0
    else
562
0
    {
563
0
      offset = prevOpt.getRecordBasePtr() + prevOpt.getTotalSize() - m_Data;
564
0
    }
565
566
0
    return addOptionAt(optionBuilder, offset);
567
0
  }
568
569
  bool IPv4Layer::removeOption(IPv4OptionTypes option)
570
0
  {
571
0
    IPv4Option opt = getOption(option);
572
0
    if (opt.isNull())
573
0
    {
574
0
      return false;
575
0
    }
576
577
    // calculate total option size
578
0
    IPv4Option curOpt = getFirstOption();
579
0
    size_t totalOptSize = 0;
580
0
    while (!curOpt.isNull())
581
0
    {
582
0
      totalOptSize += curOpt.getTotalSize();
583
0
      curOpt = getNextOption(curOpt);
584
0
    }
585
0
    totalOptSize -= opt.getTotalSize();
586
587
0
    int offset = opt.getRecordBasePtr() - m_Data;
588
589
0
    size_t sizeToShorten = opt.getTotalSize();
590
0
    if (!shortenLayer(offset, sizeToShorten))
591
0
    {
592
0
      PCPP_LOG_ERROR("Failed to remove IPv4 option: cannot shorten layer");
593
0
      return false;
594
0
    }
595
596
    // setting this m_TempHeaderExtension because adjustOptionsTrailer() may extend or shorten the layer and the
597
    // extend or shorten methods need to know the accurate current size of the header. m_TempHeaderExtension will be
598
    // added to the length extracted from getIPv4Header()->internetHeaderLength as the temp new size
599
0
    m_TempHeaderExtension = 0 - sizeToShorten;
600
0
    adjustOptionsTrailer(totalOptSize);
601
    // the adjustOptionsTrailer() adds or removed the trailing bytes and sets getIPv4Header()->internetHeaderLength
602
    // to the correct size, so the m_TempHeaderExtension isn't needed anymore
603
0
    m_TempHeaderExtension = 0;
604
605
0
    m_OptionReader.changeTLVRecordCount(-1);
606
607
0
    return true;
608
0
  }
609
610
  bool IPv4Layer::removeAllOptions()
611
0
  {
612
0
    int offset = sizeof(iphdr);
613
614
0
    if (!shortenLayer(offset, getHeaderLen() - offset))
615
0
      return false;
616
617
0
    getIPv4Header()->internetHeaderLength = (5 & 0xf);
618
0
    m_NumOfTrailingBytes = 0;
619
0
    m_OptionReader.changeTLVRecordCount(0 - getOptionCount());
620
0
    return true;
621
0
  }
622
623
}  // namespace pcpp