summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorDavid Lönnhager <david.l@mullvad.net>2022-05-04 16:28:25 +0200
committerDavid Lönnhager <david.l@mullvad.net>2022-05-09 17:19:13 +0200
commitaeef04647359ceb42370e5fed0b16a07a388b852 (patch)
tree783c92515d0c784e31cbd870df44a3a8bb112a5a
parente08b1c0e00c8e1526b428818c4feed05e8a7f334 (diff)
downloadmullvadvpn-aeef04647359ceb42370e5fed0b16a07a388b852.tar.xz
mullvadvpn-aeef04647359ceb42370e5fed0b16a07a388b852.zip
Add server ownership constraint to the daemon and CLI
-rw-r--r--mullvad-cli/src/cmds/bridge.rs46
-rw-r--r--mullvad-cli/src/cmds/relay.rs44
-rw-r--r--mullvad-management-interface/proto/management_interface.proto13
-rw-r--r--mullvad-management-interface/src/types.rs50
-rw-r--r--mullvad-relay-selector/src/lib.rs26
-rw-r--r--mullvad-relay-selector/src/matcher.rs12
-rw-r--r--mullvad-types/src/relay_constraints.rs53
7 files changed, 227 insertions, 17 deletions
diff --git a/mullvad-cli/src/cmds/bridge.rs b/mullvad-cli/src/cmds/bridge.rs
index 40afc93b3b..3f00a7f69a 100644
--- a/mullvad-cli/src/cmds/bridge.rs
+++ b/mullvad-cli/src/cmds/bridge.rs
@@ -59,6 +59,19 @@ fn create_bridge_set_subcommand() -> clap::App<'static> {
.required(true),
),
)
+ .subcommand(
+ clap::App::new("ownership")
+ .about(
+ "Filters bridges based on ownership. The 'list' \
+ command shows the available relays and whether they're rented.",
+ )
+ .arg(
+ clap::Arg::new("ownership")
+ .help("Ownership preference, or 'any' for no preference.")
+ .possible_values(&["any", "owned", "rented"])
+ .required(true),
+ ),
+ )
.subcommand(location::get_subcommand().about(
"Set country or city to select bridge relays from. Use the 'list' \
command to show available alternatives.",
@@ -186,6 +199,9 @@ impl Bridge {
Some(("provider", provider_matches)) => {
Self::handle_set_bridge_provider(provider_matches).await
}
+ Some(("ownership", ownership_matches)) => {
+ Self::handle_set_bridge_ownership(ownership_matches).await
+ }
Some(("custom", custom_matches)) => {
Self::handle_bridge_set_custom_settings(custom_matches).await
}
@@ -220,7 +236,12 @@ impl Bridge {
}
async fn handle_set_bridge_location(matches: &clap::ArgMatches) -> Result<()> {
- Self::update_bridge_settings(Some(location::get_constraint_from_args(matches)), None).await
+ Self::update_bridge_settings(
+ Some(location::get_constraint_from_args(matches)),
+ None,
+ None,
+ )
+ .await
}
async fn handle_set_bridge_provider(matches: &clap::ArgMatches) -> Result<()> {
@@ -231,12 +252,19 @@ impl Bridge {
providers
};
- Self::update_bridge_settings(None, Some(providers)).await
+ Self::update_bridge_settings(None, Some(providers), None).await
+ }
+
+ async fn handle_set_bridge_ownership(matches: &clap::ArgMatches) -> Result<()> {
+ let ownership =
+ super::relay::parse_ownership_constraint(matches.value_of("ownership").unwrap());
+ Self::update_bridge_settings(None, None, Some(ownership)).await
}
async fn update_bridge_settings(
location: Option<types::RelayLocation>,
providers: Option<Vec<String>>,
+ ownership: Option<types::Ownership>,
) -> Result<()> {
let mut rpc = new_rpc_client().await?;
let settings = rpc.get_settings(()).await?.into_inner();
@@ -251,6 +279,9 @@ impl Bridge {
constraints.providers =
types::try_providers_constraint_from_proto(&new_providers).unwrap();
}
+ if let Some(new_ownership) = ownership {
+ constraints.ownership = types::ownership_constraint_from_proto(new_ownership);
+ }
constraints
}
_ => {
@@ -258,10 +289,14 @@ impl Bridge {
let providers =
types::try_providers_constraint_from_proto(&providers.unwrap_or_default())
.unwrap();
+ let ownership = ownership
+ .map(types::ownership_constraint_from_proto)
+ .unwrap_or_default();
BridgeConstraints {
location,
providers,
+ ownership,
}
}
};
@@ -433,8 +468,13 @@ impl Bridge {
city.name, city.code, city.latitude, city.longitude
);
for relay in &city.relays {
+ let ownership = if relay.owned {
+ "Mullvad-owned"
+ } else {
+ "rented"
+ };
println!(
- "\t\t{} ({}) - hosted by {}",
+ "\t\t{} ({}) - hosted by {} ({ownership})",
relay.hostname, relay.ipv4_addr_in, relay.provider
);
}
diff --git a/mullvad-cli/src/cmds/relay.rs b/mullvad-cli/src/cmds/relay.rs
index c11ee82158..d0d75dea20 100644
--- a/mullvad-cli/src/cmds/relay.rs
+++ b/mullvad-cli/src/cmds/relay.rs
@@ -124,6 +124,17 @@ impl Command for Relay {
)
)
.subcommand(
+ clap::App::new("ownership")
+ .about("Filters relays based on ownership. The 'list' \
+ command shows the available relays and whether they're rented.")
+ .arg(
+ clap::Arg::new("ownership")
+ .help("Ownership preference, or 'any' for no preference.")
+ .possible_values(&["any", "owned", "rented"])
+ .required(true)
+ )
+ )
+ .subcommand(
clap::App::new("tunnel")
.about("Set tunnel protocol-specific constraints.")
.setting(clap::AppSettings::SubcommandRequiredElseHelp)
@@ -226,6 +237,8 @@ impl Relay {
self.set_hostname(relay_matches).await
} else if let Some(providers_matches) = matches.subcommand_matches("provider") {
self.set_providers(providers_matches).await
+ } else if let Some(ownership_matches) = matches.subcommand_matches("ownership") {
+ self.set_ownership(ownership_matches).await
} else if let Some(matches) = matches.subcommand_matches("tunnel") {
if let Some(tunnel_matches) = matches.subcommand_matches("openvpn") {
self.set_openvpn_constraints(tunnel_matches).await
@@ -483,6 +496,21 @@ impl Relay {
.await
}
+ async fn set_ownership(&self, matches: &clap::ArgMatches) -> Result<()> {
+ let ownership = parse_ownership_constraint(matches.value_of("ownership").unwrap());
+ self.update_constraints(types::RelaySettingsUpdate {
+ r#type: Some(types::relay_settings_update::Type::Normal(
+ types::NormalRelaySettingsUpdate {
+ ownership: Some(types::OwnershipUpdate {
+ ownership: ownership as i32,
+ }),
+ ..Default::default()
+ },
+ )),
+ })
+ .await
+ }
+
async fn set_openvpn_constraints(&self, matches: &clap::ArgMatches) -> Result<()> {
let mut openvpn_constraints = {
let mut rpc = new_rpc_client().await?;
@@ -646,12 +674,17 @@ impl Relay {
(false, true) => "WireGuard",
_ => unreachable!("Bug in relay filtering earlier on"),
};
+ let ownership = if relay.owned {
+ "Mullvad-owned"
+ } else {
+ "rented"
+ };
let mut addresses = vec![&relay.ipv4_addr_in];
if !relay.ipv6_addr_in.is_empty() {
addresses.push(&relay.ipv6_addr_in);
}
println!(
- "\t\t{} ({}) - {}, hosted by {}",
+ "\t\t{} ({}) - {}, hosted by {} ({ownership})",
relay.hostname,
addresses.iter().join(", "),
support_msg,
@@ -801,3 +834,12 @@ fn parse_transport_port(
)),
}
}
+
+pub fn parse_ownership_constraint(constraint: &str) -> types::Ownership {
+ match constraint {
+ "any" => types::Ownership::Any,
+ "owned" => types::Ownership::MullvadOwned,
+ "rented" => types::Ownership::Rented,
+ _ => unreachable!(),
+ }
+}
diff --git a/mullvad-management-interface/proto/management_interface.proto b/mullvad-management-interface/proto/management_interface.proto
index ef69be0706..c14d621cac 100644
--- a/mullvad-management-interface/proto/management_interface.proto
+++ b/mullvad-management-interface/proto/management_interface.proto
@@ -239,10 +239,17 @@ message GeoIpLocation {
string obfuscator_hostname = 11;
}
+enum Ownership {
+ ANY = 0;
+ MULLVAD_OWNED = 1;
+ RENTED = 2;
+}
+
message BridgeSettings {
message BridgeConstraints {
RelayLocation location = 1;
repeated string providers = 2;
+ Ownership ownership = 3;
}
message LocalProxySettings {
@@ -335,6 +342,7 @@ message NormalRelaySettings {
TunnelTypeConstraint tunnel_type = 3;
WireguardConstraints wireguard_constraints = 4;
OpenvpnConstraints openvpn_constraints = 5;
+ Ownership ownership = 6;
}
// Constraints are only updated for fields that are provided
@@ -344,6 +352,7 @@ message NormalRelaySettingsUpdate {
TunnelTypeUpdate tunnel_type = 3;
WireguardConstraints wireguard_constraints = 4;
OpenvpnConstraints openvpn_constraints = 5;
+ OwnershipUpdate ownership = 6;
}
message ProviderUpdate {
@@ -363,6 +372,10 @@ message OpenvpnConstraints {
TransportPort port = 1;
}
+message OwnershipUpdate {
+ Ownership ownership = 1;
+}
+
enum IpVersion {
V4 = 0;
V6 = 1;
diff --git a/mullvad-management-interface/src/types.rs b/mullvad-management-interface/src/types.rs
index d685899256..2b45fbe840 100644
--- a/mullvad-management-interface/src/types.rs
+++ b/mullvad-management-interface/src/types.rs
@@ -501,6 +501,7 @@ impl From<mullvad_types::relay_constraints::BridgeSettings> for BridgeSettings {
.option()
.map(RelayLocation::from),
providers: convert_providers_constraint(&constraints.providers),
+ ownership: convert_ownership_constraint(&constraints.ownership) as i32,
})
}
MullvadBridgeSettings::Custom(proxy_settings) => match proxy_settings {
@@ -553,6 +554,7 @@ impl From<mullvad_types::relay_constraints::RelaySettings> for RelaySettings {
relay_settings::Endpoint::Normal(NormalRelaySettings {
location: constraints.location.option().map(RelayLocation::from),
providers: convert_providers_constraint(&constraints.providers),
+ ownership: convert_ownership_constraint(&constraints.ownership) as i32,
tunnel_type: match constraints.tunnel_protocol {
Constraint::Any => None,
Constraint::Only(talpid_net::TunnelType::Wireguard) => {
@@ -878,6 +880,7 @@ impl TryFrom<RelaySettings> for mullvad_types::relay_constraints::RelaySettings
.map(Constraint::<mullvad_types::relay_constraints::LocationConstraint>::from)
.unwrap_or(Constraint::Any);
let providers = try_providers_constraint_from_proto(&settings.providers)?;
+ let ownership = try_ownership_constraint_from_i32(settings.ownership)?;
let tunnel_protocol = settings
.tunnel_type
.map(Constraint::<net::TunnelType>::try_from)
@@ -899,6 +902,7 @@ impl TryFrom<RelaySettings> for mullvad_types::relay_constraints::RelaySettings
mullvad_constraints::RelayConstraints {
location,
providers,
+ ownership,
tunnel_protocol,
wireguard_constraints,
openvpn_constraints,
@@ -958,6 +962,13 @@ impl TryFrom<RelaySettingsUpdate> for mullvad_types::relay_constraints::RelaySet
} else {
None
};
+ let ownership = if let Some(ref ownership_update) = settings.ownership {
+ Some(try_ownership_constraint_from_i32(
+ ownership_update.ownership,
+ )?)
+ } else {
+ None
+ };
let tunnel_protocol = if let Some(update) = settings.tunnel_type {
Some(
update
@@ -989,6 +1000,7 @@ impl TryFrom<RelaySettingsUpdate> for mullvad_types::relay_constraints::RelaySet
mullvad_constraints::RelayConstraintsUpdate {
location,
providers,
+ ownership,
tunnel_protocol,
wireguard_constraints,
openvpn_constraints,
@@ -1187,11 +1199,13 @@ impl TryFrom<BridgeSettings> for mullvad_types::relay_constraints::BridgeSetting
}
};
let providers = try_providers_constraint_from_proto(&constraints.providers)?;
+ let ownership = try_ownership_constraint_from_i32(constraints.ownership)?;
Ok(mullvad_constraints::BridgeSettings::Normal(
mullvad_constraints::BridgeConstraints {
location,
providers,
+ ownership,
},
))
}
@@ -1475,6 +1489,28 @@ pub fn try_providers_constraint_from_proto(
}
}
+pub fn try_ownership_constraint_from_i32(
+ ownership: i32,
+) -> Result<Constraint<mullvad_types::relay_constraints::Ownership>, FromProtobufTypeError> {
+ Ownership::from_i32(ownership)
+ .map(ownership_constraint_from_proto)
+ .ok_or(FromProtobufTypeError::InvalidArgument(
+ "invalid ownership argument",
+ ))
+}
+
+pub fn ownership_constraint_from_proto(
+ ownership: Ownership,
+) -> Constraint<mullvad_types::relay_constraints::Ownership> {
+ use mullvad_types::relay_constraints::Ownership as MullvadOwnership;
+
+ match ownership {
+ Ownership::Any => Constraint::Any,
+ Ownership::MullvadOwned => Constraint::Only(MullvadOwnership::MullvadOwned),
+ Ownership::Rented => Constraint::Only(MullvadOwnership::Rented),
+ }
+}
+
fn convert_providers_constraint(
providers: &Constraint<mullvad_types::relay_constraints::Providers>,
) -> Vec<String> {
@@ -1484,6 +1520,20 @@ fn convert_providers_constraint(
}
}
+fn convert_ownership_constraint(
+ ownership: &Constraint<mullvad_types::relay_constraints::Ownership>,
+) -> Ownership {
+ use mullvad_types::relay_constraints::Ownership as MullvadOwnership;
+
+ match ownership.as_ref() {
+ Constraint::Any => Ownership::Any,
+ Constraint::Only(ownership) => match ownership {
+ MullvadOwnership::MullvadOwned => Ownership::MullvadOwned,
+ MullvadOwnership::Rented => Ownership::Rented,
+ },
+ }
+}
+
impl From<FromProtobufTypeError> for crate::Status {
fn from(err: FromProtobufTypeError) -> Self {
match err {
diff --git a/mullvad-relay-selector/src/lib.rs b/mullvad-relay-selector/src/lib.rs
index e011d747dc..d1470a1ad5 100644
--- a/mullvad-relay-selector/src/lib.rs
+++ b/mullvad-relay-selector/src/lib.rs
@@ -9,8 +9,9 @@ use mullvad_types::{
location::{Coordinates, Location},
relay_constraints::{
BridgeSettings, BridgeState, Constraint, InternalBridgeConstraints, LocationConstraint,
- Match, ObfuscationSettings, OpenVpnConstraints, Providers, RelayConstraints, RelaySettings,
- SelectedObfuscation, Set, TransportPort, Udp2TcpObfuscationSettings, WireguardConstraints,
+ Match, ObfuscationSettings, OpenVpnConstraints, Ownership, Providers, RelayConstraints,
+ RelaySettings, SelectedObfuscation, Set, TransportPort, Udp2TcpObfuscationSettings,
+ WireguardConstraints,
},
relay_list::{Relay, RelayList, Udp2TcpEndpointData},
CustomTunnelEndpoint,
@@ -322,6 +323,7 @@ impl RelaySelector {
Constraint::Only(TunnelType::OpenVpn) => self.get_openvpn_endpoint(
&relay_constraints.location,
&relay_constraints.providers,
+ &relay_constraints.ownership,
relay_constraints.openvpn_constraints.clone(),
bridge_state,
retry_attempt,
@@ -330,6 +332,7 @@ impl RelaySelector {
Constraint::Only(TunnelType::Wireguard) => self.get_wireguard_endpoint(
&relay_constraints.location,
&relay_constraints.providers,
+ &relay_constraints.ownership,
&relay_constraints.wireguard_constraints,
retry_attempt,
),
@@ -373,6 +376,7 @@ impl RelaySelector {
&self,
location: &Constraint<LocationConstraint>,
providers: &Constraint<Providers>,
+ ownership: &Constraint<Ownership>,
openvpn_constraints: OpenVpnConstraints,
bridge_state: BridgeState,
retry_attempt: u32,
@@ -380,6 +384,7 @@ impl RelaySelector {
let mut relay_matcher = RelayMatcher {
location: location.clone(),
providers: providers.clone(),
+ ownership: ownership.clone(),
tunnel: openvpn_constraints,
};
@@ -480,12 +485,14 @@ impl RelaySelector {
&self,
location: &Constraint<LocationConstraint>,
providers: &Constraint<Providers>,
+ ownership: &Constraint<Ownership>,
wireguard_constraints: &WireguardConstraints,
retry_attempt: u32,
) -> Result<NormalSelectedRelay, Error> {
let mut entry_relay_matcher = RelayMatcher {
location: location.clone(),
providers: providers.clone(),
+ ownership: ownership.clone(),
tunnel: wireguard_constraints.clone().into(),
};
@@ -628,6 +635,7 @@ impl RelaySelector {
retry_attempt,
&original_constraints.location,
&original_constraints.providers,
+ &original_constraints.ownership,
);
let mut relay_constraints = original_constraints.clone();
@@ -738,6 +746,7 @@ impl RelaySelector {
let bridge_constraints = InternalBridgeConstraints {
location: settings.location.clone(),
providers: settings.providers.clone(),
+ ownership: settings.ownership.clone(),
// FIXME: This is temporary while talpid-core only supports TCP proxies
transport_protocol: Constraint::Only(TransportProtocol::Tcp),
};
@@ -782,11 +791,13 @@ impl RelaySelector {
BridgeSettings::Normal(settings) => InternalBridgeConstraints {
location: settings.location.clone(),
providers: settings.providers.clone(),
+ ownership: settings.ownership.clone(),
transport_protocol: Constraint::Only(TransportProtocol::Tcp),
},
BridgeSettings::Custom(_bridge_settings) => InternalBridgeConstraints {
location: Constraint::Any,
providers: Constraint::Any,
+ ownership: Constraint::Any,
transport_protocol: Constraint::Only(TransportProtocol::Tcp),
},
};
@@ -949,6 +960,7 @@ impl RelaySelector {
retry_attempt: u32,
location_constraint: &Constraint<LocationConstraint>,
providers_constraint: &Constraint<Providers>,
+ ownership_constraint: &Constraint<Ownership>,
) -> (Constraint<u16>, TransportProtocol, TunnelType) {
#[cfg(target_os = "windows")]
{
@@ -958,6 +970,7 @@ impl RelaySelector {
&& !relay.tunnels.openvpn.is_empty()
&& location_constraint.matches(relay)
&& providers_constraint.matches(relay)
+ && ownership_constraint.matches(relay)
});
if location_supports_openvpn {
let (preferred_port, preferred_protocol) =
@@ -971,6 +984,7 @@ impl RelaySelector {
&& !relay.tunnels.wireguard.is_empty()
&& location_constraint.matches(relay)
&& providers_constraint.matches(relay)
+ && ownership_constraint.matches(relay)
});
// If location does not support WireGuard, defer to preferred OpenVPN tunnel
// constraints
@@ -1061,10 +1075,10 @@ impl RelaySelector {
relay: &Relay,
constraints: &InternalBridgeConstraints,
) -> Option<Relay> {
- if !constraints.location.matches(relay) {
- return None;
- }
- if !constraints.providers.matches(relay) {
+ if !constraints.location.matches(relay)
+ || !constraints.providers.matches(relay)
+ || !constraints.ownership.matches(relay)
+ {
return None;
}
diff --git a/mullvad-relay-selector/src/matcher.rs b/mullvad-relay-selector/src/matcher.rs
index ffd07b9121..3e88777b81 100644
--- a/mullvad-relay-selector/src/matcher.rs
+++ b/mullvad-relay-selector/src/matcher.rs
@@ -1,8 +1,8 @@
use mullvad_types::{
endpoint::{MullvadEndpoint, MullvadWireguardEndpoint},
relay_constraints::{
- Constraint, LocationConstraint, Match, OpenVpnConstraints, Providers, RelayConstraints,
- WireguardConstraints,
+ Constraint, LocationConstraint, Match, OpenVpnConstraints, Ownership, Providers,
+ RelayConstraints, WireguardConstraints,
},
relay_list::{Relay, RelayTunnels, WireguardEndpointData},
};
@@ -14,6 +14,7 @@ use talpid_types::net::{all_of_the_internet, wireguard, IpVersion, TunnelType};
pub struct RelayMatcher<T: TunnelMatcher> {
pub location: Constraint<LocationConstraint>,
pub providers: Constraint<Providers>,
+ pub ownership: Constraint<Ownership>,
pub tunnel: T,
}
@@ -22,6 +23,7 @@ impl From<RelayConstraints> for RelayMatcher<AnyTunnelMatcher> {
Self {
location: constraints.location,
providers: constraints.providers,
+ ownership: constraints.ownership,
tunnel: AnyTunnelMatcher {
wireguard: constraints.wireguard_constraints.into(),
openvpn: constraints.openvpn_constraints,
@@ -37,6 +39,7 @@ impl RelayMatcher<AnyTunnelMatcher> {
tunnel: self.tunnel.wireguard,
location: self.location,
providers: self.providers,
+ ownership: self.ownership,
}
}
}
@@ -51,7 +54,10 @@ impl<T: TunnelMatcher> RelayMatcher<T> {
/// Filter a relay and its endpoints based on constraints.
/// Only matching endpoints are included in the returned Relay.
pub fn filter_matching_relay(&self, relay: &Relay) -> Option<Relay> {
- if !self.location.matches(relay) || !self.providers.matches(relay) {
+ if !self.location.matches(relay)
+ || !self.providers.matches(relay)
+ || !self.ownership.matches(relay)
+ {
return None;
}
diff --git a/mullvad-types/src/relay_constraints.rs b/mullvad-types/src/relay_constraints.rs
index e3fd854df3..7dff97d1e4 100644
--- a/mullvad-types/src/relay_constraints.rs
+++ b/mullvad-types/src/relay_constraints.rs
@@ -185,6 +185,8 @@ pub struct RelayConstraints {
#[cfg_attr(target_os = "android", jnix(skip))]
pub providers: Constraint<Providers>,
#[cfg_attr(target_os = "android", jnix(skip))]
+ pub ownership: Constraint<Ownership>,
+ #[cfg_attr(target_os = "android", jnix(skip))]
pub tunnel_protocol: Constraint<TunnelType>,
#[cfg_attr(target_os = "android", jnix(skip))]
pub wireguard_constraints: WireguardConstraints,
@@ -199,6 +201,7 @@ impl Default for RelayConstraints {
tunnel_protocol: Constraint::Only(TunnelType::Wireguard),
location: Constraint::default(),
providers: Constraint::default(),
+ ownership: Constraint::default(),
wireguard_constraints: WireguardConstraints::default(),
openvpn_constraints: OpenVpnConstraints::default(),
}
@@ -210,6 +213,7 @@ impl RelayConstraints {
RelayConstraints {
location: update.location.unwrap_or_else(|| self.location.clone()),
providers: update.providers.unwrap_or_else(|| self.providers.clone()),
+ ownership: update.ownership.unwrap_or_else(|| self.ownership.clone()),
tunnel_protocol: update
.tunnel_protocol
.unwrap_or_else(|| self.tunnel_protocol.clone()),
@@ -250,8 +254,14 @@ impl fmt::Display for RelayConstraints {
}
write!(f, " using ")?;
match self.providers {
- Constraint::Any => write!(f, "any provider"),
- Constraint::Only(ref constraint) => constraint.fmt(f),
+ Constraint::Any => write!(f, "any provider")?,
+ Constraint::Only(ref constraint) => constraint.fmt(f)?,
+ }
+ match self.ownership {
+ Constraint::Any => Ok(()),
+ Constraint::Only(ref constraint) => {
+ write!(f, " and {}", constraint)
+ }
}
}
}
@@ -318,6 +328,31 @@ impl Set<LocationConstraint> for LocationConstraint {
}
}
+/// Limits the set of servers to choose based on ownership.
+#[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize)]
+pub enum Ownership {
+ MullvadOwned,
+ Rented,
+}
+
+impl Match<Relay> for Ownership {
+ fn matches(&self, relay: &Relay) -> bool {
+ match self {
+ Ownership::MullvadOwned => relay.owned,
+ Ownership::Rented => !relay.owned,
+ }
+ }
+}
+
+impl fmt::Display for Ownership {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
+ match self {
+ Ownership::MullvadOwned => write!(f, "Mullvad-owned servers"),
+ Ownership::Rented => write!(f, "rented servers"),
+ }
+ }
+}
+
/// Limits the set of [`crate::relay_list::Relay`]s used by a `RelaySelector` based on
/// provider.
pub type Provider = String;
@@ -519,6 +554,7 @@ pub struct ObfuscationSettings {
pub struct BridgeConstraints {
pub location: Constraint<LocationConstraint>,
pub providers: Constraint<Providers>,
+ pub ownership: Constraint<Ownership>,
}
impl fmt::Display for BridgeConstraints {
@@ -529,8 +565,14 @@ impl fmt::Display for BridgeConstraints {
}
write!(f, " using ")?;
match self.providers {
- Constraint::Any => write!(f, "any provider"),
- Constraint::Only(ref constraint) => constraint.fmt(f),
+ Constraint::Any => write!(f, "any provider")?,
+ Constraint::Only(ref constraint) => constraint.fmt(f)?,
+ }
+ match self.ownership {
+ Constraint::Any => Ok(()),
+ Constraint::Only(ref constraint) => {
+ write!(f, " and {}", constraint)
+ }
}
}
}
@@ -562,6 +604,7 @@ impl fmt::Display for BridgeState {
pub struct InternalBridgeConstraints {
pub location: Constraint<LocationConstraint>,
pub providers: Constraint<Providers>,
+ pub ownership: Constraint<Ownership>,
pub transport_protocol: Constraint<TransportProtocol>,
}
@@ -613,6 +656,8 @@ pub struct RelayConstraintsUpdate {
#[cfg_attr(target_os = "android", jnix(default))]
pub providers: Option<Constraint<Providers>>,
#[cfg_attr(target_os = "android", jnix(default))]
+ pub ownership: Option<Constraint<Ownership>>,
+ #[cfg_attr(target_os = "android", jnix(default))]
pub tunnel_protocol: Option<Constraint<TunnelType>>,
#[cfg_attr(target_os = "android", jnix(default))]
pub wireguard_constraints: Option<WireguardConstraints>,