diff options
| -rw-r--r-- | mullvad-rpc/src/cached_dns_resolver.rs | 36 |
1 files changed, 32 insertions, 4 deletions
diff --git a/mullvad-rpc/src/cached_dns_resolver.rs b/mullvad-rpc/src/cached_dns_resolver.rs index 3acfad378c..f667214499 100644 --- a/mullvad-rpc/src/cached_dns_resolver.rs +++ b/mullvad-rpc/src/cached_dns_resolver.rs @@ -2,21 +2,35 @@ use std::fs::File; use std::io::{self, Read, Write}; use std::net::{IpAddr, ToSocketAddrs}; use std::path::{Path, PathBuf}; +use std::sync::mpsc; +use std::thread; use std::time::{Duration, SystemTime, UNIX_EPOCH}; +static DNS_TIMEOUT: Duration = Duration::from_secs(2); static MAX_CACHE_AGE: Duration = Duration::from_secs(3600); static EXPIRED_CACHE_TIMESTAMP: SystemTime = UNIX_EPOCH; pub trait DnsResolver { - fn resolve(&self, host: &str) -> io::Result<IpAddr>; + fn resolve(&mut self, host: &str) -> io::Result<IpAddr>; } pub struct SystemDnsResolver; -impl DnsResolver for SystemDnsResolver { - fn resolve(&self, host: &str) -> io::Result<IpAddr> { +impl SystemDnsResolver { + fn resolve_in_background_thread(host: &str) -> mpsc::Receiver<io::Result<IpAddr>> { + let host = host.to_owned(); + let (tx, rx) = mpsc::channel(); + + thread::spawn(move || { + let _ = tx.send(Self::resolve_hostname(&host)); + }); + + rx + } + + fn resolve_hostname(host: &str) -> io::Result<IpAddr> { (host, 0) .to_socket_addrs()? .next() @@ -27,6 +41,20 @@ impl DnsResolver for SystemDnsResolver { } } +impl DnsResolver for SystemDnsResolver { + fn resolve(&mut self, host: &str) -> io::Result<IpAddr> { + Self::resolve_in_background_thread(host) + .recv_timeout(DNS_TIMEOUT) + .map_err(|_| { + io::Error::new( + io::ErrorKind::Other, + "Timeout while performing DNS resolution", + ) + }) + .and_then(|result| result) + } +} + pub struct CachedDnsResolver<R: DnsResolver = SystemDnsResolver> { hostname: String, dns_resolver: R, @@ -317,7 +345,7 @@ mod tests { } impl DnsResolver for MockDnsResolver { - fn resolve(&self, host: &str) -> io::Result<IpAddr> { + fn resolve(&mut self, host: &str) -> io::Result<IpAddr> { self.called.store(true, Ordering::Release); self.address.ok_or_else(|| { |
