2021-04-10 14:52:13 +02:00
|
|
|
# Routing daemon configuration
|
2021-03-25 04:06:53 +01:00
|
|
|
{ hostName, config, options, lib, ... }:
|
|
|
|
|
|
|
|
let
|
|
|
|
hostConf = config.site.hosts.${hostName};
|
2021-04-06 22:46:56 +02:00
|
|
|
|
2021-04-29 22:47:11 +02:00
|
|
|
isUpstream =
|
|
|
|
builtins.match "upstream.*" hostName != null ||
|
|
|
|
builtins.match "anon.*" hostName != null;
|
2021-04-29 01:44:48 +02:00
|
|
|
|
2021-04-10 14:52:13 +02:00
|
|
|
# Configuring a gateway? If so, this is the associated net.
|
2021-04-06 22:46:56 +02:00
|
|
|
gatewayNet =
|
|
|
|
let
|
|
|
|
m = builtins.match "(.+)-gw" hostName;
|
2021-04-09 20:13:58 +02:00
|
|
|
in if m == [ "cls" ]
|
|
|
|
then "cluster"
|
|
|
|
else if m == null
|
2021-04-06 22:46:56 +02:00
|
|
|
then null
|
|
|
|
else builtins.head m;
|
2021-04-13 00:46:12 +02:00
|
|
|
|
|
|
|
enumerate = n: list:
|
|
|
|
if list == []
|
|
|
|
then []
|
|
|
|
else [ {
|
|
|
|
n = n;
|
|
|
|
x = builtins.head list;
|
|
|
|
} ] ++ (enumerate (n + 1) (builtins.tail list));
|
2021-03-25 04:06:53 +01:00
|
|
|
in
|
|
|
|
{
|
|
|
|
services.bird2 = {
|
|
|
|
enable = true;
|
|
|
|
config = ''
|
|
|
|
router id ${config.site.net.core.hosts4.${hostName}};
|
|
|
|
|
|
|
|
protocol kernel K4 {
|
2021-04-29 01:44:48 +02:00
|
|
|
learn;
|
2021-03-25 04:06:53 +01:00
|
|
|
ipv4 {
|
2021-04-29 22:47:11 +02:00
|
|
|
${lib.optionalString (!isUpstream) ''
|
|
|
|
export all;
|
|
|
|
''}
|
2021-04-29 01:44:48 +02:00
|
|
|
${lib.optionalString isUpstream ''
|
2021-04-29 22:47:11 +02:00
|
|
|
export filter {
|
|
|
|
if net ~ [ 0.0.0.0/0 ] then {
|
|
|
|
# Do not set another default route on upstreams
|
|
|
|
reject;
|
|
|
|
}
|
|
|
|
accept;
|
|
|
|
};
|
2021-04-29 01:44:48 +02:00
|
|
|
import filter {
|
|
|
|
if net ~ [ 0.0.0.0/0 ] then {
|
2021-04-29 22:47:11 +02:00
|
|
|
# Learn the upstream default route
|
2021-04-29 01:44:48 +02:00
|
|
|
accept;
|
|
|
|
}
|
|
|
|
reject;
|
|
|
|
};
|
|
|
|
''}
|
2021-03-25 04:06:53 +01:00
|
|
|
};
|
|
|
|
}
|
|
|
|
protocol kernel K6 {
|
2021-04-29 01:44:48 +02:00
|
|
|
learn;
|
2021-03-25 04:06:53 +01:00
|
|
|
ipv6 {
|
2021-04-29 22:47:11 +02:00
|
|
|
${lib.optionalString (!isUpstream) ''
|
|
|
|
export all;
|
|
|
|
''}
|
2021-04-29 01:44:48 +02:00
|
|
|
${lib.optionalString isUpstream ''
|
2021-04-29 22:47:11 +02:00
|
|
|
export filter {
|
|
|
|
if net ~ [ ::/0 ] then {
|
|
|
|
# Do not set another default route on upstreams
|
|
|
|
reject;
|
|
|
|
}
|
|
|
|
accept;
|
|
|
|
};
|
|
|
|
# Learn the upstream default route
|
2021-04-29 01:44:48 +02:00
|
|
|
import filter {
|
|
|
|
if net ~ [ ::/0 ] then {
|
|
|
|
accept;
|
|
|
|
}
|
|
|
|
reject;
|
|
|
|
};
|
|
|
|
''}
|
2021-03-25 04:06:53 +01:00
|
|
|
};
|
|
|
|
}
|
|
|
|
protocol device {
|
|
|
|
scan time 10;
|
|
|
|
}
|
|
|
|
|
2021-04-29 22:46:03 +02:00
|
|
|
${lib.optionalString (builtins.match "anon.*" hostName != null) ''
|
|
|
|
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
|
|
|
|
protocol kernel VPN4 {
|
|
|
|
# "vpn4_table" configured on anon routers
|
|
|
|
kernel table 100;
|
|
|
|
ipv4 {
|
|
|
|
table vpn4_table;
|
|
|
|
export all;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
''}
|
|
|
|
|
2021-04-06 22:46:56 +02:00
|
|
|
${lib.optionalString (gatewayNet != null) ''
|
2021-04-10 14:52:13 +02:00
|
|
|
# Router advertisements
|
|
|
|
protocol radv {
|
|
|
|
rdnss ${config.site.net.serv.hosts6.dn42.dnscache};
|
2021-04-06 22:46:56 +02:00
|
|
|
|
2021-04-10 14:52:13 +02:00
|
|
|
interface "${gatewayNet}" {
|
|
|
|
min ra interval 10;
|
|
|
|
max ra interval 60;
|
2021-04-06 22:46:56 +02:00
|
|
|
|
2021-04-10 14:52:13 +02:00
|
|
|
${builtins.concatStringsSep "\n" (
|
|
|
|
map (subnet6: ''
|
|
|
|
prefix ${subnet6} {
|
2021-04-12 21:18:18 +02:00
|
|
|
preferred lifetime 600;
|
|
|
|
valid lifetime 1800;
|
2021-04-10 14:52:13 +02:00
|
|
|
};
|
|
|
|
'') (builtins.attrValues config.site.net.${gatewayNet}.subnets6)
|
|
|
|
)}
|
2021-04-06 22:46:56 +02:00
|
|
|
|
2021-04-10 14:52:13 +02:00
|
|
|
dnssl "${config.site.net.${gatewayNet}.domainName}";
|
|
|
|
};
|
|
|
|
}
|
2021-04-06 22:46:56 +02:00
|
|
|
''}
|
2021-03-25 04:06:53 +01:00
|
|
|
|
2021-04-10 14:52:13 +02:00
|
|
|
# OSPFv2 for site-local IPv4
|
2021-03-25 04:06:53 +01:00
|
|
|
protocol ospf v2 ZW4 {
|
2021-04-29 01:44:48 +02:00
|
|
|
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;
|
|
|
|
};
|
|
|
|
};
|
2021-03-25 04:06:53 +01:00
|
|
|
area 0 {
|
2021-04-10 14:52:13 +02:00
|
|
|
# Enabled on these networks
|
2021-03-25 04:06:53 +01:00
|
|
|
networks {
|
|
|
|
${builtins.concatStringsSep " " (
|
|
|
|
map (n: " ${n};") config.site.ospf.networks4
|
|
|
|
)}
|
|
|
|
};
|
|
|
|
${builtins.concatStringsSep "\n" (
|
|
|
|
builtins.attrValues (
|
|
|
|
builtins.mapAttrs (net: _:
|
2021-04-10 14:52:13 +02:00
|
|
|
# Enable OSPF only on networks with a secret. Others
|
|
|
|
# are treated as a stubnet whose routes to
|
|
|
|
# advertise.
|
2021-03-25 04:06:53 +01:00
|
|
|
if config.site.net.${net}.ospf.secret != null
|
|
|
|
then ''
|
|
|
|
interface "${net}" {
|
|
|
|
authentication cryptographic;
|
|
|
|
password "${config.site.net.${net}.ospf.secret}";
|
|
|
|
};
|
|
|
|
''
|
|
|
|
else if config.site.net.${net}.subnet4 != null
|
|
|
|
then ''
|
2021-04-10 14:52:13 +02:00
|
|
|
# Advertise route of network ${net}
|
2021-03-25 04:06:53 +01:00
|
|
|
stubnet ${config.site.net.${net}.subnet4} {};
|
|
|
|
''
|
|
|
|
else ""
|
|
|
|
) hostConf.interfaces
|
|
|
|
)
|
|
|
|
)}
|
|
|
|
${builtins.concatStringsSep "\n" (
|
2021-04-10 14:52:13 +02:00
|
|
|
map (stubnet4: ''
|
|
|
|
# Advertise additional route
|
|
|
|
stubnet ${stubnet4} {};
|
|
|
|
'') hostConf.ospf.stubNets4
|
2021-03-25 04:06:53 +01:00
|
|
|
)}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2021-04-10 14:52:13 +02:00
|
|
|
# OSPFv3 for site-local IPv6
|
2021-03-25 04:06:53 +01:00
|
|
|
protocol ospf v3 ZW6 {
|
2021-04-29 01:44:48 +02:00
|
|
|
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;
|
|
|
|
};
|
|
|
|
};
|
2021-03-25 04:06:53 +01:00
|
|
|
area 0 {
|
2021-04-10 14:52:13 +02:00
|
|
|
# Enabled on these networks
|
2021-03-25 04:06:53 +01:00
|
|
|
networks {
|
|
|
|
${builtins.concatStringsSep " " (
|
|
|
|
map (n: " ${n};") config.site.ospf.networks6
|
|
|
|
)}
|
|
|
|
};
|
|
|
|
${builtins.concatStringsSep "\n" (
|
|
|
|
builtins.attrValues (
|
|
|
|
builtins.mapAttrs (net: _:
|
2021-04-10 14:52:13 +02:00
|
|
|
# Enable OSPF only on networks with a secret. Others
|
|
|
|
# are treated as a stubnet whose routes to
|
|
|
|
# advertise.
|
2021-03-25 04:06:53 +01:00
|
|
|
if config.site.net.${net}.ospf.secret != null
|
|
|
|
then ''
|
|
|
|
interface "${net}" {
|
2021-04-06 22:08:55 +02:00
|
|
|
# TODO: enable when all bird 1.x have shut down
|
2021-04-06 23:08:27 +02:00
|
|
|
#authentication cryptographic;
|
2021-04-06 22:08:55 +02:00
|
|
|
#password "${config.site.net.${net}.ospf.secret}";
|
2021-03-25 04:06:53 +01:00
|
|
|
};
|
|
|
|
''
|
|
|
|
else builtins.concatStringsSep "\n" (
|
2021-04-10 14:52:13 +02:00
|
|
|
map (subnet6: ''
|
|
|
|
# Advertise route of network ${net}
|
|
|
|
stubnet ${subnet6} {};
|
|
|
|
'') (builtins.attrValues config.site.net.${net}.subnets6)
|
2021-03-25 04:06:53 +01:00
|
|
|
)
|
|
|
|
) hostConf.interfaces
|
|
|
|
)
|
|
|
|
)}
|
|
|
|
${builtins.concatStringsSep "\n" (
|
2021-04-10 14:52:13 +02:00
|
|
|
map (stubnet6: ''
|
|
|
|
# Advertise additional route
|
|
|
|
stubnet ${stubnet6} {};
|
|
|
|
'')
|
2021-03-25 04:06:53 +01:00
|
|
|
hostConf.ospf.stubNets6
|
|
|
|
)}
|
|
|
|
};
|
|
|
|
}
|
2021-04-13 00:46:12 +02:00
|
|
|
|
|
|
|
# Zentralwerk DN42
|
|
|
|
protocol static {
|
|
|
|
ipv4;
|
|
|
|
route 172.20.72.0/21 unreachable;
|
|
|
|
}
|
|
|
|
protocol static {
|
|
|
|
ipv6;
|
|
|
|
route fd23:42:c3d2:580::/57 unreachable;
|
|
|
|
}
|
|
|
|
# Static Vodafone
|
|
|
|
protocol static {
|
|
|
|
ipv6;
|
|
|
|
route 2a02:8106:208:5200::/56 unreachable;
|
|
|
|
route 2a02:8106:211:e900::/56 unreachable;
|
|
|
|
}
|
|
|
|
|
|
|
|
${lib.optionalString (hostConf.bgp != null) ''
|
|
|
|
template bgp bgppeer {
|
|
|
|
local as ${toString hostConf.bgp.asn};
|
|
|
|
|
|
|
|
ipv4 {
|
|
|
|
import all;
|
|
|
|
export where source=RTS_STATIC;
|
|
|
|
};
|
|
|
|
ipv6 {
|
|
|
|
import all;
|
|
|
|
export where source=RTS_STATIC;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
${builtins.concatStringsSep "\n" (
|
|
|
|
map ({ n, x }:
|
|
|
|
let
|
|
|
|
peer = x;
|
|
|
|
peerConf = hostConf.bgp.peers.${peer};
|
|
|
|
in ''
|
|
|
|
protocol bgp bgp_${toString n} from bgppeer {
|
|
|
|
neighbor ${peer} as ${toString peerConf.asn};
|
|
|
|
}
|
|
|
|
''
|
|
|
|
) (enumerate 1 (builtins.attrNames hostConf.bgp.peers))
|
|
|
|
)}
|
|
|
|
''}
|
2021-03-25 04:06:53 +01:00
|
|
|
'';
|
|
|
|
};
|
|
|
|
}
|