diff options
| author | Janito Vaqueiro Ferreira Filho <janito@mullvad.net> | 2018-12-03 16:58:04 -0200 |
|---|---|---|
| committer | Janito Vaqueiro Ferreira Filho <janito@mullvad.net> | 2018-12-11 10:15:49 -0200 |
| commit | 8663a6407791d4eba48c804683ece9b6f85db3e0 (patch) | |
| tree | 6dd09e97eaac5fa33e938aa676e70cef1e7c684a /talpid-core/src | |
| parent | c6a525169b56a04e9eadab888a21cec76ff6110c (diff) | |
| download | mullvadvpn-8663a6407791d4eba48c804683ece9b6f85db3e0.tar.xz mullvadvpn-8663a6407791d4eba48c804683ece9b6f85db3e0.zip | |
Implement `is_offline` for Linux
Diffstat (limited to 'talpid-core/src')
| -rw-r--r-- | talpid-core/src/offline/linux.rs | 73 | ||||
| -rw-r--r-- | talpid-core/src/offline/mod.rs | 6 |
2 files changed, 78 insertions, 1 deletions
diff --git a/talpid-core/src/offline/linux.rs b/talpid-core/src/offline/linux.rs new file mode 100644 index 0000000000..4b76120fb4 --- /dev/null +++ b/talpid-core/src/offline/linux.rs @@ -0,0 +1,73 @@ +extern crate iproute2; +extern crate rtnetlink; + +use error_chain::ChainedError; +use futures::{future::Either, sync::mpsc::UnboundedSender, Future}; +use log::warn; + +use self::iproute2::Link; +use self::rtnetlink::LinkLayerType; + +use tunnel_state_machine::TunnelCommand; + +error_chain! { + errors { + GetLinksError { + description("Failed to get list of IP links") + } + NetlinkConnectionError { + description("Failed to connect to netlink socket") + } + NetlinkError { + description("Error while communicating on the netlink socket") + } + NetlinkDisconnected { + description("Netlink connection has unexpectedly disconnected") + } + } +} + +pub struct MonitorHandle; + +pub fn spawn_monitor(_sender: UnboundedSender<TunnelCommand>) -> Result<MonitorHandle> { + Ok(MonitorHandle) +} + +pub fn is_offline() -> bool { + check_if_offline().unwrap_or_else(|error| { + let chained_error = error.chain_err(|| "Failed to check for internet connection"); + warn!("{}", chained_error.display_chain()); + false + }) +} + +fn check_if_offline() -> Result<bool> { + Ok(list_links_providing_connectivity()?.next().is_none()) +} + +fn list_links_providing_connectivity() -> Result<impl Iterator<Item = Link>> { + Ok(list_links()?.into_iter().filter(link_provides_connectivity)) +} + +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, + )), + } +} diff --git a/talpid-core/src/offline/mod.rs b/talpid-core/src/offline/mod.rs index 38ebc3fb1e..e73de2efc1 100644 --- a/talpid-core/src/offline/mod.rs +++ b/talpid-core/src/offline/mod.rs @@ -9,7 +9,11 @@ mod imp; #[path = "windows.rs"] mod imp; -#[cfg(not(any(windows, target_os = "macos")))] +#[cfg(target_os = "linux")] +#[path = "linux.rs"] +mod imp; + +#[cfg(not(any(windows, target_os = "linux", target_os = "macos")))] #[path = "dummy.rs"] mod imp; |
