├── .github ├── pr-labeler.yml ├── release-drafter.yml └── workflows │ ├── build.yml │ └── publish.yml ├── .gitignore ├── Cargo.toml ├── LICENSE ├── README.md ├── examples ├── filter.rs ├── listadapters.rs ├── packthru.rs └── passthru.rs └── src ├── driver.rs ├── driver ├── base.rs ├── constants.rs ├── fastio.rs ├── filters.rs └── ioctl.rs ├── lib.rs ├── ndisapi.rs ├── ndisapi ├── base_api.rs ├── defs.rs ├── fastio_api.rs ├── filters_api.rs ├── io_api.rs └── static_api.rs └── net.rs /.github/pr-labeler.yml: -------------------------------------------------------------------------------- 1 | feature: ['feat/*', 'feature/*'] 2 | chore: ['chore/*'] 3 | bug: ['fix/*', 'bug/*'] 4 | build: ['build/*'] 5 | ci: ['ci/*'] 6 | docs: ['docs/*'] 7 | style: ['style/*'] 8 | refactor: ['refactor/*'] 9 | perf: ['perf/*'] 10 | test: ['test/*'] 11 | revert: ['revert/*'] 12 | -------------------------------------------------------------------------------- /.github/release-drafter.yml: -------------------------------------------------------------------------------- 1 | name-template: "$RESOLVED_VERSION" 2 | tag-template: "$RESOLVED_VERSION" 3 | categories: 4 | - title: "✨ Features" 5 | labels: 6 | - "feature" 7 | - "enhancement" 8 | - title: "🐛 Bug Fixes" 9 | labels: 10 | - "fix" 11 | - "bugfix" 12 | - "bug" 13 | - title: "🧰 Maintenance" 14 | label: 15 | - "chore" 16 | - "dependencies" 17 | - title: "📝 Documentation" 18 | label: "docs" 19 | exclude-labels: 20 | - "skip-changelog" 21 | change-template: "- $TITLE @$AUTHOR (#$NUMBER)" 22 | change-title-escapes: '\<*_&' # You can add # and @ to disable mentions, and add ` to disable code blocks. 23 | version-resolver: 24 | major: 25 | labels: 26 | - "major" 27 | minor: 28 | labels: 29 | - "minor" 30 | patch: 31 | labels: 32 | - "patch" 33 | default: patch 34 | template: | 35 | $CHANGES 36 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: 7 | - main 8 | 9 | env: 10 | RUSTFLAGS: -Dwarnings 11 | CARGO_NET_GIT_FETCH_WITH_CLI: true 12 | 13 | jobs: 14 | draft-release: 15 | runs-on: ubuntu-latest 16 | outputs: 17 | tag_name: ${{ steps.release_drafter.outputs.tag_name }} 18 | steps: 19 | - uses: release-drafter/release-drafter@v5 20 | id: release_drafter 21 | env: 22 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 23 | 24 | build: 25 | name: Build 26 | strategy: 27 | matrix: 28 | rust: [stable, nightly] 29 | runs-on: 30 | - windows-2019 31 | - windows-2022 32 | runs-on: ${{ matrix.runs-on }} 33 | steps: 34 | - name: Checkout 35 | uses: actions/checkout@v3 36 | - uses: actions/cache@v3 37 | with: 38 | path: | 39 | ~/.cargo/.crates.toml 40 | ~/.cargo/.crates2.json 41 | ~/.cargo/.package-cache 42 | ~/.cargo/bin/ 43 | ~/.cargo/registry/index/ 44 | ~/.cargo/registry/cache/ 45 | ~/.cargo/git/db/ 46 | target/ 47 | key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} 48 | - name: Setup toolchain 49 | run: | 50 | rustup update --no-self-update ${{ matrix.rust }} 51 | rustup default ${{ matrix.rust }} 52 | rustup component add clippy 53 | - name: Run cargo static analysis checks 54 | run: | 55 | cargo check 56 | cargo clippy -- -D clippy::all 57 | cargo test 58 | - name: Build crate 59 | run: | 60 | cargo publish --dry-run 61 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish crate 2 | 3 | on: 4 | release: 5 | types: [published] 6 | 7 | jobs: 8 | static-analysis: 9 | strategy: 10 | matrix: 11 | rust: [stable, nightly] 12 | runs-on: 13 | - windows-2019 14 | - windows-2022 15 | runs-on: ${{ matrix.runs-on }} 16 | steps: 17 | - name: Checkout 18 | uses: actions/checkout@v3 19 | - name: Update toolchain 20 | run: rustup update --no-self-update ${{ matrix.rust }} && rustup default ${{ matrix.rust }} && rustup component add clippy 21 | - name: Run cargo static analysis checks 22 | run: | 23 | cargo check 24 | cargo clippy --all-targets --all-features -- -D clippy::all 25 | cargo test 26 | 27 | publish: 28 | needs: static-analysis 29 | runs-on: ubuntu-latest 30 | steps: 31 | - name: Checkout 32 | uses: actions/checkout@v3 33 | - name: Update toolchain 34 | run: rustup update --no-self-update ${{ matrix.rust }} && rustup default ${{ matrix.rust }} && rustup component add clippy 35 | - name: Sanity check tag equals crate version 36 | run: | 37 | pkg_version=$(awk -F ' = ' '$1 ~ /version/ { gsub(/[\"]/, "", $2); printf("%s",$2); exit; }' Cargo.toml) 38 | if [[ "${{ github.ref_name }}" = "$pkg_version" ]]; then 39 | echo "Github ref ${{ github.ref_name }} equals from parsed package version $pkg_version. Continuing..." 40 | else 41 | echo "Github ref ${{ github.ref_name }} differs from parsed package version $pkg_version! Aborting..." 42 | exit 1 43 | fi 44 | - name: Publish to crates.io 45 | run: | 46 | cargo publish --token ${{ secrets.CARGO_REGISTRY_TOKEN }} 47 | 48 | 49 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 6 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 7 | Cargo.lock 8 | 9 | # These are backup files generated by rustfmt 10 | **/*.rs.bk 11 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ndisapi" 3 | version = "0.2.2" 4 | edition = "2021" 5 | authors = ["Vadim Smirnov "] 6 | description = "Windows Packet Filter API for Rust" 7 | license = "Apache-2.0" 8 | documentation = "https://docs.rs/ndisapi" 9 | repository = "https://github.com/firezone/ndisapi" 10 | readme = "README.md" 11 | 12 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 13 | 14 | [dependencies] 15 | bitflags = "2.1.0" 16 | 17 | [dependencies.windows] 18 | version = "0.48.0" 19 | features = [ 20 | "Win32_Foundation", 21 | "Win32_Security", 22 | "Win32_System_Registry", 23 | "Win32_System_Threading", 24 | "Win32_System_IO", 25 | "Win32_Storage_FileSystem", 26 | "Win32_Networking_WinSock", 27 | "Win32_System_SystemInformation", 28 | ] 29 | 30 | [dev-dependencies] 31 | etherparse = "0.13" 32 | clap = {version = "4.0.32", features = ["derive"]} 33 | ctrlc = "3.2.4" 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2023 Firezone, Inc. 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NDISAPI 2 | 3 | [![Crates.io](https://img.shields.io/crates/v/ndisapi.svg)](https://crates.io/crates/ndisapi) 4 | [![Documentation](https://docs.rs/ndisapi/badge.svg)](https://docs.rs/ndisapi) 5 | [![License](https://img.shields.io/crates/l/ndisapi)](https://github.com/firezone/ndisapi/blob/main/LICENSE) 6 | 7 | NDISAPI is a Rust crate for interacting with the [Windows Packet Filter](https://www.ntkernel.com/windows-packet-filter/) driver. It provides an easy-to-use, safe, and efficient interface to efficiently filter (inspect and modify) raw network packets at the NDIS level of the network stack with minimal impact on network activity. 8 | 9 | Windows Packet Filter (WinpkFilter) is a high-performance, lightweight packet filtering framework for Windows, enabling developers to efficiently inspect, modify, and control raw network packets at the NDIS level. With user-friendly APIs and support for various Windows versions, WinpkFilter simplifies network packet manipulation without requiring kernel-mode programming expertise. 10 | 11 | ## Features 12 | 13 | - Enumerate network adapters 14 | - Query and set network adapter properties 15 | - Capture and analyze packets 16 | - Filter and modify packets 17 | - Send raw packets 18 | 19 | ## Dependencies 20 | 21 | - Rust 1.58.0 or later 22 | - Windows 7, 8, 10, or 11 23 | - [Windows Packet Filter](https://github.com/wiresock/ndisapi/releases) driver installed 24 | 25 | ## Installation 26 | 27 | Add the following to your `Cargo.toml` file: 28 | 29 | ```toml 30 | [dependencies] 31 | ndisapi = "0.2.0" 32 | ``` 33 | 34 | ## Usage 35 | 36 | Here's an example of how to enumerate network adapters and print their information: 37 | 38 | ```rust 39 | use ndisapi::{MacAddress, Ndisapi}; 40 | 41 | fn main() { 42 | let ndis = Ndisapi::new("NDISRD").expect("Failed to create NdisApi instance"); 43 | 44 | let adapters = ndis 45 | .get_tcpip_bound_adapters_info() 46 | .expect("Failed to enumerate adapters"); 47 | 48 | for adapter in adapters { 49 | println!("Adapter: {:?}", adapter.get_name()); 50 | println!( 51 | "Description: {:?}", 52 | Ndisapi::get_friendly_adapter_name(adapter.get_name()).unwrap_or("Unknown".to_string()) 53 | ); 54 | println!( 55 | "MAC Address: {:?}", 56 | MacAddress::from_slice(adapter.get_hw_address()).unwrap_or_default() 57 | ); 58 | println!("-------------------------------"); 59 | } 60 | } 61 | ``` 62 | 63 | For more examples and in-depth usage, check out the [documentation](https://docs.rs/ndisapi). 64 | 65 | ## License 66 | 67 | This project is licensed under the Apache License 2.0. See [LICENSE](https://github.com/firezone/ndisapi/blob/main/LICENSE) for details. 68 | 69 | -------------------------------------------------------------------------------- /examples/listadapters.rs: -------------------------------------------------------------------------------- 1 | /// This example demonstrates the basic usage of the `Ndisapi` object, `Ndisapi::get_tcpip_bound_adapters_info`, 2 | /// adapter name conversion functions, and `Ndisapi::get_mtu_decrement` and etc.. It retrieves information about the 3 | /// network interfaces, including their indexes, which can be passed to the `packthru` and `passthru` 4 | /// examples. The collected information is dumped to the console screen. 5 | use std::{ 6 | mem::{self, size_of}, 7 | ptr::write_bytes, 8 | }; 9 | 10 | use ndisapi::{MacAddress, Ndisapi}; 11 | use windows::core::Result; 12 | 13 | const OID_802_3_CURRENT_ADDRESS: u32 = 0x01010102; 14 | 15 | fn main() -> Result<()> { 16 | let driver = ndisapi::Ndisapi::new("NDISRD") 17 | .expect("WinpkFilter driver is not installed or failed to load!"); 18 | 19 | println!( 20 | "Detected Windows Packet Filter version {}", 21 | driver.get_version()? 22 | ); 23 | 24 | let adapters = driver.get_tcpip_bound_adapters_info()?; 25 | 26 | for (index, adapter) in adapters.iter().enumerate() { 27 | // Display the information about each network interface provided by the get_tcpip_bound_adapters_info 28 | let network_interface_name = Ndisapi::get_friendly_adapter_name(adapter.get_name()) 29 | .expect("Unkown network interface"); 30 | println!( 31 | "{}. {}\n\t{}", 32 | index + 1, 33 | network_interface_name, 34 | adapter.get_name(), 35 | ); 36 | println!("\t Medium: {}", adapter.get_medium()); 37 | println!( 38 | "\t MAC: {}", 39 | MacAddress::from_slice(adapter.get_hw_address()).unwrap_or_default() 40 | ); 41 | println!("\t MTU: {}", adapter.get_mtu()); 42 | println!( 43 | "\t FilterFlags: {:?}", 44 | driver.get_adapter_mode(adapter.get_handle()).unwrap() 45 | ); 46 | 47 | // Query hardware packet filter for the adapter using built wrapper for ndis_get_request 48 | match driver.get_hw_packet_filter(adapter.get_handle()) { 49 | Err(err) => println!( 50 | "Getting OID_GEN_CURRENT_PACKET_FILTER Error: {}", 51 | err.message().to_string_lossy() 52 | ), 53 | Ok(current_packet_filter) => { 54 | println!("\t OID_GEN_CURRENT_PACKET_FILTER: 0x{current_packet_filter:08X}") 55 | } 56 | } 57 | 58 | // Query MAC address of the network adapter using ndis_get_request directly 59 | let mut current_address_request = ndisapi::PacketOidData::new( 60 | adapter.get_handle(), 61 | OID_802_3_CURRENT_ADDRESS, 62 | ndisapi::MacAddress::default(), 63 | ); 64 | if let Err(err) = driver.ndis_get_request::<_>(&mut current_address_request) { 65 | println!( 66 | "Getting OID_802_3_CURRENT_ADDRESS Error: {}", 67 | err.message().to_string_lossy() 68 | ) 69 | } else { 70 | println!( 71 | "\t OID_802_3_CURRENT_ADDRESS: {}", 72 | current_address_request.data 73 | ) 74 | } 75 | 76 | if Ndisapi::is_ndiswan_ip(adapter.get_name()) 77 | || Ndisapi::is_ndiswan_ipv6(adapter.get_name()) 78 | { 79 | let mut ras_links_vec: Vec = Vec::with_capacity(1); 80 | // SAFETY: ndisapi::RasLinks is too large to allocate memory on the stack and results in a stackoverflow error 81 | // Here is the workaround get a raw pointer to the vector with capacity to hold one ndisapi::RasLinks structure, 82 | // zero initialize the vector allocated memory and then set a vector length to one 83 | unsafe { 84 | write_bytes::( 85 | mem::transmute(ras_links_vec.as_mut_ptr()), 86 | 0, 87 | size_of::(), 88 | ); 89 | ras_links_vec.set_len(1) 90 | }; 91 | let ras_links = &mut ras_links_vec[0]; 92 | 93 | if let Ok(()) = driver.get_ras_links(adapter.get_handle(), ras_links) { 94 | println!( 95 | "Number of active WAN links: {}", 96 | ras_links.get_number_of_links() 97 | ); 98 | 99 | for k in 0..ras_links.get_number_of_links() { 100 | println!( 101 | "\t{}) LinkSpeed = {} MTU = {}", 102 | k, 103 | ras_links.ras_links[k].get_link_speed(), 104 | ras_links.ras_links[k].get_maximum_total_size() 105 | ); 106 | 107 | let local_mac_address = 108 | MacAddress::from_slice(ras_links.ras_links[k].get_local_address()).unwrap(); 109 | let remote_mac_address = 110 | MacAddress::from_slice(ras_links.ras_links[k].get_remote_address()) 111 | .unwrap(); 112 | 113 | println!("\t\tLocal MAC:\t {local_mac_address}"); 114 | 115 | println!("\t\tRemote MAC:\t {remote_mac_address}"); 116 | 117 | if Ndisapi::is_ndiswan_ip(adapter.get_name()) { 118 | // Windows Vista and later offsets are used 119 | println!( 120 | "\t\tIP address:\t {}.{}.{}.{} mask {}.{}.{}.{}", 121 | ras_links.ras_links[k].get_protocol_buffer()[584], 122 | ras_links.ras_links[k].get_protocol_buffer()[585], 123 | ras_links.ras_links[k].get_protocol_buffer()[586], 124 | ras_links.ras_links[k].get_protocol_buffer()[587], 125 | ras_links.ras_links[k].get_protocol_buffer()[588], 126 | ras_links.ras_links[k].get_protocol_buffer()[589], 127 | ras_links.ras_links[k].get_protocol_buffer()[590], 128 | ras_links.ras_links[k].get_protocol_buffer()[591], 129 | ); 130 | } else { 131 | // IP v.6 132 | println!( 133 | "\t\tIPv6 address (without prefix):\t {:02X}{:02X}:{:02X}{:02X}:{:02X}{:02X}:{:02X}{:02X}", 134 | ras_links.ras_links[k].get_protocol_buffer()[588], 135 | ras_links.ras_links[k].get_protocol_buffer()[589], 136 | ras_links.ras_links[k].get_protocol_buffer()[590], 137 | ras_links.ras_links[k].get_protocol_buffer()[591], 138 | ras_links.ras_links[k].get_protocol_buffer()[592], 139 | ras_links.ras_links[k].get_protocol_buffer()[593], 140 | ras_links.ras_links[k].get_protocol_buffer()[594], 141 | ras_links.ras_links[k].get_protocol_buffer()[595], 142 | ); 143 | } 144 | } 145 | } else { 146 | println!("Failed to query active WAN links information."); 147 | } 148 | } 149 | } 150 | 151 | let mtu_decrement = driver.get_mtu_decrement().unwrap_or(0); 152 | 153 | println!("\nSystem wide MTU decrement: {mtu_decrement}"); 154 | 155 | let startup_mode = driver.get_adapters_startup_mode().unwrap_or(0); 156 | 157 | println!("\nSystem wide network adapter startup filter mode: {startup_mode}"); 158 | 159 | let pool_size = driver.get_pool_size().unwrap_or(0); 160 | 161 | println!("\nDriver intermediate buffer pool size multiplier: {pool_size}"); 162 | 163 | let effective_pool_size = driver.get_intermediate_buffer_pool_size().unwrap_or(0); 164 | 165 | println!("\nEffective intermediate buffer pool size: {effective_pool_size}"); 166 | 167 | Ok(()) 168 | } 169 | -------------------------------------------------------------------------------- /examples/packthru.rs: -------------------------------------------------------------------------------- 1 | /// This example demonstrates the fundamental usage of active filtering modes in packet processing. By selecting a 2 | /// network interface and configuring it to operate in a filtering mode, both sent and received packets are queued. 3 | /// The example registers a Win32 event through the `Ndisapi::set_packet_event` function and enters a waiting state 4 | /// for incoming packets. As packets are received, their content is decoded and printed on the console screen, offering 5 | /// a real-time visualization of network traffic. This example resembles the `passthru` utility but employs bulk 6 | /// packet sending and receiving to optimize performance. 7 | use clap::Parser; 8 | use etherparse::{InternetSlice::*, LinkSlice::*, TransportSlice::*, *}; 9 | use windows::{ 10 | core::Result, 11 | Win32::Foundation::HANDLE, 12 | Win32::System::Threading::{CreateEventW, WaitForSingleObject}, 13 | }; 14 | 15 | #[derive(Parser)] 16 | struct Cli { 17 | /// Network interface index (please use listadapters example to determine the right one) 18 | #[clap(short, long)] 19 | interface_index: usize, 20 | /// Number of packets to read from the specified network interface 21 | #[clap(short, long)] 22 | packets_number: usize, 23 | } 24 | 25 | const PACKET_NUMBER: usize = 256; 26 | 27 | fn main() -> Result<()> { 28 | // Parse command line arguments. 29 | let Cli { 30 | mut interface_index, 31 | mut packets_number, 32 | } = Cli::parse(); 33 | 34 | // Decrement the interface index since it's zero-based. 35 | interface_index -= 1; 36 | 37 | // Initialize the NDISAPI driver. 38 | let driver = ndisapi::Ndisapi::new("NDISRD") 39 | .expect("WinpkFilter driver is not installed or failed to load!"); 40 | 41 | // Print the detected Windows Packet Filter version. 42 | println!( 43 | "Detected Windows Packet Filter version {}", 44 | driver.get_version()? 45 | ); 46 | 47 | // Get a list of TCP/IP bound adapters. 48 | let adapters = driver.get_tcpip_bound_adapters_info()?; 49 | 50 | // Validate the user-specified interface index. 51 | if interface_index + 1 > adapters.len() { 52 | panic!("Interface index is beyond the number of available interfaces"); 53 | } 54 | 55 | // Print the selected interface and number of packets to process. 56 | println!( 57 | "Using interface {} with {} packets", 58 | adapters[interface_index].get_name(), 59 | packets_number 60 | ); 61 | 62 | // Create a Win32 event. 63 | let event: HANDLE = unsafe { CreateEventW(None, true, false, None)? }; 64 | 65 | // Set the event within the driver. 66 | driver.set_packet_event(adapters[interface_index].get_handle(), event)?; 67 | 68 | // Put the network interface into tunnel mode. 69 | driver.set_adapter_mode( 70 | adapters[interface_index].get_handle(), 71 | ndisapi::FilterFlags::MSTCP_FLAG_SENT_RECEIVE_TUNNEL, 72 | )?; 73 | 74 | // Initialize a container to store IntermediateBuffers allocated on the heap. 75 | let mut ibs: Vec = vec![Default::default(); PACKET_NUMBER]; 76 | 77 | // Initialize containers to read/write IntermediateBuffers from/to the driver. 78 | let mut to_read = ndisapi::EthMRequest::new(adapters[interface_index].get_handle()); 79 | let mut to_mstcp: ndisapi::EthMRequest = 80 | ndisapi::EthMRequest::new(adapters[interface_index].get_handle()); 81 | let mut to_adapter: ndisapi::EthMRequest = 82 | ndisapi::EthMRequest::new(adapters[interface_index].get_handle()); 83 | 84 | // Initialize the read EthMRequest object. 85 | for ib in &mut ibs { 86 | to_read.push(ndisapi::EthPacket { 87 | buffer: ib as *mut _, 88 | })?; 89 | } 90 | 91 | // Main loop: Process packets until the specified number of packets is reached. 92 | while packets_number > 0 { 93 | // Wait for the event to be signaled. 94 | unsafe { 95 | WaitForSingleObject(event, u32::MAX); 96 | } 97 | 98 | // Read packets from the driver. 99 | let mut packets_read: usize; 100 | while { 101 | packets_read = 102 | unsafe { driver.read_packets::(&mut to_read) }.unwrap_or(0usize); 103 | packets_read > 0 104 | } { 105 | // Decrement the packets counter. 106 | packets_number = packets_number.saturating_sub(packets_read); 107 | 108 | // Process each packet. 109 | for i in 0..packets_read { 110 | let mut eth = to_read.at(i).unwrap(); 111 | let packet = unsafe { eth.get_buffer_mut() }; 112 | 113 | // Print packet direction and remaining packets. 114 | if packet.get_device_flags() == ndisapi::DirectionFlags::PACKET_FLAG_ON_SEND { 115 | println!( 116 | "\nMSTCP --> Interface ({} bytes) remaining packets {}\n", 117 | packet.get_length(), 118 | packets_number + (packets_read - i) 119 | ); 120 | } else { 121 | println!( 122 | "\nInterface --> MSTCP ({} bytes) remaining packets {}\n", 123 | packet.get_length(), 124 | packets_number + (packets_read - i) 125 | ); 126 | } 127 | 128 | // Print packet information 129 | print_packet_info(packet); 130 | 131 | if packet.get_device_flags() == ndisapi::DirectionFlags::PACKET_FLAG_ON_SEND { 132 | to_adapter.push(eth)?; 133 | } else { 134 | to_mstcp.push(eth)?; 135 | } 136 | } 137 | 138 | // Re-inject packets back into the network stack 139 | if to_adapter.get_packet_number() > 0 { 140 | match unsafe { driver.send_packets_to_adapter::(&to_adapter) } { 141 | Ok(_) => {} 142 | Err(err) => println!("Error sending packet to adapter. Error code = {err}"), 143 | } 144 | to_adapter.reset(); 145 | } 146 | 147 | if !to_mstcp.get_packet_number() > 0 { 148 | match unsafe { driver.send_packets_to_mstcp::(&to_mstcp) } { 149 | Ok(_) => {} 150 | Err(err) => println!("Error sending packet to mstcp. Error code = {err}"), 151 | }; 152 | to_mstcp.reset(); 153 | } 154 | 155 | if packets_number == 0 { 156 | println!("Filtering complete\n"); 157 | break; 158 | } 159 | } 160 | } 161 | 162 | Ok(()) 163 | } 164 | 165 | /// Print detailed information about a network packet. 166 | /// 167 | /// This function takes an `IntermediateBuffer` containing a network packet and prints various 168 | /// details about the packet, such as Ethernet, IPv4, IPv6, ICMPv4, ICMPv6, UDP, and TCP information. 169 | /// 170 | /// # Arguments 171 | /// 172 | /// * `packet` - A mutable reference to an `ndisapi::IntermediateBuffer` containing the network packet. 173 | /// 174 | /// # Examples 175 | /// 176 | /// ```no_run 177 | /// let mut packet: ndisapi::IntermediateBuffer = ...; 178 | /// print_packet_info(&mut packet); 179 | /// ``` 180 | fn print_packet_info(packet: &mut ndisapi::IntermediateBuffer) { 181 | // Attempt to create a SlicedPacket from the Ethernet frame. 182 | match SlicedPacket::from_ethernet(&packet.buffer.0) { 183 | // If there's an error, print it. 184 | Err(value) => println!("Err {value:?}"), 185 | 186 | // If successful, proceed with printing packet information. 187 | Ok(value) => { 188 | // Print Ethernet information if available. 189 | if let Some(Ethernet2(value)) = value.link { 190 | println!( 191 | " Ethernet {} => {}", 192 | ndisapi::MacAddress::from_slice(&value.source()[..]).unwrap(), 193 | ndisapi::MacAddress::from_slice(&value.destination()[..]).unwrap(), 194 | ); 195 | } 196 | 197 | // Print IP information if available. 198 | match value.ip { 199 | Some(Ipv4(value, extensions)) => { 200 | println!( 201 | " Ipv4 {:?} => {:?}", 202 | value.source_addr(), 203 | value.destination_addr() 204 | ); 205 | if !extensions.is_empty() { 206 | println!(" {extensions:?}"); 207 | } 208 | } 209 | Some(Ipv6(value, extensions)) => { 210 | println!( 211 | " Ipv6 {:?} => {:?}", 212 | value.source_addr(), 213 | value.destination_addr() 214 | ); 215 | if !extensions.is_empty() { 216 | println!(" {extensions:?}"); 217 | } 218 | } 219 | None => {} 220 | } 221 | 222 | // Print transport layer information if available. 223 | match value.transport { 224 | Some(Icmpv4(value)) => println!(" Icmpv4 {value:?}"), 225 | Some(Icmpv6(value)) => println!(" Icmpv6 {value:?}"), 226 | Some(Udp(value)) => println!( 227 | " UDP {:?} -> {:?}", 228 | value.source_port(), 229 | value.destination_port() 230 | ), 231 | Some(Tcp(value)) => { 232 | println!( 233 | " TCP {:?} -> {:?}", 234 | value.source_port(), 235 | value.destination_port() 236 | ); 237 | } 238 | Some(Unknown(ip_protocol)) => { 239 | println!(" Unknown Protocol (ip protocol number {ip_protocol:?})") 240 | } 241 | None => {} 242 | } 243 | } 244 | } 245 | } 246 | -------------------------------------------------------------------------------- /examples/passthru.rs: -------------------------------------------------------------------------------- 1 | /// This example demonstrates the essential usage of active filtering modes for packet processing. It selects a 2 | /// network interface and sets it into a filtering mode, where both sent and received packets are queued. The example 3 | /// registers a Win32 event using the `Ndisapi::set_packet_event` function, and enters a waiting state for incoming packets. 4 | /// Upon receiving a packet, its content is decoded and displayed on the console screen, providing a real-time view of 5 | /// the network traffic. 6 | use clap::Parser; 7 | use etherparse::{InternetSlice::*, LinkSlice::*, TransportSlice::*, *}; 8 | use windows::{ 9 | core::Result, 10 | Win32::Foundation::HANDLE, 11 | Win32::System::Threading::{CreateEventW, WaitForSingleObject}, 12 | }; 13 | 14 | #[derive(Parser)] 15 | struct Cli { 16 | /// Network interface index (please use listadapters example to determine the right one) 17 | #[clap(short, long)] 18 | interface_index: usize, 19 | /// Number of packets to read from the specified network interface 20 | #[clap(short, long)] 21 | packets_number: usize, 22 | } 23 | 24 | fn main() -> Result<()> { 25 | let Cli { 26 | mut interface_index, 27 | mut packets_number, 28 | } = Cli::parse(); 29 | 30 | interface_index -= 1; 31 | 32 | let driver = ndisapi::Ndisapi::new("NDISRD") 33 | .expect("WinpkFilter driver is not installed or failed to load!"); 34 | 35 | println!( 36 | "Detected Windows Packet Filter version {}", 37 | driver.get_version()? 38 | ); 39 | 40 | let adapters = driver.get_tcpip_bound_adapters_info()?; 41 | 42 | if interface_index + 1 > adapters.len() { 43 | panic!("Interface index is beoynd the number of available interfaces"); 44 | } 45 | 46 | println!( 47 | "Using interface {} with {} packets", 48 | adapters[interface_index].get_name(), 49 | packets_number 50 | ); 51 | 52 | // Create Win32 event 53 | let event: HANDLE; 54 | unsafe { 55 | event = CreateEventW(None, true, false, None)?; 56 | } 57 | 58 | // Set the event within the driver 59 | driver.set_packet_event(adapters[interface_index].get_handle(), event)?; 60 | 61 | // Put network interface into the tunnel mode 62 | driver.set_adapter_mode( 63 | adapters[interface_index].get_handle(), 64 | ndisapi::FilterFlags::MSTCP_FLAG_SENT_RECEIVE_TUNNEL, 65 | )?; 66 | 67 | // Allocate single IntermediateBuffer on the stack 68 | let mut ib = ndisapi::IntermediateBuffer::default(); 69 | 70 | // Initialize EthPacket to pass to driver API 71 | let mut packet = ndisapi::EthRequest { 72 | adapter_handle: adapters[interface_index].get_handle(), 73 | packet: ndisapi::EthPacket { 74 | buffer: &mut ib as *mut ndisapi::IntermediateBuffer, 75 | }, 76 | }; 77 | 78 | while packets_number > 0 { 79 | unsafe { 80 | WaitForSingleObject(event, u32::MAX); 81 | } 82 | while unsafe { driver.read_packet(&mut packet) }.ok().is_some() { 83 | // Print packet information 84 | if ib.get_device_flags() == ndisapi::DirectionFlags::PACKET_FLAG_ON_SEND { 85 | println!( 86 | "\nMSTCP --> Interface ({} bytes) remaining packets {}\n", 87 | ib.get_length(), 88 | packets_number 89 | ); 90 | } else { 91 | println!( 92 | "\nInterface --> MSTCP ({} bytes) remaining packets {}\n", 93 | ib.get_length(), 94 | packets_number 95 | ); 96 | } 97 | 98 | // Decrement packets counter 99 | packets_number -= 1; 100 | 101 | // Print some informations about the sliced packet 102 | print_packet_info(&mut ib); 103 | 104 | // Re-inject the packet back into the network stack 105 | if ib.get_device_flags() == ndisapi::DirectionFlags::PACKET_FLAG_ON_SEND { 106 | match unsafe { driver.send_packet_to_adapter(&packet) } { 107 | Ok(_) => {} 108 | Err(err) => println!("Error sending packet to adapter. Error code = {err}"), 109 | }; 110 | } else { 111 | match unsafe { driver.send_packet_to_mstcp(&packet) } { 112 | Ok(_) => {} 113 | Err(err) => println!("Error sending packet to mstcp. Error code = {err}"), 114 | } 115 | } 116 | 117 | if packets_number == 0 { 118 | println!("Filtering complete\n"); 119 | break; 120 | } 121 | } 122 | } 123 | 124 | Ok(()) 125 | } 126 | 127 | /// Print detailed information about a network packet. 128 | /// 129 | /// This function takes an `IntermediateBuffer` containing a network packet and prints various 130 | /// details about the packet, such as Ethernet, IPv4, IPv6, ICMPv4, ICMPv6, UDP, and TCP information. 131 | /// 132 | /// # Arguments 133 | /// 134 | /// * `packet` - A mutable reference to an `ndisapi::IntermediateBuffer` containing the network packet. 135 | /// 136 | /// # Examples 137 | /// 138 | /// ```no_run 139 | /// let mut packet: ndisapi::IntermediateBuffer = ...; 140 | /// print_packet_info(&mut packet); 141 | /// ``` 142 | fn print_packet_info(packet: &mut ndisapi::IntermediateBuffer) { 143 | // Attempt to create a SlicedPacket from the Ethernet frame. 144 | match SlicedPacket::from_ethernet(&packet.buffer.0) { 145 | // If there's an error, print it. 146 | Err(value) => println!("Err {value:?}"), 147 | 148 | // If successful, proceed with printing packet information. 149 | Ok(value) => { 150 | // Print Ethernet information if available. 151 | if let Some(Ethernet2(value)) = value.link { 152 | println!( 153 | " Ethernet {} => {}", 154 | ndisapi::MacAddress::from_slice(&value.source()[..]).unwrap(), 155 | ndisapi::MacAddress::from_slice(&value.destination()[..]).unwrap(), 156 | ); 157 | } 158 | 159 | // Print IP information if available. 160 | match value.ip { 161 | Some(Ipv4(value, extensions)) => { 162 | println!( 163 | " Ipv4 {:?} => {:?}", 164 | value.source_addr(), 165 | value.destination_addr() 166 | ); 167 | if !extensions.is_empty() { 168 | println!(" {extensions:?}"); 169 | } 170 | } 171 | Some(Ipv6(value, extensions)) => { 172 | println!( 173 | " Ipv6 {:?} => {:?}", 174 | value.source_addr(), 175 | value.destination_addr() 176 | ); 177 | if !extensions.is_empty() { 178 | println!(" {extensions:?}"); 179 | } 180 | } 181 | None => {} 182 | } 183 | 184 | // Print transport layer information if available. 185 | match value.transport { 186 | Some(Icmpv4(value)) => println!(" Icmpv4 {value:?}"), 187 | Some(Icmpv6(value)) => println!(" Icmpv6 {value:?}"), 188 | Some(Udp(value)) => println!( 189 | " UDP {:?} -> {:?}", 190 | value.source_port(), 191 | value.destination_port() 192 | ), 193 | Some(Tcp(value)) => { 194 | println!( 195 | " TCP {:?} -> {:?}", 196 | value.source_port(), 197 | value.destination_port() 198 | ); 199 | } 200 | Some(Unknown(ip_protocol)) => { 201 | println!(" Unknown Protocol (ip protocol number {ip_protocol:?})") 202 | } 203 | None => {} 204 | } 205 | } 206 | } 207 | } 208 | -------------------------------------------------------------------------------- /src/driver.rs: -------------------------------------------------------------------------------- 1 | //! # Module: DRIVER 2 | //! 3 | //! This module provides a low-level interface used by NDISAPI module for communicating 4 | //! with the Windows Packet Filter driver. 5 | //! 6 | //! The submodules in this module contain various structures, functions, and constants 7 | //! required to communicate with the driver and perform operations such as setting packet filters, 8 | //! reading packets, and sending packets to the adapter or MSTCP stack. 9 | //! 10 | //! # Submodules 11 | //! 12 | //! * [`constants`] - Provides various constants and bitflag structures used to configure the 13 | //! packet filtering mechanism, specify filtering options for different protocols, and define 14 | //! the conditions for filtering at specific layers. 15 | //! 16 | //! * [`base`] - Provides Rust equivalents of several structures used in the NDISAPI Rust library 17 | //! for communicating with the Windows Packet Filter driver. he structures in this submodule are related 18 | //! to network adapters, Ethernet packets, adapter events, and Remote Access Service (RAS) links. 19 | //! 20 | //! * [`ioctl`] - Provides a collection of constants for IOCTL (Input/Output Control) codes and 21 | //! the `ctl_code` function used to generate these codes. IOCTL codes are used to communicate 22 | //! with the Windows Packet Filter driver to perform various operations. 23 | //! 24 | //! * [`filters`] - Provides structures for specifying filter conditions and actions for various protocols, 25 | //! including Ethernet 802.3, IPv4, IPv6, TCP, UDP, and ICMP. These structures allow users to define complex 26 | //! filtering rules based on multiple packet fields and layers. 27 | //! 28 | //! * [`fastio`] - Provides Rust equivalents of several structures related to Fast I/O operations 29 | //! for the NDISAPI Rust library used in communicating with the Windows Packet Filter driver. 30 | //! The structures in this submodule are related to Fast I/O sections, which include headers and packet data, 31 | //! and are involved in read and write operations. 32 | //! 33 | 34 | // Submodules 35 | pub mod base; 36 | pub mod constants; 37 | pub mod fastio; 38 | pub mod filters; 39 | pub mod ioctl; 40 | 41 | pub use self::base::*; 42 | pub use self::constants::*; 43 | pub use self::fastio::*; 44 | pub use self::filters::*; 45 | pub use self::ioctl::*; 46 | -------------------------------------------------------------------------------- /src/driver/base.rs: -------------------------------------------------------------------------------- 1 | //! # Submodule: Basic NDISAPI Structures 2 | //! 3 | //! This submodule provides Rust equivalents of several structures used in the NDISAPI Rust library 4 | //! for communicating with the Windows Packet Filter driver. 5 | //! 6 | //! The structures in this submodule are related to network adapters, Ethernet packets, adapter events, 7 | //! and Remote Access Service (RAS) links. 8 | //! 9 | //! For a detailed description of each structure, refer to their respective documentation within the 10 | //! submodule. 11 | 12 | // Import required external crates and types 13 | use std::mem::size_of; 14 | use windows::{ 15 | core::Result, 16 | Win32::Foundation::{ERROR_INVALID_PARAMETER, HANDLE}, 17 | }; 18 | 19 | use super::constants::*; 20 | 21 | /// The `TcpAdapterList` structure is the Rust equivalent of the 22 | /// [_TCP_AdapterList](https://www.ntkernel.com/docs/windows-packet-filter-documentation/structures/_tcp_adapterlist/) 23 | /// structure in the Windows Packet Filter documentation. It represents a list of network adapters, 24 | /// along with their properties, such as adapter names, handles, medium types, current addresses, and MTUs. 25 | /// 26 | /// # Fields 27 | /// 28 | /// * `adapter_count`: A 32-bit unsigned integer representing the total number of adapters in the list. 29 | /// * `adapter_name_list`: An array of arrays, with each inner array containing `ADAPTER_NAME_SIZE` bytes, 30 | /// representing the adapter names in the list. 31 | /// * `adapter_handle`: An array of `HANDLE` values, representing the handles of the adapters in the list. 32 | /// * `adapter_medium_list`: An array of 32-bit unsigned integers, representing the medium types of the 33 | /// adapters in the list. 34 | /// * `current_address`: An array of arrays, with each inner array containing `ETHER_ADDR_LENGTH` bytes, 35 | /// representing the current addresses of the adapters in the list. 36 | /// * `mtu`: An array of 16-bit unsigned integers, representing the Maximum Transmission Units (MTUs) of the 37 | /// adapters in the list. 38 | #[repr(C, packed)] 39 | #[derive(Debug, Copy, Clone)] 40 | pub struct TcpAdapterList { 41 | pub adapter_count: u32, 42 | pub adapter_name_list: [[u8; ADAPTER_NAME_SIZE]; ADAPTER_LIST_SIZE], 43 | pub adapter_handle: [HANDLE; ADAPTER_LIST_SIZE], 44 | pub adapter_medium_list: [u32; ADAPTER_LIST_SIZE], 45 | pub current_address: [[u8; ETHER_ADDR_LENGTH]; ADAPTER_LIST_SIZE], 46 | pub mtu: [u16; ADAPTER_LIST_SIZE], 47 | } 48 | 49 | /// The `ListEntry` structure is the Rust equivalent of the 50 | /// [_LIST_ENTRY](https://learn.microsoft.com/en-us/windows/win32/api/ntdef/ns-ntdef-list_entry) 51 | /// structure in the Windows API. It represents a doubly-linked list entry, containing forward and backward 52 | /// pointers to adjacent list entries. 53 | /// 54 | /// # Fields 55 | /// 56 | /// * `flink`: A mutable raw pointer to the next `ListEntry` in the list (forward link). 57 | /// * `blink`: A mutable raw pointer to the previous `ListEntry` in the list (backward link). 58 | #[repr(C)] 59 | #[derive(Debug, Copy, Clone)] 60 | pub struct ListEntry { 61 | pub flink: *mut ListEntry, 62 | pub blink: *mut ListEntry, 63 | } 64 | 65 | /// The `IntermediateBufferHeaderUnion` structure is the Rust equivalent of the union 66 | /// used for `INTERMEDIATE_BUFFER` in the driver API. It represents a union between a 67 | /// `HANDLE` and a `ListEntry`, providing a way to access either of them based on the context. 68 | /// 69 | /// # Fields 70 | /// 71 | /// * `adapter_handle`: A `HANDLE` representing the adapter handle. 72 | /// * `list_entry`: A `ListEntry` structure representing a doubly-linked list entry. 73 | #[repr(C, packed)] 74 | #[derive(Copy, Clone)] 75 | pub union IntermediateBufferHeaderUnion { 76 | pub adapter_handle: HANDLE, 77 | pub list_entry: ListEntry, 78 | } 79 | 80 | /// Provides a default implementation for the `IntermediateBufferHeaderUnion` structure. 81 | /// 82 | /// # Safety 83 | /// 84 | /// This implementation is safe because the union contains either a `HANDLE` or a `ListEntry`. 85 | /// The `ListEntry` is a union of raw pointers, which can be safely zeroed as long as they are not dereferenced. 86 | /// The `HANDLE` is a wrapper around an `isize`, which can also be safely zeroed. 87 | impl Default for IntermediateBufferHeaderUnion { 88 | fn default() -> Self { 89 | // SAFETY: This union contains either a `HANDLE` or a `ListEntry` 90 | // ListEntry: is an union of raw pointers which can be safely zeroed(as long as you not dereference it) 91 | // HANDLE: is just an `isize` wrapper which can also be zeroed 92 | unsafe { core::mem::zeroed() } 93 | } 94 | } 95 | 96 | /// The `IntermediateBuffer` structure represents an intermediate buffer that stores packet data along with some 97 | /// additional information. This structure is used internally by the packet filter driver. 98 | /// 99 | /// Rust equivalent for [_INTERMEDIATE_BUFFER](https://www.ntkernel.com/docs/windows-packet-filter-documentation/structures/_intermediate_buffer/). 100 | /// 101 | /// # Fields 102 | /// * `header`: An `IntermediateBufferHeaderUnion` which is a union of `HANDLE` and `ListEntry`. 103 | /// * `device_flags`: A `DirectionFlags` value that indicates the direction of the packet (send or receive). 104 | /// * `length`: A `u32` representing the length of the packet data. 105 | /// * `flags`: A `u32` value containing various flags related to the packet. 106 | /// * `vlan_8021q`: A `u32` value representing the VLAN tag (802.1Q) associated with the packet. 107 | /// * `filter_id`: A `u32` value identifying the filter that processed the packet. 108 | /// * `reserved`: A reserved `[u32; 4usize]` array for future use. 109 | /// * `buffer`: A `Buffer` structure containing the actual packet data. 110 | #[repr(C, packed)] 111 | #[derive(Copy, Clone, Default)] 112 | pub struct IntermediateBuffer { 113 | pub header: IntermediateBufferHeaderUnion, 114 | pub device_flags: DirectionFlags, 115 | pub length: u32, 116 | pub flags: u32, 117 | pub vlan_8021q: u32, 118 | pub filter_id: u32, 119 | pub reserved: [u32; 4usize], 120 | pub buffer: Buffer, 121 | } 122 | 123 | /// This structure represents the buffer used for storing the actual packet data. 124 | /// 125 | /// A wrapper around an array of bytes with a size of `MAX_ETHER_FRAME`. 126 | #[repr(transparent)] 127 | #[derive(Copy, Clone)] 128 | pub struct Buffer(pub [u8; MAX_ETHER_FRAME]); 129 | 130 | impl Default for Buffer { 131 | fn default() -> Self { 132 | Self([0; MAX_ETHER_FRAME]) 133 | } 134 | } 135 | 136 | /// IntermediateBuffer implementation 137 | impl IntermediateBuffer { 138 | /// Creates a new `IntermediateBuffer` with default values. 139 | /// 140 | /// # Returns 141 | /// A new `IntermediateBuffer` instance. 142 | pub fn new() -> Self { 143 | Self::default() 144 | } 145 | 146 | /// Gets the `DirectionFlags` value associated with the `IntermediateBuffer`. 147 | /// 148 | /// # Returns 149 | /// The `DirectionFlags` value indicating the direction of the packet (send or receive). 150 | pub fn get_device_flags(&self) -> DirectionFlags { 151 | self.device_flags 152 | } 153 | 154 | /// Gets the length of the packet data stored in the `IntermediateBuffer`. 155 | /// 156 | /// # Returns 157 | /// A `u32` value representing the length of the packet data. 158 | pub fn get_length(&self) -> u32 { 159 | self.length 160 | } 161 | 162 | /// Sets the length of the packet data stored in the `IntermediateBuffer`. 163 | /// 164 | /// # Arguments 165 | /// * `length`: A `u32` value representing the new length of the packet data. 166 | pub fn set_length(&mut self, length: u32) { 167 | self.length = length 168 | } 169 | } 170 | 171 | /// This structure is used to define the mode of an adapter with a specified handle and filter flags. 172 | /// 173 | /// A Rust equivalent for the [_ADAPTER_MODE](https://www.ntkernel.com/docs/windows-packet-filter-documentation/structures/adapter_mode/) structure. 174 | #[repr(C, packed)] 175 | #[derive(Debug, Copy, Clone, Default)] 176 | pub struct AdapterMode { 177 | /// A `HANDLE` representing the adapter handle. 178 | pub adapter_handle: HANDLE, 179 | /// `FilterFlags` representing the filter flags associated with the adapter mode. 180 | pub flags: FilterFlags, 181 | } 182 | 183 | /// This structure represents an Ethernet packet with a pointer to an `IntermediateBuffer`. 184 | /// 185 | /// A Rust equivalent for the [_NDISRD_ETH_Packet](https://www.ntkernel.com/docs/windows-packet-filter-documentation/structures/_ndisrd_eth_packet/) structure. 186 | #[repr(C, packed)] 187 | #[derive(Debug, Copy, Clone)] 188 | pub struct EthPacket { 189 | /// A raw pointer to an `IntermediateBuffer` representing the buffer for this Ethernet packet. 190 | pub buffer: *mut IntermediateBuffer, 191 | } 192 | 193 | impl EthPacket { 194 | /// Returns a mutable reference to the `IntermediateBuffer` pointed to by the `EthPacket`. 195 | /// 196 | /// # Safety 197 | /// 198 | /// This function is unsafe because `EthPacket.buffer` may not be initialized or may point to 199 | /// invalid memory. 200 | pub unsafe fn get_buffer_mut(&mut self) -> &mut IntermediateBuffer { 201 | &mut *self.buffer 202 | } 203 | 204 | /// Returns a reference to the `IntermediateBuffer` pointed to by the `EthPacket`. 205 | /// 206 | /// # Safety 207 | /// 208 | /// This function is unsafe because `EthPacket.buffer` may not be initialized or may point to 209 | /// invalid memory. 210 | pub unsafe fn get_buffer(&self) -> &IntermediateBuffer { 211 | &*self.buffer 212 | } 213 | } 214 | 215 | /// This structure represents a request for an Ethernet packet, containing an adapter handle and an `EthPacket`. 216 | /// 217 | /// A Rust equivalent for the [_ETH_REQUEST](https://www.ntkernel.com/docs/windows-packet-filter-documentation/structures/_eth_request/) structure. 218 | #[repr(C, packed)] 219 | #[derive(Debug, Copy, Clone)] 220 | pub struct EthRequest { 221 | /// A handle to the network adapter associated with this request. 222 | pub adapter_handle: HANDLE, 223 | /// An `EthPacket` representing the Ethernet packet for this request. 224 | pub packet: EthPacket, 225 | } 226 | 227 | /// This structure represents a multiple Ethernet packets request, containing an adapter handle, packet number, packet success, and an array of `EthPacket`. 228 | /// 229 | /// A Rust equivalent for the [_ETH_M_REQUEST](https://www.ntkernel.com/docs/windows-packet-filter-documentation/structures/_eth_m_request/) structure. 230 | #[repr(C, packed)] 231 | #[derive(Debug, Copy, Clone)] 232 | pub struct EthMRequest { 233 | /// A handle to the network adapter associated with this request. 234 | adapter_handle: HANDLE, 235 | /// The number of packets in the `packets` array. 236 | packet_number: u32, 237 | /// The number of successfully processed packets. 238 | packet_success: u32, 239 | /// An array of `EthPacket` representing the Ethernet packets for this request. 240 | packets: [EthPacket; N], 241 | } 242 | 243 | impl EthMRequest { 244 | /// Creates a new `EthMRequest` with the specified adapter handle. 245 | pub fn new(adapter_handle: HANDLE) -> Self { 246 | Self { 247 | adapter_handle, 248 | packet_number: 0, 249 | packet_success: 0, 250 | packets: [EthPacket { 251 | buffer: core::ptr::null_mut(), 252 | }; N], 253 | } 254 | } 255 | 256 | /// Returns an `EthPacket` at the specified index if the index is within the valid range. 257 | pub fn at(&self, index: usize) -> Option { 258 | if index < self.packet_number as usize { 259 | Some(self.packets[index]) 260 | } else { 261 | None 262 | } 263 | } 264 | 265 | /// Returns the number of packets in the `packets` array. 266 | pub fn get_packet_number(&self) -> u32 { 267 | self.packet_number 268 | } 269 | 270 | /// Sets the number of packets in the `packets` array. 271 | pub fn set_packet_number(&mut self, number: u32) { 272 | self.packet_number = number; 273 | } 274 | 275 | /// Resets the packet number to 0. 276 | pub fn reset(&mut self) { 277 | self.set_packet_number(0); 278 | } 279 | 280 | /// Returns the number of successfully processed packets. 281 | pub fn get_packet_success(&self) -> u32 { 282 | self.packet_success 283 | } 284 | 285 | /// Pushes an `EthPacket` to the `packets` array if there's available space, returning an error if the array is full. 286 | pub fn push(&mut self, packet: EthPacket) -> Result<()> { 287 | if (self.packet_number as usize) < N { 288 | self.packets[self.packet_number as usize] = packet; 289 | self.packet_number += 1; 290 | Ok(()) 291 | } else { 292 | Err(ERROR_INVALID_PARAMETER.into()) 293 | } 294 | } 295 | } 296 | 297 | /// This structure represents an adapter event, containing an adapter handle and an event handle. 298 | /// 299 | /// A Rust equivalent for the [_ADAPTER_EVENT](https://www.ntkernel.com/docs/windows-packet-filter-documentation/structures/adapter_event/) structure. 300 | #[repr(C, packed)] 301 | #[derive(Debug, Copy, Clone)] 302 | pub struct AdapterEvent { 303 | /// A handle to the network adapter associated with this event. 304 | pub adapter_handle: HANDLE, 305 | /// A handle to the event associated with this adapter. 306 | pub event_handle: HANDLE, 307 | } 308 | 309 | /// This structure is used to make queries or set parameters on a network adapter. 310 | /// 311 | /// A Rust equivalent for the [_PACKET_OID_DATA](https://www.ntkernel.com/docs/windows-packet-filter-documentation/structures/_packet_oid_data/) structure. 312 | #[repr(C, packed)] 313 | pub struct PacketOidData { 314 | /// A handle to the network adapter associated with this query or parameter setting. 315 | pub adapter_handle: HANDLE, 316 | /// The OID (Object Identifier) that represents the query or parameter to be set. 317 | pub oid: u32, 318 | /// The length of the data in bytes. 319 | pub length: u32, 320 | /// The data associated with the query or parameter. 321 | pub data: T, 322 | } 323 | 324 | impl PacketOidData { 325 | /// Creates a new PacketOidData instance. 326 | /// 327 | /// # Arguments 328 | /// 329 | /// * `adapter_handle` - A handle to the network adapter associated with this query or parameter setting. 330 | /// * `oid` - The OID (Object Identifier) that represents the query or parameter to be set. 331 | /// * `data` - The data associated with the query or parameter. 332 | pub fn new(adapter_handle: HANDLE, oid: u32, data: T) -> Self { 333 | Self { 334 | adapter_handle, 335 | oid, 336 | length: size_of::() as u32, 337 | data, 338 | } 339 | } 340 | } 341 | 342 | /// This structure contains information about a RAS (Remote Access Service) link. 343 | /// 344 | /// A Rust equivalent for the [_RAS_LINK_INFO](https://www.ntkernel.com/docs/windows-packet-filter-documentation/structures/_ras_link_info/) structure. 345 | #[repr(C, packed)] 346 | #[derive(Debug, Copy, Clone)] 347 | pub struct RasLinkInformation { 348 | /// The link speed in bits per second. 349 | link_speed: u32, 350 | /// The maximum total size, in bytes. 351 | maximum_total_size: u32, 352 | /// The remote MAC address. 353 | remote_address: [u8; ETHER_ADDR_LENGTH], 354 | /// The local MAC address. 355 | local_address: [u8; ETHER_ADDR_LENGTH], 356 | /// The length of the protocol buffer, in bytes. 357 | protocol_buffer_length: u32, 358 | /// The buffer containing information about the RAS-managed protocols. 359 | protocol_buffer: [u8; RAS_LINK_BUFFER_LENGTH], 360 | } 361 | 362 | impl RasLinkInformation { 363 | /// Returns the link speed in bits per second. 364 | pub fn get_link_speed(&self) -> u32 { 365 | self.link_speed 366 | } 367 | 368 | /// Returns the maximum total size. 369 | pub fn get_maximum_total_size(&self) -> u32 { 370 | self.maximum_total_size 371 | } 372 | 373 | /// Returns the remote MAC address. 374 | pub fn get_remote_address(&self) -> &[u8; ETHER_ADDR_LENGTH] { 375 | &self.remote_address 376 | } 377 | 378 | /// Returns the local MAC address. 379 | pub fn get_local_address(&self) -> &[u8; ETHER_ADDR_LENGTH] { 380 | &self.local_address 381 | } 382 | 383 | /// Returns the length of the protocol buffer, in bytes. 384 | pub fn get_protocol_buffer_length(&self) -> usize { 385 | self.protocol_buffer_length as usize 386 | } 387 | 388 | /// Returns the buffer containing information about the RAS-managed protocols. 389 | pub fn get_protocol_buffer(&self) -> &[u8; RAS_LINK_BUFFER_LENGTH] { 390 | &self.protocol_buffer 391 | } 392 | } 393 | 394 | /// This structure is a container for RAS (Remote Access Service) link information structures. 395 | /// 396 | /// A Rust equivalent for the [_RAS_LINKS](https://www.ntkernel.com/docs/windows-packet-filter-documentation/structures/_ras_links/) structure. 397 | /// Note that this struct may be too large to be allocated on the stack in Rust and may result in a stack overflow. 398 | #[repr(C, packed)] 399 | #[derive(Debug, Copy, Clone)] 400 | pub struct RasLinks { 401 | /// The number of RAS links in the array. 402 | number_of_links: u32, 403 | /// The array of RAS link information structures. 404 | pub ras_links: [RasLinkInformation; RAS_LINKS_MAX], 405 | } 406 | 407 | impl Default for RasLinks { 408 | /// Returns a zero-initialized instance of `RasLinks`. 409 | /// 410 | /// # Safety 411 | /// 412 | /// This structure is filled by the information by NDIS filter driver when passed as a memory buffer 413 | /// along with IOCTL_NDISRD_GET_RAS_LINKS. It is safe to be zeroed because contains only values and arrays that 414 | /// can be default initialized with zeroes. 415 | fn default() -> Self { 416 | unsafe { std::mem::zeroed() } 417 | } 418 | } 419 | 420 | impl RasLinks { 421 | /// Returns the number of RAS links in the array. 422 | pub fn get_number_of_links(&self) -> usize { 423 | self.number_of_links as usize 424 | } 425 | } 426 | -------------------------------------------------------------------------------- /src/driver/constants.rs: -------------------------------------------------------------------------------- 1 | //! # Submodule: Basic NDISAPI Constants and flags 2 | //! 3 | //! This submodule contains various constants and bitflag structures for the NDISAPI Rust library. 4 | //! 5 | //! The NDISAPI library provides a Rust interface for interacting with the Windows Packet Filter 6 | //! driver. This module contains various constants and bitflag structures used to configure the 7 | //! packet filtering mechanism, specify filtering options for different protocols, and define 8 | //! the conditions for filtering at specific layers. 9 | 10 | // Import required external crates and types 11 | use bitflags::bitflags; 12 | 13 | /// ADAPTER_NAME_SIZE is the maximum length for the adapter name. 14 | pub const ADAPTER_NAME_SIZE: usize = 256; 15 | 16 | /// ADAPTER_LIST_SIZE is the maximum number of adapters in the adapter list. 17 | pub const ADAPTER_LIST_SIZE: usize = 32; 18 | 19 | /// ETHER_ADDR_LENGTH is the length of an Ethernet address in bytes. 20 | pub const ETHER_ADDR_LENGTH: usize = 6; 21 | 22 | /// MAX_ETHER_FRAME is the maximum size of an Ethernet frame in bytes. If the driver was built with 23 | /// the JUMBO_FRAME_SUPPORTED option, this value would be 9014 bytes instead. 24 | pub const MAX_ETHER_FRAME: usize = 1514; 25 | 26 | /// RAS_LINK_BUFFER_LENGTH is the length of the RAS link buffer in bytes. 27 | pub const RAS_LINK_BUFFER_LENGTH: usize = 2048; 28 | 29 | /// RAS_LINKS_MAX is the maximum number of RAS links. 30 | pub const RAS_LINKS_MAX: usize = 256; 31 | 32 | /// Constant representing the IPv4 subnet type. 33 | pub const IP_SUBNET_V4_TYPE: u32 = 1; 34 | /// Constant representing the IPv4 address range type. 35 | pub const IP_RANGE_V4_TYPE: u32 = 2; 36 | 37 | /// Constant representing the IPv6 subnet type. 38 | pub const IP_SUBNET_V6_TYPE: u32 = 1; 39 | /// Constant representing the IPv6 address range type. 40 | pub const IP_RANGE_V6_TYPE: u32 = 2; 41 | 42 | /// ETH_802_3 is a constant representing the 802.3 Ethernet standard. 43 | pub const ETH_802_3: u32 = 1; 44 | 45 | /// Constant representing the IPv4 network protocols. 46 | pub const IPV4: u32 = 1; 47 | /// Constant representing the IPv6 network protocols. 48 | pub const IPV6: u32 = 2; 49 | 50 | /// Constant representing the TCP or UDP protocols. 51 | pub const TCPUDP: u32 = 1; 52 | /// Constant representing the ICMP protocol. 53 | pub const ICMP: u32 = 2; 54 | 55 | /// Allows a packet to pass through the filter without any modification. 56 | pub const FILTER_PACKET_PASS: u32 = 1; 57 | /// Drops the packet and prevents it from reaching the destination. 58 | pub const FILTER_PACKET_DROP: u32 = 2; 59 | /// Redirects the packet for processing in user-mode. 60 | pub const FILTER_PACKET_REDIRECT: u32 = 3; 61 | /// Allows the packet to pass through the filter and redirects a copy of it for processing by user-mode application. 62 | pub const FILTER_PACKET_PASS_RDR: u32 = 4; 63 | /// Drops the packet and and redirects a copy of it for processing by user-mode application. 64 | pub const FILTER_PACKET_DROP_RDR: u32 = 5; 65 | 66 | // Define bitflag structures for filter flags, direction flags, and various protocol-specific filter flags 67 | bitflags! { 68 | /// FilterFlags represent various flags used for packet filtering. 69 | /// 70 | /// These flags are used to configure the behavior of the packet filtering mechanism in different scenarios. 71 | #[derive(Default, Clone, Copy, Debug, PartialEq)] 72 | pub struct FilterFlags: u32 { 73 | /// MSTCP_FLAG_SENT_TUNNEL: Queue all packets sent from TCP/IP to network interface. Original packet is dropped. 74 | const MSTCP_FLAG_SENT_TUNNEL = 1; 75 | 76 | /// MSTCP_FLAG_RECV_TUNNEL: Queue all packets indicated by network interface to TCP/IP. Original packet is dropped. 77 | const MSTCP_FLAG_RECV_TUNNEL = 2; 78 | 79 | /// MSTCP_FLAG_SENT_LISTEN: Queue all packets sent from TCP/IP to network interface. Original packet goes ahead. 80 | const MSTCP_FLAG_SENT_LISTEN = 4; 81 | 82 | /// MSTCP_FLAG_RECV_LISTEN: Queue all packets indicated by network interface to TCP/IP. Original packet goes ahead. 83 | const MSTCP_FLAG_RECV_LISTEN = 8; 84 | 85 | /// MSTCP_FLAG_FILTER_DIRECT: In promiscuous mode, the TCP/IP stack receives all packets in the Ethernet segment 86 | /// and replies with various ICMP packets. To prevent this, set this flag. All packets with destination MAC different 87 | /// from FF-FF-FF-FF-FF-FF and network interface current MAC will never reach TCP/IP. 88 | const MSTCP_FLAG_FILTER_DIRECT = 16; 89 | 90 | /// MSTCP_FLAG_LOOPBACK_FILTER: If not set, loopback packets are silently passed over. Otherwise, these packets are 91 | /// passed for further processing (queued for redirecting to the application if not dropped by the MSTCP_FLAG_LOOPBACK_BLOCK below). 92 | const MSTCP_FLAG_LOOPBACK_FILTER = 32; 93 | 94 | /// MSTCP_FLAG_LOOPBACK_BLOCK: If set, loopback packets (with exception to broadcast/multicast) are silently dropped. 95 | const MSTCP_FLAG_LOOPBACK_BLOCK = 64; 96 | 97 | /// MSTCP_FLAG_SENT_RECEIVE_TUNNEL: Combination of MSTCP_FLAG_SENT_TUNNEL and MSTCP_FLAG_RECV_TUNNEL. 98 | const MSTCP_FLAG_SENT_RECEIVE_TUNNEL = Self::MSTCP_FLAG_SENT_TUNNEL.bits() | Self::MSTCP_FLAG_RECV_TUNNEL.bits(); 99 | 100 | /// MSTCP_FLAG_SENT_RECEIVE_LISTEN: Combination of MSTCP_FLAG_SENT_LISTEN and MSTCP_FLAG_RECV_LISTEN. 101 | const MSTCP_FLAG_SENT_RECEIVE_LISTEN = Self::MSTCP_FLAG_SENT_LISTEN.bits() | Self::MSTCP_FLAG_RECV_LISTEN.bits(); 102 | } 103 | } 104 | 105 | bitflags! { 106 | /// DirectionFlags represent various direction flags for packet processing. 107 | /// 108 | /// These flags are used to specify the direction of packets that the filter should act upon and 109 | /// to specify the packet direction in IntermediateBuffer. 110 | #[derive(Default, Clone, Copy, Debug, PartialEq)] 111 | pub struct DirectionFlags: u32 { 112 | /// PACKET_FLAG_ON_SEND: Indicates an outgoing packet. In the context of filters, the filter should act on packets being sent from the system. 113 | const PACKET_FLAG_ON_SEND = 1; 114 | 115 | /// PACKET_FLAG_ON_RECEIVE: Indicates an incoming packet. In the context of filters, the filter should act on packets being received by the system. 116 | const PACKET_FLAG_ON_RECEIVE = 2; 117 | 118 | /// PACKET_FLAG_ON_SEND_RECEIVE: Filter should act on both sent and received packets. 119 | const PACKET_FLAG_ON_SEND_RECEIVE = Self::PACKET_FLAG_ON_SEND.bits() | Self::PACKET_FLAG_ON_RECEIVE.bits(); 120 | } 121 | } 122 | 123 | bitflags! { 124 | /// Eth802_3FilterFlags represent various filtering options for Ethernet 802.3 frames. 125 | /// 126 | /// These flags are used to specify which fields of an Ethernet 802.3 frame the filter should 127 | /// consider when determining whether to process the packet. 128 | #[derive(Default, Clone, Copy, Debug, PartialEq)] 129 | pub struct Eth802_3FilterFlags: u32 { 130 | /// ETH_802_3_SRC_ADDRESS: Filter based on the source MAC address of the Ethernet 802.3 frame. 131 | const ETH_802_3_SRC_ADDRESS = 1; 132 | 133 | /// ETH_802_3_DEST_ADDRESS: Filter based on the destination MAC address of the Ethernet 802.3 frame. 134 | const ETH_802_3_DEST_ADDRESS = 2; 135 | 136 | /// ETH_802_3_PROTOCOL: Filter based on the protocol field (EtherType) of the Ethernet 802.3 frame. 137 | const ETH_802_3_PROTOCOL = 4; 138 | } 139 | } 140 | 141 | bitflags! { 142 | /// IpV4FilterFlags represent various filtering options for IPv4 packets. 143 | /// 144 | /// These flags are used to specify which fields of an IPv4 packet the filter should 145 | /// consider when determining whether to process the packet. 146 | #[derive(Default, Clone, Copy, Debug, PartialEq)] 147 | pub struct IpV4FilterFlags: u32 { 148 | /// IP_V4_FILTER_SRC_ADDRESS: Filter based on the source IP address of the IPv4 packet. 149 | const IP_V4_FILTER_SRC_ADDRESS = 1; 150 | 151 | /// IP_V4_FILTER_DEST_ADDRESS: Filter based on the destination IP address of the IPv4 packet. 152 | const IP_V4_FILTER_DEST_ADDRESS = 2; 153 | 154 | /// IP_V4_FILTER_PROTOCOL: Filter based on the protocol field of the IPv4 packet (e.g., TCP, UDP, ICMP). 155 | const IP_V4_FILTER_PROTOCOL = 4; 156 | } 157 | } 158 | 159 | bitflags! { 160 | /// IpV6FilterFlags represent various filtering options for IPv6 packets. 161 | /// 162 | /// These flags are used to specify which fields of an IPv6 packet the filter should 163 | /// consider when determining whether to process the packet. 164 | #[derive(Default, Clone, Copy, Debug, PartialEq)] 165 | pub struct IpV6FilterFlags: u32 { 166 | /// IP_V6_FILTER_SRC_ADDRESS: Filter based on the source IP address of the IPv6 packet. 167 | const IP_V6_FILTER_SRC_ADDRESS = 1; 168 | 169 | /// IP_V6_FILTER_DEST_ADDRESS: Filter based on the destination IP address of the IPv6 packet. 170 | const IP_V6_FILTER_DEST_ADDRESS = 2; 171 | 172 | /// IP_V6_FILTER_PROTOCOL: Filter based on the protocol field of the IPv6 packet (e.g., TCP, UDP, ICMPv6). 173 | const IP_V6_FILTER_PROTOCOL = 4; 174 | } 175 | } 176 | 177 | bitflags! { 178 | /// TcpUdpFilterFlags represent various filtering options for TCP and UDP packets. 179 | /// 180 | /// These flags are used to specify which fields of a TCP or UDP packet the filter should 181 | /// consider when determining whether to process the packet. 182 | #[derive(Default, Clone, Copy, Debug, PartialEq)] 183 | pub struct TcpUdpFilterFlags: u32 { 184 | /// TCPUDP_SRC_PORT: Filter based on the source port of the TCP or UDP packet. 185 | const TCPUDP_SRC_PORT = 1; 186 | 187 | /// TCPUDP_DEST_PORT: Filter based on the destination port of the TCP or UDP packet. 188 | const TCPUDP_DEST_PORT = 2; 189 | 190 | /// TCPUDP_TCP_FLAGS: Filter based on the TCP flags of a TCP packet. This flag is ignored for UDP packets. 191 | const TCPUDP_TCP_FLAGS = 4; 192 | } 193 | } 194 | 195 | bitflags! { 196 | /// IcmpFilterFlags represent various filtering options for ICMP packets. 197 | /// 198 | /// These flags are used to specify which fields of an ICMP packet the filter should 199 | /// consider when determining whether to process the packet. 200 | #[derive(Default, Clone, Copy, Debug, PartialEq)] 201 | pub struct IcmpFilterFlags: u32 { 202 | /// ICMP_TYPE: Filter based on the ICMP type of the ICMP packet. 203 | const ICMP_TYPE = 1; 204 | 205 | /// ICMP_CODE: Filter based on the ICMP code of the ICMP packet. 206 | const ICMP_CODE = 2; 207 | } 208 | } 209 | 210 | bitflags! { 211 | /// FilterLayerFlags represent the validation flags for various filter layers. 212 | /// 213 | /// These flags are used to specify which layers of a packet the filter should consider 214 | /// when determining whether to process the packet. They are typically used in conjunction 215 | /// with other filter flags to define the conditions for filtering at specific layers. 216 | #[derive(Default, Clone, Copy, Debug, PartialEq)] 217 | pub struct FilterLayerFlags: u32 { 218 | /// DATA_LINK_LAYER_VALID: Indicates that the Data Link Layer filter fields are valid and should be considered in the filtering process. 219 | const DATA_LINK_LAYER_VALID = 1; 220 | 221 | /// NETWORK_LAYER_VALID: Indicates that the Network Layer filter fields are valid and should be considered in the filtering process. 222 | const NETWORK_LAYER_VALID = 2; 223 | 224 | /// TRANSPORT_LAYER_VALID: Indicates that the Transport Layer filter fields are valid and should be considered in the filtering process. 225 | const TRANSPORT_LAYER_VALID = 4; 226 | } 227 | } 228 | -------------------------------------------------------------------------------- /src/driver/fastio.rs: -------------------------------------------------------------------------------- 1 | //! # Submodule: Fast I/O Structures 2 | //! 3 | //! This submodule provides Rust equivalents of several structures related to Fast I/O operations 4 | //! for the NDISAPI Rust library used in communicating with the Windows Packet Filter driver. 5 | //! 6 | //! The structures in this submodule are related to Fast I/O sections, which include headers and packet data, 7 | //! and are involved in read and write operations. 8 | //! 9 | //! For a detailed description of each structure, refer to their respective documentation within the 10 | //! submodule. 11 | 12 | use super::base::*; 13 | 14 | /// This structure contains the fields that make up the FastIoWriteUnion when accessed separately. 15 | #[repr(C, packed)] 16 | #[derive(Default, Copy, Clone)] 17 | pub struct FastIoWriteUnionStruct { 18 | /// The number of packets 19 | pub number_of_packets: u16, 20 | /// Flag indicating whether a write operation is in progress 21 | pub write_in_progress_flag: u16, 22 | } 23 | 24 | /// This union represents a combined 32-bit field containing both the number of packets and a flag 25 | /// indicating whether a write operation is in progress. It provides the option to access the fields individually 26 | /// through the `split` field or the combined 32-bit value through the `join` field. 27 | /// 28 | /// Rust equivalent for _FAST_IO_WRITE_UNION 29 | #[repr(C, packed)] 30 | #[derive(Copy, Clone)] 31 | pub union FastIoWriteUnion { 32 | /// Separate access to the number of packets and write in progress flag 33 | pub split: FastIoWriteUnionStruct, 34 | /// Combined 32-bit representation of the number of packets and write in progress flag 35 | pub join: u32, 36 | } 37 | 38 | impl Default for FastIoWriteUnion { 39 | /// Initializes a new `FastIoWriteUnion` with default values for both the `join` field and the fields in the `split` structure. 40 | fn default() -> Self { 41 | FastIoWriteUnion { join: 0 } 42 | } 43 | } 44 | 45 | /// This structure is used as the header for the FastIoSection structure, containing the FastIoWriteUnion 46 | /// and a flag indicating whether a read operation is in progress. 47 | /// 48 | /// Rust equivalent for _FAST_IO_SECTION_HEADER 49 | #[repr(C, packed)] 50 | #[derive(Default, Copy, Clone)] 51 | pub struct FastIoSectionHeader { 52 | /// Union containing the number of packets and write in progress flag 53 | pub fast_io_write_union: FastIoWriteUnion, 54 | /// Flag indicating whether a read operation is in progress 55 | pub read_in_progress_flag: u32, 56 | } 57 | 58 | /// This structure represents a Fast I/O section, which includes a FastIoSectionHeader and an array of IntermediateBuffer 59 | /// structures. It is used to store information about packet data and the state of read and write operations. 60 | /// 61 | /// Rust equivalent for _FAST_IO_SECTION 62 | #[repr(C, packed)] 63 | #[derive(Copy, Clone)] 64 | pub struct FastIoSection { 65 | /// Header containing the FastIoWriteUnion and read in progress flag 66 | pub fast_io_header: FastIoSectionHeader, 67 | /// Array of IntermediateBuffer structures for packet data 68 | pub fast_io_packets: [IntermediateBuffer; N], 69 | } 70 | 71 | impl Default for FastIoSection { 72 | // Initializes a new `FastIoSection` with default values for its fields. 73 | // SAFETY: This structure is filled by information by NDIS filter driver. 74 | // Zero-initialized FastIoSection is completely valid and ignored by the code. 75 | fn default() -> Self { 76 | unsafe { std::mem::zeroed() } 77 | } 78 | } 79 | 80 | /// A Rust struct that represents the parameters for fast I/O initialization. 81 | /// 82 | /// Rust equivalent for _INITIALIZE_FAST_IO_PARAMS. 83 | #[repr(C, packed)] 84 | #[derive(Debug, Copy, Clone)] 85 | pub struct InitializeFastIoParams { 86 | /// header_ptr: A mutable pointer to a FastIoSection of size N. 87 | pub header_ptr: *mut FastIoSection, 88 | /// data_size: A u32 representing the data size of the Fast I/O section. 89 | pub data_size: u32, 90 | } 91 | 92 | /// A Rust struct that represents an unsorted read/send request. 93 | /// 94 | /// Rust equivalent for _UNSORTED_READ_SEND_REQUEST. 95 | #[repr(C, packed)] 96 | #[derive(Debug, Copy, Clone)] 97 | pub struct UnsortedReadSendRequest { 98 | /// packets: A mutable pointer to an array of IntermediateBuffer of size N. 99 | pub packets: *mut [IntermediateBuffer; N], 100 | /// packets_num: A u32 representing the number of packets in the request. 101 | pub packets_num: u32, 102 | } 103 | -------------------------------------------------------------------------------- /src/driver/filters.rs: -------------------------------------------------------------------------------- 1 | //! # Submodule: Basic NDISAPI static filter definitions 2 | //! 3 | //! This submodule contains various structures used for static filters in the NDISAPI Rust library. 4 | //! 5 | //! The `filters` submodule provides a Rust interface for configuring static filters for the Windows Packet 6 | //! Filter driver. It contains structures for specifying filter conditions and actions for various protocols, 7 | //! including Ethernet 802.3, IPv4, IPv6, TCP, UDP, and ICMP. These structures allow users to define complex 8 | //! filtering rules based on multiple packet fields and layers. 9 | //! 10 | //! # Structures 11 | //! 12 | //! * [`Eth8023Filter`] - Represents a static filter for Ethernet 802.3 frames. 13 | //! * [`IpV4Filter`] - Represents a static filter for IPv4 packets. 14 | //! * [`IpV6Filter`] - Represents a static filter for IPv6 packets. 15 | //! * [`TcpUdpFilter`] - Represents a static filter for TCP and UDP packets. 16 | //! * [`IcmpFilter`] - Represents a static filter for ICMP packets. 17 | //! * [`StaticFilter`] - Represents a single static filter entry that combines filter conditions for various 18 | //! layers and the filter action to be taken. 19 | //! * [`StaticFilterTable`] - Represents a table of static filters, used for managing multiple static filter entries. 20 | 21 | // Import required external crates and types 22 | use windows::{Win32::Networking::WinSock::IN6_ADDR, Win32::Networking::WinSock::IN_ADDR}; 23 | 24 | use super::constants::*; 25 | 26 | /// This structure is used to define an Ethernet 802.3 filter based on various fields like source and destination addresses, and protocol. 27 | /// 28 | /// A Rust equivalent for the [_ETH_802_3_FILTER](https://www.ntkernel.com/docs/windows-packet-filter-documentation/structures/_eth_802_3_filter/) structure. 29 | #[repr(C, packed)] 30 | #[derive(Debug, Copy, Clone)] 31 | pub struct Eth8023Filter { 32 | /// A bitmask indicating which fields in the filter are valid. 33 | pub valid_fields: Eth802_3FilterFlags, 34 | /// The source address to filter on. 35 | pub src_address: [u8; ETHER_ADDR_LENGTH], 36 | /// The destination address to filter on. 37 | pub dest_address: [u8; ETHER_ADDR_LENGTH], 38 | /// The protocol (Ethertype) to filter on. 39 | pub protocol: u16, 40 | /// Padding to align the structure. 41 | pub padding: u16, 42 | } 43 | 44 | impl Default for Eth8023Filter { 45 | /// Returns a zero-initialized instance of `Eth8023Filter`. 46 | /// 47 | /// # Safety 48 | /// 49 | /// It is safe to zero-initialize this structure because it contains only values and arrays that 50 | /// can be default initialized with zeroes. 51 | fn default() -> Self { 52 | unsafe { std::mem::zeroed() } 53 | } 54 | } 55 | 56 | /// This structure is used to represent an IPv4 subnet based on an IP address and a subnet mask. 57 | /// 58 | /// A Rust equivalent for the [_IP_SUBNET_V4](https://www.ntkernel.com/docs/windows-packet-filter-documentation/structures/_ip_subnet_v4/) structure. 59 | #[repr(C, packed)] 60 | #[derive(Default, Copy, Clone)] 61 | pub struct IpSubnetV4 { 62 | /// The IPv4 address. 63 | pub ip: IN_ADDR, 64 | /// The subnet mask. 65 | pub ip_mask: IN_ADDR, 66 | } 67 | 68 | /// This structure is used to represent an IPv4 address range based on a start and end IP address. 69 | /// 70 | /// A Rust equivalent for the [_IP_RANGE_V4](https://www.ntkernel.com/docs/windows-packet-filter-documentation/structures/_ip_range_v4/) structure. 71 | #[repr(C, packed)] 72 | #[derive(Default, Copy, Clone)] 73 | pub struct IpRangeV4 { 74 | /// The start of the IPv4 address range. 75 | pub start_ip: IN_ADDR, 76 | /// The end of the IPv4 address range. 77 | pub end_ip: IN_ADDR, 78 | } 79 | 80 | /// A Rust union representing either an IPv4 subnet (IpSubnetV4) or an IPv4 address range (IpRangeV4). 81 | #[repr(C, packed)] 82 | #[derive(Copy, Clone)] 83 | pub union IpAddressV4Union { 84 | /// The IPv4 subnet representation. 85 | pub ip_subnet: IpSubnetV4, 86 | /// The IPv4 address range representation. 87 | pub ip_range: IpRangeV4, 88 | } 89 | 90 | impl Default for IpAddressV4Union { 91 | fn default() -> Self { 92 | // SAFETY: This union contains either a `IpSubnetV4` or a `IpRangeV4` 93 | // IpSubnetV4: when zeroed is equivalent to 0.0.0.0/0 94 | // IpRangeV4: when zeroed is equivalent to 0.0.0.0 - 0.0.0.0 95 | unsafe { std::mem::zeroed() } 96 | } 97 | } 98 | 99 | /// Represents an IPv4 address in a format used by the packet filtering mechanism. 100 | /// 101 | /// A Rust equivalent for [_IP_ADDRESS_V4](https://www.ntkernel.com/docs/windows-packet-filter-documentation/structures/_ip_address_v4/). 102 | /// 103 | /// The `address_type` field indicates whether the address is a subnet or a range. 104 | /// The `address` field contains the actual IPv4 address information in a union format. 105 | #[repr(C, packed)] 106 | #[derive(Default, Copy, Clone)] 107 | pub struct IpAddressV4 { 108 | pub address_type: u32, // IP_SUBNET_V4_TYPE or IP_RANGE_V4_TYPE 109 | pub address: IpAddressV4Union, 110 | } 111 | 112 | /// Represents an IPv4 filter used by the packet filtering mechanism. 113 | /// 114 | /// A Rust equivalent for [_IP_V4_FILTER](https://www.ntkernel.com/docs/windows-packet-filter-documentation/structures/_ip_v4_filter/). 115 | /// 116 | /// The `valid_fields` field specifies which fields in the filter structure are used for filtering. 117 | /// The `src_address` field contains the source IPv4 address information. 118 | /// The `dest_address` field contains the destination IPv4 address information. 119 | /// The `protocol` field represents the IP protocol number. 120 | /// The `padding` field is used for alignment purposes. 121 | #[repr(C, packed)] 122 | #[derive(Default, Copy, Clone)] 123 | pub struct IpV4Filter { 124 | pub valid_fields: IpV4FilterFlags, 125 | pub src_address: IpAddressV4, 126 | pub dest_address: IpAddressV4, 127 | pub protocol: u8, 128 | pub padding: [u8; 3usize], 129 | } 130 | 131 | /// Represents an IPv6 subnet used by the packet filtering mechanism. 132 | /// 133 | /// A Rust equivalent for [_IP_SUBNET_V6](https://www.ntkernel.com/docs/windows-packet-filter-documentation/structures/_ip_subnet_v6/). 134 | /// 135 | /// The `ip` field contains the IPv6 address. 136 | /// The `ip_mask` field contains the subnet mask. 137 | #[repr(C, packed)] 138 | #[derive(Copy, Clone)] 139 | pub struct IpSubnetV6 { 140 | pub ip: IN6_ADDR, 141 | pub ip_mask: IN6_ADDR, 142 | } 143 | 144 | /// Represents an IPv6 address range used by the packet filtering mechanism. 145 | /// 146 | /// A Rust equivalent for [_IP_RANGE_V6](https://www.ntkernel.com/docs/windows-packet-filter-documentation/structures/_ip_range_v6/). 147 | /// 148 | /// The `start_ip` field contains the starting IPv6 address of the range. 149 | /// The `end_ip` field contains the ending IPv6 address of the range. 150 | #[repr(C, packed)] 151 | #[derive(Copy, Clone)] 152 | pub struct IpRangeV6 { 153 | pub start_ip: IN6_ADDR, 154 | pub end_ip: IN6_ADDR, 155 | } 156 | 157 | /// This structure is used to store information about a particular address space 158 | /// for packet filtering purposes. 159 | /// 160 | /// A Rust union that represents either an IPv6 subnet or an IPv6 address range. 161 | /// 162 | /// The `ip_subnet` field contains the IPv6 subnet if the address space is a subnet. 163 | /// The `ip_range` field contains the IPv6 address range if the address space is a range. 164 | #[repr(C, packed)] 165 | #[derive(Copy, Clone)] 166 | pub union IpAddressV6Union { 167 | pub ip_subnet: IpSubnetV6, 168 | pub ip_range: IpRangeV6, 169 | } 170 | 171 | impl Default for IpAddressV6Union { 172 | fn default() -> Self { 173 | // SAFETY: This union contains either a `IpSubnetV6` or a `IpRangeV6` 174 | // IpSubnetV6: when zeroed is equivalent to ::/0 175 | // IpRangeV6: when zeroed is equivalent to :: - :: 176 | unsafe { std::mem::zeroed() } 177 | } 178 | } 179 | 180 | /// This structure is used to store information about an IPv6 address for packet filtering purposes. 181 | /// 182 | /// Rust equivalent for [_IP_ADDRESS_V6](https://www.ntkernel.com/docs/windows-packet-filter-documentation/structures/_ip_address_v6/). 183 | /// 184 | /// The `address_type` field indicates whether the address is a subnet (IP_SUBNET_V6_TYPE) or a range (IP_RANGE_V6_TYPE). 185 | /// The `address` field contains the specific IPv6 address data, either a subnet or an address range, depending on the `address_type`. 186 | #[repr(C, packed)] 187 | #[derive(Default, Copy, Clone)] 188 | pub struct IpAddressV6 { 189 | pub address_type: u32, // IP_SUBNET_V6_TYPE or IP_RANGE_V6_TYPE 190 | pub address: IpAddressV6Union, 191 | } 192 | 193 | /// This structure is used to define packet filtering rules for IPv6 packets. 194 | /// 195 | /// Rust equivalent for [_IP_V6_FILTER](https://www.ntkernel.com/docs/windows-packet-filter-documentation/structures/_ip_v6_filter/). 196 | /// 197 | /// The `valid_fields` field contains flags that specify which fields of the filter are active. 198 | /// The `src_address` and `dest_address` fields store information about the source and destination IPv6 addresses respectively. 199 | /// The `protocol` field represents the protocol used in the packet (e.g., TCP, UDP). 200 | /// The `padding` field is reserved for padding to ensure the correct alignment of the structure. 201 | #[repr(C, packed)] 202 | #[derive(Default, Copy, Clone)] 203 | pub struct IpV6Filter { 204 | pub valid_fields: IpV6FilterFlags, 205 | pub src_address: IpAddressV6, 206 | pub dest_address: IpAddressV6, 207 | pub protocol: u8, 208 | pub padding: [u8; 3usize], 209 | } 210 | 211 | /// This structure is used to define a range of port numbers for packet filtering rules. 212 | /// 213 | /// Rust equivalent for [_PORT_RANGE](https://www.ntkernel.com/docs/windows-packet-filter-documentation/structures/_port_range/). 214 | /// 215 | /// The `start_range` field represents the starting port number in the range. 216 | /// The `end_range` field represents the ending port number in the range. 217 | #[repr(C, packed)] 218 | #[derive(Default, Debug, Copy, Clone)] 219 | pub struct PortRange { 220 | pub start_range: u16, 221 | pub end_range: u16, 222 | } 223 | 224 | /// This structure is used to define filtering rules for TCP and UDP packets. 225 | /// 226 | /// Rust equivalent for [_TCPUDP_FILTER](https://www.ntkernel.com/docs/windows-packet-filter-documentation/structures/_tcpudp_filter/). 227 | /// 228 | /// The `valid_fields` field specifies which fields in the structure are valid for filtering. 229 | /// The `source_port` field represents the range of source port numbers to filter. 230 | /// The `dest_port` field represents the range of destination port numbers to filter. 231 | /// The `tcp_flags` field is used to filter TCP packets based on their flags. 232 | /// The `padding` field ensures proper alignment of the structure. 233 | #[repr(C, packed)] 234 | #[derive(Default, Debug, Copy, Clone)] 235 | pub struct TcpUdpFilter { 236 | pub valid_fields: TcpUdpFilterFlags, 237 | pub source_port: PortRange, 238 | pub dest_port: PortRange, 239 | pub tcp_flags: u8, 240 | pub padding: [u8; 3usize], 241 | } 242 | 243 | /// A Rust struct that represents a range of byte values. 244 | /// 245 | /// Rust equivalent for _BYTE_RANGE. This structure can be used to define 246 | /// filtering rules based on byte ranges, such as ICMP type or code ranges. 247 | /// 248 | /// The `start_range` field represents the start of the byte range. 249 | /// The `end_range` field represents the end of the byte range. 250 | #[repr(C)] 251 | #[derive(Default, Debug, Copy, Clone)] 252 | pub struct ByteRange { 253 | pub start_range: u8, 254 | pub end_range: u8, 255 | } 256 | 257 | /// A Rust struct that represents an ICMP filter. 258 | /// 259 | /// Rust equivalent for _ICMP_FILTER. This structure can be used to define 260 | /// filtering rules for ICMP packets based on ICMP type and code ranges. 261 | /// 262 | /// The `valid_fields` field specifies which fields in the filter are valid for filtering. 263 | /// The `type_range` field represents a range of ICMP types for filtering. 264 | /// The `code_range` field represents a range of ICMP codes for filtering. 265 | #[repr(C, packed)] 266 | #[derive(Default, Debug, Copy, Clone)] 267 | pub struct IcmpFilter { 268 | pub valid_fields: IcmpFilterFlags, 269 | pub type_range: ByteRange, 270 | pub code_range: ByteRange, 271 | } 272 | 273 | /// A Rust union that holds an `Eth8023Filter`. 274 | /// 275 | /// This union can be extended to include other data link layer filters if needed. 276 | /// Currently, it only contains an `Eth8023Filter` for filtering Ethernet/802.3 packets. 277 | #[repr(C, packed)] 278 | #[derive(Copy, Clone)] 279 | pub union DataLinkLayerFilterUnion { 280 | pub eth_8023_filter: Eth8023Filter, 281 | } 282 | 283 | impl Default for DataLinkLayerFilterUnion { 284 | fn default() -> Self { 285 | // SAFETY: This union contains an `Eth8023Filter` 286 | // Eth8023Filter: when zeroed is meaningless and ignored by code 287 | unsafe { std::mem::zeroed() } 288 | } 289 | } 290 | 291 | /// A Rust struct that represents a data link layer filter. 292 | /// 293 | /// Rust equivalent for [_DATA_LINK_LAYER_FILTER](https://www.ntkernel.com/docs/windows-packet-filter-documentation/structures/data_link_layer_filter/) 294 | /// This struct can be used to filter packets at the data link layer (e.g., Ethernet/802.3) by specifying the filter type in `union_selector`. 295 | #[repr(C, packed)] 296 | #[derive(Default, Copy, Clone)] 297 | pub struct DataLinkLayerFilter { 298 | pub union_selector: u32, // ETH_802_3 for Eth8023Filter 299 | pub data_link_layer: DataLinkLayerFilterUnion, 300 | } 301 | 302 | /// A Rust union that holds either an `IpV4Filter` or an `IpV6Filter`. 303 | /// 304 | /// This union can be used to filter packets at the network layer by specifying the appropriate filter type (IPv4 or IPv6). 305 | #[repr(C, packed)] 306 | #[derive(Copy, Clone)] 307 | pub union NetworkLayerFilterUnion { 308 | pub ipv4: IpV4Filter, 309 | pub ipv6: IpV6Filter, 310 | } 311 | 312 | impl Default for NetworkLayerFilterUnion { 313 | fn default() -> Self { 314 | // SAFETY: This union contains either a `IpV4Filter` or `IpV6Filter' 315 | // IpV4Filter: when zeroed is meaningless and ignored by code 316 | // IpV6Filter: when zeroed is meaningless and ignored by code 317 | unsafe { std::mem::zeroed() } 318 | } 319 | } 320 | 321 | /// A Rust struct that represents a network layer filter. 322 | /// 323 | /// Rust equivalent for [_NETWORK_LAYER_FILTER](https://www.ntkernel.com/docs/windows-packet-filter-documentation/structures/_network_layer_filter/). 324 | #[repr(C, packed)] 325 | #[derive(Default, Copy, Clone)] 326 | pub struct NetworkLayerFilter { 327 | /// union_selector: A field that determines the type of the network layer filter. 328 | /// Set to IPV4 for IpV4Filter, and IPV6 for IpV6Filter. 329 | pub union_selector: u32, 330 | /// network_layer: A union that holds either an IpV4Filter or an IpV6Filter, 331 | /// depending on the value of the union_selector field. 332 | pub network_layer: NetworkLayerFilterUnion, 333 | } 334 | 335 | /// A Rust union that represents a transport layer filter. 336 | /// 337 | /// Holds either a `TcpUdpFilter` or an `IcmpFilter`. 338 | #[repr(C, packed)] 339 | #[derive(Copy, Clone)] 340 | pub union TransportLayerFilterUnion { 341 | /// tcp_udp: A TcpUdpFilter struct that represents a TCP/UDP filter. 342 | pub tcp_udp: TcpUdpFilter, 343 | /// icmp: An IcmpFilter struct that represents an ICMP filter. 344 | pub icmp: IcmpFilter, 345 | } 346 | 347 | impl Default for TransportLayerFilterUnion { 348 | fn default() -> Self { 349 | // SAFETY: This union contains either a `TcpUdpFilter` or an `IcmpFilter` 350 | // TcpUdpFilter: when zeroed is meaningless and ignored by code 351 | // IcmpFilter: when zeroed is meaningless and ignored by code 352 | unsafe { std::mem::zeroed() } 353 | } 354 | } 355 | 356 | /// A Rust struct that represents a transport layer filter. 357 | /// 358 | /// Rust equivalent for [_TRANSPORT_LAYER_FILTER](https://www.ntkernel.com/docs/windows-packet-filter-documentation/structures/_transport_layer_filter/) 359 | #[repr(C, packed)] 360 | #[derive(Default, Copy, Clone)] 361 | pub struct TransportLayerFilter { 362 | /// union_selector: A u32 flag that selects the appropriate filter. 363 | /// Use TCPUDP for TcpUdpFilter and ICMP for IcmpFilter. 364 | pub union_selector: u32, 365 | /// transport_layer: A TransportLayerFilterUnion that holds either a `TcpUdpFilter` or an `IcmpFilter`. 366 | pub transport_layer: TransportLayerFilterUnion, 367 | } 368 | 369 | /// This structure is used to define a single static filter rule for packet filtering. Each rule can specify filtering criteria at 370 | /// the data link, network, and transport layers. The structure also includes counters for incoming and outgoing packets and bytes 371 | /// that match the filter rule. 372 | /// 373 | /// * Rust equivalent for [_STATIC_FILTER](https://www.ntkernel.com/docs/windows-packet-filter-documentation/structures/_static_filter/) 374 | #[repr(C, packed)] 375 | #[derive(Default, Copy, Clone)] 376 | pub struct StaticFilter { 377 | /// Adapter handle extended to 64 bit size for structure compatibility across x64 and x86 architectures 378 | pub adapter_handle: u64, 379 | /// PACKET_FLAG_ON_SEND or/and PACKET_FLAG_ON_RECEIVE to specify the direction of packets to match 380 | pub direction_flags: DirectionFlags, 381 | /// FILTER_PACKET_XXX to define the action to take when a packet matches the filter 382 | pub filter_action: u32, 383 | /// Specifies which of the fields below contain valid values and should be matched against the packet 384 | pub valid_fields: FilterLayerFlags, 385 | /// Time of the last counters reset (in seconds passed since 1 Jan 1980) 386 | pub last_reset: u32, 387 | /// Incoming packets passed through this filter 388 | pub packets_in: u64, 389 | /// Incoming bytes passed through this filter 390 | pub bytes_in: u64, 391 | /// Outgoing packets passed through this filter 392 | pub packets_out: u64, 393 | /// Outgoing bytes passed through this filter 394 | pub bytes_out: u64, 395 | /// Filter criteria for the data link layer (e.g., Ethernet) 396 | pub data_link_filter: DataLinkLayerFilter, 397 | /// Filter criteria for the network layer (e.g., IPv4, IPv6) 398 | pub network_filter: NetworkLayerFilter, 399 | /// Filter criteria for the transport layer (e.g., TCP, UDP, ICMP) 400 | pub transport_filter: TransportLayerFilter, 401 | } 402 | 403 | /// This structure represents an array of static filter rules, each of which is defined by a `StaticFilter` structure. 404 | /// It is used to manage multiple filter rules for packet filtering in a table format. 405 | /// 406 | /// * Rust equivalent to the [_STATIC_FILTER_TABLE](https://www.ntkernel.com/docs/windows-packet-filter-documentation/structures/_static_filter_table/) 407 | #[repr(C, packed)] 408 | #[derive(Copy, Clone)] 409 | pub struct StaticFilterTable { 410 | /// The number of elements in the static_filters array 411 | pub table_size: u32, 412 | /// Padding to ensure correct memory alignment 413 | pub padding: u32, 414 | /// Array of static filter rules 415 | pub static_filters: [StaticFilter; N], 416 | } 417 | 418 | impl StaticFilterTable { 419 | /// Creates a new `StaticFilterTable` with the specified number of elements. 420 | pub fn new() -> Self { 421 | Self { 422 | table_size: N as u32, 423 | padding: 0u32, 424 | static_filters: [StaticFilter::default(); N], 425 | } 426 | } 427 | } 428 | 429 | impl Default for StaticFilterTable { 430 | /// Initializes a new `StaticFilterTable` with the specified number of elements and default values for each element. 431 | fn default() -> Self { 432 | Self::new() 433 | } 434 | } 435 | -------------------------------------------------------------------------------- /src/driver/ioctl.rs: -------------------------------------------------------------------------------- 1 | //! # Submodule: Basic NDISAPI driver I/O control codes 2 | //! 3 | //! This submodule provides a collection of constants for IOCTL (Input/Output Control) codes 4 | //! and the `ctl_code` function used to generate these codes. 5 | //! 6 | //! IOCTL codes are used by the Windows Packet Filter driver to communicate with the driver 7 | //! and perform various operations such as setting packet filters, reading packets, and sending 8 | //! packets to the adapter or MSTCP stack. 9 | //! 10 | //! The `ctl_code` function is used to create the IOCTL codes by taking the device type, function, 11 | //! method, and access as input parameters. 12 | 13 | // Device and ioctl codes 14 | /// FILE_DEVICE_NDISRD: A constant u32 value representing the NDISRD device type. 15 | const FILE_DEVICE_NDISRD: u32 = 0x00008300; 16 | 17 | /// NDISRD_IOCTL_INDEX: A constant u32 value representing the NDISRD IOCTL index. 18 | const NDISRD_IOCTL_INDEX: u32 = 0x830; 19 | 20 | /// METHOD_BUFFERED: A constant u32 value representing the buffered method. 21 | const METHOD_BUFFERED: u32 = 0; 22 | 23 | /// FILE_ANY_ACCESS: A constant u32 value representing any file access. 24 | const FILE_ANY_ACCESS: u32 = 0; 25 | 26 | /// ctl_code function creates an IOCTL control code from the specified device type, function, method, and access values. 27 | /// 28 | /// # Arguments 29 | /// * `device_type`: A u32 representing the device type. 30 | /// * `function`: A u32 representing the function. 31 | /// * `method`: A u32 representing the method. 32 | /// * `access`: A u32 representing the access type. 33 | /// 34 | /// # Returns 35 | /// * A u32 value representing the resulting IOCTL control code. 36 | const fn ctl_code(device_type: u32, function: u32, method: u32, access: u32) -> u32 { 37 | (device_type << 16) | (access << 14) | (function << 2) | method 38 | } 39 | 40 | /// IOCTL_NDISRD_GET_VERSION: A constant u32 value representing the IOCTL code to get the NDISRD version. 41 | pub const IOCTL_NDISRD_GET_VERSION: u32 = ctl_code( 42 | FILE_DEVICE_NDISRD, 43 | NDISRD_IOCTL_INDEX, 44 | METHOD_BUFFERED, 45 | FILE_ANY_ACCESS, 46 | ); 47 | 48 | /// IOCTL_NDISRD_GET_TCPIP_INTERFACES: A constant u32 value representing the IOCTL code to get the TCPIP interfaces. 49 | pub const IOCTL_NDISRD_GET_TCPIP_INTERFACES: u32 = ctl_code( 50 | FILE_DEVICE_NDISRD, 51 | NDISRD_IOCTL_INDEX + 1, 52 | METHOD_BUFFERED, 53 | FILE_ANY_ACCESS, 54 | ); 55 | 56 | /// IOCTL_NDISRD_SEND_PACKET_TO_ADAPTER: A constant u32 value representing the IOCTL code to send a packet to the adapter. 57 | pub const IOCTL_NDISRD_SEND_PACKET_TO_ADAPTER: u32 = ctl_code( 58 | FILE_DEVICE_NDISRD, 59 | NDISRD_IOCTL_INDEX + 2, 60 | METHOD_BUFFERED, 61 | FILE_ANY_ACCESS, 62 | ); 63 | 64 | /// IOCTL_NDISRD_SEND_PACKET_TO_MSTCP: A constant u32 value representing the IOCTL code to send a packet to MSTCP. 65 | pub const IOCTL_NDISRD_SEND_PACKET_TO_MSTCP: u32 = ctl_code( 66 | FILE_DEVICE_NDISRD, 67 | NDISRD_IOCTL_INDEX + 3, 68 | METHOD_BUFFERED, 69 | FILE_ANY_ACCESS, 70 | ); 71 | 72 | /// IOCTL_NDISRD_READ_PACKET: A constant u32 value representing the IOCTL code to read a packet. 73 | pub const IOCTL_NDISRD_READ_PACKET: u32 = ctl_code( 74 | FILE_DEVICE_NDISRD, 75 | NDISRD_IOCTL_INDEX + 4, 76 | METHOD_BUFFERED, 77 | FILE_ANY_ACCESS, 78 | ); 79 | 80 | /// IOCTL_NDISRD_SET_ADAPTER_MODE: A constant u32 value representing the IOCTL code to set the adapter mode. 81 | pub const IOCTL_NDISRD_SET_ADAPTER_MODE: u32 = ctl_code( 82 | FILE_DEVICE_NDISRD, 83 | NDISRD_IOCTL_INDEX + 5, 84 | METHOD_BUFFERED, 85 | FILE_ANY_ACCESS, 86 | ); 87 | 88 | /// IOCTL_NDISRD_FLUSH_ADAPTER_QUEUE: A constant u32 value representing the IOCTL code to flush the adapter queue. 89 | pub const IOCTL_NDISRD_FLUSH_ADAPTER_QUEUE: u32 = ctl_code( 90 | FILE_DEVICE_NDISRD, 91 | NDISRD_IOCTL_INDEX + 6, 92 | METHOD_BUFFERED, 93 | FILE_ANY_ACCESS, 94 | ); 95 | 96 | /// IOCTL_NDISRD_SET_EVENT: A constant u32 value representing the IOCTL code to set a queued packet event. 97 | pub const IOCTL_NDISRD_SET_EVENT: u32 = ctl_code( 98 | FILE_DEVICE_NDISRD, 99 | NDISRD_IOCTL_INDEX + 7, 100 | METHOD_BUFFERED, 101 | FILE_ANY_ACCESS, 102 | ); 103 | 104 | /// IOCTL_NDISRD_NDIS_SET_REQUEST: A constant u32 value representing the IOCTL code for an NDIS set request. 105 | pub const IOCTL_NDISRD_NDIS_SET_REQUEST: u32 = ctl_code( 106 | FILE_DEVICE_NDISRD, 107 | NDISRD_IOCTL_INDEX + 8, 108 | METHOD_BUFFERED, 109 | FILE_ANY_ACCESS, 110 | ); 111 | 112 | /// IOCTL_NDISRD_NDIS_GET_REQUEST: A constant u32 value representing the IOCTL code for an NDIS get request. 113 | pub const IOCTL_NDISRD_NDIS_GET_REQUEST: u32 = ctl_code( 114 | FILE_DEVICE_NDISRD, 115 | NDISRD_IOCTL_INDEX + 9, 116 | METHOD_BUFFERED, 117 | FILE_ANY_ACCESS, 118 | ); 119 | 120 | /// IOCTL_NDISRD_SET_WAN_EVENT: A constant u32 value representing the IOCTL code to set a WAN event. 121 | pub const IOCTL_NDISRD_SET_WAN_EVENT: u32 = ctl_code( 122 | FILE_DEVICE_NDISRD, 123 | NDISRD_IOCTL_INDEX + 10, 124 | METHOD_BUFFERED, 125 | FILE_ANY_ACCESS, 126 | ); 127 | 128 | /// IOCTL_NDISRD_SET_ADAPTER_EVENT: A constant u32 value representing the IOCTL code to set an adapters list change event. 129 | pub const IOCTL_NDISRD_SET_ADAPTER_EVENT: u32 = ctl_code( 130 | FILE_DEVICE_NDISRD, 131 | NDISRD_IOCTL_INDEX + 11, 132 | METHOD_BUFFERED, 133 | FILE_ANY_ACCESS, 134 | ); 135 | 136 | /// IOCTL_NDISRD_ADAPTER_QUEUE_SIZE: A constant u32 value representing the IOCTL code to get the adapter queue size. 137 | pub const IOCTL_NDISRD_ADAPTER_QUEUE_SIZE: u32 = ctl_code( 138 | FILE_DEVICE_NDISRD, 139 | NDISRD_IOCTL_INDEX + 12, 140 | METHOD_BUFFERED, 141 | FILE_ANY_ACCESS, 142 | ); 143 | 144 | /// IOCTL_NDISRD_GET_ADAPTER_MODE: A constant u32 value representing the IOCTL code to get the adapter mode. 145 | pub const IOCTL_NDISRD_GET_ADAPTER_MODE: u32 = ctl_code( 146 | FILE_DEVICE_NDISRD, 147 | NDISRD_IOCTL_INDEX + 13, 148 | METHOD_BUFFERED, 149 | FILE_ANY_ACCESS, 150 | ); 151 | 152 | /// IOCTL_NDISRD_SET_PACKET_FILTERS: A constant u32 value representing the IOCTL code to set packet filters. 153 | pub const IOCTL_NDISRD_SET_PACKET_FILTERS: u32 = ctl_code( 154 | FILE_DEVICE_NDISRD, 155 | NDISRD_IOCTL_INDEX + 14, 156 | METHOD_BUFFERED, 157 | FILE_ANY_ACCESS, 158 | ); 159 | 160 | /// IOCTL_NDISRD_RESET_PACKET_FILTERS: A constant u32 value representing the IOCTL code to reset packet filters. 161 | pub const IOCTL_NDISRD_RESET_PACKET_FILTERS: u32 = ctl_code( 162 | FILE_DEVICE_NDISRD, 163 | NDISRD_IOCTL_INDEX + 15, 164 | METHOD_BUFFERED, 165 | FILE_ANY_ACCESS, 166 | ); 167 | 168 | /// IOCTL_NDISRD_GET_PACKET_FILTERS_TABLESIZE: A constant u32 value representing the IOCTL code to get the packet filters table size. 169 | pub const IOCTL_NDISRD_GET_PACKET_FILTERS_TABLESIZE: u32 = ctl_code( 170 | FILE_DEVICE_NDISRD, 171 | NDISRD_IOCTL_INDEX + 16, 172 | METHOD_BUFFERED, 173 | FILE_ANY_ACCESS, 174 | ); 175 | 176 | /// IOCTL_NDISRD_GET_PACKET_FILTERS: A constant u32 value representing the IOCTL code to get packet filters. 177 | pub const IOCTL_NDISRD_GET_PACKET_FILTERS: u32 = ctl_code( 178 | FILE_DEVICE_NDISRD, 179 | NDISRD_IOCTL_INDEX + 17, 180 | METHOD_BUFFERED, 181 | FILE_ANY_ACCESS, 182 | ); 183 | 184 | /// IOCTL_NDISRD_GET_PACKET_FILTERS_RESET_STATS: A constant u32 value representing the IOCTL code to get packet filters and reset their statistics. 185 | pub const IOCTL_NDISRD_GET_PACKET_FILTERS_RESET_STATS: u32 = ctl_code( 186 | FILE_DEVICE_NDISRD, 187 | NDISRD_IOCTL_INDEX + 18, 188 | METHOD_BUFFERED, 189 | FILE_ANY_ACCESS, 190 | ); 191 | 192 | /// IOCTL_NDISRD_GET_RAS_LINKS: A constant u32 value representing the IOCTL code to get active RAS links. 193 | pub const IOCTL_NDISRD_GET_RAS_LINKS: u32 = ctl_code( 194 | FILE_DEVICE_NDISRD, 195 | NDISRD_IOCTL_INDEX + 19, 196 | METHOD_BUFFERED, 197 | FILE_ANY_ACCESS, 198 | ); 199 | 200 | /// IOCTL_NDISRD_SEND_PACKETS_TO_ADAPTER: A constant u32 value representing the IOCTL code to send packets to the adapter. 201 | pub const IOCTL_NDISRD_SEND_PACKETS_TO_ADAPTER: u32 = ctl_code( 202 | FILE_DEVICE_NDISRD, 203 | NDISRD_IOCTL_INDEX + 20, 204 | METHOD_BUFFERED, 205 | FILE_ANY_ACCESS, 206 | ); 207 | 208 | /// IOCTL_NDISRD_SEND_PACKETS_TO_MSTCP: A constant u32 value representing the IOCTL code to send packets to the MSTCP. 209 | pub const IOCTL_NDISRD_SEND_PACKETS_TO_MSTCP: u32 = ctl_code( 210 | FILE_DEVICE_NDISRD, 211 | NDISRD_IOCTL_INDEX + 21, 212 | METHOD_BUFFERED, 213 | FILE_ANY_ACCESS, 214 | ); 215 | 216 | /// IOCTL_NDISRD_READ_PACKETS: A constant u32 value representing the IOCTL code to read packets. 217 | pub const IOCTL_NDISRD_READ_PACKETS: u32 = ctl_code( 218 | FILE_DEVICE_NDISRD, 219 | NDISRD_IOCTL_INDEX + 22, 220 | METHOD_BUFFERED, 221 | FILE_ANY_ACCESS, 222 | ); 223 | 224 | /// IOCTL_NDISRD_SET_ADAPTER_HWFILTER_EVENT: A constant u32 value representing the IOCTL code to set the adapter hardware filter change event. 225 | pub const IOCTL_NDISRD_SET_ADAPTER_HWFILTER_EVENT: u32 = ctl_code( 226 | FILE_DEVICE_NDISRD, 227 | NDISRD_IOCTL_INDEX + 23, 228 | METHOD_BUFFERED, 229 | FILE_ANY_ACCESS, 230 | ); 231 | 232 | /// IOCTL_NDISRD_INITIALIZE_FAST_IO: A constant u32 value representing the IOCTL code to initialize fast I/O. 233 | pub const IOCTL_NDISRD_INITIALIZE_FAST_IO: u32 = ctl_code( 234 | FILE_DEVICE_NDISRD, 235 | NDISRD_IOCTL_INDEX + 24, 236 | METHOD_BUFFERED, 237 | FILE_ANY_ACCESS, 238 | ); 239 | 240 | /// IOCTL_NDISRD_READ_PACKETS_UNSORTED: A constant u32 value representing the IOCTL code to read packets unsorted. 241 | pub const IOCTL_NDISRD_READ_PACKETS_UNSORTED: u32 = ctl_code( 242 | FILE_DEVICE_NDISRD, 243 | NDISRD_IOCTL_INDEX + 25, 244 | METHOD_BUFFERED, 245 | FILE_ANY_ACCESS, 246 | ); 247 | 248 | /// IOCTL_NDISRD_SEND_PACKET_TO_ADAPTER_UNSORTED: A constant u32 value representing the IOCTL code to send packets to the adapter unsorted. 249 | pub const IOCTL_NDISRD_SEND_PACKET_TO_ADAPTER_UNSORTED: u32 = ctl_code( 250 | FILE_DEVICE_NDISRD, 251 | NDISRD_IOCTL_INDEX + 26, 252 | METHOD_BUFFERED, 253 | FILE_ANY_ACCESS, 254 | ); 255 | 256 | /// IOCTL_NDISRD_SEND_PACKET_TO_MSTCP_UNSORTED: A constant u32 value representing the IOCTL code to send packets to the MSTCP unsorted. 257 | pub const IOCTL_NDISRD_SEND_PACKET_TO_MSTCP_UNSORTED: u32 = ctl_code( 258 | FILE_DEVICE_NDISRD, 259 | NDISRD_IOCTL_INDEX + 27, 260 | METHOD_BUFFERED, 261 | FILE_ANY_ACCESS, 262 | ); 263 | 264 | /// IOCTL_NDISRD_ADD_SECOND_FAST_IO_SECTION: A constant u32 value representing the IOCTL code to add a second fast I/O section. 265 | pub const IOCTL_NDISRD_ADD_SECOND_FAST_IO_SECTION: u32 = ctl_code( 266 | FILE_DEVICE_NDISRD, 267 | NDISRD_IOCTL_INDEX + 28, 268 | METHOD_BUFFERED, 269 | FILE_ANY_ACCESS, 270 | ); 271 | 272 | /// IOCTL_NDISRD_QUERY_IB_POOL_SIZE: A constant u32 value representing the IOCTL code to query the effective size of the Windows Packet Filter internal intermediate buffer pool. 273 | pub const IOCTL_NDISRD_QUERY_IB_POOL_SIZE: u32 = ctl_code( 274 | FILE_DEVICE_NDISRD, 275 | NDISRD_IOCTL_INDEX + 29, 276 | METHOD_BUFFERED, 277 | FILE_ANY_ACCESS, 278 | ); 279 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! The NDISAPI crate is a Rust library that provides functionality for capturing and filtering network packets 2 | //! on Windows operating systems. The crate contains three main modules: driver, ndisapi, and net. 3 | //! 4 | //! The driver module provides low-level functionality for interacting with Windows device drivers, and is used 5 | //! by the ndisapi module to capture and filter network packets. 6 | //! 7 | //! The ndisapi module contains the main functionality for capturing and filtering network packets. 8 | //! This includes various structs and enums for representing packet data and filter settings, as well as a Ndisapi 9 | //! struct for interacting with the driver and performing packet capture and filtering operations. 10 | //! 11 | //! The net module contains a MacAddress struct for representing and manipulating MAC addresses. 12 | 13 | mod driver; 14 | mod ndisapi; 15 | mod net; 16 | 17 | pub use crate::ndisapi::{ 18 | DirectionFlags, Eth802_3FilterFlags, EthMRequest, EthPacket, EthRequest, FastIoSection, 19 | FastIoSectionHeader, FilterFlags, FilterLayerFlags, IcmpFilterFlags, IntermediateBuffer, 20 | IpV4FilterFlags, IpV6FilterFlags, Ndisapi, NetworkAdapterInfo, PacketOidData, RasLinks, 21 | StaticFilterTable, TcpUdpFilterFlags, UnsortedReadSendRequest, Version, ETHER_ADDR_LENGTH, 22 | ETH_802_3, FILTER_PACKET_DROP, FILTER_PACKET_DROP_RDR, FILTER_PACKET_PASS, 23 | FILTER_PACKET_PASS_RDR, FILTER_PACKET_REDIRECT, ICMP, IPV4, IPV6, IP_RANGE_V4_TYPE, 24 | IP_RANGE_V6_TYPE, IP_SUBNET_V4_TYPE, IP_SUBNET_V6_TYPE, TCPUDP, 25 | }; 26 | 27 | pub use net::MacAddress; 28 | -------------------------------------------------------------------------------- /src/ndisapi.rs: -------------------------------------------------------------------------------- 1 | //! # Module: NDISAPI 2 | //! 3 | //! This module provides a high-level interface to the NDISAPI Rust library for communicating with the Windows Packet Filter driver. 4 | //! It includes the definition and implementation of the `Ndisapi` struct, which represents the main entry point to interact with the driver. 5 | //! 6 | //! The NDISAPI module also contains submodules for various aspects of the NDISAPI functionality, such as: 7 | //! - base_api: Basic API operations 8 | //! - defs: Definitions of constants, structures, and enumerations 9 | //! - fastio_api: Fast I/O operations 10 | //! - filters_api: Filter management and manipulation 11 | //! - io_api: Basic I/O operations 12 | //! - static_api: Static and Registry related methods for the NDISAPI 13 | //! 14 | //! For a detailed description of each submodule and the `Ndisapi` struct, refer to their respective documentation within the module. 15 | 16 | // Imports required dependencies 17 | use windows::{ 18 | core::{Result, PCWSTR}, 19 | Win32::Foundation::CloseHandle, 20 | Win32::Foundation::{GetLastError, HANDLE}, 21 | Win32::Storage::FileSystem::{ 22 | CreateFileW, FILE_FLAG_OVERLAPPED, FILE_SHARE_READ, FILE_SHARE_WRITE, 23 | OPEN_EXISTING, 24 | }, 25 | }; 26 | 27 | // Submodules 28 | mod base_api; 29 | mod defs; 30 | mod fastio_api; 31 | mod filters_api; 32 | mod io_api; 33 | mod static_api; 34 | 35 | // Re-exports the `driver` submodule 36 | pub use crate::driver::*; 37 | 38 | // Re-export already public members in `defs.rs` 39 | pub use crate::ndisapi::defs::{NetworkAdapterInfo, Version}; 40 | 41 | /// The `Ndisapi` struct represents an instance of the NDIS filter driver that provides access to network adapters and packets. 42 | /// 43 | /// This struct is used to communicate with the NDIS filter driver and access its functionalities. It contains a single field, `driver_handle`, 44 | /// which represents a handle to the driver. This handle is used to perform operations such as reading and writing packets, setting filters, and 45 | /// getting information about network adapters. 46 | /// 47 | /// To use `Ndisapi`, you should first create an instance of the struct by calling the `Ndisapi::new()` function. This will return a `Result` 48 | /// that contains an instance of `Ndisapi` if the operation was successful, or an error if it failed. Once you have an instance of `Ndisapi`, 49 | /// you can call its methods to perform various network-related operations. 50 | /// 51 | /// For example, you can use the `Ndisapi::read_packets()` method to read packets from the network adapter, or the `Ndisapi::send_packets_to_adapter()` 52 | /// 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 53 | /// packets should be captured or dropped. 54 | pub struct Ndisapi { 55 | // Represents a handle to the NDIS filter driver. 56 | driver_handle: HANDLE, 57 | // Stores the driver registry key for parameters 58 | registry_key: Vec, 59 | } 60 | 61 | // Implements the Drop trait for the `Ndisapi` struct 62 | impl Drop for Ndisapi { 63 | // Provides a custom implementation for the `drop` method 64 | fn drop(&mut self) { 65 | // Closes the driver_handle when the `Ndisapi` instance goes out of scope 66 | unsafe { 67 | CloseHandle(self.driver_handle); 68 | } 69 | } 70 | } 71 | 72 | // Implements additional methods for the `Ndisapi` struct 73 | impl Ndisapi { 74 | /// Initializes new Ndisapi instance opening the NDIS filter driver 75 | /// 76 | /// # Arguments 77 | /// 78 | /// * `driver_name` - The name of the file representing the NDIS filter driver. 79 | /// 80 | /// # Returns 81 | /// 82 | /// * `Result` - A Result containing the Ndisapi instance if successful, or an error if not. 83 | /// 84 | /// # Examples 85 | /// 86 | /// ```no_run 87 | /// use ndisapi::Ndisapi; 88 | /// let ndisapi = Ndisapi::new("NDISRD").unwrap(); 89 | /// ``` 90 | pub fn new(driver_name: &str) -> Result { 91 | // Create the filename and driver parameters registry path 92 | let filename = format!(r"\\.\{driver_name}"); 93 | let registry_key = format!(r"SYSTEM\CurrentControlSet\Services\{driver_name}\Parameters"); 94 | let mut filename: Vec = filename.encode_utf16().collect(); 95 | let mut registry_key: Vec = registry_key.encode_utf16().collect(); 96 | filename.push(0); 97 | registry_key.push(0); 98 | 99 | // Attempts to create a file handle for the NDIS filter driver 100 | if let Ok(driver_handle) = unsafe { 101 | CreateFileW( 102 | PCWSTR::from_raw(filename.as_ptr()), 103 | 0u32, 104 | FILE_SHARE_READ | FILE_SHARE_WRITE, 105 | None, 106 | OPEN_EXISTING, 107 | FILE_FLAG_OVERLAPPED, 108 | None, 109 | ) 110 | } { 111 | // Returns a new Ndisapi instance with the created handle if successful 112 | Ok(Self { 113 | driver_handle, 114 | registry_key, 115 | }) 116 | } else { 117 | // Returns an error if the file handle creation fails 118 | Err(unsafe { GetLastError() }.into()) 119 | } 120 | } 121 | 122 | pub fn get_driver_registry_key(&self) -> PCWSTR { 123 | PCWSTR::from_raw(self.registry_key.as_ptr()) 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/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 | 9 | use std::mem::{size_of, MaybeUninit}; 10 | 11 | use windows::{ 12 | core::Result, 13 | Win32::Foundation::{GetLastError, HANDLE}, 14 | Win32::System::IO::DeviceIoControl, 15 | }; 16 | 17 | use super::Ndisapi; 18 | use crate::driver::*; 19 | use crate::ndisapi::defs::*; 20 | 21 | pub const OID_GEN_CURRENT_PACKET_FILTER: u32 = 0x0001010E; 22 | 23 | impl 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` - 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 { 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::() as u32, 50 | Some(&mut adapter_mode as *mut AdapterMode as *mut std::ffi::c_void), 51 | size_of::() 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` - 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 { 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::() as u32, 109 | Some(ras_links as *const RasLinks as *mut std::ffi::c_void), 110 | size_of::() 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>` - 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> { 133 | let mut adapters: MaybeUninit = ::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::() 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` - 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 { 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::() as u32, 188 | Some(&mut version as *mut u32 as _), 189 | size_of::() 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` 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(&self, oid_request: &mut PacketOidData) -> Result<()> { 224 | let result = unsafe { 225 | DeviceIoControl( 226 | self.driver_handle, 227 | IOCTL_NDISRD_NDIS_GET_REQUEST, 228 | Some(oid_request as *const PacketOidData as *const std::ffi::c_void), 229 | size_of::>() as u32, 230 | Some(oid_request as *const PacketOidData as *mut std::ffi::c_void), 231 | size_of::>() 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` 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(&self, oid_request: &PacketOidData) -> Result<()> { 262 | let result = unsafe { 263 | DeviceIoControl( 264 | self.driver_handle, 265 | IOCTL_NDISRD_NDIS_SET_REQUEST, 266 | Some(oid_request as *const PacketOidData as *const std::ffi::c_void), 267 | size_of::>() 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::() 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::() 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::() 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::() 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` - 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 { 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::() 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 | } 476 | -------------------------------------------------------------------------------- /src/ndisapi/defs.rs: -------------------------------------------------------------------------------- 1 | //! # Submodule: High-level NDISAPI Types 2 | //! 3 | //! This submodule provides high-level NDISAPI definitions of constants, structures, and enumerations 4 | //! 5 | 6 | // Required imports for the submodule 7 | use std::fmt::{Display, Formatter, Result}; 8 | use windows::Win32::Foundation::HANDLE; 9 | 10 | /// Represents the version information for the NDIS filter driver. 11 | #[derive(PartialEq, Eq, PartialOrd, Ord)] 12 | pub struct Version { 13 | pub major: u32, 14 | pub minor: u32, 15 | pub revision: u32, 16 | } 17 | 18 | impl Display for Version { 19 | /// Formats the version information for display purposes. 20 | /// 21 | /// # Arguments 22 | /// 23 | /// * `f`: A mutable reference to a `Formatter` object. 24 | /// 25 | /// # Returns 26 | /// 27 | /// * `Result` - A formatting Result. 28 | fn fmt(&self, f: &mut Formatter<'_>) -> Result { 29 | write!(f, "{}.{}.{}", self.major, self.minor, self.revision) 30 | } 31 | } 32 | 33 | /// Represents information about a network adapter. 34 | pub struct NetworkAdapterInfo { 35 | name: String, 36 | handle: HANDLE, 37 | medium: u32, 38 | hw_address: [u8; 6], 39 | mtu: u16, 40 | } 41 | 42 | impl NetworkAdapterInfo { 43 | /// Creates a new `NetworkAdapterInfo` object with the specified properties. 44 | /// 45 | /// # Arguments 46 | /// 47 | /// * `name`: A `String` representing the name of the network adapter. 48 | /// * `handle`: A `HANDLE` to the network adapter. 49 | /// * `medium`: A `u32` value representing the network adapter medium. 50 | /// * `hw_address`: A `[u8; 6]` array representing the hardware address of the network adapter. 51 | /// * `mtu`: A `u16` value representing the maximum transmission unit (MTU) of the network adapter. 52 | /// 53 | /// # Returns 54 | /// 55 | /// * `NetworkAdapterInfo` - A new instance of `NetworkAdapterInfo`. 56 | pub fn new(name: String, handle: HANDLE, medium: u32, hw_address: [u8; 6], mtu: u16) -> Self { 57 | Self { 58 | name, 59 | handle, 60 | medium, 61 | hw_address, 62 | mtu, 63 | } 64 | } 65 | 66 | /// Returns the name of the network adapter. 67 | /// 68 | /// # Returns 69 | /// 70 | /// * `&str` - A reference to the name of the network adapter. 71 | pub fn get_name(&self) -> &str { 72 | &self.name 73 | } 74 | 75 | /// Returns the handle of the network adapter. 76 | /// 77 | /// # Returns 78 | /// 79 | /// * `HANDLE` - The handle of the network adapter. 80 | pub fn get_handle(&self) -> HANDLE { 81 | self.handle 82 | } 83 | 84 | /// Returns the medium of the network adapter. 85 | /// 86 | /// # Returns 87 | /// 88 | /// * `u32` - The medium of the network adapter. 89 | pub fn get_medium(&self) -> u32 { 90 | self.medium 91 | } 92 | 93 | /// Returns the hardware address of the network adapter. 94 | /// 95 | /// # Returns 96 | /// 97 | /// * `&[u8; 6]` - A reference to the hardware address of the network adapter. 98 | pub fn get_hw_address(&self) -> &[u8; 6] { 99 | &self.hw_address 100 | } 101 | 102 | /// Returns the maximum transmission unit (MTU) of the network adapter. 103 | /// 104 | /// # Returns 105 | /// 106 | /// * `u16` - The MTU of the network adapter. 107 | pub fn get_mtu(&self) -> u16 { 108 | self.mtu 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/ndisapi/fastio_api.rs: -------------------------------------------------------------------------------- 1 | //! # Submodule: Fast I/O operations 2 | //! 3 | //! This submodule offers methods to interact with the NDIS filter driver, allowing users to 4 | //! initialize the fast I/O mechanism, add a secondary fast I/O shared memory sections, and forward 5 | //! packets to the driver or to the target network interface or protocol layer. The methods in this 6 | //! submodule are designed to be highly flexible, allowing for parameterization by the size of the shared 7 | //! memory section or the number of packets to send. This submodule is part of the larger NDISAPI module, 8 | //! which provides a high-level API for the Windows Packet Filter on Windows. 9 | //! 10 | 11 | use std::mem::size_of; 12 | 13 | use windows::{core::Result, Win32::Foundation::GetLastError, Win32::System::IO::DeviceIoControl}; 14 | 15 | use super::Ndisapi; 16 | use crate::driver::*; 17 | 18 | impl Ndisapi { 19 | /// This function adds a secondary Fast I/O shared memory section to the NDIS filter driver, 20 | /// allowing faster communication between user-mode applications and the driver. 21 | /// 22 | /// # Type Parameters 23 | /// 24 | /// * `N`: The size of the Fast I/O shared memory section. 25 | /// 26 | /// # Arguments 27 | /// 28 | /// * `fast_io_section`: A mutable reference to a `FastIoSection` object representing 29 | /// the shared memory section to be added. 30 | /// 31 | /// # Returns 32 | /// 33 | /// * `Result<()>`: If successful, returns `Ok(())`. Otherwise, returns an error. 34 | pub fn add_secondary_fast_io( 35 | &self, 36 | fast_io_section: &mut FastIoSection, 37 | ) -> Result<()> { 38 | let params = InitializeFastIoParams:: { 39 | header_ptr: fast_io_section as *mut FastIoSection, 40 | data_size: N as u32, 41 | }; 42 | 43 | let result = unsafe { 44 | DeviceIoControl( 45 | self.driver_handle, 46 | IOCTL_NDISRD_ADD_SECOND_FAST_IO_SECTION, 47 | Some(¶ms as *const InitializeFastIoParams as *const std::ffi::c_void), 48 | size_of::>() as u32, 49 | None, 50 | 0, 51 | None, 52 | None, 53 | ) 54 | }; 55 | 56 | if !result.as_bool() { 57 | Err(unsafe { GetLastError() }.into()) 58 | } else { 59 | Ok(()) 60 | } 61 | } 62 | 63 | /// This function initializes the fast I/O mechanism for the NDIS filter driver and 64 | /// submits the initial shared memory section for faster communication between 65 | /// user-mode applications and the driver. 66 | /// 67 | /// # Type Parameters 68 | /// 69 | /// * `N`: The size of the Fast I/O shared memory section. 70 | /// 71 | /// # Arguments 72 | /// 73 | /// * `fast_io_section`: A mutable reference to a `FastIoSection` object representing 74 | /// the shared memory section to be submitted. 75 | /// 76 | /// # Returns 77 | /// 78 | /// * `Result<()>`: If successful, returns `Ok(())`. Otherwise, returns an error. 79 | pub fn initialize_fast_io( 80 | &self, 81 | fast_io_section: &mut FastIoSection, 82 | ) -> Result<()> { 83 | let params = InitializeFastIoParams:: { 84 | header_ptr: fast_io_section as *mut FastIoSection, 85 | data_size: N as u32, 86 | }; 87 | 88 | let result = unsafe { 89 | DeviceIoControl( 90 | self.driver_handle, 91 | IOCTL_NDISRD_INITIALIZE_FAST_IO, 92 | Some(¶ms as *const InitializeFastIoParams as *const std::ffi::c_void), 93 | size_of::>() as u32, 94 | None, 95 | 0, 96 | None, 97 | None, 98 | ) 99 | }; 100 | 101 | if !result.as_bool() { 102 | Err(unsafe { GetLastError() }.into()) 103 | } else { 104 | Ok(()) 105 | } 106 | } 107 | 108 | /// This function retrieves queued packets from the NDIS filter driver without considering 109 | /// the network interface. It reads packets in an unsorted manner and stores them in the 110 | /// provided buffer. 111 | /// 112 | /// # Type Parameters 113 | /// 114 | /// * `N`: The number of packets to read. 115 | /// 116 | /// # Arguments 117 | /// 118 | /// * `packets`: A mutable reference to an array of `IntermediateBuffer` objects, where the 119 | /// read packets will be stored. 120 | /// 121 | /// # Returns 122 | /// 123 | /// * `Result`: If successful, returns `Ok(usize)` with the number of packets read. 124 | /// Otherwise, returns an error. 125 | pub fn read_packets_unsorted( 126 | &self, 127 | packets: &mut [IntermediateBuffer; N], 128 | ) -> Result { 129 | let mut request = UnsortedReadSendRequest:: { 130 | packets: packets as *mut [IntermediateBuffer; N], 131 | packets_num: N as u32, 132 | }; 133 | 134 | let result = unsafe { 135 | DeviceIoControl( 136 | self.driver_handle, 137 | IOCTL_NDISRD_READ_PACKETS_UNSORTED, 138 | Some(&request as *const UnsortedReadSendRequest as *const std::ffi::c_void), 139 | size_of::>() as u32, 140 | Some(&mut request as *mut UnsortedReadSendRequest as *mut std::ffi::c_void), 141 | size_of::>() as u32, 142 | None, 143 | None, 144 | ) 145 | }; 146 | 147 | if !result.as_bool() { 148 | Err(unsafe { GetLastError() }.into()) 149 | } else { 150 | Ok(request.packets_num as usize) 151 | } 152 | } 153 | 154 | /// This function forwards packets to the NDIS filter driver in an unsorted manner, which then 155 | /// sends them to the target network interface. The target adapter handle should be set in the 156 | /// `IntermediateBuffer.header.adapter_handle` field. 157 | /// 158 | /// # Type Parameters 159 | /// 160 | /// * `N`: The number of packets to send. 161 | /// 162 | /// # Arguments 163 | /// 164 | /// * `packets`: A mutable reference to an array of `IntermediateBuffer` objects, which contain 165 | /// the packets to be sent. 166 | /// * `packets_num`: The number of packets to send from the array. 167 | /// 168 | /// # Returns 169 | /// 170 | /// * `Result`: If successful, returns `Ok(usize)` with the number of packets sent. 171 | /// Otherwise, returns an error. 172 | pub fn send_packets_to_adapters_unsorted( 173 | &self, 174 | packets: &mut [IntermediateBuffer; N], 175 | packets_num: usize, 176 | ) -> Result { 177 | let mut request = UnsortedReadSendRequest:: { 178 | packets: packets as *mut [IntermediateBuffer; N], 179 | packets_num: packets_num as u32, 180 | }; 181 | 182 | let result = unsafe { 183 | DeviceIoControl( 184 | self.driver_handle, 185 | IOCTL_NDISRD_SEND_PACKET_TO_ADAPTER_UNSORTED, 186 | Some(&request as *const UnsortedReadSendRequest as *const std::ffi::c_void), 187 | size_of::>() as u32, 188 | Some(&mut request as *mut UnsortedReadSendRequest as *mut std::ffi::c_void), 189 | size_of::>() as u32, 190 | None, 191 | None, 192 | ) 193 | }; 194 | 195 | if !result.as_bool() { 196 | Err(unsafe { GetLastError() }.into()) 197 | } else { 198 | Ok(request.packets_num as usize) 199 | } 200 | } 201 | 202 | /// This function forwards packets to the NDIS filter driver in an unsorted manner, which then 203 | /// sends them to the target protocols layer (MSTCP). The target adapter handle (to be indicated 204 | /// from) should be set in the `IntermediateBuffer.header.adapter_handle` field. 205 | /// 206 | /// # Type Parameters 207 | /// 208 | /// * `N`: The number of packets to send. 209 | /// 210 | /// # Arguments 211 | /// 212 | /// * `packets`: A mutable reference to an array of `IntermediateBuffer` objects, which contain 213 | /// the packets to be sent. 214 | /// * `packets_num`: The number of packets to send from the array. 215 | /// 216 | /// # Returns 217 | /// 218 | /// * `Result`: If successful, returns `Ok(usize)` with the number of packets sent. 219 | /// Otherwise, returns an error. 220 | pub fn send_packets_to_mstcp_unsorted( 221 | &self, 222 | packets: &mut [IntermediateBuffer; N], 223 | packets_num: usize, 224 | ) -> Result { 225 | let mut request = UnsortedReadSendRequest:: { 226 | packets: packets as *mut [IntermediateBuffer; N], 227 | packets_num: packets_num as u32, 228 | }; 229 | 230 | let result = unsafe { 231 | DeviceIoControl( 232 | self.driver_handle, 233 | IOCTL_NDISRD_SEND_PACKET_TO_MSTCP_UNSORTED, 234 | Some(&request as *const UnsortedReadSendRequest as *const std::ffi::c_void), 235 | size_of::>() as u32, 236 | Some(&mut request as *mut UnsortedReadSendRequest as *mut std::ffi::c_void), 237 | size_of::>() as u32, 238 | None, 239 | None, 240 | ) 241 | }; 242 | 243 | if !result.as_bool() { 244 | Err(unsafe { GetLastError() }.into()) 245 | } else { 246 | Ok(request.packets_num as usize) 247 | } 248 | } 249 | } 250 | -------------------------------------------------------------------------------- /src/ndisapi/filters_api.rs: -------------------------------------------------------------------------------- 1 | //! # Submodule: Static filter functions 2 | //! 3 | //! This submodule provides methods for controlling the NDIS filter driver, including retrieving and setting 4 | //! the static filter table, resetting the filter statistics, and resetting the static filter table. These 5 | //! methods are parameterized by the size of the static filter table. The submodule is part of a larger module 6 | //! (NDISAPI) that provides high-level API for the Windows packet Filter on Windows. 7 | //! 8 | 9 | use std::mem::size_of; 10 | 11 | use windows::{core::Result, Win32::Foundation::GetLastError, Win32::System::IO::DeviceIoControl}; 12 | 13 | use super::Ndisapi; 14 | use crate::driver::*; 15 | 16 | impl Ndisapi { 17 | /// This function retrieves the static filter table from the NDIS filter driver and stores it in 18 | /// the provided `filter_table` argument. 19 | /// 20 | /// # Type Parameters 21 | /// 22 | /// * `N`: The size of the static filter table. 23 | /// 24 | /// # Arguments 25 | /// 26 | /// * `filter_table`: A mutable reference to a `StaticFilterTable` object, which will store the 27 | /// queried static filter table. 28 | /// 29 | /// # Returns 30 | /// 31 | /// * `Result<()>`: If successful, returns `Ok(())`. Otherwise, returns an error. 32 | pub fn get_packet_filter_table( 33 | &self, 34 | filter_table: &mut StaticFilterTable, 35 | ) -> Result<()> { 36 | let result = unsafe { 37 | DeviceIoControl( 38 | self.driver_handle, 39 | IOCTL_NDISRD_GET_PACKET_FILTERS, 40 | None, 41 | 0, 42 | Some(filter_table as *mut StaticFilterTable as *mut std::ffi::c_void), 43 | size_of::>() as u32, 44 | None, 45 | None, 46 | ) 47 | }; 48 | 49 | if !result.as_bool() { 50 | Err(unsafe { GetLastError() }.into()) 51 | } else { 52 | Ok(()) 53 | } 54 | } 55 | 56 | /// This function retrieves the static filter table from the NDIS filter driver, stores it in 57 | /// the provided `filter_table` argument, and resets the filter statistics. 58 | /// 59 | /// # Type Parameters 60 | /// 61 | /// * `N`: The size of the static filter table. 62 | /// 63 | /// # Arguments 64 | /// 65 | /// * `filter_table`: A mutable reference to a `StaticFilterTable` object, which will store the 66 | /// queried static filter table. 67 | /// 68 | /// # Returns 69 | /// 70 | /// * `Result<()>`: If successful, returns `Ok(())`. Otherwise, returns an error. 71 | pub fn get_packet_filter_table_reset_stats( 72 | &self, 73 | filter_table: &mut StaticFilterTable, 74 | ) -> Result<()> { 75 | let result = unsafe { 76 | DeviceIoControl( 77 | self.driver_handle, 78 | IOCTL_NDISRD_GET_PACKET_FILTERS_RESET_STATS, 79 | None, 80 | 0, 81 | Some(filter_table as *mut StaticFilterTable as *mut std::ffi::c_void), 82 | size_of::>() as u32, 83 | None, 84 | None, 85 | ) 86 | }; 87 | 88 | if !result.as_bool() { 89 | Err(unsafe { GetLastError() }.into()) 90 | } else { 91 | Ok(()) 92 | } 93 | } 94 | 95 | /// This function retrieves the size of the static filter table from the NDIS filter driver. 96 | /// 97 | /// # Returns 98 | /// 99 | /// * `Result`: If successful, returns the size of the static filter table as `Ok(usize)`. 100 | /// Otherwise, returns an error. 101 | pub fn get_packet_filter_table_size(&self) -> Result { 102 | let mut size = 0u32; 103 | 104 | let result = unsafe { 105 | DeviceIoControl( 106 | self.driver_handle, 107 | IOCTL_NDISRD_GET_PACKET_FILTERS_TABLESIZE, 108 | None, 109 | 0, 110 | Some(&mut size as *mut u32 as *mut std::ffi::c_void), 111 | size_of::() as u32, 112 | None, 113 | None, 114 | ) 115 | }; 116 | 117 | if !result.as_bool() { 118 | Err(unsafe { GetLastError() }.into()) 119 | } else { 120 | Ok(size as usize) 121 | } 122 | } 123 | 124 | /// This function resets the static filter table in the NDIS filter driver, effectively 125 | /// removing all filters from the table. 126 | /// 127 | /// # Returns 128 | /// 129 | /// * `Result<()>`: If successful, returns `Ok(())`. Otherwise, returns an error. 130 | pub fn reset_packet_filter_table(&self) -> Result<()> { 131 | let result = unsafe { 132 | DeviceIoControl( 133 | self.driver_handle, 134 | IOCTL_NDISRD_RESET_PACKET_FILTERS, 135 | None, 136 | 0, 137 | None, 138 | 0, 139 | None, 140 | None, 141 | ) 142 | }; 143 | 144 | if !result.as_bool() { 145 | Err(unsafe { GetLastError() }.into()) 146 | } else { 147 | Ok(()) 148 | } 149 | } 150 | 151 | /// This function takes a static filter table and sets it as the current filter table 152 | /// in the NDIS filter driver. 153 | /// 154 | /// # Type Parameters 155 | /// 156 | /// * `N`: The number of filters in the static filter table. 157 | /// 158 | /// # Arguments 159 | /// 160 | /// * `filter_table: &StaticFilterTable`: A reference to the static filter table to be loaded. 161 | /// 162 | /// # Returns 163 | /// 164 | /// * `Result<()>`: If successful, returns `Ok(())`. Otherwise, returns an error. 165 | pub fn set_packet_filter_table( 166 | &self, 167 | filter_table: &StaticFilterTable, 168 | ) -> Result<()> { 169 | let result = unsafe { 170 | DeviceIoControl( 171 | self.driver_handle, 172 | IOCTL_NDISRD_SET_PACKET_FILTERS, 173 | Some(filter_table as *const StaticFilterTable as *const std::ffi::c_void), 174 | size_of::>() as u32, 175 | None, 176 | 0, 177 | None, 178 | None, 179 | ) 180 | }; 181 | 182 | if !result.as_bool() { 183 | Err(unsafe { GetLastError() }.into()) 184 | } else { 185 | Ok(()) 186 | } 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /src/ndisapi/io_api.rs: -------------------------------------------------------------------------------- 1 | //! # Submodule: I/O functions 2 | //! 3 | //! This submodule defines a set of functions that interact with the NDIS filter driver. 4 | //! These functions include clearing the packet queue associated with a network adapter, 5 | //! retrieving the number of packets currently queued in the packet queue, reading single 6 | //! or multiple network packets from the NDIS filter driver, and sending single or multiple 7 | //! network packets to the NDIS filter driver to be passed down or up the network stack. 8 | //! This submodule also provides a function to set a Win32 event to be signaled by the 9 | //! NDIS filter when packets are available for read on a network adapter. 10 | //! 11 | 12 | use std::mem::size_of; 13 | 14 | use windows::{ 15 | core::Result, 16 | Win32::Foundation::{GetLastError, HANDLE}, 17 | Win32::System::IO::DeviceIoControl, 18 | }; 19 | 20 | use super::Ndisapi; 21 | use crate::driver::*; 22 | 23 | impl Ndisapi { 24 | /// This function clears the packet queue associated with the specified network adapter 25 | /// handle in the NDIS filter driver. 26 | /// 27 | /// # Arguments 28 | /// 29 | /// * `adapter_handle: HANDLE`: The handle of the network adapter whose packet queue 30 | /// should be flushed. 31 | /// 32 | /// # Returns 33 | /// 34 | /// * `Result<()>`: If successful, returns `Ok(())`. Otherwise, returns an error. 35 | pub fn flush_adapter_packet_queue(&self, adapter_handle: HANDLE) -> Result<()> { 36 | let result = unsafe { 37 | DeviceIoControl( 38 | self.driver_handle, 39 | IOCTL_NDISRD_FLUSH_ADAPTER_QUEUE, 40 | Some(&adapter_handle as *const HANDLE as *const std::ffi::c_void), 41 | size_of::() as u32, 42 | None, 43 | 0, 44 | None, 45 | None, 46 | ) 47 | }; 48 | 49 | if !result.as_bool() { 50 | Err(unsafe { GetLastError() }.into()) 51 | } else { 52 | Ok(()) 53 | } 54 | } 55 | 56 | /// This function retrieves the number of packets currently queued in the packet queue associated with the 57 | /// specified network adapter handle in the NDIS filter driver. 58 | /// 59 | /// # Arguments 60 | /// 61 | /// * `adapter_handle: HANDLE`: The handle of the network adapter whose packet queue size should be queried. 62 | /// 63 | /// # Returns 64 | /// 65 | /// * `Result`: If successful, returns `Ok(queue_size)` where `queue_size` is the number of packets in the 66 | /// adapter's packet queue. Otherwise, returns an error. 67 | pub fn get_adapter_packet_queue_size(&self, adapter_handle: HANDLE) -> Result { 68 | let mut queue_size = 0u32; 69 | 70 | let result = unsafe { 71 | DeviceIoControl( 72 | self.driver_handle, 73 | IOCTL_NDISRD_ADAPTER_QUEUE_SIZE, 74 | Some(&adapter_handle as *const HANDLE as *const std::ffi::c_void), 75 | size_of::() as u32, 76 | Some(&mut queue_size as *mut u32 as *mut std::ffi::c_void), 77 | size_of::() as u32, 78 | None, 79 | None, 80 | ) 81 | }; 82 | 83 | if !result.as_bool() { 84 | Err(unsafe { GetLastError() }.into()) 85 | } else { 86 | Ok(queue_size) 87 | } 88 | } 89 | 90 | /// This function retrieves a single network packet from the NDIS filter driver associated with 91 | /// the specified `EthRequest`. 92 | /// 93 | /// # Safety 94 | /// 95 | /// This function is unsafe because `EthRequest.packet` may not be initialized or might point to 96 | /// invalid memory. 97 | /// 98 | /// # Arguments 99 | /// 100 | /// * `packet: &mut EthRequest`: A mutable reference to the `EthRequest` structure that will be filled with 101 | /// the retrieved packet data. 102 | /// 103 | /// # Returns 104 | /// 105 | /// * `Result<()>`: If successful, returns `Ok(())`. Otherwise, returns an error. 106 | pub unsafe fn read_packet(&self, packet: &mut EthRequest) -> Result<()> { 107 | let result = unsafe { 108 | DeviceIoControl( 109 | self.driver_handle, 110 | IOCTL_NDISRD_READ_PACKET, 111 | Some(packet as *const EthRequest as *const std::ffi::c_void), 112 | size_of::() as u32, 113 | Some(packet as *mut EthRequest as *mut std::ffi::c_void), 114 | size_of::() as u32, 115 | None, 116 | None, 117 | ) 118 | }; 119 | 120 | if !result.as_bool() { 121 | Err(unsafe { GetLastError() }.into()) 122 | } else { 123 | Ok(()) 124 | } 125 | } 126 | 127 | /// This function retrieves a block of network packets from the NDIS filter driver associated with 128 | /// the specified `EthMRequest`. 129 | /// 130 | /// # Safety 131 | /// 132 | /// This function is unsafe because `EthMRequest.packets` may not be initialized or might point to 133 | /// invalid memory. 134 | /// 135 | /// # Arguments 136 | /// 137 | /// * `packets: &mut EthMRequest`: A mutable reference to the `EthMRequest` structure that will be filled with 138 | /// the retrieved packet data. 139 | /// 140 | /// # Returns 141 | /// 142 | /// * `Result`: If successful, returns `Ok(packet_count)` where `packet_count` is the number of packets read 143 | /// into `EthMRequest`. Otherwise, returns an error. 144 | pub unsafe fn read_packets( 145 | &self, 146 | packets: &mut EthMRequest, 147 | ) -> Result { 148 | let result = unsafe { 149 | DeviceIoControl( 150 | self.driver_handle, 151 | IOCTL_NDISRD_READ_PACKETS, 152 | Some(packets as *const EthMRequest as *const std::ffi::c_void), 153 | size_of::>() as u32, 154 | Some(packets as *mut EthMRequest as *mut std::ffi::c_void), 155 | size_of::>() as u32, 156 | None, 157 | None, 158 | ) 159 | }; 160 | 161 | if result.as_bool() { 162 | Ok(packets.get_packet_success() as usize) 163 | } else { 164 | Err(unsafe { GetLastError() }.into()) 165 | } 166 | } 167 | 168 | /// This function sends a single network packet to the NDIS filter driver associated with 169 | /// the specified `EthRequest`, which will then be passed down the network stack. 170 | /// 171 | /// # Safety 172 | /// 173 | /// This function is unsafe because `EthRequest.packet` may not be initialized or might point to 174 | /// invalid memory. 175 | /// 176 | /// # Arguments 177 | /// 178 | /// * `packet: &EthRequest`: A reference to the `EthRequest` structure containing the packet data to be sent. 179 | /// 180 | /// # Returns 181 | /// 182 | /// * `Result<()>`: If successful, returns `Ok(())`. Otherwise, returns an error. 183 | pub unsafe fn send_packet_to_adapter(&self, packet: &EthRequest) -> Result<()> { 184 | let result = unsafe { 185 | DeviceIoControl( 186 | self.driver_handle, 187 | IOCTL_NDISRD_SEND_PACKET_TO_ADAPTER, 188 | Some(packet as *const EthRequest as *const std::ffi::c_void), 189 | size_of::() as u32, 190 | None, 191 | 0, 192 | None, 193 | None, 194 | ) 195 | }; 196 | 197 | if !result.as_bool() { 198 | Err(unsafe { GetLastError() }.into()) 199 | } else { 200 | Ok(()) 201 | } 202 | } 203 | 204 | /// This function sends a single network packet to the NDIS filter driver associated with 205 | /// the specified `EthRequest`, which will then be passed down the network stack to the Microsoft TCP/IP stack. 206 | /// 207 | /// # Safety 208 | /// 209 | /// This function is unsafe because `EthRequest.packet` may not be initialized or might point to 210 | /// invalid memory. 211 | /// 212 | /// # Arguments 213 | /// 214 | /// * `packet: &EthRequest`: A reference to the `EthRequest` structure containing the packet data to be sent. 215 | /// 216 | /// # Returns 217 | /// 218 | /// * `Result<()>`: If successful, returns `Ok(())`. Otherwise, returns an error. 219 | pub unsafe fn send_packet_to_mstcp(&self, packet: &EthRequest) -> Result<()> { 220 | let result = unsafe { 221 | DeviceIoControl( 222 | self.driver_handle, 223 | IOCTL_NDISRD_SEND_PACKET_TO_MSTCP, 224 | Some(packet as *const EthRequest as *const std::ffi::c_void), 225 | size_of::() as u32, 226 | None, 227 | 0, 228 | None, 229 | None, 230 | ) 231 | }; 232 | 233 | if !result.as_bool() { 234 | Err(unsafe { GetLastError() }.into()) 235 | } else { 236 | Ok(()) 237 | } 238 | } 239 | 240 | /// This function sends a block of network packets to the NDIS filter driver associated with 241 | /// the specified `EthMRequest`, which will then be passed down the network stack. 242 | /// 243 | /// # Safety 244 | /// 245 | /// This function is unsafe because `EthMRequest.packets` may not be initialized or might point to 246 | /// invalid memory. 247 | /// 248 | /// # Arguments 249 | /// 250 | /// * `packets: &EthMRequest`: A reference to the `EthMRequest` structure containing the packet data to be sent. 251 | /// 252 | /// # Returns 253 | /// 254 | /// * `Result<()>`: If successful, returns `Ok(())`. Otherwise, returns an error. 255 | pub unsafe fn send_packets_to_adapter( 256 | &self, 257 | packets: &EthMRequest, 258 | ) -> Result<()> { 259 | let result = unsafe { 260 | DeviceIoControl( 261 | self.driver_handle, 262 | IOCTL_NDISRD_SEND_PACKETS_TO_ADAPTER, 263 | Some(packets as *const EthMRequest as *const std::ffi::c_void), 264 | size_of::>() as u32, 265 | None, 266 | 0, 267 | None, 268 | None, 269 | ) 270 | }; 271 | 272 | if !result.as_bool() { 273 | Err(unsafe { GetLastError() }.into()) 274 | } else { 275 | Ok(()) 276 | } 277 | } 278 | 279 | /// This function sends a block of network packets to the NDIS filter driver associated with 280 | /// the specified `EthMRequest`, which will then be passed up the network stack to the Microsoft TCP/IP stack. 281 | /// 282 | /// # Safety 283 | /// 284 | /// This function is unsafe because `EthMRequest.packets` may not be initialized or might point to 285 | /// invalid memory. 286 | /// 287 | /// # Arguments 288 | /// 289 | /// * `packets: &EthMRequest`: A reference to the `EthMRequest` structure containing the packet data to be sent. 290 | /// 291 | /// # Returns 292 | /// 293 | /// * `Result<()>`: If successful, returns `Ok(())`. Otherwise, returns an error. 294 | pub unsafe fn send_packets_to_mstcp( 295 | &self, 296 | packets: &EthMRequest, 297 | ) -> Result<()> { 298 | let result = unsafe { 299 | DeviceIoControl( 300 | self.driver_handle, 301 | IOCTL_NDISRD_SEND_PACKETS_TO_MSTCP, 302 | Some(packets as *const EthMRequest as *const std::ffi::c_void), 303 | size_of::>() as u32, 304 | None, 305 | 0, 306 | None, 307 | None, 308 | ) 309 | }; 310 | 311 | if !result.as_bool() { 312 | Err(unsafe { GetLastError() }.into()) 313 | } else { 314 | Ok(()) 315 | } 316 | } 317 | 318 | /// This function sets a Win32 event to be signaled by the NDIS filter when it has queued packets available for read 319 | /// on the specified network adapter. 320 | /// 321 | /// # Arguments 322 | /// 323 | /// * `adapter_handle: HANDLE`: The handle of the network adapter to associate the event with. 324 | /// * `event_handle: HANDLE`: The handle of the Win32 event to be signaled when queued packets are available. 325 | /// 326 | /// # Returns 327 | /// 328 | /// * `Result<()>`: If successful, returns `Ok(())`. Otherwise, returns an error. 329 | pub fn set_packet_event(&self, adapter_handle: HANDLE, event_handle: HANDLE) -> Result<()> { 330 | let adapter_event = AdapterEvent { 331 | adapter_handle, 332 | event_handle, 333 | }; 334 | 335 | let result = unsafe { 336 | DeviceIoControl( 337 | self.driver_handle, 338 | IOCTL_NDISRD_SET_EVENT, 339 | Some(&adapter_event as *const AdapterEvent as *const std::ffi::c_void), 340 | size_of::() as u32, 341 | None, 342 | 0, 343 | None, 344 | None, 345 | ) 346 | }; 347 | 348 | if !result.as_bool() { 349 | Err(unsafe { GetLastError() }.into()) 350 | } else { 351 | Ok(()) 352 | } 353 | } 354 | } 355 | -------------------------------------------------------------------------------- /src/ndisapi/static_api.rs: -------------------------------------------------------------------------------- 1 | //! # Submodule: Static NDISAPI functions 2 | //! 3 | //! This module provides utility functions for interacting with the Windows Registry related 4 | //! to NDIS Filter driver and network interfaces. It defines constants for various Registry keys, 5 | //! values, and data types that are used to access and modify settings related to network interfaces. 6 | //! It also contains an //! implementation of Ndisapi that includes functions for setting and retrieving 7 | //! Registry values related to NDIS filter driver and network interfaces. 8 | //! 9 | 10 | use windows::{ 11 | core::{Result, PCWSTR, PWSTR}, 12 | s, w, 13 | Win32::System::Registry::{ 14 | RegCloseKey, RegEnumKeyExW, RegOpenKeyExW, RegQueryValueExA, RegQueryValueExW, 15 | RegSetValueExW, HKEY, HKEY_LOCAL_MACHINE, KEY_READ, KEY_WRITE, REG_DWORD, REG_VALUE_TYPE, 16 | }, 17 | }; 18 | 19 | use super::Ndisapi; 20 | use std::str; 21 | 22 | /// The registry key path for the network control class. 23 | const REGSTR_NETWORK_CONTROL_CLASS: ::windows::core::PCWSTR = 24 | w!(r"SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}"); 25 | 26 | /// The name of the registry value. 27 | const REGSTR_VAL_NAME: ::windows::core::PCWSTR = w!("Name"); 28 | 29 | /// The name of the registry value containing the component ID. 30 | const REGSTR_COMPONENTID: ::windows::core::PCSTR = s!("ComponentId"); 31 | 32 | /// The name of the registry value containing the linkage information. 33 | const REGSTR_LINKAGE: ::windows::core::PCWSTR = w!("Linkage"); 34 | 35 | /// The name of the registry value containing the export information. 36 | const REGSTR_EXPORT: ::windows::core::PCSTR = s!("Export"); 37 | 38 | /// The name of the registry value containing the MTU decrement value. 39 | const REGSTR_MTU_DECREMENT: ::windows::core::PCWSTR = w!("MTUDecrement"); 40 | 41 | /// The name of the registry value containing the network adapter startup filter mode value. 42 | const REGSTR_STARTUP_MODE: ::windows::core::PCWSTR = w!("StartupMode"); 43 | 44 | /// The name of the registry value containing theintermediate buffer pool size multiplier. 45 | const REGSTR_POOL_SIZE: ::windows::core::PCWSTR = w!("PoolSize"); 46 | 47 | /// The component ID for the NDIS WAN IP driver. 48 | const REGSTR_COMPONENTID_NDISWANIP: &str = "ms_ndiswanip"; 49 | 50 | /// The component ID for the NDIS WAN IPv6 driver. 51 | const REGSTR_COMPONENTID_NDISWANIPV6: &str = "ms_ndiswanipv6"; 52 | 53 | /// The component ID for the NDIS WAN BH driver. 54 | const REGSTR_COMPONENTID_NDISWANBH: &str = "ms_ndiswanbh"; 55 | 56 | /// The user-friendly name for the NDIS WAN IP interface. 57 | const USER_NDISWANIP: &str = "WAN Network Interface (IP)"; 58 | 59 | /// The user-friendly name for the NDIS WAN BH interface. 60 | const USER_NDISWANBH: &str = "WAN Network Interface (BH)"; 61 | 62 | /// The user-friendly name for the NDIS WAN IPv6 interface. 63 | const USER_NDISWANIPV6: &str = "WAN Network Interface (IPv6)"; 64 | 65 | impl Ndisapi { 66 | /// Determines if a given network interface is an NDISWAN interface. 67 | /// 68 | /// This function enumerates all subkeys of the registry key `HKLM\SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}`, 69 | /// and looks for the specified `component_id` (e.g., "ms_ndiswanip", "ms_ndiswanipv6", "ms_ndiswanbh"). 70 | /// If a match is found, it checks the linkage subkey and export string to determine if the interface is an NDISWAN interface. 71 | /// 72 | /// # Arguments 73 | /// 74 | /// * `adapter_name: impl Into`: The name of the network adapter to check. 75 | /// * `component_id: &str`: The component ID to look for in the registry (e.g., "ms_ndiswanip", "ms_ndiswanipv6", "ms_ndiswanbh"). 76 | /// 77 | /// # Returns 78 | /// 79 | /// * `Result`: If successful, returns `Ok(true)` if the interface is an NDISWAN interface, `Ok(false)` otherwise. 80 | /// If an error occurs, returns an error. 81 | fn is_ndiswan_interface(adapter_name: impl Into, component_id: &str) -> Result { 82 | let adapter_name = adapter_name.into(); 83 | // Handles to registry keys 84 | let mut target_key = HKEY::default(); 85 | let mut connection_key = HKEY::default(); 86 | let mut linkage_key = HKEY::default(); 87 | 88 | let result = unsafe { 89 | RegOpenKeyExW( 90 | HKEY_LOCAL_MACHINE, 91 | REGSTR_NETWORK_CONTROL_CLASS, 92 | 0, 93 | KEY_READ, 94 | &mut target_key, 95 | ) 96 | }; 97 | 98 | if result.is_err() { 99 | return Err(result.into()); 100 | } 101 | 102 | // Counter for enumerating registry keys 103 | let mut index = 0u32; 104 | 105 | // Buffers for storing registry values 106 | let mut buffer = vec![0u16; 256]; 107 | let mut buffer_size = buffer.len() as u32; 108 | let mut temp_buffer = vec![0u8; 256]; 109 | let mut temp_buffer_size = temp_buffer.len() as u32; 110 | 111 | // Set to true if found 112 | let mut found = false; 113 | 114 | while !found { 115 | let result = unsafe { 116 | RegEnumKeyExW( 117 | target_key, 118 | index, 119 | PWSTR::from_raw(buffer.as_mut_ptr()), 120 | &mut buffer_size as *mut u32, 121 | None, 122 | PWSTR::null(), 123 | None, 124 | None, 125 | ) 126 | }; 127 | 128 | if !result.is_ok() { 129 | break; 130 | } else { 131 | let result = unsafe { 132 | RegOpenKeyExW( 133 | target_key, 134 | PCWSTR::from_raw(buffer.as_ptr()), 135 | 0, 136 | KEY_READ, 137 | &mut connection_key, 138 | ) 139 | }; 140 | 141 | if result.is_ok() { 142 | let mut value_type = REG_VALUE_TYPE::default(); 143 | let result = unsafe { 144 | RegQueryValueExA( 145 | connection_key, 146 | REGSTR_COMPONENTID, 147 | None, 148 | Some(&mut value_type), 149 | Some(temp_buffer.as_mut_ptr()), 150 | Some(&mut temp_buffer_size), 151 | ) 152 | }; 153 | 154 | if result.is_ok() { 155 | let comp_id = if let Ok(id) = 156 | str::from_utf8(&temp_buffer[..temp_buffer_size as usize]) 157 | { 158 | id.trim_end_matches(char::from(0)).to_string() 159 | } else { 160 | String::default() 161 | }; 162 | 163 | if comp_id.as_str() == component_id { 164 | temp_buffer_size = temp_buffer.len() as u32; 165 | let result = unsafe { 166 | RegOpenKeyExW( 167 | connection_key, 168 | REGSTR_LINKAGE, 169 | 0, 170 | KEY_READ, 171 | &mut linkage_key, 172 | ) 173 | }; 174 | 175 | if result.is_ok() { 176 | let result = unsafe { 177 | RegQueryValueExA( 178 | linkage_key, 179 | REGSTR_EXPORT, 180 | None, 181 | Some(&mut value_type), 182 | Some(temp_buffer.as_mut_ptr()), 183 | Some(&mut temp_buffer_size), 184 | ) 185 | }; 186 | 187 | if result.is_ok() { 188 | let export = if let Ok(id) = 189 | str::from_utf8(&temp_buffer[..temp_buffer_size as usize]) 190 | { 191 | id.trim_end_matches(char::from(0)).to_string() 192 | } else { 193 | String::default() 194 | }; 195 | 196 | if export.as_str().eq_ignore_ascii_case(adapter_name.as_str()) { 197 | found = true; 198 | } 199 | } 200 | unsafe { 201 | RegCloseKey(linkage_key); 202 | } 203 | } 204 | } 205 | unsafe { 206 | RegCloseKey(connection_key); 207 | } 208 | } 209 | temp_buffer_size = temp_buffer.len() as u32; 210 | } 211 | 212 | index += 1; 213 | buffer_size = buffer.len() as u32; 214 | } 215 | } 216 | 217 | unsafe { 218 | RegCloseKey(target_key); 219 | } 220 | 221 | Ok(found) 222 | } 223 | 224 | /// Determines if a given network interface is an NDISWANIP interface. 225 | /// 226 | /// This function checks if the specified network adapter is an NDISWANIP interface by calling `is_ndiswan_interface` 227 | /// with the component ID "ms_ndiswanip". 228 | /// 229 | /// # Arguments 230 | /// 231 | /// * `adapter_name: impl Into`: The name of the network adapter to check. 232 | /// 233 | /// # Returns 234 | /// 235 | /// * `bool`: Returns `true` if the interface is an NDISWANIP interface, `false` otherwise. 236 | pub fn is_ndiswan_ip(adapter_name: impl Into) -> bool { 237 | Self::is_ndiswan_interface(adapter_name.into(), REGSTR_COMPONENTID_NDISWANIP) 238 | .unwrap_or(false) 239 | } 240 | 241 | /// Determines if a given network interface is an NDISWANIPV6 interface. 242 | /// 243 | /// This function checks if the specified network adapter is an NDISWANIPV6 interface by calling `is_ndiswan_interface` 244 | /// with the component ID "ms_ndiswanipv6". 245 | /// 246 | /// # Arguments 247 | /// 248 | /// * `adapter_name: impl Into`: The name of the network adapter to check. 249 | /// 250 | /// # Returns 251 | /// 252 | /// * `bool`: Returns `true` if the interface is an NDISWANIPV6 interface, `false` otherwise. 253 | pub fn is_ndiswan_ipv6(adapter_name: impl Into) -> bool { 254 | Self::is_ndiswan_interface(adapter_name.into(), REGSTR_COMPONENTID_NDISWANIPV6) 255 | .unwrap_or(false) 256 | } 257 | 258 | /// Determines if a given network interface is an NDISWANBH interface. 259 | /// 260 | /// This function checks if the specified network adapter is an NDISWANBH interface by calling `is_ndiswan_interface` 261 | /// with the component ID "ms_ndiswanbh". 262 | /// 263 | /// # Arguments 264 | /// 265 | /// * `adapter_name: impl Into`: The name of the network adapter to check. 266 | /// 267 | /// # Returns 268 | /// 269 | /// * `bool`: Returns `true` if the interface is an NDISWANBH interface, `false` otherwise. 270 | pub fn is_ndiswan_bh(adapter_name: impl Into) -> bool { 271 | Self::is_ndiswan_interface(adapter_name.into(), REGSTR_COMPONENTID_NDISWANBH) 272 | .unwrap_or(false) 273 | } 274 | 275 | /// This function checks if the specified network adapter is an NDISWAN IP, IPv6, or BH interface, and if not, 276 | /// attempts to find the friendly name from the registry. 277 | /// 278 | /// # Arguments 279 | /// 280 | /// * `adapter_name: impl Into`: The system-level name of the network adapter to obtain the user-friendly name for. 281 | /// 282 | /// # Returns 283 | /// 284 | /// * `Result`: Returns a `Result` containing the user-friendly name of the network adapter if found, or an error otherwise. 285 | 286 | pub fn get_friendly_adapter_name(adapter_name: impl Into) -> Result { 287 | let mut adapter_name = adapter_name.into(); 288 | 289 | if Self::is_ndiswan_ip(adapter_name.as_str()) { 290 | return Ok(USER_NDISWANIP.into()); 291 | } 292 | 293 | if Self::is_ndiswan_ipv6(adapter_name.as_str()) { 294 | return Ok(USER_NDISWANIPV6.into()); 295 | } 296 | 297 | if Self::is_ndiswan_bh(adapter_name.as_str()) { 298 | return Ok(USER_NDISWANBH.into()); 299 | } 300 | 301 | // Trim the '\DEVICE\' prefix from the adapter system name 302 | adapter_name = adapter_name.replace("\\DEVICE\\", ""); 303 | 304 | let friendly_name_key = format!( 305 | "SYSTEM\\CurrentControlSet\\Control\\Network\\{{4D36E972-E325-11CE-BFC1-08002BE10318}}\\{}\\Connection", 306 | &adapter_name 307 | ); 308 | 309 | // Convert the string to UTF16 array and get a pointer to it as PCWSTR 310 | let mut friendly_name_key = friendly_name_key.encode_utf16().collect::>(); 311 | friendly_name_key.push(0); 312 | 313 | let mut hkey = HKEY::default(); 314 | 315 | let mut result = unsafe { 316 | RegOpenKeyExW( 317 | HKEY_LOCAL_MACHINE, 318 | PCWSTR::from_raw(friendly_name_key.as_ptr()), 319 | 0, 320 | KEY_READ, 321 | &mut hkey, 322 | ) 323 | }; 324 | 325 | let mut value_type = REG_VALUE_TYPE::default(); 326 | let mut data = vec![0u16; 256]; 327 | let mut data_size = data.len() as u32; 328 | let mut friendly_name = String::default(); 329 | 330 | if result.is_ok() { 331 | result = unsafe { 332 | RegQueryValueExW( 333 | hkey, 334 | REGSTR_VAL_NAME, 335 | None, 336 | Some(&mut value_type), 337 | Some(data.as_mut_ptr() as *const u8 as *mut u8), 338 | Some(&mut data_size), 339 | ) 340 | }; 341 | 342 | if result.is_ok() { 343 | friendly_name = if let Ok(name) = String::from_utf16(&data[..data_size as usize]) { 344 | name.trim_end_matches(char::from(0)).to_string() 345 | } else { 346 | String::default() 347 | } 348 | } 349 | 350 | unsafe { 351 | RegCloseKey(hkey); 352 | } 353 | } 354 | 355 | if !result.is_ok() { 356 | Err(result.into()) 357 | } else { 358 | Ok(friendly_name) 359 | } 360 | } 361 | 362 | /// This function sets a parameter in the registry key that the filter driver reads during its initialization. 363 | /// The value set in the registry is subtracted from the actual MTU (Maximum Transmission Unit) when it is requested 364 | /// by the MSTCP (Microsoft TCP/IP) from the network. Because this parameter is read during the initialization of the 365 | /// filter driver, a system reboot is required for the changes to take effect. Requires Administrator permissions. 366 | /// 367 | /// # Arguments 368 | /// 369 | /// * `mtu_decrement: u32` - The value to subtract from the actual MTU. 370 | /// 371 | /// # Returns 372 | /// 373 | /// * `Result<()>` - Returns a `Result` that is `Ok(())` if the MTU decrement value is set successfully in the registry, or an error otherwise. 374 | pub fn set_mtu_decrement(&self, mtu_decrement: u32) -> Result<()> { 375 | let mut hkey = HKEY::default(); 376 | 377 | let mut result = unsafe { 378 | RegOpenKeyExW( 379 | HKEY_LOCAL_MACHINE, 380 | self.get_driver_registry_key(), 381 | 0, 382 | KEY_WRITE, 383 | &mut hkey, 384 | ) 385 | }; 386 | 387 | if result.is_ok() { 388 | result = unsafe { 389 | RegSetValueExW( 390 | hkey, 391 | REGSTR_MTU_DECREMENT, 392 | 0, 393 | REG_DWORD, 394 | Some(mtu_decrement.to_ne_bytes().as_ref()), 395 | ) 396 | }; 397 | } 398 | 399 | if result.is_ok() { 400 | Ok(()) 401 | } else { 402 | Err(result.into()) 403 | } 404 | } 405 | 406 | /// This function retrieves the value set by `set_mtu_decrement` from the registry. Note that if you have not 407 | /// rebooted after calling `set_mtu_decrement`, the return value is meaningless. If `MTUDecrement` value is not 408 | /// present in the registry or an error occurred, then `None` is returned. 409 | /// 410 | /// # Returns 411 | /// 412 | /// * `Option` - Returns an `Option` containing the MTU decrement value if it is present in the registry and there are no errors, or `None` otherwise. 413 | pub fn get_mtu_decrement(&self) -> Option { 414 | let mut hkey = HKEY::default(); 415 | 416 | let mut result = unsafe { 417 | RegOpenKeyExW( 418 | HKEY_LOCAL_MACHINE, 419 | self.get_driver_registry_key(), 420 | 0, 421 | KEY_READ, 422 | &mut hkey, 423 | ) 424 | }; 425 | 426 | let mut value_type = REG_VALUE_TYPE::default(); 427 | let mtu_decrement = 0u32; 428 | let mut data_size = std::mem::size_of::() as u32; 429 | 430 | if result.is_ok() { 431 | result = unsafe { 432 | RegQueryValueExW( 433 | hkey, 434 | REGSTR_MTU_DECREMENT, 435 | None, 436 | Some(&mut value_type), 437 | Some(&mtu_decrement as *const u32 as *mut u8), 438 | Some(&mut data_size), 439 | ) 440 | }; 441 | } 442 | 443 | if result.is_ok() { 444 | Some(mtu_decrement) 445 | } else { 446 | None 447 | } 448 | } 449 | 450 | /// This routine sets the default mode to be applied to each adapter as soon as it appears in the system. 451 | /// It can be helpful in scenarios where you need to delay a network interface from operating until your 452 | /// application has started. However, it's essential to note that this API call requires a system reboot to take effect. 453 | /// Requires Administrator permissions to succeed. 454 | /// 455 | /// # Arguments 456 | /// 457 | /// * `startup_mode: u32` - The default startup mode to be applied to each adapter. 458 | /// 459 | /// # Returns 460 | /// 461 | /// * `Result<()>` - Returns a `Result` indicating whether the operation succeeded or an error occurred. 462 | pub fn set_adapters_startup_mode(&self, startup_mode: u32) -> Result<()> { 463 | let mut hkey = HKEY::default(); 464 | 465 | let mut result = unsafe { 466 | RegOpenKeyExW( 467 | HKEY_LOCAL_MACHINE, 468 | self.get_driver_registry_key(), 469 | 0, 470 | KEY_WRITE, 471 | &mut hkey, 472 | ) 473 | }; 474 | 475 | if result.is_ok() { 476 | result = unsafe { 477 | RegSetValueExW( 478 | hkey, 479 | REGSTR_STARTUP_MODE, 480 | 0, 481 | REG_DWORD, 482 | Some(startup_mode.to_ne_bytes().as_ref()), 483 | ) 484 | }; 485 | } 486 | 487 | if result.is_ok() { 488 | Ok(()) 489 | } else { 490 | Err(result.into()) 491 | } 492 | } 493 | 494 | /// Returns the current default filter mode value applied to each adapter when it appears in the system. 495 | /// Note that if you have not rebooted after calling SetAdaptersStartupMode, the return value is meaningless. 496 | /// 497 | /// # Returns 498 | /// 499 | /// * `Option` - Returns the current default startup mode as `Some(u32)` if the value is present in the registry, 500 | /// or `None` if the value is not present or an error occurred. 501 | pub fn get_adapters_startup_mode(&self) -> Option { 502 | let mut hkey = HKEY::default(); 503 | 504 | let mut result = unsafe { 505 | RegOpenKeyExW( 506 | HKEY_LOCAL_MACHINE, 507 | self.get_driver_registry_key(), 508 | 0, 509 | KEY_READ, 510 | &mut hkey, 511 | ) 512 | }; 513 | 514 | let mut value_type = REG_VALUE_TYPE::default(); 515 | let startup_mode = 0u32; 516 | let mut data_size = std::mem::size_of::() as u32; 517 | 518 | if result.is_ok() { 519 | result = unsafe { 520 | RegQueryValueExW( 521 | hkey, 522 | REGSTR_STARTUP_MODE, 523 | None, 524 | Some(&mut value_type), 525 | Some(&startup_mode as *const u32 as *mut u8), 526 | Some(&mut data_size), 527 | ) 528 | }; 529 | } 530 | 531 | if result.is_ok() { 532 | Some(startup_mode) 533 | } else { 534 | None 535 | } 536 | } 537 | 538 | /// Sets the pool size multiplier for Windows Packet Filter driver in the Windows registry. 539 | /// 540 | /// This function creates or modifies the PoolSize value in the registry based on the 541 | /// given value. The appropriate registry key is selected depending on the 542 | /// Windows platform (NT/2000/XP or 9x/ME). The resulting internal packet pool size 543 | /// will be equal to 2048 (512 for Windows version before Vista) * PoolSize packets. The maximum 544 | /// effective PoolSize is 10. 545 | /// 546 | /// # Arguments 547 | /// 548 | /// * `pool_size: u32` - The desired pool size multiplier to be set in the registry. 549 | /// 550 | /// # Returns 551 | /// 552 | /// * `Result<()>` - If the pool size multiplier is successfully set, returns `Ok(())`. 553 | /// Otherwise, returns an `Err` with the error code. 554 | pub fn set_pool_size(&self, pool_size: u32) -> Result<()> { 555 | let mut hkey = HKEY::default(); 556 | 557 | let mut result = unsafe { 558 | RegOpenKeyExW( 559 | HKEY_LOCAL_MACHINE, 560 | self.get_driver_registry_key(), 561 | 0, 562 | KEY_WRITE, 563 | &mut hkey, 564 | ) 565 | }; 566 | 567 | if result.is_ok() { 568 | result = unsafe { 569 | RegSetValueExW( 570 | hkey, 571 | REGSTR_POOL_SIZE, 572 | 0, 573 | REG_DWORD, 574 | Some(pool_size.to_ne_bytes().as_ref()), 575 | ) 576 | }; 577 | } 578 | 579 | if result.is_ok() { 580 | Ok(()) 581 | } else { 582 | Err(result.into()) 583 | } 584 | } 585 | 586 | /// Retrieves the pool size multiplier for the Windows Packet Filter driver from the Windows registry. 587 | /// 588 | /// This function queries the registry for the PoolSize value and returns it. 589 | /// The appropriate registry key is used depending on the Windows platform 590 | /// (NT/2000/XP or 9x/ME). The internal packet pool size is determined by 591 | /// 2048 * PoolSize packets. The maximum effective PoolSize is 10. 592 | /// 593 | /// # Returns 594 | /// 595 | /// * `Option` - The pool size multiplier retrieved from the registry. 596 | /// If the value is not found or an error occurs, returns `None`. 597 | pub fn get_pool_size(&self) -> Option { 598 | let mut hkey = HKEY::default(); 599 | 600 | let mut result = unsafe { 601 | RegOpenKeyExW( 602 | HKEY_LOCAL_MACHINE, 603 | self.get_driver_registry_key(), 604 | 0, 605 | KEY_READ, 606 | &mut hkey, 607 | ) 608 | }; 609 | 610 | let mut value_type = REG_VALUE_TYPE::default(); 611 | let pool_size = 0u32; 612 | let mut data_size = std::mem::size_of::() as u32; 613 | 614 | if result.is_ok() { 615 | result = unsafe { 616 | RegQueryValueExW( 617 | hkey, 618 | REGSTR_POOL_SIZE, 619 | None, 620 | Some(&mut value_type), 621 | Some(&pool_size as *const u32 as *mut u8), 622 | Some(&mut data_size), 623 | ) 624 | }; 625 | } 626 | 627 | if result.is_ok() { 628 | Some(pool_size) 629 | } else { 630 | None 631 | } 632 | } 633 | } 634 | -------------------------------------------------------------------------------- /src/net.rs: -------------------------------------------------------------------------------- 1 | /// This module provides a type for a MAC address, represented as a 6-byte array of unsigned 2 | /// integers. It implements `Display` and `Debug` traits for displaying a MAC address in the 3 | /// standard colon-separated format. 4 | /// 5 | /// # Example 6 | /// 7 | /// ``` 8 | /// use ndisapi::MacAddress; 9 | /// 10 | /// let mac = MacAddress::from_slice(&[0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC]).unwrap(); 11 | /// assert_eq!(format!("{}", mac), "12:34:56:78:9A:BC"); 12 | /// assert_eq!(format!("{:?}", mac), "12:34:56:78:9A:BC"); 13 | /// ``` 14 | use crate::driver::ETHER_ADDR_LENGTH; 15 | use std::fmt::{Debug, Display, Formatter, Result}; 16 | 17 | /// A MAC address represented as a 6-byte array of unsigned integers. 18 | #[derive(Default)] 19 | pub struct MacAddress([u8; ETHER_ADDR_LENGTH]); 20 | 21 | impl Display for MacAddress { 22 | fn fmt(&self, f: &mut Formatter<'_>) -> Result { 23 | write!( 24 | f, 25 | "{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}", 26 | self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5] 27 | ) 28 | } 29 | } 30 | 31 | impl Debug for MacAddress { 32 | fn fmt(&self, f: &mut Formatter<'_>) -> Result { 33 | write!( 34 | f, 35 | "{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}", 36 | self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5] 37 | ) 38 | } 39 | } 40 | 41 | impl MacAddress { 42 | /// Creates a new `MacAddress` instance from a slice of bytes. 43 | /// 44 | /// # Arguments 45 | /// 46 | /// * `slice` - A slice of bytes representing a MAC address. 47 | /// 48 | /// # Returns 49 | /// 50 | /// An `Option` containing a `MacAddress` instance if the slice has a length of `ETHER_ADDR_LENGTH` 51 | /// bytes, `None` otherwise. 52 | pub fn from_slice(slice: &[u8]) -> Option { 53 | let mut mac_address = MacAddress::default(); 54 | if slice.len() < ETHER_ADDR_LENGTH { 55 | None 56 | } else { 57 | mac_address.0.copy_from_slice(slice); 58 | Some(mac_address) 59 | } 60 | } 61 | 62 | /// Returns a reference to the internal byte array of the `MacAddress` instance. 63 | pub fn get(&self) -> &[u8; 6] { 64 | &self.0 65 | } 66 | 67 | /// Returns a mutable reference to the internal byte array of the `MacAddress` instance. 68 | pub fn get_mut(&mut self) -> &mut [u8; 6] { 69 | &mut self.0 70 | } 71 | } 72 | --------------------------------------------------------------------------------