diff options
| -rw-r--r-- | CHANGELOG.md | 2 | ||||
| -rw-r--r-- | Cargo.lock | 1 | ||||
| -rw-r--r-- | mullvad-daemon/Cargo.toml | 1 | ||||
| -rw-r--r-- | mullvad-daemon/src/relays.rs | 105 |
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( |
