1
0
mirror of https://github.com/mfontanini/libtins synced 2026-01-23 02:35:57 +01:00

Refactored sniffer class to take a SnifferConfigurator to do the setup.

This way it is easier to extend the different configuration capabilities.
This commit is contained in:
Santiago Alessandri
2014-08-29 16:30:13 -07:00
parent 74c85085fb
commit 5b2934e102
2 changed files with 232 additions and 120 deletions

View File

@@ -45,6 +45,7 @@
namespace Tins {
class SnifferIterator;
class SnifferConfigurator;
/**
* \class BaseSniffer
@@ -239,16 +240,15 @@ namespace Tins {
*/
BaseSniffer();
/**
* \brief Initialices this BaseSniffer.
*
* \param phandle The pcap handle to be used for sniffing.
* \param filter The pcap filter which will be applied to the
* stream.
* \param if_mask The interface's subnet mask. If 0 is provided,
* then some IP broadcast tests won't work correctly.
*/
void init(pcap_t *phandle, const std::string &filter, bpf_u_int32 if_mask);
void set_pcap_handle(pcap_t* const pcap_handle);
pcap_t* get_pcap_handle();
const pcap_t* get_pcap_handle() const;
void set_if_mask(bpf_u_int32 if_mask);
bpf_u_int32 get_if_mask() const;
private:
BaseSniffer(const BaseSniffer&);
BaseSniffer &operator=(const BaseSniffer&);
@@ -264,10 +264,6 @@ namespace Tins {
*/
class Sniffer : public BaseSniffer {
public:
enum promisc_type {
NON_PROMISC,
PROMISC
};
/**
* Constructs an instance of Sniffer.
@@ -281,25 +277,18 @@ namespace Tins {
* \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, unsigned max_packet_size,
bool promisc = false, const std::string &filter = "", bool rfmon = false);
Sniffer(const std::string &device, const SnifferConfigurator& sniffer_configurator);
/**
* \brief Constructs an instance of Sniffer.
*
* 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.
*
* \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,
const std::string &filter = "", bool rfmon = false);
private:
void init_sniffer(const std::string &device, unsigned max_packet_size,
bool promisc = false, const std::string &filter = "", bool rfmon = false);
friend class SnifferConfigurator;
void set_snap_len(unsigned snap_len);
void set_buffer_size(unsigned buffer_size);
void set_promisc_mode(bool promisc_enabled);
void set_rfmon(bool rfmon_enabled);
};
/**
@@ -316,7 +305,7 @@ namespace Tins {
* \param file_name The pcap file which will be parsed.
* \param filter A capture filter to be used on the file.(optional);
*/
FileSniffer(const std::string &file_name, const std::string &filter = "");
FileSniffer(const std::string &file_name, const SnifferConfigurator& sniffer_configurator);
};
template<class T>
@@ -417,6 +406,45 @@ namespace Tins {
Packet pkt;
};
class SnifferConfigurator {
public:
SnifferConfigurator();
void set_snap_len(unsigned snap_len);
void set_buffer_size(unsigned buffer_size);
void set_promisc_mode(bool enabled);
void set_filter(const std::string& filter);
void set_rfmon(bool enabled);
void set_timeout(unsigned timeout);
protected:
friend class Sniffer;
friend class FileSniffer;
void configure_sniffer(Sniffer& sniffer) const;
void configure_sniffer(FileSniffer& sniffer) const;
bool _has_snap_len;
unsigned _snap_len;
bool _has_buffer_size;
unsigned _buffer_size;
bool _has_promisc;
bool _promisc;
bool _has_rfmon;
bool _rfmon;
bool _has_filter;
std::string _filter;
bool _has_timeout;
unsigned _timeout;
};
template<class Functor>
void Tins::BaseSniffer::sniff_loop(Functor function, uint32_t max_packets) {
for(iterator it = begin(); it != end(); ++it) {

View File

@@ -44,24 +44,41 @@ using std::runtime_error;
namespace Tins {
BaseSniffer::BaseSniffer()
: handle(0), mask(0), extract_raw(false)
: handle(0), mask(PCAP_NETMASK_UNKNOWN), extract_raw(false)
{
}
BaseSniffer::~BaseSniffer() {
if(handle)
BaseSniffer::~BaseSniffer()
{
if (handle) {
pcap_close(handle);
}
}
void BaseSniffer::init(pcap_t *phandle, const std::string &filter,
bpf_u_int32 if_mask)
void BaseSniffer::set_pcap_handle(pcap_t* const pcap_handle)
{
handle = phandle;
mask = if_mask;
handle = pcap_handle;
}
if(!filter.empty() && !set_filter(filter))
throw runtime_error("Invalid filter");
pcap_t* BaseSniffer::get_pcap_handle()
{
return handle;
}
const pcap_t* BaseSniffer::get_pcap_handle() const
{
return handle;
}
void BaseSniffer::set_if_mask(bpf_u_int32 if_mask)
{
mask = if_mask;
}
bpf_u_int32 BaseSniffer::get_if_mask() const
{
return mask;
}
struct sniff_data {
@@ -183,8 +200,9 @@ BaseSniffer::iterator BaseSniffer::end() {
bool BaseSniffer::set_filter(const std::string &filter) {
bpf_program prog;
if(pcap_compile(handle, &prog, filter.c_str(), 0, mask) == -1)
if(pcap_compile(handle, &prog, filter.c_str(), 0, mask) == -1) {
return false;
}
bool result = pcap_setfilter(handle, &prog) != -1;
pcap_freecode(&prog);
return result;
@@ -196,94 +214,160 @@ void BaseSniffer::set_timeout(int ms) {
// ****************************** Sniffer ******************************
pcap_t *
pcap_open_live_extended(const char *source, int snaplen, int promisc, int to_ms, int rfmon, std::string& error)
{
pcap_t *p;
char errbuf[PCAP_ERRBUF_SIZE];
int status;
p = pcap_create(source, errbuf);
if (p == NULL) {
error = errbuf;
return (NULL);
}
status = pcap_set_snaplen(p, snaplen);
if (status < 0)
goto fail;
status = pcap_set_promisc(p, promisc);
if (status < 0)
goto fail;
status = pcap_set_timeout(p, to_ms);
if (status < 0)
goto fail;
#ifndef WIN32
if(pcap_can_set_rfmon(p) == 1) {
status = pcap_set_rfmon(p, rfmon);
if (status < 0)
goto fail;
}
#endif // WIN32
status = pcap_activate(p);
if (status < 0)
goto fail;
return (p);
fail:
std::ostringstream oss;
oss << source << ": " << pcap_geterr(p);
error = oss.str();
pcap_close(p);
return (NULL);
}
Sniffer::Sniffer(const string &device, unsigned max_packet_size,
bool promisc, const string &filter, bool rfmon)
{
init_sniffer(device, max_packet_size, promisc, filter, rfmon);
}
Sniffer::Sniffer(const std::string &device, promisc_type promisc,
const std::string &filter, bool rfmon)
{
init_sniffer(device, 65535, promisc == PROMISC, filter, rfmon);
}
void Sniffer::init_sniffer(const std::string &device, unsigned max_packet_size,
bool promisc, const std::string &filter, bool rfmon)
Sniffer::Sniffer(const string &device, const SnifferConfigurator& sniffer_configurator)
{
char error[PCAP_ERRBUF_SIZE];
bpf_u_int32 ip, if_mask;
if (pcap_lookupnet(device.c_str(), &ip, &if_mask, error) == -1) {
ip = 0;
if_mask = 0;
pcap_t* phandle = pcap_create(device.c_str(), error);
if (!phandle) {
throw runtime_error(error);
}
std::string string_error;
pcap_t *phandle = pcap_open_live_extended(
device.c_str(),
max_packet_size,
promisc,
1000,
rfmon,
string_error
);
if(!phandle)
throw runtime_error(string_error);
set_pcap_handle(phandle);
init(phandle, filter, if_mask);
// Set the netmask if we are able to find it.
bpf_u_int32 ip, if_mask;
if (pcap_lookupnet(device.c_str(), &ip, &if_mask, error) == 0) {
set_if_mask(if_mask);
}
// Configure the sniffer
sniffer_configurator.configure_sniffer(*this);
// Finally, activate the pcap. In case of error throw runtime_error
if (pcap_activate(get_pcap_handle()) < 0) {
throw std::runtime_error(pcap_geterr(get_pcap_handle()));
}
}
void Sniffer::set_snap_len(unsigned snap_len)
{
if (pcap_set_snaplen(get_pcap_handle(), snap_len)) {
throw std::runtime_error(pcap_geterr(get_pcap_handle()));
}
}
void Sniffer::set_buffer_size(unsigned buffer_size)
{
if (pcap_set_buffer_size(get_pcap_handle(), buffer_size)) {
throw std::runtime_error(pcap_geterr(get_pcap_handle()));
}
}
void Sniffer::set_promisc_mode(bool promisc_enabled)
{
if (pcap_set_promisc(get_pcap_handle(), promisc_enabled)) {
throw runtime_error(pcap_geterr(get_pcap_handle()));
}
}
void Sniffer::set_rfmon(bool rfmon_enabled)
{
#ifdef WIN32
#warning "Setting monitor mode disabled in Windows platform"
#else
if (pcap_can_set_rfmon(get_pcap_handle()) == 1) {
if (pcap_set_rfmon(get_pcap_handle(), rfmon_enabled)) {
throw runtime_error(pcap_geterr(get_pcap_handle()));
}
}
#endif
}
// **************************** FileSniffer ****************************
FileSniffer::FileSniffer(const string &file_name, const string &filter) {
FileSniffer::FileSniffer(const string &file_name, const SnifferConfigurator& sniffer_configurator) {
char error[PCAP_ERRBUF_SIZE];
pcap_t *phandle = pcap_open_offline(file_name.c_str(), error);
if(!phandle)
if(!phandle) {
throw std::runtime_error(error);
}
set_pcap_handle(phandle);
// Configure the sniffer
sniffer_configurator.configure_sniffer(*this);
init(phandle, filter, 0);
}
// ************************ SnifferConfigurator ************************
SnifferConfigurator::SnifferConfigurator() :
_has_snap_len(false), _snap_len(0),
_has_buffer_size(false), _buffer_size(0),
_has_promisc(false), _promisc(false),
_has_rfmon(false), _rfmon(false),
_has_filter(false),
_has_timeout(false), _timeout(0)
{
}
void SnifferConfigurator::configure_sniffer(Sniffer& sniffer) const
{
if (_has_snap_len) {
sniffer.set_snap_len(_snap_len);
}
if (_has_buffer_size) {
sniffer.set_buffer_size(_buffer_size);
}
if (_has_promisc) {
sniffer.set_promisc_mode(_promisc);
}
if (_has_rfmon) {
sniffer.set_rfmon(_rfmon);
}
if (_has_filter) {
if (!sniffer.set_filter(_filter)) {
throw std::runtime_error("Could not set the filter!");
}
}
if (_has_timeout) {
sniffer.set_timeout(_timeout);
}
}
void SnifferConfigurator::configure_sniffer(FileSniffer& sniffer) const
{
if (_has_filter) {
if (!sniffer.set_filter(_filter)) {
throw std::runtime_error("Could not set the filter!");
}
}
}
void SnifferConfigurator::set_snap_len(unsigned snap_len)
{
_has_snap_len = true;
_snap_len = snap_len;
}
void SnifferConfigurator::set_buffer_size(unsigned buffer_size)
{
_has_buffer_size = true;
_buffer_size = buffer_size;
}
void SnifferConfigurator::set_promisc_mode(bool enabled)
{
_has_promisc = true;
_promisc = enabled;
}
void SnifferConfigurator::set_filter(const std::string& filter)
{
_has_filter = true;
_filter = filter;
}
void SnifferConfigurator::set_rfmon(bool enabled)
{
_has_rfmon = true;
_rfmon = enabled;
}
void SnifferConfigurator::set_timeout(unsigned timeout)
{
_has_timeout = true;
_timeout = timeout;
}
}