Detect per-interface gateway IPs by parsing the system routing table. Returns a map keyed by interface identifier (interface name on macOS/Linux, interface IP on Windows) → gateway IP. Only interfaces that have a default route entry appear in the map.
()
| 305 | /// interface IP on Windows) → gateway IP. Only interfaces that have a default |
| 306 | /// route entry appear in the map. |
| 307 | fn detect_interface_gateways() -> HashMap<String, String> { |
| 308 | let mut map = HashMap::new(); |
| 309 | |
| 310 | #[cfg(target_os = "macos")] |
| 311 | { |
| 312 | if let Ok(output) = bitfun_core::util::process_manager::create_command("netstat") |
| 313 | .args(["-rn", "-f", "inet"]) |
| 314 | .output() |
| 315 | { |
| 316 | if output.status.success() { |
| 317 | let stdout = String::from_utf8_lossy(&output.stdout); |
| 318 | // Lines look like: |
| 319 | // default 192.168.1.1 UGScg en0 |
| 320 | for line in stdout.lines() { |
| 321 | let parts: Vec<&str> = line.split_whitespace().collect(); |
| 322 | if parts.len() >= 4 && parts[0] == "default" { |
| 323 | let gateway = parts[1]; |
| 324 | let netif = parts[3]; |
| 325 | if is_ipv4(gateway) { |
| 326 | map.insert(netif.to_string(), gateway.to_string()); |
| 327 | } |
| 328 | } |
| 329 | } |
| 330 | } |
| 331 | } |
| 332 | } |
| 333 | |
| 334 | #[cfg(target_os = "linux")] |
| 335 | { |
| 336 | if let Ok(output) = bitfun_core::util::process_manager::create_command("ip") |
| 337 | .args(["route", "show", "default"]) |
| 338 | .output() |
| 339 | { |
| 340 | if output.status.success() { |
| 341 | let stdout = String::from_utf8_lossy(&output.stdout); |
| 342 | // Lines look like: |
| 343 | // default via 192.168.1.1 dev eth0 proto dhcp metric 100 |
| 344 | for line in stdout.lines() { |
| 345 | let parts: Vec<&str> = line.split_whitespace().collect(); |
| 346 | let mut via = None; |
| 347 | let mut dev = None; |
| 348 | for i in 0..parts.len() { |
| 349 | match parts[i] { |
| 350 | "via" if i + 1 < parts.len() => via = Some(parts[i + 1]), |
| 351 | "dev" if i + 1 < parts.len() => dev = Some(parts[i + 1]), |
| 352 | _ => {} |
| 353 | } |
| 354 | } |
| 355 | if let (Some(gw), Some(iface)) = (via, dev) { |
| 356 | if is_ipv4(gw) { |
| 357 | map.insert(iface.to_string(), gw.to_string()); |
| 358 | } |
| 359 | } |
| 360 | } |
| 361 | } |
| 362 | } |
| 363 | } |
| 364 |
no test coverage detected