>_NMAPRS — NMAP, REWRITTEN IN RUST
Speaks nmap's CLI dialect: every flag, every probe, every output format your scripts already know. Real TCP connect, raw IPv4 + IPv6 SYN / NULL / FIN / Xmas / ACK / Window / Maimon, UDP with ICMP unreachable listener, SCTP (INIT / COOKIE_ECHO), IP-protocol scan (-sO), idle scan via zombie (-sI), FTP bounce (-b), traceroute, --resume JSON checkpoints, ARP ping on local subnets, custom DNS via hickory-resolver, SOCKS4 + HTTP CONNECT proxies, OS detection scored against nmap-os-db MatchPoints, version detection against nmap-service-probes (TLS via rustls). What it intentionally does not ship: the full NSE Lua runtime.
Quickstart
Install from crates.io or source. The binary is published twice — nmaprs (long) and nms (short, quicker to type):
# install cargo install nmaprs # from source git clone https://github.com/MenkeTechnologies/nmaprs cd nmaprs && cargo build --release sudo cp target/release/nmaprs /usr/local/sbin/ # everyday scans (privileged forms use sudo) nmaprs scanme.nmap.org # default TCP connect, top-1000 sudo nmaprs -sS -F 192.168.1.0/24 # raw SYN, top-100 ports sudo nmaprs -A -T4 -oA scan target # aggressive (-O + -sV + -sC + traceroute) sudo nmaprs -sU --top-ports 100 target # UDP top-100 sudo nmaprs -sY -p 80,443 sctp-host # SCTP INIT sudo nmaprs -sO target # IP protocol scan (0..=255) sudo nmaprs -sI zombie.host:65535 target # idle scan sudo nmaprs --iL hosts.txt -oG out.gnmap # batch w/ grepable output # resume after Ctrl-C sudo nmaprs --resume nmaprs.checkpoint.json # nmap-compatible pipelines sudo nmaprs -oX - target | xmllint --format - sudo nmaprs -oG - target | grep '/open/'
Full reference: README or man nmaprsall (1028-line full reference under man/man1/nmaprsall.1). Short form: man nmaprs. Zsh completions ship via nmaprs --completions zsh if built.
Scan techniques — one card per probe
-sT · TCP connect
Default when unprivileged. Async, parallel, timeout-bound. Goes through SOCKS4 / HTTP CONNECT when --proxies is set.
-sS · TCP SYN (raw)
Default when root. Raw IPv4 + IPv6 via pnet. Pipelined recv + main-thread sends; sharded up to 16 concurrent pipelines per family. Falls back to connect on raw failure.
-sN / -sF / -sX / -sM
NULL, FIN, Xmas, Maimon. Same raw sharded pipeline as -sS. Maimon sends FIN+ACK.
-sA / -sW
ACK (firewall mapping: RST → unfiltered) and Window (RST nonzero-win → open). No connect fallback.
-sU · UDP
Reply → open; ICMP port-unreachable → closed; other unreachable → filtered. Single poll(2)+burst-recv listener thread on Unix.
-sY / -sZ · SCTP
INIT or COOKIE_ECHO. CRC32c segments; IPv4 layer-3, IPv6 raw SCTP (proto 132). Pipelined + sharded per family. INIT-ACK / COOKIE-ACK → open, ABORT → closed.
-sO · IP protocol
Probes 0..=255 (or just nmap-protocols with -F). IPv4: raw IPv4 headers; IPv6: IPPROTO_RAW+IPV6_HDRINCL. ICMPv4 / ICMPv6 protocol-unreachable → closed.
-sI · Idle scan
Spoofed SYN with source = zombie; sequential IP-ID delta sampling. Delta ≥ 2 → open. IPv4 only, privileged.
-b · FTP bounce
Parallel buffer_unordered sessions, one control conn per probe. IPv4 only (PORT). Maps 150/125/250 vs 425/426/421 to open/closed.
-sn · Ping scan
Raw ICMP echo via pnet, falls back to system ping / ping6. Output paths (-oN / -oG / -oX / -oS) write host-up lines like the port-scan path.
--traceroute
System traceroute; up to min(parallelism, 32) hosts concurrent. Output stays in target order.
Discovery (-P*)
SYN / ACK / UDP / SCTP / IP-proto / ICMP-echo / timestamp / mask / ARP. Auto ARP on local IPv4 subnets unless --disable-arp-ping.
Selection & port grammar
nmaprs scanme.nmap.org 10.0.0.0/24 2001:db8::/64 # hostnames + CIDR (-6 for IPv6) nmaprs --iL targets.txt # file (one per line, multiple -iL OK) nmaprs --iR 100 # 100 random hosts nmaprs --exclude 10.0.0.0/16,192.0.2.7 # skip these nmaprs --excludefile skip.txt nmaprs --resolve-all api.example.com # scan every DNS-resolved address # port spec nmaprs -p 22,80,443 # explicit list nmaprs -p 1-65535 # range (or -p -) nmaprs -p U:53,T:22,8000-9000 # mixed UDP/TCP nmaprs -p T:22,U:53 -sS -sU # SYN scan TCP, UDP scan UDP nmaprs -F # top-100 (embedded freq list) nmaprs --top-ports 1000 # top-N by frequency nmaprs --port-ratio 0.001 # all ports with ratio ≥ threshold # raw TCP flag override (only when scan type is raw TCP) nmaprs -sS --scanflags 'SYN ACK URG' # custom flag set
Output formats — nmap-compatible
-oN · Normal
Human-readable text (default to stdout). Matches nmap's interactive output shape.
-oG · Grepable
One host per line; easy grep '/open/' / awk '$5 ~ /open/' pipelines.
-oX · XML
Nmap-compatible <nmaprun> root with <scaninfo>, <host>, <status>, <address>, <hostnames>, <ports>, <extraports>, <service>, <runstats>. Existing nmap XML parsers should ingest it.
-oA · All three
Writes BASE.nmap / BASE.gnmap / BASE.xml in one go.
-oS · Script kiddie
1337-speak mirror of -oN lines. Stdout stays normal — only the file is leet.
-oM / -oH
Partial parity: -oM currently writes the same lines as -oG; -oH is a placeholder for full hex.
Timing & performance dials
# timing template (T0..T5: paranoid / sneaky / polite / normal / aggressive / insane) nmaprs -T4 target # global probe-rate caps (one limiter; shared across IPv4+IPv6) nmaprs --min-rate 100 --max-rate 5000 target # parallelism bounds (overrides timing template when set) nmaprs --min-parallelism 4 --max-parallelism 256 target nmaprs -M 256 target # short for --max-parallelism # host batching (random in [min, max] when both set) nmaprs --min-hostgroup 16 --max-hostgroup 64 --iL big-list.txt # per-probe RTT bounds (adaptive timeout floors/ceilings) nmaprs --min-rtt-timeout 50ms --initial-rtt-timeout 200ms --max-rtt-timeout 2s target # per-host wall clock + retries nmaprs --host-timeout 5m --max-retries 2 target # scan delay (uniform random in [min, max] when both set) nmaprs --scan-delay 100ms --max-scan-delay 500ms target # rate-limit-aware nmaprs --defeat-rst-ratelimit --defeat-icmp-ratelimit target # periodic progress to stderr nmaprs -sS --stats-every 30s target
Evasion (raw scans only)
All flags below are wired at the packet level for raw TCP scans (-sS, -sN, -sF, -sX, -sM, -sA, -sW):
nmaprs -sS -g 53 target # spoofed source port (DNS-friendly) nmaprs -sS --ttl 33 target # custom IP TTL nmaprs -sS --badsum target # bad TCP/UDP/SCTP checksum nmaprs -sS -D RND:5,ME,1.2.3.4 target # decoy cloak (RND:N = N random) nmaprs -sS -S 192.0.2.1 -e eth0 target # spoof source IP (needs --send-eth) nmaprs -sS --data DEADBEEFCAFE target # raw hex payload appended nmaprs -sS --data-string 'GET / HTTP/1.0' target nmaprs -sS --data-length 64 target # N random payload bytes nmaprs -sS -f target # fragment (8-byte chunks) nmaprs -sS --mtu 24 target # custom fragment MTU nmaprs -sS --spoof-mac 00:11:22:33:44:55 target # spoof source MAC on ARP frames
Parity matrix vs nmap (abridged)
| Area | Status |
|---|---|
TCP connect (-sT) | Implemented |
TCP SYN raw (-sS, IPv4 + IPv6, sharded pipeline) | Implemented |
| NULL / FIN / Xmas / Maimon / ACK / Window | Implemented |
UDP (-sU) with ICMP unreach listener | Implemented |
SCTP INIT / COOKIE-ECHO (-sY / -sZ) | Implemented |
Idle scan (-sI) | Implemented (IPv4 only) |
FTP bounce (-b) | Implemented (IPv4 only) |
IP protocol scan (-sO) | Implemented (IPv4 + IPv6 on Unix) |
Host discovery (-P*, ARP auto) | Implemented |
IPv6 (-6) | Implemented |
| Traceroute (system binary, concurrent) | Implemented |
--resume JSON checkpoint | Implemented |
Evasion (-g, --ttl, --badsum, -D, -S, --data*, -f/--mtu, --spoof-mac) | Implemented (packet-level) |
--proxies / --proxy (SOCKS4 + HTTP CONNECT) | Implemented |
--dns-servers (hickory-resolver) | Implemented |
Auto privilege detect (geteuid) | Implemented |
Output: -oN / -oG / -oX / -oA / -oS | Implemented (nmap-compatible XML) |
| Timing template / rate caps / parallelism / hostgroup / RTT / retries / scan-delay / stats-every | Implemented |
OS detection (-O) | Partial — IPv4 raw + nmap-os-db MatchPoints; IPv6 TTL only |
Service / version (-sV) | Partial — no Perl-only regex features; rest implemented |
--script / -sC | Partial — default + banner builtins only |
-oM / -oH | Partial — -oM = grepable; -oH placeholder |
| NSE Lua runtime | Not implemented (use nmap) |
Full parity table (50+ rows) lives in the README "TRUTH TABLE" section.
Architecture in one screen
src/ ├── main.rs # CLI dispatch (clap), privilege detect, top-level scan loop ├── cli.rs # 128 clap args, nmap-compatible long/short option set ├── lib.rs # public API for programmatic use (re-exports core types) ├── bin/nms.rs # short-name launcher (alias) ├── scan/ │ ├── tcp_connect.rs # async tokio TcpStream (incl. SOCKS4 / HTTP CONNECT) │ ├── raw_tcp.rs # SYN/NULL/FIN/Xmas/ACK/Window/Maimon (pnet, sharded pipeline) │ ├── udp.rs # UDP probe + raw ICMP unreach listener │ ├── sctp.rs # SCTP INIT / COOKIE_ECHO (CRC32c) │ ├── ip_proto.rs # -sO (IPv4 + IPv6 raw) │ ├── idle.rs # -sI zombie IP-ID sampling │ ├── ftp_bounce.rs # -b parallel control sessions │ ├── ping.rs # -sn + -P* discovery dispatch │ └── arp.rs # ARP on local IPv4 subnets ├── service_probes.rs # nmap-service-probes parser + matcher (regex crate) ├── os_db.rs # nmap-os-db MatchPoints scoring (subject fingerprint) ├── output/ │ ├── normal.rs # -oN │ ├── grepable.rs # -oG / -oM │ ├── xml.rs # -oX (nmap-compatible <nmaprun>) │ └── skiddie.rs # -oS ├── resume.rs # JSON checkpoint format ├── rate.rs # --min-rate / --max-rate global limiter ├── resolver.rs # hickory-resolver wrapper + --dns-servers ├── parallelism.rs # timing template ↔ parallelism inference └── data/ # embedded nmap-services, nmap-protocols, ... man/man1/ ├── nmaprs.1 # man page — short reference (roff) └── nmaprsall.1 # man page — full reference (1028 lines)
Two binaries (nmaprs + nms — same code, short alias), comprehensive man pages (man nmaprs + man nmaprsall).
Pipelined raw I/O — why this is fast
Per address family (IPv4 + IPv6), raw scans spin up:
- Dedicated recv thread — one
poll(2)blocking on the raw socket, dispatches frames to per-target oneshot channels. - Main-thread sends — serial within a shard, but up to 16 shards per family run concurrently (bounded by
effective_probe_concurrency()). - Mixed v4+v6 targets run both families concurrently via
tokio::join. - Recv-key registration before send — eliminates the classic "reply landed before we knew to listen" race that ad-hoc raw scanners hit at high parallelism.
- One ICMP unreach listener thread per scan (not per batch) for UDP / SCTP / IP-proto.
- Global rate limiter shared across IPv4 + IPv6 —
--min-rate/--max-ratebehave like nmap, not per-family.
For OS detection, IPv4 raw probes build a subject fingerprint (SEQ / OPS / WIN subset; more in progress) and score it against nmap-os-db entries with the same MatchPoints + expr_match algorithm nmap uses.
Compatibility
| Platform | Status |
|---|---|
| Linux (x86_64 + aarch64) | All scan types, raw + connect |
| macOS (arm64 + x86_64) | All scan types; IPv6 -sO requires Unix raw (works) |
| FreeBSD | All scan types |
| Windows | TCP connect + UDP via system socket only; raw modes not built (no pnet raw) |
Security & ethics
Run nmaprs only against networks and hosts you own or have explicit written permission to scan. Unauthorized scanning is illegal in many jurisdictions. The author and contributors disclaim responsibility for misuse.
This tool exists because Rust gives us a memory-safe, parallel-first foundation to rebuild one of the most useful tools in the security community. The CLI parity goal is to let your existing nmap scripts, integrations, and pipelines keep working.