1use log::*;
4use pnet::packet::{Packet, ethernet, ip, ipv4, tcp};
5use std::{
6 collections::HashMap,
7 net::Ipv4Addr,
8 sync::{self, Arc, LazyLock, Mutex, mpsc},
9 thread::{self, JoinHandle},
10 time::Duration,
11};
12
13use crate::{
14 error::{RLanLibError, Result},
15 network::NetworkInterface,
16 packet::{self, Reader, Sender, rst_packet::RstPacketBuilder, syn_packet::SynPacketBuilder},
17 scanners::{PortSet, Scanning, heartbeat::HeartBeat},
18 targets::ports::PortTargets,
19};
20
21use super::{Device, Port, ScanMessage, Scanner};
22
23static SERVICES: LazyLock<HashMap<u16, &str>> = LazyLock::new(|| {
24 HashMap::from([
25 (20, "ftp-data"),
26 (21, "ftp"),
27 (22, "ssh"),
28 (23, "telnet"),
29 (25, "smtp"),
30 (53, "dns"),
31 (80, "http"),
32 (110, "pop3"),
33 (143, "imap"),
34 (443, "https"),
35 (445, "microsoft-ds"),
36 (587, "submission"),
37 (993, "imaps"),
38 (995, "pop3s"),
39 (1433, "mssql"),
40 (3306, "mysql"),
41 (3389, "rdp"),
42 (5432, "postgresql"),
43 (5900, "vnc"),
44 (6379, "redis"),
45 (8080, "http-alt"),
46 (8443, "https-alt"),
47 (27017, "mongodb"),
48 ])
49});
50
51pub struct SYNScanner<'net> {
53 interface: &'net NetworkInterface,
54 packet_reader: Arc<Mutex<dyn Reader>>,
55 packet_sender: Arc<Mutex<dyn Sender>>,
56 targets: Vec<Device>,
57 ports: Arc<PortTargets>,
58 source_port: u16,
59 idle_timeout: Duration,
60 notifier: mpsc::Sender<ScanMessage>,
61}
62
63pub struct SYNScannerArgs<'net> {
65 pub interface: &'net NetworkInterface,
67 pub packet_reader: Arc<Mutex<dyn Reader>>,
70 pub packet_sender: Arc<Mutex<dyn Sender>>,
73 pub targets: Vec<Device>,
75 pub ports: Arc<PortTargets>,
77 pub source_port: u16,
80 pub idle_timeout: Duration,
83 pub notifier: mpsc::Sender<ScanMessage>,
86}
87
88impl<'net> SYNScanner<'net> {
89 pub fn new(args: SYNScannerArgs<'net>) -> Self {
91 Self {
92 interface: args.interface,
93 packet_reader: args.packet_reader,
94 packet_sender: args.packet_sender,
95 targets: args.targets,
96 ports: args.ports,
97 source_port: args.source_port,
98 idle_timeout: args.idle_timeout,
99 notifier: args.notifier,
100 }
101 }
102}
103
104impl SYNScanner<'_> {
105 fn read_packets(&self, done_rx: mpsc::Receiver<()>) -> JoinHandle<Result<()>> {
108 let packet_reader = Arc::clone(&self.packet_reader);
109 let heartbeat_packet_sender = Arc::clone(&self.packet_sender);
110 let rst_packet_sender = Arc::clone(&self.packet_sender);
111 let device_map: HashMap<Ipv4Addr, Device> =
113 self.targets.iter().map(|d| (d.ip, d.clone())).collect();
114 let notifier = self.notifier.clone();
115 let source_ipv4 = self.interface.ipv4;
116 let source_mac = self.interface.mac;
117 let source_port = self.source_port;
118 let (heartbeat_tx, heartbeat_rx) = sync::mpsc::channel::<()>();
119
120 thread::spawn(move || {
126 debug!("starting syn heartbeat thread");
127 let heartbeat = HeartBeat::new(
128 source_mac,
129 source_ipv4,
130 source_port,
131 heartbeat_packet_sender,
132 );
133 let interval = Duration::from_secs(1);
134 loop {
135 if heartbeat_rx.try_recv().is_ok() {
136 debug!("stopping syn heartbeat");
137 break;
138 }
139 debug!("sending syn heartbeat");
140 heartbeat.beat();
141 thread::sleep(interval);
142 }
143 });
144
145 thread::spawn(move || -> Result<()> {
146 let mut reader = packet_reader.lock()?;
147
148 loop {
149 if done_rx.try_recv().is_ok() {
150 debug!("exiting syn packet reader");
151 if let Err(e) = heartbeat_tx.send(()) {
152 error!("failed to stop heartbeat: {}", e);
153 }
154
155 break;
156 }
157
158 let pkt = reader.next_packet()?;
159
160 let Some(eth) = ethernet::EthernetPacket::new(pkt) else {
161 continue;
162 };
163
164 let Some(header) = ipv4::Ipv4Packet::new(eth.payload()) else {
165 continue;
166 };
167
168 let device_ip = header.get_source();
169 let protocol = header.get_next_level_protocol();
170 let payload = header.payload();
171
172 if protocol != ip::IpNextHeaderProtocols::Tcp {
173 continue;
174 }
175
176 let Some(tcp_packet) = tcp::TcpPacket::new(payload) else {
177 continue;
178 };
179
180 let destination_port = tcp_packet.get_destination();
181 let matches_destination = destination_port == source_port;
182 let flags: u8 = tcp_packet.get_flags();
183 let sequence = tcp_packet.get_sequence();
184 let is_syn_ack = flags == tcp::TcpFlags::SYN + tcp::TcpFlags::ACK;
185
186 if !matches_destination || !is_syn_ack {
187 continue;
188 }
189
190 let Some(device) = device_map.get(&device_ip) else {
191 continue;
192 };
193
194 let port = tcp_packet.get_source();
195
196 let dest_ipv4 = device.ip;
200 let dest_mac = device.mac;
201
202 let rst_packet = RstPacketBuilder::default()
203 .source_ip(source_ipv4)
204 .source_mac(source_mac)
205 .source_port(source_port)
206 .dest_ip(dest_ipv4)
207 .dest_mac(dest_mac)
208 .dest_port(port)
209 .sequence_number(sequence + 1)
210 .build()?;
211
212 let rst_packet = rst_packet.to_raw();
213
214 let mut rst_sender = rst_packet_sender.lock()?;
215
216 debug!("sending RST packet to {}:{}", device.ip, port);
217
218 rst_sender.send(&rst_packet)?;
219
220 let service = SERVICES
221 .get(&port)
222 .map(|s| s.to_string())
223 .unwrap_or_default();
224
225 let mut ports = PortSet::new();
226 ports.0.insert(Port { id: port, service });
227
228 notifier
229 .send(ScanMessage::SYNScanDevice(Device {
230 open_ports: ports,
231 ..device.clone()
232 }))
233 .map_err(RLanLibError::from_channel_send_error)?;
234 }
235
236 Ok(())
237 })
238 }
239}
240
241impl Scanner for SYNScanner<'_> {
243 fn scan(&self) -> JoinHandle<Result<()>> {
244 debug!("performing SYN scan on targets: {:?}", self.targets);
245
246 debug!("starting syn packet reader");
247
248 let (done_tx, done_rx) = mpsc::channel::<()>();
249 let notifier = self.notifier.clone();
250 let packet_sender = Arc::clone(&self.packet_sender);
251 let targets = self.targets.clone();
252 let interface = self.interface;
253 let source_ipv4 = interface.ipv4;
254 let source_mac = self.interface.mac;
255 let ports = Arc::clone(&self.ports);
256 let idle_timeout = self.idle_timeout;
257 let source_port = self.source_port;
258
259 let read_handle = self.read_packets(done_rx);
260
261 thread::spawn(move || -> Result<()> {
263 let mut scan_error: Option<RLanLibError> = None;
264
265 let process_port = |port: u16| -> Result<()> {
266 for device in targets.iter() {
267 thread::sleep(packet::DEFAULT_PACKET_SEND_TIMING);
269
270 debug!("scanning SYN target: {}:{}", device.ip, port);
271
272 let dest_ipv4 = device.ip;
273 let dest_mac = device.mac;
274
275 let syn_packet = SynPacketBuilder::default()
276 .source_ip(source_ipv4)
277 .source_mac(source_mac)
278 .source_port(source_port)
279 .dest_ip(dest_ipv4)
280 .dest_mac(dest_mac)
281 .dest_port(port)
282 .build()?;
283
284 let pkt_buf = syn_packet.to_raw();
285
286 notifier
288 .send(ScanMessage::Info(Scanning {
289 ip: device.ip,
290 port: Some(port),
291 }))
292 .map_err(RLanLibError::from_channel_send_error)?;
293
294 let mut sender = packet_sender.lock()?;
295
296 sender.send(&pkt_buf).map_err(|e| RLanLibError::Scan {
298 ip: Some(device.ip.to_string()),
299 port: Some(port.to_string()),
300 error: e.to_string(),
301 })?;
302 }
303
304 Ok(())
305 };
306
307 if let Err(err) = ports.lazy_loop(process_port) {
308 scan_error = Some(err);
309 }
310
311 thread::sleep(idle_timeout);
312
313 notifier
314 .send(ScanMessage::Done)
315 .map_err(RLanLibError::from_channel_send_error)?;
316
317 let _ = done_tx.send(());
320
321 let read_result = read_handle.join()?;
322
323 if let Some(err) = scan_error {
324 return Err(err);
325 }
326
327 read_result
328 })
329 }
330}
331
332#[cfg(test)]
333#[path = "./syn_scanner_tests.rs"]
334mod tests;