webrtc_util/ifaces/ffi/unix/
mod.rs

1use crate::ifaces::{Interface, Kind, NextHop};
2
3use nix::sys::socket::{AddressFamily, SockaddrLike, SockaddrStorage};
4use std::io::Error;
5use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6};
6
7fn ss_to_netsa(ss: &SockaddrStorage) -> Option<SocketAddr> {
8    match ss.family() {
9        Some(AddressFamily::Inet) => ss.as_sockaddr_in().map(|sin| {
10            SocketAddr::V4(SocketAddrV4::new(
11                std::net::Ipv4Addr::from(sin.ip()),
12                sin.port(),
13            ))
14        }),
15        Some(AddressFamily::Inet6) => ss.as_sockaddr_in6().map(|sin6| {
16            SocketAddr::V6(SocketAddrV6::new(
17                sin6.ip(),
18                sin6.port(),
19                sin6.flowinfo(),
20                sin6.scope_id(),
21            ))
22        }),
23        _ => None,
24    }
25}
26
27/// Query the local system for all interface addresses.
28pub fn ifaces() -> Result<Vec<Interface>, Error> {
29    let mut ret = Vec::new();
30    for ifa in nix::ifaddrs::getifaddrs()? {
31        if let Some(kind) = ifa
32            .address
33            .as_ref()
34            .and_then(SockaddrStorage::family)
35            .and_then(|af| match af {
36                AddressFamily::Inet => Some(Kind::Ipv4),
37                AddressFamily::Inet6 => Some(Kind::Ipv6),
38                #[cfg(any(
39                    target_os = "android",
40                    target_os = "linux",
41                    target_os = "illumos",
42                    target_os = "fuchsia",
43                    target_os = "solaris"
44                ))]
45                AddressFamily::Packet => Some(Kind::Packet),
46                #[cfg(any(
47                    target_os = "dragonfly",
48                    target_os = "freebsd",
49                    target_os = "ios",
50                    target_os = "macos",
51                    target_os = "illumos",
52                    target_os = "netbsd",
53                    target_os = "openbsd"
54                ))]
55                AddressFamily::Link => Some(Kind::Link),
56                _ => None,
57            })
58        {
59            let name = ifa.interface_name;
60            let dst = ifa.destination.as_ref().and_then(ss_to_netsa);
61            let broadcast = ifa.broadcast.as_ref().and_then(ss_to_netsa);
62            let hop = dst
63                .map(NextHop::Destination)
64                .or(broadcast.map(NextHop::Broadcast));
65            let addr = ifa.address.as_ref().and_then(ss_to_netsa);
66            let mask = ifa.netmask.as_ref().and_then(ss_to_netsa);
67
68            ret.push(Interface {
69                name,
70                kind,
71                addr,
72                mask,
73                hop,
74            });
75        }
76    }
77
78    Ok(ret)
79}