diff --git a/Cargo.lock b/Cargo.lock index d28c434fe..a392c2f88 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,21 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 - -[[package]] -name = "addr2line" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +version = 4 [[package]] name = "ahash" @@ -98,151 +83,9 @@ 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" -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 2.1.0", - "futures-lite 2.3.0", - "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 2.3.3", - "async-lock 3.4.0", - "blocking", - "futures-lite 2.3.0", - "once_cell", -] - -[[package]] -name = "async-io" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" -dependencies = [ - "async-lock 2.8.0", - "autocfg", - "cfg-if", - "concurrent-queue", - "futures-lite 1.13.0", - "log", - "parking", - "polling 2.8.0", - "rustix 0.37.27", - "slab", - "socket2 0.4.10", - "waker-fn", -] - -[[package]] -name = "async-io" -version = "2.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d6baa8f0178795da0e71bc42c9e5d13261aac7ee549853162e66a241ba17964" -dependencies = [ - "async-lock 3.4.0", - "cfg-if", - "concurrent-queue", - "futures-io", - "futures-lite 2.3.0", - "parking", - "polling 3.7.2", - "rustix 0.38.34", - "slab", - "tracing", - "windows-sys 0.52.0", -] - -[[package]] -name = "async-lock" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" -dependencies = [ - "event-listener 2.5.3", -] - -[[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.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d" -dependencies = [ - "async-channel 1.9.0", - "async-global-executor", - "async-io 1.13.0", - "async-lock 2.8.0", - "crossbeam-utils", - "futures-channel", - "futures-core", - "futures-io", - "futures-lite 1.13.0", - "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" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" [[package]] name = "async-trait" @@ -255,45 +98,18 @@ dependencies = [ "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" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" -[[package]] -name = "backtrace" -version = "0.3.73" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] - [[package]] name = "base64" version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - [[package]] name = "bitflags" version = "2.6.0" @@ -301,24 +117,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] -name = "blocking" -version = "1.6.1" +name = "blackrock2" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" +checksum = "1406c0e46d5fec228ee0f9e62cdf5f6f9c889fb2cadd87326639990140e1dd7f" dependencies = [ - "async-channel 2.3.1", - "async-task", - "futures-io", - "futures-lite 2.3.0", - "piper", + "rand 0.9.2", ] -[[package]] -name = "bumpalo" -version = "3.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" - [[package]] name = "bytes" version = "1.6.0" @@ -403,12 +209,11 @@ checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" [[package]] name = "colored" -version = "2.1.0" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" +checksum = "fde0e0ec90c9dfb3b4b1a0891a7dcd0e2bffde2f7efed5fe7c9bb00e5bfb915e" dependencies = [ - "lazy_static", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -417,21 +222,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97af0562545a7d7f3d9222fcf909963bec36dcb502afaacab98c6ffac8da47ce" -[[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 = "crossbeam-utils" -version = "0.8.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" - [[package]] name = "data-encoding" version = "2.6.0" @@ -440,30 +230,41 @@ checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" [[package]] name = "dirs" -version = "5.0.1" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" dependencies = [ "dirs-sys", ] [[package]] name = "dirs-sys" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.48.0", + "windows-sys 0.61.2", +] + +[[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" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] name = "enum-as-inner" @@ -516,53 +317,17 @@ dependencies = [ "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", -] - -[[package]] -name = "fastrand" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" -dependencies = [ - "instant", -] - [[package]] name = "fastrand" -version = "2.1.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "form_urlencoded" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" dependencies = [ "percent-encoding", ] @@ -584,9 +349,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", @@ -594,9 +359,9 @@ 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" @@ -611,32 +376,17 @@ 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 = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" -dependencies = [ - "fastrand 1.9.0", - "futures-core", - "futures-io", - "memchr", - "parking", - "pin-project-lite", - "waker-fn", -] +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-lite" -version = "2.3.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" +checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" dependencies = [ - "fastrand 2.1.0", + "fastrand", "futures-core", "futures-io", "parking", @@ -645,9 +395,9 @@ dependencies = [ [[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", @@ -656,21 +406,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", @@ -702,21 +452,15 @@ dependencies = [ ] [[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.2.6" +name = "getrandom" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ - "futures-channel", - "futures-core", - "js-sys", - "wasm-bindgen", + "cfg-if", + "libc", + "r-efi", + "wasip2", ] [[package]] @@ -736,9 +480,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.5" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" [[package]] name = "heck" @@ -752,23 +496,11 @@ 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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" - [[package]] name = "hickory-proto" -version = "0.24.1" +version = "0.24.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07698b8420e2f0d6447a436ba999ec85d8fbf2a398bbd737b82cac4a2e96e512" +checksum = "92652067c9ce6f66ce53cc38d1169daa36e6e7eb7dd3b63b5103bd9d97117248" dependencies = [ "async-trait", "cfg-if", @@ -777,13 +509,13 @@ dependencies = [ "futures-channel", "futures-io", "futures-util", - "idna 0.4.0", + "idna", "ipnet", "once_cell", - "rand", + "rand 0.8.5", "rustls", "rustls-pemfile", - "thiserror", + "thiserror 1.0.61", "tinyvec", "tokio", "tokio-rustls", @@ -793,9 +525,9 @@ dependencies = [ [[package]] name = "hickory-resolver" -version = "0.24.1" +version = "0.24.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28757f23aa75c98f254cf0405e6d8c25b831b32921b050a66692427679b1f243" +checksum = "cbb117a1ca520e111743ab2f6688eddee69db4e0ea242545a604dce8a66fd22e" dependencies = [ "cfg-if", "futures-util", @@ -804,11 +536,11 @@ dependencies = [ "lru-cache", "once_cell", "parking_lot", - "rand", + "rand 0.8.5", "resolv-conf", "rustls", "smallvec", - "thiserror", + "thiserror 1.0.61", "tokio", "tokio-rustls", "tracing", @@ -832,63 +564,125 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] -name = "idna" -version = "0.4.0" +name = "icu_collections" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", ] [[package]] -name = "idna" -version = "0.5.0" +name = "icu_locale_core" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", ] [[package]] -name = "indexmap" -version = "1.9.3" +name = "icu_normalizer" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" dependencies = [ - "autocfg", - "hashbrown 0.12.3", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", ] [[package]] -name = "indexmap" -version = "2.2.6" +name = "icu_normalizer_data" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" + +[[package]] +name = "icu_properties" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" dependencies = [ - "equivalent", - "hashbrown 0.14.5", + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", ] [[package]] -name = "instant" -version = "0.1.13" +name = "icu_properties_data" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" + +[[package]] +name = "icu_provider" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" dependencies = [ - "cfg-if", + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", ] [[package]] -name = "io-lifetimes" -version = "1.0.11" +name = "idna" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" dependencies = [ - "hermit-abi 0.3.9", - "libc", - "windows-sys 0.48.0", + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", +] + +[[package]] +name = "indexmap" +version = "2.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" +dependencies = [ + "equivalent", + "hashbrown 0.16.1", ] [[package]] @@ -917,9 +711,9 @@ checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" [[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", ] @@ -930,35 +724,11 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" -[[package]] -name = "js-sys" -version = "0.3.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" -dependencies = [ - "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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" - [[package]] name = "libc" -version = "0.2.155" +version = "0.2.178" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" [[package]] name = "libredox" @@ -966,7 +736,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.6.0", + "bitflags", "libc", ] @@ -978,15 +748,15 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "linux-raw-sys" -version = "0.3.8" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] -name = "linux-raw-sys" -version = "0.4.14" +name = "litemap" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" [[package]] name = "lock_api" @@ -1000,12 +770,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.22" +version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" -dependencies = [ - "value-bag", -] +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" [[package]] name = "lru-cache" @@ -1028,24 +795,15 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" -[[package]] -name = "miniz_oxide" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" -dependencies = [ - "adler", -] - [[package]] name = "mio" -version = "0.8.11" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" dependencies = [ "libc", "wasi", - "windows-sys 0.48.0", + "windows-sys 0.61.2", ] [[package]] @@ -1076,30 +834,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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "081b846d1d56ddfc18fdf1a922e4f6e07a11768ea1b92dec44e42b72712ccfce" -dependencies = [ - "memchr", -] - [[package]] name = "once_cell" -version = "1.19.0" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "option-ext" @@ -1130,9 +869,9 @@ dependencies = [ [[package]] name = "parking" -version = "2.2.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" @@ -1159,9 +898,9 @@ dependencies = [ [[package]] name = "percent-encoding" -version = "2.3.1" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pin-project-lite" @@ -1176,45 +915,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] -name = "piper" -version = "0.2.3" +name = "potential_utf" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae1d5c74c9876f070d3e8fd503d748c7d974c3e48da8f41350fa5222ef9b4391" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" dependencies = [ - "atomic-waker", - "fastrand 2.1.0", - "futures-io", -] - -[[package]] -name = "polling" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" -dependencies = [ - "autocfg", - "bitflags 1.3.2", - "cfg-if", - "concurrent-queue", - "libc", - "log", - "pin-project-lite", - "windows-sys 0.48.0", -] - -[[package]] -name = "polling" -version = "3.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3ed00ed3fbf728b5816498ecd316d1716eecaced9c0c8d2c5a6740ca214985b" -dependencies = [ - "cfg-if", - "concurrent-queue", - "hermit-abi 0.4.0", - "pin-project-lite", - "rustix 0.38.34", - "tracing", - "windows-sys 0.52.0", + "zerovec", ] [[package]] @@ -1225,9 +931,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" dependencies = [ "unicode-ident", ] @@ -1247,6 +953,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + [[package]] name = "rand" version = "0.8.5" @@ -1254,18 +966,38 @@ 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.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.3", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", ] [[package]] name = "rand_chacha" -version = "0.3.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.9.3", ] [[package]] @@ -1274,7 +1006,16 @@ 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.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom 0.3.4", ] [[package]] @@ -1283,18 +1024,18 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd" dependencies = [ - "bitflags 2.6.0", + "bitflags", ] [[package]] name = "redox_users" -version = "0.4.5" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" +checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" dependencies = [ - "getrandom", + "getrandom 0.2.15", "libredox", - "thiserror", + "thiserror 2.0.17", ] [[package]] @@ -1344,7 +1085,7 @@ checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", "cfg-if", - "getrandom", + "getrandom 0.2.15", "libc", "spin", "untrusted", @@ -1353,31 +1094,11 @@ dependencies = [ [[package]] name = "rlimit" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3560f70f30a0f16d11d01ed078a07740fe6b489667abc7c7b029155d9f21c3d8" -dependencies = [ - "libc", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.24" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" - -[[package]] -name = "rustix" -version = "0.37.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2" +checksum = "7043b63bd0cd1aaa628e476b80e6d4023a3b50eb32789f2728908107bd0c793a" dependencies = [ - "bitflags 1.3.2", - "errno", - "io-lifetimes", "libc", - "linux-raw-sys 0.3.8", - "windows-sys 0.48.0", ] [[package]] @@ -1386,10 +1107,10 @@ version = "0.38.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ - "bitflags 2.6.0", + "bitflags", "errno", "libc", - "linux-raw-sys 0.4.14", + "linux-raw-sys", "windows-sys 0.52.0", ] @@ -1431,25 +1152,28 @@ dependencies = [ "ansi_term", "anstream", "anyhow", - "async-std", + "blackrock2", "cidr-utils", "clap", "colored", "colorful", "dirs", + "either", "env_logger", - "futures", + "futures-lite", + "futures-util", "gcd", "hickory-resolver", "itertools", "log", "parameterized", - "rand", + "rand 0.9.2", "rlimit", "serde", - "serde_derive", "subprocess", "text_placeholder", + "tokio", + "tokio-par-stream", "toml", "wait-timeout", ] @@ -1509,9 +1233,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.6" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" dependencies = [ "serde", ] @@ -1533,22 +1257,22 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "socket2" -version = "0.4.10" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" dependencies = [ "libc", - "winapi", + "windows-sys 0.52.0", ] [[package]] name = "socket2" -version = "0.5.7" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.60.2", ] [[package]] @@ -1557,6 +1281,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.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + [[package]] name = "strsim" version = "0.11.1" @@ -1575,22 +1305,33 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.69" +version = "2.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "201fcda3845c23e8212cd466bfebf0bd20694490fc0356ae8e428e0824a915a6" +checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "terminal_size" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" dependencies = [ - "rustix 0.38.34", + "rustix", "windows-sys 0.48.0", ] @@ -1611,7 +1352,16 @@ version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" dependencies = [ - "thiserror-impl", + "thiserror-impl 1.0.61", +] + +[[package]] +name = "thiserror" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +dependencies = [ + "thiserror-impl 2.0.17", ] [[package]] @@ -1625,6 +1375,27 @@ dependencies = [ "syn", ] +[[package]] +name = "thiserror-impl" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tinystr" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +dependencies = [ + "displaydoc", + "zerovec", +] + [[package]] name = "tinyvec" version = "1.7.0" @@ -1642,18 +1413,39 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.38.0" +version = "1.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" +checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" dependencies = [ - "backtrace", "bytes", "libc", "mio", - "num_cpus", "pin-project-lite", - "socket2 0.5.7", - "windows-sys 0.48.0", + "socket2 0.6.1", + "tokio-macros", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-macros" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" +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]] @@ -1668,9 +1460,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.14" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f49eb2ab21d2f26bd6db7bf383edc527a7ebaee412d17af4d40fdccd442f335" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" dependencies = [ "serde", "serde_spanned", @@ -1680,26 +1472,33 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.6" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.22.14" +version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f21c7aaf97f1bd9ca9d4f9e73b0a6c74bd5afef56f2bc931943a6e1c37e04e38" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ - "indexmap 2.2.6", + "indexmap 2.12.1", "serde", "serde_spanned", "toml_datetime", + "toml_write", "winnow", ] +[[package]] +name = "toml_write" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" + [[package]] name = "tracing" version = "0.1.40" @@ -1713,9 +1512,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.27" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", @@ -1731,27 +1530,12 @@ 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" 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", -] - [[package]] name = "untrusted" version = "0.9.0" @@ -1760,26 +1544,27 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.2" +version = "2.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" +checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" dependencies = [ "form_urlencoded", - "idna 0.5.0", + "idna", "percent-encoding", + "serde", ] [[package]] -name = "utf8parse" -version = "0.2.2" +name = "utf8_iter" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] -name = "value-bag" -version = "1.9.0" +name = "utf8parse" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a84c137d37ab0142f0f2ddfe332651fdbf252e7b7dbb4e67b6c1f1b2e925101" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "version_check" @@ -1796,12 +1581,6 @@ dependencies = [ "libc", ] -[[package]] -name = "waker-fn" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7" - [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -1809,79 +1588,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] -name = "wasm-bindgen" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" -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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" - -[[package]] -name = "web-sys" -version = "0.3.69" +name = "wasip2" +version = "1.0.1+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" dependencies = [ - "js-sys", - "wasm-bindgen", + "wit-bindgen", ] [[package]] @@ -1912,6 +1624,12 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + [[package]] name = "windows-sys" version = "0.48.0" @@ -1930,6 +1648,24 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-targets" version = "0.48.5" @@ -1954,13 +1690,30 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", + "windows_i686_gnullvm 0.52.6", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" @@ -1973,6 +1726,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" @@ -1985,6 +1744,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + [[package]] name = "windows_i686_gnu" version = "0.48.5" @@ -1997,12 +1762,24 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + [[package]] name = "windows_i686_msvc" version = "0.48.5" @@ -2015,6 +1792,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" @@ -2027,6 +1810,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" @@ -2039,6 +1828,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" @@ -2051,11 +1846,17 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + [[package]] name = "winnow" -version = "0.6.13" +version = "0.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59b5e5f6c299a3c7890b876a2a587f3115162487e704907d9b6cd29473052ba1" +checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" dependencies = [ "memchr", ] @@ -2070,6 +1871,41 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "wit-bindgen" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" + +[[package]] +name = "writeable" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" + +[[package]] +name = "yoke" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + [[package]] name = "zerocopy" version = "0.7.35" @@ -2089,3 +1925,57 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerotrie" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/Cargo.toml b/Cargo.toml index 2e9b69bb3..547fee49d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,28 +17,31 @@ exclude = [ ] [dependencies] +tokio = { version = "1.48.0", features = ["rt-multi-thread", "net", "fs", "macros"] } +tokio-par-stream = "0.1.1" clap = { version = "4.5.9", features = ["derive", "wrap_help"] } -colored = "2.1.0" -async-std = "1.7.0" -futures = "0.3" -rlimit = "0.10.1" -log = "0.4.22" +colored = "3.0.0" +futures-lite = "2.6.1" +futures-util = "0.3.31" +rlimit = "0.10.2" +log = "0.4.29" env_logger = "0.11.3" anstream = "=0.6.14" -dirs = "5.0.1" +dirs = "6.0.0" gcd = "2.0.1" -rand = "0.8.5" +rand = "0.9.2" colorful = "0.2.1" ansi_term = "0.12.1" -toml = "0.8.14" -serde = "1.0.124" -serde_derive = "1.0.116" +toml = "0.8.23" +serde = { version = "1.0.204", features = ["derive"] } cidr-utils = "0.6.1" -itertools = "0.13.0" -hickory-resolver = { version = "0.24.0", features = ["dns-over-rustls"] } -anyhow = "1.0.40" +itertools = "0.14.0" +hickory-resolver = { version = "0.24.4", features = ["dns-over-rustls"] } +anyhow = "1.0.100" subprocess = "0.2.6" text_placeholder = { version = "0.5", features = ["struct_context"] } +either = "1.15.0" +blackrock2 = "0.1.2" [dev-dependencies] parameterized = "2.0.0" diff --git a/src/address.rs b/src/address.rs index 762f86541..de9cccba1 100644 --- a/src/address.rs +++ b/src/address.rs @@ -1,17 +1,23 @@ //! Provides functions to parse input IP addresses, CIDRs or files. -use std::fs::{self, File}; -use std::io::{prelude::*, BufReader}; -use std::net::{IpAddr, SocketAddr, ToSocketAddrs}; -use std::path::Path; + +use std::borrow::Cow; +use std::iter; +use std::net::{IpAddr, SocketAddr}; +use std::pin::Pin; use std::str::FromStr; use cidr_utils::cidr::IpCidr; +use either::Either; +use futures_lite::{stream, Stream}; +use futures_util::StreamExt as _; use hickory_resolver::{ config::{NameServerConfig, Protocol, ResolverConfig, ResolverOpts}, - Resolver, + TokioAsyncResolver, }; -use log::debug; - +use itertools::Itertools; +use tokio::{fs, io}; +use tokio::fs::File; +use tokio::io::{AsyncBufReadExt, BufReader}; use crate::input::Opts; use crate::warning; @@ -27,46 +33,40 @@ use crate::warning; /// /// let ips = parse_addresses(&opts); /// ``` -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); - } - } - - // If we got to this point this can only be a file path or the wrong input. - for file_path in unresolved_addresses { - let file_path = Path::new(file_path); - - if !file_path.is_file() { - warning!( - format!("Host {file_path:?} could not be resolved."), - input.greppable, - input.accessible - ); - - continue; - } - - if let Ok(x) = read_ips_from_file(file_path, &backup_resolver) { - ips.extend(x); - } else { - warning!( - format!("Host {file_path:?} could not be resolved."), - input.greppable, - input.accessible - ); - } - } +pub async fn parse_addresses(input: &Opts) -> Vec { + let backup_resolver = &get_resolver(&input.resolver).await; + + stream::iter(input.addresses.iter()) + .map(move |address| { + let address = address.as_str(); + async move { + (parse_address(Cow::Borrowed(address), backup_resolver).await, address) + } + }) + .buffer_unordered(10) + .map(|(adresses, addr)| async move { + let mut adresses = adresses.peekable(); + 'file_lookup: { + if adresses.peek().is_none() { + let Ok(file) = File::open(addr).await else { + warning!( + format!("Host {addr:?} could not be resolved."), + input.greppable, + input.accessible + ); + break 'file_lookup + }; + + return read_ips_from_file(file, backup_resolver).boxed() + } + } - ips + stream::iter(adresses).boxed() + }) + .buffer_unordered(10) + .flat_map_unordered(None, |stream| stream) + .collect() + .await } /// Given a string, parse it as a host, IP address, or CIDR. @@ -82,32 +82,22 @@ pub fn parse_addresses(input: &Opts) -> Vec { /// # use hickory_resolver::Resolver; /// let ips = parse_address("127.0.0.1", &Resolver::default().unwrap()); /// ``` -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!("{}:{}", &address, 80) - .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<'a>(address: Cow<'a, str>, resolver: &'a TokioAsyncResolver) -> impl Iterator + use<'a> { + match IpCidr::from_str(&address) { + Ok(cidr) => Either::Left(cidr.iter().map(|c| c.address())), + Err(_) => Either::Right(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<'a>(source: Cow<'a, str>, backup_resolver: &'a TokioAsyncResolver) -> impl Iterator + use<'a> { + if let Ok(addrs) = tokio::net::lookup_host((&*source, 80)).await { + Either::Left(addrs.into_iter().map(|x| x.ip()).collect_vec().into_iter()) + } else if let Ok(addrs) = backup_resolver.lookup_ip(&*source).await { + Either::Left(addrs.iter().collect_vec().into_iter()) + } else { + Either::Right(iter::empty()) } - - ips } /// Derive a DNS resolver. @@ -120,11 +110,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(',') @@ -137,20 +127,17 @@ fn get_resolver(resolver: &Option) -> Resolver { Protocol::Udp, )); } - Resolver::new(config, ResolverOpts::default()).unwrap() + TokioAsyncResolver::tokio(config, ResolverOpts::default()) } - None => match Resolver::from_system_conf() { - Ok(resolver) => resolver, - Err(_) => { - Resolver::new(ResolverConfig::cloudflare_tls(), ResolverOpts::default()).unwrap() - } - }, + None => TokioAsyncResolver::tokio_from_system_conf().unwrap_or_else(|_| { + TokioAsyncResolver::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) -> io::Result> { + let ips = fs::read_to_string(path).await? .lines() .filter_map(|line| IpAddr::from_str(line.trim()).ok()) .collect(); @@ -158,26 +145,31 @@ fn read_resolver_from_file(path: &str) -> Result, std::io::Error> { Ok(ips) } -#[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, -) -> 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() { - if let Ok(address) = address_line { - ips.extend(parse_address(&address, backup_resolver)); - } else { - debug!("Line in file is not valid"); - } - } - - Ok(ips) + ips: File, + backup_resolver: &TokioAsyncResolver, +) -> impl Stream + use<'_> { + let stream = stream::once_future(async move { + let reader = BufReader::new(ips); + let mut lines = reader.lines(); + let stream = stream::poll_fn(move |cx| { + Pin::new(&mut lines) + .poll_next_line(cx) + .map(Result::ok) + .map(Option::flatten) + }); + + stream + .map(move |address_line| async move { + resolve_ips_from_host(address_line.into(), backup_resolver).await + }) + .buffer_unordered(4) + .map(stream::iter) + .flatten() + }); + + stream.flatten() } #[cfg(test)] @@ -185,11 +177,13 @@ mod tests { use super::{get_resolver, parse_addresses, Opts}; use std::net::Ipv4Addr; - #[test] - fn parse_correct_addresses() { - let mut opts = Opts::default(); - opts.addresses = vec!["127.0.0.1".to_owned(), "192.168.0.0/30".to_owned()]; - let ips = parse_addresses(&opts); + #[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()], + ..Opts::default() + }; + let ips = parse_addresses(&opts).await; assert_eq!( ips, @@ -203,78 +197,94 @@ mod tests { ); } - #[test] - fn parse_correct_host_addresses() { - let mut opts = Opts::default(); - opts.addresses = vec!["google.com".to_owned()]; - let ips = parse_addresses(&opts); + #[tokio::test] + async fn parse_correct_host_addresses() { + let opts = Opts { + addresses: vec!["google.com".to_owned()], + ..Opts::default() + }; + let ips = parse_addresses(&opts).await; assert_eq!(ips.len(), 1); } - #[test] - fn parse_correct_and_incorrect_addresses() { - let mut opts = Opts::default(); - opts.addresses = vec!["127.0.0.1".to_owned(), "im_wrong".to_owned()]; - let ips = parse_addresses(&opts); + #[tokio::test] + async fn parse_correct_and_incorrect_addresses() { + let opts = Opts { + addresses: vec!["127.0.0.1".to_owned(), "im_wrong".to_owned()], + ..Opts::default() + }; + let ips = parse_addresses(&opts).await; assert_eq!(ips, [Ipv4Addr::new(127, 0, 0, 1),]); } - #[test] - fn parse_incorrect_addresses() { - let mut opts = Opts::default(); - opts.addresses = vec!["im_wrong".to_owned(), "300.10.1.1".to_owned()]; - let ips = parse_addresses(&opts); + #[tokio::test] + async fn parse_incorrect_addresses() { + let opts = Opts { + addresses: vec!["im_wrong".to_owned(), "300.10.1.1".to_owned()], + ..Opts::default() + }; + 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 mut opts = Opts::default(); - opts.addresses = vec!["fixtures/hosts.txt".to_owned()]; - let ips = parse_addresses(&opts); + let opts = Opts { + addresses: vec!["fixtures/hosts.txt".to_owned()], + ..Opts::default() + }; + let ips = parse_addresses(&opts).await; assert_eq!(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 mut opts = Opts::default(); - opts.addresses = vec!["fixtures/empty_hosts.txt".to_owned()]; - let ips = parse_addresses(&opts); - assert_eq!(ips.len(), 0); + let opts = Opts { + addresses: vec!["fixtures/empty_hosts.txt".to_owned()], + ..Opts::default() + }; + let ips = parse_addresses(&opts).await; + assert!(ips.is_empty()); } - #[test] - fn parse_naughty_host_file() { + #[tokio::test] + async fn parse_naughty_host_file() { // Host file contains IP, Hosts, incorrect IPs, incorrect hosts - let mut opts = Opts::default(); - opts.addresses = vec!["fixtures/naughty_string.txt".to_owned()]; - let ips = parse_addresses(&opts); - assert_eq!(ips.len(), 0); + let opts = Opts { + addresses: vec!["fixtures/naughty_string.txt".to_owned()], + ..Opts::default() + }; + let ips = parse_addresses(&opts).await; + assert!(ips.is_empty()); } - #[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() { - let mut opts = Opts::default(); - // https://developers.google.com/speed/public-dns - opts.resolver = Some("8.8.8.8,8.8.4.4".to_owned()); - - let resolver = get_resolver(&opts.resolver); - let lookup = resolver.lookup_ip("www.example.com.").unwrap(); + #[tokio::test] + async fn resolver_args_google_dns() { + let opts = Opts { + addresses: vec!["fixtures/naughty_string.txt".to_owned()], + // https://developers.google.com/speed/public-dns + resolver: Some("8.8.8.8,8.8.4.4".to_owned()), + ..Opts::default() + }; + + 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/input.rs b/src/input.rs index 451f5476c..226efefd6 100644 --- a/src/input.rs +++ b/src/input.rs @@ -1,9 +1,8 @@ //! 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::fs; use std::path::PathBuf; +use serde::Deserialize; const LOWEST_PORT_NUMBER: u16 = 1; const TOP_PORT_NUMBER: u16 = 65535; @@ -35,7 +34,6 @@ pub struct PortRange { pub end: u16, } -#[cfg(not(tarpaulin_include))] fn parse_range(input: &str) -> Result { let range = input .split('-') @@ -156,7 +154,6 @@ pub struct Opts { pub udp: bool, } -#[cfg(not(tarpaulin_include))] impl Opts { pub fn read() -> Self { let mut opts = Opts::parse(); @@ -249,7 +246,6 @@ impl Default for Opts { /// Struct used to deserialize the options specified within our config file. /// These will be further merged with our command line arguments in order to /// generate the final Opts struct. -#[cfg(not(tarpaulin_include))] #[derive(Debug, Deserialize)] pub struct Config { addresses: Option>, @@ -269,7 +265,6 @@ pub struct Config { udp: Option, } -#[cfg(not(tarpaulin_include))] #[allow(clippy::doc_link_with_quotes)] impl Config { /// Reads the configuration file with TOML format and parses it into a @@ -284,15 +279,9 @@ impl Config { /// exclude_ports = [8080, 9090, 80] /// udp = false /// - pub fn read(custom_config_path: Option) -> Self { - let mut content = String::new(); + pub async fn read(custom_config_path: Option) -> Self { 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(), - } - } + let content = tokio::fs::read_to_string(config_path).await.unwrap_or_default(); let config: Config = match toml::from_str(&content) { Ok(config) => config, diff --git a/src/lib.rs b/src/lib.rs index b9ad47738..e81f3d4f8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,14 +8,13 @@ //! [`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, @@ -34,7 +33,7 @@ //! false, //! ); //! -//! 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 e0cedbeb1..d6f6d1ba1 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; @@ -30,17 +29,17 @@ const AVERAGE_BATCH_SIZE: u16 = 3000; #[macro_use] extern crate log; -#[cfg(not(tarpaulin_include))] #[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() { env_logger::init(); let mut benchmarks = Benchmark::init(); let mut rustscan_bench = NamedTimer::start("RustScan"); let mut opts: Opts = Opts::read(); - let config = Config::read(opts.config_path.clone()); + let config = Config::read(opts.config_path.clone()).await; opts.merge(&config); debug!("Main() `opts` arguments are {:?}", opts); @@ -63,7 +62,7 @@ fn main() { print_opening(&opts); } - let ips: Vec = parse_addresses(&opts); + let ips: Vec = parse_addresses(&opts).await; if ips.is_empty() { warning!( @@ -99,7 +98,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); @@ -175,7 +174,7 @@ fn main() { ); match script.run() { Ok(script_result) => { - detail!(script_result.to_string(), opts.greppable, opts.accessible); + detail!(script_result.clone(), opts.greppable, opts.accessible); } Err(e) => { warning!(&format!("Error {e}"), opts.greppable, opts.accessible); @@ -299,11 +298,18 @@ mod tests { use super::{adjust_ulimit_size, infer_batch_size}; use super::{print_opening, Opts}; + + fn options() -> Opts { + Opts { + batch_size: 50_000, + ..Opts::default() + } + } + #[test] #[cfg(unix)] fn batch_size_lowered() { - let mut opts = Opts::default(); - opts.batch_size = 50_000; + let opts = options(); let batch_size = infer_batch_size(&opts, 120); assert!(batch_size < opts.batch_size); @@ -312,51 +318,54 @@ mod tests { #[test] #[cfg(unix)] fn batch_size_lowered_average_size() { - let mut opts = Opts::default(); - opts.batch_size = 50_000; + let opts = options(); let batch_size = infer_batch_size(&opts, 9_000); - assert!(batch_size == 3_000); + assert_eq!(batch_size, 3_000); } #[test] #[cfg(unix)] fn batch_size_equals_ulimit_lowered() { // because ulimit and batch size are same size, batch size is lowered // to ULIMIT - 100 - let mut opts = Opts::default(); - opts.batch_size = 50_000; + let opts = options(); let batch_size = infer_batch_size(&opts, 5_000); - assert!(batch_size == 4_900); + assert_eq!(batch_size, 4_900); } #[test] #[cfg(unix)] fn batch_size_adjusted_2000() { // ulimit == batch_size - let mut opts = Opts::default(); - opts.batch_size = 50_000; - opts.ulimit = Some(2_000); + let opts = Opts { + ulimit: Some(2_000), + ..options() + }; let batch_size = adjust_ulimit_size(&opts); - assert!(batch_size == 2_000); + assert_eq!(batch_size, 2_000); } #[test] #[cfg(unix)] fn test_high_ulimit_no_greppable_mode() { - let mut opts = Opts::default(); - opts.batch_size = 10; - opts.greppable = false; + let opts = Opts { + batch_size: 10, + greppable: false, + ..options() + }; let batch_size = infer_batch_size(&opts, 1_000_000); - assert!(batch_size == opts.batch_size); + assert_eq!(batch_size, opts.batch_size); } #[test] fn test_print_opening_no_panic() { - let mut opts = Opts::default(); - opts.ulimit = Some(2_000); + let opts = Opts { + ulimit: Some(2_000), + ..Opts::default() + }; // print opening should not panic print_opening(&opts); } diff --git a/src/port_strategy/mod.rs b/src/port_strategy.rs similarity index 63% rename from src/port_strategy/mod.rs rename to src/port_strategy.rs index bf147693c..766f4c7b4 100644 --- a/src/port_strategy/mod.rs +++ b/src/port_strategy.rs @@ -1,9 +1,7 @@ //! Provides a means to hold configuration options specifically for port scanning. -mod range_iterator; +use either::Either; use crate::input::{PortRange, ScanOrder}; use rand::seq::SliceRandom; -use rand::thread_rng; -use range_iterator::RangeIterator; /// Represents options of port scanning. /// @@ -35,7 +33,7 @@ impl PortStrategy { } ScanOrder::Serial => PortStrategy::Manual(ports.unwrap()), ScanOrder::Random => { - let mut rng = thread_rng(); + let mut rng = rand::rng(); let mut ports = ports.unwrap(); ports.shuffle(&mut rng); PortStrategy::Manual(ports) @@ -43,21 +41,23 @@ impl PortStrategy { } } - pub fn order(&self) -> Vec { + pub fn ordered_iter(&self) -> impl Iterator + use<'_> { match self { - PortStrategy::Manual(ports) => ports.clone(), - PortStrategy::Serial(range) => range.generate(), - PortStrategy::Random(range) => range.generate(), + PortStrategy::Manual(ports) => Either::Left(Either::Left(ports.iter().copied())), + PortStrategy::Serial(range) => { + Either::Left(Either::Right(range.start..=range.end)) + }, + PortStrategy::Random(range) => { + let length = range.end - range.start; + let start = range.start; + let iter = blackrock2::BlackRockIter::new(u64::from(length) + 1) + .map(move |port| port as u16 + start); + Either::Right(iter) + }, } } } -/// 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; -} - /// As the name implies SerialRange will always generate a vector in /// ascending order. #[derive(Debug)] @@ -66,12 +66,6 @@ pub struct SerialRange { end: u16, } -impl RangeOrder for SerialRange { - fn generate(&self) -> Vec { - (self.start..=self.end).collect() - } -} - /// As the name implies RandomRange will always generate a vector with /// a random order. This vector is built following the LCG algorithm. #[derive(Debug)] @@ -80,21 +74,6 @@ pub struct RandomRange { end: u16, } -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() - } -} - #[cfg(test)] mod tests { use super::PortStrategy; @@ -104,16 +83,16 @@ mod tests { 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).into_iter().collect::>(); + let result = strategy.ordered_iter().collect::>(); + let expected_range = (1..=100).collect::>(); assert_eq!(expected_range, result); } #[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).into_iter().collect::>(); + let mut result = strategy.ordered_iter().collect::>(); + let expected_range = (1..=100).collect::>(); assert_ne!(expected_range, result); result.sort_unstable(); @@ -123,15 +102,15 @@ mod tests { #[test] fn serial_strategy_with_ports() { let strategy = PortStrategy::pick(&None, Some(vec![80, 443]), ScanOrder::Serial); - let result = strategy.order(); + let result = strategy.ordered_iter().collect::>(); assert_eq!(vec![80, 443], 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).into_iter().collect::>(); + let mut result = strategy.ordered_iter().collect::>(); + let expected_range = (1..10).collect::>(); assert_ne!(expected_range, result); result.sort_unstable(); diff --git a/src/port_strategy/range_iterator.rs b/src/port_strategy/range_iterator.rs deleted file mode 100644 index df95d8d4b..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).into_iter().collect::>(); - assert_eq!(expected_range, result); - - let result = generate_sorted_range(1, 100); - let expected_range = (1..=100).into_iter().collect::>(); - assert_eq!(expected_range, result); - - let result = generate_sorted_range(1, 1000); - let expected_range = (1..=1000).into_iter().collect::>(); - assert_eq!(expected_range, result); - - let result = generate_sorted_range(1, 65_535); - let expected_range = (1..=65_535).into_iter().collect::>(); - assert_eq!(expected_range, result); - - let result = generate_sorted_range(1000, 2000); - let expected_range = (1000..=2000).into_iter().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 45fed9ccb..5779b9d2f 100644 --- a/src/scanner/mod.rs +++ b/src/scanner/mod.rs @@ -6,119 +6,32 @@ 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::HashSet, - net::{IpAddr, Shutdown, SocketAddr}, - num::NonZeroU8, + net::{IpAddr, SocketAddr}, + sync::Arc, + num::NonZero, time::Duration, }; +use tokio::{ + net::{TcpStream, UdpSocket}, + io::{self, AsyncWriteExt}, + time, +}; +use colored::Colorize; +use futures_lite::{stream, StreamExt}; +use tokio_par_stream::TokioParStream; -/// 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. -/// Added by wasuaje - 01/26/2024: -/// exclude_ports is an exclusion port list -#[cfg(not(tarpaulin_include))] #[derive(Debug)] -pub struct Scanner { - ips: Vec, - batch_size: u16, +struct ScannerConnector { + udp: bool, + tries: NonZero, timeout: Duration, - tries: NonZeroU8, greppable: bool, - port_strategy: PortStrategy, accessible: bool, - exclude_ports: Vec, - udp: bool, } -// Allowing too many arguments for clippy. -#[allow(clippy::too_many_arguments)] -impl Scanner { - pub fn new( - ips: &[IpAddr], - batch_size: u16, - timeout: Duration, - tries: u8, - greppable: bool, - port_strategy: PortStrategy, - accessible: bool, - exclude_ports: Vec, - udp: bool, - ) -> Self { - Self { - batch_size, - timeout, - tries: NonZeroU8::new(std::cmp::max(tries, 1)).unwrap(), - greppable, - port_strategy, - ips: ips.iter().map(ToOwned::to_owned).collect(), - accessible, - exclude_ports, - udp, - } - } - - /// 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` - /// Added by wasuaje - 01/26/2024: - /// Filtering port against exclude port list - pub async fn run(&self) -> Vec { - let ports: Vec = self - .port_strategy - .order() - .iter() - .filter(|&port| !self.exclude_ports.contains(port)) - .copied() - .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 errors: HashSet = HashSet::new(); - - for _ in 0..self.batch_size { - if let Some(socket) = socket_iterator.next() { - ftrs.push(self.scan_socket(socket)); - } else { - break; - } - } - - debug!("Start scanning sockets. \nBatch size {}\nNumber of ip-s {}\nNumber of ports {}\nTargets all together {} ", - self.batch_size, - 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)); - } - - match result { - Ok(socket) => open_sockets.push(socket), - Err(e) => { - let error_string = e.to_string(); - if errors.len() < self.ips.len() * 1000 { - errors.insert(error_string); - } - } - } - } - debug!("Typical socket connection errors {:?}", errors); - debug!("Open Sockets found: {:?}", &open_sockets); - open_sockets - } - +impl ScannerConnector { /// Given a socket, scan it self.tries times. /// Turns the address into a SocketAddr /// Deals with the `` type @@ -149,6 +62,7 @@ impl Scanner { } let tries = self.tries.get(); + let mut last_err = None; for nr_try in 1..=tries { match self.connect(socket).await { Ok(tcp_stream) => { @@ -156,7 +70,7 @@ impl Scanner { "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); @@ -167,17 +81,23 @@ impl Scanner { Err(e) => { let mut error_string = e.to_string(); - assert!(!error_string.to_lowercase().contains("too many open files"), "Too many open files. Please reduce batch size. The default is 5000. Try -b 2500."); + assert!( + !error_string.to_lowercase().contains("too many open files"), + "Too many open files. Please reduce batch size. The default is 5000. Try -b 2500." + ); - if nr_try == tries { + let ip = socket.ip(); + last_err = Some(move || { + use std::fmt::Write; error_string.push(' '); - error_string.push_str(&socket.ip().to_string()); - return Err(io::Error::new(io::ErrorKind::Other, error_string)); - } + write!(error_string, "{ip}").unwrap(); + io::Error::other(error_string) + }); } }; } - unreachable!(); + + Err(last_err.unwrap()()) } /// Performs the connection to the socket with timeout @@ -195,12 +115,10 @@ 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 recieve packets @@ -254,19 +172,14 @@ 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) - } - } + Ok(Err(e)) => Err(e), + Err(_) => Ok(false), } } Err(e) => { @@ -288,15 +201,113 @@ impl Scanner { } } + +/// 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. +/// Added by wasuaje - 01/26/2024: +/// exclude_ports is an exclusion port list +#[derive(Debug)] +pub struct Scanner { + ips: Box<[IpAddr]>, + port_strategy: PortStrategy, + exclude_ports: Vec, + batch_size: u16, + connector: Arc, +} + +// Allowing too many arguments for clippy. +#[allow(clippy::too_many_arguments)] +impl Scanner { + pub fn new( + ips: &[IpAddr], + batch_size: u16, + timeout: Duration, + tries: u8, + greppable: bool, + port_strategy: PortStrategy, + accessible: bool, + exclude_ports: Vec, + udp: bool, + ) -> Self { + Self { + batch_size, + port_strategy, + ips: Box::from(ips), + exclude_ports, + connector: Arc::new(ScannerConnector { + udp, + accessible, + timeout, + tries: NonZero::new(tries).unwrap_or(NonZero::::MIN), + greppable, + }) + } + } + + /// 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` + /// Added by wasuaje - 01/26/2024: + /// Filtering port against exclude port list + pub async fn run(&self) -> Vec { + let ports = self + .port_strategy + .ordered_iter() + .filter(|&port| !self.exclude_ports.contains(&port)) + .collect::>(); + + let ports_len = ports.len(); + + let socket_iterator = SocketIterator::new(&self.ips, ports.into_iter()); + let mut errors: HashSet = HashSet::new(); + + let stream = stream::iter(socket_iterator) + .map(|socket| (socket, Arc::clone(&self.connector))) + .map(|(socket, connector)| async move { + connector.scan_socket(socket).await + }) + .par_buffered_unordered(usize::from(self.batch_size)) + .filter_map(|result| { + let err = match result { + Ok(sock) => return Some(sock), + Err(err) => err, + }; + let error_string = err.to_string(); + if errors.len() < self.ips.len() * 1000 { + errors.insert(error_string); + } + None + }); + + + debug!( + "Start scanning sockets. \nBatch size {}\nNumber of ip-s {}\nNumber of ports {}\nTargets all together {} ", + self.batch_size, + self.ips.len(), + &ports_len, + self.ips.len() * ports_len + ); + + let open_sockets = stream.collect::>().await; + + debug!("Typical socket connection errors {:?}", errors); + debug!("Open Sockets found: {:?}", &open_sockets); + open_sockets + } +} + #[cfg(test)] 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 range = PortRange { @@ -315,13 +326,11 @@ mod tests { vec![9000], false, ); - block_on(scanner.run()); - // if the scan fails, it wouldn't be able to assert_eq! as it panicked! - assert_eq!(1, 1); + scanner.run().await; } - #[test] - fn ipv6_scanner_runs() { - // Makes sure the program still runs and doesn't panic + + #[tokio::test] + async fn ipv6_scanner_runs() { let addrs = vec!["::1".parse::().unwrap()]; let range = PortRange { start: 1, @@ -339,12 +348,11 @@ mod tests { vec![9000], false, ); - block_on(scanner.run()); - // if the scan fails, it wouldn't be able to assert_eq! as it panicked! - assert_eq!(1, 1); + scanner.run().await; } - #[test] - fn quad_zero_scanner_runs() { + + #[tokio::test] + async fn quad_zero_scanner_runs() { let addrs = vec!["0.0.0.0".parse::().unwrap()]; let range = PortRange { start: 1, @@ -362,11 +370,11 @@ mod tests { vec![9000], false, ); - block_on(scanner.run()); - assert_eq!(1, 1); + scanner.run().await; } - #[test] - fn google_dns_runs() { + + #[tokio::test] + async fn google_dns_runs() { let addrs = vec!["8.8.8.8".parse::().unwrap()]; let range = PortRange { start: 400, @@ -384,11 +392,11 @@ mod tests { vec![9000], false, ); - block_on(scanner.run()); - assert_eq!(1, 1); + scanner.run().await; } - #[test] - fn infer_ulimit_lowering_no_panic() { + + #[tokio::test] + async 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()]; @@ -409,12 +417,11 @@ mod tests { vec![9000], false, ); - block_on(scanner.run()); - assert_eq!(1, 1); + scanner.run().await; } - #[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 range = PortRange { @@ -433,12 +440,11 @@ mod tests { vec![9000], true, ); - block_on(scanner.run()); - // if the scan fails, it wouldn't be able to assert_eq! as it panicked! - assert_eq!(1, 1); + scanner.run().await; } - #[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 range = PortRange { @@ -457,12 +463,11 @@ mod tests { vec![9000], true, ); - block_on(scanner.run()); - // if the scan fails, it wouldn't be able to assert_eq! as it panicked! - assert_eq!(1, 1); + scanner.run().await; } - #[test] - fn udp_quad_zero_scanner_runs() { + + #[tokio::test] + async fn udp_quad_zero_scanner_runs() { let addrs = vec!["0.0.0.0".parse::().unwrap()]; let range = PortRange { start: 1, @@ -480,11 +485,11 @@ mod tests { vec![9000], true, ); - block_on(scanner.run()); - assert_eq!(1, 1); + scanner.run().await; } - #[test] - fn udp_google_dns_runs() { + + #[tokio::test] + async fn udp_google_dns_runs() { let addrs = vec!["8.8.8.8".parse::().unwrap()]; let range = PortRange { start: 100, @@ -502,7 +507,6 @@ mod tests { vec![9000], true, ); - block_on(scanner.run()); - assert_eq!(1, 1); + scanner.run().await; } } diff --git a/src/scanner/socket_iterator.rs b/src/scanner/socket_iterator.rs index 7813fe71f..c6d995dc7 100644 --- a/src/scanner/socket_iterator.rs +++ b/src/scanner/socket_iterator.rs @@ -1,7 +1,7 @@ use itertools::{iproduct, Product}; use std::net::{IpAddr, SocketAddr}; -pub struct SocketIterator<'s> { +pub struct SocketIterator<'s, I: Iterator> { // product_it is a cartesian product iterator over // the slices of ports and IP addresses. // @@ -10,8 +10,7 @@ pub struct SocketIterator<'s> { // all the IPs for one port before moving on to the next one // ("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_it: Product>, } /// An iterator that receives a slice of IPs and ports and returns a Socket @@ -19,34 +18,34 @@ pub struct SocketIterator<'s> { /// The goal of this iterator is to go over every IP and port combination /// without generating a big memory footprint. The alternative would be /// 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()); +impl<'s, I: Iterator> SocketIterator<'s, I> { + pub fn new(ips: &'s [IpAddr], ports: I) -> Self { Self { - product_it: iproduct!(ports_it, ips_it), + product_it: iproduct!(ports, ips.iter()), } } } -#[allow(clippy::doc_link_with_quotes)] -impl<'s> Iterator for SocketIterator<'s> { +impl<'s, I: Iterator> Iterator for SocketIterator<'s, I> { type Item = SocketAddr; /// Returns a socket based on the combination of one of the provided /// IPs and ports or None when these combinations are exhausted. Every /// IP will have the same port until a port is incremented. - /// + /// ```ignore + /// # use std::net::IpAddr; /// let it = SocketIterator::new(&["127.0.0.1", "192.168.0.1"], &[80, 443]); - /// it.next(); // 127.0.0.1:80 - /// it.next(); // 192.168.0.1:80 - /// it.next(); // 127.0.0.1:443 - /// it.next(); // 192.168.0.1:443 - /// it.next(); // None + /// let sock = |ip: &str| -> IpAddr { ip.parse().unwrap() }; + /// assert_eq!(it.next(), Some(sock("127.0.0.1:80"))); + /// assert_eq!(it.next(), Some(sock("192.168.0.1:80"))); + /// assert_eq!(it.next(), Some(sock("127.0.0.1:443"))); + /// assert_eq!(it.next(), Some(sock("192.168.0.1:443"))); + /// assert_eq!(it.next(), None); + /// ``` fn next(&mut self) -> Option { self.product_it .next() - .map(|(port, ip)| SocketAddr::new(*ip, *port)) + .map(|(port, &ip)| SocketAddr::new(ip, port)) } } @@ -62,7 +61,7 @@ mod tests { "192.168.0.1".parse::().unwrap(), ]; let ports: Vec = vec![22, 80, 443]; - let mut it = SocketIterator::new(&addrs, &ports); + let mut it = SocketIterator::new(&addrs, ports.iter().copied()); assert_eq!(Some(SocketAddr::new(addrs[0], ports[0])), it.next()); assert_eq!(Some(SocketAddr::new(addrs[1], ports[0])), it.next()); diff --git a/src/scripts/mod.rs b/src/scripts/mod.rs index cf14c4a21..f6f2520dc 100644 --- a/src/scripts/mod.rs +++ b/src/scripts/mod.rs @@ -78,7 +78,7 @@ use crate::input::ScriptsRequired; use anyhow::{anyhow, Result}; use log::debug; -use serde_derive::{Deserialize, Serialize}; +use serde::{Deserialize, Serialize}; use std::collections::HashSet; use std::convert::TryInto; use std::fs::{self, File}; @@ -95,7 +95,6 @@ ports_separator = "," call_format = "nmap -vvv -p {{port}} {{ip}}" "#; -#[cfg(not(tarpaulin_include))] pub fn init_scripts(scripts: ScriptsRequired) -> Result> { let mut scripts_to_run: Vec = Vec::new(); @@ -268,7 +267,6 @@ impl Script { } } -#[cfg(not(tarpaulin_include))] fn execute_script(script: &str) -> Result { debug!("\nScript arguments {}", script); let process = Exec::shell(script); @@ -360,7 +358,6 @@ pub struct ScriptConfig { pub developer: Option>, } -#[cfg(not(tarpaulin_include))] impl ScriptConfig { pub fn read_config() -> Result { let Some(mut home_dir) = dirs::home_dir() else { diff --git a/src/tui.rs b/src/tui.rs index 6f215f590..25f7c9d9c 100644 --- a/src/tui.rs +++ b/src/tui.rs @@ -67,7 +67,7 @@ macro_rules! output { #[macro_export] macro_rules! funny_opening { // prints a funny quote / opening - () => { + () => {{ use rand::seq::SliceRandom; let quotes = vec![ "Nmap? More like slowmap.🐢", @@ -98,8 +98,11 @@ macro_rules! funny_opening { "TreadStone was here 🚀", "With RustScan, I scan ports so fast, even my firewall gets whiplash 💨", ]; - let random_quote = quotes.choose(&mut rand::thread_rng()).unwrap(); + + use rand::seq::IndexedRandom; + + let random_quote = quotes.choose(&mut rand::rng()).unwrap(); println!("{}\n", random_quote); - }; + }}; } diff --git a/tests/timelimits.rs b/tests/timelimits.rs index 37ce67b17..14c4239ca 100644 --- a/tests/timelimits.rs +++ b/tests/timelimits.rs @@ -13,7 +13,6 @@ use wait_timeout::ChildExt; const TIMEOUT_MARGIN: u32 = 3; -#[cfg(not(tarpaulin_include))] fn run_rustscan_with_timeout(args: &[&str], timeout: Duration) { println!("Running: target/debug/rustscan: {}", args.join(" "));