mirror of
https://github.com/quantum5/bird-filter.git
synced 2025-04-24 09:01:57 -04:00
Compare commits
No commits in common. "f8d8ba844f1a9265752a0d20f519e14bd9c3ba5c" and "52b52aa53623d535689d71c033eeafc6a18ece26" have entirely different histories.
f8d8ba844f
...
52b52aa536
5
.github/workflows/bird.yml
vendored
5
.github/workflows/bird.yml
vendored
|
@ -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
|
||||
|
|
15
.github/workflows/python.yml
vendored
15
.github/workflows/python.yml
vendored
|
@ -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 .
|
97
README.md
97
README.md
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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";
|
Loading…
Reference in a new issue