diff options
| author | Emīls Piņķis <emils@mullvad.net> | 2019-06-06 13:44:01 +0100 |
|---|---|---|
| committer | Emīls Piņķis <emils@mullvad.net> | 2019-06-06 13:44:01 +0100 |
| commit | d20fed36f95e2d535b2272777a78dc84ed9e1e6b (patch) | |
| tree | ebc691c10fd67f5b0f63d967afb319aa4288a462 | |
| parent | 9ab06703eba719bafeef9495cd2aa16cfbd13d1e (diff) | |
| parent | 71515c8c71fad734386934a4bb4715c28c97a5f4 (diff) | |
| download | mullvadvpn-d20fed36f95e2d535b2272777a78dc84ed9e1e6b.tar.xz mullvadvpn-d20fed36f95e2d535b2272777a78dc84ed9e1e6b.zip | |
Merge branch 'show-bridge-in-gui'
| -rw-r--r-- | README.md | 7 | ||||
| -rw-r--r-- | gui/src/main/daemon-rpc.ts | 1 | ||||
| -rw-r--r-- | gui/src/renderer/components/Connect.tsx | 26 | ||||
| -rw-r--r-- | gui/src/renderer/components/ConnectionInfo.tsx | 25 | ||||
| -rw-r--r-- | gui/src/renderer/components/ConnectionInfoDisclosure.tsx | 9 | ||||
| -rw-r--r-- | gui/src/renderer/components/TunnelControl.tsx | 23 | ||||
| -rw-r--r-- | gui/src/renderer/redux/connection/reducers.ts | 2 | ||||
| -rw-r--r-- | gui/src/shared/daemon-rpc-types.ts | 25 | ||||
| -rw-r--r-- | gui/test/components/NotificationArea.spec.tsx | 2 | ||||
| -rw-r--r-- | mullvad-daemon/src/lib.rs | 38 | ||||
| -rw-r--r-- | mullvad-daemon/src/relays.rs | 12 | ||||
| -rw-r--r-- | mullvad-types/src/location.rs | 3 |
12 files changed, 137 insertions, 36 deletions
@@ -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, } } } |
