Files
doh-forwarder/docs/plan.md
Mohammadreza Khani b11d042732 docs: add project plan and development rules
- docs/plan.md: project overview, architecture, milestones, directory structure
- DEVELOP.md: dev rules, code quality standards, git workflow, testing rules, milestone tracking
2026-07-06 16:00:48 +03:30

3.8 KiB

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

  • Project scaffold (Cargo workspace, CI)
  • HTTP server with /dns-query endpoint (GET + POST)
  • Parse incoming DNS wire-format queries
  • Forward to a single upstream DoH resolver
  • Return DNS wire-format response
  • 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