summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md2
-rw-r--r--Cargo.lock1
-rw-r--r--docs/relay-selector.md10
-rw-r--r--mullvad-daemon/Cargo.toml1
-rw-r--r--mullvad-daemon/src/relays.rs121
5 files changed, 111 insertions, 24 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9375d30ccc..049739f95d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -34,6 +34,8 @@ Line wrap the file at 100 chars. Th
leaking any data during the reconnection.
### Changed
+- Prefer WireGuard when tunnel protocol is set to _auto_ on Linux and MacOS.
+
#### Android
- Allow other apps to request the VPN tunnel to connect or disconnect.
diff --git a/Cargo.lock b/Cargo.lock
index 1341249e2d..a3ede6d05a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1251,6 +1251,7 @@ name = "mullvad-daemon"
version = "2020.1.0"
dependencies = [
"android_logger 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ctrlc 3.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
diff --git a/docs/relay-selector.md b/docs/relay-selector.md
index 286ce8e0e7..8da8ea69a9 100644
--- a/docs/relay-selector.md
+++ b/docs/relay-selector.md
@@ -41,11 +41,17 @@ Endpoints may be filtered by:
Whilst all user selected constraints are always honored, when the user hasn't selected any specific
constraints, following default ones will take effect:
-- If no tunnel protocol is specified for tunnel endpoints, then by default only OpenVPN
- endpoints will be selected.
+- If no tunnel protocol is specified for tunnel endpoints, then the behavior is different on Windows
+ and other platforms.
+ - On Windows, OpenVPN is used.
+ - On MacOS and Linux, first two connection attempts will use WireGuard, over a random port at
+ first and then port 53. From the third attempt onwards, OpenVPN will be used, alternating
+ between UDP on any port and TCP on port 443.
- If the tunnel protocol is specified as WireGuard without any other protocol constraints, then the
transport protocol is not applicable as only UDP endpoints exist and any port will be matched.
+ The target port alternates between a random one every two attempts, and port 53 for the next 2
+ attempts.
- If no OpenVPN tunnel constraints are specified, then the first two attempts at selecting a tunnel
will try to select UDP endpoints on any port, and the third and fourth attempts will filter for
diff --git a/mullvad-daemon/Cargo.toml b/mullvad-daemon/Cargo.toml
index c2f934e716..f9e14b0e4b 100644
--- a/mullvad-daemon/Cargo.toml
+++ b/mullvad-daemon/Cargo.toml
@@ -8,6 +8,7 @@ edition = "2018"
publish = false
[dependencies]
+cfg-if = "0.1"
chrono = { version = "0.4", features = ["serde"] }
clap = "2.25"
err-derive = "0.2.1"
diff --git a/mullvad-daemon/src/relays.rs b/mullvad-daemon/src/relays.rs
index 558383b022..f81110badb 100644
--- a/mullvad-daemon/src/relays.rs
+++ b/mullvad-daemon/src/relays.rs
@@ -212,7 +212,7 @@ impl RelaySelector {
retry_attempt: u32,
) -> Result<(Relay, MullvadEndpoint), Error> {
let preferred_constraints =
- Self::preferred_constraints(relay_constraints, bridge_state, retry_attempt);
+ self.preferred_constraints(relay_constraints, bridge_state, retry_attempt);
if let Some((relay, endpoint)) = self.get_tunnel_endpoint_internal(&preferred_constraints) {
debug!(
"Relay matched on highest preference for retry attempt {}",
@@ -233,25 +233,27 @@ impl RelaySelector {
}
fn preferred_constraints(
+ &self,
original_constraints: &RelayConstraints,
bridge_state: &BridgeState,
retry_attempt: u32,
) -> RelayConstraints {
- // Prefer UDP by default. But if that has failed a couple of times, then try TCP port 443,
- // which works for many with UDP problems. After that, just alternate between protocols.
- let (preferred_port, mut preferred_protocol) = match retry_attempt {
- 0 | 1 => (Constraint::Any, TransportProtocol::Udp),
- 2 | 3 => (Constraint::Only(443), TransportProtocol::Tcp),
- attempt if attempt % 2 == 0 => (Constraint::Any, TransportProtocol::Udp),
- _ => (Constraint::Any, TransportProtocol::Tcp),
- };
- if *bridge_state == BridgeState::On {
- preferred_protocol = TransportProtocol::Tcp;
- }
+ let (preferred_port, preferred_protocol, preferred_tunnel) =
+ if *bridge_state != BridgeState::On {
+ self.preferred_tunnel_constraints(retry_attempt, &original_constraints.location)
+ } else {
+ (
+ Constraint::Any,
+ TransportProtocol::Tcp,
+ TunnelProtocol::OpenVpn,
+ )
+ };
+
let mut relay_constraints = RelayConstraints {
location: original_constraints.location.clone(),
tunnel_protocol: original_constraints.tunnel_protocol.clone(),
+ wireguard_constraints: original_constraints.wireguard_constraints,
..Default::default()
};
// Highest priority preference. Where we prefer OpenVPN using UDP. But without changing
@@ -271,25 +273,32 @@ impl RelaySelector {
relay_constraints.openvpn_constraints =
original_constraints.openvpn_constraints;
}
- // TODO: remove this constraint once WireGuard can be enabled in auto-relay
- // selection.
- relay_constraints.tunnel_protocol = Constraint::Only(TunnelProtocol::OpenVpn);
+
+ if relay_constraints.wireguard_constraints.port.is_any() {
+ relay_constraints.wireguard_constraints.port = preferred_port;
+ }
+
+ relay_constraints.tunnel_protocol = Constraint::Only(preferred_tunnel);
}
Constraint::Only(TunnelProtocol::OpenVpn) => {
- relay_constraints.openvpn_constraints = original_constraints.openvpn_constraints;
- if *bridge_state == BridgeState::On
- && relay_constraints.openvpn_constraints.protocol.is_any()
- {
+ let openvpn_constraints = &mut relay_constraints.openvpn_constraints;
+ *openvpn_constraints = original_constraints.openvpn_constraints;
+ if *bridge_state == BridgeState::On && openvpn_constraints.protocol.is_any() {
// FIXME: This is temporary while talpid-core only supports TCP proxies
- relay_constraints.openvpn_constraints.protocol =
- Constraint::Only(TransportProtocol::Tcp);
+ openvpn_constraints.protocol = Constraint::Only(TransportProtocol::Tcp);
+ } else if openvpn_constraints.port.is_any() && openvpn_constraints.protocol.is_any()
+ {
+ let (preferred_port, preferred_protocol) =
+ Self::preferred_openvpn_constraints(retry_attempt);
+ openvpn_constraints.port = preferred_port;
+ openvpn_constraints.protocol = Constraint::Only(preferred_protocol);
}
}
Constraint::Only(TunnelProtocol::Wireguard) => {
relay_constraints.wireguard_constraints =
original_constraints.wireguard_constraints;
// This ensures that if after the first 2 failed attempts the daemon does not
- // conenct, then afterwards 2 of each 4 successive attempts will try to connect on
+ // connect, then afterwards 2 of each 4 successive attempts will try to connect on
// port 53.
if retry_attempt % 4 > 1 && relay_constraints.wireguard_constraints.port.is_any() {
relay_constraints.wireguard_constraints.port = Constraint::Only(53);
@@ -356,6 +365,74 @@ impl RelaySelector {
})
}
+ /// Returns preferred constraints
+ #[allow(unused_variables)]
+ fn preferred_tunnel_constraints(
+ &self,
+ retry_attempt: u32,
+ location_constraint: &Constraint<LocationConstraint>,
+ ) -> (Constraint<u16>, TransportProtocol, TunnelProtocol) {
+ #[cfg(not(target_os = "windows"))]
+ {
+ let location_supports_wireguard =
+ self.parsed_relays.lock().relays().iter().any(|relay| {
+ relay.active
+ && !relay.tunnels.wireguard.is_empty()
+ && Self::relay_matches_location(relay, &location_constraint)
+ });
+ // 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, TunnelProtocol::OpenVpn);
+ }
+
+
+ // Try out WireGuard in the first two connection attempts, first with any port,
+ // afterwards on port 53. Afterwards, connect through OpenVPN alternating between UDP
+ // on any port twice and TCP on port 443 once.
+ match retry_attempt {
+ 0 if location_supports_wireguard => (
+ Constraint::Any,
+ TransportProtocol::Udp,
+ TunnelProtocol::Wireguard,
+ ),
+ 1 => (
+ Constraint::Only(53),
+ TransportProtocol::Udp,
+ TunnelProtocol::Wireguard,
+ ),
+ _ => {
+ let (preferred_port, preferred_protocol) =
+ Self::preferred_openvpn_constraints(retry_attempt - 2);
+ (preferred_port, preferred_protocol, TunnelProtocol::OpenVpn)
+ }
+ }
+ }
+
+ #[cfg(target_os = "windows")]
+ {
+ let (preferred_port, preferred_protocol) =
+ Self::preferred_openvpn_constraints(retry_attempt);
+
+
+ (preferred_port, preferred_protocol, TunnelProtocol::OpenVpn)
+ }
+ }
+
+ fn preferred_openvpn_constraints(retry_attempt: u32) -> (Constraint<u16>, TransportProtocol) {
+ // Prefer UDP by default. But if that has failed a couple of times, then try TCP port
+ // 443, which works for many with UDP problems. After that, just alternate
+ // between protocols.
+ match retry_attempt {
+ 0 | 1 => (Constraint::Any, TransportProtocol::Udp),
+ 2 | 3 => (Constraint::Only(443), TransportProtocol::Tcp),
+ attempt if attempt % 2 == 0 => (Constraint::Any, TransportProtocol::Udp),
+ _ => (Constraint::Any, TransportProtocol::Tcp),
+ }
+ }
+
/// Returns a random relay endpoint if any is matching the given constraints.
fn get_tunnel_endpoint_internal(