From d1fd591d61952d8bcfbd1b199d67c0ba99bf6484 Mon Sep 17 00:00:00 2001 From: Jukka Taimisto Date: Tue, 5 Mar 2024 12:07:16 +0200 Subject: [PATCH 1/5] Switch to tracing create for logging --- Cargo.lock | 198 ++++++++++++++++++++++++++++++++++++++++--------- Cargo.toml | 4 +- src/main.rs | 34 +++++---- src/scanner.rs | 68 +++++++++-------- 4 files changed, 222 insertions(+), 82 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 66c2e9c..921c601 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -170,29 +170,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" -[[package]] -name = "env_filter" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" -dependencies = [ - "log", - "regex", -] - -[[package]] -name = "env_logger" -version = "0.11.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcaee3d8e3cfc3fd92428d477bc97fc29ec8716d180c0d74c643bb26166660e0" -dependencies = [ - "anstream", - "anstyle", - "env_filter", - "humantime", - "log", -] - [[package]] name = "futures" version = "0.3.30" @@ -306,18 +283,18 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" -[[package]] -name = "humantime" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" - [[package]] name = "itoa" version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + [[package]] name = "libc" version = "0.2.169" @@ -340,6 +317,15 @@ version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + [[package]] name = "memchr" version = "2.7.1" @@ -366,6 +352,16 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + [[package]] name = "num_cpus" version = "1.16.0" @@ -385,6 +381,18 @@ dependencies = [ "memchr", ] +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + [[package]] name = "parking_lot" version = "0.12.1" @@ -442,15 +450,15 @@ dependencies = [ "base64", "cidr", "clap", - "env_logger", "futures", - "log", "rand", "serde", "serde_json", "signal-hook", "signal-hook-tokio", "tokio", + "tracing", + "tracing-subscriber", ] [[package]] @@ -510,8 +518,17 @@ checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" dependencies = [ "aho-corasick", "memchr", - "regex-automata", - "regex-syntax", + "regex-automata 0.4.6", + "regex-syntax 0.8.2", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", ] [[package]] @@ -522,9 +539,15 @@ checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" dependencies = [ "aho-corasick", "memchr", - "regex-syntax", + "regex-syntax 0.8.2", ] +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + [[package]] name = "regex-syntax" version = "0.8.2" @@ -580,6 +603,15 @@ dependencies = [ "serde", ] +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + [[package]] name = "signal-hook" version = "0.3.17" @@ -653,6 +685,15 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "thread_local" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +dependencies = [ + "cfg-if", +] + [[package]] name = "tokio" version = "1.36.0" @@ -683,6 +724,67 @@ dependencies = [ "syn", ] +[[package]] +name = "tracing" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + [[package]] name = "unicode-ident" version = "1.0.12" @@ -695,6 +797,12 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -710,6 +818,28 @@ dependencies = [ "wit-bindgen-rt", ] +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + [[package]] name = "windows-sys" version = "0.48.0" diff --git a/Cargo.toml b/Cargo.toml index d9762c7..7711046 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,8 +10,6 @@ edition = "2021" [dependencies] clap={version = "4.4"} -log="0.4" -env_logger="0.11" cidr= {version = "0.3", features=["std"]} tokio={version="1", features=["full"]} serde_json = {version = "1.0"} @@ -21,4 +19,6 @@ signal-hook = {version="0.3"} futures = {version="0.3"} base64 = "0.22" rand = "0.9" +tracing = "0.1" +tracing-subscriber = { version = "0.3", features = ["env-filter"] } diff --git a/src/main.rs b/src/main.rs index 7a05707..7d8673f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,3 @@ -#[macro_use] -extern crate log; - use signal_hook::consts::{SIGINT, SIGTERM}; use signal_hook_tokio::Signals; use std::net::IpAddr; @@ -57,7 +54,7 @@ async fn collect_results( } } } - trace!("Collector stopping"); + tracing::trace!("Collector stopping"); return host_infos.drain().map(|(_, v)| v).collect(); } @@ -85,7 +82,7 @@ async fn output_results( fn exit_error(message: Option) -> ! { let mut code = 0; if let Some(msg) = message { - error!("{}", msg); + tracing::error!("{msg}"); code = 127; } @@ -99,17 +96,26 @@ async fn sighandler(signals: Signals, flag: Arc) { while let Some(sig) = s.next().await { match sig { SIGINT | SIGTERM => { - debug!("Received termination signal, setting flag"); + tracing::debug!("Received termination signal, setting flag"); flag.store(true, std::sync::atomic::Ordering::SeqCst); } - _ => warn!("Received unexpected signal"), + _ => tracing::warn!("Received unexpected signal"), } } } #[tokio::main] async fn main() { - env_logger::init(); + #[cfg(debug_assertions)] + tracing_subscriber::fmt() + .pretty() + .with_env_filter(tracing_subscriber::EnvFilter::from_default_env()) + .init(); + #[cfg(not(debug_assertions))] + tracing_subscriber::fmt() + .with_ansi(false) + .with_writer(std::io::stderr) + .init(); let app = config::build_commandline_args(); @@ -157,7 +163,7 @@ async fn main() { let params: scanner::ScanParameters = cfg.as_params(); if params.retry_on_error { - info!("Retry on error set") + tracing::info!("Retry on error set") } let (tx, rx) = tokio::sync::mpsc::unbounded_channel(); @@ -182,14 +188,14 @@ async fn main() { // fatal error, results can not be trusted. exit_error(Some(e.to_string())); } else { - error!("Error while scanning: {}", e); + tracing::error!("Error while scanning: {}", e); } } match col_result { Ok(infos) => { // print results now that scan is complete if let Err(er) = output_results(&infos, number_of_ports, cfg.json()).await { - error!("Unable to output results: {}", er); + tracing::error!("Unable to output results: {}", er); } } Err(error) => { @@ -197,12 +203,12 @@ async fn main() { } }; handle.close(); - debug!( + tracing::debug!( "Waiting for sighandler task, stop is {}", stop.load(std::sync::atomic::Ordering::SeqCst) ); - if let Err(e) = sig_h.await { - warn!("signal handler error: {}", e); + if let Err(err) = sig_h.await { + tracing::warn!(?err, "error in signal handler "); } if stop.load(std::sync::atomic::Ordering::SeqCst) { std::process::exit(2); diff --git a/src/scanner.rs b/src/scanner.rs index c99a97c..a5bdb6c 100644 --- a/src/scanner.rs +++ b/src/scanner.rs @@ -101,7 +101,7 @@ fn handle_other_error( os_errcodes::OS_ERR_NET_UNREACH => Ok(PortState::NetError()), os_errcodes::OS_ERR_TOO_MANY_FILES => Err(ScanError::TooManyFiles()), _ => { - debug!("Connect returned error code: {} (kind {:?})", n, e.kind()); + tracing::debug!("Connect returned error code: {} (kind {:?})", n, e.kind()); Ok(PortState::Closed(connection_time)) } }) @@ -115,6 +115,7 @@ fn handle_other_error( /// The handler should terminate the connection if it should not be left /// open. Callback context is used because Rust does not support async closures /// yet. Data returned by callback is included in PortState::Open returned. +#[tracing::instrument(skip(handler, context))] async fn try_port( sa: SocketAddr, conn_timeout: Duration, @@ -125,7 +126,7 @@ where F: FnOnce(TcpStream, C) -> Fut, Fut: Future>>, { - trace!("Trying {:}", sa); + tracing::trace!("connecting"); let start = Instant::now(); let res = tokio::time::timeout(conn_timeout, TcpStream::connect(sa)).await; let c_time = start.elapsed(); @@ -133,22 +134,20 @@ where let c = match res { Ok(v) => v, Err(_) => { - trace!("Connection timed out"); + tracing::trace!("Connection timed out"); return Ok(PortState::Timeout(c_time)); } }; - - trace!("connect() took {}ms", c_time.as_millis()); + tracing::trace!("connect() took {}ms", c_time.as_millis()); match c { Ok(s) => { - info!("Connection to {} succesfull", sa); + tracing::trace!("connection successful"); let data = handler(s, context).await; - info!("Connection took {}ms", c_time.as_millis()); Ok(PortState::Open(c_time, data)) } Err(e) => { - trace!("Connection to {} failed: {}", sa, e); + tracing::trace!(?e, "connection failed"); match e.kind() { ErrorKind::TimedOut => Ok(PortState::Timeout(c_time)), ErrorKind::ConnectionRefused => Ok(PortState::Closed(c_time)), @@ -174,8 +173,8 @@ pub enum ScanType { /// Close given TcpStream. /// Always returns None async fn close_connection(mut s: TcpStream, _how: Shutdown) -> Option> { - if let Err(error) = s.shutdown().await { - warn!("Can not shut down connection: {}", error); + if let Err(err) = s.shutdown().await { + tracing::warn!(?err, "Can not shut down connection"); } None } @@ -189,23 +188,22 @@ struct RdParms { /// `try_port()` callback that can be used to read banner from open TCP port async fn read_banner(mut s: TcpStream, p: RdParms) -> Option> { let mut buf = vec![0; p.size]; - info!( - "Trying to read {} bytes of banner from {:?} with {}ms timeout", + tracing::info!( + "Trying to read {} bytes of banner with {}ms timeout", p.size, - s.peer_addr().unwrap(), p.timeout.as_millis() ); let ret = tokio::time::timeout(p.timeout, s.read(&mut buf)).await; - info!("Read returned {:?}", ret); + tracing::info!("Read returned {:?}", ret); let r = match ret { Ok(Ok(0)) => None, Ok(Ok(len)) => { buf.resize(len, 0); Some(buf) } - Ok(Err(e)) => { - warn!("Error while reading data from {:?}: {}", s.peer_addr(), e); + Ok(Err(err)) => { + tracing::warn!(?err, "Error while reading data from {:?} ", s.peer_addr()); None } Err(_) => None, @@ -224,6 +222,7 @@ impl ScanType { /// /// The result of scanning is sent using `tx` `Sender`. Returned time, /// if present, indicates how long it took to get response from host. + #[tracing::instrument(skip(self, tx, conn_timeout, retry_on_error, try_count))] async fn cycle( &self, sa: SocketAddr, @@ -257,15 +256,16 @@ impl ScanType { if nr_of_tries >= try_count { Ok(None) } else { - debug!( - "Retrying {} due to timeout, tried {}/{}", - sa, nr_of_tries, try_count + tracing::debug!( + "Retrying due to timeout, tried {}/{}", + nr_of_tries, + try_count ); continue; } } PortState::HostDown() => { - info!("Remote host {} is down", sa.ip()); + tracing::info!("Host down"); Err(ScanError::Down(format!("Host {} is down", sa.ip()))) } PortState::NetError() => { @@ -282,9 +282,10 @@ impl ScanType { try_count ))) } else { - info!( + tracing::info!( "waiting 500ms before next retry ({}/{} tries)", - nr_of_tries, try_count + nr_of_tries, + try_count ); tokio::time::sleep(Duration::from_millis(500)).await; continue; @@ -296,7 +297,7 @@ impl ScanType { port: sa.port(), state, })) { - warn!("Result channel closed!") + tracing::warn!("Result channel closed!") } return ret; } @@ -399,11 +400,11 @@ impl Scanner { .map(|h| SocketAddr::new(*h, *port)) { let Ok(handle) = self.sem.clone().acquire_owned().await else { - warn!("Semaphore closed"); + tracing::warn!("Semaphore closed"); break 'outer; }; if self.stop.load(Ordering::SeqCst) { - warn!("Stopping scanning due to signal"); + tracing::warn!("Stopping scanning due to signal"); drop(handle); break 'outer; } @@ -420,16 +421,19 @@ impl Scanner { drop(handle); if let Err(e) = ret { if !e.is_fatal() { - trace!("Marking host {} down", sa.ip()); + tracing::trace!("Marking host {} down", sa.ip()); if d_map.lock().await.remove(&sa.ip()) { if let Err(e) = tx.send(ScanInfo::HostScanned(sa.ip())) { - warn!("Unable to send host scanned indication: {}", e); + tracing::warn!( + "Unable to send host scanned indication: {}", + e + ); } } } else { - info!("stopping due to fatal error while scanning"); + tracing::info!("stopping due to fatal error while scanning"); if let Err(e) = tx.send(ScanInfo::HostScanned(sa.ip())) { - warn!("Unable to send host scanned indication: {}", e); + tracing::warn!("Unable to send host scanned indication: {}", e); } let mut ret = r.lock().unwrap(); *ret = Some(e); @@ -437,18 +441,18 @@ impl Scanner { } } else if is_last { if let Err(e) = tx.send(ScanInfo::HostScanned(sa.ip())) { - warn!("Unable to send host scanned indication: {}", e); + tracing::warn!("Unable to send host scanned indication: {}", e); } } }); } } } - debug!("waiting for all tasks to complete"); + tracing::debug!("waiting for all tasks to complete"); while self.sem.available_permits() < self.params.concurrent_scans { tokio::time::sleep(Duration::from_millis(100)).await; } - info!("Tasks completed"); + tracing::info!("Tasks completed"); let r = rv.lock().unwrap().take(); match r { Some(e) => Err(e), From 165b21747f0555f1af5d0ba1f2185bd3040d3c12 Mon Sep 17 00:00:00 2001 From: Jukka Taimisto Date: Wed, 6 Mar 2024 09:22:29 +0200 Subject: [PATCH 2/5] Simplify the ports structure and iterator Just use RangeInclusive instead of trying to be clever --- src/config.rs | 9 +- src/ports.rs | 231 ++++++++++++++++++++++++++----------------------- src/range.rs | 18 ++-- src/scanner.rs | 10 ++- 4 files changed, 147 insertions(+), 121 deletions(-) diff --git a/src/config.rs b/src/config.rs index 165e67d..7bebbff 100644 --- a/src/config.rs +++ b/src/config.rs @@ -813,10 +813,7 @@ mod tests { name: "ports", arg: &["--ports", "22"], check: Box::new(|c| { - let p = (0..c.ports.as_ref().unwrap().port_count() as usize) - .map(|i| c.ports.as_ref().unwrap().get(i)); - assert_eq!(p.len(), 1); - let ports = p.collect::>(); + let ports = c.ports.unwrap().into_iter().collect::>(); assert_eq!(ports.len(), 1); ports[0] == 22 }), @@ -931,9 +928,7 @@ mod tests { assert_eq!(addrs.len(), 1); assert_eq!(addrs[0], IpCidr::from_str("192.168.1.0/24").unwrap()); - let pi = (0..cfg.ports.as_ref().unwrap().port_count() as usize) - .map(|i| cfg.ports.as_ref().unwrap().get(i)); - let ports = pi.collect::>(); + let ports = cfg.ports.unwrap().into_iter().collect::>(); assert_eq!(ports.len(), 2); assert!(ports[0] == 1 && ports[1] == 2); diff --git a/src/ports.rs b/src/ports.rs index a36fb80..95995a5 100644 --- a/src/ports.rs +++ b/src/ports.rs @@ -1,85 +1,82 @@ +use std::collections::VecDeque; use std::convert::TryFrom; -use std::fmt; use std::fmt::Display; +use std::ops::RangeInclusive; -/// Continuous port range. -#[derive(Clone, PartialEq)] -enum Prange { - Range((u16, u16)), // range of continous ports from min to max, inclusive - Atom(u16), // signle port -} +/// Continuous range of one or more ports. +#[derive(Clone, PartialEq, Debug)] +struct Prange(RangeInclusive); impl Prange { - fn create(min: u16, max: u16) -> Prange { - if min == max { - Prange::Atom(min) - } else { - Prange::Range((min, max)) - } + /// Creates new port range with given max and min values (inclusive) + fn create(min: u16, max: u16) -> Self { + debug_assert!(min <= max); + Self(min..=max) + } + + /// Returns port range covering single port. + fn single(val: u16) -> Self { + Self(val..=val) } - /// Get the smallest port number + /// Returns the smallest port number fn min(&self) -> u16 { - match self { - Prange::Range((min, _max)) => *min, - Prange::Atom(val) => *val, - } + *self.0.start() } - /// Get the largest port number + /// Returns the largest port number fn max(&self) -> u16 { - match self { - Prange::Range((_min, max)) => *max, - Prange::Atom(val) => *val, - } + *self.0.end() } - /// Get the number of ports on this range + /// Returns the number of ports on this range fn count(&self) -> u16 { - match self { - Prange::Range((min, max)) => max - min + 1, - Prange::Atom(_) => 1, - } + self.max() - self.min() + 1 } - // Merge this range to other, if possible. Returns merged range or None - // if ranges could not be merged. - fn merge(&self, other: &Self) -> Option { - let (min, max, omin, omax) = (self.min(), self.max(), other.min(), other.max()); - - if max >= omin && max <= omax - || omax >= min && omax <= max - || min + 1 == omin - || omin + 1 == min - || max + 1 == omax - || omax + 1 == max - || max + 1 == omin - || omax + 1 == min - { - Some(Prange::create(min.min(omin), max.max(omax))) - } else { - None - } + /// Returns true if `val` is contained in this range + fn contains(&self, val: &u16) -> bool { + self.0.contains(val) } -} -impl fmt::Debug for Prange { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Range(arg0) => write!(f, "[{}-{}]", arg0.0, arg0.1), - Self::Atom(arg0) => write!(f, "[{}]", arg0), + /// Returns true if `other` overlaps with this range + fn is_overlapping(&self, other: &Self) -> bool { + self.contains(&other.min()) + || self.contains(&other.max()) + || other.contains(&self.min()) + || other.contains(&self.max()) + } + + /// Returns true if `other` is adjacent to this range + fn is_adjacent(&self, other: &Self) -> bool { + self.max() + .checked_add(1) + .map_or(false, |v| v == other.min()) + || other + .max() + .checked_add(1) + .map_or(false, |v| v == self.min()) + } + + /// Tries to merge this range with `other` returning the resulting range + /// if merge was possible. + fn try_merge(&self, other: &Self) -> Option { + if self.is_overlapping(other) || self.is_adjacent(other) { + Some(Prange::create( + self.min().min(other.min()), + self.max().max(other.max()), + )) + } else { + None } } } -/// A range of ports. -/// Implements Iterartor which returns `PortIterator` instances which can then -/// be used to iterare the actual ports. The `PortIterator`s returned will -/// return at maximum `step` number of ports. This allows to partition a port -/// range into stripes of ports which can then be iterated. +/// A (possibly non-continuous) range of ports. #[derive(Clone)] pub struct PortRange { - ranges: Vec, // continuous port ranges making this range + /// Continuous port ranges making this range + ranges: Vec, } /// Error returned if port range can not be parsed. @@ -109,41 +106,56 @@ impl From for Error { } impl PortRange { - /// Get number of ports in the range + /// Returns the number of ports in this range pub fn port_count(&self) -> u16 { - let mut count = 0; - for r in &self.ranges { - count += r.count(); - } - count + self.ranges.iter().map(|r| r.count()).sum() } +} - /// Get port at given index in port range. - /// Panics if given index is out-of-range - pub fn get(&self, index: usize) -> u16 { - if index >= self.port_count() as usize { - panic!("requested index out of bounds") - } - let mut curr = 0; - for r in &self.ranges { - if curr == index { - return r.min(); - } else if curr + (r.count() as usize) <= index { - curr += r.count() as usize; - continue; - } else { - return r.min() + (index - curr) as u16; - } +impl IntoIterator for PortRange { + type Item = u16; + + type IntoIter = PortIterator; + + fn into_iter(self) -> Self::IntoIter { + PortIterator { + ranges: self.ranges.into(), + iter: None, } - panic!("requested index out of bounds") } +} + +/// Iterator iterating over ports in [PortRange] +pub struct PortIterator { + /// Remaining ranges + ranges: VecDeque, + /// range we are currently iterating, if any + iter: Option>, +} - pub fn port_iter(&self) -> impl Iterator + '_ { - (0..self.port_count() as usize).map(|i| self.get(i)) +impl Iterator for PortIterator { + type Item = u16; + + fn next(&mut self) -> Option { + loop { + if let Some(range) = self.iter.as_mut() { + match range.next() { + Some(port) => return Some(port), + None => { + self.iter = None; + } + } + } + let Some(next_range) = self.ranges.pop_front() else { + // no more ports + return None; + }; + self.iter = Some(next_range.0) + } } } -/// Parse a single port range, min-max (inclusive). +/// Parses a single port range, min-max (inclusive). fn parse_single_range(val: &str) -> Result { let parts: Vec<&str> = val.split('-').collect(); if parts.len() > 2 { @@ -168,7 +180,7 @@ impl TryFrom<&str> for PortRange { let mut parsed_ranges = Vec::with_capacity(inputs.len()); for s in inputs { if !s.contains('-') { - parsed_ranges.push(Prange::Atom(s.trim().parse()?)); + parsed_ranges.push(Prange::single(s.trim().parse()?)); } else { parsed_ranges.push(parse_single_range(s.trim())?); } @@ -178,7 +190,7 @@ impl TryFrom<&str> for PortRange { parsed_ranges.sort_unstable_by_key(|k| k.min()); let mut curr = parsed_ranges.remove(0); for r in parsed_ranges.drain(0..) { - if let Some(merged) = curr.merge(&r) { + if let Some(merged) = curr.try_merge(&r) { curr = merged; } else { // could not merge current anymore, append it to final set of @@ -206,7 +218,7 @@ mod tests { fn test_simple_range(input: &str, expected: &[u16]) { let r = PortRange::try_from(input).unwrap(); assert_eq!(r.port_count() as usize, expected.len()); - check_elems((0..r.port_count() as usize).map(|i| r.get(i)), expected); + check_elems(r.into_iter(), expected); } #[test] @@ -221,10 +233,7 @@ mod tests { fn test_full_range() { let r = PortRange::try_from("1-65535").unwrap(); assert_eq!(r.port_count(), 65535); - check_elems( - (0..r.port_count() as usize).map(|i| r.get(i)), - &(1..=65535).collect::>(), - ); + check_elems(r.into_iter(), &(1..=65535).collect::>()); } #[test] @@ -235,7 +244,7 @@ mod tests { expected.append(&mut (1..11).collect::>()); expected.append(&mut (20..31).collect::>()); expected.append(&mut (41..43).collect::>()); - check_elems((0..r.port_count() as usize).map(|i| r.get(i)), &expected); + check_elems(r.into_iter(), &expected); } #[test] @@ -244,7 +253,7 @@ mod tests { let mut expected1 = vec![22, 80]; expected1.append(&mut (4000..=4025).collect()); expected1.append(&mut (8000..=8090).collect()); - check_elems((0..r.port_count() as usize).map(|i| r.get(i)), &expected1); + check_elems(r.into_iter(), &expected1); } #[test] @@ -254,55 +263,55 @@ mod tests { input: (Prange, Prange), expected: Option, } - let cases: [Case; 22] = [ + let cases: &[Case] = &[ Case { name: "same-atom", - input: (Prange::Atom(2), Prange::Atom(2)), - expected: Some(Prange::Atom(2)), + input: (Prange::single(2), Prange::single(2)), + expected: Some(Prange::single(2)), }, Case { name: "adjacent-atom", - input: (Prange::Atom(1), Prange::Atom(2)), + input: (Prange::single(1), Prange::single(2)), expected: Some(Prange::create(1, 2)), }, Case { name: "adjacent-atom2", - input: (Prange::Atom(2), Prange::Atom(1)), + input: (Prange::single(2), Prange::single(1)), expected: Some(Prange::create(1, 2)), }, Case { name: "distinct-atom", - input: (Prange::Atom(2), Prange::Atom(4)), + input: (Prange::single(2), Prange::single(4)), expected: None, }, Case { name: "adjacent-range", - input: (Prange::Atom(2), Prange::create(3, 6)), + input: (Prange::single(2), Prange::create(3, 6)), expected: Some(Prange::create(2, 6)), }, Case { name: "adjacent-range2", - input: (Prange::Atom(7), Prange::create(3, 6)), + input: (Prange::single(7), Prange::create(3, 6)), expected: Some(Prange::create(3, 7)), }, Case { name: "adjacent-range3", - input: (Prange::create(3, 6), Prange::Atom(2)), + input: (Prange::create(3, 6), Prange::single(2)), expected: Some(Prange::create(2, 6)), }, Case { name: "adjacent-range4", - input: (Prange::create(3, 6), Prange::Atom(7)), + input: (Prange::create(3, 6), Prange::single(7)), expected: Some(Prange::create(3, 7)), }, Case { name: "atom-in-range", - input: (Prange::create(3, 6), Prange::Atom(5)), + input: (Prange::create(3, 6), Prange::single(5)), expected: Some(Prange::create(3, 6)), }, Case { name: "atom-in-range2", - input: (Prange::Atom(5), Prange::create(3, 6)), + input: (Prange::single(5), Prange::create(3, 6)), expected: Some(Prange::create(3, 6)), }, Case { @@ -365,10 +374,20 @@ mod tests { input: (Prange::create(4, 8), Prange::create(4, 8)), expected: Some(Prange::create(4, 8)), }, + Case { + name: "same-max", + input: (Prange::create(65535, 65535), Prange::create(65535, 65535)), + expected: Some(Prange::create(65535, 65535)), + }, + Case { + name: "min-max", + input: (Prange::create(65535, 65535), Prange::create(0, 0)), + expected: None, + }, ]; for c in cases { - let result = c.input.0.merge(&c.input.1); + let result = c.input.0.try_merge(&c.input.1); if result != c.expected { panic!("{} : expected {:?}, got {:?}", c.name, c.expected, result) } diff --git a/src/range.rs b/src/range.rs index b064b22..0c210e7 100644 --- a/src/range.rs +++ b/src/range.rs @@ -6,7 +6,7 @@ use crate::ports::PortRange; ///ScanRnge contains information which hosts and ports on those hosts to scan pub struct ScanRange<'a> { - pub ports: PortRange, + ports: Option, addrs: &'a [IpCidr], excludes: &'a [IpAddr], } @@ -17,25 +17,31 @@ impl<'a> ScanRange<'a> { pub fn create(addrs: &'a [IpCidr], excludes: &'a [IpAddr], ports: PortRange) -> ScanRange<'a> { ScanRange { addrs, - ports, + ports: Some(ports), excludes, } } /// Get the number of ports to scan on each host pub fn get_port_count(&self) -> u16 { - self.ports.port_count() + match self.ports { + None => 0, + Some(ref p) => p.port_count(), + } + } + + pub fn ports(&mut self) -> Option { + self.ports.take() } } impl ScanRange<'_> { /// Get iterator for hosts to scan pub fn hosts(&'_ self) -> impl Iterator + '_ { - return self - .addrs + self.addrs .iter() .flat_map(|cidr| cidr.iter().addresses()) - .filter(move |a| !self.excludes.contains(a)); + .filter(move |a| !self.excludes.contains(a)) } } diff --git a/src/scanner.rs b/src/scanner.rs index a5bdb6c..b9639f8 100644 --- a/src/scanner.rs +++ b/src/scanner.rs @@ -375,12 +375,18 @@ impl Scanner { /// Do a scan for given range. Results will be sent using `tx` `Sender`. pub async fn scan( self, - range: ScanRange<'_>, + mut range: ScanRange<'_>, tx: UnboundedSender, ) -> Result<(), ScanError> { let atx = Arc::new(tx); + let mut ports = match range.ports() { + Some(p) => p.into_iter().collect::>(), + None => { + tracing::warn!("no ports to scan!"); + return Ok(()); + } + }; let host_chunks = ChunkIter::new(range.hosts(), self.params.concurrent_hosts); - let mut ports = range.ports.port_iter().collect::>(); let mut rng = rand::rng(); ports.shuffle(&mut rng); From 245d18d4f4023a64752261f5b589b0e16840004d Mon Sep 17 00:00:00 2001 From: Jukka Taimisto Date: Wed, 9 Jul 2025 13:01:10 +0300 Subject: [PATCH 3/5] Update dependencies and update to edition 2024 Updating crates.io index Locking 83 packages to latest Rust 1.88.0 compatible versions Updating addr2line v0.21.0 -> v0.24.2 Removing adler v1.0.2 Adding adler2 v2.0.1 Updating aho-corasick v1.1.2 -> v1.1.3 Updating anstream v0.6.13 -> v0.6.19 Updating anstyle v1.0.6 -> v1.0.11 Updating anstyle-parse v0.2.3 -> v0.2.7 Updating anstyle-query v1.0.2 -> v1.1.3 Updating anstyle-wincon v3.0.2 -> v3.0.9 Updating autocfg v1.1.0 -> v1.5.0 Updating backtrace v0.3.69 -> v0.3.75 Removing bitflags v1.3.2 Removing bitflags v2.8.0 Adding bitflags v2.9.1 Updating bytes v1.5.0 -> v1.10.1 Removing cc v1.0.89 Updating cfg-if v1.0.0 -> v1.0.1 Updating clap v4.5.1 -> v4.5.40 Updating clap_builder v4.5.1 -> v4.5.40 Updating clap_lex v0.7.0 -> v0.7.5 Updating colorchoice v1.0.0 -> v1.0.4 Updating futures v0.3.30 -> v0.3.31 Updating futures-channel v0.3.30 -> v0.3.31 Updating futures-core v0.3.30 -> v0.3.31 Updating futures-executor v0.3.30 -> v0.3.31 Updating futures-io v0.3.30 -> v0.3.31 Updating futures-macro v0.3.30 -> v0.3.31 Updating futures-sink v0.3.30 -> v0.3.31 Updating futures-task v0.3.30 -> v0.3.31 Updating futures-util v0.3.30 -> v0.3.31 Updating getrandom v0.3.1 -> v0.3.3 Updating gimli v0.28.1 -> v0.31.1 Removing hermit-abi v0.3.9 Adding io-uring v0.7.8 Adding is_terminal_polyfill v1.70.1 Updating itoa v1.0.10 -> v1.0.15 Updating libc v0.2.169 -> v0.2.174 Updating lock_api v0.4.11 -> v0.4.13 Updating log v0.4.21 -> v0.4.27 Updating memchr v2.7.1 -> v2.7.5 Updating miniz_oxide v0.7.2 -> v0.8.9 Updating mio v0.8.11 -> v1.0.4 Removing num_cpus v1.16.0 Updating object v0.32.2 -> v0.36.7 Adding once_cell_polyfill v1.70.1 Updating parking_lot v0.12.1 -> v0.12.4 Updating parking_lot_core v0.9.9 -> v0.9.11 Updating pin-project-lite v0.2.13 -> v0.2.16 Updating ppv-lite86 v0.2.17 -> v0.2.21 Updating proc-macro2 v1.0.78 -> v1.0.95 Updating quote v1.0.35 -> v1.0.40 Adding r-efi v5.3.0 Updating rand v0.9.0 -> v0.9.1 Updating rand_core v0.9.0 -> v0.9.3 Updating redox_syscall v0.4.1 -> v0.5.13 Updating regex v1.10.3 -> v1.11.1 Updating regex-automata v0.4.6 -> v0.4.9 Updating regex-syntax v0.8.2 -> v0.8.5 Updating rustc-demangle v0.1.23 -> v0.1.25 Updating ryu v1.0.17 -> v1.0.20 Updating serde v1.0.197 -> v1.0.219 Updating serde_derive v1.0.197 -> v1.0.219 Updating serde_json v1.0.114 -> v1.0.140 Updating signal-hook v0.3.17 -> v0.3.18 Updating signal-hook-registry v1.4.1 -> v1.4.5 Updating slab v0.4.9 -> v0.4.10 Updating smallvec v1.13.1 -> v1.15.1 Updating socket2 v0.5.6 -> v0.5.10 Updating strsim v0.11.0 -> v0.11.1 Updating syn v2.0.52 -> v2.0.104 Updating tokio v1.36.0 -> v1.46.1 Updating tokio-macros v2.2.0 -> v2.5.0 Updating unicode-ident v1.0.12 -> v1.0.18 Updating utf8parse v0.2.1 -> v0.2.2 Removing wasi v0.11.0+wasi-snapshot-preview1 Removing wasi v0.13.3+wasi-0.2.2 Adding wasi v0.11.1+wasi-snapshot-preview1 Adding wasi v0.14.2+wasi-0.2.4 Updating windows-sys v0.48.0 -> v0.59.0 Removing windows-targets v0.48.5 Removing windows-targets v0.52.4 Adding windows-targets v0.52.6 Removing windows_aarch64_gnullvm v0.48.5 Removing windows_aarch64_gnullvm v0.52.4 Adding windows_aarch64_gnullvm v0.52.6 Removing windows_aarch64_msvc v0.48.5 Removing windows_aarch64_msvc v0.52.4 Adding windows_aarch64_msvc v0.52.6 Removing windows_i686_gnu v0.48.5 Removing windows_i686_gnu v0.52.4 Adding windows_i686_gnu v0.52.6 Adding windows_i686_gnullvm v0.52.6 Removing windows_i686_msvc v0.48.5 Removing windows_i686_msvc v0.52.4 Adding windows_i686_msvc v0.52.6 Removing windows_x86_64_gnu v0.48.5 Removing windows_x86_64_gnu v0.52.4 Adding windows_x86_64_gnu v0.52.6 Removing windows_x86_64_gnullvm v0.48.5 Removing windows_x86_64_gnullvm v0.52.4 Adding windows_x86_64_gnullvm v0.52.6 Removing windows_x86_64_msvc v0.48.5 Removing windows_x86_64_msvc v0.52.4 Adding windows_x86_64_msvc v0.52.6 Updating wit-bindgen-rt v0.33.0 -> v0.39.0 Updating zerocopy v0.8.14 -> v0.8.26 Updating zerocopy-derive v0.8.14 -> v0.8.26 --- Cargo.lock | 487 ++++++++++++++++++++++++----------------------------- Cargo.toml | 2 +- 2 files changed, 221 insertions(+), 268 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 921c601..67f65f7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,95 +4,97 @@ version = 4 [[package]] name = "addr2line" -version = "0.21.0" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ "gimli", ] [[package]] -name = "adler" -version = "1.0.2" +name = "adler2" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "aho-corasick" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] [[package]] name = "anstream" -version = "0.6.13" +version = "0.6.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" +checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", + "is_terminal_polyfill", "utf8parse", ] [[package]] name = "anstyle" -version = "1.0.6" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" +checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" [[package]] name = "anstyle-parse" -version = "0.2.3" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.0.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.2" +version = "3.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882" dependencies = [ "anstyle", - "windows-sys 0.52.0", + "once_cell_polyfill", + "windows-sys 0.59.0", ] [[package]] name = "autocfg" -version = "1.1.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "backtrace" -version = "0.3.69" +version = "0.3.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", "miniz_oxide", "object", "rustc-demangle", + "windows-targets", ] [[package]] @@ -103,33 +105,21 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.8.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" [[package]] name = "bytes" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" - -[[package]] -name = "cc" -version = "1.0.89" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0ba8f7aaa012f30d5b2861462f6708eccd49c3c39863fe083a308035f63d723" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" [[package]] name = "cidr" @@ -139,18 +129,18 @@ checksum = "bd1b64030216239a2e7c364b13cd96a2097ebf0dfe5025f2dedee14a23f2ab60" [[package]] name = "clap" -version = "4.5.1" +version = "4.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c918d541ef2913577a0f9566e9ce27cb35b6df072075769e0b26cb5a554520da" +checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.5.1" +version = "4.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f3e7391dad68afb0c2ede1bf619f579a3dc9c2ec67f089baa397123a2f3d1eb" +checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e" dependencies = [ "anstream", "anstyle", @@ -160,21 +150,21 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.0" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" +checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" [[package]] name = "colorchoice" -version = "1.0.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" [[package]] name = "futures" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", @@ -187,9 +177,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", @@ -197,15 +187,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", @@ -214,15 +204,15 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-macro" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", @@ -231,21 +221,21 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-channel", "futures-core", @@ -261,33 +251,44 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.3.1" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" dependencies = [ "cfg-if", "libc", - "wasi 0.13.3+wasi-0.2.2", - "windows-targets 0.52.4", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", ] [[package]] name = "gimli" -version = "0.28.1" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] -name = "hermit-abi" -version = "0.3.9" +name = "io-uring" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b86e202f00093dcba4275d4636b93ef9dd75d025ae560d2521b45ea28ab49013" +dependencies = [ + "bitflags", + "cfg-if", + "libc", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "itoa" -version = "1.0.10" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "lazy_static" @@ -297,15 +298,15 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.169" +version = "0.2.174" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" +checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" [[package]] name = "lock_api" -version = "0.4.11" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" dependencies = [ "autocfg", "scopeguard", @@ -313,9 +314,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.21" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] name = "matchers" @@ -328,28 +329,28 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.1" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" [[package]] name = "miniz_oxide" -version = "0.7.2" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ - "adler", + "adler2", ] [[package]] name = "mio" -version = "0.8.11" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" dependencies = [ "libc", - "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.48.0", + "wasi 0.11.1+wasi-snapshot-preview1", + "windows-sys 0.59.0", ] [[package]] @@ -362,21 +363,11 @@ dependencies = [ "winapi", ] -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi", - "libc", -] - [[package]] name = "object" -version = "0.32.2" +version = "0.36.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ "memchr", ] @@ -387,6 +378,12 @@ version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +[[package]] +name = "once_cell_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" + [[package]] name = "overload" version = "0.1.1" @@ -395,9 +392,9 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] name = "parking_lot" -version = "0.12.1" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" dependencies = [ "lock_api", "parking_lot_core", @@ -405,22 +402,22 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.9" +version = "0.9.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-targets 0.48.5", + "windows-targets", ] [[package]] name = "pin-project-lite" -version = "0.2.13" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "pin-utils" @@ -430,15 +427,18 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] [[package]] name = "proc-macro2" -version = "1.0.78" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ "unicode-ident", ] @@ -463,22 +463,27 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.35" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + [[package]] name = "rand" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" +checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" dependencies = [ "rand_chacha", "rand_core", - "zerocopy", ] [[package]] @@ -493,33 +498,32 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.9.0" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b08f3c9802962f7e1b25113931d94f43ed9725bebc59db9d0c3e9a23b67e15ff" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ "getrandom", - "zerocopy", ] [[package]] name = "redox_syscall" -version = "0.4.1" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6" dependencies = [ - "bitflags 1.3.2", + "bitflags", ] [[package]] name = "regex" -version = "1.10.3" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.6", - "regex-syntax 0.8.2", + "regex-automata 0.4.9", + "regex-syntax 0.8.5", ] [[package]] @@ -533,13 +537,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.6" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.2", + "regex-syntax 0.8.5", ] [[package]] @@ -550,21 +554,21 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.2" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "rustc-demangle" -version = "0.1.23" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" [[package]] name = "ryu" -version = "1.0.17" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "scopeguard" @@ -574,18 +578,18 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" -version = "1.0.197" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.197" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", @@ -594,11 +598,12 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.114" +version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" dependencies = [ "itoa", + "memchr", "ryu", "serde", ] @@ -614,9 +619,9 @@ dependencies = [ [[package]] name = "signal-hook" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" +checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2" dependencies = [ "libc", "signal-hook-registry", @@ -624,9 +629,9 @@ dependencies = [ [[package]] name = "signal-hook-registry" -version = "1.4.1" +version = "1.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" dependencies = [ "libc", ] @@ -645,24 +650,21 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] +checksum = "04dc19736151f35336d325007ac991178d504a119863a2fcb3758cdb5e52c50d" [[package]] name = "smallvec" -version = "1.13.1" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "socket2" -version = "0.5.6" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" dependencies = [ "libc", "windows-sys 0.52.0", @@ -670,15 +672,15 @@ dependencies = [ [[package]] name = "strsim" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.52" +version = "2.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" +checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" dependencies = [ "proc-macro2", "quote", @@ -696,28 +698,29 @@ dependencies = [ [[package]] name = "tokio" -version = "1.36.0" +version = "1.46.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931" +checksum = "0cc3a2344dafbe23a245241fe8b09735b521110d30fcefbbd5feb1797ca35d17" dependencies = [ "backtrace", "bytes", + "io-uring", "libc", "mio", - "num_cpus", "parking_lot", "pin-project-lite", "signal-hook-registry", + "slab", "socket2", "tokio-macros", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "tokio-macros" -version = "2.2.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", @@ -787,15 +790,15 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] name = "utf8parse" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "valuable" @@ -805,15 +808,15 @@ checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" [[package]] name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasi" -version = "0.13.3+wasi-0.2.2" +version = "0.14.2+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" dependencies = [ "wit-bindgen-rt", ] @@ -840,161 +843,111 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - [[package]] name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.4", + "windows-targets", ] [[package]] -name = "windows-targets" -version = "0.48.5" +name = "windows-sys" +version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", + "windows-targets", ] [[package]] name = "windows-targets" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.4", - "windows_aarch64_msvc 0.52.4", - "windows_i686_gnu 0.52.4", - "windows_i686_msvc 0.52.4", - "windows_x86_64_gnu 0.52.4", - "windows_x86_64_gnullvm 0.52.4", - "windows_x86_64_msvc 0.52.4", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" -version = "0.52.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] -name = "windows_i686_msvc" -version = "0.48.5" +name = "windows_i686_gnullvm" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" -version = "0.52.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" -version = "0.52.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "wit-bindgen-rt" -version = "0.33.0" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" dependencies = [ - "bitflags 2.8.0", + "bitflags", ] [[package]] name = "zerocopy" -version = "0.8.14" +version = "0.8.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a367f292d93d4eab890745e75a778da40909cab4d6ff8173693812f79c4a2468" +checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.14" +version = "0.8.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3931cb58c62c13adec22e38686b559c86a30565e16ad6e8510a337cedc611e1" +checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 7711046..771e6ed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ version = "0.3.1" authors = ["SensorFleet R&D "] homepage = "https://github.com/sensorfleet/pscan" repository = "https://github.com/sensorfleet/pscan" -edition = "2021" +edition = "2024" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html From 44c699c7a043c467da037d1498563f05885109d2 Mon Sep 17 00:00:00 2001 From: Jukka Taimisto Date: Wed, 9 Jul 2025 13:24:20 +0300 Subject: [PATCH 4/5] Fix clippy nags --- src/config.rs | 17 ++++++----------- src/main.rs | 26 +++++++++++++------------- src/output.rs | 25 +++++++++---------------- src/ports.rs | 11 +++-------- src/range.rs | 6 +----- src/scanner.rs | 28 ++++++++++++++-------------- 6 files changed, 46 insertions(+), 67 deletions(-) diff --git a/src/config.rs b/src/config.rs index 7bebbff..fe1bce9 100644 --- a/src/config.rs +++ b/src/config.rs @@ -636,8 +636,7 @@ impl Config { if let Some(c) = self.concurrent_scans { if c == 0 { return Err(Error::Message(format!( - "invalid value for {}: Value needs to be non-zero", - ARG_CONCURRENT_SCANS + "invalid value for {ARG_CONCURRENT_SCANS}: Value needs to be non-zero" ))); } } else { @@ -646,16 +645,14 @@ impl Config { if let Some(h) = self.concurrent_hosts { if h == 0 { return Err(Error::Message(format!( - "invalid value for {}: Value needs to be non-zero", - ARG_CONCURRENT_HOSTS + "invalid value for {ARG_CONCURRENT_HOSTS}: Value needs to be non-zero" ))); } } if let Some(c) = self.try_count { if c == 0 { return Err(Error::Message(format!( - "invalid value for {}: value needs to be non-zero", - ARG_TRY_COUNT + "invalid value for {ARG_TRY_COUNT}: value needs to be non-zero" ))); } } else { @@ -678,8 +675,7 @@ impl Config { let fields = missing_fields.join(", "); return Err(Error::Message(format!( - "missing configuration values for: {}", - fields + "missing configuration values for: {fields}" ))); } Ok(()) @@ -690,12 +686,11 @@ impl Config { let p = Path::new(file_name); if !p.exists() { return Err(Error::Message(format!( - "configuration file {} not found", - file_name + "configuration file {file_name} not found" ))); } let data = fs::read_to_string(p) - .map_err(|e| Error::Message(format!("unable to read configuration file: {}", e)))?; + .map_err(|e| Error::Message(format!("unable to read configuration file: {e}")))?; serde_json::from_str(&data).map_err(|e| Error::Message(e.to_string())) } } diff --git a/src/main.rs b/src/main.rs index 7d8673f..699c874 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,7 @@ use signal_hook::consts::{SIGINT, SIGTERM}; use signal_hook_tokio::Signals; use std::net::IpAddr; -use std::sync::{atomic::AtomicBool, Arc}; +use std::sync::{Arc, atomic::AtomicBool}; use tokio::sync::mpsc::UnboundedReceiver; use futures::StreamExt; @@ -40,9 +40,9 @@ async fn collect_results( info.add_closed_port(status.port); info.add_delay(d); } - scanner::PortState::Timeout(_) => info.add_filtered_port(status.port), - scanner::PortState::HostDown() => info.mark_down(), - scanner::PortState::NetError() => info.mark_down(), + scanner::PortState::Timeout => info.add_filtered_port(status.port), + scanner::PortState::HostDown => info.mark_down(), + scanner::PortState::NetError => info.mark_down(), } } scanner::ScanInfo::HostScanned(addr) => { @@ -55,7 +55,7 @@ async fn collect_results( } } tracing::trace!("Collector stopping"); - return host_infos.drain().map(|(_, v)| v).collect(); + host_infos.into_values().collect() } /// Print the results, if `output_file` is `None`, then information is printed @@ -123,7 +123,7 @@ async fn main() { Ok(m) => m, Err(e) => match e.kind() { clap::error::ErrorKind::DisplayHelp | clap::error::ErrorKind::DisplayVersion => { - println!("{}", e); + println!("{e}"); exit_error(None); } _ => exit_error(Some(e.to_string())), @@ -136,7 +136,7 @@ async fn main() { matches.get_one::(config::ARG_CONFIG_FILE).unwrap(), ) { Ok(c) => Some(c), - Err(e) => exit_error(Some(format!("Configuration error: {}", e))), + Err(e) => exit_error(Some(format!("Configuration error: {e}"))), } } else { None @@ -144,19 +144,19 @@ async fn main() { let cfg = if let Some(cf) = cfg_from_file { match cf.override_with(&matches) { - Err(e) => exit_error(Some(format!("Configuration error: {}", e))), + Err(e) => exit_error(Some(format!("Configuration error: {e}"))), Ok(c) => c, } } else { match config::Config::try_from(matches) { - Err(e) => exit_error(Some(format!("Configuration error: {}", e))), + Err(e) => exit_error(Some(format!("Configuration error: {e}"))), Ok(c) => c, } }; // make sure configuration is good if let Err(e) = cfg.verify() { - exit_error(Some(format!("Configuration error: {}", e))) + exit_error(Some(format!("Configuration error: {e}"))) } let verbose = cfg.verbose(); @@ -170,7 +170,7 @@ async fn main() { let signals = match Signals::new([SIGINT, SIGTERM]) { Ok(h) => h, - Err(e) => exit_error(Some(format!("Unable to register signal handler: {}", e))), + Err(e) => exit_error(Some(format!("Unable to register signal handler: {e}"))), }; let stop = Arc::new(AtomicBool::new(false)); let handle = signals.handle(); @@ -188,14 +188,14 @@ async fn main() { // fatal error, results can not be trusted. exit_error(Some(e.to_string())); } else { - tracing::error!("Error while scanning: {}", e); + tracing::error!("Error while scanning: {e}"); } } match col_result { Ok(infos) => { // print results now that scan is complete if let Err(er) = output_results(&infos, number_of_ports, cfg.json()).await { - tracing::error!("Unable to output results: {}", er); + tracing::error!("Unable to output results: {er}"); } } Err(error) => { diff --git a/src/output.rs b/src/output.rs index b0271f3..cc7b071 100644 --- a/src/output.rs +++ b/src/output.rs @@ -1,5 +1,5 @@ -use serde::ser::SerializeMap; use serde::Serialize; +use serde::ser::SerializeMap; use std::collections::HashMap; use std::fmt::Write as _; use std::fmt::{self, Display}; @@ -45,11 +45,11 @@ impl Display for Banners { builder.push_str("\n\t Banners received from open ports:\n"); for (port, b) in &self.values { let _ = match std::str::from_utf8(b) { - Ok(s) => write!(builder, "\t\tPort: {} \"{}\"", port, s), + Ok(s) => write!(builder, "\t\tPort: {port} \"{s}\""), Err(_e) => write!(builder, "\t\tPort: {}: {} bytes of data", port, b.len()), }; } - write!(f, "{}", builder) + write!(f, "{builder}") } } @@ -155,13 +155,7 @@ impl HostInfo { impl fmt::Display for HostInfo { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut pstr = String::new(); - let status = { - if self.down { - "Down" - } else { - "Up" - } - }; + let status = { if self.down { "Down" } else { "Up" } }; let _ = write!( pstr, "{} is {} \n\t{} Open Ports:", @@ -170,7 +164,7 @@ impl fmt::Display for HostInfo { self.open_ports.len() ); for port in &self.open_ports { - let _ = write!(pstr, " {}", port); + let _ = write!(pstr, " {port}"); } let _ = write!( pstr, @@ -188,7 +182,7 @@ impl fmt::Display for HostInfo { if !self.banners.is_empty() { pstr.push_str(&self.banners.to_string()); } - write!(f, "{}", pstr) + write!(f, "{pstr}") } } /// `ScanComplete` information to print as JSON. Contains the results of @@ -249,11 +243,10 @@ pub fn write_results_to_stdout( number_of_silent_hosts += 1; continue; } - println!("{}\n", info); + println!("{info}\n"); } println!( - "{} ports on {} hosts scanned, {} hosts did not have open ports, {} hosts reported down by OS", - number_of_ports, number_of_hosts, number_of_silent_hosts, number_of_down_hosts + "{number_of_ports} ports on {number_of_hosts} hosts scanned, {number_of_silent_hosts} hosts did not have open ports, {number_of_down_hosts} hosts reported down by OS" ); Ok(()) } @@ -266,6 +259,6 @@ pub fn write_single_host_info(info: &HostInfo) { } else if info.open_port_count() == 0 { println!("{}: no open ports", info.address) } else { - println!("{}", info) + println!("{info}") } } diff --git a/src/ports.rs b/src/ports.rs index 95995a5..128a666 100644 --- a/src/ports.rs +++ b/src/ports.rs @@ -49,13 +49,8 @@ impl Prange { /// Returns true if `other` is adjacent to this range fn is_adjacent(&self, other: &Self) -> bool { - self.max() - .checked_add(1) - .map_or(false, |v| v == other.min()) - || other - .max() - .checked_add(1) - .map_or(false, |v| v == self.min()) + self.max().checked_add(1).is_some_and(|v| v == other.min()) + || other.max().checked_add(1).is_some_and(|v| v == self.min()) } /// Tries to merge this range with `other` returning the resulting range @@ -100,7 +95,7 @@ impl From<&str> for Error { impl From for Error { fn from(err: std::num::ParseIntError) -> Self { Error { - msg: format!("Invalid number in port range: {}", err), + msg: format!("Invalid number in port range: {err}"), } } } diff --git a/src/range.rs b/src/range.rs index 0c210e7..b2ecbcb 100644 --- a/src/range.rs +++ b/src/range.rs @@ -70,11 +70,7 @@ where None => break, }; } - if ret.is_empty() { - None - } else { - Some(ret) - } + if ret.is_empty() { None } else { Some(ret) } } } diff --git a/src/scanner.rs b/src/scanner.rs index b9639f8..2eb02ec 100644 --- a/src/scanner.rs +++ b/src/scanner.rs @@ -5,8 +5,8 @@ use std::io::ErrorKind; use std::sync::{Arc, Mutex}; use tokio::io::{AsyncReadExt, AsyncWriteExt}; use tokio::net::TcpStream; -use tokio::sync::mpsc::UnboundedSender; use tokio::sync::Semaphore; +use tokio::sync::mpsc::UnboundedSender; use std::net::{IpAddr, Shutdown, SocketAddr}; use std::sync::atomic::Ordering; @@ -42,9 +42,9 @@ static DEFAULT_CONNECTION_TIMEOUT: Duration = Duration::from_millis(2000); pub enum PortState { Open(Duration, Option>), // port is open, contains banner if we did read any Closed(Duration), // port is closed - Timeout(Duration), // Did not get response withint timeout - HostDown(), // Host was reported unreachable by OS - NetError(), // Host could not be connected due network error + Timeout, // Did not get response withint timeout + HostDown, // Host was reported unreachable by OS + NetError, // Host could not be connected due network error } /// Scanning error @@ -65,7 +65,7 @@ impl ScanError { impl fmt::Display for ScanError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - ScanError::Down(msg) => write!(f, "{}", msg), + ScanError::Down(msg) => write!(f, "{msg}"), ScanError::TooManyFiles() => write!( f, "Too many concurrent scans. Decrease number of concurrent scans, \ @@ -97,8 +97,8 @@ fn handle_other_error( ) -> Result { e.raw_os_error() .map_or(Ok(PortState::Closed(connection_time)), |n| match n { - os_errcodes::OS_ERR_HOST_DOWN => Ok(PortState::HostDown()), - os_errcodes::OS_ERR_NET_UNREACH => Ok(PortState::NetError()), + os_errcodes::OS_ERR_HOST_DOWN => Ok(PortState::HostDown), + os_errcodes::OS_ERR_NET_UNREACH => Ok(PortState::NetError), os_errcodes::OS_ERR_TOO_MANY_FILES => Err(ScanError::TooManyFiles()), _ => { tracing::debug!("Connect returned error code: {} (kind {:?})", n, e.kind()); @@ -135,7 +135,7 @@ where Ok(v) => v, Err(_) => { tracing::trace!("Connection timed out"); - return Ok(PortState::Timeout(c_time)); + return Ok(PortState::Timeout); } }; tracing::trace!("connect() took {}ms", c_time.as_millis()); @@ -149,9 +149,9 @@ where Err(e) => { tracing::trace!(?e, "connection failed"); match e.kind() { - ErrorKind::TimedOut => Ok(PortState::Timeout(c_time)), + ErrorKind::TimedOut => Ok(PortState::Timeout), ErrorKind::ConnectionRefused => Ok(PortState::Closed(c_time)), - ErrorKind::PermissionDenied => Ok(PortState::HostDown()), + ErrorKind::PermissionDenied => Ok(PortState::HostDown), _ => handle_other_error(e, c_time), } } @@ -247,12 +247,12 @@ impl ScanType { } ScanType::Test(m) => { let mut val = m.lock().unwrap(); - val.remove(&sa).unwrap_or(Ok(PortState::HostDown()))? + val.remove(&sa).unwrap_or(Ok(PortState::HostDown))? } }; let ret = match state { PortState::Open(d, _) | PortState::Closed(d) => Ok(Some(d)), - PortState::Timeout(_) => { + PortState::Timeout => { if nr_of_tries >= try_count { Ok(None) } else { @@ -264,11 +264,11 @@ impl ScanType { continue; } } - PortState::HostDown() => { + PortState::HostDown => { tracing::info!("Host down"); Err(ScanError::Down(format!("Host {} is down", sa.ip()))) } - PortState::NetError() => { + PortState::NetError => { if !retry_on_error { Err(ScanError::Down(format!( "Host {}, network error, marking down", From 5810f9506e3ab67ba8ef2af6bfe2a8d0c4a6022b Mon Sep 17 00:00:00 2001 From: Jukka Taimisto Date: Wed, 9 Jul 2025 14:26:12 +0300 Subject: [PATCH 5/5] Do not print control characters when printing banner. Also adds missing newline when printing banners. --- src/output.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/output.rs b/src/output.rs index cc7b071..0dc4fac 100644 --- a/src/output.rs +++ b/src/output.rs @@ -42,11 +42,20 @@ struct Banners { impl Display for Banners { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut builder = String::new(); - builder.push_str("\n\t Banners received from open ports:\n"); + builder.push_str("\n\tBanners received from open ports:\n"); for (port, b) in &self.values { let _ = match std::str::from_utf8(b) { - Ok(s) => write!(builder, "\t\tPort: {port} \"{s}\""), - Err(_e) => write!(builder, "\t\tPort: {}: {} bytes of data", port, b.len()), + Ok(s) => { + let pretty: String = s + .chars() + .map(|c| match c.is_control() { + true => '\u{00b7}', + false => c, + }) + .collect(); + writeln!(builder, "\t\tPort: {port} \"{pretty}\"") + } + Err(_e) => writeln!(builder, "\t\tPort: {}: {} bytes of data", port, b.len()), }; } write!(f, "{builder}")