← All lab notes

Building a Rust Port Scanner

A weekend experiment: a TCP connect scanner in Rust, and what it taught me about sockets, timeouts, and concurrency.

Design

100%

Ok

Err

CLI args

target + ports

Resolve host

Spawn worker pool

N = 512 tasks

TcpStream::connect_timeout

Port OPEN

closed / filtered

Merge results

sorted output

Diagram source
flowchart TD
    A[CLI args\ntarget + ports] --> B[Resolve host]
    B --> C[Spawn worker pool\nN = 512 tasks]
    C --> D[TcpStream::connect_timeout]
    D -- Ok --> E[Port OPEN]
    D -- Err --> F[closed / filtered]
    E --> G[Merge results\nsorted output]
    F --> G

Class view of the core

100%

produces

throttles via

1

many

Scanner

-String target

-Vec_u16 ports

-usize concurrency

+scan() : Vec_PortStatus

«enumeration»

PortStatus

Open

Closed

Filtered

RateLimiter

-Duration interval

+acquire() : Future

Diagram source
classDiagram
    class Scanner {
        -String target
        -Vec_u16 ports
        -usize concurrency
        +scan() Vec_PortStatus
    }
    class PortStatus {
        <<enumeration>>
        Open
        Closed
        Filtered
    }
    class RateLimiter {
        -Duration interval
        +acquire() Future
    }
    Scanner "1" --> "many" PortStatus : produces
    Scanner o-- RateLimiter : throttles via

Data model

100%

yields

SCAN

string

target

u16

port_range

int

workers

RESULT

u16

port

string

status

float

rtt_ms

Diagram source
erDiagram
    SCAN ||--o{ RESULT : yields
    SCAN {
        string target
        u16 port_range
        int workers
    }
    RESULT {
        u16 port
        string status
        float rtt_ms
    }

First benchmark

Scanning scanme.nmap.org ports 1–1024:

WorkersTime (s)
141.2
642.9
5120.8

Lesson: the bottleneck was never the socket API — it was my initial sequential loop. Concurrency is the design decision here.