Coverage Report

Created: 2026-11-12 06:49

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