diff options
| author | Jonatan Rhodin <jonatan.rhodin@mullvad.net> | 2025-04-04 08:49:59 +0200 |
|---|---|---|
| committer | Jonatan Rhodin <jonatan.rhodin@mullvad.net> | 2025-04-04 09:53:14 +0200 |
| commit | 637af3c22b57b9fc06e74c1ca2c34952aecc1f70 (patch) | |
| tree | ed91e4e8ce381d83d98885a277895e9e5ab64b97 /android | |
| parent | 119925c7887f735c688eaf491ea64d9e1b80b0c5 (diff) | |
| download | mullvadvpn-637af3c22b57b9fc06e74c1ca2c34952aecc1f70.tar.xz mullvadvpn-637af3c22b57b9fc06e74c1ca2c34952aecc1f70.zip | |
Show correct in ip when using multihop
Diffstat (limited to 'android')
5 files changed, 139 insertions, 9 deletions
diff --git a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/ConnectScreenTest.kt b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/ConnectScreenTest.kt index 43bc448805..4b5ea29fd6 100644 --- a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/ConnectScreenTest.kt +++ b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/ConnectScreenTest.kt @@ -482,6 +482,7 @@ class ConnectScreenTest { // In every { mockTunnelEndpoint.obfuscation } returns null + every { mockTunnelEndpoint.entryEndpoint } returns null every { mockTunnelEndpoint.endpoint.address.address.hostAddress } returns inHost every { mockTunnelEndpoint.endpoint.address.port } returns inPort every { mockTunnelEndpoint.endpoint.protocol } returns inProtocol @@ -683,4 +684,121 @@ class ConnectScreenTest { verify(exactly = 1) { onAccountClickMockk() } } } + + @Test + fun showConnectionDetailsObfuscation() { + composeExtension.use { + // Arrange + val mockLocation: GeoIpLocation = mockk(relaxed = true) + val mockTunnelEndpoint: TunnelEndpoint = mockk(relaxed = true) + val mockHostName = "Host-Name" + val inHost = "1.1.1.1" + val inPort = 99 + val inProtocol = TransportProtocol.Tcp + every { mockLocation.hostname } returns mockHostName + every { mockLocation.entryHostname } returns null + + // In + every { + mockTunnelEndpoint.obfuscation?.endpoint?.address?.address?.hostAddress + } returns inHost + every { mockTunnelEndpoint.obfuscation?.endpoint?.address?.port } returns inPort + every { mockTunnelEndpoint.obfuscation?.endpoint?.protocol } returns inProtocol + + // Out Ipv4 + val outIpv4 = "ipv4address" + every { mockLocation.ipv4?.hostAddress } returns outIpv4 + + // Out Ipv6 + val outIpv6 = "ipv6address" + every { mockLocation.ipv6?.hostAddress } returns outIpv6 + + initScreen( + state = + ConnectUiState( + location = mockLocation, + selectedRelayItemTitle = null, + tunnelState = + TunnelState.Connected(mockTunnelEndpoint, mockLocation, emptyList()), + showLocation = false, + deviceName = "", + daysLeftUntilExpiry = null, + inAppNotification = null, + isPlayBuild = false, + ) + ) + + // Act + onNodeWithTag(CONNECT_CARD_HEADER_TEST_TAG).performClick() + + // Assert + onNodeWithText(mockHostName).assertExists() + onNodeWithText("In").assertExists() + onNodeWithText("$inHost:$inPort TCP").assertExists() + + onNodeWithText("Out IPv4").assertExists() + onNodeWithText(outIpv4).assertExists() + + onNodeWithText("Out IPv6").assertExists() + onNodeWithText(outIpv6).assertExists() + } + } + + @Test + fun showConnectionDetailsMultihop() { + composeExtension.use { + // Arrange + val mockLocation: GeoIpLocation = mockk(relaxed = true) + val mockTunnelEndpoint: TunnelEndpoint = mockk(relaxed = true) + val mockHostName = "Host-Name" + val inHost = "8.8.8.8" + val inPort = 55 + val inProtocol = TransportProtocol.Udp + every { mockLocation.hostname } returns mockHostName + every { mockLocation.entryHostname } returns null + + // In + every { mockTunnelEndpoint.obfuscation } returns null + every { mockTunnelEndpoint.entryEndpoint?.address?.address?.hostAddress } returns inHost + every { mockTunnelEndpoint.entryEndpoint?.address?.port } returns inPort + every { mockTunnelEndpoint.entryEndpoint?.protocol } returns inProtocol + + // Out Ipv4 + val outIpv4 = "ipv4address" + every { mockLocation.ipv4?.hostAddress } returns outIpv4 + + // Out Ipv6 + val outIpv6 = "ipv6address" + every { mockLocation.ipv6?.hostAddress } returns outIpv6 + + initScreen( + state = + ConnectUiState( + location = mockLocation, + selectedRelayItemTitle = null, + tunnelState = + TunnelState.Connected(mockTunnelEndpoint, mockLocation, emptyList()), + showLocation = false, + deviceName = "", + daysLeftUntilExpiry = null, + inAppNotification = null, + isPlayBuild = false, + ) + ) + + // Act + onNodeWithTag(CONNECT_CARD_HEADER_TEST_TAG).performClick() + + // Assert + onNodeWithText(mockHostName).assertExists() + onNodeWithText("In").assertExists() + onNodeWithText("$inHost:$inPort UDP").assertExists() + + onNodeWithText("Out IPv4").assertExists() + onNodeWithText(outIpv4).assertExists() + + onNodeWithText("Out IPv6").assertExists() + onNodeWithText(outIpv6).assertExists() + } + } } diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/connectioninfo/ConnectionDetailPanel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/connectioninfo/ConnectionDetailPanel.kt index 796cd0ca6a..b13d153cc2 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/connectioninfo/ConnectionDetailPanel.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/connectioninfo/ConnectionDetailPanel.kt @@ -192,7 +192,11 @@ fun ConnectionDetails( @Composable fun TunnelEndpoint.toInAddress(): String { - val relayEndpoint = this.obfuscation?.endpoint ?: this.endpoint + // Order is important + // First we check for obfuscation (Shadowsocks, UDP-Over-UDP) + // Then we check for entry if we have multihop + // Finally we check for exit endpoint + val relayEndpoint = obfuscation?.endpoint ?: entryEndpoint ?: endpoint val host = relayEndpoint.address.address.hostAddress ?: "" val port = relayEndpoint.address.port diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/TunnelStatePreviewData.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/TunnelStatePreviewData.kt index bfb9ed40f8..a35de85e4c 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/TunnelStatePreviewData.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/TunnelStatePreviewData.kt @@ -40,6 +40,7 @@ object TunnelStatePreviewData { private fun generateTunnelEndpoint(quantumResistant: Boolean, daita: Boolean): TunnelEndpoint = TunnelEndpoint( + entryEndpoint = null, endpoint = generateEndpoint(TransportProtocol.Udp), quantumResistant = quantumResistant, obfuscation = diff --git a/android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/mapper/ToDomain.kt b/android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/mapper/ToDomain.kt index 5e2f7fb831..40ee4d6bcf 100644 --- a/android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/mapper/ToDomain.kt +++ b/android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/mapper/ToDomain.kt @@ -176,16 +176,15 @@ internal fun ManagementInterface.GeoIpLocation.toDomain(): GeoIpLocation = internal fun ManagementInterface.TunnelEndpoint.toDomain(): TunnelEndpoint = TunnelEndpoint( endpoint = - with(address) { - val indexOfSeparator = indexOfLast { it == ':' } - val ipPart = - address.substring(0, indexOfSeparator).filter { it !in listOf('[', ']') } - val portPart = address.substring(indexOfSeparator + 1) - + Endpoint(address = address.toInetSocketAddress(), protocol = protocol.toDomain()), + entryEndpoint = + if (hasEntryEndpoint()) { Endpoint( - address = InetSocketAddress(InetAddress.getByName(ipPart), portPart.toInt()), - protocol = protocol.toDomain(), + address = entryEndpoint.address.toInetSocketAddress(), + protocol = entryEndpoint.protocol.toDomain(), ) + } else { + null }, quantumResistant = quantumResistant, obfuscation = @@ -204,6 +203,13 @@ internal fun ManagementInterface.ObfuscationEndpoint.toDomain(): ObfuscationEndp obfuscationType = obfuscationType.toDomain(), ) +private fun String.toInetSocketAddress(): InetSocketAddress { + val indexOfSeparator = indexOfLast { it == ':' } + val ipPart = substring(0, indexOfSeparator).filter { it !in listOf('[', ']') } + val portPart = substring(indexOfSeparator + 1) + return InetSocketAddress(InetAddress.getByName(ipPart), portPart.toInt()) +} + internal fun ManagementInterface.ObfuscationEndpoint.ObfuscationType.toDomain(): ObfuscationType = when (this) { ManagementInterface.ObfuscationEndpoint.ObfuscationType.UDP2TCP -> ObfuscationType.Udp2Tcp diff --git a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/TunnelEndpoint.kt b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/TunnelEndpoint.kt index 3902e5c965..0092b4a09c 100644 --- a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/TunnelEndpoint.kt +++ b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/TunnelEndpoint.kt @@ -1,6 +1,7 @@ package net.mullvad.mullvadvpn.lib.model data class TunnelEndpoint( + val entryEndpoint: Endpoint?, val endpoint: Endpoint, val quantumResistant: Boolean, val obfuscation: ObfuscationEndpoint?, |
