From 60232adc08eb6336402cb09d23f9ccb0a1809c26 Mon Sep 17 00:00:00 2001 From: Samir Al-Sheikh Date: Mon, 11 Jul 2016 02:19:12 +0200 Subject: [PATCH] Live PRKI Origin Validation Annotation - The BGPStream will be extended by Live PRKI Origin Validation Annotation - All details concerning the provided functions, annotation elements and output format are described in issue CAIDA/bgpstream#19 and CAIDA/bgpstream/pull/26 (update) --- configure.ac | 37 +++++++ lib/bgpstream.c | 44 ++++++++ lib/bgpstream.h | 24 +++++ lib/bgpstream_constants.h | 6 ++ lib/bgpstream_elem.c | 124 ++++++++++++++++++++++ lib/bgpstream_elem.h | 96 +++++++++++++++++ lib/bgpstream_int.h | 14 +++ lib/bgpstream_record.c | 48 ++++++++- lib/utils/Makefile.am | 4 +- lib/utils/bgpstream_utils.h | 1 + lib/utils/bgpstream_utils_as_path.c | 1 - lib/utils/bgpstream_utils_as_path.h | 3 +- lib/utils/bgpstream_utils_rtr.c | 151 ++++++++++++++++++++++++++ lib/utils/bgpstream_utils_rtr.h | 112 ++++++++++++++++++++ test/Makefile.am | 15 ++- test/bgpstream-test-utils-rtr-func.c | 152 +++++++++++++++++++++++++++ test/bgpstream-test-utils-rtr.c | 121 +++++++++++++++++++++ tools/bgpreader.c | 60 ++++++++++- 18 files changed, 1004 insertions(+), 9 deletions(-) create mode 100644 lib/utils/bgpstream_utils_rtr.c create mode 100644 lib/utils/bgpstream_utils_rtr.h create mode 100644 test/bgpstream-test-utils-rtr-func.c create mode 100644 test/bgpstream-test-utils-rtr.c diff --git a/configure.ac b/configure.ac index 60dedcb..f1d0049 100644 --- a/configure.ac +++ b/configure.ac @@ -262,6 +262,43 @@ AC_DEFINE_UNQUOTED([ED_PLUGIN_INIT_ALL_ENABLED], $ED_PLUGIN_INIT_ALL_ENABLED, AC_MSG_NOTICE([----------------------------------]) +# RTR configuration +AC_MSG_CHECKING([whether the RTR library is available]) +AC_ARG_WITH([rtr], + [AS_HELP_STRING([--without-rtr], + [do not compile with rtr support])], + [], + [with_rtr=yes]) +AM_CONDITIONAL([WITH_rtr], [test "x$with_rtr" != xno]) +if test x"$with_rtr" = xyes; then +AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include "rtrlib/rtrlib.h"]])], + [AC_MSG_RESULT(yes) + AC_DEFINE([WITH_RTR],[1],[Building with RTR support])], + AC_MSG_RESULT(no) + ) +else +AC_MSG_RESULT([no]) +fi + +# SSH configuration +AC_MSG_CHECKING([whether the RTR library is compiled with SSH]) +AC_ARG_WITH([ssh], + [AS_HELP_STRING([--without-ssh], + [do not compile with ssh support])], + [], + [with_ssh=yes]) +AM_CONDITIONAL([WITH_ssh], [test "x$with_ssh" != xno]) +if test x"$with_ssh" = xyes; then +AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include "rtrlib/rtrlib.h"]], + [[struct tr_ssh_config config;]])], + [AC_MSG_RESULT(yes) + AC_DEFINE([WITH_SSH],[1],[Building with SSH support])], + AC_MSG_RESULT(no) + ) +else +AC_MSG_RESULT([no]) +fi + # we may want to come back later and add compile-time configuration for things # like datastructure providers, but for now it will all get compiled diff --git a/lib/bgpstream.c b/lib/bgpstream.c index 964bff6..4a29339 100644 --- a/lib/bgpstream.c +++ b/lib/bgpstream.c @@ -199,6 +199,11 @@ bgpstream_t *bgpstream_create() { bs = NULL; return NULL; } + +#ifdef WITH_RTR + bs->rtr_server_conf.active = 0; +#endif + /* memory for the bgpstream interface has been * allocated correctly */ bs->status = BGPSTREAM_STATUS_ALLOCATED; @@ -401,13 +406,46 @@ void bgpstream_set_live_mode(bgpstream_t *bs) { bgpstream_debug("BS: set_blocking stop"); } +#ifdef WITH_RTR +/* Get the RTR-Socket & configuration +*/ +struct rtr_mgr_config *bgpstream_get_rtr_config(bgpstream_t *bs) +{ + return bs->cfg_tr; +} + +/* Set the RTR-Configuration +*/ +int bgpstream_set_rtr_config(bgpstream_t *bs, char *host, char *port, char *ssh_user, + char *ssh_hostkey, char *ssh_privatekey, + int active) +{ + + bs->rtr_server_conf.host = host; + bs->rtr_server_conf.port = port; + bs->rtr_server_conf.ssh_user = ssh_user; + bs->rtr_server_conf.ssh_hostkey = ssh_hostkey; + bs->rtr_server_conf.ssh_privatekey = ssh_privatekey; + bs->rtr_server_conf.active = active; + return 0; +} +#endif /* turn on the bgpstream interface, i.e.: * it makes the interface ready * for a new get next call + * it starts the RTR-Connection for validation if RTR is active */ int bgpstream_start(bgpstream_t *bs) { bgpstream_debug("BS: init start"); +#ifdef WITH_RTR + if (bs->rtr_server_conf.active) { + bs->cfg_tr = bgpstream_rtr_start_connection( + bs->rtr_server_conf.host, bs->rtr_server_conf.port, NULL, NULL, NULL, + bs->rtr_server_conf.ssh_user, bs->rtr_server_conf.ssh_hostkey, + bs->rtr_server_conf.ssh_privatekey); + } +#endif if(bs == NULL || (bs != NULL && bs->status != BGPSTREAM_STATUS_ALLOCATED)) { return 0; // nothing to init } @@ -492,6 +530,12 @@ int bgpstream_get_next_record(bgpstream_t *bs, /* turn off the bgpstream interface */ void bgpstream_stop(bgpstream_t *bs) { bgpstream_debug("BS: close start"); +#ifdef WITH_RTR + if (bs->rtr_server_conf.active) { + bgpstream_rtr_close_connection(bs->cfg_tr); + bs->rtr_server_conf.active = false; + } +#endif if(bs == NULL || (bs != NULL && bs->status != BGPSTREAM_STATUS_ON)) { return; // nothing to close } diff --git a/lib/bgpstream.h b/lib/bgpstream.h index e2f6433..0169acc 100644 --- a/lib/bgpstream.h +++ b/lib/bgpstream.h @@ -146,6 +146,8 @@ typedef struct struct_bgpstream_data_interface_option } bgpstream_data_interface_option_t; +#ifdef WITH_RTR + /** @} */ /** @@ -153,6 +155,28 @@ typedef struct struct_bgpstream_data_interface_option * * @{ */ +/** Get the configuration of the RTR-Socket-Manager + * + * @return a pointer to the configuration of the rtr-socket-manager + */ +struct rtr_mgr_config *bgpstream_get_rtr_config(); + +/** Set the configuration of the RTR-Socket-Manager +* +* @param bs a pointer to a BGP Stream instance +* @param host the host of the cache server +* @param port the port of the cache server +* @param ssh_user the username for a SSH connection +* @param ssh_hostkey the hostkey for a SSH connection +* @param ssh_privatekey the private key for a SSH connection +* @param active whether the rtr-validation is enabled +*/ +int bgpstream_set_rtr_config(bgpstream_t *bs, + char *host, char *port, char *ssh_user, + char *ssh_hostkey, char *ssh_privatekey, + int active); +#endif + /** Create a new BGP Stream instance * * @return a pointer to a BGP Stream instance if successful, NULL otherwise diff --git a/lib/bgpstream_constants.h b/lib/bgpstream_constants.h index 3660cf6..47d8b20 100644 --- a/lib/bgpstream_constants.h +++ b/lib/bgpstream_constants.h @@ -30,6 +30,12 @@ // dump name max length #define BGPSTREAM_DUMP_MAX_LEN 1024 +// RPKI validation result max length +#define BGPSTREAM_RPKI_RST_MAX_LEN 2048 + +// RPKI validation result max ROA entries +#define BGPSTREAM_RPKI_MAX__ROA_ENT 16 + // parameters/attribute/filters max length #define BGPSTREAM_PAR_MAX_LEN 512 diff --git a/lib/bgpstream_elem.c b/lib/bgpstream_elem.c index b7b2519..ec1cfc4 100644 --- a/lib/bgpstream_elem.c +++ b/lib/bgpstream_elem.c @@ -30,13 +30,17 @@ #include "bgpdump_lib.h" #include "utils.h" +#include "khash.h" +#include "bgpstream.h" #include "bgpstream_utils.h" #include "bgpstream_debug.h" #include "bgpstream_record.h" +#include "bgpstream_constants.h" #include "bgpstream_elem_int.h" +#include "bgpstream_utils_rtr.h" /* ==================== PROTECTED FUNCTIONS ==================== */ @@ -81,12 +85,25 @@ void bgpstream_elem_destroy(bgpstream_elem_t *elem) { bgpstream_community_set_destroy(elem->communities); elem->communities = NULL; +#ifdef WITH_RTR + if(elem->annotations.active){ + kh_destroy(rpki_result, elem->annotations.rpki_kh); + elem->annotations.rpki_kh = NULL; + } +#endif + free(elem); } void bgpstream_elem_clear(bgpstream_elem_t *elem) { bgpstream_as_path_clear(elem->aspath); bgpstream_community_set_clear(elem->communities); +#ifdef WITH_RTR + if(elem->annotations.active && + (elem->annotations.rpki_validation_status != BGPSTREAM_ELEM_RPKI_VALIDATION_STATUS_NOTVALIDATED)){ + kh_clear(rpki_result, elem->annotations.rpki_kh); + } +#endif } bgpstream_elem_t *bgpstream_elem_copy(bgpstream_elem_t *dst, @@ -346,6 +363,17 @@ char *bgpstream_elem_custom_snprintf(char *buf, size_t len, if(B_FULL) return NULL; +#ifdef WITH_RTR + /* RPKI Validation */ + if(elem->annotations.active) { + char buf_rpki[BGPSTREAM_RPKI_RST_MAX_LEN]; + c = bgpstream_elem_get_rpki_validation_result_snprintf( + buf_rpki, sizeof(buf_rpki), elem); + strcat(buf, buf_rpki); + written += c; + buf_p += c; + } +#endif /* END OF LINE */ break; @@ -422,3 +450,99 @@ char *bgpstream_elem_snprintf(char *buf, size_t len, { return bgpstream_elem_custom_snprintf(buf, len, elem, 1); } + +#ifdef WITH_RTR +int bgpstream_elem_get_rpki_validation_result_snprintf( + char *buf, size_t len, bgpstream_elem_t const *elem) +{ + int key; + char *val; + char result_output[BGPSTREAM_RPKI_RST_MAX_LEN]; + char valid_prefixes[BGPSTREAM_RPKI_RST_MAX_LEN]; + if (elem->annotations.rpki_validation_status != + BGPSTREAM_ELEM_RPKI_VALIDATION_STATUS_NOTFOUND) { + snprintf(result_output, sizeof(result_output), "%s%s", result_output, + elem->annotations.rpki_validation_status == + BGPSTREAM_ELEM_RPKI_VALIDATION_STATUS_INVALID + ? "invalid;" : "valid;"); + + kh_foreach(elem->annotations.rpki_kh, key, val, + snprintf(valid_prefixes, sizeof(valid_prefixes), "%i,%s;", key, val); + strcat(result_output, valid_prefixes); + ); + result_output[strlen(result_output) - 1] = 0; + } else { + snprintf(result_output, sizeof(result_output), "%s%s", result_output, + "notfound"); + } + + return snprintf(buf, len, "%s", result_output); +} + +void bgpstream_elem_get_rpki_validation_result(struct rtr_mgr_config *cfg, bgpstream_elem_t *elem, + char *prefix, + uint32_t origin_asn, + uint8_t mask_len) +{ + if (elem->annotations.rpki_validation_status == + BGPSTREAM_ELEM_RPKI_VALIDATION_STATUS_NOTVALIDATED) { + + struct reasoned_result res_reasoned = + bgpstream_rtr_validate_reason(cfg, origin_asn, prefix, mask_len); + + if (res_reasoned.result == BGP_PFXV_STATE_VALID) { + elem->annotations.rpki_validation_status = + BGPSTREAM_ELEM_RPKI_VALIDATION_STATUS_VALID; + } + if (res_reasoned.result == BGP_PFXV_STATE_NOT_FOUND) { + elem->annotations.rpki_validation_status = + BGPSTREAM_ELEM_RPKI_VALIDATION_STATUS_NOTFOUND; + } + if (res_reasoned.result == BGP_PFXV_STATE_INVALID) { + elem->annotations.rpki_validation_status = + BGPSTREAM_ELEM_RPKI_VALIDATION_STATUS_INVALID; + } + + if (elem->annotations.rpki_validation_status != + BGPSTREAM_ELEM_RPKI_VALIDATION_STATUS_NOTFOUND) { + + char reason_prefix[INET6_ADDRSTRLEN]; + char buf_p[BGPSTREAM_RPKI_RST_MAX_LEN]; + + int ret; + khiter_t k; + + if(elem->annotations.khash_init != 1) { + elem->annotations.rpki_kh = kh_init(rpki_result); + elem->annotations.khash_init = 1; + } + + for (int i = 0; i < res_reasoned.reason_len; i++) { + if(kh_get(rpki_result, elem->annotations.rpki_kh, res_reasoned.reason[i].asn) == + kh_end(elem->annotations.rpki_kh)){ + k = kh_put(rpki_result, elem->annotations.rpki_kh, (int) res_reasoned.reason[i].asn, &ret); + kh_val(elem->annotations.rpki_kh, k) = '\0'; + } + else { + k = kh_get(rpki_result, elem->annotations.rpki_kh, (int) res_reasoned.reason[i].asn); + } + + lrtr_ip_addr_to_str(&(res_reasoned.reason[i].prefix), reason_prefix, sizeof(reason_prefix)); + snprintf(elem->annotations.valid_prefix[k], BGPSTREAM_RPKI_RST_MAX_LEN, "%s/%" PRIu8 "-%"PRIu8, + reason_prefix, res_reasoned.reason[i].min_len, res_reasoned.reason[i].max_len); + + if(!kh_val(elem->annotations.rpki_kh, k)){ + kh_val(elem->annotations.rpki_kh, k) = elem->annotations.valid_prefix[k]; + } + else if(!strstr(kh_val(elem->annotations.rpki_kh, k), elem->annotations.valid_prefix[k])) { + snprintf(buf_p, sizeof(buf_p), "%s %s", kh_val(elem->annotations.rpki_kh, k), + elem->annotations.valid_prefix[k]); + kh_val(elem->annotations.rpki_kh, k) = buf_p; + } + } + } + + free(res_reasoned.reason); + } +} +#endif diff --git a/lib/bgpstream_elem.h b/lib/bgpstream_elem.h index d84e791..bd66a7c 100644 --- a/lib/bgpstream_elem.h +++ b/lib/bgpstream_elem.h @@ -25,6 +25,8 @@ #define __BGPSTREAM_ELEM_H #include "bgpstream_utils.h" +#include "bgpstream_constants.h" +#include "khash.h" /** @file * @@ -105,6 +107,34 @@ typedef enum { } bgpstream_elem_type_t; +/** Validation types */ +typedef enum { + + /** Valid */ + BGPSTREAM_ELEM_RPKI_VALIDATION_STATUS_VALID = 1, + + /** Invalid */ + BGPSTREAM_ELEM_RPKI_VALIDATION_STATUS_INVALID = 0, + + /** Not found */ + BGPSTREAM_ELEM_RPKI_VALIDATION_STATUS_NOTFOUND = -1, + + /** Not validated */ + BGPSTREAM_ELEM_RPKI_VALIDATION_STATUS_NOTVALIDATED = 2, + +} bgpstream_validation_status_type_t; + +/** RPKI status */ +typedef enum { + + /** Active */ + BGPSTREAM_ELEM_RPKI_STATUS_ACTIVE = 1, + + /** Inactive */ + BGPSTREAM_ELEM_RPKI_STATUS_INACTIVE = 0, + +} bgpstream_rpki_status_type_t; + /** @} */ /** @@ -112,6 +142,46 @@ typedef enum { * * @{ */ +#ifdef WITH_RTR + +KHASH_INIT(rpki_result, khint32_t, char*, 1, kh_int_hash_func, kh_int_hash_equal) + +/** A BGP Stream Elem object for Annotations */ +typedef struct struct_bgpstream_elem_annotations_t { + + /** RPKI validation status + * + * RPKI validation status for a given prefix + */ + bgpstream_validation_status_type_t rpki_validation_status; + + /** RPKI validation result khash init status + * + * 1 - RPKI hashtable is already initialized, 0 - otherwise + */ + int khash_init; + + /** RPKI validation result khash + * + * RPKI validation result hashtable (ASN -> prefixes) + */ + khash_t(rpki_result) *rpki_kh; + + /** RPKI valid prefixes + * + * All valid prefixes for a given prefix + */ + char valid_prefix[BGPSTREAM_RPKI_MAX__ROA_ENT][BGPSTREAM_RPKI_RST_MAX_LEN]; + + /** RPKI BGPStream status + * + * BGPstream status for RPKI validation + */ + bgpstream_rpki_status_type_t active; + +} bgpstream_elem_annotations_t; +#endif + /** A BGP Stream Elem object */ typedef struct struct_bgpstream_elem_t { @@ -165,6 +235,13 @@ typedef struct struct_bgpstream_elem_t { */ bgpstream_elem_peerstate_t new_state; +#ifdef WITH_RTR + /** Annotations + * + * All additional annotations + */ + bgpstream_elem_annotations_t annotations; +#endif } bgpstream_elem_t; /** @} */ @@ -238,6 +315,25 @@ int bgpstream_elem_peerstate_snprintf(char *buf, size_t len, char *bgpstream_elem_snprintf(char *buf, size_t len, const bgpstream_elem_t *elem); +#ifdef WITH_RTR +/** Write the string representation of the RPKI validation result of an elem + * + * @param elem the elem whose RPKI validation result will be printed + */ +int bgpstream_elem_get_rpki_validation_result_snprintf( + char *buf, size_t len, bgpstream_elem_t const *elem); + +/** Get the result of the RPKI-Validation for the elem + * + * @param elem the elem which will be validated + */ +void bgpstream_elem_get_rpki_validation_result(struct rtr_mgr_config *cfg, + bgpstream_elem_t *elem, + char *prefix, + uint32_t origin_asn, + uint8_t mask_len); +#endif + /** @} */ #endif /* __BGPSTREAM_ELEM_H */ diff --git a/lib/bgpstream_int.h b/lib/bgpstream_int.h index 3035af4..d530712 100644 --- a/lib/bgpstream_int.h +++ b/lib/bgpstream_int.h @@ -31,6 +31,16 @@ #include "bgpstream_reader.h" #include "bgpstream_filter.h" +#ifdef WITH_RTR +struct rtr_server_configure { + char *host; + char *port; + char *ssh_user; + char *ssh_hostkey; + char *ssh_privatekey; + int active; +}; +#endif typedef enum { BGPSTREAM_STATUS_ALLOCATED, @@ -44,6 +54,10 @@ struct struct_bgpstream_t { bgpstream_filter_mgr_t *filter_mgr; bgpstream_datasource_mgr_t *datasource_mgr; bgpstream_status status; +#ifdef WITH_RTR + struct rtr_server_configure rtr_server_conf; + struct rtr_mgr_config *cfg_tr; +#endif }; diff --git a/lib/bgpstream_record.c b/lib/bgpstream_record.c index 8a022a1..45df388 100644 --- a/lib/bgpstream_record.c +++ b/lib/bgpstream_record.c @@ -35,6 +35,9 @@ #include "bgpstream_debug.h" #include "bgpstream_int.h" +#include "bgpstream.h" +#include "utils/bgpstream_utils_rtr.h" + /* allocate memory for a bs_record */ bgpstream_record_t *bgpstream_record_create() { @@ -172,9 +175,50 @@ bgpstream_elem_t *bgpstream_record_get_next_elem(bgpstream_record_t *record) { * then return elem, otherwise run again * bgpstream_record_get_next_elem(record) */ if(elem == NULL || bgpstream_elem_check_filters(record->bs->filter_mgr, elem) == 1) - { - return elem; + { +#ifdef WITH_RTR + if(record->bs->rtr_server_conf.active) { + if (elem != NULL && bgpstream_get_rtr_config(record->bs) != NULL) { + elem->annotations.active = BGPSTREAM_ELEM_RPKI_STATUS_ACTIVE; + elem->annotations.rpki_validation_status = + BGPSTREAM_ELEM_RPKI_VALIDATION_STATUS_NOTVALIDATED; + + char prefix[INET6_ADDRSTRLEN]; + bgpstream_pfx_t *addr_pfx; + + switch (elem->prefix.address.version) { + case BGPSTREAM_ADDR_VERSION_IPV4: + addr_pfx = (bgpstream_pfx_t *)&(elem->prefix); + bgpstream_addr_ntop(prefix, INET_ADDRSTRLEN, &(addr_pfx->address)); + break; + + case BGPSTREAM_ADDR_VERSION_IPV6: + addr_pfx = (bgpstream_pfx_t *)&(elem->prefix); + bgpstream_addr_ntop(prefix, INET6_ADDRSTRLEN, &(addr_pfx->address)); + break; + + default: + addr_pfx = NULL; + break; + } + if (addr_pfx != NULL) { + uint32_t origin_asn = 0; + bgpstream_as_path_seg_t *origin_seg = + bgpstream_as_path_get_origin_seg(elem->aspath); + if (origin_seg != NULL && + origin_seg->type == BGPSTREAM_AS_PATH_SEG_ASN) { + origin_asn = ((bgpstream_as_path_seg_asn_t *)origin_seg)->asn; + } + + bgpstream_elem_get_rpki_validation_result(bgpstream_get_rtr_config(record->bs), + elem, prefix, origin_asn, + elem->prefix.mask_len); + } + } } +#endif + return elem; + } return bgpstream_record_get_next_elem(record); } diff --git a/lib/utils/Makefile.am b/lib/utils/Makefile.am index 3159ae0..c50ac9e 100644 --- a/lib/utils/Makefile.am +++ b/lib/utils/Makefile.am @@ -74,7 +74,9 @@ libbgpstream_utils_la_SOURCES = \ bgpstream_utils_ip_counter.c \ bgpstream_utils_ip_counter.h \ bgpstream_utils_patricia.c \ - bgpstream_utils_patricia.h + bgpstream_utils_patricia.h \ + bgpstream_utils_rtr.c \ + bgpstream_utils_rtr.h libbgpstream_utils_la_LIBADD = $(CONDITIONAL_LIBS) diff --git a/lib/utils/bgpstream_utils.h b/lib/utils/bgpstream_utils.h index 4812c35..51fd1fb 100644 --- a/lib/utils/bgpstream_utils.h +++ b/lib/utils/bgpstream_utils.h @@ -56,6 +56,7 @@ #include "bgpstream_utils_pfx_set.h" /*< Prefix Set utilities */ #include "bgpstream_utils_str_set.h" /*< String Set utilities */ #include "bgpstream_utils_patricia.h" /*< Patricia Tree utilities */ +#include "bgpstream_utils_rtr.h" /*< RTR utilities */ #endif /* __BGPSTREAM_UTILS_H */ diff --git a/lib/utils/bgpstream_utils_as_path.c b/lib/utils/bgpstream_utils_as_path.c index 46d8399..5b6f4f4 100644 --- a/lib/utils/bgpstream_utils_as_path.c +++ b/lib/utils/bgpstream_utils_as_path.c @@ -581,7 +581,6 @@ inline int bgpstream_as_path_equal(bgpstream_as_path_t *path1, !bcmp(path1->data, path2->data, path1->data_len); } - /* ========== PRIVATE FUNCTIONS ========== */ #ifdef PATH_COPY_DEBUG diff --git a/lib/utils/bgpstream_utils_as_path.h b/lib/utils/bgpstream_utils_as_path.h index dd065fa..7329fd9 100644 --- a/lib/utils/bgpstream_utils_as_path.h +++ b/lib/utils/bgpstream_utils_as_path.h @@ -26,6 +26,7 @@ #define __BGPSTREAM_UTILS_AS_PATH_H #include +#include "bgpstream_utils_pfx.h" /** @file * @@ -89,7 +90,6 @@ typedef struct bgpstream_as_path bgpstream_as_path_t; * * @{ */ - /** Generic AS Path Segment. * * This must be cast to the appropriate structure based on the type @@ -358,7 +358,6 @@ bgpstream_as_path_hash(bgpstream_as_path_t *path); int bgpstream_as_path_equal(bgpstream_as_path_t *path1, bgpstream_as_path_t *path2); - /** @} */ diff --git a/lib/utils/bgpstream_utils_rtr.c b/lib/utils/bgpstream_utils_rtr.c new file mode 100644 index 0000000..04c4438 --- /dev/null +++ b/lib/utils/bgpstream_utils_rtr.c @@ -0,0 +1,151 @@ +/* + * This file is part of bgpstream + * + * CAIDA, UC San Diego + * bgpstream-info@caida.org + * + * Copyright (C) 2012 The Regents of the University of California. + * Authors: Alistair King, Chiara Orsini + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#include "bgpstream_utils_rtr.h" +#include "config.h" +#include +#include + +#ifdef WITH_RTR +#include "rtrlib/rtrlib.h" + +/* PUBLIC FUNCTIONS */ + +struct rtr_mgr_config *bgpstream_rtr_start_connection( + char *host, char *port, uint32_t *polling_period, uint32_t *cache_timeout, + uint32_t *retry_inv, char *ssh_user, char *ssh_hostkey, char *ssh_privkey) { + + uint32_t pp = 30; + if (polling_period == NULL) { + polling_period = &pp; + } + + uint32_t ct = 600; + if (cache_timeout == NULL) { + cache_timeout = &ct; + } + + uint32_t rt = 600; + if (retry_inv == NULL) { + retry_inv = &rt; + } + + struct tr_socket *tr = malloc(sizeof(struct tr_socket)); + if (!tr) { + fprintf(stderr, "ERROR: Failed to allocate memory.\n"); + exit(-1); + } + if (host != NULL && ssh_user != NULL && ssh_hostkey != NULL && + ssh_privkey != NULL) { + +#ifdef WITH_SSH + int port = port; + struct tr_ssh_config config = { + host, port, NULL, ssh_user, ssh_hostkey, ssh_privkey, + }; + tr_ssh_init(&config, tr); +#endif + if (tr_open(tr) == TR_ERROR) { + fprintf(stderr, "ERROR: The SSH-values entered caused an error while " + "initialising the transport-socket\n"); + exit(-1); + } + } + + else if (host != NULL && port != NULL) { + struct tr_tcp_config config = {host, port, NULL}; + tr_tcp_init(&config, tr); + } + + struct rtr_socket *rtr = malloc(sizeof(struct rtr_socket)); + if (!rtr) { + fprintf(stderr, "ERROR: Failed to allocate memory.\n"); + exit(-1); + } + rtr->tr_socket = tr; + + struct rtr_mgr_group groups[1]; + groups[0].sockets = malloc(sizeof(struct rtr_socket *)); + if (!groups[0].sockets) { + fprintf(stderr, "ERROR: Failed to allocate memory.\n"); + exit(-1); + } + groups[0].sockets_len = 1; + groups[0].sockets[0] = rtr; + groups[0].preference = 1; + + struct rtr_mgr_config *conf; + int ret = rtr_mgr_init(&conf, groups, 1, *polling_period, *cache_timeout, + *retry_inv, NULL, NULL, NULL, NULL); + + rtr_mgr_start(conf); + + while (!rtr_mgr_conf_in_sync(conf)) + sleep(1); + + return conf; +} + +enum pfxv_state bgpstream_rtr_validate(struct rtr_mgr_config *mgr_cfg, + uint32_t asn, char *prefix, + uint32_t mask_len) { + struct lrtr_ip_addr pref; + lrtr_ip_str_to_addr(prefix, &pref); + enum pfxv_state result; + rtr_mgr_validate(mgr_cfg, asn, &pref, mask_len, &result); + return result; +} + +struct reasoned_result +bgpstream_rtr_validate_reason(struct rtr_mgr_config *mgr_cfg, uint32_t asn, + char prefix[], uint32_t mask_len) { + struct lrtr_ip_addr pref; + lrtr_ip_str_to_addr(prefix, &pref); + enum pfxv_state result; + struct pfx_record *reason = NULL; + unsigned int reason_len = 0; + + pfx_table_validate_r(mgr_cfg->groups[0].sockets[0]->pfx_table, &reason, + &reason_len, asn, &pref, mask_len, &result); + + struct reasoned_result reasoned_res; + reasoned_res.reason = reason; + reasoned_res.reason_len = reason_len; + reasoned_res.result = result; + + return (reasoned_res); +} + +void bgpstream_rtr_close_connection(struct rtr_mgr_config *mgr_cfg) { + struct tr_socket *tr = mgr_cfg->groups[0].sockets[0]->tr_socket; + struct rtr_socket *rtr = mgr_cfg->groups[0].sockets[0]; + struct rtr_socket **socket = mgr_cfg->groups[0].sockets; + rtr_mgr_stop(mgr_cfg); + rtr_mgr_free(mgr_cfg); + tr_free(tr); + free(tr); + free(rtr); + free(socket); +} + +#endif diff --git a/lib/utils/bgpstream_utils_rtr.h b/lib/utils/bgpstream_utils_rtr.h new file mode 100644 index 0000000..c8810f4 --- /dev/null +++ b/lib/utils/bgpstream_utils_rtr.h @@ -0,0 +1,112 @@ +/* + * This file is part of bgpstream + * + * CAIDA, UC San Diego + * bgpstream-info@caida.org + * + * Copyright (C) 2012 The Regents of the University of California. + * Authors: Alistair King, Chiara Orsini + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#ifndef __BGPSTREAM_UTILS_RTR_H +#define __BGPSTREAM_UTILS_RTR_H + +#include "config.h" +#include "bgpstream_utils_pfx.h" + +#ifdef WITH_RTR +#include "rtrlib/rtrlib.h" + +/** @file + * + * @brief Header file that exposes the public interface of the RTR-Validation + * for a BGP-Record Set. + * + * @author Samir Al-Sheikh, Fabrice J. Ryba + * + */ + +/** @} */ + +struct reasoned_result { + struct pfx_record *reason; + enum pfxv_state result; + unsigned int reason_len; +}; + +/** + * @name Public API Functions + * + * @{ */ + +/** Start a connection to a desired RTR-Server over SSH or TCP + * + * @param host string of the host-address + * @param port if specific port should be used, string of the + * port-number + * @param polling_period if specific polling period should be used, + * uint32_t number (seconds) + * @param cache_timeout if specific cache_timeout should be used, + * uint32_t nuber (seconds) + * @param ssh_user if ssh should be used, the username to be used + * @param ssh_hostkey if ssh should be used, the hostkey to be used + * @param ssh_privkey if ssh should be used, the private key to be used + * @return a struct consisting of the configuration and the address of the + * transport-socket + */ +struct rtr_mgr_config *bgpstream_rtr_start_connection( + char *host, char *port, uint32_t *polling_period, uint32_t *cache_timeout, + uint32_t *retry_inv, char *ssh_user, char *ssh_hostkey, char *ssh_privkey); + +/** + * @brief Validates the origin of a BGP-Route. + * @param mgr_cfg Manager-Configuration + * @param asn Autonomous system number of the Origin-AS of the prefix + * @param prefix Announced network prefix + * @param mask_len Length of the network mask of the announced prefix + * @param[out] result Outcome of the validation + * @return the validation of the ip: BGP_PFXV_STATE_VALID, + * BGP_PFXV_STATE_NOT_FOUND or BGP_PFXV_STATE_INVALID. + */ +enum pfxv_state bgpstream_rtr_validate(struct rtr_mgr_config *mgr_cfg, + uint32_t asn, char *prefix, + uint32_t mask_len); + +/** + * @brief Validates the origin of a BGP-Route and returns the reason for the + * state. + * @param mgr_cfg Manager-Configuration + * @param asn Autonomous system number of the Origin-AS of the prefix + * @param prefix Announced network prefix + * @param mask_len Length of the network mask of the announced prefix + * @param[out] result Outcome of the validation and the reason for the state + * @return the validation of the ip: BGP_PFXV_STATE_VALID, + * BGP_PFXV_STATE_NOT_FOUND or BGP_PFXV_STATE_INVALID. + */ +struct reasoned_result +bgpstream_rtr_validate_reason(struct rtr_mgr_config *mgr_cfg, uint32_t asn, + char prefix[], uint32_t mask_len); + +/** Stop a connection to a desired RTR-Server over SSH or TCP + * + * @param mgr_cfg Configuration and socket + */ +void bgpstream_rtr_close_connection(struct rtr_mgr_config *mgr_cfg); + +/** @} */ + +#endif /*__RTR*/ +#endif /*__BGPSTREAM_UTILS_RTR_H*/ diff --git a/test/Makefile.am b/test/Makefile.am index 378cdd7..d01f5f9 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -31,14 +31,18 @@ TESTS = \ bgpstream-test-filters \ bgpstream-test-utils-addr \ bgpstream-test-utils-pfx \ - bgpstream-test-utils-patricia + bgpstream-test-utils-patricia \ + bgpstream-test-utils-rtr \ + bgpstream-test-utils-rtr-func check_PROGRAMS = \ bgpstream-test \ bgpstream-test-filters \ bgpstream-test-utils-addr \ bgpstream-test-utils-pfx \ - bgpstream-test-utils-patricia + bgpstream-test-utils-patricia \ + bgpstream-test-utils-rtr \ + bgpstream-test-utils-rtr-func bgpstream_test_SOURCES = bgpstream-test.c bgpstream_test.h bgpstream_test_LDADD = $(top_builddir)/lib/libbgpstream.la @@ -55,6 +59,13 @@ bgpstream_test_utils_pfx_LDADD = $(top_builddir)/lib/libbgpstream.la bgpstream_test_utils_patricia_SOURCES = bgpstream-test-utils-patricia.c bgpstream_test.h bgpstream_test_utils_patricia_LDADD = $(top_builddir)/lib/libbgpstream.la +bgpstream_test_utils_rtr_SOURCES = bgpstream-test-utils-rtr.c bgpstream_test.h +bgpstream_test_utils_rtr_LDADD = $(top_builddir)/lib/libbgpstream.la + +bgpstream_test_utils_rtr_func_SOURCES = bgpstream-test-utils-rtr-func.c bgpstream_test.h +bgpstream_test_utils_rtr_func_LDADD = $(top_builddir)/lib/libbgpstream.la + + ACLOCAL_AMFLAGS = -I m4 CLEANFILES = *~ diff --git a/test/bgpstream-test-utils-rtr-func.c b/test/bgpstream-test-utils-rtr-func.c new file mode 100644 index 0000000..c20ed8c --- /dev/null +++ b/test/bgpstream-test-utils-rtr-func.c @@ -0,0 +1,152 @@ +#include "bgpstream_test.h" +#include "utils.h" +#include +#include + +#define TEST_FILE "ris.rrc06.ribs.1427846400.gz" +#define TEST_W_START 0 +#define TEST_W_END -1 +#define TEST_BUF_S 1024 + +#define TEST1_O_ASN 12654 +#define TEST1_PFX "93.175.146.0/24" +#define TEST1_MAXL 24 + +#define TEST2_O_ASN 12654 +#define TEST2_PFX "2001:7fb:fd02::/48" +#define TEST2_MAXL 48 + +#define TEST3_O_ASN 196615 +#define TEST3_PFX "93.175.147.0/24" +#define TEST3_MAXL 24 + +#define TEST4_O_ASN 196615 +#define TEST4_PFX "2001:7fb:fd03::/48" +#define TEST4_MAXL 48 + +#define TEST5_PFX "84.205.83.0/24" +#define TEST6_PFX "2001:7fb:ff03::/48" + +#define TEST_RPKI_VALIDATOR_URL "rpki-validator.realmv6.org" +#define TEST_RPKI_VALIDATOR_PORT "8282" + +#define SETUP \ + do { \ + bs = bgpstream_create(); \ + rec = bgpstream_record_create(); \ + } while(0) + +#define TEARDOWN \ + do { \ + bgpstream_record_destroy(rec); \ + rec = NULL; \ + bgpstream_destroy(bs); \ + bs = NULL; \ + } while(0) + +#define SET_INTERFACE(interface) \ + do { \ + datasource_id = \ + bgpstream_get_data_interface_id_by_name(bs, STR(interface)); \ + bgpstream_set_data_interface(bs, datasource_id); \ + } while(0) + +#ifdef WITH_RTR +bgpstream_t *bs; +bgpstream_elem_t *elem; +bgpstream_record_t *rec; +bgpstream_data_interface_id_t datasource_id = 0; +bgpstream_data_interface_option_t *option; + +int test_RPKI_validation() +{ + int ret; + uint32_t asn; + char pfx[TEST_BUF_S]; + char rpki[TEST_BUF_S]; + char buf[TEST_BUF_S]; + + SETUP; + SET_INTERFACE(singlefile); + + option = bgpstream_get_data_interface_option_by_name(bs, datasource_id, + "rib-file"); + bgpstream_set_data_interface_option(bs, option, TEST_FILE); + + bgpstream_add_interval_filter(bs, TEST_W_START, TEST_W_END); + bgpstream_add_filter(bs, BGPSTREAM_FILTER_TYPE_ELEM_PREFIX, TEST1_PFX); + bgpstream_add_filter(bs, BGPSTREAM_FILTER_TYPE_ELEM_PREFIX, TEST2_PFX); + + bgpstream_add_filter(bs, BGPSTREAM_FILTER_TYPE_ELEM_PREFIX, TEST3_PFX); + bgpstream_add_filter(bs, BGPSTREAM_FILTER_TYPE_ELEM_PREFIX, TEST4_PFX); + + bgpstream_add_filter(bs, BGPSTREAM_FILTER_TYPE_ELEM_PREFIX, TEST5_PFX); + bgpstream_add_filter(bs, BGPSTREAM_FILTER_TYPE_ELEM_PREFIX, TEST6_PFX); + + /* Set RTR config and connect to public RPKI cache server */ + bgpstream_set_rtr_config(bs, TEST_RPKI_VALIDATOR_URL, TEST_RPKI_VALIDATOR_PORT, + NULL, NULL, NULL, 1); + bgpstream_start(bs); + + while((ret = bgpstream_get_next_record(bs, rec)) > 0) { + if(rec->status == BGPSTREAM_RECORD_STATUS_VALID_RECORD) { + while((elem = bgpstream_record_get_next_elem(rec)) != NULL) { + bgpstream_pfx_snprintf(pfx, sizeof(pfx), (bgpstream_pfx_t*)&(elem->prefix)); + bgpstream_elem_get_rpki_validation_result_snprintf(rpki, sizeof(rpki), elem); + bgpstream_as_path_get_origin_val(elem->aspath, &asn); + + /* Validate RPKI-enabled BGP Beacons from RIPE */ + /* see: https://www.ripe.net/analyse/internet-measurements/routing-information-service-ris/current-ris-routing-beacons */ + + if(!strcmp(pfx, TEST1_PFX) && asn == TEST1_O_ASN) { + snprintf(buf, sizeof buf, "%s;%i,%s-%i", "valid", TEST1_O_ASN, TEST1_PFX, TEST1_MAXL); + CHECK("RPKI-Testcase 1: Validation status for valid ROA Beacon", + !strcmp(rpki, buf)); + } + if(!strcmp(pfx, TEST2_PFX) && asn == TEST2_O_ASN) { + snprintf(buf, sizeof buf, "%s;%i,%s-%i", "valid", TEST2_O_ASN, TEST2_PFX, TEST2_MAXL); + CHECK("RPKI-Testcase 2: Validation status for valid ROA Beacon", + !strcmp(rpki, buf)); + } + if(!strcmp(pfx, TEST3_PFX)) { + snprintf(buf, sizeof buf, "%s;%i,%s-%i", "invalid", TEST3_O_ASN, TEST3_PFX, TEST3_MAXL); + CHECK("RPKI-Testcase 3: Validation status for invalid ROA Beacon", + !strcmp(rpki, buf)); + } + + if(!strcmp(pfx, TEST4_PFX)) { + snprintf(buf, sizeof buf, "%s;%i,%s-%i", "invalid", TEST4_O_ASN, TEST4_PFX, TEST4_MAXL); + CHECK("RPKI-Testcase 4: Validation status for invalid ROA Beacon", + !strcmp(rpki, buf)); + } + + if(!strcmp(pfx, TEST5_PFX)) { + CHECK("RPKI-Testcase 5: Validation status for non-existing ROA Beacon", + !strcmp(rpki, "notfound")); + } + + if(!strcmp(pfx, TEST6_PFX)) { + CHECK("RPKI-Testcase 6: Validation status for non-existing ROA Beacon", + !strcmp(rpki, "notfound")); + } + buf[0] = '\0'; + } + } + } + + bgpstream_stop(bs); + + TEARDOWN; + return 0; +} +#endif + +int main() +{ +#if WITH_RTR + CHECK_SECTION("RPKI validation functional test", !test_RPKI_validation()); +#else + SKIPPED("RPKI validation functional test"); +#endif + return 0; +} diff --git a/test/bgpstream-test-utils-rtr.c b/test/bgpstream-test-utils-rtr.c new file mode 100644 index 0000000..6f34b50 --- /dev/null +++ b/test/bgpstream-test-utils-rtr.c @@ -0,0 +1,121 @@ +#include "bgpstream_test.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TEST_MIN_LEN 24 +#define TEST_MAX_LEN 24 +#define TEST_SOCKET NULL +#define TEST_ASN 12654 +#define TEST_IP_ADDR "93.175.146.0\0" + +#define IPV4_TEST_PFX_A "192.0.43.0/31" +#define TEST_PFX_MAX_LEN 31 +#define TEST_PFX_ASN 12340 + +#define TEST_RPKI_VALIDATOR_URL "rpki-validator.realmv6.org" +#define TEST_RPKI_VALIDATOR_PORT "8282" + +#ifdef WITH_RTR +int test_rtr_validation() +{ + cfg_tr = bgpstream_rtr_start_connection(TEST_RPKI_VALIDATOR_URL, + TEST_RPKI_VALIDATOR_PORT, NULL, NULL, + NULL, NULL, NULL, NULL); + struct pfx_table *pfxt = cfg_tr->groups[0].sockets[0]->pfx_table; + + struct pfx_record pfx_v4; + char ipv4_address[INET_ADDRSTRLEN]; + pfx_v4.min_len = TEST_MIN_LEN; + pfx_v4.max_len = TEST_MAX_LEN; + pfx_v4.socket = TEST_SOCKET; + pfx_v4.asn = TEST_ASN; + strcpy(ipv4_address, TEST_IP_ADDR); + lrtr_ip_str_to_addr(ipv4_address, &pfx_v4.prefix); + pfx_table_remove(pfxt, &pfx_v4); + + struct pfx_record pfx_v6; + char ipv6_address[INET6_ADDRSTRLEN]; + pfx_v6.min_len = 48; + pfx_v6.max_len = 48; + pfx_v6.socket = NULL; + pfx_v6.asn = 12654; + strcpy(ipv6_address, "2001:7fb:fd02::\0"); + lrtr_ip_str_to_addr(ipv6_address, &pfx_v6.prefix); + pfx_table_remove(pfxt, &pfx_v6); + + struct reasoned_result res; + + CHECK("RTR: Add a valid pfx_record to pfx_table", + pfx_table_add(pfxt, &pfx_v4) == PFX_SUCCESS); + res = bgpstream_rtr_validate_reason(cfg_tr, pfx_v4.asn, ipv4_address, + pfx_v4.max_len); + CHECK("RTR: Compare valid IPv4 ROA with validation result", + res.result == BGP_PFXV_STATE_VALID); + + CHECK("RTR: Add a valid pfx_record to pfx_table", + pfx_table_add(pfxt, &pfx_v6) == PFX_SUCCESS); + res = bgpstream_rtr_validate_reason(cfg_tr, pfx_v6.asn, ipv6_address, + pfx_v6.max_len); + CHECK("RTR: Compare valid IPv6 ROA with validation result", + res.result == BGP_PFXV_STATE_VALID); + + res = bgpstream_rtr_validate_reason(cfg_tr, 196615, ipv4_address, + pfx_v4.max_len); + CHECK("RTR: Compare invalid (asn) IPv4 ROA with validation result", + res.result == BGP_PFXV_STATE_INVALID); + + res = bgpstream_rtr_validate_reason(cfg_tr, 196615, ipv6_address, + pfx_v6.max_len); + CHECK("RTR: Compare invalid (asn) IPv6 ROA with validation result", + res.result == BGP_PFXV_STATE_INVALID); + + res = bgpstream_rtr_validate_reason(cfg_tr, pfx_v4.asn, ipv4_address, 30); + CHECK("RTR: Compare invalid (max len) IPv4 ROA with validation result", + res.result == BGP_PFXV_STATE_INVALID); + + res = bgpstream_rtr_validate_reason(cfg_tr, pfx_v6.asn, ipv6_address, 50); + CHECK("RTR: Compare invalid (max len) IPv6 ROA with validation result", + res.result == BGP_PFXV_STATE_INVALID); + + pfx_v4.asn = 12345; + lrtr_ip_str_to_addr("84.205.83.0\0", &pfx_v4.prefix); + pfx_table_remove(pfxt, &pfx_v4); + res = bgpstream_rtr_validate_reason(cfg_tr, 12345, "84.205.83.0\0", + pfx_v4.max_len); + CHECK("RTR: Compare none existend IPv4 ROA with validation result", + res.result == BGP_PFXV_STATE_NOT_FOUND); + + pfx_v6.asn = 12345; + lrtr_ip_str_to_addr("2001:7fb:ff03::\0", &pfx_v6.prefix); + pfx_table_remove(pfxt, &pfx_v6); + res = bgpstream_rtr_validate_reason(cfg_tr, 12345, "2001:7fb:ff03::\0", + pfx_v6.max_len); + CHECK("RTR: Compare none existend IPv6 ROA with validation result", + res.result == BGP_PFXV_STATE_NOT_FOUND); + + free(res.reason); + bgpstream_rtr_close_connection(cfg_tr); + + return 0; +} + +#endif + +int main() +{ +#ifdef WITH_RTR + CHECK_SECTION("RTRLIB VALIDATION", test_rtr_validation() == 0); +#else + SKIPPED("RPKI validation unit test"); +#endif + return 0; +} diff --git a/tools/bgpreader.c b/tools/bgpreader.c index 5ae2d25..bf19f7b 100644 --- a/tools/bgpreader.c +++ b/tools/bgpreader.c @@ -43,6 +43,8 @@ #define PEERASN_CMD_CNT 1000 #define WINDOW_CMD_CNT 1024 #define OPTION_CMD_CNT 1024 +#define RTR_CMD_CNT 5 +#define RTR_MAX_CNT 2 #define BGPSTREAM_RECORD_OUTPUT_FORMAT \ "# Record format:\n" \ "# |||||\n" \ @@ -152,6 +154,8 @@ static void usage() { " -m print info for each BGP valid record in bgpdump -m format\n" " -r print info for each BGP record (used mostly for debugging BGPStream)\n" " -i print format information before output\n" + " -R ,[,,,]\n" + " enable RTR-validation with a specified cache-server via TCP or SSH" "\n" " -h print this help menu\n" "* denotes an option that can be given multiple times\n" @@ -163,6 +167,7 @@ static void usage() { static void print_bs_record(bgpstream_record_t *bs_record); static int print_elem(bgpstream_record_t *bs_record, bgpstream_elem_t *elem); static void print_rib_control_message(bgpstream_record_t *bs_record); +static void print_err_message(int args, char *minmax, char* type); int main(int argc, char *argv[]) { @@ -198,6 +203,16 @@ int main(int argc, char *argv[]) char *interface_options[OPTION_CMD_CNT]; int interface_options_cnt = 0; + char *rtr[RTR_CMD_CNT] = { NULL }; + int rtr_cnt = 2; + int rtr_cnt_arg = 0; + + char *host; + char *port; + char *ssh_user; + char *ssh_hostkey; + char *ssh_privatekey; + int rib_period = 0; int live = 0; int output_info = 0; @@ -229,7 +244,7 @@ int main(int argc, char *argv[]) } while (prevoptind = optind, - (opt = getopt (argc, argv, "d:o:p:c:t:w:j:k:y:P:lrmeivh?")) >= 0) + (opt = getopt (argc, argv, "R:d:o:p:c:t:w:j:k:y:P:lrmeivh?")) >= 0) { if (optind == prevoptind + 2 && (optarg == NULL || *optarg == '-') ) { opt = ':'; @@ -237,6 +252,40 @@ int main(int argc, char *argv[]) } switch (opt) { + +case 'R': +#ifndef WITH_RTR + fprintf(stderr, "ERROR: Could not validate the BGPStream because RTRlib " + "is not installed\n"); + exit(-1); +#else + host = strsep(&optarg, ","); + port = strsep(&optarg, ","); + + if (!host || !port) { + print_err_message(RTR_MAX_CNT, "minimum", "arguments (-R)"); + } + +#ifdef WITH_SSH + ssh_user = strsep(&optarg, ","); + ssh_hostkey = strsep(&optarg, ","); + ssh_privatekey = strsep(&optarg, ","); + if (ssh_user != NULL && (ssh_hostkey == NULL || ssh_privatekey == NULL)) { + fprintf(stderr, "ERROR: The SSH-values are incomplete\n"); + exit(-1); + } +#else + if (rtr[2] != NULL || rtr[3] != NULL || rtr[4] != NULL) { + fprintf(stderr, "Warning: RTR-Library is not compiled with " + "SSH-Support, TCP is used instead\n"); + } +#endif + + bgpstream_set_rtr_config(bs, host, port, ssh_user, ssh_hostkey, + ssh_privatekey, 1); +#endif + break; + case 'p': if(projects_cnt == PROJECT_CMD_CNT) { @@ -606,6 +655,15 @@ int main(int argc, char *argv[]) static char record_buf[65536]; +static void print_err_message(int args, char *minmax, char *type) +{ + fprintf(stderr, "ERROR: A %s of %d %s %s be specified on " + "the command line\n", + minmax, args, type, (minmax == "maximum") ? "can" : "must"); + usage(); + exit(-1); +} + static void print_bs_record(bgpstream_record_t *bs_record) { assert(bs_record);