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