mod adapter;
mod dll;
mod session;
use std::io;
use std::ptr::NonNull;
pub use adapter::TunAdapter;
pub use dll::WintunLoggerCallback;
pub use session::TunSession;
use dll::WintunSession;
use windows_sys::Win32::Foundation::HANDLE;
use crate::{DeviceState, Interface};
pub(crate) struct TunImpl {
adapter: TunAdapter,
session: NonNull<WintunSession>,
ring_size: u32,
nonblocking: bool,
}
impl TunImpl {
const MAX_TUN_ID: u32 = 1000;
#[inline]
pub fn new() -> io::Result<Self> {
let mut tun_id = 0;
let mut adapter = loop {
let if_name = format!("Tun{}", tun_id);
let iface = Interface::new(&if_name).unwrap();
if TunAdapter::open(iface).is_err() {
match TunAdapter::create(iface) {
Ok(adapter) => break adapter,
Err(e) => {
if e.kind() != io::ErrorKind::AlreadyExists {
return Err(e);
}
}
}
}
tun_id += 1;
if tun_id > Self::MAX_TUN_ID {
return Err(io::Error::new(
io::ErrorKind::AlreadyExists,
"no unused adapter could be found",
));
}
};
let session = adapter.wintun.start_session(
unsafe { adapter.adapter.as_mut() },
TunSession::DEFAULT_RING_SIZE,
)?;
Ok(Self {
adapter,
session,
ring_size: TunSession::DEFAULT_RING_SIZE,
nonblocking: false,
})
}
#[inline]
pub fn new_named(if_name: Interface) -> io::Result<Self> {
let mut race_retry = false;
let mut adapter = loop {
match TunAdapter::open(if_name) {
Ok(adapter) => break adapter,
Err(e) if e.kind() == io::ErrorKind::NotFound => {
match TunAdapter::create(if_name) {
Ok(adapter) => break adapter,
Err(e) => {
if e.kind() != io::ErrorKind::AlreadyExists {
return Err(e);
}
}
}
}
Err(e) => return Err(e),
}
if race_retry {
return Err(io::Error::new(
io::ErrorKind::Other,
"TUN interface is both present and absent (race condition)",
));
}
race_retry = true;
};
let session = adapter.wintun.start_session(
unsafe { adapter.adapter.as_mut() },
TunSession::DEFAULT_RING_SIZE,
)?;
Ok(Self {
adapter,
session,
ring_size: TunSession::DEFAULT_RING_SIZE,
nonblocking: false,
})
}
#[inline]
pub fn name(&self) -> io::Result<Interface> {
Ok(self.adapter.name())
}
#[inline]
pub fn set_state(&mut self, state: DeviceState) -> io::Result<()> {
self.adapter.set_state(state)
}
#[inline]
pub fn mtu(&self) -> io::Result<usize> {
self.adapter.mtu()
}
#[inline]
pub fn set_nonblocking(&mut self, nonblocking: bool) -> io::Result<()> {
self.nonblocking = nonblocking;
Ok(())
}
#[inline]
pub fn nonblocking(&self) -> io::Result<bool> {
Ok(self.nonblocking)
}
#[inline]
pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
TunSession::send_impl(&self.adapter, self.session.as_ptr(), self.nonblocking, buf)
}
#[inline]
pub fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
TunSession::recv_impl(&self.adapter, self.session.as_ptr(), self.nonblocking, buf)
}
#[inline]
pub fn read_handle(&self) -> HANDLE {
TunSession::read_handle_impl(&self.adapter, self.session.as_ptr())
}
}
unsafe impl Send for TunImpl {}
unsafe impl Sync for TunImpl {}