summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorErik Larkö <erik@mullvad.net>2017-10-26 09:38:10 +0200
committerErik Larkö <erik@mullvad.net>2017-11-02 09:20:09 +0100
commite543bd104d08e0838d177e10da45962ee25aa42c (patch)
tree6da3507544b30de22158131ff239df8c2a8e9157
parentd6eaa0a95d07fd1105ff37e71472edc6d3c07392 (diff)
downloadmullvadvpn-e543bd104d08e0838d177e10da45962ee25aa42c.tar.xz
mullvadvpn-e543bd104d08e0838d177e10da45962ee25aa42c.zip
Set the tunnel port and protocol over the API
-rw-r--r--Cargo.lock12
-rw-r--r--mullvad-cli/src/cmds/custom_relay.rs80
-rw-r--r--mullvad-cli/src/cmds/mod.rs6
-rw-r--r--mullvad-cli/src/cmds/relay.rs85
-rw-r--r--mullvad-daemon/Cargo.toml3
-rw-r--r--mullvad-daemon/src/main.rs68
-rw-r--r--mullvad-daemon/src/management_interface.rs36
-rw-r--r--mullvad-daemon/src/settings.rs66
-rw-r--r--mullvad-types/src/lib.rs2
-rw-r--r--mullvad-types/src/relay_constraints.rs101
10 files changed, 301 insertions, 158 deletions
diff --git a/Cargo.lock b/Cargo.lock
index d0c58be2c7..1e8207732a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -681,13 +681,14 @@ dependencies = [
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"mullvad-rpc 0.1.0",
"mullvad-types 0.1.0",
+ "rand 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"simple-signal 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"talpid-core 0.1.0",
"talpid-ipc 0.1.0",
"talpid-types 0.1.0",
- "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"uuid 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1410,14 +1411,6 @@ dependencies = [
]
[[package]]
-name = "toml"
-version = "0.4.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "serde 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
name = "unicase"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1689,7 +1682,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "24da22d077e0f15f55162bdbdc661228c1581892f52074fb242678d015b45162"
"checksum tokio-timer 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6131e780037787ff1b3f8aad9da83bca02438b72277850dd6ad0d455e0e20efc"
"checksum tokio-tls 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d88e411cac1c87e405e4090be004493c5d8072a370661033b1a64ea205ec2e13"
-"checksum toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a7540f4ffc193e0d3c94121edb19b055670d369f77d5804db11ae053a45b6e7e"
"checksum unicase 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2e01da42520092d0cd2d6ac3ae69eb21a22ad43ff195676b86f8c37f487d6b80"
"checksum unicode-bidi 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a6a2c4e3710edd365cd7e78383153ed739fa31af19f9172f72d3575060f5a43a"
"checksum unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "51ccda9ef9efa3f7ef5d91e8f9b83bbe6955f9bf86aec89d5cce2c874625920f"
diff --git a/mullvad-cli/src/cmds/custom_relay.rs b/mullvad-cli/src/cmds/custom_relay.rs
deleted file mode 100644
index d37169d52a..0000000000
--- a/mullvad-cli/src/cmds/custom_relay.rs
+++ /dev/null
@@ -1,80 +0,0 @@
-pub struct CustomRelay;
-
-use {Command, Result};
-use clap;
-use mullvad_types::relay_endpoint::RelayEndpoint;
-
-use rpc;
-
-use talpid_types::net::TransportProtocol;
-
-impl Command for CustomRelay {
- fn name(&self) -> &'static str {
- "relay"
- }
-
- fn clap_subcommand(&self) -> clap::App<'static, 'static> {
- clap::SubCommand::with_name(self.name())
- .about("Set or remove custom relay")
- .setting(clap::AppSettings::SubcommandRequired)
- .subcommand(
- clap::SubCommand::with_name("set")
- .about("Set a custom relay")
- .arg(
- clap::Arg::with_name("host")
- .help("The host name or IP of the relay")
- .required(true),
- )
- .arg(
- clap::Arg::with_name("port")
- .help("The port of the relay")
- .required(true),
- )
- .arg(
- clap::Arg::with_name("protocol")
- .help(
- "The transport protocol. UDP is recommended as it usually results in
- higher throughput than TCP",
- )
- .possible_values(&["udp", "tcp"])
- .default_value("udp"),
- ),
- )
- .subcommand(
- clap::SubCommand::with_name("remove")
- .about("Remove the custom relay and use the default relays instead"),
- )
- }
-
- fn run(&self, matches: &clap::ArgMatches) -> Result<()> {
- if let Some(set_matches) = matches.subcommand_matches("set") {
- let host = value_t_or_exit!(set_matches.value_of("host"), String);
- let port = value_t_or_exit!(set_matches.value_of("port"), u16);
- let protocol = value_t_or_exit!(set_matches.value_of("protocol"), TransportProtocol);
-
- self.set(host, port, protocol)
- } else if let Some(_) = matches.subcommand_matches("remove") {
- self.remove()
- } else {
- unreachable!("No sub command given");
- }
- }
-}
-
-impl CustomRelay {
- fn set(&self, host: String, port: u16, protocol: TransportProtocol) -> Result<()> {
- let relay_endpoint = RelayEndpoint {
- host,
- port,
- protocol,
- };
-
- rpc::call("set_custom_relay", &[relay_endpoint])
- .map(|_: Option<()>| println!("Custom relay set"))
- }
-
- fn remove(&self) -> Result<()> {
- rpc::call("remove_custom_relay", &[] as &[u8; 0])
- .map(|_: Option<()>| println!("Custom relay removed"))
- }
-}
diff --git a/mullvad-cli/src/cmds/mod.rs b/mullvad-cli/src/cmds/mod.rs
index 0104185543..1c10fa81c2 100644
--- a/mullvad-cli/src/cmds/mod.rs
+++ b/mullvad-cli/src/cmds/mod.rs
@@ -13,8 +13,8 @@ pub use self::connect::Connect;
mod disconnect;
pub use self::disconnect::Disconnect;
-mod custom_relay;
-pub use self::custom_relay::CustomRelay;
+mod relay;
+pub use self::relay::Relay;
mod shutdown;
pub use self::shutdown::Shutdown;
@@ -26,8 +26,8 @@ pub fn get_commands() -> HashMap<&'static str, Box<Command>> {
Box::new(Status),
Box::new(Connect),
Box::new(Disconnect),
- Box::new(CustomRelay),
Box::new(Shutdown),
+ Box::new(Relay),
];
let mut map = HashMap::new();
for cmd in commands {
diff --git a/mullvad-cli/src/cmds/relay.rs b/mullvad-cli/src/cmds/relay.rs
new file mode 100644
index 0000000000..1787dc0bee
--- /dev/null
+++ b/mullvad-cli/src/cmds/relay.rs
@@ -0,0 +1,85 @@
+use {Command, Result};
+use clap;
+
+use rpc;
+
+use mullvad_types::relay_constraints::{OpenVpnConstraintsUpdate, Port, RelayConstraintsUpdate,
+ TunnelConstraintsUpdate};
+use talpid_types::net::TransportProtocol;
+
+pub struct Relay;
+
+impl Command for Relay {
+ fn name(&self) -> &'static str {
+ "relay"
+ }
+
+ fn clap_subcommand(&self) -> clap::App<'static, 'static> {
+ clap::SubCommand::with_name(self.name())
+ .about("Manage relay and tunnel constraints")
+ .setting(clap::AppSettings::SubcommandRequired)
+ .subcommand(
+ clap::SubCommand::with_name("host")
+ .about("Set host")
+ .arg(clap::Arg::with_name("host").required(true)),
+ )
+ .subcommand(
+ clap::SubCommand::with_name("port")
+ .about("Set port")
+ .arg(clap::Arg::with_name("port").required(true)),
+ )
+ .subcommand(
+ clap::SubCommand::with_name("protocol")
+ .about("Set protocol")
+ .arg(
+ clap::Arg::with_name("protocol")
+ .required(true)
+ .possible_values(&["udp", "tcp"]),
+ ),
+ )
+ }
+
+ fn run(&self, matches: &clap::ArgMatches) -> Result<()> {
+ if let Some(host_matches) = matches.subcommand_matches("host") {
+ let host = value_t_or_exit!(host_matches.value_of("host"), String);
+
+ self.update_constraints(RelayConstraintsUpdate {
+ host: Some(Some(host)),
+ tunnel: TunnelConstraintsUpdate::OpenVpn(OpenVpnConstraintsUpdate {
+ port: None,
+ protocol: None,
+ }),
+ })
+ } else if let Some(port_matches) = matches.subcommand_matches("port") {
+ let port = value_t_or_exit!(port_matches.value_of("port"), Port);
+
+ self.update_constraints(RelayConstraintsUpdate {
+ host: None,
+ tunnel: TunnelConstraintsUpdate::OpenVpn(OpenVpnConstraintsUpdate {
+ port: Some(port),
+ protocol: None,
+ }),
+ })
+ } else if let Some(protocol_matches) = matches.subcommand_matches("protocol") {
+ let protocol =
+ value_t_or_exit!(protocol_matches.value_of("protocol"), TransportProtocol);
+
+ self.update_constraints(RelayConstraintsUpdate {
+ host: None,
+ tunnel: TunnelConstraintsUpdate::OpenVpn(OpenVpnConstraintsUpdate {
+ port: None,
+ protocol: Some(protocol),
+ }),
+ })
+ } else {
+ unreachable!("No relay command given");
+ }
+ }
+}
+
+impl Relay {
+ fn update_constraints(&self, constraints_update: RelayConstraintsUpdate) -> Result<()> {
+ rpc::call("update_relay_constraints", &[constraints_update])
+ .map(|_: Option<()>| println!("relay constraints updated"))
+ }
+}
diff --git a/mullvad-daemon/Cargo.toml b/mullvad-daemon/Cargo.toml
index 7449b9120e..7971054df0 100644
--- a/mullvad-daemon/Cargo.toml
+++ b/mullvad-daemon/Cargo.toml
@@ -23,6 +23,7 @@ fern = "0.4"
futures = "0.1"
serde = "1.0"
serde_derive = "1.0"
+serde_json = "1.0"
log = "0.3"
jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc", tag = "v7.1.1" }
jsonrpc-macros = { git = "https://github.com/paritytech/jsonrpc", tag = "v7.1.1" }
@@ -30,7 +31,7 @@ jsonrpc-pubsub = { git = "https://github.com/paritytech/jsonrpc", tag = "v7.1.1"
jsonrpc-ws-server = { git = "https://github.com/paritytech/jsonrpc", tag = "v7.1.1" }
uuid = { version = "0.5", features = ["v4"] }
lazy_static = "0.2"
-toml = "0.4"
+rand = "0.3"
mullvad-types = { path = "../mullvad-types" }
mullvad-rpc = { path = "../mullvad-rpc" }
diff --git a/mullvad-daemon/src/main.rs b/mullvad-daemon/src/main.rs
index ad2850b926..3a0b6854de 100644
--- a/mullvad-daemon/src/main.rs
+++ b/mullvad-daemon/src/main.rs
@@ -27,6 +27,7 @@ extern crate jsonrpc_pubsub;
extern crate jsonrpc_ws_server;
#[macro_use]
extern crate lazy_static;
+extern crate rand;
extern crate uuid;
extern crate mullvad_rpc;
@@ -48,9 +49,12 @@ use jsonrpc_core::futures::sync::oneshot::Sender as OneshotSender;
use management_interface::{BoxFuture, ManagementInterfaceServer, TunnelCommand};
use mullvad_rpc::{AccountsProxy, HttpHandle};
use mullvad_types::account::{AccountData, AccountToken};
+use mullvad_types::relay_constraints::{OpenVpnConstraints, RelayConstraintsUpdate,
+ TunnelConstraints};
use mullvad_types::relay_endpoint::RelayEndpoint;
use mullvad_types::states::{DaemonState, SecurityState, TargetState};
+use rand::Rng;
use std::io;
use std::net::Ipv4Addr;
use std::path::PathBuf;
@@ -314,7 +318,9 @@ impl Daemon {
GetAccountData(tx, account_token) => Ok(self.on_get_account_data(tx, account_token)),
SetAccount(tx, account_token) => self.on_set_account(tx, account_token),
GetAccount(tx) => Ok(self.on_get_account(tx)),
- SetCustomRelay(tx, relay_endpoint) => self.on_set_custom_relay(tx, relay_endpoint),
+ UpdateRelayConstraints(tx, constraints_update) => {
+ self.on_update_relay_constraints(tx, constraints_update)
+ }
Shutdown => self.handle_trigger_shutdown_event(),
}
}
@@ -370,22 +376,22 @@ impl Daemon {
Self::oneshot_send(tx, self.settings.get_account_token(), "current account")
}
- fn on_set_custom_relay(
+ fn on_update_relay_constraints(
&mut self,
tx: OneshotSender<()>,
- relay_endpoint: Option<RelayEndpoint>,
+ constraints: RelayConstraintsUpdate,
) -> Result<()> {
- let save_result = self.settings.set_custom_relay(relay_endpoint);
+ let save_result = self.settings.update_relay_constraints(constraints);
match save_result.chain_err(|| "Unable to save settings") {
- Ok(relays_changed) => {
- Self::oneshot_send(tx, (), "set_custom_relay response");
+ Ok(constraints_changed) => {
+ Self::oneshot_send(tx, (), "update_relay_constraints response");
let tunnel_needs_restart =
self.state == TunnelState::Connecting || self.state == TunnelState::Connected;
- if relays_changed && tunnel_needs_restart {
- info!("Initiating tunnel restart because a custom relay was selected");
+ if constraints_changed && tunnel_needs_restart {
+ info!("Initiating tunnel restart because the relay constraints changed");
self.kill_tunnel()?;
}
}
@@ -513,15 +519,37 @@ impl Daemon {
}
fn get_relay(&mut self) -> Result<Endpoint> {
- if let Some(relay_endpoint) = self.settings.get_custom_relay() {
- relay_endpoint
- .to_endpoint()
- .chain_err(|| "Invalid custom relay")
- } else {
- Ok(self.relay_iter.next().unwrap())
+ let relay_constraints = self.settings.get_relay_constraints();
+
+ let host = relay_constraints
+ .host
+ .unwrap_or_else(|| format!("{}", self.relay_iter.next().unwrap().address));
+
+ match relay_constraints.tunnel {
+ TunnelConstraints::OpenVpn(constraints) => self.get_openvpn_relay(host, constraints),
}
}
+ fn get_openvpn_relay(
+ &mut self,
+ host: String,
+ constraints: OpenVpnConstraints,
+ ) -> Result<Endpoint> {
+ let protocol = constraints.protocol;
+
+ let port = match constraints.port {
+ mullvad_types::relay_constraints::Port::Any => randomize_port(protocol),
+ mullvad_types::relay_constraints::Port::Port(port) => port,
+ };
+
+ RelayEndpoint {
+ host,
+ port,
+ protocol,
+ }.to_endpoint()
+ .chain_err(|| "Unable to construct a valid relay")
+ }
+
fn spawn_tunnel_monitor(&self, relay: Endpoint, account_token: &str) -> Result<TunnelMonitor> {
// Must wrap the channel in a Mutex because TunnelMonitor forces the closure to be Sync
let event_tx = Arc::new(Mutex::new(self.tx.clone()));
@@ -677,3 +705,15 @@ fn log_version() {
include_str!(concat!(env!("OUT_DIR"), "/git-commit-info.txt"))
)
}
+
+fn randomize_port(protocol: TransportProtocol) -> u16 {
+ let pool: Vec<u16> = if protocol == TransportProtocol::Udp {
+ vec![1194, 1195, 1196, 1197, 1300, 1301, 1302]
+ } else {
+ vec![80, 443]
+ };
+
+ *rand::thread_rng()
+ .choose(&pool)
+ .expect("no ports to randomize from")
+}
diff --git a/mullvad-daemon/src/management_interface.rs b/mullvad-daemon/src/management_interface.rs
index 43e55f4cb4..8674882613 100644
--- a/mullvad-daemon/src/management_interface.rs
+++ b/mullvad-daemon/src/management_interface.rs
@@ -10,7 +10,6 @@ use jsonrpc_ws_server;
use mullvad_rpc;
use mullvad_types::account::{AccountData, AccountToken};
use mullvad_types::location::{CountryCode, Location};
-use mullvad_types::relay_endpoint::RelayEndpoint;
use mullvad_types::states::{DaemonState, TargetState};
use serde;
@@ -21,6 +20,7 @@ use std::net::{IpAddr, Ipv4Addr};
use std::sync::{Arc, Mutex, RwLock};
use std::sync::atomic::{AtomicBool, Ordering};
+use mullvad_types::relay_constraints::RelayConstraintsUpdate;
use talpid_core::mpsc::IntoSender;
use talpid_ipc;
use uuid;
@@ -56,13 +56,12 @@ build_rpc_trait! {
#[rpc(meta, name = "get_account")]
fn get_account(&self, Self::Metadata) -> BoxFuture<Option<AccountToken>, Error>;
- /// Set which relay to connect to
- #[rpc(meta, name = "set_custom_relay")]
- fn set_custom_relay(&self, Self::Metadata, RelayEndpoint) -> BoxFuture<(), Error>;
-
- /// Unset the custom relay, reverting to the default relay listing
- #[rpc(meta, name = "remove_custom_relay")]
- fn remove_custom_relay(&self, Self::Metadata) -> BoxFuture<(), Error>;
+ /// Update constraints put on the type of tunnel connection to use
+ #[rpc(meta, name = "update_relay_constraints")]
+ fn update_relay_constraints(
+ &self,
+ Self::Metadata, RelayConstraintsUpdate
+ ) -> BoxFuture<(), Error>;
/// Set if the client should automatically establish a tunnel on start or not.
#[rpc(meta, name = "set_autoconnect")]
@@ -133,8 +132,8 @@ pub enum TunnelCommand {
SetAccount(OneshotSender<()>, Option<AccountToken>),
/// Request the current account token being used.
GetAccount(OneshotSender<Option<AccountToken>>),
- /// Set a custom relay instead of the default list of relays
- SetCustomRelay(OneshotSender<()>, Option<RelayEndpoint>),
+ /// Place constraints on the type of tunnel and relay
+ UpdateRelayConstraints(OneshotSender<()>, RelayConstraintsUpdate),
/// Makes the daemon exit the main loop and quit.
Shutdown,
}
@@ -382,30 +381,21 @@ impl<T: From<TunnelCommand> + 'static + Send> ManagementInterfaceApi for Managem
Box::new(future)
}
- fn set_custom_relay(
+ fn update_relay_constraints(
&self,
meta: Self::Metadata,
- custom_relay: RelayEndpoint,
+ constraints_update: RelayConstraintsUpdate,
) -> BoxFuture<(), Error> {
- trace!("set_custom_relay");
+ trace!("update_relay_constraints");
try_future!(self.check_auth(&meta));
let (tx, rx) = sync::oneshot::channel();
- let message = TunnelCommand::SetCustomRelay(tx, Some(custom_relay));
+ let message = TunnelCommand::UpdateRelayConstraints(tx, constraints_update);
let future = self.send_command_to_daemon(message)
.and_then(|_| rx.map_err(|_| Error::internal_error()));
Box::new(future)
}
- fn remove_custom_relay(&self, meta: Self::Metadata) -> BoxFuture<(), Error> {
- trace!("remove_custom_relay");
- try_future!(self.check_auth(&meta));
- let (tx, rx) = sync::oneshot::channel();
- let future = self.send_command_to_daemon(TunnelCommand::SetCustomRelay(tx, None))
- .and_then(|_| rx.map_err(|_| Error::internal_error()));
- Box::new(future)
- }
-
fn set_autoconnect(&self, meta: Self::Metadata, _autoconnect: bool) -> BoxFuture<(), Error> {
trace!("set_autoconnect");
try_future!(self.check_auth(&meta));
diff --git a/mullvad-daemon/src/settings.rs b/mullvad-daemon/src/settings.rs
index 1ba32eb178..f217d9a677 100644
--- a/mullvad-daemon/src/settings.rs
+++ b/mullvad-daemon/src/settings.rs
@@ -1,12 +1,14 @@
extern crate app_dirs;
-extern crate toml;
+extern crate serde_json;
use self::app_dirs::{AppDataType, AppInfo};
-use mullvad_types::relay_endpoint::RelayEndpoint;
+use talpid_types::net::TransportProtocol;
+use mullvad_types::relay_constraints::{OpenVpnConstraints, Port, RelayConstraints,
+ RelayConstraintsUpdate, TunnelConstraints};
use std::fs::File;
-use std::io::{self, Read, Write};
+use std::io;
use std::path::PathBuf;
error_chain! {
@@ -33,17 +35,30 @@ static APP_INFO: AppInfo = AppInfo {
author: "Mullvad",
};
-static SETTINGS_FILE: &str = "settings.toml";
+static SETTINGS_FILE: &str = "settings.json";
#[derive(Debug, Clone, Deserialize, Serialize)]
+#[serde(default)]
pub struct Settings {
account_token: Option<String>,
- custom_relay: Option<RelayEndpoint>,
+ relay_constraints: RelayConstraints,
+}
+
+impl Default for Settings {
+ fn default() -> Self {
+ DEFAULT_SETTINGS
+ }
}
const DEFAULT_SETTINGS: Settings = Settings {
account_token: None,
- custom_relay: None,
+ relay_constraints: RelayConstraints {
+ host: None,
+ tunnel: TunnelConstraints::OpenVpn(OpenVpnConstraints {
+ port: Port::Any,
+ protocol: TransportProtocol::Udp,
+ }),
+ },
};
impl Settings {
@@ -53,7 +68,7 @@ impl Settings {
match File::open(&settings_path) {
Ok(mut file) => {
info!("Loading settings from {}", settings_path.to_string_lossy());
- Self::read_settings(&mut file, settings_path)
+ Self::read_settings(&mut file)
}
Err(ref e) if e.kind() == io::ErrorKind::NotFound => {
info!(
@@ -68,13 +83,12 @@ impl Settings {
/// Serializes the settings and saves them to the file it was loaded from.
fn save(&self) -> Result<()> {
- let settings_path = Self::get_settings_path()?;
- let data = toml::to_string(self).chain_err(|| ErrorKind::ParseError)?;
+ let path = Self::get_settings_path()?;
- debug!("Writing settings to {}", settings_path.to_string_lossy());
- File::create(&settings_path)
- .and_then(|mut file| file.write_all(data.as_bytes()))
- .chain_err(|| ErrorKind::WriteError(settings_path))
+ debug!("Writing settings to {}", path.to_string_lossy());
+ let file = File::create(&path).chain_err(|| ErrorKind::WriteError(path.clone()))?;
+
+ serde_json::to_writer_pretty(file, self).chain_err(|| ErrorKind::WriteError(path))
}
fn get_settings_path() -> Result<PathBuf> {
@@ -83,11 +97,8 @@ impl Settings {
Ok(dir.join(SETTINGS_FILE))
}
- fn read_settings(file: &mut File, path: PathBuf) -> Result<Settings> {
- let mut data = Vec::new();
- file.read_to_end(&mut data)
- .chain_err(|| ErrorKind::ReadError(path))?;
- toml::from_slice(&data).chain_err(|| ErrorKind::ParseError)
+ fn read_settings(file: &mut File) -> Result<Settings> {
+ serde_json::from_reader(file).chain_err(|| ErrorKind::ParseError)
}
pub fn get_account_token(&self) -> Option<String> {
@@ -121,18 +132,19 @@ impl Settings {
}
}
- pub fn get_custom_relay(&self) -> Option<RelayEndpoint> {
- self.custom_relay.clone()
+ pub fn get_relay_constraints(&self) -> RelayConstraints {
+ self.relay_constraints.clone()
}
- pub fn set_custom_relay(&mut self, relay_endpoint: Option<RelayEndpoint>) -> Result<bool> {
- if self.custom_relay != relay_endpoint {
- match &relay_endpoint {
- &Some(ref data) => info!("Setting a custom relay: {}", data),
- &None => info!("Removing the custom relay"),
- }
+ pub fn update_relay_constraints(&mut self, update: RelayConstraintsUpdate) -> Result<bool> {
+ let new_constraints = self.relay_constraints.update(update);
- self.custom_relay = relay_endpoint;
+ if new_constraints {
+ debug!(
+ "changed relay constraints from {:?} to {:?}",
+ self.relay_constraints,
+ new_constraints
+ );
self.save().map(|_| true)
} else {
diff --git a/mullvad-types/src/lib.rs b/mullvad-types/src/lib.rs
index 2b72c3d538..82022bbf9a 100644
--- a/mullvad-types/src/lib.rs
+++ b/mullvad-types/src/lib.rs
@@ -7,6 +7,7 @@
//! the License, or (at your option) any later version.
extern crate chrono;
+extern crate serde;
#[macro_use]
extern crate serde_derive;
@@ -22,3 +23,4 @@ pub mod account;
pub mod location;
pub mod states;
pub mod relay_endpoint;
+pub mod relay_constraints;
diff --git a/mullvad-types/src/relay_constraints.rs b/mullvad-types/src/relay_constraints.rs
new file mode 100644
index 0000000000..6e09b06667
--- /dev/null
+++ b/mullvad-types/src/relay_constraints.rs
@@ -0,0 +1,101 @@
+use std::str::FromStr;
+use talpid_types::net::TransportProtocol;
+
+#[derive(Debug, Clone, Deserialize, Serialize)]
+pub struct RelayConstraints {
+ pub host: Option<String>,
+ pub tunnel: TunnelConstraints,
+}
+
+impl RelayConstraints {
+ pub fn update(&mut self, update: RelayConstraintsUpdate) -> bool {
+ let mut updated = false;
+
+ if let Some(new_host) = update.host {
+ self.host = new_host;
+ updated = true;
+ }
+
+ updated || self.tunnel.update(update.tunnel)
+ }
+}
+
+
+#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
+pub enum TunnelConstraints {
+ OpenVpn(OpenVpnConstraints),
+}
+
+impl TunnelConstraints {
+ pub fn update(&mut self, update: TunnelConstraintsUpdate) -> bool {
+ match *self {
+ TunnelConstraints::OpenVpn(ref mut current) => match update {
+ TunnelConstraintsUpdate::OpenVpn(openvpn_update) => current.update(openvpn_update),
+ },
+ }
+ }
+}
+
+#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
+pub struct OpenVpnConstraints {
+ pub port: Port,
+ pub protocol: TransportProtocol,
+}
+
+impl OpenVpnConstraints {
+ pub fn update(&mut self, update: OpenVpnConstraintsUpdate) -> bool {
+ let mut updated = false;
+
+ if let Some(new_port) = update.port {
+ self.port = new_port;
+ updated = true;
+ }
+ if let Some(new_protocol) = update.protocol {
+ self.protocol = new_protocol;
+ updated = true;
+ }
+
+ updated
+ }
+}
+
+
+#[derive(Debug, Deserialize, Serialize)]
+pub struct RelayConstraintsUpdate {
+ pub host: Option<Option<String>>,
+ pub tunnel: TunnelConstraintsUpdate,
+}
+
+#[derive(Debug, Deserialize, Serialize)]
+pub enum TunnelConstraintsUpdate {
+ OpenVpn(OpenVpnConstraintsUpdate),
+}
+
+#[derive(Debug, Deserialize, Serialize)]
+pub struct OpenVpnConstraintsUpdate {
+ pub port: Option<Port>,
+ pub protocol: Option<TransportProtocol>,
+}
+
+
+#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
+pub enum Port {
+ Any,
+ Port(u16),
+}
+
+impl FromStr for Port {
+ type Err = String;
+
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ let res = u16::from_str_radix(s, 10);
+ match res {
+ Ok(num) => Ok(Port::Port(num)),
+ Err(_) => if s.to_lowercase() == "any" {
+ Ok(Port::Any)
+ } else {
+ Err("not 'any' or a short".to_owned())
+ },
+ }
+ }
+}