]> git.ipfire.org Git - thirdparty/FORT-validator.git/commitdiff
Add checksum comparison for slurm files
authordhfelix <daniel.hdz.felix@hotmail.com>
Thu, 26 Mar 2020 18:20:08 +0000 (12:20 -0600)
committerdhfelix <daniel.hdz.felix@hotmail.com>
Thu, 26 Mar 2020 18:20:08 +0000 (12:20 -0600)
If no new or modified slurm files were found, same old slurm will apply
and this will avoid to parse the same previous slurm file.

src/crypto/hash.c
src/crypto/hash.h
src/rtr/db/vrps.c
src/slurm/db_slurm.c
src/slurm/db_slurm.h
src/slurm/slurm_loader.c

index 53ec81ed61dd8c76145c928bffd2e296b3f8f1da..cd747ccb2f2ace09807257e889dea1a0009a25ad 100644 (file)
@@ -36,6 +36,14 @@ hash_matches(unsigned char const *expected, size_t expected_len,
 static int
 hash_file(char const *algorithm, struct rpki_uri *uri, unsigned char *result,
     unsigned int *result_len)
+{
+       return hash_local_file(algorithm, uri_get_local(uri), result,
+               result_len);
+}
+
+int
+hash_local_file(char const *algorithm, char const *uri, unsigned char *result,
+    unsigned int *result_len)
 {
        EVP_MD const *md;
        FILE *file;
@@ -50,7 +58,7 @@ hash_file(char const *algorithm, struct rpki_uri *uri, unsigned char *result,
        if (error)
                return error;
 
-       error = file_open(uri_get_local(uri), &file, &stat);
+       error = file_open(uri, &file, &stat);
        if (error)
                return error;
 
index 43c2af617a6821a334d44359483ee377f50497f3..65910287ba0c640db84145e0850e1f7a1ef4b859 100644 (file)
@@ -15,4 +15,8 @@ int hash_validate(char const *, unsigned char const *, size_t,
 int hash_validate_octet_string(char const *, OCTET_STRING_t const*,
     OCTET_STRING_t const *);
 
+int hash_local_file(char const *, char const *, unsigned char *,
+    unsigned int *);
+
+
 #endif /* SRC_HASH_H_ */
index 03ed98eeff2fd3af1c6d93153b03156a79555f62..a54dbc2cb8301f7eeb0841ab5b787127a4398d57 100644 (file)
@@ -290,10 +290,8 @@ __vrps_update(bool *changed)
                return error;
 
        error = slurm_apply(&new_base, &state.slurm);
-       if (error) {
-               rwlock_unlock(&state_lock);
+       if (error)
                goto revert_base;
-       }
 
        rwlock_write_lock(&state_lock);
 
index 7a3e4250617de8f005310bf36e47484906b2ad0f..bff42a93cf167a11a5c9a51218ee02fd5587009c 100644 (file)
@@ -36,6 +36,7 @@ struct db_slurm {
        struct slurm_lists *cache;
        bool loaded_date_set;
        time_t loaded_date;
+       struct slurm_csum_list csum_list;
 };
 
 char addr_buf[INET6_ADDRSTRLEN];
@@ -112,6 +113,9 @@ db_slurm_create(struct db_slurm **result)
        db->loaded_date_set = false;
        db->cache = NULL;
 
+       SLIST_INIT(&db->csum_list);
+       db->csum_list.list_size = 0;
+
        *result = db;
        return 0;
 }
@@ -672,8 +676,36 @@ db_slurm_has_data(struct db_slurm *db)
 void
 db_slurm_destroy(struct db_slurm *db)
 {
+       struct slurm_file_csum *tmp;
+
        slurm_lists_cleanup(&db->lists);
        if (db->cache)
                slurm_lists_destroy(db->cache);
+
+       while (!SLIST_EMPTY(&db->csum_list)) {
+               tmp = SLIST_FIRST(&db->csum_list);
+               SLIST_REMOVE_HEAD(&db->csum_list, next);
+               free(tmp);
+       }
+
        free(db);
 }
+
+int
+db_slurm_set_csum_list(struct db_slurm *db, struct slurm_csum_list *list)
+{
+       if (!SLIST_EMPTY(&db->csum_list))
+               return pr_err("Checksum list for SLURM DB must be empty");
+
+       db->csum_list.slh_first = list->slh_first;
+       db->csum_list.list_size = list->list_size;
+       return 0;
+}
+
+void
+db_slurm_get_csum_list(struct db_slurm *db, struct slurm_csum_list *result)
+{
+       result->list_size = db->csum_list.list_size;
+       result->slh_first = db->csum_list.slh_first;
+}
+
index 9bb12abe4f3aaeb1a42fadbc7cb0b17a91ee62e8..c644f8b350c2bc989439ba75df954d6f038207c7 100644 (file)
@@ -2,6 +2,9 @@
 #define SRC_SLURM_db_slurm_H_
 
 #include <stdbool.h>
+#include <sys/queue.h>
+#include <openssl/evp.h>
+
 #include "rtr/db/vrp.h"
 
 /* Flags to get data from structs */
@@ -27,6 +30,18 @@ struct slurm_bgpsec {
        unsigned char   *router_public_key;
 };
 
+
+struct slurm_file_csum {
+       unsigned char csum[EVP_MAX_MD_SIZE];
+       unsigned int csum_len;
+       SLIST_ENTRY(slurm_file_csum) next;
+};
+
+struct slurm_csum_list {
+       struct slurm_file_csum *slh_first;      /* first element */
+       unsigned int list_size;
+};
+
 struct db_slurm;
 
 typedef int (*prefix_foreach_cb)(struct slurm_prefix *, void *);
@@ -62,4 +77,7 @@ bool db_slurm_has_data(struct db_slurm *);
 
 void db_slurm_destroy(struct db_slurm *);
 
+int db_slurm_set_csum_list(struct db_slurm *, struct slurm_csum_list *);
+void db_slurm_get_csum_list(struct db_slurm *, struct slurm_csum_list *);
+
 #endif /* SRC_SLURM_db_slurm_H_ */
index 17bbab4973bbd830a530b87c49cfe2cc829992eb..00395e4d5e10c3aff210b99aaa3700463381ed6a 100644 (file)
@@ -8,6 +8,7 @@
 #include "log.h"
 #include "config.h"
 #include "common.h"
+#include "crypto/hash.h"
 #include "slurm/slurm_parser.h"
 
 #define SLURM_FILE_EXTENSION   ".slurm"
@@ -135,19 +136,71 @@ slurm_create_parser_params(struct slurm_parser_params **result)
        return 0;
 }
 
-int
-slurm_apply(struct db_table **base, struct db_slurm **last_slurm)
+static int
+__slurm_load_checksums(char const *location, void *arg)
 {
-       struct slurm_parser_params *params = NULL;
+       struct slurm_csum_list *list;
+       struct slurm_file_csum *csum;
        int error;
 
-       if (config_get_slurm() == NULL)
-               return 0;
+       list = arg;
+       csum = malloc(sizeof(struct slurm_file_csum));
+       if (csum == NULL)
+               return pr_enomem();
 
-       pr_info("Applying configured SLURM");
-       error = slurm_create_parser_params(&params);
-       if (error)
+
+       error = hash_local_file("sha256", location, csum->csum,
+           &csum->csum_len);
+       if (error) {
+               free(csum);
+               return pr_err("Calculating slurm hash");
+       }
+
+       SLIST_INSERT_HEAD(list, csum, next);
+       list->list_size++;
+
+       return 0;
+}
+
+static void
+destroy_local_csum_list(struct slurm_csum_list *list)
+{
+       struct slurm_file_csum *tmp;
+
+       while (!SLIST_EMPTY(list)) {
+               tmp = SLIST_FIRST(list);
+               SLIST_REMOVE_HEAD(list, next);
+               free(tmp);
+       }
+}
+
+static int
+slurm_load_checksums(struct slurm_csum_list *csum_list)
+{
+       struct slurm_csum_list result;
+       int error;
+
+       SLIST_INIT(&result);
+       result.list_size = 0;
+
+       error = process_file_or_dir(config_get_slurm(), SLURM_FILE_EXTENSION,
+           __slurm_load_checksums, &result);
+       if (error) {
+               destroy_local_csum_list(&result);
                return error;
+       }
+
+       csum_list->list_size = result.list_size;
+       csum_list->slh_first = result.slh_first;
+
+       return 0;
+}
+
+static void
+__slurm_apply(struct db_slurm **last_slurm, struct slurm_parser_params *params,
+    struct slurm_csum_list *csum_list)
+{
+       int error;
 
        error = slurm_load(params);
        if (!error) {
@@ -155,8 +208,10 @@ slurm_apply(struct db_table **base, struct db_slurm **last_slurm)
                if (*last_slurm != NULL)
                        db_slurm_destroy(*last_slurm);
                *last_slurm = params->db_slurm;
-               if (*last_slurm != NULL)
+               if (*last_slurm != NULL) {
                        db_slurm_update_time(*last_slurm);
+                       db_slurm_set_csum_list(*last_slurm, csum_list);
+               }
        } else {
                /* Any error: use last valid SLURM */
                pr_warn("Error loading SLURM, the validation will still continue.");
@@ -166,6 +221,84 @@ slurm_apply(struct db_table **base, struct db_slurm **last_slurm)
                        /* Log applied SLURM as info */
                        db_slurm_log(params->db_slurm);
                }
+               destroy_local_csum_list(csum_list);
+       }
+}
+
+static bool
+are_csum_lists_equals(struct slurm_csum_list *new_list,
+    struct slurm_csum_list *old_list)
+{
+       struct slurm_file_csum *newcsum, *old;
+       bool found = false;
+
+       if (new_list->list_size != old_list->list_size) {
+               return false;
+       }
+
+       SLIST_FOREACH(newcsum, new_list, next) {
+               SLIST_FOREACH(old, old_list, next) {
+
+                       if (newcsum->csum_len != old->csum_len)
+                               continue;
+
+                       if (memcmp(newcsum->csum, old->csum,
+                           newcsum->csum_len) == 0) {
+                               found = true;
+                               break;
+                       }
+               }
+
+               if (!found)
+                       return false;
+
+               found = false;
+       }
+
+       return true;
+}
+
+int
+slurm_apply(struct db_table **base, struct db_slurm **last_slurm)
+{
+       struct slurm_parser_params *params = NULL;
+       struct slurm_csum_list csum_list, old_csum_list;
+       int error;
+       bool list_equals = false;
+
+       if (config_get_slurm() == NULL)
+               return 0;
+
+       pr_info("Checking if there are new or modified SLURM files");
+       error = slurm_load_checksums(&csum_list);
+       if (error)
+               return error;
+
+       if (*last_slurm != NULL) {
+               db_slurm_get_csum_list(*last_slurm, &old_csum_list);
+               list_equals = are_csum_lists_equals(&csum_list, &old_csum_list);
+       }
+
+       error = slurm_create_parser_params(&params);
+       if (error)
+               return error;
+
+       if (list_equals) {
+               if (*last_slurm != NULL) {
+                       pr_info("Applying same old SLURM, no changes found.");
+                       params->db_slurm = *last_slurm;
+               }
+               destroy_local_csum_list(&csum_list);
+       } else {
+               if (csum_list.list_size == 0) {
+                       if (*last_slurm != NULL)
+                               db_slurm_destroy(*last_slurm);
+                       *last_slurm = params->db_slurm;
+                       /* Empty DIR or FILE SLURM not found */
+                       goto success;
+               }
+               pr_info("Applying configured SLURM");
+               __slurm_apply(last_slurm, params, &csum_list);
        }
 
        /* If there's no new SLURM loaded, stop */