summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--mullvad-cli/src/cmds/bridge.rs17
-rw-r--r--mullvad-management-interface/src/types/conversions/custom_tunnel.rs152
-rw-r--r--mullvad-management-interface/src/types/conversions/device.rs139
-rw-r--r--mullvad-management-interface/src/types/conversions/location.rs46
-rw-r--r--mullvad-management-interface/src/types/conversions/mod.rs2001
-rw-r--r--mullvad-management-interface/src/types/conversions/net.rs191
-rw-r--r--mullvad-management-interface/src/types/conversions/relay_constraints.rs679
-rw-r--r--mullvad-management-interface/src/types/conversions/relay_list.rs205
-rw-r--r--mullvad-management-interface/src/types/conversions/settings.rs227
-rw-r--r--mullvad-management-interface/src/types/conversions/states.rs318
-rw-r--r--mullvad-management-interface/src/types/conversions/version.rs12
-rw-r--r--mullvad-management-interface/src/types/conversions/wireguard.rs14
12 files changed, 2022 insertions, 1979 deletions
diff --git a/mullvad-cli/src/cmds/bridge.rs b/mullvad-cli/src/cmds/bridge.rs
index a8a3e2de7c..9d1c5172fa 100644
--- a/mullvad-cli/src/cmds/bridge.rs
+++ b/mullvad-cli/src/cmds/bridge.rs
@@ -277,20 +277,25 @@ impl Bridge {
}
if let Some(new_providers) = providers {
constraints.providers =
- types::try_providers_constraint_from_proto(&new_providers).unwrap();
+ types::relay_constraints::try_providers_constraint_from_proto(
+ &new_providers,
+ )
+ .unwrap();
}
if let Some(new_ownership) = ownership {
- constraints.ownership = types::ownership_constraint_from_proto(new_ownership);
+ constraints.ownership =
+ types::relay_constraints::ownership_constraint_from_proto(new_ownership);
}
constraints
}
_ => {
let location = Constraint::<LocationConstraint>::from(location.unwrap_or_default());
- let providers =
- types::try_providers_constraint_from_proto(&providers.unwrap_or_default())
- .unwrap();
+ let providers = types::relay_constraints::try_providers_constraint_from_proto(
+ &providers.unwrap_or_default(),
+ )
+ .unwrap();
let ownership = ownership
- .map(types::ownership_constraint_from_proto)
+ .map(types::relay_constraints::ownership_constraint_from_proto)
.unwrap_or_default();
BridgeConstraints {
diff --git a/mullvad-management-interface/src/types/conversions/custom_tunnel.rs b/mullvad-management-interface/src/types/conversions/custom_tunnel.rs
new file mode 100644
index 0000000000..950f8f920c
--- /dev/null
+++ b/mullvad-management-interface/src/types/conversions/custom_tunnel.rs
@@ -0,0 +1,152 @@
+use crate::types::{
+ conversions::{bytes_to_privkey, bytes_to_pubkey, option_from_proto_string},
+ proto, FromProtobufTypeError,
+};
+use talpid_types::net::wireguard;
+
+impl TryFrom<proto::ConnectionConfig> for mullvad_types::ConnectionConfig {
+ type Error = FromProtobufTypeError;
+
+ fn try_from(
+ config: proto::ConnectionConfig,
+ ) -> Result<mullvad_types::ConnectionConfig, Self::Error> {
+ use talpid_types::net::{self, openvpn};
+
+ let config = config.config.ok_or(FromProtobufTypeError::InvalidArgument(
+ "missing connection config",
+ ))?;
+ match config {
+ proto::connection_config::Config::Openvpn(config) => {
+ let address = match config.address.parse() {
+ Ok(address) => address,
+ Err(_) => {
+ return Err(FromProtobufTypeError::InvalidArgument("invalid address"))
+ }
+ };
+
+ Ok(mullvad_types::ConnectionConfig::OpenVpn(
+ openvpn::ConnectionConfig {
+ endpoint: net::Endpoint {
+ address,
+ protocol: super::net::try_transport_protocol_from_i32(config.protocol)?,
+ },
+ username: config.username,
+ password: config.password,
+ },
+ ))
+ }
+ proto::connection_config::Config::Wireguard(config) => {
+ let tunnel = config.tunnel.ok_or(FromProtobufTypeError::InvalidArgument(
+ "missing tunnel config",
+ ))?;
+
+ let private_key = bytes_to_privkey(&tunnel.private_key)?;
+
+ let peer = config.peer.ok_or(FromProtobufTypeError::InvalidArgument(
+ "missing peer config",
+ ))?;
+
+ let public_key = bytes_to_pubkey(&peer.public_key)?;
+
+ let ipv4_gateway = config.ipv4_gateway.parse().map_err(|_err| {
+ FromProtobufTypeError::InvalidArgument("invalid IPv4 gateway")
+ })?;
+ let ipv6_gateway = option_from_proto_string(config.ipv6_gateway)
+ .map(|addr| {
+ addr.parse().map_err(|_err| {
+ FromProtobufTypeError::InvalidArgument("invalid IPv6 gateway")
+ })
+ })
+ .transpose()?;
+
+ let endpoint = peer.endpoint.parse().map_err(|_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);
+ }
+
+ Ok(mullvad_types::ConnectionConfig::Wireguard(
+ wireguard::ConnectionConfig {
+ tunnel: wireguard::TunnelConfig {
+ private_key,
+ addresses: tunnel_addresses,
+ },
+ peer: wireguard::PeerConfig {
+ public_key,
+ allowed_ips,
+ endpoint,
+ psk: None,
+ },
+ exit_peer: None,
+ ipv4_gateway,
+ ipv6_gateway,
+ },
+ ))
+ }
+ }
+ }
+}
+
+impl From<mullvad_types::ConnectionConfig> for proto::ConnectionConfig {
+ fn from(config: mullvad_types::ConnectionConfig) -> Self {
+ use proto::connection_config;
+
+ 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(proto::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(),
+ }),
+ ipv4_gateway: config.ipv4_gateway.to_string(),
+ ipv6_gateway: config
+ .ipv6_gateway
+ .as_ref()
+ .map(|address| address.to_string())
+ .unwrap_or_default(),
+ })
+ }
+ }),
+ }
+ }
+}
diff --git a/mullvad-management-interface/src/types/conversions/device.rs b/mullvad-management-interface/src/types/conversions/device.rs
new file mode 100644
index 0000000000..625af6c9c1
--- /dev/null
+++ b/mullvad-management-interface/src/types/conversions/device.rs
@@ -0,0 +1,139 @@
+use crate::types::{conversions::bytes_to_pubkey, proto, FromProtobufTypeError};
+use prost_types::Timestamp;
+
+impl TryFrom<proto::Device> for mullvad_types::device::Device {
+ type Error = FromProtobufTypeError;
+
+ fn try_from(device: proto::Device) -> Result<Self, Self::Error> {
+ Ok(mullvad_types::device::Device {
+ id: device.id,
+ name: device.name,
+ pubkey: bytes_to_pubkey(&device.pubkey)?,
+ ports: device
+ .ports
+ .into_iter()
+ .map(mullvad_types::device::DevicePort::from)
+ .collect(),
+ hijack_dns: device.hijack_dns,
+ created: chrono::DateTime::from_utc(
+ chrono::NaiveDateTime::from_timestamp(
+ device
+ .created
+ .ok_or(FromProtobufTypeError::InvalidArgument(
+ "missing 'created' field",
+ ))?
+ .seconds,
+ 0,
+ ),
+ chrono::Utc,
+ ),
+ })
+ }
+}
+
+impl From<mullvad_types::device::Device> for proto::Device {
+ fn from(device: mullvad_types::device::Device) -> Self {
+ proto::Device {
+ id: device.id,
+ name: device.name,
+ pubkey: device.pubkey.as_bytes().to_vec(),
+ ports: device
+ .ports
+ .into_iter()
+ .map(proto::DevicePort::from)
+ .collect(),
+ hijack_dns: device.hijack_dns,
+ created: Some(Timestamp {
+ seconds: device.created.timestamp(),
+ nanos: 0,
+ }),
+ }
+ }
+}
+
+impl From<mullvad_types::device::DevicePort> for proto::DevicePort {
+ fn from(port: mullvad_types::device::DevicePort) -> Self {
+ proto::DevicePort { id: port.id }
+ }
+}
+
+impl From<mullvad_types::device::DeviceState> for proto::DeviceState {
+ fn from(state: mullvad_types::device::DeviceState) -> Self {
+ proto::DeviceState {
+ state: proto::device_state::State::from(&state) as i32,
+ device: state.into_device().map(|device| proto::AccountAndDevice {
+ account_token: device.account_token,
+ device: Some(proto::Device::from(device.device)),
+ }),
+ }
+ }
+}
+
+impl From<&mullvad_types::device::DeviceState> for proto::device_state::State {
+ fn from(state: &mullvad_types::device::DeviceState) -> Self {
+ use mullvad_types::device::DeviceState as MullvadState;
+ match state {
+ MullvadState::LoggedIn(_) => proto::device_state::State::LoggedIn,
+ MullvadState::LoggedOut => proto::device_state::State::LoggedOut,
+ MullvadState::Revoked => proto::device_state::State::Revoked,
+ }
+ }
+}
+
+impl From<mullvad_types::device::DeviceEvent> for proto::DeviceEvent {
+ fn from(event: mullvad_types::device::DeviceEvent) -> Self {
+ proto::DeviceEvent {
+ cause: proto::device_event::Cause::from(event.cause) as i32,
+ new_state: Some(proto::DeviceState::from(event.new_state)),
+ }
+ }
+}
+
+impl From<mullvad_types::device::DeviceEventCause> for proto::device_event::Cause {
+ fn from(cause: mullvad_types::device::DeviceEventCause) -> Self {
+ use mullvad_types::device::DeviceEventCause as MullvadEvent;
+ match cause {
+ MullvadEvent::LoggedIn => proto::device_event::Cause::LoggedIn,
+ MullvadEvent::LoggedOut => proto::device_event::Cause::LoggedOut,
+ MullvadEvent::Revoked => proto::device_event::Cause::Revoked,
+ MullvadEvent::Updated => proto::device_event::Cause::Updated,
+ MullvadEvent::RotatedKey => proto::device_event::Cause::RotatedKey,
+ }
+ }
+}
+
+impl From<mullvad_types::device::RemoveDeviceEvent> for proto::RemoveDeviceEvent {
+ fn from(event: mullvad_types::device::RemoveDeviceEvent) -> Self {
+ proto::RemoveDeviceEvent {
+ account_token: event.account_token,
+ new_device_list: event
+ .new_devices
+ .into_iter()
+ .map(proto::Device::from)
+ .collect(),
+ }
+ }
+}
+
+impl From<mullvad_types::device::AccountAndDevice> for proto::AccountAndDevice {
+ fn from(device: mullvad_types::device::AccountAndDevice) -> Self {
+ proto::AccountAndDevice {
+ account_token: device.account_token,
+ device: Some(proto::Device::from(device.device)),
+ }
+ }
+}
+
+impl From<Vec<mullvad_types::device::Device>> for proto::DeviceList {
+ fn from(devices: Vec<mullvad_types::device::Device>) -> Self {
+ proto::DeviceList {
+ devices: devices.into_iter().map(proto::Device::from).collect(),
+ }
+ }
+}
+
+impl From<proto::DevicePort> for mullvad_types::device::DevicePort {
+ fn from(port: proto::DevicePort) -> Self {
+ mullvad_types::device::DevicePort { id: port.id }
+ }
+}
diff --git a/mullvad-management-interface/src/types/conversions/location.rs b/mullvad-management-interface/src/types/conversions/location.rs
new file mode 100644
index 0000000000..65fa825638
--- /dev/null
+++ b/mullvad-management-interface/src/types/conversions/location.rs
@@ -0,0 +1,46 @@
+use crate::types::{
+ conversions::{arg_from_str, option_from_proto_string},
+ proto, FromProtobufTypeError,
+};
+
+impl From<mullvad_types::location::GeoIpLocation> for proto::GeoIpLocation {
+ fn from(geoip: mullvad_types::location::GeoIpLocation) -> proto::GeoIpLocation {
+ proto::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(),
+ entry_hostname: geoip.entry_hostname.unwrap_or_default(),
+ obfuscator_hostname: geoip.obfuscator_hostname.unwrap_or_default(),
+ }
+ }
+}
+
+impl TryFrom<proto::GeoIpLocation> for mullvad_types::location::GeoIpLocation {
+ type Error = FromProtobufTypeError;
+
+ fn try_from(geoip: proto::GeoIpLocation) -> Result<Self, Self::Error> {
+ Ok(mullvad_types::location::GeoIpLocation {
+ ipv4: option_from_proto_string(geoip.ipv4)
+ .map(|addr| arg_from_str(&addr, "invalid IPv4 address"))
+ .transpose()?,
+ ipv6: option_from_proto_string(geoip.ipv6)
+ .map(|addr| arg_from_str(&addr, "invalid IPv6 address"))
+ .transpose()?,
+ country: geoip.country,
+ city: option_from_proto_string(geoip.city),
+ latitude: geoip.latitude,
+ longitude: geoip.longitude,
+ mullvad_exit_ip: geoip.mullvad_exit_ip,
+ hostname: option_from_proto_string(geoip.hostname),
+ bridge_hostname: option_from_proto_string(geoip.bridge_hostname),
+ entry_hostname: option_from_proto_string(geoip.entry_hostname),
+ obfuscator_hostname: option_from_proto_string(geoip.obfuscator_hostname),
+ })
+ }
+}
diff --git a/mullvad-management-interface/src/types/conversions/mod.rs b/mullvad-management-interface/src/types/conversions/mod.rs
index b232569558..46639424fd 100644
--- a/mullvad-management-interface/src/types/conversions/mod.rs
+++ b/mullvad-management-interface/src/types/conversions/mod.rs
@@ -1,1890 +1,42 @@
-use super::proto;
-use mullvad_types::relay_constraints::Constraint;
-use prost_types::Timestamp;
-use std::{convert::TryFrom, net::SocketAddr, str::FromStr};
-use talpid_types::{net::wireguard, ErrorExt};
+use std::str::FromStr;
-impl From<mullvad_types::location::GeoIpLocation> for proto::GeoIpLocation {
- fn from(geoip: mullvad_types::location::GeoIpLocation) -> proto::GeoIpLocation {
- proto::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(),
- entry_hostname: geoip.entry_hostname.unwrap_or_default(),
- obfuscator_hostname: geoip.obfuscator_hostname.unwrap_or_default(),
- }
- }
-}
-
-impl TryFrom<proto::GeoIpLocation> for mullvad_types::location::GeoIpLocation {
- type Error = FromProtobufTypeError;
-
- fn try_from(geoip: proto::GeoIpLocation) -> Result<Self, Self::Error> {
- Ok(mullvad_types::location::GeoIpLocation {
- ipv4: option_from_proto_string(geoip.ipv4)
- .map(|addr| arg_from_str(&addr, "invalid IPv4 address"))
- .transpose()?,
- ipv6: option_from_proto_string(geoip.ipv6)
- .map(|addr| arg_from_str(&addr, "invalid IPv6 address"))
- .transpose()?,
- country: geoip.country,
- city: option_from_proto_string(geoip.city),
- latitude: geoip.latitude,
- longitude: geoip.longitude,
- mullvad_exit_ip: geoip.mullvad_exit_ip,
- hostname: option_from_proto_string(geoip.hostname),
- bridge_hostname: option_from_proto_string(geoip.bridge_hostname),
- entry_hostname: option_from_proto_string(geoip.entry_hostname),
- obfuscator_hostname: option_from_proto_string(geoip.obfuscator_hostname),
- })
- }
-}
-
-impl From<talpid_types::net::TunnelEndpoint> for proto::TunnelEndpoint {
- fn from(endpoint: talpid_types::net::TunnelEndpoint) -> Self {
- use talpid_types::net;
-
- proto::TunnelEndpoint {
- address: endpoint.endpoint.address.to_string(),
- protocol: i32::from(proto::TransportProtocol::from(endpoint.endpoint.protocol)),
- tunnel_type: match endpoint.tunnel_type {
- net::TunnelType::Wireguard => i32::from(proto::TunnelType::Wireguard),
- net::TunnelType::OpenVpn => i32::from(proto::TunnelType::Openvpn),
- },
- quantum_resistant: endpoint.quantum_resistant,
- proxy: endpoint.proxy.map(|proxy_ep| proto::ProxyEndpoint {
- address: proxy_ep.endpoint.address.to_string(),
- protocol: i32::from(proto::TransportProtocol::from(proxy_ep.endpoint.protocol)),
- proxy_type: match proxy_ep.proxy_type {
- net::proxy::ProxyType::Shadowsocks => i32::from(proto::ProxyType::Shadowsocks),
- net::proxy::ProxyType::Custom => i32::from(proto::ProxyType::Custom),
- },
- }),
- obfuscation: endpoint.obfuscation.map(|obfuscation_endpoint| {
- proto::ObfuscationEndpoint {
- address: obfuscation_endpoint.endpoint.address.ip().to_string(),
- port: u32::from(obfuscation_endpoint.endpoint.address.port()),
- protocol: i32::from(proto::TransportProtocol::from(
- obfuscation_endpoint.endpoint.protocol,
- )),
- obfuscation_type: match obfuscation_endpoint.obfuscation_type {
- net::ObfuscationType::Udp2Tcp => i32::from(proto::ObfuscationType::Udp2tcp),
- },
- }
- }),
- entry_endpoint: endpoint.entry_endpoint.map(|entry| proto::Endpoint {
- address: entry.address.to_string(),
- protocol: i32::from(proto::TransportProtocol::from(entry.protocol)),
- }),
- }
- }
-}
-
-impl From<mullvad_types::states::TunnelState> for proto::TunnelState {
- fn from(state: mullvad_types::states::TunnelState) -> Self {
- use mullvad_types::states::TunnelState as MullvadTunnelState;
- use proto::error_state::{
- firewall_policy_error::ErrorType as PolicyErrorType, Cause, FirewallPolicyError,
- GenerationError,
- };
-
- 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 => {
- proto::tunnel_state::State::Disconnected(proto::tunnel_state::Disconnected {})
- }
- MullvadTunnelState::Connecting { endpoint, location } => {
- proto::tunnel_state::State::Connecting(proto::tunnel_state::Connecting {
- relay_info: Some(proto::TunnelStateRelayInfo {
- tunnel_endpoint: Some(proto::TunnelEndpoint::from(endpoint)),
- location: location.map(proto::GeoIpLocation::from),
- }),
- })
- }
- MullvadTunnelState::Connected { endpoint, location } => {
- proto::tunnel_state::State::Connected(proto::tunnel_state::Connected {
- relay_info: Some(proto::TunnelStateRelayInfo {
- tunnel_endpoint: Some(proto::TunnelEndpoint::from(endpoint)),
- location: location.map(proto::GeoIpLocation::from),
- }),
- })
- }
- MullvadTunnelState::Disconnecting(after_disconnect) => {
- proto::tunnel_state::State::Disconnecting(proto::tunnel_state::Disconnecting {
- after_disconnect: match after_disconnect {
- talpid_tunnel::ActionAfterDisconnect::Nothing => {
- i32::from(proto::AfterDisconnect::Nothing)
- }
- talpid_tunnel::ActionAfterDisconnect::Block => {
- i32::from(proto::AfterDisconnect::Block)
- }
- talpid_tunnel::ActionAfterDisconnect::Reconnect => {
- i32::from(proto::AfterDisconnect::Reconnect)
- }
- },
- })
- }
- MullvadTunnelState::Error(error_state) => {
- proto::tunnel_state::State::Error(proto::tunnel_state::Error {
- error_state: Some(proto::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)
- }
- #[cfg(target_os = "windows")]
- talpid_tunnel::ErrorStateCause::SplitTunnelError => {
- i32::from(Cause::SplitTunnelError)
- }
- },
- 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
- },
- }),
- })
- }
- };
-
- proto::TunnelState { state: Some(state) }
- }
-}
-
-impl TryFrom<proto::TunnelState> for mullvad_types::states::TunnelState {
- type Error = FromProtobufTypeError;
-
- fn try_from(state: proto::TunnelState) -> Result<Self, FromProtobufTypeError> {
- use mullvad_types::states::TunnelState as MullvadState;
- use talpid_types::{net as talpid_net, tunnel as talpid_tunnel};
-
- let state = match state.state {
- Some(proto::tunnel_state::State::Disconnected(_)) => MullvadState::Disconnected,
- Some(proto::tunnel_state::State::Connecting(proto::tunnel_state::Connecting {
- relay_info:
- Some(proto::TunnelStateRelayInfo {
- tunnel_endpoint: Some(tunnel_endpoint),
- location,
- }),
- })) => MullvadState::Connecting {
- endpoint: talpid_net::TunnelEndpoint::try_from(tunnel_endpoint)?,
- location: location
- .map(mullvad_types::location::GeoIpLocation::try_from)
- .transpose()?,
- },
- Some(proto::tunnel_state::State::Connected(proto::tunnel_state::Connected {
- relay_info:
- Some(proto::TunnelStateRelayInfo {
- tunnel_endpoint: Some(tunnel_endpoint),
- location,
- }),
- })) => MullvadState::Connected {
- endpoint: talpid_net::TunnelEndpoint::try_from(tunnel_endpoint)?,
- location: location
- .map(mullvad_types::location::GeoIpLocation::try_from)
- .transpose()?,
- },
- Some(proto::tunnel_state::State::Disconnecting(
- proto::tunnel_state::Disconnecting { after_disconnect },
- )) => MullvadState::Disconnecting(
- match proto::AfterDisconnect::from_i32(after_disconnect) {
- Some(proto::AfterDisconnect::Nothing) => {
- talpid_tunnel::ActionAfterDisconnect::Nothing
- }
- Some(proto::AfterDisconnect::Block) => {
- talpid_tunnel::ActionAfterDisconnect::Block
- }
- Some(proto::AfterDisconnect::Reconnect) => {
- talpid_tunnel::ActionAfterDisconnect::Reconnect
- }
- _ => {
- return Err(FromProtobufTypeError::InvalidArgument(
- "invalid \"after_disconnect\" action",
- ))
- }
- },
- ),
- Some(proto::tunnel_state::State::Error(proto::tunnel_state::Error {
- error_state:
- Some(proto::ErrorState {
- cause,
- blocking_error,
- auth_fail_reason,
- parameter_error,
- policy_error,
- }),
- })) => {
- let cause = match proto::error_state::Cause::from_i32(cause) {
- Some(proto::error_state::Cause::AuthFailed) => {
- talpid_tunnel::ErrorStateCause::AuthFailed(option_from_proto_string(
- auth_fail_reason,
- ))
- }
- Some(proto::error_state::Cause::Ipv6Unavailable) => {
- talpid_tunnel::ErrorStateCause::Ipv6Unavailable
- }
- Some(proto::error_state::Cause::IsOffline) => {
- talpid_tunnel::ErrorStateCause::IsOffline
- }
- Some(proto::error_state::Cause::SetDnsError) => {
- talpid_tunnel::ErrorStateCause::SetDnsError
- }
- Some(proto::error_state::Cause::SetFirewallPolicyError) => {
- let policy_error = policy_error.ok_or(
- FromProtobufTypeError::InvalidArgument("missing firewall policy error"),
- )?;
- let policy_error = try_firewall_policy_error_from_i32(
- policy_error.r#type,
- policy_error.lock_pid,
- policy_error.lock_name,
- )?;
- talpid_tunnel::ErrorStateCause::SetFirewallPolicyError(policy_error)
- }
- Some(proto::error_state::Cause::StartTunnelError) => {
- talpid_tunnel::ErrorStateCause::StartTunnelError
- }
- Some(proto::error_state::Cause::TunnelParameterError) => {
- let parameter_error = match proto::error_state::GenerationError::from_i32(parameter_error) {
- Some(proto::error_state::GenerationError::CustomTunnelHostResolutionError) => talpid_tunnel::ParameterGenerationError::CustomTunnelHostResultionError,
- Some(proto::error_state::GenerationError::NoMatchingBridgeRelay) => talpid_tunnel::ParameterGenerationError::NoMatchingBridgeRelay,
- Some(proto::error_state::GenerationError::NoMatchingRelay) => talpid_tunnel::ParameterGenerationError::NoMatchingRelay,
- Some(proto::error_state::GenerationError::NoWireguardKey) => talpid_tunnel::ParameterGenerationError::NoWireguardKey,
- _ => return Err(FromProtobufTypeError::InvalidArgument(
- "invalid parameter error",
- )),
- };
- talpid_tunnel::ErrorStateCause::TunnelParameterError(parameter_error)
- }
- #[cfg(target_os = "android")]
- Some(proto::error_state::Cause::VpnPermissionDenied) => {
- talpid_tunnel::ErrorStateCause::VpnPermissionDenied
- }
- #[cfg(target_os = "windows")]
- Some(proto::error_state::Cause::SplitTunnelError) => {
- talpid_tunnel::ErrorStateCause::SplitTunnelError
- }
- _ => {
- return Err(FromProtobufTypeError::InvalidArgument(
- "invalid error cause",
- ))
- }
- };
-
- let block_failure = blocking_error
- .map(|blocking_error| {
- try_firewall_policy_error_from_i32(
- blocking_error.r#type,
- blocking_error.lock_pid,
- blocking_error.lock_name,
- )
- })
- .transpose()?;
-
- MullvadState::Error(talpid_tunnel::ErrorState::new(cause, block_failure))
- }
- _ => {
- return Err(FromProtobufTypeError::InvalidArgument(
- "invalid tunnel state",
- ))
- }
- };
-
- Ok(state)
- }
-}
-
-impl TryFrom<proto::TunnelEndpoint> for talpid_types::net::TunnelEndpoint {
- type Error = FromProtobufTypeError;
-
- fn try_from(endpoint: proto::TunnelEndpoint) -> Result<Self, Self::Error> {
- use talpid_types::net as talpid_net;
-
- Ok(talpid_net::TunnelEndpoint {
- endpoint: talpid_net::Endpoint {
- address: arg_from_str(&endpoint.address, "invalid endpoint address")?,
- protocol: try_transport_protocol_from_i32(endpoint.protocol)?,
- },
- tunnel_type: try_tunnel_type_from_i32(endpoint.tunnel_type)?,
- quantum_resistant: endpoint.quantum_resistant,
- proxy: endpoint
- .proxy
- .map(|proxy_ep| {
- Ok(talpid_net::proxy::ProxyEndpoint {
- endpoint: talpid_net::Endpoint {
- address: arg_from_str(
- &proxy_ep.address,
- "invalid proxy endpoint address",
- )?,
- protocol: try_transport_protocol_from_i32(proxy_ep.protocol)?,
- },
- proxy_type: match proto::ProxyType::from_i32(proxy_ep.proxy_type) {
- Some(proto::ProxyType::Shadowsocks) => {
- talpid_net::proxy::ProxyType::Shadowsocks
- }
- Some(proto::ProxyType::Custom) => talpid_net::proxy::ProxyType::Custom,
- None => {
- return Err(FromProtobufTypeError::InvalidArgument(
- "unknown proxy type",
- ))
- }
- },
- })
- })
- .transpose()?,
- obfuscation: endpoint
- .obfuscation
- .map(|obfs_ep| {
- Ok(talpid_net::ObfuscationEndpoint {
- endpoint: talpid_net::Endpoint {
- address: SocketAddr::new(
- arg_from_str(
- &obfs_ep.address,
- "invalid obfuscation endpoint address",
- )?,
- obfs_ep.port as u16,
- ),
- protocol: try_transport_protocol_from_i32(obfs_ep.protocol)?,
- },
- obfuscation_type: match proto::ObfuscationType::from_i32(
- obfs_ep.obfuscation_type,
- ) {
- Some(proto::ObfuscationType::Udp2tcp) => {
- talpid_net::ObfuscationType::Udp2Tcp
- }
- None => {
- return Err(FromProtobufTypeError::InvalidArgument(
- "unknown obfuscation type",
- ))
- }
- },
- })
- })
- .transpose()?,
- entry_endpoint: endpoint
- .entry_endpoint
- .map(|entry| {
- Ok(talpid_net::Endpoint {
- address: arg_from_str(&entry.address, "invalid entry endpoint address")?,
- protocol: try_transport_protocol_from_i32(entry.protocol)?,
- })
- })
- .transpose()?,
- })
- }
-}
-
-impl From<mullvad_types::device::Device> for proto::Device {
- fn from(device: mullvad_types::device::Device) -> Self {
- proto::Device {
- id: device.id,
- name: device.name,
- pubkey: device.pubkey.as_bytes().to_vec(),
- ports: device
- .ports
- .into_iter()
- .map(proto::DevicePort::from)
- .collect(),
- hijack_dns: device.hijack_dns,
- created: Some(Timestamp {
- seconds: device.created.timestamp(),
- nanos: 0,
- }),
- }
- }
-}
-
-impl From<mullvad_types::device::DevicePort> for proto::DevicePort {
- fn from(port: mullvad_types::device::DevicePort) -> Self {
- proto::DevicePort { id: port.id }
- }
-}
-
-impl From<mullvad_types::device::DeviceState> for proto::DeviceState {
- fn from(state: mullvad_types::device::DeviceState) -> Self {
- proto::DeviceState {
- state: proto::device_state::State::from(&state) as i32,
- device: state.into_device().map(|device| proto::AccountAndDevice {
- account_token: device.account_token,
- device: Some(proto::Device::from(device.device)),
- }),
- }
- }
-}
-
-impl From<&mullvad_types::device::DeviceState> for proto::device_state::State {
- fn from(state: &mullvad_types::device::DeviceState) -> Self {
- use mullvad_types::device::DeviceState as MullvadState;
- match state {
- MullvadState::LoggedIn(_) => proto::device_state::State::LoggedIn,
- MullvadState::LoggedOut => proto::device_state::State::LoggedOut,
- MullvadState::Revoked => proto::device_state::State::Revoked,
- }
- }
-}
-
-impl From<mullvad_types::device::DeviceEvent> for proto::DeviceEvent {
- fn from(event: mullvad_types::device::DeviceEvent) -> Self {
- proto::DeviceEvent {
- cause: proto::device_event::Cause::from(event.cause) as i32,
- new_state: Some(proto::DeviceState::from(event.new_state)),
- }
- }
-}
-
-impl From<mullvad_types::device::DeviceEventCause> for proto::device_event::Cause {
- fn from(cause: mullvad_types::device::DeviceEventCause) -> Self {
- use mullvad_types::device::DeviceEventCause as MullvadEvent;
- match cause {
- MullvadEvent::LoggedIn => proto::device_event::Cause::LoggedIn,
- MullvadEvent::LoggedOut => proto::device_event::Cause::LoggedOut,
- MullvadEvent::Revoked => proto::device_event::Cause::Revoked,
- MullvadEvent::Updated => proto::device_event::Cause::Updated,
- MullvadEvent::RotatedKey => proto::device_event::Cause::RotatedKey,
- }
- }
-}
-
-impl From<mullvad_types::device::RemoveDeviceEvent> for proto::RemoveDeviceEvent {
- fn from(event: mullvad_types::device::RemoveDeviceEvent) -> Self {
- proto::RemoveDeviceEvent {
- account_token: event.account_token,
- new_device_list: event
- .new_devices
- .into_iter()
- .map(proto::Device::from)
- .collect(),
- }
- }
-}
-
-impl From<mullvad_types::device::AccountAndDevice> for proto::AccountAndDevice {
- fn from(device: mullvad_types::device::AccountAndDevice) -> Self {
- proto::AccountAndDevice {
- account_token: device.account_token,
- device: Some(proto::Device::from(device.device)),
- }
- }
-}
-
-impl From<Vec<mullvad_types::device::Device>> for proto::DeviceList {
- fn from(devices: Vec<mullvad_types::device::Device>) -> Self {
- proto::DeviceList {
- devices: devices.into_iter().map(proto::Device::from).collect(),
- }
- }
-}
-
-impl From<mullvad_types::wireguard::PublicKey> for proto::PublicKey {
- fn from(public_key: mullvad_types::wireguard::PublicKey) -> Self {
- proto::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 proto::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 proto::ConnectionConfig {
- fn from(config: mullvad_types::ConnectionConfig) -> Self {
- use proto::connection_config;
-
- 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(proto::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(),
- }),
- 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 proto::TransportProtocol {
- fn from(protocol: talpid_types::net::TransportProtocol) -> Self {
- match protocol {
- talpid_types::net::TransportProtocol::Udp => proto::TransportProtocol::Udp,
- talpid_types::net::TransportProtocol::Tcp => proto::TransportProtocol::Tcp,
- }
- }
-}
-
-impl From<talpid_types::net::IpVersion> for proto::IpVersion {
- fn from(version: talpid_types::net::IpVersion) -> Self {
- match version {
- talpid_types::net::IpVersion::V4 => proto::IpVersion::V4,
- talpid_types::net::IpVersion::V6 => proto::IpVersion::V6,
- }
- }
-}
-
-impl From<proto::IpVersion> for proto::IpVersionConstraint {
- fn from(version: proto::IpVersion) -> Self {
- Self {
- protocol: i32::from(version),
- }
- }
-}
-
-impl From<mullvad_types::relay_constraints::TransportPort> for proto::TransportPort {
- fn from(port: mullvad_types::relay_constraints::TransportPort) -> Self {
- proto::TransportPort {
- protocol: proto::TransportProtocol::from(port.protocol) as i32,
- port: port.port.map(u32::from).unwrap_or(0),
- }
- }
-}
-
-impl
- From<
- mullvad_types::relay_constraints::Constraint<
- mullvad_types::relay_constraints::LocationConstraint,
- >,
- > for proto::RelayLocation
-{
- fn from(
- location: mullvad_types::relay_constraints::Constraint<
- mullvad_types::relay_constraints::LocationConstraint,
- >,
- ) -> Self {
- location
- .option()
- .map(proto::RelayLocation::from)
- .unwrap_or_default()
- }
-}
-
-impl From<mullvad_types::relay_constraints::LocationConstraint> for proto::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 proto::Settings {
- fn from(settings: &mullvad_types::settings::Settings) -> Self {
- #[cfg(windows)]
- let split_tunnel = {
- let mut converted_list = vec![];
- for path in settings.split_tunnel.apps.clone().iter() {
- match path.as_path().as_os_str().to_str() {
- Some(path) => converted_list.push(path.to_string()),
- None => {
- log::error!("failed to convert OS string: {:?}", path);
- }
- }
- }
-
- Some(proto::SplitTunnelSettings {
- enable_exclusions: settings.split_tunnel.enable_exclusions,
- apps: converted_list,
- })
- };
- #[cfg(not(windows))]
- let split_tunnel = None;
-
- Self {
- relay_settings: Some(proto::RelaySettings::from(settings.get_relay_settings())),
- bridge_settings: Some(proto::BridgeSettings::from(
- settings.bridge_settings.clone(),
- )),
- bridge_state: Some(proto::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(proto::TunnelOptions::from(&settings.tunnel_options)),
- show_beta_releases: settings.show_beta_releases,
- obfuscation_settings: Some(proto::ObfuscationSettings::from(
- &settings.obfuscation_settings,
- )),
- split_tunnel,
- }
- }
-}
-
-impl From<mullvad_types::relay_constraints::BridgeState> for proto::BridgeState {
- fn from(state: mullvad_types::relay_constraints::BridgeState) -> Self {
- use mullvad_types::relay_constraints::BridgeState;
- Self {
- state: i32::from(match state {
- BridgeState::Auto => proto::bridge_state::State::Auto,
- BridgeState::On => proto::bridge_state::State::On,
- BridgeState::Off => proto::bridge_state::State::Off,
- }),
- }
- }
-}
-
-impl From<&mullvad_types::relay_constraints::ObfuscationSettings> for proto::ObfuscationSettings {
- fn from(settings: &mullvad_types::relay_constraints::ObfuscationSettings) -> Self {
- use mullvad_types::relay_constraints::SelectedObfuscation;
- let selected_obfuscation = i32::from(match settings.selected_obfuscation {
- SelectedObfuscation::Auto => proto::obfuscation_settings::SelectedObfuscation::Auto,
- SelectedObfuscation::Off => proto::obfuscation_settings::SelectedObfuscation::Off,
- SelectedObfuscation::Udp2Tcp => {
- proto::obfuscation_settings::SelectedObfuscation::Udp2tcp
- }
- });
- Self {
- selected_obfuscation,
- udp2tcp: Some(proto::Udp2TcpObfuscationSettings::from(&settings.udp2tcp)),
- }
- }
-}
-
-impl From<&mullvad_types::relay_constraints::Udp2TcpObfuscationSettings>
- for proto::Udp2TcpObfuscationSettings
-{
- fn from(settings: &mullvad_types::relay_constraints::Udp2TcpObfuscationSettings) -> Self {
- Self {
- port: u32::from(settings.port.unwrap_or(0)),
- }
- }
-}
-
-impl From<mullvad_types::relay_constraints::BridgeSettings> for proto::BridgeSettings {
- fn from(settings: mullvad_types::relay_constraints::BridgeSettings) -> Self {
- use mullvad_types::relay_constraints::BridgeSettings as MullvadBridgeSettings;
- use proto::bridge_settings;
- 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(proto::RelayLocation::from),
- providers: convert_providers_constraint(&constraints.providers),
- ownership: convert_ownership_constraint(&constraints.ownership) as i32,
- })
- }
- 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,
- })
- }
- },
- };
-
- proto::BridgeSettings {
- r#type: Some(settings),
- }
- }
-}
-
-impl From<mullvad_types::relay_constraints::RelaySettings> for proto::RelaySettings {
- fn from(settings: mullvad_types::relay_constraints::RelaySettings) -> Self {
- use mullvad_types::relay_constraints::RelaySettings as MullvadRelaySettings;
- use proto::relay_settings;
- use talpid_types::net as talpid_net;
-
- let endpoint = match settings {
- MullvadRelaySettings::CustomTunnelEndpoint(endpoint) => {
- relay_settings::Endpoint::Custom(proto::CustomRelaySettings {
- host: endpoint.host,
- config: Some(proto::ConnectionConfig::from(endpoint.config)),
- })
- }
- MullvadRelaySettings::Normal(constraints) => {
- relay_settings::Endpoint::Normal(proto::NormalRelaySettings {
- location: constraints
- .location
- .option()
- .map(proto::RelayLocation::from),
- providers: convert_providers_constraint(&constraints.providers),
- ownership: convert_ownership_constraint(&constraints.ownership) as i32,
- tunnel_type: match constraints.tunnel_protocol {
- Constraint::Any => None,
- Constraint::Only(talpid_net::TunnelType::Wireguard) => {
- Some(proto::TunnelType::Wireguard)
- }
- Constraint::Only(talpid_net::TunnelType::OpenVpn) => {
- Some(proto::TunnelType::Openvpn)
- }
- }
- .map(|tunnel_type| proto::TunnelTypeConstraint {
- tunnel_type: i32::from(tunnel_type),
- }),
-
- wireguard_constraints: Some(proto::WireguardConstraints {
- port: u32::from(constraints.wireguard_constraints.port.unwrap_or(0)),
- ip_version: constraints
- .wireguard_constraints
- .ip_version
- .option()
- .map(proto::IpVersion::from)
- .map(proto::IpVersionConstraint::from),
- use_multihop: constraints.wireguard_constraints.use_multihop,
- entry_location: constraints
- .wireguard_constraints
- .entry_location
- .option()
- .map(proto::RelayLocation::from),
- }),
-
- openvpn_constraints: Some(proto::OpenvpnConstraints {
- port: constraints
- .openvpn_constraints
- .port
- .option()
- .map(proto::TransportPort::from),
- }),
- })
- }
- };
-
- Self {
- endpoint: Some(endpoint),
- }
- }
-}
-
-impl From<&mullvad_types::settings::DnsOptions> for proto::DnsOptions {
- fn from(options: &mullvad_types::settings::DnsOptions) -> Self {
- use proto::dns_options;
-
- proto::DnsOptions {
- state: match options.state {
- mullvad_types::settings::DnsState::Default => dns_options::DnsState::Default as i32,
- mullvad_types::settings::DnsState::Custom => dns_options::DnsState::Custom as i32,
- },
- default_options: Some(proto::DefaultDnsOptions {
- block_ads: options.default_options.block_ads,
- block_trackers: options.default_options.block_trackers,
- block_malware: options.default_options.block_malware,
- block_adult_content: options.default_options.block_adult_content,
- block_gambling: options.default_options.block_gambling,
- }),
- custom_options: Some(proto::CustomDnsOptions {
- addresses: options
- .custom_options
- .addresses
- .iter()
- .map(|addr| addr.to_string())
- .collect(),
- }),
- }
- }
-}
-
-impl From<&mullvad_types::settings::TunnelOptions> for proto::TunnelOptions {
- fn from(options: &mullvad_types::settings::TunnelOptions) -> Self {
- Self {
- openvpn: Some(proto::tunnel_options::OpenvpnOptions {
- mssfix: u32::from(options.openvpn.mssfix.unwrap_or_default()),
- }),
- wireguard: Some(proto::tunnel_options::WireguardOptions {
- mtu: u32::from(options.wireguard.options.mtu.unwrap_or_default()),
- rotation_interval: options.wireguard.rotation_interval.map(|ivl| {
- prost_types::Duration::try_from(std::time::Duration::from(ivl))
- .expect("Failed to convert std::time::Duration to prost_types::Duration for tunnel_options.wireguard.rotation_interval")
- }),
- #[cfg(windows)]
- use_wireguard_nt: options.wireguard.options.use_wireguard_nt,
- #[cfg(not(windows))]
- use_wireguard_nt: false,
- use_pq_safe_psk: options.wireguard.options.use_pq_safe_psk,
- }),
- generic: Some(proto::tunnel_options::GenericOptions {
- enable_ipv6: options.generic.enable_ipv6,
- }),
- #[cfg(not(target_os = "android"))]
- dns_options: Some(proto::DnsOptions::from(&options.dns_options)),
- #[cfg(target_os = "android")]
- dns_options: None,
- }
- }
-}
-
-impl From<mullvad_types::relay_list::RelayList> for proto::RelayList {
- fn from(relay_list: mullvad_types::relay_list::RelayList) -> Self {
- let mut proto_list = proto::RelayList {
- countries: vec![],
- openvpn: Some(proto::OpenVpnEndpointData::from(relay_list.openvpn)),
- bridge: Some(proto::BridgeEndpointData::from(relay_list.bridge)),
- wireguard: Some(proto::WireguardEndpointData::from(relay_list.wireguard)),
- };
- proto_list.countries = relay_list
- .countries
- .into_iter()
- .map(proto::RelayListCountry::from)
- .collect();
- proto_list
- }
-}
-
-impl From<mullvad_types::relay_list::OpenVpnEndpointData> for proto::OpenVpnEndpointData {
- fn from(openvpn: mullvad_types::relay_list::OpenVpnEndpointData) -> Self {
- proto::OpenVpnEndpointData {
- endpoints: openvpn
- .ports
- .into_iter()
- .map(|endpoint| proto::OpenVpnEndpoint {
- port: u32::from(endpoint.port),
- protocol: proto::TransportProtocol::from(endpoint.protocol) as i32,
- })
- .collect(),
- }
- }
-}
-
-impl From<mullvad_types::relay_list::BridgeEndpointData> for proto::BridgeEndpointData {
- fn from(bridge: mullvad_types::relay_list::BridgeEndpointData) -> Self {
- proto::BridgeEndpointData {
- shadowsocks: bridge
- .shadowsocks
- .into_iter()
- .map(|endpoint| proto::ShadowsocksEndpointData {
- port: u32::from(endpoint.port),
- cipher: endpoint.cipher,
- password: endpoint.password,
- protocol: proto::TransportProtocol::from(endpoint.protocol) as i32,
- })
- .collect(),
- }
- }
-}
-
-impl From<mullvad_types::relay_list::WireguardEndpointData> for proto::WireguardEndpointData {
- fn from(wireguard: mullvad_types::relay_list::WireguardEndpointData) -> Self {
- proto::WireguardEndpointData {
- port_ranges: wireguard
- .port_ranges
- .into_iter()
- .map(|(first, last)| proto::PortRange {
- first: u32::from(first),
- last: u32::from(last),
- })
- .collect(),
- ipv4_gateway: wireguard.ipv4_gateway.to_string(),
- ipv6_gateway: wireguard.ipv6_gateway.to_string(),
- udp2tcp_ports: wireguard.udp2tcp_ports.into_iter().map(u32::from).collect(),
- }
- }
-}
-
-impl From<mullvad_types::relay_list::RelayListCountry> for proto::RelayListCountry {
- fn from(country: mullvad_types::relay_list::RelayListCountry) -> Self {
- let mut proto_country = proto::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(proto::RelayListCity {
- name: city.name,
- code: city.code,
- latitude: city.latitude,
- longitude: city.longitude,
- relays: city.relays.into_iter().map(proto::Relay::from).collect(),
- });
- }
-
- proto_country
- }
-}
-
-impl From<mullvad_types::relay_list::Relay> for proto::Relay {
- fn from(relay: mullvad_types::relay_list::Relay) -> Self {
- use mullvad_types::relay_list::RelayEndpointData as MullvadEndpointData;
-
- 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,
- endpoint_type: match &relay.endpoint_data {
- MullvadEndpointData::Openvpn => proto::relay::RelayType::Openvpn as i32,
- MullvadEndpointData::Bridge => proto::relay::RelayType::Bridge as i32,
- MullvadEndpointData::Wireguard(_) => proto::relay::RelayType::Wireguard as i32,
- },
- endpoint_data: match relay.endpoint_data {
- MullvadEndpointData::Wireguard(data) => Some(to_proto_any(
- "mullvad_daemon.management_interface/WireguardRelayEndpointData",
- proto::WireguardRelayEndpointData {
- public_key: data.public_key.as_bytes().to_vec(),
- },
- )),
- _ => None,
- },
- location: relay.location.map(|location| proto::Location {
- country: location.country,
- country_code: location.country_code,
- city: location.city,
- city_code: location.city_code,
- latitude: location.latitude,
- longitude: location.longitude,
- }),
- }
- }
-}
-
-impl TryFrom<proto::Relay> for mullvad_types::relay_list::Relay {
- type Error = FromProtobufTypeError;
-
- fn try_from(relay: proto::Relay) -> Result<Self, Self::Error> {
- use mullvad_types::{
- location::Location as MullvadLocation,
- relay_list::{Relay as MullvadRelay, RelayEndpointData as MullvadEndpointData},
- };
-
- let endpoint_data = match relay.endpoint_type {
- i if i == proto::relay::RelayType::Openvpn as i32 => MullvadEndpointData::Openvpn,
- i if i == proto::relay::RelayType::Bridge as i32 => MullvadEndpointData::Bridge,
- i if i == proto::relay::RelayType::Wireguard as i32 => {
- let data = relay
- .endpoint_data
- .ok_or(FromProtobufTypeError::InvalidArgument(
- "missing endpoint wg data",
- ))?;
- let data: proto::WireguardRelayEndpointData = try_from_proto_any(
- "mullvad_daemon.management_interface/WireguardRelayEndpointData",
- data,
- )
- .ok_or(FromProtobufTypeError::InvalidArgument(
- "invalid endpoint wg data",
- ))?;
- MullvadEndpointData::Wireguard(
- mullvad_types::relay_list::WireguardRelayEndpointData {
- public_key: bytes_to_pubkey(&data.public_key)?,
- },
- )
- }
- _ => {
- return Err(FromProtobufTypeError::InvalidArgument(
- "invalid relay endpoint type",
- ))
- }
- };
-
- let ipv6_addr_in = option_from_proto_string(relay.ipv6_addr_in)
- .map(|addr| {
- addr.parse().map_err(|_err| {
- FromProtobufTypeError::InvalidArgument("invalid relay IPv6 address")
- })
- })
- .transpose()?;
-
- Ok(MullvadRelay {
- hostname: relay.hostname,
- ipv4_addr_in: relay.ipv4_addr_in.parse().map_err(|_err| {
- FromProtobufTypeError::InvalidArgument("invalid relay IPv4 address")
- })?,
- ipv6_addr_in,
- include_in_country: relay.include_in_country,
- active: relay.active,
- owned: relay.owned,
- provider: relay.provider,
- weight: relay.weight,
- endpoint_data,
- location: relay.location.map(|location| MullvadLocation {
- country: location.country,
- country_code: location.country_code,
- city: location.city,
- city_code: location.city_code,
- latitude: location.latitude,
- longitude: location.longitude,
- }),
- })
- }
-}
-
-impl From<proto::TransportProtocol> for talpid_types::net::TransportProtocol {
- fn from(protocol: proto::TransportProtocol) -> Self {
- match protocol {
- proto::TransportProtocol::Udp => talpid_types::net::TransportProtocol::Udp,
- proto::TransportProtocol::Tcp => talpid_types::net::TransportProtocol::Tcp,
- }
- }
-}
+mod custom_tunnel;
+mod device;
+mod location;
+mod net;
+pub mod relay_constraints;
+mod relay_list;
+mod settings;
+mod states;
+mod version;
+mod wireguard;
#[derive(Debug)]
pub enum FromProtobufTypeError {
InvalidArgument(&'static str),
}
-impl TryFrom<proto::Device> for mullvad_types::device::Device {
- type Error = FromProtobufTypeError;
-
- fn try_from(device: proto::Device) -> Result<Self, Self::Error> {
- Ok(mullvad_types::device::Device {
- id: device.id,
- name: device.name,
- pubkey: bytes_to_pubkey(&device.pubkey)?,
- ports: device
- .ports
- .into_iter()
- .map(mullvad_types::device::DevicePort::from)
- .collect(),
- hijack_dns: device.hijack_dns,
- created: chrono::DateTime::from_utc(
- chrono::NaiveDateTime::from_timestamp(
- device
- .created
- .ok_or(FromProtobufTypeError::InvalidArgument(
- "missing 'created' field",
- ))?
- .seconds,
- 0,
- ),
- chrono::Utc,
- ),
- })
- }
-}
-
-impl From<proto::DevicePort> for mullvad_types::device::DevicePort {
- fn from(port: proto::DevicePort) -> Self {
- mullvad_types::device::DevicePort { id: port.id }
- }
-}
-
-impl TryFrom<&proto::WireguardConstraints>
- for mullvad_types::relay_constraints::WireguardConstraints
-{
- type Error = FromProtobufTypeError;
-
- fn try_from(
- constraints: &proto::WireguardConstraints,
- ) -> Result<mullvad_types::relay_constraints::WireguardConstraints, Self::Error> {
- use mullvad_types::relay_constraints as mullvad_constraints;
- use talpid_types::net;
-
- let ip_version = match &constraints.ip_version {
- Some(constraint) => match proto::IpVersion::from_i32(constraint.protocol) {
- Some(proto::IpVersion::V4) => Some(net::IpVersion::V4),
- Some(proto::IpVersion::V6) => Some(net::IpVersion::V6),
- None => {
- return Err(FromProtobufTypeError::InvalidArgument(
- "invalid ip protocol version",
- ))
- }
- },
- None => None,
- };
-
- Ok(mullvad_constraints::WireguardConstraints {
- port: if constraints.port == 0 {
- Constraint::Any
- } else {
- Constraint::Only(constraints.port as u16)
- },
- ip_version: Constraint::from(ip_version),
- use_multihop: constraints.use_multihop,
- entry_location: constraints
- .entry_location
- .clone()
- .map(Constraint::<mullvad_types::relay_constraints::LocationConstraint>::from)
- .unwrap_or(Constraint::Any),
- })
- }
-}
-
-impl TryFrom<&proto::OpenvpnConstraints> for mullvad_types::relay_constraints::OpenVpnConstraints {
- type Error = FromProtobufTypeError;
-
- fn try_from(
- constraints: &proto::OpenvpnConstraints,
- ) -> Result<mullvad_types::relay_constraints::OpenVpnConstraints, Self::Error> {
- use mullvad_types::relay_constraints as mullvad_constraints;
-
- Ok(mullvad_constraints::OpenVpnConstraints {
- port: Constraint::from(match &constraints.port {
- Some(port) => Some(mullvad_constraints::TransportPort::try_from(port.clone())?),
- None => None,
- }),
- })
- }
-}
-
-impl TryFrom<proto::RelaySettings> for mullvad_types::relay_constraints::RelaySettings {
- type Error = FromProtobufTypeError;
-
- fn try_from(
- settings: proto::RelaySettings,
- ) -> Result<mullvad_types::relay_constraints::RelaySettings, Self::Error> {
- use mullvad_types::{relay_constraints as mullvad_constraints, CustomTunnelEndpoint};
- use talpid_types::net;
-
- let update_value = settings
- .endpoint
- .ok_or(FromProtobufTypeError::InvalidArgument(
- "missing relay settings",
- ))?;
-
- match update_value {
- proto::relay_settings::Endpoint::Custom(settings) => {
- let config = settings
- .config
- .ok_or(FromProtobufTypeError::InvalidArgument(
- "missing relay connection config",
- ))?;
- let config = mullvad_types::ConnectionConfig::try_from(config)?;
- Ok(mullvad_constraints::RelaySettings::CustomTunnelEndpoint(
- CustomTunnelEndpoint {
- host: settings.host,
- config,
- },
- ))
- }
-
- proto::relay_settings::Endpoint::Normal(settings) => {
- let location = settings
- .location
- .map(Constraint::<mullvad_types::relay_constraints::LocationConstraint>::from)
- .unwrap_or(Constraint::Any);
- let providers = try_providers_constraint_from_proto(&settings.providers)?;
- let ownership = try_ownership_constraint_from_i32(settings.ownership)?;
- let tunnel_protocol = settings
- .tunnel_type
- .map(Constraint::<net::TunnelType>::try_from)
- .transpose()?
- .unwrap_or(Constraint::Any);
- let openvpn_constraints =
- mullvad_constraints::OpenVpnConstraints::try_from(
- &settings.openvpn_constraints.ok_or(
- FromProtobufTypeError::InvalidArgument("missing openvpn constraints"),
- )?,
- )?;
- let wireguard_constraints = mullvad_constraints::WireguardConstraints::try_from(
- &settings.wireguard_constraints.ok_or(
- FromProtobufTypeError::InvalidArgument("missing wireguard constraints"),
- )?,
- )?;
-
- Ok(mullvad_constraints::RelaySettings::Normal(
- mullvad_constraints::RelayConstraints {
- location,
- providers,
- ownership,
- tunnel_protocol,
- wireguard_constraints,
- openvpn_constraints,
- },
- ))
- }
- }
- }
-}
-
-impl TryFrom<proto::RelaySettingsUpdate> for mullvad_types::relay_constraints::RelaySettingsUpdate {
- type Error = FromProtobufTypeError;
-
- fn try_from(
- settings: proto::RelaySettingsUpdate,
- ) -> Result<mullvad_types::relay_constraints::RelaySettingsUpdate, Self::Error> {
- use mullvad_types::{relay_constraints as mullvad_constraints, CustomTunnelEndpoint};
- use talpid_types::net;
-
- let update_value = settings
- .r#type
- .ok_or(FromProtobufTypeError::InvalidArgument(
- "missing relay settings",
- ))?;
-
- match update_value {
- proto::relay_settings_update::Type::Custom(settings) => {
- let config = settings
- .config
- .ok_or(FromProtobufTypeError::InvalidArgument(
- "missing relay connection config",
- ))?;
- let config = mullvad_types::ConnectionConfig::try_from(config)?;
- Ok(
- mullvad_constraints::RelaySettingsUpdate::CustomTunnelEndpoint(
- CustomTunnelEndpoint {
- host: settings.host,
- config,
- },
- ),
- )
- }
-
- proto::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 providers = if let Some(ref provider_update) = settings.providers {
- Some(try_providers_constraint_from_proto(
- &provider_update.providers,
- )?)
- } else {
- None
- };
- let ownership = if let Some(ref ownership_update) = settings.ownership {
- Some(try_ownership_constraint_from_i32(
- ownership_update.ownership,
- )?)
- } else {
- None
- };
- let tunnel_protocol = if let Some(update) = settings.tunnel_type {
- Some(
- update
- .tunnel_type
- .map(Constraint::<net::TunnelType>::try_from)
- .transpose()?
- .unwrap_or(Constraint::Any),
- )
- } else {
- None
- };
- let openvpn_constraints =
- if let Some(ref constraints) = settings.openvpn_constraints {
- Some(mullvad_constraints::OpenVpnConstraints::try_from(
- constraints,
- )?)
- } else {
- None
- };
- let wireguard_constraints =
- if let Some(ref constraints) = settings.wireguard_constraints {
- Some(mullvad_constraints::WireguardConstraints::try_from(
- constraints,
- )?)
- } else {
- None
- };
- Ok(mullvad_constraints::RelaySettingsUpdate::Normal(
- mullvad_constraints::RelayConstraintsUpdate {
- location,
- providers,
- ownership,
- tunnel_protocol,
- wireguard_constraints,
- openvpn_constraints,
- },
- ))
- }
- }
- }
-}
-
-impl TryFrom<proto::TunnelTypeConstraint> for Constraint<talpid_types::net::TunnelType> {
- type Error = FromProtobufTypeError;
-
- fn try_from(
- tunnel_type: proto::TunnelTypeConstraint,
- ) -> Result<Constraint<talpid_types::net::TunnelType>, Self::Error> {
- let tunnel_type = try_tunnel_type_from_i32(tunnel_type.tunnel_type)?;
- Ok(Constraint::Only(tunnel_type))
- }
-}
-
-impl TryFrom<proto::ConnectionConfig> for mullvad_types::ConnectionConfig {
- type Error = FromProtobufTypeError;
-
- fn try_from(
- config: proto::ConnectionConfig,
- ) -> Result<mullvad_types::ConnectionConfig, Self::Error> {
- use talpid_types::net::{self, openvpn};
-
- let config = config.config.ok_or(FromProtobufTypeError::InvalidArgument(
- "missing connection config",
- ))?;
- match config {
- proto::connection_config::Config::Openvpn(config) => {
- let address = match config.address.parse() {
- Ok(address) => address,
- Err(_) => {
- return Err(FromProtobufTypeError::InvalidArgument("invalid address"))
- }
- };
-
- Ok(mullvad_types::ConnectionConfig::OpenVpn(
- openvpn::ConnectionConfig {
- endpoint: net::Endpoint {
- address,
- protocol: try_transport_protocol_from_i32(config.protocol)?,
- },
- username: config.username,
- password: config.password,
- },
- ))
- }
- proto::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",
- ))?;
-
- let public_key = bytes_to_pubkey(&peer.public_key)?;
-
- let ipv4_gateway = config.ipv4_gateway.parse().map_err(|_err| {
- FromProtobufTypeError::InvalidArgument("invalid IPv4 gateway")
- })?;
- let ipv6_gateway = option_from_proto_string(config.ipv6_gateway)
- .map(|addr| {
- addr.parse().map_err(|_err| {
- FromProtobufTypeError::InvalidArgument("invalid IPv6 gateway")
- })
- })
- .transpose()?;
-
- let endpoint = peer.endpoint.parse().map_err(|_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);
- }
-
- Ok(mullvad_types::ConnectionConfig::Wireguard(
- wireguard::ConnectionConfig {
- tunnel: wireguard::TunnelConfig {
- private_key: wireguard::PrivateKey::from(private_key),
- addresses: tunnel_addresses,
- },
- peer: wireguard::PeerConfig {
- public_key,
- allowed_ips,
- endpoint,
- psk: None,
- },
- exit_peer: None,
- ipv4_gateway,
- ipv6_gateway,
- },
- ))
- }
- }
- }
-}
-
-fn bytes_to_pubkey(bytes: &[u8]) -> Result<wireguard::PublicKey, FromProtobufTypeError> {
- if bytes.len() != 32 {
- return Err(FromProtobufTypeError::InvalidArgument("invalid public key"));
- }
- let mut public_key = [0; 32];
- public_key.copy_from_slice(&bytes[..32]);
- Ok(wireguard::PublicKey::from(public_key))
-}
-
-impl From<proto::RelayLocation>
- for Constraint<mullvad_types::relay_constraints::LocationConstraint>
-{
- fn from(location: proto::RelayLocation) -> Self {
- use mullvad_types::relay_constraints::LocationConstraint;
-
- if let Some(hostname) = option_from_proto_string(location.hostname) {
- Constraint::Only(LocationConstraint::Hostname(
- location.country,
- location.city,
- hostname,
- ))
- } else if let Some(city) = option_from_proto_string(location.city) {
- Constraint::Only(LocationConstraint::City(location.country, city))
- } else if let Some(country) = option_from_proto_string(location.country) {
- Constraint::Only(LocationConstraint::Country(country))
- } else {
- Constraint::Any
- }
- }
-}
-
-impl TryFrom<proto::BridgeSettings> for mullvad_types::relay_constraints::BridgeSettings {
- type Error = FromProtobufTypeError;
-
- fn try_from(settings: proto::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",
- ))? {
- proto::bridge_settings::Type::Normal(constraints) => {
- let location = match constraints.location {
- None => Constraint::Any,
- Some(location) => {
- Constraint::<mullvad_constraints::LocationConstraint>::from(location)
- }
- };
- let providers = try_providers_constraint_from_proto(&constraints.providers)?;
- let ownership = try_ownership_constraint_from_i32(constraints.ownership)?;
-
- Ok(mullvad_constraints::BridgeSettings::Normal(
- mullvad_constraints::BridgeConstraints {
- location,
- providers,
- ownership,
- },
- ))
- }
- proto::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))
- }
- proto::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))
- }
- proto::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<proto::ObfuscationSettings> for mullvad_types::relay_constraints::ObfuscationSettings {
- type Error = FromProtobufTypeError;
-
- fn try_from(settings: proto::ObfuscationSettings) -> Result<Self, Self::Error> {
- use mullvad_types::relay_constraints::SelectedObfuscation;
- use proto::obfuscation_settings::SelectedObfuscation as IpcSelectedObfuscation;
- let selected_obfuscation =
- match IpcSelectedObfuscation::from_i32(settings.selected_obfuscation) {
- Some(IpcSelectedObfuscation::Auto) => SelectedObfuscation::Auto,
- Some(IpcSelectedObfuscation::Off) => SelectedObfuscation::Off,
- Some(IpcSelectedObfuscation::Udp2tcp) => SelectedObfuscation::Udp2Tcp,
- None => {
- return Err(FromProtobufTypeError::InvalidArgument(
- "invalid selected obfuscator",
- ));
- }
- };
-
- let udp2tcp = match settings.udp2tcp {
- Some(settings) => {
- mullvad_types::relay_constraints::Udp2TcpObfuscationSettings::try_from(&settings)?
- }
- None => {
- return Err(FromProtobufTypeError::InvalidArgument(
- "invalid selected obfuscator",
- ));
- }
- };
-
- Ok(Self {
- selected_obfuscation,
- udp2tcp,
- })
- }
-}
-
-impl TryFrom<&proto::Udp2TcpObfuscationSettings>
- for mullvad_types::relay_constraints::Udp2TcpObfuscationSettings
-{
- type Error = FromProtobufTypeError;
-
- fn try_from(settings: &proto::Udp2TcpObfuscationSettings) -> Result<Self, Self::Error> {
- Ok(Self {
- port: if settings.port == 0 {
- Constraint::Any
- } else {
- Constraint::Only(settings.port as u16)
- },
- })
- }
-}
-
-impl TryFrom<proto::BridgeState> for mullvad_types::relay_constraints::BridgeState {
- type Error = FromProtobufTypeError;
-
- fn try_from(state: proto::BridgeState) -> Result<Self, Self::Error> {
- match proto::bridge_state::State::from_i32(state.state) {
- Some(proto::bridge_state::State::Auto) => {
- Ok(mullvad_types::relay_constraints::BridgeState::Auto)
- }
- Some(proto::bridge_state::State::On) => {
- Ok(mullvad_types::relay_constraints::BridgeState::On)
- }
- Some(proto::bridge_state::State::Off) => {
- Ok(mullvad_types::relay_constraints::BridgeState::Off)
- }
- None => Err(FromProtobufTypeError::InvalidArgument(
- "invalid bridge state",
- )),
- }
- }
-}
-
-impl TryFrom<proto::TunnelOptions> for mullvad_types::settings::TunnelOptions {
- type Error = FromProtobufTypeError;
-
- fn try_from(options: proto::TunnelOptions) -> Result<Self, Self::Error> {
- use talpid_types::net;
-
- let openvpn_options = options
- .openvpn
- .ok_or(FromProtobufTypeError::InvalidArgument(
- "missing openvpn tunnel options",
- ))?;
- let wireguard_options = options
- .wireguard
- .ok_or(FromProtobufTypeError::InvalidArgument(
- "missing openvpn tunnel options",
- ))?;
- let generic_options = options
- .generic
- .ok_or(FromProtobufTypeError::InvalidArgument(
- "missing generic tunnel options",
- ))?;
- let dns_options = options
- .dns_options
- .ok_or(FromProtobufTypeError::InvalidArgument(
- "missing tunnel DNS options",
- ))?;
-
- Ok(Self {
- openvpn: net::openvpn::TunnelOptions {
- mssfix: if openvpn_options.mssfix != 0 {
- Some(openvpn_options.mssfix as u16)
- } else {
- None
- },
- },
- wireguard: mullvad_types::wireguard::TunnelOptions {
- options: net::wireguard::TunnelOptions {
- mtu: if wireguard_options.mtu != 0 {
- Some(wireguard_options.mtu as u16)
- } else {
- None
- },
- use_pq_safe_psk: wireguard_options.use_pq_safe_psk,
- #[cfg(windows)]
- use_wireguard_nt: wireguard_options.use_wireguard_nt,
- },
- rotation_interval: wireguard_options
- .rotation_interval
- .map(std::time::Duration::try_from)
- .transpose()
- .map_err(|_| FromProtobufTypeError::InvalidArgument("invalid duration"))?
- .map(mullvad_types::wireguard::RotationInterval::try_from)
- .transpose()
- .map_err(|error: mullvad_types::wireguard::RotationIntervalError| {
- log::error!(
- "{}",
- error.display_chain_with_msg("Invalid rotation interval")
- );
- FromProtobufTypeError::InvalidArgument("invalid rotation interval")
- })?,
- },
- generic: net::GenericTunnelOptions {
- enable_ipv6: generic_options.enable_ipv6,
- },
- #[cfg(not(target_os = "android"))]
- dns_options: mullvad_types::settings::DnsOptions::try_from(dns_options)?,
- })
- }
+fn bytes_to_pubkey(
+ bytes: &[u8],
+) -> Result<talpid_types::net::wireguard::PublicKey, FromProtobufTypeError> {
+ Ok(talpid_types::net::wireguard::PublicKey::from(
+ *bytes_to_wg_key(bytes, "invalid public key")?,
+ ))
}
-impl TryFrom<proto::DnsOptions> for mullvad_types::settings::DnsOptions {
- type Error = FromProtobufTypeError;
-
- fn try_from(options: proto::DnsOptions) -> Result<Self, Self::Error> {
- use mullvad_types::settings::{
- CustomDnsOptions as MullvadCustomDnsOptions,
- DefaultDnsOptions as MullvadDefaultDnsOptions, DnsOptions as MullvadDnsOptions,
- DnsState as MullvadDnsState,
- };
-
- let state = match proto::dns_options::DnsState::from_i32(options.state) {
- Some(proto::dns_options::DnsState::Default) => MullvadDnsState::Default,
- Some(proto::dns_options::DnsState::Custom) => MullvadDnsState::Custom,
- None => {
- return Err(FromProtobufTypeError::InvalidArgument(
- "invalid DNS options state",
- ))
- }
- };
-
- let default_options =
- options
- .default_options
- .ok_or(FromProtobufTypeError::InvalidArgument(
- "missing default DNS options",
- ))?;
- let custom_options =
- options
- .custom_options
- .ok_or(FromProtobufTypeError::InvalidArgument(
- "missing default DNS options",
- ))?;
-
- Ok(MullvadDnsOptions {
- state,
- default_options: MullvadDefaultDnsOptions {
- block_ads: default_options.block_ads,
- block_trackers: default_options.block_trackers,
- block_malware: default_options.block_malware,
- block_adult_content: default_options.block_adult_content,
- block_gambling: default_options.block_gambling,
- },
- custom_options: MullvadCustomDnsOptions {
- addresses: custom_options
- .addresses
- .into_iter()
- .map(|addr| {
- addr.parse().map_err(|_| {
- FromProtobufTypeError::InvalidArgument("invalid IP address")
- })
- })
- .collect::<Result<Vec<_>, _>>()?,
- },
- })
- }
+fn bytes_to_privkey(
+ bytes: &[u8],
+) -> Result<talpid_types::net::wireguard::PrivateKey, FromProtobufTypeError> {
+ Ok(talpid_types::net::wireguard::PrivateKey::from(
+ *bytes_to_wg_key(bytes, "invalid private key")?,
+ ))
}
-impl TryFrom<proto::TransportPort> for mullvad_types::relay_constraints::TransportPort {
- type Error = FromProtobufTypeError;
-
- fn try_from(port: proto::TransportPort) -> Result<Self, Self::Error> {
- Ok(mullvad_types::relay_constraints::TransportPort {
- protocol: try_transport_protocol_from_i32(port.protocol)?,
- port: if port.port == 0 {
- Constraint::Any
- } else {
- Constraint::Only(port.port as u16)
- },
- })
- }
-}
-
-fn try_tunnel_type_from_i32(
- tunnel_type: i32,
-) -> Result<talpid_types::net::TunnelType, FromProtobufTypeError> {
- match proto::TunnelType::from_i32(tunnel_type) {
- Some(proto::TunnelType::Openvpn) => Ok(talpid_types::net::TunnelType::OpenVpn),
- Some(proto::TunnelType::Wireguard) => Ok(talpid_types::net::TunnelType::Wireguard),
- None => Err(FromProtobufTypeError::InvalidArgument(
- "invalid tunnel protocol",
- )),
- }
+fn bytes_to_wg_key<'a>(
+ bytes: &'a [u8],
+ error_msg: &'static str,
+) -> Result<&'a [u8; 32], FromProtobufTypeError> {
+ <&[u8; 32]>::try_from(bytes).map_err(|_| FromProtobufTypeError::InvalidArgument(error_msg))
}
/// Returns `Option<String>`, where an empty string represents `None`.
@@ -1902,103 +54,6 @@ fn arg_from_str<T: FromStr<Err = E>, E>(
T::from_str(s).map_err(|_err| FromProtobufTypeError::InvalidArgument(invalid_arg_msg))
}
-fn try_transport_protocol_from_i32(
- protocol: i32,
-) -> Result<talpid_types::net::TransportProtocol, FromProtobufTypeError> {
- Ok(proto::TransportProtocol::from_i32(protocol)
- .ok_or(FromProtobufTypeError::InvalidArgument(
- "invalid transport protocol",
- ))?
- .into())
-}
-
-#[cfg_attr(not(target_os = "windows"), allow(unused_variables))]
-fn try_firewall_policy_error_from_i32(
- policy_error: i32,
- lock_pid: u32,
- lock_name: String,
-) -> Result<talpid_types::tunnel::FirewallPolicyError, FromProtobufTypeError> {
- match proto::error_state::firewall_policy_error::ErrorType::from_i32(policy_error) {
- Some(proto::error_state::firewall_policy_error::ErrorType::Generic) => {
- Ok(talpid_types::tunnel::FirewallPolicyError::Generic)
- }
- #[cfg(windows)]
- Some(proto::error_state::firewall_policy_error::ErrorType::Locked) => {
- let blocking_app = option_from_proto_string(lock_name).map(|name| {
- talpid_types::tunnel::BlockingApplication {
- pid: lock_pid,
- name,
- }
- });
- Ok(talpid_types::tunnel::FirewallPolicyError::Locked(
- blocking_app,
- ))
- }
- _ => Err(FromProtobufTypeError::InvalidArgument(
- "invalid firewall policy error",
- )),
- }
-}
-
-pub fn try_providers_constraint_from_proto(
- providers: &[String],
-) -> Result<Constraint<mullvad_types::relay_constraints::Providers>, FromProtobufTypeError> {
- if !providers.is_empty() {
- Ok(Constraint::Only(
- mullvad_types::relay_constraints::Providers::new(providers.iter().cloned()).map_err(
- |_| FromProtobufTypeError::InvalidArgument("must specify at least one provider"),
- )?,
- ))
- } else {
- Ok(Constraint::Any)
- }
-}
-
-pub fn try_ownership_constraint_from_i32(
- ownership: i32,
-) -> Result<Constraint<mullvad_types::relay_constraints::Ownership>, FromProtobufTypeError> {
- proto::Ownership::from_i32(ownership)
- .map(ownership_constraint_from_proto)
- .ok_or(FromProtobufTypeError::InvalidArgument(
- "invalid ownership argument",
- ))
-}
-
-pub fn ownership_constraint_from_proto(
- ownership: proto::Ownership,
-) -> Constraint<mullvad_types::relay_constraints::Ownership> {
- use mullvad_types::relay_constraints::Ownership as MullvadOwnership;
-
- match ownership {
- proto::Ownership::Any => Constraint::Any,
- proto::Ownership::MullvadOwned => Constraint::Only(MullvadOwnership::MullvadOwned),
- proto::Ownership::Rented => Constraint::Only(MullvadOwnership::Rented),
- }
-}
-
-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()),
- }
-}
-
-fn convert_ownership_constraint(
- ownership: &Constraint<mullvad_types::relay_constraints::Ownership>,
-) -> proto::Ownership {
- use mullvad_types::relay_constraints::Ownership as MullvadOwnership;
-
- match ownership.as_ref() {
- Constraint::Any => proto::Ownership::Any,
- Constraint::Only(ownership) => match ownership {
- MullvadOwnership::MullvadOwned => proto::Ownership::MullvadOwned,
- MullvadOwnership::Rented => proto::Ownership::Rented,
- },
- }
-}
-
impl From<FromProtobufTypeError> for crate::Status {
fn from(err: FromProtobufTypeError) -> Self {
match err {
diff --git a/mullvad-management-interface/src/types/conversions/net.rs b/mullvad-management-interface/src/types/conversions/net.rs
new file mode 100644
index 0000000000..96210c02e3
--- /dev/null
+++ b/mullvad-management-interface/src/types/conversions/net.rs
@@ -0,0 +1,191 @@
+use crate::types::{conversions::arg_from_str, proto, FromProtobufTypeError};
+use mullvad_types::relay_constraints::Constraint;
+use std::net::SocketAddr;
+
+impl From<talpid_types::net::TunnelEndpoint> for proto::TunnelEndpoint {
+ fn from(endpoint: talpid_types::net::TunnelEndpoint) -> Self {
+ use talpid_types::net;
+
+ proto::TunnelEndpoint {
+ address: endpoint.endpoint.address.to_string(),
+ protocol: i32::from(proto::TransportProtocol::from(endpoint.endpoint.protocol)),
+ tunnel_type: match endpoint.tunnel_type {
+ net::TunnelType::Wireguard => i32::from(proto::TunnelType::Wireguard),
+ net::TunnelType::OpenVpn => i32::from(proto::TunnelType::Openvpn),
+ },
+ quantum_resistant: endpoint.quantum_resistant,
+ proxy: endpoint.proxy.map(|proxy_ep| proto::ProxyEndpoint {
+ address: proxy_ep.endpoint.address.to_string(),
+ protocol: i32::from(proto::TransportProtocol::from(proxy_ep.endpoint.protocol)),
+ proxy_type: match proxy_ep.proxy_type {
+ net::proxy::ProxyType::Shadowsocks => i32::from(proto::ProxyType::Shadowsocks),
+ net::proxy::ProxyType::Custom => i32::from(proto::ProxyType::Custom),
+ },
+ }),
+ obfuscation: endpoint.obfuscation.map(|obfuscation_endpoint| {
+ proto::ObfuscationEndpoint {
+ address: obfuscation_endpoint.endpoint.address.ip().to_string(),
+ port: u32::from(obfuscation_endpoint.endpoint.address.port()),
+ protocol: i32::from(proto::TransportProtocol::from(
+ obfuscation_endpoint.endpoint.protocol,
+ )),
+ obfuscation_type: match obfuscation_endpoint.obfuscation_type {
+ net::ObfuscationType::Udp2Tcp => i32::from(proto::ObfuscationType::Udp2tcp),
+ },
+ }
+ }),
+ entry_endpoint: endpoint.entry_endpoint.map(|entry| proto::Endpoint {
+ address: entry.address.to_string(),
+ protocol: i32::from(proto::TransportProtocol::from(entry.protocol)),
+ }),
+ }
+ }
+}
+
+impl TryFrom<proto::TunnelEndpoint> for talpid_types::net::TunnelEndpoint {
+ type Error = FromProtobufTypeError;
+
+ fn try_from(endpoint: proto::TunnelEndpoint) -> Result<Self, Self::Error> {
+ use talpid_types::net as talpid_net;
+
+ Ok(talpid_net::TunnelEndpoint {
+ endpoint: talpid_net::Endpoint {
+ address: arg_from_str(&endpoint.address, "invalid endpoint address")?,
+ protocol: try_transport_protocol_from_i32(endpoint.protocol)?,
+ },
+ tunnel_type: try_tunnel_type_from_i32(endpoint.tunnel_type)?,
+ quantum_resistant: endpoint.quantum_resistant,
+ proxy: endpoint
+ .proxy
+ .map(|proxy_ep| {
+ Ok(talpid_net::proxy::ProxyEndpoint {
+ endpoint: talpid_net::Endpoint {
+ address: arg_from_str(
+ &proxy_ep.address,
+ "invalid proxy endpoint address",
+ )?,
+ protocol: try_transport_protocol_from_i32(proxy_ep.protocol)?,
+ },
+ proxy_type: match proto::ProxyType::from_i32(proxy_ep.proxy_type) {
+ Some(proto::ProxyType::Shadowsocks) => {
+ talpid_net::proxy::ProxyType::Shadowsocks
+ }
+ Some(proto::ProxyType::Custom) => talpid_net::proxy::ProxyType::Custom,
+ None => {
+ return Err(FromProtobufTypeError::InvalidArgument(
+ "unknown proxy type",
+ ))
+ }
+ },
+ })
+ })
+ .transpose()?,
+ obfuscation: endpoint
+ .obfuscation
+ .map(|obfs_ep| {
+ Ok(talpid_net::ObfuscationEndpoint {
+ endpoint: talpid_net::Endpoint {
+ address: SocketAddr::new(
+ arg_from_str(
+ &obfs_ep.address,
+ "invalid obfuscation endpoint address",
+ )?,
+ obfs_ep.port as u16,
+ ),
+ protocol: try_transport_protocol_from_i32(obfs_ep.protocol)?,
+ },
+ obfuscation_type: match proto::ObfuscationType::from_i32(
+ obfs_ep.obfuscation_type,
+ ) {
+ Some(proto::ObfuscationType::Udp2tcp) => {
+ talpid_net::ObfuscationType::Udp2Tcp
+ }
+ None => {
+ return Err(FromProtobufTypeError::InvalidArgument(
+ "unknown obfuscation type",
+ ))
+ }
+ },
+ })
+ })
+ .transpose()?,
+ entry_endpoint: endpoint
+ .entry_endpoint
+ .map(|entry| {
+ Ok(talpid_net::Endpoint {
+ address: arg_from_str(&entry.address, "invalid entry endpoint address")?,
+ protocol: try_transport_protocol_from_i32(entry.protocol)?,
+ })
+ })
+ .transpose()?,
+ })
+ }
+}
+
+impl From<talpid_types::net::TransportProtocol> for proto::TransportProtocol {
+ fn from(protocol: talpid_types::net::TransportProtocol) -> Self {
+ match protocol {
+ talpid_types::net::TransportProtocol::Udp => proto::TransportProtocol::Udp,
+ talpid_types::net::TransportProtocol::Tcp => proto::TransportProtocol::Tcp,
+ }
+ }
+}
+
+impl From<talpid_types::net::IpVersion> for proto::IpVersion {
+ fn from(version: talpid_types::net::IpVersion) -> Self {
+ match version {
+ talpid_types::net::IpVersion::V4 => proto::IpVersion::V4,
+ talpid_types::net::IpVersion::V6 => proto::IpVersion::V6,
+ }
+ }
+}
+
+impl From<proto::TransportProtocol> for talpid_types::net::TransportProtocol {
+ fn from(protocol: proto::TransportProtocol) -> Self {
+ match protocol {
+ proto::TransportProtocol::Udp => talpid_types::net::TransportProtocol::Udp,
+ proto::TransportProtocol::Tcp => talpid_types::net::TransportProtocol::Tcp,
+ }
+ }
+}
+
+impl TryFrom<proto::TunnelTypeConstraint> for Constraint<talpid_types::net::TunnelType> {
+ type Error = FromProtobufTypeError;
+
+ fn try_from(
+ tunnel_type: proto::TunnelTypeConstraint,
+ ) -> Result<Constraint<talpid_types::net::TunnelType>, Self::Error> {
+ let tunnel_type = try_tunnel_type_from_i32(tunnel_type.tunnel_type)?;
+ Ok(Constraint::Only(tunnel_type))
+ }
+}
+
+impl From<proto::IpVersion> for proto::IpVersionConstraint {
+ fn from(version: proto::IpVersion) -> Self {
+ Self {
+ protocol: i32::from(version),
+ }
+ }
+}
+
+pub fn try_tunnel_type_from_i32(
+ tunnel_type: i32,
+) -> Result<talpid_types::net::TunnelType, FromProtobufTypeError> {
+ match proto::TunnelType::from_i32(tunnel_type) {
+ Some(proto::TunnelType::Openvpn) => Ok(talpid_types::net::TunnelType::OpenVpn),
+ Some(proto::TunnelType::Wireguard) => Ok(talpid_types::net::TunnelType::Wireguard),
+ None => Err(FromProtobufTypeError::InvalidArgument(
+ "invalid tunnel protocol",
+ )),
+ }
+}
+
+pub fn try_transport_protocol_from_i32(
+ protocol: i32,
+) -> Result<talpid_types::net::TransportProtocol, FromProtobufTypeError> {
+ Ok(proto::TransportProtocol::from_i32(protocol)
+ .ok_or(FromProtobufTypeError::InvalidArgument(
+ "invalid transport protocol",
+ ))?
+ .into())
+}
diff --git a/mullvad-management-interface/src/types/conversions/relay_constraints.rs b/mullvad-management-interface/src/types/conversions/relay_constraints.rs
new file mode 100644
index 0000000000..d76006bf7f
--- /dev/null
+++ b/mullvad-management-interface/src/types/conversions/relay_constraints.rs
@@ -0,0 +1,679 @@
+use crate::types::{conversions::option_from_proto_string, proto, FromProtobufTypeError};
+use mullvad_types::relay_constraints::Constraint;
+
+impl TryFrom<&proto::WireguardConstraints>
+ for mullvad_types::relay_constraints::WireguardConstraints
+{
+ type Error = FromProtobufTypeError;
+
+ fn try_from(
+ constraints: &proto::WireguardConstraints,
+ ) -> Result<mullvad_types::relay_constraints::WireguardConstraints, Self::Error> {
+ use mullvad_types::relay_constraints as mullvad_constraints;
+ use talpid_types::net;
+
+ let ip_version = match &constraints.ip_version {
+ Some(constraint) => match proto::IpVersion::from_i32(constraint.protocol) {
+ Some(proto::IpVersion::V4) => Some(net::IpVersion::V4),
+ Some(proto::IpVersion::V6) => Some(net::IpVersion::V6),
+ None => {
+ return Err(FromProtobufTypeError::InvalidArgument(
+ "invalid ip protocol version",
+ ))
+ }
+ },
+ None => None,
+ };
+
+ Ok(mullvad_constraints::WireguardConstraints {
+ port: if constraints.port == 0 {
+ Constraint::Any
+ } else {
+ Constraint::Only(constraints.port as u16)
+ },
+ ip_version: Constraint::from(ip_version),
+ use_multihop: constraints.use_multihop,
+ entry_location: constraints
+ .entry_location
+ .clone()
+ .map(Constraint::<mullvad_types::relay_constraints::LocationConstraint>::from)
+ .unwrap_or(Constraint::Any),
+ })
+ }
+}
+
+impl TryFrom<&proto::OpenvpnConstraints> for mullvad_types::relay_constraints::OpenVpnConstraints {
+ type Error = FromProtobufTypeError;
+
+ fn try_from(
+ constraints: &proto::OpenvpnConstraints,
+ ) -> Result<mullvad_types::relay_constraints::OpenVpnConstraints, Self::Error> {
+ use mullvad_types::relay_constraints as mullvad_constraints;
+
+ Ok(mullvad_constraints::OpenVpnConstraints {
+ port: Constraint::from(match &constraints.port {
+ Some(port) => Some(mullvad_constraints::TransportPort::try_from(port.clone())?),
+ None => None,
+ }),
+ })
+ }
+}
+
+impl TryFrom<proto::RelaySettings> for mullvad_types::relay_constraints::RelaySettings {
+ type Error = FromProtobufTypeError;
+
+ fn try_from(
+ settings: proto::RelaySettings,
+ ) -> Result<mullvad_types::relay_constraints::RelaySettings, Self::Error> {
+ use mullvad_types::{relay_constraints as mullvad_constraints, CustomTunnelEndpoint};
+ use talpid_types::net;
+
+ let update_value = settings
+ .endpoint
+ .ok_or(FromProtobufTypeError::InvalidArgument(
+ "missing relay settings",
+ ))?;
+
+ match update_value {
+ proto::relay_settings::Endpoint::Custom(settings) => {
+ let config = settings
+ .config
+ .ok_or(FromProtobufTypeError::InvalidArgument(
+ "missing relay connection config",
+ ))?;
+ let config = mullvad_types::ConnectionConfig::try_from(config)?;
+ Ok(mullvad_constraints::RelaySettings::CustomTunnelEndpoint(
+ CustomTunnelEndpoint {
+ host: settings.host,
+ config,
+ },
+ ))
+ }
+
+ proto::relay_settings::Endpoint::Normal(settings) => {
+ let location = settings
+ .location
+ .map(Constraint::<mullvad_types::relay_constraints::LocationConstraint>::from)
+ .unwrap_or(Constraint::Any);
+ let providers = try_providers_constraint_from_proto(&settings.providers)?;
+ let ownership = try_ownership_constraint_from_i32(settings.ownership)?;
+ let tunnel_protocol = settings
+ .tunnel_type
+ .map(Constraint::<net::TunnelType>::try_from)
+ .transpose()?
+ .unwrap_or(Constraint::Any);
+ let openvpn_constraints =
+ mullvad_constraints::OpenVpnConstraints::try_from(
+ &settings.openvpn_constraints.ok_or(
+ FromProtobufTypeError::InvalidArgument("missing openvpn constraints"),
+ )?,
+ )?;
+ let wireguard_constraints = mullvad_constraints::WireguardConstraints::try_from(
+ &settings.wireguard_constraints.ok_or(
+ FromProtobufTypeError::InvalidArgument("missing wireguard constraints"),
+ )?,
+ )?;
+
+ Ok(mullvad_constraints::RelaySettings::Normal(
+ mullvad_constraints::RelayConstraints {
+ location,
+ providers,
+ ownership,
+ tunnel_protocol,
+ wireguard_constraints,
+ openvpn_constraints,
+ },
+ ))
+ }
+ }
+ }
+}
+
+impl TryFrom<proto::RelaySettingsUpdate> for mullvad_types::relay_constraints::RelaySettingsUpdate {
+ type Error = FromProtobufTypeError;
+
+ fn try_from(
+ settings: proto::RelaySettingsUpdate,
+ ) -> Result<mullvad_types::relay_constraints::RelaySettingsUpdate, Self::Error> {
+ use mullvad_types::{relay_constraints as mullvad_constraints, CustomTunnelEndpoint};
+ use talpid_types::net;
+
+ let update_value = settings
+ .r#type
+ .ok_or(FromProtobufTypeError::InvalidArgument(
+ "missing relay settings",
+ ))?;
+
+ match update_value {
+ proto::relay_settings_update::Type::Custom(settings) => {
+ let config = settings
+ .config
+ .ok_or(FromProtobufTypeError::InvalidArgument(
+ "missing relay connection config",
+ ))?;
+ let config = mullvad_types::ConnectionConfig::try_from(config)?;
+ Ok(
+ mullvad_constraints::RelaySettingsUpdate::CustomTunnelEndpoint(
+ CustomTunnelEndpoint {
+ host: settings.host,
+ config,
+ },
+ ),
+ )
+ }
+
+ proto::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 providers = if let Some(ref provider_update) = settings.providers {
+ Some(try_providers_constraint_from_proto(
+ &provider_update.providers,
+ )?)
+ } else {
+ None
+ };
+ let ownership = if let Some(ref ownership_update) = settings.ownership {
+ Some(try_ownership_constraint_from_i32(
+ ownership_update.ownership,
+ )?)
+ } else {
+ None
+ };
+ let tunnel_protocol = if let Some(update) = settings.tunnel_type {
+ Some(
+ update
+ .tunnel_type
+ .map(Constraint::<net::TunnelType>::try_from)
+ .transpose()?
+ .unwrap_or(Constraint::Any),
+ )
+ } else {
+ None
+ };
+ let openvpn_constraints =
+ if let Some(ref constraints) = settings.openvpn_constraints {
+ Some(mullvad_constraints::OpenVpnConstraints::try_from(
+ constraints,
+ )?)
+ } else {
+ None
+ };
+ let wireguard_constraints =
+ if let Some(ref constraints) = settings.wireguard_constraints {
+ Some(mullvad_constraints::WireguardConstraints::try_from(
+ constraints,
+ )?)
+ } else {
+ None
+ };
+ Ok(mullvad_constraints::RelaySettingsUpdate::Normal(
+ mullvad_constraints::RelayConstraintsUpdate {
+ location,
+ providers,
+ ownership,
+ tunnel_protocol,
+ wireguard_constraints,
+ openvpn_constraints,
+ },
+ ))
+ }
+ }
+ }
+}
+
+impl From<mullvad_types::relay_constraints::BridgeState> for proto::BridgeState {
+ fn from(state: mullvad_types::relay_constraints::BridgeState) -> Self {
+ use mullvad_types::relay_constraints::BridgeState;
+ Self {
+ state: i32::from(match state {
+ BridgeState::Auto => proto::bridge_state::State::Auto,
+ BridgeState::On => proto::bridge_state::State::On,
+ BridgeState::Off => proto::bridge_state::State::Off,
+ }),
+ }
+ }
+}
+
+impl From<&mullvad_types::relay_constraints::ObfuscationSettings> for proto::ObfuscationSettings {
+ fn from(settings: &mullvad_types::relay_constraints::ObfuscationSettings) -> Self {
+ use mullvad_types::relay_constraints::SelectedObfuscation;
+ let selected_obfuscation = i32::from(match settings.selected_obfuscation {
+ SelectedObfuscation::Auto => proto::obfuscation_settings::SelectedObfuscation::Auto,
+ SelectedObfuscation::Off => proto::obfuscation_settings::SelectedObfuscation::Off,
+ SelectedObfuscation::Udp2Tcp => {
+ proto::obfuscation_settings::SelectedObfuscation::Udp2tcp
+ }
+ });
+ Self {
+ selected_obfuscation,
+ udp2tcp: Some(proto::Udp2TcpObfuscationSettings::from(&settings.udp2tcp)),
+ }
+ }
+}
+
+impl From<&mullvad_types::relay_constraints::Udp2TcpObfuscationSettings>
+ for proto::Udp2TcpObfuscationSettings
+{
+ fn from(settings: &mullvad_types::relay_constraints::Udp2TcpObfuscationSettings) -> Self {
+ Self {
+ port: u32::from(settings.port.unwrap_or(0)),
+ }
+ }
+}
+
+impl From<mullvad_types::relay_constraints::BridgeSettings> for proto::BridgeSettings {
+ fn from(settings: mullvad_types::relay_constraints::BridgeSettings) -> Self {
+ use mullvad_types::relay_constraints::BridgeSettings as MullvadBridgeSettings;
+ use proto::bridge_settings;
+ 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(proto::RelayLocation::from),
+ providers: convert_providers_constraint(&constraints.providers),
+ ownership: convert_ownership_constraint(&constraints.ownership) as i32,
+ })
+ }
+ 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,
+ })
+ }
+ },
+ };
+
+ proto::BridgeSettings {
+ r#type: Some(settings),
+ }
+ }
+}
+
+impl From<mullvad_types::relay_constraints::RelaySettings> for proto::RelaySettings {
+ fn from(settings: mullvad_types::relay_constraints::RelaySettings) -> Self {
+ use mullvad_types::relay_constraints::RelaySettings as MullvadRelaySettings;
+ use proto::relay_settings;
+ use talpid_types::net as talpid_net;
+
+ let endpoint = match settings {
+ MullvadRelaySettings::CustomTunnelEndpoint(endpoint) => {
+ relay_settings::Endpoint::Custom(proto::CustomRelaySettings {
+ host: endpoint.host,
+ config: Some(proto::ConnectionConfig::from(endpoint.config)),
+ })
+ }
+ MullvadRelaySettings::Normal(constraints) => {
+ relay_settings::Endpoint::Normal(proto::NormalRelaySettings {
+ location: constraints
+ .location
+ .option()
+ .map(proto::RelayLocation::from),
+ providers: convert_providers_constraint(&constraints.providers),
+ ownership: convert_ownership_constraint(&constraints.ownership) as i32,
+ tunnel_type: match constraints.tunnel_protocol {
+ Constraint::Any => None,
+ Constraint::Only(talpid_net::TunnelType::Wireguard) => {
+ Some(proto::TunnelType::Wireguard)
+ }
+ Constraint::Only(talpid_net::TunnelType::OpenVpn) => {
+ Some(proto::TunnelType::Openvpn)
+ }
+ }
+ .map(|tunnel_type| proto::TunnelTypeConstraint {
+ tunnel_type: i32::from(tunnel_type),
+ }),
+
+ wireguard_constraints: Some(proto::WireguardConstraints {
+ port: u32::from(constraints.wireguard_constraints.port.unwrap_or(0)),
+ ip_version: constraints
+ .wireguard_constraints
+ .ip_version
+ .option()
+ .map(proto::IpVersion::from)
+ .map(proto::IpVersionConstraint::from),
+ use_multihop: constraints.wireguard_constraints.use_multihop,
+ entry_location: constraints
+ .wireguard_constraints
+ .entry_location
+ .option()
+ .map(proto::RelayLocation::from),
+ }),
+
+ openvpn_constraints: Some(proto::OpenvpnConstraints {
+ port: constraints
+ .openvpn_constraints
+ .port
+ .option()
+ .map(proto::TransportPort::from),
+ }),
+ })
+ }
+ };
+
+ Self {
+ endpoint: Some(endpoint),
+ }
+ }
+}
+
+impl From<mullvad_types::relay_constraints::TransportPort> for proto::TransportPort {
+ fn from(port: mullvad_types::relay_constraints::TransportPort) -> Self {
+ proto::TransportPort {
+ protocol: proto::TransportProtocol::from(port.protocol) as i32,
+ port: port.port.map(u32::from).unwrap_or(0),
+ }
+ }
+}
+
+impl
+ From<
+ mullvad_types::relay_constraints::Constraint<
+ mullvad_types::relay_constraints::LocationConstraint,
+ >,
+ > for proto::RelayLocation
+{
+ fn from(
+ location: mullvad_types::relay_constraints::Constraint<
+ mullvad_types::relay_constraints::LocationConstraint,
+ >,
+ ) -> Self {
+ location
+ .option()
+ .map(proto::RelayLocation::from)
+ .unwrap_or_default()
+ }
+}
+
+impl From<mullvad_types::relay_constraints::LocationConstraint> for proto::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<proto::RelayLocation>
+ for Constraint<mullvad_types::relay_constraints::LocationConstraint>
+{
+ fn from(location: proto::RelayLocation) -> Self {
+ use mullvad_types::relay_constraints::LocationConstraint;
+
+ if let Some(hostname) = option_from_proto_string(location.hostname) {
+ Constraint::Only(LocationConstraint::Hostname(
+ location.country,
+ location.city,
+ hostname,
+ ))
+ } else if let Some(city) = option_from_proto_string(location.city) {
+ Constraint::Only(LocationConstraint::City(location.country, city))
+ } else if let Some(country) = option_from_proto_string(location.country) {
+ Constraint::Only(LocationConstraint::Country(country))
+ } else {
+ Constraint::Any
+ }
+ }
+}
+
+impl TryFrom<proto::BridgeSettings> for mullvad_types::relay_constraints::BridgeSettings {
+ type Error = FromProtobufTypeError;
+
+ fn try_from(settings: proto::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",
+ ))? {
+ proto::bridge_settings::Type::Normal(constraints) => {
+ let location = match constraints.location {
+ None => Constraint::Any,
+ Some(location) => {
+ Constraint::<mullvad_constraints::LocationConstraint>::from(location)
+ }
+ };
+ let providers = try_providers_constraint_from_proto(&constraints.providers)?;
+ let ownership = try_ownership_constraint_from_i32(constraints.ownership)?;
+
+ Ok(mullvad_constraints::BridgeSettings::Normal(
+ mullvad_constraints::BridgeConstraints {
+ location,
+ providers,
+ ownership,
+ },
+ ))
+ }
+ proto::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))
+ }
+ proto::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))
+ }
+ proto::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<proto::ObfuscationSettings> for mullvad_types::relay_constraints::ObfuscationSettings {
+ type Error = FromProtobufTypeError;
+
+ fn try_from(settings: proto::ObfuscationSettings) -> Result<Self, Self::Error> {
+ use mullvad_types::relay_constraints::SelectedObfuscation;
+ use proto::obfuscation_settings::SelectedObfuscation as IpcSelectedObfuscation;
+ let selected_obfuscation =
+ match IpcSelectedObfuscation::from_i32(settings.selected_obfuscation) {
+ Some(IpcSelectedObfuscation::Auto) => SelectedObfuscation::Auto,
+ Some(IpcSelectedObfuscation::Off) => SelectedObfuscation::Off,
+ Some(IpcSelectedObfuscation::Udp2tcp) => SelectedObfuscation::Udp2Tcp,
+ None => {
+ return Err(FromProtobufTypeError::InvalidArgument(
+ "invalid selected obfuscator",
+ ));
+ }
+ };
+
+ let udp2tcp = match settings.udp2tcp {
+ Some(settings) => {
+ mullvad_types::relay_constraints::Udp2TcpObfuscationSettings::try_from(&settings)?
+ }
+ None => {
+ return Err(FromProtobufTypeError::InvalidArgument(
+ "invalid selected obfuscator",
+ ));
+ }
+ };
+
+ Ok(Self {
+ selected_obfuscation,
+ udp2tcp,
+ })
+ }
+}
+
+impl TryFrom<&proto::Udp2TcpObfuscationSettings>
+ for mullvad_types::relay_constraints::Udp2TcpObfuscationSettings
+{
+ type Error = FromProtobufTypeError;
+
+ fn try_from(settings: &proto::Udp2TcpObfuscationSettings) -> Result<Self, Self::Error> {
+ Ok(Self {
+ port: if settings.port == 0 {
+ Constraint::Any
+ } else {
+ Constraint::Only(settings.port as u16)
+ },
+ })
+ }
+}
+
+impl TryFrom<proto::BridgeState> for mullvad_types::relay_constraints::BridgeState {
+ type Error = FromProtobufTypeError;
+
+ fn try_from(state: proto::BridgeState) -> Result<Self, Self::Error> {
+ match proto::bridge_state::State::from_i32(state.state) {
+ Some(proto::bridge_state::State::Auto) => {
+ Ok(mullvad_types::relay_constraints::BridgeState::Auto)
+ }
+ Some(proto::bridge_state::State::On) => {
+ Ok(mullvad_types::relay_constraints::BridgeState::On)
+ }
+ Some(proto::bridge_state::State::Off) => {
+ Ok(mullvad_types::relay_constraints::BridgeState::Off)
+ }
+ None => Err(FromProtobufTypeError::InvalidArgument(
+ "invalid bridge state",
+ )),
+ }
+ }
+}
+
+impl TryFrom<proto::TransportPort> for mullvad_types::relay_constraints::TransportPort {
+ type Error = FromProtobufTypeError;
+
+ fn try_from(port: proto::TransportPort) -> Result<Self, Self::Error> {
+ Ok(mullvad_types::relay_constraints::TransportPort {
+ protocol: super::net::try_transport_protocol_from_i32(port.protocol)?,
+ port: if port.port == 0 {
+ Constraint::Any
+ } else {
+ Constraint::Only(port.port as u16)
+ },
+ })
+ }
+}
+
+pub fn try_providers_constraint_from_proto(
+ providers: &[String],
+) -> Result<Constraint<mullvad_types::relay_constraints::Providers>, FromProtobufTypeError> {
+ if !providers.is_empty() {
+ Ok(Constraint::Only(
+ mullvad_types::relay_constraints::Providers::new(providers.iter().cloned()).map_err(
+ |_| FromProtobufTypeError::InvalidArgument("must specify at least one provider"),
+ )?,
+ ))
+ } else {
+ Ok(Constraint::Any)
+ }
+}
+
+pub fn try_ownership_constraint_from_i32(
+ ownership: i32,
+) -> Result<Constraint<mullvad_types::relay_constraints::Ownership>, FromProtobufTypeError> {
+ proto::Ownership::from_i32(ownership)
+ .map(ownership_constraint_from_proto)
+ .ok_or(FromProtobufTypeError::InvalidArgument(
+ "invalid ownership argument",
+ ))
+}
+
+pub fn ownership_constraint_from_proto(
+ ownership: proto::Ownership,
+) -> Constraint<mullvad_types::relay_constraints::Ownership> {
+ use mullvad_types::relay_constraints::Ownership as MullvadOwnership;
+
+ match ownership {
+ proto::Ownership::Any => Constraint::Any,
+ proto::Ownership::MullvadOwned => Constraint::Only(MullvadOwnership::MullvadOwned),
+ proto::Ownership::Rented => Constraint::Only(MullvadOwnership::Rented),
+ }
+}
+
+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()),
+ }
+}
+
+fn convert_ownership_constraint(
+ ownership: &Constraint<mullvad_types::relay_constraints::Ownership>,
+) -> proto::Ownership {
+ use mullvad_types::relay_constraints::Ownership as MullvadOwnership;
+
+ match ownership.as_ref() {
+ Constraint::Any => proto::Ownership::Any,
+ Constraint::Only(ownership) => match ownership {
+ MullvadOwnership::MullvadOwned => proto::Ownership::MullvadOwned,
+ MullvadOwnership::Rented => proto::Ownership::Rented,
+ },
+ }
+}
diff --git a/mullvad-management-interface/src/types/conversions/relay_list.rs b/mullvad-management-interface/src/types/conversions/relay_list.rs
new file mode 100644
index 0000000000..23f628ad9b
--- /dev/null
+++ b/mullvad-management-interface/src/types/conversions/relay_list.rs
@@ -0,0 +1,205 @@
+use crate::types::{
+ conversions::{bytes_to_pubkey, option_from_proto_string, to_proto_any, try_from_proto_any},
+ proto, FromProtobufTypeError,
+};
+
+impl From<mullvad_types::relay_list::RelayList> for proto::RelayList {
+ fn from(relay_list: mullvad_types::relay_list::RelayList) -> Self {
+ let mut proto_list = proto::RelayList {
+ countries: vec![],
+ openvpn: Some(proto::OpenVpnEndpointData::from(relay_list.openvpn)),
+ bridge: Some(proto::BridgeEndpointData::from(relay_list.bridge)),
+ wireguard: Some(proto::WireguardEndpointData::from(relay_list.wireguard)),
+ };
+ proto_list.countries = relay_list
+ .countries
+ .into_iter()
+ .map(proto::RelayListCountry::from)
+ .collect();
+ proto_list
+ }
+}
+
+impl From<mullvad_types::relay_list::OpenVpnEndpointData> for proto::OpenVpnEndpointData {
+ fn from(openvpn: mullvad_types::relay_list::OpenVpnEndpointData) -> Self {
+ proto::OpenVpnEndpointData {
+ endpoints: openvpn
+ .ports
+ .into_iter()
+ .map(|endpoint| proto::OpenVpnEndpoint {
+ port: u32::from(endpoint.port),
+ protocol: proto::TransportProtocol::from(endpoint.protocol) as i32,
+ })
+ .collect(),
+ }
+ }
+}
+
+impl From<mullvad_types::relay_list::BridgeEndpointData> for proto::BridgeEndpointData {
+ fn from(bridge: mullvad_types::relay_list::BridgeEndpointData) -> Self {
+ proto::BridgeEndpointData {
+ shadowsocks: bridge
+ .shadowsocks
+ .into_iter()
+ .map(|endpoint| proto::ShadowsocksEndpointData {
+ port: u32::from(endpoint.port),
+ cipher: endpoint.cipher,
+ password: endpoint.password,
+ protocol: proto::TransportProtocol::from(endpoint.protocol) as i32,
+ })
+ .collect(),
+ }
+ }
+}
+
+impl From<mullvad_types::relay_list::WireguardEndpointData> for proto::WireguardEndpointData {
+ fn from(wireguard: mullvad_types::relay_list::WireguardEndpointData) -> Self {
+ proto::WireguardEndpointData {
+ port_ranges: wireguard
+ .port_ranges
+ .into_iter()
+ .map(|(first, last)| proto::PortRange {
+ first: u32::from(first),
+ last: u32::from(last),
+ })
+ .collect(),
+ ipv4_gateway: wireguard.ipv4_gateway.to_string(),
+ ipv6_gateway: wireguard.ipv6_gateway.to_string(),
+ udp2tcp_ports: wireguard.udp2tcp_ports.into_iter().map(u32::from).collect(),
+ }
+ }
+}
+
+impl From<mullvad_types::relay_list::RelayListCountry> for proto::RelayListCountry {
+ fn from(country: mullvad_types::relay_list::RelayListCountry) -> Self {
+ let mut proto_country = proto::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(proto::RelayListCity {
+ name: city.name,
+ code: city.code,
+ latitude: city.latitude,
+ longitude: city.longitude,
+ relays: city.relays.into_iter().map(proto::Relay::from).collect(),
+ });
+ }
+
+ proto_country
+ }
+}
+
+impl From<mullvad_types::relay_list::Relay> for proto::Relay {
+ fn from(relay: mullvad_types::relay_list::Relay) -> Self {
+ use mullvad_types::relay_list::RelayEndpointData as MullvadEndpointData;
+
+ 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,
+ endpoint_type: match &relay.endpoint_data {
+ MullvadEndpointData::Openvpn => proto::relay::RelayType::Openvpn as i32,
+ MullvadEndpointData::Bridge => proto::relay::RelayType::Bridge as i32,
+ MullvadEndpointData::Wireguard(_) => proto::relay::RelayType::Wireguard as i32,
+ },
+ endpoint_data: match relay.endpoint_data {
+ MullvadEndpointData::Wireguard(data) => Some(to_proto_any(
+ "mullvad_daemon.management_interface/WireguardRelayEndpointData",
+ proto::WireguardRelayEndpointData {
+ public_key: data.public_key.as_bytes().to_vec(),
+ },
+ )),
+ _ => None,
+ },
+ location: relay.location.map(|location| proto::Location {
+ country: location.country,
+ country_code: location.country_code,
+ city: location.city,
+ city_code: location.city_code,
+ latitude: location.latitude,
+ longitude: location.longitude,
+ }),
+ }
+ }
+}
+
+impl TryFrom<proto::Relay> for mullvad_types::relay_list::Relay {
+ type Error = FromProtobufTypeError;
+
+ fn try_from(relay: proto::Relay) -> Result<Self, Self::Error> {
+ use mullvad_types::{
+ location::Location as MullvadLocation,
+ relay_list::{Relay as MullvadRelay, RelayEndpointData as MullvadEndpointData},
+ };
+
+ let endpoint_data = match relay.endpoint_type {
+ i if i == proto::relay::RelayType::Openvpn as i32 => MullvadEndpointData::Openvpn,
+ i if i == proto::relay::RelayType::Bridge as i32 => MullvadEndpointData::Bridge,
+ i if i == proto::relay::RelayType::Wireguard as i32 => {
+ let data = relay
+ .endpoint_data
+ .ok_or(FromProtobufTypeError::InvalidArgument(
+ "missing endpoint wg data",
+ ))?;
+ let data: proto::WireguardRelayEndpointData = try_from_proto_any(
+ "mullvad_daemon.management_interface/WireguardRelayEndpointData",
+ data,
+ )
+ .ok_or(FromProtobufTypeError::InvalidArgument(
+ "invalid endpoint wg data",
+ ))?;
+ MullvadEndpointData::Wireguard(
+ mullvad_types::relay_list::WireguardRelayEndpointData {
+ public_key: bytes_to_pubkey(&data.public_key)?,
+ },
+ )
+ }
+ _ => {
+ return Err(FromProtobufTypeError::InvalidArgument(
+ "invalid relay endpoint type",
+ ))
+ }
+ };
+
+ let ipv6_addr_in = option_from_proto_string(relay.ipv6_addr_in)
+ .map(|addr| {
+ addr.parse().map_err(|_err| {
+ FromProtobufTypeError::InvalidArgument("invalid relay IPv6 address")
+ })
+ })
+ .transpose()?;
+
+ Ok(MullvadRelay {
+ hostname: relay.hostname,
+ ipv4_addr_in: relay.ipv4_addr_in.parse().map_err(|_err| {
+ FromProtobufTypeError::InvalidArgument("invalid relay IPv4 address")
+ })?,
+ ipv6_addr_in,
+ include_in_country: relay.include_in_country,
+ active: relay.active,
+ owned: relay.owned,
+ provider: relay.provider,
+ weight: relay.weight,
+ endpoint_data,
+ location: relay.location.map(|location| MullvadLocation {
+ country: location.country,
+ country_code: location.country_code,
+ city: location.city,
+ city_code: location.city_code,
+ latitude: location.latitude,
+ longitude: location.longitude,
+ }),
+ })
+ }
+}
diff --git a/mullvad-management-interface/src/types/conversions/settings.rs b/mullvad-management-interface/src/types/conversions/settings.rs
new file mode 100644
index 0000000000..60805d5004
--- /dev/null
+++ b/mullvad-management-interface/src/types/conversions/settings.rs
@@ -0,0 +1,227 @@
+use crate::types::{proto, FromProtobufTypeError};
+use talpid_types::ErrorExt;
+
+impl From<&mullvad_types::settings::Settings> for proto::Settings {
+ fn from(settings: &mullvad_types::settings::Settings) -> Self {
+ #[cfg(windows)]
+ let split_tunnel = {
+ let mut converted_list = vec![];
+ for path in settings.split_tunnel.apps.clone().iter() {
+ match path.as_path().as_os_str().to_str() {
+ Some(path) => converted_list.push(path.to_string()),
+ None => {
+ log::error!("failed to convert OS string: {:?}", path);
+ }
+ }
+ }
+
+ Some(proto::SplitTunnelSettings {
+ enable_exclusions: settings.split_tunnel.enable_exclusions,
+ apps: converted_list,
+ })
+ };
+ #[cfg(not(windows))]
+ let split_tunnel = None;
+
+ Self {
+ relay_settings: Some(proto::RelaySettings::from(settings.get_relay_settings())),
+ bridge_settings: Some(proto::BridgeSettings::from(
+ settings.bridge_settings.clone(),
+ )),
+ bridge_state: Some(proto::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(proto::TunnelOptions::from(&settings.tunnel_options)),
+ show_beta_releases: settings.show_beta_releases,
+ obfuscation_settings: Some(proto::ObfuscationSettings::from(
+ &settings.obfuscation_settings,
+ )),
+ split_tunnel,
+ }
+ }
+}
+
+impl From<&mullvad_types::settings::DnsOptions> for proto::DnsOptions {
+ fn from(options: &mullvad_types::settings::DnsOptions) -> Self {
+ use proto::dns_options;
+
+ proto::DnsOptions {
+ state: match options.state {
+ mullvad_types::settings::DnsState::Default => dns_options::DnsState::Default as i32,
+ mullvad_types::settings::DnsState::Custom => dns_options::DnsState::Custom as i32,
+ },
+ default_options: Some(proto::DefaultDnsOptions {
+ block_ads: options.default_options.block_ads,
+ block_trackers: options.default_options.block_trackers,
+ block_malware: options.default_options.block_malware,
+ block_adult_content: options.default_options.block_adult_content,
+ block_gambling: options.default_options.block_gambling,
+ }),
+ custom_options: Some(proto::CustomDnsOptions {
+ addresses: options
+ .custom_options
+ .addresses
+ .iter()
+ .map(|addr| addr.to_string())
+ .collect(),
+ }),
+ }
+ }
+}
+
+impl From<&mullvad_types::settings::TunnelOptions> for proto::TunnelOptions {
+ fn from(options: &mullvad_types::settings::TunnelOptions) -> Self {
+ Self {
+ openvpn: Some(proto::tunnel_options::OpenvpnOptions {
+ mssfix: u32::from(options.openvpn.mssfix.unwrap_or_default()),
+ }),
+ wireguard: Some(proto::tunnel_options::WireguardOptions {
+ mtu: u32::from(options.wireguard.options.mtu.unwrap_or_default()),
+ rotation_interval: options.wireguard.rotation_interval.map(|ivl| {
+ prost_types::Duration::try_from(std::time::Duration::from(ivl))
+ .expect("Failed to convert std::time::Duration to prost_types::Duration for tunnel_options.wireguard.rotation_interval")
+ }),
+ #[cfg(windows)]
+ use_wireguard_nt: options.wireguard.options.use_wireguard_nt,
+ #[cfg(not(windows))]
+ use_wireguard_nt: false,
+ use_pq_safe_psk: options.wireguard.options.use_pq_safe_psk,
+ }),
+ generic: Some(proto::tunnel_options::GenericOptions {
+ enable_ipv6: options.generic.enable_ipv6,
+ }),
+ #[cfg(not(target_os = "android"))]
+ dns_options: Some(proto::DnsOptions::from(&options.dns_options)),
+ #[cfg(target_os = "android")]
+ dns_options: None,
+ }
+ }
+}
+
+impl TryFrom<proto::TunnelOptions> for mullvad_types::settings::TunnelOptions {
+ type Error = FromProtobufTypeError;
+
+ fn try_from(options: proto::TunnelOptions) -> Result<Self, Self::Error> {
+ use talpid_types::net;
+
+ let openvpn_options = options
+ .openvpn
+ .ok_or(FromProtobufTypeError::InvalidArgument(
+ "missing openvpn tunnel options",
+ ))?;
+ let wireguard_options = options
+ .wireguard
+ .ok_or(FromProtobufTypeError::InvalidArgument(
+ "missing openvpn tunnel options",
+ ))?;
+ let generic_options = options
+ .generic
+ .ok_or(FromProtobufTypeError::InvalidArgument(
+ "missing generic tunnel options",
+ ))?;
+ let dns_options = options
+ .dns_options
+ .ok_or(FromProtobufTypeError::InvalidArgument(
+ "missing tunnel DNS options",
+ ))?;
+
+ Ok(Self {
+ openvpn: net::openvpn::TunnelOptions {
+ mssfix: if openvpn_options.mssfix != 0 {
+ Some(openvpn_options.mssfix as u16)
+ } else {
+ None
+ },
+ },
+ wireguard: mullvad_types::wireguard::TunnelOptions {
+ options: net::wireguard::TunnelOptions {
+ mtu: if wireguard_options.mtu != 0 {
+ Some(wireguard_options.mtu as u16)
+ } else {
+ None
+ },
+ use_pq_safe_psk: wireguard_options.use_pq_safe_psk,
+ #[cfg(windows)]
+ use_wireguard_nt: wireguard_options.use_wireguard_nt,
+ },
+ rotation_interval: wireguard_options
+ .rotation_interval
+ .map(std::time::Duration::try_from)
+ .transpose()
+ .map_err(|_| FromProtobufTypeError::InvalidArgument("invalid duration"))?
+ .map(mullvad_types::wireguard::RotationInterval::try_from)
+ .transpose()
+ .map_err(|error: mullvad_types::wireguard::RotationIntervalError| {
+ log::error!(
+ "{}",
+ error.display_chain_with_msg("Invalid rotation interval")
+ );
+ FromProtobufTypeError::InvalidArgument("invalid rotation interval")
+ })?,
+ },
+ generic: net::GenericTunnelOptions {
+ enable_ipv6: generic_options.enable_ipv6,
+ },
+ #[cfg(not(target_os = "android"))]
+ dns_options: mullvad_types::settings::DnsOptions::try_from(dns_options)?,
+ })
+ }
+}
+
+impl TryFrom<proto::DnsOptions> for mullvad_types::settings::DnsOptions {
+ type Error = FromProtobufTypeError;
+
+ fn try_from(options: proto::DnsOptions) -> Result<Self, Self::Error> {
+ use mullvad_types::settings::{
+ CustomDnsOptions as MullvadCustomDnsOptions,
+ DefaultDnsOptions as MullvadDefaultDnsOptions, DnsOptions as MullvadDnsOptions,
+ DnsState as MullvadDnsState,
+ };
+
+ let state = match proto::dns_options::DnsState::from_i32(options.state) {
+ Some(proto::dns_options::DnsState::Default) => MullvadDnsState::Default,
+ Some(proto::dns_options::DnsState::Custom) => MullvadDnsState::Custom,
+ None => {
+ return Err(FromProtobufTypeError::InvalidArgument(
+ "invalid DNS options state",
+ ))
+ }
+ };
+
+ let default_options =
+ options
+ .default_options
+ .ok_or(FromProtobufTypeError::InvalidArgument(
+ "missing default DNS options",
+ ))?;
+ let custom_options =
+ options
+ .custom_options
+ .ok_or(FromProtobufTypeError::InvalidArgument(
+ "missing default DNS options",
+ ))?;
+
+ Ok(MullvadDnsOptions {
+ state,
+ default_options: MullvadDefaultDnsOptions {
+ block_ads: default_options.block_ads,
+ block_trackers: default_options.block_trackers,
+ block_malware: default_options.block_malware,
+ block_adult_content: default_options.block_adult_content,
+ block_gambling: default_options.block_gambling,
+ },
+ custom_options: MullvadCustomDnsOptions {
+ addresses: custom_options
+ .addresses
+ .into_iter()
+ .map(|addr| {
+ addr.parse().map_err(|_| {
+ FromProtobufTypeError::InvalidArgument("invalid IP address")
+ })
+ })
+ .collect::<Result<Vec<_>, _>>()?,
+ },
+ })
+ }
+}
diff --git a/mullvad-management-interface/src/types/conversions/states.rs b/mullvad-management-interface/src/types/conversions/states.rs
new file mode 100644
index 0000000000..c462e77aa6
--- /dev/null
+++ b/mullvad-management-interface/src/types/conversions/states.rs
@@ -0,0 +1,318 @@
+use crate::types::{conversions::option_from_proto_string, proto, FromProtobufTypeError};
+
+impl From<mullvad_types::states::TunnelState> for proto::TunnelState {
+ fn from(state: mullvad_types::states::TunnelState) -> Self {
+ use mullvad_types::states::TunnelState as MullvadTunnelState;
+ use proto::error_state::{
+ firewall_policy_error::ErrorType as PolicyErrorType, Cause, FirewallPolicyError,
+ GenerationError,
+ };
+
+ 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 => {
+ proto::tunnel_state::State::Disconnected(proto::tunnel_state::Disconnected {})
+ }
+ MullvadTunnelState::Connecting { endpoint, location } => {
+ proto::tunnel_state::State::Connecting(proto::tunnel_state::Connecting {
+ relay_info: Some(proto::TunnelStateRelayInfo {
+ tunnel_endpoint: Some(proto::TunnelEndpoint::from(endpoint)),
+ location: location.map(proto::GeoIpLocation::from),
+ }),
+ })
+ }
+ MullvadTunnelState::Connected { endpoint, location } => {
+ proto::tunnel_state::State::Connected(proto::tunnel_state::Connected {
+ relay_info: Some(proto::TunnelStateRelayInfo {
+ tunnel_endpoint: Some(proto::TunnelEndpoint::from(endpoint)),
+ location: location.map(proto::GeoIpLocation::from),
+ }),
+ })
+ }
+ MullvadTunnelState::Disconnecting(after_disconnect) => {
+ proto::tunnel_state::State::Disconnecting(proto::tunnel_state::Disconnecting {
+ after_disconnect: match after_disconnect {
+ talpid_tunnel::ActionAfterDisconnect::Nothing => {
+ i32::from(proto::AfterDisconnect::Nothing)
+ }
+ talpid_tunnel::ActionAfterDisconnect::Block => {
+ i32::from(proto::AfterDisconnect::Block)
+ }
+ talpid_tunnel::ActionAfterDisconnect::Reconnect => {
+ i32::from(proto::AfterDisconnect::Reconnect)
+ }
+ },
+ })
+ }
+ MullvadTunnelState::Error(error_state) => {
+ proto::tunnel_state::State::Error(proto::tunnel_state::Error {
+ error_state: Some(proto::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)
+ }
+ #[cfg(target_os = "windows")]
+ talpid_tunnel::ErrorStateCause::SplitTunnelError => {
+ i32::from(Cause::SplitTunnelError)
+ }
+ },
+ 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
+ },
+ }),
+ })
+ }
+ };
+
+ proto::TunnelState { state: Some(state) }
+ }
+}
+
+impl TryFrom<proto::TunnelState> for mullvad_types::states::TunnelState {
+ type Error = FromProtobufTypeError;
+
+ fn try_from(state: proto::TunnelState) -> Result<Self, FromProtobufTypeError> {
+ use mullvad_types::states::TunnelState as MullvadState;
+ use talpid_types::{net as talpid_net, tunnel as talpid_tunnel};
+
+ let state = match state.state {
+ Some(proto::tunnel_state::State::Disconnected(_)) => MullvadState::Disconnected,
+ Some(proto::tunnel_state::State::Connecting(proto::tunnel_state::Connecting {
+ relay_info:
+ Some(proto::TunnelStateRelayInfo {
+ tunnel_endpoint: Some(tunnel_endpoint),
+ location,
+ }),
+ })) => MullvadState::Connecting {
+ endpoint: talpid_net::TunnelEndpoint::try_from(tunnel_endpoint)?,
+ location: location
+ .map(mullvad_types::location::GeoIpLocation::try_from)
+ .transpose()?,
+ },
+ Some(proto::tunnel_state::State::Connected(proto::tunnel_state::Connected {
+ relay_info:
+ Some(proto::TunnelStateRelayInfo {
+ tunnel_endpoint: Some(tunnel_endpoint),
+ location,
+ }),
+ })) => MullvadState::Connected {
+ endpoint: talpid_net::TunnelEndpoint::try_from(tunnel_endpoint)?,
+ location: location
+ .map(mullvad_types::location::GeoIpLocation::try_from)
+ .transpose()?,
+ },
+ Some(proto::tunnel_state::State::Disconnecting(
+ proto::tunnel_state::Disconnecting { after_disconnect },
+ )) => MullvadState::Disconnecting(
+ match proto::AfterDisconnect::from_i32(after_disconnect) {
+ Some(proto::AfterDisconnect::Nothing) => {
+ talpid_tunnel::ActionAfterDisconnect::Nothing
+ }
+ Some(proto::AfterDisconnect::Block) => {
+ talpid_tunnel::ActionAfterDisconnect::Block
+ }
+ Some(proto::AfterDisconnect::Reconnect) => {
+ talpid_tunnel::ActionAfterDisconnect::Reconnect
+ }
+ _ => {
+ return Err(FromProtobufTypeError::InvalidArgument(
+ "invalid \"after_disconnect\" action",
+ ))
+ }
+ },
+ ),
+ Some(proto::tunnel_state::State::Error(proto::tunnel_state::Error {
+ error_state:
+ Some(proto::ErrorState {
+ cause,
+ blocking_error,
+ auth_fail_reason,
+ parameter_error,
+ policy_error,
+ }),
+ })) => {
+ let cause = match proto::error_state::Cause::from_i32(cause) {
+ Some(proto::error_state::Cause::AuthFailed) => {
+ talpid_tunnel::ErrorStateCause::AuthFailed(option_from_proto_string(
+ auth_fail_reason,
+ ))
+ }
+ Some(proto::error_state::Cause::Ipv6Unavailable) => {
+ talpid_tunnel::ErrorStateCause::Ipv6Unavailable
+ }
+ Some(proto::error_state::Cause::IsOffline) => {
+ talpid_tunnel::ErrorStateCause::IsOffline
+ }
+ Some(proto::error_state::Cause::SetDnsError) => {
+ talpid_tunnel::ErrorStateCause::SetDnsError
+ }
+ Some(proto::error_state::Cause::SetFirewallPolicyError) => {
+ let policy_error = policy_error.ok_or(
+ FromProtobufTypeError::InvalidArgument("missing firewall policy error"),
+ )?;
+ let policy_error = try_firewall_policy_error_from_i32(
+ policy_error.r#type,
+ policy_error.lock_pid,
+ policy_error.lock_name,
+ )?;
+ talpid_tunnel::ErrorStateCause::SetFirewallPolicyError(policy_error)
+ }
+ Some(proto::error_state::Cause::StartTunnelError) => {
+ talpid_tunnel::ErrorStateCause::StartTunnelError
+ }
+ Some(proto::error_state::Cause::TunnelParameterError) => {
+ let parameter_error = match proto::error_state::GenerationError::from_i32(parameter_error) {
+ Some(proto::error_state::GenerationError::CustomTunnelHostResolutionError) => talpid_tunnel::ParameterGenerationError::CustomTunnelHostResultionError,
+ Some(proto::error_state::GenerationError::NoMatchingBridgeRelay) => talpid_tunnel::ParameterGenerationError::NoMatchingBridgeRelay,
+ Some(proto::error_state::GenerationError::NoMatchingRelay) => talpid_tunnel::ParameterGenerationError::NoMatchingRelay,
+ Some(proto::error_state::GenerationError::NoWireguardKey) => talpid_tunnel::ParameterGenerationError::NoWireguardKey,
+ _ => return Err(FromProtobufTypeError::InvalidArgument(
+ "invalid parameter error",
+ )),
+ };
+ talpid_tunnel::ErrorStateCause::TunnelParameterError(parameter_error)
+ }
+ #[cfg(target_os = "android")]
+ Some(proto::error_state::Cause::VpnPermissionDenied) => {
+ talpid_tunnel::ErrorStateCause::VpnPermissionDenied
+ }
+ #[cfg(target_os = "windows")]
+ Some(proto::error_state::Cause::SplitTunnelError) => {
+ talpid_tunnel::ErrorStateCause::SplitTunnelError
+ }
+ _ => {
+ return Err(FromProtobufTypeError::InvalidArgument(
+ "invalid error cause",
+ ))
+ }
+ };
+
+ let block_failure = blocking_error
+ .map(|blocking_error| {
+ try_firewall_policy_error_from_i32(
+ blocking_error.r#type,
+ blocking_error.lock_pid,
+ blocking_error.lock_name,
+ )
+ })
+ .transpose()?;
+
+ MullvadState::Error(talpid_tunnel::ErrorState::new(cause, block_failure))
+ }
+ _ => {
+ return Err(FromProtobufTypeError::InvalidArgument(
+ "invalid tunnel state",
+ ))
+ }
+ };
+
+ Ok(state)
+ }
+}
+
+#[cfg_attr(not(target_os = "windows"), allow(unused_variables))]
+fn try_firewall_policy_error_from_i32(
+ policy_error: i32,
+ lock_pid: u32,
+ lock_name: String,
+) -> Result<talpid_types::tunnel::FirewallPolicyError, FromProtobufTypeError> {
+ match proto::error_state::firewall_policy_error::ErrorType::from_i32(policy_error) {
+ Some(proto::error_state::firewall_policy_error::ErrorType::Generic) => {
+ Ok(talpid_types::tunnel::FirewallPolicyError::Generic)
+ }
+ #[cfg(windows)]
+ Some(proto::error_state::firewall_policy_error::ErrorType::Locked) => {
+ let blocking_app = option_from_proto_string(lock_name).map(|name| {
+ talpid_types::tunnel::BlockingApplication {
+ pid: lock_pid,
+ name,
+ }
+ });
+ Ok(talpid_types::tunnel::FirewallPolicyError::Locked(
+ blocking_app,
+ ))
+ }
+ _ => Err(FromProtobufTypeError::InvalidArgument(
+ "invalid firewall policy error",
+ )),
+ }
+}
diff --git a/mullvad-management-interface/src/types/conversions/version.rs b/mullvad-management-interface/src/types/conversions/version.rs
new file mode 100644
index 0000000000..0a21667695
--- /dev/null
+++ b/mullvad-management-interface/src/types/conversions/version.rs
@@ -0,0 +1,12 @@
+use crate::types::proto;
+
+impl From<mullvad_types::version::AppVersionInfo> for proto::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(),
+ }
+ }
+}
diff --git a/mullvad-management-interface/src/types/conversions/wireguard.rs b/mullvad-management-interface/src/types/conversions/wireguard.rs
new file mode 100644
index 0000000000..e90e728c2f
--- /dev/null
+++ b/mullvad-management-interface/src/types/conversions/wireguard.rs
@@ -0,0 +1,14 @@
+use crate::types::proto;
+use prost_types::Timestamp;
+
+impl From<mullvad_types::wireguard::PublicKey> for proto::PublicKey {
+ fn from(public_key: mullvad_types::wireguard::PublicKey) -> Self {
+ proto::PublicKey {
+ key: public_key.key.as_bytes().to_vec(),
+ created: Some(Timestamp {
+ seconds: public_key.created.timestamp(),
+ nanos: 0,
+ }),
+ }
+ }
+}