Compare commits

..

No commits in common. "f8d8ba844f1a9265752a0d20f519e14bd9c3ba5c" and "52b52aa53623d535689d71c033eeafc6a18ece26" have entirely different histories.

7 changed files with 8 additions and 164 deletions

View file

@ -16,8 +16,3 @@ jobs:
sudo apt-get install -y bird2
- name: Test skeleton.conf syntax
run: /usr/sbin/bird -c skeleton.conf -p
- name: Generate aspa_invalids.conf
run: ./make-bird-aspa aspa/example.json > aspa_invalids.conf
- name: Test skeleton-aspa.conf syntax
run: /usr/sbin/bird -c skeleton-aspa.conf -p

View file

@ -1,15 +0,0 @@
name: Run Python tests
on:
push:
pull_request:
jobs:
amd64:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python 3.11
uses: actions/setup-python@v3
with:
python-version: '3.11'
- name: Run Python unit tests
run: python -m unittest discover .

View file

@ -295,12 +295,11 @@ used by downstreams:
6. Create a cron job that runs `make-prefix-limits` followed by
`birdc configure`. Daily is a reasonable cadence.
## RPKI ROA filtering
## RPKI filtering
While this filter library implements RPKI Route Origin Authorization (ROA)
filtering, you still need to populate the `rpki4` and `rpki6` routing tables via
an `rpki` protocol in `bird`. Otherwise, all routes will be treated as RPKI
unknown. This can be configured as follows:
While this filter library implements RPKI, you still need to populate the
`rpki4` and `rpki6` routing tables via an `rpki` protocol in `bird`. Otherwise,
all routes will be treated as RPKI unknown. This can be configured as follows:
```
protocol rpki {
@ -319,89 +318,6 @@ This may be provided by something like Routinator, `rtrtr`, `gortr`, or
something similar. I recommend using `rtrtr` to pull a JSON feed from someone's
Routinator instance over HTTPS.
## ASPA filtering (experimental)
This filter library also offers an implementation of the [draft ASPA
standard][aspa] for `bird`. To use it, use the [`make-bird-aspa`][aspa-script]
script to generate the `is_aspa_invalid_pair` function on which
`filter_aspa.conf` depends. This requires the JSON output from Routinator (see
[`aspa/example.json`][aspa-example] for an example):
```console
$ ./make-bird-aspa aspa/example.json > aspa_invalids.conf
```
Then, apply the following patch to [`filter_bgp.conf`][filter]:
```diff
diff --git a/filter_bgp.conf b/filter_bgp.conf
index eb85db7..27a2162 100644
--- a/filter_bgp.conf
+++ b/filter_bgp.conf
@@ -107,6 +107,9 @@ define ASN_BOGON = [
4294967295 # RFC 7300 Last 32 bit ASN
];
+include "aspa_invalids.conf";
+include "filter_aspa.conf";
+
function ip_bogon() {
case net.type {
NET_IP4: return net ~ IPV4_BOGON;
@@ -208,6 +211,11 @@ function import_peer_trusted(int peer_asn) {
bgp_large_community.add((MY_ASN, LC_INFO, INFO_PEER));
bgp_large_community.add((MY_ASN, LC_PEER_ASN, peer_asn));
+ if is_aspa_invalid_peer(peer_asn) then {
+ print proto, ": ", net, ": invalid ASPA: ", bgp_path;
+ return false;
+ }
+
return import_safe(false);
}
@@ -232,6 +240,11 @@ function import_ixp_trusted(int ixp_id) {
bgp_large_community.add((MY_ASN, LC_INFO, INFO_IXP_RS));
bgp_large_community.add((MY_ASN, LC_IXP_ID, ixp_id));
+ if is_aspa_invalid_peer(bgp_path.first) then {
+ print proto, ": ", net, ": invalid ASPA: ", bgp_path;
+ return false;
+ }
+
return import_safe(false);
}
@@ -256,6 +269,11 @@ function import_transit(int transit_asn; bool default_route) {
bgp_large_community.add((MY_ASN, LC_INFO, INFO_TRANSIT));
bgp_large_community.add((MY_ASN, LC_PEER_ASN, transit_asn));
+ if is_aspa_invalid_upstream() then {
+ print proto, ": ", net, ": invalid ASPA: ", bgp_path;
+ return false;
+ }
+
return import_safe(default_route);
}
@@ -272,6 +290,11 @@ function import_downstream(int downstream_asn; prefix set prefixes; int set as_s
}
}
+ if is_aspa_invalid_customer() then {
+ print proto, ": ", net, ": invalid ASPA: ", bgp_path;
+ return false;
+ }
+
# If they don't want to export this to us, then we won't take it at all.
if (MY_ASN, LC_NO_EXPORT, MY_ASN) ~ bgp_large_community then {
print proto, ": ", net, ": rejected by no-export to AS", MY_ASN;
```
A [Python implementation][py-aspa-validate] of the validation function is also
available along with [a suite of tests][py-aspa-test]. This helps ensure the
version in the bird filter language is correct.
[pv]: https://pathvector.io/
[filter]: filter_bgp.conf
[skeleton]: skeleton.conf
@ -409,8 +325,3 @@ version in the bird filter language is correct.
[irr-script]: make-irr-filter
[prefix-conf]: prefix-limits.example
[prefix-script]: make-prefix-limits
[aspa]: https://datatracker.ietf.org/doc/draft-ietf-sidrops-aspa-verification/
[aspa-script]: make-bird-aspa
[aspa-example]: aspa/example.json
[py-aspa-validate]: aspa/validate.py
[py-aspa-test]: aspa/test.py

View file

@ -87,10 +87,10 @@ class BirdValidator(Validator):
if self.is_invalid_pair(asn, prev_asn) and max_up_ramp > i:
max_up_ramp = i
if self.is_invalid_pair(prev_asn, asn):
if self.is_invalid_pair(prev_asn, asn) and min_down_ramp < i:
min_down_ramp = i
prev_asn = asn
i = i + 1
i += 1
return min_down_ramp > max_up_ramp

View file

@ -34,7 +34,7 @@ function is_aspa_invalid_upstream() {
if is_aspa_invalid_pair(cur_asn, cur_asn) && max_up_ramp > i then
max_up_ramp = i;
if is_aspa_invalid_pair(prev_asn, cur_asn) then
if is_aspa_invalid_pair(prev_asn, cur_asn) && min_down_ramp < i then
min_down_ramp = i;
}

View file

@ -193,7 +193,7 @@ function import_safe(bool allow_default) {
}
if rpki_invalid() then {
print proto, ": ", net, ": invalid RPKI origin: ", bgp_path.last;
print proto, ": ", net, ": invalid RPKI";
return false;
}

View file

@ -1,47 +0,0 @@
log syslog all;
# FIXME: Change this to one of your router's IPv4 addresses.
# If you have none, pick something random from 240.0.0.0/4.
router id 192.0.2.1;
protocol kernel {
scan time 60;
ipv4 {
export where source != RTS_STATIC;
# NOTE: this basic export above doesn't make the routes inserted into
# the kernel prefer your own IPs. Things will work fine with your
# server's IP assigned by the provider if you have a single upstream
# but strange things will happen if you have more than one peer.
# Instead, to use your own IP as the default source IP for outgoing
# connections on your system, add an IP from your range to the `lo`
# interface, remove the line above, and use the block below, changing
# 192.0.2.1 to the IP used.
#
# export filter {
# if source = RTS_STATIC then reject;
# if source = RTS_BGP then krt_prefsrc = 192.0.2.1;
# accept;
# };
};
}
protocol kernel {
scan time 60;
ipv6 {
export where source != RTS_STATIC;
# NOTE: similar to above, use the following block to change the default
# source IP for outgoing connections.
# export filter {
# if source = RTS_STATIC then reject;
# if source = RTS_BGP then krt_prefsrc = 2001:db8::1;
# accept;
# };
};
}
protocol device {
scan time 60;
}
include "aspa_invalids.conf";
include "filter_aspa.conf";