Coverage Report

Created: 2026-08-13 07:36

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/PcapPlusPlus/Packet++/src/IcmpLayer.cpp
Line
Count
Source
1
3.95k
#define LOG_MODULE PacketLogModuleIcmpLayer
2
3
#include "IcmpLayer.h"
4
#include "PayloadLayer.h"
5
#include "Packet.h"
6
#include "PacketUtils.h"
7
#include "Logger.h"
8
#include <sstream>
9
#include "EndianPortable.h"
10
11
namespace pcpp
12
{
13
14
  icmp_router_address_structure* icmp_router_advertisement::getRouterAddress(int index) const
15
0
  {
16
0
    if (index < 0 || index >= header->advertisementCount)
17
0
      return nullptr;
18
19
0
    uint8_t* headerAsByteArr = reinterpret_cast<uint8_t*>(header);
20
0
    return reinterpret_cast<icmp_router_address_structure*>(
21
0
        headerAsByteArr + sizeof(icmp_router_advertisement_hdr) + index * sizeof(icmp_router_address_structure));
22
0
  }
23
24
  void icmp_router_address_structure::setRouterAddress(IPv4Address addr, uint32_t preference)
25
571
  {
26
571
    routerAddress = addr.toInt();
27
571
    preferenceLevel = htobe32(preference);
28
571
  }
29
30
0
  IcmpLayer::IcmpLayer() : Layer()
31
0
  {
32
0
    allocData(sizeof(icmphdr));
33
0
    m_Protocol = ICMP;
34
0
  }
35
36
  IcmpMessageType IcmpLayer::getMessageType() const
37
190k
  {
38
190k
    uint8_t type = getIcmpHeader()->type;
39
190k
    if (type > 18)
40
0
      return ICMP_UNSUPPORTED;
41
42
190k
    return static_cast<IcmpMessageType>(type);
43
190k
  }
44
45
  bool IcmpLayer::cleanIcmpLayer()
46
5.49k
  {
47
    // remove all layers after
48
49
5.49k
    if (getAttachedPacket() != nullptr)
50
0
    {
51
0
      bool res = getAttachedPacket()->removeAllLayersAfter(this);
52
0
      if (!res)
53
0
        return false;
54
0
    }
55
56
    // shorten layer to size of icmphdr
57
58
5.49k
    size_t headerLen = this->getHeaderLen();
59
5.49k
    if (headerLen > sizeof(icmphdr))
60
4.79k
    {
61
4.79k
      if (!this->shortenLayer(sizeof(icmphdr), headerLen - sizeof(icmphdr)))
62
0
        return false;
63
4.79k
    }
64
65
5.49k
    return true;
66
5.49k
  }
67
68
  bool IcmpLayer::setEchoData(IcmpMessageType echoType, uint16_t id, uint16_t sequence, uint64_t timestamp,
69
                              const uint8_t* data, size_t dataLen)
70
0
  {
71
0
    if (!cleanIcmpLayer())
72
0
      return false;
73
74
0
    if (!this->extendLayer(m_DataLen, sizeof(icmp_echo_hdr) - sizeof(icmphdr) + dataLen))
75
0
      return false;
76
77
0
    getIcmpHeader()->type = static_cast<uint8_t>(echoType);
78
79
0
    icmp_echo_request* header = nullptr;
80
0
    if (echoType == ICMP_ECHO_REQUEST)
81
0
      header = getEchoRequestData();
82
0
    else if (echoType == ICMP_ECHO_REPLY)
83
0
      header = reinterpret_cast<icmp_echo_request*>(getEchoReplyData());
84
0
    else
85
0
      return false;
86
87
0
    header->header->code = 0;
88
0
    header->header->checksum = 0;
89
0
    header->header->id = htobe16(id);
90
0
    header->header->sequence = htobe16(sequence);
91
0
    header->header->timestamp = timestamp;
92
0
    if (data != nullptr && dataLen > 0)
93
0
      memcpy(header->data, data, dataLen);
94
95
0
    return true;
96
0
  }
97
98
  bool IcmpLayer::setIpAndL4Layers(IPv4Layer* ipLayer, Layer* l4Layer)
99
1.12k
  {
100
1.12k
    if (getAttachedPacket() == nullptr)
101
1.12k
    {
102
1.12k
      PCPP_LOG_ERROR("Cannot set ICMP data that involves IP and L4 layers on a layer not attached to a packet. "
103
1.12k
                     "Please add the ICMP layer to a packet and try again");
104
1.12k
      return false;
105
1.12k
    }
106
107
0
    if (ipLayer != nullptr && !getAttachedPacket()->addLayer(ipLayer))
108
0
    {
109
0
      PCPP_LOG_ERROR("Couldn't add IP layer to ICMP packet");
110
0
      return false;
111
0
    }
112
113
0
    if (l4Layer != nullptr && !getAttachedPacket()->addLayer(l4Layer))
114
0
    {
115
0
      PCPP_LOG_ERROR("Couldn't add L4 layer to ICMP packet");
116
0
      return false;
117
0
    }
118
119
0
    return true;
120
0
  }
121
122
  icmp_echo_request* IcmpLayer::getEchoRequestData()
123
0
  {
124
0
    if (!isMessageOfType(ICMP_ECHO_REQUEST))
125
0
      return nullptr;
126
127
0
    m_EchoData.header = reinterpret_cast<icmp_echo_hdr*>(m_Data);
128
0
    m_EchoData.data = reinterpret_cast<uint8_t*>(m_Data + sizeof(icmp_echo_hdr));
129
0
    m_EchoData.dataLength = m_DataLen - sizeof(icmp_echo_hdr);
130
131
0
    return &m_EchoData;
132
0
  }
133
134
  icmp_echo_request* IcmpLayer::setEchoRequestData(uint16_t id, uint16_t sequence, uint64_t timestamp,
135
                                                   const uint8_t* data, size_t dataLen)
136
0
  {
137
0
    if (setEchoData(ICMP_ECHO_REQUEST, id, sequence, timestamp, data, dataLen))
138
0
      return getEchoRequestData();
139
0
    else
140
0
      return nullptr;
141
0
  }
142
143
  icmp_echo_reply* IcmpLayer::getEchoReplyData()
144
0
  {
145
0
    if (!isMessageOfType(ICMP_ECHO_REPLY))
146
0
      return nullptr;
147
148
0
    m_EchoData.header = reinterpret_cast<icmp_echo_hdr*>(m_Data);
149
0
    m_EchoData.data = reinterpret_cast<uint8_t*>(m_Data + sizeof(icmp_echo_hdr));
150
0
    m_EchoData.dataLength = m_DataLen - sizeof(icmp_echo_hdr);
151
152
0
    return &m_EchoData;
153
0
  }
154
155
  icmp_echo_reply* IcmpLayer::setEchoReplyData(uint16_t id, uint16_t sequence, uint64_t timestamp,
156
                                               const uint8_t* data, size_t dataLen)
157
0
  {
158
0
    if (setEchoData(ICMP_ECHO_REPLY, id, sequence, timestamp, data, dataLen))
159
0
      return getEchoReplyData();
160
0
    else
161
0
      return nullptr;
162
0
  }
163
164
  icmp_timestamp_request* IcmpLayer::getTimestampRequestData()
165
0
  {
166
0
    if (!isMessageOfType(ICMP_TIMESTAMP_REQUEST))
167
0
      return nullptr;
168
169
0
    return reinterpret_cast<icmp_timestamp_request*>(m_Data);
170
0
  }
171
172
  icmp_timestamp_request* IcmpLayer::setTimestampRequestData(uint16_t id, uint16_t sequence,
173
                                                             timeval originateTimestamp)
174
0
  {
175
0
    if (!cleanIcmpLayer())
176
0
      return nullptr;
177
178
0
    if (!this->extendLayer(m_DataLen, sizeof(icmp_timestamp_request) - sizeof(icmphdr)))
179
0
      return nullptr;
180
181
0
    getIcmpHeader()->type = static_cast<uint8_t>(ICMP_TIMESTAMP_REQUEST);
182
183
0
    icmp_timestamp_request* header = getTimestampRequestData();
184
0
    header->code = 0;
185
0
    header->id = htobe16(id);
186
0
    header->sequence = htobe16(sequence);
187
0
    header->originateTimestamp = htobe32(originateTimestamp.tv_sec * 1000 + originateTimestamp.tv_usec / 1000);
188
0
    header->receiveTimestamp = 0;
189
0
    header->transmitTimestamp = 0;
190
191
0
    return header;
192
0
  }
193
194
  icmp_timestamp_reply* IcmpLayer::getTimestampReplyData()
195
2.28k
  {
196
2.28k
    if (!isMessageOfType(ICMP_TIMESTAMP_REPLY))
197
0
      return nullptr;
198
199
2.28k
    return reinterpret_cast<icmp_timestamp_reply*>(m_Data);
200
2.28k
  }
201
202
  icmp_timestamp_reply* IcmpLayer::setTimestampReplyData(uint16_t id, uint16_t sequence, timeval originateTimestamp,
203
                                                         timeval receiveTimestamp, timeval transmitTimestamp)
204
1.14k
  {
205
1.14k
    if (!cleanIcmpLayer())
206
0
      return nullptr;
207
208
1.14k
    if (!this->extendLayer(m_DataLen, sizeof(icmp_timestamp_reply) - sizeof(icmphdr)))
209
0
      return nullptr;
210
211
1.14k
    getIcmpHeader()->type = static_cast<uint8_t>(ICMP_TIMESTAMP_REPLY);
212
213
1.14k
    icmp_timestamp_reply* header = getTimestampReplyData();
214
1.14k
    header->code = 0;
215
1.14k
    header->id = htobe16(id);
216
1.14k
    header->sequence = htobe16(sequence);
217
1.14k
    header->originateTimestamp = htobe32(originateTimestamp.tv_sec * 1000 + originateTimestamp.tv_usec / 1000);
218
1.14k
    header->receiveTimestamp = htobe32(receiveTimestamp.tv_sec * 1000 + receiveTimestamp.tv_usec / 1000);
219
1.14k
    header->transmitTimestamp = htobe32(transmitTimestamp.tv_sec * 1000 + transmitTimestamp.tv_usec / 1000);
220
221
1.14k
    return header;
222
1.14k
  }
223
224
  icmp_destination_unreachable* IcmpLayer::getDestUnreachableData()
225
1.07k
  {
226
1.07k
    if (!isMessageOfType(ICMP_DEST_UNREACHABLE))
227
0
      return nullptr;
228
229
1.07k
    return reinterpret_cast<icmp_destination_unreachable*>(m_Data);
230
1.07k
  }
231
232
  icmp_destination_unreachable* IcmpLayer::setDestUnreachableData(IcmpDestUnreachableCodes code, uint16_t nextHopMTU,
233
                                                                  IPv4Layer* ipHeader, Layer* l4Header)
234
538
  {
235
538
    if (!cleanIcmpLayer())
236
0
      return nullptr;
237
238
538
    if (!this->extendLayer(m_DataLen, sizeof(icmp_destination_unreachable) - sizeof(icmphdr)))
239
0
      return nullptr;
240
241
538
    getIcmpHeader()->type = static_cast<uint8_t>(ICMP_DEST_UNREACHABLE);
242
243
538
    icmp_destination_unreachable* header = getDestUnreachableData();
244
538
    header->code = code;
245
538
    header->nextHopMTU = htobe16(nextHopMTU);
246
538
    header->unused = 0;
247
248
538
    if (!setIpAndL4Layers(ipHeader, l4Header))
249
538
      return nullptr;
250
251
0
    return header;
252
538
  }
253
254
  icmp_source_quench* IcmpLayer::getSourceQuenchdata()
255
0
  {
256
0
    if (!isMessageOfType(ICMP_SOURCE_QUENCH))
257
0
      return nullptr;
258
259
0
    return reinterpret_cast<icmp_source_quench*>(m_Data);
260
0
  }
261
262
  icmp_source_quench* IcmpLayer::setSourceQuenchdata(IPv4Layer* ipHeader, Layer* l4Header)
263
0
  {
264
0
    if (!cleanIcmpLayer())
265
0
      return nullptr;
266
267
0
    if (!this->extendLayer(m_DataLen, sizeof(icmp_source_quench) - sizeof(icmphdr)))
268
0
      return nullptr;
269
270
0
    getIcmpHeader()->type = static_cast<uint8_t>(ICMP_SOURCE_QUENCH);
271
272
0
    icmp_source_quench* header = getSourceQuenchdata();
273
0
    header->unused = 0;
274
275
0
    if (!setIpAndL4Layers(ipHeader, l4Header))
276
0
      return nullptr;
277
278
0
    return header;
279
0
  }
280
281
  icmp_redirect* IcmpLayer::getRedirectData()
282
0
  {
283
0
    if (!isMessageOfType(ICMP_REDIRECT))
284
0
      return nullptr;
285
286
0
    return reinterpret_cast<icmp_redirect*>(m_Data);
287
0
  }
288
289
  icmp_redirect* IcmpLayer::setRedirectData(uint8_t code, IPv4Address gatewayAddress, IPv4Layer* ipHeader,
290
                                            Layer* l4Header)
291
0
  {
292
0
    if (code > 3)
293
0
    {
294
0
      PCPP_LOG_ERROR("Unknown code " << (int)code << " for ICMP redirect data");
295
0
      return nullptr;
296
0
    }
297
298
0
    if (!cleanIcmpLayer())
299
0
      return nullptr;
300
301
0
    if (!this->extendLayer(m_DataLen, sizeof(icmp_redirect) - sizeof(icmphdr)))
302
0
      return nullptr;
303
304
0
    getIcmpHeader()->type = static_cast<uint8_t>(ICMP_REDIRECT);
305
306
0
    icmp_redirect* header = getRedirectData();
307
0
    header->code = code;
308
0
    header->gatewayAddress = gatewayAddress.toInt();
309
310
0
    if (!setIpAndL4Layers(ipHeader, l4Header))
311
0
      return nullptr;
312
313
0
    return header;
314
0
  }
315
316
  icmp_router_advertisement* IcmpLayer::getRouterAdvertisementData() const
317
6.31k
  {
318
6.31k
    if (!isMessageOfType(ICMP_ROUTER_ADV))
319
0
      return nullptr;
320
321
6.31k
    m_RouterAdvData.header = reinterpret_cast<icmp_router_advertisement_hdr*>(m_Data);
322
323
6.31k
    return &m_RouterAdvData;
324
6.31k
  }
325
326
  icmp_router_advertisement* IcmpLayer::setRouterAdvertisementData(
327
      uint8_t code, uint16_t lifetimeInSeconds, const std::vector<icmp_router_address_structure>& routerAddresses)
328
571
  {
329
571
    if (code != 0 && code != 16)
330
0
    {
331
0
      PCPP_LOG_ERROR("Unknown code " << (int)code
332
0
                                     << " for ICMP router advertisement data (only codes 0 and 16 are legal)");
333
0
      return nullptr;
334
0
    }
335
336
571
    if (!cleanIcmpLayer())
337
0
      return nullptr;
338
339
571
    if (!this->extendLayer(m_DataLen, sizeof(icmp_router_advertisement_hdr) +
340
571
                                          (routerAddresses.size() * sizeof(icmp_router_address_structure)) -
341
571
                                          sizeof(icmphdr)))
342
0
      return nullptr;
343
344
571
    getIcmpHeader()->type = static_cast<uint8_t>(ICMP_ROUTER_ADV);
345
346
571
    icmp_router_advertisement* header = getRouterAdvertisementData();
347
571
    header->header->code = code;
348
571
    header->header->lifetime = htobe16(lifetimeInSeconds);
349
571
    header->header->advertisementCount = static_cast<uint8_t>(routerAddresses.size());
350
571
    header->header->addressEntrySize = 2;
351
352
571
    icmp_router_address_structure* curPos = reinterpret_cast<icmp_router_address_structure*>(
353
571
        reinterpret_cast<uint8_t*>(header->header) + sizeof(icmp_router_advertisement_hdr));
354
571
    for (const auto& iter : routerAddresses)
355
571
    {
356
571
      curPos->routerAddress = iter.routerAddress;
357
571
      curPos->preferenceLevel = iter.preferenceLevel;
358
571
      curPos += 1;
359
571
    }
360
361
571
    return header;
362
571
  }
363
364
  icmp_router_solicitation* IcmpLayer::getRouterSolicitationData()
365
0
  {
366
0
    if (!isMessageOfType(ICMP_ROUTER_SOL))
367
0
      return nullptr;
368
369
0
    return reinterpret_cast<icmp_router_solicitation*>(m_Data);
370
0
  }
371
372
  icmp_router_solicitation* IcmpLayer::setRouterSolicitationData()
373
0
  {
374
0
    if (!cleanIcmpLayer())
375
0
      return nullptr;
376
377
0
    getIcmpHeader()->type = static_cast<uint8_t>(ICMP_ROUTER_SOL);
378
379
0
    icmp_router_solicitation* header = getRouterSolicitationData();
380
0
    header->code = 0;
381
382
0
    return header;
383
0
  }
384
385
  icmp_time_exceeded* IcmpLayer::getTimeExceededData()
386
1.00k
  {
387
1.00k
    if (!isMessageOfType(ICMP_TIME_EXCEEDED))
388
0
      return nullptr;
389
390
1.00k
    return reinterpret_cast<icmp_time_exceeded*>(m_Data);
391
1.00k
  }
392
393
  icmp_time_exceeded* IcmpLayer::setTimeExceededData(uint8_t code, IPv4Layer* ipHeader, Layer* l4Header)
394
500
  {
395
500
    if (code > 1)
396
0
    {
397
0
      PCPP_LOG_ERROR("Unknown code " << (int)code << " for ICMP time exceeded data");
398
0
      return nullptr;
399
0
    }
400
401
500
    if (!cleanIcmpLayer())
402
0
      return nullptr;
403
404
500
    if (!this->extendLayer(m_DataLen, sizeof(icmp_time_exceeded) - sizeof(icmphdr)))
405
0
      return nullptr;
406
407
500
    getIcmpHeader()->type = static_cast<uint8_t>(ICMP_TIME_EXCEEDED);
408
409
500
    icmp_time_exceeded* header = getTimeExceededData();
410
500
    header->code = code;
411
500
    header->unused = 0;
412
413
500
    if (!setIpAndL4Layers(ipHeader, l4Header))
414
500
      return nullptr;
415
416
0
    return header;
417
500
  }
418
419
  icmp_param_problem* IcmpLayer::getParamProblemData()
420
1.02k
  {
421
1.02k
    if (!isMessageOfType(ICMP_PARAM_PROBLEM))
422
0
      return nullptr;
423
424
1.02k
    return reinterpret_cast<icmp_param_problem*>(m_Data);
425
1.02k
  }
426
427
  icmp_param_problem* IcmpLayer::setParamProblemData(uint8_t code, uint8_t errorOctetPointer, IPv4Layer* ipHeader,
428
                                                     Layer* l4Header)
429
939
  {
430
939
    if (code > 2)
431
854
    {
432
854
      PCPP_LOG_ERROR("Unknown code " << (int)code << " for ICMP parameter problem data");
433
854
      return nullptr;
434
854
    }
435
436
85
    if (!cleanIcmpLayer())
437
0
      return nullptr;
438
439
85
    if (!this->extendLayer(m_DataLen, sizeof(icmp_param_problem) - sizeof(icmphdr)))
440
0
      return nullptr;
441
442
85
    getIcmpHeader()->type = static_cast<uint8_t>(ICMP_PARAM_PROBLEM);
443
444
85
    icmp_param_problem* header = getParamProblemData();
445
85
    header->code = code;
446
85
    header->unused1 = 0;
447
85
    header->unused2 = 0;
448
85
    header->pointer = errorOctetPointer;
449
450
85
    if (!setIpAndL4Layers(ipHeader, l4Header))
451
85
      return nullptr;
452
453
0
    return header;
454
85
  }
455
456
  icmp_address_mask_request* IcmpLayer::getAddressMaskRequestData()
457
1.75k
  {
458
1.75k
    if (!isMessageOfType(ICMP_ADDRESS_MASK_REQUEST))
459
0
      return nullptr;
460
461
1.75k
    return reinterpret_cast<icmp_address_mask_request*>(m_Data);
462
1.75k
  }
463
464
  icmp_address_mask_request* IcmpLayer::setAddressMaskRequestData(uint16_t id, uint16_t sequence, IPv4Address mask)
465
878
  {
466
878
    if (!cleanIcmpLayer())
467
0
      return nullptr;
468
469
878
    if (!this->extendLayer(m_DataLen, sizeof(icmp_address_mask_request) - sizeof(icmphdr)))
470
0
      return nullptr;
471
472
878
    getIcmpHeader()->type = static_cast<uint8_t>(ICMP_ADDRESS_MASK_REQUEST);
473
474
878
    icmp_address_mask_request* header = getAddressMaskRequestData();
475
878
    header->code = 0;
476
878
    header->id = htobe16(id);
477
878
    header->sequence = htobe16(sequence);
478
878
    header->addressMask = mask.toInt();
479
480
878
    return header;
481
878
  }
482
483
  icmp_address_mask_reply* IcmpLayer::getAddressMaskReplyData()
484
2.16k
  {
485
2.16k
    if (!isMessageOfType(ICMP_ADDRESS_MASK_REPLY))
486
0
      return nullptr;
487
488
2.16k
    return reinterpret_cast<icmp_address_mask_reply*>(m_Data);
489
2.16k
  }
490
491
  icmp_address_mask_reply* IcmpLayer::setAddressMaskReplyData(uint16_t id, uint16_t sequence, IPv4Address mask)
492
1.08k
  {
493
1.08k
    if (!cleanIcmpLayer())
494
0
      return nullptr;
495
496
1.08k
    if (!this->extendLayer(m_DataLen, sizeof(icmp_address_mask_reply) - sizeof(icmphdr)))
497
0
      return nullptr;
498
499
1.08k
    getIcmpHeader()->type = static_cast<uint8_t>(ICMP_ADDRESS_MASK_REPLY);
500
501
1.08k
    icmp_address_mask_reply* header = getAddressMaskReplyData();
502
1.08k
    header->code = 0;
503
1.08k
    header->id = htobe16(id);
504
1.08k
    header->sequence = htobe16(sequence);
505
1.08k
    header->addressMask = htobe32(mask.toInt());
506
507
1.08k
    return header;
508
1.08k
  }
509
510
  icmp_info_request* IcmpLayer::getInfoRequestData()
511
660
  {
512
660
    if (!isMessageOfType(ICMP_INFO_REQUEST))
513
0
      return nullptr;
514
515
660
    return reinterpret_cast<icmp_info_request*>(m_Data);
516
660
  }
517
518
  icmp_info_request* IcmpLayer::setInfoRequestData(uint16_t id, uint16_t sequence)
519
330
  {
520
330
    if (!cleanIcmpLayer())
521
0
      return nullptr;
522
523
330
    if (!this->extendLayer(m_DataLen, sizeof(icmp_info_request) - sizeof(icmphdr)))
524
0
      return nullptr;
525
526
330
    getIcmpHeader()->type = static_cast<uint8_t>(ICMP_INFO_REQUEST);
527
528
330
    icmp_info_request* header = getInfoRequestData();
529
330
    header->code = 0;
530
330
    header->id = htobe16(id);
531
330
    header->sequence = htobe16(sequence);
532
533
330
    return header;
534
330
  }
535
536
  icmp_info_reply* IcmpLayer::getInfoReplyData()
537
740
  {
538
740
    if (!isMessageOfType(ICMP_INFO_REPLY))
539
0
      return nullptr;
540
541
740
    return reinterpret_cast<icmp_info_reply*>(m_Data);
542
740
  }
543
544
  icmp_info_reply* IcmpLayer::setInfoReplyData(uint16_t id, uint16_t sequence)
545
370
  {
546
370
    if (!cleanIcmpLayer())
547
0
      return nullptr;
548
549
370
    if (!this->extendLayer(m_DataLen, sizeof(icmp_info_reply) - sizeof(icmphdr)))
550
0
      return nullptr;
551
552
370
    getIcmpHeader()->type = static_cast<uint8_t>(ICMP_INFO_REPLY);
553
554
370
    icmp_info_reply* header = getInfoReplyData();
555
370
    header->code = 0;
556
370
    header->id = htobe16(id);
557
370
    header->sequence = htobe16(sequence);
558
559
370
    return header;
560
370
  }
561
562
  void IcmpLayer::parseNextLayer()
563
43.0k
  {
564
43.0k
    size_t headerLen = getHeaderLen();
565
566
43.0k
    auto payloadPtr = m_Data + headerLen;
567
43.0k
    auto payloadLen = m_DataLen - headerLen;
568
569
43.0k
    switch (getMessageType())
570
43.0k
    {
571
3.02k
    case ICMP_DEST_UNREACHABLE:
572
5.19k
    case ICMP_SOURCE_QUENCH:
573
8.18k
    case ICMP_TIME_EXCEEDED:
574
9.87k
    case ICMP_REDIRECT:
575
15.5k
    case ICMP_PARAM_PROBLEM:
576
15.5k
    {
577
15.5k
      tryConstructNextLayerWithFallback<IPv4Layer, PayloadLayer>(payloadPtr, payloadLen);
578
15.5k
      break;
579
9.87k
    }
580
27.4k
    default:
581
27.4k
      if (m_DataLen > headerLen)
582
22.5k
      {
583
22.5k
        constructNextLayer<PayloadLayer>(payloadPtr, payloadLen);
584
22.5k
      }
585
27.4k
      break;
586
43.0k
    }
587
43.0k
  }
588
589
  size_t IcmpLayer::getHeaderLen() const
590
72.3k
  {
591
72.3k
    IcmpMessageType type = getMessageType();
592
72.3k
    size_t routerAdvSize = 0;
593
72.3k
    switch (type)
594
72.3k
    {
595
299
    case ICMP_ECHO_REQUEST:
596
3.87k
    case ICMP_ECHO_REPLY:
597
3.87k
      return m_DataLen;
598
208
    case ICMP_TIMESTAMP_REQUEST:
599
10.4k
    case ICMP_TIMESTAMP_REPLY:
600
10.4k
      return sizeof(icmp_timestamp_request);
601
3.27k
    case ICMP_ROUTER_SOL:
602
6.55k
    case ICMP_INFO_REQUEST:
603
10.6k
    case ICMP_INFO_REPLY:
604
10.6k
    case ICMP_UNSUPPORTED:
605
10.6k
      return sizeof(icmphdr);
606
9.74k
    case ICMP_ADDRESS_MASK_REPLY:
607
17.6k
    case ICMP_ADDRESS_MASK_REQUEST:
608
17.6k
      return sizeof(icmp_address_mask_request);
609
5.17k
    case ICMP_DEST_UNREACHABLE:
610
5.17k
      return sizeof(icmp_destination_unreachable);
611
2.54k
    case ICMP_REDIRECT:
612
2.54k
      return sizeof(icmp_redirect);
613
4.99k
    case ICMP_TIME_EXCEEDED:
614
8.23k
    case ICMP_SOURCE_QUENCH:
615
8.23k
      return sizeof(icmp_time_exceeded);
616
8.56k
    case ICMP_PARAM_PROBLEM:
617
8.56k
      return sizeof(icmp_param_problem);
618
5.17k
    case ICMP_ROUTER_ADV:
619
      // clang-format off
620
5.17k
      routerAdvSize = sizeof(icmp_router_advertisement_hdr) + (getRouterAdvertisementData()->header->advertisementCount * sizeof(icmp_router_address_structure));
621
      // clang-format on
622
5.17k
      if (routerAdvSize > m_DataLen)
623
45
        return m_DataLen;
624
5.12k
      return routerAdvSize;
625
0
    default:
626
0
      return sizeof(icmphdr);
627
72.3k
    }
628
72.3k
  }
629
630
  void IcmpLayer::computeCalculateFields()
631
7.93k
  {
632
    // calculate checksum
633
7.93k
    getIcmpHeader()->checksum = 0;
634
635
7.93k
    size_t icmpLen = 0;
636
7.93k
    Layer* curLayer = this;
637
26.6k
    while (curLayer != nullptr)
638
18.7k
    {
639
18.7k
      icmpLen += curLayer->getHeaderLen();
640
18.7k
      curLayer = curLayer->getNextLayer();
641
18.7k
    }
642
643
7.93k
    ScalarBuffer<uint16_t> buffer;
644
7.93k
    buffer.buffer = reinterpret_cast<uint16_t*>(getIcmpHeader());
645
7.93k
    buffer.len = icmpLen;
646
7.93k
    size_t checksum = computeChecksum(&buffer, 1);
647
648
7.93k
    getIcmpHeader()->checksum = htobe16(checksum);
649
7.93k
  }
650
651
  std::string IcmpLayer::toString() const
652
15.8k
  {
653
15.8k
    std::string messageTypeAsString;
654
15.8k
    IcmpMessageType type = getMessageType();
655
15.8k
    switch (type)
656
15.8k
    {
657
1.02k
    case ICMP_ECHO_REPLY:
658
1.02k
      messageTypeAsString = "Echo (ping) reply";
659
1.02k
      break;
660
1.07k
    case ICMP_DEST_UNREACHABLE:
661
1.07k
      messageTypeAsString = "Destination unreachable";
662
1.07k
      break;
663
722
    case ICMP_SOURCE_QUENCH:
664
722
      messageTypeAsString = "Source quench (flow control)";
665
722
      break;
666
566
    case ICMP_REDIRECT:
667
566
      messageTypeAsString = "Redirect";
668
566
      break;
669
78
    case ICMP_ECHO_REQUEST:
670
78
      messageTypeAsString = "Echo (ping) request";
671
78
      break;
672
1.14k
    case ICMP_ROUTER_ADV:
673
1.14k
      messageTypeAsString = "Router advertisement";
674
1.14k
      break;
675
728
    case ICMP_ROUTER_SOL:
676
728
      messageTypeAsString = "Router solicitation";
677
728
      break;
678
1.00k
    case ICMP_TIME_EXCEEDED:
679
1.00k
      messageTypeAsString = "Time-to-live exceeded";
680
1.00k
      break;
681
1.87k
    case ICMP_PARAM_PROBLEM:
682
1.87k
      messageTypeAsString = "Parameter problem: bad IP header";
683
1.87k
      break;
684
52
    case ICMP_TIMESTAMP_REQUEST:
685
52
      messageTypeAsString = "Timestamp request";
686
52
      break;
687
2.28k
    case ICMP_TIMESTAMP_REPLY:
688
2.28k
      messageTypeAsString = "Timestamp reply";
689
2.28k
      break;
690
660
    case ICMP_INFO_REQUEST:
691
660
      messageTypeAsString = "Information request";
692
660
      break;
693
740
    case ICMP_INFO_REPLY:
694
740
      messageTypeAsString = "Information reply";
695
740
      break;
696
1.75k
    case ICMP_ADDRESS_MASK_REQUEST:
697
1.75k
      messageTypeAsString = "Address mask request";
698
1.75k
      break;
699
2.16k
    case ICMP_ADDRESS_MASK_REPLY:
700
2.16k
      messageTypeAsString = "Address mask reply";
701
2.16k
      break;
702
0
    default:
703
0
      messageTypeAsString = "Unknown";
704
0
      break;
705
15.8k
    }
706
707
15.8k
    std::ostringstream typeStream;
708
15.8k
    typeStream << (int)getIcmpHeader()->type;
709
710
15.8k
    return "ICMP Layer, " + messageTypeAsString + " (type: " + typeStream.str() + ")";
711
15.8k
  }
712
713
}  // namespace pcpp