xref: /dflybsd-src/usr.bin/netstat/inet.c (revision bf22d4c1f95f57623b2b3030738e116d3a547284)
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.13 2004/05/03 15:18:25 hmp 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 #define CPU_STATS_FUNC(proto,type)                            \
344 static void                                                   \
345 proto ##_stats_agg(type *ary, type *ttl, int cpucnt)          \
346 {                                                             \
347     int i, off, siz;                                          \
348     siz = sizeof(type);                                       \
349                                                               \
350     if (!ary && !ttl)                                         \
351         return;                                               \
352                                                               \
353     bzero(ttl, siz);                                          \
354     if (cpucnt == 1) {                                        \
355         *ttl = ary[0];                                        \
356     } else {                                                  \
357         for (i = 0; i < cpucnt; ++i) {                        \
358             for (off = 0; off < siz; off += sizeof(u_long)) { \
359                 *(u_long *)((char *)(*(&ttl)) + off) +=       \
360                 *(u_long *)((char *)&ary[i] + off);           \
361             }                                                 \
362         }                                                     \
363     }                                                         \
364 }
365 CPU_STATS_FUNC(tcp, struct tcp_stats);
366 CPU_STATS_FUNC(ip, struct ip_stats);
367 
368 /*
369  * Dump TCP statistics structure.
370  */
371 void
372 tcp_stats(u_long off __unused, char *name, int af __unused)
373 {
374 	struct tcp_stats tcpstat, *stattmp;
375 	struct tcp_stats zerostat[SMP_MAXCPU];
376 	size_t len = sizeof(struct tcp_stats) * SMP_MAXCPU;
377 	int cpucnt;
378 
379 	if (zflag)
380 		memset(zerostat, 0, len);
381 
382 	if ((stattmp = malloc(len)) == NULL) {
383 		return;
384 	} else {
385 		if (sysctlbyname("net.inet.tcp.stats", stattmp, &len,
386 			zflag ? zerostat : NULL, zflag ? len : 0) < 0) {
387 			warn("sysctl: net.inet.tcp.stats");
388 			free(stattmp);
389 			return;
390 		} else {
391 			if ((stattmp = realloc(stattmp, len)) == NULL) {
392 				warn("tcp_stats");
393 				return;
394 			}
395 		}
396 	}
397 	cpucnt = len / sizeof(struct tcp_stats);
398 	tcp_stats_agg(stattmp, &tcpstat, cpucnt);
399 
400 #ifdef INET6
401 	if (tcp_done != 0)
402 		return;
403 	else
404 		tcp_done = 1;
405 #endif
406 
407 	printf ("%s:\n", name);
408 
409 #define	p(f, m) if (tcpstat.f || sflag <= 1) \
410     printf(m, tcpstat.f, plural(tcpstat.f))
411 #define	p1a(f, m) if (tcpstat.f || sflag <= 1) \
412     printf(m, tcpstat.f)
413 #define	p2(f1, f2, m) if (tcpstat.f1 || tcpstat.f2 || sflag <= 1) \
414     printf(m, tcpstat.f1, plural(tcpstat.f1), tcpstat.f2, plural(tcpstat.f2))
415 #define	p2a(f1, f2, m) if (tcpstat.f1 || tcpstat.f2 || sflag <= 1) \
416     printf(m, tcpstat.f1, plural(tcpstat.f1), tcpstat.f2)
417 #define	p3(f, m) if (tcpstat.f || sflag <= 1) \
418     printf(m, tcpstat.f, plurales(tcpstat.f))
419 
420 	p(tcps_sndtotal, "\t%lu packet%s sent\n");
421 	p2(tcps_sndpack,tcps_sndbyte,
422 		"\t\t%lu data packet%s (%lu byte%s)\n");
423 	p2(tcps_sndrexmitpack, tcps_sndrexmitbyte,
424 		"\t\t%lu data packet%s (%lu byte%s) retransmitted\n");
425 	p2a(tcps_sndfastrexmit, tcps_sndearlyrexmit,
426 		"\t\t%lu Fast Retransmit%s (%lu early)\n");
427 	p(tcps_sndlimited, "\t\t%lu packet%s sent by Limited Transmit\n");
428 	p(tcps_sndrtobad, "\t\t%lu spurious RTO retransmit%s\n");
429 	p2a(tcps_sndfastrexmitbad, tcps_sndearlyrexmitbad,
430 		"\t\t%lu spurious Fast Retransmit%s (%lu early)\n");
431 	p(tcps_eifeldetected, "\t\t%lu Eifel-detected spurious retransmit%s\n");
432 	p(tcps_rttdetected, "\t\t%lu RTT-detected spurious retransmit%s\n");
433 	p(tcps_mturesent, "\t\t%lu resend%s initiated by MTU discovery\n");
434 	p2a(tcps_sndacks, tcps_delack,
435 		"\t\t%lu ack-only packet%s (%lu delayed)\n");
436 	p(tcps_sndurg, "\t\t%lu URG only packet%s\n");
437 	p(tcps_sndprobe, "\t\t%lu window probe packet%s\n");
438 	p(tcps_sndwinup, "\t\t%lu window update packet%s\n");
439 	p(tcps_sndctrl, "\t\t%lu control packet%s\n");
440 	p(tcps_rcvtotal, "\t%lu packet%s received\n");
441 	p2(tcps_rcvackpack, tcps_rcvackbyte, "\t\t%lu ack%s (for %lu byte%s)\n");
442 	p(tcps_rcvdupack, "\t\t%lu duplicate ack%s\n");
443 	p(tcps_rcvacktoomuch, "\t\t%lu ack%s for unsent data\n");
444 	p2(tcps_rcvpack, tcps_rcvbyte,
445 		"\t\t%lu packet%s (%lu byte%s) received in-sequence\n");
446 	p2(tcps_rcvduppack, tcps_rcvdupbyte,
447 		"\t\t%lu completely duplicate packet%s (%lu byte%s)\n");
448 	p(tcps_pawsdrop, "\t\t%lu old duplicate packet%s\n");
449 	p2(tcps_rcvpartduppack, tcps_rcvpartdupbyte,
450 		"\t\t%lu packet%s with some dup. data (%lu byte%s duped)\n");
451 	p2(tcps_rcvoopack, tcps_rcvoobyte,
452 		"\t\t%lu out-of-order packet%s (%lu byte%s)\n");
453 	p2(tcps_rcvpackafterwin, tcps_rcvbyteafterwin,
454 		"\t\t%lu packet%s (%lu byte%s) of data after window\n");
455 	p(tcps_rcvwinprobe, "\t\t%lu window probe%s\n");
456 	p(tcps_rcvwinupd, "\t\t%lu window update packet%s\n");
457 	p(tcps_rcvafterclose, "\t\t%lu packet%s received after close\n");
458 	p(tcps_rcvbadsum, "\t\t%lu discarded for bad checksum%s\n");
459 	p(tcps_rcvbadoff, "\t\t%lu discarded for bad header offset field%s\n");
460 	p1a(tcps_rcvshort, "\t\t%lu discarded because packet too short\n");
461 	p(tcps_connattempt, "\t%lu connection request%s\n");
462 	p(tcps_accepts, "\t%lu connection accept%s\n");
463 	p(tcps_badsyn, "\t%lu bad connection attempt%s\n");
464 	p(tcps_listendrop, "\t%lu listen queue overflow%s\n");
465 	p(tcps_connects, "\t%lu connection%s established (including accepts)\n");
466 	p2(tcps_closed, tcps_drops,
467 		"\t%lu connection%s closed (including %lu drop%s)\n");
468 	p(tcps_cachedrtt, "\t\t%lu connection%s updated cached RTT on close\n");
469 	p(tcps_cachedrttvar,
470 	  "\t\t%lu connection%s updated cached RTT variance on close\n");
471 	p(tcps_cachedssthresh,
472 	  "\t\t%lu connection%s updated cached ssthresh on close\n");
473 	p(tcps_conndrops, "\t%lu embryonic connection%s dropped\n");
474 	p2(tcps_rttupdated, tcps_segstimed,
475 		"\t%lu segment%s updated rtt (of %lu attempt%s)\n");
476 	p(tcps_rexmttimeo, "\t%lu retransmit timeout%s\n");
477 	p(tcps_timeoutdrop, "\t\t%lu connection%s dropped by rexmit timeout\n");
478 	p(tcps_persisttimeo, "\t%lu persist timeout%s\n");
479 	p(tcps_persistdrop, "\t\t%lu connection%s dropped by persist timeout\n");
480 	p(tcps_keeptimeo, "\t%lu keepalive timeout%s\n");
481 	p(tcps_keepprobe, "\t\t%lu keepalive probe%s sent\n");
482 	p(tcps_keepdrops, "\t\t%lu connection%s dropped by keepalive\n");
483 	p(tcps_predack, "\t%lu correct ACK header prediction%s\n");
484 	p(tcps_preddat, "\t%lu correct data packet header prediction%s\n");
485 
486 	p(tcps_sc_added, "\t%lu syncache entries added\n");
487 	p(tcps_sc_retransmitted, "\t\t%lu retransmitted\n");
488 	p(tcps_sc_dupsyn, "\t\t%lu dupsyn\n");
489 	p(tcps_sc_dropped, "\t\t%lu dropped\n");
490 	p(tcps_sc_completed, "\t\t%lu completed\n");
491 	p(tcps_sc_bucketoverflow, "\t\t%lu bucket overflow\n");
492 	p(tcps_sc_cacheoverflow, "\t\t%lu cache overflow\n");
493 	p(tcps_sc_reset, "\t\t%lu reset\n");
494 	p(tcps_sc_stale, "\t\t%lu stale\n");
495 	p(tcps_sc_aborted, "\t\t%lu aborted\n");
496 	p(tcps_sc_badack, "\t\t%lu badack\n");
497 	p(tcps_sc_unreach, "\t\t%lu unreach\n");
498 	p(tcps_sc_zonefail, "\t\t%lu zone failures\n");
499 	p(tcps_sc_sendcookie, "\t%lu cookies sent\n");
500 	p(tcps_sc_recvcookie, "\t%lu cookies received\n");
501 	free(stattmp);
502 #undef p
503 #undef p1a
504 #undef p2
505 #undef p2a
506 #undef p3
507 }
508 
509 /*
510  * Dump UDP statistics structure.
511  */
512 void
513 udp_stats(u_long off __unused, char *name, int af __unused)
514 {
515 	struct udpstat udpstat, zerostat;
516 	size_t len = sizeof udpstat;
517 	u_long delivered;
518 
519 	if (zflag)
520 		memset(&zerostat, 0, len);
521 	if (sysctlbyname("net.inet.udp.stats", &udpstat, &len,
522 	    zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
523 		warn("sysctl: net.inet.udp.stats");
524 		return;
525 	}
526 
527 #ifdef INET6
528 	if (udp_done != 0)
529 		return;
530 	else
531 		udp_done = 1;
532 #endif
533 
534 	printf("%s:\n", name);
535 #define	p(f, m) if (udpstat.f || sflag <= 1) \
536     printf(m, udpstat.f, plural(udpstat.f))
537 #define	p1a(f, m) if (udpstat.f || sflag <= 1) \
538     printf(m, udpstat.f)
539 	p(udps_ipackets, "\t%lu datagram%s received\n");
540 	p1a(udps_hdrops, "\t%lu with incomplete header\n");
541 	p1a(udps_badlen, "\t%lu with bad data length field\n");
542 	p1a(udps_badsum, "\t%lu with bad checksum\n");
543 	p1a(udps_nosum, "\t%lu with no checksum\n");
544 	p1a(udps_noport, "\t%lu dropped due to no socket\n");
545 	p(udps_noportbcast,
546 	    "\t%lu broadcast/multicast datagram%s dropped due to no socket\n");
547 	p1a(udps_fullsock, "\t%lu dropped due to full socket buffers\n");
548 	p1a(udpps_pcbhashmiss, "\t%lu not for hashed pcb\n");
549 	delivered = udpstat.udps_ipackets -
550 		    udpstat.udps_hdrops -
551 		    udpstat.udps_badlen -
552 		    udpstat.udps_badsum -
553 		    udpstat.udps_noport -
554 		    udpstat.udps_noportbcast -
555 		    udpstat.udps_fullsock;
556 	if (delivered || sflag <= 1)
557 		printf("\t%lu delivered\n", delivered);
558 	p(udps_opackets, "\t%lu datagram%s output\n");
559 #undef p
560 #undef p1a
561 }
562 
563 /*
564  * Dump IP statistics structure.
565  */
566 void
567 ip_stats(u_long off __unused, char *name, int af __unused)
568 {
569 	struct ip_stats ipstat, *stattmp;
570 	struct ip_stats zerostat[SMP_MAXCPU];
571 	size_t len = sizeof(struct ip_stats) * SMP_MAXCPU;
572 	int cpucnt;
573 
574 	if (zflag)
575 		memset(zerostat, 0, len);
576 	if ((stattmp = malloc(len)) == NULL) {
577 		return;
578 	} else {
579 		if (sysctlbyname("net.inet.ip.stats", stattmp, &len,
580 			zflag ? zerostat : NULL, zflag ? len : 0) < 0) {
581 				warn("sysctl: net.inet.ip.stats");
582 				free(stattmp);
583 				return;
584 		} else {
585 			if ((stattmp = realloc(stattmp, len)) == NULL) {
586 				warn("ip_stats");
587 				return;
588 			}
589 		}
590 	}
591 	cpucnt = len / sizeof(struct ip_stats);
592 	ip_stats_agg(stattmp, &ipstat, cpucnt);
593 
594 	printf("%s:\n", name);
595 
596 #define	p(f, m) if (ipstat.f || sflag <= 1) \
597     printf(m, ipstat.f, plural(ipstat.f))
598 #define	p1a(f, m) if (ipstat.f || sflag <= 1) \
599     printf(m, ipstat.f)
600 
601 	p(ips_total, "\t%lu total packet%s received\n");
602 	p(ips_badsum, "\t%lu bad header checksum%s\n");
603 	p1a(ips_toosmall, "\t%lu with size smaller than minimum\n");
604 	p1a(ips_tooshort, "\t%lu with data size < data length\n");
605 	p1a(ips_toolong, "\t%lu with ip length > max ip packet size\n");
606 	p1a(ips_badhlen, "\t%lu with header length < data size\n");
607 	p1a(ips_badlen, "\t%lu with data length < header length\n");
608 	p1a(ips_badoptions, "\t%lu with bad options\n");
609 	p1a(ips_badvers, "\t%lu with incorrect version number\n");
610 	p(ips_fragments, "\t%lu fragment%s received\n");
611 	p(ips_fragdropped, "\t%lu fragment%s dropped (dup or out of space)\n");
612 	p(ips_fragtimeout, "\t%lu fragment%s dropped after timeout\n");
613 	p(ips_reassembled, "\t%lu packet%s reassembled ok\n");
614 	p(ips_delivered, "\t%lu packet%s for this host\n");
615 	p(ips_noproto, "\t%lu packet%s for unknown/unsupported protocol\n");
616 	p(ips_forward, "\t%lu packet%s forwarded");
617 	p(ips_fastforward, " (%lu packet%s fast forwarded)");
618 	if (ipstat.ips_forward || sflag <= 1)
619 		putchar('\n');
620 	p(ips_cantforward, "\t%lu packet%s not forwardable\n");
621 	p(ips_notmember,
622 	  "\t%lu packet%s received for unknown multicast group\n");
623 	p(ips_redirectsent, "\t%lu redirect%s sent\n");
624 	p(ips_localout, "\t%lu packet%s sent from this host\n");
625 	p(ips_rawout, "\t%lu packet%s sent with fabricated ip header\n");
626 	p(ips_odropped,
627 	  "\t%lu output packet%s dropped due to no bufs, etc.\n");
628 	p(ips_noroute, "\t%lu output packet%s discarded due to no route\n");
629 	p(ips_fragmented, "\t%lu output datagram%s fragmented\n");
630 	p(ips_ofragments, "\t%lu fragment%s created\n");
631 	p(ips_cantfrag, "\t%lu datagram%s that can't be fragmented\n");
632 	p(ips_nogif, "\t%lu tunneling packet%s that can't find gif\n");
633 	p(ips_badaddr, "\t%lu datagram%s with bad address in header\n");
634 	free(stattmp);
635 #undef p
636 #undef p1a
637 }
638 
639 static	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, char *name, int af __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 'cuz old message was icmp\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, char *name, int af __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, 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, pimstat.f, plural(pimstat.f))
794 #define	py(f, m) if (pimstat.f || sflag <= 1) \
795     printf(m, pimstat.f, pimstat.f != 1 ? "ies" : "y")
796 	p(pims_rcv_total_msgs, "\t%llu message%s received\n");
797 	p(pims_rcv_total_bytes, "\t%llu byte%s received\n");
798 	p(pims_rcv_tooshort, "\t%llu message%s received with too few bytes\n");
799         p(pims_rcv_badsum, "\t%llu message%s received with bad checksum\n");
800 	p(pims_rcv_badversion, "\t%llu message%s received with bad version\n");
801 	p(pims_rcv_registers_msgs, "\t%llu data register message%s received\n");
802 	p(pims_rcv_registers_bytes, "\t%llu data register byte%s received\n");
803 	p(pims_rcv_registers_wrongiif, "\t%llu data register message%s received on wrong iif\n");
804 	p(pims_rcv_badregisters, "\t%llu bad register%s received\n");
805 	p(pims_snd_registers_msgs, "\t%llu data register message%s sent\n");
806 	p(pims_snd_registers_bytes, "\t%llu 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, char *proto, int numeric_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 && !numeric_port) ? 12 : 16, inetname(in));
825 	cp = index(line, '\0');
826 	if (!numeric_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 	register 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