ADR 0137: a machine says which networks it routes, and issue 137 is how that was found

This commit is contained in:
2026-09-28 21:31:01 +02:00
parent b7bf601ca4
commit 05039c4f10
3 changed files with 191 additions and 0 deletions
@@ -0,0 +1,74 @@
---
status: resolved
opened: 2026-09-28
located-in: [mesh-controller internal/catalogue]
fixed-by: mesh-controller — a machine says which networks it routes and the derived filter forwards them, their guests keeping address and name service ([ADR 0137](../../02-DECISIONS/0137-a-machine-says-which-networks-it-routes.md)).
amended-design:
---
# 137 — Converging a machine cut off its own guests, and nothing said so
## What was observed
A workstation was flipped from adopted to converged, so the mesh's derived filter replaced what was
there. The flip reported success, the machine reported that it had applied its declaration, and every
surface of the mesh read green.
A container on one of that machine's networks could no longer reach anything:
```
192.168.64.2/20
OUTBOUND BLOCKED
```
Five of the machine's container networks were affected, and every network its test beds create. The
reason is in the filter's forward chain, which denies by default and then allows two ranges:
```
ip saddr 172.16.0.0/12 accept # the container runtime's bridge networks
ip saddr 192.168.128.0/17 accept # the networks its compose files are given
```
Those two are constants in the controller. The machine's guests were allocated from neither: its
compose networks from other parts of `192.168/16`, and each test bed a fresh `10.x/24`. So the rules
were correct for a machine whose runtime was left at its defaults, and a guess on this one.
Two further things were closed by the same flip, and for the same reason nobody saw them: a guest asks
its host for an address over DHCP and for names over DNS, both of which arrive at the input chain,
where no module had declared them.
## Why it matters beyond this instance
**The preview could not have warned.** It lists what the machine reported as *listening*, and says so
honestly: it ends with a line that traffic the machine routes is "not previewed". What it did not say
is that routing was about to be denied by default, or which ranges would survive. An operator reading
a 350-line preview approves what it shows.
**It is the second time today that a constant stood in for something the mesh cannot know.** The
intrusion-prevention module named a firewall front-end two machines do not have
([issue 136](../136-a-module-may-name-a-program-the-machine-does-not-have/00-report.md)), and the
filter names the address ranges one runtime happens to use. Both were true where they were written and
silently false elsewhere.
**And the code already knew.** The comment above those two lines says a machine configured otherwise
"needs this to say so — which is a thing the mesh cannot derive and a reason this list is named here
rather than computed". The gap was documented at the point where it was introduced, and the way to say
it was never built. A comment naming a missing mechanism is a rule that is not enforced.
## What was done
A machine says which networks it routes; the filter forwards them and admits their guests' address and
name service. Added to the runtime's defaults rather than replacing them, so a machine that names one
range keeps the others. Node-level, because the machine routes them and the module that loads the
filter may be replaced. The converge preview now says what a machine routes, and what it will keep
forwarding if it says nothing.
## What is still true
**The flip is still the moment a machine's unmanaged services close.** That is what converging means
and the preview names each one. This issue is not about the ports that were meant to close; it is about
the ones nothing could name.
**Egress is still not previewed per network.** The preview says which ranges will be forwarded, not
which of the machine's guests sit inside them. Deriving that would need the machine to report its
bridges, and a bed's bridge does not exist until the bed runs.