summaryrefslogtreecommitdiffhomepage
path: root/gui
diff options
context:
space:
mode:
authorDavid Lönnhager <david.l@mullvad.net>2020-08-04 10:53:53 +0200
committerDavid Lönnhager <david.l@mullvad.net>2020-08-04 10:53:53 +0200
commit61d14531b61cc78d951add7b3cdfd3623e45410b (patch)
tree50fce79818d21f8ad497b64243a14a4c84b2a347 /gui
parentabf7bb0dd3021daef52593515a98b0ebb189d9a0 (diff)
parent3496937abc7e6347e057a39ec6a40f49dd71e6a2 (diff)
downloadmullvadvpn-61d14531b61cc78d951add7b3cdfd3623e45410b.tar.xz
mullvadvpn-61d14531b61cc78d951add7b3cdfd3623e45410b.zip
Merge branch 'win-firewall-errors'
Diffstat (limited to 'gui')
-rw-r--r--gui/src/main/daemon-rpc.ts25
-rw-r--r--gui/src/main/index.ts2
-rw-r--r--gui/src/renderer/app.tsx2
-rw-r--r--gui/src/renderer/components/Connect.tsx4
-rw-r--r--gui/src/renderer/components/TunnelControl.tsx2
-rw-r--r--gui/src/shared/daemon-rpc-types.ts14
-rw-r--r--gui/src/shared/notifications/error.ts130
7 files changed, 122 insertions, 57 deletions
diff --git a/gui/src/main/daemon-rpc.ts b/gui/src/main/daemon-rpc.ts
index 656efd760b..6071ce515f 100644
--- a/gui/src/main/daemon-rpc.ts
+++ b/gui/src/main/daemon-rpc.ts
@@ -259,12 +259,21 @@ const tunnelStateSchema = oneOf(
object({
state: enumeration('error'),
details: object({
- is_blocking: boolean,
+ block_failure: maybe(
+ object({
+ reason: enumeration('generic', 'locked'),
+ details: maybe(
+ object({
+ name: string,
+ pid: number,
+ }),
+ ),
+ }),
+ ),
cause: oneOf(
object({
reason: enumeration(
'ipv6_unavailable',
- 'set_firewall_policy_error',
'set_dns_error',
'start_tunnel_error',
'is_offline',
@@ -272,6 +281,18 @@ const tunnelStateSchema = oneOf(
),
}),
object({
+ reason: enumeration('set_firewall_policy_error'),
+ details: object({
+ reason: enumeration('generic', 'locked'),
+ details: maybe(
+ object({
+ name: string,
+ pid: number,
+ }),
+ ),
+ }),
+ }),
+ object({
reason: enumeration('auth_failed'),
details: maybe(string),
}),
diff --git a/gui/src/main/index.ts b/gui/src/main/index.ts
index 18dfc67d29..f375de7eca 100644
--- a/gui/src/main/index.ts
+++ b/gui/src/main/index.ts
@@ -863,7 +863,7 @@ class ApplicationMain {
return 'securing';
case 'error':
- if (tunnelState.details.isBlocking) {
+ if (!tunnelState.details.blockFailure) {
return 'securing';
} else {
return 'unsecured';
diff --git a/gui/src/renderer/app.tsx b/gui/src/renderer/app.tsx
index 0dc076378a..c09ca39049 100644
--- a/gui/src/renderer/app.tsx
+++ b/gui/src/renderer/app.tsx
@@ -634,7 +634,7 @@ export default class AppRenderer {
break;
case 'error':
- actions.updateBlockState(tunnelState.details.isBlocking);
+ actions.updateBlockState(!tunnelState.details.blockFailure);
break;
}
}
diff --git a/gui/src/renderer/components/Connect.tsx b/gui/src/renderer/components/Connect.tsx
index 0db4a40141..184465bd7d 100644
--- a/gui/src/renderer/components/Connect.tsx
+++ b/gui/src/renderer/components/Connect.tsx
@@ -169,7 +169,7 @@ export default class Connect extends React.Component<IProps, IState> {
case 'connected':
return HeaderBarStyle.success;
case 'error':
- return status.details.isBlocking ? HeaderBarStyle.success : HeaderBarStyle.error;
+ return !status.details.blockFailure ? HeaderBarStyle.success : HeaderBarStyle.error;
case 'disconnecting':
switch (status.details) {
case 'block':
@@ -223,7 +223,7 @@ export default class Connect extends React.Component<IProps, IState> {
case 'connected':
return MarkerStyle.secure;
case 'error':
- return status.details.isBlocking ? MarkerStyle.secure : MarkerStyle.unsecure;
+ return !status.details.blockFailure ? MarkerStyle.secure : MarkerStyle.unsecure;
case 'disconnected':
return MarkerStyle.unsecure;
case 'disconnecting':
diff --git a/gui/src/renderer/components/TunnelControl.tsx b/gui/src/renderer/components/TunnelControl.tsx
index 04236750ee..611c24d78e 100644
--- a/gui/src/renderer/components/TunnelControl.tsx
+++ b/gui/src/renderer/components/TunnelControl.tsx
@@ -176,7 +176,7 @@ export default class TunnelControl extends React.Component<ITunnelControlProps>
case 'error':
if (
this.props.tunnelState.state === 'error' &&
- !this.props.tunnelState.details.isBlocking
+ this.props.tunnelState.details.blockFailure
) {
return (
<Wrapper>
diff --git a/gui/src/shared/daemon-rpc-types.ts b/gui/src/shared/daemon-rpc-types.ts
index bec0275e9b..1f1779a4b0 100644
--- a/gui/src/shared/daemon-rpc-types.ts
+++ b/gui/src/shared/daemon-rpc-types.ts
@@ -15,6 +15,16 @@ export interface ILocation {
bridgeHostname?: string;
}
+export type FirewallPolicyError =
+ | { reason: 'generic' }
+ | {
+ reason: 'locked';
+ details?: {
+ name: string;
+ pid: number;
+ };
+ };
+
export type TunnelParameterError =
| 'no_matching_relay'
| 'no_matching_bridge_relay'
@@ -25,12 +35,12 @@ export type ErrorStateCause =
| {
reason:
| 'ipv6_unavailable'
- | 'set_firewall_policy_error'
| 'set_dns_error'
| 'start_tunnel_error'
| 'is_offline'
| 'tap_adapter_problem';
}
+ | { reason: 'set_firewall_policy_error'; details: FirewallPolicyError }
| { reason: 'tunnel_parameter_error'; details: TunnelParameterError }
| { reason: 'auth_failed'; details?: string };
@@ -102,7 +112,7 @@ export type TunnelState =
| { state: 'error'; details: IErrorState };
export interface IErrorState {
- isBlocking: boolean;
+ blockFailure?: FirewallPolicyError;
cause: ErrorStateCause;
}
diff --git a/gui/src/shared/notifications/error.ts b/gui/src/shared/notifications/error.ts
index 1a8499739e..7b438edb54 100644
--- a/gui/src/shared/notifications/error.ts
+++ b/gui/src/shared/notifications/error.ts
@@ -1,7 +1,13 @@
import { sprintf } from 'sprintf-js';
import { hasExpired } from '../account-expiry';
import { AuthFailureKind, parseAuthFailure } from '../auth-failure';
-import { IErrorState, TunnelState, TunnelParameterError } from '../daemon-rpc-types';
+import {
+ IErrorState,
+ TunnelState,
+ TunnelParameterError,
+ ErrorStateCause,
+ FirewallPolicyError,
+} from '../daemon-rpc-types';
import { messages } from '../gettext';
import {
InAppNotification,
@@ -27,7 +33,7 @@ export class ErrorNotificationProvider
this.context.tunnelState,
this.context.accountExpiry,
),
- critical: !this.context.tunnelState.details.isBlocking,
+ critical: !!this.context.tunnelState.details.blockFailure,
}
: undefined;
}
@@ -36,7 +42,7 @@ export class ErrorNotificationProvider
return this.context.tunnelState.state === 'error'
? {
indicator: 'error',
- title: this.context.tunnelState.details.isBlocking
+ title: !this.context.tunnelState.details.blockFailure
? messages.pgettext('in-app-notifications', 'BLOCKING INTERNET')
: messages.pgettext('in-app-notifications', 'YOU MIGHT BE LEAKING NETWORK TRAFFIC'),
subtitle: getInAppNotificationSubtitle(this.context.tunnelState),
@@ -49,7 +55,7 @@ function getSystemNotificationMessage(
tunnelState: { state: 'error'; details: IErrorState },
accountExpiry?: string,
) {
- if (!tunnelState.details.isBlocking) {
+ if (tunnelState.details.blockFailure) {
return messages.pgettext('notifications', 'Critical error (your attention is required)');
} else if (
(tunnelState.details.cause.reason === 'auth_failed' &&
@@ -75,57 +81,85 @@ function getSystemNotificationMessage(
}
function getInAppNotificationSubtitle(tunnelState: { state: 'error'; details: IErrorState }) {
- if (!tunnelState.details.isBlocking) {
- return messages.pgettext(
+ let blockFailureMessage = null;
+ if (tunnelState.details.blockFailure) {
+ const extraMessage = getPolicyMessage(tunnelState.details.blockFailure);
+ blockFailureMessage = `${messages.pgettext(
'in-app-notifications',
- 'Failed to block all network traffic. Please troubleshoot or report the problem to us.',
- );
- } else {
- const blockReason = tunnelState.details.cause;
- switch (blockReason.reason) {
- case 'auth_failed':
- return parseAuthFailure(blockReason.details).message;
- case 'ipv6_unavailable':
- return messages.pgettext(
- 'in-app-notifications',
- 'Could not configure IPv6, please enable it on your system or disable it in the app',
- );
- case 'set_firewall_policy_error': {
- let extraMessage = null;
- switch (process.platform) {
- case 'linux':
- extraMessage = messages.pgettext('in-app-notifications', 'Your kernel may be outdated');
- break;
- case 'win32':
+ 'Failed to block all network traffic',
+ )}${extraMessage ? '. ' + extraMessage : ''}`;
+ }
+
+ const blockMessage = getBlockMessage(tunnelState.details.cause);
+ return blockFailureMessage
+ ? `${blockFailureMessage}. ${messages.pgettext(
+ 'in-app-notifications',
+ 'Original block reason',
+ )}: ${blockMessage}`
+ : blockMessage;
+}
+
+function getBlockMessage(blockReason: ErrorStateCause): string {
+ switch (blockReason.reason) {
+ case 'auth_failed':
+ return parseAuthFailure(blockReason.details).message;
+ case 'ipv6_unavailable':
+ return messages.pgettext(
+ 'in-app-notifications',
+ 'Could not configure IPv6, please enable it on your system or disable it in the app',
+ );
+ case 'set_firewall_policy_error': {
+ const extraMessage = getPolicyMessage(blockReason.details);
+ return `${messages.pgettext(
+ 'in-app-notifications',
+ 'Failed to apply firewall rules. The device might currently be unsecured',
+ )}${extraMessage ? '. ' + extraMessage : ''}`;
+ }
+ case 'set_dns_error':
+ return messages.pgettext('in-app-notifications', 'Failed to set system DNS server');
+ case 'start_tunnel_error':
+ return messages.pgettext('in-app-notifications', 'Failed to start tunnel connection');
+ case 'tunnel_parameter_error':
+ return getTunnelParameterMessage(blockReason.details);
+ case 'is_offline':
+ return messages.pgettext(
+ 'in-app-notifications',
+ 'This device is offline, no tunnels can be established',
+ );
+ case 'tap_adapter_problem':
+ return messages.pgettext(
+ 'in-app-notifications',
+ "Unable to detect a working TAP adapter on this device. If you've disabled it, enable it again. Otherwise, please reinstall the app",
+ );
+ }
+}
+
+function getPolicyMessage(err: FirewallPolicyError): string | null {
+ let extraMessage = null;
+ switch (process.platform) {
+ case 'linux':
+ extraMessage = messages.pgettext('in-app-notifications', 'Your kernel may be outdated');
+ break;
+ case 'win32':
+ switch (err.reason) {
+ case 'locked':
+ if (err.details) {
+ // TODO: Check if this message is ok
+ extraMessage = `${messages.pgettext(
+ 'in-app-notifications',
+ 'An application prevented the policy from being set',
+ )}: ${err.details.name}`;
+ } else {
extraMessage = messages.pgettext(
'in-app-notifications',
'This might be caused by third party security software',
);
- break;
- }
- return `${messages.pgettext(
- 'in-app-notifications',
- 'Failed to apply firewall rules. The device might currently be unsecured',
- )}${extraMessage ? '. ' + extraMessage : ''}`;
+ }
+ break;
}
- case 'set_dns_error':
- return messages.pgettext('in-app-notifications', 'Failed to set system DNS server');
- case 'start_tunnel_error':
- return messages.pgettext('in-app-notifications', 'Failed to start tunnel connection');
- case 'tunnel_parameter_error':
- return getTunnelParameterMessage(blockReason.details);
- case 'is_offline':
- return messages.pgettext(
- 'in-app-notifications',
- 'This device is offline, no tunnels can be established',
- );
- case 'tap_adapter_problem':
- return messages.pgettext(
- 'in-app-notifications',
- "Unable to detect a working TAP adapter on this device. If you've disabled it, enable it again. Otherwise, please reinstall the app",
- );
- }
+ break;
}
+ return extraMessage;
}
function getTunnelParameterMessage(err: TunnelParameterError): string {