use ipnetwork::Ipv4Network;
use std::sync::{Arc, OnceLock};
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::sync::Mutex;
static TUN: OnceLock<Arc<Mutex<TunDevice>>> = OnceLock::new();
pub fn tun() -> &'static Arc<Mutex<TunDevice>> {
TUN.get_or_init(|| {
let tun = TunDevice::start().expect("tun");
Arc::new(Mutex::new(tun))
})
}
const TUN_NETWORK_CIDR: &str = "10.0.0.0/24";
pub struct TunDevice {
dev: tun2::AsyncDevice,
}
impl TunDevice {
pub fn start() -> anyhow::Result<Self> {
let net: Ipv4Network = TUN_NETWORK_CIDR.parse()?;
let addr = net.nth(1).expect("addr");
let mut config = tun2::Configuration::default();
config.address(addr).netmask(net.mask()).up();
let dev = tun2::create_as_async(&config)?;
#[cfg(target_os = "windows")]
std::thread::sleep(std::time::Duration::from_millis(10000));
Ok(Self { dev })
}
pub async fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
let bytes_read = self.dev.read(buf).await?;
Ok(bytes_read)
}
pub async fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
self.dev.write_all(buf).await?;
Ok(buf.len())
}
}