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:
-
Download WinDivert 2.2 from: https://github.com/basil00/WinDivert/releases/download/v2.2.2/WinDivert-2.2.2-A.zip
-
Extract the ZIP file
-
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
Using CMake (Recommended)
# 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 applicationWinDivert.dll- WinDivert libraryWinDivert64.sys- WinDivert driverconfig/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:
- Right-click on Command Prompt
- Select "Run as Administrator"
- Navigate to the application directory
- 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" subdomainexample.*- 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
-
Start the filter:
dns_filter.exe -
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)
- Add a domain to block in
-
Check logs:
type dns_filter.log- Look for entries showing the blocked query
Test Live Reload
- Start the filter
- Edit
config/rules.jsonto add a new blocked domain - Save the file
- Check the console output - you should see "Configuration reloaded"
- Test the newly blocked domain with
nslookup
Test Wildcard Patterns
-
Add a wildcard rule:
{"domain": "*.ads.example.com", "action": "block"} -
Test various subdomains:
nslookup test.ads.example.com nslookup another.ads.example.com -
All should be blocked
How It Works
Architecture
- WinDivert Integration: Intercepts all DNS traffic (port 53 UDP/TCP) at the network layer
- DNS Parser: Extracts domain names from binary DNS packets
- Rule Engine: Matches domains against configured rules (exact + wildcard)
- 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
- Use exact matches when possible (faster than wildcards)
- Keep rule count reasonable (< 10,000 rules for best performance)
- 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.sysis in the same directory asdns_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.jsonexists - 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.exein antivirus software - Add exception for
WinDivert64.sysdriver
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:
- Custom DNS responses: Modify
packet_filter.cppto craft DNS responses instead of dropping - Database backend: Replace
config_manager.cppto load rules from SQLite - Web interface: Add HTTP server for real-time monitoring
- 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.