This commit is contained in:
lda
2025-08-22 17:27:08 +07:00 Unverified
parent a88682f1c2
commit 48fb5bbac7
6 changed files with 226 additions and 24 deletions
Generated
+75
View File
@@ -162,6 +162,21 @@ dependencies = [
"percent-encoding", "percent-encoding",
] ]
[[package]]
name = "futures"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876"
dependencies = [
"futures-channel",
"futures-core",
"futures-executor",
"futures-io",
"futures-sink",
"futures-task",
"futures-util",
]
[[package]] [[package]]
name = "futures-channel" name = "futures-channel"
version = "0.3.31" version = "0.3.31"
@@ -169,6 +184,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
dependencies = [ dependencies = [
"futures-core", "futures-core",
"futures-sink",
] ]
[[package]] [[package]]
@@ -177,6 +193,40 @@ version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
[[package]]
name = "futures-executor"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f"
dependencies = [
"futures-core",
"futures-task",
"futures-util",
]
[[package]]
name = "futures-io"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
[[package]]
name = "futures-macro"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "futures-sink"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7"
[[package]] [[package]]
name = "futures-task" name = "futures-task"
version = "0.3.31" version = "0.3.31"
@@ -189,10 +239,16 @@ version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
dependencies = [ dependencies = [
"futures-channel",
"futures-core", "futures-core",
"futures-io",
"futures-macro",
"futures-sink",
"futures-task", "futures-task",
"memchr",
"pin-project-lite", "pin-project-lite",
"pin-utils", "pin-utils",
"slab",
] ]
[[package]] [[package]]
@@ -325,6 +381,12 @@ version = "0.4.27"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
[[package]]
name = "macaddr"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baee0bbc17ce759db233beb01648088061bf678383130602a298e6998eedb2d8"
[[package]] [[package]]
name = "matchit" name = "matchit"
version = "0.8.4" version = "0.8.4"
@@ -501,6 +563,15 @@ dependencies = [
"lazy_static", "lazy_static",
] ]
[[package]]
name = "signal-hook-registry"
version = "1.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "slab" name = "slab"
version = "0.4.11" version = "0.4.11"
@@ -556,10 +627,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038"
dependencies = [ dependencies = [
"backtrace", "backtrace",
"bytes",
"io-uring", "io-uring",
"libc", "libc",
"mio", "mio",
"pin-project-lite", "pin-project-lite",
"signal-hook-registry",
"slab", "slab",
"socket2", "socket2",
"tokio-macros", "tokio-macros",
@@ -665,6 +738,8 @@ version = "0.0.0"
dependencies = [ dependencies = [
"axum", "axum",
"color-eyre", "color-eyre",
"futures",
"macaddr",
"tokio", "tokio",
] ]
+3 -1
View File
@@ -7,4 +7,6 @@ publish = ["gitea"]
[dependencies] [dependencies]
axum = "0.8.4" axum = "0.8.4"
color-eyre = "0.6.5" color-eyre = "0.6.5"
tokio = "1.47.1" futures = "0.3.31"
macaddr = "1.0.1"
tokio = { version = "1.47.1", features = ["fs", "process"] }
+1 -1
View File
@@ -11,6 +11,6 @@ cross build --release --target armv7-unknown-linux-musleabihf # my machine
``` ```
cross works with a random windows machine. cross works with a random windows machine.
it works; those toolchains they tried to install: add them forcefully by hand. it works; those toolchains they tried to install: add them forcefully by hand.
it works. uses docker. it works. uses docker.
+8
View File
@@ -0,0 +1,8 @@
// struct arp;
// async fn read_arp() -> io::Result<()> {
// let arp_file = tokio::fs::File::open("/proc/net/arp").await?;
// let arp_read = BufReader::new(arp_file);
// Ok(())
// }
+71 -8
View File
@@ -1,41 +1,104 @@
use axum::{Router, response::Html, routing::get}; use std::net::SocketAddr;
use axum::{
Router,
response::Html,
routing::get,
};
use tokio::net::TcpListener; use tokio::net::TcpListener;
mod arpparse;
mod utils; mod utils;
use utils::*; use utils::*;
const MACHINE_NAME: &str = "lda.lan";
async fn home() -> Html<String> { async fn home() -> Html<String> {
Html(format!( Html(format!(
r#" r#"
<html> <html>
<body> <body>
<p>the machine is {}!</p> <p>the machine is {}! <a href="/status">Status</a></p>
<form method="POST" action="/wake"> <form method="POST" action="/wake">
<button type="submit">Wake LDA</button> <button type="submit">Wake LDA</button>
</form> </form>
</body> </body>
</html> </html>
"#, "#,
if ping_ip("192.168.100.94:22").await { match get_ips(MACHINE_NAME).await {
"on" Ok(ips) => {
} else { let addrs: Vec<SocketAddr> = ips.into_iter().map(|ip|(ip, 22).into()).collect();
"off" if ping_ip(&*addrs).await { "on" } else { "off" }
}
Err(_) => "off",
} }
)) ))
} }
async fn wake_handler() -> &'static str { async fn wake_handler() -> &'static str {
match wake("lda.lan").await { match wake(MACHINE_NAME).await {
Err(_) => "Wake failed", Err(_) => "Wake failed",
Ok(_) => "Packet sent!", Ok(_) => "Packet sent!",
} }
} }
async fn status() -> Html<String> {
let formatted_ips = match get_ips(MACHINE_NAME).await {
Ok(ips) => {
let string: String = ips
.iter()
.map(|ip| format!("<tr><td>{ip}</td></tr>"))
.collect();
format!(
"<p>the ips of {m} are:</p>
<table>
<tr><th>IP</th></tr>
{string}
</table>",
m = MACHINE_NAME )
}
Err(e) => format!("<p>error getting ips: {e}</p>"),
};
let formatted_macs = match get_macs(MACHINE_NAME).await {
Ok(table) => {
let the: String = table
.iter()
.map(|(ip, mac)| {
let mac_str = if let Some(mac) = mac {
back_to_str(mac)
} else {
"None".into()
};
format!("<tr><td>{ip}</td><td>{mac_str}</td></tr>")
})
.collect();
format!(
"<p>the macs here:</p>
<table>
<tr><th>IP</th><th>MAC</th></tr>
{the}
</table>"
)
}
Err(e) => format!("<p>cant get macs either: {e}</p>"),
};
Html(format!(
r#"
<html>
<body>
{formatted_ips}
{formatted_macs}
</body>
</html>
"#,
))
}
#[tokio::main(flavor = "current_thread")] #[tokio::main(flavor = "current_thread")]
async fn main() -> color_eyre::Result<()> { async fn main() -> color_eyre::Result<()> {
color_eyre::install()?; color_eyre::install()?;
let app = Router::new() let app = Router::new()
.route("/", get(home)) .route("/", get(home))
.route("/wake", axum::routing::post(wake_handler)); .route("/wake", axum::routing::post(wake_handler))
.route("/status", get(status));
let port = TcpListener::bind("0.0.0.0:12012").await?; let port = TcpListener::bind("0.0.0.0:12012").await?;
axum::serve(port, app.into_make_service()).await?; axum::serve(port, app.into_make_service()).await?;
+68 -14
View File
@@ -1,13 +1,15 @@
pub const LDA_MACS: [[u8; 6]; 2] = [ pub const LDA_MACS: [[u8; 6]; 2] = [
[0x04, 0x7c, 0x16, 0x79, 0x6d, 0xee], [0x04, 0x7c, 0x16, 0x79, 0x6d, 0xee],
[0xbc, 0x09, 0x1b, 0xec, 0x65, 0xd0], [0xbc, 0x09, 0x1b, 0xec, 0x65, 0xd0],
]; ]; // is it time to lookup host lda.lan for this...
pub async fn wake(machine_name: &str) -> io::Result<()> {
pub async fn wake(_machine_name: &str) -> io::Result<()> {
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)?;
for mac in LDA_MACS { for (_, mac) in get_macs(machine_name).await? {
let Some(mac) = mac else {
continue;
};
let pac: Vec<u8> = iter::once([0xff; 6]) let pac: Vec<u8> = iter::once([0xff; 6])
.chain(iter::repeat_n(mac, 16)) .chain(iter::repeat_n(mac, 16))
.flatten() .flatten()
@@ -16,8 +18,9 @@ pub async fn wake(_machine_name: &str) -> io::Result<()> {
} }
Ok(()) Ok(())
} }
use std::{iter, time::Duration}; use std::{collections::HashSet, iter, net::IpAddr, time::Duration};
use macaddr::MacAddr;
use tokio::{ use tokio::{
io, io,
net::{TcpStream, ToSocketAddrs, UdpSocket}, net::{TcpStream, ToSocketAddrs, UdpSocket},
@@ -32,14 +35,65 @@ pub async fn ping_ip<T: ToSocketAddrs>(addr: T) -> bool {
.is_ok() .is_ok()
} }
pub async fn get_ips(machine_name: &str) -> io::Result<Vec<IpAddr>> {
Ok(tokio::net::lookup_host((machine_name, 0))
.await?
.map(|c| c.ip())
.collect())
}
// pub async fn get_ips(macs: &[&[u8;6]]) -> Vec<IpAddr> { pub async fn get_macs(machine_name: &str) -> io::Result<Vec<(IpAddr, Option<[u8; 6]>)>> {
// /* let ips = get_ips(machine_name).await?;
// root@AP-AX3000CV2-0A55:~# ip neigh show 192.168.100.94 let futures = ips
// 192.168.100.94 dev eth1.6 FAILED .iter()
// 192.168.100.94 dev br-lan lladdr 04:7c:16:79:6d:ee REACHABLE // .filter(|f| f.is_ipv4())
// 192.168.100.94 dev eth1.7 FAILED .map(|ip| {
// 192.168.100.94 dev eth1.5 FAILED let ip = ip.to_canonical();
// */ async move {
let mut u = tokio::process::Command::new("ip");
u.args(["neigh", "show", "to", &ip.to_string()]);
let o = u.output().await.ok()?;
let mac = o.status.success().then(|| {
let stdout = String::from_utf8_lossy(&o.stdout);
stdout
.lines()
.filter_map(|line| {
let mut parts = line.split_whitespace();
parts.find(|&x| x == "lladdr")?;
let macstr = parts.next()?;
to_arr(macstr)
})
.next()
})?;
Some((ip, mac))
}
});
let results = futures::future::join_all(futures).await;
Ok(results.into_iter().flatten().collect())
}
// } pub async fn get_macs_2(machine_name: &str) -> io::Result<HashSet<MacAddr>> {
Ok(get_macs(machine_name)
.await?
.into_iter()
.filter_map(|(_, m)| m.map(MacAddr::from))
.collect())
}
pub fn to_arr(macstr: &str) -> Option<[u8; 6]> {
let mut this = [0u8; 6];
(macstr.split(':').count() == 6).then(|| {
for (n, h) in this.iter_mut().zip(macstr.split(':')) {
*n = u8::from_str_radix(h, 16).ok()?;
}
Some(this)
})?
}
pub fn back_to_str(thing: &[u8; 6]) -> String {
thing
.iter()
.map(|n| format!("{n:02x}"))
.collect::<Vec<String>>()
.join(":")
}