diff options
| author | Janito Vaqueiro Ferreira Filho <janito@mullvad.net> | 2019-06-11 01:00:35 -0300 |
|---|---|---|
| committer | Janito Vaqueiro Ferreira Filho <janito@mullvad.net> | 2019-06-11 01:00:35 -0300 |
| commit | 14d227892a2e5de8045ec185188a69ad7ada8813 (patch) | |
| tree | 9ffd9efb92a1ddd5528514b614e01674378fb21c | |
| parent | a265fc596b7b2fca79592b494d6e3a55034bfbe2 (diff) | |
| parent | 76de34848a130d44831d5e57ddb56f13fb570bea (diff) | |
| download | mullvadvpn-14d227892a2e5de8045ec185188a69ad7ada8813.tar.xz mullvadvpn-14d227892a2e5de8045ec185188a69ad7ada8813.zip | |
Merge branch 'wireguard-on-android'
| -rw-r--r-- | android/build.gradle | 7 | ||||
| -rw-r--r-- | android/src/main/kotlin/net/mullvad/mullvadvpn/MullvadVpnService.kt | 2 | ||||
| m--------- | dist-assets/binaries | 0 | ||||
| -rw-r--r-- | mullvad-jni/src/into_java.rs | 18 | ||||
| -rw-r--r-- | talpid-core/build.rs | 19 | ||||
| -rw-r--r-- | talpid-core/src/tunnel/mod.rs | 41 | ||||
| -rw-r--r-- | talpid-core/src/tunnel/wireguard/mod.rs | 5 | ||||
| -rw-r--r-- | talpid-core/src/tunnel/wireguard/ping_monitor.rs | 39 | ||||
| -rw-r--r-- | talpid-core/src/tunnel/wireguard/wireguard_go.rs | 38 |
9 files changed, 114 insertions, 55 deletions
diff --git a/android/build.gradle b/android/build.gradle index d511691624..914ee21e88 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -46,6 +46,7 @@ android { variant.ndkCompileProvider.configure { dependsOn copyMullvadJni + dependsOn copyWireguardGo } } } @@ -99,6 +100,12 @@ task copyMullvadJni(type: Copy) { into "$extraJniDirectory/arm64-v8a" } +task copyWireguardGo(type: Copy) { + from "$repoRootPath/dist-assets/binaries/android" + include 'libwg.so' + into "$extraJniDirectory/arm64-v8a" +} + task copyApiRootCertificate(type: Copy) { from "$repoRootPath/dist-assets" include "api_root_ca.pem" diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/MullvadVpnService.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/MullvadVpnService.kt index dcd4935ee4..ec71738ef2 100644 --- a/android/src/main/kotlin/net/mullvad/mullvadvpn/MullvadVpnService.kt +++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/MullvadVpnService.kt @@ -66,7 +66,7 @@ class MullvadVpnService(val context: Context) { } for (route in config.routes) { - addRoute(route.address, route.prefixLength as Int) + addRoute(route.address, route.prefixLength.toInt()) } setMtu(config.mtu) diff --git a/dist-assets/binaries b/dist-assets/binaries -Subproject 5569328323fc1c1a7352861602029da149b1745 +Subproject c79a133c850e05f588000e5e45f6909607b4176 diff --git a/mullvad-jni/src/into_java.rs b/mullvad-jni/src/into_java.rs index 1ab7cd54e6..06116d8c3b 100644 --- a/mullvad-jni/src/into_java.rs +++ b/mullvad-jni/src/into_java.rs @@ -196,10 +196,22 @@ impl<'env> IntoJava<'env> for TunConfig { fn into_java(self, env: &JNIEnv<'env>) -> Self::JavaType { let class = get_class("net/mullvad/mullvadvpn/model/TunConfig"); let addresses = env.auto_local(self.addresses.into_java(env)); - let parameters = [JValue::Object(addresses.as_obj())]; + let dns_servers = env.auto_local(self.dns_servers.into_java(env)); + let routes = env.auto_local(self.routes.into_java(env)); + let mtu = self.mtu as jint; + let parameters = [ + JValue::Object(addresses.as_obj()), + JValue::Object(dns_servers.as_obj()), + JValue::Object(routes.as_obj()), + JValue::Int(mtu), + ]; - env.new_object(&class, "(Ljava/util/List;)V", ¶meters) - .expect("Failed to create TunConfig Java object") + env.new_object( + &class, + "(Ljava/util/List;Ljava/util/List;Ljava/util/List;I)V", + ¶meters, + ) + .expect("Failed to create TunConfig Java object") } } diff --git a/talpid-core/build.rs b/talpid-core/build.rs index 4741a440d0..b494703653 100644 --- a/talpid-core/build.rs +++ b/talpid-core/build.rs @@ -57,13 +57,20 @@ fn main() { #[cfg(not(windows))] fn main() { - let lib_dir = if cfg!(target_os = "macos") { - manifest_dir().join("../dist-assets/binaries/macos") - } else { - manifest_dir().join("../dist-assets/binaries/linux") + let target_os = env::var("CARGO_CFG_TARGET_OS").expect("CARGO_CFG_TARGET_OS not set"); + + let link_type = match target_os.as_str() { + "android" => "", + "linux" | "macos" => "=static", + _ => panic!("Unsupported platform: {}", target_os), }; - println!("cargo:rustc-link-search={}", &lib_dir.display()); - println!("cargo:rustc-link-lib=static=wg"); + + let lib_dir = manifest_dir() + .join("../dist-assets/binaries") + .join(target_os); + + println!("cargo:rustc-link-search={}", lib_dir.display()); + println!("cargo:rustc-link-lib{}=wg", link_type); } fn manifest_dir() -> PathBuf { diff --git a/talpid-core/src/tunnel/mod.rs b/talpid-core/src/tunnel/mod.rs index 62bc165ed6..a8c601b724 100644 --- a/talpid-core/src/tunnel/mod.rs +++ b/talpid-core/src/tunnel/mod.rs @@ -9,7 +9,7 @@ use std::{ }; #[cfg(not(target_os = "android"))] use talpid_types::net::openvpn as openvpn_types; -#[cfg(any(target_os = "linux", target_os = "macos"))] +#[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))] use talpid_types::net::wireguard as wireguard_types; use talpid_types::net::{GenericTunnelOptions, TunnelParameters}; @@ -17,7 +17,7 @@ use talpid_types::net::{GenericTunnelOptions, TunnelParameters}; #[cfg(not(target_os = "android"))] pub mod openvpn; -#[cfg(any(target_os = "linux", target_os = "macos"))] +#[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))] pub mod wireguard; /// A module for low level platform specific tunnel device management. @@ -45,7 +45,7 @@ pub enum Error { RotateLogError(#[error(cause)] crate::logging::RotateLogError), /// Failure to build Wireguard configuration. - #[cfg(any(target_os = "linux", target_os = "macos"))] + #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))] #[error(display = "Failed to configure Wireguard with the given parameters")] WireguardConfigError(#[error(cause)] self::wireguard::config::Error), @@ -55,7 +55,7 @@ pub enum Error { OpenVpnTunnelMonitoringError(#[error(cause)] openvpn::Error), /// There was an error listening for events from the Wireguard tunnel - #[cfg(any(target_os = "linux", target_os = "macos"))] + #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))] #[error(display = "Failed while listening for events from the Wireguard tunnel")] WirguardTunnelMonitoringError(#[error(cause)] wireguard::Error), } @@ -158,18 +158,19 @@ impl TunnelMonitor { TunnelParameters::OpenVpn(config) => { Self::start_openvpn_tunnel(&config, log_file, resource_dir, on_event) } - #[cfg(any(target_os = "linux", target_os = "macos"))] + #[cfg(target_os = "android")] + TunnelParameters::OpenVpn(_) => Err(Error::UnsupportedPlatform), + + #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))] TunnelParameters::Wireguard(config) => { Self::start_wireguard_tunnel(&config, log_file, on_event, tun_provider) } - #[cfg(target_os = "android")] - TunnelParameters::OpenVpn(_) => Err(Error::UnsupportedPlatform), - #[cfg(any(windows, target_os = "android"))] + #[cfg(windows)] TunnelParameters::Wireguard(_) => Err(Error::UnsupportedPlatform), } } - #[cfg(any(target_os = "linux", target_os = "macos"))] + #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))] fn start_wireguard_tunnel<L>( params: &wireguard_types::TunnelParameters, log: Option<PathBuf>, @@ -252,7 +253,7 @@ pub enum CloseHandle { #[cfg(not(target_os = "android"))] /// OpenVpn close handle OpenVpn(openvpn::OpenVpnCloseHandle), - #[cfg(any(target_os = "linux", target_os = "macos"))] + #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))] /// Wireguard close handle Wireguard(wireguard::CloseHandle), } @@ -260,13 +261,10 @@ pub enum CloseHandle { impl CloseHandle { /// Closes the underlying tunnel, making the `TunnelMonitor::wait` method return. pub fn close(self) -> io::Result<()> { - #[cfg(target_os = "android")] - unimplemented!(); - - #[cfg(not(target_os = "android"))] match self { + #[cfg(not(target_os = "android"))] CloseHandle::OpenVpn(handle) => handle.close(), - #[cfg(any(target_os = "linux", target_os = "macos"))] + #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))] CloseHandle::Wireguard(mut handle) => { handle.close(); Ok(()) @@ -278,28 +276,25 @@ impl CloseHandle { enum InternalTunnelMonitor { #[cfg(not(target_os = "android"))] OpenVpn(openvpn::OpenVpnMonitor), - #[cfg(any(target_os = "linux", target_os = "macos"))] + #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))] Wireguard(wireguard::WireguardMonitor), } impl InternalTunnelMonitor { fn close_handle(&self) -> CloseHandle { - #[cfg(not(target_os = "android"))] match self { + #[cfg(not(target_os = "android"))] InternalTunnelMonitor::OpenVpn(tun) => CloseHandle::OpenVpn(tun.close_handle()), - #[cfg(any(target_os = "linux", target_os = "macos"))] + #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))] InternalTunnelMonitor::Wireguard(tun) => CloseHandle::Wireguard(tun.close_handle()), } - - #[cfg(target_os = "android")] - unimplemented!(); } fn wait(self) -> Result<()> { - #[cfg(not(target_os = "android"))] match self { + #[cfg(not(target_os = "android"))] InternalTunnelMonitor::OpenVpn(tun) => tun.wait()?, - #[cfg(any(target_os = "linux", target_os = "macos"))] + #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))] InternalTunnelMonitor::Wireguard(tun) => tun.wait()?, } diff --git a/talpid-core/src/tunnel/wireguard/mod.rs b/talpid-core/src/tunnel/wireguard/mod.rs index 36d0f9d61b..810aadff49 100644 --- a/talpid-core/src/tunnel/wireguard/mod.rs +++ b/talpid-core/src/tunnel/wireguard/mod.rs @@ -44,6 +44,11 @@ pub enum Error { #[error(display = "Invalid tunnel interface name")] InterfaceNameError(#[error(cause)] std::ffi::NulError), + /// Failed to configure Wireguard sockets to bypass the tunnel. + #[cfg(target_os = "android")] + #[error(display = "Failed to configure Wireguard sockets to bypass the tunnel")] + BypassError(#[error(cause)] BoxedError), + /// Pinging timed out. #[error(display = "Ping timed out")] PingTimeoutError, diff --git a/talpid-core/src/tunnel/wireguard/ping_monitor.rs b/talpid-core/src/tunnel/wireguard/ping_monitor.rs index 69f22fc83f..89b13ee637 100644 --- a/talpid-core/src/tunnel/wireguard/ping_monitor.rs +++ b/talpid-core/src/tunnel/wireguard/ping_monitor.rs @@ -48,30 +48,29 @@ fn ping_cmd( interface: &str, exit_on_first_reply: bool, ) -> duct::Expression { - let interface_flag = if cfg!(target_os = "linux") { - "-I" - } else { - "-b" - }; - let timeout_flag = if cfg!(target_os = "linux") { + let mut args = vec!["-n", "-i", "1"]; + + let timeout_flag = if cfg!(target_os = "linux") || cfg!(target_os = "android") { "-w" } else { "-t" }; - let timeout_secs = timeout_secs.to_string(); - let ip = ip.to_string(); - let mut args = vec![ - "-n", - "-i", - "1", - &interface_flag, - &interface, - timeout_flag, - &timeout_secs, - &ip, - ]; + args.extend_from_slice(&[timeout_flag, &timeout_secs]); + + let interface_flag = if cfg!(target_os = "linux") { + Some("-I") + } else if cfg!(target_os = "macos") { + Some("-b") + } else { + None + }; + + if let Some(interface_flag) = interface_flag { + args.extend_from_slice(&[interface_flag, interface]); + } + if exit_on_first_reply { if cfg!(target_os = "macos") { args.push("-o"); @@ -79,6 +78,10 @@ fn ping_cmd( args.extend_from_slice(&["-c", "1"]) } } + + let ip = ip.to_string(); + args.push(&ip); + duct::cmd("ping", args) .stdin_null() .stdout_null() diff --git a/talpid-core/src/tunnel/wireguard/wireguard_go.rs b/talpid-core/src/tunnel/wireguard/wireguard_go.rs index eca00b76bc..f72371eb11 100644 --- a/talpid-core/src/tunnel/wireguard/wireguard_go.rs +++ b/talpid-core/src/tunnel/wireguard/wireguard_go.rs @@ -2,6 +2,8 @@ use super::{Config, Error, Result, Tunnel}; use crate::tunnel::tun_provider::{Tun, TunConfig, TunProvider}; use ipnetwork::IpNetwork; use std::{ffi::CString, fs, net::IpAddr, os::unix::io::AsRawFd, path::Path}; +#[cfg(target_os = "android")] +use talpid_types::BoxedError; pub struct WgGoTunnel { interface_name: String, @@ -19,7 +21,8 @@ impl WgGoTunnel { tun_provider: &dyn TunProvider, routes: impl Iterator<Item = IpNetwork>, ) -> Result<Self> { - let tunnel_device = tun_provider + #[cfg_attr(not(target_os = "android"), allow(unused_mut))] + let mut tunnel_device = tun_provider .create_tun(Self::create_tunnel_config(config, routes)) .map_err(Error::SetupTunnelDeviceError)?; @@ -32,9 +35,9 @@ impl WgGoTunnel { let handle = unsafe { wgTurnOnWithFd( - iface_name.as_ptr(), + iface_name.as_ptr() as *const i8, config.mtu as i64, - wg_config_str.as_ptr(), + wg_config_str.as_ptr() as *const i8, tunnel_device.as_raw_fd(), log_file.as_raw_fd(), WG_GO_LOG_DEBUG, @@ -45,6 +48,9 @@ impl WgGoTunnel { return Err(Error::StartWireguardError { status: handle }); } + #[cfg(target_os = "android")] + Self::bypass_tunnel_sockets(&mut tunnel_device, handle).map_err(Error::BypassError)?; + Ok(WgGoTunnel { interface_name, handle: Some(handle), @@ -65,6 +71,20 @@ impl WgGoTunnel { } } + #[cfg(target_os = "android")] + fn bypass_tunnel_sockets( + tunnel_device: &mut Box<dyn Tun>, + handle: i32, + ) -> std::result::Result<(), BoxedError> { + let socket_v4 = unsafe { wgGetSocketV4(handle) }; + let socket_v6 = unsafe { wgGetSocketV6(handle) }; + + tunnel_device.bypass(socket_v4)?; + tunnel_device.bypass(socket_v6)?; + + Ok(()) + } + fn stop_tunnel(&mut self) -> Result<()> { if let Some(handle) = self.handle.take() { let status = unsafe { wgTurnOff(handle) }; @@ -108,7 +128,8 @@ type WgLogLevel = i32; // wireguard-go supports log levels 0 through 3 with 3 being the most verbose const WG_GO_LOG_DEBUG: WgLogLevel = 3; -#[link(name = "wg", kind = "static")] +#[cfg_attr(target_os = "android", link(name = "wg", kind = "dylib"))] +#[cfg_attr(not(target_os = "android"), link(name = "wg", kind = "static"))] extern "C" { // Creates a new wireguard tunnel, uses the specific interface name, MTU and file descriptors // for the tunnel device and logging. @@ -123,6 +144,15 @@ extern "C" { log_fd: Fd, logLevel: WgLogLevel, ) -> i32; + // Pass a handle that was created by wgTurnOnWithFd to stop a wireguard tunnel. fn wgTurnOff(handle: i32) -> i32; + + // Returns the file descriptor of the tunnel IPv4 socket. + #[cfg(target_os = "android")] + fn wgGetSocketV4(handle: i32) -> Fd; + + // Returns the file descriptor of the tunnel IPv6 socket. + #[cfg(target_os = "android")] + fn wgGetSocketV6(handle: i32) -> Fd; } |
