use core::{
ops::{Deref, DerefMut},
ptr::{NonNull, null_mut},
};
use windows::Win32::NetworkManagement::IpHelper;
use crate::{FamilyOrBoth, Route, windows::sockaddr_inet_to_ipaddr};
pub struct RouteTable {
tab: NonNull<IpHelper::MIB_IPFORWARD_TABLE2>,
_family: FamilyOrBoth,
}
impl RouteTable {
pub fn get(family: FamilyOrBoth) -> windows::core::Result<Self> {
let mut tab = null_mut();
unsafe { IpHelper::GetIpForwardTable2(family.into(), &mut tab) }.ok()?;
Ok(Self {
tab: NonNull::new(tab).unwrap(),
_family: family,
})
}
}
unsafe impl Send for RouteTable {}
impl Deref for RouteTable {
type Target = [IpHelper::MIB_IPFORWARD_ROW2];
fn deref(&self) -> &Self::Target {
unsafe {
let tab = self.tab.as_ref();
core::slice::from_raw_parts(tab.Table.as_ptr(), tab.NumEntries as _)
}
}
}
impl DerefMut for RouteTable {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe {
let tab = self.tab.as_mut();
core::slice::from_raw_parts_mut(tab.Table.as_mut_ptr(), tab.NumEntries as _)
}
}
}
impl Drop for RouteTable {
fn drop(&mut self) {
unsafe { IpHelper::FreeMibTable(self.tab.as_ptr() as *const _) }
}
}
impl From<&IpHelper::MIB_IPFORWARD_ROW2> for Route {
fn from(route: &IpHelper::MIB_IPFORWARD_ROW2) -> Self {
let next_hop = sockaddr_inet_to_ipaddr(&route.NextHop);
let dest_ip = sockaddr_inet_to_ipaddr(&route.DestinationPrefix.Prefix);
let dst = ipnet::IpNet::new(dest_ip, route.DestinationPrefix.PrefixLength).unwrap();
Self {
metric: route.Metric as _,
gateway: if next_hop.is_unspecified() {
smallvec::smallvec![]
} else {
smallvec::smallvec![next_hop]
},
dst,
}
}
}
impl From<IpHelper::MIB_IPFORWARD_ROW2> for Route {
fn from(route: IpHelper::MIB_IPFORWARD_ROW2) -> Self {
Self::from(&route)
}
}