From: Theo Buehler Subject: rpki-client: expose superfluous ROAIPAddress maxLength To: tech@openbsd.org Date: Sat, 17 Oct 2026 08:32:11 +0200 Per RFC 9582, section 4.3.2.2, the optional maxLength element of a ROAIPAddress indicates the maximum length of an IP address prefix that the ROA authorizes the AS to advertise. If it matches the prefix length, this carries no additional information, so it can and SHOULD be omitted. In the good old tradition of sacrificing far too many lambs on the altar of Postel, this SHOULD could not be made a MUST. As of today, 26606 out of 398347 ROAs (6.7%) carry this extra element. Our internal struct roa_ip has a maxlength containing the value of the maxLength (if present) or the prefix length. This lossy representation discards the info whether the maxlength should have been there. This diff adds that info. I made the slightly dubious choice of using a 1-byte boolean because then it lands in a padding byte, thus avoiding a few megs of memory overhead in normal mode and shows this in file mode: IP address blocks: 154.208.186.0/24 maxlen: 24 (superfluous maxlen) I added a -vv warning emitted once per ROA so we can find such ROAs and a boolean to the JSON output. Having metrics for these kinds of things would be nice, but it needs a bit more thought. Index: extern.h =================================================================== RCS file: /cvs/src/usr.sbin/rpki-client/extern.h,v diff -u -p -r1.311 extern.h --- extern.h 16 Oct 2026 19:39:31 -0000 1.311 +++ extern.h 17 Oct 2026 05:40:45 -0000 @@ -309,6 +309,7 @@ struct roa_ip { unsigned char min[16]; /* full range minimum */ unsigned char max[16]; /* full range maximum */ unsigned char maxlength; /* max length or zero */ + unsigned char superfluous; /* maxLength SHOULD NOT be encoded */ }; /* Index: print.c =================================================================== RCS file: /cvs/src/usr.sbin/rpki-client/print.c,v diff -u -p -r1.79 print.c --- print.c 7 Jul 2026 13:38:54 -0000 1.79 +++ print.c 17 Oct 2026 06:12:29 -0000 @@ -550,11 +550,18 @@ roa_print(const struct cert *c, const st json_do_string("prefix", buf); json_do_uint("asid", p->asid); json_do_uint("maxlen", p->ips[i].maxlength); + json_do_bool("superfluous_maxlen", + p->ips[i].superfluous); json_do_end(); } else { + const char *superfluous = ""; + if (i > 0) printf("%26s", ""); - printf("%s maxlen: %hhu\n", buf, p->ips[i].maxlength); + if (p->ips[i].superfluous) + superfluous = " (superfluous maxlen)"; + printf("%s maxlen: %hhu%s\n", buf, p->ips[i].maxlength, + superfluous); } } if (outformats & FORMAT_JSON) Index: roa.c =================================================================== RCS file: /cvs/src/usr.sbin/rpki-client/roa.c,v diff -u -p -r1.94 roa.c --- roa.c 9 Oct 2026 08:36:50 -0000 1.94 +++ roa.c 17 Oct 2026 05:28:30 -0000 @@ -78,7 +78,7 @@ roa_parse_econtent(const char *fn, void uint64_t maxlen; struct ip_addr ipaddr; struct roa_ip *res; - int ipaddrblocksz; + int ipaddrblocksz, superfluous, warned = 0; int i, j, rc = 0; oder = d; @@ -168,6 +168,7 @@ roa_parse_econtent(const char *fn, void goto out; } maxlen = ipaddr.prefixlen; + superfluous = 0; if (addr->maxLength != NULL) { if (!ASN1_INTEGER_get_uint64(&maxlen, @@ -189,12 +190,21 @@ roa_parse_econtent(const char *fn, void fn, (unsigned long long)maxlen); goto out; } + if (ipaddr.prefixlen == maxlen) { + superfluous = 1; + if (!warned && verbose > 1) { + warnx("%s: superfluous " + "maxLength encoding", fn); + warned = 1; + } + } } res = &roa->ips[roa->num_ips++]; res->addr = ipaddr; res->afi = afi; res->maxlength = maxlen; + res->superfluous = superfluous; ip_roa_compose_ranges(res); } }