diff --git a/nix/lib/config/legacy.nix b/nix/lib/config/legacy.nix index a323b6b..ff0b8b7 100644 --- a/nix/lib/config/legacy.nix +++ b/nix/lib/config/legacy.nix @@ -58,7 +58,8 @@ in config.site.hosts = lib.mkMerge ( [ - { + { # Static definitions + mgmt-gw.firewall.enable = true; priv13-gw.firewall.enable = true; @@ -74,8 +75,24 @@ in services.dnscache.enable = true; }; + + c3d2-gw.ospf.allowedUpstreams = [ "upstream1" "upstream2" ]; + serv-gw.ospf.allowedUpstreams = [ "upstream1" "upstream2" ]; + cls-gw.ospf.allowedUpstreams = [ "upstream1" "upstream2" ]; + mgmt-gw.ospf.allowedUpstreams = [ "upstream1" "upstream2" ]; + bgp.ospf.allowedUpstreams = [ "upstream1" "upstream2" ]; } + ( + builtins.mapAttrs (hostName: _: { + ospf.allowedUpstreams = [ "upstream2" "upstream1" ]; + }) ( + lib.filterAttrs (hostName: _: + builtins.match "priv[[:digit:]]+-gw" hostName != null + ) pillar.containers + ) + ) + (builtins.foldl' (result: hostName: result // { "${hostName}" = { role = "server"; diff --git a/nix/lib/config/options.nix b/nix/lib/config/options.nix index 2fc2990..aa2fc4d 100644 --- a/nix/lib/config/options.nix +++ b/nix/lib/config/options.nix @@ -202,6 +202,11 @@ let default = []; description = "Additional IPv6 networks to announce"; }; + ospf.allowedUpstreams = mkOption { + type = with types; listOf str; + default = []; + description = "Accept default routes from these OSPF routers, in order of preference"; + }; wireguard = mkOption { default = {}; type = with types; attrsOf (submodule ( @@ -291,8 +296,23 @@ in )).dup; reportCollisions = name: getter: xs: map (k: "Duplicate ${name}: ${k}") (findCollisions getter xs); + + ospfUpstreamXorGw = + builtins.concatMap (hostName: + let + hostConf = config.site.hosts.${hostName}; + gwNets = builtins.filter (netName: + hostConf.interfaces.${netName}.gw4 != null + ) (builtins.attrNames hostConf.interfaces); + in if gwNets != [] && hostConf.ospf.allowedUpstreams != [] + then [ '' + Host ${hostName} has gateway on ${builtins.head gwNets} but accepts default routes from OSPF + '' ] + else [] + ) (builtins.attrNames config.site.hosts); in (reportCollisions "VLAN tag" (x: [x.vlan]) config.site.net) ++ (reportCollisions "IPv4 subnet" (x: if x.subnet4 == null then [] else [x.subnet4]) config.site.net) ++ - (reportCollisions "IPv6 subnet" (x: builtins.attrValues x.subnets6) config.site.net); + (reportCollisions "IPv6 subnet" (x: builtins.attrValues x.subnets6) config.site.net) ++ + ospfUpstreamXorGw; } diff --git a/nix/nixos-module/container/bird.nix b/nix/nixos-module/container/bird.nix index b82930e..39f9a31 100644 --- a/nix/nixos-module/container/bird.nix +++ b/nix/nixos-module/container/bird.nix @@ -4,6 +4,10 @@ let hostConf = config.site.hosts.${hostName}; + isUpstream = builtins.any (net: + hostConf.interfaces.${net}.upstream != null + ) (builtins.attrNames hostConf.interfaces); + # Configuring a gateway? If so, this is the associated net. gatewayNet = let @@ -29,13 +33,33 @@ in router id ${config.site.net.core.hosts4.${hostName}}; protocol kernel K4 { + learn; ipv4 { export all; + ${lib.optionalString isUpstream '' + # Learn the default route + import filter { + if net ~ [ 0.0.0.0/0 ] then { + accept; + } + reject; + }; + ''} }; } protocol kernel K6 { + learn; ipv6 { export all; + ${lib.optionalString isUpstream '' + # Learn the default route + import filter { + if net ~ [ ::/0 ] then { + accept; + } + reject; + }; + ''} }; } protocol device { @@ -67,6 +91,26 @@ in # OSPFv2 for site-local IPv4 protocol ospf v2 ZW4 { + ipv4 { + export all; + import 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; + }; + }; area 0 { # Enabled on these networks networks { @@ -107,6 +151,26 @@ in # OSPFv3 for site-local IPv6 protocol ospf v3 ZW6 { + ipv6 { + export all; + import 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; + }; + }; area 0 { # Enabled on these networks networks { diff --git a/salt-pillar/lxc-containers/server1.sls b/salt-pillar/lxc-containers/server1.sls index b7a4400..be80f7b 100644 --- a/salt-pillar/lxc-containers/server1.sls +++ b/salt-pillar/lxc-containers/server1.sls @@ -14,8 +14,8 @@ containers: interfaces: core: type: veth - gw: upstream1 - gw6: upstream1 + # gw: upstream1 + # gw6: upstream1 hwaddr: 0A:14:48:01:06:01 serv: type: veth @@ -25,8 +25,8 @@ containers: interfaces: core: type: veth - gw: upstream1 - gw6: upstream1 + # gw: upstream1 + # gw6: upstream1 hwaddr: 0A:14:48:01:06:03 cluster: type: phys @@ -36,8 +36,8 @@ containers: interfaces: core: type: veth - gw: upstream2 - gw6: upstream2 + # gw: upstream2 + # gw6: upstream2 hwaddr: 0A:14:48:01:19:00 priv1: type: phys @@ -47,8 +47,8 @@ containers: interfaces: core: type: veth - gw: upstream2 - gw6: upstream2 + # gw: upstream2 + # gw6: upstream2 hwaddr: 0A:14:48:01:18:00 priv2: type: phys @@ -58,8 +58,8 @@ containers: interfaces: core: type: veth - gw: upstream2 - gw6: upstream2 + # gw: upstream2 + # gw6: upstream2 hwaddr: 0A:14:48:01:08:00 priv3: type: phys @@ -69,8 +69,8 @@ containers: interfaces: core: type: veth - gw: upstream2 - gw6: upstream2 + # gw: upstream2 + # gw6: upstream2 hwaddr: 0A:14:48:01:17:01 priv4: type: phys @@ -80,8 +80,8 @@ containers: interfaces: core: type: veth - gw: upstream2 - gw6: upstream2 + # gw: upstream2 + # gw6: upstream2 hwaddr: 0A:14:48:01:12:00 priv5: type: phys @@ -91,8 +91,8 @@ containers: interfaces: core: type: veth - gw: anon1 - gw6: upstream2 + # gw: anon1 + # gw6: upstream2 hwaddr: 0A:14:48:01:11:00 priv6: type: phys @@ -102,8 +102,8 @@ containers: interfaces: core: type: veth - gw: upstream2 - gw6: upstream2 + # gw: upstream2 + # gw6: upstream2 hwaddr: 0A:14:48:01:10:00 priv7: type: phys @@ -113,8 +113,8 @@ containers: interfaces: core: type: veth - gw: upstream2 - gw6: upstream2 + # gw: upstream2 + # gw6: upstream2 hwaddr: 0A:14:48:01:09:00 priv8: type: phys @@ -124,8 +124,8 @@ containers: interfaces: core: type: veth - gw: upstream2 - gw6: upstream2 + # gw: upstream2 + # gw6: upstream2 hwaddr: 0A:14:48:01:20:00 priv9: type: phys @@ -135,8 +135,8 @@ containers: interfaces: core: type: veth - gw: upstream2 - gw6: upstream2 + # gw: upstream2 + # gw6: upstream2 hwaddr: 0A:14:48:01:13:02 priv10: type: phys @@ -146,8 +146,8 @@ containers: interfaces: core: type: veth - gw: upstream2 - gw6: upstream2 + # gw: upstream2 + # gw6: upstream2 hwaddr: 0A:14:48:01:29:00 priv11: type: phys @@ -157,8 +157,8 @@ containers: interfaces: core: type: veth - gw: upstream2 - gw6: upstream2 + # gw: upstream2 + # gw6: upstream2 hwaddr: 0A:14:48:01:2A:00 priv12: type: phys @@ -168,8 +168,8 @@ containers: interfaces: core: type: veth - gw: upstream2 - gw6: upstream2 + # gw: upstream2 + # gw6: upstream2 hwaddr: 0A:14:48:01:2A:10 priv13: type: phys @@ -179,8 +179,8 @@ containers: interfaces: core: type: veth - gw: upstream2 - gw6: upstream2 + # gw: upstream2 + # gw6: upstream2 hwaddr: 0A:14:48:01:2A:12 priv14: type: phys @@ -190,8 +190,8 @@ containers: interfaces: core: type: veth - gw: anon1 - gw6: upstream2 + # gw: anon1 + # gw6: upstream2 hwaddr: 0A:14:48:01:2A:14 priv15: type: phys @@ -201,8 +201,8 @@ containers: interfaces: core: type: veth - gw: upstream2 - gw6: upstream2 + # gw: upstream2 + # gw6: upstream2 hwaddr: 0A:14:48:01:2A:16 priv16: type: phys @@ -212,8 +212,8 @@ containers: interfaces: core: type: veth - gw: upstream2 - gw6: upstream2 + # gw: upstream2 + # gw6: upstream2 hwaddr: 0A:14:48:01:2A:18 priv17: type: phys @@ -223,8 +223,8 @@ containers: interfaces: core: type: veth - gw: upstream2 - gw6: upstream2 + # gw: upstream2 + # gw6: upstream2 hwaddr: 0A:14:48:01:2A:1A priv18: type: phys @@ -234,8 +234,8 @@ containers: interfaces: core: type: veth - gw: upstream2 - gw6: upstream2 + # gw: upstream2 + # gw6: upstream2 hwaddr: 0A:14:48:01:2A:1C priv19: type: phys @@ -245,8 +245,8 @@ containers: interfaces: core: type: veth - gw: upstream2 - gw6: upstream2 + # gw: upstream2 + # gw6: upstream2 hwaddr: 0A:14:48:01:2A:1E priv20: type: phys @@ -256,8 +256,8 @@ containers: interfaces: core: type: veth - gw: upstream2 - gw6: upstream2 + # gw: upstream2 + # gw6: upstream2 hwaddr: 0A:14:48:01:2A:20 priv21: type: phys @@ -267,8 +267,8 @@ containers: interfaces: core: type: veth - gw: upstream2 - gw6: upstream2 + # gw: upstream2 + # gw6: upstream2 hwaddr: 0A:14:48:01:2A:24 priv22: type: phys @@ -278,8 +278,8 @@ containers: interfaces: core: type: veth - gw: upstream2 - gw6: upstream2 + # gw: upstream2 + # gw6: upstream2 hwaddr: 0A:14:48:01:2A:22 priv23: type: phys @@ -289,8 +289,8 @@ containers: interfaces: core: type: veth - gw: upstream2 - gw6: upstream2 + # gw: upstream2 + # gw6: upstream2 hwaddr: 0A:14:48:01:2A:26 priv24: type: phys @@ -300,8 +300,8 @@ containers: interfaces: core: type: veth - gw: upstream2 - gw6: upstream2 + # gw: upstream2 + # gw6: upstream2 hwaddr: 0A:14:48:01:2A:28 priv25: type: phys @@ -311,8 +311,8 @@ containers: interfaces: core: type: veth - gw: upstream2 - gw6: upstream2 + # gw: upstream2 + # gw6: upstream2 hwaddr: 0A:14:48:01:2A:2A priv26: type: phys @@ -322,8 +322,8 @@ containers: interfaces: core: type: veth - gw: upstream2 - gw6: upstream2 + # gw: upstream2 + # gw6: upstream2 hwaddr: 0A:14:48:01:2A:2C priv27: type: phys @@ -333,8 +333,8 @@ containers: interfaces: core: type: veth - gw: upstream2 - gw6: upstream2 + # gw: upstream2 + # gw6: upstream2 hwaddr: 0A:14:48:01:2A:2E priv28: type: phys @@ -344,8 +344,8 @@ containers: interfaces: core: type: veth - gw: upstream2 - gw6: upstream2 + # gw: upstream2 + # gw6: upstream2 hwaddr: 0A:14:48:01:2A:30 priv29: type: phys @@ -355,8 +355,8 @@ containers: interfaces: core: type: veth - gw: upstream2 - gw6: upstream2 + # gw: upstream2 + # gw6: upstream2 hwaddr: 0A:14:48:01:2A:32 priv30: type: phys @@ -366,8 +366,8 @@ containers: interfaces: core: type: veth - gw: upstream2 - gw6: upstream2 + # gw: upstream2 + # gw6: upstream2 hwaddr: 0A:14:48:01:2A:34 priv31: type: phys @@ -377,8 +377,8 @@ containers: interfaces: core: type: veth - gw: upstream2 - gw6: upstream2 + # gw: upstream2 + # gw6: upstream2 hwaddr: 0A:14:48:01:2A:36 priv32: type: phys @@ -388,8 +388,8 @@ containers: interfaces: core: type: veth - gw: upstream2 - gw6: upstream2 + # gw: upstream2 + # gw6: upstream2 hwaddr: 0A:14:48:01:2A:38 priv33: type: phys @@ -399,8 +399,8 @@ containers: interfaces: core: type: veth - gw: upstream2 - gw6: upstream2 + # gw: upstream2 + # gw6: upstream2 hwaddr: 0A:14:48:01:2A:40 priv34: type: phys @@ -410,8 +410,8 @@ containers: interfaces: core: type: veth - gw: upstream2 - gw6: upstream2 + # gw: upstream2 + # gw6: upstream2 hwaddr: 0A:14:48:01:2A:42 priv35: type: phys @@ -421,8 +421,8 @@ containers: interfaces: core: type: veth - gw: upstream2 - gw6: upstream2 + # gw: upstream2 + # gw6: upstream2 hwaddr: 0A:14:48:01:2A:44 priv36: type: phys @@ -432,8 +432,8 @@ containers: interfaces: core: type: veth - gw: upstream2 - gw6: upstream2 + # gw: upstream2 + # gw6: upstream2 hwaddr: 0A:14:48:01:2A:46 priv37: type: phys @@ -443,8 +443,8 @@ containers: interfaces: core: type: veth - gw: upstream2 - gw6: upstream2 + # gw: upstream2 + # gw6: upstream2 hwaddr: 0A:14:48:01:2A:48 priv38: type: phys @@ -454,8 +454,8 @@ containers: interfaces: core: type: veth - gw: upstream2 - gw6: upstream2 + # gw: upstream2 + # gw6: upstream2 hwaddr: 0A:14:48:01:2A:4A priv39: type: phys @@ -465,8 +465,8 @@ containers: interfaces: core: type: veth - gw: upstream2 - gw6: upstream2 + # gw: upstream2 + # gw6: upstream2 hwaddr: 0A:14:48:01:2A:4C priv40: type: phys @@ -504,8 +504,8 @@ containers: interfaces: core: type: veth - gw: upstream1 - gw6: upstream1 + # gw: upstream1 + # gw6: upstream1 hwaddr: 0A:14:48:01:21:00 c3d2: type: veth @@ -526,8 +526,8 @@ containers: interfaces: core: type: veth - gw: upstream1 - gw6: upstream1 + # gw: upstream1 + # gw6: upstream1 hwaddr: 0A:14:48:01:22:00 c3d2: type: veth @@ -561,8 +561,8 @@ containers: interfaces: core: type: veth - gw: upstream1 - gw6: upstream1 + # gw: upstream1 + # gw6: upstream1 hwaddr: 0A:14:48:01:24:01 mgmt: type: veth