diff --git a/include/tins/internals.h b/include/tins/internals.h index 59a0704..8806c9d 100644 --- a/include/tins/internals.h +++ b/include/tins/internals.h @@ -5,14 +5,14 @@ * 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 @@ -26,10 +26,14 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ - + #ifndef TINS_INTERNALS_H #define TINS_INTERNALS_H +#if TINS_IS_CXX11 +#include +#endif + #include #include #include @@ -50,16 +54,16 @@ class byte_array { public: typedef uint8_t* iterator; typedef const uint8_t* const_iterator; - + byte_array() { std::fill(begin(), end(), 0); } - + template byte_array(InputIterator start, InputIterator last) { std::copy(start, last, data); } - + template byte_array(InputIterator start) { std::copy(start, n, data); @@ -72,23 +76,23 @@ public: uint8_t operator[](size_t i) const{ return data[i]; } - + iterator begin() { return data; } - + iterator end() { return data + n; } - + const_iterator begin() const { return data; } - + const_iterator end() const { return data + n; } - + size_t size() const { return n; } @@ -106,14 +110,14 @@ struct enable_if { template struct enable_if { - + }; -PDU *pdu_from_flag(Constants::Ethernet::e flag, const uint8_t *buffer, +PDU *pdu_from_flag(Constants::Ethernet::e flag, const uint8_t *buffer, uint32_t size, bool rawpdu_on_no_match = true); -PDU *pdu_from_flag(Constants::IP::e flag, const uint8_t *buffer, +PDU *pdu_from_flag(Constants::IP::e flag, const uint8_t *buffer, uint32_t size, bool rawpdu_on_no_match = true); -PDU *pdu_from_dlt_flag(int flag, const uint8_t *buffer, +PDU *pdu_from_dlt_flag(int flag, const uint8_t *buffer, uint32_t size, bool rawpdu_on_no_match = true); PDU *pdu_from_flag(PDU::PDUType type, const uint8_t *buffer, uint32_t size); @@ -200,6 +204,34 @@ template<> struct is_unsigned_integral { static const bool value = true; }; + +#if TINS_IS_CXX11 + +// Part of C++14 standard library +template +using enable_if_t = typename std::enable_if::type; + +// Template metaprogramming trait to determine if a functor can accept another parameter as an argument +template +struct accepts_type : std::false_type { }; + +template +struct accepts_type()(std::declval

()) ), bool>::value +>> : std::true_type { }; + +// use enable_if to invoke the Packet& version of the sniff_loop handler if possible - otherwise fail to old behavior +template +bool invoke_loop_cb(Functor& f, Packet& p, typename std::enable_if::value, bool>::type* = 0) { + return f(p); +} + +template +bool invoke_loop_cb(Functor& f, Packet& p, typename std::enable_if::value, bool>::type* = 0) { + return f(*p.pdu()); +} +#endif + } // namespace Internals } // namespace Tins /** diff --git a/include/tins/sniffer.h b/include/tins/sniffer.h index e7abe03..26fd21c 100644 --- a/include/tins/sniffer.h +++ b/include/tins/sniffer.h @@ -5,14 +5,14 @@ * 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 @@ -43,10 +43,6 @@ #include "exceptions.h" #include "internals.h" -#if TINS_IS_CXX11 -#include -#endif - namespace Tins { class SnifferIterator; class SnifferConfiguration; @@ -54,11 +50,11 @@ namespace Tins { /** * \class BaseSniffer * \brief Base class for sniffers. - * + * * This class implements the basic sniffing operations. Subclasses * should only initialize this object using a pcap_t pointer, which * will be used to extract packets. - * + * * Initialization must be done using the BaseSniffer::init method. */ class BaseSniffer { @@ -73,17 +69,17 @@ namespace Tins { * \brief Move constructor. * This constructor is available only in C++11. */ - BaseSniffer(BaseSniffer &&rhs) TINS_NOEXCEPT + BaseSniffer(BaseSniffer &&rhs) TINS_NOEXCEPT : handle(nullptr), mask() { *this = std::move(rhs); } - + /** * \brief Move assignment operator. * This operator is available only in C++11. */ - BaseSniffer& operator=(BaseSniffer &&rhs) TINS_NOEXCEPT + BaseSniffer& operator=(BaseSniffer &&rhs) TINS_NOEXCEPT { using std::swap; swap(handle, rhs.handle); @@ -91,99 +87,99 @@ namespace Tins { return *this; } #endif - + /** * \brief Sniffer destructor. * This frees all memory used by the pcap handle. */ virtual ~BaseSniffer(); - + /** * \brief Compiles a filter and uses it to capture one packet. - * - * This method returns the first valid sniffed packet that matches the + * + * This method returns the first valid sniffed packet that matches the * sniffer's filter, or the first sniffed packet if no filter has * been set. - * + * * The return type is a thin wrapper over a PDU* and a Timestamp - * object. This wrapper can be both implicitly converted to a + * object. This wrapper can be both implicitly converted to a * PDU* and a Packet object. So doing this: - * + * * \code * Sniffer s(...); * std::unique_ptr pdu(s.next_packet()); - * // Packet takes care of the PDU*. + * // Packet takes care of the PDU*. * Packet packet(s.next_packet()); * \endcode - * + * * Is fine, but this: - * + * * \code * // bad!! * PtrPacket p = s.next_packet(); * \endcode - * - * Is not, since PtrPacket can't be copy constructed. - * + * + * Is not, since PtrPacket can't be copy constructed. + * * \sa Packet::release_pdu - * - * \return A captured packet. If an error occured, PtrPacket::pdu - * will return 0. Caller takes ownership of the PDU pointer stored in + * + * \return A captured packet. If an error occured, PtrPacket::pdu + * will return 0. Caller takes ownership of the PDU pointer stored in * the PtrPacket. */ PtrPacket next_packet(); - + /** * \brief Starts a sniffing loop, using a callback functor for every * sniffed packet. - * - * The functor must implement an operator with one of the + * + * The functor must implement an operator with one of the * following signatures: - * + * * \code * bool(PDU&); * bool(const PDU&); * \endcode - * - * This functor will be called using the each of the sniffed packets + * + * This functor will be called using the each of the sniffed packets * as its argument. Using PDU member functions that modify the PDU, * such as PDU::release_inner_pdu, is perfectly valid. - * - * Note that if you're using a functor object, it will be copied using + * + * Note that if you're using a functor object, it will be copied using * its copy constructor, so it should be some kind of proxy to * another object which will process the packets(e.g. std::bind). * - * Sniffing will stop when either max_packets are sniffed(if it is != 0), + * Sniffing will stop when either max_packets are sniffed(if it is != 0), * or when the functor returns false. * * This method catches both malformed_packet and pdu_not_found exceptions, * which allows writing much cleaner code, since you can call PDU::rfind_pdu - * without worrying about catching the exception that can be thrown. This + * without worrying about catching the exception that can be thrown. This * allows writing code such as the following: * * \code * bool callback(const PDU& pdu) { - * // If either RawPDU is not found, or construction of the DNS - * // object fails, the BaseSniffer object will trap the exceptions, + * // If either RawPDU is not found, or construction of the DNS + * // object fails, the BaseSniffer object will trap the exceptions, * // so we don't need to worry about it. * DNS dns = pdu.rfind_pdu().to(); * return true; * } * \endcode - * + * * \param function The callback handler object which should process packets. * \param max_packets The maximum amount of packets to sniff. 0 == infinite. */ template void sniff_loop(Functor function, uint32_t max_packets = 0); - + /** * \brief Sets a filter on this sniffer. * \param filter The filter to be set. * \return True iif it was possible to apply the filter. */ bool set_filter(const std::string &filter); - + /** * \brief Stops sniffing loops. * @@ -210,13 +206,13 @@ namespace Tins { * * By default, packets will be parsed starting from link layer. * However, if you're parsing a lot of traffic, then you might - * want to extract packets and push them into a queue, + * want to extract packets and push them into a queue, * so a consumer can parse them when they're popped. * * This method allows doing that. If the parameter is true, * then packets taken from this BaseSniffer will only contain * a RawPDU which will have to entire contents of the packet. - * + * * \param value Whether to extract RawPDUs or not. */ void set_extract_raw_pdus(bool value); @@ -262,13 +258,13 @@ namespace Tins { private: BaseSniffer(const BaseSniffer&); BaseSniffer &operator=(const BaseSniffer&); - + pcap_t *handle; bpf_u_int32 mask; bool extract_raw; }; - - /** + + /** * \class Sniffer * \brief Sniffs packets from a network interface. */ @@ -292,7 +288,7 @@ namespace Tins { * when constructing a Sniffer object. * * \sa SnifferConfiguration - * + * * \param device The device which will be sniffed. * \param configuration The configuration object to use to setup the sniffer. */ @@ -304,7 +300,7 @@ namespace Tins { * By default the interface won't be put into promiscuous mode, and won't * be put into monitor mode. * - * \deprecated Use the Sniffer(const std::string&, const SnifferConfiguration&) + * \deprecated Use the Sniffer(const std::string&, const SnifferConfiguration&) * constructor. * \param device The device which will be sniffed. * \param max_packet_size The maximum packet size to be read. @@ -321,14 +317,14 @@ namespace Tins { * The maximum capture size is set to 65535. By default the interface won't * be put into promiscuous mode, and won't be put into monitor mode. * - * \deprecated Use the Sniffer(const std::string&, const SnifferConfiguration&) + * \deprecated Use the Sniffer(const std::string&, const SnifferConfiguration&) * constructor. * \param device The device which will be sniffed. * \param promisc Indicates if the interface should be put in promiscuous mode. * \param filter A capture filter to be used on the sniffing session.(optional); * \param rfmon Indicates if the interface should be put in monitor mode.(optional); */ - Sniffer(const std::string &device, promisc_type promisc = NON_PROMISC, + Sniffer(const std::string &device, promisc_type promisc = NON_PROMISC, const std::string &filter = "", bool rfmon = false); private: @@ -342,11 +338,11 @@ namespace Tins { void set_rfmon(bool rfmon_enabled); }; - + /** * \class FileSniffer * \brief Reads pcap files and interprets the packets in it. - * + * * This class acts exactly in the same way that Sniffer, but reads * packets from a pcap file instead of an interface. */ @@ -368,16 +364,16 @@ namespace Tins { */ FileSniffer(const std::string &file_name, const std::string &filter = ""); }; - + template class HandlerProxy { public: typedef T* ptr_type; typedef bool (T::*fun_type)(PDU&) ; - - HandlerProxy(ptr_type ptr, fun_type function) + + HandlerProxy(ptr_type ptr, fun_type function) : object(ptr), fun(function) {} - + bool operator()(PDU &pdu) { return (object->*fun)(pdu); } @@ -385,9 +381,9 @@ namespace Tins { ptr_type object; fun_type fun; }; - + template - HandlerProxy make_sniffer_handler(T *ptr, typename HandlerProxy::fun_type function) + HandlerProxy make_sniffer_handler(T *ptr, typename HandlerProxy::fun_type function) { return HandlerProxy(ptr, function); } @@ -467,15 +463,15 @@ namespace Tins { Packet pkt; }; - /** + /** * \class SnifferConfiguration * \brief Represents the configuration of a BaseSniffer object. * - * This class can be used as an easy way to configure a Sniffer + * This class can be used as an easy way to configure a Sniffer * or FileSniffer object. * - * It can be used by constructing an object of this type, - * setting the desired values and then passing it to the + * It can be used by constructing an object of this type, + * setting the desired values and then passing it to the * Sniffer or FileSniffer object's constructor. This sets * default values for some attributes: * @@ -485,8 +481,8 @@ namespace Tins { * * For any of the attributes not listed above, the associated * pcap function which is used to set them on a pcap handle - * won't be called at all. - * + * won't be called at all. + * * This class can be used to configure a Sniffer object, * like this: * @@ -495,7 +491,7 @@ namespace Tins { * SnifferConfiguration config; * config.set_filter("ip and port 80"); * config.set_promisc_mode(true); - * + * * // Use it on a Sniffer object. * Sniffer sniffer("eth0", config); * \endcode @@ -577,39 +573,13 @@ namespace Tins { unsigned _timeout; }; - #if TINS_IS_CXX11 - - template - using enable_if_t = typename std::enable_if::type; - - /* Template metaprogramming trait to determine if a functor can accept a Packet& as an argument */ - template - struct takes_packet : std::false_type { }; - - template - struct takes_packet()(std::declval()) ), bool>::value - >> : std::true_type { }; - - /* use enable_if to invoke the Packet& version of the sniff_loop handler if possible - otherwise fail to old behavior */ - template - bool _invoke_functor(Functor& f, Packet& p, typename std::enable_if::value, bool>::type* = 0) { - return f(p); - } - - template - bool _invoke_functor(Functor& f, Packet& p, typename std::enable_if::value, bool>::type* = 0) { - return f(*p.pdu()); - } - #endif - template void Tins::BaseSniffer::sniff_loop(Functor function, uint32_t max_packets) { for(iterator it = begin(); it != end(); ++it) { try { // If the functor returns false, we're done #if TINS_IS_CXX11 - if (!_invoke_functor(function, *it)) + if (!Tins::Internals::invoke_loop_cb(function, *it)) return; #else if(!function(*it)) @@ -623,5 +593,5 @@ namespace Tins { } } } - + #endif // TINS_SNIFFER_H