Skip to content

Commit

Permalink
Add test case for smart routing overriding multihop
Browse files Browse the repository at this point in the history
  • Loading branch information
MarkusPettersson98 committed Oct 17, 2024
1 parent 4a14652 commit 53afeb4
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 1 deletion.
4 changes: 3 additions & 1 deletion mullvad-relay-selector/src/relay_selector/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -932,7 +932,9 @@ impl RelayQueryExtensions for RelayQuery {
fn use_multihop_if_necessary(&self) -> bool {
self.wireguard_constraints()
.daita_use_multihop_if_necessary
.is_only_and(|enabled| enabled)
// The default value is `Any`, which means that we need to check the intersection.
.intersection(Constraint::Only(true))
.is_some()
}
fn singlehop(&self) -> bool {
!self.wireguard_constraints().multihop()
Expand Down
74 changes: 74 additions & 0 deletions mullvad-relay-selector/tests/relay_selector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,27 @@ static RELAYS: LazyLock<RelayList> = LazyLock::new(|| RelayList {
}),
location: DUMMY_LOCATION.clone(),
},
Relay {
hostname: "se11-wireguard".to_string(),
ipv4_addr_in: "185.213.154.69".parse().unwrap(),
ipv6_addr_in: Some("2a03:1b20:5:f011::a11f".parse().unwrap()),
overridden_ipv4: false,
overridden_ipv6: false,
include_in_country: true,
active: true,
owned: false,
provider: "provider2".to_string(),
weight: 1,
endpoint_data: RelayEndpointData::Wireguard(WireguardRelayEndpointData {
public_key: PublicKey::from_base64(
"BLNHNoGO88LjV/wDBa7CUUwUzPq/fO2UwcGLy56hKy4=",
)
.unwrap(),
daita: true,
shadowsocks_extra_addr_in: vec![],
}),
location: DUMMY_LOCATION.clone(),
},
Relay {
hostname: "se-got-001".to_string(),
ipv4_addr_in: "185.213.154.131".parse().unwrap(),
Expand Down Expand Up @@ -1401,6 +1422,59 @@ fn test_daita_any_tunnel_protocol() {
);
}

/// Always use smart routing to select a DAITA-enabled entry relay if both smart routing and multihop is enabled.
/// This applies even if the entry is set explicitly.
/// DAITA is a core privacy feature
#[test]
fn test_daita_smart_routing_overrides_multihop() {
let relay_selector = RelaySelector::from_list(SelectorConfig::default(), RELAYS.clone());
let query = RelayQueryBuilder::new()
.wireguard()
.daita()
.daita_use_multihop_if_necessary(true)
.multihop()
// Set the entry to a relay that explicitly does *not* support DAITA.
// Later, we check that the smart routing diregards this choice and selects a DAITA-enabled
// relay instead.
.entry(NON_DAITA_RELAY_LOCATION.clone())
.build();

for _ in 0..100 {
// Make sure a DAITA-enabled relay is always selected due to smart routing.
let relay = relay_selector
.get_relay_by_query(query.clone())
.expect("Expected to find a relay with daita_use_multihop_if_necessary");
match relay {
GetRelay::Wireguard {
inner: WireguardConfig::Multihop { entry, exit: _ },
..
} => {
assert!(supports_daita(&entry), "entry relay must support DAITA");
}
wrong_relay => panic!(
"Relay selector should have picked two Wireguard relays, instead chose {wrong_relay:?}"
),
}
}

// Assert that disabling smart routing for this query will fail to generate a valid multihop
// config, thus blocking the user.
let query = RelayQueryBuilder::new()
.wireguard()
.daita()
.daita_use_multihop_if_necessary(false)
.multihop()
.entry(NON_DAITA_RELAY_LOCATION.clone())
.build();

let relay = relay_selector.get_relay_by_query(query);

assert!(
relay.is_err(),
"expected there to be no valid multihop configuration! Instead got {relay:#?}"
);
}

/// Always select a WireGuard relay when multihop is enabled
/// Multihop is a core privacy feature
#[test]
Expand Down

0 comments on commit 53afeb4

Please sign in to comment.