Skip to content

Commit

Permalink
Add nanosecond precision to TCP reassembly (#1591)
Browse files Browse the repository at this point in the history
  • Loading branch information
seladb authored Oct 8, 2024
1 parent 98ecd59 commit 9f31f71
Show file tree
Hide file tree
Showing 5 changed files with 177 additions and 54 deletions.
43 changes: 23 additions & 20 deletions Packet++/header/TcpReassembly.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "IpAddress.h"
#include "PointerVector.h"
#include <unordered_map>
#include <chrono>
#include <map>
#include <list>
#include <time.h>
Expand Down Expand Up @@ -106,10 +107,14 @@ namespace pcpp
uint16_t dstPort;
/** A 4-byte hash key representing the connection */
uint32_t flowKey;
/** Start TimeStamp of the connection */
/** Start timestamp of the connection with microsecond precision */
timeval startTime;
/** End TimeStamp of the connection */
/** End timestamp of the connection with microsecond precision */
timeval endTime;
/** Start timestamp of the connection with nanosecond precision */
std::chrono::time_point<std::chrono::high_resolution_clock> startTimePrecise;
/** End timestamp of the connection with nanosecond precision */
std::chrono::time_point<std::chrono::high_resolution_clock> endTimePrecise;

/**
* A c'tor for this struct that basically zeros all members
Expand All @@ -118,22 +123,16 @@ namespace pcpp
{}

/**
* Set startTime of Connection
* @param[in] startTimeValue integer value
* Set the start time of the connection
* @param[in] startTimeValue timestamp value
*/
void setStartTime(const timeval& startTimeValue)
{
startTime = startTimeValue;
}
void setStartTime(const std::chrono::time_point<std::chrono::high_resolution_clock>& startTimeValue);

/**
* Set endTime of Connection
* @param[in] endTimeValue integer value
* Set the end time of the connection
* @param[in] endTimeValue timestamp value
*/
void setEndTime(const timeval& endTimeValue)
{
endTime = endTimeValue;
}
void setEndTime(const std::chrono::time_point<std::chrono::high_resolution_clock>& endTimeValue);
};

class TcpReassembly;
Expand All @@ -156,7 +155,7 @@ namespace pcpp
* @param[in] timestamp when this packet was received
*/
TcpStreamData(const uint8_t* tcpData, size_t tcpDataLength, size_t missingBytes, const ConnectionData& connData,
timeval timestamp)
std::chrono::time_point<std::chrono::high_resolution_clock> timestamp)
: m_Data(tcpData), m_DataLen(tcpDataLength), m_MissingBytes(missingBytes), m_Connection(connData),
m_Timestamp(timestamp)
{}
Expand Down Expand Up @@ -207,10 +206,14 @@ namespace pcpp
}

/**
* A getter for the timestamp of this packet
* @return The const timeval object with timestamp of this packet
* @return A microsecond precision of the packet timestamp
*/
timeval getTimeStamp() const;

/**
* @return A nanosecond precision of the packet timestamp
*/
timeval getTimeStamp() const
std::chrono::time_point<std::chrono::high_resolution_clock> getTimeStampPrecise() const
{
return m_Timestamp;
}
Expand All @@ -220,7 +223,7 @@ namespace pcpp
size_t m_DataLen;
size_t m_MissingBytes;
const ConnectionData& m_Connection;
timeval m_Timestamp;
std::chrono::time_point<std::chrono::high_resolution_clock> m_Timestamp;
};

/**
Expand Down Expand Up @@ -483,7 +486,7 @@ namespace pcpp
uint32_t sequence;
size_t dataLength;
uint8_t* data;
timeval timestamp;
std::chrono::time_point<std::chrono::high_resolution_clock> timestamp;

TcpFragment() : sequence(0), dataLength(0), data(nullptr)
{}
Expand Down
60 changes: 42 additions & 18 deletions Packet++/src/TcpReassembly.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,46 @@
namespace pcpp
{

static timeval timespecToTimeval(const timespec& in)
static timeval timePointToTimeval(const std::chrono::time_point<std::chrono::high_resolution_clock>& in)
{
timeval out;
TIMESPEC_TO_TIMEVAL(&out, &in);
auto duration = in.time_since_epoch();

auto seconds = std::chrono::duration_cast<std::chrono::seconds>(duration).count();
auto microseconds =
std::chrono::duration_cast<std::chrono::microseconds>(duration).count() -
std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::seconds(seconds)).count();

struct timeval out;
out.tv_sec = seconds;
out.tv_usec = microseconds;
return out;
}

static std::chrono::time_point<std::chrono::high_resolution_clock> timespecToTimePoint(const timespec& in)
{
auto duration = std::chrono::duration_cast<std::chrono::high_resolution_clock::duration>(
std::chrono::seconds(in.tv_sec) + std::chrono::nanoseconds(in.tv_nsec));

return std::chrono::time_point<std::chrono::high_resolution_clock>(duration);
}

void ConnectionData::setStartTime(const std::chrono::time_point<std::chrono::high_resolution_clock>& startTimeValue)
{
startTime = timePointToTimeval(startTimeValue);
startTimePrecise = startTimeValue;
}

void ConnectionData::setEndTime(const std::chrono::time_point<std::chrono::high_resolution_clock>& endTimeValue)
{
endTime = timePointToTimeval(endTimeValue);
endTimePrecise = endTimeValue;
}

timeval TcpStreamData::getTimeStamp() const
{
return timePointToTimeval(m_Timestamp);
}

TcpReassembly::TcpReassembly(OnTcpMessageReady onMessageReadyCallback, void* userCookie,
OnTcpConnectionStart onConnectionStartCallback,
OnTcpConnectionEnd onConnectionEndCallback, const TcpReassemblyConfiguration& config)
Expand Down Expand Up @@ -109,7 +142,7 @@ namespace pcpp
uint32_t flowKey = hash5Tuple(&tcpData);

// time stamp for this packet
timeval currTime = timespecToTimeval(tcpData.getRawPacket()->getPacketTimeStamp());
auto currTime = timespecToTimePoint(tcpData.getRawPacket()->getPacketTimeStamp());

// find the connection in the connection map
ConnectionList::iterator iter = m_ConnectionList.find(flowKey);
Expand Down Expand Up @@ -146,22 +179,13 @@ namespace pcpp

tcpReassemblyData = &iter->second;

if (currTime.tv_sec > tcpReassemblyData->connData.endTime.tv_sec)
if (currTime > tcpReassemblyData->connData.endTimePrecise)
{
tcpReassemblyData->connData.setEndTime(currTime);
m_ConnectionInfo[flowKey].setEndTime(currTime);
}
else if (currTime.tv_sec == tcpReassemblyData->connData.endTime.tv_sec)
{
if (currTime.tv_usec > tcpReassemblyData->connData.endTime.tv_usec)
{
tcpReassemblyData->connData.setEndTime(currTime);
m_ConnectionInfo[flowKey].setEndTime(currTime);
}
}
}

timeval timestampOfTheReceivedPacket = currTime;
int8_t sideIndex = -1;
bool first = false;

Expand Down Expand Up @@ -299,7 +323,7 @@ namespace pcpp
if (tcpPayloadSize != 0 && m_OnMessageReadyCallback != nullptr)
{
TcpStreamData streamData(tcpLayer->getLayerPayload(), tcpPayloadSize, 0, tcpReassemblyData->connData,
timestampOfTheReceivedPacket);
currTime);
m_OnMessageReadyCallback(sideIndex, streamData, m_UserCookie);
}
status = TcpMessageHandled;
Expand Down Expand Up @@ -337,7 +361,7 @@ namespace pcpp
if (m_OnMessageReadyCallback != nullptr)
{
TcpStreamData streamData(tcpLayer->getLayerPayload() + newLength, tcpPayloadSize - newLength, 0,
tcpReassemblyData->connData, timestampOfTheReceivedPacket);
tcpReassemblyData->connData, currTime);
m_OnMessageReadyCallback(sideIndex, streamData, m_UserCookie);
}
status = TcpMessageHandled;
Expand Down Expand Up @@ -390,7 +414,7 @@ namespace pcpp
if (m_OnMessageReadyCallback != nullptr)
{
TcpStreamData streamData(tcpLayer->getLayerPayload(), tcpPayloadSize, 0, tcpReassemblyData->connData,
timestampOfTheReceivedPacket);
currTime);
m_OnMessageReadyCallback(sideIndex, streamData, m_UserCookie);
}
status = TcpMessageHandled;
Expand Down Expand Up @@ -436,7 +460,7 @@ namespace pcpp
newTcpFrag->data = new uint8_t[tcpPayloadSize];
newTcpFrag->dataLength = tcpPayloadSize;
newTcpFrag->sequence = sequence;
newTcpFrag->timestamp = timestampOfTheReceivedPacket;
newTcpFrag->timestamp = currTime;
memcpy(newTcpFrag->data, tcpLayer->getLayerPayload(), tcpPayloadSize);
tcpReassemblyData->twoSides[sideIndex].tcpFragmentList.pushBack(newTcpFrag);

Expand Down
1 change: 1 addition & 0 deletions Tests/Pcap++Test/TestDefinition.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ PTF_TEST_CASE(TestTcpReassemblyMaxSeq);
PTF_TEST_CASE(TestTcpReassemblyDisableOOOCleanup);
PTF_TEST_CASE(TestTcpReassemblyTimeStamps);
PTF_TEST_CASE(TestTcpReassemblyFinReset);
PTF_TEST_CASE(TestTcpReassemblyHighPrecision);

// Implemented in IPFragmentationTests.cpp
PTF_TEST_CASE(TestIPFragmentationSanity);
Expand Down
Loading

0 comments on commit 9f31f71

Please sign in to comment.