refactor to async tokio with modular architecture
- Replace synchronous std::net::UdpSocket with tokio async runtime - Spawn concurrent task per incoming DNS query via tokio::spawn - Extract monolithic main.rs into modules: buffer, header, question, record, packet, config, cache, forward, stats - Share state across tasks via Arc<ServerCtx> with scoped Mutex locks - Add TOML config loading, TTL-aware cache, structured logging, stats - Add CLAUDE.md, README, dns_fun.toml config, and design docs Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
121
README.md
121
README.md
@@ -1 +1,122 @@
|
||||
# dns_fun
|
||||
|
||||
A DNS forwarding/caching proxy written from scratch in Rust. Parses and serializes DNS wire protocol (RFC 1035), serves local zone records from TOML config, caches upstream responses with TTL-aware expiration, and logs every query with structured output.
|
||||
|
||||
No async runtime, no DNS libraries — just `std::net::UdpSocket` and manual packet parsing.
|
||||
|
||||
## Record Types
|
||||
|
||||
A, NS, CNAME, MX, AAAA
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
# Run with default config (dns_fun.toml)
|
||||
sudo cargo run
|
||||
|
||||
# Run with custom config path
|
||||
sudo cargo run -- path/to/config.toml
|
||||
|
||||
# Test
|
||||
dig @127.0.0.1 google.com
|
||||
dig @127.0.0.1 mysite.local
|
||||
```
|
||||
|
||||
Requires root/sudo for binding to port 53.
|
||||
|
||||
## Configuration
|
||||
|
||||
Edit `dns_fun.toml`:
|
||||
|
||||
```toml
|
||||
[server]
|
||||
bind_addr = "0.0.0.0:53"
|
||||
|
||||
[upstream]
|
||||
address = "8.8.8.8"
|
||||
port = 53
|
||||
timeout_ms = 3000
|
||||
|
||||
[cache]
|
||||
max_entries = 10000
|
||||
min_ttl = 60 # floor: cache at least 60s
|
||||
max_ttl = 86400 # ceiling: never cache longer than 24h
|
||||
|
||||
[[zones]]
|
||||
domain = "mysite.local"
|
||||
record_type = "A"
|
||||
value = "127.0.0.1"
|
||||
ttl = 60
|
||||
|
||||
[[zones]]
|
||||
domain = "other.local"
|
||||
record_type = "AAAA"
|
||||
value = "::1"
|
||||
ttl = 120
|
||||
```
|
||||
|
||||
All sections are optional — sensible defaults are used if the config file is missing.
|
||||
|
||||
## Request Pipeline
|
||||
|
||||
```
|
||||
Query -> Parse -> Local Zones -> Cache -> Upstream Forward -> Respond
|
||||
```
|
||||
|
||||
1. **Local zones** — match against records defined in `[[zones]]`, respond immediately
|
||||
2. **Cache** — return TTL-adjusted cached response if available
|
||||
3. **Forward** — send query to upstream resolver, cache the response
|
||||
4. **SERVFAIL** — returned to client on upstream failure
|
||||
|
||||
## Caching
|
||||
|
||||
- TTL derived from minimum TTL across answer records
|
||||
- Clamped to configured `min_ttl`/`max_ttl` bounds
|
||||
- TTLs in cached responses decrease over time (adjusted on serve)
|
||||
- Lazy eviction on capacity overflow + periodic sweep every 1000 queries
|
||||
|
||||
## Logging
|
||||
|
||||
Controlled via `RUST_LOG` environment variable:
|
||||
|
||||
```bash
|
||||
RUST_LOG=info sudo cargo run # default — one line per query
|
||||
RUST_LOG=debug sudo cargo run # includes response details
|
||||
RUST_LOG=warn sudo cargo run # errors only
|
||||
```
|
||||
|
||||
Log output:
|
||||
|
||||
```
|
||||
2026-03-10T14:23:01.123Z INFO 192.168.1.5:41234 | A google.com | FORWARD | NOERROR | 12ms
|
||||
2026-03-10T14:23:01.456Z INFO 192.168.1.5:41235 | A mysite.local | LOCAL | NOERROR | 0ms
|
||||
2026-03-10T14:23:02.789Z INFO 192.168.1.5:41236 | A google.com | CACHED | NOERROR | 0ms
|
||||
```
|
||||
|
||||
Stats summary (total, forwarded, cached, local, blocked, errors) logged every 1000 queries.
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
src/
|
||||
main.rs # startup, config load, UDP listen loop, request pipeline
|
||||
lib.rs # module declarations, Error/Result type aliases
|
||||
buffer.rs # BytePacketBuffer — 512-byte DNS wire format read/write
|
||||
header.rs # DnsHeader, ResultCode
|
||||
question.rs # DnsQuestion, QueryType
|
||||
record.rs # DnsRecord (A, NS, CNAME, MX, AAAA, UNKNOWN)
|
||||
packet.rs # DnsPacket — full DNS message parse/serialize
|
||||
config.rs # TOML config loading, zone map builder
|
||||
cache.rs # TTL-aware DNS response cache with lazy eviction
|
||||
forward.rs # upstream forwarding, SERVFAIL builder
|
||||
stats.rs # query counters and periodic summary
|
||||
```
|
||||
|
||||
## Dependencies
|
||||
|
||||
```toml
|
||||
toml = "0.8"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
log = "0.4"
|
||||
env_logger = "0.11"
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user