6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright (c) 1990 Mentat Inc.
24 * netstat.c 2.2, last change 9/9/91
25 * MROUTING Revision 3.5
26 * Copyright (c) 2017, Joyent, Inc.
27 */
28
29 /*
30 * simple netstat based on snmp/mib-2 interface to the TCP/IP stack
31 *
32 * NOTES:
33 * 1. A comment "LINTED: (note 1)" appears before certain lines where
34 * lint would have complained, "pointer cast may result in improper
35 * alignment". These are lines where lint had suspected potential
36 * improper alignment of a data structure; in each such situation
37 * we have relied on the kernel guaranteeing proper alignment.
38 * 2. Some 'for' loops have been commented as "'for' loop 1", etc
39 * because they have 'continue' or 'break' statements in their
40 * bodies. 'continue' statements have been used inside some loops
41 * where avoiding them would have led to deep levels of indentation.
42 *
43 * TODO:
44 * Add ability to request subsets from kernel (with level = MIB2_IP;
45 * name = 0 meaning everything for compatibility)
46 */
219 static int isnum(char *);
220 static char *plural(int n);
221 static char *pluraly(int n);
222 static char *plurales(int n);
223 static void process_filter(char *arg);
224 static char *ifindex2str(uint_t, char *);
225 static boolean_t family_selected(int family);
226
227 static void usage(char *);
228 static void fatal(int errcode, char *str1, ...);
229
230 #define PLURAL(n) plural((int)n)
231 #define PLURALY(n) pluraly((int)n)
232 #define PLURALES(n) plurales((int)n)
233 #define IFLAGMOD(flg, val1, val2) if (flg == val1) flg = val2
234 #define MDIFF(diff, elem2, elem1, member) (diff)->member = \
235 (elem2)->member - (elem1)->member
236
237
238 static boolean_t Aflag = B_FALSE; /* All sockets/ifs/rtng-tbls */
239 static boolean_t Dflag = B_FALSE; /* DCE info */
240 static boolean_t Iflag = B_FALSE; /* IP Traffic Interfaces */
241 static boolean_t Mflag = B_FALSE; /* STREAMS Memory Statistics */
242 static boolean_t Nflag = B_FALSE; /* Numeric Network Addresses */
243 static boolean_t Rflag = B_FALSE; /* Routing Tables */
244 static boolean_t RSECflag = B_FALSE; /* Security attributes */
245 static boolean_t Sflag = B_FALSE; /* Per-protocol Statistics */
246 static boolean_t Vflag = B_FALSE; /* Verbose */
247 static boolean_t Pflag = B_FALSE; /* Net to Media Tables */
248 static boolean_t Gflag = B_FALSE; /* Multicast group membership */
249 static boolean_t MMflag = B_FALSE; /* Multicast routing table */
250 static boolean_t DHCPflag = B_FALSE; /* DHCP statistics */
251 static boolean_t Xflag = B_FALSE; /* Debug Info */
252
253 static int v4compat = 0; /* Compatible printing format for status */
254
255 static int proto = IPPROTO_MAX; /* all protocols */
256 kstat_ctl_t *kc = NULL;
257
258 /*
429 * 1, IFlag is the only feature-flag enabled
430 * : trinary variable, modified using IFLAGMOD()
431 */
432 int Iflag_only = -1;
433 boolean_t once_only = B_FALSE; /* '-i' with count > 1 */
434 extern char *optarg;
435 extern int optind;
436 char *default_ip_str = NULL;
437
438 name = argv[0];
439
440 v4compat = get_compat_flag(&default_ip_str);
441 if (v4compat == DEFAULT_PROT_BAD_VALUE)
442 fatal(2, "%s: %s: Bad value for %s in %s\n", name,
443 default_ip_str, DEFAULT_IP, INET_DEFAULT_FILE);
444 free(default_ip_str);
445
446 (void) setlocale(LC_ALL, "");
447 (void) textdomain(TEXT_DOMAIN);
448
449 while ((c = getopt(argc, argv, "adimnrspMgvxf:P:I:DRT:")) != -1) {
450 switch ((char)c) {
451 case 'a': /* all connections */
452 Aflag = B_TRUE;
453 break;
454
455 case 'd': /* DCE info */
456 Dflag = B_TRUE;
457 IFLAGMOD(Iflag_only, 1, 0); /* see macro def'n */
458 break;
459
460 case 'i': /* interface (ill/ipif report) */
461 Iflag = B_TRUE;
462 IFLAGMOD(Iflag_only, -1, 1); /* '-i' exists */
463 break;
464
465 case 'm': /* streams msg report */
466 Mflag = B_TRUE;
467 IFLAGMOD(Iflag_only, 1, 0); /* see macro def'n */
468 break;
469
470 case 'n': /* numeric format */
471 Nflag = B_TRUE;
472 break;
473
474 case 'r': /* route tables */
3323 free(cleanlist);
3324 cleanlist = tlp;
3325 }
3326 }
3327 break;
3328 }
3329 }
3330 (void) fflush(stdout);
3331 } /* 'for' loop 1 ends */
3332 if ((Iflag_only == 0) && (!once_only))
3333 (void) putchar('\n');
3334 reentry = B_TRUE;
3335 }
3336
3337 static void
3338 if_report_ip4(mib2_ipAddrEntry_t *ap,
3339 char ifname[], char logintname[], struct ifstat *statptr,
3340 boolean_t ksp_not_null)
3341 {
3342
3343 char abuf[MAXHOSTNAMELEN + 1];
3344 char dstbuf[MAXHOSTNAMELEN + 1];
3345
3346 if (ksp_not_null) {
3347 (void) printf("%-5s %-4u ",
3348 ifname, ap->ipAdEntInfo.ae_mtu);
3349 if (ap->ipAdEntInfo.ae_flags & IFF_POINTOPOINT)
3350 (void) pr_addr(ap->ipAdEntInfo.ae_pp_dst_addr,
3351 abuf, sizeof (abuf));
3352 else
3353 (void) pr_netaddr(ap->ipAdEntAddr,
3354 ap->ipAdEntNetMask, abuf, sizeof (abuf));
3355 (void) printf("%-13s %-14s %-6llu %-5llu %-6llu %-5llu "
3356 "%-6llu %-6llu\n",
3357 abuf, pr_addr(ap->ipAdEntAddr, dstbuf, sizeof (dstbuf)),
3358 statptr->ipackets, statptr->ierrors,
3359 statptr->opackets, statptr->oerrors,
3360 statptr->collisions, 0LL);
3361 }
3362 /*
3363 * Print logical interface info if Aflag set (including logical unit 0)
4422
4423 static const char ire_hdr_v4[] =
4424 "\n%s Table: IPv4\n";
4425 static const char ire_hdr_v4_compat[] =
4426 "\n%s Table:\n";
4427 static const char ire_hdr_v4_verbose[] =
4428 " Destination Mask Gateway Device "
4429 " MTU Ref Flg Out In/Fwd %s\n"
4430 "-------------------- --------------- -------------------- ------ "
4431 "----- --- --- ----- ------ %s\n";
4432
4433 static const char ire_hdr_v4_normal[] =
4434 " Destination Gateway Flags Ref Use Interface"
4435 " %s\n-------------------- -------------------- ----- ----- ---------- "
4436 "--------- %s\n";
4437
4438 static boolean_t
4439 ire_report_item_v4(const mib2_ipRouteEntry_t *rp, boolean_t first,
4440 const sec_attr_list_t *attrs)
4441 {
4442 char dstbuf[MAXHOSTNAMELEN + 1];
4443 char maskbuf[MAXHOSTNAMELEN + 1];
4444 char gwbuf[MAXHOSTNAMELEN + 1];
4445 char ifname[LIFNAMSIZ + 1];
4446 char flags[10]; /* RTF_ flags */
4447 uint_t flag_b;
4448
4449 if (!(Aflag || (rp->ipRouteInfo.re_ire_type != IRE_IF_CLONE &&
4450 rp->ipRouteInfo.re_ire_type != IRE_BROADCAST &&
4451 rp->ipRouteInfo.re_ire_type != IRE_MULTICAST &&
4452 rp->ipRouteInfo.re_ire_type != IRE_NOROUTE &&
4453 rp->ipRouteInfo.re_ire_type != IRE_LOCAL))) {
4454 return (first);
4455 }
4456
4457 flag_b = form_v4_route_flags(rp, flags);
4458
4459 if (!ire_filter_match_v4(rp, flag_b))
4460 return (first);
4461
4462 if (first) {
5540 } else {
5541 t = 'g';
5542 n /= 1024 * 1024 * 1024;
5543 }
5544
5545 (void) snprintf(buf, sizeof (buf), "%4u%c", n, t);
5546 return (buf);
5547 }
5548
5549 /* --------------------- mrt_report (netstat -m) -------------------------- */
5550
5551 static void
5552 mrt_report(mib_item_t *item)
5553 {
5554 int jtemp = 0;
5555 struct vifctl *vip;
5556 vifi_t vifi;
5557 struct mfcctl *mfccp;
5558 int numvifs = 0;
5559 int nmfc = 0;
5560 char abuf[MAXHOSTNAMELEN + 1];
5561
5562 if (!(family_selected(AF_INET)))
5563 return;
5564
5565 /* 'for' loop 1: */
5566 for (; item; item = item->next_item) {
5567 if (Xflag) {
5568 (void) printf("\n--- Entry %d ---\n", ++jtemp);
5569 (void) printf("Group = %d, mib_id = %d, "
5570 "length = %d, valp = 0x%p\n",
5571 item->group, item->mib_id, item->length,
5572 item->valp);
5573 }
5574 if (item->group != EXPER_DVMRP)
5575 continue; /* 'for' loop 1 */
5576
5577 switch (item->mib_id) {
5578
5579 case EXPER_DVMRP_VIF:
5580 if (Xflag)
5959 char *cp;
5960
5961 if (IN6_IS_ADDR_UNSPECIFIED(addr)) {
5962 (void) strncpy(dst, " *", dstlen);
5963 dst[dstlen - 1] = 0;
5964 } else {
5965 (void) pr_addr6(addr, dst, dstlen);
5966 }
5967 /* How much room is left? */
5968 cp = strchr(dst, '\0');
5969 if (dst + dstlen + 1 > cp) {
5970 *cp++ = '.';
5971 dstlen -= (cp - dst);
5972 dstlen--;
5973 (void) portname(port, proto, cp, dstlen);
5974 }
5975 return (dst);
5976 }
5977
5978 /*
5979 * Return the name of the network whose address is given. The address is
5980 * assumed to be that of a net or subnet, not a host.
5981 */
5982 static char *
5983 pr_net(uint_t addr, uint_t mask, char *dst, uint_t dstlen)
5984 {
5985 char *cp = NULL;
5986 struct netent *np = NULL;
5987 struct hostent *hp = NULL;
5988 uint_t net;
5989 int subnetshift;
5990 int error_num;
5991
5992 if (addr == INADDR_ANY && mask == INADDR_ANY) {
5993 (void) strncpy(dst, "default", dstlen);
5994 dst[dstlen - 1] = 0;
5995 return (dst);
5996 }
5997
5998 if (!Nflag && addr) {
5999 if (mask == 0) {
6000 if (IN_CLASSA(addr)) {
6001 mask = (uint_t)IN_CLASSA_NET;
6002 subnetshift = 8;
6003 } else if (IN_CLASSB(addr)) {
6004 mask = (uint_t)IN_CLASSB_NET;
6005 subnetshift = 8;
6006 } else {
6007 mask = (uint_t)IN_CLASSC_NET;
6008 subnetshift = 4;
6009 }
6010 /*
6011 * If there are more bits than the standard mask
6012 * would suggest, subnets must be in use. Guess at
6013 * the subnet mask, assuming reasonable width subnet
6014 * fields.
6015 */
6016 while (addr & ~mask)
6017 /* compiler doesn't sign extend! */
6018 mask = (mask | ((int)mask >> subnetshift));
6019 }
6020 net = addr & mask;
6021 while ((mask & 1) == 0)
6022 mask >>= 1, net >>= 1;
6023 ns_lookup_start();
6024 np = getnetbyaddr(net, AF_INET);
6025 ns_lookup_end();
6026 if (np && np->n_net == net)
6027 cp = np->n_name;
6028 else {
6029 /*
6030 * Look for subnets in hosts map.
6031 */
6032 ns_lookup_start();
6033 hp = getipnodebyaddr((char *)&addr, sizeof (uint_t),
6034 AF_INET, &error_num);
6035 ns_lookup_end();
6036 if (hp)
6037 cp = hp->h_name;
6038 }
6039 }
6040 if (cp != NULL) {
6041 (void) strncpy(dst, cp, dstlen);
6042 dst[dstlen - 1] = 0;
6043 } else {
6044 (void) inet_ntop(AF_INET, (char *)&addr, dst, dstlen);
6045 }
6046 if (hp != NULL)
6047 freehostent(hp);
6048 return (dst);
6049 }
6050
6051 /*
6052 * Return the name of the network whose address is given.
6053 * The address is assumed to be a host address.
6054 */
6055 static char *
6056 pr_netaddr(uint_t addr, uint_t mask, char *dst, uint_t dstlen)
6057 {
6058 char *cp = NULL;
6059 struct netent *np = NULL;
6060 struct hostent *hp = NULL;
6061 uint_t net;
6062 uint_t netshifted;
6063 int subnetshift;
6064 struct in_addr in;
6065 int error_num;
6066 uint_t nbo_addr = addr; /* network byte order */
6067
6068 addr = ntohl(addr);
6069 mask = ntohl(mask);
6070 if (addr == INADDR_ANY && mask == INADDR_ANY) {
6071 (void) strncpy(dst, "default", dstlen);
6072 dst[dstlen - 1] = 0;
6073 return (dst);
6074 }
6075
6076 /* Figure out network portion of address (with host portion = 0) */
6077 if (addr) {
6078 /* Try figuring out mask if unknown (all 0s). */
6079 if (mask == 0) {
6080 if (IN_CLASSA(addr)) {
6081 mask = (uint_t)IN_CLASSA_NET;
6082 subnetshift = 8;
6083 } else if (IN_CLASSB(addr)) {
6084 mask = (uint_t)IN_CLASSB_NET;
6085 subnetshift = 8;
6086 } else {
6087 mask = (uint_t)IN_CLASSC_NET;
6088 subnetshift = 4;
6089 }
6090 /*
6091 * If there are more bits than the standard mask
6092 * would suggest, subnets must be in use. Guess at
6093 * the subnet mask, assuming reasonable width subnet
6094 * fields.
6095 */
6096 while (addr & ~mask)
6097 /* compiler doesn't sign extend! */
6098 mask = (mask | ((int)mask >> subnetshift));
6099 }
6100 net = netshifted = addr & mask;
6101 while ((mask & 1) == 0)
6102 mask >>= 1, netshifted >>= 1;
6103 }
6104 else
6105 net = netshifted = 0;
6106
6107 /* Try looking up name unless -n was specified. */
6108 if (!Nflag) {
6109 ns_lookup_start();
6110 np = getnetbyaddr(netshifted, AF_INET);
6111 ns_lookup_end();
6112 if (np && np->n_net == netshifted)
6113 cp = np->n_name;
6114 else {
6115 /*
6116 * Look for subnets in hosts map.
6117 */
6118 ns_lookup_start();
6119 hp = getipnodebyaddr((char *)&nbo_addr, sizeof (uint_t),
6120 AF_INET, &error_num);
6121 ns_lookup_end();
6122 if (hp)
6123 cp = hp->h_name;
6124 }
6125
6126 if (cp != NULL) {
6127 (void) strncpy(dst, cp, dstlen);
6128 dst[dstlen - 1] = 0;
6129 if (hp != NULL)
6130 freehostent(hp);
6131 return (dst);
6132 }
6133 /*
6134 * No name found for net: fallthru and return in decimal
6135 * dot notation.
6136 */
6137 }
6138
6139 in.s_addr = htonl(net);
6140 (void) inet_ntop(AF_INET, (char *)&in, dst, dstlen);
6141 if (hp != NULL)
6142 freehostent(hp);
6143 return (dst);
6144 }
6145
6146 /*
6147 * Return the filter mode as a string:
6148 * 1 => "INCLUDE"
6149 * 2 => "EXCLUDE"
6150 * otherwise "<unknown>"
6151 */
6152 static char *
6153 fmodestr(uint_t fmode)
6154 {
6155 switch (fmode) {
6156 case 1:
6157 return ("INCLUDE");
6158 case 2:
6159 return ("EXCLUDE");
6160 default:
|
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright (c) 1990 Mentat Inc.
24 * netstat.c 2.2, last change 9/9/91
25 * MROUTING Revision 3.5
26 * Copyright 2018, Joyent, Inc.
27 */
28
29 /*
30 * simple netstat based on snmp/mib-2 interface to the TCP/IP stack
31 *
32 * NOTES:
33 * 1. A comment "LINTED: (note 1)" appears before certain lines where
34 * lint would have complained, "pointer cast may result in improper
35 * alignment". These are lines where lint had suspected potential
36 * improper alignment of a data structure; in each such situation
37 * we have relied on the kernel guaranteeing proper alignment.
38 * 2. Some 'for' loops have been commented as "'for' loop 1", etc
39 * because they have 'continue' or 'break' statements in their
40 * bodies. 'continue' statements have been used inside some loops
41 * where avoiding them would have led to deep levels of indentation.
42 *
43 * TODO:
44 * Add ability to request subsets from kernel (with level = MIB2_IP;
45 * name = 0 meaning everything for compatibility)
46 */
219 static int isnum(char *);
220 static char *plural(int n);
221 static char *pluraly(int n);
222 static char *plurales(int n);
223 static void process_filter(char *arg);
224 static char *ifindex2str(uint_t, char *);
225 static boolean_t family_selected(int family);
226
227 static void usage(char *);
228 static void fatal(int errcode, char *str1, ...);
229
230 #define PLURAL(n) plural((int)n)
231 #define PLURALY(n) pluraly((int)n)
232 #define PLURALES(n) plurales((int)n)
233 #define IFLAGMOD(flg, val1, val2) if (flg == val1) flg = val2
234 #define MDIFF(diff, elem2, elem1, member) (diff)->member = \
235 (elem2)->member - (elem1)->member
236
237
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 */
240 static boolean_t Dflag = B_FALSE; /* DCE info */
241 static boolean_t Iflag = B_FALSE; /* IP Traffic Interfaces */
242 static boolean_t Mflag = B_FALSE; /* STREAMS Memory Statistics */
243 static boolean_t Nflag = B_FALSE; /* Numeric Network Addresses */
244 static boolean_t Rflag = B_FALSE; /* Routing Tables */
245 static boolean_t RSECflag = B_FALSE; /* Security attributes */
246 static boolean_t Sflag = B_FALSE; /* Per-protocol Statistics */
247 static boolean_t Vflag = B_FALSE; /* Verbose */
248 static boolean_t Pflag = B_FALSE; /* Net to Media Tables */
249 static boolean_t Gflag = B_FALSE; /* Multicast group membership */
250 static boolean_t MMflag = B_FALSE; /* Multicast routing table */
251 static boolean_t DHCPflag = B_FALSE; /* DHCP statistics */
252 static boolean_t Xflag = B_FALSE; /* Debug Info */
253
254 static int v4compat = 0; /* Compatible printing format for status */
255
256 static int proto = IPPROTO_MAX; /* all protocols */
257 kstat_ctl_t *kc = NULL;
258
259 /*
430 * 1, IFlag is the only feature-flag enabled
431 * : trinary variable, modified using IFLAGMOD()
432 */
433 int Iflag_only = -1;
434 boolean_t once_only = B_FALSE; /* '-i' with count > 1 */
435 extern char *optarg;
436 extern int optind;
437 char *default_ip_str = NULL;
438
439 name = argv[0];
440
441 v4compat = get_compat_flag(&default_ip_str);
442 if (v4compat == DEFAULT_PROT_BAD_VALUE)
443 fatal(2, "%s: %s: Bad value for %s in %s\n", name,
444 default_ip_str, DEFAULT_IP, INET_DEFAULT_FILE);
445 free(default_ip_str);
446
447 (void) setlocale(LC_ALL, "");
448 (void) textdomain(TEXT_DOMAIN);
449
450 while ((c = getopt(argc, argv, "acdimnrspMgvxf:P:I:DRT:")) != -1) {
451 switch ((char)c) {
452 case 'a': /* all connections */
453 Aflag = B_TRUE;
454 break;
455
456 case 'c':
457 CIDRflag = B_TRUE;
458 break;
459
460 case 'd': /* DCE info */
461 Dflag = B_TRUE;
462 IFLAGMOD(Iflag_only, 1, 0); /* see macro def'n */
463 break;
464
465 case 'i': /* interface (ill/ipif report) */
466 Iflag = B_TRUE;
467 IFLAGMOD(Iflag_only, -1, 1); /* '-i' exists */
468 break;
469
470 case 'm': /* streams msg report */
471 Mflag = B_TRUE;
472 IFLAGMOD(Iflag_only, 1, 0); /* see macro def'n */
473 break;
474
475 case 'n': /* numeric format */
476 Nflag = B_TRUE;
477 break;
478
479 case 'r': /* route tables */
3328 free(cleanlist);
3329 cleanlist = tlp;
3330 }
3331 }
3332 break;
3333 }
3334 }
3335 (void) fflush(stdout);
3336 } /* 'for' loop 1 ends */
3337 if ((Iflag_only == 0) && (!once_only))
3338 (void) putchar('\n');
3339 reentry = B_TRUE;
3340 }
3341
3342 static void
3343 if_report_ip4(mib2_ipAddrEntry_t *ap,
3344 char ifname[], char logintname[], struct ifstat *statptr,
3345 boolean_t ksp_not_null)
3346 {
3347
3348 char abuf[MAXHOSTNAMELEN + 4]; /* Include /<num> for CIDR-printing. */
3349 char dstbuf[MAXHOSTNAMELEN + 1];
3350
3351 if (ksp_not_null) {
3352 (void) printf("%-5s %-4u ",
3353 ifname, ap->ipAdEntInfo.ae_mtu);
3354 if (ap->ipAdEntInfo.ae_flags & IFF_POINTOPOINT)
3355 (void) pr_addr(ap->ipAdEntInfo.ae_pp_dst_addr,
3356 abuf, sizeof (abuf));
3357 else
3358 (void) pr_netaddr(ap->ipAdEntAddr,
3359 ap->ipAdEntNetMask, abuf, sizeof (abuf));
3360 (void) printf("%-13s %-14s %-6llu %-5llu %-6llu %-5llu "
3361 "%-6llu %-6llu\n",
3362 abuf, pr_addr(ap->ipAdEntAddr, dstbuf, sizeof (dstbuf)),
3363 statptr->ipackets, statptr->ierrors,
3364 statptr->opackets, statptr->oerrors,
3365 statptr->collisions, 0LL);
3366 }
3367 /*
3368 * Print logical interface info if Aflag set (including logical unit 0)
4427
4428 static const char ire_hdr_v4[] =
4429 "\n%s Table: IPv4\n";
4430 static const char ire_hdr_v4_compat[] =
4431 "\n%s Table:\n";
4432 static const char ire_hdr_v4_verbose[] =
4433 " Destination Mask Gateway Device "
4434 " MTU Ref Flg Out In/Fwd %s\n"
4435 "-------------------- --------------- -------------------- ------ "
4436 "----- --- --- ----- ------ %s\n";
4437
4438 static const char ire_hdr_v4_normal[] =
4439 " Destination Gateway Flags Ref Use Interface"
4440 " %s\n-------------------- -------------------- ----- ----- ---------- "
4441 "--------- %s\n";
4442
4443 static boolean_t
4444 ire_report_item_v4(const mib2_ipRouteEntry_t *rp, boolean_t first,
4445 const sec_attr_list_t *attrs)
4446 {
4447 char dstbuf[MAXHOSTNAMELEN + 4]; /* + "/<num>" */
4448 char maskbuf[MAXHOSTNAMELEN + 1];
4449 char gwbuf[MAXHOSTNAMELEN + 1];
4450 char ifname[LIFNAMSIZ + 1];
4451 char flags[10]; /* RTF_ flags */
4452 uint_t flag_b;
4453
4454 if (!(Aflag || (rp->ipRouteInfo.re_ire_type != IRE_IF_CLONE &&
4455 rp->ipRouteInfo.re_ire_type != IRE_BROADCAST &&
4456 rp->ipRouteInfo.re_ire_type != IRE_MULTICAST &&
4457 rp->ipRouteInfo.re_ire_type != IRE_NOROUTE &&
4458 rp->ipRouteInfo.re_ire_type != IRE_LOCAL))) {
4459 return (first);
4460 }
4461
4462 flag_b = form_v4_route_flags(rp, flags);
4463
4464 if (!ire_filter_match_v4(rp, flag_b))
4465 return (first);
4466
4467 if (first) {
5545 } else {
5546 t = 'g';
5547 n /= 1024 * 1024 * 1024;
5548 }
5549
5550 (void) snprintf(buf, sizeof (buf), "%4u%c", n, t);
5551 return (buf);
5552 }
5553
5554 /* --------------------- mrt_report (netstat -m) -------------------------- */
5555
5556 static void
5557 mrt_report(mib_item_t *item)
5558 {
5559 int jtemp = 0;
5560 struct vifctl *vip;
5561 vifi_t vifi;
5562 struct mfcctl *mfccp;
5563 int numvifs = 0;
5564 int nmfc = 0;
5565 char abuf[MAXHOSTNAMELEN + 4]; /* Include CIDR /<num>. */
5566
5567 if (!(family_selected(AF_INET)))
5568 return;
5569
5570 /* 'for' loop 1: */
5571 for (; item; item = item->next_item) {
5572 if (Xflag) {
5573 (void) printf("\n--- Entry %d ---\n", ++jtemp);
5574 (void) printf("Group = %d, mib_id = %d, "
5575 "length = %d, valp = 0x%p\n",
5576 item->group, item->mib_id, item->length,
5577 item->valp);
5578 }
5579 if (item->group != EXPER_DVMRP)
5580 continue; /* 'for' loop 1 */
5581
5582 switch (item->mib_id) {
5583
5584 case EXPER_DVMRP_VIF:
5585 if (Xflag)
5964 char *cp;
5965
5966 if (IN6_IS_ADDR_UNSPECIFIED(addr)) {
5967 (void) strncpy(dst, " *", dstlen);
5968 dst[dstlen - 1] = 0;
5969 } else {
5970 (void) pr_addr6(addr, dst, dstlen);
5971 }
5972 /* How much room is left? */
5973 cp = strchr(dst, '\0');
5974 if (dst + dstlen + 1 > cp) {
5975 *cp++ = '.';
5976 dstlen -= (cp - dst);
5977 dstlen--;
5978 (void) portname(port, proto, cp, dstlen);
5979 }
5980 return (dst);
5981 }
5982
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 /*
6035 * Return the name of the network whose address is given. The address is
6036 * assumed to be that of a net or subnet, not a host.
6037 */
6038 static char *
6039 pr_net(uint_t addr, uint_t mask, char *dst, uint_t dstlen)
6040 {
6041 char *cp = NULL;
6042 struct netent *np = NULL;
6043 struct hostent *hp = NULL;
6044 uint_t net;
6045 int subnetshift;
6046 int error_num;
6047 int prefixlen = -1; /* -1 == Don't print prefix! */
6048 /* -2 == Noncontiguous mask... */
6049
6050 if (addr == INADDR_ANY && mask == INADDR_ANY) {
6051 (void) strlcpy(dst, "default", dstlen);
6052 return (dst);
6053 }
6054
6055 if (CIDRflag)
6056 prefixlen = v4_cidr_len(ntohl(mask));
6057
6058 if (!Nflag && addr) {
6059 if (mask == 0) {
6060 if (IN_CLASSA(addr)) {
6061 mask = (uint_t)IN_CLASSA_NET;
6062 subnetshift = 8;
6063 } else if (IN_CLASSB(addr)) {
6064 mask = (uint_t)IN_CLASSB_NET;
6065 subnetshift = 8;
6066 } else {
6067 mask = (uint_t)IN_CLASSC_NET;
6068 subnetshift = 4;
6069 }
6070 /*
6071 * If there are more bits than the standard mask
6072 * would suggest, subnets must be in use. Guess at
6073 * the subnet mask, assuming reasonable width subnet
6074 * fields.
6075 */
6076 while (addr & ~mask)
6077 /* compiler doesn't sign extend! */
6078 mask = (mask | ((int)mask >> subnetshift));
6079 if (CIDRflag)
6080 prefixlen = v4_cidr_len(mask);
6081 }
6082 net = addr & mask;
6083 while ((mask & 1) == 0)
6084 mask >>= 1, net >>= 1;
6085 ns_lookup_start();
6086 np = getnetbyaddr(net, AF_INET);
6087 ns_lookup_end();
6088 if (np && np->n_net == net)
6089 cp = np->n_name;
6090 else {
6091 /*
6092 * Look for subnets in hosts map.
6093 */
6094 ns_lookup_start();
6095 hp = getipnodebyaddr((char *)&addr, sizeof (uint_t),
6096 AF_INET, &error_num);
6097 ns_lookup_end();
6098 if (hp)
6099 cp = hp->h_name;
6100 }
6101 }
6102 if (cp != NULL) {
6103 (void) strlcpy(dst, cp, dstlen);
6104 } else {
6105 (void) inet_ntop(AF_INET, (char *)&addr, dst, dstlen);
6106 }
6107
6108 append_v4_cidr_len(dst, dstlen, prefixlen);
6109
6110 if (hp != NULL)
6111 freehostent(hp);
6112 return (dst);
6113 }
6114
6115 /*
6116 * Return the name of the network whose address is given.
6117 * The address is assumed to be a host address.
6118 */
6119 static char *
6120 pr_netaddr(uint_t addr, uint_t mask, char *dst, uint_t dstlen)
6121 {
6122 char *cp = NULL;
6123 struct netent *np = NULL;
6124 struct hostent *hp = NULL;
6125 uint_t net;
6126 uint_t netshifted;
6127 int subnetshift;
6128 struct in_addr in;
6129 int error_num;
6130 uint_t nbo_addr = addr; /* network byte order */
6131 int prefixlen = -1; /* -1 == Don't print prefix! */
6132 /* -2 == Noncontiguous mask... */
6133
6134 addr = ntohl(addr);
6135 mask = ntohl(mask);
6136 if (addr == INADDR_ANY && mask == INADDR_ANY) {
6137 (void) strlcpy(dst, "default", dstlen);
6138 return (dst);
6139 }
6140
6141 if (CIDRflag)
6142 prefixlen = v4_cidr_len(mask);
6143
6144 /* Figure out network portion of address (with host portion = 0) */
6145 if (addr) {
6146 /* Try figuring out mask if unknown (all 0s). */
6147 if (mask == 0) {
6148 if (IN_CLASSA(addr)) {
6149 mask = (uint_t)IN_CLASSA_NET;
6150 subnetshift = 8;
6151 } else if (IN_CLASSB(addr)) {
6152 mask = (uint_t)IN_CLASSB_NET;
6153 subnetshift = 8;
6154 } else {
6155 mask = (uint_t)IN_CLASSC_NET;
6156 subnetshift = 4;
6157 }
6158 /*
6159 * If there are more bits than the standard mask
6160 * would suggest, subnets must be in use. Guess at
6161 * the subnet mask, assuming reasonable width subnet
6162 * fields.
6163 */
6164 while (addr & ~mask)
6165 /* compiler doesn't sign extend! */
6166 mask = (mask | ((int)mask >> subnetshift));
6167 if (CIDRflag)
6168 prefixlen = v4_cidr_len(mask);
6169 }
6170 net = netshifted = addr & mask;
6171 while ((mask & 1) == 0)
6172 mask >>= 1, netshifted >>= 1;
6173 }
6174 else
6175 net = netshifted = 0;
6176
6177 /* Try looking up name unless -n was specified. */
6178 if (!Nflag) {
6179 ns_lookup_start();
6180 np = getnetbyaddr(netshifted, AF_INET);
6181 ns_lookup_end();
6182 if (np && np->n_net == netshifted)
6183 cp = np->n_name;
6184 else {
6185 /*
6186 * Look for subnets in hosts map.
6187 */
6188 ns_lookup_start();
6189 hp = getipnodebyaddr((char *)&nbo_addr, sizeof (uint_t),
6190 AF_INET, &error_num);
6191 ns_lookup_end();
6192 if (hp)
6193 cp = hp->h_name;
6194 }
6195
6196 if (cp != NULL) {
6197 (void) strlcpy(dst, cp, dstlen);
6198 append_v4_cidr_len(dst, dstlen, prefixlen);
6199 if (hp != NULL)
6200 freehostent(hp);
6201 return (dst);
6202 }
6203 /*
6204 * No name found for net: fallthru and return in decimal
6205 * dot notation.
6206 */
6207 }
6208
6209 in.s_addr = htonl(net);
6210 (void) inet_ntop(AF_INET, (char *)&in, dst, dstlen);
6211 append_v4_cidr_len(dst, dstlen, prefixlen);
6212 if (hp != NULL)
6213 freehostent(hp);
6214 return (dst);
6215 }
6216
6217 /*
6218 * Return the filter mode as a string:
6219 * 1 => "INCLUDE"
6220 * 2 => "EXCLUDE"
6221 * otherwise "<unknown>"
6222 */
6223 static char *
6224 fmodestr(uint_t fmode)
6225 {
6226 switch (fmode) {
6227 case 1:
6228 return ("INCLUDE");
6229 case 2:
6230 return ("EXCLUDE");
6231 default:
|