use derive_builder::Builder;
use std::{
sync::{Arc, mpsc},
thread::JoinHandle,
time::Duration,
};
use crate::{
error::Result,
network::NetworkInterface,
oui::traits::Oui,
targets::{ips::IPTargets, ports::PortTargets},
wire::{DEFAULT_PACKET_SEND_TIMING, Wire},
};
use super::{
Device, ScanMessage, Scanner, arp_scanner::ARPScanner,
syn_scanner::SYNScanner,
};
#[derive(Builder)]
#[builder(setter(into))]
pub struct FullScanner {
interface: Arc<NetworkInterface>,
wire: Wire,
targets: Arc<IPTargets>,
ports: Arc<PortTargets>,
vendor: bool,
host: bool,
idle_timeout: Duration,
#[builder(default = DEFAULT_PACKET_SEND_TIMING)]
throttle: Duration,
notifier: mpsc::Sender<ScanMessage>,
source_port: u16,
#[builder(default)]
oui: Option<Arc<dyn Oui>>,
}
impl FullScanner {
pub fn builder() -> FullScannerBuilder {
FullScannerBuilder::default()
}
fn get_syn_targets_from_arp_scan(&self) -> Result<Vec<Device>> {
let (tx, rx) = mpsc::channel::<ScanMessage>();
let mut syn_targets: Vec<Device> = Vec::new();
let mut arp_builder = ARPScanner::builder()
.interface(Arc::clone(&self.interface))
.wire(self.wire.clone())
.targets(Arc::clone(&self.targets))
.source_port(self.source_port)
.include_vendor(self.vendor)
.include_host_names(self.host)
.idle_timeout(self.idle_timeout)
.throttle(self.throttle)
.notifier(tx.clone());
if let Some(oui) = self.oui.as_ref() {
arp_builder = arp_builder.oui(Arc::clone(oui));
}
let arp = arp_builder.build()?;
arp.scan()?;
loop {
if let Ok(msg) = rx.recv() {
match msg {
ScanMessage::Done => {
log::debug!("arp sending complete");
break;
}
ScanMessage::ARPScanDevice(device) => {
syn_targets.push(device.to_owned());
}
_ => {}
}
}
}
Ok(syn_targets)
}
}
impl Scanner for FullScanner {
fn scan(&self) -> Result<JoinHandle<Result<()>>> {
let syn_targets = self.get_syn_targets_from_arp_scan()?;
let syn = SYNScanner::builder()
.interface(Arc::clone(&self.interface))
.wire(self.wire.clone())
.targets(syn_targets)
.ports(Arc::clone(&self.ports))
.source_port(self.source_port)
.idle_timeout(self.idle_timeout)
.throttle(self.throttle)
.notifier(self.notifier.clone())
.build()?;
syn.scan()
}
}
#[cfg(test)]
#[path = "./full_scanner_tests.rs"]
mod tests;