Coverage Report

Created: 2025-07-11 07:47

/src/PcapPlusPlus/Packet++/header/IcmpLayer.h
Line
Count
Source (jump to first uncovered line)
1
#pragma once
2
3
#include "Layer.h"
4
#include "IPv4Layer.h"
5
#ifdef _MSC_VER
6
# include <winsock2.h>
7
#else
8
# include <sys/time.h>
9
#endif
10
#include <vector>
11
12
/// @file
13
14
/// @namespace pcpp
15
/// @brief The main namespace for the PcapPlusPlus lib
16
namespace pcpp
17
{
18
19
  /// @struct icmphdr
20
  /// Represents ICMP basic protocol header (common for all ICMP message types)
21
#pragma pack(push, 1)
22
  typedef struct icmphdr
23
  {
24
    /// message type
25
    uint8_t type;
26
    /// message code
27
    uint8_t code;
28
    /// message checksum
29
    uint16_t checksum;
30
  } icmphdr;
31
#pragma pack(pop)
32
  static_assert(sizeof(icmphdr) == 4, "icmphdr size is not 4 bytes");
33
34
  /// An enum of all supported ICMP message types
35
  enum IcmpMessageType
36
  {
37
    /// ICMP echo (ping) reply message
38
    ICMP_ECHO_REPLY = 0,
39
    /// ICMP destination unreachable message
40
    ICMP_DEST_UNREACHABLE = 3,
41
    /// ICMP source quench message
42
    ICMP_SOURCE_QUENCH = 4,
43
    /// ICMP redirect message
44
    ICMP_REDIRECT = 5,
45
    /// ICMP echo (ping) request message
46
    ICMP_ECHO_REQUEST = 8,
47
    /// ICMP router advertisement message
48
    ICMP_ROUTER_ADV = 9,
49
    /// ICMP router soliciatation message
50
    ICMP_ROUTER_SOL = 10,
51
    /// ICMP time-to-live excceded message
52
    ICMP_TIME_EXCEEDED = 11,
53
    /// ICMP parameter problem message
54
    ICMP_PARAM_PROBLEM = 12,
55
    /// ICMP timestamp request message
56
    ICMP_TIMESTAMP_REQUEST = 13,
57
    /// ICMP timestamp reply message
58
    ICMP_TIMESTAMP_REPLY = 14,
59
    /// ICMP information request message
60
    ICMP_INFO_REQUEST = 15,
61
    /// ICMP information reply message
62
    ICMP_INFO_REPLY = 16,
63
    /// ICMP address mask request message
64
    ICMP_ADDRESS_MASK_REQUEST = 17,
65
    /// ICMP address mask reply message
66
    ICMP_ADDRESS_MASK_REPLY = 18,
67
    /// ICMP message type unsupported by PcapPlusPlus
68
    ICMP_UNSUPPORTED = 255
69
  };
70
71
  /// An enum for all possible codes for a destination unreachable message type
72
  /// Documentation is taken from Wikipedia: https://en.wikipedia.org/wiki/Internet_Control_Message_Protocol
73
  enum IcmpDestUnreachableCodes
74
  {
75
    /// Network unreachable error
76
    IcmpNetworkUnreachable = 0,
77
    /// Host unreachable error
78
    IcmpHostUnreachable = 1,
79
    /// Protocol unreachable error (the designated transport protocol is not supported)
80
    IcmpProtocolUnreachable = 2,
81
    /// Port unreachable error (the designated protocol is unable to inform the host of the incoming message)
82
    IcmpPortUnreachable = 3,
83
    /// The datagram is too big. Packet fragmentation is required but the 'don't fragment' (DF) flag is on
84
    IcmpDatagramTooBig = 4,
85
    /// Source route failed error
86
    IcmpSourceRouteFailed = 5,
87
    /// Destination network unknown error
88
    IcmpDestinationNetworkUnknown = 6,
89
    /// Destination host unknown error
90
    IcmpDestinationHostUnknown = 7,
91
    /// Source host isolated error
92
    IcmpSourceHostIsolated = 8,
93
    /// The destination network is administratively prohibited
94
    IcmpDestinationNetworkProhibited = 9,
95
    /// The destination host is administratively prohibited
96
    IcmpDestinationHostProhibited = 10,
97
    /// The network is unreachable for Type Of Service
98
    IcmpNetworkUnreachableForTypeOfService = 11,
99
    /// The host is unreachable for Type Of Service
100
    IcmpHostUnreachableForTypeOfService = 12,
101
    /// Communication administratively prohibited (administrative filtering prevents
102
    /// packet from being forwarded)
103
    IcmpCommunicationProhibited = 13,
104
    /// Host precedence violation (indicates the requested precedence is not permitted for
105
    /// the combination of host or network and port)
106
    IcmpHostPrecedenceViolation = 14,
107
    /// Precedence cutoff in effect (precedence of datagram is below the level set by
108
    /// the network administrators)
109
    IcmpPrecedenceCutoff = 15
110
  };
111
112
  /// @struct icmp_echo_hdr
113
  /// ICMP echo (ping) request/reply message structure
114
#pragma pack(push, 1)
115
  typedef struct icmp_echo_hdr : icmphdr
116
  {
117
    /// the echo (ping) request identifier
118
    uint16_t id;
119
    /// the echo (ping) request sequence number
120
    uint16_t sequence;
121
    /// a timestamp of when the message was sent
122
    uint64_t timestamp;
123
  } icmp_echo_hdr;
124
#pragma pack(pop)
125
  static_assert(sizeof(icmp_echo_hdr) == 16, "icmp_echo_hdr size is not 16 bytes");
126
127
  /// @struct icmp_echo_request
128
  /// ICMP echo (ping) request/reply message structure
129
  typedef struct icmp_echo_request
130
  {
131
    /// a pointer to the header data
132
    icmp_echo_hdr* header;
133
    /// most echo requests/replies contain some payload data. This is the data length
134
    size_t dataLength;
135
    /// most echo requests/replies contain some payload data. This is a pointer to this data
136
    uint8_t* data;
137
  } icmp_echo_request;
138
139
  /// @typedef icmp_echo_reply
140
  /// ICMP echo (ping) reply message structure, same as icmp_echo_request
141
  typedef icmp_echo_request icmp_echo_reply;
142
143
  /// @struct icmp_timestamp_request
144
  /// ICMP timestamp request message structure
145
#pragma pack(push, 1)
146
  typedef struct icmp_timestamp_request : icmphdr
147
  {
148
    /// the timestamp request identifier
149
    uint16_t id;
150
    /// the timestamp request sequence number
151
    uint16_t sequence;
152
    /// the time (in milliseconds since midnight) the sender last touched the packet
153
    uint32_t originateTimestamp;
154
    /// relevant for timestamp reply only - the time the echoer first touched it on receipt
155
    uint32_t receiveTimestamp;
156
    /// relevant for timestamp reply only - the time the echoer last touched the message on sending it
157
    uint32_t transmitTimestamp;
158
  } icmp_timestamp_request;
159
#pragma pack(pop)
160
  static_assert(sizeof(icmp_timestamp_request) == 20, "icmp_timestamp_request size is not 20 bytes");
161
162
  /// @typedef icmp_timestamp_reply
163
  /// ICMP timestamp reply message structure, same as icmp_timestamp_request
164
  typedef icmp_timestamp_request icmp_timestamp_reply;
165
  static_assert(sizeof(icmp_timestamp_reply) == 20, "icmp_timestamp_reply size is not 20 bytes");
166
167
  /// @struct icmp_destination_unreachable
168
  /// ICMP destination unreachable message structure
169
#pragma pack(push, 1)
170
  typedef struct icmp_destination_unreachable : icmphdr
171
  {
172
    /// unused 2 bytes
173
    uint16_t unused;
174
    /// contains the MTU of the next-hop network if a code 4 error occurs
175
    uint16_t nextHopMTU;
176
  } icmp_destination_unreachable;
177
#pragma pack(pop)
178
  static_assert(sizeof(icmp_destination_unreachable) == 8, "icmp_destination_unreachable size is not 8 bytes");
179
180
  /// @struct icmp_time_exceeded
181
  /// ICMP time-to-live exceeded message structure
182
#pragma pack(push, 1)
183
  typedef struct icmp_time_exceeded : icmphdr
184
  {
185
    /// unused 4 bytes
186
    uint32_t unused;
187
  } icmp_time_exceeded;
188
#pragma pack(pop)
189
  static_assert(sizeof(icmp_time_exceeded) == 8, "icmp_time_exceeded size is not 8 bytes");
190
191
  /// @typedef icmp_source_quench
192
  /// ICMP source quence message structure, same as icmp_time_exceeded
193
  typedef icmp_time_exceeded icmp_source_quench;
194
  static_assert(sizeof(icmp_source_quench) == 8, "icmp_source_quench size is not 8 bytes");
195
196
  /// @struct icmp_param_problem
197
  /// ICMP parameter problem message structure
198
#pragma pack(push, 1)
199
  typedef struct icmp_param_problem : icmphdr
200
  {
201
    /// in the case of an invalid IP header (Code 0), this field indicates the byte offset of the error in the
202
    /// header
203
    uint8_t pointer;
204
    /// unused 1 byte
205
    uint8_t unused1;
206
    /// unused 2 bytes
207
    uint16_t unused2;
208
  } icmp_param_problem;
209
#pragma pack(pop)
210
  static_assert(sizeof(icmp_param_problem) == 8, "icmp_param_problem size is not 8 bytes");
211
212
  /// @typedef icmp_router_solicitation
213
  /// ICMP router solicitation message structure, same as icmphdr
214
  typedef icmphdr icmp_router_solicitation;
215
  static_assert(sizeof(icmp_router_solicitation) == 4, "icmp_router_solicitation size is not 4 bytes");
216
217
  /// @struct icmp_redirect
218
  /// ICMP redirect message structure
219
#pragma pack(push, 1)
220
  typedef struct icmp_redirect : icmphdr
221
  {
222
    /// an IPv4 address of the gateway to which the redirection should be sent
223
    uint32_t gatewayAddress;
224
  } icmp_redirect;
225
#pragma pack(pop)
226
  static_assert(sizeof(icmp_redirect) == 8, "icmp_redirect size is not 8 bytes");
227
228
  /// @struct icmp_router_address_structure
229
  /// Router address structure, relevant for ICMP router advertisement message type (icmp_router_advertisement)
230
#pragma pack(push, 1)
231
  struct icmp_router_address_structure
232
  {
233
    /// the IPv4 address of the advertised router
234
    uint32_t routerAddress;
235
    /// The preferability of the router address as a default router address, relative to other router addresses
236
    /// on the same subnet. This is a twos-complement value where higher values indicate that the route is
237
    /// more preferable
238
    uint32_t preferenceLevel;
239
240
    /// Set router address structure from a given IPv4 address and preference level
241
    /// @param[in] addr IPv4 address to set
242
    /// @param[in] preference Preference level to set
243
    void setRouterAddress(IPv4Address addr, uint32_t preference);
244
245
    /// @return The IPv4 address extracted from icmp_router_address_structure#routerAddress field
246
    IPv4Address getAddress() const
247
0
    {
248
0
      return routerAddress;
249
0
    }
250
  };
251
#pragma pack(pop)
252
  static_assert(sizeof(icmp_router_address_structure) == 8, "icmp_router_address_structure size is not 8 bytes");
253
254
  /// @struct icmp_router_advertisement_hdr
255
  /// ICMP router advertisement message structure
256
#pragma pack(push, 1)
257
  typedef struct icmp_router_advertisement_hdr : icmphdr
258
  {
259
    /// the number of router advertisements in this message. Each advertisement contains one router
260
    /// address/preference level pair
261
    uint8_t advertisementCount;
262
    /// the number of 32-bit words of information for each router address entry in the list. The value is normally
263
    /// set to 2 (router address + preference level)
264
    uint8_t addressEntrySize;
265
    /// the maximum number of seconds that the router addresses in this list may be considered valid
266
    uint16_t lifetime;
267
  } icmp_router_advertisement_hdr;
268
#pragma pack(pop)
269
  static_assert(sizeof(icmp_router_advertisement_hdr) == 8, "icmp_router_advertisement_hdr size is not 8 bytes");
270
271
  /// @struct icmp_router_advertisement
272
  /// ICMP router advertisement message structure
273
  struct icmp_router_advertisement
274
  {
275
    /// a pointer to the header data on the packet
276
    icmp_router_advertisement_hdr* header;
277
278
    /// Extract router advertisement at a given index
279
    /// @param[in] index The index of the router advertisement
280
    /// @return A pointer to the router advertisement on the packet or null if index is out of range (less than zero
281
    /// or greater than the number of router advertisement records on this message, determined by advertisementCount
282
    /// field)
283
    icmp_router_address_structure* getRouterAddress(int index) const;
284
  };
285
286
  /// @struct icmp_address_mask_request
287
  /// ICMP address mask request message structure
288
#pragma pack(push, 1)
289
  typedef struct icmp_address_mask_request : icmphdr
290
  {
291
    /// the address mask request identifier
292
    uint16_t id;
293
    /// the address mask request sequence
294
    uint16_t sequence;
295
    /// the subnet mask of the requesting host
296
    uint32_t addressMask;
297
  } icmp_address_mask_request;
298
#pragma pack(pop)
299
  static_assert(sizeof(icmp_address_mask_request) == 12, "icmp_address_mask_request size is not 12 bytes");
300
301
  /// @typedef icmp_address_mask_reply
302
  /// ICMP address mask reply message structure, same as icmp_address_mask_request
303
  typedef icmp_address_mask_request icmp_address_mask_reply;
304
305
  /// @struct icmp_info_request
306
  /// ICMP information request message structure
307
#pragma pack(push, 1)
308
  typedef struct icmp_info_request : icmphdr
309
  {
310
    /// the information request identifier
311
    uint16_t id;
312
    /// the information request sequence
313
    uint16_t sequence;
314
  } icmp_info_request;
315
#pragma pack(pop)
316
  static_assert(sizeof(icmp_info_request) == 8, "icmp_info_request size is not 8 bytes");
317
318
  /// @typedef icmp_info_reply
319
  /// ICMP information reply message structure, same as icmp_info_request
320
  typedef icmp_info_request icmp_info_reply;
321
  static_assert(sizeof(icmp_info_reply) == 8, "icmp_info_reply size is not 8 bytes");
322
323
  /// @class IcmpLayer
324
  /// Represents an ICMP protocol layer (for IPv4 only)
325
  class IcmpLayer : public Layer
326
  {
327
  private:
328
    icmp_echo_request m_EchoData;
329
    mutable icmp_router_advertisement m_RouterAdvData;
330
331
    bool cleanIcmpLayer();
332
333
    bool setEchoData(IcmpMessageType echoType, uint16_t id, uint16_t sequence, uint64_t timestamp,
334
                     const uint8_t* data, size_t dataLen);
335
336
    bool setIpAndL4Layers(IPv4Layer* ipLayer, Layer* l4Layer);
337
338
  public:
339
    /// A constructor that creates the layer from an existing packet raw data
340
    /// @param[in] data A pointer to the raw data (will be casted to @ref arphdr)
341
    /// @param[in] dataLen Size of the data in bytes
342
    /// @param[in] prevLayer A pointer to the previous layer
343
    /// @param[in] packet A pointer to the Packet instance where layer will be stored in
344
    // cppcheck-suppress uninitMemberVar
345
    IcmpLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
346
13.1k
        : Layer(data, dataLen, prevLayer, packet, ICMP)
347
13.1k
    {}
348
349
    /// An empty constructor that creates a new layer with an empty ICMP header without setting the ICMP type or
350
    /// ICMP data. Call the set*Data() methods to set ICMP type and data
351
    IcmpLayer();
352
353
    ~IcmpLayer() override = default;
354
355
    /// Get a pointer to the basic ICMP header. Notice this points directly to the data, so every change will change
356
    /// the actual packet data
357
    /// @return A pointer to the @ref icmphdr
358
    icmphdr* getIcmpHeader() const
359
71.1k
    {
360
71.1k
      return reinterpret_cast<icmphdr*>(m_Data);
361
71.1k
    }
362
363
    /// @return The ICMP message type
364
    IcmpMessageType getMessageType() const;
365
366
    /// @param[in] type Type to check
367
    /// @return True if the layer if of the given type, false otherwise
368
    bool isMessageOfType(IcmpMessageType type) const
369
19.4k
    {
370
19.4k
      return getMessageType() == type;
371
19.4k
    }
372
373
    /// @return ICMP echo (ping) request data. If the layer isn't of type ICMP echo request nullptr is returned
374
    icmp_echo_request* getEchoRequestData();
375
376
    /// Set echo (ping) request message data
377
    /// @param[in] id Echo (ping) request identifier
378
    /// @param[in] sequence Echo (ping) request sequence
379
    /// @param[in] timestamp Echo (ping) request timestamp
380
    /// @param[in] data A pointer to echo (ping) request payload to set
381
    /// @param[in] dataLen The length of the echo (ping) request payload
382
    /// @return A pointer to the echo (ping) request data that have been set or nullptr if something went wrong
383
    /// (an appropriate error log is printed in such cases)
384
    icmp_echo_request* setEchoRequestData(uint16_t id, uint16_t sequence, uint64_t timestamp, const uint8_t* data,
385
                                          size_t dataLen);
386
387
    /// @return ICMP echo reply data. If the layer isn't of type ICMP echo reply nullptr is returned
388
    icmp_echo_reply* getEchoReplyData();
389
390
    /// Set echo (ping) reply message data
391
    /// @param[in] id Echo (ping) reply identifier
392
    /// @param[in] sequence Echo (ping) reply sequence
393
    /// @param[in] timestamp Echo (ping) reply timestamp
394
    /// @param[in] data A pointer to echo (ping) reply payload to set
395
    /// @param[in] dataLen The length of the echo (ping) reply payload
396
    /// @return A pointer to the echo (ping) reply data that have been set or nullptr if something went wrong
397
    /// (an appropriate error log is printed in such cases)
398
    icmp_echo_reply* setEchoReplyData(uint16_t id, uint16_t sequence, uint64_t timestamp, const uint8_t* data,
399
                                      size_t dataLen);
400
401
    /// @return ICMP timestamp request data. If the layer isn't of type ICMP timestamp request nullptr is returned
402
    icmp_timestamp_request* getTimestampRequestData();
403
404
    /// Set timestamp request message data
405
    /// @param[in] id Timestamp request identifier
406
    /// @param[in] sequence Timestamp request sequence
407
    /// @param[in] originateTimestamp Time (in milliseconds since midnight) the sender last touched the packet
408
    /// @return A pointer to the timestamp request data that have been set or nullptr if something went wrong
409
    /// (an appropriate error log is printed in such cases)
410
    icmp_timestamp_request* setTimestampRequestData(uint16_t id, uint16_t sequence, timeval originateTimestamp);
411
412
    /// @return ICMP timestamp reply data. If the layer isn't of type ICMP timestamp reply nullptr is returned
413
    icmp_timestamp_reply* getTimestampReplyData();
414
415
    /// Set timestamp reply message data
416
    /// @param[in] id Timestamp reply identifier
417
    /// @param[in] sequence Timestamp reply sequence
418
    /// @param[in] originateTimestamp Time (in milliseconds since midnight) the sender last touched the packet
419
    /// @param[in] receiveTimestamp The time the echoer first touched it on receipt
420
    /// @param[in] transmitTimestamp The time the echoer last touched the message on sending it
421
    /// @return A pointer to the timestamp reply data that have been set or nullptr if something went wrong
422
    /// (an appropriate error log is printed in such cases)
423
    icmp_timestamp_reply* setTimestampReplyData(uint16_t id, uint16_t sequence, timeval originateTimestamp,
424
                                                timeval receiveTimestamp, timeval transmitTimestamp);
425
426
    /// @return ICMP destination unreachable data. If the layer isn't of type ICMP destination unreachable nullptr
427
    /// is returned. The IP and L4 (ICMP/TCP/UDP) headers of the destination unreachable data are parsed as separate
428
    /// layers and can be retrieved via this->getNextLayer()
429
    icmp_destination_unreachable* getDestUnreachableData();
430
431
    /// Set destination unreachable message data. This method only works if IcmpLayer is already part of a packet
432
    /// (not a standalone layer). The reason is the Internet and L4 headers given as parameters are added as
433
    /// separate layers and need a packet to be added to
434
    /// @param[in] code Destination unreachable code
435
    /// @param[in] nextHopMTU The MTU of the next-hop network if a code 4 error occurs
436
    /// @param[in] ipHeader The Internet header of the original data. This layer is added as a separate layer on the
437
    /// packet
438
    /// @param[in] l4Header The L4 header of the original data. This layer is added as a separate layer on the
439
    /// packet
440
    /// @return A pointer to the destination unreachable data that have been set or nullptr if something went wrong
441
    /// (an appropriate error log is printed in such cases)
442
    icmp_destination_unreachable* setDestUnreachableData(IcmpDestUnreachableCodes code, uint16_t nextHopMTU,
443
                                                         IPv4Layer* ipHeader, Layer* l4Header);
444
445
    /// @return ICMP source quench data. If the layer isn't of type ICMP source quench nullptr is returned.
446
    /// The IP and L4 (ICMP/TCP/UDP) headers of the source quench data are parsed as separate layers and can be
447
    /// retrieved via this->getNextLayer()
448
    icmp_source_quench* getSourceQuenchdata();
449
450
    /// Set source quench message data. This method only works if IcmpLayer is already part of a packet (not
451
    /// a standalone layer). The reason is the Internet and L4 headers given as parameters are added as separate
452
    /// layers and need a packet to be added to
453
    /// @param[in] ipHeader The Internet header of the original data. This layer is added as a separate layer on the
454
    /// packet
455
    /// @param[in] l4Header The L4 header of the original data. This layer is added as a separate layer on the
456
    /// packet
457
    /// @return A pointer to the source quench data that have been set or nullptr if something went wrong
458
    /// (an appropriate error log is printed in such cases)
459
    icmp_source_quench* setSourceQuenchdata(IPv4Layer* ipHeader, Layer* l4Header);
460
461
    /// @return ICMP redirect data. If the layer isn't of type ICMP redirect nullptr is returned.
462
    /// The IP and L4 (ICMP/TCP/UDP) headers of the redirect data are parsed as separate layers and can be
463
    /// retrieved via this->getNextLayer()
464
    icmp_redirect* getRedirectData();
465
466
    /// Set redirect message data. This method only works if IcmpLayer is already part of a packet (not
467
    /// a standalone layer). The reason is the Internet and L4 headers given as parameters are added as separate
468
    /// layers and need a packet to be added to
469
    /// @param[in] code The redirect message code. Only values between 0 and 3 are legal, the rest will cause the
470
    /// method to fail
471
    /// @param[in] gatewayAddress An IPv4 address of the gateway to which the redirection should be sent
472
    /// @param[in] ipHeader The Internet header of the original data. This layer is added as a separate layer on the
473
    /// packet
474
    /// @param[in] l4Header The L4 header of the original data. This layer is added as a separate layer on the
475
    /// packet
476
    /// @return A pointer to the redirect data that have been set or nullptr if something went wrong
477
    /// (an appropriate error log is printed in such cases)
478
    icmp_redirect* setRedirectData(uint8_t code, IPv4Address gatewayAddress, IPv4Layer* ipHeader, Layer* l4Header);
479
480
    /// @return ICMP router advertisement data. If the layer isn't of type ICMP router advertisement nullptr is
481
    /// returned
482
    icmp_router_advertisement* getRouterAdvertisementData() const;
483
484
    /// Set router advertisement message data
485
    /// @param[in] code The router advertisement message code. Only codes 0 or 16 are legal, the rest will fail the
486
    /// method
487
    /// @param[in] lifetimeInSeconds The maximum number of seconds that the router addresses in this list may be
488
    /// considered valid
489
    /// @param[in] routerAddresses A vector of router advertisements to set
490
    /// @return A pointer to the router advertisement data that have been set or nullptr if something went wrong
491
    /// (an appropriate error log is printed in such cases)
492
    icmp_router_advertisement* setRouterAdvertisementData(
493
        uint8_t code, uint16_t lifetimeInSeconds,
494
        const std::vector<icmp_router_address_structure>& routerAddresses);
495
496
    /// @return ICMP router solicitation data. If the layer isn't of type ICMP router solicitation nullptr is
497
    /// returned
498
    icmp_router_solicitation* getRouterSolicitationData();
499
500
    /// Set router solicitation message data. This message accepts no parameters as there are no parameters to this
501
    /// type of message (code is always zero)
502
    /// @return A pointer to the router solicitation data that have been set or nullptr if something went wrong
503
    /// (an appropriate error log is printed in such cases)
504
    icmp_router_solicitation* setRouterSolicitationData();
505
506
    /// @return ICMP time-to-live exceeded data. If the layer isn't of type ICMP time-to-live exceeded nullptr is
507
    /// returned. The IP and L4 (ICMP/TCP/UDP) headers of the time exceeded data are parsed as separate layers and
508
    /// can be retrieved via this->getNextLayer()
509
    icmp_time_exceeded* getTimeExceededData();
510
511
    /// Set time-to-live exceeded message data. This method only works if IcmpLayer is already part of a packet (not
512
    /// a standalone layer). The reason is the Internet and L4 headers given as parameters are added as separate
513
    /// layers and need a packet to be added to
514
    /// @param[in] code Time-to-live exceeded message code. Only codes 0 or 1 are legal, the rest will fail the
515
    /// method
516
    /// @param[in] ipHeader The Internet header of the original data. This layer is added as a separate layer on the
517
    /// packet
518
    /// @param[in] l4Header The L4 header of the original data. This layer is added as a separate layer on the
519
    /// packet
520
    /// @return A pointer to the time-to-live exceeded data that have been set or nullptr if something went wrong
521
    /// (an appropriate error log is printed in such cases)
522
    icmp_time_exceeded* setTimeExceededData(uint8_t code, IPv4Layer* ipHeader, Layer* l4Header);
523
524
    /// @return ICMP parameter problem data. If the layer isn't of type ICMP parameter problem nullptr is returned
525
    icmp_param_problem* getParamProblemData();
526
527
    /// Set parameter problem message data. This method only works if IcmpLayer is already part of a packet (not
528
    /// a standalone layer). The reason is the Internet and L4 headers given as parameters are added as separate
529
    /// layers and need a packet to be added to
530
    /// @param[in] code Parameter problem message code. Only code between 0 and 2 are legal, the rest will fail the
531
    /// method
532
    /// @param[in] errorOctetPointer In the case of an invalid IP header (Code 0), indicate the byte offset of the
533
    /// error in the header
534
    /// @param[in] ipHeader The Internet header of the original data. This layer is added as a separate layer on the
535
    /// packet
536
    /// @param[in] l4Header The L4 header of the original data. This layer is added as a separate layer on the
537
    /// packet
538
    /// @return A pointer to the parameter problem data that have been set or nullptr if something went wrong
539
    /// (an appropriate error log is printed in such cases)
540
    icmp_param_problem* setParamProblemData(uint8_t code, uint8_t errorOctetPointer, IPv4Layer* ipHeader,
541
                                            Layer* l4Header);
542
543
    /// @return ICMP address mask request data. If the layer isn't of type ICMP address mask request nullptr is
544
    /// returned
545
    icmp_address_mask_request* getAddressMaskRequestData();
546
547
    /// Set address mask request message data
548
    /// @param[in] id Address mask request identifier
549
    /// @param[in] sequence Address mask request sequence
550
    /// @param[in] mask The subnet mask of the requesting host
551
    /// @return A pointer to the address mask request data that have been set or nullptr if something went wrong
552
    /// (an appropriate error log is printed in such cases)
553
    icmp_address_mask_request* setAddressMaskRequestData(uint16_t id, uint16_t sequence, IPv4Address mask);
554
555
    /// @return ICMP address mask reply data. If the layer isn't of type ICMP address mask reply nullptr is returned
556
    icmp_address_mask_reply* getAddressMaskReplyData();
557
558
    /// Set address mask reply message data
559
    /// @param[in] id Address mask reply identifier
560
    /// @param[in] sequence Address mask reply sequence
561
    /// @param[in] mask The subnet mask of the requesting host
562
    /// @return A pointer to the address mask reply data that have been set or nullptr if something went wrong
563
    /// (an appropriate error log is printed in such cases)
564
    icmp_address_mask_reply* setAddressMaskReplyData(uint16_t id, uint16_t sequence, IPv4Address mask);
565
566
    /// @return ICMP address information request data. If the layer isn't of type ICMP information request nullptr
567
    /// is returned
568
    icmp_info_request* getInfoRequestData();
569
570
    /// Set information request message data
571
    /// @param[in] id Information request identifier
572
    /// @param[in] sequence Information request sequence
573
    /// @return A pointer to the information request data that have been set or nullptr if something went wrong
574
    /// (an appropriate error log is printed in such cases)
575
    icmp_info_request* setInfoRequestData(uint16_t id, uint16_t sequence);
576
577
    /// @return ICMP address information reply data. If the layer isn't of type ICMP information reply nullptr is
578
    /// returned
579
    icmp_info_reply* getInfoReplyData();
580
581
    /// Set information reply message data
582
    /// @param[in] id Information reply identifier
583
    /// @param[in] sequence Information reply sequence
584
    /// @return A pointer to the information reply data that have been set or nullptr if something went wrong
585
    /// (an appropriate error log is printed in such cases)
586
    icmp_info_reply* setInfoReplyData(uint16_t id, uint16_t sequence);
587
588
    /// The static method makes validation of input data
589
    /// @param[in] data The pointer to the beginning of byte stream of ICMP packet
590
    /// @param[in] dataLen The length of byte stream
591
    /// @return True if the data is valid and can represent an ICMP packet
592
    static inline bool isDataValid(const uint8_t* data, size_t dataLen);
593
594
    // implement abstract methods
595
596
    /// ICMP messages of types: ICMP_DEST_UNREACHABLE, ICMP_SOURCE_QUENCH, ICMP_TIME_EXCEEDED, ICMP_REDIRECT,
597
    /// ICMP_PARAM_PROBLEM have data that contains IPv4 header and some L4 header (TCP/UDP/ICMP). This method parses
598
    /// these headers as separate layers on top of the ICMP layer
599
    void parseNextLayer() override;
600
601
    /// @return The ICMP header length. This length varies according to the ICMP message type. This length doesn't
602
    /// include IPv4 and L4 headers in case ICMP message type are: ICMP_DEST_UNREACHABLE, ICMP_SOURCE_QUENCH,
603
    /// ICMP_TIME_EXCEEDED, ICMP_REDIRECT, ICMP_PARAM_PROBLEM
604
    size_t getHeaderLen() const override;
605
606
    /// Calculate ICMP checksum field
607
    void computeCalculateFields() override;
608
609
    std::string toString() const override;
610
611
    OsiModelLayer getOsiModelLayer() const override
612
2.29k
    {
613
2.29k
      return OsiModelNetworkLayer;
614
2.29k
    }
615
  };
616
617
  // implementation of inline methods
618
619
  bool IcmpLayer::isDataValid(const uint8_t* data, size_t dataLen)
620
0
  {
621
0
    if (dataLen < sizeof(icmphdr))
622
0
      return false;
623
0
624
0
    uint8_t type = data[0];
625
0
626
0
    // ICMP_ECHO_REQUEST, ICMP_ECHO_REPLY, ICMP_ROUTER_SOL, ICMP_INFO_REQUEST, ICMP_INFO_REPLY
627
0
    if (type == 8 || type == 0 || type == 10 || type == 15 || type == 16)
628
0
      return true;
629
0
630
0
    // ICMP_TIMESTAMP_REQUEST, ICMP_TIMESTAMP_REPLY
631
0
    if (type == 13 || type == 14)
632
0
      return dataLen >= sizeof(icmp_timestamp_request);
633
0
634
0
    // ICMP_ADDRESS_MASK_REPLY, ICMP_ADDRESS_MASK_REQUEST
635
0
    if (type == 17 || type == 18)
636
0
      return dataLen >= sizeof(icmp_address_mask_request);
637
0
638
0
    // ICMP_DEST_UNREACHABLE
639
0
    if (type == 3)
640
0
      return dataLen >= sizeof(icmp_destination_unreachable);
641
0
642
0
    // ICMP_REDIRECT
643
0
    if (type == 5)
644
0
      return dataLen >= sizeof(icmp_redirect);
645
0
646
0
    // ICMP_TIME_EXCEEDED, ICMP_SOURCE_QUENCH
647
0
    if (type == 4 || type == 11)
648
0
      return dataLen >= sizeof(icmp_time_exceeded);
649
0
650
0
    // ICMP_PARAM_PROBLEM
651
0
    if (type == 12)
652
0
      return dataLen >= sizeof(icmp_param_problem);
653
0
654
0
    // ICMP_ROUTER_ADV
655
0
    if (type == 9)
656
0
      return dataLen >= sizeof(icmp_router_advertisement_hdr);
657
0
658
0
    return false;
659
0
  }
660
661
}  // namespace pcpp