xref: /dragonfly/usr.bin/netstat/inet.c (revision 0bb9290e)
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  * $DragonFly: src/usr.bin/netstat/inet.c,v 1.19 2005/08/04 17:31:23 drhodus Exp $
36  */
37 
38 #include <sys/param.h>
39 #include <sys/queue.h>
40 #include <sys/socket.h>
41 #include <sys/socketvar.h>
42 #include <sys/sysctl.h>
43 #include <sys/protosw.h>
44 #include <sys/time.h>
45 
46 #include <net/route.h>
47 #include <netinet/in.h>
48 #include <netinet/in_systm.h>
49 #include <netinet/ip.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, char *name, int af)
100 {
101 	int istcp;
102 	int i;
103 	void *buf;
104 	const char *mibvar;
105 	size_t len;
106 
107 	istcp = 0;
108 	switch (proto) {
109 	case IPPROTO_TCP:
110 #ifdef INET6
111 		if (tcp_done != 0)
112 			return;
113 		else
114 			tcp_done = 1;
115 #endif
116 		istcp = 1;
117 		mibvar = "net.inet.tcp.pcblist";
118 		break;
119 	case IPPROTO_UDP:
120 #ifdef INET6
121 		if (udp_done != 0)
122 			return;
123 		else
124 			udp_done = 1;
125 #endif
126 		mibvar = "net.inet.udp.pcblist";
127 		break;
128 	case IPPROTO_DIVERT:
129 		mibvar = "net.inet.divert.pcblist";
130 		break;
131 	default:
132 		mibvar = "net.inet.raw.pcblist";
133 		break;
134 	}
135 	len = 0;
136 	if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) {
137 		if (errno != ENOENT)
138 			warn("sysctl: %s", mibvar);
139 		return;
140 	}
141 	if (len == 0)
142 		return;
143 	if ((buf = malloc(len)) == 0) {
144 		warn("malloc %lu bytes", (u_long)len);
145 		return;
146 	}
147 	if (sysctlbyname(mibvar, buf, &len, 0, 0) < 0) {
148 		warn("sysctl: %s", mibvar);
149 		free(buf);
150 		return;
151 	}
152 
153 	if (istcp) {
154 		struct xtcpcb *tcp = buf;
155 		len /= sizeof(*tcp);
156 		for (i = 0; i < len; i++) {
157 			if (tcp[i].xt_len != sizeof(*tcp))
158 				break;
159 			outputpcb(proto, name, &tcp[i].xt_inp,
160 				  &tcp[i].xt_socket, &tcp[i].xt_tp);
161 		}
162 	} else {
163 		struct xinpcb *in = buf;
164 		len /= sizeof(*in);
165 		for (i = 0; i < len; i++) {
166 			if (in[i].xi_len != sizeof(*in))
167 				break;
168 			outputpcb(proto, name, &in[i].xi_inp,
169 				  &in[i].xi_socket, NULL);
170 		}
171 	}
172 	free(buf);
173 }
174 
175 static void
176 outputpcb(int proto, const char *name, struct inpcb *inp, struct xsocket *so, struct tcpcb *tp)
177 {
178 	const char *vchar;
179 	static struct clockinfo clockinfo;
180 
181 	if (clockinfo.hz == 0) {
182 		int size = sizeof(clockinfo);
183 		sysctlbyname("kern.clockrate", &clockinfo, &size, NULL, 0);
184 		if (clockinfo.hz == 0)
185 			clockinfo.hz = 100;
186 	}
187 
188 	/* Ignore sockets for protocols other than the desired one. */
189 	if (so->xso_protocol != (int)proto)
190 		return;
191 
192 	if ((af == AF_INET && (inp->inp_vflag & INP_IPV4) == 0)
193 #ifdef INET6
194 	    || (af == AF_INET6 && (inp->inp_vflag & INP_IPV6) == 0)
195 #endif /* INET6 */
196 	    || (af == AF_UNSPEC && ((inp->inp_vflag & INP_IPV4) == 0
197 #ifdef INET6
198 		&& (inp->inp_vflag & INP_IPV6) == 0
199 #endif /* INET6 */
200 		))
201 	    ) {
202 		return;
203 	}
204 	if (!aflag && (
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, char *name, int af __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 	p2a(tcps_sndfastrexmit, tcps_sndearlyrexmit,
450 		"\t\t%lu Fast Retransmit%s (%lu early)\n");
451 	p(tcps_sndlimited, "\t\t%lu packet%s sent by Limited Transmit\n");
452 	p(tcps_sndrtobad, "\t\t%lu spurious RTO retransmit%s\n");
453 	p2a(tcps_sndfastrexmitbad, tcps_sndearlyrexmitbad,
454 		"\t\t%lu spurious Fast Retransmit%s (%lu early)\n");
455 	p(tcps_eifeldetected, "\t\t%lu Eifel-detected spurious retransmit%s\n");
456 	p(tcps_rttdetected, "\t\t%lu RTT-detected spurious retransmit%s\n");
457 	p(tcps_mturesent, "\t\t%lu resend%s initiated by MTU discovery\n");
458 	p2a(tcps_sndacks, tcps_delack,
459 		"\t\t%lu ack-only packet%s (%lu delayed)\n");
460 	p(tcps_sndurg, "\t\t%lu URG only packet%s\n");
461 	p(tcps_sndprobe, "\t\t%lu window probe packet%s\n");
462 	p(tcps_sndwinup, "\t\t%lu window update packet%s\n");
463 	p(tcps_sndctrl, "\t\t%lu control packet%s\n");
464 	p(tcps_rcvtotal, "\t%lu packet%s received\n");
465 	p2(tcps_rcvackpack, tcps_rcvackbyte, "\t\t%lu ack%s (for %lu byte%s)\n");
466 	p(tcps_rcvdupack, "\t\t%lu duplicate ack%s\n");
467 	p(tcps_rcvacktoomuch, "\t\t%lu ack%s for unsent data\n");
468 	p2(tcps_rcvpack, tcps_rcvbyte,
469 		"\t\t%lu packet%s (%lu byte%s) received in-sequence\n");
470 	p2(tcps_rcvduppack, tcps_rcvdupbyte,
471 		"\t\t%lu completely duplicate packet%s (%lu byte%s)\n");
472 	p(tcps_pawsdrop, "\t\t%lu old duplicate packet%s\n");
473 	p2(tcps_rcvpartduppack, tcps_rcvpartdupbyte,
474 		"\t\t%lu packet%s with some dup. data (%lu byte%s duped)\n");
475 	p2(tcps_rcvoopack, tcps_rcvoobyte,
476 		"\t\t%lu out-of-order packet%s (%lu byte%s)\n");
477 	p2(tcps_rcvpackafterwin, tcps_rcvbyteafterwin,
478 		"\t\t%lu packet%s (%lu byte%s) of data after window\n");
479 	p(tcps_rcvwinprobe, "\t\t%lu window probe%s\n");
480 	p(tcps_rcvwinupd, "\t\t%lu window update packet%s\n");
481 	p(tcps_rcvafterclose, "\t\t%lu packet%s received after close\n");
482 	p(tcps_rcvbadsum, "\t\t%lu discarded for bad checksum%s\n");
483 	p(tcps_rcvbadoff, "\t\t%lu discarded for bad header offset field%s\n");
484 	p1a(tcps_rcvshort, "\t\t%lu discarded because packet too short\n");
485 	p(tcps_connattempt, "\t%lu connection request%s\n");
486 	p(tcps_accepts, "\t%lu connection accept%s\n");
487 	p(tcps_badsyn, "\t%lu bad connection attempt%s\n");
488 	p(tcps_listendrop, "\t%lu listen queue overflow%s\n");
489 	p(tcps_connects, "\t%lu connection%s established (including accepts)\n");
490 	p2(tcps_closed, tcps_drops,
491 		"\t%lu connection%s closed (including %lu drop%s)\n");
492 	p(tcps_cachedrtt, "\t\t%lu connection%s updated cached RTT on close\n");
493 	p(tcps_cachedrttvar,
494 	  "\t\t%lu connection%s updated cached RTT variance on close\n");
495 	p(tcps_cachedssthresh,
496 	  "\t\t%lu connection%s updated cached ssthresh on close\n");
497 	p(tcps_conndrops, "\t%lu embryonic connection%s dropped\n");
498 	p2(tcps_rttupdated, tcps_segstimed,
499 		"\t%lu segment%s updated rtt (of %lu attempt%s)\n");
500 	p(tcps_rexmttimeo, "\t%lu retransmit timeout%s\n");
501 	p(tcps_timeoutdrop, "\t\t%lu connection%s dropped by rexmit timeout\n");
502 	p(tcps_persisttimeo, "\t%lu persist timeout%s\n");
503 	p(tcps_persistdrop, "\t\t%lu connection%s dropped by persist timeout\n");
504 	p(tcps_keeptimeo, "\t%lu keepalive timeout%s\n");
505 	p(tcps_keepprobe, "\t\t%lu keepalive probe%s sent\n");
506 	p(tcps_keepdrops, "\t\t%lu connection%s dropped by keepalive\n");
507 	p(tcps_predack, "\t%lu correct ACK header prediction%s\n");
508 	p(tcps_preddat, "\t%lu correct data packet header prediction%s\n");
509 
510 	p1a(tcps_sc_added, "\t%lu syncache entries added\n");
511 	p1a(tcps_sc_retransmitted, "\t\t%lu retransmitted\n");
512 	p1a(tcps_sc_dupsyn, "\t\t%lu dupsyn\n");
513 	p1a(tcps_sc_dropped, "\t\t%lu dropped\n");
514 	p1a(tcps_sc_completed, "\t\t%lu completed\n");
515 	p1a(tcps_sc_bucketoverflow, "\t\t%lu bucket overflow\n");
516 	p1a(tcps_sc_cacheoverflow, "\t\t%lu cache overflow\n");
517 	p1a(tcps_sc_reset, "\t\t%lu reset\n");
518 	p1a(tcps_sc_stale, "\t\t%lu stale\n");
519 	p1a(tcps_sc_aborted, "\t\t%lu aborted\n");
520 	p1a(tcps_sc_badack, "\t\t%lu badack\n");
521 	p1a(tcps_sc_unreach, "\t\t%lu unreach\n");
522 	p1a(tcps_sc_zonefail, "\t\t%lu zone failures\n");
523 	p1a(tcps_sc_sendcookie, "\t%lu cookies sent\n");
524 	p1a(tcps_sc_recvcookie, "\t%lu cookies received\n");
525 	free(stattmp);
526 #undef p
527 #undef p1a
528 #undef p2
529 #undef p2a
530 #undef p3
531 }
532 
533 /*
534  * Dump UDP statistics structure.
535  */
536 void
537 udp_stats(u_long off __unused, char *name, int af __unused)
538 {
539 	struct udpstat udpstat, zerostat;
540 	size_t len = sizeof udpstat;
541 	u_long delivered;
542 
543 	if (zflag)
544 		memset(&zerostat, 0, len);
545 	if (sysctlbyname("net.inet.udp.stats", &udpstat, &len,
546 	    zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
547 		warn("sysctl: net.inet.udp.stats");
548 		return;
549 	}
550 
551 #ifdef INET6
552 	if (udp_done != 0)
553 		return;
554 	else
555 		udp_done = 1;
556 #endif
557 
558 	printf("%s:\n", name);
559 #define	p(f, m) if (udpstat.f || sflag <= 1) \
560     printf(m, udpstat.f, plural(udpstat.f))
561 #define	p1a(f, m) if (udpstat.f || sflag <= 1) \
562     printf(m, udpstat.f)
563 	p(udps_ipackets, "\t%lu datagram%s received\n");
564 	p1a(udps_hdrops, "\t%lu with incomplete header\n");
565 	p1a(udps_badlen, "\t%lu with bad data length field\n");
566 	p1a(udps_badsum, "\t%lu with bad checksum\n");
567 	p1a(udps_nosum, "\t%lu with no checksum\n");
568 	p1a(udps_noport, "\t%lu dropped due to no socket\n");
569 	p(udps_noportbcast,
570 	    "\t%lu broadcast/multicast datagram%s dropped due to no socket\n");
571 	p1a(udps_fullsock, "\t%lu dropped due to full socket buffers\n");
572 	p1a(udpps_pcbhashmiss, "\t%lu not for hashed pcb\n");
573 	delivered = udpstat.udps_ipackets -
574 		    udpstat.udps_hdrops -
575 		    udpstat.udps_badlen -
576 		    udpstat.udps_badsum -
577 		    udpstat.udps_noport -
578 		    udpstat.udps_noportbcast -
579 		    udpstat.udps_fullsock;
580 	if (delivered || sflag <= 1)
581 		printf("\t%lu delivered\n", delivered);
582 	p(udps_opackets, "\t%lu datagram%s output\n");
583 #undef p
584 #undef p1a
585 }
586 
587 /*
588  * Dump IP statistics structure.
589  */
590 void
591 ip_stats(u_long off __unused, char *name, int af __unused)
592 {
593 	struct ip_stats ipstat, *stattmp;
594 	struct ip_stats zerostat[SMP_MAXCPU];
595 	size_t len = sizeof(struct ip_stats) * SMP_MAXCPU;
596 	int cpucnt;
597 
598 	if (zflag)
599 		memset(zerostat, 0, len);
600 	if ((stattmp = malloc(len)) == NULL) {
601 		return;
602 	} else {
603 		if (sysctlbyname("net.inet.ip.stats", stattmp, &len,
604 			zflag ? zerostat : NULL, zflag ? len : 0) < 0) {
605 				warn("sysctl: net.inet.ip.stats");
606 				free(stattmp);
607 				return;
608 		} else {
609 			if ((stattmp = realloc(stattmp, len)) == NULL) {
610 				warn("ip_stats");
611 				return;
612 			}
613 		}
614 	}
615 	cpucnt = len / sizeof(struct ip_stats);
616 	ip_stats_agg(stattmp, &ipstat, cpucnt);
617 
618 	printf("%s:\n", name);
619 
620 #define	p(f, m) if (ipstat.f || sflag <= 1) \
621     printf(m, ipstat.f, plural(ipstat.f))
622 #define	p1a(f, m) if (ipstat.f || sflag <= 1) \
623     printf(m, ipstat.f)
624 
625 	p(ips_total, "\t%lu total packet%s received\n");
626 	p(ips_badsum, "\t%lu bad header checksum%s\n");
627 	p1a(ips_toosmall, "\t%lu with size smaller than minimum\n");
628 	p1a(ips_tooshort, "\t%lu with data size < data length\n");
629 	p1a(ips_toolong, "\t%lu with ip length > max ip packet size\n");
630 	p1a(ips_badhlen, "\t%lu with header length < data size\n");
631 	p1a(ips_badlen, "\t%lu with data length < header length\n");
632 	p1a(ips_badoptions, "\t%lu with bad options\n");
633 	p1a(ips_badvers, "\t%lu with incorrect version number\n");
634 	p(ips_fragments, "\t%lu fragment%s received\n");
635 	p(ips_fragdropped, "\t%lu fragment%s dropped (dup or out of space)\n");
636 	p(ips_fragtimeout, "\t%lu fragment%s dropped after timeout\n");
637 	p(ips_reassembled, "\t%lu packet%s reassembled ok\n");
638 	p(ips_delivered, "\t%lu packet%s for this host\n");
639 	p(ips_noproto, "\t%lu packet%s for unknown/unsupported protocol\n");
640 	p(ips_forward, "\t%lu packet%s forwarded");
641 	p(ips_fastforward, " (%lu packet%s fast forwarded)");
642 	if (ipstat.ips_forward || sflag <= 1)
643 		putchar('\n');
644 	p(ips_cantforward, "\t%lu packet%s not forwardable\n");
645 	p(ips_notmember,
646 	  "\t%lu packet%s received for unknown multicast group\n");
647 	p(ips_redirectsent, "\t%lu redirect%s sent\n");
648 	p(ips_localout, "\t%lu packet%s sent from this host\n");
649 	p(ips_rawout, "\t%lu packet%s sent with fabricated ip header\n");
650 	p(ips_odropped,
651 	  "\t%lu output packet%s dropped due to no bufs, etc.\n");
652 	p(ips_noroute, "\t%lu output packet%s discarded due to no route\n");
653 	p(ips_fragmented, "\t%lu output datagram%s fragmented\n");
654 	p(ips_ofragments, "\t%lu fragment%s created\n");
655 	p(ips_cantfrag, "\t%lu datagram%s that can't be fragmented\n");
656 	p(ips_nogif, "\t%lu tunneling packet%s that can't find gif\n");
657 	p(ips_badaddr, "\t%lu datagram%s with bad address in header\n");
658 	free(stattmp);
659 #undef p
660 #undef p1a
661 }
662 
663 static	char *icmpnames[] = {
664 	"echo reply",
665 	"#1",
666 	"#2",
667 	"destination unreachable",
668 	"source quench",
669 	"routing redirect",
670 	"#6",
671 	"#7",
672 	"echo",
673 	"router advertisement",
674 	"router solicitation",
675 	"time exceeded",
676 	"parameter problem",
677 	"time stamp",
678 	"time stamp reply",
679 	"information request",
680 	"information request reply",
681 	"address mask request",
682 	"address mask reply",
683 };
684 
685 /*
686  * Dump ICMP statistics.
687  */
688 void
689 icmp_stats(u_long off __unused, char *name, int af __unused)
690 {
691 	struct icmpstat icmpstat, zerostat;
692 	int i, first;
693 	int mib[4];		/* CTL_NET + PF_INET + IPPROTO_ICMP + req */
694 	size_t len;
695 
696 	mib[0] = CTL_NET;
697 	mib[1] = PF_INET;
698 	mib[2] = IPPROTO_ICMP;
699 	mib[3] = ICMPCTL_STATS;
700 
701 	len = sizeof icmpstat;
702 	if (zflag)
703 		memset(&zerostat, 0, len);
704 	if (sysctl(mib, 4, &icmpstat, &len,
705 	    zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
706 		warn("sysctl: net.inet.icmp.stats");
707 		return;
708 	}
709 
710 	printf("%s:\n", name);
711 
712 #define	p(f, m) if (icmpstat.f || sflag <= 1) \
713     printf(m, icmpstat.f, plural(icmpstat.f))
714 #define	p1a(f, m) if (icmpstat.f || sflag <= 1) \
715     printf(m, icmpstat.f)
716 #define	p2(f, m) if (icmpstat.f || sflag <= 1) \
717     printf(m, icmpstat.f, plurales(icmpstat.f))
718 
719 	p(icps_error, "\t%lu call%s to icmp_error\n");
720 	p(icps_oldicmp,
721 	    "\t%lu error%s not generated 'cuz old message was icmp\n");
722 	for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
723 		if (icmpstat.icps_outhist[i] != 0) {
724 			if (first) {
725 				printf("\tOutput histogram:\n");
726 				first = 0;
727 			}
728 			printf("\t\t%s: %lu\n", icmpnames[i],
729 				icmpstat.icps_outhist[i]);
730 		}
731 	p(icps_badcode, "\t%lu message%s with bad code fields\n");
732 	p(icps_tooshort, "\t%lu message%s < minimum length\n");
733 	p(icps_checksum, "\t%lu bad checksum%s\n");
734 	p(icps_badlen, "\t%lu message%s with bad length\n");
735 	p1a(icps_bmcastecho, "\t%lu multicast echo requests ignored\n");
736 	p1a(icps_bmcasttstamp, "\t%lu multicast timestamp requests ignored\n");
737 	for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
738 		if (icmpstat.icps_inhist[i] != 0) {
739 			if (first) {
740 				printf("\tInput histogram:\n");
741 				first = 0;
742 			}
743 			printf("\t\t%s: %lu\n", icmpnames[i],
744 				icmpstat.icps_inhist[i]);
745 		}
746 	p(icps_reflect, "\t%lu message response%s generated\n");
747 	p2(icps_badaddr, "\t%lu invalid return address%s\n");
748 	p(icps_noroute, "\t%lu no return route%s\n");
749 #undef p
750 #undef p1a
751 #undef p2
752 	mib[3] = ICMPCTL_MASKREPL;
753 	len = sizeof i;
754 	if (sysctl(mib, 4, &i, &len, (void *)0, 0) < 0)
755 		return;
756 	printf("\tICMP address mask responses are %sabled\n",
757 	       i ? "en" : "dis");
758 }
759 
760 /*
761  * Dump IGMP statistics structure.
762  */
763 void
764 igmp_stats(u_long off __unused, char *name, int af __unused)
765 {
766 	struct igmpstat igmpstat, zerostat;
767 	size_t len = sizeof igmpstat;
768 
769 	if (zflag)
770 		memset(&zerostat, 0, len);
771 	if (sysctlbyname("net.inet.igmp.stats", &igmpstat, &len,
772 	    zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
773 		warn("sysctl: net.inet.igmp.stats");
774 		return;
775 	}
776 
777 	printf("%s:\n", name);
778 
779 #define	p(f, m) if (igmpstat.f || sflag <= 1) \
780     printf(m, igmpstat.f, plural(igmpstat.f))
781 #define	py(f, m) if (igmpstat.f || sflag <= 1) \
782     printf(m, igmpstat.f, igmpstat.f != 1 ? "ies" : "y")
783 	p(igps_rcv_total, "\t%u message%s received\n");
784         p(igps_rcv_tooshort, "\t%u message%s received with too few bytes\n");
785         p(igps_rcv_badsum, "\t%u message%s received with bad checksum\n");
786         py(igps_rcv_queries, "\t%u membership quer%s received\n");
787         py(igps_rcv_badqueries, "\t%u membership quer%s received with invalid field(s)\n");
788         p(igps_rcv_reports, "\t%u membership report%s received\n");
789         p(igps_rcv_badreports, "\t%u membership report%s received with invalid field(s)\n");
790         p(igps_rcv_ourreports, "\t%u membership report%s received for groups to which we belong\n");
791         p(igps_snd_reports, "\t%u membership report%s sent\n");
792 #undef p
793 #undef py
794 }
795 
796 /*
797  * Dump PIM statistics structure.
798  */
799 void
800 pim_stats(u_long off __unused, char *name, int af1 __unused)
801 {
802 	struct pimstat pimstat, zerostat;
803 	size_t len = sizeof pimstat;
804 
805 	if (zflag)
806 		memset(&zerostat, 0, len);
807 	if (sysctlbyname("net.inet.pim.stats", &pimstat, &len,
808 	    zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
809 		if (errno != ENOENT)
810 			warn("sysctl: net.inet.pim.stats");
811 		return;
812 	}
813 
814 	printf("%s:\n", name);
815 
816 #define	p(f, m) if (pimstat.f || sflag <= 1) \
817     printf(m, pimstat.f, plural(pimstat.f))
818 #define	py(f, m) if (pimstat.f || sflag <= 1) \
819     printf(m, pimstat.f, pimstat.f != 1 ? "ies" : "y")
820 	p(pims_rcv_total_msgs, "\t%llu message%s received\n");
821 	p(pims_rcv_total_bytes, "\t%llu byte%s received\n");
822 	p(pims_rcv_tooshort, "\t%llu message%s received with too few bytes\n");
823         p(pims_rcv_badsum, "\t%llu message%s received with bad checksum\n");
824 	p(pims_rcv_badversion, "\t%llu message%s received with bad version\n");
825 	p(pims_rcv_registers_msgs, "\t%llu data register message%s received\n");
826 	p(pims_rcv_registers_bytes, "\t%llu data register byte%s received\n");
827 	p(pims_rcv_registers_wrongiif, "\t%llu data register message%s received on wrong iif\n");
828 	p(pims_rcv_badregisters, "\t%llu bad register%s received\n");
829 	p(pims_snd_registers_msgs, "\t%llu data register message%s sent\n");
830 	p(pims_snd_registers_bytes, "\t%llu data register byte%s sent\n");
831 #undef p
832 #undef py
833 }
834 
835 /*
836  * Pretty print an Internet address (net address + port).
837  */
838 void
839 inetprint(struct in_addr *in, int port, const char *proto, int numeric_port)
840 {
841 	struct servent *sp = 0;
842 	char line[80], *cp;
843 	int width;
844 
845 	if (Wflag)
846 	    sprintf(line, "%s.", inetname(in));
847 	else
848 	    sprintf(line, "%.*s.", (Aflag && !numeric_port) ? 12 : 16, inetname(in));
849 	cp = strchr(line, '\0');
850 	if (!numeric_port && port)
851 		sp = getservbyport((int)port, proto);
852 	if (sp || port == 0)
853 		sprintf(cp, "%.15s ", sp ? sp->s_name : "*");
854 	else
855 		sprintf(cp, "%d ", ntohs((u_short)port));
856 	width = (Aflag && !Wflag) ? 17 : 21;
857 	if (Wflag)
858 	    printf("%-*s ", width, line);
859 	else
860 	    printf("%-*.*s ", width, width, line);
861 }
862 
863 /*
864  * Construct an Internet address representation.
865  * If numeric_addr has been supplied, give
866  * numeric value, otherwise try for symbolic name.
867  */
868 char *
869 inetname(struct in_addr *inp)
870 {
871 	char *cp;
872 	static char line[MAXHOSTNAMELEN];
873 	struct hostent *hp;
874 	struct netent *np;
875 
876 	cp = 0;
877 	if (!numeric_addr && inp->s_addr != INADDR_ANY) {
878 		int net = inet_netof(*inp);
879 		int lna = inet_lnaof(*inp);
880 
881 		if (lna == INADDR_ANY) {
882 			np = getnetbyaddr(net, AF_INET);
883 			if (np)
884 				cp = np->n_name;
885 		}
886 		if (cp == 0) {
887 			hp = gethostbyaddr((char *)inp, sizeof (*inp), AF_INET);
888 			if (hp) {
889 				cp = hp->h_name;
890 				trimdomain(cp, strlen(cp));
891 			}
892 		}
893 	}
894 	if (inp->s_addr == INADDR_ANY)
895 		strcpy(line, "*");
896 	else if (cp) {
897 		strncpy(line, cp, sizeof(line) - 1);
898 		line[sizeof(line) - 1] = '\0';
899 	} else {
900 		inp->s_addr = ntohl(inp->s_addr);
901 #define C(x)	((u_int)((x) & 0xff))
902 		sprintf(line, "%u.%u.%u.%u", C(inp->s_addr >> 24),
903 		    C(inp->s_addr >> 16), C(inp->s_addr >> 8), C(inp->s_addr));
904 	}
905 	return (line);
906 }
907