]> Git — Sourcephile - sourcephile-nix.git/blob - nixos/modules/services/networking/netns.nix
nix: update to recent nixpkgs
[sourcephile-nix.git] / nixos / modules / services / networking / netns.nix
1 {
2 pkgs,
3 lib,
4 config,
5 options,
6 ...
7 }:
8 with lib;
9 let
10 cfg = config.services.netns;
11 inherit (config) networking;
12 # Escape as required by: https://www.freedesktop.org/software/systemd/man/systemd.unit.html
13 escapeUnitName =
14 name:
15 lib.concatMapStrings (s: if lib.isList s then "-" else s) (
16 builtins.split "[^a-zA-Z0-9_.\\-]+" name
17 );
18 in
19 {
20 options.services.netns = {
21 namespaces = mkOption {
22 description = ''
23 Network namespaces to create.
24
25 Other services can join a network namespace named <code>netns</code> with:
26 <screen>
27 PrivateNetwork=true;
28 JoinsNamespaceOf="netns-''${netns}.service";
29 </screen>
30
31 So can <literal>iproute</literal> with:
32 <code>ip -n ''${netns}</code>
33
34 <warning><para>
35 You should usually create (or update via your VPN configuration's up script)
36 a file named <literal>/etc/netns/''${netns}/resolv.conf</literal>
37 that will be bind-mounted by <code>ip -n ''${netns}</code> onto <literal>/etc/resolv.conf</literal>,
38 which you'll also want to configure in the services joining this network namespace:
39 <screen>
40 BindReadOnlyPaths = ["/etc/netns/''${netns}/resolv.conf:/etc/resolv.conf"];
41 </screen>
42 </para></warning>
43 '';
44 default = { };
45 type = types.attrsOf (
46 types.submodule {
47 options.nftables = mkOption {
48 description = "Nftables ruleset within the network namespace.";
49 type = types.lines;
50 default = networking.nftables.ruleset;
51 defaultText = "config.networking.nftables.ruleset";
52 };
53 options.sysctl = options.boot.kernel.sysctl // {
54 description = "sysctl within the network namespace.";
55 default = config.boot.kernel.sysctl;
56 defaultText = "config.boot.kernel.sysctl";
57 };
58 options.service = mkOption {
59 description = "Systemd configuration specific to this netns service";
60 type = types.attrs;
61 default = { };
62 };
63 }
64 );
65 };
66 };
67 config = {
68 systemd.services = mapAttrs' (
69 name: c:
70 nameValuePair "netns-${escapeUnitName name}" (mkMerge [
71 {
72 description = "${name} network namespace";
73 before = [ "network.target" ];
74 serviceConfig = {
75 Type = "oneshot";
76 RemainAfterExit = true;
77 # Let systemd create the netns so that PrivateNetwork=true
78 # with JoinsNamespaceOf="netns-${name}.service" works.
79 PrivateNetwork = true;
80 ExecStart =
81 [
82 # For convenience, register the netns to the tracking mecanism of iproute,
83 # and make sure resolv.conf can be used in BindReadOnlyPaths=
84 # For propagating changes to thie file to the services bind mounting it,
85 # updatingmust not remove the file, but only truncate it.
86 (pkgs.writeShellScript "ip-netns-attach" ''
87 ${pkgs.iproute}/bin/ip netns attach ${escapeShellArg name} $$
88 mkdir -p /etc/netns/${escapeShellArg name}
89 touch /etc/netns/${escapeShellArg name}/resolv.conf
90 '')
91
92 # Bringing the loopback interface is almost always a good thing.
93 "${pkgs.iproute}/bin/ip link set dev lo up"
94
95 # Use --ignore because some keys may no longer exist in that new namespace,
96 # like net.ipv6.conf.eth0.addr_gen_mode or net.core.rmem_max
97 ''
98 ${pkgs.procps}/bin/sysctl --ignore -p ${
99 pkgs.writeScript "sysctl" (
100 concatStrings (
101 mapAttrsToList (
102 n: v: optionalString (v != null) "${n}=${if v == false then "0" else toString v}\n"
103 ) c.sysctl
104 )
105 )
106 }
107 ''
108 ]
109 ++
110 # Load the nftables ruleset of this netns.
111 optional networking.nftables.enable (
112 pkgs.writeScript "nftables-ruleset" ''
113 #!${pkgs.nftables}/bin/nft -f
114 flush ruleset
115 ${c.nftables}
116 ''
117 );
118 # Unregister the netns from the tracking mecanism of iproute.
119 ExecStop = "${pkgs.iproute}/bin/ip netns delete ${escapeShellArg name}";
120 };
121 }
122 c.service
123 ])
124 ) cfg.namespaces;
125 meta.maintainers = with lib.maintainers; [ julm ];
126 };
127 }