diff options
author | Simon Garrelou <simon.garrelou@gmail.com> | 2023-06-02 21:23:29 +0200 |
---|---|---|
committer | Simon Garrelou <simon.garrelou@gmail.com> | 2023-06-02 21:23:29 +0200 |
commit | c0140aa3ace8e9d87f118c56d242a2afbea36d33 (patch) | |
tree | 8e9b1adb40ba7e71b36fd31437d7f26eaf633c9e | |
parent | 4e2bb828db4afa55c0cbcd4b5bce14ca64b982e3 (diff) | |
download | wgmgr-c0140aa3ace8e9d87f118c56d242a2afbea36d33.tar.gz wgmgr-c0140aa3ace8e9d87f118c56d242a2afbea36d33.zip |
Put each function into its own file
-rw-r--r-- | src/add.rs | 33 | ||||
-rw-r--r-- | src/config.rs | 16 | ||||
-rw-r--r-- | src/configuration.rs | 31 | ||||
-rw-r--r-- | src/list.rs | 14 | ||||
-rw-r--r-- | src/main.rs | 143 | ||||
-rw-r--r-- | src/rm.rs | 36 | ||||
-rw-r--r-- | src/wgcmd.rs | 25 |
7 files changed, 157 insertions, 141 deletions
diff --git a/src/add.rs b/src/add.rs new file mode 100644 index 0000000..8ccf53b --- /dev/null +++ b/src/add.rs | |||
@@ -0,0 +1,33 @@ | |||
1 | use std::{net::Ipv4Addr, str::FromStr, fs::File}; | ||
2 | use std::io::Write; | ||
3 | use anyhow::{anyhow, Result}; | ||
4 | use crate::wg::{config::WireguardConfig, peer::Peer}; | ||
5 | |||
6 | pub fn run(wg_conf: &mut WireguardConfig, wg_conf_path: String, peer_name: &String, ip: Option<&String>) -> Result<()> { | ||
7 | let ip = match ip { | ||
8 | Some(s) => { | ||
9 | Ipv4Addr::from_str(s.as_str())? | ||
10 | }, | ||
11 | None => { | ||
12 | match wg_conf.next_free_ip() { | ||
13 | Ok(i) => i, | ||
14 | Err(e) => { | ||
15 | return Err(e); | ||
16 | } | ||
17 | } | ||
18 | } | ||
19 | }; | ||
20 | |||
21 | match wg_conf.get_peer(peer_name.as_str()) { | ||
22 | Some(_) => { return Err(anyhow!("There is already a peer named {}", peer_name)); }, | ||
23 | None => {} | ||
24 | } | ||
25 | |||
26 | let p = Peer::new(peer_name.clone(), ip)?; | ||
27 | wg_conf.peers.push(p); | ||
28 | |||
29 | let mut f = File::create(wg_conf_path)?; | ||
30 | write!(f, "{}", wg_conf.gen_config()?)?; | ||
31 | |||
32 | Ok(()) | ||
33 | } \ No newline at end of file | ||
diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..5ae4e1e --- /dev/null +++ b/src/config.rs | |||
@@ -0,0 +1,16 @@ | |||
1 | use crate::wg::config::WireguardConfig; | ||
2 | use crate::Configuration; | ||
3 | use anyhow::{anyhow, Result}; | ||
4 | |||
5 | pub fn run(wg_conf: &WireguardConfig, conf: &Configuration, peer_name: String, is_full: bool) -> Result<()> { | ||
6 | let peer = match wg_conf.get_peer(peer_name.as_str()) { | ||
7 | Some(p) => p, | ||
8 | None => { | ||
9 | return Err(anyhow!("No such peer: {}", peer_name)); | ||
10 | } | ||
11 | }; | ||
12 | |||
13 | println!("{}", peer.gen_config(wg_conf, conf.dns.clone(), conf.endpoint.clone(), conf.port, is_full)?); | ||
14 | |||
15 | Ok(()) | ||
16 | } \ No newline at end of file | ||
diff --git a/src/configuration.rs b/src/configuration.rs deleted file mode 100644 index 839db24..0000000 --- a/src/configuration.rs +++ /dev/null | |||
@@ -1,31 +0,0 @@ | |||
1 | use serde::Deserialize; | ||
2 | use anyhow::{Result, anyhow, Context}; | ||
3 | use std::fs::read_to_string; | ||
4 | |||
5 | #[derive(Deserialize)] | ||
6 | pub struct Configuration { | ||
7 | pub endpoint: String, | ||
8 | pub wgconf: String, | ||
9 | pub port: Option<u32>, | ||
10 | pub dns: Option<String>, | ||
11 | } | ||
12 | |||
13 | pub fn find_configuration_file(argument: Option<&String>) -> Result<Configuration> { | ||
14 | match argument { | ||
15 | Some(p) => { | ||
16 | if let Ok(t) = read_to_string(p) { | ||
17 | let c: Configuration = toml::from_str(&t).context("parsing configuration file")?; | ||
18 | return Ok(c) | ||
19 | } | ||
20 | }, | ||
21 | None => { | ||
22 | // Try /etc/wgmgr.toml | ||
23 | if let Ok(t) = read_to_string("/etc/wgmgr.toml") { | ||
24 | let c: Configuration = toml::from_str(&t).context("parsing /etc/wgmgr.toml")?; | ||
25 | return Ok(c) | ||
26 | } | ||
27 | }, | ||
28 | }; | ||
29 | |||
30 | Err(anyhow!("Could not find a valid configuration file for wgmgr.")) | ||
31 | } | ||
diff --git a/src/list.rs b/src/list.rs new file mode 100644 index 0000000..3baba8f --- /dev/null +++ b/src/list.rs | |||
@@ -0,0 +1,14 @@ | |||
1 | use crate::wg::config::WireguardConfig; | ||
2 | |||
3 | pub fn run(wg_conf: &WireguardConfig) { | ||
4 | let mut max_length = 0; | ||
5 | for p in wg_conf.peers.iter() { | ||
6 | if p.name.len() > max_length { | ||
7 | max_length = p.name.len(); | ||
8 | } | ||
9 | } | ||
10 | |||
11 | for p in wg_conf.peers.iter() { | ||
12 | println!("{:max_length$} | {}", p.name, p.ip); | ||
13 | } | ||
14 | } \ No newline at end of file | ||
diff --git a/src/main.rs b/src/main.rs index 3f82d43..17b920d 100644 --- a/src/main.rs +++ b/src/main.rs | |||
@@ -1,16 +1,17 @@ | |||
1 | use std::fs::File; | ||
2 | use std::net::Ipv4Addr; | ||
3 | use std::str::FromStr; | ||
4 | use std::{env, process::exit}; | 1 | use std::{env, process::exit}; |
5 | use std::io::Write; | 2 | |
6 | use std::process::Command as processCommand; | ||
7 | 3 | ||
8 | use anyhow::{Result, anyhow, Context}; | 4 | use anyhow::{Result, anyhow, Context}; |
9 | use clap::{arg, command, Command}; | 5 | use clap::{arg, command, Command}; |
10 | use wg::config::WireguardConfig; | 6 | use serde::Deserialize; |
7 | use std::fs::read_to_string; | ||
11 | 8 | ||
12 | mod wg; | 9 | mod wg; |
13 | mod configuration; | 10 | mod list; |
11 | mod rm; | ||
12 | mod add; | ||
13 | mod wgcmd; | ||
14 | mod config; | ||
14 | 15 | ||
15 | fn main() { | 16 | fn main() { |
16 | let matches = command!() | 17 | let matches = command!() |
@@ -80,7 +81,7 @@ fn main() { | |||
80 | 81 | ||
81 | 82 | ||
82 | // Find the configuration file for wgmgr | 83 | // Find the configuration file for wgmgr |
83 | let wgmgr_conf = match configuration::find_configuration_file(matches.get_one::<String>("config")) { | 84 | let wgmgr_conf = match find_configuration_file(matches.get_one::<String>("config")) { |
84 | Ok(c) => c, | 85 | Ok(c) => c, |
85 | Err(e) => { | 86 | Err(e) => { |
86 | eprintln!("Could not find wgmgr configuration file. Place it at /etc/wgmgr.toml or use the --config flag."); | 87 | eprintln!("Could not find wgmgr configuration file. Place it at /etc/wgmgr.toml or use the --config flag."); |
@@ -102,7 +103,7 @@ fn main() { | |||
102 | 103 | ||
103 | match matches.subcommand() { | 104 | match matches.subcommand() { |
104 | Some(("ls", _)) => { | 105 | Some(("ls", _)) => { |
105 | do_list(&wg_conf); | 106 | list::run(&wg_conf); |
106 | } | 107 | } |
107 | 108 | ||
108 | Some(("config", args)) => { | 109 | Some(("config", args)) => { |
@@ -122,7 +123,7 @@ fn main() { | |||
122 | None => false | 123 | None => false |
123 | }; | 124 | }; |
124 | 125 | ||
125 | if let Err(e) = do_config(&wg_conf, &wgmgr_conf, peer_name.to_string(), is_full) { | 126 | if let Err(e) = config::run(&wg_conf, &wgmgr_conf, peer_name.to_string(), is_full) { |
126 | eprintln!("Error generating configuration for {}: {:?}", peer_name.to_string(), e); | 127 | eprintln!("Error generating configuration for {}: {:?}", peer_name.to_string(), e); |
127 | exit(1); | 128 | exit(1); |
128 | } | 129 | } |
@@ -133,7 +134,7 @@ fn main() { | |||
133 | 134 | ||
134 | Some(("add", args)) => { | 135 | Some(("add", args)) => { |
135 | let new_name = args.get_one::<String>("NAME").unwrap().to_string(); | 136 | let new_name = args.get_one::<String>("NAME").unwrap().to_string(); |
136 | if let Err(e) = do_add(&mut wg_conf, wgmgr_conf.wgconf, &new_name, args.get_one::<String>("ip")) { | 137 | if let Err(e) = add::run(&mut wg_conf, wgmgr_conf.wgconf, &new_name, args.get_one::<String>("ip")) { |
137 | eprintln!("Error adding peer: {:?}", e); | 138 | eprintln!("Error adding peer: {:?}", e); |
138 | exit(1); | 139 | exit(1); |
139 | } | 140 | } |
@@ -144,7 +145,7 @@ fn main() { | |||
144 | 145 | ||
145 | Some(("rm", args)) => { | 146 | Some(("rm", args)) => { |
146 | let rm_name = args.get_one::<String>("NAME").unwrap().to_string(); | 147 | let rm_name = args.get_one::<String>("NAME").unwrap().to_string(); |
147 | if let Err(e) = do_rm(&mut wg_conf, wgmgr_conf.wgconf, &rm_name) { | 148 | if let Err(e) = rm::run(&mut wg_conf, wgmgr_conf.wgconf, &rm_name) { |
148 | eprintln!("Error removing peer: {:?}", e); | 149 | eprintln!("Error removing peer: {:?}", e); |
149 | exit(1); | 150 | exit(1); |
150 | } | 151 | } |
@@ -153,7 +154,7 @@ fn main() { | |||
153 | }, | 154 | }, |
154 | 155 | ||
155 | Some(("wg", _)) => { | 156 | Some(("wg", _)) => { |
156 | if let Err(e) = do_wg(&wg_conf) { | 157 | if let Err(e) = wgcmd::run(&wg_conf) { |
157 | eprintln!("{:?}", e); | 158 | eprintln!("{:?}", e); |
158 | exit(1); | 159 | exit(1); |
159 | } | 160 | } |
@@ -166,109 +167,31 @@ fn main() { | |||
166 | 167 | ||
167 | } | 168 | } |
168 | 169 | ||
169 | fn do_list(wg_conf: &wg::config::WireguardConfig) { | 170 | #[derive(Deserialize)] |
170 | let mut max_length = 0; | 171 | pub struct Configuration { |
171 | for p in wg_conf.peers.iter() { | 172 | pub endpoint: String, |
172 | if p.name.len() > max_length { | 173 | pub wgconf: String, |
173 | max_length = p.name.len(); | 174 | pub port: Option<u32>, |
174 | } | 175 | pub dns: Option<String>, |
175 | } | ||
176 | |||
177 | for p in wg_conf.peers.iter() { | ||
178 | println!("{:max_length$} | {}", p.name, p.ip); | ||
179 | } | ||
180 | } | 176 | } |
181 | 177 | ||
182 | fn do_config(wg_conf: &wg::config::WireguardConfig, conf: &configuration::Configuration, peer_name: String, is_full: bool) -> Result<()> { | 178 | pub fn find_configuration_file(argument: Option<&String>) -> Result<Configuration> { |
183 | let peer = match wg_conf.get_peer(peer_name.as_str()) { | 179 | match argument { |
184 | Some(p) => p, | 180 | Some(p) => { |
185 | None => { | 181 | if let Ok(t) = read_to_string(p) { |
186 | return Err(anyhow!("No such peer: {}", peer_name)); | 182 | let c: Configuration = toml::from_str(&t).context("parsing configuration file")?; |
187 | } | 183 | return Ok(c) |
188 | }; | 184 | } |
189 | |||
190 | println!("{}", peer.gen_config(wg_conf, conf.dns.clone(), conf.endpoint.clone(), conf.port, is_full)?); | ||
191 | |||
192 | Ok(()) | ||
193 | } | ||
194 | |||
195 | fn do_add(wg_conf: &mut WireguardConfig, wg_conf_path: String, peer_name: &String, ip: Option<&String>) -> Result<()> { | ||
196 | let ip = match ip { | ||
197 | Some(s) => { | ||
198 | Ipv4Addr::from_str(s.as_str())? | ||
199 | }, | 185 | }, |
200 | None => { | 186 | None => { |
201 | match wg_conf.next_free_ip() { | 187 | // Try /etc/wgmgr.toml |
202 | Ok(i) => i, | 188 | if let Ok(t) = read_to_string("/etc/wgmgr.toml") { |
203 | Err(e) => { | 189 | let c: Configuration = toml::from_str(&t).context("parsing /etc/wgmgr.toml")?; |
204 | return Err(e); | 190 | return Ok(c) |
205 | } | ||
206 | } | 191 | } |
207 | } | 192 | }, |
208 | }; | 193 | }; |
209 | 194 | ||
210 | match wg_conf.get_peer(peer_name.as_str()) { | 195 | Err(anyhow!("Could not find a valid configuration file for wgmgr.")) |
211 | Some(_) => { return Err(anyhow!("There is already a peer named {}", peer_name)); }, | ||
212 | None => {} | ||
213 | } | ||
214 | |||
215 | let p = wg::peer::Peer::new(peer_name.clone(), ip)?; | ||
216 | wg_conf.peers.push(p); | ||
217 | |||
218 | let mut f = File::create(wg_conf_path)?; | ||
219 | write!(f, "{}", wg_conf.gen_config()?)?; | ||
220 | |||
221 | Ok(()) | ||
222 | } | 196 | } |
223 | 197 | ||
224 | fn do_rm(wg_conf: &mut WireguardConfig, wg_conf_path: String, peer_name: &String) -> Result<()> { | ||
225 | let mut del_index = 0; | ||
226 | let mut found = false; | ||
227 | let mut pk_path = String::new(); | ||
228 | |||
229 | for (i, peer) in wg_conf.peers.iter().enumerate() { | ||
230 | if &peer.name == peer_name { | ||
231 | del_index = i; | ||
232 | found = true; | ||
233 | pk_path = peer.private_key_path().context("could not get private key path")?; | ||
234 | break; | ||
235 | } | ||
236 | } | ||
237 | |||
238 | if !found { | ||
239 | return Err(anyhow!("No such peer: {}", peer_name)); | ||
240 | } | ||
241 | |||
242 | wg_conf.peers.remove(del_index); | ||
243 | |||
244 | let mut f = File::create(wg_conf_path.clone()).context(format!("error opening configuration file: {}", wg_conf_path))?; | ||
245 | let data = wg_conf.gen_config().context("error generating configuration")?; | ||
246 | |||
247 | f.write_all(data.as_bytes()).context(format!("error writing to file: {}", wg_conf_path))?; | ||
248 | |||
249 | std::fs::remove_file(pk_path).context(format!("could not remove file: {}", wg_conf_path))?; | ||
250 | |||
251 | Ok(()) | ||
252 | } | ||
253 | |||
254 | fn do_wg(wg_conf: &WireguardConfig) -> Result<()> { | ||
255 | let wg = processCommand::new("wg") | ||
256 | .env("WG_COLOR_MODE", "always") | ||
257 | .output() | ||
258 | .context("could not run 'wg', is it installed?")?; | ||
259 | |||
260 | if !wg.status.success() { | ||
261 | let err = String::from_utf8(wg.stderr)?; | ||
262 | return Err(anyhow!("error running 'wg': {}", err)); | ||
263 | } | ||
264 | |||
265 | let mut out = String::from_utf8(wg.stdout).context("error parsing stdout")?; | ||
266 | |||
267 | for peer in wg_conf.peers.iter() { | ||
268 | out = out.replace(peer.public_key.as_str(), peer.name.as_str()); | ||
269 | } | ||
270 | |||
271 | println!("{}", out); | ||
272 | |||
273 | Ok(()) | ||
274 | } | ||
diff --git a/src/rm.rs b/src/rm.rs new file mode 100644 index 0000000..61880d2 --- /dev/null +++ b/src/rm.rs | |||
@@ -0,0 +1,36 @@ | |||
1 | use std::{fs::File, io::Write}; | ||
2 | |||
3 | use anyhow::{anyhow, Result, Context}; | ||
4 | |||
5 | use crate::wg::config::WireguardConfig; | ||
6 | |||
7 | pub fn run(wg_conf: &mut WireguardConfig, wg_conf_path: String, peer_name: &String) -> Result<()> { | ||
8 | let mut del_index = 0; | ||
9 | let mut found = false; | ||
10 | let mut pk_path = String::new(); | ||
11 | |||
12 | for (i, peer) in wg_conf.peers.iter().enumerate() { | ||
13 | if &peer.name == peer_name { | ||
14 | del_index = i; | ||
15 | found = true; | ||
16 | pk_path = peer.private_key_path().context("could not get private key path")?; | ||
17 | break; | ||
18 | } | ||
19 | } | ||
20 | |||
21 | if !found { | ||
22 | return Err(anyhow!("No such peer: {}", peer_name)); | ||
23 | } | ||
24 | |||
25 | wg_conf.peers.remove(del_index); | ||
26 | |||
27 | let mut f = File::create(wg_conf_path.clone()).context(format!("error opening configuration file: {}", wg_conf_path))?; | ||
28 | let data = wg_conf.gen_config().context("error generating configuration")?; | ||
29 | |||
30 | f.write_all(data.as_bytes()).context(format!("error writing to file: {}", wg_conf_path))?; | ||
31 | |||
32 | std::fs::remove_file(pk_path).context(format!("could not remove file: {}", wg_conf_path))?; | ||
33 | |||
34 | Ok(()) | ||
35 | } | ||
36 | |||
diff --git a/src/wgcmd.rs b/src/wgcmd.rs new file mode 100644 index 0000000..32a23a6 --- /dev/null +++ b/src/wgcmd.rs | |||
@@ -0,0 +1,25 @@ | |||
1 | use crate::wg::config::WireguardConfig; | ||
2 | use std::process::Command; | ||
3 | use anyhow::{anyhow, Result, Context}; | ||
4 | |||
5 | pub fn run(wg_conf: &WireguardConfig) -> Result<()> { | ||
6 | let wg = Command::new("wg") | ||
7 | .env("WG_COLOR_MODE", "always") | ||
8 | .output() | ||
9 | .context("could not run 'wg', is it installed?")?; | ||
10 | |||
11 | if !wg.status.success() { | ||
12 | let err = String::from_utf8(wg.stderr)?; | ||
13 | return Err(anyhow!("error running 'wg': {}", err)); | ||
14 | } | ||
15 | |||
16 | let mut out = String::from_utf8(wg.stdout).context("error parsing stdout")?; | ||
17 | |||
18 | for peer in wg_conf.peers.iter() { | ||
19 | out = out.replace(peer.public_key.as_str(), peer.name.as_str()); | ||
20 | } | ||
21 | |||
22 | println!("{}", out); | ||
23 | |||
24 | Ok(()) | ||
25 | } | ||