zaphyra's git: nixfiles

zaphyra and void's nixfiles

commit 59023f566d2469360268a9e3c9bc9199cc0cfbc6
parent 6bc029ebec638507cec481ef2313a746c4e05d0b
Author: Katja (zaphyra) <git@ctu.cx>
Date: Wed, 11 Jun 2025 20:57:21 +0200

config/nixos/modules/networking/dn42: improve bird config, implement wireguard-psk support, use stayrtr for ROA
2 files changed, 128 insertions(+), 72 deletions(-)
M
config/nixos/modules/networking/dn42.nix
|
173
++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------
M
hosts/novus/dn42.nix
|
27
++++++++++++++-------------
diff --git a/config/nixos/modules/networking/dn42.nix b/config/nixos/modules/networking/dn42.nix
@@ -37,17 +37,21 @@ in
         attrsOf (submodule {
           options = {
             asn = lib.mkOption { type = types.int; };
-            ownLinkLocalAddress = lib.mkOption {
+            remoteLinkLocalAddress = lib.mkOption { type = types.str; };
+            localLinkLocalAddress = 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; };
+            publicKey = lib.mkOption { type = types.str; };
+            hasPresharedKey = lib.mkOption {
+              type = types.bool;
+              default = false;
+            };
           };
         });
     };

@@ -58,26 +62,45 @@ in
       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.services.systemd-networkd.after = [ "sops-install-secrets.service" ];
+
+    sops.secrets = (
+      cfg.peerings
+      |> lib.mapAttrsToList (
+        name: peerConfig:
+        [
+          (lib.nameValuePair "dn42/peerings/${name}/wgPrivateKey" {
+            owner = "systemd-network";
+            group = "systemd-network";
+          })
+        ]
+        ++ lib.optionals peerConfig.hasPresharedKey [
+          (lib.nameValuePair "dn42/peerings/${name}/wgPresharedKey" {
+            owner = "systemd-network";
+            group = "systemd-network";
+          })
+        ]
+      )
+      |> lib.lists.flatten
+      |> lib.listToAttrs
+    );
 
     systemd.network = {
       netdevs = lib.mapAttrs' (
         name: peerConfig:
-        lib.nameValuePair "dn42${name}" {
+        lib.nameValuePair "20-dn42${name}" {
           netdevConfig = {
             Kind = "wireguard";
             Name = "dn42${name}";
           };
-          wireguardConfig = {
-            ListenPort = peerConfig.listenPort;
-            PrivateKeyFile = config.sops.secrets."dn42/peerings/${name}/wgPrivateKey".path;
-          };
+          wireguardConfig =
+            {
+              ListenPort = peerConfig.listenPort;
+              PrivateKeyFile = config.sops.secrets."dn42/peerings/${name}/wgPrivateKey".path;
+            }
+            // (lib.optionalAttrs peerConfig.hasPresharedKey {
+              PresharedKeyFile = config.sops.secrets."dn42/peerings/${name}/wgPresharedKey".path;
+            });
           wireguardPeers = [
             {
               PersistentKeepalive = 30;

@@ -85,7 +108,7 @@ in
               PublicKey = peerConfig.publicKey;
               AllowedIPs = [
                 "fd00::/8"
-                peerConfig.linkLocalAddress
+                peerConfig.remoteLinkLocalAddress
               ];
             }
           ];

@@ -94,11 +117,11 @@ in
 
       networks = lib.mapAttrs' (
         name: peerConfig:
-        lib.nameValuePair "dn42${name}" {
+        lib.nameValuePair "20-dn42${name}" {
           matchConfig.Name = "dn42${name}";
           linkConfig.RequiredForOnline = "no";
 
-          address = [ peerConfig.ownLinkLocalAddress ];
+          address = [ peerConfig.localLinkLocalAddress ];
           routes = [ { Destination = "fe80::6b61/128"; } ];
 
           networkConfig = {

@@ -110,15 +133,17 @@ in
       ) 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
+    systemd.services.stayrtr = {
+      wantedBy = [
+        "multi-user.target"
+        "bird.service"
+      ];
+      serviceConfig.DynamicUser = true;
+      serviceConfig.ExecStart = ''
+        ${lib.getExe pkgs.stayrtr} \
+          -bind [::1]:8282 \
+          -cache=https://dn42.burble.com/roa/dn42_roa_46.json \
+          -checktime=false
       '';
     };
 

@@ -137,37 +162,68 @@ in
           log stderr all;
 
           define OWNAS = ${toString cfg.asn};
-          define OWNNETv6 = ${cfg.range};
-          define OWNNETSETv6 = [ ${cfg.range} ];
-          define OWNIPv6 = ${cfg.address};
+          define OWNNET = ${cfg.range};
+          define OWNNETSET = [ ${cfg.range} ];
+          define OWNIP = ${cfg.address};
 
           router id ${toString cfg.routerId};
           hostname "${config.networking.hostName}";
 
-          protocol device {
-            scan time 10;
-          }
+          roa6 table dn42_roa;
 
-          function is_self_net_v6() -> bool {
-            return net ~ OWNNETSETv6;
+          function is_self_net() -> bool {
+            return net ~ OWNNETSET;
           }
 
-          function is_valid_network_v6() -> bool {
+          function is_valid_network() -> bool {
             return net ~ [
-              fd00::/8{44,64} # ULA address space as per RFC 4193
+              fd00::/8{44,64}
             ];
           }
 
-          roa6 table dn42_roa_v6;
+          function import_filter() {
+            if (net.type != NET_IP6 || ! is_valid_network() || is_self_net()) then
+              reject;
+
+            if (roa_check(dn42_roa, 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;
+            }
+
+            accept;
+          }
+
+          function export_filter() {
+            if ( ! is_valid_network() ) then
+              reject;
+
+            if (source !~ [RTS_STATIC, RTS_BGP]) then
+              reject;
+
+            accept;
+          }
+
+          protocol rpki {
+            roa6 { table dn42_roa; };
+            remote ::1;
+            port 8282;
+            refresh 600;
+            retry 300;
+            expire 7200;
+          }
+
+          protocol device {
+            scan time 10;
+          }
 
           protocol static {
-            roa6 { table dn42_roa_v6; };
+            roa6 { table dn42_roa; };
             include "/etc/bird/roa_dn42.conf";
           };
 
-          # dn42 default route
-          protocol static  {
-            route OWNNETv6 unreachable;
+          protocol static {
+            route OWNNET unreachable;
 
             ipv6 {
               import all;

@@ -181,37 +237,36 @@ in
             ipv6 {
               import none;
               export filter {
-                if source = RTS_STATIC then reject; # dont export static routes
-                krt_prefsrc = OWNIPv6; # preferred outgoing source address
+                # dont export static routes
+                if source = RTS_STATIC then reject;
+                # preferred outgoing source address
+                krt_prefsrc = OWNIP;
                 accept;
               };
             };
-          };
+          }
 
-          template bgp dnpeers {
+          template bgp dn42_peers {
             local as OWNAS;
             path metric 1;
+            advertise hostname on;
+            enforce first as on;
+            med metric on;
 
             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 keep filtered;
               import limit 9000 action block;
+              import where import_filter();
+              next hop self; # advertise this router as next hop
+
+              export where export_filter();
             };
           }
         ''
         + (lib.concatStringsSep "\n" (
           lib.mapAttrsToList (name: peerConfig: ''
-            protocol bgp ${name} from dnpeers {
-              neighbor ${peerConfig.linkLocalAddress}%dn42${name} as ${toString peerConfig.asn};
+            protocol bgp ${name} from dn42_peers {
+              neighbor ${peerConfig.remoteLinkLocalAddress}%dn42${name} as ${toString peerConfig.asn};
               enable extended messages;
             }
           '') cfg.peerings
diff --git a/hosts/novus/dn42.nix b/hosts/novus/dn42.nix
@@ -15,53 +15,54 @@
       #   asn = 4242420575;
       #   linkLocalAddress = "fe80::497a";
       #   endpoint = "gw.srv.eukaryote.eu:49508";
+      #   hasPresharedKey = true;
       #   publicKey = "";
       #   listenPort = 51821;
       # };
       kioubit = {
         asn = 4242423914;
-        linkLocalAddress = "fe80::ade0";
+        remoteLinkLocalAddress = "fe80::ade0";
         endpoint = "de2.g-load.eu:21718";
         publicKey = "B1xSG/XTJRLd+GrWDsB06BqnIq8Xud93YVh/LYYYtUY=";
         listenPort = 51823;
       };
       pleiades = {
         asn = 4242420069;
-        linkLocalAddress = "fe80::706c:6569:6164:6573";
+        remoteLinkLocalAddress = "fe80::706c:6569:6164:6573";
         endpoint = "central.net.nojus.org:21718";
         publicKey = "1YAga5Bhreysf/XmhOnDGh3FmbN3Mp2jZjMSAQb/TEM=";
         listenPort = 51824;
       };
       echonet = {
         asn = 4242420714;
-        linkLocalAddress = "fe80::718";
+        remoteLinkLocalAddress = "fe80::718";
         publicKey = "NxYj58YhWf0JXC+pQAHfh3saUkQSII0lBTDvYGe5kw4=";
         listenPort = 51825;
       };
       tbspace = {
         asn = 76190;
-        linkLocalAddress = "fe80::1299:e";
+        remoteLinkLocalAddress = "fe80::1299:e";
         endpoint = "dn42.tbspace.de:49158";
         publicKey = "NW8IeEmAXmwYMuMlvrb9Zpkcko6bzotDlYtGePtgzQE=";
         listenPort = 51826;
       };
       antibldg = {
         asn = 4242421403;
-        linkLocalAddress = "fe80::1234:9320";
+        remoteLinkLocalAddress = "fe80::1234:9320";
         endpoint = "zaphyra.dn42.antibuild.ing:15569";
         publicKey = "vambITMGGpA7kxCRGFlY1X36bevxXYELT/ORNgZ72ms=";
         listenPort = 51827;
       };
       dahlabandon = {
         asn = 4242420814;
-        linkLocalAddress = "fe80::1718";
+        remoteLinkLocalAddress = "fe80::1718";
         endpoint = "cargobridge25.iron-bear.de:1718";
         publicKey = "+tg4bDDwfyQZSw0x8x9Ye2tDWPZ/VAf+KTAE1QLaKEI=";
         listenPort = 51828;
       };
       pentane = {
         asn = 4242423253;
-        linkLocalAddress = "fe80::43:59:43";
+        remoteLinkLocalAddress = "fe80::43:59:43";
         endpoint = "imp.aidoskyneen.eu:49507";
         publicKey = "W+h0FMrxsAP7RppqFFMrfDHuu5CMW5aTW9E1MZXFf1w=";
         listenPort = 51829;

@@ -70,21 +71,21 @@
   };
 
   systemd.network = {
-    netdevs.dn42 = {
+    netdevs."15-dn42" = {
       netdevConfig = {
         Kind = "dummy";
         Name = "dn42";
       };
     };
 
-    networks.dn42 = {
+    networks."15-dn42" = {
       matchConfig.Name = "dn42";
       linkConfig.RequiredForOnline = "no";
-      address = [ "fd6b:6174:6a61::1/64" ];
-      networkConfig = {
-        IPv6Forwarding = true;
-      };
+      address = [
+        "fd6b:6174:6a61::1/48"
+      ];
     };
+
   };
 
 }