basic netns management

This commit is contained in:
Robin Appelman 2025-10-30 18:16:28 +01:00
commit a4c7b3c1c9
17 changed files with 1555 additions and 0 deletions

73
nix/module.nix Normal file
View file

@ -0,0 +1,73 @@
{
config,
lib,
pkgs,
...
}:
with lib; let
cfg = config.networking.netnsd;
hasNamespaces = cfg.namespaces != {};
format = pkgs.formats.toml {};
configFile = format.generate "netnsd.toml" {
inherit (cfg) namespaces;
};
in {
options.networking.netnsd = {
package = mkOption {
type = types.package;
description = "package to use";
};
namespaces = mkOption {
type = types.attrsOf (types.submodule ({name, ...}: {
options = {
name = mkOption {
type = types.str;
default = name;
description = "target port inside the namespace";
};
forward = mkOption {
type = types.listOf (types.submodule ({config, ...}: {
options = {
source = mkOption {
type = types.oneOf[types.port types.str];
default = config.destination;
defaultText = "<destination>";
description = "source port, address or socket outside the namespace";
};
destination = mkOption {
type = types.oneOf[types.port types.str];
description = "target port or address inside the namespace";
};
};
}));
description = "ports to forward into the namespace";
};
};
}));
description = "namespaces to setup";
};
};
config = mkIf hasNamespaces {
# symlink instead of passing `configFile` directly to netnsd to allow changing the config without changing the path
environment.etc."netnsd/netnsd.toml".source = configFile;
systemd.services.netcsctl = {
reloadTriggers = [configFile];
wantedBy = ["multi-user.target"];
serviceConfig = {
Restart = "on-failure";
Type = "notify";
ExecStart = "${getExec cfg.pkg} daemon -c /etc/netnsd/netnsd.toml";
ExecReload = "${getExec cfg.pkg} reload";
PrivateTmp = true;
ProtectSystem = "full";
ProtectHome = true;
NoNewPrivileges = true;
};
};
};
}

3
nix/overlay.nix Normal file
View file

@ -0,0 +1,3 @@
final: prev: {
netnsd = final.callPackage ./package.nix {};
}

19
nix/package.nix Normal file
View file

@ -0,0 +1,19 @@
{
rustPlatform,
lib,
}: let
inherit (lib.sources) sourceByRegex;
inherit (builtins) fromTOML readFile;
src = sourceByRegex ../. ["Cargo.*" "(src|templates)(/.*)?"];
cargoPackage = (fromTOML (readFile ../Cargo.toml)).package;
in
rustPlatform.buildRustPackage rec {
pname = cargoPackage.name;
inherit (cargoPackage) version;
inherit src;
cargoLock = {
lockFile = ../Cargo.lock;
};
}