diff options
| author | Emīls Piņķis <emils@mullvad.net> | 2018-10-25 18:38:25 +0100 |
|---|---|---|
| committer | Emīls Piņķis <emils@mullvad.net> | 2018-10-25 18:38:25 +0100 |
| commit | a2117c0403fa3b0a92293055abbe3dfbcd1762a1 (patch) | |
| tree | 70e4149a09c0849ff4222f62079590141b1b008e | |
| parent | 6550301700b954a96a561fd2c25e7a1201080ca4 (diff) | |
| download | mullvadvpn-a2117c0403fa3b0a92293055abbe3dfbcd1762a1.tar.xz mullvadvpn-a2117c0403fa3b0a92293055abbe3dfbcd1762a1.zip | |
Improve NM detection
| -rw-r--r-- | talpid-core/src/security/linux/dns/network_manager.rs | 71 |
1 files changed, 71 insertions, 0 deletions
diff --git a/talpid-core/src/security/linux/dns/network_manager.rs b/talpid-core/src/security/linux/dns/network_manager.rs index 6db4893336..62eb4d6cd0 100644 --- a/talpid-core/src/security/linux/dns/network_manager.rs +++ b/talpid-core/src/security/linux/dns/network_manager.rs @@ -7,11 +7,23 @@ use self::dbus::arg::{RefArg, Variant}; use self::dbus::stdintf::*; use self::dbus::BusType; +use std::fs::File; +use std::io::{BufRead, BufReader}; +use std::path::Path; + +use error_chain::ChainedError; + error_chain! { errors { NoNetworkManager { description("NetworkManager not detected") } + NMTooOld { + description("NetworkManager is too old") + } + NMNotManagingDns{ + description("NetworkManager is not managing DNS") + } } foreign_links { @@ -21,9 +33,12 @@ error_chain! { const NM_BUS: &str = "org.freedesktop.NetworkManager"; const NM_TOP_OBJECT: &str = "org.freedesktop.NetworkManager"; +const NM_DNS_MANAGER: &str = "org.freedesktop.NetworkManager.DnsManager"; +const NM_DNS_MANAGER_PATH: &str = "/org/freedesktop/NetworkManager/DnsManager"; const NM_OBJECT_PATH: &str = "/org/freedesktop/NetworkManager"; const RPC_TIMEOUT_MS: i32 = 1000; const GLOBAL_DNS_CONF_KEY: &str = "GlobalDnsConfiguration"; +const RC_MANAGEMENT_MODE_KEY: &str = "RcManager"; pub struct NetworkManager { dbus_connection: dbus::Connection, @@ -35,6 +50,7 @@ impl NetworkManager { let dbus_connection = dbus::Connection::get_private(BusType::System)?; let manager = NetworkManager { dbus_connection }; manager.ensure_network_manager_exists()?; + manager.ensure_resolv_conf_is_managed()?; Ok(manager) } @@ -46,6 +62,36 @@ impl NetworkManager { Ok(()) } + fn ensure_resolv_conf_is_managed(&self) -> Result<()> { + // check if NM is set to manage resolv.conf + let management_mode: Result<String> = self + .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); + + match management_mode { + Err(e) => { + debug!("Failed to get NM management mode - {}", e.display_chain()); + return Err(e); + } + Ok(management_mode) => { + if management_mode == "unmanaged" { + return Err(Error::from(ErrorKind::NMNotManagingDns)); + } + } + } + + let expected_resolv_conf = "/var/run/NetworkManager/resolv.conf"; + let actual_resolv_conf = "/etc/resolv.conf"; + if !compare_files(&expected_resolv_conf, &actual_resolv_conf) { + debug!("/etc/resolv.conf differs from reference resolv.conf, therefore NM is not manaing DNS"); + return Err(Error::from(ErrorKind::NMNotManagingDns)); + } + + Ok(()) + } + fn as_manager(&self) -> dbus::ConnPath<&dbus::Connection> { self.dbus_connection .with_path(NM_BUS, NM_OBJECT_PATH, RPC_TIMEOUT_MS) @@ -108,3 +154,28 @@ fn create_empty_global_settings() -> GlobalDnsConfig { fn as_variant<T: RefArg + 'static>(t: T) -> Variant<Box<RefArg>> { Variant(Box::new(t) as Box<RefArg>) } + +fn compare_files<P: AsRef<Path>>(a: &P, b: &P) -> bool { + let file_a = match File::open(&a).map(BufReader::new) { + Ok(file) => file, + Err(e) => { + debug!("Failed top open file {}: {}", a.as_ref().display(), e); + return false; + } + }; + let file_b = match File::open(&b).map(BufReader::new) { + Ok(file) => file, + Err(e) => { + debug!("Failed top open file {}: {}", b.as_ref().display(), e); + return false; + } + }; + + file_a + .lines() + .zip(file_b.lines()) + .all(|(a, b)| match (a, b) { + (Ok(a), Ok(b)) => a == b, + _ => false, + }) +} |
