use std::{
net::IpAddr,
time::{Duration, SystemTime},
};
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum ScanResponse {
TcpSynAck,
TcpRst,
UdpResponse,
NoResponse,
IcmpUnreachable,
IcmpProhibited,
Custom(String),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Discovery {
reason: ScanResponse,
timestamp: SystemTime,
rtt: Option<Duration>,
ttl: Option<u8>,
source_ip: Option<IpAddr>,
}
impl Discovery {
pub fn new(reason: ScanResponse) -> Self {
Self {
reason,
timestamp: SystemTime::now(),
rtt: None,
ttl: None,
source_ip: None,
}
}
pub fn reason(&self) -> &ScanResponse {
&self.reason
}
pub fn timestamp(&self) -> SystemTime {
self.timestamp
}
pub fn rtt(&self) -> Option<Duration> {
self.rtt
}
pub fn ttl(&self) -> Option<u8> {
self.ttl
}
pub fn source_ip(&self) -> Option<IpAddr> {
self.source_ip
}
pub fn with_rtt(mut self, rtt: Duration) -> Self {
self.rtt = Some(rtt);
self
}
pub fn with_ttl(mut self, ttl: u8) -> Self {
self.ttl = Some(ttl);
self
}
pub fn with_source_ip(mut self, ip: IpAddr) -> Self {
self.source_ip = Some(ip);
self
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::net::Ipv4Addr;
#[test]
fn discovery_builder_pattern() {
let ip = IpAddr::V4(Ipv4Addr::new(192, 168, 1, 1));
let rtt = Duration::from_millis(45);
let discovery = Discovery::new(ScanResponse::TcpRst)
.with_ttl(64)
.with_rtt(rtt)
.with_source_ip(ip);
assert_eq!(discovery.reason(), &ScanResponse::TcpRst);
assert_eq!(discovery.ttl(), Some(64));
assert_eq!(discovery.rtt(), Some(rtt));
assert_eq!(discovery.source_ip(), Some(ip));
}
}