diff -ruN bird-2.15.1/README.aspa-asn-pairs bird-2.15.1-aspa-asn-pairs/README.aspa-asn-pairs --- bird-2.15.1/README.aspa-asn-pairs 1969-12-31 16:00:00.000000000 -0800 +++ bird-2.15.1-aspa-asn-pairs/README.aspa-asn-pairs 2024-12-17 21:14:23.000000000 -0800 @@ -0,0 +1,239 @@ + +This patch implements ASPA using tables of customer/provider ASN pairs. + +It is based off bird's original static ASPA implementation that can be found here: + +https://gitlab.nic.cz/labs/bird/-/tree/aspa + +The original ASPA code was written by Eugene Bogomazov. + +This patch adds support for customer_asn and provider_asn selection, RTR v2 support and updates draft-ietf-sidrops-aspa-verification. + +https://www.ietf.org/id/draft-ietf-sidrops-8210bis-16.html +https://datatracker.ietf.org/doc/draft-ietf-sidrops-aspa-verification/ + +Here is an example static ASPA table: + +$ cat bird-aspa.conf +aspa table at; + +protocol static +{ + aspa; + route aspa 970 54874; + route aspa 11358 835; + route aspa 11358 924; + route aspa 11358 6939; + route aspa 11358 20473; + route aspa 11358 34927; + route aspa 13852 6939; + route aspa 13852 20473; + route aspa 13852 34927; + route aspa 13852 52025; + route aspa 13852 209533; + route aspa 15562 2914; + route aspa 15562 8283; + route aspa 15562 51088; + route aspa 15562 206238; + route aspa 19330 393577; + route aspa 21957 970; +... + route aspa 401111 1012; + route aspa 401111 2497; + route aspa 401111 17676; +} + +--- + +The first AS number is the customer_asn. The second AS number is the provider_asn. + +Here is an example script that uses json dumps from rpki-client to generate a config file that can be included in your bird.conf: + +$ cat rpki-client-aspa-to-bird.pl +#!/usr/bin/perl + +use JSON; + +my $argc = $#ARGV+1; + +if ($argc < 2) { + die("not enough args"); +} + +my $filename_in = @ARGV[0]; +my $filename_out = @ARGV[1]; + +my $json_text = do { + open(my $json_fh, "<:encoding(UTF-8)", $filename_in) + or die("Can't open \"$filename_in\": $!\n"); + local $/; + <$json_fh> +}; + +open(my $bird_fh, ">:encoding(UTF-8)", $filename_out) + or die("Can't open \"$filename_out\": $!\n"); + +my $json = JSON->new; +my $data = $json->decode($json_text); + +my $customer; + +print $bird_fh "aspa table at;\n"; +print $bird_fh "\n"; +print $bird_fh "protocol static\n"; +print $bird_fh "{\n"; +print $bird_fh "\taspa;\n"; +for ( @{$data->{aspas}} ) { + $customer = $_->{customer_asid}; + for ( @{$_->{providers}} ) { + print $bird_fh "\troute aspa $customer $_;\n"; + } +} +print $bird_fh "}\n"; + +close($json_fh); +close($bird_fh); + +--- + +Here is a sample crontab script: + +$ cat update-bird-conf.sh +#!/bin/bash + +LOCKFILE="/home/rpki/bird/etc/.update-bird-conf.sh.lock" + +touch $LOCKFILE + +exec {FDLOCK}<>$LOCKFILE + +if ! flock -n -x $FDLOCK; then + exit 1 +fi + +trap "rm -f $LOCKFILE" EXIT + +RPKI_CLIENT_BIN="/home/rpki/rpki-client/sbin/rpki-client" +RPKI_CLIENT_JSON_DUMP="/home/rpki/rpki-client/var/db/rpki-client/json" +BIRD_ASPA_TABLE_NEW="/home/rpki/bird/etc/bird-aspa.conf.new" +BIRD_ASPA_TABLE="/home/rpki/bird/etc/bird-aspa.conf" +BIRD_CONV_SCRIPT="/home/rpki/rpki-client-aspa-to-bird.pl" +BIRDC_BIN="/home/rpki/bird/sbin/birdc" +MIN_ASPA_COUNT=250 + +TZ=Etc/UTC $RPKI_CLIENT_BIN -j + +$BIRD_CONV_SCRIPT $RPKI_CLIENT_JSON_DUMP $BIRD_ASPA_TABLE_NEW + +ASPA_COUNT=`grep route $BIRD_ASPA_TABLE_NEW | wc -l` + +if [ $ASPA_COUNT -le $MIN_ASPA_COUNT ]; then + rm -f $BIRD_ASPA_TABLE_NEW + exit 1 +fi + +mv $BIRD_ASPA_TABLE_NEW $BIRD_ASPA_TABLE + +$BIRDC_BIN 'configure' +$BIRDC_BIN 'reload "bgp4"' +$BIRDC_BIN 'reload "bgp6"' + +exit 0 + +--- + +Here is a function from bird.conf that can be called from a filter: + +include "bird-aspa.conf"; + +# AS12345 as transit + +function is_aspa_invalid (bgppath path) -> bool { + if (path.len > 0) then { + if (path.first ~ [ 12345 ]) then { + return aspa_check(at, path, BGP_DIR_DOWN) = ASPA_INVALID; + } else { + return aspa_check(at, path, BGP_DIR_UP) = ASPA_INVALID; + } + } else { + return false; + } +} + +--- + +This is what the table looks like: + +bird> show route table at +Table at: +aspa AS50555 AS970 [static1 2024-11-27] * (200) +aspa AS270470 AS53062 [static1 2024-11-27] * (200) +aspa AS47272 AS212895 [static1 2024-11-27] * (200) +aspa AS47272 AS212514 [static1 2024-11-27] * (200) +aspa AS47272 AS210667 [static1 2024-11-27] * (200) +aspa AS47272 AS58057 [static1 2024-11-27] * (200) +aspa AS47272 AS52210 [static1 2024-11-27] * (200) +aspa AS47272 AS52025 [static1 2024-11-27] * (200) +aspa AS47272 AS50917 [static1 2024-11-27] * (200) +... +aspa AS203843 AS53667 [static1 2024-11-27] * (200) +aspa AS203843 AS20473 [static1 2024-11-27] * (200) +aspa AS203843 AS6939 [static1 2024-11-27] * (200) +aspa AS216265 AS215051 [static1 2024-12-11] * (200) +aspa AS216265 AS202673 [static1 2024-12-11] * (200) +bird> + +--- + +Selecting multiple customer_asns: + +bird> show route table at where net.customer_asn ~ [ 11358, 28584, 54218 ] +Table at: +aspa AS54218 AS57196 [static1 2024-12-04] * (200) +aspa AS54218 AS35487 [static1 2024-12-02] * (200) +aspa AS54218 AS59678 [static1 2024-11-27] * (200) +aspa AS54218 AS53667 [static1 2024-11-27] * (200) +aspa AS54218 AS37988 [static1 2024-11-27] * (200) +aspa AS54218 AS16509 [static1 2024-11-27] * (200) +aspa AS54218 AS917 [static1 2024-11-27] * (200) +aspa AS11358 AS34927 [static1 2024-11-27] * (200) +aspa AS11358 AS20473 [static1 2024-11-27] * (200) +aspa AS11358 AS6939 [static1 2024-11-27] * (200) +aspa AS11358 AS924 [static1 2024-11-27] * (200) +aspa AS11358 AS835 [static1 2024-11-27] * (200) +aspa AS28584 AS28605 [static1 2024-11-27] * (200) +bird> + +--- + +Selecting a provider_asn: + +bird> show route table at where net.provider_asn = 16509 +Table at: +aspa AS216107 AS16509 [static1 2024-11-27] * (200) +aspa AS54218 AS16509 [static1 2024-11-27] * (200) +bird> + +--- + +Configuring RPKI for ASPA: + +protocol rpki rpki1 { + roa4 { table r4; }; + roa6 { table r6; }; + aspa { table at; }; + + remote 127.0.0.1; + port 3323; + + retry keep 90; + refresh keep 900; + expire keep 172800; + transport tcp; +} + + +--- +Ralph Covelli +Hurricane Electric / AS6939 +rcovelli@he.net diff -ruN bird-2.15.1/autogen.sh bird-2.15.1-aspa-asn-pairs/autogen.sh --- bird-2.15.1/autogen.sh 1969-12-31 16:00:00.000000000 -0800 +++ bird-2.15.1-aspa-asn-pairs/autogen.sh 2024-09-17 18:03:26.000000000 -0700 @@ -0,0 +1,88 @@ +#! /bin/sh + +TOP_DIR=$(dirname $0) + +if test ! -f $TOP_DIR/configure.ac ; then + echo "You must execute this script from the top level directory." + exit 1 +fi + +AUTOCONF=${AUTOCONF:-autoconf} +ACLOCAL=${ACLOCAL:-aclocal} +#AUTOMAKE=${AUTOMAKE:-automake} +AUTOHEADER=${AUTOHEADER:-autoheader} +LIBTOOLIZE=${LIBTOOLIZE:-libtoolize} +#SHTOOLIZE=${SHTOOLIZE:-shtoolize} + +dump_help_screen () +{ + echo "Usage: $0 [options]" + echo + echo "options:" + echo " -n skip CVS changelog creation" + echo " -h,--help show this help screen" + echo + exit 0 +} + +parse_options () +{ + while test "$1" != "" ; do + case $1 in + -h|--help) + dump_help_screen + ;; + -n) + SKIP_CVS_CHANGELOG=yes + ;; + *) + echo Invalid argument - $1 + dump_help_screen + ;; + esac + shift + done +} + +run_or_die () +{ + COMMAND=$1 + + # check for empty commands + if test -z "$COMMAND" ; then + echo "*warning* no command specified" + return 1 + fi + + shift; + + OPTIONS="$@" + + # print a message + echo -n "*info* running $COMMAND" + if test -n "$OPTIONS" ; then + echo " ($OPTIONS)" + else + echo + fi + + # run or die + $COMMAND $OPTIONS ; RESULT=$? + if test $RESULT -ne 0 ; then + echo "*error* $COMMAND failed. (exit code = $RESULT)" + exit 1 + fi + + return 0 +} + +parse_options "$@" + +echo "Building main autotools files." + +run_or_die $ACLOCAL -I m4 +run_or_die $LIBTOOLIZE --force --copy +run_or_die $AUTOHEADER +run_or_die $AUTOCONF +#run_or_die $AUTOMAKE --add-missing --copy +#run_or_die $SHTOOLIZE all diff -ruN bird-2.15.1/bird-gdb.py bird-2.15.1-aspa-asn-pairs/bird-gdb.py --- bird-2.15.1/bird-gdb.py 2023-10-07 04:59:53.000000000 -0700 +++ bird-2.15.1-aspa-asn-pairs/bird-gdb.py 2024-09-17 18:23:56.000000000 -0700 @@ -31,6 +31,8 @@ "T_ENUM_NETTYPE": "i", "T_ENUM_RA_PREFERENCE": "i", "T_ENUM_AF": "i", + "T_ENUM_ASPA": "i", + "T_ENUM_BGP_DIR": "i", "T_IP": "ip", "T_NET": "net", "T_STRING": "s", diff -ruN bird-2.15.1/conf/confbase.Y bird-2.15.1-aspa-asn-pairs/conf/confbase.Y --- bird-2.15.1/conf/confbase.Y 2024-03-10 13:42:50.000000000 -0700 +++ bird-2.15.1-aspa-asn-pairs/conf/confbase.Y 2024-09-26 20:14:21.000000000 -0700 @@ -118,7 +118,7 @@ %type