]> code.octet-stream.net Git - netwatcher/blob - src/list_unix.rs
a6b2bd3bec616d4237f86801e92b96c13cbcee47
[netwatcher] / src / list_unix.rs
1 use std::fmt::Write;
2 use std::{collections::HashMap, net::IpAddr};
3
4 use block2::Block;
5 use nix::libc::c_long;
6 use nix::{ifaddrs::getifaddrs, net::if_::if_nametoindex};
7
8 use crate::{Error, IfIndex, Interface};
9
10 struct CandidateInterface {
11 name: String,
12 index: u32,
13 hw_addr: Option<String>,
14 ips: Vec<IpAddr>,
15 }
16
17 pub(crate) fn list_interfaces() -> Result<HashMap<IfIndex, Interface>, Error> {
18 let addrs = getifaddrs().map_err(|_| Error::Internal)?;
19 let mut candidates = HashMap::new();
20
21 for addr in addrs {
22 let index = if_nametoindex(addr.interface_name.as_str()).map_err(|_| Error::Internal)?;
23 let candidate = candidates
24 .entry(addr.interface_name.clone())
25 .or_insert_with(|| CandidateInterface {
26 name: addr.interface_name.clone(),
27 index,
28 hw_addr: None,
29 ips: vec![],
30 });
31 if let Some(a) = addr.address {
32 if let Some(a) = a.as_link_addr() {
33 if let Some(raw_addr) = a.addr() {
34 candidate.hw_addr = Some(format_mac(&raw_addr)?);
35 }
36 }
37 if let Some(a) = a.as_sockaddr_in() {
38 candidate.ips.push(IpAddr::V4(a.ip()));
39 }
40 if let Some(a) = a.as_sockaddr_in6() {
41 candidate.ips.push(IpAddr::V6(a.ip()));
42 }
43 }
44 }
45
46 let ifs = candidates
47 .drain()
48 .flat_map(|(_, c)| {
49 c.hw_addr.map(|hw_addr| {
50 (
51 c.index,
52 Interface {
53 index: c.index,
54 hw_addr,
55 name: c.name,
56 ips: c.ips,
57 },
58 )
59 })
60 })
61 .collect();
62 Ok(ifs)
63 }
64
65 fn format_mac(bytes: &[u8]) -> Result<String, Error> {
66 let mut mac = String::with_capacity(bytes.len() * 3);
67 for i in 0..bytes.len() {
68 if i != 0 {
69 write!(mac, ":").map_err(|_| Error::Internal)?;
70 }
71 write!(mac, "{:02X}", bytes[i]).map_err(|_| Error::Internal)?;
72 }
73 Ok(mac)
74 }