1use std::
17{
18 ffi::{CStr, CString},
19 mem::MaybeUninit,
20 net::{IpAddr, Ipv4Addr, Ipv6Addr}
21};
22
23use nix::libc;
24
25use crate::{error::*, internal_error, internal_error_map};
26
27pub struct IfInfo
34{
35 if_inf: *mut libc::ifaddrs,
37}
38
39impl Drop for IfInfo
40{
41 fn drop(&mut self)
42 {
43 if self.if_inf.is_null() == true
44 {
45 return;
46 }
47
48 unsafe
49 {
50 libc::freeifaddrs(self.if_inf);
51 }
52 }
53}
54
55impl IfInfo
56{
57 pub unsafe
61 fn get_interfaces_info() -> CDnsResult<Self>
62 {
63 let mut addrs = MaybeUninit::<*mut libc::ifaddrs>::uninit();
64
65 let ifaddrs = unsafe { libc::getifaddrs(addrs.as_mut_ptr()) };
66
67 if ifaddrs == -1
68 {
69 internal_error!(CDnsErrorType::InternalError, "{}", std::io::Error::last_os_error());
70 }
71
72 return Ok(
73 Self { if_inf: unsafe { addrs.assume_init() } }
74 );
75 }
76
77 pub unsafe
79 fn get_ifr_ip(&self, ifr: &str, ip_addr: &IpAddr) -> CDnsResult<Option<IpAddr>>
80 {
81 if self.if_inf.is_null() == true
82 {
83 panic!("if_inf is NULL");
84 }
85
86 let c_ifr =
87 CString::new(ifr)
88 .map_err(|e|
89 internal_error_map!(CDnsErrorType::InternalError, "{}", e)
90 )?;
91
92 let mut tmp = self.if_inf;
93 while tmp.is_null() == false
94 {
95 unsafe
96 {
97 if (*tmp).ifa_name.is_null() == true
98 {
99 tmp = (*tmp).ifa_next;
100 continue;
101 }
102 }
103
104 let name = unsafe { CStr::from_ptr((*tmp).ifa_name) };
106
107 if name != c_ifr.as_c_str()
109 {
110 unsafe { tmp = (*tmp).ifa_next };
111 continue;
112 }
113
114 let addr = unsafe { (*tmp).ifa_addr };
115
116 if addr.is_null() == false
117 {
118
119 let mut host = [0_u8; libc::NI_MAXHOST as usize];
120
121 let fam = unsafe { (*addr).sa_family };
122
123 if fam as i32 == libc::AF_INET && ip_addr.is_ipv4() == true
124 {
125 let s =
126 unsafe {
127 libc::getnameinfo(
128 addr,
129 std::mem::size_of::<libc::sockaddr_in>() as u32,
130 host.as_mut_ptr() as *mut i8,
131 libc::NI_MAXHOST,
132 std::ptr::null_mut(),
133 0,
134 libc::NI_NUMERICHOST
135 )
136 };
137
138 if s != 0
139 {
140 internal_error!(CDnsErrorType::InternalError, "{}", std::io::Error::last_os_error());
141 }
142
143 let c =
144 unsafe {
145 CStr::from_ptr(host.as_ptr() as *const i8)
146 .to_str()
147 .map_err(|e| internal_error_map!(CDnsErrorType::InternalError, "{}", e))?
148 };
149
150 let ip4: Ipv4Addr = c.parse().map_err(|e| internal_error_map!(CDnsErrorType::InternalError, "{}", e))?;
151
152 return Ok(Some(IpAddr::from(ip4)));
153 }
154 else if fam as i32 == libc::AF_INET6 && ip_addr.is_ipv6() == true
155 {
156 let s =
157 unsafe
158 {
159 libc::getnameinfo(
160 addr,
161 std::mem::size_of::<libc::sockaddr_in6>() as u32,
162 host.as_mut_ptr() as *mut i8,
163 libc::NI_MAXHOST,
164 std::ptr::null_mut(),
165 0,
166 libc::NI_NUMERICHOST
167 )
168 };
169
170 if s != 0
171 {
172 internal_error!(CDnsErrorType::InternalError, "{}", std::io::Error::last_os_error());
173 }
174
175 let c =
176 unsafe
177 {
178 CStr::from_ptr(host.as_ptr() as *const i8)
179 .to_str()
180 .map_err(|e| internal_error_map!(CDnsErrorType::InternalError, "{}", e))?
181 };
182
183 let ip6: Ipv6Addr =
184 c
185 .split_once("%")
186 .map_or(c, |(ip, _)| ip)
187 .parse()
188 .map_err(|e|
189 internal_error_map!(CDnsErrorType::InternalError, "{}", e)
190 )?;
191
192 return Ok(Some(IpAddr::from(Ipv6Addr::from(ip6))));
193 }
194 }
195
196 tmp = unsafe { (*tmp).ifa_next };
198 }
199
200 return Ok(None);
201 }
202
203}