From: pcarana Date: Tue, 14 May 2019 20:27:13 +0000 (-0500) Subject: Merge remote-tracking branch 'origin/slurm-use' into cleanup X-Git-Tag: v0.0.2~35 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=49014cc00742e0ffc05a2f1670b101ed42d638c2;p=thirdparty%2FFORT-validator.git Merge remote-tracking branch 'origin/slurm-use' into cleanup --- 49014cc00742e0ffc05a2f1670b101ed42d638c2 diff --cc src/clients.c index df5e6e1c,b107f4ba..d3d4288c --- a/src/clients.c +++ b/src/clients.c @@@ -3,13 -3,8 +3,9 @@@ #include #include "common.h" #include "log.h" - #include "data_structure/uthash.h" + #include "data_structure/uthash_nonfatal.h" +#include "rtr/pdu.h" - /* - * TODO uthash panics on memory allocations... - * http://troydhanson.github.io/uthash/userguide.html#_out_of_memory - */ #define SADDR_IN(addr) ((struct sockaddr_in *) addr) #define SADDR_IN6(addr) ((struct sockaddr_in6 *) addr) @@@ -71,10 -84,24 +67,16 @@@ clients_add(struct rtr_client *client rwlock_write_lock(&lock); - HASH_FIND_INT(table, &fd, old_client); + HASH_FIND_INT(table, &client->fd, old_client); if (old_client == NULL) { + errno = 0; HASH_ADD_INT(table, meat.fd, new_client); + if (errno) { + rwlock_unlock(&lock); + free(new_client); + return -pr_errno(errno, "Couldn't create client"); + } new_client = NULL; - } else { - /* - * Isn't ready to handle distinct version on clients - * reconnection, but for now there's no problem since only - * RTRv0 is supported. - */ - if (old_client->meat.rtr_version != rtr_version) - error = -ERTR_VERSION_MISMATCH; } rwlock_unlock(&lock); diff --cc src/rtr/db/roa_table.c index ab528e11,8f444783..eba04e96 --- a/src/rtr/db/roa_table.c +++ b/src/rtr/db/roa_table.c @@@ -99,6 -103,67 +102,67 @@@ add_roa(struct roa_table *table, struc 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) ++roa_table_remove_roa(struct roa_table *table, struct vrp const *del) + { + struct hashable_roa *ptr; + + HASH_FIND(hh, table->roas, del, sizeof(*del), ptr); + if (ptr != NULL) { + HASH_DELETE(hh, table->roas, ptr); + free(ptr); + } + } + int rtrhandler_handle_roa_v4(struct roa_table *table, uint32_t asn, struct ipv4_prefix const *prefix4, uint8_t max_length) diff --cc src/rtr/db/roa_table.h index 8bd0da2d,86541d1f..94aa7eb7 --- a/src/rtr/db/roa_table.h +++ b/src/rtr/db/roa_table.h @@@ -10,6 -10,7 +10,7 @@@ struct roa_table *roa_table_create(void void roa_table_destroy(struct roa_table *); int roa_table_foreach_roa(struct roa_table *, vrp_foreach_cb, void *); -void roa_table_remove_roa(struct roa_table *, struct vrp *); ++void roa_table_remove_roa(struct roa_table *, struct vrp const *); int rtrhandler_reset(struct roa_table *); int rtrhandler_handle_roa_v4(struct roa_table *, uint32_t, diff --cc src/rtr/db/vrps.c index b8292b95,3a097139..f84fec9a --- a/src/rtr/db/vrps.c +++ b/src/rtr/db/vrps.c @@@ -1,11 -1,15 +1,15 @@@ #include "vrps.h" #include -#include + #include +#include #include "clients.h" #include "common.h" + #include "validation_handler.h" + #include "data_structure/array_list.h" #include "object/tal.h" #include "rtr/db/roa_table.h" + #include "slurm/slurm_loader.h" /* * Storage of VRPs (term taken from RFC 6811 "Validated ROA Payload") and @@@ -139,9 -163,9 +160,9 @@@ __perform_standalone_validation(struct * calculated according to the new start. */ static void -resize_deltas_db(struct deltas_db *db, struct delta *start) +resize_deltas_db(struct deltas_db *db, struct delta_group *start) { - struct delta_group *tmp; - struct delta *tmp, *ptr; ++ struct delta_group *tmp, *ptr; db->len -= (start - db->array); while (db->len < db->capacity / 2) @@@ -151,7 -175,10 +172,10 @@@ pr_enomem(); return; } - memcpy(tmp, start, db->len * sizeof(struct delta)); + memcpy(tmp, start, db->len * sizeof(struct delta_group)); + /* Release memory allocated */ + for (ptr = db->array; ptr < start; ptr++) - deltas_destroy(ptr->deltas); ++ deltas_put(ptr->deltas); free(db->array); db->array = tmp; } diff --cc src/rtr/err_pdu.c index 3be96ef0,c18b2302..f6172b6d --- a/src/rtr/err_pdu.c +++ b/src/rtr/err_pdu.c @@@ -4,93 -4,21 +4,99 @@@ #include "pdu_sender.h" #include "log.h" +typedef enum rtr_error_code { + ERR_PDU_CORRUPT_DATA = 0, + ERR_PDU_INTERNAL_ERROR = 1, + ERR_PDU_NO_DATA_AVAILABLE = 2, + ERR_PDU_INVALID_REQUEST = 3, + ERR_PDU_UNSUP_PROTO_VERSION = 4, + ERR_PDU_UNSUP_PDU_TYPE = 5, + ERR_PDU_WITHDRAWAL_UNKNOWN = 6, + ERR_PDU_DUPLICATE_ANNOUNCE = 7, + /* RTRv1 only, so not used yet. */ + ERR_PDU_UNEXPECTED_PROTO_VERSION = 8, +} rtr_error_code_t; + +/* + * TODO (urgent) According to the function below, NO_DATA_AVAILABLE is not + * fatal. However, some callers of this function are terminating the connection + * regardless of that. + */ +static int +err_pdu_send(int fd, rtr_error_code_t code, struct rtr_request const *request, + char const *message_const) +{ + char *message; + + /* + * This function must always return error so callers can interrupt + * themselves easily. + * But note that not all callers should use this. + * TODO (now) Prevent errors to errors + * (It's harder than it seems, because request->pdu is sometimes NULL.) + */ + + message = (message_const != NULL) ? strdup(message_const) : NULL; + send_error_report_pdu(fd, code, request, message); + free(message); + + return -EINVAL; +} + int -err_pdu_send(int fd, uint8_t version, uint16_t code, void *err_pdu_header, +err_pdu_send_corrupt_data(int fd, struct rtr_request const *request, char const *message) { - int error; - - error = send_error_report_pdu(fd, version, code, err_pdu_header, - message); - if (err_pdu_is_fatal(code)) { - pr_warn("Fatal error report PDU sent [code %u], closing socket.", - code); - close(fd); - } + return err_pdu_send(fd, ERR_PDU_CORRUPT_DATA, request, message); +} + +/* + * Please note: If you're planning to send this error due to a memory + * allocation failure, you probably shouldn't; you'd likely only aggravate the + * problem. + */ +int +err_pdu_send_internal_error(int fd) +{ + return err_pdu_send(fd, ERR_PDU_INTERNAL_ERROR, NULL, NULL); +} + +int +err_pdu_send_no_data_available(int fd) +{ + return err_pdu_send(fd, ERR_PDU_NO_DATA_AVAILABLE, NULL, NULL); +} - return error; +int +err_pdu_send_invalid_request(int fd, struct rtr_request const *request, + char const *message) +{ + return err_pdu_send(fd, ERR_PDU_INVALID_REQUEST, request, message); +} + +/* Caution: @header is supposed to be in serialized form. */ +int +err_pdu_send_invalid_request_truncated(int fd, unsigned char *header, + char const *message) +{ + struct rtr_request request = { + .bytes = header, + .bytes_len = RTRPDU_HEADER_LEN, + .pdu = NULL, + }; + return err_pdu_send_invalid_request(fd, &request, message); +} + ++int ++err_pdu_send_unsupported_proto_version(int fd) ++{ ++ return err_pdu_send(fd, ERR_PDU_UNSUP_PROTO_VERSION, NULL, NULL); ++} ++ +int +err_pdu_send_unsupported_pdu_type(int fd, struct rtr_request const *request) +{ + return err_pdu_send(fd, ERR_PDU_UNSUP_PDU_TYPE, request, NULL); } bool diff --cc src/rtr/err_pdu.h index 4082b6c6,1d06c7a0..be6c00b6 --- a/src/rtr/err_pdu.h +++ b/src/rtr/err_pdu.h @@@ -4,21 -4,19 +4,22 @@@ #include #include -#define ERR_PDU_CORRUPT_DATA 0 -#define ERR_PDU_INTERNAL_ERROR 1 -#define ERR_PDU_NO_DATA_AVAILABLE 2 -#define ERR_PDU_INVALID_REQUEST 3 -#define ERR_PDU_UNSUP_PROTO_VERSION 4 -#define ERR_PDU_UNSUP_PDU_TYPE 5 -#define ERR_PDU_WITHDRAWAL_UNKNOWN 6 -#define ERR_PDU_DUPLICATE_ANNOUNCE 7 -#define ERR_PDU_UNEXPECTED_PROTO_VERSION 8 +#include "rtr/pdu.h" +/* + * Wrappers for err_pdu_send(). + * Mainly, this is for the sake of making it easier to see whether the error is + * supposed to contain a message and/or the original PDU or not. + */ +int err_pdu_send_corrupt_data(int, struct rtr_request const *, char const *); +int err_pdu_send_internal_error(int); +int err_pdu_send_no_data_available(int); +int err_pdu_send_invalid_request(int, struct rtr_request const *, char const *); +int err_pdu_send_invalid_request_truncated(int, unsigned char *, char const *); ++int err_pdu_send_unsupported_proto_version(int); +int err_pdu_send_unsupported_pdu_type(int, struct rtr_request const *); -int err_pdu_send(int, uint8_t, uint16_t, void *, char const *); bool err_pdu_is_fatal(uint16_t); -void err_pdu_log(uint16_t, char *); +char const *err_pdu_to_string(uint16_t); #endif /* SRC_RTR_ERR_PDU_H_ */ diff --cc src/rtr/pdu.c index 67878018,da216c3b..1f52d8da --- a/src/rtr/pdu.c +++ b/src/rtr/pdu.c @@@ -6,108 -6,61 +6,108 @@@ #include "common.h" #include "log.h" +#include "rtr/err_pdu.h" #include "rtr/pdu_handler.h" -static int pdu_header_from_stream(int, struct pdu_header *); -static int serial_notify_from_stream(struct pdu_header *, int, void *); -static int serial_query_from_stream(struct pdu_header *, int, void *); -static int reset_query_from_stream(struct pdu_header *, int, void *); -static int cache_response_from_stream(struct pdu_header *, int, void *); -static int ipv4_prefix_from_stream(struct pdu_header *, int, void *); -static int ipv6_prefix_from_stream(struct pdu_header *, int, void *); -static int end_of_data_from_stream(struct pdu_header *, int, void *); -static int cache_reset_from_stream(struct pdu_header *, int, void *); -static int router_key_from_stream(struct pdu_header *, int, void *); -static int error_report_from_stream(struct pdu_header *, int, void *); -static void error_report_destroy(void *); +static int +pdu_header_from_reader(struct pdu_reader *reader, struct pdu_header *header) +{ + return read_int8(reader, &header->protocol_version) + || read_int8(reader, &header->pdu_type) + || read_int16(reader, &header->m.session_id) + || read_int32(reader, &header->length); +} int -pdu_load(int fd, void **pdu, struct pdu_metadata const **metadata, - uint8_t *rtr_version) +pdu_load(int fd, struct rtr_request *request, + struct pdu_metadata const **metadata) { + unsigned char hdr_bytes[RTRPDU_HEADER_LEN]; + struct pdu_reader reader; struct pdu_header header; struct pdu_metadata const *meta; - int err; + int error; + + /* Read the header into its buffer. */ + /* + * TODO (urgent) If the first read yields no bytes, the connection was + * terminated. We're not ending gracefully in those cases. + */ + error = pdu_reader_init(&reader, fd, hdr_bytes, RTRPDU_HEADER_LEN); + if (error) + /* Communication interrupted; omit error response */ + return error; + error = pdu_header_from_reader(&reader, &header); + if (error) + /* No error response because the PDU might have been an error */ + return error; - err = pdu_header_from_stream(fd, &header); - if (err) - return err; + /* - * RTRv1 expects us to respond RTRv1 messages with RTRv0 messages, - * and future protocols will probably do the same. - * So don't validate the protocol version. ++ * For now, only RTRv0 is supported + */ ++ if (header.protocol_version != RTR_V0) ++ return err_pdu_send_unsupported_proto_version(fd); + + if (header.length < RTRPDU_HEADER_LEN) + return err_pdu_send_invalid_request_truncated(fd, hdr_bytes, + "PDU is too small. (< 8 bytes)"); + + /* + * Error messages can be quite large. + * But they're probably not legitimate, so drop 'em. + * 512 is like a 5-paragraph error message, so it's probably enough. + * (Warning: I'm assuming english tho.) + */ + if (header.length > 512) { + pr_warn("Got an extremely large PDU (%u bytes). WTF?", + header.length); + return err_pdu_send_invalid_request_truncated(fd, hdr_bytes, + "PDU is too large. (> 512 bytes)"); + } + /* Read the rest of the PDU into its buffer. */ + request->bytes_len = header.length; + request->bytes = malloc(header.length); + if (request->bytes == NULL) + /* No error report PDU on allocation failures. */ + return pr_enomem(); + + memcpy(request->bytes, hdr_bytes, RTRPDU_HEADER_LEN); + error = pdu_reader_init(&reader, fd, + request->bytes + RTRPDU_HEADER_LEN, + header.length - RTRPDU_HEADER_LEN); + if (error) + /* Communication interrupted; no error PDU. */ + goto revert_bytes; + + /* Deserialize the PDU. */ meta = pdu_get_metadata(header.pdu_type); - if (!meta) - return -ENOENT; /* TODO try to skip it anyway? */ + if (!meta) { + error = err_pdu_send_unsupported_pdu_type(fd, request); + goto revert_bytes; + } - *pdu = malloc(meta->length); - if (*pdu == NULL) - return -ENOMEM; + request->pdu = malloc(meta->length); + if (request->pdu == NULL) { + error = pr_enomem(); + goto revert_bytes; + } - err = meta->from_stream(&header, fd, *pdu); - if (err) { - free(*pdu); - return err; + error = meta->from_stream(&header, &reader, request->pdu); + if (error) { + err_pdu_send_internal_error(fd); + goto revert_pdu; } - *rtr_version = header.protocol_version; - if (metadata) - *metadata = meta; + /* Happy path. */ + *metadata = meta; return 0; -} -static int -pdu_header_from_stream(int fd, struct pdu_header *header) -{ - /* If the first read yields no bytes, the connection was terminated. */ - return read_int8(fd, &header->protocol_version) - || read_int8(fd, &header->pdu_type) - || read_int16(fd, &header->m.session_id) - || read_int32(fd, &header->length); +revert_pdu: + free(request->pdu); +revert_bytes: + free(request->bytes); + return error; } static int diff --cc src/rtr/pdu_sender.c index 98eedfff,9b1fb2ca..5a1d97ac --- a/src/rtr/pdu_sender.c +++ b/src/rtr/pdu_sender.c @@@ -37,7 -52,36 +37,7 @@@ set_header_values(struct pdu_header *he header->m.reserved = reserved; } - /* TODO Include Router Key PDU serials */ -static uint32_t -length_serial_notify_pdu(struct serial_notify_pdu *pdu) -{ - return HEADER_LENGTH + sizeof(pdu->serial_number); -} - -static uint32_t -length_ipvx_prefix_pdu(bool isv4) -{ - return HEADER_LENGTH + - (isv4 ? IPV4_PREFIX_LENGTH : IPV6_PREFIX_LENGTH); -} - -static uint32_t -length_end_of_data_pdu(struct end_of_data_pdu *pdu) -{ - uint32_t len; - - len = HEADER_LENGTH; - len += sizeof(pdu->serial_number); - if (pdu->header.protocol_version == RTR_V1) { - len += sizeof(pdu->refresh_interval); - len += sizeof(pdu->retry_interval); - len += sizeof(pdu->expire_interval); - } - - return len; -} - + /* TODO (next iteration) Include Router Key PDU serials */ /** * static uint32_t * length_router_key_pdu(struct router_key_pdu *pdu) @@@ -47,40 -91,14 +47,6 @@@ * } */ - /* - * TODO Needs some testing, this is just a beta version - */ - static int - send_large_response(int fd, struct data_buffer *buffer) -static uint32_t -length_error_report_pdu(struct error_report_pdu *pdu) --{ - unsigned char *tmp_buffer, *ptr; - size_t buf_size, pending; - int written; - - buf_size = buffer->capacity; - pending = buffer->len; - ptr = buffer->data; - while (pending > 0) { - tmp_buffer = calloc(pending, sizeof(unsigned char)); - if (tmp_buffer == NULL) - return pr_enomem(); - - memcpy(tmp_buffer, ptr, buf_size); - - written = write(fd, tmp_buffer, buf_size); - free(tmp_buffer); - if (written < 0) - return pr_err("Error sending response"); - - pending -= buf_size; - ptr += buf_size; - buf_size = pending > buffer->capacity ? buffer->capacity : - pending; - } - - return 0; - return HEADER_LENGTH + - pdu->error_pdu_length + sizeof(pdu->error_pdu_length) + - pdu->error_message_length + sizeof(pdu->error_message_length); --} -- static int send_response(int fd, unsigned char *data, size_t data_len) { diff --cc src/rtr/rtr.c index cadc2a04,9ad8dbd8..cf12812d --- a/src/rtr/rtr.c +++ b/src/rtr/rtr.c @@@ -19,12 -19,23 +19,11 @@@ #include "rtr/err_pdu.h" #include "rtr/pdu.h" - /* TODO (urgent) this needs to be atomic */ - volatile bool loop; -/* TODO (next iteration) Support both RTR v0 and v1 */ -#define RTR_VERSION_SUPPORTED RTR_V0 - + struct sigaction act; -/* - * Arguments that the server socket thread will send to the client - * socket threads whenever it creates them. - */ -struct thread_param { - int client_fd; - struct sockaddr_storage client_addr; -}; - struct thread_node { pthread_t tid; - struct thread_param params; + struct rtr_client client; SLIST_ENTRY(thread_node) next; }; @@@ -173,25 -172,47 +172,25 @@@ end_client(struct rtr_client *client * The client socket threads' entry routine. */ static void * -client_thread_cb(void *param_void) +client_thread_cb(void *arg) { - struct thread_param *param = param_void; + struct rtr_client *client = arg; struct pdu_metadata const *meta; - void *pdu; - int err; - uint8_t rtr_version; + struct rtr_request request; + int error; - 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); - - /* Protocol Version Negotiation */ - if (rtr_version != RTR_VERSION_SUPPORTED) { - err_pdu_send(param->client_fd, RTR_VERSION_SUPPORTED, - ERR_PDU_UNSUP_PROTO_VERSION, - (struct pdu_header *) pdu, NULL); - return end_client(param->client_fd, meta, pdu); - } - /* RTR Version ready, now update client */ - err = clients_add(param->client_fd, ¶m->client_addr, - rtr_version); - if (err) { - if (err == -ERTR_VERSION_MISMATCH) { - err_pdu_send(param->client_fd, rtr_version, - (rtr_version == RTR_V0 - ? ERR_PDU_UNSUP_PROTO_VERSION - : ERR_PDU_UNEXPECTED_PROTO_VERSION), - (struct pdu_header *) pdu, NULL); - } - return end_client(param->client_fd, meta, pdu); - } + error = pdu_load(client->fd, &request, &meta); + if (error) + break; - err = meta->handle(param->client_fd, pdu); - meta->destructor(pdu); - if (err) - return end_client(param->client_fd, NULL, NULL); + error = meta->handle(client->fd, &request); + clean_request(&request, meta); + if (error) + break; } - return NULL; /* Unreachable. */ + return end_client(client); } /* @@@ -244,27 -256,13 +243,27 @@@ handle_client_connections(int server_fd continue; } - new_thread->params.client_fd = client_fd; - new_thread->params.client_addr = client_addr; + new_thread->client.fd = client_fd; + new_thread->client.addr = client_addr; + + error = clients_add(&new_thread->client); + if (error) { + /* + * Presently, clients_add() can only fail due to alloc + * failure. No error report PDU. + */ + free(new_thread); + close(client_fd); + continue; + } - errno = pthread_create(&new_thread->tid, NULL, - client_thread_cb, &new_thread->params); - if (errno) { - pr_errno(errno, "Could not spawn the client's thread"); + error = pthread_create(&new_thread->tid, NULL, + client_thread_cb, &new_thread->client); - if (error != EAGAIN) ++ if (error && error != EAGAIN) + err_pdu_send_internal_error(client_fd); + if (error) { + pr_errno(error, "Could not spawn the client's thread"); + clients_forget(client_fd); free(new_thread); close(client_fd); continue; diff --cc src/slurm/slurm_db.c index ea7749a2,827743b9..837224ef --- a/src/slurm/slurm_db.c +++ b/src/slurm/slurm_db.c @@@ -149,71 -137,67 +137,67 @@@ bgpsec_equal(struct slurm_bgpsec *left return equal; } - LOCATE_FUNCS(prefix_filter, struct slurm_prefix, struct al_filter_prefix, - prefix_equal, true) - LOCATE_FUNCS(bgpsec_filter, struct slurm_bgpsec, struct al_filter_bgpsec, - bgpsec_equal, true) - LOCATE_FUNCS(prefix_assertion, struct slurm_prefix, struct al_assertion_prefix, - prefix_equal, false) - LOCATE_FUNCS(bgpsec_assertion, struct slurm_bgpsec, struct al_assertion_bgpsec, - bgpsec_equal, false) - - /* - * Try to persist the @prefix filter, if it already exists or is covered - * by another filter, then the error -EEXIST is returned; otherwise, returns - * the result of persisting the @prefix. - */ - int - slurm_db_add_prefix_filter(struct slurm_prefix *prefix) - { - if (prefix_filter_exists(&array_lists_db.filter_pfx_al, prefix)) - return -EEXIST; - - return al_filter_prefix_add(&array_lists_db.filter_pfx_al, prefix); - } + #define ADD_FUNCS(name, type, list_name, db_list, equal_cb, filter) \ + static type * \ + name##_locate(type *obj) \ + { \ + type *cursor; \ + \ + ARRAYLIST_FOREACH(db_list, cursor) \ + if (equal_cb(cursor, obj, filter)) \ + return cursor; \ + \ + return NULL; \ + } \ + \ + static bool \ + name##_exists(type *obj) \ + { \ + return name##_locate(obj) != NULL; \ + } \ + \ + int \ + slurm_db_add_##name(type *elem) { \ + if (name##_exists(elem)) \ + return -EEXIST; \ + return list_name##_add(db_list, elem); \ + } - /* - * Try to persist the @prefix assertion, if it already exists, then the error - * -EEXIST is returned; otherwise, returns the result of persisting the - * @prefix. - */ - int - slurm_db_add_prefix_assertion(struct slurm_prefix *prefix) + ADD_FUNCS(prefix_filter, struct slurm_prefix, al_filter_prefix, + &array_lists_db.filter_pfx_al, prefix_equal, true) + ADD_FUNCS(bgpsec_filter, struct slurm_bgpsec, al_filter_bgpsec, + &array_lists_db.filter_bgps_al, bgpsec_equal, true) + ADD_FUNCS(prefix_assertion, struct slurm_prefix, al_assertion_prefix, + &array_lists_db.assertion_pfx_al, prefix_equal, false) + ADD_FUNCS(bgpsec_assertion, struct slurm_bgpsec, al_assertion_bgpsec, + &array_lists_db.assertion_bgps_al, bgpsec_equal, false) + + bool -slurm_db_vrp_is_filtered(struct vrp *vrp) ++slurm_db_vrp_is_filtered(struct vrp const *vrp) { - if (prefix_assertion_exists(&array_lists_db.assertion_pfx_al, prefix)) - return -EEXIST; - - return al_assertion_prefix_add(&array_lists_db.assertion_pfx_al, - prefix); - } + struct slurm_prefix slurm_prefix; - /* - * Try to persist the @bgpsec filter, if it already exists or is covered - * by another filter, then the error -EEXIST is returned; otherwise, returns - * the result of persisting the @bgpsec. - */ - int - slurm_db_add_bgpsec_filter(struct slurm_bgpsec *bgpsec) - { - if (bgpsec_filter_exists(&array_lists_db.filter_bgps_al, bgpsec)) - return -EEXIST; + slurm_prefix.data_flag = SLURM_COM_FLAG_ASN | SLURM_PFX_FLAG_PREFIX + | SLURM_PFX_FLAG_MAX_LENGTH; + slurm_prefix.vrp = *vrp; + slurm_prefix.comment = NULL; - return al_filter_bgpsec_add(&array_lists_db.filter_bgps_al, bgpsec); + return prefix_filter_exists(&slurm_prefix); } - /* - * Try to persist the @bgpsec assertion, if it already exists, then the error - * -EEXIST is returned; otherwise, returns the result of persisting the - * @bgpsec. - */ int - slurm_db_add_bgpsec_assertion(struct slurm_bgpsec *bgpsec) + slurm_db_foreach_assertion_prefix(assertion_pfx_foreach_cb cb, void *arg) { - if (bgpsec_assertion_exists(&array_lists_db.assertion_bgps_al, bgpsec)) - return -EEXIST; + struct slurm_prefix *cursor; + int error; - return al_assertion_bgpsec_add(&array_lists_db.assertion_bgps_al, - bgpsec); + ARRAYLIST_FOREACH(&array_lists_db.assertion_pfx_al, cursor) { + error = cb(cursor, arg); + if (error) + return error; + } + + return 0; } static void diff --cc src/slurm/slurm_db.h index 2e090a56,b6f5139f..52d19747 --- a/src/slurm/slurm_db.h +++ b/src/slurm/slurm_db.h @@@ -27,6 -30,9 +30,9 @@@ int slurm_db_add_prefix_assertion(struc int slurm_db_add_bgpsec_filter(struct slurm_bgpsec *); int slurm_db_add_bgpsec_assertion(struct slurm_bgpsec *); -bool slurm_db_vrp_is_filtered(struct vrp *vrp); ++bool slurm_db_vrp_is_filtered(struct vrp const *vrp); + int slurm_db_foreach_assertion_prefix(assertion_pfx_foreach_cb, void *); + void slurm_db_cleanup(void); - #endif /* SRC_SLURM_DB_H_ */ + #endif /* SRC_SLURM_SLURM_DB_H_ */ diff --cc src/slurm/slurm_loader.c index 00000000,fe9dbe5a..69a70807 mode 000000,100644..100644 --- a/src/slurm/slurm_loader.c +++ b/src/slurm/slurm_loader.c @@@ -1,0 -1,107 +1,107 @@@ + #include "slurm_loader.h" + + #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 + slurm_load(bool *loaded) + { + /* Optional configuration */ + *loaded = false; + if (config_get_slurm_location() == NULL) + return 0; + + *loaded = true; + slurm_db_init(); + + return process_dir_files(config_get_slurm_location(), + SLURM_FILE_EXTENSION, slurm_parse, NULL); + } + + static void + slurm_cleanup(void) + { + /* Only if the SLURM was configured */ + if (config_get_slurm_location() != NULL) + slurm_db_cleanup(); + } + + static int -slurm_pfx_filters_apply(struct vrp *vrp, void *arg) ++slurm_pfx_filters_apply(struct vrp const *vrp, void *arg) + { + struct roa_table *table = arg; + + if (slurm_db_vrp_is_filtered(vrp)) + roa_table_remove_roa(table, vrp); + + return 0; + } + + static int + slurm_pfx_assertions_add(struct slurm_prefix *prefix, void *arg) + { + struct roa_table *table = arg; + struct ipv4_prefix prefix4; + struct ipv6_prefix prefix6; + struct vrp vrp; + + vrp = prefix->vrp; + if ((prefix->data_flag & SLURM_PFX_FLAG_MAX_LENGTH) == 0) + vrp.max_prefix_length = vrp.prefix_length; + + if (vrp.addr_fam == AF_INET) { + prefix4.addr = vrp.prefix.v4; + prefix4.len = vrp.prefix_length; + return rtrhandler_handle_roa_v4(table, vrp.asn, &prefix4, + vrp.max_prefix_length); + } + if (vrp.addr_fam == AF_INET6) { + prefix6.addr = vrp.prefix.v6; + prefix6.len = vrp.prefix_length; + return rtrhandler_handle_roa_v6(table, vrp.asn, &prefix6, + vrp.max_prefix_length); + } + return -pr_crit("Unkown addr family type"); + } + + static int + slurm_pfx_assertions_apply(struct roa_table *base) + { + return slurm_db_foreach_assertion_prefix(slurm_pfx_assertions_add, + base); + } + + int + slurm_apply(struct roa_table *base) + { + bool loaded; + int error; + + loaded = false; + error = slurm_load(&loaded); + if (error) + goto cleanup; + + if (!loaded) + return 0; + + error = roa_table_foreach_roa(base, slurm_pfx_filters_apply, base); + if (error) + goto cleanup; + + error = slurm_pfx_assertions_apply(base); + + /** TODO (next iteration) Apply BGPsec filters and assertions */ + + cleanup: + slurm_cleanup(); + return error; + } diff --cc test/Makefile.am index 2873d3ee,6cb82fb6..29eb694c --- a/test/Makefile.am +++ b/test/Makefile.am @@@ -20,6 -20,6 +20,15 @@@ MY_LDADD = ${CHECK_LIBS BASIC_MODULES = ../src/log.c ../src/log.h BASIC_MODULES += impersonator.c ++SLURM_SOURCES = ../src/address.c ../src/address.h ++SLURM_SOURCES += ../src/json_parser.c ../src/json_parser.h ++SLURM_SOURCES += ../src/crypto/base64.c ../src/crypto/base64.h ++SLURM_SOURCES += ../src/slurm/slurm_db.c ../src/slurm/slurm_db.h ++SLURM_SOURCES += ../src/slurm/slurm_loader.c ++SLURM_SOURCES += ../src/slurm/slurm_loader.h ++SLURM_SOURCES += ../src/slurm/slurm_parser.c ++SLURM_SOURCES += ../src/slurm/slurm_parser.h ++ check_PROGRAMS = address.test check_PROGRAMS += clients.test check_PROGRAMS += line_file.test @@@ -50,17 -48,6 +59,18 @@@ line_file_test_SOURCES += ../src/line_f line_file_test_SOURCES += line_file_test.c line_file_test_LDADD = ${MY_LDADD} +pdu_handler_test_SOURCES = ${BASIC_MODULES} ++pdu_handler_test_SOURCES += ${SLURM_SOURCES} +pdu_handler_test_SOURCES += ../src/common.c +pdu_handler_test_SOURCES += ../src/rtr/pdu_handler.c +pdu_handler_test_SOURCES += ../src/rtr/err_pdu.c +pdu_handler_test_SOURCES += ../src/rtr/db/delta.c +pdu_handler_test_SOURCES += ../src/rtr/db/roa_table.c +pdu_handler_test_SOURCES += ../src/rtr/db/vrps.c +pdu_handler_test_SOURCES += rtr/db/impersonator.c +pdu_handler_test_SOURCES += rtr/pdu_handler_test.c - pdu_handler_test_LDADD = ${MY_LDADD} ++pdu_handler_test_LDADD = ${MY_LDADD} ${JANSSON_LIBS} + roa_table_test_SOURCES = ${BASIC_MODULES} roa_table_test_SOURCES += ../src/rtr/db/delta.c roa_table_test_SOURCES += ../src/rtr/db/roa_table.c @@@ -87,15 -74,6 +97,16 @@@ vcard_test_SOURCES = ${BASIC_MODULES vcard_test_SOURCES += vcard_test.c vcard_test_LDADD = ${MY_LDADD} +vrps_test_SOURCES = ${BASIC_MODULES} ++vrps_test_SOURCES += ${SLURM_SOURCES} +vrps_test_SOURCES += ../src/common.c +vrps_test_SOURCES += ../src/rtr/db/delta.c +vrps_test_SOURCES += ../src/rtr/db/roa_table.c +vrps_test_SOURCES += ../src/rtr/db/vrps.c +vrps_test_SOURCES += rtr/db/impersonator.c +vrps_test_SOURCES += rtr/db/vrps_test.c - vrps_test_LDADD = ${MY_LDADD} ++vrps_test_LDADD = ${MY_LDADD} ${JANSSON_LIBS} + #rtr_pdu_test_SOURCES = ${BASIC_MODULES} #rtr_pdu_test_SOURCES += rtr/pdu_test.c #rtr_pdu_test_SOURCES += rtr/stream.c diff --cc test/impersonator.c index 41cbbc21,41cbbc21..3d0f0ed4 --- a/test/impersonator.c +++ b/test/impersonator.c @@@ -69,3 -69,3 +69,9 @@@ config_get_rsync_args(bool is_ta static const struct string_array array = { 0 }; return &array; } ++ ++char const * ++config_get_slurm_location(void) ++{ ++ return NULL; ++} diff --cc test/rtr/db/impersonator.c index 3e2f3a95,00000000..fded5635 mode 100644,000000..100644 --- a/test/rtr/db/impersonator.c +++ b/test/rtr/db/impersonator.c @@@ -1,58 -1,0 +1,60 @@@ +#include "object/tal.h" + +#include + +static int iteration = 0; + +static void +add_v4(struct validation_handler *handler, uint32_t as) +{ + struct ipv4_prefix prefix; + prefix.addr.s_addr = htonl(0xC0000200); + prefix.len = 24; + ck_assert_int_eq(0, handler->handle_roa_v4(as, &prefix, 32, + handler->arg)); +} + +static void +add_v6(struct validation_handler *handler, uint32_t as) +{ + struct ipv6_prefix prefix; + prefix.addr.s6_addr32[0] = htonl(0x20010DB8); + prefix.addr.s6_addr32[1] = 0; + prefix.addr.s6_addr32[2] = 0; + prefix.addr.s6_addr32[3] = 0; + prefix.len = 96; + ck_assert_int_eq(0, handler->handle_roa_v6(as, &prefix, 120, + handler->arg)); +} + +int +perform_standalone_validation(struct validation_handler *handler) +{ + ck_assert_int_eq(0, handler->reset(handler->arg)); + + switch (iteration) { + case 0: + add_v4(handler, 0); + add_v6(handler, 0); + break; + case 1: + add_v4(handler, 0); + add_v6(handler, 0); + add_v4(handler, 1); + add_v6(handler, 1); + break; + case 2: + case 3: + add_v4(handler, 1); + add_v6(handler, 1); + break; + default: + ck_abort_msg("perform_standalone_validation() was called too many times (%d).", + iteration); + } ++ if (handler->merge != NULL) ++ handler->merge(handler->merge_arg, handler->arg); + + iteration++; + return 0; +}