From a06273fe89d30c777bc72cdafaafcfd22a9b0d0b Mon Sep 17 00:00:00 2001 From: "vincenzo.comito" Date: Tue, 10 Dec 2024 09:42:59 +0100 Subject: [PATCH] Add support for timestamp related options (#1656) --- Pcap++/header/PcapLiveDevice.h | 50 +++++++++++++++++++++++++++++++- Pcap++/src/PcapLiveDevice.cpp | 53 +++++++++++++++++++++++++++++++++- 2 files changed, 101 insertions(+), 2 deletions(-) diff --git a/Pcap++/header/PcapLiveDevice.h b/Pcap++/header/PcapLiveDevice.h index e37e27d7cd..b7b90bcfe7 100644 --- a/Pcap++/header/PcapLiveDevice.h +++ b/Pcap++/header/PcapLiveDevice.h @@ -186,6 +186,36 @@ namespace pcpp PCPP_OUT }; + /** + * Set which source provides timestamps associated to each captured packet + * (you can read more here: ) + */ + enum TimestampProvider { + /** host-provided, unknown characteristics, default */ + TimestampProviderHost = 0, + /** host-provided, low precision, synced with the system clock */ + TimestampProviderHostLowPrec, + /** host-provided, high precision, synced with the system clock */ + TimestampProviderHostHighPrec, + /** device-provided, synced with the system clock */ + TimestampProviderAdapter, + /** device-provided, not synced with the system clock */ + TimestampProviderAdapterUnsynced, + /** host-provided, high precision, not synced with the system clock */ + TimestampProviderHostHighPrecUnsynced + }; + + /** + * Set the precision of timestamps associated to each captured packet + * (you can read more here: ) + */ + enum TimestampPrecision { + /** use timestamps with microsecond precision, default */ + TimestampPrecisionMicroseconds = 0, + /** use timestamps with nanosecond precision */ + TimestampPrecisionNanoseconds, + }; + /** * @struct DeviceConfiguration * A struct that contains user configurable parameters for opening a device. All parameters have default values @@ -236,6 +266,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 @@ -252,10 +294,14 @@ 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 = TimestampProviderHost, + TimestampPrecision timestampPrecision = TimestampPrecisionMicroseconds) { this->mode = mode; this->packetBufferTimeoutMs = packetBufferTimeoutMs; @@ -264,6 +310,8 @@ namespace pcpp this->snapshotLength = snapshotLength; this->nflogGroup = nflogGroup; this->usePoll = usePoll; + this->timestampProvider = timestampProvider; + this->timestampPrecision = timestampPrecision; } }; diff --git a/Pcap++/src/PcapLiveDevice.cpp b/Pcap++/src/PcapLiveDevice.cpp index 6eef2111d2..323d85cb62 100644 --- a/Pcap++/src/PcapLiveDevice.cpp +++ b/Pcap++/src/PcapLiveDevice.cpp @@ -84,6 +84,37 @@ namespace pcpp } #endif + static int timestampProviderMap(const PcapLiveDevice::TimestampProvider timestampProvider) { + switch (timestampProvider) + { + case PcapLiveDevice::TimestampProviderHost: + return PCAP_TSTAMP_HOST; + case PcapLiveDevice::TimestampProviderHostLowPrec: + return PCAP_TSTAMP_HOST_LOWPREC; + case PcapLiveDevice::TimestampProviderHostHighPrec: + return PCAP_TSTAMP_HOST_HIPREC; + case PcapLiveDevice::TimestampProviderAdapter: + return PCAP_TSTAMP_ADAPTER; + case PcapLiveDevice::TimestampProviderAdapterUnsynced: + return PCAP_TSTAMP_ADAPTER_UNSYNCED; + case PcapLiveDevice::TimestampProviderHostHighPrecUnsynced: + return PCAP_TSTAMP_HOST_HIPREC_UNSYNCED; + } + return PCAP_TSTAMP_HOST; + } + + static int timestampPrecisionMap(const PcapLiveDevice::TimestampPrecision timestampPrecision) { + switch (timestampPrecision) + { + case PcapLiveDevice::TimestampPrecisionMicroseconds: + return PCAP_TSTAMP_PRECISION_MICRO; + case PcapLiveDevice::TimestampPrecisionNanoseconds: + return PCAP_TSTAMP_PRECISION_NANO; + } + return PCAP_TSTAMP_PRECISION_MICRO; + } + + PcapLiveDevice::DeviceInterfaceDetails::DeviceInterfaceDetails(pcap_if_t* pInterface) : name(pInterface->name), isLoopback(pInterface->flags & PCAP_IF_LOOPBACK) { @@ -184,7 +215,7 @@ namespace pcpp return; } - uint8_t* packetData = new uint8_t[pkthdr->caplen]; +* packetData = new uint8_t[pkthdr->caplen]; memcpy(packetData, packet, pkthdr->caplen); RawPacket* rawPacketPtr = new RawPacket(packetData, pkthdr->caplen, pkthdr->ts, true, pThis->getLinkType()); pThis->m_CapturedPackets->pushBack(rawPacketPtr); @@ -308,6 +339,26 @@ namespace pcpp } #endif + if (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) << "'"); + } + } + + if (config.timestampPrecision) + { + 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) {