{ config, pkgs, lib, ... }: with lib; let cfg = config.profiles.clerie.dn42-router; myAsn = 4242422574; ospf6Table = 1337; bgp6Table = 2342; in { options.profiles.clerie.dn42-router = { enable = mkEnableOption "DN42 router base config"; loopbackIp = mkOption { type = types.str; description = "IPv6 lookback IP"; }; routerId = mkOption { type = types.str; description = "IPv6 lookback IP"; }; ospfInterfaces = mkOption { type = with types; listOf str; default = []; }; ibgpPeers = mkOption { type = with types; listOf (submodule ({ ... }: { options = { remoteAddress = mkOption { type = types.str; }; peerName = mkOption { type = types.str; }; }; })); default = []; description = "External bgp peers"; }; bgpPeers = mkOption { type = with types; listOf (submodule ({ ... }: { options = { localAddress = mkOption { type = types.str; }; remoteAddress = mkOption { type = types.str; }; peerName = mkOption { type = types.str; }; remoteAsn = mkOption { type = types.str; }; }; })); default = []; description = "External bgp peers"; }; wireguardPeers = mkOption { type = with types; listOf (submodule ({ ... }: { options = { interfaceName = mkOption { type = types.str; }; localAddress = mkOption { type = types.str; }; #localAddressPrefixlen = ; remoteAddress = mkOption { type = types.str; }; #remoteAddressPrefixlen = ; #localPrivateKey = ; #remotePublicKey = ; #localListenPort = ; #remoteEnpoint = ; peerName = mkOption { type = types.str; }; remoteAsn = mkOption { type = types.str; }; }; })); default = []; description = "External bgp peers connected via wireguard"; }; birdExtraConfig = mkOption { type = types.str; default = ""; }; }; config = mkIf config.profiles.clerie.dn42-router.enable { systemd.network.config.routeTables = { bgp6 = bgp6Table; ospf6 = ospf6Table; }; systemd.network.config.addRouteTablesToIPRoute2 = true; environment.systemPackages = with pkgs; [ wireguard-tools ]; boot.kernel.sysctl = { "net.ipv4.ip_forward" = true; "net.ipv6.conf.all.forwarding" = true; }; networking.firewall.checkReversePath = false; # Open Firewall for BGP networking.firewall.allowedTCPPorts = [ 179 ]; # Open Fireall for OSPF networking.firewall.extraCommands = '' ip6tables -A INPUT -p ospfigp -j ACCEPT iptables -A INPUT -p ospfigp -j ACCEPT ''; systemd.network.netdevs."10-lo-dn42" = { netdevConfig = { Kind = "dummy"; Name = "lo-dn42"; }; }; systemd.network.networks."10-lo-dn42" = { matchConfig.Name = "lo-dn42"; address = [ "${ cfg.loopbackIp }/128" ]; linkConfig.RequiredForOnline = "no"; routingPolicyRules = [ { Priority = 10000; Family = "ipv6"; To = "fd56:4902:eca0::/48"; Table = "ospf6"; } { Priority = 11000; Family = "ipv6"; Table = "bgp6"; } { Priority = 15000; Family = "ipv6"; From = "fd56:4902:eca0::/48"; Type = "unreachable"; } { Priority = 16000; Family = "ipv6"; To = "fd56:4902:eca0::/48"; Type = "unreachable"; } { Priority = 20000; Family = "both"; Table = "main"; } ]; }; services.bird.enable = true; services.bird.package = pkgs.bird2; services.bird.config = '' router id ${ cfg.routerId }; ipv6 table ospf6; ipv6 table bgp6; protocol direct { interface "lo-dn42"; ipv6 { table ospf6; }; } protocol static { ipv6 { table bgp6; }; route fd56:4902:eca0::/48 via "lo-dn42"; } protocol kernel { ipv6 { table ospf6; export filter { krt_prefsrc=${ cfg.loopbackIp }; accept; }; import none; }; kernel table ${ toString ospf6Table }; } protocol kernel { ipv6 { table bgp6; export filter { krt_prefsrc=${ cfg.loopbackIp }; accept; }; import none; }; kernel table ${ toString bgp6Table }; } protocol device { scan time 10; } protocol ospf v3 { ipv6 { table ospf6; import all; export all; }; area 0 { ${ concatMapStringsSep "\n" (interfaceName: '' interface "${interfaceName}" { cost 80; type broadcast; }; '') cfg.ospfInterfaces} }; } template bgp ibgp_peer { local as ${ toString myAsn }; graceful restart on; source address ${ cfg.loopbackIp}; ipv6 { table bgp6; igp table ospf6; next hop self; import keep filtered; import all; export all; }; } ${concatMapStringsSep "\n" ( peerConfig: '' protocol bgp ${peerConfig.peerName} from ibgp_peer { neighbor ${peerConfig.remoteAddress} as ${ toString myAsn }; } '') cfg.ibgpPeers} template bgp bgp_peer { local as ${ toString myAsn }; graceful restart on; ipv6 { table bgp6; next hop self; import keep filtered; import filter { if net ~ [fd00::/8{48,64}] then accept; reject; }; export filter { if net ~ [fd00::/8{48,64}] then accept; reject; }; }; } ${concatMapStringsSep "\n" ( peerConfig: '' protocol bgp ${peerConfig.peerName} from bgp_peer { neighbor ${peerConfig.remoteAddress} as ${peerConfig.remoteAsn}; source address ${peerConfig.localAddress}; } '') cfg.bgpPeers} ${concatMapStringsSep "\n" ( peerConfig: '' protocol bgp ${peerConfig.peerName} from bgp_peer { neighbor ${peerConfig.remoteAddress}%${peerConfig.interfaceName} as ${peerConfig.remoteAsn}; source address ${peerConfig.localAddress}; } '') cfg.wireguardPeers} ${ cfg.birdExtraConfig } ''; }; }