From 492fd611f9dc8c022e0420e4046b31c93d9df677 Mon Sep 17 00:00:00 2001 From: Matias Fontanini Date: Fri, 23 Nov 2012 18:10:51 -0300 Subject: [PATCH] Added Packet and some wrapper packet classes. Modified the return value of BaseSniffer::next_packet. --- depends.d | 109 +++++++++++++++++++------ include/packet.h | 190 ++++++++++++++++++++++++++++++++++++++++++++ include/sniffer.h | 84 ++++++++++++-------- include/timestamp.h | 70 ++++++++++++++++ src/sniffer.cpp | 8 +- 5 files changed, 400 insertions(+), 61 deletions(-) create mode 100644 include/packet.h create mode 100644 include/timestamp.h diff --git a/depends.d b/depends.d index 58302e1..a32f070 100644 --- a/depends.d +++ b/depends.d @@ -44,7 +44,8 @@ include/hw_address.h: src/crypto.o: src/crypto.cpp include/crypto.h include/dot11.h \ include/pdu.h include/endianness.h include/hw_address.h \ include/small_uint.h include/pdu_option.h include/network_interface.h \ - include/ip_address.h include/utils.h include/snap.h include/rawpdu.h + include/ip_address.h include/utils.h include/ipv6_address.h \ + include/snap.h include/rawpdu.h include/crypto.h: @@ -66,6 +67,8 @@ include/ip_address.h: include/utils.h: +include/ipv6_address.h: + include/snap.h: include/rawpdu.h: @@ -169,8 +172,8 @@ include/rsn_information.h: src/ethernetII.o: src/ethernetII.cpp include/ethernetII.h include/pdu.h \ include/endianness.h include/hw_address.h include/network_interface.h \ include/ip_address.h include/packet_sender.h include/rawpdu.h \ - include/ip.h include/small_uint.h include/pdu_option.h include/arp.h \ - include/constants.h + include/ip.h include/small_uint.h include/pdu_option.h include/ipv6.h \ + include/ipv6_address.h include/arp.h include/constants.h include/ethernetII.h: @@ -194,12 +197,16 @@ include/small_uint.h: include/pdu_option.h: +include/ipv6.h: + +include/ipv6_address.h: + include/arp.h: include/constants.h: src/icmp.o: src/icmp.cpp include/icmp.h include/pdu.h \ include/endianness.h include/rawpdu.h include/utils.h \ - include/ip_address.h include/hw_address.h + include/ip_address.h include/ipv6_address.h include/hw_address.h include/icmp.h: @@ -213,6 +220,8 @@ include/utils.h: include/ip_address.h: +include/ipv6_address.h: + include/hw_address.h: src/ieee802_3.o: src/ieee802_3.cpp include/ieee802_3.h include/pdu.h \ include/endianness.h include/hw_address.h include/network_interface.h \ @@ -241,9 +250,9 @@ include/ip_address.h: include/endianness.h: src/ip.o: src/ip.cpp include/ip.h include/pdu.h include/small_uint.h \ include/endianness.h include/ip_address.h include/pdu_option.h \ - include/tcp.h include/udp.h include/icmp.h include/rawpdu.h \ - include/utils.h include/hw_address.h include/packet_sender.h \ - include/constants.h + include/ipv6.h include/ipv6_address.h include/tcp.h include/udp.h \ + include/icmp.h include/rawpdu.h include/utils.h include/hw_address.h \ + include/packet_sender.h include/constants.h include/ip.h: @@ -257,6 +266,10 @@ include/ip_address.h: include/pdu_option.h: +include/ipv6.h: + +include/ipv6_address.h: + include/tcp.h: include/udp.h: @@ -276,7 +289,10 @@ src/ipv6_address.o: src/ipv6_address.cpp include/ipv6_address.h include/ipv6_address.h: src/ipv6.o: src/ipv6.cpp include/ipv6.h include/pdu.h \ - include/endianness.h include/small_uint.h include/ipv6_address.h + include/endianness.h include/small_uint.h include/pdu_option.h \ + include/ipv6_address.h include/constants.h include/packet_sender.h \ + include/ip.h include/ip_address.h include/tcp.h include/udp.h \ + include/icmp.h include/rawpdu.h include/ipv6.h: @@ -286,7 +302,25 @@ include/endianness.h: include/small_uint.h: +include/pdu_option.h: + include/ipv6_address.h: + +include/constants.h: + +include/packet_sender.h: + +include/ip.h: + +include/ip_address.h: + +include/tcp.h: + +include/udp.h: + +include/icmp.h: + +include/rawpdu.h: src/llc.o: src/llc.cpp include/pdu.h include/llc.h include/pdu.h \ include/endianness.h include/rawpdu.h @@ -325,7 +359,7 @@ include/llc.h: include/rawpdu.h: src/network_interface.o: src/network_interface.cpp \ include/network_interface.h include/hw_address.h include/ip_address.h \ - include/utils.h include/endianness.h + include/utils.h include/ipv6_address.h include/endianness.h include/network_interface.h: @@ -335,6 +369,8 @@ include/ip_address.h: include/utils.h: +include/ipv6_address.h: + include/endianness.h: src/packet_sender.o: src/packet_sender.cpp include/pdu.h \ include/packet_sender.h @@ -343,7 +379,8 @@ include/pdu.h: include/packet_sender.h: src/packet_writer.o: src/packet_writer.cpp include/packet_writer.h \ - include/utils.h include/ip_address.h include/hw_address.h include/pdu.h + include/utils.h include/ip_address.h include/ipv6_address.h \ + include/hw_address.h include/pdu.h include/packet_writer.h: @@ -351,6 +388,8 @@ include/utils.h: include/ip_address.h: +include/ipv6_address.h: + include/hw_address.h: include/pdu.h: @@ -367,7 +406,8 @@ include/packet_sender.h: src/radiotap.o: src/radiotap.cpp include/radiotap.h include/pdu.h \ include/endianness.h include/network_interface.h include/hw_address.h \ include/ip_address.h include/dot11.h include/small_uint.h \ - include/pdu_option.h include/utils.h include/packet_sender.h + include/pdu_option.h include/utils.h include/ipv6_address.h \ + include/packet_sender.h include/radiotap.h: @@ -389,6 +429,8 @@ include/pdu_option.h: include/utils.h: +include/ipv6_address.h: + include/packet_sender.h: src/rawpdu.o: src/rawpdu.cpp include/rawpdu.h include/pdu.h @@ -430,8 +472,8 @@ include/eapol.h: src/sniffer.o: src/sniffer.cpp include/sniffer.h include/pdu.h \ include/ethernetII.h include/endianness.h include/hw_address.h \ include/network_interface.h include/ip_address.h include/radiotap.h \ - include/loopback.h include/dot11.h include/small_uint.h \ - include/pdu_option.h + include/packet.h include/timestamp.h include/loopback.h include/dot11.h \ + include/small_uint.h include/pdu_option.h include/sniffer.h: @@ -449,6 +491,10 @@ include/ip_address.h: include/radiotap.h: +include/packet.h: + +include/timestamp.h: + include/loopback.h: include/dot11.h: @@ -458,8 +504,9 @@ include/small_uint.h: include/pdu_option.h: src/tcp.o: src/tcp.cpp include/tcp.h include/pdu.h include/endianness.h \ include/small_uint.h include/pdu_option.h include/ip.h \ - include/ip_address.h include/constants.h include/rawpdu.h \ - include/utils.h include/hw_address.h + include/ip_address.h include/ipv6.h include/ipv6_address.h \ + include/constants.h include/rawpdu.h include/utils.h \ + include/hw_address.h include/tcp.h: @@ -475,6 +522,10 @@ include/ip.h: include/ip_address.h: +include/ipv6.h: + +include/ipv6_address.h: + include/constants.h: include/rawpdu.h: @@ -485,9 +536,10 @@ include/hw_address.h: src/tcp_stream.o: src/tcp_stream.cpp include/rawpdu.h include/pdu.h \ include/tcp_stream.h include/sniffer.h include/ethernetII.h \ include/endianness.h include/hw_address.h include/network_interface.h \ - include/ip_address.h include/radiotap.h include/loopback.h \ - include/dot11.h include/small_uint.h include/pdu_option.h include/tcp.h \ - include/utils.h include/ip.h + include/ip_address.h include/radiotap.h include/packet.h \ + include/timestamp.h include/loopback.h include/dot11.h \ + include/small_uint.h include/pdu_option.h include/tcp.h include/utils.h \ + include/ipv6_address.h include/ip.h include/rawpdu.h: @@ -509,6 +561,10 @@ include/ip_address.h: include/radiotap.h: +include/packet.h: + +include/timestamp.h: + include/loopback.h: include/dot11.h: @@ -521,11 +577,13 @@ include/tcp.h: include/utils.h: +include/ipv6_address.h: + include/ip.h: src/udp.o: src/udp.cpp include/udp.h include/pdu.h include/endianness.h \ include/constants.h include/utils.h include/ip_address.h \ - include/hw_address.h include/ip.h include/small_uint.h \ - include/pdu_option.h include/rawpdu.h + include/ipv6_address.h include/hw_address.h include/ip.h \ + include/small_uint.h include/pdu_option.h include/rawpdu.h include/udp.h: @@ -539,6 +597,8 @@ include/utils.h: include/ip_address.h: +include/ipv6_address.h: + include/hw_address.h: include/ip.h: @@ -549,14 +609,17 @@ include/pdu_option.h: include/rawpdu.h: src/utils.o: src/utils.cpp include/utils.h include/ip_address.h \ - include/hw_address.h include/pdu.h include/arp.h include/pdu.h \ - include/endianness.h include/ethernetII.h include/network_interface.h \ - include/endianness.h include/network_interface.h include/packet_sender.h + include/ipv6_address.h include/hw_address.h include/pdu.h include/arp.h \ + include/pdu.h include/endianness.h include/ethernetII.h \ + include/network_interface.h include/endianness.h \ + include/network_interface.h include/packet_sender.h include/utils.h: include/ip_address.h: +include/ipv6_address.h: + include/hw_address.h: include/pdu.h: diff --git a/include/packet.h b/include/packet.h new file mode 100644 index 0000000..d7d7f7a --- /dev/null +++ b/include/packet.h @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2012, Nasel + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef TINS_PACKET_H +#define TINS_PACKET_H + +#include "pdu.h" +#include "timestamp.h" + +namespace Tins { +template +class PacketWrapper; + +typedef PacketWrapper RefPacket; +typedef PacketWrapper PtrPacket; + +/** + * \brief Represents a sniffed packet. + * + * RefPackets contain a PDU reference and a timestamp. The difference between + * this class and the Packet class is that this one contains a reference + * to a PDU, and not a pointer to one. + * + * This class is only used in some BaseSniffer methods as a thin wrapper + * to a PDU pointer/reference. Only BaseSniffer and derived objects can + * create instances of it. + */ +template +class PacketWrapper { +public: + typedef PDUType pdu_type; + typedef TimestampType timestamp_type; + + /** + * \brief User defined conversion to wrapped_type. + * + * This conversion is defined so that BaseSniffer::sniff_loop callback + * or code that calls BaseSniffer::next_packet can still receive a + * PDU pointer/reference without modifying the code at all. + */ + operator pdu_type() { + return pdu_; + } + + /** + * \brief Returns the wrapped_type. + */ + pdu_type pdu() { + return pdu_; + } + + /** + * \brief Returns the PDU const reference. + */ + const pdu_type pdu() const { + return pdu_; + } + + /** + * \brief Returns the packet timestamp. + * + * This is the timestamp in which the packet was taken out of the + * network interface/pcap file. + */ + const Timestamp ×tamp() const { + return ts_; + } +private: + friend class BaseSniffer; + + PacketWrapper(pdu_type pdu, const Timestamp &ts) + : pdu_(pdu), ts_(ts) {} + + PacketWrapper(const PacketWrapper&); + PacketWrapper& operator=(const PacketWrapper&); + void* operator new (size_t size); + void operator delete (void *p); + + pdu_type pdu_; + timestamp_type ts_; +}; + +/** + * \brief Represents a sniffed packet. + * + * A Packet contains a PDU pointer and a Timestamp object. Packets can't + * be copied and will delete the stored PDU* unless you call + * release_pdu at some point before destruction. + */ +class Packet { +public: + /** + * \brief Constructs a Packet from a PtrPacket object. + */ + Packet(const PtrPacket &pck) + : pdu_(pck.pdu()), ts(pck.timestamp()) { } + + /** + * \brief Constructs a Packet from a PtrPacket object. + */ + Packet& operator=(const PtrPacket &pck) { + pdu_ = pck.pdu(); + ts = pck.timestamp(); + return *this; + } + + /** + * \brief Packet destructor. + * + * This calls operator delete on the stored PDU*. + */ + ~Packet() { + delete pdu_; + } + + /** + * Returns this Packet's timestamp. + */ + const Timestamp ×tamp() const { + return ts; + } + + /** + * \brief Returns the stored PDU*. + * + * Caller must not delete the pointer. \sa Packet::release_pdu + */ + PDU *pdu() { + return pdu_; + } + + /** + * \brief Returns the stored PDU*. + * + * Caller must not delete the pointer. \sa Packet::release_pdu + */ + const PDU *pdu() const { + return pdu_; + } + + /** + * \brief Releases ownership of the stored PDU*. + * + * This method returns the stored PDU* and sets the stored PDU* to + * a null pointer, so the destructor will be well behaved. Use this + * method if you want to keep the internal PDU* somewhere. Otherwise, + * when Packet's destructor is called, the stored pointer will be + * deleted. + */ + PDU *release_pdu() { + PDU *some_pdu = pdu_; + pdu_ = 0; + return some_pdu; + } +private: + Packet(const Packet &); + Packet& operator=(const Packet &); + + PDU *pdu_; + Timestamp ts; +}; +} + +#endif // TINS_PACKET_H diff --git a/include/sniffer.h b/include/sniffer.h index 3a3708d..1b5877b 100644 --- a/include/sniffer.h +++ b/include/sniffer.h @@ -39,6 +39,7 @@ #include "pdu.h" #include "ethernetII.h" #include "radiotap.h" +#include "packet.h" #include "loopback.h" #include "dot11.h" @@ -67,26 +68,49 @@ namespace Tins { * This method returns the first sniffed packet that matches the * sniffer's filter, or the first sniffed packet if no filter has * been set. - * \return The captured packet, matching the given filter, 0 if an - * error occured(probably compiling the filter). Caller takes - * ownership of the packet. + * + * The return type is a thin wrapper over a PDU* and a Timestamp + * object. This wrapper can be both implicitly converted to a + * PDU* and a Packet object. So doing this: + * + * Sniffer s(...); + * // smart pointer? :D + * PDU *pdu = s.next_packet(); + * // Packet takes care of the PDU*. \sa Packet::release_pdu + * Packet packet = s.next_packet(); + * + * Is fine, but this: + * + * PtrPacket p = s.next_packet(); + * + * Is not, since PtrPacket can't be copy constructed. + * + * \return The captured packet, matching the given filter. + * If an error occured(probably compiling the filter), PtrPacket::pdu + * will return 0. Caller takes ownership of the PDU * stored in + * the PtrPacket. */ - PDU *next_packet(); + PtrPacket next_packet(); /** * \brief Starts a sniffing loop, using a callback object for every * sniffed packet. * - * The callback object must implement an operator with the - * following(or compatible) signature: + * The callback object must implement an operator with some of + * the following(or compatible) signatures: * * bool operator()(PDU&); + * bool operator()(RefPacket&); * * This operator will be called using the sniffed packets - * as arguments. You can modify the PDU argument as you wish. + * as arguments. You can modify the parameter argument as you wish. * Calling PDU methods like PDU::release_inner_pdu is perfectly * valid. * + * The callback taking a RefPacket will contain a timestamp + * indicating the moment in which the packet was taken out of + * the wire/pcap file. \sa RefPacket + * * Note that the Functor object will be copied using its copy * constructor, so that object should be some kind of proxy to * another object which will process the packets(e.g. std::bind). @@ -108,17 +132,6 @@ namespace Tins { * \brief Stops sniffing loops. */ void stop_sniff(); - - /** - * \brief Retrieves the timestamp taken from the last packet - * captured in the sniffing session. - * - * This timestamp will be modified each time a packet is captured - * using both BaseSniffer::sniff_loop and BaseSniffer::next_packet. - */ - const struct timeval ×tamp() const { - return timestamp_; - } protected: /** * Default constructor. @@ -141,19 +154,18 @@ namespace Tins { pcap_t *handle; Functor c_handler; int iface_type; - timeval ×tamp; LoopData(pcap_t *_handle, const Functor _handler, - int if_type, timeval &ts) - : handle(_handle), c_handler(_handler), iface_type(if_type), - timestamp(ts) { } + int if_type) + : handle(_handle), c_handler(_handler), iface_type(if_type) + { } }; BaseSniffer(const BaseSniffer&); BaseSniffer &operator=(const BaseSniffer&); template - static bool call_functor(LoopData *data, const u_char *packet, size_t len); + static bool call_functor(LoopData *data, const u_char *packet, const struct pcap_pkthdr *header); bool compile_set_filter(const std::string &filter, bpf_program &prog); @@ -164,7 +176,6 @@ namespace Tins { bpf_u_int32 mask; bpf_program actual_filter; int iface_type; - timeval timestamp_; }; /** @@ -209,14 +220,18 @@ namespace Tins { template void Tins::BaseSniffer::sniff_loop(Functor function, uint32_t max_packets) { - LoopData data(handle, function, iface_type, timestamp_); + LoopData data(handle, function, iface_type); pcap_loop(handle, max_packets, &BaseSniffer::callback_handler, (u_char*)&data); } template - bool Tins::BaseSniffer::call_functor(LoopData *data, const u_char *packet, size_t len) { - ConcretePDU some_pdu((const uint8_t*)packet, len); - return data->c_handler(some_pdu); + bool Tins::BaseSniffer::call_functor(LoopData *data, const u_char *packet, + const struct pcap_pkthdr *header) + { + ConcretePDU some_pdu((const uint8_t*)packet, header->caplen); + Timestamp ts(header->ts); + RefPacket pck(some_pdu, ts); + return data->c_handler(pck); } template @@ -225,18 +240,19 @@ namespace Tins { std::auto_ptr pdu; LoopData *data = reinterpret_cast*>(args); bool ret_val(false); - data->timestamp = header->ts; if(data->iface_type == DLT_EN10MB) - ret_val = call_functor(data, packet, header->caplen); + ret_val = call_functor(data, packet, header); else if(data->iface_type == DLT_IEEE802_11_RADIO) - ret_val = call_functor(data, packet, header->caplen); + ret_val = call_functor(data, packet, header); else if(data->iface_type == DLT_IEEE802_11) { std::auto_ptr pdu(Tins::Dot11::from_bytes((const uint8_t*)packet, header->caplen)); - if(pdu.get()) - ret_val = data->c_handler(*pdu); + if(pdu.get()) { + RefPacket pck(*pdu, header->ts); + ret_val = data->c_handler(pck); + } } else if(data->iface_type == DLT_NULL) - ret_val = call_functor(data, packet, header->caplen); + ret_val = call_functor(data, packet, header); if(!ret_val) pcap_breakloop(data->handle); diff --git a/include/timestamp.h b/include/timestamp.h new file mode 100644 index 0000000..7ee91ab --- /dev/null +++ b/include/timestamp.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2012, Nasel + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef TINS_TIMESTAMP_H +#define TINS_TIMESTAMP_H + +#include + +namespace Tins { +/** + * \brief Represents a packet timestamp. + */ +class Timestamp { +public: + /** + * Default constructs the timestamp. + */ + Timestamp() : tv() {} + + /** + * Constructs a timestamp from a timeval object. + * \param time_val The timeval object. + */ + Timestamp(const timeval &time_val) : tv(time_val) {} + + /** + * Returns the amount of seconds in this timestamp. + */ + time_t seconds() const { + return tv.tv_sec; + } + + /** + * Returns the amount of microseconds in this timestamp. + */ + suseconds_t microseconds() const { + return tv.tv_usec; + } +private: + timeval tv; +}; +} + +#endif // TINS_TIMESTAMP_H diff --git a/src/sniffer.cpp b/src/sniffer.cpp index ccdd713..9eaf0aa 100644 --- a/src/sniffer.cpp +++ b/src/sniffer.cpp @@ -34,7 +34,7 @@ using std::string; using std::runtime_error; namespace Tins { -BaseSniffer::BaseSniffer() : handle(0), mask(0), timestamp_() +BaseSniffer::BaseSniffer() : handle(0), mask(0) { actual_filter.bf_insns = 0; } @@ -62,11 +62,11 @@ bool BaseSniffer::compile_set_filter(const string &filter, bpf_program &prog) { return (pcap_compile(handle, &prog, filter.c_str(), 0, mask) != -1 && pcap_setfilter(handle, &prog) != -1); } -PDU *BaseSniffer::next_packet() { +PtrPacket BaseSniffer::next_packet() { pcap_pkthdr header; PDU *ret = 0; const u_char *content = pcap_next(handle, &header); - timestamp_ = header.ts; +// timestamp_ = header.ts; if(content) { if(iface_type == DLT_EN10MB) ret = new EthernetII((const uint8_t*)content, header.caplen); @@ -77,7 +77,7 @@ PDU *BaseSniffer::next_packet() { else if(iface_type == DLT_LOOP) ret = new Tins::Loopback((const uint8_t*)content, header.caplen); } - return ret; + return PtrPacket(ret, header.ts); } void BaseSniffer::stop_sniff() {