diff options
| author | David Lönnhager <david.l@mullvad.net> | 2021-01-18 17:47:12 +0100 |
|---|---|---|
| committer | David Lönnhager <david.l@mullvad.net> | 2021-01-28 13:22:28 +0100 |
| commit | c04b432cd2a457b6180279a2156d3bd9ff761bd0 (patch) | |
| tree | 85899123a25066d8b0dc4e73fcf8666b84a7e9a0 | |
| parent | 1cf0d2659f16c4124f179f2f9ad8edb2cd842a22 (diff) | |
| download | mullvadvpn-c04b432cd2a457b6180279a2156d3bd9ff761bd0.tar.xz mullvadvpn-c04b432cd2a457b6180279a2156d3bd9ff761bd0.zip | |
Propagate more errors to the management interface
| -rw-r--r-- | mullvad-daemon/src/lib.rs | 398 | ||||
| -rw-r--r-- | mullvad-daemon/src/management_interface.rs | 149 |
2 files changed, 361 insertions, 186 deletions
diff --git a/mullvad-daemon/src/lib.rs b/mullvad-daemon/src/lib.rs index 42f067a4f3..754f6d34f7 100644 --- a/mullvad-daemon/src/lib.rs +++ b/mullvad-daemon/src/lib.rs @@ -82,6 +82,8 @@ const FIRST_KEY_PUSH_TIMEOUT: Duration = Duration::from_secs(5); /// Delay between generating a new WireGuard key and reconnecting const WG_RECONNECT_DELAY: Duration = Duration::from_secs(30); +pub type ResponseTx<T, E> = oneshot::Sender<Result<T, E>>; + #[derive(err_derive::Error, Debug)] #[error(no_from)] pub enum Error { @@ -94,6 +96,9 @@ pub enum Error { #[error(display = "Unable to create RPC client")] InitRpcFactory(#[error(source)] mullvad_rpc::Error), + #[error(display = "REST request failed")] + RestError(#[error(source)] mullvad_rpc::rest::Error), + #[error(display = "Unable to load account history with wireguard key cache")] LoadAccountHistory(#[error(source)] account_history::Error), @@ -107,7 +112,16 @@ pub enum Error { #[error(display = "No bridge available")] NoBridgeAvailable, - #[error(display = "Account history problems")] + #[error(display = "No account token is set")] + NoAccountToken, + + #[error(display = "No account history available for the token")] + NoAccountTokenHistory, + + #[error(display = "Settings error")] + SettingsError(#[error(source)] settings::Error), + + #[error(display = "Account history error")] AccountHistory(#[error(source)] account_history::Error), #[error(display = "Tunnel state machine error")] @@ -151,83 +165,80 @@ pub enum DaemonCommand { GetState(oneshot::Sender<TunnelState>), /// Get the current geographical location. GetCurrentLocation(oneshot::Sender<Option<GeoIpLocation>>), - CreateNewAccount(oneshot::Sender<Result<String, mullvad_rpc::rest::Error>>), + CreateNewAccount(ResponseTx<String, Error>), /// Request the metadata for an account. GetAccountData( - oneshot::Sender<Result<AccountData, mullvad_rpc::rest::Error>>, + ResponseTx<AccountData, mullvad_rpc::rest::Error>, AccountToken, ), /// Request www auth token for an account - GetWwwAuthToken(oneshot::Sender<Result<String, mullvad_rpc::rest::Error>>), + GetWwwAuthToken(ResponseTx<String, Error>), /// Submit voucher to add time to the current account. Returns time added in seconds - SubmitVoucher( - oneshot::Sender<Result<VoucherSubmission, mullvad_rpc::rest::Error>>, - String, - ), + SubmitVoucher(ResponseTx<VoucherSubmission, Error>, String), /// Request account history GetAccountHistory(oneshot::Sender<Vec<AccountToken>>), /// Request account history - RemoveAccountFromHistory(oneshot::Sender<()>, AccountToken), + RemoveAccountFromHistory(ResponseTx<(), Error>, AccountToken), /// Clear account history - ClearAccountHistory(oneshot::Sender<()>), + ClearAccountHistory(ResponseTx<(), Error>), /// Get the list of countries and cities where there are relays. GetRelayLocations(oneshot::Sender<RelayList>), /// Trigger an asynchronous relay list update. This returns before the relay list is actually /// updated. UpdateRelayLocations, /// Set which account token to use for subsequent connection attempts. - SetAccount(oneshot::Sender<()>, Option<AccountToken>), + SetAccount(ResponseTx<(), settings::Error>, Option<AccountToken>), /// Place constraints on the type of tunnel and relay - UpdateRelaySettings(oneshot::Sender<()>, RelaySettingsUpdate), + UpdateRelaySettings(ResponseTx<(), settings::Error>, RelaySettingsUpdate), /// Set the allow LAN setting. - SetAllowLan(oneshot::Sender<()>, bool), + SetAllowLan(ResponseTx<(), settings::Error>, bool), /// Set the beta program setting. - SetShowBetaReleases(oneshot::Sender<()>, bool), + SetShowBetaReleases(ResponseTx<(), settings::Error>, bool), /// Set the block_when_disconnected setting. - SetBlockWhenDisconnected(oneshot::Sender<()>, bool), + SetBlockWhenDisconnected(ResponseTx<(), settings::Error>, bool), /// Set the auto-connect setting. - SetAutoConnect(oneshot::Sender<()>, bool), + SetAutoConnect(ResponseTx<(), settings::Error>, bool), /// Set the mssfix argument for OpenVPN - SetOpenVpnMssfix(oneshot::Sender<()>, Option<u16>), + SetOpenVpnMssfix(ResponseTx<(), settings::Error>, Option<u16>), /// Set proxy details for OpenVPN - SetBridgeSettings(oneshot::Sender<Result<(), settings::Error>>, BridgeSettings), + SetBridgeSettings(ResponseTx<(), settings::Error>, BridgeSettings), /// Set proxy state - SetBridgeState(oneshot::Sender<Result<(), settings::Error>>, BridgeState), + SetBridgeState(ResponseTx<(), settings::Error>, BridgeState), /// Set if IPv6 should be enabled in the tunnel - SetEnableIpv6(oneshot::Sender<()>, bool), + SetEnableIpv6(ResponseTx<(), settings::Error>, bool), /// Set custom DNS servers to use instead of passing requests to the gateway - SetDnsOptions(oneshot::Sender<()>, DnsOptions), + SetDnsOptions(ResponseTx<(), settings::Error>, DnsOptions), /// Set MTU for wireguard tunnels - SetWireguardMtu(oneshot::Sender<()>, Option<u16>), + SetWireguardMtu(ResponseTx<(), settings::Error>, Option<u16>), /// Set automatic key rotation interval for wireguard tunnels - SetWireguardRotationInterval(oneshot::Sender<()>, Option<u32>), + SetWireguardRotationInterval(ResponseTx<(), settings::Error>, Option<u32>), /// Get the daemon settings GetSettings(oneshot::Sender<Settings>), /// Generate new wireguard key - GenerateWireguardKey(oneshot::Sender<wireguard::KeygenEvent>), + GenerateWireguardKey(ResponseTx<wireguard::KeygenEvent, Error>), /// Return a public key of the currently set wireguard private key, if there is one - GetWireguardKey(oneshot::Sender<Option<wireguard::PublicKey>>), + GetWireguardKey(ResponseTx<Option<wireguard::PublicKey>, Error>), /// Verify if the currently set wireguard key is valid. - VerifyWireguardKey(oneshot::Sender<bool>), + VerifyWireguardKey(ResponseTx<bool, Error>), /// Get information about the currently running and latest app versions GetVersionInfo(oneshot::Sender<Option<AppVersionInfo>>), /// Get current version of the app GetCurrentVersion(oneshot::Sender<AppVersion>), /// Remove settings and clear the cache #[cfg(not(target_os = "android"))] - FactoryReset(oneshot::Sender<()>), + FactoryReset(ResponseTx<(), Error>), /// Request list of processes excluded from the tunnel #[cfg(target_os = "linux")] - GetSplitTunnelProcesses(oneshot::Sender<Vec<i32>>), + GetSplitTunnelProcesses(ResponseTx<Vec<i32>, split_tunnel::Error>), /// Exclude traffic of a process (PID) from the tunnel #[cfg(target_os = "linux")] - AddSplitTunnelProcess(oneshot::Sender<()>, i32), + AddSplitTunnelProcess(ResponseTx<(), split_tunnel::Error>, i32), /// Remove process (PID) from list of processes excluded from the tunnel #[cfg(target_os = "linux")] - RemoveSplitTunnelProcess(oneshot::Sender<()>, i32), + RemoveSplitTunnelProcess(ResponseTx<(), split_tunnel::Error>, i32), /// Clear list of processes excluded from the tunnel #[cfg(target_os = "linux")] - ClearSplitTunnelProcesses(oneshot::Sender<()>), + ClearSplitTunnelProcesses(ResponseTx<(), split_tunnel::Error>), /// Makes the daemon exit the main loop and quit. Shutdown, /// Saves the target tunnel state and enters a blocking state. The state is restored @@ -258,10 +269,7 @@ pub(crate) enum InternalDaemonEvent { ), ), /// New Account created - NewAccountEvent( - AccountToken, - oneshot::Sender<Result<String, mullvad_rpc::rest::Error>>, - ), + NewAccountEvent(AccountToken, oneshot::Sender<Result<String, Error>>), /// The background job fetching new `AppVersionInfo`s got a new info object. NewAppVersionInfo(AppVersionInfo), } @@ -1220,7 +1228,7 @@ where async fn handle_new_account_event( &mut self, new_token: AccountToken, - tx: oneshot::Sender<Result<String, mullvad_rpc::rest::Error>>, + tx: ResponseTx<String, Error>, ) { match self.set_account(Some(new_token.clone())).await { Ok(_) => { @@ -1228,7 +1236,11 @@ where let _ = tx.send(Ok(new_token)); } Err(err) => { - log::error!("Failed to save new account - {}", err); + log::error!( + "{}", + err.display_chain_with_msg("Failed to save new account") + ); + let _ = tx.send(Err(Error::SettingsError(err))); } }; } @@ -1333,10 +1345,7 @@ where }) } - async fn on_create_new_account( - &mut self, - tx: oneshot::Sender<Result<String, mullvad_rpc::rest::Error>>, - ) { + async fn on_create_new_account(&mut self, tx: ResponseTx<String, Error>) { let daemon_tx = self.tx.clone(); let future = self.accounts_proxy.create_account(); @@ -1346,7 +1355,7 @@ where let _ = daemon_tx.send(InternalDaemonEvent::NewAccountEvent(account_token, tx)); } Err(err) => { - let _ = tx.send(Err(err)); + let _ = tx.send(Err(Error::RestError(err))); } } }); @@ -1354,7 +1363,7 @@ where async fn on_get_account_data( &mut self, - tx: oneshot::Sender<Result<AccountData, mullvad_rpc::rest::Error>>, + tx: ResponseTx<AccountData, mullvad_rpc::rest::Error>, account_token: AccountToken, ) { let expiry_fut = self.accounts_proxy.get_expiry(account_token); @@ -1365,30 +1374,43 @@ where tokio::spawn(rpc_call); } - async fn on_get_www_auth_token( - &mut self, - tx: oneshot::Sender<Result<String, mullvad_rpc::rest::Error>>, - ) { + async fn on_get_www_auth_token(&mut self, tx: ResponseTx<String, Error>) { if let Some(account_token) = self.settings.get_account_token() { let future = self.accounts_proxy.get_www_auth_token(account_token); let rpc_call = async { - Self::oneshot_send(tx, future.await, "get_www_auth_token response"); + Self::oneshot_send( + tx, + future.await.map_err(Error::RestError), + "get_www_auth_token response", + ); }; tokio::spawn(rpc_call); + } else { + Self::oneshot_send( + tx, + Err(Error::NoAccountToken), + "get_www_auth_token response", + ); } } async fn on_submit_voucher( &mut self, - tx: oneshot::Sender<Result<VoucherSubmission, mullvad_rpc::rest::Error>>, + tx: ResponseTx<VoucherSubmission, Error>, voucher: String, ) { if let Some(account_token) = self.settings.get_account_token() { let future = self.accounts_proxy.submit_voucher(account_token, voucher); let rpc_call = async { - Self::oneshot_send(tx, future.await, "submit_voucher response"); + Self::oneshot_send( + tx, + future.await.map_err(Error::RestError), + "submit_voucher response", + ); }; tokio::spawn(rpc_call); + } else { + Self::oneshot_send(tx, Err(Error::NoAccountToken), "submit_voucher response"); } } @@ -1400,7 +1422,11 @@ where self.relay_selector.update().await; } - async fn on_set_account(&mut self, tx: oneshot::Sender<()>, account_token: Option<String>) { + async fn on_set_account( + &mut self, + tx: ResponseTx<(), settings::Error>, + account_token: Option<String>, + ) { match self.set_account(account_token.clone()).await { Ok(account_changed) => { if account_changed { @@ -1415,10 +1441,11 @@ where } }; } - Self::oneshot_send(tx, (), "set_account response"); + Self::oneshot_send(tx, Ok(()), "set_account response"); } - Err(e) => { - log::error!("Failed to set account - {}", e); + Err(error) => { + log::error!("{}", error.display_chain_with_msg("Failed to set account")); + Self::oneshot_send(tx, Err(error), "set_account response"); } } } @@ -1454,29 +1481,34 @@ where async fn on_remove_account_from_history( &mut self, - tx: oneshot::Sender<()>, + tx: ResponseTx<(), Error>, account_token: AccountToken, ) { - if self + let result = self .account_history .remove_account(&account_token) .await - .is_ok() - { - Self::oneshot_send(tx, (), "remove_account_from_history response"); - } + .map_err(Error::AccountHistory); + Self::oneshot_send(tx, result, "remove_account_from_history response"); } - async fn on_clear_account_history(&mut self, tx: oneshot::Sender<()>) { + async fn on_clear_account_history(&mut self, tx: ResponseTx<(), Error>) { match self.account_history.clear().await { Ok(_) => { self.set_target_state(TargetState::Unsecured); - Self::oneshot_send(tx, (), "clear_account_history response"); + Self::oneshot_send(tx, Ok(()), "clear_account_history response"); + } + Err(err) => { + log::error!( + "{}", + err.display_chain_with_msg("Failed to clear account history") + ); + Self::oneshot_send( + tx, + Err(Error::AccountHistory(err)), + "clear_account_history response", + ); } - Err(err) => log::error!( - "{}", - err.display_chain_with_msg("Failed to clear account history") - ), } } @@ -1503,18 +1535,18 @@ where } #[cfg(not(target_os = "android"))] - async fn on_factory_reset(&mut self, tx: oneshot::Sender<()>) { - let mut failed = false; + async fn on_factory_reset(&mut self, tx: ResponseTx<(), Error>) { + let mut last_error = Ok(()); if let Err(e) = self.settings.reset() { log::error!("Failed to reset settings - {}", e); - failed = true; + last_error = Err(Error::SettingsError(e)); } if let Err(e) = self.account_history.clear().await { log::error!("Failed to clear account history - {}", e); - failed = true; + last_error = Err(Error::AccountHistory(e)); } // Shut the daemon down. @@ -1526,7 +1558,7 @@ where "{}", e.display_chain_with_msg("Failed to clear cache directory") ); - failed = true; + last_error = Err(e); } if let Err(e) = Self::clear_log_directory() { @@ -1534,51 +1566,61 @@ where "{}", e.display_chain_with_msg("Failed to clear log directory") ); - failed = true; - } - if !failed { - Self::oneshot_send(tx, (), "factory_reset response"); + last_error = Err(e); } + Self::oneshot_send(tx, last_error, "factory_reset response"); })); } #[cfg(target_os = "linux")] - fn on_get_split_tunnel_processes(&mut self, tx: oneshot::Sender<Vec<i32>>) { - match self.exclude_pids.list() { - Ok(pids) => Self::oneshot_send(tx, pids, "get_split_tunnel_processes response"), - Err(e) => error!("{}", e.display_chain_with_msg("Unable to obtain PIDs")), - } + fn on_get_split_tunnel_processes(&mut self, tx: ResponseTx<Vec<i32>, split_tunnel::Error>) { + let result = self.exclude_pids.list().map_err(|error| { + error!("{}", error.display_chain_with_msg("Unable to obtain PIDs")); + error + }); + Self::oneshot_send(tx, result, "get_split_tunnel_processes response"); } #[cfg(target_os = "linux")] - fn on_add_split_tunnel_process(&mut self, tx: oneshot::Sender<()>, pid: i32) { - match self.exclude_pids.add(pid) { - Ok(()) => Self::oneshot_send(tx, (), "add_split_tunnel_process response"), - Err(e) => error!("{}", e.display_chain_with_msg("Unable to add PID")), - } + fn on_add_split_tunnel_process(&mut self, tx: ResponseTx<(), split_tunnel::Error>, pid: i32) { + let result = self.exclude_pids.add(pid).map_err(|error| { + error!("{}", error.display_chain_with_msg("Unable to add PID")); + error + }); + Self::oneshot_send(tx, result, "add_split_tunnel_process response"); } #[cfg(target_os = "linux")] - fn on_remove_split_tunnel_process(&mut self, tx: oneshot::Sender<()>, pid: i32) { - match self.exclude_pids.remove(pid) { - Ok(()) => Self::oneshot_send(tx, (), "remove_split_tunnel_process response"), - Err(e) => error!("{}", e.display_chain_with_msg("Unable to remove PID")), - } + fn on_remove_split_tunnel_process( + &mut self, + tx: ResponseTx<(), split_tunnel::Error>, + pid: i32, + ) { + let result = self.exclude_pids.remove(pid).map_err(|error| { + error!("{}", error.display_chain_with_msg("Unable to remove PID")); + error + }); + Self::oneshot_send(tx, result, "remove_split_tunnel_process response"); } #[cfg(target_os = "linux")] - fn on_clear_split_tunnel_processes(&mut self, tx: oneshot::Sender<()>) { - match self.exclude_pids.clear() { - Ok(()) => Self::oneshot_send(tx, (), "clear_split_tunnel_processes response"), - Err(e) => error!("{}", e.display_chain_with_msg("Unable to clear PIDs")), - } + fn on_clear_split_tunnel_processes(&mut self, tx: ResponseTx<(), split_tunnel::Error>) { + let result = self.exclude_pids.clear().map_err(|error| { + error!("{}", error.display_chain_with_msg("Unable to clear PIDs")); + error + }); + Self::oneshot_send(tx, result, "clear_split_tunnel_processes response"); } - fn on_update_relay_settings(&mut self, tx: oneshot::Sender<()>, update: RelaySettingsUpdate) { + fn on_update_relay_settings( + &mut self, + tx: ResponseTx<(), settings::Error>, + update: RelaySettingsUpdate, + ) { let save_result = self.settings.update_relay_settings(update); match save_result { Ok(settings_changed) => { - Self::oneshot_send(tx, (), "update_relay_settings response"); + Self::oneshot_send(tx, Ok(()), "update_relay_settings response"); if settings_changed { self.event_listener .notify_settings(self.settings.to_settings()); @@ -1586,30 +1628,40 @@ where self.reconnect_tunnel(); } } - Err(e) => error!("{}", e.display_chain_with_msg("Unable to save settings")), + Err(e) => { + error!("{}", e.display_chain_with_msg("Unable to save settings")); + Self::oneshot_send(tx, Err(e), "update_relay_settings response"); + } } } - fn on_set_allow_lan(&mut self, tx: oneshot::Sender<()>, allow_lan: bool) { + fn on_set_allow_lan(&mut self, tx: ResponseTx<(), settings::Error>, allow_lan: bool) { let save_result = self.settings.set_allow_lan(allow_lan); match save_result { Ok(settings_changed) => { - Self::oneshot_send(tx, (), "set_allow_lan response"); + Self::oneshot_send(tx, Ok(()), "set_allow_lan response"); if settings_changed { self.event_listener .notify_settings(self.settings.to_settings()); self.send_tunnel_command(TunnelCommand::AllowLan(allow_lan)); } } - Err(e) => error!("{}", e.display_chain_with_msg("Unable to save settings")), + Err(e) => { + error!("{}", e.display_chain_with_msg("Unable to save settings")); + Self::oneshot_send(tx, Err(e), "set_allow_lan response"); + } } } - async fn on_set_show_beta_releases(&mut self, tx: oneshot::Sender<()>, enabled: bool) { + async fn on_set_show_beta_releases( + &mut self, + tx: ResponseTx<(), settings::Error>, + enabled: bool, + ) { let save_result = self.settings.set_show_beta_releases(enabled); match save_result { Ok(settings_changed) => { - Self::oneshot_send(tx, (), "set_show_beta_releases response"); + Self::oneshot_send(tx, Ok(()), "set_show_beta_releases response"); if settings_changed { self.event_listener .notify_settings(self.settings.to_settings()); @@ -1617,13 +1669,16 @@ where handle.set_show_beta_releases(enabled).await; } } - Err(e) => error!("{}", e.display_chain_with_msg("Unable to save settings")), + Err(e) => { + error!("{}", e.display_chain_with_msg("Unable to save settings")); + Self::oneshot_send(tx, Err(e), "set_show_beta_releases response"); + } } } fn on_set_block_when_disconnected( &mut self, - tx: oneshot::Sender<()>, + tx: ResponseTx<(), settings::Error>, block_when_disconnected: bool, ) { let save_result = self @@ -1631,7 +1686,7 @@ where .set_block_when_disconnected(block_when_disconnected); match save_result { Ok(settings_changed) => { - Self::oneshot_send(tx, (), "set_block_when_disconnected response"); + Self::oneshot_send(tx, Ok(()), "set_block_when_disconnected response"); if settings_changed { self.event_listener .notify_settings(self.settings.to_settings()); @@ -1640,29 +1695,39 @@ where )); } } - Err(e) => error!("{}", e.display_chain_with_msg("Unable to save settings")), + Err(e) => { + error!("{}", e.display_chain_with_msg("Unable to save settings")); + Self::oneshot_send(tx, Err(e), "set_block_when_disconnected response"); + } } } - fn on_set_auto_connect(&mut self, tx: oneshot::Sender<()>, auto_connect: bool) { + fn on_set_auto_connect(&mut self, tx: ResponseTx<(), settings::Error>, auto_connect: bool) { let save_result = self.settings.set_auto_connect(auto_connect); match save_result { Ok(settings_changed) => { - Self::oneshot_send(tx, (), "set auto-connect response"); + Self::oneshot_send(tx, Ok(()), "set auto-connect response"); if settings_changed { self.event_listener .notify_settings(self.settings.to_settings()); } } - Err(e) => error!("{}", e.display_chain_with_msg("Unable to save settings")), + Err(e) => { + error!("{}", e.display_chain_with_msg("Unable to save settings")); + Self::oneshot_send(tx, Err(e), "set auto-connect response"); + } } } - fn on_set_openvpn_mssfix(&mut self, tx: oneshot::Sender<()>, mssfix_arg: Option<u16>) { + fn on_set_openvpn_mssfix( + &mut self, + tx: ResponseTx<(), settings::Error>, + mssfix_arg: Option<u16>, + ) { let save_result = self.settings.set_openvpn_mssfix(mssfix_arg); match save_result { Ok(settings_changed) => { - Self::oneshot_send(tx, (), "set_openvpn_mssfix response"); + Self::oneshot_send(tx, Ok(()), "set_openvpn_mssfix response"); if settings_changed { self.event_listener .notify_settings(self.settings.to_settings()); @@ -1674,13 +1739,16 @@ where } } } - Err(e) => error!("{}", e.display_chain_with_msg("Unable to save settings")), + Err(e) => { + error!("{}", e.display_chain_with_msg("Unable to save settings")); + Self::oneshot_send(tx, Err(e), "set_openvpn_mssfix response"); + } } } fn on_set_bridge_settings( &mut self, - tx: oneshot::Sender<Result<(), settings::Error>>, + tx: ResponseTx<(), settings::Error>, new_settings: BridgeSettings, ) { match self.settings.set_bridge_settings(new_settings) { @@ -1705,7 +1773,7 @@ where fn on_set_bridge_state( &mut self, - tx: oneshot::Sender<Result<(), settings::Error>>, + tx: ResponseTx<(), settings::Error>, bridge_state: BridgeState, ) { let result = match self.settings.set_bridge_state(bridge_state) { @@ -1730,11 +1798,11 @@ where } - fn on_set_enable_ipv6(&mut self, tx: oneshot::Sender<()>, enable_ipv6: bool) { + fn on_set_enable_ipv6(&mut self, tx: ResponseTx<(), settings::Error>, enable_ipv6: bool) { let save_result = self.settings.set_enable_ipv6(enable_ipv6); match save_result { Ok(settings_changed) => { - Self::oneshot_send(tx, (), "set_enable_ipv6 response"); + Self::oneshot_send(tx, Ok(()), "set_enable_ipv6 response"); if settings_changed { self.event_listener .notify_settings(self.settings.to_settings()); @@ -1742,15 +1810,18 @@ where self.reconnect_tunnel(); } } - Err(e) => error!("{}", e.display_chain_with_msg("Unable to save settings")), + Err(e) => { + error!("{}", e.display_chain_with_msg("Unable to save settings")); + Self::oneshot_send(tx, Err(e), "set_enable_ipv6 response"); + } } } - fn on_set_dns_options(&mut self, tx: oneshot::Sender<()>, dns_options: DnsOptions) { + fn on_set_dns_options(&mut self, tx: ResponseTx<(), settings::Error>, dns_options: DnsOptions) { let save_result = self.settings.set_dns_options(dns_options.clone()); match save_result { Ok(settings_changed) => { - Self::oneshot_send(tx, (), "set_dns_options response"); + Self::oneshot_send(tx, Ok(()), "set_dns_options response"); if settings_changed { let settings = self.settings.to_settings(); let resolvers = @@ -1759,15 +1830,18 @@ where self.send_tunnel_command(TunnelCommand::CustomDns(resolvers)); } } - Err(e) => error!("{}", e.display_chain_with_msg("Unable to save settings")), + Err(e) => { + error!("{}", e.display_chain_with_msg("Unable to save settings")); + Self::oneshot_send(tx, Err(e), "set_dns_options response"); + } } } - fn on_set_wireguard_mtu(&mut self, tx: oneshot::Sender<()>, mtu: Option<u16>) { + fn on_set_wireguard_mtu(&mut self, tx: ResponseTx<(), settings::Error>, mtu: Option<u16>) { let save_result = self.settings.set_wireguard_mtu(mtu); match save_result { Ok(settings_changed) => { - Self::oneshot_send(tx, (), "set_wireguard_mtu response"); + Self::oneshot_send(tx, Ok(()), "set_wireguard_mtu response"); if settings_changed { self.event_listener .notify_settings(self.settings.to_settings()); @@ -1779,26 +1853,32 @@ where } } } - Err(e) => error!("{}", e.display_chain_with_msg("Unable to save settings")), + Err(e) => { + error!("{}", e.display_chain_with_msg("Unable to save settings")); + Self::oneshot_send(tx, Err(e), "set_wireguard_mtu response"); + } } } async fn on_set_wireguard_rotation_interval( &mut self, - tx: oneshot::Sender<()>, + tx: ResponseTx<(), settings::Error>, interval: Option<u32>, ) { let save_result = self.settings.set_wireguard_rotation_interval(interval); match save_result { Ok(settings_changed) => { - Self::oneshot_send(tx, (), "set_wireguard_rotation_interval response"); + Self::oneshot_send(tx, Ok(()), "set_wireguard_rotation_interval response"); if settings_changed { self.ensure_key_rotation().await; self.event_listener .notify_settings(self.settings.to_settings()); } } - Err(e) => error!("{}", e.display_chain_with_msg("Unable to save settings")), + Err(e) => { + error!("{}", e.display_chain_with_msg("Unable to save settings")); + Self::oneshot_send(tx, Err(e), "set_wireguard_rotation_interval response"); + } } } @@ -1822,28 +1902,29 @@ where } } - async fn on_generate_wireguard_key(&mut self, tx: oneshot::Sender<KeygenEvent>) { + async fn on_generate_wireguard_key(&mut self, tx: ResponseTx<KeygenEvent, Error>) { match self.on_generate_wireguard_key_inner().await { Ok(key_event) => { - Self::oneshot_send(tx, key_event, "generate_wireguard_key response"); + Self::oneshot_send(tx, Ok(key_event), "generate_wireguard_key"); } Err(e) => { log::error!("Failed to generate new wireguard key - {}", e); + Self::oneshot_send(tx, Err(e), "generate_wireguard_key"); } } } - async fn on_generate_wireguard_key_inner(&mut self) -> Result<KeygenEvent, String> { + async fn on_generate_wireguard_key_inner(&mut self) -> Result<KeygenEvent, Error> { let account_token = self .settings .get_account_token() - .ok_or_else(|| "No account token set".to_owned())?; + .ok_or(Error::NoAccountToken)?; let mut account_entry = self .account_history .get(&account_token) .await - .map_err(|e| format!("Failed to read account entry from history: {}", e)) + .map_err(Error::AccountHistory) .map(|data| { data.unwrap_or_else(|| { log::error!("Account token set in settings but not in account history"); @@ -1874,9 +1955,7 @@ where self.account_history .insert(account_entry) .await - .map_err(|e| { - format!("Failed to add new wireguard key to account data: {}", e) - })?; + .map_err(Error::AccountHistory)?; if let Some(TunnelType::Wireguard) = self.get_target_tunnel_type() { self.reconnect_tunnel(); } @@ -1899,29 +1978,33 @@ where Ok(keygen_event) } Err(wireguard::Error::TooManyKeys) => Ok(KeygenEvent::TooManyKeys), - Err(e) => Err(format!( - "Failed to generate new key - {}", - e.display_chain_with_msg("Failed to generate new wireguard key:") - )), + Err(wireguard::Error::RestError(error)) => Err(Error::RestError(error)), } } - async fn on_get_wireguard_key(&mut self, tx: oneshot::Sender<Option<wireguard::PublicKey>>) { + async fn on_get_wireguard_key(&mut self, tx: ResponseTx<Option<wireguard::PublicKey>, Error>) { let token = self.settings.get_account_token(); - if let Some(token) = token { + let result = if let Some(token) = token { let entry = self.account_history.get(&token).await; - if let Ok(Some(entry)) = entry { - let key = entry.wireguard.map(|wg| wg.get_public_key()); - Self::oneshot_send(tx, key, "get_wireguard_key response"); + match entry { + Ok(Some(entry)) => { + let key = entry.wireguard.map(|wg| wg.get_public_key()); + Ok(key) + } + Ok(None) => Err(Error::NoAccountTokenHistory), + Err(error) => Err(Error::AccountHistory(error)), } - } + } else { + Err(Error::NoAccountToken) + }; + Self::oneshot_send(tx, result, "get_wireguard_key response"); } - async fn on_verify_wireguard_key(&mut self, tx: oneshot::Sender<bool>) { + async fn on_verify_wireguard_key(&mut self, tx: ResponseTx<bool, Error>) { let account = match self.settings.get_account_token() { Some(account) => account, None => { - Self::oneshot_send(tx, false, "verify_wireguard_key response"); + Self::oneshot_send(tx, Ok(false), "verify_wireguard_key response"); return; } }; @@ -1935,11 +2018,16 @@ where let public_key = match key { Ok(Some(public_key)) => public_key, Ok(None) => { - Self::oneshot_send(tx, false, "verify_wireguard_key response"); + Self::oneshot_send(tx, Ok(false), "verify_wireguard_key response"); return; } Err(e) => { log::error!("Failed to read key data: {}", e); + Self::oneshot_send( + tx, + Err(Error::AccountHistory(e)), + "verify_wireguard_key response", + ); return; } }; @@ -1949,14 +2037,12 @@ where .verify_wireguard_key(account, public_key); tokio::spawn(async move { - match verification_rpc.await { - Ok(is_valid) => { - Self::oneshot_send(tx, is_valid, "verify_wireguard_key response"); - } - Err(err) => { - log::error!("Failed to verify wireguard key - {}", err); - } - } + let result = match verification_rpc.await { + Ok(is_valid) => Ok(is_valid), + Err(wireguard::Error::RestError(error)) => Err(Error::RestError(error)), + Err(wireguard::Error::TooManyKeys) => return, + }; + Self::oneshot_send(tx, result, "verify_wireguard_key response"); }); } diff --git a/mullvad-daemon/src/management_interface.rs b/mullvad-daemon/src/management_interface.rs index 03f1aab77c..907ae268b5 100644 --- a/mullvad-daemon/src/management_interface.rs +++ b/mullvad-daemon/src/management_interface.rs @@ -1,4 +1,4 @@ -use crate::{settings, DaemonCommand, DaemonCommandSender, EventListener}; +use crate::{account_history, settings, DaemonCommand, DaemonCommandSender, EventListener}; use futures::channel::oneshot; use mullvad_management_interface::{ types::{self, daemon_event, management_service_server::ManagementService}, @@ -126,8 +126,10 @@ impl ManagementService for ManagementServiceImpl { log::debug!("factory_reset"); let (tx, rx) = oneshot::channel(); self.send_command_to_daemon(DaemonCommand::FactoryReset(tx))?; - let _ = self.wait_for_result(rx).await?; - Ok(Response::new(())) + self.wait_for_result(rx) + .await? + .map(Response::new) + .map_err(map_daemon_error) } #[cfg(target_os = "android")] { @@ -174,7 +176,10 @@ impl ManagementService for ManagementServiceImpl { let message = DaemonCommand::UpdateRelaySettings(tx, constraints_update); self.send_command_to_daemon(message)?; - self.wait_for_result(rx).await.map(Response::new) + self.wait_for_result(rx) + .await? + .map(Response::new) + .map_err(map_settings_error) } async fn get_relay_locations( @@ -333,7 +338,10 @@ impl ManagementService for ManagementServiceImpl { log::debug!("set_allow_lan({})", allow_lan); let (tx, rx) = oneshot::channel(); self.send_command_to_daemon(DaemonCommand::SetAllowLan(tx, allow_lan))?; - self.wait_for_result(rx).await.map(Response::new) + self.wait_for_result(rx) + .await? + .map(Response::new) + .map_err(map_settings_error) } async fn set_show_beta_releases(&self, request: Request<bool>) -> ServiceResult<()> { @@ -341,7 +349,10 @@ impl ManagementService for ManagementServiceImpl { log::debug!("set_show_beta_releases({})", enabled); let (tx, rx) = oneshot::channel(); self.send_command_to_daemon(DaemonCommand::SetShowBetaReleases(tx, enabled))?; - self.wait_for_result(rx).await.map(Response::new) + self.wait_for_result(rx) + .await? + .map(Response::new) + .map_err(map_settings_error) } async fn set_block_when_disconnected(&self, request: Request<bool>) -> ServiceResult<()> { @@ -352,7 +363,10 @@ impl ManagementService for ManagementServiceImpl { tx, block_when_disconnected, ))?; - self.wait_for_result(rx).await.map(Response::new) + self.wait_for_result(rx) + .await? + .map(Response::new) + .map_err(map_settings_error) } async fn set_auto_connect(&self, request: Request<bool>) -> ServiceResult<()> { @@ -360,7 +374,10 @@ impl ManagementService for ManagementServiceImpl { log::debug!("set_auto_connect({})", auto_connect); let (tx, rx) = oneshot::channel(); self.send_command_to_daemon(DaemonCommand::SetAutoConnect(tx, auto_connect))?; - self.wait_for_result(rx).await.map(Response::new) + self.wait_for_result(rx) + .await? + .map(Response::new) + .map_err(map_settings_error) } async fn set_openvpn_mssfix(&self, request: Request<u32>) -> ServiceResult<()> { @@ -373,7 +390,10 @@ impl ManagementService for ManagementServiceImpl { log::debug!("set_openvpn_mssfix({:?})", mssfix); let (tx, rx) = oneshot::channel(); self.send_command_to_daemon(DaemonCommand::SetOpenVpnMssfix(tx, mssfix))?; - self.wait_for_result(rx).await.map(Response::new) + self.wait_for_result(rx) + .await? + .map(Response::new) + .map_err(map_settings_error) } async fn set_wireguard_mtu(&self, request: Request<u32>) -> ServiceResult<()> { @@ -382,7 +402,10 @@ impl ManagementService for ManagementServiceImpl { log::debug!("set_wireguard_mtu({:?})", mtu); let (tx, rx) = oneshot::channel(); self.send_command_to_daemon(DaemonCommand::SetWireguardMtu(tx, mtu))?; - self.wait_for_result(rx).await.map(Response::new) + self.wait_for_result(rx) + .await? + .map(Response::new) + .map_err(map_settings_error) } async fn set_enable_ipv6(&self, request: Request<bool>) -> ServiceResult<()> { @@ -390,7 +413,10 @@ impl ManagementService for ManagementServiceImpl { log::debug!("set_enable_ipv6({})", enable_ipv6); let (tx, rx) = oneshot::channel(); self.send_command_to_daemon(DaemonCommand::SetEnableIpv6(tx, enable_ipv6))?; - self.wait_for_result(rx).await.map(Response::new) + self.wait_for_result(rx) + .await? + .map(Response::new) + .map_err(map_settings_error) } #[cfg(not(target_os = "android"))] @@ -420,7 +446,10 @@ impl ManagementService for ManagementServiceImpl { addresses: servers_ip, }, ))?; - self.wait_for_result(rx).await.map(Response::new) + self.wait_for_result(rx) + .await? + .map(Response::new) + .map_err(map_settings_error) } #[cfg(target_os = "android")] async fn set_dns_options(&self, _: Request<types::DnsOptions>) -> ServiceResult<()> { @@ -436,7 +465,7 @@ impl ManagementService for ManagementServiceImpl { self.wait_for_result(rx) .await? .map(Response::new) - .map_err(map_rest_error) + .map_err(map_daemon_error) } async fn set_account(&self, request: Request<AccountToken>) -> ServiceResult<()> { @@ -449,7 +478,10 @@ impl ManagementService for ManagementServiceImpl { }; let (tx, rx) = oneshot::channel(); self.send_command_to_daemon(DaemonCommand::SetAccount(tx, account_token))?; - self.wait_for_result(rx).await.map(Response::new) + self.wait_for_result(rx) + .await? + .map(Response::new) + .map_err(map_settings_error) } async fn get_account_data( @@ -497,14 +529,20 @@ impl ManagementService for ManagementServiceImpl { let account_token = request.into_inner(); let (tx, rx) = oneshot::channel(); self.send_command_to_daemon(DaemonCommand::RemoveAccountFromHistory(tx, account_token))?; - self.wait_for_result(rx).await.map(Response::new) + self.wait_for_result(rx) + .await? + .map(Response::new) + .map_err(map_daemon_error) } async fn clear_account_history(&self, _: Request<()>) -> ServiceResult<()> { log::debug!("clear_account_history"); let (tx, rx) = oneshot::channel(); self.send_command_to_daemon(DaemonCommand::ClearAccountHistory(tx))?; - self.wait_for_result(rx).await.map(Response::new) + self.wait_for_result(rx) + .await? + .map(Response::new) + .map_err(map_daemon_error) } async fn get_www_auth_token(&self, _: Request<()>) -> ServiceResult<String> { @@ -512,12 +550,12 @@ impl ManagementService for ManagementServiceImpl { let (tx, rx) = oneshot::channel(); self.send_command_to_daemon(DaemonCommand::GetWwwAuthToken(tx))?; let result = self.wait_for_result(rx).await?; - result.map(Response::new).map_err(|error: RestError| { + result.map(Response::new).map_err(|error| { log::error!( "Unable to get account data from API: {}", error.display_chain() ); - map_rest_error(error) + map_daemon_error(error) }) } @@ -540,7 +578,10 @@ impl ManagementService for ManagementServiceImpl { }), }) }) - .map_err(map_rest_voucher_error) + .map_err(|error| match error { + crate::Error::RestError(error) => map_rest_voucher_error(error), + error => map_daemon_error(error), + }) } // WireGuard key management @@ -555,14 +596,20 @@ impl ManagementService for ManagementServiceImpl { tx, Some(interval), ))?; - self.wait_for_result(rx).await.map(Response::new) + self.wait_for_result(rx) + .await? + .map(Response::new) + .map_err(map_settings_error) } async fn reset_wireguard_rotation_interval(&self, _: Request<()>) -> ServiceResult<()> { log::debug!("reset_wireguard_rotation_interval"); let (tx, rx) = oneshot::channel(); self.send_command_to_daemon(DaemonCommand::SetWireguardRotationInterval(tx, None))?; - self.wait_for_result(rx).await.map(Response::new) + self.wait_for_result(rx) + .await? + .map(Response::new) + .map_err(map_settings_error) } async fn generate_wireguard_key(&self, _: Request<()>) -> ServiceResult<types::KeygenEvent> { @@ -572,15 +619,16 @@ impl ManagementService for ManagementServiceImpl { let (tx, rx) = oneshot::channel(); self.send_command_to_daemon(DaemonCommand::GenerateWireguardKey(tx))?; self.wait_for_result(rx) - .await + .await? .map(|event| Response::new(convert_wireguard_key_event(&event))) + .map_err(map_daemon_error) } async fn get_wireguard_key(&self, _: Request<()>) -> ServiceResult<types::PublicKey> { log::debug!("get_wireguard_key"); let (tx, rx) = oneshot::channel(); self.send_command_to_daemon(DaemonCommand::GetWireguardKey(tx))?; - let key = self.wait_for_result(rx).await?; + let key = self.wait_for_result(rx).await?.map_err(map_daemon_error)?; match key { Some(key) => Ok(Response::new(convert_public_key(&key))), None => Err(Status::not_found("no WireGuard key was found")), @@ -591,7 +639,10 @@ impl ManagementService for ManagementServiceImpl { log::debug!("verify_wireguard_key"); let (tx, rx) = oneshot::channel(); self.send_command_to_daemon(DaemonCommand::VerifyWireguardKey(tx))?; - self.wait_for_result(rx).await.map(Response::new) + self.wait_for_result(rx) + .await? + .map(Response::new) + .map_err(map_daemon_error) } // Split tunneling @@ -606,7 +657,10 @@ impl ManagementService for ManagementServiceImpl { log::debug!("get_split_tunnel_processes"); let (tx, rx) = oneshot::channel(); self.send_command_to_daemon(DaemonCommand::GetSplitTunnelProcesses(tx))?; - let pids = self.wait_for_result(rx).await?; + let pids = self + .wait_for_result(rx) + .await? + .map_err(|error| Status::failed_precondition(error.display_chain()))?; let (tx, rx) = tokio::sync::mpsc::unbounded_channel(); tokio::spawn(async move { @@ -630,7 +684,10 @@ impl ManagementService for ManagementServiceImpl { log::debug!("add_split_tunnel_process"); let (tx, rx) = oneshot::channel(); self.send_command_to_daemon(DaemonCommand::AddSplitTunnelProcess(tx, pid))?; - self.wait_for_result(rx).await.map(Response::new) + self.wait_for_result(rx) + .await? + .map_err(|error| Status::failed_precondition(error.display_chain()))?; + Ok(Response::new(())) } #[cfg(not(target_os = "linux"))] async fn add_split_tunnel_process(&self, _: Request<i32>) -> ServiceResult<()> { @@ -643,7 +700,10 @@ impl ManagementService for ManagementServiceImpl { log::debug!("remove_split_tunnel_process"); let (tx, rx) = oneshot::channel(); self.send_command_to_daemon(DaemonCommand::RemoveSplitTunnelProcess(tx, pid))?; - self.wait_for_result(rx).await.map(Response::new) + self.wait_for_result(rx) + .await? + .map_err(|error| Status::failed_precondition(error.display_chain()))?; + Ok(Response::new(())) } #[cfg(not(target_os = "linux"))] async fn remove_split_tunnel_process(&self, _: Request<i32>) -> ServiceResult<()> { @@ -656,7 +716,10 @@ impl ManagementService for ManagementServiceImpl { log::debug!("clear_split_tunnel_processes"); let (tx, rx) = oneshot::channel(); self.send_command_to_daemon(DaemonCommand::ClearSplitTunnelProcesses(tx))?; - self.wait_for_result(rx).await.map(Response::new) + self.wait_for_result(rx) + .await? + .map_err(|error| Status::failed_precondition(error.display_chain()))?; + Ok(Response::new(())) } #[cfg(not(target_os = "linux"))] { @@ -674,8 +737,7 @@ impl ManagementServiceImpl { } async fn wait_for_result<T>(&self, rx: oneshot::Receiver<T>) -> Result<T, Status> { - rx.await - .map_err(|_| Status::internal("the channel was dropped by the daemon")) + rx.await.map_err(|_| Status::internal("sender was dropped")) } } @@ -1568,6 +1630,21 @@ impl Drop for ManagementInterfaceEventBroadcaster { } } +/// Converts [`mullvad_daemon::Error`] into a tonic status. +fn map_daemon_error(error: crate::Error) -> Status { + use crate::Error as DaemonError; + + match error { + DaemonError::RestError(error) => map_rest_error(error), + DaemonError::SettingsError(error) => map_settings_error(error), + DaemonError::AccountHistory(error) => map_account_history_error(error), + DaemonError::NoAccountToken | DaemonError::NoAccountTokenHistory => { + Status::unauthenticated(error.display_chain()) + } + error => Status::unknown(error.display_chain()), + } +} + /// Converts a REST API voucher error into a tonic status. fn map_rest_voucher_error(error: RestError) -> Status { match error { @@ -1606,3 +1683,15 @@ fn map_settings_error(error: settings::Error) -> Status { settings::Error::SerializeError(..) => Status::new(Code::Internal, error.display_chain()), } } + +/// Converts an instance of [`mullvad_daemon::account_history::Error`] into a tonic status. +fn map_account_history_error(error: account_history::Error) -> Status { + match error { + account_history::Error::Read(..) | account_history::Error::Write(..) => { + Status::new(Code::FailedPrecondition, error.display_chain()) + } + account_history::Error::Serialize(..) | account_history::Error::WriteCancelled(..) => { + Status::new(Code::Internal, error.display_chain()) + } + } +} |
