summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorEmīls Piņķis <emils@mullvad.net>2019-02-05 11:18:20 +0000
committerEmīls Piņķis <emils@mullvad.net>2019-02-05 11:18:20 +0000
commit0d20edce0e6d8fdd8241d502e4e914307cc12fb2 (patch)
treedad5f0bfdc1428b79b5a3c2d3a55532bbb14e334
parent54142b0fa0b26a33d8e6181a61e03b4b46abda00 (diff)
parent01d6d3d874fde5ad8c4ed7f7152e25841aff2433 (diff)
downloadmullvadvpn-0d20edce0e6d8fdd8241d502e4e914307cc12fb2.tar.xz
mullvadvpn-0d20edce0e6d8fdd8241d502e4e914307cc12fb2.zip
Merge branch 'adjust-cli-gui-for-wg'
-rw-r--r--Cargo.lock26
-rw-r--r--mullvad-cli/Cargo.toml3
-rw-r--r--mullvad-cli/src/cmds/relay.rs204
-rw-r--r--mullvad-cli/src/cmds/tunnel.rs146
-rw-r--r--mullvad-daemon/src/lib.rs45
-rw-r--r--mullvad-daemon/src/management_interface.rs41
-rw-r--r--mullvad-ipc-client/src/lib.rs8
-rw-r--r--mullvad-types/Cargo.toml2
-rw-r--r--mullvad-types/src/endpoint.rs2
-rw-r--r--mullvad-types/src/settings.rs19
-rw-r--r--talpid-core/Cargo.toml5
-rw-r--r--talpid-core/src/tunnel/wireguard/config.rs9
-rw-r--r--talpid-types/Cargo.toml2
13 files changed, 407 insertions, 105 deletions
diff --git a/Cargo.lock b/Cargo.lock
index df7b6ae630..27ac5b63fa 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -603,6 +603,14 @@ dependencies = [
]
[[package]]
+name = "ipnetwork"
+version = "0.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "iproute2"
version = "0.0.2"
source = "git+https://github.com/mullvad/netlink?branch=best-effort-nla-parsing#132ab47bcbb32079ba4ededaa76a3d7b6257da40"
@@ -970,6 +978,7 @@ dependencies = [
name = "mullvad-cli"
version = "2019.1.0"
dependencies = [
+ "base64 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)",
"error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1116,7 +1125,7 @@ version = "0.1.0"
dependencies = [
"chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "ipnetwork 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "ipnetwork 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"mullvad-paths 0.1.0",
@@ -1350,14 +1359,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "pfctl"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
+version = "0.2.1"
+source = "git+https://github.com/mullvad/pfctl-rs?rev=9f31b5ddcab941862470075eab83bb398195f3d6#9f31b5ddcab941862470075eab83bb398195f3d6"
dependencies = [
"derive_builder 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"errno 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ioctl-sys 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "ipnetwork 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "ipnetwork 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1789,7 +1798,7 @@ dependencies = [
"failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
"hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "ipnetwork 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "ipnetwork 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
"iproute2 0.0.2 (git+https://github.com/mullvad/netlink?branch=best-effort-nla-parsing)",
"jsonrpc-core 8.0.2 (git+https://github.com/mullvad/jsonrpc?branch=mullvad-fork)",
"jsonrpc-macros 8.0.1 (git+https://github.com/mullvad/jsonrpc?branch=mullvad-fork)",
@@ -1803,7 +1812,7 @@ dependencies = [
"notify 4.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"openvpn-plugin 0.3.0 (git+https://github.com/mullvad/openvpn-plugin-rs?branch=auth-failed-event)",
"os_pipe 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "pfctl 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "pfctl 0.2.1 (git+https://github.com/mullvad/pfctl-rs?rev=9f31b5ddcab941862470075eab83bb398195f3d6)",
"resolv-conf 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rtnetlink 0.0.3 (git+https://github.com/mullvad/netlink?branch=best-effort-nla-parsing)",
"shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1866,7 +1875,7 @@ dependencies = [
"base64 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
"error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
"hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "ipnetwork 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "ipnetwork 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -2438,6 +2447,7 @@ dependencies = [
"checksum ioctl-sys 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5e2c4b26352496eaaa8ca7cfa9bd99e93419d3f7983dc6e99c2a35fe9e33504a"
"checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08"
"checksum ipnetwork 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1d1d8b990621b5b0806fac3dbf71d1833a4c0a9e25702d10bd8b2c629c7ae01c"
+"checksum ipnetwork 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b3d862c86f7867f19b693ec86765e0252d82e53d4240b9b629815675a0714ad1"
"checksum iproute2 0.0.2 (git+https://github.com/mullvad/netlink?branch=best-effort-nla-parsing)" = "<none>"
"checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b"
"checksum jsonrpc-client-core 0.5.0 (git+https://github.com/mullvad/jsonrpc-client-rs?rev=e9dbdc80)" = "<none>"
@@ -2496,7 +2506,7 @@ dependencies = [
"checksum parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f0802bff09003b291ba756dc7e79313e51cc31667e94afbe847def490424cde5"
"checksum parking_lot_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad7f7e6ebdc79edff6fdcb87a55b620174f7a989e3eb31b65231f4af57f00b8c"
"checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831"
-"checksum pfctl 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9aefb0dd38fc99f8bea821a69fa2cdeb57633bd80da078f2f7131d59ec4c91be"
+"checksum pfctl 0.2.1 (git+https://github.com/mullvad/pfctl-rs?rev=9f31b5ddcab941862470075eab83bb398195f3d6)" = "<none>"
"checksum pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "676e8eb2b1b4c9043511a9b7bea0915320d7e502b0a079fb03f9635a5252b18c"
"checksum proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)" = "3d7b7eaaa90b4a90a932a9ea6666c95a389e424eff347f0f793979289429feee"
"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0"
diff --git a/mullvad-cli/Cargo.toml b/mullvad-cli/Cargo.toml
index efa908d363..989d27046e 100644
--- a/mullvad-cli/Cargo.toml
+++ b/mullvad-cli/Cargo.toml
@@ -18,11 +18,12 @@ name = "mullvad"
path = "src/main.rs"
[dependencies]
-clap = "2.20"
+clap = "2.32"
error-chain = "0.12"
env_logger = "0.5"
serde = "1.0"
futures = "0.1"
+base64 = "0.10"
mullvad-ipc-client = { path = "../mullvad-ipc-client" }
mullvad-types = { path = "../mullvad-types" }
diff --git a/mullvad-cli/src/cmds/relay.rs b/mullvad-cli/src/cmds/relay.rs
index 2f3d276fce..a7d571e2ce 100644
--- a/mullvad-cli/src/cmds/relay.rs
+++ b/mullvad-cli/src/cmds/relay.rs
@@ -1,15 +1,20 @@
use crate::{new_rpc_client, Command, Result, ResultExt};
-use clap::value_t;
-use std::{net::Ipv4Addr, str::FromStr};
+use clap::{value_t, values_t};
+use std::{
+ io::{self, BufRead},
+ net::{IpAddr, Ipv4Addr, SocketAddr},
+ str::FromStr,
+};
use mullvad_types::{
+ endpoint::all_of_the_internet,
relay_constraints::{
Constraint, LocationConstraint, OpenVpnConstraints, RelayConstraintsUpdate,
RelaySettingsUpdate, TunnelConstraints,
},
ConnectionConfig, CustomTunnelEndpoint,
};
-use talpid_types::net::{openvpn, Endpoint, TransportProtocol};
+use talpid_types::net::{openvpn, wireguard, Endpoint, TransportProtocol};
pub struct Relay;
@@ -31,41 +36,72 @@ impl Command for Relay {
.subcommand(
clap::SubCommand::with_name("custom")
.about("Set a custom VPN relay")
- .arg(
- clap::Arg::with_name("tunnel")
- .required(true)
- .index(1)
- .possible_values(&["openvpn", "wireguard"]),
+ .subcommand(clap::SubCommand::with_name("wireguard")
+ .arg(
+ clap::Arg::with_name("host")
+ .help("Hostname or IP")
+ .required(true)
+ .index(1),
+ )
+ .arg(
+ clap::Arg::with_name("port")
+ .help("Remote network port")
+ .required(true)
+ .index(2),
+ )
+ .arg(
+ clap::Arg::with_name("peer-key")
+ .help("Base64 encoded peer public key")
+ .index(3)
+ .required(false),
+ )
+ .arg(
+ clap::Arg::with_name("gateway")
+ .help("Gateway address")
+ .long("gateway")
+ .index(4)
+ .required(false),
+ )
+ .arg(
+ clap::Arg::with_name("addr")
+ .help("Local address of wireguard tunnel")
+ .long("addr")
+ .takes_value(true)
+ .multiple(true)
+ .required(false),
+ ),
)
- .arg(
- clap::Arg::with_name("host")
- .help("Hostname or IP")
- .required(true)
- .index(2),
+ .subcommand(clap::SubCommand::with_name("openvpn")
+ .arg(
+ clap::Arg::with_name("host")
+ .help("Hostname or IP")
+ .required(true)
+ .index(1),
+ )
+ .arg(
+ clap::Arg::with_name("port")
+ .help("Remote network port")
+ .required(true)
+ .index(2),
+ )
+ .arg(
+ clap::Arg::with_name("protocol")
+ .help("Transport protocol. For Wireguard this is ignored.")
+ .index(3)
+ .default_value("udp")
+ .possible_values(&["udp", "tcp"]),
+ )
+ .arg(
+ clap::Arg::with_name("username")
+ .help("Username to be used with the OpenVpn relay")
+ .index(4),
+ )
+ .arg(
+ clap::Arg::with_name("password")
+ .help("Password to be used with the OpenVpn relay")
+ .index(5),
+ )
)
- .arg(
- clap::Arg::with_name("port")
- .help("Remote network port")
- .required(true)
- .index(3),
- )
- .arg(
- clap::Arg::with_name("protocol")
- .help("Transport protocol. For Wireguard this is ignored.")
- .index(4)
- .default_value("udp")
- .possible_values(&["udp", "tcp"]),
- )
- .arg(
- clap::Arg::with_name("username")
- .help("Username to be used with the OpenVpn relay")
- .index(5),
- )
- .arg(
- clap::Arg::with_name("password")
- .help("Password to be used with the OpenVpn relay")
- .index(6),
- ),
)
.subcommand(
clap::SubCommand::with_name("location")
@@ -152,29 +188,83 @@ impl Relay {
}
fn set_custom(&self, matches: &clap::ArgMatches) -> Result<()> {
+ let custom_endpoint = match matches.subcommand() {
+ ("openvpn", Some(openvpn_matches)) => Self::read_custom_openvpn_relay(openvpn_matches),
+ ("wireguard", Some(wg_matches)) => Self::read_custom_wireguard_relay(wg_matches),
+ (_unknown_tunnel, _) => unreachable!("No set relay command given"),
+ };
+ self.update_constraints(RelaySettingsUpdate::CustomTunnelEndpoint(custom_endpoint))
+ }
+
+ fn read_custom_openvpn_relay(matches: &clap::ArgMatches) -> CustomTunnelEndpoint {
let host = value_t!(matches.value_of("host"), String).unwrap_or_else(|e| e.exit());
let port = value_t!(matches.value_of("port"), u16).unwrap_or_else(|e| e.exit());
- let config = match matches.value_of("tunnel").unwrap() {
- "openvpn" => {
- let username =
- value_t!(matches.value_of("username"), String).unwrap_or_else(|e| e.exit());
- let password =
- value_t!(matches.value_of("password"), String).unwrap_or_else(|e| e.exit());
- let protocol = value_t!(matches.value_of("protocol"), TransportProtocol)
- .unwrap_or_else(|e| e.exit());
- ConnectionConfig::OpenVpn(openvpn::ConnectionConfig {
- endpoint: Endpoint::new(Ipv4Addr::UNSPECIFIED, port, protocol),
- username,
- password,
- })
- }
- // TODO: Gather all the data to build a WireguardEndpointData properly.
- // "wireguard" => TunnelEndpointData::Wireguard(WireguardEndpointData { port }),
- _ => unreachable!("Invalid tunnel protocol"),
- };
- self.update_constraints(RelaySettingsUpdate::CustomTunnelEndpoint(
- CustomTunnelEndpoint::new(host, config),
- ))
+ let username = value_t!(matches.value_of("username"), String).unwrap_or_else(|e| e.exit());
+ let password = value_t!(matches.value_of("password"), String).unwrap_or_else(|e| e.exit());
+ let protocol =
+ value_t!(matches.value_of("protocol"), TransportProtocol).unwrap_or_else(|e| e.exit());
+ CustomTunnelEndpoint::new(
+ host,
+ ConnectionConfig::OpenVpn(openvpn::ConnectionConfig {
+ endpoint: Endpoint::new(Ipv4Addr::UNSPECIFIED, port, protocol),
+ username,
+ password,
+ }),
+ )
+ }
+
+ fn read_custom_wireguard_relay(matches: &clap::ArgMatches) -> CustomTunnelEndpoint {
+ let host = value_t!(matches.value_of("host"), String).unwrap_or_else(|e| e.exit());
+ let port = value_t!(matches.value_of("port"), u16).unwrap_or_else(|e| e.exit());
+ let addresses = values_t!(matches.values_of("addr"), IpAddr).unwrap_or_else(|e| e.exit());
+ println!("addresses - {:?}", addresses);
+ let peer_key_str =
+ value_t!(matches.value_of("peer-key"), String).unwrap_or_else(|e| e.exit());
+ let gateway = value_t!(matches.value_of("gateway"), IpAddr).unwrap_or_else(|e| e.exit());
+ let mut private_key_str = String::new();
+ println!("Reading private key from standard input");
+ let _ = io::stdin().lock().read_line(&mut private_key_str);
+ if private_key_str.trim().len() == 0 {
+ eprintln!("Expected to read private key from standard input");
+ }
+ let private_key = Self::validate_wireguard_key(&private_key_str).into();
+ let peer_public_key = Self::validate_wireguard_key(&peer_key_str).into();
+
+
+ CustomTunnelEndpoint::new(
+ host,
+ ConnectionConfig::Wireguard(wireguard::ConnectionConfig {
+ tunnel: wireguard::TunnelConfig {
+ private_key,
+ addresses,
+ },
+ peer: wireguard::PeerConfig {
+ public_key: peer_public_key,
+ allowed_ips: all_of_the_internet(),
+ endpoint: SocketAddr::new(Ipv4Addr::UNSPECIFIED.into(), port),
+ },
+ gateway,
+ }),
+ )
+ }
+
+ fn validate_wireguard_key(key_str: &str) -> [u8; 32] {
+ let key_bytes = base64::decode(key_str.trim()).unwrap_or_else(|e| {
+ eprintln!("Failed to decode wireguard key: {}", e);
+ ::std::process::exit(1);
+ });
+
+ let mut key = [0u8; 32];
+ if key_bytes.len() != 32 {
+ eprintln!(
+ "Expected key length to be 32 bytes, got {}",
+ key_bytes.len()
+ );
+ ::std::process::exit(1);
+ }
+
+ key.copy_from_slice(&key_bytes);
+ key
}
fn set_location(&self, matches: &clap::ArgMatches) -> Result<()> {
diff --git a/mullvad-cli/src/cmds/tunnel.rs b/mullvad-cli/src/cmds/tunnel.rs
index 33e75d26d4..5887148abe 100644
--- a/mullvad-cli/src/cmds/tunnel.rs
+++ b/mullvad-cli/src/cmds/tunnel.rs
@@ -18,20 +18,55 @@ impl Command for Tunnel {
.about("Manage tunnel specific options")
.setting(clap::AppSettings::SubcommandRequired)
.subcommand(create_openvpn_subcommand())
+ .subcommand(create_wireguard_subcommand())
.subcommand(create_ipv6_subcommand())
}
fn run(&self, matches: &clap::ArgMatches) -> Result<()> {
- if let Some(openvpn_matches) = matches.subcommand_matches("openvpn") {
- Self::handle_openvpn_cmd(openvpn_matches)
- } else if let Some(ipv6_matches) = matches.subcommand_matches("ipv6") {
- Self::handle_ipv6_cmd(ipv6_matches)
- } else {
- unreachable!("unhandled command");
+ match matches.subcommand() {
+ ("openvpn", Some(openvpn_matches)) => Self::handle_openvpn_cmd(openvpn_matches),
+ ("wireguard", Some(wg_matches)) => Self::handle_wireguard_cmd(wg_matches),
+ ("ipv6", Some(ipv6_matches)) => Self::handle_ipv6_cmd(ipv6_matches),
+ _ => {
+ unreachable!("unhandled comand");
+ }
}
}
}
+fn create_wireguard_subcommand() -> clap::App<'static, 'static> {
+ let app = clap::SubCommand::with_name("wireguard")
+ .about("Manage options for Wireguard tunnels")
+ .setting(clap::AppSettings::SubcommandRequired)
+ .subcommand(create_wireguard_mtu_subcommand());
+ if cfg!(target_os = "linux") {
+ app.subcommand(create_wireguard_fwmark_subcommand())
+ } else {
+ app
+ }
+}
+
+fn create_wireguard_mtu_subcommand() -> clap::App<'static, 'static> {
+ clap::SubCommand::with_name("mtu")
+ .about("Configure the MTU of the wireguard tunnel")
+ .setting(clap::AppSettings::SubcommandRequired)
+ .subcommand(clap::SubCommand::with_name("get"))
+ .subcommand(clap::SubCommand::with_name("unset"))
+ .subcommand(
+ clap::SubCommand::with_name("set").arg(clap::Arg::with_name("mtu").required(true)),
+ )
+}
+
+fn create_wireguard_fwmark_subcommand() -> clap::App<'static, 'static> {
+ clap::SubCommand::with_name("fwmark")
+ .about("Configure the firewall mark used to direct traffic through Wireguard tunnel")
+ .setting(clap::AppSettings::SubcommandRequired)
+ .subcommand(clap::SubCommand::with_name("get"))
+ .subcommand(
+ clap::SubCommand::with_name("set").arg(clap::Arg::with_name("fwmark").required(true)),
+ )
+}
+
fn create_openvpn_subcommand() -> clap::App<'static, 'static> {
clap::SubCommand::with_name("openvpn")
.about("Manage options for OpenVPN tunnels")
@@ -129,39 +164,94 @@ fn create_ipv6_subcommand() -> clap::App<'static, 'static> {
impl Tunnel {
fn handle_openvpn_cmd(matches: &clap::ArgMatches) -> Result<()> {
- if let Some(m) = matches.subcommand_matches("mssfix") {
- Self::handle_openvpn_mssfix_cmd(m)
- } else if let Some(m) = matches.subcommand_matches("proxy") {
- Self::handle_openvpn_proxy_cmd(m)
- } else {
- unreachable!("unhandled command");
+ match matches.subcommand() {
+ ("mssfix", Some(mssfix_matches)) => Self::handle_openvpn_mssfix_cmd(mssfix_matches),
+ ("proxy", Some(proxy_matches)) => Self::handle_openvpn_proxy_cmd(proxy_matches),
+ _ => unreachable!("unhandled command"),
}
}
fn handle_openvpn_mssfix_cmd(matches: &clap::ArgMatches) -> Result<()> {
- if matches.subcommand_matches("get").is_some() {
- Self::process_openvpn_mssfix_get()
- } else if matches.subcommand_matches("unset").is_some() {
- Self::process_openvpn_mssfix_unset()
- } else if let Some(m) = matches.subcommand_matches("set") {
- Self::process_openvpn_mssfix_set(m)
- } else {
- unreachable!("unhandled command");
+ match matches.subcommand() {
+ ("get", Some(_)) => Self::process_openvpn_mssfix_get(),
+ ("unset", Some(_)) => Self::process_openvpn_mssfix_unset(),
+ ("set", Some(set_matches)) => Self::process_openvpn_mssfix_set(set_matches),
+ _ => unreachable!("unhandled command"),
}
}
fn handle_openvpn_proxy_cmd(matches: &clap::ArgMatches) -> Result<()> {
- if matches.subcommand_matches("get").is_some() {
- Self::process_openvpn_proxy_get()
- } else if matches.subcommand_matches("unset").is_some() {
- Self::process_openvpn_proxy_unset()
- } else if let Some(m) = matches.subcommand_matches("set") {
- Self::process_openvpn_proxy_set(m)
- } else {
- unreachable!("unhandled command");
+ match matches.subcommand() {
+ ("get", Some(_)) => Self::process_openvpn_proxy_get(),
+ ("unset", Some(_)) => Self::process_openvpn_proxy_unset(),
+ ("set", Some(set_matches)) => Self::process_openvpn_proxy_set(set_matches),
+ _ => unreachable!("unhandled command"),
}
}
+ fn handle_wireguard_cmd(matches: &clap::ArgMatches) -> Result<()> {
+ match matches.subcommand() {
+ ("mtu", Some(matches)) => match matches.subcommand() {
+ ("get", _) => Self::process_wireguard_mtu_get(),
+ ("set", Some(matches)) => Self::process_wireguard_mtu_set(matches),
+ ("unset", _) => Self::process_wireguard_mtu_unset(),
+ _ => unreachable!("unhandled command"),
+ },
+
+ #[cfg(target_os = "linux")]
+ ("fwmark", Some(matches)) => match matches.subcommand() {
+ ("get", _) => Self::process_wireguard_fwmark_get(),
+ ("set", Some(fwmark_matches)) => Self::process_wireguard_fwmark_set(fwmark_matches),
+ _ => unreachable!("unhandled command"),
+ },
+ _ => unreachable!("unhandled command"),
+ }
+ }
+
+ fn process_wireguard_mtu_get() -> Result<()> {
+ let tunnel_options = Self::get_tunnel_options()?;
+ println!(
+ "mtu: {}",
+ tunnel_options
+ .wireguard
+ .mtu
+ .map(|mtu| mtu.to_string())
+ .unwrap_or("unset".into())
+ );
+ Ok(())
+ }
+
+ fn process_wireguard_mtu_set(matches: &clap::ArgMatches) -> Result<()> {
+ let mtu = value_t!(matches.value_of("mtu"), u16).unwrap_or_else(|e| e.exit());
+ let mut rpc = new_rpc_client()?;
+ rpc.set_wireguard_mtu(Some(mtu))?;
+ println!("Wireguard MTU has been updated");
+ Ok(())
+ }
+
+ fn process_wireguard_mtu_unset() -> Result<()> {
+ let mut rpc = new_rpc_client()?;
+ rpc.set_wireguard_mtu(None)?;
+ println!("Wireguard MTU has been unset");
+ Ok(())
+ }
+
+ #[cfg(target_os = "linux")]
+ fn process_wireguard_fwmark_get() -> Result<()> {
+ let tunnel_options = Self::get_tunnel_options()?;
+ println!("fwmark: {}", tunnel_options.wireguard.fwmark);
+ Ok(())
+ }
+
+ #[cfg(target_os = "linux")]
+ fn process_wireguard_fwmark_set(matches: &clap::ArgMatches) -> Result<()> {
+ let fwmark = value_t!(matches.value_of("fwmark"), i32).unwrap_or_else(|e| e.exit());
+ let mut rpc = new_rpc_client()?;
+ rpc.set_wireguard_fwmark(fwmark)?;
+ println!("Firewall mark parameter has been updated");
+ Ok(())
+ }
+
fn handle_ipv6_cmd(matches: &clap::ArgMatches) -> Result<()> {
if matches.subcommand_matches("get").is_some() {
Self::process_ipv6_get()
diff --git a/mullvad-daemon/src/lib.rs b/mullvad-daemon/src/lib.rs
index eeb0f5755a..f66263665f 100644
--- a/mullvad-daemon/src/lib.rs
+++ b/mullvad-daemon/src/lib.rs
@@ -343,9 +343,12 @@ impl Daemon {
.ok_or_else(|| Error::from("No account token configured"))
.map(|account_token| {
match self.settings.get_relay_settings() {
- RelaySettings::CustomTunnelEndpoint(custom_relay) => custom_relay
- .to_tunnel_parameters(self.settings.get_tunnel_options().clone())
- .chain_err(|| "Custom tunnel endpoint could not be resolved"),
+ RelaySettings::CustomTunnelEndpoint(custom_relay) => {
+ self.last_generated_relay = None;
+ custom_relay
+ .to_tunnel_parameters(self.settings.get_tunnel_options().clone())
+ .chain_err(|| "Custom tunnel endpoint could not be resolved")
+ }
RelaySettings::Normal(constraints) => self
.relay_selector
.get_tunnel_endpoint(&constraints, retry_attempt)
@@ -429,6 +432,9 @@ impl Daemon {
SetOpenVpnMssfix(tx, mssfix_arg) => self.on_set_openvpn_mssfix(tx, mssfix_arg),
SetOpenVpnProxy(tx, proxy) => self.on_set_openvpn_proxy(tx, proxy),
SetEnableIpv6(tx, enable_ipv6) => self.on_set_enable_ipv6(tx, enable_ipv6),
+ #[cfg(target_os = "linux")]
+ SetWireguardFwmark(tx, fwmark) => self.on_set_wireguard_fwmark(tx, fwmark),
+ SetWireguardMtu(tx, mtu) => self.on_set_wireguard_mtu(tx, mtu),
GetSettings(tx) => self.on_get_settings(tx),
GetVersionInfo(tx) => self.on_get_version_info(tx),
GetCurrentVersion(tx) => self.on_get_current_version(tx),
@@ -723,6 +729,39 @@ impl Daemon {
}
}
+ #[cfg(target_os = "linux")]
+ fn on_set_wireguard_fwmark(&mut self, tx: oneshot::Sender<()>, fwmark: i32) {
+ let save_result = self.settings.set_wireguard_fwmark(fwmark);
+ match save_result.chain_err(|| "Unable to save settings") {
+ Ok(settings_changed) => {
+ Self::oneshot_send(tx, (), "set_wireguard_fwmark response");
+ if settings_changed {
+ self.management_interface_broadcaster
+ .notify_settings(&self.settings);
+ info!("Initiating tunnel restart because the WireGuard fwmark setting changed");
+ self.reconnect_tunnel();
+ }
+ }
+ Err(e) => error!("{}", e.display_chain()),
+ }
+ }
+
+ fn on_set_wireguard_mtu(&mut self, tx: oneshot::Sender<()>, mtu: Option<u16>) {
+ let save_result = self.settings.set_wireguard_mtu(mtu);
+ match save_result.chain_err(|| "Unable to save settings") {
+ Ok(settings_changed) => {
+ Self::oneshot_send(tx, (), "set_wireguard_mtu response");
+ if settings_changed {
+ self.management_interface_broadcaster
+ .notify_settings(&self.settings);
+ info!("Initiating tunnel restart because the WireGuard MTU setting changed");
+ self.reconnect_tunnel();
+ }
+ }
+ Err(e) => error!("{}", e.display_chain()),
+ }
+ }
+
fn on_get_settings(&self, tx: oneshot::Sender<Settings>) {
Self::oneshot_send(tx, self.settings.clone(), "get_settings response");
}
diff --git a/mullvad-daemon/src/management_interface.rs b/mullvad-daemon/src/management_interface.rs
index cea4d6a75d..aeeda483a7 100644
--- a/mullvad-daemon/src/management_interface.rs
+++ b/mullvad-daemon/src/management_interface.rs
@@ -121,6 +121,14 @@ build_rpc_trait! {
#[rpc(meta, name = "set_enable_ipv6")]
fn set_enable_ipv6(&self, Self::Metadata, bool) -> BoxFuture<(), Error>;
+ /// Set firewall marker for wireguard tunnels on Linux
+ #[rpc(meta, name = "set_wireguard_fwmark")]
+ fn set_wireguard_fwmark(&self, Self::Metadata, i32) -> BoxFuture<(), Error>;
+
+ /// Set MTU for wireguard tunnels
+ #[rpc(meta, name = "set_wireguard_mtu")]
+ fn set_wireguard_mtu(&self, Self::Metadata, Option<u16>) -> BoxFuture<(), Error>;
+
/// Returns the current daemon settings
#[rpc(meta, name = "get_settings")]
fn get_settings(&self, Self::Metadata) -> BoxFuture<Settings, Error>;
@@ -198,6 +206,11 @@ pub enum ManagementCommand {
),
/// Set if IPv6 should be enabled in the tunnel
SetEnableIpv6(OneshotSender<()>, bool),
+ #[cfg(target_os = "linux")]
+ /// Set wireguard firewall mark
+ SetWireguardFwmark(OneshotSender<()>, i32),
+ /// Set MTU for wireguard tunnels
+ SetWireguardMtu(OneshotSender<()>, Option<u16>),
/// Get the daemon settings
GetSettings(OneshotSender<Settings>),
/// Get information about the currently running and latest app versions
@@ -616,6 +629,34 @@ impl<T: From<ManagementCommand> + 'static + Send> ManagementInterfaceApi
Box::new(future)
}
+ /// Set firewall marker for wireguard tunnels on Linux
+ fn set_wireguard_fwmark(&self, _: Self::Metadata, fwmark: i32) -> BoxFuture<(), Error> {
+ #[cfg(target_os = "linux")]
+ {
+ log::debug!("set_wireguard_fwmark({:?})", fwmark);
+ let (tx, rx) = sync::oneshot::channel();
+ let future = self
+ .send_command_to_daemon(ManagementCommand::SetWireguardFwmark(tx, fwmark))
+ .and_then(|_| rx.map_err(|_| Error::internal_error()));
+
+ Box::new(future)
+ }
+ #[cfg(any(windows, target_os = "macos"))]
+ {
+ return Box::new(future::err(Error::method_not_found()));
+ }
+ }
+
+ /// Set MTU for wireguard tunnels
+ fn set_wireguard_mtu(&self, _: Self::Metadata, mtu: Option<u16>) -> BoxFuture<(), Error> {
+ log::debug!("set_wireguard_mtu({:?})", mtu);
+ let (tx, rx) = sync::oneshot::channel();
+ let future = self
+ .send_command_to_daemon(ManagementCommand::SetWireguardMtu(tx, mtu))
+ .and_then(|_| rx.map_err(|_| Error::internal_error()));
+ Box::new(future)
+ }
+
fn get_settings(&self, _: Self::Metadata) -> BoxFuture<Settings, Error> {
log::debug!("get_settings");
let (tx, rx) = sync::oneshot::channel();
diff --git a/mullvad-ipc-client/src/lib.rs b/mullvad-ipc-client/src/lib.rs
index d7eaf653ef..05d96d9dee 100644
--- a/mullvad-ipc-client/src/lib.rs
+++ b/mullvad-ipc-client/src/lib.rs
@@ -189,6 +189,14 @@ impl DaemonRpcClient {
self.call("set_enable_ipv6", &[enabled])
}
+ pub fn set_wireguard_mtu(&mut self, mtu: Option<u16>) -> Result<()> {
+ self.call("set_wireguard_mtu", &[mtu])
+ }
+
+ pub fn set_wireguard_fwmark(&mut self, fwmark: i32) -> Result<()> {
+ self.call("set_wireguard_fwmark", &[fwmark])
+ }
+
pub fn set_openvpn_mssfix(&mut self, mssfix: Option<u16>) -> Result<()> {
self.call("set_openvpn_mssfix", &[mssfix])
}
diff --git a/mullvad-types/Cargo.toml b/mullvad-types/Cargo.toml
index c0202ed1b6..3ea590c995 100644
--- a/mullvad-types/Cargo.toml
+++ b/mullvad-types/Cargo.toml
@@ -14,7 +14,7 @@ error-chain = "0.12"
log = "0.4"
regex = "1"
lazy_static = "1.1.0"
-ipnetwork = "0.13"
+ipnetwork = "0.14"
talpid-types = { path = "../talpid-types" }
mullvad-paths = { path = "../mullvad-paths" }
diff --git a/mullvad-types/src/endpoint.rs b/mullvad-types/src/endpoint.rs
index 311ca267ba..da0d5b5394 100644
--- a/mullvad-types/src/endpoint.rs
+++ b/mullvad-types/src/endpoint.rs
@@ -103,7 +103,7 @@ impl TunnelEndpointData {
}
}
-fn all_of_the_internet() -> Vec<IpNetwork> {
+pub fn all_of_the_internet() -> Vec<IpNetwork> {
vec![
"0.0.0.0/0".parse().expect("Failed to parse ipv6 network"),
"::0/0".parse().expect("Failed to parse ipv6 network"),
diff --git a/mullvad-types/src/settings.rs b/mullvad-types/src/settings.rs
index cfc445b3c9..92be2b83df 100644
--- a/mullvad-types/src/settings.rs
+++ b/mullvad-types/src/settings.rs
@@ -225,6 +225,25 @@ impl Settings {
}
}
+ #[cfg(target_os = "linux")]
+ pub fn set_wireguard_fwmark(&mut self, fwmark: i32) -> Result<bool> {
+ if self.tunnel_options.wireguard.fwmark != fwmark {
+ self.tunnel_options.wireguard.fwmark = fwmark;
+ self.save().map(|_| true)
+ } else {
+ Ok(false)
+ }
+ }
+
+ pub fn set_wireguard_mtu(&mut self, mtu: Option<u16>) -> Result<bool> {
+ if self.tunnel_options.wireguard.mtu != mtu {
+ self.tunnel_options.wireguard.mtu = mtu;
+ self.save().map(|_| true)
+ } else {
+ Ok(false)
+ }
+ }
+
pub fn get_tunnel_options(&self) -> &TunnelOptions {
&self.tunnel_options
}
diff --git a/talpid-core/Cargo.toml b/talpid-core/Cargo.toml
index cc76d632e0..154440f13c 100644
--- a/talpid-core/Cargo.toml
+++ b/talpid-core/Cargo.toml
@@ -27,7 +27,7 @@ talpid-types = { path = "../talpid-types" }
[target.'cfg(unix)'.dependencies]
hex = "0.3"
-ipnetwork = "0.13"
+ipnetwork = "0.14"
lazy_static = "1.0"
tun = { git = "https://github.com/pinkisemils/rust-tun", branch = "add-raw-fd-traits" }
nix = "0.12"
@@ -46,7 +46,8 @@ which = "2.0"
err-derive = "0.1.5"
[target.'cfg(target_os = "macos")'.dependencies]
-pfctl = "0.2"
+# TODO: Specify 0.2.1 once the crate gets published
+pfctl = { git = "https://github.com/mullvad/pfctl-rs", rev = "9f31b5ddcab941862470075eab83bb398195f3d6" }
system-configuration = "0.2"
[target.'cfg(windows)'.dependencies]
diff --git a/talpid-core/src/tunnel/wireguard/config.rs b/talpid-core/src/tunnel/wireguard/config.rs
index a15f377165..ff167edb7c 100644
--- a/talpid-core/src/tunnel/wireguard/config.rs
+++ b/talpid-core/src/tunnel/wireguard/config.rs
@@ -50,7 +50,7 @@ impl Config {
wg_options: &wireguard::TunnelOptions,
generic_options: &GenericTunnelOptions,
) -> Result<Config> {
- ensure!(peers.is_empty(), ErrorKind::NoPeersSuppliedError);
+ ensure!(!peers.is_empty(), ErrorKind::NoPeersSuppliedError);
let mtu = wg_options.mtu.unwrap_or(DEFAULT_MTU);
let is_ipv6_enabled = mtu >= SMALLEST_IPV6_MTU && generic_options.enable_ipv6;
@@ -61,7 +61,7 @@ impl Config {
.cloned()
.filter(|ip| ip.is_ipv4() || is_ipv6_enabled)
.collect();
- ensure!(peer.allowed_ips.is_empty(), ErrorKind::InvalidPeerIpError);
+ ensure!(!peer.allowed_ips.is_empty(), ErrorKind::InvalidPeerIpError);
}
tunnel.addresses = tunnel
@@ -69,7 +69,10 @@ impl Config {
.into_iter()
.filter(|ip| ip.is_ipv4() || is_ipv6_enabled)
.collect();
- ensure!(tunnel.addresses.is_empty(), ErrorKind::InvalidTunnelIpError);
+ ensure!(
+ !tunnel.addresses.is_empty(),
+ ErrorKind::InvalidTunnelIpError
+ );
Ok(Config {
tunnel,
diff --git a/talpid-types/Cargo.toml b/talpid-types/Cargo.toml
index f8023d8e86..9ef4fa89b3 100644
--- a/talpid-types/Cargo.toml
+++ b/talpid-types/Cargo.toml
@@ -8,7 +8,7 @@ edition = "2018"
[dependencies]
serde = { version = "1.0", features = ["derive"] }
-ipnetwork = "0.13"
+ipnetwork = "0.14"
base64 = "0.10"
hex = "0.3"
error-chain = "0.12"