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

Use pcap_sendpacket to send packets if this mode is enabled.

This commit is contained in:
Matias Fontanini
2015-04-18 17:46:14 -07:00
parent f2ed64293b
commit 96fc1a3749
6 changed files with 93 additions and 26 deletions

View File

@@ -81,6 +81,12 @@ IF(LIBTINS_ENABLE_DOT11)
ENDIF(LIBTINS_ENABLE_WPA2)
ENDIF(LIBTINS_ENABLE_DOT11)
OPTION(LIBTINS_USE_PCAP_SENDPACKET "Use pcap_sendpacket to send l2 packets" OFF)
IF(LIBTINS_USE_PCAP_SENDPACKET)
SET(HAVE_PACKET_SENDER_PCAP_SENDPACKET ON)
MESSAGE(STATUS "Using pcap_sendpacket to send l2 packets.")
ENDIF(LIBTINS_USE_PCAP_SENDPACKET)
# Add a target to generate API documentation using Doxygen
FIND_PACKAGE(Doxygen QUIET)
IF(DOXYGEN_FOUND)

View File

@@ -10,4 +10,7 @@
/* Have WPA2 decryption library */
#cmakedefine HAVE_WPA2_DECRYPTION
/* Use pcap_sendpacket to send l2 packets */
#cmakedefine HAVE_PACKET_SENDER_PCAP_SENDPACKET
#endif // TINS_CONFIG_H

View File

@@ -145,13 +145,10 @@ namespace Tins {
*/
uint32_t trailer_size() const;
// Windows does not support sending L2 PDUs.
#ifndef WIN32
/**
* \sa PDU::send()
*/
void send(PacketSender &sender, const NetworkInterface &iface);
#endif // WIN32
/**
* \brief Check wether ptr points to a valid response for this PDU.

View File

@@ -36,6 +36,10 @@
#include <vector>
#include <stdint.h>
#include <map>
#include "config.h"
#ifdef HAVE_PACKET_SENDER_PCAP_SENDPACKET
#include <pcap.h>
#endif // HAVE_PACKET_SENDER_PCAP_SENDPACKET
#include "network_interface.h"
#include "macros.h"
#include "cxxstd.h"
@@ -378,6 +382,9 @@ namespace Tins {
void send(PDU &pdu, const NetworkInterface &iface) {
static_cast<T&>(pdu).send(*this, iface);
}
#ifdef HAVE_PACKET_SENDER_PCAP_SENDPACKET
pcap_t* make_pcap_handle(const NetworkInterface& iface) const;
#endif // HAVE_PACKET_SENDER_PCAP_SENDPACKET
PDU *recv_match_loop(const std::vector<int>& sockets, PDU &pdu, struct sockaddr* link_addr,
uint32_t addrlen);
@@ -397,7 +404,11 @@ namespace Tins {
// In BSD we need to store the buffer size, retrieved using BIOCGBLEN
#if defined(BSD) || defined(__FreeBSD_kernel__)
int buffer_size;
#endif
#endif // BSD
#ifdef HAVE_PACKET_SENDER_PCAP_SENDPACKET
typedef std::map<NetworkInterface, pcap_t*> PcapHandleMap;
PcapHandleMap pcap_handles;
#endif // HAVE_PACKET_SENDER_PCAP_SENDPACKET
};
}

View File

@@ -43,6 +43,7 @@
#include <netinet/in.h>
#include <net/ethernet.h>
#endif
#include "config.h"
#include "ethernetII.h"
#include "packet_sender.h"
#include "rawpdu.h"
@@ -111,12 +112,17 @@ uint32_t EthernetII::trailer_size() const {
return padding;
}
#ifndef WIN32
void EthernetII::send(PacketSender &sender, const NetworkInterface &iface) {
if(!iface)
throw invalid_interface();
#if !defined(BSD) && !defined(__FreeBSD_kernel__)
#if defined(HAVE_PACKET_SENDER_PCAP_SENDPACKET) || defined(BSD) || defined(__FreeBSD_kernel__)
// Sending using pcap_sendpacket/BSD bpf packet mode is the same here
sender.send_l2(*this, 0, 0, iface);
#elif defined(WIN32)
// On Windows we can only send l2 PDUs using pcap_sendpacket
throw std::runtime_error("LIBTINS_USE_PCAP_SENDPACKET is not enabled");
#else
// Default GNU/Linux behaviour
struct sockaddr_ll addr;
memset(&addr, 0, sizeof(struct sockaddr_ll));
@@ -128,11 +134,8 @@ void EthernetII::send(PacketSender &sender, const NetworkInterface &iface) {
memcpy(&(addr.sll_addr), _eth.dst_mac, address_type::address_size);
sender.send_l2(*this, (struct sockaddr*)&addr, (uint32_t)sizeof(addr));
#else
sender.send_l2(*this, 0, 0, iface);
#endif
}
#endif // WIN32
bool EthernetII::matches_response(const uint8_t *ptr, uint32_t total_sz) const {
if(total_sz < sizeof(ethhdr))

View File

@@ -66,6 +66,8 @@
#include "ieee802_3.h"
#include "internals.h"
using std::string;
using std::runtime_error;
namespace Tins {
const int PacketSender::INVALID_RAW_SOCKET = -1;
@@ -107,12 +109,19 @@ PacketSender::~PacketSender() {
#endif
}
#if defined(BSD) || defined(__FreeBSD_kernel__)
for(BSDEtherSockets::iterator it = _ether_socket.begin(); it != _ether_socket.end(); ++it)
::close(it->second);
for(BSDEtherSockets::iterator it = _ether_socket.begin(); it != _ether_socket.end(); ++it)
::close(it->second);
#elif !defined(WIN32)
if(_ether_socket != INVALID_RAW_SOCKET)
::close(_ether_socket);
if(_ether_socket != INVALID_RAW_SOCKET)
::close(_ether_socket);
#endif
#ifdef HAVE_PACKET_SENDER_PCAP_SENDPACKET
for (PcapHandleMap::iterator it = pcap_handles.begin(); it != pcap_handles.end(); ++it) {
pcap_close(it->second);
}
pcap_handles.clear();
#endif // HAVE_PACKET_SENDER_PCAP_SENDPACKET
}
void PacketSender::default_interface(const NetworkInterface &iface) {
@@ -142,8 +151,37 @@ int PacketSender::get_ether_socket(const NetworkInterface& iface) {
#endif
}
#ifdef HAVE_PACKET_SENDER_PCAP_SENDPACKET
pcap_t* PacketSender::make_pcap_handle(const NetworkInterface& iface) const {
#ifdef WIN32
#define TINS_PREFIX_INTERFACE(x) ("\\Device\\NPF_" + x)
#else // WIN32
#define TINS_PREFIX_INTERFACE(x) (x)
#endif // WIN32
char error[PCAP_ERRBUF_SIZE];
pcap_t* handle = pcap_create(TINS_PREFIX_INTERFACE(iface.name()).c_str(), error);
if (!handle) {
throw runtime_error("Error opening pcap handle: " + string(error));
}
if (pcap_set_promisc(handle, 1) < 0) {
throw runtime_error("Failed to set pcap handle promisc mode: " + string(pcap_geterr(handle)));
}
if (pcap_activate(handle) < 0) {
throw runtime_error("Failed to activate pcap handle: " + string(pcap_geterr(handle)));
}
return handle;
}
#endif // HAVE_PACKET_SENDER_PCAP_SENDPACKET
void PacketSender::open_l2_socket(const NetworkInterface& iface) {
#if defined(BSD) || defined(__FreeBSD_kernel__)
#ifdef HAVE_PACKET_SENDER_PCAP_SENDPACKET
if (pcap_handles.count(iface) == 0) {
pcap_handles.insert(std::make_pair(iface, make_pcap_handle(iface)));
}
#elif defined(BSD) || defined(__FreeBSD_kernel__)
int sock = -1;
// At some point, there should be an available device
for (int i = 0; sock == -1;i++) {
@@ -258,7 +296,7 @@ PDU *PacketSender::send_recv(PDU &pdu, const NetworkInterface &iface) {
try {
pdu.send(*this, iface);
}
catch(std::runtime_error&) {
catch(runtime_error&) {
return 0;
}
return pdu.recv_response(*this, iface);
@@ -268,16 +306,25 @@ PDU *PacketSender::send_recv(PDU &pdu, const NetworkInterface &iface) {
void PacketSender::send_l2(PDU &pdu, struct sockaddr* link_addr,
uint32_t len_addr, const NetworkInterface &iface)
{
int sock = get_ether_socket(iface);
PDU::serialization_type buffer = pdu.serialize();
if(!buffer.empty()) {
#if defined(BSD) || defined(__FreeBSD_kernel__)
if(::write(sock, &buffer[0], buffer.size()) == -1)
#else
if(::sendto(sock, &buffer[0], buffer.size(), 0, link_addr, len_addr) == -1)
#endif
throw socket_write_error(make_error_string());
}
#ifdef HAVE_PACKET_SENDER_PCAP_SENDPACKET
open_l2_socket(iface);
pcap_t* handle = pcap_handles[iface];
if (pcap_sendpacket(handle, (u_char*)&buffer[0], buffer.size()) != 0) {
throw runtime_error("Failed to send packet: " + string(pcap_geterr(handle)));
}
#else // HAVE_PACKET_SENDER_PCAP_SENDPACKET
int sock = get_ether_socket(iface);
if(!buffer.empty()) {
#if defined(BSD) || defined(__FreeBSD_kernel__)
if(::write(sock, &buffer[0], buffer.size()) == -1)
#else
if(::sendto(sock, &buffer[0], buffer.size(), 0, link_addr, len_addr) == -1)
#endif
throw socket_write_error(make_error_string());
}
#endif // HAVE_PACKET_SENDER_PCAP_SENDPACKET
}
PDU *PacketSender::recv_l2(PDU &pdu, struct sockaddr *link_addr,
@@ -294,7 +341,7 @@ PDU *PacketSender::recv_l3(PDU &pdu, struct sockaddr* link_addr, uint32_t len_ad
std::vector<int> sockets(1, _sockets[type]);
if(type == IP_TCP_SOCKET || type == IP_UDP_SOCKET) {
#ifdef BSD
throw std::runtime_error("Receiving L3 packets not supported on this platform");
throw runtime_error("Receiving L3 packets not supported on this platform");
#endif
open_l3_socket(ICMP_SOCKET);
sockets.push_back(_sockets[ICMP_SOCKET]);