1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
//! # Module: NDISAPI
//!
//! This module provides a high-level interface to the NDISAPI Rust library for communicating with the Windows Packet Filter driver.
//! It includes the definition and implementation of the `Ndisapi` struct, which represents the main entry point to interact with the driver.
//!
//! The NDISAPI module also contains submodules for various aspects of the NDISAPI functionality, such as:
//! - base_api: Basic API operations
//! - defs: Definitions of constants, structures, and enumerations
//! - fastio_api: Fast I/O operations
//! - filters_api: Filter management and manipulation
//! - io_api: Basic I/O operations
//! - static_api: Static and Registry related methods for the NDISAPI
//!
//! For a detailed description of each submodule and the `Ndisapi` struct, refer to their respective documentation within the module.

// Imports required dependencies
use windows::{
    core::{Result, PCWSTR},
    Win32::Foundation::CloseHandle,
    Win32::Foundation::{GetLastError, HANDLE},
    Win32::Storage::FileSystem::{
        CreateFileW, FILE_FLAG_OVERLAPPED, FILE_SHARE_READ, FILE_SHARE_WRITE, OPEN_EXISTING,
    },
};

// Submodules
mod base_api;
mod defs;
mod fastio_api;
mod filters_api;
mod io_api;
mod static_api;

// Re-exports the `driver` submodule
pub use crate::driver::*;

// Re-export already public members in `defs.rs`
pub use crate::ndisapi::defs::{NetworkAdapterInfo, Version};

/// The `Ndisapi` struct represents an instance of the NDIS filter driver that provides access to network adapters and packets.
///
/// This struct is used to communicate with the NDIS filter driver and access its functionalities. It contains a single field, `driver_handle`,
/// which represents a handle to the driver. This handle is used to perform operations such as reading and writing packets, setting filters, and
/// getting information about network adapters.
///
/// To use `Ndisapi`, you should first create an instance of the struct by calling the `Ndisapi::new()` function. This will return a `Result`
/// that contains an instance of `Ndisapi` if the operation was successful, or an error if it failed. Once you have an instance of `Ndisapi`,
/// you can call its methods to perform various network-related operations.
///
/// For example, you can use the `Ndisapi::read_packets()` method to read packets from the network adapter, or the `Ndisapi::send_packets_to_adapter()`
/// method to write packets to the network adapter. You can also use the `Ndisapi::set_packet_filter_table()` method to set a filter that specifies which
/// packets should be captured or dropped.
#[derive(Debug, Clone)]
pub struct Ndisapi {
    // Represents a handle to the NDIS filter driver.
    driver_handle: HANDLE,
    // Stores the driver registry key for parameters
    registry_key: Vec<u16>,
}

// Implements the Drop trait for the `Ndisapi` struct
impl Drop for Ndisapi {
    // Provides a custom implementation for the `drop` method
    fn drop(&mut self) {
        // Closes the driver_handle when the `Ndisapi` instance goes out of scope
        unsafe {
            CloseHandle(self.driver_handle);
        }
    }
}

// Implements additional methods for the `Ndisapi` struct
impl Ndisapi {
    /// Initializes new Ndisapi instance opening the NDIS filter driver
    ///
    /// # Arguments
    ///
    /// * `driver_name` - The name of the file representing the NDIS filter driver.
    ///
    /// # Returns
    ///
    /// * `Result<Self>` - A Result containing the Ndisapi instance if successful, or an error if not.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use ndisapi_rs::Ndisapi;
    /// let ndisapi = Ndisapi::new("NDISRD").unwrap();
    /// ```
    pub fn new(driver_name: &str) -> Result<Self> {
        // Create the filename and driver parameters registry path
        let filename = format!(r"\\.\{driver_name}");
        let registry_key = format!(r"SYSTEM\CurrentControlSet\Services\{driver_name}\Parameters");
        let mut filename: Vec<u16> = filename.encode_utf16().collect();
        let mut registry_key: Vec<u16> = registry_key.encode_utf16().collect();
        filename.push(0);
        registry_key.push(0);

        // Attempts to create a file handle for the NDIS filter driver
        if let Ok(driver_handle) = unsafe {
            CreateFileW(
                PCWSTR::from_raw(filename.as_ptr()),
                0u32,
                FILE_SHARE_READ | FILE_SHARE_WRITE,
                None,
                OPEN_EXISTING,
                FILE_FLAG_OVERLAPPED,
                None,
            )
        } {
            // Returns a new Ndisapi instance with the created handle if successful
            Ok(Self {
                driver_handle,
                registry_key,
            })
        } else {
            // Returns an error if the file handle creation fails
            Err(unsafe { GetLastError() }.into())
        }
    }

    pub fn get_driver_registry_key(&self) -> PCWSTR {
        PCWSTR::from_raw(self.registry_key.as_ptr())
    }
}