Skip to content

Commit

Permalink
Merge branch 'cli_satus_lockdown'
Browse files Browse the repository at this point in the history
  • Loading branch information
MarkusPettersson98 committed Jan 18, 2024
2 parents df2c420 + 0a43e6f commit 8f8e8c4
Show file tree
Hide file tree
Showing 13 changed files with 219 additions and 46 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ Line wrap the file at 100 chars. Th
- Respect OS prefer-reduced-motion setting
- Add CLI command for exporting settings patches: `mullvad export-settings`. Currently, it generates
a patch containing all patchable settings, which only includes relay IP overrides.
- Make `mullvad status` prints if lockdown mode is enabled when disconnected.

#### Android
- Add support for all screen orientations.
Expand Down
30 changes: 21 additions & 9 deletions mullvad-cli/src/cmds/status.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,25 @@ impl Status {
println!("New tunnel state: {new_state:#?}");
} else {
// When we enter the connected or disconnected state, am.i.mullvad.net will
// be polled to get IP information. When it arrives, we will get another
// tunnel state of the same enum type, but with the IP filled in. This
// match statement checks for duplicate tunnel states and skips the second
// print to avoid spamming the user.
// be polled to get exit location. When it arrives, we will get another
// tunnel state of the same enum type, but with the location filled in. This
// match statement checks if the new state is an updated version of the old
// one and if so skips the print to avoid spamming the user. Note that for
// graphical frontends updating the drawn state with an identical one is
// invisible, so this is only an issue for the CLI.
match (&previous_tunnel_state, &new_state) {
(Some(TunnelState::Disconnected(_)), TunnelState::Disconnected(_))
| (
(
Some(TunnelState::Disconnected {
location: _,
locked_down: was_locked_down,
}),
TunnelState::Disconnected {
location: _,
locked_down,
},
// Do print an updated state if the lockdown setting was changed
) if was_locked_down == locked_down => continue,
(
Some(TunnelState::Connected { .. }),
TunnelState::Connected { .. },
) => continue,
Expand Down Expand Up @@ -91,7 +103,7 @@ pub async fn handle(cmd: Option<Status>, args: StatusArgs) -> Result<()> {
let state = rpc.get_tunnel_state().await?;
let device = rpc.get_device().await?;

print_account_loggedout(&state, &device);
print_account_logged_out(&state, &device);

if args.debug {
println!("Tunnel state: {state:#?}");
Expand All @@ -106,7 +118,7 @@ pub async fn handle(cmd: Option<Status>, args: StatusArgs) -> Result<()> {
Ok(())
}

fn print_account_loggedout(state: &TunnelState, device: &DeviceState) {
fn print_account_logged_out(state: &TunnelState, device: &DeviceState) {
match state {
TunnelState::Connecting { .. } | TunnelState::Connected { .. } | TunnelState::Error(_) => {
match device {
Expand All @@ -117,6 +129,6 @@ fn print_account_loggedout(state: &TunnelState, device: &DeviceState) {
DeviceState::LoggedIn(_) => (),
}
}
TunnelState::Disconnected(_) | TunnelState::Disconnecting(_) => (),
TunnelState::Disconnected { .. } | TunnelState::Disconnecting(_) => (),
}
}
16 changes: 13 additions & 3 deletions mullvad-cli/src/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,26 @@ pub fn print_state(state: &TunnelState, verbose: bool) {
format_relay_connection(endpoint, location.as_ref(), verbose)
);
}
Disconnected(_) => {
println!("Disconnected");
Disconnected {
location: _,
locked_down,
} => {
if *locked_down {
println!("Disconnected (Internet access is blocked due to lockdown mode)");
} else {
println!("Disconnected");
}
}
Disconnecting(_) => println!("Disconnecting..."),
}
}

pub fn print_location(state: &TunnelState) {
let location = match state {
TunnelState::Disconnected(location) => location,
TunnelState::Disconnected {
location,
locked_down: _,
} => location,
TunnelState::Connected { location, .. } => location,
_ => return,
};
Expand Down
2 changes: 1 addition & 1 deletion mullvad-daemon/src/device/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1282,7 +1282,7 @@ impl TunnelStateChangeHandler {
}
TunnelStateTransition::Error(_)
| TunnelStateTransition::Connected(_)
| TunnelStateTransition::Disconnected => 0,
| TunnelStateTransition::Disconnected { .. } => 0,
_ => retry_attempt,
}
}
Expand Down
25 changes: 17 additions & 8 deletions mullvad-daemon/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,7 @@ impl DaemonExecutionState {
match self {
Running => {
match tunnel_state {
TunnelState::Disconnected(_) => mem::replace(self, Finished),
TunnelState::Disconnected { .. } => mem::replace(self, Finished),
_ => mem::replace(self, Exiting),
};
}
Expand Down Expand Up @@ -856,7 +856,10 @@ where
);

let daemon = Daemon {
tunnel_state: TunnelState::Disconnected(None),
tunnel_state: TunnelState::Disconnected {
location: None,
locked_down: settings.block_when_disconnected,
},
target_state,
state: DaemonExecutionState::Running,
#[cfg(target_os = "linux")]
Expand Down Expand Up @@ -999,7 +1002,10 @@ where
.handle_state_transition(&tunnel_state_transition);

let tunnel_state = match tunnel_state_transition {
TunnelStateTransition::Disconnected => TunnelState::Disconnected(None),
TunnelStateTransition::Disconnected { locked_down } => TunnelState::Disconnected {
location: None,
locked_down,
},
TunnelStateTransition::Connecting(endpoint) => TunnelState::Connecting {
endpoint,
location: self.parameters_generator.get_last_location().await,
Expand All @@ -1024,7 +1030,7 @@ where
log::debug!("New tunnel state: {:?}", tunnel_state);

match tunnel_state {
TunnelState::Disconnected(_) => {
TunnelState::Disconnected { .. } => {
self.api_handle.availability.reset_inactivity_timer();
}
_ => {
Expand All @@ -1033,7 +1039,7 @@ where
}

match &tunnel_state {
TunnelState::Disconnected(_) => self.state.disconnected(),
TunnelState::Disconnected { .. } => self.state.disconnected(),
TunnelState::Connecting { .. } => {
log::debug!("Settings: {}", self.settings.summary());
}
Expand Down Expand Up @@ -1079,7 +1085,7 @@ where
TunnelState::Connected { .. } => self.settings.tunnel_options.generic.enable_ipv6,
// If not connected, we have to guess whether the users local connection supports IPv6.
// The only thing we have to go on is the wireguard setting.
TunnelState::Disconnected(_) => {
TunnelState::Disconnected { .. } => {
if let RelaySettings::Normal(relay_constraints) = &self.settings.relay_settings {
// Note that `Constraint::Any` corresponds to just IPv4
matches!(
Expand All @@ -1098,7 +1104,7 @@ where
self.location_handler.send_geo_location_request(use_ipv6);
}

/// Recieves and handles the geographical exit location received from am.i.mullvad.net, i.e. the
/// Receives and handles the geographical exit location received from am.i.mullvad.net, i.e. the
/// [`InternalDaemonEvent::LocationEvent`] event.
fn handle_location_event(&mut self, location_data: LocationEventData) {
let LocationEventData {
Expand All @@ -1112,7 +1118,10 @@ where
}

match self.tunnel_state {
TunnelState::Disconnected(ref mut location) => *location = Some(fetched_location),
TunnelState::Disconnected {
ref mut location,
locked_down: _,
} => *location = Some(fetched_location),
TunnelState::Connected {
ref mut location, ..
} => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,10 @@ message ErrorState {
}

message TunnelState {
message Disconnected { GeoIpLocation disconnected_location = 1; }
message Disconnected {
GeoIpLocation disconnected_location = 1;
bool locked_down = 2;
}
message Connecting { TunnelStateRelayInfo relay_info = 1; }
message Connected { TunnelStateRelayInfo relay_info = 1; }
message Disconnecting { AfterDisconnect after_disconnect = 1; }
Expand Down
20 changes: 12 additions & 8 deletions mullvad-management-interface/src/types/conversions/states.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,13 @@ impl From<mullvad_types::states::TunnelState> for proto::TunnelState {
};

let state = match state {
MullvadTunnelState::Disconnected(disconnected_location) => {
proto::tunnel_state::State::Disconnected(proto::tunnel_state::Disconnected {
disconnected_location: disconnected_location.map(proto::GeoIpLocation::from),
})
}
MullvadTunnelState::Disconnected {
location: disconnected_location,
locked_down,
} => proto::tunnel_state::State::Disconnected(proto::tunnel_state::Disconnected {
disconnected_location: disconnected_location.map(proto::GeoIpLocation::from),
locked_down,
}),
MullvadTunnelState::Connecting { endpoint, location } => {
proto::tunnel_state::State::Connecting(proto::tunnel_state::Connecting {
relay_info: Some(proto::TunnelStateRelayInfo {
Expand Down Expand Up @@ -193,11 +195,13 @@ impl TryFrom<proto::TunnelState> for mullvad_types::states::TunnelState {
let state = match state.state {
Some(proto::tunnel_state::State::Disconnected(proto::tunnel_state::Disconnected {
disconnected_location,
})) => MullvadState::Disconnected(
disconnected_location
locked_down,
})) => MullvadState::Disconnected {
location: disconnected_location
.map(mullvad_types::location::GeoIpLocation::try_from)
.transpose()?,
),
locked_down,
},
Some(proto::tunnel_state::State::Connecting(proto::tunnel_state::Connecting {
relay_info:
Some(proto::TunnelStateRelayInfo {
Expand Down
125 changes: 119 additions & 6 deletions mullvad-types/src/states.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
use crate::location::GeoIpLocation;
#[cfg(target_os = "android")]
use jnix::IntoJava;
use serde::{Deserialize, Serialize};
use std::fmt;
use talpid_types::{
Expand Down Expand Up @@ -31,10 +29,12 @@ impl fmt::Display for TargetState {
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
#[serde(tag = "state", content = "details")]
#[cfg_attr(target_os = "android", derive(IntoJava))]
#[cfg_attr(target_os = "android", jnix(package = "net.mullvad.mullvadvpn.model"))]
pub enum TunnelState {
Disconnected(Option<GeoIpLocation>),
Disconnected {
location: Option<GeoIpLocation>,
/// Whether internet access is blocked due to lockdown mode
locked_down: bool,
},
Connecting {
endpoint: TunnelEndpoint,
location: Option<GeoIpLocation>,
Expand All @@ -60,6 +60,119 @@ impl TunnelState {

/// Returns true if the tunnel state is in the disconnected state.
pub fn is_disconnected(&self) -> bool {
matches!(self, TunnelState::Disconnected(_))
matches!(self, TunnelState::Disconnected { .. })
}
}

#[cfg(target_os = "android")]
// Here we manually implement the `IntoJava` trait of jnix to skip the `locked_down` field of
// `TunnelState::Disconnected`. The derive macro currently does not support skipping fields in
// struct variants of enums. It was decided that this solution is the preferred to updating the
// macro since the jnix crate will be dropped once android implements gRPC.
impl<'borrow, 'env> jnix::IntoJava<'borrow, 'env> for TunnelState
where
'env: 'borrow,
{
const JNI_SIGNATURE: &'static str = "Lnet/mullvad/mullvadvpn/model/TunnelState;";
type JavaType = jnix::jni::objects::AutoLocal<'env, 'borrow>;
#[allow(non_snake_case)]
fn into_java(self, env: &'borrow jnix::JnixEnv<'env>) -> Self::JavaType {
match self {
Self::Disconnected {
location,
locked_down: _,
} => {
let constructor_signature = format!("({})V", location.jni_signature());

let location_java = location.into_java(env);
let parameters = [jnix::AsJValue::as_jvalue(&location_java)];

let class = env.get_class("net/mullvad/mullvadvpn/model/TunnelState$Disconnected");

let object = env
.new_object(&class, constructor_signature, &parameters)
.expect(
"Failed to convert TunnelState::Disconnected Rust type into net.mullvad.mullvadvpn.model.TunnelState.Disconnected Java object",
);
env.auto_local(object)
}
Self::Connecting { endpoint, location } => {
let constructor_signature = format!(
"({}{})V",
endpoint.jni_signature(),
location.jni_signature()
);

let endpoint_java = endpoint.into_java(env);
let location_java = location.into_java(env);
let parameters = [
jnix::AsJValue::as_jvalue(&endpoint_java),
jnix::AsJValue::as_jvalue(&location_java),
];

let class = env.get_class("net/mullvad/mullvadvpn/model/TunnelState$Connecting");

let object = env
.new_object(&class, constructor_signature, &parameters)
.expect(
"Failed to convert TunnelState::Connecting Rust type into net.mullvad.mullvadvpn.model.TunnelState.Connecting Java object",
);
env.auto_local(object)
}
Self::Connected { endpoint, location } => {
let constructor_signature = format!(
"({}{})V",
endpoint.jni_signature(),
location.jni_signature()
);

let endpoint_java = endpoint.into_java(env);
let location_java = location.into_java(env);
let parameters = [
jnix::AsJValue::as_jvalue(&endpoint_java),
jnix::AsJValue::as_jvalue(&location_java),
];

let class = env.get_class("net/mullvad/mullvadvpn/model/TunnelState$Connected");

let object = env
.new_object(&class, constructor_signature, &parameters)
.expect(
"Failed to convert TunnelState::Connected Rust type into net.mullvad.mullvadvpn.model.TunnelState.Connected Java object",
);
env.auto_local(object)
}
Self::Disconnecting(action_after_disconnect) => {
let constructor_signature =
format!("({})V", action_after_disconnect.jni_signature());

let action_after_disconnect_java = action_after_disconnect.into_java(env);
let parameters = [jnix::AsJValue::as_jvalue(&action_after_disconnect_java)];

let class = env.get_class("net/mullvad/mullvadvpn/model/TunnelState$Disconnecting");

let object = env
.new_object(&class, constructor_signature, &parameters)
.expect(
"Failed to convert TunnelState::Disconnecting Rust type into net.mullvad.mullvadvpn.model.TunnelState.Disconnecting Java object",
);
env.auto_local(object)
}
Self::Error(error_state) => {
let constructor_signature = format!("({})V", error_state.jni_signature());

let error_state_java = error_state.into_java(env);
let parameters = [jnix::AsJValue::as_jvalue(&error_state_java)];

let class = env.get_class("net/mullvad/mullvadvpn/model/TunnelState$Error");

let object = env
.new_object(&class, constructor_signature, &parameters)
.expect(
"Failed to convert TunnelState::Error Rust type into net.mullvad.mullvadvpn.model.TunnelState.Error Java object",
);
env.auto_local(object)
}
}
}
}
Loading

0 comments on commit 8f8e8c4

Please sign in to comment.