From e4ad659cda38db0311c87082384bf33f19aa771b Mon Sep 17 00:00:00 2001 From: Vasily Evseenko Date: Tue, 19 Mar 2024 14:45:51 +0300 Subject: [PATCH] Use raw sockets for injection instead of pcap --- Makefile | 4 +- src/tx.cpp | 118 +++++++++++++++++++++++++++++++++-------------------- src/tx.hpp | 10 ++--- 3 files changed, 80 insertions(+), 52 deletions(-) diff --git a/Makefile b/Makefile index 0382e7af..9c64f592 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ DOCKER_SRC_IMAGE ?= "p2ptech/cross-build:2023-02-21-raspios-bullseye-armhf-lite" export VERSION COMMIT SOURCE_DATE_EPOCH -_LDFLAGS := $(LDFLAGS) -lrt -lpcap -lsodium +_LDFLAGS := $(LDFLAGS) -lrt -lsodium _CFLAGS := $(CFLAGS) -Wall -O2 -DWFB_VERSION='"$(VERSION)-$(shell /bin/bash -c '_tmp=$(COMMIT); echo $${_tmp::8}')"' all: all_bin gs.key test @@ -29,7 +29,7 @@ src/%.o: src/%.cpp src/*.hpp src/*.h $(CXX) $(_CFLAGS) -std=gnu++11 -c -o $@ $< wfb_rx: src/rx.o src/radiotap.o src/fec.o src/wifibroadcast.o - $(CXX) -o $@ $^ $(_LDFLAGS) + $(CXX) -o $@ $^ $(_LDFLAGS) -lpcap wfb_tx: src/tx.o src/fec.o src/wifibroadcast.o $(CXX) -o $@ $^ $(_LDFLAGS) diff --git a/src/tx.cpp b/src/tx.cpp index fd7653f6..b2febc06 100644 --- a/src/tx.cpp +++ b/src/tx.cpp @@ -25,10 +25,12 @@ #include #include #include -#include #include #include #include +#include +#include +#include #include #include @@ -122,89 +124,115 @@ void Transmitter::make_session_key(void) } } - -PcapTransmitter::PcapTransmitter(int k, int n, const string &keypair, uint64_t epoch, uint32_t channel_id, const vector &wlans) : \ +RawSocketTransmitter::RawSocketTransmitter(int k, int n, const string &keypair, uint64_t epoch, uint32_t channel_id, const vector &wlans) : \ Transmitter(k, n, keypair, epoch, channel_id), channel_id(channel_id), current_output(0), ieee80211_seq(0) { - char errbuf[PCAP_ERRBUF_SIZE]; for(auto it=wlans.begin(); it!=wlans.end(); it++) { - pcap_t *p = pcap_create(it->c_str(), errbuf); - if (p == NULL){ - throw runtime_error(string_format("Unable to open interface %s in pcap: %s", it->c_str(), errbuf)); + int fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); + if (fd < 0) + { + throw runtime_error(string_format("Unable to open PF_PACKET socket: %s", strerror(errno))); + } + + struct ifreq ifr; + memset(&ifr, '\0', sizeof(ifr)); + strncpy(ifr.ifr_name, it->c_str(), sizeof(ifr.ifr_name) - 1); + + if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0) + { + close(fd); + throw runtime_error(string_format("Unable to get interface index for %s", it->c_str())); + } + + struct sockaddr_ll sll; + memset(&sll, '\0', sizeof(sll)); + sll.sll_family = AF_PACKET; + sll.sll_ifindex = ifr.ifr_ifindex; + sll.sll_protocol = htons(ETH_P_ALL); + + if (bind(fd, (struct sockaddr *) &sll, sizeof(sll)) < 0) + { + close(fd); + throw runtime_error(string_format("Unable to bind to %s", it->c_str())); } - if (pcap_set_snaplen(p, 4096) !=0) throw runtime_error("set_snaplen failed"); - if (pcap_set_promisc(p, 1) != 0) throw runtime_error("set_promisc failed"); - //if (pcap_set_rfmon(p, 1) !=0) throw runtime_error("set_rfmon failed"); - if (pcap_set_timeout(p, -1) !=0) throw runtime_error("set_timeout failed"); - //if (pcap_set_buffer_size(p, 2048) !=0) throw runtime_error("set_buffer_size failed"); - if (pcap_set_immediate_mode(p, 1) != 0) throw runtime_error(string_format("pcap_set_immediate_mode failed: %s", pcap_geterr(p))); - if (pcap_activate(p) !=0) throw runtime_error(string_format("pcap_activate failed: %s", pcap_geterr(p))); - //if (pcap_setnonblock(p, 1, errbuf) != 0) throw runtime_error(string_format("set_nonblock failed: %s", errbuf)); - - ppcap.push_back(p); + + sockfds.push_back(fd); } } - -void PcapTransmitter::inject_packet(const uint8_t *buf, size_t size) +void RawSocketTransmitter::inject_packet(const uint8_t *buf, size_t size) { - uint8_t txbuf[MAX_PACKET_SIZE]; - uint8_t *p = txbuf; - assert(size <= MAX_FORWARDER_PACKET_SIZE); - // radiotap header - memcpy(p, radiotap_header, sizeof(radiotap_header)); - p += sizeof(radiotap_header); - - // ieee80211 header - memcpy(p, ieee80211_header, sizeof(ieee80211_header)); + uint8_t ieee_hdr[sizeof(ieee80211_header)]; + memcpy(ieee_hdr, ieee80211_header, sizeof(ieee80211_header)); // channel_id uint32_t channel_id_be = htobe32(channel_id); - memcpy(p + SRC_MAC_THIRD_BYTE, &channel_id_be, sizeof(uint32_t)); - memcpy(p + DST_MAC_THIRD_BYTE, &channel_id_be, sizeof(uint32_t)); + memcpy(ieee_hdr + SRC_MAC_THIRD_BYTE, &channel_id_be, sizeof(uint32_t)); + memcpy(ieee_hdr + DST_MAC_THIRD_BYTE, &channel_id_be, sizeof(uint32_t)); // sequence number - p[FRAME_SEQ_LB] = ieee80211_seq & 0xff; - p[FRAME_SEQ_HB] = (ieee80211_seq >> 8) & 0xff; + ieee_hdr[FRAME_SEQ_LB] = ieee80211_seq & 0xff; + ieee_hdr[FRAME_SEQ_HB] = (ieee80211_seq >> 8) & 0xff; ieee80211_seq += 16; - p += sizeof(ieee80211_header); - // FEC data - memcpy(p, buf, size); - p += size; + struct iovec iov[3] = \ + { + // radiotap header + { .iov_base = (void*)radiotap_header, + .iov_len = sizeof(radiotap_header) + }, + // ieee80211 header + { .iov_base = (void*)ieee_hdr, + .iov_len = sizeof(ieee_hdr) + }, + // FEC encoded data + { .iov_base = (void*)buf, + .iov_len = size + } + }; + + struct msghdr msghdr = \ + { .msg_name = NULL, + .msg_namelen = 0, + .msg_iov = iov, + .msg_iovlen = 3, + .msg_control = NULL, + .msg_controllen = 0, + .msg_flags = 0}; if (current_output >= 0) { // Normal mode - if (pcap_inject(ppcap[current_output], txbuf, p - txbuf) != p - txbuf) + if (sendmsg(sockfds[current_output], &msghdr, 0) < 0) { - throw runtime_error(string_format("Unable to inject packet")); + throw runtime_error(string_format("Unable to inject packet: %s", strerror(errno))); } } else { // Mirror mode - transmit packet via all cards // Use only for different frequency channels - for(auto it=ppcap.begin(); it != ppcap.end(); it++) + for(auto it=sockfds.begin(); it != sockfds.end(); it++) { - if (pcap_inject(*it, txbuf, p - txbuf) != p - txbuf) + if (sendmsg(*it, &msghdr, 0) < 0) { - throw runtime_error(string_format("Unable to inject packet")); + throw runtime_error(string_format("Unable to inject packet: %s", strerror(errno))); } } } } -PcapTransmitter::~PcapTransmitter() +RawSocketTransmitter::~RawSocketTransmitter() { - for(auto it=ppcap.begin(); it != ppcap.end(); it++){ - pcap_close(*it); + for(auto it=sockfds.begin(); it != sockfds.end(); it++) + { + close(*it); } } @@ -611,7 +639,7 @@ int main(int argc, char * const *argv) fprintf(stderr, "Using %zu ports from %d for wlan emulation\n", wlans.size(), debug_port); t = shared_ptr(new UdpTransmitter(k, n, keypair, "127.0.0.1", debug_port, epoch, channel_id)); } else { - t = shared_ptr(new PcapTransmitter(k, n, keypair, epoch, channel_id, wlans)); + t = shared_ptr(new RawSocketTransmitter(k, n, keypair, epoch, channel_id, wlans)); } data_source(t, rx_fd, poll_timeout, mirror); diff --git a/src/tx.hpp b/src/tx.hpp index 7ced3ed6..26b8bc2e 100644 --- a/src/tx.hpp +++ b/src/tx.hpp @@ -61,19 +61,18 @@ class Transmitter uint8_t session_key_packet[sizeof(wsession_hdr_t) + sizeof(wsession_data_t) + crypto_box_MACBYTES]; }; - -class PcapTransmitter : public Transmitter +class RawSocketTransmitter : public Transmitter { public: - PcapTransmitter(int k, int m, const std::string &keypair, uint64_t epoch, uint32_t channel_id, const std::vector &wlans); - virtual ~PcapTransmitter(); + RawSocketTransmitter(int k, int m, const std::string &keypair, uint64_t epoch, uint32_t channel_id, const std::vector &wlans); + virtual ~RawSocketTransmitter(); virtual void select_output(int idx) { current_output = idx; } private: virtual void inject_packet(const uint8_t *buf, size_t size); const uint32_t channel_id; int current_output; uint16_t ieee80211_seq; - std::vector ppcap; + std::vector sockfds; }; @@ -107,6 +106,7 @@ class UdpTransmitter : public Transmitter private: virtual void inject_packet(const uint8_t *buf, size_t size) { + assert(size <= MAX_FORWARDER_PACKET_SIZE); wrxfwd_t fwd_hdr = { .wlan_idx = (uint8_t)(rand() % 2) }; memset(fwd_hdr.antenna, 0xff, sizeof(fwd_hdr.antenna));