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

Added DHCP and BootP constructors from uint8_t buffer. Normalized IP destination and source address getters/setters.

This commit is contained in:
Matias Fontanini
2011-08-19 10:13:35 -03:00
parent bb3ea10209
commit 3e2168f6fc
17 changed files with 161 additions and 73 deletions

View File

@@ -47,20 +47,21 @@ int do_arp_spoofing(uint32_t iface, const string &iface_name, uint32_t gw, uint3
cout << "Could not resolve victim's ip address.\n";
return 6;
}
// Print out the hw addresses we're using.
cout << " Using gateway hw address: " << Utils::hwaddr_to_string(gw_hw) << "\n";
cout << " Using victim hw address: " << Utils::hwaddr_to_string(victim_hw) << "\n";
cout << " Using own hw address: " << Utils::hwaddr_to_string(own_hw) << "\n";
/* We tell the gateway that the victim is at out hw address,
* and tell the victim that the gateway is at out hw address */
ARP *gw_arp = new ARP(gw, victim, gw_hw, own_hw),
ARP *gw_arp = new ARP(gw, victim, gw_hw, own_hw),
*victim_arp = new ARP(victim, gw, victim_hw, own_hw);
// We are "replying" ARP requests
gw_arp->opcode(ARP::REPLY);
victim_arp->opcode(ARP::REPLY);
/* The packet we'll send to the gateway and victim.
* We include ut hw address as the source address
* We include our hw address as the source address
* in ethernet layer, to avoid possible packet dropping
* performed by any routers. */
EthernetII to_gw(iface, gw_hw, own_hw, gw_arp);
@@ -74,12 +75,10 @@ int do_arp_spoofing(uint32_t iface, const string &iface_name, uint32_t gw, uint3
}
int main(int argc, char *argv[]) {
if(argc < 3 && cout << "Usage: " << *argv << " <Gateway> <Victim> [Interface=eth0]\n")
if(argc != 3 && cout << "Usage: " << *argv << " <Gateway> <Victim>\n")
return 1;
uint32_t gw, victim, own_ip;
uint8_t own_hw[6];
// By default, eth0 is used.
string iface("eth0");
try {
// Convert dotted-notation ip addresses to integer.
gw = Utils::ip_to_int(argv[1]);
@@ -89,9 +88,10 @@ int main(int argc, char *argv[]) {
cout << "Invalid ip found...\n";
return 2;
}
if(argc == 4)
iface = argv[3];
// Get the interface which will be the gateway for our requests.
string iface = Utils::interface_from_ip(gw);
cout << iface << "\n";
uint32_t iface_index;
// Lookup the interface id. This will be required while forging packets.
if(!Utils::interface_id(iface, iface_index) && cout << "Interface " << iface << " does not exist!\n")

View File

@@ -34,24 +34,24 @@
using namespace std;
using namespace Tins;
struct ThreadData {
string interface;
string ip;
};
/* Our scan handler. This will receive SYNs and RSTs and inform us
* the scanned port's status.
*/
struct ScanHandler {
bool operator() (PDU *pdu) {
EthernetII *eth = dynamic_cast<EthernetII*>(pdu);
if(eth) {
IP *ip = dynamic_cast<IP*>(pdu->inner_pdu());
if(ip) {
TCP *tcp = dynamic_cast<TCP*>(ip->inner_pdu());
if(tcp) {
if(tcp->get_flag(TCP::RST))
cout << "Port: " << tcp->sport() << " closed\n";
else if(tcp->get_flag(TCP::SYN))
cout << "Port: " << tcp->sport() << " open\n";
}
// Down-cast the inner PDU to IP.
IP *ip = dynamic_cast<IP*>(pdu->inner_pdu());
if(ip) {
// Down-cast IP's inner PDU to TCP.
TCP *tcp = dynamic_cast<TCP*>(ip->inner_pdu());
if(tcp) {
// Ok, it's a TCP PDU. Is RST flag on? Then port is closed.
if(tcp->get_flag(TCP::RST))
cout << "Port: " << tcp->sport() << " closed\n";
// Is SYN flag on? Then port is open!
else if(tcp->get_flag(TCP::SYN))
cout << "Port: " << tcp->sport() << " open\n";
}
}
return true;
@@ -61,15 +61,22 @@ struct ScanHandler {
Sniffer *sniffer;
// Send syns to the given ip address, using the destination ports provided.
void send_syns(const string &iface, uint32_t dest_ip, int argc, char *argv[]) {
uint32_t own_ip;
// Resolve our ip on that interface.
if(!Utils::interface_ip(iface, own_ip) && cout << "Error obtaining interface ip.\n")
return;
PacketSender sender;
TCP *tcp = new TCP();
// Allocate the IP PDU
IP ip(dest_ip, own_ip, tcp);
// Set the SYN flag on.
tcp->set_flag(TCP::SYN, 1);
// Just some arbitrary port.
tcp->sport(1337);
while(argc--) {
// Set the new port and send the packet!
uint32_t port = atoi(*(argv++));
tcp->dport(port);
sender.send(&ip);
@@ -77,11 +84,15 @@ void send_syns(const string &iface, uint32_t dest_ip, int argc, char *argv[]) {
}
void *thread_proc(void *param) {
ThreadData *data = (ThreadData*)param;
// IP address is our parameter.
string *data = (string*)param;
// The scan handler.
ScanHandler handler;
// The required subclass of AbstractSnifferHandler which will serve as
// a proxy to our handler.
AbstractSnifferHandler *my_handler = new SnifferHandler<ScanHandler>(&handler);
sniffer->sniff_loop("tcp and ip src " + data->ip, my_handler);
cout << "Listo\n";
// Sniff loop. Only sniff TCP PDUs comming from the given IP and have either RST or SYN flag on.
sniffer->sniff_loop(my_handler, "tcp and ip src " + *data + " and tcp[tcpflags] & (tcp-rst|tcp-syn) != 0");
delete my_handler;
return 0;
}
@@ -91,26 +102,33 @@ int main(int argc, char *argv[]) {
return 1;
uint32_t ip;
try {
// Resolve the ip address
ip = Utils::resolve_ip(argv[1]);
}
catch(...) {
cout << "IP address is not valid.\n";
return 2;
}
// Resolve the interface which will be our gateway
string iface = Utils::interface_from_ip(ip);
if(!iface.size() && cout << "Could not locate gateway interface for given ip address\n")
return 3;
sniffer = new Sniffer(iface, 300);
ThreadData data;
data.interface = iface;
data.ip = argv[1];
pthread_t thread;
pthread_create(&thread, 0, thread_proc, &data);
// Allocate our sniffer. 300 bytes are enough to receive SYNs and RSTs.
sniffer = new Sniffer(iface, 300);
string ip_string = argv[1];
pthread_t thread;
// Launch our sniff thread.
pthread_create(&thread, 0, thread_proc, &ip_string);
// Start sending SYNs to port.
send_syns(iface, ip, argc - 2, argv + 2);
// Give it some time...
sleep(5);
// Ok, we kill our sniffer.
pthread_cancel(thread);
delete sniffer;
}

View File

@@ -45,13 +45,24 @@ namespace Tins {
BOOTREPLY = 2
};
/** \brief Creates an instance of BootP.
/**
* \brief Creates an instance of BootP.
*
* This sets the size of the vend field to 64, as the BootP RFC
* states.
*/
BootP();
/**
* \brief Constructor which creates a BootP 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.
* \param vend_field_size The vend field size to allocate.
* Subclasses might use 0 to provide their own interpretation of this field.
*/
BootP(const uint8_t *buffer, uint32_t total_sz, uint32_t vend_field_size = 64);
/** \brief BootP destructor.
*
* This frees the memory allocated to hold the vend field.

View File

@@ -164,6 +164,15 @@ namespace Tins {
*/
DHCP();
/**
* \brief Constructor which creates a DHCP 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.
* Subclasses might use 0 to provide their own interpretation of this field.
*/
DHCP(const uint8_t *buffer, uint32_t total_sz);
/**
* \brief DHCP destructor
*

View File

@@ -175,7 +175,7 @@ namespace Tins {
* \return The cloned PDU.
* \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:
/**
* Struct that represents the Ethernet II header
@@ -190,7 +190,7 @@ namespace Tins {
*
* \param eth_ptr The pointer to the ethhdr.
*/
EthernetII(ethhdr *eth_ptr);
EthernetII(const ethhdr *eth_ptr);
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);

View File

@@ -179,12 +179,12 @@ namespace Tins {
*
* \return The source address for this IP PDU.
*/
inline uint32_t source_address() const { return _ip.saddr; }
inline uint32_t src_addr() const { return _ip.saddr; }
/** \brief Getter for the destination address field.
* \return The destination address for this IP PDU.
*/
inline uint32_t dest_address() const { return _ip.daddr; }
inline uint32_t dst_addr() const { return _ip.daddr; }
/* Setters */
@@ -249,28 +249,28 @@ namespace Tins {
*
* \param ip The ip address in dotted string notation.
*/
void source_address(const std::string &ip);
void src_addr(const std::string &ip);
/**
* \brief Setter for the source address field.
*
* \param ip The ip address in integer notation.
*/
void source_address(uint32_t ip);
void src_addr(uint32_t ip);
/**
* \brief Setter for the destination address field.
*
* \param ip The ip address in dotted string notation.
*/
void dest_address(const std::string &ip);
void dst_addr(const std::string &ip);
/**
* \brief Setter for the destination address field.
*
* \param ip The ip address in integer notation.
*/
void dest_address(uint32_t ip);
void dst_addr(uint32_t ip);
/**
* \brief Sets an IP option.

View File

@@ -79,7 +79,7 @@ namespace Tins {
* \return The captured packet, matching the given filter, 0 if an
* error occured(probably compiling the filter).
*/
PDU *next_pdu(const std::string &filter);
PDU *next_pdu(const std::string &filter = "");
/**
* \brief Starts a sniffing loop, using a callback object for every
@@ -88,11 +88,11 @@ namespace Tins {
* 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 filter The filter to use when sniffing.
* \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);
void sniff_loop(AbstractSnifferHandler *cback_handler, const std::string &filter, uint32_t max_packets = 0);
/**
* \brief Stops sniffing loops.
@@ -105,6 +105,7 @@ namespace Tins {
pcap_t *handle;
bpf_u_int32 ip, mask;
bpf_program actual_filter;
};
/**

View File

@@ -53,16 +53,26 @@ namespace Tins {
*/
UDP(const uint8_t *buffer, uint32_t total_sz);
/** \brief Returns the destination port
*/
/**
* \brief Getter for the destination port.
* \return The datagram's destination port.
*/
inline uint16_t dport() const { return _udp.dport; }
/** \brief Returns the source port
*/
/**
* \brief Getter for the source port.
* \return The datagram's source port.
*/
inline uint16_t sport() const { return _udp.sport; }
/** \brief Set the destination port.
*
/**
* \brief Getter for the length of the datagram.
* \return The length of the datagram.
*/
inline uint16_t length() const { return _udp.len; }
/**
* \brief Set the destination port.
* \param new_dport The new destination port.
*/
void dport(uint16_t new_dport);

View File

@@ -200,11 +200,7 @@ Tins::PDU* Tins::ARP::make_arp_reply(const string& iface,
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* arp = new ARP(target, sender, hw_tgt, hw_snd);
arp->opcode(REPLY);
/* Create the EthernetII PDU with the ARP PDU as its inner PDU */

View File

@@ -1,3 +1,4 @@
#include <stdexcept>
#include <cstring>
#include <cassert>
#include "bootp.h"
@@ -10,6 +11,19 @@ Tins::BootP::BootP() : PDU(255), _vend_size(64) {
std::memset(_vend, 0, 64);
}
Tins::BootP::BootP(const uint8_t *buffer, uint32_t total_sz, uint32_t vend_field_size) : PDU(255), _vend(0), _vend_size(vend_field_size) {
if(total_sz < sizeof(bootphdr) + vend_field_size)
throw std::runtime_error("Not enought size for a BootP header in the buffer.");
std::memcpy(&_bootp, buffer, sizeof(bootphdr));
buffer += sizeof(bootphdr);
total_sz -= sizeof(bootphdr);
if(_vend_size) {
_vend = new uint8_t[_vend_size];
std::memcpy(_vend, buffer, _vend_size);
}
// Maybe RawPDU on what is left on the buffer?...
}
Tins::BootP::~BootP() {
delete[] _vend;
}

View File

@@ -19,6 +19,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdexcept>
#include <cstring>
#include <cassert>
#include "utils.h"
@@ -36,6 +37,26 @@ Tins::DHCP::DHCP() : _size(sizeof(uint32_t) + 1) {
hlen(6);
}
Tins::DHCP::DHCP(const uint8_t *buffer, uint32_t total_sz) : BootP(buffer, total_sz, 0) {
buffer += BootP::header_size();
total_sz -= BootP::header_size();
uint8_t args[2];
while(total_sz) {
for(unsigned i(0); i < 2; ++i) {
args[i] = *(buffer++);
total_sz--;
if(!total_sz)
throw std::runtime_error("Not enought size for a DHCP header in the buffer.");
}
// Not enough size for this option
if(total_sz < args[1])
throw std::runtime_error("Not enought size for a DHCP header in the buffer.");
add_option((Options)args[0], args[1], buffer);
buffer += args[1];
total_sz -= args[1];
}
}
Tins::DHCP::~DHCP() {
while(_options.size()) {
delete[] _options.front().value;

View File

@@ -73,7 +73,7 @@ Tins::EthernetII::EthernetII(const uint8_t *buffer, uint32_t total_sz) : PDU(ETH
inner_pdu(next);
}
Tins::EthernetII::EthernetII(ethhdr *eth_ptr) : PDU(ETHERTYPE_IP) {
Tins::EthernetII::EthernetII(const ethhdr *eth_ptr) : PDU(ETHERTYPE_IP) {
memcpy(&_eth, eth_ptr, sizeof(ethhdr));
}
@@ -163,10 +163,10 @@ Tins::PDU *Tins::EthernetII::recv_response(PacketSender *sender) {
return sender->recv_l2(this, (struct sockaddr*)&addr, (uint32_t)sizeof(addr));
}
Tins::PDU *Tins::EthernetII::clone_packet(uint8_t *ptr, uint32_t total_sz) {
Tins::PDU *Tins::EthernetII::clone_packet(const uint8_t *ptr, uint32_t total_sz) {
if(total_sz < sizeof(ethhdr))
return 0;
ethhdr *eth_ptr = (ethhdr*)ptr;
const ethhdr *eth_ptr = (ethhdr*)ptr;
PDU *child = 0, *cloned;
if(total_sz > sizeof(ethhdr)) {
if((child = PDU::clone_inner_pdu(ptr + sizeof(ethhdr), total_sz - sizeof(ethhdr))) == 0)

View File

@@ -126,19 +126,19 @@ void Tins::IP::check(uint16_t new_check) {
_ip.check = Utils::net_to_host_s(new_check);
}
void Tins::IP::source_address(const string &ip) {
void Tins::IP::src_addr(const string &ip) {
_ip.saddr = Utils::resolve_ip(ip);
}
void Tins::IP::source_address(uint32_t ip) {
void Tins::IP::src_addr(uint32_t ip) {
_ip.saddr = ip;
}
void Tins::IP::dest_address(const string &ip) {
void Tins::IP::dst_addr(const string &ip) {
_ip.daddr = Utils::resolve_ip(ip);
}
void Tins::IP::dest_address(uint32_t ip) {
void Tins::IP::dst_addr(uint32_t ip) {
_ip.daddr = ip;
}

View File

@@ -46,9 +46,12 @@ Tins::Sniffer::Sniffer(const string &device, unsigned max_packet_size) {
handle = pcap_open_live(device.c_str(), max_packet_size, 0, 0, error);
if(!handle)
throw runtime_error(error);
actual_filter.bf_insns = 0;
}
Tins::Sniffer::~Sniffer() {
if(actual_filter.bf_insns)
pcap_freecode(&actual_filter);
if(handle)
pcap_close(handle);
}
@@ -58,9 +61,12 @@ bool Tins::Sniffer::compile_set_filter(const string &filter, bpf_program &prog)
}
Tins::PDU *Tins::Sniffer::next_pdu(const string &filter) {
bpf_program prog;
if(!compile_set_filter(filter, prog))
return 0;
if(filter.size()) {
if(actual_filter.bf_insns)
pcap_freecode(&actual_filter);
if(!compile_set_filter(filter, actual_filter))
return 0;
}
pcap_pkthdr header;
PDU *ret = 0;
while(!ret) {
@@ -72,7 +78,6 @@ Tins::PDU *Tins::Sniffer::next_pdu(const string &filter) {
ret = 0;
}
}
pcap_freecode(&prog);
return ret;
}
@@ -80,13 +85,15 @@ void Tins::Sniffer::stop_sniff() {
pcap_breakloop(handle);
}
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)) {
LoopData data(handle, cback_handler);
pcap_loop(handle, max_packets, Sniffer::callback_handler, (u_char*)&data);
pcap_freecode(&prog);
void Tins::Sniffer::sniff_loop(AbstractSnifferHandler *cback_handler, const string &filter, uint32_t max_packets) {
if(filter.size()) {
if(actual_filter.bf_insns)
pcap_freecode(&actual_filter);
if(!compile_set_filter(filter, actual_filter))
return;
}
LoopData data(handle, cback_handler);
pcap_loop(handle, max_packets, Sniffer::callback_handler, (u_char*)&data);
}
// Static

View File

@@ -198,7 +198,7 @@ void Tins::TCP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PD
const Tins::IP *ip_packet = dynamic_cast<const Tins::IP*>(parent);
memcpy(tcp_start, &_tcp, sizeof(tcphdr));
if(!_tcp.check && ip_packet) {
uint32_t checksum = PDU::pseudoheader_checksum(ip_packet->source_address(), ip_packet->dest_address(), size(), IPPROTO_TCP) +
uint32_t checksum = PDU::pseudoheader_checksum(ip_packet->src_addr(), ip_packet->dst_addr(), size(), IPPROTO_TCP) +
PDU::do_checksum(tcp_start, tcp_start + total_sz);
while (checksum >> 16)
checksum = (checksum & 0xffff) + (checksum >> 16);

View File

@@ -73,7 +73,7 @@ void Tins::UDP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PD
length(sizeof(udphdr) + inner_pdu()->size());
std::memcpy(buffer, &_udp, sizeof(udphdr));
if(!_udp.check && ip_packet) {
uint32_t checksum = PDU::pseudoheader_checksum(ip_packet->source_address(), ip_packet->dest_address(), size(), IPPROTO_UDP) +
uint32_t checksum = PDU::pseudoheader_checksum(ip_packet->src_addr(), ip_packet->dst_addr(), size(), IPPROTO_UDP) +
PDU::do_checksum(buffer, buffer + total_sz);
while (checksum >> 16)
checksum = (checksum & 0xffff)+(checksum >> 16);

View File

@@ -23,6 +23,7 @@
#include <sstream>
#include <fstream>
#include <stdexcept>
#include <iostream> //borrame
#include <cassert>
#include <cstring>
#ifndef WIN32