diff options
Diffstat (limited to 'src/main.rs')
-rw-r--r-- | src/main.rs | 143 |
1 files changed, 33 insertions, 110 deletions
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 | } | ||