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
This commit is contained in:
113
DEVELOP.md
Normal file
113
DEVELOP.md
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
# DEVELOP.md — Development Rules & Tracking
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Prerequisites
|
||||||
|
rustup show # Rust 1.80+
|
||||||
|
cargo install cargo-watch
|
||||||
|
|
||||||
|
# Run locally
|
||||||
|
cargo run -- --config config/default.toml
|
||||||
|
|
||||||
|
# Run with auto-reload
|
||||||
|
cargo watch -x run
|
||||||
|
|
||||||
|
# Run tests
|
||||||
|
cargo test
|
||||||
|
|
||||||
|
# Lint
|
||||||
|
cargo clippy -- -D warnings
|
||||||
|
cargo fmt --check
|
||||||
|
```
|
||||||
|
|
||||||
|
## Development Rules
|
||||||
|
|
||||||
|
### Code Quality
|
||||||
|
|
||||||
|
1. **No warnings.** All code must compile with zero warnings. CI treats warnings as errors (`-D warnings`).
|
||||||
|
2. **Format before commit.** Run `cargo fmt` — CI checks formatting.
|
||||||
|
3. **Clippy clean.** Run `cargo clippy -- -D warnings` — CI checks lints.
|
||||||
|
4. **Tests required.** Every new module/function must have unit tests. Public API changes require integration tests.
|
||||||
|
5. **Doc comments.** All public items (`pub fn`, `pub struct`, `pub enum`) must have `///` doc comments.
|
||||||
|
|
||||||
|
### Git Workflow
|
||||||
|
|
||||||
|
1. **Branch naming**: `<type>/<short-description>`
|
||||||
|
- `feat/dns-cache`, `fix/ttl-overflow`, `docs/readme`, `chore/ci-update`
|
||||||
|
2. **Commit messages**: Conventional Commits format
|
||||||
|
- `feat: add DNS response cache`
|
||||||
|
- `fix: handle truncated UDP responses`
|
||||||
|
- `docs: update plan.md`
|
||||||
|
3. **PR required.** All changes go through a pull request. No direct pushes to `main`.
|
||||||
|
4. **Squash merge.** PRs are squash-merged into `main`.
|
||||||
|
5. **CI must pass.** Lint, test, and build must succeed before merge.
|
||||||
|
|
||||||
|
### Architecture Rules
|
||||||
|
|
||||||
|
1. **No panics in production code.** Use `Result<T, E>` everywhere. `unwrap()` only in tests.
|
||||||
|
2. **Structured errors.** Define error types per module using `thiserror`. Use `anyhow` only in `main.rs`.
|
||||||
|
3. **Async everywhere.** All I/O is async (Tokio). No blocking calls in async context.
|
||||||
|
4. **Config-driven.** No hardcoded values. All tunables come from config file or env vars.
|
||||||
|
5. **Dependency injection.** Accept traits, not concrete types. Makes testing easy.
|
||||||
|
|
||||||
|
### Testing Rules
|
||||||
|
|
||||||
|
1. **Unit tests** in the same file (`#[cfg(test)] mod tests { ... }`).
|
||||||
|
2. **Integration tests** in `tests/` directory.
|
||||||
|
3. **Test naming**: `test_<what>_<condition>_<expected>` — e.g., `test_cache_expired_entry_returns_miss`.
|
||||||
|
4. **No external dependencies in unit tests.** Mock upstream resolvers.
|
||||||
|
5. **Integration tests** may spin up the full server on a random port.
|
||||||
|
|
||||||
|
### Security Rules
|
||||||
|
|
||||||
|
1. **No secrets in code.** Use env vars or config files (gitignored).
|
||||||
|
2. **Validate all input.** DNS queries from the network are untrusted — validate lengths, offsets, labels.
|
||||||
|
3. **Timeouts on all upstream calls.** Never hang indefinitely.
|
||||||
|
4. **Rate limiting.** Protect against abuse from a single IP.
|
||||||
|
5. **Dependency audit.** Run `cargo audit` in CI.
|
||||||
|
|
||||||
|
### Commit Checklist
|
||||||
|
|
||||||
|
Before pushing, verify:
|
||||||
|
|
||||||
|
- [ ] `cargo fmt --check` passes
|
||||||
|
- [ ] `cargo clippy -- -D warnings` passes
|
||||||
|
- [ ] `cargo test` passes
|
||||||
|
- [ ] New code has tests
|
||||||
|
- [ ] Public items have doc comments
|
||||||
|
- [ ] No `unwrap()` outside of tests
|
||||||
|
- [ ] Config values are externalized (not hardcoded)
|
||||||
|
|
||||||
|
## Milestone Tracking
|
||||||
|
|
||||||
|
See [docs/plan.md](docs/plan.md) for the full project plan and milestone checklist.
|
||||||
|
|
||||||
|
| Milestone | Status |
|
||||||
|
|-----------|--------|
|
||||||
|
| M1 — Core Forwarding | 🔲 Not started |
|
||||||
|
| M2 — Multiple Upstreams & Config | 🔲 Not started |
|
||||||
|
| M3 — Caching | 🔲 Not started |
|
||||||
|
| M4 — Observability | 🔲 Not started |
|
||||||
|
| M5 — Blocking & Filtering | 🔲 Not started |
|
||||||
|
| M6 — Production Hardening | 🔲 Not started |
|
||||||
|
|
||||||
|
## Useful Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Build release binary
|
||||||
|
cargo build --release
|
||||||
|
|
||||||
|
# Run with specific log level
|
||||||
|
RUST_LOG=debug cargo run
|
||||||
|
|
||||||
|
# Generate and open docs
|
||||||
|
cargo doc --open
|
||||||
|
|
||||||
|
# Dependency audit
|
||||||
|
cargo install cargo-audit
|
||||||
|
cargo audit
|
||||||
|
|
||||||
|
# Watch tests
|
||||||
|
cargo watch -x test
|
||||||
|
```
|
||||||
118
docs/plan.md
Normal file
118
docs/plan.md
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
# 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
|
||||||
Reference in New Issue
Block a user