summaryrefslogtreecommitdiffhomepage
path: root/talpid-core/src
diff options
context:
space:
mode:
authorJanito Vaqueiro Ferreira Filho <janito@mullvad.net>2018-12-03 16:58:04 -0200
committerJanito Vaqueiro Ferreira Filho <janito@mullvad.net>2018-12-11 10:15:49 -0200
commit8663a6407791d4eba48c804683ece9b6f85db3e0 (patch)
tree6dd09e97eaac5fa33e938aa676e70cef1e7c684a /talpid-core/src
parentc6a525169b56a04e9eadab888a21cec76ff6110c (diff)
downloadmullvadvpn-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.rs73
-rw-r--r--talpid-core/src/offline/mod.rs6
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;