diff options
| author | David Lönnhager <david.l@mullvad.net> | 2021-09-27 10:37:19 +0200 |
|---|---|---|
| committer | David Lönnhager <david.l@mullvad.net> | 2021-09-27 10:37:19 +0200 |
| commit | 2c56264c4c3d5867c1fae3141687ecd0ef9ca9bc (patch) | |
| tree | 40f69cf2deb4d178027a28de27187e92eb7fd5d4 | |
| parent | 2d11706b8db091f4eab93789ec042ee27a06f162 (diff) | |
| parent | e832ffa25c5361f2dd9342745c42d1774d7cd00f (diff) | |
| download | mullvadvpn-2c56264c4c3d5867c1fae3141687ecd0ef9ca9bc.tar.xz mullvadvpn-2c56264c4c3d5867c1fae3141687ecd0ef9ca9bc.zip | |
Merge branch 'refactor-cli-grpc-types'
| -rw-r--r-- | mullvad-cli/src/cmds/bridge.rs | 135 | ||||
| -rw-r--r-- | mullvad-cli/src/cmds/relay.rs | 277 | ||||
| -rw-r--r-- | mullvad-cli/src/location.rs | 24 | ||||
| -rw-r--r-- | mullvad-management-interface/proto/management_interface.proto | 4 | ||||
| -rw-r--r-- | mullvad-management-interface/src/types.rs | 544 |
5 files changed, 481 insertions, 503 deletions
diff --git a/mullvad-cli/src/cmds/bridge.rs b/mullvad-cli/src/cmds/bridge.rs index 0599c7aef6..17e62f3197 100644 --- a/mullvad-cli/src/cmds/bridge.rs +++ b/mullvad-cli/src/cmds/bridge.rs @@ -1,14 +1,16 @@ use crate::{location, new_rpc_client, Command, Error, Result}; use clap::{value_t, values_t}; -use mullvad_management_interface::types::{ - bridge_settings::{Type as BridgeSettingsType, *}, - bridge_state::State as BridgeStateType, - BridgeSettings, BridgeState, RelayLocation, +use mullvad_management_interface::types; +use mullvad_types::relay_constraints::{ + BridgeConstraints, BridgeSettings, BridgeState, Constraint, LocationConstraint, }; -use talpid_types::net::openvpn::SHADOWSOCKS_CIPHERS; +use talpid_types::net::openvpn::{self, SHADOWSOCKS_CIPHERS}; -use std::net::{IpAddr, SocketAddr}; +use std::{ + convert::TryFrom, + net::{IpAddr, SocketAddr}, +}; pub struct Bridge; @@ -199,19 +201,23 @@ impl Bridge { async fn handle_get() -> Result<()> { let mut rpc = new_rpc_client().await?; let settings = rpc.get_settings(()).await?.into_inner(); - Self::print_state(settings.bridge_state.unwrap()); - match settings.bridge_settings.unwrap().r#type.unwrap() { - BridgeSettingsType::Local(local_proxy) => Self::print_local_proxy(&local_proxy), - BridgeSettingsType::Remote(remote_proxy) => Self::print_remote_proxy(&remote_proxy), - BridgeSettingsType::Shadowsocks(shadowsocks_proxy) => { - Self::print_shadowsocks_proxy(&shadowsocks_proxy) - } - BridgeSettingsType::Normal(constraints) => { - println!( - "Bridge constraints - {}, {}", - location::format_location(constraints.location.as_ref()), - location::format_providers(&constraints.providers) - ); + let bridge_settings = BridgeSettings::try_from(settings.bridge_settings.unwrap()).unwrap(); + println!( + "Bridge state - {}", + BridgeState::try_from(settings.bridge_state.unwrap()).unwrap() + ); + match bridge_settings { + BridgeSettings::Custom(proxy) => match proxy { + openvpn::ProxySettings::Local(local_proxy) => Self::print_local_proxy(&local_proxy), + openvpn::ProxySettings::Remote(remote_proxy) => { + Self::print_remote_proxy(&remote_proxy) + } + openvpn::ProxySettings::Shadowsocks(shadowsocks_proxy) => { + Self::print_shadowsocks_proxy(&shadowsocks_proxy) + } + }, + BridgeSettings::Normal(constraints) => { + println!("Bridge constraints - {}", constraints) } }; Ok(()) @@ -234,56 +240,58 @@ impl Bridge { } async fn update_bridge_settings( - location: Option<RelayLocation>, + location: Option<types::RelayLocation>, providers: Option<Vec<String>>, ) -> Result<()> { let mut rpc = new_rpc_client().await?; let settings = rpc.get_settings(()).await?.into_inner(); - let bridge_settings = settings.bridge_settings.unwrap(); - let constraints = match bridge_settings.r#type.unwrap() { - BridgeSettingsType::Normal(mut constraints) => { + let bridge_settings = BridgeSettings::try_from(settings.bridge_settings.unwrap()).unwrap(); + let constraints = match bridge_settings { + BridgeSettings::Normal(mut constraints) => { if let Some(new_location) = location { - constraints.location = Some(new_location); + constraints.location = Constraint::<LocationConstraint>::from(new_location); } if let Some(new_providers) = providers { - constraints.providers = new_providers; + constraints.providers = + types::try_providers_constraint_from_proto(&new_providers).unwrap(); } constraints } _ => { - let location = location.unwrap_or_default(); - let providers = providers.unwrap_or_default(); + let location = Constraint::<LocationConstraint>::from(location.unwrap_or_default()); + let providers = + types::try_providers_constraint_from_proto(&providers.unwrap_or_default()) + .unwrap(); BridgeConstraints { - location: Some(location), + location, providers, } } }; - rpc.set_bridge_settings(BridgeSettings { - r#type: Some(BridgeSettingsType::Normal(constraints)), - }) + rpc.set_bridge_settings( + types::BridgeSettings::try_from(BridgeSettings::Normal(constraints)).unwrap(), + ) .await?; Ok(()) } async fn handle_set_bridge_state(matches: &clap::ArgMatches<'_>) -> Result<()> { let state = match matches.value_of("policy").unwrap() { - "auto" => BridgeStateType::Auto as i32, - "on" => BridgeStateType::On as i32, - "off" => BridgeStateType::Off as i32, + "auto" => BridgeState::Auto, + "on" => BridgeState::On, + "off" => BridgeState::Off, _ => unreachable!(), }; let mut rpc = new_rpc_client().await?; - rpc.set_bridge_state(BridgeState { state }).await?; + rpc.set_bridge_state(types::BridgeState::from(state)) + .await?; Ok(()) } async fn handle_bridge_set_custom_settings(matches: &clap::ArgMatches<'_>) -> Result<()> { - use talpid_types::net::openvpn; - if let Some(args) = matches.subcommand_matches("local") { let local_port = value_t!(args.value_of("local-port"), u16).unwrap_or_else(|e| e.exit()); @@ -296,19 +304,15 @@ impl Bridge { port: local_port, peer: SocketAddr::new(remote_ip, remote_port), }; - let prost_proxy = LocalProxySettings { - port: local_proxy.port as u32, - peer: local_proxy.peer.to_string(), - }; let packed_proxy = openvpn::ProxySettings::Local(local_proxy); if let Err(error) = openvpn::validate_proxy_settings(&packed_proxy) { panic!("{}", error); } let mut rpc = new_rpc_client().await?; - rpc.set_bridge_settings(BridgeSettings { - r#type: Some(BridgeSettingsType::Local(prost_proxy)), - }) + rpc.set_bridge_settings(types::BridgeSettings::from(BridgeSettings::Custom( + packed_proxy, + ))) .await?; } else if let Some(args) = matches.subcommand_matches("remote") { let remote_ip = @@ -325,29 +329,19 @@ impl Bridge { }), _ => None, }; - let prost_auth = auth.clone().map(|auth| RemoteProxyAuth { - username: auth.username.clone(), - password: auth.password.clone(), - }); - let proxy = openvpn::RemoteProxySettings { address: SocketAddr::new(remote_ip, remote_port), auth, }; - let prost_proxy = RemoteProxySettings { - address: proxy.address.to_string(), - auth: prost_auth, - }; - let packed_proxy = openvpn::ProxySettings::Remote(proxy); if let Err(error) = openvpn::validate_proxy_settings(&packed_proxy) { panic!("{}", error); } let mut rpc = new_rpc_client().await?; - rpc.set_bridge_settings(BridgeSettings { - r#type: Some(BridgeSettingsType::Remote(prost_proxy)), - }) + rpc.set_bridge_settings(types::BridgeSettings::from(BridgeSettings::Custom( + packed_proxy, + ))) .await?; } else if let Some(args) = matches.subcommand_matches("shadowsocks") { let remote_ip = @@ -362,21 +356,15 @@ impl Bridge { password, cipher, }; - let prost_proxy = ShadowsocksProxySettings { - peer: proxy.peer.to_string(), - password: proxy.password.clone(), - cipher: proxy.cipher.clone(), - }; - let packed_proxy = openvpn::ProxySettings::Shadowsocks(proxy); if let Err(error) = openvpn::validate_proxy_settings(&packed_proxy) { panic!("{}", error); } let mut rpc = new_rpc_client().await?; - rpc.set_bridge_settings(BridgeSettings { - r#type: Some(BridgeSettingsType::Shadowsocks(prost_proxy)), - }) + rpc.set_bridge_settings(types::BridgeSettings::from(BridgeSettings::Custom( + packed_proxy, + ))) .await?; } else { unreachable!("unhandled proxy type"); @@ -386,22 +374,13 @@ impl Bridge { Ok(()) } - fn print_state(state: BridgeState) { - let state = match BridgeStateType::from_i32(state.state).expect("unknown bridge state") { - BridgeStateType::Auto => "auto", - BridgeStateType::On => "on", - BridgeStateType::Off => "off", - }; - println!("Bridge state - {}", state); - } - - fn print_local_proxy(proxy: &LocalProxySettings) { + fn print_local_proxy(proxy: &openvpn::LocalProxySettings) { println!("proxy: local"); println!(" local port: {}", proxy.port); println!(" peer address: {}", proxy.peer); } - fn print_remote_proxy(proxy: &RemoteProxySettings) { + fn print_remote_proxy(proxy: &openvpn::RemoteProxySettings) { println!("proxy: remote"); println!(" server address: {}", proxy.address); @@ -413,7 +392,7 @@ impl Bridge { } } - fn print_shadowsocks_proxy(proxy: &ShadowsocksProxySettings) { + fn print_shadowsocks_proxy(proxy: &openvpn::ShadowsocksProxySettings) { println!("proxy: Shadowsocks"); println!(" peer address: {}", proxy.peer); println!(" password: {}", proxy.password); diff --git a/mullvad-cli/src/cmds/relay.rs b/mullvad-cli/src/cmds/relay.rs index 80ee09a6c9..62d2f58fb6 100644 --- a/mullvad-cli/src/cmds/relay.rs +++ b/mullvad-cli/src/cmds/relay.rs @@ -8,14 +8,8 @@ use std::{ str::FromStr, }; -use mullvad_management_interface::types::{ - connection_config::{self, OpenvpnConfig, WireguardConfig}, - relay_settings, relay_settings_update, ConnectionConfig, CustomRelaySettings, IpVersion, - IpVersionConstraint, NormalRelaySettingsUpdate, OpenvpnConstraints, ProviderUpdate, - RelayListCountry, RelayLocation, RelaySettingsUpdate, TransportPort, TransportProtocol, - TunnelType, TunnelTypeConstraint, TunnelTypeUpdate, WireguardConstraints, -}; -use mullvad_types::relay_constraints::Constraint; +use mullvad_management_interface::types; +use mullvad_types::relay_constraints::{Constraint, RelaySettings}; use talpid_types::net::all_of_the_internet; pub struct Relay; @@ -231,7 +225,7 @@ impl Command for Relay { } impl Relay { - async fn update_constraints(&self, update: RelaySettingsUpdate) -> Result<()> { + async fn update_constraints(&self, update: types::RelaySettingsUpdate) -> Result<()> { let mut rpc = new_rpc_client().await?; rpc.update_relay_settings(update) .await @@ -271,13 +265,13 @@ impl Relay { (_unknown_tunnel, _) => unreachable!("No set relay command given"), }; - self.update_constraints(RelaySettingsUpdate { - r#type: Some(relay_settings_update::Type::Custom(custom_endpoint)), + self.update_constraints(types::RelaySettingsUpdate { + r#type: Some(types::relay_settings_update::Type::Custom(custom_endpoint)), }) .await } - fn read_custom_openvpn_relay(matches: &clap::ArgMatches<'_>) -> CustomRelaySettings { + fn read_custom_openvpn_relay(matches: &clap::ArgMatches<'_>) -> types::CustomRelaySettings { let host = value_t!(matches.value_of("host"), String).unwrap_or_else(|e| e.exit()); let port = value_t!(matches.value_of("port"), u16).unwrap_or_else(|e| e.exit()); let username = value_t!(matches.value_of("username"), String).unwrap_or_else(|e| e.exit()); @@ -286,21 +280,24 @@ impl Relay { let protocol = Self::validate_transport_protocol(&protocol); - CustomRelaySettings { + types::CustomRelaySettings { host, - config: Some(ConnectionConfig { - config: Some(connection_config::Config::Openvpn(OpenvpnConfig { - address: SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), port).to_string(), - protocol: protocol as i32, - username, - password, - })), + config: Some(types::ConnectionConfig { + config: Some(types::connection_config::Config::Openvpn( + types::connection_config::OpenvpnConfig { + address: SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), port) + .to_string(), + protocol: protocol as i32, + username, + password, + }, + )), }), } } - fn read_custom_wireguard_relay(matches: &clap::ArgMatches<'_>) -> CustomRelaySettings { - use connection_config::wireguard_config; + fn read_custom_wireguard_relay(matches: &clap::ArgMatches<'_>) -> types::CustomRelaySettings { + use types::connection_config::wireguard_config; let host = value_t!(matches.value_of("host"), String).unwrap_or_else(|e| e.exit()); let port = value_t!(matches.value_of("port"), u16).unwrap_or_else(|e| e.exit()); @@ -327,33 +324,35 @@ impl Relay { let private_key = Self::validate_wireguard_key(&private_key_str); let peer_public_key = Self::validate_wireguard_key(&peer_key_str); - CustomRelaySettings { + types::CustomRelaySettings { host, - config: Some(ConnectionConfig { - config: Some(connection_config::Config::Wireguard(WireguardConfig { - tunnel: Some(wireguard_config::TunnelConfig { - private_key: private_key.to_vec(), - addresses: addresses - .iter() - .map(|address| address.to_string()) - .collect(), - }), - peer: Some(wireguard_config::PeerConfig { - public_key: peer_public_key.to_vec(), - allowed_ips: all_of_the_internet() - .iter() - .map(|address| address.to_string()) - .collect(), - endpoint: SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), port) - .to_string(), - protocol: protocol as i32, - }), - ipv4_gateway: ipv4_gateway.to_string(), - ipv6_gateway: ipv6_gateway - .as_ref() - .map(|addr| addr.to_string()) - .unwrap_or_default(), - })), + config: Some(types::ConnectionConfig { + config: Some(types::connection_config::Config::Wireguard( + types::connection_config::WireguardConfig { + tunnel: Some(wireguard_config::TunnelConfig { + private_key: private_key.to_vec(), + addresses: addresses + .iter() + .map(|address| address.to_string()) + .collect(), + }), + peer: Some(wireguard_config::PeerConfig { + public_key: peer_public_key.to_vec(), + allowed_ips: all_of_the_internet() + .iter() + .map(|address| address.to_string()) + .collect(), + endpoint: SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), port) + .to_string(), + protocol: protocol as i32, + }), + ipv4_gateway: ipv4_gateway.to_string(), + ipv6_gateway: ipv6_gateway + .as_ref() + .map(|addr| addr.to_string()) + .unwrap_or_default(), + }, + )), }), } } @@ -377,10 +376,10 @@ impl Relay { key } - fn validate_transport_protocol(protocol: &str) -> TransportProtocol { + fn validate_transport_protocol(protocol: &str) -> types::TransportProtocol { match protocol { - "udp" => TransportProtocol::Udp, - "tcp" => TransportProtocol::Tcp, + "udp" => types::TransportProtocol::Udp, + "tcp" => types::TransportProtocol::Tcp, _ => clap::Error::with_description( "invalid transport protocol", clap::ErrorKind::ValueValidation, @@ -412,15 +411,15 @@ impl Relay { location.2.hostname, location.1.name, location.0.name ); - let location_constraint = RelayLocation { + let location_constraint = types::RelayLocation { country: location.0.code.clone(), city: location.1.code.clone(), hostname: location.2.hostname.clone(), }; - self.update_constraints(RelaySettingsUpdate { - r#type: Some(relay_settings_update::Type::Normal( - NormalRelaySettingsUpdate { + self.update_constraints(types::RelaySettingsUpdate { + r#type: Some(types::relay_settings_update::Type::Normal( + types::NormalRelaySettingsUpdate { location: Some(location_constraint), ..Default::default() }, @@ -482,9 +481,9 @@ impl Relay { } } - self.update_constraints(RelaySettingsUpdate { - r#type: Some(relay_settings_update::Type::Normal( - NormalRelaySettingsUpdate { + self.update_constraints(types::RelaySettingsUpdate { + r#type: Some(types::relay_settings_update::Type::Normal( + types::NormalRelaySettingsUpdate { location: Some(location_constraint), ..Default::default() }, @@ -503,10 +502,10 @@ impl Relay { providers }; - self.update_constraints(RelaySettingsUpdate { - r#type: Some(relay_settings_update::Type::Normal( - NormalRelaySettingsUpdate { - providers: Some(ProviderUpdate { providers }), + self.update_constraints(types::RelaySettingsUpdate { + r#type: Some(types::relay_settings_update::Type::Normal( + types::NormalRelaySettingsUpdate { + providers: Some(types::ProviderUpdate { providers }), ..Default::default() }, )), @@ -516,10 +515,10 @@ impl Relay { async fn set_openvpn_constraints(&self, matches: &clap::ArgMatches<'_>) -> Result<()> { let port = parse_transport_port(matches)?; - self.update_constraints(RelaySettingsUpdate { - r#type: Some(relay_settings_update::Type::Normal( - NormalRelaySettingsUpdate { - openvpn_constraints: Some(OpenvpnConstraints { port }), + self.update_constraints(types::RelaySettingsUpdate { + r#type: Some(types::relay_settings_update::Type::Normal( + types::NormalRelaySettingsUpdate { + openvpn_constraints: Some(types::OpenvpnConstraints { port }), ..Default::default() }, )), @@ -533,13 +532,15 @@ impl Relay { let entry_location = parse_entry_location_constraint(matches.values_of("entry location").unwrap()); - self.update_constraints(RelaySettingsUpdate { - r#type: Some(relay_settings_update::Type::Normal( - NormalRelaySettingsUpdate { - wireguard_constraints: Some(WireguardConstraints { + self.update_constraints(types::RelaySettingsUpdate { + r#type: Some(types::relay_settings_update::Type::Normal( + types::NormalRelaySettingsUpdate { + wireguard_constraints: Some(types::WireguardConstraints { port, - ip_version: ip_version.option().map(|protocol| IpVersionConstraint { - protocol: protocol as i32, + ip_version: ip_version.option().map(|protocol| { + types::IpVersionConstraint { + protocol: protocol as i32, + } }), entry_location, }), @@ -552,16 +553,16 @@ impl Relay { async fn set_tunnel_protocol(&self, matches: &clap::ArgMatches<'_>) -> Result<()> { let tunnel_type = match matches.value_of("tunnel protocol").unwrap() { - "wireguard" => Some(TunnelType::Wireguard), - "openvpn" => Some(TunnelType::Openvpn), + "wireguard" => Some(types::TunnelType::Wireguard), + "openvpn" => Some(types::TunnelType::Openvpn), "any" => None, _ => unreachable!(), }; - self.update_constraints(RelaySettingsUpdate { - r#type: Some(relay_settings_update::Type::Normal( - NormalRelaySettingsUpdate { - tunnel_type: Some(TunnelTypeUpdate { - tunnel_type: tunnel_type.map(|tunnel_type| TunnelTypeConstraint { + self.update_constraints(types::RelaySettingsUpdate { + r#type: Some(types::relay_settings_update::Type::Normal( + types::NormalRelaySettingsUpdate { + tunnel_type: Some(types::TunnelTypeUpdate { + tunnel_type: tunnel_type.map(|tunnel_type| types::TunnelTypeConstraint { tunnel_type: tunnel_type as i32, }), }), @@ -574,71 +575,17 @@ impl Relay { async fn get(&self) -> Result<()> { let mut rpc = new_rpc_client().await?; - let constraints = rpc + let relay_settings = rpc .get_settings(()) .await? .into_inner() .relay_settings .unwrap(); - print!("Current constraints: "); - - match constraints.endpoint.unwrap() { - relay_settings::Endpoint::Normal(settings) => match settings.tunnel_type { - None => { - println!( - "Any tunnel protocol with OpenVPN over {} and WireGuard over {} in {} using {}", - Self::format_openvpn_constraints(settings.openvpn_constraints.as_ref()), - Self::format_wireguard_constraints(settings.wireguard_constraints.as_ref()), - location::format_location(settings.location.as_ref()), - location::format_providers(&settings.providers) - ); - } - Some(constraint) => match TunnelType::from_i32(constraint.tunnel_type).unwrap() { - TunnelType::Wireguard => { - println!( - "WireGuard over {} in {} using {}", - Self::format_wireguard_constraints( - settings.wireguard_constraints.as_ref() - ), - location::format_location(settings.location.as_ref()), - location::format_providers(&settings.providers) - ); - } - TunnelType::Openvpn => { - println!( - "OpenVPN over {} in {} using {}", - Self::format_openvpn_constraints(settings.openvpn_constraints.as_ref()), - location::format_location(settings.location.as_ref()), - location::format_providers(&settings.providers) - ); - } - }, - }, - - relay_settings::Endpoint::Custom(settings) => { - let config = settings.config.unwrap(); - match config.config.unwrap() { - connection_config::Config::Openvpn(config) => { - println!( - "custom OpenVPN relay - {} {}", - config.address, - Self::format_transport_protocol(Some( - TransportProtocol::from_i32(config.protocol).unwrap() - )), - ); - } - connection_config::Config::Wireguard(config) => { - let peer = config.peer.unwrap(); - println!( - "custom WireGuard relay - {} with public key {}", - peer.endpoint, - base64::encode(&peer.public_key), - ); - } - } - } - } + print!( + "Current constraints: {}", + RelaySettings::try_from(relay_settings).unwrap() + ); Ok(()) } @@ -692,37 +639,7 @@ impl Relay { Ok(()) } - fn format_transport_protocol(protocol: Option<TransportProtocol>) -> &'static str { - match protocol { - None => "any transport protocol", - Some(TransportProtocol::Udp) => "UDP", - Some(TransportProtocol::Tcp) => "TCP", - } - } - - fn format_openvpn_constraints(constraints: Option<&OpenvpnConstraints>) -> String { - if let Some(constraints) = constraints { - let ovpn_constraints = - mullvad_types::relay_constraints::OpenVpnConstraints::try_from(constraints) - .unwrap(); - format!("{}", ovpn_constraints) - } else { - "any port over any transport protocol".to_string() - } - } - - fn format_wireguard_constraints(constraints: Option<&WireguardConstraints>) -> String { - if let Some(constraints) = constraints { - let wg_constraints = - mullvad_types::relay_constraints::WireguardConstraints::try_from(constraints) - .unwrap(); - format!("{}", wg_constraints) - } else { - "any port over any protocol over IPv4 or IPv6".to_string() - } - } - - async fn get_filtered_relays() -> Result<Vec<RelayListCountry>> { + async fn get_filtered_relays() -> Result<Vec<types::RelayListCountry>> { let mut rpc = new_rpc_client().await?; let mut locations = rpc .get_relay_locations(()) @@ -769,27 +686,27 @@ fn parse_port_constraint(raw_port: &str) -> Result<Constraint<u16>> { } } -fn parse_protocol(raw_protocol: &str) -> Constraint<TransportProtocol> { +fn parse_protocol(raw_protocol: &str) -> Constraint<types::TransportProtocol> { match raw_protocol { "any" => Constraint::Any, - "udp" => Constraint::Only(TransportProtocol::Udp), - "tcp" => Constraint::Only(TransportProtocol::Tcp), + "udp" => Constraint::Only(types::TransportProtocol::Udp), + "tcp" => Constraint::Only(types::TransportProtocol::Tcp), _ => unreachable!(), } } -fn parse_ip_version_constraint(raw_protocol: &str) -> Constraint<IpVersion> { +fn parse_ip_version_constraint(raw_protocol: &str) -> Constraint<types::IpVersion> { match raw_protocol { "any" => Constraint::Any, - "4" => Constraint::Only(IpVersion::V4), - "6" => Constraint::Only(IpVersion::V6), + "4" => Constraint::Only(types::IpVersion::V4), + "6" => Constraint::Only(types::IpVersion::V6), _ => unreachable!(), } } fn parse_entry_location_constraint<'a, T: Iterator<Item = &'a str>>( mut location: T, -) -> Option<RelayLocation> { +) -> Option<types::RelayLocation> { let country = location.next().unwrap(); if country == "none" { @@ -803,16 +720,16 @@ fn parse_entry_location_constraint<'a, T: Iterator<Item = &'a str>>( )) } -fn parse_transport_port(matches: &clap::ArgMatches<'_>) -> Result<Option<TransportPort>> { +fn parse_transport_port(matches: &clap::ArgMatches<'_>) -> Result<Option<types::TransportPort>> { let port = parse_port_constraint(matches.value_of("port").unwrap())?; let protocol = parse_protocol(matches.value_of("transport protocol").unwrap()); match (port, protocol) { (Constraint::Any, Constraint::Any) => Ok(None), - (Constraint::Any, Constraint::Only(protocol)) => Ok(Some(TransportPort { + (Constraint::Any, Constraint::Only(protocol)) => Ok(Some(types::TransportPort { protocol: protocol as i32, - ..TransportPort::default() + ..types::TransportPort::default() })), - (Constraint::Only(port), Constraint::Only(protocol)) => Ok(Some(TransportPort { + (Constraint::Only(port), Constraint::Only(protocol)) => Ok(Some(types::TransportPort { protocol: protocol as i32, port: u32::from(port), })), diff --git a/mullvad-cli/src/location.rs b/mullvad-cli/src/location.rs index cadeaa24fe..e4719f7d37 100644 --- a/mullvad-cli/src/location.rs +++ b/mullvad-cli/src/location.rs @@ -68,30 +68,6 @@ pub fn get_constraint<T: AsRef<str>>( } } -pub fn format_location(location: Option<&RelayLocation>) -> String { - if let Some(location) = location { - if !location.hostname.is_empty() { - return format!( - "city {}, {}, hostname {}", - location.city, location.country, location.hostname - ); - } else if !location.city.is_empty() { - return format!("city {}, {}", location.city, location.country); - } else if !location.country.is_empty() { - return format!("country {}", location.country); - } - } - "any location".to_string() -} - -pub fn format_providers(providers: &Vec<String>) -> String { - if !providers.is_empty() { - format!("provider(s) {}", providers.join(", ")) - } else { - "any provider".to_string() - } -} - pub fn country_code_validator<T: AsRef<str>>(code: T) -> std::result::Result<(), String> { if code.as_ref().len() == 2 || code.as_ref() == "any" { Ok(()) diff --git a/mullvad-management-interface/proto/management_interface.proto b/mullvad-management-interface/proto/management_interface.proto index aa59458979..8711ba7b1b 100644 --- a/mullvad-management-interface/proto/management_interface.proto +++ b/mullvad-management-interface/proto/management_interface.proto @@ -223,7 +223,6 @@ message BridgeSettings { } message RemoteProxySettings { string address = 1; - // NOTE: optional RemoteProxyAuth auth = 2; } message RemoteProxyAuth { @@ -364,7 +363,6 @@ message ConnectionConfig { TunnelConfig tunnel = 1; PeerConfig peer = 2; string ipv4_gateway = 3; - // NOTE: optional string ipv6_gateway = 4; } @@ -376,11 +374,9 @@ message ConnectionConfig { message TunnelOptions { message OpenvpnOptions { - // NOTE: optional uint32 mssfix = 1; } message WireguardOptions { - // NOTE: optional uint32 mtu = 1; google.protobuf.Duration rotation_interval = 2; } diff --git a/mullvad-management-interface/src/types.rs b/mullvad-management-interface/src/types.rs index 28149c427d..81fdbb0e87 100644 --- a/mullvad-management-interface/src/types.rs +++ b/mullvad-management-interface/src/types.rs @@ -2,6 +2,7 @@ pub use prost_types::{Duration, Timestamp}; use mullvad_types::relay_constraints::Constraint; use std::convert::TryFrom; +use talpid_types::ErrorExt; tonic::include_proto!("mullvad_daemon.management_interface"); @@ -734,151 +735,105 @@ impl TryFrom<&OpenvpnConstraints> for mullvad_types::relay_constraints::OpenVpnC } } -impl TryFrom<RelaySettingsUpdate> for mullvad_types::relay_constraints::RelaySettingsUpdate { +impl TryFrom<RelaySettings> for mullvad_types::relay_constraints::RelaySettings { 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; + settings: 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 - .r#type + .endpoint .clone() .ok_or(FromProtobufTypeError::InvalidArgument( "missing relay settings", ))?; match update_value { - relay_settings_update::Type::Custom(settings) => { + relay_settings::Endpoint::Custom(settings) => { let config = settings .config .ok_or(FromProtobufTypeError::InvalidArgument( - "missing relay settings", + "missing relay connection config", ))?; - 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: try_transport_protocol_from_i32(config.protocol)?, - }, - 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 config = mullvad_types::ConnectionConfig::try_from(config)?; + Ok(mullvad_constraints::RelaySettings::CustomTunnelEndpoint( + CustomTunnelEndpoint { + host: settings.host, + config, + }, + )) + } - 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 - }; + relay_settings::Endpoint::Normal(settings) => { + let location = + Constraint::<mullvad_types::relay_constraints::LocationConstraint>::from( + settings + .location + .ok_or(FromProtobufTypeError::InvalidArgument( + "missing relay location", + ))?, + ); + let providers = try_providers_constraint_from_proto(&settings.providers)?; + 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"), + )?, + )?; - let endpoint = match peer.endpoint.parse() { - Ok(address) => address, - Err(_) => { - return Err(FromProtobufTypeError::InvalidArgument( - "invalid peer address", - )) - } - }; + Ok(mullvad_constraints::RelaySettings::Normal( + mullvad_constraints::RelayConstraints { + location, + providers, + tunnel_protocol, + wireguard_constraints, + openvpn_constraints, + }, + )) + } + } + } +} - 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); - } +impl TryFrom<RelaySettingsUpdate> for mullvad_types::relay_constraints::RelaySettingsUpdate { + type Error = FromProtobufTypeError; - 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); - } + fn try_from( + settings: RelaySettingsUpdate, + ) -> Result<mullvad_types::relay_constraints::RelaySettingsUpdate, Self::Error> { + use mullvad_types::{relay_constraints as mullvad_constraints, CustomTunnelEndpoint}; + use talpid_types::net; - 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: try_transport_protocol_from_i32(peer.protocol)?, - }, - exit_peer: None, - ipv4_gateway, - ipv6_gateway, - }) - } - }; + 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 connection config", + ))?; + let config = mullvad_types::ConnectionConfig::try_from(config)?; Ok( mullvad_constraints::RelaySettingsUpdate::CustomTunnelEndpoint( CustomTunnelEndpoint { @@ -896,107 +851,194 @@ impl TryFrom<RelaySettingsUpdate> for mullvad_types::relay_constraints::RelaySet 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 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), - } + Some( + update + .tunnel_type + .map(Constraint::<net::TunnelType>::try_from) + .transpose()? + .unwrap_or(Constraint::Any), + ) } else { None }; - - let openvpn_transport_port = + let openvpn_constraints = if let Some(ref constraints) = settings.openvpn_constraints { - match &constraints.port { - Some(port) => { - Some(mullvad_constraints::TransportPort::try_from(port.clone())?) - } - None => None, - } + Some(mullvad_constraints::OpenVpnConstraints::try_from( + constraints, + )?) } else { None }; - let wireguard_transport_port = + let wireguard_constraints = if let Some(ref constraints) = settings.wireguard_constraints { - match &constraints.port { - Some(port) => { - Some(mullvad_constraints::TransportPort::try_from(port.clone())?) - } - None => None, - } + Some(mullvad_constraints::WireguardConstraints::try_from( + constraints, + )?) } else { None }; + Ok(mullvad_constraints::RelaySettingsUpdate::Normal( + mullvad_constraints::RelayConstraintsUpdate { + location, + providers, + tunnel_protocol, + wireguard_constraints, + openvpn_constraints, + }, + )) + } + } + } +} - 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) +impl TryFrom<TunnelTypeConstraint> for Constraint<talpid_types::net::TunnelType> { + type Error = FromProtobufTypeError; + + fn try_from( + tunnel_type: TunnelTypeConstraint, + ) -> Result<Constraint<talpid_types::net::TunnelType>, Self::Error> { + match TunnelType::from_i32(tunnel_type.tunnel_type) { + Some(TunnelType::Openvpn) => { + Ok(Constraint::Only(talpid_types::net::TunnelType::OpenVpn)) + } + Some(TunnelType::Wireguard) => { + Ok(Constraint::Only(talpid_types::net::TunnelType::Wireguard)) + } + None => Err(FromProtobufTypeError::InvalidArgument( + "invalid tunnel protocol", + )), + } + } +} + +impl TryFrom<ConnectionConfig> for mullvad_types::ConnectionConfig { + type Error = FromProtobufTypeError; + + fn try_from(config: ConnectionConfig) -> Result<mullvad_types::ConnectionConfig, Self::Error> { + use talpid_types::net::{self, openvpn, wireguard}; + + let config = config.config.ok_or(FromProtobufTypeError::InvalidArgument( + "missing connection config", + ))?; + match config { + connection_config::Config::Openvpn(config) => { + let address = match config.address.parse() { + Ok(address) => address, + Err(_) => { + return Err(FromProtobufTypeError::InvalidArgument("invalid address")) } - } 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", - )) - } + + Ok(mullvad_types::ConnectionConfig::OpenVpn( + openvpn::ConnectionConfig { + endpoint: net::Endpoint { + address, + protocol: try_transport_protocol_from_i32(config.protocol)?, }, - None => None, + 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 }; - Ok(mullvad_constraints::RelaySettingsUpdate::Normal( - mullvad_constraints::RelayConstraintsUpdate { - location, - providers, - tunnel_protocol, - wireguard_constraints: settings.wireguard_constraints.map(|constraints| { - mullvad_constraints::WireguardConstraints { - port: Constraint::from(wireguard_transport_port), - ip_version: Constraint::from(ip_version), - entry_location: constraints.entry_location.map( - Constraint::< - mullvad_types::relay_constraints::LocationConstraint, - >::from, - ), - } - }), - openvpn_constraints: settings.openvpn_constraints.map(|_constraints| { - mullvad_constraints::OpenVpnConstraints { - port: Constraint::from(openvpn_transport_port), - } - }), + 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); + } + + 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: wireguard::PublicKey::from(public_key), + allowed_ips, + endpoint, + protocol: try_transport_protocol_from_i32(peer.protocol)?, + }, + exit_peer: None, + ipv4_gateway, + ipv6_gateway, }, )) } @@ -1043,20 +1085,7 @@ impl TryFrom<BridgeSettings> for mullvad_types::relay_constraints::BridgeSetting Constraint::<mullvad_constraints::LocationConstraint>::from(location) } }; - let providers = if constraints.providers.is_empty() { - Constraint::Any - } else { - Constraint::Only( - mullvad_constraints::Providers::new( - constraints.providers.clone().into_iter(), - ) - .map_err(|_| { - FromProtobufTypeError::InvalidArgument( - "must specify at least one provider", - ) - })?, - ) - }; + let providers = try_providers_constraint_from_proto(&constraints.providers)?; Ok(mullvad_constraints::BridgeSettings::Normal( mullvad_constraints::BridgeConstraints { @@ -1128,6 +1157,73 @@ impl TryFrom<BridgeState> for mullvad_types::relay_constraints::BridgeState { } } +impl TryFrom<TunnelOptions> for mullvad_types::settings::TunnelOptions { + type Error = FromProtobufTypeError; + + fn try_from(options: 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 + }, + }, + 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<DnsOptions> for mullvad_types::settings::DnsOptions { type Error = FromProtobufTypeError; @@ -1207,6 +1303,20 @@ fn try_transport_protocol_from_i32( .into()) } +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) + } +} + fn convert_providers_constraint( providers: &Constraint<mullvad_types::relay_constraints::Providers>, ) -> Vec<String> { |
