# It is not intended for manual editing.
version = 3
+[[package]]
+name = "autocfg"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
+
+[[package]]
+name = "bitflags"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "cfg_aliases"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
+
+[[package]]
+name = "libc"
+version = "0.2.155"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
+
+[[package]]
+name = "memoffset"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
+dependencies = [
+ "autocfg",
+]
+
[[package]]
name = "netwatcher"
version = "0.1.0"
dependencies = [
+ "nix",
"windows",
]
+[[package]]
+name = "nix"
+version = "0.29.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46"
+dependencies = [
+ "bitflags",
+ "cfg-if",
+ "cfg_aliases",
+ "libc",
+ "memoffset",
+]
+
[[package]]
name = "proc-macro2"
version = "1.0.84"
[dependencies]
-[dependencies.windows]
+[target.'cfg(unix)'.dependencies]
+nix = { version = "0.29.0", features = ["net"] }
+
+[target.'cfg(windows)'.dependencies.windows]
version = "0.56.0"
features = [
"Win32_NetworkManagement_IpHelper",
--- /dev/null
+use std::{collections::HashMap, net::IpAddr};
+
+use nix::{ifaddrs::getifaddrs, net::if_::if_nametoindex};
+
+use crate::util::format_mac;
+use crate::{Error, IfIndex, Interface};
+
+struct CandidateInterface {
+ name: String,
+ index: u32,
+ hw_addr: Option<String>,
+ ips: Vec<IpAddr>,
+}
+
+pub(crate) fn list_interfaces() -> Result<HashMap<IfIndex, Interface>, Error> {
+ let addrs = getifaddrs().map_err(|_| Error::Internal)?;
+ let mut candidates = HashMap::new();
+
+ for addr in addrs {
+ let index = if_nametoindex(addr.interface_name.as_str()).map_err(|_| Error::Internal)?;
+ let candidate = candidates
+ .entry(addr.interface_name.clone())
+ .or_insert_with(|| CandidateInterface {
+ name: addr.interface_name.clone(),
+ index,
+ hw_addr: None,
+ ips: vec![],
+ });
+ if let Some(a) = addr.address {
+ if let Some(a) = a.as_link_addr() {
+ if let Some(raw_addr) = a.addr() {
+ candidate.hw_addr = Some(format_mac(&raw_addr)?);
+ }
+ }
+ if let Some(a) = a.as_sockaddr_in() {
+ candidate.ips.push(IpAddr::V4(a.ip()));
+ }
+ if let Some(a) = a.as_sockaddr_in6() {
+ candidate.ips.push(IpAddr::V6(a.ip()));
+ }
+ }
+ }
+
+ let ifs = candidates
+ .drain()
+ .flat_map(|(_, c)| {
+ c.hw_addr.map(|hw_addr| {
+ (
+ c.index,
+ Interface {
+ index: c.index,
+ hw_addr,
+ name: c.name,
+ ips: c.ips,
+ },
+ )
+ })
+ })
+ .collect();
+ Ok(ifs)
+}
+
+#[cfg(test)]
+mod test {
+ use super::list_interfaces;
+
+ #[test]
+ fn list() {
+ let ifaces = list_interfaces().unwrap();
+ println!("{:?}", ifaces);
+ }
+}
};
#[cfg_attr(windows, path = "imp_win.rs")]
+#[cfg_attr(target_vendor = "apple", path = "imp_mac.rs")]
mod imp;
+mod util;
type IfIndex = u32;
--- /dev/null
+use crate::Error;
+use std::fmt::Write;
+
+pub(crate) fn format_mac(bytes: &[u8]) -> Result<String, Error> {
+ let mut mac = String::with_capacity(bytes.len() * 3);
+ for i in 0..bytes.len() {
+ if i != 0 {
+ write!(mac, ":").map_err(|_| Error::Internal)?;
+ }
+ write!(mac, "{:02X}", bytes[i]).map_err(|_| Error::Internal)?;
+ }
+ Ok(mac)
+}