diff options
| author | David Lönnhager <david.l@mullvad.net> | 2023-09-05 13:28:34 +0200 |
|---|---|---|
| committer | David Lönnhager <david.l@mullvad.net> | 2023-09-05 13:28:34 +0200 |
| commit | e4be108a972b56381a51443b59312fefef1cbfbe (patch) | |
| tree | 5c81a6de626d787172a37bd1934802c5da37d98a | |
| parent | 3b7ddae6fb8fccc0aecb2da5deb326cb0ba89fc3 (diff) | |
| parent | d494927cb3fe13681eac62fc15d19e7e04cb6e0f (diff) | |
| download | mullvadvpn-e4be108a972b56381a51443b59312fefef1cbfbe.tar.xz mullvadvpn-e4be108a972b56381a51443b59312fefef1cbfbe.zip | |
Merge branch 'macos-fix-route-monitor' into main
| -rw-r--r-- | CHANGELOG.md | 4 | ||||
| -rw-r--r-- | talpid-routing/src/unix/macos/interface.rs | 3 | ||||
| -rw-r--r-- | talpid-routing/src/unix/macos/mod.rs | 26 | ||||
| -rw-r--r-- | talpid-routing/src/unix/macos/routing_socket.rs | 9 | ||||
| -rw-r--r-- | talpid-routing/src/unix/macos/watch.rs | 2 |
5 files changed, 35 insertions, 9 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index d52998e13d..b0ca160245 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,10 @@ Line wrap the file at 100 chars. Th #### Windows - Correctly detect whether OS is Windows Server (primarily for logging in daemon.log). +#### macOS +- Ensure that the default tunnel route is added back after waking from hibernation. Previously, the + tunnel became unusable despite the app appearing to be connected. + ## [android/2023.6-beta1] - 2023-08-29 diff --git a/talpid-routing/src/unix/macos/interface.rs b/talpid-routing/src/unix/macos/interface.rs index 8ec4863ab7..5f08fa929f 100644 --- a/talpid-routing/src/unix/macos/interface.rs +++ b/talpid-routing/src/unix/macos/interface.rs @@ -43,8 +43,7 @@ pub async fn get_best_default_route( // Get interface ID let index = match if_nametoindex(iface_bytes.as_c_str()) { Ok(index) => index, - Err(error) => { - log::error!("Failed to get index of network interface: {error}"); + Err(_error) => { continue; } }; diff --git a/talpid-routing/src/unix/macos/mod.rs b/talpid-routing/src/unix/macos/mod.rs index 3e5d8b0aed..0780cd9c30 100644 --- a/talpid-routing/src/unix/macos/mod.rs +++ b/talpid-routing/src/unix/macos/mod.rs @@ -254,14 +254,14 @@ impl RouteManagerImpl { } } - if let Err(error) = self.handle_route_change(route).await { + if let Err(error) = self.handle_route_change(route, true).await { log::error!("Failed to process route change: {error}"); } } Ok(RouteSocketMessage::AddRoute(route)) | Ok(RouteSocketMessage::ChangeRoute(route)) => { // Refresh routes that are using the default interface - if let Err(error) = self.handle_route_change(route).await { + if let Err(error) = self.handle_route_change(route, false).await { log::error!("Failed to process route change: {error}"); } } @@ -273,8 +273,24 @@ impl RouteManagerImpl { } } - /// Update routes that use the non-tunnel default interface - async fn handle_route_change(&mut self, route: data::RouteMessage) -> Result<()> { + /// Handle changes to the routing table. Specifically, when a default route is added, modified, + /// or deleted: + /// + /// * Replace the default route with a default route for the tunnel interface (i.e., one whose + /// gateway is set to the link address of the tunnel interface). + /// * At the same time, update the route used by non-tunnel interfaces to reach the relay/VPN + /// server. The gateway of the relay route is set to the first interface in the network + /// service order that has a working ifscoped default route. + /// + /// # Arguments + /// + /// * `route_is_being_deleted` - A boolean that should be set to `true` if `route` is being + /// deleted. This should be `false` if the route is being modified or added. + async fn handle_route_change( + &mut self, + route: data::RouteMessage, + route_is_being_deleted: bool, + ) -> Result<()> { // Ignore routes that aren't default routes if !route.is_default().map_err(Error::InvalidData)? { return Ok(()); @@ -288,7 +304,7 @@ impl RouteManagerImpl { let tun_gateway_link_addr = tunnel_route.gateway().and_then(|addr| addr.as_link_addr()); - if new_gateway_link_addr == tun_gateway_link_addr { + if new_gateway_link_addr == tun_gateway_link_addr && !route_is_being_deleted { return Ok(()); } } diff --git a/talpid-routing/src/unix/macos/routing_socket.rs b/talpid-routing/src/unix/macos/routing_socket.rs index 213128fd8c..ddd69bab2e 100644 --- a/talpid-routing/src/unix/macos/routing_socket.rs +++ b/talpid-routing/src/unix/macos/routing_socket.rs @@ -4,6 +4,7 @@ use std::{ os::unix::prelude::{FromRawFd, RawFd}, pin::Pin, task::{ready, Context, Poll}, + time::Duration, }; use nix::{ @@ -29,10 +30,14 @@ pub enum Error { Read(io::Error), #[error(display = "Received a message that's too small")] MessageTooSmall(usize), + #[error(display = "Failed to receive response to route message")] + ResponseTimeout, } type Result<T> = std::result::Result<T, Error>; +const RESPONSE_TIMEOUT: Duration = Duration::from_secs(10); + /// Wraps a `PF_ROUTE` socket, keeps track of sent message IDs, and facilitates sending and /// receiving [route socket messages](#RouteMessage) pub struct RoutingSocket { @@ -73,7 +78,9 @@ impl RoutingSocket { ) -> Result<Vec<u8>> { let (msg, seq) = self.next_route_msg(message, message_type); match self.socket.write(&msg).await { - Ok(_) => self.wait_for_response(seq).await, + Ok(_) => tokio::time::timeout(RESPONSE_TIMEOUT, self.wait_for_response(seq)) + .await + .map_err(|_| Error::ResponseTimeout)?, Err(err) => Err(Error::Write(err)), } } diff --git a/talpid-routing/src/unix/macos/watch.rs b/talpid-routing/src/unix/macos/watch.rs index d7fdd60f42..9e5f6442ca 100644 --- a/talpid-routing/src/unix/macos/watch.rs +++ b/talpid-routing/src/unix/macos/watch.rs @@ -8,7 +8,7 @@ type Result<T> = std::result::Result<T, Error>; #[derive(Debug, err_derive::Error)] pub enum Error { - #[error(display = "Failed to open routing socket")] + #[error(display = "Routing socket error: {}", _0)] RoutingSocket(routing_socket::Error), #[error(display = "Invalid message")] InvalidMessage(data::Error), |
