[*] Target: 192.168.1.100 [*] Port range: 1-1024 [*] Threads: 100 Timeout: 1000ms [*] Resolved 192.168.1.100 -> 192.168.1.100 [*] Scanning 1024 ports with 100 threads... [+] 22/tcp open ssh [+] 80/tcp open http [+] 443/tcp open https [+] 3306/tcp open mysql ⚠ ────────────────────────────────────────────────────────── Scan Results for: 192.168.1.100 ────────────────────────────────────────────────────────── Host Status : UP (2.31ms latency) OS Guess : Linux (web server stack) (confidence: low-medium) Ports Scanned: 1024 Open Ports : 4 Scan Time : 3842ms PORT STATE SERVICE VERSION/INFO ───────────────────────────────────────────────────── 22/tcp open ssh | OpenSSH_8.9p1 80/tcp open http | Apache/2.4.54 443/tcp open https 3306/tcp open mysql ⚠ ⚠ SECURITY NOTES: • Port 3306 (mysql): Databases exposed to the network. Verify this is intentional and access is restricted.
Requires Zig 0.13+. No other dependencies — not even libpcap.
Get Zig at ziglang.org/download.
The binary is fully static: copy it to any machine and it runs.
SYN scan requires root or CAP_NET_RAW.
- [+] TCP Connect scan — full handshake, no root required, reliable
- [+] TCP SYN scan — half-open stealth scan (root / CAP_NET_RAW)
- [+] UDP scan — probes common UDP services with protocol payloads
- [+] Ping / host discovery mode — liveness check without port scan
- [+] Atomic work-stealing thread pool — up to 5000 concurrent threads
- [+] Banner grabbing — reads what services say when you connect
- [+] Version detection — parses SSH, HTTP, FTP banners into clean strings
- [+] OS fingerprinting — heuristic from port patterns + banner content
- [+] Web framework detection — Apache, nginx, IIS, Express, Flask, Tomcat
- [+] ~70 port → service name mappings (Redis, Docker, K8s, Kafka…)
- [+] Security warnings for dangerously exposed services
- [+] Real-time port discovery output during scan
- [+] JSON export — full structured output for SIEM / pipeline use
- [+] Flexible port ranges —
80,1-1024,top,all - [+] Hostname resolution — shows resolved IP alongside target
- [+] Zero external dependencies — entire tool is Zig stdlib
- [+] Single static binary — no runtime, no interpreter, no install
- [ ] IPv6 support — planned
- [ ] CIDR range scanning — planned
- [ ] NSE-style scripting — not planned (use nmap for that)
| Flag | Mode | Description | Root? |
|---|---|---|---|
| (default) | TCP Connect | Full three-way handshake. Reliable, logged by target. | No |
| -sS / --syn | TCP SYN | Half-open scan. Sends SYN, never completes handshake. Faster, less logged. | Yes |
| -sU / --udp | UDP | Probes common UDP services. Slow by nature — no handshake to confirm open/closed. | No |
| -sn / --ping | Ping / Discovery | Host liveness only — attempts TCP to ports 80, 443, 22, 8080. No port scan. | No |
| Flag | Description | Default |
|---|---|---|
| -p / --ports | Port range: 80, 1-1024, top, all / 1-65535 | 1-1024 |
| -t / --threads | Concurrent scanning threads (1–5000) | 100 |
| --timeout | Connection timeout in milliseconds | 1000ms |
| -sS / --syn | TCP SYN stealth scan (root required) | — |
| -sU / --udp | UDP scan mode | — |
| -sn / --ping | Ping / host discovery only, no port scan | — |
| -sV / --service-detect | Banner grabbing + version parsing on open ports | — |
| -O / --os-detect | OS fingerprinting (heuristic — low-medium confidence) | — |
| -v / --verbose | Verbose output — shows raw banners, extra detail | — |
| -o / --output | Write results as JSON to specified file | — |
| -h / --help | Show help and exit | — |
| -V / --version | Print version string and exit | — |
| Config | Port Range | Time | Notes |
|---|---|---|---|
| Default (100t, 1000ms) | 1-1024 | ~4s | Good general use |
| Fast (500t, 300ms) | 1-1024 | ~1s | May miss some filtered |
| Default (100t, 1000ms) | 1-65535 | ~4.5 min | Thorough, safe |
| Fast (500t, 300ms) | 1-65535 | ~45s | Fast, potentially noisy |
| Aggressive (1000t, 200ms) | 1-65535 | ~20s | Only when you need it |
--timeout 3000 or higher for internet targets.
High thread counts on slow links can cause packet loss — tune down threads, tune up timeout.
| Port | Service | Why it's flagged |
|---|---|---|
| 21 | FTP | Credentials transmitted in plaintext |
| 23 | Telnet | Entirely unencrypted. Retire it. |
| 2375 | Docker API | Unauthenticated = instant full host compromise |
| 2379 | etcd | Contains K8s cluster secrets in plaintext |
| 3389 | RDP | Frequent brute force target, many known exploits |
| 5900 | VNC | Often deployed with weak or no authentication |
| 6379 | Redis | Default install has zero authentication |
| 9200 | Elasticsearch | Default allows unauthenticated read/write of all data |
| 27017 | MongoDB | Default install has no auth — infamous for data leaks |
| 3306/5432/1433 | MySQL/PG/MSSQL | Databases shouldn't be directly network-accessible |
| 6443 | K8s API | Full cluster administration if reachable without auth |
| Feature | zigscanner | nmap |
|---|---|---|
| TCP Connect scan | ✓ | ✓ |
| TCP SYN scan | ✓ simplified | ✓ full |
| UDP scan | ✓ basic | ✓ comprehensive |
| IPv6 | ✗ planned | ✓ |
| CIDR ranges | ✗ planned | ✓ |
| NSE scripting engine | ✗ by design | ✓ thousands of scripts |
| OS fingerprinting | ✓ heuristic | ✓ ML-based, accurate |
| Version detection | ✓ banner parsing | ✓ signature database |
| Zero external deps | ✓ | ✗ libpcap, OpenSSL… |
| Single static binary | ✓ | ✗ |
| Cross-compilation (trivial) | ✓ | ✗ |
| Readable codebase | ✓ ~1500 lines | ✗ 100k+ lines C |
| JSON output native | ✓ | ✗ |
| Years of development | 1 | 27 |
The thread model uses an atomic work-stealing counter. Rather than pre-assigning port ranges to threads,
each worker calls fetchAdd on a shared atomic u32 to claim the next port. Threads that
finish fast keep claiming work; threads blocked on a timeout don't starve other threads. No deadlock possible —
the only mutex is on the results list, held only when appending an open port.
Memory management follows Zig's ownership convention: whoever allocates, frees. All allocations go through
a GeneralPurposeAllocator which reports leaks in debug builds. Banner strings are heap-allocated
(size unknown at compile time). Service names are string literals (static lifetime, no allocation).
The terminal panel in the output is not a PTY. OS fingerprinting is explicitly low-to-medium confidence — containers, Samba on Linux, and custom banners routinely fool heuristics. Treat OS guesses as starting hypotheses, not conclusions.