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(uint32_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_node_list_hdr_t *, boolean_t first,
4799 const mib2_transportMLPEntry_t *);
4800 static boolean_t tcp_report_item_v6(const mib2_tcp6ConnEntry_t *,
4801 conn_pid_node_list_hdr_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_node_list_hdr_t *cph;
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 *)cph +
4889 cph->cph_tot_size)) {
4890 aptr = v4a == NULL ? NULL : *v4a++;
4891 /* LINTED: (note 1) */
4892 cph = (conn_pid_node_list_hdr_t *)
4893 ((char *)tp + tcpConnEntrySize);
4894 print_hdr_once_v4 = tcp_report_item_v4(tp,
4895 cph, 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 *)cph +
4903 cph->cph_tot_size)) {
4904 aptr = v6a == NULL ? NULL : *v6a++;
4905 /* LINTED: (note 1) */
4906 cph = (conn_pid_node_list_hdr_t *)
4907 ((char *)tp6 + tcp6ConnEntrySize);
4908 print_hdr_once_v6 = tcp_report_item_v6(tp6,
4909 cph, 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,
4924 conn_pid_node_list_hdr_t * cph, boolean_t first,
4925 const mib2_transportMLPEntry_t *attr)
4926 {
4927 /*
4928 * lname and fname below are for the hostname as well as the portname
4929 * There is no limit on portname length so we assume MAXHOSTNAMELEN
4930 * as the limit
4931 */
4932 char lname[MAXHOSTNAMELEN + MAXHOSTNAMELEN + 1];
4933 char fname[MAXHOSTNAMELEN + MAXHOSTNAMELEN + 1];
4934
4935
4936 if (!(Aflag || tp->tcpConnEntryInfo.ce_state >= TCPS_ESTABLISHED))
4937 return (first); /* Nothing to print */
4938
4939 if (first) {
4940 (void) printf(v4compat ? tcp_hdr_v4_compat : tcp_hdr_v4);
4941 if (Uflag)
4942 (void) printf(Vflag ? tcp_hdr_v4_pid_verbose :
4943 tcp_hdr_v4_pid);
4944 else
4945 (void) printf(Vflag ? tcp_hdr_v4_verbose :
4946 tcp_hdr_v4_normal);
4947 }
4948
4949 if ((!Uflag) && Vflag) {
4950 (void) printf("%-20s\n%-20s %5u %08x %08x %5u %08x %08x "
4951 "%5u %5u %s\n",
4952 pr_ap(tp->tcpConnLocalAddress,
4953 tp->tcpConnLocalPort, "tcp", lname, sizeof (lname)),
4954 pr_ap(tp->tcpConnRemAddress,
4955 tp->tcpConnRemPort, "tcp", fname, sizeof (fname)),
4956 tp->tcpConnEntryInfo.ce_swnd,
4957 tp->tcpConnEntryInfo.ce_snxt,
4958 tp->tcpConnEntryInfo.ce_suna,
4959 tp->tcpConnEntryInfo.ce_rwnd,
4960 tp->tcpConnEntryInfo.ce_rnxt,
4961 tp->tcpConnEntryInfo.ce_rack,
4962 tp->tcpConnEntryInfo.ce_rto,
4963 tp->tcpConnEntryInfo.ce_mss,
4964 mitcp_state(tp->tcpConnEntryInfo.ce_state, attr));
4965 } else if ((!Uflag) && (!Vflag)) {
4966 int sq = (int)tp->tcpConnEntryInfo.ce_snxt -
4967 (int)tp->tcpConnEntryInfo.ce_suna - 1;
4968 int rq = (int)tp->tcpConnEntryInfo.ce_rnxt -
4969 (int)tp->tcpConnEntryInfo.ce_rack;
4970
4971 (void) printf("%-20s %-20s %5u %6d %5u %6d %s\n",
4972 pr_ap(tp->tcpConnLocalAddress,
4973 tp->tcpConnLocalPort, "tcp", lname, sizeof (lname)),
4974 pr_ap(tp->tcpConnRemAddress,
4975 tp->tcpConnRemPort, "tcp", fname, sizeof (fname)),
4976 tp->tcpConnEntryInfo.ce_swnd,
4977 (sq >= 0) ? sq : 0,
4978 tp->tcpConnEntryInfo.ce_rwnd,
4979 (rq >= 0) ? rq : 0,
4980 mitcp_state(tp->tcpConnEntryInfo.ce_state, attr));
4981 } else if (Uflag && Vflag) {
4982 int i = 0;
4983 conn_pid_node_t *cpn = cph->cph_cpns;
4984 proc_info_t *pinfo;
4985
4986 do {
4987 int pid = (cph->cph_pn_cnt)?cpn->cpn_pid:0;
4988 pinfo = get_proc_info(cpn->cpn_pid);
4989
4990 (void) printf("%-20s\n%-20s %7u %08x %08x %7u %08x %08x "
4991 "%5u %5u %-11s %-8.8s %6u %s\n",
4992 pr_ap(tp->tcpConnLocalAddress,
4993 tp->tcpConnLocalPort, "tcp", lname, sizeof (lname)),
4994 pr_ap(tp->tcpConnRemAddress,
4995 tp->tcpConnRemPort, "tcp", fname, sizeof (fname)),
4996 tp->tcpConnEntryInfo.ce_swnd,
4997 tp->tcpConnEntryInfo.ce_snxt,
4998 tp->tcpConnEntryInfo.ce_suna,
4999 tp->tcpConnEntryInfo.ce_rwnd,
5000 tp->tcpConnEntryInfo.ce_rnxt,
5001 tp->tcpConnEntryInfo.ce_rack,
5002 tp->tcpConnEntryInfo.ce_rto,
5003 tp->tcpConnEntryInfo.ce_mss,
5004 mitcp_state(tp->tcpConnEntryInfo.ce_state, attr),
5005 pinfo->pr_user, pid, pinfo->pr_psargs);
5006 i++; cpn++;
5007 } while (i < cph->cph_pn_cnt);
5008 } else if (Uflag && (!Vflag)) {
5009 int sq = (int)tp->tcpConnEntryInfo.ce_snxt -
5010 (int)tp->tcpConnEntryInfo.ce_suna - 1;
5011 int rq = (int)tp->tcpConnEntryInfo.ce_rnxt -
5012 (int)tp->tcpConnEntryInfo.ce_rack;
5013 int i = 0;
5014 conn_pid_node_t *cpn = cph->cph_cpns;
5015 proc_info_t *pinfo;
5016
5017 do {
5018 int pid = (cph->cph_pn_cnt)?cpn->cpn_pid:0;
5019 pinfo = get_proc_info(cpn->cpn_pid);
5020
5021 (void) printf("%-20s %-20s %-8.8s %6u %-13.13s %7u %6d %7u %6d %s\n",
5022 pr_ap(tp->tcpConnLocalAddress,
5023 tp->tcpConnLocalPort, "tcp", lname, sizeof (lname)),
5024 pr_ap(tp->tcpConnRemAddress,
5025 tp->tcpConnRemPort, "tcp", fname, sizeof (fname)),
5026 pinfo->pr_user, pid, pinfo->pr_fname,
5027 tp->tcpConnEntryInfo.ce_swnd,
5028 (sq >= 0) ? sq : 0,
5029 tp->tcpConnEntryInfo.ce_rwnd,
5030 (rq >= 0) ? rq : 0,
5031 mitcp_state(tp->tcpConnEntryInfo.ce_state, attr));
5032
5033 i++; cpn++;
5034 } while (i < cph->cph_pn_cnt);
5035 }
5036
5037 print_transport_label(attr);
5038
5039 return (B_FALSE);
5040 }
5041
5042 static boolean_t
5043 tcp_report_item_v6(const mib2_tcp6ConnEntry_t *tp6,
5044 conn_pid_node_list_hdr_t *cph, boolean_t first,
5045 const mib2_transportMLPEntry_t *attr)
5046 {
5047 /*
5048 * lname and fname below are for the hostname as well as the portname
5049 * There is no limit on portname length so we assume MAXHOSTNAMELEN
5050 * as the limit
5051 */
5052 char lname[MAXHOSTNAMELEN + MAXHOSTNAMELEN + 1];
5053 char fname[MAXHOSTNAMELEN + MAXHOSTNAMELEN + 1];
5054 char ifname[LIFNAMSIZ + 1];
5055 char *ifnamep;
5056
5057 if (!(Aflag || tp6->tcp6ConnEntryInfo.ce_state >= TCPS_ESTABLISHED))
5058 return (first); /* Nothing to print */
5059
5060 if (first) {
5061 (void) printf(tcp_hdr_v6);
5062 if (Uflag)
5063 (void) printf(Vflag ? tcp_hdr_v6_pid_verbose :
5064 tcp_hdr_v6_pid);
5065 else
5066 (void) printf(Vflag ? tcp_hdr_v6_verbose :
5067 tcp_hdr_v6_normal);
5068 }
5069
5070 ifnamep = (tp6->tcp6ConnIfIndex != 0) ?
5071 if_indextoname(tp6->tcp6ConnIfIndex, ifname) : NULL;
5072 if (ifnamep == NULL)
5073 ifnamep = "";
5074
5075 if ((!Uflag) && Vflag) {
5076 (void) printf("%-33s\n%-33s %5u %08x %08x %5u %08x %08x "
5077 "%5u %5u %-11s %s\n",
5078 pr_ap6(&tp6->tcp6ConnLocalAddress,
5079 tp6->tcp6ConnLocalPort, "tcp", lname, sizeof (lname)),
5080 pr_ap6(&tp6->tcp6ConnRemAddress,
5081 tp6->tcp6ConnRemPort, "tcp", fname, sizeof (fname)),
5082 tp6->tcp6ConnEntryInfo.ce_swnd,
5083 tp6->tcp6ConnEntryInfo.ce_snxt,
5084 tp6->tcp6ConnEntryInfo.ce_suna,
5085 tp6->tcp6ConnEntryInfo.ce_rwnd,
5086 tp6->tcp6ConnEntryInfo.ce_rnxt,
5087 tp6->tcp6ConnEntryInfo.ce_rack,
5088 tp6->tcp6ConnEntryInfo.ce_rto,
5089 tp6->tcp6ConnEntryInfo.ce_mss,
5090 mitcp_state(tp6->tcp6ConnEntryInfo.ce_state, attr),
5091 ifnamep);
5092 } else if ((!Uflag) && (!Vflag)) {
5093 int sq = (int)tp6->tcp6ConnEntryInfo.ce_snxt -
5094 (int)tp6->tcp6ConnEntryInfo.ce_suna - 1;
5095 int rq = (int)tp6->tcp6ConnEntryInfo.ce_rnxt -
5096 (int)tp6->tcp6ConnEntryInfo.ce_rack;
5097
5098 (void) printf("%-33s %-33s %5u %6d %5u %6d %-11s %s\n",
5099 pr_ap6(&tp6->tcp6ConnLocalAddress,
5100 tp6->tcp6ConnLocalPort, "tcp", lname, sizeof (lname)),
5101 pr_ap6(&tp6->tcp6ConnRemAddress,
5102 tp6->tcp6ConnRemPort, "tcp", fname, sizeof (fname)),
5103 tp6->tcp6ConnEntryInfo.ce_swnd,
5104 (sq >= 0) ? sq : 0,
5105 tp6->tcp6ConnEntryInfo.ce_rwnd,
5106 (rq >= 0) ? rq : 0,
5107 mitcp_state(tp6->tcp6ConnEntryInfo.ce_state, attr),
5108 ifnamep);
5109 } else if (Uflag && Vflag) {
5110 int i = 0;
5111 conn_pid_node_t *cpn = cph->cph_cpns;
5112 proc_info_t *pinfo;
5113
5114 do {
5115 int pid = (cph->cph_pn_cnt)?cpn->cpn_pid:0;
5116 pinfo = get_proc_info(cpn->cpn_pid);
5117
5118 (void) printf("%-33s\n%-33s %7u %08x %08x %7u %08x %08x "
5119 "%5u %5u %-11s %-5.5s %-8.8s %6u %s\n",
5120 pr_ap6(&tp6->tcp6ConnLocalAddress,
5121 tp6->tcp6ConnLocalPort, "tcp", lname, sizeof (lname)),
5122 pr_ap6(&tp6->tcp6ConnRemAddress,
5123 tp6->tcp6ConnRemPort, "tcp", fname, sizeof (fname)),
5124 tp6->tcp6ConnEntryInfo.ce_swnd,
5125 tp6->tcp6ConnEntryInfo.ce_snxt,
5126 tp6->tcp6ConnEntryInfo.ce_suna,
5127 tp6->tcp6ConnEntryInfo.ce_rwnd,
5128 tp6->tcp6ConnEntryInfo.ce_rnxt,
5129 tp6->tcp6ConnEntryInfo.ce_rack,
5130 tp6->tcp6ConnEntryInfo.ce_rto,
5131 tp6->tcp6ConnEntryInfo.ce_mss,
5132 mitcp_state(tp6->tcp6ConnEntryInfo.ce_state, attr),
5133 ifnamep, pinfo->pr_user, pid, pinfo->pr_psargs);
5134 i++; cpn++;
5135 } while (i < cph->cph_pn_cnt);
5136 } else if (Uflag && (!Vflag)) {
5137 int sq = (int)tp6->tcp6ConnEntryInfo.ce_snxt -
5138 (int)tp6->tcp6ConnEntryInfo.ce_suna - 1;
5139 int rq = (int)tp6->tcp6ConnEntryInfo.ce_rnxt -
5140 (int)tp6->tcp6ConnEntryInfo.ce_rack;
5141 int i = 0;
5142 conn_pid_node_t *cpn = cph->cph_cpns;
5143 proc_info_t *pinfo;
5144
5145 do {
5146 int pid = (cph->cph_pn_cnt)?cpn->cpn_pid:0;
5147 pinfo = get_proc_info(cpn->cpn_pid);
5148
5149 (void) printf("%-33s %-33s %-8.8s %6u %-14.14s %7d %6u %7d %6d %-11s %s\n",
5150 pr_ap6(&tp6->tcp6ConnLocalAddress,
5151 tp6->tcp6ConnLocalPort, "tcp", lname, sizeof (lname)),
5152 pr_ap6(&tp6->tcp6ConnRemAddress,
5153 tp6->tcp6ConnRemPort, "tcp", fname, sizeof (fname)),
5154 pinfo->pr_user, pid, pinfo->pr_fname,
5155 tp6->tcp6ConnEntryInfo.ce_swnd,
5156 (sq >= 0) ? sq : 0,
5157 tp6->tcp6ConnEntryInfo.ce_rwnd,
5158 (rq >= 0) ? rq : 0,
5159 mitcp_state(tp6->tcp6ConnEntryInfo.ce_state, attr),
5160 ifnamep);
5161
5162 i++; cpn++;
5163 } while (i < cph->cph_pn_cnt);
5164 }
5165
5166 print_transport_label(attr);
5167
5168 return (B_FALSE);
5169 }
5170
5171 /* ------------------------------- UDP_REPORT------------------------------- */
5172
5173 static boolean_t udp_report_item_v4(const mib2_udpEntry_t *ude,
5174 conn_pid_node_list_hdr_t *cph, boolean_t first,
5175 const mib2_transportMLPEntry_t *attr);
5176 static boolean_t udp_report_item_v6(const mib2_udp6Entry_t *ude6,
5177 conn_pid_node_list_hdr_t *cph, boolean_t first,
5178 const mib2_transportMLPEntry_t *attr);
5179
5180 static const char udp_hdr_v4[] =
5181 " Local Address Remote Address State\n"
5182 "-------------------- -------------------- ----------\n";
5183 static const char udp_hdr_v4_pid[] =
5184 " Local Address Remote Address User Pid "
5185 " Command State\n"
5186 "-------------------- -------------------- -------- ------ "
5187 "-------------- ----------\n";
5188 static const char udp_hdr_v4_pid_verbose[] =
5189 " Local Address Remote Address User Pid State "
5190 " Command\n"
5191 "-------------------- -------------------- -------- ------ ---------- "
5192 "----------------\n";
5193
5194 static const char udp_hdr_v6[] =
5195 " Local Address Remote Address "
5196 " State If\n"
5197 "--------------------------------- --------------------------------- "
5198 "---------- -----\n";
5199 static const char udp_hdr_v6_pid[] =
5200 " Local Address Remote Address "
5201 " User Pid Command State If\n"
5202 "--------------------------------- --------------------------------- "
5203 "-------- ------ -------------- ---------- -----\n";
5204 static const char udp_hdr_v6_pid_verbose[] =
5205 " Local Address Remote Address "
5206 " User Pid State If Command\n"
5207 "--------------------------------- --------------------------------- "
5208 "-------- ------ ---------- ----- ----------------\n";
5209
5210
5211 static void
5212 udp_report(const mib_item_t *item)
5213 {
5214 int jtemp = 0;
5215 boolean_t print_hdr_once_v4 = B_TRUE;
5216 boolean_t print_hdr_once_v6 = B_TRUE;
5217 mib2_udpEntry_t *ude;
5218 mib2_udp6Entry_t *ude6;
5219 mib2_transportMLPEntry_t **v4_attrs, **v6_attrs;
5220 mib2_transportMLPEntry_t **v4a, **v6a;
5221 mib2_transportMLPEntry_t *aptr;
5222 conn_pid_node_list_hdr_t *cph;
5223
5224 if (!protocol_selected(IPPROTO_UDP))
5225 return;
5226
5227 /*
5228 * Preparation pass: the kernel returns separate entries for UDP
5229 * connection table entries and Multilevel Port attributes. We loop
5230 * through the attributes first and set up an array for each address
5231 * family.
5232 */
5233 v4_attrs = family_selected(AF_INET) && RSECflag ?
5234 gather_attrs(item, MIB2_UDP, MIB2_UDP_ENTRY, udpEntrySize) : NULL;
5235 v6_attrs = family_selected(AF_INET6) && RSECflag ?
5236 gather_attrs(item, MIB2_UDP6, MIB2_UDP6_ENTRY, udp6EntrySize) :
5237 NULL;
5238
5239 v4a = v4_attrs;
5240 v6a = v6_attrs;
5241 /* 'for' loop 1: */
5242 for (; item; item = item->next_item) {
5243 if (Xflag) {
5244 (void) printf("\n--- Entry %d ---\n", ++jtemp);
5245 (void) printf("Group = %d, mib_id = %d, "
5246 "length = %d, valp = 0x%p\n",
5247 item->group, item->mib_id,
5248 item->length, item->valp);
5249 }
5250 if (!((item->group == MIB2_UDP &&
5251 item->mib_id == MIB2_UDP_ENTRY) ||
5252 (item->group == MIB2_UDP6 &&
5253 item->mib_id == MIB2_UDP6_ENTRY) ||
5254 (item->group == MIB2_UDP &&
5255 item->mib_id == EXPER_XPORT_PROC_INFO) ||
5256 (item->group == MIB2_UDP6 &&
5257 item->mib_id == EXPER_XPORT_PROC_INFO)))
5258 continue; /* 'for' loop 1 */
5259
5260 if (item->group == MIB2_UDP && !family_selected(AF_INET))
5261 continue; /* 'for' loop 1 */
5262 else if (item->group == MIB2_UDP6 && !family_selected(AF_INET6))
5263 continue; /* 'for' loop 1 */
5264
5265 /* xxx.xxx.xxx.xxx,pppp sss... */
5266 if ((!Uflag) && item->group == MIB2_UDP &&
5267 item->mib_id == MIB2_UDP_ENTRY) {
5268 for (ude = (mib2_udpEntry_t *)item->valp;
5269 (char *)ude < (char *)item->valp + item->length;
5270 /* LINTED: (note 1) */
5271 ude = (mib2_udpEntry_t *)((char *)ude +
5272 udpEntrySize)) {
5273 aptr = v4a == NULL ? NULL : *v4a++;
5274 print_hdr_once_v4 = udp_report_item_v4(ude,
5275 NULL, print_hdr_once_v4, aptr);
5276 }
5277 } else if ((!Uflag) && item->group == MIB2_UDP6 &&
5278 item->mib_id == MIB2_UDP6_ENTRY) {
5279 for (ude6 = (mib2_udp6Entry_t *)item->valp;
5280 (char *)ude6 < (char *)item->valp + item->length;
5281 /* LINTED: (note 1) */
5282 ude6 = (mib2_udp6Entry_t *)((char *)ude6 +
5283 udp6EntrySize)) {
5284 aptr = v6a == NULL ? NULL : *v6a++;
5285 print_hdr_once_v6 = udp_report_item_v6(ude6,
5286 NULL, print_hdr_once_v6, aptr);
5287 }
5288 } else if ((Uflag) && item->group == MIB2_UDP &&
5289 item->mib_id == EXPER_XPORT_PROC_INFO) {
5290 for (ude = (mib2_udpEntry_t *)item->valp;
5291 (char *)ude < (char *)item->valp + item->length;
5292 /* LINTED: (note 1) */
5293 ude = (mib2_udpEntry_t *)((char *)cph +
5294 cph->cph_tot_size)) {
5295 aptr = v4a == NULL ? NULL : *v4a++;
5296 /* LINTED: (note 1) */
5297 cph = (conn_pid_node_list_hdr_t *)
5298 ((char *)ude + udpEntrySize);
5299 print_hdr_once_v4 = udp_report_item_v4(ude,
5300 cph, print_hdr_once_v4, aptr);
5301 }
5302 } else if ((Uflag) && item->group == MIB2_UDP6 &&
5303 item->mib_id == EXPER_XPORT_PROC_INFO) {
5304 for (ude6 = (mib2_udp6Entry_t *)item->valp;
5305 (char *)ude6 < (char *)item->valp + item->length;
5306 /* LINTED: (note 1) */
5307 ude6 = (mib2_udp6Entry_t *)((char *)cph +
5308 cph->cph_tot_size)) {
5309 aptr = v6a == NULL ? NULL : *v6a++;
5310 /* LINTED: (note 1) */
5311 cph = (conn_pid_node_list_hdr_t *)
5312 ((char *)ude6 + udp6EntrySize);
5313 print_hdr_once_v6 = udp_report_item_v6(ude6,
5314 cph, print_hdr_once_v6, aptr);
5315 }
5316 }
5317 } /* 'for' loop 1 ends */
5318 (void) fflush(stdout);
5319
5320 if (v4_attrs != NULL)
5321 free(v4_attrs);
5322 if (v6_attrs != NULL)
5323 free(v6_attrs);
5324 }
5325
5326 static boolean_t
5327 udp_report_item_v4(const mib2_udpEntry_t *ude, conn_pid_node_list_hdr_t *cph,
5328 boolean_t first, const mib2_transportMLPEntry_t *attr)
5329 {
5330 char lname[MAXHOSTNAMELEN + MAXHOSTNAMELEN + 1];
5331 /* hostname + portname */
5332
5333 if (!(Aflag || ude->udpEntryInfo.ue_state >= MIB2_UDP_connected))
5334 return (first); /* Nothing to print */
5335
5336 if (first) {
5337 (void) printf(v4compat ? "\nUDP\n" : "\nUDP: IPv4\n");
5338
5339 if (Uflag)
5340 (void) printf(Vflag ? udp_hdr_v4_pid_verbose :
5341 udp_hdr_v4_pid);
5342 else
5343 (void) printf(udp_hdr_v4);
5344
5345 first = B_FALSE;
5346 }
5347
5348 (void) printf("%-20s %-20s ",
5349 pr_ap(ude->udpLocalAddress, ude->udpLocalPort, "udp",
5350 lname, sizeof (lname)),
5351 ude->udpEntryInfo.ue_state == MIB2_UDP_connected ?
5352 pr_ap(ude->udpEntryInfo.ue_RemoteAddress,
5353 ude->udpEntryInfo.ue_RemotePort, "udp", lname, sizeof (lname)) :
5354 "");
5355 if (!Uflag) {
5356 (void) printf("%s\n",
5357 miudp_state(ude->udpEntryInfo.ue_state, attr));
5358 } else {
5359 int i = 0;
5360 conn_pid_node_t *cpn = cph->cph_cpns;
5361 proc_info_t *pinfo;
5362
5363 do {
5364 int pid = (cph->cph_pn_cnt)?cpn->cpn_pid:0;
5365 pinfo = get_proc_info(cpn->cpn_pid);
5366 (void) printf("%-8.8s %6u ", pinfo->pr_user, pid);
5367
5368 if (Vflag) {
5369 (void) printf("%-10.10s %s\n",
5370 miudp_state(ude->udpEntryInfo.ue_state,
5371 attr),
5372 pinfo->pr_psargs);
5373 } else {
5374 (void) printf("%-14.14s %s\n", pinfo->pr_fname,
5375 miudp_state(ude->udpEntryInfo.ue_state,
5376 attr));
5377 }
5378 i++; cpn++;
5379 } while (i < cph->cph_pn_cnt);
5380 }
5381
5382 print_transport_label(attr);
5383
5384 return (first);
5385 }
5386
5387 static boolean_t
5388 udp_report_item_v6(const mib2_udp6Entry_t *ude6, conn_pid_node_list_hdr_t *cph,
5389 boolean_t first, const mib2_transportMLPEntry_t *attr)
5390 {
5391 char lname[MAXHOSTNAMELEN + MAXHOSTNAMELEN + 1];
5392 /* hostname + portname */
5393 char ifname[LIFNAMSIZ + 1];
5394 const char *ifnamep;
5395
5396 if (!(Aflag || ude6->udp6EntryInfo.ue_state >= MIB2_UDP_connected))
5397 return (first); /* Nothing to print */
5398
5399 if (first) {
5400 (void) printf("\nUDP: IPv6\n");
5401
5402 if (Uflag)
5403 (void) printf(Vflag ? udp_hdr_v6_pid_verbose :
5404 udp_hdr_v6_pid);
5405 else
5406 (void) printf(udp_hdr_v6);
5407
5408 first = B_FALSE;
5409 }
5410
5411 ifnamep = (ude6->udp6IfIndex != 0) ?
5412 if_indextoname(ude6->udp6IfIndex, ifname) : NULL;
5413
5414 (void) printf("%-33s %-33s ",
5415 pr_ap6(&ude6->udp6LocalAddress,
5416 ude6->udp6LocalPort, "udp", lname, sizeof (lname)),
5417 ude6->udp6EntryInfo.ue_state == MIB2_UDP_connected ?
5418 pr_ap6(&ude6->udp6EntryInfo.ue_RemoteAddress,
5419 ude6->udp6EntryInfo.ue_RemotePort, "udp", lname, sizeof (lname)) :
5420 "");
5421 if (!Uflag) {
5422 (void) printf("%-10s %s\n",
5423 miudp_state(ude6->udp6EntryInfo.ue_state, attr),
5424 ifnamep == NULL ? "" : ifnamep);
5425 } else {
5426 int i = 0;
5427 conn_pid_node_t *cpn = cph->cph_cpns;
5428 proc_info_t *pinfo;
5429
5430 do {
5431 int pid = (cph->cph_pn_cnt)?cpn->cpn_pid:0;
5432 pinfo = get_proc_info(cpn->cpn_pid);
5433 (void) printf("%-8.8s %6u ", pinfo->pr_user, pid);
5434
5435 if (Vflag) {
5436 (void) printf("%-10.10s %-5.5s %s\n",
5437 miudp_state(ude6->udp6EntryInfo.ue_state,
5438 attr),
5439 ifnamep == NULL ? "" : ifnamep,
5440 pinfo->pr_psargs);
5441 } else {
5442 (void) printf("%-14.14s %-10.10s %s\n",
5443 pinfo->pr_fname,
5444 miudp_state(ude6->udp6EntryInfo.ue_state,
5445 attr),
5446 ifnamep == NULL ? "" : ifnamep);
5447 }
5448 i++; cpn++;
5449 } while (i < cph->cph_pn_cnt);
5450 }
5451
5452 print_transport_label(attr);
5453
5454 return (first);
5455 }
5456
5457 /* ------------------------------ SCTP_REPORT------------------------------- */
5458
5459 static const char sctp_hdr[] =
5460 "\nSCTP:";
5461 static const char sctp_hdr_normal[] =
5462 " Local Address Remote Address "
5463 "Swind Send-Q Rwind Recv-Q StrsI/O State\n"
5464 "------------------------------- ------------------------------- "
5465 "------ ------ ------ ------ ------- -----------";
5466 static const char sctp_hdr_pid[] =
5467 " Local Address Remote Address "
5468 "Swind Send-Q Rwind Recv-Q StrsI/O User Pid Command State\n"
5469 "------------------------------- ------------------------------- ------ "
5470 "------ ------ ------ ------- -------- ------ -------------- -----------";
5471 static const char sctp_hdr_pid_verbose[] =
5472 " Local Address Remote Address "
5473 "Swind Send-Q Rwind Recv-Q StrsI/O User Pid State Command\n"
5474 "------------------------------- ------------------------------- ------ "
5475 "------ ------ ------ ------- -------- ------ ----------- --------------";
5476
5477 static const char *
5478 nssctp_state(int state, const mib2_transportMLPEntry_t *attr)
5479 {
5480 static char sctpsbuf[50];
5481 const char *cp;
5482
5483 switch (state) {
5484 case MIB2_SCTP_closed:
5485 cp = "CLOSED";
5486 break;
5487 case MIB2_SCTP_cookieWait:
5488 cp = "COOKIE_WAIT";
5489 break;
5490 case MIB2_SCTP_cookieEchoed:
5491 cp = "COOKIE_ECHOED";
5492 break;
5493 case MIB2_SCTP_established:
5494 cp = "ESTABLISHED";
5495 break;
5622 } else {
5623 (void) pr_addr(v4addr, name, namelen);
5624 }
5625 break;
5626
5627 case MIB2_SCTP_ADDR_V6:
5628 /* v6 */
5629 if (port > 0) {
5630 (void) pr_ap6(addr, port, "sctp", name, namelen);
5631 } else {
5632 (void) pr_addr6(addr, name, namelen);
5633 }
5634 break;
5635
5636 default:
5637 (void) snprintf(name, namelen, "<unknown addr type>");
5638 break;
5639 }
5640 }
5641
5642 static boolean_t
5643 sctp_conn_report_item(const mib_item_t *head, conn_pid_node_list_hdr_t * cph,
5644 boolean_t print_sctp_hdr, const mib2_sctpConnEntry_t *sp,
5645 const mib2_transportMLPEntry_t *attr)
5646 {
5647 char lname[MAXHOSTNAMELEN + MAXHOSTNAMELEN + 1];
5648 char fname[MAXHOSTNAMELEN + MAXHOSTNAMELEN + 1];
5649 const mib2_sctpConnRemoteEntry_t *sre = NULL;
5650 const mib2_sctpConnLocalEntry_t *sle = NULL;
5651 const mib_item_t *local = head;
5652 const mib_item_t *remote = head;
5653 uint32_t id = sp->sctpAssocId;
5654 boolean_t printfirst = B_TRUE;
5655
5656 if (print_sctp_hdr == B_TRUE) {
5657 (void) puts(sctp_hdr);
5658 if (Uflag)
5659 (void) puts(Vflag? sctp_hdr_pid_verbose: sctp_hdr_pid);
5660 else
5661 (void) puts(sctp_hdr_normal);
5662
5663 print_sctp_hdr = B_FALSE;
5664 }
5665
5666 sctp_pr_addr(sp->sctpAssocRemPrimAddrType, fname, sizeof (fname),
5667 &sp->sctpAssocRemPrimAddr, sp->sctpAssocRemPort);
5668 sctp_pr_addr(sp->sctpAssocRemPrimAddrType, lname, sizeof (lname),
5669 &sp->sctpAssocLocPrimAddr, sp->sctpAssocLocalPort);
5670
5671 if (Uflag) {
5672 int i = 0;
5673 conn_pid_node_t *cpn = cph->cph_cpns;
5674 proc_info_t *pinfo;
5675
5676 do {
5677 int pid = (cph->cph_pn_cnt)?cpn->cpn_pid:0;
5678 pinfo = get_proc_info(cpn->cpn_pid);
5679 (void) printf("%-31s %-31s %6u %6d %6u %6d %3d/%-3d %-8.8s %6u ",
5680 lname, fname,
5681 sp->sctpConnEntryInfo.ce_swnd,
5682 sp->sctpConnEntryInfo.ce_sendq,
5683 sp->sctpConnEntryInfo.ce_rwnd,
5684 sp->sctpConnEntryInfo.ce_recvq,
5685 sp->sctpAssocInStreams,
5686 sp->sctpAssocOutStreams,
5687 pinfo->pr_user, pid);
5688
5689 if (Vflag) {
5690 (void) printf("%-11.11s %s\n",
5691 nssctp_state(sp->sctpAssocState, attr),
5692 pinfo->pr_psargs);
5693 } else {
5694 (void) printf("%-14.14s %s\n",
5695 pinfo->pr_fname,
5696 nssctp_state(sp->sctpAssocState, attr));
5697 }
5698
5699 i++; cpn++;
5700 } while (i < cph->cph_pn_cnt);
5701
5702 } else {
5703
5704 (void) printf("%-31s %-31s %6u %6d %6u %6d %3d/%-3d %s\n",
5705 lname, fname,
5706 sp->sctpConnEntryInfo.ce_swnd,
5707 sp->sctpConnEntryInfo.ce_sendq,
5708 sp->sctpConnEntryInfo.ce_rwnd,
5709 sp->sctpConnEntryInfo.ce_recvq,
5710 sp->sctpAssocInStreams, sp->sctpAssocOutStreams,
5711 nssctp_state(sp->sctpAssocState, attr));
5712 }
5713
5714 print_transport_label(attr);
5715
5716 if (!Vflag) {
5717 return (print_sctp_hdr);
5718 }
5719
5720 /* Print remote addresses/local addresses on following lines */
5721 while ((sre = sctp_getnext_rem(&remote, sre, id)) != NULL) {
5722 if (!IN6_ARE_ADDR_EQUAL(&sre->sctpAssocRemAddr,
5723 &sp->sctpAssocRemPrimAddr)) {
5724 if (printfirst == B_TRUE) {
5725 (void) fputs("\t<Remote: ", stdout);
5726 printfirst = B_FALSE;
5727 } else {
5728 (void) fputs(", ", stdout);
5729 }
5730 sctp_pr_addr(sre->sctpAssocRemAddrType, fname,
5731 sizeof (fname), &sre->sctpAssocRemAddr, -1);
5732 if (sre->sctpAssocRemAddrActive == MIB2_SCTP_ACTIVE) {
5733 (void) fputs(fname, stdout);
5734 } else {
5735 (void) printf("(%s)", fname);
5736 }
5737 }
5740 (void) puts(">");
5741 printfirst = B_TRUE;
5742 }
5743 while ((sle = sctp_getnext_local(&local, sle, id)) != NULL) {
5744 if (!IN6_ARE_ADDR_EQUAL(&sle->sctpAssocLocalAddr,
5745 &sp->sctpAssocLocPrimAddr)) {
5746 if (printfirst == B_TRUE) {
5747 (void) fputs("\t<Local: ", stdout);
5748 printfirst = B_FALSE;
5749 } else {
5750 (void) fputs(", ", stdout);
5751 }
5752 sctp_pr_addr(sle->sctpAssocLocalAddrType, lname,
5753 sizeof (lname), &sle->sctpAssocLocalAddr, -1);
5754 (void) fputs(lname, stdout);
5755 }
5756 }
5757 if (printfirst == B_FALSE) {
5758 (void) puts(">");
5759 }
5760
5761 return (print_sctp_hdr);
5762 }
5763
5764 static void
5765 sctp_report(const mib_item_t *item)
5766 {
5767 const mib_item_t *head;
5768 const mib2_sctpConnEntry_t *sp;
5769 boolean_t print_sctp_hdr_once = B_TRUE;
5770 mib2_transportMLPEntry_t **attrs, **aptr;
5771 mib2_transportMLPEntry_t *attr;
5772 conn_pid_node_list_hdr_t *cph;
5773
5774 /*
5775 * Preparation pass: the kernel returns separate entries for SCTP
5776 * connection table entries and Multilevel Port attributes. We loop
5777 * through the attributes first and set up an array for each address
5778 * family.
5779 */
5780 attrs = RSECflag ?
5781 gather_attrs(item, MIB2_SCTP, MIB2_SCTP_CONN, sctpEntrySize) :
5782 NULL;
5783
5784 aptr = attrs;
5785 head = item;
5786 for (; item != NULL; item = item->next_item) {
5787
5788 if (!((item->group == MIB2_SCTP &&
5789 item->mib_id == MIB2_SCTP_CONN) ||
5790 (item->group == MIB2_SCTP &&
5791 item->mib_id == EXPER_XPORT_PROC_INFO)))
5792 continue;
5793
5794 if ((!Uflag) && item->group == MIB2_SCTP
5795 && item->mib_id == MIB2_SCTP_CONN) {
5796 for (sp = item->valp;
5797 (char *)sp < (char *)item->valp + item->length;
5798 /* LINTED: (note 1) */
5799 sp = (mib2_sctpConnEntry_t *)((char *)sp + sctpEntrySize)) {
5800 if (!(Aflag ||
5801 sp->sctpAssocState >= MIB2_SCTP_established))
5802 continue;
5803 attr = aptr == NULL ? NULL : *aptr++;
5804 print_sctp_hdr_once = sctp_conn_report_item(head, NULL,
5805 print_sctp_hdr_once, sp,
5806 attr);
5807 }
5808 } else if ((Uflag) && item->group == MIB2_SCTP &&
5809 item->mib_id == EXPER_XPORT_PROC_INFO) {
5810 for (sp = (mib2_sctpConnEntry_t *)item->valp;
5811 (char *)sp < (char *)item->valp + item->length;
5812 /* LINTED: (note 1) */
5813 sp = (mib2_sctpConnEntry_t *)((char *)cph +
5814 cph->cph_tot_size)) {
5815 /* LINTED: (note 1) */
5816 cph = (conn_pid_node_list_hdr_t *)
5817 ((char *)sp + sctpEntrySize);
5818 if (!(Aflag ||
5819 sp->sctpAssocState >= MIB2_SCTP_established))
5820 continue;
5821 attr = aptr == NULL ? NULL : *aptr++;
5822 print_sctp_hdr_once =
5823 sctp_conn_report_item(head, cph,
5824 print_sctp_hdr_once, sp, attr);
5825 }
5826 }
5827 }
5828 if (attrs != NULL)
5829 free(attrs);
5830 }
5831
5832 static char *
5833 plural(int n)
5834 {
5835 return (n != 1 ? "s" : "");
5836 }
5837
5838 static char *
5839 pluraly(int n)
5840 {
5841 return (n != 1 ? "ies" : "y");
5842 }
5843
5844 static char *
6792 }
6793 return (B_FALSE);
6794 }
6795
6796 /*
6797 * Convert the interface index to a string using the buffer `ifname', which
6798 * must be at least LIFNAMSIZ bytes. We first try to map it to name. If that
6799 * fails (e.g., because we're inside a zone and it does not have access to
6800 * interface for the index in question), just return "if#<num>".
6801 */
6802 static char *
6803 ifindex2str(uint_t ifindex, char *ifname)
6804 {
6805 if (if_indextoname(ifindex, ifname) == NULL)
6806 (void) snprintf(ifname, LIFNAMSIZ, "if#%d", ifindex);
6807
6808 return (ifname);
6809 }
6810
6811 /*
6812 * get proc info (psinfo_t) given pid. It doesn't return NULL.
6813 */
6814
6815 proc_info_t *
6816 get_proc_info(uint32_t pid)
6817 {
6818 static uint32_t saved_pid = 0;
6819 static proc_info_t saved_proc_info;
6820 static proc_info_t unknown_proc_info = {"<unknown>","",""};
6821 static psinfo_t pinfo;
6822 char path[128];
6823 int fd;
6824
6825 /* hardcode pid = 0 */
6826 if (pid == 0) {
6827 saved_proc_info.pr_user = "root";
6828 saved_proc_info.pr_fname = "sched";
6829 saved_proc_info.pr_psargs = "sched";
6830 saved_pid = 0;
6831 return &saved_proc_info;
6832 }
6833
6834 if (pid == saved_pid)
6835 return &saved_proc_info;
6836 if ((snprintf(path, 128, "/proc/%u/psinfo",pid) > 0) &&
6837 ((fd = open(path, O_RDONLY)) != -1)) {
6838 if (read(fd, &pinfo, sizeof(pinfo)) == sizeof(pinfo)){
6839 saved_proc_info.pr_user = get_username(pinfo.pr_uid);
6840 saved_proc_info.pr_fname = pinfo.pr_fname;
6841 saved_proc_info.pr_psargs = pinfo.pr_psargs;
6842 saved_pid = pid;
6843 (void) close(fd);
6844 return &saved_proc_info;
6845 } else {
6846 (void) close(fd);
6847 }
6848 }
6849
6850 return (&unknown_proc_info);
6851 }
6852
6853 /*
6854 * get username given uid. It doesn't return NULL.
6855 */
6856
6857 static char *
6858 get_username(uid_t u)
6859 {
6860 static uid_t saved_uid = UINT_MAX;
6861 static char saved_username[128];
6862 struct passwd *pw = NULL;
6863 if (u == UINT_MAX)
6864 return "<unknown>";
6865 if (u == saved_uid && saved_username[0] != '\0')
6866 return (saved_username);
6867 setpwent();
6868 if ((pw = getpwuid(u)) != NULL)
6869 (void) strlcpy(saved_username, pw->pw_name, 128);
6870 else
6871 (void) snprintf(saved_username, 128, "%u", u);
6872 saved_uid = u;
6873 return saved_username;
6874 }
6875
6876 /*
6877 * print the usage line
6878 */
6879 static void
6880 usage(char *cmdname)
6881 {
6882 (void) fprintf(stderr, "usage: %s [-anuv] [-f address_family] "
6883 "[-T d|u]\n", cmdname);
6884 (void) fprintf(stderr, " %s [-n] [-f address_family] "
6885 "[-P protocol] [-T d|u] [-g | -p | -s [interval [count]]]\n",
6886 cmdname);
6887 (void) fprintf(stderr, " %s -m [-v] [-T d|u] "
6888 "[interval [count]]\n", cmdname);
6889 (void) fprintf(stderr, " %s -i [-I interface] [-an] "
6890 "[-f address_family] [-T d|u] [interval [count]]\n", cmdname);
6891 (void) fprintf(stderr, " %s -r [-anv] "
6892 "[-f address_family|filter] [-T d|u]\n", cmdname);
6893 (void) fprintf(stderr, " %s -M [-ns] [-f address_family] "
6894 "[-T d|u]\n", cmdname);
6895 (void) fprintf(stderr, " %s -D [-I interface] "
6896 "[-f address_family] [-T d|u]\n", cmdname);
6897 exit(EXIT_FAILURE);
6898 }
6899
6900 /*
6901 * fatal: print error message to stderr and
6902 * call exit(errcode)
6903 */
6904 /*PRINTFLIKE2*/
6905 static void
6906 fatal(int errcode, char *format, ...)
6907 {
6908 va_list argp;
6909
6910 if (format == NULL)
6911 return;
6912
6913 va_start(argp, format);
6914 (void) vfprintf(stderr, format, argp);
6915 va_end(argp);
6916
6917 exit(errcode);
6918 }
6919
6920
6921 /* -------------------UNIX Domain Sockets Report---------------------------- */
6922
6923
6924 #define NO_ADDR " "
6925 #define SO_PAIR " (socketpair) "
6926
6927 static char *typetoname(t_scalar_t);
6928 static boolean_t uds_report_item(struct sockinfo *, boolean_t);
6929
6930
6931 static char uds_hdr[] = "\nActive UNIX domain sockets\n";
6932
6933 static char uds_hdr_normal[] =
6934 " Type Local Adress "
6935 " Remote Address\n"
6936 "---------- --------------------------------------- "
6937 "---------------------------------------\n";
6938
6939 static char uds_hdr_pid[] =
6940 " Type User Pid Command "
6941 " Local Address "
6942 " Remote Address\n"
6943 "---------- -------- ------ -------------- "
6944 "--------------------------------------- "
6945 "---------------------------------------\n";
6946 static char uds_hdr_pid_verbose[] =
6947 " Type User Pid Local Address "
6948 " Remote Address Command\n"
6949 "---------- -------- ------ --------------------------------------- "
6950 "--------------------------------------- --------------\n";
6951
6952 /*
6953 * Print a summary of connections related to a unix protocol.
6954 */
6955 static void
6956 uds_report(kstat_ctl_t *kc)
6957 {
6958 int i;
6959 kstat_t *ksp;
6960 struct sockinfo *psi; /* ptr to current sockinfo */
6961 boolean_t print_uds_hdr_once = B_TRUE;
6962
6963 if (kc == NULL) { /* sanity check. */
6964 fail(0, "uds_report: No kstat");
6965 exit(3);
6966 }
6967
6968 /* find the sockfs kstat: */
6969 if ((ksp = kstat_lookup(kc, "sockfs", 0, "sock_unix_list")) ==
6970 (kstat_t *)NULL) {
6971 fail(0, "kstat_data_lookup failed\n");
6972 }
6973
6974 if (kstat_read(kc, ksp, NULL) == -1) {
6975 fail(0, "kstat_read failed for sock_unix_list\n");
6976 }
6977
6978 if (ksp->ks_ndata == 0) {
6979 return; /* no AF_UNIX sockets found */
6980 }
6981
6982 /*
6983 * Having ks_data set with ks_data == NULL shouldn't happen;
6984 * If it does, the sockfs kstat is seriously broken.
6985 */
6986 if ((psi = ksp->ks_data) == NULL) {
6987 fail(0, "uds_report: no kstat data\n");
6988 }
6989
6990 /* for each sockinfo structure, display what we need: */
6991 for (i = 0; i < ksp->ks_ndata; i++) {
6992
6993 /* process this entry */
6994 print_uds_hdr_once = uds_report_item(psi, print_uds_hdr_once);
6995
6996 /* if si_size didn't get filled in, then we're done */
6997 if (psi->si_size == 0 ||
6998 !IS_P2ALIGNED(psi->si_size, sizeof (psi))) {
6999 break;
7000 }
7001
7002 /* point to the next sockinfo in the array */
7003 /* LINTED: (note 1) */
7004 psi = (struct sockinfo *)(((char *)psi) + psi->si_size);
7005 }
7006 }
7007
7008 static boolean_t
7009 uds_report_item(struct sockinfo *psi, boolean_t first)
7010 {
7011 int i = 0;
7012 conn_pid_node_t *cpn;
7013 proc_info_t *pinfo;
7014 char *laddr, *raddr;
7015
7016 if(first) {
7017 (void) printf("%s", uds_hdr);
7018 if (Uflag)
7019 (void) printf("%s", Vflag?uds_hdr_pid_verbose:
7020 uds_hdr_pid);
7021 else
7022 (void) printf("%s", uds_hdr_normal);
7023
7024 first = B_FALSE;
7025 }
7026
7027 cpn = psi->si_pns;
7028
7029 do {
7030 int pid = (psi->si_pn_cnt)?cpn->cpn_pid:0;
7031 pinfo = get_proc_info(cpn->cpn_pid);
7032 raddr = laddr = NO_ADDR;
7033
7034 /* laddr.soa_sa: */
7035 if ((psi->si_state & SS_ISBOUND) &&
7036 strlen(psi->si_laddr_sun_path) != 0 &&
7037 psi->si_laddr_soa_len != 0) {
7038 if (psi->si_faddr_noxlate) {
7039 laddr = SO_PAIR;
7040 } else {
7041 if (psi->si_laddr_soa_len >
7042 sizeof (psi->si_laddr_family))
7043 laddr = psi->si_laddr_sun_path;
7044 }
7045 }
7046
7047 /* faddr.soa_sa: */
7048 if ((psi->si_state & SS_ISCONNECTED) &&
7049 strlen(psi->si_faddr_sun_path) != 0 &&
7050 psi->si_faddr_soa_len != 0) {
7051
7052 if (psi->si_faddr_noxlate) {
7053 raddr = SO_PAIR;
7054 } else {
7055 if (psi->si_faddr_soa_len >
7056 sizeof (psi->si_faddr_family))
7057 raddr = psi->si_faddr_sun_path;
7058 }
7059 }
7060
7061 if (Uflag && Vflag) {
7062 (void) printf("%-10.10s %-8.8s %6u "
7063 "%-39.39s %-39.39s %s\n",
7064 typetoname(psi->si_serv_type), pinfo->pr_user,
7065 pid, laddr, raddr, pinfo->pr_psargs);
7066 } else if (Uflag && (!Vflag)) {
7067 (void) printf("%-10.10s %-8.8s %6u %-14.14s"
7068 "%-39.39s %-39.39s\n",
7069 typetoname(psi->si_serv_type), pinfo->pr_user,
7070 pid, pinfo->pr_fname, laddr, raddr);
7071 } else {
7072 (void) printf("%-10.10s %s %s\n",
7073 typetoname(psi->si_serv_type), laddr, raddr);
7074 }
7075
7076 i++; cpn++;
7077 } while (i < psi->si_pn_cnt);
7078
7079 return (first);
7080 }
7081
7082 static char *
7083 typetoname(t_scalar_t type)
7084 {
7085 switch (type) {
7086 case T_CLTS:
7087 return ("dgram");
7088
7089 case T_COTS:
7090 return ("stream");
7091
7092 case T_COTS_ORD:
7093 return ("stream-ord");
7094
7095 default:
7096 return ("");
7097 }
7098 }
|