Coverage Report

Created: 2024-02-25 06:29

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