prefect: Enable DN42 configuration

This commit is contained in:
The Hedgehog 2022-08-22 09:35:42 -04:00
parent e77b7e97cf
commit a08dfb632f
No known key found for this signature in database
8 changed files with 512 additions and 0 deletions

View file

@ -16,6 +16,9 @@
./networking.nix
./hardware.nix
# DN42 Services
./dn42.nix
# Running Services
./services/blog-update.nix
./services/caddy.nix

46
hosts/prefect/dn42.nix Normal file
View file

@ -0,0 +1,46 @@
{
hedge.dn42 = {
enable = true;
bgp = {
asn = "4242422459";
staticRoutes = {
ipv4 = [
"172.20.43.96/27"
];
ipv6 = [
"fd21:1500:66b0::/48"
];
};
};
peers = {
lutoma = {
tunnelType = "wireguard";
wireguardConfig = {
localPort = 485;
remotePort = 42518;
remoteEndpoint = "us-nyc.dn42.lutoma.org";
remotePublicKey = "PVrvKh7MAkLfCdO2u1t6WqAsAMw1afeQ8OewdL/K2Cw=";
};
interfaceName = "wg-lutoma";
bgp = {
asn = "64719";
multi_protocol = true;
local_pref = 100;
};
addresses = {
ipv4 = {
local_address = "172.20.43.96";
remote_address = "172.22.119.10";
prefix_length = 32;
};
ipv6 = {
local_address = "fe80::1";
remote_address = "fe80::acab";
prefix_length = 64;
};
};
};
};
};
}

View file

@ -0,0 +1,48 @@
{ ... }:
{
sessions = [
{ multi = true; name = "androw_2575"; neigh = "fe80::2575:6%andro_2575_zrh"; as = "4242422575"; link = "4"; }
{ multi = true; name = "bandura_2923"; neigh = "fe80::2923%band_2923_nur"; as = "4242422923"; link = "3"; }
{ multi = true; name = "dgy_0826"; neigh = "fe80::a0e:fb02%dgy_0826_la"; as = "4242420826"; link = "5"; }
{ multi = false; v4 = true; v6 = false; name = "hackfront_1472_v4"; neigh = "172.23.167.1"; as = "4242421472"; link = "4"; }
{ multi = false; v4 = false; v6 = true; name = "hackfront_1472_v6"; neigh = "fe80::1472%hackf_1472_it"; as = "4242421472"; link = "4"; }
{ multi = true; name = "jlu5_1080"; neigh = "fe80::116%jlu5_1080_lon"; as = "4242421080"; link = "3"; }
{ multi = true; name = "kioubit_3914"; neigh = "fe80::ade0%kioubit_3914_uk"; as = "4242423914"; link = "3"; }
{ multi = true; name = "n0emis_0197"; neigh = "fe80::42:42:1%n0emi_0197_gtg"; as = "4242420197"; link = "4"; }
{ multi = true; name = "napsterbater_1050"; neigh = "fe80::1:1050%napst_1050_fra"; as = "4242421050"; link = "2"; }
{ multi = true; name = "niantic_1331"; neigh = "fe80::1331%niant_1331_ams"; as = "4242421331"; link = "3"; }
{ multi = true; name = "yuetau_0925"; neigh = "fe80::925%yuetau_0925_nue"; as = "4242420925"; link = "3"; }
];
extraConfig = ''
protocol bgp iBGP_par_v4 from dnpeers {
#disabled;
neighbor 172.20.4.97 as 4242421722;
ipv4 {
next hop self;
import all;
export where dn42_export_filter(3,25,34);
import keep filtered;
};
ipv6 {
next hop self;
import none;
export none;
};
}
protocol bgp iBGP_par_v6 from dnpeers {
#disabled;
neighbor fd54:fe4b:9ed1:1::1 as 4242421722;
ipv4 {
next hop self;
import none;
export none;
};
ipv6 {
next hop self;
import all;
export where dn42_export_filter(3,25,34);
import keep filtered;
};
}
'';
}

View file

@ -0,0 +1,279 @@
log stderr all;
debug protocols all;
timeformat protocol iso long;
################################################
# Variable header #
################################################
define OWNAS = 4242422459;
define OWNIP = 172.20.43.96;
define OWNIPv6 = fd21:1500:66b0::1;
define OWNNET = 172.20.43.96/27;
define OWNNETv6 = fd21:1500:66b0::/48;
define OWNNETSET = [172.20.43.96/29+];
define OWNNETSETv6 = [fd21:1500:66b0::/48+];
define DN42_REGION = 42;
################################################
# Header end #
################################################
router id OWNIP;
protocol device {
scan time 10;
}
/*
* Utility functions
*/
function is_self_net() {
return net ~ OWNNETSET;
}
function is_self_net_v6() {
return net ~ OWNNETSETv6;
}
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
];
}
roa4 table dn42_roa;
roa6 table dn42_roa_v6;
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() {
return net ~ [
fd00::/8{44,64} # ULA address space as per RFC 4193
];
}
protocol kernel {
scan time 20;
ipv6 {
import none;
export filter {
if source = RTS_STATIC then reject;
krt_prefsrc = OWNIPv6;
accept;
};
};
};
protocol kernel {
scan time 20;
ipv4 {
import none;
export filter {
if source = RTS_STATIC then reject;
krt_prefsrc = OWNIP;
accept;
};
};
}
protocol static {
route OWNNET reject;
ipv4 {
import all;
export none;
};
}
protocol static {
route OWNNETv6 reject;
ipv6 {
import all;
export none;
};
}
template bgp dnpeers {
local as OWNAS;
path metric 1;
}
protocol ospf v3 {
ipv4 {
export filter {
if source = RTS_STATIC || source = RTS_BGP then reject;
accept;
};
};
area 0 {
interface "lo" {
stub;
};
interface "ospf_*"{
type pointopoint;
};
};
}
protocol ospf v3 {
ipv6 {
export filter {
if source = RTS_STATIC || source = RTS_BGP then reject;
accept;
};
};
area 0 {
interface "lo" {
stub;
};
interface "ospf_*" {
type pointopoint;
};
};
}
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 get_region() {
if (64511, 41) ~ bgp_community then { return 41; }
else if (64511, 42) ~ bgp_community then { return 42; }
else if (64511, 43) ~ bgp_community then { return 43; }
else if (64511, 44) ~ bgp_community then { return 44; }
else if (64511, 45) ~ bgp_community then { return 45; }
else if (64511, 46) ~ bgp_community then { return 46; }
else if (64511, 47) ~ bgp_community then { return 47; }
else if (64511, 48) ~ bgp_community then { return 48; }
else if (64511, 49) ~ bgp_community then { return 49; }
else if (64511, 50) ~ bgp_community then { return 50; }
else if (64511, 51) ~ bgp_community then { return 51; }
else if (64511, 52) ~ bgp_community then { return 52; }
else if (64511, 53) ~ bgp_community then { return 53; }
else return DN42_REGION;
}
function calculate_local_pref(int dn42_latency)
int pref;
{
pref = 100;
if (is_self_net() || is_self_net_v6()) then {
pref = 2000;
}
else if (bgp_path.len = 1) then {
pref = 1000;
}
else if (DN42_REGION = get_region()) then {
pref= 500;
}
else {
if (DN42_REGION > get_region()) then {
pref = 500 - ((DN42_REGION - get_region()) * 10);
}
else {
pref = 500 - ((get_region() - DN42_REGION) * 10);
}
}
pref = pref - 10*dn42_latency - 10* bgp_path.len;
if pref > 2000 then {
pref = 10;
}
return pref;
}
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;
if dn42_bandwidth > 5 then dn42_bandwidth = 5;
bgp_local_pref = calculate_local_pref(dn42_latency);
return true;
}
function dn42_import_filter(int link_latency; int link_bandwidth; int link_crypto) {
if (is_valid_network() && !is_self_net()) || (is_valid_network_v6() && !is_self_net_v6()) then {
if roa_check(dn42_roa, net, bgp_path.last) != ROA_VALID && roa_check(dn42_roa_v6, net, bgp_path.last) != ROA_VALID then {
print "[dn42] Import : ROA check failed for ", net, " ASN ", bgp_path.last, " on ", proto;
reject;
}
update_flags(link_latency, link_bandwidth, link_crypto);
if (65535, 666) ~ bgp_community then dest = RTD_BLACKHOLE;
accept;
}
print "[dn42] Import : Invalid Network for ", net, " ASN ", bgp_path.last, " on ", proto;
reject;
}
function dn42_export_filter(int link_latency; int link_bandwith; int link_crypto) {
if is_valid_network() || is_valid_network_v6() then {
# if roa_check(dn42_roa, net, bgp_path.last) != ROA_VALID && roa_check(dn42_roa_v6, net, bgp_path.last) != ROA_VALID then {
# print "[dn42] Export : ROA check failed for ", net, " ASN ", bgp_path.last, " on ", proto;
# reject;
# }
if source = RTS_STATIC then bgp_community.add((64511, DN42_REGION));
update_flags(link_latency, link_bandwith, link_crypto);
accept;
}
reject;
}

View file

@ -0,0 +1,15 @@
{
networking.interfaces.lo = {
ipv4.addresses = [{ address = "172.20.43.96"; prefixLength = 32; }];
ipv6.addresses = [
{ address = "fd21:1500:66b0::1"; prefixLength = 128; }
{ address = "fe80::1"; prefixLength = 128; }
];
};
environment.systemPackages = with pkgs; [
dnsutils
mtr
tcpdump
wireguard-tools
];
}

View file

@ -0,0 +1,83 @@
let
script = pkgs.writeShellScriptBin "update-roa" ''
mkdir -p /etc/bird/
${pkgs.curl}/bin/curl -sfSLR {-o,-z}/etc/bird/roa_dn42_v6.conf https://dn42.burble.com/roa/dn42_roa_bird2_6.conf
${pkgs.curl}/bin/curl -sfSLR {-o,-z}/etc/bird/roa_dn42.conf https://dn42.burble.com/roa/dn42_roa_bird2_4.conf
${pkgs.bird2}/bin/birdc c
${pkgs.bird2}/bin/birdc reload in all
'';
bgp = import peers/bgp.nix { };
in
{
systemd.timers.dn42-roa = {
description = "Trigger a ROA table update";
timerConfig = {
OnBootSec = "5m";
OnUnitInactiveSec = "1h";
Unit = "dn42-roa.service";
};
wantedBy = [ "timers.target" ];
before = [ "bird.service" ];
};
systemd.services = {
dn42-roa = {
after = [ "network.target" ];
description = "DN42 ROA Updated";
unitConfig = {
Type = "one-shot";
};
serviceConfig = {
ExecStart = "${script}/bin/update-roa";
};
};
};
services = {
bird-lg = {
proxy = {
enable = true;
allowedIPs = [ "172.20.4.97" "172.20.4.98" ];
};
frontend = {
enable = false;
servers = [ "fr-par" "fr-lyn" ];
domain = "node.tchekda.dn42";
};
};
bird2 = {
enable = true;
checkConfig = false;
config = builtins.readFile ./bird.conf + lib.concatStrings (builtins.map
(x: "
protocol bgp ${x.name} from dnpeers {
neighbor ${x.neigh} as ${x.as};
${if x.multi || x.v4 then "
ipv4 {
extended next hop on;
import where dn42_import_filter(${x.link},25,34);
export where dn42_export_filter(${x.link},25,34);
import keep filtered;
};
" else ""}
${if x.multi || x.v6 then "
ipv6 {
extended next hop on;
import where dn42_import_filter(${x.link},25,34);
export where dn42_export_filter(${x.link},25,34);
import keep filtered;
};
" else ""}
}
")
bgp.sessions) + bgp.extraConfig;
};
};
users.users.thehedgehog.extraGroups = [ "bird2" ];
}

View file

@ -0,0 +1,8 @@
{ tunnel, ospf, ... }:
let
defaultPubKey = "e6kp9sca4XIzncKa9GEQwyOnMjje299Xg9ZdgXWMwHg=";
defaultPrivKeyFile = "/run/agenix/dn42-privkey";
in
{
tunnel_name = tunnel 485 defaultPrivKeyFile "GbaMZ4f32JpaAnYuBZuUNqPFHDFgRkhqLOZUTVQYAHo" "{REMOTE_HOST:REMOTE_PORT}" "wg-dn42-lutoma" "172.20.43.96" "{TUNNEL_IPV6}";
}

View file

@ -0,0 +1,30 @@
{ config, pkgs, lib, ... }:
let
defaultLocalIPv4 = "172.20.43.96/32";
defaultLocalIPv6 = "fe80::1722:98/64";
in
{
environment.systemPackages = [ pkgs.wireguard-tools ];
networking.wireguard.interfaces = import tunnels.nix rec {
customTunnel = listenPort: privKeyFile: peerPubKey: endpoint: name: tunnelIPv4: tunnelIPv6: localIPv4: localIPv6: isOspf: {
listenPort = listenPort;
privateKey = privKeyFile;
allowedIPsAsRoutes = false;
peers = [
{
publicKey = publicKey;
allowedIPs = [ "0.0.0.0/0" "::/0" ];
endpoint = endpoint;
dynamicEndpointRefreshSeconds = 5;
}
];
postSetup = ''
${pkgs.iproute}/bin/ip addr add ${localIPv4} peer ${tunnelIPv4} dev ${name}
${pkgs.iproute}/bin/ip -6 addr add ${localIPv6} peer ${tunnelIPv6} dev ${name}
'' + lib.optionalString isOspf "${pkgs.iproute}/bin/ip -6 addr add ${defaultLocalIPv6} dev ${name}";
};
tunnel = listenPort: privateKey: publicKey: endpoint: name: tunnelIPv4: tunnelIPv6: customTunnel listenPort privateKey publicKey endpoint name tunnelIPv4 tunnelIPv6 defaultLocalIPv4 defaultLocalIPv6 false;
ospf = listenPort: privateKey: publicKey: endpoint: name: tunnelIPv4: tunnelIPv6: ULAIPv6: customTunnel listenPort privateKey publicKey endpoint name tunnelIPv4 tunnelIPv6 defaultLocalIPv4 ULAIPv6 true;
};
}