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