xref: /freebsd/usr.bin/netstat/inet.c (revision e4e9813eb92cd7c4d4b819a8fbed5cbd3d92f5d8)
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 	p(tcps_connattempt, "\t%lu connection request%s\n");
419 	p(tcps_accepts, "\t%lu connection accept%s\n");
420 	p(tcps_badsyn, "\t%lu bad connection attempt%s\n");
421 	p(tcps_listendrop, "\t%lu listen queue overflow%s\n");
422 	p(tcps_badrst, "\t%lu ignored RSTs in the window%s\n");
423 	p(tcps_connects, "\t%lu connection%s established (including accepts)\n");
424 	p2(tcps_closed, tcps_drops,
425 		"\t%lu connection%s closed (including %lu drop%s)\n");
426 	p(tcps_cachedrtt, "\t\t%lu connection%s updated cached RTT on close\n");
427 	p(tcps_cachedrttvar,
428 	  "\t\t%lu connection%s updated cached RTT variance on close\n");
429 	p(tcps_cachedssthresh,
430 	  "\t\t%lu connection%s updated cached ssthresh on close\n");
431 	p(tcps_conndrops, "\t%lu embryonic connection%s dropped\n");
432 	p2(tcps_rttupdated, tcps_segstimed,
433 		"\t%lu segment%s updated rtt (of %lu attempt%s)\n");
434 	p(tcps_rexmttimeo, "\t%lu retransmit timeout%s\n");
435 	p(tcps_timeoutdrop, "\t\t%lu connection%s dropped by rexmit timeout\n");
436 	p(tcps_persisttimeo, "\t%lu persist timeout%s\n");
437 	p(tcps_persistdrop, "\t\t%lu connection%s dropped by persist timeout\n");
438 	p(tcps_keeptimeo, "\t%lu keepalive timeout%s\n");
439 	p(tcps_keepprobe, "\t\t%lu keepalive probe%s sent\n");
440 	p(tcps_keepdrops, "\t\t%lu connection%s dropped by keepalive\n");
441 	p(tcps_predack, "\t%lu correct ACK header prediction%s\n");
442 	p(tcps_preddat, "\t%lu correct data packet header prediction%s\n");
443 
444 	p(tcps_sc_added, "\t%lu syncache entrie%s added\n");
445 	p1a(tcps_sc_retransmitted, "\t\t%lu retransmitted\n");
446 	p1a(tcps_sc_dupsyn, "\t\t%lu dupsyn\n");
447 	p1a(tcps_sc_dropped, "\t\t%lu dropped\n");
448 	p1a(tcps_sc_completed, "\t\t%lu completed\n");
449 	p1a(tcps_sc_bucketoverflow, "\t\t%lu bucket overflow\n");
450 	p1a(tcps_sc_cacheoverflow, "\t\t%lu cache overflow\n");
451 	p1a(tcps_sc_reset, "\t\t%lu reset\n");
452 	p1a(tcps_sc_stale, "\t\t%lu stale\n");
453 	p1a(tcps_sc_aborted, "\t\t%lu aborted\n");
454 	p1a(tcps_sc_badack, "\t\t%lu badack\n");
455 	p1a(tcps_sc_unreach, "\t\t%lu unreach\n");
456 	p(tcps_sc_zonefail, "\t\t%lu zone failure%s\n");
457 	p(tcps_sc_sendcookie, "\t%lu cookie%s sent\n");
458 	p(tcps_sc_recvcookie, "\t%lu cookie%s received\n");
459 
460 	p(tcps_sack_recovery_episode, "\t%lu SACK recovery episode%s\n");
461 	p(tcps_sack_rexmits,
462 		"\t%lu segment rexmit%s in SACK recovery episodes\n");
463 	p(tcps_sack_rexmit_bytes,
464 		"\t%lu byte rexmit%s in SACK recovery episodes\n");
465 	p(tcps_sack_rcv_blocks,
466 		"\t%lu SACK option%s (SACK blocks) received\n");
467 	p(tcps_sack_send_blocks, "\t%lu SACK option%s (SACK blocks) sent\n");
468 	p1a(tcps_sack_sboverflow, "\t%lu SACK scoreboard overflow\n");
469 
470 #undef p
471 #undef p1a
472 #undef p2
473 #undef p2a
474 #undef p3
475 }
476 
477 /*
478  * Dump UDP statistics structure.
479  */
480 void
481 udp_stats(u_long off __unused, const char *name, int af1 __unused)
482 {
483 	struct udpstat udpstat, zerostat;
484 	size_t len = sizeof udpstat;
485 	u_long delivered;
486 
487 	if (zflag)
488 		memset(&zerostat, 0, len);
489 	if (sysctlbyname("net.inet.udp.stats", &udpstat, &len,
490 	    zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
491 		warn("sysctl: net.inet.udp.stats");
492 		return;
493 	}
494 
495 #ifdef INET6
496 	if (udp_done != 0)
497 		return;
498 	else
499 		udp_done = 1;
500 #endif
501 
502 	printf("%s:\n", name);
503 #define	p(f, m) if (udpstat.f || sflag <= 1) \
504     printf(m, udpstat.f, plural(udpstat.f))
505 #define	p1a(f, m) if (udpstat.f || sflag <= 1) \
506     printf(m, udpstat.f)
507 	p(udps_ipackets, "\t%lu datagram%s received\n");
508 	p1a(udps_hdrops, "\t%lu with incomplete header\n");
509 	p1a(udps_badlen, "\t%lu with bad data length field\n");
510 	p1a(udps_badsum, "\t%lu with bad checksum\n");
511 	p1a(udps_nosum, "\t%lu with no checksum\n");
512 	p1a(udps_noport, "\t%lu dropped due to no socket\n");
513 	p(udps_noportbcast,
514 	    "\t%lu broadcast/multicast datagram%s dropped due to no socket\n");
515 	p1a(udps_fullsock, "\t%lu dropped due to full socket buffers\n");
516 	p1a(udpps_pcbhashmiss, "\t%lu not for hashed pcb\n");
517 	delivered = udpstat.udps_ipackets -
518 		    udpstat.udps_hdrops -
519 		    udpstat.udps_badlen -
520 		    udpstat.udps_badsum -
521 		    udpstat.udps_noport -
522 		    udpstat.udps_noportbcast -
523 		    udpstat.udps_fullsock;
524 	if (delivered || sflag <= 1)
525 		printf("\t%lu delivered\n", delivered);
526 	p(udps_opackets, "\t%lu datagram%s output\n");
527 #undef p
528 #undef p1a
529 }
530 
531 /*
532  * Dump CARP statistics structure.
533  */
534 void
535 carp_stats(u_long off __unused, const char *name, int af1 __unused)
536 {
537 	struct carpstats carpstat, zerostat;
538 	size_t len = sizeof(struct carpstats);
539 
540 	if (zflag)
541 		memset(&zerostat, 0, len);
542 	if (sysctlbyname("net.inet.carp.stats", &carpstat, &len,
543 	    zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
544 		if (errno != ENOENT)
545 			warn("sysctl: net.inet.carp.stats");
546 		return;
547 	}
548 
549 	printf("%s:\n", name);
550 
551 #define p(f, m) if (carpstat.f || sflag <= 1) \
552 	printf(m, (uintmax_t)carpstat.f, plural(carpstat.f))
553 #define p2(f, m) if (carpstat.f || sflag <= 1) \
554 	printf(m, (uintmax_t)carpstat.f)
555 
556 	p(carps_ipackets, "\t%ju packet%s received (IPv4)\n");
557 	p(carps_ipackets6, "\t%ju packet%s received (IPv6)\n");
558 	p(carps_badttl, "\t\t%ju packet%s discarded for wrong TTL\n");
559 	p(carps_hdrops, "\t\t%ju packet%s shorter than header\n");
560 	p(carps_badsum, "\t\t%ju discarded for bad checksum%s\n");
561 	p(carps_badver,	"\t\t%ju discarded packet%s with a bad version\n");
562 	p2(carps_badlen, "\t\t%ju discarded because packet too short\n");
563 	p2(carps_badauth, "\t\t%ju discarded for bad authentication\n");
564 	p2(carps_badvhid, "\t\t%ju discarded for bad vhid\n");
565 	p2(carps_badaddrs, "\t\t%ju discarded because of a bad address list\n");
566 	p(carps_opackets, "\t%ju packet%s sent (IPv4)\n");
567 	p(carps_opackets6, "\t%ju packet%s sent (IPv6)\n");
568 	p2(carps_onomem, "\t\t%ju send failed due to mbuf memory error\n");
569 #if notyet
570 	p(carps_ostates, "\t\t%s state update%s sent\n");
571 #endif
572 #undef p
573 #undef p2
574 }
575 
576 /*
577  * Dump IP statistics structure.
578  */
579 void
580 ip_stats(u_long off __unused, const char *name, int af1 __unused)
581 {
582 	struct ipstat ipstat, zerostat;
583 	size_t len = sizeof ipstat;
584 
585 	if (zflag)
586 		memset(&zerostat, 0, len);
587 	if (sysctlbyname("net.inet.ip.stats", &ipstat, &len,
588 	    zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
589 		warn("sysctl: net.inet.ip.stats");
590 		return;
591 	}
592 
593 	printf("%s:\n", name);
594 
595 #define	p(f, m) if (ipstat.f || sflag <= 1) \
596     printf(m, ipstat.f, plural(ipstat.f))
597 #define	p1a(f, m) if (ipstat.f || sflag <= 1) \
598     printf(m, ipstat.f)
599 
600 	p(ips_total, "\t%lu total packet%s received\n");
601 	p(ips_badsum, "\t%lu bad header checksum%s\n");
602 	p1a(ips_toosmall, "\t%lu with size smaller than minimum\n");
603 	p1a(ips_tooshort, "\t%lu with data size < data length\n");
604 	p1a(ips_toolong, "\t%lu with ip length > max ip packet size\n");
605 	p1a(ips_badhlen, "\t%lu with header length < data size\n");
606 	p1a(ips_badlen, "\t%lu with data length < header length\n");
607 	p1a(ips_badoptions, "\t%lu with bad options\n");
608 	p1a(ips_badvers, "\t%lu with incorrect version number\n");
609 	p(ips_fragments, "\t%lu fragment%s received\n");
610 	p(ips_fragdropped, "\t%lu fragment%s dropped (dup or out of space)\n");
611 	p(ips_fragtimeout, "\t%lu fragment%s dropped after timeout\n");
612 	p(ips_reassembled, "\t%lu packet%s reassembled ok\n");
613 	p(ips_delivered, "\t%lu packet%s for this host\n");
614 	p(ips_noproto, "\t%lu packet%s for unknown/unsupported protocol\n");
615 	p(ips_forward, "\t%lu packet%s forwarded");
616 	p(ips_fastforward, " (%lu packet%s fast forwarded)");
617 	if (ipstat.ips_forward || sflag <= 1)
618 		putchar('\n');
619 	p(ips_cantforward, "\t%lu packet%s not forwardable\n");
620 	p(ips_notmember,
621 	  "\t%lu packet%s received for unknown multicast group\n");
622 	p(ips_redirectsent, "\t%lu redirect%s sent\n");
623 	p(ips_localout, "\t%lu packet%s sent from this host\n");
624 	p(ips_rawout, "\t%lu packet%s sent with fabricated ip header\n");
625 	p(ips_odropped,
626 	  "\t%lu output packet%s dropped due to no bufs, etc.\n");
627 	p(ips_noroute, "\t%lu output packet%s discarded due to no route\n");
628 	p(ips_fragmented, "\t%lu output datagram%s fragmented\n");
629 	p(ips_ofragments, "\t%lu fragment%s created\n");
630 	p(ips_cantfrag, "\t%lu datagram%s that can't be fragmented\n");
631 	p(ips_nogif, "\t%lu tunneling packet%s that can't find gif\n");
632 	p(ips_badaddr, "\t%lu datagram%s with bad address in header\n");
633 #undef p
634 #undef p1a
635 }
636 
637 static	const char *icmpnames[] = {
638 	"echo reply",
639 	"#1",
640 	"#2",
641 	"destination unreachable",
642 	"source quench",
643 	"routing redirect",
644 	"#6",
645 	"#7",
646 	"echo",
647 	"router advertisement",
648 	"router solicitation",
649 	"time exceeded",
650 	"parameter problem",
651 	"time stamp",
652 	"time stamp reply",
653 	"information request",
654 	"information request reply",
655 	"address mask request",
656 	"address mask reply",
657 };
658 
659 /*
660  * Dump ICMP statistics.
661  */
662 void
663 icmp_stats(u_long off __unused, const char *name, int af1 __unused)
664 {
665 	struct icmpstat icmpstat, zerostat;
666 	int i, first;
667 	int mib[4];		/* CTL_NET + PF_INET + IPPROTO_ICMP + req */
668 	size_t len;
669 
670 	mib[0] = CTL_NET;
671 	mib[1] = PF_INET;
672 	mib[2] = IPPROTO_ICMP;
673 	mib[3] = ICMPCTL_STATS;
674 
675 	len = sizeof icmpstat;
676 	if (zflag)
677 		memset(&zerostat, 0, len);
678 	if (sysctl(mib, 4, &icmpstat, &len,
679 	    zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
680 		warn("sysctl: net.inet.icmp.stats");
681 		return;
682 	}
683 
684 	printf("%s:\n", name);
685 
686 #define	p(f, m) if (icmpstat.f || sflag <= 1) \
687     printf(m, icmpstat.f, plural(icmpstat.f))
688 #define	p1a(f, m) if (icmpstat.f || sflag <= 1) \
689     printf(m, icmpstat.f)
690 #define	p2(f, m) if (icmpstat.f || sflag <= 1) \
691     printf(m, icmpstat.f, plurales(icmpstat.f))
692 
693 	p(icps_error, "\t%lu call%s to icmp_error\n");
694 	p(icps_oldicmp,
695 	    "\t%lu error%s not generated in response to an icmp message\n");
696 	for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
697 		if (icmpstat.icps_outhist[i] != 0) {
698 			if (first) {
699 				printf("\tOutput histogram:\n");
700 				first = 0;
701 			}
702 			printf("\t\t%s: %lu\n", icmpnames[i],
703 				icmpstat.icps_outhist[i]);
704 		}
705 	p(icps_badcode, "\t%lu message%s with bad code fields\n");
706 	p(icps_tooshort, "\t%lu message%s < minimum length\n");
707 	p(icps_checksum, "\t%lu bad checksum%s\n");
708 	p(icps_badlen, "\t%lu message%s with bad length\n");
709 	p1a(icps_bmcastecho, "\t%lu multicast echo requests ignored\n");
710 	p1a(icps_bmcasttstamp, "\t%lu multicast timestamp requests ignored\n");
711 	for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
712 		if (icmpstat.icps_inhist[i] != 0) {
713 			if (first) {
714 				printf("\tInput histogram:\n");
715 				first = 0;
716 			}
717 			printf("\t\t%s: %lu\n", icmpnames[i],
718 				icmpstat.icps_inhist[i]);
719 		}
720 	p(icps_reflect, "\t%lu message response%s generated\n");
721 	p2(icps_badaddr, "\t%lu invalid return address%s\n");
722 	p(icps_noroute, "\t%lu no return route%s\n");
723 #undef p
724 #undef p1a
725 #undef p2
726 	mib[3] = ICMPCTL_MASKREPL;
727 	len = sizeof i;
728 	if (sysctl(mib, 4, &i, &len, (void *)0, 0) < 0)
729 		return;
730 	printf("\tICMP address mask responses are %sabled\n",
731 	       i ? "en" : "dis");
732 }
733 
734 /*
735  * Dump IGMP statistics structure.
736  */
737 void
738 igmp_stats(u_long off __unused, const char *name, int af1 __unused)
739 {
740 	struct igmpstat igmpstat, zerostat;
741 	size_t len = sizeof igmpstat;
742 
743 	if (zflag)
744 		memset(&zerostat, 0, len);
745 	if (sysctlbyname("net.inet.igmp.stats", &igmpstat, &len,
746 	    zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
747 		warn("sysctl: net.inet.igmp.stats");
748 		return;
749 	}
750 
751 	printf("%s:\n", name);
752 
753 #define	p(f, m) if (igmpstat.f || sflag <= 1) \
754     printf(m, igmpstat.f, plural(igmpstat.f))
755 #define	py(f, m) if (igmpstat.f || sflag <= 1) \
756     printf(m, igmpstat.f, igmpstat.f != 1 ? "ies" : "y")
757 	p(igps_rcv_total, "\t%u message%s received\n");
758         p(igps_rcv_tooshort, "\t%u message%s received with too few bytes\n");
759         p(igps_rcv_badsum, "\t%u message%s received with bad checksum\n");
760         py(igps_rcv_queries, "\t%u membership quer%s received\n");
761         py(igps_rcv_badqueries, "\t%u membership quer%s received with invalid field(s)\n");
762         p(igps_rcv_reports, "\t%u membership report%s received\n");
763         p(igps_rcv_badreports, "\t%u membership report%s received with invalid field(s)\n");
764         p(igps_rcv_ourreports, "\t%u membership report%s received for groups to which we belong\n");
765         p(igps_snd_reports, "\t%u membership report%s sent\n");
766 #undef p
767 #undef py
768 }
769 
770 /*
771  * Dump PIM statistics structure.
772  */
773 void
774 pim_stats(u_long off __unused, const char *name, int af1 __unused)
775 {
776 	struct pimstat pimstat, zerostat;
777 	size_t len = sizeof pimstat;
778 
779 	if (zflag)
780 		memset(&zerostat, 0, len);
781 	if (sysctlbyname("net.inet.pim.stats", &pimstat, &len,
782 	    zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
783 		if (errno != ENOENT)
784 			warn("sysctl: net.inet.pim.stats");
785 		return;
786 	}
787 
788 	printf("%s:\n", name);
789 
790 #define	p(f, m) if (pimstat.f || sflag <= 1) \
791     printf(m, (uintmax_t)pimstat.f, plural(pimstat.f))
792 #define	py(f, m) if (pimstat.f || sflag <= 1) \
793     printf(m, (uintmax_t)pimstat.f, pimstat.f != 1 ? "ies" : "y")
794 	p(pims_rcv_total_msgs, "\t%ju message%s received\n");
795 	p(pims_rcv_total_bytes, "\t%ju byte%s received\n");
796 	p(pims_rcv_tooshort, "\t%ju message%s received with too few bytes\n");
797         p(pims_rcv_badsum, "\t%ju message%s received with bad checksum\n");
798 	p(pims_rcv_badversion, "\t%ju message%s received with bad version\n");
799 	p(pims_rcv_registers_msgs, "\t%ju data register message%s received\n");
800 	p(pims_rcv_registers_bytes, "\t%ju data register byte%s received\n");
801 	p(pims_rcv_registers_wrongiif, "\t%ju data register message%s received on wrong iif\n");
802 	p(pims_rcv_badregisters, "\t%ju bad register%s received\n");
803 	p(pims_snd_registers_msgs, "\t%ju data register message%s sent\n");
804 	p(pims_snd_registers_bytes, "\t%ju data register byte%s sent\n");
805 #undef p
806 #undef py
807 }
808 
809 /*
810  * Pretty print an Internet address (net address + port).
811  */
812 void
813 inetprint(struct in_addr *in, int port, const char *proto, int num_port)
814 {
815 	struct servent *sp = 0;
816 	char line[80], *cp;
817 	int width;
818 
819 	if (Wflag)
820 	    sprintf(line, "%s.", inetname(in));
821 	else
822 	    sprintf(line, "%.*s.", (Aflag && !num_port) ? 12 : 16, inetname(in));
823 	cp = index(line, '\0');
824 	if (!num_port && port)
825 		sp = getservbyport((int)port, proto);
826 	if (sp || port == 0)
827 		sprintf(cp, "%.15s ", sp ? sp->s_name : "*");
828 	else
829 		sprintf(cp, "%d ", ntohs((u_short)port));
830 	width = (Aflag && !Wflag) ? 18 : 22;
831 	if (Wflag)
832 	    printf("%-*s ", width, line);
833 	else
834 	    printf("%-*.*s ", width, width, line);
835 }
836 
837 /*
838  * Construct an Internet address representation.
839  * If numeric_addr has been supplied, give
840  * numeric value, otherwise try for symbolic name.
841  */
842 char *
843 inetname(struct in_addr *inp)
844 {
845 	char *cp;
846 	static char line[MAXHOSTNAMELEN];
847 	struct hostent *hp;
848 	struct netent *np;
849 
850 	cp = 0;
851 	if (!numeric_addr && inp->s_addr != INADDR_ANY) {
852 		int net = inet_netof(*inp);
853 		int lna = inet_lnaof(*inp);
854 
855 		if (lna == INADDR_ANY) {
856 			np = getnetbyaddr(net, AF_INET);
857 			if (np)
858 				cp = np->n_name;
859 		}
860 		if (cp == 0) {
861 			hp = gethostbyaddr((char *)inp, sizeof (*inp), AF_INET);
862 			if (hp) {
863 				cp = hp->h_name;
864 				trimdomain(cp, strlen(cp));
865 			}
866 		}
867 	}
868 	if (inp->s_addr == INADDR_ANY)
869 		strcpy(line, "*");
870 	else if (cp) {
871 		strncpy(line, cp, sizeof(line) - 1);
872 		line[sizeof(line) - 1] = '\0';
873 	} else {
874 		inp->s_addr = ntohl(inp->s_addr);
875 #define C(x)	((u_int)((x) & 0xff))
876 		sprintf(line, "%u.%u.%u.%u", C(inp->s_addr >> 24),
877 		    C(inp->s_addr >> 16), C(inp->s_addr >> 8), C(inp->s_addr));
878 	}
879 	return (line);
880 }
881