Skip to content

Commit

Permalink
Add support for timestamp related options (seladb#1656)
Browse files Browse the repository at this point in the history
  • Loading branch information
vcomito-apexai committed Dec 10, 2024
1 parent 3d0717b commit 2b27626
Show file tree
Hide file tree
Showing 2 changed files with 155 additions and 1 deletion.
53 changes: 52 additions & 1 deletion Pcap++/header/PcapLiveDevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,38 @@ namespace pcpp
PCPP_OUT
};

/**
* Set which source provides timestamps associated to each captured packet
* (you can read more here: <https://www.tcpdump.org/manpages/pcap-tstamp.7.html>)
*/
enum class TimestampProvider
{
/** host-provided, unknown characteristics, default */
Host = 0,
/** host-provided, low precision, synced with the system clock */
HostLowPrec,
/** host-provided, high precision, synced with the system clock */
HostHighPrec,
/** device-provided, synced with the system clock */
Adapter,
/** device-provided, not synced with the system clock */
AdapterUnsynced,
/** host-provided, high precision, not synced with the system clock */
HostHighPrecUnsynced
};

/**
* Set the precision of timestamps associated to each captured packet
* (you can read more here: <https://www.tcpdump.org/manpages/pcap-tstamp.7.html>)
*/
enum class TimestampPrecision
{
/** use timestamps with microsecond precision, default */
Microseconds = 0,
/** use timestamps with nanosecond precision */
Nanoseconds,
};

/**
* @struct DeviceConfiguration
* A struct that contains user configurable parameters for opening a device. All parameters have default values
Expand Down Expand Up @@ -236,6 +268,18 @@ namespace pcpp
/// In Unix-like system, use poll() for blocking mode.
bool usePoll;

/**
* Set which timestamp provider is used.
* Depending on the capture device and the software on the host, different types of time stamp can be used
*/
TimestampProvider timestampProvider;

/**
* Set which timestamp precision is used.
* Depending on the capture device and the software on the host, different precision can be used
*/
TimestampPrecision timestampPrecision;

/**
* A c'tor for this struct
* @param[in] mode The mode to open the device: promiscuous or non-promiscuous. Default value is promiscuous
Expand All @@ -252,10 +296,15 @@ namespace pcpp
* @param[in] nflogGroup NFLOG group for NFLOG devices. Default value is 0.
* @param[in] usePoll use `poll()` when capturing packets in blocking more (`startCaptureBlockingMode()`) on
* Unix-like system. Default value is false.
* @param[in] timestampProvider the source that will provide the timestamp associated to each captured
* packet.
* @param[in] timestampPrecision the precision of the timestamp associated to each captured packet.
*/
explicit DeviceConfiguration(DeviceMode mode = Promiscuous, int packetBufferTimeoutMs = 0,
int packetBufferSize = 0, PcapDirection direction = PCPP_INOUT,
int snapshotLength = 0, unsigned int nflogGroup = 0, bool usePoll = false)
int snapshotLength = 0, unsigned int nflogGroup = 0, bool usePoll = false,
TimestampProvider timestampProvider = TimestampProvider::Host,
TimestampPrecision timestampPrecision = TimestampPrecision::Microseconds)
{
this->mode = mode;
this->packetBufferTimeoutMs = packetBufferTimeoutMs;
Expand All @@ -264,6 +313,8 @@ namespace pcpp
this->snapshotLength = snapshotLength;
this->nflogGroup = nflogGroup;
this->usePoll = usePoll;
this->timestampProvider = timestampProvider;
this->timestampPrecision = timestampPrecision;
}
};

Expand Down
103 changes: 103 additions & 0 deletions Pcap++/src/PcapLiveDevice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@
static const char* NFLOG_IFACE = "nflog";
static const int DEFAULT_SNAPLEN = 9000;

#ifndef PCAP_TSTAMP_HOST_HIPREC_UNSYNCED
// PCAP_TSTAMP_HOST_HIPREC_UNSYNCED defined only in libpcap > 1.10.0
# define PCAP_TSTAMP_HOST_HIPREC_UNSYNCED 5
#endif

namespace pcpp
{

Expand All @@ -84,6 +89,72 @@ namespace pcpp
}
#endif

static int timestampProviderMap(const PcapLiveDevice::TimestampProvider timestampProvider)
{
switch (timestampProvider)
{
case PcapLiveDevice::TimestampProvider::Host:
return PCAP_TSTAMP_HOST;
case PcapLiveDevice::TimestampProvider::HostLowPrec:
return PCAP_TSTAMP_HOST_LOWPREC;
case PcapLiveDevice::TimestampProvider::HostHighPrec:
return PCAP_TSTAMP_HOST_HIPREC;
case PcapLiveDevice::TimestampProvider::Adapter:
return PCAP_TSTAMP_ADAPTER;
case PcapLiveDevice::TimestampProvider::AdapterUnsynced:
return PCAP_TSTAMP_ADAPTER_UNSYNCED;
case PcapLiveDevice::TimestampProvider::HostHighPrecUnsynced:
return PCAP_TSTAMP_HOST_HIPREC_UNSYNCED;
}
return PCAP_TSTAMP_HOST;
}

static int timestampPrecisionMap(const PcapLiveDevice::TimestampPrecision timestampPrecision)
{
switch (timestampPrecision)
{
case PcapLiveDevice::TimestampPrecision::Microseconds:
return PCAP_TSTAMP_PRECISION_MICRO;
case PcapLiveDevice::TimestampPrecision::Nanoseconds:
return PCAP_TSTAMP_PRECISION_NANO;
}
return PCAP_TSTAMP_PRECISION_MICRO;
}

static bool is_tstamp_type_supported(pcap_t* handle, const PcapLiveDevice::TimestampProvider timestampProvider)
{
int tstamp_type = timestampProviderMap(timestampProvider);
int* supported_tstamp_types = nullptr;
const int num_supported_tstamp_types = pcap_list_tstamp_types(handle, &supported_tstamp_types);

bool is_supported = false;
if (num_supported_tstamp_types < 0)
{
std::cerr << "Error retrieving timestamp types: " << pcap_geterr(handle) << " - default Host will be used"
<< std::endl;
is_supported = false;
}
else if (num_supported_tstamp_types == 1)
{
// If 1 is returned, then the only available typestamp is TimestampProvider::Host;
return timestampProvider == PcapLiveDevice::TimestampProvider::Host;
}
else
{
for (int i = 0; i < num_supported_tstamp_types; ++i)
{
if (supported_tstamp_types[i] == tstamp_type)
{
is_supported = true;
break;
}
}
}

pcap_free_tstamp_types(supported_tstamp_types);
return is_supported;
}

PcapLiveDevice::DeviceInterfaceDetails::DeviceInterfaceDetails(pcap_if_t* pInterface)
: name(pInterface->name), isLoopback(pInterface->flags & PCAP_IF_LOOPBACK)
{
Expand Down Expand Up @@ -308,6 +379,38 @@ namespace pcpp
}
#endif

if (config.timestampProvider != PcapLiveDevice::TimestampProvider::Host)
{
if (is_tstamp_type_supported(pcap, config.timestampProvider))
{
ret = pcap_set_tstamp_type(pcap, timestampProviderMap(config.timestampProvider));
if (ret == 0)
{
PCPP_LOG_DEBUG("Timestamp provider was set");
}
else
{
PCPP_LOG_ERROR("Failed to set timestamping provider: '" << ret << "', error message: '"
<< pcap_geterr(pcap) << "'");
}
}
else
{
PCPP_LOG_ERROR("Selected timestamping provider is not supported");
}
}

ret = pcap_set_tstamp_precision(pcap, timestampPrecisionMap(config.timestampPrecision));
if (ret == 0)
{
PCPP_LOG_DEBUG("Timestamp precision was set");
}
else
{
PCPP_LOG_ERROR("Failed to set timestamping precision: '" << ret << "', error message: '"
<< pcap_geterr(pcap) << "'");
}

ret = pcap_activate(pcap);
if (ret != 0)
{
Expand Down

0 comments on commit 2b27626

Please sign in to comment.