summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJanito Vaqueiro Ferreira Filho <janito@mullvad.net>2019-02-13 09:22:33 -0200
committerJanito Vaqueiro Ferreira Filho <janito@mullvad.net>2019-02-13 09:22:33 -0200
commit3571f7a58af0fd838110d06beb91f21b737deccb (patch)
treed14fadc67c18d5c06250de60d78461a310334ce4
parent2aa65d23e6303536077e3e2189605554086a49e3 (diff)
parent9139eb7c67d995910b6b9e1411d04acc93b64c08 (diff)
downloadmullvadvpn-3571f7a58af0fd838110d06beb91f21b737deccb.tar.xz
mullvadvpn-3571f7a58af0fd838110d06beb91f21b737deccb.zip
Merge branch 'update-linux-offline-check'
-rw-r--r--CHANGELOG.md3
-rw-r--r--Cargo.lock24
-rw-r--r--talpid-core/Cargo.toml6
-rw-r--r--talpid-core/src/offline/linux.rs198
4 files changed, 114 insertions, 117 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5672999394..a0bd0c1655 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -29,6 +29,9 @@ Line wrap the file at 100 chars. Th
- Fix the potential reconnect loop in GUI, triggered by the timeout when receiving
the initial state of the daemon.
+#### Linux
+- Fix startup failure when network device with a hardware address that's not a MAC address is
+ present.
## [2019.1] - 2019-01-29
This release is identical to 2019.1-beta1
diff --git a/Cargo.lock b/Cargo.lock
index 27ac5b63fa..3bb867efd5 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -613,7 +613,7 @@ dependencies = [
[[package]]
name = "iproute2"
version = "0.0.2"
-source = "git+https://github.com/mullvad/netlink?branch=best-effort-nla-parsing#132ab47bcbb32079ba4ededaa76a3d7b6257da40"
+source = "git+https://github.com/mullvad/netlink?branch=ignore-hw-address#670b33f535107497ae5c32d02c92de62c5e800ba"
dependencies = [
"bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
"eui48 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -623,8 +623,8 @@ dependencies = [
"ipnetwork 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "netlink-socket 0.0.2 (git+https://github.com/mullvad/netlink?branch=best-effort-nla-parsing)",
- "rtnetlink 0.0.3 (git+https://github.com/mullvad/netlink?branch=best-effort-nla-parsing)",
+ "netlink-socket 0.0.2 (git+https://github.com/mullvad/netlink?branch=ignore-hw-address)",
+ "rtnetlink 0.0.3 (git+https://github.com/mullvad/netlink?branch=ignore-hw-address)",
"tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1148,7 +1148,7 @@ dependencies = [
[[package]]
name = "netlink-socket"
version = "0.0.2"
-source = "git+https://github.com/mullvad/netlink?branch=best-effort-nla-parsing#132ab47bcbb32079ba4ededaa76a3d7b6257da40"
+source = "git+https://github.com/mullvad/netlink?branch=ignore-hw-address#670b33f535107497ae5c32d02c92de62c5e800ba"
dependencies = [
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1545,14 +1545,14 @@ dependencies = [
[[package]]
name = "rtnetlink"
version = "0.0.3"
-source = "git+https://github.com/mullvad/netlink?branch=best-effort-nla-parsing#132ab47bcbb32079ba4ededaa76a3d7b6257da40"
+source = "git+https://github.com/mullvad/netlink?branch=ignore-hw-address#670b33f535107497ae5c32d02c92de62c5e800ba"
dependencies = [
"byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
"bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "netlink-socket 0.0.2 (git+https://github.com/mullvad/netlink?branch=best-effort-nla-parsing)",
+ "netlink-socket 0.0.2 (git+https://github.com/mullvad/netlink?branch=ignore-hw-address)",
"tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-reactor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1799,14 +1799,14 @@ dependencies = [
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
"hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"ipnetwork 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "iproute2 0.0.2 (git+https://github.com/mullvad/netlink?branch=best-effort-nla-parsing)",
+ "iproute2 0.0.2 (git+https://github.com/mullvad/netlink?branch=ignore-hw-address)",
"jsonrpc-core 8.0.2 (git+https://github.com/mullvad/jsonrpc?branch=mullvad-fork)",
"jsonrpc-macros 8.0.1 (git+https://github.com/mullvad/jsonrpc?branch=mullvad-fork)",
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"mnl 0.1.0 (git+https://github.com/mullvad/mnl-rs?rev=f0d19501b9b85be9a1ffaec8317a378bcbdf4fa6)",
- "netlink-socket 0.0.2 (git+https://github.com/mullvad/netlink?branch=best-effort-nla-parsing)",
+ "netlink-socket 0.0.2 (git+https://github.com/mullvad/netlink?branch=ignore-hw-address)",
"nftnl 0.1.0 (git+https://github.com/mullvad/nftnl-rs?rev=f0b1492fd2fd1f737dbffd047c9c60c300e6f7d6)",
"nix 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
"notify 4.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1814,7 +1814,7 @@ dependencies = [
"os_pipe 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"pfctl 0.2.1 (git+https://github.com/mullvad/pfctl-rs?rev=9f31b5ddcab941862470075eab83bb398195f3d6)",
"resolv-conf 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "rtnetlink 0.0.3 (git+https://github.com/mullvad/netlink?branch=best-effort-nla-parsing)",
+ "rtnetlink 0.0.3 (git+https://github.com/mullvad/netlink?branch=ignore-hw-address)",
"shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"system-configuration 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"talpid-ipc 0.1.0",
@@ -2448,7 +2448,7 @@ dependencies = [
"checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08"
"checksum ipnetwork 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1d1d8b990621b5b0806fac3dbf71d1833a4c0a9e25702d10bd8b2c629c7ae01c"
"checksum ipnetwork 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b3d862c86f7867f19b693ec86765e0252d82e53d4240b9b629815675a0714ad1"
-"checksum iproute2 0.0.2 (git+https://github.com/mullvad/netlink?branch=best-effort-nla-parsing)" = "<none>"
+"checksum iproute2 0.0.2 (git+https://github.com/mullvad/netlink?branch=ignore-hw-address)" = "<none>"
"checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b"
"checksum jsonrpc-client-core 0.5.0 (git+https://github.com/mullvad/jsonrpc-client-rs?rev=e9dbdc80)" = "<none>"
"checksum jsonrpc-client-core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f29cb249837420fb0cee7fb0fbf1d22679e121b160e71bb5e0d90b9df241c23e"
@@ -2486,7 +2486,7 @@ dependencies = [
"checksum mnl 0.1.0 (git+https://github.com/mullvad/mnl-rs?rev=f0d19501b9b85be9a1ffaec8317a378bcbdf4fa6)" = "<none>"
"checksum mnl-sys 0.1.0 (git+https://github.com/mullvad/mnl-rs?rev=f0d19501b9b85be9a1ffaec8317a378bcbdf4fa6)" = "<none>"
"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88"
-"checksum netlink-socket 0.0.2 (git+https://github.com/mullvad/netlink?branch=best-effort-nla-parsing)" = "<none>"
+"checksum netlink-socket 0.0.2 (git+https://github.com/mullvad/netlink?branch=ignore-hw-address)" = "<none>"
"checksum nftnl 0.1.0 (git+https://github.com/mullvad/nftnl-rs?rev=f0b1492fd2fd1f737dbffd047c9c60c300e6f7d6)" = "<none>"
"checksum nftnl-sys 0.1.0 (git+https://github.com/mullvad/nftnl-rs?rev=f0b1492fd2fd1f737dbffd047c9c60c300e6f7d6)" = "<none>"
"checksum nix 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d37e713a259ff641624b6cb20e3b12b2952313ba36b6823c0f16e6cfd9e5de17"
@@ -2528,7 +2528,7 @@ dependencies = [
"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"
"checksum resolv-conf 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c62bd95a41841efdf7fca2ae9951e64a8d8eae7e5da196d8ce489a2241491a92"
"checksum rs-release 0.1.7 (git+https://github.com/mullvad/rs-release?branch=snailquote-unescape)" = "<none>"
-"checksum rtnetlink 0.0.3 (git+https://github.com/mullvad/netlink?branch=best-effort-nla-parsing)" = "<none>"
+"checksum rtnetlink 0.0.3 (git+https://github.com/mullvad/netlink?branch=ignore-hw-address)" = "<none>"
"checksum rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "bcfe5b13211b4d78e5c2cadfebd7769197d95c639c35a50057eb4c05de811395"
"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
diff --git a/talpid-core/Cargo.toml b/talpid-core/Cargo.toml
index 154440f13c..4fcc06e61c 100644
--- a/talpid-core/Cargo.toml
+++ b/talpid-core/Cargo.toml
@@ -35,11 +35,11 @@ nix = "0.12"
[target.'cfg(target_os = "linux")'.dependencies]
dbus = "0.6"
failure = "0.1"
-iproute2 = { git = "https://github.com/mullvad/netlink", branch = "best-effort-nla-parsing" }
-netlink-socket = { git = "https://github.com/mullvad/netlink", branch = "best-effort-nla-parsing" }
+iproute2 = { git = "https://github.com/mullvad/netlink", branch = "ignore-hw-address" }
+netlink-socket = { git = "https://github.com/mullvad/netlink", branch = "ignore-hw-address" }
notify = "4.0"
resolv-conf = "0.6.1"
-rtnetlink = { git = "https://github.com/mullvad/netlink", branch = "best-effort-nla-parsing" }
+rtnetlink = { git = "https://github.com/mullvad/netlink", branch = "ignore-hw-address" }
nftnl = { git = "https://github.com/mullvad/nftnl-rs", rev = "f0b1492fd2fd1f737dbffd047c9c60c300e6f7d6", features = ["nftnl-1-1-0"] }
mnl = { git = "https://github.com/mullvad/mnl-rs", rev = "f0d19501b9b85be9a1ffaec8317a378bcbdf4fa6", features = ["mnl-1-0-4"] }
which = "2.0"
diff --git a/talpid-core/src/offline/linux.rs b/talpid-core/src/offline/linux.rs
index cc18a48a78..8adff502ca 100644
--- a/talpid-core/src/offline/linux.rs
+++ b/talpid-core/src/offline/linux.rs
@@ -1,13 +1,10 @@
use crate::tunnel_state_machine::TunnelCommand;
use error_chain::ChainedError;
use futures::{future::Either, sync::mpsc::UnboundedSender, Future, Stream};
-use iproute2::Link;
-use log::{error, trace, warn};
+use iproute2::{Address, Connection, ConnectionHandle, Link, NetlinkIpError};
+use log::{error, warn};
use netlink_socket::{Protocol, SocketAddr, TokioSocket};
-use rtnetlink::{
- LinkFlags, LinkHeader, LinkLayerType, LinkMessage, NetlinkCodec, NetlinkFramed, NetlinkMessage,
- RtnlMessage,
-};
+use rtnetlink::{LinkLayerType, NetlinkCodec, NetlinkFramed, NetlinkMessage};
use std::{collections::BTreeSet, thread};
error_chain! {
@@ -32,6 +29,8 @@ error_chain! {
const RTMGRP_NOTIFY: u32 = 1;
const RTMGRP_LINK: u32 = 2;
+const RTMGRP_IPV4_IFADDR: u32 = 0x10;
+const RTMGRP_IPV6_IFADDR: u32 = 0x100;
pub struct MonitorHandle;
@@ -39,11 +38,14 @@ pub fn spawn_monitor(sender: UnboundedSender<TunnelCommand>) -> Result<MonitorHa
let mut socket =
TokioSocket::new(Protocol::Route).chain_err(|| ErrorKind::NetlinkConnectionError)?;
socket
- .bind(&SocketAddr::new(0, RTMGRP_NOTIFY | RTMGRP_LINK))
+ .bind(&SocketAddr::new(
+ 0,
+ RTMGRP_NOTIFY | RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR,
+ ))
.chain_err(|| ErrorKind::NetlinkBindError)?;
let channel = NetlinkFramed::new(socket, NetlinkCodec::<NetlinkMessage>::new());
- let link_monitor = LinkMonitor::new(sender)?;
+ let link_monitor = LinkMonitor::new(sender);
thread::spawn(|| {
if let Err(error) = monitor_event_loop(channel, link_monitor) {
@@ -63,51 +65,103 @@ pub fn is_offline() -> bool {
})
}
+/// Checks if there are no running links or that none of the running links have IP addresses
+/// assigned to them.
fn check_if_offline() -> Result<bool> {
- Ok(list_links_providing_connectivity()?.next().is_none())
+ let mut connection = NetlinkConnection::new()?;
+ let interfaces = connection.running_interfaces()?;
+
+ if interfaces.is_empty() {
+ Ok(true)
+ } else {
+ // Check if the current IP addresses are not assigned to any one of the running interfaces
+ Ok(connection
+ .addresses()?
+ .into_iter()
+ .all(|address| !interfaces.contains(&address.index())))
+ }
+}
+
+struct NetlinkConnection {
+ connection: Option<Connection>,
+ connection_handle: ConnectionHandle,
}
-fn list_links_providing_connectivity() -> Result<impl Iterator<Item = Link>> {
- Ok(list_links()?.into_iter().filter(link_provides_connectivity))
+impl NetlinkConnection {
+ /// Open a connection on the netlink socket.
+ pub fn new() -> Result<Self> {
+ let (connection, connection_handle) =
+ iproute2::new_connection().chain_err(|| ErrorKind::NetlinkConnectionError)?;
+
+ Ok(NetlinkConnection {
+ connection: Some(connection),
+ connection_handle,
+ })
+ }
+
+ /// List all IP addresses assigned to all interfaces.
+ pub fn addresses(&mut self) -> Result<Vec<Address>> {
+ self.execute_request(self.connection_handle.address().get().execute())
+ }
+
+ /// List all links registered on the system.
+ fn links(&mut self) -> Result<Vec<Link>> {
+ self.execute_request(self.connection_handle.link().get().execute())
+ }
+
+ /// List all unique interface indices that have a running link.
+ pub fn running_interfaces(&mut self) -> Result<BTreeSet<u32>> {
+ let links = self.links()?;
+
+ Ok(links
+ .into_iter()
+ .filter(link_provides_connectivity)
+ .map(|link| link.index())
+ .collect())
+ }
+
+ /// Helper function to execute an asynchronous request synchronously.
+ fn execute_request<R>(&mut self, request: R) -> Result<R::Item>
+ where
+ R: Future<Error = NetlinkIpError>,
+ {
+ let connection = self
+ .connection
+ .take()
+ .ok_or(ErrorKind::NetlinkDisconnected)?;
+
+ let (result, connection) = match connection.select2(request).wait() {
+ Ok(Either::A(_)) => bail!(ErrorKind::NetlinkDisconnected),
+ Err(Either::A((error, _))) => bail!(Error::with_chain(error, ErrorKind::NetlinkError)),
+ Ok(Either::B((links, connection))) => (Ok(links), connection),
+ Err(Either::B((error, connection))) => (
+ Err(Error::with_chain(
+ failure::Fail::compat(error),
+ ErrorKind::GetLinksError,
+ )),
+ connection,
+ ),
+ };
+
+ self.connection = Some(connection);
+ result
+ }
}
-fn link_provides_connectivity(link: &impl BasicLinkInfo) -> bool {
+fn link_provides_connectivity(link: &Link) -> bool {
// Some tunnels have the link layer type set to None
link.link_layer_type() != LinkLayerType::Loopback
&& link.link_layer_type() != LinkLayerType::None
&& link.flags().is_running()
}
-fn list_links() -> Result<Vec<Link>> {
- let (connection, connection_handle) =
- iproute2::new_connection().chain_err(|| ErrorKind::NetlinkConnectionError)?;
- let links_request = connection_handle.link().get().execute();
-
- match connection.select2(links_request).wait() {
- Ok(Either::A(_)) => bail!(ErrorKind::NetlinkDisconnected),
- Ok(Either::B((links, _))) => Ok(links),
- Err(Either::A((error, _))) => Err(Error::with_chain(error, ErrorKind::NetlinkError)),
- Err(Either::B((error, _))) => Err(Error::with_chain(
- failure::Fail::compat(error),
- ErrorKind::GetLinksError,
- )),
- }
-}
-
fn monitor_event_loop(
channel: NetlinkFramed<NetlinkCodec<NetlinkMessage>>,
mut link_monitor: LinkMonitor,
) -> Result<()> {
channel
- .for_each(|(message, _address)| {
- let (_header, payload) = message.into_parts();
-
- match payload {
- RtnlMessage::NewLink(link_message) => link_monitor.new_link(link_message),
- RtnlMessage::DelLink(link_message) => link_monitor.del_link(link_message),
- _ => trace!("Ignoring unknown link message"),
- }
-
+ .for_each(|(_message, _address)| {
+ link_monitor.update();
Ok(())
})
.wait()
@@ -120,41 +174,18 @@ fn monitor_event_loop(
struct LinkMonitor {
is_offline: bool,
- running_links: BTreeSet<u32>,
sender: UnboundedSender<TunnelCommand>,
}
impl LinkMonitor {
- pub fn new(sender: UnboundedSender<TunnelCommand>) -> Result<Self> {
- let links: Vec<Link> = list_links_providing_connectivity()?.collect();
- let is_offline = links.is_empty();
- let running_links = links.into_iter().map(|link| link.index()).collect();
+ pub fn new(sender: UnboundedSender<TunnelCommand>) -> Self {
+ let is_offline = is_offline();
- Ok(LinkMonitor {
- is_offline,
- running_links,
- sender,
- })
- }
-
- pub fn new_link(&mut self, link_message: LinkMessage) {
- if self.is_offline && link_provides_connectivity(link_message.header()) {
- self.set_is_offline(false);
- }
-
- if let Ok(link) = Link::from_link_message(link_message) {
- if link_provides_connectivity(&link) {
- self.insert_link(link.index());
- } else {
- self.remove_link(link.index());
- }
- }
+ LinkMonitor { is_offline, sender }
}
- pub fn del_link(&mut self, link_message: LinkMessage) {
- if let Ok(link) = Link::from_link_message(link_message) {
- self.remove_link(link.index());
- }
+ pub fn update(&mut self) {
+ self.set_is_offline(is_offline());
}
fn set_is_offline(&mut self, is_offline: bool) {
@@ -165,41 +196,4 @@ impl LinkMonitor {
.unbounded_send(TunnelCommand::IsOffline(is_offline));
}
}
-
- fn insert_link(&mut self, link_index: u32) {
- self.running_links.insert(link_index);
- self.set_is_offline(false);
- }
-
- fn remove_link(&mut self, link_index: u32) {
- self.running_links.remove(&link_index);
- if self.running_links.is_empty() {
- self.set_is_offline(true);
- }
- }
-}
-
-trait BasicLinkInfo {
- fn flags(&self) -> LinkFlags;
- fn link_layer_type(&self) -> LinkLayerType;
-}
-
-impl BasicLinkInfo for Link {
- fn flags(&self) -> LinkFlags {
- self.flags()
- }
-
- fn link_layer_type(&self) -> LinkLayerType {
- self.link_layer_type()
- }
-}
-
-impl BasicLinkInfo for LinkHeader {
- fn flags(&self) -> LinkFlags {
- self.flags()
- }
-
- fn link_layer_type(&self) -> LinkLayerType {
- self.link_layer_type()
- }
}