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