Skip to content

Commit

Permalink
It works, check it out!
Browse files Browse the repository at this point in the history
  • Loading branch information
pinkisemils committed Oct 3, 2023
1 parent 850ee32 commit 3b327b7
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 28 deletions.
3 changes: 2 additions & 1 deletion talpid-routing/src/unix/macos/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)),
}
}

Expand Down
89 changes: 62 additions & 27 deletions talpid-routing/src/unix/macos/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@ pub struct RouteManagerImpl {
v6_default_route: Option<data::RouteMessage>,
default_route_listeners: Vec<mpsc::UnboundedSender<DefaultRouteEvent>>,
check_default_routes_restored: Pin<Box<dyn FusedStream<Item = ()> + Send>>,

// flag to indicate whether route monitor is actively trying to maintain routes
engaged: bool,
}

impl RouteManagerImpl {
Expand All @@ -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,
})
}

Expand All @@ -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
Expand All @@ -127,6 +132,7 @@ impl RouteManagerImpl {
"{}",
error.display_chain_with_msg("Failed to get initial default v6 route")
);
false
});

loop {
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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| {
Expand All @@ -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
Expand All @@ -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<bool> {
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),
Expand All @@ -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) {
Expand Down Expand Up @@ -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(())
}
Expand Down Expand Up @@ -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(&current_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(&current_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);
Expand Down

0 comments on commit 3b327b7

Please sign in to comment.