summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md4
-rw-r--r--talpid-core/src/split_tunnel/macos/mod.rs60
-rw-r--r--talpid-core/src/tunnel_state_machine/disconnected_state.rs10
3 files changed, 74 insertions, 0 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4695c1bc34..38c2bcc5b9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -33,6 +33,10 @@ Line wrap the file at 100 chars. Th
- Never use OpenVPN as a fallback protocol when any of the following features is enabled:
multihop, quantum-resistant tunnels, or DAITA.
+#### macOS
+- Disable split tunnel interface when disconnected. This prevents traffic from being sent through
+ the daemon when the VPN is disconnected.
+
### Fixed
- macOS and Linux: Fix potential crash when disconnecting with DAITA enabled.
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!(