summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorEmīls <emils@mullvad.net>2019-12-09 11:24:37 +0000
committerEmīls <emils@mullvad.net>2019-12-09 11:24:37 +0000
commitbe89341733b58f2e992141fe99713e4d6e4ba7fd (patch)
tree5c5c7413fab96d3c874cc882b7f80e253892cef0
parent345bebcf9cd75dc29328b1355c2feacbf7b65aad (diff)
parent3a041298b1433ec8b81656d77bc2379978af2691 (diff)
downloadmullvadvpn-be89341733b58f2e992141fe99713e4d6e4ba7fd.tar.xz
mullvadvpn-be89341733b58f2e992141fe99713e4d6e4ba7fd.zip
Merge branch 'add-error-state'
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/ConnectActionButton.kt4
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/ConnectionStatus.kt12
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/ForegroundNotificationManager.kt13
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/HeaderBar.kt8
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/NotificationBanner.kt39
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/SwitchLocationButton.kt2
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/WireguardKeyFragment.kt4
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/dataproxy/LocationInfoCache.kt2
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/model/TunnelState.kt4
-rw-r--r--android/src/main/kotlin/net/mullvad/talpid/tunnel/BlockReason.kt12
-rw-r--r--android/src/main/kotlin/net/mullvad/talpid/tunnel/ErrorState.kt3
-rw-r--r--android/src/main/kotlin/net/mullvad/talpid/tunnel/ErrorStateCause.kt12
-rw-r--r--android/src/main/res/values/strings.xml2
-rw-r--r--gui/src/main/daemon-rpc.ts55
-rw-r--r--gui/src/main/index.ts12
-rw-r--r--gui/src/main/notification-controller.ts21
-rw-r--r--gui/src/renderer/app.tsx8
-rw-r--r--gui/src/renderer/components/Connect.tsx14
-rw-r--r--gui/src/renderer/components/NotificationArea.tsx31
-rw-r--r--gui/src/renderer/components/TunnelControl.tsx15
-rw-r--r--gui/src/renderer/redux/connection/actions.ts12
-rw-r--r--gui/src/renderer/redux/connection/reducers.ts7
-rw-r--r--gui/src/shared/daemon-rpc-types.ts9
-rw-r--r--gui/test/components/NotificationArea.spec.tsx9
-rw-r--r--mullvad-cli/src/cmds/status.rs21
-rw-r--r--mullvad-daemon/src/lib.rs26
-rw-r--r--mullvad-jni/src/classes.rs19
-rw-r--r--mullvad-types/src/states.rs10
-rw-r--r--talpid-core/src/tunnel_state_machine/connected_state.rs18
-rw-r--r--talpid-core/src/tunnel_state_machine/connecting_state.rs36
-rw-r--r--talpid-core/src/tunnel_state_machine/disconnected_state.rs6
-rw-r--r--talpid-core/src/tunnel_state_machine/disconnecting_state.rs20
-rw-r--r--talpid-core/src/tunnel_state_machine/error_state.rs (renamed from talpid-core/src/tunnel_state_machine/blocked_state.rs)45
-rw-r--r--talpid-core/src/tunnel_state_machine/mod.rs12
-rw-r--r--talpid-types/src/tunnel.rs41
35 files changed, 323 insertions, 241 deletions
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/ConnectActionButton.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/ConnectActionButton.kt
index 4789d27a2c..cdaa302a71 100644
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/ConnectActionButton.kt
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/ConnectActionButton.kt
@@ -26,7 +26,7 @@ class ConnectActionButton(val parentView: View) {
}
is TunnelState.Connecting -> connecting()
is TunnelState.Connected -> connected()
- is TunnelState.Blocked -> connected()
+ is TunnelState.Error -> connected()
}
field = value
@@ -46,7 +46,7 @@ class ConnectActionButton(val parentView: View) {
is TunnelState.Disconnecting -> onConnect?.invoke()
is TunnelState.Connecting -> onCancel?.invoke()
is TunnelState.Connected -> onDisconnect?.invoke()
- is TunnelState.Blocked -> onDisconnect?.invoke()
+ is TunnelState.Error -> onDisconnect?.invoke()
}
}
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/ConnectionStatus.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/ConnectionStatus.kt
index 664156dd04..8fd95fab1f 100644
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/ConnectionStatus.kt
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/ConnectionStatus.kt
@@ -26,7 +26,7 @@ class ConnectionStatus(val parentView: View, val resources: Resources) {
is TunnelState.Disconnected -> disconnected()
is TunnelState.Connecting -> connecting()
is TunnelState.Connected -> connected()
- is TunnelState.Blocked -> blocked()
+ is TunnelState.Error -> errorState(state.errorState.isBlocking)
}
}
@@ -51,10 +51,16 @@ class ConnectionStatus(val parentView: View, val resources: Resources) {
text.setText(R.string.secure_connection)
}
- private fun blocked() {
+ private fun errorState(isBlocking: Boolean) {
spinner.visibility = View.GONE
+ // TODO: revise how to best inform the user about us not blocking
+ // traffic
text.setTextColor(securedTextColor)
- text.setText(R.string.blocked_connection)
+ if (isBlocking) {
+ text.setText(R.string.blocked_connection)
+ } else {
+ text.setText(R.string.blocked_connection)
+ }
}
}
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/ForegroundNotificationManager.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/ForegroundNotificationManager.kt
index 80890e56ca..e7c3886873 100644
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/ForegroundNotificationManager.kt
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/ForegroundNotificationManager.kt
@@ -66,7 +66,14 @@ class ForegroundNotificationManager(val service: Service, val connectionProxy: C
else -> R.string.disconnecting
}
}
- is TunnelState.Blocked -> R.string.blocking_all_connections
+ is TunnelState.Error -> {
+ if (state.errorState.isBlocking) {
+ R.string.blocking_all_connections
+ } else {
+ // TODO Revise use of message when the app fails to block traffic
+ R.string.unsecured
+ }
+ }
}
}
@@ -84,7 +91,7 @@ class ForegroundNotificationManager(val service: Service, val connectionProxy: C
else -> R.string.connect
}
}
- is TunnelState.Blocked -> R.string.disconnect
+ is TunnelState.Error -> R.string.disconnect
}
}
@@ -102,7 +109,7 @@ class ForegroundNotificationManager(val service: Service, val connectionProxy: C
else -> KEY_CONNECT_ACTION
}
}
- is TunnelState.Blocked -> KEY_DISCONNECT_ACTION
+ is TunnelState.Error -> KEY_DISCONNECT_ACTION
}
}
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/HeaderBar.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/HeaderBar.kt
index b89b13e08a..38022e1ef2 100644
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/HeaderBar.kt
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/HeaderBar.kt
@@ -16,7 +16,13 @@ class HeaderBar(val parentView: View, val resources: Resources) {
is TunnelState.Connecting -> secured()
is TunnelState.Connected -> secured()
is TunnelState.Disconnecting -> secured()
- is TunnelState.Blocked -> secured()
+ is TunnelState.Error -> {
+ if (state.errorState.isBlocking) {
+ secured()
+ } else {
+ unsecured()
+ }
+ }
}
}
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/NotificationBanner.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/NotificationBanner.kt
index c5cd816ce2..77133f929d 100644
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/NotificationBanner.kt
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/NotificationBanner.kt
@@ -16,7 +16,8 @@ import net.mullvad.mullvadvpn.dataproxy.WwwAuthTokenRetriever
import net.mullvad.mullvadvpn.model.KeygenEvent
import net.mullvad.mullvadvpn.model.TunnelState
import net.mullvad.talpid.tunnel.ActionAfterDisconnect
-import net.mullvad.talpid.tunnel.BlockReason
+import net.mullvad.talpid.tunnel.ErrorState
+import net.mullvad.talpid.tunnel.ErrorStateCause
import net.mullvad.talpid.tunnel.ParameterGenerationError
class NotificationBanner(
@@ -132,7 +133,7 @@ class NotificationBanner(
is TunnelState.Disconnected -> return false
is TunnelState.Connecting -> showBlocking(null)
is TunnelState.Connected -> return false
- is TunnelState.Blocked -> showBlocking(state.reason)
+ is TunnelState.Error -> showBlocking(state.errorState)
}
return true
@@ -167,18 +168,20 @@ class NotificationBanner(
return true
}
- private fun showBlocking(reason: BlockReason?) {
- val messageText = when (reason) {
+ private fun showBlocking(errorState: ErrorState?) {
+ val cause = errorState?.cause
+
+ val messageText = when (cause) {
null -> null
- is BlockReason.AuthFailed -> R.string.auth_failed
- is BlockReason.Ipv6Unavailable -> R.string.ipv6_unavailable
- is BlockReason.SetFirewallPolicyError -> R.string.set_firewall_policy_error
- is BlockReason.SetDnsError -> R.string.set_dns_error
- is BlockReason.StartTunnelError -> R.string.start_tunnel_error
- is BlockReason.IsOffline -> R.string.is_offline
- is BlockReason.TapAdapterProblem -> R.string.tap_adapter_problem
- is BlockReason.TunnelParameterError -> {
- when (reason.error) {
+ is ErrorStateCause.AuthFailed -> R.string.auth_failed
+ is ErrorStateCause.Ipv6Unavailable -> R.string.ipv6_unavailable
+ is ErrorStateCause.SetFirewallPolicyError -> R.string.set_firewall_policy_error
+ is ErrorStateCause.SetDnsError -> R.string.set_dns_error
+ is ErrorStateCause.StartTunnelError -> R.string.start_tunnel_error
+ is ErrorStateCause.IsOffline -> R.string.is_offline
+ is ErrorStateCause.TapAdapterProblem -> R.string.tap_adapter_problem
+ is ErrorStateCause.TunnelParameterError -> {
+ when (cause.error) {
ParameterGenerationError.NoMatchingRelay -> R.string.no_matching_relay
ParameterGenerationError.NoMatchingBridgeRelay -> {
R.string.no_matching_bridge_relay
@@ -190,7 +193,15 @@ class NotificationBanner(
}
}
}
- showError(R.string.blocking_internet, messageText)
+
+ // if the error state is null, we can assume that we are secure
+ val blockMessage = if (errorState?.isBlocking ?: true) {
+ R.string.blocking_internet
+ } else {
+ R.string.not_blocking_internet
+ }
+
+ showError(blockMessage, messageText)
}
private fun showError(titleText: Int, messageText: Int?) {
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/SwitchLocationButton.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/SwitchLocationButton.kt
index 930c1ff626..581fae4772 100644
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/SwitchLocationButton.kt
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/SwitchLocationButton.kt
@@ -64,7 +64,7 @@ class SwitchLocationButton(val parentView: View, val resources: Resources) {
}
is TunnelState.Connecting -> showLabel()
is TunnelState.Connected -> showLabel()
- is TunnelState.Blocked -> showLocation()
+ is TunnelState.Error -> showLocation()
}
}
}
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/WireguardKeyFragment.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/WireguardKeyFragment.kt
index 11f27d2b53..c0237fa7d6 100644
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/WireguardKeyFragment.kt
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/WireguardKeyFragment.kt
@@ -91,7 +91,7 @@ class WireguardKeyFragment : Fragment() {
urlController = BlockingController(
object : BlockableView {
override fun setEnabled(enabled: Boolean) {
- if (!enabled || tunnelState is TunnelState.Blocked) {
+ if (!enabled || tunnelState is TunnelState.Error) {
visitWebsiteView.setClickable(false)
visitWebsiteView.setAlpha(0.5f)
} else {
@@ -251,7 +251,7 @@ class WireguardKeyFragment : Fragment() {
verifyButton.visibility = View.GONE
verifySpinner.visibility = View.VISIBLE
}
- is TunnelState.Blocked -> {
+ is TunnelState.Error -> {
statusMessage.setText(R.string.wireguard_key_blocked_state_message)
statusMessage.visibility = View.VISIBLE
generateButton.setClickable(false)
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/dataproxy/LocationInfoCache.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/dataproxy/LocationInfoCache.kt
index 9c9e339541..41fb1ccbf3 100644
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/dataproxy/LocationInfoCache.kt
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/dataproxy/LocationInfoCache.kt
@@ -64,7 +64,7 @@ class LocationInfoCache(
ActionAfterDisconnect.Reconnect -> location = locationFromSelectedRelay()
}
}
- is TunnelState.Blocked -> location = null
+ is TunnelState.Error -> location = null
}
}
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/model/TunnelState.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/model/TunnelState.kt
index 040c4997c9..556517720d 100644
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/model/TunnelState.kt
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/model/TunnelState.kt
@@ -2,12 +2,12 @@ package net.mullvad.mullvadvpn.model
import net.mullvad.talpid.net.TunnelEndpoint
import net.mullvad.talpid.tunnel.ActionAfterDisconnect
-import net.mullvad.talpid.tunnel.BlockReason
+import net.mullvad.talpid.tunnel.ErrorState
sealed class TunnelState() {
class Disconnected() : TunnelState()
class Connecting(val endpoint: TunnelEndpoint?, val location: GeoIpLocation?) : TunnelState()
class Connected(val endpoint: TunnelEndpoint, val location: GeoIpLocation?) : TunnelState()
class Disconnecting(val actionAfterDisconnect: ActionAfterDisconnect) : TunnelState()
- class Blocked(val reason: BlockReason) : TunnelState()
+ class Error(val errorState: ErrorState) : TunnelState()
}
diff --git a/android/src/main/kotlin/net/mullvad/talpid/tunnel/BlockReason.kt b/android/src/main/kotlin/net/mullvad/talpid/tunnel/BlockReason.kt
deleted file mode 100644
index bed6177fb0..0000000000
--- a/android/src/main/kotlin/net/mullvad/talpid/tunnel/BlockReason.kt
+++ /dev/null
@@ -1,12 +0,0 @@
-package net.mullvad.talpid.tunnel
-
-sealed class BlockReason {
- class AuthFailed(val reason: String?) : BlockReason()
- class Ipv6Unavailable : BlockReason()
- class SetFirewallPolicyError : BlockReason()
- class SetDnsError : BlockReason()
- class StartTunnelError : BlockReason()
- class TunnelParameterError(val error: ParameterGenerationError) : BlockReason()
- class IsOffline : BlockReason()
- class TapAdapterProblem : BlockReason()
-}
diff --git a/android/src/main/kotlin/net/mullvad/talpid/tunnel/ErrorState.kt b/android/src/main/kotlin/net/mullvad/talpid/tunnel/ErrorState.kt
new file mode 100644
index 0000000000..c88a932887
--- /dev/null
+++ b/android/src/main/kotlin/net/mullvad/talpid/tunnel/ErrorState.kt
@@ -0,0 +1,3 @@
+package net.mullvad.talpid.tunnel
+
+data class ErrorState(val cause: ErrorStateCause, val isBlocking: Boolean)
diff --git a/android/src/main/kotlin/net/mullvad/talpid/tunnel/ErrorStateCause.kt b/android/src/main/kotlin/net/mullvad/talpid/tunnel/ErrorStateCause.kt
new file mode 100644
index 0000000000..e289b59551
--- /dev/null
+++ b/android/src/main/kotlin/net/mullvad/talpid/tunnel/ErrorStateCause.kt
@@ -0,0 +1,12 @@
+package net.mullvad.talpid.tunnel
+
+sealed class ErrorStateCause {
+ class AuthFailed(val reason: String?) : ErrorStateCause()
+ class Ipv6Unavailable : ErrorStateCause()
+ class SetFirewallPolicyError : ErrorStateCause()
+ class SetDnsError : ErrorStateCause()
+ class StartTunnelError : ErrorStateCause()
+ class TunnelParameterError(val error: ParameterGenerationError) : ErrorStateCause()
+ class IsOffline : ErrorStateCause()
+ class TapAdapterProblem : ErrorStateCause()
+}
diff --git a/android/src/main/res/values/strings.xml b/android/src/main/res/values/strings.xml
index 02064541a1..d019f68b17 100644
--- a/android/src/main/res/values/strings.xml
+++ b/android/src/main/res/values/strings.xml
@@ -70,6 +70,7 @@
<string name="creating_secure_connection">Creating secure connection</string>
<string name="secure_connection">Secure connection</string>
<string name="blocked_connection">Blocked connection</string>
+ <string name="error_state">Failed to secure connection</string>
<string name="connect">Secure my connection</string>
<string name="cancel">Cancel</string>
<string name="disconnect">Disconnect</string>
@@ -81,6 +82,7 @@
<string name="out_address">Out %1$s</string>
<string name="blocking_internet">Blocking internet</string>
+ <string name="not_blocking_internet">Failed to block internet</string>
<string name="auth_failed">Account authentication failed.</string>
<string name="ipv6_unavailable">Could not configure IPv6</string>
<string name="set_firewall_policy_error">
diff --git a/gui/src/main/daemon-rpc.ts b/gui/src/main/daemon-rpc.ts
index 5fcc9171e0..78748b70ab 100644
--- a/gui/src/main/daemon-rpc.ts
+++ b/gui/src/main/daemon-rpc.ts
@@ -251,32 +251,35 @@ const tunnelStateSchema = oneOf(
}),
}),
object({
- state: enumeration('blocked'),
- details: oneOf(
- object({
- reason: enumeration(
- 'ipv6_unavailable',
- 'set_firewall_policy_error',
- 'set_dns_error',
- 'start_tunnel_error',
- 'is_offline',
- 'tap_adapter_problem',
- ),
- }),
- object({
- reason: enumeration('auth_failed'),
- details: maybe(string),
- }),
- object({
- reason: enumeration('tunnel_parameter_error'),
- details: enumeration(
- 'no_matching_relay',
- 'no_matching_bridge_relay',
- 'no_wireguard_key',
- 'custom_tunnel_host_resultion_error',
- ),
- }),
- ),
+ state: enumeration('error'),
+ details: object({
+ is_blocking: boolean,
+ cause: oneOf(
+ object({
+ reason: enumeration(
+ 'ipv6_unavailable',
+ 'set_firewall_policy_error',
+ 'set_dns_error',
+ 'start_tunnel_error',
+ 'is_offline',
+ 'tap_adapter_problem',
+ ),
+ }),
+ object({
+ reason: enumeration('auth_failed'),
+ details: maybe(string),
+ }),
+ object({
+ reason: enumeration('tunnel_parameter_error'),
+ details: enumeration(
+ 'no_matching_relay',
+ 'no_matching_bridge_relay',
+ 'no_wireguard_key',
+ 'custom_tunnel_host_resultion_error',
+ ),
+ }),
+ ),
+ }),
}),
object({
state: enumeration('connected', 'connecting', 'disconnected'),
diff --git a/gui/src/main/index.ts b/gui/src/main/index.ts
index cba1caac5a..0ef641ec15 100644
--- a/gui/src/main/index.ts
+++ b/gui/src/main/index.ts
@@ -851,14 +851,12 @@ class ApplicationMain {
case 'connecting':
return 'securing';
- case 'blocked':
- switch (tunnelState.details.reason) {
- case 'set_firewall_policy_error':
- return 'unsecured';
- default:
- return 'securing';
+ case 'error':
+ if (tunnelState.details.isBlocking) {
+ return 'securing';
+ } else {
+ return 'unsecured';
}
-
case 'disconnecting':
return 'securing';
diff --git a/gui/src/main/notification-controller.ts b/gui/src/main/notification-controller.ts
index 515918f50c..99af3bcf45 100644
--- a/gui/src/main/notification-controller.ts
+++ b/gui/src/main/notification-controller.ts
@@ -75,18 +75,15 @@ export default class NotificationController {
case 'disconnected':
this.showTunnelStateNotification(messages.pgettext('notifications', 'Unsecured'));
break;
- case 'blocked':
- switch (tunnelState.details.reason) {
- case 'set_firewall_policy_error':
- this.showTunnelStateNotification(
- messages.pgettext('notifications', 'Critical failure - Unsecured'),
- );
- break;
- default:
- this.showTunnelStateNotification(
- messages.pgettext('notifications', 'Blocked all connections'),
- );
- break;
+ case 'error':
+ if (tunnelState.details.isBlocking) {
+ this.showTunnelStateNotification(
+ messages.pgettext('notifications', 'Blocked all connections'),
+ );
+ } else {
+ this.showTunnelStateNotification(
+ messages.pgettext('notifications', 'Critical failure - Unsecured'),
+ );
}
break;
case 'disconnecting':
diff --git a/gui/src/renderer/app.tsx b/gui/src/renderer/app.tsx
index ae906868a2..b3a1b257bd 100644
--- a/gui/src/renderer/app.tsx
+++ b/gui/src/renderer/app.tsx
@@ -264,7 +264,7 @@ export default class AppRenderer {
const state = this.tunnelState.state;
// connect only if tunnel is disconnected or blocked.
- if (state === 'disconnecting' || state === 'disconnected' || state === 'blocked') {
+ if (state === 'disconnecting' || state === 'disconnected' || state === 'error') {
// switch to the connecting state ahead of time to make the app look more responsive
this.reduxActions.connection.connecting();
@@ -549,7 +549,7 @@ export default class AppRenderer {
actions.connection.disconnected();
break;
- case 'blocked':
+ case 'error':
actions.connection.blocked(tunnelState.details);
break;
}
@@ -597,8 +597,8 @@ export default class AppRenderer {
actions.updateBlockState(true);
break;
- case 'blocked':
- actions.updateBlockState(tunnelState.details.reason !== 'set_firewall_policy_error');
+ case 'error':
+ actions.updateBlockState(tunnelState.details.isBlocking);
break;
}
}
diff --git a/gui/src/renderer/components/Connect.tsx b/gui/src/renderer/components/Connect.tsx
index e8d5c0e096..7f73fb7ea0 100644
--- a/gui/src/renderer/components/Connect.tsx
+++ b/gui/src/renderer/components/Connect.tsx
@@ -117,9 +117,9 @@ export default class Connect extends Component<IProps, IState> {
// Blocked with auth failure / expired account
if (
- tunnelState.state === 'blocked' &&
- tunnelState.details.reason === 'auth_failed' &&
- parseAuthFailure(tunnelState.details.details).kind === AuthFailureKind.expiredAccount
+ tunnelState.state === 'error' &&
+ tunnelState.details.cause.reason === 'auth_failed' &&
+ parseAuthFailure(tunnelState.details.cause.reason).kind === AuthFailureKind.expiredAccount
) {
return true;
}
@@ -200,8 +200,8 @@ export default class Connect extends Component<IProps, IState> {
case 'connecting':
case 'connected':
return HeaderBarStyle.success;
- case 'blocked':
- switch (status.details.reason) {
+ case 'error':
+ switch (status.details.cause.reason) {
case 'set_firewall_policy_error':
return HeaderBarStyle.error;
default:
@@ -259,8 +259,8 @@ export default class Connect extends Component<IProps, IState> {
case 'connecting':
case 'connected':
return MarkerStyle.secure;
- case 'blocked':
- switch (status.details.reason) {
+ case 'error':
+ switch (status.details.cause.reason) {
case 'set_firewall_policy_error':
return MarkerStyle.unsecure;
default:
diff --git a/gui/src/renderer/components/NotificationArea.tsx b/gui/src/renderer/components/NotificationArea.tsx
index 1d65306ef9..c459695a30 100644
--- a/gui/src/renderer/components/NotificationArea.tsx
+++ b/gui/src/renderer/components/NotificationArea.tsx
@@ -13,7 +13,7 @@ import {
NotificationTitle,
} from './NotificationBanner';
-import { BlockReason, TunnelParameterError, TunnelState } from '../../shared/daemon-rpc-types';
+import { ErrorStateCause, TunnelParameterError, TunnelState } from '../../shared/daemon-rpc-types';
import AccountExpiry from '../lib/account-expiry';
import { parseAuthFailure } from '../lib/auth-failure';
import { IVersionReduxState } from '../redux/version/reducers';
@@ -63,7 +63,7 @@ function getTunnelParameterMessage(err: TunnelParameterError): string {
}
}
-function getBlockReasonMessage(blockReason: BlockReason): string {
+function getErrorCauseMessage(blockReason: ErrorStateCause): string {
switch (blockReason.reason) {
case 'auth_failed':
return parseAuthFailure(blockReason.details).message;
@@ -124,20 +124,19 @@ export default class NotificationArea extends Component<IProps, State> {
reason: '',
};
- case 'blocked':
- switch (tunnelState.details.reason) {
- case 'set_firewall_policy_error':
- return {
- visible: true,
- type: 'failure-unsecured',
- reason: getBlockReasonMessage(tunnelState.details),
- };
- default:
- return {
- visible: true,
- type: 'blocking',
- reason: getBlockReasonMessage(tunnelState.details),
- };
+ case 'error':
+ if (tunnelState.details.isBlocking) {
+ return {
+ visible: true,
+ type: 'blocking',
+ reason: getErrorCauseMessage(tunnelState.details.cause),
+ };
+ } else {
+ return {
+ visible: true,
+ type: 'failure-unsecured',
+ reason: getErrorCauseMessage(tunnelState.details.cause),
+ };
}
case 'disconnecting':
diff --git a/gui/src/renderer/components/TunnelControl.tsx b/gui/src/renderer/components/TunnelControl.tsx
index 4acc2bd1ef..700603bd2e 100644
--- a/gui/src/renderer/components/TunnelControl.tsx
+++ b/gui/src/renderer/components/TunnelControl.tsx
@@ -115,21 +115,14 @@ export default class TunnelControl extends Component<ITunnelControlProps> {
let state = this.props.tunnelState.state;
switch (this.props.tunnelState.state) {
- case 'blocked':
- switch (this.props.tunnelState.details.reason) {
- case 'set_firewall_policy_error':
- state = 'disconnected';
- break;
- default:
- state = 'blocked';
- break;
- }
+ case 'error':
+ state = this.props.tunnelState.details.isBlocking ? 'error' : 'disconnected';
break;
case 'disconnecting':
switch (this.props.tunnelState.details) {
case 'block':
- state = 'blocked';
+ state = 'error';
break;
case 'reconnect':
state = 'connecting';
@@ -177,7 +170,7 @@ export default class TunnelControl extends Component<ITunnelControlProps> {
</Wrapper>
);
- case 'blocked':
+ case 'error':
return (
<Wrapper>
<Body>
diff --git a/gui/src/renderer/redux/connection/actions.ts b/gui/src/renderer/redux/connection/actions.ts
index 8f5b2e62bb..95d2332ed3 100644
--- a/gui/src/renderer/redux/connection/actions.ts
+++ b/gui/src/renderer/redux/connection/actions.ts
@@ -1,6 +1,6 @@
import {
AfterDisconnect,
- BlockReason,
+ IErrorState,
ILocation,
ITunnelStateRelayInfo,
} from '../../../shared/daemon-rpc-types';
@@ -25,8 +25,8 @@ interface IDisconnectingAction {
}
interface IBlockedAction {
- type: 'BLOCKED';
- reason: BlockReason;
+ type: 'TUNNEL_ERROR';
+ errorState: IErrorState;
}
interface INewLocationAction {
@@ -75,10 +75,10 @@ function disconnecting(afterDisconnect: AfterDisconnect): IDisconnectingAction {
};
}
-function blocked(reason: BlockReason): IBlockedAction {
+function blocked(errorState: IErrorState): IBlockedAction {
return {
- type: 'BLOCKED',
- reason,
+ type: 'TUNNEL_ERROR',
+ errorState,
};
}
diff --git a/gui/src/renderer/redux/connection/reducers.ts b/gui/src/renderer/redux/connection/reducers.ts
index 4772df8fc5..e7f2f0c2cf 100644
--- a/gui/src/renderer/redux/connection/reducers.ts
+++ b/gui/src/renderer/redux/connection/reducers.ts
@@ -62,10 +62,13 @@ export default function(
status: { state: 'disconnecting', details: action.afterDisconnect },
};
- case 'BLOCKED':
+ case 'TUNNEL_ERROR':
return {
...state,
- status: { state: 'blocked', details: action.reason },
+ status: {
+ state: 'error',
+ details: action.errorState,
+ },
};
default:
diff --git a/gui/src/shared/daemon-rpc-types.ts b/gui/src/shared/daemon-rpc-types.ts
index 7ce5e93111..404762d962 100644
--- a/gui/src/shared/daemon-rpc-types.ts
+++ b/gui/src/shared/daemon-rpc-types.ts
@@ -21,7 +21,7 @@ export type TunnelParameterError =
| 'no_wireguard_key'
| 'custom_tunnel_host_resultion_error';
-export type BlockReason =
+export type ErrorStateCause =
| {
reason:
| 'ipv6_unavailable'
@@ -99,7 +99,12 @@ export type TunnelState =
| { state: 'connecting'; details?: ITunnelStateRelayInfo }
| { state: 'connected'; details: ITunnelStateRelayInfo }
| { state: 'disconnecting'; details: AfterDisconnect }
- | { state: 'blocked'; details: BlockReason };
+ | { state: 'error'; details: IErrorState };
+
+export interface IErrorState {
+ isBlocking: boolean;
+ cause: ErrorStateCause;
+}
export type RelayLocation =
| { hostname: [string, string, string] }
diff --git a/gui/test/components/NotificationArea.spec.tsx b/gui/test/components/NotificationArea.spec.tsx
index 713c30faff..6aa7621724 100644
--- a/gui/test/components/NotificationArea.spec.tsx
+++ b/gui/test/components/NotificationArea.spec.tsx
@@ -145,10 +145,13 @@ describe('components/NotificationArea', () => {
const component = shallow(
<NotificationArea
tunnelState={{
- state: 'blocked',
+ state: 'error',
details: {
- reason: 'tunnel_parameter_error',
- details: 'no_matching_relay',
+ isBlocking: true,
+ cause: {
+ reason: 'tunnel_parameter_error',
+ details: 'no_matching_relay',
+ },
},
}}
version={defaultVersion}
diff --git a/mullvad-cli/src/cmds/status.rs b/mullvad-cli/src/cmds/status.rs
index bd68ae64ae..10834b60b3 100644
--- a/mullvad-cli/src/cmds/status.rs
+++ b/mullvad-cli/src/cmds/status.rs
@@ -2,7 +2,7 @@ use crate::{new_rpc_client, Command, Error, Result};
use futures::{Future, Stream};
use mullvad_ipc_client::DaemonRpcClient;
use mullvad_types::{auth_failed::AuthFailed, states::TunnelState, DaemonEvent};
-use talpid_types::tunnel::BlockReason;
+use talpid_types::tunnel::{ErrorState, ErrorStateCause};
pub struct Status;
@@ -91,7 +91,7 @@ fn print_state(state: &TunnelState) {
use self::TunnelState::*;
print!("Tunnel status: ");
match state {
- Blocked(reason) => print_blocked_reason(reason),
+ Error(reason) => print_error_state(reason),
Connected { endpoint, .. } => {
println!("Connected to {}", endpoint);
}
@@ -101,9 +101,18 @@ fn print_state(state: &TunnelState) {
}
}
-fn print_blocked_reason(reason: &BlockReason) {
+fn print_error_state(error_state: &ErrorState) {
+ if !error_state.is_blocking() {
+ eprintln!("Mullvad daemon failed to setup firewall rules!");
+ eprintln!("Deamon cannot block traffic from flowing, non-local traffic will leak");
+ }
+
+ print_blocked_reason(error_state.cause());
+}
+
+fn print_blocked_reason(reason: &ErrorStateCause) {
match reason {
- BlockReason::AuthFailed(ref auth_failure) => {
+ ErrorStateCause::AuthFailed(ref auth_failure) => {
let auth_failure_str = auth_failure
.as_ref()
.map(|s| s.as_str())
@@ -111,8 +120,8 @@ fn print_blocked_reason(reason: &BlockReason) {
println!("Blocked: {}", AuthFailed::from(auth_failure_str));
}
#[cfg(target_os = "linux")]
- BlockReason::SetFirewallPolicyError => {
- println!("Blocked: {}", BlockReason::SetFirewallPolicyError);
+ ErrorStateCause::SetFirewallPolicyError => {
+ println!("Blocked: {}", ErrorStateCause::SetFirewallPolicyError);
println!("Your kernel might be terribly out of date or missing nftables");
}
other => println!("Blocked: {}", other),
diff --git a/mullvad-daemon/src/lib.rs b/mullvad-daemon/src/lib.rs
index e78649ac63..aabcbb6952 100644
--- a/mullvad-daemon/src/lib.rs
+++ b/mullvad-daemon/src/lib.rs
@@ -64,7 +64,7 @@ use talpid_core::{
use talpid_types::android::AndroidContext;
use talpid_types::{
net::{openvpn, TransportProtocol, TunnelParameters},
- tunnel::{BlockReason, ParameterGenerationError, TunnelStateTransition},
+ tunnel::{ErrorStateCause, ParameterGenerationError, TunnelStateTransition},
ErrorExt,
};
@@ -565,7 +565,7 @@ where
TunnelStateTransition::Disconnecting(after_disconnect) => {
TunnelState::Disconnecting(after_disconnect)
}
- TunnelStateTransition::Blocked(reason) => TunnelState::Blocked(reason.clone()),
+ TunnelStateTransition::Error(error_state) => TunnelState::Error(error_state.clone()),
};
self.unschedule_reconnect();
@@ -573,10 +573,20 @@ where
debug!("New tunnel state: {:?}", tunnel_state);
match tunnel_state {
TunnelState::Disconnected => self.state.disconnected(),
- TunnelState::Blocked(ref reason) => {
- info!("Blocking all network connections, reason: {}", reason);
+ TunnelState::Error(ref error_state) => {
+ if error_state.is_blocking() {
+ info!(
+ "Blocking all network connections, reason: {}",
+ error_state.cause()
+ );
+ } else {
+ error!(
+ "FAILED TO BLOCK NETWORK CONNECTIONS, ENTERED ERROR STATE BECAUSE: {}",
+ error_state.cause()
+ );
+ }
- if let BlockReason::AuthFailed(_) = reason {
+ if let ErrorStateCause::AuthFailed(_) = error_state.cause() {
self.schedule_reconnect(Duration::from_secs(60))
}
}
@@ -925,7 +935,7 @@ where
}
fn on_reconnect(&mut self) {
- if self.target_state == TargetState::Secured || self.tunnel_state.is_blocked() {
+ if self.target_state == TargetState::Secured || self.tunnel_state.is_in_error_state() {
self.connect_tunnel();
} else {
debug!("Ignoring reconnect command. Currently not in secured state");
@@ -955,7 +965,7 @@ where
.map(Some),
)
}
- Blocked(..) => {
+ Error(..) => {
// We are not online at all at this stage so no location data is available.
Box::new(future::result(Ok(None)))
}
@@ -1485,7 +1495,7 @@ where
/// progress towards that state.
/// Returns an error if trying to set secured state, but no account token is present.
fn set_target_state(&mut self, new_state: TargetState) {
- if new_state != self.target_state || self.tunnel_state.is_blocked() {
+ if new_state != self.target_state || self.tunnel_state.is_in_error_state() {
debug!("Target state {:?} => {:?}", self.target_state, new_state);
self.target_state = new_state;
match self.target_state {
diff --git a/mullvad-jni/src/classes.rs b/mullvad-jni/src/classes.rs
index d2e37b0804..6669f2b403 100644
--- a/mullvad-jni/src/classes.rs
+++ b/mullvad-jni/src/classes.rs
@@ -30,7 +30,7 @@ pub const CLASSES: &[&str] = &[
"net/mullvad/mullvadvpn/model/RelaySettingsUpdate$RelayConstraintsUpdate",
"net/mullvad/mullvadvpn/model/RelayTunnels",
"net/mullvad/mullvadvpn/model/Settings",
- "net/mullvad/mullvadvpn/model/TunnelState$Blocked",
+ "net/mullvad/mullvadvpn/model/TunnelState$Error",
"net/mullvad/mullvadvpn/model/TunnelState$Connected",
"net/mullvad/mullvadvpn/model/TunnelState$Connecting",
"net/mullvad/mullvadvpn/model/TunnelState$Disconnected",
@@ -44,14 +44,15 @@ pub const CLASSES: &[&str] = &[
"net/mullvad/talpid/tun_provider/InetNetwork",
"net/mullvad/talpid/tun_provider/TunConfig",
"net/mullvad/talpid/tunnel/ActionAfterDisconnect",
- "net/mullvad/talpid/tunnel/BlockReason$AuthFailed",
- "net/mullvad/talpid/tunnel/BlockReason$Ipv6Unavailable",
- "net/mullvad/talpid/tunnel/BlockReason$SetFirewallPolicyError",
- "net/mullvad/talpid/tunnel/BlockReason$SetDnsError",
- "net/mullvad/talpid/tunnel/BlockReason$StartTunnelError",
- "net/mullvad/talpid/tunnel/BlockReason$TunnelParameterError",
- "net/mullvad/talpid/tunnel/BlockReason$IsOffline",
- "net/mullvad/talpid/tunnel/BlockReason$TapAdapterProblem",
+ "net/mullvad/talpid/tunnel/ErrorState",
+ "net/mullvad/talpid/tunnel/ErrorStateCause$AuthFailed",
+ "net/mullvad/talpid/tunnel/ErrorStateCause$Ipv6Unavailable",
+ "net/mullvad/talpid/tunnel/ErrorStateCause$SetFirewallPolicyError",
+ "net/mullvad/talpid/tunnel/ErrorStateCause$SetDnsError",
+ "net/mullvad/talpid/tunnel/ErrorStateCause$StartTunnelError",
+ "net/mullvad/talpid/tunnel/ErrorStateCause$TunnelParameterError",
+ "net/mullvad/talpid/tunnel/ErrorStateCause$IsOffline",
+ "net/mullvad/talpid/tunnel/ErrorStateCause$TapAdapterProblem",
"net/mullvad/talpid/tunnel/ParameterGenerationError",
"net/mullvad/talpid/ConnectivityListener",
"net/mullvad/talpid/TalpidVpnService",
diff --git a/mullvad-types/src/states.rs b/mullvad-types/src/states.rs
index e905f329c5..805210a7aa 100644
--- a/mullvad-types/src/states.rs
+++ b/mullvad-types/src/states.rs
@@ -4,7 +4,7 @@ use jnix::IntoJava;
use serde::{Deserialize, Serialize};
use talpid_types::{
net::TunnelEndpoint,
- tunnel::{ActionAfterDisconnect, BlockReason},
+ tunnel::{ActionAfterDisconnect, ErrorState},
};
/// Represents the state the client strives towards.
@@ -34,14 +34,14 @@ pub enum TunnelState {
location: Option<GeoIpLocation>,
},
Disconnecting(ActionAfterDisconnect),
- Blocked(BlockReason),
+ Error(ErrorState),
}
impl TunnelState {
- /// Returns true if the tunnel state is the blocked state.
- pub fn is_blocked(&self) -> bool {
+ /// Returns true if the tunnel state is in the error state.
+ pub fn is_in_error_state(&self) -> bool {
match self {
- TunnelState::Blocked(_) => true,
+ TunnelState::Error(_) => true,
_ => false,
}
}
diff --git a/talpid-core/src/tunnel_state_machine/connected_state.rs b/talpid-core/src/tunnel_state_machine/connected_state.rs
index fd26b20bc3..3ce80db030 100644
--- a/talpid-core/src/tunnel_state_machine/connected_state.rs
+++ b/talpid-core/src/tunnel_state_machine/connected_state.rs
@@ -1,5 +1,5 @@
use super::{
- AfterDisconnect, BlockedState, ConnectingState, DisconnectingState, EventConsequence,
+ AfterDisconnect, ConnectingState, DisconnectingState, ErrorState, EventConsequence,
SharedTunnelStateValues, TunnelCommand, TunnelState, TunnelStateTransition, TunnelStateWrapper,
};
use crate::{
@@ -12,7 +12,7 @@ use futures::{
};
use talpid_types::{
net::{Endpoint, TunnelParameters},
- tunnel::BlockReason,
+ tunnel::ErrorStateCause,
ErrorExt,
};
@@ -20,7 +20,7 @@ pub struct ConnectedStateBootstrap {
pub metadata: TunnelMetadata,
pub tunnel_events: mpsc::UnboundedReceiver<TunnelEvent>,
pub tunnel_parameters: TunnelParameters,
- pub tunnel_close_event: Option<oneshot::Receiver<Option<BlockReason>>>,
+ pub tunnel_close_event: Option<oneshot::Receiver<Option<ErrorStateCause>>>,
pub close_handle: Option<CloseHandle>,
}
@@ -29,7 +29,7 @@ pub struct ConnectedState {
metadata: TunnelMetadata,
tunnel_events: mpsc::UnboundedReceiver<TunnelEvent>,
tunnel_parameters: TunnelParameters,
- tunnel_close_event: Option<oneshot::Receiver<Option<BlockReason>>>,
+ tunnel_close_event: Option<oneshot::Receiver<Option<ErrorStateCause>>>,
close_handle: Option<CloseHandle>,
}
@@ -123,7 +123,7 @@ impl ConnectedState {
);
self.disconnect(
shared_values,
- AfterDisconnect::Block(BlockReason::SetFirewallPolicyError),
+ AfterDisconnect::Block(ErrorStateCause::SetFirewallPolicyError),
)
}
}
@@ -137,7 +137,7 @@ impl ConnectedState {
if is_offline {
self.disconnect(
shared_values,
- AfterDisconnect::Block(BlockReason::IsOffline),
+ AfterDisconnect::Block(ErrorStateCause::IsOffline),
)
} else {
SameState(self)
@@ -183,7 +183,7 @@ impl ConnectedState {
match poll_result {
Ok(Async::Ready(block_reason)) => {
if let Some(reason) = block_reason {
- return NewState(BlockedState::enter(shared_values, reason));
+ return NewState(ErrorState::enter(shared_values, reason));
}
}
Ok(Async::NotReady) => return NoEvents(self),
@@ -217,7 +217,7 @@ impl TunnelState for ConnectedState {
(
connected_state.close_handle,
connected_state.tunnel_close_event,
- AfterDisconnect::Block(BlockReason::SetFirewallPolicyError),
+ AfterDisconnect::Block(ErrorStateCause::SetFirewallPolicyError),
),
)
} else if let Err(error) = connected_state.set_dns(shared_values) {
@@ -230,7 +230,7 @@ impl TunnelState for ConnectedState {
(
connected_state.close_handle,
connected_state.tunnel_close_event,
- AfterDisconnect::Block(BlockReason::SetDnsError),
+ AfterDisconnect::Block(ErrorStateCause::SetDnsError),
),
)
} else {
diff --git a/talpid-core/src/tunnel_state_machine/connecting_state.rs b/talpid-core/src/tunnel_state_machine/connecting_state.rs
index 67036ea98e..01e39b0ebc 100644
--- a/talpid-core/src/tunnel_state_machine/connecting_state.rs
+++ b/talpid-core/src/tunnel_state_machine/connecting_state.rs
@@ -1,5 +1,5 @@
use super::{
- AfterDisconnect, BlockedState, ConnectedState, ConnectedStateBootstrap, DisconnectingState,
+ AfterDisconnect, ConnectedState, ConnectedStateBootstrap, DisconnectingState, ErrorState,
EventConsequence, SharedTunnelStateValues, TunnelCommand, TunnelState, TunnelStateTransition,
TunnelStateWrapper,
};
@@ -22,7 +22,7 @@ use std::{
};
use talpid_types::{
net::{openvpn, TunnelParameters},
- tunnel::BlockReason,
+ tunnel::ErrorStateCause,
ErrorExt,
};
@@ -34,7 +34,7 @@ const MIN_TUNNEL_ALIVE_TIME: Duration = Duration::from_millis(1000);
pub struct ConnectingState {
tunnel_events: mpsc::UnboundedReceiver<TunnelEvent>,
tunnel_parameters: TunnelParameters,
- tunnel_close_event: Option<oneshot::Receiver<Option<BlockReason>>>,
+ tunnel_close_event: Option<oneshot::Receiver<Option<ErrorStateCause>>>,
close_handle: Option<CloseHandle>,
retry_attempt: u32,
}
@@ -92,7 +92,7 @@ impl ConnectingState {
fn spawn_tunnel_monitor_wait_thread(
tunnel_monitor: TunnelMonitor,
- ) -> Option<oneshot::Receiver<Option<BlockReason>>> {
+ ) -> Option<oneshot::Receiver<Option<ErrorStateCause>>> {
let (tunnel_close_event_tx, tunnel_close_event_rx) = oneshot::channel();
thread::spawn(move || {
@@ -120,7 +120,7 @@ impl ConnectingState {
Some(tunnel_close_event_rx)
}
- fn wait_for_tunnel_monitor(tunnel_monitor: TunnelMonitor) -> Option<BlockReason> {
+ fn wait_for_tunnel_monitor(tunnel_monitor: TunnelMonitor) -> Option<ErrorStateCause> {
match tunnel_monitor.wait() {
Ok(_) => None,
Err(error) => match error {
@@ -135,7 +135,7 @@ impl ConnectingState {
"{}",
error.display_chain_with_msg("TAP adapter problem detected")
);
- Some(BlockReason::TapAdapterProblem)
+ Some(ErrorStateCause::TapAdapterProblem)
}
error => {
warn!(
@@ -183,7 +183,7 @@ impl ConnectingState {
(
self.close_handle,
self.tunnel_close_event,
- AfterDisconnect::Block(BlockReason::SetFirewallPolicyError),
+ AfterDisconnect::Block(ErrorStateCause::SetFirewallPolicyError),
),
))
}
@@ -201,7 +201,7 @@ impl ConnectingState {
(
self.close_handle,
self.tunnel_close_event,
- AfterDisconnect::Block(BlockReason::IsOffline),
+ AfterDisconnect::Block(ErrorStateCause::IsOffline),
),
))
} else {
@@ -248,7 +248,7 @@ impl ConnectingState {
(
self.close_handle,
self.tunnel_close_event,
- AfterDisconnect::Block(BlockReason::AuthFailed(reason)),
+ AfterDisconnect::Block(ErrorStateCause::AuthFailed(reason)),
),
)),
Ok(TunnelEvent::Up(metadata)) => NewState(ConnectedState::enter(
@@ -282,7 +282,7 @@ impl ConnectingState {
match poll_result {
Ok(Async::Ready(block_reason)) => {
if let Some(reason) = block_reason {
- return EventConsequence::NewState(BlockedState::enter(shared_values, reason));
+ return EventConsequence::NewState(ErrorState::enter(shared_values, reason));
}
}
Ok(Async::NotReady) => return EventConsequence::NoEvents(self),
@@ -333,13 +333,15 @@ impl TunnelState for ConnectingState {
retry_attempt: u32,
) -> (TunnelStateWrapper, TunnelStateTransition) {
if shared_values.is_offline {
- return BlockedState::enter(shared_values, BlockReason::IsOffline);
+ return ErrorState::enter(shared_values, ErrorStateCause::IsOffline);
}
match shared_values
.tunnel_parameters_generator
.generate(retry_attempt)
{
- Err(err) => BlockedState::enter(shared_values, BlockReason::TunnelParameterError(err)),
+ Err(err) => {
+ ErrorState::enter(shared_values, ErrorStateCause::TunnelParameterError(err))
+ }
Ok(tunnel_parameters) => {
if let Err(error) = Self::set_firewall_policy(shared_values, &tunnel_parameters) {
error!(
@@ -348,7 +350,7 @@ impl TunnelState for ConnectingState {
"Failed to apply firewall policy for connecting state"
)
);
- BlockedState::enter(shared_values, BlockReason::StartTunnelError)
+ ErrorState::enter(shared_values, ErrorStateCause::StartTunnelError)
} else {
#[cfg(target_os = "android")]
{
@@ -394,10 +396,12 @@ impl TunnelState for ConnectingState {
error.display_chain_with_msg("Failed to start tunnel")
);
let block_reason = match error {
- tunnel::Error::EnableIpv6Error => BlockReason::Ipv6Unavailable,
- _ => BlockReason::StartTunnelError,
+ tunnel::Error::EnableIpv6Error => {
+ ErrorStateCause::Ipv6Unavailable
+ }
+ _ => ErrorStateCause::StartTunnelError,
};
- BlockedState::enter(shared_values, block_reason)
+ ErrorState::enter(shared_values, block_reason)
}
}
}
diff --git a/talpid-core/src/tunnel_state_machine/disconnected_state.rs b/talpid-core/src/tunnel_state_machine/disconnected_state.rs
index 6b95548ddd..f183a7c78c 100644
--- a/talpid-core/src/tunnel_state_machine/disconnected_state.rs
+++ b/talpid-core/src/tunnel_state_machine/disconnected_state.rs
@@ -1,5 +1,5 @@
use super::{
- BlockedState, ConnectingState, EventConsequence, SharedTunnelStateValues, TunnelCommand,
+ ConnectingState, ErrorState, EventConsequence, SharedTunnelStateValues, TunnelCommand,
TunnelState, TunnelStateTransition, TunnelStateWrapper,
};
use crate::firewall::FirewallPolicy;
@@ -76,9 +76,7 @@ impl TunnelState for DisconnectedState {
SameState(self)
}
Ok(TunnelCommand::Connect) => NewState(ConnectingState::enter(shared_values, 0)),
- Ok(TunnelCommand::Block(reason)) => {
- NewState(BlockedState::enter(shared_values, reason))
- }
+ Ok(TunnelCommand::Block(reason)) => NewState(ErrorState::enter(shared_values, reason)),
Ok(_) => SameState(self),
Err(_) => Finished,
}
diff --git a/talpid-core/src/tunnel_state_machine/disconnecting_state.rs b/talpid-core/src/tunnel_state_machine/disconnecting_state.rs
index 733a6e2448..d18fdeb6ee 100644
--- a/talpid-core/src/tunnel_state_machine/disconnecting_state.rs
+++ b/talpid-core/src/tunnel_state_machine/disconnecting_state.rs
@@ -1,5 +1,5 @@
use super::{
- BlockedState, ConnectingState, DisconnectedState, EventConsequence, SharedTunnelStateValues,
+ ConnectingState, DisconnectedState, ErrorState, EventConsequence, SharedTunnelStateValues,
TunnelCommand, TunnelState, TunnelStateTransition, TunnelStateWrapper,
};
use crate::tunnel::CloseHandle;
@@ -9,14 +9,14 @@ use futures::{
};
use std::thread;
use talpid_types::{
- tunnel::{ActionAfterDisconnect, BlockReason},
+ tunnel::{ActionAfterDisconnect, ErrorStateCause},
ErrorExt,
};
/// This state is active from when we manually trigger a tunnel kill until the tunnel wait
/// operation (TunnelExit) returned.
pub struct DisconnectingState {
- exited: Option<oneshot::Receiver<Option<BlockReason>>>,
+ exited: Option<oneshot::Receiver<Option<ErrorStateCause>>>,
after_disconnect: AfterDisconnect,
}
@@ -58,7 +58,7 @@ impl DisconnectingState {
}
Ok(TunnelCommand::IsOffline(is_offline)) => {
shared_values.is_offline = is_offline;
- if !is_offline && reason == BlockReason::IsOffline {
+ if !is_offline && reason == ErrorStateCause::IsOffline {
AfterDisconnect::Reconnect(0)
} else {
AfterDisconnect::Block(reason)
@@ -81,7 +81,7 @@ impl DisconnectingState {
Ok(TunnelCommand::IsOffline(is_offline)) => {
shared_values.is_offline = is_offline;
if is_offline {
- AfterDisconnect::Block(BlockReason::IsOffline)
+ AfterDisconnect::Block(ErrorStateCause::IsOffline)
} else {
AfterDisconnect::Reconnect(retry_attempt)
}
@@ -117,16 +117,16 @@ impl DisconnectingState {
fn after_disconnect(
self,
- block_reason: Option<BlockReason>,
+ block_reason: Option<ErrorStateCause>,
shared_values: &mut SharedTunnelStateValues,
) -> (TunnelStateWrapper, TunnelStateTransition) {
if let Some(reason) = block_reason {
- return BlockedState::enter(shared_values, reason);
+ return ErrorState::enter(shared_values, reason);
}
match self.after_disconnect {
AfterDisconnect::Nothing => DisconnectedState::enter(shared_values, ()),
- AfterDisconnect::Block(reason) => BlockedState::enter(shared_values, reason),
+ AfterDisconnect::Block(cause) => ErrorState::enter(shared_values, cause),
AfterDisconnect::Reconnect(retry_attempt) => {
ConnectingState::enter(shared_values, retry_attempt)
}
@@ -137,7 +137,7 @@ impl DisconnectingState {
impl TunnelState for DisconnectingState {
type Bootstrap = (
Option<CloseHandle>,
- Option<oneshot::Receiver<Option<BlockReason>>>,
+ Option<oneshot::Receiver<Option<ErrorStateCause>>>,
AfterDisconnect,
);
@@ -180,7 +180,7 @@ impl TunnelState for DisconnectingState {
/// Which state should be transitioned to after disconnection is complete.
pub enum AfterDisconnect {
Nothing,
- Block(BlockReason),
+ Block(ErrorStateCause),
Reconnect(u32),
}
diff --git a/talpid-core/src/tunnel_state_machine/blocked_state.rs b/talpid-core/src/tunnel_state_machine/error_state.rs
index bdf054ab2c..9d8402997d 100644
--- a/talpid-core/src/tunnel_state_machine/blocked_state.rs
+++ b/talpid-core/src/tunnel_state_machine/error_state.rs
@@ -4,21 +4,25 @@ use super::{
};
use crate::firewall::FirewallPolicy;
use futures::{sync::mpsc, Stream};
-use talpid_types::{tunnel::BlockReason, ErrorExt};
+use talpid_types::{
+ tunnel::{self as talpid_tunnel, ErrorStateCause},
+ ErrorExt,
+};
/// No tunnel is running and all network connections are blocked.
-pub struct BlockedState {
- block_reason: BlockReason,
+pub struct ErrorState {
+ block_reason: ErrorStateCause,
}
-impl BlockedState {
- fn set_firewall_policy(shared_values: &mut SharedTunnelStateValues) -> Option<BlockReason> {
+impl ErrorState {
+ /// Returns true if firewall policy was applied successfully
+ fn set_firewall_policy(shared_values: &mut SharedTunnelStateValues) -> bool {
let policy = FirewallPolicy::Blocked {
allow_lan: shared_values.allow_lan,
};
match shared_values.firewall.apply_policy(policy) {
- Ok(()) => None,
+ Ok(()) => true,
Err(error) => {
log::error!(
"{}",
@@ -26,15 +30,16 @@ impl BlockedState {
"Failed to apply firewall policy for blocked state"
)
);
- Some(BlockReason::SetFirewallPolicyError)
+ false
}
}
}
+ /// Returns true if a new tunnel device was successfully created.
#[cfg(target_os = "android")]
- fn create_blocking_tun(shared_values: &mut SharedTunnelStateValues) -> Option<BlockReason> {
+ fn create_blocking_tun(shared_values: &mut SharedTunnelStateValues) -> bool {
match shared_values.tun_provider.create_tun_if_closed() {
- Ok(()) => None,
+ Ok(()) => true,
Err(error) => {
log::error!(
"{}",
@@ -42,28 +47,28 @@ impl BlockedState {
"Failed to open tunnel adapter to drop packets for blocked state"
)
);
- Some(BlockReason::SetFirewallPolicyError)
+ false
}
}
}
}
-impl TunnelState for BlockedState {
- type Bootstrap = BlockReason;
+impl TunnelState for ErrorState {
+ type Bootstrap = ErrorStateCause;
fn enter(
shared_values: &mut SharedTunnelStateValues,
block_reason: Self::Bootstrap,
) -> (TunnelStateWrapper, TunnelStateTransition) {
- let block_reason = Self::set_firewall_policy(shared_values).unwrap_or_else(|| block_reason);
+ #[cfg(not(target_os = "android"))]
+ let is_blocking = Self::set_firewall_policy(shared_values);
#[cfg(target_os = "android")]
- let block_reason = Self::create_blocking_tun(shared_values).unwrap_or_else(|| block_reason);
-
+ let is_blocking = Self::create_blocking_tun(shared_values);
(
- TunnelStateWrapper::from(BlockedState {
+ TunnelStateWrapper::from(ErrorState {
block_reason: block_reason.clone(),
}),
- TunnelStateTransition::Blocked(block_reason),
+ TunnelStateTransition::Error(talpid_tunnel::ErrorState::new(block_reason, is_blocking)),
)
}
@@ -86,7 +91,7 @@ impl TunnelState for BlockedState {
}
Ok(TunnelCommand::IsOffline(is_offline)) => {
shared_values.is_offline = is_offline;
- if !is_offline && self.block_reason == BlockReason::IsOffline {
+ if !is_offline && self.block_reason == ErrorStateCause::IsOffline {
NewState(ConnectingState::enter(shared_values, 0))
} else {
SameState(self)
@@ -96,9 +101,7 @@ impl TunnelState for BlockedState {
Ok(TunnelCommand::Disconnect) | Err(_) => {
NewState(DisconnectedState::enter(shared_values, ()))
}
- Ok(TunnelCommand::Block(reason)) => {
- NewState(BlockedState::enter(shared_values, reason))
- }
+ Ok(TunnelCommand::Block(reason)) => NewState(ErrorState::enter(shared_values, reason)),
}
}
}
diff --git a/talpid-core/src/tunnel_state_machine/mod.rs b/talpid-core/src/tunnel_state_machine/mod.rs
index b86795491d..76bd62a1d4 100644
--- a/talpid-core/src/tunnel_state_machine/mod.rs
+++ b/talpid-core/src/tunnel_state_machine/mod.rs
@@ -1,18 +1,18 @@
#[macro_use]
mod macros;
-mod blocked_state;
mod connected_state;
mod connecting_state;
mod disconnected_state;
mod disconnecting_state;
+mod error_state;
use self::{
- blocked_state::BlockedState,
connected_state::{ConnectedState, ConnectedStateBootstrap},
connecting_state::ConnectingState,
disconnected_state::DisconnectedState,
disconnecting_state::{AfterDisconnect, DisconnectingState},
+ error_state::ErrorState,
};
use crate::{
dns::DnsMonitor,
@@ -32,7 +32,7 @@ use std::{
use talpid_types::android::AndroidContext;
use talpid_types::{
net::TunnelParameters,
- tunnel::{BlockReason, ParameterGenerationError, TunnelStateTransition},
+ tunnel::{ErrorStateCause, ParameterGenerationError, TunnelStateTransition},
ErrorExt,
};
use tokio_core::reactor::Core;
@@ -182,7 +182,7 @@ pub enum TunnelCommand {
/// Close tunnel connection.
Disconnect,
/// Disconnect any open tunnel and block all network access
- Block(BlockReason),
+ Block(ErrorStateCause),
}
/// Asynchronous handling of the tunnel state machine.
@@ -297,7 +297,7 @@ impl<T: TunnelState> From<EventConsequence<T>> for TunnelStateMachineAction {
pub trait TunnelParametersGenerator: Send + 'static {
/// Given the number of consecutive failed retry attempts, it should yield a `TunnelParameters`
/// to establish a tunnel with.
- /// If this returns `None` then the state machine goes into the `Blocked` state.
+ /// If this returns `None` then the state machine goes into the `Error` state.
fn generate(
&mut self,
retry_attempt: u32,
@@ -427,6 +427,6 @@ state_wrapper! {
Connecting(ConnectingState),
Connected(ConnectedState),
Disconnecting(DisconnectingState),
- Blocked(BlockedState),
+ Error(ErrorState),
}
}
diff --git a/talpid-types/src/tunnel.rs b/talpid-types/src/tunnel.rs
index 9ab3ed6d36..fad6be14a4 100644
--- a/talpid-types/src/tunnel.rs
+++ b/talpid-types/src/tunnel.rs
@@ -18,7 +18,7 @@ pub enum TunnelStateTransition {
/// Disconnecting tunnel.
Disconnecting(ActionAfterDisconnect),
/// Tunnel is disconnected but secured by blocking all connections.
- Blocked(BlockReason),
+ Error(ErrorState),
}
/// Action that will be taken after disconnection is complete.
@@ -32,22 +32,43 @@ pub enum ActionAfterDisconnect {
Reconnect,
}
-impl TunnelStateTransition {
- pub fn is_blocked(&self) -> bool {
- match self {
- TunnelStateTransition::Blocked(_) => true,
- _ => false,
- }
+/// Error state
+#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
+#[serde(rename_all = "snake_case")]
+#[cfg_attr(target_os = "android", derive(IntoJava))]
+#[cfg_attr(target_os = "android", jnix(package = "net.mullvad.talpid.tunnel"))]
+pub struct ErrorState {
+ /// Reason why the tunnel state machine ended up in the error state
+ cause: ErrorStateCause,
+ /// Indicates whether the daemon is currently blocking all traffic. This _should_ always be
+ /// true - in the case it is not, the user should be notified that no traffic is being blocked.
+ /// A false value means there was a serious error and the intended security properties are not
+ /// being upheld.
+ is_blocking: bool,
+}
+
+impl ErrorState {
+ pub fn new(cause: ErrorStateCause, is_blocking: bool) -> Self {
+ Self { cause, is_blocking }
+ }
+
+ pub fn is_blocking(&self) -> bool {
+ self.is_blocking
+ }
+
+ pub fn cause(&self) -> &ErrorStateCause {
+ &self.cause
}
}
+
/// Reason for entering the blocked state.
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
#[serde(tag = "reason", content = "details")]
#[cfg_attr(target_os = "android", derive(IntoJava))]
#[cfg_attr(target_os = "android", jnix(package = "net.mullvad.talpid.tunnel"))]
-pub enum BlockReason {
+pub enum ErrorStateCause {
/// Authentication with remote server failed.
AuthFailed(Option<String>),
/// Failed to configure IPv6 because it's disabled in the platform.
@@ -86,9 +107,9 @@ pub enum ParameterGenerationError {
CustomTunnelHostResultionError,
}
-impl fmt::Display for BlockReason {
+impl fmt::Display for ErrorStateCause {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- use self::BlockReason::*;
+ use self::ErrorStateCause::*;
let description = match *self {
AuthFailed(ref reason) => {
return write!(