summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorDavid Lönnhager <david.l@mullvad.net>2023-02-21 11:07:22 +0100
committerDavid Lönnhager <david.l@mullvad.net>2023-02-21 11:07:22 +0100
commit00aeed11ab5870158622108c7ac17a3a10a60d3a (patch)
treeb8c33f1957400bb4cc6429cfd91165018ada6237
parenta83211930c6473776d2e838e357cc5583000aa9f (diff)
parentec8a7e1e729d9e25f363c3a7394acd39ddb36f42 (diff)
downloadmullvadvpn-00aeed11ab5870158622108c7ac17a3a10a60d3a.tar.xz
mullvadvpn-00aeed11ab5870158622108c7ac17a3a10a60d3a.zip
Merge branch 'make-pq-optional'
-rw-r--r--CHANGELOG.md3
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/model/WireguardTunnelOptions.kt6
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/AdvancedFragment.kt2
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/SettingsListener.kt2
-rw-r--r--android/app/src/main/kotlin/net/mullvad/talpid/net/wireguard/TunnelOptions.kt10
-rw-r--r--mullvad-cli/src/cmds/relay.rs10
-rw-r--r--mullvad-cli/src/cmds/tunnel.rs35
-rw-r--r--mullvad-daemon/src/lib.rs13
-rw-r--r--mullvad-daemon/src/management_interface.rs13
-rw-r--r--mullvad-daemon/src/migrations/mod.rs11
-rw-r--r--mullvad-daemon/src/migrations/v5.rs5
-rw-r--r--mullvad-daemon/src/migrations/v6.rs305
-rw-r--r--mullvad-daemon/src/settings.rs23
-rw-r--r--mullvad-daemon/src/tunnel.rs6
-rw-r--r--mullvad-management-interface/proto/management_interface.proto13
-rw-r--r--mullvad-management-interface/src/types/conversions/settings.rs29
-rw-r--r--mullvad-management-interface/src/types/conversions/wireguard.rs38
-rw-r--r--mullvad-types/src/custom_tunnel.rs4
-rw-r--r--mullvad-types/src/settings/mod.rs7
-rw-r--r--mullvad-types/src/wireguard.rs64
-rw-r--r--talpid-core/src/tunnel/mod.rs2
-rw-r--r--talpid-types/src/net/mod.rs4
-rw-r--r--talpid-types/src/net/wireguard.rs39
23 files changed, 521 insertions, 123 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 971a71edda..86d19580ee 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -31,6 +31,9 @@ Line wrap the file at 100 chars. Th
### Changed
- Update the Post-Quantum secure key exchange gRPC client to use the stabilized
`PskExchangeV1` endpoint
+- Add "auto" setting for the quantum-resistant tunnel feature, and make it the default. If it was
+ previously set to off, it will now be set to auto instead. That currently means the same thing as
+ "off", but this might change in the future.
#### Windows
- Remove automatic fallback to wireguard-go. This is done as a first step before fully
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/model/WireguardTunnelOptions.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/model/WireguardTunnelOptions.kt
index 251571021a..85a5ebc894 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/model/WireguardTunnelOptions.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/model/WireguardTunnelOptions.kt
@@ -2,7 +2,9 @@ package net.mullvad.mullvadvpn.model
import android.os.Parcelable
import kotlinx.parcelize.Parcelize
-import net.mullvad.talpid.net.wireguard.TunnelOptions as TalpidWireguardTunnelOptions
@Parcelize
-data class WireguardTunnelOptions(val options: TalpidWireguardTunnelOptions) : Parcelable
+data class WireguardTunnelOptions(
+ val mtu: Int?,
+ val quantumResistant: Boolean?
+) : Parcelable
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/AdvancedFragment.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/AdvancedFragment.kt
index 011e9fdc15..10a4f2b5d7 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/AdvancedFragment.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/AdvancedFragment.kt
@@ -229,7 +229,7 @@ class AdvancedFragment : BaseFragment() {
private fun updateUi(settings: Settings) {
if (this::wireguardMtuInput.isInitialized && wireguardMtuInput.hasFocus == false) {
- wireguardMtuInput.value = settings.tunnelOptions.wireguard.options.mtu
+ wireguardMtuInput.value = settings.tunnelOptions.wireguard.mtu
}
}
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/SettingsListener.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/SettingsListener.kt
index a1464a7745..1cb1cf2986 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/SettingsListener.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/SettingsListener.kt
@@ -29,7 +29,7 @@ class SettingsListener(private val connection: Messenger, eventDispatcher: Event
}
var wireguardMtu: Int?
- get() = settingsNotifier.latestEvent?.tunnelOptions?.wireguard?.options?.mtu
+ get() = settingsNotifier.latestEvent?.tunnelOptions?.wireguard?.mtu
set(value) {
connection.send(Request.SetWireGuardMtu(value).message)
}
diff --git a/android/app/src/main/kotlin/net/mullvad/talpid/net/wireguard/TunnelOptions.kt b/android/app/src/main/kotlin/net/mullvad/talpid/net/wireguard/TunnelOptions.kt
deleted file mode 100644
index 79e8ce544c..0000000000
--- a/android/app/src/main/kotlin/net/mullvad/talpid/net/wireguard/TunnelOptions.kt
+++ /dev/null
@@ -1,10 +0,0 @@
-package net.mullvad.talpid.net.wireguard
-
-import android.os.Parcelable
-import kotlinx.parcelize.Parcelize
-
-@Parcelize
-data class TunnelOptions(
- val mtu: Int?,
- val usePqSafePsk: Boolean
-) : Parcelable
diff --git a/mullvad-cli/src/cmds/relay.rs b/mullvad-cli/src/cmds/relay.rs
index 981f0fffdd..27e8df55b9 100644
--- a/mullvad-cli/src/cmds/relay.rs
+++ b/mullvad-cli/src/cmds/relay.rs
@@ -593,7 +593,7 @@ impl Relay {
wireguard_constraints.entry_location = parse_entry_location_constraint(entry);
let use_multihop = wireguard_constraints.entry_location.is_some();
if use_multihop {
- let use_pq_safe_psk = rpc
+ let quantum_resistant = rpc
.get_settings(())
.await?
.into_inner()
@@ -601,8 +601,12 @@ impl Relay {
.unwrap()
.wireguard
.unwrap()
- .use_pq_safe_psk;
- if use_pq_safe_psk {
+ .quantum_resistant;
+ if quantum_resistant
+ == Some(types::QuantumResistantState {
+ state: i32::from(types::quantum_resistant_state::State::On),
+ })
+ {
return Err(Error::CommandFailed(
"Quantum resistant tunnels do not work when multihop is enabled",
));
diff --git a/mullvad-cli/src/cmds/tunnel.rs b/mullvad-cli/src/cmds/tunnel.rs
index a40aa985b9..042590fcbb 100644
--- a/mullvad-cli/src/cmds/tunnel.rs
+++ b/mullvad-cli/src/cmds/tunnel.rs
@@ -63,7 +63,13 @@ fn create_wireguard_quantum_resistant_tunnel_subcommand() -> clap::App<'static>
.about("Controls the quantum-resistant PSK exchange in the tunnel")
.setting(clap::AppSettings::SubcommandRequiredElseHelp)
.subcommand(clap::App::new("get"))
- .subcommand(clap::App::new("set").arg(clap::Arg::new("policy").required(true)))
+ .subcommand(
+ clap::App::new("set").arg(
+ clap::Arg::new("policy")
+ .required(true)
+ .possible_values(["on", "off", "auto"]),
+ ),
+ )
}
fn create_wireguard_keys_subcommand() -> clap::App<'static> {
@@ -222,10 +228,15 @@ impl Tunnel {
async fn process_wireguard_quantum_resistant_tunnel_get() -> Result<()> {
let tunnel_options = Self::get_tunnel_options().await?;
- if tunnel_options.wireguard.unwrap().use_pq_safe_psk {
- println!("enabled");
- } else {
- println!("disabled");
+ match tunnel_options
+ .wireguard
+ .unwrap()
+ .quantum_resistant
+ .and_then(|state| types::quantum_resistant_state::State::from_i32(state.state))
+ {
+ Some(types::quantum_resistant_state::State::On) => println!("enabled"),
+ Some(types::quantum_resistant_state::State::Off) => println!("disabled"),
+ None | Some(types::quantum_resistant_state::State::Auto) => println!("auto"),
}
Ok(())
}
@@ -233,10 +244,15 @@ impl Tunnel {
async fn process_wireguard_quantum_resistant_tunnel_set(
matches: &clap::ArgMatches,
) -> Result<()> {
- let use_pq_safe_psk = matches.value_of("policy").unwrap() == "on";
+ let quantum_resistant = match matches.value_of("policy").unwrap() {
+ "auto" => types::quantum_resistant_state::State::Auto,
+ "on" => types::quantum_resistant_state::State::On,
+ "off" => types::quantum_resistant_state::State::Off,
+ _ => unreachable!("invalid PQ state"),
+ };
let mut rpc = new_rpc_client().await?;
let settings = rpc.get_settings(()).await?;
- if use_pq_safe_psk {
+ if quantum_resistant == types::quantum_resistant_state::State::On {
let multihop_is_enabled = settings
.into_inner()
.relay_settings
@@ -256,7 +272,10 @@ impl Tunnel {
));
}
}
- rpc.set_quantum_resistant_tunnel(use_pq_safe_psk).await?;
+ rpc.set_quantum_resistant_tunnel(types::QuantumResistantState {
+ state: i32::from(quantum_resistant),
+ })
+ .await?;
println!("Updated quantum resistant tunnel setting");
Ok(())
}
diff --git a/mullvad-daemon/src/lib.rs b/mullvad-daemon/src/lib.rs
index 4bb22a9aa8..6a71e9d754 100644
--- a/mullvad-daemon/src/lib.rs
+++ b/mullvad-daemon/src/lib.rs
@@ -49,7 +49,7 @@ use mullvad_types::{
settings::{DnsOptions, Settings},
states::{TargetState, TunnelState},
version::{AppVersion, AppVersionInfo},
- wireguard::{PublicKey, RotationInterval},
+ wireguard::{PublicKey, QuantumResistantState, RotationInterval},
};
use settings::SettingsPersister;
#[cfg(target_os = "android")]
@@ -226,7 +226,7 @@ pub enum DaemonCommand {
/// Set if IPv6 should be enabled in the tunnel
SetEnableIpv6(ResponseTx<(), settings::Error>, bool),
/// Set whether to enable PQ PSK exchange in the tunnel
- SetQuantumResistantTunnel(ResponseTx<(), settings::Error>, bool),
+ SetQuantumResistantTunnel(ResponseTx<(), settings::Error>, QuantumResistantState),
/// Set DNS options or servers to use
SetDnsOptions(ResponseTx<(), settings::Error>, DnsOptions),
/// Toggle macOS network check leak
@@ -1004,8 +1004,9 @@ where
}
SetBridgeState(tx, bridge_state) => self.on_set_bridge_state(tx, bridge_state).await,
SetEnableIpv6(tx, enable_ipv6) => self.on_set_enable_ipv6(tx, enable_ipv6).await,
- SetQuantumResistantTunnel(tx, enable_pq) => {
- self.on_set_quantum_resistant_tunnel(tx, enable_pq).await
+ SetQuantumResistantTunnel(tx, quantum_resistant_state) => {
+ self.on_set_quantum_resistant_tunnel(tx, quantum_resistant_state)
+ .await
}
SetDnsOptions(tx, dns_servers) => self.on_set_dns_options(tx, dns_servers).await,
SetWireguardMtu(tx, mtu) => self.on_set_wireguard_mtu(tx, mtu).await,
@@ -2019,11 +2020,11 @@ where
async fn on_set_quantum_resistant_tunnel(
&mut self,
tx: ResponseTx<(), settings::Error>,
- use_pq_safe_psk: bool,
+ quantum_resistant: QuantumResistantState,
) {
let save_result = self
.settings
- .set_quantum_resistant_tunnel(use_pq_safe_psk)
+ .set_quantum_resistant_tunnel(quantum_resistant)
.await;
match save_result {
Ok(settings_changed) => {
diff --git a/mullvad-daemon/src/management_interface.rs b/mullvad-daemon/src/management_interface.rs
index a66ee7a7db..c231c8a49e 100644
--- a/mullvad-daemon/src/management_interface.rs
+++ b/mullvad-daemon/src/management_interface.rs
@@ -345,11 +345,16 @@ impl ManagementService for ManagementServiceImpl {
.map_err(map_settings_error)
}
- async fn set_quantum_resistant_tunnel(&self, request: Request<bool>) -> ServiceResult<()> {
- let enable = request.into_inner();
- log::debug!("set_quantum_resistant_tunnel({})", enable);
+ async fn set_quantum_resistant_tunnel(
+ &self,
+ request: Request<types::QuantumResistantState>,
+ ) -> ServiceResult<()> {
+ let state = mullvad_types::wireguard::QuantumResistantState::try_from(request.into_inner())
+ .map_err(map_protobuf_type_err)?;
+
+ log::debug!("set_quantum_resistant_tunnel({state:?})");
let (tx, rx) = oneshot::channel();
- self.send_command_to_daemon(DaemonCommand::SetQuantumResistantTunnel(tx, enable))?;
+ self.send_command_to_daemon(DaemonCommand::SetQuantumResistantTunnel(tx, state))?;
self.wait_for_result(rx)
.await?
.map(Response::new)
diff --git a/mullvad-daemon/src/migrations/mod.rs b/mullvad-daemon/src/migrations/mod.rs
index c6bfc5babe..f2edfc1147 100644
--- a/mullvad-daemon/src/migrations/mod.rs
+++ b/mullvad-daemon/src/migrations/mod.rs
@@ -50,6 +50,7 @@ mod v2;
mod v3;
mod v4;
mod v5;
+mod v6;
const SETTINGS_FILE: &str = "settings.json";
@@ -95,7 +96,7 @@ pub type Result<T> = std::result::Result<T, Error>;
/// Returns whether there is any background work remaining.
#[derive(Clone)]
-pub(crate) struct MigrationComplete(Arc<AtomicBool>);
+pub struct MigrationComplete(Arc<AtomicBool>);
impl MigrationComplete {
pub fn new(state: bool) -> Self {
@@ -112,12 +113,9 @@ impl MigrationComplete {
}
/// Contains discarded data that may be useful for later work.
-pub(crate) type MigrationData = v5::MigrationData;
+pub type MigrationData = v5::MigrationData;
-pub(crate) async fn migrate_all(
- cache_dir: &Path,
- settings_dir: &Path,
-) -> Result<Option<MigrationData>> {
+pub async fn migrate_all(cache_dir: &Path, settings_dir: &Path) -> Result<Option<MigrationData>> {
#[cfg(windows)]
windows::migrate_after_windows_update(settings_dir)
.await
@@ -149,6 +147,7 @@ pub(crate) async fn migrate_all(
account_history::migrate_formats(settings_dir, &mut settings).await?;
let migration_data = v5::migrate(&mut settings)?;
+ v6::migrate(&mut settings)?;
if settings == old_settings {
// Nothing changed
diff --git a/mullvad-daemon/src/migrations/v5.rs b/mullvad-daemon/src/migrations/v5.rs
index 2c2942cd4e..cfce5c696d 100644
--- a/mullvad-daemon/src/migrations/v5.rs
+++ b/mullvad-daemon/src/migrations/v5.rs
@@ -57,7 +57,7 @@ pub struct MigrationData {
///
/// The ability to disable WireGuard multihop while preserving the entry location was added.
/// So a new field, `use_multihop` is introduced. We want this to default to `true` iff:
-/// * `use_mulithop` was not present in the settings
+/// * `use_multihop` was not present in the settings
/// * A multihop entry location had been previously specified.
///
/// It is also no longer valid to have `entry_location` set to null. So remove the field if it
@@ -72,6 +72,9 @@ pub fn migrate(settings: &mut serde_json::Value) -> Result<Option<MigrationData>
if !version_matches(settings) {
return Ok(None);
}
+
+ log::info!("Migrating settings format to V6");
+
if let Some(wireguard_constraints) = get_wireguard_constraints(settings) {
if let Some(location) = wireguard_constraints.get("entry_location") {
if wireguard_constraints.get("use_multihop").is_none() {
diff --git a/mullvad-daemon/src/migrations/v6.rs b/mullvad-daemon/src/migrations/v6.rs
new file mode 100644
index 0000000000..3fa6da7d43
--- /dev/null
+++ b/mullvad-daemon/src/migrations/v6.rs
@@ -0,0 +1,305 @@
+use super::{Error, Result};
+use mullvad_types::settings::SettingsVersion;
+
+// ======================================================
+// Section for vendoring types and values that
+// this settings version depend on. See `mod.rs`.
+
+#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
+#[serde(rename_all = "lowercase")]
+pub enum QuantumResistantState {
+ Auto,
+ On,
+ Off,
+}
+
+// ======================================================
+
+/// This is an open ended migration. There is no v7 yet!
+/// The migrations performed by this function are still backwards compatible.
+/// The JSON coming out of this migration can be read by any v6 compatible daemon.
+///
+/// When further migrations are needed, add them here and if they are not backwards
+/// compatible then create v7 and "close" this migration for further modification.
+///
+/// The `use_pq_safe_psk` tunnel option is replaced by `quantum_resistant`, which
+/// is optional. `false` is mapped to `None`. `true` is mapped to `Some(true)`.
+pub fn migrate(settings: &mut serde_json::Value) -> Result<()> {
+ if !version_matches(settings) {
+ return Ok(());
+ }
+
+ migrate_pq_setting(settings)?;
+
+ // TODO
+ // log::info!("Migrating settings format to V7");
+
+ // Note: Not incrementing the version number yet, since this migration is still open
+ // for future modification.
+ // settings["settings_version"] = serde_json::json!(SettingsVersion::V7);
+
+ Ok(())
+}
+
+fn migrate_pq_setting(settings: &mut serde_json::Value) -> Result<()> {
+ if let Some(tunnel_options) = settings
+ .get_mut("tunnel_options")
+ .and_then(|opt| opt.get_mut("wireguard"))
+ {
+ if let Some(psk_setting) = tunnel_options
+ .as_object_mut()
+ .ok_or(Error::InvalidSettingsContent)?
+ .remove("use_pq_safe_psk")
+ {
+ if let Some(true) = psk_setting.as_bool() {
+ tunnel_options["quantum_resistant"] = serde_json::json!(QuantumResistantState::On);
+ } else {
+ tunnel_options["quantum_resistant"] =
+ serde_json::json!(QuantumResistantState::Auto);
+ }
+ }
+ }
+ Ok(())
+}
+
+fn version_matches(settings: &mut serde_json::Value) -> bool {
+ settings
+ .get("settings_version")
+ .map(|version| version == SettingsVersion::V6 as u64)
+ .unwrap_or(false)
+}
+
+#[cfg(test)]
+mod test {
+ use super::{migrate, migrate_pq_setting, version_matches};
+ use serde_json;
+
+ pub const V6_SETTINGS: &str = r#"
+{
+ "relay_settings": {
+ "normal": {
+ "location": {
+ "only": {
+ "country": "se"
+ }
+ },
+ "tunnel_protocol": "any",
+ "wireguard_constraints": {
+ "port": "any",
+ "ip_version": "any",
+ "use_multihop": true,
+ "entry_location": "any"
+ },
+ "openvpn_constraints": {
+ "port": {
+ "only": {
+ "protocol": "udp",
+ "port": {
+ "only": 1195
+ }
+ }
+ }
+ }
+ }
+ },
+ "bridge_settings": {
+ "normal": {
+ "location": "any"
+ }
+ },
+ "obfuscation_settings": {
+ "selected_obfuscation": "udp2_tcp",
+ "udp2tcp": {
+ "port": "any"
+ }
+ },
+ "bridge_state": "auto",
+ "allow_lan": true,
+ "block_when_disconnected": false,
+ "auto_connect": false,
+ "tunnel_options": {
+ "openvpn": {
+ "mssfix": null
+ },
+ "wireguard": {
+ "mtu": null,
+ "rotation_interval": {
+ "secs": 86400,
+ "nanos": 0
+ },
+ "use_pq_safe_psk": false
+ },
+ "generic": {
+ "enable_ipv6": false
+ },
+ "dns_options": {
+ "state": "default",
+ "default_options": {
+ "block_ads": false,
+ "block_trackers": false
+ },
+ "custom_options": {
+ "addresses": [
+ "1.1.1.1",
+ "1.2.3.4"
+ ]
+ }
+ }
+ },
+ "settings_version": 6
+}
+"#;
+
+ pub const V7_SETTINGS: &str = r#"
+{
+ "relay_settings": {
+ "normal": {
+ "location": {
+ "only": {
+ "country": "se"
+ }
+ },
+ "tunnel_protocol": "any",
+ "wireguard_constraints": {
+ "port": "any",
+ "ip_version": "any",
+ "use_multihop": true,
+ "entry_location": "any"
+ },
+ "openvpn_constraints": {
+ "port": {
+ "only": {
+ "protocol": "udp",
+ "port": {
+ "only": 1195
+ }
+ }
+ }
+ }
+ }
+ },
+ "bridge_settings": {
+ "normal": {
+ "location": "any"
+ }
+ },
+ "obfuscation_settings": {
+ "selected_obfuscation": "udp2_tcp",
+ "udp2tcp": {
+ "port": "any"
+ }
+ },
+ "bridge_state": "auto",
+ "allow_lan": true,
+ "block_when_disconnected": false,
+ "auto_connect": false,
+ "tunnel_options": {
+ "openvpn": {
+ "mssfix": null
+ },
+ "wireguard": {
+ "mtu": null,
+ "rotation_interval": {
+ "secs": 86400,
+ "nanos": 0
+ },
+ "quantum_resistant": "auto"
+ },
+ "generic": {
+ "enable_ipv6": false
+ },
+ "dns_options": {
+ "state": "default",
+ "default_options": {
+ "block_ads": false,
+ "block_trackers": false
+ },
+ "custom_options": {
+ "addresses": [
+ "1.1.1.1",
+ "1.2.3.4"
+ ]
+ }
+ }
+ },
+ "settings_version": 6
+}
+"#;
+
+ #[test]
+ fn test_v6_to_v7_migration() {
+ let mut old_settings = serde_json::from_str(V6_SETTINGS).unwrap();
+
+ assert!(version_matches(&mut old_settings));
+ migrate(&mut old_settings).unwrap();
+ let new_settings: serde_json::Value = serde_json::from_str(V7_SETTINGS).unwrap();
+
+ assert_eq!(&old_settings, &new_settings);
+ }
+
+ /// use_pq_safe_psk=false should be replaced with quantum_resistant=null
+ #[test]
+ fn test_from_pq_safe_psk_false() {
+ let mut migrated_settings: serde_json::Value = serde_json::from_str(
+ r#"
+ {
+ "tunnel_options": {
+ "wireguard": {
+ "use_pq_safe_psk": false
+ }
+ }
+ }
+ "#,
+ )
+ .unwrap();
+ migrate_pq_setting(&mut migrated_settings).unwrap();
+
+ let expected_settings: serde_json::Value = serde_json::from_str(
+ r#"
+ {
+ "tunnel_options": {
+ "wireguard": {
+ "quantum_resistant": "auto"
+ }
+ }
+ }
+ "#,
+ )
+ .unwrap();
+
+ assert_eq!(migrated_settings, expected_settings);
+ }
+
+ /// use_pq_safe_psk=true should be replaced with quantum_resistant=true
+ #[test]
+ fn test_from_pq_safe_psk_true() {
+ let mut migrated_settings: serde_json::Value = serde_json::from_str(
+ r#"
+ {
+ "tunnel_options": {
+ "wireguard": {
+ "use_pq_safe_psk": true
+ }
+ }
+ }
+ "#,
+ )
+ .unwrap();
+ migrate_pq_setting(&mut migrated_settings).unwrap();
+
+ let expected_settings: serde_json::Value = serde_json::from_str(
+ r#"
+ {
+ "tunnel_options": {
+ "wireguard": {
+ "quantum_resistant": "on"
+ }
+ }
+ }
+ "#,
+ )
+ .unwrap();
+
+ assert_eq!(migrated_settings, expected_settings);
+ }
+}
diff --git a/mullvad-daemon/src/settings.rs b/mullvad-daemon/src/settings.rs
index 3ca4408f06..2c1ea033f9 100644
--- a/mullvad-daemon/src/settings.rs
+++ b/mullvad-daemon/src/settings.rs
@@ -3,7 +3,7 @@ use futures::TryFutureExt;
use mullvad_types::{
relay_constraints::{BridgeSettings, BridgeState, ObfuscationSettings, RelaySettingsUpdate},
settings::{DnsOptions, Settings},
- wireguard::RotationInterval,
+ wireguard::{QuantumResistantState, RotationInterval},
};
use rand::Rng;
#[cfg(target_os = "windows")]
@@ -223,16 +223,11 @@ impl SettingsPersister {
pub async fn set_quantum_resistant_tunnel(
&mut self,
- use_pq_safe_psk: bool,
+ quantum_resistant: QuantumResistantState,
) -> Result<bool, Error> {
let should_save = Self::update_field(
- &mut self
- .settings
- .tunnel_options
- .wireguard
- .options
- .use_pq_safe_psk,
- use_pq_safe_psk,
+ &mut self.settings.tunnel_options.wireguard.quantum_resistant,
+ quantum_resistant,
);
self.update(should_save).await
}
@@ -244,8 +239,7 @@ impl SettingsPersister {
}
pub async fn set_wireguard_mtu(&mut self, mtu: Option<u16>) -> Result<bool, Error> {
- let should_save =
- Self::update_field(&mut self.settings.tunnel_options.wireguard.options.mtu, mtu);
+ let should_save = Self::update_field(&mut self.settings.tunnel_options.wireguard.mtu, mtu);
self.update(should_save).await
}
@@ -301,12 +295,7 @@ impl SettingsPersister {
#[cfg(windows)]
pub async fn set_use_wireguard_nt(&mut self, state: bool) -> Result<bool, Error> {
let should_save = Self::update_field(
- &mut self
- .settings
- .tunnel_options
- .wireguard
- .options
- .use_wireguard_nt,
+ &mut self.settings.tunnel_options.wireguard.use_wireguard_nt,
state,
);
self.update(should_save).await
diff --git a/mullvad-daemon/src/tunnel.rs b/mullvad-daemon/src/tunnel.rs
index 7cf52a3c5a..8ee0f1e6d7 100644
--- a/mullvad-daemon/src/tunnel.rs
+++ b/mullvad-daemon/src/tunnel.rs
@@ -221,7 +221,11 @@ impl InnerParametersGenerator {
#[cfg(target_os = "linux")]
fwmark: Some(mullvad_types::TUNNEL_FWMARK),
},
- options: self.tunnel_options.wireguard.options.clone(),
+ options: self
+ .tunnel_options
+ .wireguard
+ .clone()
+ .into_talpid_tunnel_options(),
generic_options: self.tunnel_options.generic.clone(),
obfuscation: obfuscator_config,
}
diff --git a/mullvad-management-interface/proto/management_interface.proto b/mullvad-management-interface/proto/management_interface.proto
index cd9141981c..a2212952b0 100644
--- a/mullvad-management-interface/proto/management_interface.proto
+++ b/mullvad-management-interface/proto/management_interface.proto
@@ -43,7 +43,7 @@ service ManagementService {
rpc SetOpenvpnMssfix(google.protobuf.UInt32Value) returns (google.protobuf.Empty) {}
rpc SetWireguardMtu(google.protobuf.UInt32Value) returns (google.protobuf.Empty) {}
rpc SetEnableIpv6(google.protobuf.BoolValue) returns (google.protobuf.Empty) {}
- rpc SetQuantumResistantTunnel(google.protobuf.BoolValue) returns (google.protobuf.Empty) {}
+ rpc SetQuantumResistantTunnel(QuantumResistantState) returns (google.protobuf.Empty) {}
rpc SetDnsOptions(DnsOptions) returns (google.protobuf.Empty) {}
// Account management
@@ -437,6 +437,15 @@ message ConnectionConfig {
}
}
+message QuantumResistantState {
+ enum State {
+ AUTO = 0;
+ ON = 1;
+ OFF = 2;
+ }
+ State state = 1;
+}
+
message TunnelOptions {
message OpenvpnOptions {
uint32 mssfix = 1;
@@ -445,7 +454,7 @@ message TunnelOptions {
uint32 mtu = 1;
google.protobuf.Duration rotation_interval = 2;
bool use_wireguard_nt = 3;
- bool use_pq_safe_psk = 4;
+ QuantumResistantState quantum_resistant = 4;
}
message GenericOptions {
bool enable_ipv6 = 1;
diff --git a/mullvad-management-interface/src/types/conversions/settings.rs b/mullvad-management-interface/src/types/conversions/settings.rs
index 60805d5004..8a97c3b213 100644
--- a/mullvad-management-interface/src/types/conversions/settings.rs
+++ b/mullvad-management-interface/src/types/conversions/settings.rs
@@ -77,16 +77,16 @@ impl From<&mullvad_types::settings::TunnelOptions> for proto::TunnelOptions {
mssfix: u32::from(options.openvpn.mssfix.unwrap_or_default()),
}),
wireguard: Some(proto::tunnel_options::WireguardOptions {
- mtu: u32::from(options.wireguard.options.mtu.unwrap_or_default()),
+ mtu: u32::from(options.wireguard.mtu.unwrap_or_default()),
rotation_interval: options.wireguard.rotation_interval.map(|ivl| {
prost_types::Duration::try_from(std::time::Duration::from(ivl))
.expect("Failed to convert std::time::Duration to prost_types::Duration for tunnel_options.wireguard.rotation_interval")
}),
#[cfg(windows)]
- use_wireguard_nt: options.wireguard.options.use_wireguard_nt,
+ use_wireguard_nt: options.wireguard.use_wireguard_nt,
#[cfg(not(windows))]
use_wireguard_nt: false,
- use_pq_safe_psk: options.wireguard.options.use_pq_safe_psk,
+ quantum_resistant: Some(proto::QuantumResistantState::from(options.wireguard.quantum_resistant)),
}),
generic: Some(proto::tunnel_options::GenericOptions {
enable_ipv6: options.generic.enable_ipv6,
@@ -113,7 +113,7 @@ impl TryFrom<proto::TunnelOptions> for mullvad_types::settings::TunnelOptions {
let wireguard_options = options
.wireguard
.ok_or(FromProtobufTypeError::InvalidArgument(
- "missing openvpn tunnel options",
+ "missing wireguard tunnel options",
))?;
let generic_options = options
.generic
@@ -135,16 +135,13 @@ impl TryFrom<proto::TunnelOptions> for mullvad_types::settings::TunnelOptions {
},
},
wireguard: mullvad_types::wireguard::TunnelOptions {
- options: net::wireguard::TunnelOptions {
- mtu: if wireguard_options.mtu != 0 {
- Some(wireguard_options.mtu as u16)
- } else {
- None
- },
- use_pq_safe_psk: wireguard_options.use_pq_safe_psk,
- #[cfg(windows)]
- use_wireguard_nt: wireguard_options.use_wireguard_nt,
+ mtu: if wireguard_options.mtu != 0 {
+ Some(wireguard_options.mtu as u16)
+ } else {
+ None
},
+ #[cfg(windows)]
+ use_wireguard_nt: wireguard_options.use_wireguard_nt,
rotation_interval: wireguard_options
.rotation_interval
.map(std::time::Duration::try_from)
@@ -159,6 +156,12 @@ impl TryFrom<proto::TunnelOptions> for mullvad_types::settings::TunnelOptions {
);
FromProtobufTypeError::InvalidArgument("invalid rotation interval")
})?,
+ quantum_resistant: wireguard_options
+ .quantum_resistant
+ .map(mullvad_types::wireguard::QuantumResistantState::try_from)
+ .ok_or(FromProtobufTypeError::InvalidArgument(
+ "missing quantum resistant state",
+ ))??,
},
generic: net::GenericTunnelOptions {
enable_ipv6: generic_options.enable_ipv6,
diff --git a/mullvad-management-interface/src/types/conversions/wireguard.rs b/mullvad-management-interface/src/types/conversions/wireguard.rs
index e90e728c2f..ce2d4c7dba 100644
--- a/mullvad-management-interface/src/types/conversions/wireguard.rs
+++ b/mullvad-management-interface/src/types/conversions/wireguard.rs
@@ -1,3 +1,4 @@
+use super::FromProtobufTypeError;
use crate::types::proto;
use prost_types::Timestamp;
@@ -12,3 +13,40 @@ impl From<mullvad_types::wireguard::PublicKey> for proto::PublicKey {
}
}
}
+
+impl From<mullvad_types::wireguard::QuantumResistantState> for proto::QuantumResistantState {
+ fn from(state: mullvad_types::wireguard::QuantumResistantState) -> Self {
+ match state {
+ mullvad_types::wireguard::QuantumResistantState::Auto => proto::QuantumResistantState {
+ state: i32::from(proto::quantum_resistant_state::State::Auto),
+ },
+ mullvad_types::wireguard::QuantumResistantState::On => proto::QuantumResistantState {
+ state: i32::from(proto::quantum_resistant_state::State::On),
+ },
+ mullvad_types::wireguard::QuantumResistantState::Off => proto::QuantumResistantState {
+ state: i32::from(proto::quantum_resistant_state::State::Off),
+ },
+ }
+ }
+}
+
+impl TryFrom<proto::QuantumResistantState> for mullvad_types::wireguard::QuantumResistantState {
+ type Error = FromProtobufTypeError;
+
+ fn try_from(state: proto::QuantumResistantState) -> Result<Self, Self::Error> {
+ match proto::quantum_resistant_state::State::from_i32(state.state) {
+ Some(proto::quantum_resistant_state::State::Auto) => {
+ Ok(mullvad_types::wireguard::QuantumResistantState::Auto)
+ }
+ Some(proto::quantum_resistant_state::State::On) => {
+ Ok(mullvad_types::wireguard::QuantumResistantState::On)
+ }
+ Some(proto::quantum_resistant_state::State::Off) => {
+ Ok(mullvad_types::wireguard::QuantumResistantState::Off)
+ }
+ None => Err(FromProtobufTypeError::InvalidArgument(
+ "invalid quantum resistance state",
+ )),
+ }
+ }
+}
diff --git a/mullvad-types/src/custom_tunnel.rs b/mullvad-types/src/custom_tunnel.rs
index 2dceb7493d..a3f8c0b264 100644
--- a/mullvad-types/src/custom_tunnel.rs
+++ b/mullvad-types/src/custom_tunnel.rs
@@ -51,7 +51,7 @@ impl CustomTunnelEndpoint {
let parameters = match config {
ConnectionConfig::OpenVpn(config) => openvpn::TunnelParameters {
config,
- options: tunnel_options.openvpn.clone(),
+ options: tunnel_options.openvpn,
generic_options: tunnel_options.generic,
proxy,
#[cfg(target_os = "linux")]
@@ -60,7 +60,7 @@ impl CustomTunnelEndpoint {
.into(),
ConnectionConfig::Wireguard(connection) => wireguard::TunnelParameters {
connection,
- options: tunnel_options.wireguard.options.clone(),
+ options: tunnel_options.wireguard.into_talpid_tunnel_options(),
generic_options: tunnel_options.generic,
obfuscation: None,
}
diff --git a/mullvad-types/src/settings/mod.rs b/mullvad-types/src/settings/mod.rs
index d6949ab0bb..9b88baebc9 100644
--- a/mullvad-types/src/settings/mod.rs
+++ b/mullvad-types/src/settings/mod.rs
@@ -12,7 +12,7 @@ use rand::Rng;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
#[cfg(target_os = "windows")]
use std::{collections::HashSet, path::PathBuf};
-use talpid_types::net::{self, openvpn, GenericTunnelOptions};
+use talpid_types::net::{openvpn, GenericTunnelOptions};
mod dns;
@@ -211,10 +211,7 @@ impl Default for TunnelOptions {
fn default() -> Self {
TunnelOptions {
openvpn: openvpn::TunnelOptions::default(),
- wireguard: wireguard::TunnelOptions {
- options: net::wireguard::TunnelOptions::default(),
- rotation_interval: None,
- },
+ wireguard: wireguard::TunnelOptions::default(),
generic: GenericTunnelOptions {
// Enable IPv6 be default on Android
enable_ipv6: cfg!(target_os = "android"),
diff --git a/mullvad-types/src/wireguard.rs b/mullvad-types/src/wireguard.rs
index fac2adf0d3..5f77d769eb 100644
--- a/mullvad-types/src/wireguard.rs
+++ b/mullvad-types/src/wireguard.rs
@@ -14,6 +14,18 @@ pub const DEFAULT_ROTATION_INTERVAL: Duration = if cfg!(target_os = "android") {
Duration::from_secs(7 * 24 * 60 * 60)
};
+/// Whether to enable or disable quantum resistant tunnels when the setting
+/// is set to `QuantumResistantState::Auto`.
+const QUANTUM_RESISTANT_AUTO_STATE: bool = false;
+
+#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq, Eq)]
+#[serde(rename_all = "lowercase")]
+pub enum QuantumResistantState {
+ Auto,
+ On,
+ Off,
+}
+
/// Contains account specific wireguard data
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
pub struct WireguardData {
@@ -114,7 +126,7 @@ impl Default for RotationInterval {
}
}
-#[derive(Default, Debug, Clone, Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(default)]
#[cfg_attr(target_os = "android", derive(IntoJava))]
#[cfg_attr(
@@ -122,13 +134,59 @@ impl Default for RotationInterval {
jnix(class_name = "net.mullvad.mullvadvpn.model.WireguardTunnelOptions")
)]
pub struct TunnelOptions {
- #[serde(flatten)]
- pub options: wireguard::TunnelOptions,
+ /// MTU for the wireguard tunnel
+ #[cfg_attr(
+ target_os = "android",
+ jnix(map = "|maybe_mtu| maybe_mtu.map(|mtu| mtu as i32)")
+ )]
+ pub mtu: Option<u16>,
+ /// Temporary switch for wireguard-nt
+ #[cfg(windows)]
+ #[serde(rename = "wireguard_nt")]
+ pub use_wireguard_nt: bool,
+ /// Obtain a PSK using the relay config client.
+ #[cfg_attr(
+ target_os = "android",
+ jnix(map = "|state| match state {
+ QuantumResistantState::Auto => None,
+ QuantumResistantState::On => Some(true),
+ QuantumResistantState::Off => Some(false),
+ }")
+ )]
+ pub quantum_resistant: QuantumResistantState,
/// Interval used for automatic key rotation
#[cfg_attr(target_os = "android", jnix(skip))]
pub rotation_interval: Option<RotationInterval>,
}
+#[allow(clippy::derivable_impls)]
+impl Default for TunnelOptions {
+ fn default() -> Self {
+ TunnelOptions {
+ mtu: None,
+ quantum_resistant: QuantumResistantState::Auto,
+ #[cfg(windows)]
+ use_wireguard_nt: true,
+ rotation_interval: None,
+ }
+ }
+}
+
+impl TunnelOptions {
+ pub fn into_talpid_tunnel_options(self) -> wireguard::TunnelOptions {
+ wireguard::TunnelOptions {
+ mtu: self.mtu,
+ #[cfg(windows)]
+ use_wireguard_nt: self.use_wireguard_nt,
+ quantum_resistant: match self.quantum_resistant {
+ QuantumResistantState::Auto => QUANTUM_RESISTANT_AUTO_STATE,
+ QuantumResistantState::On => true,
+ QuantumResistantState::Off => false,
+ },
+ }
+ }
+}
+
/// Represents a published public key
#[derive(Serialize, Deserialize, Clone, Debug)]
#[cfg_attr(target_os = "android", derive(IntoJava))]
diff --git a/talpid-core/src/tunnel/mod.rs b/talpid-core/src/tunnel/mod.rs
index a8d5792d5b..29f3f9c746 100644
--- a/talpid-core/src/tunnel/mod.rs
+++ b/talpid-core/src/tunnel/mod.rs
@@ -143,7 +143,7 @@ impl TunnelMonitor {
let config = talpid_wireguard::config::Config::from_parameters(params)?;
let monitor = talpid_wireguard::WireguardMonitor::start(
config,
- if params.options.use_pq_safe_psk {
+ if params.options.quantum_resistant {
Some(
params
.connection
diff --git a/talpid-types/src/net/mod.rs b/talpid-types/src/net/mod.rs
index bcfe6f7b3c..b957e59a34 100644
--- a/talpid-types/src/net/mod.rs
+++ b/talpid-types/src/net/mod.rs
@@ -18,7 +18,7 @@ pub mod wireguard;
/// TunnelParameters are used to encapsulate all the data needed to start a tunnel. This is enum
/// should be generated by implementations of the trait
/// `talpid-core::tunnel_state_machine::TunnelParametersGenerator`
-#[derive(Clone, Eq, PartialEq, Deserialize, Serialize, Debug)]
+#[derive(Clone, Eq, PartialEq, Debug)]
pub enum TunnelParameters {
OpenVpn(openvpn::TunnelParameters),
Wireguard(wireguard::TunnelParameters),
@@ -37,7 +37,7 @@ impl TunnelParameters {
},
TunnelParameters::Wireguard(params) => TunnelEndpoint {
tunnel_type: TunnelType::Wireguard,
- quantum_resistant: params.options.use_pq_safe_psk,
+ quantum_resistant: params.options.quantum_resistant,
endpoint: params
.connection
.get_exit_endpoint()
diff --git a/talpid-types/src/net/wireguard.rs b/talpid-types/src/net/wireguard.rs
index 8d84ef5a73..181e647cf7 100644
--- a/talpid-types/src/net/wireguard.rs
+++ b/talpid-types/src/net/wireguard.rs
@@ -1,7 +1,5 @@
use crate::net::{Endpoint, GenericTunnelOptions, TransportProtocol};
use ipnetwork::IpNetwork;
-#[cfg(target_os = "android")]
-use jnix::IntoJava;
use rand::rngs::OsRng;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::{
@@ -13,7 +11,7 @@ use zeroize::{Zeroize, ZeroizeOnDrop};
/// Tunnel parameters required to start a `WireguardMonitor`.
/// See [`crate::net::TunnelParameters`].
-#[derive(Clone, Eq, PartialEq, Deserialize, Serialize, Debug)]
+#[derive(Clone, Eq, PartialEq, Debug)]
pub struct TunnelParameters {
pub connection: ConnectionConfig,
pub options: TunnelOptions,
@@ -73,44 +71,15 @@ pub struct TunnelConfig {
}
/// Options in [`TunnelParameters`] that apply to any WireGuard connection.
-#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
-#[serde(default)]
-#[cfg_attr(target_os = "android", derive(IntoJava))]
-#[cfg_attr(
- target_os = "android",
- jnix(package = "net.mullvad.talpid.net.wireguard")
-)]
+#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TunnelOptions {
/// MTU for the wireguard tunnel
- #[cfg_attr(
- target_os = "android",
- jnix(map = "|maybe_mtu| maybe_mtu.map(|mtu| mtu as i32)")
- )]
pub mtu: Option<u16>,
- /// Obtain a PSK using the relay config client.
- pub use_pq_safe_psk: bool,
/// Temporary switch for wireguard-nt
#[cfg(windows)]
- #[serde(default = "default_wgnt_setting")]
- #[serde(rename = "wireguard_nt")]
pub use_wireguard_nt: bool,
-}
-
-#[cfg(windows)]
-fn default_wgnt_setting() -> bool {
- true
-}
-
-#[allow(clippy::derivable_impls)]
-impl Default for TunnelOptions {
- fn default() -> Self {
- Self {
- mtu: None,
- use_pq_safe_psk: false,
- #[cfg(windows)]
- use_wireguard_nt: default_wgnt_setting(),
- }
- }
+ /// Perform PQ-safe PSK exchange when connecting
+ pub quantum_resistant: bool,
}
/// Wireguard x25519 private key