diff options
| author | Janito Vaqueiro Ferreira Filho <janito@mullvad.net> | 2019-12-03 09:32:25 -0300 |
|---|---|---|
| committer | Janito Vaqueiro Ferreira Filho <janito@mullvad.net> | 2019-12-03 09:32:25 -0300 |
| commit | da7b3f0ead28deee5991dff7d159c0b5cf5a5d40 (patch) | |
| tree | 8dfb8d47a905ae2a9eb659f3b8747a35c96a161e | |
| parent | b0628860be5c03af241bbfc308887686ea561bed (diff) | |
| parent | 7391871673e0640e04a4e2cb0e1d900042d16389 (diff) | |
| download | mullvadvpn-da7b3f0ead28deee5991dff7d159c0b5cf5a5d40.tar.xz mullvadvpn-da7b3f0ead28deee5991dff7d159c0b5cf5a5d40.zip | |
Merge branch 'android-rust-context'
| -rw-r--r-- | .travis.yml | 2 | ||||
| -rw-r--r-- | mullvad-daemon/src/lib.rs | 20 | ||||
| -rw-r--r-- | mullvad-jni/src/lib.rs | 35 | ||||
| -rw-r--r-- | talpid-core/src/tunnel/mod.rs | 6 | ||||
| -rw-r--r-- | talpid-core/src/tunnel/tun_provider/android.rs (renamed from mullvad-jni/src/vpn_service_tun_provider.rs) | 150 | ||||
| -rw-r--r-- | talpid-core/src/tunnel/tun_provider/mod.rs | 75 | ||||
| -rw-r--r-- | talpid-core/src/tunnel/tun_provider/stub.rs | 29 | ||||
| -rw-r--r-- | talpid-core/src/tunnel/tun_provider/unix.rs | 42 | ||||
| -rw-r--r-- | talpid-core/src/tunnel/tun_provider/windows.rs | 13 | ||||
| -rw-r--r-- | talpid-core/src/tunnel/wireguard/mod.rs | 11 | ||||
| -rw-r--r-- | talpid-core/src/tunnel/wireguard/wireguard_go.rs | 65 | ||||
| -rw-r--r-- | talpid-core/src/tunnel_state_machine/connecting_state.rs | 10 | ||||
| -rw-r--r-- | talpid-core/src/tunnel_state_machine/mod.rs | 17 | ||||
| -rw-r--r-- | talpid-types/src/android/mod.rs | 6 | ||||
| -rw-r--r-- | talpid-types/src/lib.rs | 2 |
15 files changed, 222 insertions, 261 deletions
diff --git a/.travis.yml b/.travis.yml index ee29338415..676cf27d9a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -69,7 +69,7 @@ matrix: - source env.sh aarch64-linux-android - env script: - - cargo build --target aarch64-linux-android --verbose + - cargo build --target aarch64-linux-android --verbose --package mullvad-jni - cd android - ./gradlew --console plain assembleDebug # Run ktlint with extra andorid rules diff --git a/mullvad-daemon/src/lib.rs b/mullvad-daemon/src/lib.rs index bae58b2f12..d63c28e6a6 100644 --- a/mullvad-daemon/src/lib.rs +++ b/mullvad-daemon/src/lib.rs @@ -59,9 +59,10 @@ use std::{ }; use talpid_core::{ mpsc::IntoSender, - tunnel::tun_provider::{PlatformTunProvider, TunProvider}, tunnel_state_machine::{self, TunnelCommand, TunnelParametersGenerator}, }; +#[cfg(target_os = "android")] +use talpid_types::android::AndroidContext; use talpid_types::{ net::{openvpn, TransportProtocol, TunnelParameters}, tunnel::{BlockReason, ParameterGenerationError, TunnelStateTransition}, @@ -280,6 +281,8 @@ impl Daemon<ManagementInterfaceEventBroadcaster> { log_dir: Option<PathBuf>, resource_dir: PathBuf, cache_dir: PathBuf, + // TODO: Remove this once `ManagementInterface` is less coupled to the constructor. + #[cfg(target_os = "android")] android_context: AndroidContext, ) -> Result<Self> { if rpc_uniqueness_check::is_another_instance_running() { return Err(Error::DaemonIsAlreadyRunning); @@ -291,10 +294,11 @@ impl Daemon<ManagementInterfaceEventBroadcaster> { tx, rx, management_interface_broadcaster, - PlatformTunProvider::default(), log_dir, resource_dir, cache_dir, + #[cfg(target_os = "android")] + android_context, ) } @@ -336,12 +340,12 @@ impl<L> Daemon<L> where L: EventListener + Clone + Send + 'static, { - pub fn start_with_event_listener_and_tun_provider( + pub fn start_with_event_listener( event_listener: L, - tun_provider: impl TunProvider, log_dir: Option<PathBuf>, resource_dir: PathBuf, cache_dir: PathBuf, + #[cfg(target_os = "android")] android_context: AndroidContext, ) -> Result<Self> { let (tx, rx) = mpsc::channel(); @@ -349,10 +353,11 @@ where tx, rx, event_listener, - tun_provider, log_dir, resource_dir, cache_dir, + #[cfg(target_os = "android")] + android_context, ) } @@ -360,10 +365,10 @@ where internal_event_tx: mpsc::Sender<InternalDaemonEvent>, internal_event_rx: mpsc::Receiver<InternalDaemonEvent>, event_listener: L, - tun_provider: impl TunProvider, log_dir: Option<PathBuf>, resource_dir: PathBuf, cache_dir: PathBuf, + #[cfg(target_os = "android")] android_context: AndroidContext, ) -> Result<Self> { let ca_path = resource_dir.join(mullvad_paths::resources::API_CA_FILENAME); @@ -435,11 +440,12 @@ where settings.get_allow_lan(), settings.get_block_when_disconnected(), tunnel_parameters_generator, - tun_provider, log_dir, resource_dir, cache_dir.clone(), IntoSender::from(internal_event_tx.clone()), + #[cfg(target_os = "android")] + android_context, ) .map_err(Error::TunnelError)?; diff --git a/mullvad-jni/src/lib.rs b/mullvad-jni/src/lib.rs index 0e00decd04..aeeb3ee742 100644 --- a/mullvad-jni/src/lib.rs +++ b/mullvad-jni/src/lib.rs @@ -5,11 +5,9 @@ mod daemon_interface; mod from_java; mod is_null; mod jni_event_listener; -mod vpn_service_tun_provider; use crate::{ daemon_interface::DaemonInterface, from_java::FromJava, jni_event_listener::JniEventListener, - vpn_service_tun_provider::VpnServiceTunProvider, }; use jnix::{ jni::{ @@ -27,7 +25,7 @@ use std::{ sync::{mpsc, Once}, thread, }; -use talpid_types::ErrorExt; +use talpid_types::{android::AndroidContext, ErrorExt}; const LOG_FILENAME: &str = "daemon.log"; @@ -42,12 +40,15 @@ static LOAD_CLASSES: Once = Once::new(); #[derive(Debug, err_derive::Error)] #[error(no_from)] pub enum Error { - #[error(display = "Failed to create VpnService tunnel provider")] - CreateVpnServiceTunProvider(#[error(source)] vpn_service_tun_provider::Error), + #[error(display = "Failed to create global reference to Java object")] + CreateGlobalReference(#[error(cause)] jnix::jni::errors::Error), #[error(display = "Failed to get cache directory path")] GetCacheDir(#[error(source)] mullvad_paths::Error), + #[error(display = "Failed to get Java VM instance")] + GetJvmInstance(#[error(cause)] jnix::jni::errors::Error), + #[error(display = "Failed to get log directory path")] GetLogDir(#[error(source)] mullvad_paths::Error), @@ -130,26 +131,34 @@ fn initialize( vpn_service: &JObject, log_dir: PathBuf, ) -> Result<(), Error> { - let tun_provider = - VpnServiceTunProvider::new(env, vpn_service).map_err(Error::CreateVpnServiceTunProvider)?; - let daemon_command_sender = spawn_daemon(env, this, tun_provider, log_dir)?; + let android_context = create_android_context(env, *vpn_service)?; + let daemon_command_sender = spawn_daemon(env, this, log_dir, android_context)?; DAEMON_INTERFACE.set_command_sender(daemon_command_sender); Ok(()) } +fn create_android_context(env: &JnixEnv, vpn_service: JObject) -> Result<AndroidContext, Error> { + Ok(AndroidContext { + jvm: env.get_java_vm().map_err(Error::GetJvmInstance)?, + vpn_service: env + .new_global_ref(vpn_service) + .map_err(Error::CreateGlobalReference)?, + }) +} + fn spawn_daemon( env: &JnixEnv, this: &JObject, - tun_provider: VpnServiceTunProvider, log_dir: PathBuf, + android_context: AndroidContext, ) -> Result<DaemonCommandSender, Error> { let listener = JniEventListener::spawn(env, this).map_err(Error::SpawnJniEventListener)?; let (tx, rx) = mpsc::channel(); thread::spawn( - move || match create_daemon(listener, tun_provider, log_dir) { + move || match create_daemon(listener, log_dir, android_context) { Ok(daemon) => { let _ = tx.send(Ok(daemon.command_sender())); match daemon.run() { @@ -168,18 +177,18 @@ fn spawn_daemon( fn create_daemon( listener: JniEventListener, - tun_provider: VpnServiceTunProvider, log_dir: PathBuf, + android_context: AndroidContext, ) -> Result<Daemon<JniEventListener>, Error> { let resource_dir = mullvad_paths::get_resource_dir(); let cache_dir = mullvad_paths::cache_dir().map_err(Error::GetCacheDir)?; - let daemon = Daemon::start_with_event_listener_and_tun_provider( + let daemon = Daemon::start_with_event_listener( listener, - tun_provider, Some(log_dir), resource_dir, cache_dir, + android_context, ) .map_err(Error::InitializeDaemon)?; diff --git a/talpid-core/src/tunnel/mod.rs b/talpid-core/src/tunnel/mod.rs index ddf19fcb66..6d167efed3 100644 --- a/talpid-core/src/tunnel/mod.rs +++ b/talpid-core/src/tunnel/mod.rs @@ -18,7 +18,7 @@ pub mod openvpn; pub mod wireguard; /// A module for low level platform specific tunnel device management. -pub mod tun_provider; +pub(crate) mod tun_provider; const OPENVPN_LOG_FILENAME: &str = "openvpn.log"; const WIREGUARD_LOG_FILENAME: &str = "wireguard.log"; @@ -140,7 +140,7 @@ impl TunnelMonitor { log_dir: &Option<PathBuf>, resource_dir: &Path, on_event: L, - tun_provider: &mut dyn TunProvider, + tun_provider: &mut TunProvider, ) -> Result<Self> where L: Fn(TunnelEvent) + Send + Clone + Sync + 'static, @@ -166,7 +166,7 @@ impl TunnelMonitor { params: &wireguard_types::TunnelParameters, log: Option<PathBuf>, on_event: L, - tun_provider: &mut dyn TunProvider, + tun_provider: &mut TunProvider, ) -> Result<Self> where L: Fn(TunnelEvent) + Send + Sync + Clone + 'static, diff --git a/mullvad-jni/src/vpn_service_tun_provider.rs b/talpid-core/src/tunnel/tun_provider/android.rs index 01f1905814..19d4325abf 100644 --- a/mullvad-jni/src/vpn_service_tun_provider.rs +++ b/talpid-core/src/tunnel/tun_provider/android.rs @@ -1,7 +1,8 @@ +use super::TunConfig; use ipnetwork::IpNetwork; use jnix::{ jni::{ - objects::{GlobalRef, JObject, JValue}, + objects::{GlobalRef, JValue}, signature::{JavaType, Primitive}, JavaVM, }, @@ -12,13 +13,11 @@ use std::{ net::{IpAddr, Ipv4Addr, Ipv6Addr}, os::unix::io::{AsRawFd, FromRawFd, RawFd}, }; -use talpid_core::tunnel::tun_provider::{Tun, TunConfig, TunProvider}; -use talpid_types::BoxedError; +use talpid_types::android::AndroidContext; /// Errors that occur while setting up VpnService tunnel. #[derive(Debug, err_derive::Error)] -#[error(display = "Failed to set up the VpnService")] #[error(no_from)] pub enum Error { #[error(display = "Failed to attach Java VM to tunnel thread")] @@ -33,15 +32,9 @@ pub enum Error { #[error(display = "Failed to create Java VM handle clone")] CloneJavaVm(#[error(source)] jnix::jni::errors::Error), - #[error(display = "Failed to create global reference to TalpidVpnService instance")] - CreateGlobalReference(#[error(source)] jnix::jni::errors::Error), - #[error(display = "Failed to find TalpidVpnService.{} method", _0)] FindMethod(&'static str, #[error(source)] jnix::jni::errors::Error), - #[error(display = "Failed to get Java VM instance")] - GetJvmInstance(#[error(source)] jnix::jni::errors::Error), - #[error( display = "Received an invalid result from TalpidVpnService.{}: {}", _0, @@ -51,7 +44,7 @@ pub enum Error { } /// Factory of tunnel devices on Android. -pub struct VpnServiceTunProvider { +pub struct AndroidTunProvider { jvm: JavaVM, class: GlobalRef, object: GlobalRef, @@ -59,15 +52,9 @@ pub struct VpnServiceTunProvider { last_tun_config: TunConfig, } -impl VpnServiceTunProvider { - /// Create a new VpnServiceTunProvider interfacing with Android's VpnService. - pub fn new(env: &JnixEnv, mullvad_vpn_service: &JObject) -> Result<Self, Error> { - let jvm = env.get_java_vm().map_err(Error::GetJvmInstance)?; - let class = env.get_class("net/mullvad/talpid/TalpidVpnService"); - let object = env - .new_global_ref(*mullvad_vpn_service) - .map_err(Error::CreateGlobalReference)?; - +impl AndroidTunProvider { + /// Create a new AndroidTunProvider interfacing with Android's VpnService. + pub fn new(context: AndroidContext) -> Self { // Initial configuration simply intercepts all packets. The only field that matters is // `routes`, because it determines what must enter the tunnel. All other fields contain // stub values. @@ -83,15 +70,61 @@ impl VpnServiceTunProvider { mtu: 1380, }; - Ok(VpnServiceTunProvider { - jvm, - class, - object, + let env = JnixEnv::from( + context + .jvm + .attach_current_thread_as_daemon() + .expect("Failed to attach thread to Java VM"), + ); + let talpid_vpn_service_class = env.get_class("net/mullvad/talpid/TalpidVpnService"); + + AndroidTunProvider { + jvm: context.jvm, + class: talpid_vpn_service_class, + object: context.vpn_service, active_tun: None, last_tun_config: initial_tun_config, + } + } + + /// Retrieve a tunnel device with the provided configuration. + pub fn get_tun(&mut self, config: TunConfig) -> Result<VpnServiceTun, Error> { + let tun_fd = self.get_tun_fd(config)?; + + let jvm = unsafe { JavaVM::from_raw(self.jvm.get_java_vm_pointer()) } + .map_err(Error::CloneJavaVm)?; + + Ok(VpnServiceTun { + tunnel: tun_fd, + jvm, + class: self.class.clone(), + object: self.object.clone(), }) } + /// Open a tunnel device using the previous or the default configuration. + /// + /// Will open a new tunnel if there is already an active tunnel. The previous tunnel will be + /// closed. + pub fn create_tun(&mut self) -> Result<(), Error> { + self.open_tun(self.last_tun_config.clone()) + } + + /// Open a tunnel device using the previous or the default configuration if there is no + /// currently active tunnel. + pub fn create_tun_if_closed(&mut self) -> Result<(), Error> { + if self.active_tun.is_none() { + self.create_tun()?; + } + + Ok(()) + } + + /// Close currently active tunnel device. + pub fn close_tun(&mut self) { + self.active_tun = None; + } + fn get_tun_fd(&mut self, config: TunConfig) -> Result<RawFd, Error> { if self.active_tun.is_none() || self.last_tun_config != config { self.open_tun(config)?; @@ -145,66 +178,30 @@ impl VpnServiceTunProvider { } } -impl TunProvider for VpnServiceTunProvider { - fn get_tun(&mut self, config: TunConfig) -> Result<Box<dyn Tun>, BoxedError> { - let tun_fd = self.get_tun_fd(config).map_err(BoxedError::new)?; - - let jvm = unsafe { JavaVM::from_raw(self.jvm.get_java_vm_pointer()) } - .map_err(|cause| BoxedError::new(Error::CloneJavaVm(cause)))?; - - Ok(Box::new(VpnServiceTun { - tunnel: tun_fd, - jvm, - class: self.class.clone(), - object: self.object.clone(), - })) - } - - fn create_tun(&mut self) -> Result<(), BoxedError> { - self.open_tun(self.last_tun_config.clone()) - .map_err(BoxedError::new) - } - - fn create_tun_if_closed(&mut self) -> Result<(), BoxedError> { - if self.active_tun.is_none() { - self.create_tun()?; - } - - Ok(()) - } - - fn close_tun(&mut self) { - self.active_tun = None; - } -} - -struct VpnServiceTun { +/// Handle to a tunnel device on Android. +pub struct VpnServiceTun { tunnel: RawFd, jvm: JavaVM, class: GlobalRef, object: GlobalRef, } -impl AsRawFd for VpnServiceTun { - fn as_raw_fd(&self) -> RawFd { - self.tunnel - } -} - -impl Tun for VpnServiceTun { - fn interface_name(&self) -> &str { +impl VpnServiceTun { + /// Retrieve the tunnel interface name. + pub fn interface_name(&self) -> &str { "tun" } - fn bypass(&mut self, socket: RawFd) -> Result<(), BoxedError> { + /// Allow a socket to bypass the tunnel. + pub fn bypass(&mut self, socket: RawFd) -> Result<(), Error> { let env = JnixEnv::from( self.jvm .attach_current_thread_as_daemon() - .map_err(|cause| BoxedError::new(Error::AttachJvmToThread(cause)))?, + .map_err(|cause| Error::AttachJvmToThread(cause))?, ); let create_tun_method = env .get_method_id(&self.class, "bypass", "(I)Z") - .map_err(|cause| BoxedError::new(Error::FindMethod("bypass", cause)))?; + .map_err(|cause| Error::FindMethod("bypass", cause))?; let result = env .call_method_unchecked( @@ -213,15 +210,18 @@ impl Tun for VpnServiceTun { JavaType::Primitive(Primitive::Boolean), &[JValue::Int(socket)], ) - .map_err(|cause| BoxedError::new(Error::CallMethod("bypass", cause)))?; + .map_err(|cause| Error::CallMethod("bypass", cause))?; match result { - JValue::Bool(0) => Err(BoxedError::new(Error::Bypass)), + JValue::Bool(0) => Err(Error::Bypass), JValue::Bool(_) => Ok(()), - value => Err(BoxedError::new(Error::InvalidMethodResult( - "bypass", - format!("{:?}", value), - ))), + value => Err(Error::InvalidMethodResult("bypass", format!("{:?}", value))), } } } + +impl AsRawFd for VpnServiceTun { + fn as_raw_fd(&self) -> RawFd { + self.tunnel + } +} diff --git a/talpid-core/src/tunnel/tun_provider/mod.rs b/talpid-core/src/tunnel/tun_provider/mod.rs index f0bf8f69b6..b4751e019f 100644 --- a/talpid-core/src/tunnel/tun_provider/mod.rs +++ b/talpid-core/src/tunnel/tun_provider/mod.rs @@ -3,78 +3,33 @@ use ipnetwork::IpNetwork; #[cfg(target_os = "android")] use jnix::IntoJava; use std::net::IpAddr; -#[cfg(unix)] -use std::os::unix::io::AsRawFd; -#[cfg(target_os = "android")] -use std::os::unix::io::RawFd; -use talpid_types::BoxedError; cfg_if! { - if #[cfg(all(unix, not(target_os = "android")))] { + if #[cfg(target_os = "android")] { + #[path = "android.rs"] + mod imp; + use self::imp::{AndroidTunProvider, VpnServiceTun}; + pub use self::imp::Error; + + pub type Tun = VpnServiceTun; + pub type TunProvider = AndroidTunProvider; + } else if #[cfg(all(unix, not(target_os = "android")))] { #[path = "unix.rs"] mod imp; - use self::imp::UnixTunProvider; + use self::imp::{UnixTun, UnixTunProvider}; + pub use self::imp::Error; - /// Default implementation of `TunProvider` for Unix based operating systems. - /// - /// Android has a different mechanism to obtain tunnel interfaces, so it is not supported - /// here. - pub type PlatformTunProvider = UnixTunProvider; + pub type Tun = UnixTun; + pub type TunProvider = UnixTunProvider; } else { mod stub; use self::stub::StubTunProvider; + pub use self::stub::Error; - /// Default stub implementation of `TunProvider` for Android and Windows. - pub type PlatformTunProvider = StubTunProvider; + pub type TunProvider = StubTunProvider; } } -/// Windows tunnel -#[cfg(target_os = "windows")] -pub mod windows; - -/// Generic tunnel device. -/// -/// Must be associated with a platform specific file descriptor representing the device. -#[cfg(unix)] -pub trait Tun: AsRawFd + Send { - /// Retrieve the tunnel interface name. - fn interface_name(&self) -> &str; - - /// Allow a socket to bypass the tunnel. - #[cfg(target_os = "android")] - fn bypass(&mut self, socket: RawFd) -> Result<(), BoxedError>; -} - -/// Stub tunnel device. -#[cfg(windows)] -pub trait Tun: Send { - /// Retrieve the tunnel interface name. - fn interface_name(&self) -> &str; -} - -/// Factory of tunnel devices. -pub trait TunProvider: Send + 'static { - /// Retrieve a tunnel device with the provided configuration. - fn get_tun(&mut self, config: TunConfig) -> Result<Box<dyn Tun>, BoxedError>; - - /// Open a tunnel device using the previous or the default configuration. - /// - /// Will open a new tunnel if there is already an active tunnel. The previous tunnel will be - /// closed. - #[cfg(target_os = "android")] - fn create_tun(&mut self) -> Result<(), BoxedError>; - - /// Open a tunnel device using the previous or the default configuration if there is no - /// currently active tunnel. - #[cfg(target_os = "android")] - fn create_tun_if_closed(&mut self) -> Result<(), BoxedError>; - - /// Close currently active tunnel device. - #[cfg(target_os = "android")] - fn close_tun(&mut self); -} - /// Configuration for creating a tunnel device. #[derive(Clone, Debug, Eq, PartialEq)] #[cfg_attr(target_os = "android", derive(IntoJava))] diff --git a/talpid-core/src/tunnel/tun_provider/stub.rs b/talpid-core/src/tunnel/tun_provider/stub.rs index 3cd6dd0ee8..ff659210cf 100644 --- a/talpid-core/src/tunnel/tun_provider/stub.rs +++ b/talpid-core/src/tunnel/tun_provider/stub.rs @@ -1,32 +1,17 @@ -use super::{Tun, TunConfig, TunProvider}; -use talpid_types::BoxedError; +use super::TunConfig; + +/// Error stub. +pub enum Error {} /// Factory stub of tunnel devices. pub struct StubTunProvider; -impl Default for StubTunProvider { - fn default() -> Self { +impl StubTunProvider { + pub fn new() -> Self { StubTunProvider } -} - -impl TunProvider for StubTunProvider { - fn get_tun(&mut self, _: TunConfig) -> Result<Box<dyn Tun>, BoxedError> { - unimplemented!(); - } - - #[cfg(target_os = "android")] - fn create_tun(&mut self) -> Result<(), BoxedError> { - unimplemented!(); - } - - #[cfg(target_os = "android")] - fn create_tun_if_closed(&mut self) -> Result<(), BoxedError> { - unimplemented!(); - } - #[cfg(target_os = "android")] - fn close_tun(&mut self) { + pub fn get_tun(&mut self, _: TunConfig) -> Result<(), Error> { unimplemented!(); } } diff --git a/talpid-core/src/tunnel/tun_provider/unix.rs b/talpid-core/src/tunnel/tun_provider/unix.rs index 4e05505348..d8d3b7ce01 100644 --- a/talpid-core/src/tunnel/tun_provider/unix.rs +++ b/talpid-core/src/tunnel/tun_provider/unix.rs @@ -1,7 +1,6 @@ -use super::{Tun, TunConfig, TunProvider}; +use super::TunConfig; use crate::network_interface::{self, NetworkInterface, TunnelDevice}; -use std::net::IpAddr; -use talpid_types::BoxedError; +use std::{net::IpAddr, ops::Deref}; /// Errors that can occur while setting up a tunnel device. #[derive(Debug, err_derive::Error)] @@ -23,33 +22,42 @@ pub enum Error { /// Factory of tunnel devices on Unix systems. pub struct UnixTunProvider; -impl Default for UnixTunProvider { - fn default() -> Self { +impl UnixTunProvider { + pub fn new() -> Self { UnixTunProvider } -} -impl TunProvider for UnixTunProvider { - fn get_tun(&mut self, config: TunConfig) -> Result<Box<dyn Tun>, BoxedError> { - let mut tunnel_device = TunnelDevice::new() - .map_err(|cause| BoxedError::new(Error::CreateTunnelDevice(cause)))?; + pub fn get_tun(&mut self, config: TunConfig) -> Result<UnixTun, Error> { + let mut tunnel_device = TunnelDevice::new().map_err(Error::CreateTunnelDevice)?; for ip in config.addresses.iter() { tunnel_device .set_ip(*ip) - .map_err(|cause| BoxedError::new(Error::SetIpAddr(*ip, cause)))?; + .map_err(|cause| Error::SetIpAddr(*ip, cause))?; } - tunnel_device - .set_up(true) - .map_err(|cause| BoxedError::new(Error::SetUp(cause)))?; + tunnel_device.set_up(true).map_err(Error::SetUp)?; - Ok(Box::new(tunnel_device)) + Ok(UnixTun(tunnel_device)) } } -impl Tun for TunnelDevice { - fn interface_name(&self) -> &str { +/// Generic tunnel device. +/// +/// Contains the file descriptor representing the device. +pub struct UnixTun(TunnelDevice); + +impl UnixTun { + /// Retrieve the tunnel interface name. + pub fn interface_name(&self) -> &str { self.get_name() } } + +impl Deref for UnixTun { + type Target = TunnelDevice; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} diff --git a/talpid-core/src/tunnel/tun_provider/windows.rs b/talpid-core/src/tunnel/tun_provider/windows.rs deleted file mode 100644 index 9a114bf4b7..0000000000 --- a/talpid-core/src/tunnel/tun_provider/windows.rs +++ /dev/null @@ -1,13 +0,0 @@ -use super::Tun; - -/// Windows tunnel implementation -pub struct WinTun { - /// Name of tunnel interface - pub interface_name: String, -} - -impl Tun for WinTun { - fn interface_name(&self) -> &str { - &self.interface_name - } -} diff --git a/talpid-core/src/tunnel/wireguard/mod.rs b/talpid-core/src/tunnel/wireguard/mod.rs index d45a5676c3..a2c632d36f 100644 --- a/talpid-core/src/tunnel/wireguard/mod.rs +++ b/talpid-core/src/tunnel/wireguard/mod.rs @@ -1,10 +1,12 @@ #![allow(missing_docs)] use self::config::Config; +#[cfg(not(windows))] +use super::tun_provider; use super::{tun_provider::TunProvider, TunnelEvent, TunnelMetadata}; use crate::{ping_monitor, routing}; use std::{collections::HashMap, io, path::Path, sync::mpsc}; -use talpid_types::{BoxedError, ErrorExt}; +use talpid_types::ErrorExt; pub mod config; pub mod wireguard_go; @@ -21,8 +23,9 @@ pub type Result<T> = std::result::Result<T, Error>; #[error(no_from)] pub enum Error { /// Failed to setup a tunnel device. + #[cfg(not(windows))] #[error(display = "Failed to create tunnel device")] - SetupTunnelDeviceError(#[error(source)] BoxedError), + SetupTunnelDeviceError(#[error(source)] tun_provider::Error), /// A recoverable error occurred while starting the wireguard tunnel /// @@ -63,7 +66,7 @@ pub enum Error { /// 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(source)] BoxedError), + BypassError(#[error(source)] tun_provider::Error), /// Failed to duplicate tunnel file descriptor for wireguard-go #[cfg(any(target_os = "linux", target_os = "macos", target_os = "android"))] @@ -93,7 +96,7 @@ impl WireguardMonitor { config: &Config, log_path: Option<&Path>, on_event: F, - tun_provider: &mut dyn TunProvider, + tun_provider: &mut TunProvider, ) -> Result<WireguardMonitor> { let tunnel = Box::new(WgGoTunnel::start_tunnel( &config, diff --git a/talpid-core/src/tunnel/wireguard/wireguard_go.rs b/talpid-core/src/tunnel/wireguard/wireguard_go.rs index 50df570d01..cff7f2f946 100644 --- a/talpid-core/src/tunnel/wireguard/wireguard_go.rs +++ b/talpid-core/src/tunnel/wireguard/wireguard_go.rs @@ -1,60 +1,60 @@ use super::{Config, Error, Result, Tunnel}; -use crate::tunnel::tun_provider::{Tun, TunProvider}; +use crate::tunnel::tun_provider::TunProvider; use ipnetwork::IpNetwork; use std::{ffi::CString, path::Path}; -#[cfg(not(target_os = "windows"))] -use { - crate::tunnel::tun_provider::TunConfig, - std::{net::IpAddr, os::unix::io::RawFd, ptr}, -}; - - -#[cfg(target_os = "windows")] -use crate::{ - tunnel::tun_provider::windows::WinTun, - winnet::{self, add_device_ip_addresses}, -}; - #[cfg(target_os = "android")] -use talpid_types::BoxedError; +use crate::tunnel::tun_provider; #[cfg(not(target_os = "windows"))] -const MAX_PREPARE_TUN_ATTEMPTS: usize = 4; +use { + crate::tunnel::tun_provider::{Tun, TunConfig}, + std::{ + net::IpAddr, + os::unix::io::{AsRawFd, RawFd}, + ptr, + }, +}; #[cfg(target_os = "windows")] use { + crate::winnet::{self, add_device_ip_addresses}, chrono, parking_lot::Mutex, std::{collections::HashMap, fs, io::Write}, }; +#[cfg(target_os = "windows")] +lazy_static::lazy_static! { + static ref LOG_MUTEX: Mutex<HashMap<u32, fs::File>> = Mutex::new(HashMap::new()); +} + +#[cfg(target_os = "windows")] +static mut LOG_CONTEXT_NEXT_ORDINAL: u32 = 0; + +#[cfg(not(target_os = "windows"))] +const MAX_PREPARE_TUN_ATTEMPTS: usize = 4; + + pub struct WgGoTunnel { interface_name: String, 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 - _tunnel_device: Box<dyn Tun>, + #[cfg(not(target_os = "windows"))] + _tunnel_device: Tun, // ordinal that maps to fs::File instance, used with logging callback #[cfg(target_os = "windows")] log_context_ordinal: u32, } -#[cfg(target_os = "windows")] -lazy_static::lazy_static! { - static ref LOG_MUTEX: Mutex<HashMap<u32, fs::File>> = Mutex::new(HashMap::new()); -} - -#[cfg(target_os = "windows")] -static mut LOG_CONTEXT_NEXT_ORDINAL: u32 = 0; - impl WgGoTunnel { #[cfg(not(target_os = "windows"))] pub fn start_tunnel( config: &Config, log_path: Option<&Path>, - tun_provider: &mut dyn TunProvider, + tun_provider: &mut TunProvider, routes: impl Iterator<Item = IpNetwork>, ) -> Result<Self> { #[cfg_attr(not(target_os = "android"), allow(unused_mut))] @@ -105,7 +105,7 @@ impl WgGoTunnel { pub fn start_tunnel( config: &Config, log_path: Option<&Path>, - _tun_provider: &dyn TunProvider, + _tun_provider: &mut TunProvider, _routes: impl Iterator<Item = IpNetwork>, ) -> Result<Self> { let log_file = prepare_log_file(log_path)?; @@ -147,9 +147,6 @@ impl WgGoTunnel { Ok(WgGoTunnel { interface_name: iface_name.clone(), handle: Some(handle), - _tunnel_device: Box::new(WinTun { - interface_name: iface_name.clone(), - }), log_context_ordinal, }) } @@ -238,9 +235,9 @@ impl WgGoTunnel { #[cfg(target_os = "android")] fn bypass_tunnel_sockets( - tunnel_device: &mut Box<dyn Tun>, + tunnel_device: &mut Tun, handle: i32, - ) -> std::result::Result<(), BoxedError> { + ) -> std::result::Result<(), tun_provider::Error> { let socket_v4 = unsafe { wgGetSocketV4(handle) }; let socket_v6 = unsafe { wgGetSocketV6(handle) }; @@ -262,10 +259,10 @@ impl WgGoTunnel { #[cfg(not(target_os = "windows"))] fn get_tunnel( - tun_provider: &mut dyn TunProvider, + tun_provider: &mut TunProvider, config: &Config, routes: impl Iterator<Item = IpNetwork>, - ) -> Result<(Box<dyn Tun>, RawFd)> { + ) -> Result<(Tun, RawFd)> { let mut last_error = None; let tunnel_config = Self::create_tunnel_config(config, routes); diff --git a/talpid-core/src/tunnel_state_machine/connecting_state.rs b/talpid-core/src/tunnel_state_machine/connecting_state.rs index f87b96382f..67036ea98e 100644 --- a/talpid-core/src/tunnel_state_machine/connecting_state.rs +++ b/talpid-core/src/tunnel_state_machine/connecting_state.rs @@ -15,7 +15,6 @@ use futures::{ }; use log::{debug, error, info, trace, warn}; use std::{ - borrow::BorrowMut, net::IpAddr, path::{Path, PathBuf}, thread, @@ -65,7 +64,7 @@ impl ConnectingState { parameters: TunnelParameters, log_dir: &Option<PathBuf>, resource_dir: &Path, - tun_provider: &mut dyn TunProvider, + tun_provider: &mut TunProvider, retry_attempt: u32, ) -> crate::tunnel::Result<Self> { let (event_tx, event_rx) = mpsc::unbounded(); @@ -351,13 +350,10 @@ impl TunnelState for ConnectingState { ); BlockedState::enter(shared_values, BlockReason::StartTunnelError) } else { - let tun_provider: &mut dyn TunProvider = - shared_values.tun_provider.borrow_mut(); - #[cfg(target_os = "android")] { if retry_attempt > 0 && retry_attempt % MAX_ATTEMPTS_WITH_SAME_TUN == 0 { - if let Err(error) = tun_provider.create_tun() { + if let Err(error) = shared_values.tun_provider.create_tun() { error!( "{}", error.display_chain_with_msg("Failed to recreate tun device") @@ -370,7 +366,7 @@ impl TunnelState for ConnectingState { tunnel_parameters, &shared_values.log_dir, &shared_values.resource_dir, - tun_provider, + &mut shared_values.tun_provider, retry_attempt, ) { Ok(connecting_state) => { diff --git a/talpid-core/src/tunnel_state_machine/mod.rs b/talpid-core/src/tunnel_state_machine/mod.rs index 42c959c81e..d81a787f1a 100644 --- a/talpid-core/src/tunnel_state_machine/mod.rs +++ b/talpid-core/src/tunnel_state_machine/mod.rs @@ -28,6 +28,8 @@ use std::{ sync::{mpsc as sync_mpsc, Arc}, thread, }; +#[cfg(target_os = "android")] +use talpid_types::android::AndroidContext; use talpid_types::{ net::TunnelParameters, tunnel::{BlockReason, ParameterGenerationError, TunnelStateTransition}, @@ -64,11 +66,11 @@ pub fn spawn<P, T>( allow_lan: bool, block_when_disconnected: bool, tunnel_parameters_generator: impl TunnelParametersGenerator, - tun_provider: impl TunProvider, log_dir: Option<PathBuf>, resource_dir: PathBuf, cache_dir: P, state_change_listener: IntoSender<TunnelStateTransition, T>, + #[cfg(target_os = "android")] android_context: AndroidContext, ) -> Result<Arc<mpsc::UnboundedSender<TunnelCommand>>, Error> where P: AsRef<Path> + Send + 'static, @@ -80,6 +82,11 @@ where offline::spawn_monitor(Arc::downgrade(&command_tx)).map_err(Error::OfflineMonitorError)?; let is_offline = offline_monitor.is_offline(); + let tun_provider = TunProvider::new( + #[cfg(target_os = "android")] + android_context, + ); + let (startup_result_tx, startup_result_rx) = sync_mpsc::channel(); thread::spawn(move || { match create_event_loop( @@ -126,7 +133,7 @@ fn create_event_loop<T>( block_when_disconnected: bool, is_offline: bool, tunnel_parameters_generator: impl TunnelParametersGenerator, - tun_provider: impl TunProvider, + tun_provider: TunProvider, log_dir: Option<PathBuf>, resource_dir: PathBuf, cache_dir: impl AsRef<Path>, @@ -192,7 +199,7 @@ impl TunnelStateMachine { block_when_disconnected: bool, is_offline: bool, tunnel_parameters_generator: impl TunnelParametersGenerator, - tun_provider: impl TunProvider, + tun_provider: TunProvider, log_dir: Option<PathBuf>, resource_dir: PathBuf, cache_dir: impl AsRef<Path>, @@ -218,7 +225,7 @@ impl TunnelStateMachine { block_when_disconnected, is_offline, tunnel_parameters_generator: Box::new(tunnel_parameters_generator), - tun_provider: Box::new(tun_provider), + tun_provider, log_dir, resource_dir, }; @@ -306,7 +313,7 @@ struct SharedTunnelStateValues { /// The generator of new `TunnelParameter`s tunnel_parameters_generator: Box<dyn TunnelParametersGenerator>, /// The provider of tunnel devices. - tun_provider: Box<dyn TunProvider>, + tun_provider: TunProvider, /// Directory to store tunnel log file. log_dir: Option<PathBuf>, /// Resource directory path. diff --git a/talpid-types/src/android/mod.rs b/talpid-types/src/android/mod.rs new file mode 100644 index 0000000000..70c34fea95 --- /dev/null +++ b/talpid-types/src/android/mod.rs @@ -0,0 +1,6 @@ +use jnix::jni::{objects::GlobalRef, JavaVM}; + +pub struct AndroidContext { + pub jvm: JavaVM, + pub vpn_service: GlobalRef, +} diff --git a/talpid-types/src/lib.rs b/talpid-types/src/lib.rs index 569bc94fb9..00e87859a8 100644 --- a/talpid-types/src/lib.rs +++ b/talpid-types/src/lib.rs @@ -10,6 +10,8 @@ use std::{error::Error, fmt}; +#[cfg(target_os = "android")] +pub mod android; pub mod net; pub mod tunnel; |
