Download raw body.
rpki-client: expose superfluous ROAIPAddress maxLength
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);
}
}
rpki-client: expose superfluous ROAIPAddress maxLength