Coverage Report

Created: 2026-06-10 07:57

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