Skip to main content

presolv

High-performance DNS resolver for Python. The core engine is Rust/tokio (exposed via PyO3); the Python surface is synchronous, dnspython-based, and built for bulk and streaming resolution — resolving large query lists, draining queues, or feeding results to/from message brokers.

  • Throughput: all network I/O is asynchronous (tokio) regardless of the synchronous Python API.
  • Bounded resources: a global rate limiter and connection pool cap concurrency against downstream nameservers.
  • Streaming-friendly: resolve()/resolve_stream() accept any iterable — lists, generators, or a generator wrapping a broker consumer — and presolv has no broker-specific dependencies.
  • Lame-server detection: nameservers that repeatedly fail to respond are temporarily blacklisted so they stop being sent queries.

See spec.md for the full design; this README covers install and usage.

Install

pip install presolv

Example

import presolv
import dns.message

resolver = presolv.Resolver(rate_limit=200, pool_size=50, concurrency=500)

queries = [
    presolv.Query(dns.message.make_query("example.com", "A"), nameserver="8.8.8.8", protocol="tcp"),
    presolv.Query(dns.message.make_query("example.org", "AAAA"), nameserver="1.1.1.1"),
]

results = []
for result in resolver.resolve(queries):
    if result.error is not None:
        print(f"query {result.index} failed: {result.error}")
    else:
        results.append(result.response)

resolver.close()

Results arrive in completion order, not input order; each Result carries an index matching the position of the original query so you can correlate back to the input (e.g. to ack a specific broker message).

Response formats

Resolver(response_format="message") (default) returns dns.message.Message objects. response_format="dict" returns a plain, JSON-serializable nested dict instead — useful for publishing results downstream without requiring consumers to depend on dnspython. See the dict shape in spec.md §5.7.

Broker usage patterns

Presolv has no dependency on Kafka, RabbitMQ, or any other broker client library, and ships no broker-specific adapter classes.

Pull model (resolve):

import presolv
import dns.message

def from_kafka(consumer):
    for msg in consumer:
        query = dns.message.from_wire(msg.value())
        yield presolv.Query(query, nameserver="8.8.8.8", protocol="udp")

resolver = presolv.Resolver(rate_limit=500)
for result in resolver.resolve(from_kafka(consumer)):
    handle(result)
    consumer.commit()  # ack after processing

Push model (resolve_stream, useful when offset/ack must happen exactly when a result is produced):

def handle_result(result: presolv.Result) -> None:
    publish_downstream(result)
    channel.basic_ack(delivery_tag=...)

resolver.resolve_stream(from_rabbitmq(consumer), on_result=handle_result)

Security note

Presolv pools long-lived UDP sockets, so the source port is fixed per (nameserver, protocol) key; spoofing resistance relies on DNS message-ID randomness only (ports are not randomized per query, unlike a traditional stub resolver opening a fresh socket per request). Use presolv against operator-chosen/trusted resolvers, not over hostile networks.

Out of scope (v1)

  • DNS-over-TLS (DoT) and DNS-over-HTTPS (DoH) — "udp"/"tcp" only.
  • Automatic TCP fallback on a truncated (TC-flagged) UDP response — the truncated response is returned as-is; resubmit with protocol="tcp" if needed.
  • DNSSEC validation, response caching, an asyncio-native API, and built-in broker adapter classes.

Development

python3 -m venv .venv && . .venv/bin/activate
pip install maturin pytest dnspython
maturin develop
cargo test        # Rust unit + integration tests
pytest -q         # Python test suite

Metadata

Release files for presolv 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for presolv 0.1.0
File Size Uploaded
presolv-0.1.0.tar.gz 906.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for presolv 0.1.0
File Interpreter ABI Platform
presolv-0.1.0-cp39-abi3-manylinux_2_34_x86_64.whl CPython 3.9 abi3 Linux glibc 2.34+ x86-64 Details

Total release size: 1.7 MB

Release files / presolv-0.1.0.tar.gz

Download URL presolv-0.1.0.tar.gz
Size 906.2 kB
Tags Source
SHA-256 checksum
How to use checksums
e64497eb1c172c9d7af12b0efd4a3cad5d404eb74b8227a2137695c96bff6c0e
BLAKE2b-256 checksum
How to use checksums
e3ed4773f068b9fc874eb1f16c00770cd2741429eb20f829674069c4a51c3d9b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release files / presolv-0.1.0-cp39-abi3-manylinux_2_34_x86_64.whl

Download URL presolv-0.1.0-cp39-abi3-manylinux_2_34_x86_64.whl
Size 750.6 kB
Tags CPython 3.9 Linux glibc 2.34+ x86-64 abi3
SHA-256 checksum
How to use checksums
58ecaa91eb929a7f727f656d066cf5905beda51f3489714e23caa15c1e6d2127
BLAKE2b-256 checksum
How to use checksums
02f88c85dc9bca89991578cbecfa1de48e16639d5061c638314787b799db5788
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page