summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--mullvad-cli/src/cmds/debug.rs25
-rw-r--r--mullvad-daemon/src/lib.rs62
-rw-r--r--mullvad-daemon/src/management_interface.rs20
-rw-r--r--mullvad-management-interface/proto/management_interface.proto4
-rw-r--r--mullvad-management-interface/src/client.rs11
-rw-r--r--mullvad-types/src/relay_list.rs8
6 files changed, 130 insertions, 0 deletions
diff --git a/mullvad-cli/src/cmds/debug.rs b/mullvad-cli/src/cmds/debug.rs
index d67194b058..933f1212e8 100644
--- a/mullvad-cli/src/cmds/debug.rs
+++ b/mullvad-cli/src/cmds/debug.rs
@@ -9,6 +9,19 @@ use mullvad_types::{
pub enum DebugCommands {
/// Block all internet connection by setting an invalid relay constraint.
BlockConnection,
+ /// Relay
+ #[clap(subcommand)]
+ Relay(RelayDebugCommands),
+}
+
+#[derive(clap::Subcommand, Debug)]
+pub enum RelayDebugCommands {
+ /// Inactivate this _category of relays_ - a category can be one of the following: a relay, a
+ /// city, a country or a tunnel protocol (`openvpn` or `wireguard`).
+ Disable { relay: String },
+ /// (Re)Activate this _category of relays_ - a category can be one of the following: a relay, a
+ /// city, a country or a tunnel protocol (`openvpn` or `wireguard`).
+ Enable { relay: String },
}
impl DebugCommands {
@@ -41,6 +54,18 @@ impl DebugCommands {
eprintln!("WARNING: ENTERED BLOCKED MODE");
Ok(())
}
+ DebugCommands::Relay(RelayDebugCommands::Disable { relay }) => {
+ let mut rpc = MullvadProxyClient::new().await?;
+ rpc.disable_relay(relay.clone()).await?;
+ println!("{relay} is now marked as inactive");
+ Ok(())
+ }
+ DebugCommands::Relay(RelayDebugCommands::Enable { relay }) => {
+ let mut rpc = MullvadProxyClient::new().await?;
+ rpc.enable_relay(relay.clone()).await?;
+ println!("{relay} is now marked as active");
+ Ok(())
+ }
}
}
}
diff --git a/mullvad-daemon/src/lib.rs b/mullvad-daemon/src/lib.rs
index 68e2e57285..f5ca13f976 100644
--- a/mullvad-daemon/src/lib.rs
+++ b/mullvad-daemon/src/lib.rs
@@ -392,6 +392,16 @@ pub enum DaemonCommand {
ExportJsonSettings(ResponseTx<String, settings::patch::Error>),
/// Request the current feature indicators.
GetFeatureIndicators(oneshot::Sender<FeatureIndicators>),
+
+ // Debug features
+ DisableRelay {
+ relay: String,
+ tx: oneshot::Sender<()>,
+ },
+ EnableRelay {
+ relay: String,
+ tx: oneshot::Sender<()>,
+ },
}
/// All events that can happen in the daemon. Sent from various threads and exposed interfaces.
@@ -1454,6 +1464,8 @@ impl Daemon {
ApplyJsonSettings(tx, blob) => self.on_apply_json_settings(tx, blob).await,
ExportJsonSettings(tx) => self.on_export_json_settings(tx),
GetFeatureIndicators(tx) => self.on_get_feature_indicators(tx),
+ DisableRelay { relay, tx } => self.on_toggle_relay(relay, false, tx),
+ EnableRelay { relay, tx } => self.on_toggle_relay(relay, true, tx),
}
}
@@ -3136,6 +3148,56 @@ impl Daemon {
Self::oneshot_send(tx, feature_indicators, "get_feature_indicators response");
}
+ // Debug features
+
+ /// Mark [relay] as active or inactive in the daemon's relay list.
+ fn on_toggle_relay(&mut self, relay: String, active: bool, tx: oneshot::Sender<()>) {
+ use mullvad_types::relay_list::RelayList;
+ let relays = {
+ let relay_list = self.relay_selector.get_relays();
+ let countries = {
+ let mut countries = relay_list.countries;
+ for country in &mut countries {
+ let matching_country = relay == country.name;
+ for city in &mut country.cities {
+ let matching_city = relay == city.name;
+ for settings_relay in &mut city.relays {
+ // `relay` can also be a VPN protocol. This is arbitrary, but useful.
+ let matching_protocol = (relay.to_lowercase().eq("openvpn")
+ && settings_relay.is_openvpn())
+ || (relay.to_lowercase().eq("wireguard")
+ && settings_relay.is_wireguard());
+ let matching_relay = relay == settings_relay.hostname;
+
+ if matching_relay
+ || matching_city
+ || matching_country
+ || matching_protocol
+ {
+ settings_relay.active = active;
+ }
+ }
+ }
+ }
+ countries
+ };
+ RelayList {
+ countries,
+ ..relay_list
+ }
+ };
+
+ self.relay_selector.set_relays(relays.clone());
+
+ self.management_interface
+ .notifier()
+ .notify_relay_list(relays);
+
+ self.reconnect_tunnel();
+
+ Self::oneshot_send(tx, (), "on_toggle_relay response");
+ }
+
/// Set the target state of the client. If it changed trigger the operations needed to
/// progress towards that state.
/// Returns a bool representing whether a state change was initiated.
diff --git a/mullvad-daemon/src/management_interface.rs b/mullvad-daemon/src/management_interface.rs
index 8249aea968..3efe41e288 100644
--- a/mullvad-daemon/src/management_interface.rs
+++ b/mullvad-daemon/src/management_interface.rs
@@ -1095,6 +1095,26 @@ impl ManagementService for ManagementServiceImpl {
Ok(Response::new(feature_indicators))
}
+
+ // Debug features
+
+ async fn disable_relay(&self, relay: Request<String>) -> ServiceResult<()> {
+ log::debug!("disable_relay");
+ let (tx, rx) = oneshot::channel();
+ let relay = relay.into_inner();
+ self.send_command_to_daemon(DaemonCommand::DisableRelay { relay, tx })?;
+ self.wait_for_result(rx).await?;
+ Ok(Response::new(()))
+ }
+
+ async fn enable_relay(&self, relay: Request<String>) -> ServiceResult<()> {
+ log::debug!("enable_relay");
+ let (tx, rx) = oneshot::channel();
+ let relay = relay.into_inner();
+ self.send_command_to_daemon(DaemonCommand::EnableRelay { relay, tx })?;
+ self.wait_for_result(rx).await?;
+ Ok(Response::new(()))
+ }
}
impl ManagementServiceImpl {
diff --git a/mullvad-management-interface/proto/management_interface.proto b/mullvad-management-interface/proto/management_interface.proto
index 2b2e0bfe59..5acc8c3463 100644
--- a/mullvad-management-interface/proto/management_interface.proto
+++ b/mullvad-management-interface/proto/management_interface.proto
@@ -127,6 +127,10 @@ service ManagementService {
// Get current feature indicators
rpc GetFeatureIndicators(google.protobuf.Empty) returns (FeatureIndicators) {}
+
+ // Debug features
+ rpc DisableRelay(google.protobuf.StringValue) returns (google.protobuf.Empty) {}
+ rpc EnableRelay(google.protobuf.StringValue) returns (google.protobuf.Empty) {}
}
message UUID { string value = 1; }
diff --git a/mullvad-management-interface/src/client.rs b/mullvad-management-interface/src/client.rs
index fd038cc37f..6d17e923f6 100644
--- a/mullvad-management-interface/src/client.rs
+++ b/mullvad-management-interface/src/client.rs
@@ -768,6 +768,17 @@ impl MullvadProxyClient {
.map(|response| response.into_inner())
.map(FeatureIndicators::from)
}
+
+ // Debug features
+ pub async fn disable_relay(&mut self, relay: String) -> Result<()> {
+ self.0.disable_relay(relay).await.map_err(Error::Rpc)?;
+ Ok(())
+ }
+
+ pub async fn enable_relay(&mut self, relay: String) -> Result<()> {
+ self.0.enable_relay(relay).await.map_err(Error::Rpc)?;
+ Ok(())
+ }
}
#[cfg(not(target_os = "android"))]
diff --git a/mullvad-types/src/relay_list.rs b/mullvad-types/src/relay_list.rs
index c4d1d61bb7..351c0d0e86 100644
--- a/mullvad-types/src/relay_list.rs
+++ b/mullvad-types/src/relay_list.rs
@@ -100,6 +100,14 @@ impl Relay {
self.ipv6_addr_in = Some(new_ipv6);
self.overridden_ipv6 = true;
}
+
+ pub const fn is_wireguard(&self) -> bool {
+ matches!(self.endpoint_data, RelayEndpointData::Wireguard(_))
+ }
+
+ pub const fn is_openvpn(&self) -> bool {
+ matches!(self.endpoint_data, RelayEndpointData::Openvpn)
+ }
}
impl PartialEq for Relay {