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