From 8fefd54d9095e94c2af3fd245c0aeba5c93cf7ad Mon Sep 17 00:00:00 2001 From: Cara Salter Date: Sat, 22 Apr 2023 21:04:14 -0400 Subject: [PATCH] wip not sure what's not working, but initial work on the trait --- burrow/src/main.rs | 12 ++-- tun/src/lib.rs | 35 +++++++++++- tun/src/unix/linux/mod.rs | 112 ++++++++++++++++++++------------------ tun/src/unix/mod.rs | 8 +-- tun/src/unix/queue.rs | 18 +++--- 5 files changed, 112 insertions(+), 73 deletions(-) diff --git a/burrow/src/main.rs b/burrow/src/main.rs index 13c6ff1..ac98d8f 100644 --- a/burrow/src/main.rs +++ b/burrow/src/main.rs @@ -2,19 +2,17 @@ use std::{mem::MaybeUninit, net::Ipv4Addr}; use tokio::io::Result; use tun::TunInterface; -use tun_async::TunQueue; +use tun::TunQueue; async fn try_main() -> Result<()> { - let iface = TunInterface::new()?; - iface.set_ipv4_addr(Ipv4Addr::new(10, 0, 0, 2))?; - println!("{:?}", iface.index()?); - println!("{:?}", iface.ipv4_addr()?); + let iface = tun::create_interface(); + iface.set_ipv4(Ipv4Addr::new(10, 0, 0, 2))?; - let queue = TunQueue::from_queue(iface.into())?; + let queue = TunQueue::from(iface); loop { let mut buf = [MaybeUninit::::uninit(); 1500]; - let len = queue.try_recv(&mut buf).await?; + let len = queue.recv(&mut buf)?; println!("Received {len} bytes"); } } diff --git a/tun/src/lib.rs b/tun/src/lib.rs index 7e86059..2e2f038 100644 --- a/tun/src/lib.rs +++ b/tun/src/lib.rs @@ -6,4 +6,37 @@ mod imp; #[path = "unix/mod.rs"] pub(crate) mod imp; -pub use imp::{TunInterface, TunQueue}; +/** + * Standard platform-independent interface for a tunnel. + */ +pub trait TunInterface { + /** + * Sets the interface IP address. Accepts either IPv6 or IPv4 + */ + fn set_ip(&self, ip: IpAddr) -> Result<(), std::io::Error>; + + /** + * Sets the interface IP address to an IPv4 address. + * + * Used by [set_ip](TunInterface::set_ip) + */ + fn set_ipv4(&self, ip: Ipv4Addr) -> Result<(), std::io::Error>; + + fn get_ip(&self) -> Result; + + fn get_interface_name(&self) -> Result; + + fn into_raw_socket(self) -> socket2::Socket; +} + +#[cfg(target_os = "linux")] +pub fn create_interface() -> impl TunInterface { + PlatformTun::new().unwrap() +} + +use std::{ + net::{IpAddr, Ipv4Addr}, + sync::Mutex, +}; + +pub use imp::{PlatformTun, TunQueue}; diff --git a/tun/src/unix/linux/mod.rs b/tun/src/unix/linux/mod.rs index ffa80ff..26efd7f 100644 --- a/tun/src/unix/linux/mod.rs +++ b/tun/src/unix/linux/mod.rs @@ -4,23 +4,35 @@ use socket2::{Domain, SockAddr, Socket, Type}; use std::fs::OpenOptions; use std::io::Error; use std::mem; -use std::net::{Ipv4Addr, SocketAddrV4}; +use std::net::{IpAddr, Ipv4Addr, SocketAddrV4}; use std::os::fd::RawFd; use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd}; - +use std::ptr; +use std::sync::{Arc, Mutex}; use super::{ifname_to_string, string_to_ifname}; +use crate::TunInterface; mod sys; #[derive(Debug)] -pub struct TunInterface { +pub struct PlatformTun { pub(crate) socket: socket2::Socket, } -impl TunInterface { +impl PlatformTun { #[throws] - pub fn new() -> TunInterface { + pub fn index(&self) -> i32 { + let socket = Socket::new(Domain::IPV4, Type::DGRAM, None)?; + unsafe { + let mut iff: libc::ifreq = mem::zeroed(); + iff.ifr_name = string_to_ifname(&self.get_interface_name()?); + sys::if_get_index(socket.as_raw_fd(), &mut iff)?; + iff.ifr_ifru.ifru_ifindex + } + } + #[throws] + pub(crate) fn new() -> PlatformTun { let file = OpenOptions::new() .read(true) .write(true) @@ -35,53 +47,47 @@ impl TunInterface { unsafe { sys::tun_set_iff(file.as_raw_fd(), &iff)? }; let socket = unsafe { socket2::Socket::from_raw_fd(file.into_raw_fd()) }; - TunInterface { socket } - } - - #[throws] - pub fn name(&self) -> String { - let mut iff = unsafe { mem::zeroed() }; - unsafe { sys::tun_get_iff(self.socket.as_raw_fd(), &mut iff)? }; - ifname_to_string(iff.ifr_name) - } - - #[throws] - fn ifreq(&self) -> sys::ifreq { - let mut iff: sys::ifreq = unsafe { mem::zeroed() }; - iff.ifr_name = string_to_ifname(&self.name()?); - iff - } - - #[throws] - pub fn index(&self) -> i32 { - let mut iff = self.ifreq()?; - self.perform(|fd| unsafe { sys::if_get_index(fd, &mut iff) })?; - unsafe { iff.ifr_ifru.ifru_ifindex } - } - - #[throws] - pub fn set_ipv4_addr(&self, addr: Ipv4Addr) { - let addr = SockAddr::from(SocketAddrV4::new(addr, 0)); - - let mut iff = self.ifreq()?; - iff.ifr_ifru.ifru_addr = unsafe { *addr.as_ptr() }; - - self.perform(|fd| unsafe { sys::if_set_addr(fd, &iff) })?; - } - - #[throws] - pub fn ipv4_addr(&self) -> Ipv4Addr { - let mut iff = self.ifreq()?; - self.perform(|fd| unsafe { sys::if_get_addr(fd, &mut iff) })?; - - let addr = unsafe { &*(&iff.ifr_ifru.ifru_addr as *const _ as *const sys::sockaddr_in) }; - - Ipv4Addr::from(addr.sin_addr.s_addr) - } - - #[throws] - fn perform(&self, perform: impl FnOnce(RawFd) -> Result) -> R { - let socket = Socket::new(Domain::IPV4, Type::DGRAM, None)?; - perform(socket.as_raw_fd())? + PlatformTun { socket } + } +} + +impl TunInterface for PlatformTun { + #[throws] + fn get_interface_name(&self) -> String { + unsafe { + let mut iff = mem::zeroed(); + sys::tun_get_iff(self.socket.as_raw_fd(), &mut iff)?; + ifname_to_string(iff.ifr_name) + } + } + + #[throws] + fn set_ip(&self, addr: IpAddr) { + match addr { + IpAddr::V4(addr) => self.set_ipv4(addr)?, + _ => (), + } + } + + #[throws] + fn set_ipv4(&self, addr: Ipv4Addr) { + let socket = Socket::new(Domain::IPV4, Type::DGRAM, None)?; + let addr = SockAddr::from(SocketAddrV4::new(addr, 0)); + unsafe { + let mut iff: libc::ifreq = mem::zeroed(); + iff.ifr_name = string_to_ifname(&self.get_interface_name()?); + iff.ifr_ifru.ifru_addr = *addr.as_ptr(); + sys::if_set_addr(socket.as_raw_fd(), &iff)?; + } + } + + #[throws] + fn get_ip(&self) -> IpAddr { + let addr = self.socket.local_addr()?; + addr.as_socket().unwrap().ip() + } + + fn into_raw_socket(self) -> socket2::Socket { + self.socket } } diff --git a/tun/src/unix/mod.rs b/tun/src/unix/mod.rs index 7574d02..a4b4752 100644 --- a/tun/src/unix/mod.rs +++ b/tun/src/unix/mod.rs @@ -8,11 +8,11 @@ mod imp; #[path = "linux/mod.rs"] mod imp; - - -pub use imp::TunInterface; - +pub use crate::TunInterface; +pub use imp::PlatformTun; +use libc::IFNAMSIZ; pub use queue::TunQueue; +use std::ffi::CString; pub fn ifname_to_string(buf: [libc::c_char; libc::IFNAMSIZ]) -> String { // TODO: Switch to `CStr::from_bytes_until_nul` when stabilized diff --git a/tun/src/unix/queue.rs b/tun/src/unix/queue.rs index 1288a3b..02a6ac2 100644 --- a/tun/src/unix/queue.rs +++ b/tun/src/unix/queue.rs @@ -38,10 +38,10 @@ impl Write for TunQueue { } } -impl From for TunQueue { - fn from(interface: TunInterface) -> TunQueue { +impl TunQueue { + pub fn from(interface: T) -> TunQueue { TunQueue { - socket: interface.socket, + socket: interface.into_raw_socket(), } } } @@ -52,8 +52,10 @@ impl AsRawFd for TunQueue { } } -impl IntoRawFd for TunQueue { - fn into_raw_fd(self) -> RawFd { - self.socket.into_raw_fd() - } -} +//TODO: error[E0507]: cannot move out of `*self.socket` which is behind a mutable reference + +//impl IntoRawFd for TunQueue { +// fn into_raw_fd(self) -> RawFd { +// self.socket.into_raw_fd() +// } +//}