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