zaphyra's git: nixfiles

zaphyra and void's nixfiles

commit 2ad5e7198c6c164ab2d4efcd4057bece53c5f755
parent 387fd9eaeeb53c7e8d8e2ddc8a05ba84868a4f45
Author: Katja (zaphyra) <git@ctu.cx>
Date: Mon, 9 Jun 2025 13:28:25 +0200

config/nixos/modules/networking: add `dn42`
2 files changed, 293 insertions(+), 0 deletions(-)
A
config/nixos/modules/networking/dn42.nix
|
202
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A
hosts/novus/dn42.nix
|
91
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
diff --git a/config/nixos/modules/networking/dn42.nix b/config/nixos/modules/networking/dn42.nix
@@ -0,0 +1,202 @@
+{
+  povSelf,
+  lib,
+  config,
+  pkgs,
+  ...
+}:
+
+let
+  inherit (lib) types;
+  cfg = lib.getAttrFromPath povSelf config;
+
+in
+{
+
+  options = {
+    enable = {
+      type = types.bool;
+      default = false;
+    };
+    asn = {
+      type = types.int;
+    };
+    routerId = {
+      type = types.int;
+    };
+    address = {
+      type = types.str;
+    };
+    range = {
+      type = types.str;
+    };
+    peerings = {
+      default = {};
+      type = with types; attrsOf (submodule {
+        options = {
+          asn = lib.mkOption { type = types.int; };
+          ownLinkLocalAddress = lib.mkOption {
+            type = types.str;
+            default = "fe80::6b61/64";
+          };
+          linkLocalAddress = lib.mkOption { type = types.str; };
+          endpoint = lib.mkOption {
+            type = with types; nullOr str;
+            default = null;
+          };
+          publicKey = lib.mkOption { type = types.str; };
+          listenPort = lib.mkOption { type = types.int; };
+        };
+      });
+    };
+  };
+
+  config = lib.mkIf cfg.enable {
+    networking.firewall.allowedUDPPorts = lib.mapAttrsToList (name: peerConfig: peerConfig.listenPort) cfg.peerings;
+
+    sops.secrets = lib.mapAttrs' (name: peerConfig: lib.nameValuePair "dn42/peerings/${name}/wgPrivateKey" {
+      owner = "systemd-network";
+      group = "systemd-network";
+    }) cfg.peerings;
+
+    systemd.network = {
+      netdevs = lib.mapAttrs' (name: peerConfig: lib.nameValuePair "dn42${name}" {
+        netdevConfig = {
+          Kind = "wireguard";
+          Name = "dn42${name}";
+        };
+        wireguardConfig = {
+          ListenPort = peerConfig.listenPort;
+          PrivateKeyFile = config.sops.secrets."dn42/peerings/${name}/wgPrivateKey".path;
+        };
+        wireguardPeers = [
+          {
+            PersistentKeepalive = 30;
+            Endpoint = lib.mkIf (!builtins.isNull peerConfig.endpoint) peerConfig.endpoint;
+            PublicKey = peerConfig.publicKey;
+            AllowedIPs = [ "fd00::/8" peerConfig.linkLocalAddress ];
+          }
+        ];
+      }) cfg.peerings;
+
+      networks = lib.mapAttrs' (name: peerConfig: lib.nameValuePair "dn42${name}" {
+        matchConfig.Name = "dn42${name}";
+        linkConfig.RequiredForOnline = "no";
+
+        address = [ peerConfig.ownLinkLocalAddress ];
+        routes = [ { Destination = "fe80::6b61/128"; } ];
+
+        networkConfig = {
+          IPv6Forwarding = true;
+          IPv6AcceptRA = false;
+          DHCP = false;
+        };
+      }) cfg.peerings;
+    };
+
+    systemd.services.updateDN42ROA = {
+      after = [ "network.target" ];
+      before = [ "bird.service" ];
+      startAt = [ "*-*-* */1:00:00" ];
+      script = ''
+        mkdir -p /etc/bird/
+        ${pkgs.curl}/bin/curl -sfSLR {-o,-z}/etc/bird/roa_dn42.conf https://dn42.burble.com/roa/dn42_roa_bird2_6.conf
+        ${pkgs.bird3}/bin/birdc c
+        ${pkgs.bird3}/bin/birdc reload filters all
+      '';
+    };
+
+    services.bird = {
+      enable = true;
+      package = pkgs.bird3;
+      preCheckConfig = ''
+        # Remove roa files for checking, because they are only available at runtime
+        sed -i 's|include "/etc/bird/roa_dn42.conf";||' bird.conf
+
+        cat -n bird.conf # here for debugging purposes
+      '';
+      config = ''
+        log syslog { debug, trace, info, remote, warning, error, auth, fatal, bug };
+        log stderr all;
+
+        define OWNAS = ${toString cfg.asn};
+        define OWNNETv6 = ${cfg.range};
+        define OWNNETSETv6 = [ ${cfg.range} ];
+        define OWNIPv6 = ${cfg.address};
+
+        router id ${toString cfg.routerId};
+        hostname "${config.networking.hostName}";
+
+        protocol device {
+          scan time 10;
+        }
+
+        function is_self_net_v6() -> bool {
+          return net ~ OWNNETSETv6;
+        }
+
+        function is_valid_network_v6() -> bool {
+          return net ~ [
+            fd00::/8{44,64} # ULA address space as per RFC 4193
+          ];
+        }
+
+        roa6 table dn42_roa_v6;
+
+        protocol static {
+          roa6 { table dn42_roa_v6; };
+          include "/etc/bird/roa_dn42.conf";
+        };
+
+        # dn42 default route
+        protocol static  {
+          route OWNNETv6 unreachable;
+
+          ipv6 {
+            import all;
+            export none;
+          };
+        }
+
+        protocol kernel {
+          scan time 20;
+
+          ipv6 {
+            import none;
+            export filter {
+              if source = RTS_STATIC then reject; # dont export static routes
+              krt_prefsrc = OWNIPv6; # preferred outgoing source address
+              accept;
+            };
+          };
+        };
+
+        template bgp dnpeers {
+          local as OWNAS;
+          path metric 1;
+
+          ipv6 {
+            import filter {
+              if is_valid_network_v6() && !is_self_net_v6() then {
+                if (roa_check(dn42_roa_v6, net, bgp_path.last) != ROA_VALID) then {
+                  # Reject when unknown or invalid according to ROA
+                  print "[dn42] ROA check failed for ", net, " ASN ", bgp_path.last;
+                  reject;
+                } else accept;
+              } else reject;
+            };
+
+            export filter { if is_valid_network_v6() && source ~ [RTS_STATIC, RTS_BGP] then accept; else reject; };
+            import limit 9000 action block;
+          };
+        }
+      '' + (lib.concatStringsSep "\n" (lib.mapAttrsToList (name: peerConfig: ''
+        protocol bgp ${name} from dnpeers {
+          neighbor ${peerConfig.linkLocalAddress}%dn42${name} as ${toString peerConfig.asn};
+          enable extended messages;
+        }
+      '') cfg.peerings));
+    };
+  };
+
+}
diff --git a/hosts/novus/dn42.nix b/hosts/novus/dn42.nix
@@ -0,0 +1,91 @@
+{ hostConfig, ... }:
+
+{
+
+  dns.zones."zaphyra.eu".subdomains."router-a.dn42".AAAA = [ hostConfig.networking.ip6Address ];
+
+  modules.networking.dn42 = {
+    enable = true;
+    routerId = 42171801;
+    asn = 4242421718;
+    address = "fd6b:6174:6a61::1";
+    range = "fd6b:6174:6a61::/48";
+    peerings = {
+      # void = {
+      #   asn = 4242420575;
+      #   linkLocalAddress = "fe80::497a";
+      #   endpoint = "gw.srv.eukaryote.eu:49508";
+      #   publicKey = "";
+      #   listenPort = 51821;
+      # };
+      # tech9 = {
+      #   asn = 4242421588;
+      #   ownLinkLocalAddress = "fe80::100/64";
+      #   linkLocalAddress = "fe80::1588";
+      #   endpoint = "de-nue01.dn42.tech9.io:57730";
+      #   publicKey = "4JoJgCZWITUFAq7ol8/DZzJOuYzebveqMWPk9qQEHRU=";
+      #   listenPort = 51822;
+      # };
+      kioubit = {
+        asn = 4242423914;
+        linkLocalAddress = "fe80::ade0";
+        endpoint = "de2.g-load.eu:21718";
+        publicKey = "B1xSG/XTJRLd+GrWDsB06BqnIq8Xud93YVh/LYYYtUY=";
+        listenPort = 51823;
+      };
+      pleiades = {
+        asn = 4242420069;
+        linkLocalAddress = "fe80::706c:6569:6164:6573";
+        endpoint = "central.net.nojus.org:21718";
+        publicKey = "1YAga5Bhreysf/XmhOnDGh3FmbN3Mp2jZjMSAQb/TEM=";
+        listenPort = 51824;
+      };
+      echonet = {
+        asn = 4242420714;
+        linkLocalAddress = "fe80::718";
+        publicKey = "NxYj58YhWf0JXC+pQAHfh3saUkQSII0lBTDvYGe5kw4=";
+        listenPort = 51825;
+      };
+      tbspace = {
+        asn = 76190;
+        linkLocalAddress = "fe80::1299:e";
+        endpoint = "dn42.tbspace.de:49158";
+        publicKey = "NW8IeEmAXmwYMuMlvrb9Zpkcko6bzotDlYtGePtgzQE=";
+        listenPort = 51826;
+      };
+      antibldg = {
+        asn = 4242421403;
+        linkLocalAddress = "fe80::1234:9320";
+        endpoint = "zaphyra.dn42.antibuild.ing:15569";
+        publicKey = "vambITMGGpA7kxCRGFlY1X36bevxXYELT/ORNgZ72ms=";
+        listenPort = 51827;
+      };
+      dahlabandon = {
+        asn = 4242420814;
+        linkLocalAddress = "fe80::1718";
+        endpoint = "cargobridge25.iron-bear.de:1718";
+        publicKey = "+tg4bDDwfyQZSw0x8x9Ye2tDWPZ/VAf+KTAE1QLaKEI=";
+        listenPort = 51828;
+      };
+    };
+  };
+
+  systemd.network = {
+    netdevs.dn42 = {
+      netdevConfig = {
+        Kind = "dummy";
+        Name = "dn42";
+      };
+    };
+
+    networks.dn42 = {
+      matchConfig.Name = "dn42";
+      linkConfig.RequiredForOnline = "no";
+      address = [ "fd6b:6174:6a61::1/64" ];
+      networkConfig = {
+        IPv6Forwarding = true;
+      };
+    };
+  };
+
+}