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.12+, aiodns, pycares, colorclass
Quick Start
CLI Commands
Basic validation:
$ pyresolvers -t 1.1.1.1
=======================================================
pyresolvers v2.0.1 - DNS Resolver Validator
=======================================================
[10:25:04] [INFO] Testing 1 servers
[10:25:04] [INFO] Establishing baseline...
[10:25:04] [INFO] Validating with concurrency=50...
[10:25:04] [ACCEPTED] [1.1.1.1] 20.49ms
[10:25:04] [INFO] Found 1 valid servers
Test multiple servers from file:
$ pyresolvers -tL dns_servers.txt
[10:25:11] [INFO] Testing 3 servers
[10:25:11] [INFO] Establishing baseline...
[10:25:11] [INFO] Validating with concurrency=50...
[10:25:11] [ACCEPTED] [9.9.9.9] 9.00ms
[10:25:11] [ACCEPTED] [8.8.8.8] 15.79ms
[10:25:11] [ACCEPTED] [1.1.1.1] 19.69ms
[10:25:11] [INFO] Found 3 valid servers
Silent mode (IPs only, perfect for piping):
$ pyresolvers -tL dns_servers.txt --silent
9.9.9.9
8.8.8.8
1.1.1.1
Verbose mode with speed filtering:
$ pyresolvers -tL dns_servers.txt --max-speed 15 -v
[10:25:27] [INFO] Testing 3 servers
[10:25:27] [INFO] Max speed filter: 15.0ms
[10:25:28] [ACCEPTED] [9.9.9.9] 9.05ms
[10:25:28] [REJECTED] [1.1.1.1] Too slow: 20.30ms
[10:25:28] [REJECTED] [8.8.8.8] Too slow: 20.22ms
[10:25:28] [INFO] Found 1 valid servers
JSON output format:
$ pyresolvers -tL dns_servers.txt --format json
{
"servers": [
{"ip": "9.9.9.9", "latency_ms": 10.3},
{"ip": "8.8.8.8", "latency_ms": 15.96},
{"ip": "1.1.1.1", "latency_ms": 20.35}
],
"count": 3,
"filters": {"min_ms": null, "max_ms": null}
}
More examples:
# Test from URL
pyresolvers -tL https://public-dns.info/nameservers.txt
# Speed filtering and save to file
pyresolvers -tL resolvers.txt --max-speed 50 -o fast_dns.txt
pyresolvers -tL resolvers.txt --min-speed 10 --max-speed 100
# Text with speed output
pyresolvers -tL resolvers.txt --format text-with-speed -o dns_with_speed.txt
# Exclusions
pyresolvers -tL all_resolvers.txt -e 8.8.8.8
pyresolvers -tL resolvers.txt -eL blacklist.txt
# Performance tuning
pyresolvers -tL large_list.txt -threads 200 -timeout 0.5
pyresolvers -tL https://public-dns.info/nameservers.txt -threads 200 --max-speed 30 | head -10
Library Usage
from pyresolvers import Validator
# Basic usage - get valid servers ordered by speed
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 with speed filtering
validator = Validator(concurrency=100)
fast = validator.validate_by_speed(servers, max_ms=50)
# Detailed results with error information
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)
# 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())
# Streaming for huge lists (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 Examples
Daily DNS validation with API upload:
#!/bin/bash
# /usr/local/bin/dns_monitor.sh
OUTPUT_DIR="/var/lib/dns-monitor"
mkdir -p "$OUTPUT_DIR"
# Validate and save to JSON
pyresolvers -tL https://public-dns.info/nameservers.txt \
--max-speed 100 \
--format json \
-o "$OUTPUT_DIR/resolvers.json"
# Upload to API
curl -X POST "https://api.example.com/dns/update" \
-H "Content-Type: application/json" \
-d @"$OUTPUT_DIR/resolvers.json"
Fast resolver discovery and update:
#!/bin/bash
# /usr/local/bin/update_fast_dns.sh
# Get fastest resolvers (< 30ms) and update system config
pyresolvers -tL https://public-dns.info/nameservers.txt \
--max-speed 30 \
--silent \
-threads 200 \
-timeout 0.5 \
-o /tmp/fast_dns.txt
# Use top 3 fastest
head -3 /tmp/fast_dns.txt > /etc/my_app/dns_servers.conf
Crontab entries:
# Daily API sync at 2 AM
0 2 * * * /usr/local/bin/dns_monitor.sh >> /var/log/dns-monitor.log 2>&1
# Update fast DNS every 6 hours
0 */6 * * * /usr/local/bin/update_fast_dns.sh >> /var/log/dns-update.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.
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_
Release files for pyresolvers 2.4.3
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pyresolvers-2.4.3.tar.gz | 443.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pyresolvers-2.4.3-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 461.5 kB
Release files / pyresolvers-2.4.3.tar.gz
| Download URL | pyresolvers-2.4.3.tar.gz |
|---|---|
| Size | 443.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
43f9ec5a82d0492a161aacd0d33a58c444ca1fd0029210edad2ef85e36333924
|
|
BLAKE2b-256 checksum How to use checksums |
d4f999a9022ab0679850b37211434a30ae9e462e3c5073b768350635015bf528
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.14
|
Release files / pyresolvers-2.4.3-py3-none-any.whl
| Download URL | pyresolvers-2.4.3-py3-none-any.whl |
|---|---|
| Size | 18.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e5c4f8abee6d9b432929c46dc05be69761f4dfbf007390b4a5a270940fee0b7f
|
|
BLAKE2b-256 checksum How to use checksums |
8e8b0758a0a7bc62e09784fbf73c35780277b0317b75c1af36691b145a7cd681
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.14
|