{ config, hostName, lib, pkgs, ... }: with lib; let listenPort = { "4" = 51820; "6" = 51821; }; wgSubnet = { "4" = "2a03:4000:52:ada:2"; "6" = "2a03:4000:52:ada:3"; }; wgSubnetLength = 80; wgHostLength = wgSubnetLength + 16; batSubnet = "2a03:4000:52:ada:1"; batSubnetLength = 80; batHostLength = batSubnetLength + 16; links = mkLinks [ { from = "vidhar"; to = "surtr"; endpointHost = "202.61.241.61"; PersistentKeepalive = 25; family = "4"; } { from = "vidhar"; to = "surtr"; endpointHost = "2a03:4000:52:ada::"; PersistentKeepalive = 25; family = "6"; } { from = "sif"; to = "surtr"; endpointHost = "202.61.241.61"; PersistentKeepalive = 25; family = "4"; } { from = "sif"; to = "surtr"; endpointHost = "2a03:4000:52:ada::"; PersistentKeepalive = 25; family = "6"; } { from = "sif"; to = "vidhar"; endpointHost = "10.141.0.1"; PersistentKeepalive = 25; family = "4"; } ]; wgHostIPs = mapAttrs (_family: wgSubnet: { surtr = "${wgSubnet}::/${toString wgHostLength}"; vidhar = "${wgSubnet}:1::/${toString wgHostLength}"; sif = "${wgSubnet}:2::/${toString wgHostLength}"; }) wgSubnet; greHostMACPrefixes = { "4" = { surtr = "02:00:01:00:00"; vidhar = "02:00:01:00:01"; sif = "02:00:01:00:02"; }; "6" = { surtr = "02:00:02:00:00"; vidhar = "02:00:02:00:01"; sif = "02:00:02:00:02"; }; }; batHostMACs = { surtr = "02:00:00:00:00:00"; vidhar = "02:00:00:01:00:00"; sif = "02:00:00:02:00:00"; }; batHostIPs = { surtr = ["${batSubnet}::/${toString batHostLength}"]; vidhar = ["${batSubnet}:1::/${toString batHostLength}"]; sif = ["${batSubnet}:2::/${toString batHostLength}"]; }; routers = [ "surtr" ]; mkPublicKeyPath = family: host: ./hosts + "/${family}" + "/${host}.pub"; mkPrivateKeyPath = family: host: ./hosts + "/${family}" + "/${host}.priv"; kernel = config.boot.kernelPackages; publicKeyPath = family: mkPublicKeyPath family hostName; privateKeyPath = family: mkPrivateKeyPath family hostName; inNetwork' = family: pathExists (privateKeyPath family) && pathExists (publicKeyPath family); inNetwork = any inNetwork' families; hostLinks = filterAttrs (_family: links: links != []) (mapAttrs (_family: filter ({ from, to, ... }: thisHost from || thisHost to)) links); linkToPeer = family: opts@{from, to, ...}: let other = if thisHost from then to else from; in { AllowedIPs = if elem other routers then ["::/0"] else wgHostIPs.${family}.${other}; PublicKey = trim (readFile (mkPublicKeyPath family other)); } // (optionalAttrs (thisHost from) (linkCfgFilterCustom opts // linkMkEndpointCfg family opts)); linkCfgFilterCustom = filterAttrs (n: _v: !(elem n ["from" "to" "endpointHost"])); linkMkEndpointCfg = family: opts@{from, ...}: optionalAttrs (opts ? "endpointHost" && thisHost from) { Endpoint = "${opts.endpointHost}:${toString listenPort.${family}}"; }; linkToGreDev = family: opts@{from, to, ...}: let other = if thisHost from then to else from; in nameValuePair "yggre-${other}-${family}" { netdevConfig = { Name = "yggre-${other}-${family}"; Kind = "ip6gretap"; }; tunnelConfig = { Local = stripSubnet wgHostIPs.${family}.${hostName}; Remote = stripSubnet wgHostIPs.${family}.${other}; }; }; linkToGreNetwork = family: ix: opts@{from, to, ...}: let other = if thisHost from then to else from; in nameValuePair "yggre-${other}-${family}" { matchConfig = { Name = "yggre-${other}-${family}"; }; linkConfig = { MACAddress = "${greHostMACPrefixes.${family}.${hostName}}:${toHexByte ix}"; RequiredForOnline = false; }; networkConfig = { BatmanAdvanced = "yggdrasil"; LinkLocalAddressing = "no"; }; }; familyToYggdrasilDev = family: nameValuePair "yggdrasil-wg-${family}" { netdevConfig = { Name = "yggdrasil-wg-${family}"; Kind = "wireguard"; }; wireguardConfig = { PrivateKeyFile = config.sops.secrets."yggdrasil-wg-${family}.priv".path; ListenPort = listenPort.${family}; }; wireguardPeers = map (opts@{to, from, ...}: { wireguardPeerConfig = linkToPeer family opts; }) hostLinks.${family}; }; familyToYggdrasilNetwork = family: nameValuePair "yggdrasil-wg-${family}" { name = "yggdrasil-wg-${family}"; matchConfig = { Name = "yggdrasil-wg-${family}"; }; address = [wgHostIPs.${family}.${hostName}]; routes = [ { routeConfig = { Destination = "${wgSubnet.${family}}::/${toString wgSubnetLength}"; }; } ]; linkConfig = { RequiredForOnline = false; }; networkConfig = { Tunnel = map (opts@{from, to, ...}: let other = if thisHost from then to else from; in "yggre-${other}-${family}") hostLinks.${family}; }; }; familyToSopsSecret = family: nameValuePair "yggdrasil-wg-${family}.priv" (mkIf (pathExists (privateKeyPath family)) { format = "binary"; sopsFile = privateKeyPath family; mode = "0640"; owner = "root"; group = "systemd-network"; }); thisHost = host: host == hostName; trim = str: if hasSuffix "\n" str then trim (removeSuffix "\n" str) else str; stripSubnet = addr: let matchRes = builtins.match "^(.*)/[0-9]+$" addr; in if matchRes == null then addr else elemAt matchRes 0; optIx = optName: xs: let withOpts = listToAttrs (imap0 (ix: x: nameValuePair x.name (x.value // { ${optName} = ix; })) (filter (x: x.value.${optName} or false) (imap0 (ix: nameValuePair (toString ix)) xs))); withoutOpts = listToAttrs (map (nv: nameValuePair nv.name (removeAttrs nv.value [optName])) (filter (x: !(x.value.${optName} or false)) (imap0 (ix: nameValuePair (toString ix)) xs))); in genList (ix: withOpts.${toString ix} or withoutOpts.${toString ix}) (length xs); groupFamilies = links: mapAttrs (_name: value: map (filterAttrs (k: _v: k != "family")) value) (groupBy (x: x.family) links); mkLinks = groupFamilies; families = attrNames links; hostFamilies = attrNames hostLinks; toHexByte = n: let hex = toHexString n; in if (stringLength hex < 2) then "0${hex}" else hex; in { config = { systemd.network = mkIf inNetwork { enable = true; netdevs = { yggdrasil = { netdevConfig = { Name = "yggdrasil"; Kind = "batadv"; }; extraConfig = '' [BatmanAdvanced] Fragmentation=no ''; }; } // listToAttrs (map familyToYggdrasilDev hostFamilies) // listToAttrs (concatMap (family: map (linkToGreDev family) hostLinks.${family}) hostFamilies); networks = { yggdrasil = { name = "yggdrasil"; matchConfig = { Name = "yggdrasil"; }; address = batHostIPs.${hostName}; dns = ["[2a03:4000:52:ada:1:1::]"]; domains = ["yggdrasil"]; routes = [ { routeConfig = { Destination = "${batSubnet}::/${toString batSubnetLength}"; GatewayOnLink = true; }; } { routeConfig = { Destination = "${batSubnet}::/${toString batSubnetLength}"; GatewayOnLink = true; Table = "yggdrasil"; }; } { routeConfig = { Destination = batHostIPs.${hostName}; GatewayOnLink = true; Table = "yggdrasil"; }; } ] ++ (concatMap (router: map (rAddr: { routeConfig = { Destination = "::/0"; Gateway = stripSubnet rAddr; GatewayOnLink = true; Table = "yggdrasil"; }; }) batHostIPs.${router}) routers); routingPolicyRules = map (addr: { routingPolicyRuleConfig = { Table = "yggdrasil"; From = stripSubnet addr; Priority = 1; }; }) batHostIPs.${hostName}; linkConfig = { MACAddress = "${batHostMACs.${hostName}}"; RequiredForOnline = false; MTUBytes = "1280"; }; networkConfig = { LLMNR = false; MulticastDNS = false; DNSSEC = false; }; }; } // listToAttrs (map familyToYggdrasilNetwork hostFamilies) // listToAttrs (concatMap (family: imap0 (linkToGreNetwork family) hostLinks.${family}) hostFamilies); }; environment.etc."systemd/networkd.conf" = mkIf inNetwork { text = '' [Network] RouteTable=yggdrasil:1024 ''; }; sops.secrets = listToAttrs (map familyToSopsSecret hostFamilies); boot.extraModulePackages = optional (versionOlder kernel.kernel.version "5.6") kernel.wireguard ++ [kernel.batman_adv]; environment.systemPackages = with pkgs; [ wireguard-tools batctl ]; networking.networkmanager.unmanaged = ["yggdrasil" "ip6gre0" "ip6tnl0"] ++ map (family: "yggdrasil-wg-${family}") hostFamilies ++ concatMap (family: map ({from, to, ...}: let other = if thisHost from then to else from; in "yggre-${other}-${family}") hostLinks.${family}) hostFamilies; }; }