diff options
| -rw-r--r-- | mullvad-cli/src/cmds/debug.rs | 25 | ||||
| -rw-r--r-- | mullvad-daemon/src/lib.rs | 62 | ||||
| -rw-r--r-- | mullvad-daemon/src/management_interface.rs | 20 | ||||
| -rw-r--r-- | mullvad-management-interface/proto/management_interface.proto | 4 | ||||
| -rw-r--r-- | mullvad-management-interface/src/client.rs | 11 | ||||
| -rw-r--r-- | mullvad-types/src/relay_list.rs | 8 |
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 { |
