diff --git a/nix/nixos-module/container/bird.nix b/nix/nixos-module/container/bird.nix index f1f5387..7b6fced 100644 --- a/nix/nixos-module/container/bird.nix +++ b/nix/nixos-module/container/bird.nix @@ -85,26 +85,16 @@ in } ${lib.optionalString (builtins.match "anon.*" hostName != null) '' + # BIRD routing table for Wireguard transport ipv4 table vpn4_table; - protocol pipe { - table master4; - peer table vpn4_table; - export filter { - if net = 0.0.0.0/0 then { - # Copy default route to vpn4 table - accept; - } - reject; - }; - } - # Routing table for Wireguard transport + # Kernel routing table for Wireguard transport protocol kernel VPN4 { # "vpn4_table" configured on anon routers kernel table 100; ipv4 { - table vpn4_table; export all; + table vpn4_table; }; } ''} @@ -135,20 +125,8 @@ in # OSPFv2 for site-local IPv4 protocol ospf v2 ZW4 { ipv4 { - export all; - import filter { + export filter { if net = 0.0.0.0/0 then { - ${(builtins.foldl' (result: gateway: { - text = '' - ${result.text} - if ospf_router_id = ${config.site.net.core.hosts4.${gateway}} then { - preference = preference + ${toString result.n}; - accept; - } - ''; - n = result.n - 10; - }) { text = ""; n = 900; } config.site.hosts.${hostName}.ospf.allowedUpstreams - ).text} reject; } accept; @@ -192,23 +170,89 @@ in }; } + ${lib.optionalString isUpstream '' + # OSPFv2 to advertise my default route + protocol ospf v2 ZW4_${hostName} { + ipv4 { + export filter { + if net = 0.0.0.0/0 then { + accept; + } + reject; + }; + }; + area ${config.site.net.core.hosts4.${hostName}} { + # Enabled on these networks + networks { + ${builtins.concatStringsSep " " ( + map (n: " ${n};") config.site.ospf.networks4 + )} + }; + ${builtins.concatStringsSep "\n" ( + builtins.attrValues ( + builtins.mapAttrs (net: _: + # Enable OSPF only on interfaces with a secret. + lib.optionalString (config.site.net.${net}.ospf.secret != null) '' + interface "${net}" instance 1 { + authentication cryptographic; + password "${config.site.net.${net}.ospf.secret}"; + }; + '' + ) hostConf.interfaces + ) + )} + }; + } + ''} + + ${( + builtins.foldl' ({ text, instance }: upstream: { + text = '' + ${text} + + # OSPFv2 to receive a default route + protocol ospf v2 ZW4_${upstream} { + ipv4 { + export filter { + preference = preference + 100 - ${toString instance}; + accept; + }; + ${lib.optionalString (builtins.match "anon.*" hostName != null) '' + table vpn4_table; + ''} + }; + area ${config.site.net.core.hosts4.${upstream}} { + # Enabled on these networks + networks { + ${builtins.concatStringsSep " " ( + map (n: " ${n};") config.site.ospf.networks4 + )} + }; + ${builtins.concatStringsSep "\n" ( + builtins.attrValues ( + builtins.mapAttrs (net: _: + # Enable OSPF only on interfaces with a secret. + lib.optionalString (config.site.net.${net}.ospf.secret != null) '' + interface "${net}" instance ${toString instance} { + authentication cryptographic; + password "${config.site.net.${net}.ospf.secret}"; + }; + '' + ) hostConf.interfaces + ) + )} + }; + } + ''; + instance = instance + 1; + }) { text = ""; instance = 2; } config.site.hosts.${hostName}.ospf.allowedUpstreams + ).text} + # OSPFv3 for site-local IPv6 protocol ospf v3 ZW6 { ipv6 { - export all; - import filter { + export filter { if net = ::/0 then { - ${(builtins.foldl' (result: gateway: { - text = '' - ${result.text} - if ospf_router_id = ${config.site.net.core.hosts4.${gateway}} then { - preference = preference + ${toString result.n}; - accept; - } - ''; - n = result.n - 10; - }) { text = ""; n = 900; } config.site.hosts.${hostName}.ospf.allowedUpstreams - ).text} reject; } accept; @@ -254,6 +298,81 @@ in }; } + ${lib.optionalString isUpstream '' + # OSPFv3 to advertise my default route + protocol ospf v3 ZW6_${hostName} { + ipv6 { + export filter { + if net = ::/0 then { + accept; + } + reject; + }; + }; + area ${config.site.net.core.hosts4.${hostName}} { + # Enabled on these networks + networks { + ${builtins.concatStringsSep " " ( + map (n: " ${n};") config.site.ospf.networks4 + )} + }; + ${builtins.concatStringsSep "\n" ( + builtins.attrValues ( + builtins.mapAttrs (net: _: + # Enable OSPF only on interfaces with a secret. + lib.optionalString (config.site.net.${net}.ospf.secret != null) '' + interface "${net}" instance 1 { + authentication cryptographic; + password "${config.site.net.${net}.ospf.secret}"; + }; + '' + ) hostConf.interfaces + ) + )} + }; + } + ''} + + ${lib.optionalString (builtins.match "anon.*" hostName != null) ( + builtins.foldl' ({ text, instance }: upstream: { + text = '' + ${text} + + # OSPFv3 to receive a default route + protocol ospf v3 ZW6_${upstream} { + ipv6 { + export filter { + preference = preference + 100 - ${toString instance}; + accept; + }; + }; + area ${config.site.net.core.hosts4.${upstream}} { + # Enabled on these networks + networks { + ${builtins.concatStringsSep " " ( + map (n: " ${n};") config.site.ospf.networks4 + )} + }; + ${builtins.concatStringsSep "\n" ( + builtins.attrValues ( + builtins.mapAttrs (net: _: + # Enable OSPF only on interfaces with a secret. + lib.optionalString (config.site.net.${net}.ospf.secret != null) '' + interface "${net}" instance ${toString instance} { + authentication cryptographic; + password "${config.site.net.${net}.ospf.secret}"; + }; + '' + ) hostConf.interfaces + ) + )} + }; + } + ''; + instance = instance + 1; + }) { text = ""; instance = 2; } config.site.hosts.${hostName}.ospf.allowedUpstreams + ).text} + # Zentralwerk DN42 protocol static { ipv4;