Ref: Optimiert IP-Adressprüfung und verbessert MAC-Ermittlung durch zusätzliche Validierung und Mehrfachversuche
This commit is contained in:
@@ -11,9 +11,12 @@ use std::process::Command;
|
|||||||
/// # Rückgabe
|
/// # Rückgabe
|
||||||
/// - `bool`: True wenn die Adresse erreichbar ist, False wenn nicht
|
/// - `bool`: True wenn die Adresse erreichbar ist, False wenn nicht
|
||||||
pub fn is_reachable(address: &str) -> bool {
|
pub fn is_reachable(address: &str) -> bool {
|
||||||
let addr = &*if let Some(parts) = address.split('/').nth(0) {
|
let addr_string = if let Some((ip_str, mask_str)) = address.split_once('/') {
|
||||||
if let Ok(ip) = parts.parse::<Ipv4Addr>() {
|
if ip_str.parse::<Ipv4Addr>().is_ok()
|
||||||
let next_ip = Ipv4Addr::from(u32::from(ip) + 1);
|
&& mask_str.parse::<u8>().ok().filter(|m| *m <= 32).is_some()
|
||||||
|
{
|
||||||
|
let ip = ip_str.parse::<Ipv4Addr>().unwrap();
|
||||||
|
let next_ip = Ipv4Addr::from(u32::from(ip).saturating_add(1));
|
||||||
next_ip.to_string()
|
next_ip.to_string()
|
||||||
} else {
|
} else {
|
||||||
address.to_string()
|
address.to_string()
|
||||||
@@ -21,6 +24,7 @@ pub fn is_reachable(address: &str) -> bool {
|
|||||||
} else {
|
} else {
|
||||||
address.to_string()
|
address.to_string()
|
||||||
};
|
};
|
||||||
|
let addr = addr_string.as_str();
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
{
|
{
|
||||||
@@ -30,6 +34,9 @@ pub fn is_reachable(address: &str) -> bool {
|
|||||||
.output();
|
.output();
|
||||||
|
|
||||||
if let Ok(out) = output {
|
if let Ok(out) = output {
|
||||||
|
let stdout = String::from_utf8_lossy(&out.stdout);
|
||||||
|
log("network_utils", &*stdout, LogLevel::Debug);
|
||||||
|
|
||||||
out.status.success()
|
out.status.success()
|
||||||
} else {
|
} else {
|
||||||
log::log("network_utils", &*format!("Couldn't reach address {}!", addr), LogLevel::Error);
|
log::log("network_utils", &*format!("Couldn't reach address {}!", addr), LogLevel::Error);
|
||||||
@@ -224,54 +231,98 @@ pub fn get_ip_from_mac(mac: &str, network: &str) -> Option<String> {
|
|||||||
/// # Rückgabe
|
/// # Rückgabe
|
||||||
/// - Option<String>: Die MAC-Adresse des Geräts oder None wenn nicht gefunden
|
/// - Option<String>: Die MAC-Adresse des Geräts oder None wenn nicht gefunden
|
||||||
pub fn get_mac_from_ip(ip: &str) -> Option<String> {
|
pub fn get_mac_from_ip(ip: &str) -> Option<String> {
|
||||||
|
// Hilfsfunktionen zur MAC-Normalisierung
|
||||||
|
let normalize_mac = |m: &str| -> String {
|
||||||
|
m.chars()
|
||||||
|
.filter(|c| c.is_ascii_hexdigit())
|
||||||
|
.flat_map(|c| c.to_lowercase())
|
||||||
|
.collect::<String>()
|
||||||
|
};
|
||||||
|
let canonicalize_mac = |hex_no_sep: &str| -> String {
|
||||||
|
hex_no_sep
|
||||||
|
.as_bytes()
|
||||||
|
.chunks(2)
|
||||||
|
.map(std::str::from_utf8)
|
||||||
|
.filter_map(Result::ok)
|
||||||
|
.collect::<Vec<&str>>()
|
||||||
|
.join(":")
|
||||||
|
};
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
{
|
{
|
||||||
let output = Command::new("ip")
|
// 1) Ziel kurz anpingen, damit ein ARP-Eintrag entsteht
|
||||||
.args(["neigh", "show", ip])
|
let _ = Command::new("ping")
|
||||||
|
.args(["-c", "1", "-W", "1", ip])
|
||||||
.output();
|
.output();
|
||||||
|
|
||||||
match output {
|
// 2) Bis zu drei Versuche, ARP/Neigh einzulesen (kleine Wartezeit)
|
||||||
Ok(out) => {
|
for _ in 0..3 {
|
||||||
if !out.status.success() {
|
let output = Command::new("ip")
|
||||||
return None;
|
.args(["neigh", "show", ip])
|
||||||
}
|
.output();
|
||||||
let stdout = String::from_utf8_lossy(&out.stdout);
|
|
||||||
// Format: 192.168.1.1 dev eth0 lladdr 00:11:22:33:44:55 REACHABLE
|
if let Ok(out) = output {
|
||||||
for line in stdout.lines() {
|
if out.status.success() {
|
||||||
let parts: Vec<&str> = line.split_whitespace().collect();
|
let stdout = String::from_utf8_lossy(&out.stdout);
|
||||||
if parts.len() >= 4 && parts[0] == ip && parts[2] == "lladdr" {
|
// Beispiel: 192.168.1.1 dev eth0 lladdr 00:11:22:33:44:55 REACHABLE
|
||||||
return Some(parts[3].to_string());
|
for line in stdout.lines() {
|
||||||
|
let parts: Vec<&str> = line.split_whitespace().collect();
|
||||||
|
if parts.get(0).copied() == Some(ip) {
|
||||||
|
if let Some(idx) = parts.iter().position(|p| *p == "lladdr") {
|
||||||
|
if let Some(mac_tok) = parts.get(idx + 1) {
|
||||||
|
let seen_norm = normalize_mac(mac_tok);
|
||||||
|
if seen_norm.len() == 12 {
|
||||||
|
return Some(canonicalize_mac(&seen_norm));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
|
||||||
}
|
}
|
||||||
Err(_) => None
|
|
||||||
|
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
{
|
{
|
||||||
let output = Command::new("arp")
|
// 1) Ziel kurz anpingen, damit ein ARP-Eintrag entsteht
|
||||||
.args(["-a", ip])
|
let _ = Command::new("ping")
|
||||||
|
.args(["-n", "1", "-w", "500", ip])
|
||||||
.output();
|
.output();
|
||||||
|
|
||||||
match output {
|
// 2) Bis zu drei Versuche, ARP einzulesen (kleine Wartezeit)
|
||||||
Ok(out) => {
|
for _ in 0..3 {
|
||||||
if !out.status.success() {
|
// Hinweis: `arp -a` auf Windows zeigt die gesamte Tabelle; mit IP filtert es i. d. R. auf Interface,
|
||||||
return None;
|
// daher filtern wir inhaltlich auf die Zeile mit der Ziel-IP.
|
||||||
}
|
let output = Command::new("arp")
|
||||||
let stdout = String::from_utf8_lossy(&out.stdout);
|
.args(["-a"])
|
||||||
for line in stdout.lines() {
|
.output();
|
||||||
let parts: Vec<&str> = line.split_whitespace().collect();
|
|
||||||
// Format: 192.168.1.1 00-11-22-33-44-55 dynamic
|
if let Ok(out) = output {
|
||||||
if parts.len() >= 2 && parts[0] == ip {
|
if out.status.success() {
|
||||||
return Some(parts[1].replace('-', ":"));
|
let stdout = String::from_utf8_lossy(&out.stdout);
|
||||||
|
for line in stdout.lines() {
|
||||||
|
let cols: Vec<&str> = line.split_whitespace().collect();
|
||||||
|
// Typisch: "192.168.1.1 00-11-22-33-44-55 dynamic"
|
||||||
|
if cols.get(0).copied() == Some(ip) && cols.len() >= 2 {
|
||||||
|
let mac_colon = cols[1].replace('-', ":");
|
||||||
|
let seen_norm = normalize_mac(&mac_colon);
|
||||||
|
if seen_norm.len() == 12 {
|
||||||
|
return Some(canonicalize_mac(&seen_norm));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
|
||||||
}
|
}
|
||||||
Err(_) => None
|
|
||||||
|
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(any(target_os = "linux", target_os = "windows")))]
|
#[cfg(not(any(target_os = "linux", target_os = "windows")))]
|
||||||
@@ -280,6 +331,7 @@ pub fn get_mac_from_ip(ip: &str) -> Option<String> {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sendet ein Wake-on-LAN Magic Packet an eine MAC-Adresse
|
/// Sendet ein Wake-on-LAN Magic Packet an eine MAC-Adresse
|
||||||
///
|
///
|
||||||
/// # Parameter
|
/// # Parameter
|
||||||
|
|||||||
Reference in New Issue
Block a user