diff options
| author | David Lönnhager <david.l@mullvad.net> | 2023-08-31 13:31:09 +0200 |
|---|---|---|
| committer | David Lönnhager <david.l@mullvad.net> | 2023-08-31 13:31:09 +0200 |
| commit | bbe31c1e236d66f1a77a7f944c8a264a486b6223 (patch) | |
| tree | f213aa245e742dd6ae58ccd82193b81001c2f9c5 | |
| parent | 08ec4a88df17088a2fc81c3ee5f2d1d62ef0c1f1 (diff) | |
| parent | 32f5426bb5c9ec886cfdcbb0c4fc3b516ef2d142 (diff) | |
| download | mullvadvpn-bbe31c1e236d66f1a77a7f944c8a264a486b6223.tar.xz mullvadvpn-bbe31c1e236d66f1a77a7f944c8a264a486b6223.zip | |
Merge branch 'win-remove-user-wg-des-316' into main
29 files changed, 238 insertions, 824 deletions
diff --git a/.github/workflows/daemon.yml b/.github/workflows/daemon.yml index ab270c7b67..6112f30fe8 100644 --- a/.github/workflows/daemon.yml +++ b/.github/workflows/daemon.yml @@ -148,11 +148,6 @@ jobs: target: i686-pc-windows-msvc default: true - - name: Install Go - uses: actions/setup-go@v3 - with: - go-version: 1.18.5 - - name: Install msbuild uses: microsoft/setup-msbuild@v1.0.2 with: diff --git a/BuildInstructions.md b/BuildInstructions.md index 15d8a29ec2..00d5c5440e 100644 --- a/BuildInstructions.md +++ b/BuildInstructions.md @@ -23,7 +23,7 @@ on your platform please submit an issue or a pull request. Install the `msi` hosted here: https://github.com/volta-cli/volta -- Install Go (ideally version `1.18`) by following the [official +- (Not Windows) Install Go (ideally version `1.18`) by following the [official instructions](https://golang.org/doc/install). Newer versions may work too. @@ -102,11 +102,6 @@ The host has to have the following installed: - `bash` installed as well as a few base unix utilities, including `sed` and `tail`. You are recommended to use [Git for Windows]. -- `mingw` is required for CGo. - The latest [`mingw-w64`](https://github.com/niXman/mingw-builds-binaries/releases) build works - well. Specifically, you'll need one of the releases labeled `x86_64`, `win32`, and `msvcrt`, - such as <https://github.com/niXman/mingw-builds-binaries/releases/download/13.1.0-rt_v11-rev1/x86_64-13.1.0-release-win32-seh-msvcrt-rt_v11-rev1.7z>. - - The `x86` target is required for building some NSIS plugins: ```bash diff --git a/CHANGELOG.md b/CHANGELOG.md index 6cc31848ef..fd5886c5f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -101,6 +101,9 @@ Line wrap the file at 100 chars. Th ### Removed - Remove the CLI subcommand `mullvad relay set hostname`. +#### Windows +- Remove wireguard-go (userspace WireGuard) support. + ## [2023.4] - 2023-06-27 ### Fixed @@ -200,12 +200,9 @@ function build { # Compile and link all binaries. ################################################################################ - log_header "Building wireguard-go$for_target_string" - - ./wireguard/build-wireguard-go.sh "$current_target" - if [[ "$SIGN" == "true" && "$(uname -s)" == "MINGW"* ]]; then - # Windows can only be built for this one target anyway, so it can be hardcoded. - sign_win "build/lib/x86_64-pc-windows-msvc/libwg.dll" + if [[ "$(uname -s)" != "MINGW"* ]]; then + log_header "Building wireguard-go$for_target_string" + ./wireguard/build-wireguard-go.sh "$current_target" fi log_header "Building Rust code in $RUST_BUILD_MODE mode using $RUSTC_VERSION$for_target_string" diff --git a/ci/check-rust.sh b/ci/check-rust.sh index 9ecf050f8e..d42784d36e 100755 --- a/ci/check-rust.sh +++ b/ci/check-rust.sh @@ -5,7 +5,9 @@ set -eux export RUSTFLAGS="--deny warnings" # Build WireGuard Go -./wireguard/build-wireguard-go.sh +if [[ "$(uname -s)" != "MINGW"* ]]; then + ./wireguard/build-wireguard-go.sh +fi # Build Rust crates source env.sh diff --git a/gui/tasks/distribution.js b/gui/tasks/distribution.js index fa27093e93..e1ba96103e 100644 --- a/gui/tasks/distribution.js +++ b/gui/tasks/distribution.js @@ -143,7 +143,6 @@ const config = { to: '.', }, { from: distAssets('binaries/x86_64-pc-windows-msvc/openvpn.exe'), to: '.' }, - { from: buildAssets('lib/x86_64-pc-windows-msvc/libwg.dll'), to: '.' }, { from: distAssets('binaries/x86_64-pc-windows-msvc/wintun/wintun.dll'), to: '.' }, { from: distAssets('binaries/x86_64-pc-windows-msvc/split-tunnel/mullvad-split-tunnel.sys'), to: '.' }, { diff --git a/mullvad-daemon/src/lib.rs b/mullvad-daemon/src/lib.rs index f0516dd1fc..e757258c73 100644 --- a/mullvad-daemon/src/lib.rs +++ b/mullvad-daemon/src/lib.rs @@ -292,9 +292,6 @@ pub enum DaemonCommand { /// Returns all processes currently being excluded from the tunnel #[cfg(windows)] GetSplitTunnelProcesses(ResponseTx<Vec<ExcludedProcess>, split_tunnel::Error>), - /// Toggle wireguard-nt on or off - #[cfg(target_os = "windows")] - UseWireGuardNt(ResponseTx<(), Error>, bool), /// Notify the split tunnel monitor that a volume was mounted or dismounted #[cfg(target_os = "windows")] CheckVolumes(ResponseTx<(), Error>), @@ -1064,8 +1061,6 @@ where #[cfg(windows)] GetSplitTunnelProcesses(tx) => self.on_get_split_tunnel_processes(tx), #[cfg(target_os = "windows")] - UseWireGuardNt(tx, state) => self.on_use_wireguard_nt(tx, state).await, - #[cfg(target_os = "windows")] CheckVolumes(tx) => self.on_check_volumes(tx), SetObfuscationSettings(tx, settings) => { self.on_set_obfuscation_settings(tx, settings).await @@ -1753,41 +1748,6 @@ where } #[cfg(windows)] - async fn on_use_wireguard_nt(&mut self, tx: ResponseTx<(), Error>, state: bool) { - match self - .settings - .update(move |settings| settings.tunnel_options.wireguard.use_wireguard_nt = state) - .await - { - Ok(settings_changed) => { - Self::oneshot_send(tx, Ok(()), "use_wireguard_nt response"); - if settings_changed { - self.parameters_generator - .set_tunnel_options(&self.settings.tunnel_options) - .await; - self.event_listener - .notify_settings(self.settings.to_settings()); - if let Some(TunnelType::Wireguard) = self.get_target_tunnel_type() { - log::info!("Initiating tunnel restart"); - self.reconnect_tunnel(); - } - } - } - Err(error) => { - log::error!( - "{}", - error.display_chain_with_msg("Unable to save settings") - ); - Self::oneshot_send( - tx, - Err(Error::SettingsError(error)), - "use_wireguard_nt response", - ); - } - } - } - - #[cfg(windows)] fn on_check_volumes(&mut self, tx: ResponseTx<(), Error>) { if self.volume_update_tx.unbounded_send(()).is_ok() { let _ = tx.send(Ok(())); diff --git a/mullvad-daemon/src/management_interface.rs b/mullvad-daemon/src/management_interface.rs index 1e21cc881d..76b6a7e4fd 100644 --- a/mullvad-daemon/src/management_interface.rs +++ b/mullvad-daemon/src/management_interface.rs @@ -846,22 +846,6 @@ impl ManagementService for ManagementServiceImpl { } #[cfg(windows)] - async fn set_use_wireguard_nt(&self, request: Request<bool>) -> ServiceResult<()> { - log::debug!("set_use_wireguard_nt"); - let state = request.into_inner(); - let (tx, rx) = oneshot::channel(); - self.send_command_to_daemon(DaemonCommand::UseWireGuardNt(tx, state))?; - self.wait_for_result(rx) - .await? - .map_err(map_daemon_error) - .map(Response::new) - } - #[cfg(not(windows))] - async fn set_use_wireguard_nt(&self, _: Request<bool>) -> ServiceResult<()> { - Ok(Response::new(())) - } - - #[cfg(windows)] async fn check_volumes(&self, _: Request<()>) -> ServiceResult<()> { log::debug!("check_volumes"); let (tx, rx) = oneshot::channel(); diff --git a/mullvad-management-interface/proto/management_interface.proto b/mullvad-management-interface/proto/management_interface.proto index f82f55078a..4fdff3e75c 100644 --- a/mullvad-management-interface/proto/management_interface.proto +++ b/mullvad-management-interface/proto/management_interface.proto @@ -89,8 +89,6 @@ service ManagementService { rpc SetSplitTunnelState(google.protobuf.BoolValue) returns (google.protobuf.Empty) {} rpc GetExcludedProcesses(google.protobuf.Empty) returns (ExcludedProcessList) {} - rpc SetUseWireguardNt(google.protobuf.BoolValue) returns (google.protobuf.Empty) {} - // Notify the split tunnel monitor that a volume was mounted or dismounted // (Windows). rpc CheckVolumes(google.protobuf.Empty) returns (google.protobuf.Empty) {} @@ -469,7 +467,6 @@ message TunnelOptions { message WireguardOptions { uint32 mtu = 1; google.protobuf.Duration rotation_interval = 2; - bool use_wireguard_nt = 3; QuantumResistantState quantum_resistant = 4; } message GenericOptions { bool enable_ipv6 = 1; } diff --git a/mullvad-management-interface/src/client.rs b/mullvad-management-interface/src/client.rs index b8c0b32085..e9acad1337 100644 --- a/mullvad-management-interface/src/client.rs +++ b/mullvad-management-interface/src/client.rs @@ -582,15 +582,6 @@ impl MullvadProxyClient { .collect::<Vec<_>>()) } - #[cfg(target_os = "windows")] - pub async fn set_use_wireguard_nt(&mut self, state: bool) -> Result<()> { - self.0 - .set_use_wireguard_nt(state) - .await - .map_err(Error::Rpc)?; - Ok(()) - } - // check_volumes } diff --git a/mullvad-management-interface/src/types/conversions/settings.rs b/mullvad-management-interface/src/types/conversions/settings.rs index c0611c799f..a429937410 100644 --- a/mullvad-management-interface/src/types/conversions/settings.rs +++ b/mullvad-management-interface/src/types/conversions/settings.rs @@ -84,10 +84,6 @@ impl From<&mullvad_types::settings::TunnelOptions> for proto::TunnelOptions { prost_types::Duration::try_from(std::time::Duration::from(ivl)) .expect("Failed to convert std::time::Duration to prost_types::Duration for tunnel_options.wireguard.rotation_interval") }), - #[cfg(windows)] - use_wireguard_nt: options.wireguard.use_wireguard_nt, - #[cfg(not(windows))] - use_wireguard_nt: false, quantum_resistant: Some(proto::QuantumResistantState::from(options.wireguard.quantum_resistant)), }), generic: Some(proto::tunnel_options::GenericOptions { @@ -250,8 +246,6 @@ impl TryFrom<proto::TunnelOptions> for mullvad_types::settings::TunnelOptions { } else { None }, - #[cfg(windows)] - use_wireguard_nt: wireguard_options.use_wireguard_nt, rotation_interval: wireguard_options .rotation_interval .map(std::time::Duration::try_from) diff --git a/mullvad-types/src/wireguard.rs b/mullvad-types/src/wireguard.rs index 9fdda6cb20..f551250324 100644 --- a/mullvad-types/src/wireguard.rs +++ b/mullvad-types/src/wireguard.rs @@ -198,10 +198,6 @@ pub struct TunnelOptions { jnix(map = "|maybe_mtu| maybe_mtu.map(|mtu| mtu as i32)") )] pub mtu: Option<u16>, - /// Temporary switch for wireguard-nt - #[cfg(windows)] - #[serde(rename = "wireguard_nt")] - pub use_wireguard_nt: bool, /// Obtain a PSK using the relay config client. pub quantum_resistant: QuantumResistantState, /// Interval used for automatic key rotation @@ -215,8 +211,6 @@ impl Default for TunnelOptions { TunnelOptions { mtu: None, quantum_resistant: QuantumResistantState::Auto, - #[cfg(windows)] - use_wireguard_nt: true, rotation_interval: None, } } @@ -226,8 +220,6 @@ impl TunnelOptions { pub fn into_talpid_tunnel_options(self) -> wireguard::TunnelOptions { wireguard::TunnelOptions { mtu: self.mtu, - #[cfg(windows)] - use_wireguard_nt: self.use_wireguard_nt, quantum_resistant: match self.quantum_resistant { QuantumResistantState::Auto => QUANTUM_RESISTANT_AUTO_STATE, QuantumResistantState::On => true, diff --git a/talpid-core/build.rs b/talpid-core/build.rs index 1c16a35e74..330d3c490f 100644 --- a/talpid-core/build.rs +++ b/talpid-core/build.rs @@ -54,7 +54,6 @@ fn main() { declare_library(WINFW_DIR_VAR, WINFW_BUILD_DIR, "winfw"); let lib_dir = manifest_dir().join("../build/lib/x86_64-pc-windows-msvc"); println!("cargo:rustc-link-search={}", &lib_dir.display()); - println!("cargo:rustc-link-lib=dylib=libwg"); } #[cfg(not(windows))] diff --git a/talpid-types/src/net/wireguard.rs b/talpid-types/src/net/wireguard.rs index 4de5ceb9c1..2c79e2938b 100644 --- a/talpid-types/src/net/wireguard.rs +++ b/talpid-types/src/net/wireguard.rs @@ -74,9 +74,6 @@ pub struct TunnelConfig { pub struct TunnelOptions { /// MTU for the wireguard tunnel pub mtu: Option<u16>, - /// Temporary switch for wireguard-nt - #[cfg(windows)] - pub use_wireguard_nt: bool, /// Perform PQ-safe PSK exchange when connecting pub quantum_resistant: bool, } diff --git a/talpid-wireguard/build.rs b/talpid-wireguard/build.rs index b02f603440..91a4a4e5d3 100644 --- a/talpid-wireguard/build.rs +++ b/talpid-wireguard/build.rs @@ -20,6 +20,9 @@ fn main() { }; println!("cargo:rustc-link-lib{link_type}=wg"); + + #[cfg(any(target_os = "linux", target_os = "macos", target_os = "android"))] + println!("cargo:rustc-cfg=wireguard_go"); } fn declare_libs_dir(base: &str) { diff --git a/talpid-wireguard/src/config.rs b/talpid-wireguard/src/config.rs index 358aa5d64a..fa4b7e078e 100644 --- a/talpid-wireguard/src/config.rs +++ b/talpid-wireguard/src/config.rs @@ -24,9 +24,6 @@ pub struct Config { /// Enable IPv6 routing rules #[cfg(target_os = "linux")] pub enable_ipv6: bool, - /// Temporary switch for wireguard-nt - #[cfg(target_os = "windows")] - pub use_wireguard_nt: bool, /// Obfuscator config to be used for reaching the relay. pub obfuscator_config: Option<ObfuscatorConfig>, } @@ -121,8 +118,6 @@ impl Config { fwmark: connection_config.fwmark, #[cfg(target_os = "linux")] enable_ipv6: generic_options.enable_ipv6, - #[cfg(target_os = "windows")] - use_wireguard_nt: wg_options.use_wireguard_nt, obfuscator_config, }) } diff --git a/talpid-wireguard/src/lib.rs b/talpid-wireguard/src/lib.rs index 784cafa75b..cdc09224ef 100644 --- a/talpid-wireguard/src/lib.rs +++ b/talpid-wireguard/src/lib.rs @@ -29,15 +29,13 @@ use talpid_tunnel::tun_provider; use talpid_tunnel::{tun_provider::TunProvider, TunnelArgs, TunnelEvent, TunnelMetadata}; use ipnetwork::IpNetwork; -#[cfg(windows)] -use talpid_types::BoxedError; use talpid_types::{ net::{ obfuscation::ObfuscatorConfig, wireguard::{PresharedKey, PrivateKey, PublicKey}, AllowedTunnelTraffic, Endpoint, TransportProtocol, }, - ErrorExt, + BoxedError, ErrorExt, }; use tokio::sync::Mutex as AsyncMutex; use tunnel_obfuscation::{ @@ -50,12 +48,14 @@ mod connectivity_check; mod logging; mod ping_monitor; mod stats; +#[cfg(wireguard_go)] mod wireguard_go; #[cfg(target_os = "linux")] pub(crate) mod wireguard_kernel; #[cfg(windows)] mod wireguard_nt; +#[cfg(wireguard_go)] use self::wireguard_go::WgGoTunnel; type Result<T> = std::result::Result<T, Error>; @@ -764,44 +764,33 @@ impl WireguardMonitor { } #[cfg(target_os = "windows")] - if config.use_wireguard_nt { - log::debug!("Using WireGuardNT"); - return wireguard_nt::WgNtTunnel::start_tunnel( - config, - log_path, - resource_dir, - setup_done_tx, - ) - .map(|tun| Box::new(tun) as Box<dyn Tunnel + 'static>) - .map_err(Error::TunnelError); + { + wireguard_nt::WgNtTunnel::start_tunnel(config, log_path, resource_dir, setup_done_tx) + .map(|tun| Box::new(tun) as Box<dyn Tunnel + 'static>) + .map_err(Error::TunnelError) } - #[cfg(not(windows))] - let routes = Self::get_tunnel_destinations(config).flat_map(Self::replace_default_prefixes); + #[cfg(wireguard_go)] + { + let routes = + Self::get_tunnel_destinations(config).flat_map(Self::replace_default_prefixes); - #[cfg(target_os = "android")] - let config = Self::patch_allowed_ips(config, psk_negotiation); + #[cfg(target_os = "android")] + let config = Self::patch_allowed_ips(config, psk_negotiation); - #[cfg(any(target_os = "linux", windows))] - log::debug!("Using userspace WireGuard implementation"); - Ok(Box::new( - WgGoTunnel::start_tunnel( - #[allow(clippy::needless_borrow)] - &config, - log_path, - #[cfg(not(windows))] - tun_provider, - #[cfg(not(windows))] - routes, - #[cfg(windows)] - route_manager_handle, - #[cfg(windows)] - setup_done_tx, - #[cfg(windows)] - &runtime, - ) - .map_err(Error::TunnelError)?, - )) + #[cfg(target_os = "linux")] + log::debug!("Using userspace WireGuard implementation"); + Ok(Box::new( + WgGoTunnel::start_tunnel( + #[allow(clippy::needless_borrow)] + &config, + log_path, + tun_provider, + routes, + ) + .map_err(Error::TunnelError)?, + )) + } } /// Blocks the current thread until tunnel disconnects @@ -1014,7 +1003,7 @@ pub enum TunnelError { /// Error whilst trying to parse the WireGuard config to read the stats #[error(display = "Reading tunnel stats failed")] - StatsError(#[error(source)] stats::Error), + StatsError(#[error(source)] BoxedError), /// Error whilst trying to retrieve config of a WireGuard tunnel #[error(display = "Failed to get config of WireGuard tunnel")] diff --git a/talpid-wireguard/src/logging.rs b/talpid-wireguard/src/logging.rs index 5f006d418c..f9adcb7f53 100644 --- a/talpid-wireguard/src/logging.rs +++ b/talpid-wireguard/src/logging.rs @@ -1,6 +1,5 @@ use once_cell::sync::Lazy; use parking_lot::Mutex; -use std::ffi::{c_char, c_void}; use std::{collections::HashMap, fmt, fs, io::Write, path::Path}; static LOG_MUTEX: Lazy<Mutex<HashMap<u32, fs::File>>> = Lazy::new(|| Mutex::new(HashMap::new())); @@ -45,10 +44,12 @@ pub fn clean_up_logging(ordinal: u32) { map.remove(&ordinal); } -#[allow(dead_code)] pub enum LogLevel { + #[cfg_attr(windows, allow(dead_code))] Verbose, + #[cfg_attr(wireguard_go, allow(dead_code))] Info, + #[cfg_attr(wireguard_go, allow(dead_code))] Warning, Error, } @@ -70,7 +71,6 @@ impl AsRef<str> for LogLevel { } } -#[cfg(windows)] pub fn log(context: u32, level: LogLevel, tag: &str, msg: &str) { let mut map = LOG_MUTEX.lock(); if let Some(logfile) = map.get_mut(&{ context }) { @@ -88,38 +88,3 @@ fn log_inner(logfile: &mut fs::File, level: LogLevel, tag: &str, msg: &str) { msg, ); } - -// Callback that receives messages from WireGuard -pub unsafe extern "system" fn wg_go_logging_callback( - level: WgLogLevel, - msg: *const c_char, - context: *mut c_void, -) { - let mut map = LOG_MUTEX.lock(); - if let Some(logfile) = map.get_mut(&(context as u32)) { - let managed_msg = if !msg.is_null() { - #[cfg(not(target_os = "windows"))] - let m = std::ffi::CStr::from_ptr(msg).to_string_lossy().to_string(); - #[cfg(target_os = "windows")] - let m = std::ffi::CStr::from_ptr(msg) - .to_string_lossy() - .to_string() - .replace('\n', "\r\n"); - m - } else { - "Logging message from WireGuard is NULL".to_string() - }; - - let level = match level { - WG_GO_LOG_VERBOSE => LogLevel::Verbose, - _ => LogLevel::Error, - }; - log_inner(logfile, level, "wireguard-go", &managed_msg); - } -} - -pub type WgLogLevel = u32; -// wireguard-go supports log levels 0 through 3 with 3 being the most verbose -// const WG_GO_LOG_SILENT: WgLogLevel = 0; -// const WG_GO_LOG_ERROR: WgLogLevel = 1; -const WG_GO_LOG_VERBOSE: WgLogLevel = 2; diff --git a/talpid-wireguard/src/stats.rs b/talpid-wireguard/src/stats.rs index bd7b578545..cdbe8318cf 100644 --- a/talpid-wireguard/src/stats.rs +++ b/talpid-wireguard/src/stats.rs @@ -1,21 +1,3 @@ -#[cfg(target_os = "linux")] -use super::wireguard_kernel::wg_message::{DeviceMessage, DeviceNla, PeerNla}; - -#[derive(err_derive::Error, Debug, PartialEq)] -pub enum Error { - #[error(display = "Failed to parse peer pubkey from string \"_0\"")] - PubKeyParse(String, #[error(source)] hex::FromHexError), - - #[error(display = "Failed to parse integer from string \"_0\"")] - IntParse(String, #[error(source)] std::num::ParseIntError), - - #[error(display = "Device no longer exists")] - NoTunnelDevice, - - #[error(display = "Failed to obtain tunnel config")] - NoTunnelConfig, -} - /// Contains bytes sent and received through a tunnel #[derive(Default, Debug, PartialEq, Eq, Clone, Copy)] pub struct Stats { @@ -25,127 +7,3 @@ pub struct Stats { /// A map from peer pubkeys to peer stats. pub type StatsMap = std::collections::HashMap<[u8; 32], Stats>; - -impl Stats { - pub fn parse_config_str(config: &str) -> Result<StatsMap, Error> { - let mut map = StatsMap::new(); - - let mut peer = None; - let mut tx_bytes = None; - let mut rx_bytes = None; - - // parts iterates over keys and values - let parts = config.split('\n').filter_map(|line| { - let mut pair = line.split('='); - let key = pair.next()?; - let value = pair.next()?; - Some((key, value)) - }); - - for (key, value) in parts { - match key { - "public_key" => { - let mut buffer = [0u8; 32]; - hex::decode_to_slice(value, &mut buffer) - .map_err(|err| Error::PubKeyParse(value.to_string(), err))?; - peer = Some(buffer); - tx_bytes = None; - rx_bytes = None; - } - "rx_bytes" => { - rx_bytes = Some( - value - .trim() - .parse() - .map_err(|err| Error::IntParse(value.to_string(), err))?, - ); - } - "tx_bytes" => { - tx_bytes = Some( - value - .trim() - .parse() - .map_err(|err| Error::IntParse(value.to_string(), err))?, - ); - } - - _ => continue, - } - - if let (Some(peer_val), Some(tx_bytes_val), Some(rx_bytes_val)) = - (peer, tx_bytes, rx_bytes) - { - map.insert( - peer_val, - Self { - tx_bytes: tx_bytes_val, - rx_bytes: rx_bytes_val, - }, - ); - peer = None; - tx_bytes = None; - rx_bytes = None; - } - } - Ok(map) - } - - #[cfg(target_os = "linux")] - pub fn parse_device_message(message: &DeviceMessage) -> StatsMap { - let mut map = StatsMap::new(); - - for nla in &message.nlas { - if let DeviceNla::Peers(peers) = nla { - for msg in peers { - let mut tx_bytes = 0; - let mut rx_bytes = 0; - let mut pub_key = None; - - for nla in &msg.0 { - match nla { - PeerNla::TxBytes(bytes) => tx_bytes = *bytes, - PeerNla::RxBytes(bytes) => rx_bytes = *bytes, - PeerNla::PublicKey(key) => pub_key = Some(*key), - _ => continue, - } - } - if let Some(key) = pub_key { - map.insert(key, Stats { tx_bytes, rx_bytes }); - } - } - } - } - - map - } -} - -#[cfg(test)] -mod test { - use super::{Error, Stats}; - - #[test] - fn test_parsing() { - let valid_input = "private_key=0000000000000000000000000000000000000000000000000000000000000000\npublic_key=0000000000000000000000000000000000000000000000000000000000000000\npreshared_key=0000000000000000000000000000000000000000000000000000000000000000\nprotocol_version=1\nendpoint=000.000.000.000:00000\nlast_handshake_time_sec=1578420649\nlast_handshake_time_nsec=369416131\ntx_bytes=2740\nrx_bytes=2396\npersistent_keepalive_interval=0\nallowed_ip=0.0.0.0/0\n"; - let pubkey = [0u8; 32]; - - let stats = Stats::parse_config_str(valid_input).expect("Failed to parse valid input"); - assert_eq!(stats.len(), 1); - let actual_keys: Vec<[u8; 32]> = stats.keys().cloned().collect(); - assert_eq!(actual_keys, [pubkey]); - assert_eq!(stats[&pubkey].rx_bytes, 2396); - assert_eq!(stats[&pubkey].tx_bytes, 2740); - } - - #[test] - fn test_parsing_invalid_input() { - let invalid_input = "private_key=0000000000000000000000000000000000000000000000000000000000000000\npublic_key=0000000000000000000000000000000000000000000000000000000000000000\npreshared_key=0000000000000000000000000000000000000000000000000000000000000000\nprotocol_version=1\nendpoint=000.000.000.000:00000\nlast_handshake_time_sec=1578420649\nlast_handshake_time_nsec=369416131\ntx_bytes=27error40\npersistent_keepalive_interval=0\nallowed_ip=0.0.0.0/0\n"; - let invalid_str = "27error40".to_string(); - let int_err = invalid_str.parse::<u64>().unwrap_err(); - - assert_eq!( - Stats::parse_config_str(invalid_input), - Err(Error::IntParse(invalid_str, int_err)) - ); - } -} diff --git a/talpid-wireguard/src/wireguard_go.rs b/talpid-wireguard/src/wireguard_go.rs index e848e32679..0e3ea3e9ce 100644 --- a/talpid-wireguard/src/wireguard_go.rs +++ b/talpid-wireguard/src/wireguard_go.rs @@ -2,42 +2,31 @@ use super::{ stats::{Stats, StatsMap}, Config, Tunnel, TunnelError, }; -use crate::logging::{clean_up_logging, initialize_logging, wg_go_logging_callback, WgLogLevel}; -#[cfg(windows)] -use futures::SinkExt; +use crate::logging::{clean_up_logging, initialize_logging}; +use ipnetwork::IpNetwork; use std::{ ffi::{c_char, c_void, CStr}, future::Future, path::Path, pin::Pin, }; -#[cfg(windows)] +use talpid_tunnel::tun_provider::TunProvider; use talpid_types::BoxedError; use zeroize::Zeroize; -#[cfg(not(windows))] -use {ipnetwork::IpNetwork, talpid_tunnel::tun_provider::TunProvider}; - -#[cfg(target_os = "windows")] -use std::ffi::CString; #[cfg(target_os = "android")] use talpid_tunnel::tun_provider; -#[cfg(not(target_os = "windows"))] -use { - std::{ - net::IpAddr, - os::unix::io::{AsRawFd, RawFd}, - }, - talpid_tunnel::tun_provider::{Tun, TunConfig}, +use std::{ + net::IpAddr, + os::unix::io::{AsRawFd, RawFd}, }; +use talpid_tunnel::tun_provider::{Tun, TunConfig}; type Result<T> = std::result::Result<T, TunnelError>; -#[cfg(not(target_os = "windows"))] use std::sync::{Arc, Mutex}; -#[cfg(not(target_os = "windows"))] const MAX_PREPARE_TUN_ATTEMPTS: usize = 4; struct LoggingContext(u32); @@ -53,20 +42,14 @@ pub struct WgGoTunnel { handle: Option<i32>, // holding on to the tunnel device and the log file ensures that the associated file handles // live long enough and get closed when the tunnel is stopped - #[cfg(not(target_os = "windows"))] _tunnel_device: Tun, // context that maps to fs::File instance, used with logging callback _logging_context: LoggingContext, - #[cfg(target_os = "windows")] - _route_callback_handle: Option<talpid_routing::CallbackHandle>, - #[cfg(target_os = "windows")] - setup_handle: tokio::task::JoinHandle<()>, #[cfg(target_os = "android")] tun_provider: Arc<Mutex<TunProvider>>, } impl WgGoTunnel { - #[cfg(not(target_os = "windows"))] pub fn start_tunnel( config: &Config, log_path: Option<&Path>, @@ -93,7 +76,7 @@ impl WgGoTunnel { mtu, wg_config_str.as_ptr() as _, tunnel_fd, - Some(wg_go_logging_callback), + Some(logging::wg_go_logging_callback), logging_context.0 as *mut c_void, ) }; @@ -113,139 +96,6 @@ impl WgGoTunnel { }) } - #[cfg(target_os = "windows")] - pub fn start_tunnel( - config: &Config, - log_path: Option<&Path>, - route_manager_handle: talpid_routing::RouteManagerHandle, - mut done_tx: futures::channel::mpsc::Sender<std::result::Result<(), BoxedError>>, - runtime: &tokio::runtime::Handle, - ) -> Result<Self> { - use talpid_types::ErrorExt; - - let route_callback_handle = runtime - .block_on( - route_manager_handle.add_default_route_change_callback(Box::new( - WgGoTunnel::default_route_changed_callback, - )), - ) - .ok(); - if route_callback_handle.is_none() { - log::warn!("Failed to register default route callback"); - } - - let wg_config_str = config.to_userspace_format(); - let iface_name: String = "Mullvad".to_string(); - let cstr_iface_name = - CString::new(iface_name.as_bytes()).map_err(TunnelError::InterfaceNameError)?; - let logging_context = initialize_logging(log_path) - .map(LoggingContext) - .map_err(TunnelError::LoggingError)?; - - let mut alias_ptr = std::ptr::null_mut(); - let mut interface_luid = 0u64; - - let handle = unsafe { - wgTurnOn( - cstr_iface_name.as_ptr(), - config.mtu as i64, - wg_config_str.as_ptr(), - &mut alias_ptr, - &mut interface_luid, - Some(wg_go_logging_callback), - logging_context.0 as *mut c_void, - ) - }; - check_wg_status(handle)?; - - let actual_iface_name = { - let actual_iface_name_c = unsafe { CStr::from_ptr(alias_ptr) }; - let actual_iface_name = actual_iface_name_c - .to_str() - .map_err(|_| TunnelError::InvalidAlias)? - .to_string(); - unsafe { wgFreePtr(alias_ptr as *mut c_void) }; - actual_iface_name - }; - - log::debug!("Adapter alias: {}", actual_iface_name); - - let has_ipv6 = config.tunnel.addresses.iter().any(|addr| addr.is_ipv6()); - let setup_handle = tokio::spawn(async move { - use windows_sys::Win32::NetworkManagement::Ndis::NET_LUID_LH; - let luid = NET_LUID_LH { - Value: interface_luid, - }; - log::debug!("Waiting for tunnel IP interfaces to arrive"); - - let prepare_interfaces = async move { - talpid_windows_net::wait_for_interfaces(luid, true, has_ipv6).await?; - - if let Err(error) = - talpid_tunnel::network_interface::initialize_interfaces(luid, None) - { - log::error!( - "{}", - error.display_chain_with_msg("Failed to set tunnel interface metric"), - ); - } - - Ok(()) - }; - - let _ = done_tx - .send( - prepare_interfaces - .await - .map_err(|error| BoxedError::new(TunnelError::SetupIpInterfaces(error))), - ) - .await; - log::debug!("Waiting for tunnel IP interfaces: Done"); - }); - - Ok(WgGoTunnel { - interface_name: actual_iface_name, - handle: Some(handle), - setup_handle, - _logging_context: logging_context, - _route_callback_handle: route_callback_handle, - }) - } - - // Callback to be used to rebind the tunnel sockets when the default route changes - #[cfg(target_os = "windows")] - pub fn default_route_changed_callback( - event_type: crate::routing::EventType<'_>, - address_family: talpid_windows_net::AddressFamily, - ) { - use crate::routing::EventType::*; - use windows_sys::Win32::NetworkManagement::IpHelper::ConvertInterfaceLuidToIndex; - - let iface_idx: u32 = match event_type { - Updated(default_route) => { - let mut iface_idx = 0u32; - let iface_luid = default_route.iface; - let status = unsafe { ConvertInterfaceLuidToIndex(&iface_luid, &mut iface_idx) }; - if status != 0 { - log::error!( - "Failed to convert interface LUID to interface index: {}: {}", - status, - std::io::Error::last_os_error() - ); - return; - } - iface_idx - } - // if there is no new default route, specify 0 as the interface index - Removed => 0, - // ignore interface updates that don't affect the interface to use - UpdatedDetails(_) => return, - }; - - unsafe { wgRebindTunnelSocket(address_family.to_af_family(), iface_idx) }; - } - - #[cfg(not(target_os = "windows"))] fn create_tunnel_config(config: &Config, routes: impl Iterator<Item = IpNetwork>) -> TunConfig { let mut dns_servers = vec![IpAddr::V4(config.ipv4_gateway)]; dns_servers.extend(config.ipv6_gateway.map(IpAddr::V6)); @@ -287,8 +137,6 @@ impl WgGoTunnel { } fn stop_tunnel(&mut self) -> Result<()> { - #[cfg(windows)] - self.setup_handle.abort(); if let Some(handle) = self.handle.take() { let status = unsafe { wgTurnOff(handle) }; if status < 0 { @@ -298,7 +146,6 @@ impl WgGoTunnel { Ok(()) } - #[cfg(not(target_os = "windows"))] fn get_tunnel( tun_provider: Arc<Mutex<TunProvider>>, config: &Config, @@ -355,7 +202,7 @@ impl Tunnel for WgGoTunnel { let result = Stats::parse_config_str(config_str.to_str().expect("Go strings are always UTF-8")) - .map_err(TunnelError::StatsError); + .map_err(|error| TunnelError::StatsError(BoxedError::new(error))); unsafe { // Zeroing out config string to not leave private key in memory. let slice = std::slice::from_raw_parts_mut( @@ -420,12 +267,8 @@ fn check_wg_status(wg_code: i32) -> Result<()> { } } -#[cfg(unix)] pub type Fd = std::os::unix::io::RawFd; -pub type LoggingCallback = - unsafe extern "system" fn(level: WgLogLevel, msg: *const c_char, context: *mut c_void); - const ERROR_GENERAL_FAILURE: i32 = -1; const ERROR_INTERMITTENT_FAILURE: i32 = -2; @@ -435,12 +278,12 @@ extern "C" { /// /// Positive return values are tunnel handles for this specific wireguard tunnel instance. /// Negative return values signify errors. All error codes are opaque. - #[cfg(not(any(target_os = "android", target_os = "windows")))] + #[cfg(not(target_os = "android"))] fn wgTurnOn( mtu: isize, settings: *const i8, fd: Fd, - logging_callback: Option<LoggingCallback>, + logging_callback: Option<logging::LoggingCallback>, logging_context: *mut c_void, ) -> i32; @@ -449,19 +292,7 @@ extern "C" { fn wgTurnOn( settings: *const i8, fd: Fd, - logging_callback: Option<LoggingCallback>, - logging_context: *mut c_void, - ) -> i32; - - // Windows - #[cfg(target_os = "windows")] - fn wgTurnOn( - iface_name: *const i8, - mtu: i64, - settings: *const i8, - iface_name_out: *mut *mut c_char, - iface_luid_out: *mut u64, - logging_callback: Option<LoggingCallback>, + logging_callback: Option<logging::LoggingCallback>, logging_context: *mut c_void, ) -> i32; @@ -484,8 +315,147 @@ extern "C" { // Returns the file descriptor of the tunnel IPv6 socket. #[cfg(target_os = "android")] fn wgGetSocketV6(handle: i32) -> Fd; +} + +mod stats { + use super::{Stats, StatsMap}; + + #[derive(err_derive::Error, Debug, PartialEq)] + pub enum Error { + #[error(display = "Failed to parse peer pubkey from string \"{}\"", _0)] + PubKeyParse(String, #[error(source)] hex::FromHexError), + + #[error(display = "Failed to parse integer from string \"{}\"", _0)] + IntParse(String, #[error(source)] std::num::ParseIntError), + } + + impl Stats { + pub fn parse_config_str(config: &str) -> std::result::Result<StatsMap, Error> { + let mut map = StatsMap::new(); + + let mut peer = None; + let mut tx_bytes = None; + let mut rx_bytes = None; + + // parts iterates over keys and values + let parts = config.split('\n').filter_map(|line| { + let mut pair = line.split('='); + let key = pair.next()?; + let value = pair.next()?; + Some((key, value)) + }); + + for (key, value) in parts { + match key { + "public_key" => { + let mut buffer = [0u8; 32]; + hex::decode_to_slice(value, &mut buffer) + .map_err(|err| Error::PubKeyParse(value.to_string(), err))?; + peer = Some(buffer); + tx_bytes = None; + rx_bytes = None; + } + "rx_bytes" => { + rx_bytes = Some( + value + .trim() + .parse() + .map_err(|err| Error::IntParse(value.to_string(), err))?, + ); + } + "tx_bytes" => { + tx_bytes = Some( + value + .trim() + .parse() + .map_err(|err| Error::IntParse(value.to_string(), err))?, + ); + } + + _ => continue, + } + + if let (Some(peer_val), Some(tx_bytes_val), Some(rx_bytes_val)) = + (peer, tx_bytes, rx_bytes) + { + map.insert( + peer_val, + Self { + tx_bytes: tx_bytes_val, + rx_bytes: rx_bytes_val, + }, + ); + peer = None; + tx_bytes = None; + rx_bytes = None; + } + } + Ok(map) + } + } + + #[cfg(test)] + mod test { + use super::super::stats::{Error, Stats}; + + #[test] + fn test_parsing() { + let valid_input = "private_key=0000000000000000000000000000000000000000000000000000000000000000\npublic_key=0000000000000000000000000000000000000000000000000000000000000000\npreshared_key=0000000000000000000000000000000000000000000000000000000000000000\nprotocol_version=1\nendpoint=000.000.000.000:00000\nlast_handshake_time_sec=1578420649\nlast_handshake_time_nsec=369416131\ntx_bytes=2740\nrx_bytes=2396\npersistent_keepalive_interval=0\nallowed_ip=0.0.0.0/0\n"; + let pubkey = [0u8; 32]; + + let stats = Stats::parse_config_str(valid_input).expect("Failed to parse valid input"); + assert_eq!(stats.len(), 1); + let actual_keys: Vec<[u8; 32]> = stats.keys().cloned().collect(); + assert_eq!(actual_keys, [pubkey]); + assert_eq!(stats[&pubkey].rx_bytes, 2396); + assert_eq!(stats[&pubkey].tx_bytes, 2740); + } + + #[test] + fn test_parsing_invalid_input() { + let invalid_input = "private_key=0000000000000000000000000000000000000000000000000000000000000000\npublic_key=0000000000000000000000000000000000000000000000000000000000000000\npreshared_key=0000000000000000000000000000000000000000000000000000000000000000\nprotocol_version=1\nendpoint=000.000.000.000:00000\nlast_handshake_time_sec=1578420649\nlast_handshake_time_nsec=369416131\ntx_bytes=27error40\npersistent_keepalive_interval=0\nallowed_ip=0.0.0.0/0\n"; + let invalid_str = "27error40".to_string(); + let int_err = invalid_str.parse::<u64>().unwrap_err(); + + assert_eq!( + Stats::parse_config_str(invalid_input), + Err(Error::IntParse(invalid_str, int_err)) + ); + } + } +} + +mod logging { + use super::super::logging::{log, LogLevel}; + use std::ffi::{c_char, c_void}; + + // Callback that receives messages from WireGuard + pub unsafe extern "system" fn wg_go_logging_callback( + level: WgLogLevel, + msg: *const c_char, + context: *mut c_void, + ) { + let managed_msg = if !msg.is_null() { + std::ffi::CStr::from_ptr(msg).to_string_lossy().to_string() + } else { + "Logging message from WireGuard is NULL".to_string() + }; + + let level = match level { + WG_GO_LOG_VERBOSE => LogLevel::Verbose, + _ => LogLevel::Error, + }; + + log(context as u32, level, "wireguard-go", &managed_msg); + } + + // wireguard-go supports log levels 0 through 3 with 3 being the most verbose + // const WG_GO_LOG_SILENT: WgLogLevel = 0; + // const WG_GO_LOG_ERROR: WgLogLevel = 1; + const WG_GO_LOG_VERBOSE: WgLogLevel = 2; + + pub type WgLogLevel = u32; - // Rebind tunnel socket when network interfaces change - #[cfg(target_os = "windows")] - fn wgRebindTunnelSocket(family: u16, interfaceIndex: u32); + pub type LoggingCallback = + unsafe extern "system" fn(level: WgLogLevel, msg: *const c_char, context: *mut c_void); } diff --git a/talpid-wireguard/src/wireguard_kernel/mod.rs b/talpid-wireguard/src/wireguard_kernel/mod.rs index 7a64ee3f65..15eaad4c24 100644 --- a/talpid-wireguard/src/wireguard_kernel/mod.rs +++ b/talpid-wireguard/src/wireguard_kernel/mod.rs @@ -18,6 +18,7 @@ use std::{ffi::CString, net::IpAddr}; use tokio_stream::StreamExt; mod parsers; +mod stats; pub mod wg_message; use wg_message::{DeviceMessage, DeviceNla}; diff --git a/talpid-wireguard/src/wireguard_kernel/stats.rs b/talpid-wireguard/src/wireguard_kernel/stats.rs new file mode 100644 index 0000000000..8604e8243f --- /dev/null +++ b/talpid-wireguard/src/wireguard_kernel/stats.rs @@ -0,0 +1,32 @@ +use super::wg_message::{DeviceMessage, DeviceNla, PeerNla}; +use crate::stats::{Stats, StatsMap}; + +impl Stats { + pub fn parse_device_message(message: &DeviceMessage) -> StatsMap { + let mut map = StatsMap::new(); + + for nla in &message.nlas { + if let DeviceNla::Peers(peers) = nla { + for msg in peers { + let mut tx_bytes = 0; + let mut rx_bytes = 0; + let mut pub_key = None; + + for nla in &msg.0 { + match nla { + PeerNla::TxBytes(bytes) => tx_bytes = *bytes, + PeerNla::RxBytes(bytes) => rx_bytes = *bytes, + PeerNla::PublicKey(key) => pub_key = Some(*key), + _ => continue, + } + } + if let Some(key) = pub_key { + map.insert(key, Stats { tx_bytes, rx_bytes }); + } + } + } + } + + map + } +} diff --git a/talpid-wireguard/src/wireguard_nt.rs b/talpid-wireguard/src/wireguard_nt.rs index 00cbeed0a9..1b4405eba2 100644 --- a/talpid-wireguard/src/wireguard_nt.rs +++ b/talpid-wireguard/src/wireguard_nt.rs @@ -946,9 +946,9 @@ impl Tunnel for WgNtTunnel { let (_interface, peers) = device.get_config().map_err(|error| { log::error!( "{}", - error.display_chain_with_msg("Failed to obtain wg-nt tunnel config") + error.display_chain_with_msg("Failed to obtain tunnel config") ); - super::TunnelError::StatsError(super::stats::Error::NoTunnelConfig) + super::TunnelError::GetConfigError })?; for (peer, _allowed_ips) in &peers { map.insert( @@ -961,9 +961,8 @@ impl Tunnel for WgNtTunnel { } Ok(map) } else { - Err(super::TunnelError::StatsError( - super::stats::Error::NoTunnelDevice, - )) + log::error!("Failed to obtain tunnel stats as device no longer exists"); + Err(super::TunnelError::GetConfigError) } } @@ -1027,7 +1026,6 @@ mod tests { ipv4_gateway: "0.0.0.0".parse().unwrap(), ipv6_gateway: None, mtu: 0, - use_wireguard_nt: true, obfuscator_config: None, }); diff --git a/wireguard/build-wireguard-go.sh b/wireguard/build-wireguard-go.sh index f800634f73..ebf0d2e33f 100755 --- a/wireguard/build-wireguard-go.sh +++ b/wireguard/build-wireguard-go.sh @@ -26,47 +26,6 @@ function is_docker_build { return 0 } - -function win_deduce_lib_executable_path { - msbuild_path="$(which msbuild.exe)" - msbuild_dir=$(dirname "$msbuild_path") - find "$msbuild_dir/../../../../" -name "lib.exe" | \ - grep -i "hostx64/x64" | \ - head -n1 -} - -function win_gather_export_symbols { - grep -Eo "\/\/export \w+" libwg.go libwg_windows.go | cut -d' ' -f2 -} - -function win_create_lib_file { - echo "LIBRARY libwg" > exports.def - echo "EXPORTS" >> exports.def - - for symbol in $(win_gather_export_symbols); do - printf "\t%s\n" "$symbol" >> exports.def - done - - lib_path="$(win_deduce_lib_executable_path)" - "$lib_path" \ - "/def:exports.def" \ - "/out:libwg.lib" \ - "/machine:X64" - -} - -function build_windows { - echo "Building wireguard-go for Windows" - pushd libwg - go build -v -o libwg.dll -buildmode c-shared - win_create_lib_file - - target_dir=../../build/lib/x86_64-pc-windows-msvc/ - mkdir -p $target_dir - mv libwg.dll libwg.lib $target_dir - popd -} - function unix_target_triple { local platform="$(uname -s)" if [[ ("${platform}" == "Linux") ]]; then @@ -144,7 +103,10 @@ function build_wireguard_go { local platform="$(uname -s)"; case "$platform" in Linux*|Darwin*) build_unix ${1:-$(unix_target_triple)};; - MINGW*|MSYS_NT*) build_windows;; + *) + echo "Unsupported platform" + return 1 + ;; esac } diff --git a/wireguard/libwg/README.md b/wireguard/libwg/README.md index e5b96928f7..39ad48e3e0 100644 --- a/wireguard/libwg/README.md +++ b/wireguard/libwg/README.md @@ -7,7 +7,6 @@ It currently offers support for the following platforms: - Linux - macOS - Android -- Windows # Organization @@ -17,8 +16,6 @@ It currently offers support for the following platforms: `libwg_android.go` has code specifically for Android. -`libwg_windows.go` has code specifically for Windows. - # Usage Call `wgTurnOn` to create and activate a tunnel. The prototype is different on different platforms, see the code for details. diff --git a/wireguard/libwg/go.mod b/wireguard/libwg/go.mod index 27f48a3d06..fb74c9beb8 100644 --- a/wireguard/libwg/go.mod +++ b/wireguard/libwg/go.mod @@ -5,11 +5,9 @@ go 1.18 require ( golang.org/x/sys v0.0.0-20220808155132-1c4a2a72c664 golang.zx2c4.com/wireguard v0.0.0-20220703234212-c31a7b1ab478 - golang.zx2c4.com/wireguard/windows v0.5.3 ) require ( golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect golang.org/x/net v0.0.0-20220809184613-07c6da5e1ced // indirect - golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 // indirect ) diff --git a/wireguard/libwg/go.sum b/wireguard/libwg/go.sum index d1f125b01c..3907746df4 100644 --- a/wireguard/libwg/go.sum +++ b/wireguard/libwg/go.sum @@ -4,9 +4,5 @@ golang.org/x/net v0.0.0-20220809184613-07c6da5e1ced h1:3dYNDff0VT5xj+mbj2XucFst9 golang.org/x/net v0.0.0-20220809184613-07c6da5e1ced/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/sys v0.0.0-20220808155132-1c4a2a72c664 h1:v1W7bwXHsnLLloWYTVEdvGvA7BHMeBYsPcF0GLDxIRs= golang.org/x/sys v0.0.0-20220808155132-1c4a2a72c664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 h1:Ug9qvr1myri/zFN6xL17LSCBGFDnphBBhzmILHsM5TY= -golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI= golang.zx2c4.com/wireguard v0.0.0-20220703234212-c31a7b1ab478 h1:vDy//hdR+GnROE3OdYbQKt9rdtNdHkDtONvpRwmls/0= golang.zx2c4.com/wireguard v0.0.0-20220703234212-c31a7b1ab478/go.mod h1:bVQfyl2sCM/QIIGHpWbFGfHPuDvqnCNkT6MQLTCjO/U= -golang.zx2c4.com/wireguard/windows v0.5.3 h1:On6j2Rpn3OEMXqBq00QEDC7bWSZrPIHKIus8eIuExIE= -golang.zx2c4.com/wireguard/windows v0.5.3/go.mod h1:9TEe8TJmtwyQebdFwAkEWOPr3prrtqm+REGFifP60hI= diff --git a/wireguard/libwg/interfacewatcher/interfacewatcher_windows.go b/wireguard/libwg/interfacewatcher/interfacewatcher_windows.go deleted file mode 100644 index fcb53b8584..0000000000 --- a/wireguard/libwg/interfacewatcher/interfacewatcher_windows.go +++ /dev/null @@ -1,123 +0,0 @@ -/* SPDX-License-Identifier: MIT - * - * Copyright (C) 2019 WireGuard LLC. All Rights Reserved. - * Copyright (C) 2021 Mullvad VPN AB. All Rights Reserved. - */ - -package interfacewatcher - -import ( - "sync" - "time" - - "golang.zx2c4.com/wireguard/windows/tunnel/winipcfg" -) - -type Event struct { - Luid winipcfg.LUID - Family winipcfg.AddressFamily -} - -type interfaceWatcher struct { - ready chan bool - processingMutex sync.Mutex - interfaceChangeCallback *winipcfg.InterfaceChangeCallback - seenEvents []Event - wantedEvents []Event - expired bool -} - -func NewWatcher() (*interfaceWatcher, error) { - iw := &interfaceWatcher{ - ready: make(chan bool, 1), - expired: false, - } - var err error - iw.interfaceChangeCallback, err = winipcfg.RegisterInterfaceChangeCallback(func(notificationType winipcfg.MibNotificationType, iface *winipcfg.MibIPInterfaceRow) { - if notificationType != winipcfg.MibAddInstance { - return - } - - iw.processingMutex.Lock() - defer iw.processingMutex.Unlock() - - if iw.expired { - return - } - - iw.seenEvents = append(iw.seenEvents, Event{iface.InterfaceLUID, iface.Family}) - - if len(iw.wantedEvents) != 0 { - iw.evaluateEvents() - } - }) - if err != nil { - return nil, err - } - return iw, nil -} - -func (iw *interfaceWatcher) evaluateEvents() { - matched := 0 - - // This is n*n, but typically very few items in both slices :-) - for _, wanted := range iw.wantedEvents { - for _, seen := range iw.seenEvents { - if seen == wanted { - matched += 1 - break - } - } - } - - if len(iw.wantedEvents) != matched { - return - } - - iw.expired = true - iw.ready <- true -} - -// You can only join() once after which the watcher becomes expired. -func (iw *interfaceWatcher) Join(wantedEvents []Event, timeoutSeconds int) bool { - { - iw.processingMutex.Lock() - - if iw.expired || len(wantedEvents) == 0 { - iw.processingMutex.Unlock() - return false - } - - iw.wantedEvents = wantedEvents - iw.evaluateEvents() - - iw.processingMutex.Unlock() - } - - result := false - - select { - case <- iw.ready: - result = true - case <- time.After(time.Duration(timeoutSeconds) * time.Second): - result = false - } - - { - iw.processingMutex.Lock() - - iw.wantedEvents = nil - iw.expired = true - - iw.processingMutex.Unlock() - } - - return result -} - -func (iw *interfaceWatcher) Destroy() { - if iw.interfaceChangeCallback != nil { - iw.interfaceChangeCallback.Unregister() - iw.interfaceChangeCallback = nil - } -} diff --git a/wireguard/libwg/libwg_windows.go b/wireguard/libwg/libwg_windows.go deleted file mode 100644 index a1dc4fd265..0000000000 --- a/wireguard/libwg/libwg_windows.go +++ /dev/null @@ -1,132 +0,0 @@ -/* SPDX-License-Identifier: Apache-2.0 - * - * Copyright (C) 2017-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. - * Copyright (C) 2021 Mullvad VPN AB. All Rights Reserved. - */ - -package main - -// #include <stdlib.h> -import "C" - -import ( - "bufio" - "strings" - "unsafe" - - "golang.org/x/sys/windows" - - "golang.zx2c4.com/wireguard/conn" - "golang.zx2c4.com/wireguard/device" - "golang.zx2c4.com/wireguard/tun" - - "github.com/mullvad/mullvadvpn-app/wireguard/libwg/logging" - "github.com/mullvad/mullvadvpn-app/wireguard/libwg/tunnelcontainer" -) - -// Redefined here because otherwise the compiler doesn't realize it's a type alias for a type that's safe to export. -// Taken from the contained logging package. -type LogSink = unsafe.Pointer -type LogContext = unsafe.Pointer - -//export wgTurnOn -func wgTurnOn(cIfaceName *C.char, mtu int, cSettings *C.char, cIfaceNameOut **C.char, cLuidOut *uint64, logSink LogSink, logContext LogContext) int32 { - logger := logging.NewLogger(logSink, logContext) - if cIfaceNameOut != nil { - *cIfaceNameOut = nil - } - - if cIfaceName == nil { - logger.Errorf("cIfaceName is null\n") - return ERROR_GENERAL_FAILURE - } - - if cSettings == nil { - logger.Errorf("cSettings is null\n") - return ERROR_GENERAL_FAILURE - } - - settings := C.GoString(cSettings) - ifaceName := C.GoString(cIfaceName) - - // {AFE43773-E1F8-4EBB-8536-576AB86AFE9A} - networkId := windows.GUID{0xafe43773, 0xe1f8, 0x4ebb, [8]byte{0x85, 0x36, 0x57, 0x6a, 0xb8, 0x6a, 0xfe, 0x9a}} - - tun.WintunTunnelType = "Mullvad" - - wintun, err := tun.CreateTUNWithRequestedGUID(ifaceName, &networkId, mtu) - if err != nil { - logger.Errorf("Failed to create tunnel\n") - logger.Errorf("%s\n", err) - return ERROR_INTERMITTENT_FAILURE - } - - nativeTun := wintun.(*tun.NativeTun) - - actualInterfaceName, err := nativeTun.Name() - if err != nil { - nativeTun.Close() - logger.Errorf("Failed to determine name of wintun adapter\n") - return ERROR_GENERAL_FAILURE - } - if actualInterfaceName != ifaceName { - // WireGuard picked a different name for the adapter than the one we expected. - // This indicates there is already an adapter with the name we intended to use. - logger.Verbosef("Failed to create adapter with specific name\n") - } - - device := device.NewDevice(wintun, conn.NewDefaultBind(), logger) - - setError := device.IpcSetOperation(bufio.NewReader(strings.NewReader(settings))) - if setError != nil { - logger.Errorf("Failed to set device configuration\n") - logger.Errorf("%s\n", setError) - device.Close() - return ERROR_GENERAL_FAILURE - } - - device.Up() - - context := tunnelcontainer.Context{ - Device: device, - Logger: logger, - } - - handle, err := tunnels.Insert(context) - if err != nil { - logger.Errorf("%s\n", err) - device.Close() - return ERROR_GENERAL_FAILURE - } - - if cIfaceNameOut != nil { - *cIfaceNameOut = C.CString(actualInterfaceName) - } - if cLuidOut != nil { - *cLuidOut = nativeTun.LUID() - } - - return handle -} - -//export wgRebindTunnelSocket -func wgRebindTunnelSocket(family uint16, interfaceIndex uint32) { - tunnels.ForEach(func(tunnel tunnelcontainer.Context) { - blackhole := (interfaceIndex == 0) - bind := tunnel.Device.Bind().(conn.BindSocketToInterface) - - if family == windows.AF_INET { - tunnel.Logger.Verbosef("Binding v4 socket to interface %d (blackhole=%v)\n", interfaceIndex, blackhole) - err := bind.BindSocketToInterface4(interfaceIndex, blackhole) - if err != nil { - tunnel.Logger.Verbosef("%s\n", err) - } - } else if family == windows.AF_INET6 { - tunnel.Logger.Verbosef("Binding v6 socket to interface %d (blackhole=%v)\n", interfaceIndex, blackhole) - err := bind.BindSocketToInterface6(interfaceIndex, blackhole) - if err != nil { - tunnel.Logger.Verbosef("%s\n", err) - } - } - }) -} |
