summaryrefslogtreecommitdiff
path: root/usr.sbin
diff options
context:
space:
mode:
authorClaudio Jeker <claudio@cvs.openbsd.org>2021-11-09 11:03:40 +0000
committerClaudio Jeker <claudio@cvs.openbsd.org>2021-11-09 11:03:40 +0000
commitebd2be1c7940534b23f9a7c7af363138fe94c391 (patch)
tree0826b5355368a09ec204ee490b19dc67ec015fdc /usr.sbin
parent1485a0d6103098e583e2b7c8f1f6fd5761662890 (diff)
Limit the number of publication points under a given TAL.
Introduce an additional timeout for each publication point. The limits are large enough to accomodate normal operating levels. With and OK benno@ job@ tb@ beck@ deraadt@
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/rpki-client/extern.h15
-rw-r--r--usr.sbin/rpki-client/main.c22
-rw-r--r--usr.sbin/rpki-client/repo.c98
3 files changed, 119 insertions, 16 deletions
diff --git a/usr.sbin/rpki-client/extern.h b/usr.sbin/rpki-client/extern.h
index bd6b11af238..399fc7c81f7 100644
--- a/usr.sbin/rpki-client/extern.h
+++ b/usr.sbin/rpki-client/extern.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: extern.h,v 1.94 2021/11/05 10:50:41 claudio Exp $ */
+/* $OpenBSD: extern.h,v 1.95 2021/11/09 11:03:39 claudio Exp $ */
/*
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -390,6 +390,7 @@ struct msgbuf;
extern int verbose;
extern const char *tals[];
extern const char *taldescs[];
+extern unsigned int talrepocnt[];
extern size_t talsz;
/* Routines for RPKI entities. */
@@ -501,8 +502,8 @@ void rrdp_save_state(size_t, struct rrdp_session *);
int rrdp_handle_file(size_t, enum publish_type, char *,
char *, size_t, char *, size_t);
char *repo_filename(const struct repo *, const char *);
-struct repo *ta_lookup(struct tal *);
-struct repo *repo_lookup(const char *, const char *);
+struct repo *ta_lookup(int, struct tal *);
+struct repo *repo_lookup(int, const char *, const char *);
int repo_queued(struct repo *, struct entity *);
void repo_cleanup(struct filepath_tree *);
void repo_free(void);
@@ -517,6 +518,8 @@ void rrdp_fetch(size_t, const char *, const char *,
struct rrdp_session *);
void rrdp_http_done(size_t, enum http_result, const char *);
+int repo_next_timeout(int);
+void repo_check_timeout(void);
/* Logging (though really used for OpenSSL errors). */
@@ -620,4 +623,10 @@ int mkpath(const char *);
/* Maximum number of concurrent rsync processes. */
#define MAX_RSYNC_PROCESSES 16
+/* Maximum allowd repositories per tal */
+#define MAX_REPO_PER_TAL 1000
+
+/* Timeout for repository synchronisation, in seconds */
+#define MAX_REPO_TIMEOUT (15 * 60)
+
#endif /* ! EXTERN_H */
diff --git a/usr.sbin/rpki-client/main.c b/usr.sbin/rpki-client/main.c
index 4ea97df451a..15708183d24 100644
--- a/usr.sbin/rpki-client/main.c
+++ b/usr.sbin/rpki-client/main.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: main.c,v 1.163 2021/11/04 18:00:07 claudio Exp $ */
+/* $OpenBSD: main.c,v 1.164 2021/11/09 11:03:39 claudio Exp $ */
/*
* Copyright (c) 2021 Claudio Jeker <claudio@openbsd.org>
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
@@ -51,6 +51,7 @@
const char *tals[TALSZ_MAX];
const char *taldescs[TALSZ_MAX];
+unsigned int talrepocnt[TALSZ_MAX];
size_t talsz;
size_t entity_queue;
@@ -428,7 +429,9 @@ queue_add_from_tal(struct tal *tal)
err(1, NULL);
/* Look up the repository. */
- repo = ta_lookup(tal);
+ repo = ta_lookup(tal->id, tal);
+ if (repo == NULL)
+ return;
/* steal the pkey from the tal structure */
data = tal->pkey;
@@ -446,11 +449,10 @@ queue_add_from_cert(const struct cert *cert)
struct repo *repo;
char *nfile;
- repo = repo_lookup(cert->repo, rrdpon ? cert->notify : NULL);
- if (repo == NULL) {
- warnx("%s: repository lookup failed", cert->repo);
+ repo = repo_lookup(cert->talid, cert->repo,
+ rrdpon ? cert->notify : NULL);
+ if (repo == NULL)
return;
- }
if ((nfile = strdup(cert->mft)) == NULL)
err(1, NULL);
@@ -1007,13 +1009,17 @@ main(int argc, char *argv[])
err(1, "fchdir");
while (entity_queue > 0 && !killme) {
+ int polltim;
+
for (i = 0; i < NPFD; i++) {
pfd[i].events = POLLIN;
if (queues[i]->queued)
pfd[i].events |= POLLOUT;
}
- if ((c = poll(pfd, NPFD, INFTIM)) == -1) {
+ polltim = repo_next_timeout(INFTIM);
+
+ if ((c = poll(pfd, NPFD, polltim)) == -1) {
if (errno == EINTR)
continue;
err(1, "poll");
@@ -1043,6 +1049,8 @@ main(int argc, char *argv[])
if (hangup)
break;
+ repo_check_timeout();
+
/*
* Check the rsync and http process.
* This means that one of our modules has completed
diff --git a/usr.sbin/rpki-client/repo.c b/usr.sbin/rpki-client/repo.c
index 02580d53e6e..68b3aa8f1d3 100644
--- a/usr.sbin/rpki-client/repo.c
+++ b/usr.sbin/rpki-client/repo.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: repo.c,v 1.10 2021/11/04 17:35:09 claudio Exp $ */
+/* $OpenBSD: repo.c,v 1.11 2021/11/09 11:03:39 claudio Exp $ */
/*
* Copyright (c) 2021 Claudio Jeker <claudio@openbsd.org>
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
@@ -27,6 +27,7 @@
#include <fcntl.h>
#include <fts.h>
#include <limits.h>
+#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -94,6 +95,8 @@ struct repo {
const struct rsyncrepo *rsync;
const struct tarepo *ta;
struct entityq queue; /* files waiting for repo */
+ time_t alarm; /* sync timeout */
+ int talid;
size_t id; /* identifier */
};
SLIST_HEAD(, repo) repos = SLIST_HEAD_INITIALIZER(repos);
@@ -608,14 +611,22 @@ rrdp_basedir(const char *dir)
* Allocate and insert a new repository.
*/
static struct repo *
-repo_alloc(void)
+repo_alloc(int talid)
{
struct repo *rp;
+ if (++talrepocnt[talid] >= MAX_REPO_PER_TAL) {
+ if (talrepocnt[talid] == MAX_REPO_PER_TAL)
+ warnx("too many repositories under %s", tals[talid]);
+ return NULL;
+ }
+
if ((rp = calloc(1, sizeof(*rp))) == NULL)
err(1, NULL);
rp->id = ++repoid;
+ rp->talid = talid;
+ rp->alarm = getmonotime() + MAX_REPO_TIMEOUT;
TAILQ_INIT(&rp->queue);
SLIST_INSERT_HEAD(&repos, rp, entry);
@@ -932,6 +943,9 @@ rsync_finish(size_t id, int ok)
tr = ta_find(id);
if (tr != NULL) {
+ /* repository changed state already, ignore request */
+ if (tr->state != REPO_LOADING)
+ return;
if (ok) {
logx("ta/%s: loaded from network", tr->descr);
stats.rsync_repos++;
@@ -954,6 +968,9 @@ rsync_finish(size_t id, int ok)
if (rr == NULL)
errx(1, "unknown rsync repo %zu", 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++;
@@ -982,6 +999,9 @@ rrdp_finish(size_t id, int ok)
rr = rrdp_find(id);
if (rr == NULL)
errx(1, "unknown RRDP repo %zu", id);
+ /* repository changed state already, ignore request */
+ if (rr->state != REPO_LOADING)
+ return;
if (ok && rrdp_merge_repo(rr)) {
logx("%s: loaded from network", rr->notifyuri);
@@ -1033,6 +1053,10 @@ http_finish(size_t id, enum http_result res, const char *last_mod)
return;
}
+ /* repository changed state already, ignore request */
+ if (tr->state != REPO_LOADING)
+ return;
+
/* Move downloaded TA file into place, or unlink on failure. */
if (res == HTTP_OK) {
char *file;
@@ -1066,7 +1090,7 @@ http_finish(size_t id, enum http_result res, const char *last_mod)
* Look up a trust anchor, queueing it for download if not found.
*/
struct repo *
-ta_lookup(struct tal *tal)
+ta_lookup(int id, struct tal *tal)
{
struct repo *rp;
@@ -1076,7 +1100,10 @@ ta_lookup(struct tal *tal)
return rp;
}
- rp = repo_alloc();
+ rp = repo_alloc(id);
+ if (rp == NULL)
+ return NULL;
+
if ((rp->repouri = strdup(tal->descr)) == NULL)
err(1, NULL);
rp->ta = ta_get(tal);
@@ -1088,7 +1115,7 @@ ta_lookup(struct tal *tal)
* Look up a repository, queueing it for discovery if not found.
*/
struct repo *
-repo_lookup(const char *uri, const char *notify)
+repo_lookup(int id, const char *uri, const char *notify)
{
struct repo *rp;
char *repouri;
@@ -1112,7 +1139,12 @@ repo_lookup(const char *uri, const char *notify)
return rp;
}
- rp = repo_alloc();
+ rp = repo_alloc(id);
+ if (rp == NULL) {
+ free(repouri);
+ return NULL;
+ }
+
rp->repouri = repouri;
if (notify != NULL)
if ((rp->notifyuri = strdup(notify)) == NULL)
@@ -1169,6 +1201,60 @@ repo_queued(struct repo *rp, struct entity *p)
return 0;
}
+int
+repo_next_timeout(int timeout)
+{
+ struct repo *rp;
+ time_t now;
+
+ now = getmonotime();
+ /* Look up in repository table. (Lookup should actually fail here) */
+ SLIST_FOREACH(rp, &repos, entry) {
+ if (repo_state(rp) == REPO_LOADING) {
+ int diff = rp->alarm - now;
+ diff *= 1000;
+ if (timeout == INFTIM || diff < timeout)
+ timeout = diff;
+ }
+ }
+ return timeout;
+}
+
+static void
+repo_fail(struct repo *rp)
+{
+ /* reset the alarm since code may fallback to rsync */
+ rp->alarm = getmonotime() + MAX_REPO_TIMEOUT;
+
+ if (rp->ta)
+ http_finish(rp->ta->id, HTTP_FAILED, NULL);
+ else if (rp->rrdp)
+ rrdp_finish(rp->rrdp->id, 0);
+ else if (rp->rsync)
+ rsync_finish(rp->rsync->id, 0);
+ else
+ errx(1, "%s: bad repo", rp->repouri);
+}
+
+void
+repo_check_timeout(void)
+{
+ struct repo *rp;
+ time_t now;
+
+ now = getmonotime();
+ /* Look up in repository table. (Lookup should actually fail here) */
+ SLIST_FOREACH(rp, &repos, entry) {
+ if (repo_state(rp) == REPO_LOADING) {
+ if (rp->alarm <= now) {
+ warnx("%s: synchronisation timeout",
+ rp->repouri);
+ repo_fail(rp);
+ }
+ }
+ }
+}
+
static char **
add_to_del(char **del, size_t *dsz, char *file)
{