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