diff options
| author | Linus Färnstrand <linus@mullvad.net> | 2019-04-05 20:50:25 +0200 |
|---|---|---|
| committer | Linus Färnstrand <linus@mullvad.net> | 2019-04-05 20:50:25 +0200 |
| commit | e2bc2596cf130a26ab143a173b79039f01ddb1d1 (patch) | |
| tree | 18cca9b3b5ebb07d8b638387740eeae1c091ab9e /talpid-core/src | |
| parent | 95eaba22e7cc2f4e7fcf2717258486244e320aa3 (diff) | |
| parent | e56799a487983124ce3cfcd87a275a67c91c942b (diff) | |
| download | mullvadvpn-e2bc2596cf130a26ab143a173b79039f01ddb1d1.tar.xz mullvadvpn-e2bc2596cf130a26ab143a173b79039f01ddb1d1.zip | |
Merge branch 'eliminate-error-chain-tunnel'
Diffstat (limited to 'talpid-core/src')
| -rw-r--r-- | talpid-core/src/dns/linux/static_resolv_conf.rs | 73 | ||||
| -rw-r--r-- | talpid-core/src/firewall/linux.rs | 2 | ||||
| -rw-r--r-- | talpid-core/src/lib.rs | 3 | ||||
| -rw-r--r-- | talpid-core/src/routing/android.rs | 11 | ||||
| -rw-r--r-- | talpid-core/src/routing/linux.rs | 6 | ||||
| -rw-r--r-- | talpid-core/src/routing/macos.rs | 6 | ||||
| -rw-r--r-- | talpid-core/src/routing/mod.rs | 12 | ||||
| -rw-r--r-- | talpid-core/src/tunnel/mod.rs | 66 | ||||
| -rw-r--r-- | talpid-core/src/tunnel/openvpn.rs | 156 | ||||
| -rw-r--r-- | talpid-core/src/tunnel/wireguard/mod.rs | 74 | ||||
| -rw-r--r-- | talpid-core/src/tunnel/wireguard/wireguard_go.rs | 18 | ||||
| -rw-r--r-- | talpid-core/src/tunnel_state_machine/connecting_state.rs | 18 |
12 files changed, 231 insertions, 214 deletions
diff --git a/talpid-core/src/dns/linux/static_resolv_conf.rs b/talpid-core/src/dns/linux/static_resolv_conf.rs index 71b6973edf..73c9aa4221 100644 --- a/talpid-core/src/dns/linux/static_resolv_conf.rs +++ b/talpid-core/src/dns/linux/static_resolv_conf.rs @@ -1,5 +1,4 @@ use super::RESOLV_CONF_PATH; -use error_chain::ChainedError; use notify::{RecommendedWatcher, RecursiveMode, Watcher}; use parking_lot::Mutex; use resolv_conf::{Config, ScopedIp}; @@ -9,27 +8,28 @@ use std::{ sync::{mpsc, Arc}, thread, }; +use talpid_types::ErrorExt; const RESOLV_CONF_BACKUP_PATH: &str = "/etc/resolv.conf.mullvadbackup"; -error_chain! { - errors { - WatchResolvConf { - description("Failed to watch /etc/resolv.conf for changes") - } +pub type Result<T> = std::result::Result<T, Error>; - WriteResolvConf { - description("Failed to write to /etc/resolv.conf") - } +#[derive(err_derive::Error, Debug)] +pub enum Error { + #[error(display = "Failed to watch /etc/resolv.conf for changes")] + WatchResolvConf(#[error(cause)] notify::Error), - BackupResolvConf { - description("Failed to create backup of /etc/resolv.conf") - } + #[error(display = "Failed to write to {}", _0)] + WriteResolvConf(&'static str, #[error(cause)] io::Error), - RestoreResolvConf { - description("Failed to restore /etc/resolv.conf from backup") - } - } + #[error(display = "Failed to read from {}", _0)] + ReadResolvConf(&'static str, #[error(cause)] io::Error), + + #[error(display = "resolv.conf at {} could not be parsed", _0)] + ParseError(&'static str, #[error(cause)] resolv_conf::ParseError), + + #[error(display = "Failed to remove stale resolv.conf backup at {}", _0)] + RemoveBackup(&'static str, #[error(cause)] io::Error), } pub struct StaticResolvConf { @@ -39,7 +39,7 @@ pub struct StaticResolvConf { impl StaticResolvConf { pub fn new() -> Result<Self> { - restore_from_backup().chain_err(|| ErrorKind::RestoreResolvConf)?; + restore_from_backup()?; let state = Arc::new(Mutex::new(None)); let watcher = DnsWatcher::start(state.clone())?; @@ -54,8 +54,8 @@ impl StaticResolvConf { let mut state = self.state.lock(); let new_state = match state.take() { None => { - let backup = read_config().chain_err(|| ErrorKind::BackupResolvConf)?; - write_backup(&backup).chain_err(|| ErrorKind::BackupResolvConf)?; + let backup = read_config()?; + write_backup(&backup)?; State { backup, @@ -111,11 +111,11 @@ struct DnsWatcher { impl DnsWatcher { fn start(state: Arc<Mutex<Option<State>>>) -> Result<Self> { let (event_tx, event_rx) = mpsc::channel(); - let mut watcher = notify::raw_watcher(event_tx).chain_err(|| ErrorKind::WatchResolvConf)?; + let mut watcher = notify::raw_watcher(event_tx).map_err(Error::WatchResolvConf)?; watcher .watch(RESOLV_CONF_PATH, RecursiveMode::NonRecursive) - .chain_err(|| ErrorKind::WatchResolvConf)?; + .map_err(Error::WatchResolvConf)?; thread::spawn(move || Self::event_loop(event_rx, &state)); @@ -127,9 +127,12 @@ impl DnsWatcher { let mut locked_state = state.lock(); if let Err(error) = Self::update(locked_state.as_mut()) { - let chained_error = error - .chain_err(|| "Failed to update DNS state after DNS settings have changed."); - log::error!("{}", chained_error.display_chain()); + log::error!( + "{}", + error.display_chain_with_msg( + "Failed to update DNS state after DNS settings changed" + ) + ); } } } @@ -153,7 +156,7 @@ impl DnsWatcher { new_config.nameservers.append(&mut state.backup.nameservers); state.backup = new_config; - write_backup(&state.backup).chain_err(|| "Failed to update /etc/resolv.conf backup") + write_backup(&state.backup) } } else { Ok(()) @@ -162,22 +165,21 @@ impl DnsWatcher { } fn read_config() -> Result<Config> { - let contents = - fs::read_to_string(RESOLV_CONF_PATH).chain_err(|| "Failed to read /etc/resolv.conf")?; - let config = - Config::parse(&contents).chain_err(|| "Failed to parse contents of /etc/resolv.conf")?; + let contents = fs::read_to_string(RESOLV_CONF_PATH) + .map_err(|e| Error::ReadResolvConf(RESOLV_CONF_PATH, e))?; + let config = Config::parse(&contents).map_err(|e| Error::ParseError(RESOLV_CONF_PATH, e))?; Ok(config) } fn write_config(config: &Config) -> Result<()> { fs::write(RESOLV_CONF_PATH, config.to_string().as_bytes()) - .chain_err(|| ErrorKind::WriteResolvConf) + .map_err(|e| Error::WriteResolvConf(RESOLV_CONF_PATH, e)) } fn write_backup(backup: &Config) -> Result<()> { fs::write(RESOLV_CONF_BACKUP_PATH, backup.to_string().as_bytes()) - .chain_err(|| "Failed to write to /etc/resolv.conf backup file") + .map_err(|e| Error::WriteResolvConf(RESOLV_CONF_BACKUP_PATH, e)) } fn restore_from_backup() -> Result<()> { @@ -185,20 +187,17 @@ fn restore_from_backup() -> Result<()> { Ok(backup) => { log::info!("Restoring DNS state from backup"); let config = Config::parse(&backup) - .chain_err(|| "Backup of /etc/resolv.conf could not be parsed")?; + .map_err(|e| Error::ParseError(RESOLV_CONF_BACKUP_PATH, e))?; write_config(&config)?; fs::remove_file(RESOLV_CONF_BACKUP_PATH) - .chain_err(|| "Failed to remove stale backup of /etc/resolv.conf") + .map_err(|e| Error::RemoveBackup(RESOLV_CONF_BACKUP_PATH, e)) } Err(ref error) if error.kind() == io::ErrorKind::NotFound => { log::debug!("No DNS state backup to restore"); Ok(()) } - Err(error) => Err(Error::with_chain( - error, - "Failed to read /etc/resolv.conf backup", - )), + Err(error) => Err(Error::ReadResolvConf(RESOLV_CONF_BACKUP_PATH, error)), } } diff --git a/talpid-core/src/firewall/linux.rs b/talpid-core/src/firewall/linux.rs index 5c8d9e777e..540bdff1ee 100644 --- a/talpid-core/src/firewall/linux.rs +++ b/talpid-core/src/firewall/linux.rs @@ -164,7 +164,7 @@ impl Firewall { "Expected '{}' netfilter table to be set, but it is not", expected_table.to_string_lossy() ); - bail!(Error::NetfilterTableNotSetError) + return Err(Error::NetfilterTableNotSetError); } } Ok(()) diff --git a/talpid-core/src/lib.rs b/talpid-core/src/lib.rs index 1499557439..3b2bac9529 100644 --- a/talpid-core/src/lib.rs +++ b/talpid-core/src/lib.rs @@ -11,9 +11,6 @@ //! GNU General Public License as published by the Free Software Foundation, either version 3 of //! the License, or (at your option) any later version. -#[macro_use] -extern crate error_chain; - /// Misc FFI utilities. #[cfg(windows)] #[macro_use] diff --git a/talpid-core/src/routing/android.rs b/talpid-core/src/routing/android.rs index fa5c5c8f8e..5c562537f1 100644 --- a/talpid-core/src/routing/android.rs +++ b/talpid-core/src/routing/android.rs @@ -7,7 +7,10 @@ use std::{ net::{IpAddr, Ipv4Addr}, }; -error_chain! {} +/// Stub error type for routing errors on Android. +#[derive(Debug, err_derive::Error)] +#[error(display = "Unknown Android routing error")] +pub struct Error; pub struct RouteManager; @@ -18,15 +21,15 @@ impl super::RoutingT for RouteManager { Ok(RouteManager) } - fn add_routes(&mut self, _required_routes: RequiredRoutes) -> Result<()> { + fn add_routes(&mut self, _required_routes: RequiredRoutes) -> Result<(), Self::Error> { Ok(()) } - fn delete_routes(&mut self) -> Result<()> { + fn delete_routes(&mut self) -> Result<(), Self::Error> { Ok(()) } - fn get_default_route_node(&mut self) -> Result<IpAddr> { + fn get_default_route_node(&mut self) -> Result<IpAddr, Self::Error> { Ok(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0))) } } diff --git a/talpid-core/src/routing/linux.rs b/talpid-core/src/routing/linux.rs index 73de509a0e..b229b192c2 100644 --- a/talpid-core/src/routing/linux.rs +++ b/talpid-core/src/routing/linux.rs @@ -9,20 +9,26 @@ use std::{ pub type Result<T> = std::result::Result<T, Error>; +/// Errors that can happen in the Linux routing integration #[derive(err_derive::Error, Debug)] pub enum Error { + /// Failed to add route. #[error(display = "Failed to add route")] FailedToAddRoute(#[error(cause)] io::Error), + /// Failed to remove route. #[error(display = "Failed to remove route")] FailedToRemoveRoute(#[error(cause)] io::Error), + /// Error while running "ip route". #[error(display = "Error while running \"ip route\"")] FailedToRunIp(#[error(cause)] io::Error), + /// No default route in "ip route" output. #[error(display = "No default route in \"ip route\" output")] NoDefaultRoute, + /// Failed to parse default route as IP. #[error(display = "Failed to parse default route as IP: {}", _0)] ParseDefaultRoute(String, #[error(cause)] AddrParseError), } diff --git a/talpid-core/src/routing/macos.rs b/talpid-core/src/routing/macos.rs index d0e9497c1c..722efbb320 100644 --- a/talpid-core/src/routing/macos.rs +++ b/talpid-core/src/routing/macos.rs @@ -10,20 +10,26 @@ use std::{ pub type Result<T> = std::result::Result<T, Error>; +/// Errors that can happen in the macOS routing integration. #[derive(err_derive::Error, Debug)] pub enum Error { + /// Failed to add route. #[error(display = "Failed to add route")] FailedToAddRoute(#[error(cause)] io::Error), + /// Failed to remove route. #[error(display = "Failed to remove route")] FailedToRemoveRoute(#[error(cause)] io::Error), + /// Error while running "ip route". #[error(display = "Error while running \"ip route\"")] FailedToRunIp(#[error(cause)] io::Error), + /// No default route in "ip route" output. #[error(display = "No default route in \"ip route\" output")] NoDefaultRoute, + /// Failed to parse default route as IP. #[error(display = "Failed to parse default route as IP: {}", _0)] ParseDefaultRoute(String, #[error(cause)] AddrParseError), } diff --git a/talpid-core/src/routing/mod.rs b/talpid-core/src/routing/mod.rs index 612c0b2396..b2e299553f 100644 --- a/talpid-core/src/routing/mod.rs +++ b/talpid-core/src/routing/mod.rs @@ -13,6 +13,8 @@ mod imp; #[path = "android.rs"] mod imp; +pub use self::imp::Error; + mod subprocess; /// A single route @@ -53,24 +55,24 @@ pub struct RouteManager { impl RouteManager { /// Creates a new RouteManager. - pub fn new() -> Result<Self, imp::Error> { + pub fn new() -> Result<Self, Error> { Ok(RouteManager { inner: imp::RouteManager::new()?, }) } /// Set routes in the routing table. - pub fn add_routes(&mut self, required_routes: RequiredRoutes) -> Result<(), imp::Error> { + pub fn add_routes(&mut self, required_routes: RequiredRoutes) -> Result<(), Error> { self.inner.add_routes(required_routes) } /// Remove previously set routes from the routing table. - pub fn delete_routes(&mut self) -> Result<(), imp::Error> { + pub fn delete_routes(&mut self) -> Result<(), Error> { self.inner.delete_routes() } /// Retrieves the gateway for the default route. - pub fn get_default_route_node(&mut self) -> Result<std::net::IpAddr, imp::Error> { + pub fn get_default_route_node(&mut self) -> Result<std::net::IpAddr, Error> { // use routing::RoutingT; self.inner.get_default_route_node() } @@ -87,7 +89,7 @@ impl Drop for RouteManager { /// This trait unifies platform specific implementations of route managers pub trait RoutingT: Sized { /// Error type of the implementation - type Error: ::std::error::Error; + type Error: std::error::Error; /// Creates a new router fn new() -> Result<Self, Self::Error>; diff --git a/talpid-core/src/tunnel/mod.rs b/talpid-core/src/tunnel/mod.rs index 04332908c4..987f80c872 100644 --- a/talpid-core/src/tunnel/mod.rs +++ b/talpid-core/src/tunnel/mod.rs @@ -19,36 +19,37 @@ pub mod wireguard; const OPENVPN_LOG_FILENAME: &str = "openvpn.log"; const WIREGUARD_LOG_FILENAME: &str = "wireguard.log"; +/// Results from operations in the tunnel module. +pub type Result<T> = std::result::Result<T, Error>; -error_chain! { - errors { - /// Tunnel can't have IPv6 enabled because the system has disabled IPv6 support. - EnableIpv6Error { - description("Can't enable IPv6 on tunnel interface because IPv6 is disabled") - } - /// Running on an operating system which is not supported yet. - UnsupportedPlatform { - description("Tunnel type not supported on this operating system") - } - /// Failed to rotate tunnel log file - RotateLogError { - description("Failed to rotate tunnel log file") - } - /// Failure to build Wireguard configuration. - WireguardConfigError { - description("Failed to configure Wireguard with the given parameters") - } - } +/// Errors that can occur in the [`TunnelMonitor`]. +#[derive(err_derive::Error, Debug, derive_more::From)] +pub enum Error { + /// Tunnel can't have IPv6 enabled because the system has disabled IPv6 support. + #[error(display = "Can't enable IPv6 on tunnel interface because IPv6 is disabled")] + EnableIpv6Error, - links { - OpenVpnTunnelMonitoringError(openvpn::Error, openvpn::ErrorKind) - /// There was an error listening for events from the OpenVPN tunnel - ; - WirguardTunnelMonitoringError(wireguard::Error, wireguard::ErrorKind) - /// There was an error listening for events from the OpenVPN tunnel - #[cfg(any(target_os = "linux", target_os = "macos"))] - ; - } + /// Running on an operating system which is not supported yet. + #[error(display = "Tunnel type not supported on this operating system")] + UnsupportedPlatform, + + /// Failed to rotate tunnel log file + #[error(display = "Failed to rotate tunnel log file")] + RotateLogError(#[error(cause)] crate::logging::RotateLogError), + + /// Failure to build Wireguard configuration. + #[cfg(any(target_os = "linux", target_os = "macos"))] + #[error(display = "Failed to configure Wireguard with the given parameters")] + WireguardConfigError(#[error(cause)] self::wireguard::config::Error), + + /// There was an error listening for events from the OpenVPN tunnel + #[error(display = "Failed while listening for events from the OpenVPN tunnel")] + OpenVpnTunnelMonitoringError(#[error(cause)] openvpn::Error), + + /// There was an error listening for events from the Wireguard tunnel + #[cfg(any(target_os = "linux", target_os = "macos"))] + #[error(display = "Failed while listening for events from the Wireguard tunnel")] + WirguardTunnelMonitoringError(#[error(cause)] wireguard::Error), } @@ -151,7 +152,7 @@ impl TunnelMonitor { Self::start_wireguard_tunnel(&config, log_file, on_event) } #[cfg(any(windows, target_os = "android"))] - TunnelParameters::Wireguard(_) => bail!(ErrorKind::UnsupportedPlatform), + TunnelParameters::Wireguard(_) => Err(Error::UnsupportedPlatform), } } @@ -164,8 +165,7 @@ impl TunnelMonitor { where L: Fn(TunnelEvent) + Send + Sync + Clone + 'static, { - let config = wireguard::config::Config::from_parameters(¶ms) - .chain_err(|| ErrorKind::WireguardConfigError)?; + let config = wireguard::config::Config::from_parameters(¶ms)?; let monitor = wireguard::WireguardMonitor::start( &config, log.as_ref().map(|p| p.as_path()), @@ -195,7 +195,7 @@ impl TunnelMonitor { fn ensure_ipv6_can_be_used_if_enabled(tunnel_options: &GenericTunnelOptions) -> Result<()> { if tunnel_options.enable_ipv6 && !is_ipv6_enabled_in_os() { - bail!(ErrorKind::EnableIpv6Error); + Err(Error::EnableIpv6Error) } else { Ok(()) } @@ -211,7 +211,7 @@ impl TunnelMonitor { TunnelParameters::Wireguard(_) => WIREGUARD_LOG_FILENAME, }; let tunnel_log = log_dir.join(filename); - logging::rotate_log(&tunnel_log).chain_err(|| ErrorKind::RotateLogError)?; + logging::rotate_log(&tunnel_log)?; Ok(Some(tunnel_log)) } else { Ok(None) diff --git a/talpid-core/src/tunnel/openvpn.rs b/talpid-core/src/tunnel/openvpn.rs index 8e0de74430..d8c97d468a 100644 --- a/talpid-core/src/tunnel/openvpn.rs +++ b/talpid-core/src/tunnel/openvpn.rs @@ -28,52 +28,70 @@ use talpid_types::net::openvpn; #[cfg(target_os = "linux")] use which; -error_chain! { - errors { - /// Unable to start, wait for or kill the OpenVPN process. - ChildProcessError(msg: &'static str) { - description("Unable to start, wait for or kill the OpenVPN process") - display("OpenVPN process error: {}", msg) - } - /// Unable to start or manage the IPC server listening for events from OpenVPN. - EventDispatcherError { - description("Unable to start or manage the event dispatcher IPC server") - } - #[cfg(windows)] - /// No TAP adapter was detected - MissingTapAdapter { - description("No TAP adapter was detected") - } - #[cfg(windows)] - /// TAP adapter seems to be disabled - DisabledTapAdapter { - description("The TAP adapter appears to be disabled") - } - /// The IP routing program was not found. - #[cfg(target_os = "linux")] - IpRouteNotFound { - description("The IP routing program `ip` was not found.") - } - /// The OpenVPN binary was not found. - OpenVpnNotFound(path: PathBuf) { - description("No OpenVPN binary found") - display("No OpenVPN binary found at {}", path.display()) - } - /// The OpenVPN plugin was not found. - PluginNotFound(path: PathBuf) { - description("No OpenVPN plugin found") - display("No OpenVPN plugin found at {}", path.display()) - } - /// There was an error when writing authentication credentials to temporary file. - CredentialsWriteError { - description("Error while writing credentials to temporary file") - } - /// Failures related to the proxy service. - ProxyError(msg: String) { - description("Unable to start, wait for or kill the proxy service") - display("Proxy error: {}", msg) - } - } + +/// Results from fallible operations on the OpenVPN tunnel. +pub type Result<T> = std::result::Result<T, Error>; + +/// Errors that can happen when using the OpenVPN tunnel. +#[derive(err_derive::Error, Debug)] +pub enum Error { + /// Unable to start, wait for or kill the OpenVPN process. + #[error(display = "Error in OpenVPN process management: {}", _0)] + ChildProcessError(&'static str, #[error(cause)] io::Error), + + /// Unable to start or manage the IPC server listening for events from OpenVPN. + #[error(display = "Unable to start or manage the event dispatcher IPC server")] + EventDispatcherError(#[error(cause)] talpid_ipc::Error), + + /// The OpenVPN event dispatcher exited unexpectedly + #[error(display = "The OpenVPN event dispatcher exited unexpectedly")] + EventDispatcherExited, + + /// No TAP adapter was detected + #[cfg(windows)] + #[error(display = "No TAP adapter was detected")] + MissingTapAdapter, + + /// TAP adapter seems to be disabled + #[cfg(windows)] + #[error(display = "The TAP adapter appears to be disabled")] + DisabledTapAdapter, + + /// OpenVPN process died unexpectedly + #[error(display = "OpenVPN process died unexpectedly")] + ChildProcessDied, + + /// The IP routing program was not found. + #[cfg(target_os = "linux")] + #[error(display = "The IP routing program `ip` was not found")] + IpRouteNotFound(#[error(cause)] failure::Compat<which::Error>), + + /// The OpenVPN binary was not found. + #[error(display = "No OpenVPN binary found at {}", _0)] + OpenVpnNotFound(String), + + /// The OpenVPN plugin was not found. + #[error(display = "No OpenVPN plugin found at {}", _0)] + PluginNotFound(String), + + /// Error while writing credentials to temporary file. + #[error(display = "Error while writing credentials to temporary file")] + CredentialsWriteError(#[error(cause)] io::Error), + + /// Failures related to the proxy service. + #[error(display = "Unable to start the proxy service")] + StartProxyError(#[error(cause)] io::Error), + + /// Error while monitoring proxy service + #[error(display = "Error while monitoring proxy service")] + MonitorProxyError(#[error(cause)] io::Error), + + /// The proxy exited unexpectedly + #[error( + display = "The proxy exited unexpectedly providing these details: {}", + _0 + )] + ProxyExited(String), } @@ -124,10 +142,10 @@ impl OpenVpnMonitor<OpenVpnCommand> { { let user_pass_file = Self::create_credentials_file(¶ms.config.username, ¶ms.config.password) - .chain_err(|| ErrorKind::CredentialsWriteError)?; + .map_err(Error::CredentialsWriteError)?; let proxy_auth_file = Self::create_proxy_auth_file(¶ms.options.proxy) - .chain_err(|| ErrorKind::CredentialsWriteError)?; + .map_err(Error::CredentialsWriteError)?; let user_pass_file_path = user_pass_file.to_path_buf(); @@ -205,13 +223,13 @@ impl<C: OpenVpnBuilder + 'static> OpenVpnMonitor<C> { L: Fn(openvpn_plugin::EventType, HashMap<String, String>) + Send + Sync + 'static, { let event_dispatcher = - event_server::start(on_event).chain_err(|| ErrorKind::EventDispatcherError)?; + event_server::start(on_event).map_err(Error::EventDispatcherError)?; let child = cmd .plugin(plugin_path, vec![event_dispatcher.path().to_owned()]) .log(log_path.as_ref().map(|p| p.as_path())) .start() - .chain_err(|| ErrorKind::ChildProcessError("Failed to start"))?; + .map_err(|e| Error::ChildProcessError("Failed to start", e))?; Ok(OpenVpnMonitor { child: Arc::new(child), @@ -267,21 +285,13 @@ impl<C: OpenVpnBuilder + 'static> OpenVpnMonitor<C> { // The proxy should never exit before openvpn. match proxy_result { Ok(proxy::WaitResult::ProperShutdown) => { - return Err(ErrorKind::ProxyError("The proxy exited unexpectedly without providing additional details".into()).into()); + return Err(Error::ProxyExited("No details".to_owned())); } Ok(proxy::WaitResult::UnexpectedExit(details)) => { - return Err(ErrorKind::ProxyError(format!( - "The proxy exited unexpectedly providing these details: {}", - details - )) - .into()); + return Err(Error::ProxyExited(details)); } Err(err) => { - return Err(err).chain_err(|| { - ErrorKind::ProxyError( - "Failed to wait for/monitor proxy service".into(), - ) - }); + return Err(err).map_err(Error::MonitorProxyError); } } } @@ -309,11 +319,11 @@ impl<C: OpenVpnBuilder + 'static> OpenVpnMonitor<C> { } WaitResult::Child(Err(e), _) => { log::error!("OpenVPN process wait error: {}", e); - Err(e).chain_err(|| ErrorKind::ChildProcessError("Error when waiting")) + Err(Error::ChildProcessError("Error when waiting", e)) } WaitResult::EventDispatcher => { log::error!("OpenVPN Event server exited unexpectedly"); - Err(ErrorKind::EventDispatcherError.into()) + Err(Error::EventDispatcherExited) } } } @@ -356,16 +366,16 @@ impl<C: OpenVpnBuilder + 'static> OpenVpnMonitor<C> { if let Some(log_path) = self.log_path.take() { if let Ok(log) = fs::read_to_string(log_path) { if log.contains("There are no TAP-Windows adapters on this system") { - return ErrorKind::MissingTapAdapter.into(); + return Error::MissingTapAdapter; } if log.contains("CreateFile failed on TAP device") { - return ErrorKind::DisabledTapAdapter.into(); + return Error::DisabledTapAdapter; } } } } - ErrorKind::ChildProcessError("Died unexpectedly").into() + Error::ChildProcessDied } fn create_proxy_auth_file( @@ -388,8 +398,8 @@ impl<C: OpenVpnBuilder + 'static> OpenVpnMonitor<C> { proxy_resources: &ProxyResourceData, ) -> Result<Option<Box<dyn ProxyMonitor>>> { if let Some(ref settings) = proxy_settings { - let proxy_monitor = proxy::start_proxy(settings, proxy_resources) - .chain_err(|| ErrorKind::ProxyError("Failed to start proxy service".into()))?; + let proxy_monitor = + proxy::start_proxy(settings, proxy_resources).map_err(Error::StartProxyError)?; return Ok(Some(proxy_monitor)); } Ok(None) @@ -423,7 +433,7 @@ impl<C: OpenVpnBuilder + 'static> OpenVpnMonitor<C> { log::trace!("Using OpenVPN plugin at {}", path.display()); Ok(path) } else { - bail!(ErrorKind::PluginNotFound(path)); + Err(Error::PluginNotFound(path.display().to_string())) } } @@ -443,7 +453,7 @@ impl<C: OpenVpnBuilder + 'static> OpenVpnMonitor<C> { cmd.iproute_bin( which::which("ip") .compat() - .chain_err(|| ErrorKind::IpRouteNotFound)?, + .map_err(Error::IpRouteNotFound)?, ); cmd.remote(params.config.get_tunnel_endpoint().endpoint) .user_pass(user_pass_file) @@ -467,7 +477,7 @@ impl<C: OpenVpnBuilder + 'static> OpenVpnMonitor<C> { log::trace!("Using OpenVPN at {}", path.display()); Ok(path) } else { - bail!(ErrorKind::OpenVpnNotFound(path)); + Err(Error::OpenVpnNotFound(path.display().to_string())) } } @@ -746,8 +756,8 @@ mod tests { let error = OpenVpnMonitor::new_internal(builder, |_, _| {}, "", None, TempFile::new(), None, None) .unwrap_err(); - match error.kind() { - ErrorKind::ChildProcessError(_) => (), + match error { + Error::ChildProcessError(..) => (), _ => panic!("Wrong error"), } } diff --git a/talpid-core/src/tunnel/wireguard/mod.rs b/talpid-core/src/tunnel/wireguard/mod.rs index d1c0c451d9..79034f22cd 100644 --- a/talpid-core/src/tunnel/wireguard/mod.rs +++ b/talpid-core/src/tunnel/wireguard/mod.rs @@ -1,8 +1,9 @@ #![allow(missing_docs)] + use self::config::Config; use super::{TunnelEvent, TunnelMetadata}; use crate::routing; -use std::{path::Path, sync::mpsc}; +use std::{io, path::Path, sync::mpsc}; pub mod config; mod ping_monitor; @@ -13,37 +14,38 @@ pub use self::wireguard_go::WgGoTunnel; // amount of seconds to run `ping` until it returns. const PING_TIMEOUT: u16 = 7; -error_chain! { - errors { - /// Failed to setup a tunnel device - SetupTunnelDeviceError { - description("Failed to create tunnel device") - } - /// Failed to setup wireguard tunnel - StartWireguardError(status: i32) { - display("Failed to start wireguard tunnel - {}", status) - } - /// Failed to tear down wireguard tunnel - StopWireguardError(status: i32) { - display("Failed to stop wireguard tunnel - {}", status) - } - /// Failed to set up routing - SetupRoutingError { - display("Failed to setup routing") - } - /// Failed to move or craete a log file - PrepareLogFileError { - display("Failed to setup a logging file") - } - /// Tunnel interface name contained null bytes - InterfaceNameError { - display("Tunnel interface name contains null bytes") - } - /// Pinging timed out - PingTimeoutError { - display("Ping timed out") - } - } +pub type Result<T> = std::result::Result<T, Error>; + +/// Errors that can happen in the Wireguard tunnel monitor. +#[derive(err_derive::Error, Debug)] +pub enum Error { + /// Failed to setup a tunnel device. + #[error(display = "Failed to create tunnel device")] + SetupTunnelDeviceError(#[error(cause)] crate::network_interface::Error), + + /// Failed to setup wireguard tunnel. + #[error(display = "Failed to start wireguard tunnel - {}", status)] + StartWireguardError { status: i32 }, + + /// Failed to tear down wireguard tunnel. + #[error(display = "Failed to stop wireguard tunnel - {}", status)] + StopWireguardError { status: i32 }, + + /// Failed to set up routing. + #[error(display = "Failed to setup routing")] + SetupRoutingError(#[error(cause)] crate::routing::Error), + + /// Failed to move or craete a log file. + #[error(display = "Failed to setup a logging file")] + PrepareLogFileError(#[error(cause)] io::Error), + + /// Invalid tunnel interface name. + #[error(display = "Invalid tunnel interface name")] + InterfaceNameError(#[error(cause)] std::ffi::NulError), + + /// Pinging timed out. + #[error(display = "Ping timed out")] + PingTimeoutError, } /// Spawns and monitors a wireguard tunnel @@ -65,7 +67,7 @@ impl WireguardMonitor { on_event: F, ) -> Result<WireguardMonitor> { let tunnel = Box::new(WgGoTunnel::start_tunnel(&config, log_path)?); - let router = routing::RouteManager::new().chain_err(|| ErrorKind::SetupRoutingError)?; + let router = routing::RouteManager::new().map_err(Error::SetupRoutingError)?; let event_callback = Box::new(on_event.clone()); let (close_msg_sender, close_msg_receiver) = mpsc::channel(); let mut monitor = WireguardMonitor { @@ -111,7 +113,7 @@ impl WireguardMonitor { pub fn wait(mut self) -> Result<()> { let wait_result = match self.close_msg_receiver.recv() { - Ok(CloseMsg::PingErr) => Err(ErrorKind::PingTimeoutError.into()), + Ok(CloseMsg::PingErr) => Err(Error::PingTimeoutError), Ok(CloseMsg::Stop) => Ok(()), Err(_) => Ok(()), }; @@ -148,7 +150,7 @@ impl WireguardMonitor { let default_node = self .router .get_default_route_node() - .chain_err(|| ErrorKind::SetupRoutingError)?; + .map_err(Error::SetupRoutingError)?; // route endpoints with specific routes for peer in config.peers.iter() { @@ -163,7 +165,7 @@ impl WireguardMonitor { self.router .add_routes(required_routes) - .chain_err(|| ErrorKind::SetupRoutingError) + .map_err(Error::SetupRoutingError) } fn tunnel_metadata(&self, config: &Config) -> TunnelMetadata { diff --git a/talpid-core/src/tunnel/wireguard/wireguard_go.rs b/talpid-core/src/tunnel/wireguard/wireguard_go.rs index e713a4a190..059147286d 100644 --- a/talpid-core/src/tunnel/wireguard/wireguard_go.rs +++ b/talpid-core/src/tunnel/wireguard/wireguard_go.rs @@ -1,4 +1,4 @@ -use super::{Config, ErrorKind, Result, ResultExt, Tunnel}; +use super::{Config, Error, Result, Tunnel}; use crate::network_interface::{NetworkInterface, TunnelDevice}; use std::{ffi::CString, fs, os::unix::io::AsRawFd, path::Path}; @@ -14,25 +14,24 @@ pub struct WgGoTunnel { impl WgGoTunnel { pub fn start_tunnel(config: &Config, log_path: Option<&Path>) -> Result<Self> { - let mut tunnel_device = - TunnelDevice::new().chain_err(|| ErrorKind::SetupTunnelDeviceError)?; + let mut tunnel_device = TunnelDevice::new().map_err(Error::SetupTunnelDeviceError)?; for ip in config.tunnel.addresses.iter() { tunnel_device .set_ip(*ip) - .chain_err(|| ErrorKind::SetupTunnelDeviceError)?; + .map_err(Error::SetupTunnelDeviceError)?; } tunnel_device .set_up(true) - .chain_err(|| ErrorKind::SetupTunnelDeviceError)?; + .map_err(Error::SetupTunnelDeviceError)?; let interface_name: String = tunnel_device.get_name().to_string(); let log_file = prepare_log_file(log_path)?; let wg_config_str = config.to_userspace_format(); let iface_name = - CString::new(interface_name.as_bytes()).chain_err(|| ErrorKind::InterfaceNameError)?; + CString::new(interface_name.as_bytes()).map_err(Error::InterfaceNameError)?; let handle = unsafe { wgTurnOnWithFd( @@ -46,7 +45,7 @@ impl WgGoTunnel { }; if handle < 0 { - bail!(ErrorKind::StartWireguardError(handle)); + return Err(Error::StartWireguardError { status: handle }); } Ok(WgGoTunnel { @@ -61,7 +60,7 @@ impl WgGoTunnel { if let Some(handle) = self.handle.take() { let status = unsafe { wgTurnOff(handle) }; if status < 0 { - bail!(ErrorKind::StopWireguardError(status)) + return Err(Error::StopWireguardError { status }); } } return Ok(()); @@ -77,8 +76,7 @@ impl Drop for WgGoTunnel { } fn prepare_log_file(log_path: Option<&Path>) -> Result<fs::File> { - fs::File::create(log_path.unwrap_or("/dev/null".as_ref())) - .chain_err(|| ErrorKind::PrepareLogFileError) + fs::File::create(log_path.unwrap_or("/dev/null".as_ref())).map_err(Error::PrepareLogFileError) } impl Tunnel for WgGoTunnel { diff --git a/talpid-core/src/tunnel_state_machine/connecting_state.rs b/talpid-core/src/tunnel_state_machine/connecting_state.rs index a843fa1fdd..f044c61df1 100644 --- a/talpid-core/src/tunnel_state_machine/connecting_state.rs +++ b/talpid-core/src/tunnel_state_machine/connecting_state.rs @@ -126,17 +126,11 @@ impl ConnectingState { } Err(error) => match error { #[cfg(windows)] - error @ tunnel::Error( - tunnel::ErrorKind::OpenVpnTunnelMonitoringError( - tunnel::openvpn::ErrorKind::DisabledTapAdapter, - ), - _, + error @ tunnel::Error::OpenVpnTunnelMonitoringError( + tunnel::openvpn::Error::DisabledTapAdapter, ) - | error @ tunnel::Error( - tunnel::ErrorKind::OpenVpnTunnelMonitoringError( - tunnel::openvpn::ErrorKind::MissingTapAdapter, - ), - _, + | error @ tunnel::Error::OpenVpnTunnelMonitoringError( + tunnel::openvpn::Error::MissingTapAdapter, ) => { warn!( "{}", @@ -351,8 +345,8 @@ impl TunnelState for ConnectingState { } Err(error) => { log::error!("Failed to start tunnel: {}", error); - let block_reason = match *error.kind() { - tunnel::ErrorKind::EnableIpv6Error => BlockReason::Ipv6Unavailable, + let block_reason = match error { + tunnel::Error::EnableIpv6Error => BlockReason::Ipv6Unavailable, _ => BlockReason::StartTunnelError, }; BlockedState::enter(shared_values, block_reason) |
