mirror of https://git.zx2c4.com/wireguard-rs
36 changed files with 293 additions and 52 deletions
@ -0,0 +1,179 @@
|
||||
use super::Tun; |
||||
use super::TunBind; |
||||
|
||||
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<AtomicUsize>, |
||||
} |
||||
|
||||
#[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<usize, Self::Error> { |
||||
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::Reader>, 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(); |
||||
} |
||||
} |
||||
@ -0,0 +1,36 @@
|
||||
use std::error::Error; |
||||
|
||||
use super::wireguard::bind::Bind; |
||||
use super::wireguard::tun::Tun; |
||||
|
||||
#[cfg(target_os = "linux")] |
||||
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 { |
||||
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< |
||||
( |
||||
<<Self as UDPBind>::Bind as Bind>::Reader, |
||||
<<Self as UDPBind>::Bind as Bind>::Writer, |
||||
Self::Closer, |
||||
), |
||||
Self::Error, |
||||
>; |
||||
} |
||||
|
||||
pub trait TunBind: Tun { |
||||
fn create(name: &str) -> Result<(Vec<Self::Reader>, Self::Writer, Self::MTU), Self::Error>; |
||||
} |
||||
@ -0,0 +1,23 @@
|
||||
mod wireguard; |
||||
// mod config;
|
||||
mod constants; |
||||
mod timers; |
||||
|
||||
mod handshake; |
||||
mod router; |
||||
mod types; |
||||
|
||||
#[cfg(test)] |
||||
mod tests; |
||||
|
||||
/// The WireGuard sub-module contains a pure, configurable implementation of WireGuard.
|
||||
/// The implementation is generic over:
|
||||
///
|
||||
/// - TUN type, specifying how packets are received on the interface side: a reader/writer and MTU reporting interface.
|
||||
/// - Bind type, specifying how WireGuard messages are sent/received from the internet and what constitutes an "endpoint"
|
||||
|
||||
pub use wireguard::{Wireguard, Peer}; |
||||
|
||||
pub use types::bind; |
||||
pub use types::tun; |
||||
pub use types::Endpoint; |
||||
@ -1,8 +1,6 @@
|
||||
use std::error::Error; |
||||
use std::fmt; |
||||
|
||||
use super::super::types::Endpoint; |
||||
|
||||
pub trait Opaque: Send + Sync + 'static {} |
||||
|
||||
impl<T> Opaque for T where T: Send + Sync + 'static {} |
||||
@ -1,6 +1,6 @@
|
||||
use crate::types::tun::Tun; |
||||
use crate::types::{bind, dummy, tun}; |
||||
use crate::wireguard::Wireguard; |
||||
use super::types::tun::Tun; |
||||
use super::types::{bind, dummy, tun}; |
||||
use super::wireguard::Wireguard; |
||||
|
||||
use std::thread; |
||||
use std::time::Duration; |
||||
Loading…
Reference in new issue