tap_windows/
lib.rs

1//! # tap-windows
2//! Library to interface with the tap-windows driver
3//! created by OpenVPN to manage tap interfaces.
4//! Look at the documentation for `Device` for a
5//! pretty simple example on how to use this library.
6#![cfg(windows)]
7
8/// Encode a string as a utf16 buffer
9fn encode_utf16(string: &str) -> Vec<u16> {
10    use std::iter::once;
11    string.encode_utf16().chain(once(0)).collect()
12}
13
14/// Decode a string from a utf16 buffer
15fn decode_utf16(string: &[u16]) -> String {
16    let end = string.iter().position(|b| *b == 0).unwrap_or(string.len());
17    String::from_utf16_lossy(&string[..end])
18}
19
20mod ffi;
21mod iface;
22mod netsh;
23
24use std::{io, net, time};
25use winapi::shared::ifdef::NET_LUID;
26use winapi::um::winioctl::*;
27use winapi::um::winnt::HANDLE;
28
29/// A tap-windows device handle, it offers facilities to:
30/// - create, open and delete interfaces
31/// - write and read the current configuration
32/// - write and read packets from the device
33/// Example
34/// ```no_run
35/// use tap_windows::Device;
36/// use std::io::Read;
37///
38/// const MY_INTERFACE: &str = "My Interface";
39///
40/// // Try to open the device
41/// let mut dev = Device::open(MY_INTERFACE)
42///     .or_else(|_| -> std::io::Result<_> {
43///         // The device does not exists...
44///         // try creating a new one
45///         
46///         let dev = Device::create()?;
47///         dev.set_name(MY_INTERFACE)?;
48///     
49///         Ok(dev)
50///     })
51///     // Everything failed, just panic
52///     .expect("Failed to open device");
53///
54/// // Set the device ip
55/// dev.set_ip([192, 168, 60, 1], [255, 255, 255, 0])
56///     .expect("Failed to set device ip");
57///
58/// // Setup read buffer
59/// let mtu = dev.get_mtu().unwrap_or(1500);
60/// let mut buf = vec![0; mtu as usize];
61///
62/// // Read a single packet from the device
63/// let amt = dev.read(&mut buf)
64///     .expect("Failed to read packet");
65///
66/// // Print it
67/// println!("{:#?}", &buf[..amt]);
68/// ```
69pub struct Device {
70    luid: NET_LUID,
71    handle: HANDLE,
72}
73
74impl Device {
75    /// Creates a new tap-windows device
76    /// Example
77    /// ```no_run
78    /// use tap_windows::Device;
79    ///
80    /// let dev = Device::create()
81    ///     .expect("Failed to create device");
82    ///
83    /// println!("{:?}", dev.get_name());
84    /// ```
85    pub fn create() -> io::Result<Self> {
86        let luid = iface::create_interface()?;
87
88        // Even after retrieving the luid, we might need to wait
89        let start = time::Instant::now();
90        let handle = loop {
91            // If we surpassed 2 seconds just return
92            let now = time::Instant::now();
93            if now - start > time::Duration::from_secs(2) {
94                return Err(io::Error::new(
95                    io::ErrorKind::TimedOut,
96                    "Interface timed out",
97                ));
98            }
99
100            match iface::open_interface(&luid) {
101                Err(_) => {
102                    std::thread::yield_now();
103                    continue;
104                }
105                Ok(handle) => break handle,
106            };
107        };
108
109        Ok(Self { luid, handle })
110    }
111
112    /// Opens an existing tap-windows device by name
113    /// Example
114    /// ```no_run
115    /// use tap_windows::Device;
116    ///
117    /// let dev = Device::open("My Own Device")
118    ///     .expect("Failed to open device");
119    ///
120    /// println!("{:?}", dev.get_name());
121    /// ```
122    pub fn open(name: &str) -> io::Result<Self> {
123        let name = encode_utf16(name);
124
125        let luid = ffi::alias_to_luid(&name)?;
126        iface::check_interface(&luid)?;
127
128        let handle = iface::open_interface(&luid)?;
129
130        Ok(Self { luid, handle })
131    }
132
133    /// Deletes the interface before closing it.
134    /// By default interfaces are never deleted on Drop,
135    /// with this you can choose if you want deletion or not
136    /// Example
137    /// ```no_run
138    /// use tap_windows::Device;
139    ///
140    /// let dev = Device::create()
141    ///     .expect("Failed to create device");
142    ///
143    /// println!("{:?}", dev.get_name());
144    ///
145    /// // Perform a quick cleanup before exiting
146    /// dev.delete().expect("Failed to delete device");
147    /// ```
148    pub fn delete(self) -> io::Result<()> {
149        iface::delete_interface(&self.luid)?;
150
151        Ok(())
152    }
153
154    /// Sets the status of the interface to connected.
155    /// Equivalent to `.set_status(true)`
156    pub fn up(&self) -> io::Result<()> {
157        self.set_status(true)
158    }
159
160    /// Sets the status of the interface to disconnected.
161    /// Equivalent to `.set_status(false)`
162    pub fn down(&self) -> io::Result<()> {
163        self.set_status(false)
164    }
165
166    /// Retieve the mac of the interface
167    pub fn get_mac(&self) -> io::Result<[u8; 6]> {
168        let mut mac = [0; 6];
169
170        ffi::device_io_control(
171            self.handle,
172            CTL_CODE(FILE_DEVICE_UNKNOWN, 1, METHOD_BUFFERED, FILE_ANY_ACCESS),
173            &(),
174            &mut mac,
175        )
176        .map(|_| mac)
177    }
178
179    /// Retrieve the version of the driver
180    pub fn get_version(&self) -> io::Result<[u32; 3]> {
181        let mut version = [0; 3];
182
183        ffi::device_io_control(
184            self.handle,
185            CTL_CODE(FILE_DEVICE_UNKNOWN, 2, METHOD_BUFFERED, FILE_ANY_ACCESS),
186            &(),
187            &mut version,
188        )
189        .map(|_| version)
190    }
191
192    /// Retieve the mtu of the interface
193    pub fn get_mtu(&self) -> io::Result<u32> {
194        let mut mtu = 0;
195
196        ffi::device_io_control(
197            self.handle,
198            CTL_CODE(FILE_DEVICE_UNKNOWN, 3, METHOD_BUFFERED, FILE_ANY_ACCESS),
199            &(),
200            &mut mtu,
201        )
202        .map(|_| mtu)
203    }
204
205    /// Retrieve the name of the interface
206    pub fn get_name(&self) -> io::Result<String> {
207        ffi::luid_to_alias(&self.luid).map(|name| decode_utf16(&name))
208    }
209
210    /// Set the name of the interface
211    pub fn set_name(&self, newname: &str) -> io::Result<()> {
212        let name = self.get_name()?;
213        netsh::set_interface_name(&name, newname)
214    }
215
216    /// Set the ip of the interface
217    /// ```no_run
218    /// use tap_windows::Device;
219    ///
220    /// let dev = Device::create()
221    ///     .expect("Failed to create device");
222    ///
223    /// dev.set_ip([192, 168, 60, 1], [255, 255, 255, 0])
224    ///     .expect("Failed to set interface ip");
225    ///
226    /// println!("{:?}", dev.get_name());
227    /// ```
228    pub fn set_ip<A, B>(&self, address: A, mask: B) -> io::Result<()>
229    where
230        A: Into<net::Ipv4Addr>,
231        B: Into<net::Ipv4Addr>,
232    {
233        let name = self.get_name()?;
234        let address = address.into().to_string();
235        let mask = mask.into().to_string();
236
237        netsh::set_interface_ip(&name, &address, &mask)
238    }
239
240    /// Set the status of the interface, true for connected,
241    /// false for disconnected.
242    pub fn set_status(&self, status: bool) -> io::Result<()> {
243        let status: u32 = if status { 1 } else { 0 };
244
245        ffi::device_io_control(
246            self.handle,
247            CTL_CODE(FILE_DEVICE_UNKNOWN, 6, METHOD_BUFFERED, FILE_ANY_ACCESS),
248            &status,
249            &mut (),
250        )
251    }
252}
253
254impl io::Read for Device {
255    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
256        ffi::read_file(self.handle, buf).map(|res| res as _)
257    }
258}
259
260impl io::Write for Device {
261    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
262        ffi::write_file(self.handle, buf).map(|res| res as _)
263    }
264
265    fn flush(&mut self) -> io::Result<()> {
266        Ok(())
267    }
268}
269
270impl Drop for Device {
271    fn drop(&mut self) {
272        let _ = ffi::close_handle(self.handle);
273    }
274}