Print this page
9352 netstat(1M) should be able to print IPv4 networks in CIDR form

@@ -21,11 +21,11 @@
 /*
  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 1990  Mentat Inc.
  * netstat.c 2.2, last change 9/9/91
  * MROUTING Revision 3.5
- * Copyright (c) 2017, Joyent, Inc.
+ * Copyright 2018, Joyent, Inc.
  */
 
 /*
  * simple netstat based on snmp/mib-2 interface to the TCP/IP stack
  *

@@ -234,10 +234,11 @@
 #define MDIFF(diff, elem2, elem1, member)       (diff)->member = \
         (elem2)->member - (elem1)->member
 
 
 static  boolean_t       Aflag = B_FALSE;        /* All sockets/ifs/rtng-tbls */
+static  boolean_t       CIDRflag = B_FALSE;     /* CIDR for IPv4 -i/-r addrs */
 static  boolean_t       Dflag = B_FALSE;        /* DCE info */
 static  boolean_t       Iflag = B_FALSE;        /* IP Traffic Interfaces */
 static  boolean_t       Mflag = B_FALSE;        /* STREAMS Memory Statistics */
 static  boolean_t       Nflag = B_FALSE;        /* Numeric Network Addresses */
 static  boolean_t       Rflag = B_FALSE;        /* Routing Tables */

@@ -444,16 +445,20 @@
         free(default_ip_str);
 
         (void) setlocale(LC_ALL, "");
         (void) textdomain(TEXT_DOMAIN);
 
-        while ((c = getopt(argc, argv, "adimnrspMgvxf:P:I:DRT:")) != -1) {
+        while ((c = getopt(argc, argv, "acdimnrspMgvxf:P:I:DRT:")) != -1) {
                 switch ((char)c) {
                 case 'a':               /* all connections */
                         Aflag = B_TRUE;
                         break;
 
+                case 'c':
+                        CIDRflag = B_TRUE;
+                        break;
+
                 case 'd':               /* DCE info */
                         Dflag = B_TRUE;
                         IFLAGMOD(Iflag_only, 1, 0); /* see macro def'n */
                         break;
 

@@ -3338,11 +3343,11 @@
 if_report_ip4(mib2_ipAddrEntry_t *ap,
     char ifname[], char logintname[], struct ifstat *statptr,
     boolean_t ksp_not_null)
 {
 
-        char abuf[MAXHOSTNAMELEN + 1];
+        char abuf[MAXHOSTNAMELEN + 4];  /* Include /<num> for CIDR-printing. */
         char dstbuf[MAXHOSTNAMELEN + 1];
 
         if (ksp_not_null) {
                 (void) printf("%-5s %-4u ",
                     ifname, ap->ipAdEntInfo.ae_mtu);

@@ -4437,11 +4442,11 @@
 
 static boolean_t
 ire_report_item_v4(const mib2_ipRouteEntry_t *rp, boolean_t first,
     const sec_attr_list_t *attrs)
 {
-        char                    dstbuf[MAXHOSTNAMELEN + 1];
+        char                    dstbuf[MAXHOSTNAMELEN + 4]; /* + "/<num>" */
         char                    maskbuf[MAXHOSTNAMELEN + 1];
         char                    gwbuf[MAXHOSTNAMELEN + 1];
         char                    ifname[LIFNAMSIZ + 1];
         char                    flags[10];      /* RTF_ flags */
         uint_t                  flag_b;

@@ -5555,11 +5560,11 @@
         struct vifctl   *vip;
         vifi_t          vifi;
         struct mfcctl   *mfccp;
         int             numvifs = 0;
         int             nmfc = 0;
-        char            abuf[MAXHOSTNAMELEN + 1];
+        char            abuf[MAXHOSTNAMELEN + 4]; /* Include CIDR /<num>. */
 
         if (!(family_selected(AF_INET)))
                 return;
 
         /* 'for' loop 1: */

@@ -5974,10 +5979,61 @@
         }
         return (dst);
 }
 
 /*
+ * Returns -2 to indicate a discontiguous mask.  Otherwise returns between
+ * 0 and 32.
+ */
+static int
+v4_cidr_len(uint_t mask)
+{
+        int rc = 0;
+        int i;
+
+        for (i = 0; i < 32; i++) {
+                if (mask & 0x1)
+                        rc++;
+                else if (rc > 0)
+                        return (-2);    /* Discontiguous IPv4 netmask. */
+
+                mask >>= 1;
+        }
+
+        return (rc);
+}
+
+static void
+append_v4_cidr_len(char *dst, uint_t dstlen, int prefixlen)
+{
+        char *prefixptr;
+
+        /* 4 bytes leaves room for '/' 'N' 'N' '\0' */
+        if (strlen(dst) <= dstlen - 4) {
+                prefixptr = dst + strlen(dst);
+        } else {
+                /*
+                 * Cut off last 3 chars of very-long DNS name.  All callers
+                 * should give us enough room, but name services COULD give us
+                 * a way-too-big name (see above).
+                 */
+                prefixptr = dst + strlen(dst) - 3;
+        }
+        /* At this point "prefixptr" is guaranteed to point to 4 bytes. */
+
+        if (prefixlen >= 0) {
+                if (prefixlen > 32)     /* Shouldn't happen, but... */
+                        prefixlen = 32;
+                (void) snprintf(prefixptr, 4, "/%d", prefixlen);
+        } else if (prefixlen == -2) {
+                /* "/NM" == Noncontiguous Mask. */
+                (void) strcat(prefixptr, "/NM");
+        }
+        /* Else print nothing extra. */
+}
+
+/*
  * Return the name of the network whose address is given. The address is
  * assumed to be that of a net or subnet, not a host.
  */
 static char *
 pr_net(uint_t addr, uint_t mask, char *dst, uint_t dstlen)

@@ -5986,17 +6042,21 @@
         struct netent   *np = NULL;
         struct hostent  *hp = NULL;
         uint_t          net;
         int             subnetshift;
         int             error_num;
+        int             prefixlen = -1; /* -1 == Don't print prefix! */
+                                        /* -2 == Noncontiguous mask... */
 
         if (addr == INADDR_ANY && mask == INADDR_ANY) {
-                (void) strncpy(dst, "default", dstlen);
-                dst[dstlen - 1] = 0;
+                (void) strlcpy(dst, "default", dstlen);
                 return (dst);
         }
 
+        if (CIDRflag)
+                prefixlen = v4_cidr_len(ntohl(mask));
+
         if (!Nflag && addr) {
                 if (mask == 0) {
                         if (IN_CLASSA(addr)) {
                                 mask = (uint_t)IN_CLASSA_NET;
                                 subnetshift = 8;

@@ -6014,10 +6074,12 @@
                          * fields.
                          */
                         while (addr & ~mask)
                                 /* compiler doesn't sign extend! */
                                 mask = (mask | ((int)mask >> subnetshift));
+                        if (CIDRflag)
+                                prefixlen = v4_cidr_len(mask);
                 }
                 net = addr & mask;
                 while ((mask & 1) == 0)
                         mask >>= 1, net >>= 1;
                 ns_lookup_start();

@@ -6036,15 +6098,17 @@
                         if (hp)
                                 cp = hp->h_name;
                 }
         }
         if (cp != NULL) {
-                (void) strncpy(dst, cp, dstlen);
-                dst[dstlen - 1] = 0;
+                (void) strlcpy(dst, cp, dstlen);
         } else {
                 (void) inet_ntop(AF_INET, (char *)&addr, dst, dstlen);
         }
+
+        append_v4_cidr_len(dst, dstlen, prefixlen);
+
         if (hp != NULL)
                 freehostent(hp);
         return (dst);
 }
 

@@ -6062,19 +6126,23 @@
         uint_t          netshifted;
         int             subnetshift;
         struct in_addr in;
         int             error_num;
         uint_t          nbo_addr = addr;        /* network byte order */
+        int             prefixlen = -1; /* -1 == Don't print prefix! */
+                                        /* -2 == Noncontiguous mask... */
 
         addr = ntohl(addr);
         mask = ntohl(mask);
         if (addr == INADDR_ANY && mask == INADDR_ANY) {
-                (void) strncpy(dst, "default", dstlen);
-                dst[dstlen - 1] = 0;
+                (void) strlcpy(dst, "default", dstlen);
                 return (dst);
         }
 
+        if (CIDRflag)
+                prefixlen = v4_cidr_len(mask);
+
         /* Figure out network portion of address (with host portion = 0) */
         if (addr) {
                 /* Try figuring out mask if unknown (all 0s). */
                 if (mask == 0) {
                         if (IN_CLASSA(addr)) {

@@ -6094,10 +6162,12 @@
                          * fields.
                          */
                         while (addr & ~mask)
                                 /* compiler doesn't sign extend! */
                                 mask = (mask | ((int)mask >> subnetshift));
+                        if (CIDRflag)
+                                prefixlen = v4_cidr_len(mask);
                 }
                 net = netshifted = addr & mask;
                 while ((mask & 1) == 0)
                         mask >>= 1, netshifted >>= 1;
         }

@@ -6122,12 +6192,12 @@
                         if (hp)
                                 cp = hp->h_name;
                 }
 
                 if (cp != NULL) {
-                        (void) strncpy(dst, cp, dstlen);
-                        dst[dstlen - 1] = 0;
+                        (void) strlcpy(dst, cp, dstlen);
+                        append_v4_cidr_len(dst, dstlen, prefixlen);
                         if (hp != NULL)
                                 freehostent(hp);
                         return (dst);
                 }
                 /*

@@ -6136,10 +6206,11 @@
                  */
         }
 
         in.s_addr = htonl(net);
         (void) inet_ntop(AF_INET, (char *)&in, dst, dstlen);
+        append_v4_cidr_len(dst, dstlen, prefixlen);
         if (hp != NULL)
                 freehostent(hp);
         return (dst);
 }