/src/PcapPlusPlus/Packet++/src/IcmpLayer.cpp
Line | Count | Source |
1 | 0 | #define LOG_MODULE PacketLogModuleIcmpLayer |
2 | | |
3 | | #include "IcmpLayer.h" |
4 | | #include "PayloadLayer.h" |
5 | | #include "Packet.h" |
6 | | #include "PacketUtils.h" |
7 | | #include "Logger.h" |
8 | | #include <sstream> |
9 | | #include "EndianPortable.h" |
10 | | |
11 | | namespace pcpp |
12 | | { |
13 | | |
14 | | icmp_router_address_structure* icmp_router_advertisement::getRouterAddress(int index) const |
15 | 0 | { |
16 | 0 | if (header == nullptr || index < 0 || index >= header->advertisementCount) |
17 | 0 | return nullptr; |
18 | | |
19 | | // advertisementCount is taken from the message and can't be trusted: make sure the entry is actually |
20 | | // present in the layer data |
21 | 0 | size_t addressOffset = sizeof(icmp_router_advertisement_hdr) + index * sizeof(icmp_router_address_structure); |
22 | 0 | if (addressOffset + sizeof(icmp_router_address_structure) > dataLen) |
23 | 0 | return nullptr; |
24 | | |
25 | 0 | return reinterpret_cast<icmp_router_address_structure*>(reinterpret_cast<uint8_t*>(header) + addressOffset); |
26 | 0 | } |
27 | | |
28 | | void icmp_router_address_structure::setRouterAddress(IPv4Address addr, uint32_t preference) |
29 | 0 | { |
30 | 0 | routerAddress = addr.toInt(); |
31 | 0 | preferenceLevel = htobe32(preference); |
32 | 0 | } |
33 | | |
34 | 0 | IcmpLayer::IcmpLayer() : Layer() |
35 | 0 | { |
36 | 0 | allocData(sizeof(icmphdr)); |
37 | 0 | m_Protocol = ICMP; |
38 | 0 | } |
39 | | |
40 | | IcmpMessageType IcmpLayer::getMessageType() const |
41 | 0 | { |
42 | 0 | uint8_t type = getIcmpHeader()->type; |
43 | 0 | if (type > 18) |
44 | 0 | return ICMP_UNSUPPORTED; |
45 | | |
46 | 0 | return static_cast<IcmpMessageType>(type); |
47 | 0 | } |
48 | | |
49 | | bool IcmpLayer::cleanIcmpLayer() |
50 | 0 | { |
51 | | // remove all layers after |
52 | |
|
53 | 0 | if (getAttachedPacket() != nullptr) |
54 | 0 | { |
55 | 0 | bool res = getAttachedPacket()->removeAllLayersAfter(this); |
56 | 0 | if (!res) |
57 | 0 | return false; |
58 | 0 | } |
59 | | |
60 | | // shorten layer to size of icmphdr |
61 | | |
62 | 0 | size_t headerLen = this->getHeaderLen(); |
63 | 0 | if (headerLen > sizeof(icmphdr)) |
64 | 0 | { |
65 | 0 | if (!this->shortenLayer(sizeof(icmphdr), headerLen - sizeof(icmphdr))) |
66 | 0 | return false; |
67 | 0 | } |
68 | | |
69 | 0 | return true; |
70 | 0 | } |
71 | | |
72 | | bool IcmpLayer::setEchoData(IcmpMessageType echoType, uint16_t id, uint16_t sequence, uint64_t timestamp, |
73 | | const uint8_t* data, size_t dataLen) |
74 | 0 | { |
75 | 0 | if (!cleanIcmpLayer()) |
76 | 0 | return false; |
77 | | |
78 | 0 | if (!this->extendLayer(m_DataLen, sizeof(icmp_echo_hdr) - sizeof(icmphdr) + dataLen)) |
79 | 0 | return false; |
80 | | |
81 | 0 | getIcmpHeader()->type = static_cast<uint8_t>(echoType); |
82 | |
|
83 | 0 | icmp_echo_request* header = nullptr; |
84 | 0 | if (echoType == ICMP_ECHO_REQUEST) |
85 | 0 | header = getEchoRequestData(); |
86 | 0 | else if (echoType == ICMP_ECHO_REPLY) |
87 | 0 | header = reinterpret_cast<icmp_echo_request*>(getEchoReplyData()); |
88 | 0 | else |
89 | 0 | return false; |
90 | | |
91 | 0 | header->header->code = 0; |
92 | 0 | header->header->checksum = 0; |
93 | 0 | header->header->id = htobe16(id); |
94 | 0 | header->header->sequence = htobe16(sequence); |
95 | 0 | header->header->timestamp = timestamp; |
96 | 0 | if (data != nullptr && dataLen > 0) |
97 | 0 | memcpy(header->data, data, dataLen); |
98 | |
|
99 | 0 | return true; |
100 | 0 | } |
101 | | |
102 | | bool IcmpLayer::setIpAndL4Layers(IPv4Layer* ipLayer, Layer* l4Layer) |
103 | 0 | { |
104 | 0 | if (getAttachedPacket() == nullptr) |
105 | 0 | { |
106 | 0 | PCPP_LOG_ERROR("Cannot set ICMP data that involves IP and L4 layers on a layer not attached to a packet. " |
107 | 0 | "Please add the ICMP layer to a packet and try again"); |
108 | 0 | return false; |
109 | 0 | } |
110 | | |
111 | 0 | if (ipLayer != nullptr && !getAttachedPacket()->addLayer(ipLayer)) |
112 | 0 | { |
113 | 0 | PCPP_LOG_ERROR("Couldn't add IP layer to ICMP packet"); |
114 | 0 | return false; |
115 | 0 | } |
116 | | |
117 | 0 | if (l4Layer != nullptr && !getAttachedPacket()->addLayer(l4Layer)) |
118 | 0 | { |
119 | 0 | PCPP_LOG_ERROR("Couldn't add L4 layer to ICMP packet"); |
120 | 0 | return false; |
121 | 0 | } |
122 | | |
123 | 0 | return true; |
124 | 0 | } |
125 | | |
126 | | icmp_echo_request* IcmpLayer::getEchoRequestData() |
127 | 0 | { |
128 | 0 | if (!isMessageOfType(ICMP_ECHO_REQUEST)) |
129 | 0 | return nullptr; |
130 | | |
131 | 0 | m_EchoData.header = reinterpret_cast<icmp_echo_hdr*>(m_Data); |
132 | 0 | m_EchoData.data = reinterpret_cast<uint8_t*>(m_Data + sizeof(icmp_echo_hdr)); |
133 | 0 | m_EchoData.dataLength = m_DataLen - sizeof(icmp_echo_hdr); |
134 | |
|
135 | 0 | return &m_EchoData; |
136 | 0 | } |
137 | | |
138 | | icmp_echo_request* IcmpLayer::setEchoRequestData(uint16_t id, uint16_t sequence, uint64_t timestamp, |
139 | | const uint8_t* data, size_t dataLen) |
140 | 0 | { |
141 | 0 | if (setEchoData(ICMP_ECHO_REQUEST, id, sequence, timestamp, data, dataLen)) |
142 | 0 | return getEchoRequestData(); |
143 | 0 | else |
144 | 0 | return nullptr; |
145 | 0 | } |
146 | | |
147 | | icmp_echo_reply* IcmpLayer::getEchoReplyData() |
148 | 0 | { |
149 | 0 | if (!isMessageOfType(ICMP_ECHO_REPLY)) |
150 | 0 | return nullptr; |
151 | | |
152 | 0 | m_EchoData.header = reinterpret_cast<icmp_echo_hdr*>(m_Data); |
153 | 0 | m_EchoData.data = reinterpret_cast<uint8_t*>(m_Data + sizeof(icmp_echo_hdr)); |
154 | 0 | m_EchoData.dataLength = m_DataLen - sizeof(icmp_echo_hdr); |
155 | |
|
156 | 0 | return &m_EchoData; |
157 | 0 | } |
158 | | |
159 | | icmp_echo_reply* IcmpLayer::setEchoReplyData(uint16_t id, uint16_t sequence, uint64_t timestamp, |
160 | | const uint8_t* data, size_t dataLen) |
161 | 0 | { |
162 | 0 | if (setEchoData(ICMP_ECHO_REPLY, id, sequence, timestamp, data, dataLen)) |
163 | 0 | return getEchoReplyData(); |
164 | 0 | else |
165 | 0 | return nullptr; |
166 | 0 | } |
167 | | |
168 | | icmp_timestamp_request* IcmpLayer::getTimestampRequestData() |
169 | 0 | { |
170 | 0 | if (!isMessageOfType(ICMP_TIMESTAMP_REQUEST)) |
171 | 0 | return nullptr; |
172 | | |
173 | 0 | return reinterpret_cast<icmp_timestamp_request*>(m_Data); |
174 | 0 | } |
175 | | |
176 | | icmp_timestamp_request* IcmpLayer::setTimestampRequestData(uint16_t id, uint16_t sequence, |
177 | | timeval originateTimestamp) |
178 | 0 | { |
179 | 0 | if (!cleanIcmpLayer()) |
180 | 0 | return nullptr; |
181 | | |
182 | 0 | if (!this->extendLayer(m_DataLen, sizeof(icmp_timestamp_request) - sizeof(icmphdr))) |
183 | 0 | return nullptr; |
184 | | |
185 | 0 | getIcmpHeader()->type = static_cast<uint8_t>(ICMP_TIMESTAMP_REQUEST); |
186 | |
|
187 | 0 | icmp_timestamp_request* header = getTimestampRequestData(); |
188 | 0 | header->code = 0; |
189 | 0 | header->id = htobe16(id); |
190 | 0 | header->sequence = htobe16(sequence); |
191 | 0 | header->originateTimestamp = htobe32(originateTimestamp.tv_sec * 1000 + originateTimestamp.tv_usec / 1000); |
192 | 0 | header->receiveTimestamp = 0; |
193 | 0 | header->transmitTimestamp = 0; |
194 | |
|
195 | 0 | return header; |
196 | 0 | } |
197 | | |
198 | | icmp_timestamp_reply* IcmpLayer::getTimestampReplyData() |
199 | 0 | { |
200 | 0 | if (!isMessageOfType(ICMP_TIMESTAMP_REPLY)) |
201 | 0 | return nullptr; |
202 | | |
203 | 0 | return reinterpret_cast<icmp_timestamp_reply*>(m_Data); |
204 | 0 | } |
205 | | |
206 | | icmp_timestamp_reply* IcmpLayer::setTimestampReplyData(uint16_t id, uint16_t sequence, timeval originateTimestamp, |
207 | | timeval receiveTimestamp, timeval transmitTimestamp) |
208 | 0 | { |
209 | 0 | if (!cleanIcmpLayer()) |
210 | 0 | return nullptr; |
211 | | |
212 | 0 | if (!this->extendLayer(m_DataLen, sizeof(icmp_timestamp_reply) - sizeof(icmphdr))) |
213 | 0 | return nullptr; |
214 | | |
215 | 0 | getIcmpHeader()->type = static_cast<uint8_t>(ICMP_TIMESTAMP_REPLY); |
216 | |
|
217 | 0 | icmp_timestamp_reply* header = getTimestampReplyData(); |
218 | 0 | header->code = 0; |
219 | 0 | header->id = htobe16(id); |
220 | 0 | header->sequence = htobe16(sequence); |
221 | 0 | header->originateTimestamp = htobe32(originateTimestamp.tv_sec * 1000 + originateTimestamp.tv_usec / 1000); |
222 | 0 | header->receiveTimestamp = htobe32(receiveTimestamp.tv_sec * 1000 + receiveTimestamp.tv_usec / 1000); |
223 | 0 | header->transmitTimestamp = htobe32(transmitTimestamp.tv_sec * 1000 + transmitTimestamp.tv_usec / 1000); |
224 | |
|
225 | 0 | return header; |
226 | 0 | } |
227 | | |
228 | | icmp_destination_unreachable* IcmpLayer::getDestUnreachableData() |
229 | 0 | { |
230 | 0 | if (!isMessageOfType(ICMP_DEST_UNREACHABLE)) |
231 | 0 | return nullptr; |
232 | | |
233 | 0 | return reinterpret_cast<icmp_destination_unreachable*>(m_Data); |
234 | 0 | } |
235 | | |
236 | | icmp_destination_unreachable* IcmpLayer::setDestUnreachableData(IcmpDestUnreachableCodes code, uint16_t nextHopMTU, |
237 | | IPv4Layer* ipHeader, Layer* l4Header) |
238 | 0 | { |
239 | 0 | if (!cleanIcmpLayer()) |
240 | 0 | return nullptr; |
241 | | |
242 | 0 | if (!this->extendLayer(m_DataLen, sizeof(icmp_destination_unreachable) - sizeof(icmphdr))) |
243 | 0 | return nullptr; |
244 | | |
245 | 0 | getIcmpHeader()->type = static_cast<uint8_t>(ICMP_DEST_UNREACHABLE); |
246 | |
|
247 | 0 | icmp_destination_unreachable* header = getDestUnreachableData(); |
248 | 0 | header->code = code; |
249 | 0 | header->nextHopMTU = htobe16(nextHopMTU); |
250 | 0 | header->unused = 0; |
251 | |
|
252 | 0 | if (!setIpAndL4Layers(ipHeader, l4Header)) |
253 | 0 | return nullptr; |
254 | | |
255 | 0 | return header; |
256 | 0 | } |
257 | | |
258 | | icmp_source_quench* IcmpLayer::getSourceQuenchdata() |
259 | 0 | { |
260 | 0 | if (!isMessageOfType(ICMP_SOURCE_QUENCH)) |
261 | 0 | return nullptr; |
262 | | |
263 | 0 | return reinterpret_cast<icmp_source_quench*>(m_Data); |
264 | 0 | } |
265 | | |
266 | | icmp_source_quench* IcmpLayer::setSourceQuenchdata(IPv4Layer* ipHeader, Layer* l4Header) |
267 | 0 | { |
268 | 0 | if (!cleanIcmpLayer()) |
269 | 0 | return nullptr; |
270 | | |
271 | 0 | if (!this->extendLayer(m_DataLen, sizeof(icmp_source_quench) - sizeof(icmphdr))) |
272 | 0 | return nullptr; |
273 | | |
274 | 0 | getIcmpHeader()->type = static_cast<uint8_t>(ICMP_SOURCE_QUENCH); |
275 | |
|
276 | 0 | icmp_source_quench* header = getSourceQuenchdata(); |
277 | 0 | header->unused = 0; |
278 | |
|
279 | 0 | if (!setIpAndL4Layers(ipHeader, l4Header)) |
280 | 0 | return nullptr; |
281 | | |
282 | 0 | return header; |
283 | 0 | } |
284 | | |
285 | | icmp_redirect* IcmpLayer::getRedirectData() |
286 | 0 | { |
287 | 0 | if (!isMessageOfType(ICMP_REDIRECT)) |
288 | 0 | return nullptr; |
289 | | |
290 | 0 | return reinterpret_cast<icmp_redirect*>(m_Data); |
291 | 0 | } |
292 | | |
293 | | icmp_redirect* IcmpLayer::setRedirectData(uint8_t code, IPv4Address gatewayAddress, IPv4Layer* ipHeader, |
294 | | Layer* l4Header) |
295 | 0 | { |
296 | 0 | if (code > 3) |
297 | 0 | { |
298 | 0 | PCPP_LOG_ERROR("Unknown code " << (int)code << " for ICMP redirect data"); |
299 | 0 | return nullptr; |
300 | 0 | } |
301 | | |
302 | 0 | if (!cleanIcmpLayer()) |
303 | 0 | return nullptr; |
304 | | |
305 | 0 | if (!this->extendLayer(m_DataLen, sizeof(icmp_redirect) - sizeof(icmphdr))) |
306 | 0 | return nullptr; |
307 | | |
308 | 0 | getIcmpHeader()->type = static_cast<uint8_t>(ICMP_REDIRECT); |
309 | |
|
310 | 0 | icmp_redirect* header = getRedirectData(); |
311 | 0 | header->code = code; |
312 | 0 | header->gatewayAddress = gatewayAddress.toInt(); |
313 | |
|
314 | 0 | if (!setIpAndL4Layers(ipHeader, l4Header)) |
315 | 0 | return nullptr; |
316 | | |
317 | 0 | return header; |
318 | 0 | } |
319 | | |
320 | | icmp_router_advertisement* IcmpLayer::getRouterAdvertisementData() const |
321 | 0 | { |
322 | 0 | if (!isMessageOfType(ICMP_ROUTER_ADV)) |
323 | 0 | return nullptr; |
324 | | |
325 | 0 | m_RouterAdvData.header = reinterpret_cast<icmp_router_advertisement_hdr*>(m_Data); |
326 | 0 | m_RouterAdvData.dataLen = m_DataLen; |
327 | |
|
328 | 0 | return &m_RouterAdvData; |
329 | 0 | } |
330 | | |
331 | | icmp_router_advertisement* IcmpLayer::setRouterAdvertisementData( |
332 | | uint8_t code, uint16_t lifetimeInSeconds, const std::vector<icmp_router_address_structure>& routerAddresses) |
333 | 0 | { |
334 | 0 | if (code != 0 && code != 16) |
335 | 0 | { |
336 | 0 | PCPP_LOG_ERROR("Unknown code " << (int)code |
337 | 0 | << " for ICMP router advertisement data (only codes 0 and 16 are legal)"); |
338 | 0 | return nullptr; |
339 | 0 | } |
340 | | |
341 | 0 | if (!cleanIcmpLayer()) |
342 | 0 | return nullptr; |
343 | | |
344 | 0 | if (!this->extendLayer(m_DataLen, sizeof(icmp_router_advertisement_hdr) + |
345 | 0 | (routerAddresses.size() * sizeof(icmp_router_address_structure)) - |
346 | 0 | sizeof(icmphdr))) |
347 | 0 | return nullptr; |
348 | | |
349 | 0 | getIcmpHeader()->type = static_cast<uint8_t>(ICMP_ROUTER_ADV); |
350 | |
|
351 | 0 | icmp_router_advertisement* header = getRouterAdvertisementData(); |
352 | 0 | header->header->code = code; |
353 | 0 | header->header->lifetime = htobe16(lifetimeInSeconds); |
354 | 0 | header->header->advertisementCount = static_cast<uint8_t>(routerAddresses.size()); |
355 | 0 | header->header->addressEntrySize = 2; |
356 | |
|
357 | 0 | icmp_router_address_structure* curPos = reinterpret_cast<icmp_router_address_structure*>( |
358 | 0 | reinterpret_cast<uint8_t*>(header->header) + sizeof(icmp_router_advertisement_hdr)); |
359 | 0 | for (const auto& iter : routerAddresses) |
360 | 0 | { |
361 | 0 | curPos->routerAddress = iter.routerAddress; |
362 | 0 | curPos->preferenceLevel = iter.preferenceLevel; |
363 | 0 | curPos += 1; |
364 | 0 | } |
365 | |
|
366 | 0 | return header; |
367 | 0 | } |
368 | | |
369 | | icmp_router_solicitation* IcmpLayer::getRouterSolicitationData() |
370 | 0 | { |
371 | 0 | if (!isMessageOfType(ICMP_ROUTER_SOL)) |
372 | 0 | return nullptr; |
373 | | |
374 | 0 | return reinterpret_cast<icmp_router_solicitation*>(m_Data); |
375 | 0 | } |
376 | | |
377 | | icmp_router_solicitation* IcmpLayer::setRouterSolicitationData() |
378 | 0 | { |
379 | 0 | if (!cleanIcmpLayer()) |
380 | 0 | return nullptr; |
381 | | |
382 | 0 | getIcmpHeader()->type = static_cast<uint8_t>(ICMP_ROUTER_SOL); |
383 | |
|
384 | 0 | icmp_router_solicitation* header = getRouterSolicitationData(); |
385 | 0 | header->code = 0; |
386 | |
|
387 | 0 | return header; |
388 | 0 | } |
389 | | |
390 | | icmp_time_exceeded* IcmpLayer::getTimeExceededData() |
391 | 0 | { |
392 | 0 | if (!isMessageOfType(ICMP_TIME_EXCEEDED)) |
393 | 0 | return nullptr; |
394 | | |
395 | 0 | return reinterpret_cast<icmp_time_exceeded*>(m_Data); |
396 | 0 | } |
397 | | |
398 | | icmp_time_exceeded* IcmpLayer::setTimeExceededData(uint8_t code, IPv4Layer* ipHeader, Layer* l4Header) |
399 | 0 | { |
400 | 0 | if (code > 1) |
401 | 0 | { |
402 | 0 | PCPP_LOG_ERROR("Unknown code " << (int)code << " for ICMP time exceeded data"); |
403 | 0 | return nullptr; |
404 | 0 | } |
405 | | |
406 | 0 | if (!cleanIcmpLayer()) |
407 | 0 | return nullptr; |
408 | | |
409 | 0 | if (!this->extendLayer(m_DataLen, sizeof(icmp_time_exceeded) - sizeof(icmphdr))) |
410 | 0 | return nullptr; |
411 | | |
412 | 0 | getIcmpHeader()->type = static_cast<uint8_t>(ICMP_TIME_EXCEEDED); |
413 | |
|
414 | 0 | icmp_time_exceeded* header = getTimeExceededData(); |
415 | 0 | header->code = code; |
416 | 0 | header->unused = 0; |
417 | |
|
418 | 0 | if (!setIpAndL4Layers(ipHeader, l4Header)) |
419 | 0 | return nullptr; |
420 | | |
421 | 0 | return header; |
422 | 0 | } |
423 | | |
424 | | icmp_param_problem* IcmpLayer::getParamProblemData() |
425 | 0 | { |
426 | 0 | if (!isMessageOfType(ICMP_PARAM_PROBLEM)) |
427 | 0 | return nullptr; |
428 | | |
429 | 0 | return reinterpret_cast<icmp_param_problem*>(m_Data); |
430 | 0 | } |
431 | | |
432 | | icmp_param_problem* IcmpLayer::setParamProblemData(uint8_t code, uint8_t errorOctetPointer, IPv4Layer* ipHeader, |
433 | | Layer* l4Header) |
434 | 0 | { |
435 | 0 | if (code > 2) |
436 | 0 | { |
437 | 0 | PCPP_LOG_ERROR("Unknown code " << (int)code << " for ICMP parameter problem data"); |
438 | 0 | return nullptr; |
439 | 0 | } |
440 | | |
441 | 0 | if (!cleanIcmpLayer()) |
442 | 0 | return nullptr; |
443 | | |
444 | 0 | if (!this->extendLayer(m_DataLen, sizeof(icmp_param_problem) - sizeof(icmphdr))) |
445 | 0 | return nullptr; |
446 | | |
447 | 0 | getIcmpHeader()->type = static_cast<uint8_t>(ICMP_PARAM_PROBLEM); |
448 | |
|
449 | 0 | icmp_param_problem* header = getParamProblemData(); |
450 | 0 | header->code = code; |
451 | 0 | header->unused1 = 0; |
452 | 0 | header->unused2 = 0; |
453 | 0 | header->pointer = errorOctetPointer; |
454 | |
|
455 | 0 | if (!setIpAndL4Layers(ipHeader, l4Header)) |
456 | 0 | return nullptr; |
457 | | |
458 | 0 | return header; |
459 | 0 | } |
460 | | |
461 | | icmp_address_mask_request* IcmpLayer::getAddressMaskRequestData() |
462 | 0 | { |
463 | 0 | if (!isMessageOfType(ICMP_ADDRESS_MASK_REQUEST)) |
464 | 0 | return nullptr; |
465 | | |
466 | 0 | return reinterpret_cast<icmp_address_mask_request*>(m_Data); |
467 | 0 | } |
468 | | |
469 | | icmp_address_mask_request* IcmpLayer::setAddressMaskRequestData(uint16_t id, uint16_t sequence, IPv4Address mask) |
470 | 0 | { |
471 | 0 | if (!cleanIcmpLayer()) |
472 | 0 | return nullptr; |
473 | | |
474 | 0 | if (!this->extendLayer(m_DataLen, sizeof(icmp_address_mask_request) - sizeof(icmphdr))) |
475 | 0 | return nullptr; |
476 | | |
477 | 0 | getIcmpHeader()->type = static_cast<uint8_t>(ICMP_ADDRESS_MASK_REQUEST); |
478 | |
|
479 | 0 | icmp_address_mask_request* header = getAddressMaskRequestData(); |
480 | 0 | header->code = 0; |
481 | 0 | header->id = htobe16(id); |
482 | 0 | header->sequence = htobe16(sequence); |
483 | 0 | header->addressMask = mask.toInt(); |
484 | |
|
485 | 0 | return header; |
486 | 0 | } |
487 | | |
488 | | icmp_address_mask_reply* IcmpLayer::getAddressMaskReplyData() |
489 | 0 | { |
490 | 0 | if (!isMessageOfType(ICMP_ADDRESS_MASK_REPLY)) |
491 | 0 | return nullptr; |
492 | | |
493 | 0 | return reinterpret_cast<icmp_address_mask_reply*>(m_Data); |
494 | 0 | } |
495 | | |
496 | | icmp_address_mask_reply* IcmpLayer::setAddressMaskReplyData(uint16_t id, uint16_t sequence, IPv4Address mask) |
497 | 0 | { |
498 | 0 | if (!cleanIcmpLayer()) |
499 | 0 | return nullptr; |
500 | | |
501 | 0 | if (!this->extendLayer(m_DataLen, sizeof(icmp_address_mask_reply) - sizeof(icmphdr))) |
502 | 0 | return nullptr; |
503 | | |
504 | 0 | getIcmpHeader()->type = static_cast<uint8_t>(ICMP_ADDRESS_MASK_REPLY); |
505 | |
|
506 | 0 | icmp_address_mask_reply* header = getAddressMaskReplyData(); |
507 | 0 | header->code = 0; |
508 | 0 | header->id = htobe16(id); |
509 | 0 | header->sequence = htobe16(sequence); |
510 | 0 | header->addressMask = htobe32(mask.toInt()); |
511 | |
|
512 | 0 | return header; |
513 | 0 | } |
514 | | |
515 | | icmp_info_request* IcmpLayer::getInfoRequestData() |
516 | 0 | { |
517 | 0 | if (!isMessageOfType(ICMP_INFO_REQUEST)) |
518 | 0 | return nullptr; |
519 | | |
520 | 0 | return reinterpret_cast<icmp_info_request*>(m_Data); |
521 | 0 | } |
522 | | |
523 | | icmp_info_request* IcmpLayer::setInfoRequestData(uint16_t id, uint16_t sequence) |
524 | 0 | { |
525 | 0 | if (!cleanIcmpLayer()) |
526 | 0 | return nullptr; |
527 | | |
528 | 0 | if (!this->extendLayer(m_DataLen, sizeof(icmp_info_request) - sizeof(icmphdr))) |
529 | 0 | return nullptr; |
530 | | |
531 | 0 | getIcmpHeader()->type = static_cast<uint8_t>(ICMP_INFO_REQUEST); |
532 | |
|
533 | 0 | icmp_info_request* header = getInfoRequestData(); |
534 | 0 | header->code = 0; |
535 | 0 | header->id = htobe16(id); |
536 | 0 | header->sequence = htobe16(sequence); |
537 | |
|
538 | 0 | return header; |
539 | 0 | } |
540 | | |
541 | | icmp_info_reply* IcmpLayer::getInfoReplyData() |
542 | 0 | { |
543 | 0 | if (!isMessageOfType(ICMP_INFO_REPLY)) |
544 | 0 | return nullptr; |
545 | | |
546 | 0 | return reinterpret_cast<icmp_info_reply*>(m_Data); |
547 | 0 | } |
548 | | |
549 | | icmp_info_reply* IcmpLayer::setInfoReplyData(uint16_t id, uint16_t sequence) |
550 | 0 | { |
551 | 0 | if (!cleanIcmpLayer()) |
552 | 0 | return nullptr; |
553 | | |
554 | 0 | if (!this->extendLayer(m_DataLen, sizeof(icmp_info_reply) - sizeof(icmphdr))) |
555 | 0 | return nullptr; |
556 | | |
557 | 0 | getIcmpHeader()->type = static_cast<uint8_t>(ICMP_INFO_REPLY); |
558 | |
|
559 | 0 | icmp_info_reply* header = getInfoReplyData(); |
560 | 0 | header->code = 0; |
561 | 0 | header->id = htobe16(id); |
562 | 0 | header->sequence = htobe16(sequence); |
563 | |
|
564 | 0 | return header; |
565 | 0 | } |
566 | | |
567 | | void IcmpLayer::parseNextLayer() |
568 | 0 | { |
569 | 0 | size_t headerLen = getHeaderLen(); |
570 | |
|
571 | 0 | auto payloadPtr = m_Data + headerLen; |
572 | 0 | auto payloadLen = m_DataLen - headerLen; |
573 | |
|
574 | 0 | switch (getMessageType()) |
575 | 0 | { |
576 | 0 | case ICMP_DEST_UNREACHABLE: |
577 | 0 | case ICMP_SOURCE_QUENCH: |
578 | 0 | case ICMP_TIME_EXCEEDED: |
579 | 0 | case ICMP_REDIRECT: |
580 | 0 | case ICMP_PARAM_PROBLEM: |
581 | 0 | { |
582 | 0 | tryConstructNextLayerWithFallback<IPv4Layer, PayloadLayer>(payloadPtr, payloadLen); |
583 | 0 | break; |
584 | 0 | } |
585 | 0 | default: |
586 | 0 | if (m_DataLen > headerLen) |
587 | 0 | { |
588 | 0 | constructNextLayer<PayloadLayer>(payloadPtr, payloadLen); |
589 | 0 | } |
590 | 0 | break; |
591 | 0 | } |
592 | 0 | } |
593 | | |
594 | | size_t IcmpLayer::getHeaderLen() const |
595 | 0 | { |
596 | 0 | IcmpMessageType type = getMessageType(); |
597 | 0 | size_t routerAdvSize = 0; |
598 | 0 | switch (type) |
599 | 0 | { |
600 | 0 | case ICMP_ECHO_REQUEST: |
601 | 0 | case ICMP_ECHO_REPLY: |
602 | 0 | return m_DataLen; |
603 | 0 | case ICMP_TIMESTAMP_REQUEST: |
604 | 0 | case ICMP_TIMESTAMP_REPLY: |
605 | 0 | return sizeof(icmp_timestamp_request); |
606 | 0 | case ICMP_ROUTER_SOL: |
607 | 0 | case ICMP_INFO_REQUEST: |
608 | 0 | case ICMP_INFO_REPLY: |
609 | 0 | case ICMP_UNSUPPORTED: |
610 | 0 | return sizeof(icmphdr); |
611 | 0 | case ICMP_ADDRESS_MASK_REPLY: |
612 | 0 | case ICMP_ADDRESS_MASK_REQUEST: |
613 | 0 | return sizeof(icmp_address_mask_request); |
614 | 0 | case ICMP_DEST_UNREACHABLE: |
615 | 0 | return sizeof(icmp_destination_unreachable); |
616 | 0 | case ICMP_REDIRECT: |
617 | 0 | return sizeof(icmp_redirect); |
618 | 0 | case ICMP_TIME_EXCEEDED: |
619 | 0 | case ICMP_SOURCE_QUENCH: |
620 | 0 | return sizeof(icmp_time_exceeded); |
621 | 0 | case ICMP_PARAM_PROBLEM: |
622 | 0 | return sizeof(icmp_param_problem); |
623 | 0 | case ICMP_ROUTER_ADV: |
624 | | // clang-format off |
625 | 0 | routerAdvSize = sizeof(icmp_router_advertisement_hdr) + (getRouterAdvertisementData()->header->advertisementCount * sizeof(icmp_router_address_structure)); |
626 | | // clang-format on |
627 | 0 | if (routerAdvSize > m_DataLen) |
628 | 0 | return m_DataLen; |
629 | 0 | return routerAdvSize; |
630 | 0 | default: |
631 | 0 | return sizeof(icmphdr); |
632 | 0 | } |
633 | 0 | } |
634 | | |
635 | | void IcmpLayer::computeCalculateFields() |
636 | 0 | { |
637 | | // calculate checksum |
638 | 0 | getIcmpHeader()->checksum = 0; |
639 | |
|
640 | 0 | size_t icmpLen = 0; |
641 | 0 | Layer* curLayer = this; |
642 | 0 | while (curLayer != nullptr) |
643 | 0 | { |
644 | 0 | icmpLen += curLayer->getHeaderLen(); |
645 | 0 | curLayer = curLayer->getNextLayer(); |
646 | 0 | } |
647 | |
|
648 | 0 | ScalarBuffer<uint16_t> buffer; |
649 | 0 | buffer.buffer = reinterpret_cast<uint16_t*>(getIcmpHeader()); |
650 | 0 | buffer.len = icmpLen; |
651 | 0 | size_t checksum = computeChecksum(&buffer, 1); |
652 | |
|
653 | 0 | getIcmpHeader()->checksum = htobe16(checksum); |
654 | 0 | } |
655 | | |
656 | | std::string IcmpLayer::toString() const |
657 | 0 | { |
658 | 0 | std::string messageTypeAsString; |
659 | 0 | IcmpMessageType type = getMessageType(); |
660 | 0 | switch (type) |
661 | 0 | { |
662 | 0 | case ICMP_ECHO_REPLY: |
663 | 0 | messageTypeAsString = "Echo (ping) reply"; |
664 | 0 | break; |
665 | 0 | case ICMP_DEST_UNREACHABLE: |
666 | 0 | messageTypeAsString = "Destination unreachable"; |
667 | 0 | break; |
668 | 0 | case ICMP_SOURCE_QUENCH: |
669 | 0 | messageTypeAsString = "Source quench (flow control)"; |
670 | 0 | break; |
671 | 0 | case ICMP_REDIRECT: |
672 | 0 | messageTypeAsString = "Redirect"; |
673 | 0 | break; |
674 | 0 | case ICMP_ECHO_REQUEST: |
675 | 0 | messageTypeAsString = "Echo (ping) request"; |
676 | 0 | break; |
677 | 0 | case ICMP_ROUTER_ADV: |
678 | 0 | messageTypeAsString = "Router advertisement"; |
679 | 0 | break; |
680 | 0 | case ICMP_ROUTER_SOL: |
681 | 0 | messageTypeAsString = "Router solicitation"; |
682 | 0 | break; |
683 | 0 | case ICMP_TIME_EXCEEDED: |
684 | 0 | messageTypeAsString = "Time-to-live exceeded"; |
685 | 0 | break; |
686 | 0 | case ICMP_PARAM_PROBLEM: |
687 | 0 | messageTypeAsString = "Parameter problem: bad IP header"; |
688 | 0 | break; |
689 | 0 | case ICMP_TIMESTAMP_REQUEST: |
690 | 0 | messageTypeAsString = "Timestamp request"; |
691 | 0 | break; |
692 | 0 | case ICMP_TIMESTAMP_REPLY: |
693 | 0 | messageTypeAsString = "Timestamp reply"; |
694 | 0 | break; |
695 | 0 | case ICMP_INFO_REQUEST: |
696 | 0 | messageTypeAsString = "Information request"; |
697 | 0 | break; |
698 | 0 | case ICMP_INFO_REPLY: |
699 | 0 | messageTypeAsString = "Information reply"; |
700 | 0 | break; |
701 | 0 | case ICMP_ADDRESS_MASK_REQUEST: |
702 | 0 | messageTypeAsString = "Address mask request"; |
703 | 0 | break; |
704 | 0 | case ICMP_ADDRESS_MASK_REPLY: |
705 | 0 | messageTypeAsString = "Address mask reply"; |
706 | 0 | break; |
707 | 0 | default: |
708 | 0 | messageTypeAsString = "Unknown"; |
709 | 0 | break; |
710 | 0 | } |
711 | | |
712 | 0 | std::ostringstream typeStream; |
713 | 0 | typeStream << (int)getIcmpHeader()->type; |
714 | |
|
715 | 0 | return "ICMP Layer, " + messageTypeAsString + " (type: " + typeStream.str() + ")"; |
716 | 0 | } |
717 | | |
718 | | static constexpr const char* icmpMessageTypeToString(IcmpMessageType type) |
719 | 0 | { |
720 | 0 | switch (type) |
721 | 0 | { |
722 | 0 | case ICMP_ECHO_REPLY: |
723 | 0 | return "EchoReply"; |
724 | 0 | case ICMP_DEST_UNREACHABLE: |
725 | 0 | return "DestinationUnreachable"; |
726 | 0 | case ICMP_SOURCE_QUENCH: |
727 | 0 | return "SourceQuench"; |
728 | 0 | case ICMP_REDIRECT: |
729 | 0 | return "Redirect"; |
730 | 0 | case ICMP_ECHO_REQUEST: |
731 | 0 | return "EchoRequest"; |
732 | 0 | case ICMP_ROUTER_ADV: |
733 | 0 | return "RouterAdvertisement"; |
734 | 0 | case ICMP_ROUTER_SOL: |
735 | 0 | return "RouterSolicitation"; |
736 | 0 | case ICMP_TIME_EXCEEDED: |
737 | 0 | return "TimeExceeded"; |
738 | 0 | case ICMP_PARAM_PROBLEM: |
739 | 0 | return "ParameterProblem"; |
740 | 0 | case ICMP_TIMESTAMP_REQUEST: |
741 | 0 | return "TimestampRequest"; |
742 | 0 | case ICMP_TIMESTAMP_REPLY: |
743 | 0 | return "TimestampReply"; |
744 | 0 | case ICMP_INFO_REQUEST: |
745 | 0 | return "InformationRequest"; |
746 | 0 | case ICMP_INFO_REPLY: |
747 | 0 | return "InformationReply"; |
748 | 0 | case ICMP_ADDRESS_MASK_REQUEST: |
749 | 0 | return "AddressMaskRequest"; |
750 | 0 | case ICMP_ADDRESS_MASK_REPLY: |
751 | 0 | return "AddressMaskReply"; |
752 | 0 | default: |
753 | 0 | return "Unknown"; |
754 | 0 | } |
755 | 0 | } |
756 | | |
757 | | const FieldDescriptor IcmpLayer::SerializedFields::Type{ Layer::SerializedFields::MaxID + 1, "type" }; |
758 | | const FieldDescriptor IcmpLayer::SerializedFields::TypeName{ Layer::SerializedFields::MaxID + 2, "typeName" }; |
759 | | const FieldDescriptor IcmpLayer::SerializedFields::Code{ Layer::SerializedFields::MaxID + 3, "code" }; |
760 | | const FieldDescriptor IcmpLayer::SerializedFields::Checksum{ Layer::SerializedFields::MaxID + 4, "checksum" }; |
761 | | const FieldDescriptor IcmpLayer::SerializedFields::Id{ Layer::SerializedFields::MaxID + 5, "id" }; |
762 | | const FieldDescriptor IcmpLayer::SerializedFields::Sequence{ Layer::SerializedFields::MaxID + 6, "sequence" }; |
763 | | const FieldDescriptor IcmpLayer::SerializedFields::Timestamp{ Layer::SerializedFields::MaxID + 7, "timestamp" }; |
764 | | const FieldDescriptor IcmpLayer::SerializedFields::OriginateTimestamp{ Layer::SerializedFields::MaxID + 8, |
765 | | "originateTimestamp" }; |
766 | | const FieldDescriptor IcmpLayer::SerializedFields::ReceiveTimestamp{ Layer::SerializedFields::MaxID + 9, |
767 | | "receiveTimestamp" }; |
768 | | const FieldDescriptor IcmpLayer::SerializedFields::TransmitTimestamp{ Layer::SerializedFields::MaxID + 10, |
769 | | "transmitTimestamp" }; |
770 | | const FieldDescriptor IcmpLayer::SerializedFields::NextHopMTU{ Layer::SerializedFields::MaxID + 11, "nextHopMTU" }; |
771 | | const FieldDescriptor IcmpLayer::SerializedFields::GatewayAddress{ Layer::SerializedFields::MaxID + 12, |
772 | | "gatewayAddress" }; |
773 | | const FieldDescriptor IcmpLayer::SerializedFields::AddressMask{ Layer::SerializedFields::MaxID + 13, |
774 | | "addressMask" }; |
775 | | const FieldDescriptor IcmpLayer::SerializedFields::Pointer{ Layer::SerializedFields::MaxID + 14, "pointer" }; |
776 | | const FieldDescriptor IcmpLayer::SerializedFields::AddressEntrySize{ Layer::SerializedFields::MaxID + 15, |
777 | | "addressEntrySize" }; |
778 | | const FieldDescriptor IcmpLayer::SerializedFields::Lifetime{ Layer::SerializedFields::MaxID + 16, "lifetime" }; |
779 | | const FieldDescriptor IcmpLayer::SerializedFields::RouterAddresses{ Layer::SerializedFields::MaxID + 17, |
780 | | "routerAddresses" }; |
781 | | const FieldDescriptor IcmpLayer::SerializedFields::RouterAddressEntry{ 0, "routerAddressEntry" }; |
782 | | const FieldDescriptor IcmpLayer::SerializedFields::RouterAddress{ 0, "routerAddress" }; |
783 | | const FieldDescriptor IcmpLayer::SerializedFields::PreferenceLevel{ 1, "preferenceLevel" }; |
784 | | |
785 | | void IcmpLayer::serializeLayer(ObjectScope& serializer) const |
786 | 0 | { |
787 | 0 | serializer.writeField(SerializedFields::Type, getIcmpHeader()->type); |
788 | 0 | serializer.writeField(SerializedFields::TypeName, icmpMessageTypeToString(getMessageType())); |
789 | 0 | serializer.writeField(SerializedFields::Code, getIcmpHeader()->code); |
790 | 0 | serializer.writeHexField(SerializedFields::Checksum, be16toh(getIcmpHeader()->checksum)); |
791 | |
|
792 | 0 | switch (getMessageType()) |
793 | 0 | { |
794 | 0 | case ICMP_ECHO_REQUEST: |
795 | 0 | case ICMP_ECHO_REPLY: |
796 | 0 | { |
797 | 0 | auto* echo = (getMessageType() == ICMP_ECHO_REQUEST) ? const_cast<IcmpLayer*>(this)->getEchoRequestData() |
798 | 0 | : const_cast<IcmpLayer*>(this)->getEchoReplyData(); |
799 | 0 | if (echo && echo->header) |
800 | 0 | { |
801 | 0 | serializer.writeField(SerializedFields::Id, be16toh(echo->header->id)); |
802 | 0 | serializer.writeField(SerializedFields::Sequence, be16toh(echo->header->sequence)); |
803 | 0 | if (echo->header->timestamp != 0) |
804 | 0 | { |
805 | 0 | serializer.writeField(SerializedFields::Timestamp, echo->header->timestamp); |
806 | 0 | } |
807 | 0 | } |
808 | 0 | break; |
809 | 0 | } |
810 | 0 | case ICMP_TIMESTAMP_REQUEST: |
811 | 0 | case ICMP_TIMESTAMP_REPLY: |
812 | 0 | { |
813 | 0 | auto* ts = (getMessageType() == ICMP_TIMESTAMP_REQUEST) |
814 | 0 | ? const_cast<IcmpLayer*>(this)->getTimestampRequestData() |
815 | 0 | : const_cast<IcmpLayer*>(this)->getTimestampReplyData(); |
816 | 0 | if (ts) |
817 | 0 | { |
818 | 0 | serializer.writeField(SerializedFields::Id, be16toh(ts->id)); |
819 | 0 | serializer.writeField(SerializedFields::Sequence, be16toh(ts->sequence)); |
820 | 0 | serializer.writeField(SerializedFields::OriginateTimestamp, be32toh(ts->originateTimestamp)); |
821 | 0 | serializer.writeField(SerializedFields::ReceiveTimestamp, be32toh(ts->receiveTimestamp)); |
822 | 0 | serializer.writeField(SerializedFields::TransmitTimestamp, be32toh(ts->transmitTimestamp)); |
823 | 0 | } |
824 | 0 | break; |
825 | 0 | } |
826 | 0 | case ICMP_DEST_UNREACHABLE: |
827 | 0 | { |
828 | 0 | auto* unreach = const_cast<IcmpLayer*>(this)->getDestUnreachableData(); |
829 | 0 | if (unreach) |
830 | 0 | { |
831 | 0 | serializer.writeField(SerializedFields::NextHopMTU, be16toh(unreach->nextHopMTU)); |
832 | 0 | } |
833 | 0 | break; |
834 | 0 | } |
835 | 0 | case ICMP_REDIRECT: |
836 | 0 | { |
837 | 0 | auto* redir = const_cast<IcmpLayer*>(this)->getRedirectData(); |
838 | 0 | if (redir) |
839 | 0 | { |
840 | 0 | serializer.writeField(SerializedFields::GatewayAddress, IPv4Address(redir->gatewayAddress).toString()); |
841 | 0 | } |
842 | 0 | break; |
843 | 0 | } |
844 | 0 | case ICMP_PARAM_PROBLEM: |
845 | 0 | { |
846 | 0 | auto* param = const_cast<IcmpLayer*>(this)->getParamProblemData(); |
847 | 0 | if (param) |
848 | 0 | { |
849 | 0 | serializer.writeField(SerializedFields::Pointer, param->pointer); |
850 | 0 | } |
851 | 0 | break; |
852 | 0 | } |
853 | 0 | case ICMP_ROUTER_ADV: |
854 | 0 | { |
855 | 0 | auto* adv = getRouterAdvertisementData(); |
856 | 0 | if (adv && adv->header && m_DataLen >= sizeof(icmp_router_advertisement_hdr)) |
857 | 0 | { |
858 | 0 | serializer.writeField(SerializedFields::AddressEntrySize, adv->header->addressEntrySize); |
859 | 0 | serializer.writeField(SerializedFields::Lifetime, be16toh(adv->header->lifetime)); |
860 | 0 | auto arr = serializer.writeArray(SerializedFields::RouterAddresses); |
861 | | |
862 | | // getRouterAddress() returns nullptr for entries that aren't present in the layer data |
863 | 0 | for (int i = 0; i < adv->header->advertisementCount; ++i) |
864 | 0 | { |
865 | 0 | auto* routerAddr = adv->getRouterAddress(i); |
866 | 0 | if (routerAddr) |
867 | 0 | { |
868 | 0 | auto obj = arr.writeObject(SerializedFields::RouterAddressEntry); |
869 | 0 | obj.writeField(SerializedFields::RouterAddress, routerAddr->getAddress().toString()); |
870 | 0 | obj.writeField(SerializedFields::PreferenceLevel, routerAddr->preferenceLevel); |
871 | 0 | } |
872 | 0 | else |
873 | 0 | { |
874 | 0 | break; |
875 | 0 | } |
876 | 0 | } |
877 | 0 | } |
878 | 0 | break; |
879 | 0 | } |
880 | 0 | case ICMP_ADDRESS_MASK_REQUEST: |
881 | 0 | case ICMP_ADDRESS_MASK_REPLY: |
882 | 0 | { |
883 | 0 | auto* mask = (getMessageType() == ICMP_ADDRESS_MASK_REQUEST) |
884 | 0 | ? const_cast<IcmpLayer*>(this)->getAddressMaskRequestData() |
885 | 0 | : const_cast<IcmpLayer*>(this)->getAddressMaskReplyData(); |
886 | 0 | if (mask) |
887 | 0 | { |
888 | 0 | serializer.writeField(SerializedFields::Id, be16toh(mask->id)); |
889 | 0 | serializer.writeField(SerializedFields::Sequence, be16toh(mask->sequence)); |
890 | 0 | serializer.writeField(SerializedFields::AddressMask, IPv4Address(mask->addressMask).toString()); |
891 | 0 | } |
892 | 0 | break; |
893 | 0 | } |
894 | 0 | case ICMP_INFO_REQUEST: |
895 | 0 | case ICMP_INFO_REPLY: |
896 | 0 | { |
897 | 0 | auto* info = (getMessageType() == ICMP_INFO_REQUEST) ? const_cast<IcmpLayer*>(this)->getInfoRequestData() |
898 | 0 | : const_cast<IcmpLayer*>(this)->getInfoReplyData(); |
899 | 0 | if (info) |
900 | 0 | { |
901 | 0 | serializer.writeField(SerializedFields::Id, be16toh(info->id)); |
902 | 0 | serializer.writeField(SerializedFields::Sequence, be16toh(info->sequence)); |
903 | 0 | } |
904 | 0 | break; |
905 | 0 | } |
906 | 0 | default: |
907 | 0 | break; |
908 | 0 | } |
909 | 0 | } |
910 | | |
911 | | } // namespace pcpp |