diff options
| author | Linus Färnstrand <linus@mullvad.net> | 2018-11-13 06:16:48 +0100 |
|---|---|---|
| committer | Linus Färnstrand <linus@mullvad.net> | 2018-11-13 13:34:09 +0100 |
| commit | f048c66ab3672b32098158f97a56ac6a0717c976 (patch) | |
| tree | a6aee9db2e37a9a723ca1f2140e8bedf96ba0c16 | |
| parent | e59ac7a68a5cdda11d82b4a69ad33fddd3b3d294 (diff) | |
| download | mullvadvpn-f048c66ab3672b32098158f97a56ac6a0717c976.tar.xz mullvadvpn-f048c66ab3672b32098158f97a56ac6a0717c976.zip | |
Add block_on_disconnected setting, for never unblocking the firewall
| -rw-r--r-- | mullvad-daemon/src/lib.rs | 27 | ||||
| -rw-r--r-- | mullvad-daemon/src/management_interface.rs | 22 | ||||
| -rw-r--r-- | mullvad-ipc-client/src/lib.rs | 4 | ||||
| -rw-r--r-- | mullvad-types/src/settings.rs | 17 | ||||
| -rw-r--r-- | talpid-core/src/tunnel_state_machine/blocked_state.rs | 4 | ||||
| -rw-r--r-- | talpid-core/src/tunnel_state_machine/connected_state.rs | 4 | ||||
| -rw-r--r-- | talpid-core/src/tunnel_state_machine/connecting_state.rs | 4 | ||||
| -rw-r--r-- | talpid-core/src/tunnel_state_machine/disconnected_state.rs | 41 | ||||
| -rw-r--r-- | talpid-core/src/tunnel_state_machine/disconnecting_state.rs | 12 | ||||
| -rw-r--r-- | talpid-core/src/tunnel_state_machine/mod.rs | 10 |
10 files changed, 137 insertions, 8 deletions
diff --git a/mullvad-daemon/src/lib.rs b/mullvad-daemon/src/lib.rs index f420afdff2..b5ef9dd21e 100644 --- a/mullvad-daemon/src/lib.rs +++ b/mullvad-daemon/src/lib.rs @@ -220,6 +220,7 @@ impl Daemon { let tunnel_parameters_generator = MullvadTunnelParametersGenerator { tx: tx.clone() }; let tunnel_command_tx = tunnel_state_machine::spawn( settings.get_allow_lan(), + settings.get_block_when_disconnected(), tunnel_parameters_generator, log_dir, resource_dir, @@ -423,6 +424,9 @@ impl Daemon { SetAccount(tx, account_token) => self.on_set_account(tx, account_token), UpdateRelaySettings(tx, update) => self.on_update_relay_settings(tx, update), SetAllowLan(tx, allow_lan) => self.on_set_allow_lan(tx, allow_lan), + SetBlockWhenDisconnected(tx, block_when_disconnected) => { + self.on_set_block_when_disconnected(tx, block_when_disconnected) + } SetAutoConnect(tx, auto_connect) => self.on_set_auto_connect(tx, auto_connect), SetOpenVpnMssfix(tx, mssfix_arg) => self.on_set_openvpn_mssfix(tx, mssfix_arg), SetOpenVpnProxy(tx, proxy) => self.on_set_openvpn_proxy(tx, proxy), @@ -601,6 +605,29 @@ impl Daemon { } } + fn on_set_block_when_disconnected( + &mut self, + tx: oneshot::Sender<()>, + block_when_disconnected: bool, + ) { + let save_result = self + .settings + .set_block_when_disconnected(block_when_disconnected); + match save_result.chain_err(|| "Unable to save settings") { + Ok(settings_changed) => { + Self::oneshot_send(tx, (), "set_block_when_disconnected response"); + if settings_changed { + self.management_interface_broadcaster + .notify_settings(&self.settings); + self.send_tunnel_command(TunnelCommand::BlockWhenDisconnected( + block_when_disconnected, + )); + } + } + Err(e) => error!("{}", e.display_chain()), + } + } + fn on_set_auto_connect(&mut self, tx: oneshot::Sender<()>, auto_connect: bool) { let save_result = self.settings.set_auto_connect(auto_connect); match save_result.chain_err(|| "Unable to save settings") { diff --git a/mullvad-daemon/src/management_interface.rs b/mullvad-daemon/src/management_interface.rs index d306e4c33f..f9eb8ffa63 100644 --- a/mullvad-daemon/src/management_interface.rs +++ b/mullvad-daemon/src/management_interface.rs @@ -65,6 +65,10 @@ build_rpc_trait! { #[rpc(meta, name = "set_allow_lan")] fn set_allow_lan(&self, Self::Metadata, bool) -> BoxFuture<(), Error>; + /// Set if the client should allow network communication when in the disconnected state. + #[rpc(meta, name = "set_block_when_disconnected")] + fn set_block_when_disconnected(&self, Self::Metadata, bool) -> BoxFuture<(), Error>; + /// Set if the daemon should automatically establish a tunnel on start or not. #[rpc(meta, name = "set_auto_connect")] fn set_auto_connect(&self, Self::Metadata, bool) -> BoxFuture<(), Error>; @@ -176,6 +180,8 @@ pub enum ManagementCommand { UpdateRelaySettings(OneshotSender<()>, RelaySettingsUpdate), /// Set the allow LAN setting. SetAllowLan(OneshotSender<()>, bool), + /// Set the block_when_disconnected setting. + SetBlockWhenDisconnected(OneshotSender<()>, bool), /// Set the auto-connect setting. SetAutoConnect(OneshotSender<()>, bool), /// Set the mssfix argument for OpenVPN @@ -455,6 +461,22 @@ impl<T: From<ManagementCommand> + 'static + Send> ManagementInterfaceApi Box::new(future) } + fn set_block_when_disconnected( + &self, + _: Self::Metadata, + block_when_disconnected: bool, + ) -> BoxFuture<(), Error> { + log::debug!("set_block_when_disconnected({})", block_when_disconnected); + let (tx, rx) = sync::oneshot::channel(); + let future = self + .send_command_to_daemon(ManagementCommand::SetBlockWhenDisconnected( + tx, + block_when_disconnected, + )) + .and_then(|_| rx.map_err(|_| Error::internal_error())); + Box::new(future) + } + fn set_auto_connect(&self, _: Self::Metadata, auto_connect: bool) -> BoxFuture<(), Error> { log::debug!("set_auto_connect({})", auto_connect); let (tx, rx) = sync::oneshot::channel(); diff --git a/mullvad-ipc-client/src/lib.rs b/mullvad-ipc-client/src/lib.rs index c38f6d4fc1..7f2c6a17c1 100644 --- a/mullvad-ipc-client/src/lib.rs +++ b/mullvad-ipc-client/src/lib.rs @@ -143,6 +143,10 @@ impl DaemonRpcClient { self.call("set_allow_lan", &[allow_lan]) } + pub fn set_block_when_disconnected(&mut self, block_when_disconnected: bool) -> Result<()> { + self.call("set_block_when_disconnected", &[block_when_disconnected]) + } + pub fn get_allow_lan(&mut self) -> Result<bool> { self.call("get_allow_lan", &NO_ARGS) } diff --git a/mullvad-types/src/settings.rs b/mullvad-types/src/settings.rs index 15e336dae4..a6a1b95e2c 100644 --- a/mullvad-types/src/settings.rs +++ b/mullvad-types/src/settings.rs @@ -44,6 +44,9 @@ pub struct Settings { relay_settings: RelaySettings, /// If the daemon should allow communication with private (LAN) networks. allow_lan: bool, + /// Extra level of kill switch. When this setting is on, the disconnected state will block + /// the firewall to not allow any traffic in or out. + block_when_disconnected: bool, /// If the daemon should connect the VPN tunnel directly on start or not. auto_connect: bool, /// Options that should be applied to tunnels of a specific type regardless of where the relays @@ -60,6 +63,7 @@ impl Default for Settings { tunnel: Constraint::Any, }), allow_lan: false, + block_when_disconnected: false, auto_connect: false, tunnel_options: TunnelOptions::default(), } @@ -165,6 +169,19 @@ impl Settings { } } + pub fn get_block_when_disconnected(&self) -> bool { + self.block_when_disconnected + } + + pub fn set_block_when_disconnected(&mut self, block_when_disconnected: bool) -> Result<bool> { + if block_when_disconnected != self.block_when_disconnected { + self.block_when_disconnected = block_when_disconnected; + self.save().map(|_| true) + } else { + Ok(false) + } + } + pub fn get_auto_connect(&self) -> bool { self.auto_connect } diff --git a/talpid-core/src/tunnel_state_machine/blocked_state.rs b/talpid-core/src/tunnel_state_machine/blocked_state.rs index 3e63551110..14b72a20f8 100644 --- a/talpid-core/src/tunnel_state_machine/blocked_state.rs +++ b/talpid-core/src/tunnel_state_machine/blocked_state.rs @@ -58,6 +58,10 @@ impl TunnelState for BlockedState { Self::set_security_policy(shared_values); SameState(self) } + Ok(TunnelCommand::BlockWhenDisconnected(block_when_disconnected)) => { + shared_values.block_when_disconnected = block_when_disconnected; + SameState(self) + } Ok(TunnelCommand::IsOffline(is_offline)) => { shared_values.is_offline = is_offline; if !is_offline && self.block_reason == BlockReason::IsOffline { diff --git a/talpid-core/src/tunnel_state_machine/connected_state.rs b/talpid-core/src/tunnel_state_machine/connected_state.rs index 577f435260..fa6735f145 100644 --- a/talpid-core/src/tunnel_state_machine/connected_state.rs +++ b/talpid-core/src/tunnel_state_machine/connected_state.rs @@ -94,6 +94,10 @@ impl ConnectedState { } } } + Ok(TunnelCommand::BlockWhenDisconnected(block_when_disconnected)) => { + shared_values.block_when_disconnected = block_when_disconnected; + SameState(self) + } Ok(TunnelCommand::IsOffline(is_offline)) => { shared_values.is_offline = is_offline; if is_offline { diff --git a/talpid-core/src/tunnel_state_machine/connecting_state.rs b/talpid-core/src/tunnel_state_machine/connecting_state.rs index df0a00744e..e4d81dd51e 100644 --- a/talpid-core/src/tunnel_state_machine/connecting_state.rs +++ b/talpid-core/src/tunnel_state_machine/connecting_state.rs @@ -211,6 +211,10 @@ impl ConnectingState { } } } + Ok(TunnelCommand::BlockWhenDisconnected(block_when_disconnected)) => { + shared_values.block_when_disconnected = block_when_disconnected; + SameState(self) + } Ok(TunnelCommand::IsOffline(is_offline)) => { shared_values.is_offline = is_offline; if is_offline { diff --git a/talpid-core/src/tunnel_state_machine/disconnected_state.rs b/talpid-core/src/tunnel_state_machine/disconnected_state.rs index 60444e9cc7..643395931f 100644 --- a/talpid-core/src/tunnel_state_machine/disconnected_state.rs +++ b/talpid-core/src/tunnel_state_machine/disconnected_state.rs @@ -1,7 +1,8 @@ use super::{ - BlockedState, ConnectingState, Error, EventConsequence, SharedTunnelStateValues, TunnelCommand, - TunnelState, TunnelStateTransition, TunnelStateWrapper, + BlockedState, ConnectingState, EventConsequence, ResultExt, SharedTunnelStateValues, + TunnelCommand, TunnelState, TunnelStateTransition, TunnelStateWrapper, }; +use crate::security::SecurityPolicy; use error_chain::ChainedError; use futures::sync::mpsc; use futures::Stream; @@ -10,10 +11,23 @@ use futures::Stream; pub struct DisconnectedState; impl DisconnectedState { - fn reset_security_policy(shared_values: &mut SharedTunnelStateValues) { - if let Err(error) = shared_values.security.reset_policy() { - let chained_error = Error::with_chain(error, "Failed to reset security policy"); - log::error!("{}", chained_error.display_chain()); + fn set_security_policy(shared_values: &mut SharedTunnelStateValues) { + let result = if shared_values.block_when_disconnected { + let policy = SecurityPolicy::Blocked { + allow_lan: shared_values.allow_lan, + }; + shared_values + .security + .apply_policy(policy) + .chain_err(|| "Failed to apply blocking security policy for disconnected state") + } else { + shared_values + .security + .reset_policy() + .chain_err(|| "Failed to reset security policy") + }; + if let Err(error) = result { + log::error!("{}", error.display_chain()); } } } @@ -25,8 +39,7 @@ impl TunnelState for DisconnectedState { shared_values: &mut SharedTunnelStateValues, _: Self::Bootstrap, ) -> (TunnelStateWrapper, TunnelStateTransition) { - Self::reset_security_policy(shared_values); - + Self::set_security_policy(shared_values); ( TunnelStateWrapper::from(DisconnectedState), TunnelStateTransition::Disconnected, @@ -42,7 +55,19 @@ impl TunnelState for DisconnectedState { match try_handle_event!(self, commands.poll()) { Ok(TunnelCommand::AllowLan(allow_lan)) => { + let changed = shared_values.allow_lan != allow_lan; shared_values.allow_lan = allow_lan; + if changed { + Self::set_security_policy(shared_values); + } + SameState(self) + } + Ok(TunnelCommand::BlockWhenDisconnected(block_when_disconnected)) => { + let changed = shared_values.block_when_disconnected != block_when_disconnected; + shared_values.block_when_disconnected = block_when_disconnected; + if changed { + Self::set_security_policy(shared_values); + } SameState(self) } Ok(TunnelCommand::IsOffline(is_offline)) => { diff --git a/talpid-core/src/tunnel_state_machine/disconnecting_state.rs b/talpid-core/src/tunnel_state_machine/disconnecting_state.rs index 7ebb637d2d..928880f274 100644 --- a/talpid-core/src/tunnel_state_machine/disconnecting_state.rs +++ b/talpid-core/src/tunnel_state_machine/disconnecting_state.rs @@ -33,6 +33,10 @@ impl DisconnectingState { shared_values.allow_lan = allow_lan; AfterDisconnect::Nothing } + Ok(TunnelCommand::BlockWhenDisconnected(block_when_disconnected)) => { + shared_values.block_when_disconnected = block_when_disconnected; + AfterDisconnect::Nothing + } Ok(TunnelCommand::IsOffline(is_offline)) => { shared_values.is_offline = is_offline; AfterDisconnect::Nothing @@ -46,6 +50,10 @@ impl DisconnectingState { shared_values.allow_lan = allow_lan; AfterDisconnect::Block(reason) } + Ok(TunnelCommand::BlockWhenDisconnected(block_when_disconnected)) => { + shared_values.block_when_disconnected = block_when_disconnected; + AfterDisconnect::Block(reason) + } Ok(TunnelCommand::IsOffline(is_offline)) => { shared_values.is_offline = is_offline; if !is_offline && reason == BlockReason::IsOffline { @@ -64,6 +72,10 @@ impl DisconnectingState { shared_values.allow_lan = allow_lan; AfterDisconnect::Reconnect(retry_attempt) } + Ok(TunnelCommand::BlockWhenDisconnected(block_when_disconnected)) => { + shared_values.block_when_disconnected = block_when_disconnected; + AfterDisconnect::Reconnect(retry_attempt) + } Ok(TunnelCommand::IsOffline(is_offline)) => { shared_values.is_offline = is_offline; if is_offline { diff --git a/talpid-core/src/tunnel_state_machine/mod.rs b/talpid-core/src/tunnel_state_machine/mod.rs index e44ec91234..d952e458f2 100644 --- a/talpid-core/src/tunnel_state_machine/mod.rs +++ b/talpid-core/src/tunnel_state_machine/mod.rs @@ -43,6 +43,7 @@ error_chain! { /// Spawn the tunnel state machine thread, returning a channel for sending tunnel commands. pub fn spawn<P, T>( allow_lan: bool, + block_when_disconnected: bool, tunnel_parameters_generator: impl TunnelParametersGenerator, log_dir: Option<PathBuf>, resource_dir: PathBuf, @@ -62,6 +63,7 @@ where thread::spawn(move || { match create_event_loop( allow_lan, + block_when_disconnected, is_offline, tunnel_parameters_generator, log_dir, @@ -97,6 +99,7 @@ where fn create_event_loop<T>( allow_lan: bool, + block_when_disconnected: bool, is_offline: bool, tunnel_parameters_generator: impl TunnelParametersGenerator, log_dir: Option<PathBuf>, @@ -111,6 +114,7 @@ where let reactor = Core::new().chain_err(|| ErrorKind::ReactorError)?; let state_machine = TunnelStateMachine::new( allow_lan, + block_when_disconnected, is_offline, tunnel_parameters_generator, log_dir, @@ -132,6 +136,8 @@ where pub enum TunnelCommand { /// Enable or disable LAN access in the firewall. AllowLan(bool), + /// Enable or disable the block_when_disconnected feature. + BlockWhenDisconnected(bool), /// Notify the state machine of the connectivity of the device. IsOffline(bool), /// Open tunnel connection. @@ -168,6 +174,7 @@ struct TunnelStateMachine { impl TunnelStateMachine { fn new( allow_lan: bool, + block_when_disconnected: bool, is_offline: bool, tunnel_parameters_generator: impl TunnelParametersGenerator, log_dir: Option<PathBuf>, @@ -180,6 +187,7 @@ impl TunnelStateMachine { let mut shared_values = SharedTunnelStateValues { security, allow_lan, + block_when_disconnected, is_offline, tunnel_parameters_generator: Box::new(tunnel_parameters_generator), log_dir, @@ -258,6 +266,8 @@ struct SharedTunnelStateValues { security: NetworkSecurity, /// Should LAN access be allowed outside the tunnel. allow_lan: bool, + /// Should network access be allowed when in the disconnected state. + block_when_disconnected: bool, /// True when the computer is known to be offline. is_offline: bool, /// The generator of new `TunnelParameter`s |
