Coverage Report

Created: 2026-06-30 07:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/PcapPlusPlus/Packet++/src/IcmpLayer.cpp
Line
Count
Source
1
4.61k
#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
622
  {
26
622
    routerAddress = addr.toInt();
27
622
    preferenceLevel = htobe32(preference);
28
622
  }
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
234k
  {
40
234k
    uint8_t type = getIcmpHeader()->type;
41
234k
    if (type > 18)
42
0
      return ICMP_UNSUPPORTED;
43
44
234k
    return static_cast<IcmpMessageType>(type);
45
234k
  }
46
47
  bool IcmpLayer::cleanIcmpLayer()
48
5.96k
  {
49
    // remove all layers after
50
51
5.96k
    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.96k
    size_t headerLen = this->getHeaderLen();
61
5.96k
    if (headerLen > sizeof(icmphdr))
62
5.26k
    {
63
5.26k
      if (!this->shortenLayer(sizeof(icmphdr), headerLen - sizeof(icmphdr)))
64
0
        return false;
65
5.26k
    }
66
67
5.96k
    return true;
68
5.96k
  }
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.69k
  {
102
1.69k
    if (getAttachedPacket() == nullptr)
103
1.69k
    {
104
1.69k
      PCPP_LOG_ERROR("Cannot set ICMP data that involves IP and L4 layers on a layer not attached to a packet. "
105
1.69k
                     "Please add the ICMP layer to a packet and try again");
106
1.69k
      return false;
107
1.69k
    }
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
1.97k
  {
198
1.97k
    if (!isMessageOfType(ICMP_TIMESTAMP_REPLY))
199
0
      return nullptr;
200
201
1.97k
    return reinterpret_cast<icmp_timestamp_reply*>(m_Data);
202
1.97k
  }
203
204
  icmp_timestamp_reply* IcmpLayer::setTimestampReplyData(uint16_t id, uint16_t sequence, timeval originateTimestamp,
205
                                                         timeval receiveTimestamp, timeval transmitTimestamp)
206
988
  {
207
988
    if (!cleanIcmpLayer())
208
0
      return nullptr;
209
210
988
    if (!this->extendLayer(m_DataLen, sizeof(icmp_timestamp_reply) - sizeof(icmphdr)))
211
0
      return nullptr;
212
213
988
    getIcmpHeader()->type = static_cast<uint8_t>(ICMP_TIMESTAMP_REPLY);
214
215
988
    icmp_timestamp_reply* header = getTimestampReplyData();
216
988
    header->code = 0;
217
988
    header->id = htobe16(id);
218
988
    header->sequence = htobe16(sequence);
219
988
    header->originateTimestamp = htobe32(originateTimestamp.tv_sec * 1000 + originateTimestamp.tv_usec / 1000);
220
988
    header->receiveTimestamp = htobe32(receiveTimestamp.tv_sec * 1000 + receiveTimestamp.tv_usec / 1000);
221
988
    header->transmitTimestamp = htobe32(transmitTimestamp.tv_sec * 1000 + transmitTimestamp.tv_usec / 1000);
222
223
988
    return header;
224
988
  }
225
226
  icmp_destination_unreachable* IcmpLayer::getDestUnreachableData()
227
1.87k
  {
228
1.87k
    if (!isMessageOfType(ICMP_DEST_UNREACHABLE))
229
0
      return nullptr;
230
231
1.87k
    return reinterpret_cast<icmp_destination_unreachable*>(m_Data);
232
1.87k
  }
233
234
  icmp_destination_unreachable* IcmpLayer::setDestUnreachableData(IcmpDestUnreachableCodes code, uint16_t nextHopMTU,
235
                                                                  IPv4Layer* ipHeader, Layer* l4Header)
236
939
  {
237
939
    if (!cleanIcmpLayer())
238
0
      return nullptr;
239
240
939
    if (!this->extendLayer(m_DataLen, sizeof(icmp_destination_unreachable) - sizeof(icmphdr)))
241
0
      return nullptr;
242
243
939
    getIcmpHeader()->type = static_cast<uint8_t>(ICMP_DEST_UNREACHABLE);
244
245
939
    icmp_destination_unreachable* header = getDestUnreachableData();
246
939
    header->code = code;
247
939
    header->nextHopMTU = htobe16(nextHopMTU);
248
939
    header->unused = 0;
249
250
939
    if (!setIpAndL4Layers(ipHeader, l4Header))
251
939
      return nullptr;
252
253
0
    return header;
254
939
  }
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
6.87k
  {
320
6.87k
    if (!isMessageOfType(ICMP_ROUTER_ADV))
321
0
      return nullptr;
322
323
6.87k
    m_RouterAdvData.header = reinterpret_cast<icmp_router_advertisement_hdr*>(m_Data);
324
325
6.87k
    return &m_RouterAdvData;
326
6.87k
  }
327
328
  icmp_router_advertisement* IcmpLayer::setRouterAdvertisementData(
329
      uint8_t code, uint16_t lifetimeInSeconds, const std::vector<icmp_router_address_structure>& routerAddresses)
330
622
  {
331
622
    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
622
    if (!cleanIcmpLayer())
339
0
      return nullptr;
340
341
622
    if (!this->extendLayer(m_DataLen, sizeof(icmp_router_advertisement_hdr) +
342
622
                                          (routerAddresses.size() * sizeof(icmp_router_address_structure)) -
343
622
                                          sizeof(icmphdr)))
344
0
      return nullptr;
345
346
622
    getIcmpHeader()->type = static_cast<uint8_t>(ICMP_ROUTER_ADV);
347
348
622
    icmp_router_advertisement* header = getRouterAdvertisementData();
349
622
    header->header->code = code;
350
622
    header->header->lifetime = htobe16(lifetimeInSeconds);
351
622
    header->header->advertisementCount = static_cast<uint8_t>(routerAddresses.size());
352
622
    header->header->addressEntrySize = 2;
353
354
622
    icmp_router_address_structure* curPos = reinterpret_cast<icmp_router_address_structure*>(
355
622
        reinterpret_cast<uint8_t*>(header->header) + sizeof(icmp_router_advertisement_hdr));
356
622
    for (const auto& iter : routerAddresses)
357
622
    {
358
622
      curPos->routerAddress = iter.routerAddress;
359
622
      curPos->preferenceLevel = iter.preferenceLevel;
360
622
      curPos += 1;
361
622
    }
362
363
622
    return header;
364
622
  }
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.20k
  {
389
1.20k
    if (!isMessageOfType(ICMP_TIME_EXCEEDED))
390
0
      return nullptr;
391
392
1.20k
    return reinterpret_cast<icmp_time_exceeded*>(m_Data);
393
1.20k
  }
394
395
  icmp_time_exceeded* IcmpLayer::setTimeExceededData(uint8_t code, IPv4Layer* ipHeader, Layer* l4Header)
396
602
  {
397
602
    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
602
    if (!cleanIcmpLayer())
404
0
      return nullptr;
405
406
602
    if (!this->extendLayer(m_DataLen, sizeof(icmp_time_exceeded) - sizeof(icmphdr)))
407
0
      return nullptr;
408
409
602
    getIcmpHeader()->type = static_cast<uint8_t>(ICMP_TIME_EXCEEDED);
410
411
602
    icmp_time_exceeded* header = getTimeExceededData();
412
602
    header->code = code;
413
602
    header->unused = 0;
414
415
602
    if (!setIpAndL4Layers(ipHeader, l4Header))
416
602
      return nullptr;
417
418
0
    return header;
419
602
  }
420
421
  icmp_param_problem* IcmpLayer::getParamProblemData()
422
914
  {
423
914
    if (!isMessageOfType(ICMP_PARAM_PROBLEM))
424
0
      return nullptr;
425
426
914
    return reinterpret_cast<icmp_param_problem*>(m_Data);
427
914
  }
428
429
  icmp_param_problem* IcmpLayer::setParamProblemData(uint8_t code, uint8_t errorOctetPointer, IPv4Layer* ipHeader,
430
                                                     Layer* l4Header)
431
765
  {
432
765
    if (code > 2)
433
616
    {
434
616
      PCPP_LOG_ERROR("Unknown code " << (int)code << " for ICMP parameter problem data");
435
616
      return nullptr;
436
616
    }
437
438
149
    if (!cleanIcmpLayer())
439
0
      return nullptr;
440
441
149
    if (!this->extendLayer(m_DataLen, sizeof(icmp_param_problem) - sizeof(icmphdr)))
442
0
      return nullptr;
443
444
149
    getIcmpHeader()->type = static_cast<uint8_t>(ICMP_PARAM_PROBLEM);
445
446
149
    icmp_param_problem* header = getParamProblemData();
447
149
    header->code = code;
448
149
    header->unused1 = 0;
449
149
    header->unused2 = 0;
450
149
    header->pointer = errorOctetPointer;
451
452
149
    if (!setIpAndL4Layers(ipHeader, l4Header))
453
149
      return nullptr;
454
455
0
    return header;
456
149
  }
457
458
  icmp_address_mask_request* IcmpLayer::getAddressMaskRequestData()
459
1.45k
  {
460
1.45k
    if (!isMessageOfType(ICMP_ADDRESS_MASK_REQUEST))
461
0
      return nullptr;
462
463
1.45k
    return reinterpret_cast<icmp_address_mask_request*>(m_Data);
464
1.45k
  }
465
466
  icmp_address_mask_request* IcmpLayer::setAddressMaskRequestData(uint16_t id, uint16_t sequence, IPv4Address mask)
467
725
  {
468
725
    if (!cleanIcmpLayer())
469
0
      return nullptr;
470
471
725
    if (!this->extendLayer(m_DataLen, sizeof(icmp_address_mask_request) - sizeof(icmphdr)))
472
0
      return nullptr;
473
474
725
    getIcmpHeader()->type = static_cast<uint8_t>(ICMP_ADDRESS_MASK_REQUEST);
475
476
725
    icmp_address_mask_request* header = getAddressMaskRequestData();
477
725
    header->code = 0;
478
725
    header->id = htobe16(id);
479
725
    header->sequence = htobe16(sequence);
480
725
    header->addressMask = mask.toInt();
481
482
725
    return header;
483
725
  }
484
485
  icmp_address_mask_reply* IcmpLayer::getAddressMaskReplyData()
486
2.48k
  {
487
2.48k
    if (!isMessageOfType(ICMP_ADDRESS_MASK_REPLY))
488
0
      return nullptr;
489
490
2.48k
    return reinterpret_cast<icmp_address_mask_reply*>(m_Data);
491
2.48k
  }
492
493
  icmp_address_mask_reply* IcmpLayer::setAddressMaskReplyData(uint16_t id, uint16_t sequence, IPv4Address mask)
494
1.24k
  {
495
1.24k
    if (!cleanIcmpLayer())
496
0
      return nullptr;
497
498
1.24k
    if (!this->extendLayer(m_DataLen, sizeof(icmp_address_mask_reply) - sizeof(icmphdr)))
499
0
      return nullptr;
500
501
1.24k
    getIcmpHeader()->type = static_cast<uint8_t>(ICMP_ADDRESS_MASK_REPLY);
502
503
1.24k
    icmp_address_mask_reply* header = getAddressMaskReplyData();
504
1.24k
    header->code = 0;
505
1.24k
    header->id = htobe16(id);
506
1.24k
    header->sequence = htobe16(sequence);
507
1.24k
    header->addressMask = htobe32(mask.toInt());
508
509
1.24k
    return header;
510
1.24k
  }
511
512
  icmp_info_request* IcmpLayer::getInfoRequestData()
513
660
  {
514
660
    if (!isMessageOfType(ICMP_INFO_REQUEST))
515
0
      return nullptr;
516
517
660
    return reinterpret_cast<icmp_info_request*>(m_Data);
518
660
  }
519
520
  icmp_info_request* IcmpLayer::setInfoRequestData(uint16_t id, uint16_t sequence)
521
330
  {
522
330
    if (!cleanIcmpLayer())
523
0
      return nullptr;
524
525
330
    if (!this->extendLayer(m_DataLen, sizeof(icmp_info_request) - sizeof(icmphdr)))
526
0
      return nullptr;
527
528
330
    getIcmpHeader()->type = static_cast<uint8_t>(ICMP_INFO_REQUEST);
529
530
330
    icmp_info_request* header = getInfoRequestData();
531
330
    header->code = 0;
532
330
    header->id = htobe16(id);
533
330
    header->sequence = htobe16(sequence);
534
535
330
    return header;
536
330
  }
537
538
  icmp_info_reply* IcmpLayer::getInfoReplyData()
539
740
  {
540
740
    if (!isMessageOfType(ICMP_INFO_REPLY))
541
0
      return nullptr;
542
543
740
    return reinterpret_cast<icmp_info_reply*>(m_Data);
544
740
  }
545
546
  icmp_info_reply* IcmpLayer::setInfoReplyData(uint16_t id, uint16_t sequence)
547
370
  {
548
370
    if (!cleanIcmpLayer())
549
0
      return nullptr;
550
551
370
    if (!this->extendLayer(m_DataLen, sizeof(icmp_info_reply) - sizeof(icmphdr)))
552
0
      return nullptr;
553
554
370
    getIcmpHeader()->type = static_cast<uint8_t>(ICMP_INFO_REPLY);
555
556
370
    icmp_info_reply* header = getInfoReplyData();
557
370
    header->code = 0;
558
370
    header->id = htobe16(id);
559
370
    header->sequence = htobe16(sequence);
560
561
370
    return header;
562
370
  }
563
564
  void IcmpLayer::parseNextLayer()
565
53.3k
  {
566
53.3k
    size_t headerLen = getHeaderLen();
567
568
53.3k
    auto payloadPtr = m_Data + headerLen;
569
53.3k
    auto payloadLen = m_DataLen - headerLen;
570
571
53.3k
    switch (getMessageType())
572
53.3k
    {
573
6.30k
    case ICMP_DEST_UNREACHABLE:
574
8.49k
    case ICMP_SOURCE_QUENCH:
575
12.1k
    case ICMP_TIME_EXCEEDED:
576
13.7k
    case ICMP_REDIRECT:
577
18.2k
    case ICMP_PARAM_PROBLEM:
578
18.2k
    {
579
18.2k
      tryConstructNextLayerWithFallback<IPv4Layer, PayloadLayer>(payloadPtr, payloadLen);
580
18.2k
      break;
581
13.7k
    }
582
35.0k
    default:
583
35.0k
      if (m_DataLen > headerLen)
584
22.0k
      {
585
22.0k
        constructNextLayer<PayloadLayer>(payloadPtr, payloadLen);
586
22.0k
      }
587
35.0k
      break;
588
53.3k
    }
589
53.3k
  }
590
591
  size_t IcmpLayer::getHeaderLen() const
592
87.8k
  {
593
87.8k
    IcmpMessageType type = getMessageType();
594
87.8k
    size_t routerAdvSize = 0;
595
87.8k
    switch (type)
596
87.8k
    {
597
7.74k
    case ICMP_ECHO_REQUEST:
598
15.8k
    case ICMP_ECHO_REPLY:
599
15.8k
      return m_DataLen;
600
219
    case ICMP_TIMESTAMP_REQUEST:
601
9.11k
    case ICMP_TIMESTAMP_REPLY:
602
9.11k
      return sizeof(icmp_timestamp_request);
603
3.28k
    case ICMP_ROUTER_SOL:
604
6.56k
    case ICMP_INFO_REQUEST:
605
10.6k
    case ICMP_INFO_REPLY:
606
10.6k
    case ICMP_UNSUPPORTED:
607
10.6k
      return sizeof(icmphdr);
608
11.3k
    case ICMP_ADDRESS_MASK_REPLY:
609
17.8k
    case ICMP_ADDRESS_MASK_REQUEST:
610
17.8k
      return sizeof(icmp_address_mask_request);
611
10.1k
    case ICMP_DEST_UNREACHABLE:
612
10.1k
      return sizeof(icmp_destination_unreachable);
613
2.42k
    case ICMP_REDIRECT:
614
2.42k
      return sizeof(icmp_redirect);
615
6.05k
    case ICMP_TIME_EXCEEDED:
616
9.34k
    case ICMP_SOURCE_QUENCH:
617
9.34k
      return sizeof(icmp_time_exceeded);
618
6.95k
    case ICMP_PARAM_PROBLEM:
619
6.95k
      return sizeof(icmp_param_problem);
620
5.63k
    case ICMP_ROUTER_ADV:
621
      // clang-format off
622
5.63k
      routerAdvSize = sizeof(icmp_router_advertisement_hdr) + (getRouterAdvertisementData()->header->advertisementCount * sizeof(icmp_router_address_structure));
623
      // clang-format on
624
5.63k
      if (routerAdvSize > m_DataLen)
625
45
        return m_DataLen;
626
5.58k
      return routerAdvSize;
627
0
    default:
628
0
      return sizeof(icmphdr);
629
87.8k
    }
630
87.8k
  }
631
632
  void IcmpLayer::computeCalculateFields()
633
9.51k
  {
634
    // calculate checksum
635
9.51k
    getIcmpHeader()->checksum = 0;
636
637
9.51k
    size_t icmpLen = 0;
638
9.51k
    Layer* curLayer = this;
639
31.7k
    while (curLayer != nullptr)
640
22.2k
    {
641
22.2k
      icmpLen += curLayer->getHeaderLen();
642
22.2k
      curLayer = curLayer->getNextLayer();
643
22.2k
    }
644
645
9.51k
    ScalarBuffer<uint16_t> buffer;
646
9.51k
    buffer.buffer = reinterpret_cast<uint16_t*>(getIcmpHeader());
647
9.51k
    buffer.len = icmpLen;
648
9.51k
    size_t checksum = computeChecksum(&buffer, 1);
649
650
9.51k
    getIcmpHeader()->checksum = htobe16(checksum);
651
9.51k
  }
652
653
  std::string IcmpLayer::toString() const
654
19.0k
  {
655
19.0k
    std::string messageTypeAsString;
656
19.0k
    IcmpMessageType type = getMessageType();
657
19.0k
    switch (type)
658
19.0k
    {
659
2.11k
    case ICMP_ECHO_REPLY:
660
2.11k
      messageTypeAsString = "Echo (ping) reply";
661
2.11k
      break;
662
1.87k
    case ICMP_DEST_UNREACHABLE:
663
1.87k
      messageTypeAsString = "Destination unreachable";
664
1.87k
      break;
665
730
    case ICMP_SOURCE_QUENCH:
666
730
      messageTypeAsString = "Source quench (flow control)";
667
730
      break;
668
534
    case ICMP_REDIRECT:
669
534
      messageTypeAsString = "Redirect";
670
534
      break;
671
1.70k
    case ICMP_ECHO_REQUEST:
672
1.70k
      messageTypeAsString = "Echo (ping) request";
673
1.70k
      break;
674
1.24k
    case ICMP_ROUTER_ADV:
675
1.24k
      messageTypeAsString = "Router advertisement";
676
1.24k
      break;
677
730
    case ICMP_ROUTER_SOL:
678
730
      messageTypeAsString = "Router solicitation";
679
730
      break;
680
1.20k
    case ICMP_TIME_EXCEEDED:
681
1.20k
      messageTypeAsString = "Time-to-live exceeded";
682
1.20k
      break;
683
1.53k
    case ICMP_PARAM_PROBLEM:
684
1.53k
      messageTypeAsString = "Parameter problem: bad IP header";
685
1.53k
      break;
686
54
    case ICMP_TIMESTAMP_REQUEST:
687
54
      messageTypeAsString = "Timestamp request";
688
54
      break;
689
1.97k
    case ICMP_TIMESTAMP_REPLY:
690
1.97k
      messageTypeAsString = "Timestamp reply";
691
1.97k
      break;
692
660
    case ICMP_INFO_REQUEST:
693
660
      messageTypeAsString = "Information request";
694
660
      break;
695
740
    case ICMP_INFO_REPLY:
696
740
      messageTypeAsString = "Information reply";
697
740
      break;
698
1.45k
    case ICMP_ADDRESS_MASK_REQUEST:
699
1.45k
      messageTypeAsString = "Address mask request";
700
1.45k
      break;
701
2.48k
    case ICMP_ADDRESS_MASK_REPLY:
702
2.48k
      messageTypeAsString = "Address mask reply";
703
2.48k
      break;
704
0
    default:
705
0
      messageTypeAsString = "Unknown";
706
0
      break;
707
19.0k
    }
708
709
19.0k
    std::ostringstream typeStream;
710
19.0k
    typeStream << (int)getIcmpHeader()->type;
711
712
19.0k
    return "ICMP Layer, " + messageTypeAsString + " (type: " + typeStream.str() + ")";
713
19.0k
  }
714
715
}  // namespace pcpp