# dnscrypt
[](https://crates.io/crates/dnscrypt)
[](https://docs.rs/dnscrypt)
[](https://codeberg.org/hacer-bark/dnscrypt#license)
A high-assurance implementation of the **DNSCrypt v2 client protocol**. Built on an asynchronous, Tokio-backed API, this crate provides transport-level encryption and cryptographic authentication for all your DNS queries.
No unsafe code.
## Features
- **Audited Cryptography**: X25519, Ed25519, constant-time comparison, and randomness are backed by `aws-lc-rs`. The certificate's ES version selects between `XChaCha20-Poly1305` and `XSalsa20-Poly1305` (neither supported by `aws-lc-rs`), provided by the pure-Rust `chacha20`/`salsa20`/`poly1305` crates.
- **MITM Resistance**: Relies on pinned resolver public keys hardcoded at compile-time to prevent CA-level compromise/spoofing.
- **Robust TCP Fallback**: Automatically and transparently retries queries over TCP if the decrypted DNSCrypt response indicates truncation (TC bit set).
- **Reqwest Integration**: Ships a drop-in `DnscryptResolver` to route all host lookups in a `reqwest::Client` through DNSCrypt.
- **Async Tokio API**: A single, focused async API — no synchronous entry points to keep in sync.
## Feature Flags
| `reqwest` | Enables the `DnscryptResolver` for integration with `reqwest::Client`. | Yes |
## Cryptographic Specification
| **X25519 DH** | Per-session key agreement with the resolver | `aws-lc-rs` |
| **HChaCha20** / **HSalsa20** | Key derivation from the raw Diffie-Hellman secret | `chacha20` / `salsa20` |
| **XChaCha20-Poly1305** / **XSalsa20-Poly1305** | Authenticated encryption of queries/responses | `chacha20` / `salsa20` / `poly1305` |
| **Ed25519** | Resolver certificate signature verification | `aws-lc-rs` |
The AEAD construction used per-session is whichever ES version (`0x0001` or `0x0002`) the
resolver's certificate advertises — not a client-side choice.
## Default Resolvers
`HARDCODED_RESOLVERS` ships 5 endpoints across 2 independently operated providers, each with its
Ed25519 provider public key pinned at compile time:
| [Quad9](https://quad9.net) | `9.9.9.9:8443`, `149.112.112.112:8443`, `149.112.112.9:8443` |
| [AdGuard DNS](https://adguard-dns.io) | `94.140.14.14:5443`, `94.140.15.15:5443` |
Session establishment stops once it has 3 live sessions, so a typical run only contacts a subset of
these. Supply your own list via [`HardcodedResolver`](#3-custom-dnscrypt-resolvers) to bypass the
defaults entirely.
### 1. Simple Resolution
```rust
use dnscrypt::{resolve, HARDCODED_RESOLVERS, Error};
#[tokio::main]
async fn main() -> Result<(), Error> {
// Resolve github.com using default built-in resolvers
let ips = resolve(HARDCODED_RESOLVERS, "github.com").await?;
println!("github.com => {:?}", ips);
Ok(())
}
```
### 2. Reqwest Client Integration
Enable the `reqwest` feature flag to use `DnscryptResolver`:
```rust
use dnscrypt::DnscryptResolver;
use std::sync::Arc;
#[tokio::main]
async fn main() {
let resolver = Arc::new(DnscryptResolver::new());
let client = reqwest::Client::builder()
.dns_resolver(resolver)
.build()
.unwrap();
let res = client.get("https://github.com")
.send()
.await
.unwrap();
println!("Status: {}", res.status());
}
```
### 3. Custom DNSCrypt Resolvers
Bypass the default list of resolvers by supplying your own custom configurations:
```rust
use dnscrypt::{resolve, HardcodedResolver};
use std::net::{SocketAddr, IpAddr, Ipv4Addr};
const MY_RESOLVERS: &[HardcodedResolver] = &[
HardcodedResolver {
ip: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(9, 9, 9, 9)), 8443),
provider_name: "2.dnscrypt-cert.quad9.net",
provider_pk: [
// Insert your resolver's Ed25519 public key bytes here
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
],
}
];
#[tokio::main]
async fn main() {
let ips = resolve(MY_RESOLVERS, "github.com").await.unwrap();
println!("Resolved: {:?}", ips);
}
```
## Security Hardening
This library has undergone systematic hardening to defend against transport-level threats:
- **Randomized Padding & TXIDs**: Queries are padded to randomized boundaries to prevent side-channel traffic analysis. Transaction IDs are derived from `aws-lc-rs`'s cryptographically secure random source.
- **Encrypted TC Detection**: The parser decrypts responses before validating truncation. If a response is truncated inside the secure envelope, the resolver automatically executes a retry over TCP.
## License
Licensed under the [0BSD license](https://github.com/hacer-bark/cargo-unikernel/blob/main/LICENSE).
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in
this crate shall be licensed as above, without any additional terms or conditions.