diff options
| author | David Lönnhager <david.l@mullvad.net> | 2020-02-28 13:55:50 +0100 |
|---|---|---|
| committer | David Lönnhager <david.l@mullvad.net> | 2020-06-02 10:05:01 +0200 |
| commit | 65a64170a40cfff3fb4720ab23d2ce3bae4e363c (patch) | |
| tree | 8067a122c3de63a9c79d0aba91df9e1882ae5380 /talpid-core/src | |
| parent | 312b626e288663329b9c81a700157b8f214441ec (diff) | |
| download | mullvadvpn-65a64170a40cfff3fb4720ab23d2ce3bae4e363c.tar.xz mullvadvpn-65a64170a40cfff3fb4720ab23d2ce3bae4e363c.zip | |
Create routing table for split tunneling
Diffstat (limited to 'talpid-core/src')
| -rw-r--r-- | talpid-core/src/split.rs | 61 | ||||
| -rw-r--r-- | talpid-core/src/tunnel_state_machine/mod.rs | 5 |
2 files changed, 65 insertions, 1 deletions
diff --git a/talpid-core/src/split.rs b/talpid-core/src/split.rs index b6e106a4b2..28d916c11a 100644 --- a/talpid-core/src/split.rs +++ b/talpid-core/src/split.rs @@ -1,3 +1,4 @@ +use regex::Regex; use std::{ fs, io::{self, BufRead, BufReader, Write}, @@ -8,11 +9,18 @@ const NETCLS_DIR: &str = "/sys/fs/cgroup/net_cls/"; /// Identifies packets coming from the cgroup. pub const NETCLS_CLASSID: u32 = 0x4d9f41; const CGROUP_NAME: &str = "mullvad-exclusions"; +static mut ROUTING_TABLE_ID: i32 = 19; +const ROUTING_TABLE_NAME: &str = "mullvad_exclusions"; +const RT_TABLES_PATH: &str = "/etc/iproute2/rt_tables"; /// Errors related to split tunneling. #[derive(err_derive::Error, Debug)] #[error(no_from)] pub enum Error { + /// Unable to create routing table for tagged connections and packets. + #[error(display = "Unable to create routing table")] + RoutingTableSetup(#[error(source)] io::Error), + /// Unable to create cgroup. #[error(display = "Unable to create cgroup for excluded processes")] CreateCGroup(#[error(source)] io::Error), @@ -34,6 +42,59 @@ pub enum Error { ListCGroupPids(#[error(source)] io::Error), } +fn route_marked_packets() -> Result<(), Error> { + // TODO: route fwmark'd packets using this table (if they aren't already) + Ok(()) +} + +/// 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 + + // Add routing table to /etc/iproute2/rt_tables, if it does not exist + + let mut file = fs::OpenOptions::new() + .read(true) + .append(true) + .create(true) + .open(RT_TABLES_PATH) + .map_err(Error::RoutingTableSetup)?; + let buf_reader = BufReader::new(file.try_clone().map_err(Error::RoutingTableSetup)?); + let expression = Regex::new(r"^\s*(\d+)\s+(\w+)").unwrap(); + + for line in buf_reader.lines() { + let line = line.map_err(Error::RoutingTableSetup)?; + if let Some(captures) = expression.captures(&line) { + let table_id = captures + .get(1) + .unwrap() + .as_str() + .parse::<i32>() + .expect("Table ID does not fit i32"); + let table_name = captures.get(2).unwrap().as_str(); + + // Already added + if table_name == ROUTING_TABLE_NAME { + if table_id != unsafe { ROUTING_TABLE_ID } { + unsafe { ROUTING_TABLE_ID = table_id }; + } + + return route_marked_packets(); + } + } + } + + write!( + file, + "{} {}", + unsafe { ROUTING_TABLE_ID }, + ROUTING_TABLE_NAME + ) + .map_err(Error::RoutingTableSetup)?; + + route_marked_packets() +} + /// Set up cgroup used to track PIDs for split tunneling. pub fn create_cgroup() -> Result<(), Error> { let exclusions_dir = Path::new(NETCLS_DIR).join(CGROUP_NAME); diff --git a/talpid-core/src/tunnel_state_machine/mod.rs b/talpid-core/src/tunnel_state_machine/mod.rs index 3e75206e33..f1aae86017 100644 --- a/talpid-core/src/tunnel_state_machine/mod.rs +++ b/talpid-core/src/tunnel_state_machine/mod.rs @@ -242,7 +242,10 @@ impl TunnelStateMachine { }; #[cfg(unix)] - split::create_cgroup().map_err(Error::InitSplitTunneling)?; + { + split::initialize_routing_table().map_err(Error::InitSplitTunneling)?; + split::create_cgroup().map_err(Error::InitSplitTunneling)?; + } let firewall = Firewall::new(args).map_err(Error::InitFirewallError)?; let dns_monitor = DnsMonitor::new(cache_dir).map_err(Error::InitDnsMonitorError)?; |
