summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorEmīls <emils@mullvad.net>2020-03-02 11:53:50 +0000
committerEmīls <emils@mullvad.net>2020-03-04 13:42:01 +0000
commit70e235ea2be5e315ba3555bbd30075dfaada3a05 (patch)
tree775a64b5133936af187b1dad814f183be027e12f
parentfdf300e35703970b5ea51da9c7e8447941a08c72 (diff)
downloadmullvadvpn-70e235ea2be5e315ba3555bbd30075dfaada3a05.tar.xz
mullvadvpn-70e235ea2be5e315ba3555bbd30075dfaada3a05.zip
Prefer WireGuard over OpenVPN
-rw-r--r--CHANGELOG.md2
-rw-r--r--Cargo.lock1
-rw-r--r--mullvad-daemon/Cargo.toml1
-rw-r--r--mullvad-daemon/src/relays.rs105
4 files changed, 93 insertions, 16 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/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..3c22cde3cf 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,9 +273,12 @@ 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;
@@ -289,7 +294,7 @@ impl RelaySelector {
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 +361,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(