Skip to content

Commit 6ce0cf7

Browse files
authored
Improve snoop file reader (#2050)
1 parent 0a0d2ad commit 6ce0cf7

File tree

3 files changed

+212
-28
lines changed

3 files changed

+212
-28
lines changed

Pcap++/header/PcapFileDevice.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -571,10 +571,10 @@ namespace pcpp
571571
#pragma pack()
572572

573573
LinkLayerType m_PcapLinkLayerType;
574-
std::ifstream m_snoopFile;
574+
std::ifstream m_SnoopFile;
575575

576576
bool readNextPacket(timespec& packetTimestamp, uint8_t* packetData, uint32_t packetDataLen,
577-
uint32_t& capturedLength);
577+
uint32_t& capturedLength, uint32_t& frameLength);
578578

579579
public:
580580
/// A constructor for this class that gets the snoop full path file name to open. Notice that after calling this
@@ -612,7 +612,7 @@ namespace pcpp
612612
/// @return True if the file is opened, false otherwise
613613
bool isOpened() const override
614614
{
615-
return m_snoopFile.is_open();
615+
return m_SnoopFile.is_open();
616616
}
617617

618618
/// Close the snoop file

Pcap++/src/PcapFileDevice.cpp

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1123,27 +1123,32 @@ namespace pcpp
11231123

11241124
SnoopFileReaderDevice::~SnoopFileReaderDevice()
11251125
{
1126-
m_snoopFile.close();
1126+
m_SnoopFile.close();
11271127
}
11281128

11291129
bool SnoopFileReaderDevice::open()
11301130
{
1131+
if (m_SnoopFile.is_open())
1132+
{
1133+
PCPP_LOG_ERROR("File already open");
1134+
return false;
1135+
}
1136+
11311137
resetStatisticCounters();
11321138

1133-
m_snoopFile.open(m_FileName.c_str(), std::ifstream::binary);
1134-
if (!m_snoopFile.is_open())
1139+
std::ifstream snoopFile;
1140+
snoopFile.open(m_FileName.c_str(), std::ifstream::binary);
1141+
if (!snoopFile.is_open())
11351142
{
11361143
PCPP_LOG_ERROR("Cannot open snoop reader device for filename '" << m_FileName << "'");
1137-
m_snoopFile.close();
11381144
return false;
11391145
}
11401146

11411147
snoop_file_header_t snoop_file_header;
1142-
m_snoopFile.read((char*)&snoop_file_header, sizeof(snoop_file_header_t));
1143-
if (!m_snoopFile)
1148+
snoopFile.read(reinterpret_cast<char*>(&snoop_file_header), sizeof(snoop_file_header_t));
1149+
if (!snoopFile)
11441150
{
11451151
PCPP_LOG_ERROR("Cannot read snoop file header for '" << m_FileName << "'");
1146-
m_snoopFile.close();
11471152
return false;
11481153
}
11491154

@@ -1170,22 +1175,22 @@ namespace pcpp
11701175
if (datalink_type > ARRAY_SIZE(snoop_encap) - 1)
11711176
{
11721177
PCPP_LOG_ERROR("Cannot read data link type for '" << m_FileName << "'");
1173-
m_snoopFile.close();
11741178
return false;
11751179
}
11761180

1181+
m_SnoopFile = std::move(snoopFile);
11771182
m_PcapLinkLayerType = snoop_encap[datalink_type];
11781183

11791184
PCPP_LOG_DEBUG("Successfully opened file reader device for filename '" << m_FileName << "'");
11801185
return true;
11811186
}
11821187

11831188
bool SnoopFileReaderDevice::readNextPacket(timespec& packetTimestamp, uint8_t* packetData, uint32_t packetDataLen,
1184-
uint32_t& capturedLength)
1189+
uint32_t& capturedLength, uint32_t& frameLength)
11851190
{
11861191
snoop_packet_header_t snoop_packet_header;
1187-
m_snoopFile.read(reinterpret_cast<char*>(&snoop_packet_header), sizeof(snoop_packet_header_t));
1188-
if (!m_snoopFile)
1192+
m_SnoopFile.read(reinterpret_cast<char*>(&snoop_packet_header), sizeof(snoop_packet_header_t));
1193+
if (!m_SnoopFile)
11891194
{
11901195
PCPP_LOG_ERROR("Failed to read packet metadata");
11911196
return false;
@@ -1194,26 +1199,26 @@ namespace pcpp
11941199
capturedLength = be32toh(snoop_packet_header.included_length);
11951200
if (capturedLength > packetDataLen)
11961201
{
1202+
PCPP_LOG_ERROR("Packet length " << capturedLength << " is too large");
11971203
return false;
11981204
}
11991205

1200-
m_snoopFile.read(reinterpret_cast<char*>(packetData), capturedLength);
1201-
if (!m_snoopFile)
1206+
m_SnoopFile.read(reinterpret_cast<char*>(packetData), capturedLength);
1207+
if (!m_SnoopFile)
12021208
{
1209+
PCPP_LOG_ERROR("Failed to read packet data");
12031210
return false;
12041211
}
12051212

12061213
packetTimestamp = { static_cast<time_t>(be32toh(snoop_packet_header.time_sec)),
12071214
static_cast<long>(be32toh(snoop_packet_header.time_usec)) * 1000 };
12081215

1216+
frameLength = be32toh(snoop_packet_header.original_length);
1217+
12091218
auto pad = be32toh(snoop_packet_header.packet_record_length) -
12101219
(sizeof(snoop_packet_header_t) + be32toh(snoop_packet_header.included_length));
12111220

1212-
m_snoopFile.ignore(pad);
1213-
if (!m_snoopFile)
1214-
{
1215-
return false;
1216-
}
1221+
m_SnoopFile.ignore(pad);
12171222

12181223
return true;
12191224
}
@@ -1228,15 +1233,15 @@ namespace pcpp
12281233

12291234
constexpr uint32_t maxPacketLength = 15'000;
12301235
timespec packetTimestamp{};
1231-
uint32_t capturedLength = 0;
1236+
uint32_t capturedLength = 0, frameLength = 0;
12321237
auto packetData = std::make_unique<uint8_t[]>(maxPacketLength);
12331238

1234-
while (readNextPacket(packetTimestamp, packetData.get(), maxPacketLength, capturedLength))
1239+
while (readNextPacket(packetTimestamp, packetData.get(), maxPacketLength, capturedLength, frameLength))
12351240
{
12361241
if (m_BpfWrapper.matches(packetData.get(), capturedLength, packetTimestamp, m_PcapLinkLayerType))
12371242
{
12381243
rawPacket.setRawData(capturedLength > 0 ? packetData.release() : nullptr, capturedLength, true,
1239-
packetTimestamp, m_PcapLinkLayerType);
1244+
packetTimestamp, m_PcapLinkLayerType, frameLength);
12401245
reportPacketProcessed();
12411246
return true;
12421247
}
@@ -1248,7 +1253,7 @@ namespace pcpp
12481253

12491254
void SnoopFileReaderDevice::close()
12501255
{
1251-
m_snoopFile.close();
1256+
m_SnoopFile.close();
12521257
PCPP_LOG_DEBUG("File reader closed for file '" << m_FileName << "'");
12531258
}
12541259
} // namespace pcpp

Tests/Pcap++Test/Tests/FileTests.cpp

Lines changed: 182 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "PcapFileDevice.h"
66
#include "../Common/PcapFileNamesDef.h"
77
#include "../Common/TestUtils.h"
8+
#include "EndianPortable.h"
89
#include <array>
910
#include <fstream>
1011
#include <chrono>
@@ -1792,17 +1793,88 @@ enum class SnoopPacketHeaderParam
17921793
TimestampSec,
17931794
TimestampUsec,
17941795
Caplen,
1795-
TotalLen
1796+
Wirelen,
1797+
Pad
17961798
};
17971799

1800+
std::vector<uint8_t> createSnoopPacketHeader(const std::unordered_map<SnoopPacketHeaderParam, uint32_t>& params)
1801+
{
1802+
struct snoop_packet_header
1803+
{
1804+
uint32_t original_length;
1805+
uint32_t included_length;
1806+
uint32_t packet_record_length;
1807+
uint32_t ndrops_cumulative;
1808+
uint32_t time_sec;
1809+
uint32_t time_usec;
1810+
};
1811+
1812+
// Defaults
1813+
uint32_t caplen = 1514;
1814+
uint32_t wirelen = 1514;
1815+
uint32_t pad = 0;
1816+
1817+
auto now = std::chrono::system_clock::now();
1818+
auto duration = now.time_since_epoch();
1819+
auto subSec = duration % std::chrono::seconds(1);
1820+
uint32_t sec = static_cast<uint32_t>(std::chrono::duration_cast<std::chrono::seconds>(duration).count());
1821+
uint32_t usec = static_cast<uint32_t>(std::chrono::duration_cast<std::chrono::microseconds>(subSec).count());
1822+
1823+
for (const auto& p : params)
1824+
{
1825+
switch (p.first)
1826+
{
1827+
case SnoopPacketHeaderParam::TimestampSec:
1828+
{
1829+
sec = p.second;
1830+
break;
1831+
}
1832+
case SnoopPacketHeaderParam::TimestampUsec:
1833+
{
1834+
usec = p.second;
1835+
break;
1836+
}
1837+
case SnoopPacketHeaderParam::Caplen:
1838+
{
1839+
caplen = p.second;
1840+
break;
1841+
}
1842+
case SnoopPacketHeaderParam::Wirelen:
1843+
{
1844+
wirelen = p.second;
1845+
break;
1846+
}
1847+
case SnoopPacketHeaderParam::Pad:
1848+
{
1849+
pad = p.second;
1850+
break;
1851+
}
1852+
}
1853+
}
1854+
1855+
snoop_packet_header header = { htobe32(wirelen),
1856+
htobe32(caplen),
1857+
htobe32(static_cast<uint32_t>(sizeof(snoop_packet_header) + caplen + pad)),
1858+
0u,
1859+
htobe32(sec),
1860+
htobe32(usec) };
1861+
1862+
std::vector<uint8_t> result(sizeof(snoop_packet_header));
1863+
std::memcpy(result.data(), &header, sizeof(snoop_packet_header));
1864+
return result;
1865+
}
1866+
17981867
PTF_TEST_CASE(TestSolarisSnoopFileRead)
17991868
{
18001869
SuppressLogs suppressLogs;
18011870

1871+
std::array<uint8_t, 5> packetData = { 0x01, 0x02, 0x03, 0x04, 0x05 };
1872+
18021873
// Basic test
18031874
{
18041875
pcpp::SnoopFileReaderDevice readerDev(EXAMPLE_SOLARIS_SNOOP);
18051876
PTF_ASSERT_TRUE(readerDev.open());
1877+
PTF_ASSERT_TRUE(readerDev.isOpened());
18061878
pcpp::RawPacket rawPacket;
18071879
int packetCount = 0;
18081880
int ethCount = 0;
@@ -1831,8 +1903,8 @@ PTF_TEST_CASE(TestSolarisSnoopFileRead)
18311903
pcpp::IPcapDevice::PcapStats readerStatistics;
18321904

18331905
readerDev.getStatistics(readerStatistics);
1834-
PTF_ASSERT_EQUAL((uint32_t)readerStatistics.packetsRecv, 250);
1835-
PTF_ASSERT_EQUAL((uint32_t)readerStatistics.packetsDrop, 0);
1906+
PTF_ASSERT_EQUAL(readerStatistics.packetsRecv, 250);
1907+
PTF_ASSERT_EQUAL(readerStatistics.packetsDrop, 0);
18361908

18371909
PTF_ASSERT_EQUAL(packetCount, 250);
18381910
PTF_ASSERT_EQUAL(ethCount, 142);
@@ -1870,6 +1942,65 @@ PTF_TEST_CASE(TestSolarisSnoopFileRead)
18701942
}
18711943

18721944
PTF_ASSERT_EQUAL(packetCount, 16);
1945+
1946+
pcpp::IPcapDevice::PcapStats readerStatistics;
1947+
readerDev.getStatistics(readerStatistics);
1948+
PTF_ASSERT_EQUAL(readerStatistics.packetsRecv, 16);
1949+
}
1950+
1951+
// Packet details
1952+
{
1953+
TempFile snoopFile("snoop");
1954+
snoopFile << createSnoopHeader({});
1955+
snoopFile << createSnoopPacketHeader({
1956+
{ SnoopPacketHeaderParam::Caplen, packetData.size() },
1957+
{ SnoopPacketHeaderParam::Wirelen, packetData.size() + 5 },
1958+
{ SnoopPacketHeaderParam::TimestampSec, 1234 },
1959+
{ SnoopPacketHeaderParam::TimestampUsec, 5678 }
1960+
});
1961+
snoopFile << packetData;
1962+
snoopFile.close();
1963+
1964+
pcpp::SnoopFileReaderDevice readerDev(snoopFile.getFileName());
1965+
PTF_ASSERT_TRUE(readerDev.open());
1966+
1967+
pcpp::RawPacket rawPacket;
1968+
PTF_ASSERT_TRUE(readerDev.getNextPacket(rawPacket));
1969+
1970+
PTF_ASSERT_EQUAL(rawPacket.getRawDataLen(), packetData.size());
1971+
PTF_ASSERT_EQUAL(rawPacket.getFrameLength(), packetData.size() + 5);
1972+
PTF_ASSERT_EQUAL(rawPacket.getPacketTimeStamp().tv_sec, 1234);
1973+
PTF_ASSERT_EQUAL(rawPacket.getPacketTimeStamp().tv_nsec, 5678000);
1974+
1975+
PTF_ASSERT_BUF_COMPARE(rawPacket.getRawData(), packetData.data(), packetData.size());
1976+
}
1977+
1978+
// Packet padding
1979+
{
1980+
TempFile snoopFile("snoop");
1981+
snoopFile << createSnoopHeader({});
1982+
snoopFile << createSnoopPacketHeader({
1983+
{ SnoopPacketHeaderParam::Caplen, packetData.size() },
1984+
{ SnoopPacketHeaderParam::Pad, 3 }
1985+
});
1986+
snoopFile << packetData;
1987+
snoopFile << std::array<uint8_t, 3>{ 0xff, 0xff, 0xff };
1988+
snoopFile << createSnoopPacketHeader({
1989+
{ SnoopPacketHeaderParam::Caplen, packetData.size() }
1990+
});
1991+
snoopFile << packetData;
1992+
snoopFile.close();
1993+
1994+
pcpp::SnoopFileReaderDevice readerDev(snoopFile.getFileName());
1995+
PTF_ASSERT_TRUE(readerDev.open());
1996+
1997+
pcpp::RawPacket rawPacket;
1998+
for (int i = 0; i < 2; i++)
1999+
{
2000+
PTF_ASSERT_TRUE(readerDev.getNextPacket(rawPacket));
2001+
PTF_ASSERT_EQUAL(rawPacket.getRawDataLen(), packetData.size());
2002+
PTF_ASSERT_BUF_COMPARE(rawPacket.getRawData(), packetData.data(), packetData.size());
2003+
}
18732004
}
18742005

18752006
// Device not open
@@ -1888,6 +2019,23 @@ PTF_TEST_CASE(TestSolarisSnoopFileRead)
18882019
"Cannot open snoop reader device for filename 'does_not_exist.snoop'");
18892020
}
18902021

2022+
// File already open
2023+
{
2024+
pcpp::SnoopFileReaderDevice readerDev(EXAMPLE_SOLARIS_SNOOP);
2025+
PTF_ASSERT_TRUE(readerDev.open());
2026+
2027+
PTF_ASSERT_FALSE(readerDev.open());
2028+
PTF_ASSERT_EQUAL(pcpp::Logger::getInstance().getLastError(), "File already open");
2029+
}
2030+
2031+
// Read packet from a non-open device
2032+
{
2033+
pcpp::SnoopFileReaderDevice readerDev(EXAMPLE_SOLARIS_SNOOP);
2034+
pcpp::RawPacket rawPacket;
2035+
PTF_ASSERT_FALSE(readerDev.getNextPacket(rawPacket));
2036+
PTF_ASSERT_EQUAL(pcpp::Logger::getInstance().getLastError(), "File device not open");
2037+
}
2038+
18912039
// Cannot read file header
18922040
{
18932041
TempFile snoopFile("snoop");
@@ -1897,6 +2045,7 @@ PTF_TEST_CASE(TestSolarisSnoopFileRead)
18972045
PTF_ASSERT_FALSE(readerDev.open());
18982046
PTF_ASSERT_EQUAL(pcpp::Logger::getInstance().getLastError(),
18992047
"Cannot read snoop file header for '" + snoopFile.getFileName() + "'");
2048+
PTF_ASSERT_FALSE(readerDev.isOpened());
19002049
}
19012050

19022051
// Wrong magic number
@@ -1953,6 +2102,36 @@ PTF_TEST_CASE(TestSolarisSnoopFileRead)
19532102
PTF_ASSERT_FALSE(readerDev.getNextPacket(rawPacket));
19542103
PTF_ASSERT_EQUAL(pcpp::Logger::getInstance().getLastError(), "Failed to read packet metadata");
19552104
}
2105+
2106+
// Packet data too large
2107+
{
2108+
TempFile snoopFile("snoop");
2109+
snoopFile << createSnoopHeader({});
2110+
snoopFile << createSnoopPacketHeader({
2111+
{ SnoopPacketHeaderParam::Caplen, 15'500 }
2112+
});
2113+
snoopFile.close();
2114+
2115+
pcpp::SnoopFileReaderDevice readerDev(snoopFile.getFileName());
2116+
PTF_ASSERT_TRUE(readerDev.open());
2117+
pcpp::RawPacket rawPacket;
2118+
PTF_ASSERT_FALSE(readerDev.getNextPacket(rawPacket));
2119+
PTF_ASSERT_EQUAL(pcpp::Logger::getInstance().getLastError(), "Packet length 15500 is too large");
2120+
}
2121+
2122+
// Cannot read packet data
2123+
{
2124+
TempFile snoopFile("snoop");
2125+
snoopFile << createSnoopHeader({});
2126+
snoopFile << createSnoopPacketHeader({});
2127+
snoopFile.close();
2128+
2129+
pcpp::SnoopFileReaderDevice readerDev(snoopFile.getFileName());
2130+
PTF_ASSERT_TRUE(readerDev.open());
2131+
pcpp::RawPacket rawPacket;
2132+
PTF_ASSERT_FALSE(readerDev.getNextPacket(rawPacket));
2133+
PTF_ASSERT_EQUAL(pcpp::Logger::getInstance().getLastError(), "Failed to read packet data");
2134+
}
19562135
} // TestSolarisSnoopFileRead
19572136

19582137
PTF_TEST_CASE(TestPcapFileWriterDeviceDestructor)

0 commit comments

Comments
 (0)