added dn42 bgp communities

This commit is contained in:
Marcel - 2024-03-14 21:42:08 +01:00
parent 16e12e76e1
commit 36654301a2
Signed by: m4rc3l
GPG Key ID: 446F3B093DF81C6A
6 changed files with 274 additions and 73 deletions

View File

@ -6,6 +6,7 @@ let
networking.dn42.enable = true;
virtualisation.interfaces.enp1s0.vlan = 1;
networking.useNetworkd = true;
networking.domain = "test.nixos";
systemd.network.netdevs.dummy0.netdevConfig = {
Kind = "dummy";
Name = "dummy0";
@ -20,14 +21,21 @@ pkgs.nixosTest rec {
nodes = {
foo = {
imports = [ common ];
networking.hostName = "foo";
networking.dn42 = {
as = 64600;
bandwidth = 25;
geo = 41;
country = 1276;
addr.v4 = "172.20.0.1";
nets.v4 = [ "172.20.0.0/24" ];
addr.v6 = "fec0::1";
nets.v6 = [ "fec0::/64" ];
peers.bar = {
as = 64601;
latency = 1;
bandwidth = 25;
crypto = 31;
extendedNextHop = true;
addr.v6 = (builtins.head nodes.bar.networking.interfaces.enp1s0.ipv6.addresses).address;
srcAddr.v6 = (builtins.head nodes.foo.networking.interfaces.enp1s0.ipv6.addresses).address;
@ -57,14 +65,21 @@ pkgs.nixosTest rec {
};
bar = {
imports = [ common ];
networking.hostName = "bar";
networking.dn42 = {
as = 64601;
bandwidth = 25;
geo = 41;
country = 1276;
addr.v4 = "172.20.1.1";
nets.v4 = [ "172.20.1.0/24" ];
addr.v6 = "fec0:0:0:1::1";
nets.v6 = [ "fec0:0:0:1::/64" ];
peers.foo = {
as = 64600;
latency = 1;
bandwidth = 25;
crypto = 31;
extendedNextHop = true;
addr.v6 = (builtins.head nodes.foo.networking.interfaces.enp1s0.ipv6.addresses).address;
srcAddr.v6 = (builtins.head nodes.bar.networking.interfaces.enp1s0.ipv6.addresses).address;

View File

@ -6,6 +6,7 @@ let
networking.dn42.enable = true;
virtualisation.interfaces.enp1s0.vlan = 1;
networking.useNetworkd = true;
networking.domain = "text.nixos";
systemd.network.netdevs.dummy0.netdevConfig = {
Kind = "dummy";
Name = "dummy0";
@ -20,14 +21,21 @@ pkgs.nixosTest rec {
nodes = {
foo = {
imports = [ common ];
networking.hostName = "foo";
networking.dn42 = {
as = 64600;
bandwidth = 25;
geo = 41;
country = 1276;
addr.v4 = "172.20.0.1";
nets.v4 = [ "172.20.0.0/24" ];
addr.v6 = "fec1::1";
nets.v6 = [ "fec1::/64" ];
peers.bar = {
as = 64601;
latency = 1;
bandwidth = 25;
crypto = 31;
addr.v4 = (builtins.head nodes.bar.networking.interfaces.enp1s0.ipv4.addresses).address;
addr.v6 = (builtins.head nodes.bar.networking.interfaces.enp1s0.ipv6.addresses).address;
srcAddr.v4 = (builtins.head nodes.foo.networking.interfaces.enp1s0.ipv4.addresses).address;
@ -58,14 +66,21 @@ pkgs.nixosTest rec {
};
bar = {
imports = [ common ];
networking.hostName = "bar";
networking.dn42 = {
as = 64601;
bandwidth = 25;
geo = 41;
country = 1276;
addr.v4 = "172.20.1.1";
nets.v4 = [ "172.20.1.0/24" ];
addr.v6 = "fec1:0:0:1::1";
nets.v6 = [ "fec1:0:0:1::/64" ];
peers.foo = {
as = 64600;
latency = 1;
bandwidth = 25;
crypto = 31;
addr.v4 = (builtins.head nodes.foo.networking.interfaces.enp1s0.ipv4.addresses).address;
addr.v6 = (builtins.head nodes.foo.networking.interfaces.enp1s0.ipv6.addresses).address;
srcAddr.v4 = (builtins.head nodes.bar.networking.interfaces.enp1s0.ipv4.addresses).address;

View File

@ -1,4 +1,5 @@
{ config, lib, ... }:
let
cfg = config.networking.dn42;
in
@ -18,15 +19,14 @@ in
services.bird2 = {
enable = true;
config = ''
router id ${cfg.routerId};
define OWNAS = ${toString cfg.as};
define OWNIP = ${toString cfg.addr.v6};
protocol device {
scan time 10;
}
define BANDWIDTH = ${toString cfg.bandwidth};
define REGION_GEO = ${toString cfg.geo};
define REGION_COUNTRY = ${toString cfg.country};
/*
* Utility functions
*/
define ASN_BLACKLIST = [];
function is_self_net_v4() -> bool {
return net ~ [${builtins.concatStringsSep ", " cfg.nets.v4}];
@ -36,39 +36,18 @@ in
return net ~ [${builtins.concatStringsSep ", " cfg.nets.v6}];
}
function is_valid_network_v4() -> bool {
return net ~ [
172.20.0.0/14{21,29}, # dn42
172.20.0.0/24{28,32}, # dn42 Anycast
172.21.0.0/24{28,32}, # dn42 Anycast
172.22.0.0/24{28,32}, # dn42 Anycast
172.23.0.0/24{28,32}, # dn42 Anycast
172.31.0.0/16+, # ChaosVPN
10.100.0.0/14+, # ChaosVPN
10.127.0.0/16{16,32}, # neonetwork
10.0.0.0/8{15,24} # Freifunk.net
];
function is_self_net() -> bool {
return is_self_net_v4() || is_self_net_v6();
}
/*
roa4 table dn42_roa;
roa6 table dn42_roa_v6;
include "${../resources/community_filter.conf}";
include "${../resources/filters.conf}";
router id ${cfg.routerId};
hostname "${config.networking.hostName}.${config.networking.domain}";
protocol static {
roa4 { table dn42_roa; };
include "/etc/bird/roa_dn42.conf";
};
protocol static {
roa6 { table dn42_roa_v6; };
include "/etc/bird/roa_dn42_v6.conf";
};
*/
function is_valid_network_v6() -> bool {
return net ~ [
fd00::/8{44,64} # ULA address space as per RFC 4193
];
protocol device {
scan time 10;
}
protocol kernel {
@ -121,46 +100,17 @@ in
template bgp dnpeers {
local as ${builtins.toString cfg.as};
path metric 1;
enforce first as on;
graceful restart on;
long lived graceful restart on;
interpret communities on;
advertise hostname on;
prefer older on;
ipv4 {
import filter {
if is_valid_network_v4() && !is_self_net_v4() then {
/*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;
} else*/ accept;
} else reject;
};
export filter { if is_valid_network_v4() && source ~ [RTS_STATIC, RTS_BGP] then accept; else reject; };
import limit 9000 action block;
import table 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 limit 9000 action block;
import table on;
};
# defaults
enable route refresh on;
interpret communities on;
default bgp_local_pref 100;
}
${builtins.concatStringsSep "\n" (builtins.attrValues
@ -170,6 +120,14 @@ in
protocol bgp ${name}_4 from dnpeers {
neighbor ${conf.addr.v4} as ${builtins.toString conf.as};
source address ${conf.srcAddr.v4};
ipv4 {
import limit 9000 action block;
import table on;
import where dn_import_filter(${toString conf.latency}, ${toString conf.bandwidth}, ${toString conf.crypto});
export where dn_export_filter(${toString conf.latency}, ${toString conf.bandwidth}, ${toString conf.crypto});
};
}
''}
@ -178,9 +136,22 @@ in
enable extended messages on;
ipv4 {
extended next hop on;
import limit 9000 action block;
import table on;
extended next hop on;
import where dn_import_filter(${toString conf.latency}, ${toString conf.bandwidth}, ${toString conf.crypto});
export where dn_export_filter(${toString conf.latency}, ${toString conf.bandwidth}, ${toString conf.crypto});
};
''}
ipv6 {
import limit 9000 action block;
import table on;
import where dn_import_filter(${toString conf.latency}, ${toString conf.bandwidth}, ${toString conf.crypto});
export where dn_export_filter(${toString conf.latency}, ${toString conf.bandwidth}, ${toString conf.crypto});
};
neighbor ${conf.addr.v6}%'${conf.interface}' as ${builtins.toString conf.as};
source address ${conf.srcAddr.v6};

View File

@ -22,6 +22,26 @@ in
description = "Autonomous System Number";
};
bandwidth = lib.mkOption {
type = lib.types.int;
description = "";
};
geo = lib.mkOption {
type = lib.types.int;
description = "";
};
country = lib.mkOption {
type = lib.types.int;
description = "";
};
blockedAs = lib.mkOption {
type = lib.types.listOf lib.types.int;
description = "";
};
addr = {
v4 = lib.mkOption {
type = lib.types.str;
@ -60,6 +80,21 @@ in
default = false;
};
latency = lib.mkOption {
type = lib.types.int;
description = "";
};
bandwidth = lib.mkOption {
type = lib.types.int;
description = "";
};
crypto = lib.mkOption {
type = lib.types.int;
description = "";
};
addr = {
v4 = lib.mkOption {
type = lib.types.nullOr lib.types.str;

View File

@ -0,0 +1,46 @@
function update_latency(int link_latency) {
bgp_community.add((64511, link_latency));
if (64511, 9) ~ bgp_community then { bgp_community.delete([(64511, 1..8)]); }
else if (64511, 8) ~ bgp_community then { bgp_community.delete([(64511, 1..7)]); }
else if (64511, 7) ~ bgp_community then { bgp_community.delete([(64511, 1..6)]); }
else if (64511, 6) ~ bgp_community then { bgp_community.delete([(64511, 1..5)]); }
else if (64511, 5) ~ bgp_community then { bgp_community.delete([(64511, 1..4)]); }
else if (64511, 4) ~ bgp_community then { bgp_community.delete([(64511, 1..3)]); }
else if (64511, 3) ~ bgp_community then { bgp_community.delete([(64511, 1..2)]); }
else if (64511, 2) ~ bgp_community then { bgp_community.delete([(64511, 1..1)]); }
}
function update_bandwidth(int link_bandwidth) {
bgp_community.add((64511, link_bandwidth));
if (64511, 21) ~ bgp_community then { bgp_community.delete([(64511, 22..29)]); }
else if (64511, 22) ~ bgp_community then { bgp_community.delete([(64511, 23..29)]); }
else if (64511, 23) ~ bgp_community then { bgp_community.delete([(64511, 24..29)]); }
else if (64511, 24) ~ bgp_community then { bgp_community.delete([(64511, 25..29)]); }
else if (64511, 25) ~ bgp_community then { bgp_community.delete([(64511, 26..29)]); }
else if (64511, 26) ~ bgp_community then { bgp_community.delete([(64511, 27..29)]); }
else if (64511, 27) ~ bgp_community then { bgp_community.delete([(64511, 28..29)]); }
else if (64511, 28) ~ bgp_community then { bgp_community.delete([(64511, 29..29)]); }
}
function update_crypto(int link_crypto) {
bgp_community.add((64511, link_crypto));
if (64511, 31) ~ bgp_community then { bgp_community.delete([(64511, 32..34)]); }
else if (64511, 32) ~ bgp_community then { bgp_community.delete([(64511, 33..34)]); }
else if (64511, 33) ~ bgp_community then { bgp_community.delete([(64511, 34..34)]); }
}
function update_flags(int link_latency; int link_bandwidth; int link_crypto) {
if link_bandwidth > BANDWIDTH then link_bandwidth = BANDWIDTH;
update_latency(link_latency);
update_bandwidth(link_bandwidth);
update_crypto(link_crypto);
}
function update_region() {
if is_self_net() then {
bgp_community.add((64511, REGION_GEO));
bgp_community.add((64511, REGION_COUNTRY));
}
}

119
resources/filters.conf Normal file
View File

@ -0,0 +1,119 @@
function is_valid_network_v4() -> bool{
return net ~ [
172.20.0.0/14{21,29}, # dn42
172.20.0.0/24{28,32}, # dn42 Anycast
172.21.0.0/24{28,32}, # dn42 Anycast
172.22.0.0/24{28,32}, # dn42 Anycast
172.23.0.0/24{28,32}, # dn42 Anycast
172.31.0.0/16+, # ChaosVPN
10.100.0.0/14+, # ChaosVPN
10.127.0.0/16{16,32}, # neonetwork
10.0.0.0/8{15,24} # Freifunk.net
];
}
function is_valid_network_v6() -> bool {
return net ~ [
fd00::/8{44,64}
];
}
function is_valid_network() -> bool {
return is_valid_network_v4() || is_valid_network_v6();
}
function kernel_export() {
krt_prefsrc = OWNIP;
accept;
}
function reject_invalid_roa() {
#if (roa_check(dnroa, net, bgp_path.last) != ROA_VALID) then {
# print "Reject: ROA failed|", net, "|", bgp_path;
# reject;
#}
}
function reject_default_route() {
if (net = fd00::/8 || net = ::/0) then
reject;
}
function reject_blacklisted()
int set blacklist;
{
blacklist = ASN_BLACKLIST;
if ( bgp_path ~ blacklist ) then {
print "Reject: blacklisted ASN|", bgp_path;
reject;
}
}
function honor_graceful_shutdown() {
if (65535, 0) ~ bgp_community then {
bgp_local_pref = 0;
}
}
function dn_import_filter(int link_latency; int link_bandwidth; int link_crypto) {
#if ( net.type != NET_IP6 ) then {
# print "Reject: non-IPv6 on IPv6 Channel|", net, "|", bgp_path;
# reject;
#}
if ( ! is_valid_network() ) then {
print "Reject: invalid network|", net, "|", bgp_path;
reject;
}
if ( is_self_net() ) then {
print "Reject: export our network|", net, "|", bgp_path.first;
reject;
}
if ( bgp_path.len > 25 ) then {
print "Reject: AS path too long|", net, "|", bgp_path;
reject;
}
reject_blacklisted();
reject_invalid_roa();
reject_default_route();
if (bgp_path.len = 1) then
bgp_local_pref = bgp_local_pref + 500;
update_flags(link_latency, link_bandwidth, link_crypto);
accept;
}
function dn_export_filter(int link_latency; int link_bandwidth; int link_crypto) {
if (source !~ [RTS_STATIC, RTS_BGP]) then
reject;
if (bgp_path.last != bgp_path.first) then
reject;
reject_default_route();
update_flags(link_latency, link_bandwidth, link_crypto);
update_region();
bgp_med = 0;
bgp_med = bgp_med + ( ( 4 - ( link_crypto - 30 ) ) * 600 );
bgp_med = bgp_med + ( ( 9 - ( link_bandwidth - 20 ) ) * 100);
bgp_med = bgp_med + ( ( link_latency - 1) * 300);
accept;
}
function dn_export_collector() {
if (source !~ [RTS_STATIC, RTS_BGP]) then
reject;
update_region();
accept;
}