xref: /openbsd-src/usr.bin/netstat/inet.c (revision 8500990981f885cbe5e6a4958549cacc238b5ae6)
1 /*	$OpenBSD: inet.c,v 1.74 2003/12/02 23:16:29 markus 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.74 2003/12/02 23:16:29 markus 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 #include <netinet/ip_carp.h>
74 
75 #include <arpa/inet.h>
76 #include <limits.h>
77 #include <netdb.h>
78 #include <stdio.h>
79 #include <string.h>
80 #include <unistd.h>
81 #include <stdlib.h>
82 #include "netstat.h"
83 
84 #include <rpc/rpc.h>
85 #include <rpc/pmap_prot.h>
86 #include <rpc/pmap_clnt.h>
87 
88 struct	inpcb inpcb;
89 struct	tcpcb tcpcb;
90 struct	socket sockb;
91 
92 static void protopr0(u_long, char *, int);
93 
94 char	*inetname(struct in_addr *);
95 void	inetprint(struct in_addr *, in_port_t, char *, int);
96 #ifdef INET6
97 char	*inet6name(struct in6_addr *);
98 void	inet6print(struct in6_addr *, int, char *, int);
99 #endif
100 
101 /*
102  * Print a summary of connections related to an Internet
103  * protocol.  For TCP, also give state of connection.
104  * Listening processes (aflag) are suppressed unless the
105  * -a (all) flag is specified.
106  */
107 void
108 protopr(u_long off, char *name)
109 {
110 	protopr0(off, name, AF_INET);
111 }
112 
113 #ifdef INET6
114 void
115 ip6protopr(u_long off, char *name)
116 {
117 	protopr0(off, name, AF_INET6);
118 }
119 #endif
120 
121 static void
122 protopr0(u_long off, char *name, int af)
123 {
124 	struct inpcbtable table;
125 	struct inpcb *head, *next, *prev;
126 	struct inpcb inpcb;
127 	int istcp, israw;
128 	int first = 1;
129 	char *name0;
130 	char namebuf[20];
131 
132 	name0 = name;
133 	if (off == 0)
134 		return;
135 	istcp = strcmp(name, "tcp") == 0;
136 	israw = strncmp(name, "ip", 2) == 0;
137 	kread(off, (char *)&table, sizeof table);
138 	prev = head =
139 	    (struct inpcb *)&((struct inpcbtable *)off)->inpt_queue.cqh_first;
140 	next = table.inpt_queue.cqh_first;
141 
142 	while (next != head) {
143 		kread((u_long)next, (char *)&inpcb, sizeof inpcb);
144 		if (inpcb.inp_queue.cqe_prev != prev) {
145 			printf("???\n");
146 			break;
147 		}
148 		prev = next;
149 		next = inpcb.inp_queue.cqe_next;
150 
151 		switch (af) {
152 		case AF_INET:
153 			if ((inpcb.inp_flags & INP_IPV6) != 0)
154 				continue;
155 			break;
156 		case AF_INET6:
157 			if ((inpcb.inp_flags & INP_IPV6) == 0)
158 				continue;
159 			break;
160 		default:
161 			break;
162 		}
163 
164 		if (!aflag &&
165 		    inet_lnaof(inpcb.inp_laddr) == INADDR_ANY)
166 			continue;
167 		kread((u_long)inpcb.inp_socket, (char *)&sockb, sizeof (sockb));
168 		if (istcp) {
169 			kread((u_long)inpcb.inp_ppcb,
170 			    (char *)&tcpcb, sizeof (tcpcb));
171 		}
172 		if (first) {
173 			printf("Active Internet connections");
174 			if (aflag)
175 				printf(" (including servers)");
176 			putchar('\n');
177 			if (Aflag)
178 				printf("%-*.*s %-5.5s %-6.6s %-6.6s  %-18.18s %-18.18s %s\n",
179 				    PLEN, PLEN, "PCB", "Proto", "Recv-Q",
180 				    "Send-Q", "Local Address",
181 				    "Foreign Address", "(state)");
182 			else
183 				printf("%-5.5s %-6.6s %-6.6s  %-22.22s %-22.22s %s\n",
184 				    "Proto", "Recv-Q", "Send-Q",
185 				    "Local Address", "Foreign Address",
186 				    "(state)");
187 			first = 0;
188 		}
189 		if (Aflag) {
190 			if (istcp)
191 				printf("%*p ", PLEN, inpcb.inp_ppcb);
192 			else
193 				printf("%*p ", PLEN, prev);
194 		}
195 #ifdef INET6
196 		if (inpcb.inp_flags & INP_IPV6 && !israw) {
197 			strlcpy(namebuf, name0, sizeof namebuf);
198 			strlcat(namebuf, "6", sizeof namebuf);
199 			name = namebuf;
200 		} else
201 			name = name0;
202 #endif
203 		printf("%-5.5s %6ld %6ld ", name, sockb.so_rcv.sb_cc,
204 		    sockb.so_snd.sb_cc);
205 #ifdef INET6
206 		if (inpcb.inp_flags & INP_IPV6) {
207 			inet6print(&inpcb.inp_laddr6, (int)inpcb.inp_lport,
208 			    name, 1);
209 			inet6print(&inpcb.inp_faddr6, (int)inpcb.inp_fport,
210 			    name, 0);
211 		} else
212 #endif
213 		{
214 			inetprint(&inpcb.inp_laddr, (int)inpcb.inp_lport,
215 			    name, 1);
216 			inetprint(&inpcb.inp_faddr, (int)inpcb.inp_fport,
217 			    name, 0);
218 		}
219 		if (istcp) {
220 			if (tcpcb.t_state < 0 || tcpcb.t_state >= TCP_NSTATES)
221 				printf(" %d", tcpcb.t_state);
222 			else
223 				printf(" %s", tcpstates[tcpcb.t_state]);
224 		} else if (israw) {
225 			struct protoent *pe = NULL;
226 			u_int8_t proto;
227 #ifdef INET6
228 			if (inpcb.inp_flags & INP_IPV6)
229 				proto = inpcb.inp_ipv6.ip6_nxt;
230 			else
231 #endif
232 				proto = inpcb.inp_ip.ip_p;
233 			if (!nflag)
234 				pe = getprotobynumber(proto);
235 			if (pe)
236 				printf(" %s", pe->p_name);
237 			else
238 				printf(" %u", proto);
239 		}
240 		putchar('\n');
241 	}
242 }
243 
244 /*
245  * Dump TCP statistics structure.
246  */
247 void
248 tcp_stats(u_long off, char *name)
249 {
250 	struct tcpstat tcpstat;
251 
252 	if (off == 0)
253 		return;
254 	printf("%s:\n", name);
255 	kread(off, (char *)&tcpstat, sizeof (tcpstat));
256 
257 #define	p(f, m) if (tcpstat.f || sflag <= 1) \
258 	printf(m, tcpstat.f, plural(tcpstat.f))
259 #define	p1(f, m) if (tcpstat.f || sflag <= 1) \
260 	printf(m, tcpstat.f)
261 #define	p2(f1, f2, m) if (tcpstat.f1 || tcpstat.f2 || sflag <= 1) \
262 	printf(m, tcpstat.f1, plural(tcpstat.f1), tcpstat.f2, plural(tcpstat.f2))
263 #define	p2a(f1, f2, m) if (tcpstat.f1 || tcpstat.f2 || sflag <= 1) \
264 	printf(m, tcpstat.f1, plural(tcpstat.f1), tcpstat.f2)
265 #define	p3(f, m) if (tcpstat.f || sflag <= 1) \
266 	printf(m, tcpstat.f, plurales(tcpstat.f))
267 
268 	p(tcps_sndtotal, "\t%u packet%s sent\n");
269 	p2(tcps_sndpack,tcps_sndbyte,
270 	    "\t\t%u data packet%s (%qd byte%s)\n");
271 	p2(tcps_sndrexmitpack, tcps_sndrexmitbyte,
272 	    "\t\t%u data packet%s (%qd byte%s) retransmitted\n");
273 	p(tcps_sndrexmitfast, "\t\t%qd fast retransmitted packet%s\n");
274 	p2a(tcps_sndacks, tcps_delack,
275 	    "\t\t%u ack-only packet%s (%u delayed)\n");
276 	p(tcps_sndurg, "\t\t%u URG only packet%s\n");
277 	p(tcps_sndprobe, "\t\t%u window probe packet%s\n");
278 	p(tcps_sndwinup, "\t\t%u window update packet%s\n");
279 	p(tcps_sndctrl, "\t\t%u control packet%s\n");
280 	p(tcps_outhwcsum, "\t\t%u packet%s hardware-checksummed\n");
281 	p(tcps_rcvtotal, "\t%u packet%s received\n");
282 	p2(tcps_rcvackpack, tcps_rcvackbyte, "\t\t%u ack%s (for %qd byte%s)\n");
283 	p(tcps_rcvdupack, "\t\t%u duplicate ack%s\n");
284 	p(tcps_rcvacktoomuch, "\t\t%u ack%s for unsent data\n");
285 	p2(tcps_rcvpack, tcps_rcvbyte,
286 	    "\t\t%u packet%s (%qu byte%s) received in-sequence\n");
287 	p2(tcps_rcvduppack, tcps_rcvdupbyte,
288 	    "\t\t%u completely duplicate packet%s (%qd byte%s)\n");
289 	p(tcps_pawsdrop, "\t\t%u old duplicate packet%s\n");
290 	p2(tcps_rcvpartduppack, tcps_rcvpartdupbyte,
291 	    "\t\t%u packet%s with some duplicate data (%qd byte%s duplicated)\n");
292 	p2(tcps_rcvoopack, tcps_rcvoobyte,
293 	    "\t\t%u out-of-order packet%s (%qd byte%s)\n");
294 	p2(tcps_rcvpackafterwin, tcps_rcvbyteafterwin,
295 	    "\t\t%u packet%s (%qd byte%s) of data after window\n");
296 	p(tcps_rcvwinprobe, "\t\t%u window probe%s\n");
297 	p(tcps_rcvwinupd, "\t\t%u window update packet%s\n");
298 	p(tcps_rcvafterclose, "\t\t%u packet%s received after close\n");
299 	p(tcps_rcvbadsum, "\t\t%u discarded for bad checksum%s\n");
300 	p(tcps_rcvbadoff, "\t\t%u discarded for bad header offset field%s\n");
301 	p1(tcps_rcvshort, "\t\t%u discarded because packet too short\n");
302 	p1(tcps_rcvnosec, "\t\t%u discarded for missing IPsec protection\n");
303 	p(tcps_inhwcsum, "\t\t%u packet%s hardware-checksummed\n");
304 	p(tcps_connattempt, "\t%u connection request%s\n");
305 	p(tcps_accepts, "\t%u connection accept%s\n");
306 	p(tcps_connects, "\t%u connection%s established (including accepts)\n");
307 	p2(tcps_closed, tcps_drops,
308 	    "\t%u connection%s closed (including %u drop%s)\n");
309 	p(tcps_conndrops, "\t%u embryonic connection%s dropped\n");
310 	p2(tcps_rttupdated, tcps_segstimed,
311 	    "\t%u segment%s updated rtt (of %u attempt%s)\n");
312 	p(tcps_rexmttimeo, "\t%u retransmit timeout%s\n");
313 	p(tcps_timeoutdrop, "\t\t%u connection%s dropped by rexmit timeout\n");
314 	p(tcps_persisttimeo, "\t%u persist timeout%s\n");
315 	p(tcps_keeptimeo, "\t%u keepalive timeout%s\n");
316 	p(tcps_keepprobe, "\t\t%u keepalive probe%s sent\n");
317 	p(tcps_keepdrops, "\t\t%u connection%s dropped by keepalive\n");
318 	p(tcps_predack, "\t%u correct ACK header prediction%s\n");
319 	p(tcps_preddat, "\t%u correct data packet header prediction%s\n");
320 	p3(tcps_pcbhashmiss, "\t%u PCB cache miss%s\n");
321 	p(tcps_badsyn, "\t%u SYN packet%s received with same src/dst address/port\n");
322 
323 	p(tcps_ecn_accepts, "\t%u ECN connection%s accepted\n");
324 	p(tcps_ecn_rcvece, "\t\t%u ECE packet%s received\n");
325 	p(tcps_ecn_rcvcwr, "\t\t%u CWR packet%s received\n");
326 	p(tcps_ecn_rcvce, "\t\t%u CE packet%s received\n");
327 	p(tcps_ecn_sndect, "\t\t%u ECT packet%s sent\n");
328 	p(tcps_ecn_sndece, "\t\t%u ECE packet%s sent\n");
329 	p(tcps_ecn_sndcwr, "\t\t%u CWR packet%s sent\n");
330 	p1(tcps_cwr_frecovery, "\t\t\tcwr by fastrecovery: %u\n");
331 	p1(tcps_cwr_timeout, "\t\t\tcwr by timeout: %u\n");
332 	p1(tcps_cwr_ecn, "\t\t\tcwr by ecn: %u\n");
333 
334 #undef p
335 #undef p1
336 #undef p2
337 #undef p2a
338 #undef p3
339 }
340 
341 /*
342  * Dump UDP statistics structure.
343  */
344 void
345 udp_stats(u_long off, char *name)
346 {
347 	struct udpstat udpstat;
348 	u_long delivered;
349 
350 	if (off == 0)
351 		return;
352 	kread(off, (char *)&udpstat, sizeof (udpstat));
353 	printf("%s:\n", name);
354 #define	p(f, m) if (udpstat.f || sflag <= 1) \
355 	printf(m, udpstat.f, plural(udpstat.f))
356 #define	p1(f, m) if (udpstat.f || sflag <= 1) \
357 	printf(m, udpstat.f)
358 
359 	p(udps_ipackets, "\t%lu datagram%s received\n");
360 	p1(udps_hdrops, "\t%lu with incomplete header\n");
361 	p1(udps_badlen, "\t%lu with bad data length field\n");
362 	p1(udps_badsum, "\t%lu with bad checksum\n");
363 	p1(udps_nosum, "\t%lu with no checksum\n");
364 	p(udps_inhwcsum, "\t%lu input packet%s hardware-checksummed\n");
365 	p(udps_outhwcsum, "\t%lu output packet%s hardware-checksummed\n");
366 	p1(udps_noport, "\t%lu dropped due to no socket\n");
367 	p(udps_noportbcast, "\t%lu broadcast/multicast datagram%s dropped due to no socket\n");
368 	p1(udps_nosec, "\t%lu dropped due to missing IPsec protection\n");
369 	p1(udps_fullsock, "\t%lu dropped due to full socket buffers\n");
370 	delivered = udpstat.udps_ipackets - udpstat.udps_hdrops -
371 	    udpstat.udps_badlen - udpstat.udps_badsum -
372 	    udpstat.udps_noport - udpstat.udps_noportbcast -
373 	    udpstat.udps_fullsock;
374 	if (delivered || sflag <= 1)
375 		printf("\t%lu delivered\n", delivered);
376 	p(udps_opackets, "\t%lu datagram%s output\n");
377 	p1(udps_pcbhashmiss, "\t%lu missed PCB cache\n");
378 #undef p
379 #undef p1
380 }
381 
382 /*
383  * Dump IP statistics structure.
384  */
385 void
386 ip_stats(u_long off, 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[ICMP_MAXTYPE + 1] = {
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 	"#19",
456 	"#20",
457 	"#21",
458 	"#22",
459 	"#23",
460 	"#24",
461 	"#25",
462 	"#26",
463 	"#27",
464 	"#28",
465 	"#29",
466 	"traceroute",
467 	"data conversion error",
468 	"mobile host redirect",
469 	"IPv6 where-are-you",
470 	"IPv6 i-am-here",
471 	"mobile registration request",
472 	"mobile registration reply",
473 	"#37",
474 	"#38",
475 	"SKIP",
476 	"Photuris",
477 };
478 
479 /*
480  * Dump ICMP statistics.
481  */
482 void
483 icmp_stats(u_long off, char *name)
484 {
485 	struct icmpstat icmpstat;
486 	int i, first;
487 
488 	if (off == 0)
489 		return;
490 	kread(off, (char *)&icmpstat, sizeof (icmpstat));
491 	printf("%s:\n", name);
492 
493 #define	p(f, m) if (icmpstat.f || sflag <= 1) \
494 	printf(m, icmpstat.f, plural(icmpstat.f))
495 
496 	p(icps_error, "\t%lu call%s to icmp_error\n");
497 	p(icps_oldicmp,
498 	    "\t%lu error%s not generated because old message was icmp\n");
499 	for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
500 		if (icmpstat.icps_outhist[i] != 0) {
501 			if (first) {
502 				printf("\tOutput packet histogram:\n");
503 				first = 0;
504 			}
505 			if (icmpnames[i])
506 				printf("\t\t%s:", icmpnames[i]);
507 			else
508 				printf("\t\t#%d:", i);
509 			printf(" %lu\n", icmpstat.icps_outhist[i]);
510 		}
511 	p(icps_badcode, "\t%lu message%s with bad code fields\n");
512 	p(icps_tooshort, "\t%lu message%s < minimum length\n");
513 	p(icps_checksum, "\t%lu bad checksum%s\n");
514 	p(icps_badlen, "\t%lu message%s with bad length\n");
515 	for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
516 		if (icmpstat.icps_inhist[i] != 0) {
517 			if (first) {
518 				printf("\tInput packet histogram:\n");
519 				first = 0;
520 			}
521 			if (icmpnames[i])
522 				printf("\t\t%s:", icmpnames[i]);
523 			else
524 				printf("\t\t#%d:", i);
525 			printf(" %lu\n", icmpstat.icps_inhist[i]);
526 		}
527 	p(icps_reflect, "\t%lu message response%s generated\n");
528 #undef p
529 }
530 
531 /*
532  * Dump IGMP statistics structure.
533  */
534 void
535 igmp_stats(u_long off, char *name)
536 {
537 	struct igmpstat igmpstat;
538 
539 	if (off == 0)
540 		return;
541 	kread(off, (char *)&igmpstat, sizeof (igmpstat));
542 	printf("%s:\n", name);
543 
544 #define	p(f, m) if (igmpstat.f || sflag <= 1) \
545 	printf(m, igmpstat.f, plural(igmpstat.f))
546 #define	py(f, m) if (igmpstat.f || sflag <= 1) \
547 	printf(m, igmpstat.f, igmpstat.f != 1 ? "ies" : "y")
548 
549 	p(igps_rcv_total, "\t%lu message%s received\n");
550 	p(igps_rcv_tooshort, "\t%lu message%s received with too few bytes\n");
551 	p(igps_rcv_badsum, "\t%lu message%s received with bad checksum\n");
552 	py(igps_rcv_queries, "\t%lu membership quer%s received\n");
553 	py(igps_rcv_badqueries, "\t%lu membership quer%s received with invalid field(s)\n");
554 	p(igps_rcv_reports, "\t%lu membership report%s received\n");
555 	p(igps_rcv_badreports, "\t%lu membership report%s received with invalid field(s)\n");
556 	p(igps_rcv_ourreports, "\t%lu membership report%s received for groups to which we belong\n");
557 	p(igps_snd_reports, "\t%lu membership report%s sent\n");
558 #undef p
559 #undef py
560 }
561 
562 struct rpcnams {
563 	struct rpcnams *next;
564 	in_port_t port;
565 	int	  proto;
566 	char	*rpcname;
567 };
568 
569 static char *
570 getrpcportnam(in_port_t port, int proto)
571 {
572 	struct sockaddr_in server_addr;
573 	struct hostent *hp;
574 	static struct pmaplist *head;
575 	int socket = RPC_ANYSOCK;
576 	struct timeval minutetimeout;
577 	CLIENT *client;
578 	struct rpcent *rpc;
579 	static int first;
580 	static struct rpcnams *rpcn;
581 	struct rpcnams *n;
582 	char num[20];
583 
584 	if (first == 0) {
585 		first = 1;
586 		memset((char *)&server_addr, 0, sizeof server_addr);
587 		server_addr.sin_family = AF_INET;
588 		if ((hp = gethostbyname("localhost")) != NULL)
589 			memmove((caddr_t)&server_addr.sin_addr, hp->h_addr,
590 			    hp->h_length);
591 		else
592 			(void) inet_aton("0.0.0.0", &server_addr.sin_addr);
593 
594 		minutetimeout.tv_sec = 60;
595 		minutetimeout.tv_usec = 0;
596 		server_addr.sin_port = htons(PMAPPORT);
597 		if ((client = clnttcp_create(&server_addr, PMAPPROG,
598 		    PMAPVERS, &socket, 50, 500)) == NULL)
599 			return (NULL);
600 		if (clnt_call(client, PMAPPROC_DUMP, xdr_void, NULL,
601 		    xdr_pmaplist, &head, minutetimeout) != RPC_SUCCESS) {
602 			clnt_destroy(client);
603 			return (NULL);
604 		}
605 		for (; head != NULL; head = head->pml_next) {
606 			n = (struct rpcnams *)malloc(sizeof(struct rpcnams));
607 			if (n == NULL)
608 				continue;
609 			n->next = rpcn;
610 			rpcn = n;
611 			n->port = head->pml_map.pm_port;
612 			n->proto = head->pml_map.pm_prot;
613 
614 			rpc = getrpcbynumber(head->pml_map.pm_prog);
615 			if (rpc)
616 				n->rpcname = strdup(rpc->r_name);
617 			else {
618 				snprintf(num, sizeof num, "%ld",
619 				    head->pml_map.pm_prog);
620 				n->rpcname = strdup(num);
621 			}
622 		}
623 		clnt_destroy(client);
624 	}
625 
626 	for (n = rpcn; n; n = n->next)
627 		if (n->port == port && n->proto == proto)
628 			return (n->rpcname);
629 	return (NULL);
630 }
631 
632 /*
633  * Pretty print an Internet address (net address + port).
634  * If the nflag was specified, use numbers instead of names.
635  */
636 void
637 inetprint(struct in_addr *in, in_port_t port, char *proto, int local)
638 {
639 	struct servent *sp = 0;
640 	char line[80], *cp, *nam;
641 	int width;
642 
643 	snprintf(line, sizeof line, "%.*s.", (Aflag && !nflag) ? 12 : 16,
644 	    inetname(in));
645 	cp = strchr(line, '\0');
646 	if (!nflag && port)
647 		sp = getservbyport((int)port, proto);
648 	if (sp || port == 0)
649 		snprintf(cp, line + sizeof line - cp, "%.8s",
650 		    sp ? sp->s_name : "*");
651 	else if (local && !nflag && (nam = getrpcportnam(ntohs(port),
652 	    (strcmp(proto, "tcp") == 0 ? IPPROTO_TCP : IPPROTO_UDP))))
653 		snprintf(cp, line + sizeof line - cp, "%d[%.8s]",
654 		    ntohs(port), nam);
655 	else
656 		snprintf(cp, line + sizeof line - cp, "%d", ntohs(port));
657 	width = Aflag ? 18 : 22;
658 	printf(" %-*.*s", width, width, line);
659 }
660 
661 /*
662  * Construct an Internet address representation.
663  * If the nflag has been supplied, give
664  * numeric value, otherwise try for symbolic name.
665  */
666 char *
667 inetname(struct in_addr *inp)
668 {
669 	char *cp;
670 	static char line[50];
671 	struct hostent *hp;
672 	struct netent *np;
673 	static char domain[MAXHOSTNAMELEN];
674 	static int first = 1;
675 
676 	if (first && !nflag) {
677 		first = 0;
678 		if (gethostname(domain, sizeof(domain)) == 0 &&
679 		    (cp = strchr(domain, '.')))
680 			(void) strlcpy(domain, cp + 1, sizeof domain);
681 		else
682 			domain[0] = '\0';
683 	}
684 	cp = 0;
685 	if (!nflag && inp->s_addr != INADDR_ANY) {
686 		int net = inet_netof(*inp);
687 		int lna = inet_lnaof(*inp);
688 
689 		if (lna == INADDR_ANY) {
690 			np = getnetbyaddr(net, AF_INET);
691 			if (np)
692 				cp = np->n_name;
693 		}
694 		if (cp == 0) {
695 			hp = gethostbyaddr((char *)inp, sizeof (*inp), AF_INET);
696 			if (hp) {
697 				if ((cp = strchr(hp->h_name, '.')) &&
698 				    !strcmp(cp + 1, domain))
699 					*cp = 0;
700 				cp = hp->h_name;
701 			}
702 		}
703 	}
704 	if (inp->s_addr == INADDR_ANY)
705 		snprintf(line, sizeof line, "*");
706 	else if (cp)
707 		snprintf(line, sizeof line, "%s", cp);
708 	else {
709 		inp->s_addr = ntohl(inp->s_addr);
710 #define C(x)	((x) & 0xff)
711 		snprintf(line, sizeof line, "%u.%u.%u.%u",
712 		    C(inp->s_addr >> 24), C(inp->s_addr >> 16),
713 		    C(inp->s_addr >> 8), C(inp->s_addr));
714 	}
715 	return (line);
716 }
717 
718 /*
719  * Dump AH statistics structure.
720  */
721 void
722 ah_stats(u_long off, char *name)
723 {
724 	struct ahstat ahstat;
725 
726 	if (off == 0)
727 		return;
728 	kread(off, (char *)&ahstat, sizeof (ahstat));
729 	printf("%s:\n", name);
730 
731 #define p(f, m) if (ahstat.f || sflag <= 1) \
732 	printf(m, ahstat.f, plural(ahstat.f))
733 #define p1(f, m) if (ahstat.f || sflag <= 1) \
734 	printf(m, ahstat.f)
735 
736 	p1(ahs_input, "\t%u input AH packets\n");
737 	p1(ahs_output, "\t%u output AH packets\n");
738 	p(ahs_nopf, "\t%u packet%s from unsupported protocol families\n");
739 	p(ahs_hdrops, "\t%u packet%s shorter than header shows\n");
740 	p(ahs_pdrops, "\t%u packet%s dropped due to policy\n");
741 	p(ahs_notdb, "\t%u packet%s for which no TDB was found\n");
742 	p(ahs_badkcr, "\t%u input packet%s that failed to be processed\n");
743 	p(ahs_badauth, "\t%u packet%s that failed verification received\n");
744 	p(ahs_noxform, "\t%u packet%s for which no XFORM was set in TDB received\n");
745 	p(ahs_qfull, "\t%u packet%s were dropped due to full output queue\n");
746 	p(ahs_wrap, "\t%u packet%s where counter wrapping was detected\n");
747 	p(ahs_replay, "\t%u possibly replayed packet%s received\n");
748 	p(ahs_badauthl, "\t%u packet%s with bad authenticator length received\n");
749 	p(ahs_invalid, "\t%u packet%s attempted to use an invalid TDB\n");
750 	p(ahs_toobig, "\t%u packet%s got larger than max IP packet size\n");
751 	p(ahs_crypto, "\t%u packet%s that failed crypto processing\n");
752 	p(ahs_ibytes, "\t%qu input byte%s\n");
753 	p(ahs_obytes, "\t%qu output byte%s\n");
754 
755 #undef p
756 #undef p1
757 }
758 
759 /*
760  * Dump etherip statistics structure.
761  */
762 void
763 etherip_stats(u_long off, char *name)
764 {
765 	struct etheripstat etheripstat;
766 
767 	if (off == 0)
768 		return;
769 	kread(off, (char *)&etheripstat, sizeof (etheripstat));
770 	printf("%s:\n", name);
771 
772 #define p(f, m) if (etheripstat.f || sflag <= 1) \
773 	printf(m, etheripstat.f, plural(etheripstat.f))
774 
775 	p(etherip_hdrops, "\t%u packet%s shorter than header shows\n");
776 	p(etherip_qfull, "\t%u packet%s were dropped due to full output queue\n");
777 	p(etherip_noifdrops, "\t%u packet%s were dropped because of no interface/bridge information\n");
778 	p(etherip_pdrops, "\t%u packet%s dropped due to policy\n");
779 	p(etherip_adrops, "\t%u packet%s dropped for other reasons\n");
780 	p(etherip_ipackets, "\t%u input ethernet-in-IP packet%s\n");
781 	p(etherip_opackets, "\t%u output ethernet-in-IP packet%s\n");
782 	p(etherip_ibytes, "\t%qu input byte%s\n");
783 	p(etherip_obytes, "\t%qu output byte%s\n");
784 #undef p
785 }
786 
787 /*
788  * Dump ESP statistics structure.
789  */
790 void
791 esp_stats(u_long off, char *name)
792 {
793 	struct espstat espstat;
794 
795 	if (off == 0)
796 		return;
797 	kread(off, (char *)&espstat, sizeof (espstat));
798 	printf("%s:\n", name);
799 
800 #define p(f, m) if (espstat.f || sflag <= 1) \
801 	printf(m, espstat.f, plural(espstat.f))
802 
803 	p(esps_input, "\t%u input ESP packet%s\n");
804 	p(esps_output, "\t%u output ESP packet%s\n");
805 	p(esps_nopf, "\t%u packet%s from unsupported protocol families\n");
806 	p(esps_hdrops, "\t%u packet%s shorter than header shows\n");
807 	p(esps_pdrops, "\t%u packet%s dropped due to policy\n");
808 	p(esps_notdb, "\t%u packet%s for which no TDB was found\n");
809 	p(esps_badkcr, "\t%u input packet%s that failed to be processed\n");
810 	p(esps_badenc, "\t%u packet%s with bad encryption received\n");
811 	p(esps_badauth, "\t%u packet%s that failed verification received\n");
812 	p(esps_noxform, "\t%u packet%s for which no XFORM was set in TDB received\n");
813 	p(esps_qfull, "\t%u packet%s were dropped due to full output queue\n");
814 	p(esps_wrap, "\t%u packet%s where counter wrapping was detected\n");
815 	p(esps_replay, "\t%u possibly replayed packet%s received\n");
816 	p(esps_badilen, "\t%u packet%s with bad payload size or padding received\n");
817 	p(esps_invalid, "\t%u packet%s attempted to use an invalid TDB\n");
818 	p(esps_toobig, "\t%u packet%s got larger than max IP packet size\n");
819 	p(esps_crypto, "\t%u packet%s that failed crypto processing\n");
820 	p(esps_udpencin, "\t%u input UDP encapsulated ESP packet%s\n");
821 	p(esps_udpencout, "\t%u output UDP encapsulated ESP packet%s\n");
822 	p(esps_udpinval, "\t%u UDP packet%s for non-encapsulating TDB received\n");
823 	p(esps_ibytes, "\t%qu input byte%s\n");
824 	p(esps_obytes, "\t%qu output byte%s\n");
825 
826 #undef p
827 }
828 
829 /*
830  * Dump IP-in-IP statistics structure.
831  */
832 void
833 ipip_stats(u_long off, char *name)
834 {
835 	struct ipipstat ipipstat;
836 
837 	if (off == 0)
838 		return;
839 	kread(off, (char *)&ipipstat, sizeof (ipipstat));
840 	printf("%s:\n", name);
841 
842 #define p(f, m) if (ipipstat.f || sflag <= 1) \
843 	printf(m, ipipstat.f, plural(ipipstat.f))
844 
845 	p(ipips_ipackets, "\t%u total input packet%s\n");
846 	p(ipips_opackets, "\t%u total output packet%s\n");
847 	p(ipips_hdrops, "\t%u packet%s shorter than header shows\n");
848 	p(ipips_pdrops, "\t%u packet%s dropped due to policy\n");
849 	p(ipips_spoof, "\t%u packet%s with possibly spoofed local addresses\n");
850 	p(ipips_qfull, "\t%u packet%s were dropped due to full output queue\n");
851 	p(ipips_ibytes, "\t%qu input byte%s\n");
852 	p(ipips_obytes, "\t%qu output byte%s\n");
853 	p(ipips_family, "\t%u protocol family mismatche%s\n");
854 	p(ipips_unspec, "\t%u attempt%s to use tunnel with unspecified endpoint(s)\n");
855 #undef p
856 }
857 
858 /*
859  * Dump CARP statistics structure.
860  */
861 void
862 carp_stats(u_long off, char *name)
863 {
864 	struct carpstats carpstat;
865 
866 	if (off == 0)
867 		return;
868 	kread(off, (char *)&carpstat, sizeof(carpstat));
869 	printf("%s:\n", name);
870 
871 #define p(f, m) if (carpstat.f || sflag <= 1) \
872 	printf(m, carpstat.f, plural(carpstat.f))
873 #define p2(f, m) if (carpstat.f || sflag <= 1) \
874 	printf(m, carpstat.f)
875 
876 	p(carps_ipackets, "\t%u packet%s received (IPv4)\n");
877 	p(carps_ipackets6, "\t%u packet%s received (IPv6)\n");
878 	p(carps_badif, "\t\t%u packet%s discarded for bad interface\n");
879 	p(carps_hdrops, "\t\t%u packet%s shorter than header\n");
880 	p(carps_badsum, "\t\t%u discarded for bad checksum%s\n");
881 	p(carps_badver,	"\t\t%u discarded packet%s with a bad version\n");
882 	p2(carps_badlen, "\t\t%u discarded because packet too short\n");
883 	p2(carps_badauth, "\t\t%u discarded for bad authentication\n");
884 	p2(carps_badvhid, "\t\t%u discarded for bad vhid\n");
885 	p2(carps_badaddrs, "\t\t%u discarded because of a bad address list\n");
886 	p(carps_opackets, "\t%u packet%s sent (IPv4)\n");
887 	p(carps_opackets6, "\t%u packet%s sent (IPv6)\n");
888 #if notyet
889 	p(carps_ostates, "\t\t%s state update%s sent\n");
890 #endif
891 #undef p
892 #undef p2
893 }
894 
895 /*
896  * Dump IPCOMP statistics structure.
897  */
898 void
899 ipcomp_stats(u_long off, char *name)
900 {
901 	struct ipcompstat ipcompstat;
902 
903 	if (off == 0)
904 		return;
905 	kread(off, (char *)&ipcompstat, sizeof (ipcompstat));
906 	printf("%s:\n", name);
907 
908 #define p(f, m) if (ipcompstat.f || sflag <= 1) \
909 	printf(m, ipcompstat.f, plural(ipcompstat.f))
910 
911 	p(ipcomps_input, "\t%u input IPCOMP packet%s\n");
912 	p(ipcomps_output, "\t%u output IPCOMP packet%s\n");
913 	p(ipcomps_nopf, "\t%u packet%s from unsupported protocol families\n");
914 	p(ipcomps_hdrops, "\t%u packet%s shorter than header shows\n");
915 	p(ipcomps_pdrops, "\t%u packet%s dropped due to policy\n");
916 	p(ipcomps_notdb, "\t%u packet%s for which no TDB was found\n");
917 	p(ipcomps_badkcr, "\t%u input packet%s that failed to be processed\n");
918 	p(ipcomps_noxform, "\t%u packet%s for which no XFORM was set in TDB received\n");
919 	p(ipcomps_qfull, "\t%u packet%s were dropped due to full output queue\n");
920 	p(ipcomps_wrap, "\t%u packet%s where counter wrapping was detected\n");
921 	p(ipcomps_invalid, "\t%u packet%s attempted to use an invalid TDB\n");
922 	p(ipcomps_toobig, "\t%u packet%s got larger than max IP packet size\n");
923 	p(ipcomps_crypto, "\t%u packet%s that failed (de)compression processing\n");
924 	p(ipcomps_minlen, "\t%u packet%s less than minimum compression length\n");
925 	p(ipcomps_ibytes, "\t%qu input byte%s\n");
926 	p(ipcomps_obytes, "\t%qu output byte%s\n");
927 
928 #undef p
929 }
930