1use cfg_if::cfg_if;
7use std::ffi;
8use std::iter::Iterator;
9use std::mem;
10use std::option::Option;
11
12use crate::{Result, Errno};
13use crate::sys::socket::SockAddr;
14use crate::net::if_::*;
15
16#[derive(Clone, Debug, Eq, Hash, PartialEq)]
18pub struct InterfaceAddress {
19 pub interface_name: String,
21 pub flags: InterfaceFlags,
23 pub address: Option<SockAddr>,
25 pub netmask: Option<SockAddr>,
27 pub broadcast: Option<SockAddr>,
29 pub destination: Option<SockAddr>,
31}
32
33cfg_if! {
34 if #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "fuchsia", target_os = "linux"))] {
35 fn get_ifu_from_sockaddr(info: &libc::ifaddrs) -> *const libc::sockaddr {
36 info.ifa_ifu
37 }
38 } else {
39 fn get_ifu_from_sockaddr(info: &libc::ifaddrs) -> *const libc::sockaddr {
40 info.ifa_dstaddr
41 }
42 }
43}
44
45impl InterfaceAddress {
46 fn from_libc_ifaddrs(info: &libc::ifaddrs) -> InterfaceAddress {
48 let ifname = unsafe { ffi::CStr::from_ptr(info.ifa_name) };
49 let address = unsafe { SockAddr::from_libc_sockaddr(info.ifa_addr) };
50 let netmask = unsafe { SockAddr::from_libc_sockaddr(info.ifa_netmask) };
51 let mut addr = InterfaceAddress {
52 interface_name: ifname.to_string_lossy().to_string(),
53 flags: InterfaceFlags::from_bits_truncate(info.ifa_flags as i32),
54 address,
55 netmask,
56 broadcast: None,
57 destination: None,
58 };
59
60 let ifu = get_ifu_from_sockaddr(info);
61 if addr.flags.contains(InterfaceFlags::IFF_POINTOPOINT) {
62 addr.destination = unsafe { SockAddr::from_libc_sockaddr(ifu) };
63 } else if addr.flags.contains(InterfaceFlags::IFF_BROADCAST) {
64 addr.broadcast = unsafe { SockAddr::from_libc_sockaddr(ifu) };
65 }
66
67 addr
68 }
69}
70
71#[derive(Debug, Eq, Hash, PartialEq)]
77pub struct InterfaceAddressIterator {
78 base: *mut libc::ifaddrs,
79 next: *mut libc::ifaddrs,
80}
81
82impl Drop for InterfaceAddressIterator {
83 fn drop(&mut self) {
84 unsafe { libc::freeifaddrs(self.base) };
85 }
86}
87
88impl Iterator for InterfaceAddressIterator {
89 type Item = InterfaceAddress;
90 fn next(&mut self) -> Option<<Self as Iterator>::Item> {
91 match unsafe { self.next.as_ref() } {
92 Some(ifaddr) => {
93 self.next = ifaddr.ifa_next;
94 Some(InterfaceAddress::from_libc_ifaddrs(ifaddr))
95 }
96 None => None,
97 }
98 }
99}
100
101pub fn getifaddrs() -> Result<InterfaceAddressIterator> {
127 let mut addrs = mem::MaybeUninit::<*mut libc::ifaddrs>::uninit();
128 unsafe {
129 Errno::result(libc::getifaddrs(addrs.as_mut_ptr())).map(|_| {
130 InterfaceAddressIterator {
131 base: addrs.assume_init(),
132 next: addrs.assume_init(),
133 }
134 })
135 }
136}
137
138#[cfg(test)]
139mod tests {
140 use super::*;
141
142 #[test]
144 fn test_getifaddrs() {
145 let _ = getifaddrs();
146 }
147}