bgpd: Add RPKI/RTR support

This commit adds support for the RTR protocol to receive ROA
information from a RPKI cache server. That information can than be used
to validate the BGP origin AS of IP prefixes.
Both features are implemented using [rtrlib](http://rtrlib.realmv6.org/).

Signed-off-by: Marcel Röthke <marcel.roethke@haw-hamburg.de>
This commit is contained in:
Marcel Röthke 2017-11-10 13:56:24 +01:00
parent 0db8196a96
commit dabecd7c63
9 changed files with 1547 additions and 0 deletions

View file

@ -114,6 +114,18 @@ bgpd_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS)
bgpd_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
bgpd_snmp_la_LIBADD = ../lib/libfrrsnmp.la
if RPKI
module_LTLIBRARIES += bgpd_rpki.la
endif
bgpd_rpki_la-bgp_rpki.o: bgp_rpki_clippy.c
bgp_rpki.o: bgp_rpki_clippy.c
bgpd_rpki_la_SOURCES = bgp_rpki.c
bgpd_rpki_la_CFLAGS = $(WERROR) $(RTRLIB_CFLAGS)
bgpd_rpki_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
bgpd_rpki_la_LIBADD = $(RTRLIB_LIBS)
examplesdir = $(exampledir)
dist_examples_DATA = bgpd.conf.sample bgpd.conf.sample2 \
bgpd.conf.vnc.sample

1207
bgpd/bgp_rpki.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -387,6 +387,8 @@ AC_ARG_ENABLE([protobuf],
AS_HELP_STRING([--enable-protobuf], [Enable experimental protobuf support]))
AC_ARG_ENABLE([oldvpn_commands],
AS_HELP_STRING([--enable-oldvpn-commands], [Keep old vpn commands]))
AC_ARG_ENABLE(rpki,
AS_HELP_STRING([--enable-rpki], [enable RPKI prefix validation support]))
AC_CHECK_HEADERS(json-c/json.h)
AC_CHECK_LIB(json-c, json_object_get, LIBS="$LIBS -ljson-c", [], [-lm])
@ -1796,6 +1798,30 @@ AC_SUBST(CFG_STATE)
AC_SUBST(CFG_MODULE)
AC_DEFINE_UNQUOTED(MODULE_PATH, "$CFG_MODULE", path to modules)
dnl ------------------------------------
dnl Enable RPKI and add librtr to libs
dnl ------------------------------------
if test "${enable_rpki}" = "yes"; then
PKG_CHECK_MODULES(RTRLIB,[rtrlib >= 0.5.0],
[AC_DEFINE(HAVE_RPKI,1,Enable RPKI prefix validation for BGP)
RPKI=true],
[RPKI=false
AC_MSG_ERROR([rtrlib was not found on your system or is too old.])]
)
fi
AM_CONDITIONAL([RPKI], test "x$RPKI" = "xtrue")
dnl ------------------------------------------
dnl Check whether rtrlib was build with ssh support
dnl ------------------------------------------
AC_MSG_CHECKING([whether the RTR Library is compiled with SSH])
AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include "rtrlib/rtrlib.h"]],
[[struct tr_ssh_config config;]])],
[AC_MSG_RESULT(yes)
AC_DEFINE(FOUND_SSH,,found_ssh)],
AC_MSG_RESULT(no)
)
dnl ---------------------------
dnl Check htonl works correctly
dnl ---------------------------

View file

@ -37,6 +37,7 @@ BGP-4.
* How to set up a 6-Bone connection::
* Dump BGP packets and table::
* BGP Configuration Examples::
* Prefix Origin Validation Using RPKI::
@end menu
@node Starting BGP
@ -2144,3 +2145,5 @@ route-map rm-peer-out permit 10
route-map rm-peer-in permit 10
set community additive 64512:3200
@end example
@include rpki.texi

256
doc/rpki.texi Normal file
View file

@ -0,0 +1,256 @@
@c -*-texinfo-*-
@c This is part of the FRR Manual.
@c @value{COPYRIGHT_STR}
@c See file frr.texi for copying conditions.
@node Prefix Origin Validation Using RPKI
@section Prefix Origin Validation Using RPKI
Prefix Origin Validation allows BGP routers to verify if the origin AS of
an IP prefix is legitimate to announce this IP prefix. The required
attestation objects are stored in the Resource Public Key Infrastructure
(@acronym{RPKI}). However, RPKI-enabled routers do not store cryptographic
data itself but only validation information. The validation of the
cryptographic data (so called Route Origin Authorization, or short
@acronym{ROA}, objects) will be performed by trusted cache servers. The
RPKI/RTR protocol defines a standard mechanism to maintain the exchange of
the prefix/origin AS mapping between the cache server and routers.
In combination with a BGP Prefix Origin Validation scheme a router is able
to verify received BGP updates without suffering from cryptographic
complexity.
The RPKI/RTR protocol is defined in @cite{RFC6810, The Resource Public Key
Infrastructure (RPKI) to Router Protocol}, and the validation scheme in
@cite{RFC6811, BGP Prefix Origin Validation}. The current version of Prefix
Origin Validation in FRR implements both RFCs.
For a more detailed but still easy-to-read background, we suggest the
following two articles:
@enumerate
@item @cite{Geoff Huston, Randy Bush: Securing BGP, In: The Internet
Protocol Journal, Volume 14, No. 2, 2011.}
@uref{http://www.cisco.com/web/about/ac123/ac147/archived_issues/ipj_14-2/142_bgp.html}
@item @cite{Geoff Huston: Resource Certification, In: The Internet Protocol
Journal, Volume 12, No.1, 2009.}
@uref{http://www.cisco.com/web/about/ac123/ac147/archived_issues/ipj_12-1/121_resource.html}
@end enumerate
@menu
* Features of the Current Implementation::
* Enabling RPKI::
* Configuring RPKI/RTR Cache Servers::
* Validating BGP Updates::
* Debugging::
* Displaying RPKI::
* RPKI Configuration Example::
@end menu
@node Features of the Current Implementation
@subsection Features of the Current Implementation
In a nutshell, the current implementation provides the following features
@itemize @bullet
@item The BGP router can connect to one or more RPKI cache servers to
receive validated prefix to origin AS mappings.
Advanced failover can be implemented by server sockets with different
preference values.
@item If no connection to an RPKI cache server can be established after a
pre-defined timeout, the router will process routes without prefix origin
validation. It still will try to establish a connection to an RPKI cache
server in the background.
@item By default, enabling RPKI does not change best path selection. In
particular, invalid prefixes will still be considered during best path
selection. However, the router can be configured to ignore all invalid
prefixes.
@item Route maps can be configured to match a specific RPKI validation
state. This allows the creation of local policies, which handle BGP routes
based on the outcome of the Prefix Origin Validation.
@c @item When the router receives updated validation information from the RPKI
@c cache server, all routes in the local routing table will be re-evaluated.
@end itemize
@node Enabling RPKI
@subsection Enabling RPKI
@deffn {Command} {rpki} {}
This command enables the RPKI configuration mode. Most commands that start
with @command{rpki} can only be used in this mode.
When it is used in a telnet session, leaving of this mode cause rpki to be initialized.
Executing this command alone does not activate prefix
validation. You need to configure at least one reachable cache server. See section
@ref{Configuring RPKI/RTR Cache Servers} for configuring a cache server.
@end deffn
@node Configuring RPKI/RTR Cache Servers
@subsection Configuring RPKI/RTR Cache Servers
The following commands are independent of a specific cache server.
@deffn {RPKI Command} {rpki polling_period <1-3600>} {}
@deffnx {RPKI Command} {no rpki polling_period} {}
Set the number of seconds the router waits until the router asks the cache again
for updated data.
The default value is 300 seconds.
@end deffn
@deffn {RPKI Command} {rpki timeout <1-4,294,967,296>} {}
@deffnx {RPKI Command} {no rpki timeout} {}
Set the number of seconds the router waits for the cache reply. If the
cache server is not replying within this time period, the router deletes
all received prefix records from the prefix table.
The default value is 600 seconds.
@end deffn
@deffn {RPKI Command} {rpki initial-synchronisation-timeout <1-4,294,967,296>} {}
@deffnx {RPKI Command} {no rpki initial-synchronisation-timeout} {}
Set the number of seconds until the first synchronization with the cache
server needs to be completed. If the timeout expires, BGP routing is
started without RPKI. The router will try to establish the cache server
connection in the background.
The default value is 30 seconds.
@end deffn
@noindent The following commands configure one or multiple cache servers.
@deffn {RPKI Socket Command} {rpki cache (@var{A.B.C.D}|@var{WORD}) @var{PORT} [@var{SSH_USERNAME}] [@var{SSH_PRIVKEY_PATH}] [@var{SSH_PUBKEY_PATH}] [@var{KNOWN_HOSTS_PATH}] @var{PREFERENCE}} {}
@deffnx {RPKI Socket Command} {no rpki cache (@var{A.B.C.D}|@var{WORD}) [@var{PORT}] @var{PREFERENCE}} {}
Add a cache server to the socket. By default, the connection between
router and cache server is based on plain TCP. Protecting the connection
between router and cache server by SSH is optional.
Deleting a socket removes the associated cache server and
terminates the existing connection.
@end deffn
@table @code
@item @var{A.B.C.D}|@var{WORD}
Address of the cache server.
@item @var{PORT}
Port number to connect to the cache server
@item @var{SSH_USERNAME}
SSH username to establish an SSH connection to the cache server.
@item @var{SSH_PRIVKEY_PATH}
Local path that includes the private key file of the router.
@item @var{SSH_PUBKEY_PATH}
Local path that includes the public key file of the router.
@item @var{KNOWN_HOSTS_PATH}
Local path that includes the known hosts file. The default value depends on the
configuration of the operating system environment, usually
@file{~/.ssh/known_hosts}.
@end table
@node Validating BGP Updates
@subsection Validating BGP Updates
@deffn {Route Map Command} {match rpki @{notfound|invalid|valid@}} {}
@deffnx {Route Map Command} {no match rpki @{notfound|invalid|valid@}} {}
Create a clause for a route map to match prefixes with the specified RPKI state.
@strong{Note} that the matching of invalid prefixes requires that invalid
prefixes are considered for best path selection, i.e., @command{bgp
bestpath prefix-validate disallow-invalid} is not enabled.
In the following example, the router prefers valid routes over invalid
prefixes because invalid routes have a lower local preference.
@example
! Allow for invalid routes in route selection process
route bgp 60001
!
! Set local preference of invalid prefixes to 10
route-map rpki permit 10
match rpki invalid
set local-preference 10
!
! Set local preference of valid prefixes to 500
route-map rpki permit 500
match rpki valid
set local-preference 500
@end example
@end deffn
@node Debugging
@subsection Debugging
@deffn {Command} {debug rpki} {}
@deffnx {Command} {no debug rpki} {}
Enable or disable debugging output for RPKI.
@end deffn
@node Displaying RPKI
@subsection Displaying RPKI
@deffn {Command} {show rpki prefix-table} {}
Display all validated prefix to origin AS mappings/records which have been
received from the cache servers and stored in the router. Based on this data,
the router validates BGP Updates.
@end deffn
@deffn {Command} {show rpki cache-connection} {}
Display all configured cache servers, whether active or not.
@end deffn
@node RPKI Configuration Example
@subsection RPKI Configuration Example
@example
hostname bgpd1
password zebra
! log stdout
debug bgp updates
debug bgp keepalives
debug rpki
!
rpki
rpki polling_period 1000
rpki timeout 10
! SSH Example:
rpki cache example.com 22 rtr-ssh ./ssh_key/id_rsa ./ssh_key/id_rsa.pub preference 1
! TCP Example:
rpki cache rpki-validator.realmv6.org 8282 preference 2
exit
!
router bgp 60001
bgp router-id 141.22.28.223
network 192.168.0.0/16
neighbor 123.123.123.0 remote-as 60002
neighbor 123.123.123.0 route-map rpki in
!
address-family ipv6
neighbor 123.123.123.0 activate
neighbor 123.123.123.0 route-map rpki in
exit-address-family
!
route-map rpki permit 10
match rpki invalid
set local-preference 10
!
route-map rpki permit 20
match rpki notfound
set local-preference 20
!
route-map rpki permit 30
match rpki valid
set local-preference 30
!
route-map rpki permit 40
!
@end example

View file

@ -117,6 +117,7 @@ const char *node_names[] = {
"vty", // VTY_NODE,
"link-params", // LINK_PARAMS_NODE,
"bgp evpn vni", // BGP_EVPN_VNI_NODE,
"rpki", // RPKI_NODE
};
/* Command vector which includes some level of command lists. Normally

View file

@ -140,6 +140,7 @@ enum node_type {
VTY_NODE, /* Vty node. */
LINK_PARAMS_NODE, /* Link-parameters node */
BGP_EVPN_VNI_NODE, /* BGP EVPN VNI */
RPKI_NODE, /* RPKI node for configuration of RPKI cache server connections.*/
NODE_TYPE_MAX, /* maximum */
};

View file

@ -56,6 +56,10 @@ vtysh_scan += $(top_srcdir)/bgpd/bgp_routemap.c
vtysh_scan += $(top_srcdir)/bgpd/bgp_vty.c
endif
if RPKI
vtysh_scan += $(top_srcdir)/bgpd/bgp_rpki.c
endif
if ISISD
vtysh_scan += $(top_srcdir)/isisd/isis_redist.c
vtysh_scan += $(top_srcdir)/isisd/isis_spf.c

View file

@ -1045,6 +1045,8 @@ struct cmd_node link_params_node = {
LINK_PARAMS_NODE, "%s(config-link-params)# ",
};
static struct cmd_node rpki_node = {RPKI_NODE, "%s(config-rpki)# ", 1};
/* Defined in lib/vty.c */
extern struct cmd_node vty_node;
@ -1181,6 +1183,35 @@ DEFUNSH(VTYSH_BGPD, address_family_ipv6_labeled_unicast,
return CMD_SUCCESS;
}
DEFUNSH(VTYSH_BGPD,
rpki,
rpki_cmd,
"rpki",
"Enable rpki and enter rpki configuration mode\n")
{
vty->node = RPKI_NODE;
return CMD_SUCCESS;
}
DEFUNSH(VTYSH_BGPD,
rpki_exit,
rpki_exit_cmd,
"exit",
"Exit current mode and down to previous mode\n")
{
vty->node = CONFIG_NODE;
return CMD_SUCCESS;
}
DEFUNSH(VTYSH_BGPD,
rpki_quit,
rpki_quit_cmd,
"quit",
"Exit current mode and down to previous mode\n")
{
return rpki_exit(self, vty, argc, argv);
}
DEFUNSH(VTYSH_BGPD, address_family_evpn, address_family_evpn_cmd,
"address-family <l2vpn evpn>",
"Enter Address Family command mode\n"
@ -2979,6 +3010,7 @@ void vtysh_init_vty(void)
install_node(&keychain_key_node, NULL);
install_node(&isis_node, NULL);
install_node(&vty_node, NULL);
install_node(&rpki_node, NULL);
struct cmd_node *node;
for (unsigned int i = 0; i < vector_active(cmdvec); i++) {
@ -3177,6 +3209,11 @@ void vtysh_init_vty(void)
install_element(BGP_EVPN_NODE, &exit_address_family_cmd);
install_element(BGP_IPV6L_NODE, &exit_address_family_cmd);
install_element(CONFIG_NODE, &rpki_cmd);
install_element(RPKI_NODE, &rpki_exit_cmd);
install_element(RPKI_NODE, &rpki_quit_cmd);
install_element(RPKI_NODE, &vtysh_end_all_cmd);
/* EVPN commands */
install_element(BGP_EVPN_NODE, &bgp_evpn_vni_cmd);
install_element(BGP_EVPN_VNI_NODE, &exit_vni_cmd);