summaryrefslogtreecommitdiffhomepage
path: root/talpid-dbus
diff options
context:
space:
mode:
authorDavid Lönnhager <david.l@mullvad.net>2021-05-21 10:53:18 +0200
committerDavid Lönnhager <david.l@mullvad.net>2021-06-09 15:55:07 +0200
commitf8c4a9879afb26482108ae02f3e65682d7d7ab83 (patch)
tree654461afe3da1014b547c0cfe2a7f93f1aff6ccc /talpid-dbus
parent6d9a1ea3a2502b0d4b3145231b7922984d77632a (diff)
downloadmullvadvpn-f8c4a9879afb26482108ae02f3e65682d7d7ab83.tar.xz
mullvadvpn-f8c4a9879afb26482108ae02f3e65682d7d7ab83.zip
Infer and monitor interfaces for DNS config
Diffstat (limited to 'talpid-dbus')
-rw-r--r--talpid-dbus/Cargo.toml1
-rw-r--r--talpid-dbus/src/systemd_resolved.rs156
2 files changed, 140 insertions, 17 deletions
diff --git a/talpid-dbus/Cargo.toml b/talpid-dbus/Cargo.toml
index 5685daf922..7ae6403254 100644
--- a/talpid-dbus/Cargo.toml
+++ b/talpid-dbus/Cargo.toml
@@ -12,3 +12,4 @@ lazy_static = "1.0"
log = "0.4"
libc = "0.2"
talpid-types = { path = "../talpid-types" }
+tokio = { version = "0.2", features = [ "blocking" ] }
diff --git a/talpid-dbus/src/systemd_resolved.rs b/talpid-dbus/src/systemd_resolved.rs
index 2fd2f14956..2a5b7b2b02 100644
--- a/talpid-dbus/src/systemd_resolved.rs
+++ b/talpid-dbus/src/systemd_resolved.rs
@@ -52,6 +52,9 @@ pub enum Error {
#[error(display = "Failed to remove a match for DNS config updates")]
DnsUpdateRemoveMatchError(#[error(source)] dbus::Error),
+
+ #[error(display = "Async D-Bus task failed")]
+ AsyncTaskError(#[error(source)] tokio::task::JoinError),
}
lazy_static! {
@@ -73,6 +76,7 @@ const RPC_TIMEOUT: Duration = Duration::from_secs(1);
const LINK_INTERFACE: &str = "org.freedesktop.resolve1.Link";
const MANAGER_INTERFACE: &str = "org.freedesktop.resolve1.Manager";
+const DNS_DOMAINS: &str = "Domains";
const DNS_SERVERS: &str = "DNS";
const GET_LINK_METHOD: &str = "GetLink";
const SET_DNS_METHOD: &str = "SetDNS";
@@ -84,12 +88,18 @@ pub struct SystemdResolved {
pub dbus_connection: Arc<SyncConnection>,
}
+#[derive(Clone)]
pub struct DnsState {
pub interface_path: dbus::Path<'static>,
pub interface_index: u32,
pub set_servers: Vec<IpAddr>,
}
+#[derive(Clone)]
+pub struct AsyncHandle {
+ dbus_interface: SystemdResolved,
+}
+
impl SystemdResolved {
pub fn new() -> Result<Self> {
let dbus_connection = crate::get_connection().map_err(Error::ConnectDBus)?;
@@ -218,14 +228,29 @@ impl SystemdResolved {
)
}
- pub fn set_dns(&self, interface_index: u32, servers: &[IpAddr]) -> Result<DnsState> {
+ pub fn get_dns(&self, interface_index: u32) -> Result<DnsState> {
let link_object_path = self
.fetch_link(interface_index)
.map_err(|e| Error::GetLinkError(Box::new(e)))?;
+ let set_servers = self.get_link_dns(&link_object_path)?;
+
+ Ok(DnsState {
+ interface_path: link_object_path,
+ interface_index,
+ set_servers,
+ })
+ }
- let mut set_servers = servers.to_vec();
- set_servers.sort();
- self.set_link_dns(&link_object_path, servers)?;
+ pub fn set_dns_state(&self, state: DnsState) -> Result<()> {
+ self.set_link_dns(&state.interface_path, &state.set_servers)
+ }
+
+ pub fn set_dns(&self, interface_index: u32, servers: Vec<IpAddr>) -> Result<DnsState> {
+ let set_servers = servers.to_vec();
+ let link_object_path = self
+ .fetch_link(interface_index)
+ .map_err(|e| Error::GetLinkError(Box::new(e)))?;
+ self.set_link_dns(&link_object_path, &servers)?;
Ok(DnsState {
interface_path: link_object_path,
interface_index,
@@ -233,6 +258,20 @@ impl SystemdResolved {
})
}
+ pub fn get_domains(&self, interface_index: u32) -> Result<Vec<(String, bool)>> {
+ let link_object_path = self
+ .fetch_link(interface_index)
+ .map_err(|e| Error::GetLinkError(Box::new(e)))?;
+ self.get_link_dns_domains(&link_object_path)
+ }
+
+ pub fn set_domains(&self, interface_index: u32, domains: &[(&str, bool)]) -> Result<()> {
+ let link_object_path = self
+ .fetch_link(interface_index)
+ .map_err(|e| Error::GetLinkError(Box::new(e)))?;
+ self.set_link_dns_domains(&link_object_path, domains)
+ }
+
fn fetch_link(&self, interface_index: u32) -> Result<dbus::Path<'static>> {
self.as_manager_object()
.method_call(
@@ -244,6 +283,21 @@ impl SystemdResolved {
.map(|result: (dbus::Path<'static>,)| result.0)
}
+ fn get_link_dns<'a, 'b: 'a>(
+ &'a self,
+ link_object_path: &'b dbus::Path<'static>,
+ ) -> Result<Vec<IpAddr>> {
+ let servers: Vec<(i32, Vec<u8>)> = self
+ .as_link_object(link_object_path.clone())
+ .get(LINK_INTERFACE, DNS_SERVERS)
+ .map_err(Error::DBusRpcError)?;
+
+ Ok(servers
+ .into_iter()
+ .filter_map(|(_family, addr)| ip_from_bytes(&addr))
+ .collect())
+ }
+
fn set_link_dns<'a, 'b: 'a>(
&'a self,
link_object_path: &'b dbus::Path<'static>,
@@ -255,20 +309,18 @@ impl SystemdResolved {
.collect::<Vec<_>>();
self.as_link_object(link_object_path.clone())
.method_call(LINK_INTERFACE, SET_DNS_METHOD, (servers,))
- .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
- let dns_domains: &[_] = &[(&".", true)];
+ .map_err(Error::DBusRpcError)
+ }
- Proxy::new(
- RESOLVED_BUS,
- link_object_path,
- RPC_TIMEOUT,
- &*self.dbus_connection,
- )
- .method_call(LINK_INTERFACE, SET_DOMAINS_METHOD, (dns_domains,))
- .map_err(Error::SetDomainsError)
+ fn get_link_dns_domains<'a, 'b: 'a>(
+ &'a self,
+ link_object_path: &'b dbus::Path<'static>,
+ ) -> Result<Vec<(String, bool)>> {
+ let domains: Vec<(String, bool)> = self
+ .as_link_object(link_object_path.clone())
+ .get(LINK_INTERFACE, DNS_DOMAINS)
+ .map_err(Error::DBusRpcError)?;
+ Ok(domains)
}
pub fn revert_link(&mut self, dns_state: &DnsState) -> std::result::Result<(), dbus::Error> {
@@ -289,6 +341,21 @@ impl SystemdResolved {
}
}
+ fn set_link_dns_domains<'a, 'b: 'a>(
+ &'a self,
+ link_object_path: &'b dbus::Path<'static>,
+ domains: &[(&str, bool)],
+ ) -> Result<()> {
+ Proxy::new(
+ RESOLVED_BUS,
+ link_object_path,
+ RPC_TIMEOUT,
+ &*self.dbus_connection,
+ )
+ .method_call(LINK_INTERFACE, SET_DOMAINS_METHOD, (domains,))
+ .map_err(Error::SetDomainsError)
+ }
+
pub fn watch_dns_changes<
F: FnMut(Vec<DnsServer>) + Send + Sync + 'static,
S: Fn() -> bool + Clone + Send + Sync + 'static,
@@ -338,6 +405,10 @@ impl SystemdResolved {
.remove_match(dns_matcher)
.map_err(Error::DnsUpdateRemoveMatchError)
}
+
+ pub fn async_handle(&self) -> AsyncHandle {
+ AsyncHandle::new(self.clone())
+ }
}
#[derive(Debug)]
@@ -398,3 +469,54 @@ fn ip_from_bytes(bytes: &[u8]) -> Option<IpAddr> {
_ => None,
}
}
+
+impl AsyncHandle {
+ fn new(dbus_interface: SystemdResolved) -> Self {
+ Self { dbus_interface }
+ }
+
+ pub async fn get_dns(&self, interface_index: u32) -> Result<DnsState> {
+ let interface = self.dbus_interface.clone();
+ tokio::task::spawn_blocking(move || interface.get_dns(interface_index))
+ .await
+ .map_err(Error::AsyncTaskError)?
+ }
+
+ pub async fn set_dns_state(&self, state: DnsState) -> Result<()> {
+ let interface = self.dbus_interface.clone();
+ tokio::task::spawn_blocking(move || interface.set_dns_state(state))
+ .await
+ .map_err(Error::AsyncTaskError)?
+ }
+
+ pub async fn set_dns(&self, interface_index: u32, servers: Vec<IpAddr>) -> Result<DnsState> {
+ let interface = self.dbus_interface.clone();
+ tokio::task::spawn_blocking(move || interface.set_dns(interface_index, servers))
+ .await
+ .map_err(Error::AsyncTaskError)?
+ }
+
+ pub async fn set_domains(
+ &self,
+ interface_index: u32,
+ domains: &[(&'static str, bool)],
+ ) -> Result<()> {
+ let interface = self.dbus_interface.clone();
+ let domains = domains.to_vec();
+ tokio::task::spawn_blocking(move || interface.set_domains(interface_index, &domains))
+ .await
+ .map_err(Error::AsyncTaskError)?
+ }
+
+ pub async fn revert_link(&self, state: DnsState) -> Result<()> {
+ let mut interface = self.dbus_interface.clone();
+ tokio::task::spawn_blocking(move || interface.revert_link(&state))
+ .await
+ .map_err(Error::AsyncTaskError)?
+ .map_err(Error::DBusRpcError)
+ }
+
+ pub fn handle(&self) -> &SystemdResolved {
+ &self.dbus_interface
+ }
+}