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}