diff options
| author | David Lönnhager <david.l@mullvad.net> | 2021-04-22 18:25:28 +0200 |
|---|---|---|
| committer | David Lönnhager <david.l@mullvad.net> | 2021-04-29 12:17:19 +0200 |
| commit | 5a73049c0841bab3b2704e90cf83a954facbd943 (patch) | |
| tree | 0e77d0e3e32768f9ae0c56ab2080cbe2d3cdba38 | |
| parent | cbb2171c2fb145dc291df5cf794e103959fcc3e0 (diff) | |
| download | mullvadvpn-5a73049c0841bab3b2704e90cf83a954facbd943.tar.xz mullvadvpn-5a73049c0841bab3b2704e90cf83a954facbd943.zip | |
Implement TryFrom for RelaySettingsUpdate
| -rw-r--r-- | mullvad-daemon/src/management_interface.rs | 260 | ||||
| -rw-r--r-- | mullvad-management-interface/src/types.rs | 299 |
2 files changed, 310 insertions, 249 deletions
diff --git a/mullvad-daemon/src/management_interface.rs b/mullvad-daemon/src/management_interface.rs index 83557b48fe..0c6c2f67b6 100644 --- a/mullvad-daemon/src/management_interface.rs +++ b/mullvad-daemon/src/management_interface.rs @@ -12,16 +12,13 @@ use mullvad_types::{ account::AccountToken, location::GeoIpLocation, relay_constraints::{ - BridgeConstraints, BridgeSettings, BridgeState, Constraint, LocationConstraint, - OpenVpnConstraints, Providers, RelayConstraintsUpdate, RelaySettingsUpdate, - WireguardConstraints, + BridgeConstraints, BridgeSettings, BridgeState, Constraint, Providers, RelaySettingsUpdate, }, relay_list::{Relay, RelayList, RelayListCountry}, settings::Settings, states::{TargetState, TunnelState}, version, wireguard::{self, RotationInterval, RotationIntervalError}, - ConnectionConfig, }; use parking_lot::RwLock; use std::{ @@ -30,10 +27,7 @@ use std::{ sync::{mpsc, Arc}, time::Duration, }; -use talpid_types::{ - net::{IpVersion, TunnelType}, - ErrorExt, -}; +use talpid_types::ErrorExt; #[derive(err_derive::Error, Debug)] #[error(no_from)] @@ -176,7 +170,12 @@ impl ManagementService for ManagementServiceImpl { ) -> ServiceResult<()> { log::debug!("update_relay_settings"); let (tx, rx) = oneshot::channel(); - let constraints_update = convert_relay_settings_update(&request.into_inner())?; + let constraints_update = + RelaySettingsUpdate::try_from(request.into_inner()).map_err(|error| match error { + types::FromProtobufTypeError::InvalidArgument(error) => { + Status::invalid_argument(error) + } + })?; let message = DaemonCommand::UpdateRelaySettings(tx, constraints_update); self.send_command_to_daemon(message)?; @@ -243,7 +242,9 @@ impl ManagementService for ManagementServiceImpl { BridgeSettingType::Normal(constraints) => { let location = match constraints.location { None => Constraint::Any, - Some(location) => convert_proto_location(location), + Some(location) => Constraint::< + mullvad_types::relay_constraints::LocationConstraint, + >::from(location), }; let providers = if constraints.providers.is_empty() { Constraint::Any @@ -761,229 +762,6 @@ impl ManagementServiceImpl { } } -fn convert_relay_settings_update( - settings: &types::RelaySettingsUpdate, -) -> Result<RelaySettingsUpdate, Status> { - use mullvad_types::CustomTunnelEndpoint; - use talpid_types::net::{self, openvpn, wireguard}; - use types::{ - connection_config::Config as ProtoConnectionConfig, - relay_settings_update::Type as ProtoUpdateType, - }; - - let update_value = settings - .r#type - .clone() - .ok_or(Status::invalid_argument("missing relay settings"))?; - - match update_value { - ProtoUpdateType::Custom(settings) => { - let config = settings - .config - .ok_or(Status::invalid_argument("missing relay settings"))?; - let config = config - .config - .ok_or(Status::invalid_argument("missing relay settings"))?; - let config = match config { - ProtoConnectionConfig::Openvpn(config) => { - let address = match config.address.parse() { - Ok(address) => address, - Err(_) => return Err(Status::invalid_argument("invalid address")), - }; - - ConnectionConfig::OpenVpn(openvpn::ConnectionConfig { - endpoint: net::Endpoint { - address, - protocol: types::TransportProtocol::from_i32(config.protocol) - .ok_or(Status::invalid_argument("invalid transport protocol"))? - .into(), - }, - username: config.username.clone(), - password: config.password.clone(), - }) - } - ProtoConnectionConfig::Wireguard(config) => { - let tunnel = config - .tunnel - .ok_or(Status::invalid_argument("missing tunnel config"))?; - - // Copy the private key to an array - if tunnel.private_key.len() != 32 { - return Err(Status::invalid_argument("invalid private key")); - } - - let mut private_key = [0; 32]; - let buffer = &tunnel.private_key[..private_key.len()]; - private_key.copy_from_slice(buffer); - - let peer = config - .peer - .ok_or(Status::invalid_argument("missing peer config"))?; - - // Copy the public key to an array - if peer.public_key.len() != 32 { - return Err(Status::invalid_argument("invalid public key")); - } - - let mut public_key = [0; 32]; - let buffer = &peer.public_key[..public_key.len()]; - public_key.copy_from_slice(buffer); - - let ipv4_gateway = match config.ipv4_gateway.parse() { - Ok(address) => address, - Err(_) => return Err(Status::invalid_argument("invalid IPv4 gateway")), - }; - let ipv6_gateway = if !config.ipv6_gateway.is_empty() { - let address = match config.ipv6_gateway.parse() { - Ok(address) => address, - Err(_) => return Err(Status::invalid_argument("invalid IPv6 gateway")), - }; - Some(address) - } else { - None - }; - - let endpoint = match peer.endpoint.parse() { - Ok(address) => address, - Err(_) => return Err(Status::invalid_argument("invalid peer address")), - }; - - let mut tunnel_addresses = Vec::new(); - for address in tunnel.addresses { - let address = address - .parse() - .map_err(|_| Status::invalid_argument("invalid address"))?; - tunnel_addresses.push(address); - } - - let mut allowed_ips = Vec::new(); - for address in peer.allowed_ips { - let address = address - .parse() - .map_err(|_| Status::invalid_argument("invalid address"))?; - allowed_ips.push(address); - } - - ConnectionConfig::Wireguard(wireguard::ConnectionConfig { - tunnel: wireguard::TunnelConfig { - private_key: wireguard::PrivateKey::from(private_key), - addresses: tunnel_addresses, - }, - peer: wireguard::PeerConfig { - public_key: wireguard::PublicKey::from(public_key), - allowed_ips, - endpoint, - protocol: types::TransportProtocol::from_i32(peer.protocol) - .ok_or(Status::invalid_argument("invalid transport protocol"))? - .into(), - }, - ipv4_gateway, - ipv6_gateway, - }) - } - }; - - Ok(RelaySettingsUpdate::CustomTunnelEndpoint( - CustomTunnelEndpoint { - host: settings.host.clone(), - config, - }, - )) - } - - ProtoUpdateType::Normal(settings) => { - // If `location` isn't provided, no changes are made. - // If `location` is provided, but is an empty vector, - // then the constraint is set to `Constraint::Any`. - let location = settings.location.map(convert_proto_location); - - let tunnel_protocol = if let Some(update) = settings.tunnel_type { - match update.tunnel_type { - Some(constraint) => match types::TunnelType::from_i32(constraint.tunnel_type) { - Some(types::TunnelType::Openvpn) => { - Some(Constraint::Only(TunnelType::OpenVpn)) - } - Some(types::TunnelType::Wireguard) => { - Some(Constraint::Only(TunnelType::Wireguard)) - } - None => return Err(Status::invalid_argument("invalid tunnel protocol")), - }, - None => Some(Constraint::Any), - } - } else { - None - }; - - let transport_protocol = if let Some(ref constraints) = settings.openvpn_constraints { - match &constraints.protocol { - Some(constraint) => Some( - types::TransportProtocol::from_i32(constraint.protocol) - .ok_or(Status::invalid_argument("invalid transport protocol"))? - .into(), - ), - None => None, - } - } else { - None - }; - - let providers = if let Some(ref provider_update) = settings.providers { - if !provider_update.providers.is_empty() { - Some(Constraint::Only( - Providers::new(provider_update.providers.clone().into_iter()).map_err( - |_| Status::invalid_argument("must specify at least one provider"), - )?, - )) - } else { - Some(Constraint::Any) - } - } else { - None - }; - let ip_version = if let Some(ref constraints) = settings.wireguard_constraints { - match &constraints.ip_version { - Some(constraint) => match types::IpVersion::from_i32(constraint.protocol) { - Some(types::IpVersion::V4) => Some(IpVersion::V4), - Some(types::IpVersion::V6) => Some(IpVersion::V6), - None => { - return Err(Status::invalid_argument("invalid ip protocol version")) - } - }, - None => None, - } - } else { - None - }; - - Ok(RelaySettingsUpdate::Normal(RelayConstraintsUpdate { - location, - providers, - tunnel_protocol, - wireguard_constraints: settings.wireguard_constraints.map(|constraints| { - WireguardConstraints { - port: if constraints.port != 0 { - Constraint::Only(constraints.port as u16) - } else { - Constraint::Any - }, - ip_version: Constraint::from(ip_version), - } - }), - openvpn_constraints: settings.openvpn_constraints.map(|constraints| { - OpenVpnConstraints { - port: if constraints.port != 0 { - Constraint::Only(constraints.port as u16) - } else { - Constraint::Any - }, - protocol: Constraint::from(transport_protocol), - } - }), - })) - } - } -} - fn convert_wireguard_key_event( event: &mullvad_types::wireguard::KeygenEvent, ) -> types::KeygenEvent { @@ -1258,22 +1036,6 @@ fn convert_geoip_location(geoip: GeoIpLocation) -> types::GeoIpLocation { } } -fn convert_proto_location(location: types::RelayLocation) -> Constraint<LocationConstraint> { - if !location.hostname.is_empty() { - Constraint::Only(LocationConstraint::Hostname( - location.country, - location.city, - location.hostname, - )) - } else if !location.city.is_empty() { - Constraint::Only(LocationConstraint::City(location.country, location.city)) - } else if !location.country.is_empty() { - Constraint::Only(LocationConstraint::Country(location.country)) - } else { - Constraint::Any - } -} - pub struct ManagementInterfaceServer { subscriptions: Arc<RwLock<Vec<EventsListenerSender>>>, socket_path: String, diff --git a/mullvad-management-interface/src/types.rs b/mullvad-management-interface/src/types.rs index 58d1b107d6..fe3779b80b 100644 --- a/mullvad-management-interface/src/types.rs +++ b/mullvad-management-interface/src/types.rs @@ -1,6 +1,7 @@ pub use prost_types::{Duration, Timestamp}; use mullvad_types::relay_constraints::Constraint; +use std::convert::TryFrom; tonic::include_proto!("mullvad_daemon.management_interface"); @@ -298,6 +299,304 @@ impl From<TransportProtocol> for talpid_types::net::TransportProtocol { } } +pub enum FromProtobufTypeError { + InvalidArgument(&'static str), +} + +impl TryFrom<RelaySettingsUpdate> for mullvad_types::relay_constraints::RelaySettingsUpdate { + type Error = FromProtobufTypeError; + + fn try_from( + settings: RelaySettingsUpdate, + ) -> Result<mullvad_types::relay_constraints::RelaySettingsUpdate, Self::Error> { + use mullvad_types::CustomTunnelEndpoint; + use talpid_types::net::{self, openvpn, wireguard}; + + use mullvad_types::relay_constraints as mullvad_constraints; + + let update_value = + settings + .r#type + .clone() + .ok_or(FromProtobufTypeError::InvalidArgument( + "missing relay settings", + ))?; + + match update_value { + relay_settings_update::Type::Custom(settings) => { + let config = settings + .config + .ok_or(FromProtobufTypeError::InvalidArgument( + "missing relay settings", + ))?; + let config = config.config.ok_or(FromProtobufTypeError::InvalidArgument( + "missing relay settings", + ))?; + let config = match config { + connection_config::Config::Openvpn(config) => { + let address = match config.address.parse() { + Ok(address) => address, + Err(_) => { + return Err(FromProtobufTypeError::InvalidArgument( + "invalid address", + )) + } + }; + + mullvad_types::ConnectionConfig::OpenVpn(openvpn::ConnectionConfig { + endpoint: net::Endpoint { + address, + protocol: TransportProtocol::from_i32(config.protocol) + .ok_or(FromProtobufTypeError::InvalidArgument( + "invalid transport protocol", + ))? + .into(), + }, + username: config.username, + password: config.password, + }) + } + connection_config::Config::Wireguard(config) => { + let tunnel = config.tunnel.ok_or( + FromProtobufTypeError::InvalidArgument("missing tunnel config"), + )?; + + // Copy the private key to an array + if tunnel.private_key.len() != 32 { + return Err(FromProtobufTypeError::InvalidArgument( + "invalid private key", + )); + } + + let mut private_key = [0; 32]; + let buffer = &tunnel.private_key[..private_key.len()]; + private_key.copy_from_slice(buffer); + + let peer = config.peer.ok_or(FromProtobufTypeError::InvalidArgument( + "missing peer config", + ))?; + + // Copy the public key to an array + if peer.public_key.len() != 32 { + return Err(FromProtobufTypeError::InvalidArgument( + "invalid public key", + )); + } + + let mut public_key = [0; 32]; + let buffer = &peer.public_key[..public_key.len()]; + public_key.copy_from_slice(buffer); + + let ipv4_gateway = match config.ipv4_gateway.parse() { + Ok(address) => address, + Err(_) => { + return Err(FromProtobufTypeError::InvalidArgument( + "invalid IPv4 gateway", + )) + } + }; + let ipv6_gateway = if !config.ipv6_gateway.is_empty() { + let address = match config.ipv6_gateway.parse() { + Ok(address) => address, + Err(_) => { + return Err(FromProtobufTypeError::InvalidArgument( + "invalid IPv6 gateway", + )) + } + }; + Some(address) + } else { + None + }; + + let endpoint = match peer.endpoint.parse() { + Ok(address) => address, + Err(_) => { + return Err(FromProtobufTypeError::InvalidArgument( + "invalid peer address", + )) + } + }; + + let mut tunnel_addresses = Vec::new(); + for address in tunnel.addresses { + let address = address.parse().map_err(|_| { + FromProtobufTypeError::InvalidArgument("invalid address") + })?; + tunnel_addresses.push(address); + } + + let mut allowed_ips = Vec::new(); + for address in peer.allowed_ips { + let address = address.parse().map_err(|_| { + FromProtobufTypeError::InvalidArgument("invalid address") + })?; + allowed_ips.push(address); + } + + mullvad_types::ConnectionConfig::Wireguard(wireguard::ConnectionConfig { + tunnel: wireguard::TunnelConfig { + private_key: wireguard::PrivateKey::from(private_key), + addresses: tunnel_addresses, + }, + peer: wireguard::PeerConfig { + public_key: wireguard::PublicKey::from(public_key), + allowed_ips, + endpoint, + protocol: TransportProtocol::from_i32(peer.protocol) + .ok_or(FromProtobufTypeError::InvalidArgument( + "invalid transport protocol", + ))? + .into(), + }, + ipv4_gateway, + ipv6_gateway, + }) + } + }; + + Ok( + mullvad_constraints::RelaySettingsUpdate::CustomTunnelEndpoint( + CustomTunnelEndpoint { + host: settings.host, + config, + }, + ), + ) + } + + relay_settings_update::Type::Normal(settings) => { + // If `location` isn't provided, no changes are made. + // If `location` is provided, but is an empty vector, + // then the constraint is set to `Constraint::Any`. + let location = settings + .location + .map(Constraint::<mullvad_types::relay_constraints::LocationConstraint>::from); + + let tunnel_protocol = if let Some(update) = settings.tunnel_type { + match update.tunnel_type { + Some(constraint) => match TunnelType::from_i32(constraint.tunnel_type) { + Some(TunnelType::Openvpn) => { + Some(Constraint::Only(net::TunnelType::OpenVpn)) + } + Some(TunnelType::Wireguard) => { + Some(Constraint::Only(net::TunnelType::Wireguard)) + } + None => { + return Err(FromProtobufTypeError::InvalidArgument( + "invalid tunnel protocol", + )) + } + }, + None => Some(Constraint::Any), + } + } else { + None + }; + + let transport_protocol = if let Some(ref constraints) = settings.openvpn_constraints + { + match &constraints.protocol { + Some(constraint) => Some( + TransportProtocol::from_i32(constraint.protocol) + .ok_or(FromProtobufTypeError::InvalidArgument( + "invalid transport protocol", + ))? + .into(), + ), + None => None, + } + } else { + None + }; + + let providers = if let Some(ref provider_update) = settings.providers { + if !provider_update.providers.is_empty() { + Some(Constraint::Only( + mullvad_constraints::Providers::new( + provider_update.providers.clone().into_iter(), + ) + .map_err(|_| { + FromProtobufTypeError::InvalidArgument( + "must specify at least one provider", + ) + })?, + )) + } else { + Some(Constraint::Any) + } + } else { + None + }; + let ip_version = if let Some(ref constraints) = settings.wireguard_constraints { + match &constraints.ip_version { + Some(constraint) => match IpVersion::from_i32(constraint.protocol) { + Some(IpVersion::V4) => Some(net::IpVersion::V4), + Some(IpVersion::V6) => Some(net::IpVersion::V6), + None => { + return Err(FromProtobufTypeError::InvalidArgument( + "invalid ip protocol version", + )) + } + }, + None => None, + } + } else { + None + }; + + Ok(mullvad_constraints::RelaySettingsUpdate::Normal( + mullvad_constraints::RelayConstraintsUpdate { + location, + providers, + tunnel_protocol, + wireguard_constraints: settings.wireguard_constraints.map(|constraints| { + mullvad_constraints::WireguardConstraints { + port: if constraints.port != 0 { + Constraint::Only(constraints.port as u16) + } else { + Constraint::Any + }, + ip_version: Constraint::from(ip_version), + } + }), + openvpn_constraints: settings.openvpn_constraints.map(|constraints| { + mullvad_constraints::OpenVpnConstraints { + port: if constraints.port != 0 { + Constraint::Only(constraints.port as u16) + } else { + Constraint::Any + }, + protocol: Constraint::from(transport_protocol), + } + }), + }, + )) + } + } + } +} + +impl From<RelayLocation> for Constraint<mullvad_types::relay_constraints::LocationConstraint> { + fn from(location: RelayLocation) -> Self { + use mullvad_types::relay_constraints::LocationConstraint; + + if !location.hostname.is_empty() { + Constraint::Only(LocationConstraint::Hostname( + location.country, + location.city, + location.hostname, + )) + } else if !location.city.is_empty() { + Constraint::Only(LocationConstraint::City(location.country, location.city)) + } else if !location.country.is_empty() { + Constraint::Only(LocationConstraint::Country(location.country)) + } else { + Constraint::Any + } + } +} + fn convert_providers_constraint( providers: &Constraint<mullvad_types::relay_constraints::Providers>, ) -> Vec<String> { |
