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