struct slurm_lists *cache;
bool loaded_date_set;
time_t loaded_date;
+ struct slurm_csum_list csum_list;
};
char addr_buf[INET6_ADDRSTRLEN];
db->loaded_date_set = false;
db->cache = NULL;
+ SLIST_INIT(&db->csum_list);
+ db->csum_list.list_size = 0;
+
*result = db;
return 0;
}
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;
+}
+
#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 */
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 *);
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_ */
#include "log.h"
#include "config.h"
#include "common.h"
+#include "crypto/hash.h"
#include "slurm/slurm_parser.h"
#define SLURM_FILE_EXTENSION ".slurm"
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(¶ms);
- 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) {
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.");
/* 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(¶ms);
+ 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 */