From 2f3ceab0364497a4a6cf866b505f74443ed6e3ae Mon Sep 17 00:00:00 2001 From: Mathias Hall-Andersen Date: Wed, 16 Oct 2019 13:40:40 +0200 Subject: Work on porting timer semantics and linux platform --- src/platform/linux/mod.rs | 181 +------------------------------------------- src/platform/linux/tun.rs | 188 ++++++++++++++++++++++++++++++++++++++++++++++ src/platform/linux/udp.rs | 0 src/platform/mod.rs | 18 +---- 4 files changed, 193 insertions(+), 194 deletions(-) create mode 100644 src/platform/linux/tun.rs create mode 100644 src/platform/linux/udp.rs (limited to 'src/platform') diff --git a/src/platform/linux/mod.rs b/src/platform/linux/mod.rs index ad2b8be..7a456ad 100644 --- a/src/platform/linux/mod.rs +++ b/src/platform/linux/mod.rs @@ -1,179 +1,4 @@ -use super::Tun; -use super::TunBind; +mod tun; +mod udp; -use super::super::wireguard::tun::*; - -use libc::*; - -use std::os::raw::c_short; -use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; - -const IFNAMSIZ: usize = 16; -const TUNSETIFF: u64 = 0x4004_54ca; - -const IFF_UP: i16 = 0x1; -const IFF_RUNNING: i16 = 0x40; - -const IFF_TUN: c_short = 0x0001; -const IFF_NO_PI: c_short = 0x1000; - -use std::error::Error; -use std::fmt; -use std::sync::atomic::AtomicUsize; -use std::sync::Arc; - -const CLONE_DEVICE_PATH: &'static [u8] = b"/dev/net/tun\0"; - -const TUN_MAGIC: u8 = b'T'; -const TUN_SET_IFF: u8 = 202; - -#[repr(C)] -struct Ifreq { - name: [u8; libc::IFNAMSIZ], - flags: c_short, - _pad: [u8; 64], -} - -pub struct PlatformTun {} - -pub struct PlatformTunReader { - fd: RawFd, -} - -pub struct PlatformTunWriter { - fd: RawFd, -} - -/* Listens for netlink messages - * announcing an MTU update for the interface - */ -#[derive(Clone)] -pub struct PlatformTunMTU { - value: Arc, -} - -#[derive(Debug)] -pub enum LinuxTunError { - InvalidTunDeviceName, - FailedToOpenCloneDevice, - SetIFFIoctlFailed, - Closed, // TODO -} - -impl fmt::Display for LinuxTunError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - unimplemented!() - } -} - -impl Error for LinuxTunError { - fn description(&self) -> &str { - unimplemented!() - } - - fn source(&self) -> Option<&(dyn Error + 'static)> { - unimplemented!() - } -} - -impl MTU for PlatformTunMTU { - fn mtu(&self) -> usize { - 1500 - } -} - -impl Reader for PlatformTunReader { - type Error = LinuxTunError; - - fn read(&self, buf: &mut [u8], offset: usize) -> Result { - debug_assert!( - offset < buf.len(), - "There is no space for the body of the TUN read" - ); - let n = unsafe { read(self.fd, buf[offset..].as_mut_ptr() as _, buf.len() - offset) }; - if n < 0 { - Err(LinuxTunError::Closed) - } else { - // conversion is safe - Ok(n as usize) - } - } -} - -impl Writer for PlatformTunWriter { - type Error = LinuxTunError; - - fn write(&self, src: &[u8]) -> Result<(), Self::Error> { - match unsafe { write(self.fd, src.as_ptr() as _, src.len() as _) } { - -1 => Err(LinuxTunError::Closed), - _ => Ok(()), - } - } -} - -impl Tun for PlatformTun { - type Error = LinuxTunError; - type Reader = PlatformTunReader; - type Writer = PlatformTunWriter; - type MTU = PlatformTunMTU; -} - -impl TunBind for PlatformTun { - fn create(name: &str) -> Result<(Vec, Self::Writer, Self::MTU), Self::Error> { - // construct request struct - let mut req = Ifreq { - name: [0u8; libc::IFNAMSIZ], - flags: (libc::IFF_TUN | libc::IFF_NO_PI) as c_short, - _pad: [0u8; 64], - }; - - // sanity check length of device name - let bs = name.as_bytes(); - if bs.len() > libc::IFNAMSIZ - 1 { - return Err(LinuxTunError::InvalidTunDeviceName); - } - req.name[..bs.len()].copy_from_slice(bs); - - // open clone device - let fd = match unsafe { open(CLONE_DEVICE_PATH.as_ptr() as _, O_RDWR) } { - -1 => return Err(LinuxTunError::FailedToOpenCloneDevice), - fd => fd, - }; - - // create TUN device - if unsafe { ioctl(fd, TUNSETIFF as _, &req) } < 0 { - return Err(LinuxTunError::SetIFFIoctlFailed); - } - - // create PlatformTunMTU instance - - Ok(( - vec![PlatformTunReader { fd }], - PlatformTunWriter { fd }, - PlatformTunMTU { - value: Arc::new(AtomicUsize::new(1500)), - }, - )) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use std::env; - - fn is_root() -> bool { - match env::var("USER") { - Ok(val) => val == "root", - Err(e) => false, - } - } - - #[test] - fn test_tun_create() { - if !is_root() { - return; - } - let (readers, writers, mtu) = PlatformTun::create("test").unwrap(); - } -} +pub use tun::PlatformTun; diff --git a/src/platform/linux/tun.rs b/src/platform/linux/tun.rs new file mode 100644 index 0000000..17390a1 --- /dev/null +++ b/src/platform/linux/tun.rs @@ -0,0 +1,188 @@ +use super::super::super::wireguard::tun::*; +use super::super::Tun; +use super::super::TunBind; + +use libc::*; + +use std::error::Error; +use std::fmt; +use std::os::raw::c_short; +use std::os::unix::io::RawFd; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::Arc; + +const IFNAMSIZ: usize = 16; +const TUNSETIFF: u64 = 0x4004_54ca; + +const IFF_UP: i16 = 0x1; +const IFF_RUNNING: i16 = 0x40; + +const IFF_TUN: c_short = 0x0001; +const IFF_NO_PI: c_short = 0x1000; + +const CLONE_DEVICE_PATH: &'static [u8] = b"/dev/net/tun\0"; + +const TUN_MAGIC: u8 = b'T'; +const TUN_SET_IFF: u8 = 202; + +#[repr(C)] +struct Ifreq { + name: [u8; libc::IFNAMSIZ], + flags: c_short, + _pad: [u8; 64], +} + +pub struct PlatformTun {} + +pub struct PlatformTunReader { + fd: RawFd, +} + +pub struct PlatformTunWriter { + fd: RawFd, +} + +/* Listens for netlink messages + * announcing an MTU update for the interface + */ +#[derive(Clone)] +pub struct PlatformTunMTU { + value: Arc, +} + +#[derive(Debug)] +pub enum LinuxTunError { + InvalidTunDeviceName, + FailedToOpenCloneDevice, + SetIFFIoctlFailed, + Closed, // TODO +} + +impl fmt::Display for LinuxTunError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + LinuxTunError::InvalidTunDeviceName => write!(f, "Invalid name (too long)"), + LinuxTunError::FailedToOpenCloneDevice => { + write!(f, "Failed to obtain fd for clone device") + } + LinuxTunError::SetIFFIoctlFailed => { + write!(f, "set_iff ioctl failed (insufficient permissions?)") + } + LinuxTunError::Closed => write!(f, "The tunnel has been closed"), + } + } +} + +impl Error for LinuxTunError { + fn description(&self) -> &str { + unimplemented!() + } + + fn source(&self) -> Option<&(dyn Error + 'static)> { + unimplemented!() + } +} + +impl MTU for PlatformTunMTU { + #[inline(always)] + fn mtu(&self) -> usize { + self.value.load(Ordering::Relaxed) + } +} + +impl Reader for PlatformTunReader { + type Error = LinuxTunError; + + fn read(&self, buf: &mut [u8], offset: usize) -> Result { + debug_assert!( + offset < buf.len(), + "There is no space for the body of the read" + ); + let n: isize = + unsafe { read(self.fd, buf[offset..].as_mut_ptr() as _, buf.len() - offset) }; + if n < 0 { + Err(LinuxTunError::Closed) + } else { + // conversion is safe + Ok(n as usize) + } + } +} + +impl Writer for PlatformTunWriter { + type Error = LinuxTunError; + + fn write(&self, src: &[u8]) -> Result<(), Self::Error> { + match unsafe { write(self.fd, src.as_ptr() as _, src.len() as _) } { + -1 => Err(LinuxTunError::Closed), + _ => Ok(()), + } + } +} + +impl Tun for PlatformTun { + type Error = LinuxTunError; + type Reader = PlatformTunReader; + type Writer = PlatformTunWriter; + type MTU = PlatformTunMTU; +} + +impl TunBind for PlatformTun { + fn create(name: &str) -> Result<(Vec, Self::Writer, Self::MTU), Self::Error> { + // construct request struct + let mut req = Ifreq { + name: [0u8; libc::IFNAMSIZ], + flags: (libc::IFF_TUN | libc::IFF_NO_PI) as c_short, + _pad: [0u8; 64], + }; + + // sanity check length of device name + let bs = name.as_bytes(); + if bs.len() > libc::IFNAMSIZ - 1 { + return Err(LinuxTunError::InvalidTunDeviceName); + } + req.name[..bs.len()].copy_from_slice(bs); + + // open clone device + let fd: RawFd = match unsafe { open(CLONE_DEVICE_PATH.as_ptr() as _, O_RDWR) } { + -1 => return Err(LinuxTunError::FailedToOpenCloneDevice), + fd => fd, + }; + assert!(fd >= 0); + + // create TUN device + if unsafe { ioctl(fd, TUNSETIFF as _, &req) } < 0 { + return Err(LinuxTunError::SetIFFIoctlFailed); + } + + // create PlatformTunMTU instance + Ok(( + vec![PlatformTunReader { fd }], // TODO: enable multi-queue for Linux + PlatformTunWriter { fd }, + PlatformTunMTU { + value: Arc::new(AtomicUsize::new(1500)), + }, + )) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use std::env; + + fn is_root() -> bool { + match env::var("USER") { + Ok(val) => val == "root", + Err(e) => false, + } + } + + #[test] + fn test_tun_create() { + if !is_root() { + return; + } + let (readers, writers, mtu) = PlatformTun::create("test").unwrap(); + } +} diff --git a/src/platform/linux/udp.rs b/src/platform/linux/udp.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/platform/mod.rs b/src/platform/mod.rs index e83384c..de33714 100644 --- a/src/platform/mod.rs +++ b/src/platform/mod.rs @@ -9,26 +9,12 @@ mod linux; #[cfg(target_os = "linux")] pub use linux::PlatformTun; -/* Syntax is nasty here, due to open issue: - * https://github.com/rust-lang/rust/issues/38078 - */ -pub trait UDPBind { +pub trait UDPBind: Bind { type Closer; - type Error: Error; - type Bind: Bind; /// Bind to a new port, returning the reader/writer and /// an associated instance of the Closer type, which closes the UDP socket upon "drop". - fn bind( - port: u16, - ) -> Result< - ( - <::Bind as Bind>::Reader, - <::Bind as Bind>::Writer, - Self::Closer, - ), - Self::Error, - >; + fn bind(port: u16) -> Result<(Self::Reader, Self::Writer, Self::Closer), Self::Error>; } pub trait TunBind: Tun { -- cgit v1.2.3-59-g8ed1b