#[cfg(target_os = "linux")]
use crate::linux::interface::Interface;
#[cfg(target_os = "linux")]
use crate::linux::params::Params;
use crate::result::Result;
use async_std::fs::File;
use async_std::fs::OpenOptions;
use async_std::io::{BufReader, BufWriter};
#[cfg(target_family = "unix")]
use async_std::os::unix::io::{AsRawFd, RawFd};
use async_std::sync::Arc;
use mac_address::{mac_address_by_name, MacAddress};
use std::net::Ipv4Addr;
pub struct Tun {
file: File,
iface: Arc<Interface>,
}
impl Tun {
#[cfg(target_os = "linux")]
async fn alloc(params: Params, queues: usize) -> Result<(Vec<File>, Interface)> {
let mut files = Vec::with_capacity(queues);
for _ in 0..queues {
files.push(
OpenOptions::new()
.read(true)
.write(true)
.open("/dev/net/tun")
.await?,
);
}
let iface = Interface::new(
files.iter().map(|file| file.as_raw_fd()).collect(),
params.name.as_deref().unwrap_or_default(),
params.flags,
)?;
if let Some(mtu) = params.mtu {
iface.mtu(Some(mtu))?;
}
if let Some(owner) = params.owner {
iface.owner(owner)?;
}
if let Some(group) = params.group {
iface.group(group)?;
}
if let Some(address) = params.address {
iface.address(Some(address))?;
}
if let Some(netmask) = params.netmask {
iface.netmask(Some(netmask))?;
}
if let Some(destination) = params.destination {
iface.destination(Some(destination))?;
}
if let Some(broadcast) = params.broadcast {
iface.broadcast(Some(broadcast))?;
}
if let Some(mac) = params.mac {
iface.set_mac(mac)?;
}
if params.persist {
iface.persist()?;
}
if params.up {
iface.flags(Some(libc::IFF_UP as i16 | libc::IFF_RUNNING as i16))?;
}
Ok((files, iface))
}
#[cfg(not(any(target_os = "linux")))]
async fn alloc(params: Params) -> Result<Self> {
unimplemented!()
}
pub(crate) async fn new(params: Params) -> Result<Self> {
let (files, iface) = Self::alloc(params, 1).await?;
let file = files.into_iter().next().unwrap();
Ok(Self {
file,
iface: Arc::new(iface),
})
}
#[cfg(target_os = "linux")]
pub(crate) async fn new_mq(params: Params, queues: usize) -> Result<Vec<Self>> {
let (files, iface) = Self::alloc(params, queues).await?;
let mut tuns = Vec::with_capacity(queues);
let iface = Arc::new(iface);
for file in files.into_iter() {
tuns.push(Self {
file,
iface: iface.clone(),
})
}
Ok(tuns)
}
pub fn name(&self) -> &str {
self.iface.name()
}
pub fn mtu(&self) -> Result<i32> {
self.iface.mtu(None)
}
pub fn address(&self) -> Result<Ipv4Addr> {
self.iface.address(None)
}
pub fn destination(&self) -> Result<Ipv4Addr> {
self.iface.destination(None)
}
pub fn broadcast(&self) -> Result<Ipv4Addr> {
self.iface.broadcast(None)
}
pub fn netmask(&self) -> Result<Ipv4Addr> {
self.iface.netmask(None)
}
pub fn mac(&self) -> Result<Option<MacAddress>> {
Ok(mac_address_by_name(self.name())?)
}
pub fn flags(&self) -> Result<i16> {
self.iface.flags(None)
}
pub fn split(&self) -> (BufReader<&File>, BufWriter<&File>) {
(BufReader::new(&self.file), BufWriter::new(&self.file))
}
pub fn reader(&self) -> BufReader<&File> {
BufReader::new(&self.file)
}
pub fn writer(&self) -> BufWriter<&File> {
BufWriter::new(&self.file)
}
}
#[cfg(target_family = "unix")]
impl AsRawFd for Tun {
fn as_raw_fd(&self) -> RawFd {
self.file.as_raw_fd()
}
}