diff options
| author | David Lönnhager <david.l@mullvad.net> | 2024-08-29 10:33:16 +0200 |
|---|---|---|
| committer | David Lönnhager <david.l@mullvad.net> | 2024-09-02 12:35:30 +0200 |
| commit | be93a1f57b1f8fff5fce546f3fd48c0efae5fd74 (patch) | |
| tree | f0ab209894d1d0b31a018d80ffa7fd927d3e3b90 | |
| parent | 020dc16cd790cc460f967bdf888dcad072a57e62 (diff) | |
| download | mullvadvpn-be93a1f57b1f8fff5fce546f3fd48c0efae5fd74.tar.xz mullvadvpn-be93a1f57b1f8fff5fce546f3fd48c0efae5fd74.zip | |
Remove split tunnel utun when entering the disconnected state
| -rw-r--r-- | talpid-core/src/split_tunnel/macos/mod.rs | 60 | ||||
| -rw-r--r-- | talpid-core/src/tunnel_state_machine/disconnected_state.rs | 10 |
2 files changed, 70 insertions, 0 deletions
diff --git a/talpid-core/src/split_tunnel/macos/mod.rs b/talpid-core/src/split_tunnel/macos/mod.rs index 1c705f5e6d..b3acdb0136 100644 --- a/talpid-core/src/split_tunnel/macos/mod.rs +++ b/talpid-core/src/split_tunnel/macos/mod.rs @@ -113,6 +113,11 @@ enum Message { result_tx: oneshot::Sender<Result<(), Error>>, vpn_interface: VpnInterface, }, + /// Remove VPN tunnel interface. It is sufficient to call this when entering the disconnected + /// state, to avoid pointless cleanup during reconnects. + ResetTunnel { + result_tx: oneshot::Sender<Result<(), Error>>, + }, } /// Handle for interacting with the split tunnel module @@ -157,6 +162,14 @@ impl Handle { }); result_rx.await.map_err(|_| Error::unavailable())? } + + /// Forget the VPN tunnel interface. This destroys the split tunneling interface when it is + /// active. + pub async fn reset_tunnel(&self) -> Result<(), Error> { + let (result_tx, result_rx) = oneshot::channel(); + let _ = self.tx.send(Message::ResetTunnel { result_tx }); + result_rx.await.map_err(|_| Error::unavailable())? + } } impl SplitTunnel { @@ -259,6 +272,9 @@ impl SplitTunnel { } => { let _ = result_tx.send(self.state.set_tunnel(vpn_interface).await); } + Message::ResetTunnel { result_tx } => { + let _ = result_tx.send(self.state.reset_tunnel().await); + } } true } @@ -473,6 +489,50 @@ impl State { } } + /// Forget the VPN tunnel interface. This destroys the split tunneling interface when it is + /// active. + pub async fn reset_tunnel(&mut self) -> Result<(), Error> { + self.transition(|state| state.reset_tunnel_inner()).await + } + + async fn reset_tunnel_inner(self) -> Result<Self, ErrorWithTransition> { + match self { + // If split tunneling is currently active, that means that there are paths to exclude, + // so shut down the ST utun but keep the process monitor. + State::Active { + route_manager, + process, + tun_handle, + vpn_interface: _, + } => { + if let Err(error) = tun_handle.shutdown().await { + log::error!("Failed to stop split tunnel: {error}"); + } + Ok(State::ProcessMonitorOnly { + route_manager, + process, + }) + } + // If we're in standby mode, simply forget the VPN interface. + State::StandBy { + route_manager, + vpn_interface: _, + } => Ok(State::NoExclusions { route_manager }), + // If we're in `Failed`, just forget the VPN interface. + State::Failed { + route_manager, + vpn_interface: _, + cause, + } => Ok(State::Failed { + route_manager, + vpn_interface: None, + cause, + }), + // For any other state, do nothing. + _ => Ok(self), + } + } + /// Update VPN tunnel interface that non-excluded packets are sent on async fn set_tunnel(&mut self, vpn_interface: VpnInterface) -> Result<(), Error> { self.transition(move |self_| self_.set_tunnel_inner(vpn_interface)) diff --git a/talpid-core/src/tunnel_state_machine/disconnected_state.rs b/talpid-core/src/tunnel_state_machine/disconnected_state.rs index 4ee19a5e16..74cd3b65c4 100644 --- a/talpid-core/src/tunnel_state_machine/disconnected_state.rs +++ b/talpid-core/src/tunnel_state_machine/disconnected_state.rs @@ -21,6 +21,16 @@ impl DisconnectedState { should_reset_firewall: bool, ) -> (Box<dyn TunnelState>, TunnelStateTransition) { #[cfg(target_os = "macos")] + if let Err(err) = shared_values + .runtime + .block_on(shared_values.split_tunnel.reset_tunnel()) + { + log::error!( + "{}", + err.display_chain_with_msg("Failed to disable split tunneling") + ); + } + #[cfg(target_os = "macos")] if shared_values.block_when_disconnected { if let Err(err) = Self::setup_local_dns_config(shared_values) { log::error!( |
