Coverage Report

Created: 2023-01-17 06:15

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