mirror of
https://github.com/quantum5/bird-filter.git
synced 2025-04-24 00:51:57 -04:00
Initial commit
This commit is contained in:
commit
803c85906d
245
README.md
Normal file
245
README.md
Normal file
|
@ -0,0 +1,245 @@
|
|||
# Quantum's `bird` Filter Library
|
||||
|
||||
This is meant to be a starter repository containing sample `bird` 2.x config
|
||||
files that you can use to build your own BGP filters. Filters are provided as
|
||||
composable `bird` functions and enables you to harness the full power of the
|
||||
`bird` filter mini-programming language, as an alternative to a more declarative
|
||||
solution like [PathVector][pv].
|
||||
|
||||
## Quick start
|
||||
|
||||
1. Make sure `bird` 2.x is installed, e.g. on Debian or Ubuntu, through
|
||||
`sudo apt install bird2`.
|
||||
2. Clone this repository:
|
||||
```
|
||||
git clone https://github.com/quantum5/bird-filter.git
|
||||
cd bird-filter
|
||||
```
|
||||
3. Customize [`filter_bgp.conf`][filter] by editing it. Pay special attention
|
||||
to anything tagged `FIXME`.
|
||||
4. Install `filter_bgp.conf` into your `bird` configuration directory
|
||||
(`/etc/bird` by default):
|
||||
```
|
||||
sudo cp filter_bgp.conf /etc/bird
|
||||
```
|
||||
|
||||
## Defining BGP sessions
|
||||
|
||||
You can use [`skeleton.conf`][skeleton] as a basic `bird` starting config. Note
|
||||
that in this config, static protocol routes are internal to `bird` and will not
|
||||
be exported to the kernel routing table. You can change this by changing the
|
||||
export rules for `protocol kernel`.
|
||||
|
||||
This filter library makes use of two basic static protocols:
|
||||
* `node_v4`: IPv4 routes to be exported by the `export_cone` helper.
|
||||
* `node_v6`: IPv6 routes to be exported by the `export_cone` helper.
|
||||
|
||||
For example, to advertise `198.51.100.0/24` and `2001:db8:1000::/36`:
|
||||
|
||||
```
|
||||
protocol static node_v4 {
|
||||
ipv4 {};
|
||||
route 198.51.100.0/24 reject;
|
||||
}
|
||||
|
||||
protocol static node_v6 {
|
||||
ipv6 {};
|
||||
route 2001:db8:1000::/36 reject;
|
||||
}
|
||||
```
|
||||
|
||||
Two additional static protocols are used to aid with traffic engineering for
|
||||
anycast prefixes:
|
||||
* `node_v4_anycast`: IPv4 routes to be exported by the `export_anycast` helper.
|
||||
* `node_v6_anycast`: IPv6 routes to be exported by the `export_anycast` helper.
|
||||
|
||||
You can add `protocol` blocks to this config for each BGP neighbour. This is
|
||||
dependent on the neighbour type.
|
||||
|
||||
In the follow examples, we assume the following local preferences:
|
||||
* 50 for upstreams;
|
||||
* 90 for IXPs;
|
||||
* 100 for direct peers; and
|
||||
* 120 for downstreams.
|
||||
|
||||
### Upstreams
|
||||
|
||||
```
|
||||
protocol bgp example_upstream_v4 {
|
||||
description "Example Upstream (IPv4)";
|
||||
local 192.0.2.25 as 64500;
|
||||
neighbor 192.0.2.24 as 64501;
|
||||
default bgp_local_pref 50;
|
||||
|
||||
ipv4 {
|
||||
import keep filtered;
|
||||
import where import_transit(64501, false);
|
||||
export where export_cone(64501);
|
||||
};
|
||||
}
|
||||
|
||||
protocol bgp example_upstream_v6 {
|
||||
description "Example Upstream (IPv6)";
|
||||
local 2001:db8:2000::2 as 64500;
|
||||
neighbor 2001:db8:2000::1 as 64501;
|
||||
default bgp_local_pref 50;
|
||||
|
||||
ipv6 {
|
||||
import keep filtered;
|
||||
import where import_transit(64501, false);
|
||||
export where export_cone(64501);
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
The example above assumes you are AS64500 and establishes BGP sessions over
|
||||
both IPv4 and IPv6 with an upstream AS64501 and exports your entire cone. It
|
||||
also assumes your upstream is sending you a full table and filters out the
|
||||
default route. If you expect a default route instead, use
|
||||
`import where import_transit(64501, true)`.
|
||||
|
||||
To export your anycast as well, you can simply do
|
||||
`export where export_cone(64501) || export_anycast()`.
|
||||
|
||||
### Peers
|
||||
|
||||
```
|
||||
protocol bgp example_peer_v4 {
|
||||
description "Example Peer (IPv4)";
|
||||
local 192.0.2.25 as 64500;
|
||||
neighbor 192.0.2.28 as 64502;
|
||||
default bgp_local_pref 100;
|
||||
|
||||
ipv4 {
|
||||
import keep filtered;
|
||||
import where import_peer_trusted(64502);
|
||||
export where export_cone(64502);
|
||||
};
|
||||
}
|
||||
|
||||
protocol bgp example_peer_v6 {
|
||||
description "Example Peer (IPv6)";
|
||||
local 2001:db8:2000::2 as 64500;
|
||||
neighbor 2001:db8:2000::10 as 64502;
|
||||
default bgp_local_pref 100;
|
||||
|
||||
ipv6 {
|
||||
import keep filtered;
|
||||
import where import_peer_trusted(64502);
|
||||
export where export_cone(64502);
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
The example above assumes you are AS64500 and establishes BGP sessions over
|
||||
both IPv4 and IPv6 with a peer AS64502 and exports your entire cone. It assumes
|
||||
your peer is trusted and doesn't provide any IRR filtering. If you don't trust
|
||||
your peer, see the [IRR filtering](#irr-filtering) section below.
|
||||
|
||||
### IXP route servers
|
||||
|
||||
```
|
||||
protocol bgp example_ixp_v4 {
|
||||
description "Example IXP Route Servers (IPv4)";
|
||||
local 203.0.113.3 as 64500;
|
||||
neighbor 203.0.113.1 as 64503;
|
||||
default bgp_local_pref 90;
|
||||
|
||||
ipv4 {
|
||||
import keep filtered;
|
||||
import where import_ixp_trusted(64503);
|
||||
export where export_cone(64503);
|
||||
};
|
||||
}
|
||||
|
||||
protocol bgp example_ixp_v6 {
|
||||
description "Example IXP Route Servers (IPv6)";
|
||||
local 2001:db8:3000::3 as 64500;
|
||||
neighbor 2001:db8:3000::1 as 64503;
|
||||
default bgp_local_pref 90;
|
||||
|
||||
ipv6 {
|
||||
import keep filtered;
|
||||
import where import_ixp_trusted(64503);
|
||||
export where export_cone(64503);
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
The example above assumes you are AS64500 and establishes BGP sessions over
|
||||
both IPv4 and IPv6 with the IXP route server whose ASN is 64503 and exports
|
||||
your entire cone. It assumes your IXP is trusted and doesn't provide any IRR
|
||||
filtering. If you don't trust your IXP, see the [IRR filtering](#irr-filtering)
|
||||
section below.
|
||||
|
||||
### Downstreams
|
||||
|
||||
```
|
||||
protocol bgp example_downstream_v4 {
|
||||
description "Example Downstream (IPv4)";
|
||||
local 203.0.113.3 as 64500;
|
||||
neighbor 203.0.113.7 as 64504;
|
||||
default bgp_local_pref 120;
|
||||
|
||||
ipv4 {
|
||||
import keep filtered;
|
||||
import where import_downstream(64504, IRR_DOWNSTREAM_V4, IRR_DOWNSTREAM_ASN);
|
||||
export where export_to_downstream();
|
||||
};
|
||||
}
|
||||
|
||||
protocol bgp example_downstream_v6 {
|
||||
description "Example Downstream (IPv6)";
|
||||
local 2001:db8:3000::3 as 64500;
|
||||
neighbor 2001:db8:3000::7 as 64504;
|
||||
default bgp_local_pref 120;
|
||||
|
||||
ipv6 {
|
||||
import keep filtered;
|
||||
import where import_downstream(64504, IRR_DOWNSTREAM_V6, IRR_DOWNSTREAM_ASN);
|
||||
export where export_to_downstream();
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
The example above assumes you are AS64500 and establishes BGP sessions over
|
||||
both IPv4 and IPv6 with a downstream whose ASN is 64504 and exports all your
|
||||
routes. For your protection, downstream imports without IRR is *not* supported.
|
||||
For details about setting up IRR, see the [IRR filtering](#irr-filtering)
|
||||
section below.
|
||||
|
||||
## BGP communities
|
||||
|
||||
The following large informational communities are implemented by default:
|
||||
* `YOUR_ASN:1:x`: route received from IXP with ID x;
|
||||
* `YOUR_ASN:2:x`: route received from neighbour with ASN x;
|
||||
* `YOUR_ASN:3:100`: route received from peer;
|
||||
* `YOUR_ASN:3:101`: route received from IXP route server;
|
||||
* `YOUR_ASN:3:102`: route received from upstream; and
|
||||
* `YOUR_ASN:3:103`: route received from downstream.
|
||||
|
||||
The following large control communities are implemented by default and can be
|
||||
used by downstreams:
|
||||
* `YOUR_ASN:10:x`: do not export route to ASx;
|
||||
* `YOUR_ASN:11:x`: prepend `YOUR_ASN` once upon export to ASx;
|
||||
* `YOUR_ASN:12:x`: prepend `YOUR_ASN` twice upon export to ASx; and
|
||||
* `YOUR_ASN:12:x`: prepend `YOUR_ASN` thrice upon export to ASx.
|
||||
|
||||
## IRR filtering
|
||||
|
||||
1. Follow [`irr-filters.example`][irr-conf] and create `/etc/bird/irr-filters`
|
||||
for the peers you would like to filter. (To use alternative locations, edit
|
||||
[`make-irr-filter`][irr-script] accordingly.)
|
||||
2. Run `make-irr-filter` to re-generate IRR filters.
|
||||
3. Add `include "filter_irr.conf";` into your `bird.conf`.
|
||||
4. Instead of `import_peer_trusted(asn)` or `import_ixp_trusted(ixp_id)`, use
|
||||
`import_peer(asn, IRR_PEER_V4, IRR_PEER_ASN)` or
|
||||
`import_peer(asn, IRR_PEER_V6, IRR_PEER_ASN)`, and similarly for IXPs.
|
||||
5. Create a cron job that runs `make-irr-filter` followed by `birdc configure`.
|
||||
Daily is a reasonable cadence.
|
||||
|
||||
[pv]: https://pathvector.io/
|
||||
[filter]: filter_bgp.conf
|
||||
[skeleton]: skeleton.conf
|
||||
[irr-conf]: irr-filters.example
|
||||
[irr-script]: make-irr-filter
|
288
filter_bgp.conf
Normal file
288
filter_bgp.conf
Normal file
|
@ -0,0 +1,288 @@
|
|||
roa4 table rpki4;
|
||||
roa6 table rpki6;
|
||||
attribute int export_downstream;
|
||||
|
||||
protocol static default_v4 {
|
||||
ipv4 {};
|
||||
route 0.0.0.0/0 reject;
|
||||
}
|
||||
|
||||
protocol static default_v6 {
|
||||
ipv6 {};
|
||||
route ::/0 reject;
|
||||
}
|
||||
|
||||
# FIXME: Change this to your ASN.
|
||||
define MY_ASN = 64500;
|
||||
|
||||
define LC_IXP_ID = 1;
|
||||
define LC_PEER_ASN = 2;
|
||||
define LC_INFO = 3;
|
||||
|
||||
define LC_NO_EXPORT = 10;
|
||||
define LC_PREPEND_1 = 11;
|
||||
define LC_PREPEND_2 = 12;
|
||||
define LC_PREPEND_3 = 13;
|
||||
|
||||
define LC_DOWNSTREAM_START = 10;
|
||||
define LC_DOWNSTREAM_END = 13;
|
||||
|
||||
# FIXME: define your IXPs here:
|
||||
# define IXP_EXAMPLE1 = 100;
|
||||
# define IXP_EXAMPLE2 = 101;
|
||||
|
||||
define INFO_PEER = 100;
|
||||
define INFO_IXP_RS = 101;
|
||||
define INFO_TRANSIT = 102;
|
||||
define INFO_DOWNSTREAM = 103;
|
||||
|
||||
define IPV4_BOGON = [
|
||||
0.0.0.0/8+, # RFC 1122 'this' network
|
||||
10.0.0.0/8+, # RFC 1918 private space
|
||||
100.64.0.0/10+, # RFC 6598 Carrier grade nat space
|
||||
127.0.0.0/8+, # RFC 1122 localhost
|
||||
169.254.0.0/16+, # RFC 3927 link local
|
||||
172.16.0.0/12+, # RFC 1918 private space
|
||||
192.0.2.0/24+, # RFC 5737 TEST-NET-1
|
||||
192.88.99.0/24+, # RFC 7526 6to4 anycast relay
|
||||
192.168.0.0/16+, # RFC 1918 private space
|
||||
198.18.0.0/15+, # RFC 2544 benchmarking
|
||||
198.51.100.0/24+, # RFC 5737 TEST-NET-2
|
||||
203.0.113.0/24+, # RFC 5737 TEST-NET-3
|
||||
224.0.0.0/4+, # multicast
|
||||
240.0.0.0/4+ # reserved
|
||||
];
|
||||
|
||||
define IPV6_BOGON = [
|
||||
::/0, # Default
|
||||
::/96, # IPv4-compatible IPv6 address - deprecated by RFC4291
|
||||
::/128, # Unspecified address
|
||||
::1/128, # Local host loopback address
|
||||
::ffff:0.0.0.0/96+, # IPv4-mapped addresses
|
||||
::224.0.0.0/100+, # Compatible address (IPv4 format)
|
||||
::127.0.0.0/104+, # Compatible address (IPv4 format)
|
||||
::0.0.0.0/104+, # Compatible address (IPv4 format)
|
||||
::255.0.0.0/104+, # Compatible address (IPv4 format)
|
||||
0000::/8+, # Pool used for unspecified, loopback and embedded IPv4 addresses
|
||||
0100::/8+, # RFC 6666 - reserved for Discard-Only Address Block
|
||||
0200::/7+, # OSI NSAP-mapped prefix set (RFC4548) - deprecated by RFC4048
|
||||
0400::/6+, # RFC 4291 - Reserved by IETF
|
||||
0800::/5+, # RFC 4291 - Reserved by IETF
|
||||
1000::/4+, # RFC 4291 - Reserved by IETF
|
||||
2001:10::/28+, # RFC 4843 - Deprecated (previously ORCHID)
|
||||
2001:20::/28+, # RFC 7343 - ORCHIDv2
|
||||
2001:db8::/32+, # Reserved by IANA for special purposes and documentation
|
||||
2002:e000::/20+, # Invalid 6to4 packets (IPv4 multicast)
|
||||
2002:7f00::/24+, # Invalid 6to4 packets (IPv4 loopback)
|
||||
2002:0000::/24+, # Invalid 6to4 packets (IPv4 default)
|
||||
2002:ff00::/24+, # Invalid 6to4 packets
|
||||
2002:0a00::/24+, # Invalid 6to4 packets (IPv4 private 10.0.0.0/8 network)
|
||||
2002:ac10::/28+, # Invalid 6to4 packets (IPv4 private 172.16.0.0/12 network)
|
||||
2002:c0a8::/32+, # Invalid 6to4 packets (IPv4 private 192.168.0.0/16 network)
|
||||
3ffe::/16+, # Former 6bone, now decommissioned
|
||||
4000::/3+, # RFC 4291 - Reserved by IETF
|
||||
5f00::/8+, # RFC 5156 - used for the 6bone but was returned
|
||||
6000::/3+, # RFC 4291 - Reserved by IETF
|
||||
8000::/3+, # RFC 4291 - Reserved by IETF
|
||||
a000::/3+, # RFC 4291 - Reserved by IETF
|
||||
c000::/3+, # RFC 4291 - Reserved by IETF
|
||||
e000::/4+, # RFC 4291 - Reserved by IETF
|
||||
f000::/5+, # RFC 4291 - Reserved by IETF
|
||||
f800::/6+, # RFC 4291 - Reserved by IETF
|
||||
fc00::/7+, # Unicast Unique Local Addresses (ULA) - RFC 4193
|
||||
fe80::/10+, # Link-local Unicast
|
||||
fec0::/10+, # Site-local Unicast - deprecated by RFC 3879 (replaced by ULA)
|
||||
ff00::/8+ # Multicast
|
||||
];
|
||||
|
||||
define ASN_BOGON = [
|
||||
0, # RFC 7607
|
||||
23456, # RFC 4893 AS_TRANS
|
||||
64496..64511, # RFC 5398 and documentation/example ASNs
|
||||
64512..65534, # RFC 6996 Private ASNs
|
||||
65535, # RFC 7300 Last 16 bit ASN
|
||||
65536..65551, # RFC 5398 and documentation/example ASNs
|
||||
65552..131071, # RFC IANA reserved ASNs
|
||||
4200000000..4294967294, # RFC 6996 Private ASNs
|
||||
4294967295 # RFC 7300 Last 32 bit ASN
|
||||
];
|
||||
|
||||
function ip_bogon() {
|
||||
case net.type {
|
||||
NET_IP4: return net ~ IPV4_BOGON;
|
||||
NET_IP6: return net ~ IPV6_BOGON;
|
||||
else: return true;
|
||||
}
|
||||
}
|
||||
|
||||
function rpki_invalid() {
|
||||
case net.type {
|
||||
NET_IP4: return roa_check(rpki4, net, bgp_path.last) = ROA_INVALID;
|
||||
NET_IP6: return roa_check(rpki6, net, bgp_path.last) = ROA_INVALID;
|
||||
else: return false;
|
||||
}
|
||||
}
|
||||
|
||||
function is_default_route() {
|
||||
case net.type {
|
||||
NET_IP4: return net = 0.0.0.0/0;
|
||||
NET_IP6: return net = ::/0;
|
||||
else: return false;
|
||||
}
|
||||
}
|
||||
|
||||
function bad_prefix_len() {
|
||||
case net.type {
|
||||
NET_IP4: return net.len > 24;
|
||||
NET_IP6: return net.len > 48;
|
||||
else: return false;
|
||||
}
|
||||
}
|
||||
|
||||
function clean_own_communities() {
|
||||
bgp_large_community.delete([(MY_ASN, *, *)]);
|
||||
}
|
||||
|
||||
function honour_graceful_shutdown() {
|
||||
# RFC 8326: Graceful BGP Session Shutdown
|
||||
if (65535, 0) ~ bgp_community then bgp_local_pref = 0;
|
||||
}
|
||||
|
||||
function handle_prepend(int dest_asn) {
|
||||
if (MY_ASN, LC_PREPEND_1, dest_asn) ~ bgp_large_community then {
|
||||
bgp_path.prepend(MY_ASN);
|
||||
}
|
||||
|
||||
if (MY_ASN, LC_PREPEND_2, dest_asn) ~ bgp_large_community then {
|
||||
bgp_path.prepend(MY_ASN);
|
||||
bgp_path.prepend(MY_ASN);
|
||||
}
|
||||
|
||||
if (MY_ASN, LC_PREPEND_3, dest_asn) ~ bgp_large_community then {
|
||||
bgp_path.prepend(MY_ASN);
|
||||
bgp_path.prepend(MY_ASN);
|
||||
bgp_path.prepend(MY_ASN);
|
||||
}
|
||||
}
|
||||
|
||||
function import_safe(bool allow_default) {
|
||||
if is_default_route() then return allow_default;
|
||||
if ip_bogon() then return false;
|
||||
if bgp_path ~ ASN_BOGON then return false;
|
||||
if bgp_path.len > 50 then return false;
|
||||
if bad_prefix_len() then return false;
|
||||
if rpki_invalid() then return false;
|
||||
|
||||
export_downstream = 1;
|
||||
honour_graceful_shutdown();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function import_peer_trusted(int peer_asn) {
|
||||
clean_own_communities();
|
||||
bgp_large_community.add((MY_ASN, LC_INFO, INFO_PEER));
|
||||
bgp_large_community.add((MY_ASN, LC_PEER_ASN, peer_asn));
|
||||
|
||||
return import_safe(false);
|
||||
}
|
||||
|
||||
function import_peer(int peer_asn; prefix set prefixes; int set as_set) {
|
||||
if net !~ prefixes then return false;
|
||||
|
||||
for int path_asn in bgp_path do {
|
||||
if path_asn !~ as_set then return false;
|
||||
}
|
||||
|
||||
return import_peer_trusted(peer_asn);
|
||||
}
|
||||
|
||||
function import_ixp_trusted(int ixp_id) {
|
||||
clean_own_communities();
|
||||
bgp_large_community.add((MY_ASN, LC_INFO, INFO_IXP_RS));
|
||||
bgp_large_community.add((MY_ASN, LC_IXP_ID, ixp_id));
|
||||
|
||||
return import_safe(false);
|
||||
}
|
||||
|
||||
function import_ixp(int ixp_id; prefix set prefixes; int set as_set) {
|
||||
if net !~ prefixes then return false;
|
||||
|
||||
for int path_asn in bgp_path do {
|
||||
if path_asn !~ as_set then return false;
|
||||
}
|
||||
|
||||
return import_ixp_trusted(ixp_id);
|
||||
}
|
||||
|
||||
function import_transit(int transit_asn; bool default_route) {
|
||||
clean_own_communities();
|
||||
bgp_large_community.add((MY_ASN, LC_INFO, INFO_TRANSIT));
|
||||
bgp_large_community.add((MY_ASN, LC_PEER_ASN, transit_asn));
|
||||
|
||||
return import_safe(default_route);
|
||||
}
|
||||
|
||||
function import_downstream(int downstream_asn; prefix set prefixes; int set as_set) {
|
||||
if net !~ prefixes then return false;
|
||||
|
||||
for int path_asn in bgp_path do {
|
||||
if path_asn !~ as_set then return false;
|
||||
}
|
||||
|
||||
# If they don't want to export this to us, then we won't take it at all.
|
||||
if (QUANTUM_ASN, LC_NO_EXPORT, QUANTUM_ASN) ~ bgp_large_community then return false;
|
||||
|
||||
bgp_large_community.delete([
|
||||
(QUANTUM_ASN, 0..LC_DOWNSTREAM_START-1, *),
|
||||
(QUANTUM_ASN, LC_DOWNSTREAM_END+1..0xFFFFFFFF, *)
|
||||
]);
|
||||
|
||||
bgp_large_community.add((QUANTUM_ASN, LC_INFO, INFO_DOWNSTREAM));
|
||||
bgp_large_community.add((QUANTUM_ASN, LC_PEER_ASN, downstream_asn));
|
||||
|
||||
return import_safe(false);
|
||||
}
|
||||
|
||||
function export_to_downstream() {
|
||||
return (defined(export_downstream) && export_downstream = 1) ||
|
||||
(source = RTS_STATIC && !bad_prefix_len() && (
|
||||
proto = "node_v4" ||
|
||||
proto = "node_v6" ||
|
||||
proto = "node_v4_anycast" ||
|
||||
proto = "node_v6_anycast"
|
||||
));
|
||||
}
|
||||
|
||||
function export_monitoring() {
|
||||
return export_to_downstream();
|
||||
}
|
||||
|
||||
function export_cone(int dest_asn) {
|
||||
if (MY_ASN, LC_NO_EXPORT, dest_asn) ~ bgp_large_community then return false;
|
||||
handle_prepend(dest_asn);
|
||||
|
||||
if (MY_ASN, LC_INFO, INFO_DOWNSTREAM) ~ bgp_large_community then return true;
|
||||
|
||||
case net.type {
|
||||
NET_IP4: return source = RTS_STATIC && proto = "node_v4";
|
||||
NET_IP6: return source = RTS_STATIC && proto = "node_v6";
|
||||
else: return false;
|
||||
}
|
||||
}
|
||||
|
||||
function export_anycast() {
|
||||
case net.type {
|
||||
NET_IP4: return source = RTS_STATIC && proto = "node_v4_anycast";
|
||||
NET_IP6: return source = RTS_STATIC && proto = "node_v6_anycast";
|
||||
else: return false;
|
||||
}
|
||||
}
|
||||
|
||||
function export_default() {
|
||||
case net.type {
|
||||
NET_IP4: return source = RTS_STATIC && proto = "default_v4";
|
||||
NET_IP6: return source = RTS_STATIC && proto = "default_v6";
|
||||
else: return false;
|
||||
}
|
||||
}
|
12
irr-filters.example
Normal file
12
irr-filters.example
Normal file
|
@ -0,0 +1,12 @@
|
|||
# You can use # for comments.
|
||||
EXAMPLE AS-EXAMPLE
|
||||
EXAMPLE2 RIPE::AS64500:AS-EXAMPLE2 v4
|
||||
EXAMPLE3 ARIN::AS-EXAMPLE3 v6
|
||||
# This will cause make-irr-filter to generate a configuration file containing:
|
||||
# * IRR_EXAMPLE_V4: allowed IPv4 prefixes queried from AS-EXAMPLE.
|
||||
# * IRR_EXAMPLE_V6: allowed IPv6 prefixes queried from AS-EXAMPLE.
|
||||
# * IRR_EXAMPLE_ASN: allowed ASNs queried from AS-EXAMPLE.
|
||||
# * IRR_EXAMPLE2_V4: allowed IPv4 prefixes queried from AS64500:AS-EXAMPLE2 defined in the RIPE database.
|
||||
# * IRR_EXAMPLE2_ASN: allowed ASNs queried from RIPE::AS64500:AS-EXAMPLE2.
|
||||
# * IRR_EXAMPLE3_V6: allowed IPv6 prefixes queried from AS-EXAMPLE3 defined in the ARIN database.
|
||||
# * IRR_EXAMPLE3_ASN: allowed ASNs queried from ARIN::AS-EXAMPLE3.
|
28
make-irr-filter
Executable file
28
make-irr-filter
Executable file
|
@ -0,0 +1,28 @@
|
|||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
FILTER_SOURCE=/etc/bird/irr-filters
|
||||
FILTER_OUTPUT=/etc/bird/filter_irr.conf
|
||||
|
||||
tmpfile="$(mktemp /tmp/bird-filter.XXXXXX)"
|
||||
cleanup() {
|
||||
rm -f "$tmpfile"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
grep -v '^#' "$FILTER_SOURCE" | while IFS=$'\t ' read -r -a line; do
|
||||
name="${line[0]:-}"
|
||||
asset="${line[1]:-}"
|
||||
protocol="${line[2]:-}"
|
||||
if [ -z "$name" ] || [ -z "$asset" ]; then
|
||||
echo "Malformed line found" 1>&2
|
||||
continue
|
||||
fi
|
||||
|
||||
[ "$protocol" != v6 ] && bgpq4 -4Ab -m24 "$asset" -l "define IRR_${name}_V4"
|
||||
[ "$protocol" != v4 ] && bgpq4 -6Ab -m48 "$asset" -l "define IRR_${name}_V6"
|
||||
bgpq4 -tb "$asset" -l "define IRR_${name}_ASN"
|
||||
done > "$tmpfile"
|
||||
|
||||
mv "$tmpfile" "$FILTER_OUTPUT"
|
||||
chmod a+r "$FILTER_OUTPUT"
|
41
skeleton.conf
Normal file
41
skeleton.conf
Normal file
|
@ -0,0 +1,41 @@
|
|||
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;
|
||||
};
|
||||
}
|
||||
|
||||
protocol kernel {
|
||||
scan time 60;
|
||||
ipv6 {
|
||||
export where source != RTS_STATIC;
|
||||
};
|
||||
}
|
||||
|
||||
protocol device {
|
||||
scan time 60;
|
||||
}
|
||||
|
||||
include "filter_bgp.conf";
|
||||
|
||||
protocol static node_v4 {
|
||||
ipv4 {};
|
||||
}
|
||||
|
||||
protocol static node_v6 {
|
||||
ipv6 {};
|
||||
}
|
||||
|
||||
protocol static node_v4_anycast {
|
||||
ipv4 {};
|
||||
}
|
||||
|
||||
protocol static node_v6_anycast {
|
||||
ipv6 {};
|
||||
}
|
Loading…
Reference in a new issue