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