# smartdns - Implementation Hints

## Architecture Overview

The smartdns library is structured into three main modules:

1. **Client Module** (`ts_client/`) - DNS client functionality
2. **Server Module** (`ts_server/`) - DNS server with Rust backend
3. **Main Module** (`ts/`) - Re-exports both client and server
4. **Rust Module** (`rust/`) - High-performance DNS server binary

## Rust Backend Architecture (v8.0+)

The DNS server's network I/O, packet parsing/encoding, and DNSSEC signing run in Rust.
TypeScript retains handler registration, ACME orchestration, and the public API.

### Rust Crate Structure
- `rustdns` - Main binary with IPC management loop (`--management` flag)
- `rustdns-protocol` - DNS wire format parsing/encoding, record types
- `rustdns-server` - Async UDP + HTTPS DoH servers (tokio, hyper, rustls)
- `rustdns-dnssec` - ECDSA P-256 / ED25519 key generation and RRset signing

### IPC Flow
```
DNS Query -> Rust (UDP/HTTPS) -> Parse packet
  -> Try local resolution (localhost, DNSKEY)
  -> If handler needed: emit "dnsQuery" event to TypeScript
  -> TypeScript runs minimatch handlers, sends "dnsQueryResult" back
  -> Rust builds response, signs DNSSEC if requested, sends packet
```

### Key Files
- `ts_server/classes.rustdnsbridge.ts` - TypeScript IPC bridge wrapping smartrust.RustBridge
- `ts_server/classes.dnsserver.ts` - DnsServer class (public API, delegates to Rust bridge)
- `rust/crates/rustdns/src/management.rs` - IPC management loop
- `rust/crates/rustdns/src/resolver.rs` - DNS resolver with callback support

## Client Module (Smartdns class)

### Key Features:
- DNS record queries (A, AAAA, TXT, MX, etc.)
- Support for multiple DNS providers (Google DNS, Cloudflare)
- DNS propagation checking with retry logic
- DNSSEC verification support
- Both HTTP-based (DoH) and Node.js DNS resolver fallback

### Implementation Details:
- Uses Cloudflare's DNS-over-HTTPS API as primary resolver
- Falls back to Node.js DNS module for local resolution
- Implements automatic retry logic with configurable intervals
- Properly handles quoted TXT records and trailing dots in domain names

### Key Methods:
- `getRecordsA()`, `getRecordsAAAA()`, `getRecordsTxt()` - Type-specific queries
- `getRecords()` - Generic record query with retry support
- `checkUntilAvailable()` - DNS propagation verification
- `getNameServers()` - NS record lookup
- `makeNodeProcessUseDnsProvider()` - Configure system DNS resolver

## Server Module (DnsServer class)

### Key Features:
- Full DNS server supporting UDP and HTTPS (DoH) protocols
- DNSSEC implementation with multiple algorithms
- Dynamic handler registration for custom responses
- Let's Encrypt integration for automatic SSL certificates
- Wildcard domain support with pattern matching

### DNSSEC Implementation:
- Supports ECDSA (algorithm 13), ED25519 (algorithm 15), and RSA (algorithm 8)
- Automatic DNSKEY and DS record generation
- RRSIG signature generation for authenticated responses
- Key tag computation following RFC 4034

### Let's Encrypt Integration:
- Automatic SSL certificate retrieval using DNS-01 challenges
- Dynamic TXT record handler registration for ACME validation
- Certificate renewal and HTTPS server restart capability
- Domain authorization filtering for security

### Handler System:
- Pattern-based domain matching using minimatch
- Support for all common record types
- **Multiple Handler Support**: As of v7.4.2+, multiple handlers can contribute records of the same type
- Handler chaining for complex scenarios
- Automatic SOA response for unhandled queries

### Multiple Records Support (v7.4.2+):
- Server now processes ALL matching handlers for a query (previously stopped after first match)
- Enables proper multi-NS record support for domain registration
- Supports round-robin DNS with multiple A/AAAA records
- Allows multiple TXT records (SPF, DKIM, domain verification)
- Each handler contributes its record to the response

## Key Dependencies

- `dns-packet`: DNS packet encoding/decoding (wire format, used by TS fallback path)
- `acme-client`: Let's Encrypt certificate automation
- `minimatch`: Glob pattern matching for domains
- `@push.rocks/smartrust`: TypeScript-to-Rust IPC bridge
- `@tsclass/tsclass`: Type definitions for DNS records

## Testing Insights

The test suite demonstrates:
- Mock ACME client for testing Let's Encrypt integration
- Self-signed certificate generation for HTTPS testing
- Unique port allocation to avoid conflicts
- Proper server cleanup between tests
- Both UDP and HTTPS query validation

## Common Patterns

1. **DNS Record Types**: Internally mapped to numeric values (A=1, AAAA=28, etc.)
2. **Error Handling**: Graceful fallback and retry mechanisms
3. **DNSSEC Workflow**: Zone → Key Generation → Signing → Verification
4. **Certificate Flow**: Domain validation → Challenge setup → Verification → Certificate retrieval

## Performance Considerations

- Client implements caching via DNS-over-HTTPS responses
- Server can handle concurrent UDP and HTTPS requests
- DNSSEC signing is performed on-demand for efficiency
- Handler registration is O(n) lookup but uses pattern caching

## Security Notes

- DNSSEC provides authentication but not encryption
- DoH (DNS-over-HTTPS) provides both privacy and integrity
- Let's Encrypt integration requires proper domain authorization
- Handler patterns should be carefully designed to avoid open resolvers

## Recent Improvements (v7.4.3)

1. **DNSSEC RRset Signing**: Fixed to properly sign entire RRsets together instead of individual records
2. **SOA Record Serialization**: Implemented proper SOA record encoding for DNSSEC compatibility
3. **Configurable Primary Nameserver**: Added `primaryNameserver` option to customize SOA mname field

## Recent Improvements (v7.4.8)

1. **MX Record DNSSEC Support**: Implemented MX record serialization for DNSSEC signing
   - MX records consist of a 16-bit preference value followed by the exchange domain name
   - Properly serializes both components for DNSSEC signature generation
   - Enables mail exchange records to be authenticated with DNSSEC

## Known Limitations

1. **Handler Deduplication**: If the same handler is registered multiple times, it will contribute duplicate records (this may be desired behavior for some use cases)
## Static Rust Binaries

- The Rust binaries in `dist_rust/` are statically linked (static-pie) via `"static": true` in the `@git.zone/tsrust` block of `.smartconfig.json` (tsrust >= 1.4.1). They run on both glibc (Debian/Ubuntu) and musl (Alpine) systems.
- tsrust injects `RUSTFLAGS="-C target-feature=+crt-static"` only into its own per-target cargo invocations and verifies the result (no `PT_INTERP` ELF header). Keep `rust/.cargo/config.toml` free of `rustflags` entries: the injected env variable would replace them, and a repo-wide `rustflags` would also break plain `cargo test`/`cargo check` (proc-macros cannot build with `+crt-static` on linux-gnu without an explicit `--target`).
- `pnpm run test:rust` runs the Rust unit tests; plain `cargo test` in `rust/` works as well.
- Verify linkage manually with `ldd dist_rust/<binary>_linux_amd64` → "statically linked".
