From: pcarana Date: Wed, 5 Jun 2019 17:00:11 +0000 (-0500) Subject: Add server.enabled and output.roa arguments, update server.address docs X-Git-Tag: v0.0.2~11 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=fd93d7cf295f82443ae88019a48c95dfdf709a5c;p=thirdparty%2FFORT-validator.git Add server.enabled and output.roa arguments, update server.address docs Now to perform a standalone validation, the server must be disabled (server.enabled = false). The ROAs in CSV format can be: printed to console (output.roa = '-'), printed to a file (output.roa = ''), not printed (output.roa isn't configured). 'server.address' docs specify the scenario when no value is set to that argument. --- diff --git a/docs/doc/usage.md b/docs/doc/usage.md index f682bb9c..a69ea0cb 100644 --- a/docs/doc/usage.md +++ b/docs/doc/usage.md @@ -23,18 +23,20 @@ command: fort 4. [`root-except-ta`](#root-except-ta) 7. [`--shuffle-uris`](#--shuffle-uris) 8. [`--maximum-certificate-depth`](#--maximum-certificate-depth) - 9. [`--server.address`](#--serveraddress) - 10. [`--server.port`](#--serverport) - 11. [`--server.backlog`](#--serverbacklog) - 12. [`--server.validation-interval`](#--servervalidation-interval) - 13. [`--slurm`](#--slurm) - 14. [`--log.color-output`](#--logcolor-output) - 15. [`--log.file-name-format`](#--logfile-name-format) - 16. [`--configuration-file`](#--configuration-file) - 17. [`rsync.program`](#rsyncprogram) - 18. [`rsync.arguments-recursive`](#rsyncarguments-recursive) - 19. [`rsync.arguments-flat`](#rsyncarguments-flat) - 20. [`incidences`](#incidences) + 9. [`--server.enabled`](#--serverenabled) + 10. [`--server.address`](#--serveraddress) + 11. [`--server.port`](#--serverport) + 12. [`--server.backlog`](#--serverbacklog) + 13. [`--server.validation-interval`](#--servervalidation-interval) + 14. [`--slurm`](#--slurm) + 15. [`--log.color-output`](#--logcolor-output) + 16. [`--log.file-name-format`](#--logfile-name-format) + 17. [`--output.roa`](#--outputroa) + 18. [`--configuration-file`](#--configuration-file) + 19. [`rsync.program`](#rsyncprogram) + 20. [`rsync.arguments-recursive`](#rsyncarguments-recursive) + 21. [`rsync.arguments-flat`](#rsyncarguments-flat) + 22. [`incidences`](#incidences) ## Syntax @@ -51,6 +53,7 @@ command: fort [--sync-strategy=off|strict|root|root-except-ta] [--shuffle-uris] [--maximum-certificate-depth=] + [--server.enabled=true|false] [--server.address=] [--server.port=] [--server.backlog=] @@ -58,6 +61,7 @@ command: fort [--slurm=] [--log.color-output] [--log.file-name-format=global-url|local-path|file-name] + [--output.roa=] ``` If an argument is declared more than once, the last one takes precedence: @@ -234,6 +238,16 @@ Maximum allowable RPKI tree height. Meant to protect Fort from iterating infinit Fort's tree traversal is actually iterative (not recursive), so there should be no risk of stack overflow, regardless of this value. +### `--server.enabled` + +- **Type:** Boolean +- **Availability:** `argv` and JSON +- **Default:** true + +Enable or disable the RTR server. + +If set to `false`: the server is disabled, the rest of the `server.*` arguments are discarded, and Fort performs an in-place standalone RPKI validation. + ### `--server.address` - **Type:** String @@ -242,7 +256,7 @@ Fort's tree traversal is actually iterative (not recursive), so there should be Hostname or numeric host address the RTR server will be bound to. Must resolve to (or be) a bindable IP address. IPv4 and IPv6 are supported. -If this field is omitted, Fort falls back to perform an in-place standalone RPKI validation. Presently, this is only intended for debugging. +If this field is omitted, Fort will attempt to bind the server using the IP address `INADDR_ANY` (for an IPv4 address) or `IN6ADDR_ANY_INIT` (for an IPv6 address); see '`$ man getaddrinfo`'. ### `--server.port` @@ -334,6 +348,17 @@ $ {{ page.command }} --output-file-name-format file-name --local-repository rep ERR: baz.cer: Certificate validation failed: certificate has expired {% endhighlight %} +### `--output.roa` + +- **Type:** String (Path to file) +- **Availability:** `argv` and JSON + +File where the ROAs will be stored in CSV format. + +When the file is specified, its content will be removed to store the ROAs; if the file doesn't exists, it will be created. To print at console, use a hyphen `"-"`. If RTR server is enabled, then the ROAs will be printed every [`--server.validation-interval`](#--servervalidation-interval) secs. + +If a value isn't specified, then the ROAs aren't printed. + ### `--configuration-file` - **Type:** String (Path to file) diff --git a/src/Makefile.am b/src/Makefile.am index d4aac56e..e10c71dd 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -13,7 +13,6 @@ fort_SOURCES += certificate_refs.h certificate_refs.c fort_SOURCES += cert_stack.h cert_stack.c fort_SOURCES += clients.c clients.h fort_SOURCES += common.c common.h -fort_SOURCES += console_handler.h console_handler.c fort_SOURCES += config.h config.c fort_SOURCES += debug.h debug.c fort_SOURCES += extension.h extension.c @@ -23,6 +22,7 @@ fort_SOURCES += line_file.h line_file.c fort_SOURCES += log.h log.c fort_SOURCES += nid.h nid.c fort_SOURCES += notify.c notify.h +fort_SOURCES += output_printer.h output_printer.c fort_SOURCES += random.h random.c fort_SOURCES += resource.h resource.c fort_SOURCES += rpp.h rpp.c diff --git a/src/config.c b/src/config.c index eb0d5773..f9f17c47 100644 --- a/src/config.c +++ b/src/config.c @@ -48,6 +48,8 @@ struct rpki_config { char *slurm; struct { + /** Enable/disable the RTR server. */ + bool enabled; /** The bound listening address of the RTR server. */ char *address; /** The bound listening port of the RTR server. */ @@ -80,6 +82,12 @@ struct rpki_config { /** Format in which file names will be printed. */ enum filename_format filename_format; } log; + + struct { + /** File where the validated ROAs will be stored */ + char *roa; + /** TODO (next iteration) Add BGPsec output */ + } output; }; static void print_usage(FILE *, bool); @@ -146,7 +154,7 @@ static const struct option_field options[] = { .type = >_string, .offset = offsetof(struct rpki_config, tal), .doc = "Path to the TAL file or TALs directory", - .arg_doc = "", + .arg_doc = "", }, { .id = 'r', .name = "local-repository", @@ -190,16 +198,22 @@ static const struct option_field options[] = { /* Server fields */ { .id = 5000, + .name = "server.enabled", + .type = >_bool, + .offset = offsetof(struct rpki_config, server.enabled), + .doc = "Enable or disable the RTR server.", + }, { + .id = 5001, .name = "server.address", .type = >_string, .offset = offsetof(struct rpki_config, server.address), - .doc = "Address the RTR server will bind itself to. Can be a name, in which case an address will be resolved.", + .doc = "Address to which RTR server will bind itself to. Can be a name, in which case an address will be resolved.", }, { - .id = 5001, + .id = 5002, .name = "server.port", .type = >_string, .offset = offsetof(struct rpki_config, server.port), - .doc = "Port the RTR server will bind itself to. Can be a string, in which case a number will be resolved.", + .doc = "Port to which RTR server will bind itself to. Can be a string, in which case a number will be resolved.", }, { .id = 5003, .name = "server.backlog", @@ -281,6 +295,16 @@ static const struct option_field options[] = { .availability = AVAILABILITY_JSON, }, + /* Output files */ + { + .id = 6000, + .name = "output.roa", + .type = >_string, + .offset = offsetof(struct rpki_config, output.roa), + .doc = "File where ROAs will be stored in CSV format, use '-' to print at console", + .arg_doc = "", + }, + { 0 }, }; @@ -429,6 +453,7 @@ set_default_values(void) * duplicates. */ + rpki_config.server.enabled = true; rpki_config.server.address = NULL; rpki_config.server.port = strdup("323"); if (rpki_config.server.port == NULL) @@ -469,6 +494,8 @@ set_default_values(void) rpki_config.log.color = false; rpki_config.log.filename_format = FNF_GLOBAL; + rpki_config.output.roa = NULL; + return 0; revert_recursive_array: @@ -601,6 +628,12 @@ get_option_metadatas(void) return options; } +bool +config_get_server_enabled(void) +{ + return rpki_config.server.enabled; +} + char const * config_get_server_address(void) { @@ -701,6 +734,12 @@ config_get_rsync_args(bool is_ta) pr_crit("Invalid sync strategy: '%u'", rpki_config.sync_strategy); } +char const * +config_get_output_roa(void) +{ + return rpki_config.output.roa; +} + void free_rpki_config(void) { diff --git a/src/config.h b/src/config.h index 866228ec..f9d41e3c 100644 --- a/src/config.h +++ b/src/config.h @@ -14,6 +14,7 @@ int handle_flags_config(int , char **); void free_rpki_config(void); /* Getters */ +bool config_get_server_enabled(void); char const *config_get_server_address(void); char const *config_get_server_port(void); int config_get_server_queue(void); @@ -29,6 +30,7 @@ bool config_get_color_output(void); enum filename_format config_get_filename_format(void); char *config_get_rsync_program(void); struct string_array const *config_get_rsync_args(bool); +char const *config_get_output_roa(void); /* Needed public by the JSON module */ void *get_rpki_config_field(struct option_field const *); diff --git a/src/console_handler.c b/src/console_handler.c deleted file mode 100644 index fca6f5c0..00000000 --- a/src/console_handler.c +++ /dev/null @@ -1,35 +0,0 @@ -#include "console_handler.h" - -#include "thread_var.h" -#include "validation_handler.h" -#include "object/tal.h" - -static int -print_v4_roa(uint32_t as, struct ipv4_prefix const *prefix, uint8_t max_length, - void *arg) -{ - printf("AS%u,%s/%u,%u\n", as, v4addr2str(&prefix->addr), prefix->len, - max_length); - return 0; -} - -static int -print_v6_roa(uint32_t as, struct ipv6_prefix const *prefix, uint8_t max_length, - void *arg) -{ - printf("AS%u,%s/%u,%u\n", as, v6addr2str(&prefix->addr), prefix->len, - max_length); - return 0; -} - -int -validate_into_console(void) -{ - struct validation_handler handler; - - handler.handle_roa_v4 = print_v4_roa; - handler.handle_roa_v6 = print_v6_roa; - handler.arg = NULL; - - return perform_standalone_validation(&handler); -} diff --git a/src/console_handler.h b/src/console_handler.h deleted file mode 100644 index b712f246..00000000 --- a/src/console_handler.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef SRC_CONSOLE_HANDLER_H_ -#define SRC_CONSOLE_HANDLER_H_ - -int validate_into_console(void); - -#endif /* SRC_CONSOLE_HANDLER_H_ */ diff --git a/src/file.c b/src/file.c index bb85e878..d1e26b6f 100644 --- a/src/file.c +++ b/src/file.c @@ -4,13 +4,14 @@ #include #include "log.h" -int -file_open(char const *file_name, FILE **result, struct stat *stat) +static int +file_get(char const *file_name, FILE **result, struct stat *stat, + char const *mode) { FILE *file; int error; - file = fopen(file_name, "rb"); + file = fopen(file_name, mode); if (file == NULL) return pr_errno(errno, "Could not open file '%s'", file_name); @@ -31,6 +32,18 @@ fail: return error; } +int +file_open(char const *file_name, FILE **result, struct stat *stat) +{ + return file_get(file_name, result, stat, "rb"); +} + +int +file_write(char const *file_name, FILE **result, struct stat *stat) +{ + return file_get(file_name, result, stat, "wb"); +} + void file_close(FILE *file) { diff --git a/src/file.h b/src/file.h index c494a65b..8440dfe4 100644 --- a/src/file.h +++ b/src/file.h @@ -16,6 +16,7 @@ struct file_contents { }; int file_open(char const *, FILE **, struct stat *); +int file_write(char const *, FILE **, struct stat *); void file_close(FILE *); int file_load(char const *, struct file_contents *); diff --git a/src/main.c b/src/main.c index 4c129c4b..373da9ab 100644 --- a/src/main.c +++ b/src/main.c @@ -1,6 +1,5 @@ #include "clients.h" #include "config.h" -#include "console_handler.h" #include "debug.h" #include "extension.h" #include "nid.h" @@ -53,9 +52,7 @@ main(int argc, char **argv) if (error) goto revert_nid; - error = (config_get_server_address() != NULL) - ? start_rtr_server() - : validate_into_console(); + error = start_rtr_server(); revert_nid: nid_destroy(); diff --git a/src/output_printer.c b/src/output_printer.c new file mode 100644 index 00000000..e5761b52 --- /dev/null +++ b/src/output_printer.c @@ -0,0 +1,99 @@ +#include "output_printer.h" + +#include "config.h" +#include "file.h" +#include "log.h" +#include "rtr/db/vrp.h" +#include + +char addr_buf[INET6_ADDRSTRLEN]; + +static char const * +strv4addr(struct in_addr const *addr) +{ + return inet_ntop(AF_INET, addr, addr_buf, INET6_ADDRSTRLEN); +} + +static char const * +strv6addr(struct in6_addr const *addr) +{ + return inet_ntop(AF_INET6, addr, addr_buf, INET6_ADDRSTRLEN); +} + +static int +load_output_file(FILE **result, bool *fopen) +{ + FILE *tmp; + struct stat stat; + char const *output = config_get_output_roa(); + int error; + + if (output == NULL) { + *result = NULL; + return 0; + } + + *fopen = false; + if (strcmp(output, "-") == 0) { + *result = stdout; + return 0; + } + + error = file_write(output, &tmp, &stat); + if (error) + return error; + + *fopen = true; + *result = tmp; + return 0; +} + +static int +print_roa(struct vrp const *vrp, void *arg) +{ + FILE *out = arg; + + switch(vrp->addr_fam) { + case AF_INET: + fprintf(out, "AS%u,%s/%u,%u\n", vrp->asn, + strv4addr(&vrp->prefix.v4), vrp->prefix_length, + vrp->max_prefix_length); + break; + case AF_INET6: + fprintf(out, "AS%u,%s/%u,%u\n", vrp->asn, + strv6addr(&vrp->prefix.v6), vrp->prefix_length, + vrp->max_prefix_length); + break; + default: + pr_crit("Unknown family type"); + } + + return 0; +} + +void +output_print_roas(struct roa_table *roas) +{ + FILE *out; + bool fopen; + int error; + + error = load_output_file(&out, &fopen); + if (error) { + pr_err("Error getting file '%s'", config_get_output_roa()); + return; + } + + /* No output configured */ + if (out == NULL) + return; + + fprintf(out, "ASN,Prefix,Max prefix length\n"); + error = roa_table_foreach_roa(roas, print_roa, out); + if (fopen) + file_close(out); + if (error) { + pr_err("Error printing ROAs"); + return; + } +} diff --git a/src/output_printer.h b/src/output_printer.h new file mode 100644 index 00000000..47fcdb2d --- /dev/null +++ b/src/output_printer.h @@ -0,0 +1,8 @@ +#ifndef SRC_OUTPUT_PRINTER_H_ +#define SRC_OUTPUT_PRINTER_H_ + +#include "rtr/db/roa_table.h" + +void output_print_roas(struct roa_table *); + +#endif /* SRC_OUTPUT_PRINTER_H_ */ diff --git a/src/rtr/db/vrps.c b/src/rtr/db/vrps.c index 579c6ae5..897e07f4 100644 --- a/src/rtr/db/vrps.c +++ b/src/rtr/db/vrps.c @@ -6,6 +6,7 @@ #include #include "clients.h" #include "common.h" +#include "output_printer.h" #include "validation_handler.h" #include "data_structure/array_list.h" #include "object/tal.h" @@ -127,6 +128,8 @@ __perform_standalone_validation(struct roa_table **result) validation_handler.arg = roas; error = perform_standalone_validation(&validation_handler); + /* Print after validation to avoid duplicated info */ + output_print_roas(roas); if (error) { roa_table_destroy(roas); return error; diff --git a/src/rtr/rtr.c b/src/rtr/rtr.c index e0d86b95..ffa74293 100644 --- a/src/rtr/rtr.c +++ b/src/rtr/rtr.c @@ -17,6 +17,7 @@ #include "updates_daemon.h" #include "rtr/err_pdu.h" #include "rtr/pdu.h" +#include "rtr/db/vrps.h" struct sigaction act; @@ -351,41 +352,50 @@ join_thread(pthread_t tid, void *arg) /* * Starts the server, using the current thread to listen for RTR client - * requests. + * requests. If configuration parameter 'server.enabled' is false, then the + * server runs "one time" (a.k.a. run the validation just once), it doesn't + * waits for clients requests. * - * This function blocks. + * When listening for client requests, this function blocks. */ int rtr_listen(void) { + bool changed; int server_fd; /* "file descriptor" */ int error; - error = create_server_socket(&server_fd); + error = init_signal_handler(); if (error) return error; - /* Server ready, start everything else */ error = clients_db_init(); if (error) - goto revert_server_socket; + return error; - error = updates_daemon_start(); + if (!config_get_server_enabled()) { + error = vrps_update(&changed); + if (error) + pr_err("Error %d while trying to update the ROA database.", + error); + goto revert_clients_db; /* Error 0 it's ok */ + } + + error = create_server_socket(&server_fd); if (error) goto revert_clients_db; - error = init_signal_handler(); + error = updates_daemon_start(); if (error) - goto revert_updates_daemon; + goto revert_server_socket; error = handle_client_connections(server_fd); end_clients(); -revert_updates_daemon: updates_daemon_destroy(); -revert_clients_db: - clients_db_destroy(join_thread, NULL); revert_server_socket: close(server_fd); +revert_clients_db: + clients_db_destroy(join_thread, NULL); return error; } diff --git a/test/Makefile.am b/test/Makefile.am index 24bde676..83e45d6e 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -62,6 +62,8 @@ line_file_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/file.c +pdu_handler_test_SOURCES += ../src/output_printer.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 @@ -101,6 +103,8 @@ vcard_test_LDADD = ${MY_LDADD} vrps_test_SOURCES = ${BASIC_MODULES} vrps_test_SOURCES += ${SLURM_SOURCES} vrps_test_SOURCES += ../src/common.c +vrps_test_SOURCES += ../src/file.c +vrps_test_SOURCES += ../src/output_printer.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 diff --git a/test/impersonator.c b/test/impersonator.c index aaaecdfc..bbe6a5e6 100644 --- a/test/impersonator.c +++ b/test/impersonator.c @@ -77,6 +77,18 @@ config_get_slurm(void) return NULL; } +bool +config_get_server_enabled(void) +{ + return false; +} + +char const * +config_get_output_roa(void) +{ + return "-"; +} + enum incidence_action incidence_get_action(enum incidence_id id) {