summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorMarkus Pettersson <markus.pettersson@mullvad.net>2023-09-20 15:36:01 +0200
committerDavid Lönnhager <david.l@mullvad.net>2023-10-09 14:40:08 +0200
commit43cb757d2cbb396a627fb6b970394a7b73d37dc5 (patch)
tree084fcd0a9152d50242ed1934fc5623efe8a0052d
parent7fcaad31643ca324c5dd4a17ddf0f445ac679384 (diff)
downloadmullvadvpn-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`.
-rw-r--r--Cargo.lock1
-rw-r--r--mullvad-api/src/https_client_with_sni.rs47
-rw-r--r--mullvad-api/src/proxy.rs16
-rw-r--r--mullvad-cli/Cargo.toml1
-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.rs2
-rw-r--r--mullvad-cli/src/main.rs8
-rw-r--r--mullvad-daemon/src/access_method.rs (renamed from mullvad-daemon/src/access_methods.rs)58
-rw-r--r--mullvad-daemon/src/api.rs152
-rw-r--r--mullvad-daemon/src/lib.rs46
-rw-r--r--mullvad-daemon/src/management_interface.rs83
-rw-r--r--mullvad-management-interface/proto/management_interface.proto43
-rw-r--r--mullvad-management-interface/src/client.rs26
-rw-r--r--mullvad-management-interface/src/types/conversions/api_access_method.rs304
-rw-r--r--mullvad-management-interface/src/types/conversions/settings.rs2
-rw-r--r--mullvad-types/src/access_method.rs311
-rw-r--r--mullvad-types/src/api_access_method.rs314
-rw-r--r--mullvad-types/src/lib.rs2
-rw-r--r--mullvad-types/src/settings/mod.rs6
-rw-r--r--talpid-types/src/net/openvpn.rs15
20 files changed, 891 insertions, 910 deletions
diff --git a/Cargo.lock b/Cargo.lock
index be316f8e51..b3b830e0ce 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1819,7 +1819,6 @@ dependencies = [
"env_logger 0.10.0",
"futures",
"itertools",
- "mullvad-api",
"mullvad-management-interface",
"mullvad-types",
"mullvad-version",
diff --git a/mullvad-api/src/https_client_with_sni.rs b/mullvad-api/src/https_client_with_sni.rs
index 76130de185..cc7557a8d2 100644
--- a/mullvad-api/src/https_client_with_sni.rs
+++ b/mullvad-api/src/https_client_with_sni.rs
@@ -84,15 +84,38 @@ impl InnerConnectionMode {
&self,
hostname: &str,
addr: &SocketAddr,
+ #[cfg(target_os = "android")] socket_bypass_tx: Option<mpsc::Sender<SocketBypassRequest>>,
) -> Result<ApiConnection, std::io::Error> {
use InnerConnectionMode::*;
match self {
- Direct => Self::handle_direct_connection(addr, hostname).await,
+ Direct => {
+ Self::handle_direct_connection(
+ addr,
+ hostname,
+ #[cfg(target_os = "android")]
+ socket_bypass_tx,
+ )
+ .await
+ }
Shadowsocks(config) => {
- Self::handle_shadowsocks_connection(config.clone(), addr, hostname).await
+ Self::handle_shadowsocks_connection(
+ config.clone(),
+ addr,
+ hostname,
+ #[cfg(target_os = "android")]
+ socket_bypass_tx,
+ )
+ .await
}
Socks5(proxy_config) => {
- Self::handle_socks_connection(proxy_config.clone(), addr, hostname).await
+ Self::handle_socks_connection(
+ proxy_config.clone(),
+ addr,
+ hostname,
+ #[cfg(target_os = "android")]
+ socket_bypass_tx,
+ )
+ .await
}
}
}
@@ -101,11 +124,12 @@ impl InnerConnectionMode {
async fn handle_direct_connection(
addr: &SocketAddr,
hostname: &str,
+ #[cfg(target_os = "android")] socket_bypass_tx: Option<mpsc::Sender<SocketBypassRequest>>,
) -> Result<ApiConnection, io::Error> {
let socket = HttpsConnectorWithSni::open_socket(
*addr,
#[cfg(target_os = "android")]
- socket_bypass_tx.clone(),
+ socket_bypass_tx,
)
.await?;
#[cfg(feature = "api-override")]
@@ -122,11 +146,12 @@ impl InnerConnectionMode {
shadowsocks: ShadowsocksConfig,
addr: &SocketAddr,
hostname: &str,
+ #[cfg(target_os = "android")] socket_bypass_tx: Option<mpsc::Sender<SocketBypassRequest>>,
) -> Result<ApiConnection, io::Error> {
let socket = HttpsConnectorWithSni::open_socket(
shadowsocks.params.peer,
#[cfg(target_os = "android")]
- socket_bypass_tx.clone(),
+ socket_bypass_tx,
)
.await?;
let proxy = ProxyClientStream::from_stream(
@@ -150,6 +175,7 @@ impl InnerConnectionMode {
proxy_config: SocksConfig,
addr: &SocketAddr,
hostname: &str,
+ #[cfg(target_os = "android")] socket_bypass_tx: Option<mpsc::Sender<SocketBypassRequest>>,
) -> Result<ApiConnection, io::Error> {
let socket = HttpsConnectorWithSni::open_socket(
proxy_config.peer,
@@ -222,12 +248,12 @@ impl TryFrom<ApiConnectionMode> for InnerConnectionMode {
})
}
ProxyConfig::Socks(config) => match config {
- mullvad_types::api_access_method::Socks5::Local(config) => {
+ mullvad_types::access_method::Socks5::Local(config) => {
InnerConnectionMode::Socks5(SocksConfig {
peer: SocketAddr::new("127.0.0.1".parse().unwrap(), config.port),
})
}
- mullvad_types::api_access_method::Socks5::Remote(config) => {
+ mullvad_types::access_method::Socks5::Remote(config) => {
InnerConnectionMode::Socks5(SocksConfig { peer: config.peer })
}
},
@@ -424,7 +450,12 @@ impl Service<Uri> for HttpsConnectorWithSni {
let stream = loop {
let notify = abort_notify.notified();
let proxy_config = { inner.lock().unwrap().proxy_config.clone() };
- let stream_fut = proxy_config.connect(&hostname, &addr);
+ let stream_fut = proxy_config.connect(
+ &hostname,
+ &addr,
+ #[cfg(target_os = "android")]
+ socket_bypass_tx.clone(),
+ );
pin_mut!(stream_fut);
pin_mut!(notify);
diff --git a/mullvad-api/src/proxy.rs b/mullvad-api/src/proxy.rs
index 186eea2919..44a2309587 100644
--- a/mullvad-api/src/proxy.rs
+++ b/mullvad-api/src/proxy.rs
@@ -1,6 +1,6 @@
use futures::Stream;
use hyper::client::connect::Connected;
-use mullvad_types::api_access_method;
+use mullvad_types::access_method;
use serde::{Deserialize, Serialize};
use std::{
fmt, io,
@@ -36,8 +36,8 @@ impl fmt::Display for ApiConnectionMode {
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
pub enum ProxyConfig {
- Shadowsocks(api_access_method::Shadowsocks),
- Socks(api_access_method::Socks5),
+ Shadowsocks(access_method::Shadowsocks),
+ Socks(access_method::Socks5),
}
impl ProxyConfig {
@@ -46,8 +46,8 @@ impl ProxyConfig {
match self {
ProxyConfig::Shadowsocks(ss) => ss.peer,
ProxyConfig::Socks(socks) => match socks {
- api_access_method::Socks5::Local(s) => s.peer,
- api_access_method::Socks5::Remote(s) => s.peer,
+ access_method::Socks5::Local(s) => s.peer,
+ access_method::Socks5::Remote(s) => s.peer,
},
}
}
@@ -59,10 +59,10 @@ impl fmt::Display for ProxyConfig {
// TODO: Do not hardcode TCP
ProxyConfig::Shadowsocks(ss) => write!(f, "Shadowsocks {}/TCP", ss.peer),
ProxyConfig::Socks(socks) => match socks {
- api_access_method::Socks5::Local(s) => {
- write!(f, "Socks5 localhost:{} => {}/TCP", s.port, s.peer)
+ access_method::Socks5::Local(s) => {
+ write!(f, "Socks5 {}/TCP via localhost:{}", s.peer, s.port)
}
- api_access_method::Socks5::Remote(s) => write!(f, "Socks5 {}/TCP", s.peer),
+ access_method::Socks5::Remote(s) => write!(f, "Socks5 {}/TCP", s.peer),
},
}
}
diff --git a/mullvad-cli/Cargo.toml b/mullvad-cli/Cargo.toml
index fdfa16262d..5437b1980c 100644
--- a/mullvad-cli/Cargo.toml
+++ b/mullvad-cli/Cargo.toml
@@ -23,7 +23,6 @@ natord = "1.0.9"
itertools = "0.10"
mullvad-types = { path = "../mullvad-types", features = ["clap"] }
-mullvad-api = { path = "../mullvad-api" }
mullvad-version = { path = "../mullvad-version" }
talpid-types = { path = "../talpid-types" }
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,
diff --git a/mullvad-daemon/src/access_methods.rs b/mullvad-daemon/src/access_method.rs
index a0c168c026..22a6146e8f 100644
--- a/mullvad-daemon/src/access_methods.rs
+++ b/mullvad-daemon/src/access_method.rs
@@ -2,9 +2,8 @@ use crate::{
settings::{self, MadeChanges},
Daemon, EventListener,
};
-use mullvad_types::api_access_method::{
- daemon::{ApiAccessMethodReplace, ApiAccessMethodToggle},
- AccessMethod, CustomAccessMethod,
+use mullvad_types::access_method::{
+ daemon::ApiAccessMethodReplace, ApiAccessMethod, CustomAccessMethod,
};
#[derive(err_derive::Error, Debug)]
@@ -21,14 +20,9 @@ impl<L> Daemon<L>
where
L: EventListener + Clone + Send + 'static,
{
- pub async fn add_access_method(&mut self, access_method: AccessMethod) -> Result<(), Error> {
+ pub async fn add_access_method(&mut self, access_method: ApiAccessMethod) -> Result<(), Error> {
self.settings
- .update(|settings| {
- settings
- .api_access_methods
- .api_access_methods
- .push(access_method);
- })
+ .update(|settings| settings.api_access_methods.append(access_method))
.await
.map(|did_change| self.notify_on_change(did_change))
.map_err(Error::Settings)
@@ -36,17 +30,15 @@ where
pub async fn toggle_api_access_method(
&mut self,
- access_method_toggle: ApiAccessMethodToggle,
+ api_access_method: ApiAccessMethod,
+ enable: bool,
) -> Result<(), Error> {
self.settings
.update(|settings| {
- if let Some(access_method) = settings
- .api_access_methods
- .api_access_methods
- .iter_mut()
- .find(|access_method| **access_method == access_method_toggle.access_method)
+ if let Some(api_access_method) =
+ settings.api_access_methods.find_mut(&api_access_method)
{
- access_method.toggle(access_method_toggle.enable);
+ api_access_method.toggle(enable);
}
})
.await
@@ -59,13 +51,7 @@ where
access_method: CustomAccessMethod,
) -> Result<(), Error> {
self.settings
- .update(|settings| {
- settings.api_access_methods.api_access_methods.retain(|x| {
- x.as_custom()
- .map(|c| c.id != access_method.id)
- .unwrap_or(true)
- });
- })
+ .update(|settings| settings.api_access_methods.remove(&access_method))
.await
.map(|did_change| self.notify_on_change(did_change))
.map_err(Error::Settings)
@@ -77,8 +63,8 @@ where
) -> Result<(), Error> {
self.settings
.update(|settings| {
- let access_methods = &mut settings.api_access_methods.api_access_methods;
- access_methods.push(access_method_replace.access_method);
+ let access_methods = &mut settings.api_access_methods;
+ access_methods.append(access_method_replace.access_method);
access_methods.swap_remove(access_method_replace.index);
})
.await
@@ -86,15 +72,12 @@ where
.map_err(Error::Settings)
}
- pub async fn set_api_access_method(
- &mut self,
- access_method: AccessMethod,
- ) -> Result<(), Error> {
+ pub fn set_api_access_method(&mut self, access_method: ApiAccessMethod) -> Result<(), Error> {
{
let mut connection_modes = self.connection_modes.lock().unwrap();
- connection_modes.set_access_method(access_method);
+ connection_modes.set_access_method(access_method.access_method);
}
- // Force a rotation of Acces Methods.
+ // Force a rotation of Access Methods.
let _ = self.api_handle.service().next_api_endpoint();
Ok(())
}
@@ -105,10 +88,15 @@ where
self.event_listener
.notify_settings(self.settings.to_settings());
- // TODO: Could this be replaced by message passing? Yes plz.
let mut connection_modes = self.connection_modes.lock().unwrap();
- connection_modes
- .update_access_methods(self.settings.api_access_methods.api_access_methods.clone())
+ connection_modes.update_access_methods(
+ self.settings
+ .api_access_methods
+ .api_access_methods
+ .iter()
+ .map(|x| x.access_method.clone())
+ .collect(),
+ )
};
}
}
diff --git a/mullvad-daemon/src/api.rs b/mullvad-daemon/src/api.rs
index f96dea9484..75b3ad9e47 100644
--- a/mullvad-daemon/src/api.rs
+++ b/mullvad-daemon/src/api.rs
@@ -10,7 +10,7 @@ use mullvad_api::{
ApiEndpointUpdateCallback,
};
use mullvad_relay_selector::RelaySelector;
-use mullvad_types::api_access_method;
+use mullvad_types::access_method::{self, AccessMethod, BuiltInAccessMethod};
use std::{
net::SocketAddr,
path::PathBuf,
@@ -26,78 +26,24 @@ use talpid_types::{
ErrorExt,
};
-/// TODO: Update this comment
/// A stream that returns the next API connection mode to use for reaching the API.
///
-/// When `mullvad-api` fails to contact the API, it requests a new connection mode.
-/// The API can be connected to either directly (i.e., [`ApiConnectionMode::Direct`])
-/// via a bridge ([`ApiConnectionMode::Proxied`]) or via any supported obfuscation protocol ([`ObfuscationProtocol`]).
+/// When `mullvad-api` fails to contact the API, it requests a new connection
+/// mode. The API can be connected to either directly (i.e.,
+/// [`ApiConnectionMode::Direct`]) via a bridge ([`ApiConnectionMode::Proxied`])
+/// or via any supported custom proxy protocol ([`api_access_methods::ObfuscationProtocol`]).
///
-/// * Every 3rd attempt returns [`ApiConnectionMode::Direct`].
-/// * Any other attempt returns a configuration for the bridge that is closest to the selected relay
-/// location and matches all bridge constraints.
-/// * When no matching bridge is found, e.g. if the selected hosting providers don't match any
-/// bridge, [`ApiConnectionMode::Direct`] is returned.
+/// The strategy for determining the next [`ApiConnectionMode`] is handled by
+/// [`ConnectionModesIterator`].
pub struct ApiConnectionModeProvider {
cache_dir: PathBuf,
- /// Used for selecting a Relay when the `Bridges` access method is used.
+ /// Used for selecting a Relay when the `Mullvad Bridges` access method is used.
relay_selector: RelaySelector,
retry_attempt: u32,
current_task: Option<Pin<Box<dyn Future<Output = ApiConnectionMode> + Send>>>,
connection_modes: Arc<Mutex<ConnectionModesIterator>>,
}
-/// An iterator which will always produce an [`AccessMethod`].
-///
-/// Safety: It is always safe to [`unwrap`] after calling [`next`] on a
-/// [`std::iter::Cycle`], so thereby it is safe to always call [`unwrap`] on a
-/// [`ConnectionModesIterator`]
-///
-/// [`unwrap`]: Option::unwrap
-/// [`next`]: std::iter::Iterator::next
-pub struct ConnectionModesIterator {
- available_modes: Box<dyn Iterator<Item = AccessMethod> + Send>,
- next: Option<AccessMethod>,
-}
-
-impl ConnectionModesIterator {
- pub fn new(modes: Vec<AccessMethod>) -> ConnectionModesIterator {
- Self {
- next: None,
- available_modes: Self::get_filtered_access_methods(modes),
- }
- }
-
- /// Set the next [`AccessMethod`] to be returned from this iterator.
- pub fn set_access_method(&mut self, next: AccessMethod) {
- self.next = Some(next);
- }
- /// Update the collection of [`AccessMethod`] which this iterator will
- /// return.
- pub fn update_access_methods(&mut self, access_methods: Vec<AccessMethod>) {
- self.available_modes = Self::get_filtered_access_methods(access_methods);
- }
-
- fn get_filtered_access_methods(
- modes: Vec<AccessMethod>,
- ) -> Box<dyn Iterator<Item = AccessMethod> + Send> {
- Box::new(
- modes
- .into_iter()
- .filter(|access_method| access_method.enabled())
- .cycle(),
- )
- }
-}
-
-impl Iterator for ConnectionModesIterator {
- type Item = AccessMethod;
-
- fn next(&mut self) -> Option<Self::Item> {
- self.next.take().or_else(|| self.available_modes.next())
- }
-}
-
impl Stream for ApiConnectionModeProvider {
type Item = ApiConnectionMode;
@@ -149,16 +95,15 @@ impl ApiConnectionModeProvider {
}
}
+ /// Return a pointer to the underlying iterator over [`AccessMethod`].
+ /// Having access to this iterator allow you to influence , e.g. by calling
+ /// [`ConnectionModesIterator::set_access_method()`] or
+ /// [`ConnectionModesIterator::update_access_methods()`].
pub(crate) fn handle(&self) -> Arc<Mutex<ConnectionModesIterator>> {
self.connection_modes.clone()
}
/// Return a new connection mode to be used for the API connection.
- ///
- /// TODO: Figure out an appropriate algorithm for selecting between the available AccessMethods.
- /// We need to be able to poll the daemon's settings to find out which access methods are available & active.
- /// For now, [`ApiConnectionModeProvider`] is only instanciated once during daemon startup, and does not change it's
- /// available access methods based on any "Settings-changed" events.
fn new_connection_mode(&mut self) -> ApiConnectionMode {
log::debug!("Rotating Access mode!");
let access_method = {
@@ -173,23 +118,22 @@ impl ApiConnectionModeProvider {
/// Ad-hoc version of [`std::convert::From::from`], but since some
/// [`ApiConnectionMode`]s require extra logic/data from
- /// [`ApiConnectionModeProvider`] the standard [`std::convert::From`] trait can not be used.
+ /// [`ApiConnectionModeProvider`] the standard [`std::convert::From`] trait
+ /// can not be implemented.
fn from(&mut self, access_method: &AccessMethod) -> ApiConnectionMode {
match access_method {
AccessMethod::BuiltIn(access_method) => match access_method {
- BuiltInAccessMethod::Direct(_enabled) => ApiConnectionMode::Direct,
- BuiltInAccessMethod::Bridge(enabled) => self
+ BuiltInAccessMethod::Direct => ApiConnectionMode::Direct,
+ BuiltInAccessMethod::Bridge => self
.relay_selector
.get_bridge_forced()
.and_then(|settings| match settings {
ProxySettings::Shadowsocks(ss_settings) => {
- let ss_settings: api_access_method::Shadowsocks =
- api_access_method::Shadowsocks::new(
+ let ss_settings: access_method::Shadowsocks =
+ access_method::Shadowsocks::new(
ss_settings.peer,
ss_settings.cipher,
ss_settings.password,
- enabled,
- "Mullvad Bridges".to_string(), // TODO: Move this to some central location
);
Some(ApiConnectionMode::Proxied(ProxyConfig::Shadowsocks(
ss_settings,
@@ -203,10 +147,10 @@ impl ApiConnectionModeProvider {
.unwrap_or(ApiConnectionMode::Direct),
},
AccessMethod::Custom(access_method) => match &access_method.access_method {
- api_access_method::ObfuscationProtocol::Shadowsocks(shadowsocks_config) => {
+ access_method::ObfuscationProtocol::Shadowsocks(shadowsocks_config) => {
ApiConnectionMode::Proxied(ProxyConfig::Shadowsocks(shadowsocks_config.clone()))
}
- api_access_method::ObfuscationProtocol::Socks5(socks_config) => {
+ access_method::ObfuscationProtocol::Socks5(socks_config) => {
ApiConnectionMode::Proxied(ProxyConfig::Socks(socks_config.clone()))
}
},
@@ -214,6 +158,59 @@ impl ApiConnectionModeProvider {
}
}
+/// An iterator which will always produce an [`AccessMethod`].
+///
+/// Safety: It is always safe to [`unwrap`] after calling [`next`] on a
+/// [`std::iter::Cycle`], so thereby it is safe to always call [`unwrap`] on a
+/// [`ConnectionModesIterator`].
+///
+/// [`unwrap`]: Option::unwrap
+/// [`next`]: std::iter::Iterator::next
+pub struct ConnectionModesIterator {
+ available_modes: Box<dyn Iterator<Item = AccessMethod> + Send>,
+ next: Option<AccessMethod>,
+}
+
+impl ConnectionModesIterator {
+ pub fn new(modes: Vec<AccessMethod>) -> ConnectionModesIterator {
+ Self {
+ next: None,
+ available_modes: Self::get_filtered_access_methods(modes),
+ }
+ }
+
+ /// Set the next [`AccessMethod`] to be returned from this iterator.
+ pub fn set_access_method(&mut self, next: AccessMethod) {
+ self.next = Some(next);
+ }
+ /// Update the collection of [`AccessMethod`] which this iterator will
+ /// return.
+ pub fn update_access_methods(&mut self, api_access_methods: Vec<AccessMethod>) {
+ self.available_modes = Self::get_filtered_access_methods(api_access_methods);
+ }
+
+ /// [`ConnectionModesIterator`] will only consider [`AccessMethod`]s which
+ /// are explicitly marked as enabled. As such, a pre-processing step before
+ /// assigning an iterator to `available_modes` is to filter out all disabled
+ /// [`AccessMethod`]s that may be present in the input.
+ fn get_filtered_access_methods(
+ modes: Vec<AccessMethod>,
+ ) -> Box<dyn Iterator<Item = AccessMethod> + Send> {
+ Box::new(modes
+ .into_iter()
+ // .filter(|access_method| access_method.enabled())
+ .cycle())
+ }
+}
+
+impl Iterator for ConnectionModesIterator {
+ type Item = AccessMethod;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.next.take().or_else(|| self.available_modes.next())
+ }
+}
+
/// Notifies the tunnel state machine that the API (real or proxied) endpoint has
/// changed. [ApiEndpointUpdaterHandle::callback()] creates a callback that may
/// be passed to the `mullvad-api` runtime.
@@ -245,15 +242,14 @@ impl ApiEndpointUpdaterHandle {
log::error!("Rejecting allowed endpoint: Tunnel state machine is not running");
return false;
};
-
let (result_tx, result_rx) = oneshot::channel();
let _ = tunnel_tx.unbounded_send(TunnelCommand::AllowEndpoint(
get_allowed_endpoint(address),
result_tx,
));
+ // Wait for the firewall policy to be updated.
let _ = result_rx.await;
log::debug!("API endpoint: {}", address);
-
true
}
}
diff --git a/mullvad-daemon/src/lib.rs b/mullvad-daemon/src/lib.rs
index ed7bafd007..2cb35cfcf7 100644
--- a/mullvad-daemon/src/lib.rs
+++ b/mullvad-daemon/src/lib.rs
@@ -1,7 +1,7 @@
#![deny(rust_2018_idioms)]
#![recursion_limit = "512"]
-mod access_methods;
+mod access_method;
pub mod account_history;
mod api;
#[cfg(not(target_os = "android"))]
@@ -39,11 +39,11 @@ use mullvad_relay_selector::{
RelaySelector, SelectorConfig,
};
use mullvad_types::{
- account::{AccountData, AccountToken, VoucherSubmission},
- api_access_method::{
+ access_method::{
daemon::{ApiAccessMethodReplace, ApiAccessMethodToggle},
- AccessMethod, CustomAccessMethod,
+ ApiAccessMethod, CustomAccessMethod,
},
+ account::{AccountData, AccountToken, VoucherSubmission},
auth_failed::AuthFailed,
custom_list::CustomList,
device::{Device, DeviceEvent, DeviceEventCause, DeviceId, DeviceState, RemoveDeviceEvent},
@@ -176,7 +176,7 @@ pub enum Error {
CustomListNotFound,
#[error(display = "Access method error")]
- AccessMethodError(#[error(source)] access_methods::Error),
+ AccessMethodError(#[error(source)] access_method::Error),
#[cfg(target_os = "macos")]
#[error(display = "Failed to set exclusion group")]
@@ -264,9 +264,9 @@ pub enum DaemonCommand {
/// Update a custom list with a given id
UpdateCustomList(ResponseTx<(), Error>, CustomList),
/// Get API access methods
- GetApiAccessMethods(ResponseTx<Vec<AccessMethod>, Error>),
+ GetApiAccessMethods(ResponseTx<Vec<ApiAccessMethod>, Error>),
/// Add API access methods
- AddApiAccessMethod(ResponseTx<(), Error>, AccessMethod),
+ AddApiAccessMethod(ResponseTx<(), Error>, ApiAccessMethod),
/// Remove an API access method
RemoveApiAccessMethod(ResponseTx<(), Error>, CustomAccessMethod),
/// Edit an API access method
@@ -274,7 +274,7 @@ pub enum DaemonCommand {
/// Toggle the status of an API access method
ToggleApiAccessMethod(ResponseTx<(), Error>, ApiAccessMethodToggle),
/// Set the API access method to use
- SetApiAccessMethod(ResponseTx<(), Error>, AccessMethod),
+ SetApiAccessMethod(ResponseTx<(), Error>, ApiAccessMethod),
/// Get the addresses of all known API endpoints
GetApiAddresses(ResponseTx<Vec<std::net::SocketAddr>, Error>),
/// Get information about the currently running and latest app versions
@@ -639,11 +639,15 @@ where
let initial_selector_config = new_selector_config(&settings);
let relay_selector = RelaySelector::new(initial_selector_config, &resource_dir, &cache_dir);
- // TODO: Should ApiConnectionModeProvider be an Actor instead of sharing a datastructure-behind-locks with the daemon with the daemon?
let proxy_provider = api::ApiConnectionModeProvider::new(
cache_dir.clone(),
relay_selector.clone(),
- settings.api_access_methods.api_access_methods.clone(),
+ settings
+ .api_access_methods
+ .api_access_methods
+ .iter()
+ .map(|x| x.access_method.clone())
+ .collect(),
);
let connection_modes = proxy_provider.handle();
@@ -1068,7 +1072,7 @@ where
self.on_replace_api_access_method(tx, method).await
}
ToggleApiAccessMethod(tx, method) => self.on_toggle_api_access_method(tx, method).await,
- SetApiAccessMethod(tx, method) => self.on_set_api_access_method(tx, method).await,
+ SetApiAccessMethod(tx, method) => self.on_set_api_access_method(tx, method),
GetApiAddresses(tx) => self.on_get_api_addresses(tx).await,
IsPerformingPostUpgrade(tx) => self.on_is_performing_post_upgrade(tx),
GetCurrentVersion(tx) => self.on_get_current_version(tx),
@@ -2244,12 +2248,16 @@ where
Self::oneshot_send(tx, result, "update_custom_list response");
}
- fn on_get_api_access_methods(&mut self, tx: ResponseTx<Vec<AccessMethod>, Error>) {
- let result = Ok(self.settings.api_access_methods.api_access_methods.clone());
+ fn on_get_api_access_methods(&mut self, tx: ResponseTx<Vec<ApiAccessMethod>, Error>) {
+ let result = Ok(self.settings.api_access_methods.cloned());
Self::oneshot_send(tx, result, "get_api_access_methods response");
}
- async fn on_add_api_access_method(&mut self, tx: ResponseTx<(), Error>, method: AccessMethod) {
+ async fn on_add_api_access_method(
+ &mut self,
+ tx: ResponseTx<(), Error>,
+ method: ApiAccessMethod,
+ ) {
let result = self
.add_access_method(method)
.await
@@ -2284,19 +2292,21 @@ where
async fn on_toggle_api_access_method(
&mut self,
tx: ResponseTx<(), Error>,
- method: ApiAccessMethodToggle,
+ access_method_toggle: ApiAccessMethodToggle,
) {
let result = self
- .toggle_api_access_method(method)
+ .toggle_api_access_method(
+ access_method_toggle.access_method,
+ access_method_toggle.enable,
+ )
.await
.map_err(Error::AccessMethodError);
Self::oneshot_send(tx, result, "toggle_api_access_method response");
}
- async fn on_set_api_access_method(&mut self, tx: ResponseTx<(), Error>, method: AccessMethod) {
+ fn on_set_api_access_method(&mut self, tx: ResponseTx<(), Error>, method: ApiAccessMethod) {
let result = self
.set_api_access_method(method)
- .await
.map_err(Error::AccessMethodError);
Self::oneshot_send(tx, result, "set_api_access_method response");
}
diff --git a/mullvad-daemon/src/management_interface.rs b/mullvad-daemon/src/management_interface.rs
index 88ea87056c..19c4e1e412 100644
--- a/mullvad-daemon/src/management_interface.rs
+++ b/mullvad-daemon/src/management_interface.rs
@@ -619,13 +619,88 @@ impl ManagementService for ManagementServiceImpl {
.map_err(map_daemon_error)
}
+ async fn get_api_access_methods(
+ &self,
+ _: Request<()>,
+ ) -> ServiceResult<mullvad_management_interface::types::ApiAccessMethods> {
+ log::debug!("get_api_access_methods");
+ let (tx, rx) = oneshot::channel();
+ self.send_command_to_daemon(DaemonCommand::GetApiAccessMethods(tx))?;
+ self.wait_for_result(rx)
+ .await?
+ .map(From::from)
+ .map(Response::new)
+ .map_err(map_daemon_error)
+ }
+
+ async fn add_api_access_method(
+ &self,
+ request: Request<types::ApiAccessMethod>,
+ ) -> ServiceResult<()> {
+ log::debug!("add_api_access_method");
+ let api_access_method =
+ mullvad_types::access_method::ApiAccessMethod::try_from(request.into_inner())?;
+ let (tx, rx) = oneshot::channel();
+ self.send_command_to_daemon(DaemonCommand::AddApiAccessMethod(tx, api_access_method))?;
+ self.wait_for_result(rx)
+ .await?
+ .map(Response::new)
+ .map_err(map_daemon_error)
+ }
+
+ async fn remove_api_access_method(
+ &self,
+ request: Request<types::ApiAccessMethod>,
+ ) -> ServiceResult<()> {
+ log::debug!("remove_api_access_method");
+ let api_access_method =
+ mullvad_types::access_method::ApiAccessMethod::try_from(request.into_inner())?;
+
+ match api_access_method.access_method.as_custom() {
+ None => Err(Status::not_found(
+ "Can not remove built-in API access method",
+ )),
+ Some(access_method) => {
+ let (tx, rx) = oneshot::channel();
+ self.send_command_to_daemon(DaemonCommand::RemoveApiAccessMethod(
+ tx,
+ access_method.clone(),
+ ))?;
+ self.wait_for_result(rx)
+ .await?
+ .map(Response::new)
+ .map_err(map_daemon_error)
+ }
+ }
+ }
+
+ async fn replace_api_access_method(
+ &self,
+ request: Request<types::ApiAccessMethodReplace>,
+ ) -> ServiceResult<()> {
+ log::debug!("edit_api_access_method");
+ let access_method_replace =
+ mullvad_types::access_method::daemon::ApiAccessMethodReplace::try_from(
+ request.into_inner(),
+ )?;
+ let (tx, rx) = oneshot::channel();
+ self.send_command_to_daemon(DaemonCommand::ReplaceApiAccessMethod(
+ tx,
+ access_method_replace,
+ ))?;
+ self.wait_for_result(rx)
+ .await?
+ .map(Response::new)
+ .map_err(map_daemon_error)
+ }
+
async fn toggle_api_access_method(
&self,
request: Request<types::ApiAccessMethodToggle>,
) -> ServiceResult<()> {
log::debug!("toggle_api_access_method");
let access_method_toggle =
- mullvad_types::api_access_method::daemon::ApiAccessMethodToggle::try_from(
+ mullvad_types::access_method::daemon::ApiAccessMethodToggle::try_from(
request.into_inner(),
)?;
let (tx, rx) = oneshot::channel();
@@ -644,10 +719,10 @@ impl ManagementService for ManagementServiceImpl {
request: Request<types::ApiAccessMethod>,
) -> ServiceResult<()> {
log::debug!("set_api_access_method");
- let access_method =
- mullvad_types::api_access_method::AccessMethod::try_from(request.into_inner())?;
+ let api_access_method =
+ mullvad_types::access_method::ApiAccessMethod::try_from(request.into_inner())?;
let (tx, rx) = oneshot::channel();
- self.send_command_to_daemon(DaemonCommand::SetApiAccessMethod(tx, access_method))?;
+ self.send_command_to_daemon(DaemonCommand::SetApiAccessMethod(tx, api_access_method))?;
self.wait_for_result(rx)
.await?
.map(Response::new)
diff --git a/mullvad-management-interface/proto/management_interface.proto b/mullvad-management-interface/proto/management_interface.proto
index 018906cdaf..e923ec1043 100644
--- a/mullvad-management-interface/proto/management_interface.proto
+++ b/mullvad-management-interface/proto/management_interface.proto
@@ -355,43 +355,34 @@ message CustomList {
message CustomListSettings { repeated CustomList custom_lists = 1; }
message ApiAccessMethod {
- message Direct { bool enabled = 1; }
- message Bridges { bool enabled = 1; }
+ message Direct {}
+ message Bridges {}
message Socks5Local {
- bool enabled = 1;
- string name = 2;
string id = 3;
string ip = 4;
uint32 port = 5;
uint32 local_port = 6;
}
message Socks5Remote {
- bool enabled = 1;
- string name = 2;
- string id = 3;
- string ip = 4;
- uint32 port = 5;
- }
- message Socks5 {
- oneof Socks5type {
- Socks5Local local = 1;
- Socks5Remote remote = 2;
- }
+ string id = 1;
+ string ip = 2;
+ uint32 port = 3;
}
message Shadowsocks {
- bool enabled = 1;
- string name = 2;
- string id = 3;
- string ip = 4;
- uint32 port = 5;
- string password = 6;
- string cipher = 7;
+ string id = 1;
+ string ip = 2;
+ uint32 port = 3;
+ string password = 4;
+ string cipher = 5;
}
+ string name = 1;
+ bool enabled = 2;
oneof access_method {
- Direct direct = 1;
- Bridges bridges = 2;
- Socks5 socks5 = 3;
- Shadowsocks shadowsocks = 4;
+ Direct direct = 3;
+ Bridges bridges = 4;
+ Socks5Local socks5local = 5;
+ Socks5Remote socks5remote = 6;
+ Shadowsocks shadowsocks = 7;
}
}
diff --git a/mullvad-management-interface/src/client.rs b/mullvad-management-interface/src/client.rs
index 049f8a2fe3..315e3276fc 100644
--- a/mullvad-management-interface/src/client.rs
+++ b/mullvad-management-interface/src/client.rs
@@ -3,11 +3,11 @@
use crate::types;
use futures::{Stream, StreamExt};
use mullvad_types::{
- account::{AccountData, AccountToken, VoucherSubmission},
- api_access_method::{
+ access_method::{
daemon::{ApiAccessMethodReplace, ApiAccessMethodToggle},
- AccessMethod,
+ ApiAccessMethod,
},
+ account::{AccountData, AccountToken, VoucherSubmission},
custom_list::{CustomList, Id},
device::{Device, DeviceEvent, DeviceId, DeviceState, RemoveDeviceEvent},
location::GeoIpLocation,
@@ -167,7 +167,7 @@ impl MullvadProxyClient {
mullvad_types::relay_list::RelayList::try_from(list).map_err(Error::InvalidResponse)
}
- pub async fn get_api_access_methods(&mut self) -> Result<Vec<AccessMethod>> {
+ pub async fn get_api_access_methods(&mut self) -> Result<Vec<ApiAccessMethod>> {
self.0
.get_api_access_methods(())
.await
@@ -175,13 +175,13 @@ impl MullvadProxyClient {
.into_inner()
.api_access_methods
.into_iter()
- .map(|access_method| {
- AccessMethod::try_from(access_method).map_err(Error::InvalidResponse)
+ .map(|api_access_method| {
+ ApiAccessMethod::try_from(api_access_method).map_err(Error::InvalidResponse)
})
.collect()
}
- pub async fn test_api(&mut self) -> Result<()> {
+ pub async fn get_api_addressess(&mut self) -> Result<()> {
self.0.get_api_addressess(()).await.map_err(Error::Rpc)?;
Ok(())
}
@@ -480,9 +480,9 @@ impl MullvadProxyClient {
Ok(())
}
- pub async fn add_access_method(&mut self, access_method: AccessMethod) -> Result<()> {
+ pub async fn add_access_method(&mut self, api_access_method: ApiAccessMethod) -> Result<()> {
self.0
- .add_api_access_method(types::ApiAccessMethod::from(access_method))
+ .add_api_access_method(types::ApiAccessMethod::from(api_access_method))
.await
.map_err(Error::Rpc)
.map(drop)
@@ -499,9 +499,9 @@ impl MullvadProxyClient {
.map(drop)
}
- pub async fn remove_access_method(&mut self, access_method: AccessMethod) -> Result<()> {
+ pub async fn remove_access_method(&mut self, api_access_method: ApiAccessMethod) -> Result<()> {
self.0
- .remove_api_access_method(types::ApiAccessMethod::from(access_method))
+ .remove_api_access_method(types::ApiAccessMethod::from(api_access_method))
.await
.map_err(Error::Rpc)
.map(drop)
@@ -527,9 +527,9 @@ impl MullvadProxyClient {
/// method "randomly"
///
/// [`ApiConnectionModeProvider`]: mullvad_daemon::api::ApiConnectionModeProvider
- pub async fn set_access_method(&mut self, access_method: AccessMethod) -> Result<()> {
+ pub async fn set_access_method(&mut self, api_access_method: ApiAccessMethod) -> Result<()> {
self.0
- .set_api_access_method(types::ApiAccessMethod::from(access_method))
+ .set_api_access_method(types::ApiAccessMethod::from(api_access_method))
.await
.map_err(Error::Rpc)
.map(drop)
diff --git a/mullvad-management-interface/src/types/conversions/api_access_method.rs b/mullvad-management-interface/src/types/conversions/api_access_method.rs
index 958cbf0564..28859c5013 100644
--- a/mullvad-management-interface/src/types/conversions/api_access_method.rs
+++ b/mullvad-management-interface/src/types/conversions/api_access_method.rs
@@ -1,10 +1,12 @@
-/// Implements conversions for the auxilliary proto AccessMethod type to the internal AccessMethod data type.
+/// Implements conversions for the auxilliary
+/// [`crate::types::proto::ApiAccessMethodSettings`] type to the internal
+/// [`mullvad_types::access_method::Settings`] data type.
mod settings {
use crate::types::{proto, FromProtobufTypeError};
- use mullvad_types::api_access_method;
+ use mullvad_types::access_method;
- impl From<&api_access_method::Settings> for proto::ApiAccessMethodSettings {
- fn from(settings: &api_access_method::Settings) -> Self {
+ impl From<&access_method::Settings> for proto::ApiAccessMethodSettings {
+ fn from(settings: &access_method::Settings) -> Self {
Self {
api_access_methods: settings
.api_access_methods
@@ -15,13 +17,13 @@ mod settings {
}
}
- impl From<api_access_method::Settings> for proto::ApiAccessMethodSettings {
- fn from(settings: api_access_method::Settings) -> Self {
+ impl From<access_method::Settings> for proto::ApiAccessMethodSettings {
+ fn from(settings: access_method::Settings) -> Self {
proto::ApiAccessMethodSettings::from(&settings)
}
}
- impl TryFrom<proto::ApiAccessMethodSettings> for api_access_method::Settings {
+ impl TryFrom<proto::ApiAccessMethodSettings> for access_method::Settings {
type Error = FromProtobufTypeError;
fn try_from(settings: proto::ApiAccessMethodSettings) -> Result<Self, Self::Error> {
@@ -29,267 +31,219 @@ mod settings {
api_access_methods: settings
.api_access_methods
.iter()
- .map(api_access_method::AccessMethod::try_from)
- .collect::<Result<Vec<api_access_method::AccessMethod>, _>>()?,
+ .map(access_method::ApiAccessMethod::try_from)
+ .collect::<Result<Vec<access_method::ApiAccessMethod>, _>>()?,
})
}
}
- impl From<api_access_method::daemon::ApiAccessMethodReplace> for proto::ApiAccessMethodReplace {
- fn from(value: api_access_method::daemon::ApiAccessMethodReplace) -> Self {
+ impl From<access_method::daemon::ApiAccessMethodReplace> for proto::ApiAccessMethodReplace {
+ fn from(value: access_method::daemon::ApiAccessMethodReplace) -> Self {
+ let api_access_method = value.access_method;
proto::ApiAccessMethodReplace {
index: value.index as u32,
- access_method: Some(value.access_method.into()),
+ access_method: Some(proto::ApiAccessMethod::from(api_access_method)),
}
}
}
- impl TryFrom<proto::ApiAccessMethodReplace> for api_access_method::daemon::ApiAccessMethodReplace {
+ impl TryFrom<proto::ApiAccessMethodReplace> for access_method::daemon::ApiAccessMethodReplace {
type Error = FromProtobufTypeError;
fn try_from(value: proto::ApiAccessMethodReplace) -> Result<Self, Self::Error> {
- Ok(api_access_method::daemon::ApiAccessMethodReplace {
+ Ok(access_method::daemon::ApiAccessMethodReplace {
index: value.index as usize,
access_method: value
.access_method
.ok_or(FromProtobufTypeError::InvalidArgument(
"Could not convert Access Method from protobuf",
))
- .and_then(TryInto::try_into)?,
+ .and_then(access_method::ApiAccessMethod::try_from)?,
})
}
}
- impl From<api_access_method::daemon::ApiAccessMethodToggle> for proto::ApiAccessMethodToggle {
- fn from(value: api_access_method::daemon::ApiAccessMethodToggle) -> Self {
+ impl From<access_method::daemon::ApiAccessMethodToggle> for proto::ApiAccessMethodToggle {
+ fn from(value: access_method::daemon::ApiAccessMethodToggle) -> Self {
+ let api_access_method = value.access_method;
+ let enabled = api_access_method.enabled();
proto::ApiAccessMethodToggle {
- access_method: Some(value.access_method.into()),
- enable: value.enable,
+ access_method: Some(proto::ApiAccessMethod::from(api_access_method)),
+ enable: enabled,
}
}
}
- impl TryFrom<proto::ApiAccessMethodToggle> for api_access_method::daemon::ApiAccessMethodToggle {
+ impl TryFrom<proto::ApiAccessMethodToggle> for access_method::daemon::ApiAccessMethodToggle {
type Error = FromProtobufTypeError;
fn try_from(value: proto::ApiAccessMethodToggle) -> Result<Self, Self::Error> {
- Ok(api_access_method::daemon::ApiAccessMethodToggle {
+ Ok(access_method::daemon::ApiAccessMethodToggle {
access_method: value
.access_method
.ok_or(FromProtobufTypeError::InvalidArgument(
"Could not convert Access Method from protobuf",
))
- .and_then(TryInto::try_into)?,
+ .and_then(access_method::ApiAccessMethod::try_from)?,
enable: value.enable,
})
}
}
}
-/// Implements conversions for the 'main' AccessMethod data type.
+/// Implements conversions for the auxilliary
+/// [`crate::types::proto::ApiAccessMethod`] type to the internal
+/// [`mullvad_types::access_method::AccessMethod`] data type.
mod data {
- use crate::types::{
- proto::{self, api_access_method::socks5::Socks5type},
- FromProtobufTypeError,
- };
- use mullvad_types::api_access_method::{
- AccessMethod, BuiltInAccessMethod, ObfuscationProtocol, Shadowsocks, Socks5, Socks5Local,
- Socks5Remote,
+ use crate::types::{proto, FromProtobufTypeError};
+ use mullvad_types::access_method::{
+ AccessMethod, ApiAccessMethod, BuiltInAccessMethod, ObfuscationProtocol, Shadowsocks,
+ Socks5, Socks5Local, Socks5Remote,
};
- impl TryFrom<proto::ApiAccessMethods> for Vec<AccessMethod> {
+ impl TryFrom<proto::ApiAccessMethods> for Vec<ApiAccessMethod> {
type Error = FromProtobufTypeError;
fn try_from(value: proto::ApiAccessMethods) -> Result<Self, Self::Error> {
value
.api_access_methods
.iter()
- .map(AccessMethod::try_from)
+ .map(ApiAccessMethod::try_from)
.collect()
}
}
- impl TryFrom<proto::ApiAccessMethod> for AccessMethod {
+ impl TryFrom<proto::ApiAccessMethod> for ApiAccessMethod {
type Error = FromProtobufTypeError;
fn try_from(value: proto::ApiAccessMethod) -> Result<Self, Self::Error> {
+ let name = value.name;
+ let enabled = value.enabled;
let access_method =
value
.access_method
.ok_or(FromProtobufTypeError::InvalidArgument(
- "Could not convert Access Method from protobuf",
+ "Could not deserialize Access Method from protobuf",
))?;
- Ok(match access_method {
- proto::api_access_method::AccessMethod::Socks5(socks) => {
- match socks.socks5type.unwrap() {
- Socks5type::Local(local) => Socks5Local::from_args(
- local.ip,
- local.port as u16,
- local.local_port as u16,
- local.enabled,
- local.name,
- )
- .ok_or(FromProtobufTypeError::InvalidArgument(
- "Could not parse Socks5 (local) message from protobuf",
- ))?
- .into(),
- Socks5type::Remote(remote) => Socks5Remote::from_args(
- remote.ip,
- remote.port as u16,
- remote.enabled,
- remote.name,
- )
- .ok_or({
- FromProtobufTypeError::InvalidArgument(
- "Could not parse Socks5 (remote) message from protobuf",
- )
- })?
- .into(),
- }
+ let x = match access_method {
+ proto::api_access_method::AccessMethod::Direct(
+ proto::api_access_method::Direct {},
+ ) => AccessMethod::from(BuiltInAccessMethod::Direct),
+
+ proto::api_access_method::AccessMethod::Bridges(
+ proto::api_access_method::Bridges {},
+ ) => AccessMethod::from(BuiltInAccessMethod::Bridge),
+ proto::api_access_method::AccessMethod::Socks5local(local) => {
+ let socks = Socks5Local::from_args(
+ local.ip,
+ local.port as u16,
+ local.local_port as u16,
+ )
+ .ok_or(FromProtobufTypeError::InvalidArgument(
+ "Could not parse Socks5 (local) message from protobuf",
+ ))?;
+ AccessMethod::from(socks)
}
- proto::api_access_method::AccessMethod::Shadowsocks(ss) => Shadowsocks::from_args(
- ss.ip,
- ss.port as u16,
- ss.cipher,
- ss.password,
- ss.enabled,
- ss.name,
- )
- .ok_or(FromProtobufTypeError::InvalidArgument(
- "Could not parse Shadowsocks message from protobuf",
- ))?
- .into(),
- proto::api_access_method::AccessMethod::Direct(direct_settings) => {
- BuiltInAccessMethod::Direct(direct_settings.enabled).into()
+
+ proto::api_access_method::AccessMethod::Socks5remote(remote) => {
+ let socks = Socks5Remote::from_args(remote.ip, remote.port as u16).ok_or({
+ FromProtobufTypeError::InvalidArgument(
+ "Could not parse Socks5 (remote) message from protobuf",
+ )
+ })?;
+ AccessMethod::from(socks)
}
- proto::api_access_method::AccessMethod::Bridges(bridge_settings) => {
- BuiltInAccessMethod::Bridge(bridge_settings.enabled).into()
+ proto::api_access_method::AccessMethod::Shadowsocks(ss) => {
+ let socks =
+ Shadowsocks::from_args(ss.ip, ss.port as u16, ss.cipher, ss.password)
+ .ok_or(FromProtobufTypeError::InvalidArgument(
+ "Could not parse Shadowsocks message from protobuf",
+ ))?;
+ AccessMethod::from(socks)
}
+ };
+
+ Ok(ApiAccessMethod {
+ name,
+ enabled,
+ access_method: x,
})
}
}
- impl From<AccessMethod> for proto::ApiAccessMethod {
- fn from(value: AccessMethod) -> Self {
- match value {
+ impl From<ApiAccessMethod> for proto::ApiAccessMethod {
+ fn from(value: ApiAccessMethod) -> Self {
+ let name = value.get_name();
+ let enabled = value.enabled();
+ let access_method = match value.access_method {
AccessMethod::Custom(value) => match value.access_method {
- ObfuscationProtocol::Shadowsocks(ss) => proto::api_access_method::Shadowsocks {
- id: value.id,
- ip: ss.peer.ip().to_string(),
- port: ss.peer.port() as u32,
- password: ss.password,
- cipher: ss.cipher,
- enabled: ss.enabled,
- name: ss.name,
+ ObfuscationProtocol::Shadowsocks(ss) => {
+ proto::api_access_method::AccessMethod::Shadowsocks(
+ proto::api_access_method::Shadowsocks {
+ id: value.id,
+ ip: ss.peer.ip().to_string(),
+ port: ss.peer.port() as u32,
+ password: ss.password,
+ cipher: ss.cipher,
+ },
+ )
}
- .into(),
-
- ObfuscationProtocol::Socks5(Socks5::Local(Socks5Local {
- peer,
- port,
- enabled,
- name,
- })) => proto::api_access_method::Socks5Local {
- id: value.id,
- ip: peer.ip().to_string(),
- port: peer.port() as u32,
- local_port: port as u32,
- enabled,
- name,
+ ObfuscationProtocol::Socks5(Socks5::Local(Socks5Local { peer, port })) => {
+ proto::api_access_method::AccessMethod::Socks5local(
+ proto::api_access_method::Socks5Local {
+ id: value.id,
+ ip: peer.ip().to_string(),
+ port: peer.port() as u32,
+ local_port: port as u32,
+ },
+ )
}
- .into(),
- ObfuscationProtocol::Socks5(Socks5::Remote(Socks5Remote {
- peer,
- enabled,
- name,
- })) => proto::api_access_method::Socks5Remote {
- id: value.id,
- ip: peer.ip().to_string(),
- port: peer.port() as u32,
- enabled,
- name,
+ ObfuscationProtocol::Socks5(Socks5::Remote(Socks5Remote { peer })) => {
+ proto::api_access_method::AccessMethod::Socks5remote(
+ proto::api_access_method::Socks5Remote {
+ id: value.id,
+ ip: peer.ip().to_string(),
+ port: peer.port() as u32,
+ },
+ )
}
- .into(),
},
AccessMethod::BuiltIn(value) => match value {
- mullvad_types::api_access_method::BuiltInAccessMethod::Direct(enabled) => {
- proto::api_access_method::Direct { enabled }.into()
+ mullvad_types::access_method::BuiltInAccessMethod::Direct => {
+ proto::api_access_method::AccessMethod::Direct(
+ proto::api_access_method::Direct {},
+ )
}
- mullvad_types::api_access_method::BuiltInAccessMethod::Bridge(enabled) => {
- proto::api_access_method::Bridges { enabled }.into()
+ mullvad_types::access_method::BuiltInAccessMethod::Bridge => {
+ proto::api_access_method::AccessMethod::Bridges(
+ proto::api_access_method::Bridges {},
+ )
}
},
+ };
+
+ proto::ApiAccessMethod {
+ name,
+ enabled,
+ access_method: Some(access_method),
}
}
}
- impl TryFrom<&proto::ApiAccessMethod> for AccessMethod {
+ impl TryFrom<&proto::ApiAccessMethod> for ApiAccessMethod {
type Error = FromProtobufTypeError;
fn try_from(value: &proto::ApiAccessMethod) -> Result<Self, Self::Error> {
- AccessMethod::try_from(value.clone())
+ ApiAccessMethod::try_from(value.clone())
}
}
- impl From<Vec<AccessMethod>> for proto::ApiAccessMethods {
- fn from(value: Vec<AccessMethod>) -> proto::ApiAccessMethods {
+ impl From<Vec<ApiAccessMethod>> for proto::ApiAccessMethods {
+ fn from(value: Vec<ApiAccessMethod>) -> proto::ApiAccessMethods {
proto::ApiAccessMethods {
api_access_methods: value.iter().map(|method| method.clone().into()).collect(),
}
}
}
-
- impl From<proto::api_access_method::Shadowsocks> for proto::ApiAccessMethod {
- fn from(value: proto::api_access_method::Shadowsocks) -> Self {
- proto::api_access_method::AccessMethod::Shadowsocks(value).into()
- }
- }
-
- impl From<proto::api_access_method::Socks5> for proto::ApiAccessMethod {
- fn from(value: proto::api_access_method::Socks5) -> Self {
- proto::api_access_method::AccessMethod::Socks5(value).into()
- }
- }
-
- impl From<proto::api_access_method::socks5::Socks5type> for proto::ApiAccessMethod {
- fn from(value: proto::api_access_method::socks5::Socks5type) -> Self {
- proto::api_access_method::AccessMethod::Socks5(proto::api_access_method::Socks5 {
- socks5type: Some(value),
- })
- .into()
- }
- }
-
- impl From<proto::api_access_method::Socks5Local> for proto::ApiAccessMethod {
- fn from(value: proto::api_access_method::Socks5Local) -> Self {
- proto::api_access_method::socks5::Socks5type::Local(value).into()
- }
- }
-
- impl From<proto::api_access_method::Socks5Remote> for proto::ApiAccessMethod {
- fn from(value: proto::api_access_method::Socks5Remote) -> Self {
- proto::api_access_method::socks5::Socks5type::Remote(value).into()
- }
- }
-
- impl From<proto::api_access_method::Direct> for proto::ApiAccessMethod {
- fn from(value: proto::api_access_method::Direct) -> Self {
- proto::api_access_method::AccessMethod::Direct(value).into()
- }
- }
-
- impl From<proto::api_access_method::Bridges> for proto::ApiAccessMethod {
- fn from(value: proto::api_access_method::Bridges) -> Self {
- proto::api_access_method::AccessMethod::Bridges(value).into()
- }
- }
-
- impl From<proto::api_access_method::AccessMethod> for proto::ApiAccessMethod {
- fn from(value: proto::api_access_method::AccessMethod) -> Self {
- proto::ApiAccessMethod {
- access_method: Some(value),
- }
- }
- }
}
diff --git a/mullvad-management-interface/src/types/conversions/settings.rs b/mullvad-management-interface/src/types/conversions/settings.rs
index 57694d31f0..98c195d935 100644
--- a/mullvad-management-interface/src/types/conversions/settings.rs
+++ b/mullvad-management-interface/src/types/conversions/settings.rs
@@ -180,7 +180,7 @@ impl TryFrom<proto::Settings> for mullvad_types::settings::Settings {
custom_lists: mullvad_types::custom_list::CustomListsSettings::try_from(
custom_lists_settings,
)?,
- api_access_methods: mullvad_types::api_access_method::Settings::try_from(
+ api_access_methods: mullvad_types::access_method::Settings::try_from(
api_access_methods_settings,
)?,
})
diff --git a/mullvad-types/src/access_method.rs b/mullvad-types/src/access_method.rs
new file mode 100644
index 0000000000..73f51d25b8
--- /dev/null
+++ b/mullvad-types/src/access_method.rs
@@ -0,0 +1,311 @@
+use std::collections::hash_map::DefaultHasher;
+use std::str::FromStr;
+
+use serde::{Deserialize, Serialize};
+use std::hash::{Hash, Hasher};
+use std::net::{IpAddr, Ipv4Addr, SocketAddr, SocketAddrV4};
+
+/// Daemon settings for API access methods.
+#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
+pub struct Settings {
+ pub api_access_methods: Vec<ApiAccessMethod>,
+}
+
+impl Settings {
+ /// Append an [`AccessMethod`] to the end of `api_access_methods`.
+ #[inline(always)]
+ pub fn append(&mut self, api_access_method: ApiAccessMethod) {
+ self.api_access_methods.push(api_access_method)
+ }
+
+ /// Remove a [`CustomAccessMethod`] from `api_access_methods`.
+ #[inline(always)]
+ pub fn remove(&mut self, custom_access_method: &CustomAccessMethod) {
+ self.retain(|api_access_method| {
+ api_access_method
+ .access_method
+ .as_custom()
+ .map(|access_method| access_method.id != custom_access_method.id)
+ .unwrap_or(true)
+ })
+ }
+
+ /// Search for a particular [`AccessMethod`] in `api_access_methods`.
+ ///
+ /// If the [`AccessMethod`] is found to be part of `api_access_methods`, a
+ /// mutable reference to that inner element is returned. Otherwise, `None`
+ /// is returned.
+ #[inline(always)]
+ pub fn find_mut(&mut self, element: &ApiAccessMethod) -> Option<&mut ApiAccessMethod> {
+ self.api_access_methods
+ .iter_mut()
+ .find(|api_access_method| {
+ // TODO: Can probably replace with `element.id == api_access_method.id`
+ element.access_method == api_access_method.access_method
+ })
+ }
+
+ /// Equivalent to [`Vec::retain`].
+ #[inline(always)]
+ pub fn retain<F>(&mut self, f: F)
+ where
+ F: FnMut(&ApiAccessMethod) -> bool,
+ {
+ self.api_access_methods.retain(f)
+ }
+
+ /// Removes an element from `api_access_methods` and returns it.
+ /// The removed element is replaced by the last element of the vector.
+ ///
+ /// Equivalent to [`Vec::swap_remove`].
+ #[inline(always)]
+ pub fn swap_remove(&mut self, index: usize) -> ApiAccessMethod {
+ self.api_access_methods.swap_remove(index)
+ }
+
+ /// Clone the content of `api_access_methods`.
+ #[inline(always)]
+ pub fn cloned(&self) -> Vec<ApiAccessMethod> {
+ self.api_access_methods.clone()
+ }
+}
+
+impl Default for Settings {
+ fn default() -> Self {
+ Self {
+ api_access_methods: vec![BuiltInAccessMethod::Direct, BuiltInAccessMethod::Bridge]
+ .into_iter()
+ .map(|built_in| ApiAccessMethod {
+ name: built_in.canonical_name(),
+ enabled: true,
+ access_method: AccessMethod::from(built_in),
+ })
+ .collect(),
+ }
+ }
+}
+
+/// API Access Method datastructure
+///
+/// Mirrors the protobuf definition
+/// TODO(Create a constructor functions for this struct (?))
+#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+pub struct ApiAccessMethod {
+ pub name: String,
+ pub enabled: bool,
+ pub access_method: AccessMethod,
+}
+
+/// Access Method datastructure.
+#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+pub enum AccessMethod {
+ BuiltIn(BuiltInAccessMethod),
+ Custom(CustomAccessMethod),
+}
+
+impl ApiAccessMethod {
+ pub fn get_name(&self) -> String {
+ self.name.clone()
+ }
+
+ pub fn enabled(&self) -> bool {
+ self.enabled
+ }
+
+ pub fn as_custom(&self) -> Option<&CustomAccessMethod> {
+ self.access_method.as_custom()
+ }
+
+ /// Set an API access method to be either enabled or disabled.
+ pub fn toggle(&mut self, enable: bool) {
+ self.enabled = enable;
+ }
+}
+
+/// Built-In access method datastructure.
+#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+pub enum BuiltInAccessMethod {
+ Direct,
+ Bridge,
+}
+
+/// Custom access method datastructure.
+#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+pub struct CustomAccessMethod {
+ pub id: String,
+ pub access_method: ObfuscationProtocol,
+}
+
+#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
+pub enum ObfuscationProtocol {
+ Shadowsocks(Shadowsocks),
+ Socks5(Socks5),
+}
+
+#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
+pub enum Socks5 {
+ Local(Socks5Local),
+ Remote(Socks5Remote),
+}
+
+#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
+pub struct Shadowsocks {
+ pub peer: SocketAddr,
+ pub password: String,
+ /// One of [`shadowsocks_ciphers`].
+ /// Gets validated at a later stage. Is assumed to be valid.
+ ///
+ /// shadowsocks_ciphers: talpid_types::net::openvpn::SHADOWSOCKS_CIPHERS
+ pub cipher: String,
+}
+
+#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
+pub struct Socks5Local {
+ pub peer: SocketAddr,
+ /// Port on localhost where the SOCKS5-proxy listens to.
+ pub port: u16,
+}
+
+#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
+pub struct Socks5Remote {
+ pub peer: SocketAddr,
+}
+
+impl AccessMethod {
+ pub fn as_custom(&self) -> Option<&CustomAccessMethod> {
+ match self {
+ AccessMethod::BuiltIn(_) => None,
+ AccessMethod::Custom(access_method) => Some(access_method),
+ }
+ }
+}
+
+impl BuiltInAccessMethod {
+ pub fn canonical_name(&self) -> String {
+ match self {
+ BuiltInAccessMethod::Direct => "Direct".to_string(),
+ BuiltInAccessMethod::Bridge => "Mullvad Bridges".to_string(),
+ }
+ }
+}
+
+impl Shadowsocks {
+ pub fn new(peer: SocketAddr, cipher: String, password: String) -> Self {
+ Shadowsocks {
+ peer,
+ password,
+ cipher,
+ }
+ }
+
+ /// Like [new()], but tries to parse `ip` and `port` into a [`std::net::SocketAddr`] for you.
+ /// If `ip` or `port` are valid [`Some(Socks5Local)`] is returned, otherwise [`None`].
+ pub fn from_args(ip: String, port: u16, cipher: String, password: String) -> Option<Self> {
+ let peer = SocketAddrV4::new(Ipv4Addr::from_str(&ip).ok()?, port).into();
+ Some(Self::new(peer, cipher, password))
+ }
+}
+
+impl Socks5Local {
+ pub fn new(peer: SocketAddr, port: u16) -> Self {
+ Self { peer, port }
+ }
+
+ /// Like [new()], but tries to parse `ip` and `port` into a [`std::net::SocketAddr`] for you.
+ /// If `ip` or `port` are valid [`Some(Socks5Local)`] is returned, otherwise [`None`].
+ pub fn from_args(ip: String, port: u16, localport: u16) -> Option<Self> {
+ let peer_ip = IpAddr::V4(Ipv4Addr::from_str(&ip).ok()?);
+ let peer = SocketAddr::new(peer_ip, port);
+ Some(Self::new(peer, localport))
+ }
+}
+
+impl Socks5Remote {
+ pub fn new(peer: SocketAddr) -> Self {
+ Self { peer }
+ }
+
+ /// Like [new()], but tries to parse `ip` and `port` into a [`std::net::SocketAddr`] for you.
+ /// If `ip` or `port` are valid [`Some(Socks5Remote)`] is returned, otherwise [`None`].
+ pub fn from_args(ip: String, port: u16) -> Option<Self> {
+ let peer_ip = IpAddr::V4(Ipv4Addr::from_str(&ip).ok()?);
+ let peer = SocketAddr::new(peer_ip, port);
+ Some(Self::new(peer))
+ }
+}
+
+impl From<BuiltInAccessMethod> for AccessMethod {
+ fn from(value: BuiltInAccessMethod) -> Self {
+ AccessMethod::BuiltIn(value)
+ }
+}
+
+impl From<CustomAccessMethod> for AccessMethod {
+ fn from(value: CustomAccessMethod) -> Self {
+ AccessMethod::Custom(value)
+ }
+}
+
+impl From<ObfuscationProtocol> for AccessMethod {
+ fn from(value: ObfuscationProtocol) -> Self {
+ let mut hasher = DefaultHasher::new();
+ value.hash(&mut hasher);
+ AccessMethod::from(CustomAccessMethod {
+ id: hasher.finish().to_string(),
+ access_method: value,
+ })
+ }
+}
+
+impl From<Shadowsocks> for AccessMethod {
+ fn from(value: Shadowsocks) -> Self {
+ ObfuscationProtocol::Shadowsocks(value).into()
+ }
+}
+
+impl From<Socks5> for AccessMethod {
+ fn from(value: Socks5) -> Self {
+ AccessMethod::from(ObfuscationProtocol::Socks5(value))
+ }
+}
+
+impl From<Socks5Remote> for AccessMethod {
+ fn from(value: Socks5Remote) -> Self {
+ Socks5::Remote(value).into()
+ }
+}
+
+impl From<Socks5Local> for AccessMethod {
+ fn from(value: Socks5Local) -> Self {
+ Socks5::Local(value).into()
+ }
+}
+
+impl From<Socks5Remote> for Socks5 {
+ fn from(value: Socks5Remote) -> Self {
+ Socks5::Remote(value)
+ }
+}
+
+impl From<Socks5Local> for Socks5 {
+ fn from(value: Socks5Local) -> Self {
+ Socks5::Local(value)
+ }
+}
+
+/// Some short-lived datastructure used in some RPC calls to the mullvad daemon.
+pub mod daemon {
+ use super::*;
+ /// Argument to protobuf rpc `ApiAccessMethodReplace`.
+ #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
+ pub struct ApiAccessMethodReplace {
+ pub access_method: ApiAccessMethod,
+ pub index: usize,
+ }
+ /// Argument to protobuf rpc `ApiAccessMethodToggle`.
+ #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
+ pub struct ApiAccessMethodToggle {
+ pub access_method: ApiAccessMethod,
+ pub enable: bool,
+ }
+}
diff --git a/mullvad-types/src/api_access_method.rs b/mullvad-types/src/api_access_method.rs
deleted file mode 100644
index 6aaec7171d..0000000000
--- a/mullvad-types/src/api_access_method.rs
+++ /dev/null
@@ -1,314 +0,0 @@
-use std::collections::hash_map::DefaultHasher;
-use std::str::FromStr;
-
-use serde::{Deserialize, Serialize};
-use std::hash::{Hash, Hasher};
-use std::net::{IpAddr, Ipv4Addr, SocketAddr, SocketAddrV4};
-
-/// Daemon settings for API access methods.
-#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
-pub struct Settings {
- pub api_access_methods: Vec<AccessMethod>,
-}
-
-impl Default for Settings {
- fn default() -> Self {
- Self {
- api_access_methods: vec![
- BuiltInAccessMethod::Direct(true).into(),
- BuiltInAccessMethod::Bridge(true).into(),
- ],
- }
- }
-}
-
-/// Access method datastructure.
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
-pub enum AccessMethod {
- BuiltIn(BuiltInAccessMethod),
- Custom(CustomAccessMethod),
-}
-
-/// Built-In access method datastructure.
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
-pub enum BuiltInAccessMethod {
- Direct(bool),
- Bridge(bool),
-}
-
-/// Custom access method datastructure.
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
-pub struct CustomAccessMethod {
- pub id: String,
- pub access_method: ObfuscationProtocol,
-}
-
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
-pub enum ObfuscationProtocol {
- Shadowsocks(Shadowsocks),
- Socks5(Socks5),
-}
-
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
-pub enum Socks5 {
- Local(Socks5Local),
- Remote(Socks5Remote),
-}
-
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
-pub struct Shadowsocks {
- pub peer: SocketAddr,
- pub password: String, // TODO: Mask the password (using special type)?
- pub cipher: String, // Gets validated at a later stage. Is assumed to be valid.
- pub enabled: bool,
- pub name: String,
-}
-
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
-pub struct Socks5Local {
- pub peer: SocketAddr,
- /// Port on localhost where the SOCKS5-proxy listens to.
- pub port: u16,
- pub enabled: bool,
- pub name: String,
-}
-
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
-pub struct Socks5Remote {
- pub peer: SocketAddr,
- pub enabled: bool,
- pub name: String,
-}
-
-impl Hash for Shadowsocks {
- fn hash<H: Hasher>(&self, state: &mut H) {
- self.peer.hash(state);
- self.password.hash(state);
- self.cipher.hash(state);
- }
-}
-
-impl Hash for Socks5Local {
- fn hash<H: Hasher>(&self, state: &mut H) {
- self.peer.hash(state);
- self.port.hash(state);
- }
-}
-
-impl Hash for Socks5Remote {
- fn hash<H: Hasher>(&self, state: &mut H) {
- self.peer.hash(state);
- }
-}
-
-impl Settings {
- // TODO: Do I have to clone?
- pub fn get_access_methods(&self) -> Vec<AccessMethod> {
- self.api_access_methods.clone()
- }
-}
-
-impl AccessMethod {
- pub fn is_custom(&self) -> bool {
- matches!(self, AccessMethod::Custom(..))
- }
-
- pub fn is_builtin(&self) -> bool {
- matches!(self, AccessMethod::BuiltIn(..))
- }
-
- pub fn as_custom(&self) -> Option<&CustomAccessMethod> {
- match self {
- AccessMethod::BuiltIn(_) => None,
- AccessMethod::Custom(access_method) => Some(access_method),
- }
- }
-
- pub fn enabled(&self) -> bool {
- match self {
- AccessMethod::BuiltIn(method) => match method {
- BuiltInAccessMethod::Direct(enabled) => *enabled,
- BuiltInAccessMethod::Bridge(enabled) => *enabled,
- },
- AccessMethod::Custom(method) => match &method.access_method {
- ObfuscationProtocol::Shadowsocks(ss) => ss.enabled,
- ObfuscationProtocol::Socks5(socks) => match socks {
- Socks5::Local(local) => local.enabled,
- Socks5::Remote(remote) => remote.enabled,
- },
- },
- }
- }
-
- /// Set an access method to be either enabled or disabled.
- ///
- /// This action mutates [`self`].
- pub fn toggle(&mut self, enable: bool) -> () {
- match self {
- AccessMethod::BuiltIn(method) => match method {
- BuiltInAccessMethod::Direct(enabled) => *enabled = enable,
- BuiltInAccessMethod::Bridge(enabled) => *enabled = enable,
- },
- AccessMethod::Custom(method) => match method.access_method {
- ObfuscationProtocol::Shadowsocks(ref mut ss) => ss.enabled = enable,
- ObfuscationProtocol::Socks5(ref mut socks) => match socks {
- Socks5::Local(local) => local.enabled = enable,
- Socks5::Remote(remote) => remote.enabled = enable,
- },
- },
- }
- }
-}
-
-impl Shadowsocks {
- pub fn new(
- peer: SocketAddr,
- cipher: String,
- password: String,
- enabled: bool,
- name: String,
- ) -> Self {
- Shadowsocks {
- peer,
- password,
- cipher,
- enabled,
- name,
- }
- }
-
- /// Like [new()], but tries to parse `ip` and `port` into a [`std::net::SocketAddr`] for you.
- /// If `ip` or `port` are valid [`Some(Socks5Local)`] is returned, otherwise [`None`].
- pub fn from_args(
- ip: String,
- port: u16,
- cipher: String,
- password: String,
- enabled: bool,
- name: String,
- ) -> Option<Self> {
- let peer = SocketAddrV4::new(Ipv4Addr::from_str(&ip).ok()?, port).into();
- Some(Self::new(peer, cipher, password, enabled, name))
- }
-}
-
-impl Socks5Local {
- pub fn new(peer: SocketAddr, port: u16, enabled: bool, name: String) -> Self {
- Self {
- peer,
- port,
- enabled,
- name,
- }
- }
-
- /// Like [new()], but tries to parse `ip` and `port` into a [`std::net::SocketAddr`] for you.
- /// If `ip` or `port` are valid [`Some(Socks5Local)`] is returned, otherwise [`None`].
- pub fn from_args(
- ip: String,
- port: u16,
- localport: u16,
- enabled: bool,
- name: String,
- ) -> Option<Self> {
- let peer_ip = IpAddr::V4(Ipv4Addr::from_str(&ip).ok()?);
- let peer = SocketAddr::new(peer_ip, port);
- Some(Self::new(peer, localport, enabled, name))
- }
-}
-
-impl Socks5Remote {
- pub fn new(peer: SocketAddr, enabled: bool, name: String) -> Self {
- Self {
- peer,
- enabled,
- name,
- }
- }
-
- /// Like [new()], but tries to parse `ip` and `port` into a [`std::net::SocketAddr`] for you.
- /// If `ip` or `port` are valid [`Some(Socks5Remote)`] is returned, otherwise [`None`].
- pub fn from_args(ip: String, port: u16, enabled: bool, name: String) -> Option<Self> {
- let peer_ip = IpAddr::V4(Ipv4Addr::from_str(&ip).ok()?);
- let peer = SocketAddr::new(peer_ip, port);
- Some(Self::new(peer, enabled, name))
- }
-}
-
-impl From<BuiltInAccessMethod> for AccessMethod {
- fn from(value: BuiltInAccessMethod) -> Self {
- AccessMethod::BuiltIn(value)
- }
-}
-
-impl From<CustomAccessMethod> for AccessMethod {
- fn from(value: CustomAccessMethod) -> Self {
- AccessMethod::Custom(value)
- }
-}
-
-impl From<ObfuscationProtocol> for AccessMethod {
- fn from(value: ObfuscationProtocol) -> Self {
- let mut hasher = DefaultHasher::new();
- value.hash(&mut hasher);
- CustomAccessMethod {
- id: hasher.finish().to_string(),
- access_method: value,
- }
- .into()
- }
-}
-
-impl From<Shadowsocks> for AccessMethod {
- fn from(value: Shadowsocks) -> Self {
- ObfuscationProtocol::Shadowsocks(value).into()
- }
-}
-
-impl From<Socks5> for AccessMethod {
- fn from(value: Socks5) -> Self {
- ObfuscationProtocol::Socks5(value).into()
- }
-}
-
-impl From<Socks5Remote> for AccessMethod {
- fn from(value: Socks5Remote) -> Self {
- Socks5::Remote(value).into()
- }
-}
-
-impl From<Socks5Local> for AccessMethod {
- fn from(value: Socks5Local) -> Self {
- Socks5::Local(value).into()
- }
-}
-
-impl From<Socks5Remote> for Socks5 {
- fn from(value: Socks5Remote) -> Self {
- Socks5::Remote(value)
- }
-}
-
-impl From<Socks5Local> for Socks5 {
- fn from(value: Socks5Local) -> Self {
- Socks5::Local(value)
- }
-}
-
-/// These are just extensions to the core [`AccessMethod`] datastructure which the mullvad daemon needs.
-pub mod daemon {
- use super::*;
- /// TODO: Document why this is needed.
- /// Hint: Argument to protobuf rpc `ApiAccessMethodReplace`.
- #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
- pub struct ApiAccessMethodReplace {
- pub index: usize,
- pub access_method: AccessMethod,
- }
- /// TODO: Document why this is needed.
- #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
- pub struct ApiAccessMethodToggle {
- pub access_method: AccessMethod,
- pub enable: bool,
- }
-}
diff --git a/mullvad-types/src/lib.rs b/mullvad-types/src/lib.rs
index 8b5a501663..8aefaeb400 100644
--- a/mullvad-types/src/lib.rs
+++ b/mullvad-types/src/lib.rs
@@ -1,7 +1,7 @@
#![deny(rust_2018_idioms)]
+pub mod access_method;
pub mod account;
-pub mod api_access_method;
pub mod auth_failed;
pub mod custom_list;
pub mod device;
diff --git a/mullvad-types/src/settings/mod.rs b/mullvad-types/src/settings/mod.rs
index 311a154c28..6ade7dea32 100644
--- a/mullvad-types/src/settings/mod.rs
+++ b/mullvad-types/src/settings/mod.rs
@@ -1,5 +1,5 @@
use crate::{
- api_access_method,
+ access_method,
custom_list::CustomListsSettings,
relay_constraints::{
BridgeConstraints, BridgeSettings, BridgeState, Constraint, GeographicLocationConstraint,
@@ -79,7 +79,7 @@ pub struct Settings {
pub custom_lists: CustomListsSettings,
/// API access methods.
#[cfg_attr(target_os = "android", jnix(skip))]
- pub api_access_methods: api_access_method::Settings,
+ pub api_access_methods: access_method::Settings,
/// If the daemon should allow communication with private (LAN) networks.
pub allow_lan: bool,
/// Extra level of kill switch. When this setting is on, the disconnected state will block
@@ -140,7 +140,7 @@ impl Default for Settings {
split_tunnel: SplitTunnelSettings::default(),
settings_version: CURRENT_SETTINGS_VERSION,
custom_lists: CustomListsSettings::default(),
- api_access_methods: api_access_method::Settings::default(),
+ api_access_methods: access_method::Settings::default(),
}
}
}
diff --git a/talpid-types/src/net/openvpn.rs b/talpid-types/src/net/openvpn.rs
index 7dc64ca80c..5968331b52 100644
--- a/talpid-types/src/net/openvpn.rs
+++ b/talpid-types/src/net/openvpn.rs
@@ -132,21 +132,6 @@ impl ShadowsocksProxySettings {
}
}
-/// Options for a bundled SOCKS5 proxy.
-#[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize, Serialize)]
-pub struct SocksProxySettings {
- pub peer: SocketAddr,
-}
-
-impl SocksProxySettings {
- pub fn get_endpoint(&self) -> Endpoint {
- Endpoint {
- address: self.peer,
- protocol: TransportProtocol::Tcp,
- }
- }
-}
-
/// List of ciphers usable by a Shadowsocks proxy.
/// Cf. [`ShadowsocksProxySettings::cipher`].
pub const SHADOWSOCKS_CIPHERS: [&str; 19] = [