Coverage Report

Created: 2026-03-31 07:53

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