summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorLinus Färnstrand <linus@mullvad.net>2026-04-22 12:38:22 +0200
committerLinus Färnstrand <linus@mullvad.net>2026-04-22 12:38:22 +0200
commit9e9af2d3e7d0cb497e131e43e16229091ff8cda2 (patch)
tree965a25c2e66499948459a3f61676da61c6d951b7
parent9f106b624d702ee38b4e0cd2dbc8b448c0bb81da (diff)
parentf67cf15be13f3dc5c67466c7bc3d7ccf6b16a2d8 (diff)
downloadmullvadvpn-9e9af2d3e7d0cb497e131e43e16229091ff8cda2.tar.xz
mullvadvpn-9e9af2d3e7d0cb497e131e43e16229091ff8cda2.zip
Merge branch 'remove-unused-leak-checker'
-rw-r--r--Cargo.lock3
-rw-r--r--mullvad-daemon/Cargo.toml2
-rw-r--r--mullvad-daemon/src/management_interface.rs12
-rw-r--r--mullvad-leak-checker/Cargo.toml7
-rw-r--r--mullvad-leak-checker/examples/leaker-cli.rs38
-rw-r--r--mullvad-leak-checker/src/am_i_mullvad.rs89
-rw-r--r--mullvad-leak-checker/src/lib.rs20
-rw-r--r--mullvad-leak-checker/src/traceroute/unix/linux_like.rs10
-rw-r--r--mullvad-leak-checker/src/traceroute/unix/macos.rs2
-rw-r--r--mullvad-leak-checker/src/traceroute/windows.rs10
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)