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