From 3b327b7b6493936ef0d31f29c1056cf454639858 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Em=C4=ABls?= Date: Tue, 3 Oct 2023 18:53:44 +0200 Subject: [PATCH] It works, check it out! --- talpid-routing/src/unix/macos/interface.rs | 3 +- talpid-routing/src/unix/macos/mod.rs | 89 +++++++++++++++------- 2 files changed, 64 insertions(+), 28 deletions(-) diff --git a/talpid-routing/src/unix/macos/interface.rs b/talpid-routing/src/unix/macos/interface.rs index abb674baf3ea..ff1f4dc66c2f 100644 --- a/talpid-routing/src/unix/macos/interface.rs +++ b/talpid-routing/src/unix/macos/interface.rs @@ -126,7 +126,8 @@ async fn get_router_address(family: Family, interface_name: &str) -> io::Result< match family { Family::V4 => Ok(parse_v4_ipconfig_output(output_str)), - Family::V6 => Ok(parse_v6_ipconfig_output(output_str)), + Family::V6 => Ok(None), + // Family::V6 => Ok(parse_v6_ipconfig_output(output_str)), } } diff --git a/talpid-routing/src/unix/macos/mod.rs b/talpid-routing/src/unix/macos/mod.rs index 5754711940c1..8e715d12f3dc 100644 --- a/talpid-routing/src/unix/macos/mod.rs +++ b/talpid-routing/src/unix/macos/mod.rs @@ -87,6 +87,9 @@ pub struct RouteManagerImpl { v6_default_route: Option, default_route_listeners: Vec>, check_default_routes_restored: Pin + Send>>, + + // flag to indicate whether route monitor is actively trying to maintain routes + engaged: bool, } impl RouteManagerImpl { @@ -104,6 +107,7 @@ impl RouteManagerImpl { v6_default_route: None, default_route_listeners: vec![], check_default_routes_restored: Box::pin(futures::stream::pending()), + engaged: false, }) } @@ -119,6 +123,7 @@ impl RouteManagerImpl { "{}", error.display_chain_with_msg("Failed to get initial default v4 route") ); + false }); self.update_best_default_route(interface::Family::V6) .await @@ -127,6 +132,7 @@ impl RouteManagerImpl { "{}", error.display_chain_with_msg("Failed to get initial default v6 route") ); + false }); loop { @@ -278,6 +284,7 @@ impl RouteManagerImpl { self.apply_tunnel_default_route().await?; + self.engaged = true; // Add routes that use the default interface if let Err(error) = self.apply_non_tunnel_routes().await { self.non_tunnel_routes.clear(); @@ -329,10 +336,12 @@ impl RouteManagerImpl { /// 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. async fn handle_route_socket_message(&mut self) -> Result<()> { - self.update_best_default_route(interface::Family::V4) - .await?; - self.update_best_default_route(interface::Family::V6) - .await?; + let default_route_updated = self + .update_best_default_route(interface::Family::V4) + .await? + || self + .update_best_default_route(interface::Family::V6) + .await?; // Remove any existing ifscope route that we've added self.remove_applied_routes(|route| { @@ -341,7 +350,9 @@ impl RouteManagerImpl { .await; // Substitute route with a tunnel route - self.apply_tunnel_default_route().await?; + if default_route_updated { + self.apply_tunnel_default_route().await?; + } // Update routes using default interface self.apply_non_tunnel_routes().await @@ -357,27 +368,29 @@ impl RouteManagerImpl { /// /// If there is no tunnel device, the "best route" is the unscoped default route, whatever it /// is. - async fn update_best_default_route(&mut self, family: interface::Family) -> Result<()> { - let use_scoped_route = (family == interface::Family::V4 - && self.v4_tunnel_default_route.is_some()) - || (family == interface::Family::V6 && self.v6_tunnel_default_route.is_some()); - - let best_route = if use_scoped_route { - interface::get_best_default_route(&mut self.routing_table, family).await - } else { - interface::get_unscoped_default_route(&mut self.routing_table, family).await - }; + async fn update_best_default_route(&mut self, family: interface::Family) -> Result { + let best_route = interface::get_best_default_route(&mut self.routing_table, family).await; log::trace!("Best route ({family:?}): {best_route:?}"); let default_route = get_current_best_default_route!(self, family); - if default_route == &best_route { - log::trace!("Default route ({family:?}) is unchanged"); - return Ok(()); - } + match (&default_route, &best_route) { + (Some(default_route), Some(best_route)) => { + log::trace!("Default route ({family:?}) is unchanged"); + if default_route.gateway_ip() == best_route.gateway_ip() { + return Ok(false); + } + } + (None, None) => { + log::trace!("Default route for {family} still doesn't exist"); + return Ok(false); + } + _ => (), + }; let old_route = std::mem::replace(default_route, best_route); + // TODO: this interface index is meaningless now log::debug!( "Default route change ({family:?}): interface {} -> {}", old_route.map(|r| r.interface_index()).unwrap_or(0), @@ -389,8 +402,7 @@ impl RouteManagerImpl { let changed = default_route.is_some(); self.notify_default_route_listeners(family, changed); - - Ok(()) + Ok(changed) } fn notify_default_route_listeners(&mut self, family: interface::Family, changed: bool) { @@ -551,6 +563,7 @@ impl RouteManagerImpl { self.check_default_routes_restored = Self::create_default_route_check_timer(); self.non_tunnel_routes.clear(); + self.engaged = false; Ok(()) } @@ -603,19 +616,41 @@ impl RouteManagerImpl { /// true when no routes had to be added. async fn try_restore_default_routes(&mut self) -> bool { self.restore_default_route(interface::Family::V4).await - && self.restore_default_route(interface::Family::V6).await + // && self.restore_default_route(interface::Family::V6).await } /// Add back unscoped default route for the given `family`, if it is still missing. This /// function returns true when no route had to be added. async fn restore_default_route(&mut self, family: interface::Family) -> bool { - let current_route = get_current_best_default_route!(self, family); - let message = RouteMessage::new_route(IpNetwork::from(family).into()); - if matches!(self.routing_table.get_route(&message).await, Ok(Some(_))) { - self.remove_applied_routes(|r| r.is_ifscope() && r.is_default().unwrap_or(false)) + let Some(best_default_route) = + interface::get_best_default_route(&mut self.routing_table, family).await + else { + let _ = self + .routing_table + .delete_route(&RouteMessage::new_route(IpNetwork::from(family).into())) .await; return true; - } + }; + + let current_route = get_current_best_default_route!(self, family); + + let current_default_route = RouteMessage::new_route(IpNetwork::from(family).into()); + if let Ok(Some(current_default)) = + self.routing_table.get_route(¤t_default_route).await + { + if best_default_route.gateway_ip() == current_default.gateway_ip() { + self.remove_applied_routes(|r| r.is_ifscope() && r.is_default().unwrap_or(false)) + .await; + return true; + } + + // I think we should just ignore errors. + // - King David, 2023 + let _ = self + .routing_table + .delete_route(¤t_default_route) + .await; + }; let new_route = interface::get_best_default_route(&mut self.routing_table, family).await; let old_route = std::mem::replace(current_route, new_route);