tun_tap/
lib.rs

1#![doc(
2    html_root_url = "https://docs.rs/tun-tap/0.1.4/tun-tap/",
3    test(attr(deny(warnings), allow(unused_variables)))
4)]
5#![deny(missing_docs)]
6
7//! A TUN/TAP bindings for Rust.
8//!
9//! This is a basic interface to create userspace virtual network adapter.
10//!
11//! For basic usage, create an [`Iface`](struct.Iface.html) object and call the
12//! [`send`](struct.Iface.html#method.send) and [`recv`](struct.Iface.html#method.recv) methods.
13//!
14//! You can also use [`Async`](async/struct.Async.html) if you want to integrate with tokio event
15//! loop. This is configurable by a feature (it is on by default).
16//!
17//! Creating the devices requires `CAP_NETADM` privileges (most commonly done by running as root).
18//!
19//! # Known issues
20//!
21//! * It is tested only on Linux and probably doesn't work anywhere else, even though other systems
22//!   have some TUN/TAP support. Reports that it works (or not) and pull request to add other
23//!   sustem's support are welcome.
24//! * The [`Async`](async/struct.Async.html) interface is very minimal and will require extention
25//!   for further use cases and better performance.
26//! * This doesn't support advanced usage patters, like reusing already created device or creating
27//!   persistent devices. Again, pull requests are welcome.
28//! * There are no automated tests. Any idea how to test this in a reasonable way?
29
30use std::ffi::CStr;
31use std::fs::{File, OpenOptions};
32use std::io::{Error, Read, Result, Write};
33use std::os::raw::{c_char, c_int};
34use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd};
35
36#[cfg(feature = "tokio")]
37pub mod async;
38
39extern "C" {
40    fn tuntap_setup(fd: c_int, name: *mut u8, mode: c_int, packet_info: c_int) -> c_int;
41}
42
43/// The mode in which open the virtual network adapter.
44#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
45pub enum Mode {
46    /// TUN mode
47    ///
48    /// The packets returned are on the IP layer (layer 3), prefixed with 4-byte header (2 bytes
49    /// are flags, 2 bytes are the protocol inside, eg one of
50    /// <https://en.wikipedia.org/wiki/EtherType#Examples>.
51    Tun = 1,
52    /// TAP mode
53    ///
54    /// The packets are on the transport layer (layer 2), and start with ethernet frame header.
55    Tap = 2,
56}
57
58/// The virtual interface.
59///
60/// This is the main structure of the crate, representing the actual virtual interface, either in
61/// TUN or TAP mode.
62#[derive(Debug)]
63pub struct Iface {
64    fd: File,
65    mode: Mode,
66    name: String,
67}
68
69impl Iface {
70    /// Creates a new virtual interface.
71    ///
72    /// # Parameters
73    ///
74    /// * `ifname`: The requested name of the virtual device. If left empty, the kernel will
75    ///   provide some reasonable, currently unused name. It also can contain `%d`, which will be
76    ///   replaced by a number to ensure the name is unused. Even if it isn't empty or doesn't
77    ///   contain `%d`, the actual name may be different (for example truncated to OS-dependent
78    ///   length). Use [`name`](#method.name) to find out the real name.
79    /// * `mode`: In which mode to create the device.
80    ///
81    /// # Errors
82    ///
83    /// This may fail for various OS-dependent reasons. However, two most common are:
84    ///
85    /// * The name is already taken.
86    /// * The process doesn't have the needed privileges (eg. `CAP_NETADM`).
87    ///
88    /// # Examples
89    ///
90    /// ```rust,no_run
91    /// # use tun_tap::*;
92    /// let iface = Iface::new("mytun", Mode::Tun).expect("Failed to create a TUN device");
93    /// let name = iface.name();
94    /// // Configure the device ‒ set IP address on it, bring it up.
95    /// let mut buffer = vec![0; 1504]; // MTU + 4 for the header
96    /// iface.recv(&mut buffer).unwrap();
97    /// ```
98    pub fn new(ifname: &str, mode: Mode) -> Result<Self> {
99        Iface::with_options(ifname, mode, true)
100    }
101    /// Creates a new virtual interface without the prepended packet info.
102    ///
103    /// # Parameters
104    ///
105    /// * `ifname`: The requested name of the virtual device. If left empty, the kernel will
106    ///   provide some reasonable, currently unused name. It also can contain `%d`, which will be
107    ///   replaced by a number to ensure the name is unused. Even if it isn't empty or doesn't
108    ///   contain `%d`, the actual name may be different (for example truncated to OS-dependent
109    ///   length). Use [`name`](#method.name) to find out the real name.
110    /// * `mode`: In which mode to create the device.
111    ///
112    /// # Errors
113    ///
114    /// This may fail for various OS-dependent reasons. However, two most common are:
115    ///
116    /// * The name is already taken.
117    /// * The process doesn't have the needed privileges (eg. `CAP_NETADM`).
118    ///
119    /// # Examples
120    ///
121    /// ```rust,no_run
122    /// # use tun_tap::*;
123    /// let iface = Iface::without_packet_info("mytap", Mode::Tap).expect("Failed to create a TAP device");
124    /// let name = iface.name();
125    /// // Configure the device ‒ set IP address on it, bring it up.
126    /// let mut buffer = vec![0; 1500]; // MTU
127    /// iface.recv(&mut buffer).unwrap();
128    /// ```
129    pub fn without_packet_info(ifname: &str, mode: Mode) -> Result<Self> {
130        Iface::with_options(ifname, mode, false)
131    }
132
133    fn with_options(ifname: &str, mode: Mode, packet_info: bool) -> Result<Self> {
134        let fd = OpenOptions::new()
135            .read(true)
136            .write(true)
137            .open("/dev/net/tun")?;
138        // The buffer is larger than needed, but who cares… it is large enough.
139        let mut name_buffer = Vec::new();
140        name_buffer.extend_from_slice(ifname.as_bytes());
141        name_buffer.extend_from_slice(&[0; 33]);
142        let name_ptr: *mut u8 = name_buffer.as_mut_ptr();
143        let result = unsafe { tuntap_setup(fd.as_raw_fd(), name_ptr, mode as c_int, if packet_info { 1 } else { 0 }) };
144        if result < 0 {
145            return Err(Error::last_os_error());
146        }
147        let name = unsafe {
148            CStr::from_ptr(name_ptr as *const c_char)
149                .to_string_lossy()
150                .into_owned()
151        };
152        Ok(Iface {
153            fd,
154            mode,
155            name,
156        })
157    }
158
159    /// Returns the mode of the adapter.
160    ///
161    /// It is always the same as the one passed to [`new`](#method.new).
162    pub fn mode(&self) -> Mode {
163        self.mode
164    }
165    /// Returns the real name of the adapter.
166    ///
167    /// Use this to find out what the real name of the adapter is. The parameter of
168    /// [`new`](#method.new) is more of a wish than hard requirement and the name of the created
169    /// device might be different. Therefore, always create the interface and then find out the
170    /// actual name by this method before proceeding.
171    pub fn name(&self) -> &str {
172        &self.name
173    }
174    /// Receives a packet from the interface.
175    ///
176    /// By default, blocks until a packet is sent into the virtual interface. At that point,
177    /// the content of the packet is copied into the provided buffer.
178    ///
179    /// If interface has been set to be non-blocking, this will fail with an error of kind
180    /// [`WouldBlock`](std::io::ErrorKind::WouldBlock) instead of blocking
181    /// if no packet is queued up.
182    ///
183    /// Make sure the buffer is large enough. It is MTU of the interface (usually 1500, unless
184    /// reconfigured) + 4 for the header in case that packet info is prepended, MTU + size of ethernet frame (38 bytes,
185    /// unless VLan tags are enabled). If the buffer isn't large enough, the packet gets truncated.
186    ///
187    /// # Result
188    ///
189    /// On successful receive, the number of bytes copied into the buffer is returned.
190    pub fn recv(&self, buf: &mut [u8]) -> Result<usize> {
191        (&self.fd).read(buf)
192    }
193    /// Sends a packet into the interface.
194    ///
195    /// Sends a packet through the interface. The buffer must be valid representation of a packet
196    /// (with appropriate headers).
197    ///
198    /// If interface has been set to be non-blocking, this will fail with an error of kind
199    /// [`WouldBlock`](std::io::ErrorKind::WouldBlock) instead of blocking
200    /// if interface is not ready.
201    ///
202    /// It is up to the caller to provide only packets that fit MTU.
203    ///
204    /// # Result
205    ///
206    /// On successful send, the number of bytes sent in the packet is returned. Under normal
207    /// circumstances, this should be the size of the packet passed.
208    ///
209    /// # Notes
210    ///
211    /// The TUN/TAP is a network adapter. Therefore, many errors are handled simply by dropping
212    /// packets. If you pass an invalid packet, it'll likely suceed in sending it, but will be
213    /// dropped somewhere in kernel due to failed validation. If you send packets too fast, they
214    /// are likely to get dropped too. If you send a packet for address that is not assigned to any
215    /// interface and not routed anywhere… you get the idea.
216    pub fn send(&self, buf: &[u8]) -> Result<usize> {
217        (&self.fd).write(buf)
218    }
219    /// Sets the interface to be non-blocking
220    ///
221    /// Note the behaviour of [`send`](#method.send) and [`recv`](#method.recv) will change if set.
222    ///
223    /// # Errors
224    ///
225    /// This fails with an error in case of low-level OS errors (they shouldn't usually happen).
226    ///
227    /// # Notes
228    /// If default features are excluded, include feature "libc" for this function to be available
229    #[cfg(feature = "libc")]
230    pub fn set_non_blocking(&self) -> Result<()> {
231        let fd = self.as_raw_fd();
232        let mut nonblock: c_int = 1;
233        let result = unsafe { libc::ioctl(fd, libc::FIONBIO, &mut nonblock) };
234        if result == -1 {
235            Err(Error::last_os_error())
236        } else {
237            Ok(())
238        }
239    }
240}
241
242impl AsRawFd for Iface {
243    fn as_raw_fd(&self) -> RawFd {
244        self.fd.as_raw_fd()
245    }
246}
247
248impl IntoRawFd for Iface {
249    fn into_raw_fd(self) -> RawFd {
250        self.fd.into_raw_fd()
251    }
252}