From 009da83bb556e95d58932e3b1532ab741377df9f Mon Sep 17 00:00:00 2001 From: Vrtgs Date: Sun, 29 Dec 2024 14:15:44 +0300 Subject: [PATCH 1/3] The full tokio port, Sadly there is no change in performance detected. --- Cargo.lock | 1074 +++++++++++++++------------ Cargo.toml | 13 +- benches/benchmark_portscan.rs | 45 +- build.rs | 15 +- src/address.rs | 232 +++--- src/generated.rs | 161 +--- src/input.rs | 29 +- src/lib.rs | 14 +- src/main.rs | 26 +- src/port_strategy/mod.rs | 165 ++-- src/port_strategy/range_iterator.rs | 133 ---- src/scanner/mod.rs | 241 +++--- src/scanner/socket_iterator.rs | 9 +- 13 files changed, 1034 insertions(+), 1123 deletions(-) delete mode 100644 src/port_strategy/range_iterator.rs diff --git a/Cargo.lock b/Cargo.lock index 28ee714ab..c58e4d22a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,21 +1,21 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "addr2line" -version = "0.22.0" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ "gimli", ] [[package]] -name = "adler" -version = "1.0.2" +name = "adler2" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" [[package]] name = "ahash" @@ -26,7 +26,7 @@ dependencies = [ "cfg-if", "once_cell", "version_check", - "zerocopy", + "zerocopy 0.7.35", ] [[package]] @@ -70,26 +70,26 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.7" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anstyle-parse" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.0" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -104,159 +104,40 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" - -[[package]] -name = "async-channel" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" -dependencies = [ - "concurrent-queue", - "event-listener 2.5.3", - "futures-core", -] - -[[package]] -name = "async-channel" -version = "2.3.1" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" -dependencies = [ - "concurrent-queue", - "event-listener-strategy", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-executor" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8828ec6e544c02b0d6691d21ed9f9218d0384a82542855073c2a3f58304aaf0" -dependencies = [ - "async-task", - "concurrent-queue", - "fastrand", - "futures-lite", - "slab", -] - -[[package]] -name = "async-global-executor" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" -dependencies = [ - "async-channel 2.3.1", - "async-executor", - "async-io", - "async-lock", - "blocking", - "futures-lite", - "once_cell", -] - -[[package]] -name = "async-io" -version = "2.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d6baa8f0178795da0e71bc42c9e5d13261aac7ee549853162e66a241ba17964" -dependencies = [ - "async-lock", - "cfg-if", - "concurrent-queue", - "futures-io", - "futures-lite", - "parking", - "polling", - "rustix", - "slab", - "tracing", - "windows-sys 0.52.0", -] - -[[package]] -name = "async-lock" -version = "3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" -dependencies = [ - "event-listener 5.3.1", - "event-listener-strategy", - "pin-project-lite", -] - -[[package]] -name = "async-std" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c634475f29802fde2b8f0b505b1bd00dfe4df7d4a000f0b36f7671197d5c3615" -dependencies = [ - "async-channel 1.9.0", - "async-global-executor", - "async-io", - "async-lock", - "crossbeam-utils", - "futures-channel", - "futures-core", - "futures-io", - "futures-lite", - "gloo-timers", - "kv-log-macro", - "log", - "memchr", - "once_cell", - "pin-project-lite", - "pin-utils", - "slab", - "wasm-bindgen-futures", -] - -[[package]] -name = "async-task" -version = "4.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" +checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" [[package]] name = "async-trait" -version = "0.1.81" +version = "0.1.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", "syn", ] -[[package]] -name = "atomic-waker" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" - [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "backtrace" -version = "0.3.73" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", "miniz_oxide", "object", "rustc-demangle", + "windows-targets 0.52.6", ] [[package]] @@ -272,16 +153,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] -name = "blocking" -version = "1.6.1" +name = "blackrock2" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" +checksum = "cf43b5a2324f5c0f2d4a33888deb07c430d76e31bc0c5a98040dde56b672d5d2" dependencies = [ - "async-channel 2.3.1", - "async-task", - "futures-io", - "futures-lite", - "piper", + "rand 0.9.0-beta.1", ] [[package]] @@ -290,11 +167,17 @@ version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "bytes" -version = "1.6.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" +checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" [[package]] name = "cast" @@ -304,9 +187,12 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.0.106" +version = "1.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "066fce287b1d4eafef758e89e09d724a24808a9196fe9756b8ca90e86d0719a2" +checksum = "8d6dbb628b8f8555f86d0323c2eb39e3ec81901f4b83e091db8a6a76d316a333" +dependencies = [ + "shlex", +] [[package]] name = "cfg-if" @@ -360,9 +246,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.13" +version = "4.5.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fbb260a053428790f3de475e304ff84cdbc4face759ea7a3e64c1edd938a7fc" +checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84" dependencies = [ "clap_builder", "clap_derive", @@ -370,9 +256,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.13" +version = "4.5.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64b17d7ea74e9f833c7dbf2cbe4fb12ff26783eda4782a8975b72f895c9b4d99" +checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838" dependencies = [ "anstream", "anstyle", @@ -383,11 +269,11 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.13" +version = "4.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" dependencies = [ - "heck 0.5.0", + "heck", "proc-macro2", "quote", "syn", @@ -395,15 +281,15 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.1" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" [[package]] name = "colorchoice" -version = "1.0.1" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "colored" @@ -421,15 +307,6 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffb474a9c3219a8254ead020421ecf1b90427f29b55f6aae9a2471fa62c126ef" -[[package]] -name = "concurrent-queue" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" -dependencies = [ - "crossbeam-utils", -] - [[package]] name = "criterion" version = "0.5.1" @@ -441,6 +318,7 @@ dependencies = [ "ciborium", "clap", "criterion-plot", + "futures", "is-terminal", "itertools 0.10.5", "num-traits", @@ -453,6 +331,7 @@ dependencies = [ "serde_derive", "serde_json", "tinytemplate", + "tokio", "walkdir", ] @@ -468,9 +347,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -487,9 +366,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.20" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crunchy" @@ -524,6 +403,17 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "either" version = "1.13.0" @@ -532,11 +422,11 @@ checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "enum-as-inner" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ffccbb6966c05b32ef8fbac435df276c4ae4d3dc55a8cd0eb9745e6c12f546a" +checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" dependencies = [ - "heck 0.4.1", + "heck", "proc-macro2", "quote", "syn", @@ -544,9 +434,9 @@ dependencies = [ [[package]] name = "env_filter" -version = "0.1.0" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea" +checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" dependencies = [ "log", "regex", @@ -573,47 +463,14 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "event-listener" -version = "2.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" - -[[package]] -name = "event-listener" -version = "5.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" -dependencies = [ - "concurrent-queue", - "parking", - "pin-project-lite", -] - -[[package]] -name = "event-listener-strategy" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" -dependencies = [ - "event-listener 5.3.1", - "pin-project-lite", + "windows-sys 0.59.0", ] -[[package]] -name = "fastrand" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" - [[package]] name = "form_urlencoded" version = "1.2.1" @@ -625,9 +482,9 @@ dependencies = [ [[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", @@ -640,9 +497,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", @@ -650,15 +507,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", @@ -667,28 +524,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" - -[[package]] -name = "futures-lite" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" -dependencies = [ - "fastrand", - "futures-core", - "futures-io", - "parking", - "pin-project-lite", -] +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", @@ -697,21 +541,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", @@ -725,12 +569,6 @@ dependencies = [ "slab", ] -[[package]] -name = "gcd" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d758ba1b47b00caf47f24925c0074ecb20d6dfcffe7f6d53395c0465674841a" - [[package]] name = "getrandom" version = "0.2.15" @@ -739,27 +577,30 @@ checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", ] [[package]] -name = "gimli" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" - -[[package]] -name = "gloo-timers" -version = "0.3.0" +name = "getrandom" +version = "0.3.0-rc.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" +checksum = "8a78f88e84d239c7f2619ae8b091603c26208e1cb322571f5a29d6806f56ee5e" dependencies = [ - "futures-channel", - "futures-core", + "cfg-if", "js-sys", + "libc", + "rustix", + "wasi 0.13.3+wasi-0.2.2", "wasm-bindgen", + "windows-targets 0.52.6", ] +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" + [[package]] name = "half" version = "2.4.1" @@ -787,15 +628,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.0" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" [[package]] name = "heck" @@ -803,12 +638,6 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" -[[package]] -name = "hermit-abi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" - [[package]] name = "hermit-abi" version = "0.4.0" @@ -817,9 +646,9 @@ checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" [[package]] name = "hickory-proto" -version = "0.24.1" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07698b8420e2f0d6447a436ba999ec85d8fbf2a398bbd737b82cac4a2e96e512" +checksum = "447afdcdb8afb9d0a852af6dc65d9b285ce720ed7a59e42a8bf2e931c67bc1b5" dependencies = [ "async-trait", "cfg-if", @@ -828,10 +657,10 @@ dependencies = [ "futures-channel", "futures-io", "futures-util", - "idna 0.4.0", + "idna", "ipnet", "once_cell", - "rand", + "rand 0.8.5", "rustls", "rustls-pemfile", "thiserror", @@ -855,7 +684,7 @@ dependencies = [ "lru-cache", "once_cell", "parking_lot", - "rand", + "rand 0.8.5", "resolv-conf", "rustls", "smallvec", @@ -883,23 +712,142 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] -name = "idna" -version = "0.4.0" +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] [[package]] name = "idna" -version = "0.5.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", ] [[package]] @@ -914,12 +862,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" dependencies = [ "equivalent", - "hashbrown 0.15.0", + "hashbrown 0.15.2", ] [[package]] @@ -936,9 +884,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.9.0" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" [[package]] name = "is-terminal" @@ -946,16 +894,16 @@ version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" dependencies = [ - "hermit-abi 0.4.0", + "hermit-abi", "libc", "windows-sys 0.52.0", ] [[package]] name = "is_terminal_polyfill" -version = "1.70.0" +version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "itertools" @@ -977,28 +925,20 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "js-sys" -version = "0.3.69" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7" dependencies = [ + "once_cell", "wasm-bindgen", ] -[[package]] -name = "kv-log-macro" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" -dependencies = [ - "log", -] - [[package]] name = "lazy_static" version = "1.5.0" @@ -1007,9 +947,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.155" +version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" [[package]] name = "libredox" @@ -1033,6 +973,12 @@ version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +[[package]] +name = "litemap" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" + [[package]] name = "lock_api" version = "0.4.12" @@ -1048,9 +994,6 @@ name = "log" version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" -dependencies = [ - "value-bag", -] [[package]] name = "lru-cache" @@ -1075,22 +1018,22 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "miniz_oxide" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394" dependencies = [ - "adler", + "adler2", ] [[package]] name = "mio" -version = "0.8.11" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ "libc", - "wasi", - "windows-sys 0.48.0", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.52.0", ] [[package]] @@ -1121,21 +1064,11 @@ dependencies = [ "autocfg", ] -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi 0.3.9", - "libc", -] - [[package]] name = "object" -version = "0.36.1" +version = "0.36.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "081b846d1d56ddfc18fdf1a922e4f6e07a11768ea1b92dec44e42b72712ccfce" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ "memchr", ] @@ -1179,12 +1112,6 @@ dependencies = [ "syn", ] -[[package]] -name = "parking" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" - [[package]] name = "parking_lot" version = "0.12.3" @@ -1216,9 +1143,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" [[package]] name = "pin-utils" @@ -1226,17 +1153,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" -[[package]] -name = "piper" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae1d5c74c9876f070d3e8fd503d748c7d974c3e48da8f41350fa5222ef9b4391" -dependencies = [ - "atomic-waker", - "fastrand", - "futures-io", -] - [[package]] name = "plotters" version = "0.3.7" @@ -1266,31 +1182,19 @@ dependencies = [ ] [[package]] -name = "polling" -version = "3.7.2" +name = "ppv-lite86" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3ed00ed3fbf728b5816498ecd316d1716eecaced9c0c8d2c5a6740ca214985b" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" dependencies = [ - "cfg-if", - "concurrent-queue", - "hermit-abi 0.4.0", - "pin-project-lite", - "rustix", - "tracing", - "windows-sys 0.52.0", + "zerocopy 0.7.35", ] -[[package]] -name = "ppv-lite86" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] @@ -1303,9 +1207,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" -version = "1.0.36" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" dependencies = [ "proc-macro2", ] @@ -1317,8 +1221,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha", - "rand_core", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.0-beta.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8478de76992f2825a1052cc2ae9d1401cdb62687761d4100ddd69a73dc3dc48" +dependencies = [ + "rand_chacha 0.9.0-beta.1", + "rand_core 0.9.0-beta.1", + "zerocopy 0.8.14", ] [[package]] @@ -1328,7 +1243,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0-beta.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f16da77124f4ee9fabd55ce6540866e9101431863b4876de58b68797f331adf2" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.0-beta.1", ] [[package]] @@ -1337,7 +1262,17 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom", + "getrandom 0.2.15", +] + +[[package]] +name = "rand_core" +version = "0.9.0-beta.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a98fa0b8309344136abe6244130311e76997e546f76fae8054422a7539b43df7" +dependencies = [ + "getrandom 0.3.0-rc.0", + "zerocopy 0.8.14", ] [[package]] @@ -1362,29 +1297,29 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.2" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd" +checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" dependencies = [ "bitflags", ] [[package]] name = "redox_users" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ - "getrandom", + "getrandom 0.2.15", "libredox", "thiserror", ] [[package]] name = "regex" -version = "1.10.5" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", @@ -1394,9 +1329,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", @@ -1405,9 +1340,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "resolv-conf" @@ -1427,7 +1362,7 @@ checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", "cfg-if", - "getrandom", + "getrandom 0.2.15", "libc", "spin", "untrusted", @@ -1451,15 +1386,15 @@ checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustix" -version = "0.38.34" +version = "0.38.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85" dependencies = [ "bitflags", "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1498,9 +1433,8 @@ name = "rustscan" version = "2.3.0" dependencies = [ "ansi_term", - "anstream", "anyhow", - "async-std", + "blackrock2", "cidr-utils", "clap", "colored", @@ -1509,17 +1443,17 @@ dependencies = [ "dirs", "env_logger", "futures", - "gcd", "hickory-resolver", "itertools 0.13.0", "log", - "once_cell", "parameterized", - "rand", + "rand 0.8.5", "rlimit", "serde", "serde_derive", "text_placeholder", + "tokio", + "tokio-par-stream", "toml", "wait-timeout", ] @@ -1557,18 +1491,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.204" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" +checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.204" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" +checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" dependencies = [ "proc-macro2", "quote", @@ -1577,11 +1511,12 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.120" +version = "1.0.134" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" +checksum = "d00f4175c42ee48b15416f6193a959ba3a0d67fc699a0db9ad12df9f83991c7d" dependencies = [ "itoa", + "memchr", "ryu", "serde", ] @@ -1595,6 +1530,21 @@ dependencies = [ "serde", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook-registry" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +dependencies = [ + "libc", +] + [[package]] name = "slab" version = "0.4.9" @@ -1612,9 +1562,9 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "socket2" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" dependencies = [ "libc", "windows-sys 0.52.0", @@ -1626,6 +1576,12 @@ version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "strsim" version = "0.11.1" @@ -1634,23 +1590,34 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.69" +version = "2.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "201fcda3845c23e8212cd466bfebf0bd20694490fc0356ae8e428e0824a915a6" +checksum = "70ae51629bf965c5c098cc9e87908a3df5301051a9e087d6f9bef5c9771ed126" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "terminal_size" -version = "0.3.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" +checksum = "5352447f921fda68cf61b4101566c0bdb5104eff6804d0678e5227580ab6a4e9" dependencies = [ "rustix", - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] @@ -1666,24 +1633,34 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.61" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.61" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", "syn", ] +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "zerovec", +] + [[package]] name = "tinytemplate" version = "1.2.1" @@ -1696,9 +1673,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce6b6a2fb3a985e99cebfaefa9faa3024743da73304ca1c683a36429613d3d22" +checksum = "022db8904dfa342efe721985167e9fcd16c29b226db4397ed752a761cfce81e8" dependencies = [ "tinyvec_macros", ] @@ -1711,18 +1688,42 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.38.0" +version = "1.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" +checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551" dependencies = [ "backtrace", "bytes", "libc", "mio", - "num_cpus", + "parking_lot", "pin-project-lite", + "signal-hook-registry", "socket2", - "windows-sys 0.48.0", + "tokio-macros", + "windows-sys 0.52.0", +] + +[[package]] +name = "tokio-macros" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-par-stream" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c50e0171016a0a440cf38c23e058f33608be93e6f81598a1929ff7aa78c7b9bd" +dependencies = [ + "futures", + "pin-project-lite", + "tokio", ] [[package]] @@ -1762,7 +1763,7 @@ version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ - "indexmap 2.6.0", + "indexmap 2.7.0", "serde", "serde_spanned", "toml_datetime", @@ -1771,9 +1772,9 @@ dependencies = [ [[package]] name = "tracing" -version = "0.1.40" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "pin-project-lite", "tracing-attributes", @@ -1782,9 +1783,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", @@ -1793,33 +1794,18 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.32" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" dependencies = [ "once_cell", ] -[[package]] -name = "unicode-bidi" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" - [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "unicode-normalization" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" -dependencies = [ - "tinyvec", -] +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "untrusted" @@ -1829,32 +1815,38 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.2" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" dependencies = [ "form_urlencoded", - "idna 0.5.0", + "idna", "percent-encoding", ] [[package]] -name = "utf8parse" -version = "0.2.2" +name = "utf16_iter" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" [[package]] -name = "value-bag" -version = "1.9.0" +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "utf8parse" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a84c137d37ab0142f0f2ddfe332651fdbf252e7b7dbb4e67b6c1f1b2e925101" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "wait-timeout" @@ -1881,48 +1873,45 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasi" +version = "0.13.3+wasi-0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" +dependencies = [ + "wit-bindgen-rt", +] + [[package]] name = "wasm-bindgen" -version = "0.2.92" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396" dependencies = [ "cfg-if", + "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.92" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79" dependencies = [ "bumpalo", "log", - "once_cell", "proc-macro2", "quote", "syn", "wasm-bindgen-shared", ] -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" -dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] - [[package]] name = "wasm-bindgen-macro" -version = "0.2.92" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1930,9 +1919,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.92" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" dependencies = [ "proc-macro2", "quote", @@ -1943,15 +1932,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.92" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" [[package]] name = "web-sys" -version = "0.3.69" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +checksum = "04dd7223427d52553d3702c004d3b2fe07c148165faa56313cb00211e31c12bc" dependencies = [ "js-sys", "wasm-bindgen", @@ -2161,13 +2150,68 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "wit-bindgen-rt" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" +dependencies = [ + "bitflags", +] + +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + +[[package]] +name = "yoke" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + [[package]] name = "zerocopy" version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ - "zerocopy-derive", + "byteorder", + "zerocopy-derive 0.7.35", +] + +[[package]] +name = "zerocopy" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a367f292d93d4eab890745e75a778da40909cab4d6ff8173693812f79c4a2468" +dependencies = [ + "zerocopy-derive 0.8.14", ] [[package]] @@ -2180,3 +2224,57 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zerocopy-derive" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3931cb58c62c13adec22e38686b559c86a30565e16ad6e8510a337cedc611e1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zerofrom" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/Cargo.toml b/Cargo.toml index f42a420ce..56d987dcf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,16 +17,16 @@ exclude = [ ] [dependencies] +tokio = { version = "1.42.0", features = ["full"] } +tokio-par-stream = "0.1.1" +blackrock2 = "0.1.0" clap = { version = "4.5.13", features = ["derive", "wrap_help"] } colored = "2.2.0" -async-std = "1.13.0" futures = "0.3" rlimit = "0.10.2" log = "0.4.22" env_logger = "0.11.6" -anstream = "=0.6.18" dirs = "5.0.1" -gcd = "2.0.1" rand = "0.8.5" colorful = "0.3.2" ansi_term = "0.12.1" @@ -38,17 +38,20 @@ itertools = "0.13.0" hickory-resolver = { version = "0.24.2", features = ["dns-over-rustls"] } anyhow = "1.0.40" text_placeholder = { version = "0.5", features = ["struct_context"] } -once_cell = "1.20.2" [dev-dependencies] parameterized = "2.0.0" wait-timeout = "0.2" -criterion = { version = "0.5", features = ["html_reports"] } +criterion = { version = "0.5", features = ["html_reports", "async_tokio"] } [package.metadata.deb] depends = "$auto, nmap" section = "rust" +[profile.test] +debug = "full" + + [profile.release] lto = true panic = 'abort' diff --git a/benches/benchmark_portscan.rs b/benches/benchmark_portscan.rs index 1206fa08e..896fa2acf 100644 --- a/benches/benchmark_portscan.rs +++ b/benches/benchmark_portscan.rs @@ -1,39 +1,26 @@ -use async_std::task::block_on; use criterion::{black_box, criterion_group, criterion_main, Criterion}; use rustscan::input::{PortRange, ScanOrder}; use rustscan::port_strategy::PortStrategy; use rustscan::scanner::Scanner; -use std::net::IpAddr; +use std::net::{IpAddr, Ipv4Addr}; use std::time::Duration; -fn portscan_tcp(scanner: &Scanner) { - let _scan_result = block_on(scanner.run()); -} - -fn portscan_udp(scanner: &Scanner) { - let _scan_result = block_on(scanner.run()); -} - -fn bench_address() { - let _addrs = ["127.0.0.1".parse::().unwrap()]; -} - fn bench_port_strategy() { let range = PortRange { start: 1, end: 1_000, }; - let _strategy = PortStrategy::pick(&Some(range.clone()), None, ScanOrder::Serial); + let _strategy = PortStrategy::range(black_box(range), ScanOrder::Serial); } fn criterion_benchmark(c: &mut Criterion) { - let addrs = vec!["127.0.0.1".parse::().unwrap()]; + let addrs = [IpAddr::V4(Ipv4Addr::LOCALHOST)]; let range = PortRange { start: 1, end: 1_000, }; - let strategy_tcp = PortStrategy::pick(&Some(range.clone()), None, ScanOrder::Serial); - let strategy_udp = PortStrategy::pick(&Some(range.clone()), None, ScanOrder::Serial); + let strategy_tcp = PortStrategy::range(range, ScanOrder::Serial); + let strategy_udp = PortStrategy::range(range, ScanOrder::Serial); let scanner_tcp = Scanner::new( &addrs, @@ -43,13 +30,19 @@ fn criterion_benchmark(c: &mut Criterion) { false, strategy_tcp, true, - vec![], + &[], false, ); - c.bench_function("portscan tcp", |b| { - b.iter(|| portscan_tcp(black_box(&scanner_tcp))) + let runtime = tokio::runtime::Runtime::new().unwrap(); + + let mut tcp_group = c.benchmark_group("portscan tcp"); + tcp_group.measurement_time(Duration::from_secs(20)); + tcp_group.sample_size(10); + tcp_group.bench_function("portscan tcp", |b| { + b.to_async(&runtime).iter(|| black_box(&scanner_tcp).run()) }); + tcp_group.finish(); let scanner_udp = Scanner::new( &addrs, @@ -59,20 +52,18 @@ fn criterion_benchmark(c: &mut Criterion) { false, strategy_udp, true, - vec![], + &[], true, ); let mut udp_group = c.benchmark_group("portscan udp"); udp_group.measurement_time(Duration::from_secs(20)); + udp_group.sample_size(25); udp_group.bench_function("portscan udp", |b| { - b.iter(|| portscan_udp(black_box(&scanner_udp))) + b.to_async(&runtime).iter(|| black_box(&scanner_udp).run()) }); udp_group.finish(); - - // Benching helper functions - c.bench_function("parse address", |b| b.iter(bench_address)); - + c.bench_function("port strategy", |b| b.iter(bench_port_strategy)); } diff --git a/build.rs b/build.rs index 886feb9bb..77fdb93a3 100644 --- a/build.rs +++ b/build.rs @@ -3,7 +3,7 @@ use std::fs::{self, File}; use std::env; use std::io::{BufReader, Read}; -use std::path::PathBuf; +use std::path::Path; use std::process::Command; // Reads in a file with payloads based on port @@ -59,11 +59,11 @@ pub fn main() { /// /// * `port_payload_map` - A BTreeMap mapping port numbers to payload data fn generate_code(port_payload_map: BTreeMap, Vec>) { - let dest_path = PathBuf::from("src/generated.rs"); + let dest_path = Path::new("src/generated.rs"); let mut generated_code = String::new(); generated_code.push_str("use std::collections::BTreeMap;\n"); - generated_code.push_str("use once_cell::sync::Lazy;\n\n"); + generated_code.push_str("use std::sync::LazyLock;\n\n"); generated_code.push_str("fn generated_data() -> BTreeMap, Vec> {\n"); generated_code.push_str(" let mut map = BTreeMap::new();\n"); @@ -92,7 +92,7 @@ fn generate_code(port_payload_map: BTreeMap, Vec>) { generated_code.push_str("}\n\n"); generated_code.push_str( - "static PARSED_DATA: Lazy, Vec>> = Lazy::new(generated_data);\n", + "static PARSED_DATA: LazyLock, Vec>> = LazyLock::new(generated_data);\n", ); generated_code.push_str("pub fn get_parsed_data() -> &'static BTreeMap, Vec> {\n"); generated_code.push_str(" &PARSED_DATA\n"); @@ -101,10 +101,9 @@ fn generate_code(port_payload_map: BTreeMap, Vec>) { fs::write(dest_path, generated_code).unwrap(); // format the generated code - Command::new("cargo") - .arg("fmt") - .arg("--all") - .output() + Command::new("rustfmt") + .arg(dest_path) + .status() .expect("Failed to execute cargo fmt"); } diff --git a/src/address.rs b/src/address.rs index 0f4df7fd3..8656d6ae2 100644 --- a/src/address.rs +++ b/src/address.rs @@ -1,65 +1,56 @@ //! Provides functions to parse input IP addresses, CIDRs or files. -use std::collections::BTreeSet; -use std::fs::{self, File}; -use std::io::{prelude::*, BufReader}; -use std::net::{IpAddr, SocketAddr, ToSocketAddrs}; + +use std::cell::RefCell; +use std::net::{IpAddr, SocketAddr}; use std::path::Path; +use std::pin::Pin; use std::str::FromStr; - +use std::thread; +use std::time::Duration; use cidr_utils::cidr::IpCidr; -use hickory_resolver::{ - config::{NameServerConfig, Protocol, ResolverConfig, ResolverOpts}, - Resolver, -}; +use futures::{FutureExt, StreamExt}; +use hickory_resolver::{config::{NameServerConfig, Protocol, ResolverConfig, ResolverOpts}, AsyncResolver, TokioAsyncResolver}; +use itertools::Either; use log::debug; - +use tokio::fs; +use tokio::io::AsyncBufReadExt; use crate::input::Opts; use crate::warning; -/// Parses the string(s) into IP addresses. -/// -/// Goes through all possible IP inputs (files or via argparsing). -/// -/// ```rust -/// # use rustscan::input::Opts; -/// # use rustscan::address::parse_addresses; -/// let mut opts = Opts::default(); -/// opts.addresses = vec!["192.168.0.0/30".to_owned()]; -/// -/// let ips = parse_addresses(&opts); -/// ``` -/// -/// Finally, any duplicates are removed to avoid excessive scans. -pub fn parse_addresses(input: &Opts) -> Vec { - let mut ips: Vec = Vec::new(); - let mut unresolved_addresses: Vec<&str> = Vec::new(); - let backup_resolver = get_resolver(&input.resolver); - - for address in &input.addresses { - let parsed_ips = parse_address(address, &backup_resolver); - if !parsed_ips.is_empty() { - ips.extend(parsed_ips); - } else { - unresolved_addresses.push(address); +async fn parse_addresses_inner(input: &Opts) -> Vec { + let ips = &RefCell::new(Vec::new()); + let unresolved_addresses = &RefCell::new(Vec::new()); + let backup_resolver = &get_resolver(&input.resolver).await; + + futures::stream::iter(&input.addresses).for_each_concurrent(Some(4), |address| async move { + let mut found_ip = false; + let parsed_ips = parse_address(address, backup_resolver) + .await.inspect(|_| found_ip = true); + + ips.borrow_mut().extend(parsed_ips); + + if !found_ip { + unresolved_addresses.borrow_mut().push(address); } - } + }).await; + // If we got to this point this can only be a file path or the wrong input. - for file_path in unresolved_addresses { + futures::stream::iter(unresolved_addresses.take()).for_each_concurrent(Some(4), |file_path| async move { let file_path = Path::new(file_path); - if !file_path.is_file() { + if !tokio::fs::metadata(file_path).await.map_or(false, |m| m.is_file()) { warning!( format!("Host {file_path:?} could not be resolved."), input.greppable, input.accessible ); - continue; + return; } - if let Ok(x) = read_ips_from_file(file_path, &backup_resolver) { - ips.extend(x); + if let Ok(x) = read_ips_from_file(file_path, backup_resolver).await { + ips.borrow_mut().extend(x); } else { warning!( format!("Host {file_path:?} could not be resolved."), @@ -67,12 +58,39 @@ pub fn parse_addresses(input: &Opts) -> Vec { input.accessible ); } - } + }).await; - ips.into_iter() - .collect::>() - .into_iter() - .collect() + let mut ips = ips.take(); + + ips.sort_unstable(); + ips.dedup(); + ips +} + +/// Parses the string(s) into IP addresses. +/// +/// Goes through all possible IP inputs (files or via argparsing). +/// +/// ```rust +/// # use rustscan::input::Opts; +/// # use rustscan::address::parse_addresses; +/// let mut opts = Opts::default(); +/// opts.addresses = vec!["192.168.0.0/30".to_owned()]; +/// +/// let ips = parse_addresses(&opts); +/// ``` +/// +/// Finally, any duplicates are removed to avoid excessive scans. +pub fn parse_addresses(input: &Opts) -> Vec { + thread::scope(|s| { + s.spawn(|| { + tokio::runtime::Runtime::new() + .unwrap() + .block_on(parse_addresses_inner(input)) + }) + .join() + .unwrap_or_else(|panic| std::panic::resume_unwind(panic)) + }) } /// Given a string, parse it as a host, IP address, or CIDR. @@ -85,35 +103,45 @@ pub fn parse_addresses(input: &Opts) -> Vec { /// /// ```rust /// # use rustscan::address::parse_address; -/// # use hickory_resolver::Resolver; -/// let ips = parse_address("127.0.0.1", &Resolver::default().unwrap()); +/// # use hickory_resolver::{Resolver, TokioAsyncResolver}; +/// # #[tokio::main] +/// # async fn main() { +/// let ips = parse_address("127.0.0.1", &TokioAsyncResolver::tokio_from_system_conf().unwrap()).await.collect::>(); +/// println!("{ips:?}") +/// # } /// ``` -pub fn parse_address(address: &str, resolver: &Resolver) -> Vec { - IpCidr::from_str(address) - .map(|cidr| cidr.iter().map(|c| c.address()).collect()) - .ok() - .or_else(|| { - format!("{}:80", &address) - .to_socket_addrs() - .ok() - .map(|mut iter| vec![iter.next().unwrap().ip()]) - }) - .unwrap_or_else(|| resolve_ips_from_host(address, resolver)) +pub async fn parse_address<'r>(address: &str, resolver: &'r TokioAsyncResolver) -> impl Iterator + use<'r> { + if let Ok(addr) = address.parse::() { + return Either::Right(std::iter::once(addr)); + } + + let res = IpCidr::from_str(address) + .map(|cidr| cidr.iter().map(|c| c.address())) + .ok(); + + Either::Left(match res { + Some(res) => Either::Right(res), + None => Either::Left(resolve_ips_from_host(address, resolver).await), + }) } /// Uses DNS to get the IPS associated with host -fn resolve_ips_from_host(source: &str, backup_resolver: &Resolver) -> Vec { - let mut ips: Vec = Vec::new(); - - if let Ok(addrs) = source.to_socket_addrs() { - for ip in addrs { - ips.push(ip.ip()); - } - } else if let Ok(addrs) = backup_resolver.lookup_ip(source) { - ips.extend(addrs.iter()); +async fn resolve_ips_from_host<'r>(source: &str, resolver: &'r TokioAsyncResolver) -> impl Iterator + use<'r> { + let resolver_lookup = resolver.lookup_ip(source).fuse(); + let std_lookup = tokio::net::lookup_host((source.to_owned(), 80)).fuse(); + + let success_iter = |data| Either::Right(data); + let fail_iter = || Either::Left(std::iter::empty()); + + + let timeout = tokio::time::sleep(Duration::from_secs(10)); + + tokio::select! { + Ok(res) = std_lookup => success_iter(Either::Right(res.map(|s| s.ip()))), + Ok(res) = resolver_lookup => success_iter(Either::Left(res.into_iter())), + () = timeout => fail_iter(), + else => fail_iter(), } - - ips } /// Derive a DNS resolver. @@ -126,11 +154,11 @@ fn resolve_ips_from_host(source: &str, backup_resolver: &Resolver) -> Vec) -> Resolver { +async fn get_resolver(resolver: &Option) -> TokioAsyncResolver { match resolver { Some(r) => { let mut config = ResolverConfig::new(); - let resolver_ips = match read_resolver_from_file(r) { + let resolver_ips = match read_resolver_from_file(r).await { Ok(ips) => ips, Err(_) => r .split(',') @@ -143,20 +171,17 @@ fn get_resolver(resolver: &Option) -> Resolver { Protocol::Udp, )); } - Resolver::new(config, ResolverOpts::default()).unwrap() + AsyncResolver::tokio(config, ResolverOpts::default()) } - None => match Resolver::from_system_conf() { - Ok(resolver) => resolver, - Err(_) => { - Resolver::new(ResolverConfig::cloudflare_tls(), ResolverOpts::default()).unwrap() - } - }, + None => AsyncResolver::tokio_from_system_conf().unwrap_or_else(|_| { + AsyncResolver::tokio(ResolverConfig::cloudflare_tls(), ResolverOpts::default()) + }), } } /// Parses and input file of IPs for use in DNS resolution. -fn read_resolver_from_file(path: &str) -> Result, std::io::Error> { - let ips = fs::read_to_string(path)? +async fn read_resolver_from_file(path: &str) -> Result, std::io::Error> { + let ips = fs::read_to_string(path).await? .lines() .filter_map(|line| IpAddr::from_str(line.trim()).ok()) .collect(); @@ -166,24 +191,29 @@ fn read_resolver_from_file(path: &str) -> Result, std::io::Error> { #[cfg(not(tarpaulin_include))] /// Parses an input file of IPs and uses those -fn read_ips_from_file( - ips: &std::path::Path, - backup_resolver: &Resolver, +async fn read_ips_from_file( + ips: &Path, + backup_resolver: &TokioAsyncResolver, ) -> Result, std::io::Error> { - let file = File::open(ips)?; - let reader = BufReader::new(file); - - let mut ips: Vec = Vec::new(); - - for address_line in reader.lines() { + let mut lines = tokio::io::BufReader::new(fs::File::open(ips).await?) + .lines(); + + let ips = &RefCell::new(Vec::new()); + + let stream = futures::stream::poll_fn(move |cx| { + Pin::new(&mut lines).poll_next_line(cx).map(|res| res.transpose()) + }); + + stream.for_each_concurrent(Some(4), move |address_line| async move { if let Ok(address) = address_line { - ips.extend(parse_address(&address, backup_resolver)); + let addrs = parse_address(&address, backup_resolver).await; + ips.borrow_mut().extend(addrs); } else { debug!("Line in file is not valid"); } - } + }).await; - Ok(ips) + Ok(ips.take()) } #[cfg(test)] @@ -298,27 +328,27 @@ mod tests { assert_eq!(ips.len(), 2_048); } - #[test] - fn resolver_default_cloudflare() { + #[tokio::test] + async fn resolver_default_cloudflare() { let opts = Opts::default(); - let resolver = get_resolver(&opts.resolver); - let lookup = resolver.lookup_ip("www.example.com.").unwrap(); + let resolver = get_resolver(&opts.resolver).await; + let lookup = resolver.lookup_ip("www.example.com.").await.unwrap(); assert!(opts.resolver.is_none()); assert!(lookup.iter().next().is_some()); } - #[test] - fn resolver_args_google_dns() { + #[tokio::test] + async fn resolver_args_google_dns() { // https://developers.google.com/speed/public-dns let opts = Opts { resolver: Some("8.8.8.8,8.8.4.4".to_owned()), ..Default::default() }; - let resolver = get_resolver(&opts.resolver); - let lookup = resolver.lookup_ip("www.example.com.").unwrap(); + let resolver = get_resolver(&opts.resolver).await; + let lookup = resolver.lookup_ip("www.example.com.").await.unwrap(); assert!(lookup.iter().next().is_some()); } diff --git a/src/generated.rs b/src/generated.rs index af67ff2d6..fe50abe7e 100644 --- a/src/generated.rs +++ b/src/generated.rs @@ -1,40 +1,23 @@ -use once_cell::sync::Lazy; use std::collections::BTreeMap; +use std::sync::LazyLock; fn generated_data() -> BTreeMap, Vec> { let mut map = BTreeMap::new(); + map.insert( + vec![], + vec![99, 18, 22, 113, 51, 133, 88, 98, 117, 73, 147, 37], + ); map.insert(vec![7], vec![0, 0]); map.insert( vec![53, 69, 5353, 26198], vec![0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0], ); map.insert( - vec![53, 5353, 26198], + vec![53, 5353], vec![119, 119, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 7, 4, 0, 0, 16, 0, 3], ); - map.insert( - vec![67], - vec![ - 1, 1, 6, 0, 1, 35, 69, 103, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 84, - 133, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 6, 56, 37, 54, 51, 80, 16, - ], - ); map.insert(vec![69], vec![0, 1, 112, 0]); map.insert(vec![80], vec![18, 52, 86, 120, 153, 144]); - map.insert( - vec![111], - vec![ - 114, 17, 48, 0, 0, 0, 0, 0, 0, 0, 32, 0, 24, 96, 0, 1, 151, 112, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ], - ); map.insert( vec![ 111, 2049, 4045, 32768, 32769, 32770, 32771, 32772, 32773, 32774, 32775, 32776, 32777, @@ -2774,13 +2757,6 @@ fn generated_data() -> BTreeMap, Vec> { 0, 0, 0, 0, 0, 0, 0, ], ); - map.insert( - vec![123], - vec![ - 144, 0, 0, 0, 0, 0, 0, 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 97, 87, 128, 0, 0, - ], - ); map.insert( vec![ 135, 1025, 1026, 1027, 1028, 1029, 1030, 1031, 1032, 1033, 1034, 1035, 1036, 1037, @@ -2804,33 +2780,16 @@ fn generated_data() -> BTreeMap, Vec> { ], ); map.insert( - vec![137], - vec![1, 145, 0, 16, 0, 1, 0, 0, 0, 0, 0, 0, 32, 0, 0, 33, 0, 1], - ); - map.insert( - vec![161, 260, 3401], + vec![161, 260], vec![ 48, 16, 32, 16, 0, 64, 97, 18, 2, 1, 0, 2, 1, 0, 2, 1, 0, 48, 7, 48, 5, 6, 1, 0, 5, 0, ], ); map.insert(vec![177], vec![0, 1, 0, 2, 0, 1, 0]); - map.insert( - vec![389], - vec![ - 48, 132, 0, 0, 0, 32, 32, 16, 118, 56, 64, 0, 0, 2, 64, 64, 0, 1, 0, 0, 16, 0, 32, 16, - 0, 32, 22, 64, 16, 16, 8, 112, 8, 64, 0, 0, 0, - ], - ); - map.insert( - vec![427], - vec![ - 2, 1, 0, 0, 96, 0, 0, 0, 0, 0, 16, 0, 32, 0, 0, 1, 80, 0, 112, 0, 0, 0, - ], - ); map.insert( vec![ 443, 853, 3391, 4433, 4740, 5349, 5684, 5868, 6514, 6636, 8232, 10161, 10162, 12346, - 12446, 12546, 12646, 12746, 12846, 12946, 13046, + 12446, 12546, 12646, 12746, 12846, 12946, ], vec![ 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 54, 1, 0, 0, 32, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 119, @@ -2840,19 +2799,6 @@ fn generated_data() -> BTreeMap, Vec> { ); map.insert( vec![500], - vec![ - 0, 17, 34, 51, 68, 85, 102, 119, 0, 0, 0, 0, 0, 0, 0, 0, 1, 16, 2, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 4, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 152, 1, 1, 0, 4, 3, 0, 0, 36, 1, 1, 0, - 0, 128, 1, 0, 5, 128, 2, 0, 2, 128, 3, 0, 1, 128, 4, 0, 2, 128, 0, 0, 16, 0, 0, 4, 0, - 0, 0, 1, 3, 0, 0, 36, 2, 1, 0, 0, 128, 1, 0, 5, 128, 2, 0, 1, 128, 3, 0, 1, 128, 4, 0, - 2, 128, 0, 0, 16, 0, 0, 4, 0, 0, 0, 1, 3, 0, 0, 36, 3, 1, 0, 0, 128, 1, 0, 1, 128, 2, - 0, 2, 128, 3, 0, 1, 128, 4, 0, 2, 128, 0, 0, 16, 0, 0, 4, 0, 0, 0, 1, 0, 0, 0, 36, 4, - 1, 0, 0, 128, 1, 0, 1, 128, 2, 0, 1, 128, 3, 0, 1, 128, 4, 0, 2, 128, 0, 0, 16, 0, 0, - 4, 0, 0, 0, 1, - ], - ); - map.insert( - vec![500, 4500], vec![ 49, 39, 3, 129, 9, 137, 0, 0, 0, 0, 0, 0, 0, 0, 1, 16, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 80, 1, 1, 0, 2, 3, 0, 0, 36, 1, 1, 0, 0, 128, 1, 0, @@ -2863,108 +2809,29 @@ fn generated_data() -> BTreeMap, Vec> { 134, 56, 21, 66, 113, 0, 0, 0, 20, 38, 36, 67, 134, 19, 23, 35, 99, 8, 25, ], ); - map.insert( - vec![520], - vec![ - 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, - ], - ); - map.insert( - vec![623], - vec![ - 6, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 32, 24, 136, 16, 3, 136, 4, - ], - ); map.insert(vec![626], vec![18, 112, 1]); - map.insert(vec![1194], vec![56, 1, 2, 3, 4, 5, 6, 7, 8, 0, 0, 0, 0]); - map.insert( - vec![1604], - vec![ - 16, 0, 19, 0, 40, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ], - ); + map.insert(vec![1194], vec![129, 1, 137, 128, 0, 0]); map.insert( - vec![1645, 1812], + vec![1645], vec![1, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], ); - map.insert( - vec![1701], - vec![ - 128, 32, 3, 0, 0, 0, 0, 0, 0, 0, 0, 128, 8, 0, 0, 0, 0, 0, 1, 128, 8, 0, 0, 0, 2, 1, 0, - 128, 0, 0, 0, 0, 120, 0, 0, 0, 0, 3, 0, 0, 0, 3, 128, 8, 0, 0, 0, 9, 0, 0, - ], - ); - map.insert(vec![1900], vec![17, 35, 146, 85, 37, 82, 80, 25, 0]); - map.insert( - vec![2049], - vec![ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 1, 134, 48, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ], - ); - map.insert( - vec![2123, 2152], - vec![50, 1, 0, 4, 0, 0, 66, 0, 19, 55, 0, 0], - ); + map.insert(vec![2123], vec![50, 1, 0, 4, 0, 0, 66, 0, 19, 55, 0, 0]); map.insert( vec![2302], vec![0, 2, 18, 96, 18, 96, 144, 96, 38, 87, 64, 134, 132, 130], ); map.insert(vec![3283], vec![1, 64, 1, 3]); - map.insert(vec![3386], vec![64, 16, 0, 72, 0]); map.insert( vec![3478], vec![0, 1, 0, 0, 33, 18, 68, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], ); - map.insert( - vec![3784], - vec![ - 1, 117, 117, 49, 49, 112, 33, 41, 148, 25, 8, 88, 36, 1, 17, 150, 115, 98, 129, 50, 9, - 18, 117, - ], - ); map.insert(vec![4665, 4666, 4672, 6429], vec![70]); map.insert(vec![5351], vec![0, 0]); - map.insert( - vec![5353], - vec![0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 9, 7, 4, 5, 0, 0, 0, 0], - ); map.insert(vec![5632], vec![]); map.insert(vec![5683], vec![1, 1, 4]); map.insert(vec![6481], vec![0, 0]); map.insert(vec![7777], vec![0]); - map.insert( - vec![8767], - vec![ - 64, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 2, 133, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, - 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, - ], - ); - map.insert( - vec![9987], - vec![ - 5, 113, 105, 17, 152, 144, 0, 0, 0, 0, 41, 116, 132, 87, 153, 8, 25, 65, 1, 98, 50, 99, - 72, 52, 72, 56, 133, 20, 86, 144, 149, 35, 48, 9, 114, 23, 18, 64, 97, 23, 101, 118, - 72, 82, 130, 98, 54, 81, 135, 23, 56, 56, 18, 115, 71, 115, 80, 153, 114, 36, 144, 33, - 118, 97, 39, 38, 49, 113, 149, 150, 153, 149, 112, 80, 57, 69, 96, 67, 20, 89, 33, 67, - 3, 35, 50, 88, 99, 152, 133, 38, 85, 32, 37, 151, 34, 64, 146, 137, 65, 23, 38, - ], - ); map.insert(vec![10001], vec![1, 0, 0, 0]); - map.insert(vec![10080], vec![38, 0, 0, 0, 0, 0, 0]); - map.insert(vec![11211], vec![0, 16, 0, 1, 0]); - map.insert( - vec![17185], - vec![ - 114, 55, 114, 55, 0, 0, 0, 0, 0, 0, 0, 2, 85, 85, 85, 85, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 16, 0, 0, 0, 48, 0, 0, 0, 48, 0, 0, 0, - 32, 0, 0, 0, 0, 0, 0, 0, - ], - ); map.insert( vec![ 26000, 26001, 26002, 26003, 27960, 27961, 27962, 27963, 30720, 30721, 30722, 30723, @@ -2981,16 +2848,12 @@ fn generated_data() -> BTreeMap, Vec> { ); map.insert(vec![27444], vec![68]); map.insert(vec![27910, 27911, 27912, 27913], vec![]); - map.insert( - vec![31337], - vec![99, 18, 22, 113, 51, 133, 88, 98, 117, 73, 147, 37], - ); map.insert(vec![34555], vec![]); map.insert(vec![64738], vec![0, 0, 0, 0]); map } -static PARSED_DATA: Lazy, Vec>> = Lazy::new(generated_data); +static PARSED_DATA: LazyLock, Vec>> = LazyLock::new(generated_data); pub fn get_parsed_data() -> &'static BTreeMap, Vec> { &PARSED_DATA } diff --git a/src/input.rs b/src/input.rs index a38752118..0561ecab3 100644 --- a/src/input.rs +++ b/src/input.rs @@ -1,8 +1,9 @@ //! Provides a means to read, parse and hold configuration options for scans. use clap::{Parser, ValueEnum}; use serde_derive::Deserialize; -use std::collections::HashMap; +use std::collections::{Bound, HashMap}; use std::fs; +use std::ops::RangeBounds; use std::path::PathBuf; const LOWEST_PORT_NUMBER: u16 = 1; @@ -29,12 +30,22 @@ pub enum ScriptsRequired { } /// Represents the range of ports to be scanned. -#[derive(Deserialize, Debug, Clone, PartialEq, Eq)] +#[derive(Deserialize, Debug, Copy, Clone, PartialEq, Eq)] pub struct PortRange { pub start: u16, pub end: u16, } +impl RangeBounds for PortRange { + fn start_bound(&self) -> Bound<&u16> { + Bound::Included(&self.start) + } + + fn end_bound(&self) -> Bound<&u16> { + Bound::Included(&self.end) + } +} + #[cfg(not(tarpaulin_include))] fn parse_range(input: &str) -> Result { let range = input @@ -182,9 +193,9 @@ impl Opts { fn merge_required(&mut self, config: &Config) { macro_rules! merge_required { - ($($field: ident),+) => { + ($($field: ident),+ $(,)?) => { $( - if let Some(e) = &config.$field { + if let Some(ref e) = config.$field { self.$field = e.clone(); } )+ @@ -271,7 +282,6 @@ pub struct Config { #[cfg(not(tarpaulin_include))] #[allow(clippy::doc_link_with_quotes)] -#[allow(clippy::manual_unwrap_or_default)] impl Config { /// Reads the configuration file with TOML format and parses it into a /// Config struct. @@ -289,10 +299,7 @@ impl Config { let mut content = String::new(); let config_path = custom_config_path.unwrap_or_else(default_config_path); if config_path.exists() { - content = match fs::read_to_string(config_path) { - Ok(content) => content, - Err(_) => String::new(), - } + content = fs::read_to_string(config_path).unwrap_or_default() } let config: Config = match toml::from_str(&content) { @@ -377,11 +384,11 @@ mod tests { opts.merge(&config); - assert_eq!(opts.addresses, vec![] as Vec); + assert_eq!(*opts.addresses, [] as [String; 0]); assert!(opts.greppable); assert!(!opts.accessible); assert_eq!(opts.timeout, 0); - assert_eq!(opts.command, vec![] as Vec); + assert_eq!(*opts.command, [] as [String; 0]); assert_eq!(opts.scan_order, ScanOrder::Serial); } diff --git a/src/lib.rs b/src/lib.rs index e335de58a..ce42c009b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,33 +8,33 @@ //! [`PortStrategy`](crate::port_strategy::PortStrategy): //! //! ```rust -//! use async_std::task::block_on; //! use std::{net::IpAddr, time::Duration}; //! //! use rustscan::input::{PortRange, ScanOrder}; //! use rustscan::port_strategy::PortStrategy; //! use rustscan::scanner::Scanner; -//! -//! fn main() { +//! +//! #[tokio::main] +//! async fn main() { //! let addrs = vec!["127.0.0.1".parse::().unwrap()]; //! let range = PortRange { //! start: 1, //! end: 1_000, //! }; -//! let strategy = PortStrategy::pick(&Some(range), None, ScanOrder::Random); // can be serial, random or manual https://github.com/RustScan/RustScan/blob/master/src/port_strategy/mod.rs +//! let strategy = PortStrategy::range(range, ScanOrder::Random); // can be serial, random or manual https://github.com/RustScan/RustScan/blob/master/src/port_strategy/mod.rs //! let scanner = Scanner::new( //! &addrs, // the addresses to scan //! 10, // batch_size is how many ports at a time should be scanned //! Duration::from_millis(100), //T imeout is the time RustScan should wait before declaring a port closed. As datatype Duration. //! 1, // Tries, how many retries should RustScan do? -//! true, // greppable is whether or not RustScan should print things, or wait until the end to print only the ip +//! true, // greppable is whether RustScan should print things, or wait until the end to print only the ip //! strategy, // the port strategy used //! true, // accessible, should the output be A11Y compliant? -//! vec![9000], // What ports should RustScan exclude? +//! &[9000], // What ports should RustScan exclude? //! false, // is this a UDP scan? //! ); //! -//! let scan_result = block_on(scanner.run()); +//! let scan_result = scanner.run().await; //! //! println!("{:?}", scan_result); //! } diff --git a/src/main.rs b/src/main.rs index b5574771b..fa848eb2d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -83,15 +83,37 @@ fn main() { #[cfg(not(unix))] let batch_size: u16 = AVERAGE_BATCH_SIZE; + let port_strategy = match (opts.range, opts.ports) { + (Some(range), None) => PortStrategy::range(range, opts.scan_order), + (None, Some(list)) => PortStrategy::list(list, opts.scan_order), + (Some(_), Some(_)) => { + warning!( + "Rust-scan should be called with either ports or range, not both", + opts.greppable, + opts.accessible + ); + std::process::exit(1); + }, + (None, None) => { + warning!( + "Rust-scan needs either a range or ports", + opts.greppable, + opts.accessible + ); + std::process::exit(1); + }, + }; + + let scanner = Scanner::new( &ips, batch_size, Duration::from_millis(opts.timeout.into()), opts.tries, opts.greppable, - PortStrategy::pick(&opts.range, opts.ports, opts.scan_order), + port_strategy, opts.accessible, - opts.exclude_ports.unwrap_or_default(), + &opts.exclude_ports.unwrap_or_default(), opts.udp, ); debug!("Scanner finished building: {:?}", scanner); diff --git a/src/port_strategy/mod.rs b/src/port_strategy/mod.rs index 6f5eadad8..a9d7dba3a 100644 --- a/src/port_strategy/mod.rs +++ b/src/port_strategy/mod.rs @@ -1,9 +1,11 @@ //! Provides a means to hold configuration options specifically for port scanning. -mod range_iterator; -use crate::input::{PortRange, ScanOrder}; + +use crate::input::ScanOrder; +use blackrock2::BlackRockIter; use rand::seq::SliceRandom; -use rand::thread_rng; -use range_iterator::RangeIterator; +use std::collections::Bound; +use std::ops::RangeBounds; +use itertools::Either; /// Represents options of port scanning. /// @@ -11,43 +13,46 @@ use range_iterator::RangeIterator; /// it will also contain custom lists of ports. #[derive(Debug)] pub enum PortStrategy { - Manual(Vec), + List(Box<[u16]>), Serial(SerialRange), Random(RandomRange), } impl PortStrategy { - pub fn pick(range: &Option, ports: Option>, order: ScanOrder) -> Self { - match order { - ScanOrder::Serial if ports.is_none() => { - let range = range.as_ref().unwrap(); - PortStrategy::Serial(SerialRange { - start: range.start, - end: range.end, - }) - } - ScanOrder::Random if ports.is_none() => { - let range = range.as_ref().unwrap(); - PortStrategy::Random(RandomRange { - start: range.start, - end: range.end, - }) + pub fn range(range: impl RangeBounds, order: ScanOrder) -> Self { + fn _range(range: ExclusivePortRange, order: ScanOrder) -> PortStrategy { + match order { + ScanOrder::Serial => PortStrategy::Serial(SerialRange(range)), + ScanOrder::Random => PortStrategy::Random(RandomRange(range)), } - ScanOrder::Serial => PortStrategy::Manual(ports.unwrap()), - ScanOrder::Random => { - let mut rng = thread_rng(); - let mut ports = ports.unwrap(); - ports.shuffle(&mut rng); - PortStrategy::Manual(ports) + } + + _range(ExclusivePortRange::from(range), order) + } + + pub fn list(list: impl Into>, order: ScanOrder) -> Self { + fn _list(mut list: Box<[u16]>, order: ScanOrder) -> PortStrategy { + match order { + ScanOrder::Serial => PortStrategy::List(list), + ScanOrder::Random => { + list.shuffle(&mut rand::thread_rng()); + PortStrategy::List(list) + } } } + + _list(list.into(), order) } + - pub fn order(&self) -> Vec { + + pub fn iter(&self) -> impl Iterator + use<'_> { match self { - PortStrategy::Manual(ports) => ports.clone(), - PortStrategy::Serial(range) => range.generate(), - PortStrategy::Random(range) => range.generate(), + PortStrategy::List(ports) => { + Either::Right(ports.iter().copied()) + } + PortStrategy::Serial(range) => Either::Left(Either::Right(range.iter())), + PortStrategy::Random(range) => Either::Left(Either::Left(range.iter())), } } } @@ -55,86 +60,96 @@ impl PortStrategy { /// Trait associated with a port strategy. Each PortStrategy must be able /// to generate an order for future port scanning. trait RangeOrder { - fn generate(&self) -> Vec; + fn iter(&self) -> impl Iterator; } /// As the name implies SerialRange will always generate a vector in /// ascending order. #[derive(Debug)] -pub struct SerialRange { - start: u16, - end: u16, -} +pub struct SerialRange(ExclusivePortRange); impl RangeOrder for SerialRange { - fn generate(&self) -> Vec { - (self.start..=self.end).collect() + fn iter(&self) -> impl Iterator { + (self.0.start..self.0.end).map(|x| x as u16) } } /// As the name implies RandomRange will always generate a vector with /// a random order. This vector is built following the LCG algorithm. -#[derive(Debug)] -pub struct RandomRange { - start: u16, - end: u16, +#[derive(Copy, Clone, Debug)] +pub struct ExclusivePortRange { + start: u32, + end: u32, } +impl> From for ExclusivePortRange { + fn from(value: B) -> Self { + let start = match value.start_bound() { + Bound::Included(&inclusive) => inclusive as u32, + Bound::Excluded(&excluded) => excluded as u32 + 1, + Bound::Unbounded => 0, + }; + let end = match value.end_bound() { + Bound::Included(&inclusive) => inclusive as u32 + 1, + Bound::Excluded(&excluded) => excluded as u32, + Bound::Unbounded => 1 << 16, + }; + + Self { start, end } + } +} + +#[derive(Copy, Clone, Debug)] +pub struct RandomRange(ExclusivePortRange); + impl RangeOrder for RandomRange { - // Right now using RangeIterator and generating a range + shuffling the - // vector is pretty much the same. The advantages of it will come once - // we have to generate different ranges for different IPs without storing - // actual vectors. - // - // Another benefit of RangeIterator is that it always generate a range with - // a certain distance between the items in the Array. The chances of having - // port numbers close to each other are pretty slim due to the way the - // algorithm works. - fn generate(&self) -> Vec { - RangeIterator::new(self.start.into(), self.end.into()).collect() + // use blackrock like the original masscan + fn iter(&self) -> impl Iterator { + let range = self.0.end.saturating_sub(self.0.start); + // only ever accessed if self.start < 1 << 16 + let offset = self.0.start as u16; + BlackRockIter::new(range as u64).map(move |x| (x as u16) + offset) } } #[cfg(test)] mod tests { use super::PortStrategy; - use crate::input::{PortRange, ScanOrder}; + use crate::input::ScanOrder; + use itertools::Itertools; #[test] fn serial_strategy_with_range() { - let range = PortRange { start: 1, end: 100 }; - let strategy = PortStrategy::pick(&Some(range), None, ScanOrder::Serial); - let result = strategy.order(); - let expected_range = (1..=100).collect::>(); - assert_eq!(expected_range, result); + let expected_range = 1..=100; + + let strategy = PortStrategy::range(expected_range.clone(), ScanOrder::Serial); + assert!(expected_range.eq(strategy.iter())); } #[test] fn random_strategy_with_range() { - let range = PortRange { start: 1, end: 100 }; - let strategy = PortStrategy::pick(&Some(range), None, ScanOrder::Random); - let mut result = strategy.order(); - let expected_range = (1..=100).collect::>(); - assert_ne!(expected_range, result); - - result.sort_unstable(); - assert_eq!(expected_range, result); + let range = 1..=100; + + let strategy = PortStrategy::range(range.clone(), ScanOrder::Random); + + assert!(range.clone().ne(strategy.iter())); + assert!(range.eq(strategy.iter().sorted())); } #[test] fn serial_strategy_with_ports() { - let strategy = PortStrategy::pick(&None, Some(vec![80, 443]), ScanOrder::Serial); - let result = strategy.order(); - assert_eq!(vec![80, 443], result); + let list = [80, 443]; + let strategy = PortStrategy::list(list, ScanOrder::Serial); + let result = strategy.iter(); + assert!(list.iter().copied().eq(result)); } #[test] fn random_strategy_with_ports() { - let strategy = PortStrategy::pick(&None, Some((1..10).collect()), ScanOrder::Random); - let mut result = strategy.order(); - let expected_range = (1..10).collect::>(); - assert_ne!(expected_range, result); + let expected_range = 1..300; + + let strategy = PortStrategy::list(expected_range.clone().collect_vec(), ScanOrder::Random); - result.sort_unstable(); - assert_eq!(expected_range, result); + assert!(expected_range.clone().ne(strategy.iter())); + assert!(expected_range.eq(strategy.iter().sorted())); } } diff --git a/src/port_strategy/range_iterator.rs b/src/port_strategy/range_iterator.rs deleted file mode 100644 index 84ce97d59..000000000 --- a/src/port_strategy/range_iterator.rs +++ /dev/null @@ -1,133 +0,0 @@ -use gcd::Gcd; -use rand::Rng; -use std::convert::TryInto; - -pub struct RangeIterator { - active: bool, - normalized_end: u32, - normalized_first_pick: u32, - normalized_pick: u32, - actual_start: u32, - step: u32, -} - -/// An iterator that follows the `Linear Congruential Generator` algorithm. -/// -/// For more information: -impl RangeIterator { - /// Receives the start and end of a range and normalize - /// these values before selecting a coprime for the end of the range - /// which will server as the step for the algorithm. - /// - /// For example, the range `1000-2500` will be normalized to `0-1500` - /// before going through the algorithm. - pub fn new(start: u32, end: u32) -> Self { - let normalized_end = end - start + 1; - let step = pick_random_coprime(normalized_end); - - // Randomly choose a number within the range to be the first - // and assign it as a pick. - let mut rng = rand::thread_rng(); - let normalized_first_pick = rng.gen_range(0..normalized_end); - - Self { - active: true, - normalized_end, - step, - normalized_first_pick, - normalized_pick: normalized_first_pick, - actual_start: start, - } - } -} - -impl Iterator for RangeIterator { - type Item = u16; - - // The next step is always bound by the formula: N+1 = (N + STEP) % TOP_OF_THE_RANGE - // It will only stop once we generate a number equal to the first generated number. - fn next(&mut self) -> Option { - if !self.active { - return None; - } - - let current_pick = self.normalized_pick; - let next_pick = (current_pick + self.step) % self.normalized_end; - - // If the next pick is equal to the first pick this means that - // we have iterated through the entire range. - if next_pick == self.normalized_first_pick { - self.active = false; - } - - self.normalized_pick = next_pick; - Some( - (self.actual_start + current_pick) - .try_into() - .expect("Could not convert u32 to u16"), - ) - } -} - -/// The probability that two random integers are coprime to one another -/// works out to be around 61%, given that we can safely pick a random -/// number and test it. Just in case we are having a bad day and we cannot -/// pick a coprime number after 10 tries we just return "end - 1" which -/// is guaranteed to be a coprime, but won't provide ideal randomization. -/// -/// We pick between "lower_range" and "upper_range" since values too close to -/// the boundaries, which in these case are the "start" and "end" arguments -/// would also provide non-ideal randomization as discussed on the paragraph -/// above. -fn pick_random_coprime(end: u32) -> u32 { - let range_boundary = end / 4; - let lower_range = range_boundary; - let upper_range = end - range_boundary; - let mut rng = rand::thread_rng(); - let mut candidate = rng.gen_range(lower_range..upper_range); - - for _ in 0..10 { - if end.gcd(candidate) == 1 { - return candidate; - } - candidate = rng.gen_range(lower_range..upper_range); - } - - end - 1 -} - -#[cfg(test)] -mod tests { - use super::RangeIterator; - - #[test] - fn range_iterator_iterates_through_the_entire_range() { - let result = generate_sorted_range(1, 10); - let expected_range = (1..=10).collect::>(); - assert_eq!(expected_range, result); - - let result = generate_sorted_range(1, 100); - let expected_range = (1..=100).collect::>(); - assert_eq!(expected_range, result); - - let result = generate_sorted_range(1, 1000); - let expected_range = (1..=1000).collect::>(); - assert_eq!(expected_range, result); - - let result = generate_sorted_range(1, 65_535); - let expected_range = (1..=65_535).collect::>(); - assert_eq!(expected_range, result); - - let result = generate_sorted_range(1000, 2000); - let expected_range = (1000..=2000).collect::>(); - assert_eq!(expected_range, result); - } - - fn generate_sorted_range(start: u32, end: u32) -> Vec { - let range = RangeIterator::new(start, end); - let mut result = range.into_iter().collect::>(); - result.sort_unstable(); - - result - } -} diff --git a/src/scanner/mod.rs b/src/scanner/mod.rs index 47418a108..2176ffc66 100644 --- a/src/scanner/mod.rs +++ b/src/scanner/mod.rs @@ -6,39 +6,46 @@ use log::debug; mod socket_iterator; use socket_iterator::SocketIterator; -use async_std::net::TcpStream; -use async_std::prelude::*; -use async_std::{io, net::UdpSocket}; use colored::Colorize; -use futures::stream::FuturesUnordered; use std::collections::BTreeMap; use std::{ collections::HashSet, - net::{IpAddr, Shutdown, SocketAddr}, - num::NonZeroU8, + net::{IpAddr, SocketAddr}, + num::NonZero, time::Duration, }; +use std::net::{Ipv4Addr, Ipv6Addr}; +use std::sync::Arc; +use futures::StreamExt; +use tokio::{io, time}; +use tokio::io::AsyncWriteExt; +use tokio::net::{TcpStream, UdpSocket}; +use tokio_par_stream::FuturesParallelUnordered; -/// The class for the scanner -/// IP is data type IpAddr and is the IP address -/// start & end is where the port scan starts and ends -/// batch_size is how many ports at a time should be scanned -/// Timeout is the time RustScan should wait before declaring a port closed. As datatype Duration. -/// greppable is whether or not RustScan should print things, or wait until the end to print only the ip and open ports. -#[cfg(not(tarpaulin_include))] #[derive(Debug)] -pub struct Scanner { - ips: Vec, +pub struct ScannerInner { + ips: Box<[IpAddr]>, + exclude_ports: Box<[u16]>, + batch_size: u16, timeout: Duration, - tries: NonZeroU8, + tries: NonZero, greppable: bool, port_strategy: PortStrategy, accessible: bool, - exclude_ports: Vec, udp: bool, } +/// The class for the scanner +/// IP is data type IpAddr and is the IP address +/// start & end is where the port scan starts and ends +/// batch_size is how many ports at a time should be scanned +/// Timeout is the time RustScan should wait before declaring a port closed. As datatype Duration. +/// greppable is whether RustScan should print things, or wait until the end to print only the ip and open ports. +#[cfg(not(tarpaulin_include))] +#[derive(Debug)] +pub struct Scanner(Arc); + // Allowing too many arguments for clippy. #[allow(clippy::too_many_arguments)] impl Scanner { @@ -50,42 +57,55 @@ impl Scanner { greppable: bool, port_strategy: PortStrategy, accessible: bool, - exclude_ports: Vec, + exclude_ports: &[u16], udp: bool, ) -> Self { - Self { + let inner = ScannerInner { + ips: Box::from(ips), + exclude_ports: Box::from(exclude_ports), + batch_size, timeout, - tries: NonZeroU8::new(std::cmp::max(tries, 1)).unwrap(), + tries: NonZero::new(tries).unwrap_or(NonZero::::MIN), greppable, port_strategy, - ips: ips.iter().map(ToOwned::to_owned).collect(), + accessible, - exclude_ports, udp, - } + }; + + Self(Arc::new(inner)) + } + + pub async fn run(&self) -> Vec { + self.0.run().await } +} - /// Runs scan_range with chunk sizes +impl ScannerInner { + /// Runs scan_range with chunk sizes /// If you want to run RustScan normally, this is the entry point used /// Returns all open ports as `Vec` - pub async fn run(&self) -> Vec { - let ports: Vec = self + async fn run(self: &Arc) -> Vec { + let ports = self .port_strategy - .order() .iter() - .filter(|&port| !self.exclude_ports.contains(port)) - .copied() - .collect(); + .filter(|port| !self.exclude_ports.contains(port)) + .collect::>(); + let mut socket_iterator: SocketIterator = SocketIterator::new(&self.ips, &ports); let mut open_sockets: Vec = Vec::new(); - let mut ftrs = FuturesUnordered::new(); + let mut ftrs = FuturesParallelUnordered::new(); let mut errors: HashSet = HashSet::new(); let udp_map = get_parsed_data(); - + let scan = |socket| { + let this = Arc::clone(self); + async move { this.scan_socket(socket, udp_map).await } + }; + for _ in 0..self.batch_size { if let Some(socket) = socket_iterator.next() { - ftrs.push(self.scan_socket(socket, udp_map.clone())); + ftrs.push(scan(socket)); } else { break; } @@ -95,11 +115,11 @@ impl Scanner { self.batch_size, self.ips.len(), &ports.len(), - (self.ips.len() * ports.len())); + self.ips.len() * ports.len()); while let Some(result) = ftrs.next().await { if let Some(socket) = socket_iterator.next() { - ftrs.push(self.scan_socket(socket, udp_map.clone())); + ftrs.push(scan(socket)); } match result { @@ -117,10 +137,10 @@ impl Scanner { open_sockets } - /// Given a socket, scan it self.tries times. + /// Given a socket, scan itself. Tries times. /// Turns the address into a SocketAddr /// Deals with the `` type - /// If it experiences error ErrorKind::Other then too many files are open and it Panics! + /// If it experiences error `ErrorKind::Other` then too many files are open and it Panics! /// Else any other error, it returns the error in Result as a string /// If no errors occur, it returns the port number in Result to signify the port is open. /// This function mainly deals with the logic of Results handling. @@ -134,7 +154,7 @@ impl Scanner { async fn scan_socket( &self, socket: SocketAddr, - udp_map: BTreeMap, Vec>, + udp_map: &'static BTreeMap, Vec>, ) -> io::Result { if self.udp { return self.scan_udp_socket(socket, udp_map).await; @@ -143,12 +163,12 @@ impl Scanner { let tries = self.tries.get(); for nr_try in 1..=tries { match self.connect(socket).await { - Ok(tcp_stream) => { + Ok(mut tcp_stream) => { debug!( "Connection was successful, shutting down stream {}", &socket ); - if let Err(e) = tcp_stream.shutdown(Shutdown::Both) { + if let Err(e) = tcp_stream.shutdown().await { debug!("Shutdown stream error {}", &e); } self.fmt_ports(socket); @@ -175,9 +195,9 @@ impl Scanner { async fn scan_udp_socket( &self, socket: SocketAddr, - udp_map: BTreeMap, Vec>, + udp_map: &'static BTreeMap, Vec>, ) -> io::Result { - let mut payload: Vec = Vec::new(); + let mut payload = &[][..]; for (key, value) in udp_map { if key.contains(&socket.port()) { payload = value; @@ -186,7 +206,7 @@ impl Scanner { let tries = self.tries.get(); for _ in 1..=tries { - match self.udp_scan(socket, &payload, self.timeout).await { + match self.udp_scan(socket, payload, self.timeout).await { Ok(true) => return Ok(socket), Ok(false) => continue, Err(e) => return Err(e), @@ -211,12 +231,11 @@ impl Scanner { /// ``` /// async fn connect(&self, socket: SocketAddr) -> io::Result { - let stream = io::timeout( + time::timeout( self.timeout, async move { TcpStream::connect(socket).await }, ) - .await?; - Ok(stream) + .await? } /// Binds to a UDP socket so we can send and receive packets @@ -235,8 +254,8 @@ impl Scanner { /// async fn udp_bind(&self, socket: SocketAddr) -> io::Result { let local_addr = match socket { - SocketAddr::V4(_) => "0.0.0.0:0".parse::().unwrap(), - SocketAddr::V6(_) => "[::]:0".parse::().unwrap(), + SocketAddr::V4(_) => SocketAddr::from((Ipv4Addr::UNSPECIFIED, 0)), + SocketAddr::V6(_) => SocketAddr::from((Ipv6Addr::UNSPECIFIED, 0)), }; UdpSocket::bind(local_addr).await @@ -270,19 +289,15 @@ impl Scanner { udp_socket.connect(socket).await?; udp_socket.send(payload).await?; - match io::timeout(wait, udp_socket.recv(&mut buf)).await { - Ok(size) => { + match time::timeout(wait, udp_socket.recv(&mut buf)).await { + Ok(Ok(size)) => { debug!("Received {} bytes", size); self.fmt_ports(socket); Ok(true) } - Err(e) => { - if e.kind() == io::ErrorKind::TimedOut { - Ok(false) - } else { - Err(e) - } - } + // timeout + Err(_) => Ok(false), + Ok(Err(e)) => Err(e), } } Err(e) => { @@ -308,18 +323,18 @@ impl Scanner { mod tests { use super::*; use crate::input::{PortRange, ScanOrder}; - use async_std::task::block_on; + use std::{net::IpAddr, time::Duration}; - #[test] - fn scanner_runs() { + #[tokio::test] + async fn scanner_runs() { // Makes sure the program still runs and doesn't panic - let addrs = vec!["127.0.0.1".parse::().unwrap()]; + let addrs = ["127.0.0.1".parse::().unwrap()]; let range = PortRange { start: 1, end: 1_000, }; - let strategy = PortStrategy::pick(&Some(range), None, ScanOrder::Random); + let strategy = PortStrategy::range(range, ScanOrder::Random); let scanner = Scanner::new( &addrs, 10, @@ -328,22 +343,22 @@ mod tests { true, strategy, true, - vec![9000], + &[9000], false, ); - block_on(scanner.run()); + scanner.run().await; // if the scan fails, it wouldn't be able to assert_eq! as it panicked! assert_eq!(1, 1); } - #[test] - fn ipv6_scanner_runs() { + #[tokio::test] + async fn ipv6_scanner_runs() { // Makes sure the program still runs and doesn't panic - let addrs = vec!["::1".parse::().unwrap()]; + let addrs = ["::1".parse::().unwrap()]; let range = PortRange { start: 1, end: 1_000, }; - let strategy = PortStrategy::pick(&Some(range), None, ScanOrder::Random); + let strategy = PortStrategy::range(range, ScanOrder::Random); let scanner = Scanner::new( &addrs, 10, @@ -352,21 +367,21 @@ mod tests { true, strategy, true, - vec![9000], + &[9000], false, ); - block_on(scanner.run()); + scanner.run().await; // if the scan fails, it wouldn't be able to assert_eq! as it panicked! assert_eq!(1, 1); } - #[test] - fn quad_zero_scanner_runs() { - let addrs = vec!["0.0.0.0".parse::().unwrap()]; + #[tokio::test] + async fn quad_zero_scanner_runs() { + let addrs = ["0.0.0.0".parse::().unwrap()]; let range = PortRange { start: 1, end: 1_000, }; - let strategy = PortStrategy::pick(&Some(range), None, ScanOrder::Random); + let strategy = PortStrategy::range(range, ScanOrder::Random); let scanner = Scanner::new( &addrs, 10, @@ -375,20 +390,20 @@ mod tests { true, strategy, true, - vec![9000], + &[9000], false, ); - block_on(scanner.run()); + scanner.run().await; assert_eq!(1, 1); } - #[test] - fn google_dns_runs() { - let addrs = vec!["8.8.8.8".parse::().unwrap()]; + #[tokio::test] + async fn google_dns_runs() { + let addrs = ["8.8.8.8".parse::().unwrap()]; let range = PortRange { start: 400, end: 445, }; - let strategy = PortStrategy::pick(&Some(range), None, ScanOrder::Random); + let strategy = PortStrategy::range(range, ScanOrder::Random); let scanner = Scanner::new( &addrs, 10, @@ -397,23 +412,23 @@ mod tests { true, strategy, true, - vec![9000], + &[9000], false, ); - block_on(scanner.run()); + scanner.run().await; assert_eq!(1, 1); } - #[test] - fn infer_ulimit_lowering_no_panic() { - // Test behaviour on MacOS where ulimit is not automatically lowered - let addrs = vec!["8.8.8.8".parse::().unwrap()]; + #[tokio::test] + async fn infer_ulimit_lowering_no_panic() { + // Test behaviour on macOS where ulimit is not automatically lowered + let addrs = ["8.8.8.8".parse::().unwrap()]; // mac should have this automatically scaled down let range = PortRange { start: 400, end: 600, }; - let strategy = PortStrategy::pick(&Some(range), None, ScanOrder::Random); + let strategy = PortStrategy::range(range, ScanOrder::Random); let scanner = Scanner::new( &addrs, 10, @@ -422,22 +437,22 @@ mod tests { true, strategy, true, - vec![9000], + &[9000], false, ); - block_on(scanner.run()); + scanner.run().await; assert_eq!(1, 1); } - #[test] - fn udp_scan_runs() { + #[tokio::test] + async fn udp_scan_runs() { // Makes sure the program still runs and doesn't panic - let addrs = vec!["127.0.0.1".parse::().unwrap()]; + let addrs = ["127.0.0.1".parse::().unwrap()]; let range = PortRange { start: 1, end: 1_000, }; - let strategy = PortStrategy::pick(&Some(range), None, ScanOrder::Random); + let strategy = PortStrategy::range(range, ScanOrder::Random); let scanner = Scanner::new( &addrs, 10, @@ -446,22 +461,22 @@ mod tests { true, strategy, true, - vec![9000], + &[9000], true, ); - block_on(scanner.run()); + scanner.run().await; // if the scan fails, it wouldn't be able to assert_eq! as it panicked! assert_eq!(1, 1); } - #[test] - fn udp_ipv6_runs() { + #[tokio::test] + async fn udp_ipv6_runs() { // Makes sure the program still runs and doesn't panic - let addrs = vec!["::1".parse::().unwrap()]; + let addrs = ["::1".parse::().unwrap()]; let range = PortRange { start: 1, end: 1_000, }; - let strategy = PortStrategy::pick(&Some(range), None, ScanOrder::Random); + let strategy = PortStrategy::range(range, ScanOrder::Random); let scanner = Scanner::new( &addrs, 10, @@ -470,21 +485,21 @@ mod tests { true, strategy, true, - vec![9000], + &[9000], true, ); - block_on(scanner.run()); + scanner.run().await; // if the scan fails, it wouldn't be able to assert_eq! as it panicked! assert_eq!(1, 1); } - #[test] - fn udp_quad_zero_scanner_runs() { - let addrs = vec!["0.0.0.0".parse::().unwrap()]; + #[tokio::test] + async fn udp_quad_zero_scanner_runs() { + let addrs = ["0.0.0.0".parse::().unwrap()]; let range = PortRange { start: 1, end: 1_000, }; - let strategy = PortStrategy::pick(&Some(range), None, ScanOrder::Random); + let strategy = PortStrategy::range(range, ScanOrder::Random); let scanner = Scanner::new( &addrs, 10, @@ -493,20 +508,20 @@ mod tests { true, strategy, true, - vec![9000], + &[9000], true, ); - block_on(scanner.run()); + scanner.run().await; assert_eq!(1, 1); } - #[test] - fn udp_google_dns_runs() { - let addrs = vec!["8.8.8.8".parse::().unwrap()]; + #[tokio::test] + async fn udp_google_dns_runs() { + let addrs = ["8.8.8.8".parse::().unwrap()]; let range = PortRange { start: 100, end: 150, }; - let strategy = PortStrategy::pick(&Some(range), None, ScanOrder::Random); + let strategy = PortStrategy::range(range, ScanOrder::Random); let scanner = Scanner::new( &addrs, 10, @@ -515,10 +530,10 @@ mod tests { true, strategy, true, - vec![9000], + &[9000], true, ); - block_on(scanner.run()); + scanner.run().await; assert_eq!(1, 1); } } diff --git a/src/scanner/socket_iterator.rs b/src/scanner/socket_iterator.rs index a7b602794..514ec4d10 100644 --- a/src/scanner/socket_iterator.rs +++ b/src/scanner/socket_iterator.rs @@ -1,3 +1,4 @@ +use std::iter::Copied; use itertools::{iproduct, Product}; use std::net::{IpAddr, SocketAddr}; @@ -11,7 +12,7 @@ pub struct SocketIterator<'s> { // ("hold the port, go through all the IPs, then advance the port..."). // See also the comments in the iterator implementation for an example. product_it: - Product>, Box>>, + Product>, Copied>>, } /// An iterator that receives a slice of IPs and ports and returns a Socket @@ -21,8 +22,8 @@ pub struct SocketIterator<'s> { /// generating a vector containing all these combinations. impl<'s> SocketIterator<'s> { pub fn new(ips: &'s [IpAddr], ports: &'s [u16]) -> Self { - let ports_it = Box::new(ports.iter()); - let ips_it = Box::new(ips.iter()); + let ports_it = ports.iter().copied(); + let ips_it = ips.iter().copied(); Self { product_it: iproduct!(ports_it, ips_it), } @@ -46,7 +47,7 @@ impl Iterator for SocketIterator<'_> { fn next(&mut self) -> Option { self.product_it .next() - .map(|(port, ip)| SocketAddr::new(*ip, *port)) + .map(|(port, ip)| SocketAddr::new(ip, port)) } } From 1f82c798c5e62e411a8e86ce0c5f20d8805e795a Mon Sep 17 00:00:00 2001 From: Vrtgs Date: Sat, 11 Jan 2025 17:17:43 +0300 Subject: [PATCH 2/3] fix futures executor --- src/address.rs | 45 ++++++++++++++++----------------------------- src/main.rs | 8 ++++---- 2 files changed, 20 insertions(+), 33 deletions(-) diff --git a/src/address.rs b/src/address.rs index 8656d6ae2..15ca863ef 100644 --- a/src/address.rs +++ b/src/address.rs @@ -5,7 +5,6 @@ use std::net::{IpAddr, SocketAddr}; use std::path::Path; use std::pin::Pin; use std::str::FromStr; -use std::thread; use std::time::Duration; use cidr_utils::cidr::IpCidr; use futures::{FutureExt, StreamExt}; @@ -17,7 +16,21 @@ use tokio::io::AsyncBufReadExt; use crate::input::Opts; use crate::warning; -async fn parse_addresses_inner(input: &Opts) -> Vec { +/// Parses the string(s) into IP addresses. +/// +/// Goes through all possible IP inputs (files or via argparsing). +/// +/// ```rust +/// # use rustscan::input::Opts; +/// # use rustscan::address::parse_addresses; +/// let mut opts = Opts::default(); +/// opts.addresses = vec!["192.168.0.0/30".to_owned()]; +/// +/// let ips = parse_addresses(&opts); +/// ``` +/// +/// Finally, any duplicates are removed to avoid excessive scans. +pub async fn parse_addresses(input: &Opts) -> Vec { let ips = &RefCell::new(Vec::new()); let unresolved_addresses = &RefCell::new(Vec::new()); let backup_resolver = &get_resolver(&input.resolver).await; @@ -39,7 +52,7 @@ async fn parse_addresses_inner(input: &Opts) -> Vec { futures::stream::iter(unresolved_addresses.take()).for_each_concurrent(Some(4), |file_path| async move { let file_path = Path::new(file_path); - if !tokio::fs::metadata(file_path).await.map_or(false, |m| m.is_file()) { + if !tokio::fs::metadata(file_path).await.is_ok_and(|m| m.is_file()) { warning!( format!("Host {file_path:?} could not be resolved."), input.greppable, @@ -67,32 +80,6 @@ async fn parse_addresses_inner(input: &Opts) -> Vec { ips } -/// Parses the string(s) into IP addresses. -/// -/// Goes through all possible IP inputs (files or via argparsing). -/// -/// ```rust -/// # use rustscan::input::Opts; -/// # use rustscan::address::parse_addresses; -/// let mut opts = Opts::default(); -/// opts.addresses = vec!["192.168.0.0/30".to_owned()]; -/// -/// let ips = parse_addresses(&opts); -/// ``` -/// -/// Finally, any duplicates are removed to avoid excessive scans. -pub fn parse_addresses(input: &Opts) -> Vec { - thread::scope(|s| { - s.spawn(|| { - tokio::runtime::Runtime::new() - .unwrap() - .block_on(parse_addresses_inner(input)) - }) - .join() - .unwrap_or_else(|panic| std::panic::resume_unwind(panic)) - }) -} - /// Given a string, parse it as a host, IP address, or CIDR. /// /// This allows us to pass files as hosts or cidr or IPs easily diff --git a/src/main.rs b/src/main.rs index fa848eb2d..831783f80 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,7 +10,6 @@ use rustscan::scripts::{init_scripts, Script, ScriptFile}; use rustscan::{detail, funny_opening, output, warning}; use colorful::{Color, Colorful}; -use futures::executor::block_on; use std::collections::HashMap; use std::net::IpAddr; use std::string::ToString; @@ -34,7 +33,8 @@ extern crate log; #[allow(clippy::too_many_lines)] /// Faster Nmap scanning with Rust /// If you're looking for the actual scanning, check out the module Scanner -fn main() { +#[tokio::main] +async fn main() { #[cfg(not(unix))] let _ = ansi_term::enable_ansi_support(); @@ -66,7 +66,7 @@ fn main() { print_opening(&opts); } - let ips: Vec = parse_addresses(&opts); + let ips: Vec = parse_addresses(&opts).await; if ips.is_empty() { warning!( @@ -119,7 +119,7 @@ fn main() { debug!("Scanner finished building: {:?}", scanner); let mut portscan_bench = NamedTimer::start("Portscan"); - let scan_result = block_on(scanner.run()); + let scan_result = scanner.run().await; portscan_bench.end(); benchmarks.push(portscan_bench); From 1d07aaeeb04ba9ad486a886203e9f97592c71f4e Mon Sep 17 00:00:00 2001 From: Vrtgs Date: Sat, 11 Jan 2025 17:22:10 +0300 Subject: [PATCH 3/3] fix tests --- Cargo.lock | 37 +++++++++++++++-------------------- Cargo.toml | 10 +++++----- src/address.rs | 52 +++++++++++++++++++++++++------------------------- 3 files changed, 46 insertions(+), 53 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c58e4d22a..fef86fcc5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -246,9 +246,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.23" +version = "4.5.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84" +checksum = "a8eb5e908ef3a6efbe1ed62520fb7287959888c88485abe072543190ecc66783" dependencies = [ "clap_builder", "clap_derive", @@ -256,9 +256,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.23" +version = "4.5.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838" +checksum = "96b01801b5fc6a0a232407abc821660c9c6d25a1cafc0d4f85f29fb8d9afc121" dependencies = [ "anstream", "anstyle", @@ -269,9 +269,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.18" +version = "4.5.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" +checksum = "54b755194d6389280185988721fffba69495eed5ee9feeee9a599b53db80318c" dependencies = [ "heck", "proc-macro2", @@ -293,11 +293,10 @@ checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "colored" -version = "2.2.0" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c" +checksum = "fde0e0ec90c9dfb3b4b1a0891a7dcd0e2bffde2f7efed5fe7c9bb00e5bfb915e" dependencies = [ - "lazy_static", "windows-sys 0.59.0", ] @@ -916,9 +915,9 @@ dependencies = [ [[package]] name = "itertools" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" dependencies = [ "either", ] @@ -939,12 +938,6 @@ dependencies = [ "wasm-bindgen", ] -[[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" @@ -1444,7 +1437,7 @@ dependencies = [ "env_logger", "futures", "hickory-resolver", - "itertools 0.13.0", + "itertools 0.14.0", "log", "parameterized", "rand 0.8.5", @@ -1688,9 +1681,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.42.0" +version = "1.43.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551" +checksum = "3d61fa4ffa3de412bfea335c6ecff681de2b609ba3c77ef3e00e521813a9ed9e" dependencies = [ "backtrace", "bytes", @@ -1706,9 +1699,9 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 56d987dcf..16892fcf2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "rustscan" version = "2.3.0" authors = ["Autumn "] -edition = "2018" +edition = "2021" description = "Faster Nmap Scanning with Rust" homepage = "https://github.com/rustscan/rustscan" repository = "https://github.com/rustscan/rustscan" @@ -17,11 +17,11 @@ exclude = [ ] [dependencies] -tokio = { version = "1.42.0", features = ["full"] } +tokio = { version = "1.43.0", features = ["full"] } tokio-par-stream = "0.1.1" blackrock2 = "0.1.0" -clap = { version = "4.5.13", features = ["derive", "wrap_help"] } -colored = "2.2.0" +clap = { version = "4.5.26", features = ["derive", "wrap_help"] } +colored = "3.0.0" futures = "0.3" rlimit = "0.10.2" log = "0.4.22" @@ -34,7 +34,7 @@ toml = "0.8.19" serde = "1.0.124" serde_derive = "1.0.116" cidr-utils = "0.6.1" -itertools = "0.13.0" +itertools = "0.14.0" hickory-resolver = { version = "0.24.2", features = ["dns-over-rustls"] } anyhow = "1.0.40" text_placeholder = { version = "0.5", features = ["struct_context"] } diff --git a/src/address.rs b/src/address.rs index 15ca863ef..793f8b402 100644 --- a/src/address.rs +++ b/src/address.rs @@ -208,14 +208,14 @@ mod tests { use super::{get_resolver, parse_addresses, Opts}; use std::net::Ipv4Addr; - #[test] - fn parse_correct_addresses() { + #[tokio::test] + async fn parse_correct_addresses() { let opts = Opts { addresses: vec!["127.0.0.1".to_owned(), "192.168.0.0/30".to_owned()], ..Default::default() }; - let ips = parse_addresses(&opts); + let ips = parse_addresses(&opts).await; assert_eq!( ips, @@ -229,88 +229,88 @@ mod tests { ); } - #[test] - fn parse_correct_host_addresses() { + #[tokio::test] + async fn parse_correct_host_addresses() { let opts = Opts { addresses: vec!["google.com".to_owned()], ..Default::default() }; - let ips = parse_addresses(&opts); + let ips = parse_addresses(&opts).await; - assert_eq!(ips.len(), 1); + assert!(!ips.is_empty()); } - #[test] - fn parse_correct_and_incorrect_addresses() { + #[tokio::test] + async fn parse_correct_and_incorrect_addresses() { let opts = Opts { addresses: vec!["127.0.0.1".to_owned(), "im_wrong".to_owned()], ..Default::default() }; - let ips = parse_addresses(&opts); + let ips = parse_addresses(&opts).await; assert_eq!(ips, [Ipv4Addr::new(127, 0, 0, 1),]); } - #[test] - fn parse_incorrect_addresses() { + #[tokio::test] + async fn parse_incorrect_addresses() { let opts = Opts { addresses: vec!["im_wrong".to_owned(), "300.10.1.1".to_owned()], ..Default::default() }; - let ips = parse_addresses(&opts); + let ips = parse_addresses(&opts).await; assert!(ips.is_empty()); } - #[test] - fn parse_hosts_file_and_incorrect_hosts() { + #[tokio::test] + async fn parse_hosts_file_and_incorrect_hosts() { // Host file contains IP, Hosts, incorrect IPs, incorrect hosts let opts = Opts { addresses: vec!["fixtures/hosts.txt".to_owned()], ..Default::default() }; - let ips = parse_addresses(&opts); + let ips = parse_addresses(&opts).await; - assert_eq!(ips.len(), 3); + assert!(ips.len() >= 3); } - #[test] - fn parse_empty_hosts_file() { + #[tokio::test] + async fn parse_empty_hosts_file() { // Host file contains IP, Hosts, incorrect IPs, incorrect hosts let opts = Opts { addresses: vec!["fixtures/empty_hosts.txt".to_owned()], ..Default::default() }; - let ips = parse_addresses(&opts); + let ips = parse_addresses(&opts).await; assert_eq!(ips.len(), 0); } - #[test] - fn parse_naughty_host_file() { + #[tokio::test] + async fn parse_naughty_host_file() { // Host file contains IP, Hosts, incorrect IPs, incorrect hosts let opts = Opts { addresses: vec!["fixtures/naughty_string.txt".to_owned()], ..Default::default() }; - let ips = parse_addresses(&opts); + let ips = parse_addresses(&opts).await; assert_eq!(ips.len(), 0); } - #[test] - fn parse_duplicate_cidrs() { + #[tokio::test] + async fn parse_duplicate_cidrs() { let opts = Opts { addresses: vec!["79.98.104.0/21".to_owned(), "79.98.104.0/24".to_owned()], ..Default::default() }; - let ips = parse_addresses(&opts); + let ips = parse_addresses(&opts).await; assert_eq!(ips.len(), 2_048); }