From 4989579270c81acfa381f0d4e48ad80cf2452612 Mon Sep 17 00:00:00 2001 From: atlas Date: Fri, 31 Jul 2026 18:32:01 +0200 Subject: [PATCH] fix(#2862): open the receiver's port on the mesh interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit argus caught it: binding the socket to the mesh address does not open the port. NixOS's firewall is default-deny and filters in netfilter, before a packet reaches a bound socket — the bind chooses which address accepts connections, not whether packets arrive. As shipped the receiver was unreachable. swarm.nix already shows the pattern for exactly this situation: it opens the mesh's UDP port explicitly right after bringing the interface up. Interface-scoped to wg-hive rather than host-wide, so the option's "reachable exactly by mesh peers" claim is actually true. A global allowedTCPPorts would open the port on every interface including the public NIC, leaving only the socket's bind address between the internet and a root btrfs receive. --- nix/host-modules/hive-snapshot-store.nix | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/nix/host-modules/hive-snapshot-store.nix b/nix/host-modules/hive-snapshot-store.nix index fa149656..2a31c5f8 100644 --- a/nix/host-modules/hive-snapshot-store.nix +++ b/nix/host-modules/hive-snapshot-store.nix @@ -191,6 +191,22 @@ in # creates its own tree lazily. systemd.tmpfiles.rules = [ "d ${cfg.path} 0700 root root -" ]; + # Open the receiver's port, scoped to the mesh interface. + # + # ⚠️ Binding the socket to the mesh address is NOT sufficient on its + # own: NixOS's firewall is default-deny and filters in netfilter, + # before a packet ever reaches a bound socket. The bind chooses + # WHICH address accepts connections; it does not open the port. The + # mesh's own UDP port is opened the same explicit way in swarm.nix. + # + # Interface-scoped rather than host-wide so the reachability + # property stays exactly what the option docs claim --- mesh peers + # and nobody else. A global `allowedTCPPorts` would open the port on + # every interface, including whatever public NIC the box has, and + # only the socket's bind address would still be standing between + # the internet and a root `btrfs receive`. + networking.firewall.interfaces.wg-hive.allowedTCPPorts = [ cfg.port ]; + # Socket-activated on purpose: no long-running root daemon, and the # unit exists only while a transfer does. #