diff options
Diffstat (limited to '')
-rw-r--r-- | tools/rpki-rov.c | 231 |
1 files changed, 231 insertions, 0 deletions
diff --git a/tools/rpki-rov.c b/tools/rpki-rov.c new file mode 100644 index 0000000..4089a88 --- /dev/null +++ b/tools/rpki-rov.c @@ -0,0 +1,231 @@ +/* + * This file is part of RTRlib. + * + * This file is subject to the terms and conditions of the MIT license. + * See the file LICENSE in the top level directory for more details. + * + * Website: http://rtrlib.realmv6.org/ + */ + +#include "rtrlib/rtrlib.h" + +#include <arpa/inet.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +const int connection_timeout = 20; +enum rtr_mgr_status connection_status = -1; + +static void connection_status_callback(const struct rtr_mgr_group *group __attribute__((unused)), + enum rtr_mgr_status status, + const struct rtr_socket *socket __attribute__((unused)), + void *data __attribute__((unused))) +{ + if (status == RTR_MGR_ERROR) + connection_status = status; +} + +static int connection_error(enum rtr_mgr_status status) +{ + if (status == RTR_MGR_ERROR) { + /* + * Wait for input before printing error to avoid "broken pipe" error + * while communicating with the Python program. + */ + char input[256]; + + if (fgets(input, 256, stdin)) + ; + printf("error\n"); + fflush(stdout); + return 1; + } + return 0; +} + +static int str_to_int(const char *str, int *value) +{ + errno = 0; + int tmp = strtol(str, NULL, 10); + + if (errno != 0) + return 1; + + *value = tmp; + return 0; +} + +int main(int argc, char *argv[]) +{ + /* check arguments, need hostname/IP and port of cache-server */ + if (argc < 3) { + printf("Usage: %s [host] [port]\n", argv[0]); + return EXIT_FAILURE; + } + + struct tr_socket tr_tcp; + struct tr_tcp_config tcp_config = {argv[1], argv[2], NULL, NULL, NULL, 0}; + struct rtr_socket rtr_tcp; + struct rtr_mgr_config *conf; + struct rtr_mgr_group groups[1]; + + /* init a TCP transport and create rtr socket */ + tr_tcp_init(&tcp_config, &tr_tcp); + rtr_tcp.tr_socket = &tr_tcp; + + /* create a rtr_mgr_group array with 1 element */ + groups[0].sockets = malloc(1 * sizeof(struct rtr_socket *)); + groups[0].sockets_len = 1; + groups[0].sockets[0] = &rtr_tcp; + groups[0].preference = 1; + + if (rtr_mgr_init(&conf, groups, 1, 30, 600, 600, NULL, NULL, &connection_status_callback, NULL) < 0) + return EXIT_FAILURE; + + rtr_mgr_start(conf); + + char input[256]; + int sleep_counter = 0; + + /* wait till at least one rtr_mgr_group is synchronized with server */ + while (!rtr_mgr_conf_in_sync(conf)) { + if (connection_error(connection_status)) + return EXIT_FAILURE; + + sleep(1); + sleep_counter++; + if (sleep_counter >= connection_timeout) { + /* + * Wait for input before printing "timeout", + * to avoid "broken pipee error while communicating + * with the Python program + */ + if (fgets(input, 256, stdin)) + ; + printf("timeout\n"); + fflush(stdout); + return EXIT_FAILURE; + } + } + + int counter; + /* loop for input */ + while (1) { + int input_len; + int spaces; + + /* recheck connection, exit on failure */ + if (connection_error(connection_status)) + return EXIT_FAILURE; + + /* try reading from stdin, exit on failure */ + if (!fgets(input, 256, stdin)) { + printf("input error\n"); + return EXIT_FAILURE; + } + + /* remove newline, if present */ + input_len = strlen(input) - 1; + if (input[input_len] == '\n') + input[input_len] = '\0'; + + /* check if there are exactly 3 arguments */ + spaces = 0; + for (counter = 0; counter < input_len; counter++) { + if (input[counter] == ' ' && input[counter + 1] != ' ' && input[counter + 1] != '\0' && + counter != 0) + spaces++; + } + + /* check input matching pattern */ + if (spaces != 2) { + printf("Arguments required: IP Mask ASN\n"); + fflush(stdout); + continue; + } + + char delims[] = " "; + char *input_tok = NULL; + + input_tok = strtok(input, delims); + struct lrtr_ip_addr pref; + char ip[INET6_ADDRSTRLEN]; + + if (strlen(input_tok) > sizeof(ip) - 1) { + fprintf(stderr, "Error: Invalid ip addr\n"); + continue; + } + + memset(ip, 0, sizeof(ip)); + strncpy(ip, input_tok, sizeof(ip) - 1); + + if (lrtr_ip_str_to_addr(ip, &pref) != 0) { + fprintf(stderr, "Error: Invalid ip addr\n"); + continue; + } + + input_tok = strtok(NULL, delims); + int mask; + + if (str_to_int(input_tok, &mask)) { + fprintf(stderr, "Error: Invalid mask\n"); + continue; + } + + input_tok = strtok(NULL, delims); + int asn; + + if (str_to_int(input_tok, &asn)) { + fprintf(stderr, "Error: Invalid asn\n"); + continue; + } + + enum pfxv_state result; + struct pfx_record *reason = NULL; + unsigned int reason_len = 0; + + /* do validation */ + pfx_table_validate_r(groups[0].sockets[0]->pfx_table, &reason, &reason_len, asn, &pref, mask, &result); + + int validity_code = -1; + /* translate validation result */ + if (result == BGP_PFXV_STATE_VALID) + validity_code = 0; + else if (result == BGP_PFXV_STATE_NOT_FOUND) + validity_code = 1; + else if (result == BGP_PFXV_STATE_INVALID) + validity_code = 2; + + /* IP Mask BGP-ASN| */ + printf("%s %d %d|", ip, mask, asn); + + /* ROA-ASN IP MaskMin MaskMax, ... */ + if (reason && (reason_len > 0)) { + unsigned int i; + + for (i = 0; i < reason_len; i++) { + char tmp[100]; + + lrtr_ip_addr_to_str(&reason[i].prefix, tmp, sizeof(tmp)); + printf("%u %s %u %u", reason[i].asn, tmp, reason[i].min_len, reason[i].max_len); + if ((i + 1) < reason_len) + printf(","); + } + } + + /* |validity_code */ + printf("|%d", validity_code); + + printf("\n"); + fflush(stdout); + } + + rtr_mgr_stop(conf); + rtr_mgr_free(conf); + free(groups[0].sockets); + + return EXIT_SUCCESS; +} |