diff --git a/peering.nix b/peering.nix index 170a986..ae79766 100644 --- a/peering.nix +++ b/peering.nix @@ -20,7 +20,7 @@ in type = with types; nullOr str; }; interface = mkOption { - default = "birdsong"; + default = "wg-birdsong"; example = "wg0"; description = "The name of the network interface to use for WireGuard."; type = types.str; @@ -31,11 +31,15 @@ in type = types.bool; }; 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; }; persistentKeepalive = mkOption { - default = null; + default = 0; example = 23; description = '' 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 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 - LAN. + LAN. 0 (the default) disables this. ''; - type = with types; nullOr int; + type = types.int; }; }; config = mkIf cfg.enable { assertions = [ + { + assertion = systemd.network.enable == true; + message = "birdsong depends on networkd. systemd.network.enable must be true"; + } { assertion = cfg ? privateKeyFile; message = "birdsong.peering.privateKeyFile must be set"; @@ -66,31 +74,43 @@ in "net.ipv6.conf.${cfg.interface}.forwarding" = true; }; - networking = { - firewall.allowedUDPPorts = mkIf cfg.openPorts [ host.port ]; + networking.firewall.allowedUDPPorts = mkIf cfg.openPorts [ host.port ]; - wireguard.interfaces.${cfg.interface} = { - ips = [ "${host.ipv4}/16" "${host.ipv6}/48" ] - ++ optionals host.isRouter [ "10.127.0.0/16" "fd70:81ca:0f8f::/48" ]; - privateKeyFile = cfg.privateKeyFile; - listenPort = host.port; + systemd.network = { + enable = true; - 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 canDirectPeer = host: peer: peer.subnet == "internet" || (host.subnet != "roaming" && peer.subnet == host.subnet); in mapAttrsToList (name: peer: { - name = name; - publicKey = peer.wireguardKey; - allowedIPs = [ peer.ipv4 peer.ipv6 ] - ++ optionals peer.isRouter [ "10.127.0.0/16" "fd70:81ca:0f8f::/48" ]; - endpoint = mkIf (canDirectPeer host peer) "${peer.endpoint}:${toString peer.port}"; - dynamicEndpointRefreshSeconds = mkIf (canDirectPeer host peer) 5; - persistentKeepalive = mkIf (peer.subnet != host.subnet) cfg.persistentKeepalive; + wireguardPeerConfig = { + PublicKey = peer.wireguardKey; + AllowedIPs = [ peer.ipv4 peer.ipv6 ] + ++ optionals peer.isRouter [ "10.127.0.0/16" "fd70:81ca:0f8f::/48" ]; + Endpoint = mkIf (canDirectPeer host peer) "${peer.endpoint}:${toString peer.port}"; + PersistentKeepalive = mkIf (peer.subnet != host.subnet) cfg.persistentKeepalive; + }; }) (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" ]; + }; }; }; }