summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorErik Larkö <erik@mullvad.net>2017-11-02 10:38:53 +0100
committerErik Larkö <erik@mullvad.net>2017-11-02 10:38:53 +0100
commit2761c4a61103a64c42fcea39b41b4f3a5741a55c (patch)
treec13f291950b37e7ca87897372906a63029940c1c
parentd6eaa0a95d07fd1105ff37e71472edc6d3c07392 (diff)
parente803dc36a64366ee12ef6e0e67e309404fa7a056 (diff)
downloadmullvadvpn-2761c4a61103a64c42fcea39b41b4f3a5741a55c.tar.xz
mullvadvpn-2761c4a61103a64c42fcea39b41b4f3a5741a55c.zip
Merge branch 'tcp-tunnel'
-rw-r--r--Cargo.lock28
-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.rs135
-rw-r--r--mullvad-daemon/Cargo.toml3
-rw-r--r--mullvad-daemon/src/main.rs82
-rw-r--r--mullvad-daemon/src/management_interface.rs42
-rw-r--r--mullvad-daemon/src/settings.rs69
-rw-r--r--mullvad-types/src/lib.rs2
-rw-r--r--mullvad-types/src/relay_constraints.rs95
10 files changed, 380 insertions, 162 deletions
diff --git a/Cargo.lock b/Cargo.lock
index d0c58be2c7..0e366f88c4 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1,11 +1,3 @@
-[root]
-name = "talpid-types"
-version = "0.1.0"
-dependencies = [
- "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)",
-]
-
[[package]]
name = "advapi32-sys"
version = "0.2.0"
@@ -681,13 +673,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)",
]
@@ -1274,6 +1267,14 @@ dependencies = [
]
[[package]]
+name = "talpid-types"
+version = "0.1.0"
+dependencies = [
+ "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)",
+]
+
+[[package]]
name = "tempdir"
version = "0.3.5"
source = "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..68582562f9
--- /dev/null
+++ b/mullvad-cli/src/cmds/relay.rs
@@ -0,0 +1,135 @@
+use {Command, Result};
+use clap;
+
+use mullvad_types::relay_constraints::{HostConstraint, OpenVpnConstraintsUpdate, PortConstraint,
+ ProtocolConstraint, RelayConstraints,
+ RelayConstraintsUpdate, TunnelConstraintsUpdate};
+
+use rpc;
+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("set")
+ .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"]),
+ ),
+ ),
+ )
+ .subcommand(clap::SubCommand::with_name("get"))
+ }
+
+ fn run(&self, matches: &clap::ArgMatches) -> Result<()> {
+ if let Some(set_matches) = matches.subcommand_matches("set") {
+ self.set(set_matches)
+ } else if let Some(_) = matches.subcommand_matches("get") {
+ self.get()
+ } 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"))
+ }
+
+ fn set(&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(HostConstraint::Host(host)),
+ tunnel: TunnelConstraintsUpdate::OpenVpn(OpenVpnConstraintsUpdate {
+ port: None,
+ protocol: None,
+ }),
+ })
+ } else if let Some(port_matches) = matches.subcommand_matches("port") {
+ let port = parse_port(port_matches.value_of("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 = parse_protocol(protocol_matches.value_of("protocol"))?;
+
+ self.update_constraints(RelayConstraintsUpdate {
+ host: None,
+ tunnel: TunnelConstraintsUpdate::OpenVpn(OpenVpnConstraintsUpdate {
+ port: None,
+ protocol: Some(protocol),
+ }),
+ })
+ } else {
+ unreachable!("No set relay command given");
+ }
+ }
+
+ fn get(&self) -> Result<()> {
+ let constraints: RelayConstraints = rpc::call("get_relay_constraints", &[] as &[u8; 0])?;
+ println!("Current constraints: {:?}", constraints);
+
+ Ok(())
+ }
+}
+
+fn parse_port(raw_port: Option<&str>) -> Result<PortConstraint> {
+ if let Some(s) = raw_port {
+ let res = u16::from_str_radix(s, 10);
+ match res {
+ Ok(num) => Ok(PortConstraint::Port(num)),
+ Err(_) => if s.to_lowercase() == "any" {
+ Ok(PortConstraint::Any)
+ } else {
+ bail!("not 'any' or a short".to_owned())
+ },
+ }
+ } else {
+ bail!("not 'any' or a short".to_owned())
+ }
+}
+
+fn parse_protocol(raw_protocol: Option<&str>) -> Result<ProtocolConstraint> {
+ if let Some(s) = raw_protocol {
+ if s.to_lowercase() == "any" {
+ return Ok(ProtocolConstraint::Any);
+ } else if ["udp", "tcp"].contains(&s) {
+ return Ok(ProtocolConstraint::Protocol(TransportProtocol::Udp));
+ }
+ }
+
+ bail!("not 'udp' or 'tcp'".to_owned())
+}
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..e4edb30527 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,13 @@ 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::{HostConstraint, OpenVpnConstraints, PortConstraint,
+ ProtocolConstraint, RelayConstraints,
+ 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 +319,10 @@ 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)
+ }
+ GetRelayConstraints(tx) => Ok(self.on_get_relay_constraints(tx)),
Shutdown => self.handle_trigger_shutdown_event(),
}
}
@@ -370,22 +378,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()?;
}
}
@@ -395,6 +403,14 @@ impl Daemon {
Ok(())
}
+ fn on_get_relay_constraints(&self, tx: OneshotSender<RelayConstraints>) {
+ Self::oneshot_send(
+ tx,
+ self.settings.get_relay_constraints(),
+ "relay constraints",
+ )
+ }
+
fn oneshot_send<T>(tx: OneshotSender<T>, t: T, msg: &'static str) {
if let Err(_) = tx.send(t) {
warn!("Unable to send {} to management interface client", msg);
@@ -513,15 +529,41 @@ 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 = match relay_constraints.host {
+ HostConstraint::Any => format!("{}", self.relay_iter.next().unwrap().address),
+ HostConstraint::Host(host) => host,
+ };
+
+ 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 = match constraints.protocol {
+ ProtocolConstraint::Any => TransportProtocol::Udp,
+ ProtocolConstraint::Protocol(protocol) => protocol,
+ };
+
+ let port = match constraints.port {
+ PortConstraint::Any => randomize_port(protocol),
+ PortConstraint::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 +719,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..28b905390d 100644
--- a/mullvad-daemon/src/management_interface.rs
+++ b/mullvad-daemon/src/management_interface.rs
@@ -10,7 +10,8 @@ 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::relay_constraints::{RelayConstraints, RelayConstraintsUpdate};
use mullvad_types::states::{DaemonState, TargetState};
use serde;
@@ -20,7 +21,6 @@ use std::collections::hash_map::Entry;
use std::net::{IpAddr, Ipv4Addr};
use std::sync::{Arc, Mutex, RwLock};
use std::sync::atomic::{AtomicBool, Ordering};
-
use talpid_core::mpsc::IntoSender;
use talpid_ipc;
use uuid;
@@ -56,13 +56,19 @@ 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>;
+ /// 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>;
- /// 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 = "get_relay_constraints")]
+ fn get_relay_constraints(
+ &self,
+ Self::Metadata
+ ) -> BoxFuture<RelayConstraints, Error>;
/// Set if the client should automatically establish a tunnel on start or not.
#[rpc(meta, name = "set_autoconnect")]
@@ -133,8 +139,10 @@ 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),
+ /// Read the constraints put on the tunnel and relay
+ GetRelayConstraints(OneshotSender<RelayConstraints>),
/// Makes the daemon exit the main loop and quit.
Shutdown,
}
@@ -382,26 +390,26 @@ 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");
+ fn get_relay_constraints(&self, meta: Self::Metadata) -> BoxFuture<RelayConstraints, Error> {
+ trace!("get_relay_constraints");
try_future!(self.check_auth(&meta));
let (tx, rx) = sync::oneshot::channel();
- let future = self.send_command_to_daemon(TunnelCommand::SetCustomRelay(tx, None))
+ let future = self.send_command_to_daemon(TunnelCommand::GetRelayConstraints(tx))
.and_then(|_| rx.map_err(|_| Error::internal_error()));
Box::new(future)
}
diff --git a/mullvad-daemon/src/settings.rs b/mullvad-daemon/src/settings.rs
index 1ba32eb178..d1a852c11d 100644
--- a/mullvad-daemon/src/settings.rs
+++ b/mullvad-daemon/src/settings.rs
@@ -1,12 +1,13 @@
extern crate app_dirs;
-extern crate toml;
+extern crate serde_json;
use self::app_dirs::{AppDataType, AppInfo};
-use mullvad_types::relay_endpoint::RelayEndpoint;
-
+use mullvad_types::relay_constraints::{HostConstraint, OpenVpnConstraints, PortConstraint,
+ ProtocolConstraint, RelayConstraints,
+ RelayConstraintsUpdate, TunnelConstraints};
use std::fs::File;
-use std::io::{self, Read, Write};
+use std::io;
use std::path::PathBuf;
error_chain! {
@@ -33,17 +34,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: HostConstraint::Any,
+ tunnel: TunnelConstraints::OpenVpn(OpenVpnConstraints {
+ port: PortConstraint::Any,
+ protocol: ProtocolConstraint::Any,
+ }),
+ },
};
impl Settings {
@@ -53,7 +67,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 +82,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 +96,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,19 +131,20 @@ 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"),
- }
-
- self.custom_relay = relay_endpoint;
+ pub fn update_relay_constraints(&mut self, update: RelayConstraintsUpdate) -> Result<bool> {
+ let new_constraints = self.relay_constraints.merge(update);
+ if self.relay_constraints != new_constraints {
+ debug!(
+ "changing relay constraints from {:?} to {:?}",
+ self.relay_constraints,
+ new_constraints
+ );
+ self.relay_constraints = new_constraints;
self.save().map(|_| true)
} else {
Ok(false)
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..26a3a04f84
--- /dev/null
+++ b/mullvad-types/src/relay_constraints.rs
@@ -0,0 +1,95 @@
+use talpid_types::net::TransportProtocol;
+
+#[derive(Debug, Clone, Deserialize, Serialize, Eq, PartialEq)]
+#[serde(rename_all = "snake_case")]
+pub struct RelayConstraints {
+ pub host: HostConstraint,
+ pub tunnel: TunnelConstraints,
+}
+
+impl RelayConstraints {
+ pub fn merge(&mut self, update: RelayConstraintsUpdate) -> Self {
+ RelayConstraints {
+ host: update.host.unwrap_or_else(|| self.host.clone()),
+ tunnel: self.tunnel.merge(update.tunnel),
+ }
+ }
+}
+
+
+#[derive(Debug, Clone, Deserialize, Serialize, Eq, PartialEq)]
+#[serde(rename_all = "snake_case")]
+pub enum TunnelConstraints {
+ #[serde(rename = "openvpn")] OpenVpn(OpenVpnConstraints),
+}
+
+impl TunnelConstraints {
+ pub fn merge(&mut self, update: TunnelConstraintsUpdate) -> Self {
+ match *self {
+ TunnelConstraints::OpenVpn(ref mut current) => match update {
+ TunnelConstraintsUpdate::OpenVpn(openvpn_update) => {
+ TunnelConstraints::OpenVpn(current.merge(openvpn_update))
+ }
+ },
+ }
+ }
+}
+
+#[derive(Debug, Clone, Deserialize, Serialize, Eq, PartialEq)]
+#[serde(rename_all = "snake_case")]
+pub struct OpenVpnConstraints {
+ pub port: PortConstraint,
+ pub protocol: ProtocolConstraint,
+}
+
+impl OpenVpnConstraints {
+ pub fn merge(&mut self, update: OpenVpnConstraintsUpdate) -> Self {
+ OpenVpnConstraints {
+ port: update.port.unwrap_or_else(|| self.port.clone()),
+ protocol: update.protocol.unwrap_or_else(|| self.protocol.clone()),
+ }
+ }
+}
+
+
+#[derive(Debug, Deserialize, Serialize)]
+#[serde(rename_all = "snake_case")]
+pub struct RelayConstraintsUpdate {
+ pub host: Option<HostConstraint>,
+ pub tunnel: TunnelConstraintsUpdate,
+}
+
+#[derive(Debug, Deserialize, Serialize)]
+#[serde(rename_all = "snake_case")]
+pub enum TunnelConstraintsUpdate {
+ #[serde(rename = "openvpn")] OpenVpn(OpenVpnConstraintsUpdate),
+}
+
+#[derive(Debug, Deserialize, Serialize)]
+#[serde(rename_all = "snake_case")]
+pub struct OpenVpnConstraintsUpdate {
+ pub port: Option<PortConstraint>,
+ pub protocol: Option<ProtocolConstraint>,
+}
+
+
+#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
+#[serde(rename_all = "snake_case")]
+pub enum HostConstraint {
+ Any,
+ Host(String),
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
+#[serde(rename_all = "snake_case")]
+pub enum PortConstraint {
+ Any,
+ Port(u16),
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
+#[serde(rename_all = "snake_case")]
+pub enum ProtocolConstraint {
+ Any,
+ Protocol(TransportProtocol),
+}