Index: constraints.c =================================================================== RCS file: /cvs/src/usr.sbin/rpki-client/constraints.c,v retrieving revision 1.1 diff -u -p -r1.1 constraints.c --- constraints.c 13 Oct 2023 12:06:49 -0000 1.1 +++ constraints.c 9 Nov 2023 12:36:42 -0000 @@ -542,7 +542,7 @@ constraints_check_ips(const char *fn, st return 0; } if (allow_ips != NULL) { - if (ip_addr_check_covered(cert->afi, cert->min, cert->max, + if (ip_addr_check_covered(cert->afi, &cert->min, &cert->max, allow_ips, allow_ipsz) <= 0) return 0; } @@ -588,12 +588,11 @@ constraints_validate(const char *fn, con deny_ipsz = tal_constraints[talid].deny_ipsz; for (i = 0; i < cert->ipsz; i++) { - if (constraints_check_ips(fn, &cert->ips[i], allow_ips, - allow_ipsz, deny_ips, deny_ipsz)) - continue; - - ip_warn(fn, &cert->ips[i], "violates trust anchor constraints"); - return 0; + if (!constraints_check_ips(fn, &cert->ips[i], allow_ips, + allow_ipsz, deny_ips, deny_ipsz)) { + ip_warn(fn, &cert->ips[i], "violates trust anchor constraints"); + return 0; + } } return 1; Index: extern.h =================================================================== RCS file: /cvs/src/usr.sbin/rpki-client/extern.h,v retrieving revision 1.193 diff -u -p -r1.193 extern.h --- extern.h 13 Oct 2023 12:06:49 -0000 1.193 +++ extern.h 9 Nov 2023 12:36:42 -0000 @@ -99,11 +99,15 @@ enum cert_ip_type { * The RFC specifies multiple address or ranges per AFI; this structure * encodes both the AFI and a single address or range. */ +struct ip_headdr { + uint32_t addr[4]; +}; + struct cert_ip { enum afi afi; /* AFI value */ enum cert_ip_type type; /* type of IP entry */ - unsigned char min[16]; /* full range minimum */ - unsigned char max[16]; /* full range maximum */ + struct ip_headdr min; /* full range minimum */ + struct ip_headdr max; /* full range maximum */ union { struct ip_addr ip; /* singular address */ struct ip_addr_range range; /* range */ @@ -229,8 +233,8 @@ struct mft { struct roa_ip { enum afi afi; /* AFI value */ struct ip_addr addr; /* the address prefix itself */ - unsigned char min[16]; /* full range minimum */ - unsigned char max[16]; /* full range maximum */ + struct ip_headdr min; /* full range minimum */ + struct ip_headdr max; /* full range maximum */ unsigned char maxlength; /* max length or zero */ }; @@ -713,8 +717,9 @@ void ip_addr_range_print(const struct int ip_addr_cmp(const struct ip_addr *, const struct ip_addr *); int ip_addr_check_overlap(const struct cert_ip *, const char *, const struct cert_ip *, size_t, int); -int ip_addr_check_covered(enum afi, const unsigned char *, - const unsigned char *, const struct cert_ip *, size_t); +int ip_addr_check_covered(enum afi, const struct ip_headdr *, + const struct ip_headdr *, const struct cert_ip *, + size_t); int ip_cert_compose_ranges(struct cert_ip *); void ip_roa_compose_ranges(struct roa_ip *); void ip_warn(const char *, const struct cert_ip *, const char *); Index: ip.c =================================================================== RCS file: /cvs/src/usr.sbin/rpki-client/ip.c,v retrieving revision 1.31 diff -u -p -r1.31 ip.c --- ip.c 18 Oct 2023 07:10:24 -0000 1.31 +++ ip.c 9 Nov 2023 12:36:42 -0000 @@ -25,8 +25,27 @@ #include "extern.h" +#ifndef nitems +#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) +#endif + #define PREFIX_SIZE(x) (((x) + 7) / 8) +static int +ip_headdr_cmp(const struct ip_headdr *a, const struct ip_headdr *b) +{ + size_t i; + + for (i = 0; i < nitems(a->addr); i++) { + if (a->addr[i] > b->addr[i]) + return (1); + if (a->addr[i] < b->addr[i]) + return (-1); + } + + return (0); +} + /* * Parse an IP address family. * This is defined in different places in the ROA/X509 standards, but @@ -77,22 +96,54 @@ ip_addr_afi_parse(const char *fn, const */ int ip_addr_check_covered(enum afi afi, - const unsigned char *min, const unsigned char *max, + const struct ip_headdr *min, const struct ip_headdr *max, const struct cert_ip *ips, size_t ipsz) { - size_t i, sz = AFI_IPV4 == afi ? 4 : 16; + size_t lim; + const struct cert_ip *nip = NULL; /* nearest ip */ + int cmp; - for (i = 0; i < ipsz; i++) { - if (ips[i].afi != afi) + /* + * find the entry closest to the specified min address + */ + + for (lim = ipsz; lim != 0; lim >>= 1) { + const struct cert_ip *tip = &ips[lim >> 1]; + + if (afi < tip->afi) { + /* move left */ + continue; + } + if (afi > tip->afi) { + /* move right */ + ips = tip + 1; + lim--; continue; - if (ips[i].type == CERT_IP_INHERIT) + } + + if (tip->type == CERT_IP_INHERIT) return 0; - if (memcmp(ips[i].min, min, sz) <= 0 && - memcmp(ips[i].max, max, sz) >= 0) - return 1; + + cmp = ip_headdr_cmp(&tip->min, min); + if (cmp <= 0) { + nip = tip; + if (cmp == 0) + break; + + /* move right */ + ips = tip + 1; + lim--; + } /* else move left */ } - return -1; + if (nip == NULL) + return (0); + + /* + * check the max address is inside the range + */ + + return ip_headdr_cmp(max, &nip->max) <= 0; } /* @@ -105,16 +156,20 @@ int ip_addr_check_overlap(const struct cert_ip *ip, const char *fn, const struct cert_ip *ips, size_t ipsz, int quiet) { - size_t i, sz = ip->afi == AFI_IPV4 ? 4 : 16; + size_t i; int inherit_v4 = 0, inherit_v6 = 0; int has_v4 = 0, has_v6 = 0; + size_t lim; + const struct cert_ip *nip = NULL; /* nearest ip */ + int cmp; + /* * FIXME: cache this by having a flag on the cert_ip, else we're * going to need to do a lot of scanning for big allocations. */ - for (i = 0; i < ipsz; i++) + for (i = 0; i < ipsz; i++) { if (ips[i].type == CERT_IP_INHERIT) { if (ips[i].afi == AFI_IPV4) inherit_v4 = 1; @@ -126,6 +181,7 @@ ip_addr_check_overlap(const struct cert_ else has_v6 = 1; } + } /* Disallow multiple inheritance per type. */ @@ -145,22 +201,39 @@ ip_addr_check_overlap(const struct cert_ /* Check our ranges. */ - for (i = 0; i < ipsz; i++) { - if (ips[i].afi != ip->afi) + for (lim = ipsz; lim != 0; lim >>= 1) { + const struct cert_ip *tip = &ips[lim >> 1]; + + if (ip->afi < tip->afi) { + /* move left */ continue; - if (memcmp(ips[i].max, ip->min, sz) <= 0 || - memcmp(ips[i].min, ip->max, sz) >= 0) + } + if (ip->afi > tip->afi) { + /* move right */ + ips = tip + 1; + lim--; continue; - if (!quiet) { - warnx("%s: RFC 3779 section 2.2.3.5: " - "cannot have overlapping IP addresses", fn); - ip_warn(fn, ip, "certificate IP"); - ip_warn(fn, &ips[i], "offending IP"); } - return 0; + + if (tip->type == CERT_IP_INHERIT) /* XXX is this right? */ + return 1; + + cmp = ip_headdr_cmp(&tip->min, &ip->min); + if (cmp <= 0) { + nip = tip; + if (cmp == 0) + break; + + /* move right */ + ips = tip + 1; + lim--; + } /* else move left */ } - return 1; + if (nip == NULL) + return (1); + + return ip_headdr_cmp(&ip->max, &nip->max) > 0; } /* @@ -206,7 +279,7 @@ ip_addr_parse(const ASN1_BIT_STRING *p, return 0; } - memset(addr, 0, sizeof(struct ip_addr)); + memset(addr, 0, sizeof(*addr)); addr->prefixlen = p->length * 8 - unused; memcpy(addr->addr, p->data, p->length); return 1; @@ -237,7 +310,7 @@ ip_addr_print(const struct ip_addr *addr if (inet_ntop(af, addr->addr, ipbuf, sizeof(ipbuf)) == NULL) err(1, "inet_ntop"); - ret = snprintf(buf, bufsz, "%s/%hhu", ipbuf, addr->prefixlen); + ret = snprintf(buf, bufsz, "%s/%u", ipbuf, addr->prefixlen); if (ret < 0 || (size_t)ret >= bufsz) err(1, "malformed IP address"); } @@ -284,35 +357,53 @@ ip_addr_range_print(const struct ip_addr int ip_cert_compose_ranges(struct cert_ip *p) { - size_t sz; + uint32_t addr[4] = { 0, 0, 0, 0 }; + size_t sz, plen, i; switch (p->type) { case CERT_IP_ADDR: sz = PREFIX_SIZE(p->ip.prefixlen); - memset(p->min, 0x0, sizeof(p->min)); - memcpy(p->min, p->ip.addr, sz); - memset(p->max, 0xff, sizeof(p->max)); - memcpy(p->max, p->ip.addr, sz); - if (sz > 0 && p->ip.prefixlen % 8 != 0) - p->max[sz - 1] |= (1 << (8 - p->ip.prefixlen % 8)) - 1; + memcpy(addr, p->ip.addr, sz); + for (i = 0; i < nitems(p->min.addr); i++) + p->min.addr[i] = ntohl(addr[i]); + + plen = p->ip.prefixlen; break; case CERT_IP_RANGE: - memset(p->min, 0x0, sizeof(p->min)); sz = PREFIX_SIZE(p->range.min.prefixlen); - memcpy(p->min, p->range.min.addr, sz); - memset(p->max, 0xff, sizeof(p->max)); + memcpy(addr, p->range.min.addr, sz); + for (i = 0; i < nitems(p->min.addr); i++) { + p->min.addr[i] = ntohl(addr[i]); + addr[i] = 0; /* reset for max addr */ + } + sz = PREFIX_SIZE(p->range.max.prefixlen); - memcpy(p->max, p->range.max.addr, sz); - if (sz > 0 && p->range.max.prefixlen % 8 != 0) - p->max[sz - 1] |= - (1 << (8 - p->range.max.prefixlen % 8)) - 1; + memcpy(addr, p->range.max.addr, sz); + + plen = p->range.max.prefixlen; break; default: return 1; } - sz = AFI_IPV4 == p->afi ? 4 : 16; - return memcmp(p->min, p->max, sz) <= 0; + i = 0; + while (plen >= 32) { + p->max.addr[i] = ntohl(addr[i]); + i++; + plen -= 32; + } + + if (plen % 32) { + p->max.addr[i] = ntohl(addr[i]) | ~0U >> plen; + i++; + } + + while (i < nitems(p->max.addr)) { + p->max.addr[i] = ~0U; + i++; + } + + return ip_headdr_cmp(&p->min, &p->max) <= 0; } /* @@ -322,14 +413,32 @@ ip_cert_compose_ranges(struct cert_ip *p void ip_roa_compose_ranges(struct roa_ip *p) { - size_t sz = PREFIX_SIZE(p->addr.prefixlen); + uint32_t addr[4] = { 0, 0, 0, 0 }; + size_t sz, plen, i; + + sz = PREFIX_SIZE(p->addr.prefixlen); + memcpy(addr, p->addr.addr, sz); + for (i = 0; i < nitems(p->min.addr); i++) + p->min.addr[i] = ntohl(addr[i]); - memset(p->min, 0x0, sizeof(p->min)); - memcpy(p->min, p->addr.addr, sz); - memset(p->max, 0xff, sizeof(p->max)); - memcpy(p->max, p->addr.addr, sz); - if (sz > 0 && p->addr.prefixlen % 8 != 0) - p->max[sz - 1] |= (1 << (8 - p->addr.prefixlen % 8)) - 1; + plen = p->addr.prefixlen; + + i = 0; + while (plen >= 32) { + p->max.addr[i] = ntohl(addr[i]); + i++; + plen -= 32; + } + + if (plen % 32) { + p->max.addr[i] = ntohl(addr[i]) | ~0U >> plen; + i++; + } + + while (i < nitems(p->max.addr)) { + p->max.addr[i] = ~0U; + i++; + } } void Index: print.c =================================================================== RCS file: /cvs/src/usr.sbin/rpki-client/print.c,v retrieving revision 1.43 diff -u -p -r1.43 print.c --- print.c 19 Jul 2023 21:49:30 -0000 1.43 +++ print.c 9 Nov 2023 12:36:42 -0000 @@ -203,13 +203,24 @@ as_resources_print(struct cert_as *as, s } static void +ip_headdr_ntop(int af, const struct ip_headdr *iph, char *buf, size_t buflen) +{ + uint32_t addr[4]; + size_t i; + + for (i = 0; i < 4; i++) + addr[i] = htonl(iph->addr[i]); + + inet_ntop(af, addr, buf, buflen); +} + +static void ip_resources_print(struct cert_ip *ips, size_t ipsz, size_t asz) { char buf1[64], buf2[64]; size_t i; int sockt; - for (i = 0; i < ipsz; i++) { if (outformats & FORMAT_JSON) json_do_object("resource", 1); @@ -237,8 +248,8 @@ ip_resources_print(struct cert_ip *ips, case CERT_IP_RANGE: sockt = (ips[i].afi == AFI_IPV4) ? AF_INET : AF_INET6; - inet_ntop(sockt, ips[i].min, buf1, sizeof(buf1)); - inet_ntop(sockt, ips[i].max, buf2, sizeof(buf2)); + ip_headdr_ntop(sockt, &ips[i].min, buf1, sizeof(buf1)); + ip_headdr_ntop(sockt, &ips[i].max, buf2, sizeof(buf2)); if (outformats & FORMAT_JSON) { json_do_object("ip_range", 1); json_do_string("min", buf1); Index: validate.c =================================================================== RCS file: /cvs/src/usr.sbin/rpki-client/validate.c,v retrieving revision 1.68 diff -u -p -r1.68 validate.c --- validate.c 19 Oct 2023 17:05:55 -0000 1.68 +++ validate.c 9 Nov 2023 12:36:42 -0000 @@ -61,7 +61,7 @@ valid_as(struct auth *a, uint32_t min, u */ static int valid_ip(struct auth *a, enum afi afi, - const unsigned char *min, const unsigned char *max) + const struct ip_headdr *min, const struct ip_headdr *max) { int c; @@ -172,8 +172,8 @@ valid_cert(const char *fn, struct auth * if (cert->ips[i].type == CERT_IP_INHERIT) continue; - if (valid_ip(a, cert->ips[i].afi, cert->ips[i].min, - cert->ips[i].max)) + if (valid_ip(a, cert->ips[i].afi, &cert->ips[i].min, + &cert->ips[i].max)) continue; switch (cert->ips[i].type) { @@ -209,8 +209,8 @@ valid_roa(const char *fn, struct cert *c char buf[64]; for (i = 0; i < roa->ipsz; i++) { - if (ip_addr_check_covered(roa->ips[i].afi, roa->ips[i].min, - roa->ips[i].max, cert->ips, cert->ipsz) > 0) + if (ip_addr_check_covered(roa->ips[i].afi, &roa->ips[i].min, + &roa->ips[i].max, cert->ips, cert->ipsz) > 0) continue; ip_addr_print(&roa->ips[i].addr, roa->ips[i].afi, buf, @@ -503,8 +503,8 @@ valid_rsc(const char *fn, struct cert *c } for (i = 0; i < rsc->ipsz; i++) { - if (ip_addr_check_covered(rsc->ips[i].afi, rsc->ips[i].min, - rsc->ips[i].max, cert->ips, cert->ipsz) > 0) + if (ip_addr_check_covered(rsc->ips[i].afi, &rsc->ips[i].min, + &rsc->ips[i].max, cert->ips, cert->ipsz) > 0) continue; switch (rsc->ips[i].type) { @@ -590,7 +590,7 @@ valid_geofeed(const char *fn, struct cer for (i = 0; i < g->geoipsz; i++) { if (ip_addr_check_covered(g->geoips[i].ip->afi, - g->geoips[i].ip->min, g->geoips[i].ip->max, cert->ips, + &g->geoips[i].ip->min, &g->geoips[i].ip->max, cert->ips, cert->ipsz) > 0) continue;