135 lines
3.4 KiB
Rust
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[..])
|
|
}
|
|
}
|