summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJanito Vaqueiro Ferreira Filho <janito@mullvad.net>2018-09-06 08:57:14 -0300
committerJanito Vaqueiro Ferreira Filho <janito@mullvad.net>2018-09-06 08:57:14 -0300
commitd051e71ae289a92be1743a6b844d290cbfae4fd9 (patch)
tree1f5c410b06b846fa588b8536b77d4872c2b13c7f
parentc448ca931fddacce052a392614d2d906033ca933 (diff)
parent1c9d41c964c3844aa2cf5aaa557b6d549f93f298 (diff)
downloadmullvadvpn-d051e71ae289a92be1743a6b844d290cbfae4fd9.tar.xz
mullvadvpn-d051e71ae289a92be1743a6b844d290cbfae4fd9.zip
Merge branch 'check-ipv6-enabled'
-rw-r--r--CHANGELOG.md4
-rw-r--r--Cargo.lock1
-rw-r--r--gui/packages/desktop/src/renderer/errors.js34
-rw-r--r--gui/packages/desktop/src/renderer/lib/daemon-rpc.js2
-rw-r--r--talpid-core/Cargo.toml1
-rw-r--r--talpid-core/src/lib.rs2
-rw-r--r--talpid-core/src/tunnel/mod.rs52
-rw-r--r--talpid-core/src/tunnel_state_machine/connecting_state.rs34
-rw-r--r--talpid-types/src/tunnel.rs5
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(&parameters)?;
- TunnelMonitor::new(
+ Ok(TunnelMonitor::new(
parameters.endpoint,
&parameters.options,
TUNNEL_INTERFACE_ALIAS.to_owned().map(OsString::from),
@@ -109,7 +121,7 @@ impl ConnectingState {
log_file.as_ref().map(PathBuf::as_path),
&parameters.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",