1
1
package net.mullvad.talpid.util
2
2
3
+ import arrow.core.Either
4
+ import arrow.core.raise.result
3
5
import co.touchlab.kermit.Logger
4
6
import java.net.DatagramSocket
7
+ import java.net.Inet4Address
8
+ import java.net.Inet6Address
5
9
import java.net.InetAddress
6
10
import java.net.InetSocketAddress
7
- import java.net.SocketException
8
11
import net.mullvad.talpid.model.Connectivity
9
12
10
13
/* * This class is used to check the ip version of the underlying network when a VPN is active. */
@@ -15,10 +18,10 @@ class UnderlyingConnectivityStatusResolver(
15
18
Connectivity .Status (ipv4 = hasIPv4(), ipv6 = hasIPv6())
16
19
17
20
private fun hasIPv4 (): Boolean =
18
- hasIpVersion(InetAddress .getByName(PUBLIC_IPV4_ADDRESS ), protect)
21
+ hasIpVersion(Inet4Address .getByName(PUBLIC_IPV4_ADDRESS ), protect)
19
22
20
23
private fun hasIPv6 (): Boolean =
21
- hasIpVersion(InetAddress .getByName(PUBLIC_IPV6_ADDRESS ), protect)
24
+ hasIpVersion(Inet6Address .getByName(PUBLIC_IPV6_ADDRESS ), protect)
22
25
23
26
// Fake a connection to a public ip address using a UDP socket.
24
27
// We don't care about the result of the connection, only that it is possible to create.
@@ -31,23 +34,33 @@ class UnderlyingConnectivityStatusResolver(
31
34
private fun hasIpVersion (
32
35
ip : InetAddress ,
33
36
protect : (socket: DatagramSocket ) -> Boolean ,
34
- ): Boolean {
35
- val socket = DatagramSocket ()
36
- if (! protect(socket)) {
37
- Logger .e(" Unable to protect the socket VPN is not set up correctly" )
38
- return false
39
- }
40
- return try {
41
- socket.connect(InetSocketAddress (ip, 1 ))
42
- socket.localSocketAddress.also { Logger .d(" Public Local address: $it " ) }
43
- true
44
- } catch (_: SocketException ) {
45
- Logger .e(" Socket could not be set up" )
46
- false
47
- } finally {
48
- socket.close()
49
- }
50
- }
37
+ ): Boolean =
38
+ result {
39
+ // Open socket
40
+ val socket = openSocket().bind()
41
+
42
+ val protected = protect(socket)
43
+
44
+ // Protect so we can get underlying network
45
+ if (! protected) {
46
+ // We shouldn't be doing this if we don't have a VPN, then we should of checked
47
+ // the network directly.
48
+ Logger .w(" Failed to protect socket" )
49
+ }
50
+
51
+ // "Connect" to public ip to see IP version is available
52
+ val address = InetSocketAddress (ip, 1 )
53
+ socket.connectSafe(address).bind()
54
+ }
55
+ .isSuccess
56
+
57
+ private fun openSocket (): Either <Throwable , DatagramSocket > =
58
+ Either .catch { DatagramSocket () }.onLeft { Logger .e(" Could not open socket or bind port" ) }
59
+
60
+ private fun DatagramSocket.connectSafe (address : InetSocketAddress ): Either <Throwable , Unit > =
61
+ Either .catch { connect(address.address, address.port) }
62
+ .onLeft { Logger .e(" Socket could not be set up" ) }
63
+ .also { close() }
51
64
52
65
companion object {
53
66
private const val PUBLIC_IPV4_ADDRESS = " 1.1.1.1"
0 commit comments