summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorDavid Lönnhager <david.l@mullvad.net>2023-09-05 13:28:34 +0200
committerDavid Lönnhager <david.l@mullvad.net>2023-09-05 13:28:34 +0200
commite4be108a972b56381a51443b59312fefef1cbfbe (patch)
tree5c81a6de626d787172a37bd1934802c5da37d98a
parent3b7ddae6fb8fccc0aecb2da5deb326cb0ba89fc3 (diff)
parentd494927cb3fe13681eac62fc15d19e7e04cb6e0f (diff)
downloadmullvadvpn-e4be108a972b56381a51443b59312fefef1cbfbe.tar.xz
mullvadvpn-e4be108a972b56381a51443b59312fefef1cbfbe.zip
Merge branch 'macos-fix-route-monitor' into main
-rw-r--r--CHANGELOG.md4
-rw-r--r--talpid-routing/src/unix/macos/interface.rs3
-rw-r--r--talpid-routing/src/unix/macos/mod.rs26
-rw-r--r--talpid-routing/src/unix/macos/routing_socket.rs9
-rw-r--r--talpid-routing/src/unix/macos/watch.rs2
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),