A computed module says what its machine opens, so a hub can be filtered

The machine that most needed a firewall was the one that could not have one. A
hub is dialled by every node at other sites and needs its port open; a machine
that is not a hub dials out and needs nothing open. They are the same module,
and `listens` in a manifest is one answer for every machine that runs it — so
the machine a static answer gets wrong is the one facing the public internet.

A generator can now say what it opens, in a second interface rather than a
method on every generator: most have nothing to say here, and requiring an
empty method of each would be a cost paid everywhere for one caller.

The port is the one in the endpoint, which is where the interface takes its
ListenPort from. One source, so a rule set cannot open a port the interface is
not on. Open to everywhere and deliberately: a node at another site is not on
the private network until this port lets it on, so restricting it to the mesh
would be a rule that can never be satisfied by the thing it exists for.

And a generator that cannot say is refused rather than read as silence. Closing
a port on the evidence of a failure to look is how a machine is severed by a
fault somewhere else — and the machine it would sever is the hub, whose only
route to being fixed is the network it just closed.
This commit is contained in:
2026-08-31 10:07:01 +02:00
parent d1c256c2b1
commit 092109debc
5 changed files with 313 additions and 18 deletions
+21 -1
View File
@@ -26,6 +26,22 @@ type Generator interface {
Resources(node string) ([]map[string]any, bool, error)
}
// OpensPorts is a generator that also says what its resources accept connections on.
//
// **Separate from Generator, because most generators have nothing to say here** and requiring an
// empty method of each would be a cost paid everywhere for one caller.
//
// It exists because a static field cannot express this. A hub accepts connections from every node
// at other sites; a machine that is not a hub dials out and needs nothing open — and they are the
// same module. `listens` in a manifest is one answer for every machine that runs it, so the
// machine that most needs filtering, the one facing the public internet, was the one whose rule
// set would have closed its own overlay.
type OpensPorts interface {
// Listens is what this node accepts on because of what was computed for it. Nothing is the
// ordinary answer: most machines running a computed module open no port at all.
Listens(node string) ([]Listening, error)
}
// Grant is one consumer's credential, on the machine that must create it.
type Grant struct {
// Provision is what was required.
@@ -93,7 +109,11 @@ func (r Resolution) Declaration(with Rendering) ([]map[string]any, error) {
// Once, from every module's listens -- not per module. A module receiving only its own ports
// would write a rule set that closed every other module on the machine.
filtering := AsNftables(r.Filtering(), with.Mesh)
rules, err := r.Filtering(with.Generators)
if err != nil {
return nil, err
}
filtering := AsNftables(rules, with.Mesh)
var out []map[string]any
for _, m := range r.Modules {