]> git.ipfire.org Git - thirdparty/FORT-validator.git/commitdiff
Load and start parsing SLURM file (prefixes for now)
authorpcarana <pc.moreno2099@gmail.com>
Thu, 4 Apr 2019 18:13:22 +0000 (12:13 -0600)
committerpcarana <pc.moreno2099@gmail.com>
Thu, 4 Apr 2019 18:13:22 +0000 (12:13 -0600)
src/Makefile.am
src/configuration.c
src/configuration.h
src/main.c
src/slurm/slurm_parser.c [new file with mode: 0644]
src/slurm/slurm_parser.h [new file with mode: 0644]

index 74a897ab2e0d514b7f00306a4596d8f46056bd96..39cd7c8e3e111109f2a9cfbf37e2d5980853d053 100644 (file)
@@ -24,6 +24,8 @@ rtr_server_SOURCES += rtr/primitive_reader.c rtr/primitive_reader.h
 rtr_server_SOURCES += rtr/primitive_writer.c rtr/primitive_writer.h
 rtr_server_SOURCES += rtr/rtr.c rtr/rtr.h
 
+rtr_server_SOURCES += slurm/slurm_parser.c slurm/slurm_parser.h
+
 rtr_server_LDADD = ${JANSSON_LIBS}
 
 # I'm tired of scrolling up, but feel free to comment this out.
index 71089aaa6dda127e7801bde883380c6339d3eeeb..febe6e976d850de4636cb3b539ce4ea347d668f4 100644 (file)
@@ -22,6 +22,9 @@
 #define OPTNAME_RTR_INTERVAL_REFRESH   "refresh"
 #define OPTNAME_RTR_INTERVAL_RETRY     "retry"
 #define OPTNAME_RTR_INTERVAL_EXPIRE    "expire"
+#define OPTNAME_SLURM                  "slurm"
+#define OPTNAME_SLURM_LOCATION         "location"
+#define OPTNAME_SLURM_CHECK_INTERVAL   "checkInterval"
 
 #define DEFAULT_ADDR                   NULL
 #define DEFAULT_PORT                   "323"
@@ -31,6 +34,8 @@
 #define DEFAULT_REFRESH_INTERVAL       3600
 #define DEFAULT_RETRY_INTERVAL         600
 #define DEFAULT_EXPIRE_INTERVAL                7200
+#define DEFAULT_SLURM_LOCATION         NULL
+#define DEFAULT_SLURM_CHECK_INTERVAL   60
 
 /* Protocol timing parameters ranges in secs */
 #define MIN_VRPS_CHECK_INTERVAL                60
@@ -41,6 +46,8 @@
 #define MAX_RETRY_INTERVAL             7200
 #define MIN_EXPIRE_INTERVAL            600
 #define MAX_EXPIRE_INTERVAL            172800
+#define MIN_SLURM_CHECK_INTERVAL       60
+#define MAX_SLURM_CHECK_INTERVAL       7200
 
 /* Range values for other params */
 #define MIN_LISTEN_QUEUE               1
@@ -51,16 +58,20 @@ struct rtr_config {
        struct addrinfo *address;
        /** Stored aside only for printing purposes. */
        char *port;
-       /** VRPs (Validated ROA Payload) location */
-       char *vrps_location;
        /** Maximum accepted client connections */
        int queue;
+       /** VRPs (Validated ROA Payload) location */
+       char *vrps_location;
        /** Interval used to look for updates at VRPs location */
        int vrps_check_interval;
        /** Intervals use at RTR v1 End of data PDU **/
        int refresh_interval;
        int retry_interval;
        int expire_interval;
+       /** SLURM location */
+       char *slurm_location;
+       /** Interval used to look for updates at SLURM location */
+       int slurm_check_interval;
 } config;
 
 static int handle_json(json_t *);
@@ -234,6 +245,65 @@ load_intervals(json_t *root)
        return 0;
 }
 
+static int
+load_slurm(json_t *root)
+{
+       struct stat attr;
+       json_t *slurm;
+       char const *slurm_location;
+       int slurm_check_interval;
+       int error;
+
+       slurm = json_object_get(root, OPTNAME_SLURM);
+       if (slurm != NULL) {
+               if (!json_is_object(slurm)) {
+                       warnx("The '%s' element is not a JSON object.",
+                           OPTNAME_VRPS);
+                       return -EINVAL;
+               }
+
+               error = json_get_string(slurm, OPTNAME_SLURM_LOCATION,
+                           DEFAULT_SLURM_LOCATION, &slurm_location);
+               if (error)
+                       return error;
+
+               config.slurm_location = strdup(slurm_location);
+               if (config.slurm_location == NULL) {
+                       warn("'%s' couldn't be allocated.",
+                           OPTNAME_SLURM_LOCATION);
+                       return -errno;
+               }
+
+               error = load_range(slurm, OPTNAME_SLURM_CHECK_INTERVAL,
+                   DEFAULT_SLURM_CHECK_INTERVAL, &slurm_check_interval,
+                   MIN_SLURM_CHECK_INTERVAL, MAX_SLURM_CHECK_INTERVAL);
+               if (error)
+                       return error;
+               config.slurm_check_interval = slurm_check_interval;
+       } else {
+               config.slurm_location = DEFAULT_SLURM_LOCATION;
+               config.slurm_check_interval = DEFAULT_SLURM_CHECK_INTERVAL;
+       }
+
+       /* Validate data (only if a value was set */
+       if (config.slurm_location == NULL)
+               return 0;
+
+       error = stat(config.slurm_location, &attr) < 0;
+       if (error) {
+               warn("SLURM location '%s' isn't a valid path",
+                   config.slurm_location);
+               return -errno;
+       }
+       if (S_ISDIR(attr.st_mode) != 0) {
+               warnx("SLURM location '%s' isn't a file",
+                   config.slurm_location);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 static int
 handle_json(json_t *root)
 {
@@ -287,6 +357,10 @@ handle_json(json_t *root)
        if (error)
                return error;
 
+       error = load_slurm(root);
+       if (error)
+               return error;
+
        return init_addrinfo(address, port);
 }
 
@@ -372,18 +446,18 @@ config_get_server_port(void)
        return config.port;
 }
 
-char const *
-config_get_vrps_location(void)
-{
-       return config.vrps_location;
-}
-
 int
 config_get_server_queue(void)
 {
        return config.queue;
 }
 
+char const *
+config_get_vrps_location(void)
+{
+       return config.vrps_location;
+}
+
 int
 config_get_vrps_check_interval(void)
 {
@@ -407,3 +481,15 @@ config_get_expire_interval(void)
 {
        return config.expire_interval;
 }
+
+char const *
+config_get_slurm_location(void)
+{
+       return config.slurm_location;
+}
+
+int
+config_get_slurm_check_interval(void)
+{
+       return config.slurm_check_interval;
+}
index 18145363386f9709a970ae42cc9aeab79ab5dbe9..196a032daf8acca0cae76a57c72bebcac484ac4a 100644 (file)
@@ -15,4 +15,7 @@ int config_get_refresh_interval(void);
 int config_get_retry_interval(void);
 int config_get_expire_interval(void);
 
+char const *config_get_slurm_location(void);
+int config_get_slurm_check_interval(void);
+
 #endif /* _SRC_CONFIGURATION_H_ */
index 5496b58592b1428155ca414b142a80b847cd8ae0..d55d59e32d9b3ee05fbc5c5d2c3539715e7e5424 100644 (file)
@@ -4,6 +4,7 @@
 #include <unistd.h>
 
 #include "rtr/rtr.h"
+#include "slurm/slurm_parser.h"
 #include "clients.h"
 #include "configuration.h"
 #include "csv.h"
@@ -64,9 +65,17 @@ main(int argc, char *argv[])
        if (err)
                goto end3;
 
+       err = slurm_load();
+       if (err)
+               goto end3;
+
        err = rtr_listen();
+       if (err)
+               goto end4;
 
        rtr_cleanup();
+end4:
+       slurm_cleanup();
 end3:
        clients_db_destroy();
 end2:
diff --git a/src/slurm/slurm_parser.c b/src/slurm/slurm_parser.c
new file mode 100644 (file)
index 0000000..8d10220
--- /dev/null
@@ -0,0 +1,507 @@
+#include "slurm_parser.h"
+
+#include <err.h>
+#include <errno.h>
+#include <jansson.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "../address.h"
+#include "../configuration.h"
+
+/* JSON members */
+#define SLURM_VERSION                  "slurmVersion"
+#define VALIDATION_OUTPUT_FILTERS      "validationOutputFilters"
+#define PREFIX_FILTERS                 "prefixFilters"
+#define BGPSEC_FILTERS                 "bgpsecFilters"
+#define LOCALLY_ADDED_ASSERTIONS       "locallyAddedAssertions"
+#define PREFIX_ASSERTIONS              "prefixAssertions"
+#define BGPSEC_ASSERTIONS              "bgpsecAssertions"
+
+/* Prefix and BGPsec properties */
+#define PREFIX                         "prefix"
+#define ASN                            "asn"
+#define MAX_PREFIX_LENGTH              "maxPrefixLength"
+#define SKI                            "SKI"
+#define ROUTER_PUBLIC_KEY              "routerPublicKey"
+#define COMMENT                                "comment"
+
+#define CHECK_REQUIRED(element, name)                          \
+       if (element == NULL) {                                  \
+               warnx("SLURM member '%s' is required", name);   \
+               return -EINVAL;                                 \
+       }
+
+struct slurm_prefix {
+       u_int8_t data_flag;
+       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;
+       u_int8_t        addr_fam;
+       char const      *comment;
+};
+
+struct slurm_bgpsec {
+       u_int8_t data_flag;
+       u_int32_t asn;
+       /* TODO Add SKI (Base64) and routerPublicKey */
+       char const      *comment;
+};
+
+static int handle_json(json_t *);
+static int json_get_string(json_t *, char const *, char const **);
+static int json_get_int(json_t *, char const *, json_int_t *);
+static json_t *json_get_array(json_t *, char const *);
+static json_t *json_get_object(json_t *, char const *);
+
+int
+slurm_load(void)
+{
+       json_t *json_root;
+       json_error_t json_error;
+       int error;
+
+       /* Optional configuration */
+       if (config_get_slurm_location() == NULL)
+               return 0;
+
+       json_root = json_load_file(config_get_slurm_location(),
+           JSON_REJECT_DUPLICATES, &json_error);
+       if (json_root == NULL) {
+               warnx("SLURM JSON error on line %d, column %d: %s",
+                   json_error.line, json_error.column, json_error.text);
+               return -ENOENT;
+       }
+
+       error = handle_json(json_root);
+
+       json_decref(json_root);
+       return error;
+}
+
+void
+slurm_cleanup(void)
+{
+       /* TODO Nothing for now */
+}
+
+/*
+ * TODO Maybe some of the parsing functions can be on a common place, since
+ * csv.c also does a similar parsing
+ */
+
+static int
+parse_prefix4(char *text, struct ipv4_prefix *prefixv4)
+{
+       if (text == NULL)
+               return -EINVAL;
+       return prefix4_decode(text, prefixv4);
+}
+
+static int
+parse_prefix6(char *text, struct ipv6_prefix *prefixv6)
+{
+       if (text == NULL)
+               return -EINVAL;
+       return prefix6_decode(text, prefixv6);
+}
+
+static int
+parse_prefix_length(char *text, unsigned int *value, int max_value)
+{
+       if (text == NULL)
+               return -EINVAL;
+       return prefix_length_decode(text, value, max_value);
+}
+
+static int
+set_asn(json_t *object, bool is_assertion, u_int32_t *result,
+    u_int8_t *flag)
+{
+       json_int_t int_tmp;
+       int error;
+
+       error = json_get_int(object, ASN, &int_tmp);
+       if (error)
+               return error;
+
+       if (int_tmp == 0) {
+               /* Optional for filters */
+               if(is_assertion) {
+                       warnx("ASN is required");
+                       return -EINVAL;
+               } else
+                       return 0;
+       }
+
+       /* An underflow or overflow will be considered here */
+       if (int_tmp <= 0 || UINT32_MAX < int_tmp) {
+               warnx("ASN (%lld) is out of range [1 - %u].", int_tmp,
+                   UINT32_MAX);
+               return -EINVAL;
+       }
+       *flag = *flag | SLURM_COM_FLAG_ASN;
+       *result = (u_int32_t) int_tmp;
+       return 0;
+}
+
+static int
+set_prefix(json_t *object, bool is_assertion, struct slurm_prefix *result)
+{
+       struct ipv4_prefix prefixv4;
+       struct ipv6_prefix prefixv6;
+       char const *str_prefix;
+       char *clone, *token;
+       bool isv4;
+       int error;
+
+       /* First part: Prefix in string format */
+       error = json_get_string(object, PREFIX, &str_prefix);
+       if (error)
+               return error;
+
+       if (str_prefix == NULL) {
+               /* Optional for filters */
+               if(is_assertion) {
+                       warnx("SLURM assertion prefix is required");
+                       return -EINVAL;
+               } else
+                       return 0;
+       }
+
+       clone = strdup(str_prefix);
+       if (clone == NULL) {
+               warn("Couldn't allocate string to parse prefix");
+               return -errno;
+       }
+
+       token = strtok(clone, "/");
+       isv4 = strchr(token, ':') == NULL;
+       if (isv4)
+               error = parse_prefix4(token, &prefixv4);
+       else
+               error = parse_prefix6(token, &prefixv6);
+
+       if (error) {
+               free(clone);
+               return error;
+       }
+
+       /* Second part: Prefix length in numeric format */
+       token = strtok(NULL, "/");
+       error = parse_prefix_length(token,
+           isv4 ? &prefixv4.len : &prefixv6.len,
+           isv4 ? 32 : 128);
+       free(clone);
+       if (error)
+               return error;
+
+       if (isv4) {
+               error = prefix4_validate(&prefixv4);
+               if (error)
+                       return error;
+               result->addr_fam = AF_INET;
+               result->ipv4_prefix = prefixv4.addr;
+               result->prefix_length = prefixv4.len;
+       } else {
+               error = prefix6_validate(&prefixv6);
+               if (error)
+                       return error;
+               result->addr_fam = AF_INET6;
+               result->ipv6_prefix = prefixv6.addr;
+               result->prefix_length = prefixv6.len;
+       }
+       result->data_flag |= SLURM_PFX_FLAG_PREFIX;
+       return 0;
+}
+
+static int
+set_comment(json_t *object, char const **comment, u_int8_t *flag)
+{
+       int error;
+
+       error = json_get_string(object, COMMENT, comment);
+       if (error)
+               return error;
+
+       if (*comment != NULL)
+               *flag = *flag | SLURM_COM_FLAG_COMMENT;
+
+       return 0;
+}
+
+static int
+set_max_prefix_length(json_t *object, bool is_assertion, u_int8_t addr_fam,
+    u_int8_t *result, u_int8_t *flag)
+{
+       json_int_t int_tmp;
+       int error;
+
+       /* Ignore for filters */
+       if (!is_assertion)
+               return 0;
+
+       error = json_get_int(object, MAX_PREFIX_LENGTH, &int_tmp);
+       if (error)
+               return error;
+
+       /* Optional for assertions */
+       if (int_tmp == 0)
+               return 0;
+
+       /* An underflow or overflow will be considered here */
+       if (int_tmp <= 0 || (addr_fam == AF_INET ? 32 : 128) < int_tmp) {
+               warnx("Max prefix length (%lld) is out of range [1 - %d].",
+                   int_tmp, (addr_fam == AF_INET ? 32 : 128));
+               return -EINVAL;
+       }
+       *flag = *flag | SLURM_PFX_FLAG_MAX_LENGTH;
+       *result = (u_int8_t) int_tmp;
+       return 0;
+
+}
+
+static int
+load_single_prefix(json_t *object, bool is_assertion)
+{
+       struct slurm_prefix result;
+       int error;
+
+       if (!json_is_object(object)) {
+               warnx("Not a valid JSON object");
+               return -EINVAL;
+       }
+
+       result.data_flag = SLURM_COM_FLAG_NONE;
+
+       error = set_asn(object, is_assertion, &result.asn, &result.data_flag);
+       if (error)
+               return error;
+
+       error = set_prefix(object, is_assertion, &result);
+       if (error)
+               return error;
+
+       error = set_comment(object, &result.comment, &result.data_flag);
+       if (error)
+               return error;
+
+       error = set_max_prefix_length(object, is_assertion, result.addr_fam,
+           &result.max_prefix_length, &result.data_flag);
+       if (error)
+               return error;
+
+       if (is_assertion && (result.data_flag & SLURM_PFX_FLAG_MAX_LENGTH))
+               if (result.prefix_length > result.max_prefix_length) {
+                       warnx(
+                           "Prefix length is greater than max prefix length");
+                       return -EINVAL;
+               }
+
+       /* TODO Loaded! Now persist it... */
+       return 0;
+}
+
+static int
+load_prefix_array(json_t *array, bool is_assertion)
+{
+       json_t *element;
+       int index, error;
+
+       json_array_foreach(array, index, element) {
+               error = load_single_prefix(element, is_assertion);
+               if (error) {
+                       warnx(
+                           "Error at prefix %s, element %d, ignoring content",
+                           (is_assertion ? "assertions" : "filters"),
+                           index + 1);
+               }
+       }
+
+       return 0;
+}
+
+static int
+load_bgpsec_array(json_t *array, bool is_assertion)
+{
+       /* TODO Complete me */
+       return 0;
+}
+
+static int
+load_version(json_t *root)
+{
+       json_int_t version;
+       int error;
+
+       version = -1;
+       error = json_get_int(root, SLURM_VERSION, &version);
+       if (error)
+               return error;
+
+       /* Validate data */
+       if (version != 1) {
+               warnx("'%s' must be 1", SLURM_VERSION);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int
+load_filters(json_t *root)
+{
+       json_t *filters, *prefix, *bgpsec;
+       int error;
+
+       filters = json_get_object(root, VALIDATION_OUTPUT_FILTERS);
+       CHECK_REQUIRED(filters, VALIDATION_OUTPUT_FILTERS)
+
+       prefix = json_get_array(filters, PREFIX_FILTERS);
+       CHECK_REQUIRED(prefix, PREFIX_FILTERS)
+
+       bgpsec = json_get_array(filters, BGPSEC_FILTERS);
+       CHECK_REQUIRED(bgpsec, BGPSEC_FILTERS)
+
+       /* Arrays loaded, now iterate */
+       error = load_prefix_array(prefix, false);
+       if (error)
+               return error;
+
+       error = load_bgpsec_array(bgpsec, false);
+       if (error)
+               return error;
+
+       return 0;
+}
+
+static int
+load_assertions(json_t *root)
+{
+       json_t *assertions, *prefix, *bgpsec;
+       int error;
+
+       assertions = json_get_object(root, LOCALLY_ADDED_ASSERTIONS);
+       CHECK_REQUIRED(assertions, LOCALLY_ADDED_ASSERTIONS)
+
+       prefix = json_get_array(assertions, PREFIX_ASSERTIONS);
+       CHECK_REQUIRED(prefix, PREFIX_ASSERTIONS)
+
+       bgpsec = json_get_array(assertions, BGPSEC_ASSERTIONS);
+       CHECK_REQUIRED(bgpsec, BGPSEC_ASSERTIONS)
+
+       error = load_prefix_array(prefix, true);
+       if (error)
+               return error;
+
+       error = load_bgpsec_array(bgpsec, true);
+       if (error)
+               return error;
+
+       return 0;
+}
+
+static int
+handle_json(json_t *root)
+{
+       int error;
+
+       if (!json_is_object(root)) {
+               warnx("The root of the SLURM is not a JSON object.");
+               return -EINVAL;
+       }
+
+       error = load_version(root);
+       if (error)
+               return error;
+
+       error = load_filters(root);
+       if (error)
+               return error;
+
+       error = load_assertions(root);
+       if (error)
+               return error;
+
+       return 0;
+}
+
+static int
+json_get_string(json_t *parent, char const *name, char const **result)
+{
+       json_t *child;
+
+       child = json_object_get(parent, name);
+       if (child == NULL) {
+               *result = NULL;
+               return 0;
+       }
+
+       if (!json_is_string(child)) {
+               warnx("The '%s' element is not a JSON string.", name);
+               return -EINVAL;
+       }
+
+       *result = json_string_value(child);
+       return 0;
+}
+
+static int
+json_get_int(json_t *parent, char const *name, json_int_t *result)
+{
+       json_t *child;
+
+       child = json_object_get(parent, name);
+       if (child == NULL) {
+               *result = 0;
+               return 0;
+       }
+
+       if (!json_is_integer(child)) {
+               warnx("The '%s' element is not a JSON integer.", name);
+               return -EINVAL;
+       }
+
+       *result = json_integer_value(child);
+       return 0;
+}
+
+static json_t *
+json_get_array(json_t *parent, char const *name)
+{
+       json_t *child;
+
+       child = json_object_get(parent, name);
+       if (child == NULL) {
+               return NULL;
+       }
+
+       if (!json_is_array(child)) {
+               warnx("The '%s' element is not a JSON array.", name);
+               return NULL;
+       }
+
+       return child;
+}
+
+static json_t *
+json_get_object(json_t *parent, char const *name)
+{
+       json_t *child;
+
+       child = json_object_get(parent, name);
+       if (child == NULL)
+               return NULL;
+
+       if (!json_is_object(child)) {
+               warnx("The '%s' element is not a JSON object.", name);
+               return NULL;
+       }
+
+       return child;
+}
diff --git a/src/slurm/slurm_parser.h b/src/slurm/slurm_parser.h
new file mode 100644 (file)
index 0000000..8378f12
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef SRC_SLURM_SLURM_PARSER_H_
+#define SRC_SLURM_SLURM_PARSER_H_
+
+/* Flags to get data from structs */
+#define SLURM_COM_FLAG_NONE            0x00
+#define SLURM_COM_FLAG_ASN             0x01
+#define SLURM_COM_FLAG_COMMENT         0x02
+
+#define SLURM_PFX_FLAG_PREFIX          0x04
+#define SLURM_PFX_FLAG_MAX_LENGTH      0x08
+
+#define SLURM_BGPS_FLAG_SKI            0x04
+#define SLURM_BGPS_FLAG_ROUTER_KEY     0x08
+
+
+int slurm_load(void);
+void slurm_cleanup(void);
+
+#endif /* SRC_SLURM_SLURM_PARSER_H_ */