cut down on bloat? or scale up on bloat?
This commit is contained in:
@@ -12,3 +12,7 @@ macaddr = "1.0.1"
|
|||||||
strum = { version = "0.27.2", features = ["derive", "strum_macros"] }
|
strum = { version = "0.27.2", features = ["derive", "strum_macros"] }
|
||||||
thiserror = "2.0.16"
|
thiserror = "2.0.16"
|
||||||
tokio = { version = "1.47.1", features = ["fs", "process", "rt-multi-thread"] }
|
tokio = { version = "1.47.1", features = ["fs", "process", "rt-multi-thread"] }
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
opt-level = "z"
|
||||||
|
strip = true
|
||||||
@@ -148,3 +148,52 @@ impl IpNeighLine {
|
|||||||
self.ip = ip;
|
self.ip = ip;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ideas from copilot:
|
||||||
|
|
||||||
|
|
||||||
|
impl NUDState {
|
||||||
|
// higher is "better"/more online
|
||||||
|
pub const fn rank(self) -> u8 {
|
||||||
|
match self {
|
||||||
|
NUDState::Permanent | NUDState::Reachable => 5,
|
||||||
|
NUDState::Stale => 4,
|
||||||
|
NUDState::Delay | NUDState::Probe | NUDState::Incomplete => 3,
|
||||||
|
NUDState::Noarp => 2,
|
||||||
|
NUDState::None => 1,
|
||||||
|
NUDState::Failed => 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl PartialOrd for NUDState {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||||
|
Some(self.cmp(other))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Ord for NUDState {
|
||||||
|
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||||
|
self.rank().cmp(&other.rank())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IpNeighLine {
|
||||||
|
// score for “local and online”: state, has-mac, v4, iface preference
|
||||||
|
pub fn score(&self) -> (u8, u8, u8, u8) {
|
||||||
|
let iface = self
|
||||||
|
.dev
|
||||||
|
.as_deref()
|
||||||
|
.map(|d| {
|
||||||
|
if d.starts_with("br") || d.starts_with("lan") || d.starts_with("eth") { 2 }
|
||||||
|
else if d.starts_with("wlan") || d.starts_with("wl") { 1 }
|
||||||
|
else { 0 }
|
||||||
|
})
|
||||||
|
.unwrap_or(0);
|
||||||
|
(
|
||||||
|
self.state.rank(),
|
||||||
|
self.mac.is_some() as u8,
|
||||||
|
matches!(self.ip, IpAddr::V4(_)) as u8,
|
||||||
|
iface,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
+28
-26
@@ -30,61 +30,63 @@ async fn home() -> Html<String> {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn wake_handler() -> &'static str {
|
async fn wake_handler() -> axum::response::Result< &'static str> {
|
||||||
match wake(MACHINE_NAME).await {
|
match wake(MACHINE_NAME).await {
|
||||||
Ok(x) if x > 0 => "Packet sent!",
|
Ok(x) if x > 0 => Ok("Packet sent!"),
|
||||||
_ => "Wake failed",
|
_ => Err("Wake failed".into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn status() -> Html<String> {
|
async fn status() -> Html<String> {
|
||||||
let formatted_ips = match get_ips(MACHINE_NAME).await {
|
// let formatted_ips = match get_ips(MACHINE_NAME).await {
|
||||||
Ok(ips) => {
|
// Ok(ips) => {
|
||||||
let string: String = ips
|
// let string: String = ips
|
||||||
.iter()
|
// .iter()
|
||||||
.map(|ip| format!("<tr><td>{ip}</td></tr>"))
|
// .map(|ip| format!("<tr><td>{ip}</td></tr>"))
|
||||||
.collect();
|
// .collect();
|
||||||
format!(
|
// format!(
|
||||||
r#"<p>the ips of {m} are:</p>
|
// r#"<p>the ips of {m} are:</p>
|
||||||
<table>
|
// <table>
|
||||||
<tr><th>IP</th></tr>
|
// <tr><th>IP</th></tr>
|
||||||
{string}
|
// {string}
|
||||||
</table>"#,
|
// </table>"#,
|
||||||
m = MACHINE_NAME
|
// m = MACHINE_NAME
|
||||||
)
|
// )
|
||||||
}
|
// }
|
||||||
Err(e) => format!("<p>error getting ips: {e}</p>"),
|
// Err(e) => format!("<p>error getting ips: {e}</p>"),
|
||||||
};
|
// };
|
||||||
let formatted_macs = match get_macs_2_1(MACHINE_NAME).await {
|
let formatted_macs = match get_macs_2_1(MACHINE_NAME).await {
|
||||||
Ok(table) => {
|
Ok(table) => {
|
||||||
let the: String = table
|
let the: String = table
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(ip, mac)| {
|
.map(|(ip, mac, state)| {
|
||||||
let mac_str = // if let Some(mac) = mac {
|
let mac_str = // if let Some(mac) = mac {
|
||||||
mac.to_string()
|
mac.to_string()
|
||||||
// } else {
|
// } else {
|
||||||
// "None".into()
|
// "None".into()
|
||||||
// }
|
// }
|
||||||
;
|
;
|
||||||
format!("<tr><td>{ip}</td><td>{mac_str}</td></tr>")
|
format!(
|
||||||
|
"<tr><td>{ip}</td><td>{mac_str}</td><td>{state}</td></tr>",
|
||||||
|
state = state.dumber_state()
|
||||||
|
)
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
format!(
|
format!(
|
||||||
r#"<p>the macs here:</p>
|
r#"<p>info of {MACHINE_NAME}:</p>
|
||||||
<table>
|
<table>
|
||||||
<tr><th>IP</th><th>MAC</th></tr>
|
<tr><th>IP</th><th>MAC</th><th>State</th></tr>
|
||||||
{the}
|
{the}
|
||||||
</table>"#
|
</table>"#
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Err(e) => format!("<p>cant get macs either: {e}</p>"),
|
Err(e) => format!("<p>errors getting table for {MACHINE_NAME}: {e}</p>"),
|
||||||
};
|
};
|
||||||
|
|
||||||
Html(format!(
|
Html(format!(
|
||||||
r#"
|
r#"
|
||||||
<html>
|
<html>
|
||||||
<body>
|
<body>
|
||||||
{formatted_ips}
|
|
||||||
{formatted_macs}
|
{formatted_macs}
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
+49
-37
@@ -10,41 +10,28 @@ pub static LDA_MACS_2: LazyLock<[MacAddr; 2]> = LazyLock::new(|| LDA_MACS.map(Ma
|
|||||||
pub async fn wake(machine_name: &str) -> io::Result<u32> {
|
pub async fn wake(machine_name: &str) -> io::Result<u32> {
|
||||||
let suh = UdpSocket::bind("0.0.0.0:0").await?;
|
let suh = UdpSocket::bind("0.0.0.0:0").await?;
|
||||||
suh.set_broadcast(true)?;
|
suh.set_broadcast(true)?;
|
||||||
let mut macs = get_macs_2_1(machine_name).await.unwrap_or_default();
|
let mut macs = get_macs_2_mac(machine_name).await.unwrap_or_default();
|
||||||
macs.extend(LDA_MACS_2.map(|m| ([192, 168, 100, 255].into(), m)));
|
macs.extend(*LDA_MACS_2);
|
||||||
let len = macs.len() as u32;
|
let mut sent_ok = 0;
|
||||||
// count - count fail
|
for mac in macs {
|
||||||
let mut count_fail = 0;
|
|
||||||
for (ip, mac) in macs.into_iter() {
|
|
||||||
// let Some(mac) = mac else {
|
|
||||||
// continue;
|
|
||||||
// };
|
|
||||||
let mb = mac.as_bytes();
|
let mb = mac.as_bytes();
|
||||||
let start = [0xff; 6];
|
|
||||||
let pac: Vec<u8> = iter::once(start.as_slice())
|
let mut pac = [0; 6 + 6 * 16]; // 6x FF + 16x mac6
|
||||||
.chain(iter::repeat_n(mb, 16))
|
pac[..6].fill(0xff);
|
||||||
// what happens here?
|
for i in 1..=16 {
|
||||||
.flatten()
|
pac[i * 6..(i + 1) * 6].copy_from_slice(mb);
|
||||||
.copied()
|
}
|
||||||
.collect();
|
|
||||||
suh.send_to(&pac, (ip, 9))
|
match suh
|
||||||
|
.send_to(&pac, (IpAddr::from([192, 168, 100, 255]), 9))
|
||||||
.await
|
.await
|
||||||
.inspect_err(|e| {
|
{
|
||||||
eprintln!("ping error: {e}");
|
Ok(n) if n == pac.len() => sent_ok += 1,
|
||||||
count_fail += 1;
|
Ok(n) => eprintln!("partial send ({n}/{})", pac.len()),
|
||||||
})
|
Err(e) => eprintln!("send error: {e}"),
|
||||||
.ok()
|
}
|
||||||
.inspect(|f| {
|
|
||||||
if *f < (6 + 16 * 6) {
|
|
||||||
// rare ass code path
|
|
||||||
eprintln!("not complete transmission");
|
|
||||||
count_fail += 1;
|
|
||||||
}
|
|
||||||
}); // type shit
|
|
||||||
// suh.send_to(&pac, "192.168.100.255:9").await?; // type good
|
|
||||||
// suh.send_to(&pac, "255.255.255.255:9").await?; // type ass; this doesnt work somehow.
|
|
||||||
}
|
}
|
||||||
Ok(len - count_fail)
|
Ok(sent_ok)
|
||||||
}
|
}
|
||||||
use std::{collections::HashSet, iter, net::IpAddr, str::FromStr, sync::LazyLock, time::Duration};
|
use std::{collections::HashSet, iter, net::IpAddr, str::FromStr, sync::LazyLock, time::Duration};
|
||||||
|
|
||||||
@@ -55,7 +42,7 @@ use tokio::{
|
|||||||
time::timeout,
|
time::timeout,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::arpparse::{self, IpNeighLine};
|
use crate::arpparse::{self, IpNeighLine, NUDState};
|
||||||
|
|
||||||
/// generic so you can do "123.45.67.89:22" or "lda.lan:22" as an input
|
/// generic so you can do "123.45.67.89:22" or "lda.lan:22" as an input
|
||||||
// this is so bad
|
// this is so bad
|
||||||
@@ -84,7 +71,7 @@ pub async fn get_macs(machine_name: &str) -> io::Result<Vec<(IpAddr, MacAddr)>>
|
|||||||
.map(|ip| {
|
.map(|ip| {
|
||||||
let ip = ip.to_canonical();
|
let ip = ip.to_canonical();
|
||||||
async move {
|
async move {
|
||||||
let o = exec_command("ip", ["neigh", "show", "to", &ip.to_string()])
|
let o = exec_command("ip", ["neigh", "show", "to", &ip.to_string(), "dev", "br-lan"])
|
||||||
.await
|
.await
|
||||||
.ok()?;
|
.ok()?;
|
||||||
o.status.success().then(|| {
|
o.status.success().then(|| {
|
||||||
@@ -112,7 +99,7 @@ pub async fn get_macs_1(machine_name: &str) -> io::Result<Vec<arpparse::IpNeighL
|
|||||||
let futures = ips.iter().map(|ip| {
|
let futures = ips.iter().map(|ip| {
|
||||||
let ip = ip.to_canonical();
|
let ip = ip.to_canonical();
|
||||||
async move {
|
async move {
|
||||||
let o = exec_command("ip", ["neigh", "show", "to", &ip.to_string()]).await?;
|
let o = exec_command("ip", ["neigh", "show", "to", &ip.to_string(), "dev", "br-lan"]).await?;
|
||||||
if !o.status.success() {
|
if !o.status.success() {
|
||||||
return Err(io::Error::other(format!(
|
return Err(io::Error::other(format!(
|
||||||
"`ip neigh` failed for {ip} (status: {st}): {err}",
|
"`ip neigh` failed for {ip} (status: {st}): {err}",
|
||||||
@@ -147,8 +134,33 @@ pub async fn get_macs_2(machine_name: &str) -> io::Result<HashSet<(IpAddr, MacAd
|
|||||||
Ok(get_macs(machine_name).await?.into_iter().collect())
|
Ok(get_macs(machine_name).await?.into_iter().collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_macs_2_1(machine_name: &str) -> io::Result<HashSet<(IpAddr, MacAddr)>> {
|
pub async fn get_macs_2_1(machine_name: &str) -> io::Result<HashSet<(IpAddr, MacAddr, NUDState)>> {
|
||||||
Ok(get_macs_1(machine_name).await?.into_iter().filter_map(|IpNeighLine { ip, dev: _, mac, state: _ }| mac.map(|mac| (ip, mac))).collect())
|
Ok(get_macs_1(machine_name)
|
||||||
|
.await?
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(
|
||||||
|
|IpNeighLine {
|
||||||
|
ip,
|
||||||
|
dev: _,
|
||||||
|
mac,
|
||||||
|
state,
|
||||||
|
}| mac.map(|mac| (ip, mac, state)),
|
||||||
|
)
|
||||||
|
.collect())
|
||||||
|
}
|
||||||
|
pub async fn get_macs_2_mac(machine_name: &str) -> io::Result<HashSet<MacAddr>> {
|
||||||
|
Ok(get_macs_1(machine_name)
|
||||||
|
.await?
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(
|
||||||
|
|IpNeighLine {
|
||||||
|
ip: _,
|
||||||
|
dev: _,
|
||||||
|
mac,
|
||||||
|
state: _,
|
||||||
|
}| mac,
|
||||||
|
)
|
||||||
|
.collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_arr(macstr: &str) -> Option<[u8; 6]> {
|
pub fn to_arr(macstr: &str) -> Option<[u8; 6]> {
|
||||||
|
|||||||
Reference in New Issue
Block a user