diff options
Diffstat (limited to 'talpid-core/src')
| -rw-r--r-- | talpid-core/src/tunnel/wireguard/mod.rs | 5 | ||||
| -rw-r--r-- | talpid-core/src/tunnel/wireguard/wireguard_go.rs | 50 |
2 files changed, 49 insertions, 6 deletions
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 { |
