diff options
| author | David Göransson <david.goransson@mullvad.net> | 2025-01-13 11:51:09 +0100 |
|---|---|---|
| committer | David Göransson <david.goransson@mullvad.net> | 2025-02-06 11:02:59 +0100 |
| commit | 341c10ba38752bc36151b8998064e706f70d9ea6 (patch) | |
| tree | afb60c53e267eda0b033f346b64afd9035d7495a /android/lib/common/src | |
| parent | 612aad8d8d2ae779a4e5e01e85b2848b4fc7de3c (diff) | |
| download | mullvadvpn-341c10ba38752bc36151b8998064e706f70d9ea6.tar.xz mullvadvpn-341c10ba38752bc36151b8998064e706f70d9ea6.zip | |
Replace old waitForTunnelUp function
After invoking VpnService.establish() we will get a tunnel file
descriptor that corresponds to the interface that was created. However,
this has no guarantee of the routing table beeing up to date, and we
might thus send traffic outside the tunnel. Previously this was done
through looking at the tunFd to see that traffic is sent to verify that
the routing table has changed. If no traffic is seen some traffic is
induced to a random IP address to ensure traffic can be seen. This new
implementation is slower but won't risk sending UDP traffic to a random
public address at the internet.
Diffstat (limited to 'android/lib/common/src')
| -rw-r--r-- | android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/util/VpnServiceUtils.kt | 46 |
1 files changed, 43 insertions, 3 deletions
diff --git a/android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/util/VpnServiceUtils.kt b/android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/util/VpnServiceUtils.kt index 59833cb396..06c862936b 100644 --- a/android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/util/VpnServiceUtils.kt +++ b/android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/util/VpnServiceUtils.kt @@ -2,10 +2,14 @@ package net.mullvad.mullvadvpn.lib.common.util import android.content.Context import android.content.Intent +import android.net.VpnService import android.net.VpnService.prepare +import android.os.ParcelFileDescriptor import arrow.core.Either -import arrow.core.flatten +import arrow.core.flatMap import arrow.core.left +import arrow.core.raise.either +import arrow.core.raise.ensureNotNull import arrow.core.right import co.touchlab.kermit.Logger import net.mullvad.mullvadvpn.lib.common.util.SdkUtils.getInstalledPackagesList @@ -13,6 +17,8 @@ import net.mullvad.mullvadvpn.lib.model.PrepareError import net.mullvad.mullvadvpn.lib.model.Prepared /** + * Prepare to establish a VPN connection safely. + * * Invoking VpnService.prepare() can result in 3 out comes: * 1. IllegalStateException - There is a legacy VPN profile marked as always on * 2. Intent @@ -34,7 +40,7 @@ fun Context.prepareVpnSafe(): Either<PrepareError, Prepared> = else -> throw it } } - .map { intent -> + .flatMap { intent -> if (intent == null) { Prepared.right() } else { @@ -46,7 +52,6 @@ fun Context.prepareVpnSafe(): Either<PrepareError, Prepared> = } } } - .flatten() fun Context.getAlwaysOnVpnAppName(): String? { return resolveAlwaysOnVpnPackageName() @@ -59,3 +64,38 @@ fun Context.getAlwaysOnVpnAppName(): String? { ?.loadLabel(packageManager) ?.toString() } + +/** + * Establish a VPN connection safely. + * + * This function wraps the [VpnService.Builder.establish] function and catches any exceptions that + * may be thrown and type them to a more specific error. + * + * @return [ParcelFileDescriptor] if successful, [EstablishError] otherwise + */ +fun VpnService.Builder.establishSafe(): Either<EstablishError, ParcelFileDescriptor> = either { + val vpnInterfaceFd = + Either.catch { establish() } + .mapLeft { + when (it) { + is IllegalStateException -> EstablishError.ParameterNotApplied(it) + is IllegalArgumentException -> EstablishError.ParameterNotAccepted(it) + else -> EstablishError.UnknownError(it) + } + } + .bind() + + ensureNotNull(vpnInterfaceFd) { EstablishError.NullVpnInterface } + + vpnInterfaceFd +} + +sealed interface EstablishError { + data class ParameterNotApplied(val exception: IllegalStateException) : EstablishError + + data class ParameterNotAccepted(val exception: IllegalArgumentException) : EstablishError + + data object NullVpnInterface : EstablishError + + data class UnknownError(val error: Throwable) : EstablishError +} |
