Usage of the RTRlib C Library¶
The RTRlib is supported by most Linux distributions as well as Apple macOS. Before you start using or developing with the RTRlib C library, you have to prepare your OS environment by installing a recent release package.
Installation¶
To install or build the RTRlib from source follow the steps described here.
Archlinux¶
For Archlinux we maintain two PKGBUILDs in the Archlinux User Repository, rtrlib [1] and rtrlib-git [2]. The former is for the latest official release and the latter for current git master. You can either use your favourite aur helper or execute the following commands:
sudo pacman --needed base-devel
# for the latest release
wget https://aur.archlinux.org/cgit/aur.git/snapshot/rtrlib.tar.gz
tar xf rtrlib
cd rtrlib
# for the git version
wget https://aur.archlinux.org/cgit/aur.git/snapshot/rtrlib-git.tar.gz
tar xf rtrlib-git
cd rtrlib-git
# for both
makepkg -sci
Footnotes
[1] | https://aur.archlinux.org/packages/rtrlib/ |
[2] | https://aur.archlinux.org/packages/rtrlib-git/ |
Apple macOS¶
For macOS we provide a Homebrew tap to easily install the RTRlib. First, setup Homebrew [3] and afterwards install the RTRlib package:
brew tap rtrlib/pils
brew install rtrlib
Footnotes
[3] | Homebrew – http://brew.sh |
Gentoo¶
The kind guys from the FRRouting project maintain a gentoo overlay [4] that contains an ebuild for the RTRlib. First, setup layman [5], then install rtrlib with the following commands:
# If this doe not work try layman -f
layman -a frr-gentoo
emerge rtrlib
Footnotes
[4] | https://github.com/FRRouting/gentoo-overlay |
[5] | https://wiki.gentoo.org/wiki/Layman |
Debian¶
Debian contains RTRlib since Buster [6] and can be installed with apt.
The package is called librtr0
, developers will require the librtr-dev
package, too.
apt install librtr0 librtr-dev
Debugging Symbols(librtr0-dbgsym
) and offline documentation (librtr-doc
) are also available.
Footnotes
[6] | Buster is currently in testing and scheduled for release Mid 2019 |
From Source¶
On any other Linux OS you will have to build and install the RTRlib from source. The following minimal requirements have to be met, before building the library:
- the build system is based on cmake, version >= 2.6
- libssh, to establish SSH transport connections, version >= 0.5.0
Optional requirements are:
- cmocka, a framework to run RTRlib unit tests
- doxygen, to build the RTRlib API documentation
If the requirements are fulfilled in the system, the library and tools can be build. First, either download or clone the RTRlib source code as follows:
wget https://github.com/rtrlib/rtrlib/archive/v0.3.6.tar.gz
tar xzf v0.3.6.tar.gz
cd rtrlib-0.3.6
# or
git clone https://github.com/rtrlib/rtrlib/
cd rtrlib
The contents of the RTRlib source code has the following subdirectory structure:
cmake/
CMake modulesdoxygen/
Example code and graphics used in the Doxygen documentationrtrlib/
Header and source code files of the RTRlibtests/
Function tests and unit teststools/
Containsrtrclient
andcli-validator
Afterwards, the library can be build (we recommend an out-of-source build) using cmake:
mkdir build && cd build
cmake -DCMAKE_BUILD_TYPE=Release ../
make
sudo make install
If the build command fails with any error, please consult the RTRlib README [7] and Wiki [8], you may also join our mailing list [9] or open an issue on Github [10].
To enable debug symbols and messages, change the cmake command to:
cmake -D CMAKE_BUILD_TYPE=Debug ../
For developers we provide a pre-build Doxygen API reference online [11] for the latest release of the RTRlib. Alternatively, and if Doxygen is available on your system, you can build the documentation locally as follows:
make doc
Further, you can also run the build-in tests provided by the RTRlib package via make:
make test
Footnotes
[7] | README – https://github.com/rtrlib/rtrlib/blob/master/README |
[8] | Wiki – https://github.com/rtrlib/rtrlib/wiki |
[9] | Mailing list – https://groups.google.com/forum/#!forum/rtrlib |
[10] | Issue tracker – https://github.com/rtrlib/rtrlib/issues |
[11] | API reference – https://rtrlib.realmv6.org/doxygen/latest |
Development with RTRlib¶
The RTRlib shared library is installed to /usr/local/lib
by default,
and its headers files to /usr/local/include
, respectively.
To write an application in C/C++ using the RTRlib, include the main header file
into the code:
#include "rtrlib/rtrlib.h"
The name of the corresponding shared library is rtr. To link an application against the RTRlib, pass the following parameter to the compiler:
-lrtr
If the linker reports an error such as cannot find -lrtr
, probably the
RTRlib was not installed to a standard location.
In this case, pass its location as an absolute path to the compiler,
add parameter:
-L</path/to/librtr/>
On Linux you can alternatively try to update the linker cache instead, run:
ldconfig
# verify with
ldconfig -p | grep rtr
Step-by-Step Example¶
The RTRlib package includes two command line tools, the rtrclient
and
the cli-validator
, see also Tools based on the RTRlib.
The former connects to a single RTR cache server via TCP or SSH and prints
validated prefix origin data to STDOUT. You can use this tool to get first
experiences with the RPKI-RTR protocol. With the latter you can validate
arbitrary prefix origin AS relations against records received from a connected
RPKI cache. Both tools are located in the tools/
directory. Having a look
into the source code of these tools will help to understand and integrate the
RTRlib into applications.
Any application using the RTRlib will have to setup a RTR connection manager that handles synchronization with one (or multiple) trusted RPKI cache server(s). The following provides an overview on important code segments.
First, create a RTR transport socket, for instance using TCP as shown in Listing 1.
1 2 3 4 5 6 7 8 9 10 11 12 13 | struct tr_socket tr_tcp;
struct rtr_socket rtr_tcp;
char tcp_host[] = "rpki-validator.realmv6.org";
char tcp_port[] = "8282";
struct tr_tcp_config tcp_config = {
tcp_host, // cache server host
tcp_port, // cache server port
NULL // source address, empty
};
tr_tcp_init(&tcp_config, &tr_tcp);
rtr_tcp.tr_socket = &tr_tcp;
|
Afterwards, create a group of RTR cache servers with preference 1. In this example (see Listing 2), it includes only a single cache instance.
1 2 3 4 5 | rtr_mgr_group groups[1];
groups[0].sockets = malloc(sizeof(struct rtr_socket*));
groups[0].sockets_len = 1;
groups[0].sockets[0] = &rtr_tcp;
groups[0].preference = 1;
|
Now initialize the RTR connection manager (Listing 3) providing a pointer to a configuration object, the preconfigured group(s), number of groups, a refresh interval, an expiration interval, and retry interval, as well as distinct callback functions. In this case, a refresh interval of 30 seconds, a 600s expiration timeout, and a 600s retry interval will be defined. Afterwards, start the RTR Connection Manager.
1 2 3 4 5 | struct rtr_mgr_config *conf;
int ret = rtr_mgr_init(&conf, groups, 1, 30, 600, 600,
pfx_update_fp, spki_update_fp, status_fp, NULL);
rtr_mgr_start(conf);
|
As soon as an update has been received from the RTR-Server, the callback function will be invoked. In this example, update_cb (see Listing 4) is called which prints the prefix, its minimum, and maximum length, as well as the corresponding origin AS.
1 2 3 4 5 6 7 8 9 | static void update_cb(struct pfx_table* p, const pfx_record rec, const bool added){
char ip[INET6_ADDRSTRLEN];
if(added)
printf("+ ");
else
printf("- ");
ip_addr_to_str(&(rec.prefix), ip, sizeof(ip));
printf("%-18s %3u-%-3u %10u\n", ip, rec.min_len, rec.max_len, rec.asn);
}
|
With a running RTR connection manager, you can also execute validation queries. For instance, validate the relation of prefix 10.10.0.0/24 and its origin AS 12345 as shown in Listing 5.
1 2 3 4 5 | struct lrtr_ip_addr pref;
lrtr_ip_str_to_addr("10.10.0.0", &pref);
enum pfxv_state result;
const uint8_t mask = 24;
rtr_mgr_validate(conf, 12345, &pref, mask, &result);
|
For a clean shutdown and exit of the application, first stop the RTR Connection Manager, and secondly release any memory allocated (see Listing 6).
1 2 3 | rtr_mgr_stop(conf);
rtr_mgr_free(conf);
free(groups[0].sockets);
|
Complete RTRlib Example¶
The code in Listing 7 shows a fully functional RPKI validator using the RTRlib. It includes all parts explained in the previous section, and shows how to setup multiple RPKI cache server connections using either TCP or SSH transport sockets. For the latter, the RTRlib has to be build and installed with libssh support.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | #include <stdio.h>
#include <stdlib.h>
#include "rtrlib/rtrlib.h"
int main(){
//create a SSH transport socket
char ssh_host[] = "123.231.123.221";
char ssh_user[] = "rpki_user";
char ssh_hostkey[] = "/etc/rpki-rtr/hostkey";
char ssh_privkey[] = "/etc/rpki-rtr/client.priv";
struct tr_socket tr_ssh;
struct tr_ssh_config config = {
ssh_host, //IP
22, //Port
NULL, //Source address
ssh_user,
ssh_hostkey, //Server hostkey
ssh_privkey, //Private key
};
tr_ssh_init(&config, &tr_ssh);
//create a TCP transport socket
struct tr_socket tr_tcp;
char tcp_host[] = "rpki-validator.realmv6.org";
char tcp_port[] = "8282";
struct tr_tcp_config tcp_config = {
tcp_host, //IP
tcp_port, //Port
NULL //Source address
};
tr_tcp_init(&tcp_config, &tr_tcp);
//create 3 rtr_sockets and associate them with the transprort sockets
struct rtr_socket rtr_ssh, rtr_tcp;
rtr_ssh.tr_socket = &tr_ssh;
rtr_tcp.tr_socket = &tr_tcp;
//create a rtr_mgr_group array with 2 elements
struct rtr_mgr_group groups[2];
//The first group contains both TCP RTR sockets
groups[0].sockets = malloc(sizeof(struct rtr_socket*));
groups[0].sockets_len = 1;
groups[0].sockets[0] = &rtr_tcp;
groups[0].preference = 1; //Preference value of this group
//The seconds group contains only the SSH RTR socket
groups[1].sockets = malloc(1 * sizeof(struct rtr_socket*));
groups[1].sockets_len = 1;
groups[1].sockets[0] = &rtr_ssh;
groups[1].preference = 2;
//create a rtr_mgr_config struct that stores the group
struct rtr_mgr_config *conf;
//initialize all rtr_sockets in the server pool with the same settings
int ret = rtr_mgr_init(&conf, groups, 2, 30, 600, 600, NULL, NULL, NULL, NULL);
//start the connection manager
rtr_mgr_start(conf);
//wait till at least one rtr_mgr_group is fully synchronized with the server
while(!rtr_mgr_conf_in_sync(conf)) {
sleep(1);
}
//validate the BGP-Route 10.10.0.0/24, origin ASN: 12345
struct lrtr_ip_addr pref;
lrtr_ip_str_to_addr("10.10.0.0", &pref);
enum pfxv_state result;
const uint8_t mask = 24;
rtr_mgr_validate(conf, 12345, &pref, mask, &result);
//output the result of the prefix validation above
//to showcase the returned states.
char buffer[INET_ADDRSTRLEN];
lrtr_ip_addr_to_str(&pref, buffer, sizeof(buffer));
printf("RESULT: The prefix %s/%i ", buffer, mask);
switch(result) {
case BGP_PFXV_STATE_VALID:
printf("is valid.\n");
break;
case BGP_PFXV_STATE_INVALID:
printf("is invalid.\n");
break;
case BGP_PFXV_STATE_NOT_FOUND:
printf("was not found.\n");
break;
default:
break;
}
// cleanup before exit
rtr_mgr_stop(conf);
rtr_mgr_free(conf);
free(groups[0].sockets);
free(groups[1].sockets);
}
|