diff options
author | Simon Garrelou <simon@sixfoisneuf.fr> | 2023-05-01 19:37:58 +0200 |
---|---|---|
committer | Simon Garrelou <simon@sixfoisneuf.fr> | 2023-05-01 19:37:58 +0200 |
commit | 43fea8e62bd7e678a56436d1702eed01c79f4767 (patch) | |
tree | 1cf22ff97bfb1e66b449ef0dbeb508ad4d6eb71e | |
parent | b3380324c466e01f71749416e97da9b76025008b (diff) | |
download | wgmgr-43fea8e62bd7e678a56436d1702eed01c79f4767.tar.gz wgmgr-43fea8e62bd7e678a56436d1702eed01c79f4767.zip |
Add 'rm' and 'wg' commands
-rw-r--r-- | src/main.rs | 90 | ||||
-rw-r--r-- | src/wg/config.rs | 3 | ||||
-rw-r--r-- | src/wg/peer.rs | 2 |
3 files changed, 93 insertions, 2 deletions
diff --git a/src/main.rs b/src/main.rs index a0e38ca..05b05a2 100644 --- a/src/main.rs +++ b/src/main.rs | |||
@@ -4,8 +4,9 @@ use std::net::Ipv4Addr; | |||
4 | use std::str::FromStr; | 4 | use std::str::FromStr; |
5 | use std::{env, process::exit}; | 5 | use std::{env, process::exit}; |
6 | use std::io::Write; | 6 | use std::io::Write; |
7 | use std::process::Command as processCommand; | ||
7 | 8 | ||
8 | use anyhow::{Result, anyhow}; | 9 | use anyhow::{Result, anyhow, Context}; |
9 | use clap::{command, ArgMatches}; | 10 | use clap::{command, ArgMatches}; |
10 | use clap::Command; | 11 | use clap::Command; |
11 | use clap::arg; | 12 | use clap::arg; |
@@ -59,6 +60,24 @@ fn main() { | |||
59 | .required(false) | 60 | .required(false) |
60 | ) | 61 | ) |
61 | ) | 62 | ) |
63 | |||
64 | // "rm" | ||
65 | .subcommand( | ||
66 | Command::new("rm") | ||
67 | .about("Remove a client from your VPN") | ||
68 | .arg( | ||
69 | arg!( | ||
70 | <NAME> "Name of the client to remove" | ||
71 | ) | ||
72 | .required(true) | ||
73 | ) | ||
74 | ) | ||
75 | |||
76 | // "wg" | ||
77 | .subcommand( | ||
78 | Command::new("wg") | ||
79 | .about("Run 'wg', but with the client names") | ||
80 | ) | ||
62 | .get_matches(); | 81 | .get_matches(); |
63 | 82 | ||
64 | let conf_path = match find_config_file(&matches) { | 83 | let conf_path = match find_config_file(&matches) { |
@@ -118,6 +137,23 @@ fn main() { | |||
118 | else { | 137 | else { |
119 | println!("Peer '{}' added successfully. Don't forget to restart your WireGuard server.", new_name); | 138 | println!("Peer '{}' added successfully. Don't forget to restart your WireGuard server.", new_name); |
120 | } | 139 | } |
140 | }, | ||
141 | |||
142 | Some(("rm", args)) => { | ||
143 | let rm_name = args.get_one::<String>("NAME").unwrap().to_string(); | ||
144 | if let Err(e) = do_rm(&mut conf, conf_path, &rm_name) { | ||
145 | eprintln!("Error removing peer: {}", e); | ||
146 | exit(1); | ||
147 | } | ||
148 | |||
149 | println!("Client '{}' removed successfully. Don't forget to restart your WireGuard server.", rm_name); | ||
150 | }, | ||
151 | |||
152 | Some(("wg", _)) => { | ||
153 | if let Err(e) = do_wg(&conf) { | ||
154 | eprintln!("{}", e); | ||
155 | exit(1); | ||
156 | } | ||
121 | } | 157 | } |
122 | 158 | ||
123 | _ => { | 159 | _ => { |
@@ -238,3 +274,55 @@ fn do_add(conf: &mut WireguardConfig, conf_path: String, peer_name: &String, ip: | |||
238 | 274 | ||
239 | Ok(()) | 275 | Ok(()) |
240 | } | 276 | } |
277 | |||
278 | fn do_rm(conf: &mut WireguardConfig, conf_path: String, peer_name: &String) -> Result<()> { | ||
279 | let mut del_index = 0; | ||
280 | let mut found = false; | ||
281 | let mut pk_path = String::new(); | ||
282 | |||
283 | for (i, peer) in conf.peers.iter().enumerate() { | ||
284 | if &peer.name == peer_name { | ||
285 | del_index = i; | ||
286 | found = true; | ||
287 | pk_path = peer.private_key_path().context("could not get private key path")?; | ||
288 | break; | ||
289 | } | ||
290 | } | ||
291 | |||
292 | if !found { | ||
293 | return Err(anyhow!("No such peer: {}", peer_name)); | ||
294 | } | ||
295 | |||
296 | conf.peers.remove(del_index); | ||
297 | |||
298 | let mut f = File::create(conf_path.clone()).context(format!("error opening configuration file: {}", conf_path))?; | ||
299 | let data = conf.gen_config().context("error generating configuration")?; | ||
300 | |||
301 | f.write_all(data.as_bytes()).context(format!("error writing to file: {}", conf_path))?; | ||
302 | |||
303 | std::fs::remove_file(pk_path).context(format!("could not remove file: {}", conf_path))?; | ||
304 | |||
305 | Ok(()) | ||
306 | } | ||
307 | |||
308 | fn do_wg(conf: &WireguardConfig) -> Result<()> { | ||
309 | let wg = processCommand::new("wg") | ||
310 | .env("WG_COLOR_MODE", "always") | ||
311 | .output() | ||
312 | .context("could not run 'wg', is it installed?")?; | ||
313 | |||
314 | if !wg.status.success() { | ||
315 | let err = String::from_utf8(wg.stderr)?; | ||
316 | return Err(anyhow!("error running 'wg': {}", err)); | ||
317 | } | ||
318 | |||
319 | let mut out = String::from_utf8(wg.stdout).context("error parsing stdout")?; | ||
320 | |||
321 | for peer in conf.peers.iter() { | ||
322 | out = out.replace(peer.public_key.as_str(), peer.name.as_str()); | ||
323 | } | ||
324 | |||
325 | println!("{}", out); | ||
326 | |||
327 | Ok(()) | ||
328 | } | ||
diff --git a/src/wg/config.rs b/src/wg/config.rs index 4e8c205..b354626 100644 --- a/src/wg/config.rs +++ b/src/wg/config.rs | |||
@@ -81,6 +81,9 @@ impl WireguardConfig { | |||
81 | let addr = config_value(line)?; | 81 | let addr = config_value(line)?; |
82 | conf.network = Ipv4Network::from_str(addr)?; | 82 | conf.network = Ipv4Network::from_str(addr)?; |
83 | } | 83 | } |
84 | else if line.starts_with("#") { | ||
85 | // We ignore comments, because they are used for peer identification | ||
86 | } | ||
84 | else { | 87 | else { |
85 | conf.other_lines.push(String::from(line)); | 88 | conf.other_lines.push(String::from(line)); |
86 | } | 89 | } |
diff --git a/src/wg/peer.rs b/src/wg/peer.rs index 1d2002f..7b703fc 100644 --- a/src/wg/peer.rs +++ b/src/wg/peer.rs | |||
@@ -74,7 +74,7 @@ impl Peer { | |||
74 | Ok(pk_folder) | 74 | Ok(pk_folder) |
75 | } | 75 | } |
76 | 76 | ||
77 | fn private_key_path(&self) -> Result<String> { | 77 | pub fn private_key_path(&self) -> Result<String> { |
78 | let folder_name = self.private_key_folder()?; | 78 | let folder_name = self.private_key_folder()?; |
79 | let pk_folder = Path::new(folder_name.as_str()); | 79 | let pk_folder = Path::new(folder_name.as_str()); |
80 | let pk_path = pk_folder.join(self.name.clone()); | 80 | let pk_path = pk_folder.join(self.name.clone()); |