diff --git a/src/interface/mod.rs b/src/interface/mod.rs index 24be31f..eeeeb87 100644 --- a/src/interface/mod.rs +++ b/src/interface/mod.rs @@ -6,14 +6,16 @@ pub mod types; use crate::interface::interface::Interface; +#[cfg(feature = "gateway")] +use std::net::IpAddr; + /// Get default Network Interface #[cfg(feature = "gateway")] pub fn get_default_interface() -> Result { use crate::net::ip::get_local_ipaddr; - use std::net::IpAddr; - let interfaces: Vec = interfaces(); - for iface in &interfaces { + let ifaces: Vec = interfaces(); + for iface in &ifaces { if iface.default { return Ok(iface.clone()); } @@ -22,26 +24,46 @@ pub fn get_default_interface() -> Result { Some(local_ip) => local_ip, None => return Err(String::from("Local IP address not found")), }; - for iface in interfaces { + let idx: u32 = pick_default_iface_index(&ifaces, local_ip) + .ok_or_else(|| String::from("Default interface not found"))?; + ifaces + .into_iter() + .find(|it| it.index == idx) + .ok_or_else(|| String::from("Default interface not found")) +} + +/// Get a list of available Network Interfaces +pub fn get_interfaces() -> Vec { + interfaces() +} + +/// Pick the interface index corresponding to the system's default route. +/// Prefers exact IP match; falls back to subnet containment. +#[cfg(feature = "gateway")] +pub(crate) fn pick_default_iface_index(ifaces: &[Interface], local_ip: IpAddr) -> Option { + let mut subnet_candidate: Option = None; + + for iface in ifaces { match local_ip { - IpAddr::V4(local_ipv4) => { - if iface.ipv4.iter().any(|x| x.addr() == local_ipv4) { - return Ok(iface); + IpAddr::V4(ipv4) => { + if iface.ipv4.iter().any(|x| x.addr() == ipv4) { + return Some(iface.index); + } + if subnet_candidate.is_none() && iface.ipv4.iter().any(|x| x.contains(&ipv4)) { + subnet_candidate = Some(iface.index); } } - IpAddr::V6(local_ipv6) => { - if iface.ipv6.iter().any(|x| x.addr() == local_ipv6) { - return Ok(iface); + IpAddr::V6(ipv6) => { + if iface.ipv6.iter().any(|x| x.addr() == ipv6) { + return Some(iface.index); + } + if subnet_candidate.is_none() && iface.ipv6.iter().any(|x| x.contains(&ipv6)) { + subnet_candidate = Some(iface.index); } } } } - Err(String::from("Default Interface not found")) -} - -/// Get a list of available Network Interfaces -pub fn get_interfaces() -> Vec { - interfaces() + subnet_candidate } pub(crate) fn interfaces() -> Vec { diff --git a/src/os/android/interface.rs b/src/os/android/interface.rs index 1f90bdb..bf91abc 100644 --- a/src/os/android/interface.rs +++ b/src/os/android/interface.rs @@ -11,15 +11,11 @@ use std::net::{Ipv4Addr, Ipv6Addr}; #[cfg(feature = "gateway")] use crate::net::device::NetworkDevice; #[cfg(feature = "gateway")] -use crate::net::ip::get_local_ipaddr; -#[cfg(feature = "gateway")] use crate::os::linux::procfs; #[cfg(feature = "gateway")] use crate::os::unix::dns::get_system_dns_conf; #[cfg(feature = "gateway")] use std::collections::HashMap; -#[cfg(feature = "gateway")] -use std::net::IpAddr; fn push_ipv4(v: &mut Vec, add: (Ipv4Addr, u8)) { if v.iter() @@ -55,10 +51,6 @@ fn calc_v6_scope_id(addr: &Ipv6Addr, ifindex: u32) -> u32 { pub fn interfaces() -> Vec { let mut ifaces = Vec::new(); - - #[cfg(feature = "gateway")] - let local_ip_opt: Option = get_local_ipaddr(); - // Fill ifaces via netlink first // If netlink fails, fallback to unix_interfaces match netlink::collect_interfaces() { @@ -155,23 +147,14 @@ pub fn interfaces() -> Vec { if iface.mtu.is_none() { iface.mtu = mtu::get_mtu(&iface.name); } - - #[cfg(feature = "gateway")] - { - if let Some(local_ip) = local_ip_opt { - match local_ip { - IpAddr::V4(local_ipv4) => { - if iface.ipv4.iter().any(|x| x.addr() == local_ipv4) { - iface.default = true; - iface.dns_servers = get_system_dns_conf(); - } - } - IpAddr::V6(local_ipv6) => { - if iface.ipv6.iter().any(|x| x.addr() == local_ipv6) { - iface.default = true; - iface.dns_servers = get_system_dns_conf(); - } - } + } + #[cfg(feature = "gateway")] + { + if let Some(local_ip) = crate::net::ip::get_local_ipaddr() { + if let Some(idx) = crate::interface::pick_default_iface_index(&ifaces, local_ip) { + if let Some(iface) = ifaces.iter_mut().find(|it| it.index == idx) { + iface.default = true; + iface.dns_servers = get_system_dns_conf(); } } } diff --git a/src/os/bsd/interface.rs b/src/os/bsd/interface.rs index df4595d..b591d6d 100644 --- a/src/os/bsd/interface.rs +++ b/src/os/bsd/interface.rs @@ -1,6 +1,3 @@ -#[cfg(feature = "gateway")] -use std::net::IpAddr; - use crate::{interface::interface::Interface, os::unix::interface::unix_interfaces}; pub fn interfaces() -> Vec { @@ -12,31 +9,23 @@ pub fn interfaces() -> Vec { { use crate::os::unix::dns::get_system_dns_conf; - let mut interfaces: Vec = unix_interfaces(); - let local_ip_opt: Option = crate::net::ip::get_local_ipaddr(); + let mut ifaces: Vec = unix_interfaces(); let gateway_map = super::route::get_gateway_map(); - for iface in &mut interfaces { + for iface in &mut ifaces { if let Some(gateway) = gateway_map.get(&iface.index) { iface.gateway = Some(gateway.clone()); } - - if let Some(local_ip) = local_ip_opt { - iface.ipv4.iter().for_each(|ipv4| { - if IpAddr::V4(ipv4.addr()) == local_ip { - iface.dns_servers = get_system_dns_conf(); - iface.default = true; - } - }); - iface.ipv6.iter().for_each(|ipv6| { - if IpAddr::V6(ipv6.addr()) == local_ip { - iface.dns_servers = get_system_dns_conf(); - iface.default = true; - } - }); + } + if let Some(local_ip) = crate::net::ip::get_local_ipaddr() { + if let Some(idx) = crate::interface::pick_default_iface_index(&ifaces, local_ip) { + if let Some(iface) = ifaces.iter_mut().find(|it| it.index == idx) { + iface.default = true; + iface.dns_servers = get_system_dns_conf(); + } } } - interfaces + ifaces } } diff --git a/src/os/ios/interface.rs b/src/os/ios/interface.rs index 8fdd7a0..2b1265d 100644 --- a/src/os/ios/interface.rs +++ b/src/os/ios/interface.rs @@ -1,41 +1,29 @@ -#[cfg(feature = "gateway")] -use std::net::IpAddr; - use crate::{interface::interface::Interface, os::unix::interface::unix_interfaces}; pub fn interfaces() -> Vec { - let mut interfaces: Vec = unix_interfaces(); - - #[cfg(feature = "gateway")] - let local_ip_opt: Option = crate::net::ip::get_local_ipaddr(); - + #[cfg(not(feature = "gateway"))] + { + unix_interfaces() + } #[cfg(feature = "gateway")] - let gateway_map = crate::os::darwin::route::get_gateway_map(); + { + use crate::os::unix::dns::get_system_dns_conf; - for iface in &mut interfaces { - #[cfg(feature = "gateway")] - { - use crate::os::unix::dns::get_system_dns_conf; + let mut ifaces: Vec = unix_interfaces(); + let gateway_map = crate::os::darwin::route::get_gateway_map(); + for iface in &mut ifaces { if let Some(gateway) = gateway_map.get(&iface.index) { iface.gateway = Some(gateway.clone()); } - - if let Some(local_ip) = local_ip_opt { - iface.ipv4.iter().for_each(|ipv4| { - if IpAddr::V4(ipv4.addr()) == local_ip { - iface.dns_servers = get_system_dns_conf(); - iface.default = true; - } - }); - iface.ipv6.iter().for_each(|ipv6| { - if IpAddr::V6(ipv6.addr()) == local_ip { - iface.dns_servers = get_system_dns_conf(); - iface.default = true; - } - }); + } + if let Some(local_ip) = crate::net::ip::get_local_ipaddr() { + if let Some(idx) = crate::interface::pick_default_iface_index(&ifaces, local_ip) { + if let Some(iface) = ifaces.iter_mut().find(|it| it.index == idx) { + iface.default = true; + iface.dns_servers = get_system_dns_conf(); + } } } + ifaces } - - interfaces } diff --git a/src/os/linux/interface.rs b/src/os/linux/interface.rs index cecf193..f98f82c 100644 --- a/src/os/linux/interface.rs +++ b/src/os/linux/interface.rs @@ -9,13 +9,9 @@ use std::net::{Ipv4Addr, Ipv6Addr}; #[cfg(feature = "gateway")] use crate::net::device::NetworkDevice; #[cfg(feature = "gateway")] -use crate::net::ip::get_local_ipaddr; -#[cfg(feature = "gateway")] use crate::os::unix::dns::get_system_dns_conf; #[cfg(feature = "gateway")] use std::collections::HashMap; -#[cfg(feature = "gateway")] -use std::net::IpAddr; fn push_ipv4(v: &mut Vec, add: (Ipv4Addr, u8)) { if v.iter() @@ -51,10 +47,6 @@ fn calc_v6_scope_id(addr: &Ipv6Addr, ifindex: u32) -> u32 { pub fn interfaces() -> Vec { let mut ifaces = Vec::new(); - - #[cfg(feature = "gateway")] - let local_ip_opt: Option = get_local_ipaddr(); - // Fill ifaces via netlink first // If netlink fails, fallback to unix_interfaces match netlink::collect_interfaces() { @@ -151,23 +143,14 @@ pub fn interfaces() -> Vec { if iface.mtu.is_none() { iface.mtu = super::mtu::get_mtu(&iface.name); } - - #[cfg(feature = "gateway")] - { - if let Some(local_ip) = local_ip_opt { - match local_ip { - IpAddr::V4(local_ipv4) => { - if iface.ipv4.iter().any(|x| x.addr() == local_ipv4) { - iface.default = true; - iface.dns_servers = get_system_dns_conf(); - } - } - IpAddr::V6(local_ipv6) => { - if iface.ipv6.iter().any(|x| x.addr() == local_ipv6) { - iface.default = true; - iface.dns_servers = get_system_dns_conf(); - } - } + } + #[cfg(feature = "gateway")] + { + if let Some(local_ip) = crate::net::ip::get_local_ipaddr() { + if let Some(idx) = crate::interface::pick_default_iface_index(&ifaces, local_ip) { + if let Some(iface) = ifaces.iter_mut().find(|it| it.index == idx) { + iface.default = true; + iface.dns_servers = get_system_dns_conf(); } } } diff --git a/src/os/macos/interface.rs b/src/os/macos/interface.rs index cd6876e..f2e28bd 100644 --- a/src/os/macos/interface.rs +++ b/src/os/macos/interface.rs @@ -1,6 +1,3 @@ -#[cfg(feature = "gateway")] -use std::net::IpAddr; - use crate::{ interface::{interface::Interface, types::InterfaceType}, os::unix::interface::unix_interfaces, @@ -16,15 +13,12 @@ pub struct SCInterface { pub fn interfaces() -> Vec { let type_map = super::types::get_if_type_map(); - let mut interfaces: Vec = unix_interfaces(); - - #[cfg(feature = "gateway")] - let local_ip_opt: Option = crate::net::ip::get_local_ipaddr(); + let mut ifaces: Vec = unix_interfaces(); #[cfg(feature = "gateway")] let gateway_map = crate::os::darwin::route::get_gateway_map(); - for iface in &mut interfaces { + for iface in &mut ifaces { if let Some(sc_interface) = type_map.get(&iface.name) { iface.if_type = sc_interface.interface_type; iface.friendly_name = sc_interface.friendly_name.clone(); @@ -32,27 +26,24 @@ pub fn interfaces() -> Vec { #[cfg(feature = "gateway")] { - use crate::os::unix::dns::get_system_dns_conf; if let Some(gateway) = gateway_map.get(&iface.index) { iface.gateway = Some(gateway.clone()); } + } + } - if let Some(local_ip) = local_ip_opt { - iface.ipv4.iter().for_each(|ipv4| { - if IpAddr::V4(ipv4.addr()) == local_ip { - iface.dns_servers = get_system_dns_conf(); - iface.default = true; - } - }); - iface.ipv6.iter().for_each(|ipv6| { - if IpAddr::V6(ipv6.addr()) == local_ip { - iface.dns_servers = get_system_dns_conf(); - iface.default = true; - } - }); + #[cfg(feature = "gateway")] + { + use crate::os::unix::dns::get_system_dns_conf; + if let Some(local_ip) = crate::net::ip::get_local_ipaddr() { + if let Some(idx) = crate::interface::pick_default_iface_index(&ifaces, local_ip) { + if let Some(iface) = ifaces.iter_mut().find(|it| it.index == idx) { + iface.default = true; + iface.dns_servers = get_system_dns_conf(); + } } } } - interfaces + ifaces }