summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJanito Vaqueiro Ferreira Filho <janito@mullvad.net>2019-11-04 15:31:21 -0200
committerJanito Vaqueiro Ferreira Filho <janito@mullvad.net>2019-11-04 15:31:21 -0200
commite190243460b1dead2ced88ce3b2ae1d6a5499603 (patch)
tree02e400f26896879547455afcbc6f5e5fcb73f4c3
parentea6ca75a2c360048b807ce6108866a655371c2f3 (diff)
parent8748940f30694c2d2fedb7c79adead5d76ff183a (diff)
downloadmullvadvpn-e190243460b1dead2ced88ce3b2ae1d6a5499603.tar.xz
mullvadvpn-e190243460b1dead2ced88ce3b2ae1d6a5499603.zip
Merge branch 'recreate-tun-on-reconnect-loop'
-rw-r--r--CHANGELOG.md3
-rw-r--r--mullvad-jni/src/vpn_service_tun_provider.rs84
-rw-r--r--talpid-core/src/tunnel/tun_provider/mod.rs8
-rw-r--r--talpid-core/src/tunnel/tun_provider/stub.rs5
-rw-r--r--talpid-core/src/tunnel_state_machine/connecting_state.rs18
5 files changed, 79 insertions, 39 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 760e303df3..374a6659c8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -39,6 +39,9 @@ Line wrap the file at 100 chars. Th
#### Windows
- Use a larger icon in notifications on Windows 10.
+#### Android
+- Recreate tun device after a fixed number of connection attempts on the same tun device.
+
### Fixed
#### Windows
- Detect removal of the OpenVPN TAP adapter on reconnection attempts.
diff --git a/mullvad-jni/src/vpn_service_tun_provider.rs b/mullvad-jni/src/vpn_service_tun_provider.rs
index 7da3ca3eef..68021ac8cd 100644
--- a/mullvad-jni/src/vpn_service_tun_provider.rs
+++ b/mullvad-jni/src/vpn_service_tun_provider.rs
@@ -92,42 +92,7 @@ impl VpnServiceTunProvider {
fn get_tun_fd(&mut self, config: TunConfig) -> Result<RawFd, Error> {
if self.active_tun.is_none() || self.last_tun_config != config {
- let env = self
- .jvm
- .attach_current_thread_as_daemon()
- .map_err(Error::AttachJvmToThread)?;
- let create_tun_method = env
- .get_method_id(
- &self.class,
- "createTun",
- "(Lnet/mullvad/mullvadvpn/model/TunConfig;)I",
- )
- .map_err(|cause| Error::FindMethod("createTun", cause))?;
-
- let java_config = env.auto_local(config.clone().into_java(&env));
- let result = env
- .call_method_unchecked(
- self.object.as_obj(),
- create_tun_method,
- JavaType::Primitive(Primitive::Int),
- &[JValue::Object(java_config.as_obj())],
- )
- .map_err(|cause| Error::CallMethod("createTun", cause))?;
-
- match result {
- JValue::Int(fd) => {
- let tun = unsafe { File::from_raw_fd(fd) };
-
- self.active_tun = Some(tun);
- self.last_tun_config = config;
- }
- value => {
- return Err(Error::InvalidMethodResult(
- "createTun",
- format!("{:?}", value),
- ))
- }
- }
+ self.open_tun(config)?;
}
Ok(self
@@ -136,6 +101,45 @@ impl VpnServiceTunProvider {
.expect("Tunnel should be configured")
.as_raw_fd())
}
+
+ fn open_tun(&mut self, config: TunConfig) -> Result<(), Error> {
+ let env = self
+ .jvm
+ .attach_current_thread_as_daemon()
+ .map_err(Error::AttachJvmToThread)?;
+ let create_tun_method = env
+ .get_method_id(
+ &self.class,
+ "createTun",
+ "(Lnet/mullvad/mullvadvpn/model/TunConfig;)I",
+ )
+ .map_err(|cause| Error::FindMethod("createTun", cause))?;
+
+ let java_config = env.auto_local(config.clone().into_java(&env));
+ let result = env
+ .call_method_unchecked(
+ self.object.as_obj(),
+ create_tun_method,
+ JavaType::Primitive(Primitive::Int),
+ &[JValue::Object(java_config.as_obj())],
+ )
+ .map_err(|cause| Error::CallMethod("createTun", cause))?;
+
+ match result {
+ JValue::Int(fd) => {
+ let tun = unsafe { File::from_raw_fd(fd) };
+
+ self.active_tun = Some(tun);
+ self.last_tun_config = config;
+
+ Ok(())
+ }
+ value => Err(Error::InvalidMethodResult(
+ "createTun",
+ format!("{:?}", value),
+ )),
+ }
+ }
}
impl TunProvider for VpnServiceTunProvider {
@@ -153,10 +157,14 @@ impl TunProvider for VpnServiceTunProvider {
}))
}
+ 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.get_tun_fd(self.last_tun_config.clone())
- .map_err(BoxedError::new)?;
+ self.create_tun()?;
}
Ok(())
diff --git a/talpid-core/src/tunnel/tun_provider/mod.rs b/talpid-core/src/tunnel/tun_provider/mod.rs
index 3cac459c51..16c9c3f17c 100644
--- a/talpid-core/src/tunnel/tun_provider/mod.rs
+++ b/talpid-core/src/tunnel/tun_provider/mod.rs
@@ -53,6 +53,14 @@ pub trait TunProvider: Send + 'static {
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>;
diff --git a/talpid-core/src/tunnel/tun_provider/stub.rs b/talpid-core/src/tunnel/tun_provider/stub.rs
index be985c8045..3cd6dd0ee8 100644
--- a/talpid-core/src/tunnel/tun_provider/stub.rs
+++ b/talpid-core/src/tunnel/tun_provider/stub.rs
@@ -16,6 +16,11 @@ impl TunProvider for StubTunProvider {
}
#[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!();
}
diff --git a/talpid-core/src/tunnel_state_machine/connecting_state.rs b/talpid-core/src/tunnel_state_machine/connecting_state.rs
index da71d392f3..efc75f3cbb 100644
--- a/talpid-core/src/tunnel_state_machine/connecting_state.rs
+++ b/talpid-core/src/tunnel_state_machine/connecting_state.rs
@@ -28,6 +28,7 @@ use talpid_types::{
};
+const MAX_ATTEMPTS_WITH_SAME_TUN: u32 = 5;
const MIN_TUNNEL_ALIVE_TIME: Duration = Duration::from_millis(1000);
/// The tunnel has been started, but it is not established/functional.
@@ -350,11 +351,26 @@ 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() {
+ error!(
+ "{}",
+ error.display_chain_with_msg("Failed to recreate tun device")
+ );
+ }
+ }
+ }
+
match Self::start_tunnel(
tunnel_parameters,
&shared_values.log_dir,
&shared_values.resource_dir,
- shared_values.tun_provider.borrow_mut(),
+ tun_provider,
retry_attempt,
) {
Ok(connecting_state) => {