migration is crazy
This commit is contained in:
+5
-2
@@ -1,4 +1,7 @@
|
||||
[target.armv7-unknown-linux-gnueabihf]
|
||||
linker = "arm-none-eabi-gcc"
|
||||
# [target.armv7-unknown-linux-gnueabihf]
|
||||
# linker = "arm-none-eabi-gcc"
|
||||
|
||||
# advices from gpt5rustup target add armv7-unknown-linux-musleabihf
|
||||
|
||||
[build]
|
||||
target = "armv7-unknown-linux-musleabihf"
|
||||
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"rust-analyzer.cargo.target": "armv7-unknown-linux-musleabihf"
|
||||
}
|
||||
Generated
+50
@@ -257,6 +257,12 @@ version = "0.31.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "1.3.1"
|
||||
@@ -594,6 +600,28 @@ dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strum"
|
||||
version = "0.27.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf"
|
||||
dependencies = [
|
||||
"strum_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strum_macros"
|
||||
version = "0.27.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c77a8c5abcaf0f9ce05d62342b7d298c346515365c36b673df4ebe3ced01fde8"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustversion",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.106"
|
||||
@@ -611,6 +639,26 @@ version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263"
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "2.0.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "2.0.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "1.1.9"
|
||||
@@ -740,6 +788,8 @@ dependencies = [
|
||||
"color-eyre",
|
||||
"futures",
|
||||
"macaddr",
|
||||
"strum",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
|
||||
+3
-1
@@ -9,4 +9,6 @@ axum = "0.8.4"
|
||||
color-eyre = "0.6.5"
|
||||
futures = "0.3.31"
|
||||
macaddr = "1.0.1"
|
||||
tokio = { version = "1.47.1", features = ["fs", "process"] }
|
||||
strum = { version = "0.27.2", features = ["derive", "strum_macros"] }
|
||||
thiserror = "2.0.16"
|
||||
tokio = { version = "1.47.1", features = ["fs", "process", "rt-multi-thread"] }
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
[build]
|
||||
default-target = "armv7-unknown-linux-musleabihf"
|
||||
+142
@@ -6,3 +6,145 @@
|
||||
// Ok(())
|
||||
// }
|
||||
|
||||
//! ip neigh pass
|
||||
|
||||
use std::{net::IpAddr, str::FromStr};
|
||||
|
||||
use macaddr::MacAddr;
|
||||
use strum::{Display, EnumString};
|
||||
|
||||
use crate::arpparse::error::IPNeighParseError;
|
||||
mod error;
|
||||
/// ip neigh has some cool shit.
|
||||
/// IP
|
||||
/// dev DEV | None
|
||||
/// lladdr MAC | None
|
||||
/// status { permanent | noarp | stale | reachable | none | incomplete | delay | probe | failed } (ip neigh help)
|
||||
/// so you can see its damn good
|
||||
///
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
|
||||
pub struct IpNeighLine {
|
||||
pub ip: IpAddr,
|
||||
pub dev: Option<String>,
|
||||
/// link layer address
|
||||
pub mac: Option<MacAddr>,
|
||||
/// Neighbour Unreachability Detection
|
||||
pub state: NUDState,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, EnumString, Display, Clone, Copy, Hash)]
|
||||
#[strum(serialize_all = "UPPERCASE")]
|
||||
pub enum NUDState {
|
||||
/// the neighbour entry is valid forever and can
|
||||
/// be only be removed administratively.
|
||||
Permanent,
|
||||
|
||||
/// the neighbour entry is valid. No attempts to
|
||||
/// validate this entry will be made but it can
|
||||
/// be removed when its lifetime expires.
|
||||
Noarp,
|
||||
|
||||
/// the neighbour entry is valid until the
|
||||
/// reachability timeout expires.
|
||||
Reachable,
|
||||
|
||||
/// the neighbour entry is valid but suspicious.
|
||||
/// This option to ip neigh does not change the
|
||||
/// neighbour state if it was valid and the
|
||||
/// address is not changed by this command.
|
||||
Stale,
|
||||
/// this is a pseudo state used when initially
|
||||
/// creating a neighbour entry or after trying to
|
||||
/// remove it before it becomes free to do so.
|
||||
None,
|
||||
|
||||
/// the neighbour entry has not (yet) been
|
||||
/// validated/resolved.
|
||||
Incomplete,
|
||||
/// neighbor entry validation is currently
|
||||
/// delayed.
|
||||
Delay,
|
||||
/// neighbor is being probed.
|
||||
Probe,
|
||||
/// max number of probes exceeded without
|
||||
/// success, neighbor validation has ultimately
|
||||
/// failed.
|
||||
Failed,
|
||||
}
|
||||
|
||||
impl NUDState {
|
||||
/// dumb UI label
|
||||
pub fn dumber_state(&self) -> &'static str {
|
||||
match self {
|
||||
NUDState::Permanent | NUDState::Reachable => "online",
|
||||
NUDState::Stale => "maybe online",
|
||||
NUDState::Delay | NUDState::Probe | NUDState::Incomplete => "resolving",
|
||||
NUDState::Noarp => "static",
|
||||
NUDState::None => "unknown",
|
||||
NUDState::Failed => "offline",
|
||||
}
|
||||
}
|
||||
/// dumb boolean: Some(true)=on, Some(false)=off, None=shrug
|
||||
pub fn dumber_state_this_way(&self) -> Option<bool> {
|
||||
match self {
|
||||
NUDState::Permanent | NUDState::Reachable => Some(true),
|
||||
NUDState::Failed => Some(false),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
// thanks copilot for the PEAK
|
||||
pub fn parse_ip_neigh_line(s: &str) -> Result<IpNeighLine, IPNeighParseError> {
|
||||
let mut it = s.split_whitespace();
|
||||
let ip: IpAddr = it.next().ok_or(IPNeighParseError::IpWhere)?.parse()?;
|
||||
|
||||
let mut dev: Option<String> = None;
|
||||
let mut mac: Option<MacAddr> = None;
|
||||
let mut state: Option<NUDState> = None;
|
||||
let mut last_tok: Option<&str> = None;
|
||||
|
||||
while let Some(tok) = it.next() {
|
||||
match tok {
|
||||
"dev" => dev = it.next().map(str::to_string),
|
||||
"lladdr" => {
|
||||
mac = it.next().map(|m| m.parse()).transpose()?;
|
||||
}
|
||||
"nud" => {
|
||||
// we know this aint happening
|
||||
state = it.next().map(|st| st.parse()).transpose()?;
|
||||
}
|
||||
other => last_tok = Some(other),
|
||||
}
|
||||
}
|
||||
|
||||
// If no explicit "nud", many outputs end with STATE
|
||||
if state.is_none()
|
||||
&& let Some(st) = last_tok
|
||||
{
|
||||
state = Some(st.parse()?);
|
||||
}
|
||||
|
||||
Ok(IpNeighLine {
|
||||
ip,
|
||||
dev,
|
||||
mac,
|
||||
state: state.ok_or(IPNeighParseError::StateWhere)?,
|
||||
})
|
||||
}
|
||||
|
||||
impl FromStr for IpNeighLine {
|
||||
type Err = IPNeighParseError;
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
parse_ip_neigh_line(s)
|
||||
}
|
||||
}
|
||||
/// pls dont touch ts
|
||||
impl IpNeighLine {
|
||||
pub fn set_ip(&mut self, ip: IpAddr) {
|
||||
self.ip = ip;
|
||||
}
|
||||
pub fn set_state(&mut self, ip: IpAddr) {
|
||||
self.ip = ip;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
use std::net::AddrParseError;
|
||||
|
||||
use strum::Display;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Display, Error)]
|
||||
pub enum IPNeighParseError {
|
||||
IpWhere,
|
||||
IpParseError(AddrParseError),
|
||||
DevWhere,
|
||||
MacParseError(macaddr::ParseError),
|
||||
StateWhere,
|
||||
StateParseError(strum::ParseError),
|
||||
}
|
||||
|
||||
impl From<AddrParseError> for IPNeighParseError {
|
||||
fn from(value: AddrParseError) -> Self {
|
||||
Self::IpParseError(value)
|
||||
}
|
||||
}
|
||||
impl From<macaddr::ParseError> for IPNeighParseError {
|
||||
fn from(value: macaddr::ParseError) -> Self {
|
||||
Self::MacParseError(value)
|
||||
}
|
||||
}
|
||||
impl From<strum::ParseError> for IPNeighParseError {
|
||||
fn from(value: strum::ParseError) -> Self {
|
||||
Self::StateParseError(value)
|
||||
}
|
||||
}
|
||||
+36
-28
@@ -1,10 +1,4 @@
|
||||
use std::net::SocketAddr;
|
||||
|
||||
use axum::{
|
||||
Router,
|
||||
response::Html,
|
||||
routing::get,
|
||||
};
|
||||
use axum::{Router, response::Html, routing::get};
|
||||
use tokio::net::TcpListener;
|
||||
|
||||
mod arpparse;
|
||||
@@ -23,20 +17,23 @@ async fn home() -> Html<String> {
|
||||
</body>
|
||||
</html>
|
||||
"#,
|
||||
match get_ips(MACHINE_NAME).await {
|
||||
Ok(ips) => {
|
||||
let addrs: Vec<SocketAddr> = ips.into_iter().map(|ip|(ip, 22).into()).collect();
|
||||
if ping_ip(&*addrs).await { "on" } else { "off" }
|
||||
}
|
||||
Err(_) => "off",
|
||||
}
|
||||
if ping_ip((MACHINE_NAME, 22)).await {
|
||||
"on"
|
||||
} else {
|
||||
"off"
|
||||
} // match get_ips(MACHINE_NAME).await {
|
||||
// Ok(ips) => {
|
||||
// // let addrs: Vec<SocketAddr> = ips.into_iter().map(|ip|(ip, 22).into()).collect();
|
||||
// }
|
||||
// Err(_) => "off",
|
||||
// }
|
||||
))
|
||||
}
|
||||
|
||||
async fn wake_handler() -> &'static str {
|
||||
match wake(MACHINE_NAME).await {
|
||||
Err(_) => "Wake failed",
|
||||
Ok(_) => "Packet sent!",
|
||||
Ok(x) if x > 0 => "Packet sent!",
|
||||
_ => "Wake failed",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,34 +45,36 @@ async fn status() -> Html<String> {
|
||||
.map(|ip| format!("<tr><td>{ip}</td></tr>"))
|
||||
.collect();
|
||||
format!(
|
||||
"<p>the ips of {m} are:</p>
|
||||
r#"<p>the ips of {m} are:</p>
|
||||
<table>
|
||||
<tr><th>IP</th></tr>
|
||||
{string}
|
||||
</table>",
|
||||
m = MACHINE_NAME )
|
||||
</table>"#,
|
||||
m = MACHINE_NAME
|
||||
)
|
||||
}
|
||||
Err(e) => format!("<p>error getting ips: {e}</p>"),
|
||||
};
|
||||
let formatted_macs = match get_macs(MACHINE_NAME).await {
|
||||
let formatted_macs = match get_macs_2_1(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()
|
||||
};
|
||||
let mac_str = // if let Some(mac) = mac {
|
||||
mac.to_string()
|
||||
// } else {
|
||||
// "None".into()
|
||||
// }
|
||||
;
|
||||
format!("<tr><td>{ip}</td><td>{mac_str}</td></tr>")
|
||||
})
|
||||
.collect();
|
||||
format!(
|
||||
"<p>the macs here:</p>
|
||||
r#"<p>the macs here:</p>
|
||||
<table>
|
||||
<tr><th>IP</th><th>MAC</th></tr>
|
||||
{the}
|
||||
</table>"
|
||||
</table>"#
|
||||
)
|
||||
}
|
||||
Err(e) => format!("<p>cant get macs either: {e}</p>"),
|
||||
@@ -92,7 +91,8 @@ async fn status() -> Html<String> {
|
||||
"#,
|
||||
))
|
||||
}
|
||||
#[tokio::main(flavor = "current_thread")]
|
||||
#[cfg(target_os = "linux")]
|
||||
#[tokio::main]
|
||||
async fn main() -> color_eyre::Result<()> {
|
||||
color_eyre::install()?;
|
||||
let app = Router::new()
|
||||
@@ -104,3 +104,11 @@ async fn main() -> color_eyre::Result<()> {
|
||||
axum::serve(port, app.into_make_service()).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
fn main() {
|
||||
use std::process::exit;
|
||||
|
||||
eprintln!("OS not supported! run this on your ahh router!");
|
||||
exit(1)
|
||||
}
|
||||
|
||||
+103
-31
@@ -1,24 +1,52 @@
|
||||
pub const LDA_MACS: [[u8; 6]; 2] = [
|
||||
// ether
|
||||
[0x04, 0x7c, 0x16, 0x79, 0x6d, 0xee],
|
||||
// wifi
|
||||
[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<()> {
|
||||
/// is it time to lookup host lda.lan for this...
|
||||
pub static LDA_MACS_2: LazyLock<[MacAddr; 2]> = LazyLock::new(|| LDA_MACS.map(MacAddr::from));
|
||||
pub async fn wake(machine_name: &str) -> io::Result<u32> {
|
||||
let suh = UdpSocket::bind("0.0.0.0:0").await?;
|
||||
suh.set_broadcast(true)?;
|
||||
for (_, mac) in get_macs(machine_name).await? {
|
||||
let Some(mac) = mac else {
|
||||
continue;
|
||||
};
|
||||
let pac: Vec<u8> = iter::once([0xff; 6])
|
||||
.chain(iter::repeat_n(mac, 16))
|
||||
let mut macs = get_macs_2_1(machine_name).await.unwrap_or_default();
|
||||
macs.extend(LDA_MACS_2.map(|m| ([192, 168, 100, 255].into(), m)));
|
||||
let len = macs.len() as u32;
|
||||
// count - count fail
|
||||
let mut count_fail = 0;
|
||||
for (ip, mac) in macs.into_iter() {
|
||||
// let Some(mac) = mac else {
|
||||
// continue;
|
||||
// };
|
||||
let mb = mac.as_bytes();
|
||||
let start = [0xff; 6];
|
||||
let pac: Vec<u8> = iter::once(start.as_slice())
|
||||
.chain(iter::repeat_n(mb, 16))
|
||||
// what happens here?
|
||||
.flatten()
|
||||
.copied()
|
||||
.collect();
|
||||
suh.send_to(&pac, "192.168.100.255:9").await?;
|
||||
suh.send_to(&pac, (ip, 9))
|
||||
.await
|
||||
.inspect_err(|e| {
|
||||
eprintln!("ping error: {e}");
|
||||
count_fail += 1;
|
||||
})
|
||||
.ok()
|
||||
.inspect(|f| {
|
||||
if *f < (6 + 16 * 6) {
|
||||
// rare ass code path
|
||||
eprintln!("not complete transmission");
|
||||
count_fail += 1;
|
||||
}
|
||||
Ok(())
|
||||
}); // 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.
|
||||
}
|
||||
use std::{collections::HashSet, iter, net::IpAddr, time::Duration};
|
||||
Ok(len - count_fail)
|
||||
}
|
||||
use std::{collections::HashSet, iter, net::IpAddr, str::FromStr, sync::LazyLock, time::Duration};
|
||||
|
||||
use macaddr::MacAddr;
|
||||
use tokio::{
|
||||
@@ -27,22 +55,28 @@ use tokio::{
|
||||
time::timeout,
|
||||
};
|
||||
|
||||
/// generic so you can do "123.45.67.89:22" as an input
|
||||
use crate::arpparse::{self, IpNeighLine};
|
||||
|
||||
/// generic so you can do "123.45.67.89:22" or "lda.lan:22" as an input
|
||||
// this is so bad
|
||||
pub async fn ping_ip<T: ToSocketAddrs>(addr: T) -> bool {
|
||||
// thanks cahtgpt
|
||||
timeout(Duration::from_secs(1), TcpStream::connect(addr))
|
||||
.await
|
||||
.is_ok()
|
||||
}
|
||||
pub async fn _ping_ip_2<T: ToSocketAddrs>(_addr: T) -> bool {
|
||||
todo!("use icmp")
|
||||
}
|
||||
|
||||
/// this is because i like [`IpAddr`] more than [`SocketAddr`](std::net::SocketAddr)
|
||||
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_macs(machine_name: &str) -> io::Result<Vec<(IpAddr, Option<[u8; 6]>)>> {
|
||||
// not used lets go
|
||||
pub async fn get_macs(machine_name: &str) -> io::Result<Vec<(IpAddr, MacAddr)>> {
|
||||
let ips = get_ips(machine_name).await?;
|
||||
let futures = ips
|
||||
.iter()
|
||||
@@ -50,40 +84,78 @@ pub async fn get_macs(machine_name: &str) -> io::Result<Vec<(IpAddr, Option<[u8;
|
||||
.map(|ip| {
|
||||
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 o = exec_command("ip", ["neigh", "show", "to", &ip.to_string()])
|
||||
.await
|
||||
.ok()?;
|
||||
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)
|
||||
})
|
||||
parts
|
||||
.next()
|
||||
})?;
|
||||
Some((ip, mac))
|
||||
.and_then(|mac| MacAddr::from_str(mac).ok()) // 100% correct because its ip neigh brother they know how to code.
|
||||
.map(|mac| (ip, mac))
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
}
|
||||
});
|
||||
let results = futures::future::join_all(futures).await;
|
||||
Ok(results.into_iter().flatten().collect())
|
||||
Ok(results.into_iter().flatten().flatten().collect())
|
||||
}
|
||||
|
||||
pub async fn get_macs_2(machine_name: &str) -> io::Result<HashSet<MacAddr>> {
|
||||
Ok(get_macs(machine_name)
|
||||
.await?
|
||||
pub async fn get_macs_1(machine_name: &str) -> io::Result<Vec<arpparse::IpNeighLine>> {
|
||||
let ips = get_ips(machine_name).await?;
|
||||
let futures = ips.iter().map(|ip| {
|
||||
let ip = ip.to_canonical();
|
||||
async move {
|
||||
let o = exec_command("ip", ["neigh", "show", "to", &ip.to_string()]).await?;
|
||||
if !o.status.success() {
|
||||
return Err(io::Error::other(format!(
|
||||
"`ip neigh` failed for {ip} (status: {st}): {err}",
|
||||
st = o.status,
|
||||
err = String::from_utf8_lossy(&o.stderr),
|
||||
)));
|
||||
};
|
||||
Ok(String::from_utf8_lossy(&o.stdout)
|
||||
.lines()
|
||||
.map(arpparse::parse_ip_neigh_line)
|
||||
.collect::<Vec<_>>())
|
||||
}
|
||||
});
|
||||
let res = futures::future::try_join_all(futures).await?; // async move block errs.
|
||||
Ok(res
|
||||
.into_iter()
|
||||
.filter_map(|(_, m)| m.map(MacAddr::from))
|
||||
.flatten() /* resolve double vec */
|
||||
.flatten() /* drop parse errors */
|
||||
.collect())
|
||||
}
|
||||
|
||||
async fn exec_command<S: AsRef<std::ffi::OsStr>>(
|
||||
cmd: S,
|
||||
args: impl IntoIterator<Item = S>,
|
||||
) -> io::Result<std::process::Output> {
|
||||
let mut u = tokio::process::Command::new(cmd);
|
||||
u.args(args);
|
||||
u.output().await
|
||||
}
|
||||
|
||||
pub async fn get_macs_2(machine_name: &str) -> io::Result<HashSet<(IpAddr, MacAddr)>> {
|
||||
Ok(get_macs(machine_name).await?.into_iter().collect())
|
||||
}
|
||||
|
||||
pub async fn get_macs_2_1(machine_name: &str) -> io::Result<HashSet<(IpAddr, MacAddr)>> {
|
||||
Ok(get_macs_1(machine_name).await?.into_iter().filter_map(|IpNeighLine { ip, dev: _, mac, state: _ }| mac.map(|mac| (ip, mac))).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(':')) {
|
||||
let c: Vec<_> = macstr.split(':').collect();
|
||||
(c.len() == 6).then(|| {
|
||||
for (n, h) in this.iter_mut().zip(c) {
|
||||
*n = u8::from_str_radix(h, 16).ok()?;
|
||||
}
|
||||
Some(this)
|
||||
|
||||
Reference in New Issue
Block a user