diff options
| author | Janito Vaqueiro Ferreira Filho <janito@mullvad.net> | 2019-02-13 09:22:33 -0200 |
|---|---|---|
| committer | Janito Vaqueiro Ferreira Filho <janito@mullvad.net> | 2019-02-13 09:22:33 -0200 |
| commit | 3571f7a58af0fd838110d06beb91f21b737deccb (patch) | |
| tree | d14fadc67c18d5c06250de60d78461a310334ce4 | |
| parent | 2aa65d23e6303536077e3e2189605554086a49e3 (diff) | |
| parent | 9139eb7c67d995910b6b9e1411d04acc93b64c08 (diff) | |
| download | mullvadvpn-3571f7a58af0fd838110d06beb91f21b737deccb.tar.xz mullvadvpn-3571f7a58af0fd838110d06beb91f21b737deccb.zip | |
Merge branch 'update-linux-offline-check'
| -rw-r--r-- | CHANGELOG.md | 3 | ||||
| -rw-r--r-- | Cargo.lock | 24 | ||||
| -rw-r--r-- | talpid-core/Cargo.toml | 6 | ||||
| -rw-r--r-- | talpid-core/src/offline/linux.rs | 198 |
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() - } } |
