diff options
| author | Janito Vaqueiro Ferreira Filho <janito@mullvad.net> | 2019-05-28 13:44:19 -0300 |
|---|---|---|
| committer | Janito Vaqueiro Ferreira Filho <janito@mullvad.net> | 2019-05-28 13:44:19 -0300 |
| commit | 1093f3e65ea020201dcba918a75e88a1af26bceb (patch) | |
| tree | 6cb925de4420fd02a63e402b5cfb4b23c4fa49ca | |
| parent | ec6674bd044b866f388d6e68f8380e669c067193 (diff) | |
| parent | 95a6729d2404536a3ea8ce2e5358c7710d4b43a1 (diff) | |
| download | mullvadvpn-1093f3e65ea020201dcba918a75e88a1af26bceb.tar.xz mullvadvpn-1093f3e65ea020201dcba918a75e88a1af26bceb.zip | |
Merge branch 'tun-provider'
| -rw-r--r-- | Cargo.lock | 2 | ||||
| -rw-r--r-- | mullvad-daemon/src/lib.rs | 8 | ||||
| -rw-r--r-- | mullvad-jni/Cargo.toml | 1 | ||||
| -rw-r--r-- | mullvad-jni/src/lib.rs | 4 | ||||
| -rw-r--r-- | talpid-core/Cargo.toml | 1 | ||||
| -rw-r--r-- | talpid-core/src/tunnel/mod.rs | 9 | ||||
| -rw-r--r-- | talpid-core/src/tunnel/tun_provider/mod.rs | 62 | ||||
| -rw-r--r-- | talpid-core/src/tunnel/tun_provider/stub.rs | 17 | ||||
| -rw-r--r-- | talpid-core/src/tunnel/tun_provider/unix.rs | 54 | ||||
| -rw-r--r-- | talpid-core/src/tunnel/wireguard/mod.rs | 8 | ||||
| -rw-r--r-- | talpid-core/src/tunnel/wireguard/wireguard_go.rs | 26 | ||||
| -rw-r--r-- | talpid-core/src/tunnel_state_machine/connecting_state.rs | 15 | ||||
| -rw-r--r-- | talpid-core/src/tunnel_state_machine/mod.rs | 9 | ||||
| -rw-r--r-- | talpid-types/src/lib.rs | 29 |
14 files changed, 221 insertions, 24 deletions
diff --git a/Cargo.lock b/Cargo.lock index ccf2d2491f..d6232ef395 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1175,6 +1175,7 @@ dependencies = [ "mullvad-paths 0.1.0", "mullvad-types 0.1.0", "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "talpid-core 0.1.0", "talpid-types 0.1.0", ] @@ -2094,6 +2095,7 @@ name = "talpid-core" version = "0.1.0" dependencies = [ "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "dbus 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", "derive_more 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", "duct 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/mullvad-daemon/src/lib.rs b/mullvad-daemon/src/lib.rs index 1d5851d94f..88cd834969 100644 --- a/mullvad-daemon/src/lib.rs +++ b/mullvad-daemon/src/lib.rs @@ -47,6 +47,7 @@ use mullvad_types::{ use std::{io, mem, path::PathBuf, sync::mpsc, thread, time::Duration}; use talpid_core::{ mpsc::IntoSender, + tunnel::tun_provider::{PlatformTunProvider, TunProvider}, tunnel_state_machine::{self, TunnelCommand, TunnelParametersGenerator}, }; use talpid_types::{ @@ -233,6 +234,7 @@ impl Daemon<ManagementInterfaceEventBroadcaster> { tx, rx, management_interface_broadcaster, + PlatformTunProvider::default(), log_dir, resource_dir, cache_dir, @@ -278,8 +280,9 @@ impl<L> Daemon<L> where L: EventListener + Clone + Send + 'static, { - pub fn start_with_event_listener( + pub fn start_with_event_listener_and_tun_provider( event_listener: L, + tun_provider: impl TunProvider, log_dir: Option<PathBuf>, resource_dir: PathBuf, cache_dir: PathBuf, @@ -291,6 +294,7 @@ where tx, rx, event_listener, + tun_provider, log_dir, resource_dir, cache_dir, @@ -302,6 +306,7 @@ where internal_event_tx: mpsc::Sender<InternalDaemonEvent>, internal_event_rx: mpsc::Receiver<InternalDaemonEvent>, event_listener: L, + tun_provider: impl TunProvider, log_dir: Option<PathBuf>, resource_dir: PathBuf, cache_dir: PathBuf, @@ -345,6 +350,7 @@ where settings.get_allow_lan(), settings.get_block_when_disconnected(), tunnel_parameters_generator, + tun_provider, log_dir, resource_dir, cache_dir.clone(), diff --git a/mullvad-jni/Cargo.toml b/mullvad-jni/Cargo.toml index bfb4cd7ede..9b1482f315 100644 --- a/mullvad-jni/Cargo.toml +++ b/mullvad-jni/Cargo.toml @@ -22,4 +22,5 @@ parking_lot = "0.8" mullvad-daemon = { path = "../mullvad-daemon" } mullvad-paths = { path = "../mullvad-paths" } mullvad-types = { path = "../mullvad-types" } +talpid-core = { path = "../talpid-core" } talpid-types = { path = "../talpid-types" } diff --git a/mullvad-jni/src/lib.rs b/mullvad-jni/src/lib.rs index 9e1b0c3b38..b35ec3efbf 100644 --- a/mullvad-jni/src/lib.rs +++ b/mullvad-jni/src/lib.rs @@ -19,6 +19,7 @@ use lazy_static::lazy_static; use mullvad_daemon::{logging, version, Daemon, DaemonCommandSender}; use parking_lot::{Mutex, RwLock}; use std::{collections::HashMap, path::PathBuf, sync::mpsc, thread}; +use talpid_core::tunnel::tun_provider::StubTunProvider; use talpid_types::ErrorExt; const LOG_FILENAME: &str = "daemon.log"; @@ -152,8 +153,9 @@ fn create_daemon( let resource_dir = mullvad_paths::get_resource_dir(); let cache_dir = mullvad_paths::cache_dir().map_err(Error::GetCacheDir)?; - let daemon = Daemon::start_with_event_listener( + let daemon = Daemon::start_with_event_listener_and_tun_provider( listener, + StubTunProvider, Some(log_dir), resource_dir, cache_dir, diff --git a/talpid-core/Cargo.toml b/talpid-core/Cargo.toml index 833b2cb9b6..2402bd2e52 100644 --- a/talpid-core/Cargo.toml +++ b/talpid-core/Cargo.toml @@ -8,6 +8,7 @@ edition = "2018" [dependencies] atty = "0.2" +cfg-if = "0.1" derive_more = "0.14" duct = "0.12" err-derive = "0.1.5" diff --git a/talpid-core/src/tunnel/mod.rs b/talpid-core/src/tunnel/mod.rs index 4d27be32ec..68f6c8ed63 100644 --- a/talpid-core/src/tunnel/mod.rs +++ b/talpid-core/src/tunnel/mod.rs @@ -1,3 +1,4 @@ +use self::tun_provider::TunProvider; use crate::logging; #[cfg(not(target_os = "android"))] use std::collections::HashMap; @@ -19,6 +20,9 @@ pub mod openvpn; #[cfg(any(target_os = "linux", target_os = "macos"))] pub mod wireguard; +/// A module for low level platform specific tunnel device management. +pub mod tun_provider; + const OPENVPN_LOG_FILENAME: &str = "openvpn.log"; const WIREGUARD_LOG_FILENAME: &str = "wireguard.log"; @@ -141,6 +145,7 @@ impl TunnelMonitor { log_dir: &Option<PathBuf>, resource_dir: &Path, on_event: L, + tun_provider: &dyn TunProvider, ) -> Result<Self> where L: Fn(TunnelEvent) + Send + Clone + Sync + 'static, @@ -155,7 +160,7 @@ impl TunnelMonitor { } #[cfg(any(target_os = "linux", target_os = "macos"))] TunnelParameters::Wireguard(config) => { - Self::start_wireguard_tunnel(&config, log_file, on_event) + Self::start_wireguard_tunnel(&config, log_file, on_event, tun_provider) } #[cfg(target_os = "android")] TunnelParameters::OpenVpn(_) => Err(Error::UnsupportedPlatform), @@ -169,6 +174,7 @@ impl TunnelMonitor { params: &wireguard_types::TunnelParameters, log: Option<PathBuf>, on_event: L, + tun_provider: &dyn TunProvider, ) -> Result<Self> where L: Fn(TunnelEvent) + Send + Sync + Clone + 'static, @@ -178,6 +184,7 @@ impl TunnelMonitor { &config, log.as_ref().map(|p| p.as_path()), on_event, + tun_provider, )?; Ok(TunnelMonitor { monitor: InternalTunnelMonitor::Wireguard(monitor), diff --git a/talpid-core/src/tunnel/tun_provider/mod.rs b/talpid-core/src/tunnel/tun_provider/mod.rs new file mode 100644 index 0000000000..43020114c7 --- /dev/null +++ b/talpid-core/src/tunnel/tun_provider/mod.rs @@ -0,0 +1,62 @@ +use cfg_if::cfg_if; +use std::net::IpAddr; +#[cfg(unix)] +use std::os::unix::io::AsRawFd; +use talpid_types::BoxedError; + +cfg_if! { + if #[cfg(all(unix, not(target_os = "android")))] { + #[path = "unix.rs"] + mod imp; + use self::imp::UnixTunProvider; + + /// Default implementation of `TunProvider` for Unix based operating systems. + /// + /// Android has a different mechanism to obtain tunnel interfaces, so it is not supported + /// here. + pub type PlatformTunProvider = UnixTunProvider; + } else { + mod stub; + pub use self::stub::StubTunProvider; + + /// Default stub implementation of `TunProvider` for Android and Windows. + pub type PlatformTunProvider = StubTunProvider; + } +} + +/// Generic tunnel device. +/// +/// Must be associated with a platform specific file descriptor representing the device. +#[cfg(unix)] +pub trait Tun: AsRawFd + Send { + /// Retrieve the tunnel interface name. + fn interface_name(&self) -> &str; +} + +/// Stub tunnel device. +#[cfg(windows)] +pub trait Tun: Send { + /// Retrieve the tunnel interface name. + fn interface_name(&self) -> &str; +} + +/// Factory of tunnel devices. +pub trait TunProvider: Send + 'static { + /// Create a tunnel device using the provided configuration. + fn create_tun(&self, config: TunConfig) -> Result<Box<dyn Tun>, BoxedError>; +} + +/// Configuration for creating a tunnel device. +pub struct TunConfig { + /// IP addresses for the tunnel interface. + pub addresses: Vec<IpAddr>, +} + +impl TunConfig { + /// Create a new tunnel device configuration using the specified tunnel addresses. + pub fn new(addresses: impl IntoIterator<Item = IpAddr>) -> Self { + TunConfig { + addresses: addresses.into_iter().collect(), + } + } +} diff --git a/talpid-core/src/tunnel/tun_provider/stub.rs b/talpid-core/src/tunnel/tun_provider/stub.rs new file mode 100644 index 0000000000..0b94b426bf --- /dev/null +++ b/talpid-core/src/tunnel/tun_provider/stub.rs @@ -0,0 +1,17 @@ +use super::{Tun, TunConfig, TunProvider}; +use talpid_types::BoxedError; + +/// Factory stub of tunnel devices. +pub struct StubTunProvider; + +impl Default for StubTunProvider { + fn default() -> Self { + StubTunProvider + } +} + +impl TunProvider for StubTunProvider { + fn create_tun(&self, _: TunConfig) -> Result<Box<dyn Tun>, BoxedError> { + unimplemented!(); + } +} diff --git a/talpid-core/src/tunnel/tun_provider/unix.rs b/talpid-core/src/tunnel/tun_provider/unix.rs new file mode 100644 index 0000000000..c0715a81bd --- /dev/null +++ b/talpid-core/src/tunnel/tun_provider/unix.rs @@ -0,0 +1,54 @@ +use super::{Tun, TunConfig, TunProvider}; +use crate::network_interface::{self, NetworkInterface, TunnelDevice}; +use std::net::IpAddr; +use talpid_types::BoxedError; + +/// Errors that can occur while setting up a tunnel device. +#[derive(Debug, err_derive::Error)] +pub enum Error { + /// Failure to create a tunnel device. + #[error(display = "Failed to create a tunnel device")] + CreateTunnelDevice(#[cause] network_interface::Error), + + /// Failure to set a tunnel device IP address. + #[error(display = "Failed to set tunnel IP address: {}", _0)] + SetIpAddr(IpAddr, #[cause] network_interface::Error), + + /// Failure to set the tunnel device as up. + #[error(display = "Failed to set the tunnel device as up")] + SetUp(#[cause] network_interface::Error), +} + +/// Factory of tunnel devices on Unix systems. +pub struct UnixTunProvider; + +impl Default for UnixTunProvider { + fn default() -> Self { + UnixTunProvider + } +} + +impl TunProvider for UnixTunProvider { + fn create_tun(&self, config: TunConfig) -> Result<Box<dyn Tun>, BoxedError> { + let mut tunnel_device = TunnelDevice::new() + .map_err(|cause| BoxedError::new(Error::CreateTunnelDevice(cause)))?; + + for ip in config.addresses.iter() { + tunnel_device + .set_ip(*ip) + .map_err(|cause| BoxedError::new(Error::SetIpAddr(*ip, cause)))?; + } + + tunnel_device + .set_up(true) + .map_err(|cause| BoxedError::new(Error::SetUp(cause)))?; + + Ok(Box::new(tunnel_device)) + } +} + +impl Tun for TunnelDevice { + fn interface_name(&self) -> &str { + self.get_name() + } +} diff --git a/talpid-core/src/tunnel/wireguard/mod.rs b/talpid-core/src/tunnel/wireguard/mod.rs index 24805f7dbe..05fecdb29f 100644 --- a/talpid-core/src/tunnel/wireguard/mod.rs +++ b/talpid-core/src/tunnel/wireguard/mod.rs @@ -1,9 +1,10 @@ #![allow(missing_docs)] use self::config::Config; -use super::{TunnelEvent, TunnelMetadata}; +use super::{tun_provider::TunProvider, TunnelEvent, TunnelMetadata}; use crate::routing; use std::{collections::HashMap, io, path::Path, sync::mpsc}; +use talpid_types::BoxedError; pub mod config; mod ping_monitor; @@ -21,7 +22,7 @@ pub type Result<T> = std::result::Result<T, Error>; pub enum Error { /// Failed to setup a tunnel device. #[error(display = "Failed to create tunnel device")] - SetupTunnelDeviceError(#[error(cause)] crate::network_interface::Error), + SetupTunnelDeviceError(#[error(cause)] BoxedError), /// Failed to setup wireguard tunnel. #[error(display = "Failed to start wireguard tunnel - {}", status)] @@ -65,8 +66,9 @@ impl WireguardMonitor { config: &Config, log_path: Option<&Path>, on_event: F, + tun_provider: &dyn TunProvider, ) -> Result<WireguardMonitor> { - let tunnel = Box::new(WgGoTunnel::start_tunnel(&config, log_path)?); + let tunnel = Box::new(WgGoTunnel::start_tunnel(&config, log_path, tun_provider)?); let iface_name = tunnel.get_interface_name(); let route_handle = routing::RouteManager::new( Self::get_routes(iface_name, &config), diff --git a/talpid-core/src/tunnel/wireguard/wireguard_go.rs b/talpid-core/src/tunnel/wireguard/wireguard_go.rs index 059147286d..9071766dbb 100644 --- a/talpid-core/src/tunnel/wireguard/wireguard_go.rs +++ b/talpid-core/src/tunnel/wireguard/wireguard_go.rs @@ -1,32 +1,28 @@ use super::{Config, Error, Result, Tunnel}; -use crate::network_interface::{NetworkInterface, TunnelDevice}; +use crate::tunnel::tun_provider::{Tun, TunConfig, TunProvider}; use std::{ffi::CString, fs, os::unix::io::AsRawFd, path::Path}; - pub struct WgGoTunnel { interface_name: String, handle: Option<i32>, // holding on to the tunnel device and the log file ensures that the associated file handles // live long enough and get closed when the tunnel is stopped - _tunnel_device: TunnelDevice, + _tunnel_device: Box<dyn Tun>, _log_file: fs::File, } impl WgGoTunnel { - pub fn start_tunnel(config: &Config, log_path: Option<&Path>) -> Result<Self> { - let mut tunnel_device = TunnelDevice::new().map_err(Error::SetupTunnelDeviceError)?; - - for ip in config.tunnel.addresses.iter() { - tunnel_device - .set_ip(*ip) - .map_err(Error::SetupTunnelDeviceError)?; - } - - tunnel_device - .set_up(true) + pub fn start_tunnel( + config: &Config, + log_path: Option<&Path>, + tun_provider: &dyn TunProvider, + ) -> Result<Self> { + let tunnel_config = TunConfig::new(config.tunnel.addresses.clone()); + let tunnel_device = tun_provider + .create_tun(tunnel_config) .map_err(Error::SetupTunnelDeviceError)?; - let interface_name: String = tunnel_device.get_name().to_string(); + let interface_name: String = tunnel_device.interface_name().to_string(); let log_file = prepare_log_file(log_path)?; let wg_config_str = config.to_userspace_format(); diff --git a/talpid-core/src/tunnel_state_machine/connecting_state.rs b/talpid-core/src/tunnel_state_machine/connecting_state.rs index 1f6afc16ad..c82ad27f73 100644 --- a/talpid-core/src/tunnel_state_machine/connecting_state.rs +++ b/talpid-core/src/tunnel_state_machine/connecting_state.rs @@ -5,7 +5,9 @@ use super::{ }; use crate::{ firewall::FirewallPolicy, - tunnel::{self, CloseHandle, TunnelEvent, TunnelMetadata, TunnelMonitor}, + tunnel::{ + self, tun_provider::TunProvider, CloseHandle, TunnelEvent, TunnelMetadata, TunnelMonitor, + }, }; use futures::{ sync::{mpsc, oneshot}, @@ -13,6 +15,7 @@ use futures::{ }; use log::{debug, error, info, trace, warn}; use std::{ + borrow::Borrow, net::IpAddr, path::{Path, PathBuf}, thread, @@ -62,13 +65,20 @@ impl ConnectingState { parameters: TunnelParameters, log_dir: &Option<PathBuf>, resource_dir: &Path, + tun_provider: &dyn TunProvider, retry_attempt: u32, ) -> crate::tunnel::Result<Self> { let (event_tx, event_rx) = mpsc::unbounded(); let on_tunnel_event = move |event| { let _ = event_tx.unbounded_send(event); }; - let monitor = TunnelMonitor::start(¶meters, log_dir, resource_dir, on_tunnel_event)?; + let monitor = TunnelMonitor::start( + ¶meters, + log_dir, + resource_dir, + on_tunnel_event, + tun_provider, + )?; let close_handle = monitor.close_handle(); let tunnel_close_event = Self::spawn_tunnel_monitor_wait_thread(monitor); @@ -320,6 +330,7 @@ impl TunnelState for ConnectingState { tunnel_parameters, &shared_values.log_dir, &shared_values.resource_dir, + shared_values.tun_provider.borrow(), retry_attempt, ) { Ok(connecting_state) => { diff --git a/talpid-core/src/tunnel_state_machine/mod.rs b/talpid-core/src/tunnel_state_machine/mod.rs index 715c2d773c..d947792da6 100644 --- a/talpid-core/src/tunnel_state_machine/mod.rs +++ b/talpid-core/src/tunnel_state_machine/mod.rs @@ -19,6 +19,7 @@ use crate::{ firewall::{Firewall, FirewallArguments}, mpsc::IntoSender, offline, + tunnel::tun_provider::TunProvider, }; use futures::{sync::mpsc, Async, Future, Poll, Stream}; use std::{ @@ -63,6 +64,7 @@ pub fn spawn<P, T>( allow_lan: bool, block_when_disconnected: bool, tunnel_parameters_generator: impl TunnelParametersGenerator, + tun_provider: impl TunProvider, log_dir: Option<PathBuf>, resource_dir: PathBuf, cache_dir: P, @@ -84,6 +86,7 @@ where block_when_disconnected, is_offline, tunnel_parameters_generator, + tun_provider, log_dir, resource_dir, cache_dir, @@ -122,6 +125,7 @@ fn create_event_loop<T>( block_when_disconnected: bool, is_offline: bool, tunnel_parameters_generator: impl TunnelParametersGenerator, + tun_provider: impl TunProvider, log_dir: Option<PathBuf>, resource_dir: PathBuf, cache_dir: impl AsRef<Path>, @@ -137,6 +141,7 @@ where block_when_disconnected, is_offline, tunnel_parameters_generator, + tun_provider, log_dir, resource_dir, cache_dir, @@ -186,6 +191,7 @@ impl TunnelStateMachine { block_when_disconnected: bool, is_offline: bool, tunnel_parameters_generator: impl TunnelParametersGenerator, + tun_provider: impl TunProvider, log_dir: Option<PathBuf>, resource_dir: PathBuf, cache_dir: impl AsRef<Path>, @@ -211,6 +217,7 @@ impl TunnelStateMachine { block_when_disconnected, is_offline, tunnel_parameters_generator: Box::new(tunnel_parameters_generator), + tun_provider: Box::new(tun_provider), log_dir, resource_dir, }; @@ -293,6 +300,8 @@ struct SharedTunnelStateValues { is_offline: bool, /// The generator of new `TunnelParameter`s tunnel_parameters_generator: Box<dyn TunnelParametersGenerator>, + /// The provider of tunnel devices. + tun_provider: Box<dyn TunProvider>, /// Directory to store tunnel log file. log_dir: Option<PathBuf>, /// Resource directory path. diff --git a/talpid-types/src/lib.rs b/talpid-types/src/lib.rs index 42a2dc4cf7..569bc94fb9 100644 --- a/talpid-types/src/lib.rs +++ b/talpid-types/src/lib.rs @@ -8,6 +8,8 @@ #![deny(rust_2018_idioms)] +use std::{error::Error, fmt}; + pub mod net; pub mod tunnel; @@ -20,7 +22,7 @@ pub trait ErrorExt { fn display_chain_with_msg(&self, msg: &str) -> String; } -impl<E: std::error::Error> ErrorExt for E { +impl<E: Error> ErrorExt for E { fn display_chain(&self) -> String { let mut s = format!("Error: {}", self); let mut source = self.source(); @@ -41,3 +43,28 @@ impl<E: std::error::Error> ErrorExt for E { s } } + +#[derive(Debug)] +pub struct BoxedError(Box<dyn Error>); + +impl fmt::Display for BoxedError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +impl Error for BoxedError { + fn description(&self) -> &str { + self.0.description() + } + + fn source(&self) -> Option<&(dyn Error + 'static)> { + self.0.source() + } +} + +impl BoxedError { + pub fn new(error: impl Error + 'static) -> Self { + BoxedError(Box::new(error)) + } +} |
