From 18da61ed320966b1332e64037fc88b4073b4a8a5 Mon Sep 17 00:00:00 2001 From: Brandon W Maister Date: Wed, 31 Jul 2024 10:43:02 -0400 Subject: [PATCH] make server logging show messages in the frontend now you can use the log crate and get messages in the frontend. --- Cargo.lock | 26 +++++++++++++++--- Cargo.toml | 1 + src/client/mod.rs | 15 +++++++---- src/main.rs | 63 ++++++++++++++++++++++++++++++++----------- src/server/mod.rs | 4 +++ src/server/refresh.rs | 7 +++-- 6 files changed, 91 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 44eb670..0e3a387 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -261,6 +261,25 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" +[[package]] +name = "env_filter" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" +dependencies = [ + "log", +] + +[[package]] +name = "env_logger" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" +dependencies = [ + "env_filter", + "log", +] + [[package]] name = "errno" version = "0.3.9" @@ -302,6 +321,7 @@ dependencies = [ "bytes", "copypasta", "crossterm", + "env_logger", "home", "indoc", "log", @@ -446,7 +466,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e310b3a6b5907f99202fcdb4960ff45b93735d7c7d96b760fcff8db2dc0e103d" dependencies = [ "cfg-if", - "windows-targets 0.48.5", + "windows-targets 0.52.5", ] [[package]] @@ -473,9 +493,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.20" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "malloc_buf" diff --git a/Cargo.toml b/Cargo.toml index 1193872..6569ef7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,7 @@ anyhow = "1.0" bytes = "1" copypasta = "0.10.1" crossterm = { version = "0.25", features = ["event-stream"] } +env_logger = { version = "0.11.5", default-features = false } home = "0.5.4" indoc = "1" log = { version = "0.4", features = ["std"] } diff --git a/src/client/mod.rs b/src/client/mod.rs index e13b779..79b4b15 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -323,6 +323,7 @@ async fn client_main( async fn spawn_ssh( server: &str, sudo: bool, + log_filter: &str, ) -> Result<(tokio::process::Child, u16), std::io::Error> { let socks_port = { let listener = TcpListener::bind("127.0.0.1:0").await?; @@ -337,7 +338,9 @@ async fn spawn_ssh( if sudo { cmd.arg("sudo"); } - cmd.arg("fwd").arg("--server"); + cmd.arg(format!("FWD_LOG={log_filter}")) + .arg("fwd") + .arg("--server"); cmd.stdout(std::process::Stdio::piped()); cmd.stdin(std::process::Stdio::piped()); @@ -367,13 +370,15 @@ fn is_sigint(status: std::process::ExitStatus) -> bool { async fn client_connect_loop( remote: &str, sudo: bool, + log_filter: &str, events: mpsc::Sender, ) { loop { _ = events.send(ui::UIEvent::Disconnected).await; - let (mut child, socks_port) = - spawn_ssh(remote, sudo).await.expect("failed to spawn"); + let (mut child, socks_port) = spawn_ssh(remote, sudo, log_filter) + .await + .expect("failed to spawn"); let mut stderr = child .stderr @@ -431,7 +436,7 @@ async fn client_connect_loop( } } -pub async fn run_client(remote: &str, sudo: bool) { +pub async fn run_client(remote: &str, sudo: bool, log_filter: &str) { let (event_sender, event_receiver) = mpsc::channel(1024); _ = log::set_boxed_logger(ui::Logger::new(event_sender.clone())); log::set_max_level(LevelFilter::Info); @@ -449,7 +454,7 @@ pub async fn run_client(remote: &str, sudo: bool) { // Start the reconnect loop. tokio::select! { _ = ui.run() => (), - _ = client_connect_loop(remote, sudo, event_sender) => () + _ = client_connect_loop(remote, sudo, log_filter, event_sender) => () } } diff --git a/src/main.rs b/src/main.rs index 004739d..453c78d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -26,6 +26,10 @@ Options: run as root), but requires sudo access on the server and *might* end up forwarding ports that you do not want forwarded (e.g., port 22 for sshd, or port 53 for systemd.) + --log-filter FILTER + Set remote server's log level. Default is `warn`. Supports + all of Rust's env_logger filter syntax, e.g. + `--log-filter=fwd::trace`. "}); } @@ -34,7 +38,7 @@ enum Args { Help, Version, Server, - Client(String, bool), + Client(String, bool, String), Browse(String), Clip(String), Error, @@ -43,9 +47,11 @@ enum Args { fn parse_args(args: Vec) -> Args { let mut server = None; let mut sudo = None; + let mut log_filter = None; let mut rest = Vec::new(); - for arg in args.into_iter().skip(1) { + let mut arg_iter = args.into_iter().skip(1); + while let Some(arg) = arg_iter.next() { if arg == "--help" || arg == "-?" || arg == "-h" { return Args::Help; } else if arg == "--version" { @@ -54,6 +60,14 @@ fn parse_args(args: Vec) -> Args { server = Some(true) } else if arg == "--sudo" || arg == "-s" { sudo = Some(true) + } else if arg.starts_with("--log-filter") { + if arg.contains('=') { + log_filter = Some(arg.split('=').nth(1).unwrap().to_owned()); + } else if let Some(arg) = arg_iter.next() { + log_filter = Some(arg); + } else { + return Args::Error; + } } else { rest.push(arg) } @@ -71,20 +85,24 @@ fn parse_args(args: Vec) -> Args { if rest.len() == 2 { Args::Browse(rest[1].to_string()) } else if rest.len() == 1 { - Args::Client(rest[0].to_string(), sudo.unwrap_or(false)) + Args::Client(rest[0].to_string(), sudo.unwrap_or(false), log_filter.unwrap_or("warn".to_owned())) } else { Args::Error } } else if rest[0] == "clip" { if rest.len() == 1 { - Args::Client(rest[0].to_string(), sudo.unwrap_or(false)) + Args::Client(rest[0].to_string(), sudo.unwrap_or(false), log_filter.unwrap_or("warn".to_owned())) } else if rest.len() == 2 { Args::Clip(rest[1].to_string()) } else { Args::Error } } else if rest.len() == 1 { - Args::Client(rest[0].to_string(), sudo.unwrap_or(false)) + Args::Client( + rest[0].to_string(), + sudo.unwrap_or(false), + log_filter.unwrap_or("warn".to_owned()), + ) } else { Args::Error } @@ -124,8 +142,8 @@ async fn main() { Args::Clip(file) => { clip_file(file).await; } - Args::Client(server, sudo) => { - fwd::run_client(&server, sudo).await; + Args::Client(server, sudo, log_filter) => { + fwd::run_client(&server, sudo, &log_filter).await; } Args::Error => { usage(); @@ -175,14 +193,29 @@ mod tests { #[test] fn client() { - assert_arg_parse!(&["foo.com"], Args::Client(_, false)); - assert_arg_parse!(&["a"], Args::Client(_, false)); - assert_arg_parse!(&["browse"], Args::Client(_, false)); - assert_arg_parse!(&["clip"], Args::Client(_, false)); - assert_arg_parse!(&["foo.com", "--sudo"], Args::Client(_, true)); - assert_arg_parse!(&["a", "-s"], Args::Client(_, true)); - assert_arg_parse!(&["-s", "browse"], Args::Client(_, true)); - assert_arg_parse!(&["-s", "clip"], Args::Client(_, true)); + assert_arg_parse!(&["foo.com"], Args::Client( _, false, _)); + assert_arg_parse!(&["a"], Args::Client(_, false, _)); + assert_arg_parse!(&["browse"], Args::Client(_, false, _)); + assert_arg_parse!(&["clip"], Args::Client(_, false, _)); + assert_arg_parse!(&["foo.com", "--sudo"], Args::Client(_, true, _)); + assert_arg_parse!(&["a", "-s"], Args::Client(_, true, _)); + assert_arg_parse!(&["-s", "browse"], Args::Client(_, true, _)); + assert_arg_parse!(&["-s", "clip"], Args::Client(_, true, _)); + + assert_client_parse(&["a"], "a", false, "warn"); + assert_client_parse(&["a", "--log-filter", "info"], "a", false, "info"); + assert_client_parse(&["a", "--log-filter=info"], "a", false, "info"); + assert_client_parse(&["a", "--sudo", "--log-filter=info"], "a", true, "info"); + } + + fn assert_client_parse(x: &[&str], server: &str, sudo: bool, log_filter: &str) { + let args = parse_args(args(x)); + assert_matches!(args, Args::Client(_, _, _)); + if let Args::Client(s, sdo, lf) = args { + assert_eq!(s, server); + assert_eq!(sdo, sudo); + assert_eq!(lf, log_filter); + } } #[test] diff --git a/src/server/mod.rs b/src/server/mod.rs index de61f52..1188c98 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -82,6 +82,10 @@ async fn server_main< } pub async fn run_server() { + env_logger::Builder::from_env( + env_logger::Env::new().filter_or("FWD_LOG", "warn"), + ) + .init(); let stdin = tokio::io::stdin(); let stdout = tokio::io::stdout(); if let Err(e) = server_main(stdin, stdout).await { diff --git a/src/server/refresh.rs b/src/server/refresh.rs index d269be0..6ea5c93 100644 --- a/src/server/refresh.rs +++ b/src/server/refresh.rs @@ -1,5 +1,7 @@ use anyhow::Result; -use log::{error, warn}; +#[cfg_attr(not(target_os = "linux"), allow(unused))] +use log::error; +use log::warn; use std::collections::HashMap; use crate::message::PortDesc; @@ -8,9 +10,10 @@ use crate::message::PortDesc; mod procfs; pub async fn get_entries() -> Result> { - #[allow(unused)] + #[cfg_attr(not(target_os = "linux"), allow(unused_mut))] let mut attempts = 0; + #[cfg_attr(not(target_os = "linux"), allow(unused_mut))] let mut result: HashMap = HashMap::new(); #[cfg(target_os = "linux")]