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