summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorLinus Färnstrand <linus@mullvad.net>2019-03-29 17:15:11 +0100
committerLinus Färnstrand <linus@mullvad.net>2019-03-29 19:34:35 +0100
commit1b76ddbd488c3343ebca951bca0585b8613e7684 (patch)
tree353944d60400647426ef75dd4c9aaa092c7cded5
parentbf6a9a7ed566c663107eb865fa4ff53ae33bc19a (diff)
downloadmullvadvpn-1b76ddbd488c3343ebca951bca0585b8613e7684.tar.xz
mullvadvpn-1b76ddbd488c3343ebca951bca0585b8613e7684.zip
Get rid of error-chain in systemd_resolved DNS monitor
-rw-r--r--talpid-core/src/dns/linux/systemd_resolved.rs172
-rw-r--r--talpid-core/src/lib.rs17
2 files changed, 101 insertions, 88 deletions
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/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
+ }
+}