diff options
| author | Emīls Piņķis <emils@mullvad.net> | 2019-09-25 14:41:31 +0100 |
|---|---|---|
| committer | Emīls Piņķis <emils@mullvad.net> | 2019-09-25 18:28:37 +0100 |
| commit | 8a8f3fead0cb0ed86c7f399dcaf02c96a17bcdb9 (patch) | |
| tree | 524e7d6bcbee39a5e93a944247ce6b8dc1fcf80c | |
| parent | c92f52de79106bc2f82dabc9944107af64ada15c (diff) | |
| download | mullvadvpn-8a8f3fead0cb0ed86c7f399dcaf02c96a17bcdb9.tar.xz mullvadvpn-8a8f3fead0cb0ed86c7f399dcaf02c96a17bcdb9.zip | |
Duplicate tunnel fd on all platforms for wireguard-go
| -rw-r--r-- | Cargo.lock | 1 | ||||
| -rw-r--r-- | mullvad-jni/Cargo.toml | 1 | ||||
| -rw-r--r-- | mullvad-jni/src/vpn_service_tun_provider.rs | 46 | ||||
| -rw-r--r-- | talpid-core/src/tunnel/wireguard/mod.rs | 5 | ||||
| -rw-r--r-- | talpid-core/src/tunnel/wireguard/wireguard_go.rs | 50 |
5 files changed, 52 insertions, 51 deletions
diff --git a/Cargo.lock b/Cargo.lock index 6751e21522..5203ab025e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1278,7 +1278,6 @@ dependencies = [ "jni 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-client-core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "log-panics 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "mullvad-daemon 2019.8.0", diff --git a/mullvad-jni/Cargo.toml b/mullvad-jni/Cargo.toml index c75d9f901c..06dc9e8054 100644 --- a/mullvad-jni/Cargo.toml +++ b/mullvad-jni/Cargo.toml @@ -16,7 +16,6 @@ ipnetwork = "0.15" jni = "0.12" jsonrpc-client-core = "0.5" lazy_static = "1" -libc = "0.2" log = "0.4" log-panics = "2" parking_lot = "0.9" diff --git a/mullvad-jni/src/vpn_service_tun_provider.rs b/mullvad-jni/src/vpn_service_tun_provider.rs index 49740f5e9f..f55bc466d6 100644 --- a/mullvad-jni/src/vpn_service_tun_provider.rs +++ b/mullvad-jni/src/vpn_service_tun_provider.rs @@ -7,14 +7,12 @@ use jni::{ }; use std::{ fs::File, - io, net::{IpAddr, Ipv4Addr, Ipv6Addr}, os::unix::io::{AsRawFd, FromRawFd, RawFd}, }; use talpid_core::tunnel::tun_provider::{Tun, TunConfig, TunProvider}; use talpid_types::BoxedError; -const MAX_PREPARE_TUN_ATTEMPTS: usize = 4; /// Errors that occur while setting up VpnService tunnel. #[derive(Debug, err_derive::Error)] @@ -35,9 +33,6 @@ pub enum Error { #[error(display = "Failed to create global reference to MullvadVpnService instance")] CreateGlobalReference(#[error(cause)] jni::errors::Error), - #[error(display = "Failed to duplicate tunnel file descriptor")] - DuplicateTunFd(#[error(cause)] io::Error), - #[error(display = "Failed to find MullvadVpnService.{} method", _0)] FindMethod(&'static str, #[error(cause)] jni::errors::Error), @@ -95,42 +90,6 @@ impl VpnServiceTunProvider { } fn get_tun_fd(&mut self, config: TunConfig) -> Result<RawFd, Error> { - for retry in 1..=MAX_PREPARE_TUN_ATTEMPTS { - let tun = self.prepare_tun(config.clone())?; - - match Self::duplicate_tun(tun) { - Ok(fd) => return Ok(fd), - Err(error) => match error.raw_os_error() { - Some(libc::EBADF) => { - self.active_tun = None; - - log::warn!( - "VpnService returned a bad file descriptor, retrying ({}/{})", - retry, - MAX_PREPARE_TUN_ATTEMPTS - ); - } - _ => return Err(Error::DuplicateTunFd(error)), - }, - } - } - - Err(Error::DuplicateTunFd(io::Error::from_raw_os_error( - libc::EBADF, - ))) - } - - fn duplicate_tun(tun: &File) -> Result<RawFd, io::Error> { - let tun_fd = unsafe { libc::dup(tun.as_raw_fd()) }; - - if tun_fd >= 0 { - Ok(tun_fd) - } else { - Err(io::Error::last_os_error()) - } - } - - fn prepare_tun(&mut self, config: TunConfig) -> Result<&File, Error> { if self.active_tun.is_none() || self.last_tun_config != config { let env = self .jvm @@ -172,7 +131,8 @@ impl VpnServiceTunProvider { Ok(self .active_tun .as_ref() - .expect("Tunnel should be configured")) + .expect("Tunnel should be configured") + .as_raw_fd()) } } @@ -193,7 +153,7 @@ impl TunProvider for VpnServiceTunProvider { fn create_tun_if_closed(&mut self) -> Result<(), BoxedError> { if self.active_tun.is_none() { - self.prepare_tun(self.last_tun_config.clone()) + self.get_tun_fd(self.last_tun_config.clone()) .map_err(BoxedError::new)?; } diff --git a/talpid-core/src/tunnel/wireguard/mod.rs b/talpid-core/src/tunnel/wireguard/mod.rs index 1eecfe8f85..0721a2ead7 100644 --- a/talpid-core/src/tunnel/wireguard/mod.rs +++ b/talpid-core/src/tunnel/wireguard/mod.rs @@ -60,6 +60,11 @@ pub enum Error { #[error(display = "Failed to configure Wireguard sockets to bypass the tunnel")] BypassError(#[error(cause)] BoxedError), + /// Failed to duplicate file descriptors for logging on wireguard-go + #[cfg(any(target_os = "linux", target_os = "macos", target_os = "android"))] + #[error(display = "Failed to configure Wireguard sockets to bypass the tunnel")] + FdDuplicationError(#[error(cause)] nix::Error), + /// Pinging timed out. #[error(display = "Ping timed out")] PingTimeoutError, diff --git a/talpid-core/src/tunnel/wireguard/wireguard_go.rs b/talpid-core/src/tunnel/wireguard/wireguard_go.rs index a771bfae4a..ff45685191 100644 --- a/talpid-core/src/tunnel/wireguard/wireguard_go.rs +++ b/talpid-core/src/tunnel/wireguard/wireguard_go.rs @@ -1,10 +1,18 @@ use super::{Config, Error, Result, Tunnel}; use crate::tunnel::tun_provider::{Tun, TunConfig, TunProvider}; use ipnetwork::IpNetwork; -use std::{ffi::CString, fs, net::IpAddr, os::unix::io::AsRawFd, path::Path}; +use std::{ + ffi::CString, + fs, + net::IpAddr, + os::unix::io::{AsRawFd, RawFd}, + path::Path, +}; #[cfg(target_os = "android")] use talpid_types::BoxedError; +const MAX_PREPARE_TUN_ATTEMPTS: usize = 4; + pub struct WgGoTunnel { interface_name: String, handle: Option<i32>, @@ -22,10 +30,7 @@ impl WgGoTunnel { routes: impl Iterator<Item = IpNetwork>, ) -> Result<Self> { #[cfg_attr(not(target_os = "android"), allow(unused_mut))] - let mut tunnel_device = tun_provider - .get_tun(Self::create_tunnel_config(config, routes)) - .map_err(Error::SetupTunnelDeviceError)?; - + let (mut tunnel_device, tunnel_fd) = Self::get_tunnel(tun_provider, config, routes)?; let interface_name: String = tunnel_device.interface_name().to_string(); let log_file = prepare_log_file(log_path)?; @@ -33,12 +38,13 @@ impl WgGoTunnel { let iface_name = CString::new(interface_name.as_bytes()).map_err(Error::InterfaceNameError)?; + let handle = unsafe { wgTurnOnWithFd( iface_name.as_ptr() as *const i8, config.mtu as isize, wg_config_str.as_ptr() as *const i8, - tunnel_device.as_raw_fd(), + tunnel_fd, log_file.as_raw_fd(), WG_GO_LOG_DEBUG, ) @@ -99,6 +105,38 @@ impl WgGoTunnel { } Ok(()) } + + fn get_tunnel( + tun_provider: &mut dyn TunProvider, + config: &Config, + routes: impl Iterator<Item = IpNetwork>, + ) -> Result<(Box<dyn Tun>, RawFd)> { + let tunnel_config = Self::create_tunnel_config(config, routes); + for _ in 1..=MAX_PREPARE_TUN_ATTEMPTS { + let tunnel_device = tun_provider + .get_tun(tunnel_config.clone()) + .map_err(Error::SetupTunnelDeviceError)?; + + match nix::unistd::dup(tunnel_device.as_raw_fd()) { + Ok(fd) => { + return Ok((tunnel_device, fd)); + } + #[cfg(not(target_os = "macos"))] + Err(nix::Error::Sys(nix::errno::Errno::EBADFD)) => continue, + #[cfg(target_os = "macos")] + Err(nix::Error::Sys(nix::errno::Errno::EBADF)) => continue, + Err(error) => return Err(Error::FdDuplicationError(error)), + } + } + #[cfg(not(target_os = "macos"))] + return Err(Error::FdDuplicationError(nix::Error::Sys( + nix::errno::Errno::EBADFD, + ))); + #[cfg(target_os = "macos")] + return Err(Error::FdDuplicationError(nix::Error::Sys( + nix::errno::Errno::EBADF, + ))); + } } impl Drop for WgGoTunnel { |
