async_tun/
tun.rs

1#[cfg(target_os = "linux")]
2use crate::linux::interface::Interface;
3#[cfg(target_os = "linux")]
4use crate::linux::params::Params;
5use crate::result::Result;
6use async_std::fs::File;
7use async_std::fs::OpenOptions;
8use async_std::io::{BufReader, BufWriter};
9#[cfg(target_family = "unix")]
10use async_std::os::unix::io::{AsRawFd, RawFd};
11use async_std::sync::Arc;
12use mac_address::{mac_address_by_name, MacAddress};
13use std::net::Ipv4Addr;
14
15/// Represents a Tun/Tap device. Use [`TunBuilder`](struct.TunBuilder.html) to create a new instance of [`Tun`](struct.Tun.html).
16pub struct Tun {
17    file: File,
18    iface: Arc<Interface>,
19}
20
21impl Tun {
22    #[cfg(target_os = "linux")]
23    async fn alloc(params: Params, queues: usize) -> Result<(Vec<File>, Interface)> {
24        let mut files = Vec::with_capacity(queues);
25        for _ in 0..queues {
26            files.push(
27                OpenOptions::new()
28                    .read(true)
29                    .write(true)
30                    .open("/dev/net/tun")
31                    .await?,
32            );
33        }
34        let iface = Interface::new(
35            files.iter().map(|file| file.as_raw_fd()).collect(),
36            params.name.as_deref().unwrap_or_default(),
37            params.flags,
38        )?;
39        if let Some(mtu) = params.mtu {
40            iface.mtu(Some(mtu))?;
41        }
42        if let Some(owner) = params.owner {
43            iface.owner(owner)?;
44        }
45        if let Some(group) = params.group {
46            iface.group(group)?;
47        }
48        if let Some(address) = params.address {
49            iface.address(Some(address))?;
50        }
51        if let Some(netmask) = params.netmask {
52            iface.netmask(Some(netmask))?;
53        }
54        if let Some(destination) = params.destination {
55            iface.destination(Some(destination))?;
56        }
57        if let Some(broadcast) = params.broadcast {
58            iface.broadcast(Some(broadcast))?;
59        }
60        if let Some(mac) = params.mac {
61            iface.set_mac(mac)?;
62        }
63        if params.persist {
64            iface.persist()?;
65        }
66        if params.up {
67            iface.flags(Some(libc::IFF_UP as i16 | libc::IFF_RUNNING as i16))?;
68        }
69        Ok((files, iface))
70    }
71
72    #[cfg(not(any(target_os = "linux")))]
73    async fn alloc(params: Params) -> Result<Self> {
74        unimplemented!()
75    }
76
77    /// Creates a new instance of Tun/Tap device.
78    pub(crate) async fn new(params: Params) -> Result<Self> {
79        let (files, iface) = Self::alloc(params, 1).await?;
80        let file = files.into_iter().next().unwrap();
81        Ok(Self {
82            file,
83            iface: Arc::new(iface),
84        })
85    }
86
87    /// Creates a new instance of Tun/Tap device.
88    #[cfg(target_os = "linux")]
89    pub(crate) async fn new_mq(params: Params, queues: usize) -> Result<Vec<Self>> {
90        let (files, iface) = Self::alloc(params, queues).await?;
91        let mut tuns = Vec::with_capacity(queues);
92        let iface = Arc::new(iface);
93        for file in files.into_iter() {
94            tuns.push(Self {
95                file,
96                iface: iface.clone(),
97            })
98        }
99        Ok(tuns)
100    }
101
102    /// Returns the name of Tun/Tap device.
103    pub fn name(&self) -> &str {
104        self.iface.name()
105    }
106
107    /// Returns the value of MTU.
108    pub fn mtu(&self) -> Result<i32> {
109        self.iface.mtu(None)
110    }
111
112    /// Returns the IPv4 address of MTU.
113    pub fn address(&self) -> Result<Ipv4Addr> {
114        self.iface.address(None)
115    }
116
117    /// Returns the IPv4 destination address of MTU.
118    pub fn destination(&self) -> Result<Ipv4Addr> {
119        self.iface.destination(None)
120    }
121
122    /// Returns the IPv4 broadcast address of MTU.
123    pub fn broadcast(&self) -> Result<Ipv4Addr> {
124        self.iface.broadcast(None)
125    }
126
127    /// Returns the IPv4 netmask address of MTU.
128    pub fn netmask(&self) -> Result<Ipv4Addr> {
129        self.iface.netmask(None)
130    }
131
132    /// Returns to Ethernet MAC address.
133    pub fn mac(&self) -> Result<Option<MacAddress>> {
134        Ok(mac_address_by_name(self.name())?)
135    }
136
137    /// Returns the flags of MTU.
138    pub fn flags(&self) -> Result<i16> {
139        self.iface.flags(None)
140    }
141
142    /// Splits self to reader and writer pairs.
143    pub fn split(&self) -> (BufReader<&File>, BufWriter<&File>) {
144        (BufReader::new(&self.file), BufWriter::new(&self.file))
145    }
146
147    /// Returns a reader to read from tun.
148    pub fn reader(&self) -> BufReader<&File> {
149        BufReader::new(&self.file)
150    }
151
152    /// Returns a writer to write to tun.
153    pub fn writer(&self) -> BufWriter<&File> {
154        BufWriter::new(&self.file)
155    }
156}
157
158#[cfg(target_family = "unix")]
159impl AsRawFd for Tun {
160    fn as_raw_fd(&self) -> RawFd {
161        self.file.as_raw_fd()
162    }
163}