From 264f4ef9cf0baf0679938eb509a3222051585213 Mon Sep 17 00:00:00 2001 From: claudio Date: Thu, 13 Jan 2022 13:18:41 +0000 Subject: [PATCH] Implement a RRDP_CLEAR message that instructs the parent to cleanup the rrdp directory. This is used before a snapshot download to ensure that the snapshot is applied to a clean repo. Similar cleanup happens if the transfer fails. In that case remove the temp directory contents only. This uses a new function remove_contents() to remove everything below a base directory (a bit like rm -r X/*). OK tb@ --- usr.sbin/rpki-client/extern.h | 6 ++- usr.sbin/rpki-client/main.c | 5 +- usr.sbin/rpki-client/repo.c | 93 ++++++++++++++++++++++++++--------- usr.sbin/rpki-client/rrdp.c | 19 ++++++- 4 files changed, 95 insertions(+), 28 deletions(-) diff --git a/usr.sbin/rpki-client/extern.h b/usr.sbin/rpki-client/extern.h index 737aa4588a0..c69fb03c417 100644 --- a/usr.sbin/rpki-client/extern.h +++ b/usr.sbin/rpki-client/extern.h @@ -1,4 +1,4 @@ -/* $OpenBSD: extern.h,v 1.101 2022/01/11 13:06:07 claudio Exp $ */ +/* $OpenBSD: extern.h,v 1.102 2022/01/13 13:18:41 claudio Exp $ */ /* * Copyright (c) 2019 Kristaps Dzonsons * @@ -309,10 +309,11 @@ enum rrdp_msg { RRDP_START, RRDP_SESSION, RRDP_FILE, + RRDP_CLEAR, RRDP_END, RRDP_HTTP_REQ, RRDP_HTTP_INI, - RRDP_HTTP_FIN + RRDP_HTTP_FIN, }; /* @@ -501,6 +502,7 @@ void proc_rrdp(int); /* Repository handling */ int filepath_add(struct filepath_tree *, char *); +void rrdp_clear(unsigned int); void rrdp_save_state(unsigned int, struct rrdp_session *); int rrdp_handle_file(unsigned int, enum publish_type, char *, char *, size_t, char *, size_t); diff --git a/usr.sbin/rpki-client/main.c b/usr.sbin/rpki-client/main.c index 1a976d8064b..e8084bc745f 100644 --- a/usr.sbin/rpki-client/main.c +++ b/usr.sbin/rpki-client/main.c @@ -1,4 +1,4 @@ -/* $OpenBSD: main.c,v 1.174 2022/01/13 11:50:29 claudio Exp $ */ +/* $OpenBSD: main.c,v 1.175 2022/01/13 13:18:41 claudio Exp $ */ /* * Copyright (c) 2021 Claudio Jeker * Copyright (c) 2019 Kristaps Dzonsons @@ -632,6 +632,9 @@ rrdp_process(struct ibuf *b) free(uri); free(data); break; + case RRDP_CLEAR: + rrdp_clear(id); + break; default: errx(1, "unexpected rrdp response"); } diff --git a/usr.sbin/rpki-client/repo.c b/usr.sbin/rpki-client/repo.c index 5451021f519..6bd584d9601 100644 --- a/usr.sbin/rpki-client/repo.c +++ b/usr.sbin/rpki-client/repo.c @@ -1,4 +1,4 @@ -/* $OpenBSD: repo.c,v 1.21 2022/01/13 11:47:44 claudio Exp $ */ +/* $OpenBSD: repo.c,v 1.22 2022/01/13 13:18:41 claudio Exp $ */ /* * Copyright (c) 2021 Claudio Jeker * Copyright (c) 2019 Kristaps Dzonsons @@ -106,6 +106,7 @@ static SLIST_HEAD(, repo) repos = SLIST_HEAD_INITIALIZER(repos); unsigned int repoid; static struct rsyncrepo *rsync_get(const char *, int); +static void remove_contents(char *); /* * Database of all file path accessed during a run. @@ -787,6 +788,23 @@ fail: free(file); } +/* + * Remove RRDP repo and start over. + */ +void +rrdp_clear(unsigned int id) +{ + struct rrdprepo *rr; + + rr = rrdp_find(id); + if (rr == NULL) + errx(1, "non-existant rrdp repo %u", id); + + /* remove rrdp repository contents */ + remove_contents(rr->basedir); + remove_contents(rr->temp); +} + /* * Write a file into the temporary RRDP dir but only after checking * its hash (if required). The function also makes sure that the file @@ -932,24 +950,6 @@ fail: return 0; } -static void -rrdp_clean_temp(struct rrdprepo *rr) -{ - struct filepath *fp, *nfp; - char *fn; - - filepath_free(&rr->deleted); - - RB_FOREACH_SAFE(fp, filepath_tree, &rr->added, nfp) { - if ((fn = rrdp_filename(rr, fp->file, 1)) != NULL) { - if (unlink(fn) == -1) - warn("unlink %s", fn); - free(fn); - } - filepath_put(&rr->added, fp); - } -} - /* * RSYNC sync finished, either with or without success. */ @@ -981,10 +981,10 @@ rsync_finish(unsigned int id, int ok) rr = rsync_find(id); if (rr == NULL) errx(1, "unknown rsync repo %u", id); - /* repository changed state already, ignore request */ if (rr->state != REPO_LOADING) return; + if (ok) { logx("%s: loaded from network", rr->basedir); stats.rsync_repos++; @@ -1016,15 +1016,15 @@ rrdp_finish(unsigned int id, int ok) if (ok && rrdp_merge_repo(rr)) { logx("%s: loaded from network", rr->notifyuri); - rr->state = REPO_DONE; stats.rrdp_repos++; + rr->state = REPO_DONE; repo_done(rr, ok); } else { - rrdp_clean_temp(rr); - stats.rrdp_fails++; - rr->state = REPO_FAILED; logx("%s: load from network failed, fallback to rsync", rr->notifyuri); + stats.rrdp_fails++; + rr->state = REPO_FAILED; + remove_contents(rr->temp); repo_done(rr, 0); } } @@ -1418,3 +1418,48 @@ repo_free(void) rrdp_free(); rsync_free(); } + +static void +remove_contents(char *base) +{ + char *argv[2] = { base, NULL }; + FTS *fts; + FTSENT *e; + + if ((fts = fts_open(argv, FTS_PHYSICAL | FTS_NOSTAT, NULL)) == NULL) + err(1, "fts_open"); + errno = 0; + while ((e = fts_read(fts)) != NULL) { + switch (e->fts_info) { + case FTS_NSOK: + case FTS_SL: + case FTS_SLNONE: + if (unlink(e->fts_accpath) == -1) + warn("unlink %s", e->fts_path); + break; + case FTS_D: + break; + case FTS_DP: + /* keep root directory */ + if (e->fts_level == FTS_ROOTLEVEL) + break; + if (rmdir(e->fts_accpath) == -1) + warn("rmdir %s", e->fts_path); + break; + case FTS_NS: + case FTS_ERR: + warnx("fts_read %s: %s", e->fts_path, + strerror(e->fts_errno)); + break; + default: + warnx("unhandled[%x] %s", e->fts_info, + e->fts_path); + break; + } + errno = 0; + } + if (errno) + err(1, "fts_read"); + if (fts_close(fts) == -1) + err(1, "fts_close"); +} diff --git a/usr.sbin/rpki-client/rrdp.c b/usr.sbin/rpki-client/rrdp.c index 3ee191f74d6..80c22b97207 100644 --- a/usr.sbin/rpki-client/rrdp.c +++ b/usr.sbin/rpki-client/rrdp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rrdp.c,v 1.19 2021/12/22 09:35:14 claudio Exp $ */ +/* $OpenBSD: rrdp.c,v 1.20 2022/01/13 13:18:41 claudio Exp $ */ /* * Copyright (c) 2020 Nils Fisher * Copyright (c) 2021 Claudio Jeker @@ -141,6 +141,21 @@ rrdp_state_send(struct rrdp *s) io_close_buffer(&msgq, b); } +/* + * Inform parent to clear the RRDP repository before start of snapshot. + */ +static void +rrdp_clear_repo(struct rrdp *s) +{ + enum rrdp_msg type = RRDP_CLEAR; + struct ibuf *b; + + b = io_new_buffer(); + io_simple_buffer(b, &type, sizeof(type)); + io_simple_buffer(b, &s->id, sizeof(s->id)); + io_close_buffer(&msgq, b); +} + /* * Send a blob of data to the main process to store it in the repository. */ @@ -246,6 +261,7 @@ rrdp_failed(struct rrdp *s) /* fallback to a snapshot as per RFC8182 */ free_delta_xml(s->dxml); s->dxml = NULL; + rrdp_clear_repo(s); s->sxml = new_snapshot_xml(s->parser, &s->current, s); s->task = SNAPSHOT; s->state = RRDP_STATE_REQ; @@ -315,6 +331,7 @@ rrdp_finished(struct rrdp *s) break; case SNAPSHOT: logx("%s: downloading snapshot", s->local); + rrdp_clear_repo(s); s->sxml = new_snapshot_xml(p, &s->current, s); s->state = RRDP_STATE_REQ; break; -- 2.20.1