High-performance async DNS resolver validation and speed testing library
Project description
PyResolvers
High-Performance Async DNS Resolver Validation & Speed Testing
Validate DNS resolvers, measure response times, identify the fastest servers
Overview
PyResolvers is a high-performance async Python library and CLI tool for validating DNS resolvers. It performs comprehensive validation (baseline comparison, poisoning detection, NXDOMAIN verification) and orders results by speed.
Features
- โก High-Performance Async - Up to 3x faster than thread-based validators
- ๐ Speed Testing - Measures and orders resolvers by latency
- ๐ URL Support - Download resolver lists from URLs (HTTP/HTTPS)
- ๐ Comprehensive Validation - Baseline, poisoning, NXDOMAIN checks
- ๐ก๏ธ Poisoning Detection - 3-domain check (Amazon, PayPal, Netflix)
- ๐ Multiple Formats - JSON, plain text, text+speed
- ๐ฏ Speed Filtering - Filter by min/max latency thresholds
- ๐ Smart Parsing - Auto-extracts IPs from CSV, text, and mixed formats
- ๐ Verbose Mode - See rejected/filtered servers with reasons
- ๐จ Streaming Results - Real-time output as servers are validated
Performance
Benchmark (500 servers from public-dns.info):
| Concurrency | Timeout | Time | Test Rate | Speedup |
|---|---|---|---|---|
| 50 (default) | 1.0s | 36.7s | 13.6/sec | baseline |
| 100 | 1.0s | 18.3s | 27.3/sec | 2.0x โก |
| 200 | 0.5s | 14.5s | 34.6/sec | 2.5x ๐ |
Estimated time for 62,607 servers:
- Default (50 threads): ~77 minutes
- Optimized (200 threads, 0.5s timeout): ~30 minutes
Installation
git clone https://github.com/PigeonSec/pyresolvers.git
cd pyresolvers
python3 -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
pip install -e .
Or install from PyPI:
pip install pyresolvers
Requirements: Python 3.8+, aiodns, pycares, colorclass
Quick Start
Command Line
# Test single resolver
pyresolvers -t 1.1.1.1
# Test from URL (public DNS list) with optimized settings
pyresolvers -tL https://public-dns.info/nameservers.txt --max-speed 200 -threads 200 -timeout 0.5
# Test from file
pyresolvers -tL dns_servers.txt
# Get fastest resolvers (< 50ms) and save
pyresolvers -tL https://public-dns.info/nameservers.txt --max-speed 50 -o fast_dns.txt
# Verbose mode - see rejected/slow servers
pyresolvers -tL resolvers.txt --max-speed 100 -v
# Export as JSON with speed data
pyresolvers -tL resolvers.txt --format json --max-speed 100 -o valid_dns.json
Python Library
from pyresolvers import Validator
# Basic usage
validator = Validator()
servers = ['1.1.1.1', '8.8.8.8', '9.9.9.9']
results = validator.validate_by_speed(servers)
for server, latency in results:
print(f"{server}: {latency:.2f}ms")
# High concurrency for large lists
validator = Validator(concurrency=100)
results = validator.validate_by_speed(large_server_list, max_ms=100)
# Async usage
import asyncio
async def main():
validator = Validator(concurrency=200)
results = await validator.validate_by_speed_async(servers)
return results
results = asyncio.run(main())
Examples
CLI Usage
# Use public DNS list from URL with optimized performance
pyresolvers -tL https://public-dns.info/nameservers.txt --max-speed 200 -threads 200 -timeout 0.5
# Speed filtering (10ms-100ms range)
pyresolvers -tL resolvers.txt --min-speed 10 --max-speed 100
# Verbose mode - see all results including rejected/too-slow
pyresolvers -tL resolvers.txt --max-speed 100 -v
# Silent mode (IPs only) - great for piping
pyresolvers -tL https://public-dns.info/nameservers.txt --silent --max-speed 30 > fast.txt
# Exclude specific servers
pyresolvers -tL all_resolvers.txt -e 8.8.8.8
# Exclude servers from URL
pyresolvers -tL https://public-dns.info/nameservers.txt -eL blacklist.txt
# Maximum performance (200 concurrent, 0.5s timeout)
pyresolvers -tL large_list.txt -threads 200 -timeout 0.5
# Get top 10 fastest worldwide resolvers with real-time streaming
pyresolvers -tL https://public-dns.info/nameservers.txt -threads 200 --max-speed 30 --format text-with-speed | head -10
Library Usage
Filter by Speed:
validator = Validator(concurrency=50)
fast = validator.validate_by_speed(servers, max_ms=50)
Detailed Results:
results = validator.validate(servers)
for r in results:
if r.valid:
print(f"โ {r.server}: {r.latency_ms:.2f}ms")
else:
print(f"โ {r.server}: {r.error}")
JSON Export:
json_output = validator.to_json(servers, max_ms=100, pretty=True)
with open('valid_dns.json', 'w') as f:
f.write(json_output)
Streaming (Memory Efficient):
async def process_huge_list():
validator = Validator(concurrency=100)
async for server, latency in validator.validate_streaming_async(servers):
print(f"{server}: {latency:.2f}ms")
asyncio.run(process_huge_list())
Cronjob Example
Bash Script:
#!/bin/bash
# /usr/local/bin/dns_monitor.sh
API_URL="https://api.example.com/dns/update"
OUTPUT_DIR="/var/lib/dns-monitor"
mkdir -p "$OUTPUT_DIR"
# Validate and save
pyresolvers -tL https://public-dns.info/nameservers.txt \
--max-speed 100 \
--format json \
-o "$OUTPUT_DIR/resolvers.json"
# Send to API
curl -X POST "$API_URL" \
-H "Content-Type: application/json" \
-d @"$OUTPUT_DIR/resolvers.json"
Crontab:
# Run every 6 hours
0 */6 * * * /usr/local/bin/dns_monitor.sh >> /var/log/dns-monitor.log 2>&1
Input Formats
PyResolvers supports multiple input methods for maximum flexibility.
URL Input
Download resolver lists directly from URLs:
# Public DNS list (62,000+ resolvers)
pyresolvers -tL https://public-dns.info/nameservers.txt --max-speed 50
# Your own hosted list
pyresolvers -tL https://example.com/dns-servers.txt
# GitHub raw files
pyresolvers -tL https://raw.githubusercontent.com/user/repo/main/resolvers.txt
File Input
Load from local files:
# Plain text file (one IP per line)
pyresolvers -tL resolvers.txt
# CSV format (automatically extracts IPs)
pyresolvers -tL servers.csv
# Mixed format with comments
pyresolvers -tL list.txt
Supported File Formats
PyResolvers automatically extracts valid IPv4 addresses from:
Plain Text:
8.8.8.8
1.1.1.1
208.67.222.222
CSV/TSV:
8.8.8.8,Google,US,Fast
1.1.1.1,Cloudflare,US,Fast
208.67.222.222,OpenDNS,US,Moderate
With Comments:
# Google Public DNS
8.8.8.8
# Cloudflare
1.1.1.1
# OpenDNS
208.67.222.222
Mixed Format:
Server: 8.8.8.8 (Google)
dns1=1.1.1.1
208.67.222.222 # OpenDNS Primary
Validation
All input is validated automatically:
- โ Extracts IPv4 addresses from any position in a line
- โ Validates IP format (0-255 per octet)
- โ Skips empty lines and comments (#)
- โ Handles CSV, TSV, and space-separated formats
- โ Removes duplicates automatically
Exclusions
Exclude servers using the same formats:
# Exclude from URL
pyresolvers -tL all.txt -eL https://example.com/blacklist.txt
# Exclude from file
pyresolvers -tL https://public-dns.info/nameservers.txt -eL blocked.txt
# Exclude single IP
pyresolvers -tL resolvers.txt -e 8.8.8.8
API Reference
Validator
High-performance async DNS validator.
Validator(
trusted_resolvers: Optional[List[str]] = None, # ["1.1.1.1", "8.8.8.8"]
test_domains: Optional[List[str]] = None, # ["bet365.com", "telegram.com"]
poison_check_domains: Optional[List[str]] = None,
baseline_domain: str = "bet365.com",
query_prefix: str = "dnsvalidator",
concurrency: int = 50, # Async concurrency
timeout: int = 5, # DNS timeout (seconds)
use_fast_timeout: bool = False, # Fast dead server detection (optional speedup)
batch_size: int = 100, # Memory management
verbose: bool = False
)
Methods:
validate(servers)โList[ValidationResult]- Validate serversvalidate_by_speed(servers, min_ms, max_ms)โList[Tuple[str, float]]- Get valid servers ordered by speedto_json(servers, min_ms, max_ms)โstr- Export as JSONto_text(servers, min_ms, max_ms, show_speed)โstr- Export as text
Async Methods:
await validate_async(servers)- Async validationawait validate_by_speed_async(servers, min_ms, max_ms)- Async speed validationasync for server, latency in validate_streaming_async(servers)- Async streaming
ValidationResult
@dataclass
class ValidationResult:
server: str
valid: bool
latency_ms: float
error: Optional[str] = None
CLI Options
| Option | Description |
|---|---|
-t SERVER |
Test single server |
-tL FILE/URL |
Test from file or URL |
-e SERVER |
Exclude server |
-eL FILE/URL |
Exclude from file/URL |
-r DOMAIN |
Baseline domain (default: bet365.com) |
-threads N |
Concurrency (default: 50) |
-timeout N |
Timeout seconds (default: 1) |
-o FILE |
Output file |
--format FORMAT |
text, json, text-with-speed |
--max-speed MS |
Max latency filter (ms) |
--min-speed MS |
Min latency filter (ms) |
--silent |
Only output IPs |
-v, --verbose |
Verbose output |
--no-color |
Disable colors |
Performance Tips
Recommended Settings
For 60K+ servers (fastest):
pyresolvers -tL https://public-dns.info/nameservers.txt -threads 200 -timeout 0.5 --max-speed 200 -o results.txt
For balanced speed/accuracy:
pyresolvers -tL large_list.txt -threads 100 -timeout 1 --max-speed 100
For verbose debugging:
pyresolvers -tL resolvers.txt -threads 50 -v
Configuration Guide
-
Concurrency:
- 50-100 for stable performance
- 200-300 for maximum speed (requires good network)
- Higher may trigger rate limits
-
Timeout:
- 0.5s for fast dead server detection
- 1s for balanced performance (default)
- 2s+ for slow/distant servers
-
Verbose Mode: Use
-vto see rejected servers with reasons:- "Too slow: XXms" - Exceeded max-speed filter
- "Timeout" - Server didn't respond
- "Invalid" - Failed validation checks
- "DNS poisoning" - Detected hijacking
Optimization Features
- Async I/O - Non-blocking DNS queries with aiodns
- Parallel Validation - All checks run simultaneously
- Streaming Output - Results appear in real-time
- Smart Poisoning - 3 diverse domains (Amazon, PayPal, Netflix)
- Optimized Defaults - 50 threads, 1s timeout, fast mode enabled
- Progress Indicators - Shows validation progress every 100 servers
How It Works
- Baseline Setup - Query trusted resolvers (1.1.1.1, 8.8.8.8) for ground truth
- Parallel Validation - For each server, run simultaneously:
- Poisoning Check - Test 3 random subdomains (amazon.com, paypal.com, netflix.com)
- NXDOMAIN Check - Verify correct NXDOMAIN behavior
- Baseline Compare - Ensure responses match trusted resolvers
- Latency Measurement - Measure DNS query speed for valid servers
- Real-time Output - Stream results as validation completes
- Speed Filtering - Apply min/max latency filters and output sorted results
Important Notes
Thread Count
Keep concurrency reasonable (50-100) to avoid triggering rate limits. Very high concurrency may be blocked by ISPs or DNS providers.
Domain Selection
Use non-geolocated domains for baseline (bet365.com works well). Avoid google.com, facebook.com as they return different IPs by location.
Project Structure
pyresolvers/
โโโ pyresolvers/
โ โโโ __init__.py # Package exports
โ โโโ __main__.py # CLI entry
โ โโโ validator.py # Async validation
โ โโโ lib/core/
โ โโโ input.py # CLI args
โ โโโ output.py # Formatting
โ โโโ __version__.py
โโโ requirements.txt
โโโ setup.py
โโโ README.md
License
GNU General Public License v3.0 - see LICENSE
Acknowledgments
Based on dnsvalidator by:
Enhanced with async architecture, speed testing, and performance optimizations by Karl.
Made with โค๏ธ by Karl | Based on dnsvalidator by @vortexau & @codingo_
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pyresolvers-1.2.0.tar.gz.
File metadata
- Download URL: pyresolvers-1.2.0.tar.gz
- Upload date:
- Size: 434.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
44f8b493adc47411e6e6abd93dde6aee31801a3152197adb100a5a3c85103473
|
|
| MD5 |
8444341c179926530b6081921fa86eee
|
|
| BLAKE2b-256 |
a41b57fa893107a14758d624b7000766da61d61ca586cd4a80ba111e6385257b
|
File details
Details for the file pyresolvers-1.2.0-py3-none-any.whl.
File metadata
- Download URL: pyresolvers-1.2.0-py3-none-any.whl
- Upload date:
- Size: 17.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3acb5822fc3e682307eb723aa9c367ea851a6bfbf5bb1e9aaf7c662a7bfe6d2a
|
|
| MD5 |
ec833f5a2fccc2d188e8a6aa6f391660
|
|
| BLAKE2b-256 |
65bfe281506859bf242cf11c27e9385f0baa7fe8d8d6a2a30338765251ae08f1
|