diff options
| author | Markus Pettersson <markus.pettersson@mullvad.net> | 2024-07-30 13:04:20 +0200 |
|---|---|---|
| committer | Markus Pettersson <markus.pettersson@mullvad.net> | 2024-07-30 14:22:18 +0200 |
| commit | 5c9d6fc2de0c44c22a003b30fb83c1532b7ca9d0 (patch) | |
| tree | c7c7709779dd410f15c3214ca7f427da4b181240 | |
| parent | a9464196dbf588e193b133927b2ef54bca323e2c (diff) | |
| download | mullvadvpn-5c9d6fc2de0c44c22a003b30fb83c1532b7ca9d0.tar.xz mullvadvpn-5c9d6fc2de0c44c22a003b30fb83c1532b7ca9d0.zip | |
Reconnect if split tunnel state changed
9 files changed, 85 insertions, 21 deletions
diff --git a/mullvad-management-interface/src/types/conversions/states.rs b/mullvad-management-interface/src/types/conversions/states.rs index 3fd8fbacb5..80dbb8bf2f 100644 --- a/mullvad-management-interface/src/types/conversions/states.rs +++ b/mullvad-management-interface/src/types/conversions/states.rs @@ -107,7 +107,11 @@ impl From<mullvad_types::states::TunnelState> for proto::TunnelState { talpid_tunnel::ErrorStateCause::InvalidDnsServers(_) => { i32::from(Cause::SetDnsError) } - #[cfg(any(target_os = "windows", target_os = "macos"))] + #[cfg(any( + target_os = "windows", + target_os = "macos", + target_os = "android" + ))] talpid_tunnel::ErrorStateCause::SplitTunnelError => { i32::from(Cause::SplitTunnelError) } diff --git a/talpid-core/src/tunnel_state_machine/connected_state.rs b/talpid-core/src/tunnel_state_machine/connected_state.rs index 0e4b095bf5..bd67e975ef 100644 --- a/talpid-core/src/tunnel_state_machine/connected_state.rs +++ b/talpid-core/src/tunnel_state_machine/connected_state.rs @@ -330,11 +330,31 @@ impl ConnectedState { shared_values.bypass_socket(fd, done_tx); SameState(self) } - #[cfg(any(windows, target_os = "android"))] + #[cfg(windows)] Some(TunnelCommand::SetExcludedApps(result_tx, paths)) => { shared_values.exclude_paths(paths, result_tx); SameState(self) } + #[cfg(target_os = "android")] + Some(TunnelCommand::SetExcludedApps(result_tx, paths)) => { + match shared_values.exclude_paths(paths) { + Ok(changed) => { + let _ = result_tx.send(Ok(())); + if changed { + self.disconnect(shared_values, AfterDisconnect::Reconnect(0)) + } else { + SameState(self) + } + } + Err(err) => { + let _ = result_tx.send(Err(err)); + self.disconnect( + shared_values, + AfterDisconnect::Block(ErrorStateCause::SplitTunnelError), + ) + } + } + } #[cfg(target_os = "macos")] Some(TunnelCommand::SetExcludedApps(result_tx, paths)) => { match shared_values.set_exclude_paths(paths) { diff --git a/talpid-core/src/tunnel_state_machine/connecting_state.rs b/talpid-core/src/tunnel_state_machine/connecting_state.rs index ce347e764a..9e6a21190c 100644 --- a/talpid-core/src/tunnel_state_machine/connecting_state.rs +++ b/talpid-core/src/tunnel_state_machine/connecting_state.rs @@ -470,11 +470,27 @@ impl ConnectingState { shared_values.bypass_socket(fd, done_tx); SameState(self) } - #[cfg(any(windows, target_os = "android"))] + #[cfg(windows)] Some(TunnelCommand::SetExcludedApps(result_tx, paths)) => { shared_values.exclude_paths(paths, result_tx); SameState(self) } + #[cfg(target_os = "android")] + Some(TunnelCommand::SetExcludedApps(result_tx, paths)) => { + match shared_values.exclude_paths(paths) { + Ok(_changed) => { + let _ = result_tx.send(Ok(())); + SameState(self) + } + Err(error) => { + let _ = result_tx.send(Err(error)); + self.disconnect( + shared_values, + AfterDisconnect::Block(ErrorStateCause::SplitTunnelError), + ) + } + } + } #[cfg(target_os = "macos")] Some(TunnelCommand::SetExcludedApps(result_tx, paths)) => { match shared_values.set_exclude_paths(paths) { diff --git a/talpid-core/src/tunnel_state_machine/disconnected_state.rs b/talpid-core/src/tunnel_state_machine/disconnected_state.rs index 326ae5070b..e570d3af64 100644 --- a/talpid-core/src/tunnel_state_machine/disconnected_state.rs +++ b/talpid-core/src/tunnel_state_machine/disconnected_state.rs @@ -211,11 +211,16 @@ impl TunnelState for DisconnectedState { shared_values.bypass_socket(fd, done_tx); SameState(self) } - #[cfg(any(windows, target_os = "android"))] + #[cfg(windows)] Some(TunnelCommand::SetExcludedApps(result_tx, paths)) => { shared_values.exclude_paths(paths, result_tx); SameState(self) } + #[cfg(target_os = "android")] + Some(TunnelCommand::SetExcludedApps(result_tx, paths)) => { + let _ = result_tx.send(shared_values.exclude_paths(paths).map(|_| ())); + SameState(self) + } #[cfg(target_os = "macos")] Some(TunnelCommand::SetExcludedApps(result_tx, paths)) => { let _ = result_tx.send(shared_values.set_exclude_paths(paths).map(|_| ())); diff --git a/talpid-core/src/tunnel_state_machine/disconnecting_state.rs b/talpid-core/src/tunnel_state_machine/disconnecting_state.rs index def8b246e9..099208201e 100644 --- a/talpid-core/src/tunnel_state_machine/disconnecting_state.rs +++ b/talpid-core/src/tunnel_state_machine/disconnecting_state.rs @@ -76,11 +76,16 @@ impl DisconnectingState { shared_values.bypass_socket(fd, done_tx); AfterDisconnect::Nothing } - #[cfg(any(windows, target_os = "android"))] + #[cfg(windows)] Some(TunnelCommand::SetExcludedApps(result_tx, paths)) => { shared_values.exclude_paths(paths, result_tx); AfterDisconnect::Nothing } + #[cfg(target_os = "android")] + Some(TunnelCommand::SetExcludedApps(result_tx, paths)) => { + let _ = result_tx.send(shared_values.exclude_paths(paths).map(|_| ())); + AfterDisconnect::Nothing + } #[cfg(target_os = "macos")] Some(TunnelCommand::SetExcludedApps(result_tx, paths)) => { let _ = result_tx.send(shared_values.set_exclude_paths(paths).map(|_| ())); @@ -127,11 +132,16 @@ impl DisconnectingState { shared_values.bypass_socket(fd, done_tx); AfterDisconnect::Block(reason) } - #[cfg(any(windows, target_os = "android"))] + #[cfg(windows)] Some(TunnelCommand::SetExcludedApps(result_tx, paths)) => { shared_values.exclude_paths(paths, result_tx); AfterDisconnect::Block(reason) } + #[cfg(target_os = "android")] + Some(TunnelCommand::SetExcludedApps(result_tx, paths)) => { + let _ = result_tx.send(shared_values.exclude_paths(paths).map(|_| ())); + AfterDisconnect::Block(reason) + } #[cfg(target_os = "macos")] Some(TunnelCommand::SetExcludedApps(result_tx, paths)) => { let _ = result_tx.send(shared_values.set_exclude_paths(paths).map(|_| ())); @@ -179,11 +189,16 @@ impl DisconnectingState { shared_values.bypass_socket(fd, done_tx); AfterDisconnect::Reconnect(retry_attempt) } - #[cfg(any(windows, target_os = "android"))] + #[cfg(windows)] Some(TunnelCommand::SetExcludedApps(result_tx, paths)) => { shared_values.exclude_paths(paths, result_tx); AfterDisconnect::Reconnect(retry_attempt) } + #[cfg(target_os = "android")] + Some(TunnelCommand::SetExcludedApps(result_tx, paths)) => { + let _ = result_tx.send(shared_values.exclude_paths(paths).map(|_| ())); + AfterDisconnect::Reconnect(retry_attempt) + } #[cfg(target_os = "macos")] Some(TunnelCommand::SetExcludedApps(result_tx, paths)) => { let _ = result_tx.send(shared_values.set_exclude_paths(paths).map(|_| ())); diff --git a/talpid-core/src/tunnel_state_machine/error_state.rs b/talpid-core/src/tunnel_state_machine/error_state.rs index 19630cb7b0..b4f642d8e2 100644 --- a/talpid-core/src/tunnel_state_machine/error_state.rs +++ b/talpid-core/src/tunnel_state_machine/error_state.rs @@ -211,7 +211,12 @@ impl TunnelState for ErrorState { shared_values.bypass_socket(fd, done_tx); SameState(self) } - #[cfg(any(windows, target_os = "android"))] + #[cfg(target_os = "android")] + Some(TunnelCommand::SetExcludedApps(result_tx, paths)) => { + let _ = result_tx.send(shared_values.exclude_paths(paths).map(|_| ())); + SameState(self) + } + #[cfg(windows)] Some(TunnelCommand::SetExcludedApps(result_tx, paths)) => { shared_values.exclude_paths(paths, result_tx); SameState(self) diff --git a/talpid-core/src/tunnel_state_machine/mod.rs b/talpid-core/src/tunnel_state_machine/mod.rs index 95a90e26c1..f1f0340cd9 100644 --- a/talpid-core/src/tunnel_state_machine/mod.rs +++ b/talpid-core/src/tunnel_state_machine/mod.rs @@ -651,14 +651,10 @@ impl SharedTunnelStateValues { } /// Update the set of excluded paths (split tunnel apps) for the tunnel provider. + /// Returns `Ok(true)` if the tunnel state machine should issue a tunnel reconnect. #[cfg(target_os = "android")] - pub fn exclude_paths( - &mut self, - apps: Vec<String>, - tx: oneshot::Sender<Result<(), split_tunnel::Error>>, - ) { - let exclude_apps_result = self - .tun_provider + pub fn exclude_paths(&mut self, apps: Vec<String>) -> Result<bool, split_tunnel::Error> { + self.tun_provider .lock() .unwrap() .set_exclude_apps(apps) @@ -670,9 +666,12 @@ impl SharedTunnelStateValues { "Failed to restart tunnel after updating excluded apps", ) ); - }); - - let _ = tx.send(exclude_apps_result); + })?; + // NOTE: For now, we tell the TSM to always reconnect when this function has been + // successfully called. We still return a boolean value in case we would like to introduce + // some condition in the future, thus forcing the TSM to be ready to handle both cases + // already. + Ok(true) } } diff --git a/talpid-tunnel/src/tun_provider/android/mod.rs b/talpid-tunnel/src/tun_provider/android/mod.rs index 9ebae88ea3..f8ede32954 100644 --- a/talpid-tunnel/src/tun_provider/android/mod.rs +++ b/talpid-tunnel/src/tun_provider/android/mod.rs @@ -299,7 +299,7 @@ impl AndroidTunProvider { } fn prepare_tun_config_for_excluded_apps(&self, config: &mut TunConfig) { - config.excluded_packages = self.excluded_apps.clone(); + config.excluded_packages.clone_from(&self.excluded_apps); } /// Allow a socket to bypass the tunnel. diff --git a/talpid-types/src/tunnel.rs b/talpid-types/src/tunnel.rs index a3b2eb5638..eb8d155e35 100644 --- a/talpid-types/src/tunnel.rs +++ b/talpid-types/src/tunnel.rs @@ -96,7 +96,7 @@ pub enum ErrorStateCause { #[cfg(target_os = "android")] VpnPermissionDenied, /// Error reported by split tunnel module. - #[cfg(any(target_os = "windows", target_os = "macos"))] + #[cfg(any(target_os = "windows", target_os = "macos", target_os = "android"))] SplitTunnelError, /// Missing permissions required by macOS split tunneling. #[cfg(target_os = "macos")] @@ -202,7 +202,7 @@ 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(any(target_os = "windows", target_os = "macos"))] + #[cfg(any(target_os = "windows", target_os = "macos", target_os = "android"))] SplitTunnelError => "The split tunneling module reported an error", #[cfg(target_os = "macos")] NeedFullDiskPermissions => "Need full disk access to enable split tunneling", |
