Last active
September 2, 2023 03:33
-
-
Save ssrlive/4297e39057e6d9b90923ef9069d44ab8 to your computer and use it in GitHub Desktop.
GetInterfaceInfo function (iphlpapi.h)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // | |
| // https://learn.microsoft.com/en-us/windows/win32/api/iphlpapi/nf-iphlpapi-getinterfaceinfo#examples | |
| // | |
| // [target.'cfg(target_os="windows")'.dependencies] | |
| // windows = { version = "0.51", features = [ | |
| // "Win32_NetworkManagement_IpHelper", | |
| // "Win32_NetworkManagement_Ndis", | |
| // "Win32_Networking_WinSock", | |
| // "Win32_Foundation", | |
| // ] } | |
| use std::{ | |
| convert::TryInto, | |
| mem, | |
| ptr::{self, addr_of}, | |
| slice, | |
| }; | |
| use windows::{ | |
| Win32::Foundation::*, | |
| Win32::NetworkManagement::IpHelper::{GetInterfaceInfo, IP_ADAPTER_INDEX_MAP, IP_INTERFACE_INFO}, | |
| }; | |
| fn main() -> Result<(), Box<dyn std::error::Error>> { | |
| let adapters = get_interface_info()?; | |
| println!("Num adapters: {}", adapters.len()); | |
| for adapter in adapters { | |
| println!("Adapter index: {}\tAdapter name: {}", adapter.index, adapter.name); | |
| } | |
| Ok(()) | |
| } | |
| #[derive(Debug, Clone, PartialEq, Eq, Hash)] | |
| pub struct IpAdapterIndexMap { | |
| pub index: usize, | |
| pub name: String, | |
| } | |
| pub struct RawAllocator { | |
| layout: std::alloc::Layout, | |
| base_ptr: *mut u8, | |
| } | |
| impl RawAllocator { | |
| pub fn new<T>(len: usize) -> Result<Self, Box<dyn std::error::Error>> { | |
| let layout = std::alloc::Layout::from_size_align(len, mem::align_of::<T>())?; | |
| use std::alloc::GlobalAlloc; | |
| let base_ptr = unsafe { std::alloc::System.alloc(layout) }; | |
| Ok(Self { layout, base_ptr }) | |
| } | |
| pub fn as_ptr<T>(&self) -> *mut T { | |
| self.base_ptr.cast() | |
| } | |
| } | |
| impl Drop for RawAllocator { | |
| fn drop(&mut self) { | |
| unsafe { | |
| use std::alloc::GlobalAlloc; | |
| std::alloc::System.dealloc(self.base_ptr, self.layout); | |
| } | |
| } | |
| } | |
| pub fn get_interface_info() -> Result<Vec<IpAdapterIndexMap>, Box<dyn std::error::Error>> { | |
| unsafe { | |
| // Perform the first call to know how many bytes to allocate | |
| let mut raw_buf_len = 0; | |
| let ret_val = GetInterfaceInfo(Some(ptr::null_mut()), &mut raw_buf_len); | |
| if ret_val != ERROR_INSUFFICIENT_BUFFER.0 { | |
| return Err(Box::new(std::io::Error::new( | |
| std::io::ErrorKind::Other, | |
| format!("GetInterfaceInfo: Expected to get the required buffer size, was {ret_val:?}"), | |
| ))); | |
| } | |
| // Allocate an appropriately sized *and aligned* buffer to store the result | |
| let buf_len = raw_buf_len.try_into()?; | |
| let allocator = RawAllocator::new::<IP_INTERFACE_INFO>(buf_len)?; | |
| let ip_interface_info = allocator.as_ptr(); | |
| // Perform the second call to get the data | |
| let ret_val = GetInterfaceInfo(Some(ip_interface_info), &mut raw_buf_len); | |
| if ret_val != NO_ERROR.0 { | |
| return Err(Box::new(std::io::Error::new( | |
| std::io::ErrorKind::Other, | |
| format!("GetInterfaceInfo: Could not get the data on the second call {ret_val:?}"), | |
| ))); | |
| } | |
| // Construct a pointer to the adapter array that preserves the provenance of the original pointer | |
| let adapter_ptr = addr_of!((*ip_interface_info).Adapter); | |
| let adapter_ptr = adapter_ptr.cast::<IP_ADAPTER_INDEX_MAP>(); | |
| // Combine the pointer and length into a Rust slice | |
| let n_adapters = (*ip_interface_info).NumAdapters; | |
| let n_adapters = n_adapters.try_into()?; | |
| let adapters = slice::from_raw_parts(adapter_ptr, n_adapters); | |
| let mut result = vec![]; | |
| for adapter in adapters { | |
| let IP_ADAPTER_INDEX_MAP { | |
| Index: index, | |
| Name: name, | |
| } = adapter; | |
| // The fixed-size buffer contains data after the UTF-16 NUL character | |
| let name_end = name.iter().position(|&c| c == 0).unwrap_or(name.len()); | |
| let name = String::from_utf16_lossy(&name[..name_end]); | |
| result.push(IpAdapterIndexMap { | |
| index: usize::try_from(*index)?, | |
| name, | |
| }); | |
| } | |
| Ok(result) | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment