diff options
| author | David Göransson <david.goransson@mullvad.net> | 2024-03-19 15:01:01 +0100 |
|---|---|---|
| committer | David Göransson <david.goransson@mullvad.net> | 2024-03-19 16:15:40 +0100 |
| commit | a1ab31eebd96846514fa67af99c6af091ed68208 (patch) | |
| tree | b1d2cbb4f09b4b357d92b508011725bbe5453bdf | |
| parent | fc7a0c22152c411a0bf00f20ac6ed6fb993d961b (diff) | |
| download | mullvadvpn-a1ab31eebd96846514fa67af99c6af091ed68208.tar.xz mullvadvpn-a1ab31eebd96846514fa67af99c6af091ed68208.zip | |
Implement JNI support for Server IP overrides
| -rw-r--r-- | mullvad-jni/src/classes.rs | 2 | ||||
| -rw-r--r-- | mullvad-jni/src/daemon_interface.rs | 47 | ||||
| -rw-r--r-- | mullvad-jni/src/lib.rs | 140 | ||||
| -rw-r--r-- | mullvad-types/src/relay_constraints.rs | 2 | ||||
| -rw-r--r-- | mullvad-types/src/settings/mod.rs | 1 |
5 files changed, 187 insertions, 5 deletions
diff --git a/mullvad-jni/src/classes.rs b/mullvad-jni/src/classes.rs index 969c7a5057..fb11412c26 100644 --- a/mullvad-jni/src/classes.rs +++ b/mullvad-jni/src/classes.rs @@ -57,10 +57,12 @@ pub const CLASSES: &[&str] = &[ "net/mullvad/mullvadvpn/model/RelayList", "net/mullvad/mullvadvpn/model/RelayListCity", "net/mullvad/mullvadvpn/model/RelayListCountry", + "net/mullvad/mullvadvpn/model/RelayOverride", "net/mullvad/mullvadvpn/model/RelaySettings$CustomTunnelEndpoint", "net/mullvad/mullvadvpn/model/RelaySettings$Normal", "net/mullvad/mullvadvpn/model/SelectedObfuscation", "net/mullvad/mullvadvpn/model/Settings", + "net/mullvad/mullvadvpn/model/SettingsPatchError", "net/mullvad/mullvadvpn/model/TunnelState$Error", "net/mullvad/mullvadvpn/model/TunnelState$Connected", "net/mullvad/mullvadvpn/model/TunnelState$Connecting", diff --git a/mullvad-jni/src/daemon_interface.rs b/mullvad-jni/src/daemon_interface.rs index 66cc8c3eb2..4d9cf3ad48 100644 --- a/mullvad-jni/src/daemon_interface.rs +++ b/mullvad-jni/src/daemon_interface.rs @@ -1,10 +1,10 @@ use futures::{channel::oneshot, executor::block_on}; -use mullvad_daemon::{device, DaemonCommand, DaemonCommandSender}; +use mullvad_daemon::{device, settings::patch, DaemonCommand, DaemonCommandSender}; use mullvad_types::{ account::{AccountData, AccountToken, PlayPurchase, VoucherSubmission}, custom_list::CustomList, device::{Device, DeviceState}, - relay_constraints::{ObfuscationSettings, RelaySettings}, + relay_constraints::{ObfuscationSettings, RelayOverride, RelaySettings}, relay_list::RelayList, settings::{DnsOptions, Settings}, states::{TargetState, TunnelState}, @@ -30,6 +30,9 @@ pub enum Error { #[error("Failed to update settings")] UpdateSettings, + #[error("Patch error")] + Patch(#[from] patch::Error), + #[error("Daemon returned an error")] Other(#[source] mullvad_daemon::Error), } @@ -384,6 +387,46 @@ impl DaemonInterface { .map_err(Error::from) } + pub fn apply_json_settings(&self, json: String) -> Result<()> { + let (tx, rx) = oneshot::channel(); + + self.send_command(DaemonCommand::ApplyJsonSettings(tx, json))?; + + block_on(rx) + .map_err(|_| Error::NoResponse)? + .map_err(Error::from) + } + + pub fn export_json_settings(&self) -> Result<String> { + let (tx, rx) = oneshot::channel(); + + self.send_command(DaemonCommand::ExportJsonSettings(tx))?; + + block_on(rx) + .map_err(|_| Error::NoResponse)? + .map_err(Error::from) + } + + pub fn set_relay_override(&self, relay_override: RelayOverride) -> Result<()> { + let (tx, rx) = oneshot::channel(); + + self.send_command(DaemonCommand::SetRelayOverride(tx, relay_override))?; + + block_on(rx) + .map_err(|_| Error::NoResponse)? + .map_err(|_| Error::UpdateSettings) + } + + pub fn clear_all_relay_overrides(&self) -> Result<()> { + let (tx, rx) = oneshot::channel(); + + self.send_command(DaemonCommand::ClearAllRelayOverrides(tx))?; + + block_on(rx) + .map_err(|_| Error::NoResponse)? + .map_err(|_| Error::UpdateSettings) + } + fn send_command(&self, command: DaemonCommand) -> Result<()> { self.command_sender.send(command).map_err(Error::NoDaemon) } diff --git a/mullvad-jni/src/lib.rs b/mullvad-jni/src/lib.rs index 9139f1f435..9264b5e895 100644 --- a/mullvad-jni/src/lib.rs +++ b/mullvad-jni/src/lib.rs @@ -19,12 +19,13 @@ use jnix::{ }; use mullvad_api::{rest::Error as RestError, StatusCode}; use mullvad_daemon::{ - device, exception_logging, logging, runtime::new_runtime_builder, version, Daemon, - DaemonCommandChannel, + device, exception_logging, logging, runtime::new_runtime_builder, + settings::patch::Error as PatchError, version, Daemon, DaemonCommandChannel, }; use mullvad_types::{ account::{AccountData, PlayPurchase, VoucherSubmission}, custom_list::CustomList, + relay_constraints::RelayOverride, settings::DnsOptions, }; use std::{ @@ -192,6 +193,46 @@ impl From<daemon_interface::Error> for VoucherSubmissionError { #[derive(IntoJava)] #[jnix(package = "net.mullvad.mullvadvpn.model")] +pub enum SettingsPatchError { + InvalidOrMissingValue(String), + UnknownOrProhibitedKey(String), + ParsePatch, + DeserializePatched, + RecursionLimit, + ApplyPatch, +} + +impl From<daemon_interface::Error> for SettingsPatchError { + fn from(error: daemon_interface::Error) -> Self { + match error { + daemon_interface::Error::Patch(PatchError::InvalidOrMissingValue(str)) => { + SettingsPatchError::InvalidOrMissingValue(str.to_string()) + } + daemon_interface::Error::Patch(PatchError::UnknownOrProhibitedKey(string)) => { + SettingsPatchError::UnknownOrProhibitedKey(string) + } + daemon_interface::Error::Patch(PatchError::ParsePatch(_)) => { + SettingsPatchError::ParsePatch + } + daemon_interface::Error::Patch(PatchError::DeserializePatched(_)) => { + SettingsPatchError::DeserializePatched + } + daemon_interface::Error::Patch(PatchError::SerializeSettings(_)) => { + SettingsPatchError::ApplyPatch + } + daemon_interface::Error::Patch(PatchError::SerializeValue(_)) => { + SettingsPatchError::ApplyPatch + } + daemon_interface::Error::Patch(PatchError::RecursionLimit) => { + SettingsPatchError::RecursionLimit + } + _ => SettingsPatchError::ApplyPatch, + } + } +} + +#[derive(IntoJava)] +#[jnix(package = "net.mullvad.mullvadvpn.model")] pub enum PlayPurchaseInitResult { Ok(String), Error(PlayPurchaseInitError), @@ -1465,6 +1506,101 @@ pub extern "system" fn Java_net_mullvad_mullvadvpn_service_MullvadDaemon_updateC } } +#[no_mangle] +#[allow(non_snake_case)] +pub extern "system" fn Java_net_mullvad_mullvadvpn_service_MullvadDaemon_applyJsonSettings<'env>( + env: JNIEnv<'env>, + _: JObject<'_>, + daemon_interface_address: jlong, + json: JString<'_>, +) -> JObject<'env> { + let env = JnixEnv::from(env); + + // SAFETY: The address points to an instance valid for the duration of this function call + if let Some(daemon_interface) = unsafe { get_daemon_interface(daemon_interface_address) } { + let jsonSettings = String::from_java(&env, json); + match daemon_interface.apply_json_settings(jsonSettings) { + Ok(()) => JObject::null(), + Err(error) => { + log_request_error("apply json settings", &error); + SettingsPatchError::from(error).into_java(&env).forget() + } + } + } else { + log::warn!("Daemon was unreachable"); + JObject::null() + } +} + +#[no_mangle] +#[allow(non_snake_case)] +pub extern "system" fn Java_net_mullvad_mullvadvpn_service_MullvadDaemon_exportJsonSettings< + 'env, +>( + env: JNIEnv<'env>, + _: JObject<'_>, + daemon_interface_address: jlong, + _: JObject<'_>, +) -> JObject<'env> { + let env = JnixEnv::from(env); + + // SAFETY: The address points to an instance valid for the duration of this function call + if let Some(daemon_interface) = unsafe { get_daemon_interface(daemon_interface_address) } { + match daemon_interface.export_json_settings() { + Ok(exported_json) => exported_json.into_java(&env).forget(), + Err(error) => { + log_request_error("export json settings", &error); + JObject::null() + } + } + } else { + log::warn!("Daemon was unreachable"); + JObject::null() + } +} + +#[no_mangle] +#[allow(non_snake_case)] +pub extern "system" fn Java_net_mullvad_mullvadvpn_service_MullvadDaemon_setRelayOverride( + env: JNIEnv<'_>, + _: JObject<'_>, + daemon_interface_address: jlong, + relay_override: JObject<'_>, +) { + let env = JnixEnv::from(env); + + // SAFETY: The address points to an instance valid for the duration of this function call + if let Some(daemon_interface) = unsafe { get_daemon_interface(daemon_interface_address) } { + let r_override = RelayOverride::from_java(&env, relay_override); + + match daemon_interface.set_relay_override(r_override) { + Ok(()) => (), + Err(error) => { + log_request_error("set relay override", &error); + } + } + } +} + +#[no_mangle] +#[allow(non_snake_case)] +pub extern "system" fn Java_net_mullvad_mullvadvpn_service_MullvadDaemon_clearAllRelayOverrides( + _: JNIEnv<'_>, + _: JObject<'_>, + daemon_interface_address: jlong, + _: JObject<'_>, +) { + // SAFETY: The address points to an instance valid for the duration of this function call + if let Some(daemon_interface) = unsafe { get_daemon_interface(daemon_interface_address) } { + match daemon_interface.clear_all_relay_overrides() { + Ok(()) => (), + Err(error) => { + log_request_error("clear all relay overrides", &error); + } + } + } +} + fn log_request_error(request: &str, error: &daemon_interface::Error) { match error { daemon_interface::Error::Api(RestError::Aborted) => { diff --git a/mullvad-types/src/relay_constraints.rs b/mullvad-types/src/relay_constraints.rs index b37c3ea0a1..d0a42e2303 100644 --- a/mullvad-types/src/relay_constraints.rs +++ b/mullvad-types/src/relay_constraints.rs @@ -1039,6 +1039,8 @@ pub struct InternalBridgeConstraints { /// Options to override for a particular relay to use instead of the ones specified in the relay /// list #[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize)] +#[cfg_attr(target_os = "android", derive(FromJava, IntoJava))] +#[cfg_attr(target_os = "android", jnix(package = "net.mullvad.mullvadvpn.model"))] pub struct RelayOverride { /// Hostname for which to override the given options pub hostname: Hostname, diff --git a/mullvad-types/src/settings/mod.rs b/mullvad-types/src/settings/mod.rs index b8fec8de2f..c0048a7e62 100644 --- a/mullvad-types/src/settings/mod.rs +++ b/mullvad-types/src/settings/mod.rs @@ -95,7 +95,6 @@ pub struct Settings { /// might be located. pub tunnel_options: TunnelOptions, /// Overrides for relays - #[cfg_attr(target_os = "android", jnix(skip))] pub relay_overrides: Vec<RelayOverride>, /// Whether to notify users of beta updates. pub show_beta_releases: bool, |
