heim_net/sys/unix/
nic.rs

1use macaddr::MacAddr;
2use nix::ifaddrs;
3use nix::net::if_::InterfaceFlags;
4use nix::sys::socket;
5
6use heim_common::prelude::*;
7
8use crate::Address;
9
10#[derive(Debug)]
11pub struct Nic(ifaddrs::InterfaceAddress);
12
13impl Nic {
14    pub fn name(&self) -> &str {
15        self.0.interface_name.as_str()
16    }
17
18    pub fn address(&self) -> Address {
19        self.0
20            .address
21            .as_ref()
22            .expect("NIC stream should exclude entries without address")
23            .into()
24    }
25
26    pub fn netmask(&self) -> Option<Address> {
27        self.0.netmask.as_ref().map(Into::into)
28    }
29
30    pub fn broadcast(&self) -> Option<Address> {
31        self.0.broadcast.as_ref().map(Into::into)
32    }
33
34    pub fn destination(&self) -> Option<Address> {
35        self.0.destination.as_ref().map(Into::into)
36    }
37
38    pub fn is_up(&self) -> bool {
39        self.0.flags.contains(InterfaceFlags::IFF_UP)
40    }
41
42    pub fn is_broadcast(&self) -> bool {
43        self.0.flags.contains(InterfaceFlags::IFF_BROADCAST)
44    }
45
46    pub fn is_loopback(&self) -> bool {
47        self.0.flags.contains(InterfaceFlags::IFF_LOOPBACK)
48    }
49
50    pub fn is_point_to_point(&self) -> bool {
51        self.0.flags.contains(InterfaceFlags::IFF_POINTOPOINT)
52    }
53
54    pub fn is_multicast(&self) -> bool {
55        self.0.flags.contains(InterfaceFlags::IFF_MULTICAST)
56    }
57}
58
59pub fn nic() -> impl Stream<Item = Result<Nic>> {
60    future::lazy(|_| {
61        // `nix::ifaddrs` structs are not safe to send between threads,
62        // so collecting them in a once
63        // TODO: Can we Pin them maybe?
64        let iter = ifaddrs::getifaddrs()?;
65        let interfaces = iter.collect::<Vec<_>>();
66
67        Ok(stream::iter(interfaces).map(Ok))
68    })
69    .try_flatten_stream()
70    .try_filter_map(|addr: ifaddrs::InterfaceAddress| {
71        // Skipping unsupported address families
72        let result = if addr.address.is_some() {
73            Some(Nic(addr))
74        } else {
75            None
76        };
77
78        future::ok(result)
79    })
80}
81
82impl From<&socket::SockAddr> for Address {
83    fn from(s: &socket::SockAddr) -> Self {
84        use nix::sys::socket::SockAddr::*;
85
86        match *s {
87            Inet(addr) => Address::Inet(addr.to_std()),
88            Link(addr) => Address::Link(MacAddr::from(addr.addr())),
89            other => unimplemented!("Unknown sockaddr: {:?}", other),
90        }
91    }
92}