summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorDavid Lönnhager <david.l@mullvad.net>2020-04-27 15:32:31 +0200
committerDavid Lönnhager <david.l@mullvad.net>2020-04-28 13:56:26 +0200
commit03e4fdf44391603e5c34a1bb1d8ab27a89ab74d7 (patch)
tree412451bcb3f9458fcb8a052164cb5693df364e51
parentb6ae86c12185ef5b23f7350912405a11428e43bd (diff)
downloadmullvadvpn-03e4fdf44391603e5c34a1bb1d8ab27a89ab74d7.tar.xz
mullvadvpn-03e4fdf44391603e5c34a1bb1d8ab27a89ab74d7.zip
Let RouteManager update required routes in any given table
-rw-r--r--talpid-core/src/routing/linux.rs58
-rw-r--r--talpid-core/src/routing/mod.rs15
2 files changed, 54 insertions, 19 deletions
diff --git a/talpid-core/src/routing/linux.rs b/talpid-core/src/routing/linux.rs
index c7417f7608..2adabc556a 100644
--- a/talpid-core/src/routing/linux.rs
+++ b/talpid-core/src/routing/linux.rs
@@ -103,6 +103,12 @@ impl RouteManagerImpl {
}
}
+#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
+struct RequiredDefaultRoute {
+ table_id: u8,
+ destination: IpNetwork,
+}
+
pub struct RouteManagerImplInner {
handle: Handle,
messages: UnboundedReceiver<(NetlinkMessage<RtnlMessage>, SocketAddr)>,
@@ -112,7 +118,7 @@ pub struct RouteManagerImplInner {
added_routes: HashSet<Route>,
// default route tracking
// destinations that should be routed through the default route
- required_default_routes: HashSet<IpNetwork>,
+ required_default_routes: HashSet<RequiredDefaultRoute>,
default_routes: HashSet<Route>,
best_default_node_v4: Option<Node>,
best_default_node_v6: Option<Node>,
@@ -144,7 +150,10 @@ impl RouteManagerImplInner {
required_normal_routes.insert(Route::new(node, destination));
}
NetNode::DefaultNode => {
- required_default_routes.insert(destination);
+ required_default_routes.insert(RequiredDefaultRoute {
+ table_id: RT_TABLE_MAIN,
+ destination,
+ });
}
}
}
@@ -174,15 +183,16 @@ impl RouteManagerImplInner {
monitor.add_route(normal_route).await?;
}
- for prefix in monitor.required_default_routes.clone().into_iter() {
+ for route in monitor.required_default_routes.clone().into_iter() {
if let (false, _, Some(default_node)) | (true, Some(default_node), _) = (
- prefix.is_ipv4(),
+ route.destination.is_ipv4(),
&monitor.best_default_node_v4,
&monitor.best_default_node_v6,
) {
// best to pick a single node identifier rather than device + ip
- let route = Route::new(default_node.clone(), prefix);
- monitor.add_route(route).await?;
+ let new_route =
+ Route::new(default_node.clone(), route.destination).table(route.table_id);
+ monitor.add_route(new_route).await?;
}
}
Ok(monitor)
@@ -261,16 +271,20 @@ impl RouteManagerImplInner {
if self.best_default_node_v4 != new_best_v4 && new_best_v4.is_some() {
let new_node = new_best_v4.unwrap();
let old_node = self.best_default_node_v4.take();
- let v4_destinations: Vec<_> = self
+ let v4_routes: Vec<_> = self
.required_default_routes
.iter()
- .filter(|ip| ip.is_ipv4())
+ .filter(|ip| ip.destination.is_ipv4())
.cloned()
.collect();
- for destination in v4_destinations {
- let new_route = Route::new(new_node.clone(), destination);
+ for route in v4_routes {
+ let new_route =
+ Route::new(new_node.clone(), route.destination).table(route.table_id);
+
if let Some(old_node) = &old_node {
- let old_route = Route::new(old_node.clone(), destination);
+ let old_route =
+ Route::new(old_node.clone(), route.destination).table(route.table_id);
+
if let Err(e) = self.delete_route(&old_route).await {
log::error!("Failed to remove old route {} - {}", &old_route, e);
}
@@ -286,17 +300,20 @@ impl RouteManagerImplInner {
if self.best_default_node_v6 != new_best_v6 && new_best_v6.is_some() {
let new_node = new_best_v6.unwrap();
let old_node = self.best_default_node_v6.take();
- let v6_destinations: Vec<_> = self
+ let v6_routes: Vec<_> = self
.required_default_routes
.iter()
- .filter(|ip| !ip.is_ipv4())
+ .filter(|ip| !ip.destination.is_ipv4())
.cloned()
.collect();
- for destination in v6_destinations {
- let new_route = Route::new(new_node.clone(), destination);
+ for route in v6_routes {
+ let new_route =
+ Route::new(new_node.clone(), route.destination).table(route.table_id);
+
if let Some(old_node) = &old_node {
- let old_route = Route::new(old_node.clone(), destination);
+ let old_route =
+ Route::new(old_node.clone(), route.destination).table(route.table_id);
if let Err(e) = self.delete_route(&old_route).await {
log::error!("Failed to remove old route {} - {}", &old_route, e);
@@ -478,6 +495,7 @@ impl RouteManagerImplInner {
node,
prefix: prefix.unwrap(),
metric,
+ table_id: msg.header.table,
}))
}
@@ -517,7 +535,7 @@ impl RouteManagerImplInner {
source_prefix_length: 0,
destination_prefix_length: route.prefix.prefix(),
tos: 0u8,
- table: RT_TABLE_MAIN,
+ table: route.table_id,
protocol: RTPROT_STATIC,
scope: RT_SCOPE_UNIVERSE,
kind: RTN_UNICAST,
@@ -557,7 +575,8 @@ impl RouteManagerImplInner {
.handle
.route()
.add_v4()
- .destination_prefix(v4_prefix.ip(), v4_prefix.prefix());
+ .destination_prefix(v4_prefix.ip(), v4_prefix.prefix())
+ .table(route.table_id);
if v4_prefix.size() > 1 {
add_message = add_message.scope(RT_SCOPE_LINK)
@@ -581,7 +600,8 @@ impl RouteManagerImplInner {
.handle
.route()
.add_v6()
- .destination_prefix(v6_prefix.ip(), v6_prefix.prefix());
+ .destination_prefix(v6_prefix.ip(), v6_prefix.prefix())
+ .table(route.table_id);
if v6_prefix.size() > 1 {
add_message = add_message.scope(RT_SCOPE_LINK)
diff --git a/talpid-core/src/routing/mod.rs b/talpid-core/src/routing/mod.rs
index 2baf625f2f..1b545c48fd 100644
--- a/talpid-core/src/routing/mod.rs
+++ b/talpid-core/src/routing/mod.rs
@@ -12,6 +12,9 @@ mod imp;
#[path = "unix.rs"]
mod imp;
+#[cfg(target_os = "linux")]
+use netlink_packet_route::rtnl::constants::RT_TABLE_MAIN;
+
pub use imp::{Error, RouteManager};
/// A netowrk route with a specific network node, destinaiton and an optional metric.
@@ -20,6 +23,8 @@ struct Route {
node: Node,
prefix: IpNetwork,
metric: Option<u32>,
+ #[cfg(target_os = "linux")]
+ table_id: u8,
}
impl Route {
@@ -28,8 +33,16 @@ impl Route {
node,
prefix,
metric: None,
+ #[cfg(target_os = "linux")]
+ table_id: RT_TABLE_MAIN,
}
}
+
+ #[cfg(target_os = "linux")]
+ fn table(mut self, new_id: u8) -> Self {
+ self.table_id = new_id;
+ self
+ }
}
impl fmt::Display for Route {
@@ -38,6 +51,8 @@ impl fmt::Display for Route {
if let Some(metric) = &self.metric {
write!(f, " metric {}", *metric)?;
}
+ #[cfg(target_os = "linux")]
+ write!(f, " table {}", self.table_id)?;
Ok(())
}
}