2025-02-23 18:29:12 -05:00

135 lines
3.4 KiB
Rust

use smoltcp::phy::{self, Device, DeviceCapabilities, Medium};
use pcap_sys::Interface;
use sparse_actions::{adapter, error};
struct SocketInner {
lower: Interface,
}
pub struct RawSocket {
inner: SocketInner,
mtu: usize,
}
impl RawSocket {
pub fn new<T: adapter::BeaconAdapter>(
a_interface: &adapter::BeaconInterface,
promisc: bool,
port: u16,
) -> Result<Self, error::BeaconError<T::Error>> {
let name_raw = T::interface_name_from_interface(&a_interface);
let name = std::str::from_utf8(&name_raw)?;
let mut lower = Interface::new(name)?;
let mtu = a_interface.mtu as usize + if cfg!(unix) { 14 } else { 0 };
lower.set_promisc(promisc)?;
lower.set_buffer_size(mtu as i32)?;
lower.set_non_blocking(true)?;
lower.set_buffer_size(8192)?;
lower.set_timeout(10)?;
lower.activate()?;
if cfg!(target_os = "linux") {
lower.set_filter(&format!("arp or (inbound and tcp port {port})"), true, None)?;
} else {
lower.set_filter(&format!("arp or tcp port {port}"), true, None)?;
}
Ok(Self {
inner: SocketInner { lower },
mtu,
})
}
pub fn get_ready_wait_callback(&self) -> pcap_sys::WaitHandle {
self.inner.lower.get_wait_ready_callback()
}
}
impl Device for RawSocket {
type RxToken<'a>
= RxToken
where
Self: 'a;
type TxToken<'a>
= TxToken<'a>
where
Self: 'a;
fn capabilities(&self) -> DeviceCapabilities {
let mut caps = DeviceCapabilities::default();
caps.max_transmission_unit = self.mtu;
caps.medium = Medium::Ethernet;
caps
}
fn receive(
&mut self,
_timestamp: smoltcp::time::Instant,
) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
match self.inner.lower.next_packet() {
Ok(p) => {
let rx = RxToken {
buffer: p.pkt().raw().to_vec(),
};
let tx = TxToken { inner: &self.inner };
Some((rx, tx))
}
Err(pcap_sys::error::Error::Io(e)) if e.kind() == std::io::ErrorKind::WouldBlock => {
None
}
Err(e) => {
panic!("{}", e);
}
}
}
fn transmit(&mut self, _timestamp: smoltcp::time::Instant) -> Option<Self::TxToken<'_>> {
Some(TxToken { inner: &self.inner })
}
}
pub struct TxToken<'a> {
inner: &'a SocketInner,
}
impl phy::TxToken for TxToken<'_> {
fn consume<R, F>(self, len: usize, f: F) -> R
where
F: FnOnce(&mut [u8]) -> R,
{
let mut buffer = vec![0; len];
let result = f(&mut buffer);
let packet = packets::EthernetPacket::from_raw(buffer);
match self.inner.lower.sendpacket(packet.pkt()) {
Ok(_) => {}
Err(pcap_sys::error::Error::Io(e)) if e.kind() == std::io::ErrorKind::WouldBlock => {
println!("Failed to send due to non blocking mode");
}
Err(err) => panic!("{}", err),
}
drop(packet);
result
}
}
pub struct RxToken {
buffer: Vec<u8>,
}
impl phy::RxToken for RxToken {
fn consume<R, F>(self, f: F) -> R
where
F: FnOnce(&[u8]) -> R,
{
f(&self.buffer[..])
}
}