1 //! Network interface name resolution.
2 //!
3 //! Uses Linux and/or POSIX functions to resolve interface names like "eth0"
4 //! or "socan1" into device numbers.
5
6 use std::fmt;
7 use crate::{Error, NixPath, Result};
8 use libc::c_uint;
9
10 #[cfg(not(solarish))]
11 /// type alias for InterfaceFlags
12 pub type IflagsType = libc::c_int;
13 #[cfg(solarish)]
14 /// type alias for InterfaceFlags
15 pub type IflagsType = libc::c_longlong;
16
17 /// Resolve an interface into a interface number.
if_nametoindex<P: ?Sized + NixPath>(name: &P) -> Result<c_uint>18 pub fn if_nametoindex<P: ?Sized + NixPath>(name: &P) -> Result<c_uint> {
19 let if_index = name
20 .with_nix_path(|name| unsafe { libc::if_nametoindex(name.as_ptr()) })?;
21
22 if if_index == 0 {
23 Err(Error::last())
24 } else {
25 Ok(if_index)
26 }
27 }
28
29 libc_bitflags!(
30 /// Standard interface flags, used by `getifaddrs`
31 pub struct InterfaceFlags: IflagsType {
32
33 /// Interface is running. (see
34 /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html))
35 IFF_UP as IflagsType;
36 /// Valid broadcast address set. (see
37 /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html))
38 IFF_BROADCAST as IflagsType;
39 /// Internal debugging flag. (see
40 /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html))
41 #[cfg(not(target_os = "haiku"))]
42 IFF_DEBUG as IflagsType;
43 /// Interface is a loopback interface. (see
44 /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html))
45 IFF_LOOPBACK as IflagsType;
46 /// Interface is a point-to-point link. (see
47 /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html))
48 IFF_POINTOPOINT as IflagsType;
49 /// Avoid use of trailers. (see
50 /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html))
51 #[cfg(any(
52 linux_android,
53 solarish,
54 apple_targets,
55 target_os = "fuchsia",
56 target_os = "netbsd"))]
57 IFF_NOTRAILERS as IflagsType;
58 /// Interface manages own routes.
59 #[cfg(any(target_os = "dragonfly"))]
60 IFF_SMART as IflagsType;
61 /// Resources allocated. (see
62 /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html))
63 #[cfg(any(
64 linux_android,
65 bsd,
66 solarish,
67 target_os = "fuchsia"))]
68 IFF_RUNNING as IflagsType;
69 /// No arp protocol, L2 destination address not set. (see
70 /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html))
71 IFF_NOARP as IflagsType;
72 /// Interface is in promiscuous mode. (see
73 /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html))
74 IFF_PROMISC as IflagsType;
75 /// Receive all multicast packets. (see
76 /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html))
77 IFF_ALLMULTI as IflagsType;
78 /// Master of a load balancing bundle. (see
79 /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html))
80 #[cfg(any(linux_android, target_os = "fuchsia"))]
81 IFF_MASTER;
82 /// transmission in progress, tx hardware queue is full
83 #[cfg(any(target_os = "freebsd", apple_targets, netbsdlike))]
84 IFF_OACTIVE;
85 /// Protocol code on board.
86 #[cfg(solarish)]
87 IFF_INTELLIGENT as IflagsType;
88 /// Slave of a load balancing bundle. (see
89 /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html))
90 #[cfg(any(linux_android, target_os = "fuchsia"))]
91 IFF_SLAVE;
92 /// Can't hear own transmissions.
93 #[cfg(bsd)]
94 IFF_SIMPLEX;
95 /// Supports multicast. (see
96 /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html))
97 IFF_MULTICAST as IflagsType;
98 /// Per link layer defined bit.
99 #[cfg(bsd)]
100 IFF_LINK0;
101 /// Multicast using broadcast.
102 #[cfg(solarish)]
103 IFF_MULTI_BCAST as IflagsType;
104 /// Is able to select media type via ifmap. (see
105 /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html))
106 #[cfg(any(linux_android, target_os = "fuchsia"))]
107 IFF_PORTSEL;
108 /// Per link layer defined bit.
109 #[cfg(bsd)]
110 IFF_LINK1;
111 /// Non-unique address.
112 #[cfg(solarish)]
113 IFF_UNNUMBERED as IflagsType;
114 /// Auto media selection active. (see
115 /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html))
116 #[cfg(any(linux_android, target_os = "fuchsia"))]
117 IFF_AUTOMEDIA;
118 /// Per link layer defined bit.
119 #[cfg(bsd)]
120 IFF_LINK2;
121 /// Use alternate physical connection.
122 #[cfg(any(freebsdlike, apple_targets))]
123 IFF_ALTPHYS;
124 /// DHCP controls interface.
125 #[cfg(solarish)]
126 IFF_DHCPRUNNING as IflagsType;
127 /// The addresses are lost when the interface goes down. (see
128 /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html))
129 #[cfg(any(linux_android, target_os = "fuchsia"))]
130 IFF_DYNAMIC;
131 /// Do not advertise.
132 #[cfg(solarish)]
133 IFF_PRIVATE as IflagsType;
134 /// Driver signals L1 up. Volatile.
135 #[cfg(any(target_os = "fuchsia", target_os = "linux"))]
136 IFF_LOWER_UP;
137 /// Interface is in polling mode.
138 #[cfg(any(target_os = "dragonfly"))]
139 IFF_POLLING_COMPAT;
140 /// Unconfigurable using ioctl(2).
141 #[cfg(any(target_os = "freebsd"))]
142 IFF_CANTCONFIG;
143 /// Do not transmit packets.
144 #[cfg(solarish)]
145 IFF_NOXMIT as IflagsType;
146 /// Driver signals dormant. Volatile.
147 #[cfg(any(target_os = "fuchsia", target_os = "linux"))]
148 IFF_DORMANT;
149 /// User-requested promisc mode.
150 #[cfg(freebsdlike)]
151 IFF_PPROMISC;
152 /// Just on-link subnet.
153 #[cfg(solarish)]
154 IFF_NOLOCAL as IflagsType;
155 /// Echo sent packets. Volatile.
156 #[cfg(any(target_os = "fuchsia", target_os = "linux"))]
157 IFF_ECHO;
158 /// User-requested monitor mode.
159 #[cfg(freebsdlike)]
160 IFF_MONITOR;
161 /// Address is deprecated.
162 #[cfg(solarish)]
163 IFF_DEPRECATED as IflagsType;
164 /// Static ARP.
165 #[cfg(freebsdlike)]
166 IFF_STATICARP;
167 /// Address from stateless addrconf.
168 #[cfg(solarish)]
169 IFF_ADDRCONF as IflagsType;
170 /// Interface is in polling mode.
171 #[cfg(any(target_os = "dragonfly"))]
172 IFF_NPOLLING;
173 /// Router on interface.
174 #[cfg(solarish)]
175 IFF_ROUTER as IflagsType;
176 /// Interface is in polling mode.
177 #[cfg(any(target_os = "dragonfly"))]
178 IFF_IDIRECT;
179 /// Interface is winding down
180 #[cfg(any(target_os = "freebsd"))]
181 IFF_DYING;
182 /// No NUD on interface.
183 #[cfg(solarish)]
184 IFF_NONUD as IflagsType;
185 /// Interface is being renamed
186 #[cfg(any(target_os = "freebsd"))]
187 IFF_RENAMING;
188 /// Anycast address.
189 #[cfg(solarish)]
190 IFF_ANYCAST as IflagsType;
191 /// Don't exchange routing info.
192 #[cfg(solarish)]
193 IFF_NORTEXCH as IflagsType;
194 /// Do not provide packet information
195 #[cfg(any(linux_android, target_os = "fuchsia"))]
196 IFF_NO_PI as IflagsType;
197 /// TUN device (no Ethernet headers)
198 #[cfg(any(linux_android, target_os = "fuchsia"))]
199 IFF_TUN as IflagsType;
200 /// TAP device
201 #[cfg(any(linux_android, target_os = "fuchsia"))]
202 IFF_TAP as IflagsType;
203 /// IPv4 interface.
204 #[cfg(solarish)]
205 IFF_IPV4 as IflagsType;
206 /// IPv6 interface.
207 #[cfg(solarish)]
208 IFF_IPV6 as IflagsType;
209 /// in.mpathd test address
210 #[cfg(solarish)]
211 IFF_NOFAILOVER as IflagsType;
212 /// Interface has failed
213 #[cfg(solarish)]
214 IFF_FAILED as IflagsType;
215 /// Interface is a hot-spare
216 #[cfg(solarish)]
217 IFF_STANDBY as IflagsType;
218 /// Functioning but not used
219 #[cfg(solarish)]
220 IFF_INACTIVE as IflagsType;
221 /// Interface is offline
222 #[cfg(solarish)]
223 IFF_OFFLINE as IflagsType;
224 /// Has CoS marking supported
225 #[cfg(solarish)]
226 IFF_COS_ENABLED as IflagsType;
227 /// Prefer as source addr
228 #[cfg(solarish)]
229 IFF_PREFERRED as IflagsType;
230 /// RFC3041
231 #[cfg(solarish)]
232 IFF_TEMPORARY as IflagsType;
233 /// MTU set
234 #[cfg(solarish)]
235 IFF_FIXEDMTU as IflagsType;
236 /// Cannot send/receive packets
237 #[cfg(solarish)]
238 IFF_VIRTUAL as IflagsType;
239 /// Local address in use
240 #[cfg(solarish)]
241 IFF_DUPLICATE as IflagsType;
242 /// IPMP IP interface
243 #[cfg(solarish)]
244 IFF_IPMP as IflagsType;
245 }
246 );
247
248 impl fmt::Display for InterfaceFlags {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result249 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
250 bitflags::parser::to_writer(self, f)
251 }
252 }
253
254
255 #[cfg(any(
256 bsd,
257 target_os = "fuchsia",
258 target_os = "linux",
259 solarish,
260 ))]
261 mod if_nameindex {
262 use super::*;
263
264 use std::ffi::CStr;
265 use std::fmt;
266 use std::marker::PhantomData;
267 use std::ptr::NonNull;
268
269 /// A network interface. Has a name like "eth0" or "wlp4s0" or "wlan0", as well as an index
270 /// (1, 2, 3, etc) that identifies it in the OS's networking stack.
271 #[allow(missing_copy_implementations)]
272 #[repr(transparent)]
273 pub struct Interface(libc::if_nameindex);
274
275 impl Interface {
276 /// Obtain the index of this interface.
index(&self) -> c_uint277 pub fn index(&self) -> c_uint {
278 self.0.if_index
279 }
280
281 /// Obtain the name of this interface.
name(&self) -> &CStr282 pub fn name(&self) -> &CStr {
283 unsafe { CStr::from_ptr(self.0.if_name) }
284 }
285 }
286
287 impl fmt::Debug for Interface {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result288 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
289 f.debug_struct("Interface")
290 .field("index", &self.index())
291 .field("name", &self.name())
292 .finish()
293 }
294 }
295
296 /// A list of the network interfaces available on this system. Obtained from [`if_nameindex()`].
297 #[repr(transparent)]
298 pub struct Interfaces {
299 ptr: NonNull<libc::if_nameindex>,
300 }
301
302 impl Interfaces {
303 /// Iterate over the interfaces in this list.
304 #[inline]
iter(&self) -> InterfacesIter<'_>305 pub fn iter(&self) -> InterfacesIter<'_> {
306 self.into_iter()
307 }
308
309 /// Convert this to a slice of interfaces. Note that the underlying interfaces list is
310 /// null-terminated, so calling this calculates the length. If random access isn't needed,
311 /// [`Interfaces::iter()`] should be used instead.
to_slice(&self) -> &[Interface]312 pub fn to_slice(&self) -> &[Interface] {
313 let ifs = self.ptr.as_ptr().cast();
314 let len = self.iter().count();
315 unsafe { std::slice::from_raw_parts(ifs, len) }
316 }
317 }
318
319 impl Drop for Interfaces {
drop(&mut self)320 fn drop(&mut self) {
321 unsafe { libc::if_freenameindex(self.ptr.as_ptr()) };
322 }
323 }
324
325 impl fmt::Debug for Interfaces {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result326 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
327 self.to_slice().fmt(f)
328 }
329 }
330
331 impl<'a> IntoIterator for &'a Interfaces {
332 type IntoIter = InterfacesIter<'a>;
333 type Item = &'a Interface;
334 #[inline]
into_iter(self) -> Self::IntoIter335 fn into_iter(self) -> Self::IntoIter {
336 InterfacesIter {
337 ptr: self.ptr.as_ptr(),
338 _marker: PhantomData,
339 }
340 }
341 }
342
343 /// An iterator over the interfaces in an [`Interfaces`].
344 #[derive(Debug)]
345 pub struct InterfacesIter<'a> {
346 ptr: *const libc::if_nameindex,
347 _marker: PhantomData<&'a Interfaces>,
348 }
349
350 impl<'a> Iterator for InterfacesIter<'a> {
351 type Item = &'a Interface;
352 #[inline]
next(&mut self) -> Option<Self::Item>353 fn next(&mut self) -> Option<Self::Item> {
354 unsafe {
355 if (*self.ptr).if_index == 0 {
356 None
357 } else {
358 let ret = &*(self.ptr as *const Interface);
359 self.ptr = self.ptr.add(1);
360 Some(ret)
361 }
362 }
363 }
364 }
365
366 /// Retrieve a list of the network interfaces available on the local system.
367 ///
368 /// ```
369 /// let interfaces = nix::net::if_::if_nameindex().unwrap();
370 /// for iface in &interfaces {
371 /// println!("Interface #{} is called {}", iface.index(), iface.name().to_string_lossy());
372 /// }
373 /// ```
if_nameindex() -> Result<Interfaces>374 pub fn if_nameindex() -> Result<Interfaces> {
375 unsafe {
376 let ifs = libc::if_nameindex();
377 let ptr = NonNull::new(ifs).ok_or_else(Error::last)?;
378 Ok(Interfaces { ptr })
379 }
380 }
381 }
382 #[cfg(any(
383 bsd,
384 target_os = "fuchsia",
385 target_os = "linux",
386 solarish,
387 ))]
388 pub use if_nameindex::*;
389