diff options
| author | Markus Pettersson <markus.pettersson@mullvad.net> | 2023-09-20 15:36:01 +0200 |
|---|---|---|
| committer | David Lönnhager <david.l@mullvad.net> | 2023-10-09 14:40:08 +0200 |
| commit | 43cb757d2cbb396a627fb6b970394a7b73d37dc5 (patch) | |
| tree | 084fcd0a9152d50242ed1934fc5623efe8a0052d /mullvad-cli/src | |
| parent | 7fcaad31643ca324c5dd4a17ddf0f445ac679384 (diff) | |
| download | mullvadvpn-43cb757d2cbb396a627fb6b970394a7b73d37dc5.tar.xz mullvadvpn-43cb757d2cbb396a627fb6b970394a7b73d37dc5.zip | |
Cleanup
- General code cleanup
- Fix some typos
- Add some doc comments
- Address several `TODO` comments
- Fix `clippy` warnings
- Removed unused dependency `mullvad-api` from `mullvad-cli`
- Removed unused dependency `rand` from `mullvad-daemon`
- Rename `mullvad proxy` to `mullvad api-access`
- Rename `mullvad_types::api_access_method` -> `mullvad_types::access_method`
- Remove unused `mullvad api-access edit` arguments
- Fix `Display` for `ProxyConfig` printing arguments in the wrong order
- Re-phrase `mullvad api-access test`
- If the API call failed, point out which tested access method that
did not work.
- Fix missing `socket_bypass_tx` value for Android
- Refactor `ApiAccessMethod` proto definition
- Simplify protobuf definitions of `SOCKS5` api access methods
- Remove the `Socks5` enum in favor of implementing `Socks5Local` and
`Socks5Remote` directly.
- Move `enabled` and `name` out of the individual messages and put them
next to the `oneof access_method` in `ApiAccessMethod` proto definition
- Use derived `PartialEq` and `Hash` from `AccessMethod`
- Instead of hand-rolling `Hash` and implementing an ad-hoc version of
half of `PartialEq`, these can now be derived and used as one would
imaging due to the refactoring wherer `name` and `enabled` was moved
out of `AccessMethod` into `ApiAccessMethod`.
Diffstat (limited to 'mullvad-cli/src')
| -rw-r--r-- | mullvad-cli/src/cmds/api_access.rs (renamed from mullvad-cli/src/cmds/proxy.rs) | 364 | ||||
| -rw-r--r-- | mullvad-cli/src/cmds/mod.rs | 2 | ||||
| -rw-r--r-- | mullvad-cli/src/main.rs | 8 |
3 files changed, 165 insertions, 209 deletions
diff --git a/mullvad-cli/src/cmds/proxy.rs b/mullvad-cli/src/cmds/api_access.rs index fa05081f89..921a5da811 100644 --- a/mullvad-cli/src/cmds/proxy.rs +++ b/mullvad-cli/src/cmds/api_access.rs @@ -1,8 +1,8 @@ use anyhow::{anyhow, Result}; use mullvad_management_interface::MullvadProxyClient; -use mullvad_types::api_access_method::{ +use mullvad_types::access_method::{ daemon::{ApiAccessMethodReplace, ApiAccessMethodToggle}, - AccessMethod, ObfuscationProtocol, + AccessMethod, ApiAccessMethod, ObfuscationProtocol, }; use std::net::IpAddr; @@ -10,7 +10,7 @@ use clap::{Args, Subcommand}; use talpid_types::net::openvpn::SHADOWSOCKS_CIPHERS; #[derive(Subcommand, Debug, Clone)] -pub enum Proxy { +pub enum ApiAccess { /// List the configured API proxies List, /// Add a custom API proxy @@ -19,7 +19,7 @@ pub enum Proxy { /// Edit an API proxy Edit(EditCustomCommands), /// Remove an API proxy - Remove(RemoveCustomCommands), + Remove(SelectItem), /// Enable an API proxy Enable(SelectItem), /// Disable an API proxy @@ -27,47 +27,35 @@ pub enum Proxy { /// Test an API proxy Test(SelectItem), /// Force the use of a specific API proxy. + /// + /// Selecting "Mullvad Bridges" respects your current bridge settings. Use(SelectItem), } -impl Proxy { +impl ApiAccess { pub async fn handle(self) -> Result<()> { match self { - Proxy::List => { - //println!("Listing the API access methods: .."); + ApiAccess::List => { Self::list().await?; } - Proxy::Add(cmd) => { - //println!("Adding custom proxy"); + ApiAccess::Add(cmd) => { Self::add(cmd).await?; } - Proxy::Edit(cmd) => { - // Transform human-readable index to 0-based indexing. - let index = Self::zero_to_one_based_index(cmd.index)?; - Self::edit(EditCustomCommands { index, ..cmd }).await? - } - Proxy::Remove(cmd) => { - // Transform human-readable index to 0-based indexing. - let index = Self::zero_to_one_based_index(cmd.index)?; - Self::remove(RemoveCustomCommands { index }).await? - } - Proxy::Enable(cmd) => { - let index = Self::zero_to_one_based_index(cmd.index)?; + ApiAccess::Edit(cmd) => Self::edit(cmd).await?, + ApiAccess::Remove(cmd) => Self::remove(cmd).await?, + ApiAccess::Enable(cmd) => { let enabled = true; - Self::toggle(index, enabled).await?; + Self::toggle(cmd, enabled).await?; } - Proxy::Disable(cmd) => { - let index = Self::zero_to_one_based_index(cmd.index)?; + ApiAccess::Disable(cmd) => { let enabled = false; - Self::toggle(index, enabled).await?; + Self::toggle(cmd, enabled).await?; } - Proxy::Test(cmd) => { - let index = Self::zero_to_one_based_index(cmd.index)?; - Self::test(index).await?; + ApiAccess::Test(cmd) => { + Self::test(cmd).await?; } - Proxy::Use(cmd) => { - let index = Self::zero_to_one_based_index(cmd.index)?; - Self::set(index).await?; + ApiAccess::Use(cmd) => { + Self::set(cmd).await?; } }; Ok(()) @@ -75,13 +63,12 @@ impl Proxy { /// Show all API access methods. async fn list() -> Result<()> { - use crate::cmds::proxy::pp::AccessMethodFormatter; let mut rpc = MullvadProxyClient::new().await?; for (index, api_access_method) in rpc.get_api_access_methods().await?.iter().enumerate() { println!( "{}. {}", index + 1, - AccessMethodFormatter::new(&api_access_method) + pp::ApiAccessMethodFormatter::new(api_access_method) ); } Ok(()) @@ -90,23 +77,15 @@ impl Proxy { /// Add a custom API access method. async fn add(cmd: AddCustomCommands) -> Result<()> { let mut rpc = MullvadProxyClient::new().await?; - let proxy = AccessMethod::try_from(cmd.clone())?; + let proxy = ApiAccessMethod::try_from(cmd)?; rpc.add_access_method(proxy).await?; Ok(()) } /// Remove an API access method. - async fn remove(cmd: RemoveCustomCommands) -> Result<()> { + async fn remove(cmd: SelectItem) -> Result<()> { let mut rpc = MullvadProxyClient::new().await?; - let access_method = rpc - .get_api_access_methods() - .await? - .get(cmd.index) - .ok_or(anyhow!(format!( - "Access method {} does not exist", - cmd.index + 1 - )))? - .clone(); + let access_method = Self::get_access_method(&mut rpc, &cmd).await?; rpc.remove_access_method(access_method) .await .map_err(Into::<anyhow::Error>::into) @@ -115,67 +94,65 @@ impl Proxy { /// Edit the data of an API access method. async fn edit(cmd: EditCustomCommands) -> Result<()> { let mut rpc = MullvadProxyClient::new().await?; - // Retrieve the access method to edit - let access_method = rpc - .get_api_access_methods() - .await? - .get(cmd.index) - .ok_or(anyhow!(format!( - "Access method {} does not exist", - cmd.index + 1 - )))? - .clone(); + let api_access_method = Self::get_access_method(&mut rpc, &cmd.item).await?; + let access_method = api_access_method + .as_custom() + .cloned() + .ok_or(anyhow!("Can not edit built-in access method"))?; // Create a new access method combining the new params with the previous values - let access_method = match access_method { - AccessMethod::BuiltIn(_) => Err(anyhow!("Can not edit built-in access method")), - AccessMethod::Custom(custom_access_method) => Ok(custom_access_method), - }?; - - let edited_access_method: AccessMethod = match access_method.access_method { + let edited_access_method: ApiAccessMethod = match access_method.access_method { ObfuscationProtocol::Shadowsocks(shadowsocks) => { let ip = cmd.params.ip.unwrap_or(shadowsocks.peer.ip()).to_string(); let port = cmd.params.port.unwrap_or(shadowsocks.peer.port()); let password = cmd.params.password.unwrap_or(shadowsocks.password); let cipher = cmd.params.cipher.unwrap_or(shadowsocks.cipher); - let name = cmd.params.name.unwrap_or(shadowsocks.name); - let enabled = shadowsocks.enabled; - mullvad_types::api_access_method::Shadowsocks::from_args( - ip, port, cipher, password, enabled, name, - ) - .map(|x| x.into()) + let name = cmd.params.name.unwrap_or(api_access_method.name); + let enabled = api_access_method.enabled; + mullvad_types::access_method::Shadowsocks::from_args(ip, port, cipher, password) + .map(|x| ApiAccessMethod { + name, + enabled, + access_method: AccessMethod::from(x), + }) } ObfuscationProtocol::Socks5(socks) => match socks { - mullvad_types::api_access_method::Socks5::Local(local) => { + mullvad_types::access_method::Socks5::Local(local) => { let ip = cmd.params.ip.unwrap_or(local.peer.ip()).to_string(); let port = cmd.params.port.unwrap_or(local.peer.port()); let local_port = cmd.params.local_port.unwrap_or(local.port); - let name = cmd.params.name.unwrap_or(local.name); - let enabled = local.enabled; - mullvad_types::api_access_method::Socks5Local::from_args( - ip, port, local_port, enabled, name, + let name = cmd.params.name.unwrap_or(api_access_method.get_name()); + let enabled = api_access_method.enabled(); + mullvad_types::access_method::Socks5Local::from_args(ip, port, local_port).map( + |x| ApiAccessMethod { + name, + enabled, + access_method: AccessMethod::from(x), + }, ) - .map(|x| x.into()) } - mullvad_types::api_access_method::Socks5::Remote(remote) => { + mullvad_types::access_method::Socks5::Remote(remote) => { let ip = cmd.params.ip.unwrap_or(remote.peer.ip()).to_string(); let port = cmd.params.port.unwrap_or(remote.peer.port()); - let name = cmd.params.name.unwrap_or(remote.name); - let enabled = remote.enabled; - mullvad_types::api_access_method::Socks5Remote::from_args( - ip, port, enabled, name, - ) - .map(|x| x.into()) + let name = cmd.params.name.unwrap_or(api_access_method.get_name()); + let enabled = api_access_method.enabled(); + mullvad_types::access_method::Socks5Remote::from_args(ip, port).map(|x| { + ApiAccessMethod { + name, + enabled, + access_method: AccessMethod::from(x), + } + }) } }, } .ok_or(anyhow!( "Could not edit access method {}, reverting changes.", - cmd.index + cmd.item ))?; rpc.replace_access_method(ApiAccessMethodReplace { - index: cmd.index, + index: cmd.item.as_array_index()?, access_method: edited_access_method, }) .await?; @@ -184,19 +161,9 @@ impl Proxy { } /// Toggle a custom API access method to be enabled or disabled. - async fn toggle(index: usize, enabled: bool) -> Result<()> { + async fn toggle(item: SelectItem, enabled: bool) -> Result<()> { let mut rpc = MullvadProxyClient::new().await?; - // Retrieve the access method to edit - let access_method = rpc - .get_api_access_methods() - .await? - .get(index) - .ok_or(anyhow!(format!( - "Access method {} does not exist", - index + 1 - )))? - .clone(); - + let access_method = Self::get_access_method(&mut rpc, &item).await?; rpc.toggle_access_method(ApiAccessMethodToggle { access_method, enable: enabled, @@ -206,28 +173,18 @@ impl Proxy { } /// Test an access method to see if it successfully reaches the Mullvad API. - async fn test(index: usize) -> Result<()> { + async fn test(item: SelectItem) -> Result<()> { let mut rpc = MullvadProxyClient::new().await?; - // TODO: Refactor this into some helper function. This code has been copy-pastead a lot already .. - // Step 1. - let access_method = rpc - .get_api_access_methods() - .await? - .get(index) - .ok_or(anyhow!(format!( - "Access method {} does not exist", - index + 1 - )))? - .clone(); - - // Step 2. + let access_method = Self::get_access_method(&mut rpc, &item).await?; + let name = access_method.get_name(); rpc.set_access_method(access_method).await?; - // Step 3. - let api_call = rpc.test_api().await; - // Step 4. - match api_call { - Ok(_) => println!("API call succeeded!"), - Err(_) => println!("API call failed :-("), + // Make the daemon perform an network request which involves talking to the Mullvad API. + match rpc.get_api_addressess().await { + Ok(_) => println!("Connected to the Mullvad API!"), + Err(_) => println!( + "Could *not* connect to the Mullvad API using access method \"{}\"", + name + ), } Ok(()) @@ -236,26 +193,22 @@ impl Proxy { /// Force the use of a specific access method when trying to reach the /// Mullvad API. If this method fails, the daemon will resume the automatic /// roll-over behavior (which is the default). - async fn set(index: usize) -> Result<()> { + async fn set(item: SelectItem) -> Result<()> { let mut rpc = MullvadProxyClient::new().await?; - let access_method = rpc - .get_api_access_methods() - .await? - .get(index) - .ok_or(anyhow!(format!( - "Access method {} does not exist", - index + 1 - )))? - .clone(); - + let access_method = Self::get_access_method(&mut rpc, &item).await?; rpc.set_access_method(access_method).await?; Ok(()) } - fn zero_to_one_based_index(index: usize) -> Result<usize> { - index - .checked_sub(1) - .ok_or(anyhow!("Access method 0 does not exist")) + async fn get_access_method( + rpc: &mut MullvadProxyClient, + item: &SelectItem, + ) -> Result<ApiAccessMethod> { + rpc.get_api_access_methods() + .await? + .get(item.as_array_index()?) + .cloned() + .ok_or(anyhow!(format!("Access method {} does not exist", item))) } } @@ -265,7 +218,7 @@ pub enum AddCustomCommands { #[clap(subcommand)] Socks5(Socks5AddCommands), - /// Configure bundled Shadowsocks proxy + /// Configure Shadowsocks proxy Shadowsocks { /// An easy to remember name for this custom proxy name: String, @@ -283,29 +236,6 @@ pub enum AddCustomCommands { }, } -/// A minimal wrapper type allowing the user to supply a list index to some -/// Access Method. -#[derive(Args, Debug, Clone)] -pub struct SelectItem { - /// Which access method to pick - index: usize, -} - -#[derive(Args, Debug, Clone)] -pub struct EditCustomCommands { - /// Which API proxy to edit - index: usize, - /// Editing parameters - #[clap(flatten)] - params: EditParams, -} - -#[derive(Args, Debug, Clone)] -pub struct RemoveCustomCommands { - /// Which API proxy to remove - index: usize, -} - #[derive(Subcommand, Debug, Clone)] pub enum Socks5AddCommands { /// Configure a local SOCKS5 proxy @@ -327,23 +257,47 @@ pub enum Socks5AddCommands { remote_ip: IpAddr, /// The port of the remote proxy server remote_port: u16, - /// Username for authentication - #[arg(requires = "password")] - username: Option<String>, - /// Password for authentication - #[arg(requires = "username")] - password: Option<String>, }, } +/// A minimal wrapper type allowing the user to supply a list index to some +/// Access Method. +#[derive(Args, Debug, Clone)] +pub struct SelectItem { + /// Which access method to pick + index: usize, +} + +impl SelectItem { + /// Transform human-readable (1-based) index to 0-based indexing. + pub fn as_array_index(&self) -> Result<usize> { + self.index + .checked_sub(1) + .ok_or(anyhow!("Access method 0 does not exist")) + } +} + +impl std::fmt::Display for SelectItem { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.index) + } +} + +#[derive(Args, Debug, Clone)] +pub struct EditCustomCommands { + /// Which API proxy to edit + #[clap(flatten)] + item: SelectItem, + /// Editing parameters + #[clap(flatten)] + params: EditParams, +} + #[derive(Args, Debug, Clone)] pub struct EditParams { /// Name of the API proxy in the Mullvad client [All] #[arg(long)] name: Option<String>, - /// Username for authentication [Shadowsocks] - #[arg(long)] - username: Option<String>, /// Password for authentication [Shadowsocks] #[arg(long)] password: Option<String>, @@ -367,11 +321,11 @@ pub struct EditParams { /// we define them in a hidden-away module. mod conversions { use anyhow::{anyhow, Error}; - use mullvad_types::api_access_method as daemon_types; + use mullvad_types::access_method as daemon_types; use super::{AddCustomCommands, Socks5AddCommands}; - impl TryFrom<AddCustomCommands> for daemon_types::AccessMethod { + impl TryFrom<AddCustomCommands> for daemon_types::ApiAccessMethod { type Error = Error; fn try_from(value: AddCustomCommands) -> Result<Self, Self::Error> { @@ -391,31 +345,33 @@ mod conversions { remote_ip.to_string(), remote_port, local_port, - enabled, - name, ) .ok_or(anyhow!("Could not create a local Socks5 api proxy"))?, ); - socks_proxy.into() + daemon_types::ApiAccessMethod { + name, + enabled, + access_method: daemon_types::AccessMethod::from(socks_proxy), + } } Socks5AddCommands::Remote { remote_ip, remote_port, - username, - password, name, } => { - println!("Adding REMOTE SOCKS5-proxy: {username:?}+{password:?} @ {remote_ip}:{remote_port}"); + println!("Adding REMOTE SOCKS5-proxy: {remote_ip}:{remote_port}"); let socks_proxy = daemon_types::Socks5::Remote( daemon_types::Socks5Remote::from_args( remote_ip.to_string(), remote_port, - enabled, - name, ) .ok_or(anyhow!("Could not create a remote Socks5 api proxy"))?, ); - socks_proxy.into() + daemon_types::ApiAccessMethod { + name, + enabled, + access_method: socks_proxy.into(), + } } }, AddCustomCommands::Shadowsocks { @@ -433,34 +389,37 @@ mod conversions { remote_port, cipher, password, - enabled, - name, ) .ok_or(anyhow!("Could not create a Shadowsocks api proxy"))?; - shadowsocks_proxy.into() + + daemon_types::ApiAccessMethod { + name, + enabled, + access_method: shadowsocks_proxy.into(), + } } }) } } } -/// Pretty printing of [`AccessMethod`]s +/// Pretty printing of [`ApiAccessMethod`]s mod pp { - use mullvad_types::api_access_method::{ - AccessMethod, BuiltInAccessMethod, ObfuscationProtocol, Socks5, + use mullvad_types::access_method::{ + AccessMethod, ApiAccessMethod, ObfuscationProtocol, Socks5, }; - pub struct AccessMethodFormatter<'a> { - access_method: &'a AccessMethod, + pub struct ApiAccessMethodFormatter<'a> { + api_access_method: &'a ApiAccessMethod, } - impl<'a> AccessMethodFormatter<'a> { - pub fn new(access_method: &'a AccessMethod) -> AccessMethodFormatter<'a> { - AccessMethodFormatter { access_method } + impl<'a> ApiAccessMethodFormatter<'a> { + pub fn new(api_access_method: &'a ApiAccessMethod) -> ApiAccessMethodFormatter<'a> { + ApiAccessMethodFormatter { api_access_method } } } - impl<'a> std::fmt::Display for AccessMethodFormatter<'a> { + impl<'a> std::fmt::Display for ApiAccessMethodFormatter<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { use crate::print_option; @@ -472,22 +431,19 @@ mod pp { } }; - match self.access_method { - AccessMethod::BuiltIn(method) => match method { - BuiltInAccessMethod::Direct(enabled) => { - write!(f, "Direct")?; - write_status(f, *enabled) - } - BuiltInAccessMethod::Bridge(enabled) => { - write!(f, "Mullvad Bridges")?; - write_status(f, *enabled) - } - }, + // TODO: For debugging purposes only, remove later + writeln!(f, "{:?}", self.api_access_method)?; + + match &self.api_access_method.access_method { + AccessMethod::BuiltIn(method) => { + write!(f, "{}", method.canonical_name())?; + write_status(f, self.api_access_method.enabled()) + } AccessMethod::Custom(method) => match &method.access_method { ObfuscationProtocol::Shadowsocks(shadowsocks) => { - write!(f, "{}", shadowsocks.name)?; - write_status(f, shadowsocks.enabled)?; - writeln!(f, "")?; + write!(f, "{}", self.api_access_method.get_name())?; + write_status(f, self.api_access_method.enabled())?; + writeln!(f)?; print_option!("Protocol", format!("Shadowsocks [{}]", shadowsocks.cipher)); print_option!("Peer", shadowsocks.peer); print_option!("Password", shadowsocks.password); @@ -495,17 +451,17 @@ mod pp { } ObfuscationProtocol::Socks5(socks) => match socks { Socks5::Remote(remote) => { - write!(f, "{}", remote.name)?; - write_status(f, remote.enabled)?; - writeln!(f, "")?; + write!(f, "{}", self.api_access_method.get_name())?; + write_status(f, self.api_access_method.enabled())?; + writeln!(f)?; print_option!("Protocol", "Socks5"); print_option!("Peer", remote.peer); Ok(()) } Socks5::Local(local) => { - write!(f, "{}", local.name)?; - write_status(f, local.enabled)?; - writeln!(f, "")?; + write!(f, "{}", self.api_access_method.get_name())?; + write_status(f, self.api_access_method.enabled())?; + writeln!(f)?; print_option!("Protocol", "Socks5 (local)"); print_option!("Peer", local.peer); print_option!("Local port", local.port); diff --git a/mullvad-cli/src/cmds/mod.rs b/mullvad-cli/src/cmds/mod.rs index cf715c9e9f..88e4184f07 100644 --- a/mullvad-cli/src/cmds/mod.rs +++ b/mullvad-cli/src/cmds/mod.rs @@ -2,6 +2,7 @@ use clap::builder::{PossibleValuesParser, TypedValueParser, ValueParser}; use std::ops::Deref; pub mod account; +pub mod api_access; pub mod auto_connect; pub mod beta_program; pub mod bridge; @@ -10,7 +11,6 @@ pub mod dns; pub mod lan; pub mod lockdown; pub mod obfuscation; -pub mod proxy; pub mod relay; pub mod relay_constraints; pub mod reset; diff --git a/mullvad-cli/src/main.rs b/mullvad-cli/src/main.rs index 057eb20dea..27855ded69 100644 --- a/mullvad-cli/src/main.rs +++ b/mullvad-cli/src/main.rs @@ -71,11 +71,11 @@ enum Cli { #[clap(subcommand)] Relay(relay::Relay), - /// Manage use of proxies (SOCKS proxies and Shadowsocks) for reaching the API. + /// Manage use of proxies for reaching the Mullvad API. /// Can make the daemon connect to the the Mullvad API via one of the - /// Mullvad bridge servers or a custom proxy. + /// Mullvad bridge servers or a custom proxy (SOCKS5 & Shadowsocks). #[clap(subcommand)] - Proxy(proxy::Proxy), + ApiAccess(api_access::ApiAccess), /// Manage use of obfuscation protocols for WireGuard. /// Can make WireGuard traffic look like something else on the network. @@ -140,7 +140,7 @@ async fn main() -> Result<()> { Cli::Dns(cmd) => cmd.handle().await, Cli::Lan(cmd) => cmd.handle().await, Cli::Obfuscation(cmd) => cmd.handle().await, - Cli::Proxy(cmd) => cmd.handle().await, + Cli::ApiAccess(cmd) => cmd.handle().await, Cli::Version => version::print().await, Cli::FactoryReset => reset::handle().await, Cli::Relay(cmd) => cmd.handle().await, |
