summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJonathan <jonathan@mullvad.net>2022-07-18 15:27:11 +0200
committerJonathan <jonathan@mullvad.net>2022-08-15 10:27:34 +0200
commitf25688f81f53ab3ea15acea853d2dd88e328a433 (patch)
tree56426a570a97de88e726709ee1087564ea38bbe1
parent3cd0deb3e2fb35eceaf217100deed8737d1500c1 (diff)
downloadmullvadvpn-f25688f81f53ab3ea15acea853d2dd88e328a433.tar.xz
mullvadvpn-f25688f81f53ab3ea15acea853d2dd88e328a433.zip
Allow for migrating windows users to WG
Use a potential value between 0 and 1 provided by the API version check to decide if the Windows client should use WireGuard or OpenVpn. This decision is then persisted in the settings in the form of a random value between 0 and 1 where if the value is higher than the value provided by the API the client will use OpenVpn. If there is no value provided by the API then the client will use WireGuard as the migration has concluded.
-rw-r--r--Cargo.lock1
-rw-r--r--mullvad-api/src/lib.rs10
-rw-r--r--mullvad-daemon/src/lib.rs41
-rw-r--r--mullvad-daemon/src/settings.rs11
-rw-r--r--mullvad-daemon/src/version_check.rs13
-rw-r--r--mullvad-relay-selector/src/lib.rs205
-rw-r--r--mullvad-types/Cargo.toml1
-rw-r--r--mullvad-types/src/settings/mod.rs14
-rw-r--r--mullvad-types/src/version.rs7
9 files changed, 233 insertions, 70 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 161335a35d..d0658e6d98 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1727,6 +1727,7 @@ dependencies = [
"jnix",
"lazy_static",
"log",
+ "rand 0.8.5",
"regex",
"serde",
"talpid-types",
diff --git a/mullvad-api/src/lib.rs b/mullvad-api/src/lib.rs
index d967791192..b0222ca244 100644
--- a/mullvad-api/src/lib.rs
+++ b/mullvad-api/src/lib.rs
@@ -477,6 +477,16 @@ pub struct AppVersionResponse {
pub latest: AppVersion,
pub latest_stable: Option<AppVersion>,
pub latest_beta: AppVersion,
+ #[serde(default = "default_wg_threshold")]
+ pub x_threshold_wg_default: f32,
+}
+
+/// Temporary function that will be removed later. Used to generate default wg_threshold.
+/// In case there is no `x_threshold_wg_default` returned by the API result we interpret that to
+/// mean that the migration is done and WireGuard should be the default. In that case the threshold
+/// value should be 1.0
+fn default_wg_threshold() -> f32 {
+ 1.0
}
impl AppVersionProxy {
diff --git a/mullvad-daemon/src/lib.rs b/mullvad-daemon/src/lib.rs
index 2a7799b15c..770a231013 100644
--- a/mullvad-daemon/src/lib.rs
+++ b/mullvad-daemon/src/lib.rs
@@ -586,8 +586,9 @@ where
None
});
let settings = SettingsPersister::load(&settings_dir).await;
+ let app_version_info = version_check::load_cache(&cache_dir).await;
- let initial_selector_config = new_selector_config(&settings);
+ let initial_selector_config = new_selector_config(&settings, &app_version_info);
let relay_selector = RelaySelector::new(initial_selector_config, &resource_dir, &cache_dir);
let proxy_provider =
@@ -697,7 +698,6 @@ where
on_relay_list_update,
);
- let app_version_info = version_check::load_cache(&cache_dir).await;
let (version_updater, version_updater_handle) = version_check::VersionUpdater::new(
api_handle.clone(),
api_availability.clone(),
@@ -822,7 +822,7 @@ where
Command(command) => self.handle_command(command).await,
TriggerShutdown => self.trigger_shutdown_event(),
NewAppVersionInfo(app_version_info) => {
- self.handle_new_app_version_info(app_version_info)
+ self.handle_new_app_version_info(app_version_info);
}
DeviceEvent(event) => self.handle_device_event(event).await,
DeviceMigrationEvent(event) => self.handle_device_migration_event(event).await,
@@ -1032,6 +1032,8 @@ where
fn handle_new_app_version_info(&mut self, app_version_info: AppVersionInfo) {
self.app_version_info = Some(app_version_info.clone());
+ self.relay_selector
+ .set_config(new_selector_config(&self.settings, &self.app_version_info));
self.event_listener.notify_app_version(app_version_info);
}
@@ -1742,7 +1744,7 @@ where
self.event_listener
.notify_settings(self.settings.to_settings());
self.relay_selector
- .set_config(new_selector_config(&self.settings));
+ .set_config(new_selector_config(&self.settings, &self.app_version_info));
log::info!("Initiating tunnel restart because the relay settings changed");
self.reconnect_tunnel();
}
@@ -1884,7 +1886,7 @@ where
self.event_listener
.notify_settings(self.settings.to_settings());
self.relay_selector
- .set_config(new_selector_config(&self.settings));
+ .set_config(new_selector_config(&self.settings, &self.app_version_info));
if let Err(error) = self.api_handle.service().next_api_endpoint().await {
log::error!("Failed to rotate API endpoint: {}", error);
}
@@ -1914,7 +1916,7 @@ where
self.event_listener
.notify_settings(self.settings.to_settings());
self.relay_selector
- .set_config(new_selector_config(&self.settings));
+ .set_config(new_selector_config(&self.settings, &self.app_version_info));
self.reconnect_tunnel();
}
Self::oneshot_send(tx, Ok(()), "set_obfuscation_settings");
@@ -1940,7 +1942,7 @@ where
self.event_listener
.notify_settings(self.settings.to_settings());
self.relay_selector
- .set_config(new_selector_config(&self.settings));
+ .set_config(new_selector_config(&self.settings, &self.app_version_info));
log::info!("Initiating tunnel restart because bridge state changed");
self.reconnect_tunnel();
}
@@ -2253,11 +2255,34 @@ impl DaemonShutdownHandle {
}
}
-fn new_selector_config(settings: &Settings) -> SelectorConfig {
+fn new_selector_config(
+ settings: &Settings,
+ app_version_info: &Option<AppVersionInfo>,
+) -> SelectorConfig {
+ // In case of the app not having a version we safety default to OpenVPN to guard against the
+ // case where some error causes users to not recieve a version and in that case all going to
+ // wireguard. Magic number 0.0 implies that 0% of users should use Wireguard.
+ // This will be removed in the future when we the migration is done.
+ let wg_migration_threshold = app_version_info
+ .as_ref()
+ .map(|f| f.wg_migration_threshold)
+ .unwrap_or(0.0);
+
+ let default_tunnel_type = if cfg!(target_os = "windows") {
+ if wg_migration_threshold >= settings.wg_migration_rand_num {
+ TunnelType::Wireguard
+ } else {
+ TunnelType::OpenVpn
+ }
+ } else {
+ TunnelType::Wireguard
+ };
+
SelectorConfig {
relay_settings: settings.get_relay_settings(),
bridge_state: settings.get_bridge_state(),
bridge_settings: settings.bridge_settings.clone(),
obfuscation_settings: settings.obfuscation_settings.clone(),
+ default_tunnel_type,
}
}
diff --git a/mullvad-daemon/src/settings.rs b/mullvad-daemon/src/settings.rs
index e69ca8316f..5ca3ff8908 100644
--- a/mullvad-daemon/src/settings.rs
+++ b/mullvad-daemon/src/settings.rs
@@ -5,6 +5,7 @@ use mullvad_types::{
settings::{DnsOptions, Settings},
wireguard::RotationInterval,
};
+use rand::Rng;
#[cfg(target_os = "windows")]
use std::collections::HashSet;
use std::{
@@ -69,6 +70,15 @@ impl SettingsPersister {
}
};
+ // If the settings file did not contain a wg_migration_rand_num then it will be initialized
+ // to -1.0 by serde. This block ensures that this value is correctly intitialzed to a
+ // percentage.
+ if settings.wg_migration_rand_num < 0.0 || settings.wg_migration_rand_num > 1.0 {
+ let mut rng = rand::thread_rng();
+ settings.wg_migration_rand_num = rng.gen_range(0.0..=1.0);
+ should_save |= true
+ }
+
// Force IPv6 to be enabled on Android
if cfg!(target_os = "android") {
should_save |=
@@ -185,6 +195,7 @@ impl SettingsPersister {
/// is being run or not.
fn default_settings() -> Settings {
let mut settings = Settings::default();
+
if crate::version::is_beta_version() {
settings.show_beta_releases = true;
}
diff --git a/mullvad-daemon/src/version_check.rs b/mullvad-daemon/src/version_check.rs
index 6e1a9bc568..72126b7862 100644
--- a/mullvad-daemon/src/version_check.rs
+++ b/mullvad-daemon/src/version_check.rs
@@ -47,7 +47,7 @@ const PLATFORM: &str = "windows";
#[cfg(target_os = "android")]
const PLATFORM: &str = "android";
-#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
+#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
struct CachedAppVersionInfo {
#[serde(flatten)]
pub version_info: AppVersionInfo,
@@ -281,11 +281,20 @@ impl VersionUpdater {
self.show_beta_releases || is_beta_version(),
);
+ let wg_migration_threshold = if response.x_threshold_wg_default.is_nan() {
+ // If the value should for some strange reason be NaN then safe default to 0.0
+ 0.0
+ } else {
+ // Make sure that the returned value is between 0% and 100%
+ response.x_threshold_wg_default.clamp(0.0, 1.0)
+ };
+
AppVersionInfo {
supported: response.supported,
latest_stable: response.latest_stable.unwrap_or_else(|| "".to_owned()),
latest_beta: response.latest_beta,
suggested_upgrade,
+ wg_migration_threshold,
}
}
@@ -375,6 +384,7 @@ impl VersionUpdater {
latest_stable: last_app_version_info.latest_stable,
latest_beta: last_app_version_info.latest_beta,
suggested_upgrade,
+ wg_migration_threshold: last_app_version_info.wg_migration_threshold,
}).await;
}
}
@@ -468,6 +478,7 @@ fn dev_version_cache() -> AppVersionInfo {
latest_stable: PRODUCT_VERSION.to_owned(),
latest_beta: PRODUCT_VERSION.to_owned(),
suggested_upgrade: None,
+ wg_migration_threshold: 1.0,
}
}
diff --git a/mullvad-relay-selector/src/lib.rs b/mullvad-relay-selector/src/lib.rs
index d9a16ff748..961357abf2 100644
--- a/mullvad-relay-selector/src/lib.rs
+++ b/mullvad-relay-selector/src/lib.rs
@@ -169,6 +169,7 @@ pub struct SelectorConfig {
pub bridge_state: BridgeState,
pub bridge_settings: BridgeSettings,
pub obfuscation_settings: ObfuscationSettings,
+ pub default_tunnel_type: TunnelType,
}
#[derive(Clone)]
@@ -231,8 +232,12 @@ impl RelaySelector {
Ok((SelectedRelay::Custom(custom_relay.clone()), None, None))
}
RelaySettings::Normal(constraints) => {
- let relay =
- self.get_tunnel_endpoint(constraints, config.bridge_state, retry_attempt)?;
+ let relay = self.get_tunnel_endpoint(
+ constraints,
+ config.bridge_state,
+ retry_attempt,
+ config.default_tunnel_type,
+ )?;
let bridge = match relay.endpoint {
MullvadEndpoint::OpenVpn(endpoint)
if endpoint.protocol == TransportProtocol::Tcp =>
@@ -271,6 +276,7 @@ impl RelaySelector {
relay_constraints: &RelayConstraints,
bridge_state: BridgeState,
retry_attempt: u32,
+ default_tunnel_type: TunnelType,
) -> Result<NormalSelectedRelay, Error> {
match relay_constraints.tunnel_protocol {
Constraint::Only(TunnelType::OpenVpn) => self.get_openvpn_endpoint(
@@ -289,9 +295,12 @@ impl RelaySelector {
&relay_constraints.wireguard_constraints,
retry_attempt,
),
- Constraint::Any => {
- self.get_any_tunnel_endpoint(relay_constraints, bridge_state, retry_attempt)
- }
+ Constraint::Any => self.get_any_tunnel_endpoint(
+ relay_constraints,
+ bridge_state,
+ retry_attempt,
+ default_tunnel_type,
+ ),
}
}
@@ -576,9 +585,14 @@ impl RelaySelector {
relay_constraints: &RelayConstraints,
bridge_state: BridgeState,
retry_attempt: u32,
+ default_tunnel_type: TunnelType,
) -> Result<NormalSelectedRelay, Error> {
- let preferred_constraints =
- self.preferred_constraints(relay_constraints, bridge_state, retry_attempt);
+ let preferred_constraints = self.preferred_constraints(
+ relay_constraints,
+ bridge_state,
+ retry_attempt,
+ default_tunnel_type,
+ );
if let Ok(result) = self.get_multihop_tunnel_endpoint_internal(&preferred_constraints) {
log::debug!(
@@ -604,10 +618,12 @@ impl RelaySelector {
original_constraints: &RelayConstraints,
bridge_state: BridgeState,
retry_attempt: u32,
+ default_tunnel_type: TunnelType,
) -> RelayConstraints {
let (preferred_port, preferred_protocol, preferred_tunnel) = self
.preferred_tunnel_constraints(
retry_attempt,
+ default_tunnel_type,
&original_constraints.location,
&original_constraints.providers,
&original_constraints.ownership,
@@ -929,40 +945,46 @@ impl RelaySelector {
fn preferred_tunnel_constraints(
&self,
retry_attempt: u32,
+ default_tunnel_type: TunnelType,
location_constraint: &Constraint<LocationConstraint>,
providers_constraint: &Constraint<Providers>,
ownership_constraint: &Constraint<Ownership>,
) -> (Constraint<u16>, TransportProtocol, TunnelType) {
- #[cfg(target_os = "windows")]
- {
- let location_supports_openvpn =
- self.parsed_relays.lock().relays().iter().any(|relay| {
- relay.active
- && relay.endpoint_data == RelayEndpointData::Openvpn
- && location_constraint.matches(relay)
- && providers_constraint.matches(relay)
- && ownership_constraint.matches(relay)
- });
- if location_supports_openvpn {
- let (preferred_port, preferred_protocol) =
- Self::preferred_openvpn_constraints(retry_attempt);
- return (preferred_port, preferred_protocol, TunnelType::OpenVpn);
+ match default_tunnel_type {
+ TunnelType::OpenVpn => {
+ let location_supports_openvpn =
+ self.parsed_relays.lock().relays().iter().any(|relay| {
+ relay.active
+ && relay.endpoint_data == RelayEndpointData::Openvpn
+ && location_constraint.matches(relay)
+ && providers_constraint.matches(relay)
+ && ownership_constraint.matches(relay)
+ });
+
+ if location_supports_openvpn {
+ let (preferred_port, preferred_protocol) =
+ Self::preferred_openvpn_constraints(retry_attempt);
+ return (preferred_port, preferred_protocol, TunnelType::OpenVpn);
+ }
}
- }
+ TunnelType::Wireguard => {
+ let location_supports_wireguard =
+ self.parsed_relays.lock().relays().iter().any(|relay| {
+ relay.active
+ && matches!(relay.endpoint_data, RelayEndpointData::Wireguard(_))
+ && location_constraint.matches(relay)
+ && providers_constraint.matches(relay)
+ && ownership_constraint.matches(relay)
+ });
- let location_supports_wireguard = self.parsed_relays.lock().relays().iter().any(|relay| {
- relay.active
- && matches!(relay.endpoint_data, RelayEndpointData::Wireguard(_))
- && location_constraint.matches(relay)
- && providers_constraint.matches(relay)
- && ownership_constraint.matches(relay)
- });
- // If location does not support WireGuard, defer to preferred OpenVPN tunnel
- // constraints
- if !location_supports_wireguard {
- let (preferred_port, preferred_protocol) =
- Self::preferred_openvpn_constraints(retry_attempt);
- return (preferred_port, preferred_protocol, TunnelType::OpenVpn);
+ // If location does not support WireGuard, defer to preferred OpenVPN tunnel
+ // constraints
+ if !location_supports_wireguard {
+ let (preferred_port, preferred_protocol) =
+ Self::preferred_openvpn_constraints(retry_attempt);
+ return (preferred_port, preferred_protocol, TunnelType::OpenVpn);
+ }
+ }
}
// Try out WireGuard in the first two connection attempts, first with any port,
@@ -1318,6 +1340,7 @@ mod test {
..Default::default()
},
bridge_state: BridgeState::Auto,
+ default_tunnel_type: TunnelType::Wireguard,
})),
}
}
@@ -1338,8 +1361,12 @@ mod test {
..RelayConstraints::default()
};
- let preferred =
- relay_selector.preferred_constraints(&relay_constraints, BridgeState::Off, 0);
+ let preferred = relay_selector.preferred_constraints(
+ &relay_constraints,
+ BridgeState::Off,
+ 0,
+ TunnelType::Wireguard,
+ );
assert_eq!(
preferred.tunnel_protocol,
Constraint::Only(TunnelType::Wireguard)
@@ -1347,7 +1374,12 @@ mod test {
for attempt in 0..10 {
assert!(relay_selector
- .get_any_tunnel_endpoint(&relay_constraints, BridgeState::Off, attempt)
+ .get_any_tunnel_endpoint(
+ &relay_constraints,
+ BridgeState::Off,
+ attempt,
+ TunnelType::Wireguard,
+ )
.is_ok());
}
@@ -1363,8 +1395,12 @@ mod test {
..RelayConstraints::default()
};
- let preferred =
- relay_selector.preferred_constraints(&relay_constraints, BridgeState::Off, 0);
+ let preferred = relay_selector.preferred_constraints(
+ &relay_constraints,
+ BridgeState::Off,
+ 0,
+ TunnelType::Wireguard,
+ );
assert_eq!(
preferred.tunnel_protocol,
Constraint::Only(TunnelType::OpenVpn)
@@ -1372,7 +1408,12 @@ mod test {
for attempt in 0..10 {
assert!(relay_selector
- .get_any_tunnel_endpoint(&relay_constraints, BridgeState::Off, attempt)
+ .get_any_tunnel_endpoint(
+ &relay_constraints,
+ BridgeState::Off,
+ attempt,
+ TunnelType::Wireguard,
+ )
.is_ok());
}
@@ -1385,6 +1426,7 @@ mod test {
&relay_constraints,
BridgeState::Off,
attempt,
+ TunnelType::OpenVpn,
);
assert_eq!(
preferred.tunnel_protocol,
@@ -1394,6 +1436,7 @@ mod test {
&relay_constraints,
BridgeState::Off,
attempt,
+ TunnelType::OpenVpn,
) {
Ok(result) if matches!(result.endpoint, MullvadEndpoint::OpenVpn(_)) => (),
_ => panic!("OpenVPN endpoint was not selected"),
@@ -1428,14 +1471,24 @@ mod test {
// The same host cannot be used for entry and exit
assert!(relay_selector
- .get_tunnel_endpoint(&relay_constraints, BridgeState::Off, 0)
+ .get_tunnel_endpoint(
+ &relay_constraints,
+ BridgeState::Off,
+ 0,
+ TunnelType::Wireguard,
+ )
.is_err());
relay_constraints.wireguard_constraints.entry_location = Constraint::Only(location2);
// If the entry and exit differ, this should succeed
assert!(relay_selector
- .get_tunnel_endpoint(&relay_constraints, BridgeState::Off, 0)
+ .get_tunnel_endpoint(
+ &relay_constraints,
+ BridgeState::Off,
+ 0,
+ TunnelType::Wireguard,
+ )
.is_ok());
}
@@ -1464,7 +1517,7 @@ mod test {
// The exit must not equal the entry
let exit_relay = relay_selector
- .get_tunnel_endpoint(&relay_constraints, BridgeState::Off, 0)
+ .get_tunnel_endpoint(&relay_constraints, BridgeState::Off, 0, TunnelType::OpenVpn)
.map_err(|error| error.to_string())?
.exit_relay;
@@ -1479,7 +1532,12 @@ mod test {
endpoint,
..
} = relay_selector
- .get_tunnel_endpoint(&relay_constraints, BridgeState::Off, 0)
+ .get_tunnel_endpoint(
+ &relay_constraints,
+ BridgeState::Off,
+ 0,
+ TunnelType::Wireguard,
+ )
.map_err(|error| error.to_string())?;
assert_eq!(exit_relay.hostname, specific_hostname);
@@ -1513,8 +1571,12 @@ mod test {
port: Constraint::Any,
});
- let preferred =
- relay_selector.preferred_constraints(&relay_constraints, BridgeState::On, 0);
+ let preferred = relay_selector.preferred_constraints(
+ &relay_constraints,
+ BridgeState::On,
+ 0,
+ TunnelType::Wireguard,
+ );
assert_eq!(
preferred.tunnel_protocol,
Constraint::Only(TunnelType::OpenVpn)
@@ -1539,8 +1601,12 @@ mod test {
tunnel_protocol: Constraint::Any,
..RelayConstraints::default()
};
- let preferred =
- relay_selector.preferred_constraints(&relay_constraints, BridgeState::On, 0);
+ let preferred = relay_selector.preferred_constraints(
+ &relay_constraints,
+ BridgeState::On,
+ 0,
+ TunnelType::Wireguard,
+ );
assert_eq!(
preferred.tunnel_protocol,
Constraint::Only(TunnelType::Wireguard)
@@ -1558,15 +1624,23 @@ mod test {
});
#[cfg(all(unix, not(target_os = "android")))]
{
- let preferred =
- relay_selector.preferred_constraints(&relay_constraints, BridgeState::On, 0);
+ let preferred = relay_selector.preferred_constraints(
+ &relay_constraints,
+ BridgeState::On,
+ 0,
+ TunnelType::Wireguard,
+ );
assert_eq!(
preferred.tunnel_protocol,
Constraint::Only(TunnelType::Wireguard)
);
}
- let preferred =
- relay_selector.preferred_constraints(&relay_constraints, BridgeState::On, 2);
+ let preferred = relay_selector.preferred_constraints(
+ &relay_constraints,
+ BridgeState::On,
+ 2,
+ TunnelType::Wireguard,
+ );
assert_eq!(
preferred.tunnel_protocol,
Constraint::Only(TunnelType::OpenVpn)
@@ -1597,7 +1671,13 @@ mod test {
let relay_selector = new_relay_selector();
- let result = relay_selector.get_tunnel_endpoint(&relay_constraints, BridgeState::Off, 0)
+ let default_tunnel_type = if cfg!(target_os = "windows") {
+ TunnelType::OpenVpn
+ } else {
+ TunnelType::Wireguard
+ };
+
+ let result = relay_selector.get_tunnel_endpoint(&relay_constraints, BridgeState::Off, 0, default_tunnel_type)
.expect("Failed to get relay when tunnel constraints are set to Any and retrying the selection");
// Windows will ignore WireGuard until WireGuard is supported well enough
// TODO: Remove this caveat once Windows defaults to using WireGuard
@@ -1649,7 +1729,7 @@ mod test {
fn test_selecting_wireguard_location_will_consider_multihop() {
let relay_selector = new_relay_selector();
- let result = relay_selector.get_tunnel_endpoint(&WIREGUARD_MULTIHOP_CONSTRAINTS, BridgeState::Off, 0)
+ let result = relay_selector.get_tunnel_endpoint(&WIREGUARD_MULTIHOP_CONSTRAINTS, BridgeState::Off, 0, TunnelType::Wireguard)
.expect("Failed to get relay when tunnel constraints are set to default WireGuard multihop constraints");
assert!(result.entry_relay.is_some());
@@ -1660,7 +1740,7 @@ mod test {
fn test_selecting_wg_endpoint_with_udp2tcp_obfuscation() {
let relay_selector = new_relay_selector();
- let result = relay_selector.get_tunnel_endpoint(&WIREGUARD_SINGLEHOP_CONSTRAINTS, BridgeState::Off, 0)
+ let result = relay_selector.get_tunnel_endpoint(&WIREGUARD_SINGLEHOP_CONSTRAINTS, BridgeState::Off, 0, TunnelType::Wireguard)
.expect("Failed to get relay when tunnel constraints are set to default WireGuard constraints");
assert!(result.entry_relay.is_none());
@@ -1689,7 +1769,7 @@ mod test {
fn test_selecting_wg_endpoint_with_auto_obfuscation() {
let relay_selector = new_relay_selector();
- let result = relay_selector.get_tunnel_endpoint(&WIREGUARD_SINGLEHOP_CONSTRAINTS, BridgeState::Off, 0)
+ let result = relay_selector.get_tunnel_endpoint(&WIREGUARD_SINGLEHOP_CONSTRAINTS, BridgeState::Off, 0, TunnelType::Wireguard)
.expect("Failed to get relay when tunnel constraints are set to default WireGuard constraints");
assert!(result.entry_relay.is_none());
@@ -1729,7 +1809,12 @@ mod test {
for attempt in 0..1000 {
let result = relay_selector
- .get_tunnel_endpoint(&WIREGUARD_SINGLEHOP_CONSTRAINTS, BridgeState::Off, attempt)
+ .get_tunnel_endpoint(
+ &WIREGUARD_SINGLEHOP_CONSTRAINTS,
+ BridgeState::Off,
+ attempt,
+ TunnelType::Wireguard,
+ )
.expect("Failed to select a WireGuard relay");
assert!(result.entry_relay.is_none());
@@ -1765,7 +1850,7 @@ mod test {
for i in 0..10 {
constraints.ownership = Constraint::Only(Ownership::MullvadOwned);
let relay = relay_selector
- .get_tunnel_endpoint(&constraints, BridgeState::Auto, i)
+ .get_tunnel_endpoint(&constraints, BridgeState::Auto, i, TunnelType::Wireguard)
.unwrap();
assert!(matches!(
relay,
@@ -1777,7 +1862,7 @@ mod test {
constraints.ownership = Constraint::Only(Ownership::Rented);
let relay = relay_selector
- .get_tunnel_endpoint(&constraints, BridgeState::Auto, i)
+ .get_tunnel_endpoint(&constraints, BridgeState::Auto, i, TunnelType::Wireguard)
.unwrap();
assert!(matches!(
relay,
diff --git a/mullvad-types/Cargo.toml b/mullvad-types/Cargo.toml
index 94a48c5538..c450e4e353 100644
--- a/mullvad-types/Cargo.toml
+++ b/mullvad-types/Cargo.toml
@@ -15,6 +15,7 @@ lazy_static = "1.1.0"
log = "0.4"
regex = "1"
serde = { version = "1.0", features = ["derive"] }
+rand = "0.8"
talpid-types = { path = "../talpid-types" }
diff --git a/mullvad-types/src/settings/mod.rs b/mullvad-types/src/settings/mod.rs
index 7bfff42824..d7cc62e605 100644
--- a/mullvad-types/src/settings/mod.rs
+++ b/mullvad-types/src/settings/mod.rs
@@ -8,6 +8,7 @@ use crate::{
};
#[cfg(target_os = "android")]
use jnix::IntoJava;
+use rand::Rng;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
#[cfg(target_os = "windows")]
use std::{collections::HashSet, path::PathBuf};
@@ -88,11 +89,23 @@ pub struct Settings {
/// Split tunneling settings
#[cfg(windows)]
pub split_tunnel: SplitTunnelSettings,
+ /// Temporary variable for a random number between 0 and 1 that determines if the user should
+ /// use wireguard or openvpn when the automatic feature is set. This variable will be removed
+ /// in future versions.
+ /// A value of -1.0 implies that the variable should be initialized to a random number.
+ /// NOTE: This field will be removed completely in future versions.
+ #[serde(default = "out_of_range_wg_migration_rand_num")]
+ #[cfg_attr(target_os = "android", jnix(skip))]
+ pub wg_migration_rand_num: f32,
/// Specifies settings schema version
#[cfg_attr(target_os = "android", jnix(skip))]
settings_version: SettingsVersion,
}
+fn out_of_range_wg_migration_rand_num() -> f32 {
+ -1.0
+}
+
#[cfg(windows)]
#[derive(Debug, Clone, Default, Deserialize, Serialize, PartialEq)]
pub struct SplitTunnelSettings {
@@ -120,6 +133,7 @@ impl Default for Settings {
auto_connect: false,
tunnel_options: TunnelOptions::default(),
show_beta_releases: false,
+ wg_migration_rand_num: rand::thread_rng().gen_range(0.0..=1.0),
#[cfg(windows)]
split_tunnel: SplitTunnelSettings::default(),
settings_version: CURRENT_SETTINGS_VERSION,
diff --git a/mullvad-types/src/version.rs b/mullvad-types/src/version.rs
index 8040b181b0..0bcb6ce7da 100644
--- a/mullvad-types/src/version.rs
+++ b/mullvad-types/src/version.rs
@@ -15,7 +15,7 @@ lazy_static::lazy_static! {
/// AppVersionInfo represents the current stable and the current latest release versions of the
/// Mullvad VPN app.
-#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
+#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[cfg_attr(target_os = "android", derive(IntoJava))]
#[cfg_attr(target_os = "android", jnix(package = "net.mullvad.mullvadvpn.model"))]
pub struct AppVersionInfo {
@@ -35,6 +35,11 @@ pub struct AppVersionInfo {
pub latest_beta: AppVersion,
/// Whether should update to newer version
pub suggested_upgrade: Option<AppVersion>,
+ /// Temporary field provided by the API used to decide if a user should default to Wireguard or
+ /// OpenVpn. Represents the percentage of users which should use Wireguard.
+ /// NOTE: This field will be removed completely in future versions.
+ #[cfg_attr(target_os = "android", jnix(skip))]
+ pub wg_migration_threshold: f32,
}
pub type AppVersion = String;