summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorEmīls <emils@mullvad.net>2020-11-04 17:47:40 +0000
committerEmīls <emils@mullvad.net>2020-11-05 12:28:55 +0000
commit8a5c92363c19d79b25a8da5a443a529737112b76 (patch)
tree8ca47d68e68fad3dba467cc3b0354dfde709d1dd
parentbc353efc368c32d9957d700885f75b3ad3a3e5dd (diff)
downloadmullvadvpn-8a5c92363c19d79b25a8da5a443a529737112b76.tar.xz
mullvadvpn-8a5c92363c19d79b25a8da5a443a529737112b76.zip
Prefer systemd-resolved over NM if it's working
-rw-r--r--CHANGELOG.md2
-rw-r--r--talpid-core/src/dns/linux/network_manager.rs74
-rw-r--r--talpid-core/src/dns/linux/systemd_resolved.rs9
3 files changed, 75 insertions, 10 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8f6d2b365a..38cb16bd10 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -80,6 +80,8 @@ Line wrap the file at 100 chars. Th
- Stop reconnecting when using WireGuard and NetworkManager.
- Apply DNS config quicker when managing DNS via NetworkManager.
- Fix routing rules sometimes being duplicated.
+- When NetworkManager is managing /etc/resolv.conf but ultimately using systemd-resolved, use
+ systemd-resolved directly to manage DNS.
### Security
diff --git a/talpid-core/src/dns/linux/network_manager.rs b/talpid-core/src/dns/linux/network_manager.rs
index e2695e5678..20e69f03d4 100644
--- a/talpid-core/src/dns/linux/network_manager.rs
+++ b/talpid-core/src/dns/linux/network_manager.rs
@@ -127,10 +127,7 @@ impl NetworkManager {
_ => (),
};
-
- let expected_resolv_conf = "/var/run/NetworkManager/resolv.conf";
- let actual_resolv_conf = "/etc/resolv.conf";
- if !eq_file_content(&expected_resolv_conf, &actual_resolv_conf) {
+ if !verify_etc_resolv_conf_contents() {
log::debug!("/etc/resolv.conf differs from reference resolv.conf, therefore NM is not managing DNS");
return Err(Error::NetworkManagerNotManagingDns);
}
@@ -412,6 +409,69 @@ impl NetworkManager {
}
}
+/// Given a DBus connection, verify that NM is up and running and capable of managing DNS via
+/// systemd-resolved. This includes verifying that NM is managing DNS via systemd-resolved and is
+/// controlling /etc/resolv.conf
+pub fn is_nm_managing_via_resolved(connection: &Connection) -> bool {
+ let check_nm = || -> Result<bool> {
+ let dns_mode: String = connection
+ .with_path(NM_BUS, NM_DNS_MANAGER_PATH, RPC_TIMEOUT_MS)
+ .get(NM_DNS_MANAGER, DNS_MODE_KEY)
+ .map_err(Error::Dbus)?;
+ if &dns_mode != "systemd-resolved" {
+ return Ok(false);
+ }
+
+
+ let rc_management_mode: String = connection
+ .with_path(NM_BUS, NM_DNS_MANAGER_PATH, RPC_TIMEOUT_MS)
+ .get(NM_DNS_MANAGER, RC_MANAGEMENT_MODE_KEY)
+ .map_err(Error::TooOldNetworkManager)?;
+
+ match rc_management_mode.as_str() {
+ // /etc/resolv.conf is managed via executing a command, can't verify that works, have
+ // to assume it does
+ "resolvconf" | "netconfig" => Ok(true),
+
+ "symlink" | "none" | "file" => {
+ let reload =
+ Message::new_method_call(NM_BUS, NM_OBJECT_PATH, NM_TOP_OBJECT, "Reload")
+ .map_err(Error::DbusMethodCall)?
+ .append1(0x02u32);
+ let _ = connection
+ .send_with_reply_and_block(reload, RPC_TIMEOUT_MS)
+ .map_err(Error::Dbus)?;
+ let result = verify_etc_resolv_conf_contents();
+ Ok(result)
+ }
+
+ // NM doesn't manage DNS at all
+ "unmanaged" => Ok(false),
+ unknown_rc_mode => {
+ log::error!("Unknown resolvconf management mode - {}", unknown_rc_mode);
+ Ok(false)
+ }
+ }
+ };
+ match check_nm() {
+ Ok(result) => result,
+ Err(err) => {
+ log::error!(
+ "Failed to check if NM is managing DNS via systemd-resolved: {}",
+ err
+ );
+ false
+ }
+ }
+}
+
+// Verify that the contents of /etc/resolv.conf match what NM expectes them to be.
+fn verify_etc_resolv_conf_contents() -> bool {
+ let expected_resolv_conf = "/var/run/NetworkManager/resolv.conf";
+ let actual_resolv_conf = "/etc/resolv.conf";
+ eq_file_content(&expected_resolv_conf, &actual_resolv_conf)
+}
+
fn device_is_ready(device_state: u32) -> bool {
/// Any state above `NM_DEVICE_STATE_IP_CONFIG` is considered to be an OK state to change the
/// DNS config. For the enums, see https://developer.gnome.org/NetworkManager/stable/nm-dbus-types.html#NMDeviceState
@@ -439,11 +499,11 @@ fn eq_file_content<P: AsRef<Path>>(a: &P, b: &P) -> bool {
}
};
- file_a
+ !file_a
.lines()
.zip(file_b.lines())
- .all(|(a, b)| match (a, b) {
- (Ok(a), Ok(b)) => a == b,
+ .any(|(a, b)| match (a, b) {
+ (Ok(a), Ok(b)) => a != b,
_ => false,
})
}
diff --git a/talpid-core/src/dns/linux/systemd_resolved.rs b/talpid-core/src/dns/linux/systemd_resolved.rs
index bacd416382..6abdd4990e 100644
--- a/talpid-core/src/dns/linux/systemd_resolved.rs
+++ b/talpid-core/src/dns/linux/systemd_resolved.rs
@@ -94,16 +94,19 @@ impl SystemdResolved {
};
systemd_resolved.ensure_resolved_exists()?;
- Self::ensure_resolv_conf_is_resolved_symlink()?;
+ if !super::network_manager::is_nm_managing_via_resolved(
+ &systemd_resolved.dbus_connection,
+ ) {
+ Self::ensure_resolv_conf_is_resolved_symlink()?;
+ }
Ok(systemd_resolved)
})();
match &result {
- Err(Error::NoSystemdResolved(_)) => (),
+ Ok(_) | Err(Error::NoSystemdResolved(_)) => (),
Err(error) => {
log::error!("systemd-resolved is not being used because: {}", error);
}
- Ok(_) => (),
}