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