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