ndisapi/netlib/ip_helper/network_adapter_info/
statics.rs1use crate::{IfLuid, IphlpNetworkAdapterInfo, MacAddress};
2use windows::Win32::Foundation::{SetLastError, ERROR_BUFFER_OVERFLOW, NO_ERROR};
3use windows::Win32::NetworkManagement::IpHelper::{
4 FreeMibTable, GetAdaptersAddresses, GetIfTable2, GAA_FLAG_INCLUDE_ALL_INTERFACES,
5 GAA_FLAG_INCLUDE_GATEWAYS, GAA_FLAG_SKIP_ANYCAST, GAA_FLAG_SKIP_MULTICAST,
6 IF_TYPE_SOFTWARE_LOOPBACK,
7};
8use windows::Win32::NetworkManagement::Ndis::IfOperStatusUp;
9use windows::Win32::Networking::WinSock::AF_UNSPEC;
10use windows::Win32::{
11 Foundation::WIN32_ERROR,
12 NetworkManagement::IpHelper::{IP_ADAPTER_ADDRESSES_LH, MIB_IF_TABLE2},
13};
14
15impl IphlpNetworkAdapterInfo {
16 pub fn get_external_network_connections() -> Vec<IphlpNetworkAdapterInfo> {
31 let mut ret_val = Vec::new();
32 let mut dw_size = 0;
33 let mut mib_table: *mut MIB_IF_TABLE2 = std::ptr::null_mut();
34
35 let error_code = unsafe { GetIfTable2(&mut mib_table) };
37 if error_code.is_err() {
38 return ret_val;
39 }
40
41 let error_code = unsafe {
42 GetAdaptersAddresses(
43 AF_UNSPEC.0 as u32,
44 GAA_FLAG_SKIP_ANYCAST
45 | GAA_FLAG_SKIP_MULTICAST
46 | GAA_FLAG_INCLUDE_GATEWAYS
47 | GAA_FLAG_INCLUDE_ALL_INTERFACES,
48 None,
49 None,
50 &mut dw_size,
51 )
52 };
53
54 if WIN32_ERROR(error_code) == ERROR_BUFFER_OVERFLOW && dw_size != 0 {
56 loop {
57 let mut ip_address_info = vec![0u8; dw_size as usize];
58
59 let error_code = unsafe {
60 GetAdaptersAddresses(
61 AF_UNSPEC.0 as u32,
62 GAA_FLAG_SKIP_ANYCAST
63 | GAA_FLAG_SKIP_MULTICAST
64 | GAA_FLAG_INCLUDE_GATEWAYS
65 | GAA_FLAG_INCLUDE_ALL_INTERFACES,
66 None,
67 Some(ip_address_info.as_mut_ptr() as *mut IP_ADAPTER_ADDRESSES_LH),
68 &mut dw_size,
69 )
70 };
71
72 if WIN32_ERROR(error_code) == NO_ERROR {
73 let mut current_address =
74 ip_address_info.as_ptr() as *mut IP_ADAPTER_ADDRESSES_LH;
75
76 while !current_address.is_null() {
77 let current = unsafe { &*current_address };
78
79 if current.FirstUnicastAddress.is_null()
80 || current.OperStatus != IfOperStatusUp
81 || current.IfType == IF_TYPE_SOFTWARE_LOOPBACK
82 {
83 current_address = current.Next;
84 continue;
85 }
86
87 for i in 0..unsafe { (*mib_table).NumEntries } {
89 let table_ptr = unsafe { (*mib_table).Table.as_ptr() };
90 let entry_ptr = unsafe { table_ptr.add(i as usize) };
91 if IfLuid::from(unsafe { (*entry_ptr).InterfaceLuid })
92 == IfLuid::from(current.Luid)
93 {
94 ret_val.push(unsafe {
95 IphlpNetworkAdapterInfo::new(current, entry_ptr)
96 });
97 break;
98 }
99 }
100
101 current_address = current.Next;
102 }
103
104 break;
105 }
106 if WIN32_ERROR(error_code) != ERROR_BUFFER_OVERFLOW {
108 unsafe { SetLastError(WIN32_ERROR(error_code)) };
109 break;
110 }
111 }
112 } else {
113 if WIN32_ERROR(error_code) != NO_ERROR {
115 unsafe { SetLastError(WIN32_ERROR(error_code)) };
116 }
117 }
118
119 unsafe { FreeMibTable(mib_table as *const core::ffi::c_void) };
121
122 ret_val
123 }
124
125 pub fn get_connection_by_luid(luid: IfLuid) -> Option<IphlpNetworkAdapterInfo> {
141 let mut dw_size = 0;
142 let mut mib_table: *mut MIB_IF_TABLE2 = std::ptr::null_mut();
143
144 if unsafe { GetIfTable2(&mut mib_table) }.is_err() {
146 return None;
147 }
148
149 let error_code = unsafe {
151 GetAdaptersAddresses(
152 AF_UNSPEC.0 as u32,
153 GAA_FLAG_SKIP_ANYCAST
154 | GAA_FLAG_SKIP_MULTICAST
155 | GAA_FLAG_INCLUDE_GATEWAYS
156 | GAA_FLAG_INCLUDE_ALL_INTERFACES,
157 None,
158 None,
159 &mut dw_size,
160 )
161 };
162
163 if WIN32_ERROR(error_code) == ERROR_BUFFER_OVERFLOW && dw_size != 0 {
164 loop {
165 let mut ip_address_info = vec![0u8; dw_size as usize];
166
167 let error_code = unsafe {
168 GetAdaptersAddresses(
169 AF_UNSPEC.0 as u32,
170 GAA_FLAG_SKIP_ANYCAST
171 | GAA_FLAG_SKIP_MULTICAST
172 | GAA_FLAG_INCLUDE_GATEWAYS
173 | GAA_FLAG_INCLUDE_ALL_INTERFACES,
174 None,
175 Some(ip_address_info.as_mut_ptr() as *mut IP_ADAPTER_ADDRESSES_LH),
176 &mut dw_size,
177 )
178 };
179
180 if WIN32_ERROR(error_code) == NO_ERROR {
181 let mut current_address =
182 ip_address_info.as_ptr() as *mut IP_ADAPTER_ADDRESSES_LH;
183
184 while !current_address.is_null() {
185 let current = unsafe { &*current_address };
186
187 if IfLuid::from(current.Luid) != luid {
188 current_address = current.Next;
189 continue;
190 }
191
192 for i in 0..unsafe { (*mib_table).NumEntries } {
194 let table_ptr = unsafe { (*mib_table).Table.as_ptr() };
195 let entry_ptr = unsafe { table_ptr.add(i as usize) };
196 if IfLuid::from(unsafe { (*entry_ptr).InterfaceLuid }) == luid {
197 let result =
198 unsafe { IphlpNetworkAdapterInfo::new(current, entry_ptr) };
199 unsafe { FreeMibTable(mib_table as *const core::ffi::c_void) };
200 return Some(result);
201 }
202 }
203
204 current_address = current.Next;
205 }
206
207 break;
208 }
209 if WIN32_ERROR(error_code) != ERROR_BUFFER_OVERFLOW {
211 unsafe { SetLastError(WIN32_ERROR(error_code)) };
212 break;
213 }
214 }
215 } else {
216 if WIN32_ERROR(error_code) != NO_ERROR {
218 unsafe { SetLastError(WIN32_ERROR(error_code)) };
219 }
220 }
221
222 unsafe { FreeMibTable(mib_table as *const core::ffi::c_void) };
224
225 None
226 }
227
228 pub fn get_connection_by_hw_address(address: &MacAddress) -> Option<IphlpNetworkAdapterInfo> {
244 let mut dw_size = 0;
245 let mut mib_table: *mut MIB_IF_TABLE2 = std::ptr::null_mut();
246
247 if unsafe { GetIfTable2(&mut mib_table) }.is_err() {
249 return None;
250 }
251
252 let error_code = unsafe {
254 GetAdaptersAddresses(
255 AF_UNSPEC.0 as u32,
256 GAA_FLAG_SKIP_ANYCAST
257 | GAA_FLAG_SKIP_MULTICAST
258 | GAA_FLAG_INCLUDE_GATEWAYS
259 | GAA_FLAG_INCLUDE_ALL_INTERFACES,
260 None,
261 None,
262 &mut dw_size,
263 )
264 };
265
266 if WIN32_ERROR(error_code) == ERROR_BUFFER_OVERFLOW && dw_size != 0 {
267 loop {
268 let mut ip_address_info = vec![0u8; dw_size as usize];
269
270 let error_code = unsafe {
271 GetAdaptersAddresses(
272 AF_UNSPEC.0 as u32,
273 GAA_FLAG_SKIP_ANYCAST
274 | GAA_FLAG_SKIP_MULTICAST
275 | GAA_FLAG_INCLUDE_GATEWAYS
276 | GAA_FLAG_INCLUDE_ALL_INTERFACES,
277 None,
278 Some(ip_address_info.as_mut_ptr() as *mut IP_ADAPTER_ADDRESSES_LH),
279 &mut dw_size,
280 )
281 };
282
283 if WIN32_ERROR(error_code) == NO_ERROR {
284 let mut current_address =
285 ip_address_info.as_ptr() as *mut IP_ADAPTER_ADDRESSES_LH;
286
287 while !current_address.is_null() {
288 let current = unsafe { &*current_address };
289
290 if MacAddress::from_slice(¤t.PhysicalAddress).unwrap_or_default()
291 != *address
292 {
293 current_address = current.Next;
294 continue;
295 }
296
297 for i in 0..unsafe { (*mib_table).NumEntries } {
299 let table_ptr = unsafe { (*mib_table).Table.as_ptr() };
300 let entry_ptr = unsafe { table_ptr.add(i as usize) };
301 if IfLuid::from(unsafe { (*mib_table).Table[i as usize].InterfaceLuid })
302 == IfLuid::from(current.Luid)
303 {
304 let result =
305 unsafe { IphlpNetworkAdapterInfo::new(current, entry_ptr) };
306 unsafe { FreeMibTable(mib_table as *const core::ffi::c_void) };
307 return Some(result);
308 }
309 }
310
311 current_address = current.Next;
312 }
313
314 break;
315 }
316 if WIN32_ERROR(error_code) != ERROR_BUFFER_OVERFLOW {
318 unsafe { SetLastError(WIN32_ERROR(error_code)) };
319 break;
320 }
321 }
322 } else {
323 if WIN32_ERROR(error_code) != NO_ERROR {
325 unsafe { SetLastError(WIN32_ERROR(error_code)) };
326 }
327 }
328
329 unsafe { FreeMibTable(mib_table as *const core::ffi::c_void) };
331
332 None
333 }
334
335 pub fn get_connection_by_guid(guid: &str) -> Option<IphlpNetworkAdapterInfo> {
351 let mut dw_size = 0;
352 let mut mib_table: *mut MIB_IF_TABLE2 = std::ptr::null_mut();
353
354 if unsafe { GetIfTable2(&mut mib_table) }.is_err() {
356 return None;
357 }
358
359 let error_code = unsafe {
361 GetAdaptersAddresses(
362 AF_UNSPEC.0 as u32,
363 GAA_FLAG_SKIP_ANYCAST
364 | GAA_FLAG_SKIP_MULTICAST
365 | GAA_FLAG_INCLUDE_GATEWAYS
366 | GAA_FLAG_INCLUDE_ALL_INTERFACES,
367 None,
368 None,
369 &mut dw_size,
370 )
371 };
372
373 if WIN32_ERROR(error_code) == ERROR_BUFFER_OVERFLOW && dw_size != 0 {
374 loop {
375 let mut ip_address_info = vec![0u8; dw_size as usize];
376
377 let error_code = unsafe {
378 GetAdaptersAddresses(
379 AF_UNSPEC.0 as u32,
380 GAA_FLAG_SKIP_ANYCAST
381 | GAA_FLAG_SKIP_MULTICAST
382 | GAA_FLAG_INCLUDE_GATEWAYS
383 | GAA_FLAG_INCLUDE_ALL_INTERFACES,
384 None,
385 Some(ip_address_info.as_mut_ptr() as *mut IP_ADAPTER_ADDRESSES_LH),
386 &mut dw_size,
387 )
388 };
389
390 if WIN32_ERROR(error_code) == NO_ERROR {
391 let mut current_address =
392 ip_address_info.as_ptr() as *mut IP_ADAPTER_ADDRESSES_LH;
393
394 while !current_address.is_null() {
395 let current = unsafe { &*current_address };
396
397 let adapter_name = unsafe { current.AdapterName.to_string() }
398 .unwrap_or_default()
399 .to_uppercase();
400
401 if !adapter_name.contains(guid) {
402 current_address = current.Next;
403 continue;
404 }
405
406 for i in 0..unsafe { (*mib_table).NumEntries } {
408 let table_ptr = unsafe { (*mib_table).Table.as_ptr() };
409 let entry_ptr = unsafe { table_ptr.add(i as usize) };
410 if IfLuid::from(unsafe { (*mib_table).Table[i as usize].InterfaceLuid })
411 == IfLuid::from(current.Luid)
412 {
413 let result =
414 unsafe { IphlpNetworkAdapterInfo::new(current, entry_ptr) };
415 unsafe { FreeMibTable(mib_table as *const core::ffi::c_void) };
416 return Some(result);
417 }
418 }
419
420 current_address = current.Next;
421 }
422
423 break;
424 }
425 if WIN32_ERROR(error_code) != ERROR_BUFFER_OVERFLOW {
427 unsafe { SetLastError(WIN32_ERROR(error_code)) };
428 break;
429 }
430 }
431 } else {
432 if WIN32_ERROR(error_code) != NO_ERROR {
434 unsafe { SetLastError(WIN32_ERROR(error_code)) };
435 }
436 }
437
438 unsafe { FreeMibTable(mib_table as *const core::ffi::c_void) };
440
441 None
442 }
443}