Coverage Report

Created: 2026-01-09 07:52

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