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, mpsc},
9 thread::{self, JoinHandle},
10 time::Duration,
11};
12
13use crate::{
14 error::{RLanLibError, Result},
15 network::NetworkInterface,
16 packet::{rst_packet::RstPacketBuilder, syn_packet::SynPacketBuilder},
17 scanners::{PortSet, Scanning, heartbeat::HeartBeat},
18 targets::ports::PortTargets,
19 wire::{DEFAULT_PACKET_SEND_TIMING, Wire},
20};
21
22use super::{Device, Port, ScanMessage, Scanner};
23
24static SERVICES: LazyLock<HashMap<u16, &str>> = LazyLock::new(|| {
25 HashMap::from([
26 (20, "ftp-data"),
27 (21, "ftp"),
28 (22, "ssh"),
29 (23, "telnet"),
30 (25, "smtp"),
31 (53, "dns"),
32 (80, "http"),
33 (110, "pop3"),
34 (143, "imap"),
35 (443, "https"),
36 (445, "microsoft-ds"),
37 (587, "submission"),
38 (993, "imaps"),
39 (995, "pop3s"),
40 (1433, "mssql"),
41 (3306, "mysql"),
42 (3389, "rdp"),
43 (5432, "postgresql"),
44 (5900, "vnc"),
45 (6379, "redis"),
46 (8080, "http-alt"),
47 (8443, "https-alt"),
48 (27017, "mongodb"),
49 ])
50});
51
52#[derive(Clone, Builder)]
54#[builder(setter(into))]
55pub struct SYNScanner {
56 interface: Arc<NetworkInterface>,
58 wire: Wire,
60 targets: Vec<Device>,
62 ports: Arc<PortTargets>,
64 source_port: u16,
66 idle_timeout: Duration,
68 #[builder(default = DEFAULT_PACKET_SEND_TIMING)]
71 throttle: 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(self.throttle);
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.wire.0.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 response_ttl = header.get_ttl();
139 let protocol = header.get_next_level_protocol();
140 let payload = header.payload();
141
142 if protocol != ip::IpNextHeaderProtocols::Tcp {
143 return Ok(());
144 }
145
146 let Some(tcp_packet) = tcp::TcpPacket::new(payload) else {
147 return Ok(());
148 };
149
150 let destination_port = tcp_packet.get_destination();
151 let matches_destination = destination_port == self.source_port;
152 let flags: u8 = tcp_packet.get_flags();
153 let sequence = tcp_packet.get_sequence();
154 let is_syn_ack = flags == tcp::TcpFlags::SYN + tcp::TcpFlags::ACK;
155
156 if !matches_destination || !is_syn_ack {
157 return Ok(());
158 }
159
160 let Some(device) = device_map.get(&device_ip) else {
161 return Ok(());
162 };
163
164 let port = tcp_packet.get_source();
165
166 let dest_ipv4 = device.ip;
170 let dest_mac = device.mac;
171
172 let rst_packet = RstPacketBuilder::default()
173 .source_ip(self.interface.ipv4)
174 .source_mac(self.interface.mac)
175 .source_port(self.source_port)
176 .dest_ip(dest_ipv4)
177 .dest_mac(dest_mac)
178 .dest_port(port)
179 .sequence_number(sequence + 1)
180 .build()?;
181
182 let rst_packet = rst_packet.to_raw();
183
184 let mut rst_sender = self.wire.0.lock()?;
185
186 log::debug!("sending RST packet to {}:{}", device.ip, port);
187
188 rst_sender.send(&rst_packet)?;
189
190 let service = SERVICES
191 .get(&port)
192 .map(|s| s.to_string())
193 .unwrap_or_default();
194
195 let mut ports = PortSet::new();
196 ports.0.insert(Port { id: port, service });
197
198 self.notifier
199 .send(ScanMessage::SYNScanDevice(Device {
200 open_ports: ports,
201 response_ttl: Some(response_ttl),
202 ..device.clone()
203 }))
204 .map_err(RLanLibError::from_channel_send_error)?;
205
206 Ok(())
207 }
208
209 fn read_packets(
212 &self,
213 done_rx: mpsc::Receiver<()>,
214 ) -> Result<JoinHandle<Result<()>>> {
215 let self_clone = self.clone();
216 let (heartbeat_tx, heartbeat_rx) = sync::mpsc::channel::<()>();
217
218 let heartbeat = HeartBeat::builder()
219 .source_mac(self.interface.mac)
220 .source_ipv4(self.interface.ipv4)
221 .source_port(self.source_port)
222 .packet_sender(Arc::clone(&self.wire.0))
223 .build()?;
224
225 let heart_handle = heartbeat.start_in_thread(heartbeat_rx)?;
226
227 Ok(thread::spawn(move || -> Result<()> {
228 let mut reader = self_clone.wire.1.lock()?;
229
230 let device_map: HashMap<Ipv4Addr, Device> = self_clone
232 .targets
233 .iter()
234 .map(|d| (d.ip, d.clone()))
235 .collect();
236
237 loop {
238 if done_rx.try_recv().is_ok() {
239 log::debug!("exiting syn packet reader");
240 if let Err(e) = heartbeat_tx.send(()) {
241 log::error!("failed to stop heartbeat: {}", e);
242 }
243
244 break;
245 }
246
247 let pkt = reader.next_packet()?;
248 self_clone.process_incoming_packet(pkt, &device_map)?;
249 }
250
251 heart_handle.join()??;
252
253 Ok(())
254 }))
255 }
256}
257
258impl Scanner for SYNScanner {
260 fn scan(&self) -> Result<JoinHandle<Result<()>>> {
261 log::debug!("performing SYN scan on targets: {:?}", self.targets);
262
263 let self_clone = self.clone();
264 let (done_tx, done_rx) = mpsc::channel::<()>();
265
266 log::debug!("starting syn packet reader");
267
268 let read_handle = self.read_packets(done_rx)?;
269
270 let handle = thread::spawn(move || -> Result<()> {
272 let mut scan_error: Option<RLanLibError> = None;
273
274 if let Err(err) =
275 self_clone.ports.lazy_loop(|p| self_clone.process_port(p))
276 {
277 scan_error = Some(err);
278 }
279
280 thread::sleep(self_clone.idle_timeout);
281
282 self_clone
283 .notifier
284 .send(ScanMessage::Done)
285 .map_err(RLanLibError::from_channel_send_error)?;
286
287 let _ = done_tx.send(());
290
291 let read_result = read_handle.join()?;
292
293 if let Some(err) = scan_error {
294 return Err(err);
295 }
296
297 read_result
298 });
299
300 Ok(handle)
301 }
302}
303
304#[cfg(test)]
305#[path = "./syn_scanner_tests.rs"]
306mod tests;