diff --git a/src/main.rs b/src/main.rs index 7639793..3cc55b1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,12 +1,30 @@ +use std::process::exit; +use std::thread::sleep; +use std::time::Duration; use crate::log::LogLevel; +use crate::log::log; +use crate::network::network_card::is_network_card_up; mod log; +mod network; fn main() { - log::log("main", "========== PROGRAMM START ==========", LogLevel::Info); + log("main", "========== PROGRAMM START ==========", LogLevel::Info); - log::log("main", "Hello, world!", LogLevel::Error); - log::log("main", "Hello, world!", LogLevel::Warn); - log::log("main", "Hello, world!", LogLevel::Info); - log::log("main", "Hello, world!", LogLevel::Debug); + let mut count = 0; + loop { + if count >= 10 { + log("main", "Couldn't find active network card, exiting.", LogLevel::Error); + exit(1); + } + if is_network_card_up() { + break; + } + + log("main", "No active network card found, waiting 10 seconds.", LogLevel::Warn); + count = count+1; + sleep(Duration::from_secs(10)); + } + + log("main", "========== PROGRAMM END ==========", LogLevel::Info); } diff --git a/src/network/mod.rs b/src/network/mod.rs new file mode 100644 index 0000000..5decd83 --- /dev/null +++ b/src/network/mod.rs @@ -0,0 +1 @@ +pub mod network_card; \ No newline at end of file diff --git a/src/network/network_card.rs b/src/network/network_card.rs new file mode 100644 index 0000000..10b3910 --- /dev/null +++ b/src/network/network_card.rs @@ -0,0 +1,136 @@ +use crate::log; +use crate::log::LogLevel; +use std::process::Command; + +/// Prüft, ob mindestens eine verfügbare Netzwerkschnittstelle (LAN/WLAN etc.) aktiv ist +/// und nicht nur die Loopback-Schnittstelle. +/// +/// Rückgabe: +/// - true: Mindestens eine NIC ist aktiv +/// - false: Keine aktive NIC gefunden oder Fehler beim Prüfen +pub fn is_network_card_up() -> bool { + #[cfg(target_os = "linux")] + { + use std::fs; + use std::path::Path; + + // Prüfe Interfaces in /sys/class/net + let sysfs = Path::new("/sys/class/net"); + if let Ok(entries) = fs::read_dir(sysfs) { + for entry in entries.flatten() { + let ifname = match entry.file_name().into_string() { + Ok(n) => n, + Err(_) => continue, + }; + if ifname == "lo" { + continue; + } + + let iface_path = entry.path(); + + // 1) operstate == "up" + let operstate = fs::read_to_string(iface_path.join("operstate")) + .unwrap_or_default() + .trim() + .to_string(); + if operstate != "up" { + continue; + } + + // 2) carrier == "1" (hat Link) + let carrier = fs::read_to_string(iface_path.join("carrier")) + .unwrap_or_default() + .trim() + .to_string(); + if carrier != "1" { + continue; + } + + // 3) Virtuell ausschließen: + // /sys/class/net//device -> Symlink zu physischer HW; + // zeigt der Pfad unterhalb von ".../virtual/..." oder existiert er gar nicht, + // dann ist das i. d. R. ein virtuelles Interface. + let device_link = iface_path.join("device"); + let is_virtual = match fs::read_link(&device_link) { + Ok(target) => target.as_os_str().to_string_lossy().contains("/virtual/"), + Err(_) => true, // kein device-Link -> in der Regel virtuell + }; + if is_virtual { + continue; + } + + // Optional: bekannte „logische“ Typen via Verzeichnis-Erkennung ausschließen + // (Bridges, VLANs, Macvlan etc.) + if iface_path.join("bridge").exists() + || iface_path.join("bonding").exists() + || iface_path.join("team").exists() + || iface_path.join("vlan").exists() + || iface_path.join("macvlan").exists() + { + continue; + } + + // Wenn wir hier sind, haben wir eine aktive physische NIC + log::log("network_status", "Found active network interface.", LogLevel::Info); + return true; + } + } + + let output = Command::new("ip") + .args(["-o", "link", "show", "up"]) + .output(); + + if let Ok(out) = output { + if !out.status.success() { + return false; + } + let stdout = String::from_utf8_lossy(&out.stdout); + for line in stdout.lines() { + if let Some(rest) = line.splitn(2, ": ").nth(1) { + if let Some(ifname) = rest.split(':').next() { + let name = ifname.trim(); + if name != "lo" { + log::log("network_status", "Found active network interface.", LogLevel::Info); + return true; + } + } + } + } + } + false + } + + #[cfg(target_os = "windows")] + { + // Windows: PowerShell verwenden, um aktive Adapter zu finden (Status = Up). + // Wir ignorieren Loopback/Pseudo-Interfaces, indem wir Physical=true filtern. + let ps_cmd = r#" +$adapters = Get-NetAdapter -Physical | Where-Object {$_.Status -eq 'Up'} +if ($adapters -and $adapters.Count -ge 1) { 'UP' } else { 'DOWN' } +"#; + let output = Command::new("powershell") + .args(["-NoProfile", "-NonInteractive", "-Command", ps_cmd]) + .output(); + + if let Ok(out) = output { + if !out.status.success() { + return false; + } + let stdout = String::from_utf8_lossy(&out.stdout).to_ascii_uppercase(); + + return if stdout.contains("UP") { + log::log("network_status", "Found active network interface.", LogLevel::Info); + true + } else { + false + } + } + false + } + + #[cfg(not(any(target_os = "linux", target_os = "windows")))] + { + log::log("network_status", "OS not supported.", LogLevel::Error); + false + } +}