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 {
101 "net.ipv6.conf.all.forwarding" = 1;
102 "net.ipv6.conf.all.accept_redirects" = 0;
103 "net.ipv4.conf.all.forwarding" = 1;
104 "net.ipv4.conf.all.rp_filter" = 0;
105 }
106 // lib.mapAttrs' (
107 ifname: _: lib.nameValuePair "net.ipv4.conf.${ifname}.rp_filter" (lib.mkDefault 0)
108 ) config.services.babeld.interfaces;
109
110 systemd.services.babeld = {
111 description = "Babel routing daemon";
112 after = [ "network.target" ];
113 wantedBy = [ "multi-user.target" ];
114 serviceConfig = {
115 ExecStart = "${pkgs.babeld}/bin/babeld -c ${configFile} -I /run/babeld/babeld.pid -S /var/lib/babeld/state";
116 AmbientCapabilities = [ "CAP_NET_ADMIN" ];
117 CapabilityBoundingSet = [ "CAP_NET_ADMIN" ];
118 DevicePolicy = "closed";
119 DynamicUser = true;
120 IPAddressAllow = [
121 "fe80::/64"
122 "ff00::/8"
123 "::1/128"
124 "127.0.0.0/8"
125 ];
126 IPAddressDeny = "any";
127 LockPersonality = true;
128 NoNewPrivileges = true;
129 MemoryDenyWriteExecute = true;
130 ProtectSystem = "strict";
131 ProtectClock = true;
132 ProtectKernelTunables = true;
133 ProtectKernelModules = true;
134 ProtectKernelLogs = true;
135 ProtectControlGroups = true;
136 RestrictAddressFamilies = [
137 "AF_NETLINK"
138 "AF_INET6"
139 "AF_INET"
140 ];
141 RestrictNamespaces = true;
142 RestrictRealtime = true;
143 RestrictSUIDSGID = true;
144 RemoveIPC = true;
145 ProtectHome = true;
146 ProtectHostname = true;
147 ProtectProc = "invisible";
148 PrivateMounts = true;
149 PrivateTmp = true;
150 PrivateDevices = true;
151 PrivateUsers = false; # kernel_route(ADD): Operation not permitted
152 ProcSubset = "pid";
153 SystemCallArchitectures = "native";
154 SystemCallFilter = [
155 "@system-service"
156 "~@privileged @resources"
157 ];
158 UMask = "0177";
159 RuntimeDirectory = "babeld";
160 StateDirectory = "babeld";
161 };
162 };
163 };
164}