~ober/jerboa-dns
Imported from ~/mine/jerboa-dns
about
# jerboa-dns
Authoritative-only DNS server and zone compiler in Jerboa/Chez Scheme.
`jdns` serves both UDP and TCP DNS on the configured port.
## Build and Test
```sh
make build
make test
```
Release evidence:
```sh
make release-evidence
```
The release bundle records DNS soak/load status under
`dist/release-evidence/soak/`. By default this is a blocked, record-only status;
set `JDNS_RUN_RELEASE_SOAK=1` with production-duration `JDNS_SOAK_SECONDS` to
capture current UDP `dnsperf` evidence plus bounded DNS-over-TCP smoke.
Bounded local coverage-guided fuzz evidence is recorded with:
```sh
JDNS_RUN_COVERAGE_FUZZ=1 JDNS_FUZZ_RUNS=2048 make fuzz-evidence
```
When `JDNS_RUN_COVERAGE_FUZZ=1` is set for `make release-evidence`, the release
bundle also records `coverage_fuzz_status=local-smoke-recorded` under
`dist/release-evidence/fuzz-evidence/` after `dns_query`, `cdb_record`, and
`cdb_file` complete.
Authoritative-only, amplification, and edge rate-limit policy is documented in
`docs/rate-limit-amplification.md` and copied into
`dist/release-evidence/abuse-policy.txt`.
Static release targets live behind the `static-*` Make targets, for example:
```sh
make static-freebsd
```
## Runtime Security Defaults
`jdns` binds the UDP and TCP sockets first, then chroots to `ROOT` (default
`.`), drops supplementary groups with `setgroups(0, NULL)`, applies
`setgid`/`setuid`, verifies the resulting identities, and then applies platform
filesystem restrictions. A root launch requires both a non-zero `UID` and
non-zero `GID`. Root retention is denied unless the development-only
`JDNS_RETAIN_PRIVILEGES=1` / `--retain-privileges` override is explicit; that
override is audited in the log and is not a production configuration. See
`docs/runtime-hardening.md`.
TCP handling uses Jerboa fibers over nonblocking sockets when the fiber runtime
is available before chroot. Embedded static builds can fall back to bounded
nonblocking OS-thread tasks instead of failing at startup. TCP clients are capped
at 128 concurrent sessions, and idle TCP reads/writes time out after 15 seconds.
The daemon is authoritative-only and does not recurse or forward queries.
Amplification-prone `ANY` queries are minimized with a small REFUSED response.
Production deployments must still provide edge rate limits until native
response-rate limiting exists.
Filesystem sandbox setup fails closed by default. For local development only,
you can allow a weaker fallback with either:
```sh
JDNS_ALLOW_SANDBOX_FALLBACK=1 jdns ...
jdns --allow-sandbox-fallback ...
```
The WASM DNS parser and WASM CDB reader are embedded into the binary at build
time (`lib/jerboa-dns/wasm-embedded.ss`, regenerated by `wasm/build.sh`), so
the sandbox is active with no files on disk, including inside the chroot.
If the wasmi runtime itself is not linked in, startup/query handling fails
closed by default. The only in-process parser fallback is the explicit
development opt-out `JDNS_ALLOW_IN_PROCESS_PARSER=1` or
`JDNS_ALLOW_IN_PROCESS_CDB=1`.
`JDNS_PARSER_WASM` / `JDNS_CDB_WASM` point at on-disk modules as an explicit
development override (useful for testing a rebuilt parser without relinking);
they are not needed in production.
## Zone Updates
`jdns-data` writes a temporary CDB and atomically renames it into place. The
server validates one immutable in-memory snapshot at startup. A low-frequency
watcher detects device/inode/time/size changes, builds and validates a candidate
off the request path, and atomically swaps it; in-flight queries finish against
their old snapshot. Queries never reopen the CDB. The default one-second poll
can be changed with `JDNS_CDB_RELOAD_MS` (100–60000 ms), and malformed updates
leave the last valid snapshot serving.
## Zone Formats
`jdns-data` accepts the original tinydns `data` format and a grouped
s-expression format. The s-expression form starts with `(zone ...)`, so the
compiler auto-detects it:
```scheme
(zone
(domain "example.com"
(soa "ns1.example.com" "1.2.3.4" 259200)
(ns "ns2.example.com" "1.2.3.5" 259200)
(a "1.2.3.4" 86400)
(mx "mail.example.com" 10 "1.2.3.6" 86400)
(txt "v=spf1 include:example.net mx -all" 86400)
(txt "_dmarc" "v=DMARC1; p=none" 86400))
(domain "www.example.com"
(a+ptr "1.2.3.4" 86400))
(domain "static.example.com"
(cname "www.example.com" 3600))
(domain "ipv6.example.com"
(aaaa "2001:db8::1" 86400)))
```
TXT records can optionally start with a relative owner name. For example,
`(txt "_dmarc" "v=DMARC1; p=none")` inside `example.com` compiles as a TXT
record for `_dmarc.example.com`.
Compile either format the same way:
```sh
make jdns-data ARGS="zones/example.sexp data.cdb"
```
recent commits
- Document local mine repository authority ec6c063 Jaime Fournier
- Use FreeBSD Forgejo CI runner f3019b2 user
- Set up Forgejo CI/CD policy 00bed10 Jaime Fournier
- Add package backup and project notes c132cd2 Jaime Fournier
- Update jpkg metadata for Forgejo 4b4ffb2 Jaime Fournier
- Enable FreeBSD fiber TCP builds 375410f Jaime Fournier
- Embed WASM parsers and document deployment a5e53a2 Jaime Fournier
- fixes from kimi3 4d9b686 Jaime Fournier
- docs: remove jerboa-emacs restriction 2c56431 Jaime Fournier
- Remove GitHub workflow metadata 4cdab8c Jaime Fournier