summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorDavid Lönnhager <david.l@mullvad.net>2020-09-18 13:45:51 +0200
committerDavid Lönnhager <david.l@mullvad.net>2020-09-22 13:12:18 +0200
commite7a77c44d4c9efdbd1bf84d50aa48172b1b000fc (patch)
tree79f302b65a28c484c23cf6c3b9db9a69335cf4ff
parentaa040282b4c4b608a8f6e75d304a8f97af02833a (diff)
downloadmullvadvpn-e7a77c44d4c9efdbd1bf84d50aa48172b1b000fc.tar.xz
mullvadvpn-e7a77c44d4c9efdbd1bf84d50aa48172b1b000fc.zip
Support table IDs > 255 in the Linux route manager
-rw-r--r--talpid-core/src/routing/linux.rs47
-rw-r--r--talpid-core/src/routing/mod.rs12
2 files changed, 42 insertions, 17 deletions
diff --git a/talpid-core/src/routing/linux.rs b/talpid-core/src/routing/linux.rs
index bea318aacf..bcd91d39eb 100644
--- a/talpid-core/src/routing/linux.rs
+++ b/talpid-core/src/routing/linux.rs
@@ -19,7 +19,9 @@ use netlink_packet_route::{
link::{nlas::Nla as LinkNla, LinkMessage},
route::{nlas::Nla as RouteNla, RouteHeader, RouteMessage},
rtnl::{
- constants::{RTN_UNICAST, RTPROT_STATIC, RT_SCOPE_UNIVERSE, RT_TABLE_MAIN},
+ constants::{
+ RTN_UNICAST, RTPROT_STATIC, RT_SCOPE_UNIVERSE, RT_TABLE_COMPAT, RT_TABLE_MAIN,
+ },
RouteFlags,
},
rule::{nlas::Nla as RuleNla, RuleHeader, RuleMessage},
@@ -82,7 +84,7 @@ pub enum Error {
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
struct RequiredDefaultRoute {
- table_id: u8,
+ table_id: u32,
destination: IpNetwork,
}
@@ -204,7 +206,7 @@ impl RouteManagerImpl {
ipnetwork::IpNetwork::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0).unwrap();
let mut required_routes = HashSet::new();
required_routes.insert(
- RequiredRoute::new(zero_network, NetNode::DefaultNode).table(self.split_table_id as u8),
+ RequiredRoute::new(zero_network, NetNode::DefaultNode).table(self.split_table_id),
);
self.add_required_routes(required_routes).await
}
@@ -264,7 +266,7 @@ impl RouteManagerImpl {
IpNetwork::from(*server),
Node::device(tunnel_alias.to_string()),
)
- .table(self.split_table_id as u8),
+ .table(self.split_table_id),
);
}
@@ -617,6 +619,7 @@ impl RouteManagerImpl {
let destination_length = msg.header.destination_prefix_length;
let af_spec = msg.header.address_family;
+ let mut table_id = u32::from(msg.header.table);
for nla in msg.nlas.iter() {
match nla {
@@ -650,6 +653,10 @@ impl RouteManagerImpl {
RouteNla::Priority(priority) => {
metric = Some(*priority);
}
+
+ RouteNla::Table(id) => {
+ table_id = *id;
+ }
_ => continue,
}
}
@@ -677,7 +684,7 @@ impl RouteManagerImpl {
node,
prefix: prefix.unwrap(),
metric,
- table_id: msg.header.table,
+ table_id,
}))
}
@@ -707,6 +714,7 @@ impl RouteManagerImpl {
}
async fn delete_route(&self, route: &Route) -> Result<()> {
+ let compat_table = compat_table_id(route.table_id);
let mut route_message = RouteMessage {
header: RouteHeader {
address_family: if route.prefix.is_ipv4() {
@@ -717,7 +725,7 @@ impl RouteManagerImpl {
source_prefix_length: 0,
destination_prefix_length: route.prefix.prefix(),
tos: 0u8,
- table: route.table_id,
+ table: compat_table,
protocol: RTPROT_STATIC,
scope: RT_SCOPE_UNIVERSE,
kind: RTN_UNICAST,
@@ -725,6 +733,10 @@ impl RouteManagerImpl {
},
nlas: vec![RouteNla::Destination(ip_to_bytes(route.prefix.ip()))],
};
+ if compat_table == RT_TABLE_COMPAT {
+ route_message.nlas.push(RouteNla::Table(route.table_id));
+ }
+
if let Some(interface_name) = route.node.get_device() {
if let Some(iface_idx) = self.find_iface_idx(interface_name) {
route_message.nlas.push(RouteNla::Oif(iface_idx));
@@ -750,14 +762,13 @@ impl RouteManagerImpl {
}
async fn add_route(&mut self, route: Route) -> Result<()> {
- let add_message = match &route.prefix {
+ let mut add_message = match &route.prefix {
IpNetwork::V4(v4_prefix) => {
let mut add_message = self
.handle
.route()
.add_v4()
- .destination_prefix(v4_prefix.ip(), v4_prefix.prefix())
- .table(route.table_id);
+ .destination_prefix(v4_prefix.ip(), v4_prefix.prefix());
if v4_prefix.prefix() > 0 && v4_prefix.prefix() < 32 {
add_message = add_message.scope(RT_SCOPE_LINK);
@@ -781,8 +792,7 @@ impl RouteManagerImpl {
.handle
.route()
.add_v6()
- .destination_prefix(v6_prefix.ip(), v6_prefix.prefix())
- .table(route.table_id);
+ .destination_prefix(v6_prefix.ip(), v6_prefix.prefix());
if v6_prefix.prefix() > 0 && v6_prefix.prefix() < 128 {
add_message = add_message.scope(RT_SCOPE_LINK);
@@ -802,6 +812,12 @@ impl RouteManagerImpl {
}
};
+ let compat_table = compat_table_id(route.table_id);
+ add_message.header.table = compat_table;
+ if compat_table == RT_TABLE_COMPAT {
+ add_message.nlas.push(RouteNla::Table(route.table_id));
+ }
+
// Need to modify the request in place to set the correct flags to be able to replace any
// existing routes - self.handle.route().add_v4().execute() sets the NLM_F_EXCL flag which
// will make the request fail if a route with the same destination already exists.
@@ -834,6 +850,15 @@ fn ip_to_bytes(addr: IpAddr) -> Vec<u8> {
}
}
+fn compat_table_id(id: u32) -> u8 {
+ // RT_TABLE_COMPAT must be combined with nla Table(id)
+ if id > 255 {
+ RT_TABLE_COMPAT
+ } else {
+ id as u8
+ }
+}
+
#[cfg(test)]
mod test {
use super::*;
diff --git a/talpid-core/src/routing/mod.rs b/talpid-core/src/routing/mod.rs
index 764e845ae4..41d2ff1c57 100644
--- a/talpid-core/src/routing/mod.rs
+++ b/talpid-core/src/routing/mod.rs
@@ -24,7 +24,7 @@ pub struct Route {
prefix: IpNetwork,
metric: Option<u32>,
#[cfg(target_os = "linux")]
- table_id: u8,
+ table_id: u32,
}
impl Route {
@@ -34,12 +34,12 @@ impl Route {
prefix,
metric: None,
#[cfg(target_os = "linux")]
- table_id: RT_TABLE_MAIN,
+ table_id: u32::from(RT_TABLE_MAIN),
}
}
#[cfg(target_os = "linux")]
- fn table(mut self, new_id: u8) -> Self {
+ fn table(mut self, new_id: u32) -> Self {
self.table_id = new_id;
self
}
@@ -65,7 +65,7 @@ pub struct RequiredRoute {
prefix: IpNetwork,
node: NetNode,
#[cfg(target_os = "linux")]
- table_id: u8,
+ table_id: u32,
}
impl RequiredRoute {
@@ -75,13 +75,13 @@ impl RequiredRoute {
node: node.into(),
prefix,
#[cfg(target_os = "linux")]
- table_id: RT_TABLE_MAIN,
+ table_id: u32::from(RT_TABLE_MAIN),
}
}
/// Sets the routing table ID of the route.
#[cfg(target_os = "linux")]
- pub fn table(mut self, new_id: u8) -> Self {
+ pub fn table(mut self, new_id: u32) -> Self {
self.table_id = new_id;
self
}