diff options
| author | Erik Larkö <erik@mullvad.net> | 2017-10-26 09:38:10 +0200 |
|---|---|---|
| committer | Erik Larkö <erik@mullvad.net> | 2017-11-02 09:20:09 +0100 |
| commit | e543bd104d08e0838d177e10da45962ee25aa42c (patch) | |
| tree | 6da3507544b30de22158131ff239df8c2a8e9157 | |
| parent | d6eaa0a95d07fd1105ff37e71472edc6d3c07392 (diff) | |
| download | mullvadvpn-e543bd104d08e0838d177e10da45962ee25aa42c.tar.xz mullvadvpn-e543bd104d08e0838d177e10da45962ee25aa42c.zip | |
Set the tunnel port and protocol over the API
| -rw-r--r-- | Cargo.lock | 12 | ||||
| -rw-r--r-- | mullvad-cli/src/cmds/custom_relay.rs | 80 | ||||
| -rw-r--r-- | mullvad-cli/src/cmds/mod.rs | 6 | ||||
| -rw-r--r-- | mullvad-cli/src/cmds/relay.rs | 85 | ||||
| -rw-r--r-- | mullvad-daemon/Cargo.toml | 3 | ||||
| -rw-r--r-- | mullvad-daemon/src/main.rs | 68 | ||||
| -rw-r--r-- | mullvad-daemon/src/management_interface.rs | 36 | ||||
| -rw-r--r-- | mullvad-daemon/src/settings.rs | 66 | ||||
| -rw-r--r-- | mullvad-types/src/lib.rs | 2 | ||||
| -rw-r--r-- | mullvad-types/src/relay_constraints.rs | 101 |
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()) + }, + } + } +} |
