summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJanito Vaqueiro Ferreira Filho <janito@mullvad.net>2018-12-19 10:54:34 -0200
committerJanito Vaqueiro Ferreira Filho <janito@mullvad.net>2019-01-09 07:44:06 -0200
commit027a4c5260f31e4edfc3a3ddb70cbc1a146e6c40 (patch)
treec27fb186053f71296301d967a0d21ba714e6cb44
parent8768f64ea9b8df2483735e4df92272cf2163deee (diff)
downloadmullvadvpn-027a4c5260f31e4edfc3a3ddb70cbc1a146e6c40.tar.xz
mullvadvpn-027a4c5260f31e4edfc3a3ddb70cbc1a146e6c40.zip
Block when TAP adapter problem is detected
-rw-r--r--gui/packages/desktop/src/main/daemon-rpc.js4
-rw-r--r--gui/packages/desktop/src/renderer/components/NotificationArea.js2
-rw-r--r--talpid-core/src/tunnel_state_machine/connected_state.rs16
-rw-r--r--talpid-core/src/tunnel_state_machine/connecting_state.rs61
-rw-r--r--talpid-core/src/tunnel_state_machine/disconnecting_state.rs18
-rw-r--r--talpid-types/src/tunnel.rs3
6 files changed, 81 insertions, 23 deletions
diff --git a/gui/packages/desktop/src/main/daemon-rpc.js b/gui/packages/desktop/src/main/daemon-rpc.js
index 26da6e14af..bb55e5d335 100644
--- a/gui/packages/desktop/src/main/daemon-rpc.js
+++ b/gui/packages/desktop/src/main/daemon-rpc.js
@@ -52,7 +52,8 @@ export type BlockReason =
| 'set_dns_error'
| 'start_tunnel_error'
| 'no_matching_relay'
- | 'is_offline',
+ | 'is_offline'
+ | 'tap_adapter_problem',
}
| { reason: 'auth_failed', details: ?string };
@@ -314,6 +315,7 @@ const TunnelStateTransitionSchema = oneOf(
'start_tunnel_error',
'no_matching_relay',
'is_offline',
+ 'tap_adapter_problem',
),
}),
object({
diff --git a/gui/packages/desktop/src/renderer/components/NotificationArea.js b/gui/packages/desktop/src/renderer/components/NotificationArea.js
index 646dd236c2..3eba431a52 100644
--- a/gui/packages/desktop/src/renderer/components/NotificationArea.js
+++ b/gui/packages/desktop/src/renderer/components/NotificationArea.js
@@ -55,6 +55,8 @@ function getBlockReasonMessage(blockReason: BlockReason): string {
return 'No relay server matches the current settings';
case 'is_offline':
return 'This device is offline, no tunnels can be established';
+ case 'tap_adapter_problem':
+ return "Unable to detect a working TAP adapter on this device. If you've disabled it, enable it again. Otherwise, please reinstall the app";
default:
return `Unknown error: ${(blockReason.reason: empty)}`;
}
diff --git a/talpid-core/src/tunnel_state_machine/connected_state.rs b/talpid-core/src/tunnel_state_machine/connected_state.rs
index 961889d6c2..db28a200ef 100644
--- a/talpid-core/src/tunnel_state_machine/connected_state.rs
+++ b/talpid-core/src/tunnel_state_machine/connected_state.rs
@@ -9,9 +9,9 @@ use talpid_types::{
};
use super::{
- AfterDisconnect, ConnectingState, DisconnectingState, EventConsequence, Result, ResultExt,
- SharedTunnelStateValues, TunnelCommand, TunnelParameters, TunnelState, TunnelStateTransition,
- TunnelStateWrapper,
+ AfterDisconnect, BlockedState, ConnectingState, DisconnectingState, EventConsequence, Result,
+ ResultExt, SharedTunnelStateValues, TunnelCommand, TunnelParameters, TunnelState,
+ TunnelStateTransition, TunnelStateWrapper,
};
use crate::{
security::SecurityPolicy,
@@ -22,7 +22,7 @@ pub struct ConnectedStateBootstrap {
pub metadata: TunnelMetadata,
pub tunnel_events: mpsc::UnboundedReceiver<TunnelEvent>,
pub tunnel_parameters: TunnelParameters,
- pub tunnel_close_event: oneshot::Receiver<()>,
+ pub tunnel_close_event: oneshot::Receiver<Option<BlockReason>>,
pub close_handle: CloseHandle,
}
@@ -31,7 +31,7 @@ pub struct ConnectedState {
metadata: TunnelMetadata,
tunnel_events: mpsc::UnboundedReceiver<TunnelEvent>,
tunnel_parameters: TunnelParameters,
- tunnel_close_event: oneshot::Receiver<()>,
+ tunnel_close_event: oneshot::Receiver<Option<BlockReason>>,
close_handle: CloseHandle,
}
@@ -170,7 +170,11 @@ impl ConnectedState {
use self::EventConsequence::*;
match self.tunnel_close_event.poll() {
- Ok(Async::Ready(_)) => {}
+ Ok(Async::Ready(block_reason)) => {
+ if let Some(reason) = block_reason {
+ return NewState(BlockedState::enter(shared_values, reason));
+ }
+ }
Ok(Async::NotReady) => return NoEvents(self),
Err(_cancelled) => log::warn!("Tunnel monitor thread has stopped unexpectedly"),
}
diff --git a/talpid-core/src/tunnel_state_machine/connecting_state.rs b/talpid-core/src/tunnel_state_machine/connecting_state.rs
index 6e7b88a212..a549145e90 100644
--- a/talpid-core/src/tunnel_state_machine/connecting_state.rs
+++ b/talpid-core/src/tunnel_state_machine/connecting_state.rs
@@ -54,7 +54,7 @@ error_chain! {
pub struct ConnectingState {
tunnel_events: mpsc::UnboundedReceiver<TunnelEvent>,
tunnel_parameters: TunnelParameters,
- tunnel_close_event: oneshot::Receiver<()>,
+ tunnel_close_event: oneshot::Receiver<Option<BlockReason>>,
close_handle: CloseHandle,
retry_attempt: u32,
}
@@ -147,25 +147,23 @@ impl ConnectingState {
}
}
- fn spawn_tunnel_monitor_wait_thread(tunnel_monitor: TunnelMonitor) -> oneshot::Receiver<()> {
+ fn spawn_tunnel_monitor_wait_thread(
+ tunnel_monitor: TunnelMonitor,
+ ) -> oneshot::Receiver<Option<BlockReason>> {
let (tunnel_close_event_tx, tunnel_close_event_rx) = oneshot::channel();
thread::spawn(move || {
let start = Instant::now();
- match tunnel_monitor.wait() {
- Ok(_) => debug!("Tunnel has finished without errors"),
- Err(error) => {
- let chained_error = error.chain_err(|| "Tunnel has stopped unexpectedly");
- warn!("{}", chained_error.display_chain());
- }
- }
+ let block_reason = Self::wait_for_tunnel_monitor(tunnel_monitor);
- if let Some(remaining_time) = MIN_TUNNEL_ALIVE_TIME.checked_sub(start.elapsed()) {
- thread::sleep(remaining_time);
+ if block_reason.is_none() {
+ if let Some(remaining_time) = MIN_TUNNEL_ALIVE_TIME.checked_sub(start.elapsed()) {
+ thread::sleep(remaining_time);
+ }
}
- if tunnel_close_event_tx.send(()).is_err() {
+ if tunnel_close_event_tx.send(block_reason).is_err() {
warn!("Tunnel state machine stopped before receiving tunnel closed event");
}
@@ -175,6 +173,39 @@ impl ConnectingState {
tunnel_close_event_rx
}
+ fn wait_for_tunnel_monitor(tunnel_monitor: TunnelMonitor) -> Option<BlockReason> {
+ match tunnel_monitor.wait() {
+ Ok(_) => {
+ debug!("Tunnel has finished without errors");
+ None
+ }
+ Err(error) => match error {
+ #[cfg(windows)]
+ error @ tunnel::Error(
+ tunnel::ErrorKind::OpenVpnTunnelMonitoringError(
+ tunnel::openvpn::ErrorKind::DisabledTapAdapter,
+ ),
+ _,
+ )
+ | error @ tunnel::Error(
+ tunnel::ErrorKind::OpenVpnTunnelMonitoringError(
+ tunnel::openvpn::ErrorKind::MissingTapAdapter,
+ ),
+ _,
+ ) => {
+ let chained_error = error.chain_err(|| "TAP adapter problem detected");
+ warn!("{}", chained_error.display_chain());
+ Some(BlockReason::TapAdapterProblem)
+ }
+ error => {
+ let chained_error = error.chain_err(|| "Tunnel has stopped unexpectedly");
+ warn!("{}", chained_error.display_chain());
+ None
+ }
+ },
+ }
+ }
+
fn into_connected_state_bootstrap(self, metadata: TunnelMetadata) -> ConnectedStateBootstrap {
ConnectedStateBootstrap {
metadata,
@@ -300,7 +331,11 @@ impl ConnectingState {
shared_values: &mut SharedTunnelStateValues,
) -> EventConsequence<Self> {
match self.tunnel_close_event.poll() {
- Ok(Async::Ready(_)) => {}
+ Ok(Async::Ready(block_reason)) => {
+ if let Some(reason) = block_reason {
+ return EventConsequence::NewState(BlockedState::enter(shared_values, reason));
+ }
+ }
Ok(Async::NotReady) => return EventConsequence::NoEvents(self),
Err(_cancelled) => warn!("Tunnel monitor thread has stopped unexpectedly"),
}
diff --git a/talpid-core/src/tunnel_state_machine/disconnecting_state.rs b/talpid-core/src/tunnel_state_machine/disconnecting_state.rs
index ec8be8cfe1..6f470fe370 100644
--- a/talpid-core/src/tunnel_state_machine/disconnecting_state.rs
+++ b/talpid-core/src/tunnel_state_machine/disconnecting_state.rs
@@ -16,7 +16,7 @@ use crate::tunnel::CloseHandle;
/// This state is active from when we manually trigger a tunnel kill until the tunnel wait
/// operation (TunnelExit) returned.
pub struct DisconnectingState {
- exited: oneshot::Receiver<()>,
+ exited: oneshot::Receiver<Option<BlockReason>>,
after_disconnect: AfterDisconnect,
}
@@ -103,14 +103,22 @@ impl DisconnectingState {
match self.exited.poll() {
Ok(Async::NotReady) => NoEvents(self),
- Ok(Async::Ready(_)) | Err(_) => NewState(self.after_disconnect(shared_values)),
+ Ok(Async::Ready(block_reason)) => {
+ NewState(self.after_disconnect(block_reason, shared_values))
+ }
+ Err(_) => NewState(self.after_disconnect(None, shared_values)),
}
}
fn after_disconnect(
self,
+ block_reason: Option<BlockReason>,
shared_values: &mut SharedTunnelStateValues,
) -> (TunnelStateWrapper, TunnelStateTransition) {
+ if let Some(reason) = block_reason {
+ return BlockedState::enter(shared_values, reason);
+ }
+
match self.after_disconnect {
AfterDisconnect::Nothing => DisconnectedState::enter(shared_values, ()),
AfterDisconnect::Block(reason) => BlockedState::enter(shared_values, reason),
@@ -122,7 +130,11 @@ impl DisconnectingState {
}
impl TunnelState for DisconnectingState {
- type Bootstrap = (CloseHandle, oneshot::Receiver<()>, AfterDisconnect);
+ type Bootstrap = (
+ CloseHandle,
+ oneshot::Receiver<Option<BlockReason>>,
+ AfterDisconnect,
+ );
fn enter(
_: &mut SharedTunnelStateValues,
diff --git a/talpid-types/src/tunnel.rs b/talpid-types/src/tunnel.rs
index f3b28e8bfe..613204ab19 100644
--- a/talpid-types/src/tunnel.rs
+++ b/talpid-types/src/tunnel.rs
@@ -56,6 +56,8 @@ pub enum BlockReason {
NoMatchingRelay,
/// This device is offline, no tunnels can be established.
IsOffline,
+ /// A problem with the TAP adapter has been detected.
+ TapAdapterProblem,
}
impl fmt::Display for BlockReason {
@@ -78,6 +80,7 @@ impl fmt::Display for BlockReason {
StartTunnelError => "Failed to start connection to remote server",
NoMatchingRelay => "No relay server matches the current settings",
IsOffline => "This device is offline, no tunnels can be established",
+ TapAdapterProblem => "A problem with the TAP adapter has been detected",
};
write!(f, "{}", description)