1#[cfg(feature = "async")]
2use crate::async_scan;
3#[cfg(feature = "os")]
4use crate::os;
5#[cfg(feature = "sync")]
6use crate::sync_scan;
7
8use crate::{
9 frame::{Destination, ScanType},
10 interface,
11 traceroute::Tracert,
12};
13use e_utils::dns;
14use ipnet::{self, IpNet};
15use serde_derive::Deserialize;
16use std::{
17 any::Any,
18 ffi::OsString,
19 net::{IpAddr, Ipv4Addr},
20 time::Duration,
21};
22use structopt::{clap::arg_enum, StructOpt};
23
24use super::dns::{DnsResult, DnsResultType, DnsResults};
25
26arg_enum! {
27 #[doc(hidden)]
29 #[derive(Deserialize, Debug, StructOpt, Clone, PartialEq, Copy)]
30 pub enum ScriptsRequired {
31 None,
32 Default,
33 Custom,
34 }
35}
36arg_enum! {
37 #[doc(hidden)]
39 #[derive(Deserialize, Debug, StructOpt, Clone, PartialEq, Copy)]
40 pub enum ScanModelType {
41 Sync,
42 Async,
43 Os,
44 Service,
45 Dns,
46 Traceroute,
47 None
48 }
49}
50arg_enum! {
51 #[doc(hidden)]
53 #[derive(Deserialize, Debug, StructOpt, Clone, PartialEq, Copy)]
54 pub enum ScanOrderType {
55 None,
56 Icmp,
57 TcpConnect,
58 Udp,
59 Tcp,
60 TcpSyn,
61 }
62}
63#[derive(StructOpt, Debug)]
103#[structopt(name = "", setting = structopt::clap::AppSettings::TrailingVarArg)]
104#[allow(clippy::struct_excessive_bools)]
105pub struct Opts {
106 #[structopt(short, long, use_delimiter = true)]
108 pub ips: Vec<String>,
109
110 #[structopt(short, long, use_delimiter = true)]
112 pub ports: Vec<String>,
113
114 #[structopt(long, default_value = "")]
116 pub src_ip: String,
117
118 #[structopt(short, long, default_value = "3600000")]
120 pub timeout: u64,
121
122 #[structopt(long, default_value = "3000")]
124 pub wait_time: u64,
125
126 #[structopt(short, long, default_value = "0")]
128 pub rate: u64,
129
130 #[structopt(short, long, possible_values = &ScanOrderType::variants(), case_insensitive = true, default_value = "none")]
132 pub scan: ScanOrderType,
133
134 #[structopt(short, long, possible_values = &ScanModelType::variants(), case_insensitive = true, default_value = "none")]
136 pub model: ScanModelType,
137
138 #[structopt(long, possible_values = &ScriptsRequired::variants(), case_insensitive = true, default_value = "default")]
140 pub scripts: ScriptsRequired,
141
142 #[structopt(long)]
144 pub no_gui: bool,
145
146 #[allow(dead_code)]
149 #[structopt(short, long, parse(from_occurrences))]
150 pub verbose: u8,
151
152 #[structopt(required = false, last = true)]
158 pub command: Vec<String>,
159}
160
161#[cfg(not(tarpaulin_include))]
162impl Opts {
163 pub fn new<I>(args: Option<I>) -> Result<Self, String>
200 where
201 Self: Sized,
202 I: IntoIterator,
203 I::Item: Into<OsString> + Clone,
204 {
205 match args {
206 Some(arg) => match Opts::from_iter_safe(arg) {
207 Ok(opt) => Ok(opt),
208 Err(e) => Err(String::from(e.to_string())),
209 },
210 None => Ok(Opts::from_args()),
211 }
212 }
213}
214
215impl Opts {
216 pub fn init(&self) -> Result<Box<dyn Any>, String> {
218 let src_ip = if !self.src_ip.is_empty() {
220 match self.src_ip.parse::<IpAddr>() {
221 Ok(ip) => ip,
222 Err(e) => return Err(String::from(e.to_string())),
223 }
224 } else {
225 interface::get_local_ipaddr()?
226 };
227 let ports = parse_str_ports(&self.ports);
229 let ips = parse_ip_range(&self.ips).unwrap_or(vec![]);
231 match self.model {
232 ScanModelType::Sync => {
233 #[cfg(feature = "sync")]
235 {
236 let mut scanner = sync_scan::Scanner::new(src_ip)?;
237 if self.command.len() > 0 {
239 scanner.set_method(&&self.command)?;
240 }
241 for ip in ips {
242 scanner.add_destination(Destination::new(ip, ports.clone()));
244 }
245 scanner.set_send_rate(Duration::from_millis(self.rate));
247 scanner.set_timeout(Duration::from_millis(self.timeout));
249 scanner.set_wait_time(Duration::from_millis(self.wait_time));
251 if let Some(t) = parse_scan_type(&self.scan) {
253 scanner.set_scan_type(t);
254 } else if ports.len() > 0 {
255 scanner.set_scan_type(ScanType::TcpConnectScan);
256 } else {
257 scanner.set_scan_type(ScanType::IcmpPingScan);
258 }
259 Ok(Box::new(scanner))
260 }
261 #[cfg(not(feature = "sync"))]
262 Ok(Box::new(()))
263 }
264 ScanModelType::Async => {
265 #[cfg(feature = "async")]
267 {
268 let mut scanner = async_scan::Scanner::new(src_ip)?;
269 for ip in ips {
270 scanner.add_destination(Destination::new(ip, ports.clone()));
272 }
273 scanner.set_send_rate(Duration::from_millis(self.rate));
275 scanner.set_timeout(Duration::from_millis(self.timeout));
277 scanner.set_wait_time(Duration::from_millis(self.wait_time));
279
280 if let Some(t) = parse_scan_type(&self.scan) {
282 scanner.set_scan_type(t);
283 } else if ports.len() > 0 {
284 scanner.set_scan_type(ScanType::TcpConnectScan);
285 } else {
286 scanner.set_scan_type(ScanType::IcmpPingScan);
287 }
288 Ok(Box::new(scanner))
289 }
290 #[cfg(not(feature = "async"))]
291 Ok(Box::new(()))
292 }
293 ScanModelType::Os => {
294 #[cfg(feature = "os")]
296 {
297 let mut scanner = os::Scanner::new(src_ip)?;
298 if self.command.len() > 0 {
300 scanner.set_method(&&self.command)?;
301 }
302 scanner.set_send_rate(Duration::from_millis(self.rate));
304 scanner.set_timeout(Duration::from_millis(self.timeout));
306 scanner.set_wait_time(Duration::from_millis(self.wait_time));
308 scanner.set_full_probe();
310 for ip in ips {
311 let probe_target = os::ProbeTarget {
312 ip_addr: ip,
313 open_tcp_ports: vec![80, 135, 554, 8000, 22],
314 closed_tcp_port: 443,
315 open_udp_port: 123,
316 closed_udp_port: 33455,
317 };
318 scanner.add_probe_target(probe_target);
320 }
321 Ok(Box::new(scanner))
322 }
323 #[cfg(not(feature = "os"))]
324 Ok(Box::new(()))
325 }
326 ScanModelType::Service => {
327 #[cfg(feature = "service")]
329 {
330 let mut scanner = sync_scan::Scanner::new(src_ip)?;
331 scanner.set_send_rate(Duration::from_millis(self.rate));
333 scanner.set_timeout(Duration::from_millis(self.timeout));
335 scanner.set_wait_time(Duration::from_millis(self.wait_time));
337 if let Some(t) = parse_scan_type(&self.scan) {
339 scanner.set_scan_type(t);
340 } else {
341 scanner.set_scan_type(ScanType::TcpSynScan);
342 }
343 for ip in ips {
344 scanner.add_destination(Destination::new(ip, ports.clone()));
346 }
347 Ok(Box::new(scanner))
348 }
349 #[cfg(not(feature = "service"))]
350 Ok(Box::new(()))
351 }
352 ScanModelType::Dns => return Ok(Box::new(parse_dns(self.ips.clone()))),
353 ScanModelType::Traceroute => {
354 return Ok(Box::new(Tracert::new(
355 self.ips.clone(),
356 if self.src_ip.is_empty() {
357 None
358 } else {
359 match self.src_ip.parse::<IpAddr>() {
360 Ok(ip) => Some(ip),
361 Err(_) => None,
362 }
363 },
364 )))
365 }
366 ScanModelType::None => Ok(Box::new(())),
367 }
368 }
369}
370
371fn parse_dns(target: Vec<String>) -> DnsResults {
373 target
374 .into_iter()
375 .map(|src| match src.parse::<IpAddr>() {
376 Ok(ip) => match dns::lookup_addr(&ip) {
377 Ok(dns_name) => DnsResult {
378 src,
379 result: DnsResultType::Host(dns_name),
380 },
381 Err(e) => DnsResult {
382 src,
383 result: DnsResultType::Error(e.to_string()),
384 },
385 },
386 Err(_) => match dns::lookup_host(&src) {
387 Ok(addr) => DnsResult {
388 src,
389 result: DnsResultType::Addr(addr),
390 },
391 Err(e) => DnsResult {
392 src,
393 result: DnsResultType::Error(e),
394 },
395 },
396 })
397 .collect::<Vec<DnsResult>>()
398}
399
400pub fn parse_ip_range(input: &Vec<String>) -> Result<Vec<IpAddr>, String> {
402 let mut ips = vec![];
403 for s in input {
404 if s.contains('/') {
405 match s.parse::<IpNet>() {
408 Ok(ipnet) => ips.append(&mut ipnet.hosts().collect::<Vec<IpAddr>>()),
409 Err(e) => return Err(e.to_string()),
410 }
411 } else if s.contains('-') {
412 let ipv4 = s.split('.').collect::<Vec<&str>>();
415 if ipv4.len() == 4 {
416 let mut range_ip = vec![];
417 for ip in ipv4 {
418 let r = ip.split_once('-').unwrap_or((ip, ip));
419 range_ip.push((
420 r.0.parse::<u8>().unwrap_or(0),
421 r.1.parse::<u8>().unwrap_or(0),
422 ));
423 }
424 for v1 in range_ip[0].0..range_ip[0].1 + 1 {
425 for v2 in range_ip[1].0..range_ip[1].1 + 1 {
426 for v3 in range_ip[2].0..range_ip[2].1 + 1 {
427 for v4 in range_ip[3].0..range_ip[3].1 + 1 {
428 ips.push(IpAddr::V4(Ipv4Addr::new(v1, v2, v3, v4)))
429 }
430 }
431 }
432 }
433 } else {
434 return Err(String::from("cannot parse range[-] of ipv4"));
435 }
436 } else {
437 match dns::lookup_host(s) {
440 Ok(mut addrs) => ips.append(&mut addrs),
441 Err(_) => {
442 match s.parse::<IpAddr>() {
445 Ok(ipnet) => ips.push(ipnet),
446 Err(e) => return Err(e.to_string()),
447 }
448 }
449 }
450 }
451 }
452 Ok(ips)
453}
454
455fn parse_str_ports(input: &Vec<String>) -> Vec<u16> {
457 let mut ports = vec![];
458 for s in input {
459 if s.contains('-') {
460 if let Some(r) = s.split_once('-') {
461 if let Ok(start) = r.0.parse::<u16>() {
462 if let Ok(end) = r.1.parse::<u16>() {
463 if start < end {
464 ports.append(&mut (start..end).collect::<Vec<u16>>());
465 }
466 }
467 };
468 }
469 } else {
470 if let Ok(port) = s.parse::<u16>() {
471 ports.push(port)
472 }
473 }
474 }
475 ports
476}
477fn parse_scan_type(scan_type: &ScanOrderType) -> Option<ScanType> {
479 match scan_type {
480 ScanOrderType::None => None,
481 ScanOrderType::Icmp => Some(ScanType::IcmpPingScan),
482 ScanOrderType::TcpConnect => Some(ScanType::TcpConnectScan),
483 ScanOrderType::Udp => Some(ScanType::UdpPingScan),
484 ScanOrderType::Tcp => Some(ScanType::TcpPingScan),
485 ScanOrderType::TcpSyn => Some(ScanType::TcpSynScan),
486 }
487}