Coverage Report

Created: 2025-09-27 08:03

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/PcapPlusPlus/Packet++/src/IcmpLayer.cpp
Line
Count
Source
1
4.10k
#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 = (uint8_t*)header;
20
0
    return (icmp_router_address_structure*)(headerAsByteArr + sizeof(icmp_router_advertisement_hdr) +
21
0
                                            index * sizeof(icmp_router_address_structure));
22
0
  }
23
24
  void icmp_router_address_structure::setRouterAddress(IPv4Address addr, uint32_t preference)
25
994
  {
26
994
    routerAddress = addr.toInt();
27
994
    preferenceLevel = htobe32(preference);
28
994
  }
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
174k
  {
40
174k
    uint8_t type = getIcmpHeader()->type;
41
174k
    if (type > 18)
42
0
      return ICMP_UNSUPPORTED;
43
44
174k
    return (IcmpMessageType)type;
45
174k
  }
46
47
  bool IcmpLayer::cleanIcmpLayer()
48
4.73k
  {
49
    // remove all layers after
50
51
4.73k
    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
4.73k
    size_t headerLen = this->getHeaderLen();
61
4.73k
    if (headerLen > sizeof(icmphdr))
62
3.74k
    {
63
3.74k
      if (!this->shortenLayer(sizeof(icmphdr), headerLen - sizeof(icmphdr)))
64
0
        return false;
65
3.74k
    }
66
67
4.73k
    return true;
68
4.73k
  }
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 = (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 = (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.50k
  {
102
1.50k
    if (m_Packet == nullptr)
103
1.50k
    {
104
1.50k
      PCPP_LOG_ERROR("Cannot set ICMP data that involves IP and L4 layers on a layer not attached to a packet. "
105
1.50k
                     "Please add the ICMP layer to a packet and try again");
106
1.50k
      return false;
107
1.50k
    }
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 = (icmp_echo_hdr*)m_Data;
130
0
    m_EchoData.data = (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 = (icmp_echo_hdr*)m_Data;
151
0
    m_EchoData.data = (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 (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 = (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.50k
  {
198
2.50k
    if (!isMessageOfType(ICMP_TIMESTAMP_REPLY))
199
0
      return nullptr;
200
201
2.50k
    return (icmp_timestamp_reply*)m_Data;
202
2.50k
  }
203
204
  icmp_timestamp_reply* IcmpLayer::setTimestampReplyData(uint16_t id, uint16_t sequence, timeval originateTimestamp,
205
                                                         timeval receiveTimestamp, timeval transmitTimestamp)
206
1.25k
  {
207
1.25k
    if (!cleanIcmpLayer())
208
0
      return nullptr;
209
210
1.25k
    if (!this->extendLayer(m_DataLen, sizeof(icmp_timestamp_reply) - sizeof(icmphdr)))
211
0
      return nullptr;
212
213
1.25k
    getIcmpHeader()->type = (uint8_t)ICMP_TIMESTAMP_REPLY;
214
215
1.25k
    icmp_timestamp_reply* header = getTimestampReplyData();
216
1.25k
    header->code = 0;
217
1.25k
    header->id = htobe16(id);
218
1.25k
    header->sequence = htobe16(sequence);
219
1.25k
    header->originateTimestamp = htobe32(originateTimestamp.tv_sec * 1000 + originateTimestamp.tv_usec / 1000);
220
1.25k
    header->receiveTimestamp = htobe32(receiveTimestamp.tv_sec * 1000 + receiveTimestamp.tv_usec / 1000);
221
1.25k
    header->transmitTimestamp = htobe32(transmitTimestamp.tv_sec * 1000 + transmitTimestamp.tv_usec / 1000);
222
223
1.25k
    return header;
224
1.25k
  }
225
226
  icmp_destination_unreachable* IcmpLayer::getDestUnreachableData()
227
1.68k
  {
228
1.68k
    if (!isMessageOfType(ICMP_DEST_UNREACHABLE))
229
0
      return nullptr;
230
231
1.68k
    return (icmp_destination_unreachable*)m_Data;
232
1.68k
  }
233
234
  icmp_destination_unreachable* IcmpLayer::setDestUnreachableData(IcmpDestUnreachableCodes code, uint16_t nextHopMTU,
235
                                                                  IPv4Layer* ipHeader, Layer* l4Header)
236
840
  {
237
840
    if (!cleanIcmpLayer())
238
0
      return nullptr;
239
240
840
    if (!this->extendLayer(m_DataLen, sizeof(icmp_destination_unreachable) - sizeof(icmphdr)))
241
0
      return nullptr;
242
243
840
    getIcmpHeader()->type = (uint8_t)ICMP_DEST_UNREACHABLE;
244
245
840
    icmp_destination_unreachable* header = getDestUnreachableData();
246
840
    header->code = code;
247
840
    header->nextHopMTU = htobe16(nextHopMTU);
248
840
    header->unused = 0;
249
250
840
    if (!setIpAndL4Layers(ipHeader, l4Header))
251
840
      return nullptr;
252
253
0
    return header;
254
840
  }
255
256
  icmp_source_quench* IcmpLayer::getSourceQuenchdata()
257
0
  {
258
0
    if (!isMessageOfType(ICMP_SOURCE_QUENCH))
259
0
      return nullptr;
260
261
0
    return (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 = (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 (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 = (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
10.9k
  {
320
10.9k
    if (!isMessageOfType(ICMP_ROUTER_ADV))
321
0
      return nullptr;
322
323
10.9k
    m_RouterAdvData.header = (icmp_router_advertisement_hdr*)m_Data;
324
325
10.9k
    return &m_RouterAdvData;
326
10.9k
  }
327
328
  icmp_router_advertisement* IcmpLayer::setRouterAdvertisementData(
329
      uint8_t code, uint16_t lifetimeInSeconds, const std::vector<icmp_router_address_structure>& routerAddresses)
330
994
  {
331
994
    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
994
    if (!cleanIcmpLayer())
339
0
      return nullptr;
340
341
994
    if (!this->extendLayer(m_DataLen, sizeof(icmp_router_advertisement_hdr) +
342
994
                                          (routerAddresses.size() * sizeof(icmp_router_address_structure)) -
343
994
                                          sizeof(icmphdr)))
344
0
      return nullptr;
345
346
994
    getIcmpHeader()->type = (uint8_t)ICMP_ROUTER_ADV;
347
348
994
    icmp_router_advertisement* header = getRouterAdvertisementData();
349
994
    header->header->code = code;
350
994
    header->header->lifetime = htobe16(lifetimeInSeconds);
351
994
    header->header->advertisementCount = (uint8_t)routerAddresses.size();
352
994
    header->header->addressEntrySize = 2;
353
354
994
    icmp_router_address_structure* curPos =
355
994
        (icmp_router_address_structure*)((uint8_t*)header->header + sizeof(icmp_router_advertisement_hdr));
356
994
    for (const auto& iter : routerAddresses)
357
994
    {
358
994
      curPos->routerAddress = iter.routerAddress;
359
994
      curPos->preferenceLevel = iter.preferenceLevel;
360
994
      curPos += 1;
361
994
    }
362
363
994
    return header;
364
994
  }
365
366
  icmp_router_solicitation* IcmpLayer::getRouterSolicitationData()
367
0
  {
368
0
    if (!isMessageOfType(ICMP_ROUTER_SOL))
369
0
      return nullptr;
370
371
0
    return (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 = (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 (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 = (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
727
  {
423
727
    if (!isMessageOfType(ICMP_PARAM_PROBLEM))
424
0
      return nullptr;
425
426
727
    return (icmp_param_problem*)m_Data;
427
727
  }
428
429
  icmp_param_problem* IcmpLayer::setParamProblemData(uint8_t code, uint8_t errorOctetPointer, IPv4Layer* ipHeader,
430
                                                     Layer* l4Header)
431
639
  {
432
639
    if (code > 2)
433
551
    {
434
551
      PCPP_LOG_ERROR("Unknown code " << (int)code << " for ICMP parameter problem data");
435
551
      return nullptr;
436
551
    }
437
438
88
    if (!cleanIcmpLayer())
439
0
      return nullptr;
440
441
88
    if (!this->extendLayer(m_DataLen, sizeof(icmp_param_problem) - sizeof(icmphdr)))
442
0
      return nullptr;
443
444
88
    getIcmpHeader()->type = (uint8_t)ICMP_PARAM_PROBLEM;
445
446
88
    icmp_param_problem* header = getParamProblemData();
447
88
    header->code = code;
448
88
    header->unused1 = 0;
449
88
    header->unused2 = 0;
450
88
    header->pointer = errorOctetPointer;
451
452
88
    if (!setIpAndL4Layers(ipHeader, l4Header))
453
88
      return nullptr;
454
455
0
    return header;
456
88
  }
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 (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 = (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
4
  {
487
4
    if (!isMessageOfType(ICMP_ADDRESS_MASK_REPLY))
488
0
      return nullptr;
489
490
4
    return (icmp_address_mask_reply*)m_Data;
491
4
  }
492
493
  icmp_address_mask_reply* IcmpLayer::setAddressMaskReplyData(uint16_t id, uint16_t sequence, IPv4Address mask)
494
2
  {
495
2
    if (!cleanIcmpLayer())
496
0
      return nullptr;
497
498
2
    if (!this->extendLayer(m_DataLen, sizeof(icmp_address_mask_reply) - sizeof(icmphdr)))
499
0
      return nullptr;
500
501
2
    getIcmpHeader()->type = (uint8_t)ICMP_ADDRESS_MASK_REPLY;
502
503
2
    icmp_address_mask_reply* header = getAddressMaskReplyData();
504
2
    header->code = 0;
505
2
    header->id = htobe16(id);
506
2
    header->sequence = htobe16(sequence);
507
2
    header->addressMask = htobe32(mask.toInt());
508
509
2
    return header;
510
2
  }
511
512
  icmp_info_request* IcmpLayer::getInfoRequestData()
513
972
  {
514
972
    if (!isMessageOfType(ICMP_INFO_REQUEST))
515
0
      return nullptr;
516
517
972
    return (icmp_info_request*)m_Data;
518
972
  }
519
520
  icmp_info_request* IcmpLayer::setInfoRequestData(uint16_t id, uint16_t sequence)
521
486
  {
522
486
    if (!cleanIcmpLayer())
523
0
      return nullptr;
524
525
486
    if (!this->extendLayer(m_DataLen, sizeof(icmp_info_request) - sizeof(icmphdr)))
526
0
      return nullptr;
527
528
486
    getIcmpHeader()->type = (uint8_t)ICMP_INFO_REQUEST;
529
530
486
    icmp_info_request* header = getInfoRequestData();
531
486
    header->code = 0;
532
486
    header->id = htobe16(id);
533
486
    header->sequence = htobe16(sequence);
534
535
486
    return header;
536
486
  }
537
538
  icmp_info_reply* IcmpLayer::getInfoReplyData()
539
1.00k
  {
540
1.00k
    if (!isMessageOfType(ICMP_INFO_REPLY))
541
0
      return nullptr;
542
543
1.00k
    return (icmp_info_reply*)m_Data;
544
1.00k
  }
545
546
  icmp_info_reply* IcmpLayer::setInfoReplyData(uint16_t id, uint16_t sequence)
547
504
  {
548
504
    if (!cleanIcmpLayer())
549
0
      return nullptr;
550
551
504
    if (!this->extendLayer(m_DataLen, sizeof(icmp_info_reply) - sizeof(icmphdr)))
552
0
      return nullptr;
553
554
504
    getIcmpHeader()->type = (uint8_t)ICMP_INFO_REPLY;
555
556
504
    icmp_info_reply* header = getInfoReplyData();
557
504
    header->code = 0;
558
504
    header->id = htobe16(id);
559
504
    header->sequence = htobe16(sequence);
560
561
504
    return header;
562
504
  }
563
564
  void IcmpLayer::parseNextLayer()
565
38.1k
  {
566
38.1k
    size_t headerLen = getHeaderLen();
567
568
38.1k
    switch (getMessageType())
569
38.1k
    {
570
5.77k
    case ICMP_DEST_UNREACHABLE:
571
7.65k
    case ICMP_SOURCE_QUENCH:
572
11.0k
    case ICMP_TIME_EXCEEDED:
573
11.3k
    case ICMP_REDIRECT:
574
15.2k
    case ICMP_PARAM_PROBLEM:
575
      // clang-format off
576
15.2k
      m_NextLayer = IPv4Layer::isDataValid(m_Data + headerLen, m_DataLen - headerLen)
577
15.2k
              ? static_cast<Layer*>(new IPv4Layer(m_Data + headerLen, m_DataLen - headerLen, this, m_Packet))
578
15.2k
              : static_cast<Layer*>(new PayloadLayer(m_Data + headerLen, m_DataLen - headerLen, this, m_Packet));
579
      // clang-format on
580
15.2k
      return;
581
22.9k
    default:
582
22.9k
      if (m_DataLen > headerLen)
583
16.0k
        m_NextLayer = new PayloadLayer(m_Data + headerLen, m_DataLen - headerLen, this, m_Packet);
584
22.9k
      return;
585
38.1k
    }
586
38.1k
  }
587
588
  size_t IcmpLayer::getHeaderLen() const
589
63.0k
  {
590
63.0k
    IcmpMessageType type = getMessageType();
591
63.0k
    size_t routerAdvSize = 0;
592
63.0k
    switch (type)
593
63.0k
    {
594
265
    case ICMP_ECHO_REQUEST:
595
3.65k
    case ICMP_ECHO_REPLY:
596
3.65k
      return m_DataLen;
597
512
    case ICMP_TIMESTAMP_REQUEST:
598
11.7k
    case ICMP_TIMESTAMP_REPLY:
599
11.7k
      return sizeof(icmp_timestamp_request);
600
4.21k
    case ICMP_ROUTER_SOL:
601
9.04k
    case ICMP_INFO_REQUEST:
602
14.5k
    case ICMP_INFO_REPLY:
603
14.5k
    case ICMP_UNSUPPORTED:
604
14.5k
      return sizeof(icmphdr);
605
18
    case ICMP_ADDRESS_MASK_REPLY:
606
18
    case ICMP_ADDRESS_MASK_REQUEST:
607
18
      return sizeof(icmp_address_mask_request);
608
9.13k
    case ICMP_DEST_UNREACHABLE:
609
9.13k
      return sizeof(icmp_destination_unreachable);
610
459
    case ICMP_REDIRECT:
611
459
      return sizeof(icmp_redirect);
612
5.72k
    case ICMP_TIME_EXCEEDED:
613
8.54k
    case ICMP_SOURCE_QUENCH:
614
8.54k
      return sizeof(icmp_time_exceeded);
615
5.90k
    case ICMP_PARAM_PROBLEM:
616
5.90k
      return sizeof(icmp_param_problem);
617
8.99k
    case ICMP_ROUTER_ADV:
618
      // clang-format off
619
8.99k
      routerAdvSize = sizeof(icmp_router_advertisement_hdr) + (getRouterAdvertisementData()->header->advertisementCount * sizeof(icmp_router_address_structure));
620
      // clang-format on
621
8.99k
      if (routerAdvSize > m_DataLen)
622
162
        return m_DataLen;
623
8.83k
      return routerAdvSize;
624
0
    default:
625
0
      return sizeof(icmphdr);
626
63.0k
    }
627
63.0k
  }
628
629
  void IcmpLayer::computeCalculateFields()
630
6.70k
  {
631
    // calculate checksum
632
6.70k
    getIcmpHeader()->checksum = 0;
633
634
6.70k
    size_t icmpLen = 0;
635
6.70k
    Layer* curLayer = this;
636
24.1k
    while (curLayer != nullptr)
637
17.4k
    {
638
17.4k
      icmpLen += curLayer->getHeaderLen();
639
17.4k
      curLayer = curLayer->getNextLayer();
640
17.4k
    }
641
642
6.70k
    ScalarBuffer<uint16_t> buffer;
643
6.70k
    buffer.buffer = (uint16_t*)getIcmpHeader();
644
6.70k
    buffer.len = icmpLen;
645
6.70k
    size_t checksum = computeChecksum(&buffer, 1);
646
647
6.70k
    getIcmpHeader()->checksum = htobe16(checksum);
648
6.70k
  }
649
650
  std::string IcmpLayer::toString() const
651
13.4k
  {
652
13.4k
    std::string messageTypeAsString;
653
13.4k
    IcmpMessageType type = getMessageType();
654
13.4k
    switch (type)
655
13.4k
    {
656
964
    case ICMP_ECHO_REPLY:
657
964
      messageTypeAsString = "Echo (ping) reply";
658
964
      break;
659
1.68k
    case ICMP_DEST_UNREACHABLE:
660
1.68k
      messageTypeAsString = "Destination unreachable";
661
1.68k
      break;
662
626
    case ICMP_SOURCE_QUENCH:
663
626
      messageTypeAsString = "Source quench (flow control)";
664
626
      break;
665
102
    case ICMP_REDIRECT:
666
102
      messageTypeAsString = "Redirect";
667
102
      break;
668
68
    case ICMP_ECHO_REQUEST:
669
68
      messageTypeAsString = "Echo (ping) request";
670
68
      break;
671
1.98k
    case ICMP_ROUTER_ADV:
672
1.98k
      messageTypeAsString = "Router advertisement";
673
1.98k
      break;
674
938
    case ICMP_ROUTER_SOL:
675
938
      messageTypeAsString = "Router solicitation";
676
938
      break;
677
1.15k
    case ICMP_TIME_EXCEEDED:
678
1.15k
      messageTypeAsString = "Time-to-live exceeded";
679
1.15k
      break;
680
1.27k
    case ICMP_PARAM_PROBLEM:
681
1.27k
      messageTypeAsString = "Parameter problem: bad IP header";
682
1.27k
      break;
683
128
    case ICMP_TIMESTAMP_REQUEST:
684
128
      messageTypeAsString = "Timestamp request";
685
128
      break;
686
2.50k
    case ICMP_TIMESTAMP_REPLY:
687
2.50k
      messageTypeAsString = "Timestamp reply";
688
2.50k
      break;
689
972
    case ICMP_INFO_REQUEST:
690
972
      messageTypeAsString = "Information request";
691
972
      break;
692
1.00k
    case ICMP_INFO_REPLY:
693
1.00k
      messageTypeAsString = "Information reply";
694
1.00k
      break;
695
0
    case ICMP_ADDRESS_MASK_REQUEST:
696
0
      messageTypeAsString = "Address mask request";
697
0
      break;
698
4
    case ICMP_ADDRESS_MASK_REPLY:
699
4
      messageTypeAsString = "Address mask reply";
700
4
      break;
701
0
    default:
702
0
      messageTypeAsString = "Unknown";
703
0
      break;
704
13.4k
    }
705
706
13.4k
    std::ostringstream typeStream;
707
13.4k
    typeStream << (int)getIcmpHeader()->type;
708
709
13.4k
    return "ICMP Layer, " + messageTypeAsString + " (type: " + typeStream.str() + ")";
710
13.4k
  }
711
712
}  // namespace pcpp