Skip to content

Commit

Permalink
Fix IPv6 parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
pinkisemils committed Oct 4, 2023
1 parent 468f33a commit dcc39d3
Show file tree
Hide file tree
Showing 3 changed files with 10 additions and 59 deletions.
2 changes: 1 addition & 1 deletion talpid-routing/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ err-derive = { workspace = true }
futures = "0.3.15"
ipnetwork = "0.16"
log = { workspace = true }
tokio = { workspace = true, features = ["process", "rt-multi-thread", "net", "io-util"] }
tokio = { workspace = true, features = ["process", "rt-multi-thread", "net", "io-util", "time"] }

[target.'cfg(not(target_os="android"))'.dependencies]
talpid-types = { path = "../talpid-types" }
Expand Down
61 changes: 6 additions & 55 deletions talpid-routing/src/unix/macos/interface.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
use ipnetwork::IpNetwork;
use libc::{if_indextoname, IFNAMSIZ};
use nix::net::if_::{if_nametoindex, InterfaceFlags};
use nix::net::if_::InterfaceFlags;
use std::{
ffi::{CStr, CString},
io,
net::{IpAddr, Ipv4Addr, Ipv6Addr},
};
Expand All @@ -13,10 +11,7 @@ use system_configuration::{
preferences::SCPreferences,
};

use super::{
data::{Destination, RouteMessage},
watch::RoutingTable,
};
use super::data::{Destination, RouteMessage};

#[derive(Debug, PartialEq, Clone, Copy)]
pub enum Family {
Expand All @@ -42,58 +37,14 @@ impl From<Family> for IpNetwork {
}
}

/// Retrieve the current unscoped default route. That is the only default route that does not have
/// the IF_SCOPE flag set, if such a route exists.
///
/// # Note
///
/// For some reason, the socket sometimes returns a route with the IF_SCOPE flag set, if there also
/// exists a scoped route for the same interface. This does not occur if there is no unscoped route,
/// so we can still rely on it.
pub async fn get_unscoped_default_route(
routing_table: &mut RoutingTable,
family: Family,
) -> Option<RouteMessage> {
let mut msg = RouteMessage::new_route(Destination::Network(IpNetwork::from(family)));
msg = msg.set_gateway_route(true);

let route = routing_table
.get_route(&msg)
.await
.unwrap_or_else(|error| {
log::error!("Failed to retrieve unscoped default route: {error}");
None
})?;

let idx = u32::from(route.interface_index());
if idx != 0 {
let mut ifname = [0u8; IFNAMSIZ];

// SAFETY: The buffer is large to contain any interface name.
if !unsafe { if_indextoname(idx, ifname.as_mut_ptr() as _) }.is_null() {
let ifname = CStr::from_bytes_until_nul(&ifname).unwrap();
let name = ifname.to_str().expect("expected ascii");

// Ignore the unscoped route if its interface is not "active"
if !is_active_interface(name, family).unwrap_or(true) {
return None;
}
}
}

Some(route)
}
/// Retrieve the best current default route. That is the first scoped default route, ordered by
/// network service order, and with interfaces filtered out if they do not have valid IP addresses
/// assigned.
///
/// # Note
///
/// The tunnel interface is not even listed in the service order, so it will be skipped.
pub async fn get_best_default_route(
routing_table: &mut RoutingTable,
family: Family,
) -> Option<RouteMessage> {
pub async fn get_best_default_route(family: Family) -> Option<RouteMessage> {
let mut msg = RouteMessage::new_route(Destination::Network(IpNetwork::from(family)));
msg = msg.set_gateway_route(true);

Expand Down Expand Up @@ -143,15 +94,15 @@ fn parse_v4_ipconfig_output(output: &str) -> Option<IpAddr> {
fn parse_v6_ipconfig_output(output: &str) -> Option<IpAddr> {
let mut iter = output.split_whitespace();
let pattern = ["RouterAdvertisement", ":", "from"];
loop {
'outer: loop {
let mut next_chunk = iter.next()?;
for expected_chunk in pattern {
if expected_chunk != next_chunk {
continue;
continue 'outer;
}
next_chunk = iter.next()?;
}
return iter.next()?.trim_end_matches(",").parse().ok();
return next_chunk.trim_end_matches(",").parse().ok();
}
}

Expand Down
6 changes: 3 additions & 3 deletions talpid-routing/src/unix/macos/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,7 @@ 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<bool> {
let best_route = interface::get_best_default_route(&mut self.routing_table, family).await;
let best_route = interface::get_best_default_route(family).await;
log::trace!("Best route ({family:?}): {best_route:?}");

let default_route = get_current_best_default_route!(self, family);
Expand Down Expand Up @@ -623,7 +623,7 @@ impl RouteManagerImpl {
/// function returns true when no route had to be added.
async fn restore_default_route(&mut self, family: interface::Family) -> bool {
let Some(best_default_route) =
interface::get_best_default_route(&mut self.routing_table, family).await
interface::get_best_default_route(family).await
else {
let _ = self
.routing_table
Expand Down Expand Up @@ -652,7 +652,7 @@ impl RouteManagerImpl {
.await;
};

let new_route = interface::get_best_default_route(&mut self.routing_table, family).await;
let new_route = interface::get_best_default_route(family).await;
let old_route = std::mem::replace(current_route, new_route);
let notify = &old_route != current_route;

Expand Down

0 comments on commit dcc39d3

Please sign in to comment.