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