summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorEmīls Piņķis <emils@mullvad.net>2019-06-06 13:44:01 +0100
committerEmīls Piņķis <emils@mullvad.net>2019-06-06 13:44:01 +0100
commitd20fed36f95e2d535b2272777a78dc84ed9e1e6b (patch)
treeebc691c10fd67f5b0f63d967afb319aa4288a462
parent9ab06703eba719bafeef9495cd2aa16cfbd13d1e (diff)
parent71515c8c71fad734386934a4bb4715c28c97a5f4 (diff)
downloadmullvadvpn-d20fed36f95e2d535b2272777a78dc84ed9e1e6b.tar.xz
mullvadvpn-d20fed36f95e2d535b2272777a78dc84ed9e1e6b.zip
Merge branch 'show-bridge-in-gui'
-rw-r--r--README.md7
-rw-r--r--gui/src/main/daemon-rpc.ts1
-rw-r--r--gui/src/renderer/components/Connect.tsx26
-rw-r--r--gui/src/renderer/components/ConnectionInfo.tsx25
-rw-r--r--gui/src/renderer/components/ConnectionInfoDisclosure.tsx9
-rw-r--r--gui/src/renderer/components/TunnelControl.tsx23
-rw-r--r--gui/src/renderer/redux/connection/reducers.ts2
-rw-r--r--gui/src/shared/daemon-rpc-types.ts25
-rw-r--r--gui/test/components/NotificationArea.spec.tsx2
-rw-r--r--mullvad-daemon/src/lib.rs38
-rw-r--r--mullvad-daemon/src/relays.rs12
-rw-r--r--mullvad-types/src/location.rs3
12 files changed, 137 insertions, 36 deletions
diff --git a/README.md b/README.md
index 385dcfaca2..48141e0bba 100644
--- a/README.md
+++ b/README.md
@@ -128,10 +128,11 @@ sections.
cargo build
```
-1. Copy the OpenVPN binary, and our plugin for it, to the directory we will use as resource
- directory. If you want to use any other directory, you would need to copy even more files.
+1. Copy the OpenVPN and Shadowsocks binaries, and our plugin for it, to the directory we will
+ use as resource directory. If you want to use any other directory, you would need to copy
+ even more files.
```bash
- cp dist-assets/binaries/<platform>/openvpn[.exe] dist-assets/
+ cp dist-assets/binaries/<platform>/{openvpn, sslocal}[.exe] dist-assets/
cp target/debug/*talpid_openvpn_plugin* dist-assets/
```
diff --git a/gui/src/main/daemon-rpc.ts b/gui/src/main/daemon-rpc.ts
index 86ef3dff0a..f50428ea8a 100644
--- a/gui/src/main/daemon-rpc.ts
+++ b/gui/src/main/daemon-rpc.ts
@@ -41,6 +41,7 @@ const locationSchema = maybe(
longitude: number,
mullvad_exit_ip: boolean,
hostname: maybe(string),
+ bridge_hostname: maybe(string),
}),
);
diff --git a/gui/src/renderer/components/Connect.tsx b/gui/src/renderer/components/Connect.tsx
index dea950b3f1..60fca1df50 100644
--- a/gui/src/renderer/components/Connect.tsx
+++ b/gui/src/renderer/components/Connect.tsx
@@ -12,7 +12,7 @@ import ImageView from './ImageView';
import { Container, Header, Layout } from './Layout';
import Map, { MarkerStyle, ZoomLevel } from './Map';
import NotificationArea from './NotificationArea';
-import TunnelControl, { IRelayInAddress, IRelayOutAddress } from './TunnelControl';
+import TunnelControl, { IBridgeData, IRelayInAddress, IRelayOutAddress } from './TunnelControl';
interface IProps {
connection: IConnectionReduxState;
@@ -50,7 +50,7 @@ const styles = {
paddingLeft: 24,
paddingRight: 24,
paddingBottom: 0,
- marginTop: 186,
+ marginTop: 176,
}),
container: Styles.createViewStyle({
flex: 1,
@@ -159,6 +159,11 @@ export default class Connect extends Component<IProps, IState> {
? this.tunnelEndpointToRelayInAddress(status.details)
: undefined;
+ const bridgeData: IBridgeData | undefined =
+ (status.state === 'connecting' || status.state === 'connected') && status.details
+ ? this.tunnelEndpointToBridgeData(status.details)
+ : undefined;
+
return (
<View style={styles.connect}>
<Map style={styles.map} {...this.getMapProps()} />
@@ -178,6 +183,8 @@ export default class Connect extends Component<IProps, IState> {
hostname={this.props.connection.hostname}
defaultConnectionInfoOpen={this.props.connectionInfoOpen}
relayInAddress={relayInAddress}
+ bridge={bridgeData}
+ bridgeHostname={this.props.connection.bridgeHostname}
relayOutAddress={relayOutAddress}
onConnect={this.props.onConnect}
onDisconnect={this.props.onDisconnect}
@@ -321,6 +328,21 @@ export default class Connect extends Component<IProps, IState> {
ip: socketAddr.host,
port: socketAddr.port,
protocol: tunnelEndpoint.protocol,
+ tunnelType: tunnelEndpoint.tunnelType,
+ };
+ }
+
+ private tunnelEndpointToBridgeData(endpoint: ITunnelEndpoint): IBridgeData | undefined {
+ if (!endpoint.proxy) {
+ return undefined;
+ }
+
+ const socketAddr = parseSocketAddress(endpoint.proxy.address);
+ return {
+ ip: socketAddr.host,
+ port: socketAddr.port,
+ protocol: endpoint.proxy.protocol,
+ bridgeType: endpoint.proxy.proxyType,
};
}
}
diff --git a/gui/src/renderer/components/ConnectionInfo.tsx b/gui/src/renderer/components/ConnectionInfo.tsx
index 7ab8d9907f..7bf5f4fed9 100644
--- a/gui/src/renderer/components/ConnectionInfo.tsx
+++ b/gui/src/renderer/components/ConnectionInfo.tsx
@@ -1,7 +1,9 @@
import * as React from 'react';
import { Component, Styles, Text, Types, View } from 'reactxp';
+import { proxyTypeToString, TunnelType, tunnelTypeToString } from '../../shared/daemon-rpc-types';
import { messages } from '../../shared/gettext';
import { default as ConnectionInfoDisclosure } from './ConnectionInfoDisclosure';
+import { IBridgeData } from './TunnelControl';
const styles = {
row: Styles.createViewStyle({
@@ -42,6 +44,7 @@ interface IInAddress {
ip: string;
port: number;
protocol: string;
+ tunnelType: TunnelType;
}
interface IOutAddress {
@@ -51,7 +54,9 @@ interface IOutAddress {
interface IProps {
hostname?: string;
+ bridgeHostname?: string;
inAddress?: IInAddress;
+ bridgeInfo?: IBridgeData;
outAddress?: IOutAddress;
defaultOpen?: boolean;
style?: Types.ViewStyleRuleSet | Types.ViewStyleRuleSet[];
@@ -72,24 +77,34 @@ export default class ConnectionInfo extends Component<IProps, IState> {
}
public render() {
- const { inAddress, outAddress } = this.props;
+ const { inAddress, outAddress, bridgeInfo } = this.props;
+ const transportLine =
+ (inAddress ? tunnelTypeToString(inAddress.tunnelType) : '') +
+ (bridgeInfo && inAddress ? ' via ' + proxyTypeToString(bridgeInfo.bridgeType) : '');
+
+ const entryPoint = bridgeInfo && inAddress ? bridgeInfo : inAddress;
return (
<View style={this.props.style}>
<View style={styles.header}>
- <Text style={styles.hostname}>{this.props.hostname || ''}</Text>
<ConnectionInfoDisclosure defaultOpen={this.props.defaultOpen} onToggle={this.onToggle}>
- {messages.pgettext('connection-info', 'Connection details')}
+ <Text style={styles.hostname}>
+ {this.props.hostname || ''}{' '}
+ {this.props.bridgeHostname ? `via ${this.props.bridgeHostname}` : ''}
+ </Text>
</ConnectionInfoDisclosure>
</View>
{this.state.isOpen && (
<React.Fragment>
- {inAddress && (
+ {this.props.inAddress && (
+ <View style={styles.row}>{<Text style={styles.value}>{transportLine}</Text>}</View>
+ )}
+ {entryPoint && (
<View style={styles.row}>
<Text style={styles.caption}>{messages.pgettext('connection-info', 'In')}</Text>
<Text style={styles.value}>
- {`${inAddress.ip}:${inAddress.port} ${inAddress.protocol.toUpperCase()}`}
+ {`${entryPoint.ip}:${entryPoint.port} ${entryPoint.protocol.toUpperCase()}`}
</Text>
</View>
)}
diff --git a/gui/src/renderer/components/ConnectionInfoDisclosure.tsx b/gui/src/renderer/components/ConnectionInfoDisclosure.tsx
index 93cd17b1d0..6dc324e78f 100644
--- a/gui/src/renderer/components/ConnectionInfoDisclosure.tsx
+++ b/gui/src/renderer/components/ConnectionInfoDisclosure.tsx
@@ -1,5 +1,5 @@
import * as React from 'react';
-import { Component, Styles, Text, Types, View } from 'reactxp';
+import { Component, Styles, Types, View } from 'reactxp';
import ImageView from './ImageView';
const styles = {
@@ -23,7 +23,7 @@ const styles = {
interface IProps {
onToggle?: (isOpen: boolean) => void;
defaultOpen?: boolean;
- children: string;
+ children: React.ReactNode;
style?: Types.ViewStyleRuleSet | Types.ViewStyleRuleSet[];
}
@@ -51,10 +51,7 @@ export default class ConnectionInfoDisclosure extends Component<IProps, IState>
onMouseEnter={this.onMouseEnter}
onMouseLeave={this.onMouseLeave}
onPress={this.onToggle}>
- <Text
- style={[styles.caption.base, this.state.isHovered ? styles.caption.hovered : undefined]}>
- {this.props.children}
- </Text>
+ {this.props.children}
<ImageView
source={this.state.isOpen ? 'icon-chevron-up' : 'icon-chevron-down'}
width={24}
diff --git a/gui/src/renderer/components/TunnelControl.tsx b/gui/src/renderer/components/TunnelControl.tsx
index ccad62cb51..ed062c9f0d 100644
--- a/gui/src/renderer/components/TunnelControl.tsx
+++ b/gui/src/renderer/components/TunnelControl.tsx
@@ -1,18 +1,31 @@
import * as React from 'react';
import { Component, Styles, Text, Types, View } from 'reactxp';
import { colors } from '../../config.json';
-import { RelayProtocol, TunnelStateTransition } from '../../shared/daemon-rpc-types';
+import {
+ ProxyType,
+ RelayProtocol,
+ TunnelStateTransition,
+ TunnelType,
+} from '../../shared/daemon-rpc-types';
import { cities, countries, messages, relayLocations } from '../../shared/gettext';
import * as AppButton from './AppButton';
import ConnectionInfo from './ConnectionInfo';
import SecuredLabel, { SecuredDisplayStyle } from './SecuredLabel';
-export interface IRelayInAddress {
+export interface IEndpoint {
ip: string;
port: number;
protocol: RelayProtocol;
}
+export interface IRelayInAddress extends IEndpoint {
+ tunnelType: TunnelType;
+}
+
+export interface IBridgeData extends IEndpoint {
+ bridgeType: ProxyType;
+}
+
export interface IRelayOutAddress {
ipv4?: string;
ipv6?: string;
@@ -27,6 +40,8 @@ interface ITunnelControlProps {
defaultConnectionInfoOpen?: boolean;
relayInAddress?: IRelayInAddress;
relayOutAddress?: IRelayOutAddress;
+ bridge?: IBridgeData;
+ bridgeHostname?: string;
onConnect: () => void;
onDisconnect: () => void;
onSelectLocation: () => void;
@@ -39,7 +54,7 @@ const styles = {
paddingLeft: 24,
paddingRight: 24,
paddingBottom: 0,
- marginTop: 186,
+ marginTop: 176,
flex: 1,
}),
footer: Styles.createViewStyle({
@@ -145,7 +160,9 @@ export default class TunnelControl extends Component<ITunnelControlProps> {
const connectionDetails = (
<ConnectionInfo
hostname={this.props.hostname}
+ bridgeHostname={this.props.bridgeHostname}
inAddress={this.props.relayInAddress}
+ bridgeInfo={this.props.bridge}
outAddress={this.props.relayOutAddress}
defaultOpen={this.props.defaultConnectionInfoOpen}
onToggle={this.props.onToggleConnectionInfo}
diff --git a/gui/src/renderer/redux/connection/reducers.ts b/gui/src/renderer/redux/connection/reducers.ts
index 5175b6c5ec..2719f3d3db 100644
--- a/gui/src/renderer/redux/connection/reducers.ts
+++ b/gui/src/renderer/redux/connection/reducers.ts
@@ -7,6 +7,7 @@ export interface IConnectionReduxState {
ipv4?: Ip;
ipv6?: Ip;
hostname?: string;
+ bridgeHostname?: string;
latitude?: number;
longitude?: number;
country?: string;
@@ -19,6 +20,7 @@ const initialState: IConnectionReduxState = {
ipv4: undefined,
ipv6: undefined,
hostname: undefined,
+ bridgeHostname: undefined,
latitude: undefined,
longitude: undefined,
country: undefined,
diff --git a/gui/src/shared/daemon-rpc-types.ts b/gui/src/shared/daemon-rpc-types.ts
index 3225995e75..891c06c8b9 100644
--- a/gui/src/shared/daemon-rpc-types.ts
+++ b/gui/src/shared/daemon-rpc-types.ts
@@ -12,6 +12,7 @@ export interface ILocation {
longitude: number;
mullvadExitIp: boolean;
hostname?: string;
+ bridgeHostname?: string;
}
export type BlockReason =
@@ -32,22 +33,42 @@ export type AfterDisconnect = 'nothing' | 'block' | 'reconnect';
export type TunnelState = 'connecting' | 'connected' | 'disconnecting' | 'disconnected' | 'blocked';
export type TunnelType = 'wireguard' | 'openvpn';
+export function tunnelTypeToString(tunnel: TunnelType): string {
+ switch (tunnel) {
+ case 'wireguard':
+ return 'WireGuard';
+ case 'openvpn':
+ return 'OpenVPN';
+ default:
+ return '';
+ }
+}
export type RelayProtocol = 'tcp' | 'udp';
export type ProxyType = 'shadowsocks' | 'custom';
+export function proxyTypeToString(proxy: ProxyType): string {
+ switch (proxy) {
+ case 'shadowsocks':
+ return 'Shadowsocks';
+ case 'custom':
+ return 'Custom';
+ default:
+ return '';
+ }
+}
export interface ITunnelEndpoint {
address: string;
protocol: RelayProtocol;
- tunnel: TunnelType;
+ tunnelType: TunnelType;
proxy?: IProxyEndpoint;
}
export interface IProxyEndpoint {
address: string;
protocol: RelayProtocol;
- proxy_type: ProxyType;
+ proxyType: ProxyType;
}
export type DaemonEvent =
diff --git a/gui/test/components/NotificationArea.spec.tsx b/gui/test/components/NotificationArea.spec.tsx
index c117db914e..7b1a69bd8a 100644
--- a/gui/test/components/NotificationArea.spec.tsx
+++ b/gui/test/components/NotificationArea.spec.tsx
@@ -65,7 +65,7 @@ describe('components/NotificationArea', () => {
details: {
address: '1.2.3.4',
protocol: 'tcp',
- tunnel: 'openvpn',
+ tunnelType: 'openvpn',
},
}}
version={defaultVersion}
diff --git a/mullvad-daemon/src/lib.rs b/mullvad-daemon/src/lib.rs
index 88cd834969..42c87d0024 100644
--- a/mullvad-daemon/src/lib.rs
+++ b/mullvad-daemon/src/lib.rs
@@ -214,6 +214,7 @@ pub struct Daemon<L: EventListener = ManagementInterfaceEventBroadcaster> {
tokio_remote: tokio_core::reactor::Remote,
relay_selector: relays::RelaySelector,
last_generated_relay: Option<Relay>,
+ last_generated_bridge_relay: Option<Relay>,
version: String,
}
@@ -379,6 +380,7 @@ where
tokio_remote,
relay_selector,
last_generated_relay: None,
+ last_generated_bridge_relay: None,
version,
})
}
@@ -500,6 +502,7 @@ where
) -> Result<TunnelParameters> {
let tunnel_options = self.settings.get_tunnel_options().clone();
let location = relay.location.as_ref().expect("Relay has no location set");
+ self.last_generated_bridge_relay = None;
match endpoint {
MullvadEndpoint::OpenVpn(endpoint) => {
let proxy_settings = match self.settings.get_bridge_settings() {
@@ -509,16 +512,28 @@ where
transport_protocol: Constraint::Only(endpoint.protocol),
};
match self.settings.get_bridge_state() {
- BridgeState::On => Some(
- self.relay_selector
+ BridgeState::On => {
+ let (bridge_settings, bridge_relay) = self
+ .relay_selector
.get_proxy_settings(&bridge_constraints, location)
- .ok_or(Error::NoBridgeAvailable)?,
- ),
- BridgeState::Auto => self.relay_selector.get_auto_proxy_settings(
- &bridge_constraints,
- location,
- retry_attempt,
- ),
+ .ok_or(Error::NoBridgeAvailable)?;
+ self.last_generated_bridge_relay = Some(bridge_relay);
+ Some(bridge_settings)
+ }
+ BridgeState::Auto => {
+ if let Some((bridge_settings, bridge_relay)) =
+ self.relay_selector.get_auto_proxy_settings(
+ &bridge_constraints,
+ location,
+ retry_attempt,
+ )
+ {
+ self.last_generated_bridge_relay = Some(bridge_relay);
+ Some(bridge_settings)
+ } else {
+ None
+ }
+ }
BridgeState::Off => None,
}
}
@@ -704,6 +719,10 @@ where
fn build_location_from_relay(&self) -> Option<GeoIpLocation> {
let relay = self.last_generated_relay.as_ref()?;
+ let bridge_hostname = self
+ .last_generated_bridge_relay
+ .as_ref()
+ .map(|bridge| bridge.hostname.clone());
let location = relay.location.as_ref().cloned().unwrap();
let hostname = relay.hostname.clone();
@@ -716,6 +735,7 @@ where
longitude: location.longitude,
mullvad_exit_ip: true,
hostname: Some(hostname),
+ bridge_hostname,
})
}
diff --git a/mullvad-daemon/src/relays.rs b/mullvad-daemon/src/relays.rs
index 81874e4367..e9c02c6214 100644
--- a/mullvad-daemon/src/relays.rs
+++ b/mullvad-daemon/src/relays.rs
@@ -280,7 +280,7 @@ impl RelaySelector {
bridge_constraints: &InternalBridgeConstraints,
location: &Location,
retry_attempt: u32,
- ) -> Option<ProxySettings> {
+ ) -> Option<(ProxySettings, Relay)> {
if !self.should_use_bridge(retry_attempt) {
return None;
}
@@ -307,7 +307,7 @@ impl RelaySelector {
&mut self,
constraints: &InternalBridgeConstraints,
location: &Location,
- ) -> Option<ProxySettings> {
+ ) -> Option<(ProxySettings, Relay)> {
let mut matching_relays: Vec<Relay> = self
.lock_parsed_relays()
.relays()
@@ -322,9 +322,11 @@ impl RelaySelector {
matching_relays.sort_by_cached_key(|relay| {
(relay.location.as_ref().unwrap().distance_from(&location) * 1000.0) as i64
});
- return matching_relays
- .get(0)
- .and_then(|relay| self.pick_random_bridge(&relay));
+ return matching_relays.get(0).and_then(|relay| {
+ (self
+ .pick_random_bridge(&relay)
+ .map(|bridge| (bridge, relay.clone())))
+ });
}
diff --git a/mullvad-types/src/location.rs b/mullvad-types/src/location.rs
index 514ce35809..629f15d37a 100644
--- a/mullvad-types/src/location.rs
+++ b/mullvad-types/src/location.rs
@@ -73,6 +73,7 @@ pub struct GeoIpLocation {
pub longitude: f64,
pub mullvad_exit_ip: bool,
pub hostname: Option<String>,
+ pub bridge_hostname: Option<String>,
}
impl From<AmIMullvad> for GeoIpLocation {
@@ -81,6 +82,7 @@ impl From<AmIMullvad> for GeoIpLocation {
IpAddr::V4(v4) => (Some(v4), None),
IpAddr::V6(v6) => (None, Some(v6)),
};
+
GeoIpLocation {
ipv4,
ipv6,
@@ -90,6 +92,7 @@ impl From<AmIMullvad> for GeoIpLocation {
longitude: location.longitude,
mullvad_exit_ip: location.mullvad_exit_ip,
hostname: None,
+ bridge_hostname: None,
}
}
}