aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/fileutil.rs5
-rw-r--r--src/manager/mod.rs4
-rw-r--r--src/wg.rs114
3 files changed, 73 insertions, 50 deletions
diff --git a/src/fileutil.rs b/src/fileutil.rs
index 941eb08..67c48e2 100644
--- a/src/fileutil.rs
+++ b/src/fileutil.rs
@@ -25,6 +25,11 @@ impl Drop for Temp {
impl Temp {
#[inline]
+ pub fn path(&self) -> &Path {
+ &self.path
+ }
+
+ #[inline]
pub fn leave(mut self) -> PathBuf {
mem::replace(&mut self.path, PathBuf::new())
}
diff --git a/src/manager/mod.rs b/src/manager/mod.rs
index 646349a..0425e9d 100644
--- a/src/manager/mod.rs
+++ b/src/manager/mod.rs
@@ -35,11 +35,11 @@ impl Manager {
io::Error::new(io::ErrorKind::InvalidInput, "runtime directory required")
})?;
- let mut state_path = runtime_directory;
+ let mut state_path = runtime_directory.clone();
state_path.push("state.json");
let mut m = Self {
- dev: wg::Device::open(ifname)?,
+ dev: wg::Device::open(ifname, runtime_directory)?,
global_config: c.global,
sources: vec![],
current: model::Config::empty(),
diff --git a/src/wg.rs b/src/wg.rs
index 766f18f..190c626 100644
--- a/src/wg.rs
+++ b/src/wg.rs
@@ -2,24 +2,26 @@
//
// Copyright 2019 Hristo Venev
-use crate::model;
+use crate::{fileutil, model};
use std::ffi::{OsStr, OsString};
+use std::path::PathBuf;
use std::process::{Command, Stdio};
use std::{env, fmt, io};
pub struct Device {
ifname: OsString,
+ tmpdir: PathBuf,
}
impl Device {
#[inline]
- pub fn open(ifname: OsString) -> io::Result<Self> {
- let dev = Self { ifname };
+ pub fn open(ifname: OsString, tmpdir: PathBuf) -> io::Result<Self> {
+ let dev = Self { ifname, tmpdir };
let _ = dev.get_public_key()?;
Ok(dev)
}
- pub fn wg_command() -> Command {
+ fn wg_command() -> Command {
let wg = match env::var_os("WG") {
None => OsString::new(),
Some(v) => v,
@@ -54,12 +56,7 @@ impl Device {
}
pub fn apply_diff(&mut self, old: &model::Config, new: &model::Config) -> io::Result<()> {
- let mut proc = Self::wg_command();
- proc.stdin(Stdio::piped());
- proc.stdout(Stdio::null());
- proc.arg("set");
- proc.arg(&self.ifname);
- let mut stdin = String::new();
+ let mut config = String::new();
for (pubkey, conf) in &new.peers {
let old_endpoint;
@@ -75,70 +72,91 @@ impl Device {
old_psk = None;
}
- proc.arg("peer");
- proc.arg(pubkey.to_string());
-
- proc.arg("persistent-keepalive");
- proc.arg(conf.keepalive.to_string());
+ use fmt::Write;
+ write!(
+ config,
+ "[Peer]\nPublicKey={}\nPersistentKeepalive={}\nAllowedIPs",
+ pubkey, conf.keepalive
+ )
+ .unwrap();
+ let mut delim = '=';
+ for ip in &conf.ipv4 {
+ config.push(delim);
+ delim = ',';
+ write!(config, "{}", ip).unwrap();
+ }
+ for ip in &conf.ipv6 {
+ config.push(delim);
+ delim = ',';
+ write!(config, "{}", ip).unwrap();
+ }
+ config.push('\n');
if old_endpoint != conf.endpoint {
if let Some(ref endpoint) = conf.endpoint {
- proc.arg("endpoint");
- proc.arg(endpoint.to_string());
+ write!(config, "Endpoint={}\n", endpoint).unwrap();
}
}
if old_psk != conf.psk.as_ref() {
- proc.arg("preshared-key");
- proc.arg("-");
+ config.push_str("PresharedKey=");
if let Some(psk) = conf.psk.as_ref() {
- use fmt::Write;
- writeln!(stdin, "{}", psk).unwrap();
+ writeln!(config, "{}", psk).unwrap();
+ config.push('\n');
} else {
- stdin.push('\n');
+ config.push_str("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\n");
}
}
+ }
- let mut ips = String::new();
- {
- use std::fmt::Write;
- for ip in &conf.ipv4 {
- if !ips.is_empty() {
- ips.push(',');
- }
- write!(ips, "{}", ip).unwrap();
- }
- for ip in &conf.ipv6 {
- if !ips.is_empty() {
- ips.push(',');
- }
- write!(ips, "{}", ip).unwrap();
- }
+ {
+ let mut config_file = fileutil::Writer::new_in(&self.tmpdir)?;
+ io::Write::write_all(config_file.file(), config.as_bytes())?;
+ let config_file = config_file.done();
+
+ let mut proc = Self::wg_command();
+ proc.stdin(Stdio::null());
+ proc.stdout(Stdio::null());
+ proc.arg("addconf");
+ proc.arg(&self.ifname);
+ proc.arg(config_file.path());
+
+ let r = proc.status()?;
+ if !r.success() {
+ return Err(io::Error::new(
+ io::ErrorKind::Other,
+ "`wg setconf' process failed",
+ ));
}
-
- proc.arg("allowed-ips");
- proc.arg(ips);
}
+ let mut proc = Self::wg_command();
+ let mut any_removed = false;
+ proc.stdin(Stdio::null());
+ proc.stdout(Stdio::null());
+ proc.arg("set");
+ proc.arg(&self.ifname);
+
for pubkey in old.peers.keys() {
if new.peers.contains_key(pubkey) {
continue;
}
+ any_removed = true;
proc.arg("peer");
proc.arg(pubkey.to_string());
proc.arg("remove");
}
- let mut proc = proc.spawn()?;
- {
- use io::Write;
- proc.stdin.as_mut().unwrap().write_all(stdin.as_bytes())?;
+ if any_removed {
+ let r = proc.status()?;
+ if !r.success() {
+ return Err(io::Error::new(
+ io::ErrorKind::Other,
+ "`wg set' process failed",
+ ));
+ }
}
- let r = proc.wait()?;
- if !r.success() {
- return Err(io::Error::new(io::ErrorKind::Other, "child process failed"));
- }
Ok(())
}
}