๐ก๏ธ windows-wfp: A Safe Rust Wrapper for the Windows Kernel Firewall
For the past few months, I’ve been working on a personal Rust project related to network security on Windows. An ambitious project whose full details I won’t reveal just yet โ let’s just say it requires interacting directly with the Windows kernel-level firewall. And when you dive into that world, you inevitably stumble upon the Windows Filtering Platform (WFP).
The problem? Manipulating WFP from Rust is quite the challenge. So I built a wrapper for my own needs and decided to share it as open-source on crates.io: windows-wfp.
๐ฏ What is the Windows Filtering Platform?
WFP (Windows Filtering Platform) is the kernel-level network filtering framework built into Windows since Vista/Server 2008. It’s the engine that powers Windows Firewall itself, as well as most network security solutions: antivirus, EDR, VPN…
In concrete terms, WFP allows you to:
- Block or allow network traffic based on fine-grained rules
- Filter by application: allow Firefox but block another app
- Filter by protocol, port, IP: with CIDR support for address ranges
- Monitor network events in real-time
- Operate at the kernel level: before traffic even reaches the application
It’s an extremely powerful API, used by professional security tools. But it has one major drawback: it’s designed for C/C++, and using it from Rust means juggling with low-level, unergonomic abstractions.
โ ๏ธ The Problem: Using WFP Without a Wrapper
When I started integrating WFP into my Rust project, I quickly faced three major obstacles:
1. Raw FFI Everywhere
FFI (Foreign Function Interface) is the mechanism that allows Rust to call Windows C APIs. The problem is that with raw FFI, you lose all the memory safety guarantees that make Rust powerful. You’re dealing with raw pointers, C structures, and end up writing unsafe code (where you tell the compiler: “trust me, I know what I’m doing” โ spoiler: you don’t always know ๐
).
2. Unsecured Windows Handles
A handle in Windows is an opaque identifier the system gives you when you open a resource (a WFP session, a file, a process…). The issue: you must remember to close each handle manually. Forget it โ resource leak. Use it after closing โ undefined behavior. The kind of silent bug that only manifests in production, 3 months later, at 2 AM.
3. The NT Kernel Path Trap
This is probably the most treacherous trap. WFP operates at the kernel level and uses NT kernel paths (\Device\HarddiskVolume3\Windows\System32\notepad.exe), not the usual DOS paths (C:\Windows\System32\notepad.exe).
The result? You add a filter to block notepad.exe using its classic path. The WFP API returns no error โ everything seems to work. But the filter never matches a single packet. Your rules exist, but they’re silent. ๐
I lost considerable time debugging this behavior before understanding the issue. This kind of frustration is precisely what motivated me to encapsulate all this complexity into a clean wrapper.
๐ windows-wfp: The Idiomatic Rust Approach
The windows-wfp crate encapsulates all this complexity behind a safe, ergonomic, and idiomatic Rust API.
Crate Architecture
| |
Design Principles
โ RAII for handles: Every WFP session, every provider, every filter is wrapped in a Rust type that automatically closes the handle when the object goes out of scope. Impossible to forget cleanup.
โ Builder pattern for filters: Instead of filling C structures with pointers, you build rules with a fluent, typed API.
โ Automatic path conversion: The crate transparently converts DOS paths to NT kernel paths. No more silently broken filters.
โ
100% safe API: The unsafe code (necessary to talk to Windows APIs) is isolated and encapsulated inside the crate. Users never need to write unsafe.
โ Network monitoring: Subscribe to real-time network events via a Rust callback.
Example: Blocking an Application
| |
The ? at the end of each call is Rust’s error propagation operator: if the call fails, the error is cleanly returned to the caller. No try/catch, no exceptions โ everything goes through the type system.
Example: Real-Time Network Monitoring
| |
๐ง Filtering Capabilities
The crate supports a wide range of filtering conditions that can be combined:
| Condition | Description | Example |
|---|---|---|
| Application | Filter by executable path | notepad.exe, chrome.exe |
| Protocol | TCP, UDP, ICMP, ICMPv6 | Protocol::Tcp |
| Remote port | Target server port | Port 443 (HTTPS) |
| Local port | Local application port | Port 8080 |
| IP address | IPv4/IPv6 with CIDR | 192.168.1.0/24 |
| Windows service | Filter by service name | svchost, dns |
| AppContainer | SID for UWP/Microsoft Store apps | Edge, packaged apps |
These conditions can be combined to create very precise rules. For example: block chrome.exe only on port 80 (HTTP) while allowing port 443 (HTTPS).
๐ก What I Learned Building This Crate
Windows FFI in Rust is a World of Its Own
Microsoft’s windows crate has greatly simplified access to Windows APIs from Rust. But WFP remains a complex kernel API with nested structures, C unions, and sometimes under-documented behaviors. Each WFP filter involves building FWPM_FILTER0, FWPM_FILTER_CONDITION0, and similar structures with manual memory allocation and careful lifetime management.
Path Conversion is Critical
The FilterAPI.dll!FwpmGetAppIdFromFileName function handles the DOS โ NT kernel conversion, but it has its subtleties. Network paths (UNC), symbolic links, and environment variables are all edge cases to handle. It’s the kind of invisible detail that makes the difference between a working filter and a ghost filter.
Network Monitoring Reveals a Lot
While developing the monitoring feature, I was surprised by the volume and diversity of network traffic on a standard Windows workstation. Dozens of services communicate constantly โ a reminder that the network attack surface is much broader than one might imagine.
๐ฎ What’s Next?
windows-wfp is the first building block of a larger project I’m currently working on. A project related to network security on Windows, still in Rust. I won’t say more for now… but stay tuned, it promises to be interesting. ๐
In the meantime, the crate is available and functional. Here’s the roadmap for windows-wfp itself:
Upcoming Evolutions
- ๐ Callout support: Real-time packet interception and modification
- ๐ Filtering statistics: Blocked/allowed packet counters per filter
- ๐งช Integration tests: Automated test suite with real filter creation/deletion
- ๐ Enhanced documentation: Advanced usage guides and concrete use cases
๐ Resources and Links
The Crate
Technical References
LinkedIn Post
- ๐ฃ LinkedIn Announcement: The post accompanying this release
๐ Conclusion
Building windows-wfp allowed me to dive into the internals of Windows networking at the kernel level โ a fascinating but demanding domain. The wrapper transforms a complex and trap-laden C API into something safe, ergonomic, and idiomatic in Rust.
If you work in network security on Windows, or if you’re simply curious about how to properly wrap a kernel API in Rust, feel free to explore the code, open issues, or propose contributions.
Questions? Feedback? I welcome all feedback, whether about the API, documentation, or use cases you’d like to see supported.
๐ง Email: lostyzen@gmail.com
๐ PGP Key: Download from keys.openpgp.org
๐ Fingerprint: 0205 9854 864D EE62 C2BB 455F D825 3521 EDD1 630B
