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