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 /mullvad-daemon/src | |
| parent | d6eaa0a95d07fd1105ff37e71472edc6d3c07392 (diff) | |
| download | mullvadvpn-e543bd104d08e0838d177e10da45962ee25aa42c.tar.xz mullvadvpn-e543bd104d08e0838d177e10da45962ee25aa42c.zip | |
Set the tunnel port and protocol over the API
Diffstat (limited to 'mullvad-daemon/src')
| -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 |
3 files changed, 106 insertions, 64 deletions
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 { |
