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