RustScan

RustScan sweeps all 65535 TCP ports in a second or two, then hands the open ones straight to Nmap for service, version, and script detection. Reach for it at the very start of recon, when you want Nmap’s depth without waiting on a full nmap -p-: find what is listening almost instantly, then let Nmap do the careful work on just those ports.

Mental model: rustscan -a TARGET [options] -- [nmap options]. Everything before -- tunes the sweep; everything after goes to Nmap.

New to port scanning? Core concepts
  • Address (-a): the target(s), a single IP, a comma list, a CIDR like 10.10.10.0/24, a hostname, or a newline-delimited file -a targets.txt
  • Two stages: RustScan finds open ports fast, then pipes them to Nmap. The speed is the RustScan part; the depth is the Nmap part
  • Port: a TCP endpoint from 1 to 65535; RustScan sweeps all of them by default, --top does the common 1000
  • Open vs filtered: an Open line answered; silence can mean closed, firewalled, or a timeout set too short
  • Batch size (-b): how many ports it probes at once (default 4500); higher is faster and louder
  • Timeout (-t): milliseconds to wait per port before calling it closed (default 1500)
  • Ulimit (-u): raises the open-file limit for the run, since each probe uses a socket
  • The -- handoff: everything after -- goes to Nmap, and RustScan already prepends -Pn -vvv -p <found ports> for you
When to reach for RustScan (and when not)

Reach for it to find open ports in seconds at the start of a CTF box, a homelab sweep, or an authorized internal assessment, then hand them straight to Nmap for versions and scripts. It is the “what is even listening here?” tool, run before you decide what to enumerate next, and it shines whenever a full nmap -p- would take too long to wait on.

Reach for something else when stealth matters (RustScan is loud by design; use a slow, timed nmap -T2), when you need real UDP depth (Nmap -sU), when you are scanning internet-scale ranges (masscan is rougher but faster at that scale), or when you already know the port and just want to talk to the service (curl, nc, smbclient).

Install, update, verify#

sudo apt install -y rustscan            # Kali / Debian / Ubuntu (if packaged for your release)
cargo install rustscan                  # newest release, needs the Rust toolchain
docker pull rustscan/rustscan:latest    # no local install (Nmap is inside the image)

sudo apt install --only-upgrade -y rustscan   # update the apt copy
cargo install rustscan --force                # update the cargo copy

rustscan --version    # confirm the version
command -v rustscan   # confirm it is on PATH
rustscan -a 127.0.0.1 # self-test: sweep loopback, then a short Nmap report

RustScan calls Nmap for the depth pass, so Nmap must be installed too. If command -v prints nothing after cargo install, add ~/.cargo/bin to your PATH and open a fresh shell.

Flags you’ll actually use#

Skim these first; the cheat sheet below is these flags combined.

FlagDoesFlagDoes
-aTarget(s): IP, list, CIDR, host, or file-uRaise the open-file limit for the run
-pScan a specific port list (22,80,443)--topTop 1000 ports only
-rScan a port range (1-1000)--udpUDP scan mode instead of TCP
-bBatch size, probes at once (default 4500)-gGreppable: just the open ports, no Nmap
-tPer-port timeout in ms (default 1500)--accessibleScreen-reader friendly output
--triesTries before a port is called closed--scan-orderserial or random port order
-eExclude ports from the sweep--scriptsnone / default / custom script stage
-xExclude addresses from the sweep--Pass everything after it to Nmap

Cheat sheet#

Every block starts simple and adds one flag at a time, so you can stop at the line that does the job.

# Build up a scan: stop at the line you need
rustscan -a TARGET_IP                              # 1. all 65535 TCP ports, then a default Nmap pass
rustscan -a TARGET_IP -- -sV                       # 2. + service/version detection
rustscan -a TARGET_IP -- -sC -sV                   # 3. + default scripts
rustscan -a TARGET_IP -- -sC -sV -oA scans/deep    # 4. + save all three Nmap formats

# Choose the targets
rustscan -a 10.10.10.10,10.10.10.11                # a comma list of hosts
rustscan -a 192.168.56.0/24                        # a whole CIDR subnet
rustscan -a targets.txt                            # a newline-delimited file, one per line
rustscan -a 192.168.56.0/24 -x 192.168.56.5        # exclude a host from the range

# Choose the ports
rustscan -a TARGET_IP --top                        # top 1000 ports only (fast triage)
rustscan -a TARGET_IP -p 22,80,443,445             # a known port set
rustscan -a TARGET_IP -r 1-1000                    # a port range
rustscan -a TARGET_IP -e 9100                       # scan every port but this one

# Tune speed vs. reliability
rustscan -a TARGET_IP -b 500 -t 2500               # gentler + patient (slow/fragile link)
rustscan -a TARGET_IP -b 65535                     # every port at once (needs a high ulimit)
rustscan -a TARGET_IP -u 5000                      # raise the open-file limit for this run
rustscan -a TARGET_IP --scan-order random          # randomize the port order

# Just the ports, no Nmap
rustscan -a TARGET_IP -g                           # greppable: "TARGET_IP -> [22,80,445]"
rustscan -a TARGET_IP --scripts none               # normal RustScan output, skip the Nmap stage
rustscan -a TARGET_IP -g | tee ports.txt           # capture the open-port list to a file

# UDP and the Nmap handoff
rustscan -a TARGET_IP --udp                         # UDP ports instead of TCP
rustscan -a TARGET_IP -- -sU -sV                    # UDP depth via the Nmap stage
rustscan -a TARGET_IP -- -A -oA scans/full          # aggressive Nmap on the found ports

Command breakdowns#

Each block below explains one situation, the exact command, and what to expect back.

Sweep every TCP port and hand them to Nmap#

rustscan -a TARGET_IP

RustScan probes all 65535 TCP ports in a second or two, prints the open ones, then runs Nmap against just those. The default handoff already adds -Pn -vvv -p <open ports>, so Nmap does not re-scan and does not skip a host that blocks ping.

Run scripts and version detection on only the open ports#

rustscan -a TARGET_IP -- -sC -sV

Everything after -- goes to Nmap. -sV fingerprints service versions and -sC runs the default safe scripts, both against only the ports RustScan found. This is the workhorse command.

Save the Nmap results in every format#

rustscan -a TARGET_IP -- -sC -sV -oA scans/deep

-oA is an Nmap flag, so it lives after --. It writes scans/deep.nmap, .gnmap, and .xml at once: grep the .gnmap, feed the .xml to other tools, keep the .nmap for notes.

Scan a whole subnet that is in scope#

rustscan -a 192.168.56.0/24 -b 1000 -- -sV -oA scans/subnet

Feed a CIDR to sweep every host, and lower the batch a little so a wide sweep does not exhaust sockets. You get open ports per host, then version detection across the range.

Scan many hosts from a file#

rustscan -a targets.txt -- -sV -oA scans/multi

-a accepts a newline-delimited file, one IP, CIDR, or hostname per line. Handy when your scope is a list rather than a clean range.

Scan only a known set of ports#

rustscan -a TARGET_IP -p 22,80,443,445 -- -sV

Skip the full sweep when you already know what to check. Use -r 1-1000 for a contiguous range instead of a list.

Get just the open-port list for scripting#

rustscan -a TARGET_IP -g

-g skips Nmap entirely and prints one line like TARGET_IP -> [22,80,445] you can pipe or tee into notes. Use --scripts none if you want RustScan’s normal formatted output but still no Nmap stage.

Fix “Too many open files”#

rustscan -a TARGET_IP -u 5000 -- -sV

Each probe is a socket, so a big batch can hit your open-file limit. -u raises ulimit -n for that run only. Raise it further, or lower -b, if the warning persists.

rustscan -a TARGET_IP -t 2500 -b 500 -- -sV

A short timeout on a laggy link makes real ports look closed. Raise -t (milliseconds) so slow services answer in time, and lower -b so fewer probes race at once. Slower, but reliable.

Triage fast with the top 1000 ports#

rustscan -a TARGET_IP --top -- -sV

--top scans the 1000 most common ports instead of all 65535. A quick first look when you have many hosts; follow up with a full sweep on anything interesting.

Exclude a fragile host or a port from the sweep#

rustscan -a 192.168.56.0/24 -x 192.168.56.5 -e 9100

-x drops addresses and -e drops ports from an otherwise wide sweep, for example a fragile printer at .5 or a raw-print port 9100 you must not touch.

Scan UDP ports#

rustscan -a TARGET_IP --udp

--udp switches the sweep to UDP and reports ports that send a response. UDP scanning is inherently slow and lossy, so for a careful pass reach for Nmap’s -sU directly.

Randomize the scan order#

rustscan -a TARGET_IP --scan-order random

By default ports are probed in ascending order, an obvious pattern. random shuffles them, a small nod to being less predictable on a monitored network. RustScan is still loud overall.

Run an aggressive Nmap pass on the found ports#

rustscan -a TARGET_IP -- -A -oA scans/full

-A turns on Nmap’s OS detection, version detection, default scripts, and traceroute in one flag, run only on the open ports. Heavier and noisier, but a thorough single command when you are cleared to be loud.

Reading the output#

You seeMeaningDo next
Open 10.10.10.10:22A port answeredNote it; the Nmap section explains it
Starting Nmap... then a reportThe handoff ranRead it exactly like normal Nmap output
22/tcp open ssh OpenSSH 8.2Service + version guessStrong clue, not proof; verify by connecting
No open ports foundDown, filtered, or timeout too lowRaise -t, confirm the host is up
Fewer ports than expectedBatch too aggressive, answers droppedLower -b, raise -t, re-run
Too many open filesLocal open-file limit, not a resultAdd -u 5000

The Open lines are the fast RustScan result; the Nmap section beneath them carries the depth. Treat a version banner as a lead, not a fact.

Troubleshooting#

ProblemCauseFix
command not foundNot installed / stale PATHReinstall; add ~/.cargo/bin to PATH; open a new shell
Too many open filesOpen-file limit too lowAdd -u 5000 or raise ulimit -n
Missing ports on a slow linkTimeout too short / batch too bigRaise -t 2500, lower -b 500
Nmap flags ignoredThey came before --Put every Nmap option after --
No Nmap stage runsNmap missing, or -g / --scripts none setInstall Nmap; drop the greppable/none flag
Scan feels stuck on a big rangeBatch too high for the OSLower -b, or scan fewer hosts at once
Host seems down in NmapPing-blocked host (rare)RustScan already adds -Pn; confirm the host is really up

Gotchas#

  • Everything after -- goes to Nmap; nothing before it does. Put -sC -sV -oA after the dashes or they apply to the wrong tool or error out. This is the single most common RustScan mistake.
  • RustScan already passes -Pn -vvv -p <ports> to Nmap. You rarely need to add -Pn yourself, and Nmap only scans the ports RustScan found, never a fresh range.
  • A “too many open files” warning is your machine’s limit, not a finding. The default batch of 4500 can exhaust your sockets before it exhausts the target; raise -u or lower -b.
  • Fast does not mean complete. On a lossy or rate-limited link an aggressive batch drops answers, so a short port list can be an artifact of speed rather than the truth. Lower -b, raise -t, and re-run.
  • Let the Nmap stage own the saved output. RustScan’s own result is ephemeral; only -oA (after --) writes the files you can grep and attach later.
  • RustScan is loud by design. A burst of SYNs to thousands of ports from one source is one of the easiest patterns to alert on, so scope and timing matter more here than usual.

Pairs with#

nmap is the other half of every RustScan run: it takes the open ports after -- and does versions, scripts, and OS detection with -sC -sV -oA. Once a web port shows up, gobuster and ffuf discover paths while curl inspects headers cleanly, and smbclient or netexec take over on 139/445. When you do not have RustScan, nmap -p- --min-rate 5000 covers the same ground more slowly; masscan wins only at internet scale, where its rougher output is an acceptable trade.

Find us elsewhere

Merch, stickers, and moreSupport the work at the Solvere Labs shop