diff options
| author | Albin <albin@mullvad.net> | 2023-05-09 16:49:29 +0200 |
|---|---|---|
| committer | Albin <albin@mullvad.net> | 2023-05-09 16:49:29 +0200 |
| commit | 63836bd9c5722a0901c3c91fda5fc70c468c4acf (patch) | |
| tree | 1382ab48256239f3058c27d3481df555641e4801 | |
| parent | a3299ad74fcd58f9c4b435ea57cf2c7350f1dd9f (diff) | |
| parent | ddaffe92860eb446ac50c3a180cc0eaaef8de5c4 (diff) | |
| download | mullvadvpn-63836bd9c5722a0901c3c91fda5fc70c468c4acf.tar.xz mullvadvpn-63836bd9c5722a0901c3c91fda5fc70c468c4acf.zip | |
Merge branch 'implement-ui-for-wg-over-tcp-droid-4'
50 files changed, 554 insertions, 38 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index fed040768a..fc2a8a4f7d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ Line wrap the file at 100 chars. Th #### Android - Add DNS content blockers. +- Add UDP-over-TCP ### Changed - In the CLI, update the `tunnel` subcommand to resemble `relay` more. For example, by adding a diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/BaseCell.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/BaseCell.kt index bab992bcc1..56a5a2b38b 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/BaseCell.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/BaseCell.kt @@ -23,9 +23,9 @@ import net.mullvad.mullvadvpn.compose.theme.MullvadDarkBlue @Composable fun BaseCell( - title: @Composable () -> Unit, - bodyView: @Composable () -> Unit, modifier: Modifier = Modifier, + title: @Composable () -> Unit, + bodyView: @Composable () -> Unit = {}, isRowEnabled: Boolean = true, onCellClicked: () -> Unit = {}, subtitle: @Composable (() -> Unit)? = null, diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/InformationComposeCell.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/InformationComposeCell.kt new file mode 100644 index 0000000000..f276defee8 --- /dev/null +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/InformationComposeCell.kt @@ -0,0 +1,81 @@ +package net.mullvad.mullvadvpn.compose.cell + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.layout.wrapContentWidth +import androidx.compose.material.Icon +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.alpha +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.dimensionResource +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import net.mullvad.mullvadvpn.R +import net.mullvad.mullvadvpn.compose.theme.AlphaActive +import net.mullvad.mullvadvpn.compose.theme.AlphaInactive +import net.mullvad.mullvadvpn.compose.theme.MullvadBlue +import net.mullvad.mullvadvpn.compose.theme.MullvadWhite + +@Preview +@Composable +private fun PreviewInformationComposeCell() { + InformationComposeCell( + title = "Information row title", + isEnabled = true, + onCellClicked = {}, + onInfoClicked = {} + ) +} + +@Composable +fun InformationComposeCell( + title: String, + isEnabled: Boolean = true, + background: Color = MullvadBlue, + onCellClicked: () -> Unit = {}, + onInfoClicked: (() -> Unit)? = null +) { + val titleModifier = Modifier.alpha(if (isEnabled) AlphaActive else AlphaInactive) + val bodyViewModifier = Modifier + + BaseCell( + title = { SwitchCellTitle(title = title, modifier = titleModifier) }, + background = background, + bodyView = { + InformationComposeCellBody(modifier = bodyViewModifier, onInfoClicked = onInfoClicked) + }, + onCellClicked = onCellClicked + ) +} + +@Composable +private fun InformationComposeCellBody(modifier: Modifier, onInfoClicked: (() -> Unit)? = null) { + val horizontalPadding = dimensionResource(id = R.dimen.medium_padding) + val verticalPadding = 13.dp + Row( + modifier = modifier.wrapContentWidth().wrapContentHeight(), + verticalAlignment = Alignment.CenterVertically + ) { + if (onInfoClicked != null) { + Icon( + modifier = + Modifier.clickable { onInfoClicked() } + .padding( + start = horizontalPadding, + end = horizontalPadding, + top = verticalPadding, + bottom = verticalPadding + ) + .align(Alignment.CenterVertically), + painter = painterResource(id = R.drawable.icon_info), + contentDescription = null, + tint = MullvadWhite + ) + } + } +} diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/SwitchComposeCell.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/SwitchComposeCell.kt index 79d5209a7f..980af59693 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/SwitchComposeCell.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/SwitchComposeCell.kt @@ -76,7 +76,7 @@ fun SwitchComposeCell( } @Composable -fun SwitchCellTitle(title: String, modifier: Modifier) { +fun SwitchCellTitle(title: String, modifier: Modifier = Modifier) { val textSize = dimensionResource(id = R.dimen.text_medium_plus).value.sp Text( text = title, diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/ObfuscationInfoDialog.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/ObfuscationInfoDialog.kt new file mode 100644 index 0000000000..323476a034 --- /dev/null +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/ObfuscationInfoDialog.kt @@ -0,0 +1,10 @@ +package net.mullvad.mullvadvpn.compose.dialog + +import androidx.compose.runtime.Composable +import androidx.compose.ui.res.stringResource +import net.mullvad.mullvadvpn.R + +@Composable +fun ObfuscationInfoDialog(onDismiss: () -> Unit) { + InfoDialog(message = stringResource(id = R.string.obfuscation_info), onDismiss = onDismiss) +} diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/UdpOverTcpPortInfoDialog.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/UdpOverTcpPortInfoDialog.kt new file mode 100644 index 0000000000..223791838a --- /dev/null +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/UdpOverTcpPortInfoDialog.kt @@ -0,0 +1,13 @@ +package net.mullvad.mullvadvpn.compose.dialog + +import androidx.compose.runtime.Composable +import androidx.compose.ui.res.stringResource +import net.mullvad.mullvadvpn.R + +@Composable +fun UdpOverTcpPortInfoDialog(onDismiss: () -> Unit) { + InfoDialog( + message = stringResource(id = R.string.udp_over_tcp_port_info), + onDismiss = onDismiss + ) +} diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/AdvancedSettingScreen.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/AdvancedSettingScreen.kt index 3bb4fcd6db..c07d188e42 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/AdvancedSettingScreen.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/AdvancedSettingScreen.kt @@ -47,8 +47,10 @@ import net.mullvad.mullvadvpn.compose.cell.ContentBlockersDisableModeCellSubtitl import net.mullvad.mullvadvpn.compose.cell.CustomDnsCellSubtitle import net.mullvad.mullvadvpn.compose.cell.DnsCell import net.mullvad.mullvadvpn.compose.cell.ExpandableComposeCell +import net.mullvad.mullvadvpn.compose.cell.InformationComposeCell import net.mullvad.mullvadvpn.compose.cell.MtuComposeCell import net.mullvad.mullvadvpn.compose.cell.NavigationComposeCell +import net.mullvad.mullvadvpn.compose.cell.SwitchCellTitle import net.mullvad.mullvadvpn.compose.cell.SwitchComposeCell import net.mullvad.mullvadvpn.compose.component.CollapsableAwareToolbarScaffold import net.mullvad.mullvadvpn.compose.component.CollapsingTopBar @@ -58,10 +60,13 @@ import net.mullvad.mullvadvpn.compose.dialog.CustomDnsInfoDialog import net.mullvad.mullvadvpn.compose.dialog.DnsDialog import net.mullvad.mullvadvpn.compose.dialog.MalwareInfoDialog import net.mullvad.mullvadvpn.compose.dialog.MtuDialog +import net.mullvad.mullvadvpn.compose.dialog.ObfuscationInfoDialog import net.mullvad.mullvadvpn.compose.extensions.itemWithDivider import net.mullvad.mullvadvpn.compose.state.AdvancedSettingsUiState import net.mullvad.mullvadvpn.compose.theme.MullvadBlue20 import net.mullvad.mullvadvpn.compose.theme.MullvadDarkBlue +import net.mullvad.mullvadvpn.compose.theme.MullvadGreen +import net.mullvad.mullvadvpn.model.SelectedObfuscation import net.mullvad.mullvadvpn.viewmodel.CustomDnsItem @OptIn(ExperimentalMaterialApi::class) @@ -97,7 +102,10 @@ private fun PreviewAdvancedSettings() { onCustomDnsInfoClicked = {}, onDismissInfoClicked = {}, onBackClick = {}, - toastMessagesSharedFlow = MutableSharedFlow<String>().asSharedFlow() + toastMessagesSharedFlow = MutableSharedFlow<String>().asSharedFlow(), + onStopEvent = {}, + onSelectObfuscationSetting = {}, + onObfuscationInfoClicked = {} ) } @@ -130,7 +138,9 @@ fun AdvancedSettingScreen( onDismissInfoClicked: () -> Unit = {}, onBackClick: () -> Unit = {}, onStopEvent: () -> Unit = {}, - toastMessagesSharedFlow: SharedFlow<String> + toastMessagesSharedFlow: SharedFlow<String>, + onSelectObfuscationSetting: (selectedObfuscation: SelectedObfuscation) -> Unit = {}, + onObfuscationInfoClicked: () -> Unit = {} ) { val cellVerticalSpacing = dimensionResource(id = R.dimen.cell_label_vertical_padding) val cellHorizontalSpacing = dimensionResource(id = R.dimen.cell_left_padding) @@ -164,6 +174,9 @@ fun AdvancedSettingScreen( is AdvancedSettingsUiState.MalwareInfoDialogUiState -> { MalwareInfoDialog(onDismissInfoClicked) } + is AdvancedSettingsUiState.ObfuscationInfoDialogUiState -> { + ObfuscationInfoDialog(onDismissInfoClicked) + } else -> { // NOOP } @@ -303,6 +316,62 @@ fun AdvancedSettingScreen( } } + itemWithDivider { + Spacer(modifier = Modifier.height(cellVerticalSpacing)) + InformationComposeCell( + title = stringResource(R.string.obfuscation_title), + onInfoClicked = { onObfuscationInfoClicked() } + ) + } + itemWithDivider { + BaseCell( + onCellClicked = { onSelectObfuscationSetting(SelectedObfuscation.Auto) }, + title = { + SwitchCellTitle( + title = stringResource(id = R.string.automatic), + ) + }, + background = + if (uiState.selectedObfuscation == SelectedObfuscation.Auto) { + MullvadGreen + } else { + MullvadBlue20 + } + ) + } + itemWithDivider { + BaseCell( + onCellClicked = { onSelectObfuscationSetting(SelectedObfuscation.Udp2Tcp) }, + title = { + SwitchCellTitle( + title = stringResource(id = R.string.obfuscation_on_udp_over_tcp), + ) + }, + background = + if (uiState.selectedObfuscation == SelectedObfuscation.Udp2Tcp) { + MullvadGreen + } else { + MullvadBlue20 + } + ) + } + itemWithDivider { + BaseCell( + onCellClicked = { onSelectObfuscationSetting(SelectedObfuscation.Off) }, + title = { + SwitchCellTitle( + title = stringResource(id = R.string.off), + ) + }, + background = + if (uiState.selectedObfuscation == SelectedObfuscation.Off) { + MullvadGreen + } else { + MullvadBlue20 + } + ) + } + item { Spacer(modifier = Modifier.height(cellVerticalSpacing)) SwitchComposeCell( diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/AdvancedSettingsUiState.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/AdvancedSettingsUiState.kt index feaa8e0824..f08a654078 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/AdvancedSettingsUiState.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/AdvancedSettingsUiState.kt @@ -1,6 +1,7 @@ package net.mullvad.mullvadvpn.compose.state import net.mullvad.mullvadvpn.model.DefaultDnsOptions +import net.mullvad.mullvadvpn.model.SelectedObfuscation import net.mullvad.mullvadvpn.viewmodel.CustomDnsItem import net.mullvad.mullvadvpn.viewmodel.StagedDns @@ -10,13 +11,15 @@ sealed interface AdvancedSettingsUiState { val customDnsItems: List<CustomDnsItem> val contentBlockersOptions: DefaultDnsOptions val isAllowLanEnabled: Boolean + val selectedObfuscation: SelectedObfuscation data class DefaultUiState( override val mtu: String = "", override val isCustomDnsEnabled: Boolean = false, override val isAllowLanEnabled: Boolean = false, override val customDnsItems: List<CustomDnsItem> = listOf(), - override val contentBlockersOptions: DefaultDnsOptions = DefaultDnsOptions() + override val contentBlockersOptions: DefaultDnsOptions = DefaultDnsOptions(), + override val selectedObfuscation: SelectedObfuscation = SelectedObfuscation.Off, ) : AdvancedSettingsUiState data class MtuDialogUiState( @@ -25,7 +28,8 @@ sealed interface AdvancedSettingsUiState { override val isAllowLanEnabled: Boolean = false, override val customDnsItems: List<CustomDnsItem> = listOf(), override val contentBlockersOptions: DefaultDnsOptions = DefaultDnsOptions(), - val mtuEditValue: String + val mtuEditValue: String, + override val selectedObfuscation: SelectedObfuscation = SelectedObfuscation.Off, ) : AdvancedSettingsUiState data class DnsDialogUiState( @@ -34,7 +38,8 @@ sealed interface AdvancedSettingsUiState { override val isAllowLanEnabled: Boolean = false, override val customDnsItems: List<CustomDnsItem> = listOf(), override val contentBlockersOptions: DefaultDnsOptions = DefaultDnsOptions(), - val stagedDns: StagedDns + val stagedDns: StagedDns, + override val selectedObfuscation: SelectedObfuscation = SelectedObfuscation.Off, ) : AdvancedSettingsUiState data class ContentBlockersInfoDialogUiState( @@ -42,7 +47,8 @@ sealed interface AdvancedSettingsUiState { override val isCustomDnsEnabled: Boolean = false, override val isAllowLanEnabled: Boolean = false, override val customDnsItems: List<CustomDnsItem> = listOf(), - override val contentBlockersOptions: DefaultDnsOptions = DefaultDnsOptions() + override val contentBlockersOptions: DefaultDnsOptions = DefaultDnsOptions(), + override val selectedObfuscation: SelectedObfuscation = SelectedObfuscation.Off, ) : AdvancedSettingsUiState data class CustomDnsInfoDialogUiState( @@ -50,7 +56,8 @@ sealed interface AdvancedSettingsUiState { override val isCustomDnsEnabled: Boolean = false, override val isAllowLanEnabled: Boolean = false, override val customDnsItems: List<CustomDnsItem> = listOf(), - override val contentBlockersOptions: DefaultDnsOptions = DefaultDnsOptions() + override val contentBlockersOptions: DefaultDnsOptions = DefaultDnsOptions(), + override val selectedObfuscation: SelectedObfuscation = SelectedObfuscation.Off, ) : AdvancedSettingsUiState data class MalwareInfoDialogUiState( @@ -58,6 +65,16 @@ sealed interface AdvancedSettingsUiState { override val isCustomDnsEnabled: Boolean = false, override val isAllowLanEnabled: Boolean = false, override val customDnsItems: List<CustomDnsItem> = listOf(), - override val contentBlockersOptions: DefaultDnsOptions = DefaultDnsOptions() + override val contentBlockersOptions: DefaultDnsOptions = DefaultDnsOptions(), + override val selectedObfuscation: SelectedObfuscation = SelectedObfuscation.Off, + ) : AdvancedSettingsUiState + + data class ObfuscationInfoDialogUiState( + override val mtu: String = "", + override val isCustomDnsEnabled: Boolean = false, + override val isAllowLanEnabled: Boolean = false, + override val customDnsItems: List<CustomDnsItem> = listOf(), + override val contentBlockersOptions: DefaultDnsOptions = DefaultDnsOptions(), + override val selectedObfuscation: SelectedObfuscation = SelectedObfuscation.Off, ) : AdvancedSettingsUiState } diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ipc/Request.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ipc/Request.kt index 56900e4440..b46bfbf64b 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ipc/Request.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ipc/Request.kt @@ -6,6 +6,7 @@ import java.net.InetAddress import kotlinx.parcelize.Parcelize import net.mullvad.mullvadvpn.model.DnsOptions import net.mullvad.mullvadvpn.model.LocationConstraint +import net.mullvad.mullvadvpn.model.ObfuscationSettings // Requests that the service can handle sealed class Request : Message.RequestMessage() { @@ -82,6 +83,8 @@ sealed class Request : Message.RequestMessage() { @Parcelize data class SetDnsOptions(val dnsOptions: DnsOptions) : Request() + @Parcelize data class SetObfuscationSettings(val settings: ObfuscationSettings?) : Request() + companion object { private const val MESSAGE_KEY = "request" diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/model/ObfuscationSettings.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/model/ObfuscationSettings.kt new file mode 100644 index 0000000000..19b5c0e5f2 --- /dev/null +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/model/ObfuscationSettings.kt @@ -0,0 +1,10 @@ +package net.mullvad.mullvadvpn.model + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +data class ObfuscationSettings( + val selectedObfuscation: SelectedObfuscation, + val udp2tcp: Udp2TcpObfuscationSettings +) : Parcelable diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/model/SelectedObfuscation.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/model/SelectedObfuscation.kt new file mode 100644 index 0000000000..8124bcc6a6 --- /dev/null +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/model/SelectedObfuscation.kt @@ -0,0 +1,11 @@ +package net.mullvad.mullvadvpn.model + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +enum class SelectedObfuscation : Parcelable { + Auto, + Off, + Udp2Tcp +} diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/model/Settings.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/model/Settings.kt index 2fcae9f4ea..0d45b38179 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/model/Settings.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/model/Settings.kt @@ -6,6 +6,7 @@ import kotlinx.parcelize.Parcelize @Parcelize data class Settings( val relaySettings: RelaySettings, + val obfuscationSettings: ObfuscationSettings, val allowLan: Boolean, val autoConnect: Boolean, val tunnelOptions: TunnelOptions, diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/model/Udp2TcpObfuscationSettings.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/model/Udp2TcpObfuscationSettings.kt new file mode 100644 index 0000000000..f01bb35c6f --- /dev/null +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/model/Udp2TcpObfuscationSettings.kt @@ -0,0 +1,6 @@ +package net.mullvad.mullvadvpn.model + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize data class Udp2TcpObfuscationSettings(val port: Constraint<Int>) : Parcelable diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/repository/SettingsRepository.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/repository/SettingsRepository.kt index 1e00efc3c5..9ab6eb412f 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/repository/SettingsRepository.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/repository/SettingsRepository.kt @@ -13,6 +13,7 @@ import net.mullvad.mullvadvpn.model.CustomDnsOptions import net.mullvad.mullvadvpn.model.DefaultDnsOptions import net.mullvad.mullvadvpn.model.DnsOptions import net.mullvad.mullvadvpn.model.DnsState +import net.mullvad.mullvadvpn.model.ObfuscationSettings import net.mullvad.mullvadvpn.model.Settings import net.mullvad.mullvadvpn.ui.serviceconnection.ServiceConnectionManager import net.mullvad.mullvadvpn.ui.serviceconnection.customDns @@ -56,4 +57,8 @@ class SettingsRepository( fun setWireguardMtu(value: Int?) { serviceConnectionManager.settingsListener()?.wireguardMtu = value } + + fun setObfuscationOptions(value: ObfuscationSettings) { + serviceConnectionManager.settingsListener()?.obfuscationSettings = value + } } diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadDaemon.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadDaemon.kt index 6d82ee617c..d46a71d805 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadDaemon.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadDaemon.kt @@ -13,6 +13,7 @@ import net.mullvad.mullvadvpn.model.DnsOptions import net.mullvad.mullvadvpn.model.GeoIpLocation import net.mullvad.mullvadvpn.model.GetAccountDataResult import net.mullvad.mullvadvpn.model.LoginResult +import net.mullvad.mullvadvpn.model.ObfuscationSettings import net.mullvad.mullvadvpn.model.RelayList import net.mullvad.mullvadvpn.model.RelaySettingsUpdate import net.mullvad.mullvadvpn.model.RemoveDeviceEvent @@ -173,6 +174,10 @@ class MullvadDaemon( updateRelaySettings(daemonInterfaceAddress, update) } + fun setObfuscationSettings(settings: ObfuscationSettings?) { + setObfuscationSettings(daemonInterfaceAddress, settings) + } + fun onDestroy() { onSettingsChange.unsubscribeAll() onTunnelStateChange.unsubscribeAll() @@ -245,6 +250,11 @@ class MullvadDaemon( update: RelaySettingsUpdate ) + private external fun setObfuscationSettings( + daemonInterfaceAddress: Long, + settings: ObfuscationSettings? + ) + private fun notifyAppVersionInfoEvent(appVersionInfo: AppVersionInfo) { onAppVersionInfoChange?.invoke(appVersionInfo) } diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/SettingsListener.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/SettingsListener.kt index 772e3127b9..7606e7709c 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/SettingsListener.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/SettingsListener.kt @@ -8,9 +8,7 @@ import kotlinx.coroutines.channels.actor import kotlinx.coroutines.channels.trySendBlocking import net.mullvad.mullvadvpn.ipc.Event import net.mullvad.mullvadvpn.ipc.Request -import net.mullvad.mullvadvpn.model.DnsOptions -import net.mullvad.mullvadvpn.model.RelaySettings -import net.mullvad.mullvadvpn.model.Settings +import net.mullvad.mullvadvpn.model.* import net.mullvad.mullvadvpn.service.MullvadDaemon import net.mullvad.talpid.util.EventNotifier @@ -19,6 +17,7 @@ class SettingsListener(endpoint: ServiceEndpoint) { class SetAllowLan(val allow: Boolean) : Command() class SetAutoConnect(val autoConnect: Boolean) : Command() class SetWireGuardMtu(val mtu: Int?) : Command() + class SetObfuscationSettings(val settings: ObfuscationSettings?) : Command() } private val commandChannel = spawnActor() @@ -26,6 +25,7 @@ class SettingsListener(endpoint: ServiceEndpoint) { val dnsOptionsNotifier = EventNotifier<DnsOptions?>(null) val relaySettingsNotifier = EventNotifier<RelaySettings?>(null) + val obfuscationSettingsNotifier = EventNotifier<ObfuscationSettings?>(null) val settingsNotifier = EventNotifier<Settings?>(null) var settings by settingsNotifier.notifiable() @@ -55,6 +55,10 @@ class SettingsListener(endpoint: ServiceEndpoint) { registerHandler(Request.SetWireGuardMtu::class) { request -> commandChannel.trySendBlocking(Command.SetWireGuardMtu(request.mtu)) } + + registerHandler(Request.SetObfuscationSettings::class) { request -> + commandChannel.trySendBlocking(Command.SetObfuscationSettings(request.settings)) + } } } @@ -64,6 +68,7 @@ class SettingsListener(endpoint: ServiceEndpoint) { dnsOptionsNotifier.unsubscribeAll() relaySettingsNotifier.unsubscribeAll() + obfuscationSettingsNotifier.unsubscribeAll() settingsNotifier.unsubscribeAll() } @@ -96,6 +101,10 @@ class SettingsListener(endpoint: ServiceEndpoint) { relaySettingsNotifier.notify(newSettings.relaySettings) } + if (settings?.obfuscationSettings != newSettings.obfuscationSettings) { + obfuscationSettingsNotifier.notify(newSettings.obfuscationSettings) + } + settings = newSettings } } @@ -110,6 +119,8 @@ class SettingsListener(endpoint: ServiceEndpoint) { is Command.SetAutoConnect -> daemon.await().setAutoConnect(command.autoConnect) is Command.SetWireGuardMtu -> daemon.await().setWireguardMtu(command.mtu) + is Command.SetObfuscationSettings -> + daemon.await().setObfuscationSettings(command.settings) } } } catch (exception: ClosedReceiveChannelException) { diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/LocationInfo.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/LocationInfo.kt index abe52eb3cd..be432375cc 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/LocationInfo.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/LocationInfo.kt @@ -6,8 +6,8 @@ import android.widget.TextView import net.mullvad.mullvadvpn.R import net.mullvad.mullvadvpn.model.GeoIpLocation import net.mullvad.mullvadvpn.model.TunnelState -import net.mullvad.talpid.net.Endpoint import net.mullvad.talpid.net.TransportProtocol +import net.mullvad.talpid.net.TunnelEndpoint class LocationInfo( parentView: View, @@ -26,7 +26,7 @@ class LocationInfo( private val inAddress: TextView = parentView.findViewById(R.id.in_address) private val outAddress: TextView = parentView.findViewById(R.id.out_address) - private var endpoint: Endpoint? = null + private var tunnelEndpoint: TunnelEndpoint? = null private var isTunnelInfoVisible = false var isTunnelInfoExpanded = false @@ -52,15 +52,15 @@ class LocationInfo( when (value) { is TunnelState.Connecting -> { - endpoint = value.endpoint?.endpoint + tunnelEndpoint = value.endpoint isTunnelInfoVisible = true } is TunnelState.Connected -> { - endpoint = value.endpoint.endpoint + tunnelEndpoint = value.endpoint isTunnelInfoVisible = true } else -> { - endpoint = null + tunnelEndpoint = null isTunnelInfoVisible = false } } @@ -95,7 +95,7 @@ class LocationInfo( hostname.setTextColor(hostnameColorExpanded) chevron.rotation = 180.0F protocol.setText(R.string.wireguard) - showInAddress(endpoint) + showInAddress(tunnelEndpoint) updateOutAddress(location) } else { hostname.setTextColor(hostnameColorCollapsed) @@ -106,16 +106,16 @@ class LocationInfo( } } - private fun showInAddress(endpoint: Endpoint?) { - if (endpoint != null) { - val host = endpoint.address.address.hostAddress - val port = endpoint.address.port + private fun showInAddress(tunnelEndpoint: TunnelEndpoint?) { + if (tunnelEndpoint != null) { + val relayEndpoint = tunnelEndpoint.obfuscation?.endpoint ?: tunnelEndpoint.endpoint + val host = relayEndpoint.address.address.hostAddress + val port = relayEndpoint.address.port val protocol = - when (endpoint.protocol) { + when (relayEndpoint.protocol) { TransportProtocol.Tcp -> context.getString(R.string.tcp) TransportProtocol.Udp -> context.getString(R.string.udp) } - inAddress.text = context.getString(R.string.in_address) + " $host:$port $protocol" } else { inAddress.text = "" diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/AdvancedFragment.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/AdvancedFragment.kt index 5e9be88387..4bd7ea35b8 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/AdvancedFragment.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/AdvancedFragment.kt @@ -51,7 +51,9 @@ class AdvancedFragment : BaseFragment() { onDismissInfoClicked = vm::onDismissInfoClick, onBackClick = { activity?.onBackPressed() }, onStopEvent = vm::onStopEvent, - toastMessagesSharedFlow = vm.toastMessages + toastMessagesSharedFlow = vm.toastMessages, + onSelectObfuscationSetting = vm::onSelectObfuscationSetting, + onObfuscationInfoClicked = vm::onObfuscationInfoClicked ) } } diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/SettingsListener.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/SettingsListener.kt index 1cb1cf2986..70e9721afc 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/SettingsListener.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/SettingsListener.kt @@ -5,6 +5,7 @@ import net.mullvad.mullvadvpn.ipc.Event import net.mullvad.mullvadvpn.ipc.EventDispatcher import net.mullvad.mullvadvpn.ipc.Request import net.mullvad.mullvadvpn.model.DnsOptions +import net.mullvad.mullvadvpn.model.ObfuscationSettings import net.mullvad.mullvadvpn.model.RelaySettings import net.mullvad.mullvadvpn.model.Settings import net.mullvad.talpid.util.EventNotifier @@ -34,6 +35,12 @@ class SettingsListener(private val connection: Messenger, eventDispatcher: Event connection.send(Request.SetWireGuardMtu(value).message) } + var obfuscationSettings: ObfuscationSettings? + get() = settingsNotifier.latestEvent?.obfuscationSettings + set(value) { + connection.send(Request.SetObfuscationSettings(value).message) + } + init { eventDispatcher.registerHandler(Event.SettingsUpdate::class, ::handleNewEvent) } diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/AdvancedSettingsViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/AdvancedSettingsViewModel.kt index 89f2df1399..1d353f5457 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/AdvancedSettingsViewModel.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/AdvancedSettingsViewModel.kt @@ -18,9 +18,13 @@ import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import net.mullvad.mullvadvpn.R import net.mullvad.mullvadvpn.compose.state.AdvancedSettingsUiState +import net.mullvad.mullvadvpn.model.Constraint import net.mullvad.mullvadvpn.model.DefaultDnsOptions import net.mullvad.mullvadvpn.model.DnsState +import net.mullvad.mullvadvpn.model.ObfuscationSettings +import net.mullvad.mullvadvpn.model.SelectedObfuscation import net.mullvad.mullvadvpn.model.Settings +import net.mullvad.mullvadvpn.model.Udp2TcpObfuscationSettings import net.mullvad.mullvadvpn.repository.SettingsRepository import net.mullvad.mullvadvpn.util.isValidMtu import org.apache.commons.validator.routines.InetAddressValidator @@ -47,6 +51,8 @@ class AdvancedSettingsViewModel( contentBlockersOptions = settings?.contentBlockersSettings() ?: DefaultDnsOptions(), isAllowLanEnabled = settings?.allowLan ?: false, + selectedObfuscation = settings?.selectedObfuscationSettings() + ?: SelectedObfuscation.Off, dialogState = dialogState ) } @@ -270,6 +276,21 @@ class AdvancedSettingsViewModel( } } + fun onSelectObfuscationSetting(selectedObfuscation: SelectedObfuscation) { + viewModelScope.launch(dispatcher) { + repository.setObfuscationOptions( + ObfuscationSettings( + selectedObfuscation = selectedObfuscation, + udp2tcp = Udp2TcpObfuscationSettings(Constraint.Any()) + ) + ) + } + } + + fun onObfuscationInfoClicked() { + dialogState.update { AdvancedSettingsDialogState.ObfuscationInfoDialog } + } + private fun updateDefaultDnsOptionsViaRepository(contentBlockersOption: DefaultDnsOptions) = viewModelScope.launch(dispatcher) { repository.setDnsOptions( @@ -312,6 +333,8 @@ class AdvancedSettingsViewModel( private fun Settings.contentBlockersSettings() = tunnelOptions.dnsOptions.defaultOptions + private fun Settings.selectedObfuscationSettings() = obfuscationSettings.selectedObfuscation + private fun String.isValidIp(): Boolean { return inetAddressValidator.isValid(this) } diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/AdvancedSettingsViewModelState.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/AdvancedSettingsViewModelState.kt index fddcdfb5b7..3349e58b99 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/AdvancedSettingsViewModelState.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/AdvancedSettingsViewModelState.kt @@ -2,6 +2,7 @@ package net.mullvad.mullvadvpn.viewmodel import net.mullvad.mullvadvpn.compose.state.AdvancedSettingsUiState import net.mullvad.mullvadvpn.model.DefaultDnsOptions +import net.mullvad.mullvadvpn.model.SelectedObfuscation data class AdvancedSettingsViewModelState( val mtuValue: String, @@ -9,6 +10,7 @@ data class AdvancedSettingsViewModelState( val isAllowLanEnabled: Boolean, val customDnsList: List<CustomDnsItem>, val contentBlockersOptions: DefaultDnsOptions, + val selectedObfuscation: SelectedObfuscation, val dialogState: AdvancedSettingsDialogState ) { fun toUiState(): AdvancedSettingsUiState { @@ -20,7 +22,8 @@ data class AdvancedSettingsViewModelState( isAllowLanEnabled = isAllowLanEnabled, customDnsItems = customDnsList, contentBlockersOptions = contentBlockersOptions, - mtuEditValue = dialogState.mtuEditValue + mtuEditValue = dialogState.mtuEditValue, + selectedObfuscation = selectedObfuscation ) is AdvancedSettingsDialogState.DnsDialog -> AdvancedSettingsUiState.DnsDialogUiState( @@ -29,7 +32,8 @@ data class AdvancedSettingsViewModelState( isAllowLanEnabled = isAllowLanEnabled, customDnsItems = customDnsList, contentBlockersOptions = contentBlockersOptions, - stagedDns = dialogState.stagedDns + stagedDns = dialogState.stagedDns, + selectedObfuscation = selectedObfuscation ) is AdvancedSettingsDialogState.ContentBlockersInfoDialog -> AdvancedSettingsUiState.ContentBlockersInfoDialogUiState( @@ -37,7 +41,8 @@ data class AdvancedSettingsViewModelState( isCustomDnsEnabled = isCustomDnsEnabled, isAllowLanEnabled = isAllowLanEnabled, customDnsItems = customDnsList, - contentBlockersOptions = contentBlockersOptions + contentBlockersOptions = contentBlockersOptions, + selectedObfuscation = selectedObfuscation ) is AdvancedSettingsDialogState.CustomDnsInfoDialog -> AdvancedSettingsUiState.CustomDnsInfoDialogUiState( @@ -53,7 +58,17 @@ data class AdvancedSettingsViewModelState( isCustomDnsEnabled = isCustomDnsEnabled, isAllowLanEnabled = isAllowLanEnabled, customDnsItems = customDnsList, - contentBlockersOptions = contentBlockersOptions + contentBlockersOptions = contentBlockersOptions, + selectedObfuscation = selectedObfuscation + ) + is AdvancedSettingsDialogState.ObfuscationInfoDialog -> + AdvancedSettingsUiState.ObfuscationInfoDialogUiState( + mtu = mtuValue, + isCustomDnsEnabled = isCustomDnsEnabled, + isAllowLanEnabled = isAllowLanEnabled, + customDnsItems = customDnsList, + contentBlockersOptions = contentBlockersOptions, + selectedObfuscation = selectedObfuscation ) else -> AdvancedSettingsUiState.DefaultUiState( @@ -61,7 +76,8 @@ data class AdvancedSettingsViewModelState( isCustomDnsEnabled = isCustomDnsEnabled, isAllowLanEnabled = isAllowLanEnabled, customDnsItems = customDnsList, - contentBlockersOptions = contentBlockersOptions + contentBlockersOptions = contentBlockersOptions, + selectedObfuscation = selectedObfuscation ) } } @@ -76,7 +92,8 @@ data class AdvancedSettingsViewModelState( customDnsList = listOf(), contentBlockersOptions = DefaultDnsOptions(), isAllowLanEnabled = false, - dialogState = AdvancedSettingsDialogState.NoDialog + dialogState = AdvancedSettingsDialogState.NoDialog, + selectedObfuscation = SelectedObfuscation.Auto ) } } @@ -93,6 +110,8 @@ sealed class AdvancedSettingsDialogState { object CustomDnsInfoDialog : AdvancedSettingsDialogState() object MalwareInfoDialog : AdvancedSettingsDialogState() + + object ObfuscationInfoDialog : AdvancedSettingsDialogState() } sealed interface StagedDns { diff --git a/android/app/src/main/kotlin/net/mullvad/talpid/net/ObfuscationEndpoint.kt b/android/app/src/main/kotlin/net/mullvad/talpid/net/ObfuscationEndpoint.kt new file mode 100644 index 0000000000..9ec96b1494 --- /dev/null +++ b/android/app/src/main/kotlin/net/mullvad/talpid/net/ObfuscationEndpoint.kt @@ -0,0 +1,8 @@ +package net.mullvad.talpid.net + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +data class ObfuscationEndpoint(val endpoint: Endpoint, val obfuscationType: ObfuscationType) : + Parcelable diff --git a/android/app/src/main/kotlin/net/mullvad/talpid/net/ObfuscationType.kt b/android/app/src/main/kotlin/net/mullvad/talpid/net/ObfuscationType.kt new file mode 100644 index 0000000000..72409d9026 --- /dev/null +++ b/android/app/src/main/kotlin/net/mullvad/talpid/net/ObfuscationType.kt @@ -0,0 +1,9 @@ +package net.mullvad.talpid.net + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +enum class ObfuscationType : Parcelable { + Udp2Tcp +} diff --git a/android/app/src/main/kotlin/net/mullvad/talpid/net/TunnelEndpoint.kt b/android/app/src/main/kotlin/net/mullvad/talpid/net/TunnelEndpoint.kt index 7bb9eb2530..9c45833eb2 100644 --- a/android/app/src/main/kotlin/net/mullvad/talpid/net/TunnelEndpoint.kt +++ b/android/app/src/main/kotlin/net/mullvad/talpid/net/TunnelEndpoint.kt @@ -4,4 +4,8 @@ import android.os.Parcelable import kotlinx.parcelize.Parcelize @Parcelize -data class TunnelEndpoint(val endpoint: Endpoint, val quantumResistant: Boolean) : Parcelable +data class TunnelEndpoint( + val endpoint: Endpoint, + val quantumResistant: Boolean, + val obfuscation: ObfuscationEndpoint? +) : Parcelable diff --git a/android/app/src/main/res/values-da/strings.xml b/android/app/src/main/res/values-da/strings.xml index 447fb4454a..30255e6372 100644 --- a/android/app/src/main/res/values-da/strings.xml +++ b/android/app/src/main/res/values-da/strings.xml @@ -17,6 +17,7 @@ <string name="auth_failed">Kan ikke godkende konto. Indsend en problemrapport.</string> <string name="auto_connect">Auto-tilslutning</string> <string name="auto_connect_footer">Opret automatisk forbindelse til en server, når appen starter.</string> + <string name="automatic">Automatisk</string> <string name="back">Tilbage</string> <string name="block_ads_title">Annoncer</string> <string name="block_adult_content_title">Voksenindhold</string> @@ -107,6 +108,10 @@ <string name="no_matching_relay">Ingen servere matcher dine indstillinger. Prøv at ændre server eller andre indstillinger.</string> <string name="no_wireguard_key">Gyldig WireGuard-nøgle mangler. Administrer nøgler under Avancerede indstillinger.</string> <string name="not_blocking_internet">DU LÆKKER MÅSKE NETVÆRKSTRAFIK</string> + <string name="obfuscation_info">Tilsløring skjuler WireGuard-trafikken inden i en anden protokol. Det kan bruges til at hjælpe med at omgå censur og andre typer filtrering, hvor en almindelig WireGuard-forbindelse ville blive blokeret.</string> + <string name="obfuscation_on_udp_over_tcp">Til (UDP-over-TCP)</string> + <string name="obfuscation_title">Tilsløring</string> + <string name="off">Fra</string> <string name="out_address">Ud</string> <string name="out_of_time">Tid udløbet</string> <string name="paid_until">Betalt indtil</string> @@ -142,6 +147,7 @@ <string name="toggle_vpn">Slå VPN til/fra</string> <string name="try_again">Prøv igen</string> <string name="udp">UDP</string> + <string name="udp_over_tcp_port_info">Hvilken TCP-port UDP-over-TCP tilsløringsprotokollen skal forbinde til på VPN-serveren.</string> <string name="unsecured">Ikke sikret</string> <string name="unsecured_connection">IKKE-SIKRET FORBINDELSE</string> <string name="unsupported_version">IKKE-UNDERSTØTTET VERSION</string> diff --git a/android/app/src/main/res/values-de/strings.xml b/android/app/src/main/res/values-de/strings.xml index d0e4eff57e..f0d627b6c2 100644 --- a/android/app/src/main/res/values-de/strings.xml +++ b/android/app/src/main/res/values-de/strings.xml @@ -17,6 +17,7 @@ <string name="auth_failed">Konto konnte nicht authentifiziert werden. Bitte senden Sie einen Problembericht.</string> <string name="auto_connect">Automatische Verbindung</string> <string name="auto_connect_footer">Stellt automatisch eine Verbindung zum Server her, wenn die App startet.</string> + <string name="automatic">Automatisch</string> <string name="back">Zurück</string> <string name="block_ads_title">Werbung</string> <string name="block_adult_content_title">Inhalte für Erwachsene</string> @@ -107,6 +108,10 @@ <string name="no_matching_relay">Kein Server entspricht Ihren Einstellungen. Versuchen Sie, den Server oder andere Einstellungen zu ändern.</string> <string name="no_wireguard_key">Gültiger WireGuard-Schlüssel fehlt. Sie können Ihre Schlüssel in den erweiterten Einstellungen verwalten.</string> <string name="not_blocking_internet">MÖGLICHERWEISE IST IHR NETZWERKVERKEHR UNSICHER</string> + <string name="obfuscation_info">Bei der Verschleierung wird der WireGuard-Datenverkehr in einem anderen Protokoll versteckt. Sie kann dazu verwendet werden, Zensur und andere Arten von Filtern zu umgehen, bei denen eine reine WireGuard-Verbindung blockiert würde.</string> + <string name="obfuscation_on_udp_over_tcp">An (UDP über TCP)</string> + <string name="obfuscation_title">Verschleierung</string> + <string name="off">Aus</string> <string name="out_address">Ausgehend</string> <string name="out_of_time">Zeit abgelaufen</string> <string name="paid_until">Bezahlt bis</string> @@ -142,6 +147,7 @@ <string name="toggle_vpn">VPN umschalten</string> <string name="try_again">Erneut versuchen</string> <string name="udp">UDP</string> + <string name="udp_over_tcp_port_info">Mit welchem TCP-Port sich das UDP-über-TCP-Verschleierungsprotokoll auf dem VPN-Server verbinden soll.</string> <string name="unsecured">Ungesichert</string> <string name="unsecured_connection">UNGESICHERTE VERBINDUNG</string> <string name="unsupported_version">NICHT UNTERSTÜTZTE VERSION</string> diff --git a/android/app/src/main/res/values-es/strings.xml b/android/app/src/main/res/values-es/strings.xml index f2bbcf56d8..9ff3883f87 100644 --- a/android/app/src/main/res/values-es/strings.xml +++ b/android/app/src/main/res/values-es/strings.xml @@ -17,6 +17,7 @@ <string name="auth_failed">No se puede autenticar la cuenta. Envíe un informe de problemas.</string> <string name="auto_connect">Conexión automática</string> <string name="auto_connect_footer">Al iniciarse la aplicación, se conecta automáticamente a un servidor.</string> + <string name="automatic">Automático</string> <string name="back">Volver</string> <string name="block_ads_title">Anuncios</string> <string name="block_adult_content_title">Contenido para adultos</string> @@ -107,6 +108,10 @@ <string name="no_matching_relay">Ningún servidor coincide con su configuración, pruebe con otro servidor u otra configuración.</string> <string name="no_wireguard_key">Falta una clave de WireGuard válida. Para administrar las claves, vaya a Configuración avanzada.</string> <string name="not_blocking_internet">PUEDE QUE SE ESTÉ FILTRANDO EL TRÁFICO DE RED</string> + <string name="obfuscation_info">La ofuscación oculta el tráfico de WireGuard dentro de otro protocolo. Puede usarse para sortear la censura y otros tipos de filtrado donde podría bloquearse una conexión de WireGuard normal.</string> + <string name="obfuscation_on_udp_over_tcp">Activado (UDP sobre TCP)</string> + <string name="obfuscation_title">Ofuscación</string> + <string name="off">Desactivado</string> <string name="out_address">Salida</string> <string name="out_of_time">Tiempo agotado</string> <string name="paid_until">Pagado hasta</string> @@ -142,6 +147,7 @@ <string name="toggle_vpn">Alternar VPN</string> <string name="try_again">Volver a intentarlo</string> <string name="udp">UDP</string> + <string name="udp_over_tcp_port_info">El puerto TCP al que se conectará el protocolo de ofuscación de UDP sobre TCP en el servidor VPN.</string> <string name="unsecured">No protegido</string> <string name="unsecured_connection">CONEXIÓN NO SEGURA</string> <string name="unsupported_version">VERSIÓN NO ADMITIDA</string> diff --git a/android/app/src/main/res/values-fi/strings.xml b/android/app/src/main/res/values-fi/strings.xml index ba2f61afd9..9ab3e0713f 100644 --- a/android/app/src/main/res/values-fi/strings.xml +++ b/android/app/src/main/res/values-fi/strings.xml @@ -17,6 +17,7 @@ <string name="auth_failed">Tilin todentaminen ei onnistu. Lähetä ongelmaraportti.</string> <string name="auto_connect">Automaattinen yhteys</string> <string name="auto_connect_footer">Muodosta yhteys palvelimeen automaattisesti, kun sovellus avataan.</string> + <string name="automatic">Automaattinen</string> <string name="back">Takaisin</string> <string name="block_ads_title">Mainokset</string> <string name="block_adult_content_title">Aikuisille suunnattu sisältö</string> @@ -107,6 +108,10 @@ <string name="no_matching_relay">Mikään palvelin ei vastaa asetuksiasi. Kokeile vaihtaa palvelinta tai muuttaa muita asetuksia.</string> <string name="no_wireguard_key">Käypä WireGuard-avain puuttuu. Voit hallinnoida avaimia lisäasetuksissa.</string> <string name="not_blocking_internet">VERKKOLIIKENTEESI SAATTAA VUOTAA</string> + <string name="obfuscation_info">Hämäysteknologian käyttäminen piilottaa WireGuard-liikenteen toisen protokollan sisään. Sitä voidaan käyttää kiertämään sensuuria ja muita suodatuksia niissä tapauksissa, kun tavallinen WireGuard-yhteys muutoin estettäisi.</string> + <string name="obfuscation_on_udp_over_tcp">Käytössä (UDP TCP:n kautta)</string> + <string name="obfuscation_title">Hämäysteknologia</string> + <string name="off">Pois</string> <string name="out_address">Lähtevä</string> <string name="out_of_time">Ei käyttöaikaa</string> <string name="paid_until">Maksu ennen</string> @@ -142,6 +147,7 @@ <string name="toggle_vpn">Vaihda VPN:ää</string> <string name="try_again">Yritä uudelleen</string> <string name="udp">UDP</string> + <string name="udp_over_tcp_port_info">Määrittää, mihin VPN-palvelimen TCP-porttiin \"UDP TCP:n kautta\" -hämäysteknologia-protokollan tulee muodostaa yhteys.</string> <string name="unsecured">Suojaamaton</string> <string name="unsecured_connection">SUOJAAMATON YHTEYS</string> <string name="unsupported_version">EI-TUETTU VERSIO</string> diff --git a/android/app/src/main/res/values-fr/strings.xml b/android/app/src/main/res/values-fr/strings.xml index e3e9ece581..2e20e5f4c1 100644 --- a/android/app/src/main/res/values-fr/strings.xml +++ b/android/app/src/main/res/values-fr/strings.xml @@ -17,6 +17,7 @@ <string name="auth_failed">Impossible d\'authentifier le compte. Veuillez envoyer un rapport de problème.</string> <string name="auto_connect">Connexion automatique</string> <string name="auto_connect_footer">Connexion automatique à un serveur dès le démarrage de l\'application.</string> + <string name="automatic">Automatique</string> <string name="back">Retour</string> <string name="block_ads_title">Publicités</string> <string name="block_adult_content_title">Contenu pour adultes</string> @@ -107,6 +108,10 @@ <string name="no_matching_relay">Aucun serveur ne correspond à vos paramètres, essayez de modifier les paramètres du serveur ou d\'autres paramètres.</string> <string name="no_wireguard_key">Une clé WireGuard valide manque. Gérez les clés dans les paramètres avancés.</string> <string name="not_blocking_internet">VOUS POURRIEZ AVOIR DES FUITES DE TRAFIC RÉSEAU</string> + <string name="obfuscation_info">La dissimulation cache le trafic WireGuard à l\'intérieur d\'un autre protocole. Elle peut être utilisée pour aider à contourner la censure et d\'autres types de filtrage, où une connexion WireGuard simple serait bloquée.</string> + <string name="obfuscation_on_udp_over_tcp">Activé (UDP sur TCP)</string> + <string name="obfuscation_title">Dissimulation</string> + <string name="off">Désactivé</string> <string name="out_address">Sortante</string> <string name="out_of_time">Plus de temps</string> <string name="paid_until">Payé jusqu\'au</string> @@ -142,6 +147,7 @@ <string name="toggle_vpn">Activer/désactiver le VPN</string> <string name="try_again">Réessayer</string> <string name="udp">UDP</string> + <string name="udp_over_tcp_port_info">Le port TCP auquel le protocole de dissimulation UDP sur TCP doit se connecter sur le serveur VPN.</string> <string name="unsecured">Non sécurisé</string> <string name="unsecured_connection">CONNEXION NON SÉCURISÉE</string> <string name="unsupported_version">VERSION NON PRISE EN CHARGE</string> diff --git a/android/app/src/main/res/values-it/strings.xml b/android/app/src/main/res/values-it/strings.xml index 9671c6b182..d37f5a76ec 100644 --- a/android/app/src/main/res/values-it/strings.xml +++ b/android/app/src/main/res/values-it/strings.xml @@ -17,6 +17,7 @@ <string name="auth_failed">Impossibile autenticare l\'account. Invia una segnalazione del problema.</string> <string name="auto_connect">Connessione automatica</string> <string name="auto_connect_footer">Connettiti automaticamente al server all\'avvio dell\'app.</string> + <string name="automatic">Automatico</string> <string name="back">Indietro</string> <string name="block_ads_title">Annunci</string> <string name="block_adult_content_title">Contenuti per adulti</string> @@ -107,6 +108,10 @@ <string name="no_matching_relay">Nessun server corrispondente alle tue impostazioni, prova a cambiare server o impostazioni.</string> <string name="no_wireguard_key">Manca una chiave WireGuard valida. Gestisci le chiavi da Impostazioni avanzate.</string> <string name="not_blocking_internet">POSSIBILI PERDITE NEL TRAFFICO DI RETE</string> + <string name="obfuscation_info">L\'offuscamento nasconde il traffico WireGuard all\'interno di un altro protocollo. Può essere utilizzato per aggirare la censura e altri tipi di filtraggio, in cui una semplice connessione WireGuard verrebbe bloccata.</string> + <string name="obfuscation_on_udp_over_tcp">On (UDP-over-TCP)</string> + <string name="obfuscation_title">Offuscamento</string> + <string name="off">Off</string> <string name="out_address">Invio</string> <string name="out_of_time">Scaduto</string> <string name="paid_until">Pagato fino al</string> @@ -142,6 +147,7 @@ <string name="toggle_vpn">Attiva/disattiva VPN</string> <string name="try_again">Riprova</string> <string name="udp">UDP</string> + <string name="udp_over_tcp_port_info">A quale porta TCP deve connettersi il protocollo di offuscamento UDP-over-TCP sul server VPN.</string> <string name="unsecured">Non protetto</string> <string name="unsecured_connection">CONNESSIONE NON PROTETTA</string> <string name="unsupported_version">VERSIONE NON SUPPORTATA</string> diff --git a/android/app/src/main/res/values-ja/strings.xml b/android/app/src/main/res/values-ja/strings.xml index 62b28368d7..75ecb81450 100644 --- a/android/app/src/main/res/values-ja/strings.xml +++ b/android/app/src/main/res/values-ja/strings.xml @@ -17,6 +17,7 @@ <string name="auth_failed">アカウントを認証できません。問題の報告を送信してください。</string> <string name="auto_connect">自動接続</string> <string name="auto_connect_footer">アプリ起動時に自動的にサーバーに接続します。</string> + <string name="automatic">自動</string> <string name="back">戻る</string> <string name="block_ads_title">広告</string> <string name="block_adult_content_title">アダルトコンテンツ</string> @@ -107,6 +108,10 @@ <string name="no_matching_relay">設定に一致するサーバーはありません。サーバーまたは他の設定を変更してみてください。</string> <string name="no_wireguard_key">有効なWireGuard鍵が見つかりません。詳細設定で鍵を管理してください。</string> <string name="not_blocking_internet">ネットワーク通信が漏洩している可能性があります</string> + <string name="obfuscation_info">難読化は、WireGuardトラフィックを別のプロトコル内に隠します。プレーンなWireGuard接続がブロックされる検閲やその他のフィルタリングを回避するために使用できます。</string> + <string name="obfuscation_on_udp_over_tcp">オン (UDP-over-TCP)</string> + <string name="obfuscation_title">難読化</string> + <string name="off">オフ</string> <string name="out_address">外側</string> <string name="out_of_time">時間切れ</string> <string name="paid_until">次の日時まで支払い済み</string> @@ -142,6 +147,7 @@ <string name="toggle_vpn">VPNの切り替え</string> <string name="try_again">再試行</string> <string name="udp">UDP</string> + <string name="udp_over_tcp_port_info">UDP-over-TCP難読化プロトコルで接続する必要のあるVPNサーバーのTCPポートです。</string> <string name="unsecured">セキュリティ保護されていません</string> <string name="unsecured_connection">セキュリティ保護されていない接続</string> <string name="unsupported_version">未対応のバージョン</string> diff --git a/android/app/src/main/res/values-ko/strings.xml b/android/app/src/main/res/values-ko/strings.xml index a802d7fa91..92a89a84a2 100644 --- a/android/app/src/main/res/values-ko/strings.xml +++ b/android/app/src/main/res/values-ko/strings.xml @@ -17,6 +17,7 @@ <string name="auth_failed">계정을 인증할 수 없습니다. 문제 보고서를 보내주세요.</string> <string name="auto_connect">자동 연결</string> <string name="auto_connect_footer">앱이 시작되면 자동으로 서버에 연결합니다.</string> + <string name="automatic">자동</string> <string name="back">뒤로</string> <string name="block_ads_title">광고</string> <string name="block_adult_content_title">성인 콘텐츠</string> @@ -107,6 +108,10 @@ <string name="no_matching_relay">설정과 일치하는 서버가 없습니다. 서버 또는 기타 설정을 변경해 보세요.</string> <string name="no_wireguard_key">유효한 WireGuard 키가 없습니다. 고급 설정에서 키를 관리하세요.</string> <string name="not_blocking_internet">네트워크 트래픽이 유출될 수 있습니다.</string> + <string name="obfuscation_info">난독 처리는 다른 프로토콜 내에서 WireGuard 트래픽을 숨깁니다. 일반 WireGuard 연결이 차단되는 상황에서 검열 및 기타 유형의 필터링을 우회하는 데 사용할 수 있습니다.</string> + <string name="obfuscation_on_udp_over_tcp">켜기(UDP-over-TCP)</string> + <string name="obfuscation_title">난독 처리</string> + <string name="off">끄기</string> <string name="out_address">아웃</string> <string name="out_of_time">시간 초과</string> <string name="paid_until">유효 기간</string> @@ -142,6 +147,7 @@ <string name="toggle_vpn">VPN 전환</string> <string name="try_again">다시 시도</string> <string name="udp">UDP</string> + <string name="udp_over_tcp_port_info">UDP-over-TCP 난독 처리 프로토콜이 VPN 서버에서 연결해야 하는 TCP 포트입니다.</string> <string name="unsecured">안전하지 않음</string> <string name="unsecured_connection">비보안 연결</string> <string name="unsupported_version">지원되지 않는 버전</string> diff --git a/android/app/src/main/res/values-my/strings.xml b/android/app/src/main/res/values-my/strings.xml index f5790a9137..21640ebb47 100644 --- a/android/app/src/main/res/values-my/strings.xml +++ b/android/app/src/main/res/values-my/strings.xml @@ -17,6 +17,7 @@ <string name="auth_failed">အကောင့်ကို စစ်မှန်ကြောင်း အတည်ပြု၍ မရနိုင်ပါ။ ပြဿနာ ရီပို့တ်တစ်ခု ပေးပို့ပေးပါ။</string> <string name="auto_connect">အော်တို ချိတ်ဆက်မှု</string> <string name="auto_connect_footer">အက်ပ် စတင်ဆောင်ရွက်ချိန်တွင် ဆာဗာနှင့် အော်တို ချိတ်ဆက်သွားပါမည်။</string> + <string name="automatic">အလိုအလျောက်</string> <string name="back">နောက်သို့</string> <string name="block_ads_title">ကြောငြာများ</string> <string name="block_adult_content_title">လူကြီး အကြောင်းအရာ</string> @@ -107,6 +108,10 @@ <string name="no_matching_relay">သင့်ဆက်တင်နှင့် ကိုက်ညီသော ဆာဗာများ မရှိပါ၊ ဆာဗာ သို့မဟုတ် အခြားဆက်တင်တို့ကို ပြောင်းလဲရန် ကြိုးစားကြည့်ပါ။</string> <string name="no_wireguard_key">အကျုံးဝင်သည့် WireGuard ကီး မရှိပါ။ အဆင့်မြင့်ဆက်တင် အောက်တွင် ကီးများကို စီမံခန့်ခွဲပါ။</string> <string name="not_blocking_internet">ကွန်ရက် ကူးလူးမှု ပေါက်ကြားနေနိုင်ပါသည်</string> + <string name="obfuscation_info">Obfuscation သည် အခြားပရိုတိုကောလ်အတွင်းရှိ WireGuard ကူးလူးမှုကို ဝှက်ထားပေးပါသည်။ သာမန် WireGuard ချိတ်ဆက်မှုကို ပိတ်ဆို့မည့် အခြားသော စစ်ထုတ်မှု အမျိုးအစားများနှင့် ဆင်ဆာဖြတ်တောက်ခြင်းကို ရှောင်လွှဲနိုင်စေရာတွင် ကူညီနိုင်စေရန် ဤသည်ကို သုံးနိုင်ပါသည်။</string> + <string name="obfuscation_on_udp_over_tcp">ဖွင့် (UDP-over-TCP)</string> + <string name="obfuscation_title">Obfuscation</string> + <string name="off">ပိတ်</string> <string name="out_address">အထွက်</string> <string name="out_of_time">အချိန်စေ့သွားပါပြီ</string> <string name="paid_until">ဖော်ပြပါအထိ ပေးချေထားပြီး</string> @@ -142,6 +147,7 @@ <string name="toggle_vpn">VPN ရွေးသုံးရန်</string> <string name="try_again">ထပ်ကြိုးစားရန်</string> <string name="udp">UDP</string> + <string name="udp_over_tcp_port_info">VPN ဆာဗာကို ဖွင့်ရန် ၎င်း TCP ပေါ့တ် UDP-over-TCP Obfuscation ပရိုတိုကောလ်နှင့် ချိတ်ဆက်ထားသင့်ပါသည်။</string> <string name="unsecured">မလုံခြုံပါ</string> <string name="unsecured_connection">မလုံခြုံသည့် ချိတ်ဆက်မှု</string> <string name="unsupported_version">တွဲဖက်မလုပ်ဆောင်နိုင်သည့် ဗားရှင်း</string> diff --git a/android/app/src/main/res/values-nb/strings.xml b/android/app/src/main/res/values-nb/strings.xml index 5978590146..4e389e7845 100644 --- a/android/app/src/main/res/values-nb/strings.xml +++ b/android/app/src/main/res/values-nb/strings.xml @@ -17,6 +17,7 @@ <string name="auth_failed">Kunne ikke autentisere konto. Send inn en problemrapport.</string> <string name="auto_connect">Automatisk tilkobling</string> <string name="auto_connect_footer">Kobler automatisk til en server når appen starter.</string> + <string name="automatic">Automatisk</string> <string name="back">Tilbake</string> <string name="block_ads_title">Annonser</string> <string name="block_adult_content_title">Vokseninnhold</string> @@ -107,6 +108,10 @@ <string name="no_matching_relay">Ingen servere passer til innstillingene dine. Prøv å endre server eller andre innstillinger.</string> <string name="no_wireguard_key">Det mangler en gyldig WireGuard-nøkkel. Du kan behandle nøklene under avanserte innstillinger.</string> <string name="not_blocking_internet">DET KAN VÆRE EN NETTVERKSLEKKASJE HOS DEG</string> + <string name="obfuscation_info">Tilsløring skjuler WireGuard-trafikken i en annen protokoll. Man kan på den måten omgå sensur og andre typer filter i tilfeller der en vanlig WireGuard-tilkobling ville blitt blokkert.</string> + <string name="obfuscation_on_udp_over_tcp">På (UDP-over-TCP)</string> + <string name="obfuscation_title">Tilsløring</string> + <string name="off">Av</string> <string name="out_address">Utgående</string> <string name="out_of_time">Tiden har utløpt</string> <string name="paid_until">Betalt fram til</string> @@ -142,6 +147,7 @@ <string name="toggle_vpn">Velg VPN</string> <string name="try_again">Prøv på nytt</string> <string name="udp">UDP</string> + <string name="udp_over_tcp_port_info">TCP-porten som UDP-over-TCP-tilsløringen skal koble til på VPN-serveren.</string> <string name="unsecured">Usikret</string> <string name="unsecured_connection">USIKKER TILKOBLING</string> <string name="unsupported_version">VERSJON UTEN STØTTE</string> diff --git a/android/app/src/main/res/values-nl/strings.xml b/android/app/src/main/res/values-nl/strings.xml index a05ac0b5a9..f6f235f8db 100644 --- a/android/app/src/main/res/values-nl/strings.xml +++ b/android/app/src/main/res/values-nl/strings.xml @@ -17,6 +17,7 @@ <string name="auth_failed">Kan account niet verifiëren. Stuur een probleemrapport.</string> <string name="auto_connect">Automatisch verbinden</string> <string name="auto_connect_footer">Automatisch verbinden met een server wanneer de app wordt gestart.</string> + <string name="automatic">Automatisch</string> <string name="back">Terug</string> <string name="block_ads_title">Advertenties</string> <string name="block_adult_content_title">Content voor volwassenen</string> @@ -107,6 +108,10 @@ <string name="no_matching_relay">Er zijn geen servers die overeenkomen met uw instellingen. Probeer een andere server of andere instellingen.</string> <string name="no_wireguard_key">Geldige WireGuard-sleutel ontbreekt. Beheer sleutels onder Geavanceerde instellingen.</string> <string name="not_blocking_internet">U LEKT MOGELIJK NETWERKVERKEER</string> + <string name="obfuscation_info">Obfuscatie verbergt het WireGuard-verkeer in een ander protocol. Het kan worden gebruikt om censuur en andere soorten filtering te omzeilen, waar een gewone WireGuard-verbinding zou worden geblokkeerd.</string> + <string name="obfuscation_on_udp_over_tcp">Aan (UDP-over-TCP)</string> + <string name="obfuscation_title">Obfuscatie</string> + <string name="off">Uit</string> <string name="out_address">Uit</string> <string name="out_of_time">Geen tijd meer</string> <string name="paid_until">Betaald tot</string> @@ -142,6 +147,7 @@ <string name="toggle_vpn">VPN in-/uitschakelen</string> <string name="try_again">Probeer het opnieuw</string> <string name="udp">UDP</string> + <string name="udp_over_tcp_port_info">Met welke TCP-poort moet het UDP-over-TCP-obfuscatieprotocol verbinding maken op de VPN-server.</string> <string name="unsecured">Niet beveiligd</string> <string name="unsecured_connection">NIET-BEVEILIGDE VERBINDING</string> <string name="unsupported_version">NIET-ONDERSTEUNDE VERSIE</string> diff --git a/android/app/src/main/res/values-pl/strings.xml b/android/app/src/main/res/values-pl/strings.xml index 4df7d16986..e9a704a41f 100644 --- a/android/app/src/main/res/values-pl/strings.xml +++ b/android/app/src/main/res/values-pl/strings.xml @@ -17,6 +17,7 @@ <string name="auth_failed">Nie można uwierzytelnić konta. Wyślij zgłoszenie problemu.</string> <string name="auto_connect">Automatyczne łączenie</string> <string name="auto_connect_footer">Automatycznie łącz z serwerem po uruchomieniu aplikacji.</string> + <string name="automatic">Automatycznie</string> <string name="back">Wstecz</string> <string name="block_ads_title">Reklamy</string> <string name="block_adult_content_title">Treści dla dorosłych</string> @@ -107,6 +108,10 @@ <string name="no_matching_relay">Żaden serwer nie odpowiada ustawieniom. Spróbuj zmienić serwer lub inne ustawienia.</string> <string name="no_wireguard_key">Brak prawidłowego klucza WireGuard. Zarządzaj kluczami w Ustawieniach zaawansowanych.</string> <string name="not_blocking_internet">TWÓJ RUCH SIECIOWY MOŻE WYCIEKAĆ</string> + <string name="obfuscation_info">Zaciemnianie ukrywa ruch WireGuard w innym protokole. Można go użyć do obchodzenia cenzury i innych typów filtrowania, w których zwykłe połączenie WireGuard byłoby blokowane.</string> + <string name="obfuscation_on_udp_over_tcp">Wł. (UDP-przez-TCP)</string> + <string name="obfuscation_title">Zaciemnianie</string> + <string name="off">Wył.</string> <string name="out_address">Wyjście</string> <string name="out_of_time">Koniec czasu</string> <string name="paid_until">Płatne do</string> @@ -142,6 +147,7 @@ <string name="toggle_vpn">Przełącz VPN</string> <string name="try_again">Spróbuj ponownie</string> <string name="udp">UDP</string> + <string name="udp_over_tcp_port_info">Port TCP, z którym powinien łączyć się protokół zaciemniania UDP-przez-TCP na serwerze VPN.</string> <string name="unsecured">Niezabezpieczone</string> <string name="unsecured_connection">NIEZABEZPIECZONE POŁĄCZENIE</string> <string name="unsupported_version">WERSJA NIEOBSŁUGIWANA</string> diff --git a/android/app/src/main/res/values-pt/strings.xml b/android/app/src/main/res/values-pt/strings.xml index 1bbd8bac53..ab1135859c 100644 --- a/android/app/src/main/res/values-pt/strings.xml +++ b/android/app/src/main/res/values-pt/strings.xml @@ -17,6 +17,7 @@ <string name="auth_failed">Não foi possível autenticar a conta. Envie um relatório do problema.</string> <string name="auto_connect">Ligação automática</string> <string name="auto_connect_footer">Liga-se automaticamente a um servidor quando a app inicia.</string> + <string name="automatic">Automático</string> <string name="back">Retroceder</string> <string name="block_ads_title">Anúncios</string> <string name="block_adult_content_title">Conteúdo para adultos</string> @@ -107,6 +108,10 @@ <string name="no_matching_relay">Nenhum servidor corresponde às suas definições. Tente alterar o servidor ou outras definições.</string> <string name="no_wireguard_key">Chave WireGuard válida em falta. Faça a gestão das chaves em Definições Avançadas.</string> <string name="not_blocking_internet">PODERÁ ESTAR A PERDER TRÁFEGO DE REDE</string> + <string name="obfuscation_info">A ofuscação oculta o tráfego do WireGuard dentro de outro protocolo. Pode ser utilizado para ajudar a contornar a censura e outros tipos de filtragem, onde uma simples ligação WireGuard seria bloqueada.</string> + <string name="obfuscation_on_udp_over_tcp">Ligado (UDP sobre TCP)</string> + <string name="obfuscation_title">Ofuscação</string> + <string name="off">Desligado</string> <string name="out_address">Saída</string> <string name="out_of_time">Sem tempo</string> <string name="paid_until">Pago até</string> @@ -142,6 +147,7 @@ <string name="toggle_vpn">Alternar VPN</string> <string name="try_again">Tentar novamente</string> <string name="udp">UDP</string> + <string name="udp_over_tcp_port_info">A que porta TCP o protocolo de ofuscação UDP sobre TCP deve ligar-se no servidor VPN.</string> <string name="unsecured">Inseguro</string> <string name="unsecured_connection">LIGAÇÃO INSEGURA</string> <string name="unsupported_version">VERSÃO NÃO SUPORTADA</string> diff --git a/android/app/src/main/res/values-ru/strings.xml b/android/app/src/main/res/values-ru/strings.xml index 8e67d1b789..7c3fefa8df 100644 --- a/android/app/src/main/res/values-ru/strings.xml +++ b/android/app/src/main/res/values-ru/strings.xml @@ -17,6 +17,7 @@ <string name="auth_failed">Не удается произвести аутентификацию учетной записи. Отправьте сообщение о проблеме.</string> <string name="auto_connect">Автоподключение</string> <string name="auto_connect_footer">Автоматически подключаться к серверу при запуске приложения.</string> + <string name="automatic">Автоматически</string> <string name="back">Назад</string> <string name="block_ads_title">Реклама</string> <string name="block_adult_content_title">Контент для взрослых</string> @@ -107,6 +108,10 @@ <string name="no_matching_relay">Нет серверов, соответствующих вашим настройкам. Попробуйте изменить сервер или задайте другие настройки.</string> <string name="no_wireguard_key">Не найден действительный ключ WireGuard. Управлять ключами можно в дополнительных настройках.</string> <string name="not_blocking_internet">ВОЗМОЖНА УТЕЧКА СЕТЕВОГО ТРАФИКА</string> + <string name="obfuscation_info">Обфускация скрывает трафик WireGuard внутри другого протокола. Это может использоваться для обхода цензуры и других видов фильтрации, когда обычное соединение WireGuard было бы заблокировано.</string> + <string name="obfuscation_on_udp_over_tcp">Вкл. (UDP через TCP)</string> + <string name="obfuscation_title">Обфускация</string> + <string name="off">Выключен</string> <string name="out_address">Выход</string> <string name="out_of_time">Закончилось время</string> <string name="paid_until">Оплачено до</string> @@ -142,6 +147,7 @@ <string name="toggle_vpn">Включение VPN</string> <string name="try_again">Повторить попытку</string> <string name="udp">UDP</string> + <string name="udp_over_tcp_port_info">TCP-порт, к которому должен подключаться протокол обфускации UDP через TCP на VPN-сервере.</string> <string name="unsecured">Подключение не защищено</string> <string name="unsecured_connection">НЕЗАЩИЩЕННОЕ ПОДКЛЮЧЕНИЕ</string> <string name="unsupported_version">НЕПОДДЕРЖИВАЕМАЯ ВЕРСИЯ</string> diff --git a/android/app/src/main/res/values-sv/strings.xml b/android/app/src/main/res/values-sv/strings.xml index 1c6b71c3d6..c612249eaa 100644 --- a/android/app/src/main/res/values-sv/strings.xml +++ b/android/app/src/main/res/values-sv/strings.xml @@ -17,6 +17,7 @@ <string name="auth_failed">Det går inte att autentisera kontot. Skicka en problemrapport.</string> <string name="auto_connect">Anslut automatiskt</string> <string name="auto_connect_footer">Anslut automatiskt till en server när appen startas.</string> + <string name="automatic">Automatisk</string> <string name="back">Tillbaka</string> <string name="block_ads_title">Annonser</string> <string name="block_adult_content_title">Vuxet innehåll</string> @@ -107,6 +108,10 @@ <string name="no_matching_relay">Inga servrar matchar dina inställningar. Försök att ändra server eller med andra inställningar.</string> <string name="no_wireguard_key">Giltig WireGuard-nyckel saknas. Hantera nycklar i Avancerade inställningar.</string> <string name="not_blocking_internet">DU KANSKE HAR LÄCKAGE I NÄTVERKSTRAFIKEN</string> + <string name="obfuscation_info">Obfuskering döljer WireGuard-trafik inne i ett annat protokoll. Det kan användas för att kringgå censur och andra filtertyper där en vanlig WireGuard-anslutning skulle blockeras.</string> + <string name="obfuscation_on_udp_over_tcp">På (UDP över TCP)</string> + <string name="obfuscation_title">Obfuskering</string> + <string name="off">Av</string> <string name="out_address">Ut</string> <string name="out_of_time">Ingen tid kvar</string> <string name="paid_until">Betalat till</string> @@ -142,6 +147,7 @@ <string name="toggle_vpn">Växla VPN</string> <string name="try_again">Försök igen</string> <string name="udp">UDP</string> + <string name="udp_over_tcp_port_info">Vilken TCP-port som UDP-över-TCP-obfuskeringsprotokoll bör ansluta till på VPN-servern.</string> <string name="unsecured">Oskyddad</string> <string name="unsecured_connection">OSÄKER ANSLUTNING</string> <string name="unsupported_version">VERSION UTAN STÖD</string> diff --git a/android/app/src/main/res/values-th/strings.xml b/android/app/src/main/res/values-th/strings.xml index c310ce11af..5d60396604 100644 --- a/android/app/src/main/res/values-th/strings.xml +++ b/android/app/src/main/res/values-th/strings.xml @@ -17,6 +17,7 @@ <string name="auth_failed">ไม่สามารถตรวจสอบความถูกต้องของบัญชีได้ โปรดส่งรายงานปัญหา</string> <string name="auto_connect">เชื่อมต่ออัตโนมัติ</string> <string name="auto_connect_footer">เชื่อมต่อเซิร์ฟเวอร์โดยอัตโนมัติทันทีที่เปิดแอป</string> + <string name="automatic">อัตโนมัติ</string> <string name="back">ย้อนกลับ</string> <string name="block_ads_title">โฆษณา</string> <string name="block_adult_content_title">เนื้อหาสำหรับผู้ใหญ่</string> @@ -107,6 +108,10 @@ <string name="no_matching_relay">ไม่มีเซิร์ฟเวอร์ที่ตรงกับการตั้งค่าของคุณ โปรดลองเปลี่ยนเซิร์ฟเวอร์ หรือการตั้งค่าอื่นๆ</string> <string name="no_wireguard_key">คีย์ WireGuard ที่ใช้ได้ขาดหายไป จัดการคีย์ภายใต้การตั้งค่าขั้นสูง</string> <string name="not_blocking_internet">คุณอาจมีการรับส่งข้อมูลทางเครือข่ายที่รั่วไหลอยู่</string> + <string name="obfuscation_info">ข้อมูลที่คลุมเครือจะซ่อนการรับส่งข้อมูล WireGuard ภายในอีกโพรโทคอลหนึ่ง ซึ่งใช้เพื่อช่วยหลบเลี่ยงการเซ็นเซอร์ และการกรองประเภทอื่นๆ ที่การเชื่อมต่อ WireGuard แบบธรรมดาจะถูกบล็อกได้</string> + <string name="obfuscation_on_udp_over_tcp">เปิด (UDP-ผ่าน-TCP)</string> + <string name="obfuscation_title">ข้อมูลที่คลุมเครือ</string> + <string name="off">ปิด</string> <string name="out_address">ออก</string> <string name="out_of_time">หมดเวลา</string> <string name="paid_until">ชำระเงินแล้วจนถึง</string> @@ -142,6 +147,7 @@ <string name="toggle_vpn">เปิด/ปิด VPN</string> <string name="try_again">ลองอีกครั้ง</string> <string name="udp">UDP</string> + <string name="udp_over_tcp_port_info">พอร์ต TCP ใดที่โพรโทคอลข้อมูลที่คลุมเครือ UDP-ผ่าน-TCP ควรเชื่อมต่อบนเซิร์ฟเวอร์ VPN</string> <string name="unsecured">ไม่ปลอดภัย</string> <string name="unsecured_connection">การเชื่อมต่อที่ไม่ปลอดภัย</string> <string name="unsupported_version">เวอร์ชันที่ไม่รองรับ</string> diff --git a/android/app/src/main/res/values-tr/strings.xml b/android/app/src/main/res/values-tr/strings.xml index b3b04a5c7a..88cff28b45 100644 --- a/android/app/src/main/res/values-tr/strings.xml +++ b/android/app/src/main/res/values-tr/strings.xml @@ -17,6 +17,7 @@ <string name="auth_failed">Hesap doğrulanamıyor. Lütfen bir hata raporu gönderin.</string> <string name="auto_connect">Otomatik Bağlan</string> <string name="auto_connect_footer">Uygulama başladığında bir sunucuya otomatik olarak bağlan.</string> + <string name="automatic">Otomatik</string> <string name="back">Geri</string> <string name="block_ads_title">Reklamlar</string> <string name="block_adult_content_title">Yetişkinlere özel içerik</string> @@ -107,6 +108,10 @@ <string name="no_matching_relay">Ayarlarınızla eşleşen sunucu yok. Sunucuyu veya diğer ayarları değiştirmeyi deneyin.</string> <string name="no_wireguard_key">Geçerli WireGuard anahtarı eksik. Gelişmiş ayarlardan anahtarları yönetin.</string> <string name="not_blocking_internet">AĞ TRAFİĞİNİZDE SIZINTI OLABİLİR</string> + <string name="obfuscation_info">Gizleme, WireGuard trafiğini başka bir protokolün içinde gizler. Normal bir WireGuard bağlantısının engelleneceği sansürü ve diğer filtreleme türlerini aşmaya yardımcı olmak için kullanılabilir.</string> + <string name="obfuscation_on_udp_over_tcp">Açık (TCP üzerinden UDP)</string> + <string name="obfuscation_title">Gizleme</string> + <string name="off">Kapalı</string> <string name="out_address">Çıkış</string> <string name="out_of_time">Süre doldu</string> <string name="paid_until">Şu tarihe kadar ödendi:</string> @@ -142,6 +147,7 @@ <string name="toggle_vpn">VPN\'i aç/kapat</string> <string name="try_again">Tekrar dene</string> <string name="udp">UDP</string> + <string name="udp_over_tcp_port_info">TCP üzerinden UDP gizleme protokolünün VPN sunucusunda hangi TCP portuna bağlanması gerekiyor.</string> <string name="unsecured">Güvenli değil</string> <string name="unsecured_connection">GÜVENLİ OLMAYAN BAĞLANTI</string> <string name="unsupported_version">DESTEKLENMEYEN SÜRÜM</string> diff --git a/android/app/src/main/res/values-zh-rCN/strings.xml b/android/app/src/main/res/values-zh-rCN/strings.xml index 5c8f9b0b86..1c2b856f8a 100644 --- a/android/app/src/main/res/values-zh-rCN/strings.xml +++ b/android/app/src/main/res/values-zh-rCN/strings.xml @@ -17,6 +17,7 @@ <string name="auth_failed">无法验证帐户。请发送问题报告。</string> <string name="auto_connect">自动连接</string> <string name="auto_connect_footer">在应用启动时自动连接到服务器。</string> + <string name="automatic">自动</string> <string name="back">返回</string> <string name="block_ads_title">广告</string> <string name="block_adult_content_title">成人内容</string> @@ -107,6 +108,10 @@ <string name="no_matching_relay">没有与您的设置匹配的服务器,请尝试更改服务器或其他设置。</string> <string name="no_wireguard_key">缺少有效的 WireGuard 密钥。在“高级”设置下管理密钥。</string> <string name="not_blocking_internet">您的网络流量可能在泄露</string> + <string name="obfuscation_info">混淆将 WireGuard 流量隐藏在另一个协议中。它可用于帮助规避审查和其他类型的过滤,在这些过滤中,普通的 WireGuard 连接将被阻止。</string> + <string name="obfuscation_on_udp_over_tcp">开 (UDP-over-TCP)</string> + <string name="obfuscation_title">混淆</string> + <string name="off">关</string> <string name="out_address">外部</string> <string name="out_of_time">已没有时间</string> <string name="paid_until">到期时间</string> @@ -142,6 +147,7 @@ <string name="toggle_vpn">切换 VPN</string> <string name="try_again">重试</string> <string name="udp">UDP</string> + <string name="udp_over_tcp_port_info">UDP-over-TCP 混淆协议应连接到 VPN 服务器上的哪个 TCP 端口。</string> <string name="unsecured">未受保护</string> <string name="unsecured_connection">未受保护的连接</string> <string name="unsupported_version">不受支持的版本</string> diff --git a/android/app/src/main/res/values-zh-rTW/strings.xml b/android/app/src/main/res/values-zh-rTW/strings.xml index 2b9046e1a9..12a9ae98e5 100644 --- a/android/app/src/main/res/values-zh-rTW/strings.xml +++ b/android/app/src/main/res/values-zh-rTW/strings.xml @@ -17,6 +17,7 @@ <string name="auth_failed">無法驗證帳戶。請傳送問題回報。</string> <string name="auto_connect">自動連線</string> <string name="auto_connect_footer">啟動應用程式時,自動連線伺服器。</string> + <string name="automatic">自動</string> <string name="back">返回</string> <string name="block_ads_title">廣告</string> <string name="block_adult_content_title">成人內容</string> @@ -107,6 +108,10 @@ <string name="no_matching_relay">沒有與您的設定相符的伺服器,請嘗試變更伺服器或其他設定。</string> <string name="no_wireguard_key">缺少有效的 WireGuard 金鑰。在「進階」設定下管理金鑰。</string> <string name="not_blocking_internet">您的網路流量可能正在洩露</string> + <string name="obfuscation_info">藉由混淆,WireGuard 的流量能隱藏在另一個通訊協定中。這有助於規避審查或其他類型的篩選。在這類篩選中,普通 WireGuard 連線將遭到封鎖。</string> + <string name="obfuscation_on_udp_over_tcp">開 (UDP-over-TCP)</string> + <string name="obfuscation_title">混淆</string> + <string name="off">關閉</string> <string name="out_address">出境</string> <string name="out_of_time">逾時</string> <string name="paid_until">支付至</string> @@ -142,6 +147,7 @@ <string name="toggle_vpn">切換 VPN</string> <string name="try_again">再試一次</string> <string name="udp">UDP</string> + <string name="udp_over_tcp_port_info">UDP-over-TCP 混淆通訊協定應連線到 VPN 伺服器上的哪個 TCP 連接埠。</string> <string name="unsecured">不安全</string> <string name="unsecured_connection">不安全的連線</string> <string name="unsupported_version">不支援的版本</string> diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml index d007411148..3c91b34b9c 100644 --- a/android/app/src/main/res/values/strings.xml +++ b/android/app/src/main/res/values/strings.xml @@ -187,4 +187,10 @@ <string name="settings_changes_effect_warning_short">DNS settings might not go into effect immediately</string> <string name="settings_changes_effect_warning_content_blocker">Changes to DNS related settings might not go into effect immediately due to cached results.</string> <string name="manage_account">Manage account</string> + <string name="obfuscation_title">Obfuscation</string> + <string name="obfuscation_info">Obfuscation hides the WireGuard traffic inside another protocol. It can be used to help circumvent censorship and other types of filtering, where a plain WireGuard connect would be blocked.</string> + <string name="obfuscation_on_udp_over_tcp">On (UDP-over-TCP)</string> + <string name="automatic">Automatic</string> + <string name="off">Off</string> + <string name="udp_over_tcp_port_info">Which TCP port the UDP-over-TCP obfuscation protocol should connect to on the VPN server.</string> </resources> diff --git a/mullvad-jni/src/classes.rs b/mullvad-jni/src/classes.rs index 32123ebb07..eea0dd6544 100644 --- a/mullvad-jni/src/classes.rs +++ b/mullvad-jni/src/classes.rs @@ -28,6 +28,7 @@ pub const CLASSES: &[&str] = &[ "net/mullvad/mullvadvpn/model/LocationConstraint$City", "net/mullvad/mullvadvpn/model/LocationConstraint$Country", "net/mullvad/mullvadvpn/model/LocationConstraint$Hostname", + "net/mullvad/mullvadvpn/model/ObfuscationSettings", "net/mullvad/mullvadvpn/model/PublicKey", "net/mullvad/mullvadvpn/model/Relay", "net/mullvad/mullvadvpn/model/RelayConstraints", @@ -42,12 +43,14 @@ pub const CLASSES: &[&str] = &[ "net/mullvad/mullvadvpn/model/RelaySettingsUpdate$CustomTunnelEndpoint", "net/mullvad/mullvadvpn/model/RelaySettingsUpdate$Normal", "net/mullvad/mullvadvpn/model/RelayConstraintsUpdate", + "net/mullvad/mullvadvpn/model/SelectedObfuscation", "net/mullvad/mullvadvpn/model/Settings", "net/mullvad/mullvadvpn/model/TunnelState$Error", "net/mullvad/mullvadvpn/model/TunnelState$Connected", "net/mullvad/mullvadvpn/model/TunnelState$Connecting", "net/mullvad/mullvadvpn/model/TunnelState$Disconnected", "net/mullvad/mullvadvpn/model/TunnelState$Disconnecting", + "net/mullvad/mullvadvpn/model/Udp2TcpObfuscationSettings", "net/mullvad/mullvadvpn/model/VoucherSubmission", "net/mullvad/mullvadvpn/model/VoucherSubmissionResult", "net/mullvad/mullvadvpn/model/LoginResult", @@ -57,6 +60,8 @@ pub const CLASSES: &[&str] = &[ "net/mullvad/talpid/net/Endpoint", "net/mullvad/talpid/net/TransportProtocol", "net/mullvad/talpid/net/TunnelEndpoint", + "net/mullvad/talpid/net/ObfuscationEndpoint", + "net/mullvad/talpid/net/ObfuscationType", "net/mullvad/talpid/tun_provider/InetNetwork", "net/mullvad/talpid/tun_provider/TunConfig", "net/mullvad/talpid/tunnel/ActionAfterDisconnect", diff --git a/mullvad-jni/src/daemon_interface.rs b/mullvad-jni/src/daemon_interface.rs index a9406a5507..ca4c27fb25 100644 --- a/mullvad-jni/src/daemon_interface.rs +++ b/mullvad-jni/src/daemon_interface.rs @@ -4,7 +4,7 @@ use mullvad_types::{ account::{AccountData, AccountToken, VoucherSubmission}, device::{Device, DeviceState}, location::GeoIpLocation, - relay_constraints::RelaySettingsUpdate, + relay_constraints::{ObfuscationSettings, RelaySettingsUpdate}, relay_list::RelayList, settings::{DnsOptions, Settings}, states::{TargetState, TunnelState}, @@ -316,6 +316,16 @@ impl DaemonInterface { .map_err(|_| Error::SettingsError) } + pub fn set_obfuscation_settings(&self, settings: ObfuscationSettings) -> Result<()> { + let (tx, rx) = oneshot::channel(); + + self.send_command(DaemonCommand::SetObfuscationSettings(tx, settings))?; + + block_on(rx) + .map_err(|_| Error::NoResponse)? + .map_err(|_| Error::SettingsError) + } + fn send_command(&self, command: DaemonCommand) -> Result<()> { self.command_sender.send(command).map_err(Error::NoDaemon) } diff --git a/mullvad-jni/src/lib.rs b/mullvad-jni/src/lib.rs index 370959c4e5..35db9a6766 100644 --- a/mullvad-jni/src/lib.rs +++ b/mullvad-jni/src/lib.rs @@ -1182,6 +1182,28 @@ pub extern "system" fn Java_net_mullvad_mullvadvpn_service_MullvadDaemon_updateR } } +#[no_mangle] +#[allow(non_snake_case)] +pub extern "system" fn Java_net_mullvad_mullvadvpn_service_MullvadDaemon_setObfuscationSettings( + env: JNIEnv<'_>, + _: JObject<'_>, + daemon_interface_address: jlong, + obfuscationSettings: JObject<'_>, +) { + let env = JnixEnv::from(env); + + if let Some(daemon_interface) = get_daemon_interface(daemon_interface_address) { + let settings = FromJava::from_java(&env, obfuscationSettings); + + if let Err(error) = daemon_interface.set_obfuscation_settings(settings) { + log::error!( + "{}", + error.display_chain_with_msg("Failed to update obfuscation settings") + ); + } + } +} + fn log_request_error(request: &str, error: &daemon_interface::Error) { match error { daemon_interface::Error::RpcError(RestError::Aborted) => { diff --git a/mullvad-types/src/relay_constraints.rs b/mullvad-types/src/relay_constraints.rs index 9d896a46c7..8f91ffab52 100644 --- a/mullvad-types/src/relay_constraints.rs +++ b/mullvad-types/src/relay_constraints.rs @@ -7,7 +7,7 @@ use crate::{ CustomTunnelEndpoint, }; #[cfg(target_os = "android")] -use jnix::{FromJava, IntoJava}; +use jnix::{jni::objects::JObject, FromJava, IntoJava, JnixEnv}; use serde::{Deserialize, Serialize}; use std::{collections::HashSet, fmt, str::FromStr}; use talpid_types::net::{openvpn::ProxySettings, IpVersion, TransportProtocol, TunnelType}; @@ -580,6 +580,8 @@ pub enum BridgeSettings { } #[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Deserialize, Serialize)] +#[cfg_attr(target_os = "android", derive(FromJava, IntoJava))] +#[cfg_attr(target_os = "android", jnix(package = "net.mullvad.mullvadvpn.model"))] #[serde(rename_all = "snake_case")] #[cfg_attr(feature = "clap", derive(clap::ValueEnum))] pub enum SelectedObfuscation { @@ -600,11 +602,44 @@ impl fmt::Display for SelectedObfuscation { } #[derive(Default, Debug, Clone, Eq, PartialEq, Deserialize, Serialize)] +#[cfg_attr(target_os = "android", derive(IntoJava))] +#[cfg_attr(target_os = "android", jnix(package = "net.mullvad.mullvadvpn.model"))] #[serde(rename_all = "snake_case")] pub struct Udp2TcpObfuscationSettings { + #[cfg_attr( + target_os = "android", + jnix(map = "|constraint| constraint.map(|v| v as i32)") + )] pub port: Constraint<u16>, } +#[cfg(target_os = "android")] +impl<'env, 'sub_env> FromJava<'env, JObject<'sub_env>> for Udp2TcpObfuscationSettings +where + 'env: 'sub_env, +{ + const JNI_SIGNATURE: &'static str = "Lnet/mullvad/mullvadvpn/model/Udp2TcpObfuscationSettings;"; + + fn from_java(env: &JnixEnv<'env>, object: JObject<'sub_env>) -> Self { + let object = env + .call_method( + object, + "component1", + "()Lnet/mullvad/mullvadvpn/model/Constraint;", + &[], + ) + .expect("missing Udp2TcpObfuscationSettings.port") + .l() + .expect("Udp2TcpObfuscationSettings.port did not return an object"); + + let port: Constraint<i32> = Constraint::from_java(env, object); + + Udp2TcpObfuscationSettings { + port: port.map(|port| port as u16), + } + } +} + impl fmt::Display for Udp2TcpObfuscationSettings { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.port { @@ -616,6 +651,8 @@ impl fmt::Display for Udp2TcpObfuscationSettings { /// Contains obfuscation settings #[derive(Default, Debug, Clone, Eq, PartialEq, Deserialize, Serialize)] +#[cfg_attr(target_os = "android", derive(FromJava, IntoJava))] +#[cfg_attr(target_os = "android", jnix(package = "net.mullvad.mullvadvpn.model"))] #[serde(rename_all = "snake_case")] #[serde(default)] pub struct ObfuscationSettings { diff --git a/mullvad-types/src/settings/mod.rs b/mullvad-types/src/settings/mod.rs index 80891ea970..ec4adb109a 100644 --- a/mullvad-types/src/settings/mod.rs +++ b/mullvad-types/src/settings/mod.rs @@ -68,7 +68,6 @@ pub struct Settings { pub relay_settings: RelaySettings, #[cfg_attr(target_os = "android", jnix(skip))] pub bridge_settings: BridgeSettings, - #[cfg_attr(target_os = "android", jnix(skip))] pub obfuscation_settings: ObfuscationSettings, #[cfg_attr(target_os = "android", jnix(skip))] pub bridge_state: BridgeState, diff --git a/talpid-types/src/net/mod.rs b/talpid-types/src/net/mod.rs index 910c1f168e..3daff6bae2 100644 --- a/talpid-types/src/net/mod.rs +++ b/talpid-types/src/net/mod.rs @@ -156,7 +156,6 @@ pub struct TunnelEndpoint { pub quantum_resistant: bool, #[cfg_attr(target_os = "android", jnix(skip))] pub proxy: Option<proxy::ProxyEndpoint>, - #[cfg_attr(target_os = "android", jnix(skip))] pub obfuscation: Option<ObfuscationEndpoint>, #[cfg_attr(target_os = "android", jnix(skip))] pub entry_endpoint: Option<Endpoint>, @@ -190,6 +189,8 @@ impl fmt::Display for TunnelEndpoint { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] #[serde(rename = "obfuscation_type")] +#[cfg_attr(target_os = "android", derive(IntoJava))] +#[cfg_attr(target_os = "android", jnix(package = "net.mullvad.talpid.net"))] pub enum ObfuscationType { #[serde(rename = "udp2tcp")] Udp2Tcp, @@ -205,6 +206,8 @@ impl fmt::Display for ObfuscationType { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] #[serde(rename = "obfuscation_endpoint")] +#[cfg_attr(target_os = "android", derive(IntoJava))] +#[cfg_attr(target_os = "android", jnix(package = "net.mullvad.talpid.net"))] pub struct ObfuscationEndpoint { pub endpoint: Endpoint, pub obfuscation_type: ObfuscationType, |
