e_libscanner/utils/
traceroute.rs

1use std::{
2    fmt,
3    net::IpAddr,
4    sync::{
5        mpsc::{self, Receiver, Sender},
6        Arc, Mutex,
7    },
8    thread,
9    time::Duration,
10};
11use e_utils::traceroute::Traceroute;
12
13/// Traceroute reuslt model
14#[derive(Clone, Debug)]
15pub struct TracertQueryResult {
16    #[doc(hidden)]
17    pub id: u8,
18    /// Round-Trip Time
19    pub rtt: Duration,
20    /// IP address of a remote node
21    pub addr: Vec<Vec<String>>,
22}
23impl fmt::Display for TracertQueryResult {
24    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25        write!(
26            f,
27            "[id[{}] rtt[{}] addr[{:?}]]",
28            self.id,
29            self.rtt.as_millis(),
30            self.addr
31        )
32    }
33}
34
35/// Traceroute model
36/// # Examples
37/// ```
38/// use e_libscanner::{traceroute::Tracert, Opts};
39/// fn main() -> Result<(), String> {
40///     let opts = Opts::new(Some(&[
41///         "e-libscanner",
42///         "--ips",
43///         "114.114.114.114",
44///         "--model",
45///         "traceroute",
46///     ]))?
47///     .init()?
48///     .downcast::<Tracert>();
49///     match opts {
50///         Ok(opt) => {
51///             let prx = opt.get_progress_receiver();
52///             let handle = std::thread::spawn(move || {
53///                 while let Ok(msg) = prx.lock().unwrap().recv() {
54///                     // TODO Something
55///                     eprintln!("recv {:?}", msg);
56///                 }
57///             });
58///             let results = opt.scan(None);
59///             handle.join().unwrap();
60///             println!("count result -> {}", results.len());
61///         }
62///         Err(e) => panic!("{:?}", e),
63///     }
64///     Ok(())
65/// }
66/// ```
67#[derive(Debug)]
68pub struct Tracert {
69    iface_ip: Option<IpAddr>,
70    target: Vec<String>,
71    sender: Arc<Mutex<Sender<TracertQueryResult>>>,
72    receiver: Arc<Mutex<Receiver<TracertQueryResult>>>,
73}
74impl Tracert {
75    /// targets; iface_ip: network interface ip;  
76    pub fn new(target: Vec<String>, iface_ip: Option<IpAddr>) -> Self {
77        let (tx, rx) = mpsc::channel();
78        Tracert {
79            iface_ip,
80            target,
81            sender: Arc::new(Mutex::new(tx)),
82            receiver: Arc::new(Mutex::new(rx)),
83        }
84    }
85    /// Get target length
86    pub fn len(&self) -> usize {
87        self.target.len()
88    }
89    /// Get receiver to get trace route of result
90    pub fn get_progress_receiver(&self) -> Arc<Mutex<Receiver<TracertQueryResult>>> {
91        self.receiver.clone()
92    }
93    /// Running scan to trace route
94    pub fn scan(&self, pstop: Option<Arc<Mutex<bool>>>) -> Vec<TracertQueryResult> {
95        let mut handles = vec![];
96        let mut results = vec![];
97        let stop = if let Some(p) = pstop {
98            p
99        } else {
100            Arc::new(Mutex::new(false))
101        };
102        for t in self.target.clone() {
103            let sender_cp = Arc::clone(&self.sender);
104            let iface_ip_cp = self.iface_ip.clone();
105            let stop_cp = Arc::clone(&stop);
106            handles.push(thread::spawn(move || {
107                let tracert = Traceroute::new(t.clone(), iface_ip_cp).unwrap();
108                let mut tracert_results = vec![];
109                let mut state = false;
110                for hop in tracert {
111                    if state {
112                        break;
113                    } else {
114                        let mut result = TracertQueryResult {
115                            id: hop.ttl,
116                            rtt: Duration::default(),
117                            addr: vec![],
118                        };
119                        for query_result in hop.query_result {
120                            if query_result.rtt.as_millis() > result.rtt.as_micros() {
121                                result.rtt = query_result.rtt;
122                            }
123                            result.addr.push(query_result.addr);
124                            if *stop_cp.lock().unwrap() {
125                                state = true;
126                                break;
127                            }
128                        }
129                        sender_cp.lock().unwrap().send(result.clone()).unwrap();
130                        tracert_results.push(result);
131                    }
132                }
133                tracert_results
134            }));
135        }
136        for handle in handles {
137            results.append(&mut handle.join().unwrap());
138        }
139        results
140    }
141}