summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorDavid Lönnhager <david.l@mullvad.net>2021-09-06 14:19:02 +0200
committerDavid Lönnhager <david.l@mullvad.net>2021-09-06 14:19:02 +0200
commit4ba1552c25a84dcf4a7abb4ee109804b2722e3ec (patch)
tree8c2783de6450fdb6947d6a4702860e9f69bb3454
parentc1bfddcb3f84cf3562ab8dc2641e9ea186682070 (diff)
parenta20077e86e87e9e4346c1a03e5e0861f4d3a14ba (diff)
downloadmullvadvpn-4ba1552c25a84dcf4a7abb4ee109804b2722e3ec.tar.xz
mullvadvpn-4ba1552c25a84dcf4a7abb4ee109804b2722e3ec.zip
Merge branch 'fix-ping-monitor-multiple-peers'
-rw-r--r--CHANGELOG.md1
-rw-r--r--talpid-core/src/tunnel/wireguard/connectivity_check.rs144
-rw-r--r--talpid-core/src/tunnel/wireguard/mod.rs9
-rw-r--r--talpid-core/src/tunnel/wireguard/stats.rs91
-rw-r--r--talpid-core/src/tunnel/wireguard/wireguard_go.rs7
-rw-r--r--talpid-core/src/tunnel/wireguard/wireguard_kernel/netlink_tunnel.rs7
-rw-r--r--talpid-core/src/tunnel/wireguard/wireguard_kernel/nm_tunnel.rs78
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))
+ })
}
}