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