-/* $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 <job@fastly.com>
* Copyright (c) 2022 Theo Buehler <tb@openbsd.org>
}
/*
- * 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)
-/* $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 <kristaps@bsd.lv>
*
*/
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;
};
STYPE_TOTAL,
STYPE_UNIQUE,
STYPE_DEC_UNIQUE,
+ STYPE_BOTH,
STYPE_ONLY_IPV4,
STYPE_ONLY_IPV6,
- STYPE_BOTH,
};
struct repo;
/* global variables */
extern int verbose;
extern int filemode;
+extern int excludeaspa;
extern const char *tals[];
extern const char *taldescs[];
extern unsigned int talrepocnt[];
-/* $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 <claudio@openbsd.org>
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
int verbose;
int noop;
+int excludeaspa;
int filemode;
int shortlistmode;
int rrdpon = 1;
"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;
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"
-/* $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 <kristaps@bsd.lv>
*
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;
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;
}
-/* $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 <claudio@openbsd.org>
*
}
static int
-print_vap(FILE *out, struct vap *v)
+print_vap(FILE *out, struct vap *v, enum afi afi)
{
size_t i;
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)
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)
-.\" $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 <kristaps@bsd.lv>
.\"
.\" 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
.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
.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 ,