summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorDavid Lönnhager <david.l@mullvad.net>2021-03-01 13:50:10 +0100
committerDavid Lönnhager <david.l@mullvad.net>2021-03-01 13:50:10 +0100
commitb37f17ee40f928c02ace811b3f3f3f10f7bb60b3 (patch)
treedf07af6eb14bc1745be256928561e64a2d488086
parent10878d01b27aed6e1ba976e6a59302edd84ab888 (diff)
parent50d057ae92f59f2fadca4fd96568f4401dbffa41 (diff)
downloadmullvadvpn-b37f17ee40f928c02ace811b3f3f3f10f7bb60b3.tar.xz
mullvadvpn-b37f17ee40f928c02ace811b3f3f3f10f7bb60b3.zip
Merge branch 'wireguard-over-ipv6'
-rw-r--r--CHANGELOG.md1
-rw-r--r--Cargo.lock14
-rw-r--r--mullvad-cli/Cargo.toml1
-rw-r--r--mullvad-cli/src/cmds/relay.rs67
-rw-r--r--mullvad-daemon/src/management_interface.rs28
-rw-r--r--mullvad-daemon/src/relays.rs75
-rw-r--r--mullvad-management-interface/proto/management_interface.proto11
-rw-r--r--mullvad-types/src/relay_constraints.rs13
-rw-r--r--talpid-types/src/net/mod.rs23
9 files changed, 183 insertions, 50 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e8d9eed6e3..469bbe90a7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -27,6 +27,7 @@ Line wrap the file at 100 chars. Th
- Enable isolation of the Electron renderer process to protect against potentially malicious third
party dependencies.
- Add 51820 to list of WireGuard ports in app settings.
+- Add option to connect to WireGuard relays over IPv6.
#### Android
- Allow reaching the API server when connecting, disconnecting or in a blocked state.
diff --git a/Cargo.lock b/Cargo.lock
index 9601349809..17328f4e9a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -977,6 +977,15 @@ dependencies = [
]
[[package]]
+name = "itertools"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37d572918e350e82412fe766d24b15e6682fb2ed2bbe018280caa810397cb319"
+dependencies = [
+ "either",
+]
+
+[[package]]
name = "itoa"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1231,6 +1240,7 @@ dependencies = [
"env_logger 0.8.2",
"err-derive 0.3.0",
"futures",
+ "itertools 0.10.0",
"mullvad-management-interface",
"mullvad-paths",
"mullvad-types",
@@ -1952,7 +1962,7 @@ checksum = "02b10678c913ecbd69350e8535c3aef91a8676c0773fc1d7b95cdd196d7f2f26"
dependencies = [
"bytes 0.5.6",
"heck",
- "itertools",
+ "itertools 0.8.2",
"log 0.4.14",
"multimap",
"petgraph",
@@ -1969,7 +1979,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "537aa19b95acde10a12fec4301466386f757403de4cd4e5b4fa78fb5ecb18f72"
dependencies = [
"anyhow",
- "itertools",
+ "itertools 0.8.2",
"proc-macro2",
"quote",
"syn",
diff --git a/mullvad-cli/Cargo.toml b/mullvad-cli/Cargo.toml
index 2090fd5796..603197fa32 100644
--- a/mullvad-cli/Cargo.toml
+++ b/mullvad-cli/Cargo.toml
@@ -20,6 +20,7 @@ env_logger = "0.8.2"
futures = "0.3"
natord = "1.0.9"
serde = "1.0"
+itertools = "0.10"
mullvad-types = { path = "../mullvad-types" }
mullvad-paths = { path = "../mullvad-paths" }
diff --git a/mullvad-cli/src/cmds/relay.rs b/mullvad-cli/src/cmds/relay.rs
index 4ad950fe7a..6343b9e5d5 100644
--- a/mullvad-cli/src/cmds/relay.rs
+++ b/mullvad-cli/src/cmds/relay.rs
@@ -1,5 +1,6 @@
use crate::{location, new_rpc_client, Command, Error, Result};
use clap::{value_t, values_t};
+use itertools::Itertools;
use std::{
io::{self, BufRead},
net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr},
@@ -8,10 +9,11 @@ use std::{
use mullvad_management_interface::types::{
connection_config::{self, OpenvpnConfig, WireguardConfig},
- relay_settings, relay_settings_update, ConnectionConfig, CustomRelaySettings,
- NormalRelaySettingsUpdate, OpenvpnConstraints, ProviderUpdate, RelayListCountry, RelayLocation,
- RelaySettingsUpdate, TransportProtocol, TransportProtocolConstraint, TunnelType,
- TunnelTypeConstraint, TunnelTypeUpdate, WireguardConstraints,
+ relay_settings, relay_settings_update, ConnectionConfig, CustomRelaySettings, IpVersion,
+ IpVersionConstraint, NormalRelaySettingsUpdate, OpenvpnConstraints, ProviderUpdate,
+ RelayListCountry, RelayLocation, RelaySettingsUpdate, TransportProtocol,
+ TransportProtocolConstraint, TunnelType, TunnelTypeConstraint, TunnelTypeUpdate,
+ WireguardConstraints,
};
use mullvad_types::relay_constraints::Constraint;
use talpid_types::net::all_of_the_internet;
@@ -153,6 +155,13 @@ impl Command for Relay {
.required(false)
.default_value("any")
.possible_values(&["any", "udp", "tcp"]),
+ )
+ .arg(
+ clap::Arg::with_name("ip version")
+ .long("ipv")
+ .required(false)
+ .default_value("any")
+ .possible_values(&["any", "4", "6"]),
),
)
@@ -466,6 +475,7 @@ impl Relay {
let vpn_protocol = matches.value_of("vpn protocol").unwrap();
let port = parse_port_constraint(matches.value_of("port").unwrap())?;
let protocol = parse_protocol_constraint(matches.value_of("transport protocol").unwrap());
+ let ip_version = parse_ip_version_constraint(matches.value_of("ip version").unwrap());
match vpn_protocol {
"wireguard" => {
@@ -477,6 +487,11 @@ impl Relay {
NormalRelaySettingsUpdate {
wireguard_constraints: Some(WireguardConstraints {
port: port.unwrap_or(0) as u32,
+ ip_version: ip_version.option().map(|protocol| {
+ IpVersionConstraint {
+ protocol: protocol as i32,
+ }
+ }),
}),
..Default::default()
},
@@ -485,6 +500,11 @@ impl Relay {
.await
}
"openvpn" => {
+ if let Constraint::Only(_) = ip_version {
+ return Err(Error::InvalidCommand(
+ "OpenVPN does not support the IP version constraint",
+ ));
+ }
self.update_constraints(RelaySettingsUpdate {
r#type: Some(relay_settings_update::Type::Normal(
NormalRelaySettingsUpdate {
@@ -624,9 +644,16 @@ impl Relay {
(false, true) => "WireGuard",
_ => unreachable!("Bug in relay filtering earlier on"),
};
+ let mut addresses = vec![&relay.ipv4_addr_in];
+ if !relay.ipv6_addr_in.is_empty() {
+ addresses.push(&relay.ipv6_addr_in);
+ }
println!(
"\t\t{} ({}) - {}, hosted by {}",
- relay.hostname, relay.ipv4_addr_in, support_msg, relay.provider
+ relay.hostname,
+ addresses.iter().join(", "),
+ support_msg,
+ relay.provider
);
}
}
@@ -641,6 +668,14 @@ impl Relay {
Ok(())
}
+ fn format_ip_version(protocol: Option<IpVersion>) -> &'static str {
+ match protocol {
+ None => "IPv4 or IPv6",
+ Some(IpVersion::V4) => "IPv4",
+ Some(IpVersion::V6) => "IPv6",
+ }
+ }
+
fn format_transport_protocol(protocol: Option<TransportProtocol>) -> &'static str {
match protocol {
None => "any transport protocol",
@@ -676,9 +711,18 @@ impl Relay {
fn format_wireguard_constraints(constraints: Option<&WireguardConstraints>) -> String {
if let Some(constraints) = constraints {
- Self::format_port(constraints.port)
+ format!(
+ "{} over {}",
+ Self::format_port(constraints.port),
+ Self::format_ip_version(
+ constraints
+ .ip_version
+ .clone()
+ .map(|protocol| IpVersion::from_i32(protocol.protocol).unwrap())
+ )
+ )
} else {
- "any port".to_string()
+ "any port over IPv4 or IPv6".to_string()
}
}
@@ -739,3 +783,12 @@ fn parse_protocol_constraint(raw_protocol: &str) -> Constraint<TransportProtocol
_ => unreachable!(),
}
}
+
+fn parse_ip_version_constraint(raw_protocol: &str) -> Constraint<IpVersion> {
+ match raw_protocol {
+ "any" => Constraint::Any,
+ "4" => Constraint::Only(IpVersion::V4),
+ "6" => Constraint::Only(IpVersion::V6),
+ _ => unreachable!(),
+ }
+}
diff --git a/mullvad-daemon/src/management_interface.rs b/mullvad-daemon/src/management_interface.rs
index c87b846387..732e648199 100644
--- a/mullvad-daemon/src/management_interface.rs
+++ b/mullvad-daemon/src/management_interface.rs
@@ -27,7 +27,7 @@ use std::{
sync::{mpsc, Arc},
};
use talpid_types::{
- net::{TransportProtocol, TunnelType},
+ net::{IpVersion, TransportProtocol, TunnelType},
ErrorExt,
};
@@ -949,6 +949,20 @@ fn convert_relay_settings_update(
} else {
None
};
+ let ip_version = if let Some(ref constraints) = settings.wireguard_constraints {
+ match &constraints.ip_version {
+ Some(constraint) => match types::IpVersion::from_i32(constraint.protocol) {
+ Some(types::IpVersion::V4) => Some(IpVersion::V4),
+ Some(types::IpVersion::V6) => Some(IpVersion::V6),
+ None => {
+ return Err(Status::invalid_argument("unknown ip protocol version"))
+ }
+ },
+ None => None,
+ }
+ } else {
+ None
+ };
Ok(RelaySettingsUpdate::Normal(RelayConstraintsUpdate {
location,
@@ -961,6 +975,7 @@ fn convert_relay_settings_update(
} else {
Constraint::Any
},
+ ip_version: Constraint::from(ip_version),
}
}),
openvpn_constraints: settings.openvpn_constraints.map(|constraints| {
@@ -1003,6 +1018,17 @@ fn convert_relay_settings(settings: &RelaySettings) -> types::RelaySettings {
wireguard_constraints: Some(types::WireguardConstraints {
port: u32::from(constraints.wireguard_constraints.port.unwrap_or(0)),
+ ip_version: constraints
+ .wireguard_constraints
+ .ip_version
+ .option()
+ .map(|version| match version {
+ IpVersion::V4 => types::IpVersion::V4,
+ IpVersion::V6 => types::IpVersion::V6,
+ })
+ .map(|version| types::IpVersionConstraint {
+ protocol: i32::from(version),
+ }),
}),
openvpn_constraints: Some(types::OpenvpnConstraints {
diff --git a/mullvad-daemon/src/relays.rs b/mullvad-daemon/src/relays.rs
index 26b855b3b4..2e2a009c4d 100644
--- a/mullvad-daemon/src/relays.rs
+++ b/mullvad-daemon/src/relays.rs
@@ -30,7 +30,10 @@ use std::{
};
use talpid_core::future_retry::{retry_future_with_backoff, ExponentialBackoff, Jittered};
use talpid_types::{
- net::{all_of_the_internet, openvpn::ProxySettings, wireguard, TransportProtocol, TunnelType},
+ net::{
+ all_of_the_internet, openvpn::ProxySettings, wireguard, IpVersion, TransportProtocol,
+ TunnelType,
+ },
ErrorExt,
};
use tokio::fs::File;
@@ -464,12 +467,13 @@ impl RelaySelector {
self.pick_random_relay(&matching_relays)
.and_then(|selected_relay| {
- info!(
- "Selected relay {} at {}",
- selected_relay.hostname, selected_relay.ipv4_addr_in
- );
- self.get_random_tunnel(&selected_relay, &constraints)
- .map(|endpoint| (selected_relay.clone(), endpoint))
+ let endpoint = self.get_random_tunnel(&selected_relay, &constraints);
+ let addr_in = endpoint
+ .as_ref()
+ .map(|endpoint| endpoint.to_endpoint().address.ip())
+ .unwrap_or(IpAddr::from(selected_relay.ipv4_addr_in));
+ info!("Selected relay {} at {}", selected_relay.hostname, addr_in);
+ endpoint.map(|endpoint| (selected_relay.clone(), endpoint))
})
}
@@ -638,52 +642,38 @@ impl RelaySelector {
relay: &Relay,
constraints: &RelayConstraints,
) -> Option<MullvadEndpoint> {
- match constraints.tunnel_protocol {
- // TODO: Handle Constraint::Any case by selecting from both openvpn and wireguard
- // tunnels once wireguard is mature enough
- #[cfg(not(target_os = "android"))]
- Constraint::Only(TunnelType::OpenVpn) | Constraint::Any => relay
- .tunnels
- .openvpn
- .choose(&mut self.rng)
- .cloned()
- .map(|endpoint| endpoint.into_mullvad_endpoint(relay.ipv4_addr_in.into())),
- Constraint::Only(TunnelType::Wireguard) => relay
+ let mut new_wg_endpoint = || {
+ relay
.tunnels
.wireguard
.choose(&mut self.rng)
.cloned()
.and_then(|wg_tunnel| {
- self.wg_data_to_endpoint(
- relay.ipv4_addr_in.into(),
- wg_tunnel,
- constraints.wireguard_constraints,
- )
- }),
- #[cfg(target_os = "android")]
- Constraint::Any => relay
+ self.wg_data_to_endpoint(relay, wg_tunnel, constraints.wireguard_constraints)
+ })
+ };
+
+ #[cfg(not(target_os = "android"))]
+ match constraints.tunnel_protocol {
+ Constraint::Only(TunnelType::OpenVpn) | Constraint::Any => relay
.tunnels
- .wireguard
+ .openvpn
.choose(&mut self.rng)
.cloned()
- .and_then(|wg_tunnel| {
- self.wg_data_to_endpoint(
- relay.ipv4_addr_in.into(),
- wg_tunnel,
- WireguardConstraints::default(),
- )
- }),
- #[cfg(target_os = "android")]
- Constraint::Only(TunnelType::OpenVpn) => None,
+ .map(|endpoint| endpoint.into_mullvad_endpoint(relay.ipv4_addr_in.into())),
+ Constraint::Only(TunnelType::Wireguard) => new_wg_endpoint(),
}
+ #[cfg(target_os = "android")]
+ new_wg_endpoint()
}
fn wg_data_to_endpoint(
&mut self,
- host: IpAddr,
+ relay: &Relay,
data: WireguardEndpointData,
constraints: WireguardConstraints,
) -> Option<MullvadEndpoint> {
+ let host = self.get_address_for_wireguard_relay(relay, constraints)?;
let port = self.get_port_for_wireguard_relay(&data, constraints)?;
let peer_config = wireguard::PeerConfig {
public_key: data.public_key,
@@ -697,6 +687,17 @@ impl RelaySelector {
})
}
+ fn get_address_for_wireguard_relay(
+ &mut self,
+ relay: &Relay,
+ constraints: WireguardConstraints,
+ ) -> Option<IpAddr> {
+ match constraints.ip_version {
+ Constraint::Any | Constraint::Only(IpVersion::V4) => Some(relay.ipv4_addr_in.into()),
+ Constraint::Only(IpVersion::V6) => relay.ipv6_addr_in.map(|addr| addr.into()),
+ }
+ }
+
fn get_port_for_wireguard_relay(
&mut self,
data: &WireguardEndpointData,
diff --git a/mullvad-management-interface/proto/management_interface.proto b/mullvad-management-interface/proto/management_interface.proto
index 08b8a708d9..83ea64a2ac 100644
--- a/mullvad-management-interface/proto/management_interface.proto
+++ b/mullvad-management-interface/proto/management_interface.proto
@@ -302,9 +302,20 @@ message OpenvpnConstraints {
uint32 port = 1;
TransportProtocolConstraint protocol = 2;
}
+
+enum IpVersion {
+ V4 = 0;
+ V6 = 1;
+}
+
+message IpVersionConstraint {
+ IpVersion protocol = 1;
+}
+
message WireguardConstraints {
// NOTE: optional
uint32 port = 1;
+ IpVersionConstraint ip_version = 2;
}
message CustomRelaySettings {
diff --git a/mullvad-types/src/relay_constraints.rs b/mullvad-types/src/relay_constraints.rs
index c9042c8f49..d1104f4733 100644
--- a/mullvad-types/src/relay_constraints.rs
+++ b/mullvad-types/src/relay_constraints.rs
@@ -10,7 +10,7 @@ use crate::{
use jnix::{FromJava, IntoJava};
use serde::{Deserialize, Serialize};
use std::{collections::HashSet, fmt};
-use talpid_types::net::{openvpn::ProxySettings, TransportProtocol, TunnelType};
+use talpid_types::net::{openvpn::ProxySettings, IpVersion, TransportProtocol, TunnelType};
pub trait Match<T> {
@@ -434,15 +434,22 @@ impl Match<OpenVpnEndpointData> for OpenVpnConstraints {
/// [`Constraint`]s applicable to WireGuard relay servers.
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Deserialize, Serialize)]
+#[serde(default)]
pub struct WireguardConstraints {
pub port: Constraint<u16>,
+ pub ip_version: Constraint<IpVersion>,
}
impl fmt::Display for WireguardConstraints {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
match self.port {
- Constraint::Any => write!(f, "any port"),
- Constraint::Only(port) => write!(f, "port {}", port),
+ Constraint::Any => write!(f, "any port")?,
+ Constraint::Only(port) => write!(f, "port {}", port)?,
+ }
+ write!(f, " over ")?;
+ match self.ip_version {
+ Constraint::Any => write!(f, "IPv4 or IPv6"),
+ Constraint::Only(protocol) => write!(f, "{}", protocol),
}
}
}
diff --git a/talpid-types/src/net/mod.rs b/talpid-types/src/net/mod.rs
index 29a871ee07..adea4fd512 100644
--- a/talpid-types/src/net/mod.rs
+++ b/talpid-types/src/net/mod.rs
@@ -156,6 +156,29 @@ impl fmt::Display for Endpoint {
}
}
+/// IP protocol version.
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Deserialize, Serialize)]
+#[serde(rename_all = "snake_case")]
+pub enum IpVersion {
+ V4,
+ V6,
+}
+
+impl Default for IpVersion {
+ fn default() -> IpVersion {
+ IpVersion::V4
+ }
+}
+
+impl fmt::Display for IpVersion {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
+ match *self {
+ IpVersion::V4 => "IPv4".fmt(f),
+ IpVersion::V6 => "IPv6".fmt(f),
+ }
+ }
+}
+
/// Representation of a transport protocol, either UDP or TCP.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]