use std::net::Ipv4Addr;
#[cfg(target_os = "macos")]
use std::process::Command;
pub fn detect_default_gateway() -> Option<Ipv4Addr> {
#[cfg(target_os = "linux")]
{
detect_gateway_linux()
}
#[cfg(target_os = "macos")]
{
detect_gateway_macos()
}
#[cfg(not(any(target_os = "linux", target_os = "macos")))]
{
detect_gateway_fallback()
}
}
#[cfg(target_os = "linux")]
fn detect_gateway_linux() -> Option<Ipv4Addr> {
use std::fs;
if let Ok(content) = fs::read_to_string("/proc/net/route") {
for line in content.lines().skip(1) {
let parts: Vec<&str> = line.split_whitespace().collect();
if parts.len() >= 3 {
let dest = parts[1];
let gateway_hex = parts[2];
if dest == "00000000" && gateway_hex != "00000000" {
if let Ok(gateway_u32) = u32::from_str_radix(gateway_hex, 16) {
let gateway_bytes = gateway_u32.to_le_bytes();
return Some(Ipv4Addr::new(
gateway_bytes[0],
gateway_bytes[1],
gateway_bytes[2],
gateway_bytes[3],
));
}
}
}
}
}
tracing::debug!("Failed to detect gateway on Linux");
None
}
#[cfg(target_os = "macos")]
fn detect_gateway_macos() -> Option<Ipv4Addr> {
let output = Command::new("netstat")
.arg("-rn")
.arg("-f")
.arg("inet")
.output();
if let Ok(output) = output {
let content = String::from_utf8_lossy(&output.stdout);
for line in content.lines() {
let line = line.trim();
if line.starts_with("default") || line.starts_with("0.0.0.0") {
let parts: Vec<&str> = line.split_whitespace().collect();
if parts.len() >= 2 {
if let Ok(gateway) = parts[1].parse::<Ipv4Addr>() {
return Some(gateway);
}
}
}
}
}
tracing::debug!("Failed to detect gateway on macOS");
None
}
#[cfg(not(any(target_os = "linux", target_os = "macos")))]
fn detect_gateway_fallback() -> Option<Ipv4Addr> {
tracing::warn!("Gateway detection not implemented for this platform");
None
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_detect_gateway_returns_some_ip() {
let gateway = detect_default_gateway();
if let Some(gw) = gateway {
assert_ne!(gw, Ipv4Addr::new(0, 0, 0, 0));
println!("Detected gateway: {}", gw);
} else {
println!("Gateway detection returned None (expected in some environments)");
}
}
#[test]
fn test_detect_gateway_does_not_panic() {
let _ = detect_default_gateway();
}
}