Skip to content

Commit b1bd8be

Browse files
committed
Refactor to avoid representing offline state
1 parent 64622f4 commit b1bd8be

File tree

9 files changed

+91
-136
lines changed

9 files changed

+91
-136
lines changed

mullvad-daemon/src/tunnel.rs

+8-11
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use std::{
88

99
use tokio::sync::Mutex;
1010

11-
use mullvad_relay_selector::{GetRelay, RelaySelector, RuntimeIpAvailability, WireguardConfig};
11+
use mullvad_relay_selector::{GetRelay, RelaySelector, WireguardConfig};
1212
use mullvad_types::{
1313
endpoint::MullvadWireguardEndpoint, location::GeoIpLocation, relay_list::Relay,
1414
settings::TunnelOptions,
@@ -23,7 +23,7 @@ use talpid_types::net::{
2323
#[cfg(target_os = "android")]
2424
use talpid_types::net::{obfuscation::ObfuscatorConfig, wireguard, TunnelParameters};
2525

26-
use talpid_types::{tunnel::ParameterGenerationError, ErrorExt};
26+
use talpid_types::{net::IpAvailbility, tunnel::ParameterGenerationError, ErrorExt};
2727

2828
use crate::device::{AccountManagerHandle, Error as DeviceError, PrivateAccountAndDevice};
2929

@@ -160,14 +160,12 @@ impl InnerParametersGenerator {
160160
async fn generate(
161161
&mut self,
162162
retry_attempt: u32,
163-
ipv4: bool,
164-
ipv6: bool,
163+
ip_availability: IpAvailbility,
165164
) -> Result<TunnelParameters, Error> {
166165
let data = self.device().await?;
167-
let selected_relay = self.relay_selector.get_relay(
168-
retry_attempt as usize,
169-
RuntimeIpAvailability::new(ipv4, ipv6),
170-
)?;
166+
let selected_relay = self
167+
.relay_selector
168+
.get_relay(retry_attempt as usize, ip_availability)?;
171169

172170
match selected_relay {
173171
#[cfg(not(target_os = "android"))]
@@ -301,14 +299,13 @@ impl TunnelParametersGenerator for ParametersGenerator {
301299
fn generate(
302300
&mut self,
303301
retry_attempt: u32,
304-
ipv4: bool,
305-
ipv6: bool,
302+
ip_availbility: IpAvailbility,
306303
) -> Pin<Box<dyn Future<Output = Result<TunnelParameters, ParameterGenerationError>>>> {
307304
let generator = self.0.clone();
308305
Box::pin(async move {
309306
let mut inner = generator.lock().await;
310307
inner
311-
.generate(retry_attempt, ipv4, ipv6)
308+
.generate(retry_attempt, ip_availbility)
312309
.await
313310
.inspect_err(|error| {
314311
log::error!(

mullvad-relay-selector/src/lib.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,5 @@ pub use error::Error;
1111
pub use relay_selector::{
1212
detailer, matcher, matcher::filter_matching_relay_list, query, relays::WireguardConfig,
1313
AdditionalRelayConstraints, AdditionalWireguardConstraints, GetRelay, RelaySelector,
14-
RuntimeIpAvailability, SelectedBridge, SelectedObfuscator, SelectorConfig, OPENVPN_RETRY_ORDER,
15-
WIREGUARD_RETRY_ORDER,
14+
SelectedBridge, SelectedObfuscator, SelectorConfig, OPENVPN_RETRY_ORDER, WIREGUARD_RETRY_ORDER,
1615
};

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

+11-31
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ use talpid_types::{
4747
net::{
4848
obfuscation::ObfuscatorConfig,
4949
proxy::{CustomProxy, Shadowsocks},
50-
Endpoint, IpVersion, TransportProtocol, TunnelType,
50+
Endpoint, IpAvailbility, IpVersion, TransportProtocol, TunnelType,
5151
},
5252
ErrorExt,
5353
};
@@ -178,29 +178,6 @@ pub struct AdditionalWireguardConstraints {
178178
pub quantum_resistant: QuantumResistantState,
179179
}
180180

181-
/// Whether IPv4 and IPv6 is available at runtime.
182-
///
183-
/// `None` means that no IP version is available, `Some(Any)` means that both are available,
184-
#[derive(Clone, Debug)]
185-
pub struct RuntimeIpAvailability(Option<Constraint<IpVersion>>);
186-
187-
impl RuntimeIpAvailability {
188-
pub fn new(ipv4: bool, ipv6: bool) -> RuntimeIpAvailability {
189-
RuntimeIpAvailability(match (ipv4, ipv6) {
190-
(true, true) => Some(Constraint::Any),
191-
(false, true) => Some(Constraint::Only(IpVersion::V6)),
192-
(true, false) => Some(Constraint::Only(IpVersion::V4)),
193-
(false, false) => None,
194-
})
195-
}
196-
}
197-
198-
impl Default for RuntimeIpAvailability {
199-
fn default() -> Self {
200-
RuntimeIpAvailability(Some(Constraint::Only(IpVersion::V4)))
201-
}
202-
}
203-
204181
/// This enum exists to separate the two types of [`SelectorConfig`] that exists.
205182
///
206183
/// The first one is a "regular" config, where [`SelectorConfig::relay_settings`] is
@@ -550,7 +527,7 @@ impl RelaySelector {
550527
pub fn get_relay(
551528
&self,
552529
retry_attempt: usize,
553-
runtime_ip_availability: RuntimeIpAvailability,
530+
runtime_ip_availability: IpAvailbility,
554531
) -> Result<GetRelay, Error> {
555532
let config_guard = self.config.lock().unwrap();
556533
let config = SpecializedSelectorConfig::from(&*config_guard);
@@ -584,7 +561,7 @@ impl RelaySelector {
584561
&self,
585562
retry_attempt: usize,
586563
retry_order: &[RelayQuery],
587-
runtime_ip_availability: RuntimeIpAvailability,
564+
runtime_ip_availability: IpAvailbility,
588565
) -> Result<GetRelay, Error> {
589566
let config_guard = self.config.lock().unwrap();
590567
let config = SpecializedSelectorConfig::from(&*config_guard);
@@ -627,7 +604,7 @@ impl RelaySelector {
627604
fn pick_and_merge_query(
628605
retry_attempt: usize,
629606
retry_order: &[RelayQuery],
630-
runtime_ip_availability: RuntimeIpAvailability,
607+
runtime_ip_availability: IpAvailbility,
631608
user_config: &NormalSelectorConfig<'_>,
632609
parsed_relays: &RelayList,
633610
) -> Result<RelayQuery, Error> {
@@ -1169,16 +1146,19 @@ impl RelaySelector {
11691146
}
11701147

11711148
fn apply_ip_availability(
1172-
runtime_ip_availability: RuntimeIpAvailability,
1149+
runtime_ip_availability: IpAvailbility,
11731150
user_query: &mut RelayQuery,
11741151
) -> Result<(), Error> {
1152+
let ip_version = match runtime_ip_availability {
1153+
IpAvailbility::IpV4 => Constraint::Only(IpVersion::V4),
1154+
IpAvailbility::IpV6 => Constraint::Only(IpVersion::V6),
1155+
IpAvailbility::IpV4AndIpV6 => Constraint::Any,
1156+
};
11751157
let wireguard_constraints = user_query
11761158
.wireguard_constraints()
11771159
.to_owned()
11781160
.intersection(WireguardRelayQuery {
1179-
ip_version: runtime_ip_availability
1180-
.0
1181-
.ok_or(Error::IpVersionUnavailable)?,
1161+
ip_version,
11821162
..Default::default()
11831163
})
11841164
.ok_or(Error::IpVersionUnavailable)?;

mullvad-relay-selector/tests/relay_selector.rs

+10-10
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ use talpid_types::net::{
1515

1616
use mullvad_relay_selector::{
1717
query::{builder::RelayQueryBuilder, BridgeQuery, ObfuscationQuery, OpenVpnRelayQuery},
18-
Error, GetRelay, RelaySelector, RuntimeIpAvailability, SelectedObfuscator, SelectorConfig,
19-
WireguardConfig, OPENVPN_RETRY_ORDER, WIREGUARD_RETRY_ORDER,
18+
Error, GetRelay, RelaySelector, SelectedObfuscator, SelectorConfig, WireguardConfig,
19+
OPENVPN_RETRY_ORDER, WIREGUARD_RETRY_ORDER,
2020
};
2121
use mullvad_types::{
2222
constraints::Constraint,
@@ -391,7 +391,7 @@ fn test_wireguard_retry_order() {
391391
let relay_selector = default_relay_selector();
392392
for (retry_attempt, query) in WIREGUARD_RETRY_ORDER.iter().enumerate() {
393393
let relay = relay_selector
394-
.get_relay(retry_attempt, RuntimeIpAvailability::new(false, true))
394+
.get_relay(retry_attempt, talpid_types::net::IpAvailbility::IpV6)
395395
.unwrap_or_else(|_| panic!("Retry attempt {retry_attempt} did not yield any relay"));
396396
// For each relay, cross-check that the it has the expected tunnel protocol
397397
let tunnel_type = tunnel_type(&unwrap_relay(relay.clone()));
@@ -450,7 +450,7 @@ fn test_openvpn_retry_order() {
450450

451451
for (retry_attempt, query) in OPENVPN_RETRY_ORDER.iter().enumerate() {
452452
let relay = relay_selector
453-
.get_relay(retry_attempt, RuntimeIpAvailability::new(false, true))
453+
.get_relay(retry_attempt, talpid_types::net::IpAvailbility::IpV6)
454454
.unwrap_or_else(|_| panic!("Retry attempt {retry_attempt} did not yield any relay"));
455455
// For each relay, cross-check that the it has the expected tunnel protocol
456456
let tunnel_type = tunnel_type(&unwrap_relay(relay.clone()));
@@ -1159,7 +1159,7 @@ fn test_openvpn_auto_bridge() {
11591159
.get_relay_with_custom_params(
11601160
retry_attempt,
11611161
&retry_order,
1162-
RuntimeIpAvailability::default(),
1162+
talpid_types::net::IpAvailbility::IpV4,
11631163
)
11641164
.unwrap();
11651165
match relay {
@@ -1269,7 +1269,7 @@ fn test_include_in_country() {
12691269
// If include_in_country is false for all relays, a relay must be selected anyway.
12701270
let relay_selector = RelaySelector::from_list(SelectorConfig::default(), relay_list.clone());
12711271
assert!(relay_selector
1272-
.get_relay(0, RuntimeIpAvailability::default())
1272+
.get_relay(0, talpid_types::net::IpAvailbility::IpV4)
12731273
.is_ok());
12741274

12751275
// If include_in_country is true for some relay, it must always be selected.
@@ -1278,7 +1278,7 @@ fn test_include_in_country() {
12781278
let relay_selector = RelaySelector::from_list(SelectorConfig::default(), relay_list);
12791279
let relay = unwrap_relay(
12801280
relay_selector
1281-
.get_relay(0, RuntimeIpAvailability::default())
1281+
.get_relay(0, talpid_types::net::IpAvailbility::IpV4)
12821282
.expect("expected match"),
12831283
);
12841284

@@ -1615,7 +1615,7 @@ fn valid_user_setting_should_yield_relay() {
16151615
let user_result = relay_selector.get_relay_by_query(user_query.clone());
16161616
for retry_attempt in 0..WIREGUARD_RETRY_ORDER.len() {
16171617
let post_unification_result =
1618-
relay_selector.get_relay(retry_attempt, RuntimeIpAvailability::default());
1618+
relay_selector.get_relay(retry_attempt, talpid_types::net::IpAvailbility::IpV4);
16191619
if user_result.is_ok() {
16201620
assert!(post_unification_result.is_ok(), "Expected Post-unification query to be valid because original query {:#?} yielded a connection configuration", user_query)
16211621
}
@@ -1638,7 +1638,7 @@ fn test_shadowsocks_runtime_ipv4_unavailable() {
16381638
..SelectorConfig::default()
16391639
};
16401640
let relay_selector = RelaySelector::from_list(config, RELAYS.clone());
1641-
let runtime_parameters = RuntimeIpAvailability::new(false, true);
1641+
let runtime_parameters = talpid_types::net::IpAvailbility::IpV6;
16421642
let user_result = relay_selector.get_relay(0, runtime_parameters).unwrap();
16431643
assert!(
16441644
matches!(user_result, GetRelay::Wireguard {
@@ -1666,7 +1666,7 @@ fn test_runtime_ipv4_unavailable() {
16661666
..SelectorConfig::default()
16671667
};
16681668
let relay_selector = RelaySelector::from_list(config, RELAYS.clone());
1669-
let runtime_parameters = RuntimeIpAvailability::new(false, true);
1669+
let runtime_parameters = talpid_types::net::IpAvailbility::IpV6;
16701670
let relay = relay_selector.get_relay(0, runtime_parameters).unwrap();
16711671
match relay {
16721672
GetRelay::Wireguard { endpoint, .. } => {

talpid-core/src/offline/linux.rs

+15-11
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,20 @@ async fn check_connectivity(handle: &RouteManagerHandle, fwmark: Option<u32>) ->
8282
route_exists(PUBLIC_INTERNET_ADDRESS_V4).await,
8383
route_exists(PUBLIC_INTERNET_ADDRESS_V6).await,
8484
) {
85-
(Ok(ipv4), Ok(ipv6)) => Connectivity::Status { ipv4, ipv6 },
85+
(Ok(true), Ok(true)) => Connectivity::Online(talpid_types::net::IpAvailbility::IpV4AndIpV6),
86+
(Ok(false), Ok(true)) => Connectivity::Online(talpid_types::net::IpAvailbility::IpV6),
87+
(Ok(true), no_ipv6) => {
88+
// Errors for IPv6 likely mean it's disabled, so assume it's unavailable
89+
if let Err(err) = no_ipv6 {
90+
log::trace!(
91+
"{}",
92+
err.display_chain_with_msg(
93+
"Failed to infer offline state for IPv6. Assuming it's unavailable"
94+
)
95+
)
96+
}
97+
Connectivity::Online(talpid_types::net::IpAvailbility::IpV4)
98+
}
8699
// If we fail to retrieve the IPv4 route, always assume we're connected
87100
(Err(err), _) => {
88101
log::error!(
@@ -91,15 +104,6 @@ async fn check_connectivity(handle: &RouteManagerHandle, fwmark: Option<u32>) ->
91104
);
92105
Connectivity::PresumeOnline
93106
}
94-
// Errors for IPv6 likely mean it's disabled, so assume it's unavailable
95-
(Ok(ipv4), Err(err)) => {
96-
log::trace!(
97-
"{}",
98-
err.display_chain_with_msg(
99-
"Failed to infer offline state for IPv6. Assuming it's unavailable"
100-
)
101-
);
102-
Connectivity::Status { ipv4, ipv6: false }
103-
}
107+
_ => Connectivity::Offline,
104108
}
105109
}

talpid-core/src/tunnel_state_machine/connecting_state.rs

+19-16
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use talpid_routing::RouteManagerHandle;
1010
use talpid_tunnel::tun_provider::TunProvider;
1111
use talpid_tunnel::{EventHook, TunnelArgs, TunnelEvent, TunnelMetadata};
1212
use talpid_types::net::{
13-
AllowedClients, AllowedEndpoint, AllowedTunnelTraffic, Connectivity, TunnelParameters,
13+
AllowedClients, AllowedEndpoint, AllowedTunnelTraffic, IpAvailbility, TunnelParameters,
1414
};
1515
use talpid_types::tunnel::{ErrorStateCause, FirewallPolicyError};
1616
use talpid_types::ErrorExt;
@@ -75,22 +75,25 @@ impl ConnectingState {
7575
});
7676
}
7777

78-
if shared_values.connectivity == Connectivity::Offline {
79-
// FIXME: Temporary: Nudge route manager to update the default interface
80-
#[cfg(target_os = "macos")]
81-
{
82-
log::debug!("Poking route manager to update default routes");
83-
let _ = shared_values.route_manager.refresh_routes();
78+
let ip_availability = match shared_values.connectivity {
79+
talpid_types::net::Connectivity::Offline => {
80+
// FIXME: Temporary: Nudge route manager to update the default interface
81+
#[cfg(target_os = "macos")]
82+
{
83+
log::debug!("Poking route manager to update default routes");
84+
let _ = shared_values.route_manager.refresh_routes();
85+
}
86+
return ErrorState::enter(shared_values, ErrorStateCause::IsOffline);
8487
}
85-
return ErrorState::enter(shared_values, ErrorStateCause::IsOffline);
86-
}
87-
match shared_values
88-
.runtime
89-
.block_on(shared_values.tunnel_parameters_generator.generate(
90-
retry_attempt,
91-
shared_values.connectivity.has_ipv4(),
92-
shared_values.connectivity.has_ipv6(),
93-
)) {
88+
talpid_types::net::Connectivity::PresumeOnline => IpAvailbility::IpV4,
89+
talpid_types::net::Connectivity::Online(ip_availbility) => ip_availbility,
90+
};
91+
92+
match shared_values.runtime.block_on(
93+
shared_values
94+
.tunnel_parameters_generator
95+
.generate(retry_attempt, ip_availability),
96+
) {
9497
Err(err) => {
9598
ErrorState::enter(shared_values, ErrorStateCause::TunnelParameterError(err))
9699
}

talpid-core/src/tunnel_state_machine/mod.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ use std::{
4646
#[cfg(target_os = "android")]
4747
use talpid_types::{android::AndroidContext, ErrorExt};
4848
use talpid_types::{
49-
net::{AllowedEndpoint, Connectivity, TunnelParameters},
49+
net::{AllowedEndpoint, Connectivity, IpAvailbility, TunnelParameters},
5050
tunnel::{ErrorStateCause, ParameterGenerationError, TunnelStateTransition},
5151
};
5252

@@ -452,8 +452,7 @@ pub trait TunnelParametersGenerator: Send + 'static {
452452
fn generate(
453453
&mut self,
454454
retry_attempt: u32,
455-
ipv4: bool,
456-
ipv6: bool,
455+
ip_availbility: IpAvailbility,
457456
) -> Pin<Box<dyn Future<Output = Result<TunnelParameters, ParameterGenerationError>>>>;
458457
}
459458

talpid-types/src/lib.rs

-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
#[cfg(target_os = "android")]
22
pub mod android;
33
pub mod net;
4-
pub use net::IpAvailability;
54
pub mod tunnel;
65

76
#[cfg(target_os = "linux")]

0 commit comments

Comments
 (0)