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