diff --git a/Cargo.lock b/Cargo.lock index 62d5f56..a06e2d5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -43,9 +43,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.4" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44" +checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5" dependencies = [ "anstyle", "anstyle-parse", @@ -342,6 +342,29 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "env_filter" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9eeb342678d785662fd2514be38c459bb925f02b68dd2a3e0f21d7ef82d979dd" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "humantime", + "log", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -554,6 +577,12 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + [[package]] name = "hyper" version = "0.14.27" @@ -1576,8 +1605,10 @@ dependencies = [ "chrono", "cidr", "clap", + "env_logger", "git2", "hyper", + "log", "regex", "serde", "serde_ini", diff --git a/Cargo.toml b/Cargo.toml index e90e169..5f1a1c2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,8 @@ serde_ini = { git = "https://github.com/devyn/serde-ini" } url = { version = "2.5.0", features = ["serde"] } serde_with = "3.5.0" urlencoding = "2.1.3" +log = "0.4.20" +env_logger = "0.11.0" [build-dependencies] chrono = "0.4.31" diff --git a/src/helpers.rs b/src/helpers.rs new file mode 100644 index 0000000..c77e684 --- /dev/null +++ b/src/helpers.rs @@ -0,0 +1,9 @@ +use std::process::Output; +use tokio::process::Command; + +pub async fn command_output(command: &mut Command) -> std::io::Result { + log::debug!("Shell command {:?}", command); + let output = command.output().await; + log::debug!("Output: {:?}", output); + output +} diff --git a/src/main.rs b/src/main.rs index 2902b62..a189d55 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,10 +1,12 @@ use clap::Parser; +use helpers::command_output; use std::str::FromStr; use tokio::io::{self, AsyncBufReadExt, BufReader}; use warp::Filter; use wg::Peer; mod event; +mod helpers; mod wg; type WgLink = String; @@ -59,12 +61,13 @@ async fn wg_add_address( peer: WgPeer, cidr: cidr::IpInet, ) -> Result { - let output = match tokio::process::Command::new("wg") - .arg("show") - .arg(&link) - .arg("allowed-ips") - .output() - .await + let output = match command_output( + tokio::process::Command::new("wg") + .arg("show") + .arg(&link) + .arg("allowed-ips"), + ) + .await { Ok(v) => v, Err(_) => return Err(warp::reject::custom(RejectCommandFailedToExecute)), @@ -93,12 +96,10 @@ async fn wg_add_address( .arg(&peer) .arg("allowed-ips") .arg(ips_str); - println!("command = {:?}", command); - let output = match command.output().await { + let output = match command_output(&mut command).await { Ok(v) => v, Err(_) => return Err(warp::reject::custom(RejectCommandFailedToExecute)), }; - println!("{:?}", output); if output.status.success() { Ok("") @@ -177,35 +178,80 @@ async fn send_daemon(iface: WgLink, port: u16, peers: Vec) -> () { let mut command = tokio::process::Command::new("ip"); command.arg("monitor").arg("address").arg("dev").arg(&iface); command.stdout(std::process::Stdio::piped()); - println!("{:?}", command); + command.stderr(std::process::Stdio::piped()); + log::debug!("Shell command {:?}", command); let mut child = command.spawn().unwrap(); let stdout = child.stdout.take().unwrap(); + let stderr = child.stderr.take().unwrap(); let mut reader = BufReader::new(stdout); + let mut stderr_reader = BufReader::new(stderr); + let mut buffer: Vec = vec![]; + let mut stderr_buffer: Vec = vec![]; + let mut enable_stdout = true; + let mut enable_stderr = true; loop { - let mut buffer = String::new(); let mut send_add = false; let mut send_del = false; let cidr_: String; let public_key; + let b: String; - reader.read_line(&mut buffer).await.unwrap(); - if re_send_add.is_match(&buffer) { + if enable_stdout & enable_stderr { + tokio::select!( + v = reader.read_until('\n' as u8, &mut buffer) => { + if v.is_err() | v.is_ok_and(|v_| v_ == 0) { + enable_stdout = false; + continue; + } + b = String::from_utf8(buffer).unwrap(); + buffer = vec![]; + }, + v = stderr_reader.read_until('\n' as u8, &mut stderr_buffer) => { + if v.is_err() | v.is_ok_and(|v_| v_ == 0) { + enable_stderr = false; + continue; + } + let b = String::from_utf8(stderr_buffer).unwrap(); + stderr_buffer = vec![]; + log::error!("Monitor produced error: {:?}", &b); + continue; + }, + ); + } else if enable_stdout { + let v = reader.read_until('\n' as u8, &mut buffer).await; + if v.is_err() | v.is_ok_and(|v_| v_ == 0) { + enable_stdout = false; + continue; + } + b = String::from_utf8(buffer).unwrap(); + buffer = vec![]; + } else if enable_stderr { + let v = stderr_reader + .read_until('\n' as u8, &mut stderr_buffer) + .await; + if v.is_err() | v.is_ok_and(|v_| v_ == 0) { + enable_stderr = false; + continue; + } + let b = String::from_utf8(stderr_buffer).unwrap(); + stderr_buffer = vec![]; + log::error!("Monitor produced error: {:?}", &b); + continue; + } else { + break; + } + + if re_send_add.is_match(&b) { send_add = true; - } else if re_send_del.is_match(&buffer) { + } else if re_send_del.is_match(&b) { send_del = true; } if send_add | send_del { - cidr_ = urlencoding::encode( - re_extract_ip - .captures(&buffer) - .unwrap() - .get(1) - .unwrap() - .as_str(), - ) - .into(); + cidr_ = + urlencoding::encode(re_extract_ip.captures(&b).unwrap().get(1).unwrap().as_str()) + .into(); public_key = send_daemon_get_public_key(&iface).await; } else { continue; @@ -257,9 +303,11 @@ const BUILD_INFO: &str = include!(concat!(env!("OUT_DIR"), "/buildinfo.txt")); #[tokio::main] async fn main() { + env_logger::init_from_env("WGVIRTIPD_LOG"); let args = CliArguments::parse(); let config = wg::Wg::from_file(&args.link).await; + let alive = warp::path!("alive").and(warp::get()).map(|| BUILD_INFO); let base = warp::path("wireguard") .and(warp::path::param::()) .and(warp::path("peer")) @@ -283,12 +331,12 @@ async fn main() { .and(warp::path::end()) .and(warp::delete()) .and_then(wg_del_address); - let routes = address_add.or(address_del); + let routes = alive.or(address_add.or(address_del)); - println!("{}", BUILD_INFO); + log::info!("{}", BUILD_INFO); - let (r0, r1) = tokio::join!( - warp::serve(routes).run(args.addr), - send_daemon(args.link, args.addr.port(), config.peers), + tokio::select!( + _ = warp::serve(routes).run(args.addr) => {}, + _ = send_daemon(args.link, args.addr.port(), config.peers) => {}, ); }