diff options
| -rw-r--r-- | talpid-core/src/split.rs | 55 | ||||
| -rw-r--r-- | talpid-core/src/tunnel_state_machine/connected_state.rs | 18 |
2 files changed, 68 insertions, 5 deletions
diff --git a/talpid-core/src/split.rs b/talpid-core/src/split.rs index 04a57c2034..cab42fd265 100644 --- a/talpid-core/src/split.rs +++ b/talpid-core/src/split.rs @@ -2,6 +2,7 @@ use regex::Regex; use std::{ fs, io::{self, BufRead, BufReader, Write}, + net::IpAddr, path::Path, process::Command, }; @@ -45,6 +46,14 @@ pub enum Error { /// Unable to read cgroup.procs. #[error(display = "Unable to obtain PIDs from cgroup.procs")] ListCGroupPids(#[error(source)] io::Error), + + /// Unable to add setup DNS routing. + #[error(display = "Failed to add routing table DNS rules")] + SetDns(#[error(source)] io::Error), + + /// Unable to flush routing table. + #[error(display = "Failed to clear routing table DNS rules")] + FlushDns(#[error(source)] io::Error), } /// Route PID-associated packets through the physical interface. @@ -75,6 +84,52 @@ pub fn route_marked_packets() -> Result<(), Error> { cmd.output().map(|_| ()).map_err(Error::RoutingTableSetup) } +/// Route DNS requests through the tunnel interface. +pub fn route_dns(tunnel_alias: &str, dns_servers: &[IpAddr]) -> Result<(), Error> { + // TODO: IPv6 + + let mut cmd = Command::new("ip"); + cmd.args(&["-4", "route", "flush", "table", ROUTING_TABLE_NAME]); + + log::trace!("running cmd - {:?}", &cmd); + cmd.output().map_err(Error::SetDns)?; + + for server in dns_servers { + if let IpAddr::V4(addr) = server { + let addr = addr.to_string(); + + let mut cmd = Command::new("ip"); + cmd.args(&[ + "-4", + "route", + "add", + &addr, + "via", + &addr, + "dev", + tunnel_alias, + "table", + ROUTING_TABLE_NAME, + ]); + + log::trace!("running cmd - {:?}", &cmd); + cmd.output().map_err(Error::SetDns)?; + } + } + + Ok(()) +} + +/// Reset DNS rules. +pub fn flush_dns() -> Result<(), Error> { + // For now, simply flush it + let mut cmd = Command::new("ip"); + cmd.args(&["-4", "route", "flush", "table", ROUTING_TABLE_NAME]); + + log::trace!("running cmd - {:?}", &cmd); + cmd.output().map(|_| ()).map_err(Error::FlushDns) +} + /// Set up policy-based routing for marked packets. pub fn initialize_routing_table() -> Result<(), Error> { // TODO: ensure the ID does not conflict with that of another table diff --git a/talpid-core/src/tunnel_state_machine/connected_state.rs b/talpid-core/src/tunnel_state_machine/connected_state.rs index deb7e265a4..e936499f47 100644 --- a/talpid-core/src/tunnel_state_machine/connected_state.rs +++ b/talpid-core/src/tunnel_state_machine/connected_state.rs @@ -4,6 +4,7 @@ use super::{ }; use crate::{ firewall::FirewallPolicy, + split, tunnel::{CloseHandle, TunnelEvent, TunnelMetadata}, }; use futures01::{ @@ -13,7 +14,7 @@ use futures01::{ use talpid_types::{ net::{Endpoint, TunnelParameters}, tunnel::ErrorStateCause, - ErrorExt, + BoxedError, ErrorExt, }; pub struct ConnectedStateBootstrap { @@ -69,10 +70,7 @@ impl ConnectedState { } } - fn set_dns( - &self, - shared_values: &mut SharedTunnelStateValues, - ) -> Result<(), crate::dns::Error> { + fn set_dns(&self, shared_values: &mut SharedTunnelStateValues) -> Result<(), BoxedError> { let mut dns_ips = vec![self.metadata.ipv4_gateway.into()]; if let Some(ipv6_gateway) = self.metadata.ipv6_gateway { dns_ips.push(ipv6_gateway.into()); @@ -81,9 +79,19 @@ impl ConnectedState { shared_values .dns_monitor .set(&self.metadata.interface, &dns_ips) + .map_err(BoxedError::new)?; + + split::route_dns(&self.metadata.interface, &dns_ips).map_err(BoxedError::new) } fn reset_dns(shared_values: &mut SharedTunnelStateValues) { + if let Err(error) = split::flush_dns() { + log::error!( + "{}", + error.display_chain_with_msg("Unable to update split-tunnel route") + ); + } + if let Err(error) = shared_values.dns_monitor.reset() { log::error!("{}", error.display_chain_with_msg("Unable to reset DNS")); } |
