e_libscanner/utils/
cmd_input.rs

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    /// Script
28    #[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    /// scan type
38    #[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    /// scan type
52    #[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/// Opts
64/// # Examples
65/// ```
66/// use e_libscanner::Opts;
67/// fn main() -> Result<(), String> {
68///     // more command information use: -h
69///     let opts = Opts::new(Some(&[
70///         "e-libscanner",
71///         "--ips",
72///         "192.168.9.8",
73///         "192.168.1.0/23",
74///         "192.168.10-11.0-254",
75///         "--ports",
76///         "80",
77///         "22",
78///         // "--src-ip",
79///         // "127.0.0.1",
80///         "--timeout",
81///         "3000",
82///         "--wait-time",
83///         "1000",
84///         "--rate",
85///         "0",
86///         "--model",
87///         "os",
88///         "--scan",
89///         "tcp",
90///         "--scripts",
91///         "default",
92///         "--no-gui",
93///         "-vvv",
94///         "--",
95///         "-AS",
96///     ]))?
97///     .init()?;
98///     println!("{:?}", opts);
99///     Ok(())
100/// }
101/// ```
102#[derive(StructOpt, Debug)]
103#[structopt(name = "", setting = structopt::clap::AppSettings::TrailingVarArg)]
104#[allow(clippy::struct_excessive_bools)]
105pub struct Opts {
106    /// host list; example: "192.168.1.1", "192.168.1.0/24", "192.168.8-9.80-100", "baidu.com"
107    #[structopt(short, long, use_delimiter = true)]
108    pub ips: Vec<String>,
109
110    /// port list; Example: 80,443,8080,100-1000.
111    #[structopt(short, long, use_delimiter = true)]
112    pub ports: Vec<String>,
113
114    /// use it ip match network interface of hardware;
115    #[structopt(long, default_value = "")]
116    pub src_ip: String,
117
118    /// The timeout in milliseconds before a port is assumed to be closed; default is 3_600_000ms
119    #[structopt(short, long, default_value = "3600000")]
120    pub timeout: u64,
121
122    /// Waiting time after packet sending task is completed; default is 3000ms
123    #[structopt(long, default_value = "3000")]
124    pub wait_time: u64,
125
126    /// Packet sending interval(0 for unlimited); default is 0
127    #[structopt(short, long, default_value = "0")]
128    pub rate: u64,
129
130    /// send type; [ Icmp, TcpConnect, Udp, Tcp, TcpSyn]; default: None;  
131    #[structopt(short, long, possible_values = &ScanOrderType::variants(), case_insensitive = true, default_value = "none")]
132    pub scan: ScanOrderType,
133
134    /// scan type; [ Sync, Async, Os, Service, Dns, Traceroute ]; default: sync
135    #[structopt(short, long, possible_values = &ScanModelType::variants(), case_insensitive = true, default_value = "none")]
136    pub model: ScanModelType,
137
138    /// scripts
139    #[structopt(long, possible_values = &ScriptsRequired::variants(), case_insensitive = true, default_value = "default")]
140    pub scripts: ScriptsRequired,
141
142    /// no gui window
143    #[structopt(long)]
144    pub no_gui: bool,
145
146    // The number of occurrences of the `v/verbose` flag
147    /// Verbose mode (-v, -vv, -vvv, etc.)
148    #[allow(dead_code)]
149    #[structopt(short, long, parse(from_occurrences))]
150    pub verbose: u8,
151
152    /// Extend command;
153    /// example: e-libscanner --ips baidu.com 192.168.1.0/24
154    ///         --model sync --scan icmp --no-gui -- -AS
155    /// commads:
156    /// -- -AS: ARP Spoofing,
157    #[structopt(required = false, last = true)]
158    pub command: Vec<String>,
159}
160
161#[cfg(not(tarpaulin_include))]
162impl Opts {
163    /// # Example
164    /// ```
165    /// let mut scanner = Opts::new(Some(&[
166    /// "e-libscanner",
167    /// "--ips",
168    /// "192.168.80.0/21",
169    /// "192.168.20-21.15-20",
170    /// "baidu.com",
171    /// "--model",
172    /// "sync",
173    /// "--scan",
174    /// "Icmp",
175    /// "--no-gui",
176    /// "--",
177    /// "-AS",
178    /// ]))
179    /// .init()?
180    /// .downcast::<sync_scan::Scanner>()
181    /// .unwrap();
182    /// let rx = scanner.get_progress_receiver();
183    /// // Run scan
184    /// let handle = thread::spawn(move || scanner.scan(None));
185    /// // Print progress
186    /// while let Ok(socket_addr) = rx.lock().unwrap().recv() {
187    /// println!("Check: {}", socket_addr);
188    /// }
189    /// let result = handle.join().unwrap();
190    /// // Print results
191    /// println!("Status: {:?}", result.scan_status);
192    /// println!("UP Hosts:");
193    /// let len = result.ips.len();
194    /// for host in result.ips {
195    /// println!("{:?}", host);
196    /// }
197    /// println!("Scan Time: {:?} count[ {} ]", result.scan_time, len);
198    /// ```
199    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    /// init opts data
217    pub fn init(&self) -> Result<Box<dyn Any>, String> {
218        // if not set interface ip, then throgh tcp find interface ip;
219        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        // parse ports
228        let ports = parse_str_ports(&self.ports);
229        // parse ips
230        let ips = parse_ip_range(&self.ips).unwrap_or(vec![]);
231        match self.model {
232            ScanModelType::Sync => {
233                // sync scan
234                #[cfg(feature = "sync")]
235                {
236                    let mut scanner = sync_scan::Scanner::new(src_ip)?;
237                    // set methods
238                    if self.command.len() > 0 {
239                        scanner.set_method(&&self.command)?;
240                    }
241                    for ip in ips {
242                        // add scan target
243                        scanner.add_destination(Destination::new(ip, ports.clone()));
244                    }
245                    // set scan rate
246                    scanner.set_send_rate(Duration::from_millis(self.rate));
247                    // set timeout
248                    scanner.set_timeout(Duration::from_millis(self.timeout));
249                    // set wating for time of during
250                    scanner.set_wait_time(Duration::from_millis(self.wait_time));
251                    // set scan type
252                    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                // async scan
266                #[cfg(feature = "async")]
267                {
268                    let mut scanner = async_scan::Scanner::new(src_ip)?;
269                    for ip in ips {
270                        // add scan target
271                        scanner.add_destination(Destination::new(ip, ports.clone()));
272                    }
273                    // set scan rate
274                    scanner.set_send_rate(Duration::from_millis(self.rate));
275                    // set timeout
276                    scanner.set_timeout(Duration::from_millis(self.timeout));
277                    // set wating for time of during
278                    scanner.set_wait_time(Duration::from_millis(self.wait_time));
279
280                    // set scan type
281                    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                // init OS(osscan guess) data
295                #[cfg(feature = "os")]
296                {
297                    let mut scanner = os::Scanner::new(src_ip)?;
298                    // set methods
299                    if self.command.len() > 0 {
300                        scanner.set_method(&&self.command)?;
301                    }
302                    // set scan rate
303                    scanner.set_send_rate(Duration::from_millis(self.rate));
304                    // set timeout
305                    scanner.set_timeout(Duration::from_millis(self.timeout));
306                    // set wating for time of during
307                    scanner.set_wait_time(Duration::from_millis(self.wait_time));
308                    // set probe type: default full open
309                    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                        // add scan target
319                        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                // scan service
328                #[cfg(feature = "service")]
329                {
330                    let mut scanner = sync_scan::Scanner::new(src_ip)?;
331                    // set scan rate
332                    scanner.set_send_rate(Duration::from_millis(self.rate));
333                    // set tiemout
334                    scanner.set_timeout(Duration::from_millis(self.timeout));
335                    // set scan watting for time
336                    scanner.set_wait_time(Duration::from_millis(self.wait_time));
337                    // set scan type
338                    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                        // add scan target
345                        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
371/// parse dns and address
372fn 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
400/// parse ip from string list
401pub 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            // ipv4 parse example: 192.168.8.0/24 -> [192.168.8.1..192.168.8.254];
406            // ipv6 parse fd00::/32 -> [fd00::..]
407            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            // ipv4 parse exmaple: 192.168.8-9.10-20 -> [192.168.8.10..192.168.8.20];
413            // ipv6 parse example:
414            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            // ipv4 parse exmaple: baidu.com -> [110.242.68.66, 110.242.68.67]
438            // ipv6 parse exmaple:
439            match dns::lookup_host(s) {
440                Ok(mut addrs) => ips.append(&mut addrs),
441                Err(_) => {
442                    // ipv4 parse example: 192.168.8.1
443                    // ipv6 parse exmaple: fe80::ac47:a2d1:c566:2c6d
444                    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
455/// parse port from string
456fn 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}
477/// parse scan type
478fn 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}