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