async_traceroute/traceroute/
probe.rs1use std::fmt::Display;
2use std::io;
3use std::net::Ipv4Addr;
4use std::time::{Duration, Instant};
5
6pub use parser::ProbeResponseParser;
7
8pub mod parser;
9pub mod task;
10pub mod generator;
11pub mod sniffer;
12
13pub type ProbeId = String;
14
15#[derive(Clone, Debug)]
16pub struct ProbeResponse {
17 id: ProbeId,
18 from_address: Ipv4Addr,
19}
20
21impl ProbeResponse {
22 pub fn probe_id(&self) -> ProbeId {
23 self.id.clone()
24 }
25
26 pub fn from_address(&self) -> Ipv4Addr {
27 self.from_address
28 }
29}
30
31#[derive(Clone, Debug)]
32pub struct ProbeResult {
33 id: ProbeId,
34 ttl: u8,
35 from_address: Ipv4Addr,
36 rtt: Duration,
37 hostname: Option<String>,
38}
39
40impl ProbeResult {
41 pub fn probe_id(&self) -> ProbeId {
42 self.id.clone()
43 }
44
45 pub fn from_address(&self) -> Ipv4Addr {
46 self.from_address
47 }
48
49 pub fn rtt(&self) -> Duration {
50 self.rtt
51 }
52
53 pub fn ttl(&self) -> u8 {
54 self.ttl
55 }
56
57 pub fn set_hostname(&mut self, hostname: &str) {
58 self.hostname = Some(hostname.to_string());
59 }
60 pub fn get_hostname(&self) -> Option<String> {
61 self.hostname.clone()
62 }
63}
64
65impl Display for ProbeResult {
66 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
67 let mut string = String::with_capacity(300);
68 let from_address = self.from_address;
69 string.push_str(&self.hostname.as_ref().unwrap_or(&from_address.to_string()));
70 string.push(' ');
71 string.push_str(&format!("({from_address})"));
72 string.push_str(" ");
73
74 let mut rtt_micros = self.rtt.as_micros().to_string();
75 rtt_micros.insert(2, '.');
76 string.push_str(&format!("{:2} ms", rtt_micros));
77 write!(f, "{}", string)
78 }
79}
80
81#[derive(Debug)]
82pub enum ProbeError {
83 Timeout { ttl: u8 },
84 IoError { ttl: u8, io_error: Option<io::Error> },
85}
86
87impl ProbeError {
88 pub fn get_ttl(&self) -> u8 {
89 match self {
90 ProbeError::Timeout { ttl } => *ttl,
91 ProbeError::IoError { ttl, .. } => *ttl
92 }
93 }
94}
95
96struct CompletableProbe {
97 id: ProbeId,
98 ttl: u8,
99 sent_at: Instant,
100 probe_result: Option<ProbeResult>,
101}
102
103impl CompletableProbe {
104 pub fn new(id: &str, ttl: u8) -> Self {
105 Self {
106 id: id.to_string(),
107 ttl,
108 sent_at: Instant::now(),
109 probe_result: None,
110 }
111 }
112
113 pub fn complete(&mut self, probe_response: ProbeResponse) -> Option<ProbeResult> {
114 if probe_response.id != self.id {
115 return None;
116 }
117
118 if let Some(probe_result) = &self.probe_result {
119 return Some(probe_result.clone());
120 }
121
122 Some(ProbeResult {
123 id: probe_response.id,
124 ttl: self.ttl,
125 from_address: probe_response.from_address,
126 rtt: self.sent_at.elapsed(),
127 hostname: None,
128 })
129 }
130}
131
132#[derive(Debug, clap::ValueEnum, Clone, Default)]
133pub enum ProbeMethod {
134 #[default]
135 UDP,
136 TCP,
137 ICMP,
138}