diff options
| author | David Lönnhager <david.l@mullvad.net> | 2020-09-18 13:45:51 +0200 |
|---|---|---|
| committer | David Lönnhager <david.l@mullvad.net> | 2020-09-22 13:12:18 +0200 |
| commit | e7a77c44d4c9efdbd1bf84d50aa48172b1b000fc (patch) | |
| tree | 79f302b65a28c484c23cf6c3b9db9a69335cf4ff | |
| parent | aa040282b4c4b608a8f6e75d304a8f97af02833a (diff) | |
| download | mullvadvpn-e7a77c44d4c9efdbd1bf84d50aa48172b1b000fc.tar.xz mullvadvpn-e7a77c44d4c9efdbd1bf84d50aa48172b1b000fc.zip | |
Support table IDs > 255 in the Linux route manager
| -rw-r--r-- | talpid-core/src/routing/linux.rs | 47 | ||||
| -rw-r--r-- | talpid-core/src/routing/mod.rs | 12 |
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 } |
