diff options
| author | David Lönnhager <david.l@mullvad.net> | 2020-08-11 14:44:13 +0200 |
|---|---|---|
| committer | David Lönnhager <david.l@mullvad.net> | 2020-08-20 14:41:41 +0200 |
| commit | 45ee23da9eda49462db6cc55f0e4f78b133727b9 (patch) | |
| tree | e3f90447cd9616587bd1833d83025403fbb62851 | |
| parent | 235c7189109d2d47e860cdb3a054266b4506e022 (diff) | |
| download | mullvadvpn-45ee23da9eda49462db6cc55f0e4f78b133727b9.tar.xz mullvadvpn-45ee23da9eda49462db6cc55f0e4f78b133727b9.zip | |
Add mullvad-management-interface crate for IPC types and functions
37 files changed, 581 insertions, 656 deletions
diff --git a/Cargo.lock b/Cargo.lock index 64dc79c378..1f78c3f373 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1182,7 +1182,6 @@ dependencies = [ name = "mullvad-cli" version = "2020.5.0" dependencies = [ - "async-trait 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1190,18 +1189,13 @@ dependencies = [ "err-derive 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "mullvad-management-interface 0.1.0", "mullvad-paths 0.1.0", "mullvad-types 0.1.0", "natord 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-tokio-ipc 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "prost 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "prost-types 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "talpid-types 0.1.0", "tokio 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", - "tonic 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tonic-build 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tower 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "winres 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1226,14 +1220,12 @@ dependencies = [ "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "log-panics 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "mullvad-management-interface 0.1.0", "mullvad-paths 0.1.0", "mullvad-rpc 0.1.0", "mullvad-types 0.1.0", "nix 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-tokio-ipc 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "prost 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "prost-types 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1245,9 +1237,6 @@ dependencies = [ "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-retry 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-timer 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tonic 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tonic-build 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tower 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "triggered 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1290,6 +1279,24 @@ dependencies = [ ] [[package]] +name = "mullvad-management-interface" +version = "0.1.0" +dependencies = [ + "err-derive 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "mullvad-paths 0.1.0", + "parity-tokio-ipc 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "prost 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "prost-types 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", + "tonic 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tonic-build 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tower 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "triggered 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "mullvad-paths" version = "0.1.0" dependencies = [ @@ -1353,16 +1360,11 @@ dependencies = [ "clap 2.33.3 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "err-derive 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "mullvad-management-interface 0.1.0", "mullvad-paths 0.1.0", - "parity-tokio-ipc 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "prost 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "prost-types 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "talpid-core 0.1.0", "talpid-types 0.1.0", "tokio 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", - "tonic 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tonic-build 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tower 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "winres 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1382,7 +1384,6 @@ dependencies = [ "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "talpid-types 0.1.0", - "tonic 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index fed2deb291..f87705cf22 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,7 @@ members = [ "mullvad-exclude", "talpid-openvpn-plugin", "talpid-core", + "mullvad-management-interface", ] exclude = ["dist-assets/binaries/shadowsocks-rust"] diff --git a/mullvad-cli/Cargo.toml b/mullvad-cli/Cargo.toml index 5cb9ecb187..1746993bff 100644 --- a/mullvad-cli/Cargo.toml +++ b/mullvad-cli/Cargo.toml @@ -16,7 +16,6 @@ name = "mullvad" path = "src/main.rs" [dependencies] -async-trait = "0.1" base64 = "0.10" chrono = { version = "0.4", features = ["serde"] } clap = "2.32" @@ -30,18 +29,10 @@ mullvad-types = { path = "../mullvad-types" } mullvad-paths = { path = "../mullvad-paths" } talpid-types = { path = "../talpid-types" } -tonic = "0.2" -tower = "0.3" -prost = "0.6" -prost-types = "0.6" +mullvad-management-interface = { path = "../mullvad-management-interface" } futures03 = { package = "futures", version = "0.3", features = [ "compat" ]} tokio = { version = "0.2", features = [ "io-util", "process", "rt-core", "rt-threaded", "stream"] } -parity-tokio-ipc = "0.7" - -[build-dependencies] -tonic-build = { version = "0.2", default-features = false, features = ["transport", "prost"] } - [target.'cfg(windows)'.build-dependencies] winres = "0.1" winapi = "0.3" diff --git a/mullvad-cli/build.rs b/mullvad-cli/build.rs index 4b92840529..4c19603b76 100644 --- a/mullvad-cli/build.rs +++ b/mullvad-cli/build.rs @@ -1,10 +1,6 @@ use std::{env, fs, path::PathBuf}; fn main() { - const PROTO_FILE: &str = "../mullvad-daemon/proto/management_interface.proto"; - tonic_build::compile_protos(PROTO_FILE).unwrap(); - println!("cargo:rerun-if-changed={}", PROTO_FILE); - let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); let product_version = env!("CARGO_PKG_VERSION").replacen(".0", "", 1); fs::write(out_dir.join("product-version.txt"), &product_version).unwrap(); diff --git a/mullvad-cli/src/cmds/account.rs b/mullvad-cli/src/cmds/account.rs index a0a223eaf2..ef5c117c41 100644 --- a/mullvad-cli/src/cmds/account.rs +++ b/mullvad-cli/src/cmds/account.rs @@ -1,10 +1,11 @@ -use crate::{new_grpc_client, Command, Error, Result}; +use crate::{new_rpc_client, Command, Error, Result}; use clap::value_t_or_exit; -use mullvad_types::account::{AccountToken, VoucherError}; +use mullvad_management_interface::{types::Timestamp, Code}; +use mullvad_types::account::AccountToken; pub struct Account; -#[async_trait::async_trait] +#[mullvad_management_interface::async_trait] impl Command for Account { fn name(&self) -> &'static str { "account" @@ -73,7 +74,7 @@ impl Command for Account { impl Account { async fn set(&self, token: Option<AccountToken>) -> Result<()> { - let mut rpc = new_grpc_client().await?; + let mut rpc = new_rpc_client().await?; rpc.set_account(token.clone().unwrap_or_default()).await?; if let Some(token) = token { println!("Mullvad account \"{}\" set", token); @@ -84,7 +85,7 @@ impl Account { } async fn get(&self) -> Result<()> { - let mut rpc = new_grpc_client().await?; + let mut rpc = new_rpc_client().await?; let settings = rpc.get_settings(()).await?.into_inner(); if settings.account_token != "" { println!("Mullvad account: {}", settings.account_token); @@ -103,14 +104,14 @@ impl Account { } async fn create(&self) -> Result<()> { - let mut rpc = new_grpc_client().await?; + let mut rpc = new_rpc_client().await?; rpc.create_new_account(()).await?; println!("New account created!"); self.get().await } async fn redeem_voucher(&self, mut voucher: String) -> Result<()> { - let mut rpc = new_grpc_client().await?; + let mut rpc = new_rpc_client().await?; voucher.retain(|c| c.is_alphanumeric()); match rpc.submit_voucher(voucher).await { @@ -127,11 +128,13 @@ impl Account { Ok(()) } Err(err) => { - eprintln!( - "Failed to submit voucher.\n{}", - VoucherError::from_rpc_error_code(err.code() as i64) - ); - Err(Error::GrpcClientError(err)) + match err.code() { + Code::NotFound | Code::ResourceExhausted => { + eprintln!("Failed to submit voucher: {}", err.message()); + } + _ => return Err(Error::GrpcClientError(err)), + } + std::process::exit(1); } } } @@ -149,12 +152,12 @@ impl Account { } } - fn format_expiry(expiry: &prost_types::Timestamp) -> String { + fn format_expiry(expiry: &Timestamp) -> String { chrono::NaiveDateTime::from_timestamp(expiry.seconds, expiry.nanos as u32).to_string() } async fn clear_history(&self) -> Result<()> { - let mut rpc = new_grpc_client().await?; + let mut rpc = new_rpc_client().await?; rpc.clear_account_history(()).await?; println!("Removed account history and all associated keys"); Ok(()) diff --git a/mullvad-cli/src/cmds/auto_connect.rs b/mullvad-cli/src/cmds/auto_connect.rs index e934e8e37c..40f8f2bd9e 100644 --- a/mullvad-cli/src/cmds/auto_connect.rs +++ b/mullvad-cli/src/cmds/auto_connect.rs @@ -1,9 +1,9 @@ -use crate::{new_grpc_client, Command, Result}; +use crate::{new_rpc_client, Command, Result}; use clap::value_t_or_exit; pub struct AutoConnect; -#[async_trait::async_trait] +#[mullvad_management_interface::async_trait] impl Command for AutoConnect { fn name(&self) -> &'static str { "auto-connect" @@ -42,14 +42,14 @@ impl Command for AutoConnect { impl AutoConnect { async fn set(&self, auto_connect: bool) -> Result<()> { - let mut rpc = new_grpc_client().await?; + let mut rpc = new_rpc_client().await?; rpc.set_auto_connect(auto_connect).await?; println!("Changed auto-connect sharing setting"); Ok(()) } async fn get(&self) -> Result<()> { - let mut rpc = new_grpc_client().await?; + let mut rpc = new_rpc_client().await?; let auto_connect = rpc.get_settings(()).await?.into_inner().auto_connect; println!("Autoconnect: {}", if auto_connect { "on" } else { "off" }); Ok(()) diff --git a/mullvad-cli/src/cmds/beta_program.rs b/mullvad-cli/src/cmds/beta_program.rs index 3950d54433..73a0ba15c7 100644 --- a/mullvad-cli/src/cmds/beta_program.rs +++ b/mullvad-cli/src/cmds/beta_program.rs @@ -1,9 +1,9 @@ -use crate::{new_grpc_client, Command, Error, Result, PRODUCT_VERSION}; +use crate::{new_rpc_client, Command, Error, Result, PRODUCT_VERSION}; use clap::value_t_or_exit; pub struct BetaProgram; -#[async_trait::async_trait] +#[mullvad_management_interface::async_trait] impl Command for BetaProgram { fn name(&self) -> &'static str { "beta-program" @@ -28,7 +28,7 @@ impl Command for BetaProgram { async fn run(&self, matches: &clap::ArgMatches<'_>) -> Result<()> { match matches.subcommand() { ("get", Some(_)) => { - let mut rpc = new_grpc_client().await?; + let mut rpc = new_rpc_client().await?; let settings = rpc.get_settings(()).await?.into_inner(); let enabled_str = if settings.show_beta_releases { "on" @@ -48,7 +48,7 @@ impl Command for BetaProgram { )); } - let mut rpc = new_grpc_client().await?; + let mut rpc = new_rpc_client().await?; rpc.set_show_beta_releases(enable).await?; println!("Beta program: {}", enable_str); diff --git a/mullvad-cli/src/cmds/block_when_disconnected.rs b/mullvad-cli/src/cmds/block_when_disconnected.rs index b66acf168d..3cb1baff5a 100644 --- a/mullvad-cli/src/cmds/block_when_disconnected.rs +++ b/mullvad-cli/src/cmds/block_when_disconnected.rs @@ -1,9 +1,9 @@ -use crate::{new_grpc_client, Command, Result}; +use crate::{new_rpc_client, Command, Result}; use clap::value_t_or_exit; pub struct BlockWhenDisconnected; -#[async_trait::async_trait] +#[mullvad_management_interface::async_trait] impl Command for BlockWhenDisconnected { fn name(&self) -> &'static str { "always-require-vpn" @@ -42,7 +42,7 @@ impl Command for BlockWhenDisconnected { impl BlockWhenDisconnected { async fn set(&self, block_when_disconnected: bool) -> Result<()> { - let mut rpc = new_grpc_client().await?; + let mut rpc = new_rpc_client().await?; rpc.set_block_when_disconnected(block_when_disconnected) .await?; println!("Changed always require VPN setting"); @@ -50,7 +50,7 @@ impl BlockWhenDisconnected { } async fn get(&self) -> Result<()> { - let mut rpc = new_grpc_client().await?; + let mut rpc = new_rpc_client().await?; let block_when_disconnected = rpc .get_settings(()) .await? diff --git a/mullvad-cli/src/cmds/bridge.rs b/mullvad-cli/src/cmds/bridge.rs index 7ad4cf1b22..3118c09a39 100644 --- a/mullvad-cli/src/cmds/bridge.rs +++ b/mullvad-cli/src/cmds/bridge.rs @@ -1,7 +1,7 @@ -use crate::{location, new_grpc_client, Command, Result}; +use crate::{location, new_rpc_client, Command, Result}; use clap::value_t; -use crate::proto::{ +use mullvad_management_interface::types::{ bridge_settings::{Type as BridgeSettingsType, *}, bridge_state::State as BridgeStateType, BridgeSettings, BridgeState, @@ -12,7 +12,7 @@ use std::net::{IpAddr, SocketAddr}; pub struct Bridge; -#[async_trait::async_trait] +#[mullvad_management_interface::async_trait] impl Command for Bridge { fn name(&self) -> &'static str { "bridge" @@ -164,7 +164,7 @@ impl Bridge { } async fn handle_get() -> Result<()> { - let mut rpc = new_grpc_client().await?; + 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() { @@ -185,7 +185,7 @@ impl Bridge { async fn handle_set_bridge_location(matches: &clap::ArgMatches<'_>) -> Result<()> { let constraints = location::get_constraint(matches); - let mut rpc = new_grpc_client().await?; + let mut rpc = new_rpc_client().await?; rpc.set_bridge_settings(BridgeSettings { r#type: Some(BridgeSettingsType::Normal(BridgeConstraints { location: Some(constraints), @@ -202,7 +202,7 @@ impl Bridge { "off" => BridgeStateType::Off as i32, _ => unreachable!(), }; - let mut rpc = new_grpc_client().await?; + let mut rpc = new_rpc_client().await?; rpc.set_bridge_state(BridgeState { state }).await?; Ok(()) } @@ -231,7 +231,7 @@ impl Bridge { panic!(error); } - let mut rpc = new_grpc_client().await?; + let mut rpc = new_rpc_client().await?; rpc.set_bridge_settings(BridgeSettings { r#type: Some(BridgeSettingsType::Local(prost_proxy)), }) @@ -270,7 +270,7 @@ impl Bridge { panic!(error); } - let mut rpc = new_grpc_client().await?; + let mut rpc = new_rpc_client().await?; rpc.set_bridge_settings(BridgeSettings { r#type: Some(BridgeSettingsType::Remote(prost_proxy)), }) @@ -299,7 +299,7 @@ impl Bridge { panic!(error); } - let mut rpc = new_grpc_client().await?; + let mut rpc = new_rpc_client().await?; rpc.set_bridge_settings(BridgeSettings { r#type: Some(BridgeSettingsType::Shadowsocks(prost_proxy)), }) @@ -347,7 +347,7 @@ impl Bridge { } async fn list_bridge_relays() -> Result<()> { - let mut rpc = new_grpc_client().await?; + let mut rpc = new_rpc_client().await?; let mut locations = rpc.get_relay_locations(()).await?.into_inner(); let mut countries = Vec::new(); diff --git a/mullvad-cli/src/cmds/connect.rs b/mullvad-cli/src/cmds/connect.rs index 899a450547..6fc7072580 100644 --- a/mullvad-cli/src/cmds/connect.rs +++ b/mullvad-cli/src/cmds/connect.rs @@ -1,9 +1,9 @@ -use crate::{new_grpc_client, Command, Result}; +use crate::{new_rpc_client, Command, Result}; use talpid_types::ErrorExt; pub struct Connect; -#[async_trait::async_trait] +#[mullvad_management_interface::async_trait] impl Command for Connect { fn name(&self) -> &'static str { "connect" @@ -15,7 +15,7 @@ impl Command for Connect { } async fn run(&self, _: &clap::ArgMatches<'_>) -> Result<()> { - let mut rpc = new_grpc_client().await?; + let mut rpc = new_rpc_client().await?; if let Err(e) = rpc.connect_tunnel(()).await { eprintln!("{}", e.display_chain()); } diff --git a/mullvad-cli/src/cmds/disconnect.rs b/mullvad-cli/src/cmds/disconnect.rs index a3d6698fc9..f976b96fab 100644 --- a/mullvad-cli/src/cmds/disconnect.rs +++ b/mullvad-cli/src/cmds/disconnect.rs @@ -1,8 +1,8 @@ -use crate::{new_grpc_client, Command, Result}; +use crate::{new_rpc_client, Command, Result}; pub struct Disconnect; -#[async_trait::async_trait] +#[mullvad_management_interface::async_trait] impl Command for Disconnect { fn name(&self) -> &'static str { "disconnect" @@ -14,7 +14,7 @@ impl Command for Disconnect { } async fn run(&self, _: &clap::ArgMatches<'_>) -> Result<()> { - let mut rpc = new_grpc_client().await?; + let mut rpc = new_rpc_client().await?; rpc.disconnect_tunnel(()).await?; Ok(()) } diff --git a/mullvad-cli/src/cmds/lan.rs b/mullvad-cli/src/cmds/lan.rs index 05f4f867d2..dd84851f33 100644 --- a/mullvad-cli/src/cmds/lan.rs +++ b/mullvad-cli/src/cmds/lan.rs @@ -1,9 +1,9 @@ -use crate::{new_grpc_client, Command, Result}; +use crate::{new_rpc_client, Command, Result}; use clap::value_t_or_exit; pub struct Lan; -#[async_trait::async_trait] +#[mullvad_management_interface::async_trait] impl Command for Lan { fn name(&self) -> &'static str { "lan" @@ -42,14 +42,14 @@ impl Command for Lan { impl Lan { async fn set(&self, allow_lan: bool) -> Result<()> { - let mut rpc = new_grpc_client().await?; + let mut rpc = new_rpc_client().await?; rpc.set_allow_lan(allow_lan).await?; println!("Changed local network sharing setting"); Ok(()) } async fn get(&self) -> Result<()> { - let mut rpc = new_grpc_client().await?; + let mut rpc = new_rpc_client().await?; let allow_lan = rpc.get_settings(()).await?.into_inner().allow_lan; println!( "Local network sharing setting: {}", diff --git a/mullvad-cli/src/cmds/reconnect.rs b/mullvad-cli/src/cmds/reconnect.rs index d281266e11..ecc0b089c0 100644 --- a/mullvad-cli/src/cmds/reconnect.rs +++ b/mullvad-cli/src/cmds/reconnect.rs @@ -1,9 +1,9 @@ -use crate::{new_grpc_client, Command, Result}; +use crate::{new_rpc_client, Command, Result}; use talpid_types::ErrorExt; pub struct Reconnect; -#[async_trait::async_trait] +#[mullvad_management_interface::async_trait] impl Command for Reconnect { fn name(&self) -> &'static str { "reconnect" @@ -14,7 +14,7 @@ impl Command for Reconnect { } async fn run(&self, _: &clap::ArgMatches<'_>) -> Result<()> { - let mut rpc = new_grpc_client().await?; + let mut rpc = new_rpc_client().await?; if let Err(e) = rpc.reconnect_tunnel(()).await { eprintln!("{}", e.display_chain()); } diff --git a/mullvad-cli/src/cmds/relay.rs b/mullvad-cli/src/cmds/relay.rs index 07d07fc447..ba00654258 100644 --- a/mullvad-cli/src/cmds/relay.rs +++ b/mullvad-cli/src/cmds/relay.rs @@ -1,4 +1,4 @@ -use crate::{location, new_grpc_client, proto, Command, Error, Result}; +use crate::{location, new_rpc_client, Command, Error, Result}; use clap::{value_t, values_t}; use std::{ io::{self, BufRead}, @@ -6,18 +6,18 @@ use std::{ str::FromStr, }; -use mullvad_types::relay_constraints::Constraint; -use proto::{ +use mullvad_management_interface::types::{ connection_config::{self, OpenvpnConfig, WireguardConfig}, relay_settings, relay_settings_update, ConnectionConfig, CustomRelaySettings, NormalRelaySettingsUpdate, OpenvpnConstraints, RelaySettingsUpdate, TransportProtocol, TunnelType, TunnelTypeUpdate, WireguardConstraints, }; +use mullvad_types::relay_constraints::Constraint; use talpid_types::net::all_of_the_internet; pub struct Relay; -#[async_trait::async_trait] +#[mullvad_management_interface::async_trait] impl Command for Relay { fn name(&self) -> &'static str { "relay" @@ -171,7 +171,7 @@ impl Command for Relay { impl Relay { async fn update_constraints(&self, update: RelaySettingsUpdate) -> Result<()> { - let mut rpc = new_grpc_client().await?; + let mut rpc = new_rpc_client().await?; rpc.update_relay_settings(update).await?; println!("Relay constraints updated"); Ok(()) @@ -384,7 +384,7 @@ impl Relay { } async fn get(&self) -> Result<()> { - let mut rpc = new_grpc_client().await?; + let mut rpc = new_rpc_client().await?; let constraints = rpc .get_settings(()) .await? @@ -454,7 +454,7 @@ impl Relay { } async fn list(&self) -> Result<()> { - let mut rpc = new_grpc_client().await?; + let mut rpc = new_rpc_client().await?; let mut locations = rpc.get_relay_locations(()).await?.into_inner(); let mut countries = Vec::new(); @@ -517,7 +517,7 @@ impl Relay { } async fn update(&self) -> Result<()> { - new_grpc_client().await?.update_relay_locations(()).await?; + new_rpc_client().await?.update_relay_locations(()).await?; println!("Updating relay list in the background..."); Ok(()) } diff --git a/mullvad-cli/src/cmds/reset.rs b/mullvad-cli/src/cmds/reset.rs index 2461e86ad5..bb10a3f0fe 100644 --- a/mullvad-cli/src/cmds/reset.rs +++ b/mullvad-cli/src/cmds/reset.rs @@ -1,8 +1,8 @@ -use crate::{new_grpc_client, Command, Result}; +use crate::{new_rpc_client, Command, Result}; use std::io::stdin; pub struct Reset; -#[async_trait::async_trait] +#[mullvad_management_interface::async_trait] impl Command for Reset { fn name(&self) -> &'static str { "factory-reset" @@ -13,7 +13,7 @@ impl Command for Reset { } async fn run(&self, _: &clap::ArgMatches<'_>) -> Result<()> { - let mut rpc = new_grpc_client().await?; + let mut rpc = new_rpc_client().await?; if Self::receive_confirmation() { if rpc.factory_reset(()).await.is_err() { eprintln!("FAILED TO PERFORM FACTORY RESET"); diff --git a/mullvad-cli/src/cmds/split_tunnel/linux.rs b/mullvad-cli/src/cmds/split_tunnel/linux.rs index 5e8a9b9644..5903d84f68 100644 --- a/mullvad-cli/src/cmds/split_tunnel/linux.rs +++ b/mullvad-cli/src/cmds/split_tunnel/linux.rs @@ -1,9 +1,9 @@ -use crate::{new_grpc_client, Command, Result}; +use crate::{new_rpc_client, Command, Result}; use clap::value_t_or_exit; pub struct SplitTunnel; -#[async_trait::async_trait] +#[mullvad_management_interface::async_trait] impl Command for SplitTunnel { fn name(&self) -> &'static str { "split-tunnel" @@ -43,7 +43,7 @@ impl SplitTunnel { match matches.subcommand() { ("add", Some(matches)) => { let pid = value_t_or_exit!(matches.value_of("pid"), i32); - new_grpc_client() + new_rpc_client() .await? .add_split_tunnel_process(pid) .await?; @@ -51,21 +51,21 @@ impl SplitTunnel { } ("delete", Some(matches)) => { let pid = value_t_or_exit!(matches.value_of("pid"), i32); - new_grpc_client() + new_rpc_client() .await? .remove_split_tunnel_process(pid) .await?; Ok(()) } ("clear", Some(_)) => { - new_grpc_client() + new_rpc_client() .await? .clear_split_tunnel_processes(()) .await?; Ok(()) } ("list", Some(_)) => { - let mut pids_stream = new_grpc_client() + let mut pids_stream = new_rpc_client() .await? .get_split_tunnel_processes(()) .await? diff --git a/mullvad-cli/src/cmds/status.rs b/mullvad-cli/src/cmds/status.rs index ec05492c46..5084cea8b8 100644 --- a/mullvad-cli/src/cmds/status.rs +++ b/mullvad-cli/src/cmds/status.rs @@ -1,19 +1,21 @@ -use crate::{format::print_keygen_event, new_grpc_client, proto, Command, Error, Result}; -use mullvad_types::auth_failed::AuthFailed; -use proto::{ - daemon_event::Event as EventType, - error_state::{ - firewall_policy_error::ErrorType as FirewallPolicyErrorType, Cause as ErrorStateCause, - FirewallPolicyError, GenerationError, +use crate::{format::print_keygen_event, new_rpc_client, Command, Error, Result}; +use mullvad_management_interface::{ + types::{ + daemon_event::Event as EventType, + error_state::{ + firewall_policy_error::ErrorType as FirewallPolicyErrorType, Cause as ErrorStateCause, + FirewallPolicyError, GenerationError, + }, + ErrorState, ProxyType, TransportProtocol, TunnelEndpoint, TunnelState, TunnelType, }, - management_service_client::ManagementServiceClient, - ErrorState, ProxyType, TransportProtocol, TunnelEndpoint, TunnelState, TunnelType, + ManagementServiceClient, }; +use mullvad_types::auth_failed::AuthFailed; use std::fmt::Write; pub struct Status; -#[async_trait::async_trait] +#[mullvad_management_interface::async_trait] impl Command for Status { fn name(&self) -> &'static str { "status" @@ -40,7 +42,7 @@ impl Command for Status { } async fn run(&self, matches: &clap::ArgMatches<'_>) -> Result<()> { - let mut rpc = new_grpc_client().await?; + let mut rpc = new_rpc_client().await?; let state = rpc.get_tunnel_state(()).await?.into_inner(); print_state(&state); @@ -57,7 +59,7 @@ impl Command for Status { match event.event.unwrap() { EventType::TunnelState(new_state) => { print_state(&new_state); - use proto::tunnel_state::State::*; + use mullvad_management_interface::types::tunnel_state::State::*; match new_state.state.unwrap() { Connected(..) | Disconnected(..) => { if matches.is_present("location") { @@ -97,7 +99,7 @@ impl Command for Status { } fn print_state(state: &TunnelState) { - use proto::{tunnel_state, tunnel_state::State::*}; + use mullvad_management_interface::types::{tunnel_state, tunnel_state::State::*}; print!("Tunnel status: "); match state.state.as_ref().unwrap() { @@ -242,14 +244,12 @@ fn policy_error_to_string(policy_error: &FirewallPolicyError) -> String { format!("Failed to set firewall policy: {}", cause) } -async fn print_location( - rpc: &mut ManagementServiceClient<tonic::transport::Channel>, -) -> Result<()> { +async fn print_location(rpc: &mut ManagementServiceClient) -> Result<()> { let location = rpc.get_current_location(()).await; let location = match location { Ok(response) => response.into_inner(), Err(status) => { - if status.code() == tonic::Code::NotFound { + if status.code() == mullvad_management_interface::Code::NotFound { println!("Location data unavailable"); return Ok(()); } else { diff --git a/mullvad-cli/src/cmds/tunnel.rs b/mullvad-cli/src/cmds/tunnel.rs index 3c3d55092f..601115003b 100644 --- a/mullvad-cli/src/cmds/tunnel.rs +++ b/mullvad-cli/src/cmds/tunnel.rs @@ -1,10 +1,10 @@ -use crate::{format::print_keygen_event, new_grpc_client, proto, Command, Error, Result}; +use crate::{format::print_keygen_event, new_rpc_client, Command, Error, Result}; use clap::value_t; -use proto::TunnelOptions; +use mullvad_management_interface::types::{Timestamp, TunnelOptions}; pub struct Tunnel; -#[async_trait::async_trait] +#[mullvad_management_interface::async_trait] impl Command for Tunnel { fn name(&self) -> &'static str { "tunnel" @@ -165,26 +165,26 @@ impl Tunnel { async fn process_wireguard_mtu_set(matches: &clap::ArgMatches<'_>) -> Result<()> { let mtu = value_t!(matches.value_of("mtu"), u16).unwrap_or_else(|e| e.exit()); - let mut rpc = new_grpc_client().await?; + let mut rpc = new_rpc_client().await?; rpc.set_wireguard_mtu(mtu as u32).await?; println!("Wireguard MTU has been updated"); Ok(()) } async fn process_wireguard_mtu_unset() -> Result<()> { - let mut rpc = new_grpc_client().await?; + let mut rpc = new_rpc_client().await?; rpc.set_wireguard_mtu(0).await?; println!("Wireguard MTU has been unset"); Ok(()) } async fn process_wireguard_key_check() -> Result<()> { - let mut rpc = new_grpc_client().await?; + let mut rpc = new_rpc_client().await?; let key = rpc.get_wireguard_key(()).await; let key = match key { Ok(response) => Some(response.into_inner()), Err(status) => { - if status.code() == tonic::Code::NotFound { + if status.code() == mullvad_management_interface::Code::NotFound { None } else { return Err(Error::GrpcClientError(status)); @@ -208,7 +208,7 @@ impl Tunnel { } async fn process_wireguard_key_generate() -> Result<()> { - let mut rpc = new_grpc_client().await?; + let mut rpc = new_rpc_client().await?; let keygen_event = rpc.generate_wireguard_key(()).await?; print_keygen_event(&keygen_event.into_inner()); Ok(()) @@ -226,14 +226,14 @@ impl Tunnel { async fn process_wireguard_rotation_interval_set(matches: &clap::ArgMatches<'_>) -> Result<()> { let rotate_interval = value_t!(matches.value_of("interval"), u32).unwrap_or_else(|e| e.exit()); - let mut rpc = new_grpc_client().await?; + let mut rpc = new_rpc_client().await?; rpc.set_wireguard_rotation_interval(rotate_interval).await?; println!("Set key rotation interval: {} hour(s)", rotate_interval); Ok(()) } async fn process_wireguard_rotation_interval_reset() -> Result<()> { - let mut rpc = new_grpc_client().await?; + let mut rpc = new_rpc_client().await?; rpc.reset_wireguard_rotation_interval(()).await?; println!("Set key rotation interval: default"); Ok(()) @@ -264,7 +264,7 @@ impl Tunnel { } async fn get_tunnel_options() -> Result<TunnelOptions> { - let mut rpc = new_grpc_client().await?; + let mut rpc = new_rpc_client().await?; Ok(rpc .get_settings(()) .await? @@ -274,7 +274,7 @@ impl Tunnel { } async fn process_openvpn_mssfix_unset() -> Result<()> { - let mut rpc = new_grpc_client().await?; + let mut rpc = new_rpc_client().await?; rpc.set_openvpn_mssfix(0).await?; println!("mssfix parameter has been unset"); Ok(()) @@ -282,7 +282,7 @@ impl Tunnel { async fn process_openvpn_mssfix_set(matches: &clap::ArgMatches<'_>) -> Result<()> { let new_value = value_t!(matches.value_of("mssfix"), u16).unwrap_or_else(|e| e.exit()); - let mut rpc = new_grpc_client().await?; + let mut rpc = new_rpc_client().await?; rpc.set_openvpn_mssfix(new_value as u32).await?; println!("mssfix parameter has been updated"); Ok(()) @@ -304,7 +304,7 @@ impl Tunnel { async fn process_ipv6_set(matches: &clap::ArgMatches<'_>) -> Result<()> { let enabled = matches.value_of("enable").unwrap() == "on"; - let mut rpc = new_grpc_client().await?; + let mut rpc = new_rpc_client().await?; rpc.set_enable_ipv6(enabled).await?; if enabled { println!("Enabled IPv6"); @@ -314,7 +314,7 @@ impl Tunnel { Ok(()) } - fn format_key_timestamp(timestamp: &prost_types::Timestamp) -> String { + fn format_key_timestamp(timestamp: &Timestamp) -> String { chrono::NaiveDateTime::from_timestamp(timestamp.seconds, timestamp.nanos as u32).to_string() } } diff --git a/mullvad-cli/src/cmds/version.rs b/mullvad-cli/src/cmds/version.rs index 48b3e621ed..0d66411283 100644 --- a/mullvad-cli/src/cmds/version.rs +++ b/mullvad-cli/src/cmds/version.rs @@ -1,8 +1,8 @@ -use crate::{new_grpc_client, Command, Result}; +use crate::{new_rpc_client, Command, Result}; pub struct Version; -#[async_trait::async_trait] +#[mullvad_management_interface::async_trait] impl Command for Version { fn name(&self) -> &'static str { "version" @@ -14,7 +14,7 @@ impl Command for Version { } async fn run(&self, _: &clap::ArgMatches<'_>) -> Result<()> { - let mut rpc = new_grpc_client().await?; + let mut rpc = new_rpc_client().await?; let current_version = rpc.get_current_version(()).await?.into_inner(); println!("Current version: {}", current_version); let version_info = rpc.get_version_info(()).await?.into_inner(); diff --git a/mullvad-cli/src/format.rs b/mullvad-cli/src/format.rs index c2e71fce0f..4f69d05317 100644 --- a/mullvad-cli/src/format.rs +++ b/mullvad-cli/src/format.rs @@ -1,7 +1,7 @@ -use crate::proto::KeygenEvent; +use mullvad_management_interface::types::KeygenEvent; pub fn print_keygen_event(key_event: &KeygenEvent) { - use crate::proto::keygen_event::KeygenEvent as EventType; + use mullvad_management_interface::types::keygen_event::KeygenEvent as EventType; match EventType::from_i32(key_event.event).unwrap() { EventType::NewKey => { diff --git a/mullvad-cli/src/location.rs b/mullvad-cli/src/location.rs index 3d2705ae88..21e6a1c35c 100644 --- a/mullvad-cli/src/location.rs +++ b/mullvad-cli/src/location.rs @@ -1,4 +1,4 @@ -use crate::proto::RelayLocation; +use mullvad_management_interface::types::RelayLocation; pub fn get_subcommand() -> clap::App<'static, 'static> { clap::SubCommand::with_name("location") diff --git a/mullvad-cli/src/main.rs b/mullvad-cli/src/main.rs index 11309ff019..356a50ce69 100644 --- a/mullvad-cli/src/main.rs +++ b/mullvad-cli/src/main.rs @@ -1,10 +1,12 @@ #![deny(rust_2018_idioms)] -use async_trait::async_trait; use clap::{crate_authors, crate_description}; +use mullvad_management_interface::async_trait; use std::{collections::HashMap, io}; use talpid_types::ErrorExt; +pub use mullvad_management_interface::{self, new_rpc_client}; + mod cmds; mod format; mod location; @@ -14,47 +16,22 @@ pub const PRODUCT_VERSION: &str = include_str!(concat!(env!("OUT_DIR"), "/produc pub type Result<T> = std::result::Result<T, Error>; -mod proto { - tonic::include_proto!("mullvad_daemon.management_interface"); -} -use proto::management_service_client::ManagementServiceClient; - -use parity_tokio_ipc::Endpoint as IpcEndpoint; -use tonic::{ - self, - transport::{Endpoint, Uri}, -}; -use tower::service_fn; - #[derive(err_derive::Error, Debug)] pub enum Error { #[error(display = "Failed to connect to daemon")] DaemonNotRunning(#[error(source)] io::Error), - #[error(display = "Failed to connect to mullvad-daemon over RPC")] - GrpcTransportError(#[error(source)] tonic::transport::Error), + #[error(display = "Management interface error")] + ManagementInterfaceError(#[error(source)] mullvad_management_interface::Error), #[error(display = "Failed to communicate with mullvad-daemon over RPC")] - GrpcClientError(#[error(source)] tonic::Status), + GrpcClientError(#[error(source)] mullvad_management_interface::Status), /// The given command is not correct in some way #[error(display = "Invalid command: {}", _0)] InvalidCommand(&'static str), } -pub async fn new_grpc_client() -> Result<ManagementServiceClient<tonic::transport::Channel>> { - let ipc_path = mullvad_paths::get_rpc_socket_path(); - - // The URI will be ignored - let channel = Endpoint::from_static("lttp://[::]:50051") - .connect_with_connector(service_fn(move |_: Uri| { - IpcEndpoint::connect(ipc_path.clone()) - })) - .await?; - - Ok(ManagementServiceClient::new(channel)) -} - #[tokio::main] async fn main() { let exit_code = match run().await { diff --git a/mullvad-daemon/Cargo.toml b/mullvad-daemon/Cargo.toml index 19419a8a81..f752b677a3 100644 --- a/mullvad-daemon/Cargo.toml +++ b/mullvad-daemon/Cargo.toml @@ -36,18 +36,9 @@ mullvad-rpc = { path = "../mullvad-rpc" } talpid-core = { path = "../talpid-core" } talpid-types = { path = "../talpid-types" } -tonic = "0.2" -tower = "0.3" -prost = "0.6" -prost-types = "0.6" - -parity-tokio-ipc = "0.7" - +mullvad-management-interface = { path = "../mullvad-management-interface" } triggered = "0.1.1" -[build-dependencies] -tonic-build = { version = "0.2", default-features = false, features = ["transport", "prost"] } - [target.'cfg(target_os="android")'.dependencies] android_logger = "0.8" diff --git a/mullvad-daemon/build.rs b/mullvad-daemon/build.rs index e00123a81b..c2571ca799 100644 --- a/mullvad-daemon/build.rs +++ b/mullvad-daemon/build.rs @@ -1,10 +1,6 @@ use std::{env, fs, path::PathBuf, process::Command}; fn main() { - const PROTO_FILE: &str = "proto/management_interface.proto"; - tonic_build::compile_protos(PROTO_FILE).unwrap(); - println!("cargo:rerun-if-changed={}", PROTO_FILE); - let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); let product_version = env!("CARGO_PKG_VERSION").replacen(".0", "", 1); diff --git a/mullvad-daemon/src/lib.rs b/mullvad-daemon/src/lib.rs index ef0cff448e..4dc7dcfb47 100644 --- a/mullvad-daemon/src/lib.rs +++ b/mullvad-daemon/src/lib.rs @@ -17,8 +17,6 @@ pub mod rpc_uniqueness_check; mod settings; pub mod version; mod version_check; -#[cfg(target_os = "windows")] -mod windows_permissions; use futures::future::{abortable, AbortHandle}; use futures01::{ diff --git a/mullvad-daemon/src/management_interface.rs b/mullvad-daemon/src/management_interface.rs index 5619c8efd6..01dfffbcfe 100644 --- a/mullvad-daemon/src/management_interface.rs +++ b/mullvad-daemon/src/management_interface.rs @@ -3,6 +3,10 @@ use crate::{ }; use futures::compat::Future01CompatExt; use futures01::{future, sync, Future}; +use mullvad_management_interface::{ + types::{self, daemon_event, management_service_server::ManagementService}, + Code, Request, Response, Status, +}; use mullvad_paths; use mullvad_rpc::{rest::Error as RestError, StatusCode}; use mullvad_types::{ @@ -20,7 +24,7 @@ use mullvad_types::{ }; use parking_lot::RwLock; use std::{ - cmp, io, + cmp, sync::{mpsc, Arc}, }; use talpid_types::{ @@ -28,32 +32,12 @@ use talpid_types::{ ErrorExt, }; - -mod proto { - tonic::include_proto!("mullvad_daemon.management_interface"); -} - -use proto::{ - daemon_event::Event as DaemonEventType, - management_service_server::{ManagementService, ManagementServiceServer}, -}; - -use tonic::{ - self, - transport::{server::Connected, Server}, - Request, Response, -}; - #[derive(err_derive::Error, Debug)] #[error(no_from)] pub enum Error { // Unable to start the management interface server #[error(display = "Unable to start management interface server")] - SetupError(tonic::transport::Error), - - // Unable to set the permissions on the named pipe - #[error(display = "Unable to set permissions for IPC endpoint")] - PermissionsError(#[error(source)] io::Error), + SetupError(#[error(source)] mullvad_management_interface::Error), // Unable to start the tokio runtime #[error(display = "Failed to create the tokio runtime")] @@ -65,18 +49,22 @@ struct ManagementServiceImpl { subscriptions: Arc<RwLock<Vec<EventsListenerSender>>>, } -pub type ServiceResult<T> = std::result::Result<Response<T>, tonic::Status>; +pub type ServiceResult<T> = std::result::Result<Response<T>, Status>; type EventsListenerReceiver = - tokio02::sync::mpsc::UnboundedReceiver<Result<proto::DaemonEvent, tonic::Status>>; + tokio02::sync::mpsc::UnboundedReceiver<Result<types::DaemonEvent, Status>>; type EventsListenerSender = - tokio02::sync::mpsc::UnboundedSender<Result<proto::DaemonEvent, tonic::Status>>; + tokio02::sync::mpsc::UnboundedSender<Result<types::DaemonEvent, Status>>; -#[tonic::async_trait] +const INVALID_ACCOUNT_TOKEN_MESSAGE: &str = "No valid account token configured"; +const INVALID_VOUCHER_MESSAGE: &str = "This voucher code is invalid"; +const USED_VOUCHER_MESSAGE: &str = "This voucher code has already been used"; + +#[mullvad_management_interface::async_trait] impl ManagementService for ManagementServiceImpl { type GetRelayLocationsStream = - tokio02::sync::mpsc::Receiver<Result<proto::RelayListCountry, tonic::Status>>; + tokio02::sync::mpsc::Receiver<Result<types::RelayListCountry, Status>>; type GetSplitTunnelProcessesStream = - tokio02::sync::mpsc::UnboundedReceiver<Result<i32, tonic::Status>>; + tokio02::sync::mpsc::UnboundedReceiver<Result<i32, Status>>; type EventsListenStream = EventsListenerReceiver; // Control and get the tunnel state @@ -87,12 +75,12 @@ impl ManagementService for ManagementServiceImpl { let (tx, rx) = sync::oneshot::channel(); self.send_command_to_daemon(DaemonCommand::SetTargetState(tx, TargetState::Secured)) - .and_then(|_| rx.map_err(|_| tonic::Status::internal("internal error"))) + .and_then(|_| rx.map_err(|_| Status::internal("internal error"))) .and_then(|result| match result { Ok(()) => Ok(Response::new(())), - Err(()) => Err(tonic::Status::new( - tonic::Code::from(-900), - "No account token configured", + Err(()) => Err(Status::new( + Code::Unauthenticated, + INVALID_ACCOUNT_TOKEN_MESSAGE, )), }) .compat() @@ -117,11 +105,11 @@ impl ManagementService for ManagementServiceImpl { .await } - async fn get_tunnel_state(&self, _: Request<()>) -> ServiceResult<proto::TunnelState> { + async fn get_tunnel_state(&self, _: Request<()>) -> ServiceResult<types::TunnelState> { log::debug!("get_tunnel_state"); let (tx, rx) = sync::oneshot::channel(); self.send_command_to_daemon(DaemonCommand::GetState(tx)) - .and_then(|_| rx.map_err(|_| tonic::Status::internal("internal error"))) + .and_then(|_| rx.map_err(|_| Status::internal("internal error"))) .and_then(|state| Ok(Response::new(convert_state(state)))) .compat() .await @@ -161,7 +149,7 @@ impl ManagementService for ManagementServiceImpl { log::debug!("factory_reset"); let (tx, rx) = sync::oneshot::channel(); self.send_command_to_daemon(DaemonCommand::FactoryReset(tx)) - .and_then(|_| rx.map_err(|_| tonic::Status::internal("internal error"))) + .and_then(|_| rx.map_err(|_| Status::internal("internal error"))) .map(Response::new) .compat() .await @@ -176,19 +164,19 @@ impl ManagementService for ManagementServiceImpl { log::debug!("get_current_version"); let (tx, rx) = sync::oneshot::channel(); self.send_command_to_daemon(DaemonCommand::GetCurrentVersion(tx)) - .and_then(|_| rx.map_err(|_| tonic::Status::internal("internal error"))) + .and_then(|_| rx.map_err(|_| Status::internal("internal error"))) .map(Response::new) .compat() .await } - async fn get_version_info(&self, _: Request<()>) -> ServiceResult<proto::AppVersionInfo> { + async fn get_version_info(&self, _: Request<()>) -> ServiceResult<types::AppVersionInfo> { log::debug!("get_version_info"); let (tx, rx) = sync::oneshot::channel(); let app_version_info = self .send_command_to_daemon(DaemonCommand::GetVersionInfo(tx)) - .and_then(|_| rx.map_err(|_| tonic::Status::internal("internal error"))) + .and_then(|_| rx.map_err(|_| Status::internal("internal error"))) .compat() .await?; @@ -208,7 +196,7 @@ impl ManagementService for ManagementServiceImpl { async fn update_relay_settings( &self, - request: Request<proto::RelaySettingsUpdate>, + request: Request<types::RelaySettingsUpdate>, ) -> ServiceResult<()> { log::debug!("update_relay_settings"); let (tx, rx) = sync::oneshot::channel(); @@ -216,7 +204,7 @@ impl ManagementService for ManagementServiceImpl { let message = DaemonCommand::UpdateRelaySettings(tx, constraints_update); self.send_command_to_daemon(message) - .and_then(|_| rx.map_err(|_| tonic::Status::internal("internal error"))) + .and_then(|_| rx.map_err(|_| Status::internal("internal error"))) .map(Response::new) .compat() .await @@ -231,7 +219,7 @@ impl ManagementService for ManagementServiceImpl { let (tx, rx) = sync::oneshot::channel(); let locations = self .send_command_to_daemon(DaemonCommand::GetRelayLocations(tx)) - .and_then(|_| rx.map_err(|_| tonic::Status::internal("internal error"))) + .and_then(|_| rx.map_err(|_| Status::internal("internal error"))) .compat() .await?; @@ -255,16 +243,16 @@ impl ManagementService for ManagementServiceImpl { Ok(Response::new(stream_rx)) } - async fn get_current_location(&self, _: Request<()>) -> ServiceResult<proto::GeoIpLocation> { + async fn get_current_location(&self, _: Request<()>) -> ServiceResult<types::GeoIpLocation> { log::debug!("get_current_location"); let (tx, rx) = sync::oneshot::channel(); self.send_command_to_daemon(DaemonCommand::GetCurrentLocation(tx)) - .and_then(|_| rx.map_err(|_| tonic::Status::internal("internal error"))) + .and_then(|_| rx.map_err(|_| Status::internal("internal error"))) .and_then(|geoip| { if let Some(geoip) = geoip { Ok(Response::new(convert_geoip_location(geoip))) } else { - Err(tonic::Status::not_found("no location was found")) + Err(Status::not_found("no location was found")) } }) .compat() @@ -273,98 +261,100 @@ impl ManagementService for ManagementServiceImpl { async fn set_bridge_settings( &self, - request: Request<proto::BridgeSettings>, + request: Request<types::BridgeSettings>, ) -> ServiceResult<()> { - use proto::bridge_settings::Type as BridgeSettingType; use talpid_types::net; + use types::bridge_settings::Type as BridgeSettingType; let settings = request .into_inner() .r#type - .ok_or(tonic::Status::invalid_argument("no settings provided"))?; + .ok_or(Status::invalid_argument("no settings provided"))?; - let settings = - match settings { - BridgeSettingType::Normal(constraints) => { - let constraint = match constraints.location { - None => Constraint::Any, - Some(location) => convert_proto_location(location), - }; + let settings = match settings { + BridgeSettingType::Normal(constraints) => { + let constraint = match constraints.location { + None => Constraint::Any, + Some(location) => convert_proto_location(location), + }; - BridgeSettings::Normal(BridgeConstraints { - location: constraint, - }) - } - BridgeSettingType::Local(proxy_settings) => { - let peer = proxy_settings.peer.parse().map_err(|_| { - tonic::Status::invalid_argument("failed to parse peer address") - })?; - let proxy_settings = - net::openvpn::ProxySettings::Local(net::openvpn::LocalProxySettings { - port: proxy_settings.port as u16, - peer, - }); - BridgeSettings::Custom(proxy_settings) - } - BridgeSettingType::Remote(proxy_settings) => { - let address = proxy_settings.address.parse().map_err(|_| { - tonic::Status::invalid_argument("failed to parse IP address") - })?; - let auth = proxy_settings.auth.map(|auth| net::openvpn::ProxyAuth { - username: auth.username, - password: auth.password, + BridgeSettings::Normal(BridgeConstraints { + location: constraint, + }) + } + BridgeSettingType::Local(proxy_settings) => { + let peer = proxy_settings + .peer + .parse() + .map_err(|_| Status::invalid_argument("failed to parse peer address"))?; + let proxy_settings = + net::openvpn::ProxySettings::Local(net::openvpn::LocalProxySettings { + port: proxy_settings.port as u16, + peer, }); - let proxy_settings = - net::openvpn::ProxySettings::Remote(net::openvpn::RemoteProxySettings { - address, - auth, - }); - BridgeSettings::Custom(proxy_settings) - } - BridgeSettingType::Shadowsocks(proxy_settings) => { - let peer = proxy_settings.peer.parse().map_err(|_| { - tonic::Status::invalid_argument("failed to parse peer address") - })?; - let proxy_settings = net::openvpn::ProxySettings::Shadowsocks( - net::openvpn::ShadowsocksProxySettings { - peer, - password: proxy_settings.password, - cipher: proxy_settings.cipher, - }, - ); - BridgeSettings::Custom(proxy_settings) - } - }; + BridgeSettings::Custom(proxy_settings) + } + BridgeSettingType::Remote(proxy_settings) => { + let address = proxy_settings + .address + .parse() + .map_err(|_| Status::invalid_argument("failed to parse IP address"))?; + let auth = proxy_settings.auth.map(|auth| net::openvpn::ProxyAuth { + username: auth.username, + password: auth.password, + }); + let proxy_settings = + net::openvpn::ProxySettings::Remote(net::openvpn::RemoteProxySettings { + address, + auth, + }); + BridgeSettings::Custom(proxy_settings) + } + BridgeSettingType::Shadowsocks(proxy_settings) => { + let peer = proxy_settings + .peer + .parse() + .map_err(|_| Status::invalid_argument("failed to parse peer address"))?; + let proxy_settings = net::openvpn::ProxySettings::Shadowsocks( + net::openvpn::ShadowsocksProxySettings { + peer, + password: proxy_settings.password, + cipher: proxy_settings.cipher, + }, + ); + BridgeSettings::Custom(proxy_settings) + } + }; log::debug!("set_bridge_settings({:?})", settings); let (tx, rx) = sync::oneshot::channel(); self.send_command_to_daemon(DaemonCommand::SetBridgeSettings(tx, settings)) - .and_then(|_| rx.map_err(|_| tonic::Status::internal("internal error"))) + .and_then(|_| rx.map_err(|_| Status::internal("internal error"))) .and_then(|settings_result| { - settings_result.map_err(|_| tonic::Status::internal("internal error")) + settings_result.map_err(|_| Status::internal("internal error")) }) .map(Response::new) .compat() .await } - async fn set_bridge_state(&self, request: Request<proto::BridgeState>) -> ServiceResult<()> { - use proto::bridge_state::State; + async fn set_bridge_state(&self, request: Request<types::BridgeState>) -> ServiceResult<()> { + use types::bridge_state::State; let bridge_state = match State::from_i32(request.into_inner().state) { Some(State::Auto) => BridgeState::Auto, Some(State::On) => BridgeState::On, Some(State::Off) => BridgeState::Off, - None => return Err(tonic::Status::invalid_argument("unknown bridge state")), + None => return Err(Status::invalid_argument("unknown bridge state")), }; log::debug!("set_bridge_state({:?})", bridge_state); let (tx, rx) = sync::oneshot::channel(); self.send_command_to_daemon(DaemonCommand::SetBridgeState(tx, bridge_state)) - .and_then(|_| rx.map_err(|_| tonic::Status::internal("internal error"))) + .and_then(|_| rx.map_err(|_| Status::internal("internal error"))) .and_then(|settings_result| { - settings_result.map_err(|_| tonic::Status::internal("internal error")) + settings_result.map_err(|_| Status::internal("internal error")) }) .map(Response::new) .compat() @@ -374,11 +364,11 @@ impl ManagementService for ManagementServiceImpl { // Settings // - async fn get_settings(&self, _: Request<()>) -> ServiceResult<proto::Settings> { + async fn get_settings(&self, _: Request<()>) -> ServiceResult<types::Settings> { log::debug!("get_settings"); let (tx, rx) = sync::oneshot::channel(); self.send_command_to_daemon(DaemonCommand::GetSettings(tx)) - .and_then(|_| rx.map_err(|_| tonic::Status::internal("internal error"))) + .and_then(|_| rx.map_err(|_| Status::internal("internal error"))) .map(|settings| Response::new(convert_settings(&settings))) .compat() .await @@ -389,7 +379,7 @@ impl ManagementService for ManagementServiceImpl { log::debug!("set_allow_lan({})", allow_lan); let (tx, rx) = sync::oneshot::channel(); self.send_command_to_daemon(DaemonCommand::SetAllowLan(tx, allow_lan)) - .and_then(|_| rx.map_err(|_| tonic::Status::internal("internal error"))) + .and_then(|_| rx.map_err(|_| Status::internal("internal error"))) .map(Response::new) .compat() .await @@ -400,7 +390,7 @@ impl ManagementService for ManagementServiceImpl { log::debug!("set_show_beta_releases({})", enabled); let (tx, rx) = sync::oneshot::channel(); self.send_command_to_daemon(DaemonCommand::SetShowBetaReleases(tx, enabled)) - .and_then(|_| rx.map_err(|_| tonic::Status::internal("internal error"))) + .and_then(|_| rx.map_err(|_| Status::internal("internal error"))) .map(Response::new) .compat() .await @@ -414,7 +404,7 @@ impl ManagementService for ManagementServiceImpl { tx, block_when_disconnected, )) - .and_then(|_| rx.map_err(|_| tonic::Status::internal("internal error"))) + .and_then(|_| rx.map_err(|_| Status::internal("internal error"))) .map(Response::new) .compat() .await @@ -425,7 +415,7 @@ impl ManagementService for ManagementServiceImpl { log::debug!("set_auto_connect({})", auto_connect); let (tx, rx) = sync::oneshot::channel(); self.send_command_to_daemon(DaemonCommand::SetAutoConnect(tx, auto_connect)) - .and_then(|_| rx.map_err(|_| tonic::Status::internal("internal error"))) + .and_then(|_| rx.map_err(|_| Status::internal("internal error"))) .map(Response::new) .compat() .await @@ -441,7 +431,7 @@ impl ManagementService for ManagementServiceImpl { log::debug!("set_openvpn_mssfix({:?})", mssfix); let (tx, rx) = sync::oneshot::channel(); self.send_command_to_daemon(DaemonCommand::SetOpenVpnMssfix(tx, mssfix)) - .and_then(|_| rx.map_err(|_| tonic::Status::internal("internal error"))) + .and_then(|_| rx.map_err(|_| Status::internal("internal error"))) .map(Response::new) .compat() .await @@ -453,7 +443,7 @@ impl ManagementService for ManagementServiceImpl { log::debug!("set_wireguard_mtu({:?})", mtu); let (tx, rx) = sync::oneshot::channel(); self.send_command_to_daemon(DaemonCommand::SetWireguardMtu(tx, mtu)) - .and_then(|_| rx.map_err(|_| tonic::Status::internal("internal error"))) + .and_then(|_| rx.map_err(|_| Status::internal("internal error"))) .map(Response::new) .compat() .await @@ -464,7 +454,7 @@ impl ManagementService for ManagementServiceImpl { log::debug!("set_enable_ipv6({})", enable_ipv6); let (tx, rx) = sync::oneshot::channel(); self.send_command_to_daemon(DaemonCommand::SetEnableIpv6(tx, enable_ipv6)) - .and_then(|_| rx.map_err(|_| tonic::Status::internal("internal error"))) + .and_then(|_| rx.map_err(|_| Status::internal("internal error"))) .map(Response::new) .compat() .await @@ -476,10 +466,10 @@ impl ManagementService for ManagementServiceImpl { async fn create_new_account(&self, _: Request<()>) -> ServiceResult<String> { let (tx, rx) = sync::oneshot::channel(); self.send_command_to_daemon(DaemonCommand::CreateNewAccount(tx)) - .and_then(|_| rx.map_err(|_| tonic::Status::internal("internal error"))) + .and_then(|_| rx.map_err(|_| Status::internal("internal error"))) .and_then(|result| match result { Ok(account_token) => Ok(Response::new(account_token)), - Err(_) => Err(tonic::Status::internal("internal error")), + Err(_) => Err(Status::internal("internal error")), }) .compat() .await @@ -497,7 +487,7 @@ impl ManagementService for ManagementServiceImpl { self.send_command_to_daemon(DaemonCommand::SetAccount(tx, account_token)) .and_then(|_| { rx.map(Response::new) - .map_err(|_| tonic::Status::internal("internal error")) + .map_err(|_| Status::internal("internal error")) }) .compat() .await @@ -506,17 +496,17 @@ impl ManagementService for ManagementServiceImpl { async fn get_account_data( &self, request: Request<AccountToken>, - ) -> ServiceResult<proto::AccountData> { + ) -> ServiceResult<types::AccountData> { log::debug!("get_account_data"); let account_token = request.into_inner(); let (tx, rx) = sync::oneshot::channel(); self.send_command_to_daemon(DaemonCommand::GetAccountData(tx, account_token)) - .and_then(|_| rx.map_err(|_| tonic::Status::internal("internal error"))) + .and_then(|_| rx.map_err(|_| Status::internal("internal error"))) .and_then(|rpc_future| { rpc_future .map(|account_data| { - Response::new(proto::AccountData { - expiry: Some(prost_types::Timestamp { + Response::new(types::AccountData { + expiry: Some(types::Timestamp { seconds: account_data.expiry.timestamp(), nanos: 0, }), @@ -534,13 +524,13 @@ impl ManagementService for ManagementServiceImpl { .await } - async fn get_account_history(&self, _: Request<()>) -> ServiceResult<proto::AccountHistory> { + async fn get_account_history(&self, _: Request<()>) -> ServiceResult<types::AccountHistory> { // TODO: this might be a stream log::debug!("get_account_history"); let (tx, rx) = sync::oneshot::channel(); self.send_command_to_daemon(DaemonCommand::GetAccountHistory(tx)) - .and_then(|_| rx.map_err(|_| tonic::Status::internal("internal error"))) - .map(|history| Response::new(proto::AccountHistory { token: history })) + .and_then(|_| rx.map_err(|_| Status::internal("internal error"))) + .map(|history| Response::new(types::AccountHistory { token: history })) .compat() .await } @@ -553,7 +543,7 @@ impl ManagementService for ManagementServiceImpl { let account_token = request.into_inner(); let (tx, rx) = sync::oneshot::channel(); self.send_command_to_daemon(DaemonCommand::RemoveAccountFromHistory(tx, account_token)) - .and_then(|_| rx.map_err(|_| tonic::Status::internal("internal error"))) + .and_then(|_| rx.map_err(|_| Status::internal("internal error"))) .map(Response::new) .compat() .await @@ -563,7 +553,7 @@ impl ManagementService for ManagementServiceImpl { log::debug!("clear_account_history"); let (tx, rx) = sync::oneshot::channel(); self.send_command_to_daemon(DaemonCommand::ClearAccountHistory(tx)) - .and_then(|_| rx.map_err(|_| tonic::Status::internal("internal error"))) + .and_then(|_| rx.map_err(|_| Status::internal("internal error"))) .map(Response::new) .compat() .await @@ -573,7 +563,7 @@ impl ManagementService for ManagementServiceImpl { log::debug!("get_www_auth_token"); let (tx, rx) = sync::oneshot::channel(); self.send_command_to_daemon(DaemonCommand::GetWwwAuthToken(tx)) - .and_then(|_| rx.map_err(|_| tonic::Status::internal("internal error"))) + .and_then(|_| rx.map_err(|_| Status::internal("internal error"))) .and_then(|rpc_future| { rpc_future .map(Response::new) @@ -592,17 +582,17 @@ impl ManagementService for ManagementServiceImpl { async fn submit_voucher( &self, request: Request<String>, - ) -> ServiceResult<proto::VoucherSubmission> { + ) -> ServiceResult<types::VoucherSubmission> { log::debug!("submit_voucher"); let voucher = request.into_inner(); let (tx, rx) = sync::oneshot::channel(); self.send_command_to_daemon(DaemonCommand::SubmitVoucher(tx, voucher)) - .and_then(|_| rx.map_err(|_| tonic::Status::internal("internal error"))) + .and_then(|_| rx.map_err(|_| Status::internal("internal error"))) .and_then(|f| { f.map(|submission| { - Response::new(proto::VoucherSubmission { + Response::new(types::VoucherSubmission { seconds_added: submission.time_added, - new_expiry: Some(prost_types::Timestamp { + new_expiry: Some(types::Timestamp { seconds: submission.new_expiry.timestamp(), nanos: 0, }), @@ -612,17 +602,17 @@ impl ManagementService for ManagementServiceImpl { RestError::ApiError(StatusCode::BAD_REQUEST, message) => { match &message.as_str() { &mullvad_rpc::INVALID_VOUCHER => { - tonic::Status::new(tonic::Code::NotFound, message) + Status::new(Code::NotFound, INVALID_VOUCHER_MESSAGE) } &mullvad_rpc::VOUCHER_USED => { - tonic::Status::new(tonic::Code::ResourceExhausted, message) + Status::new(Code::ResourceExhausted, USED_VOUCHER_MESSAGE) } - _ => tonic::Status::internal("internal error"), + _ => Status::internal("internal error"), } } - _ => tonic::Status::internal("internal error"), + _ => Status::internal("internal error"), }) }) .compat() @@ -641,7 +631,7 @@ impl ManagementService for ManagementServiceImpl { tx, Some(interval), )) - .and_then(|_| rx.map_err(|_| tonic::Status::internal("internal error"))) + .and_then(|_| rx.map_err(|_| Status::internal("internal error"))) .map(Response::new) .compat() .await @@ -651,32 +641,32 @@ impl ManagementService for ManagementServiceImpl { log::debug!("reset_wireguard_rotation_interval"); let (tx, rx) = sync::oneshot::channel(); self.send_command_to_daemon(DaemonCommand::SetWireguardRotationInterval(tx, None)) - .and_then(|_| rx.map_err(|_| tonic::Status::internal("internal error"))) + .and_then(|_| rx.map_err(|_| Status::internal("internal error"))) .map(Response::new) .compat() .await } - async fn generate_wireguard_key(&self, _: Request<()>) -> ServiceResult<proto::KeygenEvent> { + async fn generate_wireguard_key(&self, _: Request<()>) -> ServiceResult<types::KeygenEvent> { // TODO: return error for TooManyKeys, GenerationFailure // on success, simply return the new key or nil log::debug!("generate_wireguard_key"); let (tx, rx) = sync::oneshot::channel(); self.send_command_to_daemon(DaemonCommand::GenerateWireguardKey(tx)) - .and_then(|_| rx.map_err(|_| tonic::Status::internal("internal error"))) + .and_then(|_| rx.map_err(|_| Status::internal("internal error"))) .map(|event| Response::new(convert_wireguard_key_event(&event))) .compat() .await } - async fn get_wireguard_key(&self, _: Request<()>) -> ServiceResult<proto::PublicKey> { + async fn get_wireguard_key(&self, _: Request<()>) -> ServiceResult<types::PublicKey> { log::debug!("get_wireguard_key"); let (tx, rx) = sync::oneshot::channel(); self.send_command_to_daemon(DaemonCommand::GetWireguardKey(tx)) - .and_then(|_| rx.map_err(|_| tonic::Status::internal("internal error"))) + .and_then(|_| rx.map_err(|_| Status::internal("internal error"))) .then(|response| match response { Ok(Some(key)) => Ok(Response::new(convert_public_key(&key))), - Ok(None) => Err(tonic::Status::not_found("no WireGuard key was found")), + Ok(None) => Err(Status::not_found("no WireGuard key was found")), Err(e) => Err(e), }) .compat() @@ -687,7 +677,7 @@ impl ManagementService for ManagementServiceImpl { log::debug!("verify_wireguard_key"); let (tx, rx) = sync::oneshot::channel(); self.send_command_to_daemon(DaemonCommand::VerifyWireguardKey(tx)) - .and_then(|_| rx.map_err(|_| tonic::Status::internal("internal error"))) + .and_then(|_| rx.map_err(|_| Status::internal("internal error"))) .map(Response::new) .compat() .await @@ -706,7 +696,7 @@ impl ManagementService for ManagementServiceImpl { let (tx, rx) = sync::oneshot::channel(); let pids = self .send_command_to_daemon(DaemonCommand::GetSplitTunnelProcesses(tx)) - .and_then(|_| rx.map_err(|_| tonic::Status::internal("internal error"))) + .and_then(|_| rx.map_err(|_| Status::internal("internal error"))) .compat() .await?; @@ -732,7 +722,7 @@ impl ManagementService for ManagementServiceImpl { log::debug!("add_split_tunnel_process"); let (tx, rx) = sync::oneshot::channel(); self.send_command_to_daemon(DaemonCommand::AddSplitTunnelProcess(tx, pid)) - .and_then(|_| rx.map_err(|_| tonic::Status::internal("internal error"))) + .and_then(|_| rx.map_err(|_| Status::internal("internal error"))) .map(Response::new) .compat() .await @@ -748,7 +738,7 @@ impl ManagementService for ManagementServiceImpl { log::debug!("remove_split_tunnel_process"); let (tx, rx) = sync::oneshot::channel(); self.send_command_to_daemon(DaemonCommand::RemoveSplitTunnelProcess(tx, pid)) - .and_then(|_| rx.map_err(|_| tonic::Status::internal("internal error"))) + .and_then(|_| rx.map_err(|_| Status::internal("internal error"))) .map(Response::new) .compat() .await @@ -764,7 +754,7 @@ impl ManagementService for ManagementServiceImpl { log::debug!("clear_split_tunnel_processes"); let (tx, rx) = sync::oneshot::channel(); self.send_command_to_daemon(DaemonCommand::ClearSplitTunnelProcesses(tx)) - .and_then(|_| rx.map_err(|_| tonic::Status::internal("internal error"))) + .and_then(|_| rx.map_err(|_| Status::internal("internal error"))) .map(Response::new) .compat() .await @@ -781,17 +771,17 @@ impl ManagementServiceImpl { fn send_command_to_daemon( &self, command: DaemonCommand, - ) -> impl Future<Item = (), Error = tonic::Status> { + ) -> impl Future<Item = (), Error = Status> { future::result( self.daemon_tx .send(command) - .map_err(|_| tonic::Status::internal("internal error")), + .map_err(|_| Status::internal("internal error")), ) } } -fn convert_settings(settings: &Settings) -> proto::Settings { - proto::Settings { +fn convert_settings(settings: &Settings) -> types::Settings { + types::Settings { account_token: settings.get_account_token().unwrap_or_default(), relay_settings: Some(convert_relay_settings(&settings.get_relay_settings())), bridge_settings: Some(convert_bridge_settings(&settings.bridge_settings)), @@ -805,43 +795,43 @@ fn convert_settings(settings: &Settings) -> proto::Settings { } fn convert_relay_settings_update( - settings: &proto::RelaySettingsUpdate, -) -> Result<RelaySettingsUpdate, tonic::Status> { + settings: &types::RelaySettingsUpdate, +) -> Result<RelaySettingsUpdate, Status> { use mullvad_types::CustomTunnelEndpoint; - use proto::{ + use talpid_types::net::{self, openvpn, wireguard}; + use types::{ connection_config::Config as ProtoConnectionConfig, relay_settings_update::Type as ProtoUpdateType, }; - use talpid_types::net::{self, openvpn, wireguard}; let update_value = settings .r#type .clone() - .ok_or(tonic::Status::invalid_argument("missing relay settings"))?; + .ok_or(Status::invalid_argument("missing relay settings"))?; match update_value { ProtoUpdateType::Custom(settings) => { let config = settings .config - .ok_or(tonic::Status::invalid_argument("missing relay settings"))?; + .ok_or(Status::invalid_argument("missing relay settings"))?; let config = config .config - .ok_or(tonic::Status::invalid_argument("missing relay settings"))?; + .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(tonic::Status::invalid_argument("invalid address")), + Err(_) => return Err(Status::invalid_argument("invalid address")), }; ConnectionConfig::OpenVpn(openvpn::ConnectionConfig { endpoint: net::Endpoint { address, - protocol: match proto::TransportProtocol::from_i32(config.protocol) { - Some(proto::TransportProtocol::Udp) => TransportProtocol::Udp, - Some(proto::TransportProtocol::Tcp) => TransportProtocol::Tcp, - None | Some(proto::TransportProtocol::AnyProtocol) => { - return Err(tonic::Status::invalid_argument( + protocol: match types::TransportProtocol::from_i32(config.protocol) { + Some(types::TransportProtocol::Udp) => TransportProtocol::Udp, + Some(types::TransportProtocol::Tcp) => TransportProtocol::Tcp, + None | Some(types::TransportProtocol::AnyProtocol) => { + return Err(Status::invalid_argument( "unknown transport protocol", )) } @@ -854,11 +844,11 @@ fn convert_relay_settings_update( ProtoConnectionConfig::Wireguard(config) => { let tunnel = config .tunnel - .ok_or(tonic::Status::invalid_argument("missing tunnel config"))?; + .ok_or(Status::invalid_argument("missing tunnel config"))?; // Copy the private key to an array if tunnel.private_key.len() != 32 { - return Err(tonic::Status::invalid_argument("invalid private key")); + return Err(Status::invalid_argument("invalid private key")); } let mut private_key = [0; 32]; @@ -867,11 +857,11 @@ fn convert_relay_settings_update( let peer = config .peer - .ok_or(tonic::Status::invalid_argument("missing peer config"))?; + .ok_or(Status::invalid_argument("missing peer config"))?; // Copy the public key to an array if peer.public_key.len() != 32 { - return Err(tonic::Status::invalid_argument("invalid public key")); + return Err(Status::invalid_argument("invalid public key")); } let mut public_key = [0; 32]; @@ -880,16 +870,12 @@ fn convert_relay_settings_update( let ipv4_gateway = match config.ipv4_gateway.parse() { Ok(address) => address, - Err(_) => { - return Err(tonic::Status::invalid_argument("invalid IPv4 gateway")) - } + 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(tonic::Status::invalid_argument("invalid IPv6 gateway")) - } + Err(_) => return Err(Status::invalid_argument("invalid IPv6 gateway")), }; Some(address) } else { @@ -898,16 +884,14 @@ fn convert_relay_settings_update( let endpoint = match peer.endpoint.parse() { Ok(address) => address, - Err(_) => { - return Err(tonic::Status::invalid_argument("invalid peer 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(|_| tonic::Status::invalid_argument("invalid address"))?; + .map_err(|_| Status::invalid_argument("invalid address"))?; tunnel_addresses.push(address); } @@ -915,7 +899,7 @@ fn convert_relay_settings_update( for address in peer.allowed_ips { let address = address .parse() - .map_err(|_| tonic::Status::invalid_argument("invalid address"))?; + .map_err(|_| Status::invalid_argument("invalid address"))?; allowed_ips.push(address); } @@ -950,13 +934,13 @@ fn convert_relay_settings_update( let location = settings.location.map(convert_proto_location); let tunnel_protocol = if let Some(update) = settings.tunnel_type { - match proto::TunnelType::from_i32(update.tunnel_type) { - Some(proto::TunnelType::AnyTunnel) => Some(Constraint::Any), - Some(proto::TunnelType::Openvpn) => Some(Constraint::Only(TunnelType::OpenVpn)), - Some(proto::TunnelType::Wireguard) => { + match types::TunnelType::from_i32(update.tunnel_type) { + Some(types::TunnelType::AnyTunnel) => Some(Constraint::Any), + Some(types::TunnelType::Openvpn) => Some(Constraint::Only(TunnelType::OpenVpn)), + Some(types::TunnelType::Wireguard) => { Some(Constraint::Only(TunnelType::Wireguard)) } - None => return Err(tonic::Status::invalid_argument("unknown tunnel protocol")), + None => return Err(Status::invalid_argument("unknown tunnel protocol")), } } else { None @@ -981,11 +965,11 @@ fn convert_relay_settings_update( } else { Constraint::Any }, - protocol: match proto::TransportProtocol::from_i32(constraints.protocol) { - Some(proto::TransportProtocol::Udp) => { + protocol: match types::TransportProtocol::from_i32(constraints.protocol) { + Some(types::TransportProtocol::Udp) => { Constraint::Only(TransportProtocol::Udp) } - Some(proto::TransportProtocol::Tcp) => { + Some(types::TransportProtocol::Tcp) => { Constraint::Only(TransportProtocol::Tcp) } _ => Constraint::Any, @@ -997,64 +981,64 @@ fn convert_relay_settings_update( } } -fn convert_relay_settings(settings: &RelaySettings) -> proto::RelaySettings { - use proto::relay_settings; +fn convert_relay_settings(settings: &RelaySettings) -> types::RelaySettings { + use types::relay_settings; let endpoint = match settings { RelaySettings::CustomTunnelEndpoint(endpoint) => { - relay_settings::Endpoint::Custom(proto::CustomRelaySettings { + relay_settings::Endpoint::Custom(types::CustomRelaySettings { host: endpoint.host.clone(), config: Some(convert_connection_config(&endpoint.config)), }) } RelaySettings::Normal(constraints) => { - relay_settings::Endpoint::Normal(proto::NormalRelaySettings { + relay_settings::Endpoint::Normal(types::NormalRelaySettings { location: convert_location_constraint(&constraints.location), tunnel_type: match constraints.tunnel_protocol { - Constraint::Any => i32::from(proto::TunnelType::AnyTunnel), + Constraint::Any => i32::from(types::TunnelType::AnyTunnel), Constraint::Only(TunnelType::Wireguard) => { - i32::from(proto::TunnelType::Wireguard) + i32::from(types::TunnelType::Wireguard) } - Constraint::Only(TunnelType::OpenVpn) => i32::from(proto::TunnelType::Openvpn), + Constraint::Only(TunnelType::OpenVpn) => i32::from(types::TunnelType::Openvpn), }, - wireguard_constraints: Some(proto::WireguardConstraints { + wireguard_constraints: Some(types::WireguardConstraints { port: u32::from(constraints.wireguard_constraints.port.unwrap_or(0)), }), - openvpn_constraints: Some(proto::OpenvpnConstraints { + openvpn_constraints: Some(types::OpenvpnConstraints { port: u32::from(constraints.openvpn_constraints.port.unwrap_or(0)), protocol: i32::from( constraints .openvpn_constraints .protocol .map(|protocol| match protocol { - TransportProtocol::Tcp => proto::TransportProtocol::Tcp, - TransportProtocol::Udp => proto::TransportProtocol::Udp, + TransportProtocol::Tcp => types::TransportProtocol::Tcp, + TransportProtocol::Udp => types::TransportProtocol::Udp, }) - .unwrap_or(proto::TransportProtocol::AnyProtocol), + .unwrap_or(types::TransportProtocol::AnyProtocol), ), }), }) } }; - proto::RelaySettings { + types::RelaySettings { endpoint: Some(endpoint), } } -fn convert_connection_config(config: &ConnectionConfig) -> proto::ConnectionConfig { - use proto::connection_config; +fn convert_connection_config(config: &ConnectionConfig) -> types::ConnectionConfig { + use types::connection_config; - proto::ConnectionConfig { + types::ConnectionConfig { config: Some(match config { ConnectionConfig::OpenVpn(config) => { connection_config::Config::Openvpn(connection_config::OpenvpnConfig { address: config.endpoint.address.to_string(), protocol: match config.endpoint.protocol { - TransportProtocol::Tcp => i32::from(proto::TransportProtocol::Tcp), - TransportProtocol::Udp => i32::from(proto::TransportProtocol::Udp), + TransportProtocol::Tcp => i32::from(types::TransportProtocol::Tcp), + TransportProtocol::Udp => i32::from(types::TransportProtocol::Udp), }, username: config.username.clone(), password: config.password.clone(), @@ -1093,13 +1077,13 @@ fn convert_connection_config(config: &ConnectionConfig) -> proto::ConnectionConf } } -fn convert_bridge_settings(settings: &BridgeSettings) -> proto::BridgeSettings { - use proto::bridge_settings::{self, Type as BridgeSettingType}; +fn convert_bridge_settings(settings: &BridgeSettings) -> types::BridgeSettings { use talpid_types::net; + use types::bridge_settings::{self, Type as BridgeSettingType}; let settings = match settings { BridgeSettings::Normal(constraints) => { - BridgeSettingType::Normal(proto::bridge_settings::BridgeConstraints { + BridgeSettingType::Normal(types::bridge_settings::BridgeConstraints { location: convert_location_constraint(&constraints.location), }) } @@ -1131,18 +1115,18 @@ fn convert_bridge_settings(settings: &BridgeSettings) -> proto::BridgeSettings { }, }; - proto::BridgeSettings { + types::BridgeSettings { r#type: Some(settings), } } fn convert_wireguard_key_event( event: &mullvad_types::wireguard::KeygenEvent, -) -> proto::KeygenEvent { +) -> types::KeygenEvent { use mullvad_types::wireguard::KeygenEvent::*; - use proto::keygen_event::KeygenEvent as ProtoEvent; + use types::keygen_event::KeygenEvent as ProtoEvent; - proto::KeygenEvent { + types::KeygenEvent { event: match event { NewKey(_) => i32::from(ProtoEvent::NewKey), TooManyKeys => i32::from(ProtoEvent::TooManyKeys), @@ -1156,10 +1140,10 @@ fn convert_wireguard_key_event( } } -fn convert_public_key(public_key: &wireguard::PublicKey) -> proto::PublicKey { - proto::PublicKey { +fn convert_public_key(public_key: &wireguard::PublicKey) -> types::PublicKey { + types::PublicKey { key: public_key.key.as_bytes().to_vec(), - created: Some(prost_types::Timestamp { + created: Some(types::Timestamp { seconds: public_key.created.timestamp(), nanos: 0, }), @@ -1168,22 +1152,22 @@ fn convert_public_key(public_key: &wireguard::PublicKey) -> proto::PublicKey { fn convert_location_constraint( location: &Constraint<LocationConstraint>, -) -> Option<proto::RelayLocation> { +) -> Option<types::RelayLocation> { if location.is_any() { return None; } Some(match location.as_ref().unwrap() { - LocationConstraint::Country(country) => proto::RelayLocation { + LocationConstraint::Country(country) => types::RelayLocation { country: country.to_string(), ..Default::default() }, - LocationConstraint::City(country, city) => proto::RelayLocation { + LocationConstraint::City(country, city) => types::RelayLocation { country: country.to_string(), city: city.to_string(), ..Default::default() }, - LocationConstraint::Hostname(country, city, hostname) => proto::RelayLocation { + LocationConstraint::Hostname(country, city, hostname) => types::RelayLocation { country: country.to_string(), city: city.to_string(), hostname: hostname.to_string(), @@ -1191,44 +1175,44 @@ fn convert_location_constraint( }) } -fn convert_bridge_state(state: &BridgeState) -> proto::BridgeState { +fn convert_bridge_state(state: &BridgeState) -> types::BridgeState { let state = match state { - BridgeState::Auto => proto::bridge_state::State::Auto, - BridgeState::On => proto::bridge_state::State::On, - BridgeState::Off => proto::bridge_state::State::Off, + BridgeState::Auto => types::bridge_state::State::Auto, + BridgeState::On => types::bridge_state::State::On, + BridgeState::Off => types::bridge_state::State::Off, }; - proto::BridgeState { + types::BridgeState { state: i32::from(state), } } -fn convert_tunnel_options(options: &TunnelOptions) -> proto::TunnelOptions { - proto::TunnelOptions { - openvpn: Some(proto::tunnel_options::OpenvpnOptions { +fn convert_tunnel_options(options: &TunnelOptions) -> types::TunnelOptions { + types::TunnelOptions { + openvpn: Some(types::tunnel_options::OpenvpnOptions { mssfix: u32::from(options.openvpn.mssfix.unwrap_or_default()), }), - wireguard: Some(proto::tunnel_options::WireguardOptions { + wireguard: Some(types::tunnel_options::WireguardOptions { mtu: u32::from(options.wireguard.mtu.unwrap_or_default()), automatic_rotation: options .wireguard .automatic_rotation .unwrap_or((DEFAULT_AUTOMATIC_KEY_ROTATION.as_secs() / 60u64 / 60u64) as u32), }), - generic: Some(proto::tunnel_options::GenericOptions { + generic: Some(types::tunnel_options::GenericOptions { enable_ipv6: options.generic.enable_ipv6, }), } } -fn convert_relay_list_country(country: &RelayListCountry) -> proto::RelayListCountry { - let mut proto_country = proto::RelayListCountry { +fn convert_relay_list_country(country: &RelayListCountry) -> types::RelayListCountry { + let mut proto_country = types::RelayListCountry { name: country.name.clone(), code: country.code.clone(), cities: Vec::with_capacity(country.cities.len()), }; for city in &country.cities { - proto_country.cities.push(proto::RelayListCity { + proto_country.cities.push(types::RelayListCity { name: city.name.clone(), code: city.code.clone(), latitude: city.latitude, @@ -1244,8 +1228,8 @@ fn convert_relay_list_country(country: &RelayListCountry) -> proto::RelayListCou proto_country } -fn convert_relay(relay: &Relay) -> proto::Relay { - proto::Relay { +fn convert_relay(relay: &Relay) -> types::Relay { + types::Relay { hostname: relay.hostname.clone(), ipv4_addr_in: relay.ipv4_addr_in.to_string(), ipv6_addr_in: relay @@ -1257,17 +1241,17 @@ fn convert_relay(relay: &Relay) -> proto::Relay { owned: relay.owned, provider: relay.provider.clone(), weight: relay.weight, - tunnels: Some(proto::RelayTunnels { + tunnels: Some(types::RelayTunnels { openvpn: relay .tunnels .openvpn .iter() .map(|endpoint| { let protocol = match endpoint.protocol { - TransportProtocol::Udp => proto::TransportProtocol::Udp, - TransportProtocol::Tcp => proto::TransportProtocol::Tcp, + TransportProtocol::Udp => types::TransportProtocol::Udp, + TransportProtocol::Tcp => types::TransportProtocol::Tcp, }; - proto::OpenVpnEndpointData { + types::OpenVpnEndpointData { port: u32::from(endpoint.port), protocol: i32::from(protocol), } @@ -1281,12 +1265,12 @@ fn convert_relay(relay: &Relay) -> proto::Relay { let port_ranges = endpoint .port_ranges .iter() - .map(|range| proto::PortRange { + .map(|range| types::PortRange { first: u32::from(range.0), last: u32::from(range.1), }) .collect(); - proto::WireguardEndpointData { + types::WireguardEndpointData { port_ranges, ipv4_gateway: endpoint.ipv4_gateway.to_string(), ipv6_gateway: endpoint.ipv6_gateway.to_string(), @@ -1295,17 +1279,17 @@ fn convert_relay(relay: &Relay) -> proto::Relay { }) .collect(), }), - bridges: Some(proto::RelayBridges { + bridges: Some(types::RelayBridges { shadowsocks: relay .bridges .shadowsocks .iter() .map(|endpoint| { let protocol = match endpoint.protocol { - TransportProtocol::Udp => proto::TransportProtocol::Udp, - TransportProtocol::Tcp => proto::TransportProtocol::Tcp, + TransportProtocol::Udp => types::TransportProtocol::Udp, + TransportProtocol::Tcp => types::TransportProtocol::Tcp, }; - proto::ShadowsocksEndpointData { + types::ShadowsocksEndpointData { port: u32::from(endpoint.port), cipher: endpoint.cipher.clone(), password: endpoint.password.clone(), @@ -1314,7 +1298,7 @@ fn convert_relay(relay: &Relay) -> proto::Relay { }) .collect(), }), - location: relay.location.as_ref().map(|location| proto::Location { + location: relay.location.as_ref().map(|location| types::Location { country: location.country.clone(), country_code: location.country_code.clone(), city: location.city.clone(), @@ -1325,8 +1309,11 @@ fn convert_relay(relay: &Relay) -> proto::Relay { } } -fn convert_state(state: TunnelState) -> proto::TunnelState { - use proto::{ +fn convert_state(state: TunnelState) -> types::TunnelState { + use talpid_types::tunnel::{ + ActionAfterDisconnect, ErrorStateCause, FirewallPolicyError, ParameterGenerationError, + }; + use types::{ error_state::{ firewall_policy_error::ErrorType as PolicyErrorType, Cause as ProtoErrorCause, FirewallPolicyError as ProtoFirewallPolicyError, @@ -1334,34 +1321,31 @@ fn convert_state(state: TunnelState) -> proto::TunnelState { }, tunnel_state::{self, State as ProtoState}, }; - use talpid_types::tunnel::{ - ActionAfterDisconnect, ErrorStateCause, FirewallPolicyError, ParameterGenerationError, - }; use TunnelState::*; let state = match state { Disconnected => ProtoState::Disconnected(tunnel_state::Disconnected {}), Connecting { endpoint, location } => ProtoState::Connecting(tunnel_state::Connecting { - relay_info: Some(proto::TunnelStateRelayInfo { + relay_info: Some(types::TunnelStateRelayInfo { tunnel_endpoint: Some(convert_endpoint(endpoint)), location: location.map(convert_geoip_location), }), }), Connected { endpoint, location } => ProtoState::Connected(tunnel_state::Connected { - relay_info: Some(proto::TunnelStateRelayInfo { + relay_info: Some(types::TunnelStateRelayInfo { tunnel_endpoint: Some(convert_endpoint(endpoint)), location: location.map(convert_geoip_location), }), }), Disconnecting(after_disconnect) => ProtoState::Disconnecting(tunnel_state::Disconnecting { after_disconnect: match after_disconnect { - ActionAfterDisconnect::Nothing => i32::from(proto::AfterDisconnect::Nothing), - ActionAfterDisconnect::Block => i32::from(proto::AfterDisconnect::Block), - ActionAfterDisconnect::Reconnect => i32::from(proto::AfterDisconnect::Reconnect), + ActionAfterDisconnect::Nothing => i32::from(types::AfterDisconnect::Nothing), + ActionAfterDisconnect::Block => i32::from(types::AfterDisconnect::Block), + ActionAfterDisconnect::Reconnect => i32::from(types::AfterDisconnect::Reconnect), }, }), Error(error_state) => ProtoState::Error(tunnel_state::Error { - error_state: Some(proto::ErrorState { + error_state: Some(types::ErrorState { cause: match error_state.cause() { ErrorStateCause::AuthFailed(_) => i32::from(ProtoErrorCause::AuthFailed), ErrorStateCause::Ipv6Unavailable => i32::from(ProtoErrorCause::Ipv6Unavailable), @@ -1439,38 +1423,38 @@ fn convert_state(state: TunnelState) -> proto::TunnelState { }), }; - proto::TunnelState { state: Some(state) } + types::TunnelState { state: Some(state) } } -fn convert_endpoint(endpoint: talpid_types::net::TunnelEndpoint) -> proto::TunnelEndpoint { +fn convert_endpoint(endpoint: talpid_types::net::TunnelEndpoint) -> types::TunnelEndpoint { use talpid_types::net; - proto::TunnelEndpoint { + types::TunnelEndpoint { address: endpoint.endpoint.address.to_string(), protocol: match endpoint.endpoint.protocol { - TransportProtocol::Tcp => i32::from(proto::TransportProtocol::Tcp), - TransportProtocol::Udp => i32::from(proto::TransportProtocol::Udp), + TransportProtocol::Tcp => i32::from(types::TransportProtocol::Tcp), + TransportProtocol::Udp => i32::from(types::TransportProtocol::Udp), }, tunnel_type: match endpoint.tunnel_type { - net::TunnelType::Wireguard => i32::from(proto::TunnelType::Wireguard), - net::TunnelType::OpenVpn => i32::from(proto::TunnelType::Openvpn), + net::TunnelType::Wireguard => i32::from(types::TunnelType::Wireguard), + net::TunnelType::OpenVpn => i32::from(types::TunnelType::Openvpn), }, - proxy: endpoint.proxy.map(|proxy_ep| proto::ProxyEndpoint { + proxy: endpoint.proxy.map(|proxy_ep| types::ProxyEndpoint { address: proxy_ep.endpoint.address.to_string(), protocol: match proxy_ep.endpoint.protocol { - TransportProtocol::Tcp => i32::from(proto::TransportProtocol::Tcp), - TransportProtocol::Udp => i32::from(proto::TransportProtocol::Udp), + TransportProtocol::Tcp => i32::from(types::TransportProtocol::Tcp), + TransportProtocol::Udp => i32::from(types::TransportProtocol::Udp), }, proxy_type: match proxy_ep.proxy_type { - net::proxy::ProxyType::Shadowsocks => i32::from(proto::ProxyType::Shadowsocks), - net::proxy::ProxyType::Custom => i32::from(proto::ProxyType::Custom), + net::proxy::ProxyType::Shadowsocks => i32::from(types::ProxyType::Shadowsocks), + net::proxy::ProxyType::Custom => i32::from(types::ProxyType::Custom), }, }), } } -fn convert_geoip_location(geoip: GeoIpLocation) -> proto::GeoIpLocation { - proto::GeoIpLocation { +fn convert_geoip_location(geoip: GeoIpLocation) -> types::GeoIpLocation { + types::GeoIpLocation { ipv4: geoip.ipv4.map(|ip| ip.to_string()).unwrap_or_default(), ipv6: geoip.ipv6.map(|ip| ip.to_string()).unwrap_or_default(), country: geoip.country, @@ -1483,8 +1467,8 @@ fn convert_geoip_location(geoip: GeoIpLocation) -> proto::GeoIpLocation { } } -fn convert_version_info(version_info: &version::AppVersionInfo) -> proto::AppVersionInfo { - proto::AppVersionInfo { +fn convert_version_info(version_info: &version::AppVersionInfo) -> types::AppVersionInfo { + types::AppVersionInfo { supported: version_info.supported, latest_stable: version_info.latest_stable.clone(), latest_beta: version_info.latest_beta.clone(), @@ -1492,7 +1476,7 @@ fn convert_version_info(version_info: &version::AppVersionInfo) -> proto::AppVer } } -fn convert_proto_location(location: proto::RelayLocation) -> Constraint<LocationConstraint> { +fn convert_proto_location(location: types::RelayLocation) -> Constraint<LocationConstraint> { if !location.hostname.is_empty() { Constraint::Only(LocationConstraint::Hostname( location.country, @@ -1513,42 +1497,12 @@ pub struct ManagementInterfaceServer { socket_path: String, runtime: tokio02::runtime::Runtime, server_abort_tx: triggered::Trigger, - server_join_handle: - Option<tokio02::task::JoinHandle<std::result::Result<(), tonic::transport::Error>>>, + server_join_handle: Option< + tokio02::task::JoinHandle<std::result::Result<(), mullvad_management_interface::Error>>, + >, } impl ManagementInterfaceServer { - async fn start_server( - socket_path: String, - daemon_tx: DaemonCommandSender, - server_start_tx: std::sync::mpsc::Sender<()>, - abort_rx: triggered::Listener, - subscriptions: Arc<RwLock<Vec<EventsListenerSender>>>, - ) -> std::result::Result<(), tonic::transport::Error> { - use futures::stream::TryStreamExt; - use parity_tokio_ipc::{Endpoint as IpcEndpoint, SecurityAttributes}; - - let mut endpoint = IpcEndpoint::new(socket_path); - endpoint.set_security_attributes( - SecurityAttributes::allow_everyone_create() - .unwrap() - .set_mode(777) - .unwrap(), - ); - let incoming = endpoint.incoming().unwrap(); - let _ = server_start_tx.send(()); - - let server = ManagementServiceImpl { - daemon_tx, - subscriptions, - }; - - Server::builder() - .add_service(ManagementServiceServer::new(server)) - .serve_with_incoming_shutdown(incoming.map_ok(StreamBox), abort_rx) - .await - } - pub fn start(tunnel_tx: DaemonCommandSender) -> Result<Self, Error> { // TODO: don't spawn a tokio runtime here; make this function async let mut runtime = tokio02::runtime::Builder::new() @@ -1566,12 +1520,14 @@ impl ManagementInterfaceServer { let (server_abort_tx, server_abort_rx) = triggered::trigger(); let (start_tx, start_rx) = mpsc::channel(); - let server_join_handle = runtime.spawn(Self::start_server( - socket_path.clone(), - tunnel_tx, + let server = ManagementServiceImpl { + daemon_tx: tunnel_tx, + subscriptions: subscriptions.clone(), + }; + let server_join_handle = runtime.spawn(mullvad_management_interface::spawn_rpc_server( + server, start_tx, server_abort_rx, - subscriptions.clone(), )); if let Err(_) = start_rx.recv() { @@ -1582,19 +1538,9 @@ impl ManagementInterfaceServer { .unwrap_err()); } - #[cfg(unix)] - { - use std::{fs, os::unix::fs::PermissionsExt}; - fs::set_permissions(&socket_path, PermissionsExt::from_mode(0o766)) - .map_err(Error::PermissionsError)?; - } - #[cfg(windows)] - crate::windows_permissions::deny_network_access(&socket_path) - .map_err(Error::PermissionsError)?; - Ok(ManagementInterfaceServer { subscriptions, - socket_path: socket_path.to_string(), + socket_path, runtime, server_abort_tx, server_join_handle: Some(server_join_handle), @@ -1635,53 +1581,53 @@ pub struct ManagementInterfaceEventBroadcaster { impl EventListener for ManagementInterfaceEventBroadcaster { /// Sends a new state update to all `new_state` subscribers of the management interface. fn notify_new_state(&self, new_state: TunnelState) { - self.notify(proto::DaemonEvent { - event: Some(DaemonEventType::TunnelState(convert_state(new_state))), + self.notify(types::DaemonEvent { + event: Some(daemon_event::Event::TunnelState(convert_state(new_state))), }) } /// Sends settings to all `settings` subscribers of the management interface. fn notify_settings(&self, settings: Settings) { log::debug!("Broadcasting new settings"); - self.notify(proto::DaemonEvent { - event: Some(DaemonEventType::Settings(convert_settings(&settings))), + self.notify(types::DaemonEvent { + event: Some(daemon_event::Event::Settings(convert_settings(&settings))), }) } /// Sends relays to all subscribers of the management interface. fn notify_relay_list(&self, relay_list: RelayList) { log::debug!("Broadcasting new relay list"); - let mut new_list = proto::RelayList { + let mut new_list = types::RelayList { countries: Vec::new(), }; new_list.countries.reserve(relay_list.countries.len()); for country in &relay_list.countries { new_list.countries.push(convert_relay_list_country(country)); } - self.notify(proto::DaemonEvent { - event: Some(DaemonEventType::RelayList(new_list)), + self.notify(types::DaemonEvent { + event: Some(daemon_event::Event::RelayList(new_list)), }) } fn notify_app_version(&self, app_version_info: version::AppVersionInfo) { log::debug!("Broadcasting new app version info"); let new_info = convert_version_info(&app_version_info); - self.notify(proto::DaemonEvent { - event: Some(DaemonEventType::VersionInfo(new_info)), + self.notify(types::DaemonEvent { + event: Some(daemon_event::Event::VersionInfo(new_info)), }) } fn notify_key_event(&self, key_event: mullvad_types::wireguard::KeygenEvent) { log::debug!("Broadcasting new wireguard key event"); let new_event = convert_wireguard_key_event(&key_event); - self.notify(proto::DaemonEvent { - event: Some(DaemonEventType::KeyEvent(new_event)), + self.notify(types::DaemonEvent { + event: Some(daemon_event::Event::KeyEvent(new_event)), }) } } impl ManagementInterfaceEventBroadcaster { - fn notify(&self, value: proto::DaemonEvent) { + fn notify(&self, value: types::DaemonEvent) { let mut subscriptions = self.subscriptions.write(); // TODO: using write-lock everywhere. use a mutex instead? subscriptions.retain(|tx| tx.send(Ok(value.clone())).is_ok()); @@ -1695,51 +1641,13 @@ impl Drop for ManagementInterfaceEventBroadcaster { } // Converts a REST API error for an account into a tonic status. -fn map_rest_account_error(error: RestError) -> tonic::Status { +fn map_rest_account_error(error: RestError) -> Status { match error { RestError::ApiError(status, message) if status == StatusCode::UNAUTHORIZED || status == StatusCode::FORBIDDEN => { - tonic::Status::new(tonic::Code::Unauthenticated, message) + Status::new(Code::Unauthenticated, message) } - _ => tonic::Status::internal("internal error"), - } -} - - -// FIXME -use std::{ - pin::Pin, - task::{Context, Poll}, -}; -use tokio02::io::{AsyncRead, AsyncWrite}; - -#[derive(Debug)] -pub struct StreamBox<T: AsyncRead + AsyncWrite>(pub T); -impl<T: AsyncRead + AsyncWrite> Connected for StreamBox<T> {} -impl<T: AsyncRead + AsyncWrite + Unpin> AsyncRead for StreamBox<T> { - fn poll_read( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &mut [u8], - ) -> Poll<std::io::Result<usize>> { - Pin::new(&mut self.0).poll_read(cx, buf) - } -} -impl<T: AsyncRead + AsyncWrite + Unpin> AsyncWrite for StreamBox<T> { - fn poll_write( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &[u8], - ) -> Poll<std::io::Result<usize>> { - Pin::new(&mut self.0).poll_write(cx, buf) - } - - fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<std::io::Result<()>> { - Pin::new(&mut self.0).poll_flush(cx) - } - - fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<std::io::Result<()>> { - Pin::new(&mut self.0).poll_shutdown(cx) + _ => Status::internal("internal error"), } } diff --git a/mullvad-daemon/src/rpc_uniqueness_check.rs b/mullvad-daemon/src/rpc_uniqueness_check.rs index 50a9a150a7..76d524c765 100644 --- a/mullvad-daemon/src/rpc_uniqueness_check.rs +++ b/mullvad-daemon/src/rpc_uniqueness_check.rs @@ -1,37 +1,12 @@ -use mullvad_paths; -use parity_tokio_ipc::Endpoint as IpcEndpoint; +use mullvad_management_interface::new_rpc_client; use talpid_types::ErrorExt; -use tonic::{ - self, - transport::{self, Endpoint, Uri}, -}; -use tower::service_fn; - -mod proto { - tonic::include_proto!("mullvad_daemon.management_interface"); -} -use proto::management_service_client::ManagementServiceClient; - -async fn new_grpc_client() -> Result<ManagementServiceClient<transport::Channel>, transport::Error> -{ - let ipc_path = mullvad_paths::get_rpc_socket_path(); - - // The URI will be ignored - let channel = Endpoint::from_static("lttp://[::]:50051") - .connect_with_connector(service_fn(move |_: Uri| { - IpcEndpoint::connect(ipc_path.clone()) - })) - .await?; - - Ok(ManagementServiceClient::new(channel)) -} /// Checks if there is another instance of the daemon running. /// /// Tries to connect to another daemon and perform a simple RPC call. If it fails, assumes the /// other daemon has stopped. pub async fn is_another_instance_running() -> bool { - match new_grpc_client().await { + match new_rpc_client().await { Ok(_) => true, Err(error) => { let msg = diff --git a/mullvad-management-interface/Cargo.toml b/mullvad-management-interface/Cargo.toml new file mode 100644 index 0000000000..31647006b1 --- /dev/null +++ b/mullvad-management-interface/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "mullvad-management-interface" +version = "0.1.0" +authors = ["Mullvad VPN"] +description = "Mullvad VPN IPC. Contains types and functions for IPC clients and servers." +license = "GPL-3.0" +edition = "2018" +publish = false + +[dependencies] +err-derive = "0.2.1" +mullvad-paths = { path = "../mullvad-paths" } +tonic = "0.2" +tower = "0.3" +prost = "0.6" +prost-types = "0.6" +parity-tokio-ipc = "0.7" +futures = "0.3" +tokio = { version = "0.2", features = [ "io-util", "process", "rt-core", "rt-threaded", "stream"] } +triggered = "0.1.1" +winapi = { version = "0.3", features = ["errhandlingapi", "handleapi", "libloaderapi", "ntlsa", "synchapi", "tlhelp32", "winbase", "winerror", "winuser"] } + +[build-dependencies] +tonic-build = { version = "0.2", default-features = false, features = ["transport", "prost"] } diff --git a/mullvad-management-interface/build.rs b/mullvad-management-interface/build.rs new file mode 100644 index 0000000000..e3dd7a8186 --- /dev/null +++ b/mullvad-management-interface/build.rs @@ -0,0 +1,5 @@ +fn main() { + const PROTO_FILE: &str = "proto/management_interface.proto"; + tonic_build::compile_protos(PROTO_FILE).unwrap(); + println!("cargo:rerun-if-changed={}", PROTO_FILE); +} diff --git a/mullvad-daemon/proto/management_interface.proto b/mullvad-management-interface/proto/management_interface.proto index ea62f6976e..ea62f6976e 100644 --- a/mullvad-daemon/proto/management_interface.proto +++ b/mullvad-management-interface/proto/management_interface.proto diff --git a/mullvad-management-interface/src/lib.rs b/mullvad-management-interface/src/lib.rs new file mode 100644 index 0000000000..419e2d48b1 --- /dev/null +++ b/mullvad-management-interface/src/lib.rs @@ -0,0 +1,123 @@ +pub mod types { + tonic::include_proto!("mullvad_daemon.management_interface"); + + pub use prost_types::Timestamp; +} + +use parity_tokio_ipc::Endpoint as IpcEndpoint; +#[cfg(unix)] +use std::{fs, os::unix::fs::PermissionsExt}; +use std::{ + io, + pin::Pin, + task::{Context, Poll}, +}; +use tokio::io::{AsyncRead, AsyncWrite}; +use tonic::transport::{server::Connected, Endpoint, Server, Uri}; +use tower::service_fn; + +pub use tonic::{async_trait, transport::Channel, Code, Request, Response, Status}; + +pub type ManagementServiceClient = + types::management_service_client::ManagementServiceClient<Channel>; +pub use types::management_service_server::{ManagementService, ManagementServiceServer}; + +#[derive(err_derive::Error, Debug)] +#[error(no_from)] +pub enum Error { + #[error(display = "Management RPC server or client error")] + GrpcTransportError(#[error(source)] tonic::transport::Error), + + #[error(display = "Failed to start IPC pipe/socket")] + StartServerError(#[error(source)] io::Error), + + #[error(display = "Failed to initialize pipe/socket security attributes")] + SecurityAttributes(#[error(source)] io::Error), + + #[error(display = "Unable to set permissions for IPC endpoint")] + PermissionsError(#[error(source)] io::Error), +} + +#[cfg(target_os = "windows")] +mod windows_permissions; + +pub async fn new_rpc_client() -> Result<ManagementServiceClient, Error> { + let ipc_path = mullvad_paths::get_rpc_socket_path(); + + // The URI will be ignored + let channel = Endpoint::from_static("lttp://[::]:50051") + .connect_with_connector(service_fn(move |_: Uri| { + IpcEndpoint::connect(ipc_path.clone()) + })) + .await + .map_err(Error::GrpcTransportError)?; + + Ok(ManagementServiceClient::new(channel)) +} + +pub async fn spawn_rpc_server<T: ManagementService>( + service: T, + server_start_tx: std::sync::mpsc::Sender<()>, + abort_rx: triggered::Listener, +) -> std::result::Result<(), Error> { + use futures::stream::TryStreamExt; + use parity_tokio_ipc::SecurityAttributes; + + let socket_path = mullvad_paths::get_rpc_socket_path() + .to_string_lossy() + .to_string(); + + let mut endpoint = IpcEndpoint::new(socket_path.to_string()); + endpoint.set_security_attributes( + SecurityAttributes::allow_everyone_create() + .map_err(Error::SecurityAttributes)? + .set_mode(777) + .map_err(Error::SecurityAttributes)?, + ); + let incoming = endpoint.incoming().map_err(Error::StartServerError)?; + + #[cfg(unix)] + fs::set_permissions(&socket_path, PermissionsExt::from_mode(0o766)) + .map_err(Error::PermissionsError)?; + #[cfg(windows)] + crate::windows_permissions::deny_network_access(&socket_path) + .map_err(Error::PermissionsError)?; + + let _ = server_start_tx.send(()); + + Server::builder() + .add_service(ManagementServiceServer::new(service)) + .serve_with_incoming_shutdown(incoming.map_ok(StreamBox), abort_rx) + .await + .map_err(Error::GrpcTransportError) +} + +#[derive(Debug)] +struct StreamBox<T: AsyncRead + AsyncWrite>(pub T); +impl<T: AsyncRead + AsyncWrite> Connected for StreamBox<T> {} +impl<T: AsyncRead + AsyncWrite + Unpin> AsyncRead for StreamBox<T> { + fn poll_read( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + buf: &mut [u8], + ) -> Poll<std::io::Result<usize>> { + Pin::new(&mut self.0).poll_read(cx, buf) + } +} +impl<T: AsyncRead + AsyncWrite + Unpin> AsyncWrite for StreamBox<T> { + fn poll_write( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + buf: &[u8], + ) -> Poll<std::io::Result<usize>> { + Pin::new(&mut self.0).poll_write(cx, buf) + } + + fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<std::io::Result<()>> { + Pin::new(&mut self.0).poll_flush(cx) + } + + fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<std::io::Result<()>> { + Pin::new(&mut self.0).poll_shutdown(cx) + } +} diff --git a/mullvad-daemon/src/windows_permissions.rs b/mullvad-management-interface/src/windows_permissions.rs index 0b39282348..0b39282348 100644 --- a/mullvad-daemon/src/windows_permissions.rs +++ b/mullvad-management-interface/src/windows_permissions.rs diff --git a/mullvad-setup/Cargo.toml b/mullvad-setup/Cargo.toml index dd2e87ad71..04da0d49ca 100644 --- a/mullvad-setup/Cargo.toml +++ b/mullvad-setup/Cargo.toml @@ -15,20 +15,15 @@ path = "src/main.rs" clap = "2.32" env_logger = "0.7" err-derive = "0.2.1" -prost = "0.6" -prost-types = "0.6" -tonic = "0.2" -tower = "0.3" + +mullvad-management-interface = { path = "../mullvad-management-interface" } + tokio = { version = "0.2", features = [ "io-util", "process", "rt-core", "rt-threaded", "stream"] } -parity-tokio-ipc = "0.7" mullvad-paths = { path = "../mullvad-paths" } talpid-core = { path = "../talpid-core" } talpid-types = { path = "../talpid-types" } -[build-dependencies] -tonic-build = { version = "0.2", default-features = false, features = ["transport", "prost"] } - [target.'cfg(windows)'.build-dependencies] winres = "0.1" winapi = "0.3" diff --git a/mullvad-setup/build.rs b/mullvad-setup/build.rs index e4d26e964a..8cdd992c7c 100644 --- a/mullvad-setup/build.rs +++ b/mullvad-setup/build.rs @@ -1,10 +1,6 @@ use std::{env, fs, path::PathBuf}; fn main() { - const PROTO_FILE: &str = "../mullvad-daemon/proto/management_interface.proto"; - tonic_build::compile_protos(PROTO_FILE).unwrap(); - println!("cargo:rerun-if-changed={}", PROTO_FILE); - let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); let product_version = env!("CARGO_PKG_VERSION").replacen(".0", "", 1); fs::write(out_dir.join("product-version.txt"), &product_version).unwrap(); diff --git a/mullvad-setup/src/main.rs b/mullvad-setup/src/main.rs index 6f80be9df8..c53394a473 100644 --- a/mullvad-setup/src/main.rs +++ b/mullvad-setup/src/main.rs @@ -1,28 +1,18 @@ use clap::{crate_authors, crate_description, crate_name, SubCommand}; -use parity_tokio_ipc::Endpoint as IpcEndpoint; +use mullvad_management_interface::new_rpc_client; use std::process; use talpid_core::firewall::{self, Firewall, FirewallArguments}; use talpid_types::ErrorExt; -use tonic::{ - self, - transport::{Endpoint, Uri}, -}; -use tower::service_fn; - -mod proto { - tonic::include_proto!("mullvad_daemon.management_interface"); -} -use proto::management_service_client::ManagementServiceClient; pub const PRODUCT_VERSION: &str = include_str!(concat!(env!("OUT_DIR"), "/product-version.txt")); #[derive(err_derive::Error, Debug)] pub enum Error { - #[error(display = "Failed to connect to daemon")] - DaemonConnect(#[error(source)] tonic::transport::Error), + #[error(display = "Failed to connect to RPC client")] + RpcConnectionError(#[error(source)] mullvad_management_interface::Error), #[error(display = "RPC call failed")] - DaemonRpcError(#[error(source)] tonic::Status), + DaemonRpcError(#[error(source)] mullvad_management_interface::Status), #[error(display = "This command cannot be run if the daemon is active")] DaemonIsRunning, @@ -67,7 +57,7 @@ async fn main() { } async fn prepare_restart() -> Result<(), Error> { - let mut rpc = new_grpc_client().await?; + let mut rpc = new_rpc_client().await?; rpc.prepare_restart(()) .await .map_err(Error::DaemonRpcError)?; @@ -76,7 +66,7 @@ async fn prepare_restart() -> Result<(), Error> { async fn reset_firewall() -> Result<(), Error> { // Ensure that the daemon isn't running - if let Ok(_) = new_grpc_client().await { + if let Ok(_) = new_rpc_client().await { return Err(Error::DaemonIsRunning); } @@ -88,18 +78,3 @@ async fn reset_firewall() -> Result<(), Error> { firewall.reset_policy().map_err(Error::FirewallError) } - -pub async fn new_grpc_client() -> Result<ManagementServiceClient<tonic::transport::Channel>, Error> -{ - let ipc_path = mullvad_paths::get_rpc_socket_path(); - - // The URI will be ignored - let channel = Endpoint::from_static("lttp://[::]:50051") - .connect_with_connector(service_fn(move |_: Uri| { - IpcEndpoint::connect(ipc_path.clone()) - })) - .await - .map_err(Error::DaemonConnect)?; - - Ok(ManagementServiceClient::new(channel)) -} diff --git a/mullvad-types/Cargo.toml b/mullvad-types/Cargo.toml index ca3dab3c86..d4f7871e52 100644 --- a/mullvad-types/Cargo.toml +++ b/mullvad-types/Cargo.toml @@ -16,7 +16,6 @@ log = "0.4" regex = "1" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -tonic = "0.2" talpid-types = { path = "../talpid-types" } mullvad-paths = { path = "../mullvad-paths" } diff --git a/mullvad-types/src/account.rs b/mullvad-types/src/account.rs index a2ec85ebba..0acb0941aa 100644 --- a/mullvad-types/src/account.rs +++ b/mullvad-types/src/account.rs @@ -28,32 +28,3 @@ pub struct VoucherSubmission { #[cfg_attr(target_os = "android", jnix(map = "|expiry| expiry.to_string()"))] pub new_expiry: DateTime<Utc>, } - -/// Mapping of mullvad-api errors to enum variants. Used by frontends to explain why a voucher -/// was rejected by the `/v1/submit-voucher` RPC. -#[derive(err_derive::Error, Debug)] -pub enum VoucherError { - /// Error code `tonic::Code::NotFound` - #[error(display = "Bad voucher code")] - BadVoucher, - /// Error code `tonic::Code::ResourceExhausted` - #[error(display = "Voucher already used")] - VoucherAlreadyUsed, - /// Error code `tonic::Code::Internal` - #[error(display = "Server internal error")] - InternalError, - #[error(display = "Unknown error, {}", _0)] - UnknownError(i64), -} - -impl VoucherError { - /// Create error from RPC error code. - pub fn from_rpc_error_code(err_code: i64) -> VoucherError { - match err_code { - x if x == tonic::Code::NotFound as i64 => VoucherError::BadVoucher, - x if x == tonic::Code::ResourceExhausted as i64 => VoucherError::VoucherAlreadyUsed, - x if x == tonic::Code::Internal as i64 => VoucherError::InternalError, - err => VoucherError::UnknownError(err), - } - } -} |
