summaryrefslogtreecommitdiffhomepage
path: root/android
diff options
context:
space:
mode:
authorDavid Göransson <david.goransson@mullvad.net>2025-02-20 11:07:16 +0100
committerDavid Göransson <david.goransson@mullvad.net>2025-02-25 12:02:00 +0100
commita473a917e1bfad3c7d9baa1a948eacb5096455aa (patch)
tree81fd40d56c6c0278b004a54ca54626ddf22861cb /android
parent5bf54582abe5c1b8e0660c643feb01385d312f5c (diff)
downloadmullvadvpn-a473a917e1bfad3c7d9baa1a948eacb5096455aa.tar.xz
mullvadvpn-a473a917e1bfad3c7d9baa1a948eacb5096455aa.zip
Fix incorrectly notifying offline
Incorrectly notifying that we are offline to the daemon would result in us enter ErrorState, and thus restarting the tunnel in a blocking state, opening a small window for leaks of traffic.
Diffstat (limited to 'android')
-rw-r--r--android/lib/talpid/src/main/kotlin/net/mullvad/talpid/ConnectivityListener.kt49
1 files changed, 30 insertions, 19 deletions
diff --git a/android/lib/talpid/src/main/kotlin/net/mullvad/talpid/ConnectivityListener.kt b/android/lib/talpid/src/main/kotlin/net/mullvad/talpid/ConnectivityListener.kt
index 2e35e99f0f..9c82d62251 100644
--- a/android/lib/talpid/src/main/kotlin/net/mullvad/talpid/ConnectivityListener.kt
+++ b/android/lib/talpid/src/main/kotlin/net/mullvad/talpid/ConnectivityListener.kt
@@ -2,21 +2,23 @@ package net.mullvad.talpid
import android.net.ConnectivityManager
import android.net.LinkProperties
-import android.net.Network
import android.net.NetworkCapabilities
import android.net.NetworkRequest
import co.touchlab.kermit.Logger
import java.net.InetAddress
import kotlin.collections.ArrayList
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.flow.scan
import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.runBlocking
import net.mullvad.talpid.model.NetworkState
import net.mullvad.talpid.util.NetworkEvent
import net.mullvad.talpid.util.RawNetworkState
@@ -56,7 +58,12 @@ class ConnectivityListener(private val connectivityManager: ConnectivityManager)
_isConnected =
hasInternetCapability()
.onEach { notifyConnectivityChange(it) }
- .stateIn(scope, SharingStarted.Eagerly, false)
+ .stateIn(
+ scope,
+ SharingStarted.Eagerly,
+ true, // Assume we have internet until we know otherwise
+ )
+ }
/**
* Invalidates the network state cache. E.g when the VPN is connected or disconnected, and we
@@ -70,36 +77,40 @@ class ConnectivityListener(private val connectivityManager: ConnectivityManager)
private fun LinkProperties.dnsServersWithoutFallback(): List<InetAddress> =
dnsServers.filter { it.hostAddress != TalpidVpnService.FALLBACK_DUMMY_DNS_SERVER }
- private fun hasInternetCapability(): Flow<Boolean> {
- val request =
- NetworkRequest.Builder()
- .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
- .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
- .build()
+ private val nonVPNNetworksRequest =
+ NetworkRequest.Builder().addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN).build()
+ private fun hasInternetCapability(): Flow<Boolean> {
+ @Suppress("DEPRECATION")
return connectivityManager
- .networkEvents(request)
- .scan(setOf<Network>()) { networks, event ->
+ .networkEvents(nonVPNNetworksRequest)
+ .scan(
+ connectivityManager.allNetworks.associateWith {
+ connectivityManager.getNetworkCapabilities(it)
+ }
+ ) { networks, event ->
when (event) {
- is NetworkEvent.Available -> {
- Logger.d("Network available ${event.network}")
- (networks + event.network).also {
- Logger.d("Number of networks: ${it.size}")
- }
- }
is NetworkEvent.Lost -> {
Logger.d("Network lost ${event.network}")
(networks - event.network).also {
Logger.d("Number of networks: ${it.size}")
}
}
+ is NetworkEvent.CapabilitiesChanged -> {
+ Logger.d("Network capabilities changed ${event.network}")
+ (networks + (event.network to event.networkCapabilities)).also {
+ Logger.d("Number of networks: ${it.size}")
+ }
+ }
else -> networks
}
}
- .map { it.isNotEmpty() }
- .distinctUntilChanged()
+ .map { it.any { it.value.hasInternetCapability() } }
}
+ private fun NetworkCapabilities?.hasInternetCapability(): Boolean =
+ this?.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) == true
+
private fun RawNetworkState.toNetworkState(): NetworkState =
NetworkState(
network.networkHandle,