diff options
| author | Janito Vaqueiro Ferreira Filho <janito@mullvad.net> | 2018-09-10 19:53:45 -0300 |
|---|---|---|
| committer | Janito Vaqueiro Ferreira Filho <janito@mullvad.net> | 2018-09-17 11:00:07 -0300 |
| commit | a8925c7d5ba0b2cf42d701e66922e29f9341124c (patch) | |
| tree | fa4f27ccc8961f8c5379969364f85d864bfbb5aa | |
| parent | e7ecb193af50f78cb4f267dff90a75072333e11f (diff) | |
| download | mullvadvpn-a8925c7d5ba0b2cf42d701e66922e29f9341124c.tar.xz mullvadvpn-a8925c7d5ba0b2cf42d701e66922e29f9341124c.zip | |
Implement support for resolvconf
| -rw-r--r-- | talpid-core/src/lib.rs | 1 | ||||
| -rw-r--r-- | talpid-core/src/security/linux/dns/mod.rs | 19 | ||||
| -rw-r--r-- | talpid-core/src/security/linux/dns/resolvconf.rs | 83 | ||||
| -rw-r--r-- | talpid-core/src/security/linux/mod.rs | 3 |
4 files changed, 103 insertions, 3 deletions
diff --git a/talpid-core/src/lib.rs b/talpid-core/src/lib.rs index 54e3ef08ef..596f6a6d6c 100644 --- a/talpid-core/src/lib.rs +++ b/talpid-core/src/lib.rs @@ -11,6 +11,7 @@ //! the License, or (at your option) any later version. extern crate atty; +#[macro_use] extern crate duct; #[macro_use] extern crate log; diff --git a/talpid-core/src/security/linux/dns/mod.rs b/talpid-core/src/security/linux/dns/mod.rs index 5758104594..3e6dafed0f 100644 --- a/talpid-core/src/security/linux/dns/mod.rs +++ b/talpid-core/src/security/linux/dns/mod.rs @@ -1,28 +1,42 @@ +mod resolvconf; mod static_resolv_conf; use std::net::IpAddr; +use self::resolvconf::Resolvconf; use self::static_resolv_conf::StaticResolvConf; error_chain! { + errors { + NoDnsSettingsManager { + description("No DNS settings manager detected") + } + } + links { + Resolvconf(resolvconf::Error, resolvconf::ErrorKind); StaticResolvConf(static_resolv_conf::Error, static_resolv_conf::ErrorKind); } } pub enum DnsSettings { + Resolvconf(Resolvconf), StaticResolvConf(StaticResolvConf), } impl DnsSettings { pub fn new() -> Result<Self> { - Ok(DnsSettings::StaticResolvConf(StaticResolvConf::new()?)) + Resolvconf::new() + .map(DnsSettings::Resolvconf) + .or_else(|_| StaticResolvConf::new().map(DnsSettings::StaticResolvConf)) + .chain_err(|| ErrorKind::NoDnsSettingsManager) } - pub fn set_dns(&mut self, servers: Vec<IpAddr>) -> Result<()> { + pub fn set_dns(&mut self, interface: &str, servers: Vec<IpAddr>) -> Result<()> { use self::DnsSettings::*; match self { + Resolvconf(ref mut resolvconf) => resolvconf.set_dns(interface, servers)?, StaticResolvConf(ref mut static_resolv_conf) => static_resolv_conf.set_dns(servers)?, } @@ -33,6 +47,7 @@ impl DnsSettings { use self::DnsSettings::*; match self { + Resolvconf(ref mut resolvconf) => resolvconf.reset()?, StaticResolvConf(ref mut static_resolv_conf) => static_resolv_conf.reset()?, } diff --git a/talpid-core/src/security/linux/dns/resolvconf.rs b/talpid-core/src/security/linux/dns/resolvconf.rs new file mode 100644 index 0000000000..d1ac319edb --- /dev/null +++ b/talpid-core/src/security/linux/dns/resolvconf.rs @@ -0,0 +1,83 @@ +use std::collections::HashSet; +use std::net::IpAddr; +use std::path::PathBuf; + +use which::which; + +error_chain! { + errors { + NoResolvconf { + description("Failed to detect 'resolvconf' program") + } + RunResolvconf { + description("Failed to execute 'resolvconf' program") + } + AddRecordError(stderr: String) { + description("Using 'resolvconf' to add a record failed") + display("Using 'resolvconf' to add a record failed: {}", stderr) + } + DeleteRecordError { + description("Using 'resolvconf' to delete a record failed") + } + } +} + +pub struct Resolvconf { + record_names: HashSet<String>, + resolvconf: PathBuf, +} + +impl Resolvconf { + pub fn new() -> Result<Self> { + Ok(Resolvconf { + record_names: HashSet::new(), + resolvconf: which("resolvconf").map_err(|_| Error::from(ErrorKind::NoResolvconf))?, + }) + } + + pub fn set_dns(&mut self, interface: &str, servers: Vec<IpAddr>) -> Result<()> { + let record_name = format!("{}.mullvad", interface); + let mut record_contents = String::new(); + + for address in servers { + record_contents.push_str("nameserver "); + record_contents.push_str(&address.to_string()); + record_contents.push('\n'); + } + + let output = cmd!(&self.resolvconf, "-a", &record_name) + .input(record_contents) + .run() + .chain_err(|| ErrorKind::RunResolvconf)?; + + ensure!( + output.status.success(), + ErrorKind::AddRecordError(String::from_utf8_lossy(&output.stderr).to_string()) + ); + + self.record_names.insert(record_name); + + Ok(()) + } + + pub fn reset(&mut self) -> Result<()> { + let mut result = Ok(()); + + for record_name in self.record_names.drain() { + let output = cmd!(&self.resolvconf, "-d", &record_name) + .run() + .chain_err(|| ErrorKind::RunResolvconf)?; + + if !output.status.success() { + error!( + "Failed to delete 'resolvconf' record '{}':\n{}", + record_name, + String::from_utf8_lossy(&output.stderr) + ); + result = Err(Error::from(ErrorKind::DeleteRecordError)); + } + } + + result + } +} diff --git a/talpid-core/src/security/linux/mod.rs b/talpid-core/src/security/linux/mod.rs index f4de49bfa9..ecf9e671b5 100644 --- a/talpid-core/src/security/linux/mod.rs +++ b/talpid-core/src/security/linux/mod.rs @@ -89,7 +89,8 @@ impl NetworkSecurityT for NetworkSecurity { fn apply_policy(&mut self, policy: SecurityPolicy) -> Result<()> { if let SecurityPolicy::Connected { ref tunnel, .. } = policy { - self.dns_settings.set_dns(vec![tunnel.gateway.into()])?; + self.dns_settings + .set_dns(&tunnel.interface, vec![tunnel.gateway.into()])?; } let table = Table::new(&self.table_name, ProtoFamily::Inet)?; |
