====== RPKI Hints, Top Tips, and FAQs ====== On this page I'm collecting how to do various RPKI bits and pieces. Usually because the supplied documentation is incomplete, or just plain useless. These are my build notes, and I keep them current in so far as I use them for the validators I maintain for the NSRC Global R&E Routing Table report and for RouteViews. YMMV. **NB**: always use the most up to date/current versions of the validators - things are moving pretty quickly, and the older versions can often be quite buggy, if not unstable. Here is the list (so far): * [[rpki#as0_tals|AS0 TALs]] * [[rpki#nlnetlabs_routinator|Routinator 3000]] validator from NLnetLabs * [[rpki#fort|FORT]] validator from NIC Mexico * [[rpki#rpki-client|RPKI-client]] validator * [[rpki#stayrtr|StayRTR]] * [[rpki#cisco_ios-xe_hints|Cisco IOS-XE]] * [[rpki#juniper_hints|Juniper]] * [[rpki#bird_hints|BIRD]] * [[rpki#frrouting_hints|FRR]] The tips and tricks for the validator builds discussed below all are for Ubuntu 22.04. They should also work just fine on Ubuntu 18.04 (which is supported until April 2023) and on Ubuntu 20.04 (which is supported until April 2025). ===== AS0 TALs ===== Two of the Regional Internet Registries have supplied Trust Anchor Locators (TALs) for unassigned IP address space that they hold. If you want to use these TALs, you can read more: * [[https://www.apnic.net/community/security/resource-certification/trust-anchor-locator/|APNIC's AS0 TAL]] * [[https://www.lacnic.net/4984/2/lacnic/rpki-rpki-trust-anchor|LACNIC's AS0 TAL]] Generally, to use these TALs, place each in a separate file (eg place APNIC's one in **apnic-as0.tal**) in the usual place where you keep your TALs - it depends on your validator of course. ===== NLnetLabs Routinator ===== Nothing to say here, the instructions just work, the validator installs sweetly, and just runs. As long as the instructions are followed. The current version of Routinator is 0.13.2, at time of writing. If using Debian/Ubuntu as I do, then just use the supplied package and your favourite package manager. Described in NLnetLabs's [[https://github.com/NLnetLabs/routinator#quick-start-with-debian-and-ubuntu-packages| Github]] repo. If the link to the supplied package is added to your package manager, for example **apt** on Ubuntu, then create an entry in **/etc/apt/sources.list.d** called **nlnetlabs.list** and put this in it (which is for Ubuntu 22.04): deb [arch=amd64] https://packages.nlnetlabs.nl/linux/ubuntu/ jammy main Then run: wget -qO- https://packages.nlnetlabs.nl/aptkey.asc | sudo tee /etc/apt/trusted.gpg.d/nlnetlabs.asc And then finally: apt-get update apt install routinator Easy! The installer will set up the necessary **systemd** file so that Routinator starts automatically on boot. Remember to modify the **/etc/routinator/routinator.config** file so that Routinator listens on the IPv4 (and IPv6) ports of the system - and you can enable the default statistics pages which listen on port 8323. A working configuration file would look like this: repository-dir = "/var/lib/routinator/rpki-cache" rtr-listen = ["x.x.x.x:3323", "[x:x:x:x::x]:3323"] http-listen = ["x.x.x.x:8323", "[x:x:x:x::x]:8323"] As from Routinator 0.12.0, the 5 RIR TALs are distributed built-in to the validator, so there is no longer any need to read and agree to the ARIN RPA. At time of writing, though, if you want to use the AS0 TALs from LACNIC and APNIC (see above), the "extra-tals-dir" option mentioned in the configuration guide only works on the command line and not in the Routinator configuration file that ships as part of the package. This means creating an user modification to the systemd setup **/etc/systemd/system/routinator.service** like this: [Service] ExecStart= ExecStart=/usr/bin/routinator --config=/etc/routinator/routinator.conf --extra-tals-dir="/var/lib/routinator/tals" --syslog server where the **/var/lib/routinator/tals** folder contains the two AS0 TALs you want to use. The first blank **ExecStart** is needed to overwrite the one that is shipped in **/lib/system/system/routinator.service**. Once this bug is fixed you can remove this user defined systemd setting and put the **extra-tals-dir** definition in the configuration file, like this: repository-dir = "/var/lib/routinator/rpki-cache" extra-tals-dir = "/var/lib/routinator/tals" rtr-listen = ["x.x.x.x:3323", "[x:x:x:x::x]:3323"] http-listen = ["x.x.x.x:8323", "[x:x:x:x::x]:8323"] ===== FORT ===== FORT is the validator developed by NIC Mexico. More about it is on the [[https://fortproject.net/en/validator|Project page]]. At time of writing, version 1.6.1 has been released and fixes many issues present in previous versions. FORT is available as part of Ubuntu 22.04 packaging, but it is an older version (1.5.3-1), so for this reason we use the latest NIC Mexico produced package. FORT is not quite so easy to install, but still relatively simple as long as you follow the instructions on their [[https://nicmx.github.io/FORT-validator/installation.html| Github]] repo closely. First step is to grab the **.deb** file from their archive: wget https://github.com/NICMx/FORT-validator/releases/download/1.6.1/fort_1.6.1-1_amd64.deb and then install it: sudo apt install ./fort_1.6.1-1_amd64.deb Note that the **apt install** installs a **systemd** file and starts FORT running automatically. FORT uses TCP/323 as the listener port - you may want to customise this, and to do that, edit the configuration file **/etc/fort/config.json**. This is the configuration file that I use: { "tal": "/etc/fort/tal", "local-repository": "/var/lib/fort", "slurm": "/etc/fort/slurm/", "server": { "port": "3323" }, "log": { "output": "syslog" } } All I have done is modify the port that the server listens on. The package ships with 4 of the 5 Trust Anchor Locators, so to get the missing one (ARIN's), you will need to run: sudo fort --init-tals --tal=/etc/fort/tal You will be asked to confirm that you have read the Terms and Conditions regarding ARIN's TAL: ... Jan 26 03:50:46 DBG: Done. Total bytes transferred: 466 Jan 26 03:50:46 DBG: HTTP result code: 200 Successfully fetched '/etc/fort/tal/apnic.tal'! Attention: ARIN requires you to agree to their Relying Party Agreement (RPA) before you can download and use their TAL. Please download and read https://www.arin.net/resources/manage/rpki/rpa.pdf If you agree to the terms, type 'yes' and hit Enter: yes Jan 26 03:50:51 DBG: HTTP GET: https://www.arin.net/resources/manage/rpki/arin.tal Jan 26 03:50:51 DBG: Done. Total bytes transferred: 487 Jan 26 03:50:51 DBG: HTTP result code: 200 Successfully fetched '/etc/fort/tal/arin.tal'! Jan 26 03:50:51 DBG: HTTP GET: https://www.lacnic.net/innovaportal/file/4983/1/lacnic.tal ... One thing that I found is that FORT crashes on start up following the above installation instructions to the letter. The issue is that the **/var/lib/fort** folder is owned by **root**, not by the **fort** user. Easy to fix: sudo chown fort:fort /var/lib/fort Then restart FORT: sudo systemctl restart fort and it should run successfully. You should see something like this when you run **systemctl status fort**: * fort.service - FORT RPKI validator Loaded: loaded (/lib/systemd/system/fort.service; enabled; vendor preset: enabled) Drop-In: /run/systemd/system/service.d └─zzz-lxc-service.conf Active: active (running) since Wed 2022-01-26 03:54:05 UTC; 4s ago Docs: man:fort(8) https://nicmx.github.io/FORT-validator/ Main PID: 3100 (fort) Tasks: 37 (limit: 28794) Memory: 12.0M CGroup: /system.slice/fort.service └─3100 /usr/bin/fort --configuration-file /etc/fort/config.json You can check by using **ps ax** to get: 195 ? Ssl 95:13 /usr/bin/fort --configuration-file /etc/fort/config.json and **netstat -an** (upto Ubuntu 18.04) or **ss -an** (on Ubuntu 20.04 onwards) to get: tcp LISTEN 0 128 0.0.0.0:3323 0.0.0.0:* The **systemd** that ships with FORT doesn't have a "restart on failure" setting so it is a good idea that we do this so that if/when FORT crashes, it will automatically restart. Create a new **/etc/systemd/system/fort.service** (which is where to create user-defined extras for **systemd** go), and in it put: [Service] Restart= Restart=on-failure (If you edit the **/lib/systemd/system/fort.service** it will be overwritten on the next upgrade of FORT, so it is best create the user entry instead.) And your new FORT installation is now ready for service! ===== RPKI-client ===== **rpki-client** is just a validator - it does not have the functionality to accept connections from a router. We'll come to that later on (we'll need to use [[rpki#stayrtr|StayRTR]], which is a fork of Cloudflare's now unmaintained GoRTR). **rpki-client** has now been packaged and is available as part of the Ubuntu 22.04 distribution. However, the packaged version is old (version 7.6). At the time of writing, the current release of **rpki-client** is version 8.7. So for this reason, and to stay up to date, at least on Ubuntu, we have to build it ourselves. A pity that the **rpki-client** maintainers don't build their own deb package, or pre-build packages like NLnetLabs do with Routinator. Oh well. ==== Initial Preparation ==== Before you attempt to download and build it, the **rpki-client** instructions note that you need a few other packages in place. These include **automake**, **autoconf**, **make**, **git** itself, **libtool** and **expat**. This is all quite easy using the Ubuntu package manager. sudo apt install automake autoconf make git libtool libexpat1-dev The other required package noted in the instructions is **tls** from LibreSSL. LibreSSL is a branch of OpenSSL and is used on OpenBSD - not found on Linux, but seems to be appearing in the latest Debian/Ubuntu beta builds. So we need to download the bits we need and install. The **rpki-client** instructions don't say anything about how to do that. First we go to [[https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/|https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/]] and select the latest package, which is libressl-3.8.3.tar.gz at time of writing (libressl-3.9.0 is also out now, but I'm staying away from .0 releases) wget https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-3.8.3.tar.gz We then unpack it: tar zxf libressl-3.8.3.tar.gz and then build it: cd libressl-3.8.3 ./configure --enable-libtls-only make sudo make install Note the option to only build **libtls** - we don't need the rest of LibreSSL and it could well interfere with OpenSSL which will already be on the system. Now that **libtls** is built, the **install** action will put the libraries in **/usr/local/lib** like this: -rw-r--r-- 1 root root 923 Mar 20 00:02 libtls.la lrwxrwxrwx 1 root root 16 Mar 20 00:02 libtls.so -> libtls.so.28.0.0 lrwxrwxrwx 1 root root 16 Mar 20 00:02 libtls.so.28 -> libtls.so.28.0.0 -rw-r--r-- 1 root root 9108376 Mar 20 00:02 libtls.so.28.0.0 Run **sudo ldconfig** so that the system knows about the new libraries. Next we need to get some packages that **rpki-client** needs. These are **libssl-dev**, **rsync** and **zlib1g-dev**. sudo apt install libssl-dev rsync zlib1g-dev And now we are ready to build **rpki-client**. ==== Building rpki-client ==== Easiest is just to install **rpki-client** from the [[https://github.com/rpki-client/rpki-client-portable| Github]] repository: git clone https://github.com/rpki-client/rpki-client-portable.git and then: cd rpki-client-portable ./autogen.sh ./configure --with-tal-dir=/etc/rpki \ --with-base-dir=/var/lib/rpki-client \ --with-output-dir=/var/db/rpki-client make The **autogen.sh** script fixes the config set up, ready to run **configure** which will produce the **Makefile**. Note that we are specifying where our TALs go, where the temporary files go (following Ubuntu norms), and where the output file storing the VRPs goes (again following Ubuntu norms). Hidden in the official instructions is a comment that **rpki-client** runs as a normal user if started as root. So we need to create that normal user: sudo groupadd _rpki-client sudo useradd –g _rpki-client –s /sbin/nologin –d /nonexistent –c "rpki-client user" _rpki-client Now we can install RPKI-client: sudo make install which will install the client in **/usr/local/sbin** and the 4 TALs in **/etc/rpki**, as well as create the cache and output directories needed. Note that the ARIN TAL requires users to read the disclaimer first so is not provided by default. So you need to do this manually: wget https://www.arin.net/resources/manage/rpki/arin.tal sudo mv arin.tal /etc/rpki Now the client can be run. There is no daemon option, it simply runs at the command line, and when it has finished downloading all the VRPs (around 10-15 minutes depending on bandwidth) it exits. But that's okay. Try running the client: sudo /usr/local/sbin/rpki-client You'll see errors about various CAs or files not being accessible - that's their problem, not yours. If you check in the **/var/db/rpki-client** folder you will see an **openbgpd** file once the above run of **rpki-client** completes. This is the configuration you'd need if you run **openbgp**. However, we are going to run a standalone RtR client instead, so we will need JSON output instead. Once **rpki-client** completes, we can now set it up to run automatically. To do this, we create a file in **/etc/cron.hourly** called **rpki-client**, and in it we put: #!/bin/bash # run RPKI-client every hour # - default output location is /var/db/rpki-client # - -j option means json output, suitable for stayrtr /usr/local/sbin/rpki-client -j > /tmp/rpki-client.log 2>&1 and that's it. Every hour, cron will run **rpki-client** which will produce JSON output of all the VRPs it has collected. As noted above, JSON output is what is used by StayRTR and GoRTR as their input sources. Make sure that the **/etc/cron.hourly/rpki-client** is executable, otherwise it will not run. It's a good idea to check the log file in case **rpki-client** reports issues trying to write local files etc. But mostly what you'll see there are all the transactions with the various CAs, and the problems encountered (there will be lots, unfortunately). ===== StayRTR ===== StayRTR is a hard fork of GoRTR (which is no longer maintained by Cloudflare and is badly out of date). For this reason, I **strongly** recommend you use StayRTR rather than GoRTR. If you have an existing GoRTR install, simply replace it with StayRTR. StayRTR has now been packaged and is available as part of the Ubuntu 22.04 distribution. However, the packaged version is old (version 0.3.0). At the time of writing, the current release of StayRTR is version 0.5.1(47). I'm not going to upgrade a production system to interim Ubuntu releases just to get a slightly newer (and still out of date) version of StayRTR. So for this reason, and to stay up to date, at least on Ubuntu, we have to build it ourselves. A pity that the **StayRTR** maintainers don't build their own deb package, or pre-build packages like NLnetLabs do with Routinator. ==== Installing Go ==== First you will need a working Go environment. Full instructions are at [[https://go.dev/doc/install|https://go.dev/doc/install]], and I've reproduced the key pieces here to make it easy for installers. First off, download the latest Go package (1.22.1 at time of writing): wget https://go.dev/dl/go1.22.1.linux-amd64.tar.gz If you have an existing Go environment, perhaps save it in case something goes wrong with the new version: sudo mv /usr/local/go /usr/local/go.old and then you can unpack the new version: cd /usr/local sudo chmod 777 . tar xzf ~/go1.22.1.linux-amd64.tar.gz sudo chmod 755 . Next add **/usr/local/go/bin** to the **PATH** environment variable. If you use **bash**, this would be in the **.profile** in your home directory, and just add: if [ -d "/usr/local/go/bin" ] ; then PATH="$PATH:/usr/local/go/bin" fi Log off. And then log in again. (Easiest way of activating the updated **PATH**.) And now check you have a working Go environment: go version If the version shows what you installed, you are set! ==== Building StayRTR ==== Easiest way to install StayRTR is build from the [[https://github.com/bgp/stayrtr|Github repo]]. git clone https://github.com/bgp/stayrtr.git cd stayrtr make build-all which builds **stayrtr** as well as **rtrmon** and **rtrdump** (the latter used for testing purposes). Copy the resulting binaries to **/usr/local/bin**: cd dist sudo cp -p stayrtr-v0.5.1-47-gfebec67-linux-x86_64 /usr/local/bin/stayrtr sudo cp -p rtrdump-v0.5.1-47-gfebec67-linux-x86_64 /usr/local/bin/rtrdump sudo cp -p rtrmon-v0.5.1-47-gfebec67-linux-x86_64 /usr/local/bin/rtrmon StayRTR has lots of options, but the ones we need are these: -bind string Bind address (default ":8282") -cache string URL of the cached JSON data (default "https://console.rpki-client.org/vrps.json") We don't need to use the public RPKI-client JSON source, given we have our own from the newly created RPKI-client. We run StayRTR like this: /usr/local/bin/stayrtr -bind :3323 -cache /var/db/rpki-client/json which will at least let us test that it works. Run it and see what happens - you should see output at the command line looking like this: INFO[0000] new cache file: Updating sha256 hash -> e0a14ea955e183e2719dcfbee0e9429b34581972c6ad5f6e9e064ee1396caf60 INFO[0001] New update (307007 uniques, 307007 total prefixes). INFO[0002] Updated added, new serial 0 INFO[0002] StayRTR Server started (sessionID:60037, refresh:3600, retry:600, expire:7200) And if you check the ports that are listening (**ss -an**) you will see: tcp LISTEN 0 128 *:9847 *:* tcp LISTEN 0 128 *:3323 *:* Port 3323 is the listening port for Router connections. And Port 9847 is the metrics port, for monitoring systems to connect to. But perhaps this isn't good for long term operations as you'd prefer to have this start running automatically when the system starts. And for that we'd need to set up a suitable **systemd** entry. First off, let's create a user for StayRTR (it does not have to run as root): sudo groupadd _stayrtr sudo useradd –g _stayrtr –s /sbin/nologin –d /nonexistent –c "StayRTR user" _stayrtr Next we create a file **/etc/default/stayrtr** with the following contents: # Settings for StayRTR. Consult https://github.com/bgp/stayrtr for # more discussion and other available options STAYRTR_ARGS=-bind :3323 -cache /var/db/rpki-client/json # Then we go to the **/lib/systemd/system/** folder and create the **systemd** entry - call it **stayrtr.service**. Here is a simple one that should work: [Unit] Description=StayRTR RPKI to Router Server Documentation=https://github.com/bgp/stayrtr After=network.target [Service] EnvironmentFile=/etc/default/stayrtr ExecStart=/usr/local/bin/stayrtr $STAYRTR_ARGS Type=exec User=_stayrtr Group=_stayrtr AmbientCapabilities=CAP_NET_BIND_SERVICE CapabilityBoundingSet=CAP_NET_BIND_SERVICE [Install] WantedBy=multi-user.target We then need to enable it: sudo systemctl enable stayrtr which then displays: Created symlink /etc/systemd/system/multi-user.target.wants/stayrtr.service → /lib/systemd/system/stayrtr.service. and then we can run StayRTR, like this: sudo systemctl start stayrtr Once it is running, check that it is working by running: sudo systemctl status stayrtr and you should see something like this: * stayrtr.service - StayRTR RPKI to Router Server Loaded: loaded (/lib/systemd/system/stayrtr.service; enabled; vendor preset: ena Active: active (running) since Fri 2022-01-28 15:50:27 AEST; 25s ago Docs: https://github.com/bgp/stayrtr Main PID: 17390 (stayrtr) Tasks: 11 (limit: 4915) Memory: 241.8M CGroup: /system.slice/stayrtr.service └─17390 /usr/local/bin/stayrtr -bind :3323 -cache /var/db/rpki-client/js Jan 28 15:50:27 stayrtr systemd[1]: Starting StayRTR RPKI to Router Server... Jan 28 15:50:27 stayrtr systemd[1]: Started StayRTR RPKI to Router Server. Jan 28 15:50:27 stayrtr stayrtr[17390]: time="2022-01-28T15:50:27+10:00" level=info m Jan 28 15:50:28 stayrtr stayrtr[17390]: time="2022-01-28T15:50:28+10:00" level=info m Jan 28 15:50:29 stayrtr stayrtr[17390]: time="2022-01-28T15:50:29+10:00" level=info m Jan 28 15:50:29 stayrtr stayrtr[17390]: time="2022-01-28T15:50:29+10:00" level=info m and you can also run the more traditional **ps ax** to see something like: 17390 ? Ssl 0:04 /usr/local/bin/stayrtr -bind :3323 -cache /var/db/rpki-client/json And that's it. Enjoy your new StayRTR installation. ===== Cisco IOS-XE Hints ===== This section shows the basic configuration needed to get route origin validation up and running on a Cisco IOS-XE platform. (Cisco IOS-XR is not covered here and will likely be different.) Most commentary is for IOS-XE 16.x onwards. IOS 15.5S (and IOS-XE equivalent) will also likely work with the following examples, but their RPKI implementation is somewhat old and buggy. ==== Configuration with Validator ==== Setting up a Cisco router to talk with a validator is simple: router bgp bgp rpki server tcp port refresh 3600 where is the IP address (IPv4 or IPv6) of the validator, is the TCP port the validator listens on, and 3600 is the RFC8210 recommended refresh interval (the period which the router will use to ask the validator if there is new/updated validation information available). To find out what is in the validation database (IPv4 and IPv6 commands shown): show ip bgp rpki table show bgp ipv6 rpki table and to find out the status of the connection to the validator: show ip bgp rpki servers ==== Caveats ==== Cisco IOS-XE has many defaults which are non-standard and will be potentially frustrating for operators: * Automatically activates route origin validation (cannot be turned off!) * Automatically drops invalids (can be turned off!) * Locally originated prefixes are always marked as valid (cannot be turned off!) - fixed in most recent IOS-XE 17.x releases * Automatically prefers Valid path over Invalid/NotFound, even if latter has higher local-preference (BGP Best Path Selection over-ride) (cannot be turned off!) - only relevant if propagating validation information in IBGP (not recommended) * If validator disappears, router validation database is flushed within a few minutes - fixed in most recent IOS-XE 16.x releases To turn off the automatic dropping of invalids: router bgp bgp bestpath prefix-validate allow-invalid To propagate the validation state in IBGP, both BGP speakers need: neighbor x.x.x.x announce rpki state Please do **NOT** do this, as there are operational consequences, especially if validators become unreachable (specifically that IOS-XE has added an undocumented feature in the path selection process whereby a prefix marked as //valid// from one IBGP neighbour is preferred over //invalid/////notfound// from another IBGP neighbour regardless of //local-preference// setting). **Summary:** Cisco has tried to make it easy to deploy ROV, but unfortunately this "assistance" ignores standards and best practices. Any implementation must never take control away from the operator about what they can and cannot do, especially if there is no way of turning off mis-features. ==== Implementing Route Origin Validation ==== The final step in Cisco IOS-XE is to implement Route Origin Validation. This is achieved simply by turning off the knob we noted above that automatically drops //invalid// prefixes. router bgp no bgp bestpath prefix-validate allow-invalid ===== Juniper Hints ===== This section shows the basic configuration needed to get route origin validation up and running on a JunOS platform. JunOS follows standards, as far as I can tell. All policy has to be explicitly configured by the operator. ==== Configuration with Validator ==== The configuration needed for JunOS to talk with two validators looks like this: routing-options { validation { group ISP { /* validatorA */ session { refresh-time 600; hold-time 3600; preference 1; port ; local-address ; } /* validatorB */ session { refresh-time 600; hold-time 3600; preference 2; port ; local-address ; } } } } where is the IP address (IPv4 or IPv6) of the validator, is the TCP port the validator listens on, and 3600 is the RFC8210 recommended refresh interval (the period which the router will use to ask the validator if there is new/updated validation information available). Two validators are recommended - if you only have one, then edit the above to suit. This simply creates a validation database on the router - it does not touch the BGP RIB. To find out what is in the validation database: show validation replication database and to find out the status of the connection to the validator: show validation session detail ==== Flagging validation status in BGP RIB ==== To indicate validation status in the BGP RIB, the operator needs to implement a policy statement to do that. Here is an example: policy-options { policy-statement RPKI-validation { term VALID { from { protocol bgp; validation-database valid; } then { validation-state valid; next policy; } } term INVALID { from { protocol bgp; validation-database invalid; } then { validation-state invalid; next policy; } } term UNKNOWN { from { protocol bgp; validation-database unknown; } then { validation-state unknown; next policy; } } } } protocols { bgp { group EBGP { type external; local-address ; neighbor { description "Upstream"; import [ RPKI-validation Upstream-in ]; export LocalAS-out; peer-as ; } } } } This is intended to be used as an **inbound** policy on an EBGP peer. The //validation-database// configuration refers to the database created by the router's session with the validator. The //validation-state// configuration enters a flag in the BGP RIB to indicate the validation state of the prefix. Note that the //Upstream-in// policy is other inbound policy that is on the router, and not documented here. And then the operator can do things like: show route protocol bgp validation-state valid to show the **valid** prefixes as in this example. Other options are available for **invalid** and **notfound**. ==== Implementing Route Origin Validation ==== The final step in JunOS is to implement Route Origin Validation. This is can be simply achieved by replacing the: next policy line in the INVALID term with: reject This will discard invalid prefixes as they arrive on an EBGP speaking router. If you want to find out what has been dropped, you can run: show route protocol bgp validation invalid hidden The discarded prefixes are still in Adj-RIB-In and can be seen with the **hidden** keyword option. ===== BIRD Hints ===== This section shows the basic configuration needed to get route origin validation up and running on a [[https://bird.network.cz/|BIRD]] platform. This will be of most interest to IXPs, as BIRD is the mostly widely used Route Server implementation today. The configuration here is for BIRDv2 (2.14 at time of writing). ==== Configuration with Validator ==== The configuration needed for BIRD to talk with a validator is: roa4 table r4; roa6 table r6; protocol rpki validator1 { roa4 { table rpki4; }; roa6 { table rpki6; }; remote port ; retry keep 600; refresh keep 3600; expire keep 7200; } protocol rpki validator2 { roa4 { table rpki4; }; roa6 { table rpki6; }; remote port ; retry keep 600; refresh keep 3600; expire keep 7200; } where is the IP address (IPv4 or IPv6) of the validator, is the TCP port the validator listens on, and 3600 is the RFC8210 recommended refresh interval (the period which the router will use to ask the validator if there is new/updated validation information available). Two validators are shown in this example. This simply creates a validation database in BIRD - it does not touch the BGP RIB. To find out what is in the validation database (IPv4 and IPv6 shown): show route table rpki4 show route table rpki6 and to find out the status of the connection to //validator1//: show protocols validator1 ==== Implementing Route Origin Validation ==== The final step in BIRD is to implement Route Origin Validation. This needs a policy statement, to be applied as //outbound// policy on all BGP sessions (internal and external). We build those up using BIRD functions, like below (as used on route-server implementations of BIRD). # v4 function to check if prefix valid function is_v4_rpki_invalid () { return roa_check(rpki4, net, bgp_path.last_nonaggregated) = ROA_INVALID; } # v6 function to check if prefix valid function is_v6_rpki_invalid () { return roa_check(rpki6, net, bgp_path.last_nonaggregated) = ROA_INVALID; } # return true if invalid, false if not function prefix_is_invalid() { if net.type = NET_IP4 then if is_v4_rpki_invalid() then return true; if net.type = NET_IP6 then if is_v6_rpki_invalid() then return true; return false; } And then the //prefix_is_valid// function will be called as part of a larger outbound policy function, for example: filter EXPORT { if (prefix_is_bogon()) then reject "[Rejected Prefix: Bogon] ", net; if (prefix_is_invalid()) then reject "[Rejected Prefix: Invalid] ", net; if (as_path_contains_bogons()) then reject "[Rejected Prefix: Bogon AS] ", net; if (bgp_path.len > 32) then reject "[Rejected Prefix: Long AS] ", net; if (bgp_path.len < 1) then reject "[Rejected Prefix: No AS] ", net; accept "[Exported Prefix] ", net; } ===== FRrouting Hints ===== This section shows the basic configuration needed to get route origin validation up and running on implementations using FRrouting (FRR). The commentary below assumes FRR 8.2.2. Older versions of FRR (8.1 and 7.5) have slightly different CLI and may not have all the features shown here. ==== Configuration with Validator ==== The configuration needed for FRR to talk with a validator is: rpki rpki polling_period 3600 rpki cache preference 1 rpki cache preference 2 exit Two validators are configured in this example, the preferred one has preference 1. The backup validator (used when the primary has become unreachable) is preference 2. More can be added following this principle. FRR automatically populates the BGP RIB with validation status of each prefix. No operator intervention is needed. To find out what is in the validation database: show rpki prefix-table and to find out the status of the connection to the active validator: show rpki cache-connection To show the BGP RIB with the validation information now flagged, just use the standard: show bgp command set. To show prefixes that meet any of the validation states: show bgp rpki valid will show all the entries that are //valid//. There is also a command option for //invalid// and //notfound//. ==== Implementing Route Origin Validation ==== The final step in FRR is to implement Route Origin Validation. This needs a policy statement, to be applied as //outbound// policy on all BGP sessions (internal and external). The following example shows a route-map exporting IPv4 routes. Similar can be done for IPv6. route-map EXPORT deny 5 description Don't send RPKI Invalids match rpki invalid exit ! route-map EXPORT deny 15 description Drop the IPv4 bogons match ip address prefix-list v4bogon exit ! route-map EXPORT permit 20 description Everything else is good exit ! [[start| Back to Home page]]