windows-filter-windivert/README.md

12 KiB

Windows DNS Packet Filter

A high-performance personal DNS packet filtering application for Windows using WinDivert. Filter DNS requests in real-time based on customizable rules with support for exact matches and wildcard patterns.

Features

  • Real-time DNS Filtering: Intercepts and filters DNS queries (UDP/TCP port 53)
  • Flexible Rule System: Supports both exact domain matches and wildcard patterns
  • JSON Configuration: Easy-to-edit JSON-based rule configuration
  • Live Reload: Automatically reloads rules when configuration file changes (no restart needed)
  • Comprehensive Logging: Detailed logging of all DNS queries with timestamps and source IPs
  • Thread-Safe: Concurrent access to rules with efficient locking mechanisms
  • High Performance: Optimized for minimal latency impact on DNS queries

System Requirements

  • Operating System: Windows 7 or later (64-bit)
  • Privileges: Administrator rights (required for WinDivert driver)
  • Dependencies:
    • WinDivert 2.2 library
    • Visual C++ Redistributable (2015-2022)

Project Structure

windows-filter/
├── CMakeLists.txt              # Build configuration
├── README.md                    # This file
├── config/
│   └── rules.json              # DNS filtering rules
├── include/                     # Header files
│   ├── common.h
│   ├── dns_parser.h
│   ├── rule_engine.h
│   ├── logger.h
│   ├── config_manager.h
│   └── packet_filter.h
├── src/                         # Source files
│   ├── main.cpp
│   ├── dns_parser.cpp
│   ├── rule_engine.cpp
│   ├── logger.cpp
│   ├── config_manager.cpp
│   └── packet_filter.cpp
└── external/                    # Third-party libraries
    ├── WinDivert/              # WinDivert library
    └── json/                    # nlohmann/json

Installation

Step 1: Setup WinDivert

Since WinDivert is a Windows-only library, you need to download it on a Windows machine:

  1. Download WinDivert 2.2 from: https://github.com/basil00/WinDivert/releases/download/v2.2.2/WinDivert-2.2.2-A.zip

  2. Extract the ZIP file

  3. Copy the following files to the project:

    From WinDivert-2.2.2-A/include/:
    - Copy windivert.h to: external/WinDivert/include/windivert.h
    
    From WinDivert-2.2.2-A/x64/:
    - Copy WinDivert.dll to: external/WinDivert/lib/WinDivert.dll
    - Copy WinDivert64.sys to: external/WinDivert/lib/WinDivert64.sys
    - Copy WinDivert.lib to: external/WinDivert/lib/WinDivert.lib
    

Step 2: Build the Project

# Create build directory
mkdir build
cd build

# Configure
cmake ..

# Build
cmake --build . --config Release

Using Visual Studio

# Generate Visual Studio project files
mkdir build
cd build
cmake .. -G "Visual Studio 17 2022"

# Open the generated .sln file in Visual Studio
# Build -> Build Solution (or press F7)

Step 3: Output Files

After building, you'll find these files in build/Release/:

  • dns_filter.exe - Main application
  • WinDivert.dll - WinDivert library
  • WinDivert64.sys - WinDivert driver
  • config/rules.json - Configuration file

Usage

Running the Application

IMPORTANT: This application requires Administrator privileges.

# Run as Administrator
cd build/Release
dns_filter.exe

To run as Administrator:

  1. Right-click on Command Prompt
  2. Select "Run as Administrator"
  3. Navigate to the application directory
  4. Run dns_filter.exe

Command Line Options

# Use default configuration (config/rules.json)
dns_filter.exe

# Use custom configuration file
dns_filter.exe path/to/custom/rules.json

Stopping the Application

Press Ctrl+C to gracefully stop the application. Statistics will be displayed upon exit.

Configuration

Configuration File Format

The configuration file (config/rules.json) uses JSON format:

{
  "version": "1.0",
  "logging": {
    "enabled": true,
    "file": "dns_filter.log",
    "level": "info",
    "max_size_mb": 100
  },
  "rules": [
    {
      "domain": "example.com",
      "action": "block",
      "comment": "Optional comment"
    }
  ]
}

Rule Configuration

Each rule has the following fields:

  • domain (required): The domain name to match
  • action (required): Either "block" or "allow"
  • comment (optional): Description of the rule

Exact Match Rules

Block or allow specific domains:

{
  "domain": "malicious-site.com",
  "action": "block",
  "comment": "Known malicious domain"
}

Wildcard Rules

Use * to match multiple domains:

{
  "domain": "*.ads.example.com",
  "action": "block",
  "comment": "Block all ad subdomains"
}

Wildcard patterns supported:

  • *.example.com - Matches all subdomains of example.com
  • *.ads.* - Matches domains containing "ads" subdomain
  • example.* - Matches all TLDs for example

Example Configuration

{
  "version": "1.0",
  "logging": {
    "enabled": true,
    "file": "dns_filter.log",
    "level": "info",
    "max_size_mb": 100
  },
  "rules": [
    {
      "domain": "ads.example.com",
      "action": "block",
      "comment": "Block ads"
    },
    {
      "domain": "*.doubleclick.net",
      "action": "block",
      "comment": "Block DoubleClick ads"
    },
    {
      "domain": "*.facebook.com",
      "action": "block",
      "comment": "Block all Facebook domains"
    },
    {
      "domain": "trusted-site.com",
      "action": "allow",
      "comment": "Explicitly allowed"
    }
  ]
}

Live Configuration Reload

The application automatically detects changes to the configuration file and reloads rules without requiring a restart. Simply edit config/rules.json and save it - the changes will take effect within 1-2 seconds.

Logging

Log File

All DNS queries and filtering actions are logged to dns_filter.log.

Log Format

[2026-01-22 15:30:45.123] [INFO] DNS Query: example.com from 192.168.1.100 -> ALLOWED
[2026-01-22 15:30:46.234] [WARN] DNS Query: malicious.com from 192.168.1.105 -> BLOCKED

Log Rotation

Logs are automatically rotated when they reach the configured size (default: 100MB). Old logs are renamed to dns_filter.log.1.

Testing

Basic Functionality Test

  1. Start the filter:

    dns_filter.exe
    
  2. Test blocking:

    • Add a domain to block in config/rules.json:
      {"domain": "test.example.com", "action": "block"}
      
    • Open another terminal and run:
      nslookup test.example.com
      
    • The query should timeout (blocked)
  3. Check logs:

    type dns_filter.log
    
    • Look for entries showing the blocked query

Test Live Reload

  1. Start the filter
  2. Edit config/rules.json to add a new blocked domain
  3. Save the file
  4. Check the console output - you should see "Configuration reloaded"
  5. Test the newly blocked domain with nslookup

Test Wildcard Patterns

  1. Add a wildcard rule:

    {"domain": "*.ads.example.com", "action": "block"}
    
  2. Test various subdomains:

    nslookup test.ads.example.com
    nslookup another.ads.example.com
    
  3. All should be blocked

How It Works

Architecture

  1. WinDivert Integration: Intercepts all DNS traffic (port 53 UDP/TCP) at the network layer
  2. DNS Parser: Extracts domain names from binary DNS packets
  3. Rule Engine: Matches domains against configured rules (exact + wildcard)
  4. Packet Decision:
    • ALLOW: Packet is forwarded to its destination
    • BLOCK: Packet is silently dropped (no response sent)

Packet Flow

Application DNS Query
       ↓
Windows Network Stack
       ↓
WinDivert (Intercept)
       ↓
DNS Packet Filter
       ↓
Parse DNS Packet → Extract Domain
       ↓
Check Against Rules
       ↓
   ┌───┴───┐
 ALLOW   BLOCK
   ↓       ↓
Forward  Drop

Default Behavior

By default, the filter uses a "fail-open" approach:

  • Unknown domains are ALLOWED (safer for general connectivity)
  • Only explicitly blocked domains are dropped
  • This prevents breaking internet connectivity if rules are misconfigured

Performance

Expected Performance

  • Throughput: 10,000+ DNS queries per second
  • Latency: < 1ms added latency per query
  • Memory: < 50MB under normal load
  • CPU: Minimal impact (< 1% on modern CPUs)

Optimization Tips

  1. Use exact matches when possible (faster than wildcards)
  2. Keep rule count reasonable (< 10,000 rules for best performance)
  3. Use SSD for log files to reduce I/O bottlenecks

Troubleshooting

"Access denied" Error

Problem: Application fails to start with access denied error.

Solution: Run the application as Administrator.

"WinDivert driver not found" Error

Problem: WinDivert64.sys is missing or inaccessible.

Solution:

  • Ensure WinDivert64.sys is in the same directory as dns_filter.exe
  • Check that the file is not blocked by antivirus software
  • Verify Administrator privileges

No DNS Queries Being Filtered

Problem: Application runs but no DNS queries are logged.

Solution:

  • Check that DNS traffic is actually occurring (try browsing websites)
  • Verify the filter is running with Administrator privileges
  • Check firewall settings aren't interfering

Configuration File Not Loading

Problem: "Failed to load configuration" error.

Solution:

  • Verify config/rules.json exists
  • Check JSON syntax is valid (use a JSON validator)
  • Ensure file permissions allow reading

Live Reload Not Working

Problem: Changes to configuration file don't take effect.

Solution:

  • Wait 1-2 seconds after saving (check interval is 1 second)
  • Check console output for "Configuration reloaded" message
  • Verify file was actually saved (not just editor buffer)

Security Considerations

Administrator Privileges

This application requires Administrator privileges because:

  • WinDivert driver needs kernel-level access to intercept packets
  • Network packet filtering is a privileged operation on Windows

Firewall and Antivirus

Some antivirus software may flag WinDivert as suspicious because it's a packet filtering driver. This is a false positive. WinDivert is legitimate open-source software used for network monitoring and filtering.

To resolve:

  • Add exception for dns_filter.exe in antivirus software
  • Add exception for WinDivert64.sys driver

Privacy

All DNS queries are logged locally only. No data is sent to external servers.

Development

Building from Source

Requirements:

  • CMake 3.15 or later
  • C++17 compatible compiler (MSVC 2017+ or MinGW-w64)
  • WinDivert 2.2 library

Code Structure

  • common.h: Shared definitions and constants
  • dns_parser: Parse DNS packets (RFC 1035 format)
  • rule_engine: Thread-safe domain matching
  • logger: Thread-safe logging with rotation
  • config_manager: JSON configuration and live reload
  • packet_filter: WinDivert integration and packet processing
  • main: Application entry point and lifecycle management

Adding New Features

The codebase is modular and easy to extend. Common extensions:

  1. Custom DNS responses: Modify packet_filter.cpp to craft DNS responses instead of dropping
  2. Database backend: Replace config_manager.cpp to load rules from SQLite
  3. Web interface: Add HTTP server for real-time monitoring
  4. Statistics API: Export metrics for monitoring tools

License

This project uses the following open-source libraries:

  • WinDivert (LGPL / GPL)
  • nlohmann/json (MIT License)

Support

For issues, questions, or contributions, please see the project repository.

Acknowledgments

  • WinDivert by basil00 - Excellent packet filtering library
  • nlohmann/json - Modern JSON library for C++

Note: This software is provided for legitimate security and filtering purposes. Use responsibly and in compliance with applicable laws and regulations.