rdns-server 1.17.11

A high-performance, security-focused DNS server written in Rust
# rDNS — Rust DNS Server Architecture Plan

A high-performance, security-focused DNS server written in Rust. Supports recursive resolution, authoritative serving, DNS-over-TLS, DNSSEC validation, and RPZ filtering. Cross-platform (FreeBSD + Linux), scales from home use to ISP/enterprise.

## Architecture Overview

```
┌─────────────────────────────────────────────────────────────┐
│                        rDNS Server                          │
│                                                             │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌───────────┐  │
│  │ UDP/TCP  │  │ DNS-over- │  │ Control  │  │Prometheus │  │
│  │ Listener │  │   TLS     │  │  Socket  │  │ /metrics  │  │
│  │ :53      │  │  :853     │  │  (unix)  │  │ :9153     │  │
│  └────┬─────┘  └────┬─────┘  └────┬─────┘  └───────────┘  │
│       │              │             │                         │
│       └──────┬───────┘             │                         │
│              ▼                     ▼                         │
│  ┌───────────────────┐  ┌──────────────────┐               │
│  │   Query Router    │  │  Control Handler │               │
│  │  (auth/recurse?)  │  │  (reload/flush)  │               │
│  └─────┬───────┬─────┘  └──────────────────┘               │
│        │       │                                            │
│   ┌────▼──┐ ┌──▼──────────┐                                │
│   │ Auth  │ │  Recursive   │                                │
│   │Engine │ │  Resolver    │                                │
│   └───┬───┘ └──────┬──────┘                                │
│       │            │                                        │
│  ┌────▼────────────▼────┐                                  │
│  │   Response Cache     │                                  │
│  │  (sharded, TTL-based)│                                  │
│  └──────────────────────┘                                  │
│                                                             │
│  ┌──────────────────────┐  ┌───────────────┐               │
│  │   Zone Store         │  │  RPZ Engine   │               │
│  │  (memory-resident)   │  │  (filter)     │               │
│  └─────┬──────┬─────────┘  └───────────────┘               │
│        │      │                                             │
│   ┌────▼──┐ ┌─▼──────────┐                                │
│   │ Zone  │ │ PostgreSQL  │                                │
│   │ Files │ │ (optional)  │                                │
│   └───────┘ └─────────────┘                                │
└─────────────────────────────────────────────────────────────┘
```

## Core Design Decisions

- **Async runtime**: Tokio multi-threaded
- **Cache**: Sharded concurrent hashmap (dashmap or custom), TTL-evicted
- **Zone storage**: In-memory tree, loaded from zone files or PostgreSQL
- **Config**: TOML (server config), RFC 1035 zone files (zone data)
- **Control**: Unix domain socket + `rdns-control` CLI tool
- **Metrics**: Prometheus HTTP endpoint on configurable port
- **Security**: Privilege drop after bind, Capsicum on FreeBSD, DNSSEC validation
- **License**: MIT

## Crate Dependencies (planned)

| Crate | Purpose |
|-------|---------|
| `tokio` | Async runtime |
| `tokio-rustls` / `rustls` | TLS (no OpenSSL dependency) |
| `bytes` | Efficient buffer management |
| `dashmap` | Sharded concurrent hashmap for cache |
| `serde` / `toml` | Config parsing |
| `tracing` | Structured logging |
| `metrics` + `metrics-exporter-prometheus` | Prometheus metrics |
| `sqlx` | PostgreSQL (optional feature) |
| `ring` | Crypto for DNSSEC |
| `clap` | CLI argument parsing |
| `nix` | Unix privilege dropping, socket control |
| `capsicum` | FreeBSD Capsicum sandboxing (conditional) |

## Project Structure

```
rdns/
├── Cargo.toml
├── Cargo.lock
├── rdns.toml.example          # Example config
├── src/
│   ├── main.rs                # Entry point, signal handling
│   ├── config.rs              # TOML config parsing
│   ├── server.rs              # Server orchestration
│   ├── listener/
│   │   ├── mod.rs
│   │   ├── udp.rs             # UDP listener
│   │   ├── tcp.rs             # TCP listener
│   │   └── tls.rs             # DNS-over-TLS listener
│   ├── protocol/
│   │   ├── mod.rs
│   │   ├── header.rs          # DNS header parsing
│   │   ├── message.rs         # Full message encode/decode
│   │   ├── name.rs            # Domain name compression
│   │   ├── record.rs          # Resource record types
│   │   ├── rdata.rs           # RDATA parsing per type
│   │   ├── opcode.rs          # DNS opcodes
│   │   └── rcode.rs           # Response codes
│   ├── resolver/
│   │   ├── mod.rs
│   │   ├── recursive.rs       # Recursive resolution engine
│   │   ├── forwarder.rs       # Forwarding mode
│   │   └── iterator.rs        # Iterative query logic
│   ├── auth/
│   │   ├── mod.rs
│   │   ├── engine.rs          # Authoritative lookup engine
│   │   ├── zone.rs            # Zone data structures
│   │   ├── zone_tree.rs       # In-memory zone tree
│   │   ├── zone_parser.rs     # RFC 1035 zone file parser
│   │   └── catalog.rs         # Zone catalog (manages all zones)
│   ├── cache/
│   │   ├── mod.rs
│   │   ├── entry.rs           # Cache entry with TTL
│   │   └── store.rs           # Sharded cache store
│   ├── dnssec/
│   │   ├── mod.rs
│   │   ├── validator.rs       # DNSSEC chain validation
│   │   ├── algorithms.rs      # Signing algorithm support
│   │   └── trust_anchor.rs    # Root trust anchors
│   ├── rpz/
│   │   ├── mod.rs
│   │   ├── engine.rs          # RPZ matching engine
│   │   └── policy.rs          # Policy actions
│   ├── control/
│   │   ├── mod.rs
│   │   └── handler.rs         # Unix socket command handler
│   ├── metrics.rs             # Prometheus metrics
│   └── security/
│       ├── mod.rs
│       ├── privilege.rs       # Privilege dropping
│       └── sandbox.rs         # Capsicum / platform sandboxing
├── src/bin/
│   └── rdns-control.rs        # Control CLI binary
├── tests/
│   ├── protocol_tests.rs
│   ├── cache_tests.rs
│   ├── resolver_tests.rs
│   └── auth_tests.rs
└── zones/
    └── example.com.zone       # Example zone file
```

## Implementation Phases

### Phase 1: Foundation — Protocol & Transport
> Goal: Parse and respond to DNS queries over UDP/TCP

- [x] 1.1 — Project scaffold (Cargo.toml, module structure, config skeleton)
- [x] 1.2 — DNS protocol wire format (header, message, name compression, encode/decode)
- [x] 1.3 — Resource record types (A, AAAA, NS, CNAME, MX, TXT, SOA, PTR, SRV, CAA)
- [x] 1.4 — UDP listener (bind :53, receive query, parse, echo back SERVFAIL)
- [x] 1.5 — TCP listener (length-prefixed framing, same query handling)
- [x] 1.6 — Unit tests for protocol parsing (known-good packets)

### Phase 2: Caching Layer
> Goal: Sharded concurrent cache with TTL eviction

- [x] 2.1 — Cache entry struct (response data, TTL, insertion time, access count)
- [x] 2.2 — Sharded cache store (dashmap-based, configurable size)
- [x] 2.3 — TTL expiration (background sweep task, lazy eviction on access)
- [x] 2.4 — Cache lookup integration with listeners (check cache before processing)
- [x] 2.5 — Negative caching (NXDOMAIN, NODATA per RFC 2308)
- [x] 2.6 — Cache tests

### Phase 3: Recursive Resolver
> Goal: Full recursive resolution from root hints

- [x] 3.1 — Root hints loader (built-in root server addresses)
- [x] 3.2 — Iterative resolution engine (follow referrals from root → TLD → auth)
- [x] 3.3 — CNAME/DNAME chain following
- [x] 3.4 — Forwarder mode (forward to upstream resolvers, cache responses)
- [x] 3.5 — Query deduplication (coalesce identical in-flight queries)
- [x] 3.6 — Retry logic with timeout (configurable per-server timeout, fallback)
- [x] 3.7 — Resolver integration tests

### Phase 4: Authoritative Engine
> Goal: Serve zones from zone files loaded into memory

- [x] 4.1 — Zone data structures (zone tree, node, RRset)
- [x] 4.2 — RFC 1035 zone file parser ($ORIGIN, $TTL, $INCLUDE, RR entries)
- [x] 4.3 — Zone catalog (load/reload/remove zones)
- [x] 4.4 — Authoritative query engine (exact match, wildcard, delegation, NXDOMAIN)
- [x] 4.5 — Query router (determine if query is auth or recursive, route accordingly)
- [x] 4.6 — AXFR/IXFR zone transfer (secondary support)
- [x] 4.7 — NOTIFY handling (trigger reload on primary change)
- [x] 4.8 — Authoritative tests with sample zones

### Phase 5: DNSSEC Validation
> Goal: Full DNSSEC validation for recursive responses

- [x] 5.1 — Trust anchor management (built-in root KSK, RFC 5011 auto-update)
- [x] 5.2 — DS/DNSKEY/RRSIG record parsing and wire format
- [x] 5.3 — Signature validation (RSA/SHA-256, ECDSA P-256, Ed25519)
- [x] 5.4 — Chain of trust validation (root → TLD → zone)
- [x] 5.5 — NSEC/NSEC3 denial of existence validation
- [x] 5.6 — Set CD/AD bits correctly in responses
- [x] 5.7 — DNSSEC tests with known-good and known-bad chains

### Phase 6: DNS-over-TLS
> Goal: Serve DNS queries over TLS (RFC 7858)

- [x] 6.1 — TLS listener on :853 (rustls, configurable cert/key)
- [x] 6.2 — Connection handling (persistent connections, idle timeout)
- [x] 6.3 — Upstream DoT support (resolver can query upstream over TLS)
- [x] 6.4 — TLS session resumption for performance
- [x] 6.5 — TLS integration tests

### Phase 7: RPZ (Response Policy Zones)
> Goal: Filter/block queries based on RPZ rules

- [x] 7.1 — RPZ zone parser (load RPZ zone files)
- [x] 7.2 — RPZ matching engine (qname, IP, nsdname triggers)
- [x] 7.3 — Policy actions (NXDOMAIN, NODATA, passthru, local-data, redirect)
- [x] 7.4 — RPZ zone refresh (periodic re-fetch via AXFR/HTTP)
- [x] 7.5 — RPZ tests

### Phase 8: Control Interface & Metrics
> Goal: Runtime management and observability

- [x] 8.1 — Unix domain socket listener for control commands
- [x] 8.2 — Control protocol (simple text commands: stats, flush, reload, dump)
- [x] 8.3 — `rdns-control` CLI binary
- [x] 8.4 — Prometheus metrics endpoint (/metrics on configurable port)
- [x] 8.5 — Key metrics: QPS, cache hit/miss ratio, latency histograms, upstream errors
- [x] 8.6 — Structured logging with tracing (JSON + syslog output)

### Phase 9: Security Hardening
> Goal: Privilege separation and platform sandboxing

- [x] 9.1 — Privilege dropping (bind ports as root, drop to rdns user)
- [x] 9.2 — FreeBSD Capsicum sandboxing (enter capability mode after init)
- [x] 9.3 — Linux seccomp-bpf filtering (restrict syscalls)
- [x] 9.4 — Chroot / filesystem isolation
- [x] 9.5 — Source port randomization + 0x20 encoding (anti-spoofing)
- [x] 9.6 — Rate limiting (per-source query rate limits)

### Phase 10: PostgreSQL Backend
> Goal: Database-backed zone storage for large-scale deployments

- [x] 10.1 — Database schema (zones, records, metadata tables)
- [x] 10.2 — SQLx integration (connection pool, async queries)
- [x] 10.3 — Zone loader from DB (startup full load, single-zone reload)
- [x] 10.4 — Postgres LISTEN/NOTIFY for change detection
- [x] 10.5 — Migration tooling (sqlx migrations)
- [x] 10.6 — DB backend tests

### Phase 11: Packaging & Distribution
> Goal: Ready for production deployment

- [x] 11.1 — FreeBSD rc.d service script
- [x] 11.2 — Linux systemd unit file
- [x] 11.3 — FreeBSD port Makefile
- [x] 11.4 — Docker image
- [x] 11.5 — Man pages (rdns.8, rdns-control.8, rdns.toml.5)
- [x] 11.6 — Performance benchmarks (dnsperf / queryperf)
- [x] 11.7 — README with quick-start guide

## Config Example (rdns.toml)

```toml
[server]
# "resolver" | "authoritative" | "both"
mode = "both"
user = "rdns"
group = "rdns"
pidfile = "/var/run/rdns/rdns.pid"

[listeners]
# Plain DNS
udp = ["0.0.0.0:53", "[::]:53"]
tcp = ["0.0.0.0:53", "[::]:53"]

# DNS-over-TLS
[listeners.tls]
addresses = ["0.0.0.0:853", "[::]:853"]
cert = "/etc/rdns/tls/cert.pem"
key = "/etc/rdns/tls/key.pem"

[cache]
max_entries = 1_000_000
max_ttl = 86400        # cap TTL at 24h
min_ttl = 60           # floor TTL at 60s
negative_ttl = 300     # NXDOMAIN cache time

[resolver]
# Empty = full recursive from root hints
forwarders = []
# forwarders = ["1.1.1.1:853@tls", "8.8.8.8"]
dnssec = true
qname_minimization = true
max_recursion_depth = 30

[authoritative]
# "zone-files" | "database" | "none"
source = "zone-files"
directory = "/etc/rdns/zones"

# [authoritative.database]
# connection = "postgresql://rdns:password@localhost:5432/rdns"

[rpz]
zones = [
    { name = "rpz.example.com", file = "/etc/rdns/rpz/blocklist.rpz" },
]

[control]
socket = "/var/run/rdns/control.sock"

[metrics]
enabled = true
address = "127.0.0.1:9153"

[logging]
level = "info"         # trace, debug, info, warn, error
format = "json"        # "json" | "syslog" | "text"

[security]
sandbox = true         # Capsicum on FreeBSD, seccomp on Linux
rate_limit = 1000      # queries per second per source IP
```