From 402543e65506e01812240db8c3010392e2495574 Mon Sep 17 00:00:00 2001 From: claudio Date: Tue, 16 Feb 2021 08:52:00 +0000 Subject: [PATCH] Rework the repository handling. Split the handling of trust anchors into ta_lookup() while regular repositories (to fetch .mft files) are handled by repo_lookup(). Also the cache directory layout changed; moving the trust anchors to ./ta/{tal basename}/ the other repositories end up in ./rsync/ OK tb@ --- usr.sbin/rpki-client/extern.h | 6 +- usr.sbin/rpki-client/main.c | 174 ++++++++++++++++++++++------------ usr.sbin/rpki-client/rsync.c | 102 ++++---------------- 3 files changed, 136 insertions(+), 146 deletions(-) diff --git a/usr.sbin/rpki-client/extern.h b/usr.sbin/rpki-client/extern.h index 9b17ee73212..6c699cfd75c 100644 --- a/usr.sbin/rpki-client/extern.h +++ b/usr.sbin/rpki-client/extern.h @@ -1,4 +1,4 @@ -/* $OpenBSD: extern.h,v 1.43 2021/02/16 07:58:30 job Exp $ */ +/* $OpenBSD: extern.h,v 1.44 2021/02/16 08:52:00 claudio Exp $ */ /* * Copyright (c) 2019 Kristaps Dzonsons * @@ -396,9 +396,7 @@ void proc_parser(int) __attribute__((noreturn)); /* Rsync-specific. */ -int rsync_uri_parse(const char **, size_t *, - const char **, size_t *, const char **, size_t *, - enum rtype *, const char *); +char *rsync_base_uri(const char *); void proc_rsync(char *, char *, int) __attribute__((noreturn)); /* Logging (though really used for OpenSSL errors). */ diff --git a/usr.sbin/rpki-client/main.c b/usr.sbin/rpki-client/main.c index fce65e21ffa..9e5d64beb9e 100644 --- a/usr.sbin/rpki-client/main.c +++ b/usr.sbin/rpki-client/main.c @@ -1,4 +1,4 @@ -/* $OpenBSD: main.c,v 1.98 2021/02/05 12:26:52 claudio Exp $ */ +/* $OpenBSD: main.c,v 1.99 2021/02/16 08:52:00 claudio Exp $ */ /* * Copyright (c) 2019 Kristaps Dzonsons * @@ -78,11 +78,12 @@ * An rsync repository. */ struct repo { - char *repo; /* repository rsync URI */ - char *local; /* local path name */ - char *notify; /* RRDB notify URI if available */ - size_t id; /* identifier (array index) */ - int loaded; /* whether loaded or not */ + char *repouri; /* CA repository base URI */ + char *local; /* local path name */ + char *uris[2]; /* URIs to fetch from */ + size_t id; /* identifier (array index) */ + int uriidx; /* which URI is fetched */ + int loaded; /* whether loaded or not */ }; size_t entity_queue; @@ -284,64 +285,112 @@ entityq_add(struct entityq *q, char *file, enum rtype type, } /* - * Look up a repository, queueing it for discovery if not found. + * Allocat a new repository be extending the repotable. */ -static const struct repo * -repo_lookup(const char *uri) +static struct repo * +repo_alloc(void) +{ + struct repo *rp; + + rt.repos = reallocarray(rt.repos, rt.reposz + 1, sizeof(struct repo)); + if (rt.repos == NULL) + err(1, "reallocarray"); + + rp = &rt.repos[rt.reposz++]; + memset(rp, 0, sizeof(struct repo)); + rp->id = rt.reposz - 1; + + return rp; +} + +static void +repo_fetch(struct repo *rp) { - const char *host, *mod; - size_t hostsz, modsz, i; - char *local; - struct repo *rp; struct ibuf *b; - if (!rsync_uri_parse(&host, &hostsz, - &mod, &modsz, NULL, NULL, NULL, uri)) - errx(1, "%s: malformed", uri); + if (noop) { + rp->loaded = 1; + logx("%s: using cache", rp->local); + stats.repos++; + /* there is nothing in the queue so no need to flush */ + return; + } + + logx("%s: pulling from network", rp->local); + if ((b = ibuf_dynamic(256, UINT_MAX)) == NULL) + err(1, NULL); + io_simple_buffer(b, &rp->id, sizeof(rp->id)); + io_str_buffer(b, rp->local); + io_str_buffer(b, rp->uris[0]); + ibuf_close(&rsyncq, b); +} - if (asprintf(&local, "%.*s/%.*s", (int)hostsz, host, - (int)modsz, mod) == -1) - err(1, "asprintf"); +/* + * Look up a trust anchor, queueing it for download if not found. + */ +static const struct repo * +ta_lookup(const struct tal *tal) +{ + struct repo *rp; + char *local; + size_t i, j; - /* Look up in repository table. */ + if (asprintf(&local, "ta/%s", tal->descr) == -1) + err(1, "asprinf"); + /* Look up in repository table. (Lookup should actually fail here) */ for (i = 0; i < rt.reposz; i++) { - if (strcmp(rt.repos[i].local, local)) + if (strcmp(rt.repos[i].local, local) != 0) continue; free(local); return &rt.repos[i]; } - rt.repos = reallocarray(rt.repos, - rt.reposz + 1, sizeof(struct repo)); - if (rt.repos == NULL) - err(1, "reallocarray"); - - rp = &rt.repos[rt.reposz++]; - memset(rp, 0, sizeof(struct repo)); - rp->id = rt.reposz - 1; + rp = repo_alloc(); rp->local = local; + for (i = 0, j = 0; i < tal->urisz && j < 2; i++) { + if (strncasecmp(tal->uri[i], "rsync://", 8) != 0) + continue; /* ignore non rsync URI for now */ + rp->uris[j++] = tal->uri[i]; + } + if (j == 0) + errx(1, "TAL file has no rsync:// URI"); - if ((rp->repo = strndup(uri, mod + modsz - uri)) == NULL) - err(1, "strdup"); + repo_fetch(rp); + return rp; +} - if (!noop) { - if (asprintf(&local, "%s", rp->local) == -1) - err(1, "asprintf"); - logx("%s: pulling from network", local); - if ((b = ibuf_dynamic(256, UINT_MAX)) == NULL) - err(1, NULL); - io_simple_buffer(b, &rp->id, sizeof(rp->id)); - io_str_buffer(b, local); - io_str_buffer(b, rp->repo); - ibuf_close(&rsyncq, b); - free(local); - } else { - rp->loaded = 1; - logx("%s: using cache", rp->local); - stats.repos++; - /* there is nothing in the queue so no need to flush */ +/* + * Look up a repository, queueing it for discovery if not found. + */ +static const struct repo * +repo_lookup(const char *uri) +{ + char *local, *repo; + struct repo *rp; + size_t i; + + if ((repo = rsync_base_uri(uri)) == NULL) + return NULL; + + /* Look up in repository table. */ + for (i = 0; i < rt.reposz; i++) { + if (rt.repos[i].repouri == NULL || + strcmp(rt.repos[i].repouri, repo) != 0) + continue; + free(repo); + return &rt.repos[i]; } + + rp = repo_alloc(); + rp->repouri = repo; + local = strchr(repo, ':') + strlen("://"); + if (asprintf(&rp->local, "rsync/%s", local) == -1) + err(1, "asprintf"); + if ((rp->uris[0] = strdup(repo)) == NULL) + err(1, "strdup"); + + repo_fetch(rp); return rp; } @@ -353,7 +402,10 @@ repo_filename(const struct repo *repo, const char *uri) { char *nfile; - uri += strlen(repo->repo) + 1; + if (strstr(uri, repo->repouri) != uri) + errx(1, "%s: URI outside of repository", uri); + uri += strlen(repo->repouri) + 1; /* skip base and '/' */ + if (asprintf(&nfile, "%s/%s", repo->local, uri) == -1) err(1, "asprintf"); return nfile; @@ -484,22 +536,17 @@ queue_add_from_tal(struct entityq *q, const struct tal *tal) { char *nfile; const struct repo *repo; - const char *uri = NULL; - size_t i; + const char *uri; assert(tal->urisz); - for (i = 0; i < tal->urisz; i++) { - uri = tal->uri[i]; - if (strncasecmp(uri, "rsync://", 8) == 0) - break; - } - if (uri == NULL) - errx(1, "TAL file has no rsync:// URI"); - /* Look up the repository. */ - repo = repo_lookup(uri); - nfile = repo_filename(repo, uri); + repo = ta_lookup(tal); + + uri = strrchr(repo->uris[0], '/'); + assert(uri); + if (asprintf(&nfile, "%s/%s", repo->local, uri + 1) == -1) + err(1, "asprintf"); entityq_add(q, nfile, RTYPE_CER, repo, tal->pkey, tal->pkeysz, tal->descr); @@ -515,6 +562,9 @@ queue_add_from_cert(struct entityq *q, const struct cert *cert) char *nfile; repo = repo_lookup(cert->mft); + if (repo == NULL) /* bad repository URI */ + return; + nfile = repo_filename(repo, cert->mft); entityq_add(q, nfile, RTYPE_MFT, repo, NULL, 0, NULL); @@ -1081,8 +1131,10 @@ main(int argc, char *argv[]) /* Memory cleanup. */ for (i = 0; i < rt.reposz; i++) { + free(rt.repos[i].repouri); free(rt.repos[i].local); - free(rt.repos[i].repo); + free(rt.repos[i].uris[0]); + free(rt.repos[i].uris[1]); } free(rt.repos); diff --git a/usr.sbin/rpki-client/rsync.c b/usr.sbin/rpki-client/rsync.c index 4500be20434..0285429d1d8 100644 --- a/usr.sbin/rpki-client/rsync.c +++ b/usr.sbin/rpki-client/rsync.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rsync.c,v 1.16 2021/02/03 09:29:22 claudio Exp $ */ +/* $OpenBSD: rsync.c,v 1.17 2021/02/16 08:52:00 claudio Exp $ */ /* * Copyright (c) 2019 Kristaps Dzonsons * @@ -45,110 +45,50 @@ struct rsyncproc { }; /* - * Conforms to RFC 5781. - * Note that "Source" is broken down into the module, path, and also - * file type relevant to RPKI. - * Any of the pointers (except "uri") may be NULL. - * Returns zero on failure, non-zero on success. + * Return the base of a rsync URI (rsync://hostname/module). The + * caRepository provided by the RIR CAs point deeper than they should + * which would result in many rsync calls for almost every subdirectory. + * This is inefficent so instead crop the URI to a common base. + * The returned string needs to be freed by the caller. */ -int -rsync_uri_parse(const char **hostp, size_t *hostsz, - const char **modulep, size_t *modulesz, - const char **pathp, size_t *pathsz, - enum rtype *rtypep, const char *uri) +char * +rsync_base_uri(const char *uri) { - const char *host, *module, *path; - size_t sz; - - /* Initialise all output values to NULL or 0. */ - - if (hostsz != NULL) - *hostsz = 0; - if (modulesz != NULL) - *modulesz = 0; - if (pathsz != NULL) - *pathsz = 0; - if (hostp != NULL) - *hostp = 0; - if (modulep != NULL) - *modulep = 0; - if (pathp != NULL) - *pathp = 0; - if (rtypep != NULL) - *rtypep = RTYPE_EOF; + const char *host, *module, *rest; /* Case-insensitive rsync URI. */ - - if (strncasecmp(uri, "rsync://", 8)) { + if (strncasecmp(uri, "rsync://", 8) != 0) { warnx("%s: not using rsync schema", uri); - return 0; + return NULL; } /* Parse the non-zero-length hostname. */ - host = uri + 8; if ((module = strchr(host, '/')) == NULL) { warnx("%s: missing rsync module", uri); - return 0; + return NULL; } else if (module == host) { warnx("%s: zero-length rsync host", uri); - return 0; + return NULL; } - if (hostp != NULL) - *hostp = host; - if (hostsz != NULL) - *hostsz = module - host; - /* The non-zero-length module follows the hostname. */ - - if (module[1] == '\0') { + module++; + if (*module == '\0') { warnx("%s: zero-length rsync module", uri); - return 0; + return NULL; } - module++; - /* The path component is optional. */ - - if ((path = strchr(module, '/')) == NULL) { - assert(*module != '\0'); - if (modulep != NULL) - *modulep = module; - if (modulesz != NULL) - *modulesz = strlen(module); - return 1; - } else if (path == module) { + if ((rest = strchr(module, '/')) == NULL) { + return strdup(uri); + } else if (rest == module) { warnx("%s: zero-length module", uri); - return 0; - } - - if (modulep != NULL) - *modulep = module; - if (modulesz != NULL) - *modulesz = path - module; - - path++; - sz = strlen(path); - - if (pathp != NULL) - *pathp = path; - if (pathsz != NULL) - *pathsz = sz; - - if (rtypep != NULL && sz > 4) { - if (strcasecmp(path + sz - 4, ".roa") == 0) - *rtypep = RTYPE_ROA; - else if (strcasecmp(path + sz - 4, ".mft") == 0) - *rtypep = RTYPE_MFT; - else if (strcasecmp(path + sz - 4, ".cer") == 0) - *rtypep = RTYPE_CER; - else if (strcasecmp(path + sz - 4, ".crl") == 0) - *rtypep = RTYPE_CRL; + return NULL; } - return 1; + return strndup(uri, rest - uri); } static void -- 2.20.1