summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrea Barberio <insomniac@slackware.it>2017-07-20 23:40:14 +0100
committerMatias Fontanini <matias.fontanini@gmail.com>2017-07-23 09:38:11 -0700
commit87c0e3a337e17c5bfcfee44419623c49a4995505 (patch)
treef1002c16c12a2649950bb1f5b7dfde9499f3622c
parentcfb9b646cc89b0a1300bc863610264f7237bf6b4 (diff)
Add set_pcap_sniffing_method to specify either pcap_loop or pcap_dispatch
-rw-r--r--include/tins/sniffer.h43
-rw-r--r--src/sniffer.cpp20
2 files changed, 59 insertions, 4 deletions
diff --git a/include/tins/sniffer.h b/include/tins/sniffer.h
index 942cd71..cf9cae6 100644
--- a/include/tins/sniffer.h
+++ b/include/tins/sniffer.h
@@ -45,6 +45,7 @@
#include <pcap.h>
+
namespace Tins {
class SnifferIterator;
class SnifferConfiguration;
@@ -72,7 +73,8 @@ public:
* This constructor is available only in C++11.
*/
BaseSniffer(BaseSniffer &&rhs) TINS_NOEXCEPT
- : handle_(0), mask_(), extract_raw_(false) {
+ : handle_(0), mask_(), extract_raw_(false),
+ pcap_sniffing_method_(pcap_loop) {
*this = std::move(rhs);
}
@@ -85,6 +87,7 @@ public:
swap(handle_, rhs.handle_);
swap(mask_, rhs.mask_);
swap(extract_raw_, rhs.extract_raw_);
+ swap(pcap_sniffing_method_, rhs.pcap_sniffing_method_);
return* this;
}
#endif
@@ -238,6 +241,35 @@ public:
void set_extract_raw_pdus(bool value);
/**
+ * \brief function pointer for the sniffing method
+ *
+ * By default, libtins uses `pcap_loop` to sniff packets. With
+ * `set_pcap_sniffing_method` it is possible to specify an alternative
+ * sniffing method, for example `pcap_dispatch`, or a custom function.
+ * This function pointer has the same interface as `pcap_loop` and
+ * `pcap_dispatch`.
+ *
+ * \sa set_pcap_sniffing_method
+ */
+ typedef int(*PcapSniffingMethod)(pcap_t*, int, pcap_handler, u_char*);
+
+ /**
+ * \brief set sniffing method to either pcap_loop or pcap_dispatch.
+ *
+ * By default, packets are sniffed with `pcap_loop`, which only returns if
+ * a packet is received, thus ignoring timeout expiration, if any is set.
+ * With this method it is possible to pass an alternative sniffer function,
+ * e.g. `pcap_dispatch`, that honors timeouts, or a custom function with
+ * the same signature.
+ *
+ * See the relevant manual pages for pcap_loop and pcap_dispatch for more
+ * information on their behavior
+ *
+ * \sa PcapSniffingMethod
+ */
+ void set_pcap_sniffing_method(PcapSniffingMethod method);
+
+ /**
* \brief Retrieves this sniffer's link type.
*
* This calls pcap_datalink on the stored pcap handle and
@@ -282,6 +314,7 @@ private:
pcap_t* handle_;
bpf_u_int32 mask_;
bool extract_raw_;
+ PcapSniffingMethod pcap_sniffing_method_;
};
/**
@@ -568,6 +601,12 @@ public:
void set_filter(const std::string& filter);
/**
+ * Sets the pcap sniffing method to use.
+ * \param method The sniffing method to be used.
+ */
+ void set_pcap_sniffing_method(BaseSniffer::PcapSniffingMethod method);
+
+ /**
* Sets the rfmon option.
* \param enabled The rfmon option value.
*/
@@ -608,6 +647,7 @@ protected:
IMMEDIATE_MODE = 16,
DIRECTION = 32,
TIMESTAMP_PRECISION = 64,
+ PCAP_SNIFFING_METHOD = 128,
};
void configure_sniffer_pre_activation(Sniffer& sniffer) const;
@@ -619,6 +659,7 @@ protected:
unsigned snap_len_;
unsigned buffer_size_;
std::string filter_;
+ BaseSniffer::PcapSniffingMethod pcap_sniffing_method_;
unsigned timeout_;
bool promisc_;
bool rfmon_;
diff --git a/src/sniffer.cpp b/src/sniffer.cpp
index 87a1141..dc97feb 100644
--- a/src/sniffer.cpp
+++ b/src/sniffer.cpp
@@ -212,7 +212,7 @@ PtrPacket BaseSniffer::next_packet() {
// keep calling pcap_loop until a well-formed packet is found.
while (data.pdu == 0 && data.packet_processed) {
data.packet_processed = false;
- if (pcap_loop(handle_, 1, handler, (u_char*)&data) < 0) {
+ if (pcap_sniffing_method_(handle_, 1, handler, (u_char*)&data) < 0) {
return PtrPacket(0, Timestamp());
}
}
@@ -223,6 +223,13 @@ void BaseSniffer::set_extract_raw_pdus(bool value) {
extract_raw_ = value;
}
+void BaseSniffer::set_pcap_sniffing_method(PcapSniffingMethod method) {
+ if (method == nullptr) {
+ throw std::runtime_error("Sniffing method cannot be null");
+ }
+ pcap_sniffing_method_ = method;
+}
+
void BaseSniffer::stop_sniff() {
pcap_breakloop(handle_);
}
@@ -419,8 +426,9 @@ const unsigned SnifferConfiguration::DEFAULT_SNAP_LEN = 65535;
const unsigned SnifferConfiguration::DEFAULT_TIMEOUT = 1000;
SnifferConfiguration::SnifferConfiguration()
-: flags_(0), snap_len_(DEFAULT_SNAP_LEN), buffer_size_(0), timeout_(DEFAULT_TIMEOUT),
- promisc_(false), rfmon_(false), immediate_mode_(false), direction_(PCAP_D_INOUT),
+: flags_(0), snap_len_(DEFAULT_SNAP_LEN), buffer_size_(0),
+ pcap_sniffing_method_(pcap_loop), timeout_(DEFAULT_TIMEOUT), promisc_(false),
+ rfmon_(false), immediate_mode_(false), direction_(PCAP_D_INOUT),
timestamp_precision_(0) {
}
@@ -428,6 +436,7 @@ SnifferConfiguration::SnifferConfiguration()
void SnifferConfiguration::configure_sniffer_pre_activation(Sniffer& sniffer) const {
sniffer.set_snap_len(snap_len_);
sniffer.set_timeout(timeout_);
+ sniffer.set_pcap_sniffing_method(pcap_sniffing_method_);
if ((flags_ & BUFFER_SIZE) != 0) {
sniffer.set_buffer_size(buffer_size_);
}
@@ -488,6 +497,11 @@ void SnifferConfiguration::set_filter(const string& filter) {
filter_ = filter;
}
+void SnifferConfiguration::set_pcap_sniffing_method(BaseSniffer::PcapSniffingMethod method) {
+ flags_ |= PCAP_SNIFFING_METHOD;
+ pcap_sniffing_method_ = method;
+}
+
void SnifferConfiguration::set_rfmon(bool enabled) {
flags_ |= RFMON;
rfmon_ = enabled;