1#[cfg(feature = "ping")]
2use chrono::DateTime;
3#[cfg(feature = "ping")]
4use chrono::Local;
5#[cfg(feature = "ping")]
6use prettytable::Cell;
7#[cfg(feature = "ping")]
8use prettytable::Row;
9#[cfg(feature = "ping")]
10use prettytable::Table;
11#[cfg(feature = "ping")]
12use prettytable::row;
13#[cfg(feature = "ping")]
14use std::collections::BTreeMap;
15#[cfg(feature = "ping")]
16use std::fmt;
17#[cfg(feature = "ping")]
18use std::net::IpAddr;
19#[cfg(feature = "ping")]
20use std::net::Ipv4Addr;
21#[cfg(feature = "ping")]
22use std::net::Ipv6Addr;
23#[cfg(feature = "ping")]
24use std::sync::mpsc::channel;
25#[cfg(feature = "ping")]
26use std::time::Duration;
27#[cfg(feature = "ping")]
28use std::time::Instant;
29#[cfg(feature = "ping")]
30use tracing::error;
31
32#[cfg(feature = "ping")]
33pub mod icmp;
34#[cfg(feature = "ping")]
35pub mod icmpv6;
36
37#[cfg(feature = "ping")]
38use crate::Target;
39#[cfg(feature = "ping")]
40use crate::error::PistolError;
41#[cfg(feature = "ping")]
42use crate::layer::infer_addr;
43#[cfg(feature = "ping")]
44use crate::scan::DataRecvStatus;
45#[cfg(feature = "ping")]
46use crate::scan::PortStatus;
47#[cfg(feature = "ping")]
48use crate::scan::tcp;
49#[cfg(feature = "ping")]
50use crate::scan::tcp6;
51#[cfg(feature = "ping")]
52use crate::scan::udp;
53#[cfg(feature = "ping")]
54use crate::scan::udp6;
55#[cfg(feature = "ping")]
56use crate::utils::get_threads_pool;
57#[cfg(feature = "ping")]
58use crate::utils::num_threads_check;
59#[cfg(feature = "ping")]
60use crate::utils::random_port;
61#[cfg(feature = "ping")]
62use crate::utils::time_sec_to_string;
63#[cfg(feature = "ping")]
64use tracing::warn;
65
66#[cfg(feature = "ping")]
67const SYN_PING_DEFAULT_PORT: u16 = 80;
68#[cfg(feature = "ping")]
69const ACK_PING_DEFAULT_PORT: u16 = 80;
70#[cfg(feature = "ping")]
71const UDP_PING_DEFAULT_PORT: u16 = 125;
72
73#[cfg(feature = "ping")]
74#[derive(Debug, Clone, Copy, PartialEq)]
75pub enum PingStatus {
76 Up,
77 Down,
78 Error,
79}
80
81#[cfg(feature = "ping")]
82impl fmt::Display for PingStatus {
83 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
84 let s = match self {
85 PingStatus::Up => "up",
86 PingStatus::Down => "down",
87 PingStatus::Error => "error",
88 };
89 write!(f, "{}", s)
90 }
91}
92
93#[cfg(feature = "ping")]
94#[derive(Debug, Clone)]
95pub struct PingReport {
96 pub addr: IpAddr,
97 pub origin: Option<String>,
98 pub status: PingStatus,
99 pub cost: Duration,
100}
101
102#[cfg(feature = "ping")]
103#[derive(Debug, Clone)]
104pub struct PistolPings {
105 pub ping_reports: Vec<PingReport>,
106 pub start_time: DateTime<Local>,
107 pub end_time: DateTime<Local>,
108 max_attempts: usize,
109}
110
111#[cfg(feature = "ping")]
112impl PistolPings {
113 pub fn new(max_attempts: usize) -> PistolPings {
114 PistolPings {
115 ping_reports: Vec::new(),
116 start_time: Local::now(),
117 end_time: Local::now(),
118 max_attempts,
119 }
120 }
121 pub fn value(&self) -> Vec<PingReport> {
122 self.ping_reports.clone()
123 }
124 pub fn finish(&mut self, ping_reports: Vec<PingReport>) {
125 self.end_time = Local::now();
126 self.ping_reports = ping_reports;
127 }
128}
129
130#[cfg(feature = "ping")]
131impl fmt::Display for PistolPings {
132 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
133 let total_cost = self.end_time - self.start_time;
134
135 let mut table = Table::new();
136 table.add_row(Row::new(vec![
137 Cell::new(&format!(
138 "Ping Results (max_attempts:{})",
139 self.max_attempts
140 ))
141 .style_spec("c")
142 .with_hspan(4),
143 ]));
144
145 table.add_row(row![
146 c -> "id",
147 c -> "addr",
148 c -> "status",
149 c -> "time cost"
150 ]);
151
152 let mut btm_addr: BTreeMap<IpAddr, PingReport> = BTreeMap::new();
154 for report in &self.ping_reports {
155 btm_addr.insert(report.addr, report.clone());
156 }
157
158 let mut alive_hosts = 0;
159 let mut i = 1;
160 for (_addr, report) in btm_addr {
161 match report.status {
162 PingStatus::Up => alive_hosts += 1,
163 _ => (),
164 }
165 let addr_str = match report.origin {
166 Some(o) => format!("{}({})", report.addr, o),
167 None => format!("{}", report.addr),
168 };
169 let status_str = format!("{}", report.status);
170 let rtt_str = time_sec_to_string(report.cost);
171 table.add_row(row![c -> i, c -> addr_str, c -> status_str, c -> rtt_str]);
172 i += 1;
173 }
174
175 let avg_cost = total_cost.as_seconds_f64() / self.ping_reports.len() as f64;
179 let summary = format!(
180 "total cost: {:.3}s\navg cost: {:.3}s\nalive hosts: {}",
181 total_cost.as_seconds_f64(),
182 avg_cost,
183 alive_hosts,
184 );
185 table.add_row(Row::new(vec![Cell::new(&summary).with_hspan(4)]));
186 write!(f, "{}", table)
187 }
188}
189
190#[cfg(feature = "ping")]
191#[derive(Debug, Clone, Copy, PartialEq)]
192pub enum PingMethods {
193 Syn,
194 Ack,
195 Udp,
196 IcmpEcho,
197 IcmpTimeStamp,
198 IcmpAddressMask,
199 Icmpv6Echo,
200}
201
202#[cfg(feature = "ping")]
203fn ping_thread(
204 method: PingMethods,
205 dst_ipv4: Ipv4Addr,
206 dst_port: Option<u16>,
207 src_ipv4: Ipv4Addr,
208 src_port: u16,
209 timeout: Option<Duration>,
210) -> Result<(PingStatus, DataRecvStatus, Duration), PistolError> {
211 let (ping_status, data_return, rtt) = match method {
212 PingMethods::Syn => {
213 let dst_port = match dst_port {
214 Some(p) => p,
215 None => SYN_PING_DEFAULT_PORT,
216 };
217
218 let (port_status, data_return, rtt) =
219 tcp::send_syn_scan_packet(dst_ipv4, dst_port, src_ipv4, src_port, timeout)?;
220 match port_status {
221 PortStatus::Open => (PingStatus::Up, data_return, rtt),
222 _ => (PingStatus::Down, data_return, rtt),
223 }
224 }
225 PingMethods::Ack => {
226 let dst_port = match dst_port {
227 Some(p) => p,
228 None => ACK_PING_DEFAULT_PORT,
229 };
230
231 let (ret, data_return, rtt) =
232 tcp::send_ack_scan_packet(dst_ipv4, dst_port, src_ipv4, src_port, timeout)?;
233 match ret {
234 PortStatus::Unfiltered => (PingStatus::Up, data_return, rtt),
235 _ => (PingStatus::Down, data_return, rtt),
236 }
237 }
238 PingMethods::Udp => {
239 let dst_port = match dst_port {
240 Some(p) => p,
241 None => UDP_PING_DEFAULT_PORT,
242 };
243
244 let (ret, data_return, rtt) =
245 udp::send_udp_scan_packet(dst_ipv4, dst_port, src_ipv4, src_port, timeout)?;
246 match ret {
247 PortStatus::Open => (PingStatus::Up, data_return, rtt),
248 _ => (PingStatus::Down, data_return, rtt),
250 }
251 }
252 PingMethods::IcmpEcho => {
253 let (ret, data_return, rtt) = icmp::send_icmp_echo_packet(dst_ipv4, src_ipv4, timeout)?;
254 (ret, data_return, rtt)
255 }
256 PingMethods::IcmpTimeStamp => {
257 let (ret, data_return, rtt) =
258 icmp::send_icmp_timestamp_packet(dst_ipv4, src_ipv4, timeout)?;
259 (ret, data_return, rtt)
260 }
261 PingMethods::IcmpAddressMask => {
262 let (ret, data_return, rtt) =
263 icmp::send_icmp_address_mask_packet(dst_ipv4, src_ipv4, timeout)?;
264 (ret, data_return, rtt)
265 }
266 PingMethods::Icmpv6Echo => {
267 return Err(PistolError::PingDetectionMethodError {
268 target: dst_ipv4.into(),
269 method: String::from("icmpv6"),
270 });
271 }
272 };
273 Ok((ping_status, data_return, rtt))
274}
275
276#[cfg(feature = "ping")]
277fn ping_thread6(
278 method: PingMethods,
279 dst_ipv6: Ipv6Addr,
280 dst_port: Option<u16>,
281 src_ipv6: Ipv6Addr,
282 src_port: u16,
283 timeout: Option<Duration>,
284) -> Result<(PingStatus, DataRecvStatus, Duration), PistolError> {
285 let (ping_status, data_return, rtt) = match method {
286 PingMethods::Syn => {
287 let dst_port = match dst_port {
288 Some(p) => p,
289 None => SYN_PING_DEFAULT_PORT,
290 };
291
292 let (ret, data_return, rtt) =
293 tcp6::send_syn_scan_packet(dst_ipv6, dst_port, src_ipv6, src_port, timeout)?;
294 match ret {
295 PortStatus::Open => (PingStatus::Up, data_return, rtt),
296 _ => (PingStatus::Down, data_return, rtt),
297 }
298 }
299 PingMethods::Ack => {
300 let dst_port = match dst_port {
301 Some(p) => p,
302 None => ACK_PING_DEFAULT_PORT,
303 };
304
305 let (ret, data_return, rtt) =
306 tcp6::send_ack_scan_packet(dst_ipv6, dst_port, src_ipv6, src_port, timeout)?;
307 match ret {
308 PortStatus::Unfiltered => (PingStatus::Up, data_return, rtt),
309 _ => (PingStatus::Down, data_return, rtt),
310 }
311 }
312 PingMethods::Udp => {
313 let dst_port = match dst_port {
314 Some(p) => p,
315 None => UDP_PING_DEFAULT_PORT,
316 };
317
318 let (ret, data_return, rtt) =
319 udp6::send_udp_scan_packet(dst_ipv6, dst_port, src_ipv6, src_port, timeout)?;
320 match ret {
321 PortStatus::Open => (PingStatus::Up, data_return, rtt),
322 PortStatus::OpenOrFiltered => (PingStatus::Up, data_return, rtt),
323 _ => (PingStatus::Down, data_return, rtt),
324 }
325 }
326 PingMethods::IcmpEcho | PingMethods::IcmpTimeStamp | PingMethods::IcmpAddressMask => {
327 return Err(PistolError::PingDetectionMethodError {
328 target: dst_ipv6.into(),
329 method: String::from("icmp"),
330 });
331 }
332 PingMethods::Icmpv6Echo => icmpv6::send_icmpv6_ping_packet(dst_ipv6, src_ipv6, timeout)?,
333 };
334 Ok((ping_status, data_return, rtt))
335}
336
337#[cfg(feature = "ping")]
338fn ping(
339 targets: &[Target],
340 num_threads: Option<usize>,
341 method: PingMethods,
342 src_addr: Option<IpAddr>,
343 src_port: Option<u16>,
344 timeout: Option<Duration>,
345 max_attempts: usize,
346) -> Result<PistolPings, PistolError> {
347 let mut pistol_pings = PistolPings::new(max_attempts);
348
349 let num_threads = match num_threads {
350 Some(t) => t,
351 None => {
352 let num_threads = targets.len();
353 let num_threads = num_threads_check(num_threads);
354 num_threads
355 }
356 };
357
358 let pool = get_threads_pool(num_threads);
359 let (tx, rx) = channel();
360 let mut recv_size = 0;
361
362 for target in targets {
363 let dst_addr = target.addr;
364 let origin = target.origin.clone();
365 match dst_addr {
366 IpAddr::V4(_) => {
367 let src_port = match src_port {
368 Some(p) => p,
369 None => random_port(),
370 };
371 let tx = tx.clone();
372 let (dst_ipv4, src_ipv4) = match infer_addr(dst_addr, src_addr)? {
373 Some(ia) => ia.ipv4_addr()?,
374 None => return Err(PistolError::CanNotFoundSourceAddress),
375 };
376 let dst_port = if target.ports.len() > 0 {
378 Some(target.ports[0])
379 } else {
380 None
381 };
382
383 let no_port_vec = vec![
384 PingMethods::IcmpEcho,
385 PingMethods::IcmpTimeStamp,
386 PingMethods::Icmpv6Echo,
387 ];
388
389 let dst_port = if !no_port_vec.contains(&method) {
390 dst_port
391 } else {
392 None
393 };
394 recv_size += 1;
395 pool.execute(move || {
396 for ind in 0..max_attempts {
397 let start_time = Instant::now();
398 let ping_ret =
399 ping_thread(method, dst_ipv4, dst_port, src_ipv4, src_port, timeout);
400 if ind == max_attempts - 1 {
401 let _ =
403 tx.send((dst_addr, origin.clone(), ping_ret, start_time.elapsed()));
404 } else {
405 match ping_ret {
406 Ok((_port_status, data_return, _)) => {
407 match data_return {
408 DataRecvStatus::Yes => {
409 let _ = tx.send((
411 dst_addr,
412 origin.clone(),
413 ping_ret,
414 start_time.elapsed(),
415 ));
416 break; }
418 DataRecvStatus::No => (), }
421 }
422 Err(_) => {
423 let _ = tx.send((
425 dst_addr,
426 origin.clone(),
427 ping_ret,
428 start_time.elapsed(),
429 ));
430 break;
431 }
432 }
433 }
434 }
435 });
436 }
437 IpAddr::V6(_) => {
438 let src_port = match src_port {
439 Some(p) => p,
440 None => random_port(),
441 };
442 let tx = tx.clone();
443 let (dst_ipv6, src_ipv6) = match infer_addr(dst_addr, src_addr)? {
444 Some(ia) => ia.ipv6_addr()?,
445 None => return Err(PistolError::CanNotFoundSourceAddress),
446 };
447 let dst_port = if target.ports.len() > 0 {
448 Some(target.ports[0])
449 } else {
450 None
451 };
452 let dst_port =
453 if method != PingMethods::IcmpEcho && method != PingMethods::Icmpv6Echo {
454 dst_port
455 } else {
456 None
457 };
458 recv_size += 1;
459 pool.execute(move || {
460 for ind in 0..max_attempts {
461 let start_time = Instant::now();
462 let ping_ret =
463 ping_thread6(method, dst_ipv6, dst_port, src_ipv6, src_port, timeout);
464 if ind == max_attempts - 1 {
465 let _ =
467 tx.send((dst_addr, origin.clone(), ping_ret, start_time.elapsed()));
468 } else {
469 match ping_ret {
470 Ok((_port_status, data_return, _)) => {
471 match data_return {
472 DataRecvStatus::Yes => {
473 let _ = tx.send((
475 dst_addr,
476 origin.clone(),
477 ping_ret,
478 start_time.elapsed(),
479 ));
480 break; }
482 DataRecvStatus::No => (), }
485 }
486 Err(_) => {
487 let _ = tx.send((
489 dst_addr,
490 origin.clone(),
491 ping_ret,
492 start_time.elapsed(),
493 ));
494 break;
495 }
496 }
497 }
498 }
499 });
500 }
501 }
502 }
503
504 let iter = rx.into_iter().take(recv_size);
505 let mut reports = Vec::new();
506 for (dst_addr, origin, v, elapsed) in iter {
507 match v {
508 Ok((status, _data_return, rtt)) => {
509 let ping_report = PingReport {
510 addr: dst_addr,
511 origin,
512 status,
513 cost: rtt,
514 };
515 reports.push(ping_report);
516 }
517 Err(e) => match e {
518 PistolError::CanNotFoundMacAddress => {
519 let scan_report = PingReport {
520 addr: dst_addr,
521 origin,
522 status: PingStatus::Down,
523 cost: elapsed,
524 };
525 reports.push(scan_report);
526 }
527 _ => {
528 error!("ping error: {}", e);
529 let scan_report = PingReport {
530 addr: dst_addr,
531 origin,
532 status: PingStatus::Error,
533 cost: elapsed,
534 };
535 reports.push(scan_report);
536 }
537 },
538 }
539 }
540 pistol_pings.finish(reports);
541 Ok(pistol_pings)
542}
543
544#[cfg(feature = "ping")]
548pub fn tcp_syn_ping(
549 targets: &[Target],
550 num_threads: Option<usize>,
551 src_addr: Option<IpAddr>,
552 src_port: Option<u16>,
553 timeout: Option<Duration>,
554 max_attempts: usize,
555) -> Result<PistolPings, PistolError> {
556 ping(
557 targets,
558 num_threads,
559 PingMethods::Syn,
560 src_addr,
561 src_port,
562 timeout,
563 max_attempts,
564 )
565}
566
567#[cfg(feature = "ping")]
569pub fn tcp_syn_ping_raw(
570 dst_addr: IpAddr,
571 dst_port: u16,
572 src_addr: Option<IpAddr>,
573 src_port: Option<u16>,
574 timeout: Option<Duration>,
575) -> Result<(PingStatus, Duration), PistolError> {
576 let src_port = match src_port {
577 Some(p) => p,
578 None => random_port(),
579 };
580 let ia = match infer_addr(dst_addr, src_addr)? {
581 Some(ia) => ia,
582 None => return Err(PistolError::CanNotFoundSourceAddress),
583 };
584 match dst_addr {
585 IpAddr::V4(_) => {
586 let (dst_ipv4, src_ipv4) = ia.ipv4_addr()?;
587 let (ret, _data_return, rtt) =
588 tcp::send_syn_scan_packet(dst_ipv4, dst_port, src_ipv4, src_port, timeout)?;
589 let (s, rtt) = match ret {
590 PortStatus::Open => (PingStatus::Up, rtt),
591 _ => (PingStatus::Down, rtt),
592 };
593 Ok((s, rtt))
594 }
595 IpAddr::V6(_) => {
596 let (dst_ipv6, src_ipv6) = ia.ipv6_addr()?;
597 let (ret, _data_return, rtt) =
598 tcp6::send_syn_scan_packet(dst_ipv6, dst_port, src_ipv6, src_port, timeout)?;
599 let (s, rtt) = match ret {
600 PortStatus::Open => (PingStatus::Up, rtt),
601 _ => (PingStatus::Down, rtt),
602 };
603 Ok((s, rtt))
604 }
605 }
606}
607
608#[cfg(feature = "ping")]
612pub fn tcp_ack_ping(
613 targets: &[Target],
614 num_threads: Option<usize>,
615 src_addr: Option<IpAddr>,
616 src_port: Option<u16>,
617 timeout: Option<Duration>,
618 max_attempts: usize,
619) -> Result<PistolPings, PistolError> {
620 ping(
621 targets,
622 num_threads,
623 PingMethods::Ack,
624 src_addr,
625 src_port,
626 timeout,
627 max_attempts,
628 )
629}
630
631#[cfg(feature = "ping")]
633pub fn tcp_ack_ping_raw(
634 dst_addr: IpAddr,
635 dst_port: u16,
636 src_addr: Option<IpAddr>,
637 src_port: Option<u16>,
638 timeout: Option<Duration>,
639) -> Result<(PingStatus, Duration), PistolError> {
640 let src_port = match src_port {
641 Some(p) => p,
642 None => random_port(),
643 };
644 let ia = match infer_addr(dst_addr, src_addr)? {
645 Some(ia) => ia,
646 None => return Err(PistolError::CanNotFoundSourceAddress),
647 };
648 match dst_addr {
649 IpAddr::V4(_) => {
650 let (dst_ipv4, src_ipv4) = ia.ipv4_addr()?;
651 let (ret, _data_return, rtt) =
652 tcp::send_ack_scan_packet(dst_ipv4, dst_port, src_ipv4, src_port, timeout)?;
653 let (s, rtt) = match ret {
654 PortStatus::Unfiltered => (PingStatus::Up, rtt),
655 _ => (PingStatus::Down, rtt),
656 };
657 Ok((s, rtt))
658 }
659 IpAddr::V6(_) => {
660 let (dst_ipv6, src_ipv6) = ia.ipv6_addr()?;
661 let (ret, _data_return, rtt) =
662 tcp6::send_ack_scan_packet(dst_ipv6, dst_port, src_ipv6, src_port, timeout)?;
663 let (s, rtt) = match ret {
664 PortStatus::Unfiltered => (PingStatus::Up, rtt),
665 _ => (PingStatus::Down, rtt),
666 };
667 Ok((s, rtt))
668 }
669 }
670}
671
672#[cfg(feature = "ping")]
676pub fn udp_ping(
677 targets: &[Target],
678 num_threads: Option<usize>,
679 src_addr: Option<IpAddr>,
680 src_port: Option<u16>,
681 timeout: Option<Duration>,
682 max_attempts: usize,
683) -> Result<PistolPings, PistolError> {
684 ping(
685 targets,
686 num_threads,
687 PingMethods::Udp,
688 src_addr,
689 src_port,
690 timeout,
691 max_attempts,
692 )
693}
694
695#[cfg(feature = "ping")]
697pub fn udp_ping_raw(
698 dst_addr: IpAddr,
699 dst_port: u16,
700 src_addr: Option<IpAddr>,
701 src_port: Option<u16>,
702 timeout: Option<Duration>,
703) -> Result<(PingStatus, Duration), PistolError> {
704 let src_port = match src_port {
705 Some(p) => p,
706 None => random_port(),
707 };
708 let ia = match infer_addr(dst_addr, src_addr)? {
709 Some(ia) => ia,
710 None => return Err(PistolError::CanNotFoundSourceAddress),
711 };
712 match dst_addr {
713 IpAddr::V4(_) => {
714 let (dst_ipv4, src_ipv4) = ia.ipv4_addr()?;
715 let (ret, _data_return, rtt) =
716 udp::send_udp_scan_packet(dst_ipv4, dst_port, src_ipv4, src_port, timeout)?;
717 let (s, rtt) = match ret {
718 PortStatus::Open => (PingStatus::Up, rtt),
719 _ => (PingStatus::Down, rtt),
721 };
722 Ok((s, rtt))
723 }
724 IpAddr::V6(_) => {
725 let (dst_ipv6, src_ipv6) = ia.ipv6_addr()?;
726 let (ret, _data_return, rtt) =
727 udp6::send_udp_scan_packet(dst_ipv6, dst_port, src_ipv6, src_port, timeout)?;
728 let (s, rtt) = match ret {
729 PortStatus::Open => (PingStatus::Up, rtt),
730 _ => (PingStatus::Down, rtt),
732 };
733 Ok((s, rtt))
734 }
735 }
736}
737
738#[cfg(feature = "ping")]
746pub fn icmp_echo_ping(
747 targets: &[Target],
748 num_threads: Option<usize>,
749 src_addr: Option<IpAddr>,
750 src_port: Option<u16>,
751 timeout: Option<Duration>,
752 max_attempts: usize,
753) -> Result<PistolPings, PistolError> {
754 ping(
755 targets,
756 num_threads,
757 PingMethods::IcmpEcho,
758 src_addr,
759 src_port,
760 timeout,
761 max_attempts,
762 )
763}
764
765#[cfg(feature = "ping")]
766pub fn icmp_echo_ping_raw(
767 dst_addr: IpAddr,
768 src_addr: Option<IpAddr>,
769 timeout: Option<Duration>,
770) -> Result<PingStatus, PistolError> {
771 let ia = match infer_addr(dst_addr, src_addr)? {
772 Some(ia) => ia,
773 None => return Err(PistolError::CanNotFoundSourceAddress),
774 };
775 match dst_addr {
776 IpAddr::V4(_) => {
777 let (dst_ipv4, src_ipv4) = ia.ipv4_addr()?;
778 let (ret, _data_return, _rtt) =
779 icmp::send_icmp_echo_packet(dst_ipv4, src_ipv4, timeout)?;
780 Ok(ret)
781 }
782 IpAddr::V6(_) => {
783 let (dst_ipv6, src_ipv6) = ia.ipv6_addr()?;
784 let (ret, _data_return, _rtt) =
785 icmpv6::send_icmpv6_ping_packet(dst_ipv6, src_ipv6, timeout)?;
786 Ok(ret)
787 }
788 }
789}
790
791#[cfg(feature = "ping")]
804pub fn icmp_timestamp_ping(
805 targets: &[Target],
806 num_threads: Option<usize>,
807 src_addr: Option<IpAddr>,
808 src_port: Option<u16>,
809 timeout: Option<Duration>,
810 max_attempts: usize,
811) -> Result<PistolPings, PistolError> {
812 ping(
813 targets,
814 num_threads,
815 PingMethods::IcmpTimeStamp,
816 src_addr,
817 src_port,
818 timeout,
819 max_attempts,
820 )
821}
822
823#[cfg(feature = "ping")]
824pub fn icmp_timestamp_ping_raw(
825 dst_addr: IpAddr,
826 src_addr: Option<IpAddr>,
827 timeout: Option<Duration>,
828) -> Result<PingStatus, PistolError> {
829 let ia = match infer_addr(dst_addr, src_addr)? {
830 Some(ia) => ia,
831 None => return Err(PistolError::CanNotFoundSourceAddress),
832 };
833 match dst_addr {
834 IpAddr::V4(_) => {
835 let (dst_ipv4, src_ipv4) = ia.ipv4_addr()?;
836 let (ret, _data_return, _rtt) =
837 icmp::send_icmp_timestamp_packet(dst_ipv4, src_ipv4, timeout)?;
838 Ok(ret)
839 }
840 IpAddr::V6(_) => {
841 warn!("ipv6 address not supported the icmp timestamp ping");
842 let (dst_ipv6, src_ipv6) = ia.ipv6_addr()?;
843 let (ret, _data_return, _rtt) =
844 icmpv6::send_icmpv6_ping_packet(dst_ipv6, src_ipv6, timeout)?;
845 Ok(ret)
846 }
847 }
848}
849
850#[cfg(feature = "ping")]
864pub fn icmp_address_mask_ping(
865 targets: &[Target],
866 num_threads: Option<usize>,
867 src_addr: Option<IpAddr>,
868 src_port: Option<u16>,
869 timeout: Option<Duration>,
870 max_attempts: usize,
871) -> Result<PistolPings, PistolError> {
872 ping(
873 targets,
874 num_threads,
875 PingMethods::IcmpAddressMask,
876 src_addr,
877 src_port,
878 timeout,
879 max_attempts,
880 )
881}
882
883#[cfg(feature = "ping")]
884pub fn icmp_address_mask_ping_raw(
885 dst_addr: IpAddr,
886 src_addr: Option<IpAddr>,
887 timeout: Option<Duration>,
888) -> Result<PingStatus, PistolError> {
889 let ia = match infer_addr(dst_addr, src_addr)? {
890 Some(ia) => ia,
891 None => return Err(PistolError::CanNotFoundSourceAddress),
892 };
893 match dst_addr {
894 IpAddr::V4(_) => {
895 let (dst_ipv4, src_ipv4) = ia.ipv4_addr()?;
896 let (ret, _data_return, _rtt) =
897 icmp::send_icmp_address_mask_packet(dst_ipv4, src_ipv4, timeout)?;
898 Ok(ret)
899 }
900 IpAddr::V6(_) => {
901 warn!("ipv6 address not supported the icmp address mask ping");
902 let (dst_ipv6, src_ipv6) = ia.ipv6_addr()?;
903 let (ret, _data_return, _rtt) =
904 icmpv6::send_icmpv6_ping_packet(dst_ipv6, src_ipv6, timeout)?;
905 Ok(ret)
906 }
907 }
908}
909
910#[cfg(feature = "ping")]
912pub fn icmpv6_ping(
913 targets: &[Target],
914 num_threads: Option<usize>,
915 src_addr: Option<IpAddr>,
916 src_port: Option<u16>,
917 timeout: Option<Duration>,
918 max_attempts: usize,
919) -> Result<PistolPings, PistolError> {
920 ping(
921 targets,
922 num_threads,
923 PingMethods::Icmpv6Echo,
924 src_addr,
925 src_port,
926 timeout,
927 max_attempts,
928 )
929}
930
931#[cfg(feature = "ping")]
933pub fn icmp_ping_raw(
934 dst_addr: IpAddr,
935 src_addr: Option<IpAddr>,
936 timeout: Option<Duration>,
937) -> Result<(PingStatus, Duration), PistolError> {
938 let ia = match infer_addr(dst_addr, src_addr)? {
939 Some(ia) => ia,
940 None => return Err(PistolError::CanNotFoundSourceAddress),
941 };
942 match dst_addr {
943 IpAddr::V4(_) => {
944 let (dst_ipv4, src_ipv4) = ia.ipv4_addr()?;
945 let (ret, _data_return, rtt) =
946 icmp::send_icmp_echo_packet(dst_ipv4, src_ipv4, timeout)?;
947 Ok((ret, rtt))
948 }
949 IpAddr::V6(_) => {
950 let (dst_ipv6, src_ipv6) = ia.ipv6_addr()?;
951 let (ret, _data_return, rtt) =
952 icmpv6::send_icmpv6_ping_packet(dst_ipv6, src_ipv6, timeout)?;
953 Ok((ret, rtt))
954 }
955 }
956}
957
958#[cfg(feature = "ping")]
959#[cfg(test)]
960mod max_attempts {
961 use super::*;
962 use crate::PistolLogger;
963 use crate::PistolRunner;
964 use crate::Target;
965 use std::str::FromStr;
966 #[test]
967 fn test_tcp_syn_ping() {
968 let _pr = PistolRunner::init(
969 PistolLogger::None,
970 Some(String::from("tcp_syn_ping.pcapng")),
971 None, )
973 .unwrap();
974 let src_ipv4 = None;
975 let src_port = None;
976 let timeout = Some(Duration::new(1, 0));
977 let addr1 = IpAddr::V4(Ipv4Addr::new(192, 168, 5, 2));
978 let addr2 = IpAddr::V4(Ipv4Addr::new(192, 168, 5, 5));
979 let addr3 = IpAddr::V4(Ipv4Addr::new(192, 168, 5, 10));
980 let target1 = Target::new(addr1, Some(vec![80]));
981 let target2 = Target::new(addr2, Some(vec![80]));
982 let target3 = Target::new(addr3, Some(vec![80]));
983 let max_attempts = 2;
984 let num_threads = Some(8);
985 let ret = tcp_syn_ping(
986 &[target1, target2, target3],
987 num_threads,
989 src_ipv4,
990 src_port,
991 timeout,
992 max_attempts,
993 )
994 .unwrap();
995 println!("{}", ret);
996 }
997 #[test]
998 fn test_tcp_syn_ping_raw() {
999 let _pr = PistolRunner::init(
1000 PistolLogger::None,
1001 Some(String::from("tcp_syn_ping_raw.pcapng")),
1002 None, )
1004 .unwrap();
1005 let src_ipv4 = None;
1006 let src_port = None;
1007 let timeout = Some(Duration::new(3, 0));
1008 let addr1 = IpAddr::V4(Ipv4Addr::new(192, 168, 5, 5));
1009 let dst_port = 80;
1010 let (ret, _rtt) = tcp_syn_ping_raw(addr1, dst_port, src_ipv4, src_port, timeout).unwrap();
1011 println!("{:?}", ret);
1012 }
1013 #[test]
1014 fn test_tcp_syn_ping6() {
1015 let _pr = PistolRunner::init(
1016 PistolLogger::None,
1017 Some(String::from("tcp_syn_ping6.pcapng")),
1018 None, )
1020 .unwrap();
1021 let src_ipv4 = None;
1022 let src_port = None;
1023 let timeout = Some(Duration::new(1, 0));
1024 let addr1 = Ipv6Addr::from_str("fe80::20c:29ff:fe2c:9e4").unwrap();
1025 let addr2 = Ipv6Addr::from_str("fe80::20c:29ff:fe2c:9e5").unwrap();
1026 let addr3 = Ipv6Addr::from_str("fe80::20c:29ff:fe2c:9e6").unwrap();
1027 let target1 = Target::new(addr1.into(), Some(vec![80]));
1028 let target2 = Target::new(addr2.into(), Some(vec![80]));
1029 let target3 = Target::new(addr3.into(), Some(vec![80]));
1030 let max_attempts = 4;
1031 let num_threads = Some(8);
1032 let ret = tcp_syn_ping(
1033 &[target1, target2, target3],
1034 num_threads,
1035 src_ipv4,
1036 src_port,
1037 timeout,
1038 max_attempts,
1039 )
1040 .unwrap();
1041 println!("{}", ret);
1042 }
1043 #[test]
1044 fn test_icmp_echo_ping() {
1045 let _pr = PistolRunner::init(
1046 PistolLogger::None,
1047 None,
1048 None, )
1050 .unwrap();
1051 let src_ipv4 = None;
1052 let src_port: Option<u16> = None;
1053 let timeout = Some(Duration::new(1, 0));
1054 let addr1 = Ipv4Addr::new(192, 168, 5, 5);
1055 let target1 = Target::new(addr1.into(), Some(vec![]));
1059 let max_attempts = 4;
1063 let num_threads = Some(8);
1064 let ret = icmp_echo_ping(
1065 &[target1],
1067 num_threads,
1068 src_ipv4,
1069 src_port,
1070 timeout,
1071 max_attempts,
1072 )
1073 .unwrap();
1074
1075 println!("{}", ret);
1076 }
1077 #[test]
1078 fn test_icmp_timestamp_ping() {
1079 let _pr = PistolRunner::init(
1080 PistolLogger::None,
1081 None,
1082 None, )
1084 .unwrap();
1085 let src_ipv4 = None;
1086 let src_port: Option<u16> = None;
1087 let timeout = Some(Duration::new(1, 0));
1088 let addr1 = Ipv4Addr::new(192, 168, 5, 5);
1089 let target1 = Target::new(addr1.into(), Some(vec![]));
1093 let max_attempts = 4;
1097 let num_threads = Some(8);
1098 let ret = icmp_timestamp_ping(
1099 &[target1],
1101 num_threads,
1102 src_ipv4,
1103 src_port,
1104 timeout,
1105 max_attempts,
1106 )
1107 .unwrap();
1108 println!("{}", ret);
1109 }
1110 #[test]
1111 fn test_icmp_ping_debug() {
1112 let _pr = PistolRunner::init(
1113 PistolLogger::None,
1114 None,
1115 None, )
1117 .unwrap();
1118 let src_ipv4 = None;
1119 let src_port: Option<u16> = None;
1120 let timeout = Some(Duration::new(1, 0));
1121 let targets = Target::from_domain("scanme.nmap.org", None).unwrap();
1122
1123 let max_attempts = 4;
1124 let num_threads = Some(8);
1125 let ret = icmp_echo_ping(
1126 &targets,
1127 num_threads,
1128 src_ipv4,
1129 src_port,
1130 timeout,
1131 max_attempts,
1132 )
1133 .unwrap();
1134 println!("{}", ret.ping_reports.len());
1135 println!("{}", ret);
1136 }
1137 #[test]
1138 fn test_icmpv6_ping() {
1139 let _pr = PistolRunner::init(
1140 PistolLogger::None,
1141 Some(String::from("icmpv6_ping.pcapng")),
1142 None, )
1144 .unwrap();
1145 let src_port: Option<u16> = None;
1146 let src_addr = None;
1147 let addr1 = Ipv6Addr::from_str("fe80::20c:29ff:fe2c:9e4").unwrap();
1148 let addr2 = Ipv6Addr::from_str("fe80::20c:29ff:fe2c:9e5").unwrap();
1149 let addr3 = Ipv6Addr::from_str("fe80::20c:29ff:fe2c:9e6").unwrap();
1150 let target1 = Target::new(addr1.into(), Some(vec![80]));
1151 let target2 = Target::new(addr2.into(), Some(vec![80]));
1152 let target3 = Target::new(addr3.into(), Some(vec![80]));
1153 let max_attempts = 4;
1154 let num_threads = Some(8);
1155 let timeout = Some(Duration::new(1, 0));
1156 let ret = icmpv6_ping(
1157 &[target1, target2, target3],
1158 num_threads,
1159 src_addr,
1160 src_port,
1161 timeout,
1162 max_attempts,
1163 )
1164 .unwrap();
1165 println!("{}", ret);
1166 }
1167 #[test]
1168 #[ignore]
1169 fn test_github_issues_14() {
1170 use std::process::Command;
1171 let pid = std::process::id();
1172 let num_threads = Some(8);
1173
1174 for i in 0..10_000 {
1175 let c2 = Command::new("bash")
1176 .arg("-c")
1177 .arg(&format!("lsof -p {} | wc -l", pid))
1178 .output()
1179 .unwrap();
1180 println!(
1181 "pid: {}, lsof output: {}",
1182 &pid,
1183 String::from_utf8_lossy(&c2.stdout)
1184 );
1185 let addr1 = IpAddr::V4(Ipv4Addr::new(192, 168, 1, 2));
1186 let target = Target::new(addr1, None);
1187 let _ret = icmp_echo_ping(
1188 &[target],
1189 num_threads,
1190 None,
1191 None,
1192 Some(Duration::new(1, 0)),
1193 1,
1194 )
1195 .unwrap();
1196 println!("id: {}", i);
1198 }
1200 }
1201}