diff options
| author | David Lönnhager <david.l@mullvad.net> | 2024-08-19 10:25:25 +0200 |
|---|---|---|
| committer | David Lönnhager <david.l@mullvad.net> | 2024-08-20 12:02:24 +0200 |
| commit | cfd1accfed1c946ecff7c800c743771af3c9f477 (patch) | |
| tree | a5294a92a8ef4bac6608fdabe16a5c391a9ed716 | |
| parent | fc4facca1610e135bc40dae5453b9ae5ed6d4ae8 (diff) | |
| download | mullvadvpn-cfd1accfed1c946ecff7c800c743771af3c9f477.tar.xz mullvadvpn-cfd1accfed1c946ecff7c800c743771af3c9f477.zip | |
Add interface/mtu change listener
| -rw-r--r-- | talpid-routing/src/unix/macos/data.rs | 4 | ||||
| -rw-r--r-- | talpid-routing/src/unix/macos/mod.rs | 23 | ||||
| -rw-r--r-- | talpid-routing/src/unix/mod.rs | 20 |
3 files changed, 47 insertions, 0 deletions
diff --git a/talpid-routing/src/unix/macos/data.rs b/talpid-routing/src/unix/macos/data.rs index a5e8a49efd..5ac83d0885 100644 --- a/talpid-routing/src/unix/macos/data.rs +++ b/talpid-routing/src/unix/macos/data.rs @@ -634,6 +634,10 @@ impl Interface { self.header.ifm_index } + pub fn mtu(&self) -> u32 { + self.header.ifm_data.ifi_mtu + } + fn from_byte_buffer(buffer: &[u8]) -> Result<Self> { const INTERFACE_MESSAGE_HEADER_SIZE: usize = std::mem::size_of::<libc::if_msghdr>(); if INTERFACE_MESSAGE_HEADER_SIZE > buffer.len() { diff --git a/talpid-routing/src/unix/macos/mod.rs b/talpid-routing/src/unix/macos/mod.rs index 141b8c06d3..85a020ba79 100644 --- a/talpid-routing/src/unix/macos/mod.rs +++ b/talpid-routing/src/unix/macos/mod.rs @@ -90,6 +90,7 @@ pub struct RouteManagerImpl { v6_default_route: Option<interface::DefaultRoute>, update_trigger: BurstGuard, default_route_listeners: Vec<mpsc::UnboundedSender<DefaultRouteEvent>>, + interface_change_listeners: Vec<mpsc::UnboundedSender<super::InterfaceEvent>>, check_default_routes_restored: Pin<Box<dyn FusedStream<Item = ()> + Send>>, unhandled_default_route_changes: bool, primary_interface_monitor: interface::PrimaryInterfaceMonitor, @@ -127,6 +128,7 @@ impl RouteManagerImpl { v6_default_route: None, update_trigger, default_route_listeners: vec![], + interface_change_listeners: vec![], check_default_routes_restored: Box::pin(futures::stream::pending()), unhandled_default_route_changes: false, primary_interface_monitor, @@ -227,6 +229,13 @@ impl RouteManagerImpl { log::error!("Failed to clean up rotues: {err}"); } }, + + Some(RouteManagerCommand::NewInterfaceChangeListener(tx)) => { + let (events_tx, events_rx) = mpsc::unbounded(); + self.interface_change_listeners.push(events_tx); + let _ = tx.send(events_rx); + } + Some(RouteManagerCommand::RefreshRoutes) => { if let Err(error) = self.refresh_routes().await { log::error!("Failed to refresh routes: {error}"); @@ -377,6 +386,20 @@ impl RouteManagerImpl { Ok(RouteSocketMessage::AddAddress(_) | RouteSocketMessage::DeleteAddress(_)) => { self.update_trigger.trigger(); } + Ok(RouteSocketMessage::Interface(iface)) => { + let Ok(mtu) = u16::try_from(iface.mtu()) else { + log::warn!("Invalid mtu for interface: {}", iface.index()); + return; + }; + + self.interface_change_listeners.retain(|tx| { + tx.unbounded_send(super::InterfaceEvent { + interface_index: iface.index(), + mtu, + }) + .is_ok() + }); + } // ignore all other message types Ok(_) => {} Err(err) => { diff --git a/talpid-routing/src/unix/mod.rs b/talpid-routing/src/unix/mod.rs index 044a09433a..d257140f7e 100644 --- a/talpid-routing/src/unix/mod.rs +++ b/talpid-routing/src/unix/mod.rs @@ -118,10 +118,18 @@ pub(crate) enum RouteManagerCommand { RefreshRoutes, NewDefaultRouteListener(oneshot::Sender<mpsc::UnboundedReceiver<DefaultRouteEvent>>), GetDefaultRoutes(oneshot::Sender<(Option<DefaultRoute>, Option<DefaultRoute>)>), + NewInterfaceChangeListener(oneshot::Sender<mpsc::UnboundedReceiver<InterfaceEvent>>), /// Return gateway for V4 and V6 GetDefaultGateway(oneshot::Sender<(Option<Gateway>, Option<Gateway>)>), } +/// Event that is sent when interface details may have changed for some interface. +#[cfg(target_os = "macos")] +pub struct InterfaceEvent { + pub interface_index: u16, + pub mtu: u16, +} + /// Event that is sent when a preferred non-tunnel default route is /// added or removed. #[cfg(target_os = "macos")] @@ -227,6 +235,18 @@ impl RouteManagerHandle { response_rx.await.map_err(|_| Error::ManagerChannelDown) } + /// Listen for interface changes. + #[cfg(target_os = "macos")] + pub async fn interface_change_listener( + &self, + ) -> Result<impl Stream<Item = InterfaceEvent>, Error> { + let (response_tx, response_rx) = oneshot::channel(); + self.tx + .unbounded_send(RouteManagerCommand::NewInterfaceChangeListener(response_tx)) + .map_err(|_| Error::RouteManagerDown)?; + response_rx.await.map_err(|_| Error::ManagerChannelDown) + } + /// Get default gateway #[cfg(target_os = "macos")] pub async fn get_default_gateway(&self) -> Result<(Option<Gateway>, Option<Gateway>), Error> { |
