py-doh-core
Python bindings for doh-core,
a Rust DNS resolver library that only speaks secure transports — DNS-over-HTTPS
(RFC 8484), DNS-over-TLS (RFC 7858), and DNS-over-QUIC (RFC 9250) — with no
fallback to classic plaintext DNS. If a query can't be answered securely, you
get a clear exception instead of a silent, unencrypted lookup.
pip install py-doh-core
Quickstart
import py_doh_core as doh
transport = doh.DohTransport("https://dns.google/dns-query")
response = transport.resolve("example.com", "A")
for answer in response.answers:
print(answer.name, answer.ttl, answer.rdata)
Every resolve() has an async def-compatible aresolve() twin:
import asyncio
import py_doh_core as doh
async def main() -> None:
transport = doh.DotTransport("dns.google")
response = await transport.aresolve("example.com", "AAAA")
print(response.answers[0].rdata)
asyncio.run(main())
resolve() blocks the calling thread but releases the GIL for the network
call, so other Python threads keep running; aresolve() returns a normal
awaitable. Both forms exist on all three transports below.
Transports
| Class | Protocol | Constructor |
|---|---|---|
DohTransport |
DNS-over-HTTPS | DohTransport(server_url, method=None) — server_url e.g. "https://dns.google/dns-query" (must be https://); method is "get" (default) or "post" |
DotTransport |
DNS-over-TLS | DotTransport(server_addr) — server_addr is host[:port], default port 853 |
DoqTransport |
DNS-over-QUIC | DoqTransport(server_addr) — same host[:port] form; the QUIC connection is pooled and reused across every resolve()/aresolve() call on the instance |
All three share the same API: resolve, aresolve, resolve_many,
aresolve_many. Pick a transport, not a different way of calling it.
Responses are typed, not dicts
resolve()/aresolve() return a ParsedResponse with real attributes —
response.answers[0].rdata, not response["answers"][0]["rdata"] — mirroring
every field of the underlying doh_core::ParsedResponse (header flags,
question, answer/authority/additional sections, wire size). op_code and
response_code are OpCode/ResponseCode enums, not magic strings or ints:
if response.response_code == doh.ResponseCode.NXDOMAIN:
... # the name doesn't exist -- this is a successful response, not an error
See py_doh_core.pyi
for the full type signatures.
Handling errors
Anything that isn't a clean "no error" or "name does not exist" response —
a bad server URL, a connection failure, SERVFAIL, REFUSED, a malformed
reply — raises doh.DohError rather than returning a half-empty result:
try:
response = transport.resolve("dnssec-failed.org", "A")
except doh.DohError as exc:
print("lookup failed:", exc)
str(exc) carries the same message the underlying Rust library produces.
Multiple record types in one call
resolve_many()/aresolve_many() query several record types for one name
against a single transport instance. Queries run in turn, reusing the
connection where that matters (DoqTransport's pooled connection in
particular), and one type's failure doesn't abort the rest — each entry in
the returned list is a QueryResult with exactly one of response/error
set:
for result in transport.resolve_many("example.com", ["A", "AAAA", "MX"]):
if result.error is not None:
print(result.record_type, "failed:", result.error)
else:
print(result.record_type, [a.rdata for a in result.response.answers])
An unparseable record type string is the one exception: it raises DohError
immediately, before any query in the batch is sent.
Logging
Verbose/debug output uses Python's standard logging module — no separate
init call needed:
import logging
logging.basicConfig(level=logging.DEBUG)
Logger names follow the Rust module path, e.g. doh_core.transport.doh,
doh_core.transport.doq, py_doh_core.transport. DEBUG shows one line per
query (server, method, connection reuse, response codes); a small amount of
extra detail (e.g. response sizes) logs at level 5, below logging.DEBUG
(10) — pass level=5 to see it. Scope to just this library with
logging.getLogger("doh_core").setLevel(logging.DEBUG).
Only doh_core/py_doh_core targets are bridged to Python — dependency
crates (reqwest, h2, rustls, quinn) are deliberately not, since their
logging runs on long-lived background threads that can outlive a single
resolve() call and, in rare cases, still be active as the Python
interpreter shuts down.
Development
py-doh-core is a PyO3 cdylib extension module, built with
maturin. It's intentionally excluded from the
main Cargo workspace (see the root Cargo.toml) since it needs maturin's
linker setup to resolve Python symbols at import time — plain
cargo build/cargo test --workspace can't link it.
Build from source
cd py-doh-core
python3 -m venv .venv
source .venv/bin/activate
pip install maturin
maturin develop
Tests
pip install pytest pytest-asyncio
pytest
tests/test_resolve.py runs live against real public resolvers (no mocking
layer, same approach the Rust side uses). DoT/DoQ cases skip automatically
if port 853 is unreachable on the current network.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
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 py_doh_core-0.1.1.tar.gz.
File metadata
- Download URL: py_doh_core-0.1.1.tar.gz
- Upload date:
- Size: 82.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
469166eac33639a08abf4b809ef1499c70185ea401e0c8340b224111d13a6684
|
|
| MD5 |
bdaa95d0f62eeea31c8fd3d4c816dcb5
|
|
| BLAKE2b-256 |
82c1ca80dec7fb696e8a9e2a2bfba7d9fe77b4a4220eacaf1e87ae84311911d0
|
Provenance
The following attestation bundles were made for py_doh_core-0.1.1.tar.gz:
Publisher:
py-doh-core-release.yml on ubahmapk/doh
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
py_doh_core-0.1.1.tar.gz -
Subject digest:
469166eac33639a08abf4b809ef1499c70185ea401e0c8340b224111d13a6684 - Sigstore transparency entry: 2500126505
- Sigstore integration time:
-
Permalink:
ubahmapk/doh@d63c795ec49c5ae859891697c3557a58f908fc92 -
Branch / Tag:
refs/tags/py-v0.1.1 - Owner: https://github.com/ubahmapk
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
py-doh-core-release.yml@d63c795ec49c5ae859891697c3557a58f908fc92 -
Trigger Event:
push
-
Statement type:
File details
Details for the file py_doh_core-0.1.1-cp39-abi3-win_amd64.whl.
File metadata
- Download URL: py_doh_core-0.1.1-cp39-abi3-win_amd64.whl
- Upload date:
- Size: 3.1 MB
- Tags: CPython 3.9+, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
297d83e182c306796c9ab889b35aaefaeef13c55bba6902529d80e5f550ba67e
|
|
| MD5 |
3bf3d4903189a7196db59d5d9e0ee527
|
|
| BLAKE2b-256 |
a605c723b966676b5891ec4b82b4cff1d9ff5fe0f3bd5878f0018985f5d2c055
|
Provenance
The following attestation bundles were made for py_doh_core-0.1.1-cp39-abi3-win_amd64.whl:
Publisher:
py-doh-core-release.yml on ubahmapk/doh
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
py_doh_core-0.1.1-cp39-abi3-win_amd64.whl -
Subject digest:
297d83e182c306796c9ab889b35aaefaeef13c55bba6902529d80e5f550ba67e - Sigstore transparency entry: 2500126521
- Sigstore integration time:
-
Permalink:
ubahmapk/doh@d63c795ec49c5ae859891697c3557a58f908fc92 -
Branch / Tag:
refs/tags/py-v0.1.1 - Owner: https://github.com/ubahmapk
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
py-doh-core-release.yml@d63c795ec49c5ae859891697c3557a58f908fc92 -
Trigger Event:
push
-
Statement type:
File details
Details for the file py_doh_core-0.1.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: py_doh_core-0.1.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 3.8 MB
- Tags: CPython 3.9+, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ff49d082aeda195ef7d52b52de4a8b9a7476c339b95cbc29e8e09db0933473db
|
|
| MD5 |
35008ba3c00021a58c58fec5068f8d3c
|
|
| BLAKE2b-256 |
262c6d2064f43a8bfe92bd2d944a062ee3117fb3217e356d0fa7bb905d65ca00
|
Provenance
The following attestation bundles were made for py_doh_core-0.1.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:
Publisher:
py-doh-core-release.yml on ubahmapk/doh
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
py_doh_core-0.1.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl -
Subject digest:
ff49d082aeda195ef7d52b52de4a8b9a7476c339b95cbc29e8e09db0933473db - Sigstore transparency entry: 2500126511
- Sigstore integration time:
-
Permalink:
ubahmapk/doh@d63c795ec49c5ae859891697c3557a58f908fc92 -
Branch / Tag:
refs/tags/py-v0.1.1 - Owner: https://github.com/ubahmapk
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
py-doh-core-release.yml@d63c795ec49c5ae859891697c3557a58f908fc92 -
Trigger Event:
push
-
Statement type:
File details
Details for the file py_doh_core-0.1.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.
File metadata
- Download URL: py_doh_core-0.1.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
- Upload date:
- Size: 3.9 MB
- Tags: CPython 3.9+, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f7c31b03ed2fa3db3b7325c2c8ac23bcd1ca54be07bc8dcf8cab322a4c0ab879
|
|
| MD5 |
7632925b8179e7a465125897de4fb80f
|
|
| BLAKE2b-256 |
44d3d9a38b29d9a302bd113dbf8a805850edfed601f5760bedbe0e30eb6248e1
|
Provenance
The following attestation bundles were made for py_doh_core-0.1.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:
Publisher:
py-doh-core-release.yml on ubahmapk/doh
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
py_doh_core-0.1.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl -
Subject digest:
f7c31b03ed2fa3db3b7325c2c8ac23bcd1ca54be07bc8dcf8cab322a4c0ab879 - Sigstore transparency entry: 2500126507
- Sigstore integration time:
-
Permalink:
ubahmapk/doh@d63c795ec49c5ae859891697c3557a58f908fc92 -
Branch / Tag:
refs/tags/py-v0.1.1 - Owner: https://github.com/ubahmapk
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
py-doh-core-release.yml@d63c795ec49c5ae859891697c3557a58f908fc92 -
Trigger Event:
push
-
Statement type:
File details
Details for the file py_doh_core-0.1.1-cp39-abi3-macosx_11_0_arm64.whl.
File metadata
- Download URL: py_doh_core-0.1.1-cp39-abi3-macosx_11_0_arm64.whl
- Upload date:
- Size: 3.5 MB
- Tags: CPython 3.9+, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fba80694184d11f6e906931ec466c8b0cc2cba98f8547ac7db2059cb316a6d2c
|
|
| MD5 |
cd1e8684a9a58affaf38676ebca1e54c
|
|
| BLAKE2b-256 |
60910bbaec28e2b04f4e5ea3f389ea6abde04874b55e05086acf86b44687e790
|
Provenance
The following attestation bundles were made for py_doh_core-0.1.1-cp39-abi3-macosx_11_0_arm64.whl:
Publisher:
py-doh-core-release.yml on ubahmapk/doh
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
py_doh_core-0.1.1-cp39-abi3-macosx_11_0_arm64.whl -
Subject digest:
fba80694184d11f6e906931ec466c8b0cc2cba98f8547ac7db2059cb316a6d2c - Sigstore transparency entry: 2500126517
- Sigstore integration time:
-
Permalink:
ubahmapk/doh@d63c795ec49c5ae859891697c3557a58f908fc92 -
Branch / Tag:
refs/tags/py-v0.1.1 - Owner: https://github.com/ubahmapk
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
py-doh-core-release.yml@d63c795ec49c5ae859891697c3557a58f908fc92 -
Trigger Event:
push
-
Statement type:
File details
Details for the file py_doh_core-0.1.1-cp39-abi3-macosx_10_12_x86_64.whl.
File metadata
- Download URL: py_doh_core-0.1.1-cp39-abi3-macosx_10_12_x86_64.whl
- Upload date:
- Size: 3.6 MB
- Tags: CPython 3.9+, macOS 10.12+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a05f47e3b1f6fe5c7f3ca30f5aa9b2eb99e6813535b1fbaec17f67505496e874
|
|
| MD5 |
7e05e9c28078c8f4dfc18d761ca61cdc
|
|
| BLAKE2b-256 |
0e918eeed73d9f3d897e63d1a3472d60802af31fc5a2862c26d5bd335cc4f982
|
Provenance
The following attestation bundles were made for py_doh_core-0.1.1-cp39-abi3-macosx_10_12_x86_64.whl:
Publisher:
py-doh-core-release.yml on ubahmapk/doh
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
py_doh_core-0.1.1-cp39-abi3-macosx_10_12_x86_64.whl -
Subject digest:
a05f47e3b1f6fe5c7f3ca30f5aa9b2eb99e6813535b1fbaec17f67505496e874 - Sigstore transparency entry: 2500126529
- Sigstore integration time:
-
Permalink:
ubahmapk/doh@d63c795ec49c5ae859891697c3557a58f908fc92 -
Branch / Tag:
refs/tags/py-v0.1.1 - Owner: https://github.com/ubahmapk
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
py-doh-core-release.yml@d63c795ec49c5ae859891697c3557a58f908fc92 -
Trigger Event:
push
-
Statement type: