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