* Refactor SocketIterator for allocation-free performance
Refactor SocketIterator to eliminate boxing and improve memory efficiency. Update documentation and tests to reflect changes.
* fix(socket_iterator): fix clone test off-by-one and skip private doc example
- clone_resumes_independently expected None after 3 of 4 sockets; assert
the exact remaining sequence for both the original and the clone.
- The struct doc example referenced a placeholder crate and a private
module, so it could never compile as a doctest; mark it ignore.
- Add a test for empty IP/port inputs covering size_hint and the
FusedIterator promise.
---------
Co-authored-by: Autumn Skerritt <[email protected]>
Small cleanups in main.rs:
- Iterate over the parsed scripts by reference and clone only the script being run, instead of cloning the whole list for every IP.
- Use `or_default()` for the per-IP port map.
- If the soft file-descriptor limit does not fit in a `usize` (32-bit targets), fall back to `DEFAULT_FILE_DESCRIPTORS_LIMIT` instead of `usize::MAX`, which bypassed all batch-size adjustments.
- Fix a typo.
The effective-batch-size warning fix originally proposed here landed via #921.
Co-authored-by: Autumn Skerritt <[email protected]>
New opt-in `--interval <MS>` option (also `interval` in the config file): after a port has been scanned on every address, wait that many milliseconds before scanning the next port, for slow, low-noise scans. Within a port `--batch-size` still limits concurrency; with the default of 0 scanning behaviour is unchanged.
Library: `Scanner::with_interval(Duration)` is added; `Scanner::new()` is unchanged.
Co-authored-by: Autumn Skerritt <[email protected]>
New `--closed` option (also `closed = true` in the config file) that additionally lists TCP ports that actively refused the connection: printed live as `Closed ip:port` and summarised under `closed ports:` at the end (also in greppable mode). Scripts are never run against closed ports, and without `--closed` scanning behaviour is unchanged.
Library: `Scanner::with_closed_ports()` and `Scanner::run_with_status() -> Vec<PortStatus>` are added; `Scanner::new()` and `run()` are unchanged.
Co-authored-by: Autumn Skerritt <[email protected]>
`-r/--range` now accepts several comma-separated ranges, e.g. `-r 1-100,200-300,5000-5100`. Overlapping/adjacent ranges are merged; random order uses the existing LCG walk extended over the merged ranges (every port visited exactly once), serial order follows the input order and skips duplicates. Reversed ranges (`300-200`) are now rejected instead of underflowing.
`range` in the config file keeps accepting the old `{ start = 1, end = 1000 }` table and additionally accepts `"1-500,1000-2500"` or `[[1, 500], [1000, 2500]]`.
Library API: `input::PortRange { start, end }` is replaced by `input::PortRanges(Vec<(u16, u16)>)`; `PortStrategy::pick` keeps its signature otherwise.
Fixes#835.
Co-authored-by: Autumn Skerritt <[email protected]>
Add regression tests for CIDR inputs whose host bits are set (e.g. `192.168.1.13/29` -> 192.168.1.8–15, `192.168.1.5/23`, `10.0.0.7/30`). The parsing itself was already fixed on master by 3bdac9c (IpInet accepts host bits), so the proposed normalize_cidr helper was dropped as unreachable.
On native Windows, use the configured `-b/--batch-size` instead of a hard-coded 3000, and report the effective batch size (not the raw CLI value) in the "no open ports" hint on all platforms. `--ulimit` is hidden from Windows help and rejected on Windows (exit code 2), including when it comes from the config file. Unix batch-size/ulimit inference is unchanged.
Effective-batch-size reporting fix originally identified by @0xxreacher in #905.
Co-authored-by: 0xxreacher <[email protected]>
Look for the config file at the XDG-style `$XDG_CONFIG_HOME/rustscan/config.toml` first (via `dirs::config_dir()`, so the platform equivalent on macOS/Windows), then fall back to the previous `$XDG_CONFIG_HOME/.rustscan.toml` and `~/.rustscan.toml` locations so existing configs keep working.
Fixes#741.
Build a port -> payload lookup once per UDP scan instead of cloning the whole nmap payload BTreeMap into every scanned socket and scanning it linearly. Payload selection keeps the previous "last match wins" semantics.
Adds a socket-free micro-benchmark (benches/benchmark_helpers.rs) and lookup tests (tests/udp_payload_lookup.rs).
`Scanner` no longer prints each open socket to stdout by default, so library users can embed it and use the returned sockets without unsolicited output. The CLI opts in via the new `Scanner::with_open_port_output()` builder. The UDP socket bind error is now logged at debug level instead of printed.
Fixes#706.
Rewrite the nmap-payloads decoder in build.rs to follow Nmap's C-style escape format: `\xNN` and single-character escapes are decoded, all other characters are kept literally, and multi-line quoted segments are concatenated. Literal protocol text (e.g. the SNMP `public` community string, NetBIOS names, SSDP headers) was previously dropped, producing malformed probes. Also strip CR line endings when reading nmap-payloads.
Adds regression tests pinning the SNMP (161) and SSDP (1900) probe bytes.
Fixes#933.
Route all user-facing stdout writes through tui::println_safe, which exits 0 on BrokenPipe (e.g. `rustscan -g ... | head`) instead of panicking (fatal under panic = "abort"). On Windows, skip hickory-resolver's system configuration and hosts file when SystemRoot is unset, falling back to the existing cloudflare_tls resolver.
Fixes#939, fixes#940.
Add the GitHub-hosted ubuntu-24.04-arm runner to the test matrix so the suite runs natively on arm64 Linux (macos-latest already covers arm64 macOS; build.yml already cross-builds armv7/aarch64 Linux binaries), and document ARM support in docs/arm-support.md.
Fixes#683.
Co-authored-by: Autumn Skerritt <[email protected]>
Build release archives with houseabsolute/actions-rust-release and publish them (plus the .deb and checksums) to the GitHub release when a tag is pushed. CD now runs on pushes to master and tags only.
Also: read-only default workflow token (publish job gets contents: write), third-party actions pinned to release SHAs, fail on unmatched release assets, and the disabled trigger-less dependabot auto-merge workflow is removed.
Fixes#700, fixes#801.
Co-authored-by: Autumn Skerritt <[email protected]>
Replace the deprecated actions-rs/toolchain action with actions-rust-lang/setup-rust-toolchain (pinned to v1.17.0, clippy + rustfmt components, built-in cache and default RUSTFLAGS disabled) and restrict the workflow token to contents: read.
Co-authored-by: Autumn Skerritt <[email protected]>