Skip to content

Commit 03865ae

Browse files
committed
Pick DAITA use_anywhere relays based on distance to selected location
1 parent da01b47 commit 03865ae

File tree

2 files changed

+58
-22
lines changed

2 files changed

+58
-22
lines changed

mullvad-relay-selector/src/relay_selector/mod.rs

+55-20
Original file line numberDiff line numberDiff line change
@@ -756,12 +756,42 @@ impl RelaySelector {
756756
custom_lists: &CustomListsSettings,
757757
parsed_relays: &ParsedRelays,
758758
) -> Result<WireguardConfig, Error> {
759-
// Modify the query to enable multihop
760-
let mut query = query.clone();
761-
query.wireguard_constraints.use_multihop = Constraint::Only(true);
762-
query.wireguard_constraints.entry_location = Constraint::Any; // TODO: smarter location selection
759+
let mut exit_relay_query = query.clone();
760+
761+
// DAITA should only be enabled for the entry relay
762+
exit_relay_query.wireguard_constraints.daita = Constraint::Only(false);
763+
764+
let exit_candidates =
765+
filter_matching_relay_list(&exit_relay_query, parsed_relays.relays(), custom_lists);
766+
let exit = helpers::pick_random_relay(&exit_candidates).ok_or(Error::NoRelay)?;
767+
768+
// generate a list of potential entry relays, disregarding any location constraint
769+
let entry_query = RelayQuery {
770+
location: Constraint::Any,
771+
..query.clone()
772+
};
773+
let mut entry_candidates =
774+
filter_matching_relay_list(&entry_query, parsed_relays.relays(), custom_lists)
775+
.into_iter()
776+
.map(|entry| RelayWithDistance::new_with_distance_from(entry, &exit.location))
777+
.collect_vec();
778+
779+
// sort entry relay candidates by distance, and pick one from those that are closest
780+
entry_candidates.sort_unstable_by(|a, b| a.distance.total_cmp(&b.distance));
781+
let smallest_distance = entry_candidates.first().map(|relay| relay.distance);
782+
let smallest_distance = smallest_distance.unwrap_or_default();
783+
let entry_candidates = entry_candidates
784+
.into_iter()
785+
// only consider the relay(s) with the smallest distance. note that the list is sorted.
786+
// NOTE: we could relax this requirement, but since so few relays support DAITA
787+
// (and this function is only used for daita) we might end up picking relays that are
788+
// needlessly far away. Consider making this closure configurable if needed.
789+
.take_while(|relay| relay.distance <= smallest_distance)
790+
.map(|relay_with_distance| relay_with_distance.relay)
791+
.collect_vec();
792+
let entry = pick_random_excluding(&entry_candidates, &exit).ok_or(Error::NoRelay)?;
763793

764-
Self::get_wireguard_multihop_config(&query, custom_lists, parsed_relays)
794+
Ok(WireguardConfig::multihop(exit.clone(), entry.clone()))
765795
}
766796

767797
/// This function selects a valid entry and exit relay to be used in a multihop configuration.
@@ -793,11 +823,6 @@ impl RelaySelector {
793823
let entry_candidates =
794824
filter_matching_relay_list(&entry_relay_query, parsed_relays.relays(), custom_lists);
795825

796-
fn pick_random_excluding<'a>(list: &'a [Relay], exclude: &'a Relay) -> Option<&'a Relay> {
797-
list.iter()
798-
.filter(|&a| a != exclude)
799-
.choose(&mut thread_rng())
800-
}
801826
// We avoid picking the same relay for entry and exit by choosing one and excluding it when
802827
// choosing the other.
803828
let (exit, entry) = match (exit_candidates.as_slice(), entry_candidates.as_slice()) {
@@ -1026,19 +1051,10 @@ impl RelaySelector {
10261051
const MIN_BRIDGE_COUNT: usize = 5;
10271052
let location = location.into();
10281053

1029-
#[derive(Clone)]
1030-
struct RelayWithDistance {
1031-
relay: Relay,
1032-
distance: f64,
1033-
}
1034-
10351054
// Filter out all candidate bridges.
10361055
let matching_bridges: Vec<RelayWithDistance> = relays
10371056
.into_iter()
1038-
.map(|relay| RelayWithDistance {
1039-
distance: relay.location.distance_from(&location),
1040-
relay,
1041-
})
1057+
.map(|relay| RelayWithDistance::new_with_distance_from(relay, location))
10421058
.sorted_unstable_by_key(|relay| relay.distance as usize)
10431059
.take(MIN_BRIDGE_COUNT)
10441060
.collect();
@@ -1100,3 +1116,22 @@ impl RelaySelector {
11001116
helpers::pick_random_relay(&candidates).cloned()
11011117
}
11021118
}
1119+
1120+
fn pick_random_excluding<'a>(list: &'a [Relay], exclude: &'a Relay) -> Option<&'a Relay> {
1121+
list.iter()
1122+
.filter(|&a| a != exclude)
1123+
.choose(&mut thread_rng())
1124+
}
1125+
1126+
#[derive(Clone)]
1127+
struct RelayWithDistance {
1128+
distance: f64,
1129+
relay: Relay,
1130+
}
1131+
1132+
impl RelayWithDistance {
1133+
fn new_with_distance_from(relay: Relay, from: impl Into<Coordinates>) -> Self {
1134+
let distance = relay.location.distance_from(from);
1135+
RelayWithDistance { relay, distance }
1136+
}
1137+
}

mullvad-types/src/location.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ pub struct Location {
1919
const RAIDUS_OF_EARTH: f64 = 6372.8;
2020

2121
impl Location {
22-
pub fn distance_from(&self, other: &Coordinates) -> f64 {
22+
pub fn distance_from(&self, other: impl Into<Coordinates>) -> f64 {
23+
let other: Coordinates = other.into();
2324
haversine_dist_deg(
2425
self.latitude,
2526
self.longitude,
@@ -33,7 +34,7 @@ impl Location {
3334
}
3435
}
3536

36-
#[derive(Debug, Clone, PartialEq)]
37+
#[derive(Debug, Clone, Copy, PartialEq)]
3738
pub struct Coordinates {
3839
pub latitude: f64,
3940
pub longitude: f64,

0 commit comments

Comments
 (0)