Files
hq/02-DECISIONS/0186-a-ban-list-never-holds-a-neighbour.md
T

5.3 KiB

topic, status, date, deciders, reconstructed, extends
topic status date deciders reconstructed extends
the mesh accepted 2026-10-02 jochen false 02-DECISIONS/0179-the-intrusion-seat-serves-its-verbs-and-every-door-declares-its-jail.md

186. A ban list never holds a neighbour, and the mesh's own bans are its own wherever they hang

Context

ADR 0179 gave the public proxy a jail. Within the hour the home server's ban list held 192.168.1.1 — the house's own router. The router reflects local traffic, so every client in the building reaches that machine as the gateway's address; one local request for a name the mesh does not serve, three times in a day, and the whole house is refused by the machine it was asking. The jails inherited an ignoreip of the loopback and the mesh's own range, which was right when the only jail read the ssh daemon and the only clients were the mesh's; a jail on a public front door sees the neighbours too.

The same jail broke the other half of ADR 0168. The home server began reading NOT the mesh alone: 1 rule set the mesh did not write refuses traffic here, and the rule set named was the mesh's own ban chain, written by the mesh's own intrusion prevention minutes earlier. The host's reader of the legacy filter required every path into a chain of refusals to come from a built-in chain whose policy accepts, before it would call that chain a ban. On that machine the chain hangs off the container runtime's user chain as well as the input chain, and the runtime had set the forward policy to DROP — so the mesh reported its own work as a foreigner's, on the one machine where the group's exit condition was supposed to hold.

Both faults are one mistake in two places: a rule written about the public internet, applied to everything that arrives.

Decision

1. A ban list never holds a neighbour. The jails the mesh composes never ban a source on a private range — the mesh's own range, which was already named rather than written (ADR 0112), and every address space reserved for private use beside it, in both families. A machine behind a router that reflects local traffic sees its whole building as one address; a ban there is a self-inflicted outage, and the sources worth banning are not on those ranges in the first place.

2. The mesh's own bans are its own wherever they hang. A chain of refusals is a ban list when every refusal names the sources it refuses and the chain accepts nothing — the rule the host already applied to the packet filter's own tables, now applied to the legacy filter too, and nothing more. The policy of the chains that jump into it says nothing about what it is: that policy is already classified where it belongs, as the container runtime's, and requiring it here counted it twice.

3. A chain that accepts anything is still not a ban. That is what keeps a predecessor's allow-these-and-drop-the-rest chain classified as something an operator must look at, which is the distinction ADR 0168 exists to draw.

Consequences

  • The composed jails gain the private ranges in their never-ban list. An address already banned stays banned until it is released; the house's router was released by hand the moment it was found.
  • The home server reads the mesh alone again, which is group 7's exit condition and was false for about an hour.
  • A machine whose apply fails for an unrelated reason does not revisit its found firewall's record at all — the step runs only after a clean apply (ADR 0168). The home server's record therefore still reads retired by the mesh although the front end is uninstalled, and will correct itself once that machine's own stuck module is fixed. It is a stale record, not a wrong machine.
  • The record number the front end's removal was given moved under it: another session took 0175 while that record was in review, and it is now ADR 0180. The citations the host and the control plane print were pointing at an unrelated record and are corrected here.

How this is checked

Rule Checked by
A private source is never banned the module's jail configuration, read back by fail2ban.fail2ban_settings on a machine
The mesh's own ban chain reads as a ban behind a dropping forward policy a host test over the home server's own captured rule set
A chain that accepts anything is not a ban a host test
Live done 2026-10-02: all four machines read the mesh alone, the home server counting its own ban chain as a ban; no ban held anywhere is a private address

References