diff options
| author | Janito Vaqueiro Ferreira Filho <janito@mullvad.net> | 2018-04-09 22:24:37 -0300 |
|---|---|---|
| committer | Janito Vaqueiro Ferreira Filho <janito@mullvad.net> | 2018-04-17 07:33:50 -0300 |
| commit | 90db45c2baec09d6577bb2dbc6f16d5b046e6859 (patch) | |
| tree | 4417b5d16b5d822b747a4affd2f7ff7d1658e2e6 /talpid-core/src | |
| parent | 6939b5ef97b34d4052c6a55768ae18c382e8633b (diff) | |
| download | mullvadvpn-90db45c2baec09d6577bb2dbc6f16d5b046e6859.tar.xz mullvadvpn-90db45c2baec09d6577bb2dbc6f16d5b046e6859.zip | |
Implement Linux DNS configuration with resolv.conf
Diffstat (limited to 'talpid-core/src')
| -rw-r--r-- | talpid-core/src/firewall/linux.rs | 21 | ||||
| -rw-r--r-- | talpid-core/src/firewall/linux/dns.rs | 93 | ||||
| -rw-r--r-- | talpid-core/src/firewall/linux/mod.rs | 47 |
3 files changed, 140 insertions, 21 deletions
diff --git a/talpid-core/src/firewall/linux.rs b/talpid-core/src/firewall/linux.rs deleted file mode 100644 index 53c3bfb12f..0000000000 --- a/talpid-core/src/firewall/linux.rs +++ /dev/null @@ -1,21 +0,0 @@ -use super::{Firewall, SecurityPolicy}; - -error_chain!{} - -/// The Linux implementation for the `Firewall` trait. -pub struct Netfilter; -impl Firewall for Netfilter { - type Error = Error; - - fn new() -> Result<Self> { - Ok(Netfilter) - } - - fn apply_policy(&mut self, _policy: SecurityPolicy) -> Result<()> { - Ok(()) - } - - fn reset_policy(&mut self) -> Result<()> { - Ok(()) - } -} diff --git a/talpid-core/src/firewall/linux/dns.rs b/talpid-core/src/firewall/linux/dns.rs new file mode 100644 index 0000000000..d2d1627dd0 --- /dev/null +++ b/talpid-core/src/firewall/linux/dns.rs @@ -0,0 +1,93 @@ +extern crate resolv_conf; + +use std::fs::File; +use std::io::{self, Read, Write}; +use std::net::IpAddr; + +use self::resolv_conf::{Config, ScopedIp}; + +error_chain!{ + errors { + ParseResolvConf { + description("failed to parse contents of /etc/resolv.conf") + } + + ReadResolvConf { + description("failed to read /etc/resolv.conf") + } + + WriteResolvConf { + description("failed to write to /etc/resolv.conf") + } + } +} + +pub struct DnsSettings { + backup: Option<String>, + desired_dns: Option<Vec<IpAddr>>, +} + +impl DnsSettings { + pub fn new() -> Result<Self> { + Ok(DnsSettings { + backup: None, + desired_dns: None, + }) + } + + pub fn set_dns(&mut self, servers: Vec<IpAddr>) -> Result<()> { + if self.backup.is_none() { + self.backup = Some(Self::read_resolv_conf().chain_err(|| ErrorKind::ReadResolvConf)?); + } + + self.desired_dns = Some(servers); + self.configure_dns()?; + + Ok(()) + } + + pub fn reset(&mut self) -> Result<()> { + self.desired_dns = None; + + if let Some(backup) = self.backup.take() { + Self::write_resolv_conf(&backup).chain_err(|| ErrorKind::WriteResolvConf)?; + } + + Ok(()) + } + + fn configure_dns(&self) -> Result<()> { + let mut config = match self.backup { + Some(ref previous_config) => { + Config::parse(previous_config).chain_err(|| ErrorKind::ParseResolvConf)? + } + None => Config::new(), + }; + + if let Some(ref nameservers) = self.desired_dns { + config.nameservers = nameservers + .iter() + .map(|&address| ScopedIp::from(address)) + .collect(); + } else { + config.nameservers.clear(); + } + + Self::write_resolv_conf(&config.to_string()).chain_err(|| ErrorKind::WriteResolvConf) + } + + fn read_resolv_conf() -> io::Result<String> { + let mut file = File::open("/etc/resolv.conf")?; + let mut contents = String::new(); + + file.read_to_string(&mut contents)?; + + Ok(contents) + } + + fn write_resolv_conf(contents: &str) -> io::Result<()> { + let mut file = File::create("/etc/resolv.conf")?; + + file.write_all(contents.as_bytes()) + } +} diff --git a/talpid-core/src/firewall/linux/mod.rs b/talpid-core/src/firewall/linux/mod.rs new file mode 100644 index 0000000000..6b8e213f54 --- /dev/null +++ b/talpid-core/src/firewall/linux/mod.rs @@ -0,0 +1,47 @@ +use error_chain::ChainedError; + +use super::{Firewall, SecurityPolicy}; + +mod dns; + +use self::dns::DnsSettings; + +error_chain! { + links { + DnsSettings(self::dns::Error, self::dns::ErrorKind) #[doc = "DNS error"]; + } +} + +/// The Linux implementation for the `Firewall` trait. +pub struct Netfilter { + dns_settings: DnsSettings, +} + +impl Firewall for Netfilter { + type Error = Error; + + fn new() -> Result<Self> { + Ok(Netfilter { + dns_settings: DnsSettings::new()?, + }) + } + + fn apply_policy(&mut self, policy: SecurityPolicy) -> Result<()> { + match policy { + SecurityPolicy::Connected { tunnel, .. } => { + self.dns_settings.set_dns(vec![tunnel.gateway.into()])?; + } + _ => (), + } + + Ok(()) + } + + fn reset_policy(&mut self) -> Result<()> { + if let Err(error) = self.dns_settings.reset() { + warn!("Failed to reset DNS settings: {}", error.display_chain()); + } + + Ok(()) + } +} |
