diff --git a/examples/arpspoofing.cpp b/examples/arpspoofing.cpp index 53e0cc1..f93e0c7 100644 --- a/examples/arpspoofing.cpp +++ b/examples/arpspoofing.cpp @@ -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 << " [Interface=eth0]\n") + if(argc != 3 && cout << "Usage: " << *argv << " \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") diff --git a/examples/portscan.cpp b/examples/portscan.cpp index 5f9c0d6..5f7c96b 100644 --- a/examples/portscan.cpp +++ b/examples/portscan.cpp @@ -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(pdu); - if(eth) { - IP *ip = dynamic_cast(pdu->inner_pdu()); - if(ip) { - TCP *tcp = dynamic_cast(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(pdu->inner_pdu()); + if(ip) { + // Down-cast IP's inner PDU to TCP. + TCP *tcp = dynamic_cast(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(&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; + + // Allocate our sniffer. 300 bytes are enough to receive SYNs and RSTs. sniffer = new Sniffer(iface, 300); - ThreadData data; - data.interface = iface; - data.ip = argv[1]; + + string ip_string = argv[1]; pthread_t thread; - pthread_create(&thread, 0, thread_proc, &data); + // 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; } diff --git a/include/bootp.h b/include/bootp.h index 5772316..30cad84 100644 --- a/include/bootp.h +++ b/include/bootp.h @@ -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. diff --git a/include/dhcp.h b/include/dhcp.h index 7239f12..dfda95b 100644 --- a/include/dhcp.h +++ b/include/dhcp.h @@ -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 * diff --git a/include/ethernetII.h b/include/ethernetII.h index a5ae816..c141146 100644 --- a/include/ethernetII.h +++ b/include/ethernetII.h @@ -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); diff --git a/include/ip.h b/include/ip.h index 606c710..4f2990d 100644 --- a/include/ip.h +++ b/include/ip.h @@ -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. diff --git a/include/sniffer.h b/include/sniffer.h index 1adfd71..84f77d2 100644 --- a/include/sniffer.h +++ b/include/sniffer.h @@ -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; }; /** diff --git a/include/udp.h b/include/udp.h index e3baeaa..096d5b3 100644 --- a/include/udp.h +++ b/include/udp.h @@ -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 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. - * + /** + * \brief Set the destination port. * \param new_dport The new destination port. */ void dport(uint16_t new_dport); diff --git a/src/arp.cpp b/src/arp.cpp index d0d9cb7..ab58e43 100644 --- a/src/arp.cpp +++ b/src/arp.cpp @@ -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 */ diff --git a/src/bootp.cpp b/src/bootp.cpp index ed6a0a6..0199e5f 100644 --- a/src/bootp.cpp +++ b/src/bootp.cpp @@ -1,3 +1,4 @@ +#include #include #include #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; } diff --git a/src/dhcp.cpp b/src/dhcp.cpp index cb42878..98a7666 100644 --- a/src/dhcp.cpp +++ b/src/dhcp.cpp @@ -19,6 +19,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include #include #include #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; diff --git a/src/ethernetII.cpp b/src/ethernetII.cpp index 85f9d25..d117eaa 100644 --- a/src/ethernetII.cpp +++ b/src/ethernetII.cpp @@ -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) diff --git a/src/ip.cpp b/src/ip.cpp index c513ae5..df986da 100644 --- a/src/ip.cpp +++ b/src/ip.cpp @@ -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; } diff --git a/src/sniffer.cpp b/src/sniffer.cpp index 434539d..f31abd6 100644 --- a/src/sniffer.cpp +++ b/src/sniffer.cpp @@ -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 diff --git a/src/tcp.cpp b/src/tcp.cpp index 421bd98..e08c110 100644 --- a/src/tcp.cpp +++ b/src/tcp.cpp @@ -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(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); diff --git a/src/udp.cpp b/src/udp.cpp index 0f6aa44..ca0250c 100644 --- a/src/udp.cpp +++ b/src/udp.cpp @@ -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); diff --git a/src/utils.cpp b/src/utils.cpp index 295cade..4c033de 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -23,6 +23,7 @@ #include #include #include +#include //borrame #include #include #ifndef WIN32