mirror of
https://github.com/NixOS/nixpkgs.git
synced 2025-07-13 21:50:33 +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
|
@ -1286,6 +1286,7 @@
|
||||||
./services/networking/wg-quick.nix
|
./services/networking/wg-quick.nix
|
||||||
./services/networking/wgautomesh.nix
|
./services/networking/wgautomesh.nix
|
||||||
./services/networking/wireguard.nix
|
./services/networking/wireguard.nix
|
||||||
|
./services/networking/wireguard-networkd.nix
|
||||||
./services/networking/wpa_supplicant.nix
|
./services/networking/wpa_supplicant.nix
|
||||||
./services/networking/wstunnel.nix
|
./services/networking/wstunnel.nix
|
||||||
./services/networking/x2goserver.nix
|
./services/networking/x2goserver.nix
|
||||||
|
|
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;
|
||||||
|
};
|
||||||
|
}
|
|
@ -49,6 +49,9 @@ let
|
||||||
default = null;
|
default = null;
|
||||||
description = ''
|
description = ''
|
||||||
Private key file as generated by {command}`wg genkey`.
|
Private key file as generated by {command}`wg genkey`.
|
||||||
|
|
||||||
|
When {option}`networking.wireguard.useNetworkd` is enabled, this file
|
||||||
|
must be readable by the `systemd-network` user.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -182,6 +185,28 @@ let
|
||||||
Set the metric of routes related to this Wireguard interface.
|
Set the metric of routes related to this Wireguard interface.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
dynamicEndpointRefreshSeconds = mkOption {
|
||||||
|
default = 0;
|
||||||
|
example = 300;
|
||||||
|
type = with types; int;
|
||||||
|
description = ''
|
||||||
|
Periodically refresh the endpoint hostname or address for all peers.
|
||||||
|
Allows WireGuard to notice DNS and IPv4/IPv6 connectivity changes.
|
||||||
|
This option can be set or overridden for individual peers.
|
||||||
|
|
||||||
|
Setting this to `0` disables periodic refresh.
|
||||||
|
|
||||||
|
::: {.warning}
|
||||||
|
When {option}`networking.wireguard.useNetworkd` is enabled, this
|
||||||
|
option deletes the Wireguard interface and brings it back up by
|
||||||
|
reconfiguring the network with `networkctl reload` on every refresh.
|
||||||
|
This could have adverse effects on your network and cause brief
|
||||||
|
connectivity blips. See [systemd/systemd#9911](https://github.com/systemd/systemd/issues/9911)
|
||||||
|
for an upstream feature request that can make this less hacky.
|
||||||
|
:::
|
||||||
|
'';
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -234,6 +259,9 @@ let
|
||||||
Optional, and may be omitted. This option adds an additional layer of
|
Optional, and may be omitted. This option adds an additional layer of
|
||||||
symmetric-key cryptography to be mixed into the already existing
|
symmetric-key cryptography to be mixed into the already existing
|
||||||
public-key cryptography, for post-quantum resistance.
|
public-key cryptography, for post-quantum resistance.
|
||||||
|
|
||||||
|
When {option}`networking.wireguard.useNetworkd` is enabled, this file
|
||||||
|
must be readable by the `systemd-network` user.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -269,15 +297,21 @@ let
|
||||||
};
|
};
|
||||||
|
|
||||||
dynamicEndpointRefreshSeconds = mkOption {
|
dynamicEndpointRefreshSeconds = mkOption {
|
||||||
default = 0;
|
default = null;
|
||||||
|
defaultText = literalExpression "config.networking.wireguard.interfaces.<name>.dynamicEndpointRefreshSeconds";
|
||||||
example = 5;
|
example = 5;
|
||||||
type = with types; int;
|
type = with types; nullOr int;
|
||||||
description = ''
|
description = ''
|
||||||
Periodically re-execute the `wg` utility every
|
Periodically re-execute the `wg` utility every
|
||||||
this many seconds in order to let WireGuard notice DNS / hostname
|
this many seconds in order to let WireGuard notice DNS / hostname
|
||||||
changes.
|
changes.
|
||||||
|
|
||||||
Setting this to `0` disables periodic reexecution.
|
Setting this to `0` disables periodic reexecution.
|
||||||
|
|
||||||
|
::: {.note}
|
||||||
|
This peer-level setting is not available when {option}`networking.wireguard.useNetworkd`
|
||||||
|
is enabled. The interface-level setting may be used instead.
|
||||||
|
:::
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -349,6 +383,11 @@ let
|
||||||
in
|
in
|
||||||
"wireguard-${interfaceName}-peer-${peerName}${refreshSuffix}";
|
"wireguard-${interfaceName}-peer-${peerName}${refreshSuffix}";
|
||||||
|
|
||||||
|
dynamicRefreshSeconds = interfaceCfg: peer:
|
||||||
|
if peer.dynamicEndpointRefreshSeconds != null
|
||||||
|
then peer.dynamicEndpointRefreshSeconds
|
||||||
|
else interfaceCfg.dynamicEndpointRefreshSeconds;
|
||||||
|
|
||||||
generatePeerUnit = { interfaceName, interfaceCfg, peer }:
|
generatePeerUnit = { interfaceName, interfaceCfg, peer }:
|
||||||
let
|
let
|
||||||
psk =
|
psk =
|
||||||
|
@ -359,7 +398,8 @@ let
|
||||||
dst = interfaceCfg.interfaceNamespace;
|
dst = interfaceCfg.interfaceNamespace;
|
||||||
ip = nsWrap "ip" src dst;
|
ip = nsWrap "ip" src dst;
|
||||||
wg = nsWrap "wg" src dst;
|
wg = nsWrap "wg" src dst;
|
||||||
dynamicRefreshEnabled = peer.dynamicEndpointRefreshSeconds != 0;
|
dynamicEndpointRefreshSeconds = dynamicRefreshSeconds interfaceCfg peer;
|
||||||
|
dynamicRefreshEnabled = dynamicEndpointRefreshSeconds != 0;
|
||||||
# We generate a different name (a `-refresh` suffix) when `dynamicEndpointRefreshSeconds`
|
# We generate a different name (a `-refresh` suffix) when `dynamicEndpointRefreshSeconds`
|
||||||
# to avoid that the same service switches `Type` (`oneshot` vs `simple`),
|
# to avoid that the same service switches `Type` (`oneshot` vs `simple`),
|
||||||
# with the intent to make scripting more obvious.
|
# with the intent to make scripting more obvious.
|
||||||
|
@ -395,7 +435,7 @@ let
|
||||||
Restart = "always";
|
Restart = "always";
|
||||||
RestartSec = if null != peer.dynamicEndpointRefreshRestartSeconds
|
RestartSec = if null != peer.dynamicEndpointRefreshRestartSeconds
|
||||||
then peer.dynamicEndpointRefreshRestartSeconds
|
then peer.dynamicEndpointRefreshRestartSeconds
|
||||||
else peer.dynamicEndpointRefreshSeconds;
|
else dynamicEndpointRefreshSeconds;
|
||||||
};
|
};
|
||||||
unitConfig = lib.optionalAttrs dynamicRefreshEnabled {
|
unitConfig = lib.optionalAttrs dynamicRefreshEnabled {
|
||||||
StartLimitIntervalSec = 0;
|
StartLimitIntervalSec = 0;
|
||||||
|
@ -419,13 +459,13 @@ let
|
||||||
${wg_setup}
|
${wg_setup}
|
||||||
${route_setup}
|
${route_setup}
|
||||||
|
|
||||||
${optionalString (peer.dynamicEndpointRefreshSeconds != 0) ''
|
${optionalString (dynamicEndpointRefreshSeconds != 0) ''
|
||||||
# Re-execute 'wg' periodically to notice DNS / hostname changes.
|
# Re-execute 'wg' periodically to notice DNS / hostname changes.
|
||||||
# Note this will not time out on transient DNS failures such as DNS names
|
# Note this will not time out on transient DNS failures such as DNS names
|
||||||
# because we have set 'WG_ENDPOINT_RESOLUTION_RETRIES=infinity'.
|
# because we have set 'WG_ENDPOINT_RESOLUTION_RETRIES=infinity'.
|
||||||
# Also note that 'wg' limits its maximum retry delay to 20 seconds as of writing.
|
# Also note that 'wg' limits its maximum retry delay to 20 seconds as of writing.
|
||||||
while ${wg_setup}; do
|
while ${wg_setup}; do
|
||||||
sleep "${toString peer.dynamicEndpointRefreshSeconds}";
|
sleep "${toString dynamicEndpointRefreshSeconds}";
|
||||||
done
|
done
|
||||||
''}
|
''}
|
||||||
'';
|
'';
|
||||||
|
@ -445,7 +485,7 @@ let
|
||||||
# the target is required to start new peer units when they are added
|
# the target is required to start new peer units when they are added
|
||||||
generateInterfaceTarget = name: values:
|
generateInterfaceTarget = name: values:
|
||||||
let
|
let
|
||||||
mkPeerUnit = peer: (peerUnitServiceName name peer.name (peer.dynamicEndpointRefreshSeconds != 0)) + ".service";
|
mkPeerUnit = peer: (peerUnitServiceName name peer.name (dynamicRefreshSeconds values peer != 0)) + ".service";
|
||||||
in
|
in
|
||||||
nameValuePair "wireguard-${name}"
|
nameValuePair "wireguard-${name}"
|
||||||
rec {
|
rec {
|
||||||
|
@ -530,9 +570,10 @@ in
|
||||||
description = ''
|
description = ''
|
||||||
Whether to enable WireGuard.
|
Whether to enable WireGuard.
|
||||||
|
|
||||||
Please note that {option}`systemd.network.netdevs` has more features
|
::: {.note}
|
||||||
and is better maintained. When building new things, it is advised to
|
By default, this module is powered by a script-based backend. You can
|
||||||
use that instead.
|
enable the networkd backend with {option}`networking.wireguard.useNetworkd`.
|
||||||
|
:::
|
||||||
'';
|
'';
|
||||||
type = types.bool;
|
type = types.bool;
|
||||||
# 2019-05-25: Backwards compatibility.
|
# 2019-05-25: Backwards compatibility.
|
||||||
|
@ -544,10 +585,6 @@ in
|
||||||
interfaces = mkOption {
|
interfaces = mkOption {
|
||||||
description = ''
|
description = ''
|
||||||
WireGuard interfaces.
|
WireGuard interfaces.
|
||||||
|
|
||||||
Please note that {option}`systemd.network.netdevs` has more features
|
|
||||||
and is better maintained. When building new things, it is advised to
|
|
||||||
use that instead.
|
|
||||||
'';
|
'';
|
||||||
default = {};
|
default = {};
|
||||||
example = {
|
example = {
|
||||||
|
@ -597,13 +634,13 @@ in
|
||||||
boot.kernelModules = [ "wireguard" ];
|
boot.kernelModules = [ "wireguard" ];
|
||||||
environment.systemPackages = [ pkgs.wireguard-tools ];
|
environment.systemPackages = [ pkgs.wireguard-tools ];
|
||||||
|
|
||||||
systemd.services =
|
systemd.services = mkIf (!cfg.useNetworkd) (
|
||||||
(mapAttrs' generateInterfaceUnit cfg.interfaces)
|
(mapAttrs' generateInterfaceUnit cfg.interfaces)
|
||||||
// (listToAttrs (map generatePeerUnit all_peers))
|
// (listToAttrs (map generatePeerUnit all_peers))
|
||||||
// (mapAttrs' generateKeyServiceUnit
|
// (mapAttrs' generateKeyServiceUnit
|
||||||
(filterAttrs (name: value: value.generatePrivateKeyFile) cfg.interfaces));
|
(filterAttrs (name: value: value.generatePrivateKeyFile) cfg.interfaces)));
|
||||||
|
|
||||||
systemd.targets = mapAttrs' generateInterfaceTarget cfg.interfaces;
|
systemd.targets = mkIf (!cfg.useNetworkd) (mapAttrs' generateInterfaceTarget cfg.interfaces);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -11,9 +11,12 @@ let
|
||||||
tests = let callTest = p: args: import p ({ inherit system pkgs; } // args); in {
|
tests = let callTest = p: args: import p ({ inherit system pkgs; } // args); in {
|
||||||
basic = callTest ./basic.nix;
|
basic = callTest ./basic.nix;
|
||||||
namespaces = callTest ./namespaces.nix;
|
namespaces = callTest ./namespaces.nix;
|
||||||
|
networkd = callTest ./networkd.nix;
|
||||||
wg-quick = callTest ./wg-quick.nix;
|
wg-quick = callTest ./wg-quick.nix;
|
||||||
wg-quick-nftables = args: callTest ./wg-quick.nix ({ nftables = true; } // args);
|
wg-quick-nftables = args: callTest ./wg-quick.nix ({ nftables = true; } // args);
|
||||||
generated = callTest ./generated.nix;
|
generated = callTest ./generated.nix;
|
||||||
|
dynamic-refresh = callTest ./dynamic-refresh.nix;
|
||||||
|
dynamic-refresh-networkd = args: callTest ./dynamic-refresh.nix ({ useNetworkd = true; } // args);
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
|
|
||||||
|
|
102
nixos/tests/wireguard/dynamic-refresh.nix
Normal file
102
nixos/tests/wireguard/dynamic-refresh.nix
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
import ../make-test-python.nix (
|
||||||
|
{
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
kernelPackages ? null,
|
||||||
|
useNetworkd ? false,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
wg-snakeoil-keys = import ./snakeoil-keys.nix;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
name = "wireguard-dynamic-refresh";
|
||||||
|
meta = with lib.maintainers; {
|
||||||
|
maintainers = [ majiir ];
|
||||||
|
};
|
||||||
|
|
||||||
|
nodes = {
|
||||||
|
server = {
|
||||||
|
virtualisation.vlans = [
|
||||||
|
1
|
||||||
|
2
|
||||||
|
];
|
||||||
|
boot = lib.mkIf (kernelPackages != null) { inherit kernelPackages; };
|
||||||
|
networking.firewall.allowedUDPPorts = [ 23542 ];
|
||||||
|
networking.useDHCP = false;
|
||||||
|
networking.wireguard.useNetworkd = useNetworkd;
|
||||||
|
networking.wireguard.interfaces.wg0 = {
|
||||||
|
ips = [ "10.23.42.1/32" ];
|
||||||
|
listenPort = 23542;
|
||||||
|
|
||||||
|
# !!! Don't do this with real keys. The /nix store is world-readable!
|
||||||
|
privateKeyFile = toString (pkgs.writeText "privateKey" wg-snakeoil-keys.peer0.privateKey);
|
||||||
|
|
||||||
|
peers = lib.singleton {
|
||||||
|
allowedIPs = [ "10.23.42.2/32" ];
|
||||||
|
|
||||||
|
inherit (wg-snakeoil-keys.peer1) publicKey;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
client =
|
||||||
|
{ nodes, ... }:
|
||||||
|
{
|
||||||
|
virtualisation.vlans = [
|
||||||
|
1
|
||||||
|
2
|
||||||
|
];
|
||||||
|
boot = lib.mkIf (kernelPackages != null) { inherit kernelPackages; };
|
||||||
|
networking.useDHCP = false;
|
||||||
|
networking.wireguard.useNetworkd = useNetworkd;
|
||||||
|
networking.wireguard.interfaces.wg0 = {
|
||||||
|
ips = [ "10.23.42.2/32" ];
|
||||||
|
|
||||||
|
# !!! Don't do this with real keys. The /nix store is world-readable!
|
||||||
|
privateKeyFile = toString (pkgs.writeText "privateKey" wg-snakeoil-keys.peer1.privateKey);
|
||||||
|
|
||||||
|
dynamicEndpointRefreshSeconds = 2;
|
||||||
|
|
||||||
|
peers = lib.singleton {
|
||||||
|
allowedIPs = [
|
||||||
|
"0.0.0.0/0"
|
||||||
|
"::/0"
|
||||||
|
];
|
||||||
|
endpoint = "server:23542";
|
||||||
|
|
||||||
|
inherit (wg-snakeoil-keys.peer0) publicKey;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
specialisation.update-hosts.configuration = {
|
||||||
|
networking.extraHosts =
|
||||||
|
let
|
||||||
|
testCfg = nodes.server.virtualisation.test;
|
||||||
|
in
|
||||||
|
lib.mkForce "192.168.2.${toString testCfg.nodeNumber} ${testCfg.nodeName}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
testScript =
|
||||||
|
{ nodes, ... }:
|
||||||
|
''
|
||||||
|
start_all()
|
||||||
|
|
||||||
|
server.wait_for_unit("network-online.target")
|
||||||
|
client.wait_for_unit("network-online.target")
|
||||||
|
|
||||||
|
client.succeed("ping -n -w 1 -c 1 10.23.42.1")
|
||||||
|
|
||||||
|
client.succeed("ip link set down eth1")
|
||||||
|
|
||||||
|
client.fail("ping -n -w 1 -c 1 10.23.42.1")
|
||||||
|
|
||||||
|
with client.nested("update hosts file"):
|
||||||
|
client.succeed("${nodes.client.system.build.toplevel}/specialisation/update-hosts/bin/switch-to-configuration test")
|
||||||
|
|
||||||
|
client.succeed("sleep 5 && ping -n -w 1 -c 1 10.23.42.1")
|
||||||
|
'';
|
||||||
|
}
|
||||||
|
)
|
89
nixos/tests/wireguard/networkd.nix
Normal file
89
nixos/tests/wireguard/networkd.nix
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
import ../make-test-python.nix (
|
||||||
|
{
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
kernelPackages ? null,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
wg-snakeoil-keys = import ./snakeoil-keys.nix;
|
||||||
|
peer = (import ./make-peer.nix) { inherit lib; };
|
||||||
|
in
|
||||||
|
{
|
||||||
|
name = "wireguard-networkd";
|
||||||
|
meta = with pkgs.lib.maintainers; {
|
||||||
|
maintainers = [ majiir ];
|
||||||
|
};
|
||||||
|
|
||||||
|
nodes = {
|
||||||
|
peer0 = peer {
|
||||||
|
ip4 = "192.168.0.1";
|
||||||
|
ip6 = "fd00::1";
|
||||||
|
extraConfig = {
|
||||||
|
boot = lib.mkIf (kernelPackages != null) { inherit kernelPackages; };
|
||||||
|
networking.firewall.allowedUDPPorts = [ 23542 ];
|
||||||
|
networking.wireguard.useNetworkd = true;
|
||||||
|
networking.wireguard.interfaces.wg0 = {
|
||||||
|
ips = [
|
||||||
|
"10.23.42.1/32"
|
||||||
|
"fc00::1/128"
|
||||||
|
];
|
||||||
|
listenPort = 23542;
|
||||||
|
|
||||||
|
# !!! Don't do this with real keys. The /nix store is world-readable!
|
||||||
|
privateKeyFile = toString (pkgs.writeText "privateKey" wg-snakeoil-keys.peer0.privateKey);
|
||||||
|
|
||||||
|
peers = lib.singleton {
|
||||||
|
allowedIPs = [
|
||||||
|
"10.23.42.2/32"
|
||||||
|
"fc00::2/128"
|
||||||
|
];
|
||||||
|
|
||||||
|
inherit (wg-snakeoil-keys.peer1) publicKey;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
peer1 = peer {
|
||||||
|
ip4 = "192.168.0.2";
|
||||||
|
ip6 = "fd00::2";
|
||||||
|
extraConfig = {
|
||||||
|
boot = lib.mkIf (kernelPackages != null) { inherit kernelPackages; };
|
||||||
|
networking.wireguard.useNetworkd = true;
|
||||||
|
networking.wireguard.interfaces.wg0 = {
|
||||||
|
ips = [
|
||||||
|
"10.23.42.2/32"
|
||||||
|
"fc00::2/128"
|
||||||
|
];
|
||||||
|
listenPort = 23542;
|
||||||
|
|
||||||
|
# !!! Don't do this with real keys. The /nix store is world-readable!
|
||||||
|
privateKeyFile = toString (pkgs.writeText "privateKey" wg-snakeoil-keys.peer1.privateKey);
|
||||||
|
|
||||||
|
peers = lib.singleton {
|
||||||
|
allowedIPs = [
|
||||||
|
"0.0.0.0/0"
|
||||||
|
"::/0"
|
||||||
|
];
|
||||||
|
endpoint = "192.168.0.1:23542";
|
||||||
|
persistentKeepalive = 25;
|
||||||
|
|
||||||
|
inherit (wg-snakeoil-keys.peer0) publicKey;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
testScript = ''
|
||||||
|
start_all()
|
||||||
|
|
||||||
|
peer0.wait_for_unit("systemd-networkd-wait-online.service")
|
||||||
|
peer1.wait_for_unit("systemd-networkd-wait-online.service")
|
||||||
|
|
||||||
|
peer1.succeed("ping -c5 fc00::1")
|
||||||
|
peer1.succeed("ping -c5 10.23.42.1")
|
||||||
|
'';
|
||||||
|
}
|
||||||
|
)
|
Loading…
Add table
Add a link
Reference in a new issue