docs: add README with usage, config, and API reference
This commit is contained in:
160
README.md
Normal file
160
README.md
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
# doh-forwarder
|
||||||
|
|
||||||
|
A lightweight DNS-over-HTTPS (DoH) forwarder written in Rust.
|
||||||
|
|
||||||
|
Accepts DNS queries over HTTPS ([RFC 8484](https://www.rfc-editor.org/rfc/rfc8484)) 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 endpoint** — `GET /health`
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 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](config/default.toml)):
|
||||||
|
|
||||||
|
```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.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
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
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 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](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
|
||||||
Reference in New Issue
Block a user