ndisapi_rs/ndisapi/base_api.rs
1//! # Submodule: Basic NDISAPI functions
2//!
3//! This submodule provides a comprehensive set of functionalities for interacting with the Windows Packet Filter Kit,
4//! allowing users to perform various actions on network adapters within Windows operating systems.
5//! It includes methods for setting various adapter parameters, configuring packet filter modes,
6//! handling hardware packet filters, and managing events related to adapter list changes
7//! and WAN connections.
8
9use std::mem::{size_of, MaybeUninit};
10
11use windows::{
12 core::Result,
13 Win32::Foundation::{GetLastError, HANDLE},
14 Win32::System::IO::DeviceIoControl,
15};
16
17use super::Ndisapi;
18use crate::driver::*;
19use crate::ndisapi::defs::*;
20
21pub const OID_GEN_CURRENT_PACKET_FILTER: u32 = 0x0001010E;
22
23impl Ndisapi {
24 /// This method takes an adapter handle as an argument and returns a Result containing
25 /// the FilterFlags enum for the selected network interface. If an error occurs, the
26 /// GetLastError function is called to retrieve the error and is then converted into
27 /// a Result::Err variant.
28 ///
29 /// # Arguments
30 ///
31 /// * `adapter_handle` - A HANDLE representing the network interface for which the
32 /// packet filter mode should be queried.
33 ///
34 /// # Returns
35 ///
36 /// * `Result<FilterFlags>` - A Result containing the FilterFlags enum for the selected
37 /// network interface if the query was successful, or an error if it failed.
38 pub fn get_adapter_mode(&self, adapter_handle: HANDLE) -> Result<FilterFlags> {
39 let mut adapter_mode = AdapterMode {
40 adapter_handle,
41 ..Default::default()
42 };
43
44 let result = unsafe {
45 DeviceIoControl(
46 self.driver_handle,
47 IOCTL_NDISRD_GET_ADAPTER_MODE,
48 Some(&adapter_mode as *const AdapterMode as *const std::ffi::c_void),
49 size_of::<AdapterMode>() as u32,
50 Some(&mut adapter_mode as *mut AdapterMode as *mut std::ffi::c_void),
51 size_of::<AdapterMode>() as u32,
52 None,
53 None,
54 )
55 };
56
57 if !result.as_bool() {
58 Err(unsafe { GetLastError() }.into())
59 } else {
60 Ok(adapter_mode.flags)
61 }
62 }
63
64 /// This method takes an adapter handle as an argument and returns a Result containing
65 /// a u32 value representing the hardware packet filter for the specified network interface.
66 /// If an error occurs, it will be propagated as a Result::Err variant.
67 ///
68 /// # Arguments
69 ///
70 /// * `adapter_handle` - A HANDLE representing the network interface for which the
71 /// hardware packet filter should be queried.
72 ///
73 /// # Returns
74 ///
75 /// * `Result<u32>` - A Result containing a u32 value representing the hardware packet
76 /// filter for the specified network interface if the query was successful, or an error
77 /// if it failed.
78 pub fn get_hw_packet_filter(&self, adapter_handle: HANDLE) -> Result<u32> {
79 let mut oid = PacketOidData::new(adapter_handle, OID_GEN_CURRENT_PACKET_FILTER, 0u32);
80
81 self.ndis_get_request::<_>(&mut oid)?;
82
83 Ok(oid.data)
84 }
85
86 /// This method takes an adapter handle and a mutable reference to a RasLinks struct
87 /// as arguments. It queries the active WAN connections from the NDIS filter driver
88 /// and updates the `ras_links` argument with the received information. If an error
89 /// occurs, it will be propagated as a Result::Err variant.
90 ///
91 /// # Arguments
92 ///
93 /// * `adapter_handle` - A HANDLE representing the network interface for which the
94 /// active WAN connections should be queried.
95 /// * `ras_links` - A mutable reference to a RasLinks struct that will be updated
96 /// with the information about active WAN connections.
97 ///
98 /// # Returns
99 ///
100 /// * `Result<()>` - A Result containing an empty tuple if the query was successful,
101 /// or an error if it failed.
102 pub fn get_ras_links(&self, adapter_handle: HANDLE, ras_links: &mut RasLinks) -> Result<()> {
103 let result = unsafe {
104 DeviceIoControl(
105 self.driver_handle,
106 IOCTL_NDISRD_GET_RAS_LINKS,
107 Some(&adapter_handle as *const HANDLE as *const std::ffi::c_void),
108 size_of::<HANDLE>() as u32,
109 Some(ras_links as *const RasLinks as *mut std::ffi::c_void),
110 size_of::<RasLinks>() as u32,
111 None,
112 None,
113 )
114 };
115
116 if !result.as_bool() {
117 Err(unsafe { GetLastError() }.into())
118 } else {
119 Ok(())
120 }
121 }
122
123 /// This method retrieves information about network interfaces that available to NDIS filter driver.
124 /// It returns a Result containing a vector of NetworkAdapterInfo
125 /// structs, which contain detailed information about each network interface.
126 ///
127 /// # Returns
128 ///
129 /// * `Result<Vec<NetworkAdapterInfo>>` - A Result containing a vector of NetworkAdapterInfo
130 /// structs representing the available network interfaces if the query was successful,
131 /// or an error if it failed.
132 pub fn get_tcpip_bound_adapters_info(&self) -> Result<Vec<NetworkAdapterInfo>> {
133 let mut adapters: MaybeUninit<TcpAdapterList> = ::std::mem::MaybeUninit::uninit();
134
135 let result = unsafe {
136 DeviceIoControl(
137 self.driver_handle,
138 IOCTL_NDISRD_GET_TCPIP_INTERFACES,
139 None,
140 0,
141 Some(adapters.as_mut_ptr() as _),
142 size_of::<TcpAdapterList>() as u32,
143 None,
144 None,
145 )
146 };
147
148 if result.as_bool() {
149 let mut result = Vec::new();
150 let adapters = unsafe { adapters.assume_init() };
151
152 for i in 0..adapters.adapter_count as usize {
153 let adapter_name =
154 String::from_utf8(adapters.adapter_name_list[i].to_vec()).unwrap();
155 let adapter_name = adapter_name.trim_end_matches(char::from(0)).to_owned();
156 let next = NetworkAdapterInfo::new(
157 adapter_name,
158 adapters.adapter_handle[i],
159 adapters.adapter_medium_list[i],
160 adapters.current_address[i],
161 adapters.mtu[i],
162 );
163 result.push(next);
164 }
165 Ok(result)
166 } else {
167 Err(unsafe { GetLastError() }.into())
168 }
169 }
170
171 /// This method retrieves the version of the NDIS filter driver currently running on the
172 /// system. It returns a Result containing a Version struct with the major, minor, and
173 /// revision numbers of the driver version.
174 ///
175 /// # Returns
176 ///
177 /// * `Result<Version>` - A Result containing a Version struct representing the NDIS
178 /// filter driver version if the query was successful, or an error if it failed.
179 pub fn get_version(&self) -> Result<Version> {
180 let mut version = u32::MAX;
181
182 let result = unsafe {
183 DeviceIoControl(
184 self.driver_handle,
185 IOCTL_NDISRD_GET_VERSION,
186 Some(&mut version as *mut u32 as _),
187 size_of::<u32>() as u32,
188 Some(&mut version as *mut u32 as _),
189 size_of::<u32>() as u32,
190 None,
191 None,
192 )
193 };
194
195 if !result.as_bool() {
196 Err(unsafe { GetLastError() }.into())
197 } else {
198 Ok(Version {
199 major: (version & (0xF000)) >> 12,
200 minor: (version & (0xFF000000)) >> 24,
201 revision: (version & (0xFF0000)) >> 16,
202 })
203 }
204 }
205
206 /// This function is used to obtain various parameters of the network adapter, such as the
207 /// dimension of the internal buffers, the link speed, or the counter of corrupted packets.
208 /// The constants that define the operations are declared in the file `ntddndis.h`.
209 ///
210 /// # Type Parameters
211 ///
212 /// * `T`: The type of data to be queried from the network adapter.
213 ///
214 /// # Arguments
215 ///
216 /// * `oid_request`: A mutable reference to a `PacketOidData<T>` struct that specifies
217 /// the adapter handle and the operation to perform.
218 ///
219 /// # Returns
220 ///
221 /// * `Result<()>` - A Result indicating whether the query operation was successful or not.
222 /// On success, returns `Ok(())`. On failure, returns an error.
223 pub fn ndis_get_request<T>(&self, oid_request: &mut PacketOidData<T>) -> Result<()> {
224 let result = unsafe {
225 DeviceIoControl(
226 self.driver_handle,
227 IOCTL_NDISRD_NDIS_GET_REQUEST,
228 Some(oid_request as *const PacketOidData<T> as *const std::ffi::c_void),
229 size_of::<PacketOidData<T>>() as u32,
230 Some(oid_request as *const PacketOidData<T> as *mut std::ffi::c_void),
231 size_of::<PacketOidData<T>>() as u32,
232 None,
233 None,
234 )
235 };
236
237 if !result.as_bool() {
238 Err(unsafe { GetLastError() }.into())
239 } else {
240 Ok(())
241 }
242 }
243
244 /// This function is used to set various parameters of the network adapter, such as the
245 /// dimension of the internal buffers, the link speed, or the counter of corrupted packets.
246 /// The constants that define the operations are declared in the file `ntddndis.h`.
247 ///
248 /// # Type Parameters
249 ///
250 /// * `T`: The type of data to be set for the network adapter.
251 ///
252 /// # Arguments
253 ///
254 /// * `oid_request`: A reference to a `PacketOidData<T>` struct that specifies
255 /// the adapter handle and the operation to perform.
256 ///
257 /// # Returns
258 ///
259 /// * `Result<()>` - A Result indicating whether the set operation was successful or not.
260 /// On success, returns `Ok(())`. On failure, returns an error.
261 pub fn ndis_set_request<T>(&self, oid_request: &PacketOidData<T>) -> Result<()> {
262 let result = unsafe {
263 DeviceIoControl(
264 self.driver_handle,
265 IOCTL_NDISRD_NDIS_SET_REQUEST,
266 Some(oid_request as *const PacketOidData<T> as *const std::ffi::c_void),
267 size_of::<PacketOidData<T>>() as u32,
268 None,
269 0,
270 None,
271 None,
272 )
273 };
274
275 if !result.as_bool() {
276 Err(unsafe { GetLastError() }.into())
277 } else {
278 Ok(())
279 }
280 }
281
282 /// The user application should create a Win32 event (with the `CreateEvent` API call) and pass
283 /// the event handle to this function. The helper driver will signal this event when the
284 /// NDIS filter adapter's list changes, for example, when a network card is plugged/unplugged,
285 /// a network connection is disabled/enabled, or other similar events.
286 ///
287 /// # Arguments
288 ///
289 /// * `event_handle`: A `HANDLE` to a Win32 event created by the user application.
290 ///
291 /// # Returns
292 ///
293 /// * `Result<()>` - A Result indicating whether setting the event was successful or not.
294 /// On success, returns `Ok(())`. On failure, returns an error.
295 pub fn set_adapter_list_change_event(&self, event_handle: HANDLE) -> Result<()> {
296 let result = unsafe {
297 DeviceIoControl(
298 self.driver_handle,
299 IOCTL_NDISRD_SET_ADAPTER_EVENT,
300 Some(&event_handle as *const HANDLE as *const std::ffi::c_void),
301 size_of::<HANDLE>() as u32,
302 None,
303 0,
304 None,
305 None,
306 )
307 };
308
309 if !result.as_bool() {
310 Err(unsafe { GetLastError() }.into())
311 } else {
312 Ok(())
313 }
314 }
315
316 /// Sets the packet filter mode for the selected network interface.
317 ///
318 /// # Arguments
319 ///
320 /// * `adapter_handle`: A `HANDLE` to the network interface (obtained via call to `get_tcpip_bound_adapters_info`).
321 /// * `flags`: A `FilterFlags` value representing the combination of packet filter mode flags.
322 /// * `MSTCP_FLAG_SENT_TUNNEL` – Queue all packets sent from MSTCP to the network interface. Original packet dropped.
323 /// * `MSTCP_FLAG_RECV_TUNNEL` – Queue all packets indicated by the network interface to MSTCP. Original packet dropped.
324 /// * `MSTCP_FLAG_SENT_LISTEN` – Queue all packets sent from MSTCP to the network interface. Original packet goes ahead.
325 /// * `MSTCP_FLAG_RECV_LISTEN` – Queue all packets indicated by the network interface to MSTCP. Original packet goes ahead.
326 /// * `MSTCP_FLAG_FILTER_DIRECT` – In promiscuous mode, the TCP/IP stack receives all packets in the Ethernet segment and replies
327 /// with various ICMP packets. To prevent this, set this flag. All packets with destination MAC different from
328 /// FF-FF-FF-FF-FF-FF and the network interface's current MAC will never reach MSTCP.
329 ///
330 /// # Returns
331 ///
332 /// * `Result<()>` - A Result indicating whether setting the adapter mode was successful or not.
333 /// On success, returns `Ok(())`. On failure, returns an error.
334 pub fn set_adapter_mode(&self, adapter_handle: HANDLE, flags: FilterFlags) -> Result<()> {
335 let adapter_mode = AdapterMode {
336 adapter_handle,
337 flags,
338 };
339
340 let result = unsafe {
341 DeviceIoControl(
342 self.driver_handle,
343 IOCTL_NDISRD_SET_ADAPTER_MODE,
344 Some(&adapter_mode as *const AdapterMode as *const std::ffi::c_void),
345 size_of::<AdapterMode>() as u32,
346 None,
347 0,
348 None,
349 None,
350 )
351 };
352
353 if !result.as_bool() {
354 Err(unsafe { GetLastError() }.into())
355 } else {
356 Ok(())
357 }
358 }
359
360 /// This method allows setting the hardware packet filter mode for the specified network interface by calling
361 /// the `ndis_set_request` function.
362 ///
363 /// # Arguments
364 ///
365 /// * `adapter_handle`: A `HANDLE` to the network interface.
366 /// * `filter`: A `u32` value representing the packet filter mode.
367 ///
368 /// # Returns
369 ///
370 /// * `Result<()>` - A Result indicating whether setting the hardware packet filter was successful or not.
371 /// On success, returns `Ok(())`. On failure, returns an error.
372 pub fn set_hw_packet_filter(&self, adapter_handle: HANDLE, filter: u32) -> Result<()> {
373 let oid = PacketOidData::new(adapter_handle, OID_GEN_CURRENT_PACKET_FILTER, filter);
374
375 self.ndis_set_request::<_>(&oid)?;
376
377 Ok(())
378 }
379
380 /// This method allows setting a Win32 event that will be signaled by the filter driver when the hardware packet
381 /// filter for the network interface changes.
382 ///
383 /// # Arguments
384 ///
385 /// * `event_handle`: A `HANDLE` to the Win32 event created by the user application.
386 ///
387 /// # Returns
388 ///
389 /// * `Result<()>` - A Result indicating whether setting the hardware packet filter event was successful or not.
390 /// On success, returns `Ok(())`. On failure, returns an error.
391 pub fn set_hw_packet_filter_event(&self, event_handle: HANDLE) -> Result<()> {
392 let result = unsafe {
393 DeviceIoControl(
394 self.driver_handle,
395 IOCTL_NDISRD_SET_ADAPTER_HWFILTER_EVENT,
396 Some(&event_handle as *const HANDLE as *const std::ffi::c_void),
397 size_of::<HANDLE>() as u32,
398 None,
399 0,
400 None,
401 None,
402 )
403 };
404
405 if !result.as_bool() {
406 Err(unsafe { GetLastError() }.into())
407 } else {
408 Ok(())
409 }
410 }
411
412 /// This method allows setting a Win32 event that will be signaled by the filter driver when a WAN connection
413 /// (such as dial-up, DSL, ADSL, etc.) is established or terminated.
414 ///
415 /// # Arguments
416 ///
417 /// * `event_handle`: A `HANDLE` to the Win32 event created by the user application.
418 ///
419 /// # Returns
420 ///
421 /// * `Result<()>` - A Result indicating whether setting the WAN event was successful or not. On success,
422 /// returns `Ok(())`. On failure, returns an error.
423 pub fn set_wan_event(&self, event_handle: HANDLE) -> Result<()> {
424 let result = unsafe {
425 DeviceIoControl(
426 self.driver_handle,
427 IOCTL_NDISRD_SET_WAN_EVENT,
428 Some(&event_handle as *const HANDLE as *const std::ffi::c_void),
429 size_of::<HANDLE>() as u32,
430 None,
431 0,
432 None,
433 None,
434 )
435 };
436
437 if !result.as_bool() {
438 Err(unsafe { GetLastError() }.into())
439 } else {
440 Ok(())
441 }
442 }
443
444 /// Retrieves the effective size of the Windows Packet Filter internal intermediate buffer pool.
445 ///
446 /// # Returns
447 ///
448 /// * `Result<u32>` - If the operation is successful, returns `Ok(pool_size)` where `pool_size`
449 /// is the size of the intermediate buffer pool. Otherwise, returns an `Err` with the error code.
450 ///
451 /// This function retrieves the size of the intermediate buffer pool used by the driver.
452 /// It uses `DeviceIoControl` with the `IOCTL_NDISRD_QUERY_IB_POOL_SIZE` code to perform the operation.
453 pub fn get_intermediate_buffer_pool_size(&self) -> Result<u32> {
454 let mut pool_size: u32 = 0;
455
456 let result = unsafe {
457 DeviceIoControl(
458 self.driver_handle,
459 IOCTL_NDISRD_QUERY_IB_POOL_SIZE,
460 None,
461 0,
462 Some(&mut pool_size as *mut u32 as _),
463 size_of::<u32>() as u32,
464 None,
465 None,
466 )
467 };
468
469 if !result.as_bool() {
470 Err(unsafe { GetLastError() }.into())
471 } else {
472 Ok(pool_size)
473 }
474 }
475}