//! Specifying the address of the DNS server to send requests to. use std::io; use log::*; /// A **resolver** is used to obtain the IP address of the server we should /// send DNS requests to. #[derive(PartialEq, Debug)] pub enum Resolver { /// Read the list of nameservers from the system, and use that. SystemDefault, // Use a specific nameserver specified by the user. Specified(Nameserver), } pub type Nameserver = String; impl Resolver { /// Returns a nameserver that queries should be sent to, possibly by /// obtaining one based on the system, returning an error if there was a /// problem looking one up. pub fn lookup(self) -> io::Result> { match self { Self::Specified(ns) => Ok(Some(ns)), Self::SystemDefault => system_nameservers(), } } } /// Looks up the system default nameserver on Unix, by querying /// `/etc/resolv.conf` and returning the first line that specifies one. /// Returns an error if there’s a problem reading the file, or `None` if no /// nameserver is specified in the file. #[cfg(unix)] fn system_nameservers() -> io::Result> { use std::io::{BufRead, BufReader}; use std::fs::File; let f = File::open("/etc/resolv.conf")?; let reader = BufReader::new(f); let mut nameservers = Vec::new(); for line in reader.lines() { let line = line?; if let Some(nameserver_str) = line.strip_prefix("nameserver ") { let ip: Result = nameserver_str.parse(); // TODO: This will need to be changed for IPv6 support. match ip { Ok(_ip) => nameservers.push(nameserver_str.into()), Err(e) => warn!("Failed to parse nameserver line {:?}: {}", line, e), } } } Ok(nameservers.first().cloned()) } /// Looks up the system default nameserver on Windows, by iterating through /// the list of network adapters and returning the first nameserver it finds. #[cfg(windows)] fn system_nameservers() -> io::Result> { let adapters = match ipconfig::get_adapters() { Ok(a) => a, Err(e) => { warn!("Error getting network adapters: {}", e); return Ok(None); } }; for adapter in adapters.iter().filter(|a| { a.oper_status() == ipconfig::OperStatus::IfOperStatusUp && !a.gateways().is_empty() }) { for dns_server in adapter.dns_servers().iter() { // TODO: This will need to be changed for IPv6 support. if dns_server.is_ipv4() { debug!("Found first nameserver {:?}", dns_server); return Ok(Some(dns_server.to_string())); } } } warn!("No nameservers available"); return Ok(None) } /// The fall-back system default nameserver determinator that is not very /// determined as it returns nothing without actually checking anything. #[cfg(all(not(unix), not(windows)))] fn system_nameservers() -> io::Result> { warn!("Unable to fetch default nameservers on this platform."); Ok(None) }