use std::io;
pub fn ifname_to_index(name: &str) -> io::Result<u32> {
ifname_to_index_in(name)
}
#[cfg(bsd_like)]
fn ifname_to_index_in(name: &str) -> io::Result<u32> {
use std::ffi::CString;
let name_cstr = CString::new(name).map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?;
let res = unsafe { libc::if_nametoindex(name_cstr.as_ptr()) };
if res == 0 {
Err(io::Error::last_os_error())
} else {
Ok(res)
}
}
#[cfg(linux_like)]
fn ifname_to_index_in(name: &str) -> io::Result<u32> {
use rustix::net::{netdevice::name_to_index, socket, AddressFamily, SocketType};
let socket_fd = socket(AddressFamily::INET, SocketType::DGRAM, None)?;
name_to_index(socket_fd, name).map_err(Into::into)
}
#[cfg(windows)]
fn ifname_to_index_in(name: &str) -> io::Result<u32> {
use std::ffi::CString;
use widestring::U16CString;
use windows_sys::Win32::NetworkManagement::{
IpHelper::{if_nametoindex, ConvertInterfaceAliasToLuid, ConvertInterfaceLuidToIndex},
Ndis::NET_LUID_LH,
};
fn try_friendly_name(name: &str) -> io::Result<u32> {
let wide_name =
U16CString::from_str(name).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
let mut luid = NET_LUID_LH { Value: 0 };
let result = unsafe { ConvertInterfaceAliasToLuid(wide_name.as_ptr(), &mut luid) };
if result != 0 {
return Err(io::Error::last_os_error());
}
let mut idx = 0u32;
let result = unsafe { ConvertInterfaceLuidToIndex(&luid, &mut idx) };
if result != 0 {
return Err(io::Error::last_os_error());
}
Ok(idx)
}
try_friendly_name(name).or_else(|_| {
let name_cstr =
CString::new(name).map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?;
let res = unsafe { if_nametoindex(name_cstr.as_ptr() as _) };
if res == 0 {
Err(io::Error::last_os_error())
} else {
Ok(res)
}
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn nonexistent_name_returns_err() {
let r = ifname_to_index("nonexistent_iface_xyz_12345");
assert!(r.is_err());
}
#[cfg(not(target_os = "dragonfly"))]
#[test]
fn round_trip_first_interface() {
let ift = crate::interfaces().unwrap();
let first = ift.iter().next().unwrap();
let idx = ifname_to_index(first.name()).unwrap();
assert_eq!(idx, first.index());
}
}