summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorDavid Göransson <david.goransson@mullvad.net>2024-03-19 15:01:01 +0100
committerDavid Göransson <david.goransson@mullvad.net>2024-03-19 16:15:40 +0100
commita1ab31eebd96846514fa67af99c6af091ed68208 (patch)
treeb1d2cbb4f09b4b357d92b508011725bbe5453bdf
parentfc7a0c22152c411a0bf00f20ac6ed6fb993d961b (diff)
downloadmullvadvpn-a1ab31eebd96846514fa67af99c6af091ed68208.tar.xz
mullvadvpn-a1ab31eebd96846514fa67af99c6af091ed68208.zip
Implement JNI support for Server IP overrides
-rw-r--r--mullvad-jni/src/classes.rs2
-rw-r--r--mullvad-jni/src/daemon_interface.rs47
-rw-r--r--mullvad-jni/src/lib.rs140
-rw-r--r--mullvad-types/src/relay_constraints.rs2
-rw-r--r--mullvad-types/src/settings/mod.rs1
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,