From: pcarana Date: Fri, 10 May 2019 18:06:58 +0000 (-0500) Subject: Remove some TODOs and re-classify others X-Git-Tag: v0.0.2~35^2~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=44bbf8d611877b0eb577c7b2de818882a25e071e;p=thirdparty%2FFORT-validator.git Remove some TODOs and re-classify others -Move directory loading and file filtering to common.h. -Accept a TALs directory in configuration. -Don't check for overriden PDUs if there's only 1 delta to send. -Add roa_table merge function, this allows to merge distinct roa tables so that the VRPs base can have all the data from multiple TALs. -Remove 'loop' var (isn't necessary) and make 'sigaction act' a global var. --- diff --git a/src/common.c b/src/common.c index e210c1a1..07627fdb 100644 --- a/src/common.c +++ b/src/common.c @@ -1,7 +1,9 @@ #include "common.h" #include +#include #include +#include #include "log.h" int @@ -84,3 +86,75 @@ close_thread(pthread_t thread, char const *what) return error; } +static int +process_file(char const *dir_name, char const *file_name, char const *file_ext, + process_file_cb cb, void *arg) +{ + char *ext, *fullpath, *tmp; + int error; + + if (file_ext != NULL) { + ext = strrchr(file_name, '.'); + /* Ignore file if extension isn't the expected */ + if (ext == NULL || strcmp(ext, file_ext) != 0) + return 0; + } + + /* Get the full file path */ + tmp = strdup(dir_name); + if (tmp == NULL) + return -pr_errno(errno, "Couldn't create temporal char"); + + tmp = realloc(tmp, strlen(tmp) + 1 + strlen(file_name) + 1); + if (tmp == NULL) + return -pr_errno(errno, "Couldn't reallocate temporal char"); + + strcat(tmp, "/"); + strcat(tmp, file_name); + fullpath = realpath(tmp, NULL); + if (fullpath == NULL) { + free(tmp); + return -pr_errno(errno, + "Error getting real path for file '%s' at dir '%s'", + dir_name, file_name); + } + + error = cb(fullpath, arg); + free(tmp); + free(fullpath); + return error; +} + +int +process_dir_files(char const *location, char const *file_ext, + process_file_cb cb, void *arg) +{ + DIR *dir_loc; + struct dirent *dir_ent; + int error; + + dir_loc = opendir(location); + if (dir_loc == NULL) { + error = -pr_errno(errno, "Couldn't open dir %s", location); + goto end; + } + + errno = 0; + while ((dir_ent = readdir(dir_loc)) != NULL) { + error = process_file(location, dir_ent->d_name, file_ext, cb, + arg); + if (error) { + pr_err("The error was at file %s", dir_ent->d_name); + goto close_dir; + } + errno = 0; + } + if (errno) { + pr_err("Error reading dir %s", location); + error = -errno; + } +close_dir: + closedir(dir_loc); +end: + return error; +} diff --git a/src/common.h b/src/common.h index 469a4c85..c13756a8 100644 --- a/src/common.h +++ b/src/common.h @@ -35,4 +35,7 @@ void rwlock_unlock(pthread_rwlock_t *); /** Also boilerplate. */ int close_thread(pthread_t thread, char const *what); +typedef int (*process_file_cb)(char const *, void *); +int process_dir_files(char const *, char const *, process_file_cb, void *); + #endif /* SRC_RTR_COMMON_H_ */ diff --git a/src/config.c b/src/config.c index 9221debb..a05239d6 100644 --- a/src/config.c +++ b/src/config.c @@ -26,7 +26,7 @@ * Assuming you don't need to create a data type, that should be all. */ struct rpki_config { - /** TAL file name or directory. TODO (urgent) support directories */ + /** TAL file name or directory. */ char *tal; /** Path of our local clone of the repository */ char *local_repository; @@ -143,7 +143,7 @@ static const struct option_field options[] = { .name = "tal", .type = >_string, .offset = offsetof(struct rpki_config, tal), - .doc = "Path to the TAL file", + .doc = "Path to the TAL file or TALs directory", .arg_doc = "", }, { .id = 'r', @@ -497,7 +497,7 @@ validate_config(void) { return (rpki_config.tal != NULL) ? 0 - : pr_err("The TAL file (--tal) is mandatory."); + : pr_err("The TAL file/directory (--tal) is mandatory."); } static void diff --git a/src/console_handler.c b/src/console_handler.c index e10a34e3..2c87072c 100644 --- a/src/console_handler.c +++ b/src/console_handler.c @@ -27,6 +27,8 @@ validate_into_console(void) { struct validation_handler handler; + handler.merge = NULL; + handler.merge_arg = NULL; handler.reset = NULL; handler.traverse_down = NULL; handler.traverse_up = NULL; diff --git a/src/object/tal.c b/src/object/tal.c index c0691577..70abe80b 100644 --- a/src/object/tal.c +++ b/src/object/tal.c @@ -20,6 +20,8 @@ #include "object/certificate.h" #include "rsync/rsync.h" +#define TAL_FILE_EXTENSION ".tal" + struct uris { char **array; /* This is an array of string pointers. */ unsigned int count; @@ -328,7 +330,11 @@ handle_tal_uri(struct tal *tal, struct rpki_uri const *uri, void *arg) break; } } else { - error = 1; + error = vhandler_merge(arg); + if (error) + error = ENSURE_NEGATIVE(error); + else + error = 1; } end: validation_destroy(state); @@ -336,29 +342,53 @@ end: validation_destroy(state); return error; } -int -perform_standalone_validation(struct validation_handler *handler) +static int +do_file_validation(char const *tal_file, void *arg) { struct tal *tal; int error; - fnstack_init(); - fnstack_push(config_get_tal()); + fnstack_push(tal_file); - error = tal_load(config_get_tal(), &tal); + error = tal_load(tal_file, &tal); if (error) goto end; if (config_get_shuffle_tal_uris()) tal_shuffle_uris(tal); - error = foreach_uri(tal, handle_tal_uri, handler); + error = foreach_uri(tal, handle_tal_uri, arg); if (error > 0) error = 0; else if (error == 0) - error = pr_err("None of the URIs of the TAL yielded a successful traversal."); + error = pr_err("None of the URIs of the TAL '%s' yielded a successful traversal.", + tal_file); end: tal_destroy(tal); fnstack_pop(); + return error; +} + +int +perform_standalone_validation(struct validation_handler *handler) +{ + char const *config_tal; + struct stat attr; + int error; + + config_tal = config_get_tal(); + error = stat(config_tal, &attr); + if (error) { + pr_errno(errno, "Error reading path '%s'", config_tal); + return -errno; + } + + fnstack_init(); + if (S_ISDIR(attr.st_mode) == 0) + error = do_file_validation(config_tal, handler); + else + error = process_dir_files(config_tal, TAL_FILE_EXTENSION, + do_file_validation, handler); + fnstack_cleanup(); return error; } diff --git a/src/rtr/db/roa_table.c b/src/rtr/db/roa_table.c index 9c3aae39..28f0c12e 100644 --- a/src/rtr/db/roa_table.c +++ b/src/rtr/db/roa_table.c @@ -100,6 +100,55 @@ add_roa(struct roa_table *table, struct hashable_roa *new) return 0; } +static int +duplicate_roa(struct roa_table *dst, struct hashable_roa *new) +{ + struct vrp vrp; + struct ipv4_prefix prefix4; + struct ipv6_prefix prefix6; + + vrp = new->data; + switch (vrp.addr_fam) { + case AF_INET: + prefix4.addr = vrp.prefix.v4; + prefix4.len = vrp.prefix_length; + return rtrhandler_handle_roa_v4(dst, vrp.asn, &prefix4, + vrp.max_prefix_length); + case AF_INET6: + prefix6.addr = vrp.prefix.v6; + prefix6.len = vrp.prefix_length; + return rtrhandler_handle_roa_v6(dst, vrp.asn, &prefix6, + vrp.max_prefix_length); + } + return pr_crit("Unknown address family: %d", vrp.addr_fam); +} + +static int +roa_table_merge(struct roa_table *dst, struct roa_table *src) +{ + struct hashable_roa *node, *tmp, *found; + int error; + + /** Must look for it due to the new mem allocation */ + HASH_ITER(hh, src->roas, node, tmp) { + HASH_FIND(hh, dst->roas, &node->data, sizeof(node->data), + found); + if (found != NULL) + continue; + error = duplicate_roa(dst, node); + if (error) + return error; + } + + return 0; +} + +int +rtrhandler_merge(struct roa_table *dst, struct roa_table *src) +{ + return roa_table_merge(dst, src); +} + void roa_table_remove_roa(struct roa_table *table, struct vrp *del) { diff --git a/src/rtr/db/roa_table.h b/src/rtr/db/roa_table.h index 9c18e0f5..86541d1f 100644 --- a/src/rtr/db/roa_table.h +++ b/src/rtr/db/roa_table.h @@ -17,6 +17,7 @@ int rtrhandler_handle_roa_v4(struct roa_table *, uint32_t, struct ipv4_prefix const *, uint8_t); int rtrhandler_handle_roa_v6(struct roa_table *, uint32_t, struct ipv6_prefix const *, uint8_t); +int rtrhandler_merge(struct roa_table *, struct roa_table *); int compute_deltas(struct roa_table *, struct roa_table *, struct deltas **); diff --git a/src/rtr/db/vrps.c b/src/rtr/db/vrps.c index 182f29bd..3a097139 100644 --- a/src/rtr/db/vrps.c +++ b/src/rtr/db/vrps.c @@ -93,6 +93,12 @@ vrps_destroy(void) pthread_rwlock_destroy(&lock); /* Nothing to do with error code */ } +static int +__merge(void *dst, void *src) +{ + return rtrhandler_merge(dst, src); +} + static int __reset(void *arg) { @@ -116,7 +122,7 @@ __handle_roa_v6(uint32_t as, struct ipv6_prefix const * prefix, static int __perform_standalone_validation(struct roa_table **result) { - struct roa_table *roas; + struct roa_table *roas, *global_roas; struct validation_handler validation_handler; int error; @@ -124,6 +130,14 @@ __perform_standalone_validation(struct roa_table **result) if (roas == NULL) return pr_enomem(); + global_roas = roa_table_create(); + if (global_roas == NULL) { + roa_table_destroy(roas); + return pr_enomem(); + } + + validation_handler.merge = __merge; + validation_handler.merge_arg = global_roas; validation_handler.reset = __reset; validation_handler.traverse_down = NULL; validation_handler.traverse_up = NULL; @@ -132,12 +146,13 @@ __perform_standalone_validation(struct roa_table **result) validation_handler.arg = roas; error = perform_standalone_validation(&validation_handler); + roa_table_destroy(roas); if (error) { - roa_table_destroy(roas); + roa_table_destroy(global_roas); return error; } - *result = roas; + *result = global_roas; return 0; } diff --git a/src/rtr/pdu_sender.c b/src/rtr/pdu_sender.c index 3dd12cbf..26cb6285 100644 --- a/src/rtr/pdu_sender.c +++ b/src/rtr/pdu_sender.c @@ -79,7 +79,7 @@ length_end_of_data_pdu(struct end_of_data_pdu *pdu) return len; } -/* TODO Include Router Key PDU serials */ +/* TODO (next iteration) Include Router Key PDU serials */ /** * static uint32_t * length_router_key_pdu(struct router_key_pdu *pdu) @@ -322,6 +322,11 @@ send_pdus_delta(struct sender_common *common) struct vrp_node *ptr; int error; + /** Just 1 delta to send, no need to check for overridden PDUs */ + if (*common->start_serial == *common->end_serial - 1) + return vrps_foreach_delta_roa(*common->start_serial, + *common->end_serial, send_prefix_pdu, common); + SLIST_INIT(&filtered_vrps); error = vrps_foreach_delta_roa(*common->start_serial, *common->end_serial, vrp_ovrd_remove, &filtered_vrps); diff --git a/src/rtr/rtr.c b/src/rtr/rtr.c index b2cf7fdc..9ad8dbd8 100644 --- a/src/rtr/rtr.c +++ b/src/rtr/rtr.c @@ -22,8 +22,7 @@ /* TODO (next iteration) Support both RTR v0 and v1 */ #define RTR_VERSION_SUPPORTED RTR_V0 -/* TODO (urgent) this needs to be atomic */ -volatile bool loop; +struct sigaction act; /* * Arguments that the server socket thread will send to the client @@ -181,7 +180,7 @@ client_thread_cb(void *param_void) int err; uint8_t rtr_version; - while (loop) { /* For each PDU... */ + while (true) { /* For each PDU... */ err = pdu_load(param->client_fd, &pdu, &meta, &rtr_version); if (err) return end_client(param->client_fd, NULL, NULL); @@ -285,7 +284,6 @@ signal_handler(int signal, siginfo_t *info, void *param) static int init_signal_handler(void) { - struct sigaction act; int error; memset(&act, 0, sizeof act); @@ -293,7 +291,6 @@ init_signal_handler(void) act.sa_flags = SA_SIGINFO; act.sa_sigaction = signal_handler; - /* TODO is this really legal? @act might need to be global. */ error = sigaction(SIGINT, &act, NULL); if (error) { pr_errno(errno, "Error initializing signal handler"); @@ -308,7 +305,6 @@ wait_threads(void) { struct thread_node *ptr; - loop = false; while (!SLIST_EMPTY(&threads)) { ptr = SLIST_FIRST(&threads); SLIST_REMOVE_HEAD(&threads, next); @@ -343,7 +339,6 @@ rtr_listen(void) goto revert_server_socket; /* Init global vars */ - loop = true; SLIST_INIT(&threads); error = init_signal_handler(); diff --git a/src/slurm/slurm_loader.c b/src/slurm/slurm_loader.c index 71bec6a4..fe9dbe5a 100644 --- a/src/slurm/slurm_loader.c +++ b/src/slurm/slurm_loader.c @@ -1,97 +1,29 @@ #include "slurm_loader.h" -#include -#include #include #include -#include #include "log.h" #include "config.h" +#include "common.h" #include "slurm/slurm_db.h" #include "slurm/slurm_parser.h" #define SLURM_FILE_EXTENSION ".slurm" -static int -single_slurm_load(const char *dir_name, const char *file_name) -{ - char *ext, *fullpath, *tmp; - int error; - - ext = strrchr(file_name, '.'); - /* Ignore file if extension isn't the expected */ - if (ext == NULL || strcmp(ext, SLURM_FILE_EXTENSION) != 0) - return 0; - - /* Get the full file path */ - tmp = strdup(dir_name); - if (tmp == NULL) - return -pr_errno(errno, - "Couldn't create temporal char for SLURM"); - - tmp = realloc(tmp, strlen(tmp) + 1 + strlen(file_name) + 1); - if (tmp == NULL) - return -pr_errno(errno, - "Couldn't reallocate temporal char for SLURM"); - - strcat(tmp, "/"); - strcat(tmp, file_name); - fullpath = realpath(tmp, NULL); - if (fullpath == NULL) { - free(tmp); - return -pr_errno(errno, - "Error getting real path for file '%s' at dir '%s'", - dir_name, file_name); - } - - error = slurm_parse(fullpath); - free(tmp); - free(fullpath); - return error; -} - static int slurm_load(bool *loaded) { - DIR *dir_loc; - struct dirent *dir_ent; - char const *slurm_dir; - int error; - /* Optional configuration */ *loaded = false; - slurm_dir = config_get_slurm_location(); - if (slurm_dir == NULL) + if (config_get_slurm_location() == NULL) return 0; *loaded = true; slurm_db_init(); - dir_loc = opendir(slurm_dir); - if (dir_loc == NULL) { - error = -pr_errno(errno, "Couldn't open dir %s", slurm_dir); - goto end; - } - - errno = 0; - while ((dir_ent = readdir(dir_loc)) != NULL) { - error = single_slurm_load(slurm_dir, dir_ent->d_name); - if (error) { - pr_err("The error was at SLURM file %s", - dir_ent->d_name); - goto close_dir; - } - errno = 0; - } - if (errno) { - pr_err("Error reading dir %s", slurm_dir); - error = -errno; - } -close_dir: - closedir(dir_loc); -end: - return error; + return process_dir_files(config_get_slurm_location(), + SLURM_FILE_EXTENSION, slurm_parse, NULL); } static void @@ -167,7 +99,7 @@ slurm_apply(struct roa_table *base) error = slurm_pfx_assertions_apply(base); - /** TODO Apply BGPsec filters and assertions */ + /** TODO (next iteration) Apply BGPsec filters and assertions */ cleanup: slurm_cleanup(); diff --git a/src/slurm/slurm_parser.c b/src/slurm/slurm_parser.c index ce6c1d86..90dd4c61 100644 --- a/src/slurm/slurm_parser.c +++ b/src/slurm/slurm_parser.c @@ -35,7 +35,7 @@ static int handle_json(json_t *); int -slurm_parse(char const *location) +slurm_parse(char const *location, void *arg) { json_t *json_root; json_error_t json_error; @@ -292,14 +292,12 @@ set_router_pub_key(json_t *object, bool is_assertion, return pr_err("'%s' couldn't be decoded", str_encoded); /* - * TODO Validate that 'routerPublicKey' is: "the equivalent to the - * subjectPublicKeyInfo value of the router certificate's public key, - * as described in [RFC8208]. This is the full ASN.1 DER encoding of - * the subjectPublicKeyInfo, including the ASN.1 tag and length values + * TODO (next iteration) Reuse the functions to validate that + * 'routerPublicKey' is: "the equivalent to the subjectPublicKeyInfo + * value of the router certificate's public key, as described in + * [RFC8208]. This is the full ASN.1 DER encoding of the + * subjectPublicKeyInfo, including the ASN.1 tag and length values * of the subjectPublicKeyInfo SEQUENCE. - */ - /* - * TODO When the merge is done, reuse the functions at fort-validator * * #include * #include "asn1/decode.h" diff --git a/src/slurm/slurm_parser.h b/src/slurm/slurm_parser.h index 6a1b0ef8..cb64f035 100644 --- a/src/slurm/slurm_parser.h +++ b/src/slurm/slurm_parser.h @@ -31,7 +31,7 @@ struct slurm_bgpsec { }; -int slurm_parse(char const *); +int slurm_parse(char const *, void *); #endif /* SRC_SLURM_SLURM_PARSER_H_ */ diff --git a/src/validation_handler.c b/src/validation_handler.c index 971af061..65633308 100644 --- a/src/validation_handler.c +++ b/src/validation_handler.c @@ -4,6 +4,13 @@ #include "log.h" #include "thread_var.h" +int +vhandler_merge(struct validation_handler *handler) +{ + return (handler->merge != NULL) ? + handler->merge(handler->merge_arg, handler->arg) : 0; +} + int vhandler_reset(struct validation_handler *handler) { diff --git a/src/validation_handler.h b/src/validation_handler.h index 72ca4260..5b21be54 100644 --- a/src/validation_handler.h +++ b/src/validation_handler.h @@ -7,6 +7,8 @@ struct validation_handler { /* All of these can be NULL. */ + int (*merge)(void *, void *); + void *merge_arg; int (*reset)(void *); int (*traverse_down)(struct rfc5280_name *, void *); int (*traverse_up)(void *); @@ -17,6 +19,7 @@ struct validation_handler { void *arg; }; +int vhandler_merge(struct validation_handler *); int vhandler_reset(struct validation_handler *); int vhandler_traverse_down(struct rfc5280_name *); int vhandler_traverse_up(void); diff --git a/test/rtr/db/roa_table_test.c b/test/rtr/db/roa_table_test.c index 6b3850f8..31c6d3e3 100644 --- a/test/rtr/db/roa_table_test.c +++ b/test/rtr/db/roa_table_test.c @@ -156,20 +156,120 @@ START_TEST(test_basic) for (i = 0; i < TOTAL_ROAS; i++) ck_assert_int_eq(true, roas_found[i]); - roa_table_put(table); + roa_table_destroy(table); +} +END_TEST + +START_TEST(test_merge) +{ + struct ipv4_prefix prefix4; + struct ipv6_prefix prefix6; + struct roa_table *left, *right, *merged; + array_index i; + int left_count, right_count, total_merged; + + left = roa_table_create(); + ck_assert_ptr_ne(NULL, left); + right = roa_table_create(); + ck_assert_ptr_ne(NULL, right); + merged = roa_table_create(); + ck_assert_ptr_ne(NULL, merged); + + prefix4.addr.s_addr = ADDR1; + prefix4.len = 24; + prefix6.addr.s6_addr32[0] = htonl(0x20010DB8); + prefix6.addr.s6_addr32[1] = 0; + prefix6.addr.s6_addr32[2] = 0; + prefix6.addr.s6_addr32[3] = htonl(0x00000001); + prefix6.len = 120; + + left_count = 0; + right_count = 0; + total_merged = 0; + + /** Add the same roas on both tables*/ + ck_assert_int_eq(0, rtrhandler_handle_roa_v4(left, 10, &prefix4, 32)); + left_count++; + ck_assert_int_eq(0, rtrhandler_handle_roa_v4(right, 10, &prefix4, 32)); + right_count++; + ck_assert_int_eq(0, rtrhandler_handle_roa_v4(left, 11, &prefix4, 32)); + left_count++; + ck_assert_int_eq(0, rtrhandler_handle_roa_v4(right, 11, &prefix4, 32)); + right_count++; + + /** And add distinct roas on each table */ + prefix4.addr.s_addr = ADDR2; + ck_assert_int_eq(0, rtrhandler_handle_roa_v4(left, 10, &prefix4, 32)); + left_count++; + + prefix4.addr.s_addr = ADDR1; + prefix4.len = 25; + ck_assert_int_eq(0, rtrhandler_handle_roa_v4(right, 10, &prefix4, 32)); + right_count++; + + prefix4.len = 24; + ck_assert_int_eq(0, rtrhandler_handle_roa_v4(left, 10, &prefix4, 30)); + left_count++; + + /* IPv6 */ + ck_assert_int_eq(0, rtrhandler_handle_roa_v6(right, 10, &prefix6, 128)); + right_count++; + ck_assert_int_eq(0, rtrhandler_handle_roa_v6(left, 11, &prefix6, 128)); + left_count++; + + prefix6.addr.s6_addr32[3] = htonl(0x00000002); + ck_assert_int_eq(0, rtrhandler_handle_roa_v6(right, 10, &prefix6, 128)); + right_count++; + + prefix6.addr.s6_addr32[3] = htonl(0x00000001); + prefix6.len = 121; + ck_assert_int_eq(0, rtrhandler_handle_roa_v6(left, 10, &prefix6, 128)); + left_count++; + + prefix6.len = 120; + ck_assert_int_eq(0, rtrhandler_handle_roa_v6(right, 10, &prefix6, 127)); + right_count++; + + /** Do the merge */ + ck_assert_int_eq(0, rtrhandler_merge(merged, left)); + ck_assert_int_eq(0, rtrhandler_merge(merged, right)); + + /** + * Must have: + * count(left) + count(right) - 2 (duplicated elements) + */ + total_merged = left_count + right_count - 2; + ck_assert_int_eq(total_merged, TOTAL_ROAS); + + /* Check table contents and that merged table has new memory refs */ + roa_table_destroy(left); + roa_table_destroy(right); + + memset(roas_found, 0, sizeof(roas_found)); + total_found = 0; + ck_assert_int_eq(0, roa_table_foreach_roa(merged, foreach_cb, NULL)); + ck_assert_int_eq(TOTAL_ROAS, total_found); + for (i = 0; i < TOTAL_ROAS; i++) + ck_assert_int_eq(true, roas_found[i]); + + roa_table_destroy(merged); } END_TEST Suite *pdu_suite(void) { Suite *suite; - TCase *core; + TCase *core, *merge; core = tcase_create("Core"); tcase_add_test(core, test_basic); + merge = tcase_create("Merge"); + tcase_add_test(core, test_merge); + suite = suite_create("ROA Table"); suite_add_tcase(suite, core); + suite_add_tcase(suite, merge); return suite; }