diff options
| author | Emīls <emils@mullvad.net> | 2020-12-15 17:48:48 +0000 |
|---|---|---|
| committer | Emīls <emils@mullvad.net> | 2020-12-15 17:48:48 +0000 |
| commit | 691d14ffd8bb3f7dc53549b173646b07c17cd9b4 (patch) | |
| tree | 0ebe2ffdf2f7b6b71626c6d1900ab620e637df80 | |
| parent | c9994fc0348b9b2c36df6945fc31983af94f7f93 (diff) | |
| parent | 45f6dbcca5c920d3c61aadc542f1391bcc45975a (diff) | |
| download | mullvadvpn-691d14ffd8bb3f7dc53549b173646b07c17cd9b4.tar.xz mullvadvpn-691d14ffd8bb3f7dc53549b173646b07c17cd9b4.zip | |
Merge branch 'linux-add-resolved-conf-path' into master
| -rw-r--r-- | CHANGELOG.md | 3 | ||||
| -rw-r--r-- | talpid-core/src/dns/linux/systemd_resolved.rs | 45 |
2 files changed, 37 insertions, 11 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 02aeb18a78..ed29c92eb2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,9 @@ Line wrap the file at 100 chars. Th #### Android - Allow to configure the tunnel to use custom DNS servers. +#### Linux +- Improved compatiblitiy with newer versions of systemd-resolved. + ## [2020.8-beta2] - 2020-12-11 This release is for desktop only. diff --git a/talpid-core/src/dns/linux/systemd_resolved.rs b/talpid-core/src/dns/linux/systemd_resolved.rs index 5ebdb34eb9..de754345cd 100644 --- a/talpid-core/src/dns/linux/systemd_resolved.rs +++ b/talpid-core/src/dns/linux/systemd_resolved.rs @@ -6,7 +6,7 @@ use dbus::{ }; use lazy_static::lazy_static; use libc::{AF_INET, AF_INET6}; -use std::{fs, io, net::IpAddr, path::Path, sync::Arc, time::Duration}; +use std::{fs, net::IpAddr, path::Path, sync::Arc, time::Duration}; use talpid_types::ErrorExt as _; pub type Result<T> = std::result::Result<T, Error>; @@ -20,15 +20,12 @@ pub enum Error { #[error(display = "/etc/resolv.conf is not a symlink to Systemd resolved")] NotSymlinkedToResolvConf, + #[error(display = "Static stub file does not point to localhost")] + StaticStubNotPointingToLocalhost, + #[error(display = "Systemd resolved not detected")] NoSystemdResolved(#[error(source)] dbus::Error), - #[error(display = "Failed to read Systemd resolved's resolv.conf")] - ReadResolvConfFailed(#[error(source)] io::Error), - - #[error(display = "Failed to parse Systemd resolved's resolv.conf")] - ParseResolvConfFailed(#[error(source)] resolv_conf::ParseError), - #[error(display = "Invalid network interface name")] InvalidInterfaceName(#[error(source)] crate::linux::IfaceIndexLookupError), @@ -43,9 +40,6 @@ pub enum Error { #[error(display = "Failed to perform RPC call on D-Bus")] DBusRpcError(#[error(source)] dbus::Error), - - #[error(display = "Failed to match the returned D-Bus object with expected type")] - MatchDBusTypeError(#[error(source)] dbus::arg::TypeMismatchError), } lazy_static! { @@ -57,6 +51,7 @@ lazy_static! { ]; } +const STATIC_STUB_PATH: &str = "/usr/lib/systemd/resolv.conf"; const RESOLVED_BUS: &str = "org.freedesktop.resolve1"; const RPC_TIMEOUT: Duration = Duration::from_secs(1); @@ -105,7 +100,9 @@ impl SystemdResolved { // this will mean adding 1 and 2 seconds of latency to DNS queries, other times our // resolver won't be considered at all. In this case, it's better to fall back to cruder // management methods. - if Self::path_is_resolvconf_stub(&link_target) { + if Self::path_is_resolvconf_stub(&link_target) + || Self::resolv_conf_is_static_stub(&link_target)? + { Ok(()) } else { Err(Error::NotSymlinkedToResolvConf) @@ -131,6 +128,32 @@ impl SystemdResolved { } } + /// Checks if path is pointing to the systemd-resolved _static_ resolv.conf file. If it's not, + /// it returns false, otherwise it checks whether the static stub file points to the local + /// resolver. If not, the file has been _meddled_ with, so we can't trust it. + fn resolv_conf_is_static_stub(link_path: &Path) -> Result<bool> { + if link_path == &STATIC_STUB_PATH.as_ref() { + let points_to_localhost = fs::read_to_string(link_path) + .map(|contents| { + let parts = contents.trim().split(' '); + parts + .map(str::parse::<IpAddr>) + .map(|maybe_ip| maybe_ip.map(|addr| addr.is_loopback()).unwrap_or(false)) + .any(|is_loopback| is_loopback) + }) + .unwrap_or(false); + + if points_to_localhost { + Ok(true) + } else { + Err(Error::StaticStubNotPointingToLocalhost) + } + } else { + Ok(false) + } + } + + fn as_manager_object(&self) -> Proxy<'_, &SyncConnection> { Proxy::new( RESOLVED_BUS, |
