From de82dc23224e37639e54b58cba5152c2281dde1d Mon Sep 17 00:00:00 2001 From: Matias Fontanini Date: Wed, 28 Nov 2012 16:50:47 -0300 Subject: [PATCH] Link layer protocols can now be sent on BSD. --- include/packet_sender.h | 22 ++++++- src/dot11.cpp | 2 +- src/ethernetII.cpp | 4 +- src/ieee802_3.cpp | 6 +- src/packet_sender.cpp | 124 ++++++++++++++++++++++++++++++---------- src/radiotap.cpp | 2 +- 6 files changed, 120 insertions(+), 40 deletions(-) diff --git a/include/packet_sender.h b/include/packet_sender.h index ca66219..89f5f62 100644 --- a/include/packet_sender.h +++ b/include/packet_sender.h @@ -37,8 +37,10 @@ #include #include #include "network_interface.h" +#include "arch.h" struct timeval; +struct sockaddr; namespace Tins { class PDU; @@ -115,7 +117,7 @@ namespace Tins { * * \param type The type of the socket to be closed. */ - void close_socket(SocketType type); + void close_socket(SocketType type, const NetworkInterface &iface = NetworkInterface()); /** * \brief Sends a PDU. @@ -154,7 +156,8 @@ namespace Tins { * \param len_addr The sockaddr struct length. * \return Returns the response PDU. If no response is received, then 0 is returned. */ - PDU *recv_l2(PDU &pdu, struct sockaddr *link_addr, uint32_t len_addr); + PDU *recv_l2(PDU &pdu, struct sockaddr *link_addr, uint32_t len_addr, + const NetworkInterface &iface = NetworkInterface()); /** * \brief Sends a level 2 PDU. @@ -169,7 +172,8 @@ namespace Tins { * \param link_addr The sockaddr struct which will be used to send the PDU. * \param len_addr The sockaddr struct length. */ - void send_l2(PDU &pdu, struct sockaddr* link_addr, uint32_t len_addr); + void send_l2(PDU &pdu, struct sockaddr* link_addr, uint32_t len_addr, + const NetworkInterface &iface = NetworkInterface()); #endif // WIN32 /** @@ -207,10 +211,22 @@ namespace Tins { int find_type(SocketType type); int timeval_subtract (struct timeval *result, struct timeval *x, struct timeval *y); + #ifndef WIN32 + bool ether_socket_initialized(const NetworkInterface& iface = NetworkInterface()) const; + int get_ether_socket(const NetworkInterface& iface = NetworkInterface()); + #endif PDU *recv_match_loop(int sock, PDU &pdu, struct sockaddr* link_addr, uint32_t addrlen); std::vector _sockets; + #ifndef WIN32 + #ifdef BSD + typedef std::map BSDEtherSockets; + BSDEtherSockets _ether_socket; + #else + int _ether_socket; + #endif + #endif SocketTypeMap _types; uint32_t _timeout, _timeout_usec; }; diff --git a/src/dot11.cpp b/src/dot11.cpp index 44c1434..5e0fc02 100644 --- a/src/dot11.cpp +++ b/src/dot11.cpp @@ -188,7 +188,7 @@ void Dot11::send(PacketSender &sender) { memcpy(&(addr.sll_addr), _header.addr1, 6); sender.send_l2(*this, (struct sockaddr*)&addr, (uint32_t)sizeof(addr)); #else - sender.send_l2(*this, 0, 0); + sender.send_l2(*this, 0, 0, _iface); #endif } #endif // WIN32 diff --git a/src/ethernetII.cpp b/src/ethernetII.cpp index de33fd0..ce6b9d0 100644 --- a/src/ethernetII.cpp +++ b/src/ethernetII.cpp @@ -130,7 +130,7 @@ void EthernetII::send(PacketSender &sender) { sender.send_l2(*this, (struct sockaddr*)&addr, (uint32_t)sizeof(addr)); #else - sender.send_l2(*this, 0, 0); + sender.send_l2(*this, 0, 0, _iface); #endif } #endif // WIN32 @@ -185,7 +185,7 @@ PDU *EthernetII::recv_response(PacketSender &sender) { return sender.recv_l2(*this, (struct sockaddr*)&addr, (uint32_t)sizeof(addr)); #else - return sender.recv_l2(*this, 0, 0); + return sender.recv_l2(*this, 0, 0, _iface); #endif } #endif // WIN32 diff --git a/src/ieee802_3.cpp b/src/ieee802_3.cpp index 2d93755..6bf0533 100644 --- a/src/ieee802_3.cpp +++ b/src/ieee802_3.cpp @@ -110,7 +110,7 @@ void IEEE802_3::send(PacketSender &sender) { sender.send_l2(*this, (struct sockaddr*)&addr, (uint32_t)sizeof(addr)); #else - sender.send_l2(*this, 0, 0); + sender.send_l2(*this, 0, 0, _iface); #endif } #endif // WIN32 @@ -141,6 +141,8 @@ void IEEE802_3::write_serialization(uint8_t *buffer, uint32_t total_sz, const PD #ifndef WIN32 PDU *IEEE802_3::recv_response(PacketSender &sender) { + if(!_iface) + throw std::runtime_error("Interface has not been set"); #ifndef BSD struct sockaddr_ll addr; memset(&addr, 0, sizeof(struct sockaddr_ll)); @@ -153,7 +155,7 @@ PDU *IEEE802_3::recv_response(PacketSender &sender) { return sender.recv_l2(*this, (struct sockaddr*)&addr, (uint32_t)sizeof(addr)); #else - return sender.recv_l2(*this, 0, 0); + return sender.recv_l2(*this, 0, 0, _iface); #endif } #endif // WIN32 diff --git a/src/packet_sender.cpp b/src/packet_sender.cpp index a676fab..748e9ac 100644 --- a/src/packet_sender.cpp +++ b/src/packet_sender.cpp @@ -27,13 +27,13 @@ * */ +#include "packet_sender.h" #ifndef WIN32 #include #include #include #include #include - #include "arch.h" #ifdef BSD #include #include @@ -57,7 +57,6 @@ #include #include "pdu.h" #include "arch.h" -#include "packet_sender.h" #include "network_interface.h" @@ -74,7 +73,11 @@ const uint32_t PacketSender::DEFAULT_TIMEOUT = 2; #endif PacketSender::PacketSender(uint32_t recv_timeout, uint32_t usec) -: _sockets(SOCKETS_END, INVALID_RAW_SOCKET), _timeout(recv_timeout), +: _sockets(SOCKETS_END, INVALID_RAW_SOCKET), +#ifndef BSD + _ether_socket(INVALID_RAW_SOCKET), +#endif + _timeout(recv_timeout), _timeout_usec(usec) { _types[IP_SOCKET] = IPPROTO_RAW; @@ -90,21 +93,62 @@ PacketSender::~PacketSender() { ::closesocket(_sockets[i]); #endif } + #ifdef BSD + for(BSDEtherSockets::iterator it = _ether_socket.begin(); it != _ether_socket.end(); ++it) + ::close(it->second); + #else + if(_ether_socket != INVALID_RAW_SOCKET) + ::close(_ether_socket); + #endif } #ifndef WIN32 +bool PacketSender::ether_socket_initialized(const NetworkInterface& iface) const { + #ifdef BSD + return _ether_socket.count(iface.id()); + #else + return _ether_socket != INVALID_RAW_SOCKET; + #endif +} + +int PacketSender::get_ether_socket(const NetworkInterface& iface) { + if(!ether_socket_initialized(iface)) + open_l2_socket(iface); + #ifdef BSD + return _ether_socket[iface.id()]; + #else + return _ether_socket; + #endif +} + void PacketSender::open_l2_socket(const NetworkInterface& iface) { - if (_sockets[ETHER_SOCKET] == INVALID_RAW_SOCKET) { - int sock; - #ifdef BSD - // FIXME - #else - sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); - #endif - if (sock == -1) + #ifdef BSD + int sock = -1; + // At some point, there should be an available device + for (int i = 0; sock == -1;i++) { + std::ostringstream oss; + oss << "/dev/bpf" << i; + + sock = open(oss.str().c_str(), O_RDWR); + } + if(sock == -1) + throw SocketOpenError(make_error_string()); + + struct ifreq ifr; + strncpy(ifr.ifr_name, iface.name().c_str(), sizeof(ifr.ifr_name) - 1); + if(ioctl(sock, BIOCSETIF, (caddr_t)&ifr) < 0) { + ::close(sock); + throw SocketOpenError(make_error_string()); + } + _ether_socket[iface.id()] = sock; + #else + if (_ether_socket == INVALID_RAW_SOCKET) { + _ether_socket = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); + + if (_ether_socket == -1) throw SocketOpenError(make_error_string()); - _sockets[ETHER_SOCKET] = sock; } + #endif } #endif // WIN32 @@ -130,16 +174,34 @@ void PacketSender::open_l3_socket(SocketType type) { } } -void PacketSender::close_socket(SocketType type) { - if(type >= SOCKETS_END || _sockets[type] == INVALID_RAW_SOCKET) - throw InvalidSocketTypeError(); - #ifndef WIN32 - if(close(_sockets[type]) == -1) - throw SocketCloseError(make_error_string()); - #else - closesocket(_sockets[type]); - #endif - _sockets[type] = INVALID_RAW_SOCKET; +void PacketSender::close_socket(SocketType type, const NetworkInterface &iface) { + if(type == ETHER_SOCKET) { + #ifdef BSD + BSDEtherSockets::iterator it = _ether_socket.find(iface.id()); + if(it == _ether_socket.end()) + throw InvalidSocketTypeError(); + if(::close(it->second) == -1) + throw SocketCloseError(make_error_string()); + _ether_socket.erase(it); + #else + if(_ether_socket == INVALID_RAW_SOCKET) + throw InvalidSocketTypeError(); + if(::close(_ether_socket) == -1) + throw SocketCloseError(make_error_string()); + _ether_socket = INVALID_RAW_SOCKET; + #endif + } + else { + if(type >= SOCKETS_END || _sockets[type] == INVALID_RAW_SOCKET) + throw InvalidSocketTypeError(); + #ifndef WIN32 + if(close(_sockets[type]) == -1) + throw SocketCloseError(make_error_string()); + #else + closesocket(_sockets[type]); + #endif + _sockets[type] = INVALID_RAW_SOCKET; + } } void PacketSender::send(PDU &pdu) { @@ -156,24 +218,24 @@ PDU *PacketSender::send_recv(PDU &pdu) { return pdu.recv_response(*this); } #ifndef WIN32 -void PacketSender::send_l2(PDU &pdu, struct sockaddr* link_addr, uint32_t len_addr) { - open_l2_socket(); - - int sock = _sockets[ETHER_SOCKET]; +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()) { #ifdef BSD - if(write(sock, &buffer[0], buffer.size()) == -1) + if(::write(sock, &buffer[0], buffer.size()) == -1) #else - if(sendto(sock, &buffer[0], buffer.size(), 0, link_addr, len_addr) == -1) + if(::sendto(sock, &buffer[0], buffer.size(), 0, link_addr, len_addr) == -1) #endif throw SocketWriteError(make_error_string()); } } -PDU *PacketSender::recv_l2(PDU &pdu, struct sockaddr *link_addr, uint32_t len_addr) { - open_l2_socket(); - return recv_match_loop(_sockets[ETHER_SOCKET], pdu, link_addr, len_addr); +PDU *PacketSender::recv_l2(PDU &pdu, struct sockaddr *link_addr, + uint32_t len_addr, const NetworkInterface &iface) { + int sock = get_ether_socket(iface); + return recv_match_loop(sock, pdu, link_addr, len_addr); } #endif // WIN32 diff --git a/src/radiotap.cpp b/src/radiotap.cpp index c149a7f..293be62 100644 --- a/src/radiotap.cpp +++ b/src/radiotap.cpp @@ -249,7 +249,7 @@ void RadioTap::send(PacketSender &sender) { sender.send_l2(*this, (struct sockaddr*)&addr, (uint32_t)sizeof(addr)); #else - sender.send_l2(*this, 0, 0); + sender.send_l2(*this, 0, 0, _iface); #endif }