RustScan is a blazing-fast port scanner written in Rust, developed by Autumn "bee-san" Skerritt and the RustScan team. Its defining feature is that it scans all 65535 TCP ports in seconds and then automatically hands the discovered open ports to nmap for service/version/script scanning. The design philosophy is simple: "RustScan does the fast port discovery, nmap does the deep inspection." In other words, RustScan does not replace nmap — it complements it. The long-standing pain of "scanning all ports with nmap is slow" is crushed at once by Rust's concurrency, while nmap's familiar analytical power is kept fully intact. That is RustScan's position.
What RustScan is — speed and the nmap hand-off #
There are two keys to understanding RustScan: its overwhelming scan speed and its automatic hand-off to nmap. RustScan first surfaces only "which ports are open" at high speed, then passes that result to nmap to dig into "what is running on those ports." The roles split cleanly.
| Stage | Owner | What it does |
|---|---|---|
| Port discovery | RustScan | Hammers 65535 ports in parallel and quickly identifies the open ones |
| Service identification | nmap | Runs version detection and scripts only on the open ports |
Thanks to this division, the problem of "scanning every port with nmap -p- is far too slow" disappears. Because RustScan narrows down the candidate ports before handing them to nmap, nmap never wastes time on closed ports and can concentrate solely on the open ones.
RustScan only specializes in the speed of port discovery; it performs service identification and script execution by calling nmap internally. So even when using RustScan, nmap must be installed, and your nmap knowledge (-sV / -sC / -A, etc.) carries straight over. The two are not competitors but an upstream (discovery) / downstream (analysis) relationship.
Legal and ethical considerations #
Port scanning is the act of investigating, without permission, "what services a target is exposing," and against the wrong target it is clearly seen as reconnaissance or a precursor to an attack. RustScan in particular fires a large volume of packets at tens of thousands of ports in a short time, so it is also technically heavy on load. Firing RustScan at someone else's host without permission can be an illegal act under Japan's Unauthorised Computer Access Act or laws against obstruction of business, and the equivalents elsewhere.
- Hosts you own or administer — a local test environment, a VPS you pay for, an isolated learning lab.
- Targets you have explicit written permission for — a pentest or vulnerability-assessment contract where the scope (target hosts, period, rate limits) is documented.
- Legitimate learning platforms — Hack The Box, TryHackMe, and other environments where the operator permits port scanning.
The faster a tool is, the more fatal a careless shot at someone else becomes. If you raise the batch size (-b) and fire at a production network, you can overload the target's devices or links, and the worst case — damages and criminal liability — is entirely possible. Always confirm the target and your authorization first.
Basic usage and target specification #
The minimal form of RustScan is just passing the target with -a (--addresses). That alone scans all ports at high speed and automatically hands the open ports to nmap. -a supports comma-separated multiple targets, CIDR notation, and hostnames.
| How to specify | How to write it | Purpose |
|---|---|---|
| Single host | -a 10.0.0.1 |
Scan all ports on one host |
| Multiple hosts | -a 10.0.0.1,10.0.0.2 |
List them comma-separated |
| CIDR | -a 192.168.1.0/24 |
Sweep a subnet at once |
| Specific ports | -p 80,443,8080 |
Only these ports |
| Port range | --range 1-1000 |
Scan a bounded range |
$ rustscan -a 10.0.0.1
# -a specifies the target (positional rustscan 10.0.0.1 also works)
# scans 65535 ports fast and auto-hands open ports to nmapTo narrow the scan range, use --range (a continuous range) or -p (an explicit port list). This makes a "start narrow and fast, widen on a hit" workflow easy.
$ rustscan -a 10.0.0.1 --range 1-1000
# scan only ports 1-1000
$ rustscan -a 10.0.0.1 -p 80,443,8080
# -p lists individual ports, comma-separated
$ rustscan -a 192.168.1.0/24 -g
# sweep a /24 by CIDR, -g for machine-readable ip:ports outputIf you want to parse results in a script, use -g (--greppable). It drops ASCII art and decoration and prints only ip:ports. For screen-reader users there is -A (--accessible), which produces output with less decoration that is easier to read aloud. If the banner is in the way, hide it with --no-banner.
Speed tuning and the "Too many open files" fix #
RustScan's speed comes from hammering a large number of ports in parallel. The degree of that parallelism is set by the batch size (-b), which defaults to 4500. Because it tries that many ports at once, exceeding the system's file-descriptor limit (ulimit) makes it fail with a "Too many open files" error. This is the pitfall you hit most often with RustScan.
| Option | Role | Default |
|---|---|---|
-b / --batch-size |
Number of ports probed in parallel | 4500 |
-u / --ulimit |
Raise the file-descriptor limit for the scan | — |
-t / --timeout |
Per-port timeout (milliseconds) | 1500 |
--tries |
Number of retries per port | — |
--scan-order |
Scan order (serial / random) |
— |
If the batch size exceeds the ulimit, it dies with Too many open files. There are two fixes — (A) raise the ulimit with -u, or (B) lower the batch size with -b. On low-spec or tightly-restricted hosts, dropping to around -b 1000 stabilizes it. Conversely, on roomy environments, raising -u to gain parallelism makes it faster.
$ rustscan -a 10.0.0.1 -b 1000 -u 5000
# -b 1000 lower the parallel port count to avoid "Too many open files"
# -u 5000 raise the file-descriptor limit
$ rustscan -a 10.0.0.1 -t 2000
# -t 2000 extend the timeout to 2000ms for slow targets (default 1500)The scan order can be chosen with --scan-order, either serial (in order) or random. If you have targets you scan often, writing defaults like ports or batch_size into the config file ~/.rustscan.toml saves you from specifying them every time. Conversely, to ignore the config file and run with plain behavior, add --no-config.
The nmap hand-off and a real-world workflow #
RustScan's real value lies in the mechanism of "everything after -- (the double-dash) is passed straight to nmap." After RustScan identifies the open ports, it carries the arguments written after -- over to nmap verbatim and runs them. In other words, you can chain "fast discovery" and "nmap's deep analysis" in a single command.
$ rustscan -a 10.0.0.1 --range 1-1000 -- -sV
# scan 1-1000 fast -> hand open ports to nmap
# everything after -- (-sV) goes to nmap = service/version detectionIn practice, the staple workflow is "discover all ports with RustScan, then run nmap's aggressive scan (-A) and default scripts (-sC) only on the open ports." Speed tuning and the nmap hand-off can be used together.
$ rustscan -a 10.0.0.1 -b 1000 -u 5000 -- -A -sC
# discover all ports while stabilizing with -b/-u
# the -A -sC after -- go to nmap
# -A = OS/version/traceroute, -sC = default scriptsWhen you start a new machine, the go-to is to fire rustscan -a TARGET -- -sV -sC -A. In seconds you know all the open ports, and nmap then produces the service and script results too, so you complete "full port discovery + service identification" in one shot. After -- you simply line up your usual nmap options — there is nothing new to relearn.
To try it quickly with Docker, you can use the official image and run it without installing the binary locally.
$ docker run -it --rm --name rustscan rustscan/rustscan:latest -a 127.0.0.1
# run RustScan via the official image (no binary install needed)Where it sits among similar tools — when to pick RustScan #
There are several port scanners, and RustScan's position comes down to one thing: "blazing-fast port discovery + a seamless hand-off to nmap." masscan rivals it on raw speed, but RustScan pulls ahead on the ease of its nmap integration.
| Tool | Language | Characteristics |
|---|---|---|
RustScan | Rust | Specializes in blazing-fast port discovery. Its biggest weapon: auto-handing open ports to nmap via everything after -- |
nmap | C | The standard. Rich in service identification, scripts, and OS detection, but slow at all-port scanning. RustScan's hand-off target |
masscan | C | Also extremely fast, good at internet-scale scanning. But its nmap integration is not as effortless as RustScan's |
naabu | Go | Made by ProjectDiscovery. A lightweight port scanner suited to pipeline workflows |
| Aspect | RustScan | nmap alone |
|---|---|---|
| All-port scan speed | seconds | slow, in minutes |
| Service/version identification | delegated to nmap | its specialty |
| Discover→analyze in one command | `-- -sV -sC` | `-p-` does it all in nmap |
When you "want to enumerate all ports fast," RustScan is the shortest path. masscan is fast too, but the ease of piping straight into nmap for a single, end-to-end deep dive is unique to RustScan. Think of RustScan not as an nmap replacement but as an accelerator in front of it. Drill rustscan -a TARGET -- <nmap options> into your fingers, and when "Too many open files" appears, adjust with -u / -b — that is the first step to mastering RustScan.