xref: /dragonfly/usr.bin/netstat/inet.c (revision 611395e5)
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.16 2004/12/20 11:03:16 joerg 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, const char *, int);
82 #ifdef INET6
83 extern void	inet6print (struct in6_addr *, int, const 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 
94 static int ppr_first = 1;
95 static void outputpcb(int proto, const char *name, struct inpcb *inp, struct xsocket *so, struct tcpcb *tp);
96 
97 void
98 protopr(u_long proto, char *name, int af)
99 {
100 	int istcp;
101 	int i;
102 	void *buf;
103 	const char *mibvar;
104 	size_t len;
105 
106 	istcp = 0;
107 	switch (proto) {
108 	case IPPROTO_TCP:
109 #ifdef INET6
110 		if (tcp_done != 0)
111 			return;
112 		else
113 			tcp_done = 1;
114 #endif
115 		istcp = 1;
116 		mibvar = "net.inet.tcp.pcblist";
117 		break;
118 	case IPPROTO_UDP:
119 #ifdef INET6
120 		if (udp_done != 0)
121 			return;
122 		else
123 			udp_done = 1;
124 #endif
125 		mibvar = "net.inet.udp.pcblist";
126 		break;
127 	case IPPROTO_DIVERT:
128 		mibvar = "net.inet.divert.pcblist";
129 		break;
130 	default:
131 		mibvar = "net.inet.raw.pcblist";
132 		break;
133 	}
134 	len = 0;
135 	if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) {
136 		if (errno != ENOENT)
137 			warn("sysctl: %s", mibvar);
138 		return;
139 	}
140 	if (len == 0)
141 		return;
142 	if ((buf = malloc(len)) == 0) {
143 		warn("malloc %lu bytes", (u_long)len);
144 		return;
145 	}
146 	if (sysctlbyname(mibvar, buf, &len, 0, 0) < 0) {
147 		warn("sysctl: %s", mibvar);
148 		free(buf);
149 		return;
150 	}
151 
152 	if (istcp) {
153 		struct xtcpcb *tcp = buf;
154 		len /= sizeof(*tcp);
155 		for (i = 0; i < len; i++) {
156 			if (tcp[i].xt_len != sizeof(*tcp))
157 				break;
158 			outputpcb(proto, name, &tcp[i].xt_inp,
159 				  &tcp[i].xt_socket, &tcp[i].xt_tp);
160 		}
161 	} else {
162 		struct xinpcb *in = buf;
163 		len /= sizeof(*in);
164 		for (i = 0; i < len; i++) {
165 			if (in[i].xi_len != sizeof(*in))
166 				break;
167 			outputpcb(proto, name, &in[i].xi_inp,
168 				  &in[i].xi_socket, NULL);
169 		}
170 	}
171 	free(buf);
172 }
173 
174 static void
175 outputpcb(int proto, const char *name, struct inpcb *inp, struct xsocket *so, struct tcpcb *tp)
176 {
177 	const char *vchar;
178 
179 	/* Ignore sockets for protocols other than the desired one. */
180 	if (so->xso_protocol != (int)proto)
181 		return;
182 
183 	if ((af == AF_INET && (inp->inp_vflag & INP_IPV4) == 0)
184 #ifdef INET6
185 	    || (af == AF_INET6 && (inp->inp_vflag & INP_IPV6) == 0)
186 #endif /* INET6 */
187 	    || (af == AF_UNSPEC && ((inp->inp_vflag & INP_IPV4) == 0
188 #ifdef INET6
189 		&& (inp->inp_vflag & INP_IPV6) == 0
190 #endif /* INET6 */
191 		))
192 	    ) {
193 		return;
194 	}
195 	if (!aflag && (
196 		(af == AF_INET && inet_lnaof(inp->inp_laddr) == INADDR_ANY)
197 #ifdef INET6
198 	    || (af == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr))
199 #endif /* INET6 */
200 	    || (af == AF_UNSPEC && (((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 		return;
209 	}
210 
211 	if (ppr_first) {
212 		if (!Lflag) {
213 			printf("Active Internet connections");
214 			if (aflag)
215 				printf(" (including servers)");
216 		} else {
217 			printf("Current listen queue sizes "
218 				"(qlen/incqlen/maxqlen)");
219 		}
220 		putchar('\n');
221 		if (Aflag)
222 			printf("%-8.8s ", "Socket");
223 		if (Lflag) {
224 			printf("%-5.5s %-14.14s %-22.22s\n",
225 				"Proto", "Listen", "Local Address");
226 		} else {
227 			printf((Aflag && !Wflag) ?
228 			    "%-5.5s %-6.6s %-6.6s %-17.17s %-17.17s %s\n" :
229 			    "%-5.5s %-6.6s %-6.6s %-21.21s %-21.21s %s\n",
230 			    "Proto", "Recv-Q", "Send-Q",
231 			    "Local Address", "Foreign Address",
232 			    "(state)");
233 		}
234 		ppr_first = 0;
235 	}
236 	if (Lflag && so->so_qlimit == 0)
237 		return;
238 	if (Aflag) {
239 		if (tp)
240 			printf("%8lx ", (u_long)inp->inp_ppcb);
241 		else
242 			printf("%8lx ", (u_long)so->so_pcb);
243 	}
244 #ifdef INET6
245 	if ((inp->inp_vflag & INP_IPV6) != 0)
246 		vchar = ((inp->inp_vflag & INP_IPV4) != 0) ? "46" : "6 ";
247 	else
248 #endif
249 		vchar = ((inp->inp_vflag & INP_IPV4) != 0) ? "4 " : "  ";
250 
251 	printf("%-3.3s%-2.2s ", name, vchar);
252 	if (Lflag) {
253 		char buf[15];
254 
255 		snprintf(buf, sizeof(buf), "%d/%d/%d", so->so_qlen,
256 			 so->so_incqlen, so->so_qlimit);
257 		printf("%-13.13s ", buf);
258 	} else if (Bflag) {
259 		printf("%6ld %6ld ",
260 		       so->so_rcv.sb_hiwat,
261 		       so->so_snd.sb_hiwat);
262 	} else {
263 		printf("%6ld %6ld ",
264 		       so->so_rcv.sb_cc,
265 		       so->so_snd.sb_cc);
266 	}
267 	if (numeric_port) {
268 		if (inp->inp_vflag & INP_IPV4) {
269 			inetprint(&inp->inp_laddr, (int)inp->inp_lport,
270 				  name, 1);
271 			if (!Lflag)
272 				inetprint(&inp->inp_faddr,
273 					  (int)inp->inp_fport, name, 1);
274 		}
275 #ifdef INET6
276 		else if (inp->inp_vflag & INP_IPV6) {
277 			inet6print(&inp->in6p_laddr,
278 				   (int)inp->inp_lport, name, 1);
279 			if (!Lflag)
280 				inet6print(&inp->in6p_faddr,
281 					   (int)inp->inp_fport, name, 1);
282 		} /* else nothing printed now */
283 #endif /* INET6 */
284 	} else if (inp->inp_flags & INP_ANONPORT) {
285 		if (inp->inp_vflag & INP_IPV4) {
286 			inetprint(&inp->inp_laddr, (int)inp->inp_lport,
287 				  name, 1);
288 			if (!Lflag)
289 				inetprint(&inp->inp_faddr,
290 					  (int)inp->inp_fport, name, 0);
291 		}
292 #ifdef INET6
293 		else if (inp->inp_vflag & INP_IPV6) {
294 			inet6print(&inp->in6p_laddr,
295 				   (int)inp->inp_lport, name, 1);
296 			if (!Lflag)
297 				inet6print(&inp->in6p_faddr,
298 					   (int)inp->inp_fport, name, 0);
299 		} /* else nothing printed now */
300 #endif /* INET6 */
301 	} else {
302 		if (inp->inp_vflag & INP_IPV4) {
303 			inetprint(&inp->inp_laddr, (int)inp->inp_lport,
304 				  name, 0);
305 			if (!Lflag)
306 				inetprint(&inp->inp_faddr,
307 					  (int)inp->inp_fport, name,
308 					  inp->inp_lport !=
309 						inp->inp_fport);
310 		}
311 #ifdef INET6
312 		else if (inp->inp_vflag & INP_IPV6) {
313 			inet6print(&inp->in6p_laddr,
314 				   (int)inp->inp_lport, name, 0);
315 			if (!Lflag)
316 				inet6print(&inp->in6p_faddr,
317 					   (int)inp->inp_fport, name,
318 					   inp->inp_lport !=
319 						inp->inp_fport);
320 		} /* else nothing printed now */
321 #endif /* INET6 */
322 	}
323 	if (tp && !Lflag) {
324 		if (tp->t_state < 0 || tp->t_state >= TCP_NSTATES)
325 			printf("%d", tp->t_state);
326 	      else {
327 			printf("%s", tcpstates[tp->t_state]);
328 #if defined(TF_NEEDSYN) && defined(TF_NEEDFIN)
329 		      /* Show T/TCP `hidden state' */
330 		      if (tp->t_flags & (TF_NEEDSYN|TF_NEEDFIN))
331 			      putchar('*');
332 #endif /* defined(TF_NEEDSYN) && defined(TF_NEEDFIN) */
333 	      }
334 	}
335 	putchar('\n');
336 }
337 
338 
339 
340 #define CPU_STATS_FUNC(proto,type)                            \
341 static void                                                   \
342 proto ##_stats_agg(type *ary, type *ttl, int cpucnt)          \
343 {                                                             \
344     int i, off, siz;                                          \
345     siz = sizeof(type);                                       \
346                                                               \
347     if (!ary && !ttl)                                         \
348         return;                                               \
349                                                               \
350     bzero(ttl, siz);                                          \
351     if (cpucnt == 1) {                                        \
352         *ttl = ary[0];                                        \
353     } else {                                                  \
354         for (i = 0; i < cpucnt; ++i) {                        \
355             for (off = 0; off < siz; off += sizeof(u_long)) { \
356                 *(u_long *)((char *)(*(&ttl)) + off) +=       \
357                 *(u_long *)((char *)&ary[i] + off);           \
358             }                                                 \
359         }                                                     \
360     }                                                         \
361 }
362 CPU_STATS_FUNC(tcp, struct tcp_stats);
363 CPU_STATS_FUNC(ip, struct ip_stats);
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 ip_stats ipstat, *stattmp;
567 	struct ip_stats zerostat[SMP_MAXCPU];
568 	size_t len = sizeof(struct ip_stats) * SMP_MAXCPU;
569 	int cpucnt;
570 
571 	if (zflag)
572 		memset(zerostat, 0, len);
573 	if ((stattmp = malloc(len)) == NULL) {
574 		return;
575 	} else {
576 		if (sysctlbyname("net.inet.ip.stats", stattmp, &len,
577 			zflag ? zerostat : NULL, zflag ? len : 0) < 0) {
578 				warn("sysctl: net.inet.ip.stats");
579 				free(stattmp);
580 				return;
581 		} else {
582 			if ((stattmp = realloc(stattmp, len)) == NULL) {
583 				warn("ip_stats");
584 				return;
585 			}
586 		}
587 	}
588 	cpucnt = len / sizeof(struct ip_stats);
589 	ip_stats_agg(stattmp, &ipstat, cpucnt);
590 
591 	printf("%s:\n", name);
592 
593 #define	p(f, m) if (ipstat.f || sflag <= 1) \
594     printf(m, ipstat.f, plural(ipstat.f))
595 #define	p1a(f, m) if (ipstat.f || sflag <= 1) \
596     printf(m, ipstat.f)
597 
598 	p(ips_total, "\t%lu total packet%s received\n");
599 	p(ips_badsum, "\t%lu bad header checksum%s\n");
600 	p1a(ips_toosmall, "\t%lu with size smaller than minimum\n");
601 	p1a(ips_tooshort, "\t%lu with data size < data length\n");
602 	p1a(ips_toolong, "\t%lu with ip length > max ip packet size\n");
603 	p1a(ips_badhlen, "\t%lu with header length < data size\n");
604 	p1a(ips_badlen, "\t%lu with data length < header length\n");
605 	p1a(ips_badoptions, "\t%lu with bad options\n");
606 	p1a(ips_badvers, "\t%lu with incorrect version number\n");
607 	p(ips_fragments, "\t%lu fragment%s received\n");
608 	p(ips_fragdropped, "\t%lu fragment%s dropped (dup or out of space)\n");
609 	p(ips_fragtimeout, "\t%lu fragment%s dropped after timeout\n");
610 	p(ips_reassembled, "\t%lu packet%s reassembled ok\n");
611 	p(ips_delivered, "\t%lu packet%s for this host\n");
612 	p(ips_noproto, "\t%lu packet%s for unknown/unsupported protocol\n");
613 	p(ips_forward, "\t%lu packet%s forwarded");
614 	p(ips_fastforward, " (%lu packet%s fast forwarded)");
615 	if (ipstat.ips_forward || sflag <= 1)
616 		putchar('\n');
617 	p(ips_cantforward, "\t%lu packet%s not forwardable\n");
618 	p(ips_notmember,
619 	  "\t%lu packet%s received for unknown multicast group\n");
620 	p(ips_redirectsent, "\t%lu redirect%s sent\n");
621 	p(ips_localout, "\t%lu packet%s sent from this host\n");
622 	p(ips_rawout, "\t%lu packet%s sent with fabricated ip header\n");
623 	p(ips_odropped,
624 	  "\t%lu output packet%s dropped due to no bufs, etc.\n");
625 	p(ips_noroute, "\t%lu output packet%s discarded due to no route\n");
626 	p(ips_fragmented, "\t%lu output datagram%s fragmented\n");
627 	p(ips_ofragments, "\t%lu fragment%s created\n");
628 	p(ips_cantfrag, "\t%lu datagram%s that can't be fragmented\n");
629 	p(ips_nogif, "\t%lu tunneling packet%s that can't find gif\n");
630 	p(ips_badaddr, "\t%lu datagram%s with bad address in header\n");
631 	free(stattmp);
632 #undef p
633 #undef p1a
634 }
635 
636 static	char *icmpnames[] = {
637 	"echo reply",
638 	"#1",
639 	"#2",
640 	"destination unreachable",
641 	"source quench",
642 	"routing redirect",
643 	"#6",
644 	"#7",
645 	"echo",
646 	"router advertisement",
647 	"router solicitation",
648 	"time exceeded",
649 	"parameter problem",
650 	"time stamp",
651 	"time stamp reply",
652 	"information request",
653 	"information request reply",
654 	"address mask request",
655 	"address mask reply",
656 };
657 
658 /*
659  * Dump ICMP statistics.
660  */
661 void
662 icmp_stats(u_long off __unused, char *name, int af __unused)
663 {
664 	struct icmpstat icmpstat, zerostat;
665 	int i, first;
666 	int mib[4];		/* CTL_NET + PF_INET + IPPROTO_ICMP + req */
667 	size_t len;
668 
669 	mib[0] = CTL_NET;
670 	mib[1] = PF_INET;
671 	mib[2] = IPPROTO_ICMP;
672 	mib[3] = ICMPCTL_STATS;
673 
674 	len = sizeof icmpstat;
675 	if (zflag)
676 		memset(&zerostat, 0, len);
677 	if (sysctl(mib, 4, &icmpstat, &len,
678 	    zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
679 		warn("sysctl: net.inet.icmp.stats");
680 		return;
681 	}
682 
683 	printf("%s:\n", name);
684 
685 #define	p(f, m) if (icmpstat.f || sflag <= 1) \
686     printf(m, icmpstat.f, plural(icmpstat.f))
687 #define	p1a(f, m) if (icmpstat.f || sflag <= 1) \
688     printf(m, icmpstat.f)
689 #define	p2(f, m) if (icmpstat.f || sflag <= 1) \
690     printf(m, icmpstat.f, plurales(icmpstat.f))
691 
692 	p(icps_error, "\t%lu call%s to icmp_error\n");
693 	p(icps_oldicmp,
694 	    "\t%lu error%s not generated 'cuz old message was icmp\n");
695 	for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
696 		if (icmpstat.icps_outhist[i] != 0) {
697 			if (first) {
698 				printf("\tOutput histogram:\n");
699 				first = 0;
700 			}
701 			printf("\t\t%s: %lu\n", icmpnames[i],
702 				icmpstat.icps_outhist[i]);
703 		}
704 	p(icps_badcode, "\t%lu message%s with bad code fields\n");
705 	p(icps_tooshort, "\t%lu message%s < minimum length\n");
706 	p(icps_checksum, "\t%lu bad checksum%s\n");
707 	p(icps_badlen, "\t%lu message%s with bad length\n");
708 	p1a(icps_bmcastecho, "\t%lu multicast echo requests ignored\n");
709 	p1a(icps_bmcasttstamp, "\t%lu multicast timestamp requests ignored\n");
710 	for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
711 		if (icmpstat.icps_inhist[i] != 0) {
712 			if (first) {
713 				printf("\tInput histogram:\n");
714 				first = 0;
715 			}
716 			printf("\t\t%s: %lu\n", icmpnames[i],
717 				icmpstat.icps_inhist[i]);
718 		}
719 	p(icps_reflect, "\t%lu message response%s generated\n");
720 	p2(icps_badaddr, "\t%lu invalid return address%s\n");
721 	p(icps_noroute, "\t%lu no return route%s\n");
722 #undef p
723 #undef p1a
724 #undef p2
725 	mib[3] = ICMPCTL_MASKREPL;
726 	len = sizeof i;
727 	if (sysctl(mib, 4, &i, &len, (void *)0, 0) < 0)
728 		return;
729 	printf("\tICMP address mask responses are %sabled\n",
730 	       i ? "en" : "dis");
731 }
732 
733 /*
734  * Dump IGMP statistics structure.
735  */
736 void
737 igmp_stats(u_long off __unused, char *name, int af __unused)
738 {
739 	struct igmpstat igmpstat, zerostat;
740 	size_t len = sizeof igmpstat;
741 
742 	if (zflag)
743 		memset(&zerostat, 0, len);
744 	if (sysctlbyname("net.inet.igmp.stats", &igmpstat, &len,
745 	    zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
746 		warn("sysctl: net.inet.igmp.stats");
747 		return;
748 	}
749 
750 	printf("%s:\n", name);
751 
752 #define	p(f, m) if (igmpstat.f || sflag <= 1) \
753     printf(m, igmpstat.f, plural(igmpstat.f))
754 #define	py(f, m) if (igmpstat.f || sflag <= 1) \
755     printf(m, igmpstat.f, igmpstat.f != 1 ? "ies" : "y")
756 	p(igps_rcv_total, "\t%u message%s received\n");
757         p(igps_rcv_tooshort, "\t%u message%s received with too few bytes\n");
758         p(igps_rcv_badsum, "\t%u message%s received with bad checksum\n");
759         py(igps_rcv_queries, "\t%u membership quer%s received\n");
760         py(igps_rcv_badqueries, "\t%u membership quer%s received with invalid field(s)\n");
761         p(igps_rcv_reports, "\t%u membership report%s received\n");
762         p(igps_rcv_badreports, "\t%u membership report%s received with invalid field(s)\n");
763         p(igps_rcv_ourreports, "\t%u membership report%s received for groups to which we belong\n");
764         p(igps_snd_reports, "\t%u membership report%s sent\n");
765 #undef p
766 #undef py
767 }
768 
769 /*
770  * Dump PIM statistics structure.
771  */
772 void
773 pim_stats(u_long off __unused, char *name, int af1 __unused)
774 {
775 	struct pimstat pimstat, zerostat;
776 	size_t len = sizeof pimstat;
777 
778 	if (zflag)
779 		memset(&zerostat, 0, len);
780 	if (sysctlbyname("net.inet.pim.stats", &pimstat, &len,
781 	    zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
782 		if (errno != ENOENT)
783 			warn("sysctl: net.inet.pim.stats");
784 		return;
785 	}
786 
787 	printf("%s:\n", name);
788 
789 #define	p(f, m) if (pimstat.f || sflag <= 1) \
790     printf(m, pimstat.f, plural(pimstat.f))
791 #define	py(f, m) if (pimstat.f || sflag <= 1) \
792     printf(m, pimstat.f, pimstat.f != 1 ? "ies" : "y")
793 	p(pims_rcv_total_msgs, "\t%llu message%s received\n");
794 	p(pims_rcv_total_bytes, "\t%llu byte%s received\n");
795 	p(pims_rcv_tooshort, "\t%llu message%s received with too few bytes\n");
796         p(pims_rcv_badsum, "\t%llu message%s received with bad checksum\n");
797 	p(pims_rcv_badversion, "\t%llu message%s received with bad version\n");
798 	p(pims_rcv_registers_msgs, "\t%llu data register message%s received\n");
799 	p(pims_rcv_registers_bytes, "\t%llu data register byte%s received\n");
800 	p(pims_rcv_registers_wrongiif, "\t%llu data register message%s received on wrong iif\n");
801 	p(pims_rcv_badregisters, "\t%llu bad register%s received\n");
802 	p(pims_snd_registers_msgs, "\t%llu data register message%s sent\n");
803 	p(pims_snd_registers_bytes, "\t%llu data register byte%s sent\n");
804 #undef p
805 #undef py
806 }
807 
808 /*
809  * Pretty print an Internet address (net address + port).
810  */
811 void
812 inetprint(struct in_addr *in, int port, const char *proto, int numeric_port)
813 {
814 	struct servent *sp = 0;
815 	char line[80], *cp;
816 	int width;
817 
818 	if (Wflag)
819 	    sprintf(line, "%s.", inetname(in));
820 	else
821 	    sprintf(line, "%.*s.", (Aflag && !numeric_port) ? 12 : 16, inetname(in));
822 	cp = strchr(line, '\0');
823 	if (!numeric_port && port)
824 		sp = getservbyport((int)port, proto);
825 	if (sp || port == 0)
826 		sprintf(cp, "%.15s ", sp ? sp->s_name : "*");
827 	else
828 		sprintf(cp, "%d ", ntohs((u_short)port));
829 	width = (Aflag && !Wflag) ? 17 : 21;
830 	if (Wflag)
831 	    printf("%-*s ", width, line);
832 	else
833 	    printf("%-*.*s ", width, width, line);
834 }
835 
836 /*
837  * Construct an Internet address representation.
838  * If numeric_addr has been supplied, give
839  * numeric value, otherwise try for symbolic name.
840  */
841 char *
842 inetname(struct in_addr *inp)
843 {
844 	register char *cp;
845 	static char line[MAXHOSTNAMELEN];
846 	struct hostent *hp;
847 	struct netent *np;
848 
849 	cp = 0;
850 	if (!numeric_addr && inp->s_addr != INADDR_ANY) {
851 		int net = inet_netof(*inp);
852 		int lna = inet_lnaof(*inp);
853 
854 		if (lna == INADDR_ANY) {
855 			np = getnetbyaddr(net, AF_INET);
856 			if (np)
857 				cp = np->n_name;
858 		}
859 		if (cp == 0) {
860 			hp = gethostbyaddr((char *)inp, sizeof (*inp), AF_INET);
861 			if (hp) {
862 				cp = hp->h_name;
863 				trimdomain(cp, strlen(cp));
864 			}
865 		}
866 	}
867 	if (inp->s_addr == INADDR_ANY)
868 		strcpy(line, "*");
869 	else if (cp) {
870 		strncpy(line, cp, sizeof(line) - 1);
871 		line[sizeof(line) - 1] = '\0';
872 	} else {
873 		inp->s_addr = ntohl(inp->s_addr);
874 #define C(x)	((u_int)((x) & 0xff))
875 		sprintf(line, "%u.%u.%u.%u", C(inp->s_addr >> 24),
876 		    C(inp->s_addr >> 16), C(inp->s_addr >> 8), C(inp->s_addr));
877 	}
878 	return (line);
879 }
880