migrate to systemd-networkd

This commit is contained in:
Katherina Walshe-Grey 2024-11-05 14:30:41 +00:00
parent 7f2f906acc
commit 29ca46fcdd

View file

@ -20,7 +20,7 @@ in
type = with types; nullOr str; type = with types; nullOr str;
}; };
interface = mkOption { interface = mkOption {
default = "birdsong"; default = "wg-birdsong";
example = "wg0"; example = "wg0";
description = "The name of the network interface to use for WireGuard."; description = "The name of the network interface to use for WireGuard.";
type = types.str; type = types.str;
@ -31,11 +31,15 @@ in
type = types.bool; type = types.bool;
}; };
privateKeyFile = mkOption { privateKeyFile = mkOption {
description = "Path to the private key for this peer, as generated by `wg genkey`."; description = ''
Path to the private key for this peer, as generated by `wg genkey`. Must
be readable by the user "systemd-network"; systemd.netdev(5) recommends
it be owned by "root:systemd-network" with a "0640" file mode.
'';
type = types.path; type = types.path;
}; };
persistentKeepalive = mkOption { persistentKeepalive = mkOption {
default = null; default = 0;
example = 23; example = 23;
description = '' description = ''
Constantly ping each peer outside the LAN this often, in seconds, in Constantly ping each peer outside the LAN this often, in seconds, in
@ -43,14 +47,18 @@ in
to keep the NAT session active, or if you have a dynamic IP to keep the to keep the NAT session active, or if you have a dynamic IP to keep the
other peers aware when your IP changes. To avoid syncing, this should other peers aware when your IP changes. To avoid syncing, this should
ideally be a prime number that is not shared by another peer in the same ideally be a prime number that is not shared by another peer in the same
LAN. LAN. 0 (the default) disables this.
''; '';
type = with types; nullOr int; type = types.int;
}; };
}; };
config = mkIf cfg.enable { config = mkIf cfg.enable {
assertions = [ assertions = [
{
assertion = systemd.network.enable == true;
message = "birdsong depends on networkd. systemd.network.enable must be true";
}
{ {
assertion = cfg ? privateKeyFile; assertion = cfg ? privateKeyFile;
message = "birdsong.peering.privateKeyFile must be set"; message = "birdsong.peering.privateKeyFile must be set";
@ -66,31 +74,43 @@ in
"net.ipv6.conf.${cfg.interface}.forwarding" = true; "net.ipv6.conf.${cfg.interface}.forwarding" = true;
}; };
networking = { networking.firewall.allowedUDPPorts = mkIf cfg.openPorts [ host.port ];
firewall.allowedUDPPorts = mkIf cfg.openPorts [ host.port ];
wireguard.interfaces.${cfg.interface} = { systemd.network = {
ips = [ "${host.ipv4}/16" "${host.ipv6}/48" ] enable = true;
++ optionals host.isRouter [ "10.127.0.0/16" "fd70:81ca:0f8f::/48" ];
privateKeyFile = cfg.privateKeyFile;
listenPort = host.port;
peers = netdevs."30-birdsong" = {
netdevConfig = {
Name = cfg.interface;
Kind = "wireguard";
Description = "wireguard tunnel to the birdsong network";
};
wireguardConfig = {
PrivateKeyFile = cfg.privateKeyFile;
ListenPort = host.port;
};
wireguardPeers =
let let
canDirectPeer = host: peer: peer.subnet == "internet" || (host.subnet != "roaming" && peer.subnet == host.subnet); canDirectPeer = host: peer: peer.subnet == "internet" || (host.subnet != "roaming" && peer.subnet == host.subnet);
in in
mapAttrsToList mapAttrsToList
(name: peer: { (name: peer: {
name = name; wireguardPeerConfig = {
publicKey = peer.wireguardKey; PublicKey = peer.wireguardKey;
allowedIPs = [ peer.ipv4 peer.ipv6 ] AllowedIPs = [ peer.ipv4 peer.ipv6 ]
++ optionals peer.isRouter [ "10.127.0.0/16" "fd70:81ca:0f8f::/48" ]; ++ optionals peer.isRouter [ "10.127.0.0/16" "fd70:81ca:0f8f::/48" ];
endpoint = mkIf (canDirectPeer host peer) "${peer.endpoint}:${toString peer.port}"; Endpoint = mkIf (canDirectPeer host peer) "${peer.endpoint}:${toString peer.port}";
dynamicEndpointRefreshSeconds = mkIf (canDirectPeer host peer) 5; PersistentKeepalive = mkIf (peer.subnet != host.subnet) cfg.persistentKeepalive;
persistentKeepalive = mkIf (peer.subnet != host.subnet) cfg.persistentKeepalive; };
}) })
(filterAttrs (name: peer: peer != host && (host.subnet == "internet" || canDirectPeer host peer)) hosts); (filterAttrs (name: peer: peer != host && (host.subnet == "internet" || canDirectPeer host peer)) hosts);
}; };
networks."30-birdsong" = {
matchConfig.Name = cfg.interface;
networkConfig.Address = [ "${host.ipv4}/16" "${host.ipv6}/48" ]
++ optionals host.isRouter [ "10.127.0.0/16" "fd70:81ca:0f8f::/48" ];
};
}; };
}; };
} }