diff options
| author | Janito Vaqueiro Ferreira Filho <janito@mullvad.net> | 2018-12-19 10:54:34 -0200 |
|---|---|---|
| committer | Janito Vaqueiro Ferreira Filho <janito@mullvad.net> | 2019-01-09 07:44:06 -0200 |
| commit | 027a4c5260f31e4edfc3a3ddb70cbc1a146e6c40 (patch) | |
| tree | c27fb186053f71296301d967a0d21ba714e6cb44 | |
| parent | 8768f64ea9b8df2483735e4df92272cf2163deee (diff) | |
| download | mullvadvpn-027a4c5260f31e4edfc3a3ddb70cbc1a146e6c40.tar.xz mullvadvpn-027a4c5260f31e4edfc3a3ddb70cbc1a146e6c40.zip | |
Block when TAP adapter problem is detected
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) |
