diff options
| author | Linus Färnstrand <linus@mullvad.net> | 2026-04-22 12:38:22 +0200 |
|---|---|---|
| committer | Linus Färnstrand <linus@mullvad.net> | 2026-04-22 12:38:22 +0200 |
| commit | 9e9af2d3e7d0cb497e131e43e16229091ff8cda2 (patch) | |
| tree | 965a25c2e66499948459a3f61676da61c6d951b7 | |
| parent | 9f106b624d702ee38b4e0cd2dbc8b448c0bb81da (diff) | |
| parent | f67cf15be13f3dc5c67466c7bc3d7ccf6b16a2d8 (diff) | |
| download | mullvadvpn-9e9af2d3e7d0cb497e131e43e16229091ff8cda2.tar.xz mullvadvpn-9e9af2d3e7d0cb497e131e43e16229091ff8cda2.zip | |
Merge branch 'remove-unused-leak-checker'
| -rw-r--r-- | Cargo.lock | 3 | ||||
| -rw-r--r-- | mullvad-daemon/Cargo.toml | 2 | ||||
| -rw-r--r-- | mullvad-daemon/src/management_interface.rs | 12 | ||||
| -rw-r--r-- | mullvad-leak-checker/Cargo.toml | 7 | ||||
| -rw-r--r-- | mullvad-leak-checker/examples/leaker-cli.rs | 38 | ||||
| -rw-r--r-- | mullvad-leak-checker/src/am_i_mullvad.rs | 89 | ||||
| -rw-r--r-- | mullvad-leak-checker/src/lib.rs | 20 | ||||
| -rw-r--r-- | mullvad-leak-checker/src/traceroute/unix/linux_like.rs | 10 | ||||
| -rw-r--r-- | mullvad-leak-checker/src/traceroute/unix/macos.rs | 2 | ||||
| -rw-r--r-- | mullvad-leak-checker/src/traceroute/windows.rs | 10 |
10 files changed, 19 insertions, 174 deletions
diff --git a/Cargo.lock b/Cargo.lock index c007cdc221..4d1a37b118 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3103,12 +3103,9 @@ dependencies = [ "log", "nix 0.30.1", "pnet_packet 0.35.0", - "reqwest", - "serde", "socket2 0.5.8", "talpid-windows", "tokio", - "tracing-subscriber", "windows-sys 0.61.2", ] diff --git a/mullvad-daemon/Cargo.toml b/mullvad-daemon/Cargo.toml index 25c16ffef0..e44597032e 100644 --- a/mullvad-daemon/Cargo.toml +++ b/mullvad-daemon/Cargo.toml @@ -80,7 +80,7 @@ log-panics = "2.0.0" mullvad-api = { path = "../mullvad-api" } mullvad-encrypted-dns-proxy = { path = "../mullvad-encrypted-dns-proxy" } mullvad-fs = { path = "../mullvad-fs" } -mullvad-leak-checker = { path = "../mullvad-leak-checker", default-features = false } +mullvad-leak-checker = { path = "../mullvad-leak-checker" } mullvad-logging = { path = "../mullvad-logging" } mullvad-management-interface = { path = "../mullvad-management-interface" } mullvad-paths = { path = "../mullvad-paths" } diff --git a/mullvad-daemon/src/management_interface.rs b/mullvad-daemon/src/management_interface.rs index 5de38f50b4..a1df9a27db 100644 --- a/mullvad-daemon/src/management_interface.rs +++ b/mullvad-daemon/src/management_interface.rs @@ -1485,17 +1485,11 @@ impl ManagementInterfaceEventBroadcaster { /// Notify clients about a potential leak. pub(crate) fn notify_leak(&self, leak: mullvad_leak_checker::LeakInfo) { - use mullvad_leak_checker::LeakInfo; - let LeakInfo::NodeReachableOnInterface { + log::trace!("Broadcasting leak info: {leak:#?}"); + let mullvad_leak_checker::LeakInfo { reachable_nodes, interface, - } = &leak - else { - log::trace!("Matched on unexpected leak checker event: {leak:#?}"); - return; - }; - - log::trace!("Broadcasting leak info: {leak:#?}"); + } = &leak; let interface = match interface { mullvad_leak_checker::Interface::Name(name) => name.to_owned(), #[cfg(target_os = "macos")] diff --git a/mullvad-leak-checker/Cargo.toml b/mullvad-leak-checker/Cargo.toml index e860f3dfb9..a07d24e189 100644 --- a/mullvad-leak-checker/Cargo.toml +++ b/mullvad-leak-checker/Cargo.toml @@ -11,8 +11,6 @@ anyhow.workspace = true clap = { workspace = true, features = ["derive"] } futures.workspace = true log.workspace = true -reqwest = { workspace = true, features = ["json"], optional = true } -serde = { workspace = true, features = ["derive"] } socket2 = { workspace = true, features = ["all"] } tokio = { workspace = true, features = [ "macros", @@ -25,7 +23,6 @@ tokio = { workspace = true, features = [ [dev-dependencies] tokio = { workspace = true, features = ["full"] } -tracing-subscriber = { workspace = true } [target.'cfg(unix)'.dependencies] nix = { workspace = true, features = ["net", "socket", "uio"] } @@ -35,9 +32,5 @@ pnet_packet.workspace = true talpid-windows = { path = "../talpid-windows" } windows-sys = { workspace = true, features = ["Win32_NetworkManagement_Ndis"] } -[features] -default = ["am-i-mullvad"] -am-i-mullvad = ["dep:reqwest"] - [lints] workspace = true diff --git a/mullvad-leak-checker/examples/leaker-cli.rs b/mullvad-leak-checker/examples/leaker-cli.rs deleted file mode 100644 index 150d26d530..0000000000 --- a/mullvad-leak-checker/examples/leaker-cli.rs +++ /dev/null @@ -1,38 +0,0 @@ -use clap::{Parser, Subcommand}; -use mullvad_leak_checker::traceroute::TracerouteOpt; -use tracing_subscriber::{EnvFilter, filter::LevelFilter}; - -#[derive(Parser)] -pub struct Opt { - #[clap(subcommand)] - pub method: LeakMethod, -} - -#[derive(Subcommand, Clone)] -pub enum LeakMethod { - /// Check for leaks by binding to a non-tunnel interface and probing for reachable nodes. - Traceroute(#[clap(flatten)] TracerouteOpt), - - /// Ask `am.i.mullvad.net` whether you are leaking. - #[cfg(feature = "am-i-mullvad")] - AmIMullvad(#[clap(flatten)] mullvad_leak_checker::am_i_mullvad::AmIMullvadOpt), -} - -#[tokio::main] -async fn main() -> anyhow::Result<()> { - tracing_subscriber::fmt() - .with_env_filter(EnvFilter::from_default_env().add_directive(LevelFilter::INFO.into())) - .init(); - - let opt = Opt::parse(); - - let leak_status = match &opt.method { - LeakMethod::Traceroute(opt) => mullvad_leak_checker::traceroute::run_leak_test(opt).await, - #[cfg(feature = "am-i-mullvad")] - LeakMethod::AmIMullvad(opt) => mullvad_leak_checker::am_i_mullvad::run_leak_test(opt).await, - }; - - log::info!("Leak status: {leak_status:#?}"); - - Ok(()) -} diff --git a/mullvad-leak-checker/src/am_i_mullvad.rs b/mullvad-leak-checker/src/am_i_mullvad.rs deleted file mode 100644 index 1948a109fb..0000000000 --- a/mullvad-leak-checker/src/am_i_mullvad.rs +++ /dev/null @@ -1,89 +0,0 @@ -use anyhow::{Context, anyhow}; -use futures::TryFutureExt; -use reqwest::{Client, ClientBuilder}; -use serde::Deserialize; - -use crate::{LeakInfo, LeakStatus}; - -#[derive(Clone, clap::Args)] -pub struct AmIMullvadOpt { - /// Try to bind to a specific interface - #[clap(short, long)] - interface: Option<String>, -} - -const AM_I_MULLVAD_URL: &str = "https://am.i.mullvad.net/json"; - -/// [try_run_leak_test], but on an error, assume we aren't leaking. -pub async fn run_leak_test(opt: &AmIMullvadOpt) -> LeakStatus { - try_run_leak_test(opt) - .await - .inspect_err(|e| log::debug!("Leak test errored, assuming no leak. {e:?}")) - .unwrap_or(LeakStatus::NoLeak) -} - -/// Check if connected to Mullvad and print the result to stdout -pub async fn try_run_leak_test(opt: &AmIMullvadOpt) -> anyhow::Result<LeakStatus> { - #[derive(Debug, Deserialize)] - struct Response { - ip: String, - mullvad_exit_ip_hostname: Option<String>, - } - - let mut client = Client::builder(); - - if let Some(interface) = &opt.interface { - client = bind_client_to_interface(client, interface)?; - } - - let client = client.build().context("Failed to create HTTP client")?; - let response: Response = client - .get(AM_I_MULLVAD_URL) - //.timeout(Duration::from_secs(opt.timeout)) - .send() - .and_then(|r| r.json()) - .await - .with_context(|| anyhow!("Failed to GET {AM_I_MULLVAD_URL}"))?; - - if let Some(server) = &response.mullvad_exit_ip_hostname { - log::debug!( - "You are connected to Mullvad (server {}). Your IP address is {}", - server, - response.ip - ); - Ok(LeakStatus::NoLeak) - } else { - log::debug!( - "You are not connected to Mullvad. Your IP address is {}", - response.ip - ); - Ok(LeakStatus::LeakDetected(LeakInfo::AmIMullvad { - ip: response.ip.parse().context("Malformed IP")?, - })) - } -} - -#[cfg(target_os = "linux")] -fn bind_client_to_interface( - builder: ClientBuilder, - interface: &str, -) -> anyhow::Result<ClientBuilder> { - log::debug!("Binding HTTP client to {interface}"); - Ok(builder.interface(interface)) -} - -#[cfg(any(target_os = "macos", target_os = "windows", target_os = "android"))] -fn bind_client_to_interface( - builder: ClientBuilder, - interface: &str, -) -> anyhow::Result<ClientBuilder> { - use crate::Interface; - use crate::util::{Ip, get_interface_ip}; - - let interface = Interface::Name(interface.to_string()); - let ip = get_interface_ip(&interface, Ip::v6()) - .or_else(|_| get_interface_ip(&interface, Ip::v4()))?; - - log::debug!("Binding HTTP client to {ip} ({interface:?})"); - Ok(builder.local_address(ip)) -} diff --git a/mullvad-leak-checker/src/lib.rs b/mullvad-leak-checker/src/lib.rs index 59dc57103a..e5f1163568 100644 --- a/mullvad-leak-checker/src/lib.rs +++ b/mullvad-leak-checker/src/lib.rs @@ -1,7 +1,5 @@ use std::{fmt, net::IpAddr}; -#[cfg(feature = "am-i-mullvad")] -pub mod am_i_mullvad; pub mod traceroute; mod util; @@ -11,19 +9,13 @@ pub enum LeakStatus { LeakDetected(LeakInfo), } -/// Details about how a leak happened +/// Details about how a leak happened. +/// +/// Managed to reach another network node on the physical interface, bypassing firewall rules. #[derive(Clone, Debug)] -#[non_exhaustive] -pub enum LeakInfo { - /// Managed to reach another network node on the physical interface, bypassing firewall rules. - NodeReachableOnInterface { - reachable_nodes: Vec<IpAddr>, - interface: Interface, - }, - - /// Queried a <https://am.i.mullvad.net>, and was not mullvad. - #[cfg(feature = "am-i-mullvad")] - AmIMullvad { ip: IpAddr }, +pub struct LeakInfo { + pub reachable_nodes: Vec<IpAddr>, + pub interface: Interface, } #[derive(Clone)] diff --git a/mullvad-leak-checker/src/traceroute/unix/linux_like.rs b/mullvad-leak-checker/src/traceroute/unix/linux_like.rs index dbca77fd2b..622949d6f7 100644 --- a/mullvad-leak-checker/src/traceroute/unix/linux_like.rs +++ b/mullvad-leak-checker/src/traceroute/unix/linux_like.rs @@ -252,12 +252,10 @@ async fn recv_ttl_responses( debug_assert!(!reachable_nodes.is_empty()); - Ok(LeakStatus::LeakDetected( - LeakInfo::NodeReachableOnInterface { - reachable_nodes, - interface: interface.clone(), - }, - )) + Ok(LeakStatus::LeakDetected(LeakInfo { + reachable_nodes, + interface: interface.clone(), + })) } struct RecvPacket<'a, S> { diff --git a/mullvad-leak-checker/src/traceroute/unix/macos.rs b/mullvad-leak-checker/src/traceroute/unix/macos.rs index 0fe1054ba3..3cf95dcfeb 100644 --- a/mullvad-leak-checker/src/traceroute/unix/macos.rs +++ b/mullvad-leak-checker/src/traceroute/unix/macos.rs @@ -142,7 +142,7 @@ async fn recv_ttl_responses( .context("Failed to read from raw socket")?, _timeout = timer => { - return Ok(LeakStatus::LeakDetected(LeakInfo::NodeReachableOnInterface { + return Ok(LeakStatus::LeakDetected(LeakInfo { reachable_nodes, interface: interface.clone(), })); diff --git a/mullvad-leak-checker/src/traceroute/windows.rs b/mullvad-leak-checker/src/traceroute/windows.rs index 6f6c787150..79a39cae4d 100644 --- a/mullvad-leak-checker/src/traceroute/windows.rs +++ b/mullvad-leak-checker/src/traceroute/windows.rs @@ -86,12 +86,10 @@ pub async fn traceroute_using_ping(opt: &TracerouteOpt) -> anyhow::Result<LeakSt while let Some(result) = ping_tasks.next().await { let Some(ip) = result? else { continue }; - return Ok(LeakStatus::LeakDetected( - LeakInfo::NodeReachableOnInterface { - reachable_nodes: vec![ip], - interface: opt.interface.clone(), - }, - )); + return Ok(LeakStatus::LeakDetected(LeakInfo { + reachable_nodes: vec![ip], + interface: opt.interface.clone(), + })); } anyhow::Ok(LeakStatus::NoLeak) |
