summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorLinus Färnstrand <linus@mullvad.net>2016-12-06 23:42:22 +0100
committerLinus Färnstrand <linus@mullvad.net>2016-12-06 23:42:22 +0100
commit876441779e8bdb64abe7822969a822db81f5c7ac (patch)
tree84d85d3371e13e6dc8dcbafc5970f204f6435c05
parent22da2098045bdf69a178eb7e4eaaaf38989235af (diff)
parent532fb722fef76a501643f63ebc3eec4734050d25 (diff)
downloadmullvadvpn-876441779e8bdb64abe7822969a822db81f5c7ac.tar.xz
mullvadvpn-876441779e8bdb64abe7822969a822db81f5c7ac.zip
Merge branch 'add-remotes'
-rw-r--r--src/lib.rs3
-rw-r--r--src/net.rs40
-rw-r--r--src/process.rs61
3 files changed, 101 insertions, 3 deletions
diff --git a/src/lib.rs b/src/lib.rs
index fec2e1da5e..c65c221aec 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -5,6 +5,9 @@
/// Working with processes.
pub mod process;
+/// Network primitives.
+pub mod net;
+
#[cfg(test)]
mod tests {
#[test]
diff --git a/src/net.rs b/src/net.rs
new file mode 100644
index 0000000000..0906426f7b
--- /dev/null
+++ b/src/net.rs
@@ -0,0 +1,40 @@
+/// Representation of a TCP or UDP endpoint. The host is represented as a String since it can be
+/// both a hostname/domain as well as an IP.
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct RemoteAddr {
+ address: String,
+ port: u16,
+}
+
+impl RemoteAddr {
+ /// Constructs a new `RemoteAddr` from the given address and port.
+ pub fn new(address: &str, port: u16) -> Self {
+ RemoteAddr {
+ address: address.to_owned(),
+ port: port,
+ }
+ }
+
+ /// Returns the address associated with this `RemoteAddr`.
+ pub fn address(&self) -> &str {
+ &self.address
+ }
+
+ /// Returns the port associated with this `RemoteAddr`.
+ pub fn port(&self) -> u16 {
+ self.port
+ }
+}
+
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn remote_addr_new_and_getters() {
+ let remote_addr = RemoteAddr::new("a_domain", 543);
+ assert_eq!("a_domain", remote_addr.address());
+ assert_eq!(543, remote_addr.port());
+ }
+}
diff --git a/src/process.rs b/src/process.rs
index 7143b85eb3..eb372de04e 100644
--- a/src/process.rs
+++ b/src/process.rs
@@ -1,3 +1,5 @@
+use net::RemoteAddr;
+
use std::ffi::{OsString, OsStr};
use std::io;
use std::path::{Path, PathBuf};
@@ -8,6 +10,7 @@ use std::process::{Command, Child, Stdio};
pub struct OpenVpnBuilder {
openvpn_bin: OsString,
config: Option<PathBuf>,
+ remotes: Vec<RemoteAddr>,
}
impl OpenVpnBuilder {
@@ -17,6 +20,7 @@ impl OpenVpnBuilder {
OpenVpnBuilder {
openvpn_bin: OsString::from(openvpn_bin.as_ref()),
config: None,
+ remotes: vec![],
}
}
@@ -26,10 +30,17 @@ impl OpenVpnBuilder {
self
}
+ /// Sets the addresses that OpenVPN will connect to. See OpenVPN documentation for how multiple
+ /// remotes are handled.
+ pub fn remotes(&mut self, remotes: Vec<RemoteAddr>) -> &mut Self {
+ self.remotes = remotes;
+ self
+ }
+
/// Executes the OpenVPN process as a child process, returning a handle to it.
pub fn spawn(&mut self) -> io::Result<Child> {
let mut command = self.create_command();
- self.apply_settings(&mut command);
+ command.args(&self.get_arguments());
command.spawn()
}
@@ -42,9 +53,53 @@ impl OpenVpnBuilder {
command
}
- fn apply_settings(&self, command: &mut Command) {
+ /// Returns all arguments that the subprocess would be spawned with.
+ pub fn get_arguments(&self) -> Vec<OsString> {
+ let mut args = vec![];
if let Some(ref config) = self.config {
- command.arg("--config").arg(config);
+ args.push(OsString::from("--config"));
+ args.push(OsString::from(config.as_os_str()));
+ }
+ for remote in &self.remotes {
+ args.push(OsString::from("--remote"));
+ args.push(OsString::from(remote.address()));
+ args.push(OsString::from(remote.port().to_string()));
}
+ args
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use net::RemoteAddr;
+ use std::ffi::OsString;
+ use super::OpenVpnBuilder;
+
+ #[test]
+ fn no_arguments() {
+ let args = OpenVpnBuilder::new("").get_arguments();
+ assert_eq!(0, args.len());
+ }
+
+ #[test]
+ fn passes_one_remote() {
+ let remotes = vec![RemoteAddr::new("example.com", 3333)];
+
+ let args = OpenVpnBuilder::new("").remotes(remotes).get_arguments();
+
+ assert!(args.contains(&OsString::from("example.com")));
+ assert!(args.contains(&OsString::from("3333")));
+ }
+
+ #[test]
+ fn passes_two_remotes() {
+ let remotes = vec![RemoteAddr::new("127.0.0.1", 998), RemoteAddr::new("fe80::1", 1337)];
+
+ let args = OpenVpnBuilder::new("").remotes(remotes).get_arguments();
+
+ assert!(args.contains(&OsString::from("127.0.0.1")));
+ assert!(args.contains(&OsString::from("998")));
+ assert!(args.contains(&OsString::from("fe80::1")));
+ assert!(args.contains(&OsString::from("1337")));
}
}