diff options
| author | David Lönnhager <david.l@mullvad.net> | 2021-04-16 13:05:17 +0200 |
|---|---|---|
| committer | David Lönnhager <david.l@mullvad.net> | 2021-07-02 09:54:19 +0200 |
| commit | fb2b7e9778350bace1ea636b8f11c76890eb5b98 (patch) | |
| tree | 83f984fa943d896c5937734983f00668fb1cd771 | |
| parent | af7d9b09663672d0a8a8a84c02387a9749a3bf98 (diff) | |
| download | mullvadvpn-fb2b7e9778350bace1ea636b8f11c76890eb5b98.tar.xz mullvadvpn-fb2b7e9778350bace1ea636b8f11c76890eb5b98.zip | |
Notify tunnel of errors while registering addresses in driver
| -rw-r--r-- | mullvad-cli/src/format.rs | 2 | ||||
| -rw-r--r-- | mullvad-management-interface/proto/management_interface.proto | 1 | ||||
| -rw-r--r-- | mullvad-management-interface/src/types.rs | 4 | ||||
| -rw-r--r-- | talpid-core/src/split_tunnel/windows/mod.rs | 27 | ||||
| -rw-r--r-- | talpid-core/src/tunnel_state_machine/mod.rs | 9 | ||||
| -rw-r--r-- | talpid-types/src/tunnel.rs | 5 |
6 files changed, 38 insertions, 10 deletions
diff --git a/mullvad-cli/src/format.rs b/mullvad-cli/src/format.rs index 52014076c3..b056ffff53 100644 --- a/mullvad-cli/src/format.rs +++ b/mullvad-cli/src/format.rs @@ -160,6 +160,8 @@ fn error_state_to_string(error_state: &ErrorState) -> String { IsOffline => "This device is offline, no tunnels can be established", #[cfg(target_os = "android")] VpnPermissionDenied => "The Android VPN permission was denied when creating the tunnel", + #[cfg(target_os = "windows")] + SplitTunnelError => "The split tunneling module reported an error", #[cfg(not(target_os = "android"))] _ => unreachable!("unknown error cause"), }; diff --git a/mullvad-management-interface/proto/management_interface.proto b/mullvad-management-interface/proto/management_interface.proto index e5ee4cb23f..39bfa20669 100644 --- a/mullvad-management-interface/proto/management_interface.proto +++ b/mullvad-management-interface/proto/management_interface.proto @@ -108,6 +108,7 @@ message ErrorState { TUNNEL_PARAMETER_ERROR = 5; IS_OFFLINE = 6; VPN_PERMISSION_DENIED = 7; + SPLIT_TUNNEL_ERROR = 8; } enum GenerationError { diff --git a/mullvad-management-interface/src/types.rs b/mullvad-management-interface/src/types.rs index bebdb14d77..abd0b3a17c 100644 --- a/mullvad-management-interface/src/types.rs +++ b/mullvad-management-interface/src/types.rs @@ -143,6 +143,10 @@ impl From<mullvad_types::states::TunnelState> for TunnelState { talpid_tunnel::ErrorStateCause::VpnPermissionDenied => { i32::from(Cause::VpnPermissionDenied) } + #[cfg(target_os = "windows")] + talpid_tunnel::ErrorStateCause::SplitTunnelError => { + i32::from(Cause::SplitTunnelError) + } }, blocking_error: error_state.block_failure().map(map_firewall_error), auth_fail_reason: if let talpid_tunnel::ErrorStateCause::AuthFailed( diff --git a/talpid-core/src/split_tunnel/windows/mod.rs b/talpid-core/src/split_tunnel/windows/mod.rs index c8a0eb183d..bf7ef40ee6 100644 --- a/talpid-core/src/split_tunnel/windows/mod.rs +++ b/talpid-core/src/split_tunnel/windows/mod.rs @@ -3,10 +3,12 @@ mod windows; use crate::{ tunnel::TunnelMetadata, + tunnel_state_machine::TunnelCommand, winnet::{ self, get_best_default_route, interface_luid_to_ip, WinNetAddrFamily, WinNetCallbackHandle, }, }; +use futures::channel::mpsc; use lazy_static::lazy_static; use std::{ ffi::OsStr, @@ -14,9 +16,9 @@ use std::{ net::{IpAddr, Ipv4Addr, Ipv6Addr}, os::windows::io::{AsRawHandle, RawHandle}, ptr, - sync::{Arc, Mutex}, + sync::{Arc, Mutex, Weak}, }; -use talpid_types::ErrorExt; +use talpid_types::{tunnel::ErrorStateCause, ErrorExt}; use winapi::{ shared::minwindef::{FALSE, TRUE}, um::{ @@ -77,6 +79,7 @@ pub struct SplitTunnel { event_thread: Option<std::thread::JoinHandle<()>>, quit_event: RawHandle, _route_change_callback: Option<WinNetCallbackHandle>, + daemon_tx: Weak<mpsc::UnboundedSender<TunnelCommand>>, } struct EventThreadContext { @@ -88,7 +91,7 @@ unsafe impl Send for EventThreadContext {} impl SplitTunnel { /// Initialize the driver. - pub fn new() -> Result<Self, Error> { + pub fn new(daemon_tx: Weak<mpsc::UnboundedSender<TunnelCommand>>) -> Result<Self, Error> { let handle = driver::DeviceHandle::new().map_err(Error::InitializationFailed)?; let mut event_overlapped: OVERLAPPED = unsafe { mem::zeroed() }; @@ -248,6 +251,7 @@ impl SplitTunnel { event_thread: Some(event_thread), quit_event, _route_change_callback: None, + daemon_tx, }) } @@ -303,6 +307,7 @@ impl SplitTunnel { let context = SplitTunnelDefaultRouteChangeHandlerContext::new( self.handle.clone(), + self.daemon_tx.clone(), tunnel_ipv4, tunnel_ipv6, internet_ipv4, @@ -399,6 +404,7 @@ impl Drop for SplitTunnel { struct SplitTunnelDefaultRouteChangeHandlerContext { handle: Arc<Mutex<driver::DeviceHandle>>, + pub daemon_tx: Weak<mpsc::UnboundedSender<TunnelCommand>>, pub tunnel_ipv4: Ipv4Addr, pub tunnel_ipv6: Option<Ipv6Addr>, pub internet_ipv4: Ipv4Addr, @@ -408,6 +414,7 @@ struct SplitTunnelDefaultRouteChangeHandlerContext { impl SplitTunnelDefaultRouteChangeHandlerContext { pub fn new( handle: Arc<Mutex<driver::DeviceHandle>>, + daemon_tx: Weak<mpsc::UnboundedSender<TunnelCommand>>, tunnel_ipv4: Ipv4Addr, tunnel_ipv6: Option<Ipv6Addr>, internet_ipv4: Ipv4Addr, @@ -415,6 +422,7 @@ impl SplitTunnelDefaultRouteChangeHandlerContext { ) -> Self { SplitTunnelDefaultRouteChangeHandlerContext { handle, + daemon_tx, tunnel_ipv4, tunnel_ipv6, internet_ipv4, @@ -442,6 +450,13 @@ unsafe extern "system" fn split_tunnel_default_route_change_handler( // Update the "internet interface" IP when best default route changes let ctx = &mut *(ctx as *mut SplitTunnelDefaultRouteChangeHandlerContext); + let daemon_tx = ctx.daemon_tx.upgrade(); + let maybe_send = move |content| { + if let Some(tx) = daemon_tx { + let _ = tx.unbounded_send(content); + } + }; + let result = match event_type { winnet::WinNetDefaultRouteChangeEventType::DefaultRouteChanged => { let ip = interface_luid_to_ip(address_family.clone(), default_route.interface_luid); @@ -450,7 +465,7 @@ unsafe extern "system" fn split_tunnel_default_route_change_handler( Ok(Some(ip)) => ip, Ok(None) => { log::error!("Failed to obtain new default route address: none found",); - // TODO: Send tunnel command + maybe_send(TunnelCommand::Block(ErrorStateCause::SplitTunnelError)); return; } Err(error) => { @@ -458,7 +473,7 @@ unsafe extern "system" fn split_tunnel_default_route_change_handler( "{}", error.display_chain_with_msg("Failed to obtain new default route address") ); - // TODO: Send tunnel command + maybe_send(TunnelCommand::Block(ErrorStateCause::SplitTunnelError)); return; } }; @@ -491,10 +506,10 @@ unsafe extern "system" fn split_tunnel_default_route_change_handler( }; if let Err(error) = result { - // TODO: Send tunnel command log::error!( "{}", error.display_chain_with_msg("Failed to register new addresses in split tunnel driver") ); + maybe_send(TunnelCommand::Block(ErrorStateCause::SplitTunnelError)); } } diff --git a/talpid-core/src/tunnel_state_machine/mod.rs b/talpid-core/src/tunnel_state_machine/mod.rs index 1ea7365688..2f8f6cea0c 100644 --- a/talpid-core/src/tunnel_state_machine/mod.rs +++ b/talpid-core/src/tunnel_state_machine/mod.rs @@ -218,7 +218,7 @@ impl TunnelStateMachine { log_dir: Option<PathBuf>, resource_dir: PathBuf, cache_dir: impl AsRef<Path>, - commands: mpsc::UnboundedReceiver<TunnelCommand>, + commands_rx: mpsc::UnboundedReceiver<TunnelCommand>, reset_firewall: bool, #[cfg(target_os = "android")] android_context: AndroidContext, #[cfg(windows)] exclude_paths: Vec<OsString>, @@ -243,7 +243,7 @@ impl TunnelStateMachine { ) .map_err(Error::InitDnsMonitorError)?; let mut offline_monitor = offline::spawn_monitor( - command_tx, + command_tx.clone(), #[cfg(target_os = "linux")] route_manager .handle() @@ -256,7 +256,8 @@ impl TunnelStateMachine { let is_offline = offline_monitor.is_offline().await; #[cfg(windows)] - let split_tunnel = split_tunnel::SplitTunnel::new().map_err(Error::InitSplitTunneling)?; + let split_tunnel = + split_tunnel::SplitTunnel::new(command_tx).map_err(Error::InitSplitTunneling)?; #[cfg(windows)] split_tunnel .set_paths(&exclude_paths) @@ -287,7 +288,7 @@ impl TunnelStateMachine { Ok(TunnelStateMachine { current_state: Some(initial_state), - commands: commands.fuse(), + commands: commands_rx.fuse(), shared_values, }) } diff --git a/talpid-types/src/tunnel.rs b/talpid-types/src/tunnel.rs index b3a75999b4..3c300c30cc 100644 --- a/talpid-types/src/tunnel.rs +++ b/talpid-types/src/tunnel.rs @@ -104,6 +104,9 @@ pub enum ErrorStateCause { /// The Android VPN permission was denied. #[cfg(target_os = "android")] VpnPermissionDenied, + /// Error reported by split tunnel module. + #[cfg(target_os = "windows")] + SplitTunnelError, } /// Errors that can occur when generating tunnel parameters. @@ -194,6 +197,8 @@ impl fmt::Display for ErrorStateCause { IsOffline => "This device is offline, no tunnels can be established", #[cfg(target_os = "android")] VpnPermissionDenied => "The Android VPN permission was denied when creating the tunnel", + #[cfg(target_os = "windows")] + SplitTunnelError => "The split tunneling module reported an error", }; write!(f, "{}", description) |
