# DoH Forwarder — Project Plan ## Overview A lightweight DNS-over-HTTPS (DoH) forwarder that accepts DNS queries over HTTPS (RFC 8484) and forwards them to upstream DoH resolvers, with caching, logging, and optional blocking. ## Goals - Accept DoH queries (GET and POST per RFC 8484) - Forward to configurable upstream DoH resolvers (Cloudflare, Google, Quad9, custom) - In-memory DNS response cache with configurable TTL - Query logging (stdout/file) - Optional domain blocklist (ad-blocking / parental control) - Health-check endpoint - Low resource footprint, single binary ## Architecture ``` ┌─────────────┐ ┌──────────────────┐ ┌─────────────────┐ │ DNS Client │─────▶│ DoH Forwarder │─────▶│ Upstream DoH │ │ (browser, │ HTTPS│ (this project) │ HTTPS│ (1.1.1.1, │ │ OS, app) │◀─────│ │◀─────│ 8.8.8.8, …) │ └─────────────┘ └──────────────────┘ └─────────────────┘ ``` ## Tech Stack - **Language**: Rust - **HTTP server**: Axum - **DNS wire-format**: hickory-proto (formerly trust-dns-proto) - **Async runtime**: Tokio - **Config**: TOML (config file) + env vars - **Logging**: tracing + tracing-subscriber ## Milestones ### M1 — Core Forwarding - [x] Project scaffold (Cargo workspace, CI) - [x] HTTP server with `/dns-query` endpoint (GET + POST) - [x] Parse incoming DNS wire-format queries - [x] Forward to a single upstream DoH resolver - [x] Return DNS wire-format response - [x] Basic integration test ### M2 — Multiple Upstreams & Config - [ ] TOML config file support - [ ] Multiple upstream resolver support - [ ] Upstream selection strategy (round-robin / failover) - [ ] Environment variable overrides - [ ] Graceful shutdown ### M3 — Caching - [ ] In-memory DNS response cache - [ ] Cache key = (query name, query type) - [ ] Respect DNS response TTL (with configurable max) - [ ] Cache eviction (TTL-based + LRU size cap) - [ ] Cache stats endpoint (`/cache/stats`) ### M4 — Observability - [ ] Structured logging (tracing) - [ ] Request logging middleware (query name, type, latency, upstream used) - [ ] Health endpoint (`/health`) - [ ] Metrics endpoint (optional, Prometheus format) ### M5 — Blocking & Filtering - [ ] Domain blocklist (file-based, one domain per line) - [ ] Wildcard / suffix matching - [ ] Return NXDOMAIN for blocked queries - [ ] Hot-reload blocklist on SIGHUP ### M6 — Production Hardening - [ ] Rate limiting (per-IP) - [ ] Request timeout for upstream queries - [ ] Dockerfile (multi-stage, distroless) - [ ] Helm chart - [ ] CI pipeline (lint, test, build, image push) ## Directory Structure (target) ``` doh-forwarder/ ├── Cargo.toml ├── src/ │ ├── main.rs # entrypoint, server setup │ ├── config.rs # config parsing │ ├── dns/ │ │ ├── mod.rs │ │ ├── query.rs # parse incoming DNS queries │ │ └── response.rs # build/parse DNS responses │ ├── upstream/ │ │ ├── mod.rs │ │ └── doh_client.rs # DoH forwarding client │ ├── cache.rs # DNS cache │ ├── blocklist.rs # domain blocking │ ├── routes.rs # HTTP route handlers │ └── middleware.rs # logging, rate-limit ├── config/ │ └── default.toml ├── docs/ │ └── plan.md ├── DEVELOP.md └── tests/ └── integration.rs ``` ## Non-Goals (for now) - DNS-over-TLS (DoT) listener - DNSSEC validation - Persistent cache (Redis / disk) - Web UI / dashboard