mirror of
https://github.com/NixOS/nixpkgs.git
synced 2024-11-23 06:01:15 +00:00
Merge pull request #121331 from nh2/wireguard-dynamicEndpointRefreshSeconds
nixos/wireguard: Add `dynamicEndpointRefreshSeconds` option
This commit is contained in:
commit
83a8acc392
|
@ -395,6 +395,15 @@
|
|||
which is the new stable release. OpenAFS 1.6 was removed.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
The WireGuard module gained a new option
|
||||
<option>networking.wireguard.interfaces.<name>.peers.*.dynamicEndpointRefreshSeconds</option>
|
||||
that implements refreshing the IP of DNS-based endpoints periodically
|
||||
(which WireGuard itself
|
||||
<link xlink:href="https://lists.zx2c4.com/pipermail/wireguard/2017-November/002028.html">cannot do</link>).
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
MariaDB has been updated to 10.5.
|
||||
|
|
|
@ -198,7 +198,32 @@ let
|
|||
example = "demo.wireguard.io:12913";
|
||||
type = with types; nullOr str;
|
||||
description = ''Endpoint IP or hostname of the peer, followed by a colon,
|
||||
and then a port number of the peer.'';
|
||||
and then a port number of the peer.
|
||||
|
||||
Warning for endpoints with changing IPs:
|
||||
The WireGuard kernel side cannot perform DNS resolution.
|
||||
Thus DNS resolution is done once by the <literal>wg</literal> userspace
|
||||
utility, when setting up WireGuard. Consequently, if the IP address
|
||||
behind the name changes, WireGuard will not notice.
|
||||
This is especially common for dynamic-DNS setups, but also applies to
|
||||
any other DNS-based setup.
|
||||
If you do not use IP endpoints, you likely want to set
|
||||
<option>networking.wireguard.dynamicEndpointRefreshSeconds</option>
|
||||
to refresh the IPs periodically.
|
||||
'';
|
||||
};
|
||||
|
||||
dynamicEndpointRefreshSeconds = mkOption {
|
||||
default = 0;
|
||||
example = 5;
|
||||
type = with types; int;
|
||||
description = ''
|
||||
Periodically re-execute the <literal>wg</literal> utility every
|
||||
this many seconds in order to let WireGuard notice DNS / hostname
|
||||
changes.
|
||||
|
||||
Setting this to <literal>0</literal> disables periodic reexecution.
|
||||
'';
|
||||
};
|
||||
|
||||
persistentKeepalive = mkOption {
|
||||
|
@ -259,12 +284,18 @@ let
|
|||
'';
|
||||
};
|
||||
|
||||
generatePeerUnit = { interfaceName, interfaceCfg, peer }:
|
||||
peerUnitServiceName = interfaceName: publicKey: dynamicRefreshEnabled:
|
||||
let
|
||||
keyToUnitName = replaceChars
|
||||
[ "/" "-" " " "+" "=" ]
|
||||
[ "-" "\\x2d" "\\x20" "\\x2b" "\\x3d" ];
|
||||
unitName = keyToUnitName peer.publicKey;
|
||||
unitName = keyToUnitName publicKey;
|
||||
refreshSuffix = optionalString dynamicRefreshEnabled "-refresh";
|
||||
in
|
||||
"wireguard-${interfaceName}-peer-${unitName}${refreshSuffix}";
|
||||
|
||||
generatePeerUnit = { interfaceName, interfaceCfg, peer }:
|
||||
let
|
||||
psk =
|
||||
if peer.presharedKey != null
|
||||
then pkgs.writeText "wg-psk" peer.presharedKey
|
||||
|
@ -273,7 +304,12 @@ let
|
|||
dst = interfaceCfg.interfaceNamespace;
|
||||
ip = nsWrap "ip" src dst;
|
||||
wg = nsWrap "wg" src dst;
|
||||
in nameValuePair "wireguard-${interfaceName}-peer-${unitName}"
|
||||
dynamicRefreshEnabled = peer.dynamicEndpointRefreshSeconds != 0;
|
||||
# We generate a different name (a `-refresh` suffix) when `dynamicEndpointRefreshSeconds`
|
||||
# to avoid that the same service switches `Type` (`oneshot` vs `simple`),
|
||||
# with the intent to make scripting more obvious.
|
||||
serviceName = peerUnitServiceName interfaceName peer.publicKey dynamicRefreshEnabled;
|
||||
in nameValuePair serviceName
|
||||
{
|
||||
description = "WireGuard Peer - ${interfaceName} - ${peer.publicKey}";
|
||||
requires = [ "wireguard-${interfaceName}.service" ];
|
||||
|
@ -283,36 +319,59 @@ let
|
|||
environment.WG_ENDPOINT_RESOLUTION_RETRIES = "infinity";
|
||||
path = with pkgs; [ iproute2 wireguard-tools ];
|
||||
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
};
|
||||
serviceConfig =
|
||||
if !dynamicRefreshEnabled
|
||||
then
|
||||
{
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Type = "simple"; # re-executes 'wg' indefinitely
|
||||
# Note that `Type = "oneshot"` services with `RemainAfterExit = true`
|
||||
# cannot be used with systemd timers (see `man systemd.timer`),
|
||||
# which is why `simple` with a loop is the best choice here.
|
||||
# It also makes starting and stopping easiest.
|
||||
};
|
||||
|
||||
script = let
|
||||
wg_setup = "${wg} set ${interfaceName} 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}";
|
||||
wg_setup = concatStringsSep " " (
|
||||
[ ''${wg} set ${interfaceName} peer "${peer.publicKey}"'' ]
|
||||
++ optional (psk != null) ''preshared-key "${psk}"''
|
||||
++ optional (peer.endpoint != null) ''endpoint "${peer.endpoint}"''
|
||||
++ optional (peer.persistentKeepalive != null) ''persistent-keepalive "${toString peer.persistentKeepalive}"''
|
||||
++ optional (peer.allowedIPs != []) ''allowed-ips "${concatStringsSep "," peer.allowedIPs}"''
|
||||
);
|
||||
route_setup =
|
||||
optionalString interfaceCfg.allowedIPsAsRoutes
|
||||
(concatMapStringsSep "\n"
|
||||
(allowedIP:
|
||||
"${ip} route replace ${allowedIP} dev ${interfaceName} table ${interfaceCfg.table}"
|
||||
''${ip} route replace "${allowedIP}" dev "${interfaceName}" table "${interfaceCfg.table}"''
|
||||
) peer.allowedIPs);
|
||||
in ''
|
||||
${wg_setup}
|
||||
${route_setup}
|
||||
|
||||
${optionalString (peer.dynamicEndpointRefreshSeconds != 0) ''
|
||||
# Re-execute 'wg' periodically to notice DNS / hostname changes.
|
||||
# Note this will not time out on transient DNS failures such as DNS names
|
||||
# because we have set 'WG_ENDPOINT_RESOLUTION_RETRIES=infinity'.
|
||||
# Also note that 'wg' limits its maximum retry delay to 20 seconds as of writing.
|
||||
while ${wg_setup}; do
|
||||
sleep "${toString peer.dynamicEndpointRefreshSeconds}";
|
||||
done
|
||||
''}
|
||||
'';
|
||||
|
||||
postStop = let
|
||||
route_destroy = optionalString interfaceCfg.allowedIPsAsRoutes
|
||||
(concatMapStringsSep "\n"
|
||||
(allowedIP:
|
||||
"${ip} route delete ${allowedIP} dev ${interfaceName} table ${interfaceCfg.table}"
|
||||
''${ip} route delete "${allowedIP}" dev "${interfaceName}" table "${interfaceCfg.table}"''
|
||||
) peer.allowedIPs);
|
||||
in ''
|
||||
${wg} set ${interfaceName} peer ${peer.publicKey} remove
|
||||
${wg} set "${interfaceName}" peer "${peer.publicKey}" remove
|
||||
${route_destroy}
|
||||
'';
|
||||
};
|
||||
|
@ -348,23 +407,25 @@ let
|
|||
|
||||
${values.preSetup}
|
||||
|
||||
${ipPreMove} link add dev ${name} type wireguard
|
||||
${optionalString (values.interfaceNamespace != null && values.interfaceNamespace != values.socketNamespace) "${ipPreMove} link set ${name} netns ${ns}"}
|
||||
${ipPreMove} link add dev "${name}" type wireguard
|
||||
${optionalString (values.interfaceNamespace != null && values.interfaceNamespace != values.socketNamespace) ''${ipPreMove} link set "${name}" netns "${ns}"''}
|
||||
|
||||
${concatMapStringsSep "\n" (ip:
|
||||
"${ipPostMove} address add ${ip} dev ${name}"
|
||||
''${ipPostMove} address add "${ip}" dev "${name}"''
|
||||
) values.ips}
|
||||
|
||||
${wg} set ${name} private-key ${privKey} ${
|
||||
optionalString (values.listenPort != null) " listen-port ${toString values.listenPort}"}
|
||||
${concatStringsSep " " (
|
||||
[ ''${wg} set "${name}" private-key "${privKey}"'' ]
|
||||
++ optional (values.listenPort != null) ''listen-port "${toString values.listenPort}"''
|
||||
)}
|
||||
|
||||
${ipPostMove} link set up dev ${name}
|
||||
${ipPostMove} link set up dev "${name}"
|
||||
|
||||
${values.postSetup}
|
||||
'';
|
||||
|
||||
postStop = ''
|
||||
${ipPostMove} link del dev ${name}
|
||||
${ipPostMove} link del dev "${name}"
|
||||
${values.postShutdown}
|
||||
'';
|
||||
};
|
||||
|
@ -374,7 +435,7 @@ let
|
|||
nsList = filter (ns: ns != null) [ src dst ];
|
||||
ns = last nsList;
|
||||
in
|
||||
if (length nsList > 0 && ns != "init") then "ip netns exec ${ns} ${cmd}" else cmd;
|
||||
if (length nsList > 0 && ns != "init") then ''ip netns exec "${ns}" "${cmd}"'' else cmd;
|
||||
in
|
||||
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue