xref: /dragonfly/usr.bin/netstat/inet.c (revision 110def69)
1 /*
2  * Copyright (c) 1983, 1988, 1993, 1995
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * @(#)inet.c	8.5 (Berkeley) 5/24/95
30  * $FreeBSD: src/usr.bin/netstat/inet.c,v 1.37.2.11 2003/11/27 14:46:49 ru Exp $
31  */
32 
33 #include <sys/param.h>
34 #include <sys/queue.h>
35 #include <sys/socket.h>
36 #include <sys/socketvar.h>
37 #include <sys/sysctl.h>
38 #include <sys/protosw.h>
39 #include <sys/time.h>
40 
41 #include <net/route.h>
42 #include <netinet/in.h>
43 #include <netinet/in_systm.h>
44 #include <netinet/ip.h>
45 #include <netinet/ip_carp.h>
46 #ifdef INET6
47 #include <netinet/ip6.h>
48 #endif /* INET6 */
49 #include <netinet/in_pcb.h>
50 #include <netinet/ip_icmp.h>
51 #include <netinet/icmp_var.h>
52 #include <netinet/igmp_var.h>
53 #include <netinet/ip_var.h>
54 #include <netinet/pim_var.h>
55 #include <netinet/tcp.h>
56 #include <netinet/tcpip.h>
57 #include <netinet/tcp_seq.h>
58 #define TCPSTATES
59 #include <netinet/tcp_fsm.h>
60 #include <netinet/tcp_timer.h>
61 #include <netinet/tcp_var.h>
62 #include <netinet/tcp_debug.h>
63 #include <netinet/udp.h>
64 #include <netinet/udp_var.h>
65 
66 #include <arpa/inet.h>
67 #include <err.h>
68 #include <errno.h>
69 #include <libutil.h>
70 #include <netdb.h>
71 #include <stdio.h>
72 #include <stdlib.h>
73 #include <string.h>
74 #include <unistd.h>
75 #include "netstat.h"
76 
77 char	*inetname (struct in_addr *);
78 void	inetprint (struct in_addr *, int, const char *, int);
79 #ifdef INET6
80 extern void	inet6print (struct in6_addr *, int, const char *, int);
81 static int udp_done, tcp_done;
82 #endif /* INET6 */
83 
84 /*
85  * Print a summary of connections related to an Internet
86  * protocol.  For TCP, also give state of connection.
87  * Listening processes (aflag) are suppressed unless the
88  * -a (all) flag is specified.
89  */
90 
91 static int ppr_first = 1;
92 static void outputpcb(int proto, const char *name, struct inpcb *inp, struct xsocket *so, struct tcpcb *tp);
93 
94 void
95 protopr(u_long proto, const char *name, int af1 __unused)
96 {
97 	int istcp;
98 	void *buf;
99 	const char *mibvar;
100 	size_t i, len;
101 
102 	istcp = 0;
103 	switch (proto) {
104 	case IPPROTO_TCP:
105 #ifdef INET6
106 		if (tcp_done != 0)
107 			return;
108 		else
109 			tcp_done = 1;
110 #endif
111 		istcp = 1;
112 		mibvar = "net.inet.tcp.pcblist";
113 		break;
114 	case IPPROTO_UDP:
115 #ifdef INET6
116 		if (udp_done != 0)
117 			return;
118 		else
119 			udp_done = 1;
120 #endif
121 		mibvar = "net.inet.udp.pcblist";
122 		break;
123 	case IPPROTO_DIVERT:
124 		mibvar = "net.inet.divert.pcblist";
125 		break;
126 	default:
127 		mibvar = "net.inet.raw.pcblist";
128 		break;
129 	}
130 	len = 0;
131 	if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) {
132 		if (errno != ENOENT)
133 			warn("sysctl: %s", mibvar);
134 		return;
135 	}
136 	if (len == 0)
137 		return;
138 	if ((buf = malloc(len)) == NULL) {
139 		warn("malloc %lu bytes", (u_long)len);
140 		return;
141 	}
142 	if (sysctlbyname(mibvar, buf, &len, 0, 0) < 0) {
143 		warn("sysctl: %s", mibvar);
144 		free(buf);
145 		return;
146 	}
147 
148 	if (istcp) {
149 		struct xtcpcb *tcp = buf;
150 		len /= sizeof(*tcp);
151 		for (i = 0; i < len; i++) {
152 			if (tcp[i].xt_len != sizeof(*tcp))
153 				break;
154 			outputpcb(proto, name, &tcp[i].xt_inp,
155 				  &tcp[i].xt_socket, &tcp[i].xt_tp);
156 		}
157 	} else {
158 		struct xinpcb *in = buf;
159 		len /= sizeof(*in);
160 		for (i = 0; i < len; i++) {
161 			if (in[i].xi_len != sizeof(*in))
162 				break;
163 			outputpcb(proto, name, &in[i].xi_inp,
164 				  &in[i].xi_socket, NULL);
165 		}
166 	}
167 	free(buf);
168 }
169 
170 static void
171 outputpcb(int proto, const char *name, struct inpcb *inp, struct xsocket *so, struct tcpcb *tp)
172 {
173 	const char *vchar;
174 	static struct clockinfo clockinfo;
175 
176 	if (clockinfo.hz == 0) {
177 		size_t size = sizeof(clockinfo);
178 		sysctlbyname("kern.clockrate", &clockinfo, &size, NULL, 0);
179 		if (clockinfo.hz == 0)
180 			clockinfo.hz = 100;
181 	}
182 
183 	/* Ignore sockets for protocols other than the desired one. */
184 	if (so->xso_protocol != (int)proto)
185 		return;
186 
187 	if ((af == AF_INET && !INP_ISIPV4(inp))
188 #ifdef INET6
189 	    || (af == AF_INET6 && !INP_ISIPV6(inp))
190 #endif /* INET6 */
191 	    || (af == AF_UNSPEC && (!INP_ISIPV4(inp)
192 #ifdef INET6
193 		&& !INP_ISIPV6(inp)
194 #endif /* INET6 */
195 		))
196 	    ) {
197 		return;
198 	}
199 	if (!aflag && (
200 		(proto == IPPROTO_TCP && tp->t_state == TCPS_LISTEN) ||
201 		(af == AF_INET && inet_lnaof(inp->inp_laddr) == INADDR_ANY)
202 #ifdef INET6
203 	    || (af == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr))
204 #endif /* INET6 */
205 	    || (af == AF_UNSPEC && ((INP_ISIPV4(inp) &&
206 		inet_lnaof(inp->inp_laddr) == INADDR_ANY)
207 #ifdef INET6
208 	    || (INP_ISIPV6(inp) &&
209 		IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr))
210 #endif
211 		  ))
212 	     )) {
213 		return;
214 	}
215 
216 	if (ppr_first) {
217 		if (!Lflag) {
218 			printf("Active Internet connections");
219 			if (aflag)
220 				printf(" (including servers)");
221 		} else {
222 			printf("Current listen queue sizes "
223 				"(qlen/incqlen/maxqlen)");
224 		}
225 		putchar('\n');
226 		if (Aflag)
227 			printf("%-8.8s ", "Socket");
228 		if (Pflag)
229 			printf("%8.8s %8.8s %8.8s ", "TxWin", "Unacked", "RTT/ms");
230 		if (Lflag) {
231 			printf("%-5.5s %-14.14s %-22.22s\n",
232 				"Proto", "Listen", "Local Address");
233 		} else {
234 			printf((Aflag && !Wflag) ?
235 			    "%-5.5s %-6.6s %-6.6s %-17.17s %-17.17s %s\n" :
236 			    "%-5.5s %-6.6s %-6.6s %-21.21s %-21.21s %s\n",
237 			    "Proto", "Recv-Q", "Send-Q",
238 			    "Local Address", "Foreign Address",
239 			    "(state)");
240 		}
241 		ppr_first = 0;
242 	}
243 	if (Lflag && so->so_qlimit == 0)
244 		return;
245 	if (Aflag) {
246 		if (tp)
247 			printf("%8lx ", (u_long)inp->inp_ppcb);
248 		else
249 			printf("%8lx ", (u_long)so->so_pcb);
250 	}
251 	if (Pflag) {
252 		if (tp) {
253 			int window = MIN(tp->snd_cwnd, tp->snd_bwnd);
254 			if (window == 1073725440)
255 				printf("%8s ", "max");
256 			else
257 				printf("%8d ", (int)MIN(tp->snd_cwnd, tp->snd_bwnd));
258 			printf("%8d ", (int)(tp->snd_max - tp->snd_una));
259 			if (tp->t_srtt == 0)
260 			    printf("%8s ", "-");
261 			else
262 			    printf("%8.3f ", (double)tp->t_srtt * 1000.0 / TCP_RTT_SCALE / clockinfo.hz);
263 		} else {
264 			printf("%8s %8s %8s ", "-", "-", "-");
265 		}
266 	}
267 #ifdef INET6
268 	if (INP_ISIPV6(inp))
269 		vchar = "6 ";
270 	else
271 #endif
272 		vchar = INP_ISIPV4(inp) ? "4 " : "  ";
273 
274 	printf("%-3.3s%-2.2s ", name, vchar);
275 	if (Lflag) {
276 		char buf[15];
277 
278 		snprintf(buf, sizeof(buf), "%hd/%hd/%hd", so->so_qlen,
279 			 so->so_incqlen, so->so_qlimit);
280 		printf("%-13.13s ", buf);
281 	} else if (Bflag) {
282 		printf("%6ld %6ld ",
283 		       so->so_rcv.sb_hiwat,
284 		       so->so_snd.sb_hiwat);
285 	} else {
286 		printf("%6ld %6ld ",
287 		       so->so_rcv.sb_cc,
288 		       so->so_snd.sb_cc);
289 	}
290 	if (numeric_port) {
291 		if (INP_ISIPV4(inp)) {
292 			inetprint(&inp->inp_laddr, (int)inp->inp_lport,
293 				  name, 1);
294 			if (!Lflag)
295 				inetprint(&inp->inp_faddr,
296 					  (int)inp->inp_fport, name, 1);
297 		}
298 #ifdef INET6
299 		else if (INP_ISIPV6(inp)) {
300 			inet6print(&inp->in6p_laddr,
301 				   (int)inp->inp_lport, name, 1);
302 			if (!Lflag)
303 				inet6print(&inp->in6p_faddr,
304 					   (int)inp->inp_fport, name, 1);
305 		} /* else nothing printed now */
306 #endif /* INET6 */
307 	} else if (inp->inp_flags & INP_ANONPORT) {
308 		if (INP_ISIPV4(inp)) {
309 			inetprint(&inp->inp_laddr, (int)inp->inp_lport,
310 				  name, 1);
311 			if (!Lflag)
312 				inetprint(&inp->inp_faddr,
313 					  (int)inp->inp_fport, name, 0);
314 		}
315 #ifdef INET6
316 		else if (INP_ISIPV6(inp)) {
317 			inet6print(&inp->in6p_laddr,
318 				   (int)inp->inp_lport, name, 1);
319 			if (!Lflag)
320 				inet6print(&inp->in6p_faddr,
321 					   (int)inp->inp_fport, name, 0);
322 		} /* else nothing printed now */
323 #endif /* INET6 */
324 	} else {
325 		if (INP_ISIPV4(inp)) {
326 			inetprint(&inp->inp_laddr, (int)inp->inp_lport,
327 				  name, 0);
328 			if (!Lflag)
329 				inetprint(&inp->inp_faddr,
330 					  (int)inp->inp_fport, name,
331 					  inp->inp_lport !=
332 						inp->inp_fport);
333 		}
334 #ifdef INET6
335 		else if (INP_ISIPV6(inp)) {
336 			inet6print(&inp->in6p_laddr,
337 				   (int)inp->inp_lport, name, 0);
338 			if (!Lflag)
339 				inet6print(&inp->in6p_faddr,
340 					   (int)inp->inp_fport, name,
341 					   inp->inp_lport !=
342 						inp->inp_fport);
343 		} /* else nothing printed now */
344 #endif /* INET6 */
345 	}
346 	if (tp && !Lflag) {
347 		if (tp->t_state < 0 || tp->t_state >= TCP_NSTATES)
348 			printf("%d", tp->t_state);
349 	      else {
350 			printf("%s", tcpstates[tp->t_state]);
351 #if defined(TF_NEEDSYN) && defined(TF_NEEDFIN)
352 		      /* Show T/TCP `hidden state' */
353 		      if (tp->t_flags & (TF_NEEDSYN|TF_NEEDFIN))
354 			      putchar('*');
355 #endif /* defined(TF_NEEDSYN) && defined(TF_NEEDFIN) */
356 	      }
357 	}
358 	putchar('\n');
359 }
360 
361 
362 
363 #define CPU_STATS_FUNC(proto,type)                            \
364 static void                                                   \
365 proto ##_stats_agg(type *ary, type *ttl, int cpucnt)          \
366 {                                                             \
367     int i, off, siz;                                          \
368     siz = sizeof(type);                                       \
369                                                               \
370     if (!ary && !ttl)                                         \
371         return;                                               \
372                                                               \
373     bzero(ttl, siz);                                          \
374     if (cpucnt == 1) {                                        \
375         *ttl = ary[0];                                        \
376     } else {                                                  \
377         for (i = 0; i < cpucnt; ++i) {                        \
378             for (off = 0; off < siz; off += sizeof(u_long)) { \
379                 *(u_long *)((char *)(*(&ttl)) + off) +=       \
380                 *(u_long *)((char *)&ary[i] + off);           \
381             }                                                 \
382         }                                                     \
383     }                                                         \
384 }
385 CPU_STATS_FUNC(tcp, struct tcp_stats);
386 CPU_STATS_FUNC(ip, struct ip_stats);
387 CPU_STATS_FUNC(udp, struct udpstat);
388 
389 /*
390  * Dump TCP statistics structure.
391  */
392 void
393 tcp_stats(u_long off __unused, const char *name, int af1 __unused)
394 {
395 	u_long state_count[TCP_NSTATES];
396 	struct tcp_stats tcpstat, *stattmp;
397 	struct tcp_stats zerostat[SMP_MAXCPU];
398 	size_t len = sizeof(struct tcp_stats) * SMP_MAXCPU;
399 	int cpucnt;
400 
401 	if (zflag)
402 		memset(zerostat, 0, len);
403 
404 	if ((stattmp = malloc(len)) == NULL) {
405 		return;
406 	} else {
407 		if (sysctlbyname("net.inet.tcp.stats", stattmp, &len,
408 			zflag ? zerostat : NULL, zflag ? len : 0) < 0) {
409 			warn("sysctl: net.inet.tcp.stats");
410 			free(stattmp);
411 			return;
412 		} else {
413 			if ((stattmp = realloc(stattmp, len)) == NULL) {
414 				warn("tcp_stats");
415 				return;
416 			}
417 		}
418 	}
419 	cpucnt = len / sizeof(struct tcp_stats);
420 	tcp_stats_agg(stattmp, &tcpstat, cpucnt);
421 
422 #ifdef INET6
423 	if (tcp_done != 0)
424 		return;
425 	else
426 		tcp_done = 1;
427 #endif
428 
429 	printf ("%s:\n", name);
430 
431 #define	p(f, m) if (tcpstat.f || sflag <= 1) \
432     printf(m, tcpstat.f, plural(tcpstat.f))
433 #define	p1a(f, m) if (tcpstat.f || sflag <= 1) \
434     printf(m, tcpstat.f)
435 #define	p2(f1, f2, m) if (tcpstat.f1 || tcpstat.f2 || sflag <= 1) \
436     printf(m, tcpstat.f1, plural(tcpstat.f1), tcpstat.f2, plural(tcpstat.f2))
437 #define	p2a(f1, f2, m) if (tcpstat.f1 || tcpstat.f2 || sflag <= 1) \
438     printf(m, tcpstat.f1, plural(tcpstat.f1), tcpstat.f2)
439 #define	p3(f, m) if (tcpstat.f || sflag <= 1) \
440     printf(m, tcpstat.f, plurales(tcpstat.f))
441 
442 	p(tcps_sndtotal, "\t%lu packet%s sent\n");
443 	p2(tcps_sndpack,tcps_sndbyte,
444 		"\t\t%lu data packet%s (%lu byte%s)\n");
445 	p2(tcps_sndrexmitpack, tcps_sndrexmitbyte,
446 		"\t\t%lu data packet%s (%lu byte%s) retransmitted\n");
447 	p2(tcps_sndsackrtopack, tcps_sndsackrtobyte,
448 		"\t\t%lu data packet%s (%lu byte%s) retransmitted by SACK\n");
449 	p2(tcps_sndsackpack, tcps_sndsackbyte,
450 		"\t\t%lu data packet%s (%lu byte%s) sent by SACK recovery\n");
451 	p2(tcps_sackrescue, tcps_sackrescue_try,
452 		"\t\t%lu SACK rescue packet%s sent (of %lu attempt%s)\n");
453 	p2a(tcps_sndfastrexmit, tcps_sndearlyrexmit,
454 		"\t\t%lu Fast Retransmit%s (%lu early)\n");
455 	p(tcps_sndlimited, "\t\t%lu packet%s sent by Limited Transmit\n");
456 	p2(tcps_sndrtobad, tcps_eifelresponse,
457 		"\t\t%lu spurious RTO retransmit%s (%lu Eifel-response%s)\n");
458 	p2a(tcps_sndfastrexmitbad, tcps_sndearlyrexmitbad,
459 		"\t\t%lu spurious Fast Retransmit%s (%lu early)\n");
460 	p2a(tcps_eifeldetected, tcps_rttcantdetect,
461 		"\t\t%lu Eifel-detected spurious retransmit%s (%lu non-RTT)\n");
462 	p(tcps_rttdetected, "\t\t%lu RTT-detected spurious retransmit%s\n");
463 	p(tcps_mturesent, "\t\t%lu resend%s initiated by MTU discovery\n");
464 	p(tcps_sndsackopt, "\t\t%lu SACK option%s sent\n");
465 	p(tcps_snddsackopt, "\t\t%lu D-SACK option%s sent\n");
466 	p2a(tcps_sndacks, tcps_delack,
467 		"\t\t%lu ack-only packet%s (%lu delayed)\n");
468 	p(tcps_sndurg, "\t\t%lu URG only packet%s\n");
469 	p(tcps_sndprobe, "\t\t%lu window probe packet%s\n");
470 	p(tcps_sndwinup, "\t\t%lu window update packet%s\n");
471 	p(tcps_sndctrl, "\t\t%lu control packet%s\n");
472 	p(tcps_rcvtotal, "\t%lu packet%s received\n");
473 	p2(tcps_rcvackpack, tcps_rcvackbyte, "\t\t%lu ack%s (for %lu byte%s)\n");
474 	p(tcps_rcvdupack, "\t\t%lu duplicate ack%s\n");
475 	p(tcps_rcvacktoomuch, "\t\t%lu ack%s for unsent data\n");
476 	p2(tcps_rcvpack, tcps_rcvbyte,
477 		"\t\t%lu packet%s (%lu byte%s) received in-sequence\n");
478 	p2(tcps_rcvduppack, tcps_rcvdupbyte,
479 		"\t\t%lu completely duplicate packet%s (%lu byte%s)\n");
480 	p2(tcps_pawsdrop, tcps_pawsaccept,
481 		"\t\t%lu old duplicate packet%s (%lu packet%s accepted)\n");
482 	p2(tcps_rcvpartduppack, tcps_rcvpartdupbyte,
483 		"\t\t%lu packet%s with some dup. data (%lu byte%s duped)\n");
484 	p2(tcps_rcvoopack, tcps_rcvoobyte,
485 		"\t\t%lu out-of-order packet%s (%lu byte%s)\n");
486 	p2(tcps_rcvpackafterwin, tcps_rcvbyteafterwin,
487 		"\t\t%lu packet%s (%lu byte%s) of data after window\n");
488 	p(tcps_rcvwinprobe, "\t\t%lu window probe%s\n");
489 	p(tcps_rcvwinupd, "\t\t%lu window update packet%s\n");
490 	p(tcps_rcvafterclose, "\t\t%lu packet%s received after close\n");
491 	p(tcps_rcvbadsum, "\t\t%lu discarded for bad checksum%s\n");
492 	p(tcps_rcvbadoff, "\t\t%lu discarded for bad header offset field%s\n");
493 	p1a(tcps_rcvshort, "\t\t%lu discarded because packet too short\n");
494 	p(tcps_rcvbadsackopt, "\t\t%lu bad SACK option%s\n");
495 	p1a(tcps_sackrenege, "\t\t%lu other side reneged\n");
496 	p(tcps_connattempt, "\t%lu connection request%s\n");
497 	p(tcps_accepts, "\t%lu connection accept%s\n");
498 	p(tcps_badsyn, "\t%lu bad connection attempt%s\n");
499 	p(tcps_listendrop, "\t%lu listen queue overflow%s\n");
500 	p(tcps_connects, "\t%lu connection%s established (including accepts)\n");
501 	p2(tcps_closed, tcps_drops,
502 		"\t%lu connection%s closed (including %lu drop%s)\n");
503 	p(tcps_cachedrtt, "\t\t%lu connection%s updated cached RTT on close\n");
504 	p(tcps_cachedrttvar,
505 	  "\t\t%lu connection%s updated cached RTT variance on close\n");
506 	p(tcps_cachedssthresh,
507 	  "\t\t%lu connection%s updated cached ssthresh on close\n");
508 	p(tcps_conndrops, "\t%lu embryonic connection%s dropped\n");
509 	p2(tcps_rttupdated, tcps_segstimed,
510 		"\t%lu segment%s updated rtt (of %lu attempt%s)\n");
511 	p(tcps_rexmttimeo, "\t%lu retransmit timeout%s\n");
512 	p(tcps_timeoutdrop, "\t\t%lu connection%s dropped by rexmit timeout\n");
513 	p(tcps_persisttimeo, "\t%lu persist timeout%s\n");
514 	p(tcps_persistdrop, "\t\t%lu connection%s dropped by persist timeout\n");
515 	p(tcps_keeptimeo, "\t%lu keepalive timeout%s\n");
516 	p(tcps_keepprobe, "\t\t%lu keepalive probe%s sent\n");
517 	p(tcps_keepdrops, "\t\t%lu connection%s dropped by keepalive\n");
518 	p(tcps_predack, "\t%lu correct ACK header prediction%s\n");
519 	p(tcps_preddat, "\t%lu correct data packet header prediction%s\n");
520 	p(tcps_sndidle, "\t%lu send idle%s\n");
521 
522 	p1a(tcps_sc_added, "\t%lu syncache entries added\n");
523 	p1a(tcps_sc_retransmitted, "\t\t%lu retransmitted\n");
524 	p1a(tcps_sc_dupsyn, "\t\t%lu dupsyn\n");
525 	p1a(tcps_sc_dropped, "\t\t%lu dropped\n");
526 	p1a(tcps_sc_completed, "\t\t%lu completed\n");
527 	p1a(tcps_sc_bucketoverflow, "\t\t%lu bucket overflow\n");
528 	p1a(tcps_sc_cacheoverflow, "\t\t%lu cache overflow\n");
529 	p1a(tcps_sc_reset, "\t\t%lu reset\n");
530 	p1a(tcps_sc_stale, "\t\t%lu stale\n");
531 	p1a(tcps_sc_aborted, "\t\t%lu aborted\n");
532 	p1a(tcps_sc_badack, "\t\t%lu badack\n");
533 	p1a(tcps_sc_unreach, "\t\t%lu unreach\n");
534 	p1a(tcps_sc_zonefail, "\t\t%lu zone failures\n");
535 	p1a(tcps_sc_sendcookie, "\t\t%lu cookies sent\n");
536 	p1a(tcps_sc_recvcookie, "\t\t%lu cookies received\n");
537 
538 	p(tcps_sacksbupdate, "\t%lu SACK scoreboard update%s\n");
539 	p(tcps_sacksboverflow, "\t\t%lu overflow%s\n");
540 	p(tcps_sacksbfailed, "\t\t%lu failure%s\n");
541 	p(tcps_sacksbreused, "\t\t%lu record%s reused\n");
542 	p(tcps_sacksbfast, "\t\t%lu record%s fast allocated\n");
543 
544 	free(stattmp);
545 #undef p
546 #undef p1a
547 #undef p2
548 #undef p2a
549 #undef p3
550 
551 	len = sizeof(state_count);
552 	if (sysctlbyname("net.inet.tcp.state_count", state_count, &len, NULL, 0) == 0) {
553 		int s;
554 
555 		for (s = TCPS_TERMINATING + 1; s < TCP_NSTATES; ++s) {
556 			printf("\t%lu connection%s in %s state\n", state_count[s],
557 			    state_count[s] == 1 ? "" : "s", tcpstates[s]);
558 		}
559 	}
560 }
561 
562 /*
563  * Dump UDP statistics structure.
564  */
565 void
566 udp_stats(u_long off __unused, const char *name, int af1 __unused)
567 {
568 	struct udpstat udpstat, *stattmp;
569 	struct udpstat zerostat[SMP_MAXCPU];
570 	size_t len = sizeof(struct udpstat) * SMP_MAXCPU;
571 	int cpucnt;
572 	u_long delivered;
573 
574 	if (zflag)
575 		memset(&zerostat, 0, len);
576 
577 	if ((stattmp = malloc(len)) == NULL) {
578 		return;
579 	} else {
580 		if (sysctlbyname("net.inet.udp.stats", stattmp, &len,
581 			zflag ? zerostat : NULL, zflag ? len : 0) < 0) {
582 			warn("sysctl: net.inet.udp.stats");
583 			free(stattmp);
584 			return;
585 		} else {
586 			if ((stattmp = realloc(stattmp, len)) == NULL) {
587 				warn("udp_stats");
588 				return;
589 			}
590 		}
591 	}
592 	cpucnt = len / sizeof(struct udpstat);
593 	udp_stats_agg(stattmp, &udpstat, cpucnt);
594 
595 #ifdef INET6
596 	if (udp_done != 0)
597 		return;
598 	else
599 		udp_done = 1;
600 #endif
601 
602 	printf("%s:\n", name);
603 #define	p(f, m) if (udpstat.f || sflag <= 1) \
604     printf(m, udpstat.f, plural(udpstat.f))
605 #define	p1a(f, m) if (udpstat.f || sflag <= 1) \
606     printf(m, udpstat.f)
607 	p(udps_ipackets, "\t%lu datagram%s received\n");
608 	p1a(udps_hdrops, "\t%lu with incomplete header\n");
609 	p1a(udps_badlen, "\t%lu with bad data length field\n");
610 	p1a(udps_badsum, "\t%lu with bad checksum\n");
611 	p1a(udps_nosum, "\t%lu with no checksum\n");
612 	p1a(udps_noport, "\t%lu dropped due to no socket\n");
613 	p(udps_noportbcast,
614 	    "\t%lu broadcast/multicast datagram%s dropped due to no socket\n");
615 	p1a(udps_fullsock, "\t%lu dropped due to full socket buffers\n");
616 	p1a(udpps_pcbhashmiss, "\t%lu not for hashed pcb\n");
617 	delivered = udpstat.udps_ipackets -
618 		    udpstat.udps_hdrops -
619 		    udpstat.udps_badlen -
620 		    udpstat.udps_badsum -
621 		    udpstat.udps_noport -
622 		    udpstat.udps_noportbcast -
623 		    udpstat.udps_fullsock;
624 	if (delivered || sflag <= 1)
625 		printf("\t%lu delivered\n", delivered);
626 	p(udps_opackets, "\t%lu datagram%s output\n");
627 #undef p
628 #undef p1a
629 }
630 
631 /*
632  * Dump CARP statistics structure.
633  */
634 void
635 carp_stats(u_long off __unused, const char *name, int af1 __unused)
636 {
637        struct carpstats carpstat, zerostat;
638        size_t len = sizeof(struct carpstats);
639 
640        if (zflag)
641                memset(&zerostat, 0, len);
642        if (sysctlbyname("net.inet.carp.stats", &carpstat, &len,
643            zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
644                warn("sysctl: net.inet.carp.stats");
645                return;
646        }
647 
648        printf("%s:\n", name);
649 
650 #define p(f, m) if (carpstat.f || sflag <= 1) \
651        printf(m, (uintmax_t)carpstat.f, plural((int)carpstat.f))
652 #define p2(f, m) if (carpstat.f || sflag <= 1) \
653        printf(m, (uintmax_t)carpstat.f)
654 
655        p(carps_ipackets, "\t%ju packet%s received (IPv4)\n");
656        p(carps_ipackets6, "\t%ju packet%s received (IPv6)\n");
657        p(carps_badttl, "\t\t%ju packet%s discarded for wrong TTL\n");
658        p(carps_hdrops, "\t\t%ju packet%s shorter than header\n");
659        p(carps_badsum, "\t\t%ju discarded for bad checksum%s\n");
660        p(carps_badver, "\t\t%ju discarded packet%s with a bad version\n");
661        p2(carps_badlen, "\t\t%ju discarded because packet too short\n");
662        p2(carps_badauth, "\t\t%ju discarded for bad authentication\n");
663        p2(carps_badvhid, "\t\t%ju discarded for bad vhid\n");
664        p2(carps_badaddrs, "\t\t%ju discarded because of a bad address list\n");
665        p(carps_opackets, "\t%ju packet%s sent (IPv4)\n");
666        p(carps_opackets6, "\t%ju packet%s sent (IPv6)\n");
667        p2(carps_onomem, "\t\t%ju send failed due to mbuf memory error\n");
668 #if notyet
669        p(carps_ostates, "\t\t%s state update%s sent\n");
670 #endif
671 #undef p
672 #undef p2
673 }
674 
675 /*
676  * Dump IP statistics structure.
677  */
678 void
679 ip_stats(u_long off __unused, const char *name, int af1 __unused)
680 {
681 	struct ip_stats ipstat, *stattmp;
682 	struct ip_stats zerostat[SMP_MAXCPU];
683 	size_t len = sizeof(struct ip_stats) * SMP_MAXCPU;
684 	int cpucnt;
685 
686 	if (zflag)
687 		memset(zerostat, 0, len);
688 	if ((stattmp = malloc(len)) == NULL) {
689 		return;
690 	} else {
691 		if (sysctlbyname("net.inet.ip.stats", stattmp, &len,
692 			zflag ? zerostat : NULL, zflag ? len : 0) < 0) {
693 				warn("sysctl: net.inet.ip.stats");
694 				free(stattmp);
695 				return;
696 		} else {
697 			if ((stattmp = realloc(stattmp, len)) == NULL) {
698 				warn("ip_stats");
699 				return;
700 			}
701 		}
702 	}
703 	cpucnt = len / sizeof(struct ip_stats);
704 	ip_stats_agg(stattmp, &ipstat, cpucnt);
705 
706 	printf("%s:\n", name);
707 
708 #define	p(f, m) if (ipstat.f || sflag <= 1) \
709     printf(m, ipstat.f, plural(ipstat.f))
710 #define	p1a(f, m) if (ipstat.f || sflag <= 1) \
711     printf(m, ipstat.f)
712 
713 	p(ips_total, "\t%lu total packet%s received\n");
714 	p(ips_badsum, "\t%lu bad header checksum%s\n");
715 	p1a(ips_toosmall, "\t%lu with size smaller than minimum\n");
716 	p1a(ips_tooshort, "\t%lu with data size < data length\n");
717 	p1a(ips_toolong, "\t%lu with ip length > max ip packet size\n");
718 	p1a(ips_badhlen, "\t%lu with header length < data size\n");
719 	p1a(ips_badlen, "\t%lu with data length < header length\n");
720 	p1a(ips_badoptions, "\t%lu with bad options\n");
721 	p1a(ips_badvers, "\t%lu with incorrect version number\n");
722 	p(ips_fragments, "\t%lu fragment%s received\n");
723 	p(ips_fragdropped, "\t%lu fragment%s dropped (dup or out of space)\n");
724 	p(ips_fragtimeout, "\t%lu fragment%s dropped after timeout\n");
725 	p(ips_reassembled, "\t%lu packet%s reassembled ok\n");
726 	p(ips_delivered, "\t%lu packet%s for this host\n");
727 	p(ips_noproto, "\t%lu packet%s for unknown/unsupported protocol\n");
728 	p(ips_forward, "\t%lu packet%s forwarded");
729 	p(ips_fastforward, " (%lu packet%s fast forwarded)");
730 	if (ipstat.ips_forward || sflag <= 1)
731 		putchar('\n');
732 	p(ips_cantforward, "\t%lu packet%s not forwardable\n");
733 	p(ips_notmember,
734 	  "\t%lu packet%s received for unknown multicast group\n");
735 	p(ips_redirectsent, "\t%lu redirect%s sent\n");
736 	p(ips_localout, "\t%lu packet%s sent from this host\n");
737 	p(ips_rawout, "\t%lu packet%s sent with fabricated ip header\n");
738 	p(ips_odropped,
739 	  "\t%lu output packet%s dropped due to no bufs, etc.\n");
740 	p(ips_noroute, "\t%lu output packet%s discarded due to no route\n");
741 	p(ips_fragmented, "\t%lu output datagram%s fragmented\n");
742 	p(ips_ofragments, "\t%lu fragment%s created\n");
743 	p(ips_cantfrag, "\t%lu datagram%s that can't be fragmented\n");
744 	p(ips_nogif, "\t%lu tunneling packet%s that can't find gif\n");
745 	p(ips_badaddr, "\t%lu datagram%s with bad address in header\n");
746 	free(stattmp);
747 #undef p
748 #undef p1a
749 }
750 
751 static	const char *icmpnames[] = {
752 	"echo reply",
753 	"#1",
754 	"#2",
755 	"destination unreachable",
756 	"source quench",
757 	"routing redirect",
758 	"#6",
759 	"#7",
760 	"echo",
761 	"router advertisement",
762 	"router solicitation",
763 	"time exceeded",
764 	"parameter problem",
765 	"time stamp",
766 	"time stamp reply",
767 	"information request",
768 	"information request reply",
769 	"address mask request",
770 	"address mask reply",
771 };
772 
773 /*
774  * Dump ICMP statistics.
775  */
776 void
777 icmp_stats(u_long off __unused, const char *name, int af1 __unused)
778 {
779 	struct icmpstat icmpstat, zerostat;
780 	int i, first;
781 	int mib[4];		/* CTL_NET + PF_INET + IPPROTO_ICMP + req */
782 	size_t len;
783 
784 	mib[0] = CTL_NET;
785 	mib[1] = PF_INET;
786 	mib[2] = IPPROTO_ICMP;
787 	mib[3] = ICMPCTL_STATS;
788 
789 	len = sizeof icmpstat;
790 	if (zflag)
791 		memset(&zerostat, 0, len);
792 	if (sysctl(mib, 4, &icmpstat, &len,
793 	    zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
794 		warn("sysctl: net.inet.icmp.stats");
795 		return;
796 	}
797 
798 	printf("%s:\n", name);
799 
800 #define	p(f, m) if (icmpstat.f || sflag <= 1) \
801     printf(m, icmpstat.f, plural(icmpstat.f))
802 #define	p1a(f, m) if (icmpstat.f || sflag <= 1) \
803     printf(m, icmpstat.f)
804 #define	p2(f, m) if (icmpstat.f || sflag <= 1) \
805     printf(m, icmpstat.f, plurales(icmpstat.f))
806 
807 	p(icps_error, "\t%lu call%s to icmp_error\n");
808 	p(icps_oldicmp,
809 	    "\t%lu error%s not generated 'cuz old message was icmp\n");
810 	for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
811 		if (icmpstat.icps_outhist[i] != 0) {
812 			if (first) {
813 				printf("\tOutput histogram:\n");
814 				first = 0;
815 			}
816 			printf("\t\t%s: %lu\n", icmpnames[i],
817 				icmpstat.icps_outhist[i]);
818 		}
819 	p(icps_badcode, "\t%lu message%s with bad code fields\n");
820 	p(icps_tooshort, "\t%lu message%s < minimum length\n");
821 	p(icps_checksum, "\t%lu bad checksum%s\n");
822 	p(icps_badlen, "\t%lu message%s with bad length\n");
823 	p1a(icps_bmcastecho, "\t%lu multicast echo requests ignored\n");
824 	p1a(icps_bmcasttstamp, "\t%lu multicast timestamp requests ignored\n");
825 	for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
826 		if (icmpstat.icps_inhist[i] != 0) {
827 			if (first) {
828 				printf("\tInput histogram:\n");
829 				first = 0;
830 			}
831 			printf("\t\t%s: %lu\n", icmpnames[i],
832 				icmpstat.icps_inhist[i]);
833 		}
834 	p(icps_reflect, "\t%lu message response%s generated\n");
835 	p2(icps_badaddr, "\t%lu invalid return address%s\n");
836 	p(icps_noroute, "\t%lu no return route%s\n");
837 #undef p
838 #undef p1a
839 #undef p2
840 	mib[3] = ICMPCTL_MASKREPL;
841 	len = sizeof i;
842 	if (sysctl(mib, 4, &i, &len, NULL, 0) < 0)
843 		return;
844 	printf("\tICMP address mask responses are %sabled\n",
845 	       i ? "en" : "dis");
846 }
847 
848 /*
849  * Dump IGMP statistics structure.
850  */
851 void
852 igmp_stats(u_long off __unused, const char *name, int af1 __unused)
853 {
854 	struct igmpstat igmpstat, zerostat;
855 	size_t len = sizeof igmpstat;
856 
857 	if (zflag)
858 		memset(&zerostat, 0, len);
859 	if (sysctlbyname("net.inet.igmp.stats", &igmpstat, &len,
860 	    zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
861 		warn("sysctl: net.inet.igmp.stats");
862 		return;
863 	}
864 
865 	printf("%s:\n", name);
866 
867 #define	p(f, m) if (igmpstat.f || sflag <= 1) \
868     printf(m, igmpstat.f, plural(igmpstat.f))
869 #define	py(f, m) if (igmpstat.f || sflag <= 1) \
870     printf(m, igmpstat.f, igmpstat.f != 1 ? "ies" : "y")
871 	p(igps_rcv_total, "\t%u message%s received\n");
872         p(igps_rcv_tooshort, "\t%u message%s received with too few bytes\n");
873         p(igps_rcv_badsum, "\t%u message%s received with bad checksum\n");
874         py(igps_rcv_queries, "\t%u membership quer%s received\n");
875         py(igps_rcv_badqueries, "\t%u membership quer%s received with invalid field(s)\n");
876         p(igps_rcv_reports, "\t%u membership report%s received\n");
877         p(igps_rcv_badreports, "\t%u membership report%s received with invalid field(s)\n");
878         p(igps_rcv_ourreports, "\t%u membership report%s received for groups to which we belong\n");
879         p(igps_snd_reports, "\t%u membership report%s sent\n");
880 #undef p
881 #undef py
882 }
883 
884 /*
885  * Dump PIM statistics structure.
886  */
887 void
888 pim_stats(u_long off __unused, const char *name, int af1 __unused)
889 {
890 	struct pimstat pimstat, zerostat;
891 	size_t len = sizeof pimstat;
892 
893 	if (zflag)
894 		memset(&zerostat, 0, len);
895 	if (sysctlbyname("net.inet.pim.stats", &pimstat, &len,
896 	    zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
897 		if (errno != ENOENT)
898 			warn("sysctl: net.inet.pim.stats");
899 		return;
900 	}
901 
902 	printf("%s:\n", name);
903 
904 #define	p(f, m) if (pimstat.f || sflag <= 1) \
905     printf(m, (uintmax_t)pimstat.f, plural(pimstat.f))
906 #define	py(f, m) if (pimstat.f || sflag <= 1) \
907     printf(m, (uintmax_t)pimstat.f, pimstat.f != 1 ? "ies" : "y")
908 	p(pims_rcv_total_msgs, "\t%ju message%s received\n");
909 	p(pims_rcv_total_bytes, "\t%ju byte%s received\n");
910 	p(pims_rcv_tooshort, "\t%ju message%s received with too few bytes\n");
911         p(pims_rcv_badsum, "\t%ju message%s received with bad checksum\n");
912 	p(pims_rcv_badversion, "\t%ju message%s received with bad version\n");
913 	p(pims_rcv_registers_msgs, "\t%ju data register message%s received\n");
914 	p(pims_rcv_registers_bytes, "\t%ju data register byte%s received\n");
915 	p(pims_rcv_registers_wrongiif, "\t%ju data register message%s received on wrong iif\n");
916 	p(pims_rcv_badregisters, "\t%ju bad register%s received\n");
917 	p(pims_snd_registers_msgs, "\t%ju data register message%s sent\n");
918 	p(pims_snd_registers_bytes, "\t%ju data register byte%s sent\n");
919 #undef p
920 #undef py
921 }
922 
923 /*
924  * Pretty print an Internet address (net address + port).
925  */
926 void
927 inetprint(struct in_addr *in, int port, const char *proto, int num_port)
928 {
929 	struct servent *sp = NULL;
930 	char line[80], *cp;
931 	int width;
932 
933 	if (Wflag)
934 	    sprintf(line, "%s.", inetname(in));
935 	else
936 	    sprintf(line, "%.*s.", (Aflag && !num_port) ? 12 : 16, inetname(in));
937 	cp = strchr(line, '\0');
938 	if (!num_port && port)
939 		sp = getservbyport((int)port, proto);
940 	if (sp || port == 0)
941 		sprintf(cp, "%.15s ", sp ? sp->s_name : "*");
942 	else
943 		sprintf(cp, "%d ", ntohs((u_short)port));
944 	width = (Aflag && !Wflag) ? 17 : 21;
945 	if (Wflag)
946 	    printf("%-*s ", width, line);
947 	else
948 	    printf("%-*.*s ", width, width, line);
949 }
950 
951 /*
952  * Construct an Internet address representation.
953  * If numeric_addr has been supplied, give
954  * numeric value, otherwise try for symbolic name.
955  */
956 char *
957 inetname(struct in_addr *inp)
958 {
959 	char *cp;
960 	static char line[MAXHOSTNAMELEN];
961 	struct hostent *hp;
962 	struct netent *np;
963 
964 	cp = NULL;
965 	if (!numeric_addr && inp->s_addr != INADDR_ANY) {
966 		int net = inet_netof(*inp);
967 		int lna = inet_lnaof(*inp);
968 
969 		if (lna == INADDR_ANY) {
970 			np = getnetbyaddr(net, AF_INET);
971 			if (np)
972 				cp = np->n_name;
973 		}
974 		if (cp == NULL) {
975 			hp = gethostbyaddr(inp, sizeof (*inp), AF_INET);
976 			if (hp) {
977 				cp = hp->h_name;
978 				trimdomain(cp, strlen(cp));
979 			}
980 		}
981 	}
982 	if (inp->s_addr == INADDR_ANY)
983 		strcpy(line, "*");
984 	else if (cp) {
985 		strncpy(line, cp, sizeof(line) - 1);
986 		line[sizeof(line) - 1] = '\0';
987 	} else {
988 		inp->s_addr = ntohl(inp->s_addr);
989 #define C(x)	((u_int)((x) & 0xff))
990 		sprintf(line, "%u.%u.%u.%u", C(inp->s_addr >> 24),
991 		    C(inp->s_addr >> 16), C(inp->s_addr >> 8), C(inp->s_addr));
992 	}
993 	return (line);
994 }
995