Files
mesh-controller/internal/overlay/names.go
T
jochen 51163b9f14 The mesh's names are written into the hosts file, not over it (hq 128)
/etc/hosts is the machine's: the distribution's localhost lines, the
operator's own entries, and marked blocks other tools maintain there.
Writing node-names whole replaced all of it the moment the private
network was taken, and every later write by those tools was lost at
the next machine joining. The node-names fact is now emitted with
into: "block", so the host owns only its marked region and keeps the
rest byte for byte. The region holds only the mesh's names: no header
claiming the file, no localhost, no 127.0.1.1 line — the floor was
never the mesh's to write. How a fact is written is a property of the
fact in the closed table; node-zones stays a whole file the mesh owns.

Sequencing: a host older than the block mode refuses the whole
declaration on an unknown into, so every host must be upgraded before
this controller is rolled out.
2026-09-26 23:46:51 +02:00

55 lines
2.4 KiB
Go

package overlay
import (
"os"
"regexp"
"strings"
)
// Names are how one node reaches another by name rather than by address.
//
// novox/hq 08-connectivity: what the host receives is the resolver's configuration, as files,
// listing every peer's internal name and overlay address. Computed centrally for the same reason
// the peer graph is — it needs every node at once.
// SuffixVar lets a mesh choose what its internal names end in.
const SuffixVar = "MESH_INTERNAL_SUFFIX"
// DefaultSuffix is `.internal`, which IANA reserved for exactly this in 2024. A name under it can
// never collide with a public one, so an internal name that leaks into a public resolver fails
// rather than reaching a stranger's machine.
const DefaultSuffix = "internal"
// HostsPath is where the names go.
//
// This is not the `/etc/hosts` floor the design removes. That floor existed because a node had to
// reach the mesh's database before its own DNS worked — a fallback for a circularity, and the
// circularity is gone. This is the mechanism itself: the complete set of names in this mesh
// (novox/hq ADR 0011). Written as a marked region *into* the file rather than as the file: the
// rest of it — `localhost`, the machine's own name, other tools' blocks — is the machine's, and
// writing it whole replaced all of that (novox/hq issue 128).
//
// A file rather than a resolver daemon, deliberately, for now: it works on every Linux, needs no
// package, and has no failure mode of its own. A daemon becomes necessary when names are wanted
// that are not one-per-node — service names, wildcards — and that is not yet true.
const HostsPath = "/etc/hosts"
// Suffix is what internal names end in.
func Suffix() string {
if v := strings.TrimSpace(os.Getenv(SuffixVar)); v != "" {
return strings.TrimPrefix(v, ".")
}
return DefaultSuffix
}
// nodeName is what a node may be called, so that it can also be a hostname.
var nodeName = regexp.MustCompile(`^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$`)
// InternalName is a node's name inside the mesh.
func InternalName(node string) string { return node + "." + Suffix() }
// **What remains of a larger file.** The rest wrote /etc/hosts — that is the `node-names` fact now
// (catalogue.FactsInto), computed where the graph lives instead of by a module that ran nothing.
// The naming stays here, because several things compose a node's internal name and one of them
// writing the suffix differently would be a name nothing answers to.