mirror of
https://github.com/NixOS/nixpkgs.git
synced 2025-07-13 13:40:28 +03:00
nixos/wireguard-networkd: init
Adds a networkd backend for the networking.wireguard options.
This commit is contained in:
parent
f3f364ed3e
commit
a5de36518f
6 changed files with 456 additions and 17 deletions
207
nixos/modules/services/networking/wireguard-networkd.nix
Normal file
207
nixos/modules/services/networking/wireguard-networkd.nix
Normal file
|
@ -0,0 +1,207 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
inherit (lib) types;
|
||||
inherit (lib.attrsets)
|
||||
filterAttrs
|
||||
mapAttrs
|
||||
mapAttrs'
|
||||
mapAttrsToList
|
||||
nameValuePair
|
||||
;
|
||||
inherit (lib.lists) concatMap concatLists;
|
||||
inherit (lib.modules) mkIf;
|
||||
inherit (lib.options) literalExpression mkOption;
|
||||
inherit (lib.strings) hasInfix;
|
||||
inherit (lib.trivial) flip;
|
||||
|
||||
removeNulls = filterAttrs (_: v: v != null);
|
||||
|
||||
generateNetdev =
|
||||
name: interface:
|
||||
nameValuePair "40-${name}" {
|
||||
netdevConfig = removeNulls {
|
||||
Kind = "wireguard";
|
||||
Name = name;
|
||||
MTUBytes = interface.mtu;
|
||||
};
|
||||
wireguardConfig = removeNulls {
|
||||
PrivateKeyFile = interface.privateKeyFile;
|
||||
ListenPort = interface.listenPort;
|
||||
FirewallMark = interface.fwMark;
|
||||
RouteTable = if interface.allowedIPsAsRoutes then interface.table else null;
|
||||
RouteMetric = interface.metric;
|
||||
};
|
||||
wireguardPeers = map generateWireguardPeer interface.peers;
|
||||
};
|
||||
|
||||
generateWireguardPeer =
|
||||
peer:
|
||||
removeNulls {
|
||||
PublicKey = peer.publicKey;
|
||||
PresharedKeyFile = peer.presharedKeyFile;
|
||||
AllowedIPs = peer.allowedIPs;
|
||||
Endpoint = peer.endpoint;
|
||||
PersistentKeepalive = peer.persistentKeepalive;
|
||||
};
|
||||
|
||||
generateNetwork = name: interface: {
|
||||
matchConfig.Name = name;
|
||||
address = interface.ips;
|
||||
};
|
||||
|
||||
cfg = config.networking.wireguard;
|
||||
|
||||
refreshEnabledInterfaces = filterAttrs (
|
||||
name: interface: interface.dynamicEndpointRefreshSeconds != 0
|
||||
) cfg.interfaces;
|
||||
|
||||
generateRefreshTimer =
|
||||
name: interface:
|
||||
nameValuePair "wireguard-dynamic-refresh-${name}" {
|
||||
partOf = [ "wireguard-dynamic-refresh-${name}.service" ];
|
||||
wantedBy = [ "timers.target" ];
|
||||
description = "Wireguard dynamic endpoint refresh (${name}) timer";
|
||||
timerConfig.OnBootSec = interface.dynamicEndpointRefreshSeconds;
|
||||
timerConfig.OnUnitInactiveSec = interface.dynamicEndpointRefreshSeconds;
|
||||
};
|
||||
|
||||
generateRefreshService =
|
||||
name: interface:
|
||||
nameValuePair "wireguard-dynamic-refresh-${name}" {
|
||||
description = "Wireguard dynamic endpoint refresh (${name})";
|
||||
after = [ "network-online.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
path = with pkgs; [
|
||||
iproute2
|
||||
systemd
|
||||
];
|
||||
# networkd doesn't provide a mechanism for refreshing endpoints.
|
||||
# See: https://github.com/systemd/systemd/issues/9911
|
||||
# This hack does the job but takes down the whole interface to do it.
|
||||
script = ''
|
||||
ip link delete ${name}
|
||||
networkctl reload
|
||||
'';
|
||||
};
|
||||
|
||||
in
|
||||
{
|
||||
meta.maintainers = [ lib.maintainers.majiir ];
|
||||
|
||||
options.networking.wireguard = {
|
||||
useNetworkd = mkOption {
|
||||
default = config.networking.useNetworkd;
|
||||
defaultText = literalExpression "config.networking.useNetworkd";
|
||||
type = types.bool;
|
||||
description = ''
|
||||
Whether to use networkd as the network configuration backend for
|
||||
Wireguard instead of the legacy script-based system.
|
||||
|
||||
::: {.warning}
|
||||
Some options have slightly different behavior with the networkd and
|
||||
script-based backends. Check the documentation for each Wireguard
|
||||
option you use before enabling this option.
|
||||
:::
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf (cfg.enable && cfg.useNetworkd) {
|
||||
|
||||
# TODO: Some of these options may be possible to support in networkd.
|
||||
#
|
||||
# privateKey and presharedKey are trivial to support, but we deliberately
|
||||
# don't in order to discourage putting secrets in the /nix store.
|
||||
#
|
||||
# generatePrivateKeyFile can be supported if we can order a service before
|
||||
# networkd configures interfaces. There is also a systemd feature request
|
||||
# for key generation: https://github.com/systemd/systemd/issues/14282
|
||||
#
|
||||
# preSetup, postSetup, preShutdown and postShutdown may be possible, but
|
||||
# networkd is not likely to support script hooks like this directly. See:
|
||||
# https://github.com/systemd/systemd/issues/11629
|
||||
#
|
||||
# socketNamespace and interfaceNamespace can be implemented once networkd
|
||||
# supports setting a netdev's namespace. See:
|
||||
# https://github.com/systemd/systemd/issues/11629
|
||||
# https://github.com/systemd/systemd/pull/14915
|
||||
|
||||
assertions = concatLists (
|
||||
flip mapAttrsToList cfg.interfaces (
|
||||
name: interface:
|
||||
[
|
||||
# Interface assertions
|
||||
{
|
||||
assertion = interface.privateKey == null;
|
||||
message = "networking.wireguard.interfaces.${name}.privateKey cannot be used with networkd. Use privateKeyFile instead.";
|
||||
}
|
||||
{
|
||||
assertion = !interface.generatePrivateKeyFile;
|
||||
message = "networking.wireguard.interfaces.${name}.generatePrivateKeyFile cannot be used with networkd.";
|
||||
}
|
||||
{
|
||||
assertion = interface.preSetup == "";
|
||||
message = "networking.wireguard.interfaces.${name}.preSetup cannot be used with networkd.";
|
||||
}
|
||||
{
|
||||
assertion = interface.postSetup == "";
|
||||
message = "networking.wireguard.interfaces.${name}.postSetup cannot be used with networkd.";
|
||||
}
|
||||
{
|
||||
assertion = interface.preShutdown == "";
|
||||
message = "networking.wireguard.interfaces.${name}.preShutdown cannot be used with networkd.";
|
||||
}
|
||||
{
|
||||
assertion = interface.postShutdown == "";
|
||||
message = "networking.wireguard.interfaces.${name}.postShutdown cannot be used with networkd.";
|
||||
}
|
||||
{
|
||||
assertion = interface.socketNamespace == null;
|
||||
message = "networking.wireguard.interfaces.${name}.socketNamespace cannot be used with networkd.";
|
||||
}
|
||||
{
|
||||
assertion = interface.interfaceNamespace == null;
|
||||
message = "networking.wireguard.interfaces.${name}.interfaceNamespace cannot be used with networkd.";
|
||||
}
|
||||
]
|
||||
++ flip concatMap interface.ips (ip: [
|
||||
# IP assertions
|
||||
{
|
||||
assertion = hasInfix "/" ip;
|
||||
message = "networking.wireguard.interfaces.${name}.ips value \"${ip}\" requires a subnet (e.g. 192.0.2.1/32) with networkd.";
|
||||
}
|
||||
])
|
||||
++ flip concatMap interface.peers (peer: [
|
||||
# Peer assertions
|
||||
{
|
||||
assertion = peer.presharedKey == null;
|
||||
message = "networking.wireguard.interfaces.${name}.peers[].presharedKey cannot be used with networkd. Use presharedKeyFile instead.";
|
||||
}
|
||||
{
|
||||
assertion = peer.dynamicEndpointRefreshSeconds == null;
|
||||
message = "networking.wireguard.interfaces.${name}.peers[].dynamicEndpointRefreshSeconds cannot be used with networkd. Use networking.wireguard.interfaces.${name}.dynamicEndpointRefreshSeconds instead.";
|
||||
}
|
||||
{
|
||||
assertion = peer.dynamicEndpointRefreshRestartSeconds == null;
|
||||
message = "networking.wireguard.interfaces.${name}.peers[].dynamicEndpointRefreshRestartSeconds cannot be used with networkd.";
|
||||
}
|
||||
])
|
||||
)
|
||||
);
|
||||
|
||||
systemd.network = {
|
||||
enable = true;
|
||||
netdevs = mapAttrs' generateNetdev cfg.interfaces;
|
||||
networks = mapAttrs generateNetwork cfg.interfaces;
|
||||
};
|
||||
|
||||
systemd.timers = mapAttrs' generateRefreshTimer refreshEnabledInterfaces;
|
||||
systemd.services = mapAttrs' generateRefreshService refreshEnabledInterfaces;
|
||||
};
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue