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

Split Close
Expand all
Collapse all
          --- old/usr/src/cmd/cmd-inet/usr.bin/netstat/netstat.c
          +++ new/usr/src/cmd/cmd-inet/usr.bin/netstat/netstat.c
↓ open down ↓ 15 lines elided ↑ open up ↑
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  /*
  22   22   * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
  23   23   * Copyright (c) 1990  Mentat Inc.
  24   24   * netstat.c 2.2, last change 9/9/91
  25   25   * MROUTING Revision 3.5
  26      - * Copyright (c) 2017, Joyent, Inc.
       26 + * Copyright 2018, Joyent, Inc.
  27   27   */
  28   28  
  29   29  /*
  30   30   * simple netstat based on snmp/mib-2 interface to the TCP/IP stack
  31   31   *
  32   32   * NOTES:
  33   33   * 1. A comment "LINTED: (note 1)" appears before certain lines where
  34   34   *    lint would have complained, "pointer cast may result in improper
  35   35   *    alignment". These are lines where lint had suspected potential
  36   36   *    improper alignment of a data structure; in each such situation
↓ open down ↓ 192 lines elided ↑ open up ↑
 229  229  
 230  230  #define PLURAL(n) plural((int)n)
 231  231  #define PLURALY(n) pluraly((int)n)
 232  232  #define PLURALES(n) plurales((int)n)
 233  233  #define IFLAGMOD(flg, val1, val2)       if (flg == val1) flg = val2
 234  234  #define MDIFF(diff, elem2, elem1, member)       (diff)->member = \
 235  235          (elem2)->member - (elem1)->member
 236  236  
 237  237  
 238  238  static  boolean_t       Aflag = B_FALSE;        /* All sockets/ifs/rtng-tbls */
      239 +static  boolean_t       CIDRflag = B_FALSE;     /* CIDR for IPv4 -i/-r addrs */
 239  240  static  boolean_t       Dflag = B_FALSE;        /* DCE info */
 240  241  static  boolean_t       Iflag = B_FALSE;        /* IP Traffic Interfaces */
 241  242  static  boolean_t       Mflag = B_FALSE;        /* STREAMS Memory Statistics */
 242  243  static  boolean_t       Nflag = B_FALSE;        /* Numeric Network Addresses */
 243  244  static  boolean_t       Rflag = B_FALSE;        /* Routing Tables */
 244  245  static  boolean_t       RSECflag = B_FALSE;     /* Security attributes */
 245  246  static  boolean_t       Sflag = B_FALSE;        /* Per-protocol Statistics */
 246  247  static  boolean_t       Vflag = B_FALSE;        /* Verbose */
 247  248  static  boolean_t       Pflag = B_FALSE;        /* Net to Media Tables */
 248  249  static  boolean_t       Gflag = B_FALSE;        /* Multicast group membership */
↓ open down ↓ 190 lines elided ↑ open up ↑
 439  440  
 440  441          v4compat = get_compat_flag(&default_ip_str);
 441  442          if (v4compat == DEFAULT_PROT_BAD_VALUE)
 442  443                  fatal(2, "%s: %s: Bad value for %s in %s\n", name,
 443  444                      default_ip_str, DEFAULT_IP, INET_DEFAULT_FILE);
 444  445          free(default_ip_str);
 445  446  
 446  447          (void) setlocale(LC_ALL, "");
 447  448          (void) textdomain(TEXT_DOMAIN);
 448  449  
 449      -        while ((c = getopt(argc, argv, "adimnrspMgvxf:P:I:DRT:")) != -1) {
      450 +        while ((c = getopt(argc, argv, "acdimnrspMgvxf:P:I:DRT:")) != -1) {
 450  451                  switch ((char)c) {
 451  452                  case 'a':               /* all connections */
 452  453                          Aflag = B_TRUE;
 453  454                          break;
 454  455  
      456 +                case 'c':
      457 +                        CIDRflag = B_TRUE;
      458 +                        break;
      459 +
 455  460                  case 'd':               /* DCE info */
 456  461                          Dflag = B_TRUE;
 457  462                          IFLAGMOD(Iflag_only, 1, 0); /* see macro def'n */
 458  463                          break;
 459  464  
 460  465                  case 'i':               /* interface (ill/ipif report) */
 461  466                          Iflag = B_TRUE;
 462  467                          IFLAGMOD(Iflag_only, -1, 1); /* '-i' exists */
 463  468                          break;
 464  469  
↓ open down ↓ 2868 lines elided ↑ open up ↑
3333 3338                  (void) putchar('\n');
3334 3339          reentry = B_TRUE;
3335 3340  }
3336 3341  
3337 3342  static void
3338 3343  if_report_ip4(mib2_ipAddrEntry_t *ap,
3339 3344      char ifname[], char logintname[], struct ifstat *statptr,
3340 3345      boolean_t ksp_not_null)
3341 3346  {
3342 3347  
3343      -        char abuf[MAXHOSTNAMELEN + 1];
     3348 +        char abuf[MAXHOSTNAMELEN + 4];  /* Include /<num> for CIDR-printing. */
3344 3349          char dstbuf[MAXHOSTNAMELEN + 1];
3345 3350  
3346 3351          if (ksp_not_null) {
3347 3352                  (void) printf("%-5s %-4u ",
3348 3353                      ifname, ap->ipAdEntInfo.ae_mtu);
3349 3354                  if (ap->ipAdEntInfo.ae_flags & IFF_POINTOPOINT)
3350 3355                          (void) pr_addr(ap->ipAdEntInfo.ae_pp_dst_addr,
3351 3356                              abuf, sizeof (abuf));
3352 3357                  else
3353 3358                          (void) pr_netaddr(ap->ipAdEntAddr,
↓ open down ↓ 1078 lines elided ↑ open up ↑
4432 4437  
4433 4438  static const char ire_hdr_v4_normal[] =
4434 4439  "  Destination           Gateway           Flags  Ref     Use     Interface"
4435 4440  " %s\n-------------------- -------------------- ----- ----- ---------- "
4436 4441  "--------- %s\n";
4437 4442  
4438 4443  static boolean_t
4439 4444  ire_report_item_v4(const mib2_ipRouteEntry_t *rp, boolean_t first,
4440 4445      const sec_attr_list_t *attrs)
4441 4446  {
4442      -        char                    dstbuf[MAXHOSTNAMELEN + 1];
     4447 +        char                    dstbuf[MAXHOSTNAMELEN + 4]; /* + "/<num>" */
4443 4448          char                    maskbuf[MAXHOSTNAMELEN + 1];
4444 4449          char                    gwbuf[MAXHOSTNAMELEN + 1];
4445 4450          char                    ifname[LIFNAMSIZ + 1];
4446 4451          char                    flags[10];      /* RTF_ flags */
4447 4452          uint_t                  flag_b;
4448 4453  
4449 4454          if (!(Aflag || (rp->ipRouteInfo.re_ire_type != IRE_IF_CLONE &&
4450 4455              rp->ipRouteInfo.re_ire_type != IRE_BROADCAST &&
4451 4456              rp->ipRouteInfo.re_ire_type != IRE_MULTICAST &&
4452 4457              rp->ipRouteInfo.re_ire_type != IRE_NOROUTE &&
↓ open down ↓ 1097 lines elided ↑ open up ↑
5550 5555  
5551 5556  static void
5552 5557  mrt_report(mib_item_t *item)
5553 5558  {
5554 5559          int             jtemp = 0;
5555 5560          struct vifctl   *vip;
5556 5561          vifi_t          vifi;
5557 5562          struct mfcctl   *mfccp;
5558 5563          int             numvifs = 0;
5559 5564          int             nmfc = 0;
5560      -        char            abuf[MAXHOSTNAMELEN + 1];
     5565 +        char            abuf[MAXHOSTNAMELEN + 4]; /* Include CIDR /<num>. */
5561 5566  
5562 5567          if (!(family_selected(AF_INET)))
5563 5568                  return;
5564 5569  
5565 5570          /* 'for' loop 1: */
5566 5571          for (; item; item = item->next_item) {
5567 5572                  if (Xflag) {
5568 5573                          (void) printf("\n--- Entry %d ---\n", ++jtemp);
5569 5574                          (void) printf("Group = %d, mib_id = %d, "
5570 5575                              "length = %d, valp = 0x%p\n",
↓ open down ↓ 398 lines elided ↑ open up ↑
5969 5974          if (dst + dstlen + 1 > cp) {
5970 5975                  *cp++ = '.';
5971 5976                  dstlen -= (cp - dst);
5972 5977                  dstlen--;
5973 5978                  (void) portname(port, proto, cp, dstlen);
5974 5979          }
5975 5980          return (dst);
5976 5981  }
5977 5982  
5978 5983  /*
     5984 + * Returns -2 to indicate a discontiguous mask.  Otherwise returns between
     5985 + * 0 and 32.
     5986 + */
     5987 +static int
     5988 +v4_cidr_len(uint_t mask)
     5989 +{
     5990 +        int rc = 0;
     5991 +        int i;
     5992 +
     5993 +        for (i = 0; i < 32; i++) {
     5994 +                if (mask & 0x1)
     5995 +                        rc++;
     5996 +                else if (rc > 0)
     5997 +                        return (-2);    /* Discontiguous IPv4 netmask. */
     5998 +
     5999 +                mask >>= 1;
     6000 +        }
     6001 +
     6002 +        return (rc);
     6003 +}
     6004 +
     6005 +static void
     6006 +append_v4_cidr_len(char *dst, uint_t dstlen, int prefixlen)
     6007 +{
     6008 +        char *prefixptr;
     6009 +
     6010 +        /* 4 bytes leaves room for '/' 'N' 'N' '\0' */
     6011 +        if (strlen(dst) <= dstlen - 4) {
     6012 +                prefixptr = dst + strlen(dst);
     6013 +        } else {
     6014 +                /*
     6015 +                 * Cut off last 3 chars of very-long DNS name.  All callers
     6016 +                 * should give us enough room, but name services COULD give us
     6017 +                 * a way-too-big name (see above).
     6018 +                 */
     6019 +                prefixptr = dst + strlen(dst) - 3;
     6020 +        }
     6021 +        /* At this point "prefixptr" is guaranteed to point to 4 bytes. */
     6022 +
     6023 +        if (prefixlen >= 0) {
     6024 +                if (prefixlen > 32)     /* Shouldn't happen, but... */
     6025 +                        prefixlen = 32;
     6026 +                (void) snprintf(prefixptr, 4, "/%d", prefixlen);
     6027 +        } else if (prefixlen == -2) {
     6028 +                /* "/NM" == Noncontiguous Mask. */
     6029 +                (void) strcat(prefixptr, "/NM");
     6030 +        }
     6031 +        /* Else print nothing extra. */
     6032 +}
     6033 +
     6034 +/*
5979 6035   * Return the name of the network whose address is given. The address is
5980 6036   * assumed to be that of a net or subnet, not a host.
5981 6037   */
5982 6038  static char *
5983 6039  pr_net(uint_t addr, uint_t mask, char *dst, uint_t dstlen)
5984 6040  {
5985 6041          char            *cp = NULL;
5986 6042          struct netent   *np = NULL;
5987 6043          struct hostent  *hp = NULL;
5988 6044          uint_t          net;
5989 6045          int             subnetshift;
5990 6046          int             error_num;
     6047 +        int             prefixlen = -1; /* -1 == Don't print prefix! */
     6048 +                                        /* -2 == Noncontiguous mask... */
5991 6049  
5992 6050          if (addr == INADDR_ANY && mask == INADDR_ANY) {
5993      -                (void) strncpy(dst, "default", dstlen);
5994      -                dst[dstlen - 1] = 0;
     6051 +                (void) strlcpy(dst, "default", dstlen);
5995 6052                  return (dst);
5996 6053          }
5997 6054  
     6055 +        if (CIDRflag)
     6056 +                prefixlen = v4_cidr_len(ntohl(mask));
     6057 +
5998 6058          if (!Nflag && addr) {
5999 6059                  if (mask == 0) {
6000 6060                          if (IN_CLASSA(addr)) {
6001 6061                                  mask = (uint_t)IN_CLASSA_NET;
6002 6062                                  subnetshift = 8;
6003 6063                          } else if (IN_CLASSB(addr)) {
6004 6064                                  mask = (uint_t)IN_CLASSB_NET;
6005 6065                                  subnetshift = 8;
6006 6066                          } else {
6007 6067                                  mask = (uint_t)IN_CLASSC_NET;
↓ open down ↓ 1 lines elided ↑ open up ↑
6009 6069                          }
6010 6070                          /*
6011 6071                           * If there are more bits than the standard mask
6012 6072                           * would suggest, subnets must be in use. Guess at
6013 6073                           * the subnet mask, assuming reasonable width subnet
6014 6074                           * fields.
6015 6075                           */
6016 6076                          while (addr & ~mask)
6017 6077                                  /* compiler doesn't sign extend! */
6018 6078                                  mask = (mask | ((int)mask >> subnetshift));
     6079 +                        if (CIDRflag)
     6080 +                                prefixlen = v4_cidr_len(mask);
6019 6081                  }
6020 6082                  net = addr & mask;
6021 6083                  while ((mask & 1) == 0)
6022 6084                          mask >>= 1, net >>= 1;
6023 6085                  ns_lookup_start();
6024 6086                  np = getnetbyaddr(net, AF_INET);
6025 6087                  ns_lookup_end();
6026 6088                  if (np && np->n_net == net)
6027 6089                          cp = np->n_name;
6028 6090                  else {
↓ open down ↓ 2 lines elided ↑ open up ↑
6031 6093                           */
6032 6094                          ns_lookup_start();
6033 6095                          hp = getipnodebyaddr((char *)&addr, sizeof (uint_t),
6034 6096                              AF_INET, &error_num);
6035 6097                          ns_lookup_end();
6036 6098                          if (hp)
6037 6099                                  cp = hp->h_name;
6038 6100                  }
6039 6101          }
6040 6102          if (cp != NULL) {
6041      -                (void) strncpy(dst, cp, dstlen);
6042      -                dst[dstlen - 1] = 0;
     6103 +                (void) strlcpy(dst, cp, dstlen);
6043 6104          } else {
6044 6105                  (void) inet_ntop(AF_INET, (char *)&addr, dst, dstlen);
6045 6106          }
     6107 +
     6108 +        append_v4_cidr_len(dst, dstlen, prefixlen);
     6109 +
6046 6110          if (hp != NULL)
6047 6111                  freehostent(hp);
6048 6112          return (dst);
6049 6113  }
6050 6114  
6051 6115  /*
6052 6116   * Return the name of the network whose address is given.
6053 6117   * The address is assumed to be a host address.
6054 6118   */
6055 6119  static char *
↓ open down ↓ 1 lines elided ↑ open up ↑
6057 6121  {
6058 6122          char            *cp = NULL;
6059 6123          struct netent   *np = NULL;
6060 6124          struct hostent  *hp = NULL;
6061 6125          uint_t          net;
6062 6126          uint_t          netshifted;
6063 6127          int             subnetshift;
6064 6128          struct in_addr in;
6065 6129          int             error_num;
6066 6130          uint_t          nbo_addr = addr;        /* network byte order */
     6131 +        int             prefixlen = -1; /* -1 == Don't print prefix! */
     6132 +                                        /* -2 == Noncontiguous mask... */
6067 6133  
6068 6134          addr = ntohl(addr);
6069 6135          mask = ntohl(mask);
6070 6136          if (addr == INADDR_ANY && mask == INADDR_ANY) {
6071      -                (void) strncpy(dst, "default", dstlen);
6072      -                dst[dstlen - 1] = 0;
     6137 +                (void) strlcpy(dst, "default", dstlen);
6073 6138                  return (dst);
6074 6139          }
6075 6140  
     6141 +        if (CIDRflag)
     6142 +                prefixlen = v4_cidr_len(mask);
     6143 +
6076 6144          /* Figure out network portion of address (with host portion = 0) */
6077 6145          if (addr) {
6078 6146                  /* Try figuring out mask if unknown (all 0s). */
6079 6147                  if (mask == 0) {
6080 6148                          if (IN_CLASSA(addr)) {
6081 6149                                  mask = (uint_t)IN_CLASSA_NET;
6082 6150                                  subnetshift = 8;
6083 6151                          } else if (IN_CLASSB(addr)) {
6084 6152                                  mask = (uint_t)IN_CLASSB_NET;
6085 6153                                  subnetshift = 8;
↓ open down ↓ 3 lines elided ↑ open up ↑
6089 6157                          }
6090 6158                          /*
6091 6159                           * If there are more bits than the standard mask
6092 6160                           * would suggest, subnets must be in use. Guess at
6093 6161                           * the subnet mask, assuming reasonable width subnet
6094 6162                           * fields.
6095 6163                           */
6096 6164                          while (addr & ~mask)
6097 6165                                  /* compiler doesn't sign extend! */
6098 6166                                  mask = (mask | ((int)mask >> subnetshift));
     6167 +                        if (CIDRflag)
     6168 +                                prefixlen = v4_cidr_len(mask);
6099 6169                  }
6100 6170                  net = netshifted = addr & mask;
6101 6171                  while ((mask & 1) == 0)
6102 6172                          mask >>= 1, netshifted >>= 1;
6103 6173          }
6104 6174          else
6105 6175                  net = netshifted = 0;
6106 6176  
6107 6177          /* Try looking up name unless -n was specified. */
6108 6178          if (!Nflag) {
↓ open down ↓ 8 lines elided ↑ open up ↑
6117 6187                           */
6118 6188                          ns_lookup_start();
6119 6189                          hp = getipnodebyaddr((char *)&nbo_addr, sizeof (uint_t),
6120 6190                              AF_INET, &error_num);
6121 6191                          ns_lookup_end();
6122 6192                          if (hp)
6123 6193                                  cp = hp->h_name;
6124 6194                  }
6125 6195  
6126 6196                  if (cp != NULL) {
6127      -                        (void) strncpy(dst, cp, dstlen);
6128      -                        dst[dstlen - 1] = 0;
     6197 +                        (void) strlcpy(dst, cp, dstlen);
     6198 +                        append_v4_cidr_len(dst, dstlen, prefixlen);
6129 6199                          if (hp != NULL)
6130 6200                                  freehostent(hp);
6131 6201                          return (dst);
6132 6202                  }
6133 6203                  /*
6134 6204                   * No name found for net: fallthru and return in decimal
6135 6205                   * dot notation.
6136 6206                   */
6137 6207          }
6138 6208  
6139 6209          in.s_addr = htonl(net);
6140 6210          (void) inet_ntop(AF_INET, (char *)&in, dst, dstlen);
     6211 +        append_v4_cidr_len(dst, dstlen, prefixlen);
6141 6212          if (hp != NULL)
6142 6213                  freehostent(hp);
6143 6214          return (dst);
6144 6215  }
6145 6216  
6146 6217  /*
6147 6218   * Return the filter mode as a string:
6148 6219   *      1 => "INCLUDE"
6149 6220   *      2 => "EXCLUDE"
6150 6221   *      otherwise "<unknown>"
↓ open down ↓ 393 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX