Home | History | Annotate | Line # | Download | only in netstat
inet.c revision 1.83
      1 /*	$NetBSD: inet.c,v 1.83 2008/04/08 01:03:58 thorpej Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1983, 1988, 1993
      5  *	The Regents of the University of California.  All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. Neither the name of the University nor the names of its contributors
     16  *    may be used to endorse or promote products derived from this software
     17  *    without specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29  * SUCH DAMAGE.
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 #ifndef lint
     34 #if 0
     35 static char sccsid[] = "from: @(#)inet.c	8.4 (Berkeley) 4/20/94";
     36 #else
     37 __RCSID("$NetBSD: inet.c,v 1.83 2008/04/08 01:03:58 thorpej Exp $");
     38 #endif
     39 #endif /* not lint */
     40 
     41 #define	_CALLOUT_PRIVATE	/* for defs in sys/callout.h */
     42 
     43 #include <sys/param.h>
     44 #include <sys/queue.h>
     45 #include <sys/socket.h>
     46 #include <sys/socketvar.h>
     47 #include <sys/mbuf.h>
     48 #include <sys/protosw.h>
     49 #include <sys/sysctl.h>
     50 
     51 #include <net/if_arp.h>
     52 #include <net/route.h>
     53 #include <netinet/in.h>
     54 #include <netinet/in_systm.h>
     55 #include <netinet/ip.h>
     56 #include <netinet/in_pcb.h>
     57 #include <netinet/ip_icmp.h>
     58 
     59 #ifdef INET6
     60 #include <netinet/ip6.h>
     61 #endif
     62 
     63 #include <netinet/icmp_var.h>
     64 #include <netinet/igmp_var.h>
     65 #include <netinet/ip_var.h>
     66 #include <netinet/pim_var.h>
     67 #include <netinet/tcp.h>
     68 #include <netinet/tcpip.h>
     69 #include <netinet/tcp_seq.h>
     70 #define TCPSTATES
     71 #include <netinet/tcp_fsm.h>
     72 #define	TCPTIMERS
     73 #include <netinet/tcp_timer.h>
     74 #include <netinet/tcp_var.h>
     75 #include <netinet/tcp_debug.h>
     76 #include <netinet/udp.h>
     77 #include <netinet/ip_carp.h>
     78 #include <netinet/udp_var.h>
     79 
     80 #include <arpa/inet.h>
     81 #include <kvm.h>
     82 #include <netdb.h>
     83 #include <stdio.h>
     84 #include <string.h>
     85 #include <unistd.h>
     86 #include <stdlib.h>
     87 #include <err.h>
     88 #include "netstat.h"
     89 
     90 struct	inpcb inpcb;
     91 struct	tcpcb tcpcb;
     92 struct	socket sockb;
     93 
     94 char	*inetname __P((struct in_addr *));
     95 void	inetprint __P((struct in_addr *, u_int16_t, const char *, int));
     96 
     97 /*
     98  * Print a summary of connections related to an Internet
     99  * protocol.  For TCP, also give state of connection.
    100  * Listening processes (aflag) are suppressed unless the
    101  * -a (all) flag is specified.
    102  */
    103 static int width;
    104 static int compact;
    105 
    106 static void
    107 protoprhdr(void)
    108 {
    109 	printf("Active Internet connections");
    110 	if (aflag)
    111 		printf(" (including servers)");
    112 	putchar('\n');
    113 	if (Aflag)
    114 		printf("%-8.8s ", "PCB");
    115 	printf("%-5.5s %-6.6s %-6.6s %s%-*.*s %-*.*s %s\n",
    116 		"Proto", "Recv-Q", "Send-Q", compact ? "" : " ",
    117 		width, width, "Local Address",
    118 		width, width, "Foreign Address",
    119 		"State");
    120 }
    121 
    122 static void
    123 protopr0(intptr_t ppcb, u_long rcv_sb_cc, u_long snd_sb_cc,
    124 	 struct in_addr *laddr, u_int16_t lport,
    125 	 struct in_addr *faddr, u_int16_t fport,
    126 	 short t_state, char *name)
    127 {
    128 	static const char *shorttcpstates[] = {
    129 		"CLOSED",	"LISTEN",	"SYNSEN",	"SYSRCV",
    130 		"ESTABL",	"CLWAIT",	"FWAIT1",	"CLOSNG",
    131 		"LASTAK",	"FWAIT2",	"TMWAIT",
    132 	};
    133 	int istcp;
    134 
    135 	istcp = strcmp(name, "tcp") == 0;
    136 
    137 	if (Aflag) {
    138 		printf("%8" PRIxPTR " ", ppcb);
    139 	}
    140 	printf("%-5.5s %6ld %6ld%s", name, rcv_sb_cc, snd_sb_cc,
    141 	       compact ? "" : " ");
    142 	if (numeric_port) {
    143 		inetprint(laddr, lport, name, 1);
    144 		inetprint(faddr, fport, name, 1);
    145 	} else if (inpcb.inp_flags & INP_ANONPORT) {
    146 		inetprint(laddr, lport, name, 1);
    147 		inetprint(faddr, fport, name, 0);
    148 	} else {
    149 		inetprint(laddr, lport, name, 0);
    150 		inetprint(faddr, fport, name, 0);
    151 	}
    152 	if (istcp) {
    153 		if (t_state < 0 || t_state >= TCP_NSTATES)
    154 			printf(" %d", t_state);
    155 		else
    156 			printf(" %s", compact ? shorttcpstates[t_state] :
    157 			       tcpstates[t_state]);
    158 	}
    159 	putchar('\n');
    160 }
    161 
    162 void
    163 protopr(off, name)
    164 	u_long off;
    165 	char *name;
    166 {
    167 	struct inpcbtable table;
    168 	struct inpcb *head, *next, *prev;
    169 	struct inpcb inpcb;
    170 	int istcp;
    171 	static int first = 1;
    172 
    173 	compact = 0;
    174 	if (Aflag) {
    175 		if (!numeric_addr)
    176 			width = 18;
    177 		else {
    178 			width = 21;
    179 			compact = 1;
    180 		}
    181 	} else
    182 		width = 22;
    183 
    184 	if (use_sysctl) {
    185 		struct kinfo_pcb *pcblist;
    186 		int mib[8];
    187 		size_t namelen = 0, size = 0, i;
    188 		char *mibname = NULL;
    189 
    190 		memset(mib, 0, sizeof(mib));
    191 
    192 		if (asprintf(&mibname, "net.inet.%s.pcblist", name) == -1)
    193 			err(1, "asprintf");
    194 
    195 		/* get dynamic pcblist node */
    196 		if (sysctlnametomib(mibname, mib, &namelen) == -1)
    197 			err(1, "sysctlnametomib: %s", mibname);
    198 
    199 		if (sysctl(mib, sizeof(mib) / sizeof(*mib), NULL, &size,
    200 			   NULL, 0) == -1)
    201 			err(1, "sysctl (query)");
    202 
    203 		if ((pcblist = malloc(size)) == NULL)
    204 			err(1, "malloc");
    205 		memset(pcblist, 0, size);
    206 
    207 	        mib[6] = sizeof(*pcblist);
    208         	mib[7] = size / sizeof(*pcblist);
    209 
    210 		if (sysctl(mib, sizeof(mib) / sizeof(*mib), pcblist,
    211 			   &size, NULL, 0) == -1)
    212 			err(1, "sysctl (copy)");
    213 
    214 		for (i = 0; i < size / sizeof(*pcblist); i++) {
    215 			struct sockaddr_in src, dst;
    216 
    217 			memcpy(&src, &pcblist[i].ki_s, sizeof(src));
    218 			memcpy(&dst, &pcblist[i].ki_d, sizeof(dst));
    219 
    220 			if (first) {
    221 				protoprhdr();
    222 				first = 0;
    223 			}
    224 
    225 	                protopr0((intptr_t) pcblist[i].ki_ppcbaddr,
    226 				 pcblist[i].ki_rcvq, pcblist[i].ki_sndq,
    227 				 &src.sin_addr, src.sin_port,
    228 				 &dst.sin_addr, dst.sin_port,
    229 				 pcblist[i].ki_tstate, name);
    230 		}
    231 
    232 		free(pcblist);
    233 		return;
    234 	}
    235 
    236 	if (off == 0)
    237 		return;
    238 	istcp = strcmp(name, "tcp") == 0;
    239 	kread(off, (char *)&table, sizeof table);
    240 	prev = head =
    241 	    (struct inpcb *)&((struct inpcbtable *)off)->inpt_queue.cqh_first;
    242 	next = (struct inpcb *)table.inpt_queue.cqh_first;
    243 
    244 	while (next != head) {
    245 		kread((u_long)next, (char *)&inpcb, sizeof inpcb);
    246 		if ((struct inpcb *)inpcb.inp_queue.cqe_prev != prev) {
    247 			printf("???\n");
    248 			break;
    249 		}
    250 		prev = next;
    251 		next = (struct inpcb *)inpcb.inp_queue.cqe_next;
    252 
    253 		if (inpcb.inp_af != AF_INET)
    254 			continue;
    255 
    256 		if (!aflag &&
    257 		    inet_lnaof(inpcb.inp_laddr) == INADDR_ANY)
    258 			continue;
    259 		kread((u_long)inpcb.inp_socket, (char *)&sockb, sizeof (sockb));
    260 		if (istcp) {
    261 			kread((u_long)inpcb.inp_ppcb,
    262 			    (char *)&tcpcb, sizeof (tcpcb));
    263 		}
    264 
    265 		if (first) {
    266 			protoprhdr();
    267 			first = 0;
    268 		}
    269 
    270 		protopr0(istcp ? (intptr_t) inpcb.inp_ppcb : (intptr_t) prev,
    271 			 sockb.so_rcv.sb_cc, sockb.so_snd.sb_cc,
    272 			 &inpcb.inp_laddr, inpcb.inp_lport,
    273 			 &inpcb.inp_faddr, inpcb.inp_fport,
    274 			 tcpcb.t_state, name);
    275 	}
    276 }
    277 
    278 /*
    279  * Dump TCP statistics structure.
    280  */
    281 void
    282 tcp_stats(u_long off, char *name)
    283 {
    284 	uint64_t tcpstat[TCP_NSTATS];
    285 
    286 	if (use_sysctl) {
    287 		size_t size = sizeof(tcpstat);
    288 
    289 		if (sysctlbyname("net.inet.tcp.stats", tcpstat, &size,
    290 				 NULL, 0) == -1)
    291 			err(1, "net.inet.tcp.stats");
    292 	} else {
    293 		if (off == 0)
    294 			return;
    295 		kread(off, (char *)tcpstat, sizeof (tcpstat));
    296 	}
    297 
    298 	printf ("%s:\n", name);
    299 
    300 #define	ps(f, m) if (tcpstat[f] || sflag <= 1) \
    301     printf(m, (unsigned long long)tcpstat[f])
    302 #define	p(f, m) if (tcpstat[f] || sflag <= 1) \
    303     printf(m, (unsigned long long)tcpstat[f], plural(tcpstat[f]))
    304 #define	p2(f1, f2, m) if (tcpstat[f1] || tcpstat[f2] || sflag <= 1) \
    305     printf(m, (unsigned long long)tcpstat[f1], plural(tcpstat[f1]), \
    306     (unsigned long long)tcpstat[f2], plural(tcpstat[f2]))
    307 #define	p2s(f1, f2, m) if (tcpstat[f1] || tcpstat[f2] || sflag <= 1) \
    308     printf(m, (unsigned long long)tcpstat[f1], plural(tcpstat[f1]), \
    309     (unsigned long long)tcpstat[f2])
    310 #define	p3(f, m) if (tcpstat[f] || sflag <= 1) \
    311     printf(m, (unsigned long long)tcpstat[f], plurales(tcpstat[f]))
    312 
    313 	p(TCP_STAT_SNDTOTAL, "\t%llu packet%s sent\n");
    314 	p2(TCP_STAT_SNDPACK,TCP_STAT_SNDBYTE,
    315 		"\t\t%llu data packet%s (%llu byte%s)\n");
    316 	p2(TCP_STAT_SNDREXMITPACK, TCP_STAT_SNDREXMITBYTE,
    317 		"\t\t%llu data packet%s (%llu byte%s) retransmitted\n");
    318 	p2s(TCP_STAT_SNDACKS, TCP_STAT_DELACK,
    319 		"\t\t%llu ack-only packet%s (%llu delayed)\n");
    320 	p(TCP_STAT_SNDURG, "\t\t%llu URG only packet%s\n");
    321 	p(TCP_STAT_SNDPROBE, "\t\t%llu window probe packet%s\n");
    322 	p(TCP_STAT_SNDWINUP, "\t\t%llu window update packet%s\n");
    323 	p(TCP_STAT_SNDCTRL, "\t\t%llu control packet%s\n");
    324 	p(TCP_STAT_SELFQUENCH,
    325 	    "\t\t%llu send attempt%s resulted in self-quench\n");
    326 	p(TCP_STAT_RCVTOTAL, "\t%llu packet%s received\n");
    327 	p2(TCP_STAT_RCVACKPACK, TCP_STAT_RCVACKBYTE,
    328 		"\t\t%llu ack%s (for %llu byte%s)\n");
    329 	p(TCP_STAT_RCVDUPACK, "\t\t%llu duplicate ack%s\n");
    330 	p(TCP_STAT_RCVACKTOOMUCH, "\t\t%llu ack%s for unsent data\n");
    331 	p2(TCP_STAT_RCVPACK, TCP_STAT_RCVBYTE,
    332 		"\t\t%llu packet%s (%llu byte%s) received in-sequence\n");
    333 	p2(TCP_STAT_RCVDUPPACK, TCP_STAT_RCVDUPBYTE,
    334 		"\t\t%llu completely duplicate packet%s (%llu byte%s)\n");
    335 	p(TCP_STAT_PAWSDROP, "\t\t%llu old duplicate packet%s\n");
    336 	p2(TCP_STAT_RCVPARTDUPPACK, TCP_STAT_RCVPARTDUPBYTE,
    337 		"\t\t%llu packet%s with some dup. data (%llu byte%s duped)\n");
    338 	p2(TCP_STAT_RCVOOPACK, TCP_STAT_RCVOOBYTE,
    339 		"\t\t%llu out-of-order packet%s (%llu byte%s)\n");
    340 	p2(TCP_STAT_RCVPACKAFTERWIN, TCP_STAT_RCVBYTEAFTERWIN,
    341 		"\t\t%llu packet%s (%llu byte%s) of data after window\n");
    342 	p(TCP_STAT_RCVWINPROBE, "\t\t%llu window probe%s\n");
    343 	p(TCP_STAT_RCVWINUPD, "\t\t%llu window update packet%s\n");
    344 	p(TCP_STAT_RCVAFTERCLOSE, "\t\t%llu packet%s received after close\n");
    345 	p(TCP_STAT_RCVBADSUM, "\t\t%llu discarded for bad checksum%s\n");
    346 	p(TCP_STAT_RCVBADOFF, "\t\t%llu discarded for bad header offset field%s\n");
    347 	ps(TCP_STAT_RCVSHORT, "\t\t%llu discarded because packet too short\n");
    348 	p(TCP_STAT_CONNATTEMPT, "\t%llu connection request%s\n");
    349 	p(TCP_STAT_ACCEPTS, "\t%llu connection accept%s\n");
    350 	p(TCP_STAT_CONNECTS,
    351 		"\t%llu connection%s established (including accepts)\n");
    352 	p2(TCP_STAT_CLOSED, TCP_STAT_DROPS,
    353 		"\t%llu connection%s closed (including %llu drop%s)\n");
    354 	p(TCP_STAT_CONNDROPS, "\t%llu embryonic connection%s dropped\n");
    355 	p(TCP_STAT_DELAYED_FREE, "\t%llu delayed free%s of tcpcb\n");
    356 	p2(TCP_STAT_RTTUPDATED, TCP_STAT_SEGSTIMED,
    357 		"\t%llu segment%s updated rtt (of %llu attempt%s)\n");
    358 	p(TCP_STAT_REXMTTIMEO, "\t%llu retransmit timeout%s\n");
    359 	p(TCP_STAT_TIMEOUTDROP,
    360 		"\t\t%llu connection%s dropped by rexmit timeout\n");
    361 	p2(TCP_STAT_PERSISTTIMEO, TCP_STAT_PERSISTDROPS,
    362 	   "\t%llu persist timeout%s (resulting in %llu dropped "
    363 		"connection%s)\n");
    364 	p(TCP_STAT_KEEPTIMEO, "\t%llu keepalive timeout%s\n");
    365 	p(TCP_STAT_KEEPPROBE, "\t\t%llu keepalive probe%s sent\n");
    366 	p(TCP_STAT_KEEPDROPS, "\t\t%llu connection%s dropped by keepalive\n");
    367 	p(TCP_STAT_PREDACK, "\t%llu correct ACK header prediction%s\n");
    368 	p(TCP_STAT_PREDDAT, "\t%llu correct data packet header prediction%s\n");
    369 	p3(TCP_STAT_PCBHASHMISS, "\t%llu PCB hash miss%s\n");
    370 	ps(TCP_STAT_NOPORT, "\t%llu dropped due to no socket\n");
    371 	p(TCP_STAT_CONNSDRAINED, "\t%llu connection%s drained due to memory "
    372 		"shortage\n");
    373 	p(TCP_STAT_PMTUBLACKHOLE, "\t%llu PMTUD blackhole%s detected\n");
    374 
    375 	p(TCP_STAT_BADSYN, "\t%llu bad connection attempt%s\n");
    376 	ps(TCP_STAT_SC_ADDED, "\t%llu SYN cache entries added\n");
    377 	p(TCP_STAT_SC_COLLISIONS, "\t\t%llu hash collision%s\n");
    378 	ps(TCP_STAT_SC_COMPLETED, "\t\t%llu completed\n");
    379 	ps(TCP_STAT_SC_ABORTED, "\t\t%llu aborted (no space to build PCB)\n");
    380 	ps(TCP_STAT_SC_TIMED_OUT, "\t\t%llu timed out\n");
    381 	ps(TCP_STAT_SC_OVERFLOWED, "\t\t%llu dropped due to overflow\n");
    382 	ps(TCP_STAT_SC_BUCKETOVERFLOW, "\t\t%llu dropped due to bucket overflow\n");
    383 	ps(TCP_STAT_SC_RESET, "\t\t%llu dropped due to RST\n");
    384 	ps(TCP_STAT_SC_UNREACH, "\t\t%llu dropped due to ICMP unreachable\n");
    385 	ps(TCP_STAT_SC_DELAYED_FREE, "\t\t%llu delayed free of SYN cache "
    386 		"entries\n");
    387 	p(TCP_STAT_SC_RETRANSMITTED, "\t%llu SYN,ACK%s retransmitted\n");
    388 	p(TCP_STAT_SC_DUPESYN, "\t%llu duplicate SYN%s received for entries "
    389 		"already in the cache\n");
    390 	p(TCP_STAT_SC_DROPPED, "\t%llu SYN%s dropped (no route or no space)\n");
    391 	p(TCP_STAT_BADSIG, "\t%llu packet%s with bad signature\n");
    392 	p(TCP_STAT_GOODSIG, "\t%llu packet%s with good signature\n");
    393 
    394 	p(TCP_STAT_ECN_SHS, "\t%llu sucessful ECN handshake%s\n");
    395 	p(TCP_STAT_ECN_CE, "\t%llu packet%s with ECN CE bit\n");
    396 	p(TCP_STAT_ECN_ECT, "\t%llu packet%s ECN ECT(0) bit\n");
    397 #undef p
    398 #undef ps
    399 #undef p2
    400 #undef p2s
    401 #undef p3
    402 }
    403 
    404 /*
    405  * Dump UDP statistics structure.
    406  */
    407 void
    408 udp_stats(u_long off, char *name)
    409 {
    410 	uint64_t udpstat[UDP_NSTATS];
    411 	u_quad_t delivered;
    412 
    413 	if (use_sysctl) {
    414 		size_t size = sizeof(udpstat);
    415 
    416 		if (sysctlbyname("net.inet.udp.stats", udpstat, &size,
    417 				 NULL, 0) == -1)
    418 			err(1, "net.inet.udp.stats");
    419 	} else {
    420 		if (off == 0)
    421 			return;
    422 		kread(off, (char *)udpstat, sizeof (udpstat));
    423 	}
    424 
    425 	printf ("%s:\n", name);
    426 
    427 #define	ps(f, m) if (udpstat[f] || sflag <= 1) \
    428     printf(m, (unsigned long long)udpstat[f])
    429 #define	p(f, m) if (udpstat[f] || sflag <= 1) \
    430     printf(m, (unsigned long long)udpstat[f], plural(udpstat[f]))
    431 #define	p3(f, m) if (udpstat[f] || sflag <= 1) \
    432     printf(m, (unsigned long long)udpstat[f], plurales(udpstat[f]))
    433 
    434 	p(UDP_STAT_IPACKETS, "\t%llu datagram%s received\n");
    435 	ps(UDP_STAT_HDROPS, "\t%llu with incomplete header\n");
    436 	ps(UDP_STAT_BADLEN, "\t%llu with bad data length field\n");
    437 	ps(UDP_STAT_BADSUM, "\t%llu with bad checksum\n");
    438 	ps(UDP_STAT_NOPORT, "\t%llu dropped due to no socket\n");
    439 	p(UDP_STAT_NOPORTBCAST,
    440 	  "\t%llu broadcast/multicast datagram%s dropped due to no socket\n");
    441 	ps(UDP_STAT_FULLSOCK, "\t%llu dropped due to full socket buffers\n");
    442 	delivered = udpstat[UDP_STAT_IPACKETS] -
    443 		    udpstat[UDP_STAT_HDROPS] -
    444 		    udpstat[UDP_STAT_BADLEN] -
    445 		    udpstat[UDP_STAT_BADSUM] -
    446 		    udpstat[UDP_STAT_NOPORT] -
    447 		    udpstat[UDP_STAT_NOPORTBCAST] -
    448 		    udpstat[UDP_STAT_FULLSOCK];
    449 	if (delivered || sflag <= 1)
    450 		printf("\t%llu delivered\n", (unsigned long long)delivered);
    451 	p3(UDP_STAT_PCBHASHMISS, "\t%llu PCB hash miss%s\n");
    452 	p(UDP_STAT_OPACKETS, "\t%llu datagram%s output\n");
    453 
    454 #undef ps
    455 #undef p
    456 #undef p3
    457 }
    458 
    459 /*
    460  * Dump IP statistics structure.
    461  */
    462 void
    463 ip_stats(u_long off, char *name)
    464 {
    465 	uint64_t ipstat[IP_NSTATS];
    466 
    467 	if (use_sysctl) {
    468 		size_t size = sizeof(ipstat);
    469 
    470 		if (sysctlbyname("net.inet.ip.stats", ipstat, &size,
    471 				 NULL, 0) == -1)
    472 			err(1, "net.inet.ip.stats");
    473 	} else {
    474 		if (off == 0)
    475 			return;
    476 		kread(off, (char *)ipstat, sizeof (ipstat));
    477 	}
    478 
    479 	printf("%s:\n", name);
    480 
    481 #define	ps(f, m) if (ipstat[f] || sflag <= 1) \
    482     printf(m, (unsigned long long)ipstat[f])
    483 #define	p(f, m) if (ipstat[f] || sflag <= 1) \
    484     printf(m, (unsigned long long)ipstat[f], plural(ipstat[f]))
    485 
    486 	p(IP_STAT_TOTAL, "\t%llu total packet%s received\n");
    487 	p(IP_STAT_BADSUM, "\t%llu bad header checksum%s\n");
    488 	ps(IP_STAT_TOOSMALL, "\t%llu with size smaller than minimum\n");
    489 	ps(IP_STAT_TOOSHORT, "\t%llu with data size < data length\n");
    490 	ps(IP_STAT_TOOLONG, "\t%llu with length > max ip packet size\n");
    491 	ps(IP_STAT_BADHLEN, "\t%llu with header length < data size\n");
    492 	ps(IP_STAT_BADLEN, "\t%llu with data length < header length\n");
    493 	ps(IP_STAT_BADOPTIONS, "\t%llu with bad options\n");
    494 	ps(IP_STAT_BADVERS, "\t%llu with incorrect version number\n");
    495 	p(IP_STAT_FRAGMENTS, "\t%llu fragment%s received\n");
    496 	p(IP_STAT_FRAGDROPPED, "\t%llu fragment%s dropped (dup or out of space)\n");
    497 	p(IP_STAT_RCVMEMDROP, "\t%llu fragment%s dropped (out of ipqent)\n");
    498 	p(IP_STAT_BADFRAGS, "\t%llu malformed fragment%s dropped\n");
    499 	p(IP_STAT_FRAGTIMEOUT, "\t%llu fragment%s dropped after timeout\n");
    500 	p(IP_STAT_REASSEMBLED, "\t%llu packet%s reassembled ok\n");
    501 	p(IP_STAT_DELIVERED, "\t%llu packet%s for this host\n");
    502 	p(IP_STAT_NOPROTO, "\t%llu packet%s for unknown/unsupported protocol\n");
    503 	p(IP_STAT_FORWARD, "\t%llu packet%s forwarded");
    504 	p(IP_STAT_FASTFORWARD, " (%llu packet%s fast forwarded)");
    505 	if (ipstat[IP_STAT_FORWARD] || sflag <= 1)
    506 		putchar('\n');
    507 	p(IP_STAT_CANTFORWARD, "\t%llu packet%s not forwardable\n");
    508 	p(IP_STAT_REDIRECTSENT, "\t%llu redirect%s sent\n");
    509 	p(IP_STAT_NOGIF, "\t%llu packet%s no matching gif found\n");
    510 	p(IP_STAT_LOCALOUT, "\t%llu packet%s sent from this host\n");
    511 	p(IP_STAT_RAWOUT, "\t%llu packet%s sent with fabricated ip header\n");
    512 	p(IP_STAT_ODROPPED, "\t%llu output packet%s dropped due to no bufs, etc.\n");
    513 	p(IP_STAT_NOROUTE, "\t%llu output packet%s discarded due to no route\n");
    514 	p(IP_STAT_FRAGMENTED, "\t%llu output datagram%s fragmented\n");
    515 	p(IP_STAT_OFRAGMENTS, "\t%llu fragment%s created\n");
    516 	p(IP_STAT_CANTFRAG, "\t%llu datagram%s that can't be fragmented\n");
    517 	p(IP_STAT_BADADDR, "\t%llu datagram%s with bad address in header\n");
    518 #undef ps
    519 #undef p
    520 }
    521 
    522 static	const char *icmpnames[] = {
    523 	"echo reply",
    524 	"#1",
    525 	"#2",
    526 	"destination unreachable",
    527 	"source quench",
    528 	"routing redirect",
    529 	"alternate host address",
    530 	"#7",
    531 	"echo",
    532 	"router advertisement",
    533 	"router solicitation",
    534 	"time exceeded",
    535 	"parameter problem",
    536 	"time stamp",
    537 	"time stamp reply",
    538 	"information request",
    539 	"information request reply",
    540 	"address mask request",
    541 	"address mask reply",
    542 };
    543 
    544 /*
    545  * Dump ICMP statistics.
    546  */
    547 void
    548 icmp_stats(u_long off, char *name)
    549 {
    550 	uint64_t icmpstat[ICMP_NSTATS];
    551 	int i, first;
    552 
    553 	if (use_sysctl) {
    554 		size_t size = sizeof(icmpstat);
    555 
    556 		if (sysctlbyname("net.inet.icmp.stats", icmpstat, &size,
    557 				 NULL, 0) == -1)
    558 			err(1, "net.inet.icmp.stats");
    559 	} else {
    560 		if (off == 0)
    561 			return;
    562 		kread(off, (char *)icmpstat, sizeof (icmpstat));
    563 	}
    564 
    565 	printf("%s:\n", name);
    566 
    567 #define	p(f, m) if (icmpstat[f] || sflag <= 1) \
    568     printf(m, (unsigned long long)icmpstat[f], plural(icmpstat[f]))
    569 
    570 	p(ICMP_STAT_ERROR, "\t%llu call%s to icmp_error\n");
    571 	p(ICMP_STAT_OLDICMP,
    572 	    "\t%llu error%s not generated because old message was icmp\n");
    573 	for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
    574 		if (icmpstat[ICMP_STAT_OUTHIST + i] != 0) {
    575 			if (first) {
    576 				printf("\tOutput histogram:\n");
    577 				first = 0;
    578 			}
    579 			printf("\t\t%s: %llu\n", icmpnames[i],
    580 			   (unsigned long long)icmpstat[ICMP_STAT_OUTHIST + i]);
    581 		}
    582 	p(ICMP_STAT_BADCODE, "\t%llu message%s with bad code fields\n");
    583 	p(ICMP_STAT_TOOSHORT, "\t%llu message%s < minimum length\n");
    584 	p(ICMP_STAT_CHECKSUM, "\t%llu bad checksum%s\n");
    585 	p(ICMP_STAT_BADLEN, "\t%llu message%s with bad length\n");
    586 	for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
    587 		if (icmpstat[ICMP_STAT_INHIST + i] != 0) {
    588 			if (first) {
    589 				printf("\tInput histogram:\n");
    590 				first = 0;
    591 			}
    592 			printf("\t\t%s: %llu\n", icmpnames[i],
    593 			    (unsigned long long)icmpstat[ICMP_STAT_INHIST + i]);
    594 		}
    595 	p(ICMP_STAT_REFLECT, "\t%llu message response%s generated\n");
    596 	p(ICMP_STAT_PMTUCHG, "\t%llu path MTU change%s\n");
    597 #undef p
    598 }
    599 
    600 /*
    601  * Dump IGMP statistics structure.
    602  */
    603 void
    604 igmp_stats(off, name)
    605 	u_long off;
    606 	char *name;
    607 {
    608 	struct igmpstat igmpstat;
    609 
    610 	if (off == 0)
    611 		return;
    612 	kread(off, (char *)&igmpstat, sizeof (igmpstat));
    613 	printf("%s:\n", name);
    614 
    615 #define	p(f, m) if (igmpstat.f || sflag <= 1) \
    616     printf(m, (unsigned long long)igmpstat.f, plural(igmpstat.f))
    617 #define	py(f, m) if (igmpstat.f || sflag <= 1) \
    618     printf(m, (unsigned long long)igmpstat.f, igmpstat.f != 1 ? "ies" : "y")
    619 	p(igps_rcv_total, "\t%llu message%s received\n");
    620         p(igps_rcv_tooshort, "\t%llu message%s received with too few bytes\n");
    621         p(igps_rcv_badsum, "\t%llu message%s received with bad checksum\n");
    622         py(igps_rcv_queries, "\t%llu membership quer%s received\n");
    623         py(igps_rcv_badqueries, "\t%llu membership quer%s received with invalid field(s)\n");
    624         p(igps_rcv_reports, "\t%llu membership report%s received\n");
    625         p(igps_rcv_badreports, "\t%llu membership report%s received with invalid field(s)\n");
    626         p(igps_rcv_ourreports, "\t%llu membership report%s received for groups to which we belong\n");
    627         p(igps_snd_reports, "\t%llu membership report%s sent\n");
    628 #undef p
    629 #undef py
    630 }
    631 
    632 /*
    633  * Dump CARP statistics structure.
    634  */
    635 void
    636 carp_stats(u_long off, char *name)
    637 {
    638 	struct carpstats carpstat;
    639 
    640 	if (use_sysctl) {
    641 		size_t size = sizeof(carpstat);
    642 
    643 		if (sysctlbyname("net.inet.carp.stats", &carpstat, &size,
    644 				 NULL, 0) == -1) {
    645 			/* most likely CARP is not compiled in the kernel */
    646 			return;
    647 		}
    648 	} else {
    649 		if (off == 0)
    650 			return;
    651 		kread(off, (char *)&carpstat, sizeof(carpstat));
    652 	}
    653 
    654 	printf("%s:\n", name);
    655 
    656 #define p(f, m) if (carpstat.f || sflag <= 1) \
    657 	printf(m, carpstat.f, plural(carpstat.f))
    658 #define p2(f, m) if (carpstat.f || sflag <= 1) \
    659 	printf(m, carpstat.f)
    660 
    661 	p(carps_ipackets, "\t%" PRIu64 " packet%s received (IPv4)\n");
    662 	p(carps_ipackets6, "\t%" PRIu64 " packet%s received (IPv6)\n");
    663 	p(carps_badif,
    664 	    "\t\t%" PRIu64 " packet%s discarded for bad interface\n");
    665 	p(carps_badttl,
    666 	    "\t\t%" PRIu64 " packet%s discarded for wrong TTL\n");
    667 	p(carps_hdrops, "\t\t%" PRIu64 " packet%s shorter than header\n");
    668 	p(carps_badsum, "\t\t%" PRIu64
    669 		" packet%s discarded for bad checksum\n");
    670 	p(carps_badver,
    671 	    "\t\t%" PRIu64 " packet%s discarded with a bad version\n");
    672 	p2(carps_badlen,
    673 	    "\t\t%" PRIu64 " discarded because packet was too short\n");
    674 	p(carps_badauth,
    675 	    "\t\t%" PRIu64 " packet%s discarded for bad authentication\n");
    676 	p(carps_badvhid, "\t\t%" PRIu64 " packet%s discarded for bad vhid\n");
    677 	p(carps_badaddrs, "\t\t%" PRIu64
    678 		" packet%s discarded because of a bad address list\n");
    679 	p(carps_opackets, "\t%" PRIu64 " packet%s sent (IPv4)\n");
    680 	p(carps_opackets6, "\t%" PRIu64 " packet%s sent (IPv6)\n");
    681 	p2(carps_onomem,
    682 	    "\t\t%" PRIu64 " send failed due to mbuf memory error\n");
    683 #undef p
    684 #undef p2
    685 }
    686 
    687 /*
    688  * Dump PIM statistics structure.
    689  */
    690 void
    691 pim_stats(off, name)
    692 	u_long off;
    693 	char *name;
    694 {
    695 	struct pimstat pimstat;
    696 
    697 	if (off == 0)
    698 		return;
    699 	if (kread(off, (char *)&pimstat, sizeof (pimstat)) != 0) {
    700 		/* XXX: PIM is probably not enabled in the kernel */
    701 		return;
    702 	}
    703 
    704 	printf("%s:\n", name);
    705 
    706 #define	p(f, m) if (pimstat.f || sflag <= 1) \
    707 	printf(m, (unsigned long long)pimstat.f, plural(pimstat.f))
    708 
    709 	p(pims_rcv_total_msgs, "\t%llu message%s received\n");
    710 	p(pims_rcv_total_bytes, "\t%llu byte%s received\n");
    711 	p(pims_rcv_tooshort, "\t%llu message%s received with too few bytes\n");
    712         p(pims_rcv_badsum, "\t%llu message%s received with bad checksum\n");
    713 	p(pims_rcv_badversion, "\t%llu message%s received with bad version\n");
    714 	p(pims_rcv_registers_msgs, "\t%llu data register message%s received\n");
    715 	p(pims_rcv_registers_bytes, "\t%llu data register byte%s received\n");
    716 	p(pims_rcv_registers_wrongiif, "\t%llu data register message%s received on wrong iif\n");
    717 	p(pims_rcv_badregisters, "\t%llu bad register%s received\n");
    718 	p(pims_snd_registers_msgs, "\t%llu data register message%s sent\n");
    719 	p(pims_snd_registers_bytes, "\t%llu data register byte%s sent\n");
    720 #undef p
    721 }
    722 
    723 /*
    724  * Dump the ARP statistics structure.
    725  */
    726 void
    727 arp_stats(off, name)
    728 	u_long off;
    729 	char *name;
    730 {
    731 	struct arpstat arpstat;
    732 
    733 	if (off == 0)
    734 		return;
    735 	kread(off, (char *)&arpstat, sizeof (arpstat));
    736 	printf("%s:\n", name);
    737 
    738 #define	ps(f, m) if (arpstat.f || sflag <= 1) \
    739     printf(m, (unsigned long long)arpstat.f)
    740 #define	p(f, m) if (arpstat.f || sflag <= 1) \
    741     printf(m, (unsigned long long)arpstat.f, plural(arpstat.f))
    742 
    743 	p(as_sndtotal, "\t%llu packet%s sent\n");
    744 	p(as_sndreply, "\t\t%llu reply packet%s\n");
    745 	p(as_sndrequest, "\t\t%llu request packet%s\n");
    746 
    747 	p(as_rcvtotal, "\t%llu packet%s received\n");
    748 	p(as_rcvreply, "\t\t%llu reply packet%s\n");
    749 	p(as_rcvrequest, "\t\t%llu valid request packet%s\n");
    750 	p(as_rcvmcast, "\t\t%llu broadcast/multicast packet%s\n");
    751 	p(as_rcvbadproto, "\t\t%llu packet%s with unknown protocol type\n");
    752 	p(as_rcvbadlen, "\t\t%llu packet%s with bad (short) length\n");
    753 	p(as_rcvzerotpa, "\t\t%llu packet%s with null target IP address\n");
    754 	p(as_rcvzerospa, "\t\t%llu packet%s with null source IP address\n");
    755 	ps(as_rcvnoint, "\t\t%llu could not be mapped to an interface\n");
    756 	p(as_rcvlocalsha, "\t\t%llu packet%s sourced from a local hardware "
    757 	    "address\n");
    758 	p(as_rcvbcastsha, "\t\t%llu packet%s with a broadcast "
    759 	    "source hardware address\n");
    760 	p(as_rcvlocalspa, "\t\t%llu duplicate%s for a local IP address\n");
    761 	p(as_rcvoverperm, "\t\t%llu attempt%s to overwrite a static entry\n");
    762 	p(as_rcvoverint, "\t\t%llu packet%s received on wrong interface\n");
    763 	p(as_rcvover, "\t\t%llu entry%s overwritten\n");
    764 	p(as_rcvlenchg, "\t\t%llu change%s in hardware address length\n");
    765 
    766 	p(as_dfrtotal, "\t%llu packet%s deferred pending ARP resolution\n");
    767 	ps(as_dfrsent, "\t\t%llu sent\n");
    768 	ps(as_dfrdropped, "\t\t%llu dropped\n");
    769 
    770 	p(as_allocfail, "\t%llu failure%s to allocate llinfo\n");
    771 
    772 #undef ps
    773 #undef p
    774 }
    775 
    776 /*
    777  * Pretty print an Internet address (net address + port).
    778  * Take numeric_addr and numeric_port into consideration.
    779  */
    780 void
    781 inetprint(in, port, proto, numeric_port)
    782 	struct in_addr *in;
    783 	u_int16_t port;
    784 	const char *proto;
    785 	int numeric_port;
    786 {
    787 	struct servent *sp = 0;
    788 	char line[80], *cp;
    789 	size_t space;
    790 
    791 	(void)snprintf(line, sizeof line, "%.*s.",
    792 	    (Aflag && !numeric_addr) ? 12 : 16, inetname(in));
    793 	cp = strchr(line, '\0');
    794 	if (!numeric_port && port)
    795 		sp = getservbyport((int)port, proto);
    796 	space = sizeof line - (cp-line);
    797 	if (sp || port == 0)
    798 		(void)snprintf(cp, space, "%s", sp ? sp->s_name : "*");
    799 	else
    800 		(void)snprintf(cp, space, "%u", ntohs(port));
    801 	(void)printf(" %-*.*s", width, width, line);
    802 }
    803 
    804 /*
    805  * Construct an Internet address representation.
    806  * If numeric_addr has been supplied, give
    807  * numeric value, otherwise try for symbolic name.
    808  */
    809 char *
    810 inetname(inp)
    811 	struct in_addr *inp;
    812 {
    813 	char *cp;
    814 	static char line[50];
    815 	struct hostent *hp;
    816 	struct netent *np;
    817 	static char domain[MAXHOSTNAMELEN + 1];
    818 	static int first = 1;
    819 
    820 	if (first && !numeric_addr) {
    821 		first = 0;
    822 		if (gethostname(domain, sizeof domain) == 0) {
    823 			domain[sizeof(domain) - 1] = '\0';
    824 			if ((cp = strchr(domain, '.')))
    825 				(void) strlcpy(domain, cp + 1, sizeof(domain));
    826 			else
    827 				domain[0] = 0;
    828 		} else
    829 			domain[0] = 0;
    830 	}
    831 	cp = 0;
    832 	if (!numeric_addr && inp->s_addr != INADDR_ANY) {
    833 		int net = inet_netof(*inp);
    834 		int lna = inet_lnaof(*inp);
    835 
    836 		if (lna == INADDR_ANY) {
    837 			np = getnetbyaddr(net, AF_INET);
    838 			if (np)
    839 				cp = np->n_name;
    840 		}
    841 		if (cp == 0) {
    842 			hp = gethostbyaddr((char *)inp, sizeof (*inp), AF_INET);
    843 			if (hp) {
    844 				if ((cp = strchr(hp->h_name, '.')) &&
    845 				    !strcmp(cp + 1, domain))
    846 					*cp = 0;
    847 				cp = hp->h_name;
    848 			}
    849 		}
    850 	}
    851 	if (inp->s_addr == INADDR_ANY)
    852 		strlcpy(line, "*", sizeof line);
    853 	else if (cp)
    854 		strlcpy(line, cp, sizeof line);
    855 	else {
    856 		inp->s_addr = ntohl(inp->s_addr);
    857 #define C(x)	((x) & 0xff)
    858 		(void)snprintf(line, sizeof line, "%u.%u.%u.%u",
    859 		    C(inp->s_addr >> 24), C(inp->s_addr >> 16),
    860 		    C(inp->s_addr >> 8), C(inp->s_addr));
    861 #undef C
    862 	}
    863 	return (line);
    864 }
    865 
    866 /*
    867  * Dump the contents of a TCP PCB.
    868  */
    869 void
    870 tcp_dump(pcbaddr)
    871 	u_long pcbaddr;
    872 {
    873 	callout_impl_t *ci;
    874 	struct tcpcb tcpcb;
    875 	int i, hardticks;
    876 
    877 	kread(pcbaddr, (char *)&tcpcb, sizeof(tcpcb));
    878 	hardticks = get_hardticks();
    879 
    880 	printf("TCP Protocol Control Block at 0x%08lx:\n\n", pcbaddr);
    881 
    882 	printf("Timers:\n");
    883 	for (i = 0; i < TCPT_NTIMERS; i++) {
    884 		ci = (callout_impl_t *)&tcpcb.t_timer[i];
    885 		printf("\t%s: %d", tcptimers[i],
    886 		    (ci->c_flags & CALLOUT_PENDING) ?
    887 		    ci->c_time - hardticks : 0);
    888 	}
    889 	printf("\n\n");
    890 
    891 	if (tcpcb.t_state < 0 || tcpcb.t_state >= TCP_NSTATES)
    892 		printf("State: %d", tcpcb.t_state);
    893 	else
    894 		printf("State: %s", tcpstates[tcpcb.t_state]);
    895 	printf(", flags 0x%x, inpcb 0x%lx, in6pcb 0x%lx\n\n", tcpcb.t_flags,
    896 	    (u_long)tcpcb.t_inpcb, (u_long)tcpcb.t_in6pcb);
    897 
    898 	printf("rxtshift %d, rxtcur %d, dupacks %d\n", tcpcb.t_rxtshift,
    899 	    tcpcb.t_rxtcur, tcpcb.t_dupacks);
    900 	printf("peermss %u, ourmss %u, segsz %u\n\n", tcpcb.t_peermss,
    901 	    tcpcb.t_ourmss, tcpcb.t_segsz);
    902 
    903 	printf("snd_una %u, snd_nxt %u, snd_up %u\n",
    904 	    tcpcb.snd_una, tcpcb.snd_nxt, tcpcb.snd_up);
    905 	printf("snd_wl1 %u, snd_wl2 %u, iss %u, snd_wnd %lu\n\n",
    906 	    tcpcb.snd_wl1, tcpcb.snd_wl2, tcpcb.iss, tcpcb.snd_wnd);
    907 
    908 	printf("rcv_wnd %lu, rcv_nxt %u, rcv_up %u, irs %u\n\n",
    909 	    tcpcb.rcv_wnd, tcpcb.rcv_nxt, tcpcb.rcv_up, tcpcb.irs);
    910 
    911 	printf("rcv_adv %u, snd_max %u, snd_cwnd %lu, snd_ssthresh %lu\n",
    912 	    tcpcb.rcv_adv, tcpcb.snd_max, tcpcb.snd_cwnd, tcpcb.snd_ssthresh);
    913 
    914 	printf("rcvtime %u, rtttime %u, rtseq %u, srtt %d, rttvar %d, "
    915 	    "rttmin %d, max_sndwnd %lu\n\n", tcpcb.t_rcvtime, tcpcb.t_rtttime,
    916 	    tcpcb.t_rtseq, tcpcb.t_srtt, tcpcb.t_rttvar, tcpcb.t_rttmin,
    917 	    tcpcb.max_sndwnd);
    918 
    919 	printf("oobflags %d, iobc %d, softerror %d\n\n", tcpcb.t_oobflags,
    920 	    tcpcb.t_iobc, tcpcb.t_softerror);
    921 
    922 	printf("snd_scale %d, rcv_scale %d, req_r_scale %d, req_s_scale %d\n",
    923 	    tcpcb.snd_scale, tcpcb.rcv_scale, tcpcb.request_r_scale,
    924 	    tcpcb.requested_s_scale);
    925 	printf("ts_recent %u, ts_regent_age %d, last_ack_sent %u\n",
    926 	    tcpcb.ts_recent, tcpcb.ts_recent_age, tcpcb.last_ack_sent);
    927 }
    928