]> git.ipfire.org Git - thirdparty/FORT-validator.git/commitdiff
Save in memory the VRPs loaded from CSV
authorpcarana <pc.moreno2099@gmail.com>
Mon, 18 Feb 2019 16:29:40 +0000 (10:29 -0600)
committerpcarana <pc.moreno2099@gmail.com>
Mon, 18 Feb 2019 16:29:40 +0000 (10:29 -0600)
src/Makefile.am
src/array_list.h [new file with mode: 0644]
src/configuration.c
src/configuration.h
src/csv.c
src/csv.h
src/main.c
src/vrps.c [new file with mode: 0644]
src/vrps.h [new file with mode: 0644]

index d9764d9d30be496eac68fab726245e1b8a90d322..fcb7d29c597818b987794dede8f97ede0d262e7a 100644 (file)
@@ -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 (file)
index 0000000..a944aab
--- /dev/null
@@ -0,0 +1,65 @@
+#ifndef SRC_ARRAY_LIST_H_
+#define SRC_ARRAY_LIST_H_
+
+#include <err.h>
+#include <errno.h>
+
+#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_ */
index 69df376d2a77e4a644fe0a831177243d7e3ef452..41451c8de39ad36060e00cb62e9da7d70bcfafbd 100644 (file)
@@ -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;
 }
index 145143bf2c3d08d56ada97f005ba99502c794d10..343ab18b722b16dbb2443d4913f4cfcee0bdd435 100644 (file)
@@ -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_ */
index bd8d0514f5e3360b7f0af4afc261d9aa9556b4ef..b9275f8839568cef5dc342f9b8bab39c66f784da 100644 (file)
--- a/src/csv.c
+++ b/src/csv.c
@@ -3,18 +3,14 @@
 #include <err.h>
 #include <errno.h>
 #include <stdbool.h>
+#include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
 
+#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;
 
index 8fc6a343bc0bfae4205c7b266ceb9d44bf9db997..3b96f80261b1cefc055cf3df17d196c0153b382a 100644 (file)
--- 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_ */
index c8e8fb3175655151866ed51b791bcb4dea1dd062..44dd4a0017e36a868bbb6d9fca99d01bf2af8914 100644 (file)
@@ -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 (file)
index 0000000..41f1c78
--- /dev/null
@@ -0,0 +1,129 @@
+#include "vrps.h"
+
+#include <netinet/in.h>
+#include <stdlib.h>
+#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 (file)
index 0000000..41aabad
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef SRC_VRPS_H_
+#define SRC_VRPS_H_
+
+#include <netinet/ip.h>
+
+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_ */