use std::{
fmt::Display,
net::{IpAddr, Ipv4Addr, Ipv6Addr},
};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Route {
pub destination: IpAddr,
pub prefix: u8,
pub gateway: IpAddr,
pub ifindex: Option<u32>,
pub metric: Option<u32>,
pub luid: Option<u64>,
}
impl Route {
pub fn new(destination: IpAddr, prefix: u8) -> Self {
Self {
destination,
prefix,
gateway: match destination {
IpAddr::V4(_) => IpAddr::V4(Ipv4Addr::UNSPECIFIED),
IpAddr::V6(_) => IpAddr::V6(Ipv6Addr::UNSPECIFIED),
},
ifindex: None,
metric: None,
luid: None,
}
}
pub fn destination(mut self, destination: IpAddr) -> Self {
self.destination = destination;
self
}
pub fn prefix(mut self, prefix: u8) -> Self {
self.prefix = prefix;
self
}
pub fn gateway(mut self, gateway: IpAddr) -> Self {
self.gateway = gateway;
self
}
pub fn ifindex(mut self, idx: u32) -> Self {
self.ifindex = Some(idx);
self
}
pub fn metric(mut self, metric: u32) -> Self {
self.metric = Some(metric);
self
}
pub fn luid(mut self, luid: u64) -> Self {
self.luid = Some(luid);
self
}
}
impl Display for Route {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}/{} gateway {} metric {:?}",
self.destination.to_string(),
self.prefix,
self.gateway.to_string(),
self.metric,
)
}
}
#[cfg(test)]
pub mod test_route {
use super::Route;
#[test]
fn testv4() {
let route = Route::new("192.168.1.0".parse().unwrap(), 32)
.destination("192.168.0.0".parse().unwrap())
.prefix(24)
.gateway("172.1.1.254".parse().unwrap())
.ifindex(1)
.luid(123456)
.metric(1);
assert_eq!(
"192.168.0.0/24 gateway 172.1.1.254 metric Some(1)",
route.to_string()
);
let route = Route::new("192.168.1.0".parse().unwrap(), 32);
assert_eq!(
"192.168.1.0/32 gateway 0.0.0.0 metric None",
route.to_string()
);
}
#[test]
fn testv6() {
let route = Route::new("fe80:9464::".parse().unwrap(), 32);
assert_eq!("fe80:9464::/32 gateway :: metric None", route.to_string());
}
}