summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJanito Vaqueiro Ferreira Filho <janito@mullvad.net>2018-09-10 19:53:45 -0300
committerJanito Vaqueiro Ferreira Filho <janito@mullvad.net>2018-09-17 11:00:07 -0300
commita8925c7d5ba0b2cf42d701e66922e29f9341124c (patch)
treefa4f27ccc8961f8c5379969364f85d864bfbb5aa
parente7ecb193af50f78cb4f267dff90a75072333e11f (diff)
downloadmullvadvpn-a8925c7d5ba0b2cf42d701e66922e29f9341124c.tar.xz
mullvadvpn-a8925c7d5ba0b2cf42d701e66922e29f9341124c.zip
Implement support for resolvconf
-rw-r--r--talpid-core/src/lib.rs1
-rw-r--r--talpid-core/src/security/linux/dns/mod.rs19
-rw-r--r--talpid-core/src/security/linux/dns/resolvconf.rs83
-rw-r--r--talpid-core/src/security/linux/mod.rs3
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)?;