1{
2 config,
3 lib,
4 pkgs,
5 ...
6}:
7let
8
9 cfg = config.services.babeld;
10
11 conditionalBoolToString =
12 value: if (lib.isBool value) then (lib.boolToString value) else (toString value);
13
14 paramsString =
15 params:
16 lib.concatMapStringsSep " " (name: "${name} ${conditionalBoolToString (lib.getAttr name params)}") (
17 lib.attrNames params
18 );
19
20 interfaceConfig =
21 name:
22 let
23 interface = lib.getAttr name cfg.interfaces;
24 in
25 "interface ${name} ${paramsString interface}\n";
26
27 configFile =
28 with cfg;
29 pkgs.writeText "babeld.conf" (
30 ''
31 skip-kernel-setup true
32 ''
33 + (lib.optionalString (cfg.interfaceDefaults != null) ''
34 default ${paramsString cfg.interfaceDefaults}
35 '')
36 + (lib.concatMapStrings interfaceConfig (lib.attrNames cfg.interfaces))
37 + extraConfig
38 );
39
40in
41
42{
43
44 meta.maintainers = with lib.maintainers; [ hexa ];
45
46 ###### interface
47
48 options = {
49
50 services.babeld = {
51
52 enable = lib.mkEnableOption "the babeld network routing daemon";
53
54 interfaceDefaults = lib.mkOption {
55 default = null;
56 description = ''
57 A set describing default parameters for babeld interfaces.
58 See {manpage}`babeld(8)` for options.
59 '';
60 type = lib.types.nullOr (lib.types.attrsOf lib.types.unspecified);
61 example = {
62 type = "tunnel";
63 split-horizon = true;
64 };
65 };
66
67 interfaces = lib.mkOption {
68 default = { };
69 description = ''
70 A set describing babeld interfaces.
71 See {manpage}`babeld(8)` for options.
72 '';
73 type = lib.types.attrsOf (lib.types.attrsOf lib.types.unspecified);
74 example = {
75 enp0s2 = {
76 type = "wired";
77 hello-interval = 5;
78 split-horizon = "auto";
79 };
80 };
81 };
82
83 extraConfig = lib.mkOption {
84 default = "";
85 type = lib.types.lines;
86 description = ''
87 Options that will be copied to babeld.conf.
88 See {manpage}`babeld(8)` for details.
89 '';
90 };
91 };
92
93 };
94
95 ###### implementation
96
97 config = lib.mkIf config.services.babeld.enable {
98
99 boot.kernel.sysctl = {
100 "net.ipv6.conf.all.forwarding" = 1;
101 "net.ipv6.conf.all.accept_redirects" = 0;
102 "net.ipv4.conf.all.forwarding" = 1;
103 "net.ipv4.conf.all.rp_filter" = 0;
104 }
105 // lib.mapAttrs' (
106 ifname: _: lib.nameValuePair "net.ipv4.conf.${ifname}.rp_filter" (lib.mkDefault 0)
107 ) config.services.babeld.interfaces;
108
109 systemd.services.babeld = {
110 description = "Babel routing daemon";
111 after = [ "network.target" ];
112 wantedBy = [ "multi-user.target" ];
113 serviceConfig = {
114 ExecStart = "${pkgs.babeld}/bin/babeld -c ${configFile} -I /run/babeld/babeld.pid -S /var/lib/babeld/state";
115 AmbientCapabilities = [ "CAP_NET_ADMIN" ];
116 CapabilityBoundingSet = [ "CAP_NET_ADMIN" ];
117 DevicePolicy = "closed";
118 DynamicUser = true;
119 IPAddressAllow = [
120 "fe80::/64"
121 "ff00::/8"
122 "::1/128"
123 "127.0.0.0/8"
124 ];
125 IPAddressDeny = "any";
126 LockPersonality = true;
127 NoNewPrivileges = true;
128 MemoryDenyWriteExecute = true;
129 ProtectSystem = "strict";
130 ProtectClock = true;
131 ProtectKernelTunables = true;
132 ProtectKernelModules = true;
133 ProtectKernelLogs = true;
134 ProtectControlGroups = true;
135 RestrictAddressFamilies = [
136 "AF_NETLINK"
137 "AF_INET6"
138 "AF_INET"
139 ];
140 RestrictNamespaces = true;
141 RestrictRealtime = true;
142 RestrictSUIDSGID = true;
143 RemoveIPC = true;
144 ProtectHome = true;
145 ProtectHostname = true;
146 ProtectProc = "invisible";
147 PrivateMounts = true;
148 PrivateTmp = true;
149 PrivateDevices = true;
150 PrivateUsers = false; # kernel_route(ADD): Operation not permitted
151 ProcSubset = "pid";
152 SystemCallArchitectures = "native";
153 SystemCallFilter = [
154 "@system-service"
155 "~@privileged @resources"
156 ];
157 UMask = "0177";
158 RuntimeDirectory = "babeld";
159 StateDirectory = "babeld";
160 };
161 };
162 };
163}