diff options
| author | Emīls Piņķis <emils@mullvad.net> | 2019-02-05 11:18:20 +0000 |
|---|---|---|
| committer | Emīls Piņķis <emils@mullvad.net> | 2019-02-05 11:18:20 +0000 |
| commit | 0d20edce0e6d8fdd8241d502e4e914307cc12fb2 (patch) | |
| tree | dad5f0bfdc1428b79b5a3c2d3a55532bbb14e334 | |
| parent | 54142b0fa0b26a33d8e6181a61e03b4b46abda00 (diff) | |
| parent | 01d6d3d874fde5ad8c4ed7f7152e25841aff2433 (diff) | |
| download | mullvadvpn-0d20edce0e6d8fdd8241d502e4e914307cc12fb2.tar.xz mullvadvpn-0d20edce0e6d8fdd8241d502e4e914307cc12fb2.zip | |
Merge branch 'adjust-cli-gui-for-wg'
| -rw-r--r-- | Cargo.lock | 26 | ||||
| -rw-r--r-- | mullvad-cli/Cargo.toml | 3 | ||||
| -rw-r--r-- | mullvad-cli/src/cmds/relay.rs | 204 | ||||
| -rw-r--r-- | mullvad-cli/src/cmds/tunnel.rs | 146 | ||||
| -rw-r--r-- | mullvad-daemon/src/lib.rs | 45 | ||||
| -rw-r--r-- | mullvad-daemon/src/management_interface.rs | 41 | ||||
| -rw-r--r-- | mullvad-ipc-client/src/lib.rs | 8 | ||||
| -rw-r--r-- | mullvad-types/Cargo.toml | 2 | ||||
| -rw-r--r-- | mullvad-types/src/endpoint.rs | 2 | ||||
| -rw-r--r-- | mullvad-types/src/settings.rs | 19 | ||||
| -rw-r--r-- | talpid-core/Cargo.toml | 5 | ||||
| -rw-r--r-- | talpid-core/src/tunnel/wireguard/config.rs | 9 | ||||
| -rw-r--r-- | talpid-types/Cargo.toml | 2 |
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" |
