summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorDavid Lönnhager <david.l@mullvad.net>2021-01-18 17:47:12 +0100
committerDavid Lönnhager <david.l@mullvad.net>2021-01-28 13:22:28 +0100
commitc04b432cd2a457b6180279a2156d3bd9ff761bd0 (patch)
tree85899123a25066d8b0dc4e73fcf8666b84a7e9a0
parent1cf0d2659f16c4124f179f2f9ad8edb2cd842a22 (diff)
downloadmullvadvpn-c04b432cd2a457b6180279a2156d3bd9ff761bd0.tar.xz
mullvadvpn-c04b432cd2a457b6180279a2156d3bd9ff761bd0.zip
Propagate more errors to the management interface
-rw-r--r--mullvad-daemon/src/lib.rs398
-rw-r--r--mullvad-daemon/src/management_interface.rs149
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())
+ }
+ }
+}