-Add functions to apply SLURM BGPsec filters and assertions.
-Remove length variables of SKI and SPKI on SLURM BGPsec structs.
-Send Router Key PDUs of base data (only PDUs from deltas were sent).
-Update outdated unit tests (bad calls, missing calls, impersonate functions).
-Complete filtering functions for BGPsec data.
}
}
-/*
- * FIXME and TODO: add more funcs for router keys
- * void
- * db_table_remove_router_key(struct db_table *table,
- * struct router_key const *del)
- * {
- * struct hashable_key *ptr;
- *
- * HASH_FIND(hh, table->router_keys, del, sizeof(*del), ptr);
- * if (ptr != NULL) {
- * HASH_DELETE(hh, table->router_keys, ptr);
- * router_key_cleanup(&ptr->data);
- * free(ptr);
- * }
- * }
- */
+void
+db_table_remove_router_key(struct db_table *table,
+ struct router_key const *del)
+{
+ struct hashable_key *ptr;
+
+ HASH_FIND(hh, table->router_keys, del, sizeof(*del), ptr);
+ if (ptr != NULL) {
+ HASH_DELETE(hh, table->router_keys, ptr);
+ router_key_cleanup(&ptr->data);
+ free(ptr);
+ }
+}
int
rtrhandler_handle_roa_v4(struct db_table *table, uint32_t asn,
int db_table_foreach_roa(struct db_table *, vrp_foreach_cb, void *);
void db_table_remove_roa(struct db_table *, struct vrp const *);
-int db_table_foreach_router_key(struct db_table *, router_key_foreach_cb cb,
+int db_table_foreach_router_key(struct db_table *, router_key_foreach_cb,
void *);
+void db_table_remove_router_key(struct db_table *, struct router_key const *);
int rtrhandler_handle_roa_v4(struct db_table *, uint32_t,
struct ipv4_prefix const *, uint8_t);
if (error)
return error;
- /* FIXME Temporary, this must not be null */
- if (cb_bgpsec == NULL)
- return 0;
-
error = __foreach_bgpsec(&deltas->bgpsec.adds, cb_bgpsec, arg, serial,
FLAG_ANNOUNCEMENT);
if (error)
SLIST_ENTRY(vrp_node) next;
};
+struct bgpsec_node {
+ struct delta_bgpsec delta;
+ SLIST_ENTRY(bgpsec_node) next;
+};
+
/** Sorted list to filter deltas */
SLIST_HEAD(vrp_slist, vrp_node);
+SLIST_HEAD(bgpsec_slist, bgpsec_node);
+
+struct sorted_lists {
+ struct vrp_slist prefixes;
+ struct bgpsec_slist bgpsec;
+};
struct state {
/**
* 2. -EAGAIN: No data available; database still under construction.
*/
int
-vrps_foreach_base_roa(vrp_foreach_cb cb, void *arg)
+vrps_foreach_base(vrp_foreach_cb cb_roa, router_key_foreach_cb cb_rk, void *arg)
{
int error;
if (error)
return error;
- if (state.base != NULL)
- error = db_table_foreach_roa(state.base, cb, arg);
- else
+ if (state.base != NULL) {
+ error = db_table_foreach_roa(state.base, cb_roa, arg);
+ if (error)
+ goto unlock;
+ error = db_table_foreach_router_key(state.base, cb_rk, arg);
+ } else
error = -EAGAIN;
+unlock:
rwlock_unlock(&lock);
return error;
static int
vrp_ovrd_remove(struct delta_vrp const *delta, void *arg)
{
+ struct sorted_lists *lists = arg;
struct vrp_node *ptr;
- struct vrp_slist *filtered_vrps = arg;
+ struct vrp_slist *filtered_vrps;
+ filtered_vrps = &lists->prefixes;
SLIST_FOREACH(ptr, filtered_vrps, next)
if (VRP_EQ(&delta->vrp, &ptr->delta.vrp) &&
delta->flags != ptr->delta.flags) {
return 0;
}
+static int
+bgpsec_ovrd_remove(struct delta_bgpsec const *delta, void *arg)
+{
+ struct sorted_lists *lists = arg;
+ struct bgpsec_node *ptr;
+ struct bgpsec_slist *filtered_bgpsec;
+ struct router_key const *key;
+
+ filtered_bgpsec = &lists->bgpsec;
+ SLIST_FOREACH(ptr, filtered_bgpsec, next) {
+ key = &delta->router_key;
+ if (key->as == ptr->delta.router_key.as &&
+ memcmp(sk_info_get_ski(key->sk),
+ sk_info_get_ski(ptr->delta.router_key.sk), RK_SKI_LEN) &&
+ memcmp(sk_info_get_spk(key->sk),
+ sk_info_get_spk(ptr->delta.router_key.sk), RK_SPKI_LEN) &&
+ delta->flags != ptr->delta.flags) {
+ SLIST_REMOVE(filtered_bgpsec, ptr, bgpsec_node, next);
+ free(ptr);
+ return 0;
+ }
+ }
+
+ ptr = malloc(sizeof(struct bgpsec_node));
+ if (ptr == NULL)
+ return pr_enomem();
+
+ ptr->delta = *delta;
+ SLIST_INSERT_HEAD(filtered_bgpsec, ptr, next);
+ return 0;
+}
+
/*
* Remove all operations on @deltas that override each other, and do @cb (with
* @arg) on each element of the resultant delta.
*/
int
-vrps_foreach_filtered_delta(struct deltas_db *deltas, delta_vrp_foreach_cb cb,
+vrps_foreach_filtered_delta(struct deltas_db *deltas,
+ delta_vrp_foreach_cb cb_prefix, delta_bgpsec_foreach_cb cb_bgpsec,
void *arg)
{
- struct vrp_slist filtered_vrps;
+ struct sorted_lists filtered_lists;
struct delta_group *group;
- struct vrp_node *ptr;
+ struct vrp_node *vnode;
+ struct bgpsec_node *bnode;
array_index i;
int error = 0;
* (We'll have to build a separate list because the database nodes
* are immutable.)
*/
- SLIST_INIT(&filtered_vrps);
+ SLIST_INIT(&filtered_lists.prefixes);
+ SLIST_INIT(&filtered_lists.bgpsec);
ARRAYLIST_FOREACH(deltas, group, i) {
- /* FIXME Add cb function for router keys */
error = deltas_foreach(group->serial, group->deltas,
- vrp_ovrd_remove, NULL, &filtered_vrps);
+ vrp_ovrd_remove, bgpsec_ovrd_remove, &filtered_lists);
if (error)
goto release_list;
}
- /* Now do the callback on the filtered deltas */
- SLIST_FOREACH(ptr, &filtered_vrps, next) {
- error = cb(&ptr->delta, arg);
+ /* Now do the corresponding callback on the filtered deltas */
+ SLIST_FOREACH(vnode, &filtered_lists.prefixes, next) {
+ error = cb_prefix(&vnode->delta, arg);
+ if (error)
+ break;
+ }
+ SLIST_FOREACH(bnode, &filtered_lists.bgpsec, next) {
+ error = cb_bgpsec(&bnode->delta, arg);
if (error)
break;
}
release_list:
- while (!SLIST_EMPTY(&filtered_vrps)) {
- ptr = filtered_vrps.slh_first;
- SLIST_REMOVE_HEAD(&filtered_vrps, next);
- free(ptr);
+ while (!SLIST_EMPTY(&filtered_lists.prefixes)) {
+ vnode = filtered_lists.prefixes.slh_first;
+ SLIST_REMOVE_HEAD(&filtered_lists.prefixes, next);
+ free(vnode);
+ }
+ while (!SLIST_EMPTY(&filtered_lists.bgpsec)) {
+ bnode = filtered_lists.bgpsec.slh_first;
+ SLIST_REMOVE_HEAD(&filtered_lists.bgpsec, next);
+ free(bnode);
}
return error;
* Handle gracefully.
*/
-/* FIXME Also add BGPSEC */
-int vrps_foreach_base_roa(vrp_foreach_cb, void *);
+int vrps_foreach_base(vrp_foreach_cb, router_key_foreach_cb, void *);
int vrps_get_deltas_from(serial_t, serial_t *, struct deltas_db *);
int get_last_serial_number(serial_t *);
-/* FIXME Also filter BGPSEC */
int vrps_foreach_filtered_delta(struct deltas_db *, delta_vrp_foreach_cb,
- void *);
+ delta_bgpsec_foreach_cb, void *);
uint16_t get_current_session_id(uint8_t);
return send_prefix_pdu(args->fd, args->version, vrp, FLAG_ANNOUNCEMENT);
}
+
+
+static int
+send_base_router_key(struct router_key const *key, void *arg)
+{
+ struct base_roa_args *args = arg;
+ int error;
+
+ if (!args->started) {
+ error = send_cache_response_pdu(args->fd, args->version);
+ if (error)
+ return error;
+ args->started = true;
+ }
+
+ return send_router_key_pdu(args->fd, args->version, key,
+ FLAG_ANNOUNCEMENT);
+}
+
int
handle_reset_query_pdu(int fd, struct rtr_request const *request)
{
* queries than reset queries.
*/
- /* FIXME Apply to router keys as well */
- error = vrps_foreach_base_roa(send_base_roa, &args);
+ error = vrps_foreach_base(send_base_roa, send_base_router_key, &args);
/* See handle_serial_query_pdu() for some comments. */
switch (error) {
vrp_simply_send, router_key_simply_send, ¶m);
}
- /* FIXME Apply to router keys as well */
- return vrps_foreach_filtered_delta(deltas, vrp_simply_send, ¶m);
+ return vrps_foreach_filtered_delta(deltas, vrp_simply_send,
+ router_key_simply_send, ¶m);
}
#define GET_END_OF_DATA_LENGTH(version) \
#include <sys/socket.h> /* AF_INET, AF_INET6 (needed in OpenBSD) */
#include "data_structure/array_list.h"
+#include "object/router_key.h"
ARRAY_LIST(al_filter_prefix, struct slurm_prefix)
ARRAY_LIST(al_assertion_prefix, struct slurm_prefix)
/* Both have a SKI */
if ((bgpsec->data_flag & SLURM_BGPS_FLAG_SKI) > 0 &&
- (filter->data_flag & SLURM_BGPS_FLAG_SKI) > 0 &&
- bgpsec->ski_len == filter->ski_len)
- return memcmp(bgpsec->ski, filter->ski, bgpsec->ski_len) == 0;
+ (filter->data_flag & SLURM_BGPS_FLAG_SKI) > 0)
+ return memcmp(bgpsec->ski, filter->ski, RK_SKI_LEN) == 0;
return false;
}
equal = equal && left->asn == right->asn;
if ((left->data_flag & SLURM_BGPS_FLAG_SKI) > 0)
- equal = equal && left->ski_len == right->ski_len &&
- memcmp(left->ski, right->ski, left->ski_len) == 0;
+ equal = equal &&
+ memcmp(left->ski, right->ski, RK_SKI_LEN) == 0;
if ((left->data_flag & SLURM_BGPS_FLAG_ROUTER_KEY) > 0)
equal = equal &&
- left->router_public_key_len ==
- right->router_public_key_len &&
memcmp(left->router_public_key, right->router_public_key,
- left->router_public_key_len) == 0;
+ RK_SPKI_LEN) == 0;
return equal;
}
return 0;
}
+bool
+slurm_db_bgpsec_is_filtered(struct router_key const *key)
+{
+ struct slurm_bgpsec slurm_bgpsec;
+
+ sk_info_refget(key->sk);
+ slurm_bgpsec.data_flag = SLURM_COM_FLAG_ASN | SLURM_BGPS_FLAG_SKI
+ | SLURM_BGPS_FLAG_ROUTER_KEY;
+ slurm_bgpsec.ski = sk_info_get_ski(key->sk);
+ slurm_bgpsec.router_public_key = sk_info_get_spk(key->sk);
+ slurm_bgpsec.comment = NULL;
+ sk_info_refput(key->sk);
+
+ return bgpsec_filter_exists(&slurm_bgpsec);
+}
+
+int
+slurm_db_foreach_assertion_bgpsec(assertion_bgpsec_foreach_cb cb, void *arg)
+{
+ struct slurm_bgpsec *cursor;
+ array_index i;
+ int error;
+
+ ARRAYLIST_FOREACH(&array_lists_db.assertion_bgps_al, cursor, i) {
+ error = cb(cursor, arg);
+ if (error)
+ return error;
+ }
+
+ return 0;
+}
+
static void
clean_slurm_prefix(struct slurm_prefix *prefix)
{
};
typedef int (*assertion_pfx_foreach_cb)(struct slurm_prefix *, void *);
+typedef int (*assertion_bgpsec_foreach_cb)(struct slurm_bgpsec *, void *);
void slurm_db_init(void);
int slurm_db_add_bgpsec_filter(struct slurm_bgpsec *);
int slurm_db_add_bgpsec_assertion(struct slurm_bgpsec *);
-bool slurm_db_vrp_is_filtered(struct vrp const *vrp);
+bool slurm_db_vrp_is_filtered(struct vrp const *);
int slurm_db_foreach_assertion_prefix(assertion_pfx_foreach_cb, void *);
+bool slurm_db_bgpsec_is_filtered(struct router_key const *);
+int slurm_db_foreach_assertion_bgpsec(assertion_bgpsec_foreach_cb, void *);
+
void slurm_db_cleanup(void);
#endif /* SRC_SLURM_SLURM_DB_H_ */
base);
}
+static int
+slurm_bgpsec_filters_apply(struct router_key const *key, void *arg)
+{
+ struct db_table *table = arg;
+
+ if (slurm_db_bgpsec_is_filtered(key))
+ db_table_remove_router_key(table, key);
+
+ return 0;
+}
+
+static int
+slurm_bgpsec_assertions_add(struct slurm_bgpsec *bgpsec, void *arg)
+{
+ struct db_table *table = arg;
+
+ return rtrhandler_handle_router_key(table, bgpsec->ski,
+ bgpsec->asn, bgpsec->router_public_key);
+}
+
+static int
+slurm_bgpsec_assertions_apply(struct db_table *base)
+{
+ return slurm_db_foreach_assertion_bgpsec(slurm_bgpsec_assertions_add,
+ base);
+}
+
/*
* Load the SLURM file/dir and try to apply it on @base.
*
if (error)
goto release_new;
+ error = db_table_foreach_router_key(new_base,
+ slurm_bgpsec_filters_apply, new_base);
+ if (error)
+ goto release_new;
+
error = slurm_pfx_assertions_apply(new_base);
+ if (error) {
+ goto release_new;
+ }
+
+ error = slurm_bgpsec_assertions_apply(new_base);
if (!error) {
db_table_destroy(*base);
*base = new_base;
goto cleanup;
}
- /** TODO (next iteration) Apply BGPsec filters and assertions */
release_new:
db_table_destroy(new_base);
cleanup:
#include "log.h"
#include "address.h"
#include "json_parser.h"
+#include "object/router_key.h"
#include "slurm/slurm_db.h"
/* JSON members */
size_t *members_loaded)
{
char const *str_encoded;
+ size_t ski_len;
int error;
error = json_get_string(object, SKI, &str_encoded);
if (error)
return error;
- error = base64url_decode(str_encoded, &result->ski, &result->ski_len);
+ error = base64url_decode(str_encoded, &result->ski, &ski_len);
if (error)
return error;
/* Validate that's at least 20 octects long */
- if (result->ski_len != 20) {
+ if (ski_len != RK_SKI_LEN) {
free(result->ski);
return pr_err("The decoded SKI must be 20 octets long");
}
struct slurm_bgpsec *result, size_t *members_loaded)
{
char const *str_encoded;
+ size_t spk_len;
int error;
error = json_get_string(object, ROUTER_PUBLIC_KEY, &str_encoded);
return error;
error = base64url_decode(str_encoded, &result->router_public_key,
- &result->router_public_key_len);
+ &spk_len);
if (error)
return pr_err("'%s' couldn't be decoded", str_encoded);
slurm_bgpsec->data_flag = SLURM_COM_FLAG_NONE;
slurm_bgpsec->asn = 0;
slurm_bgpsec->ski = NULL;
- slurm_bgpsec->ski_len = 0;
slurm_bgpsec->router_public_key = NULL;
- slurm_bgpsec->router_public_key_len = 0;
slurm_bgpsec->comment = NULL;
}
uint8_t data_flag;
uint32_t asn;
unsigned char *ski;
- size_t ski_len;
unsigned char *router_public_key;
- size_t router_public_key_len;
char *comment;
};
return -EINVAL;
}
+static int
+rk_fail(struct router_key const *key, void *arg)
+{
+ ck_abort_msg("Expected no callbacks, got from RK ASN %u.", key->as);
+ return -EINVAL;
+}
+
static array_index
get_vrp_index(struct vrp const *vrp)
{
return 0;
}
+static int
+rk_check(struct router_key const *rk, void *arg)
+{
+ /* FIXME (now) add index with Router key examples */
+ return 0;
+}
+
static int
delta_check(struct delta_vrp const *delta, void *arg)
{
return 0;
}
+static int
+delta_rk_check(struct delta_bgpsec const *delta, void *arg)
+{
+ /* FIXME (now) add index with Router key examples */
+ return 0;
+}
+
static void
check_serial(serial_t expected_serial)
{
memset(actual_base, 0, sizeof(actual_base));
ck_assert_int_eq(0, get_last_serial_number(&actual_serial));
- ck_assert_int_eq(0, vrps_foreach_base_roa(vrp_check, actual_base));
+ ck_assert_int_eq(0, vrps_foreach_base(vrp_check, rk_check,
+ actual_base));
ck_assert_uint_eq(expected_serial, actual_serial);
for (i = 0; i < ARRAY_LEN(actual_base); i++)
ck_assert_uint_eq(expected_base[i], actual_base[i]);
return 0;
}
+static int
+rk_add(struct delta_bgpsec const *delta, void *arg)
+{
+ struct deltas *deltas = arg;
+ struct router_key key;
+
+ key = delta->router_key;
+ deltas_add_bgpsec(deltas, &key, delta->flags);
+ return 0;
+}
+
static void
filter_deltas(struct deltas_db *db)
{
ck_assert_int_eq(0, deltas_create(&deltas));
group.deltas = deltas;
ck_assert_int_eq(0, vrps_foreach_filtered_delta(db, vrp_add,
- group.deltas));
+ rk_add, group.deltas));
deltas_db_init(&tmp);
ck_assert_int_eq(0, deltas_db_add(&tmp, &group));
filter_deltas(&deltas);
memset(actual_deltas, 0, sizeof(actual_deltas));
- /* FIXME Add cb function for router keys */
ARRAYLIST_FOREACH(&deltas, group, i)
ck_assert_int_eq(0, deltas_foreach(group->serial, group->deltas,
- delta_check, NULL, actual_deltas));
+ delta_check, delta_rk_check, actual_deltas));
for (i = 0; i < ARRAY_LEN(actual_deltas); i++)
ck_assert_uint_eq(expected_deltas[i], actual_deltas[i]);
}
/* First validation not yet performed: Tell routers to wait */
ck_assert_int_eq(-EAGAIN, get_last_serial_number(serial));
- ck_assert_int_eq(-EAGAIN, vrps_foreach_base_roa(vrp_fail,
+ ck_assert_int_eq(-EAGAIN, vrps_foreach_base(vrp_fail, rk_fail,
iterated_entries));
ck_assert_int_eq(-EAGAIN, vrps_get_deltas_from(0, serial, deltas));
}
int
-send_cache_reset_pdu(int fd)
+clients_set_rtr_version(int fd, uint8_t rtr_version)
+{
+ return 0;
+}
+
+int
+clients_get_rtr_version_set(int fd, bool *is_set, uint8_t *rtr_version)
+{
+ (*is_set) = true;
+ (*rtr_version) = RTR_V0;
+ return 0;
+}
+
+int
+send_cache_reset_pdu(int fd, uint8_t version)
{
pr_info(" Server sent Cache Reset.");
ck_assert_int_eq(pop_expected_pdu(), PDU_TYPE_CACHE_RESET);
}
int
-send_cache_response_pdu(int fd)
+send_cache_response_pdu(int fd, uint8_t version)
{
pr_info(" Server sent Cache Response.");
ck_assert_int_eq(pop_expected_pdu(), PDU_TYPE_CACHE_RESPONSE);
}
int
-send_prefix_pdu(int fd, struct vrp const *vrp, uint8_t flags)
+send_prefix_pdu(int fd, uint8_t version, struct vrp const *vrp, uint8_t flags)
{
/*
* We don't care about order.
return 0;
}
+int
+send_router_key_pdu(int fd, uint8_t version,
+ struct router_key const *router_key, uint8_t flags)
+{
+ /*
+ * We don't care about order.
+ * If the server is expected to return `M` IPv4 PDUs and `N` IPv6 PDUs,
+ * we'll just check `M + N` contiguous Prefix PDUs.
+ */
+ uint8_t pdu_type = pop_expected_pdu();
+ pr_info(" Server sent Router Key PDU.");
+ ck_assert_msg(pdu_type == PDU_TYPE_ROUTER_KEY,
+ "Server's PDU type is %d, not Router Key type.", pdu_type);
+ return 0;
+}
+
static int
handle_delta(struct delta_vrp const *delta, void *arg)
{
int *fd = arg;
- ck_assert_int_eq(0, send_prefix_pdu(*fd, &delta->vrp, delta->flags));
+ ck_assert_int_eq(0, send_prefix_pdu(*fd, RTR_V0, &delta->vrp,
+ delta->flags));
+ return 0;
+}
+
+static int
+handle_delta_bgpsec(struct delta_bgpsec const *delta, void *arg)
+{
+ int *fd = arg;
+ ck_assert_int_eq(0, send_router_key_pdu(*fd, RTR_V0, &delta->router_key,
+ delta->flags));
return 0;
}
int
-send_delta_pdus(int fd, struct deltas_db *deltas)
+send_delta_pdus(int fd, uint8_t version, struct deltas_db *deltas)
{
struct delta_group *group;
array_index i;
- /* FIXME Add cb function for router keys */
ARRAYLIST_FOREACH(deltas, group, i)
ck_assert_int_eq(0, deltas_foreach(group->serial, group->deltas,
- handle_delta, NULL, &fd));
+ handle_delta, handle_delta_bgpsec, &fd));
return 0;
}
int
-send_end_of_data_pdu(int fd, serial_t end_serial)
+send_end_of_data_pdu(int fd, uint8_t version, serial_t end_serial)
{
pr_info(" Server sent End of Data.");
ck_assert_int_eq(pop_expected_pdu(), PDU_TYPE_END_OF_DATA);
}
int
-send_error_report_pdu(int fd, uint16_t code, struct rtr_request const *request,
- char *message)
+send_error_report_pdu(int fd, uint8_t version, uint16_t code,
+ struct rtr_request const *request, char *message)
{
pr_info(" Server sent Error Report %u: '%s'", code, message);
ck_assert_int_eq(pop_expected_pdu(), PDU_TYPE_ERROR_REPORT);
return 12345;
}
+int
+clients_set_rtr_version(int fd, uint8_t rtr_version)
+{
+ return 0;
+}
+
+int
+clients_get_rtr_version_set(int fd, bool *is_set, uint8_t *rtr_version)
+{
+ (*is_set) = true;
+ (*rtr_version) = RTR_V0;
+ return 0;
+}
+
IMPERSONATE_HANDLER(serial_notify)
IMPERSONATE_HANDLER(serial_query)
IMPERSONATE_HANDLER(reset_query)
IMPERSONATE_HANDLER(error_report)
int
-send_error_report_pdu(int fd, uint16_t code, struct rtr_request const *request,
- char *message)
+send_error_report_pdu(int fd, uint8_t version, uint16_t code,
+ struct rtr_request const *request, char *message)
{
pr_info(" Server sent Error Report %u: '%s'", code, message);
return 0;