default_net/interface/
unix.rs

1use super::Interface;
2use super::MacAddr;
3use crate::gateway;
4use crate::interface::InterfaceType;
5use crate::ip::{Ipv4Net, Ipv6Net};
6use crate::sys;
7use libc;
8use std::ffi::{CStr, CString};
9use std::mem::{self, MaybeUninit};
10use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
11use std::os::raw::c_char;
12use std::str::from_utf8_unchecked;
13
14#[cfg(any(target_os = "openbsd", target_os = "freebsd", target_os = "netbsd"))]
15pub fn interfaces() -> Vec<Interface> {
16    let mut interfaces: Vec<Interface> = unix_interfaces();
17    let local_ip: IpAddr = match super::get_local_ipaddr() {
18        Some(local_ip) => local_ip,
19        None => return interfaces,
20    };
21    for iface in &mut interfaces {
22        match local_ip {
23            IpAddr::V4(local_ipv4) => {
24                if iface.ipv4.iter().any(|x| x.addr == local_ipv4) {
25                    match gateway::unix::get_default_gateway(iface.name.clone()) {
26                        Ok(gateway) => {
27                            iface.gateway = Some(gateway);
28                        }
29                        Err(_) => {}
30                    }
31                }
32            }
33            IpAddr::V6(local_ipv6) => {
34                if iface.ipv6.iter().any(|x| x.addr == local_ipv6) {
35                    match gateway::unix::get_default_gateway(iface.name.clone()) {
36                        Ok(gateway) => {
37                            iface.gateway = Some(gateway);
38                        }
39                        Err(_) => {}
40                    }
41                }
42            }
43        }
44    }
45    interfaces
46}
47
48#[cfg(any(target_os = "macos", target_os = "ios"))]
49pub fn interfaces() -> Vec<Interface> {
50    use super::macos;
51
52    let type_map = macos::get_if_type_map();
53    let mut interfaces: Vec<Interface> = unix_interfaces();
54    let local_ip: IpAddr = match super::get_local_ipaddr() {
55        Some(local_ip) => local_ip,
56        None => return interfaces,
57    };
58    for iface in &mut interfaces {
59        iface.if_type = *type_map.get(&iface.name).unwrap_or(&InterfaceType::Unknown);
60        match local_ip {
61            IpAddr::V4(local_ipv4) => {
62                if iface.ipv4.iter().any(|x| x.addr == local_ipv4) {
63                    match gateway::macos::get_default_gateway(iface.name.clone()) {
64                        Ok(gateway) => {
65                            iface.gateway = Some(gateway);
66                        }
67                        Err(_) => {}
68                    }
69                }
70            }
71            IpAddr::V6(local_ipv6) => {
72                if iface.ipv6.iter().any(|x| x.addr == local_ipv6) {
73                    match gateway::macos::get_default_gateway(iface.name.clone()) {
74                        Ok(gateway) => {
75                            iface.gateway = Some(gateway);
76                        }
77                        Err(_) => {}
78                    }
79                }
80            }
81        }
82    }
83    interfaces
84}
85
86#[cfg(any(target_os = "linux", target_os = "android"))]
87pub fn interfaces() -> Vec<Interface> {
88    use super::linux;
89
90    let mut interfaces: Vec<Interface> = unix_interfaces();
91    let local_ip: IpAddr = match super::get_local_ipaddr() {
92        Some(local_ip) => local_ip,
93        None => return interfaces,
94    };
95    for iface in &mut interfaces {
96        iface.if_type = linux::get_interface_type(iface.name.clone());
97        let if_speed: Option<u64> = linux::get_interface_speed(iface.name.clone());
98        iface.transmit_speed = if_speed;
99        iface.receive_speed = if_speed;
100        match local_ip {
101            IpAddr::V4(local_ipv4) => {
102                if iface.ipv4.iter().any(|x| x.addr == local_ipv4) {
103                    match gateway::linux::get_default_gateway(iface.name.clone()) {
104                        Ok(gateway) => {
105                            iface.gateway = Some(gateway);
106                        }
107                        Err(_) => {}
108                    }
109                }
110            }
111            IpAddr::V6(local_ipv6) => {
112                if iface.ipv6.iter().any(|x| x.addr == local_ipv6) {
113                    match gateway::linux::get_default_gateway(iface.name.clone()) {
114                        Ok(gateway) => {
115                            iface.gateway = Some(gateway);
116                        }
117                        Err(_) => {}
118                    }
119                }
120            }
121        }
122    }
123    interfaces
124}
125
126#[cfg(any(target_os = "linux", target_os = "android"))]
127pub(super) fn sockaddr_to_network_addr(
128    sa: *mut libc::sockaddr,
129) -> (Option<MacAddr>, Option<IpAddr>) {
130    use std::net::SocketAddr;
131
132    unsafe {
133        if sa.is_null() {
134            (None, None)
135        } else if (*sa).sa_family as libc::c_int == libc::AF_PACKET {
136            let sll: *const libc::sockaddr_ll = mem::transmute(sa);
137            let mac = MacAddr(
138                (*sll).sll_addr[0],
139                (*sll).sll_addr[1],
140                (*sll).sll_addr[2],
141                (*sll).sll_addr[3],
142                (*sll).sll_addr[4],
143                (*sll).sll_addr[5],
144            );
145
146            (Some(mac), None)
147        } else {
148            let addr =
149                sys::sockaddr_to_addr(mem::transmute(sa), mem::size_of::<libc::sockaddr_storage>());
150
151            match addr {
152                Ok(SocketAddr::V4(sa)) => (None, Some(IpAddr::V4(*sa.ip()))),
153                Ok(SocketAddr::V6(sa)) => (None, Some(IpAddr::V6(*sa.ip()))),
154                Err(_) => (None, None),
155            }
156        }
157    }
158}
159
160#[cfg(any(
161    target_os = "openbsd",
162    target_os = "freebsd",
163    target_os = "netbsd",
164    target_os = "macos",
165    target_os = "ios"
166))]
167fn sockaddr_to_network_addr(sa: *mut libc::sockaddr) -> (Option<MacAddr>, Option<IpAddr>) {
168    use std::net::SocketAddr;
169
170    unsafe {
171        if sa.is_null() {
172            (None, None)
173        } else if (*sa).sa_family as libc::c_int == libc::AF_LINK {
174            let nlen: i8 = (*sa).sa_data[3];
175            let alen: i8 = (*sa).sa_data[4];
176            if alen > 0 && alen as u8 + nlen as u8 + 8 <= (*sa).sa_len {
177                let ptr = (*sa).sa_data.as_mut_ptr();
178                let extended =
179                    std::slice::from_raw_parts_mut(ptr, 6 + nlen as usize + alen as usize);
180
181                let mac = MacAddr(
182                    extended[6 + nlen as usize] as u8,
183                    extended[6 + nlen as usize + 1] as u8,
184                    extended[6 + nlen as usize + 2] as u8,
185                    extended[6 + nlen as usize + 3] as u8,
186                    extended[6 + nlen as usize + 4] as u8,
187                    extended[6 + nlen as usize + 5] as u8,
188                );
189                return (Some(mac), None);
190            }
191            (None, None)
192        } else {
193            let addr =
194                sys::sockaddr_to_addr(mem::transmute(sa), mem::size_of::<libc::sockaddr_storage>());
195
196            match addr {
197                Ok(SocketAddr::V4(sa)) => (None, Some(IpAddr::V4(*sa.ip()))),
198                Ok(SocketAddr::V6(sa)) => (None, Some(IpAddr::V6(*sa.ip()))),
199                Err(_) => (None, None),
200            }
201        }
202    }
203}
204
205#[cfg(target_os = "android")]
206pub fn unix_interfaces() -> Vec<Interface> {
207    use super::android;
208
209    if let Some((getifaddrs, freeifaddrs)) = android::get_libc_ifaddrs() {
210        return unix_interfaces_inner(getifaddrs, freeifaddrs);
211    }
212
213    android::netlink::unix_interfaces()
214}
215
216#[cfg(not(target_os = "android"))]
217pub fn unix_interfaces() -> Vec<Interface> {
218    unix_interfaces_inner(libc::getifaddrs, libc::freeifaddrs)
219}
220
221fn unix_interfaces_inner(
222    getifaddrs: unsafe extern "C" fn(*mut *mut libc::ifaddrs) -> libc::c_int,
223    freeifaddrs: unsafe extern "C" fn(*mut libc::ifaddrs),
224) -> Vec<Interface> {
225    let mut ifaces: Vec<Interface> = vec![];
226    let mut addrs: MaybeUninit<*mut libc::ifaddrs> = MaybeUninit::uninit();
227    if unsafe { getifaddrs(addrs.as_mut_ptr()) } != 0 {
228        return ifaces;
229    }
230    let addrs = unsafe { addrs.assume_init() };
231    let mut addr = addrs;
232    while !addr.is_null() {
233        let addr_ref: &libc::ifaddrs = unsafe { &*addr };
234        let c_str = addr_ref.ifa_name as *const c_char;
235        let bytes = unsafe { CStr::from_ptr(c_str).to_bytes() };
236        let name = unsafe { from_utf8_unchecked(bytes).to_owned() };
237        let (mac, ip) = sockaddr_to_network_addr(addr_ref.ifa_addr as *mut libc::sockaddr);
238        let (_, netmask) = sockaddr_to_network_addr(addr_ref.ifa_netmask as *mut libc::sockaddr);
239        let mut ini_ipv4: Vec<Ipv4Net> = vec![];
240        let mut ini_ipv6: Vec<Ipv6Net> = vec![];
241        if let Some(ip) = ip {
242            match ip {
243                IpAddr::V4(ipv4) => {
244                    let netmask: Ipv4Addr = match netmask {
245                        Some(netmask) => match netmask {
246                            IpAddr::V4(netmask) => netmask,
247                            IpAddr::V6(_) => Ipv4Addr::UNSPECIFIED,
248                        },
249                        None => Ipv4Addr::UNSPECIFIED,
250                    };
251                    let ipv4_net: Ipv4Net = Ipv4Net::new_with_netmask(ipv4, netmask);
252                    ini_ipv4.push(ipv4_net);
253                }
254                IpAddr::V6(ipv6) => {
255                    let netmask: Ipv6Addr = match netmask {
256                        Some(netmask) => match netmask {
257                            IpAddr::V4(_) => Ipv6Addr::UNSPECIFIED,
258                            IpAddr::V6(netmask) => netmask,
259                        },
260                        None => Ipv6Addr::UNSPECIFIED,
261                    };
262                    let ipv6_net: Ipv6Net = Ipv6Net::new_with_netmask(ipv6, netmask);
263                    ini_ipv6.push(ipv6_net);
264                }
265            }
266        }
267        let interface: Interface = Interface {
268            index: 0,
269            name: name.clone(),
270            friendly_name: None,
271            description: None,
272            if_type: InterfaceType::Unknown,
273            mac_addr: mac.clone(),
274            ipv4: ini_ipv4,
275            ipv6: ini_ipv6,
276            flags: addr_ref.ifa_flags,
277            transmit_speed: None,
278            receive_speed: None,
279            gateway: None,
280        };
281        let mut found: bool = false;
282        for iface in &mut ifaces {
283            if name == iface.name {
284                if let Some(mac) = mac.clone() {
285                    iface.mac_addr = Some(mac);
286                }
287                if let Some(ip) = ip {
288                    match ip {
289                        IpAddr::V4(ipv4) => {
290                            let netmask: Ipv4Addr = match netmask {
291                                Some(netmask) => match netmask {
292                                    IpAddr::V4(netmask) => netmask,
293                                    IpAddr::V6(_) => Ipv4Addr::UNSPECIFIED,
294                                },
295                                None => Ipv4Addr::UNSPECIFIED,
296                            };
297                            let ipv4_net: Ipv4Net = Ipv4Net::new_with_netmask(ipv4, netmask);
298                            iface.ipv4.push(ipv4_net);
299                        }
300                        IpAddr::V6(ipv6) => {
301                            let netmask: Ipv6Addr = match netmask {
302                                Some(netmask) => match netmask {
303                                    IpAddr::V4(_) => Ipv6Addr::UNSPECIFIED,
304                                    IpAddr::V6(netmask) => netmask,
305                                },
306                                None => Ipv6Addr::UNSPECIFIED,
307                            };
308                            let ipv6_net: Ipv6Net = Ipv6Net::new_with_netmask(ipv6, netmask);
309                            iface.ipv6.push(ipv6_net);
310                        }
311                    }
312                }
313                found = true;
314            }
315        }
316        if !found {
317            ifaces.push(interface);
318        }
319        addr = addr_ref.ifa_next;
320    }
321    unsafe {
322        freeifaddrs(addrs);
323    }
324    for iface in &mut ifaces {
325        let name = CString::new(iface.name.as_bytes()).unwrap();
326        unsafe {
327            iface.index = libc::if_nametoindex(name.as_ptr());
328        }
329    }
330    ifaces
331}
332
333#[cfg(test)]
334mod tests {
335    use super::*;
336    #[test]
337    fn test_unix_interfaces() {
338        let interfaces = interfaces();
339        for interface in interfaces {
340            println!("{:#?}", interface);
341        }
342    }
343}