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 - 2-3x faster than thread-based validators
- 🚀 Speed Testing - Measures and orders resolvers by latency
- 🔍 Comprehensive Validation - Multiple validation layers
- 🛡️ Poisoning Detection - Identifies DNS hijacking
- 📊 Multiple Formats - JSON, plain text, text+speed
- 🎯 Speed Filtering - Filter by min/max latency thresholds
Performance
| Method | Time (5 servers) | Improvement |
|---|---|---|
| Original (unoptimized) | 5.36s | baseline |
| PyResolvers | 2.32s | 56.7% faster ⚡ |
| Speedup | 2.31x |
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 file
pyresolvers -tL dns_servers.txt
# Get fastest resolvers (< 50ms)
pyresolvers -tL resolvers.txt --max-speed 50 --format text-with-speed
# Export as JSON
pyresolvers -tL resolvers.txt --format json -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
# Speed filtering
pyresolvers -tL resolvers.txt --min-speed 10 --max-speed 100
# Silent mode (IPs only)
pyresolvers -tL resolvers.txt --silent
# Exclude specific servers
pyresolvers -tL all_resolvers.txt -e 8.8.8.8
# High performance (100 concurrent)
pyresolvers -tL large_list.txt -threads 100
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
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: 5) |
-timeout N |
Timeout seconds (default: 600) |
-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
- Concurrency: 50-100 for best performance on most systems
- Timeout: Lower (3s) for speed, higher (10s+) for thoroughness
- Fast Timeout: Enable (
use_fast_timeout=True) for 30-50% speedup (may miss slow servers) - Batch Size: Increase for more memory, decrease for less
- Network: Run from VPS to avoid ISP throttling
Optimization Features
- Async I/O - Non-blocking DNS queries with aiodns
- Parallel Baseline - Queries trusted resolvers simultaneously
- Fast Timeout - 1s initial timeout for dead server detection
- Combined Queries - Reduces DNS round trips
- Batch Processing - Memory-efficient for huge lists
- Streaming - Progressive results without holding all in memory
How It Works
- Baseline - Query trusted DNS (Cloudflare, Google) for ground truth
- Poisoning Check - Test random subdomains to detect hijacking
- NXDOMAIN - Verify correct NXDOMAIN behavior
- Baseline Compare - Ensure responses match baseline
- Speed Test - Measure latency and order 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.0.0.tar.gz.
File metadata
- Download URL: pyresolvers-1.0.0.tar.gz
- Upload date:
- Size: 197.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
99cd28b521c4cae0a916c8ee1447f5ffac83dfcd1faedd885f7ccc2538a33dea
|
|
| MD5 |
54bb7e85fc0d2e37306a38f7f3bbe94d
|
|
| BLAKE2b-256 |
6e263473ce9c1dc8014c173988a5cd571439030a1db8e65e6bc784f7496f4d92
|
File details
Details for the file pyresolvers-1.0.0-py3-none-any.whl.
File metadata
- Download URL: pyresolvers-1.0.0-py3-none-any.whl
- Upload date:
- Size: 14.3 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 |
e5c54c52d41acf32285da34a0935aae5d076a15e1e165760456f7931b6b1a715
|
|
| MD5 |
6b1f0ce1431418a4c9f487851b3925ce
|
|
| BLAKE2b-256 |
7aa4d4ef2b506b0f4dc1ded22eb59e6cdf003eee6e220bfe9b7b1b34662ebf78
|