- plan.md: architecture flow diagram - README.md: simple forwarder overview diagram - story.md: DNS censorship and SOCKS5 proxy diagrams - intra-comparison.md: all ASCII diagrams converted to Mermaid
164 lines
4.5 KiB
Markdown
164 lines
4.5 KiB
Markdown
# doh-forwarder
|
|
|
|
A lightweight DNS-over-HTTPS (DoH) forwarder written in Rust.
|
|
|
|
Accepts DNS queries over traditional DNS (UDP/TCP) and HTTP DoH ([RFC 8484](https://www.rfc-editor.org/rfc/rfc8484)), then forwards them upstream via DoH (HTTPS POST) to configurable resolvers.
|
|
|
|
```mermaid
|
|
flowchart LR
|
|
client["DNS Client"] -- "UDP/TCP or HTTPS" --> forwarder["doh-forwarder"]
|
|
forwarder -- "HTTPS POST (DoH)" --> upstream["Upstream Resolvers\n(Cloudflare, Google, ...)"]
|
|
upstream -- "DNS response" --> forwarder
|
|
forwarder -- "DNS response" --> client
|
|
```
|
|
|
|
## Why?
|
|
|
|
See [docs/story.md](docs/story.md) for the full context — why this exists, what already works, and where this project is headed.
|
|
|
|
## Features
|
|
|
|
- **Dual-protocol listener** — traditional DNS (UDP/TCP) + HTTP DoH endpoints
|
|
- **RFC 8484 compliant** — GET (`?dns=base64url`) and POST (`application/dns-message`)
|
|
- **Multiple upstreams** — configure several DoH resolvers
|
|
- **Selection strategies** — round-robin or failover with automatic retry
|
|
- **Environment overrides** — override config via env vars
|
|
- **Graceful shutdown** — handles SIGINT and SIGTERM
|
|
- **Health endpoint** — `GET /health`
|
|
|
|
## Quick Start
|
|
|
|
```bash
|
|
# Build
|
|
cargo build --release
|
|
|
|
# Run with default config (DoH on :8800, DNS on :53530)
|
|
./target/release/doh-forwarder
|
|
|
|
# Run with a custom config
|
|
./target/release/doh-forwarder --config /path/to/config.toml
|
|
```
|
|
|
|
## Configuration
|
|
|
|
See [config/default.toml](config/default.toml):
|
|
|
|
```toml
|
|
[server]
|
|
listen = "0.0.0.0:8800"
|
|
|
|
[dns]
|
|
listen = "0.0.0.0:53530"
|
|
|
|
[upstream]
|
|
resolvers = [
|
|
{ name = "cloudflare", url = "https://cloudflare-dns.com/dns-query" },
|
|
]
|
|
strategy = "round-robin" # or "failover"
|
|
```
|
|
|
|
### Environment Variable Overrides
|
|
|
|
| Variable | Description | Example |
|
|
|---|---|---|
|
|
| `DOH_LISTEN` | Override DoH 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` |
|
|
|
|
## Usage
|
|
|
|
### Point your system DNS at the forwarder
|
|
|
|
```bash
|
|
# /etc/resolv.conf
|
|
nameserver 127.0.0.1
|
|
# Then run the forwarder with [dns] listen = "127.0.0.1:53"
|
|
```
|
|
|
|
Or use `resolvectl` with systemd-resolved:
|
|
|
|
```bash
|
|
resolvectl dns eth0 127.0.0.1
|
|
resolvectl dns-over-tls no # we handle encryption upstream
|
|
```
|
|
|
|
### DoH API
|
|
|
|
**POST `/dns-query`** — raw DNS wire-format in body:
|
|
|
|
```bash
|
|
curl -X POST http://localhost:8800/dns-query \
|
|
-H "Content-Type: application/dns-message" \
|
|
-H "Accept: application/dns-message" \
|
|
--data-binary @query.bin
|
|
```
|
|
|
|
**GET `/dns-query`** — base64url-encoded query parameter:
|
|
|
|
```bash
|
|
curl "http://localhost:8800/dns-query?dns=<base64url-encoded-query>"
|
|
```
|
|
|
|
**GET `/health`** — returns `ok`:
|
|
|
|
```bash
|
|
curl http://localhost:8800/health
|
|
```
|
|
|
|
### Upstream Strategies
|
|
|
|
| Strategy | Behavior |
|
|
|---|---|
|
|
| `round-robin` | Distributes queries across resolvers in rotation |
|
|
| `failover` | Tries resolvers in order; moves to the next on failure |
|
|
|
|
## Project Structure
|
|
|
|
```
|
|
doh-forwarder/
|
|
├── Cargo.toml
|
|
├── config/
|
|
│ └── default.toml # Default configuration
|
|
├── docs/
|
|
│ ├── plan.md # Project plan & milestones
|
|
│ └── story.md # Why this project exists
|
|
├── src/
|
|
│ ├── main.rs # Entrypoint, server setup, graceful shutdown
|
|
│ ├── lib.rs # Public API re-exports
|
|
│ ├── config.rs # TOML config + env overrides
|
|
│ ├── routes.rs # HTTP route handlers (/dns-query, /health)
|
|
│ ├── dns/
|
|
│ │ ├── mod.rs
|
|
│ │ ├── query.rs # DNS query parsing
|
|
│ │ ├── response.rs # DNS response building (SERVFAIL)
|
|
│ │ └── listener.rs # UDP/TCP DNS listener
|
|
│ └── upstream/
|
|
│ ├── mod.rs
|
|
│ └── doh_client.rs # DoH forwarding client (retry, strategies)
|
|
├── tests/
|
|
│ └── integration.rs # HTTP integration tests
|
|
└── DEVELOP.md # Development rules & milestone tracking
|
|
```
|
|
|
|
## Development
|
|
|
|
See [DEVELOP.md](DEVELOP.md) for development rules, coding standards, and milestone tracking.
|
|
|
|
```bash
|
|
# 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
|
|
```
|
|
|
|
## License
|
|
|
|
MIT
|