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