Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use 'ConvertInterfaceLuidToIndex' to obtain the index #26

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 18 additions & 58 deletions src/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,8 @@
core::GUID,
Win32::{
Foundation::FALSE,
NetworkManagement::{
IpHelper::{ConvertLengthToIpv4Mask, IP_ADAPTER_ADDRESSES_LH},
Ndis::NET_LUID_LH,
},
System::{Com::CLSIDFromString, Threading::CreateEventA},
NetworkManagement::{IpHelper::ConvertLengthToIpv4Mask, Ndis::NET_LUID_LH},
System::Threading::CreateEventA,
},
};

Expand All @@ -35,29 +32,16 @@
adapter: UnsafeHandle<wintun_raw::WINTUN_ADAPTER_HANDLE>,
wintun: Wintun,
guid: u128,
}

fn get_adapter_luid(wintun: &Wintun, adapter: wintun_raw::WINTUN_ADAPTER_HANDLE) -> NET_LUID_LH {
let mut luid: wintun_raw::NET_LUID = unsafe { std::mem::zeroed() };
unsafe { wintun.WintunGetAdapterLUID(adapter, &mut luid as *mut wintun_raw::NET_LUID) };
unsafe { std::mem::transmute(luid) }
index: u32,
luid: NET_LUID_LH,
}

impl Adapter {
/// Returns the `Friendly Name` of this adapter,
/// which is the human readable name shown in Windows
pub fn get_name(&self) -> Result<String, Error> {
let name = util::guid_to_win_style_string(&GUID::from_u128(self.guid))?;
let mut friendly_name = None;

util::get_adapters_addresses(|address| {
let name_iter = unsafe { util::win_pstr_to_string(address.AdapterName) }?;
if name_iter == name {
friendly_name = Some(unsafe { util::win_pwstr_to_string(address.FriendlyName)? });
}
Ok(())
})?;
friendly_name.ok_or(format!("Unable to find matching {}", name).into())
let name = crate::ffi::luid_to_alias(&self.luid)?;
Ok(util::decode_utf16(&name))
}

/// Sets the `Friendly Name` of this adapter,
Expand Down Expand Up @@ -86,8 +70,6 @@
/// Creates a new wintun adapter inside the name `name` with tunnel type `tunnel_type`
///
/// Optionally a GUID can be specified that will become the GUID of this adapter once created.
/// Adapters obtained via this function will be able to return their adapter index via
/// [`Adapter::get_adapter_index`]
pub fn create(wintun: &Wintun, name: &str, tunnel_type: &str, guid: Option<u128>) -> Result<Arc<Adapter>, Error> {
let name_utf16: Vec<_> = name.encode_utf16().chain(std::iter::once(0)).collect();
let tunnel_type_utf16: Vec<u16> = tunnel_type.encode_utf16().chain(std::iter::once(0)).collect();
Expand All @@ -111,22 +93,19 @@
if result.is_null() {
Err("Failed to create adapter".into())
} else {
let luid = crate::ffi::alias_to_luid(&name_utf16)?;
let index = crate::ffi::luid_to_index(&luid)?;
Ok(Arc::new(Adapter {
adapter: UnsafeHandle(result),
wintun: wintun.clone(),
guid,
index,
luid,
}))
}
}
TroyNeubauer marked this conversation as resolved.
Show resolved Hide resolved

/// Attempts to open an existing wintun interface name `name`.
///
/// Adapters opened via this call will have an unknown GUID meaning [`Adapter::get_adapter_index`]
/// will always fail because knowing the adapter's GUID is required to determine its index.
/// Currently a workaround is to delete and re-create a new adapter every time one is needed so
/// that it gets created with a known GUID, allowing [`Adapter::get_adapter_index`] to works as
/// expected. There is likely a way to get the GUID of our adapter using the Windows Registry
/// or via the Win32 API, so PR's that solve this issue are always welcome!
pub fn open(wintun: &Wintun, name: &str) -> Result<Arc<Adapter>, Error> {
let name_utf16: Vec<u16> = OsStr::new(name).encode_wide().chain(std::iter::once(0)).collect();

Expand All @@ -137,24 +116,16 @@
if result.is_null() {
Err("WintunOpenAdapter failed".into())
} else {
let mut guid = None;
util::get_adapters_addresses(|address: IP_ADAPTER_ADDRESSES_LH| {
let frindly_name = unsafe { util::win_pwstr_to_string(address.FriendlyName)? };
if frindly_name == name {
let adapter_name = unsafe { util::win_pstr_to_string(address.AdapterName) }?;
let adapter_name_utf16: Vec<u16> = adapter_name.encode_utf16().chain(std::iter::once(0)).collect();
let adapter_name_ptr: *const u16 = adapter_name_utf16.as_ptr();
let mut adapter: GUID = unsafe { std::mem::zeroed() };
unsafe { CLSIDFromString(adapter_name_ptr, &mut adapter as *mut GUID) };
guid = Some(adapter);
}
Ok(())
})?;
let guid = util::win_guid_to_u128(&guid.ok_or("Unable to find matching GUID")?);
let luid = crate::ffi::alias_to_luid(&name_utf16)?;
let index = crate::ffi::luid_to_index(&luid)?;
let guid = crate::ffi::luid_to_guid(&luid)?;
let guid = unsafe { std::mem::transmute(guid) };

Check failure on line 122 in src/adapter.rs

View workflow job for this annotation

GitHub Actions / Clippy Check & Build

transmute used without annotations
Ok(Arc::new(Adapter {
adapter: UnsafeHandle(result),
wintun: wintun.clone(),
guid,
index,
luid,
}))
}
}
Expand Down Expand Up @@ -199,7 +170,7 @@

/// Returns the Win32 LUID for this adapter
pub fn get_luid(&self) -> NET_LUID_LH {
get_adapter_luid(&self.wintun, self.adapter.0)
self.luid
}

/// Set `MTU` of this adapter
Expand All @@ -217,18 +188,7 @@
/// Returns the Win32 interface index of this adapter. Useful for specifying the interface
/// when executing `netsh interface ip` commands
pub fn get_adapter_index(&self) -> Result<u32, Error> {
let name = util::guid_to_win_style_string(&GUID::from_u128(self.guid))?;
let mut adapter_index = None;

util::get_adapters_addresses(|address| {
let name_iter = unsafe { util::win_pstr_to_string(address.AdapterName) }?;
if name_iter == name {
adapter_index = unsafe { Some(address.Anonymous1.Anonymous.IfIndex) };
// adapter_index = Some(address.Ipv6IfIndex);
}
Ok(())
})?;
adapter_index.ok_or(format!("Unable to find matching {}", name).into())
Ok(self.index)
}

/// Sets the IP address for this adapter, using command `netsh`.
Expand Down
43 changes: 43 additions & 0 deletions src/ffi.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
use crate::wintun_raw::WCHAR;
TroyNeubauer marked this conversation as resolved.
Show resolved Hide resolved
use std::{io, mem};
use windows_sys::core::GUID;
use windows_sys::Win32::NetworkManagement::IpHelper::{
ConvertInterfaceAliasToLuid, ConvertInterfaceLuidToAlias, ConvertInterfaceLuidToGuid, ConvertInterfaceLuidToIndex,
};
use windows_sys::Win32::NetworkManagement::Ndis::NET_LUID_LH;

pub fn luid_to_alias(luid: &NET_LUID_LH) -> io::Result<Vec<WCHAR>> {
// IF_MAX_STRING_SIZE + 1
let mut alias = vec![0; 257];

match unsafe { ConvertInterfaceLuidToAlias(luid, alias.as_mut_ptr(), alias.len()) } {
0 => Ok(alias),
err => Err(io::Error::from_raw_os_error(err as _)),
}
}

pub fn alias_to_luid(alias: &[WCHAR]) -> io::Result<NET_LUID_LH> {
let mut luid = unsafe { mem::zeroed() };

match unsafe { ConvertInterfaceAliasToLuid(alias.as_ptr(), &mut luid) } {
0 => Ok(luid),
err => Err(io::Error::from_raw_os_error(err as _)),
}
}
pub fn luid_to_index(luid: &NET_LUID_LH) -> io::Result<u32> {
let mut index = 0;

match unsafe { ConvertInterfaceLuidToIndex(luid, &mut index) } {
0 => Ok(index),
err => Err(io::Error::from_raw_os_error(err as _)),
}
}

pub fn luid_to_guid(luid: &NET_LUID_LH) -> io::Result<GUID> {
let mut guid = unsafe { mem::zeroed() };

match unsafe { ConvertInterfaceLuidToGuid(luid, &mut guid) } {
0 => Ok(guid),
err => Err(io::Error::from_raw_os_error(err as _)),
}
}
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,17 +66,18 @@
//! # Features
//!
//! - `panic_on_unsent_packets`: Panics if a send packet is dropped without being sent. Useful for
//! debugging packet issues because unsent packets that are dropped without being sent hold up

Check failure on line 69 in src/lib.rs

View workflow job for this annotation

GitHub Actions / Clippy Check & Build

doc list item missing indentation
//! wintun's internal ring buffer.

Check failure on line 70 in src/lib.rs

View workflow job for this annotation

GitHub Actions / Clippy Check & Build

doc list item missing indentation
//!
//! # TODO:
//! - Add async support
//! Requires hooking into a windows specific reactor and registering read interest on wintun's read

Check failure on line 74 in src/lib.rs

View workflow job for this annotation

GitHub Actions / Clippy Check & Build

doc list item missing indentation
//! handle. Asyncify other slow operations via tokio::spawn_blocking. As always, PR's are welcome!

Check failure on line 75 in src/lib.rs

View workflow job for this annotation

GitHub Actions / Clippy Check & Build

doc list item missing indentation
//!

mod adapter;
mod error;
mod ffi;
mod log;
mod packet;
mod session;
Expand Down
5 changes: 5 additions & 0 deletions src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,11 @@ pub(crate) fn get_adapter_mtu(luid: &NET_LUID_LH) -> std::io::Result<usize> {
}
}

pub fn decode_utf16(string: &[u16]) -> String {
let end = string.iter().position(|b| *b == 0).unwrap_or(string.len());
String::from_utf16_lossy(&string[..end])
}

#[repr(C, align(1))]
#[derive(c2rust_bitfields::BitfieldStruct)]
#[allow(non_snake_case)]
Expand Down
Loading