summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorEmīls <emils@mullvad.net>2021-11-19 13:53:29 +0000
committerEmīls <emils@mullvad.net>2021-12-10 09:58:51 +0000
commitbb9582cc37d59b8d852f53521cc496d0e55f2d0b (patch)
treed78e4d8b4a64f0851c116d4401360ac0ca71d781
parent1ff05fbf885ca0354a0d9709300b84253a74c9bf (diff)
downloadmullvadvpn-bb9582cc37d59b8d852f53521cc496d0e55f2d0b.tar.xz
mullvadvpn-bb9582cc37d59b8d852f53521cc496d0e55f2d0b.zip
Have DNS manager select the best DNS config
-rw-r--r--talpid-core/src/dns/macos.rs11
-rw-r--r--talpid-core/src/dns/mod.rs4
-rw-r--r--talpid-core/src/resolver/mod.rs36
-rw-r--r--talpid-core/src/tunnel_state_machine/mod.rs2
4 files changed, 33 insertions, 20 deletions
diff --git a/talpid-core/src/dns/macos.rs b/talpid-core/src/dns/macos.rs
index 1f63310449..fe7501d905 100644
--- a/talpid-core/src/dns/macos.rs
+++ b/talpid-core/src/dns/macos.rs
@@ -72,7 +72,9 @@ impl State {
if let Some(tunnel_tx) = self.tunnel_tx.upgrade() {
match parse_sc_config(&self.backup) {
Ok(config) => {
- let _ = tunnel_tx.unbounded_send(TunnelCommand::HostDnsConfig(config));
+ // TODO: do better filtering to get the best resolver
+ let _ = tunnel_tx
+ .unbounded_send(TunnelCommand::HostDnsConfig(config.into_iter().next()));
}
Err(err) => {
log::error!("Failed to parse host's DNS config: {}", err);
@@ -319,7 +321,7 @@ impl DnsMonitor {
result_rx.recv().unwrap()
}
/// Get the system config without our changes
- pub fn get_system_config(&self) -> Result<HashMap<String, Vec<IpAddr>>> {
+ pub fn get_system_config(&self) -> Result<Option<(String, Vec<IpAddr>)>> {
self.state
.lock()
.as_ref()
@@ -330,7 +332,7 @@ impl DnsMonitor {
fn parse_sc_config(
config: &HashMap<String, Option<DnsSettings>>,
-) -> Result<HashMap<String, Vec<IpAddr>>> {
+) -> Result<Option<(String, Vec<IpAddr>)>> {
config
.iter()
.filter_map(|(path, maybe_config)| {
@@ -344,7 +346,8 @@ fn parse_sc_config(
let addresses = settings.interface_config(path.as_str())?;
Ok((settings.name.clone(), addresses))
})
- .collect::<Result<_>>()
+ .next()
+ .transpose()
}
/// Creates a `SCDynamicStore` that watches all network interfaces for changes to the DNS settings.
diff --git a/talpid-core/src/dns/mod.rs b/talpid-core/src/dns/mod.rs
index a941cf783e..5a7b5c0dec 100644
--- a/talpid-core/src/dns/mod.rs
+++ b/talpid-core/src/dns/mod.rs
@@ -1,7 +1,5 @@
#[cfg(target_os = "linux")]
use crate::routing::RouteManagerHandle;
-#[cfg(target_os = "macos")]
-use std::collections::HashMap;
use std::net::IpAddr;
#[cfg(target_os = "macos")]
@@ -54,7 +52,7 @@ impl DnsMonitor {
/// Returns a map of interfaces and respective list of resolvers that don't contain our
/// changes.
#[cfg(target_os = "macos")]
- pub fn get_system_config(&self) -> Result<HashMap<String, Vec<IpAddr>>, Error> {
+ pub fn get_system_config(&self) -> Result<Option<(String, Vec<IpAddr>)>, Error> {
self.inner.get_system_config()
}
diff --git a/talpid-core/src/resolver/mod.rs b/talpid-core/src/resolver/mod.rs
index 28ce99c355..fc3509f513 100644
--- a/talpid-core/src/resolver/mod.rs
+++ b/talpid-core/src/resolver/mod.rs
@@ -1,7 +1,7 @@
use socket2::{Domain, Socket, Type};
use std::{
- collections::{BTreeSet, HashMap},
+ collections::BTreeSet,
ffi::CString,
future::Future,
io,
@@ -151,7 +151,7 @@ type ExcludedUpstreamResolver = AsyncResolver<GenericConnection, OurConnectionPr
#[derive(Debug, PartialEq, Clone)]
pub(crate) enum ResolverState {
- Active(HashMap<String, Vec<IpAddr>>),
+ Active(Option<(String, Vec<IpAddr>)>),
Inactive,
Shutdown,
}
@@ -208,7 +208,7 @@ impl ResolverHandle {
/// Enable the resolver
pub async fn set_active(
&self,
- config: HashMap<String, Vec<IpAddr>>,
+ config: Option<(String, Vec<IpAddr>)>,
) -> Result<ResolverStateToggleResult, Error> {
self.set_state(ResolverState::Active(config)).await
}
@@ -373,15 +373,13 @@ impl FilteringResolver {
fn get_resolver_config(&self) -> (&str, &[IpAddr]) {
match &self.resolver_state {
- ResolverState::Active(resolvers) => {
+ ResolverState::Active(ref resolvers) => {
// TODO: actually pick the best resolver
resolvers
- .iter()
- // ignore anay config with loopback addresses
+ .as_ref()
.filter(|(_, addresses)| {
!addresses.iter().any(|ip| ip.is_loopback())
})
- .next()
.map(|(interface_name, addresses)| (interface_name.as_str(), addresses.as_slice()))
.unwrap_or(("", &[]))
}
@@ -658,7 +656,7 @@ impl LookupObject for ForwardLookup {
#[cfg(test)]
mod test {
use super::*;
- use std::{fs, net::UdpSocket};
+ use std::{fs, net::UdpSocket, process::Command};
use subslice::SubsliceExt;
fn random_port() -> u16 {
@@ -668,7 +666,7 @@ mod test {
const NAMESERVER: &[u8] = b"nameserver";
- fn read_resolvconf() -> HashMap<String, Vec<IpAddr>> {
+ fn read_resolvconf() -> Option<(String, Vec<IpAddr>)> {
let contents = fs::read("/etc/resolv.conf").unwrap();
let nameserver_index = contents
.find(NAMESERVER)
@@ -681,9 +679,23 @@ mod test {
let resolver_ip =
IpAddr::from_str(std::str::from_utf8(ip_addr_subslice).unwrap().trim()).unwrap();
- let mut map = HashMap::new();
- map.insert("".to_string(), vec![resolver_ip]);
- map
+ let route_output = String::from_utf8(
+ Command::new("route")
+ .arg("get")
+ .arg(resolver_ip.to_string())
+ .output()
+ .expect("Failed to run 'route get'")
+ .stdout,
+ )
+ .unwrap();
+
+ let mut output_parts = route_output.split_whitespace();
+ while let Some(part) = output_parts.next() {
+ if part.trim() == "interface:" {
+ return Some((output_parts.next().unwrap().to_string(), vec![resolver_ip]));
+ }
+ }
+ panic!("Couldn't deduce interface")
}
async fn start_resolver() -> (
diff --git a/talpid-core/src/tunnel_state_machine/mod.rs b/talpid-core/src/tunnel_state_machine/mod.rs
index 0130a4a42d..a6696117fc 100644
--- a/talpid-core/src/tunnel_state_machine/mod.rs
+++ b/talpid-core/src/tunnel_state_machine/mod.rs
@@ -192,7 +192,7 @@ pub enum TunnelCommand {
SetCustomResolver(bool, oneshot::Sender<Result<(), crate::resolver::Error>>),
/// Receive up-to-date system DNS config. It should never contain our changes to the DNS.
#[cfg(target_os = "macos")]
- HostDnsConfig(HashMap<String, Vec<IpAddr>>),
+ HostDnsConfig(Option<(String, Vec<IpAddr>)>),
}
type TunnelCommandReceiver = stream::Fuse<mpsc::UnboundedReceiver<TunnelCommand>>;