Skip to main content

netdev/interface/
mod.rs

1pub mod flags;
2pub mod interface;
3pub mod ipv6_addr_flags;
4pub mod mtu;
5pub mod state;
6pub mod types;
7
8use crate::interface::interface::Interface;
9
10#[cfg(feature = "gateway")]
11use std::net::IpAddr;
12
13/// Returns the interface currently used for the system's default route.
14///
15/// This function is available when the `gateway` feature is enabled.
16///
17/// Returns an error when no default route can be determined or when the local IP address
18/// cannot be resolved on the current platform.
19#[cfg(feature = "gateway")]
20pub fn get_default_interface() -> Result<Interface, String> {
21    resolve_default_interface(interfaces())
22}
23
24/// Returns a list of the network interfaces.
25///
26/// Each `Interface` contains the data that could be collected at discovery time.
27pub fn get_interfaces() -> Vec<Interface> {
28    interfaces()
29}
30
31/// Pick the interface index corresponding to the system's default route.
32/// Prefers exact IP match; falls back to subnet containment.
33#[cfg(feature = "gateway")]
34pub(crate) fn pick_default_iface_index(ifaces: &[Interface], local_ip: IpAddr) -> Option<u32> {
35    let mut subnet_candidate: Option<u32> = None;
36
37    for iface in ifaces {
38        match local_ip {
39            IpAddr::V4(ipv4) => {
40                if iface.ipv4.iter().any(|x| x.addr() == ipv4) {
41                    return Some(iface.index);
42                }
43                if subnet_candidate.is_none() && iface.ipv4.iter().any(|x| x.contains(&ipv4)) {
44                    subnet_candidate = Some(iface.index);
45                }
46            }
47            IpAddr::V6(ipv6) => {
48                if iface.ipv6.iter().any(|x| x.addr() == ipv6) {
49                    return Some(iface.index);
50                }
51                if subnet_candidate.is_none() && iface.ipv6.iter().any(|x| x.contains(&ipv6)) {
52                    subnet_candidate = Some(iface.index);
53                }
54            }
55        }
56    }
57    subnet_candidate
58}
59
60#[cfg(feature = "gateway")]
61pub(crate) fn iface_has_ip(iface: &Interface, local_ip: IpAddr) -> bool {
62    match local_ip {
63        IpAddr::V4(ipv4) => iface.ipv4.iter().any(|x| x.addr() == ipv4),
64        IpAddr::V6(ipv6) => iface.ipv6.iter().any(|x| x.addr() == ipv6),
65    }
66}
67
68#[cfg(feature = "gateway")]
69pub(crate) fn resolve_default_interface(mut ifaces: Vec<Interface>) -> Result<Interface, String> {
70    use crate::net::ip::get_local_ipaddr;
71
72    if let Some(pos) = ifaces.iter().position(|iface| iface.default) {
73        return Ok(ifaces.swap_remove(pos));
74    }
75
76    let local_ip: IpAddr = match get_local_ipaddr() {
77        Some(local_ip) => local_ip,
78        None => return Err(String::from("Local IP address not found")),
79    };
80
81    let idx = pick_default_iface_index(&ifaces, local_ip)
82        .ok_or_else(|| String::from("Default interface not found"))?;
83    ifaces
84        .into_iter()
85        .find(|iface| iface.index == idx)
86        .ok_or_else(|| String::from("Default interface not found"))
87}
88
89pub(crate) fn interfaces() -> Vec<Interface> {
90    #[cfg(target_os = "linux")]
91    {
92        crate::os::linux::interface::interfaces()
93    }
94    #[cfg(target_os = "android")]
95    {
96        crate::os::android::interface::interfaces()
97    }
98    #[cfg(target_os = "windows")]
99    {
100        crate::os::windows::interface::interfaces()
101    }
102    #[cfg(target_os = "macos")]
103    {
104        crate::os::macos::interface::interfaces()
105    }
106    //#[cfg(target_os = "ios")]
107    #[cfg(all(target_vendor = "apple", not(target_os = "macos")))]
108    {
109        crate::os::ios::interface::interfaces()
110    }
111    #[cfg(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))]
112    {
113        crate::os::bsd::interface::interfaces()
114    }
115}
116
117#[cfg(test)]
118mod tests {
119    #![cfg(feature = "gateway")]
120    use crate::interface::types::InterfaceType;
121    use crate::interface::{interface::Interface, pick_default_iface_index};
122    use ipnet::{Ipv4Net, Ipv6Net};
123    use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
124
125    #[test]
126    fn exact_match_and_fallback_v4() {
127        let mut a = Interface::dummy();
128        a.index = 1;
129        a.if_type = InterfaceType::Ethernet;
130        a.ipv4 = vec![Ipv4Net::new(Ipv4Addr::new(192, 168, 1, 10), 24).unwrap()];
131
132        let mut b = Interface::dummy();
133        b.index = 2;
134        b.if_type = InterfaceType::Ethernet;
135        b.ipv4 = vec![Ipv4Net::new(Ipv4Addr::new(10, 0, 0, 2), 8).unwrap()];
136
137        // Prefers exact match
138        let local = IpAddr::V4(Ipv4Addr::new(192, 168, 1, 10));
139        assert_eq!(
140            pick_default_iface_index(&[a.clone(), b.clone()], local),
141            Some(1)
142        );
143
144        // Fallback to subnet match
145        let in_subnet = IpAddr::V4(Ipv4Addr::new(10, 0, 5, 23));
146        assert_eq!(pick_default_iface_index(&[a, b], in_subnet), Some(2));
147    }
148
149    #[test]
150    fn exact_match_and_fallback_v6() {
151        let mut a = Interface::dummy();
152        a.index = 11;
153        a.if_type = InterfaceType::Ethernet;
154        a.ipv6 = vec![Ipv6Net::new("2001:db8::10".parse::<Ipv6Addr>().unwrap(), 64).unwrap()];
155
156        let mut b = Interface::dummy();
157        b.index = 22;
158        b.if_type = InterfaceType::Ethernet;
159        b.ipv6 = vec![Ipv6Net::new("2606:4700::2".parse::<Ipv6Addr>().unwrap(), 32).unwrap()];
160
161        // Prefers exact match
162        let local = IpAddr::V6("2001:db8::10".parse().unwrap());
163        assert_eq!(
164            pick_default_iface_index(&[a.clone(), b.clone()], local),
165            Some(11)
166        );
167
168        // Fallback to subnet match
169        let in_subnet = IpAddr::V6("2606:4700::abcd".parse().unwrap());
170        assert_eq!(pick_default_iface_index(&[a, b], in_subnet), Some(22));
171    }
172
173    #[test]
174    fn no_exact_nor_subnet() {
175        let mut a = Interface::dummy();
176        a.index = 3;
177        a.ipv4 = vec![Ipv4Net::new(Ipv4Addr::new(192, 168, 0, 5), 24).unwrap()];
178        let local = IpAddr::V4(Ipv4Addr::new(172, 16, 0, 1));
179        assert_eq!(pick_default_iface_index(&[a], local), None);
180    }
181}