Skip to main content

fs_share_utils/ip/
unix.rs

1use std::ffi::CStr;
2use std::io;
3use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
4
5use libc::ifaddrs;
6
7pub struct IterIpAddr {
8    head: *mut ifaddrs,
9    curr: *mut ifaddrs,
10}
11
12unsafe impl Send for IterIpAddr {}
13
14impl Drop for IterIpAddr {
15    fn drop(&mut self) {
16        if !self.head.is_null() {
17            unsafe {
18                libc::freeifaddrs(self.head);
19            }
20        }
21    }
22}
23
24impl IterIpAddr {
25    pub fn new() -> io::Result<Self> {
26        let mut ifaddr: *mut ifaddrs = std::ptr::null_mut();
27        unsafe {
28            if libc::getifaddrs(&mut ifaddr) == -1 {
29                Err(io::Error::last_os_error())
30            } else {
31                Ok(Self {
32                    head: ifaddr,
33                    curr: ifaddr,
34                })
35            }
36        }
37    }
38    pub fn get_addr<U: AsRef<str>, T: AsRef<[U]>>(self, ifa_name: T) -> Option<IpAddr> {
39        self.filter(|(i, _)| {
40            ifa_name
41                .as_ref()
42                .iter()
43                .find(|&a| a.as_ref() == i)
44                .is_some()
45        })
46        .next()
47        .map(|(_, v)| v)
48    }
49    pub fn iter_ipv4(self) -> impl Iterator<Item = (String, Ipv4Addr)> {
50        self.filter_map(|(a, b)| match b {
51            IpAddr::V4(addr) => Some((a, addr)),
52            IpAddr::V6(_) => None,
53        })
54    }
55    pub fn iter_ipv6(self) -> impl Iterator<Item = (String, Ipv6Addr)> {
56        self.filter_map(|(a, b)| match b {
57            IpAddr::V4(_) => None,
58            IpAddr::V6(addr) => Some((a, addr)),
59        })
60    }
61}
62
63impl Iterator for IterIpAddr {
64    type Item = (String, IpAddr);
65    fn next(&mut self) -> Option<Self::Item> {
66        if self.curr.is_null() {
67            return None;
68        }
69        unsafe {
70            while !self.curr.is_null() {
71                let ifa = &*self.curr;
72                self.curr = ifa.ifa_next;
73
74                if ifa.ifa_addr.is_null() {
75                    continue;
76                }
77
78                let name = CStr::from_ptr(ifa.ifa_name).to_string_lossy().into_owned();
79                let family = (*ifa.ifa_addr).sa_family as i32;
80
81                match family {
82                    libc::AF_INET => {
83                        let sa = ifa.ifa_addr as *const libc::sockaddr_in;
84                        let ip = Ipv4Addr::from(u32::from_be((*sa).sin_addr.s_addr));
85                        return Some((name, IpAddr::V4(ip)));
86                    }
87                    libc::AF_INET6 => {
88                        let sa6 = ifa.ifa_addr as *const libc::sockaddr_in6;
89                        let ip = Ipv6Addr::from((*sa6).sin6_addr.s6_addr);
90                        return Some((name, IpAddr::V6(ip)));
91                    }
92                    _ => continue,
93                }
94            }
95        }
96        None
97    }
98}