summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorDavid Lönnhager <david.l@mullvad.net>2021-04-29 12:30:52 +0200
committerDavid Lönnhager <david.l@mullvad.net>2021-04-29 12:30:52 +0200
commitb45459236d1832e944885963cee37d81033139eb (patch)
tree85877256be72252f95f5374c00abd0bccac5710c
parent6f1427902092012c8e975494bb5f177861d25979 (diff)
parenta726f5d732b12cc3e7aa669b5988233432a4d6cc (diff)
downloadmullvadvpn-b45459236d1832e944885963cee37d81033139eb.tar.xz
mullvadvpn-b45459236d1832e944885963cee37d81033139eb.zip
Merge branch 'improve-proto-conversions'
-rw-r--r--Cargo.lock2
-rw-r--r--mullvad-daemon/src/management_interface.rs942
-rw-r--r--mullvad-daemon/src/relays.rs10
-rw-r--r--mullvad-management-interface/Cargo.toml2
-rw-r--r--mullvad-management-interface/src/lib.rs6
-rw-r--r--mullvad-management-interface/src/types.rs1018
-rw-r--r--mullvad-types/src/relay_constraints.rs2
-rw-r--r--mullvad-types/src/settings/mod.rs4
8 files changed, 1078 insertions, 908 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 66d327ae81..9d3b2f2c53 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1351,10 +1351,12 @@ dependencies = [
"futures",
"lazy_static",
"mullvad-paths",
+ "mullvad-types",
"nix 0.19.1",
"parity-tokio-ipc",
"prost",
"prost-types",
+ "talpid-types",
"tokio",
"tonic",
"tonic-build",
diff --git a/mullvad-daemon/src/management_interface.rs b/mullvad-daemon/src/management_interface.rs
index 05bd38e1dc..a9b07a1214 100644
--- a/mullvad-daemon/src/management_interface.rs
+++ b/mullvad-daemon/src/management_interface.rs
@@ -10,18 +10,12 @@ use mullvad_rpc::{rest::Error as RestError, StatusCode};
use mullvad_types::settings::DnsOptions;
use mullvad_types::{
account::AccountToken,
- location::GeoIpLocation,
- relay_constraints::{
- BridgeConstraints, BridgeSettings, BridgeState, Constraint, LocationConstraint,
- OpenVpnConstraints, Providers, RelayConstraintsUpdate, RelaySettings, RelaySettingsUpdate,
- WireguardConstraints,
- },
- relay_list::{Relay, RelayList, RelayListCountry},
- settings::{Settings, TunnelOptions},
+ relay_constraints::{BridgeSettings, BridgeState, RelaySettingsUpdate},
+ relay_list::RelayList,
+ settings::Settings,
states::{TargetState, TunnelState},
version,
- wireguard::{self, RotationInterval, RotationIntervalError},
- ConnectionConfig,
+ wireguard::{RotationInterval, RotationIntervalError},
};
use parking_lot::RwLock;
use std::{
@@ -30,10 +24,7 @@ use std::{
sync::{mpsc, Arc},
time::Duration,
};
-use talpid_types::{
- net::{IpVersion, TransportProtocol, TunnelType},
- ErrorExt,
-};
+use talpid_types::ErrorExt;
#[derive(err_derive::Error, Debug)]
#[error(no_from)]
@@ -97,7 +88,7 @@ impl ManagementService for ManagementServiceImpl {
let (tx, rx) = oneshot::channel();
self.send_command_to_daemon(DaemonCommand::GetState(tx))?;
let state = self.wait_for_result(rx).await?;
- Ok(Response::new(convert_state(state)))
+ Ok(Response::new(types::TunnelState::from(state)))
}
// Control the daemon and receive events
@@ -157,7 +148,7 @@ impl ManagementService for ManagementServiceImpl {
self.wait_for_result(rx)
.await?
.ok_or(Status::not_found("no version cache"))
- .map(|version_info| convert_version_info(&version_info))
+ .map(types::AppVersionInfo::from)
.map(Response::new)
}
@@ -176,7 +167,12 @@ impl ManagementService for ManagementServiceImpl {
) -> ServiceResult<()> {
log::debug!("update_relay_settings");
let (tx, rx) = oneshot::channel();
- let constraints_update = convert_relay_settings_update(&request.into_inner())?;
+ let constraints_update =
+ RelaySettingsUpdate::try_from(request.into_inner()).map_err(|error| match error {
+ types::FromProtobufTypeError::InvalidArgument(error) => {
+ Status::invalid_argument(error)
+ }
+ })?;
let message = DaemonCommand::UpdateRelaySettings(tx, constraints_update);
self.send_command_to_daemon(message)?;
@@ -200,9 +196,9 @@ impl ManagementService for ManagementServiceImpl {
tokio::sync::mpsc::channel(cmp::max(1, locations.countries.len()));
tokio::spawn(async move {
- for country in &locations.countries {
+ for country in locations.countries.into_iter() {
if let Err(error) = stream_tx
- .send(Ok(convert_relay_list_country(country)))
+ .send(Ok(types::RelayListCountry::from(country)))
.await
{
log::error!(
@@ -222,7 +218,7 @@ impl ManagementService for ManagementServiceImpl {
self.send_command_to_daemon(DaemonCommand::GetCurrentLocation(tx))?;
let result = self.wait_for_result(rx).await?;
match result {
- Some(geoip) => Ok(Response::new(convert_geoip_location(geoip))),
+ Some(geoip) => Ok(Response::new(types::GeoIpLocation::from(geoip))),
None => Err(Status::not_found("no location was found")),
}
}
@@ -231,78 +227,12 @@ impl ManagementService for ManagementServiceImpl {
&self,
request: Request<types::BridgeSettings>,
) -> ServiceResult<()> {
- use talpid_types::net;
- use types::bridge_settings::Type as BridgeSettingType;
-
- let settings = request
- .into_inner()
- .r#type
- .ok_or(Status::invalid_argument("no settings provided"))?;
-
- let settings = match settings {
- BridgeSettingType::Normal(constraints) => {
- let location = match constraints.location {
- None => Constraint::Any,
- Some(location) => convert_proto_location(location),
- };
- let providers = if constraints.providers.is_empty() {
- Constraint::Any
- } else {
- Constraint::Only(
- Providers::new(constraints.providers.clone().into_iter()).map_err(
- |_| Status::invalid_argument("must specify at least one provider"),
- )?,
- )
- };
-
- BridgeSettings::Normal(BridgeConstraints {
- location,
- providers,
- })
- }
- BridgeSettingType::Local(proxy_settings) => {
- let peer = proxy_settings
- .peer
- .parse()
- .map_err(|_| Status::invalid_argument("failed to parse peer address"))?;
- let proxy_settings =
- net::openvpn::ProxySettings::Local(net::openvpn::LocalProxySettings {
- port: proxy_settings.port as u16,
- peer,
- });
- BridgeSettings::Custom(proxy_settings)
- }
- BridgeSettingType::Remote(proxy_settings) => {
- let address = proxy_settings
- .address
- .parse()
- .map_err(|_| Status::invalid_argument("failed to parse IP address"))?;
- let auth = proxy_settings.auth.map(|auth| net::openvpn::ProxyAuth {
- username: auth.username,
- password: auth.password,
- });
- let proxy_settings =
- net::openvpn::ProxySettings::Remote(net::openvpn::RemoteProxySettings {
- address,
- auth,
- });
- BridgeSettings::Custom(proxy_settings)
- }
- BridgeSettingType::Shadowsocks(proxy_settings) => {
- let peer = proxy_settings
- .peer
- .parse()
- .map_err(|_| Status::invalid_argument("failed to parse peer address"))?;
- let proxy_settings = net::openvpn::ProxySettings::Shadowsocks(
- net::openvpn::ShadowsocksProxySettings {
- peer,
- password: proxy_settings.password,
- cipher: proxy_settings.cipher,
- },
- );
- BridgeSettings::Custom(proxy_settings)
- }
- };
+ let settings =
+ BridgeSettings::try_from(request.into_inner()).map_err(|error| match error {
+ types::FromProtobufTypeError::InvalidArgument(error) => {
+ Status::invalid_argument(error)
+ }
+ })?;
log::debug!("set_bridge_settings({:?})", settings);
@@ -315,14 +245,12 @@ impl ManagementService for ManagementServiceImpl {
}
async fn set_bridge_state(&self, request: Request<types::BridgeState>) -> ServiceResult<()> {
- use types::bridge_state::State;
-
- let bridge_state = match State::from_i32(request.into_inner().state) {
- Some(State::Auto) => BridgeState::Auto,
- Some(State::On) => BridgeState::On,
- Some(State::Off) => BridgeState::Off,
- None => return Err(Status::invalid_argument("unknown bridge state")),
- };
+ let bridge_state =
+ BridgeState::try_from(request.into_inner()).map_err(|error| match error {
+ types::FromProtobufTypeError::InvalidArgument(error) => {
+ Status::invalid_argument(error)
+ }
+ })?;
log::debug!("set_bridge_state({:?})", bridge_state);
let (tx, rx) = oneshot::channel();
@@ -342,7 +270,7 @@ impl ManagementService for ManagementServiceImpl {
self.send_command_to_daemon(DaemonCommand::GetSettings(tx))?;
self.wait_for_result(rx)
.await
- .map(|settings| Response::new(convert_settings(&settings)))
+ .map(|settings| Response::new(types::Settings::from(&settings)))
}
async fn set_allow_lan(&self, request: Request<bool>) -> ServiceResult<()> {
@@ -640,7 +568,7 @@ impl ManagementService for ManagementServiceImpl {
self.send_command_to_daemon(DaemonCommand::GenerateWireguardKey(tx))?;
self.wait_for_result(rx)
.await?
- .map(|event| Response::new(convert_wireguard_key_event(&event)))
+ .map(|event| Response::new(types::KeygenEvent::from(event)))
.map_err(map_daemon_error)
}
@@ -650,7 +578,7 @@ impl ManagementService for ManagementServiceImpl {
self.send_command_to_daemon(DaemonCommand::GetWireguardKey(tx))?;
let key = self.wait_for_result(rx).await?.map_err(map_daemon_error)?;
match key {
- Some(key) => Ok(Response::new(convert_public_key(&key))),
+ Some(key) => Ok(Response::new(types::PublicKey::from(key))),
None => Err(Status::not_found("no WireGuard key was found")),
}
}
@@ -761,790 +689,6 @@ impl ManagementServiceImpl {
}
}
-fn convert_settings(settings: &Settings) -> types::Settings {
- types::Settings {
- account_token: settings.get_account_token().unwrap_or_default(),
- relay_settings: Some(convert_relay_settings(&settings.get_relay_settings())),
- bridge_settings: Some(convert_bridge_settings(&settings.bridge_settings)),
- bridge_state: Some(convert_bridge_state(settings.get_bridge_state())),
- allow_lan: settings.allow_lan,
- block_when_disconnected: settings.block_when_disconnected,
- auto_connect: settings.auto_connect,
- tunnel_options: Some(convert_tunnel_options(&settings.tunnel_options)),
- show_beta_releases: settings.show_beta_releases,
- }
-}
-
-fn convert_relay_settings_update(
- settings: &types::RelaySettingsUpdate,
-) -> Result<RelaySettingsUpdate, Status> {
- use mullvad_types::CustomTunnelEndpoint;
- use talpid_types::net::{self, openvpn, wireguard};
- use types::{
- connection_config::Config as ProtoConnectionConfig,
- relay_settings_update::Type as ProtoUpdateType,
- };
-
- let update_value = settings
- .r#type
- .clone()
- .ok_or(Status::invalid_argument("missing relay settings"))?;
-
- match update_value {
- ProtoUpdateType::Custom(settings) => {
- let config = settings
- .config
- .ok_or(Status::invalid_argument("missing relay settings"))?;
- let config = config
- .config
- .ok_or(Status::invalid_argument("missing relay settings"))?;
- let config = match config {
- ProtoConnectionConfig::Openvpn(config) => {
- let address = match config.address.parse() {
- Ok(address) => address,
- Err(_) => return Err(Status::invalid_argument("invalid address")),
- };
-
- ConnectionConfig::OpenVpn(openvpn::ConnectionConfig {
- endpoint: net::Endpoint {
- address,
- protocol: convert_proto_transport_protocol(config.protocol)?,
- },
- username: config.username.clone(),
- password: config.password.clone(),
- })
- }
- ProtoConnectionConfig::Wireguard(config) => {
- let tunnel = config
- .tunnel
- .ok_or(Status::invalid_argument("missing tunnel config"))?;
-
- // Copy the private key to an array
- if tunnel.private_key.len() != 32 {
- return Err(Status::invalid_argument("invalid private key"));
- }
-
- let mut private_key = [0; 32];
- let buffer = &tunnel.private_key[..private_key.len()];
- private_key.copy_from_slice(buffer);
-
- let peer = config
- .peer
- .ok_or(Status::invalid_argument("missing peer config"))?;
-
- // Copy the public key to an array
- if peer.public_key.len() != 32 {
- return Err(Status::invalid_argument("invalid public key"));
- }
-
- let mut public_key = [0; 32];
- let buffer = &peer.public_key[..public_key.len()];
- public_key.copy_from_slice(buffer);
-
- let ipv4_gateway = match config.ipv4_gateway.parse() {
- Ok(address) => address,
- Err(_) => return Err(Status::invalid_argument("invalid IPv4 gateway")),
- };
- let ipv6_gateway = if !config.ipv6_gateway.is_empty() {
- let address = match config.ipv6_gateway.parse() {
- Ok(address) => address,
- Err(_) => return Err(Status::invalid_argument("invalid IPv6 gateway")),
- };
- Some(address)
- } else {
- None
- };
-
- let endpoint = match peer.endpoint.parse() {
- Ok(address) => address,
- Err(_) => return Err(Status::invalid_argument("invalid peer address")),
- };
-
- let mut tunnel_addresses = Vec::new();
- for address in tunnel.addresses {
- let address = address
- .parse()
- .map_err(|_| Status::invalid_argument("invalid address"))?;
- tunnel_addresses.push(address);
- }
-
- let mut allowed_ips = Vec::new();
- for address in peer.allowed_ips {
- let address = address
- .parse()
- .map_err(|_| Status::invalid_argument("invalid address"))?;
- allowed_ips.push(address);
- }
-
- ConnectionConfig::Wireguard(wireguard::ConnectionConfig {
- tunnel: wireguard::TunnelConfig {
- private_key: wireguard::PrivateKey::from(private_key),
- addresses: tunnel_addresses,
- },
- peer: wireguard::PeerConfig {
- public_key: wireguard::PublicKey::from(public_key),
- allowed_ips,
- endpoint,
- protocol: convert_proto_transport_protocol(peer.protocol)?,
- },
- ipv4_gateway,
- ipv6_gateway,
- })
- }
- };
-
- Ok(RelaySettingsUpdate::CustomTunnelEndpoint(
- CustomTunnelEndpoint {
- host: settings.host.clone(),
- config,
- },
- ))
- }
-
- ProtoUpdateType::Normal(settings) => {
- // If `location` isn't provided, no changes are made.
- // If `location` is provided, but is an empty vector,
- // then the constraint is set to `Constraint::Any`.
- let location = settings.location.map(convert_proto_location);
-
- let tunnel_protocol = if let Some(update) = settings.tunnel_type {
- match update.tunnel_type {
- Some(constraint) => match types::TunnelType::from_i32(constraint.tunnel_type) {
- Some(types::TunnelType::Openvpn) => {
- Some(Constraint::Only(TunnelType::OpenVpn))
- }
- Some(types::TunnelType::Wireguard) => {
- Some(Constraint::Only(TunnelType::Wireguard))
- }
- None => return Err(Status::invalid_argument("invalid tunnel protocol")),
- },
- None => Some(Constraint::Any),
- }
- } else {
- None
- };
-
- let transport_protocol = if let Some(ref constraints) = settings.openvpn_constraints {
- match &constraints.protocol {
- Some(constraint) => {
- Some(convert_proto_transport_protocol(constraint.protocol)?)
- }
- None => None,
- }
- } else {
- None
- };
-
- let providers = if let Some(ref provider_update) = settings.providers {
- if !provider_update.providers.is_empty() {
- Some(Constraint::Only(
- Providers::new(provider_update.providers.clone().into_iter()).map_err(
- |_| Status::invalid_argument("must specify at least one provider"),
- )?,
- ))
- } else {
- Some(Constraint::Any)
- }
- } else {
- None
- };
- let ip_version = if let Some(ref constraints) = settings.wireguard_constraints {
- match &constraints.ip_version {
- Some(constraint) => match types::IpVersion::from_i32(constraint.protocol) {
- Some(types::IpVersion::V4) => Some(IpVersion::V4),
- Some(types::IpVersion::V6) => Some(IpVersion::V6),
- None => {
- return Err(Status::invalid_argument("invalid ip protocol version"))
- }
- },
- None => None,
- }
- } else {
- None
- };
-
- Ok(RelaySettingsUpdate::Normal(RelayConstraintsUpdate {
- location,
- providers,
- tunnel_protocol,
- wireguard_constraints: settings.wireguard_constraints.map(|constraints| {
- WireguardConstraints {
- port: if constraints.port != 0 {
- Constraint::Only(constraints.port as u16)
- } else {
- Constraint::Any
- },
- ip_version: Constraint::from(ip_version),
- }
- }),
- openvpn_constraints: settings.openvpn_constraints.map(|constraints| {
- OpenVpnConstraints {
- port: if constraints.port != 0 {
- Constraint::Only(constraints.port as u16)
- } else {
- Constraint::Any
- },
- protocol: Constraint::from(transport_protocol),
- }
- }),
- }))
- }
- }
-}
-
-fn convert_relay_settings(settings: &RelaySettings) -> types::RelaySettings {
- use types::relay_settings;
-
- let endpoint = match settings {
- RelaySettings::CustomTunnelEndpoint(endpoint) => {
- relay_settings::Endpoint::Custom(types::CustomRelaySettings {
- host: endpoint.host.clone(),
- config: Some(convert_connection_config(&endpoint.config)),
- })
- }
- RelaySettings::Normal(constraints) => {
- relay_settings::Endpoint::Normal(types::NormalRelaySettings {
- location: convert_location_constraint(&constraints.location),
- providers: convert_providers_constraint(&constraints.providers),
- tunnel_type: match constraints.tunnel_protocol {
- Constraint::Any => None,
- Constraint::Only(TunnelType::Wireguard) => Some(types::TunnelType::Wireguard),
- Constraint::Only(TunnelType::OpenVpn) => Some(types::TunnelType::Openvpn),
- }
- .map(|tunnel_type| types::TunnelTypeConstraint {
- tunnel_type: i32::from(tunnel_type),
- }),
-
- wireguard_constraints: Some(types::WireguardConstraints {
- port: u32::from(constraints.wireguard_constraints.port.unwrap_or(0)),
- ip_version: constraints
- .wireguard_constraints
- .ip_version
- .option()
- .map(|version| match version {
- IpVersion::V4 => types::IpVersion::V4,
- IpVersion::V6 => types::IpVersion::V6,
- })
- .map(|version| types::IpVersionConstraint {
- protocol: i32::from(version),
- }),
- }),
-
- openvpn_constraints: Some(types::OpenvpnConstraints {
- port: u32::from(constraints.openvpn_constraints.port.unwrap_or(0)),
- protocol: constraints
- .openvpn_constraints
- .protocol
- .as_ref()
- .option()
- .map(|protocol| match protocol {
- TransportProtocol::Tcp => types::TransportProtocol::Tcp,
- TransportProtocol::Udp => types::TransportProtocol::Udp,
- })
- .map(|protocol| types::TransportProtocolConstraint {
- protocol: i32::from(protocol),
- }),
- }),
- })
- }
- };
-
- types::RelaySettings {
- endpoint: Some(endpoint),
- }
-}
-
-fn convert_connection_config(config: &ConnectionConfig) -> types::ConnectionConfig {
- use types::connection_config;
-
- types::ConnectionConfig {
- config: Some(match config {
- ConnectionConfig::OpenVpn(config) => {
- connection_config::Config::Openvpn(connection_config::OpenvpnConfig {
- address: config.endpoint.address.to_string(),
- protocol: match config.endpoint.protocol {
- TransportProtocol::Tcp => i32::from(types::TransportProtocol::Tcp),
- TransportProtocol::Udp => i32::from(types::TransportProtocol::Udp),
- },
- username: config.username.clone(),
- password: config.password.clone(),
- })
- }
- ConnectionConfig::Wireguard(config) => {
- connection_config::Config::Wireguard(connection_config::WireguardConfig {
- tunnel: Some(connection_config::wireguard_config::TunnelConfig {
- private_key: config.tunnel.private_key.to_bytes().to_vec(),
- addresses: config
- .tunnel
- .addresses
- .iter()
- .map(|address| address.to_string())
- .collect(),
- }),
- peer: Some(connection_config::wireguard_config::PeerConfig {
- public_key: config.peer.public_key.as_bytes().to_vec(),
- allowed_ips: config
- .peer
- .allowed_ips
- .iter()
- .map(|address| address.to_string())
- .collect(),
- endpoint: config.peer.endpoint.to_string(),
- protocol: i32::from(match config.peer.protocol {
- TransportProtocol::Udp => types::TransportProtocol::Udp,
- TransportProtocol::Tcp => types::TransportProtocol::Tcp,
- }),
- }),
- ipv4_gateway: config.ipv4_gateway.to_string(),
- ipv6_gateway: config
- .ipv6_gateway
- .as_ref()
- .map(|address| address.to_string())
- .unwrap_or_default(),
- })
- }
- }),
- }
-}
-
-fn convert_bridge_settings(settings: &BridgeSettings) -> types::BridgeSettings {
- use talpid_types::net;
- use types::bridge_settings::{self, Type as BridgeSettingType};
-
- let settings = match settings {
- BridgeSettings::Normal(constraints) => {
- BridgeSettingType::Normal(types::bridge_settings::BridgeConstraints {
- location: convert_location_constraint(&constraints.location),
- providers: convert_providers_constraint(&constraints.providers),
- })
- }
- BridgeSettings::Custom(proxy_settings) => match proxy_settings {
- net::openvpn::ProxySettings::Local(proxy_settings) => {
- BridgeSettingType::Local(bridge_settings::LocalProxySettings {
- port: u32::from(proxy_settings.port),
- peer: proxy_settings.peer.to_string(),
- })
- }
- net::openvpn::ProxySettings::Remote(proxy_settings) => {
- BridgeSettingType::Remote(bridge_settings::RemoteProxySettings {
- address: proxy_settings.address.to_string(),
- auth: proxy_settings.auth.as_ref().map(|auth| {
- bridge_settings::RemoteProxyAuth {
- username: auth.username.clone(),
- password: auth.password.clone(),
- }
- }),
- })
- }
- net::openvpn::ProxySettings::Shadowsocks(proxy_settings) => {
- BridgeSettingType::Shadowsocks(bridge_settings::ShadowsocksProxySettings {
- peer: proxy_settings.peer.to_string(),
- password: proxy_settings.password.clone(),
- cipher: proxy_settings.cipher.clone(),
- })
- }
- },
- };
-
- types::BridgeSettings {
- r#type: Some(settings),
- }
-}
-
-fn convert_wireguard_key_event(
- event: &mullvad_types::wireguard::KeygenEvent,
-) -> types::KeygenEvent {
- use mullvad_types::wireguard::KeygenEvent::*;
- use types::keygen_event::KeygenEvent as ProtoEvent;
-
- types::KeygenEvent {
- event: match event {
- NewKey(_) => i32::from(ProtoEvent::NewKey),
- TooManyKeys => i32::from(ProtoEvent::TooManyKeys),
- GenerationFailure => i32::from(ProtoEvent::GenerationFailure),
- },
- new_key: if let NewKey(key) = event {
- Some(convert_public_key(&key))
- } else {
- None
- },
- }
-}
-
-fn convert_public_key(public_key: &wireguard::PublicKey) -> types::PublicKey {
- types::PublicKey {
- key: public_key.key.as_bytes().to_vec(),
- created: Some(types::Timestamp {
- seconds: public_key.created.timestamp(),
- nanos: 0,
- }),
- }
-}
-
-fn convert_location_constraint(
- location: &Constraint<LocationConstraint>,
-) -> Option<types::RelayLocation> {
- location.as_ref().option().map(|location| match location {
- LocationConstraint::Country(country) => types::RelayLocation {
- country: country.to_string(),
- ..Default::default()
- },
- LocationConstraint::City(country, city) => types::RelayLocation {
- country: country.to_string(),
- city: city.to_string(),
- ..Default::default()
- },
- LocationConstraint::Hostname(country, city, hostname) => types::RelayLocation {
- country: country.to_string(),
- city: city.to_string(),
- hostname: hostname.to_string(),
- },
- })
-}
-
-fn convert_providers_constraint(providers: &Constraint<Providers>) -> Vec<String> {
- match providers.as_ref() {
- Constraint::Any => vec![],
- Constraint::Only(providers) => Vec::from(providers.clone()),
- }
-}
-
-fn convert_bridge_state(state: &BridgeState) -> types::BridgeState {
- let state = match state {
- BridgeState::Auto => types::bridge_state::State::Auto,
- BridgeState::On => types::bridge_state::State::On,
- BridgeState::Off => types::bridge_state::State::Off,
- };
- types::BridgeState {
- state: i32::from(state),
- }
-}
-
-fn convert_tunnel_options(options: &TunnelOptions) -> types::TunnelOptions {
- types::TunnelOptions {
- openvpn: Some(types::tunnel_options::OpenvpnOptions {
- mssfix: u32::from(options.openvpn.mssfix.unwrap_or_default()),
- }),
- wireguard: Some(types::tunnel_options::WireguardOptions {
- mtu: u32::from(options.wireguard.options.mtu.unwrap_or_default()),
- rotation_interval: options
- .wireguard
- .rotation_interval
- .map(|ivl| types::Duration::from(Duration::from(ivl))),
- }),
- generic: Some(types::tunnel_options::GenericOptions {
- enable_ipv6: options.generic.enable_ipv6,
- }),
- #[cfg(not(target_os = "android"))]
- dns_options: Some(types::DnsOptions {
- custom: options.dns_options.custom,
- addresses: options
- .dns_options
- .addresses
- .iter()
- .map(|addr| addr.to_string())
- .collect(),
- }),
- #[cfg(target_os = "android")]
- dns_options: None,
- }
-}
-
-fn convert_relay_list_country(country: &RelayListCountry) -> types::RelayListCountry {
- let mut proto_country = types::RelayListCountry {
- name: country.name.clone(),
- code: country.code.clone(),
- cities: Vec::with_capacity(country.cities.len()),
- };
-
- for city in &country.cities {
- proto_country.cities.push(types::RelayListCity {
- name: city.name.clone(),
- code: city.code.clone(),
- latitude: city.latitude,
- longitude: city.longitude,
- relays: city
- .relays
- .iter()
- .map(|relay| convert_relay(relay))
- .collect(),
- });
- }
-
- proto_country
-}
-
-fn convert_relay(relay: &Relay) -> types::Relay {
- types::Relay {
- hostname: relay.hostname.clone(),
- ipv4_addr_in: relay.ipv4_addr_in.to_string(),
- ipv6_addr_in: relay
- .ipv6_addr_in
- .map(|addr| addr.to_string())
- .unwrap_or_default(),
- include_in_country: relay.include_in_country,
- active: relay.active,
- owned: relay.owned,
- provider: relay.provider.clone(),
- weight: relay.weight,
- tunnels: Some(types::RelayTunnels {
- openvpn: relay
- .tunnels
- .openvpn
- .iter()
- .map(|endpoint| {
- let protocol = match endpoint.protocol {
- TransportProtocol::Udp => types::TransportProtocol::Udp,
- TransportProtocol::Tcp => types::TransportProtocol::Tcp,
- };
- types::OpenVpnEndpointData {
- port: u32::from(endpoint.port),
- protocol: i32::from(protocol),
- }
- })
- .collect(),
- wireguard: relay
- .tunnels
- .wireguard
- .iter()
- .map(|endpoint| {
- let port_ranges = endpoint
- .port_ranges
- .iter()
- .map(|range| types::PortRange {
- first: u32::from(range.0),
- last: u32::from(range.1),
- })
- .collect();
- types::WireguardEndpointData {
- port_ranges,
- ipv4_gateway: endpoint.ipv4_gateway.to_string(),
- ipv6_gateway: endpoint.ipv6_gateway.to_string(),
- public_key: endpoint.public_key.as_bytes().to_vec(),
- }
- })
- .collect(),
- }),
- bridges: Some(types::RelayBridges {
- shadowsocks: relay
- .bridges
- .shadowsocks
- .iter()
- .map(|endpoint| {
- let protocol = match endpoint.protocol {
- TransportProtocol::Udp => types::TransportProtocol::Udp,
- TransportProtocol::Tcp => types::TransportProtocol::Tcp,
- };
- types::ShadowsocksEndpointData {
- port: u32::from(endpoint.port),
- cipher: endpoint.cipher.clone(),
- password: endpoint.password.clone(),
- protocol: i32::from(protocol),
- }
- })
- .collect(),
- }),
- location: relay.location.as_ref().map(|location| types::Location {
- country: location.country.clone(),
- country_code: location.country_code.clone(),
- city: location.city.clone(),
- city_code: location.city_code.clone(),
- latitude: location.latitude,
- longitude: location.longitude,
- }),
- }
-}
-
-fn convert_state(state: TunnelState) -> types::TunnelState {
- use talpid_types::tunnel::{
- ActionAfterDisconnect, ErrorStateCause, FirewallPolicyError, ParameterGenerationError,
- };
- use types::{
- error_state::{
- firewall_policy_error::ErrorType as PolicyErrorType, Cause as ProtoErrorCause,
- FirewallPolicyError as ProtoFirewallPolicyError,
- GenerationError as ProtoGenerationError,
- },
- tunnel_state::{self, State as ProtoState},
- };
- use TunnelState::*;
-
- let map_firewall_error = |firewall_error: &FirewallPolicyError| match firewall_error {
- FirewallPolicyError::Generic => ProtoFirewallPolicyError {
- r#type: i32::from(PolicyErrorType::Generic),
- ..Default::default()
- },
- #[cfg(windows)]
- FirewallPolicyError::Locked(blocking_app) => {
- let (lock_pid, lock_name) = match blocking_app {
- Some(app) => (app.pid, app.name.clone()),
- None => (0, "".to_string()),
- };
-
- ProtoFirewallPolicyError {
- r#type: i32::from(PolicyErrorType::Locked),
- lock_pid,
- lock_name,
- }
- }
- };
-
- let state = match state {
- Disconnected => ProtoState::Disconnected(tunnel_state::Disconnected {}),
- Connecting { endpoint, location } => ProtoState::Connecting(tunnel_state::Connecting {
- relay_info: Some(types::TunnelStateRelayInfo {
- tunnel_endpoint: Some(convert_endpoint(endpoint)),
- location: location.map(convert_geoip_location),
- }),
- }),
- Connected { endpoint, location } => ProtoState::Connected(tunnel_state::Connected {
- relay_info: Some(types::TunnelStateRelayInfo {
- tunnel_endpoint: Some(convert_endpoint(endpoint)),
- location: location.map(convert_geoip_location),
- }),
- }),
- Disconnecting(after_disconnect) => ProtoState::Disconnecting(tunnel_state::Disconnecting {
- after_disconnect: match after_disconnect {
- ActionAfterDisconnect::Nothing => i32::from(types::AfterDisconnect::Nothing),
- ActionAfterDisconnect::Block => i32::from(types::AfterDisconnect::Block),
- ActionAfterDisconnect::Reconnect => i32::from(types::AfterDisconnect::Reconnect),
- },
- }),
- Error(error_state) => ProtoState::Error(tunnel_state::Error {
- error_state: Some(types::ErrorState {
- cause: match error_state.cause() {
- ErrorStateCause::AuthFailed(_) => i32::from(ProtoErrorCause::AuthFailed),
- ErrorStateCause::Ipv6Unavailable => i32::from(ProtoErrorCause::Ipv6Unavailable),
- ErrorStateCause::SetFirewallPolicyError(_) => {
- i32::from(ProtoErrorCause::SetFirewallPolicyError)
- }
- ErrorStateCause::SetDnsError => i32::from(ProtoErrorCause::SetDnsError),
- ErrorStateCause::StartTunnelError => {
- i32::from(ProtoErrorCause::StartTunnelError)
- }
- ErrorStateCause::TunnelParameterError(_) => {
- i32::from(ProtoErrorCause::TunnelParameterError)
- }
- ErrorStateCause::IsOffline => i32::from(ProtoErrorCause::IsOffline),
- #[cfg(target_os = "android")]
- ErrorStateCause::VpnPermissionDenied => {
- i32::from(ProtoErrorCause::VpnPermissionDenied)
- }
- },
- blocking_error: error_state.block_failure().map(map_firewall_error),
- auth_fail_reason: if let ErrorStateCause::AuthFailed(reason) = error_state.cause() {
- reason.clone().unwrap_or_default()
- } else {
- "".to_string()
- },
- parameter_error: if let ErrorStateCause::TunnelParameterError(reason) =
- error_state.cause()
- {
- match reason {
- ParameterGenerationError::NoMatchingRelay => {
- i32::from(ProtoGenerationError::NoMatchingRelay)
- }
- ParameterGenerationError::NoMatchingBridgeRelay => {
- i32::from(ProtoGenerationError::NoMatchingBridgeRelay)
- }
- ParameterGenerationError::NoWireguardKey => {
- i32::from(ProtoGenerationError::NoWireguardKey)
- }
- ParameterGenerationError::CustomTunnelHostResultionError => {
- i32::from(ProtoGenerationError::CustomTunnelHostResolutionError)
- }
- }
- } else {
- 0
- },
- policy_error: if let ErrorStateCause::SetFirewallPolicyError(reason) =
- error_state.cause()
- {
- Some(map_firewall_error(reason))
- } else {
- None
- },
- }),
- }),
- };
-
- types::TunnelState { state: Some(state) }
-}
-
-fn convert_endpoint(endpoint: talpid_types::net::TunnelEndpoint) -> types::TunnelEndpoint {
- use talpid_types::net;
-
- types::TunnelEndpoint {
- address: endpoint.endpoint.address.to_string(),
- protocol: match endpoint.endpoint.protocol {
- TransportProtocol::Tcp => i32::from(types::TransportProtocol::Tcp),
- TransportProtocol::Udp => i32::from(types::TransportProtocol::Udp),
- },
- tunnel_type: match endpoint.tunnel_type {
- net::TunnelType::Wireguard => i32::from(types::TunnelType::Wireguard),
- net::TunnelType::OpenVpn => i32::from(types::TunnelType::Openvpn),
- },
- proxy: endpoint.proxy.map(|proxy_ep| types::ProxyEndpoint {
- address: proxy_ep.endpoint.address.to_string(),
- protocol: match proxy_ep.endpoint.protocol {
- TransportProtocol::Tcp => i32::from(types::TransportProtocol::Tcp),
- TransportProtocol::Udp => i32::from(types::TransportProtocol::Udp),
- },
- proxy_type: match proxy_ep.proxy_type {
- net::proxy::ProxyType::Shadowsocks => i32::from(types::ProxyType::Shadowsocks),
- net::proxy::ProxyType::Custom => i32::from(types::ProxyType::Custom),
- },
- }),
- }
-}
-
-fn convert_geoip_location(geoip: GeoIpLocation) -> types::GeoIpLocation {
- types::GeoIpLocation {
- ipv4: geoip.ipv4.map(|ip| ip.to_string()).unwrap_or_default(),
- ipv6: geoip.ipv6.map(|ip| ip.to_string()).unwrap_or_default(),
- country: geoip.country,
- city: geoip.city.unwrap_or_default(),
- latitude: geoip.latitude,
- longitude: geoip.longitude,
- mullvad_exit_ip: geoip.mullvad_exit_ip,
- hostname: geoip.hostname.unwrap_or_default(),
- bridge_hostname: geoip.bridge_hostname.unwrap_or_default(),
- }
-}
-
-fn convert_version_info(version_info: &version::AppVersionInfo) -> types::AppVersionInfo {
- types::AppVersionInfo {
- supported: version_info.supported,
- latest_stable: version_info.latest_stable.clone(),
- latest_beta: version_info.latest_beta.clone(),
- suggested_upgrade: version_info.suggested_upgrade.clone().unwrap_or_default(),
- }
-}
-
-fn convert_proto_location(location: types::RelayLocation) -> Constraint<LocationConstraint> {
- if !location.hostname.is_empty() {
- Constraint::Only(LocationConstraint::Hostname(
- location.country,
- location.city,
- location.hostname,
- ))
- } else if !location.city.is_empty() {
- Constraint::Only(LocationConstraint::City(location.country, location.city))
- } else if !location.country.is_empty() {
- Constraint::Only(LocationConstraint::Country(location.country))
- } else {
- Constraint::Any
- }
-}
-
-fn convert_proto_transport_protocol(protocol: i32) -> Result<TransportProtocol, Status> {
- match types::TransportProtocol::from_i32(protocol) {
- Some(types::TransportProtocol::Udp) => Ok(TransportProtocol::Udp),
- Some(types::TransportProtocol::Tcp) => Ok(TransportProtocol::Tcp),
- None => Err(Status::invalid_argument("invalid transport protocol")),
- }
-}
-
pub struct ManagementInterfaceServer {
subscriptions: Arc<RwLock<Vec<EventsListenerSender>>>,
socket_path: String,
@@ -1623,7 +767,9 @@ impl EventListener for ManagementInterfaceEventBroadcaster {
/// Sends a new state update to all `new_state` subscribers of the management interface.
fn notify_new_state(&self, new_state: TunnelState) {
self.notify(types::DaemonEvent {
- event: Some(daemon_event::Event::TunnelState(convert_state(new_state))),
+ event: Some(daemon_event::Event::TunnelState(types::TunnelState::from(
+ new_state,
+ ))),
})
}
@@ -1631,7 +777,9 @@ impl EventListener for ManagementInterfaceEventBroadcaster {
fn notify_settings(&self, settings: Settings) {
log::debug!("Broadcasting new settings");
self.notify(types::DaemonEvent {
- event: Some(daemon_event::Event::Settings(convert_settings(&settings))),
+ event: Some(daemon_event::Event::Settings(types::Settings::from(
+ &settings,
+ ))),
})
}
@@ -1642,8 +790,10 @@ impl EventListener for ManagementInterfaceEventBroadcaster {
countries: Vec::new(),
};
new_list.countries.reserve(relay_list.countries.len());
- for country in &relay_list.countries {
- new_list.countries.push(convert_relay_list_country(country));
+ for country in relay_list.countries.into_iter() {
+ new_list
+ .countries
+ .push(types::RelayListCountry::from(country));
}
self.notify(types::DaemonEvent {
event: Some(daemon_event::Event::RelayList(new_list)),
@@ -1652,17 +802,19 @@ impl EventListener for ManagementInterfaceEventBroadcaster {
fn notify_app_version(&self, app_version_info: version::AppVersionInfo) {
log::debug!("Broadcasting new app version info");
- let new_info = convert_version_info(&app_version_info);
self.notify(types::DaemonEvent {
- event: Some(daemon_event::Event::VersionInfo(new_info)),
+ event: Some(daemon_event::Event::VersionInfo(
+ types::AppVersionInfo::from(app_version_info),
+ )),
})
}
fn notify_key_event(&self, key_event: mullvad_types::wireguard::KeygenEvent) {
log::debug!("Broadcasting new wireguard key event");
- let new_event = convert_wireguard_key_event(&key_event);
self.notify(types::DaemonEvent {
- event: Some(daemon_event::Event::KeyEvent(new_event)),
+ event: Some(daemon_event::Event::KeyEvent(types::KeygenEvent::from(
+ key_event,
+ ))),
})
}
}
diff --git a/mullvad-daemon/src/relays.rs b/mullvad-daemon/src/relays.rs
index c029baaa54..54d664b640 100644
--- a/mullvad-daemon/src/relays.rs
+++ b/mullvad-daemon/src/relays.rs
@@ -218,7 +218,7 @@ impl RelaySelector {
pub fn get_tunnel_endpoint(
&mut self,
relay_constraints: &RelayConstraints,
- bridge_state: &BridgeState,
+ bridge_state: BridgeState,
retry_attempt: u32,
wg_key_exists: bool,
) -> Result<(Relay, MullvadEndpoint), Error> {
@@ -250,12 +250,12 @@ impl RelaySelector {
fn preferred_constraints(
&self,
original_constraints: &RelayConstraints,
- bridge_state: &BridgeState,
+ bridge_state: BridgeState,
retry_attempt: u32,
wg_key_exists: bool,
) -> RelayConstraints {
let (preferred_port, preferred_protocol, preferred_tunnel) =
- if *bridge_state != BridgeState::On {
+ if bridge_state != BridgeState::On {
self.preferred_tunnel_constraints(
retry_attempt,
&original_constraints.location,
@@ -277,7 +277,7 @@ impl RelaySelector {
Constraint::Any => {
if original_constraints.openvpn_constraints.port.is_any()
&& original_constraints.openvpn_constraints.protocol.is_any()
- || *bridge_state == BridgeState::On
+ || bridge_state == BridgeState::On
{
relay_constraints.openvpn_constraints = OpenVpnConstraints {
port: preferred_port,
@@ -297,7 +297,7 @@ impl RelaySelector {
Constraint::Only(TunnelType::OpenVpn) => {
let openvpn_constraints = &mut relay_constraints.openvpn_constraints;
*openvpn_constraints = original_constraints.openvpn_constraints;
- if *bridge_state == BridgeState::On && openvpn_constraints.protocol.is_any() {
+ if bridge_state == BridgeState::On && openvpn_constraints.protocol.is_any() {
// FIXME: This is temporary while talpid-core only supports TCP proxies
openvpn_constraints.protocol = Constraint::Only(TransportProtocol::Tcp);
} else if openvpn_constraints.port.is_any() && openvpn_constraints.protocol.is_any()
diff --git a/mullvad-management-interface/Cargo.toml b/mullvad-management-interface/Cargo.toml
index cb28f4b9ed..6b4cce66ac 100644
--- a/mullvad-management-interface/Cargo.toml
+++ b/mullvad-management-interface/Cargo.toml
@@ -9,7 +9,9 @@ publish = false
[dependencies]
err-derive = "0.3.0"
+mullvad-types = { path = "../mullvad-types" }
mullvad-paths = { path = "../mullvad-paths" }
+talpid-types = { path = "../talpid-types" }
tonic = "0.3.1"
tower = "0.3"
prost = "0.6"
diff --git a/mullvad-management-interface/src/lib.rs b/mullvad-management-interface/src/lib.rs
index abf4282923..cc4c266af7 100644
--- a/mullvad-management-interface/src/lib.rs
+++ b/mullvad-management-interface/src/lib.rs
@@ -1,8 +1,4 @@
-pub mod types {
- tonic::include_proto!("mullvad_daemon.management_interface");
-
- pub use prost_types::{Duration, Timestamp};
-}
+pub mod types;
use parity_tokio_ipc::Endpoint as IpcEndpoint;
#[cfg(unix)]
diff --git a/mullvad-management-interface/src/types.rs b/mullvad-management-interface/src/types.rs
new file mode 100644
index 0000000000..753149f35e
--- /dev/null
+++ b/mullvad-management-interface/src/types.rs
@@ -0,0 +1,1018 @@
+pub use prost_types::{Duration, Timestamp};
+
+use mullvad_types::relay_constraints::Constraint;
+use std::convert::TryFrom;
+
+tonic::include_proto!("mullvad_daemon.management_interface");
+
+impl From<mullvad_types::location::GeoIpLocation> for GeoIpLocation {
+ fn from(geoip: mullvad_types::location::GeoIpLocation) -> GeoIpLocation {
+ GeoIpLocation {
+ ipv4: geoip.ipv4.map(|ip| ip.to_string()).unwrap_or_default(),
+ ipv6: geoip.ipv6.map(|ip| ip.to_string()).unwrap_or_default(),
+ country: geoip.country,
+ city: geoip.city.unwrap_or_default(),
+ latitude: geoip.latitude,
+ longitude: geoip.longitude,
+ mullvad_exit_ip: geoip.mullvad_exit_ip,
+ hostname: geoip.hostname.unwrap_or_default(),
+ bridge_hostname: geoip.bridge_hostname.unwrap_or_default(),
+ }
+ }
+}
+
+impl From<talpid_types::net::TunnelEndpoint> for TunnelEndpoint {
+ fn from(endpoint: talpid_types::net::TunnelEndpoint) -> Self {
+ use talpid_types::net;
+
+ TunnelEndpoint {
+ address: endpoint.endpoint.address.to_string(),
+ protocol: i32::from(TransportProtocol::from(endpoint.endpoint.protocol)),
+ tunnel_type: match endpoint.tunnel_type {
+ net::TunnelType::Wireguard => i32::from(TunnelType::Wireguard),
+ net::TunnelType::OpenVpn => i32::from(TunnelType::Openvpn),
+ },
+ proxy: endpoint.proxy.map(|proxy_ep| ProxyEndpoint {
+ address: proxy_ep.endpoint.address.to_string(),
+ protocol: i32::from(TransportProtocol::from(proxy_ep.endpoint.protocol)),
+ proxy_type: match proxy_ep.proxy_type {
+ net::proxy::ProxyType::Shadowsocks => i32::from(ProxyType::Shadowsocks),
+ net::proxy::ProxyType::Custom => i32::from(ProxyType::Custom),
+ },
+ }),
+ }
+ }
+}
+
+impl From<mullvad_types::states::TunnelState> for TunnelState {
+ fn from(state: mullvad_types::states::TunnelState) -> Self {
+ use error_state::{
+ firewall_policy_error::ErrorType as PolicyErrorType, Cause, FirewallPolicyError,
+ GenerationError,
+ };
+ use mullvad_types::states::TunnelState as MullvadTunnelState;
+
+ use talpid_types::tunnel as talpid_tunnel;
+
+ let map_firewall_error =
+ |firewall_error: &talpid_tunnel::FirewallPolicyError| match firewall_error {
+ talpid_tunnel::FirewallPolicyError::Generic => FirewallPolicyError {
+ r#type: i32::from(PolicyErrorType::Generic),
+ ..Default::default()
+ },
+ #[cfg(windows)]
+ talpid_tunnel::FirewallPolicyError::Locked(blocking_app) => {
+ let (lock_pid, lock_name) = match blocking_app {
+ Some(app) => (app.pid, app.name.clone()),
+ None => (0, "".to_string()),
+ };
+
+ FirewallPolicyError {
+ r#type: i32::from(PolicyErrorType::Locked),
+ lock_pid,
+ lock_name,
+ }
+ }
+ };
+
+ let state = match state {
+ MullvadTunnelState::Disconnected => {
+ tunnel_state::State::Disconnected(tunnel_state::Disconnected {})
+ }
+ MullvadTunnelState::Connecting { endpoint, location } => {
+ tunnel_state::State::Connecting(tunnel_state::Connecting {
+ relay_info: Some(TunnelStateRelayInfo {
+ tunnel_endpoint: Some(TunnelEndpoint::from(endpoint)),
+ location: location.map(GeoIpLocation::from),
+ }),
+ })
+ }
+ MullvadTunnelState::Connected { endpoint, location } => {
+ tunnel_state::State::Connected(tunnel_state::Connected {
+ relay_info: Some(TunnelStateRelayInfo {
+ tunnel_endpoint: Some(TunnelEndpoint::from(endpoint)),
+ location: location.map(GeoIpLocation::from),
+ }),
+ })
+ }
+ MullvadTunnelState::Disconnecting(after_disconnect) => {
+ tunnel_state::State::Disconnecting(tunnel_state::Disconnecting {
+ after_disconnect: match after_disconnect {
+ talpid_tunnel::ActionAfterDisconnect::Nothing => {
+ i32::from(AfterDisconnect::Nothing)
+ }
+ talpid_tunnel::ActionAfterDisconnect::Block => {
+ i32::from(AfterDisconnect::Block)
+ }
+ talpid_tunnel::ActionAfterDisconnect::Reconnect => {
+ i32::from(AfterDisconnect::Reconnect)
+ }
+ },
+ })
+ }
+ MullvadTunnelState::Error(error_state) => {
+ tunnel_state::State::Error(tunnel_state::Error {
+ error_state: Some(ErrorState {
+ cause: match error_state.cause() {
+ talpid_tunnel::ErrorStateCause::AuthFailed(_) => {
+ i32::from(Cause::AuthFailed)
+ }
+ talpid_tunnel::ErrorStateCause::Ipv6Unavailable => {
+ i32::from(Cause::Ipv6Unavailable)
+ }
+ talpid_tunnel::ErrorStateCause::SetFirewallPolicyError(_) => {
+ i32::from(Cause::SetFirewallPolicyError)
+ }
+ talpid_tunnel::ErrorStateCause::SetDnsError => {
+ i32::from(Cause::SetDnsError)
+ }
+ talpid_tunnel::ErrorStateCause::StartTunnelError => {
+ i32::from(Cause::StartTunnelError)
+ }
+ talpid_tunnel::ErrorStateCause::TunnelParameterError(_) => {
+ i32::from(Cause::TunnelParameterError)
+ }
+ talpid_tunnel::ErrorStateCause::IsOffline => {
+ i32::from(Cause::IsOffline)
+ }
+ #[cfg(target_os = "android")]
+ talpid_tunnel::ErrorStateCause::VpnPermissionDenied => {
+ i32::from(Cause::VpnPermissionDenied)
+ }
+ },
+ blocking_error: error_state.block_failure().map(map_firewall_error),
+ auth_fail_reason: if let talpid_tunnel::ErrorStateCause::AuthFailed(
+ reason,
+ ) = error_state.cause()
+ {
+ reason.clone().unwrap_or_default()
+ } else {
+ "".to_string()
+ },
+ parameter_error:
+ if let talpid_tunnel::ErrorStateCause::TunnelParameterError(reason) =
+ error_state.cause()
+ {
+ match reason {
+ talpid_tunnel::ParameterGenerationError::NoMatchingRelay => {
+ i32::from(GenerationError::NoMatchingRelay)
+ }
+ talpid_tunnel::ParameterGenerationError::NoMatchingBridgeRelay => {
+ i32::from(GenerationError::NoMatchingBridgeRelay)
+ }
+ talpid_tunnel::ParameterGenerationError::NoWireguardKey => {
+ i32::from(GenerationError::NoWireguardKey)
+ }
+ talpid_tunnel::ParameterGenerationError::CustomTunnelHostResultionError => {
+ i32::from(GenerationError::CustomTunnelHostResolutionError)
+ }
+ }
+ } else {
+ 0
+ },
+ policy_error:
+ if let talpid_tunnel::ErrorStateCause::SetFirewallPolicyError(reason) =
+ error_state.cause()
+ {
+ Some(map_firewall_error(reason))
+ } else {
+ None
+ },
+ }),
+ })
+ }
+ };
+
+ TunnelState { state: Some(state) }
+ }
+}
+
+impl From<mullvad_types::wireguard::KeygenEvent> for KeygenEvent {
+ fn from(event: mullvad_types::wireguard::KeygenEvent) -> Self {
+ use keygen_event::KeygenEvent as Event;
+ use mullvad_types::wireguard::KeygenEvent as MullvadEvent;
+
+ KeygenEvent {
+ event: match event {
+ MullvadEvent::NewKey(_) => i32::from(Event::NewKey),
+ MullvadEvent::TooManyKeys => i32::from(Event::TooManyKeys),
+ MullvadEvent::GenerationFailure => i32::from(Event::GenerationFailure),
+ },
+ new_key: if let MullvadEvent::NewKey(key) = event {
+ Some(PublicKey::from(key))
+ } else {
+ None
+ },
+ }
+ }
+}
+
+impl From<mullvad_types::wireguard::PublicKey> for PublicKey {
+ fn from(public_key: mullvad_types::wireguard::PublicKey) -> Self {
+ PublicKey {
+ key: public_key.key.as_bytes().to_vec(),
+ created: Some(Timestamp {
+ seconds: public_key.created.timestamp(),
+ nanos: 0,
+ }),
+ }
+ }
+}
+
+impl From<mullvad_types::version::AppVersionInfo> for AppVersionInfo {
+ fn from(version_info: mullvad_types::version::AppVersionInfo) -> Self {
+ Self {
+ supported: version_info.supported,
+ latest_stable: version_info.latest_stable,
+ latest_beta: version_info.latest_beta,
+ suggested_upgrade: version_info.suggested_upgrade.unwrap_or_default(),
+ }
+ }
+}
+
+impl From<mullvad_types::ConnectionConfig> for ConnectionConfig {
+ fn from(config: mullvad_types::ConnectionConfig) -> Self {
+ Self {
+ config: Some(match config {
+ mullvad_types::ConnectionConfig::OpenVpn(config) => {
+ connection_config::Config::Openvpn(connection_config::OpenvpnConfig {
+ address: config.endpoint.address.to_string(),
+ protocol: i32::from(TransportProtocol::from(config.endpoint.protocol)),
+ username: config.username,
+ password: config.password,
+ })
+ }
+ mullvad_types::ConnectionConfig::Wireguard(config) => {
+ connection_config::Config::Wireguard(connection_config::WireguardConfig {
+ tunnel: Some(connection_config::wireguard_config::TunnelConfig {
+ private_key: config.tunnel.private_key.to_bytes().to_vec(),
+ addresses: config
+ .tunnel
+ .addresses
+ .iter()
+ .map(|address| address.to_string())
+ .collect(),
+ }),
+ peer: Some(connection_config::wireguard_config::PeerConfig {
+ public_key: config.peer.public_key.as_bytes().to_vec(),
+ allowed_ips: config
+ .peer
+ .allowed_ips
+ .iter()
+ .map(|address| address.to_string())
+ .collect(),
+ endpoint: config.peer.endpoint.to_string(),
+ protocol: i32::from(TransportProtocol::from(config.peer.protocol)),
+ }),
+ ipv4_gateway: config.ipv4_gateway.to_string(),
+ ipv6_gateway: config
+ .ipv6_gateway
+ .as_ref()
+ .map(|address| address.to_string())
+ .unwrap_or_default(),
+ })
+ }
+ }),
+ }
+ }
+}
+
+impl From<talpid_types::net::TransportProtocol> for TransportProtocol {
+ fn from(protocol: talpid_types::net::TransportProtocol) -> Self {
+ match protocol {
+ talpid_types::net::TransportProtocol::Udp => TransportProtocol::Udp,
+ talpid_types::net::TransportProtocol::Tcp => TransportProtocol::Tcp,
+ }
+ }
+}
+
+impl From<TransportProtocol> for TransportProtocolConstraint {
+ fn from(protocol: TransportProtocol) -> Self {
+ Self {
+ protocol: i32::from(protocol),
+ }
+ }
+}
+
+impl From<talpid_types::net::IpVersion> for IpVersion {
+ fn from(version: talpid_types::net::IpVersion) -> Self {
+ match version {
+ talpid_types::net::IpVersion::V4 => Self::V4,
+ talpid_types::net::IpVersion::V6 => Self::V6,
+ }
+ }
+}
+
+impl From<IpVersion> for IpVersionConstraint {
+ fn from(version: IpVersion) -> Self {
+ Self {
+ protocol: i32::from(version),
+ }
+ }
+}
+
+impl From<mullvad_types::relay_constraints::LocationConstraint> for RelayLocation {
+ fn from(location: mullvad_types::relay_constraints::LocationConstraint) -> Self {
+ use mullvad_types::relay_constraints::LocationConstraint;
+
+ match location {
+ LocationConstraint::Country(country) => Self {
+ country,
+ ..Default::default()
+ },
+ LocationConstraint::City(country, city) => Self {
+ country,
+ city,
+ ..Default::default()
+ },
+ LocationConstraint::Hostname(country, city, hostname) => Self {
+ country,
+ city,
+ hostname,
+ },
+ }
+ }
+}
+
+impl From<&mullvad_types::settings::Settings> for Settings {
+ fn from(settings: &mullvad_types::settings::Settings) -> Self {
+ Self {
+ account_token: settings.get_account_token().unwrap_or_default(),
+ relay_settings: Some(RelaySettings::from(settings.get_relay_settings())),
+ bridge_settings: Some(BridgeSettings::from(settings.bridge_settings.clone())),
+ bridge_state: Some(BridgeState::from(settings.get_bridge_state())),
+ allow_lan: settings.allow_lan,
+ block_when_disconnected: settings.block_when_disconnected,
+ auto_connect: settings.auto_connect,
+ tunnel_options: Some(TunnelOptions::from(&settings.tunnel_options)),
+ show_beta_releases: settings.show_beta_releases,
+ }
+ }
+}
+
+impl From<mullvad_types::relay_constraints::BridgeState> for BridgeState {
+ fn from(state: mullvad_types::relay_constraints::BridgeState) -> Self {
+ use mullvad_types::relay_constraints::BridgeState;
+ Self {
+ state: i32::from(match state {
+ BridgeState::Auto => bridge_state::State::Auto,
+ BridgeState::On => bridge_state::State::On,
+ BridgeState::Off => bridge_state::State::Off,
+ }),
+ }
+ }
+}
+
+impl From<mullvad_types::relay_constraints::BridgeSettings> for BridgeSettings {
+ fn from(settings: mullvad_types::relay_constraints::BridgeSettings) -> Self {
+ use mullvad_types::relay_constraints::BridgeSettings as MullvadBridgeSettings;
+ use talpid_types::net as talpid_net;
+
+ let settings = match settings {
+ MullvadBridgeSettings::Normal(constraints) => {
+ bridge_settings::Type::Normal(bridge_settings::BridgeConstraints {
+ location: constraints
+ .location
+ .clone()
+ .option()
+ .map(RelayLocation::from),
+ providers: convert_providers_constraint(&constraints.providers),
+ })
+ }
+ MullvadBridgeSettings::Custom(proxy_settings) => match proxy_settings {
+ talpid_net::openvpn::ProxySettings::Local(proxy_settings) => {
+ bridge_settings::Type::Local(bridge_settings::LocalProxySettings {
+ port: u32::from(proxy_settings.port),
+ peer: proxy_settings.peer.to_string(),
+ })
+ }
+ talpid_net::openvpn::ProxySettings::Remote(proxy_settings) => {
+ bridge_settings::Type::Remote(bridge_settings::RemoteProxySettings {
+ address: proxy_settings.address.to_string(),
+ auth: proxy_settings.auth.as_ref().map(|auth| {
+ bridge_settings::RemoteProxyAuth {
+ username: auth.username.clone(),
+ password: auth.password.clone(),
+ }
+ }),
+ })
+ }
+ talpid_net::openvpn::ProxySettings::Shadowsocks(proxy_settings) => {
+ bridge_settings::Type::Shadowsocks(bridge_settings::ShadowsocksProxySettings {
+ peer: proxy_settings.peer.to_string(),
+ password: proxy_settings.password.clone(),
+ cipher: proxy_settings.cipher.clone(),
+ })
+ }
+ },
+ };
+
+ BridgeSettings {
+ r#type: Some(settings),
+ }
+ }
+}
+
+impl From<mullvad_types::relay_constraints::RelaySettings> for RelaySettings {
+ fn from(settings: mullvad_types::relay_constraints::RelaySettings) -> Self {
+ use mullvad_types::relay_constraints::RelaySettings as MullvadRelaySettings;
+ use talpid_types::net as talpid_net;
+
+ let endpoint = match settings {
+ MullvadRelaySettings::CustomTunnelEndpoint(endpoint) => {
+ relay_settings::Endpoint::Custom(CustomRelaySettings {
+ host: endpoint.host,
+ config: Some(ConnectionConfig::from(endpoint.config)),
+ })
+ }
+ MullvadRelaySettings::Normal(constraints) => {
+ relay_settings::Endpoint::Normal(NormalRelaySettings {
+ location: constraints.location.option().map(RelayLocation::from),
+ providers: convert_providers_constraint(&constraints.providers),
+ tunnel_type: match constraints.tunnel_protocol {
+ Constraint::Any => None,
+ Constraint::Only(talpid_net::TunnelType::Wireguard) => {
+ Some(TunnelType::Wireguard)
+ }
+ Constraint::Only(talpid_net::TunnelType::OpenVpn) => {
+ Some(TunnelType::Openvpn)
+ }
+ }
+ .map(|tunnel_type| TunnelTypeConstraint {
+ tunnel_type: i32::from(tunnel_type),
+ }),
+
+ wireguard_constraints: Some(WireguardConstraints {
+ port: u32::from(constraints.wireguard_constraints.port.unwrap_or(0)),
+ ip_version: constraints
+ .wireguard_constraints
+ .ip_version
+ .option()
+ .map(IpVersion::from)
+ .map(IpVersionConstraint::from),
+ }),
+
+ openvpn_constraints: Some(OpenvpnConstraints {
+ port: u32::from(constraints.openvpn_constraints.port.unwrap_or(0)),
+ protocol: constraints
+ .openvpn_constraints
+ .protocol
+ .as_ref()
+ .option()
+ .map(|protocol| TransportProtocol::from(*protocol))
+ .map(TransportProtocolConstraint::from),
+ }),
+ })
+ }
+ };
+
+ Self {
+ endpoint: Some(endpoint),
+ }
+ }
+}
+
+impl From<&mullvad_types::settings::TunnelOptions> for TunnelOptions {
+ fn from(options: &mullvad_types::settings::TunnelOptions) -> Self {
+ Self {
+ openvpn: Some(tunnel_options::OpenvpnOptions {
+ mssfix: u32::from(options.openvpn.mssfix.unwrap_or_default()),
+ }),
+ wireguard: Some(tunnel_options::WireguardOptions {
+ mtu: u32::from(options.wireguard.options.mtu.unwrap_or_default()),
+ rotation_interval: options
+ .wireguard
+ .rotation_interval
+ .map(|ivl| Duration::from(std::time::Duration::from(ivl))),
+ }),
+ generic: Some(tunnel_options::GenericOptions {
+ enable_ipv6: options.generic.enable_ipv6,
+ }),
+ #[cfg(not(target_os = "android"))]
+ dns_options: Some(DnsOptions {
+ custom: options.dns_options.custom,
+ addresses: options
+ .dns_options
+ .addresses
+ .iter()
+ .map(|addr| addr.to_string())
+ .collect(),
+ }),
+ #[cfg(target_os = "android")]
+ dns_options: None,
+ }
+ }
+}
+
+impl From<mullvad_types::relay_list::RelayListCountry> for RelayListCountry {
+ fn from(country: mullvad_types::relay_list::RelayListCountry) -> Self {
+ let mut proto_country = RelayListCountry {
+ name: country.name,
+ code: country.code,
+ cities: Vec::with_capacity(country.cities.len()),
+ };
+
+ for city in country.cities.into_iter() {
+ proto_country.cities.push(RelayListCity {
+ name: city.name,
+ code: city.code,
+ latitude: city.latitude,
+ longitude: city.longitude,
+ relays: city.relays.into_iter().map(Relay::from).collect(),
+ });
+ }
+
+ proto_country
+ }
+}
+
+impl From<mullvad_types::relay_list::Relay> for Relay {
+ fn from(relay: mullvad_types::relay_list::Relay) -> Self {
+ Self {
+ hostname: relay.hostname,
+ ipv4_addr_in: relay.ipv4_addr_in.to_string(),
+ ipv6_addr_in: relay
+ .ipv6_addr_in
+ .map(|addr| addr.to_string())
+ .unwrap_or_default(),
+ include_in_country: relay.include_in_country,
+ active: relay.active,
+ owned: relay.owned,
+ provider: relay.provider,
+ weight: relay.weight,
+ tunnels: Some(RelayTunnels {
+ openvpn: relay
+ .tunnels
+ .openvpn
+ .iter()
+ .map(|endpoint| OpenVpnEndpointData {
+ port: u32::from(endpoint.port),
+ protocol: i32::from(TransportProtocol::from(endpoint.protocol)),
+ })
+ .collect(),
+ wireguard: relay
+ .tunnels
+ .wireguard
+ .iter()
+ .map(|endpoint| {
+ let port_ranges = endpoint
+ .port_ranges
+ .iter()
+ .map(|range| PortRange {
+ first: u32::from(range.0),
+ last: u32::from(range.1),
+ })
+ .collect();
+ WireguardEndpointData {
+ port_ranges,
+ ipv4_gateway: endpoint.ipv4_gateway.to_string(),
+ ipv6_gateway: endpoint.ipv6_gateway.to_string(),
+ public_key: endpoint.public_key.as_bytes().to_vec(),
+ }
+ })
+ .collect(),
+ }),
+ bridges: Some(RelayBridges {
+ shadowsocks: relay
+ .bridges
+ .shadowsocks
+ .into_iter()
+ .map(|endpoint| ShadowsocksEndpointData {
+ port: u32::from(endpoint.port),
+ cipher: endpoint.cipher,
+ password: endpoint.password,
+ protocol: i32::from(TransportProtocol::from(endpoint.protocol)),
+ })
+ .collect(),
+ }),
+ location: relay.location.map(|location| Location {
+ country: location.country,
+ country_code: location.country_code,
+ city: location.city,
+ city_code: location.city_code,
+ latitude: location.latitude,
+ longitude: location.longitude,
+ }),
+ }
+ }
+}
+
+impl From<TransportProtocol> for talpid_types::net::TransportProtocol {
+ fn from(protocol: TransportProtocol) -> Self {
+ match protocol {
+ TransportProtocol::Udp => talpid_types::net::TransportProtocol::Udp,
+ TransportProtocol::Tcp => talpid_types::net::TransportProtocol::Tcp,
+ }
+ }
+}
+
+pub enum FromProtobufTypeError {
+ InvalidArgument(&'static str),
+}
+
+impl TryFrom<RelaySettingsUpdate> for mullvad_types::relay_constraints::RelaySettingsUpdate {
+ type Error = FromProtobufTypeError;
+
+ fn try_from(
+ settings: RelaySettingsUpdate,
+ ) -> Result<mullvad_types::relay_constraints::RelaySettingsUpdate, Self::Error> {
+ use mullvad_types::CustomTunnelEndpoint;
+ use talpid_types::net::{self, openvpn, wireguard};
+
+ use mullvad_types::relay_constraints as mullvad_constraints;
+
+ let update_value =
+ settings
+ .r#type
+ .clone()
+ .ok_or(FromProtobufTypeError::InvalidArgument(
+ "missing relay settings",
+ ))?;
+
+ match update_value {
+ relay_settings_update::Type::Custom(settings) => {
+ let config = settings
+ .config
+ .ok_or(FromProtobufTypeError::InvalidArgument(
+ "missing relay settings",
+ ))?;
+ let config = config.config.ok_or(FromProtobufTypeError::InvalidArgument(
+ "missing relay settings",
+ ))?;
+ let config = match config {
+ connection_config::Config::Openvpn(config) => {
+ let address = match config.address.parse() {
+ Ok(address) => address,
+ Err(_) => {
+ return Err(FromProtobufTypeError::InvalidArgument(
+ "invalid address",
+ ))
+ }
+ };
+
+ mullvad_types::ConnectionConfig::OpenVpn(openvpn::ConnectionConfig {
+ endpoint: net::Endpoint {
+ address,
+ protocol: TransportProtocol::from_i32(config.protocol)
+ .ok_or(FromProtobufTypeError::InvalidArgument(
+ "invalid transport protocol",
+ ))?
+ .into(),
+ },
+ username: config.username,
+ password: config.password,
+ })
+ }
+ connection_config::Config::Wireguard(config) => {
+ let tunnel = config.tunnel.ok_or(
+ FromProtobufTypeError::InvalidArgument("missing tunnel config"),
+ )?;
+
+ // Copy the private key to an array
+ if tunnel.private_key.len() != 32 {
+ return Err(FromProtobufTypeError::InvalidArgument(
+ "invalid private key",
+ ));
+ }
+
+ let mut private_key = [0; 32];
+ let buffer = &tunnel.private_key[..private_key.len()];
+ private_key.copy_from_slice(buffer);
+
+ let peer = config.peer.ok_or(FromProtobufTypeError::InvalidArgument(
+ "missing peer config",
+ ))?;
+
+ // Copy the public key to an array
+ if peer.public_key.len() != 32 {
+ return Err(FromProtobufTypeError::InvalidArgument(
+ "invalid public key",
+ ));
+ }
+
+ let mut public_key = [0; 32];
+ let buffer = &peer.public_key[..public_key.len()];
+ public_key.copy_from_slice(buffer);
+
+ let ipv4_gateway = match config.ipv4_gateway.parse() {
+ Ok(address) => address,
+ Err(_) => {
+ return Err(FromProtobufTypeError::InvalidArgument(
+ "invalid IPv4 gateway",
+ ))
+ }
+ };
+ let ipv6_gateway = if !config.ipv6_gateway.is_empty() {
+ let address = match config.ipv6_gateway.parse() {
+ Ok(address) => address,
+ Err(_) => {
+ return Err(FromProtobufTypeError::InvalidArgument(
+ "invalid IPv6 gateway",
+ ))
+ }
+ };
+ Some(address)
+ } else {
+ None
+ };
+
+ let endpoint = match peer.endpoint.parse() {
+ Ok(address) => address,
+ Err(_) => {
+ return Err(FromProtobufTypeError::InvalidArgument(
+ "invalid peer address",
+ ))
+ }
+ };
+
+ let mut tunnel_addresses = Vec::new();
+ for address in tunnel.addresses {
+ let address = address.parse().map_err(|_| {
+ FromProtobufTypeError::InvalidArgument("invalid address")
+ })?;
+ tunnel_addresses.push(address);
+ }
+
+ let mut allowed_ips = Vec::new();
+ for address in peer.allowed_ips {
+ let address = address.parse().map_err(|_| {
+ FromProtobufTypeError::InvalidArgument("invalid address")
+ })?;
+ allowed_ips.push(address);
+ }
+
+ mullvad_types::ConnectionConfig::Wireguard(wireguard::ConnectionConfig {
+ tunnel: wireguard::TunnelConfig {
+ private_key: wireguard::PrivateKey::from(private_key),
+ addresses: tunnel_addresses,
+ },
+ peer: wireguard::PeerConfig {
+ public_key: wireguard::PublicKey::from(public_key),
+ allowed_ips,
+ endpoint,
+ protocol: TransportProtocol::from_i32(peer.protocol)
+ .ok_or(FromProtobufTypeError::InvalidArgument(
+ "invalid transport protocol",
+ ))?
+ .into(),
+ },
+ ipv4_gateway,
+ ipv6_gateway,
+ })
+ }
+ };
+
+ Ok(
+ mullvad_constraints::RelaySettingsUpdate::CustomTunnelEndpoint(
+ CustomTunnelEndpoint {
+ host: settings.host,
+ config,
+ },
+ ),
+ )
+ }
+
+ relay_settings_update::Type::Normal(settings) => {
+ // If `location` isn't provided, no changes are made.
+ // If `location` is provided, but is an empty vector,
+ // then the constraint is set to `Constraint::Any`.
+ let location = settings
+ .location
+ .map(Constraint::<mullvad_types::relay_constraints::LocationConstraint>::from);
+
+ let tunnel_protocol = if let Some(update) = settings.tunnel_type {
+ match update.tunnel_type {
+ Some(constraint) => match TunnelType::from_i32(constraint.tunnel_type) {
+ Some(TunnelType::Openvpn) => {
+ Some(Constraint::Only(net::TunnelType::OpenVpn))
+ }
+ Some(TunnelType::Wireguard) => {
+ Some(Constraint::Only(net::TunnelType::Wireguard))
+ }
+ None => {
+ return Err(FromProtobufTypeError::InvalidArgument(
+ "invalid tunnel protocol",
+ ))
+ }
+ },
+ None => Some(Constraint::Any),
+ }
+ } else {
+ None
+ };
+
+ let transport_protocol = if let Some(ref constraints) = settings.openvpn_constraints
+ {
+ match &constraints.protocol {
+ Some(constraint) => Some(
+ TransportProtocol::from_i32(constraint.protocol)
+ .ok_or(FromProtobufTypeError::InvalidArgument(
+ "invalid transport protocol",
+ ))?
+ .into(),
+ ),
+ None => None,
+ }
+ } else {
+ None
+ };
+
+ let providers = if let Some(ref provider_update) = settings.providers {
+ if !provider_update.providers.is_empty() {
+ Some(Constraint::Only(
+ mullvad_constraints::Providers::new(
+ provider_update.providers.clone().into_iter(),
+ )
+ .map_err(|_| {
+ FromProtobufTypeError::InvalidArgument(
+ "must specify at least one provider",
+ )
+ })?,
+ ))
+ } else {
+ Some(Constraint::Any)
+ }
+ } else {
+ None
+ };
+ let ip_version = if let Some(ref constraints) = settings.wireguard_constraints {
+ match &constraints.ip_version {
+ Some(constraint) => match IpVersion::from_i32(constraint.protocol) {
+ Some(IpVersion::V4) => Some(net::IpVersion::V4),
+ Some(IpVersion::V6) => Some(net::IpVersion::V6),
+ None => {
+ return Err(FromProtobufTypeError::InvalidArgument(
+ "invalid ip protocol version",
+ ))
+ }
+ },
+ None => None,
+ }
+ } else {
+ None
+ };
+
+ Ok(mullvad_constraints::RelaySettingsUpdate::Normal(
+ mullvad_constraints::RelayConstraintsUpdate {
+ location,
+ providers,
+ tunnel_protocol,
+ wireguard_constraints: settings.wireguard_constraints.map(|constraints| {
+ mullvad_constraints::WireguardConstraints {
+ port: if constraints.port != 0 {
+ Constraint::Only(constraints.port as u16)
+ } else {
+ Constraint::Any
+ },
+ ip_version: Constraint::from(ip_version),
+ }
+ }),
+ openvpn_constraints: settings.openvpn_constraints.map(|constraints| {
+ mullvad_constraints::OpenVpnConstraints {
+ port: if constraints.port != 0 {
+ Constraint::Only(constraints.port as u16)
+ } else {
+ Constraint::Any
+ },
+ protocol: Constraint::from(transport_protocol),
+ }
+ }),
+ },
+ ))
+ }
+ }
+ }
+}
+
+impl From<RelayLocation> for Constraint<mullvad_types::relay_constraints::LocationConstraint> {
+ fn from(location: RelayLocation) -> Self {
+ use mullvad_types::relay_constraints::LocationConstraint;
+
+ if !location.hostname.is_empty() {
+ Constraint::Only(LocationConstraint::Hostname(
+ location.country,
+ location.city,
+ location.hostname,
+ ))
+ } else if !location.city.is_empty() {
+ Constraint::Only(LocationConstraint::City(location.country, location.city))
+ } else if !location.country.is_empty() {
+ Constraint::Only(LocationConstraint::Country(location.country))
+ } else {
+ Constraint::Any
+ }
+ }
+}
+
+impl TryFrom<BridgeSettings> for mullvad_types::relay_constraints::BridgeSettings {
+ type Error = FromProtobufTypeError;
+
+ fn try_from(settings: BridgeSettings) -> Result<Self, Self::Error> {
+ use mullvad_types::relay_constraints as mullvad_constraints;
+ use talpid_types::net as talpid_net;
+
+ match settings
+ .r#type
+ .ok_or(FromProtobufTypeError::InvalidArgument(
+ "no settings provided",
+ ))? {
+ bridge_settings::Type::Normal(constraints) => {
+ let location = match constraints.location {
+ None => Constraint::Any,
+ Some(location) => {
+ Constraint::<mullvad_constraints::LocationConstraint>::from(location)
+ }
+ };
+ let providers = if constraints.providers.is_empty() {
+ Constraint::Any
+ } else {
+ Constraint::Only(
+ mullvad_constraints::Providers::new(
+ constraints.providers.clone().into_iter(),
+ )
+ .map_err(|_| {
+ FromProtobufTypeError::InvalidArgument(
+ "must specify at least one provider",
+ )
+ })?,
+ )
+ };
+
+ Ok(mullvad_constraints::BridgeSettings::Normal(
+ mullvad_constraints::BridgeConstraints {
+ location,
+ providers,
+ },
+ ))
+ }
+ bridge_settings::Type::Local(proxy_settings) => {
+ let peer = proxy_settings.peer.parse().map_err(|_| {
+ FromProtobufTypeError::InvalidArgument("failed to parse peer address")
+ })?;
+ let proxy_settings = talpid_net::openvpn::ProxySettings::Local(
+ talpid_net::openvpn::LocalProxySettings {
+ port: proxy_settings.port as u16,
+ peer,
+ },
+ );
+ Ok(mullvad_constraints::BridgeSettings::Custom(proxy_settings))
+ }
+ bridge_settings::Type::Remote(proxy_settings) => {
+ let address = proxy_settings.address.parse().map_err(|_| {
+ FromProtobufTypeError::InvalidArgument("failed to parse IP address")
+ })?;
+ let auth = proxy_settings
+ .auth
+ .map(|auth| talpid_net::openvpn::ProxyAuth {
+ username: auth.username,
+ password: auth.password,
+ });
+ let proxy_settings = talpid_net::openvpn::ProxySettings::Remote(
+ talpid_net::openvpn::RemoteProxySettings { address, auth },
+ );
+ Ok(mullvad_constraints::BridgeSettings::Custom(proxy_settings))
+ }
+ bridge_settings::Type::Shadowsocks(proxy_settings) => {
+ let peer = proxy_settings.peer.parse().map_err(|_| {
+ FromProtobufTypeError::InvalidArgument("failed to parse peer address")
+ })?;
+ let proxy_settings = talpid_net::openvpn::ProxySettings::Shadowsocks(
+ talpid_net::openvpn::ShadowsocksProxySettings {
+ peer,
+ password: proxy_settings.password,
+ cipher: proxy_settings.cipher,
+ },
+ );
+ Ok(mullvad_constraints::BridgeSettings::Custom(proxy_settings))
+ }
+ }
+ }
+}
+
+impl TryFrom<BridgeState> for mullvad_types::relay_constraints::BridgeState {
+ type Error = FromProtobufTypeError;
+
+ fn try_from(state: BridgeState) -> Result<Self, Self::Error> {
+ match bridge_state::State::from_i32(state.state) {
+ Some(bridge_state::State::Auto) => {
+ Ok(mullvad_types::relay_constraints::BridgeState::Auto)
+ }
+ Some(bridge_state::State::On) => Ok(mullvad_types::relay_constraints::BridgeState::On),
+ Some(bridge_state::State::Off) => {
+ Ok(mullvad_types::relay_constraints::BridgeState::Off)
+ }
+ None => Err(FromProtobufTypeError::InvalidArgument(
+ "invalid bridge state",
+ )),
+ }
+ }
+}
+
+fn convert_providers_constraint(
+ providers: &Constraint<mullvad_types::relay_constraints::Providers>,
+) -> Vec<String> {
+ match providers.as_ref() {
+ Constraint::Any => vec![],
+ Constraint::Only(providers) => Vec::from(providers.clone()),
+ }
+}
diff --git a/mullvad-types/src/relay_constraints.rs b/mullvad-types/src/relay_constraints.rs
index 908b0d3215..d32608124d 100644
--- a/mullvad-types/src/relay_constraints.rs
+++ b/mullvad-types/src/relay_constraints.rs
@@ -498,7 +498,7 @@ impl fmt::Display for BridgeConstraints {
}
/// Setting indicating whether to connect to a bridge server, or to handle it automatically.
-#[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize)]
+#[derive(Debug, Clone, Copy, Eq, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum BridgeState {
Auto,
diff --git a/mullvad-types/src/settings/mod.rs b/mullvad-types/src/settings/mod.rs
index 9ea32fdb3b..1cd900edfc 100644
--- a/mullvad-types/src/settings/mod.rs
+++ b/mullvad-types/src/settings/mod.rs
@@ -143,8 +143,8 @@ impl Settings {
}
}
- pub fn get_bridge_state(&self) -> &BridgeState {
- &self.bridge_state
+ pub fn get_bridge_state(&self) -> BridgeState {
+ self.bridge_state
}
pub fn set_bridge_state(&mut self, bridge_state: BridgeState) -> bool {