diff --git a/nixos/modules/services/networking/netbird.nix b/nixos/modules/services/networking/netbird.nix index 84383f7e28ca..c41183b9d307 100644 --- a/nixos/modules/services/networking/netbird.nix +++ b/nixos/modules/services/networking/netbird.nix @@ -12,6 +12,7 @@ let escapeShellArgs filterAttrs getExe + listToAttrs literalExpression maintainers makeBinPath @@ -28,6 +29,7 @@ let optional optionalAttrs optionalString + optionals toShellVars versionAtLeast versionOlder @@ -471,6 +473,16 @@ in toClientList (client: optional client.openFirewall client.port) ); + # Ports opened on a specific + networking.firewall.interfaces = listToAttrs ( + toClientList (client: { + name = client.interface; + value.allowedUDPPorts = optionals client.openFirewall [ + 5353 # required for the DNS forwarding/routing to work + ]; + }) + ); + systemd.network.networks = mkIf config.networking.useNetworkd ( toClientAttrs ( client: @@ -504,7 +516,14 @@ in after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; - path = optional (!config.services.resolved.enable) pkgs.openresolv; + path = + optionals (!config.services.resolved.enable) [ pkgs.openresolv ] + # useful for `netbird debug` system info gathering + ++ optionals config.networking.nftables.enable [ pkgs.nftables ] + ++ optionals (!config.networking.nftables.enable) [ + pkgs.iptables + pkgs.ipset + ]; serviceConfig = { ExecStart = "${getExe client.wrapper} service run"; diff --git a/nixos/tests/netbird.nix b/nixos/tests/netbird.nix index 581c6eeeab2e..873f5405935e 100644 --- a/nixos/tests/netbird.nix +++ b/nixos/tests/netbird.nix @@ -18,19 +18,18 @@ # TODO: confirm the whole solution is working end-to-end when netbird server is implemented testScript = '' start_all() - def did_start(node, name): + def did_start(node, name, interval=0.5, timeout=10): node.wait_for_unit(f"{name}.service") node.wait_for_file(f"/var/run/{name}/sock") - output = node.succeed(f"{name} status") + # `netbird status` returns a full "Disconnected" status during initialization + # only after a while passes it starts returning "NeedsLogin" help message - # not sure why, but it can print either of: - # - Daemon status: NeedsLogin - # - Management: Disconnected - expected = [ - "Disconnected", - "NeedsLogin", - ] - assert any(msg in output for msg in expected) + start = time.time() + output = node.succeed(f"{name} status") + while "Disconnected" in output and (time.time() - start) < timeout: + time.sleep(interval) + output = node.succeed(f"{name} status") + assert "NeedsLogin" in output did_start(clients, "netbird") did_start(clients, "netbird-custom")