diff options
| author | David Lönnhager <david.l@mullvad.net> | 2025-09-04 10:42:50 +0200 |
|---|---|---|
| committer | David Lönnhager <david.l@mullvad.net> | 2025-09-08 10:15:26 +0200 |
| commit | 45b2d7d6d8765c8af07af330cf03851378132f5f (patch) | |
| tree | 4cf79676d7bf95e5abd46b3716d86aca4eabe929 | |
| parent | 88b1c0c542e9fbf46364d36ef25f8be95c12c213 (diff) | |
| download | mullvadvpn-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.rs | 86 |
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< |
