Technical Specifications v2.0

Comprehensive technical specifications for ProRT-IP WarScan network scanner. This reference documents system requirements, protocol specifications, packet formats, scanning techniques, detection engines, data structures, and file formats.

Version: 2.0 Last Updated: November 2025 Status: Production


System Requirements

Hardware Requirements

Minimum Configuration (Small Networks)

ComponentRequirementPurpose
CPU2 cores @ 2.0 GHzBasic scanning operations
RAM2 GBSmall network scans (<1,000 hosts)
Storage100 MBBinary + dependencies
Network100 MbpsBasic throughput (~10K pps)

Supported Workloads:

  • Single-target scans
  • Port range: 1-1000 ports
  • Network size: <1,000 hosts
  • Scan types: TCP SYN, Connect
  • No service detection
ComponentRequirementPurpose
CPU8+ cores @ 3.0 GHzParallel scanning, high throughput
RAM16 GBLarge network scans (100K+ hosts)
Storage1 GB SSDFast result database operations
Network1 Gbps+High-speed scanning (100K pps)

Supported Workloads:

  • Multi-target scans (100K+ hosts)
  • All 65,535 ports
  • Scan types: All 8 types (SYN, Connect, UDP, FIN, NULL, Xmas, ACK, Idle)
  • Service detection + OS fingerprinting
  • Database storage

High-Performance Configuration (Internet-Scale)

ComponentRequirementPurpose
CPU16+ cores @ 3.5+ GHzInternet-scale scanning
RAM32+ GBStateful scanning of millions of targets
Storage10+ GB NVMe SSDMassive result storage
Network10 Gbps+Maximum throughput (1M+ pps)
NIC FeaturesRSS, multi-queue, SR-IOVPacket distribution across cores

Supported Workloads:

  • Internet-wide IPv4 scans (3.7B hosts)
  • All protocols (TCP, UDP, ICMP, IPv6)
  • Stateless scanning at 10M+ pps
  • NUMA-optimized packet processing
  • Real-time streaming to database

NIC Requirements:

  • RSS (Receive Side Scaling): Distribute packets across CPU cores
  • Multi-Queue: Multiple TX/RX queues (16+ recommended)
  • SR-IOV: Direct NIC hardware access for VMs
  • Hardware Offloading: TCP checksum, segmentation offload

Software Requirements

Operating Systems

Linux (Primary Platform):

Supported Distributions:

  • Ubuntu 20.04+ LTS / 22.04+ LTS
  • Debian 11+ (Bullseye) / 12+ (Bookworm)
  • Fedora 35+ / 38+
  • RHEL 8+ / 9+ (Red Hat Enterprise Linux)
  • Arch Linux (rolling release)
  • CentOS Stream 8+ / 9+

Kernel Requirements:

  • Minimum: 4.15+ (for sendmmsg/recvmmsg syscalls)
  • Recommended: 5.x+ (for eBPF/XDP support)
  • Optimal: 6.x+ (latest performance improvements)

System Packages:

# Debian/Ubuntu
sudo apt install libpcap-dev pkg-config libssl-dev

# Fedora/RHEL/CentOS
sudo dnf install libpcap-devel pkgconfig openssl-devel

# Arch Linux
sudo pacman -S libpcap pkg-config openssl

Runtime Libraries:

  • libpcap 1.9+ (packet capture)
  • OpenSSL 1.1+ or 3.x (TLS certificate analysis)
  • glibc 2.27+ (standard C library)

Windows:

Supported Versions:

  • Windows 10 (version 1809+)
  • Windows 11 (all versions)
  • Windows Server 2016+
  • Windows Server 2019+
  • Windows Server 2022+

Requirements:

  • Npcap 1.70+ (packet capture driver) - Download
  • Visual C++ Redistributable 2019+ (runtime libraries)
  • Administrator privileges (required for raw packet access)

Installation:

# Download and install Npcap
# Enable "WinPcap API-compatible Mode" during installation
# Restart computer after Npcap installation

# Verify installation
prtip --version

Known Limitations:

  • FIN/NULL/Xmas scans not supported (Windows TCP/IP stack limitation)
  • Administrator privileges required (no capability-based alternative)
  • SYN discovery tests fail on loopback (127.0.0.1) - expected Npcap behavior

macOS:

Supported Versions:

  • macOS 11.0+ (Big Sur) - Intel & Apple Silicon
  • macOS 12.0+ (Monterey) - M1/M2 chips
  • macOS 13.0+ (Ventura) - M1/M2/M3 chips
  • macOS 14.0+ (Sonoma) - M1/M2/M3/M4 chips

Requirements:

  • Xcode Command Line Tools (clang compiler)
  • libpcap (pre-installed on macOS)
  • Root privileges OR access_bpf group membership

Setup BPF Access (Recommended):

# Grant user BPF device access (avoids sudo)
sudo dseditgroup -o edit -a $(whoami) -t user access_bpf

# Verify group membership
dseditgroup -o checkmember -m $(whoami) access_bpf

# Logout and login for changes to take effect

Installation:

# Remove quarantine attribute (macOS Gatekeeper)
xattr -d com.apple.quarantine /usr/local/bin/prtip

# Verify installation
prtip --version

Runtime Dependencies

Rust Dependency Tree (from Cargo.toml):

[dependencies]
# Core runtime (required)
tokio = { version = "1.35", features = ["full"] }
pnet = "0.34"                  # Packet manipulation
pcap = "1.1"                   # Packet capture (libpcap wrapper)
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"             # JSON serialization

# Networking
socket2 = "0.5"                # Low-level socket operations
etherparse = "0.13"            # Ethernet/IP/TCP/UDP parsing

# Async utilities
tokio-util = "0.7"
futures = "0.3"
crossbeam = "0.8"              # Lock-free data structures

# CLI
clap = { version = "4.4", features = ["derive", "cargo"] }
colored = "2.0"                # Terminal colors

# Database (optional features)
rusqlite = { version = "0.30", optional = true }
sqlx = { version = "0.7", features = ["sqlite", "postgres"], optional = true }

# Plugin system (optional)
mlua = { version = "0.9", features = ["lua54", "send"], optional = true }

# Cryptography
ring = "0.17"                  # SipHash for stateless cookies
x509-parser = "0.15"           # TLS certificate parsing

# Logging
tracing = "0.1"
tracing-subscriber = "0.3"

Feature Flags:

# Default build (SQLite + plugins)
cargo build --release

# Minimal build (no database, no plugins)
cargo build --release --no-default-features

# PostgreSQL support
cargo build --release --features postgres

# All features
cargo build --release --all-features

Network Protocol Specifications

Ethernet (Layer 2)

Frame Format

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Destination MAC Address                    |
+                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                               |                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
|                      Source MAC Address                       |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|           EtherType           |          Payload...           |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Field Specifications:

FieldSizeDescriptionCommon Values
Destination MAC6 bytesTarget MAC addressFF:FF:FF:FF:FF:FF (broadcast)
Source MAC6 bytesScanner's MAC addressInterface MAC
EtherType2 bytesProtocol identifier0x0800 (IPv4), 0x0806 (ARP), 0x86DD (IPv6)

ProRT-IP Implementation:

  • Automatically discovers gateway MAC via ARP for remote targets
  • Uses broadcast MAC for LAN scans
  • Supports VLAN tagging (802.1Q) when --vlan flag specified

IPv4 (Layer 3)

Header Format

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Version|  IHL  |Type of Service|          Total Length         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|         Identification        |Flags|      Fragment Offset    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|  Time to Live |    Protocol   |         Header Checksum       |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                       Source IP Address                       |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Destination IP Address                     |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Options (if IHL > 5)                       |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Field Specifications:

FieldSizeDescriptionProRT-IP Default
Version4 bitsIP version4 (IPv4)
IHL4 bitsHeader length in 32-bit words5 (20 bytes, no options)
ToS/DSCP8 bitsType of Service0 (default, configurable with --tos)
Total Length16 bitsEntire packet sizeVariable (header + TCP/UDP)
Identification16 bitsFragment identificationRandom (per packet)
Flags3 bitsDF, MF, ReservedDF=1 (Don't Fragment)
Fragment Offset13 bitsFragment position0 (no fragmentation)
TTL8 bitsTime To Live64 (Linux default), configurable with --ttl
Protocol8 bitsUpper layer protocol6 (TCP), 17 (UDP), 1 (ICMP)
Header Checksum16 bitsOne's complement checksumCalculated automatically
Source IP32 bitsScanner's IP addressInterface IP (configurable with -S)
Destination IP32 bitsTarget IP addressUser-specified target

Fragmentation Support:

ProRT-IP supports IP fragmentation for firewall evasion (-f flag):

# Fragment packets into 8-byte segments
prtip -f -sS -p 80,443 192.168.1.1

# Custom MTU (Maximum Transmission Unit)
prtip --mtu 16 -sS -p 80,443 192.168.1.1

TCP (Layer 4)

Header Format

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|          Source Port          |       Destination Port        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                        Sequence Number                        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Acknowledgment Number                      |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|  Data |       |C|E|U|A|P|R|S|F|                               |
| Offset| Rsrvd |W|C|R|C|S|S|Y|I|            Window             |
|       |       |R|E|G|K|H|T|N|N|                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|           Checksum            |         Urgent Pointer        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Options (if Data Offset > 5)               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Field Specifications:

FieldSizeDescriptionProRT-IP Default
Source Port16 bitsScanner's source portRandom 1024-65535 (configurable with -g)
Destination Port16 bitsTarget port being scannedUser-specified (-p flag)
Sequence Number32 bitsInitial sequence numberRandom (SYN scan), SipHash-derived (stateless)
Acknowledgment Number32 bitsACK number0 (SYN scan), varies (Connect scan)
Data Offset4 bitsHeader length in 32-bit words5 (20 bytes) or 6 (24 bytes with MSS)
Flags8 bitsCWR, ECE, URG, ACK, PSH, RST, SYN, FINScan-type dependent
Window16 bitsReceive window size64240 (typical), 65535 (max)
Checksum16 bitsTCP checksum (includes pseudo-header)Calculated automatically
Urgent Pointer16 bitsUrgent data pointer0 (not used in scanning)

TCP Flag Combinations by Scan Type:

Scan TypeSYNFINRSTACKPSHURGUse Case
SYN (-sS)100000Stealth, most common
Connect (-sT)100000Full TCP handshake
FIN (-sF)010000Firewall evasion
NULL (-sN)000000Stealth scan
Xmas (-sX)010011Named for "lit up" flags
ACK (-sA)000100Firewall rule detection

TCP Options

Common Options Used in Scanning:

OptionKindLengthDataPurpose
EOL (End of Option List)01-Terminates option list
NOP (No Operation)11-Padding for alignment
MSS (Maximum Segment Size)242 bytesMaximum segment size (typical: 1460)
Window Scale331 byteWindow scaling factor (0-14)
SACK Permitted42-Selective ACK support
Timestamp8108 bytesTimestamps (TSval, TSecr)

Standard Option Ordering (for OS fingerprinting):

MSS, NOP, Window Scale, NOP, NOP, Timestamp, SACK Permitted, EOL

Example (24-byte TCP header with MSS option):

Data Offset: 6 (24 bytes)
Options:
  - MSS: Kind=2, Length=4, Value=1460
  - EOL: Kind=0

UDP (Layer 4)

Header Format

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|          Source Port          |       Destination Port        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|            Length             |           Checksum            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                         Payload...                            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Field Specifications:

FieldSizeDescriptionProRT-IP Default
Source Port16 bitsScanner's source portRandom 1024-65535
Destination Port16 bitsTarget UDP portUser-specified (-p)
Length16 bitsHeader + payload lengthVariable (8 + payload_len)
Checksum16 bitsUDP checksum (optional)Calculated (0 if disabled)

UDP Scan Challenges:

UDP scanning is 10-100x slower than TCP due to:

  1. No handshake: Cannot determine "open" without application response
  2. ICMP rate limiting: Many firewalls/routers rate-limit ICMP unreachable messages
  3. Stateless: Requires protocol-specific payloads to elicit responses

Protocol-Specific Payloads:

ProRT-IP includes built-in payloads for common UDP services:

PortServicePayload TypeExpected Response
53DNSStandard DNS A queryDNS response or ICMP unreachable
161SNMPGetRequest (community: public)GetResponse or ICMP unreachable
123NTPNTP version 3 queryNTP response or ICMP unreachable
137NetBIOSNBNS name queryName response or ICMP unreachable
111RPC (Portmapper)NULL procedure callRPC response or ICMP unreachable
500ISAKMP (IKE)IKE SA INITIKE response or ICMP unreachable
1900UPnP (SSDP)M-SEARCH discoverySSDP response or ICMP unreachable

ICMP (Layer 3/4)

Echo Request/Reply Format

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|     Type      |     Code      |          Checksum             |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|           Identifier          |        Sequence Number        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                         Payload...                            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Type/Code Combinations:

TypeCodeMeaningUse in ProRT-IP
00Echo ReplyHost discovery confirmation
30Network UnreachableTarget network filtered
31Host UnreachableTarget host filtered
33Port UnreachableUDP scan: port closed
39Network ProhibitedFirewall blocking
310Host ProhibitedFirewall blocking
313Admin ProhibitedRate limiting triggered
80Echo RequestHost discovery probe
110Time ExceededTraceroute (TTL=0)
130Timestamp RequestOS fingerprinting probe
170Address Mask RequestOS fingerprinting probe

ICMP Rate Limiting Detection:

ProRT-IP includes adaptive rate limiting based on ICMP Type 3 Code 13 responses:

# Enable adaptive rate limiting (monitors ICMP unreachable messages)
prtip -sS -p 1-1000 --adaptive-rate 192.168.1.0/24

Backoff Levels:

  • Level 0: No backoff (initial state)
  • Level 1: 2 seconds backoff
  • Level 2: 4 seconds backoff
  • Level 3: 8 seconds backoff
  • Level 4: 16 seconds backoff (maximum)

Packet Format Specifications

TCP SYN Scan Packet (Complete Structure)

Full packet: 58 bytes (Ethernet + IPv4 + TCP with MSS)

#![allow(unused)]
fn main() {
// Ethernet Header (14 bytes)
[
    0x00, 0x11, 0x22, 0x33, 0x44, 0x55,  // Destination MAC (target or gateway)
    0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,  // Source MAC (scanner's interface)
    0x08, 0x00,                          // EtherType: IPv4 (0x0800)
]

// IPv4 Header (20 bytes, no options)
[
    0x45,              // Version (4) + IHL (5 = 20 bytes)
    0x00,              // DSCP (0) + ECN (0)
    0x00, 0x2C,        // Total Length: 44 bytes (20 IP + 24 TCP)
    0x12, 0x34,        // Identification: random (e.g., 0x1234)
    0x40, 0x00,        // Flags: DF (0x4000) + Fragment Offset (0)
    0x40,              // TTL: 64 (Linux default)
    0x06,              // Protocol: TCP (6)
    0x00, 0x00,        // Header Checksum (calculated, placeholder here)
    0x0A, 0x00, 0x00, 0x01,  // Source IP: 10.0.0.1
    0x0A, 0x00, 0x00, 0x02,  // Destination IP: 10.0.0.2
]

// TCP Header with MSS Option (24 bytes)
[
    0x30, 0x39,        // Source Port: 12345 (random 1024-65535)
    0x00, 0x50,        // Destination Port: 80 (HTTP)
    0xAB, 0xCD, 0xEF, 0x12,  // Sequence Number: random or SipHash-derived
    0x00, 0x00, 0x00, 0x00,  // Acknowledgment: 0 (not ACK flag)
    0x60,              // Data Offset: 6 (24 bytes) + Reserved (0)
    0x02,              // Flags: SYN (0x02)
    0xFF, 0xFF,        // Window: 65535 (maximum)
    0x00, 0x00,        // Checksum (calculated, placeholder here)
    0x00, 0x00,        // Urgent Pointer: 0 (not urgent)

    // TCP Options (4 bytes)
    0x02, 0x04,        // MSS: Kind=2, Length=4
    0x05, 0xB4,        // MSS Value: 1460 (typical Ethernet MTU 1500 - 40)
]
}

Checksum Calculation:

IPv4 Checksum:

#![allow(unused)]
fn main() {
// One's complement sum of 16-bit words
let mut sum: u32 = 0;
for chunk in header.chunks(2) {
    sum += u16::from_be_bytes([chunk[0], chunk[1]]) as u32;
}
while (sum >> 16) > 0 {
    sum = (sum & 0xFFFF) + (sum >> 16);
}
let checksum = !(sum as u16);
}

TCP Checksum (includes pseudo-header):

#![allow(unused)]
fn main() {
// Pseudo-header: Source IP (4) + Dest IP (4) + Zero (1) + Protocol (1) + TCP Length (2)
let pseudo_header = [
    src_ip[0], src_ip[1], src_ip[2], src_ip[3],
    dst_ip[0], dst_ip[1], dst_ip[2], dst_ip[3],
    0x00,
    0x06,  // Protocol: TCP
    (tcp_len >> 8) as u8, tcp_len as u8,
];
// Then checksum pseudo_header + TCP header + payload
}

UDP Scan Packet with DNS Payload

Full packet: 56 bytes (Ethernet + IPv4 + UDP + DNS)

#![allow(unused)]
fn main() {
// Ethernet Header (14 bytes) - same as above

// IPv4 Header (20 bytes)
[
    0x45,              // Version + IHL
    0x00,              // DSCP + ECN
    0x00, 0x2A,        // Total Length: 42 bytes (20 IP + 8 UDP + 14 DNS)
    0x56, 0x78,        // Identification: random
    0x00, 0x00,        // Flags: no DF + Fragment Offset: 0
    0x40,              // TTL: 64
    0x11,              // Protocol: UDP (17)
    0x00, 0x00,        // Checksum (calculated)
    0x0A, 0x00, 0x00, 0x01,  // Source IP
    0x0A, 0x00, 0x00, 0x02,  // Destination IP
]

// UDP Header (8 bytes)
[
    0x30, 0x39,        // Source Port: 12345
    0x00, 0x35,        // Destination Port: 53 (DNS)
    0x00, 0x16,        // Length: 22 bytes (8 UDP + 14 DNS)
    0x00, 0x00,        // Checksum: 0 (optional for IPv4)
]

// DNS Query Payload (14 bytes)
[
    0x12, 0x34,        // Transaction ID: random
    0x01, 0x00,        // Flags: Standard query, recursion desired
    0x00, 0x01,        // Questions: 1
    0x00, 0x00,        // Answer RRs: 0
    0x00, 0x00,        // Authority RRs: 0
    0x00, 0x00,        // Additional RRs: 0

    // Query for "." (DNS root)
    0x00,              // Name: root (zero-length label)
    0x00, 0x01,        // Type: A (host address)
    0x00, 0x01,        // Class: IN (Internet)
]
}

Scanning Technique Specifications

TCP SYN Scan (-sS)

Packet Sequence Diagram:

Scanner                           Target
   |                                 |
   |-------- SYN ------------------>|  (1) Probe: SYN flag set
   |                                 |
   |<------- SYN/ACK --------------|  (2a) OPEN: Responds with SYN/ACK
   |-------- RST ------------------>|  (3a) Reset connection (stealth)
   |                                 |
   |<------- RST ------------------|  (2b) CLOSED: Responds with RST
   |                                 |
   |         (timeout)               |  (2c) FILTERED: No response
   |                                 |
   |<------- ICMP Unreachable -----|  (2d) FILTERED: ICMP Type 3

State Determination Logic:

ResponsePort StateFlagsCode
SYN/ACK receivedOpenTCP: SYN+ACK-
RST receivedClosedTCP: RST-
ICMP Type 3 Code 1/2/3/9/10/13Filtered-ICMP unreachable
No response after timeout + retriesFiltered--

Timing Parameters by Template:

TemplateInitial TimeoutMax TimeoutMax RetriesScan Delay
T0 (Paranoid)300 sec300 sec55 min
T1 (Sneaky)15 sec15 sec515 sec
T2 (Polite)1 sec10 sec50.4 sec
T3 (Normal)1 sec10 sec20
T4 (Aggressive)500 ms1250 ms60
T5 (Insane)250 ms300 ms20

Example:

# Normal SYN scan (T3)
prtip -sS -p 80,443 192.168.1.1

# Aggressive scan (T4 - faster)
prtip -T4 -sS -p 1-10000 192.168.1.0/24

# Paranoid scan (T0 - stealth)
prtip -T0 -sS -p 22,23,3389 target.com

UDP Scan (-sU)

Packet Sequence Diagram:

Scanner                           Target
   |                                 |
   |-------- UDP ------------------>|  (1) Probe: UDP packet (with/without payload)
   |                                 |
   |<------- UDP Response ---------|  (2a) OPEN: Application responds
   |                                 |
   |<------- ICMP Type 3 Code 3 ---|  (2b) CLOSED: Port unreachable
   |                                 |
   |<------- ICMP Type 3 Other -----|  (2c) FILTERED: Other unreachable codes
   |                                 |
   |         (timeout)               |  (2d) OPEN|FILTERED: No response

State Determination Logic:

ResponsePort State
UDP response receivedOpen
ICMP Type 3 Code 3 (Port Unreachable)Closed
ICMP Type 3 Code 1/2/9/10/13Filtered
No response after timeoutOpen|Filtered (indeterminate)

UDP Scan Optimization:

ProRT-IP uses protocol-specific payloads to increase accuracy:

# UDP scan with protocol-specific probes
prtip -sU -p 53,161,123,137,111,500 192.168.1.1

Known Limitations:

  • 10-100x slower than TCP: ICMP rate limiting on routers/firewalls
  • Open|Filtered: Cannot distinguish without application response
  • Firewall Detection: Many firewalls silently drop UDP packets

Idle Scan (-sI zombie_host)

Packet Sequence Diagram:

Scanner          Zombie (Idle Host)        Target
   |               |                       |
   |-- SYN/ACK -->|                       |  (1) Probe zombie IPID
   |<--- RST -----|                       |
   | (IPID: 1000) |                       |
   |               |                       |
   |               |<------ SYN ----------|  (2) Spoof SYN from zombie to target
   |               |                       |
   |               |------- SYN/ACK ----->|  (3a) If port OPEN: Target sends SYN/ACK
   |               |<------ RST ----------|  (4a) Zombie responds with RST (IPID increments)
   |               |                       |
   |               |------- RST ---------->|  (3b) If port CLOSED: Target sends RST
   |               |       (no response)   |  (4b) Zombie does nothing (IPID unchanged)
   |               |                       |
   |-- SYN/ACK -->|                       |  (5) Re-probe zombie IPID
   |<--- RST -----|                       |
   | (IPID: 1002) |                       |  (IPID increased by 2 = PORT OPEN)
   | (IPID: 1001) |                       |  (IPID increased by 1 = PORT CLOSED/FILTERED)

IPID Interpretation:

IPID DeltaPort StateExplanation
+2OpenZombie sent RST in response to target's SYN/ACK (incremented by 1), plus scanner's probe (+1)
+1Closed or FilteredOnly scanner's probe incremented IPID (no traffic from zombie)
>+2IndeterminateZombie is receiving other traffic (not idle)

Zombie Host Requirements:

  1. Idle: Little to no network traffic (predictable IPID sequence)
  2. Incremental IPID: IP ID increments globally (not per-connection)
  3. Unfiltered: Responds to unsolicited SYN/ACK with RST

Zombie Suitability Test:

# Test if host is suitable as zombie
prtip --idle-scan-test potential_zombie_host

# Example output:
# Zombie Analysis: 192.168.1.100
#   IPID Generation: Incremental (GOOD)
#   Traffic Level: <5 pps (IDLE)
#   Responds to SYN/ACK: Yes (SUITABLE)
#   Recommendation: SUITABLE for idle scan

Idle Scan Usage:

# Perform idle scan using zombie host
prtip -sI 192.168.1.100 -p 80,443 target.com

Advantages:

  • Maximum anonymity: Target logs zombie's IP, not scanner's
  • Firewall bypass: Bypasses source IP-based filtering
  • No packets from scanner to target: Ultimate stealth

Disadvantages:

  • Requires idle zombie host: Difficult to find suitable zombies
  • Slower: Multiple probes per port (zombie probe → spoof → zombie probe)
  • 99.5% accuracy: Not 100% due to network timing variations

Detection Engine Specifications

OS Fingerprinting

16-Probe Sequence

ProRT-IP implements Nmap-compatible OS fingerprinting with 16 distinct probes:

Probe #TypeTarget PortFlagsPurposeKey Attributes
1TCPOpen portSYNInitial SYN probeISN, TCP options, window size
2TCPOpen portSYNISN probe (100ms later)ISN delta calculation
3TCPOpen portSYNISN probe (100ms later)ISN delta calculation
4TCPOpen portSYNISN probe (100ms later)ISN delta calculation
5TCPOpen portSYNISN probe (100ms later)ISN delta calculation
6TCPOpen portSYNISN probe (100ms later)ISN delta (GCD calculation)
7ICMPAnyEcho (TOS=0, code=0)ICMP echo responseDF flag, TTL, TOS handling
8ICMPAnyEcho (TOS=4, code=9)ICMP error handlingNon-standard code handling
9TCPOpen portECN, SYN, CWR, ECEECN support testECN echo, option handling
10TCPClosed portNULLNo flags setResponse to NULL scan
11TCPClosed portSYN+FIN+URG+PSHUnusual flagsUnusual flags handling
12TCPClosed portACKACK probeWindow value in RST
13TCPClosed portACK (window=128)Firewall detectionWindow scaling detection
14TCPClosed portACK (window=256)Firewall detectionWindow scaling detection
15TCPOpen portSYN (options vary)Option handlingOption ordering, values
16UDPClosed portEmpty UDP packetICMP unreachableICMP response analysis

Fingerprint Attributes Analyzed

TCP Initial Sequence Number (ISN) Analysis:

AttributeDescriptionCalculation
GCDGreatest common divisor of ISN deltasgcd(Δ1, Δ2, Δ3, Δ4, Δ5) where Δn = ISN(n+1) - ISN(n)
ISRISN counter rate (increments per second)avg(Δ1, Δ2, Δ3, Δ4, Δ5) / 0.1s
SPSequence predictability indexVariance in ISN deltas (0-255, 0=random, 255=sequential)

Example:

Probe 1: ISN = 1000000
Probe 2: ISN = 1001250  (Δ1 = 1250)
Probe 3: ISN = 1002500  (Δ2 = 1250)
Probe 4: ISN = 1003750  (Δ3 = 1250)
Probe 5: ISN = 1005000  (Δ4 = 1250)
Probe 6: ISN = 1006250  (Δ5 = 1250)

GCD = 1250
ISR = 1250 / 0.1s = 12,500 increments/sec
SP = 0 (no variance, highly predictable)

TCP Options Encoding:

ProRT-IP records the exact ordering and values of TCP options:

CodeOptionExample
MMSS (Maximum Segment Size)M1460 (MSS value 1460)
WWindow ScaleW7 (scale factor 7)
TTimestampT (timestamp present)
SSACK PermittedS (SACK supported)
EEOL (End of Option List)E
NNOP (No Operation)N

Example Option String:

Options: MNWNNTS
Breakdown:
  M = MSS (1460)
  N = NOP (padding)
  W = Window Scale (7)
  N = NOP (padding)
  N = NOP (padding)
  T = Timestamp
  S = SACK Permitted

IP ID Generation Patterns:

PatternCodeDescriptionExample OSes
IncrementalIGlobally incremental IP IDWindows, older Linux
Random IncrementalRIRandom but incrementalSome BSD variants
ZeroZAlways 0Some embedded systems
Broken IncrementBIIncremental with wrap issuesRare

Example Fingerprint:

OS: Linux 5.x
GCD: 1
ISR: 12800
SP: 0-5
TI: I  (TCP IPID incremental)
CI: I  (Closed port IPID incremental)
II: I  (ICMP IPID incremental)
SS: S  (SYN scan IPID sequence)
TS: 100HZ  (TCP timestamp frequency)
Options: MWNNTS
Window: 5840  (typical Linux)

Fingerprint Database

ProRT-IP includes a comprehensive OS fingerprint database:

#![allow(unused)]
fn main() {
// Location: crates/prtip-core/src/os_db.rs
pub struct OsDatabase {
    fingerprints: Vec<OsFingerprint>,  // 2,600+ fingerprints
    index: HashMap<String, Vec<usize>>,  // Fast lookup by attribute
}

pub struct OsFingerprint {
    pub name: String,              // "Linux 5.10-5.15"
    pub class: OsClass,            // OS family, vendor, type
    pub cpe: Vec<String>,          // CPE identifiers
    pub tests: FingerprintTests,   // All 16 probe results
}
}

Database Statistics:

  • Total Fingerprints: 2,600+
  • OS Families: 15+ (Linux, Windows, BSD, macOS, iOS, Android, etc.)
  • Vendors: 200+ (Microsoft, Apple, Cisco, Juniper, etc.)
  • Match Accuracy: 85-95% for common OSes

Service Version Detection

Probe Intensity Levels

ProRT-IP supports configurable probe intensity (0-9):

LevelProbes SentDurationUse Case
0Registered probes only<1 secExpected service (e.g., HTTP on port 80)
1Registered + NULL probe~2 secQuick check with null probe fallback
2-6Incremental3-8 secBalanced (increasingly thorough)
7Common + comprehensive~10 secDefault recommended
8Nearly all probes~20 secThorough detection
9All 187 probes~30 secExhaustive (slow)

Example:

# Default intensity (level 7)
prtip -sV -p 80,443 192.168.1.1

# Minimal intensity (level 0)
prtip -sV --version-intensity 0 -p 80,443 192.168.1.1

# Exhaustive intensity (level 9)
prtip -sV --version-intensity 9 -p 1-1000 192.168.1.1

nmap-service-probes Format

ProRT-IP uses Nmap-compatible service probe definitions:

Probe TCP GetRequest q|GET / HTTP/1.0\r\n\r\n|
rarity 1
ports 80,443,8080,8443,8000,8888,9000

match http m|^HTTP/1\.[01] (\d\d\d)| p/HTTP/ v/$1/
match http m|^Server: ([^\r\n]+)| p/$1/
match http m|^Server: Apache/([^\s]+)| p/Apache httpd/ v/$1/
match nginx m|^Server: nginx/([^\s]+)| p/nginx/ v/$1/

Probe TCP TLSSessionReq q|\x16\x03\x00\x00S\x01\x00\x00O\x03\x00|
rarity 2
ports 443,8443,8444,9443,4443,10443,12443,18091,18092

match ssl m|^\x16\x03[\x00\x01\x02\x03]|s p/SSL/ v/TLSv1/

Probe Components:

ComponentDescriptionExample
ProbeProtocol + NameTCP GetRequest
q|...|Query payload (hex or string)`q
rarityProbe frequency (1=common, 9=rare)rarity 1
portsTarget portsports 80,443,8080
matchRegex pattern`m
p/Product namep/Apache httpd/
v/Versionv/$1/ (from capture group)

Probe Database:

  • Total Probes: 187
  • Protocols Supported: HTTP, HTTPS, FTP, SSH, SMTP, POP3, IMAP, Telnet, RDP, VNC, MySQL, PostgreSQL, MongoDB, Redis, and 50+ more
  • Match Patterns: 1,200+ regex patterns

Detection Accuracy:

  • Common Services: 85-90% (HTTP, HTTPS, SSH, FTP)
  • Databases: 80-85% (MySQL, PostgreSQL, MongoDB)
  • Proprietary Protocols: 60-70% (vendor-specific)

Data Structures

ScanResult

Primary result structure for individual port scan results:

#![allow(unused)]
fn main() {
pub struct ScanResult {
    /// Target socket address (IP:port)
    pub target: SocketAddr,

    /// Port number (1-65535)
    pub port: u16,

    /// Protocol (TCP, UDP, SCTP)
    pub protocol: Protocol,

    /// Port state (Open, Closed, Filtered, etc.)
    pub state: PortState,

    /// Detected service information (if -sV used)
    pub service: Option<ServiceInfo>,

    /// Banner grabbed from service (if available)
    pub banner: Option<String>,

    /// Response time (latency)
    pub response_time: Duration,

    /// Timestamp of scan
    pub timestamp: SystemTime,
}

pub enum Protocol {
    Tcp,
    Udp,
    Sctp,
}

pub enum PortState {
    Open,           // Port accepting connections
    Closed,         // Port actively rejecting connections (RST)
    Filtered,       // Firewall/filter blocking access
    OpenFiltered,   // UDP scan: could be open or filtered
    ClosedFiltered, // Rare: IPID idle scan
    Unknown,        // Unexpected response
}

pub struct ServiceInfo {
    /// Service name (e.g., "http", "ssh", "mysql")
    pub name: String,

    /// Service version (e.g., "2.4.52")
    pub version: Option<String>,

    /// Product name (e.g., "Apache httpd", "OpenSSH")
    pub product: Option<String>,

    /// CPE identifier (if available)
    pub cpe: Option<String>,

    /// OS hint from service banner
    pub os_hint: Option<String>,
}
}

Example JSON Serialization:

{
  "target": "192.168.1.100:80",
  "port": 80,
  "protocol": "Tcp",
  "state": "Open",
  "service": {
    "name": "http",
    "version": "2.4.52",
    "product": "Apache httpd",
    "cpe": "cpe:/a:apache:http_server:2.4.52",
    "os_hint": "Ubuntu"
  },
  "banner": "Apache/2.4.52 (Ubuntu)",
  "response_time_ms": 12,
  "timestamp": "2025-11-15T10:30:00Z"
}

OsFingerprint

OS fingerprinting data structure:

#![allow(unused)]
fn main() {
pub struct OsFingerprint {
    /// OS name (e.g., "Linux 5.10-5.15")
    pub name: String,

    /// OS classification
    pub class: OsClass,

    /// CPE identifiers
    pub cpe: Vec<String>,

    /// All fingerprint test results
    pub tests: FingerprintTests,
}

pub struct OsClass {
    /// OS family (Linux, Windows, BSD, etc.)
    pub family: String,

    /// Vendor (Microsoft, Apple, Red Hat, etc.)
    pub vendor: String,

    /// Device type (general purpose, router, firewall, etc.)
    pub device_type: String,

    /// Generation (e.g., "5.x", "Windows 10", "iOS 14")
    pub generation: String,
}

pub struct FingerprintTests {
    /// Sequence generation (ISN analysis)
    pub seq: SequenceGeneration,

    /// TCP options from probes
    pub ops: TcpOptions,

    /// Window sizes from probes
    pub win: WindowSizes,

    /// ECN response (probe 9)
    pub ecn: EcnResponse,

    /// TCP tests (probes 1-6, 10-15)
    pub t1_t7: TcpTests,

    /// UDP test (probe 16)
    pub u1: UdpTest,

    /// ICMP echo tests (probes 7-8)
    pub ie: IcmpEchoTests,
}

pub struct SequenceGeneration {
    /// Greatest common divisor of ISN deltas
    pub gcd: u32,

    /// ISN counter rate (increments/sec)
    pub isr: u32,

    /// Sequence predictability (0-255)
    pub sp: u8,

    /// TCP IPID sequence type
    pub ti: IpIdType,

    /// Closed port IPID sequence
    pub ci: IpIdType,

    /// ICMP IPID sequence
    pub ii: IpIdType,

    /// SYN scan IPID sequence
    pub ss: IpIdType,

    /// TCP timestamp frequency
    pub ts: TimestampFrequency,
}

pub enum IpIdType {
    Incremental,
    RandomIncremental,
    Zero,
    BrokenIncrement,
}
}

File Formats

JSON Output Format

ProRT-IP JSON output follows this schema:

{
  "scan_info": {
    "version": "0.5.0",
    "start_time": "2025-11-15T10:00:00Z",
    "end_time": "2025-11-15T10:05:30Z",
    "scan_type": ["SYN", "SERVICE"],
    "targets": ["192.168.1.0/24"],
    "ports": "1-1000",
    "timing_template": "Normal",
    "max_rate": 100000
  },
  "results": [
    {
      "ip": "192.168.1.100",
      "hostname": "server1.example.com",
      "state": "up",
      "latency_ms": 2,
      "ports": [
        {
          "port": 80,
          "protocol": "tcp",
          "state": "open",
          "service": {
            "name": "http",
            "product": "nginx",
            "version": "1.21.6",
            "cpe": "cpe:/a:nginx:nginx:1.21.6"
          },
          "banner": "nginx/1.21.6",
          "response_time_ms": 12
        },
        {
          "port": 443,
          "protocol": "tcp",
          "state": "open",
          "service": {
            "name": "https",
            "product": "nginx",
            "version": "1.21.6",
            "ssl": true
          },
          "tls_certificate": {
            "subject": "CN=server1.example.com",
            "issuer": "CN=Let's Encrypt",
            "valid_from": "2025-10-01T00:00:00Z",
            "valid_to": "2026-01-01T00:00:00Z",
            "san": ["server1.example.com", "www.server1.example.com"]
          }
        }
      ],
      "os": {
        "name": "Linux 5.15-5.19",
        "family": "Linux",
        "vendor": "Linux",
        "accuracy": 95,
        "cpe": ["cpe:/o:linux:linux_kernel:5.15"]
      }
    }
  ],
  "statistics": {
    "total_hosts": 256,
    "hosts_up": 42,
    "hosts_down": 214,
    "total_ports_scanned": 42000,
    "ports_open": 156,
    "ports_closed": 89,
    "ports_filtered": 41755,
    "scan_duration_sec": 330,
    "packets_sent": 84312,
    "packets_received": 245,
    "throughput_pps": 255
  }
}

Usage:

# JSON output
prtip -sS -p 1-1000 192.168.1.0/24 -oJ scan_results.json

# JSON with service detection
prtip -sV -p 80,443 targets.txt -oJ results_with_services.json

# Parse with jq
jq '.results[] | select(.ports[].state == "open")' scan_results.json

SQLite Schema

Database: scans.db (default location: ./scans.db)

-- Scan metadata table
CREATE TABLE scans (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    start_time TIMESTAMP NOT NULL,
    end_time TIMESTAMP,
    scan_type TEXT NOT NULL,
    targets TEXT NOT NULL,
    ports TEXT NOT NULL,
    timing_template TEXT,
    max_rate INTEGER,
    config_json TEXT
);

-- Host discovery results
CREATE TABLE hosts (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    scan_id INTEGER NOT NULL,
    ip TEXT NOT NULL,
    hostname TEXT,
    state TEXT NOT NULL,
    latency_ms INTEGER,
    os_name TEXT,
    os_family TEXT,
    os_accuracy INTEGER,
    os_cpe TEXT,
    FOREIGN KEY (scan_id) REFERENCES scans(id) ON DELETE CASCADE
);

-- Port scan results
CREATE TABLE ports (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    host_id INTEGER NOT NULL,
    port INTEGER NOT NULL,
    protocol TEXT NOT NULL,
    state TEXT NOT NULL,
    service_name TEXT,
    service_product TEXT,
    service_version TEXT,
    service_cpe TEXT,
    banner TEXT,
    response_time_ms INTEGER,
    timestamp TIMESTAMP NOT NULL,
    FOREIGN KEY (host_id) REFERENCES hosts(id) ON DELETE CASCADE
);

-- TLS certificates (optional)
CREATE TABLE tls_certificates (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    port_id INTEGER NOT NULL,
    subject TEXT,
    issuer TEXT,
    serial_number TEXT,
    valid_from TIMESTAMP,
    valid_to TIMESTAMP,
    san TEXT,  -- Subject Alternative Names (JSON array)
    fingerprint_sha256 TEXT,
    FOREIGN KEY (port_id) REFERENCES ports(id) ON DELETE CASCADE
);

-- Indexes for fast queries
CREATE INDEX idx_scan_id ON hosts(scan_id);
CREATE INDEX idx_host_id ON ports(host_id);
CREATE INDEX idx_port ON ports(port);
CREATE INDEX idx_state ON ports(state);
CREATE INDEX idx_service_name ON ports(service_name);
CREATE INDEX idx_ip ON hosts(ip);

Usage:

# Enable database storage
prtip -sS -p 1-1000 192.168.1.0/24 --with-db

# Custom database location
prtip -sS -p 1-1000 192.168.1.0/24 --with-db --database /path/to/results.db

# Query results
prtip db query results.db --scan-id 1
prtip db query results.db --target 192.168.1.100
prtip db query results.db --port 22 --open

# Export from database
prtip db export results.db --scan-id 1 --format json -o scan1.json

API Specifications

Core Scanner API

Primary scanning interface:

#![allow(unused)]
fn main() {
use prtip_core::{Scanner, ScanConfig, ScanReport};

pub struct Scanner {
    config: ScanConfig,
    runtime: Runtime,
}

impl Scanner {
    /// Create new scanner with configuration
    pub fn new(config: ScanConfig) -> Result<Self> {
        // Validates configuration
        // Initializes runtime environment
        // Drops privileges after initialization
    }

    /// Execute scan and return complete report
    pub async fn execute(&self) -> Result<ScanReport> {
        // Runs scan based on config
        // Returns complete results
    }

    /// Execute scan with real-time progress callback
    pub async fn execute_with_progress<F>(&self, callback: F) -> Result<ScanReport>
    where
        F: Fn(ScanProgress) + Send + 'static
    {
        // Calls callback periodically with progress updates
        // Returns complete results when done
    }

    /// Execute scan with event stream
    pub async fn execute_with_events(&self) -> Result<(ScanReport, EventReceiver)> {
        // Returns results + event stream for real-time monitoring
    }
}

pub struct ScanConfig {
    /// Target specifications (IPs, CIDRs, hostnames)
    pub targets: Vec<Target>,

    /// Port range to scan
    pub ports: PortRange,

    /// Scan technique (SYN, Connect, UDP, etc.)
    pub scan_type: ScanType,

    /// Timing template (T0-T5)
    pub timing: TimingTemplate,

    /// Maximum packets per second (rate limiting)
    pub max_rate: Option<u32>,

    /// Output configuration
    pub output: OutputConfig,

    /// Enable service detection
    pub service_detection: bool,

    /// Service detection intensity (0-9)
    pub version_intensity: u8,

    /// Enable OS fingerprinting
    pub os_detection: bool,

    /// Database storage
    pub database: Option<PathBuf>,
}

pub struct ScanReport {
    /// All scan results
    pub results: Vec<ScanResult>,

    /// Scan statistics
    pub statistics: ScanStatistics,

    /// Scan metadata
    pub metadata: ScanMetadata,
}

pub struct ScanProgress {
    /// Percentage complete (0.0-100.0)
    pub percentage: f64,

    /// Estimated time remaining
    pub eta_seconds: Option<u64>,

    /// Throughput (packets per second)
    pub throughput_pps: u64,

    /// Number of results so far
    pub results_count: usize,
}
}

Example Usage:

use prtip_core::{Scanner, ScanConfig, ScanType, TimingTemplate, PortRange};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let config = ScanConfig {
        targets: vec!["192.168.1.0/24".parse()?],
        ports: PortRange::parse("80,443")?,
        scan_type: ScanType::Syn,
        timing: TimingTemplate::Normal,
        max_rate: Some(100_000),
        service_detection: true,
        version_intensity: 7,
        os_detection: false,
        ..Default::default()
    };

    let scanner = Scanner::new(config)?;

    // With progress callback
    let report = scanner.execute_with_progress(|progress| {
        println!("Progress: {:.1}% | ETA: {:?}s",
                 progress.percentage,
                 progress.eta_seconds);
    }).await?;

    println!("Scan complete: {} results", report.results.len());
    Ok(())
}

Plugin API

Extensible plugin interface for custom scanning logic:

#![allow(unused)]
fn main() {
pub trait Plugin: Send + Sync {
    /// Plugin name (unique identifier)
    fn name(&self) -> &str;

    /// Initialize plugin with configuration
    fn init(&mut self, config: &PluginConfig) -> Result<()>;

    /// Called for each discovered port
    fn on_port_discovered(&mut self, result: &ScanResult) -> Result<()>;

    /// Called when service is detected
    fn on_service_detected(&mut self, result: &ScanResult, service: &ServiceInfo) -> Result<()>;

    /// Called at scan completion
    fn on_scan_complete(&mut self, report: &ScanReport) -> Result<()>;

    /// Cleanup resources
    fn cleanup(&mut self) -> Result<()>;
}

pub struct PluginConfig {
    /// Plugin-specific configuration (JSON)
    pub config: serde_json::Value,

    /// Plugin capabilities (read-only, network, filesystem)
    pub capabilities: PluginCapabilities,
}

pub struct PluginCapabilities {
    /// Read-only mode (no modifications)
    pub read_only: bool,

    /// Network access allowed
    pub network_access: bool,

    /// Filesystem access allowed
    pub filesystem_access: bool,
}
}

Example Plugin (Lua):

-- vulnerability_scanner.lua
plugin = {
    name = "VulnerabilityScanner",
    version = "1.0"
}

function plugin:on_service_detected(result, service)
    -- Check for known vulnerable versions
    if service.product == "Apache httpd" and service.version == "2.4.49" then
        log("WARNING: CVE-2021-41773 detected on " .. result.target)
    end
end

function plugin:on_scan_complete(report)
    log("Scan complete: " .. #report.results .. " results")
end

Load Plugin:

prtip -sV -p 80,443 --plugin vulnerability_scanner.lua 192.168.1.0/24

See Also