Coverage Report

Created: 2026-10-17 07:07

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/PcapPlusPlus/Packet++/src/IcmpLayer.cpp
Line
Count
Source
1
0
#define LOG_MODULE PacketLogModuleIcmpLayer
2
3
#include "IcmpLayer.h"
4
#include "PayloadLayer.h"
5
#include "Packet.h"
6
#include "PacketUtils.h"
7
#include "Logger.h"
8
#include <sstream>
9
#include "EndianPortable.h"
10
11
namespace pcpp
12
{
13
14
  icmp_router_address_structure* icmp_router_advertisement::getRouterAddress(int index) const
15
0
  {
16
0
    if (index < 0 || index >= header->advertisementCount)
17
0
      return nullptr;
18
19
0
    uint8_t* headerAsByteArr = reinterpret_cast<uint8_t*>(header);
20
0
    return reinterpret_cast<icmp_router_address_structure*>(
21
0
        headerAsByteArr + sizeof(icmp_router_advertisement_hdr) + index * sizeof(icmp_router_address_structure));
22
0
  }
23
24
  void icmp_router_address_structure::setRouterAddress(IPv4Address addr, uint32_t preference)
25
0
  {
26
0
    routerAddress = addr.toInt();
27
0
    preferenceLevel = htobe32(preference);
28
0
  }
29
30
0
  IcmpLayer::IcmpLayer() : Layer()
31
0
  {
32
0
    allocData(sizeof(icmphdr));
33
0
    m_Protocol = ICMP;
34
0
  }
35
36
  IcmpMessageType IcmpLayer::getMessageType() const
37
0
  {
38
0
    uint8_t type = getIcmpHeader()->type;
39
0
    if (type > 18)
40
0
      return ICMP_UNSUPPORTED;
41
42
0
    return static_cast<IcmpMessageType>(type);
43
0
  }
44
45
  bool IcmpLayer::cleanIcmpLayer()
46
0
  {
47
    // remove all layers after
48
49
0
    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
0
    size_t headerLen = this->getHeaderLen();
59
0
    if (headerLen > sizeof(icmphdr))
60
0
    {
61
0
      if (!this->shortenLayer(sizeof(icmphdr), headerLen - sizeof(icmphdr)))
62
0
        return false;
63
0
    }
64
65
0
    return true;
66
0
  }
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
0
  {
100
0
    if (getAttachedPacket() == nullptr)
101
0
    {
102
0
      PCPP_LOG_ERROR("Cannot set ICMP data that involves IP and L4 layers on a layer not attached to a packet. "
103
0
                     "Please add the ICMP layer to a packet and try again");
104
0
      return false;
105
0
    }
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
0
  {
196
0
    if (!isMessageOfType(ICMP_TIMESTAMP_REPLY))
197
0
      return nullptr;
198
199
0
    return reinterpret_cast<icmp_timestamp_reply*>(m_Data);
200
0
  }
201
202
  icmp_timestamp_reply* IcmpLayer::setTimestampReplyData(uint16_t id, uint16_t sequence, timeval originateTimestamp,
203
                                                         timeval receiveTimestamp, timeval transmitTimestamp)
204
0
  {
205
0
    if (!cleanIcmpLayer())
206
0
      return nullptr;
207
208
0
    if (!this->extendLayer(m_DataLen, sizeof(icmp_timestamp_reply) - sizeof(icmphdr)))
209
0
      return nullptr;
210
211
0
    getIcmpHeader()->type = static_cast<uint8_t>(ICMP_TIMESTAMP_REPLY);
212
213
0
    icmp_timestamp_reply* header = getTimestampReplyData();
214
0
    header->code = 0;
215
0
    header->id = htobe16(id);
216
0
    header->sequence = htobe16(sequence);
217
0
    header->originateTimestamp = htobe32(originateTimestamp.tv_sec * 1000 + originateTimestamp.tv_usec / 1000);
218
0
    header->receiveTimestamp = htobe32(receiveTimestamp.tv_sec * 1000 + receiveTimestamp.tv_usec / 1000);
219
0
    header->transmitTimestamp = htobe32(transmitTimestamp.tv_sec * 1000 + transmitTimestamp.tv_usec / 1000);
220
221
0
    return header;
222
0
  }
223
224
  icmp_destination_unreachable* IcmpLayer::getDestUnreachableData()
225
0
  {
226
0
    if (!isMessageOfType(ICMP_DEST_UNREACHABLE))
227
0
      return nullptr;
228
229
0
    return reinterpret_cast<icmp_destination_unreachable*>(m_Data);
230
0
  }
231
232
  icmp_destination_unreachable* IcmpLayer::setDestUnreachableData(IcmpDestUnreachableCodes code, uint16_t nextHopMTU,
233
                                                                  IPv4Layer* ipHeader, Layer* l4Header)
234
0
  {
235
0
    if (!cleanIcmpLayer())
236
0
      return nullptr;
237
238
0
    if (!this->extendLayer(m_DataLen, sizeof(icmp_destination_unreachable) - sizeof(icmphdr)))
239
0
      return nullptr;
240
241
0
    getIcmpHeader()->type = static_cast<uint8_t>(ICMP_DEST_UNREACHABLE);
242
243
0
    icmp_destination_unreachable* header = getDestUnreachableData();
244
0
    header->code = code;
245
0
    header->nextHopMTU = htobe16(nextHopMTU);
246
0
    header->unused = 0;
247
248
0
    if (!setIpAndL4Layers(ipHeader, l4Header))
249
0
      return nullptr;
250
251
0
    return header;
252
0
  }
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
0
  {
318
0
    if (!isMessageOfType(ICMP_ROUTER_ADV))
319
0
      return nullptr;
320
321
0
    m_RouterAdvData.header = reinterpret_cast<icmp_router_advertisement_hdr*>(m_Data);
322
323
0
    return &m_RouterAdvData;
324
0
  }
325
326
  icmp_router_advertisement* IcmpLayer::setRouterAdvertisementData(
327
      uint8_t code, uint16_t lifetimeInSeconds, const std::vector<icmp_router_address_structure>& routerAddresses)
328
0
  {
329
0
    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
0
    if (!cleanIcmpLayer())
337
0
      return nullptr;
338
339
0
    if (!this->extendLayer(m_DataLen, sizeof(icmp_router_advertisement_hdr) +
340
0
                                          (routerAddresses.size() * sizeof(icmp_router_address_structure)) -
341
0
                                          sizeof(icmphdr)))
342
0
      return nullptr;
343
344
0
    getIcmpHeader()->type = static_cast<uint8_t>(ICMP_ROUTER_ADV);
345
346
0
    icmp_router_advertisement* header = getRouterAdvertisementData();
347
0
    header->header->code = code;
348
0
    header->header->lifetime = htobe16(lifetimeInSeconds);
349
0
    header->header->advertisementCount = static_cast<uint8_t>(routerAddresses.size());
350
0
    header->header->addressEntrySize = 2;
351
352
0
    icmp_router_address_structure* curPos = reinterpret_cast<icmp_router_address_structure*>(
353
0
        reinterpret_cast<uint8_t*>(header->header) + sizeof(icmp_router_advertisement_hdr));
354
0
    for (const auto& iter : routerAddresses)
355
0
    {
356
0
      curPos->routerAddress = iter.routerAddress;
357
0
      curPos->preferenceLevel = iter.preferenceLevel;
358
0
      curPos += 1;
359
0
    }
360
361
0
    return header;
362
0
  }
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
0
  {
387
0
    if (!isMessageOfType(ICMP_TIME_EXCEEDED))
388
0
      return nullptr;
389
390
0
    return reinterpret_cast<icmp_time_exceeded*>(m_Data);
391
0
  }
392
393
  icmp_time_exceeded* IcmpLayer::setTimeExceededData(uint8_t code, IPv4Layer* ipHeader, Layer* l4Header)
394
0
  {
395
0
    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
0
    if (!cleanIcmpLayer())
402
0
      return nullptr;
403
404
0
    if (!this->extendLayer(m_DataLen, sizeof(icmp_time_exceeded) - sizeof(icmphdr)))
405
0
      return nullptr;
406
407
0
    getIcmpHeader()->type = static_cast<uint8_t>(ICMP_TIME_EXCEEDED);
408
409
0
    icmp_time_exceeded* header = getTimeExceededData();
410
0
    header->code = code;
411
0
    header->unused = 0;
412
413
0
    if (!setIpAndL4Layers(ipHeader, l4Header))
414
0
      return nullptr;
415
416
0
    return header;
417
0
  }
418
419
  icmp_param_problem* IcmpLayer::getParamProblemData()
420
0
  {
421
0
    if (!isMessageOfType(ICMP_PARAM_PROBLEM))
422
0
      return nullptr;
423
424
0
    return reinterpret_cast<icmp_param_problem*>(m_Data);
425
0
  }
426
427
  icmp_param_problem* IcmpLayer::setParamProblemData(uint8_t code, uint8_t errorOctetPointer, IPv4Layer* ipHeader,
428
                                                     Layer* l4Header)
429
0
  {
430
0
    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
0
    if (!cleanIcmpLayer())
437
0
      return nullptr;
438
439
0
    if (!this->extendLayer(m_DataLen, sizeof(icmp_param_problem) - sizeof(icmphdr)))
440
0
      return nullptr;
441
442
0
    getIcmpHeader()->type = static_cast<uint8_t>(ICMP_PARAM_PROBLEM);
443
444
0
    icmp_param_problem* header = getParamProblemData();
445
0
    header->code = code;
446
0
    header->unused1 = 0;
447
0
    header->unused2 = 0;
448
0
    header->pointer = errorOctetPointer;
449
450
0
    if (!setIpAndL4Layers(ipHeader, l4Header))
451
0
      return nullptr;
452
453
0
    return header;
454
0
  }
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
0
  {
485
0
    if (!isMessageOfType(ICMP_ADDRESS_MASK_REPLY))
486
0
      return nullptr;
487
488
0
    return reinterpret_cast<icmp_address_mask_reply*>(m_Data);
489
0
  }
490
491
  icmp_address_mask_reply* IcmpLayer::setAddressMaskReplyData(uint16_t id, uint16_t sequence, IPv4Address mask)
492
0
  {
493
0
    if (!cleanIcmpLayer())
494
0
      return nullptr;
495
496
0
    if (!this->extendLayer(m_DataLen, sizeof(icmp_address_mask_reply) - sizeof(icmphdr)))
497
0
      return nullptr;
498
499
0
    getIcmpHeader()->type = static_cast<uint8_t>(ICMP_ADDRESS_MASK_REPLY);
500
501
0
    icmp_address_mask_reply* header = getAddressMaskReplyData();
502
0
    header->code = 0;
503
0
    header->id = htobe16(id);
504
0
    header->sequence = htobe16(sequence);
505
0
    header->addressMask = htobe32(mask.toInt());
506
507
0
    return header;
508
0
  }
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
0
  {
538
0
    if (!isMessageOfType(ICMP_INFO_REPLY))
539
0
      return nullptr;
540
541
0
    return reinterpret_cast<icmp_info_reply*>(m_Data);
542
0
  }
543
544
  icmp_info_reply* IcmpLayer::setInfoReplyData(uint16_t id, uint16_t sequence)
545
0
  {
546
0
    if (!cleanIcmpLayer())
547
0
      return nullptr;
548
549
0
    if (!this->extendLayer(m_DataLen, sizeof(icmp_info_reply) - sizeof(icmphdr)))
550
0
      return nullptr;
551
552
0
    getIcmpHeader()->type = static_cast<uint8_t>(ICMP_INFO_REPLY);
553
554
0
    icmp_info_reply* header = getInfoReplyData();
555
0
    header->code = 0;
556
0
    header->id = htobe16(id);
557
0
    header->sequence = htobe16(sequence);
558
559
0
    return header;
560
0
  }
561
562
  void IcmpLayer::parseNextLayer()
563
0
  {
564
0
    size_t headerLen = getHeaderLen();
565
566
0
    auto payloadPtr = m_Data + headerLen;
567
0
    auto payloadLen = m_DataLen - headerLen;
568
569
0
    switch (getMessageType())
570
0
    {
571
0
    case ICMP_DEST_UNREACHABLE:
572
0
    case ICMP_SOURCE_QUENCH:
573
0
    case ICMP_TIME_EXCEEDED:
574
0
    case ICMP_REDIRECT:
575
0
    case ICMP_PARAM_PROBLEM:
576
0
    {
577
0
      tryConstructNextLayerWithFallback<IPv4Layer, PayloadLayer>(payloadPtr, payloadLen);
578
0
      break;
579
0
    }
580
0
    default:
581
0
      if (m_DataLen > headerLen)
582
0
      {
583
0
        constructNextLayer<PayloadLayer>(payloadPtr, payloadLen);
584
0
      }
585
0
      break;
586
0
    }
587
0
  }
588
589
  size_t IcmpLayer::getHeaderLen() const
590
0
  {
591
0
    IcmpMessageType type = getMessageType();
592
0
    size_t routerAdvSize = 0;
593
0
    switch (type)
594
0
    {
595
0
    case ICMP_ECHO_REQUEST:
596
0
    case ICMP_ECHO_REPLY:
597
0
      return m_DataLen;
598
0
    case ICMP_TIMESTAMP_REQUEST:
599
0
    case ICMP_TIMESTAMP_REPLY:
600
0
      return sizeof(icmp_timestamp_request);
601
0
    case ICMP_ROUTER_SOL:
602
0
    case ICMP_INFO_REQUEST:
603
0
    case ICMP_INFO_REPLY:
604
0
    case ICMP_UNSUPPORTED:
605
0
      return sizeof(icmphdr);
606
0
    case ICMP_ADDRESS_MASK_REPLY:
607
0
    case ICMP_ADDRESS_MASK_REQUEST:
608
0
      return sizeof(icmp_address_mask_request);
609
0
    case ICMP_DEST_UNREACHABLE:
610
0
      return sizeof(icmp_destination_unreachable);
611
0
    case ICMP_REDIRECT:
612
0
      return sizeof(icmp_redirect);
613
0
    case ICMP_TIME_EXCEEDED:
614
0
    case ICMP_SOURCE_QUENCH:
615
0
      return sizeof(icmp_time_exceeded);
616
0
    case ICMP_PARAM_PROBLEM:
617
0
      return sizeof(icmp_param_problem);
618
0
    case ICMP_ROUTER_ADV:
619
      // clang-format off
620
0
      routerAdvSize = sizeof(icmp_router_advertisement_hdr) + (getRouterAdvertisementData()->header->advertisementCount * sizeof(icmp_router_address_structure));
621
      // clang-format on
622
0
      if (routerAdvSize > m_DataLen)
623
0
        return m_DataLen;
624
0
      return routerAdvSize;
625
0
    default:
626
0
      return sizeof(icmphdr);
627
0
    }
628
0
  }
629
630
  void IcmpLayer::computeCalculateFields()
631
0
  {
632
    // calculate checksum
633
0
    getIcmpHeader()->checksum = 0;
634
635
0
    size_t icmpLen = 0;
636
0
    Layer* curLayer = this;
637
0
    while (curLayer != nullptr)
638
0
    {
639
0
      icmpLen += curLayer->getHeaderLen();
640
0
      curLayer = curLayer->getNextLayer();
641
0
    }
642
643
0
    ScalarBuffer<uint16_t> buffer;
644
0
    buffer.buffer = reinterpret_cast<uint16_t*>(getIcmpHeader());
645
0
    buffer.len = icmpLen;
646
0
    size_t checksum = computeChecksum(&buffer, 1);
647
648
0
    getIcmpHeader()->checksum = htobe16(checksum);
649
0
  }
650
651
  std::string IcmpLayer::toString() const
652
0
  {
653
0
    std::string messageTypeAsString;
654
0
    IcmpMessageType type = getMessageType();
655
0
    switch (type)
656
0
    {
657
0
    case ICMP_ECHO_REPLY:
658
0
      messageTypeAsString = "Echo (ping) reply";
659
0
      break;
660
0
    case ICMP_DEST_UNREACHABLE:
661
0
      messageTypeAsString = "Destination unreachable";
662
0
      break;
663
0
    case ICMP_SOURCE_QUENCH:
664
0
      messageTypeAsString = "Source quench (flow control)";
665
0
      break;
666
0
    case ICMP_REDIRECT:
667
0
      messageTypeAsString = "Redirect";
668
0
      break;
669
0
    case ICMP_ECHO_REQUEST:
670
0
      messageTypeAsString = "Echo (ping) request";
671
0
      break;
672
0
    case ICMP_ROUTER_ADV:
673
0
      messageTypeAsString = "Router advertisement";
674
0
      break;
675
0
    case ICMP_ROUTER_SOL:
676
0
      messageTypeAsString = "Router solicitation";
677
0
      break;
678
0
    case ICMP_TIME_EXCEEDED:
679
0
      messageTypeAsString = "Time-to-live exceeded";
680
0
      break;
681
0
    case ICMP_PARAM_PROBLEM:
682
0
      messageTypeAsString = "Parameter problem: bad IP header";
683
0
      break;
684
0
    case ICMP_TIMESTAMP_REQUEST:
685
0
      messageTypeAsString = "Timestamp request";
686
0
      break;
687
0
    case ICMP_TIMESTAMP_REPLY:
688
0
      messageTypeAsString = "Timestamp reply";
689
0
      break;
690
0
    case ICMP_INFO_REQUEST:
691
0
      messageTypeAsString = "Information request";
692
0
      break;
693
0
    case ICMP_INFO_REPLY:
694
0
      messageTypeAsString = "Information reply";
695
0
      break;
696
0
    case ICMP_ADDRESS_MASK_REQUEST:
697
0
      messageTypeAsString = "Address mask request";
698
0
      break;
699
0
    case ICMP_ADDRESS_MASK_REPLY:
700
0
      messageTypeAsString = "Address mask reply";
701
0
      break;
702
0
    default:
703
0
      messageTypeAsString = "Unknown";
704
0
      break;
705
0
    }
706
707
0
    std::ostringstream typeStream;
708
0
    typeStream << (int)getIcmpHeader()->type;
709
710
0
    return "ICMP Layer, " + messageTypeAsString + " (type: " + typeStream.str() + ")";
711
0
  }
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