r_lanlib/
scanners.rs

1//! Provides data structure an implementations for performing network scanning
2//!
3//! This includes:
4//! - ARP Scanning
5//! - SYN Scanning
6//! - Full Scanning (ARP + SYN)
7
8#[cfg(test)]
9use mockall::{automock, predicate::*};
10
11use serde;
12use serde::{Deserialize, Serialize};
13use std::collections::HashSet;
14use std::error::Error;
15use std::fmt;
16use std::thread::JoinHandle;
17
18/// The default idle timeout for a scanner
19pub const IDLE_TIMEOUT: u16 = 10000;
20
21#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
22/// Data structure representing a port
23pub struct Port {
24    /// The ID of the port i.e. 22, 80, 443 etc.
25    pub id: u16,
26    /// The associated service name for the port if known
27    pub service: String,
28}
29
30// ARP Result from a single device
31#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
32/// Data structure representing a device on the network
33pub struct Device {
34    /// Hostname of the device
35    pub hostname: String,
36    /// IPv4 of the device
37    pub ip: String,
38    /// MAC address of the device
39    pub mac: String,
40    /// Vendor of the device if known
41    pub vendor: String,
42    /// Whether or not the device is the current host running the scan
43    pub is_current_host: bool,
44}
45
46// Device with open ports
47#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
48/// Data structure representing a device on the network with detected open ports
49pub struct DeviceWithPorts {
50    /// IPv4 of the device
51    pub ip: String,
52    /// MAC address of the device
53    pub mac: String,
54    /// Hostname of the device
55    pub hostname: String,
56    /// Device vendor if known
57    pub vendor: String,
58    /// Whether or not the device is the current host running the scan
59    pub is_current_host: bool,
60    /// A list of detected open ports on the device
61    pub open_ports: HashSet<Port>,
62}
63
64impl From<DeviceWithPorts> for Device {
65    fn from(value: DeviceWithPorts) -> Self {
66        Self {
67            ip: value.ip.clone(),
68            mac: value.mac.clone(),
69            hostname: value.hostname.clone(),
70            vendor: value.vendor.clone(),
71            is_current_host: value.is_current_host,
72        }
73    }
74}
75
76#[derive(Debug)]
77/// Data structure representing a message that a device is being scanned
78pub struct Scanning {
79    /// IPv4 of the device
80    pub ip: String,
81    /// Port being scanned
82    pub port: Option<String>,
83}
84
85#[derive(Debug)]
86/// Data structure representing a message that an error occurred while scanning
87pub struct ScanError {
88    /// The IPv4 of device being scanned if known
89    pub ip: Option<String>,
90    /// The port being scanned if known
91    pub port: Option<String>,
92    /// The error encountered
93    pub error: Box<dyn Error>,
94}
95
96impl fmt::Display for ScanError {
97    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
98        let ip = self.ip.clone().unwrap_or(String::from(""));
99        let port = self.port.clone().unwrap_or(String::from(""));
100        let msg = format!(
101            "scanning error: ip {ip}, port: {port}, msg: {0}",
102            self.error
103        );
104        write!(f, "{msg}")
105    }
106}
107
108impl Error for ScanError {}
109unsafe impl Send for ScanError {}
110unsafe impl Sync for ScanError {}
111
112#[derive(Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
113/// Data structure representing the result of SYN scan on a device for a port
114pub struct SYNScanResult {
115    /// The device that was scanned
116    pub device: Device,
117    /// The port that was scanned
118    pub open_port: Port,
119}
120
121#[derive(Debug)]
122/// Generic enum representing the various kinds of scanning messages over the
123/// mcsp channel
124pub enum ScanMessage {
125    /// Indicates that scanning has completed
126    Done,
127    /// Send to inform that a device is about to be scanned
128    Info(Scanning),
129    /// Sent whenever an ARP response is received from a device
130    ARPScanResult(Device),
131    /// Sent whenever a SYN response is received from a device
132    SYNScanResult(SYNScanResult),
133}
134
135#[cfg_attr(test, automock)]
136/// Trait used by all scanners
137pub trait Scanner: Sync + Send {
138    /// Performs network scanning
139    fn scan(&self) -> JoinHandle<Result<(), ScanError>>;
140}
141
142pub mod arp_scanner;
143pub mod full_scanner;
144mod heartbeat;
145pub mod syn_scanner;
146
147#[cfg(test)]
148#[path = "./scanners_tests.rs"]
149mod tests;