Coverage Report

Created: 2026-04-12 07:26

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
951k
  {
184
951k
    m_Protocol = IPv4;
185
951k
    m_NumOfTrailingBytes = 0;
186
951k
    m_TempHeaderExtension = 0;
187
951k
    if (setTotalLenAsDataLen)
188
951k
    {
189
951k
      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
951k
      if ((totalLen < m_DataLen) && (totalLen != 0))
193
198k
      {
194
198k
        auto headerLen = getHeaderLen();
195
        // Make sure totalLen is larger than header len, otherwise it's a malformed packet
196
198k
        m_DataLen = totalLen > headerLen ? totalLen : headerLen;
197
198k
      }
198
951k
    }
199
951k
  }
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
951k
      : Layer(data, dataLen, prevLayer, packet)
221
951k
  {
222
951k
    initLayerInPacket(true);
223
951k
  }
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
951k
  {
249
951k
    size_t hdrLen = getHeaderLen();
250
951k
    if (m_DataLen <= hdrLen || hdrLen == 0)
251
1.51k
      return;
252
253
950k
    iphdr* ipHdr = getIPv4Header();
254
255
950k
    uint8_t* payload = m_Data + hdrLen;
256
950k
    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
950k
    if (isFragment())
261
7.89k
    {
262
7.89k
      constructNextLayer<PayloadLayer>(payload, payloadLen, getAttachedPacket());
263
7.89k
      return;
264
7.89k
    }
265
266
942k
    switch (ipHdr->protocol)
267
942k
    {
268
335k
    case PACKETPP_IPPROTO_UDP:
269
335k
      tryConstructNextLayerWithFallback<UdpLayer, PayloadLayer>(payload, payloadLen, getAttachedPacket());
270
335k
      break;
271
454k
    case PACKETPP_IPPROTO_TCP:
272
454k
      tryConstructNextLayerWithFallback<TcpLayer, PayloadLayer>(payload, payloadLen, getAttachedPacket());
273
454k
      break;
274
43.4k
    case PACKETPP_IPPROTO_ICMP:
275
43.4k
      tryConstructNextLayerWithFallback<IcmpLayer, PayloadLayer>(payload, payloadLen, getAttachedPacket());
276
43.4k
      break;
277
2.07k
    case PACKETPP_IPPROTO_IPIP:
278
2.07k
    {
279
      // todo: no tests for this case
280
2.07k
      switch (IPLayer::getIPVersion(payload, payloadLen))
281
2.07k
      {
282
1.78k
      case IPv4:
283
1.78k
        tryConstructNextLayerWithFallback<IPv4Layer, PayloadLayer>(payload, payloadLen, getAttachedPacket());
284
1.78k
        break;
285
77
      case IPv6:
286
77
        tryConstructNextLayerWithFallback<IPv6Layer, PayloadLayer>(payload, payloadLen, getAttachedPacket());
287
77
        break;
288
215
      default:
289
215
        constructNextLayer<PayloadLayer>(payload, payloadLen, getAttachedPacket());
290
215
        break;
291
2.07k
      }
292
2.07k
      break;
293
2.07k
    }
294
74.5k
    case PACKETPP_IPPROTO_GRE:
295
74.5k
    {
296
74.5k
      switch (GreLayer::getGREVersion(payload, payloadLen))
297
74.5k
      {
298
3.21k
      case GREv0:
299
3.21k
        tryConstructNextLayerWithFallback<GREv0Layer, PayloadLayer>(payload, payloadLen, getAttachedPacket());
300
3.21k
        break;
301
71.0k
      case GREv1:
302
71.0k
        tryConstructNextLayerWithFallback<GREv1Layer, PayloadLayer>(payload, payloadLen, getAttachedPacket());
303
71.0k
        break;
304
294
      default:
305
294
        constructNextLayer<PayloadLayer>(payload, payloadLen, getAttachedPacket());
306
294
        break;
307
74.5k
      };
308
74.5k
      break;
309
74.5k
    }
310
15.5k
    case PACKETPP_IPPROTO_IGMP:
311
15.5k
    {
312
15.5k
      bool igmpQuery = false;
313
15.5k
      ProtocolType igmpVer = IgmpLayer::getIGMPVerFromData(
314
15.5k
          payload, std::min<size_t>(payloadLen, be16toh(getIPv4Header()->totalLength) - hdrLen), igmpQuery);
315
316
15.5k
      switch (igmpVer)
317
15.5k
      {
318
3.13k
      case IGMPv1:
319
3.13k
        tryConstructNextLayerWithFallback<IgmpV1Layer, PayloadLayer>(payload, payloadLen, getAttachedPacket());
320
3.13k
        break;
321
7.73k
      case IGMPv2:
322
7.73k
        tryConstructNextLayerWithFallback<IgmpV2Layer, PayloadLayer>(payload, payloadLen, getAttachedPacket());
323
7.73k
        break;
324
3.93k
      case IGMPv3:
325
3.93k
      {
326
3.93k
        if (igmpQuery)
327
1.70k
          tryConstructNextLayerWithFallback<IgmpV3QueryLayer, PayloadLayer>(payload, payloadLen,
328
1.70k
                                                                            getAttachedPacket());
329
2.23k
        else
330
2.23k
          tryConstructNextLayerWithFallback<IgmpV3ReportLayer, PayloadLayer>(payload, payloadLen,
331
2.23k
                                                                             getAttachedPacket());
332
3.93k
        break;
333
0
      }
334
736
      default:
335
736
        constructNextLayer<PayloadLayer>(payload, payloadLen, getAttachedPacket());
336
736
        break;
337
15.5k
      }
338
15.5k
      break;
339
15.5k
    }
340
15.5k
    case PACKETPP_IPPROTO_AH:
341
5.67k
      tryConstructNextLayerWithFallback<AuthenticationHeaderLayer, PayloadLayer>(payload, payloadLen,
342
5.67k
                                                                                 getAttachedPacket());
343
5.67k
      break;
344
2.74k
    case PACKETPP_IPPROTO_ESP:
345
2.74k
      tryConstructNextLayerWithFallback<ESPLayer, PayloadLayer>(payload, payloadLen, getAttachedPacket());
346
2.74k
      break;
347
278
    case PACKETPP_IPPROTO_IPV6:
348
278
      tryConstructNextLayerWithFallback<IPv6Layer, PayloadLayer>(payload, payloadLen, getAttachedPacket());
349
278
      break;
350
7.45k
    case PACKETPP_IPPROTO_VRRP:
351
7.45k
    {
352
7.45k
      switch (VrrpLayer::getVersionFromData(payload, payloadLen))
353
7.45k
      {
354
3.97k
      case VRRPv2:
355
3.97k
        tryConstructNextLayerWithFallback<VrrpV2Layer, PayloadLayer>(payload, payloadLen, getAttachedPacket());
356
3.97k
        break;
357
3.24k
      case VRRPv3:
358
3.24k
        tryConstructNextLayerWithFallback<VrrpV3Layer, PayloadLayer>(payload, payloadLen, getAttachedPacket(),
359
3.24k
                                                                     IPAddress::IPv4AddressType);
360
3.24k
        break;
361
229
      default:
362
229
        constructNextLayer<PayloadLayer>(payload, payloadLen, getAttachedPacket());
363
229
        break;
364
7.45k
      }
365
7.45k
      break;
366
7.45k
    }
367
942k
    }
368
369
    // If no next layer was constructed, assume it's a payload layer
370
942k
    if (!hasNextLayer())
371
962
      constructNextLayer<PayloadLayer>(payload, payloadLen, getAttachedPacket());
372
942k
  }
373
374
  void IPv4Layer::computeCalculateFields()
375
162k
  {
376
162k
    iphdr* ipHdr = getIPv4Header();
377
162k
    ipHdr->ipVersion = (4 & 0x0f);
378
162k
    ipHdr->totalLength = htobe16(m_DataLen);
379
162k
    ipHdr->headerChecksum = 0;
380
381
162k
    if (m_NextLayer != nullptr)
382
161k
    {
383
161k
      switch (m_NextLayer->getProtocol())
384
161k
      {
385
82.6k
      case TCP:
386
82.6k
        ipHdr->protocol = PACKETPP_IPPROTO_TCP;
387
82.6k
        break;
388
53.4k
      case UDP:
389
53.4k
        ipHdr->protocol = PACKETPP_IPPROTO_UDP;
390
53.4k
        break;
391
7.56k
      case ICMP:
392
7.56k
        ipHdr->protocol = PACKETPP_IPPROTO_ICMP;
393
7.56k
        break;
394
596
      case GREv0:
395
7.16k
      case GREv1:
396
7.16k
        ipHdr->protocol = PACKETPP_IPPROTO_GRE;
397
7.16k
        break;
398
635
      case IGMPv1:
399
2.18k
      case IGMPv2:
400
3.06k
      case IGMPv3:
401
3.06k
        ipHdr->protocol = PACKETPP_IPPROTO_IGMP;
402
3.06k
        break;
403
987
      case VRRPv2:
404
1.71k
      case VRRPv3:
405
1.71k
        ipHdr->protocol = PACKETPP_IPPROTO_VRRP;
406
1.71k
        break;
407
6.08k
      default:
408
6.08k
        break;
409
161k
      }
410
161k
    }
411
412
162k
    ScalarBuffer<uint16_t> scalar = { (uint16_t*)ipHdr, (size_t)(ipHdr->internetHeaderLength * 4) };
413
162k
    ipHdr->headerChecksum = htobe16(computeChecksum(&scalar, 1));
414
162k
  }
415
416
  bool IPv4Layer::isFragment() const
417
1.28M
  {
418
1.28M
    return ((getFragmentFlags() & PCPP_IP_MORE_FRAGMENTS) != 0 || getFragmentOffset() != 0);
419
1.28M
  }
420
421
  bool IPv4Layer::isFirstFragment() const
422
3.17k
  {
423
3.17k
    return isFragment() && (getFragmentOffset() == 0);
424
3.17k
  }
425
426
  bool IPv4Layer::isLastFragment() const
427
2.91k
  {
428
2.91k
    return isFragment() && ((getFragmentFlags() & PCPP_IP_MORE_FRAGMENTS) == 0);
429
2.91k
  }
430
431
  uint8_t IPv4Layer::getFragmentFlags() const
432
1.28M
  {
433
1.28M
    return getIPv4Header()->fragmentOffset & 0xE0;
434
1.28M
  }
435
436
  uint16_t IPv4Layer::getFragmentOffset() const
437
1.27M
  {
438
1.27M
    return be16toh(getIPv4Header()->fragmentOffset & (uint16_t)0xFF1F) * 8;
439
1.27M
  }
440
441
  std::string IPv4Layer::toString() const
442
324k
  {
443
324k
    std::string fragment = "";
444
324k
    if (isFragment())
445
3.17k
    {
446
3.17k
      if (isFirstFragment())
447
258
        fragment = "First fragment";
448
2.91k
      else if (isLastFragment())
449
1.79k
        fragment = "Last fragment";
450
1.12k
      else
451
1.12k
        fragment = "Fragment";
452
453
3.17k
      std::stringstream sstm;
454
3.17k
      sstm << fragment << " [offset= " << getFragmentOffset() << "], ";
455
3.17k
      fragment = sstm.str();
456
3.17k
    }
457
458
324k
    return "IPv4 Layer, " + fragment + "Src: " + getSrcIPv4Address().toString() +
459
324k
           ", Dst: " + getDstIPv4Address().toString();
460
324k
  }
461
462
  IPv4Option IPv4Layer::getOption(IPv4OptionTypes option) const
463
0
  {
464
0
    return m_OptionReader.getTLVRecord((uint8_t)option, getOptionsBasePtr(), getHeaderLen() - sizeof(iphdr));
465
0
  }
466
467
  IPv4Option IPv4Layer::getFirstOption() const
468
0
  {
469
0
    return m_OptionReader.getFirstTLVRecord(getOptionsBasePtr(), getHeaderLen() - sizeof(iphdr));
470
0
  }
471
472
  IPv4Option IPv4Layer::getNextOption(IPv4Option& option) const
473
0
  {
474
0
    return m_OptionReader.getNextTLVRecord(option, getOptionsBasePtr(), getHeaderLen() - sizeof(iphdr));
475
0
  }
476
477
  size_t IPv4Layer::getOptionCount() const
478
0
  {
479
0
    return m_OptionReader.getTLVRecordCount(getOptionsBasePtr(), getHeaderLen() - sizeof(iphdr));
480
0
  }
481
482
  void IPv4Layer::adjustOptionsTrailer(size_t totalOptSize)
483
0
  {
484
0
    size_t ipHdrSize = sizeof(iphdr);
485
486
0
    int newNumberOfTrailingBytes = 0;
487
0
    while ((totalOptSize + newNumberOfTrailingBytes) % 4 != 0)
488
0
      newNumberOfTrailingBytes++;
489
490
0
    if (newNumberOfTrailingBytes < m_NumOfTrailingBytes)
491
0
      shortenLayer(ipHdrSize + totalOptSize, m_NumOfTrailingBytes - newNumberOfTrailingBytes);
492
0
    else if (newNumberOfTrailingBytes > m_NumOfTrailingBytes)
493
0
      extendLayer(ipHdrSize + totalOptSize, newNumberOfTrailingBytes - m_NumOfTrailingBytes);
494
495
0
    m_NumOfTrailingBytes = newNumberOfTrailingBytes;
496
497
0
    for (int i = 0; i < m_NumOfTrailingBytes; i++)
498
0
      m_Data[ipHdrSize + totalOptSize + i] = IPV4OPT_DUMMY;
499
500
0
    m_TempHeaderExtension = 0;
501
0
    getIPv4Header()->internetHeaderLength = ((ipHdrSize + totalOptSize + m_NumOfTrailingBytes) / 4 & 0x0f);
502
0
  }
503
504
  IPv4Option IPv4Layer::addOptionAt(const IPv4OptionBuilder& optionBuilder, int offset)
505
0
  {
506
0
    IPv4Option newOption = optionBuilder.build();
507
0
    if (newOption.isNull())
508
0
      return newOption;
509
510
0
    size_t sizeToExtend = newOption.getTotalSize();
511
512
0
    size_t totalOptSize = getHeaderLen() - sizeof(iphdr) - m_NumOfTrailingBytes + sizeToExtend;
513
514
0
    if (totalOptSize > IPV4_MAX_OPT_SIZE)
515
0
    {
516
0
      PCPP_LOG_ERROR("Cannot add option - adding this option will exceed IPv4 total option size which is "
517
0
                     << IPV4_MAX_OPT_SIZE);
518
0
      newOption.purgeRecordData();
519
0
      return IPv4Option(nullptr);
520
0
    }
521
522
0
    if (!extendLayer(offset, sizeToExtend))
523
0
    {
524
0
      PCPP_LOG_ERROR("Could not extend IPv4Layer in [" << sizeToExtend << "] bytes");
525
0
      newOption.purgeRecordData();
526
0
      return IPv4Option(nullptr);
527
0
    }
528
529
0
    memcpy(m_Data + offset, newOption.getRecordBasePtr(), newOption.getTotalSize());
530
531
0
    newOption.purgeRecordData();
532
533
    // setting this m_TempHeaderExtension because adjustOptionsTrailer() may extend or shorten the layer and the
534
    // extend or shorten methods need to know the accurate current size of the header. m_TempHeaderExtension will be
535
    // added to the length extracted from getIPv4Header()->internetHeaderLength as the temp new size
536
0
    m_TempHeaderExtension = sizeToExtend;
537
0
    adjustOptionsTrailer(totalOptSize);
538
    // the adjustOptionsTrailer() adds or removed the trailing bytes and sets getIPv4Header()->internetHeaderLength
539
    // to the correct size, so the m_TempHeaderExtension isn't needed anymore
540
0
    m_TempHeaderExtension = 0;
541
542
0
    m_OptionReader.changeTLVRecordCount(1);
543
544
0
    uint8_t* newOptPtr = m_Data + offset;
545
546
0
    return IPv4Option(newOptPtr);
547
0
  }
548
549
  IPv4Option IPv4Layer::addOption(const IPv4OptionBuilder& optionBuilder)
550
0
  {
551
0
    return addOptionAt(optionBuilder, getHeaderLen() - m_NumOfTrailingBytes);
552
0
  }
553
554
  IPv4Option IPv4Layer::addOptionAfter(const IPv4OptionBuilder& optionBuilder, IPv4OptionTypes prevOptionType)
555
0
  {
556
0
    int offset = 0;
557
558
0
    IPv4Option prevOpt = getOption(prevOptionType);
559
560
0
    if (prevOpt.isNull())
561
0
    {
562
0
      offset = sizeof(iphdr);
563
0
    }
564
0
    else
565
0
    {
566
0
      offset = prevOpt.getRecordBasePtr() + prevOpt.getTotalSize() - m_Data;
567
0
    }
568
569
0
    return addOptionAt(optionBuilder, offset);
570
0
  }
571
572
  bool IPv4Layer::removeOption(IPv4OptionTypes option)
573
0
  {
574
0
    IPv4Option opt = getOption(option);
575
0
    if (opt.isNull())
576
0
    {
577
0
      return false;
578
0
    }
579
580
    // calculate total option size
581
0
    IPv4Option curOpt = getFirstOption();
582
0
    size_t totalOptSize = 0;
583
0
    while (!curOpt.isNull())
584
0
    {
585
0
      totalOptSize += curOpt.getTotalSize();
586
0
      curOpt = getNextOption(curOpt);
587
0
    }
588
0
    totalOptSize -= opt.getTotalSize();
589
590
0
    int offset = opt.getRecordBasePtr() - m_Data;
591
592
0
    size_t sizeToShorten = opt.getTotalSize();
593
0
    if (!shortenLayer(offset, sizeToShorten))
594
0
    {
595
0
      PCPP_LOG_ERROR("Failed to remove IPv4 option: cannot shorten layer");
596
0
      return false;
597
0
    }
598
599
    // setting this m_TempHeaderExtension because adjustOptionsTrailer() may extend or shorten the layer and the
600
    // extend or shorten methods need to know the accurate current size of the header. m_TempHeaderExtension will be
601
    // added to the length extracted from getIPv4Header()->internetHeaderLength as the temp new size
602
0
    m_TempHeaderExtension = 0 - sizeToShorten;
603
0
    adjustOptionsTrailer(totalOptSize);
604
    // the adjustOptionsTrailer() adds or removed the trailing bytes and sets getIPv4Header()->internetHeaderLength
605
    // to the correct size, so the m_TempHeaderExtension isn't needed anymore
606
0
    m_TempHeaderExtension = 0;
607
608
0
    m_OptionReader.changeTLVRecordCount(-1);
609
610
0
    return true;
611
0
  }
612
613
  bool IPv4Layer::removeAllOptions()
614
0
  {
615
0
    int offset = sizeof(iphdr);
616
617
0
    if (!shortenLayer(offset, getHeaderLen() - offset))
618
0
      return false;
619
620
0
    getIPv4Header()->internetHeaderLength = (5 & 0xf);
621
0
    m_NumOfTrailingBytes = 0;
622
0
    m_OptionReader.changeTLVRecordCount(0 - getOptionCount());
623
0
    return true;
624
0
  }
625
626
}  // namespace pcpp