Coverage Report

Created: 2026-08-15 08:03

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