Skip to content

Commit 44e9085

Browse files
authored
Read and write pcap files without libpcap (#2034)
1 parent 50c8430 commit 44e9085

File tree

13 files changed

+1655
-422
lines changed

13 files changed

+1655
-422
lines changed

.github/workflows/build_and_test.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ jobs:
156156
- name: Create Cobertura Report
157157
run: |
158158
. .venv/bin/activate
159-
python3 -m pip install gcovr
159+
python3 -m pip install gcovr==8.2
160160
gcovr -v -r . ${{ matrix.additional-gcov-flags }} $GCOVR_FLAGS -o coverage.xml
161161
162162
- name: Upload Coverage Results
@@ -226,7 +226,7 @@ jobs:
226226
- name: Create Cobertura Report
227227
run: |
228228
. .venv/bin/activate
229-
python3 -m pip install gcovr
229+
python3 -m pip install gcovr==8.2
230230
gcovr -v -r . $GCOVR_FLAGS -o coverage.xml
231231
232232
- name: Upload Coverage Results
@@ -471,7 +471,7 @@ jobs:
471471
- name: Create Cobertura Report
472472
if: ${{ matrix.host-arch == matrix.arch }}
473473
run: |
474-
python3 -m pip install gcovr
474+
python3 -m pip install gcovr==8.2
475475
gcovr -v -r . $GCOVR_FLAGS -o coverage.xml
476476
477477
- name: Upload Coverage Results
@@ -592,7 +592,7 @@ jobs:
592592
python -m pytest --root-path=../../Dist/examples_bin
593593
594594
- name: Install Coverage Requirements
595-
run: python3 -m pip install gcovr
595+
run: python3 -m pip install gcovr==8.2
596596

597597
- name: Process Coverage Files
598598
shell: msys2 {0}
@@ -906,7 +906,7 @@ jobs:
906906
907907
- name: Create Cobertura Report
908908
run: |
909-
python -m pip install gcovr
909+
python -m pip install gcovr==8.2
910910
gcovr -v -r . $GCOVR_FLAGS -o coverage.xml
911911
912912
- name: Upload Coverage Results

Pcap++/header/PcapFileDevice.h

Lines changed: 95 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -152,77 +152,84 @@ namespace pcpp
152152
/// packet-by-packet
153153
class PcapFileReaderDevice : public IFileReaderDevice
154154
{
155-
private:
156-
FileTimestampPrecision m_Precision;
157-
LinkLayerType m_PcapLinkLayerType;
158-
159-
// private copy c'tor
160-
PcapFileReaderDevice(const PcapFileReaderDevice& other);
161-
PcapFileReaderDevice& operator=(const PcapFileReaderDevice& other);
162-
163155
public:
164156
/// A constructor for this class that gets the pcap full path file name to open. Notice that after calling this
165157
/// constructor the file isn't opened yet, so reading packets will fail. For opening the file call open()
166158
/// @param[in] fileName The full path of the file to read
167-
PcapFileReaderDevice(const std::string& fileName)
168-
: IFileReaderDevice(fileName), m_Precision(FileTimestampPrecision::Unknown),
169-
m_PcapLinkLayerType(LINKTYPE_ETHERNET)
159+
explicit PcapFileReaderDevice(const std::string& fileName) : IFileReaderDevice(fileName)
170160
{}
171161

172162
/// A destructor for this class
173-
virtual ~PcapFileReaderDevice() = default;
163+
~PcapFileReaderDevice() override = default;
164+
165+
PcapFileReaderDevice(const PcapFileReaderDevice& other) = delete;
166+
PcapFileReaderDevice& operator=(const PcapFileReaderDevice& other) = delete;
174167

175168
/// @return The link layer type of this file
176169
LinkLayerType getLinkLayerType() const
177170
{
178171
return m_PcapLinkLayerType;
179172
}
180173

181-
/// @return The precision of the timestamps in the file. If the platform supports nanosecond precision, this
182-
/// method will return nanoseconds even if the file has microseconds since libpcap scales timestamps before
183-
/// supply. Otherwise, it will return microseconds.
174+
/// @return The precision of the timestamps in the file
184175
FileTimestampPrecision getTimestampPrecision() const
185176
{
186177
return m_Precision;
187178
}
188179

180+
/// @return The file's snapshot length (snaplen)
181+
uint32_t getSnapshotLength() const
182+
{
183+
return m_SnapshotLength;
184+
}
185+
189186
/// A static method that checks if nano-second precision is supported in the current platform and environment
190187
/// @return True if nano-second precision is supported, false otherwise
191-
static bool isNanoSecondPrecisionSupported();
188+
/// @deprecated Nanosecond precision is now natively supported by the internal parser and always returns true
189+
PCPP_DEPRECATED("Nanosecond precision is now natively supported by the internal parser and always returns true")
190+
static bool isNanoSecondPrecisionSupported()
191+
{
192+
return true;
193+
}
192194

193195
// overridden methods
194196

195197
/// Read the next packet from the file. Before using this method please verify the file is opened using open()
196198
/// @param[out] rawPacket A reference for an empty RawPacket where the packet will be written
197199
/// @return True if a packet was read successfully. False will be returned if the file isn't opened (also, an
198200
/// error log will be printed) or if reached end-of-file
199-
bool getNextPacket(RawPacket& rawPacket);
201+
bool getNextPacket(RawPacket& rawPacket) override;
200202

201203
/// Open the file name which path was specified in the constructor in a read-only mode
202204
/// @return True if file was opened successfully or if file is already opened. False if opening the file failed
203205
/// for some reason (for example: file path does not exist)
204-
bool open();
206+
bool open() override;
207+
208+
/// Close the pacp file
209+
void close() override;
210+
211+
protected:
212+
bool doUpdateFilter(std::string const* filterAsString) override;
213+
214+
private:
215+
FileTimestampPrecision m_Precision = FileTimestampPrecision::Unknown;
216+
LinkLayerType m_PcapLinkLayerType = LINKTYPE_ETHERNET;
217+
std::ifstream m_PcapFile;
218+
bool m_NeedsSwap = false;
219+
uint32_t m_SnapshotLength = 0;
220+
BpfFilterWrapper m_BpfWrapper;
221+
222+
bool readNextPacket(timespec& packetTimestamp, uint8_t* packetData, uint32_t packetDataLen,
223+
uint32_t& capturedLength, uint32_t& frameLength);
205224
};
206225

207226
/// @class PcapFileWriterDevice
208-
/// A class for opening a pcap file for writing or create a new pcap file and write packets to it. This class adds
209-
/// a unique capability that isn't supported in WinPcap and in older libpcap versions which is to open a pcap file
210-
/// in append mode where packets are written at the end of the pcap file instead of running it over
227+
/// A class for opening a pcap file for writing or creating a new pcap file and writing packets to it.
228+
/// It supports opening a pcap file in append mode where packets are written at the end of the file
229+
/// instead of overwriting it. This implementation writes the pcap stream directly using C++ I/O
230+
/// facilities (std::fstream) and does not require libpcap/WinPcap at runtime.
211231
class PcapFileWriterDevice : public IFileWriterDevice
212232
{
213-
private:
214-
pcap_dumper_t* m_PcapDumpHandler;
215-
LinkLayerType m_PcapLinkLayerType;
216-
bool m_AppendMode;
217-
FileTimestampPrecision m_Precision;
218-
FILE* m_File;
219-
220-
// private copy c'tor
221-
PcapFileWriterDevice(const PcapFileWriterDevice& other);
222-
PcapFileWriterDevice& operator=(const PcapFileWriterDevice& other);
223-
224-
void closeFile();
225-
226233
public:
227234
/// A constructor for this class that gets the pcap full path file name to open for writing or create. Notice
228235
/// that after calling this constructor the file isn't opened yet, so writing packets will fail. For opening the
@@ -237,11 +244,8 @@ namespace pcpp
237244
PcapFileWriterDevice(const std::string& fileName, LinkLayerType linkLayerType = LINKTYPE_ETHERNET,
238245
bool nanosecondsPrecision = false);
239246

240-
/// A destructor for this class
241-
~PcapFileWriterDevice()
242-
{
243-
PcapFileWriterDevice::close();
244-
}
247+
PcapFileWriterDevice(const PcapFileWriterDevice& other) = delete;
248+
PcapFileWriterDevice& operator=(const PcapFileWriterDevice& other) = delete;
245249

246250
/// Write a RawPacket to the file. Before using this method please verify the file is opened using open(). This
247251
/// method won't change the written packet
@@ -268,9 +272,17 @@ namespace pcpp
268272

269273
/// A static method that checks if nano-second precision is supported in the current platform and environment
270274
/// @return True if nano-second precision is supported, false otherwise
271-
static bool isNanoSecondPrecisionSupported();
275+
/// @deprecated Nanosecond precision is now natively supported by the internal parser and always returns true
276+
PCPP_DEPRECATED("Nanosecond precision is now natively supported by the internal parser and always returns true")
277+
static bool isNanoSecondPrecisionSupported()
278+
{
279+
return true;
280+
}
272281

273-
// override methods
282+
LinkLayerType getLinkLayerType() const
283+
{
284+
return m_PcapLinkLayerType;
285+
}
274286

275287
/// Open the file in a write mode. If file doesn't exist, it will be created. If it does exist it will be
276288
/// overwritten, meaning all its current content will be deleted
@@ -294,9 +306,49 @@ namespace pcpp
294306
/// Flush packets to disk.
295307
void flush();
296308

309+
protected:
310+
bool doUpdateFilter(std::string const* filterAsString) override;
311+
297312
private:
298-
bool openWrite();
299-
bool openAppend();
313+
LinkLayerType m_PcapLinkLayerType = LINKTYPE_ETHERNET;
314+
bool m_NeedsSwap = false;
315+
FileTimestampPrecision m_Precision = FileTimestampPrecision::Unknown;
316+
std::fstream m_PcapFile;
317+
BpfFilterWrapper m_BpfWrapper;
318+
319+
struct CheckHeaderResult
320+
{
321+
enum class Result
322+
{
323+
HeaderOk,
324+
HeaderError,
325+
HeaderNeeded
326+
};
327+
328+
Result result;
329+
std::string error;
330+
bool needsSwap = false;
331+
332+
static CheckHeaderResult fromOk(bool needsSwap)
333+
{
334+
return { Result::HeaderOk, "", needsSwap };
335+
}
336+
337+
static CheckHeaderResult fromError(const std::string& error)
338+
{
339+
return { Result::HeaderError, error };
340+
}
341+
342+
static CheckHeaderResult fromHeaderNeeded()
343+
{
344+
return { Result::HeaderNeeded };
345+
}
346+
};
347+
348+
static bool writeHeader(std::fstream& pcapFile, FileTimestampPrecision precision, uint32_t snaplen,
349+
LinkLayerType linkType);
350+
static CheckHeaderResult checkHeader(std::fstream& pcapFile, FileTimestampPrecision requestedPrecision,
351+
LinkLayerType requestedLinkType);
300352
};
301353

302354
/// @class PcapNgFileReaderDevice

0 commit comments

Comments
 (0)