1use derive_builder::Builder;
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::{
17 self, Reader, Sender, rst_packet::RstPacketBuilder,
18 syn_packet::SynPacketBuilder,
19 },
20 scanners::{PortSet, Scanning, heartbeat::HeartBeat},
21 targets::ports::PortTargets,
22};
23
24use super::{Device, Port, ScanMessage, Scanner};
25
26static SERVICES: LazyLock<HashMap<u16, &str>> = LazyLock::new(|| {
27 HashMap::from([
28 (20, "ftp-data"),
29 (21, "ftp"),
30 (22, "ssh"),
31 (23, "telnet"),
32 (25, "smtp"),
33 (53, "dns"),
34 (80, "http"),
35 (110, "pop3"),
36 (143, "imap"),
37 (443, "https"),
38 (445, "microsoft-ds"),
39 (587, "submission"),
40 (993, "imaps"),
41 (995, "pop3s"),
42 (1433, "mssql"),
43 (3306, "mysql"),
44 (3389, "rdp"),
45 (5432, "postgresql"),
46 (5900, "vnc"),
47 (6379, "redis"),
48 (8080, "http-alt"),
49 (8443, "https-alt"),
50 (27017, "mongodb"),
51 ])
52});
53
54#[derive(Clone, Builder)]
56#[builder(setter(into))]
57pub struct SYNScanner {
58 interface: Arc<NetworkInterface>,
60 packet_reader: Arc<Mutex<dyn Reader>>,
62 packet_sender: Arc<Mutex<dyn Sender>>,
64 targets: Vec<Device>,
66 ports: Arc<PortTargets>,
68 source_port: u16,
70 idle_timeout: Duration,
72 notifier: mpsc::Sender<ScanMessage>,
74}
75
76impl SYNScanner {
77 pub fn builder() -> SYNScannerBuilder {
79 SYNScannerBuilder::default()
80 }
81
82 fn process_port(&self, port: u16) -> Result<()> {
83 for device in self.targets.iter() {
84 thread::sleep(packet::DEFAULT_PACKET_SEND_TIMING);
86
87 log::debug!("scanning SYN target: {}:{}", device.ip, port);
88
89 let dest_ipv4 = device.ip;
90 let dest_mac = device.mac;
91
92 let syn_packet = SynPacketBuilder::default()
93 .source_ip(self.interface.ipv4)
94 .source_mac(self.interface.mac)
95 .source_port(self.source_port)
96 .dest_ip(dest_ipv4)
97 .dest_mac(dest_mac)
98 .dest_port(port)
99 .build()?;
100
101 let pkt_buf = syn_packet.to_raw();
102
103 self.notifier
105 .send(ScanMessage::Info(Scanning {
106 ip: device.ip,
107 port: Some(port),
108 }))
109 .map_err(RLanLibError::from_channel_send_error)?;
110
111 let mut sender = self.packet_sender.lock()?;
112
113 sender.send(&pkt_buf).map_err(|e| RLanLibError::Scan {
115 ip: Some(device.ip.to_string()),
116 port: Some(port.to_string()),
117 error: e.to_string(),
118 })?;
119 }
120
121 Ok(())
122 }
123
124 fn process_incoming_packet(
125 &self,
126 pkt: &[u8],
127 device_map: &HashMap<Ipv4Addr, Device>,
128 ) -> Result<()> {
129 let Some(eth) = ethernet::EthernetPacket::new(pkt) else {
130 return Ok(());
131 };
132
133 let Some(header) = ipv4::Ipv4Packet::new(eth.payload()) else {
134 return Ok(());
135 };
136
137 let device_ip = header.get_source();
138 let protocol = header.get_next_level_protocol();
139 let payload = header.payload();
140
141 if protocol != ip::IpNextHeaderProtocols::Tcp {
142 return Ok(());
143 }
144
145 let Some(tcp_packet) = tcp::TcpPacket::new(payload) else {
146 return Ok(());
147 };
148
149 let destination_port = tcp_packet.get_destination();
150 let matches_destination = destination_port == self.source_port;
151 let flags: u8 = tcp_packet.get_flags();
152 let sequence = tcp_packet.get_sequence();
153 let is_syn_ack = flags == tcp::TcpFlags::SYN + tcp::TcpFlags::ACK;
154
155 if !matches_destination || !is_syn_ack {
156 return Ok(());
157 }
158
159 let Some(device) = device_map.get(&device_ip) else {
160 return Ok(());
161 };
162
163 let port = tcp_packet.get_source();
164
165 let dest_ipv4 = device.ip;
169 let dest_mac = device.mac;
170
171 let rst_packet = RstPacketBuilder::default()
172 .source_ip(self.interface.ipv4)
173 .source_mac(self.interface.mac)
174 .source_port(self.source_port)
175 .dest_ip(dest_ipv4)
176 .dest_mac(dest_mac)
177 .dest_port(port)
178 .sequence_number(sequence + 1)
179 .build()?;
180
181 let rst_packet = rst_packet.to_raw();
182
183 let mut rst_sender = self.packet_sender.lock()?;
184
185 log::debug!("sending RST packet to {}:{}", device.ip, port);
186
187 rst_sender.send(&rst_packet)?;
188
189 let service = SERVICES
190 .get(&port)
191 .map(|s| s.to_string())
192 .unwrap_or_default();
193
194 let mut ports = PortSet::new();
195 ports.0.insert(Port { id: port, service });
196
197 self.notifier
198 .send(ScanMessage::SYNScanDevice(Device {
199 open_ports: ports,
200 ..device.clone()
201 }))
202 .map_err(RLanLibError::from_channel_send_error)?;
203
204 Ok(())
205 }
206
207 fn read_packets(
210 &self,
211 done_rx: mpsc::Receiver<()>,
212 ) -> Result<JoinHandle<Result<()>>> {
213 let self_clone = self.clone();
214 let (heartbeat_tx, heartbeat_rx) = sync::mpsc::channel::<()>();
215
216 let heartbeat = HeartBeat::builder()
217 .source_mac(self.interface.mac)
218 .source_ipv4(self.interface.ipv4)
219 .source_port(self.source_port)
220 .packet_sender(Arc::clone(&self.packet_sender))
221 .build()?;
222
223 let heart_handle = heartbeat.start_in_thread(heartbeat_rx)?;
224
225 Ok(thread::spawn(move || -> Result<()> {
226 let mut reader = self_clone.packet_reader.lock()?;
227
228 let device_map: HashMap<Ipv4Addr, Device> = self_clone
230 .targets
231 .iter()
232 .map(|d| (d.ip, d.clone()))
233 .collect();
234
235 loop {
236 if done_rx.try_recv().is_ok() {
237 log::debug!("exiting syn packet reader");
238 if let Err(e) = heartbeat_tx.send(()) {
239 log::error!("failed to stop heartbeat: {}", e);
240 }
241
242 break;
243 }
244
245 let pkt = reader.next_packet()?;
246 self_clone.process_incoming_packet(pkt, &device_map)?;
247 }
248
249 heart_handle.join()??;
250
251 Ok(())
252 }))
253 }
254}
255
256impl Scanner for SYNScanner {
258 fn scan(&self) -> Result<JoinHandle<Result<()>>> {
259 log::debug!("performing SYN scan on targets: {:?}", self.targets);
260
261 let self_clone = self.clone();
262 let (done_tx, done_rx) = mpsc::channel::<()>();
263
264 log::debug!("starting syn packet reader");
265
266 let read_handle = self.read_packets(done_rx)?;
267
268 let handle = thread::spawn(move || -> Result<()> {
270 let mut scan_error: Option<RLanLibError> = None;
271
272 if let Err(err) =
273 self_clone.ports.lazy_loop(|p| self_clone.process_port(p))
274 {
275 scan_error = Some(err);
276 }
277
278 thread::sleep(self_clone.idle_timeout);
279
280 self_clone
281 .notifier
282 .send(ScanMessage::Done)
283 .map_err(RLanLibError::from_channel_send_error)?;
284
285 let _ = done_tx.send(());
288
289 let read_result = read_handle.join()?;
290
291 if let Some(err) = scan_error {
292 return Err(err);
293 }
294
295 read_result
296 });
297
298 Ok(handle)
299 }
300}
301
302#[cfg(test)]
303#[path = "./syn_scanner_tests.rs"]
304mod tests;