use std::net::IpAddr;
use std::time::{Duration, Instant};
#[cfg(any(
target_os = "freebsd",
target_os = "openbsd",
target_os = "netbsd",
target_os = "dragonfly"
))]
pub mod bsd;
pub mod factory;
pub mod icmp;
#[cfg(target_os = "linux")]
pub mod linux;
#[cfg(target_os = "macos")]
pub mod macos;
pub mod traits;
pub mod utils;
#[cfg(target_os = "windows")]
pub mod windows;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum IpVersion {
V4,
V6,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum ProbeProtocol {
Icmp,
Udp,
Tcp,
}
impl ProbeProtocol {
pub fn description(&self) -> &'static str {
match self {
ProbeProtocol::Icmp => "ICMP",
ProbeProtocol::Udp => "UDP",
ProbeProtocol::Tcp => "TCP",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum SocketMode {
Raw,
Dgram,
Stream,
}
impl SocketMode {
pub fn description(&self) -> &'static str {
match self {
SocketMode::Raw => "Raw",
SocketMode::Dgram => "Datagram",
SocketMode::Stream => "Stream",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ProbeMode {
pub ip_version: IpVersion,
pub protocol: ProbeProtocol,
pub socket_mode: SocketMode,
}
impl ProbeMode {
pub fn description(&self) -> String {
format!(
"{} {} {}",
match self.socket_mode {
SocketMode::Raw => "Raw",
SocketMode::Dgram => "Datagram",
SocketMode::Stream => "Stream",
},
match self.protocol {
ProbeProtocol::Icmp => match self.ip_version {
IpVersion::V4 => "ICMP",
IpVersion::V6 => "ICMPv6",
},
ProbeProtocol::Udp => "UDP",
ProbeProtocol::Tcp => "TCP",
},
match self.ip_version {
IpVersion::V4 => "IPv4",
IpVersion::V6 => "IPv6",
}
)
}
}
#[derive(Debug, Clone)]
pub struct ProbeInfo {
pub ttl: u8,
pub identifier: u16,
pub sequence: u16,
pub sent_at: Instant,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ResponseType {
TimeExceeded,
DestinationUnreachable(u8), EchoReply,
TcpSynAck,
TcpRst,
UdpPortUnreachable,
}
#[derive(Debug, Clone)]
pub struct ProbeResponse {
pub from_addr: IpAddr,
pub response_type: ResponseType,
pub probe_info: ProbeInfo,
pub rtt: Duration,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_probe_mode_description() {
let mode = ProbeMode {
ip_version: IpVersion::V4,
protocol: ProbeProtocol::Icmp,
socket_mode: SocketMode::Dgram,
};
assert_eq!(mode.description(), "Datagram ICMP IPv4");
let mode = ProbeMode {
ip_version: IpVersion::V6,
protocol: ProbeProtocol::Udp,
socket_mode: SocketMode::Raw,
};
assert_eq!(mode.description(), "Raw UDP IPv6");
}
#[test]
fn test_ip_version() {
assert_eq!(IpVersion::V4, IpVersion::V4);
assert_ne!(IpVersion::V4, IpVersion::V6);
}
#[test]
fn test_response_types() {
let resp = ResponseType::DestinationUnreachable(3);
match resp {
ResponseType::DestinationUnreachable(code) => assert_eq!(code, 3),
_ => panic!("Wrong response type"),
}
}
}