rtr_server_SOURCES = main.c
rtr_server_SOURCES += address.c address.h
+rtr_server_SOURCES += array_list.h
rtr_server_SOURCES += common.c common.h
rtr_server_SOURCES += configuration.c configuration.h
rtr_server_SOURCES += csv.c csv.h
rtr_server_SOURCES += line_file.c line_file.h
+rtr_server_SOURCES += vrps.c vrps.h
rtr_server_SOURCES += rtr/pdu_handler.c rtr/pdu_handler.h
rtr_server_SOURCES += rtr/pdu.c rtr/pdu.h
--- /dev/null
+#ifndef SRC_ARRAY_LIST_H_
+#define SRC_ARRAY_LIST_H_
+
+#include <err.h>
+#include <errno.h>
+
+#define ARRAY_LIST(name, elem_type) \
+ struct name { \
+ /** Unidimensional array. */ \
+ elem_type *array; \
+ /** Number of elements in @array. */ \
+ unsigned int len; \
+ /** Actual allocated slots in @array. */ \
+ unsigned int capacity; \
+ }; \
+ \
+ static int \
+ name##_init(struct name *list) \
+ { \
+ list->capacity = 8; \
+ list->len = 0; \
+ list->array = malloc(list->capacity \
+ * sizeof(elem_type)); \
+ return (list->array != NULL) ? 0 : -ENOMEM; \
+ } \
+ \
+ static void \
+ name##_cleanup(struct name *list, void (*cb)(elem_type *)) \
+ { \
+ unsigned int i; \
+ for (i = 0; i < list->len; i++) \
+ cb(&list->array[i]); \
+ free(list->array); \
+ } \
+ \
+ /* Will store a shallow copy, not @elem */ \
+ static int \
+ name##_add(struct name *list, elem_type *elem) \
+ { \
+ elem_type *tmp; \
+ \
+ list->len++; \
+ while (list->len >= list->capacity) { \
+ list->capacity *= 2; \
+ \
+ tmp = realloc(list->array, list->capacity \
+ * sizeof(elem_type)); \
+ if (tmp == NULL) { \
+ err(-ENOMEM, "Out of memory"); \
+ return -ENOMEM; \
+ } \
+ list->array = tmp; \
+ } \
+ \
+ list->array[list->len - 1] = *elem; \
+ return 0; \
+ }
+
+#define ARRAYLIST_FOREACH(list, cursor) for ( \
+ cursor = (list)->array; \
+ (cursor - ((typeof(cursor)) ((list)->array))) < (list)->len; \
+ cursor++ \
+)
+
+#endif /* SRC_ARRAY_LIST_H_ */
#define OPTNAME_LISTEN "listen"
#define OPTNAME_LISTEN_ADDRESS "address"
#define OPTNAME_LISTEN_PORT "port"
-#define OPTNAME_VRPS "vrps"
+#define OPTNAME_VRPS_LOCATION "vrpsLocation"
#define DEFAULT_ADDR NULL
#define DEFAULT_PORT "323"
/** Stored aside only for printing purposes. */
char *port;
/** VRPs (Validated ROA Payload) location */
- char *vrps;
+ char *vrps_location;
} config;
static int handle_json(json_t *);
static int json_get_string(json_t *, char const *, char *, char const **);
static int init_addrinfo(char const *, char const *);
-static int init_vrps_db(char const *);
int
config_init(char const *json_file_path)
freeaddrinfo(config.address);
if (config.port != NULL)
free(config.port);
- if (config.vrps != NULL)
- free(config.vrps);
+ if (config.vrps_location != NULL)
+ free(config.vrps_location);
}
static int
port = DEFAULT_PORT;
}
- error = json_get_string(root, OPTNAME_VRPS,
+ error = json_get_string(root, OPTNAME_VRPS_LOCATION,
DEFAULT_VRPS, &vrps);
if (error)
return error;
-
- error = init_vrps_db(vrps);
- if (error)
- return error;
+ config.vrps_location = str_clone(vrps);
return init_addrinfo(address, port);
}
return 0;
}
-static int
-init_vrps_db(char const *vrps_location)
-{
- /* FIXME Complete me! */
- int error;
-
- if (vrps_location == NULL || strlen(vrps_location) < 1) {
- warnx("VRPs location must be set");
- return -EINVAL;
- }
-
- error = parse_file(vrps_location);
- if (error)
- return error; /* Error msg already printed. */
-
- return 0;
-}
-
static int
init_addrinfo(char const *hostname, char const *service)
{
}
char const *
-config_get_vrps(void)
+config_get_vrps_location(void)
{
- return config.vrps;
+ return config.vrps_location;
}
struct addrinfo const *config_get_server_addrinfo(void);
char const *config_get_server_port(void);
+char const *config_get_vrps_location(void);
#endif /* _SRC_CONFIGURATION_H_ */
#include <err.h>
#include <errno.h>
#include <stdbool.h>
+#include <stdint.h>
#include <stdlib.h>
#include <string.h>
+#include "configuration.h"
#include "address.h"
#include "line_file.h"
-
-struct csv_data {
- char *asn;
- char *prefix;
- int max_length;
- char *trust_anchor;
-};
+#include "vrps.h"
/* @ext must include the period. */
static bool
}
static int
-parse_asn(char *text)
+parse_asn(char *text, unsigned int *value)
{
- if (text == NULL)
+ unsigned long asn;
+ char *start;
+
+ if (text == NULL) {
+ err(-EINVAL, "Null string received, can't decode ASN");
+ return -EINVAL;
+ }
+
+ /* The text 'AS' may precede the number */
+ start = strchr(text, 'S');
+ start = start != NULL ? start + 1 : text;
+
+ errno = 0;
+ asn = strtoul(start, NULL, 10);
+ if (errno) {
+ err(errno, "Invalid ASN '%s': %s", text, strerror(errno));
return -EINVAL;
+ }
+ /* An underflow or overflow will be considered here */
+ if (asn < 0 || UINT32_MAX < asn) {
+ err(-EINVAL, "Prefix length (%lu) is out of bounds (0-%u).",
+ asn, UINT32_MAX);
+ return -EINVAL;
+ }
+ *value = (unsigned int) asn;
+
return 0;
}
}
static int
-add_vrp(char *line)
+add_vrp(char *line, struct delta *delta)
{
struct ipv4_prefix prefixv4;
struct ipv6_prefix prefixv6;
- unsigned int prefix_length, max_prefix_length;
+ struct vrp *vrp;
+ unsigned int asn, prefix_length, max_prefix_length;
int error;
bool isv4;
char *token, *line_copy;
/* First column: ASN in format "AS###" */
token = strtok(line_copy, ",");
- error = parse_asn(token);
+ error = parse_asn(token, &asn);
if (error)
goto error;
/* Second column (second part): Prefix length in numeric format */
token = strtok(NULL, ",");
- error = parse_prefix_length(token, &prefix_length, isv4 ? 32 : 128);
+ error = parse_prefix_length(token, isv4 ? &prefixv4.len : &prefixv6.len,
+ isv4 ? 32 : 128);
if (error)
goto error;
/* Now validate the prefix */
if (isv4) {
- prefixv4.len = prefix_length;
+ prefix_length = prefixv4.len;
error = prefix4_validate(&prefixv4);
} else {
- prefixv6.len = prefix_length;
+ prefix_length = prefixv6.len;
error = prefix6_validate(&prefixv6);
}
if (error)
if (prefix_length > max_prefix_length) {
error = -EINVAL;
- err(error, "Prefix length is greater than max prefix length [%u > %u]",
- prefix_length, max_prefix_length);
+ err(error, "Prefix length is greater than max prefix length at line '%s'",
+ line);
+ goto error;
}
- /* TODO Now store the values in memory */
+ if (isv4)
+ vrp = create_vrp4(asn, prefixv4.addr, prefixv4.len, max_prefix_length);
+ else
+ vrp = create_vrp6(asn, prefixv6.addr, prefixv6.len, max_prefix_length);
+
+ if (vrp == NULL) {
+ error = -ENOMEM;
+ err(error, "Couldn't allocate VRP of line '%s'", line);
+ goto error;
+ }
+
+ error = delta_add_vrp(delta, vrp);
+ if (error) {
+ vrp_destroy(vrp);
+ goto error;
+ }
+
+ return 0;
+
error:
return error;
}
static int
-read_vrps(struct line_file *lfile)
+load_vrps(struct line_file *lfile)
{
+ struct delta *delta;
char *line;
int current_line;
int error;
}
if (line == NULL) {
error = -EINVAL;
- err(error, "Empty file, stop processing.");
+ err(error, "Empty CSV file, stop processing.");
return error;
}
+ /* Start the initial delta */
+ delta = create_delta();
do {
++current_line;
error = lfile_read(lfile, &line);
if (error) {
- err(error, "Error at line %d, stop processing file.", current_line);
- if (line != NULL)
- free(line);
- return error;
+ err(error, "Error reading line %d, stop processing file.", current_line);
+ delta_destroy(delta);
+ goto end;
}
if (line == NULL) {
- free(line);
- return 0;
+ error = 0;
+ goto persist;
}
if (strcmp(line, "") == 0) {
warn("There's nothing at line %d, ignoring.", current_line);
continue;
}
- error = add_vrp(line);
+ error = add_vrp(line, delta);
if (error) {
- free(line);
- return error;
+ delta_destroy(delta);
+ goto end;
}
} while (true);
+persist:
+ error = deltas_db_add_delta(delta);
+ if (error)
+ err(error, "VRPs Delta couldn't be persisted");
+end:
+ if (line != NULL)
+ free(line);
+ return error;
}
int
-parse_file(char const *location)
+csv_parse_vrps_file()
{
struct line_file *lfile;
+ char const *location;
int error;
+ location = config_get_vrps_location();
if (!location_has_extension(location, ".csv")) {
warn("%s isn't a CSV file", location);
error = -EINVAL;
if (error)
goto end1; /* Error msg already printed. */
- error = read_vrps(lfile);
+ error = load_vrps(lfile);
if (error)
goto end2;
#ifndef SRC_CSV_H_
#define SRC_CSV_H_
-int parse_file(char const *);
+int csv_parse_vrps_file();
#endif /* SRC_CSV_H_ */
#include "rtr/rtr.h"
#include "configuration.h"
+#include "csv.h"
+#include "vrps.h"
/*
* This program is an RTR server.
if (err)
return err;
+ err = deltas_db_init();
+ if (err)
+ goto end1;
+
+ err = csv_parse_vrps_file();
+ if (err)
+ goto end2;
+
err = rtr_listen();
+end2:
+ deltas_db_destroy();
+end1:
config_cleanup();
return err;
}
--- /dev/null
+#include "vrps.h"
+
+#include <netinet/in.h>
+#include <stdlib.h>
+#include "array_list.h"
+
+struct vrp {
+ 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;
+};
+
+ARRAY_LIST(delta, struct vrp)
+ARRAY_LIST(deltasdb, struct delta)
+
+struct deltasdb db;
+
+int
+deltas_db_init(void)
+{
+ int error;
+
+ error = deltasdb_init(&db);
+ if (error) {
+ err(error, "Deltas DB couldn't be allocated");
+ return error;
+ }
+
+ return 0;
+}
+
+struct delta *
+create_delta(void)
+{
+ struct delta *result;
+
+ result = malloc(sizeof(struct delta));
+ if (result == NULL)
+ goto fail1;
+
+ if (delta_init(result) != 0)
+ goto fail2;
+
+ return result;
+fail2:
+ free(result);
+fail1:
+ return NULL;
+}
+
+static struct vrp *
+create_vrp (u_int32_t asn, u_int8_t prefix_length, u_int8_t max_prefix_length) {
+ struct vrp *result;
+
+ result = malloc(sizeof(struct vrp));
+ if (result == NULL)
+ return NULL;
+
+ result->asn = asn;
+ result->prefix_length = prefix_length;
+ result->max_prefix_length = max_prefix_length;
+
+ return result;
+}
+
+struct vrp *
+create_vrp4(u_int32_t asn, struct in_addr ipv4_prefix, u_int8_t prefix_length,
+ u_int8_t max_prefix_length)
+{
+ struct vrp *result;
+
+ result = create_vrp(asn, prefix_length, max_prefix_length);
+ if (result == NULL)
+ return NULL;
+
+ result->ipv4_prefix = ipv4_prefix;
+
+ return result;
+}
+
+struct vrp *
+create_vrp6(u_int32_t asn, struct in6_addr ipv6_prefix, u_int8_t prefix_length,
+ u_int8_t max_prefix_length)
+{
+ struct vrp *result;
+
+ result = create_vrp(asn, prefix_length, max_prefix_length);
+ if (result == NULL)
+ return NULL;
+
+ result->ipv6_prefix = ipv6_prefix;
+
+ return result;
+}
+
+int
+deltas_db_add_delta(struct delta *delta)
+{
+ return deltasdb_add(&db, delta);
+}
+
+int
+delta_add_vrp(struct delta *delta, struct vrp *vrp)
+{
+ return delta_add(delta, vrp);
+}
+
+void
+vrp_destroy(struct vrp *vrp)
+{
+ free(vrp);
+}
+
+void
+delta_destroy(struct delta *delta)
+{
+ delta_cleanup(delta, vrp_destroy);
+ free(delta);
+}
+
+void
+deltas_db_destroy()
+{
+ deltasdb_cleanup(&db, delta_destroy);
+}
--- /dev/null
+#ifndef SRC_VRPS_H_
+#define SRC_VRPS_H_
+
+#include <netinet/ip.h>
+
+struct vrp;
+struct delta;
+
+int deltas_db_init(void);
+
+struct delta *create_delta(void);
+struct vrp *create_vrp4(u_int32_t, struct in_addr, u_int8_t, u_int8_t);
+struct vrp *create_vrp6(u_int32_t, struct in6_addr, u_int8_t, u_int8_t);
+
+int delta_add_vrp(struct delta *, struct vrp *);
+int deltas_db_add_delta(struct delta *);
+
+void vrp_destroy(struct vrp *);
+void delta_destroy(struct delta *);
+void deltas_db_destroy();
+
+#endif /* SRC_VRPS_H_ */