diff options
| author | Linus Färnstrand <linus@mullvad.net> | 2019-03-29 20:24:35 +0100 |
|---|---|---|
| committer | Linus Färnstrand <linus@mullvad.net> | 2019-03-29 20:24:35 +0100 |
| commit | bcf731749bddebb2eb25ccc6a5b83b45de8fdb0e (patch) | |
| tree | 353944d60400647426ef75dd4c9aaa092c7cded5 | |
| parent | f019ca88e7387fd0a0871baed97fec047f55242f (diff) | |
| parent | 1b76ddbd488c3343ebca951bca0585b8613e7684 (diff) | |
| download | mullvadvpn-bcf731749bddebb2eb25ccc6a5b83b45de8fdb0e.tar.xz mullvadvpn-bcf731749bddebb2eb25ccc6a5b83b45de8fdb0e.zip | |
Merge branch 'eliminate-more-error-chain'
| -rw-r--r-- | Cargo.lock | 15 | ||||
| -rw-r--r-- | mullvad-daemon/src/management_interface.rs | 2 | ||||
| -rw-r--r-- | talpid-core/Cargo.toml | 1 | ||||
| -rw-r--r-- | talpid-core/src/dns/linux/mod.rs | 41 | ||||
| -rw-r--r-- | talpid-core/src/dns/linux/network_manager.rs | 48 | ||||
| -rw-r--r-- | talpid-core/src/dns/linux/resolvconf.rs | 58 | ||||
| -rw-r--r-- | talpid-core/src/dns/linux/systemd_resolved.rs | 172 | ||||
| -rw-r--r-- | talpid-core/src/dns/macos.rs | 45 | ||||
| -rw-r--r-- | talpid-core/src/lib.rs | 17 | ||||
| -rw-r--r-- | talpid-core/src/tunnel/openvpn.rs | 2 | ||||
| -rw-r--r-- | talpid-core/src/tunnel/wireguard/config.rs | 39 | ||||
| -rw-r--r-- | talpid-core/src/tunnel/wireguard/ping_monitor.rs | 39 | ||||
| -rw-r--r-- | talpid-core/src/winnet.rs | 52 | ||||
| -rw-r--r-- | talpid-ipc/Cargo.toml | 2 | ||||
| -rw-r--r-- | talpid-ipc/src/lib.rs | 43 |
15 files changed, 306 insertions, 270 deletions
diff --git a/Cargo.lock b/Cargo.lock index 76061d1a26..e4fac23be8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -306,6 +306,17 @@ dependencies = [ ] [[package]] +name = "derive_more" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "digest" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1970,6 +1981,7 @@ version = "0.1.0" dependencies = [ "atty 0.2.11 (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)", "err-derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2015,7 +2027,7 @@ version = "0.1.0" dependencies = [ "assert_matches 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "err-derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-client-core 0.5.0 (git+https://github.com/mullvad/jsonrpc-client-rs?rev=68aac55b)", "jsonrpc-client-ipc 0.5.0 (git+https://github.com/mullvad/jsonrpc-client-rs?rev=68aac55b)", @@ -2633,6 +2645,7 @@ dependencies = [ "checksum derive-try-from-primitive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "81dbd65eb15734b6d50dc6ac86f14f928462be0a5df6bda17761e909071ede5d" "checksum derive_builder 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c998e6ab02a828dd9735c18f154e14100e674ed08cb4e1938f0e4177543f439" "checksum derive_builder_core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "735e24ee9e5fa8e16b86da5007856e97d592e11867e45d76e0c0d0a164a0b757" +"checksum derive_more 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fbe9f11be34f800b3ecaaed0ec9ec2e015d1d0ba0c8644c1310f73d6e8994615" "checksum digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05f47366984d3ad862010e22c7ce81a7dbcaebbdfb37241a620f8b6596ee135c" "checksum dirs 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901" "checksum duct 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3640af123c78bedc20c1d3928e43cc0621e57011899d1ef917900c12fdb7a1ee" diff --git a/mullvad-daemon/src/management_interface.rs b/mullvad-daemon/src/management_interface.rs index a6bc12f8b8..22337d3b3c 100644 --- a/mullvad-daemon/src/management_interface.rs +++ b/mullvad-daemon/src/management_interface.rs @@ -231,7 +231,7 @@ pub struct ManagementInterfaceServer { } impl ManagementInterfaceServer { - pub fn start<T>(tunnel_tx: IntoSender<ManagementCommand, T>) -> talpid_ipc::Result<Self> + pub fn start<T>(tunnel_tx: IntoSender<ManagementCommand, T>) -> Result<Self, talpid_ipc::Error> where T: From<ManagementCommand> + 'static + Send, { diff --git a/talpid-core/Cargo.toml b/talpid-core/Cargo.toml index d7116a7457..1d2e0f5276 100644 --- a/talpid-core/Cargo.toml +++ b/talpid-core/Cargo.toml @@ -8,6 +8,7 @@ edition = "2018" [dependencies] atty = "0.2" +derive_more = "0.14" duct = "0.12" error-chain = "0.12" err-derive = "0.1.5" diff --git a/talpid-core/src/dns/linux/mod.rs b/talpid-core/src/dns/linux/mod.rs index 17ec6b7e39..5f378875f4 100644 --- a/talpid-core/src/dns/linux/mod.rs +++ b/talpid-core/src/dns/linux/mod.rs @@ -12,19 +12,30 @@ use std::{env, fmt, net::IpAddr, path::Path}; const RESOLV_CONF_PATH: &str = "/etc/resolv.conf"; -error_chain! { - errors { - NoDnsMonitor { - description("No suitable DNS monitor implementation detected") - } - } +pub type Result<T> = std::result::Result<T, Error>; - links { - Resolvconf(resolvconf::Error, resolvconf::ErrorKind); - StaticResolvConf(static_resolv_conf::Error, static_resolv_conf::ErrorKind); - SystemdResolved(systemd_resolved::Error, systemd_resolved::ErrorKind); - NetworkManager(network_manager::Error, network_manager::ErrorKind); - } +/// Errors that can happen in the Linux DNS monitor +#[derive(err_derive::Error, derive_more::From, Debug)] +pub enum Error { + /// Error in systemd-resolved DNS monitor + #[error(display = "Error in systemd-resolved DNS monitor")] + SystemdResolved(#[error(cause)] systemd_resolved::Error), + + /// Error in NetworkManager DNS monitor + #[error(display = "Error in NetworkManager DNS monitor")] + NetworkManager(#[error(cause)] network_manager::Error), + + /// Error in resolvconf DNS monitor + #[error(display = "Error in resolvconf DNS monitor")] + Resolvconf(#[error(cause)] resolvconf::Error), + + /// Error in static /etc/resolv.conf DNS monitor + #[error(display = "Error in static /etc/resolv.conf DNS monitor")] + StaticResolvConf(#[error(cause)] static_resolv_conf::Error), + + /// No suitable DNS monitor implementation detected + #[error(display = "No suitable DNS monitor implementation detected")] + NoDnsMonitor, } pub struct DnsMonitor { @@ -56,10 +67,10 @@ impl super::DnsMonitorT for DnsMonitor { } pub enum DnsMonitorHolder { - Resolvconf(Resolvconf), - StaticResolvConf(StaticResolvConf), SystemdResolved(SystemdResolved), NetworkManager(NetworkManager), + Resolvconf(Resolvconf), + StaticResolvConf(StaticResolvConf), } impl fmt::Display for DnsMonitorHolder { @@ -96,7 +107,7 @@ impl DnsMonitorHolder { .or_else(|_| NetworkManager::new().map(DnsMonitorHolder::NetworkManager)) .or_else(|_| Resolvconf::new().map(DnsMonitorHolder::Resolvconf)) .or_else(|_| StaticResolvConf::new().map(DnsMonitorHolder::StaticResolvConf)) - .chain_err(|| ErrorKind::NoDnsMonitor) + .map_err(|_| Error::NoDnsMonitor) } fn set(&mut self, interface: &str, servers: &[IpAddr]) -> Result<()> { diff --git a/talpid-core/src/dns/linux/network_manager.rs b/talpid-core/src/dns/linux/network_manager.rs index d42bb4efab..46777e8223 100644 --- a/talpid-core/src/dns/linux/network_manager.rs +++ b/talpid-core/src/dns/linux/network_manager.rs @@ -3,7 +3,6 @@ use dbus::{ stdintf::*, BusType, }; -use error_chain::ChainedError; use std::{ collections::HashMap, fs::File, @@ -12,22 +11,21 @@ use std::{ path::Path, }; -error_chain! { - errors { - NoNetworkManager { - description("NetworkManager not detected") - } - NmTooOld { - description("NetworkManager is too old") - } - NmNotManagingDns{ - description("NetworkManager is not managing DNS") - } - } +pub type Result<T> = std::result::Result<T, Error>; - foreign_links { - DbusError(dbus::Error); - } +#[derive(err_derive::Error, Debug)] +pub enum Error { + #[error(display = "NetworkManager not detected")] + NetworkManagerNotDetected(#[error(cause)] dbus::Error), + + #[error(display = "NetworkManager is too old")] + TooOldNetworkManager(#[error(cause)] dbus::Error), + + #[error(display = "NetworkManager is not managing DNS")] + NetworkManagerNotManagingDns, + + #[error(display = "Error while communicating over Dbus")] + Dbus(#[error(cause)] dbus::Error), } const NM_BUS: &str = "org.freedesktop.NetworkManager"; @@ -46,7 +44,8 @@ pub struct NetworkManager { impl NetworkManager { pub fn new() -> Result<Self> { - let dbus_connection = dbus::Connection::get_private(BusType::System)?; + let dbus_connection = + dbus::Connection::get_private(BusType::System).map_err(Error::Dbus)?; let manager = NetworkManager { dbus_connection }; manager.ensure_network_manager_exists()?; manager.ensure_resolv_conf_is_managed()?; @@ -57,7 +56,7 @@ impl NetworkManager { let _: Box<RefArg> = self .as_manager() .get(&NM_TOP_OBJECT, GLOBAL_DNS_CONF_KEY) - .chain_err(|| ErrorKind::NoNetworkManager)?; + .map_err(Error::NetworkManagerNotDetected)?; Ok(()) } @@ -67,16 +66,13 @@ impl NetworkManager { .dbus_connection .with_path(NM_BUS, NM_DNS_MANAGER_PATH, RPC_TIMEOUT_MS) .get(NM_DNS_MANAGER, RC_MANAGEMENT_MODE_KEY) - .chain_err(|| ErrorKind::NmTooOld); + .map_err(Error::TooOldNetworkManager); match management_mode { - Err(e) => { - log::debug!("Failed to get NM management mode - {}", e.display_chain()); - return Err(e); - } + Err(e) => return Err(e), Ok(management_mode) => { if management_mode == "unmanaged" { - return Err(Error::from(ErrorKind::NmNotManagingDns)); + return Err(Error::NetworkManagerNotManagingDns); } } } @@ -85,7 +81,7 @@ impl NetworkManager { let actual_resolv_conf = "/etc/resolv.conf"; if !eq_file_content(&expected_resolv_conf, &actual_resolv_conf) { log::debug!("/etc/resolv.conf differs from reference resolv.conf, therefore NM is not managing DNS"); - bail!(ErrorKind::NmNotManagingDns); + return Err(Error::NetworkManagerNotManagingDns); } Ok(()) @@ -103,7 +99,7 @@ impl NetworkManager { fn set_global_dns(&mut self, config: GlobalDnsConfig) -> Result<()> { self.as_manager() .set(NM_TOP_OBJECT, GLOBAL_DNS_CONF_KEY, config) - .map_err(|e| e.into()) + .map_err(Error::Dbus) } pub fn reset(&mut self) -> Result<()> { diff --git a/talpid-core/src/dns/linux/resolvconf.rs b/talpid-core/src/dns/linux/resolvconf.rs index 32b8fcd6b9..14ce3107a1 100644 --- a/talpid-core/src/dns/linux/resolvconf.rs +++ b/talpid-core/src/dns/linux/resolvconf.rs @@ -1,31 +1,30 @@ use std::{ collections::HashSet, ffi::OsStr, - fs, + fs, io, net::IpAddr, path::{Path, PathBuf}, }; use which::which; -error_chain! { - errors { - NoResolvconf { - description("Failed to detect 'resolvconf' program") - } - ResolvconfUsesResolved { - description("The existing resolvconf binary is just a symlink to systemd-resolved") - } - RunResolvconf { - description("Failed to execute 'resolvconf' program") - } - AddRecordError(stderr: String) { - description("Using 'resolvconf' to add a record failed") - display("Using 'resolvconf' to add a record failed: {}", stderr) - } - DeleteRecordError { - description("Using 'resolvconf' to delete a record failed") - } - } +pub type Result<T> = std::result::Result<T, Error>; + +#[derive(err_derive::Error, Debug)] +pub enum Error { + #[error(display = "Failed to detect 'resolvconf' program")] + NoResolvconf, + + #[error(display = "The resolvconf in PATH is just a symlink to systemd-resolved")] + ResolvconfUsesResolved, + + #[error(display = "Failed to execute 'resolvconf' program")] + RunResolvconf(#[error(cause)] io::Error), + + #[error(display = "Using 'resolvconf' to add a record failed: {}", stderr)] + AddRecordError { stderr: String }, + + #[error(display = "Using 'resolvconf' to delete a record failed")] + DeleteRecordError, } pub struct Resolvconf { @@ -35,10 +34,9 @@ pub struct Resolvconf { impl Resolvconf { pub fn new() -> Result<Self> { - let resolvconf_path = - which("resolvconf").map_err(|_| Error::from(ErrorKind::NoResolvconf))?; + let resolvconf_path = which("resolvconf").map_err(|_| Error::NoResolvconf)?; if Self::resolvconf_is_resolved_symlink(&resolvconf_path) { - bail!(ErrorKind::ResolvconfUsesResolved); + return Err(Error::ResolvconfUsesResolved); } Ok(Resolvconf { record_names: HashSet::new(), @@ -69,12 +67,12 @@ impl Resolvconf { .stderr_capture() .unchecked() .run() - .chain_err(|| ErrorKind::RunResolvconf)?; + .map_err(Error::RunResolvconf)?; - ensure!( - output.status.success(), - ErrorKind::AddRecordError(String::from_utf8_lossy(&output.stderr).to_string()) - ); + if !output.status.success() { + let stderr = String::from_utf8_lossy(&output.stderr).to_string(); + return Err(Error::AddRecordError { stderr }); + } self.record_names.insert(record_name); @@ -89,7 +87,7 @@ impl Resolvconf { .stderr_capture() .unchecked() .run() - .chain_err(|| ErrorKind::RunResolvconf)?; + .map_err(Error::RunResolvconf)?; if !output.status.success() { log::error!( @@ -97,7 +95,7 @@ impl Resolvconf { record_name, String::from_utf8_lossy(&output.stderr) ); - result = Err(Error::from(ErrorKind::DeleteRecordError)); + result = Err(Error::DeleteRecordError); } } diff --git a/talpid-core/src/dns/linux/systemd_resolved.rs b/talpid-core/src/dns/linux/systemd_resolved.rs index 6734a1819c..f8d0df11af 100644 --- a/talpid-core/src/dns/linux/systemd_resolved.rs +++ b/talpid-core/src/dns/linux/systemd_resolved.rs @@ -1,46 +1,56 @@ use super::RESOLV_CONF_PATH; -use crate::linux::iface_index; +use crate::{linux::iface_index, ErrorExt as _}; use dbus::{ arg::RefArg, stdintf::*, BusType, Interface, Member, Message, MessageItem, MessageItemArray, Signature, }; -use error_chain::ChainedError; use lazy_static::lazy_static; use libc::{AF_INET, AF_INET6}; use std::{ - fs, + fs, io, net::{IpAddr, Ipv4Addr}, path::Path, }; +pub type Result<T> = std::result::Result<T, Error>; -error_chain! { - errors { - NoSystemdResolved { - description("Systemd resolved not detected") - } - InvalidInterfaceName { - description("Invalid network interface name") - } - DbusRpcError { - description("Failed to perform RPC call on DBus") - } - GetLinkError { - description("Failed to find link interface in resolved manager") - } - SetDnsError { - description("Failed to configure DNS servers") - } - SetDomainsError { - description("Failed to configure DNS domains") - } - RevertDnsError { - description("Failed to revert DNS configuration") - } - DBusError { - description("Failed to initialize a connection to dbus") - } - } +#[derive(err_derive::Error, Debug)] +pub enum Error { + #[error(display = "Failed to initialize a connection to D-Bus")] + ConnectDBus(#[error(cause)] dbus::Error), + + #[error(display = "/etc/resolv.conf is not a symlink to Systemd resolved")] + NotSymlinkedToResolvConf, + + #[error(display = "Systemd resolved DNS 127.0.0.53, is not currently configured")] + NoDnsPointsToResolved, + + #[error(display = "Systemd resolved not detected")] + NoSystemdResolved(#[error(cause)] dbus::Error), + + #[error(display = "Failed to read Systemd resolved's resolv.conf")] + ReadResolvConfFailed(#[error(cause)] io::Error), + + #[error(display = "Failed to parse Systemd resolved's resolv.conf")] + ParseResolvConfFailed(#[error(cause)] resolv_conf::ParseError), + + #[error(display = "Invalid network interface name")] + InvalidInterfaceName(#[error(cause)] crate::linux::IfaceIndexLookupError), + + #[error(display = "Failed to find link interface in resolved manager")] + GetLinkError(#[error(cause)] Box<Error>), + + #[error(display = "Failed to configure DNS domains")] + SetDomainsError(#[error(cause)] dbus::Error), + + #[error(display = "Failed to revert DNS settings of interface: {}", _0)] + RevertDnsError(String, #[error(cause)] dbus::Error), + + #[error(display = "Failed to perform RPC call on D-Bus")] + DBusRpcError(#[error(cause)] dbus::Error), + + #[error(display = "Failed to match the returned D-Bus object with expected type")] + MatchDBusTypeError(#[error(cause)] dbus::arg::TypeMismatchError), } const DYNAMIC_RESOLV_CONF_PATH: &str = "/run/systemd/resolve/resolv.conf"; @@ -68,14 +78,15 @@ pub struct SystemdResolved { impl SystemdResolved { pub fn new() -> Result<Self> { let dbus_connection = - dbus::Connection::get_private(BusType::System).chain_err(|| ErrorKind::DBusError)?; + dbus::Connection::get_private(BusType::System).map_err(Error::ConnectDBus)?; let systemd_resolved = SystemdResolved { dbus_connection, interface_link: None, }; - SystemdResolved::ensure_resolved_is_active()?; systemd_resolved.ensure_resolved_exists()?; + Self::ensure_resolv_conf_is_resolved_symlink()?; + Self::ensure_resolv_conf_has_resolved_dns()?; Ok(systemd_resolved) } @@ -84,38 +95,39 @@ impl SystemdResolved { let _: Box<RefArg> = self .as_manager_object() .get(&MANAGER_INTERFACE, "DNS") - .chain_err(|| ErrorKind::NoSystemdResolved)?; - - Ok(()) - } - - fn ensure_resolved_is_active() -> Result<()> { - ensure!( - Self::resolv_conf_is_resolved_symlink() || Self::resolv_conf_has_resolved_dns()?, - ErrorKind::NoSystemdResolved - ); + .map_err(Error::NoSystemdResolved)?; Ok(()) } - fn resolv_conf_is_resolved_symlink() -> bool { - fs::read_link(RESOLV_CONF_PATH) + fn ensure_resolv_conf_is_resolved_symlink() -> Result<()> { + let is_correct_symlink = fs::read_link(RESOLV_CONF_PATH) .map(|resolv_conf_target| resolv_conf_target == Path::new(DYNAMIC_RESOLV_CONF_PATH)) - .unwrap_or_else(|_| false) + .unwrap_or_else(|_| false); + if is_correct_symlink { + Ok(()) + } else { + Err(Error::NotSymlinkedToResolvConf) + } } - fn resolv_conf_has_resolved_dns() -> Result<bool> { + fn ensure_resolv_conf_has_resolved_dns() -> Result<()> { let resolv_conf_contents = - fs::read_to_string(RESOLV_CONF_PATH).chain_err(|| ErrorKind::NoSystemdResolved)?; + fs::read_to_string(RESOLV_CONF_PATH).map_err(Error::ReadResolvConfFailed)?; let parsed_resolv_conf = resolv_conf::Config::parse(resolv_conf_contents) - .chain_err(|| ErrorKind::NoSystemdResolved)?; + .map_err(Error::ParseResolvConfFailed)?; let resolved_dns_server = resolv_conf::ScopedIp::V4(Ipv4Addr::from(RESOLVED_DNS_SERVER_ADDRESS)); - Ok(parsed_resolv_conf + if parsed_resolv_conf .nameservers .into_iter() - .any(|nameserver| nameserver == resolved_dns_server)) + .any(|nameserver| nameserver == resolved_dns_server) + { + Ok(()) + } else { + Err(Error::NoDnsPointsToResolved) + } } fn as_manager_object(&self) -> dbus::ConnPath<&dbus::Connection> { @@ -132,7 +144,9 @@ impl SystemdResolved { } pub fn set_dns(&mut self, interface_name: &str, servers: &[IpAddr]) -> Result<()> { - let link_object_path = self.fetch_link(interface_name)?; + let link_object_path = self + .fetch_link(interface_name) + .map_err(|e| Error::GetLinkError(Box::new(e)))?; if let Err(e) = self.reset() { log::debug!( "Failed to reset previous DNS settings - {}", @@ -147,19 +161,19 @@ impl SystemdResolved { } fn fetch_link(&self, interface_name: &str) -> Result<dbus::Path<'static>> { - let interface_index = - iface_index(interface_name).chain_err(|| ErrorKind::InvalidInterfaceName)?; + let interface_index = iface_index(interface_name).map_err(Error::InvalidInterfaceName)?; let mut reply = self .as_manager_object() .method_call_with_args(&MANAGER_INTERFACE, &GET_LINK_METHOD, |message| { message.append_items(&[MessageItem::Int32(interface_index as i32)]); }) - .chain_err(|| ErrorKind::DbusRpcError)?; - - let result = reply.as_result().chain_err(|| ErrorKind::GetLinkError)?; - - result.read1().chain_err(|| ErrorKind::GetLinkError) + .map_err(Error::DBusRpcError)?; + reply + .as_result() + .map_err(Error::DBusRpcError)? + .read1() + .map_err(Error::MatchDBusTypeError) } fn set_link_dns<'a, 'b: 'a>( @@ -168,18 +182,12 @@ impl SystemdResolved { servers: &[IpAddr], ) -> Result<()> { let server_addresses = build_addresses_argument(servers); - - let mut reply = self - .as_link_object(link_object_path.clone()) + self.as_link_object(link_object_path.clone()) .method_call_with_args(&LINK_INTERFACE, &SET_DNS_METHOD, |message| { message.append_items(&[server_addresses]); }) - .chain_err(|| ErrorKind::DbusRpcError)?; - - reply - .as_result() - .map(|_| ()) - .chain_err(|| ErrorKind::SetDnsError)?; + .and_then(|mut reply| reply.as_result().map(|_| ())) + .map_err(Error::DBusRpcError)?; // set the search domain to catch all DNS requests, forces the link to be the prefered // resolver, otherwise systemd-resolved will use other interfaces to do DNS lookups @@ -194,43 +202,31 @@ impl SystemdResolved { .expect("failed to construct a new dbus message") .append1(dns_domains); - let mut reply = self - .dbus_connection + self.dbus_connection .send_with_reply_and_block(msg, RPC_TIMEOUT_MS) - .chain_err(|| ErrorKind::SetDomainsError)?; - reply - .as_result() - .map(|_| ()) - .chain_err(|| ErrorKind::SetDomainsError) + .and_then(|mut reply| reply.as_result().map(|_| ())) + .map_err(Error::SetDomainsError) } pub fn reset(&mut self) -> Result<()> { if let Some((interface_name, link_object_path)) = self.interface_link.take() { self.revert_link(link_object_path, &interface_name) - .chain_err(|| { - format!( - "Failed to revert DNS settings of interface: {}", - interface_name - ) - })?; + .map_err(|e| Error::RevertDnsError(interface_name.to_owned(), e)) } else { log::trace!("No DNS settings to reset"); - }; - Ok(()) + Ok(()) + } } fn revert_link( &mut self, link_object_path: dbus::Path<'static>, interface_name: &str, - ) -> Result<()> { + ) -> std::result::Result<(), dbus::Error> { let link = self.as_link_object(link_object_path); match link.method_call_with_args(&LINK_INTERFACE, &REVERT_METHOD, |_| {}) { - Ok(mut reply) => reply - .as_result() - .map(|_| ()) - .chain_err(|| ErrorKind::RevertDnsError), + Ok(mut reply) => reply.as_result().map(|_| ()), Err(error) => { if error.name() == Some("org.freedesktop.DBus.Error.UnknownObject") { log::info!( @@ -239,7 +235,7 @@ impl SystemdResolved { ); Ok(()) } else { - Err(error).chain_err(|| ErrorKind::DbusRpcError) + Err(error) } } } diff --git a/talpid-core/src/dns/macos.rs b/talpid-core/src/dns/macos.rs index 3dfc8d2be4..4c735e9e44 100644 --- a/talpid-core/src/dns/macos.rs +++ b/talpid-core/src/dns/macos.rs @@ -1,4 +1,3 @@ -use error_chain::ChainedError; use log::{debug, trace}; use parking_lot::Mutex; use std::{ @@ -22,11 +21,18 @@ use system_configuration::{ sys::schema_definitions::kSCPropNetDNSServerAddresses, }; -error_chain! { - errors { - SettingDnsFailed { description("Error while setting DNS servers") } - DynamicStoreInitError { description("Failed to initialize dynamic store") } - } +pub type Result<T> = std::result::Result<T, Error>; + +/// Errors that can happen when setting/monitoring DNS on macOS. +#[derive(err_derive::Error, Debug)] +pub enum Error { + /// Error while setting DNS servers + #[error(display = "Error while setting DNS servers")] + SettingDnsFailed, + + /// Failed to initialize dynamic store + #[error(display = "Failed to initialize dynamic store")] + DynamicStoreInitError, } const STATE_PATH_PATTERN: &str = "State:/Network/Service/.*/DNS"; @@ -88,7 +94,7 @@ impl DnsSettings { if store.set(path, self.0.clone()) { Ok(()) } else { - bail!(ErrorKind::SettingDnsFailed) + Err(Error::SettingDnsFailed) } } @@ -187,7 +193,7 @@ impl super::DnsMonitorT for DnsMonitor { } else { debug!("Removing DNS for {}", service_path); if !self.store.remove(CFString::new(&service_path)) { - bail!(ErrorKind::SettingDnsFailed); + return Err(Error::SettingDnsFailed); } } } @@ -235,7 +241,7 @@ fn create_dynamic_store(state: Arc<Mutex<Option<State>>>) -> Result<SCDynamicSto trace!("Registered for dynamic store notifications"); Ok(store) } else { - bail!(ErrorKind::DynamicStoreInitError) + Err(Error::DynamicStoreInitError) } } @@ -260,9 +266,7 @@ fn dns_change_callback( trace!("Not injecting DNS at this time"); } Some(ref mut state) => { - if let Err(e) = dns_change_callback_internal(store, changed_keys, state) { - log::error!("{}", e.display_chain()); - } + dns_change_callback_internal(store, changed_keys, state); } } } @@ -271,7 +275,7 @@ fn dns_change_callback_internal( store: SCDynamicStore, changed_keys: CFArray<CFString>, state: &mut State, -) -> Result<()> { +) { for path in &changed_keys { let should_set_dns = match DnsSettings::load(&store, path.clone()) { None => { @@ -291,10 +295,9 @@ fn dns_change_callback_internal( } }; if should_set_dns { - state - .dns_settings - .save(&store, path.clone()) - .chain_err(|| format!("Failed changing DNS for {}", *path))?; + if let Err(e) = state.dns_settings.save(&store, path.clone()) { + log::error!("Failed changing DNS for {}: {}", *path, e); + } // If we changed a "state" entry, also set the corresponding "setup" entry. if let Some(setup_path_str) = state_to_setup_path(&path.to_string()) { let setup_path = CFString::new(&setup_path_str); @@ -304,14 +307,12 @@ fn dns_change_callback_internal( DnsSettings::load(&store, setup_path.clone()), ); } - state - .dns_settings - .save(&store, setup_path.clone()) - .chain_err(|| format!("Failed changing DNS for {}", setup_path))?; + if let Err(e) = state.dns_settings.save(&store, setup_path.clone()) { + log::error!("Failed changing DNS for {}: {}", setup_path, e); + } } } } - Ok(()) } /// Read all existing DNS settings and return them. diff --git a/talpid-core/src/lib.rs b/talpid-core/src/lib.rs index 40f450aa72..1147e40fd6 100644 --- a/talpid-core/src/lib.rs +++ b/talpid-core/src/lib.rs @@ -59,3 +59,20 @@ mod mktemp; /// Misc utilities for the Linux platform. #[cfg(target_os = "linux")] mod linux; + + +trait ErrorExt { + fn display_chain(&self) -> String; +} + +impl<E: std::error::Error> ErrorExt for E { + fn display_chain(&self) -> String { + let mut s = format!("Error: {}", self); + let mut source = self.source(); + while let Some(error) = source { + s.push_str(&format!("\nCaused by: {}", error)); + source = error.source(); + } + s + } +} diff --git a/talpid-core/src/tunnel/openvpn.rs b/talpid-core/src/tunnel/openvpn.rs index 0d0c4a932f..d3e2b9858f 100644 --- a/talpid-core/src/tunnel/openvpn.rs +++ b/talpid-core/src/tunnel/openvpn.rs @@ -569,7 +569,7 @@ mod event_server { use uuid; /// Construct and start the IPC server with the given event listener callback. - pub fn start<L>(on_event: L) -> talpid_ipc::Result<talpid_ipc::IpcServer> + pub fn start<L>(on_event: L) -> std::result::Result<talpid_ipc::IpcServer, talpid_ipc::Error> where L: Fn(openvpn_plugin::EventType, HashMap<String, String>) + Send + Sync + 'static, { diff --git a/talpid-core/src/tunnel/wireguard/config.rs b/talpid-core/src/tunnel/wireguard/config.rs index 97d7832a60..63c99dfdce 100644 --- a/talpid-core/src/tunnel/wireguard/config.rs +++ b/talpid-core/src/tunnel/wireguard/config.rs @@ -17,24 +17,20 @@ pub struct Config { const SMALLEST_IPV6_MTU: u16 = 1420; const DEFAULT_MTU: u16 = SMALLEST_IPV6_MTU; -error_chain! { - errors { - InvalidTunnelIpError { - description("No valid tunnel IP"), - } +#[derive(err_derive::Error, Debug)] +pub enum Error { + #[error(display = "No valid tunnel IP")] + InvalidTunnelIpError, - InvalidPeerIpError { - description("Supplied peer has no valid IPs") - } + #[error(display = "Supplied peer has no valid IPs")] + InvalidPeerIpError, - NoPeersSuppliedError{ - description("No peers supplied") - } - } + #[error(display = "No peers supplied")] + NoPeersSuppliedError, } impl Config { - pub fn from_parameters(params: &wireguard::TunnelParameters) -> Result<Config> { + pub fn from_parameters(params: &wireguard::TunnelParameters) -> Result<Config, Error> { let tunnel = params.connection.tunnel.clone(); let peer = vec![params.connection.peer.clone()]; Self::new( @@ -52,8 +48,10 @@ impl Config { connection_config: &wireguard::ConnectionConfig, wg_options: &wireguard::TunnelOptions, generic_options: &GenericTunnelOptions, - ) -> Result<Config> { - ensure!(!peers.is_empty(), ErrorKind::NoPeersSuppliedError); + ) -> Result<Config, Error> { + if peers.is_empty() { + return Err(Error::NoPeersSuppliedError); + } let mtu = wg_options.mtu.unwrap_or(DEFAULT_MTU); let is_ipv6_enabled = mtu >= SMALLEST_IPV6_MTU && generic_options.enable_ipv6; @@ -64,7 +62,9 @@ impl Config { .cloned() .filter(|ip| ip.is_ipv4() || is_ipv6_enabled) .collect(); - ensure!(!peer.allowed_ips.is_empty(), ErrorKind::InvalidPeerIpError); + if peer.allowed_ips.is_empty() { + return Err(Error::InvalidPeerIpError); + } } tunnel.addresses = tunnel @@ -72,10 +72,9 @@ impl Config { .into_iter() .filter(|ip| ip.is_ipv4() || is_ipv6_enabled) .collect(); - ensure!( - !tunnel.addresses.is_empty(), - ErrorKind::InvalidTunnelIpError - ); + if tunnel.addresses.is_empty() { + return Err(Error::InvalidTunnelIpError); + } Ok(Config { tunnel, diff --git a/talpid-core/src/tunnel/wireguard/ping_monitor.rs b/talpid-core/src/tunnel/wireguard/ping_monitor.rs index d471971ca6..69f22fc83f 100644 --- a/talpid-core/src/tunnel/wireguard/ping_monitor.rs +++ b/talpid-core/src/tunnel/wireguard/ping_monitor.rs @@ -1,23 +1,25 @@ -use std::{net::IpAddr, thread, time}; +use std::{ + io, + net::IpAddr, + thread, + time::{Duration, Instant}, +}; -error_chain! { - errors { - PingError{ - description("Failed to run ping") - } +#[derive(err_derive::Error, Debug)] +pub enum Error { + #[error(display = "Failed to run ping command")] + PingError(#[error(cause)] io::Error), - TimeoutError { - description("Ping timed out") - } - } + #[error(display = "Ping timed out")] + TimeoutError, } -pub fn monitor_ping(ip: IpAddr, timeout_secs: u16, interface: &str) -> Result<()> { +pub fn monitor_ping(ip: IpAddr, timeout_secs: u16, interface: &str) -> Result<(), Error> { loop { - let start = time::Instant::now(); + let start = Instant::now(); ping(ip, timeout_secs, &interface, false)?; if let Some(remaining) = - time::Duration::from_secs(timeout_secs.into()).checked_sub(start.elapsed()) + Duration::from_secs(timeout_secs.into()).checked_sub(start.elapsed()) { thread::sleep(remaining); } @@ -29,14 +31,15 @@ pub fn ping( timeout_secs: u16, interface: &str, exit_on_first_reply: bool, -) -> Result<()> { +) -> Result<(), Error> { let output = ping_cmd(ip, timeout_secs, interface, exit_on_first_reply) .run() - .chain_err(|| ErrorKind::PingError)?; - if !output.status.success() { - bail!(ErrorKind::TimeoutError); + .map_err(Error::PingError)?; + if output.status.success() { + Ok(()) + } else { + Err(Error::TimeoutError) } - Ok(()) } fn ping_cmd( diff --git a/talpid-core/src/winnet.rs b/talpid-core/src/winnet.rs index f6a932acfb..1211cd7545 100644 --- a/talpid-core/src/winnet.rs +++ b/talpid-core/src/winnet.rs @@ -3,19 +3,17 @@ use std::ptr; use libc::{c_char, c_void, wchar_t}; use widestring::WideCString; -error_chain! { - errors{ - /// Failure to set metrics of network interfaces - MetricApplication{ - description("Failed to set the metrics for a network interface") - } - InvalidInterfaceAlias{ - description("Supplied interface alias is invalid") - } - GetIpv6Status { - description("Failed to read IPv6 status on the TAP network interface") - } - } +#[derive(err_derive::Error, Debug)] +pub enum Error { + /// Failure to set metrics of network interfaces + #[error(display = "Failed to set the metrics for a network interface")] + MetricApplication, + + #[error(display = "Supplied interface alias is invalid")] + InvalidInterfaceAlias(#[error(cause)] widestring::NulError<u16>), + + #[error(display = "Failed to read IPv6 status on the TAP network interface")] + GetIpv6Status, } pub type ErrorSink = extern "system" fn(msg: *const c_char, ctx: *mut c_void); @@ -30,9 +28,9 @@ pub extern "system" fn error_sink(msg: *const c_char, _ctx: *mut c_void) { } /// Returns true if metrics were changed, false otherwise -pub fn ensure_top_metric_for_interface(interface_alias: &str) -> Result<bool> { +pub fn ensure_top_metric_for_interface(interface_alias: &str) -> Result<bool, Error> { let interface_alias_ws = - WideCString::from_str(interface_alias).chain_err(|| ErrorKind::InvalidInterfaceAlias)?; + WideCString::from_str(interface_alias).map_err(Error::InvalidInterfaceAlias)?; let metric_result = unsafe { WinRoute_EnsureTopMetric( @@ -48,11 +46,14 @@ pub fn ensure_top_metric_for_interface(interface_alias: &str) -> Result<bool> { // Metrics changed 1 => Ok(true), // Failure - 2 => Err(Error::from(ErrorKind::MetricApplication)), + 2 => Err(Error::MetricApplication), // Unexpected value - _ => { - log::error!("Unexpected return code from WinRoute_EnsureTopMetric"); - Err(Error::from(ErrorKind::MetricApplication)) + i => { + log::error!( + "Unexpected return code from WinRoute_EnsureTopMetric: {}", + i + ); + Err(Error::MetricApplication) } } } @@ -68,7 +69,7 @@ extern "system" { /// Checks if IPv6 is enabled for the TAP interface -pub fn get_tap_interface_ipv6_status() -> Result<bool> { +pub fn get_tap_interface_ipv6_status() -> Result<bool, Error> { let tap_ipv6_status = unsafe { GetTapInterfaceIpv6Status(Some(error_sink), ptr::null_mut()) }; match tap_ipv6_status { @@ -77,11 +78,14 @@ pub fn get_tap_interface_ipv6_status() -> Result<bool> { // Disabled 1 => Ok(false), // Failure - 2 => Err(Error::from(ErrorKind::GetIpv6Status)), + 2 => Err(Error::GetIpv6Status), // Unexpected value - _ => { - log::error!("Unexpected return code from GetTapInterfaceIpv6Status"); - Err(Error::from(ErrorKind::GetIpv6Status)) + i => { + log::error!( + "Unexpected return code from GetTapInterfaceIpv6Status: {}", + i + ); + Err(Error::GetIpv6Status) } } } diff --git a/talpid-ipc/Cargo.toml b/talpid-ipc/Cargo.toml index e813011f37..e0838acfd5 100644 --- a/talpid-ipc/Cargo.toml +++ b/talpid-ipc/Cargo.toml @@ -7,7 +7,7 @@ license = "GPL-3.0" edition = "2018" [dependencies] -error-chain = "0.12" +err-derive = "0.1.5" serde = "1.0" serde_json = "1.0" log = "0.4" diff --git a/talpid-ipc/src/lib.rs b/talpid-ipc/src/lib.rs index a84a982aa7..60192712cd 100644 --- a/talpid-ipc/src/lib.rs +++ b/talpid-ipc/src/lib.rs @@ -6,14 +6,8 @@ //! GNU General Public License as published by the Free Software Foundation, either version 3 of //! the License, or (at your option) any later version. -#![recursion_limit = "128"] - -#[macro_use] -extern crate error_chain; - - use futures::Future; -use std::thread; +use std::{io, thread}; use jsonrpc_core::{MetaIoHandler, Metadata}; use jsonrpc_ipc_server::{MetaExtractor, NoopExtractor, SecurityAttributes, Server, ServerBuilder}; @@ -24,16 +18,16 @@ use std::fmt; /// An Id created by the Ipc server that the client can use to connect to it pub type IpcServerId = String; -error_chain! { - errors { - IpcServerError { - description("Error in IPC server") - } +#[derive(err_derive::Error, Debug)] +pub enum Error { + #[error(display = "Unable to start IPC server")] + StartServerError(#[error(cause)] io::Error), - PermissionsError { - description("Unable to set permissions for IPC endpoint") - } - } + #[error(display = "Error in IPC server")] + IpcServerError(#[error(cause)] io::Error), + + #[error(display = "Unable to set permissions for IPC endpoint")] + PermissionsError(#[error(cause)] io::Error), } @@ -43,7 +37,10 @@ pub struct IpcServer { } impl IpcServer { - pub fn start<M: Metadata + Default>(handler: MetaIoHandler<M>, path: &str) -> Result<Self> { + pub fn start<M: Metadata + Default>( + handler: MetaIoHandler<M>, + path: &str, + ) -> Result<Self, Error> { Self::start_with_metadata(handler, NoopExtractor, path) } @@ -51,17 +48,17 @@ impl IpcServer { handler: MetaIoHandler<M>, meta_extractor: E, path: &str, - ) -> Result<Self> + ) -> Result<Self, Error> where M: Metadata + Default, E: MetaExtractor<M>, { - let security_attributes = SecurityAttributes::allow_everyone_create() - .chain_err(|| ErrorKind::PermissionsError)?; + let security_attributes = + SecurityAttributes::allow_everyone_create().map_err(Error::PermissionsError)?; let server = ServerBuilder::with_meta_extractor(handler, meta_extractor) .set_security_attributes(security_attributes) .start(path) - .chain_err(|| ErrorKind::IpcServerError) + .map_err(Error::StartServerError) .and_then(|(fut, start, server)| { thread::spawn(move || tokio::run(fut)); start @@ -69,7 +66,7 @@ impl IpcServer { .expect("server panicked") .map(Err) .unwrap_or_else(|| Ok(server)) - .chain_err(|| ErrorKind::IpcServerError) + .map_err(Error::IpcServerError) }) .map(|server| IpcServer { path: path.to_owned(), @@ -80,7 +77,7 @@ impl IpcServer { { use std::{fs, os::unix::fs::PermissionsExt}; fs::set_permissions(&path, PermissionsExt::from_mode(0o766)) - .chain_err(|| ErrorKind::PermissionsError)?; + .map_err(Error::PermissionsError)?; } Ok(server) } |
