1
0
Fork 0
mirror of https://github.com/LnL7/nix-darwin.git synced 2024-12-14 11:57:34 +00:00
nix-darwin/modules/services/wg-quick.nix

233 lines
7.5 KiB
Nix
Raw Normal View History

2022-11-29 09:32:13 +00:00
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.networking.wg-quick;
peerOpts = { ... }: {
options = {
allowedIPs = mkOption {
type = types.listOf types.str;
default = [ ];
2024-04-14 21:02:32 +00:00
description = "List of IP addresses associated with this peer.";
2022-11-29 09:32:13 +00:00
};
endpoint = mkOption {
type = types.nullOr types.str;
default = null;
2024-04-14 21:02:32 +00:00
description = "IP and port to connect to this peer at.";
2022-11-29 09:32:13 +00:00
};
persistentKeepalive = mkOption {
type = types.nullOr types.int;
default = null;
2024-04-14 21:02:32 +00:00
description = "Interval in seconds to send keepalive packets";
2022-11-29 09:32:13 +00:00
};
presharedKeyFile = mkOption {
type = types.nullOr types.str;
default = null;
description =
2024-04-14 21:02:32 +00:00
"Optional, path to file containing the pre-shared key for this peer.";
2022-11-29 09:32:13 +00:00
};
publicKey = mkOption {
default = null;
type = types.str;
2024-04-14 21:02:32 +00:00
description = "The public key for this peer.";
2022-11-29 09:32:13 +00:00
};
};
};
interfaceOpts = { ... }: {
options = {
address = mkOption {
type = types.nullOr (types.listOf types.str);
default = [ ];
2024-04-14 21:02:32 +00:00
description = "List of IP addresses for this interface.";
2022-11-29 09:32:13 +00:00
};
autostart = mkOption {
type = types.bool;
default = true;
description =
2024-04-14 21:02:32 +00:00
"Whether to bring up this interface automatically during boot.";
2022-11-29 09:32:13 +00:00
};
dns = mkOption {
type = types.listOf types.str;
default = [ ];
2024-04-14 21:02:32 +00:00
description = "List of DNS servers for this interface.";
2022-11-29 09:32:13 +00:00
};
listenPort = mkOption {
type = types.nullOr types.int;
default = null;
2024-04-14 21:02:32 +00:00
description = "Port to listen on, randomly selected if not specified.";
2022-11-29 09:32:13 +00:00
};
mtu = mkOption {
type = types.nullOr types.int;
default = null;
description =
2024-04-14 21:02:32 +00:00
"MTU to set for this interface, automatically set if not specified";
2022-11-29 09:32:13 +00:00
};
peers = mkOption {
type = types.listOf (types.submodule peerOpts);
default = [ ];
2024-04-14 21:02:32 +00:00
description = "List of peers associated with this interface.";
2022-11-29 09:32:13 +00:00
};
preDown = mkOption {
type = with types; coercedTo (listOf str) (concatStringsSep "\n") lines;
default = "";
2024-04-14 21:02:32 +00:00
description = "List of commadns to run before interface shutdown.";
2022-11-29 09:32:13 +00:00
};
preUp = mkOption {
type = with types; coercedTo (listOf str) (concatStringsSep "\n") lines;
default = "";
2024-04-14 21:02:32 +00:00
description = "List of commands to run before interface setup.";
2022-11-29 09:32:13 +00:00
};
postDown = mkOption {
type = with types; coercedTo (listOf str) (concatStringsSep "\n") lines;
default = "";
2024-04-14 21:02:32 +00:00
description = "List of commands to run after interface shutdown";
2022-11-29 09:32:13 +00:00
};
postUp = mkOption {
type = with types; coercedTo (listOf str) (concatStringsSep "\n") lines;
default = "";
2024-04-14 21:02:32 +00:00
description = "List of commands to run after interface setup.";
2022-11-29 09:32:13 +00:00
};
privateKeyFile = mkOption {
type = types.str;
default = null;
2024-04-14 21:02:32 +00:00
description = "Path to file containing this interface's private key.";
2022-11-29 09:32:13 +00:00
};
table = mkOption {
type = types.nullOr types.str;
default = null;
2024-04-14 21:02:32 +00:00
description = ''
Controls the routing table to which routes are added. There are two
special values: `off` disables the creation of routes altogether,
and `auto` (the default) adds routes to the default table and
enables special handling of default routes.
'';
2022-11-29 09:32:13 +00:00
};
};
};
generateInterfaceScript = name: text:
((pkgs.writeShellScriptBin name text) + "/bin/${name}");
generatePostUpPSKText = name: interfaceOpt:
map (peer:
optionalString (peer.presharedKeyFile != null) ''
wg set $(cat /var/run/wireguard/${name}.name) peer ${peer.publicKey} preshared-key ${peer.presharedKeyFile}
'') interfaceOpt.peers;
generatePostUpText = name: interfaceOpt:
(optionalString (interfaceOpt.privateKeyFile != null) ''
wg set $(cat /var/run/wireguard/${name}.name) private-key ${interfaceOpt.privateKeyFile}
'') + (concatStrings (generatePostUpPSKText name interfaceOpt))
+ interfaceOpt.postUp;
generateInterfacePostUp = name: interfaceOpt:
generateInterfaceScript "postUp.sh" (generatePostUpText name interfaceOpt);
generateInterfaceConfig = name: interfaceOpt:
''
[Interface]
'' + optionalString (interfaceOpt.address != [ ]) (''
Address = ${concatStringsSep "," interfaceOpt.address}
'') + optionalString (interfaceOpt.dns != [ ]) ''
2023-03-21 10:23:16 +00:00
DNS = ${concatStringsSep "," interfaceOpt.dns}
2022-11-29 09:32:13 +00:00
'' + optionalString (interfaceOpt.listenPort != null) ''
ListenPort = ${toString interfaceOpt.listenPort}
'' + optionalString (interfaceOpt.mtu != null) ''
MTU = ${toString interfaceOpt.mtu}
'' + optionalString (interfaceOpt.preUp != "") ''
PreUp = ${generateInterfaceScript "preUp.sh" interfaceOpt.preUp}
'' + optionalString (interfaceOpt.preDown != "") ''
PreDown = ${generateInterfaceScript "preDown.sh" interfaceOpt.preDown}
'' + optionalString
(interfaceOpt.privateKeyFile != null || interfaceOpt.postUp != "") ''
PostUp = ${generateInterfacePostUp name interfaceOpt}
'' + optionalString (interfaceOpt.postDown != "") ''
PostDown = ${generateInterfaceScript "postDown.sh" interfaceOpt.postDown}
'' + optionalString (interfaceOpt.table != null) ''
Table = ${interfaceOpt.table}
'' + optionalString (interfaceOpt.peers != [ ]) "\n"
+ concatStringsSep "\n" (map generatePeerConfig interfaceOpt.peers);
generatePeerConfig = peerOpt:
''
[Peer]
PublicKey = ${peerOpt.publicKey}
'' + optionalString (peerOpt.allowedIPs != [ ]) ''
AllowedIPs = ${concatStringsSep "," peerOpt.allowedIPs}
'' + optionalString (peerOpt.endpoint != null) ''
Endpoint = ${peerOpt.endpoint}
'' + optionalString (peerOpt.persistentKeepalive != null) ''
PersistentKeepalive = ${toString peerOpt.persistentKeepalive}
'';
generateInterfaceAttrs = name: interfaceOpt:
nameValuePair "wireguard/${name}.conf" {
enable = true;
text = generateInterfaceConfig name interfaceOpt;
};
generateLaunchDaemonAttrs = name: interfaceOpt:
nameValuePair "wg-quick-${name}" {
serviceConfig = {
EnvironmentVariables = {
PATH =
"${pkgs.wireguard-tools}/bin:${pkgs.wireguard-go}/bin:${config.environment.systemPath}";
};
KeepAlive = {
NetworkState = true;
SuccessfulExit = true;
};
ProgramArguments =
[ "${pkgs.wireguard-tools}/bin/wg-quick" "up" "${name}" ];
RunAtLoad = true;
StandardErrorPath = "${cfg.logDir}/wg-quick-${name}.log";
StandardOutPath = "${cfg.logDir}/wg-quick-${name}.log";
};
};
in {
options = {
networking.wg-quick = {
interfaces = mkOption {
type = types.attrsOf (types.submodule interfaceOpts);
default = { };
2024-04-14 21:02:32 +00:00
description = "Set of wg-quick interfaces.";
2022-11-29 09:32:13 +00:00
};
logDir = mkOption {
type = types.str;
default = "/var/log";
2024-04-14 21:02:32 +00:00
description = "Directory to save wg-quick logs to.";
2022-11-29 09:32:13 +00:00
};
};
};
config = mkIf (cfg.interfaces != { }) {
launchd.daemons = mapAttrs' generateLaunchDaemonAttrs
(filterAttrs (name: interfaceOpt: interfaceOpt.autostart)
config.networking.wg-quick.interfaces);
environment.etc =
mapAttrs' generateInterfaceAttrs config.networking.wg-quick.interfaces;
environment.systemPackages = [ pkgs.wireguard-go pkgs.wireguard-tools ];
};
}