summaryrefslogtreecommitdiffhomepage
path: root/talpid-core/src
diff options
context:
space:
mode:
authorDavid Lönnhager <david.l@mullvad.net>2020-02-28 13:55:50 +0100
committerDavid Lönnhager <david.l@mullvad.net>2020-06-02 10:05:01 +0200
commit65a64170a40cfff3fb4720ab23d2ce3bae4e363c (patch)
tree8067a122c3de63a9c79d0aba91df9e1882ae5380 /talpid-core/src
parent312b626e288663329b9c81a700157b8f214441ec (diff)
downloadmullvadvpn-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.rs61
-rw-r--r--talpid-core/src/tunnel_state_machine/mod.rs5
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)?;