/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 */ |