From 3d1cd06983aaf05f3eae520dd4a3d83d5dfd989f Mon Sep 17 00:00:00 2001 From: famfo Date: Sat, 11 Jun 2022 00:59:24 +0200 Subject: [PATCH] Update IPAM, base config --- RFCs/IPAM.md | 5 +- base/bird/bird.conf | 94 ++++++++++++++++ base/bird/bird/config/community_filters.conf | 107 ++++++++++++++++++ base/bird/bird/config/custom_filters.conf | 109 +++++++++++++++++++ base/bird/bird/config/functions.conf | 38 +++++++ base/bird/bird/igp/ospf/ospf.conf | 16 +++ base/bird/bird/igp/ospf/ospf_backbone.conf | 6 + base/crontabs/root | 2 + 8 files changed, 375 insertions(+), 2 deletions(-) create mode 100644 base/bird/bird.conf create mode 100644 base/bird/bird/config/community_filters.conf create mode 100644 base/bird/bird/config/custom_filters.conf create mode 100644 base/bird/bird/config/functions.conf create mode 100644 base/bird/bird/igp/ospf/ospf.conf create mode 100644 base/bird/bird/igp/ospf/ospf_backbone.conf create mode 100644 base/crontabs/root diff --git a/RFCs/IPAM.md b/RFCs/IPAM.md index 4ad4e67..b7a19bc 100644 --- a/RFCs/IPAM.md +++ b/RFCs/IPAM.md @@ -23,13 +23,13 @@ | 172.23.196.32 | Reserved | | 172.23.196.33 | GPVM | | 172.23.196.34 | Bagpipe | -| 172.23.196.35 | Unassigned | +| 172.23.196.35 | LXC | | Reserve | | | 172.23.196.36 - 172.23.196.39 | | | Private dn42 devices | | | 172.23.196.40 | NAT | | 172.23.196.41 | famfo PC | -| 172.23.196.42 | Nameserver (TO MOVE) | +| 172.23.196.42 | Unassigned | | 172.23.196.43 | lemon PC | | 172.23.196.44 | Unassigned | | 172.23.196.45 | Unassigned | @@ -70,6 +70,7 @@ |---------------------------|-------------------| | fd42:deca:fbad::1 | GPVM | | fd42:deca:fbad::2 | Bagpipe | +| fd42:deca:fbad::3 | LXC | | fd42:deca:fbad::f1:c47:ff | Authoritative DNS | | fd42:deca:fbad::f1:c0de:0 | Reserved | | fd42:deca:fbad::f1:c0de:1 | famfo PC | diff --git a/base/bird/bird.conf b/base/bird/bird.conf new file mode 100644 index 0000000..7558718 --- /dev/null +++ b/base/bird/bird.conf @@ -0,0 +1,94 @@ +define AS = 4242421411; +define IPv4 = ; +define IPv6 = ; +define NETv4 = 172.23.196.32/27; +define NETv6 = fd42:deca:fbad::/48; +define NETSETv4 = [172.23.196.32/27+]; +define NETSETv6 = [fd42:deca:fbad::/48+]; +define DN42_REGION = ; + +router id IPv4; + +log "/tmp/bird.log" all; + +roa4 table dn42_roa; +roa6 table dn42_roa6; + +protocol device { + scan time 10; +}; + +protocol kernel { + scan time 20; + ipv4 { + import none; + export filter { + if source = RTS_STATIC then reject; + krt_prefsrc = IPv4; + accept; + }; + }; +}; + +protocol kernel { + scan time 20; + ipv6 { + import none; + export filter { + if source = RTS_STATIC then reject; + krt_prefsrc = IPv6; + accept; + }; + }; +}; + +protocol static { + roa4 { + table dn42_roa; + }; + include "/etc/bird/roa/dn42_roa_bird2_4.conf"; +}; + +protocol static { + roa6 { + table dn42_roa6; + }; + include "/etc/bird/roa/dn42_roa_bird2_6.conf"; +}; + +protocol static { + route NETv4 reject; + ipv4 { + import all; + export none; + }; +}; + +protocol static { + route NETv6 reject; + ipv6 { + import all; + export none; + }; +}; + +template bgp dn42_peer { + local as AS; + prefer older on; + enforce first as on; + advertise hostname on; + allow bgp_local_pref; +}; + +template bgp dn42_igp { + local as AS; + direct; +}; + +include "/etc/bird/config/functions.conf"; +include "/etc/bird/config/custom_filters.conf"; +include "/etc/bird/config/community_filters.conf"; +include "/etc/bird/igp/ospf/ospf.conf"; +include "/etc/bird/igp/peers/*"; +include "/etc/bird/peers/*"; + diff --git a/base/bird/bird/config/community_filters.conf b/base/bird/bird/config/community_filters.conf new file mode 100644 index 0000000..be4ec25 --- /dev/null +++ b/base/bird/bird/config/community_filters.conf @@ -0,0 +1,107 @@ +# Stole from https://github.com/jlu5/ansible-dn42/tree/main/roles/config-bird2 +# adapted for our general config (thanks jlu5 for sharing it) +# +# DN42 community filters. Based off https://dn42.net/howto/Bird-communities and tweaked +# for Bird 2 + +function update_latency(int link_latency) { + bgp_community.add((64511, link_latency)); + if (64511, 9) ~ bgp_community then { bgp_community.delete([(64511, 1..8)]); return 9; } + else if (64511, 8) ~ bgp_community then { bgp_community.delete([(64511, 1..7)]); return 8; } + else if (64511, 7) ~ bgp_community then { bgp_community.delete([(64511, 1..6)]); return 7; } + else if (64511, 6) ~ bgp_community then { bgp_community.delete([(64511, 1..5)]); return 6; } + else if (64511, 5) ~ bgp_community then { bgp_community.delete([(64511, 1..4)]); return 5; } + else if (64511, 4) ~ bgp_community then { bgp_community.delete([(64511, 1..3)]); return 4; } + else if (64511, 3) ~ bgp_community then { bgp_community.delete([(64511, 1..2)]); return 3; } + else if (64511, 2) ~ bgp_community then { bgp_community.delete([(64511, 1..1)]); return 2; } + else return 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)]); return 21; } + else if (64511, 22) ~ bgp_community then { bgp_community.delete([(64511, 23..29)]); return 22; } + else if (64511, 23) ~ bgp_community then { bgp_community.delete([(64511, 24..29)]); return 23; } + else if (64511, 24) ~ bgp_community then { bgp_community.delete([(64511, 25..29)]); return 24; } + else if (64511, 25) ~ bgp_community then { bgp_community.delete([(64511, 26..29)]); return 25; } + else if (64511, 26) ~ bgp_community then { bgp_community.delete([(64511, 27..29)]); return 26; } + else if (64511, 27) ~ bgp_community then { bgp_community.delete([(64511, 28..29)]); return 27; } + else if (64511, 28) ~ bgp_community then { bgp_community.delete([(64511, 29..29)]); return 28; } + else return 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)]); return 31; } + else if (64511, 32) ~ bgp_community then { bgp_community.delete([(64511, 33..34)]); return 32; } + else if (64511, 33) ~ bgp_community then { bgp_community.delete([(64511, 34..34)]); return 33; } + else return 34; +} + +function update_flags(int link_latency; int link_bandwidth; int link_crypto) +int dn42_latency; +int dn42_bandwidth; +int dn42_crypto; +{ + dn42_latency = update_latency(link_latency); + dn42_bandwidth = update_bandwidth(link_bandwidth) - 20; + dn42_crypto = update_crypto(link_crypto) - 30; + # TODO: abstract this out into a config variable + if dn42_bandwidth > 4 then dn42_bandwidth = 4; + return true; +} + +function dn42_import_filter(int link_latency; int link_bandwidth; int link_crypto) { + if net.type = NET_IP4 && is_valid_network() && !is_self_net() then { + if (roa_check(dn42_roa, net, bgp_path.last) != ROA_VALID) then { + print "[dn42] ROA check failed for ", net, " - AS ", bgp_path.last; + reject; + } + } else if net.type = NET_IP6 && is_valid_network_v6() && !is_self_net_v6() then { + if (roa_check(dn42_roa6, net, bgp_path.last) != ROA_VALID) then { + print "[dn42] ROA check failed for ", net, " - AS ", bgp_path.last; + reject; + } + } else { # Invalid IP or unknown net type + reject; + } + update_flags(link_latency, link_bandwidth, link_crypto); + bgp_import_filter(); + + accept; +} + +function dn42_export_filter(int link_latency; int link_bandwidth; int link_crypto) { + if (is_valid_network() || is_valid_network_v6()) then { + if source = RTS_STATIC || source = RTS_DEVICE then { + bgp_community.add((64511, DN42_REGION)); + } + update_flags(link_latency, link_bandwidth, link_crypto); + + accept; + } + + reject; +} + +function dn42_ibgp_import_filter(int link_latency; int link_bandwidth; int link_crypto) { + if source = RTS_BGP && net.type = NET_IP4 && is_valid_network() && !is_self_net() then { + update_flags(link_latency, link_bandwidth, link_crypto); + accept; + } else if source = RTS_BGP && net.type = NET_IP6 && is_valid_network_v6() && !is_self_net_v6() then { + update_flags(link_latency, link_bandwidth, link_crypto); + accept; + } else { + reject; + } +} + +function dn42_ibgp_export_filter(int link_latency; int link_bandwidth; int link_crypto) { + if source = RTS_BGP && (is_valid_network() || is_valid_network_v6()) && (!is_self_net() || !is_self_net_v6()) then { + update_flags(link_latency, link_bandwidth, link_crypto); + accept; + } + reject; +} + + diff --git a/base/bird/bird/config/custom_filters.conf b/base/bird/bird/config/custom_filters.conf new file mode 100644 index 0000000..590a802 --- /dev/null +++ b/base/bird/bird/config/custom_filters.conf @@ -0,0 +1,109 @@ +# Based on jlu5's custom filters +# https://github.com/jlu5/ansible-dn42 +# Adapted for AS4242421411 - C4TG1RL5 +# +function lower_pref(int x) { + if (bgp_local_pref > x) then { + bgp_local_pref = bgp_local_pref - x; + } else { + bgp_local_pref = 0; + } +} + +function get_region_tag(int region_tag) { + if (region_tag = 44) then { + return 1; # North America - West + } else if (region_tag ~ [42..43]) then { + return 2; # North America - Central/East + } else if (region_tag = 41) then { + return 3; # Europe + } else if (region_tag ~ [51..53]) then { + return 4; # Asia E/SE + Oceania + } + return 0; +} + +function prefer_same_region_origin(int base_weight) + int region_tag; + int incoming_tag; +{ + region_tag = get_region_tag(DN42_REGION); + incoming_tag = 0; + + if ((64511, 41) ~ bgp_community) then { + incoming_tag = get_region_tag(41); + } + else if ((64511, 42) ~ bgp_community) then { + incoming_tag = get_region_tag(42); + } + else if ((64511, 43) ~ bgp_community) then { + incoming_tag = get_region_tag(43); + } + else if ((64511, 44) ~ bgp_community) then { + incoming_tag = get_region_tag(44); + } + else if ((64511, 50) ~ bgp_community) then { + incoming_tag = get_region_tag(50); + } + else if ((64511, 51) ~ bgp_community) then { + incoming_tag = get_region_tag(51); + } + else if ((64511, 52) ~ bgp_community) then { + incoming_tag = get_region_tag(52); + } + else if ((64511, 53) ~ bgp_community) then { + incoming_tag = get_region_tag(53); + } + + if (incoming_tag = 0 || incoming_tag = region_tag) then { + # print "Route ", net, " has incoming tag ", incoming_tag, " matching ours ", region_tag; + bgp_local_pref = bgp_local_pref + 50; + } +} + +function bgp_import_filter() { + # Reject routes with long path lengths + if (bgp_path.len > 12) then { + reject; + } + + bgp_local_pref = bgp_local_pref + 1400; + lower_pref(bgp_path.len * 100); + prefer_same_region_origin(200); + + if (source = RTS_BGP && (65535, 666) ~ bgp_community) then { + dest = RTD_BLACKHOLE; + } +}; + +function ibgp_import_filter() { + if (source != RTS_BGP) then { + reject; + } + if (!is_valid_network() && !is_valid_network_v6()) then { + reject; + } + + bgp_local_pref = bgp_local_pref + 1400; + lower_pref(bgp_path.len * 100); + if (bgp_path.len = 0) then { + bgp_local_pref = bgp_local_pref + 2000; + } + + accept; +} + +# TODO: implement exports with the bgp_med attribute + +function ibgp_export_filter() { + if (source != RTS_BGP && !is_ibgp_network()) then { + reject; + } + # Don't export device routes for dn42 anycast networks. These will be filled in via a static route config + # triggered by service start/stop + if (is_ibgp_network() && source = RTS_DEVICE) then { + reject; + } + accept; +} + diff --git a/base/bird/bird/config/functions.conf b/base/bird/bird/config/functions.conf new file mode 100644 index 0000000..3554096 --- /dev/null +++ b/base/bird/bird/config/functions.conf @@ -0,0 +1,38 @@ +function is_self_net() { + return net ~ NETSETv4; +} + +function is_valid_network() { + 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_v6() { + return net ~ NETSETv6; +} + +function is_valid_network_v6() { + return net ~ [ + fd00::/8{44,64} # ULA address space as per RFC 4193 + ]; +} + +function is_ibgp_network() { + if net.type = NETv4 && net ~ NETSETv4 then { + return true; + } else if net.type = NETv6 && net ~ NETSETv6 then { + return true; + } else { + return false; + } +} + diff --git a/base/bird/bird/igp/ospf/ospf.conf b/base/bird/bird/igp/ospf/ospf.conf new file mode 100644 index 0000000..a25598a --- /dev/null +++ b/base/bird/bird/igp/ospf/ospf.conf @@ -0,0 +1,16 @@ +protocol ospf v3 ospf_gpvm { + ipv4 { + import where is_self_net() && source != RTS_BGP; + export where is_self_net() && source != RTS_BGP; + }; + include "/etc/bird/igp/ospf/ospf_backbone.conf"; +}; + +protocol ospf v3 ospf6_gpvm { + ipv6 { + import where is_self_net_v6() && source != RTS_BGP; + export where is_self_net_v6() && source != RTS_BGP; + }; + include "/etc/bird/igp/ospf/ospf_backbone.conf"; +}; + diff --git a/base/bird/bird/igp/ospf/ospf_backbone.conf b/base/bird/bird/igp/ospf/ospf_backbone.conf new file mode 100644 index 0000000..7038a54 --- /dev/null +++ b/base/bird/bird/igp/ospf/ospf_backbone.conf @@ -0,0 +1,6 @@ +area 0 { + interface "dn42_igp" { + stub; + }; +}; + diff --git a/base/crontabs/root b/base/crontabs/root new file mode 100644 index 0000000..20faa47 --- /dev/null +++ b/base/crontabs/root @@ -0,0 +1,2 @@ +0 * * * * curl -sfo /etc/bird/roa/dn42_roa_bird2_6.conf https://dn42.burble.com/roa/dn42_roa_bird2_6.conf && birdc configure +0 * * * * curl -sfo /etc/bird/roa/dn42_roa_bird2_4.conf https://dn42.burble.com/roa/dn42_roa_bird2_4.conf && birdc configure