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 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 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}