#include <pthread.h>
#include "common.h"
#include "log.h"
- #include "data_structure/uthash.h"
+ #include "data_structure/uthash_nonfatal.h"
+#include "rtr/pdu.h"
- /*
- * TODO uthash panics on memory allocations...
- * http://troydhanson.github.io/uthash/userguide.html#_out_of_memory
- */
#define SADDR_IN(addr) ((struct sockaddr_in *) addr)
#define SADDR_IN6(addr) ((struct sockaddr_in6 *) addr)
rwlock_write_lock(&lock);
- HASH_FIND_INT(table, &fd, old_client);
+ HASH_FIND_INT(table, &client->fd, old_client);
if (old_client == NULL) {
+ errno = 0;
HASH_ADD_INT(table, meat.fd, new_client);
+ if (errno) {
+ rwlock_unlock(&lock);
+ free(new_client);
+ return -pr_errno(errno, "Couldn't create client");
+ }
new_client = NULL;
- } else {
- /*
- * Isn't ready to handle distinct version on clients
- * reconnection, but for now there's no problem since only
- * RTRv0 is supported.
- */
- if (old_client->meat.rtr_version != rtr_version)
- error = -ERTR_VERSION_MISMATCH;
}
rwlock_unlock(&lock);
return 0;
}
-roa_table_remove_roa(struct roa_table *table, struct vrp *del)
+ static int
+ duplicate_roa(struct roa_table *dst, struct hashable_roa *new)
+ {
+ struct vrp vrp;
+ struct ipv4_prefix prefix4;
+ struct ipv6_prefix prefix6;
+
+ vrp = new->data;
+ switch (vrp.addr_fam) {
+ case AF_INET:
+ prefix4.addr = vrp.prefix.v4;
+ prefix4.len = vrp.prefix_length;
+ return rtrhandler_handle_roa_v4(dst, vrp.asn, &prefix4,
+ vrp.max_prefix_length);
+ case AF_INET6:
+ prefix6.addr = vrp.prefix.v6;
+ prefix6.len = vrp.prefix_length;
+ return rtrhandler_handle_roa_v6(dst, vrp.asn, &prefix6,
+ vrp.max_prefix_length);
+ }
+ return pr_crit("Unknown address family: %d", vrp.addr_fam);
+ }
+
+ static int
+ roa_table_merge(struct roa_table *dst, struct roa_table *src)
+ {
+ struct hashable_roa *node, *tmp, *found;
+ int error;
+
+ /** Must look for it due to the new mem allocation */
+ HASH_ITER(hh, src->roas, node, tmp) {
+ HASH_FIND(hh, dst->roas, &node->data, sizeof(node->data),
+ found);
+ if (found != NULL)
+ continue;
+ error = duplicate_roa(dst, node);
+ if (error)
+ return error;
+ }
+
+ return 0;
+ }
+
+ int
+ rtrhandler_merge(struct roa_table *dst, struct roa_table *src)
+ {
+ return roa_table_merge(dst, src);
+ }
+
+ void
++roa_table_remove_roa(struct roa_table *table, struct vrp const *del)
+ {
+ struct hashable_roa *ptr;
+
+ HASH_FIND(hh, table->roas, del, sizeof(*del), ptr);
+ if (ptr != NULL) {
+ HASH_DELETE(hh, table->roas, ptr);
+ free(ptr);
+ }
+ }
+
int
rtrhandler_handle_roa_v4(struct roa_table *table, uint32_t asn,
struct ipv4_prefix const *prefix4, uint8_t max_length)
void roa_table_destroy(struct roa_table *);
int roa_table_foreach_roa(struct roa_table *, vrp_foreach_cb, void *);
-void roa_table_remove_roa(struct roa_table *, struct vrp *);
++void roa_table_remove_roa(struct roa_table *, struct vrp const *);
int rtrhandler_reset(struct roa_table *);
int rtrhandler_handle_roa_v4(struct roa_table *, uint32_t,
#include "vrps.h"
#include <pthread.h>
-#include <stdbool.h>
+ #include <string.h>
+#include <time.h>
#include "clients.h"
#include "common.h"
+ #include "validation_handler.h"
+ #include "data_structure/array_list.h"
#include "object/tal.h"
#include "rtr/db/roa_table.h"
+ #include "slurm/slurm_loader.h"
/*
* Storage of VRPs (term taken from RFC 6811 "Validated ROA Payload") and
* calculated according to the new start.
*/
static void
-resize_deltas_db(struct deltas_db *db, struct delta *start)
+resize_deltas_db(struct deltas_db *db, struct delta_group *start)
{
- struct delta_group *tmp;
- struct delta *tmp, *ptr;
++ struct delta_group *tmp, *ptr;
db->len -= (start - db->array);
while (db->len < db->capacity / 2)
pr_enomem();
return;
}
- memcpy(tmp, start, db->len * sizeof(struct delta));
+ memcpy(tmp, start, db->len * sizeof(struct delta_group));
+ /* Release memory allocated */
+ for (ptr = db->array; ptr < start; ptr++)
- deltas_destroy(ptr->deltas);
++ deltas_put(ptr->deltas);
free(db->array);
db->array = tmp;
}
#include "pdu_sender.h"
#include "log.h"
+typedef enum rtr_error_code {
+ ERR_PDU_CORRUPT_DATA = 0,
+ ERR_PDU_INTERNAL_ERROR = 1,
+ ERR_PDU_NO_DATA_AVAILABLE = 2,
+ ERR_PDU_INVALID_REQUEST = 3,
+ ERR_PDU_UNSUP_PROTO_VERSION = 4,
+ ERR_PDU_UNSUP_PDU_TYPE = 5,
+ ERR_PDU_WITHDRAWAL_UNKNOWN = 6,
+ ERR_PDU_DUPLICATE_ANNOUNCE = 7,
+ /* RTRv1 only, so not used yet. */
+ ERR_PDU_UNEXPECTED_PROTO_VERSION = 8,
+} rtr_error_code_t;
+
+/*
+ * TODO (urgent) According to the function below, NO_DATA_AVAILABLE is not
+ * fatal. However, some callers of this function are terminating the connection
+ * regardless of that.
+ */
+static int
+err_pdu_send(int fd, rtr_error_code_t code, struct rtr_request const *request,
+ char const *message_const)
+{
+ char *message;
+
+ /*
+ * This function must always return error so callers can interrupt
+ * themselves easily.
+ * But note that not all callers should use this.
+ * TODO (now) Prevent errors to errors
+ * (It's harder than it seems, because request->pdu is sometimes NULL.)
+ */
+
+ message = (message_const != NULL) ? strdup(message_const) : NULL;
+ send_error_report_pdu(fd, code, request, message);
+ free(message);
+
+ return -EINVAL;
+}
+
int
-err_pdu_send(int fd, uint8_t version, uint16_t code, void *err_pdu_header,
+err_pdu_send_corrupt_data(int fd, struct rtr_request const *request,
char const *message)
{
- int error;
-
- error = send_error_report_pdu(fd, version, code, err_pdu_header,
- message);
- if (err_pdu_is_fatal(code)) {
- pr_warn("Fatal error report PDU sent [code %u], closing socket.",
- code);
- close(fd);
- }
+ return err_pdu_send(fd, ERR_PDU_CORRUPT_DATA, request, message);
+}
+
+/*
+ * Please note: If you're planning to send this error due to a memory
+ * allocation failure, you probably shouldn't; you'd likely only aggravate the
+ * problem.
+ */
+int
+err_pdu_send_internal_error(int fd)
+{
+ return err_pdu_send(fd, ERR_PDU_INTERNAL_ERROR, NULL, NULL);
+}
+
+int
+err_pdu_send_no_data_available(int fd)
+{
+ return err_pdu_send(fd, ERR_PDU_NO_DATA_AVAILABLE, NULL, NULL);
+}
- return error;
+int
+err_pdu_send_invalid_request(int fd, struct rtr_request const *request,
+ char const *message)
+{
+ return err_pdu_send(fd, ERR_PDU_INVALID_REQUEST, request, message);
+}
+
+/* Caution: @header is supposed to be in serialized form. */
+int
+err_pdu_send_invalid_request_truncated(int fd, unsigned char *header,
+ char const *message)
+{
+ struct rtr_request request = {
+ .bytes = header,
+ .bytes_len = RTRPDU_HEADER_LEN,
+ .pdu = NULL,
+ };
+ return err_pdu_send_invalid_request(fd, &request, message);
+}
+
++int
++err_pdu_send_unsupported_proto_version(int fd)
++{
++ return err_pdu_send(fd, ERR_PDU_UNSUP_PROTO_VERSION, NULL, NULL);
++}
++
+int
+err_pdu_send_unsupported_pdu_type(int fd, struct rtr_request const *request)
+{
+ return err_pdu_send(fd, ERR_PDU_UNSUP_PDU_TYPE, request, NULL);
}
bool
#include <stdbool.h>
#include <stdint.h>
-#define ERR_PDU_CORRUPT_DATA 0
-#define ERR_PDU_INTERNAL_ERROR 1
-#define ERR_PDU_NO_DATA_AVAILABLE 2
-#define ERR_PDU_INVALID_REQUEST 3
-#define ERR_PDU_UNSUP_PROTO_VERSION 4
-#define ERR_PDU_UNSUP_PDU_TYPE 5
-#define ERR_PDU_WITHDRAWAL_UNKNOWN 6
-#define ERR_PDU_DUPLICATE_ANNOUNCE 7
-#define ERR_PDU_UNEXPECTED_PROTO_VERSION 8
+#include "rtr/pdu.h"
+/*
+ * Wrappers for err_pdu_send().
+ * Mainly, this is for the sake of making it easier to see whether the error is
+ * supposed to contain a message and/or the original PDU or not.
+ */
+int err_pdu_send_corrupt_data(int, struct rtr_request const *, char const *);
+int err_pdu_send_internal_error(int);
+int err_pdu_send_no_data_available(int);
+int err_pdu_send_invalid_request(int, struct rtr_request const *, char const *);
+int err_pdu_send_invalid_request_truncated(int, unsigned char *, char const *);
++int err_pdu_send_unsupported_proto_version(int);
+int err_pdu_send_unsupported_pdu_type(int, struct rtr_request const *);
-int err_pdu_send(int, uint8_t, uint16_t, void *, char const *);
bool err_pdu_is_fatal(uint16_t);
-void err_pdu_log(uint16_t, char *);
+char const *err_pdu_to_string(uint16_t);
#endif /* SRC_RTR_ERR_PDU_H_ */
#include "common.h"
#include "log.h"
+#include "rtr/err_pdu.h"
#include "rtr/pdu_handler.h"
-static int pdu_header_from_stream(int, struct pdu_header *);
-static int serial_notify_from_stream(struct pdu_header *, int, void *);
-static int serial_query_from_stream(struct pdu_header *, int, void *);
-static int reset_query_from_stream(struct pdu_header *, int, void *);
-static int cache_response_from_stream(struct pdu_header *, int, void *);
-static int ipv4_prefix_from_stream(struct pdu_header *, int, void *);
-static int ipv6_prefix_from_stream(struct pdu_header *, int, void *);
-static int end_of_data_from_stream(struct pdu_header *, int, void *);
-static int cache_reset_from_stream(struct pdu_header *, int, void *);
-static int router_key_from_stream(struct pdu_header *, int, void *);
-static int error_report_from_stream(struct pdu_header *, int, void *);
-static void error_report_destroy(void *);
+static int
+pdu_header_from_reader(struct pdu_reader *reader, struct pdu_header *header)
+{
+ return read_int8(reader, &header->protocol_version)
+ || read_int8(reader, &header->pdu_type)
+ || read_int16(reader, &header->m.session_id)
+ || read_int32(reader, &header->length);
+}
int
-pdu_load(int fd, void **pdu, struct pdu_metadata const **metadata,
- uint8_t *rtr_version)
+pdu_load(int fd, struct rtr_request *request,
+ struct pdu_metadata const **metadata)
{
+ unsigned char hdr_bytes[RTRPDU_HEADER_LEN];
+ struct pdu_reader reader;
struct pdu_header header;
struct pdu_metadata const *meta;
- int err;
+ int error;
+
+ /* Read the header into its buffer. */
+ /*
+ * TODO (urgent) If the first read yields no bytes, the connection was
+ * terminated. We're not ending gracefully in those cases.
+ */
+ error = pdu_reader_init(&reader, fd, hdr_bytes, RTRPDU_HEADER_LEN);
+ if (error)
+ /* Communication interrupted; omit error response */
+ return error;
+ error = pdu_header_from_reader(&reader, &header);
+ if (error)
+ /* No error response because the PDU might have been an error */
+ return error;
- err = pdu_header_from_stream(fd, &header);
- if (err)
- return err;
+ /*
- * RTRv1 expects us to respond RTRv1 messages with RTRv0 messages,
- * and future protocols will probably do the same.
- * So don't validate the protocol version.
++ * For now, only RTRv0 is supported
+ */
++ if (header.protocol_version != RTR_V0)
++ return err_pdu_send_unsupported_proto_version(fd);
+
+ if (header.length < RTRPDU_HEADER_LEN)
+ return err_pdu_send_invalid_request_truncated(fd, hdr_bytes,
+ "PDU is too small. (< 8 bytes)");
+
+ /*
+ * Error messages can be quite large.
+ * But they're probably not legitimate, so drop 'em.
+ * 512 is like a 5-paragraph error message, so it's probably enough.
+ * (Warning: I'm assuming english tho.)
+ */
+ if (header.length > 512) {
+ pr_warn("Got an extremely large PDU (%u bytes). WTF?",
+ header.length);
+ return err_pdu_send_invalid_request_truncated(fd, hdr_bytes,
+ "PDU is too large. (> 512 bytes)");
+ }
+ /* Read the rest of the PDU into its buffer. */
+ request->bytes_len = header.length;
+ request->bytes = malloc(header.length);
+ if (request->bytes == NULL)
+ /* No error report PDU on allocation failures. */
+ return pr_enomem();
+
+ memcpy(request->bytes, hdr_bytes, RTRPDU_HEADER_LEN);
+ error = pdu_reader_init(&reader, fd,
+ request->bytes + RTRPDU_HEADER_LEN,
+ header.length - RTRPDU_HEADER_LEN);
+ if (error)
+ /* Communication interrupted; no error PDU. */
+ goto revert_bytes;
+
+ /* Deserialize the PDU. */
meta = pdu_get_metadata(header.pdu_type);
- if (!meta)
- return -ENOENT; /* TODO try to skip it anyway? */
+ if (!meta) {
+ error = err_pdu_send_unsupported_pdu_type(fd, request);
+ goto revert_bytes;
+ }
- *pdu = malloc(meta->length);
- if (*pdu == NULL)
- return -ENOMEM;
+ request->pdu = malloc(meta->length);
+ if (request->pdu == NULL) {
+ error = pr_enomem();
+ goto revert_bytes;
+ }
- err = meta->from_stream(&header, fd, *pdu);
- if (err) {
- free(*pdu);
- return err;
+ error = meta->from_stream(&header, &reader, request->pdu);
+ if (error) {
+ err_pdu_send_internal_error(fd);
+ goto revert_pdu;
}
- *rtr_version = header.protocol_version;
- if (metadata)
- *metadata = meta;
+ /* Happy path. */
+ *metadata = meta;
return 0;
-}
-static int
-pdu_header_from_stream(int fd, struct pdu_header *header)
-{
- /* If the first read yields no bytes, the connection was terminated. */
- return read_int8(fd, &header->protocol_version)
- || read_int8(fd, &header->pdu_type)
- || read_int16(fd, &header->m.session_id)
- || read_int32(fd, &header->length);
+revert_pdu:
+ free(request->pdu);
+revert_bytes:
+ free(request->bytes);
+ return error;
}
static int
header->m.reserved = reserved;
}
- /* TODO Include Router Key PDU serials */
-static uint32_t
-length_serial_notify_pdu(struct serial_notify_pdu *pdu)
-{
- return HEADER_LENGTH + sizeof(pdu->serial_number);
-}
-
-static uint32_t
-length_ipvx_prefix_pdu(bool isv4)
-{
- return HEADER_LENGTH +
- (isv4 ? IPV4_PREFIX_LENGTH : IPV6_PREFIX_LENGTH);
-}
-
-static uint32_t
-length_end_of_data_pdu(struct end_of_data_pdu *pdu)
-{
- uint32_t len;
-
- len = HEADER_LENGTH;
- len += sizeof(pdu->serial_number);
- if (pdu->header.protocol_version == RTR_V1) {
- len += sizeof(pdu->refresh_interval);
- len += sizeof(pdu->retry_interval);
- len += sizeof(pdu->expire_interval);
- }
-
- return len;
-}
-
+ /* TODO (next iteration) Include Router Key PDU serials */
/**
* static uint32_t
* length_router_key_pdu(struct router_key_pdu *pdu)
* }
*/
- /*
- * TODO Needs some testing, this is just a beta version
- */
- static int
- send_large_response(int fd, struct data_buffer *buffer)
-static uint32_t
-length_error_report_pdu(struct error_report_pdu *pdu)
--{
- unsigned char *tmp_buffer, *ptr;
- size_t buf_size, pending;
- int written;
-
- buf_size = buffer->capacity;
- pending = buffer->len;
- ptr = buffer->data;
- while (pending > 0) {
- tmp_buffer = calloc(pending, sizeof(unsigned char));
- if (tmp_buffer == NULL)
- return pr_enomem();
-
- memcpy(tmp_buffer, ptr, buf_size);
-
- written = write(fd, tmp_buffer, buf_size);
- free(tmp_buffer);
- if (written < 0)
- return pr_err("Error sending response");
-
- pending -= buf_size;
- ptr += buf_size;
- buf_size = pending > buffer->capacity ? buffer->capacity :
- pending;
- }
-
- return 0;
- return HEADER_LENGTH +
- pdu->error_pdu_length + sizeof(pdu->error_pdu_length) +
- pdu->error_message_length + sizeof(pdu->error_message_length);
--}
--
static int
send_response(int fd, unsigned char *data, size_t data_len)
{
#include "rtr/err_pdu.h"
#include "rtr/pdu.h"
- /* TODO (urgent) this needs to be atomic */
- volatile bool loop;
-/* TODO (next iteration) Support both RTR v0 and v1 */
-#define RTR_VERSION_SUPPORTED RTR_V0
-
+ struct sigaction act;
-/*
- * Arguments that the server socket thread will send to the client
- * socket threads whenever it creates them.
- */
-struct thread_param {
- int client_fd;
- struct sockaddr_storage client_addr;
-};
-
struct thread_node {
pthread_t tid;
- struct thread_param params;
+ struct rtr_client client;
SLIST_ENTRY(thread_node) next;
};
* The client socket threads' entry routine.
*/
static void *
-client_thread_cb(void *param_void)
+client_thread_cb(void *arg)
{
- struct thread_param *param = param_void;
+ struct rtr_client *client = arg;
struct pdu_metadata const *meta;
- void *pdu;
- int err;
- uint8_t rtr_version;
+ struct rtr_request request;
+ int error;
- while (loop) { /* For each PDU... */
+ while (true) { /* For each PDU... */
- err = pdu_load(param->client_fd, &pdu, &meta, &rtr_version);
- if (err)
- return end_client(param->client_fd, NULL, NULL);
-
- /* Protocol Version Negotiation */
- if (rtr_version != RTR_VERSION_SUPPORTED) {
- err_pdu_send(param->client_fd, RTR_VERSION_SUPPORTED,
- ERR_PDU_UNSUP_PROTO_VERSION,
- (struct pdu_header *) pdu, NULL);
- return end_client(param->client_fd, meta, pdu);
- }
- /* RTR Version ready, now update client */
- err = clients_add(param->client_fd, ¶m->client_addr,
- rtr_version);
- if (err) {
- if (err == -ERTR_VERSION_MISMATCH) {
- err_pdu_send(param->client_fd, rtr_version,
- (rtr_version == RTR_V0
- ? ERR_PDU_UNSUP_PROTO_VERSION
- : ERR_PDU_UNEXPECTED_PROTO_VERSION),
- (struct pdu_header *) pdu, NULL);
- }
- return end_client(param->client_fd, meta, pdu);
- }
+ error = pdu_load(client->fd, &request, &meta);
+ if (error)
+ break;
- err = meta->handle(param->client_fd, pdu);
- meta->destructor(pdu);
- if (err)
- return end_client(param->client_fd, NULL, NULL);
+ error = meta->handle(client->fd, &request);
+ clean_request(&request, meta);
+ if (error)
+ break;
}
- return NULL; /* Unreachable. */
+ return end_client(client);
}
/*
continue;
}
- new_thread->params.client_fd = client_fd;
- new_thread->params.client_addr = client_addr;
+ new_thread->client.fd = client_fd;
+ new_thread->client.addr = client_addr;
+
+ error = clients_add(&new_thread->client);
+ if (error) {
+ /*
+ * Presently, clients_add() can only fail due to alloc
+ * failure. No error report PDU.
+ */
+ free(new_thread);
+ close(client_fd);
+ continue;
+ }
- errno = pthread_create(&new_thread->tid, NULL,
- client_thread_cb, &new_thread->params);
- if (errno) {
- pr_errno(errno, "Could not spawn the client's thread");
+ error = pthread_create(&new_thread->tid, NULL,
+ client_thread_cb, &new_thread->client);
- if (error != EAGAIN)
++ if (error && error != EAGAIN)
+ err_pdu_send_internal_error(client_fd);
+ if (error) {
+ pr_errno(error, "Could not spawn the client's thread");
+ clients_forget(client_fd);
free(new_thread);
close(client_fd);
continue;
return equal;
}
- LOCATE_FUNCS(prefix_filter, struct slurm_prefix, struct al_filter_prefix,
- prefix_equal, true)
- LOCATE_FUNCS(bgpsec_filter, struct slurm_bgpsec, struct al_filter_bgpsec,
- bgpsec_equal, true)
- LOCATE_FUNCS(prefix_assertion, struct slurm_prefix, struct al_assertion_prefix,
- prefix_equal, false)
- LOCATE_FUNCS(bgpsec_assertion, struct slurm_bgpsec, struct al_assertion_bgpsec,
- bgpsec_equal, false)
-
- /*
- * Try to persist the @prefix filter, if it already exists or is covered
- * by another filter, then the error -EEXIST is returned; otherwise, returns
- * the result of persisting the @prefix.
- */
- int
- slurm_db_add_prefix_filter(struct slurm_prefix *prefix)
- {
- if (prefix_filter_exists(&array_lists_db.filter_pfx_al, prefix))
- return -EEXIST;
-
- return al_filter_prefix_add(&array_lists_db.filter_pfx_al, prefix);
- }
+ #define ADD_FUNCS(name, type, list_name, db_list, equal_cb, filter) \
+ static type * \
+ name##_locate(type *obj) \
+ { \
+ type *cursor; \
+ \
+ ARRAYLIST_FOREACH(db_list, cursor) \
+ if (equal_cb(cursor, obj, filter)) \
+ return cursor; \
+ \
+ return NULL; \
+ } \
+ \
+ static bool \
+ name##_exists(type *obj) \
+ { \
+ return name##_locate(obj) != NULL; \
+ } \
+ \
+ int \
+ slurm_db_add_##name(type *elem) { \
+ if (name##_exists(elem)) \
+ return -EEXIST; \
+ return list_name##_add(db_list, elem); \
+ }
- /*
- * Try to persist the @prefix assertion, if it already exists, then the error
- * -EEXIST is returned; otherwise, returns the result of persisting the
- * @prefix.
- */
- int
- slurm_db_add_prefix_assertion(struct slurm_prefix *prefix)
+ ADD_FUNCS(prefix_filter, struct slurm_prefix, al_filter_prefix,
+ &array_lists_db.filter_pfx_al, prefix_equal, true)
+ ADD_FUNCS(bgpsec_filter, struct slurm_bgpsec, al_filter_bgpsec,
+ &array_lists_db.filter_bgps_al, bgpsec_equal, true)
+ ADD_FUNCS(prefix_assertion, struct slurm_prefix, al_assertion_prefix,
+ &array_lists_db.assertion_pfx_al, prefix_equal, false)
+ ADD_FUNCS(bgpsec_assertion, struct slurm_bgpsec, al_assertion_bgpsec,
+ &array_lists_db.assertion_bgps_al, bgpsec_equal, false)
+
+ bool
-slurm_db_vrp_is_filtered(struct vrp *vrp)
++slurm_db_vrp_is_filtered(struct vrp const *vrp)
{
- if (prefix_assertion_exists(&array_lists_db.assertion_pfx_al, prefix))
- return -EEXIST;
-
- return al_assertion_prefix_add(&array_lists_db.assertion_pfx_al,
- prefix);
- }
+ struct slurm_prefix slurm_prefix;
- /*
- * Try to persist the @bgpsec filter, if it already exists or is covered
- * by another filter, then the error -EEXIST is returned; otherwise, returns
- * the result of persisting the @bgpsec.
- */
- int
- slurm_db_add_bgpsec_filter(struct slurm_bgpsec *bgpsec)
- {
- if (bgpsec_filter_exists(&array_lists_db.filter_bgps_al, bgpsec))
- return -EEXIST;
+ slurm_prefix.data_flag = SLURM_COM_FLAG_ASN | SLURM_PFX_FLAG_PREFIX
+ | SLURM_PFX_FLAG_MAX_LENGTH;
+ slurm_prefix.vrp = *vrp;
+ slurm_prefix.comment = NULL;
- return al_filter_bgpsec_add(&array_lists_db.filter_bgps_al, bgpsec);
+ return prefix_filter_exists(&slurm_prefix);
}
- /*
- * Try to persist the @bgpsec assertion, if it already exists, then the error
- * -EEXIST is returned; otherwise, returns the result of persisting the
- * @bgpsec.
- */
int
- slurm_db_add_bgpsec_assertion(struct slurm_bgpsec *bgpsec)
+ slurm_db_foreach_assertion_prefix(assertion_pfx_foreach_cb cb, void *arg)
{
- if (bgpsec_assertion_exists(&array_lists_db.assertion_bgps_al, bgpsec))
- return -EEXIST;
+ struct slurm_prefix *cursor;
+ int error;
- return al_assertion_bgpsec_add(&array_lists_db.assertion_bgps_al,
- bgpsec);
+ ARRAYLIST_FOREACH(&array_lists_db.assertion_pfx_al, cursor) {
+ error = cb(cursor, arg);
+ if (error)
+ return error;
+ }
+
+ return 0;
}
static 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 *vrp);
++bool slurm_db_vrp_is_filtered(struct vrp const *vrp);
+ int slurm_db_foreach_assertion_prefix(assertion_pfx_foreach_cb, void *);
+
void slurm_db_cleanup(void);
- #endif /* SRC_SLURM_DB_H_ */
+ #endif /* SRC_SLURM_SLURM_DB_H_ */
--- /dev/null
-slurm_pfx_filters_apply(struct vrp *vrp, void *arg)
+ #include "slurm_loader.h"
+
+ #include <stdlib.h>
+ #include <stdbool.h>
+
+ #include "log.h"
+ #include "config.h"
+ #include "common.h"
+ #include "slurm/slurm_db.h"
+ #include "slurm/slurm_parser.h"
+
+ #define SLURM_FILE_EXTENSION ".slurm"
+
+ static int
+ slurm_load(bool *loaded)
+ {
+ /* Optional configuration */
+ *loaded = false;
+ if (config_get_slurm_location() == NULL)
+ return 0;
+
+ *loaded = true;
+ slurm_db_init();
+
+ return process_dir_files(config_get_slurm_location(),
+ SLURM_FILE_EXTENSION, slurm_parse, NULL);
+ }
+
+ static void
+ slurm_cleanup(void)
+ {
+ /* Only if the SLURM was configured */
+ if (config_get_slurm_location() != NULL)
+ slurm_db_cleanup();
+ }
+
+ static int
++slurm_pfx_filters_apply(struct vrp const *vrp, void *arg)
+ {
+ struct roa_table *table = arg;
+
+ if (slurm_db_vrp_is_filtered(vrp))
+ roa_table_remove_roa(table, vrp);
+
+ return 0;
+ }
+
+ static int
+ slurm_pfx_assertions_add(struct slurm_prefix *prefix, void *arg)
+ {
+ struct roa_table *table = arg;
+ struct ipv4_prefix prefix4;
+ struct ipv6_prefix prefix6;
+ struct vrp vrp;
+
+ vrp = prefix->vrp;
+ if ((prefix->data_flag & SLURM_PFX_FLAG_MAX_LENGTH) == 0)
+ vrp.max_prefix_length = vrp.prefix_length;
+
+ if (vrp.addr_fam == AF_INET) {
+ prefix4.addr = vrp.prefix.v4;
+ prefix4.len = vrp.prefix_length;
+ return rtrhandler_handle_roa_v4(table, vrp.asn, &prefix4,
+ vrp.max_prefix_length);
+ }
+ if (vrp.addr_fam == AF_INET6) {
+ prefix6.addr = vrp.prefix.v6;
+ prefix6.len = vrp.prefix_length;
+ return rtrhandler_handle_roa_v6(table, vrp.asn, &prefix6,
+ vrp.max_prefix_length);
+ }
+ return -pr_crit("Unkown addr family type");
+ }
+
+ static int
+ slurm_pfx_assertions_apply(struct roa_table *base)
+ {
+ return slurm_db_foreach_assertion_prefix(slurm_pfx_assertions_add,
+ base);
+ }
+
+ int
+ slurm_apply(struct roa_table *base)
+ {
+ bool loaded;
+ int error;
+
+ loaded = false;
+ error = slurm_load(&loaded);
+ if (error)
+ goto cleanup;
+
+ if (!loaded)
+ return 0;
+
+ error = roa_table_foreach_roa(base, slurm_pfx_filters_apply, base);
+ if (error)
+ goto cleanup;
+
+ error = slurm_pfx_assertions_apply(base);
+
+ /** TODO (next iteration) Apply BGPsec filters and assertions */
+
+ cleanup:
+ slurm_cleanup();
+ return error;
+ }
BASIC_MODULES = ../src/log.c ../src/log.h
BASIC_MODULES += impersonator.c
++SLURM_SOURCES = ../src/address.c ../src/address.h
++SLURM_SOURCES += ../src/json_parser.c ../src/json_parser.h
++SLURM_SOURCES += ../src/crypto/base64.c ../src/crypto/base64.h
++SLURM_SOURCES += ../src/slurm/slurm_db.c ../src/slurm/slurm_db.h
++SLURM_SOURCES += ../src/slurm/slurm_loader.c
++SLURM_SOURCES += ../src/slurm/slurm_loader.h
++SLURM_SOURCES += ../src/slurm/slurm_parser.c
++SLURM_SOURCES += ../src/slurm/slurm_parser.h
++
check_PROGRAMS = address.test
check_PROGRAMS += clients.test
check_PROGRAMS += line_file.test
line_file_test_SOURCES += line_file_test.c
line_file_test_LDADD = ${MY_LDADD}
- pdu_handler_test_LDADD = ${MY_LDADD}
+pdu_handler_test_SOURCES = ${BASIC_MODULES}
++pdu_handler_test_SOURCES += ${SLURM_SOURCES}
+pdu_handler_test_SOURCES += ../src/common.c
+pdu_handler_test_SOURCES += ../src/rtr/pdu_handler.c
+pdu_handler_test_SOURCES += ../src/rtr/err_pdu.c
+pdu_handler_test_SOURCES += ../src/rtr/db/delta.c
+pdu_handler_test_SOURCES += ../src/rtr/db/roa_table.c
+pdu_handler_test_SOURCES += ../src/rtr/db/vrps.c
+pdu_handler_test_SOURCES += rtr/db/impersonator.c
+pdu_handler_test_SOURCES += rtr/pdu_handler_test.c
++pdu_handler_test_LDADD = ${MY_LDADD} ${JANSSON_LIBS}
+
roa_table_test_SOURCES = ${BASIC_MODULES}
roa_table_test_SOURCES += ../src/rtr/db/delta.c
roa_table_test_SOURCES += ../src/rtr/db/roa_table.c
vcard_test_SOURCES += vcard_test.c
vcard_test_LDADD = ${MY_LDADD}
- vrps_test_LDADD = ${MY_LDADD}
+vrps_test_SOURCES = ${BASIC_MODULES}
++vrps_test_SOURCES += ${SLURM_SOURCES}
+vrps_test_SOURCES += ../src/common.c
+vrps_test_SOURCES += ../src/rtr/db/delta.c
+vrps_test_SOURCES += ../src/rtr/db/roa_table.c
+vrps_test_SOURCES += ../src/rtr/db/vrps.c
+vrps_test_SOURCES += rtr/db/impersonator.c
+vrps_test_SOURCES += rtr/db/vrps_test.c
++vrps_test_LDADD = ${MY_LDADD} ${JANSSON_LIBS}
+
#rtr_pdu_test_SOURCES = ${BASIC_MODULES}
#rtr_pdu_test_SOURCES += rtr/pdu_test.c
#rtr_pdu_test_SOURCES += rtr/stream.c
static const struct string_array array = { 0 };
return &array;
}
++
++char const *
++config_get_slurm_location(void)
++{
++ return NULL;
++}
--- /dev/null
+#include "object/tal.h"
+
+#include <check.h>
+
+static int iteration = 0;
+
+static void
+add_v4(struct validation_handler *handler, uint32_t as)
+{
+ struct ipv4_prefix prefix;
+ prefix.addr.s_addr = htonl(0xC0000200);
+ prefix.len = 24;
+ ck_assert_int_eq(0, handler->handle_roa_v4(as, &prefix, 32,
+ handler->arg));
+}
+
+static void
+add_v6(struct validation_handler *handler, uint32_t as)
+{
+ struct ipv6_prefix prefix;
+ prefix.addr.s6_addr32[0] = htonl(0x20010DB8);
+ prefix.addr.s6_addr32[1] = 0;
+ prefix.addr.s6_addr32[2] = 0;
+ prefix.addr.s6_addr32[3] = 0;
+ prefix.len = 96;
+ ck_assert_int_eq(0, handler->handle_roa_v6(as, &prefix, 120,
+ handler->arg));
+}
+
+int
+perform_standalone_validation(struct validation_handler *handler)
+{
+ ck_assert_int_eq(0, handler->reset(handler->arg));
+
+ switch (iteration) {
+ case 0:
+ add_v4(handler, 0);
+ add_v6(handler, 0);
+ break;
+ case 1:
+ add_v4(handler, 0);
+ add_v6(handler, 0);
+ add_v4(handler, 1);
+ add_v6(handler, 1);
+ break;
+ case 2:
+ case 3:
+ add_v4(handler, 1);
+ add_v6(handler, 1);
+ break;
+ default:
+ ck_abort_msg("perform_standalone_validation() was called too many times (%d).",
+ iteration);
+ }
++ if (handler->merge != NULL)
++ handler->merge(handler->merge_arg, handler->arg);
+
+ iteration++;
+ return 0;
+}