fs_share_utils/ip/
unix.rs1use 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}