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