xref: /openbsd-src/usr.bin/netstat/inet.c (revision 47911bd667ac77dc523b8a13ef40b012dbffa741)
1 /*	$OpenBSD: inet.c,v 1.62 2002/06/09 04:07:10 jsyn Exp $	*/
2 /*	$NetBSD: inet.c,v 1.14 1995/10/03 21:42:37 thorpej Exp $	*/
3 
4 /*
5  * Copyright (c) 1983, 1988, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by the University of
19  *	California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36 
37 #ifndef lint
38 #if 0
39 static char sccsid[] = "from: @(#)inet.c	8.4 (Berkeley) 4/20/94";
40 #else
41 static char *rcsid = "$OpenBSD: inet.c,v 1.62 2002/06/09 04:07:10 jsyn Exp $";
42 #endif
43 #endif /* not lint */
44 
45 #include <sys/param.h>
46 #include <sys/queue.h>
47 #include <sys/socket.h>
48 #include <sys/socketvar.h>
49 #include <sys/mbuf.h>
50 #include <sys/protosw.h>
51 
52 #include <net/route.h>
53 #include <netinet/in.h>
54 #include <netinet/in_systm.h>
55 #include <netinet/ip.h>
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 #include <netinet/ip_ipsp.h>
72 #include <netinet/ip_ah.h>
73 #include <netinet/ip_esp.h>
74 #include <netinet/ip_ipip.h>
75 #include <netinet/ip_ipcomp.h>
76 #include <netinet/ip_ether.h>
77 
78 #include <arpa/inet.h>
79 #include <limits.h>
80 #include <netdb.h>
81 #include <stdio.h>
82 #include <string.h>
83 #include <unistd.h>
84 #include <stdlib.h>
85 #include "netstat.h"
86 
87 #include <rpc/rpc.h>
88 #include <rpc/pmap_prot.h>
89 #include <rpc/pmap_clnt.h>
90 
91 struct	inpcb inpcb;
92 struct	tcpcb tcpcb;
93 struct	socket sockb;
94 
95 static void protopr0(u_long, char *, int);
96 
97 char	*inetname(struct in_addr *);
98 void	inetprint(struct in_addr *, int, char *, int);
99 #ifdef INET6
100 char	*inet6name(struct in6_addr *);
101 void	inet6print(struct in6_addr *, int, char *, int);
102 #endif
103 
104 /*
105  * Print a summary of connections related to an Internet
106  * protocol.  For TCP, also give state of connection.
107  * Listening processes (aflag) are suppressed unless the
108  * -a (all) flag is specified.
109  */
110 void
111 protopr(off, name)
112 	u_long off;
113 	char *name;
114 {
115 	protopr0(off, name, AF_INET);
116 }
117 
118 #ifdef INET6
119 void
120 ip6protopr(off, name)
121 	u_long off;
122 	char *name;
123 {
124 	protopr0(off, name, AF_INET6);
125 }
126 #endif
127 
128 static void
129 protopr0(off, name, af)
130 	u_long off;
131 	char *name;
132 	int af;
133 {
134 	struct inpcbtable table;
135 	struct inpcb *head, *next, *prev;
136 	struct inpcb inpcb;
137 	int istcp;
138 	int first = 1;
139 	char *name0;
140 	char namebuf[20];
141 
142 	name0 = name;
143 	if (off == 0)
144 		return;
145 	istcp = strcmp(name, "tcp") == 0;
146 	kread(off, (char *)&table, sizeof table);
147 	prev = head =
148 	    (struct inpcb *)&((struct inpcbtable *)off)->inpt_queue.cqh_first;
149 	next = table.inpt_queue.cqh_first;
150 
151 	while (next != head) {
152 		kread((u_long)next, (char *)&inpcb, sizeof inpcb);
153 		if (inpcb.inp_queue.cqe_prev != prev) {
154 			printf("???\n");
155 			break;
156 		}
157 		prev = next;
158 		next = inpcb.inp_queue.cqe_next;
159 
160 		switch (af) {
161 		case AF_INET:
162 			if ((inpcb.inp_flags & INP_IPV6) != 0)
163 				continue;
164 			break;
165 		case AF_INET6:
166 			if ((inpcb.inp_flags & INP_IPV6) == 0)
167 				continue;
168 			break;
169 		default:
170 			break;
171 		}
172 
173 		if (!aflag &&
174 		    inet_lnaof(inpcb.inp_laddr) == INADDR_ANY)
175 			continue;
176 		kread((u_long)inpcb.inp_socket, (char *)&sockb, sizeof (sockb));
177 		if (istcp) {
178 			kread((u_long)inpcb.inp_ppcb,
179 			    (char *)&tcpcb, sizeof (tcpcb));
180 		}
181 		if (first) {
182 			printf("Active Internet connections");
183 			if (aflag)
184 				printf(" (including servers)");
185 			putchar('\n');
186 			if (Aflag)
187 				printf("%-*.*s %-5.5s %-6.6s %-6.6s  %-18.18s %-18.18s %s\n",
188 				    PLEN, PLEN, "PCB", "Proto", "Recv-Q",
189 				    "Send-Q", "Local Address",
190 				    "Foreign Address", "(state)");
191 			else
192 				printf("%-5.5s %-6.6s %-6.6s  %-22.22s %-22.22s %s\n",
193 				    "Proto", "Recv-Q", "Send-Q",
194 				    "Local Address", "Foreign Address",
195 				    "(state)");
196 			first = 0;
197 		}
198 		if (Aflag) {
199 			if (istcp)
200 				printf("%*p ", PLEN, inpcb.inp_ppcb);
201 			else
202 				printf("%*p ", PLEN, prev);
203 		}
204 #ifdef INET6
205 		if (inpcb.inp_flags & INP_IPV6) {
206 			strlcpy(namebuf, name0, sizeof namebuf);
207 			strlcat(namebuf, "6", sizeof namebuf);
208 			name = namebuf;
209 		} else
210 			name = name0;
211 #endif
212 		printf("%-5.5s %6ld %6ld ", name, sockb.so_rcv.sb_cc,
213 			sockb.so_snd.sb_cc);
214 #ifdef INET6
215 		if (inpcb.inp_flags & INP_IPV6) {
216 			inet6print(&inpcb.inp_laddr6, (int)inpcb.inp_lport,
217 				name, 1);
218 			inet6print(&inpcb.inp_faddr6, (int)inpcb.inp_fport,
219 				name, 0);
220 		} else
221 #endif
222 		{
223 			inetprint(&inpcb.inp_laddr, (int)inpcb.inp_lport,
224 				name, 1);
225 			inetprint(&inpcb.inp_faddr, (int)inpcb.inp_fport,
226 				name, 0);
227 		}
228 		if (istcp) {
229 			if (tcpcb.t_state < 0 || tcpcb.t_state >= TCP_NSTATES)
230 				printf(" %d", tcpcb.t_state);
231 			else
232 				printf(" %s", tcpstates[tcpcb.t_state]);
233 		}
234 		putchar('\n');
235 	}
236 }
237 
238 /*
239  * Dump TCP statistics structure.
240  */
241 void
242 tcp_stats(off, name)
243 	u_long off;
244 	char *name;
245 {
246 	struct tcpstat tcpstat;
247 
248 	if (off == 0)
249 		return;
250 	printf ("%s:\n", name);
251 	kread(off, (char *)&tcpstat, sizeof (tcpstat));
252 
253 #define	p(f, m) if (tcpstat.f || sflag <= 1) \
254 	printf(m, tcpstat.f, plural(tcpstat.f))
255 #define	p1(f, m) if (tcpstat.f || sflag <= 1) \
256 	printf(m, tcpstat.f)
257 #define	p2(f1, f2, m) if (tcpstat.f1 || tcpstat.f2 || sflag <= 1) \
258 	printf(m, tcpstat.f1, plural(tcpstat.f1), tcpstat.f2, plural(tcpstat.f2))
259 #define	p2a(f1, f2, m) if (tcpstat.f1 || tcpstat.f2 || sflag <= 1) \
260 	printf(m, tcpstat.f1, plural(tcpstat.f1), tcpstat.f2)
261 #define	p3(f, m) if (tcpstat.f || sflag <= 1) \
262 	printf(m, tcpstat.f, plurales(tcpstat.f))
263 
264 	p(tcps_sndtotal, "\t%u packet%s sent\n");
265 	p2(tcps_sndpack,tcps_sndbyte,
266 	    "\t\t%u data packet%s (%qd byte%s)\n");
267 	p2(tcps_sndrexmitpack, tcps_sndrexmitbyte,
268 	    "\t\t%u data packet%s (%qd byte%s) retransmitted\n");
269 	p(tcps_sndrexmitfast, "\t\t%qd fast retransmitted packet%s\n");
270 	p2a(tcps_sndacks, tcps_delack,
271 	    "\t\t%u ack-only packet%s (%u delayed)\n");
272 	p(tcps_sndurg, "\t\t%u URG only packet%s\n");
273 	p(tcps_sndprobe, "\t\t%u window probe packet%s\n");
274 	p(tcps_sndwinup, "\t\t%u window update packet%s\n");
275 	p(tcps_sndctrl, "\t\t%u control packet%s\n");
276 	p(tcps_outhwcsum, "\t\t%u packet%s hardware-checksummed\n");
277 	p(tcps_rcvtotal, "\t%u packet%s received\n");
278 	p2(tcps_rcvackpack, tcps_rcvackbyte, "\t\t%u ack%s (for %qd byte%s)\n");
279 	p(tcps_rcvdupack, "\t\t%u duplicate ack%s\n");
280 	p(tcps_rcvacktoomuch, "\t\t%u ack%s for unsent data\n");
281 	p2(tcps_rcvpack, tcps_rcvbyte,
282 	    "\t\t%u packet%s (%qu byte%s) received in-sequence\n");
283 	p2(tcps_rcvduppack, tcps_rcvdupbyte,
284 	    "\t\t%u completely duplicate packet%s (%qd byte%s)\n");
285 	p(tcps_pawsdrop, "\t\t%u old duplicate packet%s\n");
286 	p2(tcps_rcvpartduppack, tcps_rcvpartdupbyte,
287 	    "\t\t%u packet%s with some duplicate data (%qd byte%s duplicated)\n");
288 	p2(tcps_rcvoopack, tcps_rcvoobyte,
289 	    "\t\t%u out-of-order packet%s (%qd byte%s)\n");
290 	p2(tcps_rcvpackafterwin, tcps_rcvbyteafterwin,
291 	    "\t\t%u packet%s (%qd byte%s) of data after window\n");
292 	p(tcps_rcvwinprobe, "\t\t%u window probe%s\n");
293 	p(tcps_rcvwinupd, "\t\t%u window update packet%s\n");
294 	p(tcps_rcvafterclose, "\t\t%u packet%s received after close\n");
295 	p(tcps_rcvbadsum, "\t\t%u discarded for bad checksum%s\n");
296 	p(tcps_rcvbadoff, "\t\t%u discarded for bad header offset field%s\n");
297 	p1(tcps_rcvshort, "\t\t%u discarded because packet too short\n");
298 	p1(tcps_rcvnosec, "\t\t%u discarded for missing IPsec protection\n");
299 	p(tcps_inhwcsum, "\t\t%u packet%s hardware-checksummed\n");
300 	p(tcps_connattempt, "\t%u connection request%s\n");
301 	p(tcps_accepts, "\t%u connection accept%s\n");
302 	p(tcps_connects, "\t%u connection%s established (including accepts)\n");
303 	p2(tcps_closed, tcps_drops,
304 	    "\t%u connection%s closed (including %u drop%s)\n");
305 	p(tcps_conndrops, "\t%u embryonic connection%s dropped\n");
306 	p2(tcps_rttupdated, tcps_segstimed,
307 	    "\t%u segment%s updated rtt (of %u attempt%s)\n");
308 	p(tcps_rexmttimeo, "\t%u retransmit timeout%s\n");
309 	p(tcps_timeoutdrop, "\t\t%u connection%s dropped by rexmit timeout\n");
310 	p(tcps_persisttimeo, "\t%u persist timeout%s\n");
311 	p(tcps_keeptimeo, "\t%u keepalive timeout%s\n");
312 	p(tcps_keepprobe, "\t\t%u keepalive probe%s sent\n");
313 	p(tcps_keepdrops, "\t\t%u connection%s dropped by keepalive\n");
314 	p(tcps_predack, "\t%u correct ACK header prediction%s\n");
315 	p(tcps_preddat, "\t%u correct data packet header prediction%s\n");
316 	p3(tcps_pcbhashmiss, "\t%u PCB cache miss%s\n");
317 	p(tcps_badsyn, "\t%u SYN packet%s received with same src/dst address/port\n");
318 
319 	p(tcps_ecn_accepts, "\t%u ECN connection%s accepted\n");
320 	p(tcps_ecn_rcvece, "\t\t%u ECE packet%s received\n");
321 	p(tcps_ecn_rcvcwr, "\t\t%u CWR packet%s received\n");
322 	p(tcps_ecn_rcvce, "\t\t%u CE packet%s received\n");
323 	p(tcps_ecn_sndect, "\t\t%u ECT packet%s sent\n");
324 	p(tcps_ecn_sndece, "\t\t%u ECE packet%s sent\n");
325 	p(tcps_ecn_sndcwr, "\t\t%u CWR packet%s sent\n");
326 	p1(tcps_cwr_frecovery, "\t\t\tcwr by fastrecovery: %u\n");
327 	p1(tcps_cwr_timeout, "\t\t\tcwr by timeout: %u\n");
328 	p1(tcps_cwr_ecn, "\t\t\tcwr by ecn: %u\n");
329 
330 #undef p
331 #undef p1
332 #undef p2
333 #undef p2a
334 #undef p3
335 }
336 
337 /*
338  * Dump UDP statistics structure.
339  */
340 void
341 udp_stats(off, name)
342 	u_long off;
343 	char *name;
344 {
345 	struct udpstat udpstat;
346 	u_long delivered;
347 
348 	if (off == 0)
349 		return;
350 	kread(off, (char *)&udpstat, sizeof (udpstat));
351 	printf("%s:\n", name);
352 #define	p(f, m) if (udpstat.f || sflag <= 1) \
353 	printf(m, udpstat.f, plural(udpstat.f))
354 #define	p1(f, m) if (udpstat.f || sflag <= 1) \
355 	printf(m, udpstat.f)
356 
357 	p(udps_ipackets, "\t%lu datagram%s received\n");
358 	p1(udps_hdrops, "\t%lu with incomplete header\n");
359 	p1(udps_badlen, "\t%lu with bad data length field\n");
360 	p1(udps_badsum, "\t%lu with bad checksum\n");
361 	p1(udps_nosum, "\t%lu with no checksum\n");
362 	p(udps_inhwcsum, "\t%lu input packet%s hardware-checksummed\n");
363 	p(udps_outhwcsum, "\t%lu output packet%s hardware-checksummed\n");
364 	p1(udps_noport, "\t%lu dropped due to no socket\n");
365 	p(udps_noportbcast, "\t%lu broadcast/multicast datagram%s dropped due to no socket\n");
366 	p1(udps_nosec, "\t%lu dropped due to missing IPsec protection\n");
367 	p1(udps_fullsock, "\t%lu dropped due to full socket buffers\n");
368 	delivered = udpstat.udps_ipackets - udpstat.udps_hdrops -
369 	    udpstat.udps_badlen - udpstat.udps_badsum -
370 	    udpstat.udps_noport - udpstat.udps_noportbcast -
371 	    udpstat.udps_fullsock;
372 	if (delivered || sflag <= 1)
373 		printf("\t%lu delivered\n", delivered);
374 	p(udps_opackets, "\t%lu datagram%s output\n");
375 	p1(udps_pcbhashmiss, "\t%lu missed PCB cache\n");
376 #undef p
377 #undef p1
378 }
379 
380 /*
381  * Dump IP statistics structure.
382  */
383 void
384 ip_stats(off, name)
385 	u_long off;
386 	char *name;
387 {
388 	struct ipstat ipstat;
389 
390 	if (off == 0)
391 		return;
392 	kread(off, (char *)&ipstat, sizeof (ipstat));
393 	printf("%s:\n", name);
394 
395 #define	p(f, m) if (ipstat.f || sflag <= 1) \
396 	printf(m, ipstat.f, plural(ipstat.f))
397 #define	p1(f, m) if (ipstat.f || sflag <= 1) \
398 	printf(m, ipstat.f)
399 
400 	p(ips_total, "\t%lu total packet%s received\n");
401 	p(ips_badsum, "\t%lu bad header checksum%s\n");
402 	p1(ips_toosmall, "\t%lu with size smaller than minimum\n");
403 	p1(ips_tooshort, "\t%lu with data size < data length\n");
404 	p1(ips_badhlen, "\t%lu with header length < data size\n");
405 	p1(ips_badlen, "\t%lu with data length < header length\n");
406 	p1(ips_badoptions, "\t%lu with bad options\n");
407 	p1(ips_badvers, "\t%lu with incorrect version number\n");
408 	p(ips_fragments, "\t%lu fragment%s received\n");
409 	p(ips_fragdropped, "\t%lu fragment%s dropped (duplicates or out of space)\n");
410 	p(ips_badfrags, "\t%lu malformed fragment%s dropped\n");
411 	p(ips_fragtimeout, "\t%lu fragment%s dropped after timeout\n");
412 	p(ips_reassembled, "\t%lu packet%s reassembled ok\n");
413 	p(ips_delivered, "\t%lu packet%s for this host\n");
414 	p(ips_noproto, "\t%lu packet%s for unknown/unsupported protocol\n");
415 	p(ips_forward, "\t%lu packet%s forwarded\n");
416 	p(ips_cantforward, "\t%lu packet%s not forwardable\n");
417 	p(ips_redirectsent, "\t%lu redirect%s sent\n");
418 	p(ips_localout, "\t%lu packet%s sent from this host\n");
419 	p(ips_rawout, "\t%lu packet%s sent with fabricated ip header\n");
420 	p(ips_odropped, "\t%lu output packet%s dropped due to no bufs, etc.\n");
421 	p(ips_noroute, "\t%lu output packet%s discarded due to no route\n");
422 	p(ips_fragmented, "\t%lu output datagram%s fragmented\n");
423 	p(ips_ofragments, "\t%lu fragment%s created\n");
424 	p(ips_cantfrag, "\t%lu datagram%s that can't be fragmented\n");
425 	p1(ips_rcvmemdrop, "\t%lu fragment floods\n");
426 	p(ips_toolong, "\t%lu packet%s with ip length > max ip packet size\n");
427 	p(ips_nogif, "\t%lu tunneling packet%s that can't find gif\n");
428 	p(ips_badaddr, "\t%lu datagram%s with bad address in header\n");
429 	p(ips_inhwcsum, "\t%lu input datagram%s checksum-processed by hardware\n");
430 	p(ips_outhwcsum, "\t%lu output datagram%s checksum-processed by hardware\n");
431 #undef p
432 #undef p1
433 }
434 
435 static	char *icmpnames[] = {
436 	"echo reply",
437 	"#1",
438 	"#2",
439 	"destination unreachable",
440 	"source quench",
441 	"routing redirect",
442 	"#6",
443 	"#7",
444 	"echo",
445 	"router advertisement",
446 	"router solicitation",
447 	"time exceeded",
448 	"parameter problem",
449 	"time stamp",
450 	"time stamp reply",
451 	"information request",
452 	"information request reply",
453 	"address mask request",
454 	"address mask reply",
455 };
456 
457 /*
458  * Dump ICMP statistics.
459  */
460 void
461 icmp_stats(off, name)
462 	u_long off;
463 	char *name;
464 {
465 	struct icmpstat icmpstat;
466 	int i, first;
467 
468 	if (off == 0)
469 		return;
470 	kread(off, (char *)&icmpstat, sizeof (icmpstat));
471 	printf("%s:\n", name);
472 
473 #define	p(f, m) if (icmpstat.f || sflag <= 1) \
474 	printf(m, icmpstat.f, plural(icmpstat.f))
475 
476 	p(icps_error, "\t%lu call%s to icmp_error\n");
477 	p(icps_oldicmp,
478 	    "\t%lu error%s not generated because old message was icmp\n");
479 	for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
480 		if (icmpstat.icps_outhist[i] != 0) {
481 			if (first) {
482 				printf("\tOutput packet histogram:\n");
483 				first = 0;
484 			}
485 			printf("\t\t%s: %lu\n", icmpnames[i],
486 			    icmpstat.icps_outhist[i]);
487 		}
488 	p(icps_badcode, "\t%lu message%s with bad code fields\n");
489 	p(icps_tooshort, "\t%lu message%s < minimum length\n");
490 	p(icps_checksum, "\t%lu bad checksum%s\n");
491 	p(icps_badlen, "\t%lu message%s with bad length\n");
492 	for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
493 		if (icmpstat.icps_inhist[i] != 0) {
494 			if (first) {
495 				printf("\tInput packet histogram:\n");
496 				first = 0;
497 			}
498 			printf("\t\t%s: %lu\n", icmpnames[i],
499 			    icmpstat.icps_inhist[i]);
500 		}
501 	p(icps_reflect, "\t%lu message response%s generated\n");
502 #undef p
503 }
504 
505 /*
506  * Dump IGMP statistics structure.
507  */
508 void
509 igmp_stats(off, name)
510 	u_long off;
511 	char *name;
512 {
513 	struct igmpstat igmpstat;
514 
515 	if (off == 0)
516 		return;
517 	kread(off, (char *)&igmpstat, sizeof (igmpstat));
518 	printf("%s:\n", name);
519 
520 #define	p(f, m) if (igmpstat.f || sflag <= 1) \
521 	printf(m, igmpstat.f, plural(igmpstat.f))
522 #define	py(f, m) if (igmpstat.f || sflag <= 1) \
523 	printf(m, igmpstat.f, igmpstat.f != 1 ? "ies" : "y")
524 
525 	p(igps_rcv_total, "\t%lu message%s received\n");
526 	p(igps_rcv_tooshort, "\t%lu message%s received with too few bytes\n");
527 	p(igps_rcv_badsum, "\t%lu message%s received with bad checksum\n");
528 	py(igps_rcv_queries, "\t%lu membership quer%s received\n");
529 	py(igps_rcv_badqueries, "\t%lu membership quer%s received with invalid field(s)\n");
530 	p(igps_rcv_reports, "\t%lu membership report%s received\n");
531 	p(igps_rcv_badreports, "\t%lu membership report%s received with invalid field(s)\n");
532 	p(igps_rcv_ourreports, "\t%lu membership report%s received for groups to which we belong\n");
533 	p(igps_snd_reports, "\t%lu membership report%s sent\n");
534 #undef p
535 #undef py
536 }
537 
538 struct rpcnams {
539 	struct rpcnams *next;
540 	in_port_t port;
541 	int	  proto;
542 	char	*rpcname;
543 };
544 
545 char *
546 getrpcportnam(port, proto)
547 	in_port_t port;
548 	int proto;
549 {
550 	struct sockaddr_in server_addr;
551 	struct hostent *hp;
552 	static struct pmaplist *head;
553 	int socket = RPC_ANYSOCK;
554 	struct timeval minutetimeout;
555 	CLIENT *client;
556 	struct rpcent *rpc;
557 	static int first;
558 	static struct rpcnams *rpcn;
559 	struct rpcnams *n;
560 	char num[20];
561 
562 	if (first == 0) {
563 		first = 1;
564 		memset((char *)&server_addr, 0, sizeof server_addr);
565 		server_addr.sin_family = AF_INET;
566 		if ((hp = gethostbyname("localhost")) != NULL)
567 			memmove((caddr_t)&server_addr.sin_addr, hp->h_addr,
568 			    hp->h_length);
569 		else
570 			(void) inet_aton("0.0.0.0", &server_addr.sin_addr);
571 
572 		minutetimeout.tv_sec = 60;
573 		minutetimeout.tv_usec = 0;
574 		server_addr.sin_port = htons(PMAPPORT);
575 		if ((client = clnttcp_create(&server_addr, PMAPPROG,
576 		    PMAPVERS, &socket, 50, 500)) == NULL)
577 			return (NULL);
578 		if (clnt_call(client, PMAPPROC_DUMP, xdr_void, NULL,
579 		    xdr_pmaplist, &head, minutetimeout) != RPC_SUCCESS) {
580 			clnt_destroy(client);
581 			return (NULL);
582 		}
583 		for (; head != NULL; head = head->pml_next) {
584 			n = (struct rpcnams *)malloc(sizeof(struct rpcnams));
585 			if (n == NULL)
586 				continue;
587 			n->next = rpcn;
588 			rpcn = n;
589 			n->port = head->pml_map.pm_port;
590 			n->proto = head->pml_map.pm_prot;
591 
592 			rpc = getrpcbynumber(head->pml_map.pm_prog);
593 			if (rpc)
594 				n->rpcname = strdup(rpc->r_name);
595 			else {
596 				snprintf(num, sizeof num, "%ld",
597 				    head->pml_map.pm_prog);
598 				n->rpcname = strdup(num);
599 			}
600 		}
601 		clnt_destroy(client);
602 	}
603 
604 	for (n = rpcn; n; n = n->next)
605 		if (n->port == port && n->proto == proto)
606 			return (n->rpcname);
607 	return (NULL);
608 }
609 
610 /*
611  * Pretty print an Internet address (net address + port).
612  * If the nflag was specified, use numbers instead of names.
613  */
614 void
615 inetprint(in, port, proto, local)
616 	struct in_addr *in;
617 	in_port_t port;
618 	char *proto;
619 	int local;
620 {
621 	struct servent *sp = 0;
622 	char line[80], *cp, *nam;
623 	int width;
624 
625 	snprintf(line, sizeof line, "%.*s.", (Aflag && !nflag) ? 12 : 16,
626 	    inetname(in));
627 	cp = strchr(line, '\0');
628 	if (!nflag && port)
629 		sp = getservbyport((int)port, proto);
630 	if (sp || port == 0)
631 		snprintf(cp, line + sizeof line - cp, "%.8s",
632 		    sp ? sp->s_name : "*");
633 	else if (local && !nflag && (nam = getrpcportnam(ntohs(port),
634 	    (strcmp(proto, "tcp") == 0 ? IPPROTO_TCP : IPPROTO_UDP))))
635 		snprintf(cp, line + sizeof line - cp, "%d[%.8s]",
636 		    ntohs(port), nam);
637 	else
638 		snprintf(cp, line + sizeof line - cp, "%d", ntohs(port));
639 	width = Aflag ? 18 : 22;
640 	printf(" %-*.*s", width, width, line);
641 }
642 
643 /*
644  * Construct an Internet address representation.
645  * If the nflag has been supplied, give
646  * numeric value, otherwise try for symbolic name.
647  */
648 char *
649 inetname(inp)
650 	struct in_addr *inp;
651 {
652 	char *cp;
653 	static char line[50];
654 	struct hostent *hp;
655 	struct netent *np;
656 	static char domain[MAXHOSTNAMELEN];
657 	static int first = 1;
658 
659 	if (first && !nflag) {
660 		first = 0;
661 		if (gethostname(domain, sizeof(domain)) == 0 &&
662 		    (cp = strchr(domain, '.')))
663 			(void) strlcpy(domain, cp + 1, sizeof domain);
664 		else
665 			domain[0] = '\0';
666 	}
667 	cp = 0;
668 	if (!nflag && inp->s_addr != INADDR_ANY) {
669 		int net = inet_netof(*inp);
670 		int lna = inet_lnaof(*inp);
671 
672 		if (lna == INADDR_ANY) {
673 			np = getnetbyaddr(net, AF_INET);
674 			if (np)
675 				cp = np->n_name;
676 		}
677 		if (cp == 0) {
678 			hp = gethostbyaddr((char *)inp, sizeof (*inp), AF_INET);
679 			if (hp) {
680 				if ((cp = strchr(hp->h_name, '.')) &&
681 				    !strcmp(cp + 1, domain))
682 					*cp = 0;
683 				cp = hp->h_name;
684 			}
685 		}
686 	}
687 	if (inp->s_addr == INADDR_ANY)
688 		snprintf(line, sizeof line, "*");
689 	else if (cp)
690 		snprintf(line, sizeof line, "%s", cp);
691 	else {
692 		inp->s_addr = ntohl(inp->s_addr);
693 #define C(x)	((x) & 0xff)
694 		snprintf(line, sizeof line, "%u.%u.%u.%u",
695 		    C(inp->s_addr >> 24), C(inp->s_addr >> 16),
696 		    C(inp->s_addr >> 8), C(inp->s_addr));
697 	}
698 	return (line);
699 }
700 
701 /*
702  * Dump AH statistics structure.
703  */
704 void
705 ah_stats(off, name)
706 	u_long off;
707 	char *name;
708 {
709 	struct ahstat ahstat;
710 
711 	if (off == 0)
712 		return;
713 	kread(off, (char *)&ahstat, sizeof (ahstat));
714 	printf("%s:\n", name);
715 
716 #define p(f, m) if (ahstat.f || sflag <= 1) \
717 	printf(m, ahstat.f, plural(ahstat.f))
718 #define p1(f, m) if (ahstat.f || sflag <= 1) \
719 	printf(m, ahstat.f)
720 
721 	p1(ahs_input, "\t%u input AH packets\n");
722 	p1(ahs_output, "\t%u output AH packets\n");
723 	p(ahs_nopf, "\t%u packet%s from unsupported protocol families\n");
724 	p(ahs_hdrops, "\t%u packet%s shorter than header shows\n");
725 	p(ahs_pdrops, "\t%u packet%s dropped due to policy\n");
726 	p(ahs_notdb, "\t%u packet%s for which no TDB was found\n");
727 	p(ahs_badkcr, "\t%u input packet%s that failed to be processed\n");
728 	p(ahs_badauth, "\t%u packet%s that failed verification received\n");
729 	p(ahs_noxform, "\t%u packet%s for which no XFORM was set in TDB received\n");
730 	p(ahs_qfull, "\t%u packet%s were dropped due to full output queue\n");
731 	p(ahs_wrap, "\t%u packet%s where counter wrapping was detected\n");
732 	p(ahs_replay, "\t%u possibly replayed packet%s received\n");
733 	p(ahs_badauthl, "\t%u packet%s with bad authenticator length received\n");
734 	p(ahs_invalid, "\t%u packet%s attempted to use an invalid TDB\n");
735 	p(ahs_toobig, "\t%u packet%s got larger than max IP packet size\n");
736 	p(ahs_crypto, "\t%u packet%s that failed crypto processing\n");
737 	p(ahs_ibytes, "\t%qu input byte%s\n");
738 	p(ahs_obytes, "\t%qu output byte%s\n");
739 
740 #undef p
741 #undef p1
742 }
743 
744 /*
745  * Dump etherip statistics structure.
746  */
747 void
748 etherip_stats(off, name)
749 	u_long off;
750 	char *name;
751 {
752 	struct etheripstat etheripstat;
753 
754 	if (off == 0)
755 		return;
756 	kread(off, (char *)&etheripstat, sizeof (etheripstat));
757 	printf("%s:\n", name);
758 
759 #define p(f, m) if (etheripstat.f || sflag <= 1) \
760 	printf(m, etheripstat.f, plural(etheripstat.f))
761 
762 
763 	p(etherip_hdrops, "\t%u packet%s shorter than header shows\n");
764 	p(etherip_qfull, "\t%u packet%s were dropped due to full output queue\n");
765 	p(etherip_noifdrops, "\t%u packet%s were dropped because of no interface/bridge information\n");
766 	p(etherip_pdrops, "\t%u packet%s dropped due to policy\n");
767 	p(etherip_adrops, "\t%u packet%s dropped for other reasons\n");
768 	p(etherip_ipackets, "\t%u input ethernet-in-IP packet%s\n");
769 	p(etherip_opackets, "\t%u output ethernet-in-IP packet%s\n");
770 	p(etherip_ibytes, "\t%qu input byte%s\n");
771 	p(etherip_obytes, "\t%qu output byte%s\n");
772 #undef p
773 }
774 
775 /*
776  * Dump ESP statistics structure.
777  */
778 void
779 esp_stats(off, name)
780 	u_long off;
781 	char *name;
782 {
783 	struct espstat espstat;
784 
785 	if (off == 0)
786 		return;
787 	kread(off, (char *)&espstat, sizeof (espstat));
788 	printf("%s:\n", name);
789 
790 #define p(f, m) if (espstat.f || sflag <= 1) \
791 	printf(m, espstat.f, plural(espstat.f))
792 
793 	p(esps_input, "\t%u input ESP packet%s\n");
794 	p(esps_output, "\t%u output ESP packet%s\n");
795 	p(esps_nopf, "\t%u packet%s from unsupported protocol families\n");
796 	p(esps_hdrops, "\t%u packet%s shorter than header shows\n");
797 	p(esps_pdrops, "\t%u packet%s dropped due to policy\n");
798 	p(esps_notdb, "\t%u packet%s for which no TDB was found\n");
799 	p(esps_badkcr, "\t%u input packet%s that failed to be processed\n");
800 	p(esps_badenc, "\t%u packet%s with bad encryption received\n");
801 	p(esps_badauth, "\t%u packet%s that failed verification received\n");
802 	p(esps_noxform, "\t%u packet%s for which no XFORM was set in TDB received\n");
803 	p(esps_qfull, "\t%u packet%s were dropped due to full output queue\n");
804 	p(esps_wrap, "\t%u packet%s where counter wrapping was detected\n");
805 	p(esps_replay, "\t%u possibly replayed packet%s received\n");
806 	p(esps_badilen, "\t%u packet%s with bad payload size or padding received\n");
807 	p(esps_invalid, "\t%u packet%s attempted to use an invalid TDB\n");
808 	p(esps_toobig, "\t%u packet%s got larger than max IP packet size\n");
809 	p(esps_crypto, "\t%u packet%s that failed crypto processing\n");
810 	p(esps_ibytes, "\t%qu input byte%s\n");
811 	p(esps_obytes, "\t%qu output byte%s\n");
812 
813 #undef p
814 }
815 
816 /*
817  * Dump ESP statistics structure.
818  */
819 void
820 ipip_stats(off, name)
821 	u_long off;
822 	char *name;
823 {
824 	struct ipipstat ipipstat;
825 
826 	if (off == 0)
827 		return;
828 	kread(off, (char *)&ipipstat, sizeof (ipipstat));
829 	printf("%s:\n", name);
830 
831 #define p(f, m) if (ipipstat.f || sflag <= 1) \
832 	printf(m, ipipstat.f, plural(ipipstat.f))
833 
834 	p(ipips_ipackets, "\t%u total input packet%s\n");
835 	p(ipips_opackets, "\t%u total output packet%s\n");
836 	p(ipips_hdrops, "\t%u packet%s shorter than header shows\n");
837 	p(ipips_pdrops, "\t%u packet%s dropped due to policy\n");
838 	p(ipips_spoof, "\t%u packet%s with possibly spoofed local addresses\n");
839 	p(ipips_qfull, "\t%u packet%s were dropped due to full output queue\n");
840 	p(ipips_ibytes, "\t%qu input byte%s\n");
841 	p(ipips_obytes, "\t%qu output byte%s\n");
842 	p(ipips_family, "\t%u protocol family mismatches\n");
843 	p(ipips_unspec, "\t%u attempts to use tunnel with unspecified endpoint(s)\n");
844 #undef p
845 }
846 
847 /*
848  * Dump IPCOMP statistics structure.
849  */
850 void
851 ipcomp_stats(off, name)
852 	u_long off;
853 	char *name;
854 {
855 	struct ipcompstat ipcompstat;
856 
857 	if (off == 0)
858 		return;
859 	kread(off, (char *)&ipcompstat, sizeof (ipcompstat));
860 	printf("%s:\n", name);
861 
862 #define p(f, m) if (ipcompstat.f || sflag <= 1) \
863 	printf(m, ipcompstat.f, plural(ipcompstat.f))
864 
865 	p(ipcomps_input, "\t%u input IPCOMP packet%s\n");
866 	p(ipcomps_output, "\t%u output IPCOMP packet%s\n");
867 	p(ipcomps_nopf, "\t%u packet%s from unsupported protocol families\n");
868 	p(ipcomps_hdrops, "\t%u packet%s shorter than header shows\n");
869 	p(ipcomps_pdrops, "\t%u packet%s dropped due to policy\n");
870 	p(ipcomps_notdb, "\t%u packet%s for which no TDB was found\n");
871 	p(ipcomps_badkcr, "\t%u input packet%s that failed to be processed\n");
872 	p(ipcomps_noxform, "\t%u packet%s for which no XFORM was set in TDB received\n");
873 	p(ipcomps_qfull, "\t%u packet%s were dropped due to full output queue\n");
874 	p(ipcomps_wrap, "\t%u packet%s where counter wrapping was detected\n");
875 	p(ipcomps_invalid, "\t%u packet%s attempted to use an invalid TDB\n");
876 	p(ipcomps_toobig, "\t%u packet%s got larger than max IP packet size\n");
877 	p(ipcomps_crypto, "\t%u packet%s that failed (de)compression processing\n");
878 	p(ipcomps_ibytes, "\t%qu input byte%s\n");
879 	p(ipcomps_obytes, "\t%qu output byte%s\n");
880 
881 #undef p
882 }
883