--- old/usr/src/cmd/cmd-inet/usr.bin/netstat/netstat.c	Mon Mar 26 09:12:46 2018
+++ new/usr/src/cmd/cmd-inet/usr.bin/netstat/netstat.c	Mon Mar 26 09:12:46 2018
@@ -23,7 +23,7 @@
  * 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.
  */
 
 /*
@@ -236,6 +236,7 @@
 
 
 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 */
@@ -446,12 +447,16 @@
 	(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 */
@@ -3340,7 +3345,7 @@
     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) {
@@ -4439,7 +4444,7 @@
 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];
@@ -5557,7 +5562,7 @@
 	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;
@@ -5976,6 +5981,57 @@
 }
 
 /*
+ * 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.
  */
@@ -5988,13 +6044,17 @@
 	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)) {
@@ -6016,6 +6076,8 @@
 			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)
@@ -6038,11 +6100,13 @@
 		}
 	}
 	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);
@@ -6064,15 +6128,19 @@
 	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). */
@@ -6096,6 +6164,8 @@
 			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)
@@ -6124,8 +6194,8 @@
 		}
 
 		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);
@@ -6138,6 +6208,7 @@
 
 	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);
--- old/usr/src/man/man1m/netstat.1m	Mon Mar 26 09:12:47 2018
+++ new/usr/src/man/man1m/netstat.1m	Mon Mar 26 09:12:47 2018
@@ -1,4 +1,5 @@
 '\" te
+.\" Copyright 2018, Joyent, Inc.
 .\" Copyright (C) 2002, Sun Microsystems, Inc. All Rights Reserved
 .\" Copyright 1989 AT&T
 .\" Copyright (c) 1983 Regents of the University of California. All rights reserved. The Berkeley software License Agreement specifies the terms and conditions for redistribution.
@@ -34,18 +35,18 @@
 
 .LP
 .nf
-\fBnetstat\fR \fB-i\fR [\fB-I\fR \fIinterface\fR] [\fB-an\fR] [\fB-f\fR \fIaddress_family\fR]
+\fBnetstat\fR \fB-i\fR [\fB-I\fR \fIinterface\fR] [\fB-acn\fR] [\fB-f\fR \fIaddress_family\fR]
      [\fB-T\fR u | d ] [\fIinterval\fR [\fIcount\fR]]
 .fi
 
 .LP
 .nf
-\fBnetstat\fR \fB-r\fR [\fB-anvR\fR] [\fB-f\fR \fIaddress_family\fR | \fIfilter\fR]
+\fBnetstat\fR \fB-r\fR [\fB-acnvR\fR] [\fB-f\fR \fIaddress_family\fR | \fIfilter\fR]
 .fi
 
 .LP
 .nf
-\fBnetstat\fR \fB-M\fR [\fB-ns\fR] [\fB-f\fR \fIaddress_family\fR]
+\fBnetstat\fR \fB-M\fR [\fB-cns\fR] [\fB-f\fR \fIaddress_family\fR]
 .fi
 
 .LP
@@ -124,6 +125,19 @@
 default routes are shown and only the status of physical interfaces is shown.
 .RE
 
+.sp
+.ne 2
+.na
+\fB\fB-c\fR\fR
+.ad
+.sp .6
+.RS 4n
+Print IPv4 networks using CIDR (x.y.z.a/NN) notation with the \fB-i\fR,
+\fB-r\fR, and \fB-M\fR options. IPv6 networks default to this, but due to
+backward compatibility, IPv4 ones do not without this flag.  A noncontiguous
+IPv4 netmask will print "/NM" if this flag is enabled.
+.RE
+
 .sp
 .ne 2
 .na
