diff --git a/docs/gotchas.md b/docs/gotchas.md index 4c106d3d..c50421be 100644 --- a/docs/gotchas.md +++ b/docs/gotchas.md @@ -72,32 +72,6 @@ the path entry resolves to `/run/wrappers/bin/bin` instead. hive-c0re restarts. Without it, every restart wipes bind sources and existing containers can't be started. -### `RestrictAddressFamilies` fails as "Address family not supported by protocol" - -A unit whose `RestrictAddressFamilies` omits a family gets `EAFNOSUPPORT` -(errno 97) back from `socket()`. Clients surface that as *"tcp open error: -Address family not supported by protocol"* — the message names the -**protocol** and never the **sandbox**, so it reads like a dead network, a -missing route, or an IPv6 problem. - -⇒ On that error, read the unit before you touch the network. - -Two things to get right when a daemon needs outbound TCP: - -- list `AF_INET` **and** `AF_INET6` — omitting one leaves a client that - works until DNS hands back the other family; -- list `AF_NETLINK` too. glibc's `getaddrinfo` opens a netlink socket to - enumerate local addresses before it returns any, so name resolution - fails without it even when `AF_INET` is allowed. - -**The directive is a claim about what the program does, and nothing -re-checks it when the program changes.** A unit that only served a unix -socket when it was written is correct at `[ "AF_UNIX" ]` and silently wrong -the day someone adds an HTTP client. Check the unit in the same commit as -the client — and when narrowing it, prefer a test that derives the required -families from the code (which fails on the *next* client too) over one that -asserts today's list. - ### `register_agent` is idempotent Drops any prior socket task before rebinding. Required so a diff --git a/nix/host-modules/swarm-controller.nix b/nix/host-modules/swarm-controller.nix index 9c8b1fca..90c2ca67 100644 --- a/nix/host-modules/swarm-controller.nix +++ b/nix/host-modules/swarm-controller.nix @@ -508,7 +508,8 @@ in StateDirectoryMode = "0750"; # Nothing here needs a writable filesystem, real privileges, or a - # view of the rest of the machine. + # view of the rest of the machine; the daemon reads its socket path + # from config and serves. PrivateTmp = true; ProtectSystem = "strict"; ProtectHome = true; @@ -517,27 +518,8 @@ in ProtectKernelTunables = true; ProtectKernelModules = true; ProtectControlGroups = true; - - # `AF_UNIX` for the socket this daemon serves on, plus what its - # outbound clients need: it mints authelia tokens and calls the forge - # over HTTPS (`auth.rs`, `forge.rs`) and reaches the queue over NATS - # (`main.rs`, `status.rs`). `AF_NETLINK` because glibc's - # `getaddrinfo` opens a netlink socket to enumerate local addresses - # before it will return one. - # - # ⚠️ This list is a CLAIM ABOUT WHAT THE DAEMON DOES, so it goes stale - # the moment the daemon grows a client — and it goes stale in the - # worst available way: a blocked family makes `socket()` return - # EAFNOSUPPORT, i.e. "Address family not supported by protocol", so - # the error names the protocol and never the sandbox that refused it. - # This was `AF_UNIX`-only while the daemon merely served its socket; - # all three clients above arrived later, and the restriction was not - # revisited. Add the family when you add the client. RestrictAddressFamilies = [ "AF_UNIX" - "AF_INET" - "AF_INET6" - "AF_NETLINK" ]; };