From: claudio Date: Fri, 13 Jan 2023 08:58:36 +0000 (+0000) Subject: Add aspa-set to openbgpd config output. X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=acb55ac2725cfb2041919d27278b2cb9074532fc;p=openbsd Add aspa-set to openbgpd config output. Change the way the validated ASPA tree is built since OpenBGPD config follows more the ASPA profile and puts the optional AFI to each provider ASnum instead of duplicated everything into an IPv4 and IPv6 tree. The JSON output of ASPA is still the same. The inclusion of the aspa-set can currently be disabled by the -A flag. OK tb@ --- diff --git a/usr.sbin/rpki-client/aspa.c b/usr.sbin/rpki-client/aspa.c index d41ef8bfc8a..363288ad631 100644 --- a/usr.sbin/rpki-client/aspa.c +++ b/usr.sbin/rpki-client/aspa.c @@ -1,4 +1,4 @@ -/* $OpenBSD: aspa.c,v 1.10 2022/12/15 12:02:29 claudio Exp $ */ +/* $OpenBSD: aspa.c,v 1.11 2023/01/13 08:58:36 claudio Exp $ */ /* * Copyright (c) 2022 Job Snijders * Copyright (c) 2022 Theo Buehler @@ -328,120 +328,80 @@ aspa_read(struct ibuf *b) } /* - * draft-ietf-sidrops-8210bis section 5.12 states: - * - * "The router MUST see at most one ASPA for a given AFI from a cache for - * a particular Customer ASID active at any time. As a number of conditions - * in the global RPKI may present multiple valid ASPA RPKI records for a - * single customer to a particular RP cache, this places a burden on the - * cache to form the union of multiple ASPA records it has received from - * the global RPKI into one RPKI-To-Router (RTR) ASPA PDU." - * - * The above described 'burden' (which is specific to RTR) is resolved in - * insert_vap() and aspa_insert_vaps() functions below. - * - * XXX: for bgpd(8), ASPA config injection (via /var/db/rpki-client/openbgpd) - * we probably want to undo the 'burden solving' and compress into implicit - * AFIs. + * Insert a new aspa_provider at index idx in the struct vap v. + * All elements in the provider array from idx are moved up by one + * to make space for the new element. */ - -/* - * If the CustomerASID (CAS) showed up before, append the ProviderAS (PAS); - * otherwise create a new entry in the RB tree. - * Ensure there are no duplicates in the 'providers' array. - * Always compare 'expires': use the soonest expiration moment. - */ -static int -insert_vap(struct vap_tree *tree, uint32_t cas, uint32_t pas, time_t expires, - enum afi afi, struct repo *rp) +static void +insert_vap(struct vap *v, uint32_t idx, struct aspa_provider *p) { - struct vap *v, *found; - size_t i; - - if ((v = malloc(sizeof(*v))) == NULL) - err(1, NULL); - v->afi = afi; - v->custasid = cas; - v->expires = expires; - - if ((found = RB_INSERT(vap_tree, tree, v)) == NULL) { - if ((v->providers = malloc(sizeof(uint32_t))) == NULL) - err(1, NULL); - - v->providers[0] = pas; - v->providersz = 1; - - repo_stat_inc(rp, RTYPE_ASPA, STYPE_UNIQUE); - return 1; - } - - free(v); - - if (found->expires > expires) - found->expires = expires; - - for (i = 0; i < found->providersz; i++) { - if (found->providers[i] == pas) - return 0; - } - - found->providers = reallocarray(found->providers, - found->providersz + 1, sizeof(uint32_t)); - if (found->providers == NULL) - err(1, NULL); - found->providers[found->providersz++] = pas; - return 1; + if (idx < v->providersz) + memmove(v->providers + idx + 1, v->providers + idx, + (v->providersz - idx) * sizeof(*v->providers)); + v->providers[idx] = *p; + v->providersz++; } /* * Add each ProviderAS entry into the Validated ASPA Providers (VAP) tree. - * Updates "vaps" to be the total number of VAPs, and "uniqs" to be the - * pre-'AFI explosion' deduplicated count. + * Duplicated entries are merged. */ void aspa_insert_vaps(struct vap_tree *tree, struct aspa *aspa, struct repo *rp) { - size_t i; - uint32_t cas, pas; - time_t expires; - int new; - - cas = aspa->custasid; - expires = aspa->expires; + struct vap *v, *found; + size_t i, j; repo_stat_inc(rp, RTYPE_ASPA, STYPE_TOTAL); - for (i = 0; i < aspa->providersz; i++) { - pas = aspa->providers[i].as; - - switch (aspa->providers[i].afi) { - case AFI_IPV4: - if (insert_vap(tree, cas, pas, expires, AFI_IPV4, rp)) - repo_stat_inc(rp, RTYPE_ASPA, STYPE_ONLY_IPV4); - break; - case AFI_IPV6: - if (insert_vap(tree, cas, pas, expires, AFI_IPV6, rp)) - repo_stat_inc(rp, RTYPE_ASPA, STYPE_ONLY_IPV6); - break; - default: - new = insert_vap(tree, cas, pas, expires, AFI_IPV4, rp); - new += insert_vap(tree, cas, pas, expires, AFI_IPV6, - rp); - if (new != 0) - repo_stat_inc(rp, RTYPE_ASPA, STYPE_BOTH); - break; + if ((v = calloc(1, sizeof(*v))) == NULL) + err(1, NULL); + v->custasid = aspa->custasid; + v->expires = aspa->expires; + + if ((found = RB_INSERT(vap_tree, tree, v)) != NULL) { + if (found->expires > v->expires) + found->expires = v->expires; + free(v); + v = found; + } else + repo_stat_inc(rp, RTYPE_ASPA, STYPE_UNIQUE); + + v->providers = reallocarray(v->providers, + v->providersz + aspa->providersz, sizeof(*v->providers)); + if (v->providers == NULL) + err(1, NULL); + + /* + * Merge all data from aspa into v: loop over all aspa providers, + * insert them in the right place in v->providers while keeping the + * order of the providers array. + */ + for (i = 0, j = 0; i < aspa->providersz; ) { + if (j == v->providersz || + aspa->providers[i].as < v->providers[j].as) { + /* merge provider from aspa into v */ + repo_stat_inc(rp, RTYPE_ASPA, + STYPE_BOTH + aspa->providers[i].afi); + insert_vap(v, j, &aspa->providers[i]); + i++; + } else if (aspa->providers[i].as == v->providers[j].as) { + /* duplicate provider, merge afi */ + if (v->providers[j].afi != aspa->providers[i].afi) { + repo_stat_inc(rp, RTYPE_ASPA, + STYPE_BOTH + aspa->providers[i].afi); + v->providers[j].afi = 0; + } + i++; } + if (j < v->providersz) + j++; } } static inline int vapcmp(struct vap *a, struct vap *b) { - if (a->afi > b->afi) - return 1; - if (a->afi < b->afi) - return -1; - if (a->custasid > b->custasid) return 1; if (a->custasid < b->custasid) diff --git a/usr.sbin/rpki-client/extern.h b/usr.sbin/rpki-client/extern.h index ed76f358463..9470d77e336 100644 --- a/usr.sbin/rpki-client/extern.h +++ b/usr.sbin/rpki-client/extern.h @@ -1,4 +1,4 @@ -/* $OpenBSD: extern.h,v 1.166 2023/01/04 14:22:43 claudio Exp $ */ +/* $OpenBSD: extern.h,v 1.167 2023/01/13 08:58:36 claudio Exp $ */ /* * Copyright (c) 2019 Kristaps Dzonsons * @@ -356,9 +356,8 @@ struct aspa { */ struct vap { RB_ENTRY(vap) entry; - enum afi afi; uint32_t custasid; - uint32_t *providers; + struct aspa_provider *providers; size_t providersz; time_t expires; }; @@ -503,9 +502,9 @@ enum stype { STYPE_TOTAL, STYPE_UNIQUE, STYPE_DEC_UNIQUE, + STYPE_BOTH, STYPE_ONLY_IPV4, STYPE_ONLY_IPV6, - STYPE_BOTH, }; struct repo; @@ -568,6 +567,7 @@ struct msgbuf; /* global variables */ extern int verbose; extern int filemode; +extern int excludeaspa; extern const char *tals[]; extern const char *taldescs[]; extern unsigned int talrepocnt[]; diff --git a/usr.sbin/rpki-client/main.c b/usr.sbin/rpki-client/main.c index 2be19c9a74b..7150511f64c 100644 --- a/usr.sbin/rpki-client/main.c +++ b/usr.sbin/rpki-client/main.c @@ -1,4 +1,4 @@ -/* $OpenBSD: main.c,v 1.230 2023/01/06 16:06:43 claudio Exp $ */ +/* $OpenBSD: main.c,v 1.231 2023/01/13 08:58:36 claudio Exp $ */ /* * Copyright (c) 2021 Claudio Jeker * Copyright (c) 2019 Kristaps Dzonsons @@ -67,6 +67,7 @@ const char *bird_tablename = "ROAS"; int verbose; int noop; +int excludeaspa; int filemode; int shortlistmode; int rrdpon = 1; @@ -942,8 +943,11 @@ main(int argc, char *argv[]) "proc exec unveil", NULL) == -1) err(1, "pledge"); - while ((c = getopt(argc, argv, "b:Bcd:e:fH:jmnorRs:S:t:T:vV")) != -1) + while ((c = getopt(argc, argv, "Ab:Bcd:e:fH:jmnorRs:S:t:T:vV")) != -1) switch (c) { + case 'A': + excludeaspa = 1; + break; case 'b': bind_addr = optarg; break; @@ -1423,7 +1427,7 @@ main(int argc, char *argv[]) usage: fprintf(stderr, - "usage: rpki-client [-BcjmnoRrVv] [-b sourceaddr] [-d cachedir]" + "usage: rpki-client [-ABcjmnoRrVv] [-b sourceaddr] [-d cachedir]" " [-e rsync_prog]\n" " [-H fqdn] [-S skiplist] [-s timeout] [-T table]" " [-t tal]\n" diff --git a/usr.sbin/rpki-client/output-bgpd.c b/usr.sbin/rpki-client/output-bgpd.c index 54c00e53c6f..98c2d712b04 100644 --- a/usr.sbin/rpki-client/output-bgpd.c +++ b/usr.sbin/rpki-client/output-bgpd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: output-bgpd.c,v 1.24 2022/08/30 18:56:49 job Exp $ */ +/* $OpenBSD: output-bgpd.c,v 1.25 2023/01/13 08:58:36 claudio Exp $ */ /* * Copyright (c) 2019 Kristaps Dzonsons * @@ -23,7 +23,9 @@ int output_bgpd(FILE *out, struct vrp_tree *vrps, struct brk_tree *brks, struct vap_tree *vaps, struct stats *st) { - struct vrp *v; + struct vrp *vrp; + struct vap *vap; + size_t i; if (outputheader(out, st) < 0) return -1; @@ -31,23 +33,58 @@ output_bgpd(FILE *out, struct vrp_tree *vrps, struct brk_tree *brks, if (fprintf(out, "roa-set {\n") < 0) return -1; - RB_FOREACH(v, vrp_tree, vrps) { + RB_FOREACH(vrp, vrp_tree, vrps) { char ipbuf[64], maxlenbuf[100]; - ip_addr_print(&v->addr, v->afi, ipbuf, sizeof(ipbuf)); - if (v->maxlength > v->addr.prefixlen) { + ip_addr_print(&vrp->addr, vrp->afi, ipbuf, sizeof(ipbuf)); + if (vrp->maxlength > vrp->addr.prefixlen) { int ret = snprintf(maxlenbuf, sizeof(maxlenbuf), - "maxlen %u ", v->maxlength); + "maxlen %u ", vrp->maxlength); if (ret < 0 || (size_t)ret > sizeof(maxlenbuf)) return -1; } else maxlenbuf[0] = '\0'; if (fprintf(out, "\t%s %ssource-as %u expires %lld\n", - ipbuf, maxlenbuf, v->asid, (long long)v->expires) < 0) + ipbuf, maxlenbuf, vrp->asid, (long long)vrp->expires) < 0) return -1; } if (fprintf(out, "}\n") < 0) return -1; + + if (excludeaspa) + return 0; + + if (fprintf(out, "\naspa-set {\n") < 0) + return -1; + RB_FOREACH(vap, vap_tree, vaps) { + if (fprintf(out, "\tcustomer-as %d expires %lld " + "provider-as { ", vap->custasid, + (long long)vap->expires) < 0) + return -1; + for (i = 0; i < vap->providersz; i++) { + if (fprintf(out, "%u", vap->providers[i].as) < 0) + return -1; + switch (vap->providers[i].afi) { + case AFI_IPV4: + if (fprintf(out, "allow inet") < 0) + return -1; + break; + case AFI_IPV6: + if (fprintf(out, "allow inet6") < 0) + return -1; + break; + } + if (i + 1 < vap->providersz) + if (fprintf(out, ", ") < 0) + return -1; + } + + if (fprintf(out, " }\n") < 0) + return -1; + } + if (fprintf(out, "}\n") < 0) + return -1; + return 0; } diff --git a/usr.sbin/rpki-client/output-json.c b/usr.sbin/rpki-client/output-json.c index 4945af19c9f..95bb5b1fdb2 100644 --- a/usr.sbin/rpki-client/output-json.c +++ b/usr.sbin/rpki-client/output-json.c @@ -1,4 +1,4 @@ -/* $OpenBSD: output-json.c,v 1.30 2022/12/15 12:02:29 claudio Exp $ */ +/* $OpenBSD: output-json.c,v 1.31 2023/01/13 08:58:36 claudio Exp $ */ /* * Copyright (c) 2019 Claudio Jeker * @@ -112,7 +112,7 @@ outputheader_json(FILE *out, struct stats *st) } static int -print_vap(FILE *out, struct vap *v) +print_vap(FILE *out, struct vap *v, enum afi afi) { size_t i; @@ -120,7 +120,9 @@ print_vap(FILE *out, struct vap *v) v->custasid) < 0) return -1; for (i = 0; i < v->providersz; i++) { - if (fprintf(out, "%u", v->providers[i]) < 0) + if (v->providers[i].afi != 0 && v->providers[i].afi != afi) + continue; + if (fprintf(out, "%u", v->providers[i].as) < 0) return -1; if (i + 1 < v->providersz) if (fprintf(out, ", ") < 0) @@ -143,31 +145,28 @@ output_aspa(FILE *out, struct vap_tree *vaps) return -1; first = 1; - RB_FOREACH(v, vap_tree, vaps) - if (v->afi == AFI_IPV4) { - if (!first) { - if (fprintf(out, ",\n") < 0) - return -1; - } - first = 0; - if (print_vap(out, v)) + RB_FOREACH(v, vap_tree, vaps) { + if (!first) { + if (fprintf(out, ",\n") < 0) return -1; } + first = 0; + if (print_vap(out, v, AFI_IPV4)) + return -1; + } if (fprintf(out, "\n\t\t],\n\t\t\"ipv6\": [\n") < 0) return -1; first = 1; RB_FOREACH(v, vap_tree, vaps) { - if (v->afi == AFI_IPV6) { - if (!first) { - if (fprintf(out, ",\n") < 0) - return -1; - } - first = 0; - if (print_vap(out, v)) + if (!first) { + if (fprintf(out, ",\n") < 0) return -1; } + first = 0; + if (print_vap(out, v, AFI_IPV6)) + return -1; } if (fprintf(out, "\n\t\t]\n\t}\n") < 0) diff --git a/usr.sbin/rpki-client/rpki-client.8 b/usr.sbin/rpki-client/rpki-client.8 index 4c8fdd88706..e5431a953bd 100644 --- a/usr.sbin/rpki-client/rpki-client.8 +++ b/usr.sbin/rpki-client/rpki-client.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: rpki-client.8,v 1.82 2022/12/15 12:02:29 claudio Exp $ +.\" $OpenBSD: rpki-client.8,v 1.83 2023/01/13 08:58:36 claudio Exp $ .\" .\" Copyright (c) 2019 Kristaps Dzonsons .\" @@ -14,7 +14,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: December 15 2022 $ +.Dd $Mdocdate: January 13 2023 $ .Dt RPKI-CLIENT 8 .Os .Sh NAME @@ -22,7 +22,7 @@ .Nd RPKI validator to support BGP routing security .Sh SYNOPSIS .Nm -.Op Fl BcjmnoRrVv +.Op Fl ABcjmnoRrVv .Op Fl b Ar sourceaddr .Op Fl d Ar cachedir .Op Fl e Ar rsync_prog @@ -62,6 +62,8 @@ in various formats. .Pp The options are as follows: .Bl -tag -width Ds +.It Fl A +Exclude the aspa-set in the OpenBGPD specific output file. .It Fl B Create output in the files .Pa bird1v4 ,