On Tue, May 30, 2023 at 03:12:46PM +0200, Claudio Jeker wrote: > On Tue, May 30, 2023 at 02:38:23PM +0200, Claudio Jeker wrote: > > On Wed, May 24, 2023 at 04:18:30PM +0000, Job Snijders wrote: > > > Dear all, > > > > > > Claudio made some suggestions to pass the desired modification times > > > around in a different way, below is an updated patch proposal. > > > I also added some instrumentation to also adjust GBRs and TAKs. > > > > > > RIPE & APNIC informally indicated some interest in this hack. > > > > > > > This looks good. Some feedback below.
How about this? Index: extern.h =================================================================== RCS file: /cvs/src/usr.sbin/rpki-client/extern.h,v retrieving revision 1.182 diff -u -p -r1.182 extern.h --- extern.h 30 May 2023 12:14:48 -0000 1.182 +++ extern.h 30 May 2023 13:49:16 -0000 @@ -348,6 +348,7 @@ struct gbr { time_t notbefore; /* EE cert's Not Before */ time_t notafter; /* Not After of the GBR EE */ time_t expires; /* when the signature path expires */ + int talid; /* TAL the GBR is chained up to */ }; struct aspa_provider { @@ -755,7 +756,7 @@ void proc_http(char *, int) __attribut void proc_rrdp(int) __attribute__((noreturn)); /* Repository handling */ -int filepath_add(struct filepath_tree *, char *); +int filepath_add(struct filepath_tree *, char *, time_t); void rrdp_clear(unsigned int); void rrdp_save_state(unsigned int, struct rrdp_session *); int rrdp_handle_file(unsigned int, enum publish_type, char *, Index: filemode.c =================================================================== RCS file: /cvs/src/usr.sbin/rpki-client/filemode.c,v retrieving revision 1.32 diff -u -p -r1.32 filemode.c --- filemode.c 30 May 2023 12:02:22 -0000 1.32 +++ filemode.c 30 May 2023 13:49:16 -0000 @@ -589,6 +589,7 @@ parse_file(struct entityq *q, struct msg struct entity *entp; struct ibuf *b; struct tal *tal; + time_t dummy = 0; while ((entp = TAILQ_FIRST(q)) != NULL) { TAILQ_REMOVE(q, entp, entries); @@ -615,6 +616,7 @@ parse_file(struct entityq *q, struct msg io_simple_buffer(b, &entp->repoid, sizeof(entp->repoid)); io_simple_buffer(b, &entp->talid, sizeof(entp->talid)); io_str_buffer(b, entp->file); + io_simple_buffer(b, &dummy, sizeof(dummy)); io_close_buffer(msgq, b); entity_free(entp); } Index: main.c =================================================================== RCS file: /cvs/src/usr.sbin/rpki-client/main.c,v retrieving revision 1.240 diff -u -p -r1.240 main.c --- main.c 30 May 2023 12:14:48 -0000 1.240 +++ main.c 30 May 2023 13:49:16 -0000 @@ -559,6 +559,7 @@ entity_process(struct ibuf *b, struct st struct aspa *aspa; struct repo *rp; char *file; + time_t mtime; unsigned int id; int talid; int c; @@ -573,12 +574,13 @@ entity_process(struct ibuf *b, struct st io_read_buf(b, &id, sizeof(id)); io_read_buf(b, &talid, sizeof(talid)); io_read_str(b, &file); + io_read_buf(b, &mtime, sizeof(mtime)); /* in filemode messages can be ignored, only the accounting matters */ if (filemode) goto done; - if (filepath_add(&fpt, file) == 0) { + if (filepath_add(&fpt, file, mtime) == 0) { warnx("%s: File already visited", file); goto done; } Index: parser.c =================================================================== RCS file: /cvs/src/usr.sbin/rpki-client/parser.c,v retrieving revision 1.95 diff -u -p -r1.95 parser.c --- parser.c 30 May 2023 12:14:48 -0000 1.95 +++ parser.c 30 May 2023 13:49:16 -0000 @@ -352,7 +352,8 @@ proc_parser_mft_post(char *file, struct * Load the most recent MFT by opening both options and comparing the two. */ static char * -proc_parser_mft(struct entity *entp, struct mft **mp, char **crlfile) +proc_parser_mft(struct entity *entp, struct mft **mp, char **crlfile, + time_t *crlmtime) { struct mft *mft1 = NULL, *mft2 = NULL; struct crl *crl, *crl1, *crl2; @@ -360,6 +361,7 @@ proc_parser_mft(struct entity *entp, str const char *err1, *err2; *mp = NULL; + *crlmtime = 0; mft1 = proc_parser_mft_pre(entp, DIR_VALID, &file1, &crl1, &crl1file, &err1); @@ -392,6 +394,7 @@ proc_parser_mft(struct entity *entp, str } if (*mp != NULL) { + *crlmtime = crl->lastupdate; if (!crl_insert(&crlt, crl)) { warnx("%s: duplicate AKI %s", file, crl->aki); crl_free(crl); @@ -488,7 +491,7 @@ proc_parser_root_cert(char *file, const /* * Parse a ghostbuster record */ -static void +static struct gbr * proc_parser_gbr(char *file, const unsigned char *der, size_t len, const char *mftaki) { @@ -499,17 +502,23 @@ proc_parser_gbr(char *file, const unsign const char *errstr; if ((gbr = gbr_parse(&x509, file, der, len)) == NULL) - return; + return NULL; a = valid_ski_aki(file, &auths, gbr->ski, gbr->aki, mftaki); crl = crl_get(&crlt, a); /* return value can be ignored since nothing happens here */ - if (!valid_x509(file, ctx, x509, a, crl, &errstr)) + if (!valid_x509(file, ctx, x509, a, crl, &errstr)) { warnx("%s: %s", file, errstr); - + X509_free(x509); + gbr_free(gbr); + return NULL; + } X509_free(x509); - gbr_free(gbr); + + gbr->talid = a->cert->talid; + + return gbr; } /* @@ -618,8 +627,11 @@ parse_entity(struct entityq *q, struct m struct mft *mft; struct roa *roa; struct aspa *aspa; + struct gbr *gbr; + struct tak *tak; struct ibuf *b; unsigned char *f; + time_t mtime, crlmtime; size_t flen; char *file, *crlfile; int c; @@ -642,9 +654,13 @@ parse_entity(struct entityq *q, struct m file = NULL; f = NULL; + mtime = 0; + crlmtime = 0; + switch (entp->type) { case RTYPE_TAL: io_str_buffer(b, entp->file); + io_simple_buffer(b, &mtime, sizeof(mtime)); if ((tal = tal_parse(entp->file, entp->data, entp->datasz)) == NULL) errx(1, "%s: could not parse tal file", @@ -663,6 +679,9 @@ parse_entity(struct entityq *q, struct m else cert = proc_parser_cert(file, f, flen, entp->mftaki); + if (cert != NULL) + mtime = cert->notbefore; + io_simple_buffer(b, &mtime, sizeof(mtime)); c = (cert != NULL); io_simple_buffer(b, &c, sizeof(int)); if (cert != NULL) { @@ -676,8 +695,11 @@ parse_entity(struct entityq *q, struct m */ break; case RTYPE_MFT: - file = proc_parser_mft(entp, &mft, &crlfile); + file = proc_parser_mft(entp, &mft, &crlfile, &crlmtime); io_str_buffer(b, file); + if (mft != NULL) + mtime = mft->signtime; + io_simple_buffer(b, &mtime, sizeof(mtime)); c = (mft != NULL); io_simple_buffer(b, &c, sizeof(int)); if (mft != NULL) @@ -696,6 +718,8 @@ parse_entity(struct entityq *q, struct m io_simple_buffer(b2, &entp->talid, sizeof(entp->talid)); io_str_buffer(b2, crlfile); + io_simple_buffer(b2, &crlmtime, + sizeof(crlmtime)); free(crlfile); io_close_buffer(msgq, b2); @@ -706,6 +730,9 @@ parse_entity(struct entityq *q, struct m file = parse_load_file(entp, &f, &flen); io_str_buffer(b, file); roa = proc_parser_roa(file, f, flen, entp->mftaki); + if (roa != NULL) + mtime = roa->signtime; + io_simple_buffer(b, &mtime, sizeof(mtime)); c = (roa != NULL); io_simple_buffer(b, &c, sizeof(int)); if (roa != NULL) @@ -715,12 +742,19 @@ parse_entity(struct entityq *q, struct m case RTYPE_GBR: file = parse_load_file(entp, &f, &flen); io_str_buffer(b, file); - proc_parser_gbr(file, f, flen, entp->mftaki); + gbr = proc_parser_gbr(file, f, flen, entp->mftaki); + if (gbr != NULL) + mtime = gbr->signtime; + io_simple_buffer(b, &mtime, sizeof(mtime)); + gbr_free(gbr); break; case RTYPE_ASPA: file = parse_load_file(entp, &f, &flen); io_str_buffer(b, file); aspa = proc_parser_aspa(file, f, flen, entp->mftaki); + if (aspa != NULL) + mtime = aspa->signtime; + io_simple_buffer(b, &mtime, sizeof(mtime)); c = (aspa != NULL); io_simple_buffer(b, &c, sizeof(int)); if (aspa != NULL) @@ -730,13 +764,18 @@ parse_entity(struct entityq *q, struct m case RTYPE_TAK: file = parse_load_file(entp, &f, &flen); io_str_buffer(b, file); - proc_parser_tak(file, f, flen, entp->mftaki); + tak = proc_parser_tak(file, f, flen, entp->mftaki); + if (tak != NULL) + mtime = tak->signtime; + io_simple_buffer(b, &mtime, sizeof(mtime)); + tak_free(tak); break; case RTYPE_CRL: default: file = parse_filepath(entp->repoid, entp->path, entp->file, entp->location); io_str_buffer(b, file); + io_simple_buffer(b, &mtime, sizeof(mtime)); warnx("%s: unhandled type %d", file, entp->type); break; } Index: repo.c =================================================================== RCS file: /cvs/src/usr.sbin/rpki-client/repo.c,v retrieving revision 1.46 diff -u -p -r1.46 repo.c --- repo.c 25 May 2023 12:49:39 -0000 1.46 +++ repo.c 30 May 2023 13:49:16 -0000 @@ -119,6 +119,7 @@ static void remove_contents(char *); struct filepath { RB_ENTRY(filepath) entry; char *file; + time_t mtime; }; static inline int @@ -133,12 +134,13 @@ RB_PROTOTYPE(filepath_tree, filepath, en * Functions to lookup which files have been accessed during computation. */ int -filepath_add(struct filepath_tree *tree, char *file) +filepath_add(struct filepath_tree *tree, char *file, time_t mtime) { struct filepath *fp; if ((fp = malloc(sizeof(*fp))) == NULL) err(1, NULL); + fp->mtime = mtime; if ((fp->file = strdup(file)) == NULL) err(1, NULL); @@ -838,7 +840,7 @@ rrdp_handle_file(unsigned int id, enum p /* write new content or mark uri as deleted. */ if (pt == PUB_DEL) { - filepath_add(&rr->deleted, uri); + filepath_add(&rr->deleted, uri, 0); } else { fp = filepath_find(&rr->deleted, uri); if (fp != NULL) @@ -1536,6 +1538,27 @@ repo_move_valid(struct filepath_tree *tr base = strchr(fp->file + rrdpsz, '/'); assert(base != NULL); fn = base + 1; + + /* + * Adjust file last modification time in order to + * minimize RSYNC synchronization load after transport + * failover. While serializing RRDP datastructures to + * disk, set the last modified timestamp to the CMS + * signing-time or the X.509 notBefore timestamp. + */ + if (fp->mtime != 0) { + int ret; + struct timespec ts[2]; + + ts[0].tv_nsec = UTIME_OMIT; + ts[1].tv_sec = fp->mtime; + ts[1].tv_nsec = 0; + ret = utimensat(AT_FDCWD, fp->file, ts, 0); + if (ret == -1) { + warn("utimensat %s", fp->file); + continue; + } + } } if (repo_mkpath(AT_FDCWD, fn) == -1)