diff --git a/CHANGELOG.md b/CHANGELOG.md index efd3fa6c3be1..64a2bda55e85 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,8 @@ Line wrap the file at 100 chars. Th #### macOS - Fix default route not being restored when disconnecting when the gateway was a link-local IPv6 address. +- Fix app sometimes getting stuck in error state when the connection is unstable. This occurred + when the default route was removed while connecting. ### Changed - Remove `--location` flag from `mullvad status` CLI. Location and IP will now always diff --git a/talpid-core/src/tunnel_state_machine/connecting_state.rs b/talpid-core/src/tunnel_state_machine/connecting_state.rs index e49e5b69d8e2..75f3d8eebf81 100644 --- a/talpid-core/src/tunnel_state_machine/connecting_state.rs +++ b/talpid-core/src/tunnel_state_machine/connecting_state.rs @@ -599,7 +599,7 @@ fn should_retry(error: &tunnel::Error, retry_attempt: u32) -> bool { TunnelError::BypassError(_), )) => true, - #[cfg(windows)] + #[cfg(any(target_os = "windows", target_os = "macos"))] tunnel::Error::WireguardTunnelMonitoringError(Error::SetupRoutingError(error)) => { is_recoverable_routing_error(error) } @@ -624,6 +624,18 @@ fn is_recoverable_routing_error(error: &talpid_routing::Error) -> bool { matches!(error, talpid_routing::Error::AddRoutesFailed(_)) } +#[cfg(target_os = "macos")] +fn is_recoverable_routing_error(error: &talpid_routing::Error) -> bool { + // If the default route disappears while connecting but before it is caught by the offline + // monitor, then the gateway will be unreachable. In this case, just retry. + matches!( + error, + talpid_routing::Error::PlatformError(talpid_routing::PlatformError::AddRoute( + talpid_routing::RouteError::Unreachable, + )) + ) +} + impl TunnelState for ConnectingState { fn handle_event( mut self: Box, diff --git a/talpid-routing/src/lib.rs b/talpid-routing/src/lib.rs index 7bb337b12732..aa4349041926 100644 --- a/talpid-routing/src/lib.rs +++ b/talpid-routing/src/lib.rs @@ -23,7 +23,7 @@ mod imp; use netlink_packet_route::rtnl::constants::RT_TABLE_MAIN; #[cfg(target_os = "macos")] -pub use imp::{DefaultRouteEvent, PlatformError}; +pub use imp::{imp::RouteError, DefaultRouteEvent, PlatformError}; pub use imp::{Error, RouteManager}; diff --git a/talpid-routing/src/unix/macos/mod.rs b/talpid-routing/src/unix/macos/mod.rs index ec5da51baec3..9c01b70820f5 100644 --- a/talpid-routing/src/unix/macos/mod.rs +++ b/talpid-routing/src/unix/macos/mod.rs @@ -23,6 +23,8 @@ mod interface; mod routing_socket; mod watch; +pub use watch::Error as RouteError; + pub type Result = std::result::Result; const BURST_BUFFER_PERIOD: Duration = Duration::from_millis(200); @@ -36,7 +38,7 @@ pub enum Error { #[error(display = "Error occurred when interfacing with the routing table")] RoutingTable(#[error(source)] watch::Error), - /// Failed to remvoe route + /// Failed to remove route #[error(display = "Error occurred when deleting a route")] DeleteRoute(#[error(source)] watch::Error), diff --git a/talpid-routing/src/unix/macos/watch.rs b/talpid-routing/src/unix/macos/watch.rs index 9e5f6442cafc..d22a262e2c71 100644 --- a/talpid-routing/src/unix/macos/watch.rs +++ b/talpid-routing/src/unix/macos/watch.rs @@ -6,20 +6,28 @@ use std::io; type Result = std::result::Result; +/// Errors that can occur for a PF_ROUTE socket #[derive(Debug, err_derive::Error)] pub enum Error { + /// Generic routing socket error #[error(display = "Routing socket error: {}", _0)] RoutingSocket(routing_socket::Error), + /// Failed to parse route message #[error(display = "Invalid message")] InvalidMessage(data::Error), + /// Failed to send route message #[error(display = "Failed to send routing message")] Send(routing_socket::Error), + /// Received unexpected response to route message #[error(display = "Unexpected message type")] UnexpectedMessageType(RouteSocketMessage, MessageType), + /// Route not found #[error(display = "Route not found")] RouteNotFound, + /// No route to destination #[error(display = "Destination unreachable")] Unreachable, + /// Failed to delete route #[error(display = "Failed to delete a route")] Deletion(RouteMessage), }