ball knowledge

(claude handholding)
This commit is contained in:
lda
2025-10-27 06:24:17 +07:00 Unverified
parent e8db4e831d
commit 17431b1c83
8 changed files with 258 additions and 35 deletions
+10 -3
View File
@@ -69,9 +69,16 @@ pub enum NUDState {
/// everything i see
#[derive(Debug, PartialEq, Eq, Clone, Hash, Serialize, Deserialize)]
pub struct NeighborItem {
dst: IpAddr,
#[serde(rename(deserialize = "dst"))]
ip: IpAddr,
dev: String,
#[serde(deserialize_with = "des_opm", serialize_with = "ser_opm")]
lladdr: Option<MacAddr>,
#[serde(
deserialize_with = "des_opm",
serialize_with = "ser_opm",
default,
rename(deserialize = "lladdr")
)]
mac: Option<MacAddr>,
#[serde(default)]
state: Vec<NUDState>,
}
+72 -29
View File
@@ -1,9 +1,13 @@
// hallo
use std::net::IpAddr;
use std::{
collections::{HashMap, HashSet},
net::IpAddr,
};
use futures::TryStreamExt;
use macaddr::MacAddr;
use rtnetlink::packet_route::{
AddressFamily,
link::LinkAttribute,
neighbour::{NeighbourAddress, NeighbourAttribute, NeighbourState},
};
@@ -16,47 +20,42 @@ pub async fn get(
dev: Option<&str>,
nud: &[NUDState],
) -> anyhow::Result<Vec<NeighborItem>> {
let (gip, gdev, gnud) = (ip, dev, nud);
let (conn, handle, _) = rtnetlink::new_connection()?;
tokio::spawn(conn); // every time?
let mut neighbor_data = handle.neighbours().get().execute(); // can i change header with message_mut? what even is header.
let mut neighbor_data = handle.neighbours().get().execute();
let nudset: HashSet<&NUDState> = HashSet::from_iter(gnud);
let mut ball: HashMap<u32, String> = HashMap::new();
let mut result = vec![];
'big: while let Some(neighbour_message_item) = neighbor_data.try_next().await? {
// Filter by address family
if !matches!(
neighbour_message_item.header.family,
AddressFamily::Inet | AddressFamily::Inet6
) || matches!(neighbour_message_item.header.state, NeighbourState::Noarp)
{
continue 'big;
}
let state = vec![
neighbour_message_item
.header
.state
.try_into()
.unwrap_or_default(),
];
let mut dst = None;
let mut lladdr = None;
]; // ONE ITEM. why tf ts design json.
let mut ip = None;
let mut mac = None;
// a hassle and a half to get the name
let dev = handle
.link()
.get()
.match_index(neighbour_message_item.header.ifindex)
.execute()
.try_next()
.await?
.and_then(|a| {
for link_attr in a.attributes {
match link_attr {
LinkAttribute::IfName(name) => return Some(name),
_ => continue,
}
}
None
});
for neigh_attr in neighbour_message_item.attributes {
match neigh_attr {
NeighbourAttribute::Destination(neighbour_address) => match neighbour_address {
NeighbourAddress::Inet(ipv4_addr) => dst = Some(ipv4_addr.into()),
NeighbourAddress::Inet6(ipv6_addr) => dst = Some(ipv6_addr.into()),
NeighbourAddress::Inet(ipv4_addr) => ip = Some(ipv4_addr.into()),
NeighbourAddress::Inet6(ipv6_addr) => ip = Some(ipv6_addr.into()),
_ => continue 'big,
},
NeighbourAttribute::LinkLocalAddress(items) => {
lladdr = match items.len() {
mac = match items.len() {
6 => items.first_chunk::<6>().map(|&e| MacAddr::from(e)),
8 => items.first_chunk::<8>().map(|&e| MacAddr::from(e)),
_ => continue 'big,
@@ -65,13 +64,57 @@ pub async fn get(
_ => continue,
}
}
let Some((dst, dev)) = dst.zip(dev) else {
continue;
// exquisite
let dev = if let Some(cached) = ball.get(&neighbour_message_item.header.ifindex) {
Some(cached.clone())
} else {
// Query and cache
let name = handle
.link()
.get()
.match_index(neighbour_message_item.header.ifindex)
.execute()
.try_next()
.await?
.and_then(|a| {
a.attributes.into_iter().find_map(|attr| match attr {
LinkAttribute::IfName(name) => Some(name),
_ => None,
})
});
if let Some(ref n) = name {
ball.insert(neighbour_message_item.header.ifindex, n.clone());
}
name
};
let Some((ip, dev)) = ip.zip(dev) else {
continue 'big;
};
{
// low block
if let Some(fip) = gip
&& fip != ip
{
continue 'big;
}
if let Some(fdev) = gdev
&& dev != fdev
{
continue 'big;
}
if !nudset.is_empty() && !nudset.contains(&state[0]) {
continue 'big;
};
}
result.push(NeighborItem {
dst,
ip,
dev,
lladdr,
mac,
state,
});
}