system_info/unix/posix/
network.rs1extern crate alloc;
4
5use alloc::vec::Vec;
6use alloc::borrow::Cow;
7
8use core::{slice, iter};
9
10pub use crate::data::network::{Ip, Address};
11
12#[inline(always)]
13pub(crate) fn slice_c_str(input: &[u8; libc::IFNAMSIZ]) -> &[u8] {
14 for idx in 0..input.len() {
15 if input[idx] == 0 {
16 return &input[..idx];
17 }
18 }
19
20 &input[..]
21}
22
23pub struct Addresses<'a> {
25 cursor: iter::Copied<slice::Iter<'a, Address>>
26}
27
28impl<'a> Addresses<'a> {
29 pub fn next_addr(&mut self) -> Option<Address> {
31 self.cursor.next()
32 }
33}
34
35impl<'a> Iterator for Addresses<'a> {
36 type Item = Address;
37
38 #[inline]
39 fn next(&mut self) -> Option<Self::Item> {
40 self.next_addr()
41 }
42}
43
44pub(crate) struct InterfaceData {
45 pub(crate) name: [u8; libc::IFNAMSIZ],
46 pub(crate) addresses: Vec<Address>
47}
48
49impl InterfaceData {
50 #[inline]
51 pub(crate) fn name(&self) -> &[u8] {
52 slice_c_str(&self.name)
53 }
54
55 #[inline]
56 pub(crate) fn push(&mut self, addr: Address) {
57 self.addresses.push(addr);
58 }
59}
60
61pub struct Interface<'a> {
63 data: &'a InterfaceData
64}
65
66impl<'a> Interface<'a> {
67 #[inline]
68 pub fn name(&'a self) -> Option<Cow<'a, str>> {
70 let name = self.data.name();
71 match core::str::from_utf8(name) {
72 Ok(name) => Some(name.into()),
73 Err(_) => None,
74 }
75 }
76
77 #[inline(always)]
78 pub fn addresses(&'a self) -> Addresses<'a> {
80 Addresses {
81 cursor: self.data.addresses.iter().copied()
82 }
83 }
84}
85
86pub struct InterfacesIter<'a> {
88 cursor: slice::Iter<'a, InterfaceData>,
89}
90
91impl<'a> InterfacesIter<'a> {
92 #[inline(always)]
93 pub fn interface(&'a self) -> Option<Interface<'a>> {
95 self.cursor.as_slice().get(0).map(|data| Interface {
96 data
97 })
98 }
99
100 #[inline(always)]
101 pub fn next_interface(&'a mut self) -> Option<Interface<'a>> {
103 self.next()
104 }
105}
106
107impl<'a> Iterator for InterfacesIter<'a> {
108 type Item = Interface<'a>;
109
110 #[inline]
111 fn next(&mut self) -> Option<Self::Item> {
112 self.cursor.next().map(|data| Interface {
113 data
114 })
115 }
116}
117
118pub struct Interfaces {
120 pub(crate) inner: Vec<InterfaceData>,
121}
122
123impl Interfaces {
124 pub fn iter(&self) -> InterfacesIter<'_> {
126 InterfacesIter {
127 cursor: self.inner.iter()
128 }
129 }
130
131 #[cfg(not(any(target_os = "linux", target_os = "android")))]
132 fn store_interface(&mut self, ifa_name: *const i8) -> &mut InterfaceData {
133 use core::{cmp, ptr};
134
135 let mut name = [0u8; libc::IFNAMSIZ];
136 if !ifa_name.is_null() {
137 unsafe {
138 let len = cmp::min(name.len(), libc::strlen(ifa_name));
139 ptr::copy_nonoverlapping(ifa_name, name.as_mut_ptr() as _, len)
140 };
141 }
142
143 let real_name = slice_c_str(&name);
144
145 match self.inner.binary_search_by_key(&real_name, |interface| interface.name()) {
146 Ok(idx) => unsafe {
147 self.inner.get_unchecked_mut(idx)
148 },
149 Err(idx) => {
150 let interface = InterfaceData {
151 name,
152 addresses: Vec::new(),
153 };
154 self.inner.insert(idx, interface);
155
156 unsafe {
157 self.inner.get_unchecked_mut(idx)
158 }
159 }
160 }
161 }
162
163 #[cfg(not(any(target_os = "linux", target_os = "android")))]
164 pub fn new() -> Option<Self> {
168 use core::mem;
169
170 struct IfAddrs(*mut libc::ifaddrs);
171
172 impl IfAddrs {
173 fn iter<'a>(&'a self) -> IfAddrsIter<'a> {
174 unsafe {
175 IfAddrsIter(self.0.as_ref())
176 }
177 }
178 }
179
180 impl Drop for IfAddrs {
181 fn drop(&mut self) {
182 unsafe {
183 libc::freeifaddrs(self.0);
184 }
185 }
186 }
187
188 struct IfAddrsIter<'a>(Option<&'a libc::ifaddrs>);
189
190 impl<'a> Iterator for IfAddrsIter<'a> {
191 type Item = &'a libc::ifaddrs;
192 fn next(&mut self) -> Option<Self::Item> {
193 match self.0 {
194 Some(next) => unsafe {
195 self.0 = next.ifa_next.as_ref();
196 Some(next)
197 },
198 None => None,
199 }
200 }
201 }
202
203 let mut if_addrs = mem::MaybeUninit::<*mut libc::ifaddrs>::uninit();
204 let if_addrs = unsafe {
205 if libc::getifaddrs(if_addrs.as_mut_ptr()) != 0 {
206 return None;
207 }
208 IfAddrs(if_addrs.assume_init())
209 };
210
211 let mut result = Interfaces {
212 inner: Vec::new()
213 };
214 for addr in if_addrs.iter() {
215 let ifa_addr = unsafe {
216 addr.ifa_addr.as_ref()
217 };
218 let ifa_addr = match ifa_addr {
220 Some(ifa_addr) => ifa_addr,
221 None => continue,
222 };
223
224 let interface = result.store_interface(addr.ifa_name);
225 if ifa_addr.sa_family == libc::AF_INET as _ {
226 let ifa_addr: &libc::sockaddr_in = unsafe {
227 mem::transmute(ifa_addr)
228 };
229
230 let ip = ifa_addr.sin_addr.s_addr.to_ne_bytes();
231 let ip = Ip::V4([ip[0], ip[1], ip[2], ip[3]]);
232 let net_mask = unsafe {
233 addr.ifa_netmask.as_ref()
234 };
235 let prefix = match net_mask {
236 Some(net_mask) if net_mask.sa_family == libc::AF_INET as _ => {
239 let net_mask: &libc::sockaddr_in = unsafe {
240 mem::transmute(net_mask)
241 };
242
243 net_mask.sin_addr.s_addr.count_ones() as u8
244 },
245 _ => 0
246 };
247
248 interface.push(Address {
249 ip,
250 prefix
251 });
252 } else if ifa_addr.sa_family == libc::AF_INET6 as _ {
253 let ifa_addr: &libc::sockaddr_in6 = unsafe {
254 mem::transmute(ifa_addr)
255 };
256
257 let ip: [u16; 8] = unsafe {
258 mem::transmute(ifa_addr.sin6_addr.s6_addr)
259 };
260 let ip = Ip::V6(ip);
261 let net_mask = unsafe {
262 addr.ifa_netmask.as_ref()
263 };
264 let prefix = match net_mask {
265 Some(net_mask) if net_mask.sa_family == libc::AF_INET6 as _ => {
268 let net_mask: &libc::sockaddr_in6 = unsafe {
269 mem::transmute(net_mask)
270 };
271
272 let net_mask: u128 = unsafe {
273 mem::transmute(net_mask.sin6_addr.s6_addr)
274 };
275 net_mask.count_ones() as u8
276 },
277 _ => 0
278 };
279
280 interface.push(Address {
281 ip,
282 prefix
283 });
284 }
285 }
286
287 Some(result)
288 }
289}
290
291impl<'a> IntoIterator for &'a Interfaces {
292 type Item = Interface<'a>;
293 type IntoIter = InterfacesIter<'a>;
294
295 #[inline(always)]
296 fn into_iter(self) -> Self::IntoIter {
297 self.iter()
298 }
299}