xref: /freebsd/usr.bin/netstat/inet.c (revision 2357939bc239bd5334a169b62313806178dd8f30)
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_badrst, "\t%lu ignored RSTs in the window%s\n");
419 	p(tcps_connects, "\t%lu connection%s established (including accepts)\n");
420 	p2(tcps_closed, tcps_drops,
421 		"\t%lu connection%s closed (including %lu drop%s)\n");
422 	p(tcps_cachedrtt, "\t\t%lu connection%s updated cached RTT on close\n");
423 	p(tcps_cachedrttvar,
424 	  "\t\t%lu connection%s updated cached RTT variance on close\n");
425 	p(tcps_cachedssthresh,
426 	  "\t\t%lu connection%s updated cached ssthresh on close\n");
427 	p(tcps_conndrops, "\t%lu embryonic connection%s dropped\n");
428 	p2(tcps_rttupdated, tcps_segstimed,
429 		"\t%lu segment%s updated rtt (of %lu attempt%s)\n");
430 	p(tcps_rexmttimeo, "\t%lu retransmit timeout%s\n");
431 	p(tcps_timeoutdrop, "\t\t%lu connection%s dropped by rexmit timeout\n");
432 	p(tcps_persisttimeo, "\t%lu persist timeout%s\n");
433 	p(tcps_persistdrop, "\t\t%lu connection%s dropped by persist timeout\n");
434 	p(tcps_keeptimeo, "\t%lu keepalive timeout%s\n");
435 	p(tcps_keepprobe, "\t\t%lu keepalive probe%s sent\n");
436 	p(tcps_keepdrops, "\t\t%lu connection%s dropped by keepalive\n");
437 	p(tcps_predack, "\t%lu correct ACK header prediction%s\n");
438 	p(tcps_preddat, "\t%lu correct data packet header prediction%s\n");
439 
440 	p(tcps_sc_added, "\t%lu syncache entrie%s added\n");
441 	p1a(tcps_sc_retransmitted, "\t\t%lu retransmitted\n");
442 	p1a(tcps_sc_dupsyn, "\t\t%lu dupsyn\n");
443 	p1a(tcps_sc_dropped, "\t\t%lu dropped\n");
444 	p1a(tcps_sc_completed, "\t\t%lu completed\n");
445 	p1a(tcps_sc_bucketoverflow, "\t\t%lu bucket overflow\n");
446 	p1a(tcps_sc_cacheoverflow, "\t\t%lu cache overflow\n");
447 	p1a(tcps_sc_reset, "\t\t%lu reset\n");
448 	p1a(tcps_sc_stale, "\t\t%lu stale\n");
449 	p1a(tcps_sc_aborted, "\t\t%lu aborted\n");
450 	p1a(tcps_sc_badack, "\t\t%lu badack\n");
451 	p1a(tcps_sc_unreach, "\t\t%lu unreach\n");
452 	p(tcps_sc_zonefail, "\t\t%lu zone failure%s\n");
453 	p(tcps_sc_sendcookie, "\t%lu cookie%s sent\n");
454 	p(tcps_sc_recvcookie, "\t%lu cookie%s received\n");
455 #undef p
456 #undef p1a
457 #undef p2
458 #undef p2a
459 #undef p3
460 }
461 
462 /*
463  * Dump UDP statistics structure.
464  */
465 void
466 udp_stats(u_long off __unused, const char *name, int af1 __unused)
467 {
468 	struct udpstat udpstat, zerostat;
469 	size_t len = sizeof udpstat;
470 	u_long delivered;
471 
472 	if (zflag)
473 		memset(&zerostat, 0, len);
474 	if (sysctlbyname("net.inet.udp.stats", &udpstat, &len,
475 	    zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
476 		warn("sysctl: net.inet.udp.stats");
477 		return;
478 	}
479 
480 #ifdef INET6
481 	if (udp_done != 0)
482 		return;
483 	else
484 		udp_done = 1;
485 #endif
486 
487 	printf("%s:\n", name);
488 #define	p(f, m) if (udpstat.f || sflag <= 1) \
489     printf(m, udpstat.f, plural(udpstat.f))
490 #define	p1a(f, m) if (udpstat.f || sflag <= 1) \
491     printf(m, udpstat.f)
492 	p(udps_ipackets, "\t%lu datagram%s received\n");
493 	p1a(udps_hdrops, "\t%lu with incomplete header\n");
494 	p1a(udps_badlen, "\t%lu with bad data length field\n");
495 	p1a(udps_badsum, "\t%lu with bad checksum\n");
496 	p1a(udps_nosum, "\t%lu with no checksum\n");
497 	p1a(udps_noport, "\t%lu dropped due to no socket\n");
498 	p(udps_noportbcast,
499 	    "\t%lu broadcast/multicast datagram%s dropped due to no socket\n");
500 	p1a(udps_fullsock, "\t%lu dropped due to full socket buffers\n");
501 	p1a(udpps_pcbhashmiss, "\t%lu not for hashed pcb\n");
502 	delivered = udpstat.udps_ipackets -
503 		    udpstat.udps_hdrops -
504 		    udpstat.udps_badlen -
505 		    udpstat.udps_badsum -
506 		    udpstat.udps_noport -
507 		    udpstat.udps_noportbcast -
508 		    udpstat.udps_fullsock;
509 	if (delivered || sflag <= 1)
510 		printf("\t%lu delivered\n", delivered);
511 	p(udps_opackets, "\t%lu datagram%s output\n");
512 #undef p
513 #undef p1a
514 }
515 
516 /*
517  * Dump IP statistics structure.
518  */
519 void
520 ip_stats(u_long off __unused, const char *name, int af1 __unused)
521 {
522 	struct ipstat ipstat, zerostat;
523 	size_t len = sizeof ipstat;
524 
525 	if (zflag)
526 		memset(&zerostat, 0, len);
527 	if (sysctlbyname("net.inet.ip.stats", &ipstat, &len,
528 	    zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
529 		warn("sysctl: net.inet.ip.stats");
530 		return;
531 	}
532 
533 	printf("%s:\n", name);
534 
535 #define	p(f, m) if (ipstat.f || sflag <= 1) \
536     printf(m, ipstat.f, plural(ipstat.f))
537 #define	p1a(f, m) if (ipstat.f || sflag <= 1) \
538     printf(m, ipstat.f)
539 
540 	p(ips_total, "\t%lu total packet%s received\n");
541 	p(ips_badsum, "\t%lu bad header checksum%s\n");
542 	p1a(ips_toosmall, "\t%lu with size smaller than minimum\n");
543 	p1a(ips_tooshort, "\t%lu with data size < data length\n");
544 	p1a(ips_toolong, "\t%lu with ip length > max ip packet size\n");
545 	p1a(ips_badhlen, "\t%lu with header length < data size\n");
546 	p1a(ips_badlen, "\t%lu with data length < header length\n");
547 	p1a(ips_badoptions, "\t%lu with bad options\n");
548 	p1a(ips_badvers, "\t%lu with incorrect version number\n");
549 	p(ips_fragments, "\t%lu fragment%s received\n");
550 	p(ips_fragdropped, "\t%lu fragment%s dropped (dup or out of space)\n");
551 	p(ips_fragtimeout, "\t%lu fragment%s dropped after timeout\n");
552 	p(ips_reassembled, "\t%lu packet%s reassembled ok\n");
553 	p(ips_delivered, "\t%lu packet%s for this host\n");
554 	p(ips_noproto, "\t%lu packet%s for unknown/unsupported protocol\n");
555 	p(ips_forward, "\t%lu packet%s forwarded");
556 	p(ips_fastforward, " (%lu packet%s fast forwarded)");
557 	if (ipstat.ips_forward || sflag <= 1)
558 		putchar('\n');
559 	p(ips_cantforward, "\t%lu packet%s not forwardable\n");
560 	p(ips_notmember,
561 	  "\t%lu packet%s received for unknown multicast group\n");
562 	p(ips_redirectsent, "\t%lu redirect%s sent\n");
563 	p(ips_localout, "\t%lu packet%s sent from this host\n");
564 	p(ips_rawout, "\t%lu packet%s sent with fabricated ip header\n");
565 	p(ips_odropped,
566 	  "\t%lu output packet%s dropped due to no bufs, etc.\n");
567 	p(ips_noroute, "\t%lu output packet%s discarded due to no route\n");
568 	p(ips_fragmented, "\t%lu output datagram%s fragmented\n");
569 	p(ips_ofragments, "\t%lu fragment%s created\n");
570 	p(ips_cantfrag, "\t%lu datagram%s that can't be fragmented\n");
571 	p(ips_nogif, "\t%lu tunneling packet%s that can't find gif\n");
572 	p(ips_badaddr, "\t%lu datagram%s with bad address in header\n");
573 #undef p
574 #undef p1a
575 }
576 
577 static	const char *icmpnames[] = {
578 	"echo reply",
579 	"#1",
580 	"#2",
581 	"destination unreachable",
582 	"source quench",
583 	"routing redirect",
584 	"#6",
585 	"#7",
586 	"echo",
587 	"router advertisement",
588 	"router solicitation",
589 	"time exceeded",
590 	"parameter problem",
591 	"time stamp",
592 	"time stamp reply",
593 	"information request",
594 	"information request reply",
595 	"address mask request",
596 	"address mask reply",
597 };
598 
599 /*
600  * Dump ICMP statistics.
601  */
602 void
603 icmp_stats(u_long off __unused, const char *name, int af1 __unused)
604 {
605 	struct icmpstat icmpstat, zerostat;
606 	int i, first;
607 	int mib[4];		/* CTL_NET + PF_INET + IPPROTO_ICMP + req */
608 	size_t len;
609 
610 	mib[0] = CTL_NET;
611 	mib[1] = PF_INET;
612 	mib[2] = IPPROTO_ICMP;
613 	mib[3] = ICMPCTL_STATS;
614 
615 	len = sizeof icmpstat;
616 	if (zflag)
617 		memset(&zerostat, 0, len);
618 	if (sysctl(mib, 4, &icmpstat, &len,
619 	    zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
620 		warn("sysctl: net.inet.icmp.stats");
621 		return;
622 	}
623 
624 	printf("%s:\n", name);
625 
626 #define	p(f, m) if (icmpstat.f || sflag <= 1) \
627     printf(m, icmpstat.f, plural(icmpstat.f))
628 #define	p1a(f, m) if (icmpstat.f || sflag <= 1) \
629     printf(m, icmpstat.f)
630 #define	p2(f, m) if (icmpstat.f || sflag <= 1) \
631     printf(m, icmpstat.f, plurales(icmpstat.f))
632 
633 	p(icps_error, "\t%lu call%s to icmp_error\n");
634 	p(icps_oldicmp,
635 	    "\t%lu error%s not generated in response to an icmp message\n");
636 	for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
637 		if (icmpstat.icps_outhist[i] != 0) {
638 			if (first) {
639 				printf("\tOutput histogram:\n");
640 				first = 0;
641 			}
642 			printf("\t\t%s: %lu\n", icmpnames[i],
643 				icmpstat.icps_outhist[i]);
644 		}
645 	p(icps_badcode, "\t%lu message%s with bad code fields\n");
646 	p(icps_tooshort, "\t%lu message%s < minimum length\n");
647 	p(icps_checksum, "\t%lu bad checksum%s\n");
648 	p(icps_badlen, "\t%lu message%s with bad length\n");
649 	p1a(icps_bmcastecho, "\t%lu multicast echo requests ignored\n");
650 	p1a(icps_bmcasttstamp, "\t%lu multicast timestamp requests ignored\n");
651 	for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
652 		if (icmpstat.icps_inhist[i] != 0) {
653 			if (first) {
654 				printf("\tInput histogram:\n");
655 				first = 0;
656 			}
657 			printf("\t\t%s: %lu\n", icmpnames[i],
658 				icmpstat.icps_inhist[i]);
659 		}
660 	p(icps_reflect, "\t%lu message response%s generated\n");
661 	p2(icps_badaddr, "\t%lu invalid return address%s\n");
662 	p(icps_noroute, "\t%lu no return route%s\n");
663 #undef p
664 #undef p1a
665 #undef p2
666 	mib[3] = ICMPCTL_MASKREPL;
667 	len = sizeof i;
668 	if (sysctl(mib, 4, &i, &len, (void *)0, 0) < 0)
669 		return;
670 	printf("\tICMP address mask responses are %sabled\n",
671 	       i ? "en" : "dis");
672 }
673 
674 /*
675  * Dump IGMP statistics structure.
676  */
677 void
678 igmp_stats(u_long off __unused, const char *name, int af1 __unused)
679 {
680 	struct igmpstat igmpstat, zerostat;
681 	size_t len = sizeof igmpstat;
682 
683 	if (zflag)
684 		memset(&zerostat, 0, len);
685 	if (sysctlbyname("net.inet.igmp.stats", &igmpstat, &len,
686 	    zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
687 		warn("sysctl: net.inet.igmp.stats");
688 		return;
689 	}
690 
691 	printf("%s:\n", name);
692 
693 #define	p(f, m) if (igmpstat.f || sflag <= 1) \
694     printf(m, igmpstat.f, plural(igmpstat.f))
695 #define	py(f, m) if (igmpstat.f || sflag <= 1) \
696     printf(m, igmpstat.f, igmpstat.f != 1 ? "ies" : "y")
697 	p(igps_rcv_total, "\t%u message%s received\n");
698         p(igps_rcv_tooshort, "\t%u message%s received with too few bytes\n");
699         p(igps_rcv_badsum, "\t%u message%s received with bad checksum\n");
700         py(igps_rcv_queries, "\t%u membership quer%s received\n");
701         py(igps_rcv_badqueries, "\t%u membership quer%s received with invalid field(s)\n");
702         p(igps_rcv_reports, "\t%u membership report%s received\n");
703         p(igps_rcv_badreports, "\t%u membership report%s received with invalid field(s)\n");
704         p(igps_rcv_ourreports, "\t%u membership report%s received for groups to which we belong\n");
705         p(igps_snd_reports, "\t%u membership report%s sent\n");
706 #undef p
707 #undef py
708 }
709 
710 /*
711  * Dump PIM statistics structure.
712  */
713 void
714 pim_stats(u_long off __unused, const char *name, int af1 __unused)
715 {
716 	struct pimstat pimstat, zerostat;
717 	size_t len = sizeof pimstat;
718 
719 	if (zflag)
720 		memset(&zerostat, 0, len);
721 	if (sysctlbyname("net.inet.pim.stats", &pimstat, &len,
722 	    zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
723 		if (errno != ENOENT)
724 			warn("sysctl: net.inet.pim.stats");
725 		return;
726 	}
727 
728 	printf("%s:\n", name);
729 
730 #define	p(f, m) if (pimstat.f || sflag <= 1) \
731     printf(m, pimstat.f, plural(pimstat.f))
732 #define	py(f, m) if (pimstat.f || sflag <= 1) \
733     printf(m, pimstat.f, pimstat.f != 1 ? "ies" : "y")
734 	p(pims_rcv_total_msgs, "\t%llu message%s received\n");
735 	p(pims_rcv_total_bytes, "\t%llu byte%s received\n");
736 	p(pims_rcv_tooshort, "\t%llu message%s received with too few bytes\n");
737         p(pims_rcv_badsum, "\t%llu message%s received with bad checksum\n");
738 	p(pims_rcv_badversion, "\t%llu message%s received with bad version\n");
739 	p(pims_rcv_registers_msgs, "\t%llu data register message%s received\n");
740 	p(pims_rcv_registers_bytes, "\t%llu data register byte%s received\n");
741 	p(pims_rcv_registers_wrongiif, "\t%llu data register message%s received on wrong iif\n");
742 	p(pims_rcv_badregisters, "\t%llu bad register%s received\n");
743 	p(pims_snd_registers_msgs, "\t%llu data register message%s sent\n");
744 	p(pims_snd_registers_bytes, "\t%llu data register byte%s sent\n");
745 #undef p
746 #undef py
747 }
748 
749 /*
750  * Pretty print an Internet address (net address + port).
751  */
752 void
753 inetprint(struct in_addr *in, int port, const char *proto, int num_port)
754 {
755 	struct servent *sp = 0;
756 	char line[80], *cp;
757 	int width;
758 
759 	if (Wflag)
760 	    sprintf(line, "%s.", inetname(in));
761 	else
762 	    sprintf(line, "%.*s.", (Aflag && !num_port) ? 12 : 16, inetname(in));
763 	cp = index(line, '\0');
764 	if (!num_port && port)
765 		sp = getservbyport((int)port, proto);
766 	if (sp || port == 0)
767 		sprintf(cp, "%.15s ", sp ? sp->s_name : "*");
768 	else
769 		sprintf(cp, "%d ", ntohs((u_short)port));
770 	width = (Aflag && !Wflag) ? 18 : 22;
771 	if (Wflag)
772 	    printf("%-*s ", width, line);
773 	else
774 	    printf("%-*.*s ", width, width, line);
775 }
776 
777 /*
778  * Construct an Internet address representation.
779  * If numeric_addr has been supplied, give
780  * numeric value, otherwise try for symbolic name.
781  */
782 char *
783 inetname(struct in_addr *inp)
784 {
785 	char *cp;
786 	static char line[MAXHOSTNAMELEN];
787 	struct hostent *hp;
788 	struct netent *np;
789 
790 	cp = 0;
791 	if (!numeric_addr && inp->s_addr != INADDR_ANY) {
792 		int net = inet_netof(*inp);
793 		int lna = inet_lnaof(*inp);
794 
795 		if (lna == INADDR_ANY) {
796 			np = getnetbyaddr(net, AF_INET);
797 			if (np)
798 				cp = np->n_name;
799 		}
800 		if (cp == 0) {
801 			hp = gethostbyaddr((char *)inp, sizeof (*inp), AF_INET);
802 			if (hp) {
803 				cp = hp->h_name;
804 				trimdomain(cp, strlen(cp));
805 			}
806 		}
807 	}
808 	if (inp->s_addr == INADDR_ANY)
809 		strcpy(line, "*");
810 	else if (cp) {
811 		strncpy(line, cp, sizeof(line) - 1);
812 		line[sizeof(line) - 1] = '\0';
813 	} else {
814 		inp->s_addr = ntohl(inp->s_addr);
815 #define C(x)	((u_int)((x) & 0xff))
816 		sprintf(line, "%u.%u.%u.%u", C(inp->s_addr >> 24),
817 		    C(inp->s_addr >> 16), C(inp->s_addr >> 8), C(inp->s_addr));
818 	}
819 	return (line);
820 }
821