r_lanlib/scanners/
arp_scanner.rs1use derive_builder::Builder;
4use pnet::packet::{Packet, arp, ethernet};
5use std::{
6 net::Ipv4Addr,
7 sync::{self, Arc},
8 thread::{self, JoinHandle},
9 time::Duration,
10};
11use threadpool::ThreadPool;
12
13use crate::{
14 error::{RLanLibError, Result},
15 network::NetworkInterface,
16 packet::{self, arp_packet::ArpPacketBuilder, wire::Wire},
17 scanners::{Device, PortSet, Scanning},
18 targets::ips::IPTargets,
19};
20
21use super::{ScanMessage, Scanner, heartbeat::HeartBeat};
22
23#[derive(Clone, Builder)]
25#[builder(setter(into))]
26pub struct ARPScanner {
27 interface: Arc<NetworkInterface>,
29 wire: Wire,
31 targets: Arc<IPTargets>,
33 source_port: u16,
35 include_vendor: bool,
37 include_host_names: bool,
39 idle_timeout: Duration,
41 notifier: sync::mpsc::Sender<ScanMessage>,
43}
44
45impl ARPScanner {
46 pub fn builder() -> ARPScannerBuilder {
48 ARPScannerBuilder::default()
49 }
50
51 fn process_target(&self, target: Ipv4Addr) -> Result<()> {
52 thread::sleep(packet::DEFAULT_PACKET_SEND_TIMING);
54
55 log::debug!("scanning ARP target: {}", target);
56
57 let arp_packet = ArpPacketBuilder::default()
58 .source_ip(self.interface.ipv4)
59 .source_mac(self.interface.mac)
60 .dest_ip(target)
61 .build()?;
62
63 let pkt_buf = arp_packet.to_raw();
64
65 self.notifier
67 .send(ScanMessage::Info(Scanning {
68 ip: target,
69 port: None,
70 }))
71 .map_err(RLanLibError::from_channel_send_error)?;
72
73 let mut pkt_sender = self.wire.0.lock()?;
74
75 pkt_sender.send(&pkt_buf)?;
77
78 Ok(())
79 }
80
81 fn process_incoming_packet(
82 &self,
83 pkt: &[u8],
84 pool: &ThreadPool,
85 ) -> Result<()> {
86 let Some(eth) = ethernet::EthernetPacket::new(pkt) else {
87 return Ok(());
88 };
89
90 let Some(header) = arp::ArpPacket::new(eth.payload()) else {
91 return Ok(());
92 };
93
94 if header.get_operation() != arp::ArpOperations::Reply {
97 return Ok(());
98 }
99
100 let ip4 = header.get_sender_proto_addr();
101 let mac = eth.get_source();
102
103 let notification_sender = self.notifier.clone();
104 let interface = Arc::clone(&self.interface);
105 let include_host_names = self.include_host_names;
106 let include_vendor = self.include_vendor;
107
108 pool.execute(move || {
111 let hostname = if include_host_names {
112 log::debug!("looking up hostname for {}", ip4);
113 dns_lookup::lookup_addr(&ip4.into()).unwrap_or_default()
114 } else {
115 String::new()
116 };
117
118 let vendor = if include_vendor {
119 oui_data::lookup(&mac.to_string())
120 .map(|v| v.organization().to_owned())
121 .unwrap_or_default()
122 } else {
123 String::new()
124 };
125
126 let _ =
127 notification_sender.send(ScanMessage::ARPScanDevice(Device {
128 hostname,
129 ip: ip4,
130 mac,
131 vendor,
132 is_current_host: ip4 == interface.ipv4,
133 open_ports: PortSet::new(),
134 }));
135 });
136
137 Ok(())
138 }
139
140 fn read_packets(
143 &self,
144 done: sync::mpsc::Receiver<()>,
145 ) -> Result<JoinHandle<Result<()>>> {
146 let (heartbeat_tx, heartbeat_rx) = sync::mpsc::channel::<()>();
147
148 let heartbeat = HeartBeat::builder()
149 .source_mac(self.interface.mac)
150 .source_ipv4(self.interface.ipv4)
151 .source_port(self.source_port)
152 .packet_sender(Arc::clone(&self.wire.0))
153 .build()?;
154
155 heartbeat.start_in_thread(heartbeat_rx)?;
156
157 let self_clone = self.clone();
158
159 Ok(thread::spawn(move || -> Result<()> {
160 let mut reader = self_clone.wire.1.lock()?;
161 let lookup_pool = ThreadPool::new(8);
164
165 loop {
166 if done.try_recv().is_ok() {
167 log::debug!("exiting arp packet reader");
168 if let Err(e) = heartbeat_tx.send(()) {
169 log::error!("failed to stop heartbeat: {}", e);
170 }
171 break;
172 }
173
174 let pkt = reader.next_packet()?;
175
176 self_clone.process_incoming_packet(pkt, &lookup_pool)?;
177 }
178
179 Ok(())
180 }))
181 }
182}
183
184impl Scanner for ARPScanner {
186 fn scan(&self) -> Result<JoinHandle<Result<()>>> {
187 log::debug!("performing ARP scan on targets: {:?}", self.targets);
188 log::debug!("include_vendor: {}", self.include_vendor);
189 log::debug!("include_host_names: {}", self.include_host_names);
190 log::debug!("starting arp packet reader");
191
192 let self_clone = self.clone();
193 let (done_tx, done_rx) = sync::mpsc::channel::<()>();
194
195 let read_handle = self.read_packets(done_rx)?;
196
197 let scan_handle = thread::spawn(move || -> Result<()> {
199 let mut scan_error: Option<RLanLibError> = None;
200
201 if let Err(err) = self_clone
202 .targets
203 .lazy_loop(|t| self_clone.process_target(t))
204 {
205 scan_error = Some(err);
206 }
207
208 thread::sleep(self_clone.idle_timeout);
209
210 self_clone
211 .notifier
212 .send(ScanMessage::Done)
213 .map_err(RLanLibError::from_channel_send_error)?;
214
215 let _ = done_tx.send(());
218
219 let read_result = read_handle.join()?;
220
221 if let Some(err) = scan_error {
222 return Err(err);
223 }
224
225 read_result
226 });
227
228 Ok(scan_handle)
229 }
230}
231
232#[cfg(test)]
233#[path = "./arp_scanner_tests.rs"]
234mod tests;