Coverage Report

Created: 2026-10-17 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/PcapPlusPlus/Packet++/src/IcmpLayer.cpp
Line
Count
Source
1
1.22k
#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
178
  {
26
178
    routerAddress = addr.toInt();
27
178
    preferenceLevel = htobe32(preference);
28
178
  }
29
30
0
  IcmpLayer::IcmpLayer() : Layer()
31
0
  {
32
0
    allocData(sizeof(icmphdr));
33
0
    m_Protocol = ICMP;
34
0
  }
35
36
  IcmpMessageType IcmpLayer::getMessageType() const
37
94.8k
  {
38
94.8k
    uint8_t type = getIcmpHeader()->type;
39
94.8k
    if (type > 18)
40
0
      return ICMP_UNSUPPORTED;
41
42
94.8k
    return static_cast<IcmpMessageType>(type);
43
94.8k
  }
44
45
  bool IcmpLayer::cleanIcmpLayer()
46
2.48k
  {
47
    // remove all layers after
48
49
2.48k
    if (getAttachedPacket() != nullptr)
50
0
    {
51
0
      bool res = getAttachedPacket()->removeAllLayersAfter(this);
52
0
      if (!res)
53
0
        return false;
54
0
    }
55
56
    // shorten layer to size of icmphdr
57
58
2.48k
    size_t headerLen = this->getHeaderLen();
59
2.48k
    if (headerLen > sizeof(icmphdr))
60
1.32k
    {
61
1.32k
      if (!this->shortenLayer(sizeof(icmphdr), headerLen - sizeof(icmphdr)))
62
0
        return false;
63
1.32k
    }
64
65
2.48k
    return true;
66
2.48k
  }
67
68
  bool IcmpLayer::setEchoData(IcmpMessageType echoType, uint16_t id, uint16_t sequence, uint64_t timestamp,
69
                              const uint8_t* data, size_t dataLen)
70
0
  {
71
0
    if (!cleanIcmpLayer())
72
0
      return false;
73
74
0
    if (!this->extendLayer(m_DataLen, sizeof(icmp_echo_hdr) - sizeof(icmphdr) + dataLen))
75
0
      return false;
76
77
0
    getIcmpHeader()->type = static_cast<uint8_t>(echoType);
78
79
0
    icmp_echo_request* header = nullptr;
80
0
    if (echoType == ICMP_ECHO_REQUEST)
81
0
      header = getEchoRequestData();
82
0
    else if (echoType == ICMP_ECHO_REPLY)
83
0
      header = reinterpret_cast<icmp_echo_request*>(getEchoReplyData());
84
0
    else
85
0
      return false;
86
87
0
    header->header->code = 0;
88
0
    header->header->checksum = 0;
89
0
    header->header->id = htobe16(id);
90
0
    header->header->sequence = htobe16(sequence);
91
0
    header->header->timestamp = timestamp;
92
0
    if (data != nullptr && dataLen > 0)
93
0
      memcpy(header->data, data, dataLen);
94
95
0
    return true;
96
0
  }
97
98
  bool IcmpLayer::setIpAndL4Layers(IPv4Layer* ipLayer, Layer* l4Layer)
99
612
  {
100
612
    if (getAttachedPacket() == nullptr)
101
612
    {
102
612
      PCPP_LOG_ERROR("Cannot set ICMP data that involves IP and L4 layers on a layer not attached to a packet. "
103
612
                     "Please add the ICMP layer to a packet and try again");
104
612
      return false;
105
612
    }
106
107
0
    if (ipLayer != nullptr && !getAttachedPacket()->addLayer(ipLayer))
108
0
    {
109
0
      PCPP_LOG_ERROR("Couldn't add IP layer to ICMP packet");
110
0
      return false;
111
0
    }
112
113
0
    if (l4Layer != nullptr && !getAttachedPacket()->addLayer(l4Layer))
114
0
    {
115
0
      PCPP_LOG_ERROR("Couldn't add L4 layer to ICMP packet");
116
0
      return false;
117
0
    }
118
119
0
    return true;
120
0
  }
121
122
  icmp_echo_request* IcmpLayer::getEchoRequestData()
123
0
  {
124
0
    if (!isMessageOfType(ICMP_ECHO_REQUEST))
125
0
      return nullptr;
126
127
0
    m_EchoData.header = reinterpret_cast<icmp_echo_hdr*>(m_Data);
128
0
    m_EchoData.data = reinterpret_cast<uint8_t*>(m_Data + sizeof(icmp_echo_hdr));
129
0
    m_EchoData.dataLength = m_DataLen - sizeof(icmp_echo_hdr);
130
131
0
    return &m_EchoData;
132
0
  }
133
134
  icmp_echo_request* IcmpLayer::setEchoRequestData(uint16_t id, uint16_t sequence, uint64_t timestamp,
135
                                                   const uint8_t* data, size_t dataLen)
136
0
  {
137
0
    if (setEchoData(ICMP_ECHO_REQUEST, id, sequence, timestamp, data, dataLen))
138
0
      return getEchoRequestData();
139
0
    else
140
0
      return nullptr;
141
0
  }
142
143
  icmp_echo_reply* IcmpLayer::getEchoReplyData()
144
0
  {
145
0
    if (!isMessageOfType(ICMP_ECHO_REPLY))
146
0
      return nullptr;
147
148
0
    m_EchoData.header = reinterpret_cast<icmp_echo_hdr*>(m_Data);
149
0
    m_EchoData.data = reinterpret_cast<uint8_t*>(m_Data + sizeof(icmp_echo_hdr));
150
0
    m_EchoData.dataLength = m_DataLen - sizeof(icmp_echo_hdr);
151
152
0
    return &m_EchoData;
153
0
  }
154
155
  icmp_echo_reply* IcmpLayer::setEchoReplyData(uint16_t id, uint16_t sequence, uint64_t timestamp,
156
                                               const uint8_t* data, size_t dataLen)
157
0
  {
158
0
    if (setEchoData(ICMP_ECHO_REPLY, id, sequence, timestamp, data, dataLen))
159
0
      return getEchoReplyData();
160
0
    else
161
0
      return nullptr;
162
0
  }
163
164
  icmp_timestamp_request* IcmpLayer::getTimestampRequestData()
165
0
  {
166
0
    if (!isMessageOfType(ICMP_TIMESTAMP_REQUEST))
167
0
      return nullptr;
168
169
0
    return reinterpret_cast<icmp_timestamp_request*>(m_Data);
170
0
  }
171
172
  icmp_timestamp_request* IcmpLayer::setTimestampRequestData(uint16_t id, uint16_t sequence,
173
                                                             timeval originateTimestamp)
174
0
  {
175
0
    if (!cleanIcmpLayer())
176
0
      return nullptr;
177
178
0
    if (!this->extendLayer(m_DataLen, sizeof(icmp_timestamp_request) - sizeof(icmphdr)))
179
0
      return nullptr;
180
181
0
    getIcmpHeader()->type = static_cast<uint8_t>(ICMP_TIMESTAMP_REQUEST);
182
183
0
    icmp_timestamp_request* header = getTimestampRequestData();
184
0
    header->code = 0;
185
0
    header->id = htobe16(id);
186
0
    header->sequence = htobe16(sequence);
187
0
    header->originateTimestamp = htobe32(originateTimestamp.tv_sec * 1000 + originateTimestamp.tv_usec / 1000);
188
0
    header->receiveTimestamp = 0;
189
0
    header->transmitTimestamp = 0;
190
191
0
    return header;
192
0
  }
193
194
  icmp_timestamp_reply* IcmpLayer::getTimestampReplyData()
195
388
  {
196
388
    if (!isMessageOfType(ICMP_TIMESTAMP_REPLY))
197
0
      return nullptr;
198
199
388
    return reinterpret_cast<icmp_timestamp_reply*>(m_Data);
200
388
  }
201
202
  icmp_timestamp_reply* IcmpLayer::setTimestampReplyData(uint16_t id, uint16_t sequence, timeval originateTimestamp,
203
                                                         timeval receiveTimestamp, timeval transmitTimestamp)
204
194
  {
205
194
    if (!cleanIcmpLayer())
206
0
      return nullptr;
207
208
194
    if (!this->extendLayer(m_DataLen, sizeof(icmp_timestamp_reply) - sizeof(icmphdr)))
209
0
      return nullptr;
210
211
194
    getIcmpHeader()->type = static_cast<uint8_t>(ICMP_TIMESTAMP_REPLY);
212
213
194
    icmp_timestamp_reply* header = getTimestampReplyData();
214
194
    header->code = 0;
215
194
    header->id = htobe16(id);
216
194
    header->sequence = htobe16(sequence);
217
194
    header->originateTimestamp = htobe32(originateTimestamp.tv_sec * 1000 + originateTimestamp.tv_usec / 1000);
218
194
    header->receiveTimestamp = htobe32(receiveTimestamp.tv_sec * 1000 + receiveTimestamp.tv_usec / 1000);
219
194
    header->transmitTimestamp = htobe32(transmitTimestamp.tv_sec * 1000 + transmitTimestamp.tv_usec / 1000);
220
221
194
    return header;
222
194
  }
223
224
  icmp_destination_unreachable* IcmpLayer::getDestUnreachableData()
225
952
  {
226
952
    if (!isMessageOfType(ICMP_DEST_UNREACHABLE))
227
0
      return nullptr;
228
229
952
    return reinterpret_cast<icmp_destination_unreachable*>(m_Data);
230
952
  }
231
232
  icmp_destination_unreachable* IcmpLayer::setDestUnreachableData(IcmpDestUnreachableCodes code, uint16_t nextHopMTU,
233
                                                                  IPv4Layer* ipHeader, Layer* l4Header)
234
476
  {
235
476
    if (!cleanIcmpLayer())
236
0
      return nullptr;
237
238
476
    if (!this->extendLayer(m_DataLen, sizeof(icmp_destination_unreachable) - sizeof(icmphdr)))
239
0
      return nullptr;
240
241
476
    getIcmpHeader()->type = static_cast<uint8_t>(ICMP_DEST_UNREACHABLE);
242
243
476
    icmp_destination_unreachable* header = getDestUnreachableData();
244
476
    header->code = code;
245
476
    header->nextHopMTU = htobe16(nextHopMTU);
246
476
    header->unused = 0;
247
248
476
    if (!setIpAndL4Layers(ipHeader, l4Header))
249
476
      return nullptr;
250
251
0
    return header;
252
476
  }
253
254
  icmp_source_quench* IcmpLayer::getSourceQuenchdata()
255
0
  {
256
0
    if (!isMessageOfType(ICMP_SOURCE_QUENCH))
257
0
      return nullptr;
258
259
0
    return reinterpret_cast<icmp_source_quench*>(m_Data);
260
0
  }
261
262
  icmp_source_quench* IcmpLayer::setSourceQuenchdata(IPv4Layer* ipHeader, Layer* l4Header)
263
0
  {
264
0
    if (!cleanIcmpLayer())
265
0
      return nullptr;
266
267
0
    if (!this->extendLayer(m_DataLen, sizeof(icmp_source_quench) - sizeof(icmphdr)))
268
0
      return nullptr;
269
270
0
    getIcmpHeader()->type = static_cast<uint8_t>(ICMP_SOURCE_QUENCH);
271
272
0
    icmp_source_quench* header = getSourceQuenchdata();
273
0
    header->unused = 0;
274
275
0
    if (!setIpAndL4Layers(ipHeader, l4Header))
276
0
      return nullptr;
277
278
0
    return header;
279
0
  }
280
281
  icmp_redirect* IcmpLayer::getRedirectData()
282
0
  {
283
0
    if (!isMessageOfType(ICMP_REDIRECT))
284
0
      return nullptr;
285
286
0
    return reinterpret_cast<icmp_redirect*>(m_Data);
287
0
  }
288
289
  icmp_redirect* IcmpLayer::setRedirectData(uint8_t code, IPv4Address gatewayAddress, IPv4Layer* ipHeader,
290
                                            Layer* l4Header)
291
0
  {
292
0
    if (code > 3)
293
0
    {
294
0
      PCPP_LOG_ERROR("Unknown code " << (int)code << " for ICMP redirect data");
295
0
      return nullptr;
296
0
    }
297
298
0
    if (!cleanIcmpLayer())
299
0
      return nullptr;
300
301
0
    if (!this->extendLayer(m_DataLen, sizeof(icmp_redirect) - sizeof(icmphdr)))
302
0
      return nullptr;
303
304
0
    getIcmpHeader()->type = static_cast<uint8_t>(ICMP_REDIRECT);
305
306
0
    icmp_redirect* header = getRedirectData();
307
0
    header->code = code;
308
0
    header->gatewayAddress = gatewayAddress.toInt();
309
310
0
    if (!setIpAndL4Layers(ipHeader, l4Header))
311
0
      return nullptr;
312
313
0
    return header;
314
0
  }
315
316
  icmp_router_advertisement* IcmpLayer::getRouterAdvertisementData() const
317
1.60k
  {
318
1.60k
    if (!isMessageOfType(ICMP_ROUTER_ADV))
319
0
      return nullptr;
320
321
1.60k
    m_RouterAdvData.header = reinterpret_cast<icmp_router_advertisement_hdr*>(m_Data);
322
323
1.60k
    return &m_RouterAdvData;
324
1.60k
  }
325
326
  icmp_router_advertisement* IcmpLayer::setRouterAdvertisementData(
327
      uint8_t code, uint16_t lifetimeInSeconds, const std::vector<icmp_router_address_structure>& routerAddresses)
328
178
  {
329
178
    if (code != 0 && code != 16)
330
0
    {
331
0
      PCPP_LOG_ERROR("Unknown code " << (int)code
332
0
                                     << " for ICMP router advertisement data (only codes 0 and 16 are legal)");
333
0
      return nullptr;
334
0
    }
335
336
178
    if (!cleanIcmpLayer())
337
0
      return nullptr;
338
339
178
    if (!this->extendLayer(m_DataLen, sizeof(icmp_router_advertisement_hdr) +
340
178
                                          (routerAddresses.size() * sizeof(icmp_router_address_structure)) -
341
178
                                          sizeof(icmphdr)))
342
0
      return nullptr;
343
344
178
    getIcmpHeader()->type = static_cast<uint8_t>(ICMP_ROUTER_ADV);
345
346
178
    icmp_router_advertisement* header = getRouterAdvertisementData();
347
178
    header->header->code = code;
348
178
    header->header->lifetime = htobe16(lifetimeInSeconds);
349
178
    header->header->advertisementCount = static_cast<uint8_t>(routerAddresses.size());
350
178
    header->header->addressEntrySize = 2;
351
352
178
    icmp_router_address_structure* curPos = reinterpret_cast<icmp_router_address_structure*>(
353
178
        reinterpret_cast<uint8_t*>(header->header) + sizeof(icmp_router_advertisement_hdr));
354
178
    for (const auto& iter : routerAddresses)
355
178
    {
356
178
      curPos->routerAddress = iter.routerAddress;
357
178
      curPos->preferenceLevel = iter.preferenceLevel;
358
178
      curPos += 1;
359
178
    }
360
361
178
    return header;
362
178
  }
363
364
  icmp_router_solicitation* IcmpLayer::getRouterSolicitationData()
365
0
  {
366
0
    if (!isMessageOfType(ICMP_ROUTER_SOL))
367
0
      return nullptr;
368
369
0
    return reinterpret_cast<icmp_router_solicitation*>(m_Data);
370
0
  }
371
372
  icmp_router_solicitation* IcmpLayer::setRouterSolicitationData()
373
0
  {
374
0
    if (!cleanIcmpLayer())
375
0
      return nullptr;
376
377
0
    getIcmpHeader()->type = static_cast<uint8_t>(ICMP_ROUTER_SOL);
378
379
0
    icmp_router_solicitation* header = getRouterSolicitationData();
380
0
    header->code = 0;
381
382
0
    return header;
383
0
  }
384
385
  icmp_time_exceeded* IcmpLayer::getTimeExceededData()
386
144
  {
387
144
    if (!isMessageOfType(ICMP_TIME_EXCEEDED))
388
0
      return nullptr;
389
390
144
    return reinterpret_cast<icmp_time_exceeded*>(m_Data);
391
144
  }
392
393
  icmp_time_exceeded* IcmpLayer::setTimeExceededData(uint8_t code, IPv4Layer* ipHeader, Layer* l4Header)
394
72
  {
395
72
    if (code > 1)
396
0
    {
397
0
      PCPP_LOG_ERROR("Unknown code " << (int)code << " for ICMP time exceeded data");
398
0
      return nullptr;
399
0
    }
400
401
72
    if (!cleanIcmpLayer())
402
0
      return nullptr;
403
404
72
    if (!this->extendLayer(m_DataLen, sizeof(icmp_time_exceeded) - sizeof(icmphdr)))
405
0
      return nullptr;
406
407
72
    getIcmpHeader()->type = static_cast<uint8_t>(ICMP_TIME_EXCEEDED);
408
409
72
    icmp_time_exceeded* header = getTimeExceededData();
410
72
    header->code = code;
411
72
    header->unused = 0;
412
413
72
    if (!setIpAndL4Layers(ipHeader, l4Header))
414
72
      return nullptr;
415
416
0
    return header;
417
72
  }
418
419
  icmp_param_problem* IcmpLayer::getParamProblemData()
420
128
  {
421
128
    if (!isMessageOfType(ICMP_PARAM_PROBLEM))
422
0
      return nullptr;
423
424
128
    return reinterpret_cast<icmp_param_problem*>(m_Data);
425
128
  }
426
427
  icmp_param_problem* IcmpLayer::setParamProblemData(uint8_t code, uint8_t errorOctetPointer, IPv4Layer* ipHeader,
428
                                                     Layer* l4Header)
429
64
  {
430
64
    if (code > 2)
431
0
    {
432
0
      PCPP_LOG_ERROR("Unknown code " << (int)code << " for ICMP parameter problem data");
433
0
      return nullptr;
434
0
    }
435
436
64
    if (!cleanIcmpLayer())
437
0
      return nullptr;
438
439
64
    if (!this->extendLayer(m_DataLen, sizeof(icmp_param_problem) - sizeof(icmphdr)))
440
0
      return nullptr;
441
442
64
    getIcmpHeader()->type = static_cast<uint8_t>(ICMP_PARAM_PROBLEM);
443
444
64
    icmp_param_problem* header = getParamProblemData();
445
64
    header->code = code;
446
64
    header->unused1 = 0;
447
64
    header->unused2 = 0;
448
64
    header->pointer = errorOctetPointer;
449
450
64
    if (!setIpAndL4Layers(ipHeader, l4Header))
451
64
      return nullptr;
452
453
0
    return header;
454
64
  }
455
456
  icmp_address_mask_request* IcmpLayer::getAddressMaskRequestData()
457
0
  {
458
0
    if (!isMessageOfType(ICMP_ADDRESS_MASK_REQUEST))
459
0
      return nullptr;
460
461
0
    return reinterpret_cast<icmp_address_mask_request*>(m_Data);
462
0
  }
463
464
  icmp_address_mask_request* IcmpLayer::setAddressMaskRequestData(uint16_t id, uint16_t sequence, IPv4Address mask)
465
0
  {
466
0
    if (!cleanIcmpLayer())
467
0
      return nullptr;
468
469
0
    if (!this->extendLayer(m_DataLen, sizeof(icmp_address_mask_request) - sizeof(icmphdr)))
470
0
      return nullptr;
471
472
0
    getIcmpHeader()->type = static_cast<uint8_t>(ICMP_ADDRESS_MASK_REQUEST);
473
474
0
    icmp_address_mask_request* header = getAddressMaskRequestData();
475
0
    header->code = 0;
476
0
    header->id = htobe16(id);
477
0
    header->sequence = htobe16(sequence);
478
0
    header->addressMask = mask.toInt();
479
480
0
    return header;
481
0
  }
482
483
  icmp_address_mask_reply* IcmpLayer::getAddressMaskReplyData()
484
690
  {
485
690
    if (!isMessageOfType(ICMP_ADDRESS_MASK_REPLY))
486
0
      return nullptr;
487
488
690
    return reinterpret_cast<icmp_address_mask_reply*>(m_Data);
489
690
  }
490
491
  icmp_address_mask_reply* IcmpLayer::setAddressMaskReplyData(uint16_t id, uint16_t sequence, IPv4Address mask)
492
345
  {
493
345
    if (!cleanIcmpLayer())
494
0
      return nullptr;
495
496
345
    if (!this->extendLayer(m_DataLen, sizeof(icmp_address_mask_reply) - sizeof(icmphdr)))
497
0
      return nullptr;
498
499
345
    getIcmpHeader()->type = static_cast<uint8_t>(ICMP_ADDRESS_MASK_REPLY);
500
501
345
    icmp_address_mask_reply* header = getAddressMaskReplyData();
502
345
    header->code = 0;
503
345
    header->id = htobe16(id);
504
345
    header->sequence = htobe16(sequence);
505
345
    header->addressMask = htobe32(mask.toInt());
506
507
345
    return header;
508
345
  }
509
510
  icmp_info_request* IcmpLayer::getInfoRequestData()
511
0
  {
512
0
    if (!isMessageOfType(ICMP_INFO_REQUEST))
513
0
      return nullptr;
514
515
0
    return reinterpret_cast<icmp_info_request*>(m_Data);
516
0
  }
517
518
  icmp_info_request* IcmpLayer::setInfoRequestData(uint16_t id, uint16_t sequence)
519
0
  {
520
0
    if (!cleanIcmpLayer())
521
0
      return nullptr;
522
523
0
    if (!this->extendLayer(m_DataLen, sizeof(icmp_info_request) - sizeof(icmphdr)))
524
0
      return nullptr;
525
526
0
    getIcmpHeader()->type = static_cast<uint8_t>(ICMP_INFO_REQUEST);
527
528
0
    icmp_info_request* header = getInfoRequestData();
529
0
    header->code = 0;
530
0
    header->id = htobe16(id);
531
0
    header->sequence = htobe16(sequence);
532
533
0
    return header;
534
0
  }
535
536
  icmp_info_reply* IcmpLayer::getInfoReplyData()
537
2.30k
  {
538
2.30k
    if (!isMessageOfType(ICMP_INFO_REPLY))
539
0
      return nullptr;
540
541
2.30k
    return reinterpret_cast<icmp_info_reply*>(m_Data);
542
2.30k
  }
543
544
  icmp_info_reply* IcmpLayer::setInfoReplyData(uint16_t id, uint16_t sequence)
545
1.15k
  {
546
1.15k
    if (!cleanIcmpLayer())
547
0
      return nullptr;
548
549
1.15k
    if (!this->extendLayer(m_DataLen, sizeof(icmp_info_reply) - sizeof(icmphdr)))
550
0
      return nullptr;
551
552
1.15k
    getIcmpHeader()->type = static_cast<uint8_t>(ICMP_INFO_REPLY);
553
554
1.15k
    icmp_info_reply* header = getInfoReplyData();
555
1.15k
    header->code = 0;
556
1.15k
    header->id = htobe16(id);
557
1.15k
    header->sequence = htobe16(sequence);
558
559
1.15k
    return header;
560
1.15k
  }
561
562
  void IcmpLayer::parseNextLayer()
563
21.0k
  {
564
21.0k
    size_t headerLen = getHeaderLen();
565
566
21.0k
    auto payloadPtr = m_Data + headerLen;
567
21.0k
    auto payloadLen = m_DataLen - headerLen;
568
569
21.0k
    switch (getMessageType())
570
21.0k
    {
571
3.24k
    case ICMP_DEST_UNREACHABLE:
572
3.51k
    case ICMP_SOURCE_QUENCH:
573
3.96k
    case ICMP_TIME_EXCEEDED:
574
4.47k
    case ICMP_REDIRECT:
575
4.73k
    case ICMP_PARAM_PROBLEM:
576
4.73k
    {
577
4.73k
      tryConstructNextLayerWithFallback<IPv4Layer, PayloadLayer>(payloadPtr, payloadLen);
578
4.73k
      break;
579
4.47k
    }
580
16.2k
    default:
581
16.2k
      if (m_DataLen > headerLen)
582
8.84k
      {
583
8.84k
        constructNextLayer<PayloadLayer>(payloadPtr, payloadLen);
584
8.84k
      }
585
16.2k
      break;
586
21.0k
    }
587
21.0k
  }
588
589
  size_t IcmpLayer::getHeaderLen() const
590
35.3k
  {
591
35.3k
    IcmpMessageType type = getMessageType();
592
35.3k
    size_t routerAdvSize = 0;
593
35.3k
    switch (type)
594
35.3k
    {
595
4.66k
    case ICMP_ECHO_REQUEST:
596
10.5k
    case ICMP_ECHO_REPLY:
597
10.5k
      return m_DataLen;
598
341
    case ICMP_TIMESTAMP_REQUEST:
599
1.89k
    case ICMP_TIMESTAMP_REPLY:
600
1.89k
      return sizeof(icmp_timestamp_request);
601
0
    case ICMP_ROUTER_SOL:
602
0
    case ICMP_INFO_REQUEST:
603
10.3k
    case ICMP_INFO_REPLY:
604
10.3k
    case ICMP_UNSUPPORTED:
605
10.3k
      return sizeof(icmphdr);
606
3.42k
    case ICMP_ADDRESS_MASK_REPLY:
607
3.42k
    case ICMP_ADDRESS_MASK_REQUEST:
608
3.42k
      return sizeof(icmp_address_mask_request);
609
5.20k
    case ICMP_DEST_UNREACHABLE:
610
5.20k
      return sizeof(icmp_destination_unreachable);
611
889
    case ICMP_REDIRECT:
612
889
      return sizeof(icmp_redirect);
613
744
    case ICMP_TIME_EXCEEDED:
614
1.21k
    case ICMP_SOURCE_QUENCH:
615
1.21k
      return sizeof(icmp_time_exceeded);
616
512
    case ICMP_PARAM_PROBLEM:
617
512
      return sizeof(icmp_param_problem);
618
1.25k
    case ICMP_ROUTER_ADV:
619
      // clang-format off
620
1.25k
      routerAdvSize = sizeof(icmp_router_advertisement_hdr) + (getRouterAdvertisementData()->header->advertisementCount * sizeof(icmp_router_address_structure));
621
      // clang-format on
622
1.25k
      if (routerAdvSize > m_DataLen)
623
1.23k
        return m_DataLen;
624
13
      return routerAdvSize;
625
0
    default:
626
0
      return sizeof(icmphdr);
627
35.3k
    }
628
35.3k
  }
629
630
  void IcmpLayer::computeCalculateFields()
631
3.91k
  {
632
    // calculate checksum
633
3.91k
    getIcmpHeader()->checksum = 0;
634
635
3.91k
    size_t icmpLen = 0;
636
3.91k
    Layer* curLayer = this;
637
11.6k
    while (curLayer != nullptr)
638
7.75k
    {
639
7.75k
      icmpLen += curLayer->getHeaderLen();
640
7.75k
      curLayer = curLayer->getNextLayer();
641
7.75k
    }
642
643
3.91k
    ScalarBuffer<uint16_t> buffer;
644
3.91k
    buffer.buffer = reinterpret_cast<uint16_t*>(getIcmpHeader());
645
3.91k
    buffer.len = icmpLen;
646
3.91k
    size_t checksum = computeChecksum(&buffer, 1);
647
648
3.91k
    getIcmpHeader()->checksum = htobe16(checksum);
649
3.91k
  }
650
651
  std::string IcmpLayer::toString() const
652
7.83k
  {
653
7.83k
    std::string messageTypeAsString;
654
7.83k
    IcmpMessageType type = getMessageType();
655
7.83k
    switch (type)
656
7.83k
    {
657
1.44k
    case ICMP_ECHO_REPLY:
658
1.44k
      messageTypeAsString = "Echo (ping) reply";
659
1.44k
      break;
660
952
    case ICMP_DEST_UNREACHABLE:
661
952
      messageTypeAsString = "Destination unreachable";
662
952
      break;
663
134
    case ICMP_SOURCE_QUENCH:
664
134
      messageTypeAsString = "Source quench (flow control)";
665
134
      break;
666
254
    case ICMP_REDIRECT:
667
254
      messageTypeAsString = "Redirect";
668
254
      break;
669
982
    case ICMP_ECHO_REQUEST:
670
982
      messageTypeAsString = "Echo (ping) request";
671
982
      break;
672
356
    case ICMP_ROUTER_ADV:
673
356
      messageTypeAsString = "Router advertisement";
674
356
      break;
675
0
    case ICMP_ROUTER_SOL:
676
0
      messageTypeAsString = "Router solicitation";
677
0
      break;
678
144
    case ICMP_TIME_EXCEEDED:
679
144
      messageTypeAsString = "Time-to-live exceeded";
680
144
      break;
681
128
    case ICMP_PARAM_PROBLEM:
682
128
      messageTypeAsString = "Parameter problem: bad IP header";
683
128
      break;
684
62
    case ICMP_TIMESTAMP_REQUEST:
685
62
      messageTypeAsString = "Timestamp request";
686
62
      break;
687
388
    case ICMP_TIMESTAMP_REPLY:
688
388
      messageTypeAsString = "Timestamp reply";
689
388
      break;
690
0
    case ICMP_INFO_REQUEST:
691
0
      messageTypeAsString = "Information request";
692
0
      break;
693
2.30k
    case ICMP_INFO_REPLY:
694
2.30k
      messageTypeAsString = "Information reply";
695
2.30k
      break;
696
0
    case ICMP_ADDRESS_MASK_REQUEST:
697
0
      messageTypeAsString = "Address mask request";
698
0
      break;
699
690
    case ICMP_ADDRESS_MASK_REPLY:
700
690
      messageTypeAsString = "Address mask reply";
701
690
      break;
702
0
    default:
703
0
      messageTypeAsString = "Unknown";
704
0
      break;
705
7.83k
    }
706
707
7.83k
    std::ostringstream typeStream;
708
7.83k
    typeStream << (int)getIcmpHeader()->type;
709
710
7.83k
    return "ICMP Layer, " + messageTypeAsString + " (type: " + typeStream.str() + ")";
711
7.83k
  }
712
713
  static constexpr const char* icmpMessageTypeToString(IcmpMessageType type)
714
0
  {
715
0
    switch (type)
716
0
    {
717
0
    case ICMP_ECHO_REPLY:
718
0
      return "EchoReply";
719
0
    case ICMP_DEST_UNREACHABLE:
720
0
      return "DestinationUnreachable";
721
0
    case ICMP_SOURCE_QUENCH:
722
0
      return "SourceQuench";
723
0
    case ICMP_REDIRECT:
724
0
      return "Redirect";
725
0
    case ICMP_ECHO_REQUEST:
726
0
      return "EchoRequest";
727
0
    case ICMP_ROUTER_ADV:
728
0
      return "RouterAdvertisement";
729
0
    case ICMP_ROUTER_SOL:
730
0
      return "RouterSolicitation";
731
0
    case ICMP_TIME_EXCEEDED:
732
0
      return "TimeExceeded";
733
0
    case ICMP_PARAM_PROBLEM:
734
0
      return "ParameterProblem";
735
0
    case ICMP_TIMESTAMP_REQUEST:
736
0
      return "TimestampRequest";
737
0
    case ICMP_TIMESTAMP_REPLY:
738
0
      return "TimestampReply";
739
0
    case ICMP_INFO_REQUEST:
740
0
      return "InformationRequest";
741
0
    case ICMP_INFO_REPLY:
742
0
      return "InformationReply";
743
0
    case ICMP_ADDRESS_MASK_REQUEST:
744
0
      return "AddressMaskRequest";
745
0
    case ICMP_ADDRESS_MASK_REPLY:
746
0
      return "AddressMaskReply";
747
0
    default:
748
0
      return "Unknown";
749
0
    }
750
0
  }
751
752
  const FieldDescriptor IcmpLayer::SerializedFields::Type{ Layer::SerializedFields::MaxID + 1, "type" };
753
  const FieldDescriptor IcmpLayer::SerializedFields::TypeName{ Layer::SerializedFields::MaxID + 2, "typeName" };
754
  const FieldDescriptor IcmpLayer::SerializedFields::Code{ Layer::SerializedFields::MaxID + 3, "code" };
755
  const FieldDescriptor IcmpLayer::SerializedFields::Checksum{ Layer::SerializedFields::MaxID + 4, "checksum" };
756
  const FieldDescriptor IcmpLayer::SerializedFields::Id{ Layer::SerializedFields::MaxID + 5, "id" };
757
  const FieldDescriptor IcmpLayer::SerializedFields::Sequence{ Layer::SerializedFields::MaxID + 6, "sequence" };
758
  const FieldDescriptor IcmpLayer::SerializedFields::Timestamp{ Layer::SerializedFields::MaxID + 7, "timestamp" };
759
  const FieldDescriptor IcmpLayer::SerializedFields::OriginateTimestamp{ Layer::SerializedFields::MaxID + 8,
760
                                                                       "originateTimestamp" };
761
  const FieldDescriptor IcmpLayer::SerializedFields::ReceiveTimestamp{ Layer::SerializedFields::MaxID + 9,
762
                                                                     "receiveTimestamp" };
763
  const FieldDescriptor IcmpLayer::SerializedFields::TransmitTimestamp{ Layer::SerializedFields::MaxID + 10,
764
                                                                      "transmitTimestamp" };
765
  const FieldDescriptor IcmpLayer::SerializedFields::NextHopMTU{ Layer::SerializedFields::MaxID + 11, "nextHopMTU" };
766
  const FieldDescriptor IcmpLayer::SerializedFields::GatewayAddress{ Layer::SerializedFields::MaxID + 12,
767
                                                                   "gatewayAddress" };
768
  const FieldDescriptor IcmpLayer::SerializedFields::AddressMask{ Layer::SerializedFields::MaxID + 13,
769
                                                                "addressMask" };
770
  const FieldDescriptor IcmpLayer::SerializedFields::Pointer{ Layer::SerializedFields::MaxID + 14, "pointer" };
771
  const FieldDescriptor IcmpLayer::SerializedFields::AddressEntrySize{ Layer::SerializedFields::MaxID + 15,
772
                                                                     "addressEntrySize" };
773
  const FieldDescriptor IcmpLayer::SerializedFields::Lifetime{ Layer::SerializedFields::MaxID + 16, "lifetime" };
774
  const FieldDescriptor IcmpLayer::SerializedFields::RouterAddresses{ Layer::SerializedFields::MaxID + 17,
775
                                                                    "routerAddresses" };
776
  const FieldDescriptor IcmpLayer::SerializedFields::RouterAddressEntry{ 0, "routerAddressEntry" };
777
  const FieldDescriptor IcmpLayer::SerializedFields::RouterAddress{ 0, "routerAddress" };
778
  const FieldDescriptor IcmpLayer::SerializedFields::PreferenceLevel{ 1, "preferenceLevel" };
779
780
  void IcmpLayer::serializeLayer(ObjectScope& serializer) const
781
0
  {
782
0
    serializer.writeField(SerializedFields::Type, getIcmpHeader()->type);
783
0
    serializer.writeField(SerializedFields::TypeName, icmpMessageTypeToString(getMessageType()));
784
0
    serializer.writeField(SerializedFields::Code, getIcmpHeader()->code);
785
0
    serializer.writeHexField(SerializedFields::Checksum, be16toh(getIcmpHeader()->checksum));
786
787
0
    switch (getMessageType())
788
0
    {
789
0
    case ICMP_ECHO_REQUEST:
790
0
    case ICMP_ECHO_REPLY:
791
0
    {
792
0
      auto* echo = (getMessageType() == ICMP_ECHO_REQUEST) ? const_cast<IcmpLayer*>(this)->getEchoRequestData()
793
0
                                                           : const_cast<IcmpLayer*>(this)->getEchoReplyData();
794
0
      if (echo && echo->header)
795
0
      {
796
0
        serializer.writeField(SerializedFields::Id, be16toh(echo->header->id));
797
0
        serializer.writeField(SerializedFields::Sequence, be16toh(echo->header->sequence));
798
0
        if (echo->header->timestamp != 0)
799
0
        {
800
0
          serializer.writeField(SerializedFields::Timestamp, echo->header->timestamp);
801
0
        }
802
0
      }
803
0
      break;
804
0
    }
805
0
    case ICMP_TIMESTAMP_REQUEST:
806
0
    case ICMP_TIMESTAMP_REPLY:
807
0
    {
808
0
      auto* ts = (getMessageType() == ICMP_TIMESTAMP_REQUEST)
809
0
                     ? const_cast<IcmpLayer*>(this)->getTimestampRequestData()
810
0
                     : const_cast<IcmpLayer*>(this)->getTimestampReplyData();
811
0
      if (ts)
812
0
      {
813
0
        serializer.writeField(SerializedFields::Id, be16toh(ts->id));
814
0
        serializer.writeField(SerializedFields::Sequence, be16toh(ts->sequence));
815
0
        serializer.writeField(SerializedFields::OriginateTimestamp, be32toh(ts->originateTimestamp));
816
0
        serializer.writeField(SerializedFields::ReceiveTimestamp, be32toh(ts->receiveTimestamp));
817
0
        serializer.writeField(SerializedFields::TransmitTimestamp, be32toh(ts->transmitTimestamp));
818
0
      }
819
0
      break;
820
0
    }
821
0
    case ICMP_DEST_UNREACHABLE:
822
0
    {
823
0
      auto* unreach = const_cast<IcmpLayer*>(this)->getDestUnreachableData();
824
0
      if (unreach)
825
0
      {
826
0
        serializer.writeField(SerializedFields::NextHopMTU, be16toh(unreach->nextHopMTU));
827
0
      }
828
0
      break;
829
0
    }
830
0
    case ICMP_REDIRECT:
831
0
    {
832
0
      auto* redir = const_cast<IcmpLayer*>(this)->getRedirectData();
833
0
      if (redir)
834
0
      {
835
0
        serializer.writeField(SerializedFields::GatewayAddress, IPv4Address(redir->gatewayAddress).toString());
836
0
      }
837
0
      break;
838
0
    }
839
0
    case ICMP_PARAM_PROBLEM:
840
0
    {
841
0
      auto* param = const_cast<IcmpLayer*>(this)->getParamProblemData();
842
0
      if (param)
843
0
      {
844
0
        serializer.writeField(SerializedFields::Pointer, param->pointer);
845
0
      }
846
0
      break;
847
0
    }
848
0
    case ICMP_ROUTER_ADV:
849
0
    {
850
0
      auto* adv = getRouterAdvertisementData();
851
0
      if (adv && adv->header)
852
0
      {
853
0
        serializer.writeField(SerializedFields::AddressEntrySize, adv->header->addressEntrySize);
854
0
        serializer.writeField(SerializedFields::Lifetime, be16toh(adv->header->lifetime));
855
0
        auto arr = serializer.writeArray(SerializedFields::RouterAddresses);
856
0
        for (int i = 0; i < adv->header->advertisementCount; ++i)
857
0
        {
858
0
          auto* routerAddr = adv->getRouterAddress(i);
859
0
          if (routerAddr)
860
0
          {
861
0
            auto obj = arr.writeObject(SerializedFields::RouterAddressEntry);
862
0
            obj.writeField(SerializedFields::RouterAddress, routerAddr->getAddress().toString());
863
0
            obj.writeField(SerializedFields::PreferenceLevel, routerAddr->preferenceLevel);
864
0
          }
865
0
          else
866
0
          {
867
0
            break;
868
0
          }
869
0
        }
870
0
      }
871
0
      break;
872
0
    }
873
0
    case ICMP_ADDRESS_MASK_REQUEST:
874
0
    case ICMP_ADDRESS_MASK_REPLY:
875
0
    {
876
0
      auto* mask = (getMessageType() == ICMP_ADDRESS_MASK_REQUEST)
877
0
                       ? const_cast<IcmpLayer*>(this)->getAddressMaskRequestData()
878
0
                       : const_cast<IcmpLayer*>(this)->getAddressMaskReplyData();
879
0
      if (mask)
880
0
      {
881
0
        serializer.writeField(SerializedFields::Id, be16toh(mask->id));
882
0
        serializer.writeField(SerializedFields::Sequence, be16toh(mask->sequence));
883
0
        serializer.writeField(SerializedFields::AddressMask, IPv4Address(mask->addressMask).toString());
884
0
      }
885
0
      break;
886
0
    }
887
0
    case ICMP_INFO_REQUEST:
888
0
    case ICMP_INFO_REPLY:
889
0
    {
890
0
      auto* info = (getMessageType() == ICMP_INFO_REQUEST) ? const_cast<IcmpLayer*>(this)->getInfoRequestData()
891
0
                                                           : const_cast<IcmpLayer*>(this)->getInfoReplyData();
892
0
      if (info)
893
0
      {
894
0
        serializer.writeField(SerializedFields::Id, be16toh(info->id));
895
0
        serializer.writeField(SerializedFields::Sequence, be16toh(info->sequence));
896
0
      }
897
0
      break;
898
0
    }
899
0
    default:
900
0
      break;
901
0
    }
902
0
  }
903
904
}  // namespace pcpp