diff options
| author | Emīls <emils@mullvad.net> | 2020-11-04 18:19:28 +0000 |
|---|---|---|
| committer | Emīls <emils@mullvad.net> | 2020-11-11 10:16:23 +0000 |
| commit | d0f9058d62308bd3213e02f00040808fb9f2d920 (patch) | |
| tree | 30e04a34db1116c4a39e33a3bd0212d74b845885 | |
| parent | aed5e13c1859ea0988b823b0b5a11ece50a2acc1 (diff) | |
| download | mullvadvpn-d0f9058d62308bd3213e02f00040808fb9f2d920.tar.xz mullvadvpn-d0f9058d62308bd3213e02f00040808fb9f2d920.zip | |
Parse loopback routes semi-correctly
| -rw-r--r-- | CHANGELOG.md | 1 | ||||
| -rw-r--r-- | talpid-core/src/routing/linux.rs | 54 | ||||
| -rw-r--r-- | talpid-core/src/routing/mod.rs | 5 |
3 files changed, 42 insertions, 18 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 0aaae48ca6..3e7c3fc1f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -82,6 +82,7 @@ Line wrap the file at 100 chars. Th - Reset DNS config correctly when the tunnel monitor unexpectedly goes down. - Set search domains in NetworkManager's DNS configuration, resolving issues where NetworkManager is used to manage DNS via systemd-resolved. +- Parse routes more permissively and log parsing errors less verbosely. ### Security - Restore the last target state if the daemon crashes. Previously, if auto-connect and diff --git a/talpid-core/src/routing/linux.rs b/talpid-core/src/routing/linux.rs index 8d5b76d2fe..cf9c621d84 100644 --- a/talpid-core/src/routing/linux.rs +++ b/talpid-core/src/routing/linux.rs @@ -9,7 +9,7 @@ use ipnetwork::IpNetwork; use std::{ collections::{BTreeMap, HashSet}, io, - net::{IpAddr, Ipv4Addr}, + net::{IpAddr, Ipv4Addr, Ipv6Addr}, }; use futures::{channel::mpsc::UnboundedReceiver, future::FutureExt, StreamExt, TryStreamExt}; @@ -440,6 +440,7 @@ impl RouteManagerImpl { let table_id = table_id.unwrap_or(RT_TABLE_MAIN as u32); let mut route_request = self.handle.route().get(version).execute(); + let mut num_ignored_loopback_interfaces: u32 = 0; while let Some(route) = route_request .try_next() .await @@ -449,9 +450,20 @@ impl RouteManagerImpl { if route.table_id != table_id { continue; } + // Ignore loopback routes - we don't want to mess with those anyway + if route.is_loopback() { + num_ignored_loopback_interfaces += 1; + continue; + } routes.insert(route); } } + if num_ignored_loopback_interfaces != 0 { + log::debug!( + "Ignored {} loopback routes", + num_ignored_loopback_interfaces + ); + } Ok(routes) } @@ -774,22 +786,38 @@ impl RouteManagerImpl { let mut node_addr = None; let mut device = None; let mut metric = None; - let mut gateway = None; + let mut gateway: Option<IpAddr> = None; let destination_length = msg.header.destination_prefix_length; let af_spec = msg.header.address_family; let mut table_id = u32::from(msg.header.table); + let is_ipv4 = match af_spec as i32 { + AF_INET => true, + AF_INET6 => false, + af_spec => { + log::error!("Unexpected routing protocol: {}", af_spec); + return Ok(None); + } + }; + + let mut is_loopback = false; + for nla in msg.nlas.iter() { match nla { RouteNla::Oif(device_idx) => { match self.iface_map.get(&device_idx) { Some(route_device) => { - if route_device.is_loopback() { - log::debug!("Ignoring route with interface '{}' because it's a loopback interface", route_device.name); - return Ok(None); + if !route_device.is_loopback() { + device = Some(route_device); + } else { + is_loopback = true; + gateway = if is_ipv4 { + Some(Ipv4Addr::LOCALHOST.into()) + } else { + Some(Ipv6Addr::LOCALHOST.into()) + }; } - device = Some(route_device); } None => { return Err(Error::UnknownDeviceIndex(*device_idx)); @@ -826,23 +854,13 @@ impl RouteManagerImpl { } } - - // when a gateway is specified but prefix is none, then this is a default route - if prefix.is_none() && gateway.is_some() { - prefix = match af_spec as i32 { - AF_INET => Some("0.0.0.0/0".parse().expect("failed to parse ipnetwork")), - AF_INET6 => Some("::/0".parse().expect("failed to parse ipnetwork")), - _ => None, - }; - } - - if device.is_none() && node_addr.is_none() || prefix.is_none() { + if device.is_none() && node_addr.is_none() && gateway.is_none() { return Err(Error::InvalidRoute); } let node = Node { - ip: node_addr.or(gateway), + ip: node_addr.or(gateway.into()), device: device.map(|dev| dev.name.clone()), }; diff --git a/talpid-core/src/routing/mod.rs b/talpid-core/src/routing/mod.rs index d75073df8a..15bf1b04ae 100644 --- a/talpid-core/src/routing/mod.rs +++ b/talpid-core/src/routing/mod.rs @@ -45,6 +45,11 @@ impl Route { self.table_id = new_id; self } + + #[cfg(target_os = "linux")] + fn is_loopback(&self) -> bool { + self.node.ip.map(|ip| ip.is_loopback()).unwrap_or(false) + } } impl fmt::Display for Route { |
