mirror of
https://github.com/edera-dev/krata.git
synced 2025-08-04 05:31:32 +00:00
203 lines
5.0 KiB
Rust
203 lines
5.0 KiB
Rust
![]() |
use futures::ready;
|
||
|
use std::os::unix::io::{AsRawFd, RawFd};
|
||
|
use std::pin::Pin;
|
||
|
use std::task::{Context, Poll};
|
||
|
use std::{io, mem};
|
||
|
|
||
|
use anyhow::Result;
|
||
|
use tokio::io::unix::AsyncFd;
|
||
|
use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
|
||
|
|
||
|
const SIOCGIFINDEX: libc::c_ulong = 0x8933;
|
||
|
|
||
|
#[derive(Debug)]
|
||
|
pub struct RawSocket {
|
||
|
protocol: libc::c_short,
|
||
|
lower: libc::c_int,
|
||
|
ifreq: Ifreq,
|
||
|
}
|
||
|
|
||
|
impl AsRawFd for RawSocket {
|
||
|
fn as_raw_fd(&self) -> RawFd {
|
||
|
self.lower
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl RawSocket {
|
||
|
pub fn new(name: &str) -> io::Result<RawSocket> {
|
||
|
let protocol: libc::c_short = 0x0003;
|
||
|
let lower = unsafe {
|
||
|
let lower = libc::socket(
|
||
|
libc::AF_PACKET,
|
||
|
libc::SOCK_RAW | libc::SOCK_NONBLOCK,
|
||
|
protocol.to_be() as i32,
|
||
|
);
|
||
|
if lower == -1 {
|
||
|
return Err(io::Error::last_os_error());
|
||
|
}
|
||
|
lower
|
||
|
};
|
||
|
|
||
|
Ok(RawSocket {
|
||
|
protocol,
|
||
|
lower,
|
||
|
ifreq: ifreq_for(name),
|
||
|
})
|
||
|
}
|
||
|
|
||
|
pub fn bind_interface(&mut self) -> io::Result<()> {
|
||
|
let sockaddr = libc::sockaddr_ll {
|
||
|
sll_family: libc::AF_PACKET as u16,
|
||
|
sll_protocol: self.protocol.to_be() as u16,
|
||
|
sll_ifindex: ifreq_ioctl(self.lower, &mut self.ifreq, SIOCGIFINDEX)?,
|
||
|
sll_hatype: 1,
|
||
|
sll_pkttype: 0,
|
||
|
sll_halen: 6,
|
||
|
sll_addr: [0; 8],
|
||
|
};
|
||
|
|
||
|
unsafe {
|
||
|
let res = libc::bind(
|
||
|
self.lower,
|
||
|
&sockaddr as *const libc::sockaddr_ll as *const libc::sockaddr,
|
||
|
mem::size_of::<libc::sockaddr_ll>() as libc::socklen_t,
|
||
|
);
|
||
|
if res == -1 {
|
||
|
return Err(io::Error::last_os_error());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Ok(())
|
||
|
}
|
||
|
|
||
|
pub fn recv(&self, buffer: &mut [u8]) -> io::Result<usize> {
|
||
|
unsafe {
|
||
|
let len = libc::recv(
|
||
|
self.lower,
|
||
|
buffer.as_mut_ptr() as *mut libc::c_void,
|
||
|
buffer.len(),
|
||
|
0,
|
||
|
);
|
||
|
if len == -1 {
|
||
|
return Err(io::Error::last_os_error());
|
||
|
}
|
||
|
Ok(len as usize)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pub fn send(&self, buffer: &[u8]) -> io::Result<usize> {
|
||
|
unsafe {
|
||
|
let len = libc::send(
|
||
|
self.lower,
|
||
|
buffer.as_ptr() as *const libc::c_void,
|
||
|
buffer.len(),
|
||
|
0,
|
||
|
);
|
||
|
if len == -1 {
|
||
|
return Err(io::Error::last_os_error());
|
||
|
}
|
||
|
Ok(len as usize)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl Drop for RawSocket {
|
||
|
fn drop(&mut self) {
|
||
|
unsafe {
|
||
|
libc::close(self.lower);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#[repr(C)]
|
||
|
#[derive(Debug)]
|
||
|
struct Ifreq {
|
||
|
ifr_name: [libc::c_char; libc::IF_NAMESIZE],
|
||
|
ifr_data: libc::c_int, /* ifr_ifindex or ifr_mtu */
|
||
|
}
|
||
|
|
||
|
fn ifreq_for(name: &str) -> Ifreq {
|
||
|
let mut ifreq = Ifreq {
|
||
|
ifr_name: [0; libc::IF_NAMESIZE],
|
||
|
ifr_data: 0,
|
||
|
};
|
||
|
for (i, byte) in name.as_bytes().iter().enumerate() {
|
||
|
ifreq.ifr_name[i] = *byte as libc::c_char
|
||
|
}
|
||
|
ifreq
|
||
|
}
|
||
|
|
||
|
fn ifreq_ioctl(
|
||
|
lower: libc::c_int,
|
||
|
ifreq: &mut Ifreq,
|
||
|
cmd: libc::c_ulong,
|
||
|
) -> io::Result<libc::c_int> {
|
||
|
unsafe {
|
||
|
let res = libc::ioctl(lower, cmd as _, ifreq as *mut Ifreq);
|
||
|
if res == -1 {
|
||
|
return Err(io::Error::last_os_error());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Ok(ifreq.ifr_data)
|
||
|
}
|
||
|
|
||
|
pub struct AsyncRawSocket {
|
||
|
inner: AsyncFd<RawSocket>,
|
||
|
}
|
||
|
|
||
|
impl AsyncRawSocket {
|
||
|
pub fn new(socket: RawSocket) -> Result<Self> {
|
||
|
Ok(Self {
|
||
|
inner: AsyncFd::new(socket)?,
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl AsyncRead for AsyncRawSocket {
|
||
|
fn poll_read(
|
||
|
self: Pin<&mut Self>,
|
||
|
cx: &mut Context<'_>,
|
||
|
buf: &mut ReadBuf<'_>,
|
||
|
) -> Poll<io::Result<()>> {
|
||
|
loop {
|
||
|
let mut guard = ready!(self.inner.poll_read_ready(cx))?;
|
||
|
|
||
|
let unfilled = buf.initialize_unfilled();
|
||
|
match guard.try_io(|inner| inner.get_ref().recv(unfilled)) {
|
||
|
Ok(Ok(len)) => {
|
||
|
buf.advance(len);
|
||
|
return Poll::Ready(Ok(()));
|
||
|
}
|
||
|
Ok(Err(err)) => return Poll::Ready(Err(err)),
|
||
|
Err(_would_block) => continue,
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl AsyncWrite for AsyncRawSocket {
|
||
|
fn poll_write(
|
||
|
self: Pin<&mut Self>,
|
||
|
cx: &mut Context<'_>,
|
||
|
buf: &[u8],
|
||
|
) -> Poll<io::Result<usize>> {
|
||
|
loop {
|
||
|
let mut guard = ready!(self.inner.poll_write_ready(cx))?;
|
||
|
|
||
|
match guard.try_io(|inner| inner.get_ref().send(buf)) {
|
||
|
Ok(result) => return Poll::Ready(result),
|
||
|
Err(_would_block) => continue,
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fn poll_flush(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<io::Result<()>> {
|
||
|
Poll::Ready(Ok(()))
|
||
|
}
|
||
|
|
||
|
fn poll_shutdown(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<io::Result<()>> {
|
||
|
Poll::Ready(Ok(()))
|
||
|
}
|
||
|
}
|