nmaprs — Documentation
Description: nmaprs — Rust-native network scanner with nmap-compatible CLI. Real TCP connect, raw SYN/NULL/FIN/Xmas/ACK/Window/Maimon, UDP, ICMP, SCTP INIT/COOKIE_ECHO, IP protocol scan, idle scan, FTP bounce, IPv6, traceroute, --resume, OS detection via nmap-os-db MatchPoints, version detection via nmap-service-probes. Pipelined raw send/recv, sharded up to 16 concurrent pipelines per family.

// Color scheme

## >_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-rate` behave 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.