Index | Thread | Search

From:
Theo Buehler <tb@theobuehler.org>
Subject:
rpki-client: expose superfluous ROAIPAddress maxLength
To:
tech@openbsd.org
Date:
Sat, 17 Oct 2026 08:32:11 +0200

Download raw body.

Thread
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);
 		}
 	}