{ lib, config, ... }: { config = let currenthost = config.networking.hostName; wg = config.oxalab.wg; # get all the networks we participate in networks = builtins.filter (net: builtins.hasAttr "${currenthost}" net.hosts) wg; # create wg networks network-attrset = map (net: { name = "30-wg-${net.networkName}"; value = { matchConfig.Name = "wg-${net.networkName}"; networkConfig = { Address = net.hosts.${currenthost}.address; IPv6AcceptRA = false; # for now static IPv6 } // ( if net.hosts.${currenthost}.endpoint.enable then { IPv4Forwarding = true; IPv6Forwarding = true; } else { } ); }; }) networks; systemd-networks = builtins.listToAttrs network-attrset; # get all the networks we client in net-client = builtins.filter (net: !net.hosts.${currenthost}.endpoint.enable) networks; # get all the networks we are endpoint of net-endpoint = builtins.filter (net: net.hosts.${currenthost}.endpoint.enable) networks; # wg netdevs # client netdev-client-list = map (net: { name = "30-wg-${net.networkName}"; value = { netdevConfig = { Kind = "wireguard"; Name = "wg-${net.networkName}"; }; wireguardConfig.PrivateKeyFile = net.hosts.${currenthost}.privateKeyFile; # for client this is only endpoint for now wireguardPeers = let endpoint = lib.attrsets.filterAttrs (_k: v: v.endpoint.enable) net.hosts; wg-peers-attrs = lib.attrsets.mapAttrs (_k: v: { PersistentKeepalive = 29; PublicKey = v.publicKey; Endpoint = "${v.endpoint.endpoint}:${toString v.endpoint.port}"; AllowedIPs = net.CIDRs; }) endpoint; wg-peers = lib.attrsets.attrValues wg-peers-attrs; in wg-peers; }; }) net-client; netdev-client = builtins.listToAttrs netdev-client-list; maskip = ( _net: hostattrs: if hostattrs.endpoint.enable then hostattrs.address else map (baseaddr: if lib.strings.hasInfix "." baseaddr then "${baseaddr}/32" else "${baseaddr}/128") ( map (addr: builtins.elemAt (lib.strings.splitString "/" addr) 0) hostattrs.address ) ); # endpoint # TODO: this requires bit more logic for allowedIPs if we have more then # 2 endpoints e.g. for routing client -> endpoint1 -> endpoint2 -> # client2 netdev-endpoint-list = map (net: { name = "30-wg-${net.networkName}"; value = { netdevConfig = { Kind = "wireguard"; Name = "wg-${net.networkName}"; }; wireguardConfig.PrivateKeyFile = net.hosts.${currenthost}.privateKeyFile; wireguardConfig.ListenPort = net.hosts.${currenthost}.endpoint.port; wireguardPeers = let peers = lib.attrsets.filterAttrs (k: _v: k != currenthost) net.hosts; wg-peers-attrs = lib.attrsets.mapAttrs ( _k: v: { PersistentKeepalive = 29; PublicKey = v.publicKey; # only route to /32 or /128, i.e. single client AllowedIPs = maskip net v; } // ( if !isNull v.endpoint.endpoint then { Endpoint = "${v.endpoint.endpoint}:${toString v.endpoint.port}"; } else { } ) ) peers; wg-peers = lib.attrsets.attrValues wg-peers-attrs; in wg-peers; }; }) net-endpoint; netdev-endpoint = builtins.listToAttrs netdev-endpoint-list; in { # make sure that the networkd and wg are enabled networking.wireguard.enable = true; systemd.network.enable = true; systemd.network.networks = systemd-networks; systemd.network.netdevs = netdev-client // netdev-endpoint; }; }