/src/PcapPlusPlus/Pcap++/src/PcapFileDevice.cpp
Line | Count | Source (jump to first uncovered line) |
1 | 50.6k | #define LOG_MODULE PcapLogModuleFileDevice |
2 | | |
3 | | #include <stdio.h> |
4 | | #include <cerrno> |
5 | | #include "PcapFileDevice.h" |
6 | | #include "light_pcapng_ext.h" |
7 | | #include "Logger.h" |
8 | | #include "TimespecTimeval.h" |
9 | | #include "pcap.h" |
10 | | #include <string.h> |
11 | | #include <fstream> |
12 | | #include "EndianPortable.h" |
13 | | |
14 | | namespace pcpp |
15 | | { |
16 | | |
17 | | template <typename T, size_t N> |
18 | 0 | constexpr size_t ARRAY_SIZE(T (&)[N]) { return N; } |
19 | | |
20 | | struct pcap_file_header |
21 | | { |
22 | | uint32_t magic; |
23 | | uint16_t version_major; |
24 | | uint16_t version_minor; |
25 | | int32_t thiszone; |
26 | | uint32_t sigfigs; |
27 | | uint32_t snaplen; |
28 | | uint32_t linktype; |
29 | | }; |
30 | | |
31 | | struct packet_header |
32 | | { |
33 | | uint32_t tv_sec; |
34 | | uint32_t tv_usec; |
35 | | uint32_t caplen; |
36 | | uint32_t len; |
37 | | }; |
38 | | |
39 | | // ~~~~~~~~~~~~~~~~~~~ |
40 | | // IFileDevice members |
41 | | // ~~~~~~~~~~~~~~~~~~~ |
42 | | |
43 | | IFileDevice::IFileDevice(const std::string& fileName) : IPcapDevice() |
44 | 17.8k | { |
45 | 17.8k | m_FileName = fileName; |
46 | 17.8k | } |
47 | | |
48 | | IFileDevice::~IFileDevice() |
49 | 17.8k | { |
50 | 17.8k | IFileDevice::close(); |
51 | 17.8k | } |
52 | | |
53 | | std::string IFileDevice::getFileName() const |
54 | 0 | { |
55 | 0 | return m_FileName; |
56 | 0 | } |
57 | | |
58 | | void IFileDevice::close() |
59 | 33.5k | { |
60 | 33.5k | if (m_PcapDescriptor != NULL) |
61 | 16.8k | { |
62 | 16.8k | pcap_close(m_PcapDescriptor); |
63 | 16.8k | PCPP_LOG_DEBUG("Successfully closed file reader device for filename '" << m_FileName << "'"); |
64 | 16.8k | m_PcapDescriptor = NULL; |
65 | 16.8k | } |
66 | | |
67 | 33.5k | m_DeviceOpened = false; |
68 | 33.5k | } |
69 | | |
70 | | |
71 | | // ~~~~~~~~~~~~~~~~~~~~~~~~~ |
72 | | // IFileReaderDevice members |
73 | | // ~~~~~~~~~~~~~~~~~~~~~~~~~ |
74 | | |
75 | | IFileReaderDevice::IFileReaderDevice(const std::string& fileName) : IFileDevice(fileName) |
76 | 17.8k | { |
77 | 17.8k | m_NumOfPacketsNotParsed = 0; |
78 | 17.8k | m_NumOfPacketsRead = 0; |
79 | 17.8k | } |
80 | | |
81 | | IFileReaderDevice* IFileReaderDevice::getReader(const std::string& fileName) |
82 | 0 | { |
83 | 0 | const auto extensionPos = fileName.find_last_of('.'); |
84 | 0 | const auto fileExtension = extensionPos != std::string::npos ? fileName.substr(extensionPos) : ""; |
85 | |
|
86 | 0 | if (fileExtension == ".pcapng" || fileExtension == ".zstd" || fileExtension == ".zst") |
87 | 0 | return new PcapNgFileReaderDevice(fileName); |
88 | 0 | else if (fileExtension == ".snoop") |
89 | 0 | return new SnoopFileReaderDevice(fileName); |
90 | | |
91 | 0 | return new PcapFileReaderDevice(fileName); |
92 | 0 | } |
93 | | |
94 | | uint64_t IFileReaderDevice::getFileSize() const |
95 | 0 | { |
96 | 0 | std::ifstream fileStream(m_FileName.c_str(), std::ifstream::ate | std::ifstream::binary); |
97 | 0 | return fileStream.tellg(); |
98 | 0 | } |
99 | | |
100 | | int IFileReaderDevice::getNextPackets(RawPacketVector& packetVec, int numOfPacketsToRead) |
101 | 0 | { |
102 | 0 | int numOfPacketsRead = 0; |
103 | |
|
104 | 0 | for (; numOfPacketsToRead < 0 || numOfPacketsRead < numOfPacketsToRead; numOfPacketsRead++) |
105 | 0 | { |
106 | 0 | RawPacket* newPacket = new RawPacket(); |
107 | 0 | bool packetRead = getNextPacket(*newPacket); |
108 | 0 | if (packetRead) |
109 | 0 | { |
110 | 0 | packetVec.pushBack(newPacket); |
111 | 0 | } |
112 | 0 | else |
113 | 0 | { |
114 | 0 | delete newPacket; |
115 | 0 | break; |
116 | 0 | } |
117 | 0 | } |
118 | |
|
119 | 0 | return numOfPacketsRead; |
120 | 0 | } |
121 | | |
122 | | // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
123 | | // SnoopFileReaderDevice members |
124 | | // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
125 | | |
126 | | SnoopFileReaderDevice::~SnoopFileReaderDevice() |
127 | 0 | { |
128 | 0 | m_snoopFile.close(); |
129 | 0 | } |
130 | | |
131 | | bool SnoopFileReaderDevice::open() |
132 | 0 | { |
133 | 0 | m_NumOfPacketsRead = 0; |
134 | 0 | m_NumOfPacketsNotParsed = 0; |
135 | |
|
136 | 0 | m_snoopFile.open(m_FileName.c_str(), std::ifstream::binary); |
137 | 0 | if (!m_snoopFile.is_open()) |
138 | 0 | { |
139 | 0 | PCPP_LOG_ERROR("Cannot open snoop reader device for filename '" << m_FileName << "'"); |
140 | 0 | m_snoopFile.close(); |
141 | 0 | return false; |
142 | 0 | } |
143 | | |
144 | 0 | snoop_file_header_t snoop_file_header; |
145 | 0 | m_snoopFile.read((char*)&snoop_file_header, sizeof(snoop_file_header_t)); |
146 | 0 | if (!m_snoopFile) |
147 | 0 | { |
148 | 0 | PCPP_LOG_ERROR("Cannot read snoop file header for '" << m_FileName << "'"); |
149 | 0 | m_snoopFile.close(); |
150 | 0 | return false; |
151 | 0 | } |
152 | | |
153 | 0 | if(be64toh(snoop_file_header.identification_pattern) != 0x736e6f6f70000000 && be32toh(snoop_file_header.version_number) == 2) |
154 | 0 | return false; |
155 | | |
156 | | // From https://datatracker.ietf.org/doc/html/rfc1761 |
157 | 0 | static const pcpp::LinkLayerType snoop_encap[] = { |
158 | 0 | LINKTYPE_ETHERNET, /* IEEE 802.3 */ |
159 | 0 | LINKTYPE_NULL, /* IEEE 802.4 Token Bus */ |
160 | 0 | LINKTYPE_IEEE802_5, /* IEEE 802.5 */ |
161 | 0 | LINKTYPE_NULL, /* IEEE 802.6 Metro Net */ |
162 | 0 | LINKTYPE_ETHERNET, /* Ethernet */ |
163 | 0 | LINKTYPE_C_HDLC, /* HDLC */ |
164 | 0 | LINKTYPE_NULL, /* Character Synchronous, e.g. bisync */ |
165 | 0 | LINKTYPE_NULL, /* IBM Channel-to-Channel */ |
166 | 0 | LINKTYPE_FDDI /* FDDI */ |
167 | 0 | }; |
168 | 0 | uint32_t datalink_type = be32toh(snoop_file_header.datalink_type); |
169 | 0 | if (datalink_type > ARRAY_SIZE(snoop_encap) - 1) |
170 | 0 | { |
171 | 0 | PCPP_LOG_ERROR("Cannot read data link type for '" << m_FileName << "'"); |
172 | 0 | m_snoopFile.close(); |
173 | 0 | return false; |
174 | 0 | } |
175 | | |
176 | 0 | m_PcapLinkLayerType = snoop_encap[datalink_type]; |
177 | |
|
178 | 0 | PCPP_LOG_DEBUG("Successfully opened file reader device for filename '" << m_FileName << "'"); |
179 | 0 | m_DeviceOpened = true; |
180 | 0 | return true; |
181 | 0 | } |
182 | | |
183 | | void SnoopFileReaderDevice::getStatistics(PcapStats& stats) const |
184 | 0 | { |
185 | 0 | stats.packetsRecv = m_NumOfPacketsRead; |
186 | 0 | stats.packetsDrop = m_NumOfPacketsNotParsed; |
187 | 0 | stats.packetsDropByInterface = 0; |
188 | 0 | PCPP_LOG_DEBUG("Statistics received for reader device for filename '" << m_FileName << "'"); |
189 | 0 | } |
190 | | |
191 | | bool SnoopFileReaderDevice::getNextPacket(RawPacket& rawPacket) |
192 | 0 | { |
193 | 0 | rawPacket.clear(); |
194 | 0 | if (m_DeviceOpened != true) |
195 | 0 | { |
196 | 0 | PCPP_LOG_ERROR("File device '" << m_FileName << "' not opened"); |
197 | 0 | return false; |
198 | 0 | } |
199 | 0 | snoop_packet_header_t snoop_packet_header; |
200 | 0 | m_snoopFile.read((char*)&snoop_packet_header, sizeof(snoop_packet_header_t)); |
201 | 0 | if(!m_snoopFile) { |
202 | 0 | return false; |
203 | 0 | } |
204 | 0 | size_t packetSize = be32toh(snoop_packet_header.included_length); |
205 | 0 | if(packetSize > 15000) { |
206 | 0 | return false; |
207 | 0 | } |
208 | 0 | char* packetData = new char[packetSize]; |
209 | 0 | m_snoopFile.read(packetData, packetSize); |
210 | 0 | if(!m_snoopFile) { |
211 | 0 | return false; |
212 | 0 | } |
213 | 0 | timespec ts = { static_cast<time_t>(be32toh(snoop_packet_header.time_sec)), static_cast<long>(be32toh(snoop_packet_header.time_usec)) * 1000 }; |
214 | 0 | if (!rawPacket.setRawData((const uint8_t*)packetData, packetSize, ts, static_cast<LinkLayerType>(m_PcapLinkLayerType))) |
215 | 0 | { |
216 | 0 | PCPP_LOG_ERROR("Couldn't set data to raw packet"); |
217 | 0 | return false; |
218 | 0 | } |
219 | 0 | size_t pad = be32toh(snoop_packet_header.packet_record_length) - (sizeof(snoop_packet_header_t) + be32toh(snoop_packet_header.included_length)); |
220 | 0 | m_snoopFile.ignore(pad); |
221 | 0 | if(!m_snoopFile) { |
222 | 0 | return false; |
223 | 0 | } |
224 | | |
225 | 0 | m_NumOfPacketsRead++; |
226 | 0 | return true; |
227 | 0 | } |
228 | | |
229 | | void SnoopFileReaderDevice::close() |
230 | 0 | { |
231 | 0 | m_snoopFile.close(); |
232 | 0 | m_DeviceOpened = false; |
233 | 0 | PCPP_LOG_DEBUG("File reader closed for file '" << m_FileName << "'"); |
234 | 0 | } |
235 | | |
236 | | |
237 | | // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
238 | | // PcapFileReaderDevice members |
239 | | // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
240 | | |
241 | | |
242 | | bool PcapFileReaderDevice::open() |
243 | 17.8k | { |
244 | 17.8k | m_NumOfPacketsRead = 0; |
245 | 17.8k | m_NumOfPacketsNotParsed = 0; |
246 | | |
247 | 17.8k | if (m_PcapDescriptor != NULL) |
248 | 0 | { |
249 | 0 | PCPP_LOG_DEBUG("Pcap descriptor already opened. Nothing to do"); |
250 | 0 | return true; |
251 | 0 | } |
252 | | |
253 | 17.8k | char errbuf[PCAP_ERRBUF_SIZE]; |
254 | 17.8k | #if defined(PCAP_TSTAMP_PRECISION_NANO) |
255 | 17.8k | m_PcapDescriptor = pcap_open_offline_with_tstamp_precision(m_FileName.c_str(), PCAP_TSTAMP_PRECISION_NANO, errbuf); |
256 | | #else |
257 | | m_PcapDescriptor = pcap_open_offline(m_FileName.c_str(), errbuf); |
258 | | #endif |
259 | 17.8k | if (m_PcapDescriptor == NULL) |
260 | 833 | { |
261 | 833 | PCPP_LOG_ERROR("Cannot open file reader device for filename '" << m_FileName << "': " << errbuf); |
262 | 833 | m_DeviceOpened = false; |
263 | 833 | return false; |
264 | 833 | } |
265 | | |
266 | 16.9k | int linkLayer = pcap_datalink(m_PcapDescriptor); |
267 | 16.9k | if (!RawPacket::isLinkTypeValid(linkLayer)) |
268 | 95 | { |
269 | 95 | PCPP_LOG_ERROR("Invalid link layer (" << linkLayer << ") for reader device filename '" << m_FileName << "'"); |
270 | 95 | pcap_close(m_PcapDescriptor); |
271 | 95 | m_PcapDescriptor = NULL; |
272 | 95 | m_DeviceOpened = false; |
273 | 95 | return false; |
274 | 95 | } |
275 | | |
276 | 16.8k | m_PcapLinkLayerType = static_cast<LinkLayerType>(linkLayer); |
277 | | |
278 | 16.8k | PCPP_LOG_DEBUG("Successfully opened file reader device for filename '" << m_FileName << "'"); |
279 | 16.8k | m_DeviceOpened = true; |
280 | 16.8k | return true; |
281 | 16.9k | } |
282 | | |
283 | | void PcapFileReaderDevice::getStatistics(PcapStats& stats) const |
284 | 0 | { |
285 | 0 | stats.packetsRecv = m_NumOfPacketsRead; |
286 | 0 | stats.packetsDrop = m_NumOfPacketsNotParsed; |
287 | 0 | stats.packetsDropByInterface = 0; |
288 | 0 | PCPP_LOG_DEBUG("Statistics received for reader device for filename '" << m_FileName << "'"); |
289 | 0 | } |
290 | | |
291 | | bool PcapFileReaderDevice::getNextPacket(RawPacket& rawPacket) |
292 | 915k | { |
293 | 915k | rawPacket.clear(); |
294 | 915k | if (m_PcapDescriptor == NULL) |
295 | 0 | { |
296 | 0 | PCPP_LOG_ERROR("File device '" << m_FileName << "' not opened"); |
297 | 0 | return false; |
298 | 0 | } |
299 | 915k | pcap_pkthdr pkthdr; |
300 | 915k | const uint8_t* pPacketData = pcap_next(m_PcapDescriptor, &pkthdr); |
301 | 915k | if (pPacketData == NULL) |
302 | 16.8k | { |
303 | 16.8k | PCPP_LOG_DEBUG("Packet could not be read. Probably end-of-file"); |
304 | 16.8k | return false; |
305 | 16.8k | } |
306 | | |
307 | 898k | uint8_t* pMyPacketData = new uint8_t[pkthdr.caplen]; |
308 | 898k | memcpy(pMyPacketData, pPacketData, pkthdr.caplen); |
309 | 898k | #if defined(PCAP_TSTAMP_PRECISION_NANO) |
310 | 898k | timespec ts = { pkthdr.ts.tv_sec, static_cast<long>(pkthdr.ts.tv_usec) }; //because we opened with nano second precision 'tv_usec' is actually nanos |
311 | | #else |
312 | | struct timeval ts = pkthdr.ts; |
313 | | #endif |
314 | 898k | if (!rawPacket.setRawData(pMyPacketData, pkthdr.caplen, ts, static_cast<LinkLayerType>(m_PcapLinkLayerType), pkthdr.len)) |
315 | 0 | { |
316 | 0 | PCPP_LOG_ERROR("Couldn't set data to raw packet"); |
317 | 0 | return false; |
318 | 0 | } |
319 | 898k | m_NumOfPacketsRead++; |
320 | 898k | return true; |
321 | 898k | } |
322 | | |
323 | | |
324 | | // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
325 | | // PcapNgFileReaderDevice members |
326 | | // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
327 | | |
328 | | PcapNgFileReaderDevice::PcapNgFileReaderDevice(const std::string& fileName) : IFileReaderDevice(fileName) |
329 | 0 | { |
330 | 0 | m_LightPcapNg = NULL; |
331 | 0 | } |
332 | | |
333 | | bool PcapNgFileReaderDevice::open() |
334 | 0 | { |
335 | 0 | m_NumOfPacketsRead = 0; |
336 | 0 | m_NumOfPacketsNotParsed = 0; |
337 | |
|
338 | 0 | if (m_LightPcapNg != NULL) |
339 | 0 | { |
340 | 0 | PCPP_LOG_DEBUG("pcapng descriptor already opened. Nothing to do"); |
341 | 0 | return true; |
342 | 0 | } |
343 | | |
344 | 0 | m_LightPcapNg = light_pcapng_open_read(m_FileName.c_str(), LIGHT_FALSE); |
345 | 0 | if (m_LightPcapNg == NULL) |
346 | 0 | { |
347 | 0 | PCPP_LOG_ERROR("Cannot open pcapng reader device for filename '" << m_FileName << "'"); |
348 | 0 | m_DeviceOpened = false; |
349 | 0 | return false; |
350 | 0 | } |
351 | | |
352 | 0 | PCPP_LOG_DEBUG("Successfully opened pcapng reader device for filename '" << m_FileName << "'"); |
353 | 0 | m_DeviceOpened = true; |
354 | 0 | return true; |
355 | 0 | } |
356 | | |
357 | | bool PcapNgFileReaderDevice::getNextPacket(RawPacket& rawPacket, std::string& packetComment) |
358 | 0 | { |
359 | 0 | rawPacket.clear(); |
360 | 0 | packetComment = ""; |
361 | |
|
362 | 0 | if (m_LightPcapNg == NULL) |
363 | 0 | { |
364 | 0 | PCPP_LOG_ERROR("Pcapng file device '" << m_FileName << "' not opened"); |
365 | 0 | return false; |
366 | 0 | } |
367 | | |
368 | 0 | light_packet_header pktHeader; |
369 | 0 | const uint8_t* pktData = NULL; |
370 | |
|
371 | 0 | if (!light_get_next_packet((light_pcapng_t*)m_LightPcapNg, &pktHeader, &pktData)) |
372 | 0 | { |
373 | 0 | PCPP_LOG_DEBUG("Packet could not be read. Probably end-of-file"); |
374 | 0 | return false; |
375 | 0 | } |
376 | | |
377 | 0 | while (!m_BpfWrapper.matchPacketWithFilter(pktData, pktHeader.captured_length, pktHeader.timestamp, pktHeader.data_link)) |
378 | 0 | { |
379 | 0 | if (!light_get_next_packet((light_pcapng_t*)m_LightPcapNg, &pktHeader, &pktData)) |
380 | 0 | { |
381 | 0 | PCPP_LOG_DEBUG("Packet could not be read. Probably end-of-file"); |
382 | 0 | return false; |
383 | 0 | } |
384 | 0 | } |
385 | | |
386 | 0 | uint8_t* myPacketData = new uint8_t[pktHeader.captured_length]; |
387 | 0 | memcpy(myPacketData, pktData, pktHeader.captured_length); |
388 | 0 | if (!rawPacket.setRawData(myPacketData, pktHeader.captured_length, pktHeader.timestamp, static_cast<LinkLayerType>(pktHeader.data_link), pktHeader.original_length)) |
389 | 0 | { |
390 | 0 | PCPP_LOG_ERROR("Couldn't set data to raw packet"); |
391 | 0 | return false; |
392 | 0 | } |
393 | | |
394 | 0 | if (pktHeader.comment != NULL && pktHeader.comment_length > 0) |
395 | 0 | packetComment = std::string(pktHeader.comment, pktHeader.comment_length); |
396 | |
|
397 | 0 | m_NumOfPacketsRead++; |
398 | 0 | return true; |
399 | 0 | } |
400 | | |
401 | | bool PcapNgFileReaderDevice::getNextPacket(RawPacket& rawPacket) |
402 | 0 | { |
403 | 0 | std::string temp; |
404 | 0 | return getNextPacket(rawPacket, temp); |
405 | 0 | } |
406 | | |
407 | | void PcapNgFileReaderDevice::getStatistics(PcapStats& stats) const |
408 | 0 | { |
409 | 0 | stats.packetsRecv = m_NumOfPacketsRead; |
410 | 0 | stats.packetsDrop = m_NumOfPacketsNotParsed; |
411 | 0 | stats.packetsDropByInterface = 0; |
412 | 0 | PCPP_LOG_DEBUG("Statistics received for pcapng reader device for filename '" << m_FileName << "'"); |
413 | 0 | } |
414 | | |
415 | | bool PcapNgFileReaderDevice::setFilter(std::string filterAsString) |
416 | 0 | { |
417 | 0 | return m_BpfWrapper.setFilter(filterAsString); |
418 | 0 | } |
419 | | |
420 | | void PcapNgFileReaderDevice::close() |
421 | 0 | { |
422 | 0 | if (m_LightPcapNg == NULL) |
423 | 0 | return; |
424 | | |
425 | 0 | light_pcapng_close((light_pcapng_t*)m_LightPcapNg); |
426 | 0 | m_LightPcapNg = NULL; |
427 | |
|
428 | 0 | m_DeviceOpened = false; |
429 | 0 | PCPP_LOG_DEBUG("File reader closed for file '" << m_FileName << "'"); |
430 | 0 | } |
431 | | |
432 | | |
433 | | std::string PcapNgFileReaderDevice::getOS() const |
434 | 0 | { |
435 | 0 | if (m_LightPcapNg == NULL) |
436 | 0 | { |
437 | 0 | PCPP_LOG_ERROR("Pcapng file device '" << m_FileName << "' not opened"); |
438 | 0 | return ""; |
439 | 0 | } |
440 | | |
441 | 0 | light_pcapng_file_info* fileInfo = light_pcang_get_file_info((light_pcapng_t*)m_LightPcapNg); |
442 | 0 | char* res = fileInfo->os_desc; |
443 | 0 | size_t len = fileInfo->os_desc_size; |
444 | 0 | if (len == 0 || res == NULL) |
445 | 0 | return ""; |
446 | | |
447 | 0 | return std::string(res, len); |
448 | 0 | } |
449 | | |
450 | | std::string PcapNgFileReaderDevice::getHardware() const |
451 | 0 | { |
452 | 0 | if (m_LightPcapNg == NULL) |
453 | 0 | { |
454 | 0 | PCPP_LOG_ERROR("Pcapng file device '" << m_FileName << "' not opened"); |
455 | 0 | return ""; |
456 | 0 | } |
457 | | |
458 | 0 | light_pcapng_file_info* fileInfo = light_pcang_get_file_info((light_pcapng_t*)m_LightPcapNg); |
459 | 0 | char* res = fileInfo->hardware_desc; |
460 | 0 | size_t len = fileInfo->hardware_desc_size; |
461 | 0 | if (len == 0 || res == NULL) |
462 | 0 | return ""; |
463 | | |
464 | 0 | return std::string(res, len); |
465 | 0 | } |
466 | | |
467 | | std::string PcapNgFileReaderDevice::getCaptureApplication() const |
468 | 0 | { |
469 | 0 | if (m_LightPcapNg == NULL) |
470 | 0 | { |
471 | 0 | PCPP_LOG_ERROR("Pcapng file device '" << m_FileName << "' not opened"); |
472 | 0 | return ""; |
473 | 0 | } |
474 | | |
475 | 0 | light_pcapng_file_info* fileInfo = light_pcang_get_file_info((light_pcapng_t*)m_LightPcapNg); |
476 | 0 | char* res = fileInfo->user_app_desc; |
477 | 0 | size_t len = fileInfo->user_app_desc_size; |
478 | 0 | if (len == 0 || res == NULL) |
479 | 0 | return ""; |
480 | | |
481 | 0 | return std::string(res, len); |
482 | 0 | } |
483 | | |
484 | | std::string PcapNgFileReaderDevice::getCaptureFileComment() const |
485 | 0 | { |
486 | 0 | if (m_LightPcapNg == NULL) |
487 | 0 | { |
488 | 0 | PCPP_LOG_ERROR("Pcapng file device '" << m_FileName << "' not opened"); |
489 | 0 | return ""; |
490 | 0 | } |
491 | | |
492 | 0 | light_pcapng_file_info* fileInfo = light_pcang_get_file_info((light_pcapng_t*)m_LightPcapNg); |
493 | 0 | char* res = fileInfo->file_comment; |
494 | 0 | size_t len = fileInfo->file_comment_size; |
495 | 0 | if (len == 0 || res == NULL) |
496 | 0 | return ""; |
497 | | |
498 | 0 | return std::string(res, len); |
499 | 0 | } |
500 | | |
501 | | |
502 | | // ~~~~~~~~~~~~~~~~~~~~~~~~~ |
503 | | // IFileWriterDevice members |
504 | | // ~~~~~~~~~~~~~~~~~~~~~~~~~ |
505 | | |
506 | | IFileWriterDevice:: IFileWriterDevice(const std::string& fileName) : IFileDevice(fileName) |
507 | 0 | { |
508 | 0 | m_NumOfPacketsNotWritten = 0; |
509 | 0 | m_NumOfPacketsWritten = 0; |
510 | 0 | } |
511 | | |
512 | | |
513 | | // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
514 | | // PcapFileWriterDevice members |
515 | | // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
516 | | |
517 | | PcapFileWriterDevice::PcapFileWriterDevice(const std::string& fileName, LinkLayerType linkLayerType) : IFileWriterDevice(fileName) |
518 | 0 | { |
519 | 0 | m_PcapDumpHandler = NULL; |
520 | 0 | m_NumOfPacketsNotWritten = 0; |
521 | 0 | m_NumOfPacketsWritten = 0; |
522 | 0 | m_PcapLinkLayerType = linkLayerType; |
523 | 0 | m_AppendMode = false; |
524 | 0 | m_File = NULL; |
525 | 0 | } |
526 | | |
527 | | void PcapFileWriterDevice::closeFile() |
528 | 0 | { |
529 | 0 | if (m_AppendMode && m_File != NULL) |
530 | 0 | { |
531 | 0 | fclose(m_File); |
532 | 0 | m_File = NULL; |
533 | 0 | } |
534 | 0 | } |
535 | | |
536 | | bool PcapFileWriterDevice::writePacket(RawPacket const& packet) |
537 | 0 | { |
538 | 0 | if ((!m_AppendMode && m_PcapDescriptor == NULL) || (m_PcapDumpHandler == NULL)) |
539 | 0 | { |
540 | 0 | PCPP_LOG_ERROR("Device not opened"); |
541 | 0 | m_NumOfPacketsNotWritten++; |
542 | 0 | return false; |
543 | 0 | } |
544 | | |
545 | 0 | if (packet.getLinkLayerType() != m_PcapLinkLayerType) |
546 | 0 | { |
547 | 0 | PCPP_LOG_ERROR("Cannot write a packet with a different link layer type"); |
548 | 0 | m_NumOfPacketsNotWritten++; |
549 | 0 | return false; |
550 | 0 | } |
551 | | |
552 | 0 | pcap_pkthdr pktHdr; |
553 | 0 | pktHdr.caplen = ((RawPacket&)packet).getRawDataLen(); |
554 | 0 | pktHdr.len = ((RawPacket&)packet).getFrameLength(); |
555 | 0 | timespec packet_timestamp = ((RawPacket&)packet).getPacketTimeStamp(); |
556 | 0 | TIMESPEC_TO_TIMEVAL(&pktHdr.ts, &packet_timestamp); |
557 | 0 | if (!m_AppendMode) |
558 | 0 | pcap_dump((uint8_t*)m_PcapDumpHandler, &pktHdr, ((RawPacket&)packet).getRawData()); |
559 | 0 | else |
560 | 0 | { |
561 | | // Below are actually the lines run by pcap_dump. The reason I had to put them instead pcap_dump is that on Windows using WinPcap/Npcap |
562 | | // you can't pass pointers between libraries compiled with different compilers. In this case - PcapPlusPlus and WinPcap/Npcap weren't |
563 | | // compiled with the same compiler so it's impossible to fopen a file in PcapPlusPlus, pass the pointer to WinPcap/Npcap and use the |
564 | | // FILE* pointer there. Doing this throws an exception. So the only option when implementing append to pcap is to write all relevant |
565 | | // WinPcap/Npcap code that handles opening/closing/writing to pcap files inside PcapPlusPlus code |
566 | | |
567 | | // the reason to create this packet_header struct is timeval has different sizes in 32-bit and 64-bit systems, |
568 | | // but pcap format uses the 32-bit timeval version, so we need to align timeval to that |
569 | 0 | packet_header pktHdrTemp; |
570 | 0 | pktHdrTemp.tv_sec = pktHdr.ts.tv_sec; |
571 | 0 | pktHdrTemp.tv_usec = pktHdr.ts.tv_usec; |
572 | 0 | pktHdrTemp.caplen = pktHdr.caplen; |
573 | 0 | pktHdrTemp.len = pktHdr.len; |
574 | 0 | fwrite(&pktHdrTemp, sizeof(pktHdrTemp), 1, m_File); |
575 | 0 | fwrite(((RawPacket&)packet).getRawData(), pktHdrTemp.caplen, 1, m_File); |
576 | 0 | } |
577 | 0 | PCPP_LOG_DEBUG("Packet written successfully to '" << m_FileName << "'"); |
578 | 0 | m_NumOfPacketsWritten++; |
579 | 0 | return true; |
580 | 0 | } |
581 | | |
582 | | bool PcapFileWriterDevice::writePackets(const RawPacketVector& packets) |
583 | 0 | { |
584 | 0 | for (RawPacketVector::ConstVectorIterator iter = packets.begin(); iter != packets.end(); iter++) |
585 | 0 | { |
586 | 0 | if (!writePacket(**iter)) |
587 | 0 | return false; |
588 | 0 | } |
589 | | |
590 | 0 | return true; |
591 | 0 | } |
592 | | |
593 | | bool PcapFileWriterDevice::open() |
594 | 0 | { |
595 | 0 | if (m_PcapDescriptor != NULL) |
596 | 0 | { |
597 | 0 | PCPP_LOG_DEBUG("Pcap descriptor already opened. Nothing to do"); |
598 | 0 | return true; |
599 | 0 | } |
600 | | |
601 | 0 | switch(m_PcapLinkLayerType) |
602 | 0 | { |
603 | 0 | case LINKTYPE_RAW: |
604 | 0 | case LINKTYPE_DLT_RAW2: |
605 | 0 | PCPP_LOG_ERROR("The only Raw IP link type supported in libpcap/WinPcap/Npcap is LINKTYPE_DLT_RAW1, please use that instead"); |
606 | 0 | return false; |
607 | 0 | default: |
608 | 0 | break; |
609 | 0 | } |
610 | | |
611 | 0 | m_NumOfPacketsNotWritten = 0; |
612 | 0 | m_NumOfPacketsWritten = 0; |
613 | |
|
614 | 0 | m_PcapDescriptor = pcap_open_dead(m_PcapLinkLayerType, PCPP_MAX_PACKET_SIZE); |
615 | 0 | if (m_PcapDescriptor == NULL) |
616 | 0 | { |
617 | 0 | PCPP_LOG_ERROR("Error opening file writer device for file '" << m_FileName << "': pcap_open_dead returned NULL"); |
618 | 0 | m_DeviceOpened = false; |
619 | 0 | return false; |
620 | 0 | } |
621 | | |
622 | | |
623 | 0 | m_PcapDumpHandler = pcap_dump_open(m_PcapDescriptor, m_FileName.c_str()); |
624 | 0 | if (m_PcapDumpHandler == NULL) |
625 | 0 | { |
626 | 0 | PCPP_LOG_ERROR("Error opening file writer device for file '" << m_FileName << "': pcap_dump_open returned NULL with error: '" << pcap_geterr(m_PcapDescriptor) << "'"); |
627 | 0 | m_DeviceOpened = false; |
628 | 0 | return false; |
629 | 0 | } |
630 | | |
631 | 0 | m_DeviceOpened = true; |
632 | 0 | PCPP_LOG_DEBUG("File writer device for file '" << m_FileName << "' opened successfully"); |
633 | 0 | return true; |
634 | 0 | } |
635 | | |
636 | | void PcapFileWriterDevice::flush() |
637 | 0 | { |
638 | 0 | if (!m_DeviceOpened) |
639 | 0 | return; |
640 | | |
641 | 0 | if (!m_AppendMode && pcap_dump_flush(m_PcapDumpHandler) == -1) |
642 | 0 | { |
643 | 0 | PCPP_LOG_ERROR("Error while flushing the packets to file"); |
644 | 0 | } |
645 | | // in append mode it's impossible to use pcap_dump_flush, see comment above pcap_dump |
646 | 0 | else if (m_AppendMode && fflush(m_File) == EOF) |
647 | 0 | { |
648 | 0 | PCPP_LOG_ERROR("Error while flushing the packets to file"); |
649 | 0 | } |
650 | |
|
651 | 0 | } |
652 | | |
653 | | void PcapFileWriterDevice::close() |
654 | 0 | { |
655 | 0 | if (!m_DeviceOpened) |
656 | 0 | return; |
657 | | |
658 | 0 | flush(); |
659 | |
|
660 | 0 | IFileDevice::close(); |
661 | |
|
662 | 0 | if (!m_AppendMode && m_PcapDumpHandler != NULL) |
663 | 0 | { |
664 | 0 | pcap_dump_close(m_PcapDumpHandler); |
665 | 0 | } |
666 | 0 | else if (m_AppendMode && m_File != NULL) |
667 | 0 | { |
668 | | // in append mode it's impossible to use pcap_dump_close, see comment above pcap_dump |
669 | 0 | fclose(m_File); |
670 | 0 | } |
671 | |
|
672 | 0 | m_PcapDumpHandler = NULL; |
673 | 0 | m_File = NULL; |
674 | 0 | PCPP_LOG_DEBUG("File writer closed for file '" << m_FileName << "'"); |
675 | 0 | } |
676 | | |
677 | | void PcapFileWriterDevice::getStatistics(PcapStats& stats) const |
678 | 0 | { |
679 | 0 | stats.packetsRecv = m_NumOfPacketsWritten; |
680 | 0 | stats.packetsDrop = m_NumOfPacketsNotWritten; |
681 | 0 | stats.packetsDropByInterface = 0; |
682 | 0 | PCPP_LOG_DEBUG("Statistics received for writer device for filename '" << m_FileName << "'"); |
683 | 0 | } |
684 | | |
685 | | bool PcapFileWriterDevice::open(bool appendMode) |
686 | 0 | { |
687 | 0 | if (!appendMode) |
688 | 0 | return open(); |
689 | | |
690 | 0 | m_AppendMode = appendMode; |
691 | |
|
692 | 0 | #if !defined(_WIN32) |
693 | 0 | m_File = fopen(m_FileName.c_str(), "r+"); |
694 | | #else |
695 | | m_File = fopen(m_FileName.c_str(), "rb+"); |
696 | | #endif |
697 | |
|
698 | 0 | if (m_File == NULL) |
699 | 0 | { |
700 | 0 | PCPP_LOG_ERROR("Cannot open '" << m_FileName << "' for reading and writing"); |
701 | 0 | return false; |
702 | 0 | } |
703 | | |
704 | 0 | pcap_file_header pcapFileHeader; |
705 | 0 | int amountRead = fread(&pcapFileHeader, 1, sizeof(pcapFileHeader), m_File); |
706 | 0 | if (amountRead != sizeof(pcap_file_header)) |
707 | 0 | { |
708 | 0 | if (ferror(m_File)) |
709 | 0 | PCPP_LOG_ERROR("Cannot read pcap header from file '" << m_FileName << "', error was: " << errno); |
710 | 0 | else |
711 | 0 | PCPP_LOG_ERROR("Cannot read pcap header from file '" << m_FileName << "', unknown error"); |
712 | |
|
713 | 0 | closeFile(); |
714 | 0 | return false; |
715 | 0 | } |
716 | | |
717 | 0 | LinkLayerType linkLayerType = static_cast<LinkLayerType>(pcapFileHeader.linktype); |
718 | 0 | if (linkLayerType != m_PcapLinkLayerType) |
719 | 0 | { |
720 | 0 | PCPP_LOG_ERROR("Pcap file has a different link layer type than the one chosen in PcapFileWriterDevice c'tor, " << linkLayerType << ", " << m_PcapLinkLayerType); |
721 | 0 | closeFile(); |
722 | 0 | return false; |
723 | 0 | } |
724 | | |
725 | 0 | if (fseek(m_File, 0, SEEK_END) == -1) |
726 | 0 | { |
727 | 0 | PCPP_LOG_ERROR("Cannot read pcap file '" << m_FileName << "' to it's end, error was: " << errno); |
728 | 0 | closeFile(); |
729 | 0 | return false; |
730 | 0 | } |
731 | | |
732 | 0 | m_PcapDumpHandler = ((pcap_dumper_t *)m_File); |
733 | |
|
734 | 0 | m_DeviceOpened = true; |
735 | 0 | PCPP_LOG_DEBUG("File writer device for file '" << m_FileName << "' opened successfully in append mode"); |
736 | 0 | return true; |
737 | 0 | } |
738 | | |
739 | | |
740 | | // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
741 | | // PcapNgFileWriterDevice members |
742 | | // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
743 | | |
744 | | PcapNgFileWriterDevice::PcapNgFileWriterDevice(const std::string& fileName, int compressionLevel) : IFileWriterDevice(fileName) |
745 | 0 | { |
746 | 0 | m_LightPcapNg = NULL; |
747 | 0 | m_CompressionLevel = compressionLevel; |
748 | 0 | } |
749 | | |
750 | | bool PcapNgFileWriterDevice::open(const std::string& os, const std::string& hardware, const std::string& captureApp, const std::string& fileComment) |
751 | 0 | { |
752 | 0 | if (m_LightPcapNg != NULL) |
753 | 0 | { |
754 | 0 | PCPP_LOG_DEBUG("Pcap-ng descriptor already opened. Nothing to do"); |
755 | 0 | return true; |
756 | 0 | } |
757 | | |
758 | 0 | m_NumOfPacketsNotWritten = 0; |
759 | 0 | m_NumOfPacketsWritten = 0; |
760 | |
|
761 | 0 | light_pcapng_file_info* info = light_create_file_info(os.c_str(), hardware.c_str(), captureApp.c_str(), fileComment.c_str()); |
762 | |
|
763 | 0 | m_LightPcapNg = light_pcapng_open_write(m_FileName.c_str(), info, m_CompressionLevel); |
764 | 0 | if (m_LightPcapNg == NULL) |
765 | 0 | { |
766 | 0 | PCPP_LOG_ERROR("Error opening file writer device for file '" << m_FileName << "': light_pcapng_open_write returned NULL"); |
767 | |
|
768 | 0 | light_free_file_info(info); |
769 | |
|
770 | 0 | m_DeviceOpened = false; |
771 | 0 | return false; |
772 | 0 | } |
773 | | |
774 | 0 | m_DeviceOpened = true; |
775 | 0 | PCPP_LOG_DEBUG("pcap-ng writer device for file '" << m_FileName << "' opened successfully"); |
776 | 0 | return true; |
777 | 0 | } |
778 | | |
779 | | bool PcapNgFileWriterDevice::writePacket(RawPacket const& packet, const std::string& comment) |
780 | 0 | { |
781 | 0 | if (m_LightPcapNg == NULL) |
782 | 0 | { |
783 | 0 | PCPP_LOG_ERROR("Device not opened"); |
784 | 0 | m_NumOfPacketsNotWritten++; |
785 | 0 | return false; |
786 | 0 | } |
787 | | |
788 | 0 | if (!m_BpfWrapper.matchPacketWithFilter(&packet)) |
789 | 0 | { |
790 | 0 | return false; |
791 | 0 | } |
792 | | |
793 | 0 | light_packet_header pktHeader; |
794 | 0 | pktHeader.captured_length = ((RawPacket&)packet).getRawDataLen(); |
795 | 0 | pktHeader.original_length = ((RawPacket&)packet).getFrameLength(); |
796 | 0 | pktHeader.timestamp = ((RawPacket&)packet).getPacketTimeStamp(); |
797 | 0 | pktHeader.data_link = (uint16_t)packet.getLinkLayerType(); |
798 | 0 | pktHeader.interface_id = 0; |
799 | 0 | if (!comment.empty()) |
800 | 0 | { |
801 | 0 | pktHeader.comment = (char*)comment.c_str(); |
802 | 0 | pktHeader.comment_length = static_cast<uint16_t>(comment.size()); |
803 | 0 | } |
804 | 0 | else |
805 | 0 | { |
806 | 0 | pktHeader.comment = NULL; |
807 | 0 | pktHeader.comment_length = 0; |
808 | 0 | } |
809 | |
|
810 | 0 | const uint8_t* pktData = ((RawPacket&)packet).getRawData(); |
811 | |
|
812 | 0 | light_write_packet((light_pcapng_t*)m_LightPcapNg, &pktHeader, pktData); |
813 | 0 | m_NumOfPacketsWritten++; |
814 | 0 | return true; |
815 | 0 | } |
816 | | |
817 | | bool PcapNgFileWriterDevice::writePacket(RawPacket const& packet) |
818 | 0 | { |
819 | 0 | return writePacket(packet, std::string()); |
820 | 0 | } |
821 | | |
822 | | bool PcapNgFileWriterDevice::writePackets(const RawPacketVector& packets) |
823 | 0 | { |
824 | 0 | for (RawPacketVector::ConstVectorIterator iter = packets.begin(); iter != packets.end(); iter++) |
825 | 0 | { |
826 | 0 | if (!writePacket(**iter)) |
827 | 0 | return false; |
828 | 0 | } |
829 | | |
830 | 0 | return true; |
831 | 0 | } |
832 | | |
833 | | bool PcapNgFileWriterDevice::open() |
834 | 0 | { |
835 | 0 | if (m_LightPcapNg != NULL) |
836 | 0 | { |
837 | 0 | PCPP_LOG_DEBUG("Pcap-ng descriptor already opened. Nothing to do"); |
838 | 0 | return true; |
839 | 0 | } |
840 | | |
841 | 0 | m_NumOfPacketsNotWritten = 0; |
842 | 0 | m_NumOfPacketsWritten = 0; |
843 | |
|
844 | 0 | light_pcapng_file_info* info = light_create_default_file_info(); |
845 | |
|
846 | 0 | m_LightPcapNg = light_pcapng_open_write(m_FileName.c_str(), info, m_CompressionLevel); |
847 | 0 | if (m_LightPcapNg == NULL) |
848 | 0 | { |
849 | 0 | PCPP_LOG_ERROR("Error opening file writer device for file '" << m_FileName << "': light_pcapng_open_write returned NULL"); |
850 | |
|
851 | 0 | light_free_file_info(info); |
852 | |
|
853 | 0 | m_DeviceOpened = false; |
854 | 0 | return false; |
855 | 0 | } |
856 | | |
857 | 0 | m_DeviceOpened = true; |
858 | 0 | PCPP_LOG_DEBUG("pcap-ng writer device for file '" << m_FileName << "' opened successfully"); |
859 | 0 | return true; |
860 | 0 | } |
861 | | |
862 | | bool PcapNgFileWriterDevice::open(bool appendMode) |
863 | 0 | { |
864 | 0 | if (!appendMode) |
865 | 0 | return open(); |
866 | | |
867 | 0 | m_NumOfPacketsNotWritten = 0; |
868 | 0 | m_NumOfPacketsWritten = 0; |
869 | |
|
870 | 0 | m_LightPcapNg = light_pcapng_open_append(m_FileName.c_str()); |
871 | 0 | if (m_LightPcapNg == NULL) |
872 | 0 | { |
873 | 0 | PCPP_LOG_ERROR("Error opening file writer device in append mode for file '" << m_FileName << "': light_pcapng_open_append returned NULL"); |
874 | 0 | m_DeviceOpened = false; |
875 | 0 | return false; |
876 | 0 | } |
877 | | |
878 | 0 | m_DeviceOpened = true; |
879 | 0 | PCPP_LOG_DEBUG("pcap-ng writer device for file '" << m_FileName << "' opened successfully"); |
880 | 0 | return true; |
881 | |
|
882 | 0 | } |
883 | | |
884 | | void PcapNgFileWriterDevice::flush() |
885 | 0 | { |
886 | 0 | if (!m_DeviceOpened || m_LightPcapNg == NULL) |
887 | 0 | return; |
888 | | |
889 | 0 | light_pcapng_flush((light_pcapng_t*)m_LightPcapNg); |
890 | 0 | PCPP_LOG_DEBUG("File writer flushed to file '" << m_FileName << "'"); |
891 | 0 | } |
892 | | |
893 | | void PcapNgFileWriterDevice::close() |
894 | 0 | { |
895 | 0 | if (m_LightPcapNg == NULL) |
896 | 0 | return; |
897 | | |
898 | 0 | light_pcapng_close((light_pcapng_t*)m_LightPcapNg); |
899 | 0 | m_LightPcapNg = NULL; |
900 | |
|
901 | 0 | m_DeviceOpened = false; |
902 | 0 | PCPP_LOG_DEBUG("File writer closed for file '" << m_FileName << "'"); |
903 | 0 | } |
904 | | |
905 | | void PcapNgFileWriterDevice::getStatistics(PcapStats& stats) const |
906 | 0 | { |
907 | 0 | stats.packetsRecv = m_NumOfPacketsWritten; |
908 | 0 | stats.packetsDrop = m_NumOfPacketsNotWritten; |
909 | 0 | stats.packetsDropByInterface = 0; |
910 | 0 | PCPP_LOG_DEBUG("Statistics received for pcap-ng writer device for filename '" << m_FileName << "'"); |
911 | 0 | } |
912 | | |
913 | | bool PcapNgFileWriterDevice::setFilter(std::string filterAsString) |
914 | 0 | { |
915 | 0 | return m_BpfWrapper.setFilter(filterAsString); |
916 | 0 | } |
917 | | |
918 | | |
919 | | } // namespace pcpp |