├── .github ├── FUNDING.yml └── workflows │ └── check.yml ├── .gitignore ├── Cargo.toml ├── windivert-sys ├── wrapper.h ├── build │ ├── compile │ │ ├── mod.rs │ │ ├── gnu.rs │ │ └── msvc.rs │ └── main.rs ├── src │ ├── lib.rs │ └── bindings │ │ ├── error.rs │ │ ├── ioctl.rs │ │ ├── bitfield.rs │ │ ├── mod.rs │ │ ├── address.rs │ │ ├── header.rs │ │ └── newtypes.rs └── Cargo.toml ├── .gitmodules ├── windivert ├── src │ ├── lib.rs │ ├── layer.rs │ ├── packet.rs │ ├── error.rs │ ├── divert │ │ ├── mod.rs │ │ └── blocking.rs │ └── address.rs └── Cargo.toml ├── README.md ├── CHANGELOG.md └── LICENSE /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | ko_fi: rubensei -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Cargo.lock 2 | /target 3 | /bin 4 | /.vscode 5 | /.idea -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = ["windivert-sys", "windivert"] -------------------------------------------------------------------------------- /windivert-sys/wrapper.h: -------------------------------------------------------------------------------- 1 | #include "vendor/include/windivert.h" 2 | #include "vendor/include/windivert_device.h" -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "windivert-sys/vendor"] 2 | path = windivert-sys/vendor 3 | url = git@github.com:basil00/Divert.git 4 | -------------------------------------------------------------------------------- /windivert-sys/build/compile/mod.rs: -------------------------------------------------------------------------------- 1 | use cc::Build; 2 | 3 | mod gnu; 4 | mod msvc; 5 | 6 | pub fn lib() { 7 | if Build::new().get_compiler().is_like_gnu() { 8 | return gnu::lib(); 9 | } 10 | 11 | msvc::lib(); 12 | } 13 | 14 | pub fn dll() { 15 | if Build::new().get_compiler().is_like_gnu() { 16 | return gnu::dll(); 17 | } 18 | msvc::dll(); 19 | } 20 | -------------------------------------------------------------------------------- /windivert-sys/src/lib.rs: -------------------------------------------------------------------------------- 1 | /*! 2 | Raw FFI bindings for [WinDivert]. 3 | 4 | For more information, refer to [WinDivert's documentation]. 5 | 6 | [WinDivert]: https://www.reqrypt.org/windivert.html 7 | [WinDivert's documentation]: https://www.reqrypt.org/windivert-doc.html 8 | */ 9 | #[warn(missing_docs)] 10 | #[cfg(target_os = "windows")] 11 | mod bindings; 12 | 13 | #[cfg(target_os = "windows")] 14 | pub use bindings::*; 15 | -------------------------------------------------------------------------------- /windivert/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![deny(missing_docs)] 2 | /*! 3 | Wrapper around [`windivert_sys`] ffi crate. 4 | */ 5 | 6 | /// WinDivert address data structures 7 | pub mod address; 8 | mod divert; 9 | /// WinDivert error types 10 | pub mod error; 11 | /// Layer types used for typestate pattern 12 | pub mod layer; 13 | /// WinDivert packet types 14 | pub mod packet; 15 | 16 | pub use divert::*; 17 | 18 | /// Prelude module for [`WinDivert`]. 19 | pub mod prelude { 20 | pub use windivert_sys::{ 21 | WinDivertEvent, WinDivertFlags, WinDivertLayer, WinDivertParam, WinDivertShutdownMode, 22 | }; 23 | 24 | pub use crate::divert::*; 25 | pub use crate::error::*; 26 | pub use crate::layer::*; 27 | pub use crate::packet::*; 28 | } 29 | -------------------------------------------------------------------------------- /windivert-sys/src/bindings/error.rs: -------------------------------------------------------------------------------- 1 | use thiserror::Error; 2 | 3 | /** 4 | WinDivert error for unexpected values type conversions. 5 | */ 6 | #[derive(Debug, Error)] 7 | pub enum WinDivertValueError { 8 | /// Error produced for unexpected values in `TryFrom` for [`WinDivertLayer`](super::WinDivertLayer) 9 | #[error("Unexpected value for WinDivertLayer: {0}")] 10 | Layer(u32), 11 | /// Error produced for unexpected values in `TryFrom` for [`WinDivertEvent`](super::WinDivertEvent) 12 | #[error("Unexpected value for WinDivertEvent: {0}")] 13 | Event(u8), 14 | /// Error produced for unexpected values in `TryFrom` for [`WinDivertParameter`](super::WinDivertParam) 15 | #[error("Unexpected value for WinDivertParameter: {0}")] 16 | Parameter(u32), 17 | /// Error produced for unexpected values in `TryFrom` for [`WinDivertShutdownMode`](super::WinDivertShutdownMode) 18 | #[error("Unexpected value for WinDivertShutdownMode: {0}")] 19 | Shutdown(u32), 20 | } 21 | -------------------------------------------------------------------------------- /windivert-sys/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "windivert-sys" 3 | version = "0.10.0" 4 | description = "Raw FFI bindings for WinDivert user mode library" 5 | authors = ["Ruben Serrano Izquierdo "] 6 | repository = "https://github.com/Rubensei/windivert-rust.git" 7 | homepage = "https://github.com/Rubensei/windivert-rust" 8 | documentation = "https://docs.rs/windivert-sys" 9 | keywords = ["ffi", "windivert", "bindings", "driver"] 10 | categories = ["external-ffi-bindings"] 11 | readme = "../README.md" 12 | license = "LGPL-3.0-or-later" 13 | edition = "2021" 14 | rust-version = "1.68" 15 | links = "WinDivert" 16 | build = "build/main.rs" 17 | 18 | [lib] 19 | name = "windivert_sys" 20 | 21 | [features] 22 | default = [] 23 | vendored = [] 24 | static = ["vendored"] 25 | 26 | [dependencies] 27 | thiserror = "1" 28 | 29 | [dependencies.windows] 30 | version = "0.48" 31 | features = [ 32 | "Win32_Foundation", 33 | "Win32_System_IO", 34 | ] 35 | 36 | [build-dependencies] 37 | cc = "1.0" 38 | 39 | [package.metadata.docs.rs] 40 | default-target = "x86_64-pc-windows-msvc" 41 | -------------------------------------------------------------------------------- /windivert/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "windivert" 3 | version = "0.6.0" 4 | description = "Wrapper library around windivert-sys" 5 | authors = ["Ruben Serrano Izquierdo "] 6 | repository = "https://github.com/Rubensei/windivert-rust.git" 7 | homepage = "https://github.com/Rubensei/windivert-rust" 8 | keywords = ["ffi", "windivert", "bindings", "driver"] 9 | categories = ["external-ffi-bindings"] 10 | readme = "../README.md" 11 | license = "LGPL-3.0-or-later" 12 | edition = "2021" 13 | 14 | [features] 15 | default = [] 16 | vendored = ["windivert-sys/vendored"] 17 | static = ["vendored", "windivert-sys/static"] 18 | 19 | [dependencies] 20 | etherparse = "0.13" 21 | thiserror = "1" 22 | windivert-sys = { version = "0.10.0", path = "../windivert-sys" } 23 | 24 | [dependencies.windows] 25 | version = "0.48" 26 | features = [ 27 | "Devices_Custom", 28 | "Win32_Devices", 29 | "Win32_Foundation", 30 | "Win32_Security", 31 | "Win32_Storage_FileSystem", 32 | "Win32_System_Diagnostics", 33 | "Win32_System_IO", 34 | "Win32_System_Ioctl", 35 | "Win32_System_Services", 36 | "Win32_System_Threading", 37 | ] 38 | 39 | [package.metadata.docs.rs] 40 | default-target = "x86_64-pc-windows-msvc" -------------------------------------------------------------------------------- /windivert/src/layer.rs: -------------------------------------------------------------------------------- 1 | use windivert_sys::WinDivertLayer; 2 | 3 | /// Network type for typestate pattern. 4 | #[derive(Debug, Clone)] 5 | pub enum NetworkLayer {} 6 | /// Forward type for typestate pattern. 7 | #[derive(Debug, Clone)] 8 | pub enum ForwardLayer {} 9 | /// Flow type for typestate pattern. 10 | #[derive(Debug, Clone)] 11 | pub enum FlowLayer {} 12 | /// Socket type for typestate pattern. 13 | #[derive(Debug, Clone)] 14 | pub enum SocketLayer {} 15 | /// Reflect type for typestate pattern. 16 | #[derive(Debug, Clone)] 17 | pub enum ReflectLayer {} 18 | 19 | /// Trait for typestate pattern. 20 | pub trait WinDivertLayerTrait: sealed::Sealed + std::fmt::Debug + std::clone::Clone {} 21 | 22 | impl WinDivertLayerTrait for NetworkLayer {} 23 | 24 | impl WinDivertLayerTrait for ForwardLayer {} 25 | 26 | impl WinDivertLayerTrait for FlowLayer {} 27 | 28 | impl WinDivertLayerTrait for SocketLayer {} 29 | 30 | impl WinDivertLayerTrait for ReflectLayer {} 31 | 32 | impl WinDivertLayerTrait for WinDivertLayer {} 33 | 34 | impl WinDivertLayerTrait for () {} 35 | 36 | mod sealed { 37 | pub trait Sealed {} 38 | 39 | impl Sealed for () {} 40 | impl Sealed for super::NetworkLayer {} 41 | impl Sealed for super::ForwardLayer {} 42 | impl Sealed for super::FlowLayer {} 43 | impl Sealed for super::SocketLayer {} 44 | impl Sealed for super::ReflectLayer {} 45 | impl Sealed for super::WinDivertLayer {} 46 | } 47 | -------------------------------------------------------------------------------- /windivert-sys/src/bindings/ioctl.rs: -------------------------------------------------------------------------------- 1 | /*! 2 | WinDivert IOCTL types. 3 | 4 | This types are not used by this crate but some of them are used by the wrapper crate in order to implement wait variants for `recv` and `recv_ex`. 5 | */ 6 | #![allow(missing_docs)] 7 | 8 | #[repr(C)] 9 | #[derive(Copy, Clone)] 10 | pub union WINDIVERT_IOCTL { 11 | pub recv: WINDIVERT_IOCTL_RECV, 12 | pub send: WINDIVERT_IOCTL_SEND, 13 | pub initialize: WINDIVERT_IOCTL_INITIALIZE, 14 | pub startup: WINDIVERT_IOCTL_STARTUP, 15 | pub shutdown: WINDIVERT_IOCTL_SHUTDOWN, 16 | pub get_param: WINDIVERT_IOCTL_GET_PARAM, 17 | pub set_param: WINDIVERT_IOCTL_SET_PARAM, 18 | _union_align: [u8; 16usize], 19 | } 20 | 21 | #[repr(C, packed)] 22 | #[derive(Debug, Default, Copy, Clone)] 23 | pub struct WINDIVERT_IOCTL_RECV { 24 | pub addr: u64, 25 | pub addr_len_ptr: u64, 26 | } 27 | 28 | pub type WINDIVERT_IOCTL_SEND = WINDIVERT_IOCTL_RECV; 29 | 30 | #[repr(C, packed)] 31 | #[derive(Debug, Default, Copy, Clone)] 32 | pub struct WINDIVERT_IOCTL_INITIALIZE { 33 | pub layer: u32, 34 | pub priority: u32, 35 | pub flags: u64, 36 | } 37 | 38 | #[repr(C, packed)] 39 | #[derive(Debug, Default, Copy, Clone)] 40 | pub struct WINDIVERT_IOCTL_STARTUP { 41 | pub flags: u64, 42 | } 43 | 44 | #[repr(C, packed)] 45 | #[derive(Debug, Default, Copy, Clone)] 46 | pub struct WINDIVERT_IOCTL_SHUTDOWN { 47 | pub how: u32, 48 | } 49 | 50 | #[repr(C, packed)] 51 | #[derive(Debug, Default, Copy, Clone)] 52 | pub struct WINDIVERT_IOCTL_GET_PARAM { 53 | pub param: u32, 54 | } 55 | 56 | #[repr(C, packed)] 57 | #[derive(Debug, Default, Copy, Clone)] 58 | pub struct WINDIVERT_IOCTL_SET_PARAM { 59 | pub val: u64, 60 | pub param: u32, 61 | } 62 | -------------------------------------------------------------------------------- /windivert-sys/build/compile/gnu.rs: -------------------------------------------------------------------------------- 1 | use cc::Build; 2 | use std::process::{Command, Stdio}; 3 | use std::{env, fs}; 4 | 5 | pub fn lib() { 6 | let mut build = Build::new(); 7 | let out_dir = env::var("OUT_DIR").unwrap(); 8 | 9 | build 10 | .out_dir(&out_dir) 11 | .include(r#"vendor/include"#) 12 | .file(r#"vendor/dll/windivert.c"#); 13 | 14 | build.compile("WinDivert"); 15 | } 16 | 17 | pub fn dll() { 18 | let out_dir = env::var("OUT_DIR").unwrap(); 19 | let compiler = Build::new().get_compiler(); 20 | 21 | let mut cmd = compiler.to_command(); 22 | cmd.stdout(Stdio::inherit()).stderr(Stdio::inherit()); 23 | 24 | let mangle = if env::var("CARGO_CFG_TARGET_ARCH").unwrap() == "x86" { 25 | "_" 26 | } else { 27 | "" 28 | }; 29 | cmd.args(DYNAMIC_C_OPTIONS); 30 | cmd.arg(format!("-Wl,--entry=${mangle}WinDivertDllEntry")); 31 | cmd.args(["-c", "vendor/dll/windivert.c"]); 32 | cmd.args(["-o", &format!("{out_dir}/WinDivert.o")]); 33 | cmd.output().expect("Error compiling windivert c library"); 34 | 35 | let mut cmd = Build::new().get_compiler().to_command(); 36 | cmd.args(DYNAMIC_C_OPTIONS); 37 | cmd.args(["-o", &format!("{out_dir}/WinDivert.dll")]); 38 | cmd.args([ 39 | &format!("{out_dir}/WinDivert.o"), 40 | "vendor/dll/windivert.def", 41 | "-nostdlib", 42 | ]); 43 | cmd.args(DYNAMIC_C_INCLUDES); 44 | cmd.output().expect("Error building windivert dll"); 45 | 46 | let strip = Build::new() 47 | .get_compiler() 48 | .path() 49 | .to_string_lossy() 50 | .replace("gcc", "strip"); 51 | 52 | let mut strip = Command::new(strip); 53 | strip.stdout(Stdio::inherit()).stderr(Stdio::inherit()); 54 | 55 | strip.arg(&format!("{out_dir}/WinDivert.dll")); 56 | let _ = strip.output().expect("Error striping windivert dll"); 57 | 58 | let dlltool = Build::new() 59 | .get_compiler() 60 | .path() 61 | .to_string_lossy() 62 | .replace("gcc", "dlltool"); 63 | let mut dlltool = Command::new(dlltool); 64 | dlltool.stdout(Stdio::inherit()).stderr(Stdio::inherit()); 65 | 66 | dlltool.args(["--dllname", &format!("{out_dir}/WinDivert.dll")]); 67 | dlltool.args(["--def", "vendor/dll/windivert.def"]); 68 | dlltool.args(["--output-lib", &format!("{out_dir}/WinDivert.lib")]); 69 | let _ = dlltool.output().expect("Error building windivert lib"); 70 | 71 | let _ = fs::remove_file(format!("{out_dir}/WinDivert.o")); 72 | } 73 | 74 | const DYNAMIC_C_OPTIONS: &[&str] = &[ 75 | r#"-fno-ident"#, 76 | r#"-shared"#, 77 | r#"-Wall"#, 78 | r#"-Wno-pointer-to-int-cast"#, 79 | r#"-Os"#, 80 | r#"-Ivendor/include/"#, 81 | r#"-Wl,--enable-stdcall-fixup"#, 82 | ]; 83 | 84 | const DYNAMIC_C_INCLUDES: &[&str] = &[r#"-lkernel32"#, r#"-ladvapi32"#]; 85 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WinDivert 2 Rust Wrapper 2 | 3 | [![GitHub](https://img.shields.io/github/license/Rubensei/windivert-rust?color=blue)](https://raw.githubusercontent.com/Rubensei/windivert-rust/master/LICENSE) 4 | 5 | **Note**: This is a work in process, so the crates won't follow semantic 6 | versioning until 1.0.0 release, so any version change below 1.0.0 might 7 | introduce breaking changes in the API or the crate usage in general. 8 | 9 | This projects allows you to use 10 | [WinDivert](https://www.reqrypt.org/windivert.html) from rust. It consists of 11 | two crates: 12 | 13 | - `windivert-sys` 14 | [![crates.io](https://img.shields.io/crates/v/windivert-sys)](https://crates.io/crates/windivert-sys) 15 | [![docs](https://docs.rs/windivert-sys/badge.svg)](https://docs.rs/windivert-sys/) 16 | [![dependency status](https://deps.rs/repo/github/Rubensei/windivert-rust/status.svg?path=windivert-sys)](https://deps.rs/repo/github/Rubensei/windivert-rust?path=windivert-sys): 17 | Crate providing raw bindings to the WinDivert user mode library. 18 | - `windivert` 19 | [![crates.io](https://img.shields.io/crates/v/windivert)](https://crates.io/crates/windivert) 20 | [![docs](https://docs.rs/windivert/badge.svg)](https://docs.rs/windivert/) 21 | [![dependency status](https://deps.rs/repo/github/Rubensei/windivert-rust/status.svg?path=windivert)](https://deps.rs/repo/github/Rubensei/windivert-rust?path=windivert): 22 | (WIP) Built on top of `windivert-sys` and providing a friendlier Rust API and 23 | some abstractions. 24 | 25 | # Build 26 | 27 | To be able to build `windivert-sys` you require WinDivert library files: 28 | 29 | - It's recommended to specify the path of the folder containing downloaded dll, 30 | lib & sys files using the `WINDIVERT_PATH` environment variable. 31 | - As a fallback windivert dll & lib files can be compiled from source if the 32 | **vendored** feature is enabled. To avoid multiple compilations set 33 | `WINDIVERT_DLL_OUTPUT` environment variable to save the generated build. 34 | - It's possible to compile for statically linking to the windivert library by 35 | enabling the **static** feature. Static linking can also be enabled if the 36 | `WINDIVERT_STATIC` is set and it takes priority over the crate features. 37 | - **Any vendoring method will only compile the library. Sys files must always be 38 | provided.** 39 | 40 | # Usage 41 | 42 | - `windivert-sys` shares the same API the native library uses. Read 43 | [official documentation](https://www.reqrypt.org/windivert-doc.html) for more 44 | details. 45 | - `windivert` WIP 46 | 47 | **Note:** WinDivert dll expects the corresponding driver sys file to be located 48 | on the same folder. Since the dll lib & sys files come in the same folder when 49 | downloading from [official web](https://www.reqrypt.org/windivert.html) 50 | `windivert-sys` will search for it on the path provided with `WINDIVERT_PATH`. 51 | -------------------------------------------------------------------------------- /windivert-sys/build/main.rs: -------------------------------------------------------------------------------- 1 | mod compile; 2 | 3 | use std::{env, fs}; 4 | 5 | pub const LIB_PATH_ARG: &str = "WINDIVERT_PATH"; 6 | pub const DLL_OUTPUT_PATH_ARG: &str = "WINDIVERT_DLL_OUTPUT"; 7 | pub const STATIC_BUILD_ARG: &str = "WINDIVERT_STATIC"; 8 | 9 | fn main() { 10 | // Avoid build in docs.rs 11 | if env::var("DOCS_RS").is_ok() { 12 | return; 13 | } 14 | 15 | let out_dir = env::var("OUT_DIR").unwrap(); 16 | println!("cargo:rerun-if-env-changed={LIB_PATH_ARG}"); 17 | println!("cargo:rerun-if-env-changed={DLL_OUTPUT_PATH_ARG}"); 18 | println!("cargo:rerun-if-env-changed={STATIC_BUILD_ARG}"); 19 | 20 | let arch = match env::var("CARGO_CFG_TARGET_ARCH").unwrap().as_ref() { 21 | "x86" => "32", 22 | "x86_64" => "64", 23 | _ => panic!("Unsupported target architecture!"), 24 | }; 25 | 26 | // Prioritize environment variables over feature flags 27 | if env::var(STATIC_BUILD_ARG).is_ok() || cfg!(feature = "static") { 28 | println!("cargo:rerun-if-changed=wrapper.h"); 29 | compile::lib(); 30 | 31 | println!( 32 | "cargo:warning=WinDivert{arch}.sys must be located in the same path as the executable." 33 | ) 34 | } else if let Ok(lib_path) = env::var(LIB_PATH_ARG) { 35 | println!("cargo:rustc-link-search=native={lib_path}"); 36 | println!("cargo:rustc-link-search=native={out_dir}"); 37 | println!("cargo:rustc-link-lib=dylib=WinDivert"); 38 | handle_provided_dll(arch, &out_dir, &lib_path); 39 | } else if cfg!(feature = "vendored") { 40 | println!("cargo:rerun-if-changed=wrapper.h"); 41 | println!("cargo:rustc-link-search=native={out_dir}"); 42 | println!("cargo:rustc-link-lib=dylib=WinDivert"); 43 | compile::dll(); 44 | } else { 45 | panic!("Environment variable {LIB_PATH_ARG} not found and feature vendored not enabled, please provide the path to the WinDivert library files or enable the vendored feature to compile from source."); 46 | } 47 | } 48 | 49 | fn handle_provided_dll(arch: &str, out_dir: &str, lib_path: &str) { 50 | println!( 51 | "cargo:warning=Copying windivert dll, lib & sys files from the path provided if present." 52 | ); 53 | for f in fs::read_dir(lib_path).unwrap() { 54 | let file = f.unwrap(); 55 | if let Some(name) = file.file_name().to_str() { 56 | match name { 57 | "WinDivert.dll" | "WinDivert.lib" | "WinDivert32.sys" | "WinDivert64.sys" => { 58 | let _ = fs::copy(file.path(), format!("{out_dir}/{name}")); 59 | } 60 | _ => {} 61 | } 62 | } 63 | } 64 | 65 | if fs::metadata(format!("{lib_path}\\WinDivert{arch}.sys")).is_err() { 66 | println!("cargo:warning=WinDivert{arch}.sys not found on the same directory as the dll.") 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /windivert-sys/src/bindings/bitfield.rs: -------------------------------------------------------------------------------- 1 | #[repr(C)] 2 | #[derive(Copy, Clone, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] 3 | pub struct BitfieldUnit { 4 | storage: Storage, 5 | align: [Align; 0], 6 | } 7 | 8 | impl BitfieldUnit { 9 | #[inline] 10 | #[allow(dead_code)] 11 | pub const fn new(storage: Storage) -> Self { 12 | Self { storage, align: [] } 13 | } 14 | } 15 | 16 | impl BitfieldUnit 17 | where 18 | Storage: AsRef<[u8]> + AsMut<[u8]>, 19 | { 20 | #[inline] 21 | pub fn get_bit(&self, index: usize) -> bool { 22 | debug_assert!(index / 8 < self.storage.as_ref().len()); 23 | let byte_index = index / 8; 24 | let byte = self.storage.as_ref()[byte_index]; 25 | let bit_index = if cfg!(target_endian = "big") { 26 | 7 - (index % 8) 27 | } else { 28 | index % 8 29 | }; 30 | let mask = 1 << bit_index; 31 | byte & mask == mask 32 | } 33 | #[inline] 34 | pub fn set_bit(&mut self, index: usize, val: bool) { 35 | debug_assert!(index / 8 < self.storage.as_ref().len()); 36 | let byte_index = index / 8; 37 | let byte = &mut self.storage.as_mut()[byte_index]; 38 | let bit_index = if cfg!(target_endian = "big") { 39 | 7 - (index % 8) 40 | } else { 41 | index % 8 42 | }; 43 | let mask = 1 << bit_index; 44 | if val { 45 | *byte |= mask; 46 | } else { 47 | *byte &= !mask; 48 | } 49 | } 50 | #[inline] 51 | pub fn get(&self, bit_offset: usize, bit_width: u8) -> u64 { 52 | debug_assert!(bit_width <= 64); 53 | debug_assert!(bit_offset / 8 < self.storage.as_ref().len()); 54 | debug_assert!((bit_offset + (bit_width as usize)) / 8 <= self.storage.as_ref().len()); 55 | let mut val = 0; 56 | for i in 0..(bit_width as usize) { 57 | if self.get_bit(i + bit_offset) { 58 | let index = if cfg!(target_endian = "big") { 59 | bit_width as usize - 1 - i 60 | } else { 61 | i 62 | }; 63 | val |= 1 << index; 64 | } 65 | } 66 | val 67 | } 68 | #[inline] 69 | pub fn set(&mut self, bit_offset: usize, bit_width: u8, val: u64) { 70 | debug_assert!(bit_width <= 64); 71 | debug_assert!(bit_offset / 8 < self.storage.as_ref().len()); 72 | debug_assert!((bit_offset + (bit_width as usize)) / 8 <= self.storage.as_ref().len()); 73 | for i in 0..(bit_width as usize) { 74 | let mask = 1 << i; 75 | let val_bit_is_set = val & mask == mask; 76 | let index = if cfg!(target_endian = "big") { 77 | bit_width as usize - 1 - i 78 | } else { 79 | i 80 | }; 81 | self.set_bit(index + bit_offset, val_bit_is_set); 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /windivert/src/packet.rs: -------------------------------------------------------------------------------- 1 | use windivert_sys::{ChecksumFlags, WinDivertHelperCalcChecksums}; 2 | 3 | use crate::{address::WinDivertAddress, layer, prelude::WinDivertError}; 4 | 5 | use std::{ 6 | borrow::{BorrowMut, Cow}, 7 | ffi::c_void, 8 | fmt::Debug, 9 | }; 10 | 11 | /// Raw captured packet 12 | #[derive(Debug, Clone)] 13 | pub struct WinDivertPacket<'a, L: layer::WinDivertLayerTrait> { 14 | /// Address data 15 | pub address: WinDivertAddress, 16 | /// Raw captured data 17 | pub data: Cow<'a, [u8]>, 18 | } 19 | 20 | impl<'a> WinDivertPacket<'a, layer::NetworkLayer> { 21 | /// Create a new network packet from a raw buffer 22 | /// # Safety 23 | /// `address` is zeroed, user must fill it with correct data before sending. 24 | pub unsafe fn new(data: Vec) -> Self { 25 | Self { 26 | address: WinDivertAddress::::new(), 27 | data: Cow::from(data), 28 | } 29 | } 30 | 31 | /// Recalculate the checksums of the packet 32 | /// This is a noop if the packet is not owned. 33 | pub fn recalculate_checksums(&mut self, flags: ChecksumFlags) -> Result<(), WinDivertError> { 34 | if let Cow::Owned(ref mut data) = self.data.borrow_mut() { 35 | let res = unsafe { 36 | WinDivertHelperCalcChecksums( 37 | data.as_mut_ptr() as *mut c_void, 38 | data.len() as u32, 39 | self.address.as_mut(), 40 | flags, 41 | ) 42 | }; 43 | if !res.as_bool() { 44 | return Err(WinDivertError::from(windows::core::Error::from_win32())); 45 | } 46 | } 47 | Ok(()) 48 | } 49 | } 50 | 51 | impl<'a> WinDivertPacket<'a, layer::ForwardLayer> { 52 | /// Create a new network forward packet from a raw buffer 53 | /// # Safety 54 | /// `address` is zeroed, user must fill it with correct data before sending. 55 | pub unsafe fn new(data: Vec) -> Self { 56 | Self { 57 | address: WinDivertAddress::::new(), 58 | data: Cow::from(data), 59 | } 60 | } 61 | 62 | /// Recalculate the checksums of the packet 63 | /// This is a noop if the packet is not owned. 64 | pub fn recalculate_checksums(&mut self, flags: ChecksumFlags) -> Result<(), WinDivertError> { 65 | if let Cow::Owned(ref mut data) = self.data.borrow_mut() { 66 | let res = unsafe { 67 | WinDivertHelperCalcChecksums( 68 | data.as_mut_ptr() as *mut c_void, 69 | data.len() as u32, 70 | self.address.as_mut(), 71 | flags, 72 | ) 73 | }; 74 | if !res.as_bool() { 75 | return Err(WinDivertError::from(windows::core::Error::from_win32())); 76 | } 77 | } 78 | Ok(()) 79 | } 80 | } 81 | 82 | impl<'a, L: layer::WinDivertLayerTrait> WinDivertPacket<'a, L> { 83 | /// Create an owned packet from a borrowed packet 84 | pub fn into_owned(self) -> WinDivertPacket<'static, L> { 85 | WinDivertPacket { 86 | address: self.address, 87 | data: self.data.into_owned().into(), 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to 7 | [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 8 | 9 | ## [Unreleased] 10 | 11 | ## [Unreleased-sys] 12 | 13 | ### Fixed 14 | 15 | - Cross compilation path issues in `windivert-sys` gnu build script. 16 | 17 | ## [0.6.0] 18 | 19 | ### Added 20 | 21 | - Add `static` feature to statically link to windivert library. 22 | 23 | ## [sys-0.10.0] 24 | 25 | ### Added 26 | 27 | - Add `WinDivertFlags::_default` methods. 28 | - Add `static` feature to statically link to windivert library. 29 | 30 | ### Changed 31 | 32 | - Refactor build scripts. 33 | 34 | ## [sys-0.9.3] - 2023-04-03 35 | 36 | ### Fixed 37 | 38 | - Fix wrong comparison in `MF` and `DF` flag getters 39 | 40 | ## [sys-0.9.2] - 2023-03-23 41 | 42 | ### Fixed 43 | 44 | - Downgrade windows to `0.43` to avoid build issues with `windivert` due to 45 | different windows versions 46 | 47 | ## [0.5.5] - 2023-03-23 48 | 49 | ### Fixed 50 | 51 | - Fix `close` errors due to double inner close call 52 | 53 | ### Added 54 | 55 | - Add `WinDivert::<()>::MAX_BATCH` 56 | 57 | ## [sys-0.9.1] - 2023-02-06 58 | 59 | ### Fixed 60 | 61 | - Fix logic error in bitflag methods 62 | ([#2](https://github.com/Rubensei/windivert-rust/issues/2)) 63 | - Fix incorrect links in documentation 64 | ([#3](https://github.com/Rubensei/windivert-rust/issues/3)) 65 | 66 | ## [0.5.3] - 2023-01-07 67 | 68 | ### Fixed 69 | 70 | - Fix `send_ex` error due to incorrect use of iterator. 71 | 72 | ## [0.5.3] - 2023-01-03 73 | 74 | ### Changed 75 | 76 | - Add Debug and Clone trait bounds to the types used for typestate pattern 77 | 78 | ## [sys-0.9.0] - 2022-12-21 79 | 80 | ### Added 81 | 82 | - Initial tagged release 83 | 84 | ## [0.5.1] - 2022-12-21 85 | 86 | ### Changed 87 | 88 | - Make typestate types public 89 | 90 | ## [0.5.0] - 2022-12-21 91 | 92 | ### Added 93 | 94 | - Initial tagged release 95 | 96 | [unreleased]: https://github.com/Rubensei/windivert-rust/compare/windivert-0.6.0...HEAD 97 | [unreleased-sys]: https://github.com/Rubensei/windivert-rust/compare/windivert-sys-0.10.0...HEAD 98 | [0.6.0]: https://github.com/Rubensei/windivert-rust/compare/windivert-0.5.5...windivert-0.6.0 99 | [sys-0.10.0]: https://github.com/Rubensei/windivert-rust/compare/windivert-sys-0.9.3...windivert-sys-0.10.0 100 | [sys-0.9.3]: https://github.com/Rubensei/windivert-rust/compare/windivert-sys-0.9.2...windivert-sys-0.9.3 101 | [sys-0.9.2]: https://github.com/Rubensei/windivert-rust/compare/windivert-sys-0.9.1...windivert-sys-0.9.2 102 | [0.5.5]: https://github.com/Rubensei/windivert-rust/compare/windivert-0.5.4...windivert-0.5.5 103 | [sys-0.9.1]: https://github.com/Rubensei/windivert-rust/compare/windivert-sys-0.9.0...windivert-sys-0.9.1 104 | [0.5.4]: https://github.com/Rubensei/windivert-rust/compare/windivert-0.5.3...windivert-0.5.4 105 | [0.5.3]: https://github.com/Rubensei/windivert-rust/compare/windivert-0.5.1...windivert-0.5.3 106 | [sys-0.9.0]: https://github.com/Rubensei/windivert-rust/releases/tag/windivert-sys-0.9.0 107 | [0.5.1]: https://github.com/Rubensei/windivert-rust/compare/windivert-0.5.0...windivert-0.5.1 108 | [0.5.0]: https://github.com/Rubensei/windivert-rust/releases/tag/windivert-0.5.0 109 | -------------------------------------------------------------------------------- /.github/workflows/check.yml: -------------------------------------------------------------------------------- 1 | permissions: 2 | contents: read 3 | 4 | on: 5 | push: 6 | branches: [master, dev] 7 | pull_request: {} 8 | workflow_dispatch: {} 9 | 10 | concurrency: 11 | group: ${{ github.workflow }}-${{ github.head_ref || github.ref_name || github.run_id }} 12 | cancel-in-progress: true 13 | 14 | name: CI 15 | jobs: 16 | check: 17 | runs-on: windows-latest 18 | name: ${{matrix.feature}} / ${{ matrix.compiler }} 19 | strategy: 20 | fail-fast: false 21 | matrix: 22 | compiler: [msvc, gnu] 23 | feature: [vendored, static] 24 | steps: 25 | - uses: actions/checkout@v4 26 | with: 27 | submodules: true 28 | - name: Install stable 29 | uses: dtolnay/rust-toolchain@stable 30 | id: toolchain 31 | with: 32 | targets: x86_64-pc-windows-${{ matrix.compiler }} 33 | - uses: Swatinem/rust-cache@v2 34 | with: 35 | key: ${{ steps.toolchain.outputs.cachekey }}-${{ matrix.compiler }} 36 | - name: cargo check 37 | run: cargo check --target x86_64-pc-windows-${{ matrix.compiler }} --features ${{ matrix.feature }} 38 | - name: Semver checks 39 | uses: obi1kenobi/cargo-semver-checks-action@v2 40 | with: 41 | shared-key: ${{ steps.toolchain.outputs.cachekey }}-${{ matrix.compiler }} 42 | 43 | cross-compile: 44 | runs-on: ubuntu-latest 45 | name: GNU cross compilation / ${{matrix.feature}} 46 | needs: [check] 47 | strategy: 48 | fail-fast: false 49 | matrix: 50 | feature: [vendored, static] 51 | steps: 52 | - uses: actions/checkout@v4 53 | with: 54 | submodules: true 55 | - name: Install MinGW toolchain 56 | run: | 57 | sudo apt-get update 58 | sudo apt-get install -y mingw-w64 59 | - name: Install stable 60 | uses: dtolnay/rust-toolchain@stable 61 | id: toolchain 62 | with: 63 | targets: x86_64-pc-windows-gnu 64 | - uses: Swatinem/rust-cache@v2 65 | with: 66 | key: ${{ steps.toolchain.outputs.cachekey }} 67 | - name: cargo check 68 | run: cargo check --target x86_64-pc-windows-gnu --features ${{ matrix.feature }} 69 | 70 | doc: 71 | runs-on: windows-latest 72 | name: docs / stable 73 | steps: 74 | - uses: actions/checkout@v4 75 | with: 76 | submodules: true 77 | - name: Install stable 78 | uses: dtolnay/rust-toolchain@stable 79 | id: toolchain 80 | - uses: Swatinem/rust-cache@v2 81 | with: 82 | key: ${{ steps.toolchain.outputs.cachekey }} 83 | - name: cargo doc 84 | run: cargo doc --no-deps --all-features 85 | env: 86 | DOCS_RS: true 87 | RUSTDOCFLAGS: --cfg docsrs 88 | 89 | msrv: 90 | runs-on: windows-latest 91 | name: msrv / ${{ matrix.msrv }} 92 | strategy: 93 | fail-fast: false 94 | matrix: 95 | msrv: ["1.68"] 96 | steps: 97 | - uses: actions/checkout@v4 98 | with: 99 | submodules: true 100 | - name: Install stable 101 | uses: dtolnay/rust-toolchain@master 102 | id: toolchain 103 | with: 104 | toolchain: ${{ matrix.msrv }} 105 | - uses: Swatinem/rust-cache@v2 106 | with: 107 | key: ${{ steps.toolchain.outputs.cachekey }} 108 | - name: cargo +${{ matrix.msrv }} check 109 | run: cargo check --all-features 110 | -------------------------------------------------------------------------------- /windivert-sys/build/compile/msvc.rs: -------------------------------------------------------------------------------- 1 | use cc::Build; 2 | use std::{env, fs}; 3 | 4 | use crate::DLL_OUTPUT_PATH_ARG; 5 | 6 | pub fn lib() { 7 | let mut build = Build::new(); 8 | let out_dir = env::var("OUT_DIR").unwrap(); 9 | 10 | build 11 | .out_dir(&out_dir) 12 | .include(r#"vendor\include"#) 13 | .file(r#"vendor\dll\windivert.c"#); 14 | 15 | for &flag in STATIC_CL_ARGS { 16 | build.flag(flag); 17 | } 18 | build.compile("WinDivert"); 19 | } 20 | 21 | pub fn dll() { 22 | let out_dir = env::var("OUT_DIR").unwrap(); 23 | let mut compiler = Build::new().get_compiler().to_command(); 24 | 25 | let arch = match env::var("CARGO_CFG_TARGET_ARCH").unwrap().as_ref() { 26 | "x86" => "x86", 27 | "x86_64" => "x64", 28 | _ => panic!("Unsupported target architecture!"), 29 | }; 30 | 31 | for &flag in DYNAMIC_CL_ARGS { 32 | compiler.arg(flag); 33 | } 34 | 35 | compiler.arg(&format!("/MACHINE:{arch}")); 36 | 37 | compiler.arg(&format!(r#"/PDB:{out_dir}\WinDivertDll.pdb"#)); 38 | compiler.arg(&format!(r#"/OUT:{out_dir}\WinDivert.dll"#)); 39 | compiler.arg(&format!(r#"/IMPLIB:{out_dir}\WinDivert.lib"#)); 40 | 41 | if let Ok(out) = compiler.output() { 42 | if !out.status.success() { 43 | panic!( 44 | "\nERROR: {:?}\n{}\n", 45 | &out.status, 46 | String::from_utf8_lossy(&out.stdout), 47 | ) 48 | } 49 | } else { 50 | panic!("Error compiling windivert dll."); 51 | } 52 | 53 | if let Ok(dylib_save_dir) = env::var(DLL_OUTPUT_PATH_ARG) { 54 | let _ = fs::copy( 55 | format!(r#"{out_dir}\WinDivert.dll"#), 56 | format!(r#"{dylib_save_dir}\WinDivert.dll"#), 57 | ); 58 | let _ = fs::copy( 59 | format!(r#"{out_dir}\WinDivert.lib"#), 60 | format!(r#"{dylib_save_dir}\WinDivert.lib"#), 61 | ); 62 | } else { 63 | println!("cargo:warning=Environment variable {DLL_OUTPUT_PATH_ARG} not found, compiled dll & lib files will be stored on {out_dir}"); 64 | }; 65 | } 66 | 67 | const DYNAMIC_CL_ARGS: &[&str] = &[ 68 | r#"/Ivendor\include"#, 69 | r#"/ZI"#, 70 | r#"/JMC"#, 71 | r#"/nologo"#, 72 | r#"/W1"#, 73 | r#"/WX-"#, 74 | r#"/diagnostics:column"#, 75 | r#"/O1"#, 76 | r#"/Oi"#, 77 | r#"/Gm-"#, 78 | r#"/EHsc"#, 79 | r#"/MDd"#, 80 | r#"/GS-"#, 81 | r#"/fp:precise"#, 82 | r#"/Zc:wchar_t"#, 83 | r#"/Zc:forScope"#, 84 | r#"/Zc:inline"#, 85 | r#"/Gd"#, 86 | r#"/TC"#, 87 | r#"/FC"#, 88 | r#"/errorReport:queue"#, 89 | r#"vendor\dll\windivert.c"#, 90 | r#"/link"#, 91 | r#"/ERRORREPORT:QUEUE"#, 92 | r#"/INCREMENTAL"#, 93 | r#"/NOLOGO"#, 94 | r#"kernel32.lib"#, 95 | r#"advapi32.lib"#, 96 | r#"/NODEFAULTLIB"#, 97 | r#"/DEF:vendor/dll/windivert.def"#, 98 | r#"/MANIFEST"#, 99 | r#"/manifest:embed"#, 100 | r#"/DEBUG:FASTLINK"#, 101 | r#"/TLDLIB:1"#, 102 | r#"/ENTRY:"WinDivertDllEntry""#, 103 | r#"/DYNAMICBASE"#, 104 | r#"/NXCOMPAT"#, 105 | r#"/DLL"#, 106 | ]; 107 | 108 | const STATIC_CL_ARGS: &[&str] = &[ 109 | r#"/nologo"#, 110 | r#"/WX-"#, 111 | r#"/diagnostics:column"#, 112 | r#"/O1"#, 113 | r#"/Oi"#, 114 | r#"/EHsc"#, 115 | r#"/GS-"#, 116 | r#"/fp:precise"#, 117 | r#"/Zc:wchar_t"#, 118 | r#"/Zc:forScope"#, 119 | r#"/Zc:inline"#, 120 | r#"/Gd"#, 121 | r#"/TC"#, 122 | r#"/FC"#, 123 | r#"/errorReport:queue"#, 124 | ]; 125 | -------------------------------------------------------------------------------- /windivert/src/error.rs: -------------------------------------------------------------------------------- 1 | use std::convert::TryFrom; 2 | use std::ffi::NulError; 3 | 4 | use thiserror::Error; 5 | use windivert_sys::{WinDivertParam, WinDivertValueError}; 6 | 7 | /** 8 | WinDivert error type. 9 | */ 10 | #[derive(Debug, Error)] 11 | pub enum WinDivertError { 12 | /// Unexpected value in type conversions. 13 | #[error(transparent)] 14 | Value(#[from] WinDivertValueError), 15 | /// Specific errors for divert constructor invocation. 16 | #[error(transparent)] 17 | Open(#[from] WinDivertOpenError), 18 | /// Specific errors for [`WinDivert::recv()`](fn@super::WinDivert::::recv). 19 | #[error(transparent)] 20 | Recv(#[from] WinDivertRecvError), 21 | /// Error for nul terminated filter strings. 22 | #[error(transparent)] 23 | NullError(#[from] NulError), 24 | /// Generic IO error. 25 | #[error(transparent)] 26 | IOError(#[from] std::io::Error), 27 | /// Generic OS error. 28 | #[error(transparent)] 29 | OSError(#[from] windows::core::Error), 30 | /// Error indicating that a wrong parameter was used in [`set_param()`](fn@crate::WinDivert::set_param) 31 | #[error("Invalid parameter for set_param(). Parameter: {0:?}, Value: {1}")] 32 | Parameter(WinDivertParam, u64), 33 | } 34 | 35 | /** 36 | Possible errors for [`WinDivertOpen()`](fn@windivert_sys::WinDivertOpen) 37 | */ 38 | #[derive(Debug, Error)] 39 | pub enum WinDivertOpenError { 40 | /// The driver files WinDivert32.sys or WinDivert64.sys were not found. 41 | #[error("SYS driver file not found")] 42 | MissingSYS, // 2 43 | /// The calling application does not have Administrator privileges. 44 | #[error("Running without elevated access rights")] 45 | AccessDenied, // 5 46 | /// This indicates an invalid packet filter string, layer, priority, or flags. 47 | #[error("Invalid parameter (filter string, layer, priority, or flags)")] 48 | InvalidParameter, // 87 49 | /// The WinDivert32.sys or WinDivert64.sys driver does not have a valid digital signature. 50 | #[error("SYS driver file has invalid digital signature")] 51 | InvalidImageHash, // 577 52 | /// An incompatible version of the WinDivert driver is currently loaded. 53 | #[error("An incompatible version of the WinDivert driver is currently loaded")] 54 | IncompatibleVersion, // 654 55 | /// The handle was opened with the WINDIVERT_FLAG_NO_INSTALL flag and the WinDivert driver is not already installed. 56 | #[error("The handle was opened with the WINDIVERT_FLAG_NO_INSTALL flag and the WinDivert driver is not already installed")] 57 | MissingInstall, // 1060 58 | /// The WinDivert driver is blocked by security software or you are using a virtualization environment that does not support drivers. 59 | #[error("WinDivert driver is blocked by security software or you are using a virtualization environment that does not support drivers")] 60 | DriverBlocked, // 1257 61 | /// This error occurs when the Base Filtering Engine service has been disabled. 62 | #[error("Base Filtering Engine service has been disabled")] 63 | BaseFilteringEngineDisabled, // 1753 64 | } 65 | 66 | impl TryFrom for WinDivertOpenError { 67 | type Error = std::io::Error; 68 | 69 | fn try_from(value: i32) -> Result { 70 | match value { 71 | 2 => Ok(WinDivertOpenError::MissingSYS), 72 | 5 => Ok(WinDivertOpenError::AccessDenied), 73 | 87 => Ok(WinDivertOpenError::InvalidParameter), 74 | 577 => Ok(WinDivertOpenError::InvalidImageHash), 75 | 654 => Ok(WinDivertOpenError::IncompatibleVersion), 76 | 1060 => Ok(WinDivertOpenError::MissingInstall), 77 | 1257 => Ok(WinDivertOpenError::DriverBlocked), 78 | 1753 => Ok(WinDivertOpenError::BaseFilteringEngineDisabled), 79 | _ => Err(std::io::Error::from_raw_os_error(value)), 80 | } 81 | } 82 | } 83 | 84 | impl TryFrom for WinDivertOpenError { 85 | type Error = std::io::Error; 86 | 87 | fn try_from(error: std::io::Error) -> Result { 88 | error 89 | .raw_os_error() 90 | .map(WinDivertOpenError::try_from) 91 | .unwrap_or(Err(error)) 92 | } 93 | } 94 | 95 | /** 96 | Possible errors for [`WinDivertRecv()`](fn@windivert_sys::WinDivertRecv) 97 | */ 98 | #[derive(Debug, Error)] 99 | pub enum WinDivertRecvError { 100 | /// The captured packet is larger than the provided buffer. 101 | #[error("Captured packet is larger than the provided buffer")] 102 | InsufficientBuffer, // 122 103 | /// The handle has been shutdown and the packet queue is empty. 104 | #[error("Not possible to get more data. Packet queue is empty and handle has been shutdown")] 105 | NoData, // 232 106 | } 107 | 108 | impl TryFrom for WinDivertRecvError { 109 | type Error = std::io::Error; 110 | 111 | fn try_from(value: i32) -> Result { 112 | match value { 113 | 122 => Ok(WinDivertRecvError::InsufficientBuffer), 114 | 232 => Ok(WinDivertRecvError::NoData), 115 | _ => Err(std::io::Error::from_raw_os_error(value)), 116 | } 117 | } 118 | } 119 | 120 | impl TryFrom for WinDivertRecvError { 121 | type Error = std::io::Error; 122 | 123 | fn try_from(error: std::io::Error) -> Result { 124 | error 125 | .raw_os_error() 126 | .map(WinDivertRecvError::try_from) 127 | .unwrap_or(Err(error)) 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /windivert/src/divert/mod.rs: -------------------------------------------------------------------------------- 1 | mod blocking; 2 | 3 | use std::{ 4 | ffi::{c_void, CString}, 5 | marker::PhantomData, 6 | mem::MaybeUninit, 7 | }; 8 | 9 | use crate::layer; 10 | use crate::prelude::*; 11 | use sys::{WinDivertParam, WinDivertShutdownMode}; 12 | use windivert_sys as sys; 13 | 14 | use windows::{ 15 | core::{Error as WinError, Result as WinResult, PCSTR}, 16 | Win32::{ 17 | Foundation::{GetLastError, HANDLE}, 18 | System::{ 19 | Services::{ 20 | CloseServiceHandle, ControlService, OpenSCManagerA, OpenServiceA, 21 | SC_MANAGER_ALL_ACCESS, SERVICE_CONTROL_STOP, SERVICE_STATUS, 22 | }, 23 | Threading::{CreateEventA, TlsAlloc, TlsGetValue, TlsSetValue}, 24 | }, 25 | }, 26 | }; 27 | 28 | /// Main wrapper struct around windivert functionalities. 29 | #[non_exhaustive] 30 | pub struct WinDivert { 31 | handle: HANDLE, 32 | _tls_idx: u32, 33 | _layer: PhantomData, 34 | } 35 | 36 | /// Recv implementations 37 | impl WinDivert { 38 | /// Open a handle using the specified parameters. 39 | fn new( 40 | filter: &str, 41 | layer: WinDivertLayer, 42 | priority: i16, 43 | flags: WinDivertFlags, 44 | ) -> Result { 45 | let filter = CString::new(filter)?; 46 | let windivert_tls_idx = unsafe { TlsAlloc() }; 47 | let handle = unsafe { sys::WinDivertOpen(filter.as_ptr(), layer, priority, flags) }; 48 | if handle.is_invalid() { 49 | let open_err = WinDivertOpenError::try_from(std::io::Error::last_os_error())?; 50 | Err(open_err.into()) 51 | } else { 52 | Ok(Self { 53 | handle, 54 | _tls_idx: windivert_tls_idx, 55 | _layer: PhantomData::, 56 | }) 57 | } 58 | } 59 | 60 | pub(crate) fn _get_event(tls_idx: u32) -> Result { 61 | let mut event = HANDLE::default(); 62 | unsafe { 63 | event.0 = TlsGetValue(tls_idx) as isize; 64 | if event.is_invalid() { 65 | event = CreateEventA(None, false, false, None)?; 66 | TlsSetValue(tls_idx, Some(event.0 as *mut c_void)); 67 | } 68 | } 69 | Ok(event) 70 | } 71 | 72 | /// Methods that allows to query the driver for parameters. 73 | pub fn get_param(&self, param: WinDivertParam) -> Result { 74 | let mut value = 0; 75 | let res = unsafe { sys::WinDivertGetParam(self.handle, param, &mut value) }; 76 | if !res.as_bool() { 77 | return Err(std::io::Error::last_os_error().into()); 78 | } 79 | Ok(value) 80 | } 81 | 82 | /// Method that allows setting driver parameters. 83 | pub fn set_param(&self, param: WinDivertParam, value: u64) -> Result<(), WinDivertError> { 84 | match param { 85 | WinDivertParam::VersionMajor | WinDivertParam::VersionMinor => { 86 | Err(WinDivertError::Parameter(param, value)) 87 | } 88 | _ => unsafe { sys::WinDivertSetParam(self.handle, param, value) } 89 | .ok() 90 | .map_err(|_| std::io::Error::last_os_error().into()), 91 | } 92 | } 93 | 94 | /// Handle close function. 95 | pub fn close(&mut self, action: CloseAction) -> WinResult<()> { 96 | let res = unsafe { sys::WinDivertClose(self.handle) }; 97 | if !res.as_bool() { 98 | return Err(WinError::from(unsafe { GetLastError() })); 99 | } 100 | match action { 101 | CloseAction::Uninstall => WinDivert::uninstall(), 102 | CloseAction::Nothing => Ok(()), 103 | } 104 | } 105 | 106 | /// Shutdown function. 107 | pub fn shutdown(&mut self, mode: WinDivertShutdownMode) -> WinResult<()> { 108 | let res = unsafe { sys::WinDivertShutdown(self.handle, mode) }; 109 | if !res.as_bool() { 110 | return Err(WinError::from(unsafe { GetLastError() })); 111 | } 112 | Ok(()) 113 | } 114 | } 115 | 116 | impl WinDivert { 117 | /// WinDivert constructor for network layer. 118 | pub fn network( 119 | filter: impl AsRef, 120 | priority: i16, 121 | flags: WinDivertFlags, 122 | ) -> Result { 123 | Self::new(filter.as_ref(), WinDivertLayer::Network, priority, flags) 124 | } 125 | } 126 | 127 | impl WinDivert { 128 | /// WinDivert constructor for forward layer. 129 | pub fn forward( 130 | filter: impl AsRef, 131 | priority: i16, 132 | flags: WinDivertFlags, 133 | ) -> Result { 134 | Self::new(filter.as_ref(), WinDivertLayer::Forward, priority, flags) 135 | } 136 | } 137 | 138 | impl WinDivert { 139 | /// WinDivert constructor for flow layer. 140 | pub fn flow( 141 | filter: &str, 142 | priority: i16, 143 | flags: WinDivertFlags, 144 | ) -> Result { 145 | Self::new( 146 | filter, 147 | WinDivertLayer::Flow, 148 | priority, 149 | flags.set_recv_only().set_sniff(), 150 | ) 151 | } 152 | } 153 | 154 | impl WinDivert { 155 | /// WinDivert constructor for socket layer. 156 | pub fn socket( 157 | filter: impl AsRef, 158 | priority: i16, 159 | flags: WinDivertFlags, 160 | ) -> Result { 161 | Self::new( 162 | filter.as_ref(), 163 | WinDivertLayer::Socket, 164 | priority, 165 | flags.set_recv_only(), 166 | ) 167 | } 168 | } 169 | 170 | impl WinDivert { 171 | /// WinDivert constructor for reflect layer. 172 | pub fn reflect( 173 | filter: impl AsRef, 174 | priority: i16, 175 | flags: WinDivertFlags, 176 | ) -> Result { 177 | Self::new( 178 | filter.as_ref(), 179 | WinDivertLayer::Reflect, 180 | priority, 181 | flags.set_recv_only().set_sniff(), 182 | ) 183 | } 184 | } 185 | 186 | impl WinDivert<()> { 187 | /// Maximum number of packets that can be captured/sent in a single batched operation 188 | pub const MAX_BATCH: u8 = windivert_sys::WINDIVERT_BATCH_MAX as u8; 189 | 190 | /// Method that tries to uninstall WinDivert driver. 191 | pub fn uninstall() -> WinResult<()> { 192 | let status: *mut SERVICE_STATUS = MaybeUninit::uninit().as_mut_ptr(); 193 | unsafe { 194 | let manager = OpenSCManagerA(None, None, SC_MANAGER_ALL_ACCESS)?; 195 | let service = OpenServiceA( 196 | manager, 197 | PCSTR::from_raw("WinDivert".as_ptr()), 198 | SC_MANAGER_ALL_ACCESS, 199 | )?; 200 | let res = ControlService(service, SERVICE_CONTROL_STOP, status); 201 | if !res.as_bool() { 202 | return Err(WinError::from(GetLastError())); 203 | } 204 | let res = CloseServiceHandle(service); 205 | if !res.as_bool() { 206 | return Err(WinError::from(GetLastError())); 207 | } 208 | let res = CloseServiceHandle(manager); 209 | if !res.as_bool() { 210 | return Err(WinError::from(GetLastError())); 211 | } 212 | } 213 | Ok(()) 214 | } 215 | } 216 | 217 | /// Action parameter for [`WinDivert::close()`](`fn@WinDivert::close`) 218 | pub enum CloseAction { 219 | /// Close the handle and try to uninstall the WinDivert driver. 220 | Uninstall, 221 | /// Close the handle without uninstalling the driver. 222 | Nothing, 223 | } 224 | 225 | impl Default for CloseAction { 226 | fn default() -> Self { 227 | Self::Nothing 228 | } 229 | } 230 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. -------------------------------------------------------------------------------- /windivert-sys/src/bindings/mod.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_upper_case_globals)] 2 | #![allow(non_camel_case_types)] 3 | #![allow(non_snake_case)] 4 | 5 | pub mod address; 6 | pub mod header; 7 | pub mod ioctl; 8 | 9 | mod bitfield; 10 | use std::ffi::c_void; 11 | 12 | pub(crate) use bitfield::BitfieldUnit; 13 | mod error; 14 | pub use error::*; 15 | mod newtypes; 16 | pub use newtypes::*; 17 | 18 | use windows::Win32::{ 19 | Foundation::{BOOL, HANDLE}, 20 | System::IO::OVERLAPPED, 21 | }; 22 | /// Default value for queue length parameter. 23 | pub const WINDIVERT_PARAM_QUEUE_LENGTH_DEFAULT: u64 = 4096; 24 | /// Minimum valid value for queue length parameter. 25 | pub const WINDIVERT_PARAM_QUEUE_LENGTH_MIN: u64 = 32; 26 | /// Maximum valid value for queue length parameter. 27 | pub const WINDIVERT_PARAM_QUEUE_LENGTH_MAX: u64 = 16384; 28 | /// Default value for queue time parameter. 29 | pub const WINDIVERT_PARAM_QUEUE_TIME_DEFAULT: u64 = 2000; /* 2s */ 30 | /// Minimum valid value for queue time parameter. 31 | pub const WINDIVERT_PARAM_QUEUE_TIME_MIN: u64 = 100; /* 100ms */ 32 | /// Maximum valid value for queue time parameter. 33 | pub const WINDIVERT_PARAM_QUEUE_TIME_MAX: u64 = 16000; /* 16s */ 34 | /// Default value for queue size parameter. 35 | pub const WINDIVERT_PARAM_QUEUE_SIZE_DEFAULT: u64 = 4194304; /* 4MB */ 36 | /// Minimum valid value for queue size parameter. 37 | pub const WINDIVERT_PARAM_QUEUE_SIZE_MIN: u64 = 65535; /* 64KB */ 38 | /// Maximum valid value for queue size parameter. 39 | pub const WINDIVERT_PARAM_QUEUE_SIZE_MAX: u64 = 33554432; /* 32MB */ 40 | /// Maximum valid value for priority parameter. 41 | pub const WINDIVERT_PRIORITY_MAX: u32 = 30000; 42 | /// Minimum valid value for priority parameter. 43 | pub const WINDIVERT_PRIORITY_MIN: i32 = -30000; 44 | /// Maximum valid batch length. 45 | pub const WINDIVERT_BATCH_MAX: u32 = 255; 46 | /// Maximum valid mtu size. 47 | pub const WINDIVERT_MTU_MAX: u32 = 65575; 48 | 49 | extern "C" { 50 | /// Check the official [docs](https://reqrypt.org/windivert-doc.html#divert_open) 51 | pub fn WinDivertOpen( 52 | filter: *const ::std::os::raw::c_char, 53 | layer: WinDivertLayer, 54 | priority: i16, 55 | flags: WinDivertFlags, 56 | ) -> HANDLE; 57 | 58 | /// Check the official [docs](https://reqrypt.org/windivert-doc.html#divert_recv) 59 | pub fn WinDivertRecv( 60 | handle: HANDLE, 61 | pPacket: *mut ::std::os::raw::c_void, 62 | packetLen: u32, 63 | pRecvLen: *mut u32, 64 | pAddr: *mut address::WINDIVERT_ADDRESS, 65 | ) -> BOOL; 66 | 67 | /// Check the official [docs](https://reqrypt.org/windivert-doc.html#divert_recv_ex) 68 | pub fn WinDivertRecvEx( 69 | handle: HANDLE, 70 | pPacket: *mut ::std::os::raw::c_void, 71 | packetLen: u32, 72 | pRecvLen: *mut u32, 73 | flags: u64, 74 | pAddr: *mut address::WINDIVERT_ADDRESS, 75 | pAddrLen: *mut u32, 76 | lpOverlapped: *mut OVERLAPPED, 77 | ) -> BOOL; 78 | 79 | /// Check the official [docs](https://reqrypt.org/windivert-doc.html#divert_send) 80 | pub fn WinDivertSend( 81 | handle: HANDLE, 82 | pPacket: *const ::std::os::raw::c_void, 83 | packetLen: u32, 84 | pSendLen: *mut u32, 85 | pAddr: *const address::WINDIVERT_ADDRESS, 86 | ) -> BOOL; 87 | 88 | /// Check the official [docs](https://reqrypt.org/windivert-doc.html#divert_send_ex) 89 | pub fn WinDivertSendEx( 90 | handle: HANDLE, 91 | pPacket: *const ::std::os::raw::c_void, 92 | packetLen: u32, 93 | pSendLen: *mut u32, 94 | flags: u64, 95 | pAddr: *const address::WINDIVERT_ADDRESS, 96 | addrLen: u32, 97 | lpOverlapped: *mut OVERLAPPED, 98 | ) -> BOOL; 99 | 100 | /// Check the official [docs](https://reqrypt.org/windivert-doc.html#divert_shutdown) 101 | pub fn WinDivertShutdown(handle: HANDLE, how: WinDivertShutdownMode) -> BOOL; 102 | 103 | /// Check the official [docs](https://reqrypt.org/windivert-doc.html#divert_close) 104 | pub fn WinDivertClose(handle: HANDLE) -> BOOL; 105 | 106 | /// Check the official [docs](https://reqrypt.org/windivert-doc.html#divert_set_param) 107 | pub fn WinDivertSetParam(handle: HANDLE, param: WinDivertParam, value: u64) -> BOOL; 108 | 109 | /// Check the official [docs](https://reqrypt.org/windivert-doc.html#divert_get_param) 110 | pub fn WinDivertGetParam(handle: HANDLE, param: WinDivertParam, pValue: *mut u64) -> BOOL; 111 | } 112 | 113 | extern "C" { 114 | /// Check the official [docs](https://reqrypt.org/windivert-doc.html#divert_helper_parse_packet) 115 | pub fn WinDivertHelperParsePacket( 116 | pPacket: *const ::std::os::raw::c_void, 117 | packetLen: u32, 118 | ppIpHdr: *mut header::PWINDIVERT_IPHDR, 119 | ppIpv6Hdr: *mut header::PWINDIVERT_IPV6HDR, 120 | pProtocol: *mut u8, 121 | ppIcmpHdr: *mut header::PWINDIVERT_ICMPHDR, 122 | ppIcmpv6Hdr: *mut header::PWINDIVERT_ICMPV6HDR, 123 | ppTcpHdr: *mut header::PWINDIVERT_TCPHDR, 124 | ppUdpHdr: *mut header::PWINDIVERT_UDPHDR, 125 | ppData: *mut c_void, 126 | pDataLen: *mut u32, 127 | ppNext: *mut c_void, 128 | pNextLen: *mut u32, 129 | ) -> BOOL; 130 | 131 | /// Check the official [docs](https://reqrypt.org/windivert-doc.html#divert_helper_hash_packet) 132 | pub fn WinDivertHelperHashPacket( 133 | pPacket: *const ::std::os::raw::c_void, 134 | packetLen: u32, 135 | seed: u64, 136 | ) -> u64; 137 | 138 | /// Check the official [docs](https://reqrypt.org/windivert-doc.html#divert_helper_parse_ipv4_address) 139 | pub fn WinDivertHelperParseIPv4Address( 140 | addrStr: *const ::std::os::raw::c_char, 141 | pAddr: *mut u32, 142 | ) -> BOOL; 143 | 144 | /// Check the official [docs](https://reqrypt.org/windivert-doc.html#divert_helper_parse_ipv6_address) 145 | pub fn WinDivertHelperParseIPv6Address( 146 | addrStr: *const ::std::os::raw::c_char, 147 | pAddr: *mut u32, 148 | ) -> BOOL; 149 | 150 | /// Check the official [docs](https://reqrypt.org/windivert-doc.html#divert_helper_format_ipv4_address) 151 | pub fn WinDivertHelperFormatIPv4Address( 152 | addr: u32, 153 | buffer: *mut ::std::os::raw::c_char, 154 | bufLen: u32, 155 | ) -> BOOL; 156 | 157 | /// Check the official [docs](https://reqrypt.org/windivert-doc.html#divert_helper_format_ipv6_address) 158 | pub fn WinDivertHelperFormatIPv6Address( 159 | pAddr: *const u32, 160 | buffer: *mut ::std::os::raw::c_char, 161 | bufLen: u32, 162 | ) -> BOOL; 163 | 164 | /// Check the official [docs](https://reqrypt.org/windivert-doc.html#divert_helper_calc_checksums) 165 | pub fn WinDivertHelperCalcChecksums( 166 | pPacket: *mut ::std::os::raw::c_void, 167 | packetLen: u32, 168 | pAddr: *mut address::WINDIVERT_ADDRESS, 169 | flags: ChecksumFlags, 170 | ) -> BOOL; 171 | 172 | /// Check the official [docs](https://reqrypt.org/windivert-doc.html#divert_helper_dec_ttl) 173 | pub fn WinDivertHelperDecrementTTL( 174 | pPacket: *mut ::std::os::raw::c_void, 175 | packetLen: u32, 176 | ) -> BOOL; 177 | 178 | /// Check the official [docs](https://reqrypt.org/windivert-doc.html#divert_helper_compile_filter) 179 | pub fn WinDivertHelperCompileFilter( 180 | filter: *const ::std::os::raw::c_char, 181 | layer: WinDivertLayer, 182 | object: *mut ::std::os::raw::c_char, 183 | objLen: u32, 184 | errorStr: *mut *const ::std::os::raw::c_char, 185 | errorPos: *mut u32, 186 | ) -> BOOL; 187 | 188 | /// Check the official [docs](https://reqrypt.org/windivert-doc.html#divert_helper_eval_filter) 189 | pub fn WinDivertHelperEvalFilter( 190 | filter: *const ::std::os::raw::c_char, 191 | pPacket: *const ::std::os::raw::c_void, 192 | packetLen: u32, 193 | pAddr: *const address::WINDIVERT_ADDRESS, 194 | ) -> BOOL; 195 | 196 | /// Check the official [docs](https://reqrypt.org/windivert-doc.html#divert_helper_format_filter) 197 | pub fn WinDivertHelperFormatFilter( 198 | filter: *const ::std::os::raw::c_char, 199 | layer: WinDivertLayer, 200 | buffer: *mut ::std::os::raw::c_char, 201 | bufLen: u32, 202 | ) -> BOOL; 203 | 204 | /// Check the official [docs](https://reqrypt.org/windivert-doc.html#divert_helper_ntoh) 205 | pub fn WinDivertHelperNtohs(x: u16) -> u16; 206 | 207 | /// Check the official [docs](https://reqrypt.org/windivert-doc.html#divert_helper_hton) 208 | pub fn WinDivertHelperHtons(x: u16) -> u16; 209 | 210 | /// Check the official [docs](https://reqrypt.org/windivert-doc.html#divert_helper_ntoh) 211 | pub fn WinDivertHelperNtohl(x: u32) -> u32; 212 | 213 | /// Check the official [docs](https://reqrypt.org/windivert-doc.html#divert_helper_hton) 214 | pub fn WinDivertHelperHtonl(x: u32) -> u32; 215 | 216 | /// Check the official [docs](https://reqrypt.org/windivert-doc.html#divert_helper_ntoh) 217 | pub fn WinDivertHelperNtohll(x: u64) -> u64; 218 | 219 | /// Check the official [docs](https://reqrypt.org/windivert-doc.html#divert_helper_hton) 220 | pub fn WinDivertHelperHtonll(x: u64) -> u64; 221 | 222 | /// Check the official [docs](https://reqrypt.org/windivert-doc.html#divert_helper_ntoh) 223 | pub fn WinDivertHelperNtohIPv6Address(inAddr: *const u32, outAddr: *mut u32); 224 | 225 | /// Check the official [docs](https://reqrypt.org/windivert-doc.html#divert_helper_hton) 226 | pub fn WinDivertHelperHtonIPv6Address(inAddr: *const u32, outAddr: *mut u32); 227 | 228 | /// Check the official [docs](https://reqrypt.org/windivert-doc.html#divert_helper_ntoh) 229 | pub fn WinDivertHelperNtohIpv6Address(inAddr: *const u32, outAddr: *mut u32); 230 | 231 | /// Check the official [docs](https://reqrypt.org/windivert-doc.html#divert_helper_hton) 232 | pub fn WinDivertHelperHtonIpv6Address(inAddr: *const u32, outAddr: *mut u32); 233 | } 234 | -------------------------------------------------------------------------------- /windivert-sys/src/bindings/address.rs: -------------------------------------------------------------------------------- 1 | /*! 2 | WinDivert address types. 3 | 4 | For more info, refer to the [docs](https://reqrypt.org/windivert-doc.html#divert_address). 5 | */ 6 | 7 | use std::{convert::TryFrom, fmt::Debug}; 8 | 9 | use super::{BitfieldUnit, WinDivertEvent, WinDivertFlags, WinDivertLayer}; 10 | 11 | #[repr(C)] 12 | #[derive(Debug, Default, Copy, Clone)] 13 | /** 14 | Represents the associated data recieved using [`WinDivertLayer::Network`] 15 | */ 16 | pub struct WINDIVERT_DATA_NETWORK { 17 | /// Interface index on whick the packet arrived (for inbound packets) or will be sent (for outbound packets). 18 | pub interface_id: u32, 19 | /// The sub-interface index for `interface_id` 20 | pub subinterface_id: u32, 21 | } 22 | 23 | #[repr(C)] 24 | #[derive(Debug, Default, Copy, Clone)] 25 | /** 26 | Represents the associated data recieved using [`WinDivertLayer::Flow`] 27 | */ 28 | pub struct WINDIVERT_DATA_FLOW { 29 | /// The endpoint ID of the flow. 30 | pub endpoint_id: u64, 31 | /// The parent endpoint ID of the flow. 32 | pub parent_endpoint_id: u64, 33 | /// The id of the process associated with the flow. 34 | pub process_id: u32, 35 | /** 36 | The local address associated with the socket. 37 | 38 | For IPv4, this field will contain IPv4-mapped IPv6 addresses, e.g. the IPv4 address X.Y.Z.W will be represented by ::ffff:X.Y.Z.W. 39 | 40 | This field can contain a value o zero, since [`SocketBind`](WinDivertEvent::SocketBind) and [`SocketBind`](WinDivertEvent::SocketListen) events can occur before a connection attempt has been made. 41 | */ 42 | pub local_addr: [u32; 4usize], 43 | /** 44 | The remote address associated with the socket. 45 | 46 | For IPv4, this field will contain IPv4-mapped IPv6 addresses, e.g. the IPv4 address X.Y.Z.W will be represented by ::ffff:X.Y.Z.W. 47 | 48 | This field can contain a value o zero, since [`SocketBind`](WinDivertEvent::SocketBind) and [`SocketBind`](WinDivertEvent::SocketListen) events can occur before a connection attempt has been made. 49 | */ 50 | pub remote_addr: [u32; 4usize], 51 | /// The local port associated with the flow. 52 | pub local_port: u16, 53 | /// The remote port associated with the flow. 54 | pub remote_port: u16, 55 | /// The flow protocol. 56 | pub protocol: u8, 57 | } 58 | 59 | #[repr(C)] 60 | #[derive(Debug, Default, Copy, Clone)] 61 | /** 62 | Represents the associated data recieved using [`WinDivertLayer::Socket`] 63 | */ 64 | pub struct WINDIVERT_DATA_SOCKET { 65 | /// The endpoint ID of the socket. 66 | pub endpoint_id: u64, 67 | /// The parent endpoint ID of the socket. 68 | pub parent_endpoint_id: u64, 69 | /// The id of the process associated with the socket. 70 | pub process_id: u32, 71 | /** 72 | The local address associated with the socket. 73 | 74 | For IPv4, this field will contain IPv4-mapped IPv6 addresses, e.g. the IPv4 address X.Y.Z.W will be represented by ::ffff:X.Y.Z.W. 75 | */ 76 | pub local_addr: [u32; 4usize], 77 | /** 78 | The remote address associated with the socket. 79 | 80 | For IPv4, this field will contain IPv4-mapped IPv6 addresses, e.g. the IPv4 address X.Y.Z.W will be represented by ::ffff:X.Y.Z.W. 81 | */ 82 | pub remote_addr: [u32; 4usize], 83 | /// The local port associated with the socket. 84 | pub local_port: u16, 85 | /// The remote port associated with the socket. 86 | pub remote_port: u16, 87 | /// The socket protocol. 88 | pub protocol: u8, 89 | } 90 | 91 | #[repr(C)] 92 | #[derive(Debug, Copy, Clone)] 93 | /** 94 | Represents the associated data recieved using [`WinDivertLayer::Reflect`] 95 | */ 96 | pub struct WINDIVERT_DATA_REFLECT { 97 | /// Timestamp indicating when the handle was opened. 98 | pub timestamp: i64, 99 | /// Process if of the process that opened the handle. 100 | pub process_id: u32, 101 | /// [`WinDivertLayer`] parameter on [`WinDivertOpen`](super::WinDivertOpen) for the specified handle. 102 | pub layer: WinDivertLayer, 103 | /// [`WinDivertFlags`] parameter on [`WinDivertOpen`](super::WinDivertOpen) for the specified handle. 104 | pub flags: WinDivertFlags, 105 | /// Priority parameter on [`WinDivertOpen`](super::WinDivertOpen) for the specified handle. 106 | pub priority: i16, 107 | } 108 | 109 | impl Default for WINDIVERT_DATA_REFLECT { 110 | fn default() -> Self { 111 | unsafe { ::std::mem::zeroed() } 112 | } 113 | } 114 | 115 | #[repr(C)] 116 | #[derive(Copy, Clone)] 117 | /// Union of the different data types associated with the possible layer values. 118 | pub union WINDIVERT_ADDRESS_UNION_FIELD { 119 | /// Address data related to [`Network`](WinDivertLayer::Network) and [`Forward`](WinDivertLayer::Forward) layers. 120 | pub Network: WINDIVERT_DATA_NETWORK, 121 | /// Address data related to [`Flow`](WinDivertLayer::Flow) layer. 122 | pub Flow: WINDIVERT_DATA_FLOW, 123 | /// Address data related to [`Socket`](WinDivertLayer::Socket) layer. 124 | pub Socket: WINDIVERT_DATA_SOCKET, 125 | /// Address data related to [`Reflect`](WinDivertLayer::Reflect) layer. 126 | pub Reflect: WINDIVERT_DATA_REFLECT, 127 | reserved: [u8; 64usize], 128 | _union_align: [u64; 8usize], 129 | } 130 | 131 | impl Default for WINDIVERT_ADDRESS_UNION_FIELD { 132 | fn default() -> Self { 133 | unsafe { ::std::mem::zeroed() } 134 | } 135 | } 136 | 137 | #[repr(C)] 138 | #[derive(Copy, Clone)] 139 | /** 140 | Base data type returned by [`recv`](fn@super::WinDivertRecv) and required by [`send`](fn@super::WinDivertSend) 141 | 142 | Most address fields are ignored by [`WinDivertSend()`](fn@super::WinDivertSend). The exceptions are Outbound (for [`WinDivertLayer::Network`] layer only), Impostor, IPChecksum, TCPChecksum, UDPChecksum, [`Network.interface_id`](WINDIVERT_DATA_NETWORK::interface_id) and [`Network.subinterface_id`](WINDIVERT_DATA_NETWORK::subinterface_id). 143 | */ 144 | pub struct WINDIVERT_ADDRESS { 145 | /// Timestamp indicating when the event occurred. 146 | pub timestamp: i64, 147 | addr_bitfield: BitfieldUnit<[u8; 4usize], u8>, 148 | reserved: u32, 149 | /// Union of the different data types associated with the possible layer values. 150 | pub union_field: WINDIVERT_ADDRESS_UNION_FIELD, 151 | } 152 | 153 | impl Default for WINDIVERT_ADDRESS { 154 | fn default() -> Self { 155 | unsafe { ::std::mem::zeroed() } 156 | } 157 | } 158 | 159 | impl WINDIVERT_ADDRESS { 160 | #[inline] 161 | /// Getter for the handle [`layer`](super::WinDivertLayer) 162 | pub fn layer(&self) -> WinDivertLayer { 163 | WinDivertLayer::try_from(self.addr_bitfield.get(0usize, 8u8) as u32) 164 | .expect("Layer always is correct since it would have produced an error in Open()") 165 | } 166 | #[inline] 167 | /// Setter for the handle [`layer`](super::WinDivertLayer) 168 | pub fn set_layer(&mut self, val: WinDivertLayer) { 169 | self.addr_bitfield.set(0usize, 8u8, u32::from(val) as u64) 170 | } 171 | #[inline] 172 | /// Getter for the handle [`event`](super::WinDivertEvent) 173 | pub fn event(&self) -> WinDivertEvent { 174 | WinDivertEvent::try_from(self.addr_bitfield.get(8usize, 8u8) as u8) 175 | .expect("Event always is correct since the value comes from the DLL functions.") 176 | } 177 | #[inline] 178 | /// Setter for the handle [`event`](super::WinDivertEvent) 179 | pub fn set_event(&mut self, val: WinDivertEvent) { 180 | self.addr_bitfield.set(8usize, 8u8, u32::from(val) as u64) 181 | } 182 | #[inline] 183 | /// Set to true if the packet was sniffed (not blocked). 184 | pub fn sniffed(&self) -> bool { 185 | self.addr_bitfield.get(16usize, 1u8) == 1 186 | } 187 | #[inline] 188 | /// Sniffed flag setter. 189 | pub fn set_sniffed(&mut self, val: bool) { 190 | self.addr_bitfield.set(16usize, 1u8, val as u64) 191 | } 192 | #[inline] 193 | /// Set to true for outbound packet events. 194 | pub fn outbound(&self) -> bool { 195 | self.addr_bitfield.get(17usize, 1u8) == 1 196 | } 197 | #[inline] 198 | /// Outbound flag setter. 199 | pub fn set_outbound(&mut self, val: bool) { 200 | self.addr_bitfield.set(17usize, 1u8, val as u64) 201 | } 202 | #[inline] 203 | /// Set to true for loopback packets. 204 | pub fn loopback(&self) -> bool { 205 | self.addr_bitfield.get(18usize, 1u8) == 1 206 | } 207 | #[inline] 208 | /// Loopback flag setter. 209 | pub fn set_loopback(&mut self, val: bool) { 210 | self.addr_bitfield.set(18usize, 1u8, val as u64) 211 | } 212 | #[inline] 213 | /// Set to true for "impostor" packets. 214 | pub fn impostor(&self) -> bool { 215 | self.addr_bitfield.get(19usize, 1u8) == 1 216 | } 217 | #[inline] 218 | /// Impostor flag setter. 219 | pub fn set_impostor(&mut self, val: bool) { 220 | self.addr_bitfield.set(19usize, 1u8, val as u64) 221 | } 222 | #[inline] 223 | /// Set to true for IPv6 packets. 224 | pub fn ipv6(&self) -> bool { 225 | self.addr_bitfield.get(20usize, 1u8) == 1 226 | } 227 | #[inline] 228 | /// IPv6 flag setter. 229 | pub fn set_ipv6(&mut self, val: bool) { 230 | self.addr_bitfield.set(20usize, 1u8, val as u64) 231 | } 232 | #[inline] 233 | /// Set to true if the IPv4 checksum is valid. 234 | pub fn ipchecksum(&self) -> bool { 235 | self.addr_bitfield.get(21usize, 1u8) == 1 236 | } 237 | #[inline] 238 | /// IPv4 checksum flag setter. 239 | pub fn set_ipchecksum(&mut self, val: bool) { 240 | self.addr_bitfield.set(21usize, 1u8, val as u64) 241 | } 242 | #[inline] 243 | /// Set to true if the TCP checksum is valid. 244 | pub fn tcpchecksum(&self) -> bool { 245 | self.addr_bitfield.get(22usize, 1u8) == 1 246 | } 247 | #[inline] 248 | /// TCP checksum flag setter. 249 | pub fn set_tcpchecksum(&mut self, val: bool) { 250 | self.addr_bitfield.set(22usize, 1u8, val as u64) 251 | } 252 | #[inline] 253 | /// Set to true if the UDP checksum is valid. 254 | pub fn udpchecksum(&self) -> bool { 255 | self.addr_bitfield.get(23usize, 1u8) == 1 256 | } 257 | #[inline] 258 | /// UDP checksum flag setter. 259 | pub fn set_udpchecksum(&mut self, val: bool) { 260 | self.addr_bitfield.set(23usize, 1u8, val as u64) 261 | } 262 | } 263 | 264 | impl Debug for WINDIVERT_ADDRESS { 265 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 266 | let union_str = match self.event() { 267 | WinDivertEvent::NetworkPacket => { 268 | format!("{:?}", unsafe { self.union_field.Network }) 269 | } 270 | WinDivertEvent::FlowStablished | WinDivertEvent::FlowDeleted => { 271 | format!("{:?}", unsafe { self.union_field.Flow }) 272 | } 273 | WinDivertEvent::SocketBind 274 | | WinDivertEvent::SocketConnect 275 | | WinDivertEvent::SocketListen 276 | | WinDivertEvent::SocketAccept 277 | | WinDivertEvent::SocketClose => { 278 | format!("{:?}", unsafe { self.union_field.Socket }) 279 | } 280 | WinDivertEvent::ReflectOpen | WinDivertEvent::ReflectClose => { 281 | format!("{:?}", unsafe { self.union_field.Reflect }) 282 | } 283 | }; 284 | write!(f, "WINDIVERT_ADDRESS {{ Timestamp: {:?}, Layer: {:?}, Event: {:?}, Sniffed: {:?}, Outbound: {:?}, Loopback: {:?}, Impostor: {:?}, IPv6: {:?}, IPChecksum: {:?}, TCPChecksum: {:?}, UDPChecksum: {:?}, {}}}", 285 | self.timestamp, self.layer(), self.event(), self.sniffed(), self.outbound(), self.loopback(), self.impostor(), self.ipv6(), self.ipchecksum(), self.tcpchecksum(), self.udpchecksum(), union_str) 286 | } 287 | } 288 | -------------------------------------------------------------------------------- /windivert/src/address.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | marker::PhantomData, 3 | net::{IpAddr, Ipv4Addr, Ipv6Addr}, 4 | }; 5 | 6 | use crate::{layer, prelude::*}; 7 | use windivert_sys::address::*; 8 | 9 | /// Newtype wrapper around [`WINDIVERT_ADDRESS`] using typestate to provide a safe interface. 10 | #[repr(transparent)] 11 | #[derive(Debug, Clone)] 12 | pub struct WinDivertAddress { 13 | data: WINDIVERT_ADDRESS, 14 | _layer: PhantomData, 15 | } 16 | 17 | impl WinDivertAddress { 18 | #[inline] 19 | pub(crate) fn from_raw(data: WINDIVERT_ADDRESS) -> Self { 20 | Self { 21 | data, 22 | _layer: PhantomData, 23 | } 24 | } 25 | 26 | /// Timestamp of the event. Uses same clock as `QueryPerformanceCounter()` 27 | #[inline] 28 | pub fn event_timestamp(&self) -> i64 { 29 | self.data.timestamp 30 | } 31 | 32 | /// Type of captured event 33 | #[inline] 34 | pub fn event(&self) -> WinDivertEvent { 35 | self.data.event() 36 | } 37 | 38 | /// The handle's layer 39 | #[inline] 40 | pub fn event_layer(&self) -> WinDivertLayer { 41 | self.data.layer() 42 | } 43 | 44 | /// Set to `true` if the event was sniffed (i.e., not blocked), `false` otherwise 45 | #[inline] 46 | pub fn sniffed(&self) -> bool { 47 | self.data.sniffed() 48 | } 49 | 50 | /// Set to `true` for outbound packets/event, `false` for inbound or otherwise 51 | #[inline] 52 | pub fn outbound(&self) -> bool { 53 | self.data.outbound() 54 | } 55 | 56 | /// Outbound setter 57 | #[inline] 58 | pub fn set_outbound(&mut self, value: bool) { 59 | self.data.set_outbound(value) 60 | } 61 | 62 | /// Set to `true` for loopback packets, `false` otherwise 63 | #[inline] 64 | pub fn loopback(&self) -> bool { 65 | self.data.loopback() 66 | } 67 | 68 | /// Set to `true` for impostor packets, `false` otherwise. 69 | #[inline] 70 | pub fn impostor(&self) -> bool { 71 | self.data.impostor() 72 | } 73 | 74 | /// Impostor setter 75 | #[inline] 76 | pub fn set_impostor(&mut self, value: bool) { 77 | self.data.set_impostor(value) 78 | } 79 | 80 | /// Set to `true` for IPv6 packets/events, `false` otherwise 81 | #[inline] 82 | pub fn ipv6(&self) -> bool { 83 | self.data.ipv6() 84 | } 85 | 86 | /// Set to `true` if the IPv4 checksum is valid, `false` otherwise. 87 | #[inline] 88 | pub fn ip_checksum(&self) -> bool { 89 | self.data.ipchecksum() 90 | } 91 | 92 | /// IPv4 checksum setter 93 | #[inline] 94 | pub fn set_ip_checksum(&mut self, value: bool) { 95 | self.data.set_ipchecksum(value) 96 | } 97 | 98 | /// Set to `true` if the TCP checksum is valid, `false` otherwise. 99 | #[inline] 100 | pub fn tcp_checksum(&self) -> bool { 101 | self.data.tcpchecksum() 102 | } 103 | 104 | /// TCP checksum setter 105 | #[inline] 106 | pub fn set_tcp_checksum(&mut self, value: bool) { 107 | self.data.set_tcpchecksum(value) 108 | } 109 | 110 | /// Set to `true` if the UDP checksum is valid, `false` otherwise. 111 | #[inline] 112 | pub fn udp_checksum(&self) -> bool { 113 | self.data.udpchecksum() 114 | } 115 | 116 | /// UDP checksum setter 117 | #[inline] 118 | pub fn set_udp_checksum(&mut self, value: bool) { 119 | self.data.set_udpchecksum(value) 120 | } 121 | } 122 | 123 | impl AsRef for WinDivertAddress { 124 | #[inline] 125 | fn as_ref(&self) -> &WINDIVERT_ADDRESS { 126 | &self.data 127 | } 128 | } 129 | 130 | impl AsMut for WinDivertAddress { 131 | #[inline] 132 | fn as_mut(&mut self) -> &mut WINDIVERT_ADDRESS { 133 | &mut self.data 134 | } 135 | } 136 | 137 | impl WinDivertAddress { 138 | /// Create a new [`WinDivertAddress`] to inject new packets. 139 | /// # Safety 140 | /// The default value for address is zeroed memory, caller must fill with valid data before sending. 141 | pub unsafe fn new() -> Self { 142 | Self { 143 | data: Default::default(), 144 | _layer: PhantomData, 145 | } 146 | } 147 | 148 | #[inline] 149 | fn data(&self) -> &WINDIVERT_DATA_NETWORK { 150 | // SAFETY: Thanks to typestate, we know that self is a network layer address 151 | unsafe { &self.data.union_field.Network } 152 | } 153 | 154 | #[inline] 155 | fn data_mut(&mut self) -> &mut WINDIVERT_DATA_NETWORK { 156 | // SAFETY: Thanks to typestate, we know that self is a network layer address 157 | unsafe { &mut self.data.union_field.Network } 158 | } 159 | 160 | /// The interface index on which the packet arrived (for inbound packets), or is to be sent (for outbound packets) 161 | #[inline] 162 | pub fn interface_index(&self) -> u32 { 163 | self.data().interface_id 164 | } 165 | 166 | /// Interface index setter 167 | #[inline] 168 | pub fn set_interface_index(&mut self, value: u32) { 169 | self.data_mut().interface_id = value 170 | } 171 | 172 | /// The sub-interface index for `interface_id()` 173 | #[inline] 174 | pub fn subinterface_index(&self) -> u32 { 175 | self.data().subinterface_id 176 | } 177 | 178 | /// Sub interface index setter 179 | #[inline] 180 | pub fn set_subinterface_index(&mut self, value: u32) { 181 | self.data_mut().subinterface_id = value 182 | } 183 | } 184 | 185 | impl WinDivertAddress { 186 | /// Create a new [`WinDivertAddress`] to inject new packets. 187 | /// # Safety 188 | /// The default value for address is zeroed memory, caller must fill with valid data before sending. 189 | pub unsafe fn new() -> Self { 190 | Self { 191 | data: Default::default(), 192 | _layer: PhantomData, 193 | } 194 | } 195 | 196 | #[inline] 197 | fn data(&self) -> &WINDIVERT_DATA_NETWORK { 198 | // SAFETY: Thanks to typestate, we know that self is a network layer address 199 | unsafe { &self.data.union_field.Network } 200 | } 201 | 202 | #[inline] 203 | fn data_mut(&mut self) -> &mut WINDIVERT_DATA_NETWORK { 204 | // SAFETY: Thanks to typestate, we know that self is a network layer address 205 | unsafe { &mut self.data.union_field.Network } 206 | } 207 | 208 | /// The interface index on which the packet arrived (for inbound packets), or is to be sent (for outbound packets) 209 | #[inline] 210 | pub fn interface_index(&self) -> u32 { 211 | self.data().interface_id 212 | } 213 | 214 | /// Interface index setter 215 | #[inline] 216 | pub fn set_interface_index(&mut self, value: u32) { 217 | self.data_mut().interface_id = value 218 | } 219 | 220 | /// The sub-interface index for `interface_id()` 221 | #[inline] 222 | pub fn subinterface_index(&self) -> u32 { 223 | self.data().subinterface_id 224 | } 225 | 226 | /// Sub interface index setter 227 | #[inline] 228 | pub fn set_subinterface_index(&mut self, value: u32) { 229 | self.data_mut().subinterface_id = value 230 | } 231 | } 232 | 233 | impl WinDivertAddress { 234 | #[inline] 235 | fn data(&self) -> &WINDIVERT_DATA_FLOW { 236 | // SAFETY: Thanks to typestate, we know that self is a flow layer address 237 | unsafe { &self.data.union_field.Flow } 238 | } 239 | 240 | /// The endpoint ID of the flow 241 | #[inline] 242 | pub fn endpoint_id(&self) -> u64 { 243 | self.data().endpoint_id 244 | } 245 | 246 | /// The parent endpoint ID of the flow 247 | #[inline] 248 | pub fn parent_endpoint_id(&self) -> u64 { 249 | self.data().parent_endpoint_id 250 | } 251 | 252 | /// The process ID of the flow 253 | #[inline] 254 | pub fn process_id(&self) -> u32 { 255 | self.data().process_id 256 | } 257 | 258 | /// The local address associated with the flow 259 | #[inline] 260 | pub fn local_address(&self) -> IpAddr { 261 | if self.data.ipv6() { 262 | IpAddr::V6(Ipv6Addr::from( 263 | self.data() 264 | .local_addr 265 | .iter() 266 | .rev() 267 | .fold(0u128, |acc, &x| acc << 32 | (x as u128)), 268 | )) 269 | } else { 270 | IpAddr::V4(Ipv4Addr::from(self.data().local_addr[0])) 271 | } 272 | } 273 | 274 | /// The remote address associated with the flow 275 | #[inline] 276 | pub fn remote_address(&self) -> IpAddr { 277 | if self.data.ipv6() { 278 | IpAddr::V6(Ipv6Addr::from( 279 | self.data() 280 | .remote_addr 281 | .iter() 282 | .rev() 283 | .fold(0u128, |acc, &x| acc << 32 | (x as u128)), 284 | )) 285 | } else { 286 | IpAddr::V4(Ipv4Addr::from(self.data().remote_addr[0])) 287 | } 288 | } 289 | 290 | /// The locla port associated with the flow 291 | #[inline] 292 | pub fn local_port(&self) -> u16 { 293 | self.data().local_port 294 | } 295 | 296 | /// The remote port associated with the flow 297 | #[inline] 298 | pub fn remote_port(&self) -> u16 { 299 | self.data().remote_port 300 | } 301 | 302 | /// The protocol associated with the flow 303 | #[inline] 304 | pub fn protocol(&self) -> u8 { 305 | self.data().protocol 306 | } 307 | } 308 | 309 | impl WinDivertAddress { 310 | #[inline] 311 | fn data(&self) -> &WINDIVERT_DATA_FLOW { 312 | // SAFETY: Thanks to typestate, we know that self is a flow layer address 313 | unsafe { &self.data.union_field.Flow } 314 | } 315 | 316 | /// The endpoint ID of the flow 317 | #[inline] 318 | pub fn endpoint_id(&self) -> u64 { 319 | self.data().endpoint_id 320 | } 321 | 322 | /// The parent endpoint ID of the flow 323 | #[inline] 324 | pub fn parent_endpoint_id(&self) -> u64 { 325 | self.data().parent_endpoint_id 326 | } 327 | 328 | /// The parent endpoint ID of the flow 329 | #[inline] 330 | pub fn process_id(&self) -> u32 { 331 | self.data().process_id 332 | } 333 | 334 | /// The local address associated with the flow 335 | #[inline] 336 | pub fn local_address(&self) -> IpAddr { 337 | if self.data.ipv6() { 338 | IpAddr::V6(Ipv6Addr::from( 339 | self.data() 340 | .local_addr 341 | .iter() 342 | .rev() 343 | .fold(0u128, |acc, &x| acc << 32 | (x as u128)), 344 | )) 345 | } else { 346 | IpAddr::V4(Ipv4Addr::from(self.data().local_addr[0])) 347 | } 348 | } 349 | 350 | /// The remote address associated with the flow 351 | #[inline] 352 | pub fn remote_address(&self) -> IpAddr { 353 | if self.data.ipv6() { 354 | IpAddr::V6(Ipv6Addr::from( 355 | self.data() 356 | .remote_addr 357 | .iter() 358 | .rev() 359 | .fold(0u128, |acc, &x| acc << 32 | (x as u128)), 360 | )) 361 | } else { 362 | IpAddr::V4(Ipv4Addr::from(self.data().remote_addr[0])) 363 | } 364 | } 365 | 366 | /// The locla port associated with the flow 367 | #[inline] 368 | pub fn local_port(&self) -> u16 { 369 | self.data().local_port 370 | } 371 | 372 | /// The remote port associated with the flow 373 | #[inline] 374 | pub fn remote_port(&self) -> u16 { 375 | self.data().remote_port 376 | } 377 | 378 | /// The protocol associated with the flow 379 | #[inline] 380 | pub fn protocol(&self) -> u8 { 381 | self.data().protocol 382 | } 383 | } 384 | 385 | impl WinDivertAddress { 386 | #[inline] 387 | fn data(&self) -> &WINDIVERT_DATA_REFLECT { 388 | // SAFETY: Thanks to typestate, we know that self is a reflect layer address 389 | unsafe { &self.data.union_field.Reflect } 390 | } 391 | 392 | /// A timestamp indicating when the handle was opened 393 | #[inline] 394 | pub fn timestamp(&self) -> i64 { 395 | self.data().timestamp 396 | } 397 | 398 | /// The ID of the process that opened the handle 399 | #[inline] 400 | pub fn process_id(&self) -> u32 { 401 | self.data().process_id 402 | } 403 | 404 | /// The layer of the opened handle 405 | #[inline] 406 | pub fn layer(&self) -> WinDivertLayer { 407 | self.data().layer 408 | } 409 | 410 | /// The flags of the opened handle 411 | #[inline] 412 | pub fn flags(&self) -> WinDivertFlags { 413 | self.data().flags 414 | } 415 | 416 | /// The priority of the opened handle 417 | #[inline] 418 | pub fn priority(&self) -> i16 { 419 | self.data().priority 420 | } 421 | } 422 | -------------------------------------------------------------------------------- /windivert/src/divert/blocking.rs: -------------------------------------------------------------------------------- 1 | use std::borrow::Cow; 2 | use std::{ffi::c_void, mem::MaybeUninit}; 3 | 4 | use crate::address::WinDivertAddress; 5 | use crate::layer; 6 | use crate::prelude::*; 7 | use etherparse::{InternetSlice, SlicedPacket}; 8 | use sys::address::WINDIVERT_ADDRESS; 9 | use windivert_sys as sys; 10 | 11 | const ADDR_SIZE: usize = std::mem::size_of::(); 12 | 13 | impl WinDivert { 14 | fn internal_recv<'a>( 15 | &self, 16 | buffer: Option<&'a mut [u8]>, 17 | ) -> Result, WinDivertError> { 18 | let mut packet_length = 0; 19 | let mut addr = MaybeUninit::uninit(); 20 | let (buffer_ptr, buffer_len) = if let Some(ref buffer) = buffer { 21 | (buffer.as_ptr(), buffer.len()) 22 | } else { 23 | (std::ptr::null(), 0) 24 | }; 25 | 26 | let res = unsafe { 27 | sys::WinDivertRecv( 28 | self.handle, 29 | buffer_ptr as *mut c_void, 30 | buffer_len as u32, 31 | &mut packet_length, 32 | addr.as_mut_ptr(), 33 | ) 34 | }; 35 | 36 | if res.as_bool() { 37 | Ok(WinDivertPacket { 38 | address: WinDivertAddress::::from_raw(unsafe { addr.assume_init() }), 39 | data: buffer 40 | .map(|b| Cow::Borrowed(&b[..packet_length as usize])) 41 | .unwrap_or_default(), 42 | }) 43 | } else { 44 | let recv_err = WinDivertRecvError::try_from(std::io::Error::last_os_error())?; 45 | Err(recv_err.into()) 46 | } 47 | } 48 | 49 | fn internal_recv_ex<'a>( 50 | &self, 51 | buffer: Option<&'a mut [u8]>, 52 | packet_count: usize, 53 | ) -> Result<(Option<&'a [u8]>, Vec), WinDivertError> { 54 | let mut packet_length = 0; 55 | 56 | let mut addr_len = (ADDR_SIZE * packet_count) as u32; 57 | let mut addr_buffer: Vec = 58 | vec![WINDIVERT_ADDRESS::default(); packet_count]; 59 | 60 | let (buffer_ptr, buffer_len) = if let Some(buffer) = &buffer { 61 | (buffer.as_ptr(), buffer.len()) 62 | } else { 63 | (std::ptr::null(), 0) 64 | }; 65 | 66 | let res = unsafe { 67 | sys::WinDivertRecvEx( 68 | self.handle, 69 | buffer_ptr as *mut c_void, 70 | buffer_len as u32, 71 | &mut packet_length, 72 | 0, 73 | addr_buffer.as_mut_ptr(), 74 | &mut addr_len, 75 | std::ptr::null_mut(), 76 | ) 77 | }; 78 | 79 | if res.as_bool() { 80 | addr_buffer.truncate((addr_len / ADDR_SIZE as u32) as usize); 81 | Ok(( 82 | buffer.map(|buffer| &buffer[..packet_length as usize]), 83 | addr_buffer, 84 | )) 85 | } else { 86 | let recv_err = WinDivertRecvError::try_from(std::io::Error::last_os_error())?; 87 | Err(recv_err.into()) 88 | } 89 | } 90 | 91 | fn internal_send(&self, packet: &WinDivertPacket) -> Result { 92 | let mut injected_length = 0; 93 | 94 | let res = unsafe { 95 | sys::WinDivertSend( 96 | self.handle, 97 | packet.data.as_ptr() as *const c_void, 98 | packet.data.len() as u32, 99 | &mut injected_length, 100 | packet.address.as_ref(), 101 | ) 102 | }; 103 | 104 | if !res.as_bool() { 105 | return Err(std::io::Error::last_os_error().into()); 106 | } 107 | 108 | Ok(injected_length) 109 | } 110 | 111 | fn internal_send_ex<'data, 'packets, P>(&self, packets: P) -> Result 112 | where 113 | P: ExactSizeIterator>, 114 | 'data: 'packets, 115 | L: 'packets, 116 | { 117 | let packet_count = packets.len(); 118 | let mut injected_length = 0; 119 | let mut packet_buffer: Vec = Vec::new(); 120 | let mut address_buffer: Vec = Vec::with_capacity(packet_count); 121 | packets.for_each(|packet: &'packets WinDivertPacket<'data, L>| { 122 | packet_buffer.extend(&packet.data[..]); 123 | address_buffer.push(*packet.address.as_ref()); 124 | }); 125 | 126 | let res = unsafe { 127 | sys::WinDivertSendEx( 128 | self.handle, 129 | packet_buffer.as_ptr() as *const c_void, 130 | packet_buffer.len() as u32, 131 | &mut injected_length, 132 | 0, 133 | address_buffer.as_ptr(), 134 | (std::mem::size_of::() * packet_count) as u32, 135 | std::ptr::null_mut(), 136 | ) 137 | }; 138 | 139 | if !res.as_bool() { 140 | return Err(std::io::Error::last_os_error().into()); 141 | } 142 | 143 | Ok(injected_length) 144 | } 145 | } 146 | 147 | impl WinDivert { 148 | /// Single packet blocking recv function. 149 | pub fn recv<'a>( 150 | &self, 151 | buffer: Option<&'a mut [u8]>, 152 | ) -> Result, WinDivertError> { 153 | self.internal_recv(buffer) 154 | } 155 | 156 | /// Batched blocking recv function. 157 | pub fn recv_ex<'a>( 158 | &self, 159 | buffer: Option<&'a mut [u8]>, 160 | packet_count: usize, 161 | ) -> Result>, WinDivertError> { 162 | let (mut buffer, addresses) = self.internal_recv_ex(buffer, packet_count)?; 163 | let mut packets = Vec::with_capacity(addresses.len()); 164 | for addr in addresses.into_iter() { 165 | packets.push(WinDivertPacket { 166 | address: WinDivertAddress::::from_raw(addr), 167 | data: buffer 168 | .map(|inner_buffer| { 169 | let headers = SlicedPacket::from_ip(inner_buffer) 170 | .expect("WinDivert can't capture anything below ip"); 171 | let offset = match headers.ip.unwrap() { 172 | InternetSlice::Ipv4(ip_header, _) => ip_header.total_len() as usize, 173 | InternetSlice::Ipv6(ip6header, _) => { 174 | ip6header.payload_length() as usize + 40 175 | } 176 | }; 177 | let (data, tail) = inner_buffer.split_at(offset); 178 | buffer = Some(tail); 179 | Cow::Borrowed(data) 180 | }) 181 | .unwrap_or_default(), 182 | }); 183 | } 184 | Ok(packets) 185 | } 186 | 187 | /// Single packet send function. 188 | pub fn send( 189 | &self, 190 | packet: &WinDivertPacket, 191 | ) -> Result { 192 | self.internal_send(packet) 193 | } 194 | 195 | /// Batched packet send function. 196 | pub fn send_ex<'data, 'packets, P, I>(&self, packets: P) -> Result 197 | where 198 | P: IntoIterator, 199 | I: ExactSizeIterator>, 200 | 'data: 'packets, 201 | { 202 | self.internal_send_ex(packets.into_iter()) 203 | } 204 | } 205 | 206 | impl WinDivert { 207 | /// Single packet blocking recv function. 208 | pub fn recv<'a>( 209 | &self, 210 | buffer: Option<&'a mut [u8]>, 211 | ) -> Result, WinDivertError> { 212 | self.internal_recv(buffer) 213 | } 214 | 215 | /// Batched blocking recv function. 216 | pub fn recv_ex<'a>( 217 | &self, 218 | buffer: Option<&'a mut [u8]>, 219 | packet_count: usize, 220 | ) -> Result>, WinDivertError> { 221 | let (mut buffer, addresses) = self.internal_recv_ex(buffer, packet_count)?; 222 | let mut packets = Vec::with_capacity(addresses.len()); 223 | for addr in addresses.into_iter() { 224 | packets.push(WinDivertPacket { 225 | address: WinDivertAddress::::from_raw(addr), 226 | data: buffer 227 | .map(|inner_buffer| { 228 | let headers = SlicedPacket::from_ip(inner_buffer) 229 | .expect("WinDivert can't capture anything below ip"); 230 | let offset = match headers.ip.unwrap() { 231 | InternetSlice::Ipv4(ip_header, _) => ip_header.total_len() as usize, 232 | InternetSlice::Ipv6(ip6header, _) => { 233 | ip6header.payload_length() as usize + 40 234 | } 235 | }; 236 | let (data, tail) = inner_buffer.split_at(offset); 237 | buffer = Some(tail); 238 | Cow::Borrowed(data) 239 | }) 240 | .unwrap_or_default(), 241 | }); 242 | } 243 | Ok(packets) 244 | } 245 | 246 | /// Single packet send function. 247 | pub fn send( 248 | &self, 249 | packet: &WinDivertPacket, 250 | ) -> Result { 251 | self.internal_send(packet) 252 | } 253 | 254 | /// Batched packet send function. 255 | pub fn send_ex<'data, 'packets, P, I>(&self, packets: P) -> Result 256 | where 257 | P: IntoIterator, 258 | I: ExactSizeIterator>, 259 | 'data: 'packets, 260 | { 261 | self.internal_send_ex(packets.into_iter()) 262 | } 263 | } 264 | 265 | impl WinDivert { 266 | /// Single packet blocking recv function. 267 | pub fn recv<'a>( 268 | &self, 269 | buffer: Option<&'a mut [u8]>, 270 | ) -> Result, WinDivertError> { 271 | self.internal_recv(buffer) 272 | } 273 | 274 | /// Batched blocking recv function. 275 | pub fn recv_ex<'a>( 276 | &self, 277 | packet_count: usize, 278 | ) -> Result>, WinDivertError> { 279 | let (_, addresses) = self.internal_recv_ex(None, packet_count)?; 280 | let mut packets = Vec::with_capacity(addresses.len()); 281 | for addr in addresses.into_iter() { 282 | packets.push(WinDivertPacket:: { 283 | address: WinDivertAddress::::from_raw(addr), 284 | data: Default::default(), 285 | }); 286 | } 287 | Ok(packets) 288 | } 289 | } 290 | 291 | impl WinDivert { 292 | /// Single packet blocking recv function. 293 | pub fn recv<'a>( 294 | &self, 295 | buffer: Option<&'a mut [u8]>, 296 | ) -> Result, WinDivertError> { 297 | self.internal_recv(buffer) 298 | } 299 | 300 | /// Batched blocking recv function. 301 | pub fn recv_ex<'a>( 302 | &self, 303 | packet_count: usize, 304 | ) -> Result>, WinDivertError> { 305 | let (_, addresses) = self.internal_recv_ex(None, packet_count)?; 306 | let mut packets = Vec::with_capacity(addresses.len()); 307 | for addr in addresses.into_iter() { 308 | packets.push(WinDivertPacket:: { 309 | address: WinDivertAddress::::from_raw(addr), 310 | data: Default::default(), 311 | }); 312 | } 313 | Ok(packets) 314 | } 315 | } 316 | 317 | impl WinDivert { 318 | /// Single packet blocking recv function. 319 | pub fn recv<'a>( 320 | &self, 321 | buffer: Option<&'a mut [u8]>, 322 | ) -> Result, WinDivertError> { 323 | self.internal_recv(buffer) 324 | } 325 | 326 | /// Batched blocking recv function. 327 | pub fn recv_ex<'a>( 328 | &self, 329 | buffer: Option<&'a mut [u8]>, 330 | packet_count: usize, 331 | ) -> Result>, WinDivertError> { 332 | let (mut buffer, addresses) = self.internal_recv_ex(buffer, packet_count)?; 333 | let mut packets = Vec::with_capacity(addresses.len()); 334 | for addr in addresses.into_iter() { 335 | packets.push(WinDivertPacket { 336 | address: WinDivertAddress::::from_raw(addr), 337 | data: buffer 338 | .map(|inner_buffer| { 339 | let (data, tail) = inner_buffer.split_at( 340 | inner_buffer 341 | .iter() 342 | .position(|&x| x == b'\0') 343 | .expect("CStrings always end in null"), 344 | ); 345 | buffer = Some(tail); 346 | Cow::Borrowed(data) 347 | }) 348 | .unwrap_or_default(), 349 | }); 350 | } 351 | Ok(packets) 352 | } 353 | } 354 | -------------------------------------------------------------------------------- /windivert-sys/src/bindings/header.rs: -------------------------------------------------------------------------------- 1 | /*! 2 | WinDivert header types. 3 | */ 4 | #![allow(missing_docs)] 5 | use std::{ 6 | fmt::Debug, 7 | net::{Ipv4Addr, Ipv6Addr}, 8 | }; 9 | 10 | use super::BitfieldUnit; 11 | 12 | /** 13 | IPV4 header. 14 | 15 | For more info, refer to the [docs](https://reqrypt.org/windivert-doc.html#divert_iphdr) 16 | */ 17 | #[repr(C)] 18 | #[derive(Default, Copy, Clone)] 19 | pub struct WINDIVERT_IPHDR { 20 | addr_bitfield: BitfieldUnit<[u8; 1usize], u8>, 21 | pub tos: u8, 22 | length: u16, 23 | id: u16, 24 | fragment_offset_and_flags: u16, 25 | pub ttl: u8, 26 | pub protocol: u8, 27 | checksum: u16, 28 | src_addr: u32, 29 | dst_addr: u32, 30 | } 31 | 32 | impl WINDIVERT_IPHDR { 33 | #[inline] 34 | pub fn header_length(&self) -> u8 { 35 | self.addr_bitfield.get(0usize, 4u8) as u8 36 | } 37 | #[inline] 38 | pub fn set_header_length(&mut self, val: u8) { 39 | self.addr_bitfield.set(0usize, 4u8, val as u64) 40 | } 41 | #[inline] 42 | pub fn version(&self) -> u8 { 43 | self.addr_bitfield.get(4usize, 4u8) as u8 44 | } 45 | #[inline] 46 | pub fn set_version(&mut self, val: u8) { 47 | self.addr_bitfield.set(4usize, 4u8, val as u64) 48 | } 49 | #[inline] 50 | pub fn length(&self) -> u16 { 51 | u16::from_be(self.length) 52 | } 53 | #[inline] 54 | pub fn set_length(&mut self, value: u16) { 55 | self.length = value.to_be(); 56 | } 57 | #[inline] 58 | pub fn id(&self) -> u16 { 59 | u16::from_be(self.id) 60 | } 61 | #[inline] 62 | pub fn set_id(&mut self, value: u16) { 63 | self.id = value.to_be(); 64 | } 65 | #[inline] 66 | pub fn fragment_offset(&self) -> u16 { 67 | u16::from_be(self.fragment_offset_and_flags & 0xFF1F) 68 | } 69 | #[inline] 70 | pub fn set_fragment_offset(&mut self, value: u16) { 71 | self.fragment_offset_and_flags = 72 | self.fragment_offset_and_flags & 0x00E0 | (value & 0x1FFF).to_be() 73 | } 74 | #[inline] 75 | pub fn MF(&self) -> bool { 76 | self.fragment_offset_and_flags & 0x0020 != 0 77 | } 78 | #[inline] 79 | pub fn set_MF(&mut self, value: bool) { 80 | self.fragment_offset_and_flags = 81 | self.fragment_offset_and_flags & 0xFFDF | ((value as u16) << 5) 82 | } 83 | #[inline] 84 | pub fn DF(&self) -> bool { 85 | self.fragment_offset_and_flags & 0x0040 != 0 86 | } 87 | #[inline] 88 | pub fn set_DF(&mut self, value: bool) { 89 | self.fragment_offset_and_flags = 90 | self.fragment_offset_and_flags & 0xFFBF | ((value as u16) << 6) 91 | } 92 | #[inline] 93 | pub fn checksum(&self) -> u16 { 94 | u16::from_be(self.checksum) 95 | } 96 | #[inline] 97 | pub fn set_checksum(&mut self, value: u16) { 98 | self.checksum = value.to_be(); 99 | } 100 | #[inline] 101 | pub fn src_addr(&self) -> u32 { 102 | u32::from_be(self.src_addr) 103 | } 104 | #[inline] 105 | pub fn src_ip_addr(&self) -> Ipv4Addr { 106 | Ipv4Addr::from(self.src_addr) 107 | } 108 | #[inline] 109 | pub fn set_src_addr(&mut self, value: u32) { 110 | self.src_addr = value.to_be(); 111 | } 112 | #[inline] 113 | pub fn dst_addr(&self) -> u32 { 114 | u32::from_be(self.dst_addr) 115 | } 116 | #[inline] 117 | pub fn dst_ip_addr(&self) -> Ipv4Addr { 118 | Ipv4Addr::from(self.dst_addr) 119 | } 120 | #[inline] 121 | pub fn set_dst_addr(&mut self, value: u32) { 122 | self.dst_addr = value.to_be(); 123 | } 124 | } 125 | 126 | impl Debug for WINDIVERT_IPHDR { 127 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 128 | write!(f, "WINDIVERT_IPHDR {{ header_length: {:?}, version: {:?}, tos: {:?}, length: {:?}, id: {:?}, MF: {:?}, DF: {:?}, fragment_offset: {:?}, ttl: {:?}, protocol: {:?}, checksum: {:?}, src_addr: {:?}, dst_addr: {:?} }}", 129 | self.header_length(), self.version(), self.tos, self.length(), self.id(), self.MF(), self.DF(), self.fragment_offset(), self.ttl, self.protocol, self.checksum(), self.src_addr(), self.dst_addr()) 130 | } 131 | } 132 | 133 | /// [IPV4 header](WINDIVERT_IPHDR) pointer type. 134 | pub type PWINDIVERT_IPHDR = *mut WINDIVERT_IPHDR; 135 | 136 | /** 137 | IPV6 header. 138 | 139 | For more info, refer to the [docs](https://reqrypt.org/windivert-doc.html#divert_ipv6hdr) 140 | */ 141 | #[repr(C)] 142 | #[derive(Default, Copy, Clone)] 143 | pub struct WINDIVERT_IPV6HDR { 144 | addr_bitfield: BitfieldUnit<[u8; 2usize], u8>, 145 | flow_label_1: u16, 146 | length: u16, 147 | pub next_header: u8, 148 | pub hop_limit: u8, 149 | src_addr: [u32; 4usize], 150 | dst_addr: [u32; 4usize], 151 | } 152 | 153 | impl WINDIVERT_IPV6HDR { 154 | #[inline] 155 | pub fn version(&self) -> u8 { 156 | self.addr_bitfield.get(4usize, 4u8) as u8 157 | } 158 | #[inline] 159 | pub fn set_version(&mut self, val: u8) { 160 | self.addr_bitfield.set(4usize, 4u8, val as u64) 161 | } 162 | #[inline] 163 | pub fn traffic_class(&self) -> u8 { 164 | u8::from_be(self.traffic_class0() << 4 | self.traffic_class1()) 165 | } 166 | pub fn set_traffic_class(&mut self, value: u8) { 167 | let value = value.to_be(); 168 | self.set_traffic_class0(value >> 4); 169 | self.set_traffic_class1(value); 170 | } 171 | #[inline] 172 | fn traffic_class0(&self) -> u8 { 173 | self.addr_bitfield.get(0usize, 4u8) as u8 174 | } 175 | #[inline] 176 | fn set_traffic_class0(&mut self, val: u8) { 177 | self.addr_bitfield.set(0usize, 4u8, val as u64) 178 | } 179 | #[inline] 180 | fn traffic_class1(&self) -> u8 { 181 | self.addr_bitfield.get(12usize, 4u8) as u8 182 | } 183 | #[inline] 184 | fn set_traffic_class1(&mut self, val: u8) { 185 | self.addr_bitfield.set(12usize, 4u8, val as u64) 186 | } 187 | #[inline] 188 | pub fn flow_label(&self) -> u32 { 189 | u32::from_be((self.flow_label0() as u32) << 16 | self.flow_label_1 as u32) 190 | } 191 | #[inline] 192 | pub fn set_flow_label(&mut self, value: u32) { 193 | let value = value.to_be(); 194 | self.set_flow_label0((value >> 16) as u8); 195 | self.flow_label_1 = value as u16; 196 | } 197 | #[inline] 198 | fn flow_label0(&self) -> u8 { 199 | self.addr_bitfield.get(8usize, 4u8) as u8 200 | } 201 | #[inline] 202 | fn set_flow_label0(&mut self, val: u8) { 203 | self.addr_bitfield.set(8usize, 4u8, val as u64) 204 | } 205 | #[inline] 206 | pub fn length(&self) -> u16 { 207 | u16::from_be(self.length) 208 | } 209 | #[inline] 210 | pub fn src_addr(&self) -> u128 { 211 | u128::from_be( 212 | self.src_addr 213 | .iter() 214 | .rev() 215 | .fold(0u128, |acc, &x| (acc << 32) | x as u128), 216 | ) 217 | } 218 | #[inline] 219 | pub fn src_ip_addr(&self) -> Ipv6Addr { 220 | Ipv6Addr::from(self.src_addr()) 221 | } 222 | #[inline] 223 | pub fn set_src_addr(&mut self, value: u128) { 224 | let tmp = value 225 | .to_be_bytes() 226 | .chunks(4) 227 | .map(|x| { 228 | let mut tmp: [u8; 4] = Default::default(); 229 | tmp.copy_from_slice(x); 230 | u32::from_ne_bytes(tmp) 231 | }) 232 | .collect::>(); 233 | self.src_addr.copy_from_slice(&tmp); 234 | } 235 | #[inline] 236 | pub fn dst_addr(&self) -> u128 { 237 | u128::from_be( 238 | self.dst_addr 239 | .iter() 240 | .rev() 241 | .fold(0u128, |acc, &x| (acc << 32) | x as u128), 242 | ) 243 | } 244 | #[inline] 245 | pub fn dst_ip_addr(&self) -> Ipv6Addr { 246 | Ipv6Addr::from(self.dst_addr()) 247 | } 248 | #[inline] 249 | pub fn set_dst_addr(&mut self, value: u128) { 250 | let tmp = value 251 | .to_be_bytes() 252 | .chunks(4) 253 | .map(|x| { 254 | let mut tmp: [u8; 4] = Default::default(); 255 | tmp.copy_from_slice(x); 256 | u32::from_ne_bytes(tmp) 257 | }) 258 | .collect::>(); 259 | self.dst_addr.copy_from_slice(&tmp); 260 | } 261 | } 262 | 263 | impl Debug for WINDIVERT_IPV6HDR { 264 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 265 | write!(f, "WINDIVERT_IPV6HDR {{ version: {:?}, traffic_class: {:?}, flow_label: {:?}, length: {:?}, MextHdr: {:?}, hop_limit: {:?}, src_addr: {:?}, dst_addr: {:?} }}", self.version(), self.traffic_class(), self.flow_label(), self.length(), self.next_header, self.hop_limit, self.src_addr(), self.dst_addr()) 266 | } 267 | } 268 | 269 | /// [IPV6 header](WINDIVERT_IPV6HDR) pointer type. 270 | pub type PWINDIVERT_IPV6HDR = *mut WINDIVERT_IPV6HDR; 271 | 272 | /** 273 | ICMP header. 274 | 275 | For more info, refer to the [docs](https://reqrypt.org/windivert-doc.html#divert_icmphdr) 276 | */ 277 | #[repr(C)] 278 | #[derive(Default, Copy, Clone)] 279 | pub struct WINDIVERT_ICMPHDR { 280 | pub msg_type: u8, 281 | pub msg_code: u8, 282 | checksum: u16, 283 | body: u32, 284 | } 285 | 286 | impl WINDIVERT_ICMPHDR { 287 | #[inline] 288 | pub fn checksum(&self) -> u16 { 289 | u16::from_be(self.checksum) 290 | } 291 | #[inline] 292 | pub fn set_Checksum(&mut self, value: u16) { 293 | self.checksum = value.to_be(); 294 | } 295 | #[inline] 296 | pub fn body(&self) -> u32 { 297 | u32::from_be(self.body) 298 | } 299 | #[inline] 300 | pub fn set_Body(&mut self, value: u32) { 301 | self.body = value.to_be(); 302 | } 303 | } 304 | 305 | impl Debug for WINDIVERT_ICMPHDR { 306 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 307 | write!( 308 | f, 309 | "WINDIVERT_ICMPHDR {{ msg_type: {:?}, msg_code: {:?}, checksum: {:?}, body: {:?} }}", 310 | self.msg_type, 311 | self.msg_code, 312 | self.checksum(), 313 | self.body() 314 | ) 315 | } 316 | } 317 | 318 | /// [ICMP header](WINDIVERT_ICMPHDR) pointer type. 319 | pub type PWINDIVERT_ICMPHDR = *mut WINDIVERT_ICMPHDR; 320 | 321 | /** 322 | ICMPV6 header. 323 | 324 | For more info, refer to the [docs](https://reqrypt.org/windivert-doc.html#divert_icmpv6hdr) 325 | */ 326 | #[repr(C)] 327 | #[derive(Default, Copy, Clone)] 328 | pub struct WINDIVERT_ICMPV6HDR { 329 | pub msg_type: u8, 330 | pub msg_code: u8, 331 | checksum: u16, 332 | body: u32, 333 | } 334 | 335 | impl WINDIVERT_ICMPV6HDR { 336 | #[inline] 337 | pub fn checksum(&self) -> u16 { 338 | u16::from_be(self.checksum) 339 | } 340 | #[inline] 341 | pub fn set_Checksum(&mut self, value: u16) { 342 | self.checksum = value.to_be(); 343 | } 344 | #[inline] 345 | pub fn body(&self) -> u32 { 346 | u32::from_be(self.body) 347 | } 348 | #[inline] 349 | pub fn set_Body(&mut self, value: u32) { 350 | self.body = value.to_be(); 351 | } 352 | } 353 | 354 | impl Debug for WINDIVERT_ICMPV6HDR { 355 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 356 | write!( 357 | f, 358 | "WINDIVERT_ICMPHDR {{ msg_type: {:?}, msg_code: {:?}, checksum: {:?}, body: {:?} }}", 359 | self.msg_type, 360 | self.msg_code, 361 | self.checksum(), 362 | self.body() 363 | ) 364 | } 365 | } 366 | 367 | /// [ICMPV6 header](WINDIVERT_ICMPV6HDR) pointer type. 368 | pub type PWINDIVERT_ICMPV6HDR = *mut WINDIVERT_ICMPV6HDR; 369 | 370 | /** 371 | TCP header. 372 | 373 | For more info, refer to the [docs](https://reqrypt.org/windivert-doc.html#divert_tcphdr) 374 | */ 375 | #[repr(C)] 376 | #[derive(Default, Copy, Clone)] 377 | pub struct WINDIVERT_TCPHDR { 378 | src_port: u16, 379 | dst_port: u16, 380 | seq_number: u32, 381 | ACK_number: u32, 382 | addr_bitfield: BitfieldUnit<[u8; 2usize], u8>, 383 | window: u16, 384 | checksum: u16, 385 | urg_ptr: u16, 386 | } 387 | 388 | impl WINDIVERT_TCPHDR { 389 | #[inline] 390 | pub fn src_port(&self) -> u16 { 391 | u16::from_be(self.src_port) 392 | } 393 | #[inline] 394 | pub fn set_src_port(&mut self, value: u16) { 395 | self.src_port = value.to_be(); 396 | } 397 | #[inline] 398 | pub fn dst_port(&self) -> u16 { 399 | u16::from_be(self.dst_port) 400 | } 401 | #[inline] 402 | pub fn set_dst_port(&mut self, value: u16) { 403 | self.dst_port = value.to_be(); 404 | } 405 | #[inline] 406 | pub fn seq_number(&self) -> u32 { 407 | u32::from_be(self.seq_number) 408 | } 409 | #[inline] 410 | pub fn set_seq_number(&mut self, value: u32) { 411 | self.seq_number = value.to_be(); 412 | } 413 | #[inline] 414 | pub fn ACK_number(&self) -> u32 { 415 | u32::from_be(self.ACK_number) 416 | } 417 | #[inline] 418 | pub fn set_ACK_number(&mut self, value: u32) { 419 | self.ACK_number = value.to_be(); 420 | } 421 | #[inline] 422 | pub fn header_length(&self) -> u16 { 423 | self.addr_bitfield.get(4usize, 4u8) as u16 424 | } 425 | #[inline] 426 | pub fn set_header_length(&mut self, val: u16) { 427 | self.addr_bitfield.set(4usize, 4u8, val as u64) 428 | } 429 | #[inline] 430 | pub fn FIN(&self) -> u16 { 431 | self.addr_bitfield.get(8usize, 1u8) as u16 432 | } 433 | #[inline] 434 | pub fn set_FIN(&mut self, val: u16) { 435 | self.addr_bitfield.set(8usize, 1u8, val as u64) 436 | } 437 | #[inline] 438 | pub fn SYN(&self) -> u16 { 439 | self.addr_bitfield.get(9usize, 1u8) as u16 440 | } 441 | #[inline] 442 | pub fn set_SYN(&mut self, val: u16) { 443 | self.addr_bitfield.set(9usize, 1u8, val as u64) 444 | } 445 | #[inline] 446 | pub fn RST(&self) -> u16 { 447 | self.addr_bitfield.get(10usize, 1u8) as u16 448 | } 449 | #[inline] 450 | pub fn set_RST(&mut self, val: u16) { 451 | self.addr_bitfield.set(10usize, 1u8, val as u64) 452 | } 453 | #[inline] 454 | pub fn PSH(&self) -> u16 { 455 | self.addr_bitfield.get(11usize, 1u8) as u16 456 | } 457 | #[inline] 458 | pub fn set_PSH(&mut self, val: u16) { 459 | self.addr_bitfield.set(11usize, 1u8, val as u64) 460 | } 461 | #[inline] 462 | pub fn ACK(&self) -> u16 { 463 | self.addr_bitfield.get(12usize, 1u8) as u16 464 | } 465 | #[inline] 466 | pub fn set_ACK(&mut self, val: u16) { 467 | self.addr_bitfield.set(12usize, 1u8, val as u64) 468 | } 469 | #[inline] 470 | pub fn URG(&self) -> u16 { 471 | self.addr_bitfield.get(13usize, 1u8) as u16 472 | } 473 | #[inline] 474 | pub fn set_URG(&mut self, val: u16) { 475 | self.addr_bitfield.set(13usize, 1u8, val as u64) 476 | } 477 | #[inline] 478 | pub fn window(&self) -> u16 { 479 | u16::from_be(self.window) 480 | } 481 | #[inline] 482 | pub fn set_window(&mut self, value: u16) { 483 | self.window = value.to_be(); 484 | } 485 | #[inline] 486 | pub fn checksum(&self) -> u16 { 487 | u16::from_be(self.checksum) 488 | } 489 | #[inline] 490 | pub fn set_Checksum(&mut self, value: u16) { 491 | self.checksum = value.to_be(); 492 | } 493 | #[inline] 494 | pub fn urg_ptr(&self) -> u16 { 495 | u16::from_be(self.urg_ptr) 496 | } 497 | #[inline] 498 | pub fn set_urg_ptr(&mut self, value: u16) { 499 | self.urg_ptr = value.to_be(); 500 | } 501 | } 502 | 503 | impl Debug for WINDIVERT_TCPHDR { 504 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 505 | write!(f, "WINDIVERT_TCPHDR {{ src_port: {:?}, dst_port: {:?}, seq_number: {:?}, ACK_number: {:?}, header_length: {:?}, URG: {:?}, ACK: {:?}, PSH: {:?}, RST: {:?}, SYN: {:?}, FIN: {:?}, window: {:?}, checksum: {:?}, urg_ptr: {:?} }}", self.src_port(), self.dst_port(), self.seq_number(), self.ACK_number(), self.header_length(), self.URG(), self.ACK(), self.PSH(), self.RST(), self.SYN(), self.FIN(), self.window(), self.checksum(), self.urg_ptr()) 506 | } 507 | } 508 | 509 | /// [TCP header](WINDIVERT_TCPHDR) pointer type. 510 | pub type PWINDIVERT_TCPHDR = *mut WINDIVERT_TCPHDR; 511 | 512 | /** 513 | UDP header. 514 | 515 | For more info, refer to the [docs](https://reqrypt.org/windivert-doc.html#divert_udphdr) 516 | */ 517 | #[repr(C)] 518 | #[derive(Default, Copy, Clone)] 519 | pub struct WINDIVERT_UDPHDR { 520 | src_port: u16, 521 | dst_port: u16, 522 | length: u16, 523 | checksum: u16, 524 | } 525 | 526 | impl WINDIVERT_UDPHDR { 527 | #[inline] 528 | pub fn src_port(&self) -> u16 { 529 | u16::from_be(self.src_port) 530 | } 531 | #[inline] 532 | pub fn set_src_port(&mut self, value: u16) { 533 | self.src_port = value.to_be(); 534 | } 535 | #[inline] 536 | pub fn dst_port(&self) -> u16 { 537 | u16::from_be(self.dst_port) 538 | } 539 | #[inline] 540 | pub fn set_dst_port(&mut self, value: u16) { 541 | self.dst_port = value.to_be(); 542 | } 543 | #[inline] 544 | pub fn length(&self) -> u16 { 545 | u16::from_be(self.length) 546 | } 547 | #[inline] 548 | pub fn set_length(&mut self, value: u16) { 549 | self.length = value.to_be(); 550 | } 551 | #[inline] 552 | pub fn checksum(&self) -> u16 { 553 | u16::from_be(self.checksum) 554 | } 555 | #[inline] 556 | pub fn set_Checksum(&mut self, value: u16) { 557 | self.checksum = value.to_be(); 558 | } 559 | } 560 | 561 | impl Debug for WINDIVERT_UDPHDR { 562 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 563 | write!( 564 | f, 565 | "WINDIVERT_UDPHDR {{ src_port: {:?}, dst_port: {:?}, length: {:?}, checksum: {:?} }}", 566 | self.src_port(), 567 | self.dst_port(), 568 | self.length(), 569 | self.checksum() 570 | ) 571 | } 572 | } 573 | 574 | /// [UDP header](WINDIVERT_UDPHDR) pointer type. 575 | pub type PWINDIVERT_UDPHDR = *mut WINDIVERT_UDPHDR; 576 | -------------------------------------------------------------------------------- /windivert-sys/src/bindings/newtypes.rs: -------------------------------------------------------------------------------- 1 | use std::{convert::TryFrom, u32}; 2 | 3 | use super::WinDivertValueError; 4 | 5 | /** 6 | WinDivert layer to initialize the handle. 7 | 8 | WinDivert supports several layers for diverting or capturing network packets/events. Each layer has its own capabilities, such as the ability to block events or to inject new events, etc. The list of supported WinDivert layers is summarized below: 9 | 10 | | Layer | Block? | Inject? | Data? | PID? | Description | 11 | | --------- | ---------- | ----------- | ----- | ---- | -------------------------------------------------- | 12 | | `Network` | ✔ | ✔ | ✔ | | Network packets to/from the local machine. | 13 | | `Forward` | ✔ | ✔ | ✔ | | Network packets passing through the local machine. | 14 | | `Flow` | | | | ✔ | Network flow established/deleted events. | 15 | | `Socket` | ✔ | | | ✔ | Socket operation events. | 16 | | `Reflect` | | | ✔ | ✔ | WinDivert handle events. | 17 | */ 18 | #[repr(u32)] 19 | #[derive(Debug, Copy, Clone)] 20 | pub enum WinDivertLayer { 21 | /// Network packets to/from the local machine. 22 | Network = 0, 23 | /// Network packets passing through the local machine. 24 | Forward = 1, 25 | /// Network flow established/deleted events. 26 | Flow = 2, 27 | /// Socket operation events 28 | Socket = 3, 29 | /// WinDivert handle events. 30 | Reflect = 4, 31 | } 32 | 33 | impl TryFrom for WinDivertLayer { 34 | type Error = WinDivertValueError; 35 | 36 | fn try_from(value: u32) -> Result { 37 | match value { 38 | 0 => Ok(WinDivertLayer::Network), 39 | 1 => Ok(WinDivertLayer::Forward), 40 | 2 => Ok(WinDivertLayer::Flow), 41 | 3 => Ok(WinDivertLayer::Socket), 42 | 4 => Ok(WinDivertLayer::Reflect), 43 | _ => Err(WinDivertValueError::Layer(value)), 44 | } 45 | } 46 | } 47 | 48 | impl From for u8 { 49 | fn from(value: WinDivertLayer) -> Self { 50 | match value { 51 | WinDivertLayer::Network => 0, 52 | WinDivertLayer::Forward => 1, 53 | WinDivertLayer::Flow => 2, 54 | WinDivertLayer::Socket => 3, 55 | WinDivertLayer::Reflect => 4, 56 | } 57 | } 58 | } 59 | 60 | impl From for u32 { 61 | fn from(value: WinDivertLayer) -> Self { 62 | u8::from(value) as u32 63 | } 64 | } 65 | 66 | /** 67 | WinDivert event identifiers. 68 | 69 | Each [`WinDivertLayer`] supports one or more kind of events: 70 | * [`Network`](WinDivertLayer::Network) and [`Forward`](WinDivertLayer::Forward): 71 | * [`WinDivertEvent::NetworkPacket`] 72 | * [`Flow`](WinDivertLayer::Flow): 73 | * [`WinDivertEvent::FlowStablished`] 74 | * [`WinDivertEvent::FlowDeleted`] 75 | * [`Socket`](WinDivertLayer::Socket): 76 | * [`WinDivertEvent::SocketBind`] 77 | * [`WinDivertEvent::SocketConnect`] 78 | * [`WinDivertEvent::SocketListen`] 79 | * [`WinDivertEvent::SocketAccept`] 80 | * [`WinDivertEvent::SocketClose`] 81 | * [`Reflect`](WinDivertLayer::Reflect): 82 | * [`WinDivertEvent::ReflectOpen`] 83 | * [`WinDivertEvent::ReflectClose`] 84 | */ 85 | #[repr(C)] 86 | #[derive(Debug, Copy, Clone)] 87 | pub enum WinDivertEvent { 88 | /// Network packet. 89 | NetworkPacket = 0, 90 | /// Flow established. 91 | FlowStablished = 1, 92 | /// Flow deleted. 93 | FlowDeleted = 2, 94 | /// Socket bind. 95 | SocketBind = 3, 96 | /// Socket connect. 97 | SocketConnect = 4, 98 | /// Socket listen. 99 | SocketListen = 5, 100 | /// Socket accept. 101 | SocketAccept = 6, 102 | /// Socket close. 103 | SocketClose = 7, 104 | /// WinDivert handle opened. 105 | ReflectOpen = 8, 106 | /// WinDivert handle closed. 107 | ReflectClose = 9, 108 | } 109 | 110 | impl TryFrom for WinDivertEvent { 111 | type Error = WinDivertValueError; 112 | 113 | fn try_from(value: u8) -> Result { 114 | match value { 115 | 0 => Ok(Self::NetworkPacket), 116 | 1 => Ok(Self::FlowStablished), 117 | 2 => Ok(Self::FlowDeleted), 118 | 3 => Ok(Self::SocketBind), 119 | 4 => Ok(Self::SocketConnect), 120 | 5 => Ok(Self::SocketListen), 121 | 6 => Ok(Self::SocketAccept), 122 | 7 => Ok(Self::SocketClose), 123 | 8 => Ok(Self::ReflectOpen), 124 | 9 => Ok(Self::ReflectClose), 125 | _ => Err(WinDivertValueError::Event(value)), 126 | } 127 | } 128 | } 129 | 130 | impl From for u8 { 131 | fn from(value: WinDivertEvent) -> Self { 132 | match value { 133 | WinDivertEvent::NetworkPacket => 0, 134 | WinDivertEvent::FlowStablished => 1, 135 | WinDivertEvent::FlowDeleted => 2, 136 | WinDivertEvent::SocketBind => 3, 137 | WinDivertEvent::SocketConnect => 4, 138 | WinDivertEvent::SocketListen => 5, 139 | WinDivertEvent::SocketAccept => 6, 140 | WinDivertEvent::SocketClose => 7, 141 | WinDivertEvent::ReflectOpen => 8, 142 | WinDivertEvent::ReflectClose => 9, 143 | } 144 | } 145 | } 146 | 147 | impl From for u32 { 148 | fn from(value: WinDivertEvent) -> Self { 149 | u8::from(value) as u32 150 | } 151 | } 152 | 153 | /** 154 | WinDivert shutdown mode. 155 | */ 156 | #[repr(u32)] 157 | #[derive(Debug, Copy, Clone)] 158 | pub enum WinDivertShutdownMode { 159 | /// Stops new packets being queued for [`WinDivertRecv`](fn@super::WinDivertRecv) 160 | Recv = 1, 161 | /// Stops new packets being injected via [`WinDivertSend`](fn@super::WinDivertSend) 162 | Send = 2, 163 | /// Equivalent to [`WinDivertShutdownMode::Recv`] | [`WinDivertShutdownMode::Send`] 164 | Both = 3, 165 | } 166 | 167 | impl TryFrom for WinDivertShutdownMode { 168 | type Error = WinDivertValueError; 169 | 170 | fn try_from(value: u32) -> Result { 171 | match value { 172 | 1 => Ok(WinDivertShutdownMode::Recv), 173 | 2 => Ok(WinDivertShutdownMode::Send), 174 | 3 => Ok(WinDivertShutdownMode::Both), 175 | _ => Err(WinDivertValueError::Shutdown(value)), 176 | } 177 | } 178 | } 179 | 180 | impl From for u32 { 181 | fn from(value: WinDivertShutdownMode) -> Self { 182 | match value { 183 | WinDivertShutdownMode::Recv => 1, 184 | WinDivertShutdownMode::Send => 2, 185 | WinDivertShutdownMode::Both => 3, 186 | } 187 | } 188 | } 189 | 190 | /** 191 | WinDivert parameter enum. 192 | 193 | Used to specify the parameter in [`WinDivertGetParam()`](fn@super::WinDivertGetParam) and [`WinDivertSetParam()`](fn@super::WinDivertSetParam). 194 | */ 195 | #[repr(u32)] 196 | #[derive(Debug, Copy, Clone)] 197 | pub enum WinDivertParam { 198 | /** 199 | WINDIVERT_PARAM_QUEUE_TIME parameter. 200 | 201 | Sets the maximum length of the packet queue for [`WinDivertRecv()`](fn@super::WinDivertRecv). 202 | 203 | The range of valid values goes from [`WINDIVERT_PARAM_QUEUE_LENGTH_MIN`](value@super::WINDIVERT_PARAM_QUEUE_LENGTH_MIN) to [`WINDIVERT_PARAM_QUEUE_LENGTH_MAX`](value@super::WINDIVERT_PARAM_QUEUE_LENGTH_MAX), with a default value of [`WINDIVERT_PARAM_QUEUE_LENGTH_DEFAULT`](`value@super::WINDIVERT_PARAM_QUEUE_LENGTH_DEFAULT`). 204 | */ 205 | QueueLength = 0, 206 | /** 207 | WINDIVERT_PARAM_QUEUE_LENGTH parameter. 208 | 209 | Sets the minimum time, in milliseconds, a packet can be queued before it is automatically dropped. Packets cannot be queued indefinitely, and ideally, packets should be processed by the application as soon as is possible. Note that this sets the minimum time a packet can be queued before it can be dropped. The actual time may be exceed this value. 210 | 211 | The range of valid values goes from [`WINDIVERT_PARAM_QUEUE_TIME_MIN`](value@super::WINDIVERT_PARAM_QUEUE_TIME_MIN) to [`WINDIVERT_PARAM_QUEUE_TIME_MAX`](value@super::WINDIVERT_PARAM_QUEUE_TIME_MAX), with a fefault value of [`WINDIVERT_PARAM_QUEUE_TIME_DEFAULT`](`value@super::WINDIVERT_PARAM_QUEUE_TIME_DEFAULT`). 212 | */ 213 | QueueTime = 1, 214 | /** 215 | WINDIVERT_PARAM_QUEUE_SIZE parameter. 216 | 217 | Sets the maximum number of bytes that can be stored in the packet queue for [`WinDivertRecv()`](fn@super::WinDivertRecv). 218 | 219 | The range of valid values goes from [`WINDIVERT_PARAM_QUEUE_SIZE_MIN`](value@super::WINDIVERT_PARAM_QUEUE_SIZE_MIN) to [`WINDIVERT_PARAM_QUEUE_SIZE_MAX`](value@super::WINDIVERT_PARAM_QUEUE_SIZE_MAX), with a fefault value of [`WINDIVERT_PARAM_QUEUE_SIZE_DEFAULT`](`value@super::WINDIVERT_PARAM_QUEUE_SIZE_DEFAULT`). 220 | */ 221 | QueueSize = 2, 222 | /// Obtains the major version of the driver. 223 | VersionMajor = 3, 224 | /// Obtains the minor version of the driver. 225 | VersionMinor = 4, 226 | } 227 | 228 | impl TryFrom for WinDivertParam { 229 | type Error = WinDivertValueError; 230 | 231 | fn try_from(value: u32) -> Result { 232 | match value { 233 | 0 => Ok(WinDivertParam::QueueLength), 234 | 1 => Ok(WinDivertParam::QueueTime), 235 | 2 => Ok(WinDivertParam::QueueSize), 236 | 3 => Ok(WinDivertParam::VersionMajor), 237 | 4 => Ok(WinDivertParam::VersionMinor), 238 | _ => Err(WinDivertValueError::Parameter(value)), 239 | } 240 | } 241 | } 242 | 243 | impl From for u32 { 244 | fn from(value: WinDivertParam) -> Self { 245 | match value { 246 | WinDivertParam::QueueLength => 0, 247 | WinDivertParam::QueueTime => 1, 248 | WinDivertParam::QueueSize => 2, 249 | WinDivertParam::VersionMajor => 3, 250 | WinDivertParam::VersionMinor => 4, 251 | } 252 | } 253 | } 254 | 255 | /** 256 | Flag type required by [`WinDivertOpen()`](fn@super::WinDivertOpen). It follows a builder like style. 257 | 258 | Different flags affect how the opened handle behaves. The following flags are supported: 259 | * `sniff`: This flag opens the WinDivert handle in `packet sniffing` mode. In packet sniffing mode the original packet is not dropped-and-diverted (the default) but copied-and-diverted. This mode is useful for implementing packet sniffing tools similar to those applications that currently use Winpcap. 260 | * `drop`: This flag indicates that the user application does not intend to read matching packets with [`recv()`](fn@super::WinDivertRecv) (or any of it's variants), instead the packets should be silently dropped. This is useful for implementing simple packet filters using the WinDivert [filter language](https://reqrypt.org/windivert-doc.html#filter_language). 261 | * `recv_only`: This flags forces the handle into receive only mode which effectively disables [`send()`](fn@super::WinDivertSend) (and any of it's variants). This means that it is possible to block/capture packets or events but not inject them. 262 | * `send_only`: This flags forces the handle into send only mode which effectively disables [`recv()`](fn@super::WinDivertRecv) (and any of it's variants). This means that it is possible to inject packets or events, but not block/capture them. 263 | * `no_installs`: This flags causes [`WinDivertOpen`](fn@super::WinDivertOpen) to fail with ERROR_SERVICE_DOES_NOT_EXIST (1060) if the WinDivert driver is not already installed. This flag is useful for querying the WinDivert driver state using [`Reflect`](super::WinDivertLayer::Reflect) layer. 264 | * `fragments`: If set, the handle will capture inbound IP fragments, but not inbound reassembled IP packets. Otherwise, if not set (the default), the handle will capture inbound reassembled IP packets, but not inbound IP fragments. This flag only affects inbound packets at the [`Network`](super::WinDivertLayer::Network) layer, else the flag is ignored. 265 | Note that any combination of (`snif` | `drop`) or (`recv_only` | `send_only`) are considered invalid. 266 | 267 | Some layers have mandatory flags: 268 | * [`WinDivertLayer::Flow`](type@WinDivertLayer::Flow): (`sniff` | `recv_only`) 269 | * [`WinDivertLayer::Socket`](type@WinDivertLayer::Socket): `recv_only` 270 | * [`WinDivertLayer::Reflect`](type@WinDivertLayer::Reflect): (`sniff` | `recv_only`) 271 | */ 272 | #[derive(Debug, Default, Copy, Clone)] 273 | #[repr(transparent)] 274 | pub struct WinDivertFlags(u64); 275 | 276 | /// WinDivertFlags builder methods. 277 | impl WinDivertFlags { 278 | /// Creates a new flag field with all options unset. 279 | pub const fn new() -> Self { 280 | Self(0) 281 | } 282 | 283 | /// Sets `sniff` flag. 284 | pub const fn set_sniff(mut self) -> Self { 285 | self.0 |= 0x0001; 286 | self 287 | } 288 | 289 | /// Unsets `sniff` flag. 290 | pub const fn unset_sniff(mut self) -> Self { 291 | self.0 &= !0x001; 292 | self 293 | } 294 | 295 | /// Sets `sniff` flag to `value`. 296 | pub fn set_sniff_value(&mut self, value: bool) { 297 | self.0 = (self.0 & !0x0001) | (value as u64); 298 | } 299 | 300 | /// Sets `drop` flag. 301 | pub const fn set_drop(mut self) -> Self { 302 | self.0 |= 0x0002; 303 | self 304 | } 305 | 306 | /// Unsets `drop` flag. 307 | pub const fn unset_drop(mut self) -> Self { 308 | self.0 &= !0x0002; 309 | self 310 | } 311 | 312 | /// Sets `drop` flag to `value`. 313 | pub fn set_drop_value(&mut self, value: bool) { 314 | self.0 = (self.0 & !0x0002) | ((value as u64) << 1); 315 | } 316 | 317 | /// Sets `recv_only` flag 318 | pub const fn set_recv_only(mut self) -> Self { 319 | self.0 |= 0x0004; 320 | self 321 | } 322 | 323 | /// Unsets `recv_only` flag 324 | pub const fn unset_recv_only(mut self) -> Self { 325 | self.0 &= !0x0004; 326 | self 327 | } 328 | 329 | /// Sets `recv_only` flag to `value`. 330 | pub fn set_recv_only_value(&mut self, value: bool) { 331 | self.0 = (self.0 & !0x0004) | ((value as u64) << 2); 332 | } 333 | 334 | /// Sets `send_only` flag. 335 | pub const fn set_send_only(mut self) -> Self { 336 | self.0 |= 0x0008; 337 | self 338 | } 339 | 340 | /// Unsets `send_only` flag. 341 | pub const fn unset_send_only(mut self) -> Self { 342 | self.0 &= !0x0008; 343 | self 344 | } 345 | 346 | /// Sets `send_only` flag to `value`. 347 | pub fn set_send_only_value(&mut self, value: bool) { 348 | self.0 = (self.0 & !0x0008) | ((value as u64) << 3); 349 | } 350 | 351 | /// Sets `no_installs` flag. 352 | pub const fn set_no_installs(mut self) -> Self { 353 | self.0 |= 0x0010; 354 | self 355 | } 356 | 357 | /// Unsets `no_installs` flag. 358 | pub const fn unset_no_installs(mut self) -> Self { 359 | self.0 &= !0x0010; 360 | self 361 | } 362 | 363 | /// Sets `no_installs` flag to `value`. 364 | pub fn set_no_installs_value(&mut self, value: bool) { 365 | self.0 = (self.0 & !0x0010) | ((value as u64) << 4); 366 | } 367 | 368 | /// Sets `fragments` flag. 369 | pub const fn set_fragments(mut self) -> Self { 370 | self.0 |= 0x0020; 371 | self 372 | } 373 | 374 | /// Unsets `fragments` flag. 375 | pub const fn unset_fragments(mut self) -> Self { 376 | self.0 &= !0x0020; 377 | self 378 | } 379 | 380 | /// Sets `fragments` flag to `value`. 381 | pub fn set_fragments_value(&mut self, value: bool) { 382 | self.0 = (self.0 & !0x0020) | ((value as u64) << 5); 383 | } 384 | } 385 | 386 | impl From for u64 { 387 | fn from(flags: WinDivertFlags) -> Self { 388 | flags.0 389 | } 390 | } 391 | 392 | /** 393 | Wrapper helper struct around u64. 394 | 395 | The type uses transparent representation to enforce using the provided methods to set the values of the flags used by [`WinDivertHelperCalcChecksums()`](fn@super::WinDivertHelperCalcChecksums) 396 | 397 | The different flag values are: 398 | * `no_ip`: Do not calculate the IPv4 checksum. 399 | * `no_icmp`: Do not calculate the ICMP checksum. 400 | * `no_icmpv6`: Do not calculate the ICMPv6 checksum. 401 | * `no_tcp`: Do not calculate the TCP checksum. 402 | * `no_udp`: Do not calculate the UDP checksum. 403 | */ 404 | #[derive(Debug, Default, Copy, Clone)] 405 | #[repr(transparent)] 406 | pub struct ChecksumFlags(u64); 407 | 408 | impl ChecksumFlags { 409 | /// Creates a new flag field with default zero value. 410 | pub const fn new() -> Self { 411 | Self(0) 412 | } 413 | 414 | /// Sets `no_ip` flag 415 | pub const fn set_no_ip(mut self) -> Self { 416 | self.0 |= 0x0001; 417 | self 418 | } 419 | 420 | /// Unsets `no_ip` flag 421 | pub const fn unset_no_ip(mut self) -> Self { 422 | self.0 &= !0x0001; 423 | self 424 | } 425 | 426 | /// Sets `no_ip` flag to `value`. 427 | pub fn set_no_ip_value(&mut self, value: bool) { 428 | self.0 = (self.0 & !0x0001) | (value as u64); 429 | } 430 | 431 | /// Sets `no_icmp` flag 432 | pub const fn set_no_icmp(mut self) -> Self { 433 | self.0 |= 0x0002; 434 | self 435 | } 436 | 437 | /// Unsets `no_icmp` flag 438 | pub const fn unset_no_icmp(mut self) -> Self { 439 | self.0 &= !0x0002; 440 | self 441 | } 442 | 443 | /// Sets `no_icmp` flag to `value`. 444 | pub fn set_no_icmp_value(&mut self, value: bool) { 445 | self.0 = (self.0 & !0x0002) | ((value as u64) << 1); 446 | } 447 | 448 | /// Sets `no_icmpv6` flag 449 | pub const fn set_no_icmpv6(mut self) -> Self { 450 | self.0 |= 0x0004; 451 | self 452 | } 453 | 454 | /// Unsets `no_icmpv6` flag 455 | pub const fn unset_no_icmpv6(mut self) -> Self { 456 | self.0 &= !0x0004; 457 | self 458 | } 459 | 460 | /// Sets `no_icmpv6` flag to `value`. 461 | pub fn set_no_icmpv6_value(&mut self, value: bool) { 462 | self.0 = (self.0 & !0x0004) | ((value as u64) << 2); 463 | } 464 | 465 | /// Sets `no_tcp` flag 466 | pub const fn set_no_tcp(mut self) -> Self { 467 | self.0 |= 0x0008; 468 | self 469 | } 470 | 471 | /// Unsets `no_tcp` flag 472 | pub const fn unset_no_tcp(mut self) -> Self { 473 | self.0 &= !0x0008; 474 | self 475 | } 476 | 477 | /// Sets `no_tcp` flag to `value`. 478 | pub fn set_no_tcp_value(&mut self, value: bool) { 479 | self.0 = (self.0 & !0x0008) | ((value as u64) << 3); 480 | } 481 | 482 | /// Sets `no_udp` flag 483 | pub const fn set_no_udp(mut self) -> Self { 484 | self.0 |= 0x0010; 485 | self 486 | } 487 | 488 | /// Unsets `no_udp` flag 489 | pub const fn unset_no_udp(mut self) -> Self { 490 | self.0 &= !0x0010; 491 | self 492 | } 493 | 494 | /// Sets `no_udp` flag to `value`. 495 | pub fn set_no_udp_value(&mut self, value: bool) { 496 | self.0 = (self.0 & !0x0010) | ((value as u64) << 4); 497 | } 498 | } 499 | 500 | impl From for u64 { 501 | fn from(flags: ChecksumFlags) -> Self { 502 | flags.0 503 | } 504 | } 505 | --------------------------------------------------------------------------------