Windows Packet Filter
High-performance raw Ethernet frame filtering, packet inspection, and packet injection for Windows. Filter and manipulate network traffic in user mode without writing kernel drivers.
Complete Control Over Raw Ethernet Traffic
Windows Packet Filter intercepts network traffic directly between the protocol drivers (TCP/IP) and the network interface driver, granting bidirectional packet inspection and manipulation.
Capture
Intercept Layer 2 raw Ethernet frames before protocol stack processing.
Inspect
Parse full Ethernet, IPv4/IPv6, TCP/UDP headers and payloads.
Filter / Modify
Drop, pass, or rewrite intercepted frames in user-mode memory.
Inject
Re-inject packets into the network stack or forward to physical adapters.
Native APIs for C++, C# (.NET), Rust, and Go
Intercept packets from a TCP/IP-bound adapter and reinject them unchanged in both directions using tunnel mode. The same packet-processing model is available through the C++, .NET, Rust, and Go APIs.
#include <iostream>
#include <memory>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
#include <tchar.h>
#include "common.h"
#include "ndisapi.h"
// Use a dedicated test adapter: tunnel mode temporarily diverts its traffic.
// Stops after 100 packet notifications or 5 seconds without a notification.
struct SessionCleanup {
CNdisApi& api;
HANDLE adapter;
HANDLE event;
bool event_registered = false;
bool tunnel_enabled = false;
bool finish() {
bool ok = true;
if (tunnel_enabled) {
ADAPTER_MODE mode{};
mode.hAdapterHandle = adapter;
if (!api.SetAdapterMode(&mode)) {
std::cerr << "Could not restore adapter mode.\n";
ok = false;
} else {
tunnel_enabled = false;
}
}
if (event_registered) {
if (!api.SetPacketEvent(adapter, nullptr)) {
std::cerr << "Could not unregister packet event.\n";
ok = false;
} else {
event_registered = false;
}
}
if (event) {
if (!CloseHandle(event)) {
std::cerr << "Could not close packet event: " << GetLastError() << '\n';
ok = false;
} else {
event = nullptr;
}
}
return ok;
}
~SessionCleanup() { finish(); }
};
int main()
{
auto api = std::make_unique<CNdisApi>();
if (!api->IsDriverLoaded()) {
std::cerr << "WinpkFilter driver is not loaded.\n";
return 1;
}
TCP_AdapterList adapters{};
if (!api->GetTcpipBoundAdaptersInfo(&adapters) || adapters.m_nAdapterCount == 0) {
std::cerr << "No TCP/IP bound adapters found.\n";
return 1;
}
HANDLE adapter = adapters.m_nAdapterHandle[0];
ADAPTER_MODE mode{};
mode.hAdapterHandle = adapter;
if (!api->GetAdapterMode(&mode)) {
std::cerr << "Could not query adapter mode.\n";
return 1;
}
if (mode.dwFlags != 0) {
std::cerr << "Adapter filtering is already active; select an idle dedicated test adapter.\n";
return 1;
}
HANDLE event = CreateEvent(nullptr, TRUE, FALSE, nullptr);
if (!event) {
std::cerr << "Could not create packet event: " << GetLastError() << '\n';
return 1;
}
SessionCleanup cleanup{*api, adapter, event};
if (!api->SetPacketEvent(adapter, event)) {
std::cerr << "Could not register packet event.\n";
return 1;
}
cleanup.event_registered = true;
mode.dwFlags = MSTCP_FLAG_SENT_TUNNEL | MSTCP_FLAG_RECV_TUNNEL;
if (!api->SetAdapterMode(&mode)) {
std::cerr << "Could not enter tunnel mode.\n";
return 1;
}
cleanup.tunnel_enabled = true;
INTERMEDIATE_BUFFER packet{};
ETH_REQUEST request{};
request.hAdapterHandle = adapter;
request.EthPacket.Buffer = &packet;
// Process a bounded number of notification cycles for this minimal example
constexpr int DEMO_WAKEUPS = 100;
constexpr DWORD IDLE_TIMEOUT_MS = 5000;
for (int i = 0; i < DEMO_WAKEUPS; ++i) {
DWORD status = WaitForSingleObject(event, IDLE_TIMEOUT_MS);
if (status == WAIT_TIMEOUT) {
std::cout << "No packet notification for 5 seconds; stopping. Generate traffic on the selected test adapter to capture packets.\n";
break;
}
if (status != WAIT_OBJECT_0) {
std::cerr << "Packet-event wait failed: " << GetLastError() << '\n';
return 1;
}
if (!ResetEvent(event)) {
std::cerr << "Could not reset packet event: " << GetLastError() << '\n';
return 1;
}
// FALSE ends this drain of the adapter's currently queued packets.
while (api->ReadPacket(&request)) {
BOOL sent = packet.m_dwDeviceFlags == PACKET_FLAG_ON_SEND
? api->SendPacketToAdapter(&request)
: api->SendPacketToMstcp(&request);
if (!sent) {
std::cerr << "Could not reinject packet.\n";
return 1;
}
}
}
return cleanup.finish() ? 0 : 1;
}
using System;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using NdisApiDotNet;
using NativeApi = NdisApiDotNet.Native.NdisApi;
// .NET 8, C# 12, AllowUnsafeBlocks=true; deploy a matching Unicode ndisapi.dll.
// Run on a test adapter: tunnel mode temporarily diverts its traffic.
using var filter = NdisApi.Open();
if (!filter.IsDriverLoaded())
throw new InvalidOperationException("WinpkFilter driver is not loaded.");
var adapter = filter.GetNetworkAdapters().FirstOrDefault(a => a.IsValid)
?? throw new InvalidOperationException("No valid network adapter found.");
if (!filter.GetAdapterMode(adapter, out var previousMode))
throw new InvalidOperationException("Could not query adapter mode.");
if (previousMode.dwFlags != NativeApi.MSTCP_FLAGS.MSTCP_FLAG_NONE)
throw new InvalidOperationException("Choose a test adapter with no existing filtering mode.");
Console.WriteLine($"Adapter: {adapter.FriendlyName}");
using var waitEvent = new AutoResetEvent(false);
unsafe
{
// Allocate before changing driver state.
NativeApi.ETH_REQUEST* request = filter.CreateEthRequest();
request->hAdapterHandle = adapter.Handle;
bool eventSet = false, modeSet = false;
int sent = 0, received = 0;
Exception primaryFailure = null;
try
{
eventSet = filter.SetPacketEvent(adapter, waitEvent);
if (!eventSet)
throw new InvalidOperationException("Could not register packet event.");
modeSet = filter.SetAdapterMode(adapter,
NativeApi.MSTCP_FLAGS.MSTCP_FLAG_SENT_TUNNEL |
NativeApi.MSTCP_FLAGS.MSTCP_FLAG_RECV_TUNNEL);
if (!modeSet)
throw new InvalidOperationException("Could not enable tunnel mode.");
var timer = Stopwatch.StartNew();
// Stop after 100 notifications, 5 idle seconds, or 10 seconds in total.
// Process a bounded number of notification cycles for this minimal example
const int DemoWakeups = 100;
for (int i = 0; i < DemoWakeups; i++)
{
int remaining = (int)Math.Min(5000, 10000 - timer.ElapsedMilliseconds);
if (remaining <= 0 || !waitEvent.WaitOne(remaining))
break;
// Check the deadline while draining a busy queue, too.
while (timer.ElapsedMilliseconds < 10000 && filter.ReadPacket(ref *request))
{
var buffer = (NativeApi.INTERMEDIATE_BUFFER*)request->EthPacket.Buffer;
bool onSend = (buffer->m_dwDeviceFlags & NativeApi.PACKET_FLAG.PACKET_FLAG_ON_SEND) != 0;
bool forwarded = onSend
? filter.SendPacketToAdapter(ref *request)
: filter.SendPacketToMstcp(ref *request);
if (!forwarded)
throw new InvalidOperationException("Could not reinject packet.");
if (onSend) sent++; else received++;
}
}
Console.WriteLine($"Forwarded: sent={sent}, received={received}");
}
catch (Exception ex)
{
primaryFailure = ex;
throw;
}
finally
{
// Restore mode before removing the notification event.
bool modeReset = !modeSet || filter.ResetAdapterMode(adapter);
bool eventReset = !eventSet || filter.ResetPacketEvent(adapter);
filter.DisposeObject(request);
if (!modeReset)
Console.Error.WriteLine("Could not reset adapter mode.");
if (!eventReset)
Console.Error.WriteLine("Could not unregister packet event.");
if ((!modeReset || !eventReset) && primaryFailure == null)
throw new InvalidOperationException("Packet capture cleanup failed.");
}
}
use ndisapi::{
DirectionFlags, EthRequest, EthRequestMut, FilterFlags, IntermediateBuffer, Ndisapi,
};
use windows::Win32::Foundation::{
CloseHandle, HANDLE, WAIT_FAILED, WAIT_OBJECT_0, WAIT_TIMEOUT,
};
use windows::Win32::System::Threading::{CreateEventW, ResetEvent, WaitForSingleObject};
// Own the notification event and restore the adapter on every return path.
struct PacketSession<'a> {
driver: &'a Ndisapi,
adapter: HANDLE,
event: HANDLE,
attached: bool,
}
impl<'a> PacketSession<'a> {
fn new(driver: &'a Ndisapi, adapter: HANDLE) -> windows::core::Result<Self> {
let event = unsafe { CreateEventW(None, true, false, None)? };
let mut session = Self { driver, adapter, event, attached: false };
driver.set_packet_event(adapter, event)?;
session.attached = true;
Ok(session)
}
fn stop(&mut self) -> windows::core::Result<()> {
if !self.attached {
return Ok(());
}
let mode = self.driver.set_adapter_mode(self.adapter, FilterFlags::default());
let event = self.driver.set_packet_event(self.adapter, HANDLE::default());
if mode.is_ok() && event.is_ok() {
self.attached = false;
}
mode.and(event)
}
}
impl Drop for PacketSession<'_> {
fn drop(&mut self) {
// Explicit stop below reports errors; Drop retries cleanup after errors.
let _ = self.stop();
let _ = unsafe { CloseHandle(self.event) };
}
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let driver = Ndisapi::new("NDISRD")
.map_err(|e| format!("Failed to connect to driver: {e:?}"))?;
let adapters = driver.get_tcpip_bound_adapters_info()?;
let adapter = adapters.first().ok_or("No TCP/IP bound adapters found")?;
let handle = adapter.get_handle();
if !driver.get_adapter_mode(handle)?.is_empty() {
return Err("Adapter is already being filtered".into());
}
let mut session = PacketSession::new(&driver, handle)?;
driver.set_adapter_mode(
handle,
FilterFlags::MSTCP_FLAG_SENT_TUNNEL | FilterFlags::MSTCP_FLAG_RECV_TUNNEL,
)?;
println!("Passing packets on the first adapter; stopping after 5 seconds idle or 100 wakeups.");
let mut packet = IntermediateBuffer::default();
const DEMO_WAKEUPS: usize = 100;
const IDLE_TIMEOUT_MS: u32 = 5_000;
for _ in 0..DEMO_WAKEUPS {
match unsafe { WaitForSingleObject(session.event, IDLE_TIMEOUT_MS) } {
WAIT_OBJECT_0 => (),
WAIT_TIMEOUT => {
println!("No packets for 5 seconds; stopping.");
break;
}
WAIT_FAILED => return Err(std::io::Error::last_os_error().into()),
_ => return Err("Unexpected packet event wait result".into()),
}
// Reset before draining: arrivals after an empty read keep the event set.
unsafe { ResetEvent(session.event)?; }
loop {
let mut read_request = EthRequestMut::new(handle);
read_request.set_packet(&mut packet);
if driver.read_packet(&mut read_request).is_err() {
break;
}
let mut write_request = EthRequest::new(handle);
write_request.set_packet(&packet);
if packet.get_device_flags().contains(DirectionFlags::PACKET_FLAG_ON_SEND) {
driver.send_packet_to_adapter(&write_request)?;
} else {
driver.send_packet_to_mstcp(&write_request)?;
}
}
}
session.stop()?;
println!("Filtering disabled; packet event detached.");
Ok(())
}
package main
// Go 1.20+, native 64-bit Windows (amd64 or arm64).
// Select a test adapter: tunnel mode temporarily diverts its traffic.
// This demo waits for 100 packet notifications and can block on an idle adapter.
import (
"errors"
"fmt"
"log"
"unsafe"
"github.com/wiresock/ndisapi-go"
"golang.org/x/sys/windows"
)
func main() {
if err := run(); err != nil {
log.Fatal(err)
}
}
func run() (result error) {
// These bindings use 64-bit driver handles; reject incompatible layouts.
if unsafe.Sizeof(uintptr(0)) != 8 {
return fmt.Errorf("this example requires 64-bit Windows (amd64 or arm64)")
}
// Open WinpkFilter driver instance
api, err := ndisapi.NewNdisApi()
if err != nil {
return fmt.Errorf("open NDIS API: %w", err)
}
defer api.Close()
if !api.IsDriverLoaded() {
return fmt.Errorf("WinpkFilter driver is not loaded")
}
// Query TCP/IP bound network adapters
adapters, err := api.GetTcpipBoundAdaptersInfo()
if err != nil {
return fmt.Errorf("enumerate adapters: %w", err)
}
if adapters.AdapterCount == 0 {
return fmt.Errorf("no TCP/IP bound adapters found")
}
adapter := adapters.AdapterHandle[0]
event, err := windows.CreateEvent(nil, 1, 0, nil)
if err != nil {
return fmt.Errorf("create packet event: %w", err)
}
defer func() { result = errors.Join(result, windows.CloseHandle(event)) }()
if err := api.SetPacketEvent(adapter, event); err != nil {
return fmt.Errorf("set packet event: %w", err)
}
defer func() { result = errors.Join(result, api.SetPacketEvent(adapter, 0)) }()
// Enter bidirectional tunnel mode
mode := &ndisapi.AdapterMode{
AdapterHandle: adapter,
Flags: ndisapi.MSTCP_FLAG_SENT_TUNNEL | ndisapi.MSTCP_FLAG_RECV_TUNNEL,
}
if err := api.SetAdapterMode(mode); err != nil {
return fmt.Errorf("set adapter mode: %w", err)
}
defer func() {
mode.Flags = 0
result = errors.Join(result, api.SetAdapterMode(mode))
}()
var buffer ndisapi.IntermediateBuffer
request := &ndisapi.EtherRequest{
AdapterHandle: adapter,
EthernetPacket: ndisapi.EthernetPacket{
Buffer: &buffer,
},
}
// Process a bounded number of notification cycles for this minimal example
const demoWakeups = 100
for i := 0; i < demoWakeups; i++ {
status, err := windows.WaitForSingleObject(event, windows.INFINITE)
if err != nil {
return fmt.Errorf("wait for packet event: %w", err)
}
if status != windows.WAIT_OBJECT_0 {
return fmt.Errorf("unexpected wait result: %d", status)
}
if err := windows.ResetEvent(event); err != nil {
return fmt.Errorf("reset packet event: %w", err)
}
// Use the IOCTL result directly: nil means a packet was read.
for {
requestSize := uint32(unsafe.Sizeof(*request))
if err := api.DeviceIoControl(
ndisapi.IOCTL_NDISRD_READ_PACKET,
unsafe.Pointer(request), requestSize,
unsafe.Pointer(request), requestSize,
nil, nil,
); err != nil {
break
}
if buffer.DeviceFlags == ndisapi.PACKET_FLAG_ON_SEND {
// Outgoing from TCP/IP: reinject downward to network adapter
err = api.SendPacketToAdapter(request)
} else {
// Incoming from network: reinject upward to TCP/IP stack
err = api.SendPacketToMstcp(request)
}
if err != nil {
return fmt.Errorf("reinject packet: %w", err)
}
}
}
// Deferred cleanup restores normal mode, unregisters the event, and closes handles.
return nil
}
Driver Position in the Windows Network Stack
WinpkFilter attaches as an NDIS 6.x Lightweight Filter (LWF) directly below all Windows protocol drivers (TCP/IP) and above the physical or virtual network interface drivers.
Standard IOCTL queues provide synchronous packet reading and reinjection for supported network adapters.
ndisapi.dll
→
IOCTL Queues
→
ndisrd.sys
High-throughput path utilizing shared memory (FAST_IO_SECTION) between user space and kernel driver for low-latency packet processing.
ndisapi.dll
→
FAST_IO_SECTION
→
ndisrd.sys
Full Layer 2 Inspection
Because the driver sits below tcpip.sys, packets are captured with complete 802.3 Ethernet headers intact. You can filter non-IP protocols (ARP, PPPoE, custom ethertypes) that higher-layer platforms cannot see.
Bidirectional Injection
Inject generated or modified frames directly up towards the Windows protocol stack (simulating inbound wire traffic) or downstream towards the network adapter (transmitting to the physical wire).
Standard & Optional Fast I/O
Provides reliable standard IOCTL queues (ReadPackets / SendPackets) alongside an optional shared-memory mechanism (FAST_IO_SECTION) for low-latency, high-throughput packet processing.
Why an NDIS Lightweight Filter?
Selecting the right Windows network packet interception architecture depends on your required network layer, development model, and deployment constraints.
vs. Windows Filtering Platform (WFP)
While modern WFP provides Layer 2 MAC-layer filtering in addition to transport and socket layers, developing custom kernel callout drivers requires specialized Windows Driver Kit (WDK) development, complex kernel-mode debugging, and ongoing driver maintenance.
WinpkFilter provides a mature, pre-compiled NDIS 6 LWF driver. Applications can intercept, inspect, modify, and reinject network traffic through a straightforward user-mode API (C++, C#, Rust, Go), while Windows Packet Filter handles the low-level Windows networking integration.
vs. WinPcap & Npcap
WinPcap and Npcap are primarily designed for packet capture (promiscuous mode sniffing) and raw packet injection. They do not provide transparent, inline bidirectional packet modification or blocking for host network traffic.
WinpkFilter operates directly in the data path between protocol drivers and physical adapters, granting authoritative control to allow, drop, modify, or redirect every frame in real time.
Modern NDIS LWF vs. Legacy NDIS Techniques
Earlier Windows releases required packet-filtering solutions to use techniques such as NDIS hooking or NDIS Intermediate (IM) drivers. NDIS hooking intercepted internal driver dispatch tables, making it undocumented, brittle, and prone to instability across service packs. NDIS Intermediate drivers were complex to install and manage, introduced significant packet processing overhead, and could cause binding conflicts with other network components.
Modern Windows supports the NDIS 6 Lightweight Filter (LWF) architecture for filtering in the network stack. WinpkFilter provides an NDIS 6 LWF implementation alongside its historical driver models; choose the appropriate package for your Windows version and architecture.
Engineered for Demanding Systems Software
Battle-tested since 2002 across enterprise firewalls, secure VPN gateways, industrial protocol analyzers, and commercial cybersecurity products.
Shared-Memory Fast I/O & Low Latency
Shared-memory packet sections between ndisrd.sys and user space reduce per-packet read IOCTL overhead. Throughput and CPU use depend on the application, packet sizes, hardware, and filtering configuration.
Bidirectional Packet Injection & Redirection
Transmit custom or modified packets in either direction: outbound to physical Ethernet/Wi-Fi media or inbound directly into the Windows TCP/IP stack. Transparently divert connections to local proxy sockets or encrypted tunnels.
System-Wide MTU Decrement & Jumbo Frames
A configurable system-wide MTU decrement helps account for tunnel encapsulation overhead. Jumbo-frame support is available in custom driver builds and requires matching user-mode packet-buffer capacity.
In-Kernel Rule Filtering & Buffer Pool
Programmatic rule engine inside ndisrd.sys allows developers to set pass, drop, or redirect rules directly in kernel space. Configurable intermediate buffer pool size optimizes memory allocation for bursty traffic.
Operating System & Hardware Support
WinpkFilter maintains a 20+ year lineage supporting modern enterprise Windows deployments while preserving legacy driver architectures.
Current Release (WinpkFilter 3.x)
NDIS 6.x LWFPre-compiled driver packages for supported Windows releases and CPU architectures:
| Platform Installer | Supported Windows Versions | Architecture |
|---|---|---|
| ARM64 Installer | Windows 11, Windows 10 | ARM64 |
| x64 Installer | Windows 11, 10, 8.1, 8, 7, Vista* | x64 (64-bit) |
| x86 Installer | Windows 10, 8.1, 8, 7, Vista* | x86 (32-bit) |
Compatible with 64-bit Windows Server editions sharing the equivalent client kernel / NDIS version.
* Legacy Windows versions may require signing updates or an appropriate historical driver package. Verify the signing requirements and driver loading on your exact OS version.
Legacy Windows Driver Line
NDIS 3 – 5Dedicated legacy driver builds maintained for older operating systems and industrial environments:
| Operating System | Driver Model | Architectures |
|---|---|---|
| Windows Server 2003 / Windows XP | NDIS 5.1 Intermediate (IM) Filter | x86, x64 |
| Windows 2000 / Windows NT 4.0 | NDIS 4 Hooking Filter | x86 |
| Windows 95 / 98 / ME | NDIS 3.1 Virtual Device Driver (VxD) | x86 |
Archived driver packages for legacy system maintenance and long-term embedded deployment.
Supported Network Interfaces & Connection Media
Applicability & Use Cases
Developers use Windows Packet Filter across a wide spectrum of network engineering, diagnostic, and security applications.
Firewalls & Packet Filtering
- User-mode desktop firewalls without writing kernel driver code
- Custom in-kernel filtering routines using the Source Code license
- Application traffic isolation, domain blocking, and parental filters
- Network protocol validation and malformed packet discarding
VPNs & Encrypted Tunnels
- Custom WireGuard, IPsec, and SSL VPN client integration
- Network packet encapsulation and tunneling (SSL, SSH, HTTP)
- System-wide MTU decrementing to prevent tunnel packet fragmentation
- Selective routing of application traffic through encrypted tunnels
Transparent Proxies & Redirection
- Transparent SOCKS5 proxification of arbitrary Windows applications
- Layer 2/3 packet redirection to local analysis or proxy sockets
- SSL/TLS Server Name Indication (SNI) inspection and routing
- Local DNS interception and DNS query redirection
Traffic Shaping & Analysis
- Bandwidth metering, traffic shaping, and token bucket rate limiters
- High-speed packet capture and PCAP file logging
- Transparent software bridging between wired Ethernet and Wi-Fi
- Industrial & SCADA raw Ethernet frame inspection
Real-World Software & Developer Samples
WinpkFilter powers enterprise networking software and provides maintained language bindings and representative sample applications.
WireSock Secure Connect
High-performance WireGuard client for Windows. Uses Windows Packet Filter in both transparent and virtual adapter modes for application traffic routing and filtering. Transparent mode does not require a virtual network adapter.
Learn about WireSock Secure Connect →ProxiFyre SOCKS5 Client
Advanced SOCKS5 proxifier for Windows built on WinpkFilter. Transparently routes application TCP and UDP traffic through proxy instances without modifying client software.
Explore ProxiFyre →Representative Open-Source Samples
View all 14+ samples on GitHub →| Sample Application | Language | Functionality Description | Source |
|---|---|---|---|
| Capture Packet Filter | C++ | High-speed packet sniffer with pcap storage using Shared-Memory Fast I/O. | GitHub |
| DNS Proxy Server | C++ | Transparently redirects DNS UDP traffic through a local proxy socket. | GitHub |
| Static Packet Filter | C++ | Demonstrates in-kernel static packet filtering rules (pass, drop, or redirect to user space) using static filter tables. | GitHub |
| SNI Inspector | C++ | Extracts TLS Server Name Indication (SNI) and HTTP Host headers in real time using Fast I/O. | GitHub |
| ListAdapters | C++ | Enumerates TCP/IP bound network interfaces, MAC addresses, and adapter MTU. | GitHub |
Looking for Substantial Engineering Applications?
Explore dedicated architectural guides and source code for Internet Gateway (MFC NAT), WAN Emulator (latency injection), and Ethernet Bridge.
Licensing Options
Windows Packet Filter is free for personal or educational use, with transparent commercial licensing for software publishers.
Personal / Educational
Free for personal use, educational research, and non-profit organizations.
- ✓ Complete SDK & User-Mode APIs
- ✓ Official signed driver installer
- ✓ Access to all sample applications
- ✓ Community Forum Support
- ✕ Commercial redistribution
- ✕ Kernel driver source code
Binary License
For software publishers redistributing Windows Packet Filter binaries with one product.
- ✓ Royalty-free binary redistribution with one product
- ✓ Pre-compiled signed drivers (
ndisrd.sys) - ✓ C++, C# (.NET), Rust, and Go client libraries
- ✓ 1 Year of free updates & technical support
- ✓ 1 custom driver build included
- ✕ Kernel driver source code
Source Code License
Complete driver and user-mode library source code for custom kernel development.
- ✓ Full C/C++ driver source code (
ndisrd.sys) - ✓ Full user-mode DLL source code (
ndisapi.dll) - ✓ Custom in-kernel filtering routines
- ✓ Independent compilation with the WDK
- ✓ 1 custom driver build included (built to agreed configuration)
- ✓ 1 Year of free updates & developer support
- ✓ Royalty-free redistribution
Technical Support & Discussion
Have questions about NDIS 6 LWF behavior, packet injection edge cases, or multi-adapter configurations? Browse the support forum or ask directly.