API Reference

Complete API documentation for ProRT-IP's public interfaces.

Version: 2.0 Last Updated: November 2025


Core Scanner API

Scanner

Main entry point for executing network scans.

#![allow(unused)]
fn main() {
pub struct Scanner { /* private fields */ }
}

Constructor

#![allow(unused)]
fn main() {
impl Scanner {
    /// Create a new scanner with configuration
    ///
    /// # Arguments
    /// * `config` - Scan configuration
    ///
    /// # Returns
    /// * `Result<Self>` - Scanner instance or error
    ///
    /// # Errors
    /// * `Error::InvalidTarget` - Invalid target specification
    /// * `Error::InvalidPortRange` - Invalid port range
    /// * `Error::PermissionDenied` - Insufficient privileges for raw sockets
    ///
    /// # Example
    /// ```rust
    /// use prtip_core::{Scanner, ScanConfig, ScanType};
    ///
    /// let config = ScanConfig {
    ///     targets: vec!["192.168.1.0/24".parse()?],
    ///     ports: PortRange::new(1, 1000),
    ///     scan_type: ScanType::Syn,
    ///     ..Default::default()
    /// };
    ///
    /// let scanner = Scanner::new(config)?;
    /// # Ok::<(), Box<dyn std::error::Error>>(())
    /// ```
    pub fn new(config: ScanConfig) -> Result<Self>
}
}

Execution Methods

#![allow(unused)]
fn main() {
impl Scanner {
    /// Execute the scan asynchronously
    ///
    /// Runs the scan with default progress tracking.
    ///
    /// # Returns
    /// * `Result<ScanReport>` - Complete scan report with all results
    ///
    /// # Example
    /// ```rust
    /// # use prtip_core::{Scanner, ScanConfig};
    /// # let scanner = Scanner::new(ScanConfig::default())?;
    /// let report = scanner.execute().await?;
    /// println!("Scanned {} hosts, found {} open ports",
    ///     report.stats.hosts_scanned,
    ///     report.stats.ports_open);
    /// # Ok::<(), Box<dyn std::error::Error>>(())
    /// ```
    pub async fn execute(&self) -> Result<ScanReport>

    /// Execute with progress callback
    ///
    /// Provides real-time progress updates during scanning.
    ///
    /// # Arguments
    /// * `callback` - Function called periodically with progress updates
    ///
    /// # Example
    /// ```rust
    /// # use prtip_core::{Scanner, ScanConfig, ScanProgress};
    /// # let scanner = Scanner::new(ScanConfig::default())?;
    /// let report = scanner.execute_with_progress(|progress| {
    ///     println!("Progress: {:.1}% ({}/{} ports)",
    ///         progress.percentage(),
    ///         progress.completed,
    ///         progress.total);
    /// }).await?;
    /// # Ok::<(), Box<dyn std::error::Error>>(())
    /// ```
    pub async fn execute_with_progress<F>(&self, callback: F) -> Result<ScanReport>
    where
        F: Fn(ScanProgress) + Send + 'static

    /// Execute with event stream
    ///
    /// Returns event receiver for real-time scan events.
    ///
    /// # Returns
    /// * Tuple of (ScanReport, EventReceiver)
    ///
    /// # Example
    /// ```rust
    /// # use prtip_core::Scanner;
    /// # let scanner = Scanner::new(Default::default())?;
    /// let (report, mut events) = scanner.execute_with_events().await?;
    ///
    /// while let Some(event) = events.recv().await {
    ///     match event {
    ///         ScanEvent::PortFound { target, port, state } => {
    ///             println!("Found: {}:{} ({:?})", target, port, state);
    ///         }
    ///         _ => {}
    ///     }
    /// }
    /// # Ok::<(), Box<dyn std::error::Error>>(())
    /// ```
    pub async fn execute_with_events(&self) -> Result<(ScanReport, EventReceiver)>
}
}

Control Methods

#![allow(unused)]
fn main() {
impl Scanner {
    /// Pause the scan
    ///
    /// Suspends packet transmission while preserving state.
    ///
    /// # Example
    /// ```rust
    /// # use prtip_core::Scanner;
    /// # let scanner = Scanner::new(Default::default())?;
    /// scanner.pause()?;
    /// # Ok::<(), Box<dyn std::error::Error>>(())
    /// ```
    pub fn pause(&self) -> Result<()>

    /// Resume a paused scan
    ///
    /// Resumes packet transmission from paused state.
    pub fn resume(&self) -> Result<()>

    /// Stop the scan gracefully
    ///
    /// Waits for in-flight probes before terminating.
    pub fn stop(&self) -> Result<()>
}
}

ScanConfig

Configuration for scan execution.

#![allow(unused)]
fn main() {
#[derive(Debug, Clone)]
pub struct ScanConfig {
    /// Target hosts/networks to scan
    pub targets: Vec<Target>,

    /// Ports to scan
    pub ports: PortRange,

    /// Type of scan to perform
    pub scan_type: ScanType,

    /// Skip host discovery (assume all hosts are up)
    pub skip_discovery: bool,

    /// Enable service version detection
    pub service_detection: bool,

    /// Service detection intensity (0-9, default 7)
    pub service_intensity: u8,

    /// Enable OS fingerprinting
    pub os_detection: bool,

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

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

    /// Minimum packet rate (packets/second)
    pub min_rate: Option<u32>,

    /// Maximum retransmissions per probe
    pub max_retries: u8,

    /// Maximum scan duration
    pub max_duration: Option<Duration>,

    /// Output configuration
    pub output: OutputConfig,
}

impl Default for ScanConfig {
    fn default() -> Self {
        Self {
            targets: Vec::new(),
            ports: PortRange::new(1, 1000),
            scan_type: ScanType::Syn,
            skip_discovery: false,
            service_detection: false,
            service_intensity: 7,
            os_detection: false,
            timing: TimingTemplate::Normal,
            max_rate: Some(100_000),  // 100K pps
            min_rate: None,
            max_retries: 2,
            max_duration: None,
            output: OutputConfig::default(),
        }
    }
}
}

Field Descriptions:

FieldTypeDefaultDescription
targetsVec<Target>[]Target hosts/networks (IP, CIDR, hostname, range)
portsPortRange1-1000Ports to scan (individual or ranges)
scan_typeScanTypeSynScan technique (SYN, Connect, UDP, etc.)
skip_discoveryboolfalseAssume all hosts up (skip ping)
service_detectionboolfalseEnable version detection
service_intensityu87Probe intensity 0-9 (higher = more probes)
os_detectionboolfalseEnable OS fingerprinting
timingTimingTemplateNormalTiming template T0-T5
max_rateOption<u32>100000Maximum packets/second (None = unlimited)
min_rateOption<u32>NoneMinimum packets/second
max_retriesu82Retransmissions per probe
max_durationOption<Duration>NoneMaximum scan time (None = no limit)
outputOutputConfigdefaultOutput formats and destinations

ScanType

Supported scan techniques.

#![allow(unused)]
fn main() {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ScanType {
    /// TCP SYN scan (half-open, stealth)
    ///
    /// Most common scan type. Sends SYN packets without completing
    /// the TCP handshake (never sends final ACK).
    Syn,

    /// TCP Connect scan (full connection)
    ///
    /// Completes full TCP handshake. More detectable but works
    /// without raw socket privileges.
    Connect,

    /// UDP scan
    ///
    /// Sends UDP probes with protocol-specific payloads. 10-100x
    /// slower than TCP due to ICMP rate limiting.
    Udp,

    /// TCP FIN scan (firewall evasion)
    ///
    /// Sends FIN packets. Open ports ignore, closed ports send RST.
    /// May bypass simple firewalls.
    Fin,

    /// TCP NULL scan (no flags)
    ///
    /// Sends packets with no TCP flags set. Similar to FIN scan
    /// for firewall evasion.
    Null,

    /// TCP Xmas scan (FIN+PSH+URG)
    ///
    /// Sends packets with FIN, PSH, and URG flags (lights up like
    /// a Christmas tree). Evasion technique.
    Xmas,

    /// TCP ACK scan (firewall detection)
    ///
    /// Sends ACK packets to detect firewall rules. Distinguishes
    /// between filtered and unfiltered ports.
    Ack,

    /// TCP Window scan (advanced)
    ///
    /// Examines TCP window field in RST responses to determine
    /// port state. More reliable than ACK scan.
    Window,

    /// Idle scan (zombie, maximum anonymity)
    ///
    /// Uses third-party "zombie" host to scan target. Attacker's
    /// IP never directly contacts target.
    ///
    /// # Requirements
    /// - Zombie host must be idle (predictable IPID)
    /// - Zombie must use incremental IPID globally
    /// - Zombie must respond to unsolicited SYN/ACK with RST
    Idle {
        /// Zombie host IP address
        zombie: IpAddr,
    },
}
}

Scan Type Comparison:

Scan TypeSpeedStealthPrivilegesFirewall Evasion
SYN⚡⚡⚡ Fast🔒 MediumRoot/AdminLow
Connect⚡⚡ Medium🔓 LowNoneNone
UDP⚡ Slow🔒 MediumRoot/AdminLow
FIN/NULL/Xmas⚡⚡ Medium🔒🔒 HighRoot/AdminHigh
ACK⚡⚡⚡ Fast🔒 MediumRoot/AdminN/A (firewall test)
Idle⚡ Slow🔒🔒🔒 MaximumRoot/AdminMaximum

TimingTemplate

Predefined timing configurations (T0-T5).

#![allow(unused)]
fn main() {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TimingTemplate {
    /// Paranoid (T0): IDS evasion, 5-minute delays
    Paranoid,

    /// Sneaky (T1): Slow IDS evasion, 15-second delays
    Sneaky,

    /// Polite (T2): Less bandwidth/target load, 0.4-second delays
    Polite,

    /// Normal (T3): Default balanced scanning
    Normal,

    /// Aggressive (T4): Fast networks, assumes good connectivity
    Aggressive,

    /// Insane (T5): Maximum speed, may overwhelm targets
    Insane,
}

impl TimingTemplate {
    /// Get timing parameters for template
    pub fn params(&self) -> TimingParams {
        match self {
            TimingTemplate::Paranoid => TimingParams {
                initial_timeout: Duration::from_secs(300),
                max_timeout: Duration::from_secs(300),
                max_retries: 5,
                scan_delay: Some(Duration::from_secs(300)),
            },
            TimingTemplate::Sneaky => TimingParams {
                initial_timeout: Duration::from_secs(15),
                max_timeout: Duration::from_secs(15),
                max_retries: 5,
                scan_delay: Some(Duration::from_secs(15)),
            },
            TimingTemplate::Polite => TimingParams {
                initial_timeout: Duration::from_secs(1),
                max_timeout: Duration::from_secs(10),
                max_retries: 5,
                scan_delay: Some(Duration::from_millis(400)),
            },
            TimingTemplate::Normal => TimingParams {
                initial_timeout: Duration::from_secs(1),
                max_timeout: Duration::from_secs(10),
                max_retries: 2,
                scan_delay: None,
            },
            TimingTemplate::Aggressive => TimingParams {
                initial_timeout: Duration::from_millis(500),
                max_timeout: Duration::from_millis(1250),
                max_retries: 6,
                scan_delay: None,
            },
            TimingTemplate::Insane => TimingParams {
                initial_timeout: Duration::from_millis(250),
                max_timeout: Duration::from_millis(300),
                max_retries: 2,
                scan_delay: None,
            },
        }
    }
}
}

Timing Template Parameters:

TemplateInitial TimeoutMax TimeoutMax RetriesScan DelayUse Case
T0 (Paranoid)300 sec300 sec55 minIDS evasion, ultra-stealth
T1 (Sneaky)15 sec15 sec515 secSlow stealth scanning
T2 (Polite)1 sec10 sec50.4 secBandwidth-limited
T3 (Normal)1 sec10 sec20Default balanced
T4 (Aggressive)500 ms1250 ms60Fast reliable networks
T5 (Insane)250 ms300 ms20Maximum speed (risky)

Network Protocol API

TcpPacketBuilder

Builder for constructing TCP packets with options.

#![allow(unused)]
fn main() {
pub struct TcpPacketBuilder { /* private fields */ }
}

Methods

#![allow(unused)]
fn main() {
impl TcpPacketBuilder {
    /// Create new TCP packet builder
    pub fn new() -> Self

    /// Set source IP and port
    ///
    /// # Example
    /// ```rust
    /// use prtip_net::TcpPacketBuilder;
    /// use std::net::Ipv4Addr;
    ///
    /// let packet = TcpPacketBuilder::new()
    ///     .source(Ipv4Addr::new(10, 0, 0, 1), 12345)
    ///     .build()?;
    /// # Ok::<(), Box<dyn std::error::Error>>(())
    /// ```
    pub fn source(self, ip: Ipv4Addr, port: u16) -> Self

    /// Set destination IP and port
    pub fn destination(self, ip: Ipv4Addr, port: u16) -> Self

    /// Set sequence number (random for SYN, SipHash-derived for stateless)
    pub fn sequence(self, seq: u32) -> Self

    /// Set acknowledgment number
    pub fn acknowledgment(self, ack: u32) -> Self

    /// Set TCP flags
    ///
    /// # Example
    /// ```rust
    /// use prtip_net::{TcpPacketBuilder, TcpFlags};
    ///
    /// let packet = TcpPacketBuilder::new()
    ///     .flags(TcpFlags::SYN)
    ///     .build()?;
    /// # Ok::<(), Box<dyn std::error::Error>>(())
    /// ```
    pub fn flags(self, flags: TcpFlags) -> Self

    /// Set window size (default 65535)
    pub fn window_size(self, window: u16) -> Self

    /// Add TCP option
    ///
    /// # Example
    /// ```rust
    /// use prtip_net::{TcpPacketBuilder, TcpOption};
    ///
    /// let packet = TcpPacketBuilder::new()
    ///     .tcp_option(TcpOption::Mss(1460))
    ///     .tcp_option(TcpOption::WindowScale(7))
    ///     .tcp_option(TcpOption::SackPermitted)
    ///     .build()?;
    /// # Ok::<(), Box<dyn std::error::Error>>(())
    /// ```
    pub fn tcp_option(self, option: TcpOption) -> Self

    /// Build the packet
    ///
    /// # Returns
    /// * `Result<Vec<u8>>` - Complete IP+TCP packet bytes
    ///
    /// # Errors
    /// * `Error::InvalidAddress` - Source or destination not set
    /// * `Error::PacketTooLarge` - Options exceed 40-byte maximum
    pub fn build(self) -> Result<Vec<u8>>
}
}

TcpFlags

TCP control flags (bitflags).

#![allow(unused)]
fn main() {
bitflags::bitflags! {
    pub struct TcpFlags: u8 {
        const FIN = 0b00000001;  // Finish connection
        const SYN = 0b00000010;  // Synchronize sequence numbers
        const RST = 0b00000100;  // Reset connection
        const PSH = 0b00001000;  // Push buffered data
        const ACK = 0b00010000;  // Acknowledgment
        const URG = 0b00100000;  // Urgent pointer valid
        const ECE = 0b01000000;  // ECN echo
        const CWR = 0b10000000;  // Congestion window reduced
    }
}
}

Common Flag Combinations:

#![allow(unused)]
fn main() {
// SYN scan
TcpFlags::SYN

// SYN/ACK response
TcpFlags::SYN | TcpFlags::ACK

// FIN scan
TcpFlags::FIN

// Xmas scan
TcpFlags::FIN | TcpFlags::PSH | TcpFlags::URG

// NULL scan
TcpFlags::empty()

// ACK scan
TcpFlags::ACK
}

TcpOption

TCP options for packet customization.

#![allow(unused)]
fn main() {
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum TcpOption {
    /// Maximum Segment Size (MSS)
    ///
    /// Typical values: 1460 (Ethernet), 1440 (PPPoE), 536 (dial-up)
    Mss(u16),

    /// Window Scale factor (0-14)
    ///
    /// Multiplier for TCP window field: actual_window = window << scale
    WindowScale(u8),

    /// SACK Permitted
    ///
    /// Enables Selective Acknowledgment
    SackPermitted,

    /// Timestamp (RFC 7323)
    ///
    /// Used for RTT measurement and PAWS (Protection Against Wrapped Sequences)
    Timestamp {
        /// Timestamp value
        tsval: u32,
        /// Timestamp echo reply
        tsecr: u32,
    },

    /// No Operation (padding)
    Nop,

    /// End of Options
    Eol,
}

impl TcpOption {
    /// Get option length in bytes
    pub fn length(&self) -> usize

    /// Serialize to bytes
    pub fn to_bytes(&self) -> Vec<u8>

    /// Parse from bytes
    ///
    /// # Returns
    /// * Tuple of (TcpOption, bytes_consumed)
    pub fn from_bytes(data: &[u8]) -> Result<(Self, usize)>
}
}

PacketCapture

Packet capture interface (libpcap/Npcap/BPF wrapper).

#![allow(unused)]
fn main() {
pub struct PacketCapture { /* private fields */ }

impl PacketCapture {
    /// Create new packet capture on interface
    ///
    /// # Arguments
    /// * `interface` - Network interface name (e.g., "eth0", "\\Device\\NPF_{GUID}")
    ///
    /// # Example
    /// ```no_run
    /// use prtip_net::PacketCapture;
    ///
    /// let mut capture = PacketCapture::new("eth0")?;
    /// # Ok::<(), Box<dyn std::error::Error>>(())
    /// ```
    pub fn new(interface: &str) -> Result<Self>

    /// Set BPF filter for packet filtering
    ///
    /// # Example
    /// ```no_run
    /// # use prtip_net::PacketCapture;
    /// # let mut capture = PacketCapture::new("eth0")?;
    /// // Capture only TCP traffic to port 80
    /// capture.set_filter("tcp and dst port 80")?;
    ///
    /// // Capture SYN/ACK responses from 192.168.1.0/24
    /// capture.set_filter("tcp[tcpflags] & (tcp-syn|tcp-ack) != 0 and src net 192.168.1.0/24")?;
    /// # Ok::<(), Box<dyn std::error::Error>>(())
    /// ```
    pub fn set_filter(&mut self, filter: &str) -> Result<()>

    /// Get next packet (blocking)
    ///
    /// Returns None if timeout expires without packet.
    pub fn next_packet(&mut self) -> Result<Option<Vec<u8>>>

    /// Get next packet asynchronously
    ///
    /// # Example
    /// ```no_run
    /// # use prtip_net::PacketCapture;
    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
    /// # let mut capture = PacketCapture::new("eth0")?;
    /// let packet = capture.recv_async().await?;
    /// println!("Received {} bytes", packet.len());
    /// # Ok(())
    /// # }
    /// ```
    pub async fn recv_async(&mut self) -> Result<Vec<u8>>
}
}

Detection Engine API

ServiceDetector

Service version detection engine.

#![allow(unused)]
fn main() {
pub struct ServiceDetector { /* private fields */ }

impl ServiceDetector {
    /// Create new service detector
    ///
    /// # Arguments
    /// * `intensity` - Detection intensity (0-9)
    ///   - 0: Registered ports only
    ///   - 7: Recommended default (common + comprehensive)
    ///   - 9: All 187 probes (exhaustive)
    ///
    /// # Example
    /// ```rust
    /// use prtip_detect::ServiceDetector;
    ///
    /// let detector = ServiceDetector::new(7);
    /// ```
    pub fn new(intensity: u8) -> Self

    /// Load probe database from file
    ///
    /// # Example
    /// ```no_run
    /// # use prtip_detect::ServiceDetector;
    /// let mut detector = ServiceDetector::new(7);
    /// detector.load_probes("probes/nmap-service-probes")?;
    /// # Ok::<(), Box<dyn std::error::Error>>(())
    /// ```
    pub fn load_probes(&mut self, path: &str) -> Result<()>

    /// Detect service on target port
    ///
    /// Sends probes and matches responses against database.
    ///
    /// # Returns
    /// * `Option<ServiceInfo>` - Detected service or None if unrecognized
    ///
    /// # Example
    /// ```no_run
    /// # use prtip_detect::ServiceDetector;
    /// # use std::net::SocketAddr;
    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
    /// # let detector = ServiceDetector::new(7);
    /// let target: SocketAddr = "192.168.1.1:80".parse()?;
    /// if let Some(service) = detector.detect(target).await? {
    ///     println!("Service: {} {} ({})",
    ///         service.name,
    ///         service.version.unwrap_or_default(),
    ///         service.product.unwrap_or_default());
    /// }
    /// # Ok(())
    /// # }
    /// ```
    pub async fn detect(&self, target: SocketAddr) -> Result<Option<ServiceInfo>>
}
}

ServiceInfo

Detected service information.

#![allow(unused)]
fn main() {
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ServiceInfo {
    /// Service name (e.g., "http", "ssh", "mysql")
    pub name: String,

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

    /// Version string (e.g., "1.21.6", "8.9p1", "8.0.32")
    pub version: Option<String>,

    /// Extra info (e.g., "Ubuntu Linux; protocol 2.0")
    pub extra_info: Option<String>,

    /// CPE identifier (e.g., "cpe:/a:openbsd:openssh:8.9p1")
    pub cpe: Option<String>,

    /// OS hint from service banner (e.g., "Ubuntu", "Windows")
    pub os_hint: Option<String>,
}
}

Example ServiceInfo:

#![allow(unused)]
fn main() {
ServiceInfo {
    name: "http".to_string(),
    product: Some("nginx".to_string()),
    version: Some("1.21.6".to_string()),
    extra_info: Some("Ubuntu".to_string()),
    cpe: Some("cpe:/a:igor_sysoev:nginx:1.21.6".to_string()),
    os_hint: Some("Linux".to_string()),
}
}

OsDetector

OS fingerprinting engine.

#![allow(unused)]
fn main() {
pub struct OsDetector { /* private fields */ }

impl OsDetector {
    /// Create new OS detector
    pub fn new() -> Self

    /// Load fingerprint database
    ///
    /// # Example
    /// ```no_run
    /// # use prtip_detect::OsDetector;
    /// let mut detector = OsDetector::new();
    /// detector.load_fingerprints("fingerprints/nmap-os-db")?;
    /// # Ok::<(), Box<dyn std::error::Error>>(())
    /// ```
    pub fn load_fingerprints(&mut self, path: &str) -> Result<()>

    /// Detect OS of target
    ///
    /// Sends 16-probe sequence (6 TCP SYN ISN, 2 ICMP, 7 TCP misc, 1 UDP).
    ///
    /// # Arguments
    /// * `target` - Target IP address
    /// * `open_port` - Known open TCP port
    /// * `closed_port` - Known closed TCP port
    ///
    /// # Returns
    /// * `Vec<OsMatch>` - Possible OS matches sorted by confidence (highest first)
    ///
    /// # Example
    /// ```no_run
    /// # use prtip_detect::OsDetector;
    /// # use std::net::Ipv4Addr;
    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
    /// # let detector = OsDetector::new();
    /// let target = Ipv4Addr::new(192, 168, 1, 1);
    /// let matches = detector.detect(target, 80, 12345).await?;
    ///
    /// if let Some(best) = matches.first() {
    ///     println!("OS: {} ({}% confidence)", best.name, best.accuracy);
    ///     println!("Class: {} {} {}",
    ///         best.class.vendor,
    ///         best.class.os_family,
    ///         best.class.device_type);
    /// }
    /// # Ok(())
    /// # }
    /// ```
    pub async fn detect(
        &self,
        target: Ipv4Addr,
        open_port: u16,
        closed_port: u16
    ) -> Result<Vec<OsMatch>>
}
}

OsMatch

OS detection match result.

#![allow(unused)]
fn main() {
#[derive(Debug, Clone)]
pub struct OsMatch {
    /// OS name (e.g., "Linux 5.15", "Windows 10 or 11")
    pub name: String,

    /// OS classification
    pub class: OsClass,

    /// Match accuracy (0-100)
    pub accuracy: u8,

    /// CPE identifiers (e.g., ["cpe:/o:linux:linux_kernel:5.15"])
    pub cpe: Vec<String>,

    /// Additional info
    pub info: Option<String>,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct OsClass {
    /// Vendor (e.g., "Linux", "Microsoft", "Apple")
    pub vendor: String,

    /// OS family (e.g., "Linux", "Windows", "embedded")
    pub os_family: String,

    /// OS generation (e.g., "5.x", "10", "11")
    pub os_generation: Option<String>,

    /// Device type (e.g., "general purpose", "router", "firewall")
    pub device_type: String,
}
}

Example OsMatch:

#![allow(unused)]
fn main() {
OsMatch {
    name: "Linux 5.15".to_string(),
    class: OsClass {
        vendor: "Linux".to_string(),
        os_family: "Linux".to_string(),
        os_generation: Some("5.x".to_string()),
        device_type: "general purpose".to_string(),
    },
    accuracy: 95,
    cpe: vec!["cpe:/o:linux:linux_kernel:5.15".to_string()],
    info: None,
}
}

Plugin API

Plugin Trait

Interface for extending scanner functionality.

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

    /// Plugin version (semantic versioning)
    fn version(&self) -> &str {
        "1.0.0"
    }

    /// Initialize plugin with configuration
    ///
    /// # Arguments
    /// * `config` - Plugin-specific configuration
    fn init(&mut self, config: &PluginConfig) -> Result<()> {
        Ok(())
    }

    /// Called when scan starts
    ///
    /// # Arguments
    /// * `scan_info` - Scan metadata (targets, ports, scan type)
    fn on_scan_start(&mut self, _scan_info: &ScanInfo) -> Result<()> {
        Ok(())
    }

    /// Called for each discovered host
    fn on_host_discovered(&mut self, _host: &HostInfo) -> Result<()> {
        Ok(())
    }

    /// Called for each discovered port
    ///
    /// # Example
    /// ```rust
    /// # use prtip_plugins::Plugin;
    /// # struct AlertPlugin;
    /// # impl Plugin for AlertPlugin {
    /// #     fn name(&self) -> &str { "alert" }
    /// fn on_port_discovered(&mut self, result: &ScanResult) -> Result<()> {
    ///     if result.port == 22 && result.state == PortState::Open {
    ///         println!("Alert: SSH port open on {}", result.target);
    ///     }
    ///     Ok(())
    /// }
    /// # }
    /// ```
    fn on_port_discovered(&mut self, _result: &ScanResult) -> Result<()> {
        Ok(())
    }

    /// Called when service is detected
    fn on_service_detected(&mut self, _result: &ScanResult, _service: &ServiceInfo) -> Result<()> {
        Ok(())
    }

    /// Called when scan completes
    fn on_scan_complete(&mut self, _report: &ScanReport) -> Result<()> {
        Ok(())
    }

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

PluginManager

Manages plugin lifecycle and event dispatch.

#![allow(unused)]
fn main() {
pub struct PluginManager { /* private fields */ }

impl PluginManager {
    /// Create new plugin manager
    pub fn new() -> Self

    /// Register a plugin
    ///
    /// # Example
    /// ```rust
    /// # use prtip_plugins::{PluginManager, Plugin};
    /// # struct MyPlugin;
    /// # impl Plugin for MyPlugin {
    /// #     fn name(&self) -> &str { "my-plugin" }
    /// # }
    /// let mut manager = PluginManager::new();
    /// manager.register(Box::new(MyPlugin))?;
    /// # Ok::<(), Box<dyn std::error::Error>>(())
    /// ```
    pub fn register(&mut self, plugin: Box<dyn Plugin>) -> Result<()>

    /// Load plugin from shared library file
    ///
    /// # Example
    /// ```no_run
    /// # use prtip_plugins::PluginManager;
    /// # let mut manager = PluginManager::new();
    /// manager.load_from_file("plugins/alert.so")?;
    /// # Ok::<(), Box<dyn std::error::Error>>(())
    /// ```
    pub fn load_from_file(&mut self, path: &str) -> Result<()>

    /// Notify all plugins of scan start
    pub fn notify_scan_start(&mut self, scan_info: &ScanInfo) -> Result<()>

    /// Notify all plugins of port discovery
    pub fn notify_port_discovered(&mut self, result: &ScanResult) -> Result<()>

    /// Notify all plugins of service detection
    pub fn notify_service_detected(&mut self, result: &ScanResult, service: &ServiceInfo) -> Result<()>

    /// Notify all plugins of scan completion
    pub fn notify_scan_complete(&mut self, report: &ScanReport) -> Result<()>
}
}

Configuration API

Target

Target specification (IP, network, hostname, range).

#![allow(unused)]
fn main() {
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Target {
    /// Single IP address
    Ip(IpAddr),

    /// Network in CIDR notation (e.g., "192.168.1.0/24")
    Network(IpNetwork),

    /// Hostname (requires DNS resolution)
    Hostname(String),

    /// IP range (e.g., "192.168.1.1-192.168.1.254")
    Range {
        start: IpAddr,
        end: IpAddr,
    },
}

impl Target {
    /// Parse target from string
    ///
    /// Supports:
    /// - Single IP: "192.168.1.1"
    /// - CIDR notation: "10.0.0.0/24"
    /// - Hostname: "example.com"
    /// - IP range: "192.168.1.1-192.168.1.254"
    ///
    /// # Example
    /// ```rust
    /// use prtip_core::Target;
    ///
    /// let t1: Target = "192.168.1.1".parse()?;
    /// let t2: Target = "10.0.0.0/24".parse()?;
    /// let t3: Target = "example.com".parse()?;
    /// let t4: Target = "192.168.1.1-192.168.1.254".parse()?;
    /// # Ok::<(), Box<dyn std::error::Error>>(())
    /// ```
    pub fn parse(s: &str) -> Result<Self>

    /// Expand into IP addresses
    ///
    /// # Example
    /// ```rust
    /// # use prtip_core::Target;
    /// let target: Target = "192.168.1.0/30".parse()?;
    /// let ips = target.expand()?;
    /// assert_eq!(ips.len(), 4);  // 192.168.1.0, .1, .2, .3
    /// # Ok::<(), Box<dyn std::error::Error>>(())
    /// ```
    pub fn expand(&self) -> Result<Vec<IpAddr>>
}
}

PortRange

Port range specification (individual ports or ranges).

#![allow(unused)]
fn main() {
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PortRange {
    ranges: Vec<(u16, u16)>,
}

impl PortRange {
    /// Create new port range
    ///
    /// # Example
    /// ```rust
    /// use prtip_core::PortRange;
    ///
    /// let range = PortRange::new(1, 1000);
    /// assert_eq!(range.count(), 1000);
    /// ```
    pub fn new(start: u16, end: u16) -> Self

    /// Parse from string
    ///
    /// Supports:
    /// - Individual ports: "80,443,8080"
    /// - Ranges: "1-1000"
    /// - Mixed: "80,443,8000-9000"
    /// - Special: "-" or "all" for 1-65535
    ///
    /// # Example
    /// ```rust
    /// use prtip_core::PortRange;
    ///
    /// let p1: PortRange = "80,443".parse()?;
    /// let p2: PortRange = "1-1000".parse()?;
    /// let p3: PortRange = "80,443,8000-9000".parse()?;
    /// # Ok::<(), Box<dyn std::error::Error>>(())
    /// ```
    pub fn parse(s: &str) -> Result<Self>

    /// Iterate over all ports
    ///
    /// # Example
    /// ```rust
    /// # use prtip_core::PortRange;
    /// let range: PortRange = "80,443,8000-8002".parse()?;
    /// let ports: Vec<u16> = range.iter().collect();
    /// assert_eq!(ports, vec![80, 443, 8000, 8001, 8002]);
    /// # Ok::<(), Box<dyn std::error::Error>>(())
    /// ```
    pub fn iter(&self) -> impl Iterator<Item = u16>

    /// Count of ports in range
    pub fn count(&self) -> usize
}
}

Result Types

ScanReport

Complete scan report with all results.

#![allow(unused)]
fn main() {
#[derive(Debug, Clone)]
pub struct ScanReport {
    /// Scan configuration used
    pub config: ScanConfig,

    /// Scan start time
    pub start_time: SystemTime,

    /// Scan end time
    pub end_time: SystemTime,

    /// Results per host
    pub hosts: Vec<HostResult>,

    /// Scan statistics
    pub stats: ScanStats,
}

impl ScanReport {
    /// Duration of scan
    pub fn duration(&self) -> Duration {
        self.end_time.duration_since(self.start_time).unwrap()
    }

    /// Total open ports across all hosts
    pub fn total_open_ports(&self) -> usize {
        self.hosts.iter()
            .flat_map(|h| &h.ports)
            .filter(|p| p.state == PortState::Open)
            .count()
    }

    /// Export to JSON
    ///
    /// # Example
    /// ```rust
    /// # use prtip_core::ScanReport;
    /// # let report = ScanReport::default();
    /// let json = report.to_json()?;
    /// std::fs::write("scan_results.json", json)?;
    /// # Ok::<(), Box<dyn std::error::Error>>(())
    /// ```
    pub fn to_json(&self) -> Result<String> {
        serde_json::to_string_pretty(self).map_err(Into::into)
    }

    /// Export to Nmap-compatible XML
    pub fn to_xml(&self) -> Result<String>

    /// Save to SQLite database
    ///
    /// # Example
    /// ```no_run
    /// # use prtip_core::ScanReport;
    /// # let report = ScanReport::default();
    /// report.save_to_db("scans.db")?;
    /// # Ok::<(), Box<dyn std::error::Error>>(())
    /// ```
    pub fn save_to_db(&self, db_path: &str) -> Result<()>
}
}

HostResult

Results for a single host.

#![allow(unused)]
fn main() {
#[derive(Debug, Clone)]
pub struct HostResult {
    /// IP address
    pub ip: IpAddr,

    /// Resolved hostname (if available)
    pub hostname: Option<String>,

    /// Host state (Up/Down/Unknown)
    pub state: HostState,

    /// Port scan results
    pub ports: Vec<PortResult>,

    /// OS fingerprint match (if OS detection enabled)
    pub os: Option<OsMatch>,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum HostState {
    /// Host is up (responded to probes)
    Up,

    /// Host is down (no response)
    Down,

    /// Unable to determine (skip_discovery=true)
    Unknown,
}
}

PortResult

Results for a single port.

#![allow(unused)]
fn main() {
#[derive(Debug, Clone)]
pub struct PortResult {
    /// Port number (1-65535)
    pub port: u16,

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

    /// Port state
    pub state: PortState,

    /// Detected service (if service_detection enabled)
    pub service: Option<ServiceInfo>,

    /// Raw service banner (if captured)
    pub banner: Option<String>,

    /// Response time (RTT)
    pub response_time: Duration,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PortState {
    /// Port is open (accepting connections)
    Open,

    /// Port is closed (actively rejecting with RST)
    Closed,

    /// Port is filtered (firewall blocking)
    Filtered,

    /// Open or filtered (UDP scan ambiguity)
    OpenFiltered,

    /// Closed or filtered (rare, IPID idle scan)
    ClosedFiltered,

    /// Unknown state (unexpected response)
    Unknown,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Protocol {
    Tcp,
    Udp,
}
}

Error Types

Error

Main error type for all ProRT-IP operations.

#![allow(unused)]
fn main() {
#[derive(Error, Debug)]
pub enum Error {
    #[error("Invalid target: {0}")]
    InvalidTarget(String),

    #[error("Invalid port range: {0}")]
    InvalidPortRange(String),

    #[error("Permission denied: {0}")]
    PermissionDenied(String),

    #[error("Network error: {0}")]
    Network(#[from] std::io::Error),

    #[error("Timeout waiting for response")]
    Timeout,

    #[error("Configuration error: {0}")]
    Config(String),

    #[error("Plugin error: {0}")]
    Plugin(String),

    #[error("Invalid packet: {0}")]
    InvalidPacket(String),

    #[error("Database error: {0}")]
    Database(String),

    #[error("Serialization error: {0}")]
    Serialization(String),
}

pub type Result<T> = std::result::Result<T, Error>;
}

Common Error Scenarios:

ErrorCauseSolution
PermissionDeniedRaw socket accessRun with root/Administrator privileges
InvalidTargetMalformed IP/CIDRCheck target syntax (e.g., "192.168.1.0/24")
InvalidPortRangeInvalid port specificationValid range: 1-65535
TimeoutNo response from targetIncrease timeout or retry count
NetworkNetwork interface issueCheck interface name, connectivity
ConfigInvalid configurationReview ScanConfig fields
PluginPlugin initialization failedCheck plugin compatibility

See Also