diff options
| -rw-r--r-- | Cargo.lock | 1 | ||||
| -rw-r--r-- | mullvad-jni/Cargo.toml | 1 | ||||
| -rw-r--r-- | mullvad-jni/src/vpn_service_tun_provider.rs | 53 |
3 files changed, 46 insertions, 9 deletions
diff --git a/Cargo.lock b/Cargo.lock index 17330baa87..856ee14fec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1237,6 +1237,7 @@ dependencies = [ "jni 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-client-core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "log-panics 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "mullvad-daemon 2019.7.0", diff --git a/mullvad-jni/Cargo.toml b/mullvad-jni/Cargo.toml index 21b1d15ba3..2f0884f29d 100644 --- a/mullvad-jni/Cargo.toml +++ b/mullvad-jni/Cargo.toml @@ -16,6 +16,7 @@ ipnetwork = "0.14" jni = "0.12" jsonrpc-client-core = "0.5" lazy_static = "1" +libc = "0.2" log = "0.4" log-panics = "2" parking_lot = "0.8" diff --git a/mullvad-jni/src/vpn_service_tun_provider.rs b/mullvad-jni/src/vpn_service_tun_provider.rs index 92bd9b2a95..50be013504 100644 --- a/mullvad-jni/src/vpn_service_tun_provider.rs +++ b/mullvad-jni/src/vpn_service_tun_provider.rs @@ -4,7 +4,11 @@ use jni::{ signature::{JavaType, Primitive}, JNIEnv, JavaVM, }; -use std::os::unix::io::{AsRawFd, RawFd}; +use std::{ + fs::File, + io, + os::unix::io::{AsRawFd, FromRawFd, RawFd}, +}; use talpid_core::tunnel::tun_provider::{Tun, TunConfig, TunProvider}; use talpid_types::BoxedError; @@ -27,6 +31,9 @@ pub enum Error { #[error(display = "Failed to create global reference to MullvadVpnService instance")] CreateGlobalReference(#[error(cause)] jni::errors::Error), + #[error(display = "Failed to duplicate tunnel file descriptor")] + DuplicateTunFd(#[error(cause)] io::Error), + #[error(display = "Failed to find {} method", _0)] FindMethod(&'static str, #[error(cause)] jni::errors::Error), @@ -42,6 +49,7 @@ pub struct VpnServiceTunProvider { jvm: JavaVM, class: GlobalRef, object: GlobalRef, + active_tun: Option<File>, } impl VpnServiceTunProvider { @@ -53,10 +61,25 @@ impl VpnServiceTunProvider { .new_global_ref(*mullvad_vpn_service) .map_err(Error::CreateGlobalReference)?; - Ok(VpnServiceTunProvider { jvm, class, object }) + Ok(VpnServiceTunProvider { + jvm, + class, + object, + active_tun: None, + }) + } + + fn duplicate_tun(tun: &File) -> Result<RawFd, Error> { + let tun_fd = unsafe { libc::dup(tun.as_raw_fd()) }; + + if tun_fd >= 0 { + Ok(tun_fd) + } else { + Err(Error::DuplicateTunFd(io::Error::last_os_error())) + } } - fn prepare_tun(&mut self, config: TunConfig) -> Result<RawFd, Error> { + fn prepare_tun(&mut self, config: TunConfig) -> Result<&File, Error> { let env = self .jvm .attach_current_thread() @@ -79,24 +102,36 @@ impl VpnServiceTunProvider { .map_err(|cause| Error::CallMethod("MullvadVpnService.createTun", cause))?; match result { - JValue::Int(fd) => Ok(fd), - value => Err(Error::InvalidMethodResult( - "MullvadVpnService.createTun", - format!("{:?}", value), - )), + JValue::Int(fd) => { + let tun = unsafe { File::from_raw_fd(fd) }; + + self.active_tun = Some(tun); + } + value => { + return Err(Error::InvalidMethodResult( + "MullvadVpnService.createTun", + format!("{:?}", value), + )) + } } + + Ok(self + .active_tun + .as_ref() + .expect("Tunnel should be configured")) } } impl TunProvider for VpnServiceTunProvider { fn get_tun(&mut self, config: TunConfig) -> Result<Box<dyn Tun>, BoxedError> { let tun = self.prepare_tun(config).map_err(BoxedError::new)?; + let tun_fd = Self::duplicate_tun(tun).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, + tunnel: tun_fd, jvm, class: self.class.clone(), object: self.object.clone(), |
