Answer DNS questions about the overlay

The zone and the server, without any of the operating system yet.

`dns::zone` decides what the answer is and knows nothing about packets
or sockets, so the parts worth getting right are testable on their own:
which names exist, that a neighbouring name like `evillab` is not inside
`lab`, and the difference between a name that is absent and one that
exists with nothing of the type asked for. Getting that last one wrong
would teach a resolver to stop asking for the A record it could have
had.

Names come from signed state, which is the point: a member that is
switched off still resolves, because its claim outlived the session.
Only IPv4 is served. The IPv6 overlay address derives from a WireGuard
key that travels in live announcements and is not in signed state, so it
cannot be answered for an absent member, and answering for some members
and not others depending on who happens to be online is worse than not
answering.

`dns::server` puts that on the wire with simple-dns, which is already in
the tree through iroh — a packet codec rather than a server framework,
which is the right size for answering A records from memory. respond()
goes from bytes to bytes so everything done to a packet is tested
without a socket.

It is authoritative for one zone and refuses everything else: no
recursion, no forwarding, no cache, so pointing a resolver here can
never make it a path to the outside. A message that is not a question
gets no reply at all, rather than making this a reflector for anyone who
can spoof a source address, and ANY is answered as an address question
rather than by dumping the zone. Answers too large for the client's UDP
limit are truncated so a resolver retries over TCP instead of waiting;
TCP reads are length-checked before allocating, timed out, and bounded
in number.

The zone is shared rather than copied in, so a member joining is one
write instead of a rebind that would drop questions in flight.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
tsunagi
2026-09-21 16:50:55 +01:00
co-authored by Claude Opus 5
parent 43e8ac8159
commit 240e471c88
6 changed files with 1088 additions and 0 deletions
+4
View File
@@ -43,6 +43,10 @@ zeroize = { version = "1.9", features = ["derive"] }
rand = "0.10"
serde = { version = "1.0", features = ["derive"] }
postcard = { version = "1.1", default-features = false, features = ["use-std"] }
# Already in the tree through iroh. A packet codec, not a DNS server: the
# zone logic is ours and a full server framework would be a large dependency
# for answering A records from memory.
simple-dns = "0.12"
data-encoding = "2.11"
hex = "0.4"
thiserror = "2.0"