Here's a new diff that removes the duplicate parsing bits as mentioned
before but leaves masking the address to mask_addr() instead of doing it
manually.

Furthermore, it also stops route(8) from assuming address strings
without explicit prefix length to be /64.

The old behaviour described in RFC 2374 from 1998 is obsolete as per
RFC 3587 which states

        RFC 2374 was the definition of addresses for Format Prefix 001
        (2000::/3) which is formally made historic by this document.  Even
        though currently only 2000::/3 is being delegated by the IANA,
        implementations should not make any assumptions about 2000::/3 being
        special.  In the future, the IANA might be directed to delegate
        currently unassigned portions of the IPv6 address space for the
        purpose of Global Unicast as well.

This was brought to my attention by the (recent) misc@ thread
"Confusing IPv6 route(8) results"[0] in which benno@ mentioned an
important side effect when it comes to using `-prefixlen' before the
address string since order is relavant here and the following would
therefore blackhole a single /128 with after my patch applied:

        # route add -inet6 -prefixlen 56 2001:db8:: ::1 -blackhole

Thus, I'll put a note into current.html in case this change should go in.

FWIW, both FreeBSD and NetBSD already use `prefixlen()' and do not mask
the address in `inet6_makenetandmask()'. NetBSD still assumes /64 as per
RFC 2374 while FreeBSD does the same already I'm aiming for.

Regress passes, no regressions found when manually adding/removing
routes.

Feedback? Objections? OK?

0:      https://marc.info/?l=openbsd-misc&m=152712936731762


Index: route.c
===================================================================
RCS file: /cvs/src/sbin/route/route.c,v
retrieving revision 1.214
diff -u -p -r1.214 route.c
--- route.c     1 May 2018 18:14:10 -0000       1.214
+++ route.c     10 Jun 2018 22:35:43 -0000
@@ -786,50 +786,19 @@ inet_makenetandmask(u_int32_t net, struc
        sin->sin_len = 1 + cp - (char *)sin;
 }
 
-/*
- * XXX the function may need more improvement...
- */
 int
 inet6_makenetandmask(struct sockaddr_in6 *sin6, char *plen)
 {
-       struct in6_addr in6;
-       const char *errstr;
-       int i, len, q, r;
-
-       if (NULL==plen) {
+       if (!plen) {
                if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) &&
-                   sin6->sin6_scope_id == 0) {
+                   sin6->sin6_scope_id == 0)
                        plen = "0";
-               } else if ((sin6->sin6_addr.s6_addr[0] & 0xe0) == 0x20) {
-                       /* aggregatable global unicast - RFC2374 */
-                       memset(&in6, 0, sizeof(in6));
-                       if (!memcmp(&sin6->sin6_addr.s6_addr[8],
-                           &in6.s6_addr[8], 8))
-                               plen = "64";
-               }
        }
 
-       if (!plen || strcmp(plen, "128") == 0)
+       if (!plen || prefixlen(AF_INET6, plen))
                return (1);
-       else {
-               rtm_addrs |= RTA_NETMASK;
-               prefixlen(AF_INET6, plen);
-
-               len = strtonum(plen, 0, 128, &errstr);
-               if (errstr)
-                       errx(1, "prefixlen %s is %s", plen, errstr);
-
-               q = (128-len) >> 3;
-               r = (128-len) & 7;
-               i = 15;
 
-               while (q-- > 0)
-                       sin6->sin6_addr.s6_addr[i--] = 0;
-               if (r > 0)
-                       sin6->sin6_addr.s6_addr[i] &= 0xff << r;
-
-               return (0);
-       }
+       return (0);
 }
 
 /*
===================================================================
Stats: --- 35 lines 798 chars
Stats: +++ 4 lines 100 chars
Stats: -31 lines
Stats: -698 chars

Reply via email to