From d7fed87ebb637a1a1e7fa115fbc75992e01e7d6e Mon Sep 17 00:00:00 2001 From: Matias Fontanini Date: Tue, 3 May 2016 19:34:46 -0700 Subject: [PATCH] Use recvfrom on BSD/OSX when capturing layer 3 packets Fixes #147 --- include/tins/packet_sender.h | 3 ++- src/packet_sender.cpp | 22 +++++++++++++++------- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/include/tins/packet_sender.h b/include/tins/packet_sender.h index 337beed..a5caa2c 100644 --- a/include/tins/packet_sender.h +++ b/include/tins/packet_sender.h @@ -399,7 +399,8 @@ private: PDU* recv_match_loop(const std::vector& sockets, PDU& pdu, struct sockaddr* link_addr, - uint32_t addrlen); + uint32_t addrlen, + bool is_layer_3); std::vector sockets_; #ifndef _WIN32 diff --git a/src/packet_sender.cpp b/src/packet_sender.cpp index ebc1744..0e2b34d 100644 --- a/src/packet_sender.cpp +++ b/src/packet_sender.cpp @@ -383,7 +383,7 @@ PDU* PacketSender::recv_l2(PDU& pdu, const NetworkInterface& iface) { int sock = get_ether_socket(iface); vector sockets(1, sock); - return recv_match_loop(sockets, pdu, link_addr, len_addr); + return recv_match_loop(sockets, pdu, link_addr, len_addr, false); } #endif // _WIN32 @@ -400,7 +400,7 @@ PDU* PacketSender::recv_l3(PDU& pdu, open_l3_socket(ICMP_SOCKET); sockets.push_back(sockets_[ICMP_SOCKET]); } - return recv_match_loop(sockets, pdu, link_addr, len_addr); + return recv_match_loop(sockets, pdu, link_addr, len_addr, true); } void PacketSender::send_l3(PDU& pdu, @@ -419,7 +419,8 @@ void PacketSender::send_l3(PDU& pdu, PDU* PacketSender::recv_match_loop(const vector& sockets, PDU& pdu, struct sockaddr* link_addr, - uint32_t addrlen) { + uint32_t addrlen, + bool is_layer_3) { #ifdef _WIN32 typedef int socket_len_type; typedef int recvfrom_ret_type; @@ -431,10 +432,13 @@ PDU* PacketSender::recv_match_loop(const vector& sockets, struct timeval timeout, end_time; int read; #if defined(BSD) || defined(__FreeBSD_kernel__) + bool is_bsd = true; // On* BSD, we need to allocate a buffer using the given size. - vector actual_buffer(buffer_size_); + const int buffer_size = is_layer_3 ? 2048 : buffer_size_; + vector actual_buffer(buffer_size); uint8_t* buffer = &actual_buffer[0]; #else + bool is_bsd = false; uint8_t buffer[2048]; const int buffer_size = 2048; #endif @@ -456,7 +460,9 @@ PDU* PacketSender::recv_match_loop(const vector& sockets, for (vector::const_iterator it = sockets.begin(); it != sockets.end(); ++it) { if (FD_ISSET(*it, &readfds)) { recvfrom_ret_type size; - #if defined(BSD) || defined(__FreeBSD_kernel__) + // Crappy way of only conditionally running this on BSD + layer2 + if (is_bsd && !is_layer_3) { + #if defined(BSD) || defined(__FreeBSD_kernel__) size = ::read(*it, buffer, buffer_size_); const uint8_t* ptr = buffer; // We might see more than one packet @@ -468,13 +474,15 @@ PDU* PacketSender::recv_match_loop(const vector& sockets, } ptr += BPF_WORDALIGN(bpf_header->bh_hdrlen + bpf_header->bh_caplen); } - #else + #endif // BSD + } + else { socket_len_type length = addrlen; size = ::recvfrom(*it, (char*)buffer, buffer_size, 0, link_addr, &length); if (pdu.matches_response(buffer, size)) { return Internals::pdu_from_flag(pdu.pdu_type(), buffer, size); } - #endif + } } } }