|
|
|
@ -23,8 +23,23 @@ let |
|
|
|
|
|
|
|
|
|
privateKey = mkOption { |
|
|
|
|
example = "yAnz5TF+lXXJte14tji3zlMNq+hd2rYUIgJBgB3fBmk="; |
|
|
|
|
type = types.str; |
|
|
|
|
description = "Base64 private key generated by wg genkey."; |
|
|
|
|
type = with types; nullOr str; |
|
|
|
|
default = null; |
|
|
|
|
description = '' |
|
|
|
|
Base64 private key generated by wg genkey. |
|
|
|
|
|
|
|
|
|
Warning: Consider using privateKeyFile instead if you do not |
|
|
|
|
want to store the key in the world-readable Nix store. |
|
|
|
|
''; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
privateKeyFile = mkOption { |
|
|
|
|
example = "/private/wireguard_key"; |
|
|
|
|
type = with types; nullOr str; |
|
|
|
|
default = null; |
|
|
|
|
description = '' |
|
|
|
|
Private key file as generated by wg genkey. |
|
|
|
|
''; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
listenPort = mkOption { |
|
|
|
@ -91,7 +106,22 @@ let |
|
|
|
|
example = "rVXs/Ni9tu3oDBLS4hOyAUAa1qTWVA3loR8eL20os3I="; |
|
|
|
|
type = with types; nullOr str; |
|
|
|
|
description = '' |
|
|
|
|
base64 preshared key generated by wg genpsk. Optional, |
|
|
|
|
Base64 preshared key generated by wg genpsk. Optional, |
|
|
|
|
and may be omitted. This option adds an additional layer of |
|
|
|
|
symmetric-key cryptography to be mixed into the already existing |
|
|
|
|
public-key cryptography, for post-quantum resistance. |
|
|
|
|
|
|
|
|
|
Warning: Consider using presharedKeyFile instead if you do not |
|
|
|
|
want to store the key in the world-readable Nix store. |
|
|
|
|
''; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
presharedKeyFile = mkOption { |
|
|
|
|
default = null; |
|
|
|
|
example = "/private/wireguard_psk"; |
|
|
|
|
type = with types; nullOr str; |
|
|
|
|
description = '' |
|
|
|
|
File pointing to preshared key as generated by wg pensk. Optional, |
|
|
|
|
and may be omitted. This option adds an additional layer of |
|
|
|
|
symmetric-key cryptography to be mixed into the already existing |
|
|
|
|
public-key cryptography, for post-quantum resistance. |
|
|
|
@ -134,54 +164,59 @@ let |
|
|
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
generateConf = name: values: pkgs.writeText "wireguard-${name}.conf" '' |
|
|
|
|
[Interface] |
|
|
|
|
PrivateKey = ${values.privateKey} |
|
|
|
|
${optionalString (values.listenPort != null) "ListenPort = ${toString values.listenPort}"} |
|
|
|
|
|
|
|
|
|
${concatStringsSep "\n\n" (map (peer: '' |
|
|
|
|
[Peer] |
|
|
|
|
PublicKey = ${peer.publicKey} |
|
|
|
|
${optionalString (peer.presharedKey != null) "PresharedKey = ${peer.presharedKey}"} |
|
|
|
|
${optionalString (peer.allowedIPs != []) "AllowedIPs = ${concatStringsSep ", " peer.allowedIPs}"} |
|
|
|
|
${optionalString (peer.endpoint != null) "Endpoint = ${peer.endpoint}"} |
|
|
|
|
${optionalString (peer.persistentKeepalive != null) "PersistentKeepalive = ${toString peer.persistentKeepalive}"} |
|
|
|
|
'') values.peers)} |
|
|
|
|
''; |
|
|
|
|
|
|
|
|
|
ipCommand = "${pkgs.iproute}/bin/ip"; |
|
|
|
|
wgCommand = "${pkgs.wireguard}/bin/wg"; |
|
|
|
|
|
|
|
|
|
generateUnit = name: values: |
|
|
|
|
# exactly one way to specify the private key must be set |
|
|
|
|
assert (values.privateKey != null) != (values.privateKeyFile != null); |
|
|
|
|
let privKey = if values.privateKeyFile != null then values.privateKeyFile else pkgs.writeText "wg-key" values.privateKey; |
|
|
|
|
in |
|
|
|
|
nameValuePair "wireguard-${name}" |
|
|
|
|
{ |
|
|
|
|
description = "WireGuard Tunnel - ${name}"; |
|
|
|
|
after = [ "network.target" ]; |
|
|
|
|
wantedBy = [ "multi-user.target" ]; |
|
|
|
|
|
|
|
|
|
serviceConfig = { |
|
|
|
|
Type = "oneshot"; |
|
|
|
|
RemainAfterExit = true; |
|
|
|
|
ExecStart = lib.flatten([ |
|
|
|
|
ExecStart = flatten([ |
|
|
|
|
values.preSetup |
|
|
|
|
|
|
|
|
|
"-${ipCommand} link del dev ${name}" |
|
|
|
|
"${ipCommand} link add dev ${name} type wireguard" |
|
|
|
|
"${wgCommand} setconf ${name} ${generateConf name values}" |
|
|
|
|
|
|
|
|
|
(map (ip: |
|
|
|
|
''${ipCommand} address add ${ip} dev ${name}'' |
|
|
|
|
"${ipCommand} address add ${ip} dev ${name}" |
|
|
|
|
) values.ips) |
|
|
|
|
|
|
|
|
|
("${wgCommand} set ${name} private-key ${privKey}" + |
|
|
|
|
optionalString (values.listenPort != null) " listen-port ${toString values.listenPort}") |
|
|
|
|
|
|
|
|
|
(map (peer: |
|
|
|
|
assert (peer.presharedKeyFile == null) || (peer.presharedKey == null); # at most one of the two must be set |
|
|
|
|
let psk = if peer.presharedKey != null then pkgs.writeText "wg-psk" peer.presharedKey else peer.presharedKeyFile; |
|
|
|
|
in |
|
|
|
|
"${wgCommand} set ${name} peer ${peer.publicKey}" + |
|
|
|
|
optionalString (psk != null) " preshared-key ${psk}" + |
|
|
|
|
optionalString (peer.endpoint != null) " endpoint ${peer.endpoint}" + |
|
|
|
|
optionalString (peer.persistentKeepalive != null) " persistent-keepalive ${toString peer.persistentKeepalive}" + |
|
|
|
|
optionalString (peer.allowedIPs != []) " allowed-ips ${concatStringsSep "," peer.allowedIPs}" |
|
|
|
|
) values.peers) |
|
|
|
|
|
|
|
|
|
"${ipCommand} link set up dev ${name}" |
|
|
|
|
|
|
|
|
|
(flatten (map (peer: (map (ip: |
|
|
|
|
(map (peer: (map (ip: |
|
|
|
|
"${ipCommand} route add ${ip} dev ${name}" |
|
|
|
|
) peer.allowedIPs)) values.peers)) |
|
|
|
|
) peer.allowedIPs)) values.peers) |
|
|
|
|
|
|
|
|
|
values.postSetup |
|
|
|
|
]); |
|
|
|
|
|
|
|
|
|
ExecStop = [ ''${ipCommand} link del dev "${name}"'' ] ++ values.postShutdown; |
|
|
|
|
ExecStop = flatten([ |
|
|
|
|
"${ipCommand} link del dev ${name}" |
|
|
|
|
values.postShutdown |
|
|
|
|
]); |
|
|
|
|
}; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|