From c88f8b13122e9bd405b070eaab3c03554b16e784 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20L=C3=B6nnhager?= Date: Fri, 30 Aug 2024 19:29:46 +0200 Subject: [PATCH 1/2] Set tunnel name to wg0-mullvad for wireguard-go Co-authored-by: Markus Pettersson --- CHANGELOG.md | 3 + talpid-tunnel/src/tun_provider/mod.rs | 4 + talpid-tunnel/src/tun_provider/unix.rs | 88 ++++++++++++------- talpid-wireguard/src/config.rs | 4 + talpid-wireguard/src/wireguard_go/mod.rs | 6 ++ talpid-wireguard/src/wireguard_kernel/mod.rs | 2 - .../src/wireguard_kernel/netlink_tunnel.rs | 4 +- .../src/wireguard_kernel/nm_tunnel.rs | 4 +- 8 files changed, 78 insertions(+), 37 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 38c2bcc5b933..e4bac530c91f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,9 @@ Line wrap the file at 100 chars. Th ### Fixed - macOS and Linux: Fix potential crash when disconnecting with DAITA enabled. +#### Linux +- Set tunnel name to `wg0-mullvad` for userspace WireGuard. + #### macOS - Exclude programs when executed using a relative path from a shell. - Reduce packet loss when using split tunneling. diff --git a/talpid-tunnel/src/tun_provider/mod.rs b/talpid-tunnel/src/tun_provider/mod.rs index da7baf9889c1..94a82735d183 100644 --- a/talpid-tunnel/src/tun_provider/mod.rs +++ b/talpid-tunnel/src/tun_provider/mod.rs @@ -34,6 +34,9 @@ cfg_if! { /// Configuration for creating a tunnel device. #[derive(Clone, Debug, Eq, PartialEq)] pub struct TunConfig { + /// Interface name to use. + pub name: Option, + /// IP addresses for the tunnel interface. pub addresses: Vec, @@ -77,6 +80,7 @@ impl TunConfig { /// Android to route all traffic inside the tunnel. pub fn blocking_config() -> TunConfig { TunConfig { + name: None, addresses: vec![IpAddr::V4(Ipv4Addr::new(10, 0, 0, 1))], mtu: 1380, ipv4_gateway: Ipv4Addr::new(10, 64, 0, 1), diff --git a/talpid-tunnel/src/tun_provider/unix.rs b/talpid-tunnel/src/tun_provider/unix.rs index 640af527b31c..6aa71ed3936f 100644 --- a/talpid-tunnel/src/tun_provider/unix.rs +++ b/talpid-tunnel/src/tun_provider/unix.rs @@ -42,7 +42,17 @@ impl UnixTunProvider { /// Open a tunnel using the current tunnel config. pub fn open_tun(&mut self) -> Result { - let mut tunnel_device = TunnelDevice::new().map_err(Error::CreateTunnelDevice)?; + let mut tunnel_device = { + #[allow(unused_mut)] + let mut builder = TunnelDeviceBuilder::default(); + #[cfg(target_os = "linux")] + builder.enable_packet_information(); + #[cfg(target_os = "linux")] + if let Some(ref name) = self.config.name { + builder.name(name); + } + builder.create().map_err(Error::CreateTunnelDevice)? + }; for ip in self.config.addresses.iter() { tunnel_device @@ -100,43 +110,55 @@ pub enum NetworkInterfaceError { ToggleDevice(#[source] tun::Error), } -/// A trait for managing link devices -pub trait NetworkInterface: Sized { - /// Bring a given interface up or down - fn set_up(&mut self, up: bool) -> Result<(), NetworkInterfaceError>; - - /// Set host IPs for interface - fn set_ip(&mut self, ip: IpAddr) -> Result<(), NetworkInterfaceError>; - - /// Get name of interface - fn get_name(&self) -> &str; -} - -fn apply_async_flags(fd: RawFd) -> Result<(), nix::Error> { - fcntl::fcntl(fd, fcntl::FcntlArg::F_GETFL)?; - let arg = fcntl::FcntlArg::F_SETFL(fcntl::OFlag::O_RDWR | fcntl::OFlag::O_NONBLOCK); - fcntl::fcntl(fd, arg)?; - Ok(()) -} - /// A tunnel device pub struct TunnelDevice { dev: platform::Device, } -impl TunnelDevice { - /// Creates a new Tunnel device - #[allow(unused_mut)] - pub fn new() -> Result { - let mut config = Configuration::default(); - - #[cfg(target_os = "linux")] - config.platform(|config| { - config.packet_information(true); - }); - let mut dev = platform::create(&config).map_err(NetworkInterfaceError::CreateDevice)?; +/// A tunnel device builder. +/// +/// Call [`Self::create`] to create [`TunnelDevice`] from the config. +pub struct TunnelDeviceBuilder { + config: Configuration, +} + +impl TunnelDeviceBuilder { + /// Create a [`TunnelDevice`] from this builder. + pub fn create(self) -> Result { + fn apply_async_flags(fd: RawFd) -> Result<(), nix::Error> { + fcntl::fcntl(fd, fcntl::FcntlArg::F_GETFL)?; + let arg = fcntl::FcntlArg::F_SETFL(fcntl::OFlag::O_RDWR | fcntl::OFlag::O_NONBLOCK); + fcntl::fcntl(fd, arg)?; + Ok(()) + } + + let dev = platform::create(&self.config).map_err(NetworkInterfaceError::CreateDevice)?; apply_async_flags(dev.as_raw_fd()).map_err(NetworkInterfaceError::SetDeviceAsync)?; - Ok(Self { dev }) + Ok(TunnelDevice { dev }) + } + + /// Set a custom name for this tunnel device. + #[cfg(target_os = "linux")] + pub fn name(&mut self, name: &str) -> &mut Self { + self.config.name(name); + self + } + + /// Enable packet information. + /// When enabled the first 4 bytes of each packet is a header with flags and protocol type. + #[cfg(target_os = "linux")] + pub fn enable_packet_information(&mut self) -> &mut Self { + self.config.platform(|platform_config| { + platform_config.packet_information(true); + }); + self + } +} + +impl Default for TunnelDeviceBuilder { + fn default() -> Self { + let config = Configuration::default(); + Self { config } } } @@ -152,7 +174,7 @@ impl IntoRawFd for TunnelDevice { } } -impl NetworkInterface for TunnelDevice { +impl TunnelDevice { fn set_ip(&mut self, ip: IpAddr) -> Result<(), NetworkInterfaceError> { match ip { IpAddr::V4(ipv4) => self diff --git a/talpid-wireguard/src/config.rs b/talpid-wireguard/src/config.rs index 924446e8ebd0..c599d3448323 100644 --- a/talpid-wireguard/src/config.rs +++ b/talpid-wireguard/src/config.rs @@ -5,6 +5,10 @@ use std::{ }; use talpid_types::net::{obfuscation::ObfuscatorConfig, wireguard, GenericTunnelOptions}; +/// Name to use for the tunnel device +#[cfg(target_os = "linux")] +pub(crate) const MULLVAD_INTERFACE_NAME: &str = "wg0-mullvad"; + /// Config required to set up a single WireGuard tunnel #[derive(Debug, Clone)] pub struct Config { diff --git a/talpid-wireguard/src/wireguard_go/mod.rs b/talpid-wireguard/src/wireguard_go/mod.rs index 14f2d82cc683..678412bb1ef3 100644 --- a/talpid-wireguard/src/wireguard_go/mod.rs +++ b/talpid-wireguard/src/wireguard_go/mod.rs @@ -19,6 +19,8 @@ use super::{ stats::{Stats, StatsMap}, Config, Tunnel, TunnelError, }; +#[cfg(target_os = "linux")] +use crate::config::MULLVAD_INTERFACE_NAME; use crate::logging::{clean_up_logging, initialize_logging}; const MAX_PREPARE_TUN_ATTEMPTS: usize = 4; @@ -130,6 +132,10 @@ impl WgGoTunnel { let mut tun_provider = tun_provider.lock().unwrap(); let tun_config = tun_provider.config_mut(); + #[cfg(target_os = "linux")] + { + tun_config.name = Some(MULLVAD_INTERFACE_NAME.to_string()); + } tun_config.addresses = config.tunnel.addresses.clone(); tun_config.ipv4_gateway = config.ipv4_gateway; tun_config.ipv6_gateway = config.ipv6_gateway; diff --git a/talpid-wireguard/src/wireguard_kernel/mod.rs b/talpid-wireguard/src/wireguard_kernel/mod.rs index a3c053acfc07..db00557ffa1d 100644 --- a/talpid-wireguard/src/wireguard_kernel/mod.rs +++ b/talpid-wireguard/src/wireguard_kernel/mod.rs @@ -84,8 +84,6 @@ pub enum Error { NetworkManager(#[source] nm_tunnel::Error), } -pub(crate) const MULLVAD_INTERFACE_NAME: &str = "wg0-mullvad"; - #[derive(Debug)] pub struct Handle { pub wg_handle: WireguardConnection, diff --git a/talpid-wireguard/src/wireguard_kernel/netlink_tunnel.rs b/talpid-wireguard/src/wireguard_kernel/netlink_tunnel.rs index 0c6bec882327..52d8616c029a 100644 --- a/talpid-wireguard/src/wireguard_kernel/netlink_tunnel.rs +++ b/talpid-wireguard/src/wireguard_kernel/netlink_tunnel.rs @@ -2,10 +2,12 @@ use std::pin::Pin; use futures::Future; +use crate::config::MULLVAD_INTERFACE_NAME; + use super::{ super::stats::{Stats, StatsMap}, wg_message::DeviceNla, - Config, Error, Handle, Tunnel, TunnelError, MULLVAD_INTERFACE_NAME, + Config, Error, Handle, Tunnel, TunnelError, }; pub struct NetlinkTunnel { diff --git a/talpid-wireguard/src/wireguard_kernel/nm_tunnel.rs b/talpid-wireguard/src/wireguard_kernel/nm_tunnel.rs index 12f37f3e4540..76cfbcaddd6b 100644 --- a/talpid-wireguard/src/wireguard_kernel/nm_tunnel.rs +++ b/talpid-wireguard/src/wireguard_kernel/nm_tunnel.rs @@ -1,6 +1,8 @@ +use crate::config::MULLVAD_INTERFACE_NAME; + use super::{ super::stats::{Stats, StatsMap}, - Config, Error as WgKernelError, Handle, Tunnel, TunnelError, MULLVAD_INTERFACE_NAME, + Config, Error as WgKernelError, Handle, Tunnel, TunnelError, }; use futures::Future; use std::{collections::HashMap, pin::Pin}; From 6df61153bc7385587b209c67699bdaa1cd61a9b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20L=C3=B6nnhager?= Date: Mon, 2 Sep 2024 12:21:54 +0200 Subject: [PATCH 2/2] Remove unused NetworkInterface trait --- talpid-tunnel/src/tun_provider/unix.rs | 81 +++++++++----------------- 1 file changed, 29 insertions(+), 52 deletions(-) diff --git a/talpid-tunnel/src/tun_provider/unix.rs b/talpid-tunnel/src/tun_provider/unix.rs index 6aa71ed3936f..1081b3ce44b8 100644 --- a/talpid-tunnel/src/tun_provider/unix.rs +++ b/talpid-tunnel/src/tun_provider/unix.rs @@ -11,17 +11,25 @@ use tun::{platform, Configuration, Device}; /// Errors that can occur while setting up a tunnel device. #[derive(Debug, thiserror::Error)] pub enum Error { - /// Failure to create a tunnel device. - #[error("Failed to create a tunnel device")] - CreateTunnelDevice(#[source] NetworkInterfaceError), + /// Failed to set IP address + #[error("Failed to set IPv4 address")] + SetIpv4(#[source] tun::Error), + + /// Failed to set IP address + #[error("Failed to set IPv6 address")] + SetIpv6(#[source] io::Error), - /// Failure to set a tunnel device IP address. - #[error("Failed to set tunnel IP address: {0}")] - SetIpAddr(IpAddr, #[source] NetworkInterfaceError), + /// Unable to open a tunnel device + #[error("Unable to open a tunnel device")] + CreateDevice(#[source] tun::Error), - /// Failure to set the tunnel device as up. - #[error("Failed to set the tunnel device as up")] - SetUp(#[source] NetworkInterfaceError), + /// Failed to apply async flags to tunnel device + #[error("Failed to apply async flags to tunnel device")] + SetDeviceAsync(#[source] nix::Error), + + /// Failed to enable/disable link device + #[error("Failed to enable/disable link device")] + ToggleDevice(#[source] tun::Error), } /// Factory of tunnel devices on Unix systems. @@ -51,16 +59,14 @@ impl UnixTunProvider { if let Some(ref name) = self.config.name { builder.name(name); } - builder.create().map_err(Error::CreateTunnelDevice)? + builder.create()? }; for ip in self.config.addresses.iter() { - tunnel_device - .set_ip(*ip) - .map_err(|cause| Error::SetIpAddr(*ip, cause))?; + tunnel_device.set_ip(*ip)?; } - tunnel_device.set_up(true).map_err(Error::SetUp)?; + tunnel_device.set_up(true)?; Ok(UnixTun(tunnel_device)) } @@ -86,30 +92,6 @@ impl Deref for UnixTun { } } -/// Errors that can happen when working with *nix tunnel interfaces. -#[derive(thiserror::Error, Debug)] -pub enum NetworkInterfaceError { - /// Failed to set IP address - #[error("Failed to set IPv4 address")] - SetIpv4(#[source] tun::Error), - - /// Failed to set IP address - #[error("Failed to set IPv6 address")] - SetIpv6(#[source] io::Error), - - /// Unable to open a tunnel device - #[error("Unable to open a tunnel device")] - CreateDevice(#[source] tun::Error), - - /// Failed to apply async flags to tunnel device - #[error("Failed to apply async flags to tunnel device")] - SetDeviceAsync(#[source] nix::Error), - - /// Failed to enable/disable link device - #[error("Failed to enable/disable link device")] - ToggleDevice(#[source] tun::Error), -} - /// A tunnel device pub struct TunnelDevice { dev: platform::Device, @@ -124,7 +106,7 @@ pub struct TunnelDeviceBuilder { impl TunnelDeviceBuilder { /// Create a [`TunnelDevice`] from this builder. - pub fn create(self) -> Result { + pub fn create(self) -> Result { fn apply_async_flags(fd: RawFd) -> Result<(), nix::Error> { fcntl::fcntl(fd, fcntl::FcntlArg::F_GETFL)?; let arg = fcntl::FcntlArg::F_SETFL(fcntl::OFlag::O_RDWR | fcntl::OFlag::O_NONBLOCK); @@ -132,8 +114,8 @@ impl TunnelDeviceBuilder { Ok(()) } - let dev = platform::create(&self.config).map_err(NetworkInterfaceError::CreateDevice)?; - apply_async_flags(dev.as_raw_fd()).map_err(NetworkInterfaceError::SetDeviceAsync)?; + let dev = platform::create(&self.config).map_err(Error::CreateDevice)?; + apply_async_flags(dev.as_raw_fd()).map_err(Error::SetDeviceAsync)?; Ok(TunnelDevice { dev }) } @@ -175,12 +157,9 @@ impl IntoRawFd for TunnelDevice { } impl TunnelDevice { - fn set_ip(&mut self, ip: IpAddr) -> Result<(), NetworkInterfaceError> { + fn set_ip(&mut self, ip: IpAddr) -> Result<(), Error> { match ip { - IpAddr::V4(ipv4) => self - .dev - .set_address(ipv4) - .map_err(NetworkInterfaceError::SetIpv4), + IpAddr::V4(ipv4) => self.dev.set_address(ipv4).map_err(Error::SetIpv4), IpAddr::V6(ipv6) => { #[cfg(target_os = "linux")] { @@ -195,7 +174,7 @@ impl TunnelDevice { ) .run() .map(|_| ()) - .map_err(NetworkInterfaceError::SetIpv6) + .map_err(Error::SetIpv6) } #[cfg(target_os = "macos")] { @@ -208,16 +187,14 @@ impl TunnelDevice { ) .run() .map(|_| ()) - .map_err(NetworkInterfaceError::SetIpv6) + .map_err(Error::SetIpv6) } } } } - fn set_up(&mut self, up: bool) -> Result<(), NetworkInterfaceError> { - self.dev - .enabled(up) - .map_err(NetworkInterfaceError::ToggleDevice) + fn set_up(&mut self, up: bool) -> Result<(), Error> { + self.dev.enabled(up).map_err(Error::ToggleDevice) } fn get_name(&self) -> &str {