dns: read resolv.conf through an Eio capability in dns-eio
Dns_eio.v discovered nameservers by reading /etc/resolv.conf with
blocking stdlib channels inside an Eio program -- benign at config-build
time, but the pattern the tree bans, and the caller had no way to name
the file or supply a capability.
v now takes ?resolv_conf, an Eio.Path capability naming the file to
read; discovery goes through Eio.Path.load and the file's content is
parsed by Dns.Resolv_conf (retiring the inline duplicate parser). An
explicit ~nameservers list still wins, and a missing, unreadable, or
nameserver-less file falls back to 1.1.1.1/8.8.8.8 as before.
The no-argument default keeps reading /etc/resolv.conf with one stdlib
read at configuration build: the call sites that omit both arguments
(atproto-handle, mirage caps) hold no filesystem capability, so the
read stays at this documented boundary and never runs per query.
Tests land with the new entry point: nameservers from a file named by
a capability (exact values, IPv4 + IPv6), fallback on a missing file
and on one without nameserver lines, and explicit-list precedence.
Also links the of_string doc reference in resolv_conf.mli the odoc way
(E420, follow-up to the previous commit).
nox-dns: make the forwarding resolver a pure state machine
Dns.Forward was an I/O-free decision core but mutated its state in place
(cfg, cache, health, hosts) and pulled an injected clock and RNG. Rework
it into a pure state machine, matching the monorepo's pure-core doctrine:
- the state is immutable; decide and on_reply return the next state
(a cache lookup prunes, on_reply caches and records health);
- now and rng are passed per call rather than held;
- the reload verbs are with_config/with_hosts (pure), and a new
with_hosts/hosts pair lets a control plane swap the local names table
live -- the hosts analogue of the existing config reload.
nox-dns-eio's Forward_eio becomes the thin I/O edge: it holds the one
mutable core ref, threads the clock and RNG into each call, and swaps in
the state the core returns. Its public API (resolve, set_config,
set_hosts) is unchanged, so downstream consumers are untouched.
A new fuzz property pins the invariant the pure core now guarantees and
the old mutable core could not: decide and on_reply never mutate the
state handed to them. It forwards a name, caches the reply into the
returned state, and asserts the pre-reply state still treats the name as
a miss -- under the old core that check saw a cache hit.
nox-dns: make the forwarding resolver a pure state machine
Dns.Forward was an I/O-free decision core but mutated its state in place
(cfg, cache, health, hosts) and pulled an injected clock and RNG. Rework
it into a pure state machine, matching the monorepo's pure-core doctrine:
- the state is immutable; decide and on_reply return the next state
(a cache lookup prunes, on_reply caches and records health);
- now and rng are passed per call rather than held;
- the reload verbs are with_config/with_hosts (pure), and a new
with_hosts/hosts pair lets a control plane swap the local names table
live -- the hosts analogue of the existing config reload.
nox-dns-eio's Forward_eio becomes the thin I/O edge: it holds the one
mutable core ref, threads the clock and RNG into each call, and swaps in
the state the core returns. Its public API (resolve, set_config,
set_hosts) is unchanged, so downstream consumers are untouched.
A new fuzz property pins the invariant the pure core now guarantees and
the old mutable core could not: decide and on_reply never mutate the
state handed to them. It forwards a name, caches the reply into the
returned state, and asserts the pre-reply state still treats the name as
a miss -- under the old core that check saw a cache hit.