38 * because they have 'continue' or 'break' statements in their
39 * bodies. 'continue' statements have been used inside some loops
40 * where avoiding them would have led to deep levels of indentation.
41 *
42 * TODO:
43 * Add ability to request subsets from kernel (with level = MIB2_IP;
44 * name = 0 meaning everything for compatibility)
45 */
46
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <stdarg.h>
50 #include <unistd.h>
51 #include <strings.h>
52 #include <string.h>
53 #include <errno.h>
54 #include <ctype.h>
55 #include <kstat.h>
56 #include <assert.h>
57 #include <locale.h>
58
59 #include <sys/types.h>
60 #include <sys/stream.h>
61 #include <stropts.h>
62 #include <sys/strstat.h>
63 #include <sys/tihdr.h>
64
65 #include <sys/socket.h>
66 #include <sys/sockio.h>
67 #include <netinet/in.h>
68 #include <net/if.h>
69 #include <net/route.h>
70
71 #include <inet/mib2.h>
72 #include <inet/ip.h>
73 #include <inet/arp.h>
74 #include <inet/tcp.h>
75 #include <netinet/igmp_var.h>
76 #include <netinet/ip_mroute.h>
77
78 #include <arpa/inet.h>
79 #include <netdb.h>
80 #include <fcntl.h>
81 #include <sys/systeminfo.h>
82 #include <arpa/inet.h>
83
84 #include <netinet/dhcp.h>
85 #include <dhcpagent_ipc.h>
86 #include <dhcpagent_util.h>
87 #include <compat.h>
88
89 #include <libtsnet.h>
90 #include <tsol/label.h>
91
92 #include "statcommon.h"
93
94 extern void unixpr(kstat_ctl_t *kc);
95
96 #define STR_EXPAND 4
97
98 #define V4MASK_TO_V6(v4, v6) ((v6)._S6_un._S6_u32[0] = 0xfffffffful, \
99 (v6)._S6_un._S6_u32[1] = 0xfffffffful, \
100 (v6)._S6_un._S6_u32[2] = 0xfffffffful, \
101 (v6)._S6_un._S6_u32[3] = (v4))
102
103 #define IN6_IS_V4MASK(v6) ((v6)._S6_un._S6_u32[0] == 0xfffffffful && \
104 (v6)._S6_un._S6_u32[1] == 0xfffffffful && \
105 (v6)._S6_un._S6_u32[2] == 0xfffffffful)
106
107 /*
108 * This is used as a cushion in the buffer allocation directed by SIOCGLIFNUM.
109 * Because there's no locking between SIOCGLIFNUM and SIOCGLIFCONF, it's
110 * possible for an administrator to plumb new interfaces between those two
111 * calls, resulting in the failure of the latter. This addition makes that
112 * less likely.
113 */
114 #define LIFN_GUARD_VALUE 10
118 int group;
119 int mib_id;
120 int length;
121 void *valp;
122 } mib_item_t;
123
124 struct ifstat {
125 uint64_t ipackets;
126 uint64_t ierrors;
127 uint64_t opackets;
128 uint64_t oerrors;
129 uint64_t collisions;
130 };
131
132 struct iflist {
133 struct iflist *next_if;
134 char ifname[LIFNAMSIZ];
135 struct ifstat tot;
136 };
137
138 static mib_item_t *mibget(int sd);
139 static void mibfree(mib_item_t *firstitem);
140 static int mibopen(void);
141 static void mib_get_constants(mib_item_t *item);
142 static mib_item_t *mib_item_dup(mib_item_t *item);
143 static mib_item_t *mib_item_diff(mib_item_t *item1,
144 mib_item_t *item2);
145 static void mib_item_destroy(mib_item_t **item);
146
147 static boolean_t octetstrmatch(const Octet_t *a, const Octet_t *b);
148 static char *octetstr(const Octet_t *op, int code,
149 char *dst, uint_t dstlen);
150 static char *pr_addr(uint_t addr,
151 char *dst, uint_t dstlen);
152 static char *pr_addrnz(ipaddr_t addr, char *dst, uint_t dstlen);
153 static char *pr_addr6(const in6_addr_t *addr,
154 char *dst, uint_t dstlen);
155 static char *pr_mask(uint_t addr,
156 char *dst, uint_t dstlen);
157 static char *pr_prefix6(const struct in6_addr *addr,
174 const mib2_transportMLPEntry_t *attr);
175
176 static void stat_report(mib_item_t *item);
177 static void mrt_stat_report(mib_item_t *item);
178 static void arp_report(mib_item_t *item);
179 static void ndp_report(mib_item_t *item);
180 static void mrt_report(mib_item_t *item);
181 static void if_stat_total(struct ifstat *oldstats,
182 struct ifstat *newstats, struct ifstat *sumstats);
183 static void if_report(mib_item_t *item, char *ifname,
184 int Iflag_only, boolean_t once_only);
185 static void if_report_ip4(mib2_ipAddrEntry_t *ap,
186 char ifname[], char logintname[],
187 struct ifstat *statptr, boolean_t ksp_not_null);
188 static void if_report_ip6(mib2_ipv6AddrEntry_t *ap6,
189 char ifname[], char logintname[],
190 struct ifstat *statptr, boolean_t ksp_not_null);
191 static void ire_report(const mib_item_t *item);
192 static void tcp_report(const mib_item_t *item);
193 static void udp_report(const mib_item_t *item);
194 static void group_report(mib_item_t *item);
195 static void dce_report(mib_item_t *item);
196 static void print_ip_stats(mib2_ip_t *ip);
197 static void print_icmp_stats(mib2_icmp_t *icmp);
198 static void print_ip6_stats(mib2_ipv6IfStatsEntry_t *ip6);
199 static void print_icmp6_stats(mib2_ipv6IfIcmpEntry_t *icmp6);
200 static void print_sctp_stats(mib2_sctp_t *tcp);
201 static void print_tcp_stats(mib2_tcp_t *tcp);
202 static void print_udp_stats(mib2_udp_t *udp);
203 static void print_rawip_stats(mib2_rawip_t *rawip);
204 static void print_igmp_stats(struct igmpstat *igps);
205 static void print_mrt_stats(struct mrtstat *mrts);
206 static void sctp_report(const mib_item_t *item);
207 static void sum_ip6_stats(mib2_ipv6IfStatsEntry_t *ip6,
208 mib2_ipv6IfStatsEntry_t *sum6);
209 static void sum_icmp6_stats(mib2_ipv6IfIcmpEntry_t *icmp6,
210 mib2_ipv6IfIcmpEntry_t *sum6);
211 static void m_report(void);
212 static void dhcp_report(char *);
213
214 static uint64_t kstat_named_value(kstat_t *, char *);
215 static kid_t safe_kstat_read(kstat_ctl_t *, kstat_t *, void *);
216 static int isnum(char *);
217 static char *plural(int n);
218 static char *pluraly(int n);
219 static char *plurales(int n);
220 static void process_filter(char *arg);
221 static char *ifindex2str(uint_t, char *);
222 static boolean_t family_selected(int family);
223
224 static void usage(char *);
225 static void fatal(int errcode, char *str1, ...);
226
227 #define PLURAL(n) plural((int)n)
228 #define PLURALY(n) pluraly((int)n)
229 #define PLURALES(n) plurales((int)n)
230 #define IFLAGMOD(flg, val1, val2) if (flg == val1) flg = val2
231 #define MDIFF(diff, elem2, elem1, member) (diff)->member = \
232 (elem2)->member - (elem1)->member
233
234
235 static boolean_t Aflag = B_FALSE; /* All sockets/ifs/rtng-tbls */
236 static boolean_t Dflag = B_FALSE; /* DCE info */
237 static boolean_t Iflag = B_FALSE; /* IP Traffic Interfaces */
238 static boolean_t Mflag = B_FALSE; /* STREAMS Memory Statistics */
239 static boolean_t Nflag = B_FALSE; /* Numeric Network Addresses */
240 static boolean_t Rflag = B_FALSE; /* Routing Tables */
241 static boolean_t RSECflag = B_FALSE; /* Security attributes */
242 static boolean_t Sflag = B_FALSE; /* Per-protocol Statistics */
243 static boolean_t Vflag = B_FALSE; /* Verbose */
244 static boolean_t Pflag = B_FALSE; /* Net to Media Tables */
245 static boolean_t Gflag = B_FALSE; /* Multicast group membership */
246 static boolean_t MMflag = B_FALSE; /* Multicast routing table */
247 static boolean_t DHCPflag = B_FALSE; /* DHCP statistics */
248 static boolean_t Xflag = B_FALSE; /* Debug Info */
249
250 static int v4compat = 0; /* Compatible printing format for status */
251
252 static int proto = IPPROTO_MAX; /* all protocols */
253 kstat_ctl_t *kc = NULL;
254
255 /*
256 * Sizes of data structures extracted from the base mib.
257 * This allows the size of the tables entries to grow while preserving
258 * binary compatibility.
259 */
260 static int ipAddrEntrySize;
261 static int ipRouteEntrySize;
262 static int ipNetToMediaEntrySize;
263 static int ipMemberEntrySize;
368 * 1, IFlag is the only feature-flag enabled
369 * : trinary variable, modified using IFLAGMOD()
370 */
371 int Iflag_only = -1;
372 boolean_t once_only = B_FALSE; /* '-i' with count > 1 */
373 extern char *optarg;
374 extern int optind;
375 char *default_ip_str = NULL;
376
377 name = argv[0];
378
379 v4compat = get_compat_flag(&default_ip_str);
380 if (v4compat == DEFAULT_PROT_BAD_VALUE)
381 fatal(2, "%s: %s: Bad value for %s in %s\n", name,
382 default_ip_str, DEFAULT_IP, INET_DEFAULT_FILE);
383 free(default_ip_str);
384
385 (void) setlocale(LC_ALL, "");
386 (void) textdomain(TEXT_DOMAIN);
387
388 while ((c = getopt(argc, argv, "adimnrspMgvxf:P:I:DRT:")) != -1) {
389 switch ((char)c) {
390 case 'a': /* all connections */
391 Aflag = B_TRUE;
392 break;
393
394 case 'd': /* DCE info */
395 Dflag = B_TRUE;
396 IFLAGMOD(Iflag_only, 1, 0); /* see macro def'n */
397 break;
398
399 case 'i': /* interface (ill/ipif report) */
400 Iflag = B_TRUE;
401 IFLAGMOD(Iflag_only, -1, 1); /* '-i' exists */
402 break;
403
404 case 'm': /* streams msg report */
405 Mflag = B_TRUE;
406 IFLAGMOD(Iflag_only, 1, 0); /* see macro def'n */
407 break;
408
428 case 'p': /* arp/ndp table */
429 Pflag = B_TRUE;
430 IFLAGMOD(Iflag_only, 1, 0); /* see macro def'n */
431 break;
432
433 case 'M': /* multicast routing tables */
434 MMflag = B_TRUE;
435 IFLAGMOD(Iflag_only, 1, 0); /* see macro def'n */
436 break;
437
438 case 'g': /* multicast group membership */
439 Gflag = B_TRUE;
440 IFLAGMOD(Iflag_only, 1, 0); /* see macro def'n */
441 break;
442
443 case 'v': /* verbose output format */
444 Vflag = B_TRUE;
445 IFLAGMOD(Iflag_only, 1, 0); /* see macro def'n */
446 break;
447
448 case 'x': /* turn on debugging */
449 Xflag = B_TRUE;
450 break;
451
452 case 'f':
453 process_filter(optarg);
454 break;
455
456 case 'P':
457 if (strcmp(optarg, "ip") == 0) {
458 proto = IPPROTO_IP;
459 } else if (strcmp(optarg, "ipv6") == 0 ||
460 strcmp(optarg, "ip6") == 0) {
461 v4compat = 0; /* Overridden */
462 proto = IPPROTO_IPV6;
463 } else if (strcmp(optarg, "icmp") == 0) {
464 proto = IPPROTO_ICMP;
465 } else if (strcmp(optarg, "icmpv6") == 0 ||
466 strcmp(optarg, "icmp6") == 0) {
467 v4compat = 0; /* Overridden */
637 if (MMflag)
638 mrt_report(item);
639 }
640 if (Gflag)
641 group_report(item);
642 if (Pflag) {
643 if (family_selected(AF_INET))
644 arp_report(item);
645 if (family_selected(AF_INET6))
646 ndp_report(item);
647 }
648 if (Dflag)
649 dce_report(item);
650 mib_item_destroy(&curritem);
651 }
652
653 /* netstat: AF_UNIX behaviour */
654 if (family_selected(AF_UNIX) &&
655 (!(Dflag || Iflag || Rflag || Sflag || Mflag ||
656 MMflag || Pflag || Gflag)))
657 unixpr(kc);
658 (void) kstat_close(kc);
659
660 /* iteration handling code */
661 if (count > 0 && --count == 0)
662 break;
663 (void) sleep(interval);
664
665 /* re-populating of data structures */
666 if (family_selected(AF_INET) || family_selected(AF_INET6)) {
667 if (Sflag) {
668 /* previtem is a cut-down list */
669 previtem = mib_item_dup(item);
670 if (previtem == NULL)
671 fatal(1, "can't process mib data, "
672 "out of memory\n");
673 }
674 mibfree(item);
675 (void) close(sd);
676 if ((sd = mibopen()) == -1)
677 fatal(1, "can't open mib stream anymore\n");
4725 free(sl_str);
4726 }
4727 }
4728
4729 /* ------------------------------ TCP_REPORT------------------------------- */
4730
4731 static const char tcp_hdr_v4[] =
4732 "\nTCP: IPv4\n";
4733 static const char tcp_hdr_v4_compat[] =
4734 "\nTCP\n";
4735 static const char tcp_hdr_v4_verbose[] =
4736 "Local/Remote Address Swind Snext Suna Rwind Rnext Rack "
4737 " Rto Mss State\n"
4738 "-------------------- ----- -------- -------- ----- -------- -------- "
4739 "----- ----- -----------\n";
4740 static const char tcp_hdr_v4_normal[] =
4741 " Local Address Remote Address Swind Send-Q Rwind Recv-Q "
4742 " State\n"
4743 "-------------------- -------------------- ----- ------ ----- ------ "
4744 "-----------\n";
4745
4746 static const char tcp_hdr_v6[] =
4747 "\nTCP: IPv6\n";
4748 static const char tcp_hdr_v6_verbose[] =
4749 "Local/Remote Address Swind Snext Suna Rwind Rnext "
4750 " Rack Rto Mss State If\n"
4751 "--------------------------------- ----- -------- -------- ----- -------- "
4752 "-------- ----- ----- ----------- -----\n";
4753 static const char tcp_hdr_v6_normal[] =
4754 " Local Address Remote Address "
4755 "Swind Send-Q Rwind Recv-Q State If\n"
4756 "--------------------------------- --------------------------------- "
4757 "----- ------ ----- ------ ----------- -----\n";
4758
4759 static boolean_t tcp_report_item_v4(const mib2_tcpConnEntry_t *,
4760 boolean_t first, const mib2_transportMLPEntry_t *);
4761 static boolean_t tcp_report_item_v6(const mib2_tcp6ConnEntry_t *,
4762 boolean_t first, const mib2_transportMLPEntry_t *);
4763
4764 static void
4765 tcp_report(const mib_item_t *item)
4766 {
4767 int jtemp = 0;
4768 boolean_t print_hdr_once_v4 = B_TRUE;
4769 boolean_t print_hdr_once_v6 = B_TRUE;
4770 mib2_tcpConnEntry_t *tp;
4771 mib2_tcp6ConnEntry_t *tp6;
4772 mib2_transportMLPEntry_t **v4_attrs, **v6_attrs;
4773 mib2_transportMLPEntry_t **v4a, **v6a;
4774 mib2_transportMLPEntry_t *aptr;
4775
4776 if (!protocol_selected(IPPROTO_TCP))
4777 return;
4778
4779 /*
4780 * Preparation pass: the kernel returns separate entries for TCP
4781 * connection table entries and Multilevel Port attributes. We loop
4782 * through the attributes first and set up an array for each address
4783 * family.
4784 */
4785 v4_attrs = family_selected(AF_INET) && RSECflag ?
4786 gather_attrs(item, MIB2_TCP, MIB2_TCP_CONN, tcpConnEntrySize) :
4787 NULL;
4788 v6_attrs = family_selected(AF_INET6) && RSECflag ?
4789 gather_attrs(item, MIB2_TCP6, MIB2_TCP6_CONN, tcp6ConnEntrySize) :
4790 NULL;
4791
4792 /* 'for' loop 1: */
4793 v4a = v4_attrs;
4794 v6a = v6_attrs;
4795 for (; item != NULL; item = item->next_item) {
4796 if (Xflag) {
4797 (void) printf("\n--- Entry %d ---\n", ++jtemp);
4798 (void) printf("Group = %d, mib_id = %d, "
4799 "length = %d, valp = 0x%p\n",
4800 item->group, item->mib_id,
4801 item->length, item->valp);
4802 }
4803
4804 if (!((item->group == MIB2_TCP &&
4805 item->mib_id == MIB2_TCP_CONN) ||
4806 (item->group == MIB2_TCP6 &&
4807 item->mib_id == MIB2_TCP6_CONN)))
4808 continue; /* 'for' loop 1 */
4809
4810 if (item->group == MIB2_TCP && !family_selected(AF_INET))
4811 continue; /* 'for' loop 1 */
4812 else if (item->group == MIB2_TCP6 && !family_selected(AF_INET6))
4813 continue; /* 'for' loop 1 */
4814
4815 if (item->group == MIB2_TCP) {
4816 for (tp = (mib2_tcpConnEntry_t *)item->valp;
4817 (char *)tp < (char *)item->valp + item->length;
4818 /* LINTED: (note 1) */
4819 tp = (mib2_tcpConnEntry_t *)((char *)tp +
4820 tcpConnEntrySize)) {
4821 aptr = v4a == NULL ? NULL : *v4a++;
4822 print_hdr_once_v4 = tcp_report_item_v4(tp,
4823 print_hdr_once_v4, aptr);
4824 }
4825 } else {
4826 for (tp6 = (mib2_tcp6ConnEntry_t *)item->valp;
4827 (char *)tp6 < (char *)item->valp + item->length;
4828 /* LINTED: (note 1) */
4829 tp6 = (mib2_tcp6ConnEntry_t *)((char *)tp6 +
4830 tcp6ConnEntrySize)) {
4831 aptr = v6a == NULL ? NULL : *v6a++;
4832 print_hdr_once_v6 = tcp_report_item_v6(tp6,
4833 print_hdr_once_v6, aptr);
4834 }
4835 }
4836 } /* 'for' loop 1 ends */
4837 (void) fflush(stdout);
4838
4839 if (v4_attrs != NULL)
4840 free(v4_attrs);
4841 if (v6_attrs != NULL)
4842 free(v6_attrs);
4843 }
4844
4845 static boolean_t
4846 tcp_report_item_v4(const mib2_tcpConnEntry_t *tp, boolean_t first,
4847 const mib2_transportMLPEntry_t *attr)
4848 {
4849 /*
4850 * lname and fname below are for the hostname as well as the portname
4851 * There is no limit on portname length so we assume MAXHOSTNAMELEN
4852 * as the limit
4853 */
4854 char lname[MAXHOSTNAMELEN + MAXHOSTNAMELEN + 1];
4855 char fname[MAXHOSTNAMELEN + MAXHOSTNAMELEN + 1];
4856
4857 if (!(Aflag || tp->tcpConnEntryInfo.ce_state >= TCPS_ESTABLISHED))
4858 return (first); /* Nothing to print */
4859
4860 if (first) {
4861 (void) printf(v4compat ? tcp_hdr_v4_compat : tcp_hdr_v4);
4862 (void) printf(Vflag ? tcp_hdr_v4_verbose : tcp_hdr_v4_normal);
4863 }
4864
4865 if (Vflag) {
4866 (void) printf("%-20s\n%-20s %5u %08x %08x %5u %08x %08x "
4867 "%5u %5u %s\n",
4868 pr_ap(tp->tcpConnLocalAddress,
4869 tp->tcpConnLocalPort, "tcp", lname, sizeof (lname)),
4870 pr_ap(tp->tcpConnRemAddress,
4871 tp->tcpConnRemPort, "tcp", fname, sizeof (fname)),
4872 tp->tcpConnEntryInfo.ce_swnd,
4873 tp->tcpConnEntryInfo.ce_snxt,
4874 tp->tcpConnEntryInfo.ce_suna,
4875 tp->tcpConnEntryInfo.ce_rwnd,
4876 tp->tcpConnEntryInfo.ce_rnxt,
4877 tp->tcpConnEntryInfo.ce_rack,
4878 tp->tcpConnEntryInfo.ce_rto,
4879 tp->tcpConnEntryInfo.ce_mss,
4880 mitcp_state(tp->tcpConnEntryInfo.ce_state, attr));
4881 } else {
4882 int sq = (int)tp->tcpConnEntryInfo.ce_snxt -
4883 (int)tp->tcpConnEntryInfo.ce_suna - 1;
4884 int rq = (int)tp->tcpConnEntryInfo.ce_rnxt -
4885 (int)tp->tcpConnEntryInfo.ce_rack;
4886
4887 (void) printf("%-20s %-20s %5u %6d %5u %6d %s\n",
4888 pr_ap(tp->tcpConnLocalAddress,
4889 tp->tcpConnLocalPort, "tcp", lname, sizeof (lname)),
4890 pr_ap(tp->tcpConnRemAddress,
4891 tp->tcpConnRemPort, "tcp", fname, sizeof (fname)),
4892 tp->tcpConnEntryInfo.ce_swnd,
4893 (sq >= 0) ? sq : 0,
4894 tp->tcpConnEntryInfo.ce_rwnd,
4895 (rq >= 0) ? rq : 0,
4896 mitcp_state(tp->tcpConnEntryInfo.ce_state, attr));
4897 }
4898
4899 print_transport_label(attr);
4900
4901 return (B_FALSE);
4902 }
4903
4904 static boolean_t
4905 tcp_report_item_v6(const mib2_tcp6ConnEntry_t *tp6, boolean_t first,
4906 const mib2_transportMLPEntry_t *attr)
4907 {
4908 /*
4909 * lname and fname below are for the hostname as well as the portname
4910 * There is no limit on portname length so we assume MAXHOSTNAMELEN
4911 * as the limit
4912 */
4913 char lname[MAXHOSTNAMELEN + MAXHOSTNAMELEN + 1];
4914 char fname[MAXHOSTNAMELEN + MAXHOSTNAMELEN + 1];
4915 char ifname[LIFNAMSIZ + 1];
4916 char *ifnamep;
4917
4918 if (!(Aflag || tp6->tcp6ConnEntryInfo.ce_state >= TCPS_ESTABLISHED))
4919 return (first); /* Nothing to print */
4920
4921 if (first) {
4922 (void) printf(tcp_hdr_v6);
4923 (void) printf(Vflag ? tcp_hdr_v6_verbose : tcp_hdr_v6_normal);
4924 }
4925
4926 ifnamep = (tp6->tcp6ConnIfIndex != 0) ?
4927 if_indextoname(tp6->tcp6ConnIfIndex, ifname) : NULL;
4928 if (ifnamep == NULL)
4929 ifnamep = "";
4930
4931 if (Vflag) {
4932 (void) printf("%-33s\n%-33s %5u %08x %08x %5u %08x %08x "
4933 "%5u %5u %-11s %s\n",
4934 pr_ap6(&tp6->tcp6ConnLocalAddress,
4935 tp6->tcp6ConnLocalPort, "tcp", lname, sizeof (lname)),
4936 pr_ap6(&tp6->tcp6ConnRemAddress,
4937 tp6->tcp6ConnRemPort, "tcp", fname, sizeof (fname)),
4938 tp6->tcp6ConnEntryInfo.ce_swnd,
4939 tp6->tcp6ConnEntryInfo.ce_snxt,
4940 tp6->tcp6ConnEntryInfo.ce_suna,
4941 tp6->tcp6ConnEntryInfo.ce_rwnd,
4942 tp6->tcp6ConnEntryInfo.ce_rnxt,
4943 tp6->tcp6ConnEntryInfo.ce_rack,
4944 tp6->tcp6ConnEntryInfo.ce_rto,
4945 tp6->tcp6ConnEntryInfo.ce_mss,
4946 mitcp_state(tp6->tcp6ConnEntryInfo.ce_state, attr),
4947 ifnamep);
4948 } else {
4949 int sq = (int)tp6->tcp6ConnEntryInfo.ce_snxt -
4950 (int)tp6->tcp6ConnEntryInfo.ce_suna - 1;
4951 int rq = (int)tp6->tcp6ConnEntryInfo.ce_rnxt -
4952 (int)tp6->tcp6ConnEntryInfo.ce_rack;
4953
4954 (void) printf("%-33s %-33s %5u %6d %5u %6d %-11s %s\n",
4955 pr_ap6(&tp6->tcp6ConnLocalAddress,
4956 tp6->tcp6ConnLocalPort, "tcp", lname, sizeof (lname)),
4957 pr_ap6(&tp6->tcp6ConnRemAddress,
4958 tp6->tcp6ConnRemPort, "tcp", fname, sizeof (fname)),
4959 tp6->tcp6ConnEntryInfo.ce_swnd,
4960 (sq >= 0) ? sq : 0,
4961 tp6->tcp6ConnEntryInfo.ce_rwnd,
4962 (rq >= 0) ? rq : 0,
4963 mitcp_state(tp6->tcp6ConnEntryInfo.ce_state, attr),
4964 ifnamep);
4965 }
4966
4967 print_transport_label(attr);
4968
4969 return (B_FALSE);
4970 }
4971
4972 /* ------------------------------- UDP_REPORT------------------------------- */
4973
4974 static boolean_t udp_report_item_v4(const mib2_udpEntry_t *ude,
4975 boolean_t first, const mib2_transportMLPEntry_t *attr);
4976 static boolean_t udp_report_item_v6(const mib2_udp6Entry_t *ude6,
4977 boolean_t first, const mib2_transportMLPEntry_t *attr);
4978
4979 static const char udp_hdr_v4[] =
4980 " Local Address Remote Address State\n"
4981 "-------------------- -------------------- ----------\n";
4982
4983 static const char udp_hdr_v6[] =
4984 " Local Address Remote Address "
4985 " State If\n"
4986 "--------------------------------- --------------------------------- "
4987 "---------- -----\n";
4988
4989 static void
4990 udp_report(const mib_item_t *item)
4991 {
4992 int jtemp = 0;
4993 boolean_t print_hdr_once_v4 = B_TRUE;
4994 boolean_t print_hdr_once_v6 = B_TRUE;
4995 mib2_udpEntry_t *ude;
4996 mib2_udp6Entry_t *ude6;
4997 mib2_transportMLPEntry_t **v4_attrs, **v6_attrs;
4998 mib2_transportMLPEntry_t **v4a, **v6a;
4999 mib2_transportMLPEntry_t *aptr;
5000
5001 if (!protocol_selected(IPPROTO_UDP))
5002 return;
5003
5004 /*
5005 * Preparation pass: the kernel returns separate entries for UDP
5006 * connection table entries and Multilevel Port attributes. We loop
5007 * through the attributes first and set up an array for each address
5008 * family.
5009 */
5010 v4_attrs = family_selected(AF_INET) && RSECflag ?
5011 gather_attrs(item, MIB2_UDP, MIB2_UDP_ENTRY, udpEntrySize) : NULL;
5012 v6_attrs = family_selected(AF_INET6) && RSECflag ?
5013 gather_attrs(item, MIB2_UDP6, MIB2_UDP6_ENTRY, udp6EntrySize) :
5014 NULL;
5015
5016 v4a = v4_attrs;
5017 v6a = v6_attrs;
5018 /* 'for' loop 1: */
5019 for (; item; item = item->next_item) {
5020 if (Xflag) {
5021 (void) printf("\n--- Entry %d ---\n", ++jtemp);
5022 (void) printf("Group = %d, mib_id = %d, "
5023 "length = %d, valp = 0x%p\n",
5024 item->group, item->mib_id,
5025 item->length, item->valp);
5026 }
5027 if (!((item->group == MIB2_UDP &&
5028 item->mib_id == MIB2_UDP_ENTRY) ||
5029 (item->group == MIB2_UDP6 &&
5030 item->mib_id == MIB2_UDP6_ENTRY)))
5031 continue; /* 'for' loop 1 */
5032
5033 if (item->group == MIB2_UDP && !family_selected(AF_INET))
5034 continue; /* 'for' loop 1 */
5035 else if (item->group == MIB2_UDP6 && !family_selected(AF_INET6))
5036 continue; /* 'for' loop 1 */
5037
5038 /* xxx.xxx.xxx.xxx,pppp sss... */
5039 if (item->group == MIB2_UDP) {
5040 for (ude = (mib2_udpEntry_t *)item->valp;
5041 (char *)ude < (char *)item->valp + item->length;
5042 /* LINTED: (note 1) */
5043 ude = (mib2_udpEntry_t *)((char *)ude +
5044 udpEntrySize)) {
5045 aptr = v4a == NULL ? NULL : *v4a++;
5046 print_hdr_once_v4 = udp_report_item_v4(ude,
5047 print_hdr_once_v4, aptr);
5048 }
5049 } else {
5050 for (ude6 = (mib2_udp6Entry_t *)item->valp;
5051 (char *)ude6 < (char *)item->valp + item->length;
5052 /* LINTED: (note 1) */
5053 ude6 = (mib2_udp6Entry_t *)((char *)ude6 +
5054 udp6EntrySize)) {
5055 aptr = v6a == NULL ? NULL : *v6a++;
5056 print_hdr_once_v6 = udp_report_item_v6(ude6,
5057 print_hdr_once_v6, aptr);
5058 }
5059 }
5060 } /* 'for' loop 1 ends */
5061 (void) fflush(stdout);
5062
5063 if (v4_attrs != NULL)
5064 free(v4_attrs);
5065 if (v6_attrs != NULL)
5066 free(v6_attrs);
5067 }
5068
5069 static boolean_t
5070 udp_report_item_v4(const mib2_udpEntry_t *ude, boolean_t first,
5071 const mib2_transportMLPEntry_t *attr)
5072 {
5073 char lname[MAXHOSTNAMELEN + MAXHOSTNAMELEN + 1];
5074 /* hostname + portname */
5075
5076 if (!(Aflag || ude->udpEntryInfo.ue_state >= MIB2_UDP_connected))
5077 return (first); /* Nothing to print */
5078
5079 if (first) {
5080 (void) printf(v4compat ? "\nUDP\n" : "\nUDP: IPv4\n");
5081 (void) printf(udp_hdr_v4);
5082 first = B_FALSE;
5083 }
5084
5085 (void) printf("%-20s ",
5086 pr_ap(ude->udpLocalAddress, ude->udpLocalPort, "udp",
5087 lname, sizeof (lname)));
5088 (void) printf("%-20s %s\n",
5089 ude->udpEntryInfo.ue_state == MIB2_UDP_connected ?
5090 pr_ap(ude->udpEntryInfo.ue_RemoteAddress,
5091 ude->udpEntryInfo.ue_RemotePort, "udp", lname, sizeof (lname)) :
5092 "",
5093 miudp_state(ude->udpEntryInfo.ue_state, attr));
5094
5095 print_transport_label(attr);
5096
5097 return (first);
5098 }
5099
5100 static boolean_t
5101 udp_report_item_v6(const mib2_udp6Entry_t *ude6, boolean_t first,
5102 const mib2_transportMLPEntry_t *attr)
5103 {
5104 char lname[MAXHOSTNAMELEN + MAXHOSTNAMELEN + 1];
5105 /* hostname + portname */
5106 char ifname[LIFNAMSIZ + 1];
5107 const char *ifnamep;
5108
5109 if (!(Aflag || ude6->udp6EntryInfo.ue_state >= MIB2_UDP_connected))
5110 return (first); /* Nothing to print */
5111
5112 if (first) {
5113 (void) printf("\nUDP: IPv6\n");
5114 (void) printf(udp_hdr_v6);
5115 first = B_FALSE;
5116 }
5117
5118 ifnamep = (ude6->udp6IfIndex != 0) ?
5119 if_indextoname(ude6->udp6IfIndex, ifname) : NULL;
5120
5121 (void) printf("%-33s ",
5122 pr_ap6(&ude6->udp6LocalAddress,
5123 ude6->udp6LocalPort, "udp", lname, sizeof (lname)));
5124 (void) printf("%-33s %-10s %s\n",
5125 ude6->udp6EntryInfo.ue_state == MIB2_UDP_connected ?
5126 pr_ap6(&ude6->udp6EntryInfo.ue_RemoteAddress,
5127 ude6->udp6EntryInfo.ue_RemotePort, "udp", lname, sizeof (lname)) :
5128 "",
5129 miudp_state(ude6->udp6EntryInfo.ue_state, attr),
5130 ifnamep == NULL ? "" : ifnamep);
5131
5132 print_transport_label(attr);
5133
5134 return (first);
5135 }
5136
5137 /* ------------------------------ SCTP_REPORT------------------------------- */
5138
5139 static const char sctp_hdr[] =
5140 "\nSCTP:";
5141 static const char sctp_hdr_normal[] =
5142 " Local Address Remote Address "
5143 "Swind Send-Q Rwind Recv-Q StrsI/O State\n"
5144 "------------------------------- ------------------------------- "
5145 "------ ------ ------ ------ ------- -----------";
5146
5147 static const char *
5148 nssctp_state(int state, const mib2_transportMLPEntry_t *attr)
5149 {
5150 static char sctpsbuf[50];
5151 const char *cp;
5152
5153 switch (state) {
5154 case MIB2_SCTP_closed:
5155 cp = "CLOSED";
5156 break;
5157 case MIB2_SCTP_cookieWait:
5158 cp = "COOKIE_WAIT";
5159 break;
5160 case MIB2_SCTP_cookieEchoed:
5161 cp = "COOKIE_ECHOED";
5162 break;
5163 case MIB2_SCTP_established:
5164 cp = "ESTABLISHED";
5165 break;
5292 } else {
5293 (void) pr_addr(v4addr, name, namelen);
5294 }
5295 break;
5296
5297 case MIB2_SCTP_ADDR_V6:
5298 /* v6 */
5299 if (port > 0) {
5300 (void) pr_ap6(addr, port, "sctp", name, namelen);
5301 } else {
5302 (void) pr_addr6(addr, name, namelen);
5303 }
5304 break;
5305
5306 default:
5307 (void) snprintf(name, namelen, "<unknown addr type>");
5308 break;
5309 }
5310 }
5311
5312 static void
5313 sctp_conn_report_item(const mib_item_t *head, const mib2_sctpConnEntry_t *sp,
5314 const mib2_transportMLPEntry_t *attr)
5315 {
5316 char lname[MAXHOSTNAMELEN + MAXHOSTNAMELEN + 1];
5317 char fname[MAXHOSTNAMELEN + MAXHOSTNAMELEN + 1];
5318 const mib2_sctpConnRemoteEntry_t *sre = NULL;
5319 const mib2_sctpConnLocalEntry_t *sle = NULL;
5320 const mib_item_t *local = head;
5321 const mib_item_t *remote = head;
5322 uint32_t id = sp->sctpAssocId;
5323 boolean_t printfirst = B_TRUE;
5324
5325 sctp_pr_addr(sp->sctpAssocRemPrimAddrType, fname, sizeof (fname),
5326 &sp->sctpAssocRemPrimAddr, sp->sctpAssocRemPort);
5327 sctp_pr_addr(sp->sctpAssocRemPrimAddrType, lname, sizeof (lname),
5328 &sp->sctpAssocLocPrimAddr, sp->sctpAssocLocalPort);
5329
5330 (void) printf("%-31s %-31s %6u %6d %6u %6d %3d/%-3d %s\n",
5331 lname, fname,
5332 sp->sctpConnEntryInfo.ce_swnd,
5333 sp->sctpConnEntryInfo.ce_sendq,
5334 sp->sctpConnEntryInfo.ce_rwnd,
5335 sp->sctpConnEntryInfo.ce_recvq,
5336 sp->sctpAssocInStreams, sp->sctpAssocOutStreams,
5337 nssctp_state(sp->sctpAssocState, attr));
5338
5339 print_transport_label(attr);
5340
5341 if (!Vflag) {
5342 return;
5343 }
5344
5345 /* Print remote addresses/local addresses on following lines */
5346 while ((sre = sctp_getnext_rem(&remote, sre, id)) != NULL) {
5347 if (!IN6_ARE_ADDR_EQUAL(&sre->sctpAssocRemAddr,
5348 &sp->sctpAssocRemPrimAddr)) {
5349 if (printfirst == B_TRUE) {
5350 (void) fputs("\t<Remote: ", stdout);
5351 printfirst = B_FALSE;
5352 } else {
5353 (void) fputs(", ", stdout);
5354 }
5355 sctp_pr_addr(sre->sctpAssocRemAddrType, fname,
5356 sizeof (fname), &sre->sctpAssocRemAddr, -1);
5357 if (sre->sctpAssocRemAddrActive == MIB2_SCTP_ACTIVE) {
5358 (void) fputs(fname, stdout);
5359 } else {
5360 (void) printf("(%s)", fname);
5361 }
5362 }
5365 (void) puts(">");
5366 printfirst = B_TRUE;
5367 }
5368 while ((sle = sctp_getnext_local(&local, sle, id)) != NULL) {
5369 if (!IN6_ARE_ADDR_EQUAL(&sle->sctpAssocLocalAddr,
5370 &sp->sctpAssocLocPrimAddr)) {
5371 if (printfirst == B_TRUE) {
5372 (void) fputs("\t<Local: ", stdout);
5373 printfirst = B_FALSE;
5374 } else {
5375 (void) fputs(", ", stdout);
5376 }
5377 sctp_pr_addr(sle->sctpAssocLocalAddrType, lname,
5378 sizeof (lname), &sle->sctpAssocLocalAddr, -1);
5379 (void) fputs(lname, stdout);
5380 }
5381 }
5382 if (printfirst == B_FALSE) {
5383 (void) puts(">");
5384 }
5385 }
5386
5387 static void
5388 sctp_report(const mib_item_t *item)
5389 {
5390 const mib_item_t *head;
5391 const mib2_sctpConnEntry_t *sp;
5392 boolean_t first = B_TRUE;
5393 mib2_transportMLPEntry_t **attrs, **aptr;
5394 mib2_transportMLPEntry_t *attr;
5395
5396 /*
5397 * Preparation pass: the kernel returns separate entries for SCTP
5398 * connection table entries and Multilevel Port attributes. We loop
5399 * through the attributes first and set up an array for each address
5400 * family.
5401 */
5402 attrs = RSECflag ?
5403 gather_attrs(item, MIB2_SCTP, MIB2_SCTP_CONN, sctpEntrySize) :
5404 NULL;
5405
5406 aptr = attrs;
5407 head = item;
5408 for (; item != NULL; item = item->next_item) {
5409
5410 if (!(item->group == MIB2_SCTP &&
5411 item->mib_id == MIB2_SCTP_CONN))
5412 continue;
5413
5414 for (sp = item->valp;
5415 (char *)sp < (char *)item->valp + item->length;
5416 /* LINTED: (note 1) */
5417 sp = (mib2_sctpConnEntry_t *)((char *)sp + sctpEntrySize)) {
5418 attr = aptr == NULL ? NULL : *aptr++;
5419 if (Aflag ||
5420 sp->sctpAssocState >= MIB2_SCTP_established) {
5421 if (first == B_TRUE) {
5422 (void) puts(sctp_hdr);
5423 (void) puts(sctp_hdr_normal);
5424 first = B_FALSE;
5425 }
5426 sctp_conn_report_item(head, sp, attr);
5427 }
5428 }
5429 }
5430 if (attrs != NULL)
5431 free(attrs);
5432 }
5433
5434 static char *
5435 plural(int n)
5436 {
5437 return (n != 1 ? "s" : "");
5438 }
5439
5440 static char *
5441 pluraly(int n)
5442 {
5443 return (n != 1 ? "ies" : "y");
5444 }
5445
5446 static char *
6394 }
6395 return (B_FALSE);
6396 }
6397
6398 /*
6399 * Convert the interface index to a string using the buffer `ifname', which
6400 * must be at least LIFNAMSIZ bytes. We first try to map it to name. If that
6401 * fails (e.g., because we're inside a zone and it does not have access to
6402 * interface for the index in question), just return "if#<num>".
6403 */
6404 static char *
6405 ifindex2str(uint_t ifindex, char *ifname)
6406 {
6407 if (if_indextoname(ifindex, ifname) == NULL)
6408 (void) snprintf(ifname, LIFNAMSIZ, "if#%d", ifindex);
6409
6410 return (ifname);
6411 }
6412
6413 /*
6414 * print the usage line
6415 */
6416 static void
6417 usage(char *cmdname)
6418 {
6419 (void) fprintf(stderr, "usage: %s [-anv] [-f address_family] "
6420 "[-T d|u]\n", cmdname);
6421 (void) fprintf(stderr, " %s [-n] [-f address_family] "
6422 "[-P protocol] [-T d|u] [-g | -p | -s [interval [count]]]\n",
6423 cmdname);
6424 (void) fprintf(stderr, " %s -m [-v] [-T d|u] "
6425 "[interval [count]]\n", cmdname);
6426 (void) fprintf(stderr, " %s -i [-I interface] [-an] "
6427 "[-f address_family] [-T d|u] [interval [count]]\n", cmdname);
6428 (void) fprintf(stderr, " %s -r [-anv] "
6429 "[-f address_family|filter] [-T d|u]\n", cmdname);
6430 (void) fprintf(stderr, " %s -M [-ns] [-f address_family] "
6431 "[-T d|u]\n", cmdname);
6432 (void) fprintf(stderr, " %s -D [-I interface] "
6433 "[-f address_family] [-T d|u]\n", cmdname);
6434 exit(EXIT_FAILURE);
6435 }
6436
6437 /*
6438 * fatal: print error message to stderr and
6439 * call exit(errcode)
6440 */
6441 /*PRINTFLIKE2*/
6442 static void
6443 fatal(int errcode, char *format, ...)
6444 {
6445 va_list argp;
6446
6447 if (format == NULL)
6448 return;
6449
6450 va_start(argp, format);
6451 (void) vfprintf(stderr, format, argp);
6452 va_end(argp);
6453
6454 exit(errcode);
6455 }
|
38 * because they have 'continue' or 'break' statements in their
39 * bodies. 'continue' statements have been used inside some loops
40 * where avoiding them would have led to deep levels of indentation.
41 *
42 * TODO:
43 * Add ability to request subsets from kernel (with level = MIB2_IP;
44 * name = 0 meaning everything for compatibility)
45 */
46
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <stdarg.h>
50 #include <unistd.h>
51 #include <strings.h>
52 #include <string.h>
53 #include <errno.h>
54 #include <ctype.h>
55 #include <kstat.h>
56 #include <assert.h>
57 #include <locale.h>
58 #include <pwd.h>
59 #include <limits.h>
60
61 #include <sys/types.h>
62 #include <sys/stat.h>
63 #include <sys/stream.h>
64 #include <stropts.h>
65 #include <sys/strstat.h>
66 #include <sys/tihdr.h>
67 #include <procfs.h>
68
69 #include <sys/socket.h>
70 #include <sys/socketvar.h>
71 #include <sys/sockio.h>
72 #include <netinet/in.h>
73 #include <net/if.h>
74 #include <net/route.h>
75
76 #include <inet/mib2.h>
77 #include <inet/ip.h>
78 #include <inet/arp.h>
79 #include <inet/tcp.h>
80 #include <netinet/igmp_var.h>
81 #include <netinet/ip_mroute.h>
82
83 #include <arpa/inet.h>
84 #include <netdb.h>
85 #include <fcntl.h>
86 #include <sys/systeminfo.h>
87 #include <arpa/inet.h>
88
89 #include <netinet/dhcp.h>
90 #include <dhcpagent_ipc.h>
91 #include <dhcpagent_util.h>
92 #include <compat.h>
93
94 #include <libtsnet.h>
95 #include <tsol/label.h>
96
97 #include "statcommon.h"
98
99
100 #define STR_EXPAND 4
101
102 #define V4MASK_TO_V6(v4, v6) ((v6)._S6_un._S6_u32[0] = 0xfffffffful, \
103 (v6)._S6_un._S6_u32[1] = 0xfffffffful, \
104 (v6)._S6_un._S6_u32[2] = 0xfffffffful, \
105 (v6)._S6_un._S6_u32[3] = (v4))
106
107 #define IN6_IS_V4MASK(v6) ((v6)._S6_un._S6_u32[0] == 0xfffffffful && \
108 (v6)._S6_un._S6_u32[1] == 0xfffffffful && \
109 (v6)._S6_un._S6_u32[2] == 0xfffffffful)
110
111 /*
112 * This is used as a cushion in the buffer allocation directed by SIOCGLIFNUM.
113 * Because there's no locking between SIOCGLIFNUM and SIOCGLIFCONF, it's
114 * possible for an administrator to plumb new interfaces between those two
115 * calls, resulting in the failure of the latter. This addition makes that
116 * less likely.
117 */
118 #define LIFN_GUARD_VALUE 10
122 int group;
123 int mib_id;
124 int length;
125 void *valp;
126 } mib_item_t;
127
128 struct ifstat {
129 uint64_t ipackets;
130 uint64_t ierrors;
131 uint64_t opackets;
132 uint64_t oerrors;
133 uint64_t collisions;
134 };
135
136 struct iflist {
137 struct iflist *next_if;
138 char ifname[LIFNAMSIZ];
139 struct ifstat tot;
140 };
141
142 typedef struct proc_info {
143 char *pr_user;
144 char *pr_fname;
145 char *pr_psargs;
146 } proc_info_t;
147
148 static mib_item_t *mibget(int sd);
149 static void mibfree(mib_item_t *firstitem);
150 static int mibopen(void);
151 static void mib_get_constants(mib_item_t *item);
152 static mib_item_t *mib_item_dup(mib_item_t *item);
153 static mib_item_t *mib_item_diff(mib_item_t *item1,
154 mib_item_t *item2);
155 static void mib_item_destroy(mib_item_t **item);
156
157 static boolean_t octetstrmatch(const Octet_t *a, const Octet_t *b);
158 static char *octetstr(const Octet_t *op, int code,
159 char *dst, uint_t dstlen);
160 static char *pr_addr(uint_t addr,
161 char *dst, uint_t dstlen);
162 static char *pr_addrnz(ipaddr_t addr, char *dst, uint_t dstlen);
163 static char *pr_addr6(const in6_addr_t *addr,
164 char *dst, uint_t dstlen);
165 static char *pr_mask(uint_t addr,
166 char *dst, uint_t dstlen);
167 static char *pr_prefix6(const struct in6_addr *addr,
184 const mib2_transportMLPEntry_t *attr);
185
186 static void stat_report(mib_item_t *item);
187 static void mrt_stat_report(mib_item_t *item);
188 static void arp_report(mib_item_t *item);
189 static void ndp_report(mib_item_t *item);
190 static void mrt_report(mib_item_t *item);
191 static void if_stat_total(struct ifstat *oldstats,
192 struct ifstat *newstats, struct ifstat *sumstats);
193 static void if_report(mib_item_t *item, char *ifname,
194 int Iflag_only, boolean_t once_only);
195 static void if_report_ip4(mib2_ipAddrEntry_t *ap,
196 char ifname[], char logintname[],
197 struct ifstat *statptr, boolean_t ksp_not_null);
198 static void if_report_ip6(mib2_ipv6AddrEntry_t *ap6,
199 char ifname[], char logintname[],
200 struct ifstat *statptr, boolean_t ksp_not_null);
201 static void ire_report(const mib_item_t *item);
202 static void tcp_report(const mib_item_t *item);
203 static void udp_report(const mib_item_t *item);
204 static void uds_report(kstat_ctl_t *);
205 static void group_report(mib_item_t *item);
206 static void dce_report(mib_item_t *item);
207 static void print_ip_stats(mib2_ip_t *ip);
208 static void print_icmp_stats(mib2_icmp_t *icmp);
209 static void print_ip6_stats(mib2_ipv6IfStatsEntry_t *ip6);
210 static void print_icmp6_stats(mib2_ipv6IfIcmpEntry_t *icmp6);
211 static void print_sctp_stats(mib2_sctp_t *tcp);
212 static void print_tcp_stats(mib2_tcp_t *tcp);
213 static void print_udp_stats(mib2_udp_t *udp);
214 static void print_rawip_stats(mib2_rawip_t *rawip);
215 static void print_igmp_stats(struct igmpstat *igps);
216 static void print_mrt_stats(struct mrtstat *mrts);
217 static void sctp_report(const mib_item_t *item);
218 static void sum_ip6_stats(mib2_ipv6IfStatsEntry_t *ip6,
219 mib2_ipv6IfStatsEntry_t *sum6);
220 static void sum_icmp6_stats(mib2_ipv6IfIcmpEntry_t *icmp6,
221 mib2_ipv6IfIcmpEntry_t *sum6);
222 static void m_report(void);
223 static void dhcp_report(char *);
224
225 static uint64_t kstat_named_value(kstat_t *, char *);
226 static kid_t safe_kstat_read(kstat_ctl_t *, kstat_t *, void *);
227 static int isnum(char *);
228 static char *plural(int n);
229 static char *pluraly(int n);
230 static char *plurales(int n);
231 static void process_filter(char *arg);
232 static char *ifindex2str(uint_t, char *);
233 static boolean_t family_selected(int family);
234
235 static void usage(char *);
236 static char *get_username(uid_t);
237 proc_info_t *get_proc_info(pid_t);
238 static void fatal(int errcode, char *str1, ...);
239
240 #define PLURAL(n) plural((int)n)
241 #define PLURALY(n) pluraly((int)n)
242 #define PLURALES(n) plurales((int)n)
243 #define IFLAGMOD(flg, val1, val2) if (flg == val1) flg = val2
244 #define MDIFF(diff, elem2, elem1, member) (diff)->member = \
245 (elem2)->member - (elem1)->member
246
247
248 static boolean_t Aflag = B_FALSE; /* All sockets/ifs/rtng-tbls */
249 static boolean_t Dflag = B_FALSE; /* DCE info */
250 static boolean_t Iflag = B_FALSE; /* IP Traffic Interfaces */
251 static boolean_t Mflag = B_FALSE; /* STREAMS Memory Statistics */
252 static boolean_t Nflag = B_FALSE; /* Numeric Network Addresses */
253 static boolean_t Rflag = B_FALSE; /* Routing Tables */
254 static boolean_t RSECflag = B_FALSE; /* Security attributes */
255 static boolean_t Sflag = B_FALSE; /* Per-protocol Statistics */
256 static boolean_t Vflag = B_FALSE; /* Verbose */
257 static boolean_t Uflag = B_FALSE; /* Show PID and UID info. */
258 static boolean_t Pflag = B_FALSE; /* Net to Media Tables */
259 static boolean_t Gflag = B_FALSE; /* Multicast group membership */
260 static boolean_t MMflag = B_FALSE; /* Multicast routing table */
261 static boolean_t DHCPflag = B_FALSE; /* DHCP statistics */
262 static boolean_t Xflag = B_FALSE; /* Debug Info */
263
264 static int v4compat = 0; /* Compatible printing format for status */
265
266 static int proto = IPPROTO_MAX; /* all protocols */
267 kstat_ctl_t *kc = NULL;
268
269 /*
270 * Sizes of data structures extracted from the base mib.
271 * This allows the size of the tables entries to grow while preserving
272 * binary compatibility.
273 */
274 static int ipAddrEntrySize;
275 static int ipRouteEntrySize;
276 static int ipNetToMediaEntrySize;
277 static int ipMemberEntrySize;
382 * 1, IFlag is the only feature-flag enabled
383 * : trinary variable, modified using IFLAGMOD()
384 */
385 int Iflag_only = -1;
386 boolean_t once_only = B_FALSE; /* '-i' with count > 1 */
387 extern char *optarg;
388 extern int optind;
389 char *default_ip_str = NULL;
390
391 name = argv[0];
392
393 v4compat = get_compat_flag(&default_ip_str);
394 if (v4compat == DEFAULT_PROT_BAD_VALUE)
395 fatal(2, "%s: %s: Bad value for %s in %s\n", name,
396 default_ip_str, DEFAULT_IP, INET_DEFAULT_FILE);
397 free(default_ip_str);
398
399 (void) setlocale(LC_ALL, "");
400 (void) textdomain(TEXT_DOMAIN);
401
402 while ((c = getopt(argc, argv, "adimnrspMgvuxf:P:I:DRT:")) != -1) {
403 switch ((char)c) {
404 case 'a': /* all connections */
405 Aflag = B_TRUE;
406 break;
407
408 case 'd': /* DCE info */
409 Dflag = B_TRUE;
410 IFLAGMOD(Iflag_only, 1, 0); /* see macro def'n */
411 break;
412
413 case 'i': /* interface (ill/ipif report) */
414 Iflag = B_TRUE;
415 IFLAGMOD(Iflag_only, -1, 1); /* '-i' exists */
416 break;
417
418 case 'm': /* streams msg report */
419 Mflag = B_TRUE;
420 IFLAGMOD(Iflag_only, 1, 0); /* see macro def'n */
421 break;
422
442 case 'p': /* arp/ndp table */
443 Pflag = B_TRUE;
444 IFLAGMOD(Iflag_only, 1, 0); /* see macro def'n */
445 break;
446
447 case 'M': /* multicast routing tables */
448 MMflag = B_TRUE;
449 IFLAGMOD(Iflag_only, 1, 0); /* see macro def'n */
450 break;
451
452 case 'g': /* multicast group membership */
453 Gflag = B_TRUE;
454 IFLAGMOD(Iflag_only, 1, 0); /* see macro def'n */
455 break;
456
457 case 'v': /* verbose output format */
458 Vflag = B_TRUE;
459 IFLAGMOD(Iflag_only, 1, 0); /* see macro def'n */
460 break;
461
462 case 'u': /* show pid and uid information */
463 Uflag = B_TRUE;
464 break;
465
466 case 'x': /* turn on debugging */
467 Xflag = B_TRUE;
468 break;
469
470 case 'f':
471 process_filter(optarg);
472 break;
473
474 case 'P':
475 if (strcmp(optarg, "ip") == 0) {
476 proto = IPPROTO_IP;
477 } else if (strcmp(optarg, "ipv6") == 0 ||
478 strcmp(optarg, "ip6") == 0) {
479 v4compat = 0; /* Overridden */
480 proto = IPPROTO_IPV6;
481 } else if (strcmp(optarg, "icmp") == 0) {
482 proto = IPPROTO_ICMP;
483 } else if (strcmp(optarg, "icmpv6") == 0 ||
484 strcmp(optarg, "icmp6") == 0) {
485 v4compat = 0; /* Overridden */
655 if (MMflag)
656 mrt_report(item);
657 }
658 if (Gflag)
659 group_report(item);
660 if (Pflag) {
661 if (family_selected(AF_INET))
662 arp_report(item);
663 if (family_selected(AF_INET6))
664 ndp_report(item);
665 }
666 if (Dflag)
667 dce_report(item);
668 mib_item_destroy(&curritem);
669 }
670
671 /* netstat: AF_UNIX behaviour */
672 if (family_selected(AF_UNIX) &&
673 (!(Dflag || Iflag || Rflag || Sflag || Mflag ||
674 MMflag || Pflag || Gflag)))
675 uds_report(kc);
676 (void) kstat_close(kc);
677
678 /* iteration handling code */
679 if (count > 0 && --count == 0)
680 break;
681 (void) sleep(interval);
682
683 /* re-populating of data structures */
684 if (family_selected(AF_INET) || family_selected(AF_INET6)) {
685 if (Sflag) {
686 /* previtem is a cut-down list */
687 previtem = mib_item_dup(item);
688 if (previtem == NULL)
689 fatal(1, "can't process mib data, "
690 "out of memory\n");
691 }
692 mibfree(item);
693 (void) close(sd);
694 if ((sd = mibopen()) == -1)
695 fatal(1, "can't open mib stream anymore\n");
4743 free(sl_str);
4744 }
4745 }
4746
4747 /* ------------------------------ TCP_REPORT------------------------------- */
4748
4749 static const char tcp_hdr_v4[] =
4750 "\nTCP: IPv4\n";
4751 static const char tcp_hdr_v4_compat[] =
4752 "\nTCP\n";
4753 static const char tcp_hdr_v4_verbose[] =
4754 "Local/Remote Address Swind Snext Suna Rwind Rnext Rack "
4755 " Rto Mss State\n"
4756 "-------------------- ----- -------- -------- ----- -------- -------- "
4757 "----- ----- -----------\n";
4758 static const char tcp_hdr_v4_normal[] =
4759 " Local Address Remote Address Swind Send-Q Rwind Recv-Q "
4760 " State\n"
4761 "-------------------- -------------------- ----- ------ ----- ------ "
4762 "-----------\n";
4763 static const char tcp_hdr_v4_pid[] =
4764 " Local Address Remote Address User Pid Command Swind"
4765 " Send-Q Rwind Recv-Q State\n"
4766 "-------------------- -------------------- -------- ------ ------------- ------"
4767 "- ------ ------- ------ -----------\n";
4768 static const char tcp_hdr_v4_pid_verbose[] =
4769 "Local/Remote Address Swind Snext Suna Rwind Rnext Rack Rto "
4770 " Mss State User Pid Command\n"
4771 "-------------------- ------- -------- -------- ------- -------- -------- -----"
4772 " ----- ----------- -------- ------ --------------\n";
4773
4774 static const char tcp_hdr_v6[] =
4775 "\nTCP: IPv6\n";
4776 static const char tcp_hdr_v6_verbose[] =
4777 "Local/Remote Address Swind Snext Suna Rwind Rnext "
4778 " Rack Rto Mss State If\n"
4779 "--------------------------------- ----- -------- -------- ----- -------- "
4780 "-------- ----- ----- ----------- -----\n";
4781 static const char tcp_hdr_v6_normal[] =
4782 " Local Address Remote Address "
4783 "Swind Send-Q Rwind Recv-Q State If\n"
4784 "--------------------------------- --------------------------------- "
4785 "----- ------ ----- ------ ----------- -----\n";
4786 static const char tcp_hdr_v6_pid[] =
4787 " Local Address Remote Address User"
4788 " Pid Command Swind Send-Q Rwind Recv-Q State If\n"
4789 "--------------------------------- --------------------------------- --------"
4790 " ------ -------------- ------- ------ ------- ------ ----------- -----\n";
4791 static const char tcp_hdr_v6_pid_verbose[] =
4792 "Local/Remote Address Swind Snext Suna Rwind Rnext"
4793 " Rack Rto Mss State If User Pid Command\n"
4794 "--------------------------------- ------- -------- -------- ------- --------"
4795 " -------- ----- ----- ----------- ----- -------- ------ --------------\n";
4796
4797 static boolean_t tcp_report_item_v4(const mib2_tcpConnEntry_t *,
4798 conn_pid_info_t *, boolean_t first,
4799 const mib2_transportMLPEntry_t *);
4800 static boolean_t tcp_report_item_v6(const mib2_tcp6ConnEntry_t *,
4801 conn_pid_info_t *, boolean_t first,
4802 const mib2_transportMLPEntry_t *);
4803
4804
4805 static void
4806 tcp_report(const mib_item_t *item)
4807 {
4808 int jtemp = 0;
4809 boolean_t print_hdr_once_v4 = B_TRUE;
4810 boolean_t print_hdr_once_v6 = B_TRUE;
4811 mib2_tcpConnEntry_t *tp;
4812 mib2_tcp6ConnEntry_t *tp6;
4813 mib2_transportMLPEntry_t **v4_attrs, **v6_attrs;
4814 mib2_transportMLPEntry_t **v4a, **v6a;
4815 mib2_transportMLPEntry_t *aptr;
4816 conn_pid_info_t *cpi;
4817
4818 if (!protocol_selected(IPPROTO_TCP))
4819 return;
4820
4821 /*
4822 * Preparation pass: the kernel returns separate entries for TCP
4823 * connection table entries and Multilevel Port attributes. We loop
4824 * through the attributes first and set up an array for each address
4825 * family.
4826 */
4827 v4_attrs = family_selected(AF_INET) && RSECflag ?
4828 gather_attrs(item, MIB2_TCP, MIB2_TCP_CONN, tcpConnEntrySize) :
4829 NULL;
4830 v6_attrs = family_selected(AF_INET6) && RSECflag ?
4831 gather_attrs(item, MIB2_TCP6, MIB2_TCP6_CONN, tcp6ConnEntrySize) :
4832 NULL;
4833
4834 /* 'for' loop 1: */
4835 v4a = v4_attrs;
4836 v6a = v6_attrs;
4837 for (; item != NULL; item = item->next_item) {
4838 if (Xflag) {
4839 (void) printf("\n--- Entry %d ---\n", ++jtemp);
4840 (void) printf("Group = %d, mib_id = %d, "
4841 "length = %d, valp = 0x%p\n",
4842 item->group, item->mib_id,
4843 item->length, item->valp);
4844 }
4845
4846 if (!((item->group == MIB2_TCP &&
4847 item->mib_id == MIB2_TCP_CONN) ||
4848 (item->group == MIB2_TCP6 &&
4849 item->mib_id == MIB2_TCP6_CONN) ||
4850 (item->group == MIB2_TCP &&
4851 item->mib_id == EXPER_XPORT_PROC_INFO) ||
4852 (item->group == MIB2_TCP6 &&
4853 item->mib_id == EXPER_XPORT_PROC_INFO)))
4854 continue; /* 'for' loop 1 */
4855
4856 if (item->group == MIB2_TCP && !family_selected(AF_INET))
4857 continue; /* 'for' loop 1 */
4858 else if (item->group == MIB2_TCP6 && !family_selected(AF_INET6))
4859 continue; /* 'for' loop 1 */
4860
4861 if ((!Uflag) && item->group == MIB2_TCP &&
4862 item->mib_id == MIB2_TCP_CONN) {
4863 for (tp = (mib2_tcpConnEntry_t *)item->valp;
4864 (char *)tp < (char *)item->valp + item->length;
4865 /* LINTED: (note 1) */
4866 tp = (mib2_tcpConnEntry_t *)((char *)tp +
4867 tcpConnEntrySize)) {
4868 aptr = v4a == NULL ? NULL : *v4a++;
4869 print_hdr_once_v4 = tcp_report_item_v4(tp,
4870 NULL, print_hdr_once_v4, aptr);
4871 }
4872 } else if ((!Uflag) && item->group == MIB2_TCP6 &&
4873 item->mib_id == MIB2_TCP6_CONN) {
4874 for (tp6 = (mib2_tcp6ConnEntry_t *)item->valp;
4875 (char *)tp6 < (char *)item->valp + item->length;
4876 /* LINTED: (note 1) */
4877 tp6 = (mib2_tcp6ConnEntry_t *)((char *)tp6 +
4878 tcp6ConnEntrySize)) {
4879 aptr = v6a == NULL ? NULL : *v6a++;
4880 print_hdr_once_v6 = tcp_report_item_v6(tp6,
4881 NULL, print_hdr_once_v6, aptr);
4882 }
4883 } else if ((Uflag) && item->group == MIB2_TCP &&
4884 item->mib_id == EXPER_XPORT_PROC_INFO) {
4885 for (tp = (mib2_tcpConnEntry_t *)item->valp;
4886 (char *)tp < (char *)item->valp + item->length;
4887 /* LINTED: (note 1) */
4888 tp = (mib2_tcpConnEntry_t *)((char *)cpi +
4889 cpi->cpi_tot_size)) {
4890 aptr = v4a == NULL ? NULL : *v4a++;
4891 /* LINTED: (note 1) */
4892 cpi = (conn_pid_info_t *) ((char *)tp +
4893 tcpConnEntrySize);
4894 print_hdr_once_v4 = tcp_report_item_v4(tp,
4895 cpi, print_hdr_once_v4, aptr);
4896 }
4897 } else if ((Uflag) && item->group == MIB2_TCP6 &&
4898 item->mib_id == EXPER_XPORT_PROC_INFO) {
4899 for (tp6 = (mib2_tcp6ConnEntry_t *)item->valp;
4900 (char *)tp6 < (char *)item->valp + item->length;
4901 /* LINTED: (note 1) */
4902 tp6 = (mib2_tcp6ConnEntry_t *)((char *)cpi +
4903 cpi->cpi_tot_size)) {
4904 aptr = v6a == NULL ? NULL : *v6a++;
4905 /* LINTED: (note 1) */
4906 cpi = (conn_pid_info_t *) ((char *)tp6 +
4907 tcp6ConnEntrySize);
4908 print_hdr_once_v6 = tcp_report_item_v6(tp6,
4909 cpi, print_hdr_once_v6, aptr);
4910 }
4911 }
4912
4913 } /* 'for' loop 1 ends */
4914 (void) fflush(stdout);
4915
4916 if (v4_attrs != NULL)
4917 free(v4_attrs);
4918 if (v6_attrs != NULL)
4919 free(v6_attrs);
4920 }
4921
4922 static boolean_t
4923 tcp_report_item_v4(const mib2_tcpConnEntry_t *tp, conn_pid_info_t * cpi,
4924 boolean_t first, const mib2_transportMLPEntry_t *attr)
4925 {
4926 /*
4927 * lname and fname below are for the hostname as well as the portname
4928 * There is no limit on portname length so we assume MAXHOSTNAMELEN
4929 * as the limit
4930 */
4931 char lname[MAXHOSTNAMELEN + MAXHOSTNAMELEN + 1];
4932 char fname[MAXHOSTNAMELEN + MAXHOSTNAMELEN + 1];
4933
4934
4935 if (!(Aflag || tp->tcpConnEntryInfo.ce_state >= TCPS_ESTABLISHED))
4936 return (first); /* Nothing to print */
4937
4938 if (first) {
4939 (void) printf(v4compat ? tcp_hdr_v4_compat : tcp_hdr_v4);
4940 if (Uflag)
4941 (void) printf(Vflag ? tcp_hdr_v4_pid_verbose :
4942 tcp_hdr_v4_pid);
4943 else
4944 (void) printf(Vflag ? tcp_hdr_v4_verbose :
4945 tcp_hdr_v4_normal);
4946 }
4947
4948 if ((!Uflag) && Vflag) {
4949 (void) printf("%-20s\n%-20s %5u %08x %08x %5u %08x %08x "
4950 "%5u %5u %s\n",
4951 pr_ap(tp->tcpConnLocalAddress,
4952 tp->tcpConnLocalPort, "tcp", lname, sizeof (lname)),
4953 pr_ap(tp->tcpConnRemAddress,
4954 tp->tcpConnRemPort, "tcp", fname, sizeof (fname)),
4955 tp->tcpConnEntryInfo.ce_swnd,
4956 tp->tcpConnEntryInfo.ce_snxt,
4957 tp->tcpConnEntryInfo.ce_suna,
4958 tp->tcpConnEntryInfo.ce_rwnd,
4959 tp->tcpConnEntryInfo.ce_rnxt,
4960 tp->tcpConnEntryInfo.ce_rack,
4961 tp->tcpConnEntryInfo.ce_rto,
4962 tp->tcpConnEntryInfo.ce_mss,
4963 mitcp_state(tp->tcpConnEntryInfo.ce_state, attr));
4964 } else if ((!Uflag) && (!Vflag)) {
4965 int sq = (int)tp->tcpConnEntryInfo.ce_snxt -
4966 (int)tp->tcpConnEntryInfo.ce_suna - 1;
4967 int rq = (int)tp->tcpConnEntryInfo.ce_rnxt -
4968 (int)tp->tcpConnEntryInfo.ce_rack;
4969
4970 (void) printf("%-20s %-20s %5u %6d %5u %6d %s\n",
4971 pr_ap(tp->tcpConnLocalAddress,
4972 tp->tcpConnLocalPort, "tcp", lname, sizeof (lname)),
4973 pr_ap(tp->tcpConnRemAddress,
4974 tp->tcpConnRemPort, "tcp", fname, sizeof (fname)),
4975 tp->tcpConnEntryInfo.ce_swnd,
4976 (sq >= 0) ? sq : 0,
4977 tp->tcpConnEntryInfo.ce_rwnd,
4978 (rq >= 0) ? rq : 0,
4979 mitcp_state(tp->tcpConnEntryInfo.ce_state, attr));
4980 } else if (Uflag && Vflag) {
4981 int i = 0;
4982 pid_t *pids = cpi->cpi_pids;
4983 proc_info_t *pinfo;
4984 do {
4985 pinfo = get_proc_info(*pids);
4986 (void) printf("%-20s\n%-20s %7u %08x %08x %7u %08x %08x "
4987 "%5u %5u %-11s %-8.8s %6u %s\n",
4988 pr_ap(tp->tcpConnLocalAddress,
4989 tp->tcpConnLocalPort, "tcp", lname, sizeof (lname)),
4990 pr_ap(tp->tcpConnRemAddress,
4991 tp->tcpConnRemPort, "tcp", fname, sizeof (fname)),
4992 tp->tcpConnEntryInfo.ce_swnd,
4993 tp->tcpConnEntryInfo.ce_snxt,
4994 tp->tcpConnEntryInfo.ce_suna,
4995 tp->tcpConnEntryInfo.ce_rwnd,
4996 tp->tcpConnEntryInfo.ce_rnxt,
4997 tp->tcpConnEntryInfo.ce_rack,
4998 tp->tcpConnEntryInfo.ce_rto,
4999 tp->tcpConnEntryInfo.ce_mss,
5000 mitcp_state(tp->tcpConnEntryInfo.ce_state, attr),
5001 pinfo->pr_user, (int)*pids, pinfo->pr_psargs);
5002 i++; pids++;
5003 } while (i < cpi->cpi_pids_cnt);
5004 } else if (Uflag && (!Vflag)) {
5005 int sq = (int)tp->tcpConnEntryInfo.ce_snxt -
5006 (int)tp->tcpConnEntryInfo.ce_suna - 1;
5007 int rq = (int)tp->tcpConnEntryInfo.ce_rnxt -
5008 (int)tp->tcpConnEntryInfo.ce_rack;
5009 int i = 0;
5010 pid_t *pids = cpi->cpi_pids;
5011 proc_info_t *pinfo;
5012 do {
5013 pinfo = get_proc_info(*pids);
5014 (void) printf("%-20s %-20s %-8.8s %6u %-13.13s %7u %6d %7u %6d %s\n",
5015 pr_ap(tp->tcpConnLocalAddress,
5016 tp->tcpConnLocalPort, "tcp", lname, sizeof (lname)),
5017 pr_ap(tp->tcpConnRemAddress,
5018 tp->tcpConnRemPort, "tcp", fname, sizeof (fname)),
5019 pinfo->pr_user, (int)*pids, pinfo->pr_fname,
5020 tp->tcpConnEntryInfo.ce_swnd,
5021 (sq >= 0) ? sq : 0,
5022 tp->tcpConnEntryInfo.ce_rwnd,
5023 (rq >= 0) ? rq : 0,
5024 mitcp_state(tp->tcpConnEntryInfo.ce_state, attr));
5025 i++; pids++;
5026 } while (i < cpi->cpi_pids_cnt);
5027 }
5028
5029 print_transport_label(attr);
5030
5031 return (B_FALSE);
5032 }
5033
5034 static boolean_t
5035 tcp_report_item_v6(const mib2_tcp6ConnEntry_t *tp6, conn_pid_info_t *cpi,
5036 boolean_t first, const mib2_transportMLPEntry_t *attr)
5037 {
5038 /*
5039 * lname and fname below are for the hostname as well as the portname
5040 * There is no limit on portname length so we assume MAXHOSTNAMELEN
5041 * as the limit
5042 */
5043 char lname[MAXHOSTNAMELEN + MAXHOSTNAMELEN + 1];
5044 char fname[MAXHOSTNAMELEN + MAXHOSTNAMELEN + 1];
5045 char ifname[LIFNAMSIZ + 1];
5046 char *ifnamep;
5047
5048 if (!(Aflag || tp6->tcp6ConnEntryInfo.ce_state >= TCPS_ESTABLISHED))
5049 return (first); /* Nothing to print */
5050
5051 if (first) {
5052 (void) printf(tcp_hdr_v6);
5053 if (Uflag)
5054 (void) printf(Vflag ? tcp_hdr_v6_pid_verbose :
5055 tcp_hdr_v6_pid);
5056 else
5057 (void) printf(Vflag ? tcp_hdr_v6_verbose :
5058 tcp_hdr_v6_normal);
5059 }
5060
5061 ifnamep = (tp6->tcp6ConnIfIndex != 0) ?
5062 if_indextoname(tp6->tcp6ConnIfIndex, ifname) : NULL;
5063 if (ifnamep == NULL)
5064 ifnamep = "";
5065
5066 if ((!Uflag) && Vflag) {
5067 (void) printf("%-33s\n%-33s %5u %08x %08x %5u %08x %08x "
5068 "%5u %5u %-11s %s\n",
5069 pr_ap6(&tp6->tcp6ConnLocalAddress,
5070 tp6->tcp6ConnLocalPort, "tcp", lname, sizeof (lname)),
5071 pr_ap6(&tp6->tcp6ConnRemAddress,
5072 tp6->tcp6ConnRemPort, "tcp", fname, sizeof (fname)),
5073 tp6->tcp6ConnEntryInfo.ce_swnd,
5074 tp6->tcp6ConnEntryInfo.ce_snxt,
5075 tp6->tcp6ConnEntryInfo.ce_suna,
5076 tp6->tcp6ConnEntryInfo.ce_rwnd,
5077 tp6->tcp6ConnEntryInfo.ce_rnxt,
5078 tp6->tcp6ConnEntryInfo.ce_rack,
5079 tp6->tcp6ConnEntryInfo.ce_rto,
5080 tp6->tcp6ConnEntryInfo.ce_mss,
5081 mitcp_state(tp6->tcp6ConnEntryInfo.ce_state, attr),
5082 ifnamep);
5083 } else if ((!Uflag) && (!Vflag)) {
5084 int sq = (int)tp6->tcp6ConnEntryInfo.ce_snxt -
5085 (int)tp6->tcp6ConnEntryInfo.ce_suna - 1;
5086 int rq = (int)tp6->tcp6ConnEntryInfo.ce_rnxt -
5087 (int)tp6->tcp6ConnEntryInfo.ce_rack;
5088
5089 (void) printf("%-33s %-33s %5u %6d %5u %6d %-11s %s\n",
5090 pr_ap6(&tp6->tcp6ConnLocalAddress,
5091 tp6->tcp6ConnLocalPort, "tcp", lname, sizeof (lname)),
5092 pr_ap6(&tp6->tcp6ConnRemAddress,
5093 tp6->tcp6ConnRemPort, "tcp", fname, sizeof (fname)),
5094 tp6->tcp6ConnEntryInfo.ce_swnd,
5095 (sq >= 0) ? sq : 0,
5096 tp6->tcp6ConnEntryInfo.ce_rwnd,
5097 (rq >= 0) ? rq : 0,
5098 mitcp_state(tp6->tcp6ConnEntryInfo.ce_state, attr),
5099 ifnamep);
5100 } else if (Uflag && Vflag) {
5101 int i = 0;
5102 pid_t *pids = cpi->cpi_pids;
5103 proc_info_t *pinfo;
5104 do {
5105 pinfo = get_proc_info(*pids);
5106 (void) printf("%-33s\n%-33s %7u %08x %08x %7u %08x %08x "
5107 "%5u %5u %-11s %-5.5s %-8.8s %6u %s\n",
5108 pr_ap6(&tp6->tcp6ConnLocalAddress,
5109 tp6->tcp6ConnLocalPort, "tcp", lname, sizeof (lname)),
5110 pr_ap6(&tp6->tcp6ConnRemAddress,
5111 tp6->tcp6ConnRemPort, "tcp", fname, sizeof (fname)),
5112 tp6->tcp6ConnEntryInfo.ce_swnd,
5113 tp6->tcp6ConnEntryInfo.ce_snxt,
5114 tp6->tcp6ConnEntryInfo.ce_suna,
5115 tp6->tcp6ConnEntryInfo.ce_rwnd,
5116 tp6->tcp6ConnEntryInfo.ce_rnxt,
5117 tp6->tcp6ConnEntryInfo.ce_rack,
5118 tp6->tcp6ConnEntryInfo.ce_rto,
5119 tp6->tcp6ConnEntryInfo.ce_mss,
5120 mitcp_state(tp6->tcp6ConnEntryInfo.ce_state, attr),
5121 ifnamep, pinfo->pr_user, (int)*pids, pinfo->pr_psargs);
5122 i++; pids++;
5123 } while (i < cpi->cpi_pids_cnt);
5124 } else if (Uflag && (!Vflag)) {
5125 int sq = (int)tp6->tcp6ConnEntryInfo.ce_snxt -
5126 (int)tp6->tcp6ConnEntryInfo.ce_suna - 1;
5127 int rq = (int)tp6->tcp6ConnEntryInfo.ce_rnxt -
5128 (int)tp6->tcp6ConnEntryInfo.ce_rack;
5129 int i = 0;
5130 pid_t *pids = cpi->cpi_pids;
5131 proc_info_t *pinfo;
5132 do {
5133 pinfo = get_proc_info(*pids);
5134 (void) printf("%-33s %-33s %-8.8s %6u %-14.14s %7d %6u %7d %6d %-11s %s\n",
5135 pr_ap6(&tp6->tcp6ConnLocalAddress,
5136 tp6->tcp6ConnLocalPort, "tcp", lname, sizeof (lname)),
5137 pr_ap6(&tp6->tcp6ConnRemAddress,
5138 tp6->tcp6ConnRemPort, "tcp", fname, sizeof (fname)),
5139 pinfo->pr_user, (int)*pids, pinfo->pr_fname,
5140 tp6->tcp6ConnEntryInfo.ce_swnd,
5141 (sq >= 0) ? sq : 0,
5142 tp6->tcp6ConnEntryInfo.ce_rwnd,
5143 (rq >= 0) ? rq : 0,
5144 mitcp_state(tp6->tcp6ConnEntryInfo.ce_state, attr),
5145 ifnamep);
5146 i++; pids++;
5147 } while (i < cpi->cpi_pids_cnt);
5148 }
5149
5150 print_transport_label(attr);
5151
5152 return (B_FALSE);
5153 }
5154
5155 /* ------------------------------- UDP_REPORT------------------------------- */
5156
5157 static boolean_t udp_report_item_v4(const mib2_udpEntry_t *ude,
5158 conn_pid_info_t *cpi, boolean_t first,
5159 const mib2_transportMLPEntry_t *attr);
5160 static boolean_t udp_report_item_v6(const mib2_udp6Entry_t *ude6,
5161 conn_pid_info_t *cpi, boolean_t first,
5162 const mib2_transportMLPEntry_t *attr);
5163
5164 static const char udp_hdr_v4[] =
5165 " Local Address Remote Address State\n"
5166 "-------------------- -------------------- ----------\n";
5167 static const char udp_hdr_v4_pid[] =
5168 " Local Address Remote Address User Pid "
5169 " Command State\n"
5170 "-------------------- -------------------- -------- ------ "
5171 "-------------- ----------\n";
5172 static const char udp_hdr_v4_pid_verbose[] =
5173 " Local Address Remote Address User Pid State "
5174 " Command\n"
5175 "-------------------- -------------------- -------- ------ ---------- "
5176 "----------------\n";
5177
5178 static const char udp_hdr_v6[] =
5179 " Local Address Remote Address "
5180 " State If\n"
5181 "--------------------------------- --------------------------------- "
5182 "---------- -----\n";
5183 static const char udp_hdr_v6_pid[] =
5184 " Local Address Remote Address "
5185 " User Pid Command State If\n"
5186 "--------------------------------- --------------------------------- "
5187 "-------- ------ -------------- ---------- -----\n";
5188 static const char udp_hdr_v6_pid_verbose[] =
5189 " Local Address Remote Address "
5190 " User Pid State If Command\n"
5191 "--------------------------------- --------------------------------- "
5192 "-------- ------ ---------- ----- ----------------\n";
5193
5194
5195 static void
5196 udp_report(const mib_item_t *item)
5197 {
5198 int jtemp = 0;
5199 boolean_t print_hdr_once_v4 = B_TRUE;
5200 boolean_t print_hdr_once_v6 = B_TRUE;
5201 mib2_udpEntry_t *ude;
5202 mib2_udp6Entry_t *ude6;
5203 mib2_transportMLPEntry_t **v4_attrs, **v6_attrs;
5204 mib2_transportMLPEntry_t **v4a, **v6a;
5205 mib2_transportMLPEntry_t *aptr;
5206 conn_pid_info_t *cpi;
5207
5208 if (!protocol_selected(IPPROTO_UDP))
5209 return;
5210
5211 /*
5212 * Preparation pass: the kernel returns separate entries for UDP
5213 * connection table entries and Multilevel Port attributes. We loop
5214 * through the attributes first and set up an array for each address
5215 * family.
5216 */
5217 v4_attrs = family_selected(AF_INET) && RSECflag ?
5218 gather_attrs(item, MIB2_UDP, MIB2_UDP_ENTRY, udpEntrySize) : NULL;
5219 v6_attrs = family_selected(AF_INET6) && RSECflag ?
5220 gather_attrs(item, MIB2_UDP6, MIB2_UDP6_ENTRY, udp6EntrySize) :
5221 NULL;
5222
5223 v4a = v4_attrs;
5224 v6a = v6_attrs;
5225 /* 'for' loop 1: */
5226 for (; item; item = item->next_item) {
5227 if (Xflag) {
5228 (void) printf("\n--- Entry %d ---\n", ++jtemp);
5229 (void) printf("Group = %d, mib_id = %d, "
5230 "length = %d, valp = 0x%p\n",
5231 item->group, item->mib_id,
5232 item->length, item->valp);
5233 }
5234 if (!((item->group == MIB2_UDP &&
5235 item->mib_id == MIB2_UDP_ENTRY) ||
5236 (item->group == MIB2_UDP6 &&
5237 item->mib_id == MIB2_UDP6_ENTRY) ||
5238 (item->group == MIB2_UDP &&
5239 item->mib_id == EXPER_XPORT_PROC_INFO) ||
5240 (item->group == MIB2_UDP6 &&
5241 item->mib_id == EXPER_XPORT_PROC_INFO)))
5242 continue; /* 'for' loop 1 */
5243
5244 if (item->group == MIB2_UDP && !family_selected(AF_INET))
5245 continue; /* 'for' loop 1 */
5246 else if (item->group == MIB2_UDP6 && !family_selected(AF_INET6))
5247 continue; /* 'for' loop 1 */
5248
5249 /* xxx.xxx.xxx.xxx,pppp sss... */
5250 if ((!Uflag) && item->group == MIB2_UDP &&
5251 item->mib_id == MIB2_UDP_ENTRY) {
5252 for (ude = (mib2_udpEntry_t *)item->valp;
5253 (char *)ude < (char *)item->valp + item->length;
5254 /* LINTED: (note 1) */
5255 ude = (mib2_udpEntry_t *)((char *)ude +
5256 udpEntrySize)) {
5257 aptr = v4a == NULL ? NULL : *v4a++;
5258 print_hdr_once_v4 = udp_report_item_v4(ude,
5259 NULL, print_hdr_once_v4, aptr);
5260 }
5261 } else if ((!Uflag) && item->group == MIB2_UDP6 &&
5262 item->mib_id == MIB2_UDP6_ENTRY) {
5263 for (ude6 = (mib2_udp6Entry_t *)item->valp;
5264 (char *)ude6 < (char *)item->valp + item->length;
5265 /* LINTED: (note 1) */
5266 ude6 = (mib2_udp6Entry_t *)((char *)ude6 +
5267 udp6EntrySize)) {
5268 aptr = v6a == NULL ? NULL : *v6a++;
5269 print_hdr_once_v6 = udp_report_item_v6(ude6,
5270 NULL, print_hdr_once_v6, aptr);
5271 }
5272 } else if ((Uflag) && item->group == MIB2_UDP &&
5273 item->mib_id == EXPER_XPORT_PROC_INFO) {
5274 for (ude = (mib2_udpEntry_t *)item->valp;
5275 (char *)ude < (char *)item->valp + item->length;
5276 /* LINTED: (note 1) */
5277 ude = (mib2_udpEntry_t *)((char *)cpi +
5278 cpi->cpi_tot_size)) {
5279 aptr = v4a == NULL ? NULL : *v4a++;
5280 /* LINTED: (note 1) */
5281 cpi = (conn_pid_info_t *) ((char *)ude +
5282 udpEntrySize);
5283 print_hdr_once_v4 = udp_report_item_v4(ude,
5284 cpi, print_hdr_once_v4, aptr);
5285 }
5286 } else if ((Uflag) && item->group == MIB2_UDP6 &&
5287 item->mib_id == EXPER_XPORT_PROC_INFO) {
5288 for (ude6 = (mib2_udp6Entry_t *)item->valp;
5289 (char *)ude6 < (char *)item->valp + item->length;
5290 /* LINTED: (note 1) */
5291 ude6 = (mib2_udp6Entry_t *)((char *)cpi +
5292 cpi->cpi_tot_size)) {
5293 aptr = v6a == NULL ? NULL : *v6a++;
5294 /* LINTED: (note 1) */
5295 cpi = (conn_pid_info_t *) ((char *)ude6 +
5296 udp6EntrySize);
5297 print_hdr_once_v6 = udp_report_item_v6(ude6,
5298 cpi, print_hdr_once_v6, aptr);
5299 }
5300 }
5301 } /* 'for' loop 1 ends */
5302 (void) fflush(stdout);
5303
5304 if (v4_attrs != NULL)
5305 free(v4_attrs);
5306 if (v6_attrs != NULL)
5307 free(v6_attrs);
5308 }
5309
5310 static boolean_t
5311 udp_report_item_v4(const mib2_udpEntry_t *ude, conn_pid_info_t *cpi,
5312 boolean_t first, const mib2_transportMLPEntry_t *attr)
5313 {
5314 char lname[MAXHOSTNAMELEN + MAXHOSTNAMELEN + 1];
5315 /* hostname + portname */
5316
5317 if (!(Aflag || ude->udpEntryInfo.ue_state >= MIB2_UDP_connected))
5318 return (first); /* Nothing to print */
5319
5320 if (first) {
5321 (void) printf(v4compat ? "\nUDP\n" : "\nUDP: IPv4\n");
5322
5323 if (Uflag)
5324 (void) printf(Vflag ? udp_hdr_v4_pid_verbose :
5325 udp_hdr_v4_pid);
5326 else
5327 (void) printf(udp_hdr_v4);
5328
5329 first = B_FALSE;
5330 }
5331
5332 (void) printf("%-20s %-20s ",
5333 pr_ap(ude->udpLocalAddress, ude->udpLocalPort, "udp",
5334 lname, sizeof (lname)),
5335 ude->udpEntryInfo.ue_state == MIB2_UDP_connected ?
5336 pr_ap(ude->udpEntryInfo.ue_RemoteAddress,
5337 ude->udpEntryInfo.ue_RemotePort, "udp", lname, sizeof (lname)) :
5338 "");
5339 if (!Uflag) {
5340 (void) printf("%s\n",
5341 miudp_state(ude->udpEntryInfo.ue_state, attr));
5342 } else {
5343 int i = 0;
5344 pid_t *pids = cpi->cpi_pids;
5345 proc_info_t *pinfo;
5346 do {
5347 pinfo = get_proc_info(*pids);
5348 (void) printf("%-8.8s %6u ", pinfo->pr_user,
5349 (int)*pids);
5350 if (Vflag) {
5351 (void) printf("%-10.10s %s\n",
5352 miudp_state(ude->udpEntryInfo.ue_state,
5353 attr),
5354 pinfo->pr_psargs);
5355 } else {
5356 (void) printf("%-14.14s %s\n", pinfo->pr_fname,
5357 miudp_state(ude->udpEntryInfo.ue_state,
5358 attr));
5359 }
5360 i++; pids++;
5361 } while (i < cpi->cpi_pids_cnt);
5362 }
5363
5364 print_transport_label(attr);
5365
5366 return (first);
5367 }
5368
5369 static boolean_t
5370 udp_report_item_v6(const mib2_udp6Entry_t *ude6, conn_pid_info_t *cpi,
5371 boolean_t first, const mib2_transportMLPEntry_t *attr)
5372 {
5373 char lname[MAXHOSTNAMELEN + MAXHOSTNAMELEN + 1];
5374 /* hostname + portname */
5375 char ifname[LIFNAMSIZ + 1];
5376 const char *ifnamep;
5377
5378 if (!(Aflag || ude6->udp6EntryInfo.ue_state >= MIB2_UDP_connected))
5379 return (first); /* Nothing to print */
5380
5381 if (first) {
5382 (void) printf("\nUDP: IPv6\n");
5383
5384 if (Uflag)
5385 (void) printf(Vflag ? udp_hdr_v6_pid_verbose :
5386 udp_hdr_v6_pid);
5387 else
5388 (void) printf(udp_hdr_v6);
5389
5390 first = B_FALSE;
5391 }
5392
5393 ifnamep = (ude6->udp6IfIndex != 0) ?
5394 if_indextoname(ude6->udp6IfIndex, ifname) : NULL;
5395
5396 (void) printf("%-33s %-33s ",
5397 pr_ap6(&ude6->udp6LocalAddress,
5398 ude6->udp6LocalPort, "udp", lname, sizeof (lname)),
5399 ude6->udp6EntryInfo.ue_state == MIB2_UDP_connected ?
5400 pr_ap6(&ude6->udp6EntryInfo.ue_RemoteAddress,
5401 ude6->udp6EntryInfo.ue_RemotePort, "udp", lname, sizeof (lname)) :
5402 "");
5403 if (!Uflag) {
5404 (void) printf("%-10s %s\n",
5405 miudp_state(ude6->udp6EntryInfo.ue_state, attr),
5406 ifnamep == NULL ? "" : ifnamep);
5407 } else {
5408 int i = 0;
5409 pid_t *pids = cpi->cpi_pids;
5410 proc_info_t *pinfo;
5411 do {
5412 pinfo = get_proc_info(*pids);
5413 (void) printf("%-8.8s %6u ", pinfo->pr_user,
5414 (int)*pids);
5415 if (Vflag) {
5416 (void) printf("%-10.10s %-5.5s %s\n",
5417 miudp_state(ude6->udp6EntryInfo.ue_state,
5418 attr),
5419 ifnamep == NULL ? "" : ifnamep,
5420 pinfo->pr_psargs);
5421 } else {
5422 (void) printf("%-14.14s %-10.10s %s\n",
5423 pinfo->pr_fname,
5424 miudp_state(ude6->udp6EntryInfo.ue_state,
5425 attr),
5426 ifnamep == NULL ? "" : ifnamep);
5427 }
5428 i++; pids++;
5429 } while (i < cpi->cpi_pids_cnt);
5430 }
5431
5432 print_transport_label(attr);
5433
5434 return (first);
5435 }
5436
5437 /* ------------------------------ SCTP_REPORT------------------------------- */
5438
5439 static const char sctp_hdr[] =
5440 "\nSCTP:";
5441 static const char sctp_hdr_normal[] =
5442 " Local Address Remote Address "
5443 "Swind Send-Q Rwind Recv-Q StrsI/O State\n"
5444 "------------------------------- ------------------------------- "
5445 "------ ------ ------ ------ ------- -----------";
5446 static const char sctp_hdr_pid[] =
5447 " Local Address Remote Address "
5448 "Swind Send-Q Rwind Recv-Q StrsI/O User Pid Command State\n"
5449 "------------------------------- ------------------------------- ------ "
5450 "------ ------ ------ ------- -------- ------ -------------- -----------";
5451 static const char sctp_hdr_pid_verbose[] =
5452 " Local Address Remote Address "
5453 "Swind Send-Q Rwind Recv-Q StrsI/O User Pid State Command\n"
5454 "------------------------------- ------------------------------- ------ "
5455 "------ ------ ------ ------- -------- ------ ----------- --------------";
5456
5457 static const char *
5458 nssctp_state(int state, const mib2_transportMLPEntry_t *attr)
5459 {
5460 static char sctpsbuf[50];
5461 const char *cp;
5462
5463 switch (state) {
5464 case MIB2_SCTP_closed:
5465 cp = "CLOSED";
5466 break;
5467 case MIB2_SCTP_cookieWait:
5468 cp = "COOKIE_WAIT";
5469 break;
5470 case MIB2_SCTP_cookieEchoed:
5471 cp = "COOKIE_ECHOED";
5472 break;
5473 case MIB2_SCTP_established:
5474 cp = "ESTABLISHED";
5475 break;
5602 } else {
5603 (void) pr_addr(v4addr, name, namelen);
5604 }
5605 break;
5606
5607 case MIB2_SCTP_ADDR_V6:
5608 /* v6 */
5609 if (port > 0) {
5610 (void) pr_ap6(addr, port, "sctp", name, namelen);
5611 } else {
5612 (void) pr_addr6(addr, name, namelen);
5613 }
5614 break;
5615
5616 default:
5617 (void) snprintf(name, namelen, "<unknown addr type>");
5618 break;
5619 }
5620 }
5621
5622 static boolean_t
5623 sctp_conn_report_item(const mib_item_t *head, conn_pid_info_t * cpi,
5624 boolean_t print_sctp_hdr, const mib2_sctpConnEntry_t *sp,
5625 const mib2_transportMLPEntry_t *attr)
5626 {
5627 char lname[MAXHOSTNAMELEN + MAXHOSTNAMELEN + 1];
5628 char fname[MAXHOSTNAMELEN + MAXHOSTNAMELEN + 1];
5629 const mib2_sctpConnRemoteEntry_t *sre = NULL;
5630 const mib2_sctpConnLocalEntry_t *sle = NULL;
5631 const mib_item_t *local = head;
5632 const mib_item_t *remote = head;
5633 uint32_t id = sp->sctpAssocId;
5634 boolean_t printfirst = B_TRUE;
5635
5636 if (print_sctp_hdr == B_TRUE) {
5637 (void) puts(sctp_hdr);
5638 if (Uflag)
5639 (void) puts(Vflag? sctp_hdr_pid_verbose: sctp_hdr_pid);
5640 else
5641 (void) puts(sctp_hdr_normal);
5642
5643 print_sctp_hdr = B_FALSE;
5644 }
5645
5646 sctp_pr_addr(sp->sctpAssocRemPrimAddrType, fname, sizeof (fname),
5647 &sp->sctpAssocRemPrimAddr, sp->sctpAssocRemPort);
5648 sctp_pr_addr(sp->sctpAssocRemPrimAddrType, lname, sizeof (lname),
5649 &sp->sctpAssocLocPrimAddr, sp->sctpAssocLocalPort);
5650
5651 if (Uflag) {
5652 int i = 0;
5653 pid_t *pids = cpi->cpi_pids;
5654 proc_info_t *pinfo;
5655 do {
5656 pinfo = get_proc_info(*pids);
5657 (void) printf("%-31s %-31s %6u %6d %6u %6d %3d/%-3d %-8.8s %6u ",
5658 lname, fname,
5659 sp->sctpConnEntryInfo.ce_swnd,
5660 sp->sctpConnEntryInfo.ce_sendq,
5661 sp->sctpConnEntryInfo.ce_rwnd,
5662 sp->sctpConnEntryInfo.ce_recvq,
5663 sp->sctpAssocInStreams,
5664 sp->sctpAssocOutStreams,
5665 pinfo->pr_user, (int)*pids);
5666 if (Vflag) {
5667 (void) printf("%-11.11s %s\n",
5668 nssctp_state(sp->sctpAssocState, attr),
5669 pinfo->pr_psargs);
5670 } else {
5671 (void) printf("%-14.14s %s\n",
5672 pinfo->pr_fname,
5673 nssctp_state(sp->sctpAssocState, attr));
5674 }
5675 i++; pids++;
5676 } while (i < cpi->cpi_pids_cnt);
5677
5678 } else {
5679
5680 (void) printf("%-31s %-31s %6u %6d %6u %6d %3d/%-3d %s\n",
5681 lname, fname,
5682 sp->sctpConnEntryInfo.ce_swnd,
5683 sp->sctpConnEntryInfo.ce_sendq,
5684 sp->sctpConnEntryInfo.ce_rwnd,
5685 sp->sctpConnEntryInfo.ce_recvq,
5686 sp->sctpAssocInStreams, sp->sctpAssocOutStreams,
5687 nssctp_state(sp->sctpAssocState, attr));
5688 }
5689
5690 print_transport_label(attr);
5691
5692 if (!Vflag) {
5693 return (print_sctp_hdr);
5694 }
5695
5696 /* Print remote addresses/local addresses on following lines */
5697 while ((sre = sctp_getnext_rem(&remote, sre, id)) != NULL) {
5698 if (!IN6_ARE_ADDR_EQUAL(&sre->sctpAssocRemAddr,
5699 &sp->sctpAssocRemPrimAddr)) {
5700 if (printfirst == B_TRUE) {
5701 (void) fputs("\t<Remote: ", stdout);
5702 printfirst = B_FALSE;
5703 } else {
5704 (void) fputs(", ", stdout);
5705 }
5706 sctp_pr_addr(sre->sctpAssocRemAddrType, fname,
5707 sizeof (fname), &sre->sctpAssocRemAddr, -1);
5708 if (sre->sctpAssocRemAddrActive == MIB2_SCTP_ACTIVE) {
5709 (void) fputs(fname, stdout);
5710 } else {
5711 (void) printf("(%s)", fname);
5712 }
5713 }
5716 (void) puts(">");
5717 printfirst = B_TRUE;
5718 }
5719 while ((sle = sctp_getnext_local(&local, sle, id)) != NULL) {
5720 if (!IN6_ARE_ADDR_EQUAL(&sle->sctpAssocLocalAddr,
5721 &sp->sctpAssocLocPrimAddr)) {
5722 if (printfirst == B_TRUE) {
5723 (void) fputs("\t<Local: ", stdout);
5724 printfirst = B_FALSE;
5725 } else {
5726 (void) fputs(", ", stdout);
5727 }
5728 sctp_pr_addr(sle->sctpAssocLocalAddrType, lname,
5729 sizeof (lname), &sle->sctpAssocLocalAddr, -1);
5730 (void) fputs(lname, stdout);
5731 }
5732 }
5733 if (printfirst == B_FALSE) {
5734 (void) puts(">");
5735 }
5736
5737 return (print_sctp_hdr);
5738 }
5739
5740 static void
5741 sctp_report(const mib_item_t *item)
5742 {
5743 const mib_item_t *head;
5744 const mib2_sctpConnEntry_t *sp;
5745 boolean_t print_sctp_hdr_once = B_TRUE;
5746 mib2_transportMLPEntry_t **attrs, **aptr;
5747 mib2_transportMLPEntry_t *attr;
5748 conn_pid_info_t *cpi;
5749
5750 /*
5751 * Preparation pass: the kernel returns separate entries for SCTP
5752 * connection table entries and Multilevel Port attributes. We loop
5753 * through the attributes first and set up an array for each address
5754 * family.
5755 */
5756 attrs = RSECflag ?
5757 gather_attrs(item, MIB2_SCTP, MIB2_SCTP_CONN, sctpEntrySize) :
5758 NULL;
5759
5760 aptr = attrs;
5761 head = item;
5762 for (; item != NULL; item = item->next_item) {
5763
5764 if (!((item->group == MIB2_SCTP &&
5765 item->mib_id == MIB2_SCTP_CONN) ||
5766 (item->group == MIB2_SCTP &&
5767 item->mib_id == EXPER_XPORT_PROC_INFO)))
5768 continue;
5769
5770 if ((!Uflag) && item->group == MIB2_SCTP
5771 && item->mib_id == MIB2_SCTP_CONN) {
5772 for (sp = item->valp;
5773 (char *)sp < (char *)item->valp + item->length;
5774 /* LINTED: (note 1) */
5775 sp = (mib2_sctpConnEntry_t *)((char *)sp + sctpEntrySize)) {
5776 if (!(Aflag ||
5777 sp->sctpAssocState >= MIB2_SCTP_established))
5778 continue;
5779 attr = aptr == NULL ? NULL : *aptr++;
5780 print_sctp_hdr_once = sctp_conn_report_item(head, NULL,
5781 print_sctp_hdr_once, sp,
5782 attr);
5783 }
5784 } else if ((Uflag) && item->group == MIB2_SCTP &&
5785 item->mib_id == EXPER_XPORT_PROC_INFO) {
5786 for (sp = (mib2_sctpConnEntry_t *)item->valp;
5787 (char *)sp < (char *)item->valp + item->length;
5788 /* LINTED: (note 1) */
5789 sp = (mib2_sctpConnEntry_t *)((char *)cpi +
5790 cpi->cpi_tot_size)) {
5791 /* LINTED: (note 1) */
5792 cpi = (conn_pid_info_t *) ((char *)sp +
5793 sctpEntrySize);
5794 if (!(Aflag ||
5795 sp->sctpAssocState >= MIB2_SCTP_established))
5796 continue;
5797 attr = aptr == NULL ? NULL : *aptr++;
5798 print_sctp_hdr_once =
5799 sctp_conn_report_item(head, cpi,
5800 print_sctp_hdr_once, sp, attr);
5801 }
5802 }
5803 }
5804 if (attrs != NULL)
5805 free(attrs);
5806 }
5807
5808 static char *
5809 plural(int n)
5810 {
5811 return (n != 1 ? "s" : "");
5812 }
5813
5814 static char *
5815 pluraly(int n)
5816 {
5817 return (n != 1 ? "ies" : "y");
5818 }
5819
5820 static char *
6768 }
6769 return (B_FALSE);
6770 }
6771
6772 /*
6773 * Convert the interface index to a string using the buffer `ifname', which
6774 * must be at least LIFNAMSIZ bytes. We first try to map it to name. If that
6775 * fails (e.g., because we're inside a zone and it does not have access to
6776 * interface for the index in question), just return "if#<num>".
6777 */
6778 static char *
6779 ifindex2str(uint_t ifindex, char *ifname)
6780 {
6781 if (if_indextoname(ifindex, ifname) == NULL)
6782 (void) snprintf(ifname, LIFNAMSIZ, "if#%d", ifindex);
6783
6784 return (ifname);
6785 }
6786
6787 /*
6788 * Gets proc info in (proc_info_t) given pid. It doesn't return NULL.
6789 */
6790 proc_info_t *
6791 get_proc_info(pid_t pid)
6792 {
6793 static pid_t saved_pid = 0;
6794 static proc_info_t saved_proc_info;
6795 static proc_info_t unknown_proc_info = {"<unknown>","",""};
6796 static psinfo_t pinfo;
6797 char path[128];
6798 int fd;
6799
6800 /* hardcode pid = 0 */
6801 if (pid == 0) {
6802 saved_proc_info.pr_user = "root";
6803 saved_proc_info.pr_fname = "sched";
6804 saved_proc_info.pr_psargs = "sched";
6805 saved_pid = 0;
6806 return &saved_proc_info;
6807 }
6808
6809 if (pid == saved_pid)
6810 return &saved_proc_info;
6811 if ((snprintf(path, 128, "/proc/%u/psinfo",(int)pid) > 0) &&
6812 ((fd = open(path, O_RDONLY)) != -1)) {
6813 if (read(fd, &pinfo, sizeof(pinfo)) == sizeof(pinfo)){
6814 saved_proc_info.pr_user = get_username(pinfo.pr_uid);
6815 saved_proc_info.pr_fname = pinfo.pr_fname;
6816 saved_proc_info.pr_psargs = pinfo.pr_psargs;
6817 saved_pid = pid;
6818 (void) close(fd);
6819 return &saved_proc_info;
6820 } else {
6821 (void) close(fd);
6822 }
6823 }
6824
6825 return (&unknown_proc_info);
6826 }
6827
6828 /*
6829 * Gets username given uid. It doesn't return NULL.
6830 */
6831 static char *
6832 get_username(uid_t u)
6833 {
6834 static uid_t saved_uid = UINT_MAX;
6835 static char saved_username[128];
6836 struct passwd *pw = NULL;
6837 if (u == UINT_MAX)
6838 return "<unknown>";
6839 if (u == saved_uid && saved_username[0] != '\0')
6840 return (saved_username);
6841 setpwent();
6842 if ((pw = getpwuid(u)) != NULL)
6843 (void) strlcpy(saved_username, pw->pw_name, 128);
6844 else
6845 (void) snprintf(saved_username, 128, "%u", u);
6846 saved_uid = u;
6847 return saved_username;
6848 }
6849
6850 /*
6851 * print the usage line
6852 */
6853 static void
6854 usage(char *cmdname)
6855 {
6856 (void) fprintf(stderr, "usage: %s [-anuv] [-f address_family] "
6857 "[-T d|u]\n", cmdname);
6858 (void) fprintf(stderr, " %s [-n] [-f address_family] "
6859 "[-P protocol] [-T d|u] [-g | -p | -s [interval [count]]]\n",
6860 cmdname);
6861 (void) fprintf(stderr, " %s -m [-v] [-T d|u] "
6862 "[interval [count]]\n", cmdname);
6863 (void) fprintf(stderr, " %s -i [-I interface] [-an] "
6864 "[-f address_family] [-T d|u] [interval [count]]\n", cmdname);
6865 (void) fprintf(stderr, " %s -r [-anv] "
6866 "[-f address_family|filter] [-T d|u]\n", cmdname);
6867 (void) fprintf(stderr, " %s -M [-ns] [-f address_family] "
6868 "[-T d|u]\n", cmdname);
6869 (void) fprintf(stderr, " %s -D [-I interface] "
6870 "[-f address_family] [-T d|u]\n", cmdname);
6871 exit(EXIT_FAILURE);
6872 }
6873
6874 /*
6875 * fatal: print error message to stderr and
6876 * call exit(errcode)
6877 */
6878 /*PRINTFLIKE2*/
6879 static void
6880 fatal(int errcode, char *format, ...)
6881 {
6882 va_list argp;
6883
6884 if (format == NULL)
6885 return;
6886
6887 va_start(argp, format);
6888 (void) vfprintf(stderr, format, argp);
6889 va_end(argp);
6890
6891 exit(errcode);
6892 }
6893
6894
6895 /* -------------------UNIX Domain Sockets Report---------------------------- */
6896
6897
6898 #define NO_ADDR " "
6899 #define SO_PAIR " (socketpair) "
6900
6901 static char *typetoname(t_scalar_t);
6902 static boolean_t uds_report_item(struct sockinfo *, boolean_t);
6903
6904
6905 static char uds_hdr[] = "\nActive UNIX domain sockets\n";
6906
6907 static char uds_hdr_normal[] =
6908 " Type Local Adress "
6909 " Remote Address\n"
6910 "---------- --------------------------------------- "
6911 "---------------------------------------\n";
6912
6913 static char uds_hdr_pid[] =
6914 " Type User Pid Command "
6915 " Local Address "
6916 " Remote Address\n"
6917 "---------- -------- ------ -------------- "
6918 "--------------------------------------- "
6919 "---------------------------------------\n";
6920 static char uds_hdr_pid_verbose[] =
6921 " Type User Pid Local Address "
6922 " Remote Address Command\n"
6923 "---------- -------- ------ --------------------------------------- "
6924 "--------------------------------------- --------------\n";
6925
6926 /*
6927 * Print a summary of connections related to unix protocols.
6928 */
6929 static void
6930 uds_report(kstat_ctl_t *kc)
6931 {
6932 int i;
6933 kstat_t *ksp;
6934 struct sockinfo *psi;
6935 boolean_t print_uds_hdr_once = B_TRUE;
6936
6937 if (kc == NULL) {
6938 fail(0, "uds_report: No kstat");
6939 exit(3);
6940 }
6941
6942 if ((ksp = kstat_lookup(kc, "sockfs", 0, "sock_unix_list")) ==
6943 (kstat_t *)NULL) {
6944 fail(0, "kstat_data_lookup failed\n");
6945 }
6946
6947 if (kstat_read(kc, ksp, NULL) == -1) {
6948 fail(0, "kstat_read failed for sock_unix_list\n");
6949 }
6950
6951 if (ksp->ks_ndata == 0) {
6952 return; /* no AF_UNIX sockets found */
6953 }
6954
6955 /*
6956 * Having ks_data set with ks_data == NULL shouldn't happen;
6957 * If it does, the sockfs kstat is seriously broken.
6958 */
6959 if ((psi = ksp->ks_data) == NULL) {
6960 fail(0, "uds_report: no kstat data\n");
6961 }
6962
6963 for (i = 0; i < ksp->ks_ndata; i++) {
6964
6965 print_uds_hdr_once = uds_report_item(psi, print_uds_hdr_once);
6966
6967 /* if si_size didn't get filled in, then we're done */
6968 if (psi->si_size == 0 ||
6969 !IS_P2ALIGNED(psi->si_size, sizeof (psi))) {
6970 break;
6971 }
6972
6973 /* point to the next sockinfo in the array */
6974 /* LINTED: (note 1) */
6975 psi = (struct sockinfo *)(((char *)psi) + psi->si_size);
6976 }
6977 }
6978
6979 static boolean_t
6980 uds_report_item(struct sockinfo *psi, boolean_t first)
6981 {
6982 int i = 0;
6983 pid_t *pids;
6984 proc_info_t *pinfo;
6985 char *laddr, *raddr;
6986
6987 if(first) {
6988 (void) printf("%s", uds_hdr);
6989 if (Uflag)
6990 (void) printf("%s", Vflag?uds_hdr_pid_verbose:
6991 uds_hdr_pid);
6992 else
6993 (void) printf("%s", uds_hdr_normal);
6994
6995 first = B_FALSE;
6996 }
6997
6998 pids = psi->si_pids;
6999
7000 do {
7001 pinfo = get_proc_info(*pids);
7002 raddr = laddr = NO_ADDR;
7003
7004 /* Try to fill laddr */
7005 if ((psi->si_state & SS_ISBOUND) &&
7006 strlen(psi->si_laddr_sun_path) != 0 &&
7007 psi->si_laddr_soa_len != 0) {
7008 if (psi->si_faddr_noxlate) {
7009 laddr = SO_PAIR;
7010 } else {
7011 if (psi->si_laddr_soa_len >
7012 sizeof (psi->si_laddr_family))
7013 laddr = psi->si_laddr_sun_path;
7014 }
7015 }
7016
7017 /* Try to fill raddr */
7018 if ((psi->si_state & SS_ISCONNECTED) &&
7019 strlen(psi->si_faddr_sun_path) != 0 &&
7020 psi->si_faddr_soa_len != 0) {
7021
7022 if (psi->si_faddr_noxlate) {
7023 raddr = SO_PAIR;
7024 } else {
7025 if (psi->si_faddr_soa_len >
7026 sizeof (psi->si_faddr_family))
7027 raddr = psi->si_faddr_sun_path;
7028 }
7029 }
7030
7031 if (Uflag && Vflag) {
7032 (void) printf("%-10.10s %-8.8s %6u "
7033 "%-39.39s %-39.39s %s\n",
7034 typetoname(psi->si_serv_type), pinfo->pr_user,
7035 (int)*pids, laddr, raddr, pinfo->pr_psargs);
7036 } else if (Uflag && (!Vflag)) {
7037 (void) printf("%-10.10s %-8.8s %6u %-14.14s"
7038 "%-39.39s %-39.39s\n",
7039 typetoname(psi->si_serv_type), pinfo->pr_user,
7040 (int)*pids, pinfo->pr_fname, laddr, raddr);
7041 } else {
7042 (void) printf("%-10.10s %s %s\n",
7043 typetoname(psi->si_serv_type), laddr, raddr);
7044 }
7045
7046 i++; pids++;
7047 } while (i < psi->si_pn_cnt);
7048
7049 return (first);
7050 }
7051
7052 static char *
7053 typetoname(t_scalar_t type)
7054 {
7055 switch (type) {
7056 case T_CLTS:
7057 return ("dgram");
7058
7059 case T_COTS:
7060 return ("stream");
7061
7062 case T_COTS_ORD:
7063 return ("stream-ord");
7064
7065 default:
7066 return ("");
7067 }
7068 }
|