Files
smartdns/ts_server/readme.md

111 lines
3.9 KiB
Markdown

# @push.rocks/smartdns/server
DNS server module for `@push.rocks/smartdns` — a full-featured authoritative DNS server powered by a Rust backend with DNSSEC, DNS-over-HTTPS, and Let's Encrypt integration.
## Import
```typescript
import { DnsServer } from '@push.rocks/smartdns/server';
```
## Architecture
The server delegates network I/O, DNS packet parsing/encoding, and DNSSEC signing to a compiled **Rust binary** (`rustdns`). TypeScript retains the public API, handler registration, and ACME certificate orchestration.
Communication happens via JSON-over-stdin/stdout IPC using `@push.rocks/smartrust`'s `RustBridge`. DNS queries that need handler resolution are forwarded from Rust to TypeScript with correlation IDs, then results are sent back for response assembly and DNSSEC signing.
### Rust Crate Structure
| Crate | Purpose |
|---|---|
| `rustdns` | Main binary with IPC management loop |
| `rustdns-protocol` | DNS wire format parsing/encoding, RDATA encode/decode |
| `rustdns-server` | Async UDP + HTTPS servers (tokio, hyper, rustls) |
| `rustdns-dnssec` | ECDSA/ED25519 key generation and RRset signing |
## Classes
### `DnsServer`
The primary class. Manages handler registration, server lifecycle, and certificate retrieval.
```typescript
const server = new DnsServer({
udpPort: 53,
httpsPort: 443,
httpsKey: '...pem...',
httpsCert: '...pem...',
dnssecZone: 'example.com',
primaryNameserver: 'ns1.example.com',
});
```
#### Options
| Option | Type | Default | Description |
|---|---|---|---|
| `udpPort` | `number` | — | UDP DNS port |
| `httpsPort` | `number` | — | HTTPS DoH port |
| `httpsKey` | `string` | — | TLS private key (PEM) |
| `httpsCert` | `string` | — | TLS certificate (PEM) |
| `dnssecZone` | `string` | — | Zone to enable DNSSEC for |
| `primaryNameserver` | `string` | `ns1.{zone}` | SOA mname field |
| `udpBindInterface` | `string` | `0.0.0.0` | IP to bind UDP |
| `httpsBindInterface` | `string` | `0.0.0.0` | IP to bind HTTPS |
| `manualUdpMode` | `boolean` | `false` | Don't auto-bind UDP |
| `manualHttpsMode` | `boolean` | `false` | Don't auto-bind HTTPS |
| `enableLocalhostHandling` | `boolean` | `true` | Handle RFC 6761 localhost |
#### Key Methods
| Method | Description |
|---|---|
| `start()` | Spawn Rust binary and start listening |
| `stop()` | Gracefully shut down |
| `registerHandler(pattern, types, fn)` | Add a DNS handler (glob patterns via minimatch) |
| `unregisterHandler(pattern, types)` | Remove a handler |
| `handleUdpMessage(msg, rinfo, cb)` | Process a UDP message manually |
| `processRawDnsPacket(buf)` | Sync packet processing (TS fallback) |
| `processRawDnsPacketAsync(buf)` | Async packet processing (Rust bridge, includes DNSSEC) |
| `retrieveSslCertificate(domains, opts)` | ACME DNS-01 certificate retrieval |
| `filterAuthorizedDomains(domains)` | Filter domains the server is authoritative for |
### `RustDnsBridge`
Low-level IPC bridge to the `rustdns` binary. Used internally by `DnsServer` — typically not imported directly.
Emits events: `dnsQuery`, `started`, `stopped`, `error`.
## Handler System
Handlers use **glob patterns** (via `minimatch`) for domain matching. Multiple handlers can contribute records to a single response.
```typescript
server.registerHandler('*.example.com', ['A'], (question) => ({
name: question.name,
type: 'A',
class: 'IN',
ttl: 300,
data: '10.0.0.1',
}));
```
When no handler matches, the server returns an automatic **SOA record** for the zone.
## DNSSEC
Enabled automatically with the `dnssecZone` option. Supports:
- **ECDSAP256SHA256** (13) — default
- **ED25519** (15)
- **RSASHA256** (8)
Key generation, DNSKEY/RRSIG/NSEC record creation is fully handled by the Rust backend.
## Dependencies
- `@push.rocks/smartrust` — TypeScript-to-Rust IPC bridge
- `dns-packet` — DNS wire format codec (used for TS fallback path)
- `minimatch` — glob pattern matching for handlers
- `acme-client` — Let's Encrypt ACME protocol