wireguard service: use scripts instead of ExecStarts/Stops
This is more in line with what other services do; also looks cleaner. It changes configuration entries for pre-and post-hooks type to lines from lists of strings which are more logical for them; coersion is provided for backwards compatibility. Finally, add several steps to improve robustness: 1. Load kernel module on start if not loaded; 2. Don't remove wireguard interface on start; it is removed on service stop. If it's not something is wrong.
This commit is contained in:
parent
fb7cdbc15d
commit
7c90a86770
1 changed files with 48 additions and 47 deletions
|
@ -53,30 +53,30 @@ let
|
||||||
};
|
};
|
||||||
|
|
||||||
preSetup = mkOption {
|
preSetup = mkOption {
|
||||||
example = literalExample [''
|
example = literalExample ''
|
||||||
${pkgs.iproute}/bin/ip netns add foo
|
${pkgs.iproute}/bin/ip netns add foo
|
||||||
''];
|
'';
|
||||||
default = [];
|
default = "";
|
||||||
type = with types; listOf str;
|
type = with types; coercedTo (listOf str) (concatStringsSep "\n") lines;
|
||||||
description = ''
|
description = ''
|
||||||
A list of commands called at the start of the interface setup.
|
Commands called at the start of the interface setup.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
postSetup = mkOption {
|
postSetup = mkOption {
|
||||||
example = literalExample [''
|
example = literalExample ''
|
||||||
${pkgs.bash} -c 'printf "nameserver 10.200.100.1" | ${pkgs.openresolv}/bin/resolvconf -a wg0 -m 0'
|
printf "nameserver 10.200.100.1" | ${pkgs.openresolv}/bin/resolvconf -a wg0 -m 0
|
||||||
''];
|
'';
|
||||||
default = [];
|
default = "";
|
||||||
type = with types; listOf str;
|
type = with types; coercedTo (listOf str) (concatStringsSep "\n") lines;
|
||||||
description = "A list of commands called at the end of the interface setup.";
|
description = "Commands called at the end of the interface setup.";
|
||||||
};
|
};
|
||||||
|
|
||||||
postShutdown = mkOption {
|
postShutdown = mkOption {
|
||||||
example = literalExample ["${pkgs.openresolv}/bin/resolvconf -d wg0"];
|
example = literalExample "${pkgs.openresolv}/bin/resolvconf -d wg0";
|
||||||
default = [];
|
default = "";
|
||||||
type = with types; listOf str;
|
type = with types; coercedTo (listOf str) (concatStringsSep "\n") lines;
|
||||||
description = "A list of commands called after shutting down the interface.";
|
description = "Commands called after shutting down the interface.";
|
||||||
};
|
};
|
||||||
|
|
||||||
table = mkOption {
|
table = mkOption {
|
||||||
|
@ -182,9 +182,6 @@ let
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
ipCommand = "${pkgs.iproute}/bin/ip";
|
|
||||||
wgCommand = "${pkgs.wireguard}/bin/wg";
|
|
||||||
|
|
||||||
generateUnit = name: values:
|
generateUnit = name: values:
|
||||||
# exactly one way to specify the private key must be set
|
# exactly one way to specify the private key must be set
|
||||||
assert (values.privateKey != null) != (values.privateKeyFile != null);
|
assert (values.privateKey != null) != (values.privateKeyFile != null);
|
||||||
|
@ -196,49 +193,53 @@ let
|
||||||
after = [ "network.target" ];
|
after = [ "network.target" ];
|
||||||
wantedBy = [ "multi-user.target" ];
|
wantedBy = [ "multi-user.target" ];
|
||||||
environment.DEVICE = name;
|
environment.DEVICE = name;
|
||||||
|
path = with pkgs; [ kmod iproute wireguard ];
|
||||||
|
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
Type = "oneshot";
|
Type = "oneshot";
|
||||||
RemainAfterExit = true;
|
RemainAfterExit = true;
|
||||||
ExecStart = flatten([
|
};
|
||||||
values.preSetup
|
|
||||||
|
|
||||||
"-${ipCommand} link del dev ${name}"
|
script = ''
|
||||||
"${ipCommand} link add dev ${name} type wireguard"
|
modprobe wireguard
|
||||||
|
|
||||||
(map (ip:
|
${values.preSetup}
|
||||||
"${ipCommand} address add ${ip} dev ${name}"
|
|
||||||
) values.ips)
|
|
||||||
|
|
||||||
("${wgCommand} set ${name} private-key ${privKey}" +
|
ip link add dev ${name} type wireguard
|
||||||
optionalString (values.listenPort != null) " listen-port ${toString values.listenPort}")
|
|
||||||
|
|
||||||
(map (peer:
|
${concatMapStringsSep "\n" (ip:
|
||||||
|
"ip address add ${ip} dev ${name}"
|
||||||
|
) values.ips}
|
||||||
|
|
||||||
|
wg set ${name} private-key ${privKey} ${
|
||||||
|
optionalString (values.listenPort != null) " listen-port ${toString values.listenPort}"}
|
||||||
|
|
||||||
|
${concatMapStringsSep "\n" (peer:
|
||||||
assert (peer.presharedKeyFile == null) || (peer.presharedKey == null); # at most one of the two must be set
|
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;
|
let psk = if peer.presharedKey != null then pkgs.writeText "wg-psk" peer.presharedKey else peer.presharedKeyFile;
|
||||||
in
|
in
|
||||||
"${wgCommand} set ${name} peer ${peer.publicKey}" +
|
"wg set ${name} peer ${peer.publicKey}" +
|
||||||
optionalString (psk != null) " preshared-key ${psk}" +
|
optionalString (psk != null) " preshared-key ${psk}" +
|
||||||
optionalString (peer.endpoint != null) " endpoint ${peer.endpoint}" +
|
optionalString (peer.endpoint != null) " endpoint ${peer.endpoint}" +
|
||||||
optionalString (peer.persistentKeepalive != null) " persistent-keepalive ${toString peer.persistentKeepalive}" +
|
optionalString (peer.persistentKeepalive != null) " persistent-keepalive ${toString peer.persistentKeepalive}" +
|
||||||
optionalString (peer.allowedIPs != []) " allowed-ips ${concatStringsSep "," peer.allowedIPs}"
|
optionalString (peer.allowedIPs != []) " allowed-ips ${concatStringsSep "," peer.allowedIPs}"
|
||||||
) values.peers)
|
) values.peers}
|
||||||
|
|
||||||
"${ipCommand} link set up dev ${name}"
|
ip link set up dev ${name}
|
||||||
|
|
||||||
(optionals (values.allowedIPsAsRoutes != false) (map (peer:
|
${optionalString (values.allowedIPsAsRoutes != false) (concatStringsSep "\n" (concatMap (peer:
|
||||||
(map (allowedIP:
|
(map (allowedIP:
|
||||||
"${ipCommand} route replace ${allowedIP} dev ${name} table ${values.table}"
|
"ip route replace ${allowedIP} dev ${name} table ${values.table}"
|
||||||
) peer.allowedIPs)
|
) peer.allowedIPs)
|
||||||
) values.peers))
|
) values.peers))}
|
||||||
|
|
||||||
values.postSetup
|
${values.postSetup}
|
||||||
]);
|
'';
|
||||||
ExecStop = flatten([
|
|
||||||
"${ipCommand} link del dev ${name}"
|
preStop = ''
|
||||||
values.postShutdown
|
ip link del dev ${name}
|
||||||
]);
|
${values.postShutdown}
|
||||||
};
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
in
|
in
|
||||||
|
|
Loading…
Reference in a new issue