1
0
mirror of https://github.com/mfontanini/libtins synced 2026-01-30 13:34:27 +01:00

Added Packet and some wrapper packet classes. Modified the return value of BaseSniffer::next_packet.

This commit is contained in:
Matias Fontanini
2012-11-23 18:10:51 -03:00
parent a938d2ecfd
commit 492fd611f9
5 changed files with 400 additions and 61 deletions

190
include/packet.h Normal file
View File

@@ -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<typename WrappedType, typename TimestampType>
class PacketWrapper;
typedef PacketWrapper<PDU&, const Timestamp&> RefPacket;
typedef PacketWrapper<PDU*, Timestamp> 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<typename PDUType, typename TimestampType>
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 &timestamp() 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 <b>will delete</b> 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 &timestamp() const {
return ts;
}
/**
* \brief Returns the stored PDU*.
*
* Caller <b>must not</b> delete the pointer. \sa Packet::release_pdu
*/
PDU *pdu() {
return pdu_;
}
/**
* \brief Returns the stored PDU*.
*
* Caller <b>must not</b> 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

View File

@@ -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 &timestamp() const {
return timestamp_;
}
protected:
/**
* Default constructor.
@@ -141,19 +154,18 @@ namespace Tins {
pcap_t *handle;
Functor c_handler;
int iface_type;
timeval &timestamp;
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<class ConcretePDU, class Functor>
static bool call_functor(LoopData<Functor> *data, const u_char *packet, size_t len);
static bool call_functor(LoopData<Functor> *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<class Functor>
void Tins::BaseSniffer::sniff_loop(Functor function, uint32_t max_packets) {
LoopData<Functor> data(handle, function, iface_type, timestamp_);
LoopData<Functor> data(handle, function, iface_type);
pcap_loop(handle, max_packets, &BaseSniffer::callback_handler<Functor>, (u_char*)&data);
}
template<class ConcretePDU, class Functor>
bool Tins::BaseSniffer::call_functor(LoopData<Functor> *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<Functor> *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<class Functor>
@@ -225,18 +240,19 @@ namespace Tins {
std::auto_ptr<PDU> pdu;
LoopData<Functor> *data = reinterpret_cast<LoopData<Functor>*>(args);
bool ret_val(false);
data->timestamp = header->ts;
if(data->iface_type == DLT_EN10MB)
ret_val = call_functor<Tins::EthernetII>(data, packet, header->caplen);
ret_val = call_functor<Tins::EthernetII>(data, packet, header);
else if(data->iface_type == DLT_IEEE802_11_RADIO)
ret_val = call_functor<Tins::RadioTap>(data, packet, header->caplen);
ret_val = call_functor<Tins::RadioTap>(data, packet, header);
else if(data->iface_type == DLT_IEEE802_11) {
std::auto_ptr<PDU> 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<Tins::Loopback>(data, packet, header->caplen);
ret_val = call_functor<Tins::Loopback>(data, packet, header);
if(!ret_val)
pcap_breakloop(data->handle);

70
include/timestamp.h Normal file
View File

@@ -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 <sys/time.h>
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