xref: /freebsd/usr.bin/netstat/inet.c (revision 23f282aa31e9b6fceacd449020e936e98d6f2298)
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 %-22.22s\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 			const u_char *vchar;
250 
251 #ifdef INET6
252 			if ((inp->inp_vflag & INP_IPV6) != 0)
253 				vchar = ((inp->inp_vflag & INP_IPV4) != 0)
254 					? "46" : "6 ";
255 			else
256 #endif
257 			vchar = ((inp->inp_vflag & INP_IPV4) != 0)
258 					? "4 " : "  ";
259 
260 			printf("%-3.3s%-2.2s %6ld %6ld  ", name, vchar,
261 			       so->so_rcv.sb_cc,
262 			       so->so_snd.sb_cc);
263 		}
264 		if (nflag) {
265 			if (inp->inp_vflag & INP_IPV4) {
266 				inetprint(&inp->inp_laddr, (int)inp->inp_lport,
267 					  name, 1);
268 				if (!Lflag)
269 					inetprint(&inp->inp_faddr,
270 						  (int)inp->inp_fport, name, 1);
271 			}
272 #ifdef INET6
273 			else if (inp->inp_vflag & INP_IPV6) {
274 				inet6print(&inp->in6p_laddr,
275 					   (int)inp->inp_lport, name, 1);
276 				if (!Lflag)
277 					inet6print(&inp->in6p_faddr,
278 						   (int)inp->inp_fport, name, 1);
279 			} /* else nothing printed now */
280 #endif /* INET6 */
281 		} else if (inp->inp_flags & INP_ANONPORT) {
282 			if (inp->inp_vflag & INP_IPV4) {
283 				inetprint(&inp->inp_laddr, (int)inp->inp_lport,
284 					  name, 1);
285 				if (!Lflag)
286 					inetprint(&inp->inp_faddr,
287 						  (int)inp->inp_fport, name, 0);
288 			}
289 #ifdef INET6
290 			else if (inp->inp_vflag & INP_IPV6) {
291 				inet6print(&inp->in6p_laddr,
292 					   (int)inp->inp_lport, name, 1);
293 				if (!Lflag)
294 					inet6print(&inp->in6p_faddr,
295 						   (int)inp->inp_fport, name, 0);
296 			} /* else nothing printed now */
297 #endif /* INET6 */
298 		} else {
299 			if (inp->inp_vflag & INP_IPV4) {
300 				inetprint(&inp->inp_laddr, (int)inp->inp_lport,
301 					  name, 0);
302 				if (!Lflag)
303 					inetprint(&inp->inp_faddr,
304 						  (int)inp->inp_fport, name,
305 						  inp->inp_lport !=
306 							inp->inp_fport);
307 			}
308 #ifdef INET6
309 			else if (inp->inp_vflag & INP_IPV6) {
310 				inet6print(&inp->in6p_laddr,
311 					   (int)inp->inp_lport, name, 0);
312 				if (!Lflag)
313 					inet6print(&inp->in6p_faddr,
314 						   (int)inp->inp_fport, name,
315 						   inp->inp_lport !=
316 							inp->inp_fport);
317 			} /* else nothing printed now */
318 #endif /* INET6 */
319 		}
320 		if (istcp && !Lflag) {
321 			if (tp->t_state < 0 || tp->t_state >= TCP_NSTATES)
322 				printf("%d", tp->t_state);
323                       else {
324 				printf("%s", tcpstates[tp->t_state]);
325 #if defined(TF_NEEDSYN) && defined(TF_NEEDFIN)
326                               /* Show T/TCP `hidden state' */
327                               if (tp->t_flags & (TF_NEEDSYN|TF_NEEDFIN))
328                                       putchar('*');
329 #endif /* defined(TF_NEEDSYN) && defined(TF_NEEDFIN) */
330                       }
331 		}
332 		putchar('\n');
333 	}
334 	if (xig != oxig && xig->xig_gen != oxig->xig_gen) {
335 		if (oxig->xig_count > xig->xig_count) {
336 			printf("Some %s sockets may have been deleted.\n",
337 			       name);
338 		} else if (oxig->xig_count < xig->xig_count) {
339 			printf("Some %s sockets may have been created.\n",
340 			       name);
341 		} else {
342 			printf("Some %s sockets may have been created or deleted",
343 			       name);
344 		}
345 	}
346 	free(buf);
347 }
348 
349 /*
350  * Dump TCP statistics structure.
351  */
352 void
353 tcp_stats(off, name)
354 	u_long off;
355 	char *name;
356 {
357 	struct tcpstat tcpstat;
358 	size_t len = sizeof tcpstat;
359 
360 	if (sysctlbyname("net.inet.tcp.stats", &tcpstat, &len, 0, 0) < 0) {
361 		warn("sysctl: net.inet.tcp.stats");
362 		return;
363 	}
364 
365 #ifdef INET6
366 	if (tcp_done != 0)
367 		return;
368 	else
369 		tcp_done = 1;
370 #endif
371 
372 	printf ("%s:\n", name);
373 
374 #define	p(f, m) if (tcpstat.f || sflag <= 1) \
375     printf(m, tcpstat.f, plural(tcpstat.f))
376 #define	p1a(f, m) if (tcpstat.f || sflag <= 1) \
377     printf(m, tcpstat.f)
378 #define	p2(f1, f2, m) if (tcpstat.f1 || tcpstat.f2 || sflag <= 1) \
379     printf(m, tcpstat.f1, plural(tcpstat.f1), tcpstat.f2, plural(tcpstat.f2))
380 #define	p2a(f1, f2, m) if (tcpstat.f1 || tcpstat.f2 || sflag <= 1) \
381     printf(m, tcpstat.f1, plural(tcpstat.f1), tcpstat.f2)
382 #define	p3(f, m) if (tcpstat.f || sflag <= 1) \
383     printf(m, tcpstat.f, plurales(tcpstat.f))
384 
385 	p(tcps_sndtotal, "\t%lu packet%s sent\n");
386 	p2(tcps_sndpack,tcps_sndbyte,
387 		"\t\t%lu data packet%s (%lu byte%s)\n");
388 	p2(tcps_sndrexmitpack, tcps_sndrexmitbyte,
389 		"\t\t%lu data packet%s (%lu byte%s) retransmitted\n");
390 	p(tcps_mturesent, "\t\t%lu resend%s initiated by MTU discovery\n");
391 	p2a(tcps_sndacks, tcps_delack,
392 		"\t\t%lu ack-only packet%s (%lu delayed)\n");
393 	p(tcps_sndurg, "\t\t%lu URG only packet%s\n");
394 	p(tcps_sndprobe, "\t\t%lu window probe packet%s\n");
395 	p(tcps_sndwinup, "\t\t%lu window update packet%s\n");
396 	p(tcps_sndctrl, "\t\t%lu control packet%s\n");
397 	p(tcps_rcvtotal, "\t%lu packet%s received\n");
398 	p2(tcps_rcvackpack, tcps_rcvackbyte, "\t\t%lu ack%s (for %lu byte%s)\n");
399 	p(tcps_rcvdupack, "\t\t%lu duplicate ack%s\n");
400 	p(tcps_rcvacktoomuch, "\t\t%lu ack%s for unsent data\n");
401 	p2(tcps_rcvpack, tcps_rcvbyte,
402 		"\t\t%lu packet%s (%lu byte%s) received in-sequence\n");
403 	p2(tcps_rcvduppack, tcps_rcvdupbyte,
404 		"\t\t%lu completely duplicate packet%s (%lu byte%s)\n");
405 	p(tcps_pawsdrop, "\t\t%lu old duplicate packet%s\n");
406 	p2(tcps_rcvpartduppack, tcps_rcvpartdupbyte,
407 		"\t\t%lu packet%s with some dup. data (%lu byte%s duped)\n");
408 	p2(tcps_rcvoopack, tcps_rcvoobyte,
409 		"\t\t%lu out-of-order packet%s (%lu byte%s)\n");
410 	p2(tcps_rcvpackafterwin, tcps_rcvbyteafterwin,
411 		"\t\t%lu packet%s (%lu byte%s) of data after window\n");
412 	p(tcps_rcvwinprobe, "\t\t%lu window probe%s\n");
413 	p(tcps_rcvwinupd, "\t\t%lu window update packet%s\n");
414 	p(tcps_rcvafterclose, "\t\t%lu packet%s received after close\n");
415 	p(tcps_rcvbadsum, "\t\t%lu discarded for bad checksum%s\n");
416 	p(tcps_rcvbadoff, "\t\t%lu discarded for bad header offset field%s\n");
417 	p1a(tcps_rcvshort, "\t\t%lu discarded because packet too short\n");
418 	p(tcps_connattempt, "\t%lu connection request%s\n");
419 	p(tcps_accepts, "\t%lu connection accept%s\n");
420 	p(tcps_badsyn, "\t%lu bad connection attempt%s\n");
421 	p(tcps_listendrop, "\t%lu listen queue overflow%s\n");
422 	p(tcps_connects, "\t%lu connection%s established (including accepts)\n");
423 	p2(tcps_closed, tcps_drops,
424 		"\t%lu connection%s closed (including %lu drop%s)\n");
425 	p(tcps_cachedrtt, "\t\t%lu connection%s updated cached RTT on close\n");
426 	p(tcps_cachedrttvar,
427 	  "\t\t%lu connection%s updated cached RTT variance on close\n");
428 	p(tcps_cachedssthresh,
429 	  "\t\t%lu connection%s updated cached ssthresh on close\n");
430 	p(tcps_conndrops, "\t%lu embryonic connection%s dropped\n");
431 	p2(tcps_rttupdated, tcps_segstimed,
432 		"\t%lu segment%s updated rtt (of %lu attempt%s)\n");
433 	p(tcps_rexmttimeo, "\t%lu retransmit timeout%s\n");
434 	p(tcps_timeoutdrop, "\t\t%lu connection%s dropped by rexmit timeout\n");
435 	p(tcps_persisttimeo, "\t%lu persist timeout%s\n");
436 	p(tcps_persistdrop, "\t\t%lu connection%s dropped by persist timeout\n");
437 	p(tcps_keeptimeo, "\t%lu keepalive timeout%s\n");
438 	p(tcps_keepprobe, "\t\t%lu keepalive probe%s sent\n");
439 	p(tcps_keepdrops, "\t\t%lu connection%s dropped by keepalive\n");
440 	p(tcps_predack, "\t%lu correct ACK header prediction%s\n");
441 	p(tcps_preddat, "\t%lu correct data packet header prediction%s\n");
442 #undef p
443 #undef p1a
444 #undef p2
445 #undef p2a
446 #undef p3
447 }
448 
449 /*
450  * Dump UDP statistics structure.
451  */
452 void
453 udp_stats(off, name)
454 	u_long off;
455 	char *name;
456 {
457 	struct udpstat udpstat;
458 	size_t len = sizeof udpstat;
459 	u_long delivered;
460 
461 	if (sysctlbyname("net.inet.udp.stats", &udpstat, &len, 0, 0) < 0) {
462 		warn("sysctl: net.inet.udp.stats");
463 		return;
464 	}
465 
466 #ifdef INET6
467 	if (udp_done != 0)
468 		return;
469 	else
470 		udp_done = 1;
471 #endif
472 
473 	printf("%s:\n", name);
474 #define	p(f, m) if (udpstat.f || sflag <= 1) \
475     printf(m, udpstat.f, plural(udpstat.f))
476 #define	p1a(f, m) if (udpstat.f || sflag <= 1) \
477     printf(m, udpstat.f)
478 	p(udps_ipackets, "\t%lu datagram%s received\n");
479 	p1a(udps_hdrops, "\t%lu with incomplete header\n");
480 	p1a(udps_badlen, "\t%lu with bad data length field\n");
481 	p1a(udps_badsum, "\t%lu with bad checksum\n");
482 	p1a(udps_noport, "\t%lu dropped due to no socket\n");
483 	p(udps_noportbcast,
484 	    "\t%lu broadcast/multicast datagram%s dropped due to no socket\n");
485 	p1a(udps_fullsock, "\t%lu dropped due to full socket buffers\n");
486 	p1a(udpps_pcbhashmiss, "\t%lu not for hashed pcb\n");
487 	delivered = udpstat.udps_ipackets -
488 		    udpstat.udps_hdrops -
489 		    udpstat.udps_badlen -
490 		    udpstat.udps_badsum -
491 		    udpstat.udps_noport -
492 		    udpstat.udps_noportbcast -
493 		    udpstat.udps_fullsock;
494 	if (delivered || sflag <= 1)
495 		printf("\t%lu delivered\n", delivered);
496 	p(udps_opackets, "\t%lu datagram%s output\n");
497 #undef p
498 #undef p1a
499 }
500 
501 /*
502  * Dump IP statistics structure.
503  */
504 void
505 ip_stats(off, name)
506 	u_long off;
507 	char *name;
508 {
509 	struct ipstat ipstat;
510 	size_t len = sizeof ipstat;
511 
512 	if (sysctlbyname("net.inet.ip.stats", &ipstat, &len, 0, 0) < 0) {
513 		warn("sysctl: net.inet.ip.stats");
514 		return;
515 	}
516 
517 	printf("%s:\n", name);
518 
519 #define	p(f, m) if (ipstat.f || sflag <= 1) \
520     printf(m, ipstat.f, plural(ipstat.f))
521 #define	p1a(f, m) if (ipstat.f || sflag <= 1) \
522     printf(m, ipstat.f)
523 
524 	p(ips_total, "\t%lu total packet%s received\n");
525 	p(ips_badsum, "\t%lu bad header checksum%s\n");
526 	p1a(ips_toosmall, "\t%lu with size smaller than minimum\n");
527 	p1a(ips_tooshort, "\t%lu with data size < data length\n");
528 	p1a(ips_toolong, "\t%lu with ip length > max ip packet size\n");
529 	p1a(ips_badhlen, "\t%lu with header length < data size\n");
530 	p1a(ips_badlen, "\t%lu with data length < header length\n");
531 	p1a(ips_badoptions, "\t%lu with bad options\n");
532 	p1a(ips_badvers, "\t%lu with incorrect version number\n");
533 	p(ips_fragments, "\t%lu fragment%s received\n");
534 	p(ips_fragdropped, "\t%lu fragment%s dropped (dup or out of space)\n");
535 	p(ips_fragtimeout, "\t%lu fragment%s dropped after timeout\n");
536 	p(ips_reassembled, "\t%lu packet%s reassembled ok\n");
537 	p(ips_delivered, "\t%lu packet%s for this host\n");
538 	p(ips_noproto, "\t%lu packet%s for unknown/unsupported protocol\n");
539 	p(ips_forward, "\t%lu packet%s forwarded");
540 	p(ips_fastforward, " (%lu packet%s fast forwarded)");
541 	if (ipstat.ips_forward || sflag <= 1)
542 		putchar('\n');
543 	p(ips_cantforward, "\t%lu packet%s not forwardable\n");
544 	p(ips_notmember,
545 	  "\t%lu packet%s received for unknown multicast group\n");
546 	p(ips_redirectsent, "\t%lu redirect%s sent\n");
547 	p(ips_localout, "\t%lu packet%s sent from this host\n");
548 	p(ips_rawout, "\t%lu packet%s sent with fabricated ip header\n");
549 	p(ips_odropped,
550 	  "\t%lu output packet%s dropped due to no bufs, etc.\n");
551 	p(ips_noroute, "\t%lu output packet%s discarded due to no route\n");
552 	p(ips_fragmented, "\t%lu output datagram%s fragmented\n");
553 	p(ips_ofragments, "\t%lu fragment%s created\n");
554 	p(ips_cantfrag, "\t%lu datagram%s that can't be fragmented\n");
555 	p(ips_nogif, "\t%lu tunneling packet%s that can't find gif\n");
556 #undef p
557 #undef p1a
558 }
559 
560 static	char *icmpnames[] = {
561 	"echo reply",
562 	"#1",
563 	"#2",
564 	"destination unreachable",
565 	"source quench",
566 	"routing redirect",
567 	"#6",
568 	"#7",
569 	"echo",
570 	"router advertisement",
571 	"router solicitation",
572 	"time exceeded",
573 	"parameter problem",
574 	"time stamp",
575 	"time stamp reply",
576 	"information request",
577 	"information request reply",
578 	"address mask request",
579 	"address mask reply",
580 };
581 
582 /*
583  * Dump ICMP statistics.
584  */
585 void
586 icmp_stats(off, name)
587 	u_long off;
588 	char *name;
589 {
590 	struct icmpstat icmpstat;
591 	int i, first;
592 	int mib[4];		/* CTL_NET + PF_INET + IPPROTO_ICMP + req */
593 	size_t len;
594 
595 	mib[0] = CTL_NET;
596 	mib[1] = PF_INET;
597 	mib[2] = IPPROTO_ICMP;
598 	mib[3] = ICMPCTL_STATS;
599 
600 	len = sizeof icmpstat;
601 	memset(&icmpstat, 0, len);
602 	if (sysctl(mib, 4, &icmpstat, &len, (void *)0, 0) < 0)
603 		return;		/* XXX should complain, but not traditional */
604 
605 	printf("%s:\n", name);
606 
607 #define	p(f, m) if (icmpstat.f || sflag <= 1) \
608     printf(m, icmpstat.f, plural(icmpstat.f))
609 #define	p1a(f, m) if (icmpstat.f || sflag <= 1) \
610     printf(m, icmpstat.f)
611 
612 	p(icps_error, "\t%lu call%s to icmp_error\n");
613 	p(icps_oldicmp,
614 	    "\t%lu error%s not generated 'cuz old message was icmp\n");
615 	for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
616 		if (icmpstat.icps_outhist[i] != 0) {
617 			if (first) {
618 				printf("\tOutput histogram:\n");
619 				first = 0;
620 			}
621 			printf("\t\t%s: %lu\n", icmpnames[i],
622 				icmpstat.icps_outhist[i]);
623 		}
624 	p(icps_badcode, "\t%lu message%s with bad code fields\n");
625 	p(icps_tooshort, "\t%lu message%s < minimum length\n");
626 	p(icps_checksum, "\t%lu bad checksum%s\n");
627 	p(icps_badlen, "\t%lu message%s with bad length\n");
628 	p1a(icps_bmcastecho, "\t%lu multicast echo requests ignored\n");
629 	p1a(icps_bmcasttstamp, "\t%lu multicast timestamp requests ignored\n");
630 	for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
631 		if (icmpstat.icps_inhist[i] != 0) {
632 			if (first) {
633 				printf("\tInput histogram:\n");
634 				first = 0;
635 			}
636 			printf("\t\t%s: %lu\n", icmpnames[i],
637 				icmpstat.icps_inhist[i]);
638 		}
639 	p(icps_reflect, "\t%lu message response%s generated\n");
640 #undef p
641 #undef p1a
642 	mib[3] = ICMPCTL_MASKREPL;
643 	len = sizeof i;
644 	if (sysctl(mib, 4, &i, &len, (void *)0, 0) < 0)
645 		return;
646 	printf("\tICMP address mask responses are %sabled\n",
647 	       i ? "en" : "dis");
648 }
649 
650 /*
651  * Dump IGMP statistics structure.
652  */
653 void
654 igmp_stats(off, name)
655 	u_long off;
656 	char *name;
657 {
658 	struct igmpstat igmpstat;
659 	size_t len = sizeof igmpstat;
660 
661 	if (sysctlbyname("net.inet.igmp.stats", &igmpstat, &len, 0, 0) < 0) {
662 		warn("sysctl: net.inet.igmp.stats");
663 		return;
664 	}
665 
666 	printf("%s:\n", name);
667 
668 #define	p(f, m) if (igmpstat.f || sflag <= 1) \
669     printf(m, igmpstat.f, plural(igmpstat.f))
670 #define	py(f, m) if (igmpstat.f || sflag <= 1) \
671     printf(m, igmpstat.f, igmpstat.f != 1 ? "ies" : "y")
672 	p(igps_rcv_total, "\t%u message%s received\n");
673         p(igps_rcv_tooshort, "\t%u message%s received with too few bytes\n");
674         p(igps_rcv_badsum, "\t%u message%s received with bad checksum\n");
675         py(igps_rcv_queries, "\t%u membership quer%s received\n");
676         py(igps_rcv_badqueries, "\t%u membership quer%s received with invalid field(s)\n");
677         p(igps_rcv_reports, "\t%u membership report%s received\n");
678         p(igps_rcv_badreports, "\t%u membership report%s received with invalid field(s)\n");
679         p(igps_rcv_ourreports, "\t%u membership report%s received for groups to which we belong\n");
680         p(igps_snd_reports, "\t%u membership report%s sent\n");
681 #undef p
682 #undef py
683 }
684 
685 #ifdef IPSEC
686 static	char *ipsec_ahnames[] = {
687 	"none",
688 	"hmac MD5",
689 	"hmac SHA1",
690 	"keyed MD5",
691 	"keyed SHA1",
692 	"null",
693 };
694 
695 static	char *ipsec_espnames[] = {
696 	"none",
697 	"DES CBC",
698 	"3DES CBC",
699 	"simple",
700 	"blowfish CBC",
701 	"CAST128 CBC",
702 	"RC5 CBC",
703 };
704 
705 /*
706  * Dump IPSEC statistics structure.
707  */
708 void
709 ipsec_stats(off, name)
710 	u_long off;
711 	char *name;
712 {
713 	struct ipsecstat ipsecstat;
714 	int first, proto;
715 
716 	if (off == 0)
717 		return;
718 	printf ("%s:\n", name);
719 	kread(off, (char *)&ipsecstat, sizeof (ipsecstat));
720 
721 #define	p(f, m) if (ipsecstat.f || sflag <= 1) \
722     printf(m, ipsecstat.f, plural(ipsecstat.f))
723 
724 	p(in_success, "\t%lu inbound packet%s processed successfully\n");
725 	p(in_polvio, "\t%lu inbound packet%s violated process security "
726 		"policy\n");
727 	p(in_nosa, "\t%lu inbound packet%s with no SA available\n");
728 	p(in_inval, "\t%lu inbound packet%s failed processing due to EINVAL\n");
729 	p(in_badspi, "\t%lu inbound packet%s failed getting SPI\n");
730 	p(in_ahreplay, "\t%lu inbound packet%s failed on AH replay check\n");
731 	p(in_espreplay, "\t%lu inbound packet%s failed on ESP replay check\n");
732 	p(in_ahauthsucc, "\t%lu inbound AH packet%s considered authentic\n");
733 	p(in_ahauthfail, "\t%lu inbound AH packet%s failed on authentication\n");
734 	p(in_espauthsucc, "\t%lu inbound ESP packet%s considered authentic\n");
735 	p(in_espauthfail, "\t%lu inbound ESP packet%s failed on authentication\n");
736 	for (first = 1, proto = 0; proto < SADB_AALG_MAX; proto++) {
737 		if (ipsecstat.in_ahhist[proto] <= 0)
738 			continue;
739 		if (first) {
740 			printf("\tAH input histogram:\n");
741 			first = 0;
742 		}
743 		printf("\t\t%s: %lu\n", ipsec_ahnames[proto],
744 			ipsecstat.in_ahhist[proto]);
745 	}
746 	for (first = 1, proto = 0; proto < SADB_EALG_MAX; proto++) {
747 		if (ipsecstat.in_esphist[proto] <= 0)
748 			continue;
749 		if (first) {
750 			printf("\tESP input histogram:\n");
751 		first = 0;
752 		}
753 		printf("\t\t%s: %lu\n", ipsec_espnames[proto],
754 			ipsecstat.in_esphist[proto]);
755 	}
756 
757 	p(out_success, "\t%lu outbound packet%s processed successfully\n");
758 	p(out_polvio, "\t%lu outbound packet%s violated process security "
759 		"policy\n");
760 	p(out_nosa, "\t%lu outbound packet%s with no SA available\n");
761 	p(out_inval, "\t%lu outbound packet%s failed processing due to "
762 		"EINVAL\n");
763 	p(out_noroute, "\t%lu outbound packet%s with no route\n");
764 	for (first = 1, proto = 0; proto < SADB_AALG_MAX; proto++) {
765 		if (ipsecstat.out_ahhist[proto] <= 0)
766 			continue;
767 		if (first) {
768 			printf("\tAH output histogram:\n");
769 			first = 0;
770 		}
771 		printf("\t\t%s: %lu\n", ipsec_ahnames[proto],
772 			ipsecstat.out_ahhist[proto]);
773 	}
774 	for (first = 1, proto = 0; proto < SADB_EALG_MAX; proto++) {
775 		if (ipsecstat.out_esphist[proto] <= 0)
776 			continue;
777 		if (first) {
778 			printf("\tESP output histogram:\n");
779 			first = 0;
780 		}
781 		printf("\t\t%s: %lu\n", ipsec_espnames[proto],
782 			ipsecstat.out_esphist[proto]);
783 	}
784 #undef p
785 }
786 #endif /*IPSEC*/
787 
788 /*
789  * Pretty print an Internet address (net address + port).
790  */
791 void
792 inetprint(in, port, proto,numeric)
793 	register struct in_addr *in;
794 	int port;
795 	char *proto;
796 	int numeric;
797 {
798 	struct servent *sp = 0;
799 	char line[80], *cp;
800 	int width;
801 
802 	sprintf(line, "%.*s.", (Aflag && !numeric) ? 12 : 16, inetname(in));
803 	cp = index(line, '\0');
804 	if (!numeric && port)
805 		sp = getservbyport((int)port, proto);
806 	if (sp || port == 0)
807 		sprintf(cp, "%.15s", sp ? sp->s_name : "*");
808 	else
809 		sprintf(cp, "%d", ntohs((u_short)port));
810 	width = Aflag ? 18 : 22;
811 	printf("%-*.*s ", width, width, line);
812 }
813 
814 /*
815  * Construct an Internet address representation.
816  * If the nflag has been supplied, give
817  * numeric value, otherwise try for symbolic name.
818  */
819 char *
820 inetname(inp)
821 	struct in_addr *inp;
822 {
823 	register char *cp;
824 	static char line[MAXHOSTNAMELEN + 1];
825 	struct hostent *hp;
826 	struct netent *np;
827 
828 	cp = 0;
829 	if (!nflag && inp->s_addr != INADDR_ANY) {
830 		int net = inet_netof(*inp);
831 		int lna = inet_lnaof(*inp);
832 
833 		if (lna == INADDR_ANY) {
834 			np = getnetbyaddr(net, AF_INET);
835 			if (np)
836 				cp = np->n_name;
837 		}
838 		if (cp == 0) {
839 			hp = gethostbyaddr((char *)inp, sizeof (*inp), AF_INET);
840 			if (hp) {
841 				cp = hp->h_name;
842 				trimdomain(cp);
843 			}
844 		}
845 	}
846 	if (inp->s_addr == INADDR_ANY)
847 		strcpy(line, "*");
848 	else if (cp) {
849 		strncpy(line, cp, sizeof(line) - 1);
850 		line[sizeof(line) - 1] = '\0';
851 	} else {
852 		inp->s_addr = ntohl(inp->s_addr);
853 #define C(x)	((u_int)((x) & 0xff))
854 		sprintf(line, "%u.%u.%u.%u", C(inp->s_addr >> 24),
855 		    C(inp->s_addr >> 16), C(inp->s_addr >> 8), C(inp->s_addr));
856 	}
857 	return (line);
858 }
859