summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorEmīls Piņķis <emils@mullvad.net>2019-01-30 14:02:13 +0000
committerEmīls Piņķis <emils@mullvad.net>2019-01-30 14:02:13 +0000
commit2139dfb9c37f0d7d6b5e823631bac23b511b38f6 (patch)
tree68254aa2fea067b92cd55fcce9195c87292df6e5
parent8c43e0cd550b84c8688270edad525c022d49cd78 (diff)
parent68dd1990e1555ea074d408adeda3cd502abb2e8f (diff)
downloadmullvadvpn-2139dfb9c37f0d7d6b5e823631bac23b511b38f6.tar.xz
mullvadvpn-2139dfb9c37f0d7d6b5e823631bac23b511b38f6.zip
Merge branch 'refactor-talpid-types'
-rw-r--r--Cargo.lock67
-rw-r--r--gui/packages/desktop/src/main/daemon-rpc.js44
-rw-r--r--gui/packages/desktop/src/main/index.js10
-rw-r--r--gui/packages/desktop/src/renderer/app.js22
-rw-r--r--gui/packages/desktop/src/renderer/components/Connect.js8
-rw-r--r--gui/packages/desktop/src/renderer/lib/relay-settings-builder.js60
-rw-r--r--gui/packages/desktop/src/shared/daemon-rpc-types.js71
-rw-r--r--gui/packages/desktop/test/relay-settings-builder.spec.js21
-rw-r--r--mullvad-cli/src/cmds/relay.rs39
-rw-r--r--mullvad-cli/src/cmds/tunnel.rs32
-rw-r--r--mullvad-daemon/src/lib.rs44
-rw-r--r--mullvad-daemon/src/management_interface.rs8
-rw-r--r--mullvad-daemon/src/relays.rs14
-rw-r--r--mullvad-ipc-client/src/lib.rs9
-rw-r--r--mullvad-types/Cargo.toml1
-rw-r--r--mullvad-types/src/custom_tunnel.rs81
-rw-r--r--mullvad-types/src/endpoint.rs111
-rw-r--r--mullvad-types/src/lib.rs1
-rw-r--r--mullvad-types/src/relay_constraints.rs3
-rw-r--r--mullvad-types/src/relay_list.rs49
-rw-r--r--mullvad-types/src/settings.rs36
-rw-r--r--talpid-core/src/process/openvpn.rs10
-rw-r--r--talpid-core/src/security/macos/mod.rs5
-rw-r--r--talpid-core/src/tunnel/mod.rs67
-rw-r--r--talpid-core/src/tunnel/openvpn.rs29
-rw-r--r--talpid-core/src/tunnel/wireguard/config.rs147
-rw-r--r--talpid-core/src/tunnel/wireguard/mod.rs30
-rw-r--r--talpid-core/src/tunnel/wireguard/wireguard_go.rs4
-rw-r--r--talpid-core/src/tunnel_state_machine/connected_state.rs30
-rw-r--r--talpid-core/src/tunnel_state_machine/connecting_state.rs62
-rw-r--r--talpid-core/src/tunnel_state_machine/mod.rs13
-rw-r--r--talpid-types/Cargo.toml3
-rw-r--r--talpid-types/src/net.rs363
-rw-r--r--talpid-types/src/net/mod.rs164
-rw-r--r--talpid-types/src/net/openvpn.rs128
-rw-r--r--talpid-types/src/net/wireguard.rs173
-rw-r--r--talpid-types/src/tunnel.rs2
37 files changed, 1128 insertions, 833 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 2c905c1322..973752aab2 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -158,14 +158,6 @@ dependencies = [
]
[[package]]
-name = "clear_on_drop"
-version = "0.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
name = "cloudabi"
version = "0.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -237,19 +229,6 @@ dependencies = [
]
[[package]]
-name = "curve25519-dalek"
-version = "0.19.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "subtle 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
name = "dbus"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -287,14 +266,6 @@ dependencies = [
]
[[package]]
-name = "digest"
-version = "0.7.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
name = "dirs"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -489,14 +460,6 @@ version = "0.3.55"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
-name = "generic-array"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
name = "globset"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1141,6 +1104,7 @@ version = "0.1.0"
dependencies = [
"chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "ipnetwork 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"mullvad-paths 0.1.0",
@@ -1740,11 +1704,6 @@ version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
-name = "subtle"
-version = "0.7.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
name = "syn"
version = "0.11.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1892,9 +1851,10 @@ name = "talpid-types"
version = "0.1.0"
dependencies = [
"base64 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"ipnetwork 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
- "x25519-dalek 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -2205,11 +2165,6 @@ dependencies = [
]
[[package]]
-name = "typenum"
-version = "1.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
name = "ucd-util"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2400,15 +2355,6 @@ dependencies = [
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
-[[package]]
-name = "x25519-dalek"
-version = "0.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "curve25519-dalek 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
[metadata]
"checksum aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1e9a933f4e58658d7b12defcf96dc5c720f20832deebe3e0a19efd3b6aaeeb9e"
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
@@ -2430,7 +2376,6 @@ dependencies = [
"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4"
"checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878"
"checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e"
-"checksum clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "97276801e127ffb46b66ce23f35cc96bd454fa311294bced4bbace7baa8b1d17"
"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
"checksum colored 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc0a60679001b62fb628c4da80e574b9645ab4646056d7c9018885efffe45533"
"checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e"
@@ -2440,12 +2385,10 @@ dependencies = [
"checksum crossbeam-epoch 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "30fecfcac6abfef8771151f8be4abc9e4edc112c2bcb233314cafde2680536e9"
"checksum crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "677d453a17e8bd2b913fa38e8b9cf04bcdbb5be790aa294f2389661d72036015"
"checksum ctrlc 3.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "630391922b1b893692c6334369ff528dcc3a9d8061ccf4c803aa8f83cb13db5e"
-"checksum curve25519-dalek 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)" = "15d6d81c070d8090389f752510ce22c7d571100a78fa4e7c06e6f6d95585bb49"
"checksum dbus 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3d975a175aa2dced1a6cd410b89a1bf23918f301eab2b6f7c5e608291b757639"
"checksum derive-try-from-primitive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "81dbd65eb15734b6d50dc6ac86f14f928462be0a5df6bda17761e909071ede5d"
"checksum derive_builder 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c998e6ab02a828dd9735c18f154e14100e674ed08cb4e1938f0e4177543f439"
"checksum derive_builder_core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "735e24ee9e5fa8e16b86da5007856e97d592e11867e45d76e0c0d0a164a0b757"
-"checksum digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "03b072242a8cbaf9c145665af9d250c59af3b958f83ed6824e13533cf76d5b90"
"checksum dirs 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "88972de891f6118092b643d85a0b28e0678e0f948d7f879aa32f2d5aafe97d2a"
"checksum duct 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f87f5af80601599209bff21146e4113e8c54471151049deebc37e75b78e42729"
"checksum env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)" = "15b0a4d2e39f8420210be8b27eeda28029729e2fd4291019455016c348240c38"
@@ -2469,7 +2412,6 @@ dependencies = [
"checksum futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)" = "49e7653e374fe0d0c12de4250f0bdb60680b8c80eed558c5c7538eec9c89e21b"
"checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4"
"checksum gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2"
-"checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d"
"checksum globset 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "90d069fe6beb9be359ef505650b3f73228c5591a3c4b1f32be2f4f44459ffa3a"
"checksum globset 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4743617a7464bbda3c8aec8558ff2f9429047e025771037df561d383337ff865"
"checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77"
@@ -2588,7 +2530,6 @@ dependencies = [
"checksum socket2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "c4d11a52082057d87cb5caa31ad812f4504b97ab44732cd8359df2e9ff9f48e7"
"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8"
"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
-"checksum subtle 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5938f1b89f10d6356339f071eca74209deeae0b6891c2678d655feb78637e369"
"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
"checksum syn 0.15.18 (registry+https://github.com/rust-lang/crates.io-index)" = "90c39a061e2f412a9f869540471ab679e85e50c6b05604daf28bc3060f75c430"
"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6"
@@ -2623,7 +2564,6 @@ dependencies = [
"checksum toml 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "4a2ecc31b0351ea18b3fe11274b8db6e4d82bce861bbb22e6dbed40417902c65"
"checksum try-lock 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee2aa4715743892880f70885373966c83d73ef1b0838a664ef0c76fffd35e7c2"
"checksum tun 0.4.2 (git+https://github.com/pinkisemils/rust-tun?branch=add-raw-fd-traits)" = "<none>"
-"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169"
"checksum ucd-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d0f8bfa9ff0cadcd210129ad9d2c5f145c13e9ced3d3e5d948a6213487d52444"
"checksum unicase 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9d3218ea14b4edcaccfa0df0a64a3792a2c32cc706f1b336e48867f9d3147f90"
"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
@@ -2652,4 +2592,3 @@ dependencies = [
"checksum winreg 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a27a759395c1195c4cc5cda607ef6f8f6498f64e78f7900f5de0a127a424704a"
"checksum winres 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f07dabda4e79413ecac65bc9a2234ad3d85dc49f9d289f868cd9d8611d88f28d"
"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
-"checksum x25519-dalek 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "538296831e9794ec5b3ec9d4a1a8c3e3c86271e9635a0e776e3214fec9c727de"
diff --git a/gui/packages/desktop/src/main/daemon-rpc.js b/gui/packages/desktop/src/main/daemon-rpc.js
index 000dc544b9..6b3ec60135 100644
--- a/gui/packages/desktop/src/main/daemon-rpc.js
+++ b/gui/packages/desktop/src/main/daemon-rpc.js
@@ -53,12 +53,32 @@ const constraint = <T>(constraintValue: SchemaNode<T>) => {
);
};
-const TunnelEndpointDataSchema = partialObject({
- openvpn: partialObject({
- port: number,
- protocol: enumeration('udp', 'tcp'),
+const CustomTunnelEndpoint = oneOf(
+ object({
+ openvpn: object({
+ endpoint: object({
+ address: string,
+ protocol: enumeration('udp', 'tcp'),
+ }),
+ username: string,
+ password: string,
+ }),
}),
-});
+ object({
+ wireguard: object({
+ tunnel: object({
+ private_key: string,
+ addresses: arrayOf(string),
+ }),
+ peer: object({
+ public_key: string,
+ allowed_ips: arrayOf(string),
+ endpoint: string,
+ }),
+ gateway: string,
+ }),
+ }),
+);
const RelaySettingsSchema = oneOf(
object({
@@ -89,7 +109,7 @@ const RelaySettingsSchema = oneOf(
object({
custom_tunnel_endpoint: partialObject({
host: string,
- tunnel: TunnelEndpointDataSchema,
+ config: CustomTunnelEndpoint,
}),
}),
);
@@ -142,11 +162,18 @@ const OpenVpnProxySchema = maybe(
);
const TunnelOptionsSchema = partialObject({
- enable_ipv6: boolean,
openvpn: partialObject({
mssfix: maybe(number),
proxy: OpenVpnProxySchema,
}),
+ wireguard: partialObject({
+ mtu: maybe(number),
+ // only relevant on linux
+ fmwark: maybe(number),
+ }),
+ generic: partialObject({
+ enable_ipv6: boolean,
+ }),
});
const AccountDataSchema = partialObject({
@@ -162,7 +189,8 @@ const TunnelStateTransitionSchema = oneOf(
state: enumeration('connecting', 'connected'),
details: partialObject({
address: string,
- tunnel: TunnelEndpointDataSchema,
+ protocol: enumeration('tcp', 'udp'),
+ tunnel_type: enumeration('wireguard', 'openvpn'),
}),
}),
object({
diff --git a/gui/packages/desktop/src/main/index.js b/gui/packages/desktop/src/main/index.js
index 4d20e98d0a..d13956cbc5 100644
--- a/gui/packages/desktop/src/main/index.js
+++ b/gui/packages/desktop/src/main/index.js
@@ -77,11 +77,17 @@ const ApplicationMain = {
},
},
tunnelOptions: {
- enableIpv6: false,
+ generic: {
+ enableIpv6: false,
+ },
openvpn: {
mssfix: null,
+ proxy: null,
+ },
+ wireguard: {
+ mtu: null,
+ fwmark: null,
},
- proxy: null,
},
}: Settings),
_guiSettings: new GuiSettings(),
diff --git a/gui/packages/desktop/src/renderer/app.js b/gui/packages/desktop/src/renderer/app.js
index afea9e9651..280c815ba8 100644
--- a/gui/packages/desktop/src/renderer/app.js
+++ b/gui/packages/desktop/src/renderer/app.js
@@ -30,6 +30,7 @@ import { IpcRendererEventChannel } from '../shared/ipc-event-channel';
import type {
AccountToken,
AccountData,
+ ConnectionConfig,
Location,
RelayList,
RelaySettingsUpdate,
@@ -274,12 +275,19 @@ export default class AppRenderer {
});
} else if (relaySettings.customTunnelEndpoint) {
const customTunnelEndpoint = relaySettings.customTunnelEndpoint;
- const {
- host,
- tunnel: {
- openvpn: { port, protocol },
- },
- } = customTunnelEndpoint;
+ const host = customTunnelEndpoint.host;
+ const config: ConnectionConfig = customTunnelEndpoint.config;
+
+ let port = 0;
+ let protocol = 'udp';
+ if (config.openvpn) {
+ port = config.openvpn.endpoint.port;
+ protocol = config.openvpn.endpoint.protocol;
+ }
+
+ if (config.wireguard) {
+ // TODO: handle wireguard
+ }
actions.settings.updateRelay({
customTunnelEndpoint: {
@@ -449,7 +457,7 @@ export default class AppRenderer {
const reduxAccount = this._reduxActions.account;
reduxSettings.updateAllowLan(newSettings.allowLan);
- reduxSettings.updateEnableIpv6(newSettings.tunnelOptions.enableIpv6);
+ reduxSettings.updateEnableIpv6(newSettings.tunnelOptions.generic.enableIpv6);
reduxSettings.updateBlockWhenDisconnected(newSettings.blockWhenDisconnected);
reduxSettings.updateOpenVpnMssfix(newSettings.tunnelOptions.openvpn.mssfix);
diff --git a/gui/packages/desktop/src/renderer/components/Connect.js b/gui/packages/desktop/src/renderer/components/Connect.js
index c4d26d15db..08636ad567 100644
--- a/gui/packages/desktop/src/renderer/components/Connect.js
+++ b/gui/packages/desktop/src/renderer/components/Connect.js
@@ -10,6 +10,7 @@ import TunnelControl from './TunnelControl';
import Map from './Map';
import styles from './ConnectStyles';
import { NoCreditError, NoInternetError } from '../../main/errors';
+import { parseSocketAddress } from '../../shared/daemon-rpc-types';
import type { RelayOutAddress, RelayInAddress } from './TunnelControl';
import type AccountExpiry from '../lib/account-expiry';
@@ -170,10 +171,11 @@ export default class Connect extends Component<Props> {
let relayInAddress: ?RelayInAddress = null;
if ((tunnelState === 'connecting' || tunnelState === 'connected') && details) {
+ const socketAddr = parseSocketAddress(details.address);
relayInAddress = {
- ip: details.address,
- port: details.tunnel.openvpn.port,
- protocol: details.tunnel.openvpn.protocol,
+ ip: socketAddr.host,
+ port: socketAddr.port,
+ protocol: details.protocol,
};
}
diff --git a/gui/packages/desktop/src/renderer/lib/relay-settings-builder.js b/gui/packages/desktop/src/renderer/lib/relay-settings-builder.js
index d81c4d6fac..3397f543df 100644
--- a/gui/packages/desktop/src/renderer/lib/relay-settings-builder.js
+++ b/gui/packages/desktop/src/renderer/lib/relay-settings-builder.js
@@ -5,7 +5,6 @@ import type {
RelayProtocol,
RelaySettingsUpdate,
RelaySettingsNormalUpdate,
- RelaySettingsCustom,
} from '../../shared/daemon-rpc-types';
type LocationBuilder<Self> = {
@@ -139,65 +138,6 @@ class NormalRelaySettingsBuilder {
}
}
-type CustomOpenVPNConfigurator<Self> = {
- port: (port: number) => Self,
- protocol: (protocol: RelayProtocol) => Self,
-};
-
-type CustomTunnelBuilder<Self> = {
- openvpn: (configurator: (CustomOpenVPNConfigurator<*>) => void) => Self,
-};
-
-class CustomRelaySettingsBuilder {
- _payload: RelaySettingsCustom = {
- host: '',
- tunnel: {
- openvpn: {
- port: 0,
- protocol: 'udp',
- },
- },
- };
-
- build(): RelaySettingsUpdate {
- return {
- customTunnelEndpoint: this._payload,
- };
- }
-
- host(value: string) {
- this._payload.host = value;
- return this;
- }
-
- get tunnel(): CustomTunnelBuilder<CustomRelaySettingsBuilder> {
- const updateOpenvpn = (next) => {
- const tunnel = this._payload.tunnel || {};
- const prev = tunnel.openvpn || {};
- this._payload.tunnel = {
- openvpn: { ...prev, ...next },
- };
- };
-
- return {
- openvpn: (configurator) => {
- configurator({
- port: function(port: number) {
- updateOpenvpn({ port });
- return this;
- },
- protocol: function(protocol: RelayProtocol) {
- updateOpenvpn({ protocol });
- return this;
- },
- });
- return this;
- },
- };
- }
-}
-
export default {
normal: () => new NormalRelaySettingsBuilder(),
- custom: () => new CustomRelaySettingsBuilder(),
};
diff --git a/gui/packages/desktop/src/shared/daemon-rpc-types.js b/gui/packages/desktop/src/shared/daemon-rpc-types.js
index 82e52a7603..9b39ba90c2 100644
--- a/gui/packages/desktop/src/shared/daemon-rpc-types.js
+++ b/gui/packages/desktop/src/shared/daemon-rpc-types.js
@@ -1,5 +1,4 @@
// @flow
-
export type AccountData = { expiry: string };
export type AccountToken = string;
export type Ip = string;
@@ -30,16 +29,14 @@ export type AfterDisconnect = 'nothing' | 'block' | 'reconnect';
export type TunnelState = 'connecting' | 'connected' | 'disconnecting' | 'disconnected' | 'blocked';
+export type TunnelType = 'wireguard' | 'openvpn';
+
+export type RelayProtocol = 'tcp' | 'udp';
+
export type TunnelEndpoint = {
address: string,
- tunnel: TunnelEndpointData,
-};
-
-export type TunnelEndpointData = {
- openvpn: {
- port: number,
- protocol: RelayProtocol,
- },
+ protocol: RelayProtocol,
+ tunnel: TunnelType,
};
export type TunnelStateTransition =
@@ -49,7 +46,6 @@ export type TunnelStateTransition =
| { state: 'disconnecting', details: AfterDisconnect }
| { state: 'blocked', details: BlockReason };
-export type RelayProtocol = 'tcp' | 'udp';
export type RelayLocation =
| {| hostname: [string, string, string] |}
| {| city: [string, string] |}
@@ -77,10 +73,36 @@ type RelaySettingsNormal<TTunnelConstraints> = {
},
};
+export type ConnectionConfig =
+ | {|
+ openvpn: {
+ endpoint: {
+ ip: string,
+ port: number,
+ protocol: RelayProtocol,
+ },
+ username: string,
+ },
+ |}
+ | {|
+ wireguard: {
+ tunnel: {
+ private_key: string,
+ addresses: Array<string>,
+ },
+ peer: {
+ public_key: string,
+ addresses: Array<string>,
+ endpoint: string,
+ },
+ gateway: string,
+ },
+ |};
+
// types describing the structure of RelaySettings
export type RelaySettingsCustom = {
host: string,
- tunnel: TunnelEndpointData,
+ config: ConnectionConfig,
};
export type RelaySettings =
| {|
@@ -128,11 +150,18 @@ export type RelayListHostname = {
};
export type TunnelOptions = {
- enableIpv6: boolean,
openvpn: {
mssfix: ?number,
+ proxy: ?ProxySettings,
+ },
+ wireguard: {
+ mtu: ?number,
+ // Only relevant on Linux
+ fwmark: ?number,
+ },
+ generic: {
+ enableIpv6: boolean,
},
- proxy: ?ProxySettings,
};
export type ProxySettings = LocalProxySettings | RemoteProxySettings;
@@ -168,3 +197,19 @@ export type Settings = {
relaySettings: RelaySettings,
tunnelOptions: TunnelOptions,
};
+
+export type SocketAddress = { host: string, port: number };
+
+export function parseSocketAddress(socketAddrStr: string): SocketAddress {
+ const re = new RegExp(/(.+):(\d+)$/);
+ const matches = socketAddrStr.match(re);
+
+ if (!matches || matches.length < 3) {
+ throw new Error(`Failed to parse socket address from address string '${socketAddrStr}'`);
+ }
+ const socketAddress: SocketAddress = {
+ host: matches[1],
+ port: Number(matches[2]),
+ };
+ return socketAddress;
+}
diff --git a/gui/packages/desktop/test/relay-settings-builder.spec.js b/gui/packages/desktop/test/relay-settings-builder.spec.js
index 56126adca5..0782476fe8 100644
--- a/gui/packages/desktop/test/relay-settings-builder.spec.js
+++ b/gui/packages/desktop/test/relay-settings-builder.spec.js
@@ -122,25 +122,4 @@ describe('Relay settings builder', () => {
},
});
});
-
- it('should set custom endpoint settings', () => {
- expect(
- RelaySettingsBuilder.custom()
- .host('se2.mullvad.net')
- .tunnel.openvpn((openvpn) => {
- openvpn.port(80).protocol('tcp');
- })
- .build(),
- ).to.deep.equal({
- customTunnelEndpoint: {
- host: 'se2.mullvad.net',
- tunnel: {
- openvpn: {
- port: 80,
- protocol: 'tcp',
- },
- },
- },
- });
- });
});
diff --git a/mullvad-cli/src/cmds/relay.rs b/mullvad-cli/src/cmds/relay.rs
index 5acee6fd39..2f3d276fce 100644
--- a/mullvad-cli/src/cmds/relay.rs
+++ b/mullvad-cli/src/cmds/relay.rs
@@ -1,17 +1,15 @@
use crate::{new_rpc_client, Command, Result, ResultExt};
use clap::value_t;
-use std::str::FromStr;
+use std::{net::Ipv4Addr, str::FromStr};
use mullvad_types::{
relay_constraints::{
Constraint, LocationConstraint, OpenVpnConstraints, RelayConstraintsUpdate,
RelaySettingsUpdate, TunnelConstraints,
},
- CustomTunnelEndpoint,
-};
-use talpid_types::net::{
- OpenVpnEndpointData, TransportProtocol, TunnelEndpointData, WireguardEndpointData,
+ ConnectionConfig, CustomTunnelEndpoint,
};
+use talpid_types::net::{openvpn, Endpoint, TransportProtocol};
pub struct Relay;
@@ -57,6 +55,16 @@ impl Command for Relay {
.index(4)
.default_value("udp")
.possible_values(&["udp", "tcp"]),
+ )
+ .arg(
+ clap::Arg::with_name("username")
+ .help("Username to be used with the OpenVpn relay")
+ .index(5),
+ )
+ .arg(
+ clap::Arg::with_name("password")
+ .help("Password to be used with the OpenVpn relay")
+ .index(6),
),
)
.subcommand(
@@ -146,17 +154,26 @@ impl Relay {
fn set_custom(&self, matches: &clap::ArgMatches) -> Result<()> {
let host = value_t!(matches.value_of("host"), String).unwrap_or_else(|e| e.exit());
let port = value_t!(matches.value_of("port"), u16).unwrap_or_else(|e| e.exit());
- let tunnel = match matches.value_of("tunnel").unwrap() {
- "openvpn" => TunnelEndpointData::OpenVpn(OpenVpnEndpointData {
- port,
- protocol: value_t!(matches.value_of("protocol"), TransportProtocol).unwrap(),
- }),
+ let config = match matches.value_of("tunnel").unwrap() {
+ "openvpn" => {
+ let username =
+ value_t!(matches.value_of("username"), String).unwrap_or_else(|e| e.exit());
+ let password =
+ value_t!(matches.value_of("password"), String).unwrap_or_else(|e| e.exit());
+ let protocol = value_t!(matches.value_of("protocol"), TransportProtocol)
+ .unwrap_or_else(|e| e.exit());
+ ConnectionConfig::OpenVpn(openvpn::ConnectionConfig {
+ endpoint: Endpoint::new(Ipv4Addr::UNSPECIFIED, port, protocol),
+ username,
+ password,
+ })
+ }
// TODO: Gather all the data to build a WireguardEndpointData properly.
// "wireguard" => TunnelEndpointData::Wireguard(WireguardEndpointData { port }),
_ => unreachable!("Invalid tunnel protocol"),
};
self.update_constraints(RelaySettingsUpdate::CustomTunnelEndpoint(
- CustomTunnelEndpoint { host, tunnel },
+ CustomTunnelEndpoint::new(host, config),
))
}
diff --git a/mullvad-cli/src/cmds/tunnel.rs b/mullvad-cli/src/cmds/tunnel.rs
index a45ae31c17..33e75d26d4 100644
--- a/mullvad-cli/src/cmds/tunnel.rs
+++ b/mullvad-cli/src/cmds/tunnel.rs
@@ -1,10 +1,8 @@
use crate::{new_rpc_client, Command, Result};
use clap::value_t;
-use talpid_types::net::{
- LocalOpenVpnProxySettings, OpenVpnProxyAuth, OpenVpnProxySettings,
- OpenVpnProxySettingsValidation, RemoteOpenVpnProxySettings, TunnelOptions,
-};
+use mullvad_types::settings::TunnelOptions;
+use talpid_types::net::openvpn;
use std::net::{IpAddr, SocketAddr};
@@ -102,11 +100,13 @@ fn create_openvpn_proxy_subcommand() -> clap::App<'static, 'static> {
.arg(
clap::Arg::with_name("username")
.help("Specifies the username for remote authentication")
+ .required(true)
.index(3),
)
.arg(
clap::Arg::with_name("password")
.help("Specifies the password for remote authentication")
+ .required(true)
.index(4),
),
),
@@ -207,9 +207,9 @@ impl Tunnel {
fn process_openvpn_proxy_get() -> Result<()> {
let tunnel_options = Self::get_tunnel_options()?;
if let Some(proxy) = tunnel_options.openvpn.proxy {
- if let OpenVpnProxySettings::Local(local_proxy) = proxy {
+ if let openvpn::ProxySettings::Local(local_proxy) = proxy {
Self::print_local_proxy(&local_proxy)
- } else if let OpenVpnProxySettings::Remote(remote_proxy) = proxy {
+ } else if let openvpn::ProxySettings::Remote(remote_proxy) = proxy {
Self::print_remote_proxy(&remote_proxy)
} else {
unreachable!("unhandled proxy type");
@@ -220,14 +220,14 @@ impl Tunnel {
Ok(())
}
- fn print_local_proxy(proxy: &LocalOpenVpnProxySettings) {
+ fn print_local_proxy(proxy: &openvpn::LocalProxySettings) {
println!("proxy: local");
println!(" local port: {}", proxy.port);
println!(" peer IP: {}", proxy.peer.ip());
println!(" peer port: {}", proxy.peer.port());
}
- fn print_remote_proxy(proxy: &RemoteOpenVpnProxySettings) {
+ fn print_remote_proxy(proxy: &openvpn::RemoteProxySettings) {
println!("proxy: remote");
println!(" server IP: {}", proxy.address.ip());
println!(" server port: {}", proxy.address.port());
@@ -256,14 +256,14 @@ impl Tunnel {
let remote_port =
value_t!(args.value_of("remote-port"), u16).unwrap_or_else(|e| e.exit());
- let proxy = LocalOpenVpnProxySettings {
+ let proxy = openvpn::LocalProxySettings {
port: local_port,
peer: SocketAddr::new(remote_ip, remote_port),
};
- let packed_proxy = OpenVpnProxySettings::Local(proxy);
+ let packed_proxy = openvpn::ProxySettings::Local(proxy);
- if let Err(error) = OpenVpnProxySettingsValidation::validate(&packed_proxy) {
+ if let Err(error) = openvpn::ProxySettingsValidation::validate(&packed_proxy) {
panic!(error);
}
@@ -278,21 +278,21 @@ impl Tunnel {
let password = args.value_of("password");
let auth = match (username, password) {
- (Some(username), Some(password)) => Some(OpenVpnProxyAuth {
+ (Some(username), Some(password)) => Some(openvpn::ProxyAuth {
username: username.to_string(),
password: password.to_string(),
}),
_ => None,
};
- let proxy = RemoteOpenVpnProxySettings {
+ let proxy = openvpn::RemoteProxySettings {
address: SocketAddr::new(remote_ip, remote_port),
auth,
};
- let packed_proxy = OpenVpnProxySettings::Remote(proxy);
+ let packed_proxy = openvpn::ProxySettings::Remote(proxy);
- if let Err(error) = OpenVpnProxySettingsValidation::validate(&packed_proxy) {
+ if let Err(error) = openvpn::ProxySettingsValidation::validate(&packed_proxy) {
panic!(error);
}
@@ -311,7 +311,7 @@ impl Tunnel {
let tunnel_options = Self::get_tunnel_options()?;
println!(
"IPv6: {}",
- if tunnel_options.enable_ipv6 {
+ if tunnel_options.generic.enable_ipv6 {
"on"
} else {
"off"
diff --git a/mullvad-daemon/src/lib.rs b/mullvad-daemon/src/lib.rs
index 63dee4e536..eeb0f5755a 100644
--- a/mullvad-daemon/src/lib.rs
+++ b/mullvad-daemon/src/lib.rs
@@ -29,6 +29,7 @@ use log::{debug, error, info, warn};
use mullvad_rpc::{AccountsProxy, AppVersionProxy, HttpHandle};
use mullvad_types::{
account::{AccountData, AccountToken},
+ endpoint::MullvadEndpoint,
location::GeoIpLocation,
relay_constraints::{
Constraint, OpenVpnConstraints, RelayConstraintsUpdate, RelaySettings, RelaySettingsUpdate,
@@ -42,10 +43,10 @@ use mullvad_types::{
use std::{mem, path::PathBuf, sync::mpsc, thread, time::Duration};
use talpid_core::{
mpsc::IntoSender,
- tunnel_state_machine::{self, TunnelCommand, TunnelParameters, TunnelParametersGenerator},
+ tunnel_state_machine::{self, TunnelCommand, TunnelParametersGenerator},
};
use talpid_types::{
- net::{OpenVpnProxySettings, TransportProtocol},
+ net::{openvpn, TransportProtocol, TunnelParameters},
tunnel::{BlockReason, TunnelStateTransition},
};
@@ -58,6 +59,9 @@ error_chain! {
DaemonIsAlreadyRunning {
description("Another instance of the daemon is already running")
}
+ UnsupportedTunnel {
+ description("Unsupported tunnel")
+ }
ManagementInterfaceError(msg: &'static str) {
description("Error in the management interface")
display("Management interface error: {}", msg)
@@ -340,24 +344,20 @@ impl Daemon {
.map(|account_token| {
match self.settings.get_relay_settings() {
RelaySettings::CustomTunnelEndpoint(custom_relay) => custom_relay
- .to_tunnel_endpoint()
+ .to_tunnel_parameters(self.settings.get_tunnel_options().clone())
.chain_err(|| "Custom tunnel endpoint could not be resolved"),
RelaySettings::Normal(constraints) => self
.relay_selector
.get_tunnel_endpoint(&constraints, retry_attempt)
.chain_err(|| "No valid relay servers match the current settings")
- .map(|(relay, endpoint)| {
+ .and_then(|(relay, endpoint)| {
self.last_generated_relay = Some(relay);
- endpoint
+ self.create_tunnel_parameters(endpoint, account_token)
}),
}
- .map(|endpoint| {
+ .map(|tunnel_params| {
tunnel_parameters_tx
- .send(TunnelParameters {
- endpoint,
- options: self.settings.get_tunnel_options().clone(),
- username: account_token,
- })
+ .send(tunnel_params)
.map_err(|_| Error::from("Tunnel parameters receiver stopped listening"))
})
});
@@ -366,6 +366,26 @@ impl Daemon {
}
}
+ fn create_tunnel_parameters(
+ &self,
+ endpoint: MullvadEndpoint,
+ account_token: String,
+ ) -> Result<TunnelParameters> {
+ let tunnel_options = self.settings.get_tunnel_options().clone();
+ match endpoint {
+ MullvadEndpoint::OpenVpn(endpoint) => Ok(openvpn::TunnelParameters {
+ config: openvpn::ConnectionConfig::new(endpoint, account_token, "-".to_string()),
+ options: tunnel_options.openvpn,
+ generic_options: tunnel_options.generic,
+ }
+ .into()),
+ MullvadEndpoint::Wireguard {
+ peer: _,
+ gateway: _,
+ } => Err(ErrorKind::UnsupportedTunnel.into()),
+ }
+ }
+
fn schedule_reconnect(&mut self, delay: Duration) {
let tunnel_command_tx = self.tx.clone();
let (tx, rx) = mpsc::channel();
@@ -639,7 +659,7 @@ impl Daemon {
fn on_set_openvpn_proxy(
&mut self,
tx: oneshot::Sender<::std::result::Result<(), settings::Error>>,
- proxy: Option<OpenVpnProxySettings>,
+ proxy: Option<openvpn::ProxySettings>,
) {
let constraints_result = match proxy {
Some(_) => self.apply_proxy_constraints(),
diff --git a/mullvad-daemon/src/management_interface.rs b/mullvad-daemon/src/management_interface.rs
index c68c8ff967..cea4d6a75d 100644
--- a/mullvad-daemon/src/management_interface.rs
+++ b/mullvad-daemon/src/management_interface.rs
@@ -30,7 +30,7 @@ use std::{
};
use talpid_core::mpsc::IntoSender;
use talpid_ipc;
-use talpid_types::{net::OpenVpnProxySettings, tunnel::TunnelStateTransition};
+use talpid_types::{net::openvpn, tunnel::TunnelStateTransition};
use uuid;
/// FIXME(linus): This is here just because the futures crate has deprecated it and jsonrpc_core
@@ -115,7 +115,7 @@ build_rpc_trait! {
/// Sets proxy details for OpenVPN
#[rpc(meta, name = "set_openvpn_proxy")]
- fn set_openvpn_proxy(&self, Self::Metadata, Option<OpenVpnProxySettings>) -> BoxFuture<(), Error>;
+ fn set_openvpn_proxy(&self, Self::Metadata, Option<openvpn::ProxySettings>) -> BoxFuture<(), Error>;
/// Set if IPv6 is enabled in the tunnel
#[rpc(meta, name = "set_enable_ipv6")]
@@ -194,7 +194,7 @@ pub enum ManagementCommand {
/// Set proxy details for OpenVPN
SetOpenVpnProxy(
OneshotSender<Result<(), settings::Error>>,
- Option<OpenVpnProxySettings>,
+ Option<openvpn::ProxySettings>,
),
/// Set if IPv6 should be enabled in the tunnel
SetEnableIpv6(OneshotSender<()>, bool),
@@ -587,7 +587,7 @@ impl<T: From<ManagementCommand> + 'static + Send> ManagementInterfaceApi
fn set_openvpn_proxy(
&self,
_: Self::Metadata,
- proxy: Option<OpenVpnProxySettings>,
+ proxy: Option<openvpn::ProxySettings>,
) -> BoxFuture<(), Error> {
log::debug!("set_openvpn_proxy({:?})", proxy);
let (tx, rx) = sync::oneshot::channel();
diff --git a/mullvad-daemon/src/relays.rs b/mullvad-daemon/src/relays.rs
index 0dba9dd9a3..11c0d49930 100644
--- a/mullvad-daemon/src/relays.rs
+++ b/mullvad-daemon/src/relays.rs
@@ -4,6 +4,7 @@ use futures::Future;
use mullvad_rpc::{HttpHandle, RelayListProxy};
use mullvad_types::{
+ endpoint::{MullvadEndpoint, TunnelEndpointData},
location::Location,
relay_constraints::{
Constraint, LocationConstraint, Match, OpenVpnConstraints, RelayConstraints,
@@ -14,12 +15,11 @@ use mullvad_types::{
use serde_json;
-use talpid_types::net::{TransportProtocol, TunnelEndpoint, TunnelEndpointData};
+use talpid_types::net::TransportProtocol;
use std::{
fs::File,
io,
- net::IpAddr,
path::{Path, PathBuf},
sync::{mpsc, Arc, Mutex, MutexGuard},
thread,
@@ -196,7 +196,7 @@ impl RelaySelector {
&mut self,
constraints: &RelayConstraints,
retry_attempt: u32,
- ) -> Result<(Relay, TunnelEndpoint)> {
+ ) -> Result<(Relay, MullvadEndpoint)> {
let preferred_constraints = Self::preferred_constraints(constraints, retry_attempt);
if let Some((relay, endpoint)) = self.get_tunnel_endpoint_internal(&preferred_constraints) {
debug!(
@@ -264,7 +264,7 @@ impl RelaySelector {
fn get_tunnel_endpoint_internal(
&mut self,
constraints: &RelayConstraints,
- ) -> Option<(Relay, TunnelEndpoint)> {
+ ) -> Option<(Relay, MullvadEndpoint)> {
let matching_relays: Vec<Relay> = self
.lock_parsed_relays()
.relays()
@@ -280,10 +280,8 @@ impl RelaySelector {
);
self.get_random_tunnel(&selected_relay.tunnels)
.map(|tunnel_parameters| {
- let endpoint = TunnelEndpoint {
- address: IpAddr::V4(selected_relay.ipv4_addr_in),
- tunnel: tunnel_parameters,
- };
+ let endpoint = tunnel_parameters
+ .to_mullvad_endpoint(selected_relay.ipv4_addr_in.into());
(selected_relay.clone(), endpoint)
})
})
diff --git a/mullvad-ipc-client/src/lib.rs b/mullvad-ipc-client/src/lib.rs
index 99f9ff6815..d7eaf653ef 100644
--- a/mullvad-ipc-client/src/lib.rs
+++ b/mullvad-ipc-client/src/lib.rs
@@ -12,15 +12,12 @@ use mullvad_types::{
location::GeoIpLocation,
relay_constraints::{RelaySettings, RelaySettingsUpdate},
relay_list::RelayList,
- settings::Settings,
+ settings::{Settings, TunnelOptions},
version::AppVersionInfo,
};
use serde::{Deserialize, Serialize};
use std::{path::Path, sync::mpsc, thread, time::Duration};
-use talpid_types::{
- net::{OpenVpnProxySettings, TunnelOptions},
- tunnel::TunnelStateTransition,
-};
+use talpid_types::{net::openvpn, tunnel::TunnelStateTransition};
pub use jsonrpc_client_core::{Error as RpcError, ErrorKind as RpcErrorKind};
@@ -196,7 +193,7 @@ impl DaemonRpcClient {
self.call("set_openvpn_mssfix", &[mssfix])
}
- pub fn set_openvpn_proxy(&mut self, proxy: Option<OpenVpnProxySettings>) -> Result<()> {
+ pub fn set_openvpn_proxy(&mut self, proxy: Option<openvpn::ProxySettings>) -> Result<()> {
self.call("set_openvpn_proxy", &[proxy])
}
diff --git a/mullvad-types/Cargo.toml b/mullvad-types/Cargo.toml
index 8239696b9b..c0202ed1b6 100644
--- a/mullvad-types/Cargo.toml
+++ b/mullvad-types/Cargo.toml
@@ -14,6 +14,7 @@ error-chain = "0.12"
log = "0.4"
regex = "1"
lazy_static = "1.1.0"
+ipnetwork = "0.13"
talpid-types = { path = "../talpid-types" }
mullvad-paths = { path = "../mullvad-paths" }
diff --git a/mullvad-types/src/custom_tunnel.rs b/mullvad-types/src/custom_tunnel.rs
index 475dfa2eaf..83211ba64a 100644
--- a/mullvad-types/src/custom_tunnel.rs
+++ b/mullvad-types/src/custom_tunnel.rs
@@ -1,40 +1,77 @@
+use crate::settings::TunnelOptions;
use serde::{Deserialize, Serialize};
use std::{
fmt,
- net::{IpAddr, ToSocketAddrs},
+ net::{IpAddr, SocketAddr, ToSocketAddrs},
};
-use talpid_types::net::{TunnelEndpoint, TunnelEndpointData};
+use talpid_types::net::{openvpn, wireguard, TunnelParameters};
error_chain! {
errors {
InvalidHost(host: String) {
display("Invalid host: {}", host)
}
+ Unsupported {
+ description("Tunnel type not supported")
+ }
}
}
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
pub struct CustomTunnelEndpoint {
- pub host: String,
- pub tunnel: TunnelEndpointData,
+ host: String,
+ config: ConnectionConfig,
}
impl CustomTunnelEndpoint {
- pub fn to_tunnel_endpoint(&self) -> Result<TunnelEndpoint> {
- Ok(TunnelEndpoint {
- address: resolve_to_ip(&self.host)?,
- tunnel: self.tunnel.clone(),
- })
+ pub fn new(host: String, config: ConnectionConfig) -> Self {
+ Self { host, config }
+ }
+
+ pub fn to_tunnel_parameters(&self, tunnel_options: TunnelOptions) -> Result<TunnelParameters> {
+ let ip = resolve_to_ip(&self.host)?;
+ let mut config = self.config.clone();
+ config.set_ip(ip);
+
+ let parameters = match config {
+ ConnectionConfig::OpenVpn(config) => openvpn::TunnelParameters {
+ config,
+ options: tunnel_options.openvpn.clone(),
+ generic_options: tunnel_options.generic.clone(),
+ }
+ .into(),
+ ConnectionConfig::Wireguard(connection) => wireguard::TunnelParameters {
+ connection,
+ options: tunnel_options.wireguard.clone(),
+ generic_options: tunnel_options.generic.clone(),
+ }
+ .into(),
+ };
+ Ok(parameters)
}
}
impl fmt::Display for CustomTunnelEndpoint {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "{} over {}", self.host, self.tunnel)
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match &self.config {
+ ConnectionConfig::OpenVpn(config) => write!(
+ f,
+ "OpenVPN relay - {}:{} {}",
+ self.host,
+ config.endpoint.address.port(),
+ config.endpoint.protocol
+ ),
+ ConnectionConfig::Wireguard(connection) => write!(
+ f,
+ "WireGuard relay - {} with public key {}",
+ connection.peer.endpoint, connection.peer.public_key
+ ),
+ }
}
}
+
/// Does a DNS lookup if the host isn't an IP.
/// Returns the first IPv4 address if one exists, otherwise the first IPv6 address.
/// Rust only provides means to resolve a socket addr, not just a host, for some reason. So
@@ -53,3 +90,25 @@ fn resolve_to_ip(host: &str) -> Result<IpAddr> {
})
.ok_or_else(|| ErrorKind::InvalidHost(host.to_owned()).into())
}
+
+#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
+#[serde(rename = "connection_config")]
+pub enum ConnectionConfig {
+ #[serde(rename = "openvpn")]
+ OpenVpn(openvpn::ConnectionConfig),
+ #[serde(rename = "wireguard")]
+ Wireguard(wireguard::ConnectionConfig),
+}
+
+impl ConnectionConfig {
+ fn set_ip(&mut self, ip: IpAddr) {
+ match self {
+ ConnectionConfig::OpenVpn(config) => {
+ config.endpoint.address = SocketAddr::new(ip, config.endpoint.address.port());
+ }
+ ConnectionConfig::Wireguard(config) => {
+ config.peer.endpoint = SocketAddr::new(ip, config.peer.endpoint.port())
+ }
+ }
+ }
+}
diff --git a/mullvad-types/src/endpoint.rs b/mullvad-types/src/endpoint.rs
new file mode 100644
index 0000000000..311ca267ba
--- /dev/null
+++ b/mullvad-types/src/endpoint.rs
@@ -0,0 +1,111 @@
+use ipnetwork::IpNetwork;
+use serde::{Deserialize, Serialize};
+use std::{
+ fmt,
+ net::{IpAddr, SocketAddr},
+};
+use talpid_types::net::{wireguard, Endpoint, TransportProtocol};
+
+use crate::relay_list::{OpenVpnEndpointData, WireguardEndpointData};
+
+/// Contains server data needed to conenct to a single mullvad endpoint
+#[derive(Debug, Clone)]
+pub enum MullvadEndpoint {
+ OpenVpn(Endpoint),
+ Wireguard {
+ peer: wireguard::PeerConfig,
+ gateway: IpAddr,
+ },
+}
+
+impl MullvadEndpoint {
+ /// Returns this tunnel endpoint as an `Endpoint`.
+ pub fn to_endpoint(&self) -> Endpoint {
+ match self {
+ MullvadEndpoint::OpenVpn(endpoint) => *endpoint,
+ MullvadEndpoint::Wireguard { peer, gateway: _ } => Endpoint::new(
+ peer.endpoint.ip(),
+ peer.endpoint.port(),
+ TransportProtocol::Udp,
+ ),
+ }
+ }
+}
+/// TunnelEndpointData contains data required to connect to a given tunnel endpoint.
+/// Different endpoint types can require different types of data.
+#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)]
+pub enum TunnelEndpointData {
+ /// Extra parameters for an OpenVPN tunnel endpoint.
+ #[serde(rename = "openvpn")]
+ OpenVpn(OpenVpnEndpointData),
+ /// Extra parameters for a Wireguard tunnel endpoint.
+ #[serde(rename = "wireguard")]
+ Wireguard(WireguardEndpointData),
+}
+impl From<OpenVpnEndpointData> for TunnelEndpointData {
+ fn from(endpoint_data: OpenVpnEndpointData) -> TunnelEndpointData {
+ TunnelEndpointData::OpenVpn(endpoint_data)
+ }
+}
+
+impl From<WireguardEndpointData> for TunnelEndpointData {
+ fn from(endpoint_data: WireguardEndpointData) -> TunnelEndpointData {
+ TunnelEndpointData::Wireguard(endpoint_data)
+ }
+}
+
+impl fmt::Display for TunnelEndpointData {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
+ match self {
+ TunnelEndpointData::OpenVpn(openvpn_data) => {
+ write!(f, "OpenVPN ")?;
+ openvpn_data.fmt(f)
+ }
+ TunnelEndpointData::Wireguard(wireguard_data) => {
+ write!(f, "Wireguard ")?;
+ wireguard_data.fmt(f)
+ }
+ }
+ }
+}
+
+impl TunnelEndpointData {
+ pub fn to_mullvad_endpoint(self, host: IpAddr) -> MullvadEndpoint {
+ match self {
+ TunnelEndpointData::OpenVpn(metadata) => {
+ MullvadEndpoint::OpenVpn(Endpoint::new(host, metadata.port, metadata.protocol))
+ }
+ TunnelEndpointData::Wireguard(metadata) => {
+ let peer_config = wireguard::PeerConfig {
+ public_key: metadata.peer_public_key,
+ endpoint: SocketAddr::new(host, metadata.port),
+ allowed_ips: all_of_the_internet(),
+ };
+ MullvadEndpoint::Wireguard {
+ peer: peer_config,
+ gateway: metadata.gateway,
+ }
+ }
+ }
+ }
+ pub fn port(&self) -> u16 {
+ match self {
+ TunnelEndpointData::OpenVpn(metadata) => metadata.port,
+ TunnelEndpointData::Wireguard(metadata) => metadata.port,
+ }
+ }
+
+ pub fn transport_protocol(&self) -> TransportProtocol {
+ match self {
+ TunnelEndpointData::OpenVpn(metadata) => metadata.protocol,
+ TunnelEndpointData::Wireguard(_) => TransportProtocol::Udp,
+ }
+ }
+}
+
+fn all_of_the_internet() -> Vec<IpNetwork> {
+ vec![
+ "0.0.0.0/0".parse().expect("Failed to parse ipv6 network"),
+ "::0/0".parse().expect("Failed to parse ipv6 network"),
+ ]
+}
diff --git a/mullvad-types/src/lib.rs b/mullvad-types/src/lib.rs
index a972719460..11e6ac4005 100644
--- a/mullvad-types/src/lib.rs
+++ b/mullvad-types/src/lib.rs
@@ -11,6 +11,7 @@ extern crate error_chain;
pub mod account;
pub mod auth_failed;
+pub mod endpoint;
pub mod location;
pub mod relay_constraints;
pub mod relay_list;
diff --git a/mullvad-types/src/relay_constraints.rs b/mullvad-types/src/relay_constraints.rs
index 52f22a9229..41305115c2 100644
--- a/mullvad-types/src/relay_constraints.rs
+++ b/mullvad-types/src/relay_constraints.rs
@@ -1,10 +1,11 @@
use crate::{
location::{CityCode, CountryCode, Hostname},
+ relay_list::{OpenVpnEndpointData, WireguardEndpointData},
CustomTunnelEndpoint,
};
use serde::{Deserialize, Serialize};
use std::fmt;
-use talpid_types::net::{OpenVpnEndpointData, TransportProtocol, WireguardEndpointData};
+use talpid_types::net::TransportProtocol;
pub trait Match<T> {
diff --git a/mullvad-types/src/relay_list.rs b/mullvad-types/src/relay_list.rs
index bc5d66eb80..1e16dcb6ba 100644
--- a/mullvad-types/src/relay_list.rs
+++ b/mullvad-types/src/relay_list.rs
@@ -1,7 +1,10 @@
use crate::location::{CityCode, CountryCode, Location};
use serde::{Deserialize, Serialize};
-use std::net::Ipv4Addr;
-use talpid_types::net::{OpenVpnEndpointData, WireguardEndpointData};
+use std::{
+ fmt,
+ net::{IpAddr, Ipv4Addr},
+};
+use talpid_types::net::{wireguard, TransportProtocol};
#[derive(Debug, Clone, Deserialize, Serialize)]
@@ -63,3 +66,45 @@ impl RelayTunnels {
self.wireguard.clear();
}
}
+
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Deserialize, Serialize)]
+pub struct OpenVpnEndpointData {
+ pub port: u16,
+ pub protocol: TransportProtocol,
+}
+
+impl fmt::Display for OpenVpnEndpointData {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
+ write!(f, "{} port {}", self.protocol, self.port)
+ }
+}
+
+#[derive(Clone, Eq, PartialEq, Hash, Deserialize, Serialize)]
+pub struct WireguardEndpointData {
+ /// Port to connect to
+ pub port: u16,
+ /// Peer's IP address
+ pub gateway: IpAddr,
+ /// The peer's public key
+ pub peer_public_key: wireguard::PublicKey,
+}
+
+impl fmt::Debug for WireguardEndpointData {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
+ f.debug_struct(&"WireguardEndpointData")
+ .field("port", &self.port)
+ .field("gateway", &self.gateway)
+ .field("peer_public_key", &self.peer_public_key)
+ .finish()
+ }
+}
+
+impl fmt::Display for WireguardEndpointData {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
+ write!(
+ f,
+ "gateway {} port {} peer_public_key {}",
+ self.gateway, self.port, self.peer_public_key,
+ )
+ }
+}
diff --git a/mullvad-types/src/settings.rs b/mullvad-types/src/settings.rs
index 70f5d6b35e..cfc445b3c9 100644
--- a/mullvad-types/src/settings.rs
+++ b/mullvad-types/src/settings.rs
@@ -5,7 +5,7 @@ use log::{debug, info};
use serde::{Deserialize, Serialize};
use serde_json;
use std::{fs::File, io, path::PathBuf};
-use talpid_types::net::{OpenVpnProxySettings, OpenVpnProxySettingsValidation, TunnelOptions};
+use talpid_types::net::{openvpn, wireguard, GenericTunnelOptions};
error_chain! {
errors {
@@ -201,9 +201,9 @@ impl Settings {
}
}
- pub fn set_openvpn_proxy(&mut self, proxy: Option<OpenVpnProxySettings>) -> Result<bool> {
+ pub fn set_openvpn_proxy(&mut self, proxy: Option<openvpn::ProxySettings>) -> Result<bool> {
if let Some(ref settings) = proxy {
- if let Err(validation_error) = OpenVpnProxySettingsValidation::validate(settings) {
+ if let Err(validation_error) = openvpn::ProxySettingsValidation::validate(settings) {
bail!(ErrorKind::InvalidProxyData(validation_error));
}
}
@@ -217,8 +217,8 @@ impl Settings {
}
pub fn set_enable_ipv6(&mut self, enable_ipv6: bool) -> Result<bool> {
- if self.tunnel_options.enable_ipv6 != enable_ipv6 {
- self.tunnel_options.enable_ipv6 = enable_ipv6;
+ if self.tunnel_options.generic.enable_ipv6 != enable_ipv6 {
+ self.tunnel_options.generic.enable_ipv6 = enable_ipv6;
self.save().map(|_| true)
} else {
Ok(false)
@@ -229,3 +229,29 @@ impl Settings {
&self.tunnel_options
}
}
+
+/// TunnelOptions holds configuration data that applies to all kinds of tunnels.
+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
+#[serde(default)]
+pub struct TunnelOptions {
+ /// openvpn holds OpenVPN specific tunnel options.
+ pub openvpn: openvpn::TunnelOptions,
+ /// Contains wireguard tunnel options.
+ pub wireguard: wireguard::TunnelOptions,
+ /// Contains generic tunnel options that may apply to more than a single tunnel type.
+ pub generic: GenericTunnelOptions,
+}
+
+impl Default for TunnelOptions {
+ fn default() -> Self {
+ TunnelOptions {
+ openvpn: openvpn::TunnelOptions::default(),
+ wireguard: wireguard::TunnelOptions {
+ mtu: None,
+ #[cfg(target_os = "linux")]
+ fwmark: 78_78_78,
+ },
+ generic: GenericTunnelOptions { enable_ipv6: false },
+ }
+ }
+}
diff --git a/talpid-core/src/process/openvpn.rs b/talpid-core/src/process/openvpn.rs
index 104471db2b..a55d5d3453 100644
--- a/talpid-core/src/process/openvpn.rs
+++ b/talpid-core/src/process/openvpn.rs
@@ -61,7 +61,7 @@ pub struct OpenVpnCommand {
iproute_bin: Option<OsString>,
plugin: Option<(PathBuf, Vec<String>)>,
log: Option<PathBuf>,
- tunnel_options: net::OpenVpnTunnelOptions,
+ tunnel_options: net::openvpn::TunnelOptions,
tunnel_alias: Option<OsString>,
enable_ipv6: bool,
}
@@ -81,7 +81,7 @@ impl OpenVpnCommand {
iproute_bin: None,
plugin: None,
log: None,
- tunnel_options: net::OpenVpnTunnelOptions::default(),
+ tunnel_options: net::openvpn::TunnelOptions::default(),
tunnel_alias: None,
enable_ipv6: true,
}
@@ -150,7 +150,7 @@ impl OpenVpnCommand {
}
/// Sets extra options
- pub fn tunnel_options(&mut self, tunnel_options: &net::OpenVpnTunnelOptions) -> &mut Self {
+ pub fn tunnel_options(&mut self, tunnel_options: &net::openvpn::TunnelOptions) -> &mut Self {
self.tunnel_options = tunnel_options.clone();
self
}
@@ -275,7 +275,7 @@ impl OpenVpnCommand {
fn proxy_arguments(&self) -> Vec<String> {
let mut args = vec![];
match self.tunnel_options.proxy {
- Some(net::OpenVpnProxySettings::Local(ref local_proxy)) => {
+ Some(net::openvpn::ProxySettings::Local(ref local_proxy)) => {
args.push("--socks-proxy".to_owned());
args.push("127.0.0.1".to_owned());
args.push(local_proxy.port.to_string());
@@ -284,7 +284,7 @@ impl OpenVpnCommand {
args.push("255.255.255.255".to_owned());
args.push("net_gateway".to_owned());
}
- Some(net::OpenVpnProxySettings::Remote(ref remote_proxy)) => {
+ Some(net::openvpn::ProxySettings::Remote(ref remote_proxy)) => {
args.push("--socks-proxy".to_owned());
args.push(remote_proxy.address.ip().to_string());
args.push(remote_proxy.address.port().to_string());
diff --git a/talpid-core/src/security/macos/mod.rs b/talpid-core/src/security/macos/mod.rs
index b4d300e66f..cc14fbfd6e 100644
--- a/talpid-core/src/security/macos/mod.rs
+++ b/talpid-core/src/security/macos/mod.rs
@@ -1,6 +1,9 @@
use super::{NetworkSecurityT, SecurityPolicy};
use pfctl::FilterRuleAction;
-use std::{env, net::Ipv4Addr};
+use std::{
+ env,
+ net::{Ipv4Addr, SocketAddr},
+};
use talpid_types::net;
mod dns;
diff --git a/talpid-core/src/tunnel/mod.rs b/talpid-core/src/tunnel/mod.rs
index 4011db3e84..c0f1abcde2 100644
--- a/talpid-core/src/tunnel/mod.rs
+++ b/talpid-core/src/tunnel/mod.rs
@@ -6,7 +6,9 @@ use std::{
path::{Path, PathBuf},
};
-use talpid_types::net::{TunnelEndpoint, TunnelEndpointData, TunnelOptions};
+#[cfg(unix)]
+use talpid_types::net::wireguard as wireguard_types;
+use talpid_types::net::{openvpn as openvpn_types, GenericTunnelOptions, TunnelParameters};
/// A module for all OpenVPN related tunnel management.
pub mod openvpn;
@@ -113,10 +115,8 @@ impl TunnelMonitor {
/// Creates a new `TunnelMonitor` that connects to the given remote and notifies `on_event`
/// on tunnel state changes.
pub fn start<L>(
- tunnel_endpoint: TunnelEndpoint,
- tunnel_options: &TunnelOptions,
+ tunnel_parameters: &TunnelParameters,
tunnel_alias: Option<OsString>,
- username: &str,
log: Option<PathBuf>,
resource_dir: &Path,
on_event: L,
@@ -124,60 +124,46 @@ impl TunnelMonitor {
where
L: Fn(TunnelEvent) + Send + Sync + 'static,
{
- Self::ensure_ipv6_can_be_used_if_enabled(tunnel_options)?;
- match &tunnel_endpoint.tunnel {
- TunnelEndpointData::OpenVpn(_) => Self::start_openvpn_tunnel(
- tunnel_endpoint,
- tunnel_options,
- tunnel_alias,
- username,
- log,
- resource_dir,
- on_event,
- ),
+ Self::ensure_ipv6_can_be_used_if_enabled(&tunnel_parameters.get_generic_options())?;
+
+ match tunnel_parameters {
+ TunnelParameters::OpenVpn(config) => {
+ Self::start_openvpn_tunnel(&config, tunnel_alias, log, resource_dir, on_event)
+ }
#[cfg(unix)]
- TunnelEndpointData::Wireguard(_) => {
- Self::start_wireguard_tunnel(tunnel_endpoint, tunnel_options, log, on_event)
+ TunnelParameters::Wireguard(config) => {
+ Self::start_wireguard_tunnel(&config, log, on_event)
}
#[cfg(windows)]
- TunnelEndpointData::Wireguard(_) => bail!(ErrorKind::UnsupportedPlatform),
+ TunnelParameters::Wireguard(_) => bail!(ErrorKind::UnsupportedPlatform),
}
}
#[cfg(unix)]
fn start_wireguard_tunnel<L>(
- tunnel_endpoint: TunnelEndpoint,
- tunnel_options: &TunnelOptions,
+ params: &wireguard_types::TunnelParameters,
log: Option<PathBuf>,
on_event: L,
) -> Result<Self>
where
L: Fn(TunnelEvent) + Send + Sync + 'static,
{
- let TunnelEndpoint { address, tunnel } = tunnel_endpoint;
- let data = match tunnel {
- TunnelEndpointData::Wireguard(data) => data,
- _ => unreachable!("expected wireguard endpoint data"),
- };
-
+ let config = wireguard::config::Config::from_parameters(&params)
+ .chain_err(|| ErrorKind::TunnelMonitoringError)?;
let monitor = wireguard::WireguardMonitor::start(
- address,
- data,
- tunnel_options,
+ &config,
log.as_ref().map(|p| p.as_path()),
on_event,
)
- .chain_err(|| ErrorKind::TunnelMonitoringError)?;
+ .chain_err(|| ErrorKind::TunnelMonitorSetUpError)?;
Ok(TunnelMonitor {
monitor: InternalTunnelMonitor::Wireguard(monitor),
})
}
fn start_openvpn_tunnel<L>(
- tunnel_endpoint: TunnelEndpoint,
- tunnel_options: &TunnelOptions,
+ config: &openvpn_types::TunnelParameters,
tunnel_alias: Option<OsString>,
- username: &str,
log: Option<PathBuf>,
resource_dir: &Path,
on_event: L,
@@ -185,22 +171,15 @@ impl TunnelMonitor {
where
L: Fn(TunnelEvent) + Send + Sync + 'static,
{
- let monitor = openvpn::OpenVpnMonitor::start(
- on_event,
- tunnel_endpoint.to_endpoint(),
- tunnel_options,
- tunnel_alias,
- log,
- resource_dir,
- username,
- )
- .chain_err(|| ErrorKind::TunnelMonitorSetUpError)?;
+ let monitor =
+ openvpn::OpenVpnMonitor::start(on_event, config, tunnel_alias, log, resource_dir)
+ .chain_err(|| ErrorKind::TunnelMonitorSetUpError)?;
Ok(TunnelMonitor {
monitor: InternalTunnelMonitor::OpenVpn(monitor),
})
}
- fn ensure_ipv6_can_be_used_if_enabled(tunnel_options: &TunnelOptions) -> Result<()> {
+ fn ensure_ipv6_can_be_used_if_enabled(tunnel_options: &GenericTunnelOptions) -> Result<()> {
if tunnel_options.enable_ipv6 && !is_ipv6_enabled_in_os() {
bail!(ErrorKind::EnableIpv6Error);
} else {
diff --git a/talpid-core/src/tunnel/openvpn.rs b/talpid-core/src/tunnel/openvpn.rs
index fadb035966..38aee11755 100644
--- a/talpid-core/src/tunnel/openvpn.rs
+++ b/talpid-core/src/tunnel/openvpn.rs
@@ -23,7 +23,7 @@ use std::{
time::Duration,
};
use talpid_ipc;
-use talpid_types::net::{Endpoint, OpenVpnProxySettings, TunnelOptions};
+use talpid_types::net::openvpn;
#[cfg(target_os = "linux")]
use which;
@@ -107,20 +107,19 @@ impl OpenVpnMonitor<OpenVpnCommand> {
/// path.
pub fn start<L>(
on_event: L,
- endpoint: Endpoint,
- tunnel_options: &TunnelOptions,
+ params: &openvpn::TunnelParameters,
tunnel_alias: Option<OsString>,
log_path: Option<PathBuf>,
resource_dir: &Path,
- username: &str,
) -> Result<Self>
where
L: Fn(TunnelEvent) + Send + Sync + 'static,
{
- let user_pass_file = Self::create_credentials_file(username, "-")
- .chain_err(|| ErrorKind::CredentialsWriteError)?;
+ let user_pass_file =
+ Self::create_credentials_file(&params.config.username, &params.config.password)
+ .chain_err(|| ErrorKind::CredentialsWriteError)?;
- let proxy_auth_file = Self::create_proxy_auth_file(&tunnel_options.openvpn.proxy)
+ let proxy_auth_file = Self::create_proxy_auth_file(&params.options.proxy)
.chain_err(|| ErrorKind::CredentialsWriteError)?;
@@ -147,9 +146,8 @@ impl OpenVpnMonitor<OpenVpnCommand> {
}
};
let cmd = Self::create_openvpn_cmd(
- endpoint,
+ params,
tunnel_alias,
- &tunnel_options,
user_pass_file.as_ref(),
match proxy_auth_file {
Some(ref file) => Some(file.as_ref()),
@@ -293,9 +291,9 @@ impl<C: OpenVpnBuilder> OpenVpnMonitor<C> {
}
fn create_proxy_auth_file(
- proxy: &Option<OpenVpnProxySettings>,
+ proxy: &Option<openvpn::ProxySettings>,
) -> ::std::result::Result<Option<mktemp::TempFile>, io::Error> {
- if let Some(OpenVpnProxySettings::Remote(ref remote_proxy)) = proxy {
+ if let Some(openvpn::ProxySettings::Remote(ref remote_proxy)) = proxy {
if let Some(ref proxy_auth) = remote_proxy.auth {
return Ok(Some(Self::create_credentials_file(
&proxy_auth.username,
@@ -339,9 +337,8 @@ impl<C: OpenVpnBuilder> OpenVpnMonitor<C> {
}
fn create_openvpn_cmd(
- remote: Endpoint,
+ params: &openvpn::TunnelParameters,
tunnel_alias: Option<OsString>,
- options: &TunnelOptions,
user_pass_file: &Path,
proxy_auth_file: Option<&Path>,
resource_dir: &Path,
@@ -356,10 +353,10 @@ impl<C: OpenVpnBuilder> OpenVpnMonitor<C> {
.compat()
.chain_err(|| ErrorKind::IpRouteNotFound)?,
);
- cmd.remote(remote)
+ cmd.remote(params.config.get_tunnel_endpoint().endpoint)
.user_pass(user_pass_file)
- .tunnel_options(&options.openvpn)
- .enable_ipv6(options.enable_ipv6)
+ .tunnel_options(&params.options)
+ .enable_ipv6(params.generic_options.enable_ipv6)
.tunnel_alias(tunnel_alias)
.ca(resource_dir.join("ca.crt"));
if let Some(proxy_auth_file) = proxy_auth_file {
diff --git a/talpid-core/src/tunnel/wireguard/config.rs b/talpid-core/src/tunnel/wireguard/config.rs
index a99e46994f..a15f377165 100644
--- a/talpid-core/src/tunnel/wireguard/config.rs
+++ b/talpid-core/src/tunnel/wireguard/config.rs
@@ -1,60 +1,83 @@
-use super::{ErrorKind, Result};
-use ipnetwork::IpNetwork;
-use std::{
- borrow::Cow,
- ffi::CString,
- net::{IpAddr, SocketAddr},
-};
-use talpid_types::net::{TunnelOptions, WgPrivateKey, WgPublicKey, WireguardEndpointData};
+use std::{borrow::Cow, ffi::CString, net::IpAddr};
+use talpid_types::net::{wireguard, GenericTunnelOptions};
pub struct Config {
- pub interface: TunnelConfig,
+ pub tunnel: wireguard::TunnelConfig,
+ pub peers: Vec<wireguard::PeerConfig>,
pub gateway: IpAddr,
- pub preferred_name: Option<String>,
+ pub mtu: u16,
+ #[cfg(target_os = "linux")]
+ pub fwmark: i32,
+}
+
+/// Smallest MTU that supports IPv6
+const SMALLEST_IPV6_MTU: u16 = 1420;
+const DEFAULT_MTU: u16 = SMALLEST_IPV6_MTU;
+
+error_chain! {
+ errors {
+ InvalidTunnelIpError {
+ description("No valid tunnel IP"),
+ }
+
+ InvalidPeerIpError {
+ description("Supplied peer has no valid IPs")
+ }
+
+ NoPeersSuppliedError{
+ description("No peers supplied")
+ }
+ }
}
-// Smallest MTU that supports IPv6
-const MIN_IPV6_MTU: u16 = 1420;
-const DEFAULT_MTU: u16 = MIN_IPV6_MTU;
impl Config {
- pub fn from_data(
- ip: IpAddr,
- data: WireguardEndpointData,
- options: &TunnelOptions,
+ pub fn from_parameters(params: &wireguard::TunnelParameters) -> Result<Config> {
+ let tunnel = params.connection.tunnel.clone();
+ let peer = vec![params.connection.peer.clone()];
+ Self::new(
+ tunnel,
+ peer,
+ params.connection.gateway,
+ &params.options,
+ &params.generic_options,
+ )
+ }
+
+ pub fn new(
+ mut tunnel: wireguard::TunnelConfig,
+ mut peers: Vec<wireguard::PeerConfig>,
+ gateway: IpAddr,
+ wg_options: &wireguard::TunnelOptions,
+ generic_options: &GenericTunnelOptions,
) -> Result<Config> {
- let private_key = match data.client_private_key {
- Some(private_key) => private_key,
- None => bail!(ErrorKind::NoKeyError),
- };
+ ensure!(peers.is_empty(), ErrorKind::NoPeersSuppliedError);
+ let mtu = wg_options.mtu.unwrap_or(DEFAULT_MTU);
+ let is_ipv6_enabled = mtu >= SMALLEST_IPV6_MTU && generic_options.enable_ipv6;
- let mtu = options.wireguard.mtu.unwrap_or(DEFAULT_MTU);
- let ipv6_enabled = options.enable_ipv6 && mtu >= MIN_IPV6_MTU;
- let peer = PeerConfig {
- public_key: data.peer_public_key,
- allowed_ips: all_of_the_internet()
- .into_iter()
- .filter(|ip| ip.is_ipv4() || ipv6_enabled)
- .collect(),
- endpoint: SocketAddr::new(ip, data.port),
- };
+ for peer in &mut peers {
+ peer.allowed_ips = peer
+ .allowed_ips
+ .iter()
+ .cloned()
+ .filter(|ip| ip.is_ipv4() || is_ipv6_enabled)
+ .collect();
+ ensure!(peer.allowed_ips.is_empty(), ErrorKind::InvalidPeerIpError);
+ }
- let tunnel_config = TunnelConfig {
- private_key,
- addresses: data
- .addresses
- .into_iter()
- .filter(|ip| ip.is_ipv4() || ipv6_enabled)
- .collect(),
- mtu,
- #[cfg(target_os = "linux")]
- fwmark: options.wireguard.fwmark,
- peers: vec![peer],
- };
+ tunnel.addresses = tunnel
+ .addresses
+ .into_iter()
+ .filter(|ip| ip.is_ipv4() || is_ipv6_enabled)
+ .collect();
+ ensure!(tunnel.addresses.is_empty(), ErrorKind::InvalidTunnelIpError);
Ok(Config {
- interface: tunnel_config,
- gateway: data.gateway,
- preferred_name: Some("talpid".to_string()),
+ tunnel,
+ peers,
+ gateway,
+ mtu,
+ #[cfg(target_os = "linux")]
+ fwmark: wg_options.fwmark,
})
}
@@ -63,20 +86,17 @@ impl Config {
// the order of insertion matters, public key entry denotes a new peer entry
let mut wg_conf = WgConfigBuffer::new();
wg_conf
- .add(
- "private_key",
- self.interface.private_key.as_bytes().as_ref(),
- )
+ .add("private_key", self.tunnel.private_key.as_bytes().as_ref())
.add("listen_port", "0");
#[cfg(target_os = "linux")]
{
- wg_conf.add("fwmark", self.interface.fwmark.to_string().as_str());
+ wg_conf.add("fwmark", self.fwmark.to_string().as_str());
}
wg_conf.add("replace_peers", "true");
- for peer in &self.interface.peers {
+ for peer in &self.peers {
wg_conf
.add("public_key", peer.public_key.as_bytes().as_ref())
.add("endpoint", peer.endpoint.to_string().as_str())
@@ -91,29 +111,6 @@ impl Config {
}
}
-pub struct PeerConfig {
- pub public_key: WgPublicKey,
- pub allowed_ips: Vec<IpNetwork>,
- pub endpoint: SocketAddr,
-}
-
-pub struct TunnelConfig {
- pub private_key: WgPrivateKey,
- pub addresses: Vec<IpAddr>,
- #[cfg(target_os = "linux")]
- pub fwmark: i32,
- pub mtu: u16,
- pub peers: Vec<PeerConfig>,
-}
-
-
-fn all_of_the_internet() -> Vec<IpNetwork> {
- vec![
- "::0/0".parse().expect("Failed to parse ipv6 network"),
- "0.0.0.0/0".parse().expect("Failed to parse ipv4 network"),
- ]
-}
-
pub enum ConfValue<'a> {
String(&'a str),
Bytes(&'a [u8]),
diff --git a/talpid-core/src/tunnel/wireguard/mod.rs b/talpid-core/src/tunnel/wireguard/mod.rs
index c74dc8d41e..cc60f71c38 100644
--- a/talpid-core/src/tunnel/wireguard/mod.rs
+++ b/talpid-core/src/tunnel/wireguard/mod.rs
@@ -1,8 +1,7 @@
use self::config::Config;
use super::{TunnelEvent, TunnelMetadata};
use crate::routing;
-use std::{net::IpAddr, path::Path, sync::mpsc};
-use talpid_types::net::{TunnelOptions, WireguardEndpointData};
+use std::{path::Path, sync::mpsc};
pub mod config;
mod ping_monitor;
@@ -15,6 +14,10 @@ const PING_TIMEOUT: u16 = 5;
error_chain! {
errors {
+ /// Config error
+ ConfigError{
+ description("Invalid configuration")
+ }
/// Failed to setup a tunnel device
SetupTunnelDeviceError {
description("Failed to create tunnel device")
@@ -64,13 +67,10 @@ pub struct WireguardMonitor {
impl WireguardMonitor {
pub fn start<F: Fn(TunnelEvent) + Send + Sync + 'static>(
- address: IpAddr,
- data: WireguardEndpointData,
- options: &TunnelOptions,
+ config: &Config,
log_path: Option<&Path>,
on_event: F,
) -> Result<WireguardMonitor> {
- let config = Config::from_data(address, data.clone(), options)?;
let tunnel = Box::new(WgGoTunnel::start_tunnel(&config, log_path)?);
let router = routing::RouteManager::new().chain_err(|| ErrorKind::SetupRoutingError)?;
let event_callback = Box::new(on_event);
@@ -84,7 +84,7 @@ impl WireguardMonitor {
};
monitor.setup_routing(&config)?;
monitor.start_pinger(&config);
- monitor.tunnel_up(data);
+ monitor.tunnel_up(&config);
Ok(monitor)
}
@@ -111,7 +111,6 @@ impl WireguardMonitor {
fn setup_routing(&mut self, config: &Config) -> Result<()> {
let iface_name = self.tunnel.get_interface_name();
let mut routes: Vec<_> = config
- .interface
.peers
.iter()
.flat_map(|peer| peer.allowed_ips.iter())
@@ -129,11 +128,12 @@ impl WireguardMonitor {
.router
.get_default_route_node()
.chain_err(|| ErrorKind::SetupRoutingError)?;
+
// route endpoints with specific routes
- for peer in config.interface.peers.iter() {
+ for peer in config.peers.iter() {
let default_route = routing::Route::new(
- peer.endpoint.ip().clone().into(),
- routing::NetNode::Address(default_node.clone()),
+ peer.endpoint.ip().into(),
+ routing::NetNode::Address(default_node),
);
routes.push(default_route);
}
@@ -142,7 +142,7 @@ impl WireguardMonitor {
let required_routes = routing::RequiredRoutes {
routes,
#[cfg(target_os = "linux")]
- fwmark: Some(config.interface.fwmark.to_string()),
+ fwmark: Some(config.fwmark.to_string()),
};
self.router
.add_routes(required_routes)
@@ -162,12 +162,12 @@ impl WireguardMonitor {
)
}
- fn tunnel_up(&self, data: WireguardEndpointData) {
+ fn tunnel_up(&self, config: &Config) {
let interface_name = self.tunnel.get_interface_name();
let metadata = TunnelMetadata {
interface: interface_name.to_string(),
- ips: data.addresses,
- gateway: data.gateway,
+ ips: config.tunnel.addresses.clone(),
+ gateway: config.gateway,
};
(self.event_callback)(TunnelEvent::Up(metadata));
}
diff --git a/talpid-core/src/tunnel/wireguard/wireguard_go.rs b/talpid-core/src/tunnel/wireguard/wireguard_go.rs
index 32d82889cc..e9531e88be 100644
--- a/talpid-core/src/tunnel/wireguard/wireguard_go.rs
+++ b/talpid-core/src/tunnel/wireguard/wireguard_go.rs
@@ -20,7 +20,7 @@ impl WgGoTunnel {
let mut tunnel_device =
TunnelDevice::new().chain_err(|| ErrorKind::SetupTunnelDeviceError)?;
- for ip in config.interface.addresses.iter() {
+ for ip in config.tunnel.addresses.iter() {
tunnel_device
.set_ip(*ip)
.chain_err(|| ErrorKind::SetupTunnelDeviceError)?;
@@ -40,7 +40,7 @@ impl WgGoTunnel {
let handle = unsafe {
wgTurnOnWithFd(
iface_name.as_ptr(),
- config.interface.mtu as i64,
+ config.mtu as i64,
wg_config_str.as_ptr(),
tunnel_device.as_raw_fd(),
log_file.as_raw_fd(),
diff --git a/talpid-core/src/tunnel_state_machine/connected_state.rs b/talpid-core/src/tunnel_state_machine/connected_state.rs
index 4a65e7fadd..b5a88c7181 100644
--- a/talpid-core/src/tunnel_state_machine/connected_state.rs
+++ b/talpid-core/src/tunnel_state_machine/connected_state.rs
@@ -4,14 +4,14 @@ use futures::{
Async, Future, Stream,
};
use talpid_types::{
- net::{Endpoint, OpenVpnProxySettings, TransportProtocol},
+ net::{Endpoint, TunnelParameters},
tunnel::BlockReason,
};
use super::{
AfterDisconnect, BlockedState, ConnectingState, DisconnectingState, EventConsequence, Result,
- ResultExt, SharedTunnelStateValues, TunnelCommand, TunnelParameters, TunnelState,
- TunnelStateTransition, TunnelStateWrapper,
+ ResultExt, SharedTunnelStateValues, TunnelCommand, TunnelState, TunnelStateTransition,
+ TunnelStateWrapper,
};
use crate::{
security::SecurityPolicy,
@@ -48,17 +48,7 @@ impl ConnectedState {
fn set_security_policy(&self, shared_values: &mut SharedTunnelStateValues) -> Result<()> {
// If a proxy is specified we need to pass it on as the peer endpoint.
- let peer_endpoint = match self.tunnel_parameters.options.openvpn.proxy {
- Some(OpenVpnProxySettings::Local(ref local_proxy)) => Endpoint {
- address: local_proxy.peer,
- protocol: TransportProtocol::Tcp,
- },
- Some(OpenVpnProxySettings::Remote(ref remote_proxy)) => Endpoint {
- address: remote_proxy.address,
- protocol: TransportProtocol::Tcp,
- },
- _ => self.tunnel_parameters.endpoint.to_endpoint(),
- };
+ let peer_endpoint = self.get_endpoint_from_params();
let policy = SecurityPolicy::Connected {
peer_endpoint,
@@ -71,6 +61,16 @@ impl ConnectedState {
.chain_err(|| "Failed to apply security policy for connected state")
}
+ fn get_endpoint_from_params(&self) -> Endpoint {
+ match self.tunnel_parameters {
+ TunnelParameters::OpenVpn(ref config) => match config.options.proxy {
+ Some(ref proxy_settings) => proxy_settings.get_endpoint(),
+ None => self.tunnel_parameters.get_tunnel_endpoint().endpoint,
+ },
+ _ => self.tunnel_parameters.get_tunnel_endpoint().endpoint,
+ }
+ }
+
fn set_dns(&self, shared_values: &mut SharedTunnelStateValues) -> Result<()> {
shared_values
.dns_monitor
@@ -192,8 +192,8 @@ impl TunnelState for ConnectedState {
shared_values: &mut SharedTunnelStateValues,
bootstrap: Self::Bootstrap,
) -> (TunnelStateWrapper, TunnelStateTransition) {
- let tunnel_endpoint = bootstrap.tunnel_parameters.endpoint.clone();
let connected_state = ConnectedState::from(bootstrap);
+ let tunnel_endpoint = connected_state.tunnel_parameters.get_tunnel_endpoint();
if let Err(error) = connected_state.set_security_policy(shared_values) {
log::error!("{}", error.display_chain());
diff --git a/talpid-core/src/tunnel_state_machine/connecting_state.rs b/talpid-core/src/tunnel_state_machine/connecting_state.rs
index 3a4ea3d37a..ad3712144a 100644
--- a/talpid-core/src/tunnel_state_machine/connecting_state.rs
+++ b/talpid-core/src/tunnel_state_machine/connecting_state.rs
@@ -12,14 +12,14 @@ use futures::{
};
use log::{debug, error, info, trace, warn};
use talpid_types::{
- net::{Endpoint, OpenVpnProxySettings, TransportProtocol, TunnelEndpoint, TunnelEndpointData},
+ net::{openvpn, Endpoint, TunnelParameters},
tunnel::BlockReason,
};
use super::{
AfterDisconnect, BlockedState, ConnectedState, ConnectedStateBootstrap, DisconnectingState,
- EventConsequence, SharedTunnelStateValues, TunnelCommand, TunnelParameters, TunnelState,
- TunnelStateTransition, TunnelStateWrapper,
+ EventConsequence, SharedTunnelStateValues, TunnelCommand, TunnelState, TunnelStateTransition,
+ TunnelStateWrapper,
};
use crate::{
logging,
@@ -62,20 +62,13 @@ pub struct ConnectingState {
impl ConnectingState {
fn set_security_policy(
shared_values: &mut SharedTunnelStateValues,
- proxy: &Option<OpenVpnProxySettings>,
- endpoint: TunnelEndpoint,
+ proxy: &Option<openvpn::ProxySettings>,
+ endpoint: Endpoint,
) -> Result<()> {
// If a proxy is specified we need to pass it on as the peer endpoint.
let peer_endpoint = match proxy {
- Some(OpenVpnProxySettings::Local(ref local_proxy)) => Endpoint {
- address: local_proxy.peer,
- protocol: TransportProtocol::Tcp,
- },
- Some(OpenVpnProxySettings::Remote(ref remote_proxy)) => Endpoint {
- address: remote_proxy.address,
- protocol: TransportProtocol::Tcp,
- },
- _ => endpoint.to_endpoint(),
+ Some(proxy_settings) => proxy_settings.get_endpoint(),
+ None => endpoint,
};
let policy = SecurityPolicy::Connecting {
@@ -120,10 +113,8 @@ impl ConnectingState {
let log_file = Self::prepare_tunnel_log_file(&parameters, log_dir)?;
Ok(TunnelMonitor::start(
- parameters.endpoint.clone(),
- &parameters.options,
+ &parameters,
TUNNEL_INTERFACE_ALIAS.to_owned().map(OsString::from),
- &parameters.username,
log_file.clone(),
resource_dir,
on_tunnel_event,
@@ -135,9 +126,9 @@ impl ConnectingState {
log_dir: &Option<PathBuf>,
) -> Result<Option<PathBuf>> {
if let Some(ref log_dir) = log_dir {
- let filename = match parameters.endpoint.tunnel {
- TunnelEndpointData::OpenVpn(_) => OPENVPN_LOG_FILENAME,
- TunnelEndpointData::Wireguard(_) => WIREGUARD_LOG_FILENAME,
+ let filename = match parameters {
+ TunnelParameters::OpenVpn(_) => OPENVPN_LOG_FILENAME,
+ TunnelParameters::Wireguard(_) => WIREGUARD_LOG_FILENAME,
};
let tunnel_log = log_dir.join(filename);
logging::rotate_log(&tunnel_log).chain_err(|| ErrorKind::RotateLogError)?;
@@ -228,8 +219,8 @@ impl ConnectingState {
shared_values.allow_lan = allow_lan;
match Self::set_security_policy(
shared_values,
- &self.tunnel_parameters.options.openvpn.proxy,
- self.tunnel_parameters.endpoint.clone(),
+ &get_openvpn_proxy_settings(&self.tunnel_parameters),
+ self.tunnel_parameters.get_tunnel_endpoint().endpoint,
) {
Ok(()) => SameState(self),
Err(error) => {
@@ -292,6 +283,7 @@ impl ConnectingState {
}
}
+
fn handle_tunnel_events(
mut self,
shared_values: &mut SharedTunnelStateValues,
@@ -351,6 +343,15 @@ impl ConnectingState {
}
}
+fn get_openvpn_proxy_settings(
+ tunnel_parameters: &TunnelParameters,
+) -> &Option<openvpn::ProxySettings> {
+ match tunnel_parameters {
+ TunnelParameters::OpenVpn(ref config) => &config.options.proxy,
+ _ => &None,
+ }
+}
+
impl TunnelState for ConnectingState {
type Bootstrap = u32;
@@ -367,11 +368,11 @@ impl TunnelState for ConnectingState {
{
None => BlockedState::enter(shared_values, BlockReason::NoMatchingRelay),
Some(tunnel_parameters) => {
- let tunnel_endpoint = tunnel_parameters.endpoint.clone();
+ let endpoint = tunnel_parameters.get_tunnel_endpoint().endpoint;
if let Err(error) = Self::set_security_policy(
shared_values,
- &tunnel_parameters.options.openvpn.proxy,
- tunnel_endpoint.clone(),
+ &get_openvpn_proxy_settings(&tunnel_parameters),
+ endpoint,
) {
error!("{}", error.display_chain());
BlockedState::enter(shared_values, BlockReason::StartTunnelError)
@@ -382,10 +383,13 @@ impl TunnelState for ConnectingState {
&shared_values.resource_dir,
retry_attempt,
) {
- Ok(connecting_state) => (
- TunnelStateWrapper::from(connecting_state),
- TunnelStateTransition::Connecting(tunnel_endpoint),
- ),
+ Ok(connecting_state) => {
+ let params = connecting_state.tunnel_parameters.clone();
+ (
+ TunnelStateWrapper::from(connecting_state),
+ TunnelStateTransition::Connecting(params.get_tunnel_endpoint()),
+ )
+ }
Err(error) => {
let block_reason = match *error.kind() {
ErrorKind::TunnelMonitorError(
diff --git a/talpid-core/src/tunnel_state_machine/mod.rs b/talpid-core/src/tunnel_state_machine/mod.rs
index 53d58060d3..8e20e3a159 100644
--- a/talpid-core/src/tunnel_state_machine/mod.rs
+++ b/talpid-core/src/tunnel_state_machine/mod.rs
@@ -18,7 +18,7 @@ use futures::{sync::mpsc, Async, Future, Poll, Stream};
use tokio_core::reactor::Core;
use talpid_types::{
- net::{TunnelEndpoint, TunnelOptions},
+ net::TunnelParameters,
tunnel::{BlockReason, TunnelStateTransition},
};
@@ -162,17 +162,6 @@ pub enum TunnelCommand {
Block(BlockReason),
}
-/// Information necessary to open a tunnel.
-#[derive(Debug, PartialEq)]
-pub struct TunnelParameters {
- /// Tunnel enpoint to connect to.
- pub endpoint: TunnelEndpoint,
- /// Tunnel connection options.
- pub options: TunnelOptions,
- /// Username to use for setting up the tunnel.
- pub username: String,
-}
-
/// Asynchronous handling of the tunnel state machine.
///
/// This type implements `Stream`, and attempts to advance the state machine based on the events
diff --git a/talpid-types/Cargo.toml b/talpid-types/Cargo.toml
index 8bf28fdcc7..f8023d8e86 100644
--- a/talpid-types/Cargo.toml
+++ b/talpid-types/Cargo.toml
@@ -10,4 +10,5 @@ edition = "2018"
serde = { version = "1.0", features = ["derive"] }
ipnetwork = "0.13"
base64 = "0.10"
-x25519-dalek = { version = "0.3", default-features = false, features = ["u64_backend"]}
+hex = "0.3"
+error-chain = "0.12"
diff --git a/talpid-types/src/net.rs b/talpid-types/src/net.rs
deleted file mode 100644
index f63705154d..0000000000
--- a/talpid-types/src/net.rs
+++ /dev/null
@@ -1,363 +0,0 @@
-use serde::{Deserialize, Serialize};
-use std::{
- error::Error,
- fmt,
- net::{IpAddr, SocketAddr},
- str::FromStr,
-};
-
-/// Represents one tunnel endpoint. Address, plus extra parameters specific to tunnel protocol.
-#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)]
-pub struct TunnelEndpoint {
- pub address: IpAddr,
- pub tunnel: TunnelEndpointData,
-}
-
-impl TunnelEndpoint {
- /// Returns this tunnel endpoint as an `Endpoint`.
- pub fn to_endpoint(&self) -> Endpoint {
- Endpoint::new(
- self.address,
- self.tunnel.port(),
- self.tunnel.transport_protocol(),
- )
- }
-}
-
-/// TunnelEndpointData contains data required to connect to a given tunnel endpoint.
-/// Different endpoint types can require different types of data.
-#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)]
-pub enum TunnelEndpointData {
- /// Extra parameters for an OpenVPN tunnel endpoint.
- #[serde(rename = "openvpn")]
- OpenVpn(OpenVpnEndpointData),
- /// Extra parameters for a Wireguard tunnel endpoint.
- #[serde(rename = "wireguard")]
- Wireguard(WireguardEndpointData),
-}
-
-impl fmt::Display for TunnelEndpointData {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
- match self {
- TunnelEndpointData::OpenVpn(openvpn_data) => {
- write!(f, "OpenVPN ")?;
- openvpn_data.fmt(f)
- }
- TunnelEndpointData::Wireguard(wireguard_data) => {
- write!(f, "Wireguard ")?;
- wireguard_data.fmt(f)
- }
- }
- }
-}
-
-impl TunnelEndpointData {
- pub fn port(&self) -> u16 {
- match self {
- TunnelEndpointData::OpenVpn(metadata) => metadata.port,
- TunnelEndpointData::Wireguard(metadata) => metadata.port,
- }
- }
-
- pub fn transport_protocol(&self) -> TransportProtocol {
- match self {
- TunnelEndpointData::OpenVpn(metadata) => metadata.protocol,
- TunnelEndpointData::Wireguard(_) => TransportProtocol::Udp,
- }
- }
-}
-
-#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Deserialize, Serialize)]
-pub struct OpenVpnEndpointData {
- pub port: u16,
- pub protocol: TransportProtocol,
-}
-
-impl fmt::Display for OpenVpnEndpointData {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
- write!(f, "{} port {}", self.protocol, self.port)
- }
-}
-
-#[derive(Clone, Eq, PartialEq, Hash, Deserialize, Serialize)]
-pub struct WireguardEndpointData {
- /// Port to connect to
- pub port: u16,
- /// Link addresses
- pub addresses: Vec<IpAddr>,
- /// Peer's IP address
- pub gateway: IpAddr,
- #[serde(skip)]
- /// Client's private key
- pub client_private_key: Option<WgPrivateKey>,
- /// The peer's public key
- pub peer_public_key: WgPublicKey,
-}
-
-impl fmt::Debug for WireguardEndpointData {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
- f.debug_struct(&"WireguardEndpointData")
- .field("port", &self.port)
- .field("addresses", &self.addresses)
- .field("gateway", &self.gateway)
- .field("peer_public_key", &self.peer_public_key)
- .finish()
- }
-}
-
-impl fmt::Display for WireguardEndpointData {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
- write!(
- f,
- "gateway {} port {} peer_public_key {} addresses {}",
- self.gateway,
- self.port,
- self.peer_public_key,
- self.addresses
- .iter()
- .map(|a| a.to_string())
- .collect::<Vec<_>>()
- .join(",")
- )
- }
-}
-
-
-/// Represents a network layer IP address together with the transport layer protocol and port.
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub struct Endpoint {
- /// The address part of this endpoint, contains the IP and port.
- pub address: SocketAddr,
- /// The protocol part of this endpoint.
- pub protocol: TransportProtocol,
-}
-
-impl Endpoint {
- /// Constructs a new `Endpoint` from the given parameters.
- pub fn new(address: impl Into<IpAddr>, port: u16, protocol: TransportProtocol) -> Self {
- Endpoint {
- address: SocketAddr::new(address.into(), port),
- protocol,
- }
- }
-}
-
-impl fmt::Display for Endpoint {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
- write!(f, "{}:{}", self.address, self.protocol)
- }
-}
-
-/// Representation of a transport protocol, either UDP or TCP.
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
-#[serde(rename_all = "snake_case")]
-pub enum TransportProtocol {
- /// Represents the UDP transport protocol.
- Udp,
- /// Represents the TCP transport protocol.
- Tcp,
-}
-
-impl FromStr for TransportProtocol {
- type Err = TransportProtocolParseError;
-
- fn from_str(s: &str) -> ::std::result::Result<TransportProtocol, Self::Err> {
- match s {
- "udp" => Ok(TransportProtocol::Udp),
- "tcp" => Ok(TransportProtocol::Tcp),
- _ => Err(TransportProtocolParseError),
- }
- }
-}
-
-impl fmt::Display for TransportProtocol {
- fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
- match *self {
- TransportProtocol::Udp => "UDP".fmt(fmt),
- TransportProtocol::Tcp => "TCP".fmt(fmt),
- }
- }
-}
-
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct TransportProtocolParseError;
-
-impl fmt::Display for TransportProtocolParseError {
- fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
- fmt.write_str(self.description())
- }
-}
-
-impl Error for TransportProtocolParseError {
- fn description(&self) -> &str {
- "Not a valid transport protocol"
- }
-}
-
-/// TunnelOptions holds optional settings for tunnels, that are to be applied to any tunnel of the
-/// appropriate type.
-#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
-#[serde(default)]
-pub struct TunnelOptions {
- /// openvpn holds OpenVPN specific tunnel options.
- pub openvpn: OpenVpnTunnelOptions,
- /// Contains wireguard tunnel options.
- pub wireguard: WireguardTunnelOptions,
- /// Enable configuration of IPv6 on the tunnel interface, allowing IPv6 communication to be
- /// forwarded through the tunnel. By default, this is set to `true`.
- pub enable_ipv6: bool,
-}
-
-impl Default for TunnelOptions {
- fn default() -> Self {
- TunnelOptions {
- openvpn: OpenVpnTunnelOptions::default(),
- wireguard: WireguardTunnelOptions::default(),
- enable_ipv6: false,
- }
- }
-}
-
-/// OpenVpnTunnelOptions contains options for an openvpn tunnel that should be applied irrespective
-/// of the relay parameters - i.e. have nothing to do with the particular OpenVPN server, but do
-/// affect the connection.
-#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
-#[serde(default)]
-pub struct OpenVpnTunnelOptions {
- /// Optional argument for openvpn to try and limit TCP packet size,
- /// as discussed [here](https://openvpn.net/archive/openvpn-users/2003-11/msg00154.html)
- pub mssfix: Option<u16>,
- /// Proxy settings, for when the relay connection should be via a proxy.
- pub proxy: Option<OpenVpnProxySettings>,
-}
-
-#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)]
-#[serde(rename_all = "snake_case")]
-pub enum OpenVpnProxySettings {
- Local(LocalOpenVpnProxySettings),
- Remote(RemoteOpenVpnProxySettings),
-}
-
-#[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize, Serialize)]
-pub struct LocalOpenVpnProxySettings {
- pub port: u16,
- pub peer: SocketAddr,
-}
-
-#[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize, Serialize)]
-pub struct RemoteOpenVpnProxySettings {
- pub address: SocketAddr,
- pub auth: Option<OpenVpnProxyAuth>,
-}
-
-#[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize, Serialize)]
-pub struct OpenVpnProxyAuth {
- pub username: String,
- pub password: String,
-}
-
-pub struct OpenVpnProxySettingsValidation;
-
-impl OpenVpnProxySettingsValidation {
- pub fn validate(proxy: &OpenVpnProxySettings) -> Result<(), String> {
- match proxy {
- OpenVpnProxySettings::Local(local) => {
- if local.port == 0 {
- return Err(String::from("Invalid local port number"));
- }
- if local.peer.ip().is_loopback() {
- return Err(String::from(
- "localhost is not a valid peer in this context",
- ));
- }
- if local.peer.port() == 0 {
- return Err(String::from("Invalid remote port number"));
- }
- }
- OpenVpnProxySettings::Remote(remote) => {
- if remote.address.port() == 0 {
- return Err(String::from("Invalid port number"));
- }
- if remote.address.ip().is_loopback() {
- return Err(String::from("localhost is not a valid remote server"));
- }
- }
- };
- Ok(())
- }
-}
-
-/// Wireguard tunnel options
-#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
-#[serde(default)]
-pub struct WireguardTunnelOptions {
- /// MTU for the wireguard tunnel
- pub mtu: Option<u16>,
- /// firewall mark
- #[cfg(target_os = "linux")]
- pub fwmark: i32,
-}
-
-impl Default for WireguardTunnelOptions {
- fn default() -> WireguardTunnelOptions {
- Self {
- mtu: None,
- // Magic value that should be different for different end user applications, used as a
- // firewall marker on Linux.
- #[cfg(target_os = "linux")]
- fwmark: 787878,
- }
- }
-}
-
-/// Wireguard x25519 private key
-#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Hash)]
-pub struct WgPrivateKey([u8; 32]);
-
-impl WgPrivateKey {
- /// Get private key as bytes
- pub fn as_bytes(&self) -> &[u8; 32] {
- &self.0
- }
-
- /// Get public key from private key
- pub fn public_key(&self) -> WgPublicKey {
- WgPublicKey(x25519_dalek::generate_public(self.as_bytes()).to_bytes())
- }
-}
-
-impl From<[u8; 32]> for WgPrivateKey {
- fn from(private_key: [u8; 32]) -> WgPrivateKey {
- WgPrivateKey(private_key)
- }
-}
-
-/// Wireguard x25519 public key
-#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Hash)]
-pub struct WgPublicKey([u8; 32]);
-
-impl WgPublicKey {
- /// Get the public key as bytes
- pub fn as_bytes(&self) -> &[u8; 32] {
- &self.0
- }
-}
-
-
-impl From<[u8; 32]> for WgPublicKey {
- fn from(public_key: [u8; 32]) -> WgPublicKey {
- WgPublicKey(public_key)
- }
-}
-
-impl fmt::Debug for WgPublicKey {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
- write!(f, "{}", &self)
- }
-}
-
-impl fmt::Display for WgPublicKey {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
- write!(f, "{}", &base64::encode(&self.0))
- }
-}
diff --git a/talpid-types/src/net/mod.rs b/talpid-types/src/net/mod.rs
new file mode 100644
index 0000000000..74b3e8bfb1
--- /dev/null
+++ b/talpid-types/src/net/mod.rs
@@ -0,0 +1,164 @@
+use serde::{Deserialize, Serialize};
+use std::{
+ error::Error,
+ fmt,
+ net::{IpAddr, SocketAddr},
+ str::FromStr,
+};
+
+pub mod openvpn;
+pub mod wireguard;
+
+/// TunnelParameters are used to encapsulate all the data needed to start a tunnel. This is enum
+/// should be generated by implementations of the trait
+/// `talpid-core::tunnel_state_machine::TunnelParametersGenerator`
+#[derive(Clone, Eq, PartialEq, Deserialize, Serialize, Debug)]
+pub enum TunnelParameters {
+ OpenVpn(openvpn::TunnelParameters),
+ Wireguard(wireguard::TunnelParameters),
+}
+
+
+impl TunnelParameters {
+ pub fn get_tunnel_endpoint(&self) -> TunnelEndpoint {
+ match self {
+ TunnelParameters::OpenVpn(params) => params.config.get_tunnel_endpoint(),
+ TunnelParameters::Wireguard(params) => params.connection.get_tunnel_endpoint(),
+ }
+ }
+
+ pub fn get_generic_options(&self) -> &GenericTunnelOptions {
+ match &self {
+ TunnelParameters::OpenVpn(params) => &params.generic_options,
+ TunnelParameters::Wireguard(params) => &params.generic_options,
+ }
+ }
+}
+
+impl From<wireguard::TunnelParameters> for TunnelParameters {
+ fn from(wg_params: wireguard::TunnelParameters) -> TunnelParameters {
+ TunnelParameters::Wireguard(wg_params)
+ }
+}
+
+impl From<openvpn::TunnelParameters> for TunnelParameters {
+ fn from(params: openvpn::TunnelParameters) -> TunnelParameters {
+ TunnelParameters::OpenVpn(params)
+ }
+}
+
+/// Type of the tunnel
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
+#[serde(rename = "tunnel_type")]
+pub enum TunnelType {
+ #[serde(rename = "openvpn")]
+ OpenVpn,
+ #[serde(rename = "wireguard")]
+ Wireguard,
+}
+
+impl fmt::Display for TunnelType {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
+ let tunnel = match self {
+ TunnelType::OpenVpn => "OpenVPN",
+ TunnelType::Wireguard => "WireGuard",
+ };
+ write!(f, "{}", tunnel)
+ }
+}
+
+/// A tunnel endpoint is broadcast during the connecting and connected states of the tunnel state
+/// machine.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
+pub struct TunnelEndpoint {
+ #[serde(flatten)]
+ pub endpoint: Endpoint,
+ /// Type of the tunnel
+ pub tunnel_type: TunnelType,
+}
+
+impl fmt::Display for TunnelEndpoint {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
+ write!(f, "{} - {}", self.tunnel_type, self.endpoint,)
+ }
+}
+
+
+/// Represents a network layer IP address together with the transport layer protocol and port.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
+pub struct Endpoint {
+ /// The socket address for the endpoint
+ pub address: SocketAddr,
+ /// The protocol part of this endpoint.
+ pub protocol: TransportProtocol,
+}
+
+impl Endpoint {
+ /// Constructs a new `Endpoint` from the given parameters.
+ pub fn new(address: impl Into<IpAddr>, port: u16, protocol: TransportProtocol) -> Self {
+ Endpoint {
+ address: SocketAddr::new(address.into(), port),
+ protocol,
+ }
+ }
+}
+
+impl fmt::Display for Endpoint {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
+ write!(f, "{} over {}", self.address, self.protocol)
+ }
+}
+
+/// Representation of a transport protocol, either UDP or TCP.
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
+#[serde(rename_all = "snake_case")]
+pub enum TransportProtocol {
+ /// Represents the UDP transport protocol.
+ Udp,
+ /// Represents the TCP transport protocol.
+ Tcp,
+}
+
+impl FromStr for TransportProtocol {
+ type Err = TransportProtocolParseError;
+
+ fn from_str(s: &str) -> ::std::result::Result<TransportProtocol, Self::Err> {
+ match s {
+ "udp" => Ok(TransportProtocol::Udp),
+ "tcp" => Ok(TransportProtocol::Tcp),
+ _ => Err(TransportProtocolParseError),
+ }
+ }
+}
+
+impl fmt::Display for TransportProtocol {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match *self {
+ TransportProtocol::Udp => "UDP".fmt(fmt),
+ TransportProtocol::Tcp => "TCP".fmt(fmt),
+ }
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct TransportProtocolParseError;
+
+impl fmt::Display for TransportProtocolParseError {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt.write_str(self.description())
+ }
+}
+
+impl Error for TransportProtocolParseError {
+ fn description(&self) -> &str {
+ "Not a valid transport protocol"
+ }
+}
+
+/// Holds optional settings that can apply to different kinds of tunnels
+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]
+pub struct GenericTunnelOptions {
+ /// Enable configuration of IPv6 on the tunnel interface, allowing IPv6 communication to be
+ /// forwarded through the tunnel.
+ pub enable_ipv6: bool,
+}
diff --git a/talpid-types/src/net/openvpn.rs b/talpid-types/src/net/openvpn.rs
new file mode 100644
index 0000000000..2f8c92f65e
--- /dev/null
+++ b/talpid-types/src/net/openvpn.rs
@@ -0,0 +1,128 @@
+use crate::net::{Endpoint, GenericTunnelOptions, TransportProtocol, TunnelEndpoint, TunnelType};
+use serde::{Deserialize, Serialize};
+use std::net::SocketAddr;
+
+#[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize, Serialize)]
+pub struct TunnelParameters {
+ pub config: ConnectionConfig,
+ pub options: TunnelOptions,
+ pub generic_options: GenericTunnelOptions,
+}
+
+#[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize, Serialize)]
+pub struct ConnectionConfig {
+ pub endpoint: Endpoint,
+ pub username: String,
+ pub password: String,
+}
+
+impl ConnectionConfig {
+ pub fn new(endpoint: Endpoint, username: String, password: String) -> ConnectionConfig {
+ Self {
+ endpoint,
+ username,
+ password,
+ }
+ }
+ pub fn get_tunnel_endpoint(&self) -> TunnelEndpoint {
+ TunnelEndpoint {
+ tunnel_type: TunnelType::OpenVpn,
+ endpoint: self.endpoint,
+ }
+ }
+}
+
+/// TunnelOptions contains options for an openvpn tunnel that should be applied
+/// irrespective of the relay parameters - i.e. have nothing to do with the particular
+/// OpenVPN server, but do affect the connection.
+#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
+pub struct TunnelOptions {
+ /// Optional argument for openvpn to try and limit TCP packet size,
+ /// as discussed [here](https://openvpn.net/archive/openvpn-users/2003-11/msg00154.html)
+ pub mssfix: Option<u16>,
+ /// Proxy settings, for when the relay connection should be via a proxy.
+ pub proxy: Option<ProxySettings>,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)]
+#[serde(rename_all = "snake_case")]
+pub enum ProxySettings {
+ Local(LocalProxySettings),
+ Remote(RemoteProxySettings),
+}
+
+impl ProxySettings {
+ pub fn get_endpoint(&self) -> Endpoint {
+ match self {
+ ProxySettings::Local(settings) => settings.get_endpoint(),
+ ProxySettings::Remote(settings) => settings.get_endpoint(),
+ }
+ }
+}
+
+#[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize, Serialize)]
+pub struct LocalProxySettings {
+ pub port: u16,
+ pub peer: SocketAddr,
+}
+
+impl LocalProxySettings {
+ pub fn get_endpoint(&self) -> Endpoint {
+ Endpoint {
+ address: self.peer,
+ protocol: TransportProtocol::Tcp,
+ }
+ }
+}
+
+#[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize, Serialize)]
+pub struct RemoteProxySettings {
+ pub address: SocketAddr,
+ pub auth: Option<ProxyAuth>,
+}
+
+impl RemoteProxySettings {
+ pub fn get_endpoint(&self) -> Endpoint {
+ Endpoint {
+ address: self.address,
+ protocol: TransportProtocol::Tcp,
+ }
+ }
+}
+
+#[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize, Serialize)]
+pub struct ProxyAuth {
+ pub username: String,
+ pub password: String,
+}
+
+pub struct ProxySettingsValidation;
+
+impl ProxySettingsValidation {
+ pub fn validate(proxy: &ProxySettings) -> Result<(), String> {
+ match proxy {
+ ProxySettings::Local(local) => {
+ if local.port == 0 {
+ return Err(String::from("Invalid local port number"));
+ }
+ if local.peer.ip().is_loopback() {
+ return Err(String::from(
+ "localhost is not a valid peer in this context",
+ ));
+ }
+ if local.peer.port() == 0 {
+ return Err(String::from("Invalid remote port number"));
+ }
+ }
+ ProxySettings::Remote(remote) => {
+ if remote.address.port() == 0 {
+ return Err(String::from("Invalid port number"));
+ }
+ if remote.address.ip().is_loopback() {
+ return Err(String::from("localhost is not a valid remote server"));
+ }
+ }
+ };
+ Ok(())
+ }
+}
diff --git a/talpid-types/src/net/wireguard.rs b/talpid-types/src/net/wireguard.rs
new file mode 100644
index 0000000000..d24ffee0e3
--- /dev/null
+++ b/talpid-types/src/net/wireguard.rs
@@ -0,0 +1,173 @@
+use crate::net::{Endpoint, GenericTunnelOptions, TransportProtocol, TunnelEndpoint, TunnelType};
+use ipnetwork::IpNetwork;
+use serde::{Deserialize, Deserializer, Serialize, Serializer};
+use std::{
+ fmt,
+ net::{IpAddr, SocketAddr},
+};
+
+
+#[derive(Clone, Eq, PartialEq, Deserialize, Serialize, Debug)]
+/// Wireguard tunnel parameters
+pub struct TunnelParameters {
+ pub connection: ConnectionConfig,
+ pub options: TunnelOptions,
+ pub generic_options: GenericTunnelOptions,
+}
+
+#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
+pub struct ConnectionConfig {
+ pub tunnel: TunnelConfig,
+ pub peer: PeerConfig,
+ pub gateway: IpAddr,
+}
+
+impl ConnectionConfig {
+ pub fn get_tunnel_endpoint(&self) -> TunnelEndpoint {
+ let host = self.peer.endpoint;
+ TunnelEndpoint {
+ tunnel_type: TunnelType::Wireguard,
+ endpoint: Endpoint {
+ address: host,
+ protocol: TransportProtocol::Udp,
+ },
+ }
+ }
+}
+
+#[derive(Clone, Eq, PartialEq, Deserialize, Serialize, Debug, Hash)]
+pub struct PeerConfig {
+ pub public_key: PublicKey,
+ pub allowed_ips: Vec<IpNetwork>,
+ pub endpoint: SocketAddr,
+}
+
+#[derive(Clone, Eq, PartialEq, Deserialize, Serialize, Debug)]
+pub struct TunnelConfig {
+ pub private_key: PrivateKey,
+ pub addresses: Vec<IpAddr>,
+}
+
+/// Wireguard tunnel options
+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
+pub struct TunnelOptions {
+ /// MTU for the wireguard tunnel
+ pub mtu: Option<u16>,
+ /// firewall mark
+ #[cfg(target_os = "linux")]
+ pub fwmark: i32,
+}
+
+/// Wireguard x25519 private key
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct PrivateKey([u8; 32]);
+
+impl PrivateKey {
+ /// Get private key as bytes
+ pub fn as_bytes(&self) -> &[u8; 32] {
+ &self.0
+ }
+}
+
+impl From<[u8; 32]> for PrivateKey {
+ fn from(private_key: [u8; 32]) -> PrivateKey {
+ PrivateKey(private_key)
+ }
+}
+
+impl Serialize for PrivateKey {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ serialize_key(&self.0, serializer)
+ }
+}
+
+
+impl<'de> Deserialize<'de> for PrivateKey {
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ deserialize_key(deserializer)
+ }
+}
+
+/// Wireguard x25519 public key
+#[derive(Clone, PartialEq, Eq, Hash)]
+pub struct PublicKey([u8; 32]);
+
+impl PublicKey {
+ /// Get the public key as bytes
+ pub fn as_bytes(&self) -> &[u8; 32] {
+ &self.0
+ }
+}
+
+
+impl From<[u8; 32]> for PublicKey {
+ fn from(public_key: [u8; 32]) -> PublicKey {
+ PublicKey(public_key)
+ }
+}
+
+impl Serialize for PublicKey {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ serialize_key(&self.0, serializer)
+ }
+}
+
+
+impl<'de> Deserialize<'de> for PublicKey {
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ deserialize_key(deserializer)
+ }
+}
+
+impl fmt::Debug for PublicKey {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{}", &self)
+ }
+}
+
+impl fmt::Display for PublicKey {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{}", &base64::encode(&self.0))
+ }
+}
+
+fn serialize_key<S>(key: &[u8; 32], serializer: S) -> Result<S::Ok, S::Error>
+where
+ S: Serializer,
+{
+ serializer.serialize_str(&base64::encode(&key))
+}
+
+fn deserialize_key<'de, D, K>(deserializer: D) -> Result<K, D::Error>
+where
+ D: Deserializer<'de>,
+ K: From<[u8; 32]>,
+{
+ use serde::de::Error;
+
+ String::deserialize(deserializer)
+ .and_then(|string| base64::decode(&string).map_err(|err| Error::custom(err.to_string())))
+ .and_then(|buffer| {
+ let mut key = [0u8; 32];
+ if buffer.len() != 32 {
+ return Err(Error::custom(format!(
+ "Key has unexpected length: {}",
+ buffer.len()
+ )));
+ }
+ key.copy_from_slice(&buffer);
+ Ok(From::from(key))
+ })
+}
diff --git a/talpid-types/src/tunnel.rs b/talpid-types/src/tunnel.rs
index 613204ab19..07d0675bde 100644
--- a/talpid-types/src/tunnel.rs
+++ b/talpid-types/src/tunnel.rs
@@ -1,4 +1,4 @@
-use super::net::TunnelEndpoint;
+use crate::net::TunnelEndpoint;
use serde::{Deserialize, Serialize};
use std::fmt;