diff options
| author | Janito Vaqueiro Ferreira Filho <janito@mullvad.net> | 2018-09-06 08:57:14 -0300 |
|---|---|---|
| committer | Janito Vaqueiro Ferreira Filho <janito@mullvad.net> | 2018-09-06 08:57:14 -0300 |
| commit | d051e71ae289a92be1743a6b844d290cbfae4fd9 (patch) | |
| tree | 1f5c410b06b846fa588b8536b77d4872c2b13c7f | |
| parent | c448ca931fddacce052a392614d2d906033ca933 (diff) | |
| parent | 1c9d41c964c3844aa2cf5aaa557b6d549f93f298 (diff) | |
| download | mullvadvpn-d051e71ae289a92be1743a6b844d290cbfae4fd9.tar.xz mullvadvpn-d051e71ae289a92be1743a6b844d290cbfae4fd9.zip | |
Merge branch 'check-ipv6-enabled'
| -rw-r--r-- | CHANGELOG.md | 4 | ||||
| -rw-r--r-- | Cargo.lock | 1 | ||||
| -rw-r--r-- | gui/packages/desktop/src/renderer/errors.js | 34 | ||||
| -rw-r--r-- | gui/packages/desktop/src/renderer/lib/daemon-rpc.js | 2 | ||||
| -rw-r--r-- | talpid-core/Cargo.toml | 1 | ||||
| -rw-r--r-- | talpid-core/src/lib.rs | 2 | ||||
| -rw-r--r-- | talpid-core/src/tunnel/mod.rs | 52 | ||||
| -rw-r--r-- | talpid-core/src/tunnel_state_machine/connecting_state.rs | 34 | ||||
| -rw-r--r-- | talpid-types/src/tunnel.rs | 5 |
9 files changed, 106 insertions, 29 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c9ee2c6cd..db326d4788 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,8 +27,8 @@ Line wrap the file at 100 chars. Th - Add option to enable or disable IPv6 on the tunnel interface. - Log panics in the daemon to the log file. - Warn in the Settings screen if a new version is available. -- Enter a "blocked" state in case of connection error, relay server unavailability or invalid - configuration, which prevents leaking traffic until the user specifically requests to disconnect. +- Add a "blocked" state in the app that blocks the entire network and waits for user action when + something has gone wrong. - Add support for Ubuntu 14.04 and other distributions that use the Upstart init system. - Make scrollbar thumb draggable. - Ability to expand cities with multiple servers and configure the app to use a specific server. diff --git a/Cargo.lock b/Cargo.lock index 699e31e4a5..05ff2b7f7c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1654,6 +1654,7 @@ dependencies = [ "uuid 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "which 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "widestring 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winreg 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/gui/packages/desktop/src/renderer/errors.js b/gui/packages/desktop/src/renderer/errors.js index b333f66221..32ec75b105 100644 --- a/gui/packages/desktop/src/renderer/errors.js +++ b/gui/packages/desktop/src/renderer/errors.js @@ -4,22 +4,24 @@ import type { BlockReason } from './lib/daemon-rpc'; export class BlockedError extends Error { constructor(reason: BlockReason) { - switch (reason) { - case 'set_security_policy_error': - super('Failed to apply security policy'); - break; - case 'start_tunnel_error': - super('Failed to start tunnel connection'); - break; - case 'no_matching_relay': - super('No relay server matches the current settings'); - break; - case 'no_account_token': - super('No account token configured'); - break; - default: - super(`Unknown error: ${(reason: empty)}`); - } + const message = (function() { + switch (reason) { + case 'enable_ipv6_error': + return 'Could not configure IPv6, please enable it on your system or disable it in the app'; + case 'set_security_policy_error': + return 'Failed to apply security policy'; + case 'start_tunnel_error': + return 'Failed to start tunnel connection'; + case 'no_matching_relay': + return 'No relay server matches the current settings'; + case 'no_account_token': + return 'No account token configured'; + default: + return `Unknown error: ${(reason: empty)}`; + } + })(); + + super(message); } } diff --git a/gui/packages/desktop/src/renderer/lib/daemon-rpc.js b/gui/packages/desktop/src/renderer/lib/daemon-rpc.js index aa9f020826..7a3a0bb030 100644 --- a/gui/packages/desktop/src/renderer/lib/daemon-rpc.js +++ b/gui/packages/desktop/src/renderer/lib/daemon-rpc.js @@ -42,6 +42,7 @@ const LocationSchema = object({ }); export type BlockReason = + | 'enable_ipv6_error' | 'set_security_policy_error' | 'start_tunnel_error' | 'no_matching_relay' @@ -245,6 +246,7 @@ const AccountDataSchema = object({ }); const allBlockReasons: Array<BlockReason> = [ + 'enable_ipv6_error', 'set_security_policy_error', 'start_tunnel_error', 'no_matching_relay', diff --git a/talpid-core/Cargo.toml b/talpid-core/Cargo.toml index 23df76dfd8..1041d184a3 100644 --- a/talpid-core/Cargo.toml +++ b/talpid-core/Cargo.toml @@ -43,6 +43,7 @@ tokio-core = "0.1" [target.'cfg(windows)'.dependencies] widestring = "0.3" +winreg = "0.5" [dev-dependencies] tempfile = "3.0" diff --git a/talpid-core/src/lib.rs b/talpid-core/src/lib.rs index 55df5e135f..ecc530aec3 100644 --- a/talpid-core/src/lib.rs +++ b/talpid-core/src/lib.rs @@ -34,6 +34,8 @@ extern crate tokio_core; extern crate uuid; #[cfg(target_os = "linux")] extern crate which; +#[cfg(windows)] +extern crate winreg; extern crate openvpn_plugin; extern crate talpid_ipc; diff --git a/talpid-core/src/tunnel/mod.rs b/talpid-core/src/tunnel/mod.rs index ce49ea7b0d..59f032b286 100644 --- a/talpid-core/src/tunnel/mod.rs +++ b/talpid-core/src/tunnel/mod.rs @@ -60,6 +60,10 @@ error_chain!{ CredentialsWriteError { description("Error while writing credentials to temporary file") } + /// Tunnel can't have IPv6 enabled because the system has disabled IPv6 support. + EnableIpv6Error { + description("Can't enable IPv6 on tunnel interface because IPv6 is disabled") + } /// Running on an operating system which is not supported yet. UnsupportedPlatform { description("Running on an unsupported operating system") @@ -150,10 +154,9 @@ impl TunnelMonitor { where L: Fn(TunnelEvent) + Send + Sync + 'static, { - match tunnel_endpoint.tunnel { - TunnelEndpointData::OpenVpn(_) => (), - TunnelEndpointData::Wireguard(_) => bail!(ErrorKind::UnsupportedTunnelProtocol), - } + Self::ensure_endpoint_is_openvpn(&tunnel_endpoint)?; + Self::ensure_ipv6_can_be_used_if_enabled(tunnel_options)?; + let user_pass_file = Self::create_user_pass_file(username).chain_err(|| ErrorKind::CredentialsWriteError)?; let cmd = Self::create_openvpn_cmd( @@ -188,6 +191,21 @@ impl TunnelMonitor { }) } + fn ensure_endpoint_is_openvpn(endpoint: &TunnelEndpoint) -> Result<()> { + match endpoint.tunnel { + TunnelEndpointData::OpenVpn(_) => Ok(()), + TunnelEndpointData::Wireguard(_) => bail!(ErrorKind::UnsupportedTunnelProtocol), + } + } + + fn ensure_ipv6_can_be_used_if_enabled(tunnel_options: &TunnelOptions) -> Result<()> { + if tunnel_options.enable_ipv6 && !is_ipv6_enabled_in_os() { + bail!(ErrorKind::EnableIpv6Error); + } else { + Ok(()) + } + } + fn create_openvpn_cmd( remote: Endpoint, tunnel_alias: Option<OsString>, @@ -297,3 +315,29 @@ impl CloseHandle { self.0.close() } } + +fn is_ipv6_enabled_in_os() -> bool { + #[cfg(windows)] + { + use winreg::enums::*; + use winreg::RegKey; + + const IPV6_DISABLED: u8 = 0xFF; + + RegKey::predef(HKEY_LOCAL_MACHINE) + .open_subkey(r#"SYSTEM\CurrentControlSet\Services\Tcpip6\Parameters"#) + .and_then(|ipv6_config| ipv6_config.get_value("DisabledComponents")) + .map(|ipv6_disabled_bits: u32| (ipv6_disabled_bits & 0xFF) == IPV6_DISABLED as u32) + .unwrap_or(false) + } + #[cfg(target_os = "linux")] + { + fs::read_to_string("/proc/sys/net/ipv6/conf/all/disable_ipv6") + .map(|disable_ipv6| disable_ipv6.trim() == "0") + .unwrap_or(false) + } + #[cfg(target_os = "macos")] + { + true + } +} diff --git a/talpid-core/src/tunnel_state_machine/connecting_state.rs b/talpid-core/src/tunnel_state_machine/connecting_state.rs index 80fd94f364..6c31a08c69 100644 --- a/talpid-core/src/tunnel_state_machine/connecting_state.rs +++ b/talpid-core/src/tunnel_state_machine/connecting_state.rs @@ -14,12 +14,12 @@ use talpid_types::tunnel::BlockReason; use super::{ AfterDisconnect, BlockedState, ConnectedState, ConnectedStateBootstrap, DisconnectingState, - EventConsequence, Result, ResultExt, SharedTunnelStateValues, TunnelCommand, TunnelParameters, - TunnelState, TunnelStateTransition, TunnelStateWrapper, + EventConsequence, SharedTunnelStateValues, TunnelCommand, TunnelParameters, TunnelState, + TunnelStateTransition, TunnelStateWrapper, }; use logging; use security::SecurityPolicy; -use tunnel::{CloseHandle, TunnelEvent, TunnelMetadata, TunnelMonitor}; +use tunnel::{self, CloseHandle, TunnelEvent, TunnelMetadata, TunnelMonitor}; const MIN_TUNNEL_ALIVE_TIME: Duration = Duration::from_millis(1000); @@ -31,6 +31,18 @@ const TUNNEL_INTERFACE_ALIAS: Option<&str> = Some("Mullvad"); #[cfg(not(windows))] const TUNNEL_INTERFACE_ALIAS: Option<&str> = None; +error_chain! { + errors { + RotateLogError { + description("Failed to rotate tunnel log file") + } + } + + links { + TunnelMonitorError(tunnel::Error, tunnel::ErrorKind); + } +} + /// The tunnel has been started, but it is not established/functional. pub struct ConnectingState { tunnel_events: mpsc::UnboundedReceiver<TunnelEvent>, @@ -101,7 +113,7 @@ impl ConnectingState { }; let log_file = Self::prepare_tunnel_log_file(¶meters)?; - TunnelMonitor::new( + Ok(TunnelMonitor::new( parameters.endpoint, ¶meters.options, TUNNEL_INTERFACE_ALIAS.to_owned().map(OsString::from), @@ -109,7 +121,7 @@ impl ConnectingState { log_file.as_ref().map(PathBuf::as_path), ¶meters.resource_dir, on_tunnel_event, - ).chain_err(|| "Unable to start tunnel monitor") + )?) } fn prepare_tunnel_log_file(parameters: &TunnelParameters) -> Result<Option<PathBuf>> { @@ -119,7 +131,7 @@ impl ConnectingState { TunnelEndpointData::Wireguard(_) => WIREGUARD_LOG_FILENAME, }; let tunnel_log = log_dir.join(filename); - logging::rotate_log(&tunnel_log).chain_err(|| "Unable to rotate tunnel log")?; + logging::rotate_log(&tunnel_log).chain_err(|| ErrorKind::RotateLogError)?; Ok(Some(tunnel_log)) } else { Ok(None) @@ -291,9 +303,17 @@ impl TunnelState for ConnectingState { TunnelStateTransition::Connecting, ), Err(error) => { + let block_reason = match *error.kind() { + ErrorKind::TunnelMonitorError(tunnel::ErrorKind::EnableIpv6Error) => { + BlockReason::Ipv6Unavailable + } + _ => BlockReason::StartTunnelError, + }; + let chained_error = error.chain_err(|| "Failed to start tunnel"); error!("{}", chained_error.display_chain()); - BlockedState::enter(shared_values, (BlockReason::StartTunnelError, allow_lan)) + + BlockedState::enter(shared_values, (block_reason, allow_lan)) } } } diff --git a/talpid-types/src/tunnel.rs b/talpid-types/src/tunnel.rs index 77a1ffacb5..324ad4e7d4 100644 --- a/talpid-types/src/tunnel.rs +++ b/talpid-types/src/tunnel.rs @@ -21,6 +21,8 @@ pub enum TunnelStateTransition { #[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] pub enum BlockReason { + /// Failed to configure IPv6 because it's disabled in the platform. + Ipv6Unavailable, /// Failed to set security policy. SetSecurityPolicyError, /// Failed to start connection to remote server. @@ -34,6 +36,9 @@ pub enum BlockReason { impl fmt::Display for BlockReason { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { let description = match *self { + BlockReason::Ipv6Unavailable => { + "Failed to configure IPv6 because it's disabled in the platform" + } BlockReason::SetSecurityPolicyError => "Failed to set security policy", BlockReason::StartTunnelError => "Failed to start connection to remote server", BlockReason::NoMatchingRelay => "No relay server matches the current settings", |
