diff options
Diffstat (limited to 'modules')
-rw-r--r-- | modules/networkd.nix | 297 | ||||
-rw-r--r-- | modules/networkd/default.nix | 1686 | ||||
-rw-r--r-- | modules/networkd/systemd-lib.nix | 237 | ||||
-rw-r--r-- | modules/networkd/systemd-unit-options.nix | 536 | ||||
-rw-r--r-- | modules/yggdrasil-wg/default.nix | 234 |
5 files changed, 2627 insertions, 363 deletions
diff --git a/modules/networkd.nix b/modules/networkd.nix deleted file mode 100644 index d0a48f98..00000000 --- a/modules/networkd.nix +++ /dev/null | |||
@@ -1,297 +0,0 @@ | |||
1 | { config, lib, utils, pkgs, ... }: | ||
2 | |||
3 | with utils; | ||
4 | with lib; | ||
5 | |||
6 | let | ||
7 | |||
8 | cfg = config.networking; | ||
9 | interfaces = attrValues cfg.interfaces; | ||
10 | |||
11 | interfaceIps = i: | ||
12 | i.ipv4.addresses | ||
13 | ++ optionals cfg.enableIPv6 i.ipv6.addresses; | ||
14 | |||
15 | dhcpStr = useDHCP: if useDHCP == true || useDHCP == null then "yes" else "no"; | ||
16 | |||
17 | slaves = | ||
18 | concatLists (map (bond: bond.interfaces) (attrValues cfg.bonds)) | ||
19 | ++ concatLists (map (bridge: bridge.interfaces) (attrValues cfg.bridges)) | ||
20 | ++ map (sit: sit.dev) (attrValues cfg.sits) | ||
21 | ++ map (vlan: vlan.interface) (attrValues cfg.vlans) | ||
22 | # add dependency to physical or independently created vswitch member interface | ||
23 | # TODO: warn the user that any address configured on those interfaces will be useless | ||
24 | ++ concatMap (i: attrNames (filterAttrs (_: config: config.type != "internal") i.interfaces)) (attrValues cfg.vswitches); | ||
25 | |||
26 | in | ||
27 | |||
28 | { | ||
29 | disabledModules = [ "tasks/network-interfaces-systemd.nix" ]; | ||
30 | |||
31 | config = mkIf cfg.useNetworkd { | ||
32 | |||
33 | assertions = [ { | ||
34 | assertion = cfg.defaultGatewayWindowSize == null; | ||
35 | message = "networking.defaultGatewayWindowSize is not supported by networkd."; | ||
36 | } { | ||
37 | assertion = cfg.vswitches == {}; | ||
38 | message = "networking.vswitches are not supported by networkd."; | ||
39 | } { | ||
40 | assertion = cfg.defaultGateway == null || cfg.defaultGateway.interface == null; | ||
41 | message = "networking.defaultGateway.interface is not supported by networkd."; | ||
42 | } { | ||
43 | assertion = cfg.defaultGateway6 == null || cfg.defaultGateway6.interface == null; | ||
44 | message = "networking.defaultGateway6.interface is not supported by networkd."; | ||
45 | } { | ||
46 | assertion = cfg.useDHCP == false; | ||
47 | message = '' | ||
48 | networking.useDHCP is not supported by networkd. | ||
49 | Please use per interface configuration and set the global option to false. | ||
50 | ''; | ||
51 | } ] ++ flip mapAttrsToList cfg.bridges (n: { rstp, ... }: { | ||
52 | assertion = !rstp; | ||
53 | message = "networking.bridges.${n}.rstp is not supported by networkd."; | ||
54 | }); | ||
55 | |||
56 | networking.dhcpcd.enable = mkDefault false; | ||
57 | |||
58 | systemd.network = | ||
59 | let | ||
60 | domains = cfg.search ++ (optional (cfg.domain != null) cfg.domain); | ||
61 | genericNetwork = override: | ||
62 | let gateways = optional (cfg.defaultGateway != null && (cfg.defaultGateway.address or "") != "") cfg.defaultGateway.address | ||
63 | ++ optional (cfg.defaultGateway6 != null && (cfg.defaultGateway6.address or "") != "") cfg.defaultGateway6.address; | ||
64 | in optionalAttrs (gateways != [ ]) { | ||
65 | routes = override (map (gateway: { | ||
66 | routeConfig = { | ||
67 | Gateway = gateway; | ||
68 | GatewayOnLink = false; | ||
69 | }; | ||
70 | }) gateways); | ||
71 | } // optionalAttrs (domains != [ ]) { | ||
72 | domains = override domains; | ||
73 | }; | ||
74 | in mkMerge [ { | ||
75 | enable = true; | ||
76 | } | ||
77 | (mkMerge (forEach interfaces (i: { | ||
78 | netdevs = mkIf i.virtual ({ | ||
79 | "40-${i.name}" = { | ||
80 | netdevConfig = { | ||
81 | Name = i.name; | ||
82 | Kind = i.virtualType; | ||
83 | }; | ||
84 | "${i.virtualType}Config" = optionalAttrs (i.virtualOwner != null) { | ||
85 | User = i.virtualOwner; | ||
86 | }; | ||
87 | }; | ||
88 | }); | ||
89 | networks."40-${i.name}" = mkMerge [ (genericNetwork mkDefault) { | ||
90 | name = mkDefault i.name; | ||
91 | DHCP = mkForce (dhcpStr | ||
92 | (if i.useDHCP != null then i.useDHCP else false)); | ||
93 | address = forEach (interfaceIps i) | ||
94 | (ip: "${ip.address}/${toString ip.prefixLength}"); | ||
95 | networkConfig.IPv6PrivacyExtensions = "kernel"; | ||
96 | linkConfig = optionalAttrs (i.macAddress != null) { | ||
97 | MACAddress = i.macAddress; | ||
98 | } // optionalAttrs (i.mtu != null) { | ||
99 | MTUBytes = toString i.mtu; | ||
100 | }; | ||
101 | }]; | ||
102 | }))) | ||
103 | (mkMerge (flip mapAttrsToList cfg.bridges (name: bridge: { | ||
104 | netdevs."40-${name}" = { | ||
105 | netdevConfig = { | ||
106 | Name = name; | ||
107 | Kind = "bridge"; | ||
108 | }; | ||
109 | }; | ||
110 | networks = listToAttrs (forEach bridge.interfaces (bi: | ||
111 | nameValuePair "40-${bi}" (mkMerge [ (genericNetwork (mkOverride 999)) { | ||
112 | DHCP = mkOverride 0 (dhcpStr false); | ||
113 | networkConfig.Bridge = name; | ||
114 | } ]))); | ||
115 | }))) | ||
116 | (mkMerge (flip mapAttrsToList cfg.bonds (name: bond: { | ||
117 | netdevs."40-${name}" = { | ||
118 | netdevConfig = { | ||
119 | Name = name; | ||
120 | Kind = "bond"; | ||
121 | }; | ||
122 | bondConfig = let | ||
123 | # manual mapping as of 2017-02-03 | ||
124 | # man 5 systemd.netdev [BOND] | ||
125 | # to https://www.kernel.org/doc/Documentation/networking/bonding.txt | ||
126 | # driver options. | ||
127 | driverOptionMapping = let | ||
128 | trans = f: optName: { valTransform = f; optNames = [optName]; }; | ||
129 | simp = trans id; | ||
130 | ms = trans (v: v + "ms"); | ||
131 | in { | ||
132 | Mode = simp "mode"; | ||
133 | TransmitHashPolicy = simp "xmit_hash_policy"; | ||
134 | LACPTransmitRate = simp "lacp_rate"; | ||
135 | MIIMonitorSec = ms "miimon"; | ||
136 | UpDelaySec = ms "updelay"; | ||
137 | DownDelaySec = ms "downdelay"; | ||
138 | LearnPacketIntervalSec = simp "lp_interval"; | ||
139 | AdSelect = simp "ad_select"; | ||
140 | FailOverMACPolicy = simp "fail_over_mac"; | ||
141 | ARPValidate = simp "arp_validate"; | ||
142 | # apparently in ms for this value?! Upstream bug? | ||
143 | ARPIntervalSec = simp "arp_interval"; | ||
144 | ARPIPTargets = simp "arp_ip_target"; | ||
145 | ARPAllTargets = simp "arp_all_targets"; | ||
146 | PrimaryReselectPolicy = simp "primary_reselect"; | ||
147 | ResendIGMP = simp "resend_igmp"; | ||
148 | PacketsPerSlave = simp "packets_per_slave"; | ||
149 | GratuitousARP = { valTransform = id; | ||
150 | optNames = [ "num_grat_arp" "num_unsol_na" ]; }; | ||
151 | AllSlavesActive = simp "all_slaves_active"; | ||
152 | MinLinks = simp "min_links"; | ||
153 | }; | ||
154 | |||
155 | do = bond.driverOptions; | ||
156 | assertNoUnknownOption = let | ||
157 | knownOptions = flatten (mapAttrsToList (_: kOpts: kOpts.optNames) | ||
158 | driverOptionMapping); | ||
159 | # options that apparently don’t exist in the networkd config | ||
160 | unknownOptions = [ "primary" ]; | ||
161 | assertTrace = bool: msg: if bool then true else builtins.trace msg false; | ||
162 | in assert all (driverOpt: assertTrace | ||
163 | (elem driverOpt (knownOptions ++ unknownOptions)) | ||
164 | "The bond.driverOption `${driverOpt}` cannot be mapped to the list of known networkd bond options. Please add it to the mapping above the assert or to `unknownOptions` should it not exist in networkd.") | ||
165 | (mapAttrsToList (k: _: k) do); ""; | ||
166 | # get those driverOptions that have been set | ||
167 | filterSystemdOptions = filterAttrs (sysDOpt: kOpts: | ||
168 | any (kOpt: do ? ${kOpt}) kOpts.optNames); | ||
169 | # build final set of systemd options to bond values | ||
170 | buildOptionSet = mapAttrs (_: kOpts: with kOpts; | ||
171 | # we simply take the first set kernel bond option | ||
172 | # (one option has multiple names, which is silly) | ||
173 | head (map (optN: valTransform (do.${optN})) | ||
174 | # only map those that exist | ||
175 | (filter (o: do ? ${o}) optNames))); | ||
176 | in seq assertNoUnknownOption | ||
177 | (buildOptionSet (filterSystemdOptions driverOptionMapping)); | ||
178 | |||
179 | }; | ||
180 | |||
181 | networks = listToAttrs (forEach bond.interfaces (bi: | ||
182 | nameValuePair "40-${bi}" (mkMerge [ (genericNetwork (mkOverride 999)) { | ||
183 | DHCP = mkOverride 0 (dhcpStr false); | ||
184 | networkConfig.Bond = name; | ||
185 | } ]))); | ||
186 | }))) | ||
187 | (mkMerge (flip mapAttrsToList cfg.macvlans (name: macvlan: { | ||
188 | netdevs."40-${name}" = { | ||
189 | netdevConfig = { | ||
190 | Name = name; | ||
191 | Kind = "macvlan"; | ||
192 | }; | ||
193 | macvlanConfig = optionalAttrs (macvlan.mode != null) { Mode = macvlan.mode; }; | ||
194 | }; | ||
195 | networks."40-${macvlan.interface}" = (mkMerge [ (genericNetwork (mkOverride 999)) { | ||
196 | macvlan = [ name ]; | ||
197 | } ]); | ||
198 | }))) | ||
199 | (mkMerge (flip mapAttrsToList cfg.sits (name: sit: { | ||
200 | netdevs."40-${name}" = { | ||
201 | netdevConfig = { | ||
202 | Name = name; | ||
203 | Kind = "sit"; | ||
204 | }; | ||
205 | tunnelConfig = | ||
206 | (optionalAttrs (sit.remote != null) { | ||
207 | Remote = sit.remote; | ||
208 | }) // (optionalAttrs (sit.local != null) { | ||
209 | Local = sit.local; | ||
210 | }) // (optionalAttrs (sit.ttl != null) { | ||
211 | TTL = sit.ttl; | ||
212 | }); | ||
213 | }; | ||
214 | networks = mkIf (sit.dev != null) { | ||
215 | "40-${sit.dev}" = (mkMerge [ (genericNetwork (mkOverride 999)) { | ||
216 | tunnel = [ name ]; | ||
217 | } ]); | ||
218 | }; | ||
219 | }))) | ||
220 | (mkMerge (flip mapAttrsToList cfg.vlans (name: vlan: { | ||
221 | netdevs."40-${name}" = { | ||
222 | netdevConfig = { | ||
223 | Name = name; | ||
224 | Kind = "vlan"; | ||
225 | }; | ||
226 | vlanConfig.Id = vlan.id; | ||
227 | }; | ||
228 | networks."40-${vlan.interface}" = (mkMerge [ (genericNetwork (mkOverride 999)) { | ||
229 | vlan = [ name ]; | ||
230 | } ]); | ||
231 | }))) | ||
232 | ]; | ||
233 | |||
234 | # We need to prefill the slaved devices with networking options | ||
235 | # This forces the network interface creator to initialize slaves. | ||
236 | networking.interfaces = listToAttrs (map (i: nameValuePair i { }) slaves); | ||
237 | |||
238 | systemd.services = let | ||
239 | # We must escape interfaces due to the systemd interpretation | ||
240 | subsystemDevice = interface: | ||
241 | "sys-subsystem-net-devices-${escapeSystemdPath interface}.device"; | ||
242 | # support for creating openvswitch switches | ||
243 | createVswitchDevice = n: v: nameValuePair "${n}-netdev" | ||
244 | (let | ||
245 | deps = map subsystemDevice (attrNames (filterAttrs (_: config: config.type != "internal") v.interfaces)); | ||
246 | ofRules = pkgs.writeText "vswitch-${n}-openFlowRules" v.openFlowRules; | ||
247 | in | ||
248 | { description = "Open vSwitch Interface ${n}"; | ||
249 | wantedBy = [ "network.target" (subsystemDevice n) ]; | ||
250 | # and create bridge before systemd-networkd starts because it might create internal interfaces | ||
251 | before = [ "systemd-networkd.service" ]; | ||
252 | # shutdown the bridge when network is shutdown | ||
253 | partOf = [ "network.target" ]; | ||
254 | # requires ovs-vswitchd to be alive at all times | ||
255 | bindsTo = [ "ovs-vswitchd.service" ]; | ||
256 | # start switch after physical interfaces and vswitch daemon | ||
257 | after = [ "network-pre.target" "ovs-vswitchd.service" ] ++ deps; | ||
258 | wants = deps; # if one or more interface fails, the switch should continue to run | ||
259 | serviceConfig.Type = "oneshot"; | ||
260 | serviceConfig.RemainAfterExit = true; | ||
261 | path = [ pkgs.iproute2 config.virtualisation.vswitch.package ]; | ||
262 | preStart = '' | ||
263 | echo "Resetting Open vSwitch ${n}..." | ||
264 | ovs-vsctl --if-exists del-br ${n} -- add-br ${n} \ | ||
265 | -- set bridge ${n} protocols=${concatStringsSep "," v.supportedOpenFlowVersions} | ||
266 | ''; | ||
267 | script = '' | ||
268 | echo "Configuring Open vSwitch ${n}..." | ||
269 | ovs-vsctl ${concatStrings (mapAttrsToList (name: config: " -- add-port ${n} ${name}" + optionalString (config.vlan != null) " tag=${toString config.vlan}") v.interfaces)} \ | ||
270 | ${concatStrings (mapAttrsToList (name: config: optionalString (config.type != null) " -- set interface ${name} type=${config.type}") v.interfaces)} \ | ||
271 | ${concatMapStrings (x: " -- set-controller ${n} " + x) v.controllers} \ | ||
272 | ${concatMapStrings (x: " -- " + x) (splitString "\n" v.extraOvsctlCmds)} | ||
273 | |||
274 | |||
275 | echo "Adding OpenFlow rules for Open vSwitch ${n}..." | ||
276 | ovs-ofctl --protocols=${v.openFlowVersion} add-flows ${n} ${ofRules} | ||
277 | ''; | ||
278 | postStop = '' | ||
279 | echo "Cleaning Open vSwitch ${n}" | ||
280 | echo "Shuting down internal ${n} interface" | ||
281 | ip link set ${n} down || true | ||
282 | echo "Deleting flows for ${n}" | ||
283 | ovs-ofctl --protocols=${v.openFlowVersion} del-flows ${n} || true | ||
284 | echo "Deleting Open vSwitch ${n}" | ||
285 | ovs-vsctl --if-exists del-br ${n} || true | ||
286 | ''; | ||
287 | }); | ||
288 | in mapAttrs' createVswitchDevice cfg.vswitches | ||
289 | // { | ||
290 | "network-local-commands" = { | ||
291 | after = [ "systemd-networkd.service" ]; | ||
292 | bindsTo = [ "systemd-networkd.service" ]; | ||
293 | }; | ||
294 | }; | ||
295 | }; | ||
296 | |||
297 | } | ||
diff --git a/modules/networkd/default.nix b/modules/networkd/default.nix new file mode 100644 index 00000000..007f14c6 --- /dev/null +++ b/modules/networkd/default.nix | |||
@@ -0,0 +1,1686 @@ | |||
1 | { config, lib, pkgs, ... }: | ||
2 | |||
3 | with lib; | ||
4 | with import ./systemd-unit-options.nix { inherit config lib; }; | ||
5 | with import ./systemd-lib.nix { inherit config lib pkgs; }; | ||
6 | |||
7 | let | ||
8 | |||
9 | cfg = config.systemd.network; | ||
10 | |||
11 | check = { | ||
12 | |||
13 | link = { | ||
14 | |||
15 | sectionLink = checkUnitConfig "Link" [ | ||
16 | (assertOnlyFields [ | ||
17 | "Description" | ||
18 | "Alias" | ||
19 | "MACAddressPolicy" | ||
20 | "MACAddress" | ||
21 | "NamePolicy" | ||
22 | "Name" | ||
23 | "AlternativeNamesPolicy" | ||
24 | "AlternativeName" | ||
25 | "MTUBytes" | ||
26 | "BitsPerSecond" | ||
27 | "Duplex" | ||
28 | "AutoNegotiation" | ||
29 | "WakeOnLan" | ||
30 | "Port" | ||
31 | "Advertise" | ||
32 | "ReceiveChecksumOffload" | ||
33 | "TransmitChecksumOffload" | ||
34 | "TCPSegmentationOffload" | ||
35 | "TCP6SegmentationOffload" | ||
36 | "GenericSegmentationOffload" | ||
37 | "GenericReceiveOffload" | ||
38 | "LargeReceiveOffload" | ||
39 | "RxChannels" | ||
40 | "TxChannels" | ||
41 | "OtherChannels" | ||
42 | "CombinedChannels" | ||
43 | "RxBufferSize" | ||
44 | "TxBufferSize" | ||
45 | ]) | ||
46 | (assertValueOneOf "MACAddressPolicy" ["persistent" "random" "none"]) | ||
47 | (assertMacAddress "MACAddress") | ||
48 | (assertByteFormat "MTUBytes") | ||
49 | (assertByteFormat "BitsPerSecond") | ||
50 | (assertValueOneOf "Duplex" ["half" "full"]) | ||
51 | (assertValueOneOf "AutoNegotiation" boolValues) | ||
52 | (assertValueOneOf "WakeOnLan" ["phy" "unicast" "multicast" "broadcast" "arp" "magic" "secureon" "off"]) | ||
53 | (assertValueOneOf "Port" ["tp" "aui" "bnc" "mii" "fibre"]) | ||
54 | (assertValueOneOf "ReceiveChecksumOffload" boolValues) | ||
55 | (assertValueOneOf "TransmitChecksumOffload" boolValues) | ||
56 | (assertValueOneOf "TCPSegmentationOffload" boolValues) | ||
57 | (assertValueOneOf "TCP6SegmentationOffload" boolValues) | ||
58 | (assertValueOneOf "GenericSegmentationOffload" boolValues) | ||
59 | (assertValueOneOf "GenericReceiveOffload" boolValues) | ||
60 | (assertValueOneOf "LargeReceiveOffload" boolValues) | ||
61 | (assertInt "RxChannels") | ||
62 | (assertRange "RxChannels" 1 4294967295) | ||
63 | (assertInt "TxChannels") | ||
64 | (assertRange "TxChannels" 1 4294967295) | ||
65 | (assertInt "OtherChannels") | ||
66 | (assertRange "OtherChannels" 1 4294967295) | ||
67 | (assertInt "CombinedChannels") | ||
68 | (assertRange "CombinedChannels" 1 4294967295) | ||
69 | (assertInt "RxBufferSize") | ||
70 | (assertInt "TxBufferSize") | ||
71 | ]; | ||
72 | }; | ||
73 | |||
74 | netdev = let | ||
75 | |||
76 | tunChecks = [ | ||
77 | (assertOnlyFields [ | ||
78 | "MultiQueue" | ||
79 | "PacketInfo" | ||
80 | "VNetHeader" | ||
81 | "User" | ||
82 | "Group" | ||
83 | ]) | ||
84 | (assertValueOneOf "MultiQueue" boolValues) | ||
85 | (assertValueOneOf "PacketInfo" boolValues) | ||
86 | (assertValueOneOf "VNetHeader" boolValues) | ||
87 | ]; | ||
88 | in { | ||
89 | |||
90 | sectionNetdev = checkUnitConfig "Netdev" [ | ||
91 | (assertOnlyFields [ | ||
92 | "Description" | ||
93 | "Name" | ||
94 | "Kind" | ||
95 | "MTUBytes" | ||
96 | "MACAddress" | ||
97 | ]) | ||
98 | (assertHasField "Name") | ||
99 | (assertHasField "Kind") | ||
100 | (assertValueOneOf "Kind" [ | ||
101 | "bond" | ||
102 | "bridge" | ||
103 | "dummy" | ||
104 | "gre" | ||
105 | "gretap" | ||
106 | "erspan" | ||
107 | "ip6gre" | ||
108 | "ip6tnl" | ||
109 | "ip6gretap" | ||
110 | "ipip" | ||
111 | "ipvlan" | ||
112 | "macvlan" | ||
113 | "macvtap" | ||
114 | "sit" | ||
115 | "tap" | ||
116 | "tun" | ||
117 | "veth" | ||
118 | "vlan" | ||
119 | "vti" | ||
120 | "vti6" | ||
121 | "vxlan" | ||
122 | "geneve" | ||
123 | "l2tp" | ||
124 | "macsec" | ||
125 | "vrf" | ||
126 | "vcan" | ||
127 | "vxcan" | ||
128 | "wireguard" | ||
129 | "netdevsim" | ||
130 | "nlmon" | ||
131 | "fou" | ||
132 | "xfrm" | ||
133 | "ifb" | ||
134 | "bareudp" | ||
135 | "batadv" | ||
136 | ]) | ||
137 | (assertByteFormat "MTUBytes") | ||
138 | (assertMacAddress "MACAddress") | ||
139 | ]; | ||
140 | |||
141 | sectionVLAN = checkUnitConfig "VLAN" [ | ||
142 | (assertOnlyFields [ | ||
143 | "Id" | ||
144 | "GVRP" | ||
145 | "MVRP" | ||
146 | "LooseBinding" | ||
147 | "ReorderHeader" | ||
148 | ]) | ||
149 | (assertInt "Id") | ||
150 | (assertRange "Id" 0 4094) | ||
151 | (assertValueOneOf "GVRP" boolValues) | ||
152 | (assertValueOneOf "MVRP" boolValues) | ||
153 | (assertValueOneOf "LooseBinding" boolValues) | ||
154 | (assertValueOneOf "ReorderHeader" boolValues) | ||
155 | ]; | ||
156 | |||
157 | sectionMACVLAN = checkUnitConfig "MACVLAN" [ | ||
158 | (assertOnlyFields [ | ||
159 | "Mode" | ||
160 | ]) | ||
161 | (assertValueOneOf "Mode" ["private" "vepa" "bridge" "passthru"]) | ||
162 | ]; | ||
163 | |||
164 | sectionVXLAN = checkUnitConfig "VXLAN" [ | ||
165 | (assertOnlyFields [ | ||
166 | "VNI" | ||
167 | "Remote" | ||
168 | "Local" | ||
169 | "Group" | ||
170 | "TOS" | ||
171 | "TTL" | ||
172 | "MacLearning" | ||
173 | "FDBAgeingSec" | ||
174 | "MaximumFDBEntries" | ||
175 | "ReduceARPProxy" | ||
176 | "L2MissNotification" | ||
177 | "L3MissNotification" | ||
178 | "RouteShortCircuit" | ||
179 | "UDPChecksum" | ||
180 | "UDP6ZeroChecksumTx" | ||
181 | "UDP6ZeroChecksumRx" | ||
182 | "RemoteChecksumTx" | ||
183 | "RemoteChecksumRx" | ||
184 | "GroupPolicyExtension" | ||
185 | "GenericProtocolExtension" | ||
186 | "DestinationPort" | ||
187 | "PortRange" | ||
188 | "FlowLabel" | ||
189 | "IPDoNotFragment" | ||
190 | ]) | ||
191 | (assertInt "VNI") | ||
192 | (assertRange "VNI" 1 16777215) | ||
193 | (assertValueOneOf "MacLearning" boolValues) | ||
194 | (assertInt "MaximumFDBEntries") | ||
195 | (assertValueOneOf "ReduceARPProxy" boolValues) | ||
196 | (assertValueOneOf "L2MissNotification" boolValues) | ||
197 | (assertValueOneOf "L3MissNotification" boolValues) | ||
198 | (assertValueOneOf "RouteShortCircuit" boolValues) | ||
199 | (assertValueOneOf "UDPChecksum" boolValues) | ||
200 | (assertValueOneOf "UDP6ZeroChecksumTx" boolValues) | ||
201 | (assertValueOneOf "UDP6ZeroChecksumRx" boolValues) | ||
202 | (assertValueOneOf "RemoteChecksumTx" boolValues) | ||
203 | (assertValueOneOf "RemoteChecksumRx" boolValues) | ||
204 | (assertValueOneOf "GroupPolicyExtension" boolValues) | ||
205 | (assertValueOneOf "GenericProtocolExtension" boolValues) | ||
206 | (assertInt "FlowLabel") | ||
207 | (assertRange "FlowLabel" 0 1048575) | ||
208 | (assertValueOneOf "IPDoNotFragment" (boolValues + ["inherit"])) | ||
209 | ]; | ||
210 | |||
211 | sectionTunnel = checkUnitConfig "Tunnel" [ | ||
212 | (assertOnlyFields [ | ||
213 | "Local" | ||
214 | "Remote" | ||
215 | "TOS" | ||
216 | "TTL" | ||
217 | "DiscoverPathMTU" | ||
218 | "IPv6FlowLabel" | ||
219 | "CopyDSCP" | ||
220 | "EncapsulationLimit" | ||
221 | "Key" | ||
222 | "InputKey" | ||
223 | "OutputKey" | ||
224 | "Mode" | ||
225 | "Independent" | ||
226 | "AssignToLoopback" | ||
227 | "AllowLocalRemote" | ||
228 | "FooOverUDP" | ||
229 | "FOUDestinationPort" | ||
230 | "FOUSourcePort" | ||
231 | "Encapsulation" | ||
232 | "IPv6RapidDeploymentPrefix" | ||
233 | "ISATAP" | ||
234 | "SerializeTunneledPackets" | ||
235 | "ERSPANIndex" | ||
236 | ]) | ||
237 | (assertInt "TTL") | ||
238 | (assertRange "TTL" 0 255) | ||
239 | (assertValueOneOf "DiscoverPathMTU" boolValues) | ||
240 | (assertValueOneOf "CopyDSCP" boolValues) | ||
241 | (assertValueOneOf "Mode" ["ip6ip6" "ipip6" "any"]) | ||
242 | (assertValueOneOf "Independent" boolValues) | ||
243 | (assertValueOneOf "AssignToLoopback" boolValues) | ||
244 | (assertValueOneOf "AllowLocalRemote" boolValues) | ||
245 | (assertValueOneOf "FooOverUDP" boolValues) | ||
246 | (assertPort "FOUDestinationPort") | ||
247 | (assertPort "FOUSourcePort") | ||
248 | (assertValueOneOf "Encapsulation" ["FooOverUDP" "GenericUDPEncapsulation"]) | ||
249 | (assertValueOneOf "ISATAP" boolValues) | ||
250 | (assertValueOneOf "SerializeTunneledPackets" boolValues) | ||
251 | (assertInt "ERSPANIndex") | ||
252 | (assertRange "ERSPANIndex" 1 1048575) | ||
253 | ]; | ||
254 | |||
255 | sectionPeer = checkUnitConfig "Peer" [ | ||
256 | (assertOnlyFields [ | ||
257 | "Name" | ||
258 | "MACAddress" | ||
259 | ]) | ||
260 | (assertMacAddress "MACAddress") | ||
261 | ]; | ||
262 | |||
263 | sectionTun = checkUnitConfig "Tun" tunChecks; | ||
264 | |||
265 | sectionTap = checkUnitConfig "Tap" tunChecks; | ||
266 | |||
267 | # NOTE The PrivateKey directive is missing on purpose here, please | ||
268 | # do not add it to this list. The nix store is world-readable let's | ||
269 | # refrain ourselves from providing a footgun. | ||
270 | sectionWireGuard = checkUnitConfig "WireGuard" [ | ||
271 | (assertOnlyFields [ | ||
272 | "PrivateKeyFile" | ||
273 | "ListenPort" | ||
274 | "FirewallMark" | ||
275 | ]) | ||
276 | (assertInt "FirewallMark") | ||
277 | (assertRange "FirewallMark" 1 4294967295) | ||
278 | ]; | ||
279 | |||
280 | # NOTE The PresharedKey directive is missing on purpose here, please | ||
281 | # do not add it to this list. The nix store is world-readable,let's | ||
282 | # refrain ourselves from providing a footgun. | ||
283 | sectionWireGuardPeer = checkUnitConfig "WireGuardPeer" [ | ||
284 | (assertOnlyFields [ | ||
285 | "PublicKey" | ||
286 | "PresharedKeyFile" | ||
287 | "AllowedIPs" | ||
288 | "Endpoint" | ||
289 | "PersistentKeepalive" | ||
290 | ]) | ||
291 | (assertInt "PersistentKeepalive") | ||
292 | (assertRange "PersistentKeepalive" 0 65535) | ||
293 | ]; | ||
294 | |||
295 | sectionBond = checkUnitConfig "Bond" [ | ||
296 | (assertOnlyFields [ | ||
297 | "Mode" | ||
298 | "TransmitHashPolicy" | ||
299 | "LACPTransmitRate" | ||
300 | "MIIMonitorSec" | ||
301 | "UpDelaySec" | ||
302 | "DownDelaySec" | ||
303 | "LearnPacketIntervalSec" | ||
304 | "AdSelect" | ||
305 | "AdActorSystemPriority" | ||
306 | "AdUserPortKey" | ||
307 | "AdActorSystem" | ||
308 | "FailOverMACPolicy" | ||
309 | "ARPValidate" | ||
310 | "ARPIntervalSec" | ||
311 | "ARPIPTargets" | ||
312 | "ARPAllTargets" | ||
313 | "PrimaryReselectPolicy" | ||
314 | "ResendIGMP" | ||
315 | "PacketsPerSlave" | ||
316 | "GratuitousARP" | ||
317 | "AllSlavesActive" | ||
318 | "DynamicTransmitLoadBalancing" | ||
319 | "MinLinks" | ||
320 | ]) | ||
321 | (assertValueOneOf "Mode" [ | ||
322 | "balance-rr" | ||
323 | "active-backup" | ||
324 | "balance-xor" | ||
325 | "broadcast" | ||
326 | "802.3ad" | ||
327 | "balance-tlb" | ||
328 | "balance-alb" | ||
329 | ]) | ||
330 | (assertValueOneOf "TransmitHashPolicy" [ | ||
331 | "layer2" | ||
332 | "layer3+4" | ||
333 | "layer2+3" | ||
334 | "encap2+3" | ||
335 | "encap3+4" | ||
336 | ]) | ||
337 | (assertValueOneOf "LACPTransmitRate" ["slow" "fast"]) | ||
338 | (assertValueOneOf "AdSelect" ["stable" "bandwidth" "count"]) | ||
339 | (assertInt "AdActorSystemPriority") | ||
340 | (assertRange "AdActorSystemPriority" 1 65535) | ||
341 | (assertInt "AdUserPortKey") | ||
342 | (assertRange "AdUserPortKey" 0 1023) | ||
343 | (assertValueOneOf "FailOverMACPolicy" ["none" "active" "follow"]) | ||
344 | (assertValueOneOf "ARPValidate" ["none" "active" "backup" "all"]) | ||
345 | (assertValueOneOf "ARPAllTargets" ["any" "all"]) | ||
346 | (assertValueOneOf "PrimaryReselectPolicy" ["always" "better" "failure"]) | ||
347 | (assertInt "ResendIGMP") | ||
348 | (assertRange "ResendIGMP" 0 255) | ||
349 | (assertInt "PacketsPerSlave") | ||
350 | (assertRange "PacketsPerSlave" 0 65535) | ||
351 | (assertInt "GratuitousARP") | ||
352 | (assertRange "GratuitousARP" 0 255) | ||
353 | (assertValueOneOf "AllSlavesActive" boolValues) | ||
354 | (assertValueOneOf "DynamicTransmitLoadBalancing" boolValues) | ||
355 | (assertInt "MinLinks") | ||
356 | (assertMinimum "MinLinks" 0) | ||
357 | ]; | ||
358 | |||
359 | sectionXfrm = checkUnitConfig "Xfrm" [ | ||
360 | (assertOnlyFields [ | ||
361 | "InterfaceId" | ||
362 | "Independent" | ||
363 | ]) | ||
364 | (assertInt "InterfaceId") | ||
365 | (assertRange "InterfaceId" 1 4294967295) | ||
366 | (assertValueOneOf "Independent" boolValues) | ||
367 | ]; | ||
368 | |||
369 | sectionVRF = checkUnitConfig "VRF" [ | ||
370 | (assertOnlyFields [ | ||
371 | "Table" | ||
372 | ]) | ||
373 | (assertInt "Table") | ||
374 | (assertMinimum "Table" 0) | ||
375 | ]; | ||
376 | }; | ||
377 | |||
378 | network = { | ||
379 | |||
380 | sectionLink = checkUnitConfig "Link" [ | ||
381 | (assertOnlyFields [ | ||
382 | "MACAddress" | ||
383 | "MTUBytes" | ||
384 | "ARP" | ||
385 | "Multicast" | ||
386 | "AllMulticast" | ||
387 | "Unmanaged" | ||
388 | "RequiredForOnline" | ||
389 | "ActivationPolicy" | ||
390 | ]) | ||
391 | (assertMacAddress "MACAddress") | ||
392 | (assertByteFormat "MTUBytes") | ||
393 | (assertValueOneOf "ARP" boolValues) | ||
394 | (assertValueOneOf "Multicast" boolValues) | ||
395 | (assertValueOneOf "AllMulticast" boolValues) | ||
396 | (assertValueOneOf "Unmanaged" boolValues) | ||
397 | (assertValueOneOf "RequiredForOnline" (boolValues ++ [ | ||
398 | "missing" | ||
399 | "off" | ||
400 | "no-carrier" | ||
401 | "dormant" | ||
402 | "degraded-carrier" | ||
403 | "carrier" | ||
404 | "degraded" | ||
405 | "enslaved" | ||
406 | "routable" | ||
407 | ])) | ||
408 | (assertValueOneOf "ActivationPolicy" ([ | ||
409 | "up" | ||
410 | "always-up" | ||
411 | "manual" | ||
412 | "always-down" | ||
413 | "down" | ||
414 | "bound" | ||
415 | ])) | ||
416 | ]; | ||
417 | |||
418 | sectionNetwork = checkUnitConfig "Network" [ | ||
419 | (assertOnlyFields [ | ||
420 | "Description" | ||
421 | "DHCP" | ||
422 | "DHCPServer" | ||
423 | "LinkLocalAddressing" | ||
424 | "IPv4LLRoute" | ||
425 | "DefaultRouteOnDevice" | ||
426 | "IPv6Token" | ||
427 | "LLMNR" | ||
428 | "MulticastDNS" | ||
429 | "DNSOverTLS" | ||
430 | "DNSSEC" | ||
431 | "DNSSECNegativeTrustAnchors" | ||
432 | "LLDP" | ||
433 | "EmitLLDP" | ||
434 | "BindCarrier" | ||
435 | "Address" | ||
436 | "Gateway" | ||
437 | "DNS" | ||
438 | "Domains" | ||
439 | "DNSDefaultRoute" | ||
440 | "NTP" | ||
441 | "IPForward" | ||
442 | "IPMasquerade" | ||
443 | "IPv6PrivacyExtensions" | ||
444 | "IPv6AcceptRA" | ||
445 | "IPv6DuplicateAddressDetection" | ||
446 | "IPv6HopLimit" | ||
447 | "IPv4ProxyARP" | ||
448 | "IPv6ProxyNDP" | ||
449 | "IPv6ProxyNDPAddress" | ||
450 | "IPv6SendRA" | ||
451 | "DHCPv6PrefixDelegation" | ||
452 | "IPv6MTUBytes" | ||
453 | "BatmanAdvanced" | ||
454 | "Bridge" | ||
455 | "Bond" | ||
456 | "VRF" | ||
457 | "VLAN" | ||
458 | "IPVLAN" | ||
459 | "MACVLAN" | ||
460 | "VXLAN" | ||
461 | "Tunnel" | ||
462 | "MACsec" | ||
463 | "ActiveSlave" | ||
464 | "PrimarySlave" | ||
465 | "ConfigureWithoutCarrier" | ||
466 | "IgnoreCarrierLoss" | ||
467 | "Xfrm" | ||
468 | "KeepConfiguration" | ||
469 | ]) | ||
470 | # Note: For DHCP the values both, none, v4, v6 are deprecated | ||
471 | (assertValueOneOf "DHCP" ["yes" "no" "ipv4" "ipv6"]) | ||
472 | (assertValueOneOf "DHCPServer" boolValues) | ||
473 | (assertValueOneOf "LinkLocalAddressing" ["yes" "no" "ipv4" "ipv6" "fallback" "ipv4-fallback"]) | ||
474 | (assertValueOneOf "IPv4LLRoute" boolValues) | ||
475 | (assertValueOneOf "DefaultRouteOnDevice" boolValues) | ||
476 | (assertValueOneOf "LLMNR" (boolValues ++ ["resolve"])) | ||
477 | (assertValueOneOf "MulticastDNS" (boolValues ++ ["resolve"])) | ||
478 | (assertValueOneOf "DNSOverTLS" (boolValues ++ ["opportunistic"])) | ||
479 | (assertValueOneOf "DNSSEC" (boolValues ++ ["allow-downgrade"])) | ||
480 | (assertValueOneOf "LLDP" (boolValues ++ ["routers-only"])) | ||
481 | (assertValueOneOf "EmitLLDP" (boolValues ++ ["nearest-bridge" "non-tpmr-bridge" "customer-bridge"])) | ||
482 | (assertValueOneOf "DNSDefaultRoute" boolValues) | ||
483 | (assertValueOneOf "IPForward" (boolValues ++ ["ipv4" "ipv6"])) | ||
484 | (assertValueOneOf "IPMasquerade" boolValues) | ||
485 | (assertValueOneOf "IPv6PrivacyExtensions" (boolValues ++ ["prefer-public" "kernel"])) | ||
486 | (assertValueOneOf "IPv6AcceptRA" boolValues) | ||
487 | (assertInt "IPv6DuplicateAddressDetection") | ||
488 | (assertMinimum "IPv6DuplicateAddressDetection" 0) | ||
489 | (assertInt "IPv6HopLimit") | ||
490 | (assertMinimum "IPv6HopLimit" 0) | ||
491 | (assertValueOneOf "IPv4ProxyARP" boolValues) | ||
492 | (assertValueOneOf "IPv6ProxyNDP" boolValues) | ||
493 | (assertValueOneOf "IPv6SendRA" boolValues) | ||
494 | (assertValueOneOf "DHCPv6PrefixDelegation" boolValues) | ||
495 | (assertByteFormat "IPv6MTUBytes") | ||
496 | (assertValueOneOf "ActiveSlave" boolValues) | ||
497 | (assertValueOneOf "PrimarySlave" boolValues) | ||
498 | (assertValueOneOf "ConfigureWithoutCarrier" boolValues) | ||
499 | (assertValueOneOf "IgnoreCarrierLoss" boolValues) | ||
500 | (assertValueOneOf "KeepConfiguration" (boolValues ++ ["static" "dhcp-on-stop" "dhcp"])) | ||
501 | ]; | ||
502 | |||
503 | sectionAddress = checkUnitConfig "Address" [ | ||
504 | (assertOnlyFields [ | ||
505 | "Address" | ||
506 | "Peer" | ||
507 | "Broadcast" | ||
508 | "Label" | ||
509 | "PreferredLifetime" | ||
510 | "Scope" | ||
511 | "HomeAddress" | ||
512 | "DuplicateAddressDetection" | ||
513 | "ManageTemporaryAddress" | ||
514 | "AddPrefixRoute" | ||
515 | "AutoJoin" | ||
516 | ]) | ||
517 | (assertHasField "Address") | ||
518 | (assertValueOneOf "PreferredLifetime" ["forever" "infinity" "0" 0]) | ||
519 | (assertValueOneOf "HomeAddress" boolValues) | ||
520 | (assertValueOneOf "DuplicateAddressDetection" ["ipv4" "ipv6" "both" "none"]) | ||
521 | (assertValueOneOf "ManageTemporaryAddress" boolValues) | ||
522 | (assertValueOneOf "AddPrefixRoute" boolValues) | ||
523 | (assertValueOneOf "AutoJoin" boolValues) | ||
524 | ]; | ||
525 | |||
526 | sectionRoutingPolicyRule = checkUnitConfig "RoutingPolicyRule" [ | ||
527 | (assertOnlyFields [ | ||
528 | "TypeOfService" | ||
529 | "From" | ||
530 | "To" | ||
531 | "FirewallMark" | ||
532 | "Table" | ||
533 | "Priority" | ||
534 | "IncomingInterface" | ||
535 | "OutgoingInterface" | ||
536 | "SourcePort" | ||
537 | "DestinationPort" | ||
538 | "IPProtocol" | ||
539 | "InvertRule" | ||
540 | "Family" | ||
541 | "User" | ||
542 | "SuppressPrefixLength" | ||
543 | ]) | ||
544 | (assertInt "TypeOfService") | ||
545 | (assertRange "TypeOfService" 0 255) | ||
546 | (assertInt "FirewallMark") | ||
547 | (assertRange "FirewallMark" 1 4294967295) | ||
548 | (assertInt "Priority") | ||
549 | (assertPort "SourcePort") | ||
550 | (assertPort "DestinationPort") | ||
551 | (assertValueOneOf "InvertRule" boolValues) | ||
552 | (assertValueOneOf "Family" ["ipv4" "ipv6" "both"]) | ||
553 | (assertInt "SuppressPrefixLength") | ||
554 | (assertRange "SuppressPrefixLength" 0 128) | ||
555 | ]; | ||
556 | |||
557 | sectionRoute = checkUnitConfig "Route" [ | ||
558 | (assertOnlyFields [ | ||
559 | "Gateway" | ||
560 | "GatewayOnLink" | ||
561 | "Destination" | ||
562 | "Source" | ||
563 | "Metric" | ||
564 | "IPv6Preference" | ||
565 | "Scope" | ||
566 | "PreferredSource" | ||
567 | "Table" | ||
568 | "Protocol" | ||
569 | "Type" | ||
570 | "InitialCongestionWindow" | ||
571 | "InitialAdvertisedReceiveWindow" | ||
572 | "QuickAck" | ||
573 | "FastOpenNoCookie" | ||
574 | "TTLPropagate" | ||
575 | "MTUBytes" | ||
576 | "IPServiceType" | ||
577 | "MultiPathRoute" | ||
578 | ]) | ||
579 | (assertValueOneOf "GatewayOnLink" boolValues) | ||
580 | (assertInt "Metric") | ||
581 | (assertValueOneOf "IPv6Preference" ["low" "medium" "high"]) | ||
582 | (assertValueOneOf "Scope" ["global" "site" "link" "host" "nowhere"]) | ||
583 | (assertValueOneOf "Type" [ | ||
584 | "unicast" | ||
585 | "local" | ||
586 | "broadcast" | ||
587 | "anycast" | ||
588 | "multicast" | ||
589 | "blackhole" | ||
590 | "unreachable" | ||
591 | "prohibit" | ||
592 | "throw" | ||
593 | "nat" | ||
594 | "xresolve" | ||
595 | ]) | ||
596 | (assertValueOneOf "QuickAck" boolValues) | ||
597 | (assertValueOneOf "FastOpenNoCookie" boolValues) | ||
598 | (assertValueOneOf "TTLPropagate" boolValues) | ||
599 | (assertByteFormat "MTUBytes") | ||
600 | (assertValueOneOf "IPServiceType" ["CS6" "CS4"]) | ||
601 | ]; | ||
602 | |||
603 | sectionDHCPv4 = checkUnitConfig "DHCPv4" [ | ||
604 | (assertOnlyFields [ | ||
605 | "UseDNS" | ||
606 | "RoutesToDNS" | ||
607 | "UseNTP" | ||
608 | "UseSIP" | ||
609 | "UseMTU" | ||
610 | "Anonymize" | ||
611 | "SendHostname" | ||
612 | "UseHostname" | ||
613 | "Hostname" | ||
614 | "UseDomains" | ||
615 | "UseRoutes" | ||
616 | "UseTimezone" | ||
617 | "ClientIdentifier" | ||
618 | "VendorClassIdentifier" | ||
619 | "UserClass" | ||
620 | "MaxAttempts" | ||
621 | "DUIDType" | ||
622 | "DUIDRawData" | ||
623 | "IAID" | ||
624 | "RequestBroadcast" | ||
625 | "RouteMetric" | ||
626 | "RouteTable" | ||
627 | "RouteMTUBytes" | ||
628 | "ListenPort" | ||
629 | "SendRelease" | ||
630 | "SendDecline" | ||
631 | "BlackList" | ||
632 | "RequestOptions" | ||
633 | "SendOption" | ||
634 | ]) | ||
635 | (assertValueOneOf "UseDNS" boolValues) | ||
636 | (assertValueOneOf "RoutesToDNS" boolValues) | ||
637 | (assertValueOneOf "UseNTP" boolValues) | ||
638 | (assertValueOneOf "UseSIP" boolValues) | ||
639 | (assertValueOneOf "UseMTU" boolValues) | ||
640 | (assertValueOneOf "Anonymize" boolValues) | ||
641 | (assertValueOneOf "SendHostname" boolValues) | ||
642 | (assertValueOneOf "UseHostname" boolValues) | ||
643 | (assertValueOneOf "UseDomains" (boolValues ++ ["route"])) | ||
644 | (assertValueOneOf "UseRoutes" boolValues) | ||
645 | (assertValueOneOf "UseTimezone" boolValues) | ||
646 | (assertValueOneOf "ClientIdentifier" ["mac" "duid" "duid-only"]) | ||
647 | (assertInt "IAID") | ||
648 | (assertValueOneOf "RequestBroadcast" boolValues) | ||
649 | (assertInt "RouteMetric") | ||
650 | (assertInt "RouteTable") | ||
651 | (assertRange "RouteTable" 0 4294967295) | ||
652 | (assertByteFormat "RouteMTUBytes") | ||
653 | (assertPort "ListenPort") | ||
654 | (assertValueOneOf "SendRelease" boolValues) | ||
655 | (assertValueOneOf "SendDecline" boolValues) | ||
656 | ]; | ||
657 | |||
658 | sectionDHCPv6 = checkUnitConfig "DHCPv6" [ | ||
659 | (assertOnlyFields [ | ||
660 | "UseAddress" | ||
661 | "UseDNS" | ||
662 | "UseNTP" | ||
663 | "RouteMetric" | ||
664 | "RapidCommit" | ||
665 | "MUDURL" | ||
666 | "RequestOptions" | ||
667 | "SendVendorOption" | ||
668 | "ForceDHCPv6PDOtherInformation" | ||
669 | "PrefixDelegationHint" | ||
670 | "WithoutRA" | ||
671 | "SendOption" | ||
672 | "UserClass" | ||
673 | "VendorClass" | ||
674 | ]) | ||
675 | (assertValueOneOf "UseAddress" boolValues) | ||
676 | (assertValueOneOf "UseDNS" boolValues) | ||
677 | (assertValueOneOf "UseNTP" boolValues) | ||
678 | (assertInt "RouteMetric") | ||
679 | (assertValueOneOf "RapidCommit" boolValues) | ||
680 | (assertValueOneOf "ForceDHCPv6PDOtherInformation" boolValues) | ||
681 | (assertValueOneOf "WithoutRA" ["solicit" "information-request"]) | ||
682 | (assertRange "SendOption" 1 65536) | ||
683 | ]; | ||
684 | |||
685 | sectionDHCPv6PrefixDelegation = checkUnitConfig "DHCPv6PrefixDelegation" [ | ||
686 | (assertOnlyFields [ | ||
687 | "SubnetId" | ||
688 | "Announce" | ||
689 | "Assign" | ||
690 | "Token" | ||
691 | ]) | ||
692 | (assertValueOneOf "Announce" boolValues) | ||
693 | (assertValueOneOf "Assign" boolValues) | ||
694 | ]; | ||
695 | |||
696 | sectionIPv6AcceptRA = checkUnitConfig "IPv6AcceptRA" [ | ||
697 | (assertOnlyFields [ | ||
698 | "UseDNS" | ||
699 | "UseDomains" | ||
700 | "RouteTable" | ||
701 | "UseAutonomousPrefix" | ||
702 | "UseOnLinkPrefix" | ||
703 | "RouterDenyList" | ||
704 | "RouterAllowList" | ||
705 | "PrefixDenyList" | ||
706 | "PrefixAllowList" | ||
707 | "RouteDenyList" | ||
708 | "RouteAllowList" | ||
709 | "DHCPv6Client" | ||
710 | ]) | ||
711 | (assertValueOneOf "UseDNS" boolValues) | ||
712 | (assertValueOneOf "UseDomains" (boolValues ++ ["route"])) | ||
713 | (assertRange "RouteTable" 0 4294967295) | ||
714 | (assertValueOneOf "UseAutonomousPrefix" boolValues) | ||
715 | (assertValueOneOf "UseOnLinkPrefix" boolValues) | ||
716 | (assertValueOneOf "DHCPv6Client" (boolValues ++ ["always"])) | ||
717 | ]; | ||
718 | |||
719 | sectionDHCPServer = checkUnitConfig "DHCPServer" [ | ||
720 | (assertOnlyFields [ | ||
721 | "PoolOffset" | ||
722 | "PoolSize" | ||
723 | "DefaultLeaseTimeSec" | ||
724 | "MaxLeaseTimeSec" | ||
725 | "EmitDNS" | ||
726 | "DNS" | ||
727 | "EmitNTP" | ||
728 | "NTP" | ||
729 | "EmitSIP" | ||
730 | "SIP" | ||
731 | "EmitPOP3" | ||
732 | "POP3" | ||
733 | "EmitSMTP" | ||
734 | "SMTP" | ||
735 | "EmitLPR" | ||
736 | "LPR" | ||
737 | "EmitRouter" | ||
738 | "EmitTimezone" | ||
739 | "Timezone" | ||
740 | "SendOption" | ||
741 | "SendVendorOption" | ||
742 | ]) | ||
743 | (assertInt "PoolOffset") | ||
744 | (assertMinimum "PoolOffset" 0) | ||
745 | (assertInt "PoolSize") | ||
746 | (assertMinimum "PoolSize" 0) | ||
747 | (assertValueOneOf "EmitDNS" boolValues) | ||
748 | (assertValueOneOf "EmitNTP" boolValues) | ||
749 | (assertValueOneOf "EmitSIP" boolValues) | ||
750 | (assertValueOneOf "EmitPOP3" boolValues) | ||
751 | (assertValueOneOf "EmitSMTP" boolValues) | ||
752 | (assertValueOneOf "EmitLPR" boolValues) | ||
753 | (assertValueOneOf "EmitRouter" boolValues) | ||
754 | (assertValueOneOf "EmitTimezone" boolValues) | ||
755 | ]; | ||
756 | |||
757 | sectionIPv6SendRA = checkUnitConfig "IPv6SendRA" [ | ||
758 | (assertOnlyFields [ | ||
759 | "Managed" | ||
760 | "OtherInformation" | ||
761 | "RouterLifetimeSec" | ||
762 | "RouterPreference" | ||
763 | "EmitDNS" | ||
764 | "DNS" | ||
765 | "EmitDomains" | ||
766 | "Domains" | ||
767 | "DNSLifetimeSec" | ||
768 | ]) | ||
769 | (assertValueOneOf "Managed" boolValues) | ||
770 | (assertValueOneOf "OtherInformation" boolValues) | ||
771 | (assertValueOneOf "RouterPreference" ["high" "medium" "low" "normal" "default"]) | ||
772 | (assertValueOneOf "EmitDNS" boolValues) | ||
773 | (assertValueOneOf "EmitDomains" boolValues) | ||
774 | ]; | ||
775 | |||
776 | sectionIPv6Prefix = checkUnitConfig "IPv6Prefix" [ | ||
777 | (assertOnlyFields [ | ||
778 | "AddressAutoconfiguration" | ||
779 | "OnLink" | ||
780 | "Prefix" | ||
781 | "PreferredLifetimeSec" | ||
782 | "ValidLifetimeSec" | ||
783 | ]) | ||
784 | (assertValueOneOf "AddressAutoconfiguration" boolValues) | ||
785 | (assertValueOneOf "OnLink" boolValues) | ||
786 | ]; | ||
787 | |||
788 | }; | ||
789 | }; | ||
790 | |||
791 | commonNetworkOptions = { | ||
792 | |||
793 | enable = mkOption { | ||
794 | default = true; | ||
795 | type = types.bool; | ||
796 | description = '' | ||
797 | Whether to manage network configuration using <command>systemd-network</command>. | ||
798 | ''; | ||
799 | }; | ||
800 | |||
801 | matchConfig = mkOption { | ||
802 | default = {}; | ||
803 | example = { Name = "eth0"; }; | ||
804 | type = types.attrsOf unitOption; | ||
805 | description = '' | ||
806 | Each attribute in this set specifies an option in the | ||
807 | <literal>[Match]</literal> section of the unit. See | ||
808 | <citerefentry><refentrytitle>systemd.link</refentrytitle><manvolnum>5</manvolnum></citerefentry> | ||
809 | <citerefentry><refentrytitle>systemd.netdev</refentrytitle><manvolnum>5</manvolnum></citerefentry> | ||
810 | <citerefentry><refentrytitle>systemd.network</refentrytitle><manvolnum>5</manvolnum></citerefentry> | ||
811 | for details. | ||
812 | ''; | ||
813 | }; | ||
814 | |||
815 | extraConfig = mkOption { | ||
816 | default = ""; | ||
817 | type = types.lines; | ||
818 | description = "Extra configuration append to unit"; | ||
819 | }; | ||
820 | }; | ||
821 | |||
822 | linkOptions = commonNetworkOptions // { | ||
823 | # overwrite enable option from above | ||
824 | enable = mkOption { | ||
825 | default = true; | ||
826 | type = types.bool; | ||
827 | description = '' | ||
828 | Whether to enable this .link unit. It's handled by udev no matter if <command>systemd-networkd</command> is enabled or not | ||
829 | ''; | ||
830 | }; | ||
831 | |||
832 | linkConfig = mkOption { | ||
833 | default = {}; | ||
834 | example = { MACAddress = "00:ff:ee:aa:cc:dd"; }; | ||
835 | type = types.addCheck (types.attrsOf unitOption) check.link.sectionLink; | ||
836 | description = '' | ||
837 | Each attribute in this set specifies an option in the | ||
838 | <literal>[Link]</literal> section of the unit. See | ||
839 | <citerefentry><refentrytitle>systemd.link</refentrytitle> | ||
840 | <manvolnum>5</manvolnum></citerefentry> for details. | ||
841 | ''; | ||
842 | }; | ||
843 | |||
844 | }; | ||
845 | |||
846 | wireguardPeerOptions = { | ||
847 | options = { | ||
848 | wireguardPeerConfig = mkOption { | ||
849 | default = {}; | ||
850 | example = { }; | ||
851 | type = types.addCheck (types.attrsOf unitOption) check.netdev.sectionWireGuardPeer; | ||
852 | description = '' | ||
853 | Each attribute in this set specifies an option in the | ||
854 | <literal>[WireGuardPeer]</literal> section of the unit. See | ||
855 | <citerefentry><refentrytitle>systemd.network</refentrytitle> | ||
856 | <manvolnum>5</manvolnum></citerefentry> for details. | ||
857 | ''; | ||
858 | }; | ||
859 | }; | ||
860 | }; | ||
861 | |||
862 | netdevOptions = commonNetworkOptions // { | ||
863 | |||
864 | netdevConfig = mkOption { | ||
865 | default = {}; | ||
866 | example = { Name = "mybridge"; Kind = "bridge"; }; | ||
867 | type = types.addCheck (types.attrsOf unitOption) check.netdev.sectionNetdev; | ||
868 | description = '' | ||
869 | Each attribute in this set specifies an option in the | ||
870 | <literal>[Netdev]</literal> section of the unit. See | ||
871 | <citerefentry><refentrytitle>systemd.netdev</refentrytitle> | ||
872 | <manvolnum>5</manvolnum></citerefentry> for details. | ||
873 | ''; | ||
874 | }; | ||
875 | |||
876 | vlanConfig = mkOption { | ||
877 | default = {}; | ||
878 | example = { Id = 4; }; | ||
879 | type = types.addCheck (types.attrsOf unitOption) check.netdev.sectionVLAN; | ||
880 | description = '' | ||
881 | Each attribute in this set specifies an option in the | ||
882 | <literal>[VLAN]</literal> section of the unit. See | ||
883 | <citerefentry><refentrytitle>systemd.netdev</refentrytitle> | ||
884 | <manvolnum>5</manvolnum></citerefentry> for details. | ||
885 | ''; | ||
886 | }; | ||
887 | |||
888 | macvlanConfig = mkOption { | ||
889 | default = {}; | ||
890 | example = { Mode = "private"; }; | ||
891 | type = types.addCheck (types.attrsOf unitOption) check.netdev.sectionMACVLAN; | ||
892 | description = '' | ||
893 | Each attribute in this set specifies an option in the | ||
894 | <literal>[MACVLAN]</literal> section of the unit. See | ||
895 | <citerefentry><refentrytitle>systemd.netdev</refentrytitle> | ||
896 | <manvolnum>5</manvolnum></citerefentry> for details. | ||
897 | ''; | ||
898 | }; | ||
899 | |||
900 | vxlanConfig = mkOption { | ||
901 | default = {}; | ||
902 | example = { Id = "4"; }; | ||
903 | type = types.addCheck (types.attrsOf unitOption) check.netdev.sectionVXLAN; | ||
904 | description = '' | ||
905 | Each attribute in this set specifies an option in the | ||
906 | <literal>[VXLAN]</literal> section of the unit. See | ||
907 | <citerefentry><refentrytitle>systemd.netdev</refentrytitle> | ||
908 | <manvolnum>5</manvolnum></citerefentry> for details. | ||
909 | ''; | ||
910 | }; | ||
911 | |||
912 | tunnelConfig = mkOption { | ||
913 | default = {}; | ||
914 | example = { Remote = "192.168.1.1"; }; | ||
915 | type = types.addCheck (types.attrsOf unitOption) check.netdev.sectionTunnel; | ||
916 | description = '' | ||
917 | Each attribute in this set specifies an option in the | ||
918 | <literal>[Tunnel]</literal> section of the unit. See | ||
919 | <citerefentry><refentrytitle>systemd.netdev</refentrytitle> | ||
920 | <manvolnum>5</manvolnum></citerefentry> for details. | ||
921 | ''; | ||
922 | }; | ||
923 | |||
924 | peerConfig = mkOption { | ||
925 | default = {}; | ||
926 | example = { Name = "veth2"; }; | ||
927 | type = types.addCheck (types.attrsOf unitOption) check.netdev.sectionPeer; | ||
928 | description = '' | ||
929 | Each attribute in this set specifies an option in the | ||
930 | <literal>[Peer]</literal> section of the unit. See | ||
931 | <citerefentry><refentrytitle>systemd.netdev</refentrytitle> | ||
932 | <manvolnum>5</manvolnum></citerefentry> for details. | ||
933 | ''; | ||
934 | }; | ||
935 | |||
936 | tunConfig = mkOption { | ||
937 | default = {}; | ||
938 | example = { User = "openvpn"; }; | ||
939 | type = types.addCheck (types.attrsOf unitOption) check.netdev.sectionTun; | ||
940 | description = '' | ||
941 | Each attribute in this set specifies an option in the | ||
942 | <literal>[Tun]</literal> section of the unit. See | ||
943 | <citerefentry><refentrytitle>systemd.netdev</refentrytitle> | ||
944 | <manvolnum>5</manvolnum></citerefentry> for details. | ||
945 | ''; | ||
946 | }; | ||
947 | |||
948 | tapConfig = mkOption { | ||
949 | default = {}; | ||
950 | example = { User = "openvpn"; }; | ||
951 | type = types.addCheck (types.attrsOf unitOption) check.netdev.sectionTap; | ||
952 | description = '' | ||
953 | Each attribute in this set specifies an option in the | ||
954 | <literal>[Tap]</literal> section of the unit. See | ||
955 | <citerefentry><refentrytitle>systemd.netdev</refentrytitle> | ||
956 | <manvolnum>5</manvolnum></citerefentry> for details. | ||
957 | ''; | ||
958 | }; | ||
959 | |||
960 | wireguardConfig = mkOption { | ||
961 | default = {}; | ||
962 | example = { | ||
963 | PrivateKeyFile = "/etc/wireguard/secret.key"; | ||
964 | ListenPort = 51820; | ||
965 | FwMark = 42; | ||
966 | }; | ||
967 | type = types.addCheck (types.attrsOf unitOption) check.netdev.sectionWireGuard; | ||
968 | description = '' | ||
969 | Each attribute in this set specifies an option in the | ||
970 | <literal>[WireGuard]</literal> section of the unit. See | ||
971 | <citerefentry><refentrytitle>systemd.netdev</refentrytitle> | ||
972 | <manvolnum>5</manvolnum></citerefentry> for details. | ||
973 | Use <literal>PrivateKeyFile</literal> instead of | ||
974 | <literal>PrivateKey</literal>: the nix store is | ||
975 | world-readable. | ||
976 | ''; | ||
977 | }; | ||
978 | |||
979 | wireguardPeers = mkOption { | ||
980 | default = []; | ||
981 | example = [ { wireguardPeerConfig={ | ||
982 | Endpoint = "192.168.1.1:51820"; | ||
983 | PublicKey = "27s0OvaBBdHoJYkH9osZpjpgSOVNw+RaKfboT/Sfq0g="; | ||
984 | PresharedKeyFile = "/etc/wireguard/psk.key"; | ||
985 | AllowedIPs = [ "10.0.0.1/32" ]; | ||
986 | PersistentKeepalive = 15; | ||
987 | };}]; | ||
988 | type = with types; listOf (submodule wireguardPeerOptions); | ||
989 | description = '' | ||
990 | Each item in this array specifies an option in the | ||
991 | <literal>[WireGuardPeer]</literal> section of the unit. See | ||
992 | <citerefentry><refentrytitle>systemd.netdev</refentrytitle> | ||
993 | <manvolnum>5</manvolnum></citerefentry> for details. | ||
994 | Use <literal>PresharedKeyFile</literal> instead of | ||
995 | <literal>PresharedKey</literal>: the nix store is | ||
996 | world-readable. | ||
997 | ''; | ||
998 | }; | ||
999 | |||
1000 | bondConfig = mkOption { | ||
1001 | default = {}; | ||
1002 | example = { Mode = "802.3ad"; }; | ||
1003 | type = types.addCheck (types.attrsOf unitOption) check.netdev.sectionBond; | ||
1004 | description = '' | ||
1005 | Each attribute in this set specifies an option in the | ||
1006 | <literal>[Bond]</literal> section of the unit. See | ||
1007 | <citerefentry><refentrytitle>systemd.netdev</refentrytitle> | ||
1008 | <manvolnum>5</manvolnum></citerefentry> for details. | ||
1009 | ''; | ||
1010 | }; | ||
1011 | |||
1012 | xfrmConfig = mkOption { | ||
1013 | default = {}; | ||
1014 | example = { InterfaceId = 1; }; | ||
1015 | type = types.addCheck (types.attrsOf unitOption) check.netdev.sectionXfrm; | ||
1016 | description = '' | ||
1017 | Each attribute in this set specifies an option in the | ||
1018 | <literal>[Xfrm]</literal> section of the unit. See | ||
1019 | <citerefentry><refentrytitle>systemd.netdev</refentrytitle> | ||
1020 | <manvolnum>5</manvolnum></citerefentry> for details. | ||
1021 | ''; | ||
1022 | }; | ||
1023 | |||
1024 | vrfConfig = mkOption { | ||
1025 | default = {}; | ||
1026 | example = { Table = 2342; }; | ||
1027 | type = types.addCheck (types.attrsOf unitOption) check.netdev.sectionVRF; | ||
1028 | description = '' | ||
1029 | Each attribute in this set specifies an option in the | ||
1030 | <literal>[VRF]</literal> section of the unit. See | ||
1031 | <citerefentry><refentrytitle>systemd.netdev</refentrytitle> | ||
1032 | <manvolnum>5</manvolnum></citerefentry> for details. | ||
1033 | A detailed explanation about how VRFs work can be found in the | ||
1034 | <link xlink:href="https://www.kernel.org/doc/Documentation/networking/vrf.txt">kernel | ||
1035 | docs</link>. | ||
1036 | ''; | ||
1037 | }; | ||
1038 | |||
1039 | }; | ||
1040 | |||
1041 | addressOptions = { | ||
1042 | options = { | ||
1043 | addressConfig = mkOption { | ||
1044 | default = {}; | ||
1045 | example = { Address = "192.168.0.100/24"; }; | ||
1046 | type = types.addCheck (types.attrsOf unitOption) check.network.sectionAddress; | ||
1047 | description = '' | ||
1048 | Each attribute in this set specifies an option in the | ||
1049 | <literal>[Address]</literal> section of the unit. See | ||
1050 | <citerefentry><refentrytitle>systemd.network</refentrytitle> | ||
1051 | <manvolnum>5</manvolnum></citerefentry> for details. | ||
1052 | ''; | ||
1053 | }; | ||
1054 | }; | ||
1055 | }; | ||
1056 | |||
1057 | routingPolicyRulesOptions = { | ||
1058 | options = { | ||
1059 | routingPolicyRuleConfig = mkOption { | ||
1060 | default = { }; | ||
1061 | example = { routingPolicyRuleConfig = { Table = 10; IncomingInterface = "eth1"; Family = "both"; } ;}; | ||
1062 | type = types.addCheck (types.attrsOf unitOption) check.network.sectionRoutingPolicyRule; | ||
1063 | description = '' | ||
1064 | Each attribute in this set specifies an option in the | ||
1065 | <literal>[RoutingPolicyRule]</literal> section of the unit. See | ||
1066 | <citerefentry><refentrytitle>systemd.network</refentrytitle> | ||
1067 | <manvolnum>5</manvolnum></citerefentry> for details. | ||
1068 | ''; | ||
1069 | }; | ||
1070 | }; | ||
1071 | }; | ||
1072 | |||
1073 | routeOptions = { | ||
1074 | options = { | ||
1075 | routeConfig = mkOption { | ||
1076 | default = {}; | ||
1077 | example = { Gateway = "192.168.0.1"; }; | ||
1078 | type = types.addCheck (types.attrsOf unitOption) check.network.sectionRoute; | ||
1079 | description = '' | ||
1080 | Each attribute in this set specifies an option in the | ||
1081 | <literal>[Route]</literal> section of the unit. See | ||
1082 | <citerefentry><refentrytitle>systemd.network</refentrytitle> | ||
1083 | <manvolnum>5</manvolnum></citerefentry> for details. | ||
1084 | ''; | ||
1085 | }; | ||
1086 | }; | ||
1087 | }; | ||
1088 | |||
1089 | ipv6PrefixOptions = { | ||
1090 | options = { | ||
1091 | ipv6PrefixConfig = mkOption { | ||
1092 | default = {}; | ||
1093 | example = { Prefix = "fd00::/64"; }; | ||
1094 | type = types.addCheck (types.attrsOf unitOption) check.network.sectionIPv6Prefix; | ||
1095 | description = '' | ||
1096 | Each attribute in this set specifies an option in the | ||
1097 | <literal>[IPv6Prefix]</literal> section of the unit. See | ||
1098 | <citerefentry><refentrytitle>systemd.network</refentrytitle> | ||
1099 | <manvolnum>5</manvolnum></citerefentry> for details. | ||
1100 | ''; | ||
1101 | }; | ||
1102 | }; | ||
1103 | }; | ||
1104 | |||
1105 | networkOptions = commonNetworkOptions // { | ||
1106 | |||
1107 | linkConfig = mkOption { | ||
1108 | default = {}; | ||
1109 | example = { Unmanaged = true; }; | ||
1110 | type = types.addCheck (types.attrsOf unitOption) check.network.sectionLink; | ||
1111 | description = '' | ||
1112 | Each attribute in this set specifies an option in the | ||
1113 | <literal>[Link]</literal> section of the unit. See | ||
1114 | <citerefentry><refentrytitle>systemd.network</refentrytitle> | ||
1115 | <manvolnum>5</manvolnum></citerefentry> for details. | ||
1116 | ''; | ||
1117 | }; | ||
1118 | |||
1119 | networkConfig = mkOption { | ||
1120 | default = {}; | ||
1121 | example = { Description = "My Network"; }; | ||
1122 | type = types.addCheck (types.attrsOf unitOption) check.network.sectionNetwork; | ||
1123 | description = '' | ||
1124 | Each attribute in this set specifies an option in the | ||
1125 | <literal>[Network]</literal> section of the unit. See | ||
1126 | <citerefentry><refentrytitle>systemd.network</refentrytitle> | ||
1127 | <manvolnum>5</manvolnum></citerefentry> for details. | ||
1128 | ''; | ||
1129 | }; | ||
1130 | |||
1131 | # systemd.network.networks.*.dhcpConfig has been deprecated in favor of ….dhcpV4Config | ||
1132 | # Produce a nice warning message so users know it is gone. | ||
1133 | dhcpConfig = mkOption { | ||
1134 | visible = false; | ||
1135 | apply = _: throw "The option `systemd.network.networks.*.dhcpConfig` can no longer be used since it's been removed. Please use `systemd.network.networks.*.dhcpV4Config` instead."; | ||
1136 | }; | ||
1137 | |||
1138 | dhcpV4Config = mkOption { | ||
1139 | default = {}; | ||
1140 | example = { UseDNS = true; UseRoutes = true; }; | ||
1141 | type = types.addCheck (types.attrsOf unitOption) check.network.sectionDHCPv4; | ||
1142 | description = '' | ||
1143 | Each attribute in this set specifies an option in the | ||
1144 | <literal>[DHCPv4]</literal> section of the unit. See | ||
1145 | <citerefentry><refentrytitle>systemd.network</refentrytitle> | ||
1146 | <manvolnum>5</manvolnum></citerefentry> for details. | ||
1147 | ''; | ||
1148 | }; | ||
1149 | |||
1150 | dhcpV6Config = mkOption { | ||
1151 | default = {}; | ||
1152 | example = { UseDNS = true; UseRoutes = true; }; | ||
1153 | type = types.addCheck (types.attrsOf unitOption) check.network.sectionDHCPv6; | ||
1154 | description = '' | ||
1155 | Each attribute in this set specifies an option in the | ||
1156 | <literal>[DHCPv6]</literal> section of the unit. See | ||
1157 | <citerefentry><refentrytitle>systemd.network</refentrytitle> | ||
1158 | <manvolnum>5</manvolnum></citerefentry> for details. | ||
1159 | ''; | ||
1160 | }; | ||
1161 | |||
1162 | dhcpV6PrefixDelegationConfig = mkOption { | ||
1163 | default = {}; | ||
1164 | example = { SubnetId = "auto"; Announce = true; }; | ||
1165 | type = types.addCheck (types.attrsOf unitOption) check.network.sectionDHCPv6PrefixDelegation; | ||
1166 | description = '' | ||
1167 | Each attribute in this set specifies an option in the | ||
1168 | <literal>[DHCPv6PrefixDelegation]</literal> section of the unit. See | ||
1169 | <citerefentry><refentrytitle>systemd.network</refentrytitle> | ||
1170 | <manvolnum>5</manvolnum></citerefentry> for details. | ||
1171 | ''; | ||
1172 | }; | ||
1173 | |||
1174 | ipv6AcceptRAConfig = mkOption { | ||
1175 | default = {}; | ||
1176 | example = { UseDNS = true; DHCPv6Client = "always"; }; | ||
1177 | type = types.addCheck (types.attrsOf unitOption) check.network.sectionIPv6AcceptRA; | ||
1178 | description = '' | ||
1179 | Each attribute in this set specifies an option in the | ||
1180 | <literal>[IPv6AcceptRA]</literal> section of the unit. See | ||
1181 | <citerefentry><refentrytitle>systemd.network</refentrytitle> | ||
1182 | <manvolnum>5</manvolnum></citerefentry> for details. | ||
1183 | ''; | ||
1184 | }; | ||
1185 | |||
1186 | dhcpServerConfig = mkOption { | ||
1187 | default = {}; | ||
1188 | example = { PoolOffset = 50; EmitDNS = false; }; | ||
1189 | type = types.addCheck (types.attrsOf unitOption) check.network.sectionDHCPServer; | ||
1190 | description = '' | ||
1191 | Each attribute in this set specifies an option in the | ||
1192 | <literal>[DHCPServer]</literal> section of the unit. See | ||
1193 | <citerefentry><refentrytitle>systemd.network</refentrytitle> | ||
1194 | <manvolnum>5</manvolnum></citerefentry> for details. | ||
1195 | ''; | ||
1196 | }; | ||
1197 | |||
1198 | # systemd.network.networks.*.ipv6PrefixDelegationConfig has been deprecated | ||
1199 | # in 247 in favor of systemd.network.networks.*.ipv6SendRAConfig. | ||
1200 | ipv6PrefixDelegationConfig = mkOption { | ||
1201 | visible = false; | ||
1202 | apply = _: throw "The option `systemd.network.networks.*.ipv6PrefixDelegationConfig` has been replaced by `systemd.network.networks.*.ipv6SendRAConfig`."; | ||
1203 | }; | ||
1204 | |||
1205 | ipv6SendRAConfig = mkOption { | ||
1206 | default = {}; | ||
1207 | example = { EmitDNS = true; Managed = true; OtherInformation = true; }; | ||
1208 | type = types.addCheck (types.attrsOf unitOption) check.network.sectionIPv6SendRA; | ||
1209 | description = '' | ||
1210 | Each attribute in this set specifies an option in the | ||
1211 | <literal>[IPv6SendRA]</literal> section of the unit. See | ||
1212 | <citerefentry><refentrytitle>systemd.network</refentrytitle> | ||
1213 | <manvolnum>5</manvolnum></citerefentry> for details. | ||
1214 | ''; | ||
1215 | }; | ||
1216 | |||
1217 | ipv6Prefixes = mkOption { | ||
1218 | default = []; | ||
1219 | example = { AddressAutoconfiguration = true; OnLink = true; }; | ||
1220 | type = with types; listOf (submodule ipv6PrefixOptions); | ||
1221 | description = '' | ||
1222 | A list of ipv6Prefix sections to be added to the unit. See | ||
1223 | <citerefentry><refentrytitle>systemd.network</refentrytitle> | ||
1224 | <manvolnum>5</manvolnum></citerefentry> for details. | ||
1225 | ''; | ||
1226 | }; | ||
1227 | |||
1228 | name = mkOption { | ||
1229 | type = types.nullOr types.str; | ||
1230 | default = null; | ||
1231 | description = '' | ||
1232 | The name of the network interface to match against. | ||
1233 | ''; | ||
1234 | }; | ||
1235 | |||
1236 | DHCP = mkOption { | ||
1237 | type = types.nullOr types.str; | ||
1238 | default = null; | ||
1239 | description = '' | ||
1240 | Whether to enable DHCP on the interfaces matched. | ||
1241 | ''; | ||
1242 | }; | ||
1243 | |||
1244 | domains = mkOption { | ||
1245 | type = types.nullOr (types.listOf types.str); | ||
1246 | default = null; | ||
1247 | description = '' | ||
1248 | A list of domains to pass to the network config. | ||
1249 | ''; | ||
1250 | }; | ||
1251 | |||
1252 | address = mkOption { | ||
1253 | default = [ ]; | ||
1254 | type = types.listOf types.str; | ||
1255 | description = '' | ||
1256 | A list of addresses to be added to the network section of the | ||
1257 | unit. See <citerefentry><refentrytitle>systemd.network</refentrytitle> | ||
1258 | <manvolnum>5</manvolnum></citerefentry> for details. | ||
1259 | ''; | ||
1260 | }; | ||
1261 | |||
1262 | gateway = mkOption { | ||
1263 | default = [ ]; | ||
1264 | type = types.listOf types.str; | ||
1265 | description = '' | ||
1266 | A list of gateways to be added to the network section of the | ||
1267 | unit. See <citerefentry><refentrytitle>systemd.network</refentrytitle> | ||
1268 | <manvolnum>5</manvolnum></citerefentry> for details. | ||
1269 | ''; | ||
1270 | }; | ||
1271 | |||
1272 | dns = mkOption { | ||
1273 | default = [ ]; | ||
1274 | type = types.listOf types.str; | ||
1275 | description = '' | ||
1276 | A list of dns servers to be added to the network section of the | ||
1277 | unit. See <citerefentry><refentrytitle>systemd.network</refentrytitle> | ||
1278 | <manvolnum>5</manvolnum></citerefentry> for details. | ||
1279 | ''; | ||
1280 | }; | ||
1281 | |||
1282 | ntp = mkOption { | ||
1283 | default = [ ]; | ||
1284 | type = types.listOf types.str; | ||
1285 | description = '' | ||
1286 | A list of ntp servers to be added to the network section of the | ||
1287 | unit. See <citerefentry><refentrytitle>systemd.network</refentrytitle> | ||
1288 | <manvolnum>5</manvolnum></citerefentry> for details. | ||
1289 | ''; | ||
1290 | }; | ||
1291 | |||
1292 | bridge = mkOption { | ||
1293 | default = [ ]; | ||
1294 | type = types.listOf types.str; | ||
1295 | description = '' | ||
1296 | A list of bridge interfaces to be added to the network section of the | ||
1297 | unit. See <citerefentry><refentrytitle>systemd.network</refentrytitle> | ||
1298 | <manvolnum>5</manvolnum></citerefentry> for details. | ||
1299 | ''; | ||
1300 | }; | ||
1301 | |||
1302 | bond = mkOption { | ||
1303 | default = [ ]; | ||
1304 | type = types.listOf types.str; | ||
1305 | description = '' | ||
1306 | A list of bond interfaces to be added to the network section of the | ||
1307 | unit. See <citerefentry><refentrytitle>systemd.network</refentrytitle> | ||
1308 | <manvolnum>5</manvolnum></citerefentry> for details. | ||
1309 | ''; | ||
1310 | }; | ||
1311 | |||
1312 | vrf = mkOption { | ||
1313 | default = [ ]; | ||
1314 | type = types.listOf types.str; | ||
1315 | description = '' | ||
1316 | A list of vrf interfaces to be added to the network section of the | ||
1317 | unit. See <citerefentry><refentrytitle>systemd.network</refentrytitle> | ||
1318 | <manvolnum>5</manvolnum></citerefentry> for details. | ||
1319 | ''; | ||
1320 | }; | ||
1321 | |||
1322 | vlan = mkOption { | ||
1323 | default = [ ]; | ||
1324 | type = types.listOf types.str; | ||
1325 | description = '' | ||
1326 | A list of vlan interfaces to be added to the network section of the | ||
1327 | unit. See <citerefentry><refentrytitle>systemd.network</refentrytitle> | ||
1328 | <manvolnum>5</manvolnum></citerefentry> for details. | ||
1329 | ''; | ||
1330 | }; | ||
1331 | |||
1332 | macvlan = mkOption { | ||
1333 | default = [ ]; | ||
1334 | type = types.listOf types.str; | ||
1335 | description = '' | ||
1336 | A list of macvlan interfaces to be added to the network section of the | ||
1337 | unit. See <citerefentry><refentrytitle>systemd.network</refentrytitle> | ||
1338 | <manvolnum>5</manvolnum></citerefentry> for details. | ||
1339 | ''; | ||
1340 | }; | ||
1341 | |||
1342 | vxlan = mkOption { | ||
1343 | default = [ ]; | ||
1344 | type = types.listOf types.str; | ||
1345 | description = '' | ||
1346 | A list of vxlan interfaces to be added to the network section of the | ||
1347 | unit. See <citerefentry><refentrytitle>systemd.network</refentrytitle> | ||
1348 | <manvolnum>5</manvolnum></citerefentry> for details. | ||
1349 | ''; | ||
1350 | }; | ||
1351 | |||
1352 | tunnel = mkOption { | ||
1353 | default = [ ]; | ||
1354 | type = types.listOf types.str; | ||
1355 | description = '' | ||
1356 | A list of tunnel interfaces to be added to the network section of the | ||
1357 | unit. See <citerefentry><refentrytitle>systemd.network</refentrytitle> | ||
1358 | <manvolnum>5</manvolnum></citerefentry> for details. | ||
1359 | ''; | ||
1360 | }; | ||
1361 | |||
1362 | xfrm = mkOption { | ||
1363 | default = [ ]; | ||
1364 | type = types.listOf types.str; | ||
1365 | description = '' | ||
1366 | A list of xfrm interfaces to be added to the network section of the | ||
1367 | unit. See <citerefentry><refentrytitle>systemd.network</refentrytitle> | ||
1368 | <manvolnum>5</manvolnum></citerefentry> for details. | ||
1369 | ''; | ||
1370 | }; | ||
1371 | |||
1372 | addresses = mkOption { | ||
1373 | default = [ ]; | ||
1374 | type = with types; listOf (submodule addressOptions); | ||
1375 | description = '' | ||
1376 | A list of address sections to be added to the unit. See | ||
1377 | <citerefentry><refentrytitle>systemd.network</refentrytitle> | ||
1378 | <manvolnum>5</manvolnum></citerefentry> for details. | ||
1379 | ''; | ||
1380 | }; | ||
1381 | |||
1382 | routingPolicyRules = mkOption { | ||
1383 | default = [ ]; | ||
1384 | type = with types; listOf (submodule routingPolicyRulesOptions); | ||
1385 | description = '' | ||
1386 | A list of routing policy rules sections to be added to the unit. See | ||
1387 | <citerefentry><refentrytitle>systemd.network</refentrytitle> | ||
1388 | <manvolnum>5</manvolnum></citerefentry> for details. | ||
1389 | ''; | ||
1390 | }; | ||
1391 | |||
1392 | routes = mkOption { | ||
1393 | default = [ ]; | ||
1394 | type = with types; listOf (submodule routeOptions); | ||
1395 | description = '' | ||
1396 | A list of route sections to be added to the unit. See | ||
1397 | <citerefentry><refentrytitle>systemd.network</refentrytitle> | ||
1398 | <manvolnum>5</manvolnum></citerefentry> for details. | ||
1399 | ''; | ||
1400 | }; | ||
1401 | |||
1402 | }; | ||
1403 | |||
1404 | networkConfig = { config, ... }: { | ||
1405 | config = { | ||
1406 | matchConfig = optionalAttrs (config.name != null) { | ||
1407 | Name = config.name; | ||
1408 | }; | ||
1409 | networkConfig = optionalAttrs (config.DHCP != null) { | ||
1410 | DHCP = config.DHCP; | ||
1411 | } // optionalAttrs (config.domains != null) { | ||
1412 | Domains = concatStringsSep " " config.domains; | ||
1413 | }; | ||
1414 | }; | ||
1415 | }; | ||
1416 | |||
1417 | commonMatchText = def: optionalString (def.matchConfig != { }) '' | ||
1418 | [Match] | ||
1419 | ${attrsToSection def.matchConfig} | ||
1420 | ''; | ||
1421 | |||
1422 | linkToUnit = name: def: | ||
1423 | { inherit (def) enable; | ||
1424 | text = commonMatchText def | ||
1425 | + '' | ||
1426 | [Link] | ||
1427 | ${attrsToSection def.linkConfig} | ||
1428 | '' | ||
1429 | + def.extraConfig; | ||
1430 | }; | ||
1431 | |||
1432 | netdevToUnit = name: def: | ||
1433 | { inherit (def) enable; | ||
1434 | text = commonMatchText def | ||
1435 | + '' | ||
1436 | [NetDev] | ||
1437 | ${attrsToSection def.netdevConfig} | ||
1438 | '' | ||
1439 | + optionalString (def.vlanConfig != { }) '' | ||
1440 | [VLAN] | ||
1441 | ${attrsToSection def.vlanConfig} | ||
1442 | '' | ||
1443 | + optionalString (def.macvlanConfig != { }) '' | ||
1444 | [MACVLAN] | ||
1445 | ${attrsToSection def.macvlanConfig} | ||
1446 | '' | ||
1447 | + optionalString (def.vxlanConfig != { }) '' | ||
1448 | [VXLAN] | ||
1449 | ${attrsToSection def.vxlanConfig} | ||
1450 | '' | ||
1451 | + optionalString (def.tunnelConfig != { }) '' | ||
1452 | [Tunnel] | ||
1453 | ${attrsToSection def.tunnelConfig} | ||
1454 | '' | ||
1455 | + optionalString (def.peerConfig != { }) '' | ||
1456 | [Peer] | ||
1457 | ${attrsToSection def.peerConfig} | ||
1458 | '' | ||
1459 | + optionalString (def.tunConfig != { }) '' | ||
1460 | [Tun] | ||
1461 | ${attrsToSection def.tunConfig} | ||
1462 | '' | ||
1463 | + optionalString (def.tapConfig != { }) '' | ||
1464 | [Tap] | ||
1465 | ${attrsToSection def.tapConfig} | ||
1466 | '' | ||
1467 | + optionalString (def.wireguardConfig != { }) '' | ||
1468 | [WireGuard] | ||
1469 | ${attrsToSection def.wireguardConfig} | ||
1470 | '' | ||
1471 | + flip concatMapStrings def.wireguardPeers (x: '' | ||
1472 | [WireGuardPeer] | ||
1473 | ${attrsToSection x.wireguardPeerConfig} | ||
1474 | '') | ||
1475 | + optionalString (def.bondConfig != { }) '' | ||
1476 | [Bond] | ||
1477 | ${attrsToSection def.bondConfig} | ||
1478 | '' | ||
1479 | + optionalString (def.xfrmConfig != { }) '' | ||
1480 | [Xfrm] | ||
1481 | ${attrsToSection def.xfrmConfig} | ||
1482 | '' | ||
1483 | + optionalString (def.vrfConfig != { }) '' | ||
1484 | [VRF] | ||
1485 | ${attrsToSection def.vrfConfig} | ||
1486 | '' | ||
1487 | + def.extraConfig; | ||
1488 | }; | ||
1489 | |||
1490 | networkToUnit = name: def: | ||
1491 | { inherit (def) enable; | ||
1492 | text = commonMatchText def | ||
1493 | + optionalString (def.linkConfig != { }) '' | ||
1494 | [Link] | ||
1495 | ${attrsToSection def.linkConfig} | ||
1496 | '' | ||
1497 | + '' | ||
1498 | [Network] | ||
1499 | '' | ||
1500 | + attrsToSection def.networkConfig | ||
1501 | + optionalString (def.address != [ ]) '' | ||
1502 | ${concatStringsSep "\n" (map (s: "Address=${s}") def.address)} | ||
1503 | '' | ||
1504 | + optionalString (def.gateway != [ ]) '' | ||
1505 | ${concatStringsSep "\n" (map (s: "Gateway=${s}") def.gateway)} | ||
1506 | '' | ||
1507 | + optionalString (def.dns != [ ]) '' | ||
1508 | ${concatStringsSep "\n" (map (s: "DNS=${s}") def.dns)} | ||
1509 | '' | ||
1510 | + optionalString (def.ntp != [ ]) '' | ||
1511 | ${concatStringsSep "\n" (map (s: "NTP=${s}") def.ntp)} | ||
1512 | '' | ||
1513 | + optionalString (def.bridge != [ ]) '' | ||
1514 | ${concatStringsSep "\n" (map (s: "Bridge=${s}") def.bridge)} | ||
1515 | '' | ||
1516 | + optionalString (def.bond != [ ]) '' | ||
1517 | ${concatStringsSep "\n" (map (s: "Bond=${s}") def.bond)} | ||
1518 | '' | ||
1519 | + optionalString (def.vrf != [ ]) '' | ||
1520 | ${concatStringsSep "\n" (map (s: "VRF=${s}") def.vrf)} | ||
1521 | '' | ||
1522 | + optionalString (def.vlan != [ ]) '' | ||
1523 | ${concatStringsSep "\n" (map (s: "VLAN=${s}") def.vlan)} | ||
1524 | '' | ||
1525 | + optionalString (def.macvlan != [ ]) '' | ||
1526 | ${concatStringsSep "\n" (map (s: "MACVLAN=${s}") def.macvlan)} | ||
1527 | '' | ||
1528 | + optionalString (def.vxlan != [ ]) '' | ||
1529 | ${concatStringsSep "\n" (map (s: "VXLAN=${s}") def.vxlan)} | ||
1530 | '' | ||
1531 | + optionalString (def.tunnel != [ ]) '' | ||
1532 | ${concatStringsSep "\n" (map (s: "Tunnel=${s}") def.tunnel)} | ||
1533 | '' | ||
1534 | + optionalString (def.xfrm != [ ]) '' | ||
1535 | ${concatStringsSep "\n" (map (s: "Xfrm=${s}") def.xfrm)} | ||
1536 | '' | ||
1537 | + '' | ||
1538 | |||
1539 | '' | ||
1540 | + flip concatMapStrings def.addresses (x: '' | ||
1541 | [Address] | ||
1542 | ${attrsToSection x.addressConfig} | ||
1543 | '') | ||
1544 | + flip concatMapStrings def.routingPolicyRules (x: '' | ||
1545 | [RoutingPolicyRule] | ||
1546 | ${attrsToSection x.routingPolicyRuleConfig} | ||
1547 | '') | ||
1548 | + flip concatMapStrings def.routes (x: '' | ||
1549 | [Route] | ||
1550 | ${attrsToSection x.routeConfig} | ||
1551 | '') | ||
1552 | + optionalString (def.dhcpV4Config != { }) '' | ||
1553 | [DHCPv4] | ||
1554 | ${attrsToSection def.dhcpV4Config} | ||
1555 | '' | ||
1556 | + optionalString (def.dhcpV6Config != { }) '' | ||
1557 | [DHCPv6] | ||
1558 | ${attrsToSection def.dhcpV6Config} | ||
1559 | '' | ||
1560 | + optionalString (def.dhcpV6PrefixDelegationConfig != { }) '' | ||
1561 | [DHCPv6PrefixDelegation] | ||
1562 | ${attrsToSection def.dhcpV6PrefixDelegationConfig} | ||
1563 | '' | ||
1564 | + optionalString (def.ipv6AcceptRAConfig != { }) '' | ||
1565 | [IPv6AcceptRA] | ||
1566 | ${attrsToSection def.ipv6AcceptRAConfig} | ||
1567 | '' | ||
1568 | + optionalString (def.dhcpServerConfig != { }) '' | ||
1569 | [DHCPServer] | ||
1570 | ${attrsToSection def.dhcpServerConfig} | ||
1571 | '' | ||
1572 | + optionalString (def.ipv6SendRAConfig != { }) '' | ||
1573 | [IPv6SendRA] | ||
1574 | ${attrsToSection def.ipv6SendRAConfig} | ||
1575 | '' | ||
1576 | + flip concatMapStrings def.ipv6Prefixes (x: '' | ||
1577 | [IPv6Prefix] | ||
1578 | ${attrsToSection x.ipv6PrefixConfig} | ||
1579 | '') | ||
1580 | + def.extraConfig; | ||
1581 | }; | ||
1582 | |||
1583 | unitFiles = listToAttrs (map (name: { | ||
1584 | name = "systemd/network/${name}"; | ||
1585 | value.source = "${cfg.units.${name}.unit}/${name}"; | ||
1586 | }) (attrNames cfg.units)); | ||
1587 | in | ||
1588 | |||
1589 | { | ||
1590 | disabledModules = [ "system/boot/networkd.nix" ]; | ||
1591 | |||
1592 | options = { | ||
1593 | |||
1594 | systemd.network.enable = mkOption { | ||
1595 | default = false; | ||
1596 | type = types.bool; | ||
1597 | description = '' | ||
1598 | Whether to enable networkd or not. | ||
1599 | ''; | ||
1600 | }; | ||
1601 | |||
1602 | systemd.network.links = mkOption { | ||
1603 | default = {}; | ||
1604 | type = with types; attrsOf (submodule [ { options = linkOptions; } ]); | ||
1605 | description = "Definition of systemd network links."; | ||
1606 | }; | ||
1607 | |||
1608 | systemd.network.netdevs = mkOption { | ||
1609 | default = {}; | ||
1610 | type = with types; attrsOf (submodule [ { options = netdevOptions; } ]); | ||
1611 | description = "Definition of systemd network devices."; | ||
1612 | }; | ||
1613 | |||
1614 | systemd.network.networks = mkOption { | ||
1615 | default = {}; | ||
1616 | type = with types; attrsOf (submodule [ { options = networkOptions; } networkConfig ]); | ||
1617 | description = "Definition of systemd networks."; | ||
1618 | }; | ||
1619 | |||
1620 | systemd.network.units = mkOption { | ||
1621 | description = "Definition of networkd units."; | ||
1622 | default = {}; | ||
1623 | internal = true; | ||
1624 | type = with types; attrsOf (submodule ( | ||
1625 | { name, config, ... }: | ||
1626 | { options = mapAttrs (_: x: x // { internal = true; }) concreteUnitOptions; | ||
1627 | config = { | ||
1628 | unit = mkDefault (makeUnit name config); | ||
1629 | }; | ||
1630 | })); | ||
1631 | }; | ||
1632 | |||
1633 | }; | ||
1634 | |||
1635 | config = mkMerge [ | ||
1636 | |||
1637 | # .link units are honored by udev, no matter if systemd-networkd is enabled or not. | ||
1638 | { | ||
1639 | systemd.network.units = mapAttrs' (n: v: nameValuePair "${n}.link" (linkToUnit n v)) cfg.links; | ||
1640 | environment.etc = unitFiles; | ||
1641 | } | ||
1642 | |||
1643 | (mkIf config.systemd.network.enable { | ||
1644 | |||
1645 | users.users.systemd-network.group = "systemd-network"; | ||
1646 | |||
1647 | systemd.additionalUpstreamSystemUnits = [ | ||
1648 | "systemd-networkd-wait-online.service" | ||
1649 | "systemd-networkd.service" | ||
1650 | "systemd-networkd.socket" | ||
1651 | ]; | ||
1652 | |||
1653 | systemd.network.units = mapAttrs' (n: v: nameValuePair "${n}.netdev" (netdevToUnit n v)) cfg.netdevs | ||
1654 | // mapAttrs' (n: v: nameValuePair "${n}.network" (networkToUnit n v)) cfg.networks; | ||
1655 | |||
1656 | # systemd-networkd is socket-activated by kernel netlink route change | ||
1657 | # messages. It is important to have systemd buffer those on behalf of | ||
1658 | # networkd. | ||
1659 | systemd.sockets.systemd-networkd.wantedBy = [ "sockets.target" ]; | ||
1660 | |||
1661 | systemd.services.systemd-networkd = { | ||
1662 | wantedBy = [ "multi-user.target" ]; | ||
1663 | aliases = [ "dbus-org.freedesktop.network1.service" ]; | ||
1664 | restartTriggers = map (x: x.source) (attrValues unitFiles); | ||
1665 | }; | ||
1666 | |||
1667 | systemd.services.systemd-networkd-wait-online = { | ||
1668 | wantedBy = [ "network-online.target" ]; | ||
1669 | }; | ||
1670 | |||
1671 | systemd.services."systemd-network-wait-online@" = { | ||
1672 | description = "Wait for Network Interface %I to be Configured"; | ||
1673 | conflicts = [ "shutdown.target" ]; | ||
1674 | requisite = [ "systemd-networkd.service" ]; | ||
1675 | after = [ "systemd-networkd.service" ]; | ||
1676 | serviceConfig = { | ||
1677 | Type = "oneshot"; | ||
1678 | RemainAfterExit = true; | ||
1679 | ExecStart = "${config.systemd.package}/lib/systemd/systemd-networkd-wait-online -i %I"; | ||
1680 | }; | ||
1681 | }; | ||
1682 | |||
1683 | services.resolved.enable = mkDefault true; | ||
1684 | }) | ||
1685 | ]; | ||
1686 | } | ||
diff --git a/modules/networkd/systemd-lib.nix b/modules/networkd/systemd-lib.nix new file mode 100644 index 00000000..2dbf1503 --- /dev/null +++ b/modules/networkd/systemd-lib.nix | |||
@@ -0,0 +1,237 @@ | |||
1 | { config, lib, pkgs }: | ||
2 | |||
3 | with lib; | ||
4 | |||
5 | let | ||
6 | cfg = config.systemd; | ||
7 | lndir = "${pkgs.xorg.lndir}/bin/lndir"; | ||
8 | in rec { | ||
9 | |||
10 | shellEscape = s: (replaceChars [ "\\" ] [ "\\\\" ] s); | ||
11 | |||
12 | mkPathSafeName = lib.replaceChars ["@" ":" "\\" "[" "]"] ["-" "-" "-" "" ""]; | ||
13 | |||
14 | makeUnit = name: unit: | ||
15 | if unit.enable then | ||
16 | pkgs.runCommand "unit-${mkPathSafeName name}" | ||
17 | { preferLocalBuild = true; | ||
18 | allowSubstitutes = false; | ||
19 | inherit (unit) text; | ||
20 | } | ||
21 | '' | ||
22 | mkdir -p $out | ||
23 | echo -n "$text" > $out/${shellEscape name} | ||
24 | '' | ||
25 | else | ||
26 | pkgs.runCommand "unit-${mkPathSafeName name}-disabled" | ||
27 | { preferLocalBuild = true; | ||
28 | allowSubstitutes = false; | ||
29 | } | ||
30 | '' | ||
31 | mkdir -p $out | ||
32 | ln -s /dev/null $out/${shellEscape name} | ||
33 | ''; | ||
34 | |||
35 | boolValues = [true false "yes" "no"]; | ||
36 | |||
37 | digits = map toString (range 0 9); | ||
38 | |||
39 | isByteFormat = s: | ||
40 | let | ||
41 | l = reverseList (stringToCharacters s); | ||
42 | suffix = head l; | ||
43 | nums = tail l; | ||
44 | in elem suffix (["K" "M" "G" "T"] ++ digits) | ||
45 | && all (num: elem num digits) nums; | ||
46 | |||
47 | assertByteFormat = name: group: attr: | ||
48 | optional (attr ? ${name} && ! isByteFormat attr.${name}) | ||
49 | "Systemd ${group} field `${name}' must be in byte format [0-9]+[KMGT]."; | ||
50 | |||
51 | hexChars = stringToCharacters "0123456789abcdefABCDEF"; | ||
52 | |||
53 | isMacAddress = s: stringLength s == 17 | ||
54 | && flip all (splitString ":" s) (bytes: | ||
55 | all (byte: elem byte hexChars) (stringToCharacters bytes) | ||
56 | ); | ||
57 | |||
58 | assertMacAddress = name: group: attr: | ||
59 | optional (attr ? ${name} && ! isMacAddress attr.${name}) | ||
60 | "Systemd ${group} field `${name}' must be a valid mac address."; | ||
61 | |||
62 | isPort = i: i >= 0 && i <= 65535; | ||
63 | |||
64 | assertPort = name: group: attr: | ||
65 | optional (attr ? ${name} && ! isPort attr.${name}) | ||
66 | "Error on the systemd ${group} field `${name}': ${attr.name} is not a valid port number."; | ||
67 | |||
68 | assertValueOneOf = name: values: group: attr: | ||
69 | optional (attr ? ${name} && !elem attr.${name} values) | ||
70 | "Systemd ${group} field `${name}' cannot have value `${toString attr.${name}}'."; | ||
71 | |||
72 | assertHasField = name: group: attr: | ||
73 | optional (!(attr ? ${name})) | ||
74 | "Systemd ${group} field `${name}' must exist."; | ||
75 | |||
76 | assertRange = name: min: max: group: attr: | ||
77 | optional (attr ? ${name} && !(min <= attr.${name} && max >= attr.${name})) | ||
78 | "Systemd ${group} field `${name}' is outside the range [${toString min},${toString max}]"; | ||
79 | |||
80 | assertMinimum = name: min: group: attr: | ||
81 | optional (attr ? ${name} && attr.${name} < min) | ||
82 | "Systemd ${group} field `${name}' must be greater than or equal to ${toString min}"; | ||
83 | |||
84 | assertOnlyFields = fields: group: attr: | ||
85 | let badFields = filter (name: ! elem name fields) (attrNames attr); in | ||
86 | optional (badFields != [ ]) | ||
87 | "Systemd ${group} has extra fields [${concatStringsSep " " badFields}]."; | ||
88 | |||
89 | assertInt = name: group: attr: | ||
90 | optional (attr ? ${name} && !isInt attr.${name}) | ||
91 | "Systemd ${group} field `${name}' is not an integer"; | ||
92 | |||
93 | checkUnitConfig = group: checks: attrs: let | ||
94 | # We're applied at the top-level type (attrsOf unitOption), so the actual | ||
95 | # unit options might contain attributes from mkOverride and mkIf that we need to | ||
96 | # convert into single values before checking them. | ||
97 | defs = mapAttrs (const (v: | ||
98 | if v._type or "" == "override" then v.content | ||
99 | else if v._type or "" == "if" then v.content | ||
100 | else v | ||
101 | )) attrs; | ||
102 | errors = concatMap (c: c group defs) checks; | ||
103 | in if errors == [] then true | ||
104 | else builtins.trace (concatStringsSep "\n" errors) false; | ||
105 | |||
106 | toOption = x: | ||
107 | if x == true then "true" | ||
108 | else if x == false then "false" | ||
109 | else toString x; | ||
110 | |||
111 | attrsToSection = as: | ||
112 | concatStrings (concatLists (mapAttrsToList (name: value: | ||
113 | map (x: '' | ||
114 | ${name}=${toOption x} | ||
115 | '') | ||
116 | (if isList value then value else [value])) | ||
117 | as)); | ||
118 | |||
119 | generateUnits = generateUnits' true; | ||
120 | |||
121 | generateUnits' = allowCollisions: type: units: upstreamUnits: upstreamWants: | ||
122 | pkgs.runCommand "${type}-units" | ||
123 | { preferLocalBuild = true; | ||
124 | allowSubstitutes = false; | ||
125 | } '' | ||
126 | mkdir -p $out | ||
127 | |||
128 | # Copy the upstream systemd units we're interested in. | ||
129 | for i in ${toString upstreamUnits}; do | ||
130 | fn=${cfg.package}/example/systemd/${type}/$i | ||
131 | if ! [ -e $fn ]; then echo "missing $fn"; false; fi | ||
132 | if [ -L $fn ]; then | ||
133 | target="$(readlink "$fn")" | ||
134 | if [ ''${target:0:3} = ../ ]; then | ||
135 | ln -s "$(readlink -f "$fn")" $out/ | ||
136 | else | ||
137 | cp -pd $fn $out/ | ||
138 | fi | ||
139 | else | ||
140 | ln -s $fn $out/ | ||
141 | fi | ||
142 | done | ||
143 | |||
144 | # Copy .wants links, but only those that point to units that | ||
145 | # we're interested in. | ||
146 | for i in ${toString upstreamWants}; do | ||
147 | fn=${cfg.package}/example/systemd/${type}/$i | ||
148 | if ! [ -e $fn ]; then echo "missing $fn"; false; fi | ||
149 | x=$out/$(basename $fn) | ||
150 | mkdir $x | ||
151 | for i in $fn/*; do | ||
152 | y=$x/$(basename $i) | ||
153 | cp -pd $i $y | ||
154 | if ! [ -e $y ]; then rm $y; fi | ||
155 | done | ||
156 | done | ||
157 | |||
158 | # Symlink all units provided listed in systemd.packages. | ||
159 | packages="${toString cfg.packages}" | ||
160 | |||
161 | # Filter duplicate directories | ||
162 | declare -A unique_packages | ||
163 | for k in $packages ; do unique_packages[$k]=1 ; done | ||
164 | |||
165 | for i in ''${!unique_packages[@]}; do | ||
166 | for fn in $i/etc/systemd/${type}/* $i/lib/systemd/${type}/*; do | ||
167 | if ! [[ "$fn" =~ .wants$ ]]; then | ||
168 | if [[ -d "$fn" ]]; then | ||
169 | targetDir="$out/$(basename "$fn")" | ||
170 | mkdir -p "$targetDir" | ||
171 | ${lndir} "$fn" "$targetDir" | ||
172 | else | ||
173 | ln -s $fn $out/ | ||
174 | fi | ||
175 | fi | ||
176 | done | ||
177 | done | ||
178 | |||
179 | # Symlink all units defined by systemd.units. If these are also | ||
180 | # provided by systemd or systemd.packages, then add them as | ||
181 | # <unit-name>.d/overrides.conf, which makes them extend the | ||
182 | # upstream unit. | ||
183 | for i in ${toString (mapAttrsToList (n: v: v.unit) units)}; do | ||
184 | fn=$(basename $i/*) | ||
185 | if [ -e $out/$fn ]; then | ||
186 | if [ "$(readlink -f $i/$fn)" = /dev/null ]; then | ||
187 | ln -sfn /dev/null $out/$fn | ||
188 | else | ||
189 | ${if allowCollisions then '' | ||
190 | mkdir -p $out/$fn.d | ||
191 | ln -s $i/$fn $out/$fn.d/overrides.conf | ||
192 | '' else '' | ||
193 | echo "Found multiple derivations configuring $fn!" | ||
194 | exit 1 | ||
195 | ''} | ||
196 | fi | ||
197 | else | ||
198 | ln -fs $i/$fn $out/ | ||
199 | fi | ||
200 | done | ||
201 | |||
202 | # Create service aliases from aliases option. | ||
203 | ${concatStrings (mapAttrsToList (name: unit: | ||
204 | concatMapStrings (name2: '' | ||
205 | ln -sfn '${name}' $out/'${name2}' | ||
206 | '') unit.aliases) units)} | ||
207 | |||
208 | # Create .wants and .requires symlinks from the wantedBy and | ||
209 | # requiredBy options. | ||
210 | ${concatStrings (mapAttrsToList (name: unit: | ||
211 | concatMapStrings (name2: '' | ||
212 | mkdir -p $out/'${name2}.wants' | ||
213 | ln -sfn '../${name}' $out/'${name2}.wants'/ | ||
214 | '') unit.wantedBy) units)} | ||
215 | |||
216 | ${concatStrings (mapAttrsToList (name: unit: | ||
217 | concatMapStrings (name2: '' | ||
218 | mkdir -p $out/'${name2}.requires' | ||
219 | ln -sfn '../${name}' $out/'${name2}.requires'/ | ||
220 | '') unit.requiredBy) units)} | ||
221 | |||
222 | ${optionalString (type == "system") '' | ||
223 | # Stupid misc. symlinks. | ||
224 | ln -s ${cfg.defaultUnit} $out/default.target | ||
225 | ln -s ${cfg.ctrlAltDelUnit} $out/ctrl-alt-del.target | ||
226 | ln -s rescue.target $out/kbrequest.target | ||
227 | |||
228 | mkdir -p $out/getty.target.wants/ | ||
229 | ln -s ../autovt@tty1.service $out/getty.target.wants/ | ||
230 | |||
231 | ln -s ../local-fs.target ../remote-fs.target \ | ||
232 | ../nss-lookup.target ../nss-user-lookup.target ../swap.target \ | ||
233 | $out/multi-user.target.wants/ | ||
234 | ''} | ||
235 | ''; # */ | ||
236 | |||
237 | } | ||
diff --git a/modules/networkd/systemd-unit-options.nix b/modules/networkd/systemd-unit-options.nix new file mode 100644 index 00000000..4154389b --- /dev/null +++ b/modules/networkd/systemd-unit-options.nix | |||
@@ -0,0 +1,536 @@ | |||
1 | { config, lib }: | ||
2 | |||
3 | with lib; | ||
4 | with import ./systemd-lib.nix { inherit config lib pkgs; }; | ||
5 | |||
6 | let | ||
7 | checkService = checkUnitConfig "Service" [ | ||
8 | (assertValueOneOf "Type" [ | ||
9 | "exec" "simple" "forking" "oneshot" "dbus" "notify" "idle" | ||
10 | ]) | ||
11 | (assertValueOneOf "Restart" [ | ||
12 | "no" "on-success" "on-failure" "on-abnormal" "on-abort" "always" | ||
13 | ]) | ||
14 | ]; | ||
15 | |||
16 | in rec { | ||
17 | |||
18 | unitOption = mkOptionType { | ||
19 | name = "systemd option"; | ||
20 | merge = loc: defs: | ||
21 | let | ||
22 | defs' = filterOverrides defs; | ||
23 | defs'' = getValues defs'; | ||
24 | in | ||
25 | if isList (head defs'') | ||
26 | then concatLists defs'' | ||
27 | else mergeEqualOption loc defs'; | ||
28 | }; | ||
29 | |||
30 | sharedOptions = { | ||
31 | |||
32 | enable = mkOption { | ||
33 | default = true; | ||
34 | type = types.bool; | ||
35 | description = '' | ||
36 | If set to false, this unit will be a symlink to | ||
37 | /dev/null. This is primarily useful to prevent specific | ||
38 | template instances | ||
39 | (e.g. <literal>serial-getty@ttyS0</literal>) from being | ||
40 | started. Note that <literal>enable=true</literal> does not | ||
41 | make a unit start by default at boot; if you want that, see | ||
42 | <literal>wantedBy</literal>. | ||
43 | ''; | ||
44 | }; | ||
45 | |||
46 | requiredBy = mkOption { | ||
47 | default = []; | ||
48 | type = types.listOf types.str; | ||
49 | description = '' | ||
50 | Units that require (i.e. depend on and need to go down with) | ||
51 | this unit. The discussion under <literal>wantedBy</literal> | ||
52 | applies here as well: inverse <literal>.requires</literal> | ||
53 | symlinks are established. | ||
54 | ''; | ||
55 | }; | ||
56 | |||
57 | wantedBy = mkOption { | ||
58 | default = []; | ||
59 | type = types.listOf types.str; | ||
60 | description = '' | ||
61 | Units that want (i.e. depend on) this unit. The standard way | ||
62 | to make a unit start by default at boot is to set this option | ||
63 | to <literal>[ "multi-user.target" ]</literal>. That's despite | ||
64 | the fact that the systemd.unit(5) manpage says this option | ||
65 | goes in the <literal>[Install]</literal> section that controls | ||
66 | the behaviour of <literal>systemctl enable</literal>. Since | ||
67 | such a process is stateful and thus contrary to the design of | ||
68 | NixOS, setting this option instead causes the equivalent | ||
69 | inverse <literal>.wants</literal> symlink to be present, | ||
70 | establishing the same desired relationship in a stateless way. | ||
71 | ''; | ||
72 | }; | ||
73 | |||
74 | aliases = mkOption { | ||
75 | default = []; | ||
76 | type = types.listOf types.str; | ||
77 | description = "Aliases of that unit."; | ||
78 | }; | ||
79 | |||
80 | }; | ||
81 | |||
82 | concreteUnitOptions = sharedOptions // { | ||
83 | |||
84 | text = mkOption { | ||
85 | type = types.nullOr types.str; | ||
86 | default = null; | ||
87 | description = "Text of this systemd unit."; | ||
88 | }; | ||
89 | |||
90 | unit = mkOption { | ||
91 | internal = true; | ||
92 | description = "The generated unit."; | ||
93 | }; | ||
94 | |||
95 | }; | ||
96 | |||
97 | commonUnitOptions = sharedOptions // { | ||
98 | |||
99 | description = mkOption { | ||
100 | default = ""; | ||
101 | type = types.str; | ||
102 | description = "Description of this unit used in systemd messages and progress indicators."; | ||
103 | }; | ||
104 | |||
105 | documentation = mkOption { | ||
106 | default = []; | ||
107 | type = types.listOf types.str; | ||
108 | description = "A list of URIs referencing documentation for this unit or its configuration."; | ||
109 | }; | ||
110 | |||
111 | requires = mkOption { | ||
112 | default = []; | ||
113 | type = types.listOf types.str; | ||
114 | description = '' | ||
115 | Start the specified units when this unit is started, and stop | ||
116 | this unit when the specified units are stopped or fail. | ||
117 | ''; | ||
118 | }; | ||
119 | |||
120 | wants = mkOption { | ||
121 | default = []; | ||
122 | type = types.listOf types.str; | ||
123 | description = '' | ||
124 | Start the specified units when this unit is started. | ||
125 | ''; | ||
126 | }; | ||
127 | |||
128 | after = mkOption { | ||
129 | default = []; | ||
130 | type = types.listOf types.str; | ||
131 | description = '' | ||
132 | If the specified units are started at the same time as | ||
133 | this unit, delay this unit until they have started. | ||
134 | ''; | ||
135 | }; | ||
136 | |||
137 | before = mkOption { | ||
138 | default = []; | ||
139 | type = types.listOf types.str; | ||
140 | description = '' | ||
141 | If the specified units are started at the same time as | ||
142 | this unit, delay them until this unit has started. | ||
143 | ''; | ||
144 | }; | ||
145 | |||
146 | bindsTo = mkOption { | ||
147 | default = []; | ||
148 | type = types.listOf types.str; | ||
149 | description = '' | ||
150 | Like ‘requires’, but in addition, if the specified units | ||
151 | unexpectedly disappear, this unit will be stopped as well. | ||
152 | ''; | ||
153 | }; | ||
154 | |||
155 | partOf = mkOption { | ||
156 | default = []; | ||
157 | type = types.listOf types.str; | ||
158 | description = '' | ||
159 | If the specified units are stopped or restarted, then this | ||
160 | unit is stopped or restarted as well. | ||
161 | ''; | ||
162 | }; | ||
163 | |||
164 | conflicts = mkOption { | ||
165 | default = []; | ||
166 | type = types.listOf types.str; | ||
167 | description = '' | ||
168 | If the specified units are started, then this unit is stopped | ||
169 | and vice versa. | ||
170 | ''; | ||
171 | }; | ||
172 | |||
173 | requisite = mkOption { | ||
174 | default = []; | ||
175 | type = types.listOf types.str; | ||
176 | description = '' | ||
177 | Similar to requires. However if the units listed are not started, | ||
178 | they will not be started and the transaction will fail. | ||
179 | ''; | ||
180 | }; | ||
181 | |||
182 | unitConfig = mkOption { | ||
183 | default = {}; | ||
184 | example = { RequiresMountsFor = "/data"; }; | ||
185 | type = types.attrsOf unitOption; | ||
186 | description = '' | ||
187 | Each attribute in this set specifies an option in the | ||
188 | <literal>[Unit]</literal> section of the unit. See | ||
189 | <citerefentry><refentrytitle>systemd.unit</refentrytitle> | ||
190 | <manvolnum>5</manvolnum></citerefentry> for details. | ||
191 | ''; | ||
192 | }; | ||
193 | |||
194 | restartTriggers = mkOption { | ||
195 | default = []; | ||
196 | type = types.listOf types.unspecified; | ||
197 | description = '' | ||
198 | An arbitrary list of items such as derivations. If any item | ||
199 | in the list changes between reconfigurations, the service will | ||
200 | be restarted. | ||
201 | ''; | ||
202 | }; | ||
203 | |||
204 | onFailure = mkOption { | ||
205 | default = []; | ||
206 | type = types.listOf types.str; | ||
207 | description = '' | ||
208 | A list of one or more units that are activated when | ||
209 | this unit enters the "failed" state. | ||
210 | ''; | ||
211 | }; | ||
212 | |||
213 | startLimitBurst = mkOption { | ||
214 | type = types.int; | ||
215 | description = '' | ||
216 | Configure unit start rate limiting. Units which are started | ||
217 | more than startLimitBurst times within an interval time | ||
218 | interval are not permitted to start any more. | ||
219 | ''; | ||
220 | }; | ||
221 | |||
222 | startLimitIntervalSec = mkOption { | ||
223 | type = types.int; | ||
224 | description = '' | ||
225 | Configure unit start rate limiting. Units which are started | ||
226 | more than startLimitBurst times within an interval time | ||
227 | interval are not permitted to start any more. | ||
228 | ''; | ||
229 | }; | ||
230 | |||
231 | }; | ||
232 | |||
233 | |||
234 | serviceOptions = commonUnitOptions // { | ||
235 | |||
236 | environment = mkOption { | ||
237 | default = {}; | ||
238 | type = with types; attrsOf (nullOr (oneOf [ str path package ])); | ||
239 | example = { PATH = "/foo/bar/bin"; LANG = "nl_NL.UTF-8"; }; | ||
240 | description = "Environment variables passed to the service's processes."; | ||
241 | }; | ||
242 | |||
243 | path = mkOption { | ||
244 | default = []; | ||
245 | type = with types; listOf (oneOf [ package str ]); | ||
246 | description = '' | ||
247 | Packages added to the service's <envar>PATH</envar> | ||
248 | environment variable. Both the <filename>bin</filename> | ||
249 | and <filename>sbin</filename> subdirectories of each | ||
250 | package are added. | ||
251 | ''; | ||
252 | }; | ||
253 | |||
254 | serviceConfig = mkOption { | ||
255 | default = {}; | ||
256 | example = | ||
257 | { RestartSec = 5; | ||
258 | }; | ||
259 | type = types.addCheck (types.attrsOf unitOption) checkService; | ||
260 | description = '' | ||
261 | Each attribute in this set specifies an option in the | ||
262 | <literal>[Service]</literal> section of the unit. See | ||
263 | <citerefentry><refentrytitle>systemd.service</refentrytitle> | ||
264 | <manvolnum>5</manvolnum></citerefentry> for details. | ||
265 | ''; | ||
266 | }; | ||
267 | |||
268 | script = mkOption { | ||
269 | type = types.lines; | ||
270 | default = ""; | ||
271 | description = "Shell commands executed as the service's main process."; | ||
272 | }; | ||
273 | |||
274 | scriptArgs = mkOption { | ||
275 | type = types.str; | ||
276 | default = ""; | ||
277 | description = "Arguments passed to the main process script."; | ||
278 | }; | ||
279 | |||
280 | preStart = mkOption { | ||
281 | type = types.lines; | ||
282 | default = ""; | ||
283 | description = '' | ||
284 | Shell commands executed before the service's main process | ||
285 | is started. | ||
286 | ''; | ||
287 | }; | ||
288 | |||
289 | postStart = mkOption { | ||
290 | type = types.lines; | ||
291 | default = ""; | ||
292 | description = '' | ||
293 | Shell commands executed after the service's main process | ||
294 | is started. | ||
295 | ''; | ||
296 | }; | ||
297 | |||
298 | reload = mkOption { | ||
299 | type = types.lines; | ||
300 | default = ""; | ||
301 | description = '' | ||
302 | Shell commands executed when the service's main process | ||
303 | is reloaded. | ||
304 | ''; | ||
305 | }; | ||
306 | |||
307 | preStop = mkOption { | ||
308 | type = types.lines; | ||
309 | default = ""; | ||
310 | description = '' | ||
311 | Shell commands executed to stop the service. | ||
312 | ''; | ||
313 | }; | ||
314 | |||
315 | postStop = mkOption { | ||
316 | type = types.lines; | ||
317 | default = ""; | ||
318 | description = '' | ||
319 | Shell commands executed after the service's main process | ||
320 | has exited. | ||
321 | ''; | ||
322 | }; | ||
323 | |||
324 | restartIfChanged = mkOption { | ||
325 | type = types.bool; | ||
326 | default = true; | ||
327 | description = '' | ||
328 | Whether the service should be restarted during a NixOS | ||
329 | configuration switch if its definition has changed. | ||
330 | ''; | ||
331 | }; | ||
332 | |||
333 | reloadIfChanged = mkOption { | ||
334 | type = types.bool; | ||
335 | default = false; | ||
336 | description = '' | ||
337 | Whether the service should be reloaded during a NixOS | ||
338 | configuration switch if its definition has changed. If | ||
339 | enabled, the value of <option>restartIfChanged</option> is | ||
340 | ignored. | ||
341 | ''; | ||
342 | }; | ||
343 | |||
344 | stopIfChanged = mkOption { | ||
345 | type = types.bool; | ||
346 | default = true; | ||
347 | description = '' | ||
348 | If set, a changed unit is restarted by calling | ||
349 | <command>systemctl stop</command> in the old configuration, | ||
350 | then <command>systemctl start</command> in the new one. | ||
351 | Otherwise, it is restarted in a single step using | ||
352 | <command>systemctl restart</command> in the new configuration. | ||
353 | The latter is less correct because it runs the | ||
354 | <literal>ExecStop</literal> commands from the new | ||
355 | configuration. | ||
356 | ''; | ||
357 | }; | ||
358 | |||
359 | startAt = mkOption { | ||
360 | type = with types; either str (listOf str); | ||
361 | default = []; | ||
362 | example = "Sun 14:00:00"; | ||
363 | description = '' | ||
364 | Automatically start this unit at the given date/time, which | ||
365 | must be in the format described in | ||
366 | <citerefentry><refentrytitle>systemd.time</refentrytitle> | ||
367 | <manvolnum>7</manvolnum></citerefentry>. This is equivalent | ||
368 | to adding a corresponding timer unit with | ||
369 | <option>OnCalendar</option> set to the value given here. | ||
370 | ''; | ||
371 | apply = v: if isList v then v else [ v ]; | ||
372 | }; | ||
373 | |||
374 | }; | ||
375 | |||
376 | |||
377 | socketOptions = commonUnitOptions // { | ||
378 | |||
379 | listenStreams = mkOption { | ||
380 | default = []; | ||
381 | type = types.listOf types.str; | ||
382 | example = [ "0.0.0.0:993" "/run/my-socket" ]; | ||
383 | description = '' | ||
384 | For each item in this list, a <literal>ListenStream</literal> | ||
385 | option in the <literal>[Socket]</literal> section will be created. | ||
386 | ''; | ||
387 | }; | ||
388 | |||
389 | listenDatagrams = mkOption { | ||
390 | default = []; | ||
391 | type = types.listOf types.str; | ||
392 | example = [ "0.0.0.0:993" "/run/my-socket" ]; | ||
393 | description = '' | ||
394 | For each item in this list, a <literal>ListenDatagram</literal> | ||
395 | option in the <literal>[Socket]</literal> section will be created. | ||
396 | ''; | ||
397 | }; | ||
398 | |||
399 | socketConfig = mkOption { | ||
400 | default = {}; | ||
401 | example = { ListenStream = "/run/my-socket"; }; | ||
402 | type = types.attrsOf unitOption; | ||
403 | description = '' | ||
404 | Each attribute in this set specifies an option in the | ||
405 | <literal>[Socket]</literal> section of the unit. See | ||
406 | <citerefentry><refentrytitle>systemd.socket</refentrytitle> | ||
407 | <manvolnum>5</manvolnum></citerefentry> for details. | ||
408 | ''; | ||
409 | }; | ||
410 | |||
411 | }; | ||
412 | |||
413 | |||
414 | timerOptions = commonUnitOptions // { | ||
415 | |||
416 | timerConfig = mkOption { | ||
417 | default = {}; | ||
418 | example = { OnCalendar = "Sun 14:00:00"; Unit = "foo.service"; }; | ||
419 | type = types.attrsOf unitOption; | ||
420 | description = '' | ||
421 | Each attribute in this set specifies an option in the | ||
422 | <literal>[Timer]</literal> section of the unit. See | ||
423 | <citerefentry><refentrytitle>systemd.timer</refentrytitle> | ||
424 | <manvolnum>5</manvolnum></citerefentry> and | ||
425 | <citerefentry><refentrytitle>systemd.time</refentrytitle> | ||
426 | <manvolnum>7</manvolnum></citerefentry> for details. | ||
427 | ''; | ||
428 | }; | ||
429 | |||
430 | }; | ||
431 | |||
432 | |||
433 | pathOptions = commonUnitOptions // { | ||
434 | |||
435 | pathConfig = mkOption { | ||
436 | default = {}; | ||
437 | example = { PathChanged = "/some/path"; Unit = "changedpath.service"; }; | ||
438 | type = types.attrsOf unitOption; | ||
439 | description = '' | ||
440 | Each attribute in this set specifies an option in the | ||
441 | <literal>[Path]</literal> section of the unit. See | ||
442 | <citerefentry><refentrytitle>systemd.path</refentrytitle> | ||
443 | <manvolnum>5</manvolnum></citerefentry> for details. | ||
444 | ''; | ||
445 | }; | ||
446 | |||
447 | }; | ||
448 | |||
449 | |||
450 | mountOptions = commonUnitOptions // { | ||
451 | |||
452 | what = mkOption { | ||
453 | example = "/dev/sda1"; | ||
454 | type = types.str; | ||
455 | description = "Absolute path of device node, file or other resource. (Mandatory)"; | ||
456 | }; | ||
457 | |||
458 | where = mkOption { | ||
459 | example = "/mnt"; | ||
460 | type = types.str; | ||
461 | description = '' | ||
462 | Absolute path of a directory of the mount point. | ||
463 | Will be created if it doesn't exist. (Mandatory) | ||
464 | ''; | ||
465 | }; | ||
466 | |||
467 | type = mkOption { | ||
468 | default = ""; | ||
469 | example = "ext4"; | ||
470 | type = types.str; | ||
471 | description = "File system type."; | ||
472 | }; | ||
473 | |||
474 | options = mkOption { | ||
475 | default = ""; | ||
476 | example = "noatime"; | ||
477 | type = types.commas; | ||
478 | description = "Options used to mount the file system."; | ||
479 | }; | ||
480 | |||
481 | mountConfig = mkOption { | ||
482 | default = {}; | ||
483 | example = { DirectoryMode = "0775"; }; | ||
484 | type = types.attrsOf unitOption; | ||
485 | description = '' | ||
486 | Each attribute in this set specifies an option in the | ||
487 | <literal>[Mount]</literal> section of the unit. See | ||
488 | <citerefentry><refentrytitle>systemd.mount</refentrytitle> | ||
489 | <manvolnum>5</manvolnum></citerefentry> for details. | ||
490 | ''; | ||
491 | }; | ||
492 | }; | ||
493 | |||
494 | automountOptions = commonUnitOptions // { | ||
495 | |||
496 | where = mkOption { | ||
497 | example = "/mnt"; | ||
498 | type = types.str; | ||
499 | description = '' | ||
500 | Absolute path of a directory of the mount point. | ||
501 | Will be created if it doesn't exist. (Mandatory) | ||
502 | ''; | ||
503 | }; | ||
504 | |||
505 | automountConfig = mkOption { | ||
506 | default = {}; | ||
507 | example = { DirectoryMode = "0775"; }; | ||
508 | type = types.attrsOf unitOption; | ||
509 | description = '' | ||
510 | Each attribute in this set specifies an option in the | ||
511 | <literal>[Automount]</literal> section of the unit. See | ||
512 | <citerefentry><refentrytitle>systemd.automount</refentrytitle> | ||
513 | <manvolnum>5</manvolnum></citerefentry> for details. | ||
514 | ''; | ||
515 | }; | ||
516 | }; | ||
517 | |||
518 | targetOptions = commonUnitOptions; | ||
519 | |||
520 | sliceOptions = commonUnitOptions // { | ||
521 | |||
522 | sliceConfig = mkOption { | ||
523 | default = {}; | ||
524 | example = { MemoryMax = "2G"; }; | ||
525 | type = types.attrsOf unitOption; | ||
526 | description = '' | ||
527 | Each attribute in this set specifies an option in the | ||
528 | <literal>[Slice]</literal> section of the unit. See | ||
529 | <citerefentry><refentrytitle>systemd.slice</refentrytitle> | ||
530 | <manvolnum>5</manvolnum></citerefentry> for details. | ||
531 | ''; | ||
532 | }; | ||
533 | |||
534 | }; | ||
535 | |||
536 | } | ||
diff --git a/modules/yggdrasil-wg/default.nix b/modules/yggdrasil-wg/default.nix index 8e2ba7a4..80443644 100644 --- a/modules/yggdrasil-wg/default.nix +++ b/modules/yggdrasil-wg/default.nix | |||
@@ -5,86 +5,183 @@ with lib; | |||
5 | let | 5 | let |
6 | listenPort = 51820; | 6 | listenPort = 51820; |
7 | udp2rawPort = 51821; | 7 | udp2rawPort = 51821; |
8 | subnet = "2a03:4000:52:ada:1"; | 8 | wgSubnet = "2a03:4000:52:ada:1"; |
9 | subnetLength = 80; | 9 | wgSubnetLength = 80; |
10 | hostLength = subnetLength + 16; | 10 | wgHostLength = wgSubnetLength + 16; |
11 | batSubnet = "2a03:4000:52:ada:2"; | ||
12 | batSubnetLength = 80; | ||
13 | batHostLength = batSubnetLength + 16; | ||
11 | 14 | ||
12 | links = [ | 15 | links = mkLinks [ |
13 | { from = "vidhar"; | 16 | { from = "vidhar"; |
14 | to = "surtr"; | 17 | to = "surtr"; |
15 | endpointHost = "202.61.241.61"; | 18 | endpointHost = "202.61.241.61"; |
16 | persistentKeepalive = 25; | 19 | udp2raw = true; |
17 | dynamicEndpointRefreshSeconds = 86400; | 20 | PersistentKeepalive = 25; |
18 | } | 21 | } |
19 | { from = "sif"; | 22 | { from = "sif"; |
20 | to = "surtr"; | 23 | to = "surtr"; |
21 | endpointHost = "202.61.241.61"; | 24 | endpointHost = "202.61.241.61"; |
22 | persistentKeepalive = 25; | 25 | udp2raw = true; |
23 | dynamicEndpointRefreshSeconds = 86400; | 26 | PersistentKeepalive = 25; |
24 | } | 27 | } |
25 | ]; | ||
26 | routes = [ | ||
27 | { from = "sif"; | 28 | { from = "sif"; |
28 | to = "vidhar"; | 29 | to = "vidhar"; |
29 | via = "surtr"; | 30 | endpointHost = "192.168.2.168"; |
30 | } | 31 | PersistentKeepalive = 25; |
31 | { from = "vidhar"; | ||
32 | to = "sif"; | ||
33 | via = "surtr"; | ||
34 | } | 32 | } |
35 | ]; | 33 | ]; |
36 | hostIPs = { | 34 | wgHostIPs = { |
37 | surtr = ["${subnet}::/${toString hostLength}"]; | 35 | surtr = "${wgSubnet}::/${toString wgHostLength}"; |
38 | vidhar = ["${subnet}:1::/${toString hostLength}"]; | 36 | vidhar = "${wgSubnet}:1::/${toString wgHostLength}"; |
39 | sif = ["${subnet}:2::/${toString hostLength}"]; | 37 | sif = "${wgSubnet}:2::/${toString wgHostLength}"; |
38 | }; | ||
39 | greHostMACPrefixes = { | ||
40 | surtr = "02:00:00:00:00"; | ||
41 | vidhar = "02:00:00:00:01"; | ||
42 | sif = "02:00:00:00:02"; | ||
43 | }; | ||
44 | batHostIPs = { | ||
45 | surtr = ["${batSubnet}::/${toString batHostLength}"]; | ||
46 | vidhar = ["${batSubnet}:1::/${toString batHostLength}"]; | ||
47 | sif = ["${batSubnet}:2::/${toString batHostLength}"]; | ||
40 | }; | 48 | }; |
41 | 49 | ||
42 | mkPublicKeyPath = host: ./hosts + "/${host}.pub"; | 50 | mkPublicKeyPath = host: ./hosts + "/${host}.pub"; |
43 | mkPrivateKeyPath = host: ./hosts + "/${host}.priv"; | 51 | mkPrivateKeyPath = host: ./hosts + "/${host}.priv"; |
52 | |||
53 | kernel = config.boot.kernelPackages; | ||
44 | 54 | ||
45 | publicKeyPath = mkPublicKeyPath hostName; | 55 | publicKeyPath = mkPublicKeyPath hostName; |
46 | privateKeyPath = mkPrivateKeyPath hostName; | 56 | privateKeyPath = mkPrivateKeyPath hostName; |
47 | inNetwork = pathExists privateKeyPath && pathExists publicKeyPath; | 57 | inNetwork = pathExists privateKeyPath && pathExists publicKeyPath; |
48 | hostLinks = filter ({ from, to, ... }: from == hostName || to == hostName) links; | 58 | hostLinks = filter ({ from, to, ... }: from == hostName || to == hostName) links; |
49 | hostRoutes = filter ({ from, to, ... }: from == hostName || to == hostName) routes; | 59 | # hostRoutes = filter ({ from, to, ... }: from == hostName || to == hostName) routes; |
50 | isRouter = inNetwork && any ({via, ...}: via == hostName) routes; | 60 | # isRouter = inNetwork && any ({via, ...}: via == hostName) routes; |
51 | linkToPeer = ix: opts@{from, to, ...}: | 61 | linkToPeer = opts@{from, to, ...}: |
52 | let | 62 | let |
53 | other = if from == hostName then to else from; | 63 | other = if from == hostName then to else from; |
54 | in { | 64 | in { |
55 | allowedIPs = hostIPs.${other} ++ concatMap (rArgs: if rArgs.from != hostName || rArgs.via != to then [] else hostIPs.${rArgs.to}) routes; | 65 | AllowedIPs = wgHostIPs.${other}; # ++ concatMap (rArgs: if rArgs.from != hostName || rArgs.via != to then [] else wgHostIPs.${rArgs.to}) routes; |
56 | publicKey = trim (readFile (mkPublicKeyPath other)); | 66 | PublicKey = trim (readFile (mkPublicKeyPath other)); |
57 | } // (optionalAttrs (from == hostName) (filterAttrs (n: _v: !(elem n ["from" "to" "endpointHost"])) opts // optionalAttrs (opts ? "endpointHost") { endpoint = "127.0.0.1:${toString (udp2rawPort + ix)}"; })); | 67 | } // (optionalAttrs (from == hostName) (filterAttrs (n: _v: !(elem n ["from" "to" "endpointHost" "udp2raw"])) opts // optionalAttrs (opts ? "endpointHost") (if opts ? "udp2raw" then { Endpoint = "127.0.0.1:${toString (udp2rawPort + opts.udp2raw)}"; } else { Endpoint = "${opts.endpointHost}:${toString listenPort}"; }))); |
58 | 68 | linkToGreDev = opts@{from, to, ...}: | |
69 | let | ||
70 | other = if from == hostName then to else from; | ||
71 | in nameValuePair "yggdrasil-gre-${other}" { | ||
72 | netdevConfig = { | ||
73 | Name = "yggdrasil-gre-${other}"; | ||
74 | Kind = "ip6gretap"; | ||
75 | MTUBytes = toString 1280; | ||
76 | }; | ||
77 | tunnelConfig = { | ||
78 | Local = stripSubnet wgHostIPs.${hostName}; | ||
79 | Remote = stripSubnet wgHostIPs.${other}; | ||
80 | }; | ||
81 | }; | ||
82 | linkToGreNetwork = ix: opts@{from, to, ...}: | ||
83 | let | ||
84 | other = if from == hostName then to else from; | ||
85 | hexIx = let | ||
86 | hexIx' = toHexString ix; | ||
87 | in if (stringLength hexIx' < 2) then "0${hexIx'}" else hexIx'; | ||
88 | in nameValuePair "yggdrasil-gre-${other}" { | ||
89 | matchConfig = { | ||
90 | Name = "yggdrasil-gre-${other}"; | ||
91 | }; | ||
92 | linkConfig = { | ||
93 | MACAddress = "${greHostMACPrefixes.${hostName}}:${hexIx}"; | ||
94 | }; | ||
95 | networkConfig = { | ||
96 | Tunnel = "yggdrasil-gre-${other}"; | ||
97 | BatmanAdvanced = "yggdrasil"; | ||
98 | }; | ||
99 | linkConfig = { | ||
100 | RequiredForOnline = false; | ||
101 | }; | ||
102 | }; | ||
103 | |||
59 | trim = str: if hasSuffix "\n" str then trim (removeSuffix "\n" str) else str; | 104 | trim = str: if hasSuffix "\n" str then trim (removeSuffix "\n" str) else str; |
60 | stripSubnet = addr: let matchRes = builtins.match "^(.*)/[0-9]+$" addr; in if matchRes == null then addr else elemAt matchRes 0; | 105 | stripSubnet = addr: let matchRes = builtins.match "^(.*)/[0-9]+$" addr; in if matchRes == null then addr else elemAt matchRes 0; |
106 | optIx = optName: xs: let | ||
107 | withOpts = listToAttrs (imap0 (ix: x: nameValuePair x.name (x.value // { ${optName} = ix; })) (filter (x: x.value.${optName} or false) (imap0 (ix: nameValuePair (toString ix)) xs))); | ||
108 | withoutOpts = listToAttrs (map (nv: nameValuePair nv.name (removeAttrs nv.value [optName])) (filter (x: !(x.value.${optName} or false)) (imap0 (ix: nameValuePair (toString ix)) xs))); | ||
109 | in genList (ix: withOpts.${toString ix} or withoutOpts.${toString ix}) (length xs); | ||
110 | mkLinks = optIx "udp2raw"; | ||
61 | in { | 111 | in { |
62 | config = { | 112 | config = { |
63 | assertions = [ | 113 | assertions = [ |
64 | { assertion = inNetwork || !(pathExists privateKeyPath || pathExists publicKeyPath); | 114 | { assertion = inNetwork || !(pathExists privateKeyPath || pathExists publicKeyPath); |
65 | message = "yggdrasil-wg: Either both public and private keys must exist or neither."; | 115 | message = "yggdrasil-wg: Either both public and private keys must exist or neither."; |
66 | } | 116 | } |
67 | { assertion = !inNetwork || (hostIPs ? "${hostName}"); | 117 | { assertion = !inNetwork || (wgHostIPs ? "${hostName}"); |
68 | message = "yggdrasil-wg: Entry in hostIPs must exist."; | 118 | message = "yggdrasil-wg: Entry in wgHostIPs must exist."; |
69 | } | 119 | } |
70 | ] ++ map ({from, to, ...}: let other = if from == hostName then to else from; in { assertion = pathExists (mkPublicKeyPath other); message = "yggdrasil-wg: This host (${hostName}) has a link with ‘${other}’, but no public key is available for ‘${other}’."; }) hostLinks; | 120 | ] ++ map ({from, to, ...}: let other = if from == hostName then to else from; in { assertion = pathExists (mkPublicKeyPath other); message = "yggdrasil-wg: This host (${hostName}) has a link with ‘${other}’, but no public key is available for ‘${other}’."; }) hostLinks; |
71 | 121 | ||
72 | networking.wireguard.interfaces = mkIf inNetwork { | 122 | systemd.network = mkIf inNetwork { |
73 | yggdrasil = { | 123 | enable = true; |
74 | allowedIPsAsRoutes = false; | 124 | netdevs = { |
75 | inherit listenPort; | 125 | yggdrasil-wg = { |
76 | ips = hostIPs.${hostName}; | 126 | netdevConfig = { |
77 | peers = filter (value: value != null) (imap0 (ix: opts@{to, from, ...}: if from == hostName || to == hostName then linkToPeer ix opts else null) links); | 127 | Name = "yggdrasil-wg"; |
78 | privateKeyFile = config.sops.secrets."yggdrasil-wg.priv".path; | 128 | Kind = "wireguard"; |
79 | postSetup = '' | 129 | MTUBytes = toString (1280 + 70); |
80 | ip li set mtu 1280 dev yggdrasil | 130 | }; |
81 | ${concatMapStringsSep "\n" (linkArgs: let other = if linkArgs.from == hostName then linkArgs.to else linkArgs.from; in concatMapStringsSep "\n" (otherIP: "ip route replace \"${otherIP}\" dev \"yggdrasil\" table \"main\"") hostIPs.${other}) hostLinks} | 131 | wireguardConfig = { |
82 | ${concatMapStringsSep "\n" (routeArgs: let other = if routeArgs.from == hostName then routeArgs.to else routeArgs.from; in concatMapStringsSep "\n" (otherIP: concatMapStringsSep "\n" (viaIP: "ip route replace \"${otherIP}\" via \"${viaIP}\" dev \"yggdrasil\" table \"main\"") (map stripSubnet hostIPs.${routeArgs.via})) hostIPs.${other}) hostRoutes} | 132 | PrivateKeyFile = config.sops.secrets."yggdrasil-wg.priv".path; |
83 | ''; | 133 | ListenPort = listenPort; |
84 | }; | 134 | }; |
135 | wireguardPeers = map (opts@{to, from, ...}: { wireguardPeerConfig = linkToPeer opts; }) hostLinks; | ||
136 | }; | ||
137 | yggdrasil = { | ||
138 | netdevConfig = { | ||
139 | Name = "yggdrasil"; | ||
140 | Kind = "batadv"; | ||
141 | }; | ||
142 | }; | ||
143 | } // listToAttrs (map linkToGreDev hostLinks); | ||
144 | |||
145 | networks = { | ||
146 | yggdrasil-wg = { | ||
147 | name = "yggdrasil-wg"; | ||
148 | matchConfig = { | ||
149 | Name = "yggdrasil-wg"; | ||
150 | }; | ||
151 | address = [wgHostIPs.${hostName}]; | ||
152 | linkConfig = { | ||
153 | RequiredForOnline = false; | ||
154 | }; | ||
155 | }; | ||
156 | yggdrasil = { | ||
157 | name = "yggdrasil"; | ||
158 | matchConfig = { | ||
159 | Name = "yggdrasil"; | ||
160 | }; | ||
161 | address = batHostIPs.${hostName}; | ||
162 | linkConfig = { | ||
163 | RequiredForOnline = false; | ||
164 | }; | ||
165 | }; | ||
166 | } // listToAttrs (imap0 linkToGreNetwork hostLinks); | ||
85 | }; | 167 | }; |
86 | 168 | ||
87 | systemd.services = listToAttrs (filter ({ value, ...}: value != null) (imap0 (ix: opts@{to, from, ...}: let other = if from == hostName then to else from; in nameValuePair "yggdrasil-udp2raw@${other}" (if opts ? "endpointHost" && (from == hostName || to == hostName) then { | 169 | # networking.wireguard.interfaces = mkIf inNetwork { |
170 | # yggdrasil = { | ||
171 | # allowedIPsAsRoutes = false; | ||
172 | # inherit listenPort; | ||
173 | # ips = wgHostIPs.${hostName}; | ||
174 | # peers = filter (value: value != null) (map (opts@{to, from, ...}: if from == hostName || to == hostName then linkToPeer opts else null) links); | ||
175 | # privateKeyFile = config.sops.secrets."yggdrasil-wg.priv".path; | ||
176 | # postSetup = '' | ||
177 | # ip li set mtu 1280 dev yggdrasil | ||
178 | # ${concatMapStringsSep "\n" (linkArgs: let other = if linkArgs.from == hostName then linkArgs.to else linkArgs.from; in concatMapStringsSep "\n" (otherIP: "ip route replace \"${otherIP}\" dev \"yggdrasil\" table \"main\"") wgHostIPs.${other}) hostLinks} | ||
179 | # ${concatMapStringsSep "\n" (routeArgs: let other = if routeArgs.from == hostName then routeArgs.to else routeArgs.from; in concatMapStringsSep "\n" (otherIP: concatMapStringsSep "\n" (viaIP: "ip route replace \"${otherIP}\" via \"${viaIP}\" dev \"yggdrasil\" table \"main\"") (map stripSubnet wgHostIPs.${routeArgs.via})) wgHostIPs.${other}) hostRoutes} | ||
180 | # ''; | ||
181 | # }; | ||
182 | # }; | ||
183 | |||
184 | systemd.services = listToAttrs (filter ({ value, ...}: value != null) (map (opts@{to, from, ...}: let other = if from == hostName then to else from; in nameValuePair "yggdrasil-udp2raw@${other}" (if opts ? "endpointHost" && opts ? "udp2raw" then { | ||
88 | path = with pkgs; [iptables]; | 185 | path = with pkgs; [iptables]; |
89 | serviceConfig = { | 186 | serviceConfig = { |
90 | RuntimeDirectory = ["udp2raw-config-${other}"]; | 187 | RuntimeDirectory = ["udp2raw-config-${other}"]; |
@@ -95,16 +192,17 @@ in { | |||
95 | cat >''${RUNTIME_DIRECTORY}/udp2raw.conf <<EOF | 192 | cat >''${RUNTIME_DIRECTORY}/udp2raw.conf <<EOF |
96 | ${if from == hostName then '' | 193 | ${if from == hostName then '' |
97 | -c | 194 | -c |
98 | -l 127.0.0.1:${toString (udp2rawPort + ix)} | 195 | -l 127.0.0.1:${toString (udp2rawPort + opts.udp2raw)} |
99 | -r ${opts.endpointHost}:${toString (udp2rawPort + ix)} | 196 | -r ${opts.endpointHost}:${toString (udp2rawPort + opts.udp2raw)} |
100 | '' else '' | 197 | '' else '' |
101 | -s | 198 | -s |
102 | -l 0.0.0.0:${toString (udp2rawPort + ix)} | 199 | -l 0.0.0.0:${toString (udp2rawPort + opts.udp2raw)} |
103 | -r 127.0.0.1:${toString listenPort} | 200 | -r 127.0.0.1:${toString listenPort} |
104 | ''} | 201 | ''} |
105 | -k $secret | 202 | -k $secret |
106 | --auth-mode hmac_sha1 | 203 | --auth-mode hmac_sha1 |
107 | --raw-mode faketcp | 204 | --raw-mode faketcp |
205 | --seq-mode 4 | ||
108 | -a | 206 | -a |
109 | --retry-on-error | 207 | --retry-on-error |
110 | EOF | 208 | EOF |
@@ -112,38 +210,42 @@ in { | |||
112 | ExecStart = "${pkgs.udp2raw}/bin/udp2raw --conf-file \${RUNTIME_DIRECTORY}/udp2raw.conf"; | 210 | ExecStart = "${pkgs.udp2raw}/bin/udp2raw --conf-file \${RUNTIME_DIRECTORY}/udp2raw.conf"; |
113 | Restart = "always"; | 211 | Restart = "always"; |
114 | }; | 212 | }; |
115 | } else null)) links)) // { | 213 | } else null)) hostLinks)); |
116 | "wireguard-yggdrasil" = { | 214 | # // { |
117 | bindsTo = filter (value: value != null) (map (opts@{to, from, ...}: let other = if from == hostName then to else from; in if opts ? "endpointHost" then "yggdrasil-udp2raw@${other}.service" else null) hostLinks); | 215 | # "wireguard-yggdrasil" = { |
118 | after = filter (value: value != null) (map (opts@{to, from, ...}: let other = if from == hostName then to else from; in if opts ? "endpointHost" then "yggdrasil-udp2raw@${other}.service" else null) hostLinks); | 216 | # bindsTo = filter (value: value != null) (map (opts@{to, from, ...}: let other = if from == hostName then to else from; in if opts ? "endpointHost" && opts ? "udp2raw" then "yggdrasil-udp2raw@${other}.service" else null) hostLinks); |
119 | }; | 217 | # after = filter (value: value != null) (map (opts@{to, from, ...}: let other = if from == hostName then to else from; in if opts ? "endpointHost" && opts ? "udp2raw" then "yggdrasil-udp2raw@${other}.service" else null) hostLinks); |
120 | firewall.path = optionals isRouter [pkgs.procps]; | 218 | # }; |
121 | }; | 219 | # firewall.path = optionals isRouter [pkgs.procps]; |
220 | # }; | ||
122 | 221 | ||
123 | sops.secrets = { | 222 | sops.secrets = { |
124 | "yggdrasil-wg.priv" = mkIf (pathExists privateKeyPath) { | 223 | "yggdrasil-wg.priv" = mkIf (pathExists privateKeyPath) { |
125 | format = "binary"; | 224 | format = "binary"; |
126 | sopsFile = privateKeyPath; | 225 | sopsFile = privateKeyPath; |
127 | }; | 226 | }; |
128 | "yggdrasil-udp2raw-secret" = mkIf (any (opts@{to, from, ...}: (to == hostName || from == hostName) && opts ? "endpointHost") links) { | 227 | "yggdrasil-udp2raw-secret" = mkIf (any (opts@{to, from, ...}: opts ? "endpointHost" && opts ? "udp2raw") hostLinks) { |
129 | format = "binary"; | 228 | format = "binary"; |
130 | sopsFile = ./udp2raw-secret; | 229 | sopsFile = ./udp2raw-secret; |
131 | }; | 230 | }; |
132 | }; | 231 | }; |
133 | 232 | ||
134 | networking.hosts = mkIf inNetwork (listToAttrs (concatMap ({name, value}: map (ip: nameValuePair (stripSubnet ip) ["${name}.yggdrasil"]) value) (mapAttrsToList nameValuePair hostIPs))); | 233 | networking.hosts = mkIf inNetwork (listToAttrs (concatMap ({name, value}: map (ip: nameValuePair (stripSubnet ip) ["${name}.yggdrasil"]) value) (mapAttrsToList nameValuePair batHostIPs))); |
135 | 234 | ||
136 | networking.firewall = mkIf isRouter { | 235 | # networking.firewall = mkIf isRouter { |
137 | extraCommands = '' | 236 | # extraCommands = '' |
138 | ip6tables -A FORWARD -i yggdrasil -o yggdrasil -j nixos-fw-accept | 237 | # ip6tables -A FORWARD -i yggdrasil -o yggdrasil -j nixos-fw-accept |
139 | ip46tables -A FORWARD -j nixos-fw-log-refuse | 238 | # ip46tables -A FORWARD -j nixos-fw-log-refuse |
140 | sysctl net.ipv6.conf.all.forwarding=1 | 239 | # sysctl net.ipv6.conf.all.forwarding=1 |
141 | ''; | 240 | # ''; |
142 | extraStopCommands = '' | 241 | # extraStopCommands = '' |
143 | sysctl net.ipv6.conf.all.forwarding=0 | 242 | # sysctl net.ipv6.conf.all.forwarding=0 |
144 | ip46tables -D FORWARD -j nixos-fw-log-refuse || true | 243 | # ip46tables -D FORWARD -j nixos-fw-log-refuse || true |
145 | ip6tables -D FORWARD -i yggdrasil -o yggdrasil -j nixos-fw-accept || true | 244 | # ip6tables -D FORWARD -i yggdrasil -o yggdrasil -j nixos-fw-accept || true |
146 | ''; | 245 | # ''; |
147 | }; | 246 | # }; |
247 | |||
248 | boot.extraModulePackages = optional (versionOlder kernel.kernel.version "5.6") kernel.wireguard ++ [kernel.batman_adv]; | ||
249 | environment.systemPackages = with pkgs; [ wireguard-tools batctl ]; | ||
148 | }; | 250 | }; |
149 | } | 251 | } |