if ((opt->availability == 0) || \
(opt->availability & type))
+struct config_out_file {
+ FILE *fd;
+ char *file_name;
+};
+
/**
* To add a member to this structure,
*
bool color;
/** Format in which file names will be printed. */
enum filename_format filename_format;
+ /** Output stream where the valid ROAs will be dumped. */
+ struct config_out_file roa_output;
} output;
};
static void print_usage(FILE *, bool);
#define DECLARE_PRINT_FN(name) \
- void name( \
+ static void name( \
struct group_fields const *, \
struct option_field const *, \
void * \
DECLARE_PRINT_FN(print_string_array);
DECLARE_PRINT_FN(print_sync_strategy);
DECLARE_PRINT_FN(print_filename_format);
+DECLARE_PRINT_FN(print_out_file);
#define DECLARE_PARSE_ARGV_FN(name) \
static int name( \
DECLARE_PARSE_ARGV_FN(parse_argv_string);
DECLARE_PARSE_ARGV_FN(parse_argv_sync_strategy);
DECLARE_PARSE_ARGV_FN(parse_argv_filename_format);
+DECLARE_PARSE_ARGV_FN(parse_argv_out_file);
#define DECLARE_PARSE_TOML_FN(name) \
static int name( \
DECLARE_PARSE_TOML_FN(parse_toml_sync_strategy);
DECLARE_PARSE_TOML_FN(parse_toml_string_array);
DECLARE_PARSE_TOML_FN(parse_toml_filename_format);
+DECLARE_PARSE_TOML_FN(parse_toml_out_file);
#define DECLARE_HANDLE_FN(name) \
static int name( \
#define DECLARE_FREE_FN(name) static void name(void *)
DECLARE_FREE_FN(free_string);
DECLARE_FREE_FN(free_string_array);
+DECLARE_FREE_FN(free_out_file);
static char const *program_name;
static struct rpki_config rpki_config;
.arg_doc = FNF_VALUE_GLOBAL "|" FNF_VALUE_LOCAL "|" FNF_VALUE_NAME,
};
+static const struct global_type gt_out_file = {
+ .has_arg = required_argument,
+ .size = sizeof(struct config_out_file),
+ .print = print_out_file,
+ .parse.argv = parse_argv_out_file,
+ .parse.toml = parse_toml_out_file,
+ .free = free_out_file,
+ .arg_doc = "<file>",
+};
+
/**
* An option that takes no arguments, is not correlated to any rpki_config
* fields, and is entirely managed by its handler function.
.name = "color-output",
.type = >_bool,
.offset = offsetof(struct rpki_config, output.color),
- .doc = "Print ANSI color codes?",
+ .doc = "Print ANSI color codes.",
}, {
.id = 4000,
.name = "output-file-name-format",
.type = >_filename_format,
.offset = offsetof(struct rpki_config, output.filename_format),
.doc = "File name variant to print during debug/error messages",
+ }, {
+ .id = 'o',
+ .name = "roa-output-file",
+ .type = >_out_file,
+ .offset = offsetof(struct rpki_config, output.roa_output),
+ .doc = "File where the valid ROAs will be dumped.",
},
{ 0 },
};
return ((unsigned char *) &rpki_config) + field->offset;
}
-void
+static void
print_bool(struct group_fields const *group, struct option_field const *field,
void *_value)
{
(*value) ? "true" : "false");
}
-void
+static void
print_u_int(struct group_fields const *group, struct option_field const *field,
void *value)
{
*((unsigned int *) value));
}
-void
+static void
print_string(struct group_fields const *group, struct option_field const *field,
void *value)
{
pr_info("%s.%s: %s", group->name, field->name, *((char **) value));
}
-void
+static void
print_string_array(struct group_fields const *group,
struct option_field const *field, void *_value)
{
pr_indent_rm();
}
-void
+static void
print_sync_strategy(struct group_fields const *group,
struct option_field const *field, void *value)
{
pr_info("%s.%s: %s", group->name, field->name, str);
}
-void
+static void
print_filename_format(struct group_fields const *group,
struct option_field const *field, void *value)
{
pr_info("%s.%s: %s", group->name, field->name, str);
}
+static void
+print_out_file(struct group_fields const *group,
+ struct option_field const *field, void *value)
+{
+ struct config_out_file *file = value;
+ pr_info("%s.%s: %s", group->name, field->name, file->file_name);
+}
+
static int
parse_argv_bool(struct option_field const *field, char const *str, void *result)
{
return 0;
}
+static int
+parse_argv_out_file(struct option_field const *field, char const *file_name,
+ void *_result)
+{
+ struct config_out_file *file = _result;
+
+ field->type->free(file);
+
+ file->file_name = strdup(file_name);
+ if (file->file_name == NULL)
+ return pr_enomem();
+
+ file->fd = fopen(file_name, "w");
+ if (file->fd == NULL) {
+ free(file->file_name);
+ file->file_name = NULL;
+ return pr_errno(errno, "Could not open file '%s'", file_name);
+ }
+
+ return 0;
+}
+
static int
parse_toml_bool(struct option_field const *opt, struct toml_table_t *toml,
void *_result)
int error;
char *string;
+ string = NULL;
error = parse_toml_string(opt, toml, &string);
if (error)
return error;
int error;
char *string;
+ string = NULL;
error = parse_toml_string(opt, toml, &string);
if (error)
return error;
return error;
}
+static int
+parse_toml_out_file(struct option_field const *opt, struct toml_table_t *toml,
+ void *_result)
+{
+ char *file_name;
+ int error;
+
+ file_name = NULL;
+ error = parse_toml_string(opt, toml, &file_name);
+ if (error)
+ return error;
+
+ error = parse_argv_out_file(opt, file_name, _result);
+
+ free(file_name);
+ return error;
+}
+
static int
handle_help(struct option_field const *field, char *arg)
{
for (i = 0; i < array->length; i++)
free(array->array[i]);
+ free(array->array);
array->array = NULL;
array->length = 0;
}
+static void
+free_out_file(void *_file)
+{
+ struct config_out_file *file = _file;
+
+ if (file->fd != NULL) {
+ fclose(file->fd);
+ file->fd = NULL;
+ }
+
+ free(file->file_name);
+ file->file_name = NULL;
+}
+
static bool
is_alphanumeric(int chara)
{
rpki_config.output.color = false;
rpki_config.output.filename_format = FNF_GLOBAL;
+ rpki_config.output.roa_output.fd = NULL;
+ rpki_config.output.roa_output.file_name = NULL;
return 0;
return rpki_config.output.filename_format;
}
+FILE *
+config_get_roa_output(void)
+{
+ return (rpki_config.output.roa_output.fd != NULL)
+ ? rpki_config.output.roa_output.fd
+ : stdout;
+}
+
char *
config_get_rsync_program(void)
{
static int
validate_dates(GeneralizedTime_t *this, GeneralizedTime_t *next)
{
- const struct asn_TYPE_descriptor_s *def = &asn_DEF_GeneralizedTime;
- return (GeneralizedTime_compare(def, this, next) < 0) ? 0 : -EINVAL;
+#define TM_FMT "%02d/%02d/%02d %02d:%02d:%02d"
+#define TM_ARGS(tm) \
+ tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, \
+ tm.tm_hour, tm.tm_min, tm.tm_sec
+
+ time_t thisUpdate;
+ time_t nextUpdate;
+ time_t now;
+ struct tm thisUpdate_tm;
+ struct tm nextUpdate_tm;
+
+ /*
+ * BTW: We only need the tm variables for error messages, which are
+ * rarely needed.
+ * So maybe we could get a small performance boost by postponing the
+ * calls to localtime_r().
+ */
+ thisUpdate = asn_GT2time(this, &thisUpdate_tm, false);
+ nextUpdate = asn_GT2time(next, &nextUpdate_tm, false);
+
+ if (difftime(thisUpdate, nextUpdate) > 0) {
+ return pr_err(
+ "Manifest's thisUpdate (" TM_FMT ") > nextUpdate ("
+ TM_FMT ").",
+ TM_ARGS(thisUpdate_tm),
+ TM_ARGS(nextUpdate_tm));
+ }
+
+ now = time(NULL);
+ if (now == ((time_t) -1))
+ return pr_errno(errno, "Error getting the current time");
+
+ if (difftime(now, thisUpdate) < 0) {
+ return pr_err(
+ "Manifest is not valid yet. (thisUpdate: " TM_FMT ")",
+ TM_ARGS(thisUpdate_tm));
+ }
+ if (difftime(now, nextUpdate) > 0) {
+ return pr_err(
+ "Manifest is expired. (nextUpdate: " TM_FMT ")",
+ TM_ARGS(nextUpdate_tm));
+ }
+
+ return 0;
+
+#undef TM_FMT
+#undef TM_ARGS
}
static int
/* rfc6486#section-4.2.1 */
/*
- * TODO (field)
+ * BTW:
*
- * If a "one-time-use" EE certificate is employed to verify a manifest,
+ * "If a "one-time-use" EE certificate is employed to verify a manifest,
* the EE certificate MUST have a validity period that coincides with
* the interval from thisUpdate to nextUpdate, to prevent needless
- * growth of the CA's CRL.
+ * growth of the CA's CRL."
*
- * If a "sequential-use" EE certificate is employed to verify a
+ * "If a "sequential-use" EE certificate is employed to verify a
* manifest, the EE certificate's validity period needs to be no shorter
- * than the nextUpdate time of the current manifest.
+ * than the nextUpdate time of the current manifest."
+ *
+ * It would appear that there's no way to tell whether an EE certificate
+ * is "one-time-use" or "sequential-use," so we have no way to validate
+ * this.
*/
/* rfc6486#section-4.4.2 */
if (manifest->manifestNumber.size > 20)
return pr_err("Manifest number is larger than 20 octets");
- /*
- * TODO (field)
- *
- * "CRL issuers conforming to this profile MUST encode thisUpdate as
- * UTCTime for dates through the year 2049. CRL issuers conforming to
- * this profile MUST encode thisUpdate as GeneralizedTime for dates in
- * the year 2050 or later. Conforming applications MUST be able to
- * process dates that are encoded in either UTCTime or GeneralizedTime."
- *
- * WTF man. thisUpdate is defined in the spec as GeneralizedTime;
- * not as CMSTime. This requirement makes no sense whatsoever.
- *
- * Check the errata?
- */
- /* manifest->thisUpdate */
-
- /*
- * TODO (field) again, same bullshit:
- *
- * "CRL issuers conforming to this profile MUST encode nextUpdate as
- * UTCTime for dates through the year 2049. CRL issuers conforming to
- * this profile MUST encode nextUpdate as GeneralizedTime for dates in
- * the year 2050 or later. Conforming applications MUST be able to
- * process dates that are encoded in either UTCTime or GeneralizedTime."
- */
- /* manifest->nextUpdate */
-
/* rfc6486#section-4.4.3 */
error = validate_dates(&manifest->thisUpdate, &manifest->nextUpdate);
if (error)
#include <arpa/inet.h>
#include <libcmscodec/RouteOriginAttestation.h>
+#include "config.h"
#include "log.h"
#include "thread_var.h"
#include "asn1/decode.h"
return pr_err("Prefix length (%u) > maxLength (%lu)",
prefix.len, max_length);
}
+
+ } else {
+ max_length = prefix.len;
}
str2 = inet_ntop(AF_INET, &prefix.addr, str, sizeof(str));
prefix.len);
}
- printf("AS%lu,%s/%u", asn, str2, prefix.len);
- if (roa_addr->maxLength != NULL)
- printf(",%lu", max_length);
- else
- printf(",%u", prefix.len);
- printf("\n");
-
+ fprintf(config_get_roa_output(), "AS%lu,%s/%u,%lu\n", asn, str2,
+ prefix.len, max_length);
return 0;
}
return pr_err("Prefix length (%u) > maxLength (%lu)",
prefix.len, max_length);
}
+
+ } else {
+ max_length = prefix.len;
}
str2 = inet_ntop(AF_INET6, &prefix.addr, str, sizeof(str));
prefix.len);
}
- printf("AS%lu,%s/%u", asn, str2, prefix.len);
- if (roa_addr->maxLength != NULL)
- printf(",%lu", max_length);
- else
- printf(",%u", prefix.len);
- printf("\n");
-
+ fprintf(config_get_roa_output(), "AS%lu,%s/%u,%lu\n", asn, str2,
+ prefix.len, max_length);
return 0;
}