commit 59023f566d2469360268a9e3c9bc9199cc0cfbc6
parent 6bc029ebec638507cec481ef2313a746c4e05d0b
Author: Katja (zaphyra) <git@ctu.cx>
Date: Wed, 11 Jun 2025 20:57:21 +0200
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
|
173
++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------
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" + ]; }; + }; }