aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Garrelou <simon@sixfoisneuf.fr>2023-05-01 19:37:58 +0200
committerSimon Garrelou <simon@sixfoisneuf.fr>2023-05-01 19:37:58 +0200
commit43fea8e62bd7e678a56436d1702eed01c79f4767 (patch)
tree1cf22ff97bfb1e66b449ef0dbeb508ad4d6eb71e
parentb3380324c466e01f71749416e97da9b76025008b (diff)
downloadwgmgr-43fea8e62bd7e678a56436d1702eed01c79f4767.tar.gz
wgmgr-43fea8e62bd7e678a56436d1702eed01c79f4767.zip
Add 'rm' and 'wg' commands
-rw-r--r--src/main.rs90
-rw-r--r--src/wg/config.rs3
-rw-r--r--src/wg/peer.rs2
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;
4use std::str::FromStr; 4use std::str::FromStr;
5use std::{env, process::exit}; 5use std::{env, process::exit};
6use std::io::Write; 6use std::io::Write;
7use std::process::Command as processCommand;
7 8
8use anyhow::{Result, anyhow}; 9use anyhow::{Result, anyhow, Context};
9use clap::{command, ArgMatches}; 10use clap::{command, ArgMatches};
10use clap::Command; 11use clap::Command;
11use clap::arg; 12use 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
278fn 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
308fn 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());