From dca2e9025a525b050c2013b4608c76e9dc0bd2c4 Mon Sep 17 00:00:00 2001 From: pcarana Date: Mon, 18 Feb 2019 10:29:40 -0600 Subject: [PATCH] Save in memory the VRPs loaded from CSV --- src/Makefile.am | 2 + src/array_list.h | 65 ++++++++++++++++++++++ src/configuration.c | 38 +++---------- src/configuration.h | 1 + src/csv.c | 115 ++++++++++++++++++++++++++++----------- src/csv.h | 2 +- src/main.c | 13 +++++ src/vrps.c | 129 ++++++++++++++++++++++++++++++++++++++++++++ src/vrps.h | 22 ++++++++ 9 files changed, 325 insertions(+), 62 deletions(-) create mode 100644 src/array_list.h create mode 100644 src/vrps.c create mode 100644 src/vrps.h diff --git a/src/Makefile.am b/src/Makefile.am index d9764d9d..fcb7d29c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -5,10 +5,12 @@ bin_PROGRAMS = rtr_server rtr_server_SOURCES = main.c rtr_server_SOURCES += address.c address.h +rtr_server_SOURCES += array_list.h rtr_server_SOURCES += common.c common.h rtr_server_SOURCES += configuration.c configuration.h rtr_server_SOURCES += csv.c csv.h rtr_server_SOURCES += line_file.c line_file.h +rtr_server_SOURCES += vrps.c vrps.h rtr_server_SOURCES += rtr/pdu_handler.c rtr/pdu_handler.h rtr_server_SOURCES += rtr/pdu.c rtr/pdu.h diff --git a/src/array_list.h b/src/array_list.h new file mode 100644 index 00000000..a944aabb --- /dev/null +++ b/src/array_list.h @@ -0,0 +1,65 @@ +#ifndef SRC_ARRAY_LIST_H_ +#define SRC_ARRAY_LIST_H_ + +#include +#include + +#define ARRAY_LIST(name, elem_type) \ + struct name { \ + /** Unidimensional array. */ \ + elem_type *array; \ + /** Number of elements in @array. */ \ + unsigned int len; \ + /** Actual allocated slots in @array. */ \ + unsigned int capacity; \ + }; \ + \ + static int \ + name##_init(struct name *list) \ + { \ + list->capacity = 8; \ + list->len = 0; \ + list->array = malloc(list->capacity \ + * sizeof(elem_type)); \ + return (list->array != NULL) ? 0 : -ENOMEM; \ + } \ + \ + static void \ + name##_cleanup(struct name *list, void (*cb)(elem_type *)) \ + { \ + unsigned int i; \ + for (i = 0; i < list->len; i++) \ + cb(&list->array[i]); \ + free(list->array); \ + } \ + \ + /* Will store a shallow copy, not @elem */ \ + static int \ + name##_add(struct name *list, elem_type *elem) \ + { \ + elem_type *tmp; \ + \ + list->len++; \ + while (list->len >= list->capacity) { \ + list->capacity *= 2; \ + \ + tmp = realloc(list->array, list->capacity \ + * sizeof(elem_type)); \ + if (tmp == NULL) { \ + err(-ENOMEM, "Out of memory"); \ + return -ENOMEM; \ + } \ + list->array = tmp; \ + } \ + \ + list->array[list->len - 1] = *elem; \ + return 0; \ + } + +#define ARRAYLIST_FOREACH(list, cursor) for ( \ + cursor = (list)->array; \ + (cursor - ((typeof(cursor)) ((list)->array))) < (list)->len; \ + cursor++ \ +) + +#endif /* SRC_ARRAY_LIST_H_ */ diff --git a/src/configuration.c b/src/configuration.c index 69df376d..41451c8d 100644 --- a/src/configuration.c +++ b/src/configuration.c @@ -13,7 +13,7 @@ #define OPTNAME_LISTEN "listen" #define OPTNAME_LISTEN_ADDRESS "address" #define OPTNAME_LISTEN_PORT "port" -#define OPTNAME_VRPS "vrps" +#define OPTNAME_VRPS_LOCATION "vrpsLocation" #define DEFAULT_ADDR NULL #define DEFAULT_PORT "323" @@ -25,13 +25,12 @@ struct rtr_config { /** Stored aside only for printing purposes. */ char *port; /** VRPs (Validated ROA Payload) location */ - char *vrps; + char *vrps_location; } config; static int handle_json(json_t *); static int json_get_string(json_t *, char const *, char *, char const **); static int init_addrinfo(char const *, char const *); -static int init_vrps_db(char const *); int config_init(char const *json_file_path) @@ -68,8 +67,8 @@ config_cleanup(void) freeaddrinfo(config.address); if (config.port != NULL) free(config.port); - if (config.vrps != NULL) - free(config.vrps); + if (config.vrps_location != NULL) + free(config.vrps_location); } static int @@ -109,14 +108,11 @@ handle_json(json_t *root) port = DEFAULT_PORT; } - error = json_get_string(root, OPTNAME_VRPS, + error = json_get_string(root, OPTNAME_VRPS_LOCATION, DEFAULT_VRPS, &vrps); if (error) return error; - - error = init_vrps_db(vrps); - if (error) - return error; + config.vrps_location = str_clone(vrps); return init_addrinfo(address, port); } @@ -142,24 +138,6 @@ json_get_string(json_t *parent, char const *name, char *default_value, return 0; } -static int -init_vrps_db(char const *vrps_location) -{ - /* FIXME Complete me! */ - int error; - - if (vrps_location == NULL || strlen(vrps_location) < 1) { - warnx("VRPs location must be set"); - return -EINVAL; - } - - error = parse_file(vrps_location); - if (error) - return error; /* Error msg already printed. */ - - return 0; -} - static int init_addrinfo(char const *hostname, char const *service) { @@ -196,7 +174,7 @@ config_get_server_port(void) } char const * -config_get_vrps(void) +config_get_vrps_location(void) { - return config.vrps; + return config.vrps_location; } diff --git a/src/configuration.h b/src/configuration.h index 145143bf..343ab18b 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -8,5 +8,6 @@ void config_cleanup(void); struct addrinfo const *config_get_server_addrinfo(void); char const *config_get_server_port(void); +char const *config_get_vrps_location(void); #endif /* _SRC_CONFIGURATION_H_ */ diff --git a/src/csv.c b/src/csv.c index bd8d0514..b9275f88 100644 --- a/src/csv.c +++ b/src/csv.c @@ -3,18 +3,14 @@ #include #include #include +#include #include #include +#include "configuration.h" #include "address.h" #include "line_file.h" - -struct csv_data { - char *asn; - char *prefix; - int max_length; - char *trust_anchor; -}; +#include "vrps.h" /* @ext must include the period. */ static bool @@ -33,10 +29,34 @@ location_has_extension(char const *location, char const *ext) } static int -parse_asn(char *text) +parse_asn(char *text, unsigned int *value) { - if (text == NULL) + unsigned long asn; + char *start; + + if (text == NULL) { + err(-EINVAL, "Null string received, can't decode ASN"); + return -EINVAL; + } + + /* The text 'AS' may precede the number */ + start = strchr(text, 'S'); + start = start != NULL ? start + 1 : text; + + errno = 0; + asn = strtoul(start, NULL, 10); + if (errno) { + err(errno, "Invalid ASN '%s': %s", text, strerror(errno)); return -EINVAL; + } + /* An underflow or overflow will be considered here */ + if (asn < 0 || UINT32_MAX < asn) { + err(-EINVAL, "Prefix length (%lu) is out of bounds (0-%u).", + asn, UINT32_MAX); + return -EINVAL; + } + *value = (unsigned int) asn; + return 0; } @@ -65,11 +85,12 @@ parse_prefix_length(char *text, unsigned int *value, int max_value) } static int -add_vrp(char *line) +add_vrp(char *line, struct delta *delta) { struct ipv4_prefix prefixv4; struct ipv6_prefix prefixv6; - unsigned int prefix_length, max_prefix_length; + struct vrp *vrp; + unsigned int asn, prefix_length, max_prefix_length; int error; bool isv4; char *token, *line_copy; @@ -85,7 +106,7 @@ add_vrp(char *line) /* First column: ASN in format "AS###" */ token = strtok(line_copy, ","); - error = parse_asn(token); + error = parse_asn(token, &asn); if (error) goto error; @@ -102,7 +123,8 @@ add_vrp(char *line) /* Second column (second part): Prefix length in numeric format */ token = strtok(NULL, ","); - error = parse_prefix_length(token, &prefix_length, isv4 ? 32 : 128); + error = parse_prefix_length(token, isv4 ? &prefixv4.len : &prefixv6.len, + isv4 ? 32 : 128); if (error) goto error; @@ -114,10 +136,10 @@ add_vrp(char *line) /* Now validate the prefix */ if (isv4) { - prefixv4.len = prefix_length; + prefix_length = prefixv4.len; error = prefix4_validate(&prefixv4); } else { - prefixv6.len = prefix_length; + prefix_length = prefixv6.len; error = prefix6_validate(&prefixv6); } if (error) @@ -125,18 +147,38 @@ add_vrp(char *line) if (prefix_length > max_prefix_length) { error = -EINVAL; - err(error, "Prefix length is greater than max prefix length [%u > %u]", - prefix_length, max_prefix_length); + err(error, "Prefix length is greater than max prefix length at line '%s'", + line); + goto error; } - /* TODO Now store the values in memory */ + if (isv4) + vrp = create_vrp4(asn, prefixv4.addr, prefixv4.len, max_prefix_length); + else + vrp = create_vrp6(asn, prefixv6.addr, prefixv6.len, max_prefix_length); + + if (vrp == NULL) { + error = -ENOMEM; + err(error, "Couldn't allocate VRP of line '%s'", line); + goto error; + } + + error = delta_add_vrp(delta, vrp); + if (error) { + vrp_destroy(vrp); + goto error; + } + + return 0; + error: return error; } static int -read_vrps(struct line_file *lfile) +load_vrps(struct line_file *lfile) { + struct delta *delta; char *line; int current_line; int error; @@ -150,41 +192,52 @@ read_vrps(struct line_file *lfile) } if (line == NULL) { error = -EINVAL; - err(error, "Empty file, stop processing."); + err(error, "Empty CSV file, stop processing."); return error; } + /* Start the initial delta */ + delta = create_delta(); do { ++current_line; error = lfile_read(lfile, &line); if (error) { - err(error, "Error at line %d, stop processing file.", current_line); - if (line != NULL) - free(line); - return error; + err(error, "Error reading line %d, stop processing file.", current_line); + delta_destroy(delta); + goto end; } if (line == NULL) { - free(line); - return 0; + error = 0; + goto persist; } if (strcmp(line, "") == 0) { warn("There's nothing at line %d, ignoring.", current_line); continue; } - error = add_vrp(line); + error = add_vrp(line, delta); if (error) { - free(line); - return error; + delta_destroy(delta); + goto end; } } while (true); +persist: + error = deltas_db_add_delta(delta); + if (error) + err(error, "VRPs Delta couldn't be persisted"); +end: + if (line != NULL) + free(line); + return error; } int -parse_file(char const *location) +csv_parse_vrps_file() { struct line_file *lfile; + char const *location; int error; + location = config_get_vrps_location(); if (!location_has_extension(location, ".csv")) { warn("%s isn't a CSV file", location); error = -EINVAL; @@ -195,7 +248,7 @@ parse_file(char const *location) if (error) goto end1; /* Error msg already printed. */ - error = read_vrps(lfile); + error = load_vrps(lfile); if (error) goto end2; diff --git a/src/csv.h b/src/csv.h index 8fc6a343..3b96f802 100644 --- a/src/csv.h +++ b/src/csv.h @@ -1,6 +1,6 @@ #ifndef SRC_CSV_H_ #define SRC_CSV_H_ -int parse_file(char const *); +int csv_parse_vrps_file(); #endif /* SRC_CSV_H_ */ diff --git a/src/main.c b/src/main.c index c8e8fb31..44dd4a00 100644 --- a/src/main.c +++ b/src/main.c @@ -5,6 +5,8 @@ #include "rtr/rtr.h" #include "configuration.h" +#include "csv.h" +#include "vrps.h" /* * This program is an RTR server. @@ -42,8 +44,19 @@ main(int argc, char *argv[]) if (err) return err; + err = deltas_db_init(); + if (err) + goto end1; + + err = csv_parse_vrps_file(); + if (err) + goto end2; + err = rtr_listen(); +end2: + deltas_db_destroy(); +end1: config_cleanup(); return err; } diff --git a/src/vrps.c b/src/vrps.c new file mode 100644 index 00000000..41f1c78a --- /dev/null +++ b/src/vrps.c @@ -0,0 +1,129 @@ +#include "vrps.h" + +#include +#include +#include "array_list.h" + +struct vrp { + u_int32_t asn; + union { + struct in_addr ipv4_prefix; + struct in6_addr ipv6_prefix; + }; + u_int8_t prefix_length; + u_int8_t max_prefix_length; +}; + +ARRAY_LIST(delta, struct vrp) +ARRAY_LIST(deltasdb, struct delta) + +struct deltasdb db; + +int +deltas_db_init(void) +{ + int error; + + error = deltasdb_init(&db); + if (error) { + err(error, "Deltas DB couldn't be allocated"); + return error; + } + + return 0; +} + +struct delta * +create_delta(void) +{ + struct delta *result; + + result = malloc(sizeof(struct delta)); + if (result == NULL) + goto fail1; + + if (delta_init(result) != 0) + goto fail2; + + return result; +fail2: + free(result); +fail1: + return NULL; +} + +static struct vrp * +create_vrp (u_int32_t asn, u_int8_t prefix_length, u_int8_t max_prefix_length) { + struct vrp *result; + + result = malloc(sizeof(struct vrp)); + if (result == NULL) + return NULL; + + result->asn = asn; + result->prefix_length = prefix_length; + result->max_prefix_length = max_prefix_length; + + return result; +} + +struct vrp * +create_vrp4(u_int32_t asn, struct in_addr ipv4_prefix, u_int8_t prefix_length, + u_int8_t max_prefix_length) +{ + struct vrp *result; + + result = create_vrp(asn, prefix_length, max_prefix_length); + if (result == NULL) + return NULL; + + result->ipv4_prefix = ipv4_prefix; + + return result; +} + +struct vrp * +create_vrp6(u_int32_t asn, struct in6_addr ipv6_prefix, u_int8_t prefix_length, + u_int8_t max_prefix_length) +{ + struct vrp *result; + + result = create_vrp(asn, prefix_length, max_prefix_length); + if (result == NULL) + return NULL; + + result->ipv6_prefix = ipv6_prefix; + + return result; +} + +int +deltas_db_add_delta(struct delta *delta) +{ + return deltasdb_add(&db, delta); +} + +int +delta_add_vrp(struct delta *delta, struct vrp *vrp) +{ + return delta_add(delta, vrp); +} + +void +vrp_destroy(struct vrp *vrp) +{ + free(vrp); +} + +void +delta_destroy(struct delta *delta) +{ + delta_cleanup(delta, vrp_destroy); + free(delta); +} + +void +deltas_db_destroy() +{ + deltasdb_cleanup(&db, delta_destroy); +} diff --git a/src/vrps.h b/src/vrps.h new file mode 100644 index 00000000..41aabad4 --- /dev/null +++ b/src/vrps.h @@ -0,0 +1,22 @@ +#ifndef SRC_VRPS_H_ +#define SRC_VRPS_H_ + +#include + +struct vrp; +struct delta; + +int deltas_db_init(void); + +struct delta *create_delta(void); +struct vrp *create_vrp4(u_int32_t, struct in_addr, u_int8_t, u_int8_t); +struct vrp *create_vrp6(u_int32_t, struct in6_addr, u_int8_t, u_int8_t); + +int delta_add_vrp(struct delta *, struct vrp *); +int deltas_db_add_delta(struct delta *); + +void vrp_destroy(struct vrp *); +void delta_destroy(struct delta *); +void deltas_db_destroy(); + +#endif /* SRC_VRPS_H_ */ -- 2.47.3