summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorDavid Lönnhager <david.l@mullvad.net>2025-09-04 10:42:50 +0200
committerDavid Lönnhager <david.l@mullvad.net>2025-09-08 10:15:26 +0200
commit45b2d7d6d8765c8af07af330cf03851378132f5f (patch)
tree4cf79676d7bf95e5abd46b3716d86aca4eabe929
parent88b1c0c542e9fbf46364d36ef25f8be95c12c213 (diff)
downloadmullvadvpn-45b2d7d6d8765c8af07af330cf03851378132f5f.tar.xz
mullvadvpn-45b2d7d6d8765c8af07af330cf03851378132f5f.zip
Use PF_ROUTE socket to track missing loopback alias instead of polling
-rw-r--r--talpid-core/src/resolver.rs86
1 files changed, 34 insertions, 52 deletions
diff --git a/talpid-core/src/resolver.rs b/talpid-core/src/resolver.rs
index 5107759297..8dcea70679 100644
--- a/talpid-core/src/resolver.rs
+++ b/talpid-core/src/resolver.rs
@@ -456,35 +456,8 @@ impl LocalResolver {
log::debug!("Created loopback address {addr}");
- let detect_removed_alias_task = tokio::spawn(async move {
- // Periodically check that the alias still exists, and recreate it if it doesn't
- // This fixes the issue that macOS sometimes removes the alias
- // TODO: This could be done by listening to events on a PF_ROUTE socket
- loop {
- tokio::time::sleep(Duration::from_secs(10)).await;
-
- let found_loopback_addr = match is_valid_address(LOOPBACK, addr.into()) {
- Ok(found_loopback_addr) => found_loopback_addr,
- Err(err) => {
- log::warn!("Failed to check if loopback address {addr} exists: {err}");
- continue;
- }
- };
-
- if !found_loopback_addr {
- log::debug!("Missing loopback address alias {addr}. Recreating");
-
- talpid_macos::net::add_alias(LOOPBACK, IpAddr::from(addr))
- .await
- .inspect_err(|e| {
- log::warn!("Failed to add loopback {LOOPBACK} alias {addr}: {e}");
- })
- .ok();
- } else {
- log::trace!("Loopback address {addr} exists");
- }
- }
- });
+ let detect_removed_alias_task =
+ tokio::spawn(detect_loopback_address_removal(IpAddr::from(addr)));
// Clean up ip address when stopping the resolver
let cleanup_ifconfig = on_drop(move || {
@@ -648,37 +621,46 @@ fn kill_mdnsresponder() -> io::Result<()> {
Ok(())
}
-/// Return whether the IP address is assigned for the given `interface`
-fn is_valid_address(interface: &'static str, addr_to_find: IpAddr) -> nix::Result<bool> {
- let mut found_addr = false;
-
- let interface_addrs = nix::ifaddrs::getifaddrs()?;
+/// Detect when the loopback address is removed on the loopback interface, and add it back whenever
+/// that occurs.
+async fn detect_loopback_address_removal(addr: IpAddr) -> Result<(), talpid_routing::RouteError> {
+ let mut routing_table = talpid_routing::RoutingTable::new().map_err(|e| {
+ log::warn!("Failed to create routing table interface: {e}");
+ e
+ })?;
- for interface_addr in interface_addrs {
- let Some(address) = interface_addr.address else {
+ // Listen for the loopback address being removed, and add it back if that happens
+ loop {
+ let Ok(msg) = routing_table.next_message().await else {
+ log::trace!("Failed to read next message from routing table");
continue;
};
- if interface_addr.interface_name != interface {
- continue;
- }
- let ip: Option<IpAddr> = address
- .as_sockaddr_in()
- .map(|addr| IpAddr::from(addr.ip()))
- .or_else(|| {
- address
- .as_sockaddr_in6()
- .map(|addr| IpAddr::from(addr.ip()))
- });
- let Some(ip) = ip else {
+
+ let RouteSocketMessage::DeleteAddress(msg) = msg else {
continue;
};
- if ip == addr_to_find {
- found_addr = true;
- break;
+ // The deleted address either matches the one we care about, or we do not know
+ let matches_addr = msg
+ .address()
+ .map(|deleted_addr| deleted_addr == addr)
+ .unwrap_or(true);
+ if !matches_addr {
+ continue;
}
+
+ // Sleep for a bit so we do not spin if something weird is going on
+ tokio::time::sleep(Duration::from_secs(1)).await;
+
+ log::debug!("Detected possible removal of loopback address {addr}. Adding it back");
+
+ talpid_macos::net::add_alias(LOOPBACK, addr)
+ .await
+ .inspect_err(|e| {
+ log::warn!("Failed to add loopback {LOOPBACK} alias {addr}: {e}");
+ })
+ .ok();
}
- Ok(found_addr)
}
type LookupResponse<'a> = MessageResponse<