diff options
| author | David Lönnhager <david.l@mullvad.net> | 2021-09-06 14:19:02 +0200 |
|---|---|---|
| committer | David Lönnhager <david.l@mullvad.net> | 2021-09-06 14:19:02 +0200 |
| commit | 4ba1552c25a84dcf4a7abb4ee109804b2722e3ec (patch) | |
| tree | 8c2783de6450fdb6947d6a4702860e9f69bb3454 | |
| parent | c1bfddcb3f84cf3562ab8dc2641e9ea186682070 (diff) | |
| parent | a20077e86e87e9e4346c1a03e5e0861f4d3a14ba (diff) | |
| download | mullvadvpn-4ba1552c25a84dcf4a7abb4ee109804b2722e3ec.tar.xz mullvadvpn-4ba1552c25a84dcf4a7abb4ee109804b2722e3ec.zip | |
Merge branch 'fix-ping-monitor-multiple-peers'
| -rw-r--r-- | CHANGELOG.md | 1 | ||||
| -rw-r--r-- | talpid-core/src/tunnel/wireguard/connectivity_check.rs | 144 | ||||
| -rw-r--r-- | talpid-core/src/tunnel/wireguard/mod.rs | 9 | ||||
| -rw-r--r-- | talpid-core/src/tunnel/wireguard/stats.rs | 91 | ||||
| -rw-r--r-- | talpid-core/src/tunnel/wireguard/wireguard_go.rs | 7 | ||||
| -rw-r--r-- | talpid-core/src/tunnel/wireguard/wireguard_kernel/netlink_tunnel.rs | 7 | ||||
| -rw-r--r-- | talpid-core/src/tunnel/wireguard/wireguard_kernel/nm_tunnel.rs | 78 |
7 files changed, 200 insertions, 137 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 68bee316f2..12e0df97ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -61,6 +61,7 @@ Line wrap the file at 100 chars. Th desktop app. - Fix in-app notification button not working for some notifications. - Fix incorrectly positioned navigation bar title when navigating back to a scrolled down view. +- Fix connectivity check for WireGuard multihop when the exit hop is down. #### Linux - Make offline monitor aware of routing table changes. diff --git a/talpid-core/src/tunnel/wireguard/connectivity_check.rs b/talpid-core/src/tunnel/wireguard/connectivity_check.rs index 0e3dc1186e..be97608821 100644 --- a/talpid-core/src/tunnel/wireguard/connectivity_check.rs +++ b/talpid-core/src/tunnel/wireguard/connectivity_check.rs @@ -1,6 +1,6 @@ use crate::{ ping_monitor::{new_pinger, Pinger}, - tunnel::wireguard::stats::Stats, + tunnel::wireguard::stats::StatsMap, }; use std::{ net::Ipv4Addr, @@ -110,12 +110,6 @@ impl ConnectivityMonitor { let start = Instant::now(); while start.elapsed() < PING_TIMEOUT { if self.check_connectivity(Instant::now())? { - #[cfg(target_os = "linux")] - self.tunnel_handle.upgrade().and_then::<(), _>(|tunnel| { - let tunnel = tunnel.lock().ok()?; - tunnel.as_ref()?.slow_stats_refresh_rate(); - None - }); return Ok(true); } if self.should_shut_down(DELAY_ON_INITIAL_SETUP) { @@ -182,7 +176,7 @@ impl ConnectivityMonitor { /// If None is returned, then the underlying tunnel has already been closed and all subsequent /// calls will also return None. - fn get_stats(&self) -> Option<Result<Stats, Error>> { + fn get_stats(&self) -> Option<Result<StatsMap, Error>> { self.tunnel_handle .upgrade()? .lock() @@ -229,18 +223,18 @@ impl ConnectivityMonitor { enum ConnState { Connecting { start: Instant, - stats: Stats, + stats: StatsMap, tx_timestamp: Option<Instant>, }, Connected { rx_timestamp: Instant, tx_timestamp: Instant, - stats: Stats, + stats: StatsMap, }, } impl ConnState { - pub fn new(start: Instant, stats: Stats) -> Self { + pub fn new(start: Instant, stats: StatsMap) -> Self { ConnState::Connecting { start, stats, @@ -249,14 +243,14 @@ impl ConnState { } /// Returns true if incoming traffic counters incremented - pub fn update(&mut self, now: Instant, new_stats: Stats) -> bool { + pub fn update(&mut self, now: Instant, new_stats: StatsMap) -> bool { match self { ConnState::Connecting { start, stats, tx_timestamp, } => { - if new_stats.rx_bytes > 0 { + if !new_stats.is_empty() && new_stats.values().all(|stats| stats.rx_bytes > 0) { let tx_timestamp = tx_timestamp.unwrap_or(*start); let connected_state = ConnState::Connected { rx_timestamp: now, @@ -266,7 +260,9 @@ impl ConnState { *self = connected_state; return true; } - if stats.tx_bytes < new_stats.tx_bytes { + if stats.values().map(|stats| stats.tx_bytes).sum::<u64>() + < new_stats.values().map(|stats| stats.tx_bytes).sum() + { let start = *start; let stats = new_stats; *self = ConnState::Connecting { @@ -283,9 +279,16 @@ impl ConnState { tx_timestamp, stats, } => { - let rx_incremented = stats.rx_bytes < new_stats.rx_bytes; + let rx_incremented = stats.iter().all(|(key, peer_stats)| { + new_stats + .get(key) + .map(|new_stats| new_stats.rx_bytes > peer_stats.rx_bytes) + .unwrap_or(false) + }); let rx_timestamp = if rx_incremented { now } else { *rx_timestamp }; - let tx_timestamp = if stats.tx_bytes < new_stats.tx_bytes { + let tx_timestamp = if stats.values().map(|stats| stats.tx_bytes).sum::<u64>() + < new_stats.values().map(|stats| stats.tx_bytes).sum() + { now } else { *tx_timestamp @@ -354,7 +357,10 @@ impl ConnState { #[cfg(test)] mod test { use super::*; - use crate::tunnel::wireguard::{stats, TunnelError}; + use crate::tunnel::wireguard::{ + stats::{self, Stats}, + TunnelError, + }; use std::{ sync::{ atomic::{AtomicBool, Ordering}, @@ -392,13 +398,15 @@ mod test { fn test_conn_state_connects() { let start = Instant::now().checked_sub(Duration::from_secs(2)).unwrap(); let mut conn_state = ConnState::new(start, Default::default()); - conn_state.update( - Instant::now(), + let mut stats = StatsMap::new(); + stats.insert( + [0u8; 32], Stats { rx_bytes: 1, tx_bytes: 0, }, ); + conn_state.update(Instant::now(), stats); assert!(conn_state.connected()); assert!(!conn_state.rx_timed_out()); @@ -415,13 +423,15 @@ mod test { let mut conn_state = ConnState::new(start, Default::default()); let connect_time = Instant::now().checked_sub(TRAFFIC_TIMEOUT).unwrap(); - conn_state.update( - connect_time, + let mut stats = StatsMap::new(); + stats.insert( + [0u8; 32], Stats { rx_bytes: 1, tx_bytes: 0, }, ); + conn_state.update(connect_time, stats); assert!(conn_state.connected()); assert!(!conn_state.rx_timed_out()); @@ -437,22 +447,26 @@ mod test { .unwrap(); let mut conn_state = ConnState::new(start, Default::default()); - conn_state.update( - start, + let mut stats = StatsMap::new(); + stats.insert( + [0u8; 32], Stats { rx_bytes: 1, tx_bytes: 0, }, ); + conn_state.update(start, stats); let update_time = Instant::now().checked_sub(BYTES_RX_TIMEOUT).unwrap(); - conn_state.update( - update_time, + let mut stats = StatsMap::new(); + stats.insert( + [0u8; 32], Stats { rx_bytes: 1, tx_bytes: 1, }, ); + conn_state.update(update_time, stats); assert!(conn_state.connected()); assert!(conn_state.rx_timed_out()); @@ -474,28 +488,36 @@ mod test { } struct MockTunnel { - on_get_stats: Box<dyn Fn() -> Result<stats::Stats, TunnelError> + Send>, + on_get_stats: Box<dyn Fn() -> Result<stats::StatsMap, TunnelError> + Send>, } impl MockTunnel { - fn new<F: Fn() -> Result<stats::Stats, TunnelError> + Send + 'static>(f: F) -> Self { + const PEER: [u8; 32] = [0u8; 32]; + + fn new<F: Fn() -> Result<stats::StatsMap, TunnelError> + Send + 'static>(f: F) -> Self { Self { on_get_stats: Box::new(f), } } fn always_incrementing() -> Self { - let traffic = Mutex::new(stats::Stats { - tx_bytes: 0, - rx_bytes: 0, - }); + let mut map = stats::StatsMap::new(); + map.insert( + Self::PEER, + stats::Stats { + tx_bytes: 0, + rx_bytes: 0, + }, + ); + let peers = Mutex::new(map); Self { on_get_stats: Box::new(move || { - let mut traffic = traffic.lock().unwrap(); - traffic.tx_bytes += 1; - traffic.rx_bytes += 1; - - Ok(*traffic) + let mut peers = peers.lock().unwrap(); + for traffic in peers.values_mut() { + traffic.tx_bytes += 1; + traffic.rx_bytes += 1; + } + Ok(peers.clone()) }), } } @@ -503,10 +525,15 @@ mod test { fn never_incrementing() -> Self { Self { on_get_stats: Box::new(|| { - Ok(stats::Stats { - tx_bytes: 0, - rx_bytes: 0, - }) + let mut map = stats::StatsMap::new(); + map.insert( + Self::PEER, + stats::Stats { + tx_bytes: 0, + rx_bytes: 0, + }, + ); + Ok(map) }), } } @@ -538,7 +565,7 @@ mod test { Ok(()) } - fn get_tunnel_stats(&self) -> Result<stats::Stats, TunnelError> { + fn get_tunnel_stats(&self) -> Result<stats::StatsMap, TunnelError> { (self.on_get_stats)() } } @@ -560,13 +587,19 @@ mod test { } fn connected_state(timestamp: Instant) -> ConnState { - ConnState::Connected { - rx_timestamp: timestamp, - tx_timestamp: timestamp, - stats: stats::Stats { + const PEER: [u8; 32] = [0u8; 32]; + let mut stats = stats::StatsMap::new(); + stats.insert( + PEER, + stats::Stats { tx_bytes: 0, rx_bytes: 0, }, + ); + ConnState::Connected { + rx_timestamp: timestamp, + tx_timestamp: timestamp, + stats, } } @@ -654,18 +687,27 @@ mod test { let should_stop = Arc::new(AtomicBool::new(false)); let should_stop_inner = should_stop.clone(); - let tunnel_stats = Mutex::new(stats::Stats { - rx_bytes: 0, - tx_bytes: 0, - }); + let mut map = stats::StatsMap::new(); + map.insert( + [0u8; 32], + stats::Stats { + tx_bytes: 0, + rx_bytes: 0, + }, + ); + let tunnel_stats = Mutex::new(map); let pinger = MockPinger::default(); let (_tunnel_anchor, tunnel) = MockTunnel::new(move || { let mut tunnel_stats = tunnel_stats.lock().unwrap(); if !should_stop_inner.load(Ordering::SeqCst) { - tunnel_stats.rx_bytes += 1; + for traffic in tunnel_stats.values_mut() { + traffic.rx_bytes += 1; + } + } + for traffic in tunnel_stats.values_mut() { + traffic.tx_bytes += 1; } - tunnel_stats.tx_bytes += 1; Ok(tunnel_stats.clone()) }) .into_locked(); diff --git a/talpid-core/src/tunnel/wireguard/mod.rs b/talpid-core/src/tunnel/wireguard/mod.rs index ed19f9bf69..71de9ad660 100644 --- a/talpid-core/src/tunnel/wireguard/mod.rs +++ b/talpid-core/src/tunnel/wireguard/mod.rs @@ -327,7 +327,10 @@ impl WireguardMonitor { #[cfg(target_os = "linux")] if !*FORCE_USERSPACE_WIREGUARD { if crate::dns::will_use_nm() { - match wireguard_kernel::NetworkManagerTunnel::new(config) { + match wireguard_kernel::NetworkManagerTunnel::new( + route_manager.runtime_handle(), + config, + ) { Ok(tunnel) => { log::debug!("Using NetworkManager to use kernel WireGuard implementation"); return Ok(Box::new(tunnel)); @@ -559,9 +562,7 @@ pub(crate) trait Tunnel: Send { #[cfg(target_os = "windows")] fn get_interface_luid(&self) -> u64; fn stop(self: Box<Self>) -> std::result::Result<(), TunnelError>; - fn get_tunnel_stats(&self) -> std::result::Result<stats::Stats, TunnelError>; - #[cfg(target_os = "linux")] - fn slow_stats_refresh_rate(&self) {} + fn get_tunnel_stats(&self) -> std::result::Result<stats::StatsMap, TunnelError>; } /// Errors to be returned from WireGuard implementations, namely implementers of the Tunnel trait diff --git a/talpid-core/src/tunnel/wireguard/stats.rs b/talpid-core/src/tunnel/wireguard/stats.rs index dbfd9fcc0a..ff076fd714 100644 --- a/talpid-core/src/tunnel/wireguard/stats.rs +++ b/talpid-core/src/tunnel/wireguard/stats.rs @@ -4,12 +4,12 @@ use super::wireguard_kernel::wg_message::{DeviceMessage, DeviceNla, PeerNla}; #[derive(err_derive::Error, Debug, PartialEq)] pub enum Error { + #[error(display = "Failed to parse peer pubkey from string \"_0\"")] + PubKeyParseError(String, #[error(source)] hex::FromHexError), + #[error(display = "Failed to parse integer from string \"_0\"")] IntParseError(String, #[error(source)] std::num::ParseIntError), - #[error(display = "Config key not found")] - KeyNotFoundError, - #[error(display = "Device no longer exists")] NoTunnelDevice, } @@ -21,8 +21,14 @@ pub struct Stats { pub rx_bytes: u64, } +/// A map from peer pubkeys to peer stats. +pub type StatsMap = std::collections::HashMap<[u8; 32], Stats>; + impl Stats { - pub fn parse_config_str(config: &str) -> Result<Self, Error> { + pub fn parse_config_str(config: &str) -> Result<StatsMap, Error> { + let mut map = StatsMap::new(); + + let mut peer = None; let mut tx_bytes = None; let mut rx_bytes = None; @@ -36,6 +42,14 @@ impl Stats { for (key, value) in parts { match key { + "public_key" => { + let mut buffer = [0u8; 32]; + hex::decode_to_slice(value, &mut buffer) + .map_err(|err| Error::PubKeyParseError(value.to_string(), err))?; + peer = Some(buffer); + tx_bytes = None; + rx_bytes = None; + } "rx_bytes" => { rx_bytes = Some( value @@ -55,35 +69,53 @@ impl Stats { _ => continue, } - } - match (tx_bytes, rx_bytes) { - (Some(tx_bytes), Some(rx_bytes)) => Ok(Self { tx_bytes, rx_bytes }), - _ => Err(Error::KeyNotFoundError), + match (peer, tx_bytes, rx_bytes) { + (Some(peer_val), Some(tx_bytes_val), Some(rx_bytes_val)) => { + map.insert( + peer_val, + Self { + tx_bytes: tx_bytes_val, + rx_bytes: rx_bytes_val, + }, + ); + peer = None; + tx_bytes = None; + rx_bytes = None; + } + _ => (), + } } + Ok(map) } #[cfg(target_os = "linux")] - pub fn parse_device_message(message: &DeviceMessage) -> Self { - // iterate over device attributes - let mut tx_bytes = 0; - let mut rx_bytes = 0; + pub fn parse_device_message(message: &DeviceMessage) -> StatsMap { + let mut map = StatsMap::new(); + for nla in &message.nlas { if let DeviceNla::Peers(peers) = nla { - // iterate over all peer attributes - let peer_iter = peers.iter().map(|peer| peer.0.as_slice()).flatten(); + for msg in peers { + let mut tx_bytes = 0; + let mut rx_bytes = 0; + let mut pub_key = None; - for peer_nla in peer_iter { - match peer_nla { - PeerNla::TxBytes(bytes) => tx_bytes += *bytes, - PeerNla::RxBytes(bytes) => rx_bytes += *bytes, - _ => continue, - }; + for nla in &msg.0 { + match nla { + PeerNla::TxBytes(bytes) => tx_bytes = *bytes, + PeerNla::RxBytes(bytes) => rx_bytes = *bytes, + PeerNla::PublicKey(key) => pub_key = Some(*key), + _ => continue, + } + } + if let Some(key) = pub_key { + map.insert(key, Stats { tx_bytes, rx_bytes }); + } } } } - Self { tx_bytes, rx_bytes } + map } } @@ -95,10 +127,14 @@ mod test { #[test] fn test_parsing() { let valid_input = "private_key=0000000000000000000000000000000000000000000000000000000000000000\npublic_key=0000000000000000000000000000000000000000000000000000000000000000\npreshared_key=0000000000000000000000000000000000000000000000000000000000000000\nprotocol_version=1\nendpoint=000.000.000.000:00000\nlast_handshake_time_sec=1578420649\nlast_handshake_time_nsec=369416131\ntx_bytes=2740\nrx_bytes=2396\npersistent_keepalive_interval=0\nallowed_ip=0.0.0.0/0\n"; + let pubkey = [0u8; 32]; let stats = Stats::parse_config_str(valid_input).expect("Failed to parse valid input"); - assert_eq!(stats.rx_bytes, 2396); - assert_eq!(stats.tx_bytes, 2740); + assert_eq!(stats.len(), 1); + let actual_keys: Vec<[u8; 32]> = stats.keys().cloned().collect(); + assert_eq!(actual_keys, [pubkey]); + assert_eq!(stats[&pubkey].rx_bytes, 2396); + assert_eq!(stats[&pubkey].tx_bytes, 2740); } #[test] @@ -112,13 +148,4 @@ mod test { Err(Error::IntParseError(invalid_str, int_err)) ); } - - #[test] - fn test_parsing_missing_keys() { - let invalid_input = "private_key=0000000000000000000000000000000000000000000000000000000000000000\npublic_key=0000000000000000000000000000000000000000000000000000000000000000\npreshared_key=0000000000000000000000000000000000000000000000000000000000000000\nprotocol_version=1\nendpoint=000.000.000.000:00000\nlast_handshake_time_sec=1578420649\nlast_handshake_time_nsec=369416131\ntx_bytes=2740\npersistent_keepalive_interval=0\nallowed_ip=0.0.0.0/0\n"; - assert_eq!( - Stats::parse_config_str(invalid_input), - Err(Error::KeyNotFoundError) - ); - } } diff --git a/talpid-core/src/tunnel/wireguard/wireguard_go.rs b/talpid-core/src/tunnel/wireguard/wireguard_go.rs index 2145bb96d6..f8fbd21e2e 100644 --- a/talpid-core/src/tunnel/wireguard/wireguard_go.rs +++ b/talpid-core/src/tunnel/wireguard/wireguard_go.rs @@ -1,4 +1,7 @@ -use super::{stats::Stats, Config, Tunnel, TunnelError}; +use super::{ + stats::{Stats, StatsMap}, + Config, Tunnel, TunnelError, +}; use crate::tunnel::{ tun_provider::TunProvider, wireguard::logging::{clean_up_logging, initialize_logging, logging_callback, WgLogLevel}, @@ -307,7 +310,7 @@ impl Tunnel for WgGoTunnel { self.interface_luid } - fn get_tunnel_stats(&self) -> Result<Stats> { + fn get_tunnel_stats(&self) -> Result<StatsMap> { let config_str = unsafe { let ptr = wgGetConfig(self.handle.unwrap()); if ptr.is_null() { diff --git a/talpid-core/src/tunnel/wireguard/wireguard_kernel/netlink_tunnel.rs b/talpid-core/src/tunnel/wireguard/wireguard_kernel/netlink_tunnel.rs index b5a4f1429a..9606fe4b64 100644 --- a/talpid-core/src/tunnel/wireguard/wireguard_kernel/netlink_tunnel.rs +++ b/talpid-core/src/tunnel/wireguard/wireguard_kernel/netlink_tunnel.rs @@ -1,6 +1,7 @@ use super::{ - super::stats::Stats, wg_message::DeviceNla, Config, Error, Handle, Tunnel, TunnelError, - MULLVAD_INTERFACE_NAME, + super::stats::{Stats, StatsMap}, + wg_message::DeviceNla, + Config, Error, Handle, Tunnel, TunnelError, MULLVAD_INTERFACE_NAME, }; @@ -97,7 +98,7 @@ impl Tunnel for NetlinkTunnel { }) } - fn get_tunnel_stats(&self) -> std::result::Result<Stats, TunnelError> { + fn get_tunnel_stats(&self) -> std::result::Result<StatsMap, TunnelError> { let mut wg = self.netlink_connections.wg_handle.clone(); let interface_index = self.interface_index; let result = self.tokio_handle.block_on(async move { diff --git a/talpid-core/src/tunnel/wireguard/wireguard_kernel/nm_tunnel.rs b/talpid-core/src/tunnel/wireguard/wireguard_kernel/nm_tunnel.rs index 21f5f283cc..1df358ab8d 100644 --- a/talpid-core/src/tunnel/wireguard/wireguard_kernel/nm_tunnel.rs +++ b/talpid-core/src/tunnel/wireguard/wireguard_kernel/nm_tunnel.rs @@ -1,6 +1,6 @@ use super::{ - super::stats::{Error as StatsError, Stats}, - Config, Error as WgKernelError, Tunnel, TunnelError, MULLVAD_INTERFACE_NAME, + super::stats::{Stats, StatsMap}, + Config, Error as WgKernelError, Handle, Tunnel, TunnelError, MULLVAD_INTERFACE_NAME, }; use std::collections::HashMap; use talpid_dbus::{ @@ -10,7 +10,6 @@ use talpid_dbus::{ WireguardTunnel, }, }; -use talpid_types::ErrorExt; #[derive(err_derive::Error, Debug)] @@ -22,17 +21,20 @@ pub enum Error { NetworkManager(#[error(source)] NetworkManagerError), } -const TRAFFIC_STATS_REFRESH_RATE_MS: u32 = 1000; -const INITIAL_TRAFFIC_STATS_REFRESH_RATE_MS: u32 = 10; - pub struct NetworkManagerTunnel { network_manager: NetworkManager, tunnel: Option<WireguardTunnel>, + netlink_connections: Handle, + tokio_handle: tokio::runtime::Handle, + interface_name: String, } impl NetworkManagerTunnel { - pub fn new(config: &Config) -> std::result::Result<Self, WgKernelError> { + pub fn new( + tokio_handle: tokio::runtime::Handle, + config: &Config, + ) -> std::result::Result<Self, WgKernelError> { let network_manager = NetworkManager::new() .map_err(Error::NetworkManager) .map_err(WgKernelError::NetworkManager)?; @@ -41,29 +43,28 @@ impl NetworkManagerTunnel { .create_wg_tunnel(&config_map) .map_err(|err| WgKernelError::NetworkManager(err.into()))?; - network_manager - .set_stats_refresh_rate(&tunnel, INITIAL_TRAFFIC_STATS_REFRESH_RATE_MS) - .map_err(|err| WgKernelError::NetworkManager(err.into()))?; - + let interface_name = match network_manager.get_interface_name(&tunnel) { + Ok(name) => name, + Err(error) => { + log::error!("Failed to fetch interface name from NM: {}", error); + MULLVAD_INTERFACE_NAME.to_string() + } + }; + let netlink_connections = tokio_handle.block_on(Handle::connect())?; Ok(NetworkManagerTunnel { network_manager, tunnel: Some(tunnel), + netlink_connections, + tokio_handle, + interface_name, }) } } impl Tunnel for NetworkManagerTunnel { fn get_interface_name(&self) -> String { - if let Some(tunnel) = self.tunnel.as_ref() { - match self.network_manager.get_interface_name(tunnel) { - Ok(name) => { - return name; - } - Err(error) => log::error!("Failed to fetch interface name from NM: {}", error), - } - } - MULLVAD_INTERFACE_NAME.to_string() + self.interface_name.clone() } fn stop(mut self: Box<Self>) -> std::result::Result<(), TunnelError> { @@ -79,31 +80,18 @@ impl Tunnel for NetworkManagerTunnel { } } - fn get_tunnel_stats(&self) -> std::result::Result<Stats, TunnelError> { - let tunnel = self - .tunnel - .as_ref() - .ok_or(TunnelError::StatsError(StatsError::NoTunnelDevice))?; - let (tx_bytes, rx_bytes) = self - .network_manager - .get_tunnel_stats(tunnel) - .map_err(|_| TunnelError::StatsError(StatsError::KeyNotFoundError))?; - - Ok(Stats { tx_bytes, rx_bytes }) - } - - fn slow_stats_refresh_rate(&self) { - if let Some(tunnel) = self.tunnel.as_ref() { - if let Err(err) = self - .network_manager - .set_stats_refresh_rate(tunnel, TRAFFIC_STATS_REFRESH_RATE_MS) - { - log::error!( - "{}", - err.display_chain_with_msg("Failed to reset stats refresh rate: ") - ); - } - } + fn get_tunnel_stats(&self) -> std::result::Result<StatsMap, TunnelError> { + let mut wg = self.netlink_connections.wg_handle.clone(); + self.tokio_handle.block_on(async move { + let device = wg + .get_by_name(self.interface_name.clone()) + .await + .map_err(|err| { + log::error!("Failed to fetch WireGuard device config: {}", err); + TunnelError::GetConfigError + })?; + Ok(Stats::parse_device_message(&device)) + }) } } |
