Mohammadreza Khani 4c62b1436a feat: add Arch Linux package (PKGBUILD, systemd service, sysusers)
- PKGBUILD for building the package
- Systemd service with CAP_NET_BIND_SERVICE for port 53
- sysusers.d config to create doh-forwarder system user
- Default config at /etc/doh-forwarder/config.toml
2026-07-06 18:58:48 +03:30

doh-forwarder

A lightweight DNS-over-HTTPS (DoH) forwarder written in Rust.

Accepts DNS queries over HTTPS (RFC 8484) and forwards them to upstream DoH resolvers (Cloudflare, Google, Quad9, or custom).

Features

  • RFC 8484 compliant — GET (?dns=base64url) and POST (application/dns-message)
  • Multiple upstreams — configure several DoH resolvers
  • Selection strategies — round-robin or failover
  • In-memory cache — TTL-aware with LRU eviction (configurable)
  • Environment overrides — override config via env vars
  • Graceful shutdown — handles SIGINT and SIGTERM
  • Health endpointGET /health

Quick Start

# Build
cargo build --release

# Run with default config
./target/release/doh-forwarder

# Run with a custom config
./target/release/doh-forwarder --config /path/to/config.toml

Configuration

Create a TOML config file (see config/default.toml):

[server]
listen = "0.0.0.0:3000"

[upstream]
resolvers = [
    { name = "cloudflare", url = "https://cloudflare-dns.com/dns-query" },
    { name = "google", url = "https://dns.google/dns-query" },
    { name = "quad9", url = "https://dns.quad9.net/dns-query" },
]
strategy = "round-robin"  # or "failover"

[cache]
enabled = true
max_entries = 10000
max_ttl_secs = 3600

Environment Variable Overrides

Variable Description Example
DOH_LISTEN Override server listen address 0.0.0.0:8080
DOH_UPSTREAM_STRATEGY Override upstream strategy failover
DOH_UPSTREAM_RESOLVERS Comma-separated name=url pairs google=https://dns.google/dns-query,cf=https://cloudflare-dns.com/dns-query
RUST_LOG Log level filter debug, doh_forwarder=trace

API

POST /dns-query

Send a raw DNS wire-format query in the request body.

# Using a pre-built DNS query (hex-encoded)
curl -X POST http://localhost:3000/dns-query \
  -H "Content-Type: application/dns-message" \
  -H "Accept: application/dns-message" \
  --data-binary @query.bin

GET /dns-query

Send a base64url-encoded DNS query as a query parameter.

# Encode a DNS query and send via GET
QUERY=$(python3 -c "
import base64, struct
# Minimal A record query for example.com
q = b'\\x12\\x34'  # ID
q += b'\\x01\\x00'  # flags
q += b'\\x00\\x01'  # 1 question
q += b'\\x00\\x00'  # 0 answers
q += b'\\x00\\x00'  # 0 authority
q += b'\\x00\\x00'  # 0 additional
q += b'\\x07example\\x03com\\x00'  # name
q += b'\\x00\\x01'  # type A
q += b'\\x00\\x01'  # class IN
print(base64.urlsafe_b64encode(q).rstrip(b'=').decode())
")
curl "http://localhost:3000/dns-query?dns=$QUERY"

GET /health

Returns ok if the server is running.

curl http://localhost:3000/health
# ok

Upstream Strategies

Strategy Behavior
round-robin Distributes queries across resolvers in order
failover Tries resolvers in order; moves to the next on failure

Development

# Prerequisites
rustup show            # Rust 1.80+

# Run with auto-reload
cargo install cargo-watch
cargo watch -x run

# Run tests
cargo test

# Lint & format
cargo clippy -- -D warnings
cargo fmt --check

See DEVELOP.md for full development rules and milestone tracking.

Project Structure

doh-forwarder/
├── Cargo.toml
├── config/
│   └── default.toml         # Default configuration
├── src/
│   ├── main.rs               # Entrypoint, server setup
│   ├── lib.rs                # Public API re-exports
│   ├── config.rs             # TOML config + env overrides
│   ├── cache.rs              # DNS response cache (TTL + LRU)
│   ├── dns/
│   │   ├── mod.rs
│   │   ├── query.rs          # DNS query parsing
│   │   └── response.rs       # DNS response building
│   ├── upstream/
│   │   ├── mod.rs
│   │   └── doh_client.rs     # DoH forwarding client
│   └── routes.rs             # HTTP route handlers
└── tests/
    └── integration.rs        # Integration tests

License

MIT

Description
No description provided
Readme MIT 2.1 MiB
v0.1.0 Latest
2026-07-06 15:30:16 +00:00
Languages
Rust 55.7%
Shell 37.1%
Perl 7.2%