summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorEmīls <emils@mullvad.net>2020-11-04 18:19:28 +0000
committerEmīls <emils@mullvad.net>2020-11-11 10:16:23 +0000
commitd0f9058d62308bd3213e02f00040808fb9f2d920 (patch)
tree30e04a34db1116c4a39e33a3bd0212d74b845885
parentaed5e13c1859ea0988b823b0b5a11ece50a2acc1 (diff)
downloadmullvadvpn-d0f9058d62308bd3213e02f00040808fb9f2d920.tar.xz
mullvadvpn-d0f9058d62308bd3213e02f00040808fb9f2d920.zip
Parse loopback routes semi-correctly
-rw-r--r--CHANGELOG.md1
-rw-r--r--talpid-core/src/routing/linux.rs54
-rw-r--r--talpid-core/src/routing/mod.rs5
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 {