Skip to content

Commit 4467ab7

Browse files
committedFeb 21, 2025
Rewrote some code
1 parent 807acd6 commit 4467ab7

File tree

2 files changed

+53
-14
lines changed

2 files changed

+53
-14
lines changed
 

‎android/lib/talpid/src/main/kotlin/net/mullvad/talpid/ConnectivityListener.kt

+46-10
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import android.net.ConnectivityManager
44
import android.net.LinkProperties
55
import android.net.Network
66
import android.net.NetworkCapabilities
7+
import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN
78
import android.net.NetworkRequest
89
import co.touchlab.kermit.Logger
910
import java.net.DatagramSocket
@@ -16,6 +17,7 @@ import kotlinx.coroutines.flow.SharingStarted
1617
import kotlinx.coroutines.flow.StateFlow
1718
import kotlinx.coroutines.flow.combine
1819
import kotlinx.coroutines.flow.distinctUntilChanged
20+
import kotlinx.coroutines.flow.filterIsInstance
1921
import kotlinx.coroutines.flow.map
2022
import kotlinx.coroutines.flow.onEach
2123
import kotlinx.coroutines.flow.scan
@@ -25,13 +27,14 @@ import net.mullvad.talpid.model.Connectivity
2527
import net.mullvad.talpid.model.NetworkState
2628
import net.mullvad.talpid.util.IPAvailabilityUtils
2729
import net.mullvad.talpid.util.NetworkEvent
30+
import net.mullvad.talpid.util.NetworkEvent.CapabilitiesChanged
2831
import net.mullvad.talpid.util.RawNetworkState
2932
import net.mullvad.talpid.util.defaultRawNetworkStateFlow
3033
import net.mullvad.talpid.util.networkEvents
3134

3235
class ConnectivityListener(
3336
val connectivityManager: ConnectivityManager,
34-
val protect: (socket: DatagramSocket) -> Unit,
37+
val protect: (socket: DatagramSocket) -> Boolean,
3538
) {
3639
private lateinit var _isConnected: StateFlow<Connectivity>
3740
// Used by JNI
@@ -60,22 +63,55 @@ class ConnectivityListener(
6063
.stateIn(scope, SharingStarted.Eagerly, null)
6164

6265
_isConnected =
63-
combine(_currentNetworkState, hasInternetCapability()) { linkPropertiesChanged: NetworkState?,
66+
combine(
67+
_currentNetworkState,
68+
connectivityManager
69+
.defaultRawNetworkStateFlow()
70+
.filterIsInstance<CapabilitiesChanged>(),
71+
hasInternetCapability(),
72+
) {
73+
currentNetworkState: NetworkState?,
74+
capabilitiesChanged: CapabilitiesChanged,
6475
hasInternetCapability: Boolean ->
6576
if (hasInternetCapability) {
66-
Connectivity.Status(
67-
IPAvailabilityUtils.isIPv4Available(protect = { protect(it) }),
68-
IPAvailabilityUtils.isIPv6Available(protect = { protect(it) }),
69-
)
77+
if (
78+
capabilitiesChanged.networkCapabilities.hasCapability(
79+
NET_CAPABILITY_NOT_VPN
80+
)
81+
) {
82+
// If the default network is not a VPN we can check the addresses
83+
// directly
84+
Connectivity.Status(
85+
ipv4 =
86+
currentNetworkState?.routes?.any {
87+
!it.destination.isIpv6
88+
} == true,
89+
ipv6 =
90+
currentNetworkState?.routes?.any {
91+
it.destination.isIpv6
92+
} == true,
93+
)
94+
} else {
95+
// If the default network is a VPN we need to use a socket to check
96+
// the underlying network
97+
Connectivity.Status(
98+
IPAvailabilityUtils.isIPv4Available(protect = { protect(it) }),
99+
IPAvailabilityUtils.isIPv6Available(protect = { protect(it) }),
100+
)
101+
}
70102
// If we have internet, but both IPv4 and IPv6 are not available, we
71-
// assume something is wrong and instead
72-
// will return both as available since this is the previous behavior.
73-
.takeUnless { !it.ipv4 && !it.ipv6 } ?: Connectivity.Status(true, true)
103+
// assume something is wrong and instead will return presume online.
104+
.takeUnless { !it.ipv4 && !it.ipv6 } ?: Connectivity.PresumeOnline
74105
} else {
75106
Connectivity.Status(false, false)
76107
}
77108
}
78-
.onEach { notifyConnectivityChange(it.ipv4, it.ipv6) }
109+
.onEach {
110+
when (it) {
111+
Connectivity.PresumeOnline -> notifyConnectivityChange(true, true)
112+
is Connectivity.Status -> notifyConnectivityChange(it.ipv4, it.ipv6)
113+
}
114+
}
79115
.stateIn(
80116
scope + Dispatchers.IO,
81117
SharingStarted.Eagerly,

‎android/lib/talpid/src/main/kotlin/net/mullvad/talpid/util/IPAvailabilityUtils.kt

+7-4
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ import java.net.InetSocketAddress
77
import java.net.SocketException
88

99
object IPAvailabilityUtils {
10-
fun isIPv4Available(protect: (socket: DatagramSocket) -> Unit): Boolean =
10+
fun isIPv4Available(protect: (socket: DatagramSocket) -> Boolean): Boolean =
1111
isIPAvailable(InetAddress.getByName(PUBLIC_IPV4_ADDRESS), protect)
1212

13-
fun isIPv6Available(protect: (socket: DatagramSocket) -> Unit): Boolean =
13+
fun isIPv6Available(protect: (socket: DatagramSocket) -> Boolean): Boolean =
1414
isIPAvailable(InetAddress.getByName(PUBLIC_IPV6_ADDRESS), protect)
1515

1616
// Fake a connection to a public ip address using a UDP socket.
@@ -23,11 +23,14 @@ object IPAvailabilityUtils {
2323
// exception. Otherwise we assume it is available.
2424
private inline fun <reified T : InetAddress> isIPAvailable(
2525
ip: T,
26-
protect: (socket: DatagramSocket) -> Unit,
26+
protect: (socket: DatagramSocket) -> Boolean,
2727
): Boolean {
2828
val socket = DatagramSocket()
29+
if(!protect(socket)) {
30+
Logger.e("Unable to protect the socket VPN is not set up correctly")
31+
return false
32+
}
2933
return try {
30-
protect(socket)
3134
socket.connect(InetSocketAddress(ip, 1))
3235
true
3336
} catch (_: SocketException) {

0 commit comments

Comments
 (0)
Failed to load comments.