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

Added Sniffer class. Added a constructor to eery PDU subclass which creates an instance of the PDU from a byte array.

This commit is contained in:
Matias Fontanini
2011-08-18 20:36:55 -03:00
parent d6ae9d498d
commit 18750fe18a
21 changed files with 492 additions and 103 deletions

View File

@@ -52,6 +52,14 @@ namespace Tins {
*/ */
ARP(uint32_t target_ip = 0, uint32_t sender_ip = 0, const uint8_t *target_hw = 0, const uint8_t *sender_hw = 0); ARP(uint32_t target_ip = 0, uint32_t sender_ip = 0, const uint8_t *target_hw = 0, const uint8_t *sender_hw = 0);
/**
* \brief Constructor which creates an TCP object from a buffer and adds all identifiable
* PDUs found in the buffer as children of this one.
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
ARP(const uint8_t *buffer, uint32_t total_sz);
/* Getters */ /* Getters */
/** /**
* \brief Getter for the sender's hardware address. * \brief Getter for the sender's hardware address.
@@ -305,7 +313,7 @@ namespace Tins {
* \return The cloned PDU. * \return The cloned PDU.
* \sa PDU::clone_packet * \sa PDU::clone_packet
*/ */
PDU *clone_packet(uint8_t *ptr, uint32_t total_sz); PDU *clone_packet(const uint8_t *ptr, uint32_t total_sz);
private: private:
struct arphdr { struct arphdr {
@@ -325,7 +333,7 @@ namespace Tins {
* *
* \param arp_ptr The pointer to the arphdr. * \param arp_ptr The pointer to the arphdr.
*/ */
ARP(arphdr *arp_ptr); ARP(const arphdr *arp_ptr);
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent); void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);

View File

@@ -131,9 +131,28 @@ namespace Tins {
* \brief DHCP options struct. * \brief DHCP options struct.
*/ */
struct DHCPOption { struct DHCPOption {
uint8_t option, length; /**
* \brief The option number.
*/
uint8_t option;
/**
* \brief The value's length in bytes.
*/
uint8_t length;
/**
* \brief The option's value.
*/
uint8_t *value; uint8_t *value;
/**
* \brief Creates an instance of DHCPOption.
*
* The option's value is copied, therefore the user should
* manually free any memory pointed by the "val" parameter.
* \param opt The option number.
* \param len The length of the option's value in bytes.
* \param val The option's value.
*/
DHCPOption(uint8_t opt, uint8_t len, const uint8_t *val); DHCPOption(uint8_t opt, uint8_t len, const uint8_t *val);
}; };
@@ -201,7 +220,7 @@ namespace Tins {
/** /**
* \brief Adds a domain name servers option. * \brief Adds a domain name servers option.
* \param routers A list of ip addresses in integer notation. * \param dns A list of ip addresses in integer notation.
* \return True if the option was added successfully. \sa DHCP::add_option * \return True if the option was added successfully. \sa DHCP::add_option
*/ */
bool add_dns_options(const std::list<uint32_t> &dns); bool add_dns_options(const std::list<uint32_t> &dns);

View File

@@ -66,6 +66,14 @@ namespace Tins {
*/ */
EthernetII(uint32_t iface_index, const uint8_t* mac_dst = 0, const uint8_t* mac_src = 0, PDU* child = 0); EthernetII(uint32_t iface_index, const uint8_t* mac_dst = 0, const uint8_t* mac_src = 0, PDU* child = 0);
/**
* \brief Constructor which creates an EthernetII object from a buffer and adds all identifiable
* PDUs found in the buffer as children of this one.
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
EthernetII(const uint8_t *buffer, uint32_t total_sz);
/* Getters */ /* Getters */
/** /**
* \brief Getter for the destination's mac address. * \brief Getter for the destination's mac address.
@@ -88,7 +96,14 @@ namespace Tins {
*/ */
inline uint32_t iface() const { return this->_iface_index; } inline uint32_t iface() const { return this->_iface_index; }
/**
* \brief Getter for the payload_type
* \return The payload type.
*/
uint16_t payload_type() const;
/* Setters */ /* Setters */
/** /**
* \brief Setter for the destination's MAC. * \brief Setter for the destination's MAC.
* *
@@ -177,11 +192,11 @@ namespace Tins {
*/ */
EthernetII(ethhdr *eth_ptr); EthernetII(ethhdr *eth_ptr);
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
ethhdr _eth; ethhdr _eth;
uint32_t _iface_index; uint32_t _iface_index;
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
}; };
}; };

View File

@@ -57,6 +57,14 @@ namespace Tins {
*/ */
ICMP(Flags flag = ECHO_REQUEST); ICMP(Flags flag = ECHO_REQUEST);
/**
* \brief Constructor which creates an ICMP object from a buffer and adds all identifiable
* PDUs found in the buffer as children of this one.
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
ICMP(const uint8_t *buffer, uint32_t total_sz);
/** /**
* \brief Sets the code field. * \brief Sets the code field.
* *
@@ -273,7 +281,7 @@ namespace Tins {
* \return The cloned PDU. * \return The cloned PDU.
* \sa PDU::clone_packet * \sa PDU::clone_packet
*/ */
PDU *clone_packet(uint8_t *ptr, uint32_t total_sz); PDU *clone_packet(const uint8_t *ptr, uint32_t total_sz);
private: private:
static uint16_t global_id, global_seq; static uint16_t global_id, global_seq;
@@ -298,7 +306,7 @@ namespace Tins {
* *
* \param ptr The icmphdr to clone. * \param ptr The icmphdr to clone.
*/ */
ICMP(icmphdr *ptr); ICMP(const icmphdr *ptr);
/** \brief Serialices this ICMP PDU. /** \brief Serialices this ICMP PDU.
* \param buffer The buffer in which the PDU will be serialized. * \param buffer The buffer in which the PDU will be serialized.

View File

@@ -100,6 +100,14 @@ namespace Tins {
*/ */
IP(uint32_t ip_dst = 0, uint32_t ip_src = 0, PDU *child = 0); IP(uint32_t ip_dst = 0, uint32_t ip_src = 0, PDU *child = 0);
/**
* \brief Constructor which creates an IP object from a buffer and adds all identifiable
* PDUs found in the buffer as children of this one.
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
IP(const uint8_t *buffer, uint32_t total_sz);
/** /**
* \brief Destructor for IP objects. * \brief Destructor for IP objects.
* *
@@ -340,7 +348,7 @@ namespace Tins {
* \return The cloned PDU. * \return The cloned PDU.
* \sa PDU::clone_packet * \sa PDU::clone_packet
*/ */
PDU *clone_packet(uint8_t *ptr, uint32_t total_sz); PDU *clone_packet(const uint8_t *ptr, uint32_t total_sz);
private: private:
static const uint8_t DEFAULT_TTL; static const uint8_t DEFAULT_TTL;

View File

@@ -164,7 +164,7 @@ namespace Tins {
* \param total_sz The size of the buffer. * \param total_sz The size of the buffer.
* \return The cloned PDU. * \return The cloned PDU.
*/ */
virtual PDU *clone_packet(uint8_t *ptr, uint32_t total_sz) { return 0; } virtual PDU *clone_packet(const uint8_t *ptr, uint32_t total_sz) { return 0; }
protected: protected:
/** \brief Serializes this PDU and propagates this action to child PDUs. /** \brief Serializes this PDU and propagates this action to child PDUs.
* *
@@ -181,7 +181,7 @@ namespace Tins {
* \param total_sz The total size of the buffer. * \param total_sz The total size of the buffer.
* \return Returns the cloned PDU. Will be 0 if cloning failed. * \return Returns the cloned PDU. Will be 0 if cloning failed.
*/ */
PDU *clone_inner_pdu(uint8_t *ptr, uint32_t total_sz); PDU *clone_inner_pdu(const uint8_t *ptr, uint32_t total_sz);
/** \brief Serializes this TCP PDU. /** \brief Serializes this TCP PDU.
* *

View File

@@ -37,14 +37,21 @@ namespace Tins {
public: public:
/** \brief Creates an instance of RawPDU. /** \brief Creates an instance of RawPDU.
* *
* The payload is not copied by default, therefore it must be * The payload is copied, therefore the original payload's memory
* manually freed by the user. If the payload was to be copied, * must be freed by the user.
* then the copy flag must be set to true.
* \param pload The payload which the RawPDU will contain. * \param pload The payload which the RawPDU will contain.
* \param size The size of the payload. * \param size The size of the payload.
* \param copy Flag indicating wether to copy the payload.
*/ */
RawPDU(uint8_t *pload, uint32_t size, bool copy = false); RawPDU(const uint8_t *pload, uint32_t size);
/** \brief Creates an instance of RawPDU.
*
* The payload is not copied in this constructor, therefore
* it must be manually freed by the user.
* \param pload The payload which the RawPDU will contain.
* \param size The size of the payload.
*/
RawPDU(uint8_t *pload, uint32_t size);
/** \brief RawPDU destructor. /** \brief RawPDU destructor.
* *

111
include/sniffer.h Normal file
View File

@@ -0,0 +1,111 @@
#ifndef __SNIFFER_H
#define __SNIFFER_H
#include <pcap.h>
#include <string>
#include "pdu.h"
namespace Tins {
/**
* \brief Abstract sniffed packet handler.
*
* Base class to handle sniffed packets when using Sniffer::sniff_loop.
* Users should either inherit this class, or use the template class
* SnifferHandler to provide their own handlers.
*/
class AbstractSnifferHandler {
public:
/**
* \brief AbstractSnifferHandler destructor.
*/
virtual ~AbstractSnifferHandler() { }
/**
* \brief Handle a captured PDU.
* \return Should return false if no more sniffing is required.
*/
virtual bool handle(PDU *pdu) = 0;
};
/**
* \brief Sniffer class can be used to sniff packets using filters.
*/
class Sniffer {
public:
/**
* \brief Creates an instance of sniffer.
* \param device The device which will be sniffed.
* \param max_packet_size The maximum packet size to be read.
*/
Sniffer(const std::string &device, unsigned max_packet_size);
/**
* \brief Sniffer destructor.
* This frees all memory used by the pcap handle.
*/
~Sniffer();
/**
* \brief Compiles a filter and uses it to capture one packet.
*
* This method should be used only when expecting few packets.
* It's innefficient since it recompiles the filter every time it
* is called. To reuse a filter and sniff more efficiently, use
* Sniffer::sniff_loop.
* \param filter The filter which will be used while sniffing.
* \return The captured packet, matching the given filter, 0 if an
* error occured(probably compiling the filter).
*/
PDU *next_pdu(const std::string &filter);
/**
* \brief Starts a sniffing loop, using a callback object for every
* sniffed packet.
*
* Handlers could be user-provided classes which inherit AbstractSnifferHandler,
* or it could be a specific SnifferHandler specialization. This method deletes
* packets after they are handled, therefore the handlers MUST NOT delete them.
* \param filter The filter to use when sniffing.
* \param cback_handler The callback handler object which should process packets.
* \param max_packets The maximum amount of packets to sniff. 0 == infinite.
*/
void sniff_loop(const std::string &filter, AbstractSnifferHandler *cback_handler, uint32_t max_packets = 0);
private:
bool compile_set_filter(const std::string &filter, bpf_program &prog);
static void callback_handler(u_char *args, const struct pcap_pkthdr *header, const u_char *packet);
pcap_t *handle;
bpf_u_int32 ip, mask;
};
/**
* \brief Concrete implementation of AbstractSnifferHandler.
*
* This class is instantiated using a pointer to the actual handler.
* Every time a packet is sniffed, operator() (PDU*) will be called on
* the given pointer. \sa AbstractSnifferHandler
*/
template<class T> class SnifferHandler : public AbstractSnifferHandler {
public:
/**
* Creates an instance of SnifferHandler.
* \param ptr The pointer to the actual handler.
*/
SnifferHandler(T *ptr) : handler(ptr) { }
/**
* \brief The overriden AbstractSnifferHandler::handle.
* \param pdu The sniffed PDU.
* \return False if no more sniffing is required, otherwise true.
*/
bool handle(PDU *pdu) {
return (*handler)(pdu);
}
private:
T *handler;
};
};
#endif

View File

@@ -78,15 +78,21 @@ namespace Tins {
* \param dport Destination port. * \param dport Destination port.
* \param sport Source port. * \param sport Source port.
* */ * */
TCP(uint16_t dport = 0, uint16_t sport = 0); TCP(uint16_t dport = 0, uint16_t sport = 0);
/**
* \brief Constructor which creates an TCP object from a buffer and adds all identifiable
* PDUs found in the buffer as children of this one.
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
TCP(const uint8_t *buffer, uint32_t total_sz);
/** /**
* \brief TCP destructor. * \brief TCP destructor.
* *
* Destructs the TCP instance. Does not free the payload. * Destructs the TCP instance. Does not free the payload.
* */ * */
~TCP(); ~TCP();
/** /**
@@ -145,6 +151,16 @@ namespace Tins {
*/ */
inline uint8_t data_offset() const { return this->_tcp.doff; } inline uint8_t data_offset() const { return this->_tcp.doff; }
/**
* \brief Gets the value of a flag.
*
* \param tcp_flag The polled flag.
* \return The value of the flag.
*/
uint8_t get_flag(Flags tcp_flag);
/* Setters */
/** /**
* \brief Setter for the destination port field. * \brief Setter for the destination port field.
* *

View File

@@ -34,15 +34,24 @@ namespace Tins {
*/ */
class UDP : public PDU { class UDP : public PDU {
public: public:
/** \brief UDP constructor. /**
* \brief UDP constructor.
* *
* Creates an instance of UDP. Destination and source port can * Creates an instance of UDP. Destination and source port can
* be provided, otherwise both will be 0. * be provided, otherwise both will be 0.
* \param dport Destination port. * \param dport Destination port.
* \param sport Source port. * \param sport Source port.
* \param child The child PDU(optional).
* */ * */
UDP(uint16_t dport = 0, uint16_t sport = 0, PDU *child = 0); UDP(uint16_t dport = 0, uint16_t sport = 0, PDU *child = 0);
/**
* \brief Constructor which creates an UDP object from a buffer and adds all identifiable
* PDUs found in the buffer as children of this one.
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
UDP(const uint8_t *buffer, uint32_t total_sz);
/** \brief Returns the destination port /** \brief Returns the destination port
*/ */

View File

@@ -118,7 +118,7 @@ namespace Tins {
* *
* If the lookup fails, false will be returned, true otherwise. * If the lookup fails, false will be returned, true otherwise.
* \param iface The interface from which to extract the identifier. * \param iface The interface from which to extract the identifier.
* \param flag The interface id will be returned in this parameter. * \param id The interface id will be returned in this parameter.
*/ */
bool interface_id(const std::string &iface, uint32_t &id); bool interface_id(const std::string &iface, uint32_t &id);

View File

@@ -31,66 +31,9 @@
using namespace std; using namespace std;
Tins::PDU* Tins::ARP::make_arp_request(const std::string& iface,
const std::string& target,
const std::string& sender,
const uint8_t* hw_snd) {
uint32_t target_ip = Tins::Utils::resolve_ip(target);
uint32_t sender_ip = Tins::Utils::resolve_ip(sender);
return make_arp_request(iface, target_ip, sender_ip, hw_snd);
}
Tins::PDU* Tins::ARP::make_arp_request(const std::string& iface,
uint32_t target,
uint32_t sender,
const uint8_t* hw_snd) {
/* Create ARP packet and set its attributes */
ARP* arp = new ARP();
arp->target_ip_addr(target);
arp->sender_ip_addr(sender);
if (hw_snd) {
arp->sender_hw_addr(hw_snd);
}
arp->opcode(REQUEST);
/* Create the EthernetII PDU with the ARP PDU as its inner PDU */
EthernetII* eth = new EthernetII(iface, Tins::EthernetII::BROADCAST, hw_snd, arp);
return eth;
}
Tins::PDU* Tins::ARP::make_arp_reply(const string& iface,
const string& target,
const string& sender,
const uint8_t* hw_tgt,
const uint8_t* hw_snd) {
uint32_t target_ip = Tins::Utils::resolve_ip(target);
uint32_t sender_ip = Tins::Utils::resolve_ip(sender);
return make_arp_reply(iface, target_ip, sender_ip, hw_tgt, hw_snd);
}
Tins::PDU* Tins::ARP::make_arp_reply(const string& iface,
uint32_t target,
uint32_t sender,
const uint8_t* hw_tgt,
const uint8_t* hw_snd) {
/* Create ARP packet and set its attributes */
ARP* arp = new ARP();
arp->target_ip_addr(target);
arp->sender_ip_addr(sender);
arp->target_hw_addr(hw_tgt);
arp->sender_hw_addr(hw_snd);
arp->opcode(REPLY);
/* Create the EthernetII PDU with the ARP PDU as its inner PDU */
EthernetII* eth = new EthernetII(iface, hw_tgt, hw_snd, arp);
return eth;
}
Tins::ARP::ARP(uint32_t target_ip, uint32_t sender_ip, const uint8_t *target_hw, const uint8_t *sender_hw) : PDU(0x0608) { Tins::ARP::ARP(uint32_t target_ip, uint32_t sender_ip, const uint8_t *target_hw, const uint8_t *sender_hw) : PDU(0x0608) {
std::memset(&_arp, 0, sizeof(arphdr)); memset(&_arp, 0, sizeof(arphdr));
hw_addr_format(1); hw_addr_format(1);
prot_addr_format(0x0800); prot_addr_format(0x0800);
hw_addr_length(6); hw_addr_length(6);
@@ -103,7 +46,16 @@ Tins::ARP::ARP(uint32_t target_ip, uint32_t sender_ip, const uint8_t *target_hw,
target_hw_addr(target_hw); target_hw_addr(target_hw);
} }
Tins::ARP::ARP(arphdr *arp_ptr) : PDU(Utils::net_to_host_s(0x0806)) { Tins::ARP::ARP(const uint8_t *buffer, uint32_t total_sz) : PDU(0x0608) {
if(total_sz < sizeof(arphdr))
throw std::runtime_error("Not enought size for an ARP header in the buffer.");
memcpy(&_arp, buffer, sizeof(arphdr));
total_sz -= sizeof(arphdr);
if(total_sz)
inner_pdu(new RawPDU(buffer + sizeof(arphdr), total_sz));
}
Tins::ARP::ARP(const arphdr *arp_ptr) : PDU(Utils::net_to_host_s(0x0806)) {
memcpy(&_arp, arp_ptr, sizeof(arphdr)); memcpy(&_arp, arp_ptr, sizeof(arphdr));
} }
@@ -188,10 +140,10 @@ bool Tins::ARP::matches_response(uint8_t *ptr, uint32_t total_sz) {
return arp_ptr->ar_sip == _arp.ar_tip && arp_ptr->ar_tip == _arp.ar_sip; return arp_ptr->ar_sip == _arp.ar_tip && arp_ptr->ar_tip == _arp.ar_sip;
} }
Tins::PDU *Tins::ARP::clone_packet(uint8_t *ptr, uint32_t total_sz) { Tins::PDU *Tins::ARP::clone_packet(const uint8_t *ptr, uint32_t total_sz) {
if(total_sz < sizeof(arphdr)) if(total_sz < sizeof(arphdr))
return 0; return 0;
arphdr *arp_ptr = (arphdr*)ptr; const arphdr *arp_ptr = (arphdr*)ptr;
PDU *child = 0, *cloned; PDU *child = 0, *cloned;
if(total_sz > sizeof(arphdr)) { if(total_sz > sizeof(arphdr)) {
if((child = PDU::clone_inner_pdu(ptr + sizeof(arphdr), total_sz - sizeof(arphdr))) == 0) if((child = PDU::clone_inner_pdu(ptr + sizeof(arphdr), total_sz - sizeof(arphdr))) == 0)
@@ -201,3 +153,61 @@ Tins::PDU *Tins::ARP::clone_packet(uint8_t *ptr, uint32_t total_sz) {
cloned->inner_pdu(child); cloned->inner_pdu(child);
return cloned; return cloned;
} }
Tins::PDU* Tins::ARP::make_arp_request(const string& iface,
const string& target,
const string& sender,
const uint8_t* hw_snd) {
uint32_t target_ip = Tins::Utils::resolve_ip(target);
uint32_t sender_ip = Tins::Utils::resolve_ip(sender);
return make_arp_request(iface, target_ip, sender_ip, hw_snd);
}
Tins::PDU* Tins::ARP::make_arp_request(const std::string& iface,
uint32_t target,
uint32_t sender,
const uint8_t* hw_snd) {
/* Create ARP packet and set its attributes */
ARP* arp = new ARP();
arp->target_ip_addr(target);
arp->sender_ip_addr(sender);
if (hw_snd) {
arp->sender_hw_addr(hw_snd);
}
arp->opcode(REQUEST);
/* Create the EthernetII PDU with the ARP PDU as its inner PDU */
EthernetII* eth = new EthernetII(iface, Tins::EthernetII::BROADCAST, hw_snd, arp);
return eth;
}
Tins::PDU* Tins::ARP::make_arp_reply(const string& iface,
const string& target,
const string& sender,
const uint8_t* hw_tgt,
const uint8_t* hw_snd) {
uint32_t target_ip = Tins::Utils::resolve_ip(target);
uint32_t sender_ip = Tins::Utils::resolve_ip(sender);
return make_arp_reply(iface, target_ip, sender_ip, hw_tgt, hw_snd);
}
Tins::PDU* Tins::ARP::make_arp_reply(const string& iface,
uint32_t target,
uint32_t sender,
const uint8_t* hw_tgt,
const uint8_t* hw_snd) {
/* Create ARP packet and set its attributes */
ARP* arp = new ARP();
arp->target_ip_addr(target);
arp->sender_ip_addr(sender);
arp->target_hw_addr(hw_tgt);
arp->sender_hw_addr(hw_snd);
arp->opcode(REPLY);
/* Create the EthernetII PDU with the ARP PDU as its inner PDU */
EthernetII* eth = new EthernetII(iface, hw_tgt, hw_snd, arp);
return eth;
}

View File

@@ -21,7 +21,6 @@
#include <cstring> #include <cstring>
#include <cassert> #include <cassert>
#include <iostream> //borrame
#include "utils.h" #include "utils.h"
#include "dhcp.h" #include "dhcp.h"

View File

@@ -21,7 +21,7 @@
#include <cassert> #include <cassert>
#include <cstring> #include <cstring>
#include <stdexcept>
#ifndef WIN32 #ifndef WIN32
#include <net/ethernet.h> #include <net/ethernet.h>
#include <netpacket/packet.h> #include <netpacket/packet.h>
@@ -29,6 +29,8 @@
#endif #endif
#include "ethernetII.h" #include "ethernetII.h"
#include "rawpdu.h" #include "rawpdu.h"
#include "ip.h"
#include "arp.h"
#include "utils.h" #include "utils.h"
const uint8_t* Tins::EthernetII::BROADCAST = (const uint8_t*)"\xff\xff\xff\xff\xff\xff"; const uint8_t* Tins::EthernetII::BROADCAST = (const uint8_t*)"\xff\xff\xff\xff\xff\xff";
@@ -54,10 +56,31 @@ Tins::EthernetII::EthernetII(uint32_t iface_index, const uint8_t* mac_dst, const
this->_eth.payload_type = 0; this->_eth.payload_type = 0;
} }
Tins::EthernetII::EthernetII(const uint8_t *buffer, uint32_t total_sz) : PDU(ETHERTYPE_IP) {
if(total_sz < sizeof(ethhdr))
throw std::runtime_error("Not enought size for an ethernetII header in the buffer.");
memcpy(&_eth, buffer, sizeof(ethhdr));
PDU *next = 0;
switch(payload_type()) {
case ETHERTYPE_IP:
next = new Tins::IP(buffer + sizeof(ethhdr), total_sz - sizeof(ethhdr));
break;
case ETHERTYPE_ARP:
next = new Tins::ARP(buffer + sizeof(ethhdr), total_sz - sizeof(ethhdr));
break;
// Other protos plz
}
inner_pdu(next);
}
Tins::EthernetII::EthernetII(ethhdr *eth_ptr) : PDU(ETHERTYPE_IP) { Tins::EthernetII::EthernetII(ethhdr *eth_ptr) : PDU(ETHERTYPE_IP) {
memcpy(&_eth, eth_ptr, sizeof(ethhdr)); memcpy(&_eth, eth_ptr, sizeof(ethhdr));
} }
uint16_t Tins::EthernetII::payload_type() const {
return Utils::net_to_host_s(_eth.payload_type);
}
void Tins::EthernetII::dst_mac(const uint8_t* new_dst_mac) { void Tins::EthernetII::dst_mac(const uint8_t* new_dst_mac) {
memcpy(this->_eth.dst_mac, new_dst_mac, 6); memcpy(this->_eth.dst_mac, new_dst_mac, 6);
} }

View File

@@ -19,12 +19,12 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#include <stdexcept>
#include <cstring>
#include <cassert>
#ifndef WIN32 #ifndef WIN32
#include <netinet/in.h> #include <netinet/in.h>
#endif #endif
#include <cstring>
#include <cassert>
#include "icmp.h" #include "icmp.h"
#include "rawpdu.h" #include "rawpdu.h"
#include "utils.h" #include "utils.h"
@@ -48,7 +48,16 @@ Tins::ICMP::ICMP(Flags flag) : PDU(IPPROTO_ICMP) {
}; };
} }
Tins::ICMP::ICMP(icmphdr *ptr) : PDU(IPPROTO_ICMP) { Tins::ICMP::ICMP(const uint8_t *buffer, uint32_t total_sz) : PDU(IPPROTO_ICMP) {
if(total_sz < sizeof(icmphdr))
throw std::runtime_error("Not enought size for an ICMP header in the buffer.");
std::memcpy(&_icmp, buffer, sizeof(icmphdr));
total_sz -= sizeof(icmphdr);
if(total_sz)
inner_pdu(new RawPDU(buffer + sizeof(icmphdr), total_sz));
}
Tins::ICMP::ICMP(const icmphdr *ptr) : PDU(IPPROTO_ICMP) {
std::memcpy(&_icmp, ptr, sizeof(icmphdr)); std::memcpy(&_icmp, ptr, sizeof(icmphdr));
} }
@@ -177,10 +186,10 @@ bool Tins::ICMP::matches_response(uint8_t *ptr, uint32_t total_sz) {
return false; return false;
} }
Tins::PDU *Tins::ICMP::clone_packet(uint8_t *ptr, uint32_t total_sz) { Tins::PDU *Tins::ICMP::clone_packet(const uint8_t *ptr, uint32_t total_sz) {
if(total_sz < sizeof(icmphdr)) if(total_sz < sizeof(icmphdr))
return 0; return 0;
icmphdr *icmp_ptr = (icmphdr*)ptr; const icmphdr *icmp_ptr = (icmphdr*)ptr;
PDU *child = 0, *cloned; PDU *child = 0, *cloned;
if(total_sz > sizeof(icmphdr)) { if(total_sz > sizeof(icmphdr)) {
if((child = PDU::clone_inner_pdu(ptr + sizeof(icmphdr), total_sz - sizeof(icmphdr))) == 0) if((child = PDU::clone_inner_pdu(ptr + sizeof(icmphdr), total_sz - sizeof(icmphdr))) == 0)

View File

@@ -19,12 +19,16 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#include <stdexcept>
#include <cstring> #include <cstring>
#include <cassert> #include <cassert>
#ifndef WIN32 #ifndef WIN32
#include <netinet/in.h> #include <netinet/in.h>
#endif #endif
#include "ip.h" #include "ip.h"
#include "tcp.h"
#include "udp.h"
#include "icmp.h"
#include "rawpdu.h" #include "rawpdu.h"
#include "utils.h" #include "utils.h"
@@ -42,6 +46,29 @@ Tins::IP::IP(const string &ip_dst, const string &ip_src, PDU *child) : PDU(IPPRO
} }
Tins::IP::IP(const uint8_t *buffer, uint32_t total_sz) : PDU(IPPROTO_IP) {
if(total_sz < sizeof(iphdr))
throw std::runtime_error("Not enought size for an IP header in the buffer.");
std::memcpy(&_ip, buffer, sizeof(iphdr));
/* Options... */
buffer += head_len() * sizeof(uint32_t);
total_sz -= head_len() * sizeof(uint32_t);
switch(_ip.protocol) {
case IPPROTO_TCP:
inner_pdu(new Tins::TCP(buffer, total_sz));
break;
case IPPROTO_UDP:
inner_pdu(new Tins::UDP(buffer, total_sz));
break;
case IPPROTO_ICMP:
inner_pdu(new Tins::ICMP(buffer, total_sz));
break;
default:
inner_pdu(new Tins::RawPDU(buffer, total_sz));
break;
}
}
Tins::IP::IP(const iphdr *ptr) : PDU(IPPROTO_IP) { Tins::IP::IP(const iphdr *ptr) : PDU(IPPROTO_IP) {
std::memcpy(&_ip, ptr, sizeof(iphdr)); std::memcpy(&_ip, ptr, sizeof(iphdr));
/* Options... */ /* Options... */
@@ -241,10 +268,10 @@ bool Tins::IP::matches_response(uint8_t *ptr, uint32_t total_sz) {
return false; return false;
} }
Tins::PDU *Tins::IP::clone_packet(uint8_t *ptr, uint32_t total_sz) { Tins::PDU *Tins::IP::clone_packet(const uint8_t *ptr, uint32_t total_sz) {
if(total_sz < sizeof(iphdr)) if(total_sz < sizeof(iphdr))
return 0; return 0;
iphdr *ip_ptr = (iphdr*)ptr; const iphdr *ip_ptr = (iphdr*)ptr;
uint32_t sz = ip_ptr->ihl * sizeof(uint32_t); uint32_t sz = ip_ptr->ihl * sizeof(uint32_t);
if(total_sz < sz) if(total_sz < sz)
return 0; return 0;

View File

@@ -20,7 +20,6 @@
*/ */
#include <cassert> #include <cassert>
#include <iostream> //borrame
#include "utils.h" #include "utils.h"
#include "pdu.h" #include "pdu.h"
#include "rawpdu.h" #include "rawpdu.h"
@@ -69,7 +68,7 @@ void Tins::PDU::serialize(uint8_t *buffer, uint32_t total_sz, const PDU *parent)
write_serialization(buffer, total_sz, parent); write_serialization(buffer, total_sz, parent);
} }
Tins::PDU *Tins::PDU::clone_inner_pdu(uint8_t *ptr, uint32_t total_sz) { Tins::PDU *Tins::PDU::clone_inner_pdu(const uint8_t *ptr, uint32_t total_sz) {
PDU *child = 0; PDU *child = 0;
if(inner_pdu()) { if(inner_pdu()) {
child = inner_pdu()->clone_packet(ptr, total_sz); child = inner_pdu()->clone_packet(ptr, total_sz);
@@ -77,7 +76,7 @@ Tins::PDU *Tins::PDU::clone_inner_pdu(uint8_t *ptr, uint32_t total_sz) {
return 0; return 0;
} }
else else
child = new RawPDU(ptr, total_sz, true); child = new RawPDU(ptr, total_sz);
return child; return child;
} }

View File

@@ -24,11 +24,13 @@
#include "rawpdu.h" #include "rawpdu.h"
Tins::RawPDU::RawPDU(uint8_t *pload, uint32_t size, bool copy) : PDU(255), _payload(pload), _payload_size(size), _owns_payload(copy) { Tins::RawPDU::RawPDU(const uint8_t *pload, uint32_t size) : PDU(255), _payload_size(size), _owns_payload(true) {
if(copy) { _payload = new uint8_t[size];
_payload = new uint8_t[size]; std::memcpy(_payload, pload, size);
std::memcpy(_payload, pload, size); }
}
Tins::RawPDU::RawPDU(uint8_t *pload, uint32_t size) : PDU(255), _payload(pload), _payload_size(size), _owns_payload(false) {
} }
Tins::RawPDU::~RawPDU() { Tins::RawPDU::~RawPDU() {

64
src/sniffer.cpp Normal file
View File

@@ -0,0 +1,64 @@
#include <stdexcept>
#include "sniffer.h"
#include "ethernetII.h"
using namespace std;
Tins::Sniffer::Sniffer(const string &device, unsigned max_packet_size) {
char error[PCAP_ERRBUF_SIZE];
if (pcap_lookupnet(device.c_str(), &ip, &mask, error) == -1)
throw runtime_error(error);
handle = pcap_open_live(device.c_str(), max_packet_size, 0, 0, error);
if(!handle)
throw runtime_error(error);
}
Tins::Sniffer::~Sniffer() {
if(handle)
pcap_close(handle);
}
bool Tins::Sniffer::compile_set_filter(const string &filter, bpf_program &prog) {
return (pcap_compile(handle, &prog, filter.c_str(), 0, ip) != -1 && pcap_setfilter(handle, &prog) != -1);
}
Tins::PDU *Tins::Sniffer::next_pdu(const string &filter) {
bpf_program prog;
if(!compile_set_filter(filter, prog))
return 0;
pcap_pkthdr header;
PDU *ret = 0;
while(!ret) {
const u_char *content = pcap_next(handle, &header);
try {
ret = new EthernetII((const uint8_t*)content, header.caplen);
}
catch(...) {
ret = 0;
}
}
pcap_freecode(&prog);
return ret;
}
void Tins::Sniffer::sniff_loop(const std::string &filter, AbstractSnifferHandler *cback_handler, uint32_t max_packets) {
bpf_program prog;
if(compile_set_filter(filter, prog)) {
pcap_loop(handle, max_packets, Sniffer::callback_handler, (u_char*)cback_handler);
pcap_freecode(&prog);
}
}
// Static
void Tins::Sniffer::callback_handler(u_char *args, const struct pcap_pkthdr *header, const u_char *packet) {
try {
PDU *pdu = new EthernetII((const uint8_t*)packet, header->caplen);
reinterpret_cast<AbstractSnifferHandler*>(args)->handle(pdu);
delete pdu;
}
catch(...) {
}
}

View File

@@ -19,6 +19,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#include <stdexcept>
#include <cstring> #include <cstring>
#include <cassert> #include <cassert>
#ifndef WIN32 #ifndef WIN32
@@ -41,6 +42,18 @@ Tins::TCP::TCP(uint16_t dport, uint16_t sport) : PDU(IPPROTO_TCP), _options_size
this->check(0); this->check(0);
} }
Tins::TCP::TCP(const uint8_t *buffer, uint32_t total_sz) : PDU(IPPROTO_TCP) {
if(total_sz < sizeof(tcphdr))
throw std::runtime_error("Not enought size for an TCP header in the buffer.");
std::memcpy(&_tcp, buffer, sizeof(tcphdr));
/* Options... */
total_sz -= sizeof(tcphdr);
if(total_sz)
inner_pdu(new RawPDU(buffer + sizeof(tcphdr), total_sz));
}
Tins::TCP::~TCP() { Tins::TCP::~TCP() {
for(unsigned i(0); i < _options.size(); ++i) for(unsigned i(0); i < _options.size(); ++i)
delete[] _options[i].data; delete[] _options[i].data;
@@ -92,6 +105,38 @@ void Tins::TCP::set_timestamp(uint32_t value, uint32_t reply) {
add_option(TSOPT, 8, (uint8_t*)&buffer); add_option(TSOPT, 8, (uint8_t*)&buffer);
} }
uint8_t Tins::TCP::get_flag(Flags tcp_flag) {
switch(tcp_flag) {
case FIN:
return _tcp.fin;
break;
case SYN:
return _tcp.syn;
break;
case RST:
return _tcp.rst;
break;
case PSH:
return _tcp.psh;
break;
case ACK:
return _tcp.ack;
break;
case URG:
return _tcp.urg;
break;
case ECE:
return _tcp.ece;
break;
case CWR:
return _tcp.cwr;
break;
default:
return 0;
break;
};
}
void Tins::TCP::set_flag(Flags tcp_flag, uint8_t value) { void Tins::TCP::set_flag(Flags tcp_flag, uint8_t value) {
switch(tcp_flag) { switch(tcp_flag) {
case FIN: case FIN:

View File

@@ -19,11 +19,12 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#include <stdexcept>
#include <cassert>
#include <cstring>
#ifndef WIN32 #ifndef WIN32
#include <netinet/in.h> #include <netinet/in.h>
#endif #endif
#include <cassert>
#include <cstring>
#include "utils.h" #include "utils.h"
#include "udp.h" #include "udp.h"
#include "ip.h" #include "ip.h"
@@ -36,6 +37,15 @@ Tins::UDP::UDP(uint16_t dport, uint16_t sport, PDU *child) : PDU(IPPROTO_UDP, ch
_udp.len = 0; _udp.len = 0;
} }
Tins::UDP::UDP(const uint8_t *buffer, uint32_t total_sz) : PDU(IPPROTO_UDP) {
if(total_sz < sizeof(udphdr))
throw std::runtime_error("Not enought size for an UDP header in the buffer.");
std::memcpy(&_udp, buffer, sizeof(udphdr));
total_sz -= sizeof(udphdr);
if(total_sz)
inner_pdu(new RawPDU(buffer + sizeof(udphdr), total_sz));
}
void Tins::UDP::payload(uint8_t *new_payload, uint32_t new_payload_size) { void Tins::UDP::payload(uint8_t *new_payload, uint32_t new_payload_size) {
inner_pdu(new RawPDU(new_payload, new_payload_size)); inner_pdu(new RawPDU(new_payload, new_payload_size));
} }