Home | History | Annotate | Line # | Download | only in netstat
inet.c revision 1.80
      1 /*	$NetBSD: inet.c,v 1.80 2008/04/06 20:17:27 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.80 2008/04/06 20:17:27 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 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(off, name)
    283 	u_long off;
    284 	char *name;
    285 {
    286 	struct tcpstat tcpstat;
    287 
    288 	if (use_sysctl) {
    289 		size_t size = sizeof(tcpstat);
    290 
    291 		if (sysctlbyname("net.inet.tcp.stats", &tcpstat, &size,
    292 				 NULL, 0) == -1)
    293 			err(1, "net.inet.tcp.stats");
    294 	} else {
    295 		if (off == 0)
    296 			return;
    297 		kread(off, (char *)&tcpstat, sizeof (tcpstat));
    298 	}
    299 
    300 	printf ("%s:\n", name);
    301 
    302 #define	ps(f, m) if (tcpstat.f || sflag <= 1) \
    303     printf(m, (unsigned long long)tcpstat.f)
    304 #define	p(f, m) if (tcpstat.f || sflag <= 1) \
    305     printf(m, (unsigned long long)tcpstat.f, plural(tcpstat.f))
    306 #define	p2(f1, f2, m) if (tcpstat.f1 || tcpstat.f2 || sflag <= 1) \
    307     printf(m, (unsigned long long)tcpstat.f1, plural(tcpstat.f1), \
    308     (unsigned long long)tcpstat.f2, plural(tcpstat.f2))
    309 #define	p2s(f1, f2, m) if (tcpstat.f1 || tcpstat.f2 || sflag <= 1) \
    310     printf(m, (unsigned long long)tcpstat.f1, plural(tcpstat.f1), \
    311     (unsigned long long)tcpstat.f2)
    312 #define	p3(f, m) if (tcpstat.f || sflag <= 1) \
    313     printf(m, (unsigned long long)tcpstat.f, plurales(tcpstat.f))
    314 
    315 	p(tcps_sndtotal, "\t%llu packet%s sent\n");
    316 	p2(tcps_sndpack,tcps_sndbyte,
    317 		"\t\t%llu data packet%s (%llu byte%s)\n");
    318 	p2(tcps_sndrexmitpack, tcps_sndrexmitbyte,
    319 		"\t\t%llu data packet%s (%llu byte%s) retransmitted\n");
    320 	p2s(tcps_sndacks, tcps_delack,
    321 		"\t\t%llu ack-only packet%s (%llu delayed)\n");
    322 	p(tcps_sndurg, "\t\t%llu URG only packet%s\n");
    323 	p(tcps_sndprobe, "\t\t%llu window probe packet%s\n");
    324 	p(tcps_sndwinup, "\t\t%llu window update packet%s\n");
    325 	p(tcps_sndctrl, "\t\t%llu control packet%s\n");
    326 	p(tcps_selfquench,
    327 	    "\t\t%llu send attempt%s resulted in self-quench\n");
    328 	p(tcps_rcvtotal, "\t%llu packet%s received\n");
    329 	p2(tcps_rcvackpack, tcps_rcvackbyte,
    330 		"\t\t%llu ack%s (for %llu byte%s)\n");
    331 	p(tcps_rcvdupack, "\t\t%llu duplicate ack%s\n");
    332 	p(tcps_rcvacktoomuch, "\t\t%llu ack%s for unsent data\n");
    333 	p2(tcps_rcvpack, tcps_rcvbyte,
    334 		"\t\t%llu packet%s (%llu byte%s) received in-sequence\n");
    335 	p2(tcps_rcvduppack, tcps_rcvdupbyte,
    336 		"\t\t%llu completely duplicate packet%s (%llu byte%s)\n");
    337 	p(tcps_pawsdrop, "\t\t%llu old duplicate packet%s\n");
    338 	p2(tcps_rcvpartduppack, tcps_rcvpartdupbyte,
    339 		"\t\t%llu packet%s with some dup. data (%llu byte%s duped)\n");
    340 	p2(tcps_rcvoopack, tcps_rcvoobyte,
    341 		"\t\t%llu out-of-order packet%s (%llu byte%s)\n");
    342 	p2(tcps_rcvpackafterwin, tcps_rcvbyteafterwin,
    343 		"\t\t%llu packet%s (%llu byte%s) of data after window\n");
    344 	p(tcps_rcvwinprobe, "\t\t%llu window probe%s\n");
    345 	p(tcps_rcvwinupd, "\t\t%llu window update packet%s\n");
    346 	p(tcps_rcvafterclose, "\t\t%llu packet%s received after close\n");
    347 	p(tcps_rcvbadsum, "\t\t%llu discarded for bad checksum%s\n");
    348 	p(tcps_rcvbadoff, "\t\t%llu discarded for bad header offset field%s\n");
    349 	ps(tcps_rcvshort, "\t\t%llu discarded because packet too short\n");
    350 	p(tcps_connattempt, "\t%llu connection request%s\n");
    351 	p(tcps_accepts, "\t%llu connection accept%s\n");
    352 	p(tcps_connects,
    353 		"\t%llu connection%s established (including accepts)\n");
    354 	p2(tcps_closed, tcps_drops,
    355 		"\t%llu connection%s closed (including %llu drop%s)\n");
    356 	p(tcps_conndrops, "\t%llu embryonic connection%s dropped\n");
    357 	p(tcps_delayed_free, "\t%llu delayed free%s of tcpcb\n");
    358 	p2(tcps_rttupdated, tcps_segstimed,
    359 		"\t%llu segment%s updated rtt (of %llu attempt%s)\n");
    360 	p(tcps_rexmttimeo, "\t%llu retransmit timeout%s\n");
    361 	p(tcps_timeoutdrop,
    362 		"\t\t%llu connection%s dropped by rexmit timeout\n");
    363 	p2(tcps_persisttimeo, tcps_persistdrops,
    364 	   "\t%llu persist timeout%s (resulting in %llu dropped "
    365 		"connection%s)\n");
    366 	p(tcps_keeptimeo, "\t%llu keepalive timeout%s\n");
    367 	p(tcps_keepprobe, "\t\t%llu keepalive probe%s sent\n");
    368 	p(tcps_keepdrops, "\t\t%llu connection%s dropped by keepalive\n");
    369 	p(tcps_predack, "\t%llu correct ACK header prediction%s\n");
    370 	p(tcps_preddat, "\t%llu correct data packet header prediction%s\n");
    371 	p3(tcps_pcbhashmiss, "\t%llu PCB hash miss%s\n");
    372 	ps(tcps_noport, "\t%llu dropped due to no socket\n");
    373 	p(tcps_connsdrained, "\t%llu connection%s drained due to memory "
    374 		"shortage\n");
    375 	p(tcps_pmtublackhole, "\t%llu PMTUD blackhole%s detected\n");
    376 
    377 	p(tcps_badsyn, "\t%llu bad connection attempt%s\n");
    378 	ps(tcps_sc_added, "\t%llu SYN cache entries added\n");
    379 	p(tcps_sc_collisions, "\t\t%llu hash collision%s\n");
    380 	ps(tcps_sc_completed, "\t\t%llu completed\n");
    381 	ps(tcps_sc_aborted, "\t\t%llu aborted (no space to build PCB)\n");
    382 	ps(tcps_sc_timed_out, "\t\t%llu timed out\n");
    383 	ps(tcps_sc_overflowed, "\t\t%llu dropped due to overflow\n");
    384 	ps(tcps_sc_bucketoverflow, "\t\t%llu dropped due to bucket overflow\n");
    385 	ps(tcps_sc_reset, "\t\t%llu dropped due to RST\n");
    386 	ps(tcps_sc_unreach, "\t\t%llu dropped due to ICMP unreachable\n");
    387 	ps(tcps_sc_delayed_free, "\t\t%llu delayed free of SYN cache "
    388 		"entries\n");
    389 	p(tcps_sc_retransmitted, "\t%llu SYN,ACK%s retransmitted\n");
    390 	p(tcps_sc_dupesyn, "\t%llu duplicate SYN%s received for entries "
    391 		"already in the cache\n");
    392 	p(tcps_sc_dropped, "\t%llu SYN%s dropped (no route or no space)\n");
    393 	p(tcps_badsig, "\t%llu packet%s with bad signature\n");
    394 	p(tcps_goodsig, "\t%llu packet%s with good signature\n");
    395 
    396 	p(tcps_ecn_shs, "\t%llu sucessful ECN handshake%s\n");
    397 	p(tcps_ecn_ce, "\t%llu packet%s with ECN CE bit\n");
    398 	p(tcps_ecn_ect, "\t%llu packet%s ECN ECT(0) bit\n");
    399 #undef p
    400 #undef ps
    401 #undef p2
    402 #undef p2s
    403 #undef p3
    404 }
    405 
    406 /*
    407  * Dump UDP statistics structure.
    408  */
    409 void
    410 udp_stats(u_long off, char *name)
    411 {
    412 	uint64_t udpstat[UDP_NSTATS];
    413 	u_quad_t delivered;
    414 
    415 	if (use_sysctl) {
    416 		size_t size = sizeof(udpstat);
    417 
    418 		if (sysctlbyname("net.inet.udp.stats", udpstat, &size,
    419 				 NULL, 0) == -1)
    420 			err(1, "net.inet.udp.stats");
    421 	} else {
    422 		if (off == 0)
    423 			return;
    424 		kread(off, (char *)udpstat, sizeof (udpstat));
    425 	}
    426 
    427 	printf ("%s:\n", name);
    428 
    429 #define	ps(f, m) if (udpstat[f] || sflag <= 1) \
    430     printf(m, (unsigned long long)udpstat[f])
    431 #define	p(f, m) if (udpstat[f] || sflag <= 1) \
    432     printf(m, (unsigned long long)udpstat[f], plural(udpstat[f]))
    433 #define	p3(f, m) if (udpstat[f] || sflag <= 1) \
    434     printf(m, (unsigned long long)udpstat[f], plurales(udpstat[f]))
    435 
    436 	p(UDP_STAT_IPACKETS, "\t%llu datagram%s received\n");
    437 	ps(UDP_STAT_HDROPS, "\t%llu with incomplete header\n");
    438 	ps(UDP_STAT_BADLEN, "\t%llu with bad data length field\n");
    439 	ps(UDP_STAT_BADSUM, "\t%llu with bad checksum\n");
    440 	ps(UDP_STAT_NOPORT, "\t%llu dropped due to no socket\n");
    441 	p(UDP_STAT_NOPORTBCAST,
    442 	  "\t%llu broadcast/multicast datagram%s dropped due to no socket\n");
    443 	ps(UDP_STAT_FULLSOCK, "\t%llu dropped due to full socket buffers\n");
    444 	delivered = udpstat[UDP_STAT_IPACKETS] -
    445 		    udpstat[UDP_STAT_HDROPS] -
    446 		    udpstat[UDP_STAT_BADLEN] -
    447 		    udpstat[UDP_STAT_BADSUM] -
    448 		    udpstat[UDP_STAT_NOPORT] -
    449 		    udpstat[UDP_STAT_NOPORTBCAST] -
    450 		    udpstat[UDP_STAT_FULLSOCK];
    451 	if (delivered || sflag <= 1)
    452 		printf("\t%llu delivered\n", (unsigned long long)delivered);
    453 	p3(UDP_STAT_PCBHASHMISS, "\t%llu PCB hash miss%s\n");
    454 	p(UDP_STAT_OPACKETS, "\t%llu datagram%s output\n");
    455 
    456 #undef ps
    457 #undef p
    458 #undef p3
    459 }
    460 
    461 /*
    462  * Dump IP statistics structure.
    463  */
    464 void
    465 ip_stats(off, name)
    466 	u_long off;
    467 	char *name;
    468 {
    469 	struct ipstat ipstat;
    470 
    471 	if (use_sysctl) {
    472 		size_t size = sizeof(ipstat);
    473 
    474 		if (sysctlbyname("net.inet.ip.stats", &ipstat, &size,
    475 				 NULL, 0) == -1)
    476 			err(1, "net.inet.ip.stats");
    477 	} else {
    478 		if (off == 0)
    479 			return;
    480 		kread(off, (char *)&ipstat, sizeof (ipstat));
    481 	}
    482 
    483 	printf("%s:\n", name);
    484 
    485 #define	ps(f, m) if (ipstat.f || sflag <= 1) \
    486     printf(m, (unsigned long long)ipstat.f)
    487 #define	p(f, m) if (ipstat.f || sflag <= 1) \
    488     printf(m, (unsigned long long)ipstat.f, plural(ipstat.f))
    489 
    490 	p(ips_total, "\t%llu total packet%s received\n");
    491 	p(ips_badsum, "\t%llu bad header checksum%s\n");
    492 	ps(ips_toosmall, "\t%llu with size smaller than minimum\n");
    493 	ps(ips_tooshort, "\t%llu with data size < data length\n");
    494 	ps(ips_toolong, "\t%llu with length > max ip packet size\n");
    495 	ps(ips_badhlen, "\t%llu with header length < data size\n");
    496 	ps(ips_badlen, "\t%llu with data length < header length\n");
    497 	ps(ips_badoptions, "\t%llu with bad options\n");
    498 	ps(ips_badvers, "\t%llu with incorrect version number\n");
    499 	p(ips_fragments, "\t%llu fragment%s received\n");
    500 	p(ips_fragdropped, "\t%llu fragment%s dropped (dup or out of space)\n");
    501 	p(ips_rcvmemdrop, "\t%llu fragment%s dropped (out of ipqent)\n");
    502 	p(ips_badfrags, "\t%llu malformed fragment%s dropped\n");
    503 	p(ips_fragtimeout, "\t%llu fragment%s dropped after timeout\n");
    504 	p(ips_reassembled, "\t%llu packet%s reassembled ok\n");
    505 	p(ips_delivered, "\t%llu packet%s for this host\n");
    506 	p(ips_noproto, "\t%llu packet%s for unknown/unsupported protocol\n");
    507 	p(ips_forward, "\t%llu packet%s forwarded");
    508 	p(ips_fastforward, " (%llu packet%s fast forwarded)");
    509 	if (ipstat.ips_forward || sflag <= 1)
    510 		putchar('\n');
    511 	p(ips_cantforward, "\t%llu packet%s not forwardable\n");
    512 	p(ips_redirectsent, "\t%llu redirect%s sent\n");
    513 	p(ips_nogif, "\t%llu packet%s no matching gif found\n");
    514 	p(ips_localout, "\t%llu packet%s sent from this host\n");
    515 	p(ips_rawout, "\t%llu packet%s sent with fabricated ip header\n");
    516 	p(ips_odropped, "\t%llu output packet%s dropped due to no bufs, etc.\n");
    517 	p(ips_noroute, "\t%llu output packet%s discarded due to no route\n");
    518 	p(ips_fragmented, "\t%llu output datagram%s fragmented\n");
    519 	p(ips_ofragments, "\t%llu fragment%s created\n");
    520 	p(ips_cantfrag, "\t%llu datagram%s that can't be fragmented\n");
    521 	p(ips_badaddr, "\t%llu datagram%s with bad address in header\n");
    522 #undef ps
    523 #undef p
    524 }
    525 
    526 static	const char *icmpnames[] = {
    527 	"echo reply",
    528 	"#1",
    529 	"#2",
    530 	"destination unreachable",
    531 	"source quench",
    532 	"routing redirect",
    533 	"alternate host address",
    534 	"#7",
    535 	"echo",
    536 	"router advertisement",
    537 	"router solicitation",
    538 	"time exceeded",
    539 	"parameter problem",
    540 	"time stamp",
    541 	"time stamp reply",
    542 	"information request",
    543 	"information request reply",
    544 	"address mask request",
    545 	"address mask reply",
    546 };
    547 
    548 /*
    549  * Dump ICMP statistics.
    550  */
    551 void
    552 icmp_stats(u_long off, char *name)
    553 {
    554 	uint64_t icmpstat[ICMP_NSTATS];
    555 	int i, first;
    556 
    557 	if (use_sysctl) {
    558 		size_t size = sizeof(icmpstat);
    559 
    560 		if (sysctlbyname("net.inet.icmp.stats", icmpstat, &size,
    561 				 NULL, 0) == -1)
    562 			err(1, "net.inet.icmp.stats");
    563 	} else {
    564 		if (off == 0)
    565 			return;
    566 		kread(off, (char *)icmpstat, sizeof (icmpstat));
    567 	}
    568 
    569 	printf("%s:\n", name);
    570 
    571 #define	p(f, m) if (icmpstat[f] || sflag <= 1) \
    572     printf(m, (unsigned long long)icmpstat.f, plural(icmpstat[f]))
    573 
    574 	p(ICMP_STAT_ERROR, "\t%llu call%s to icmp_error\n");
    575 	p(ICMP_STAT_OLDICMP,
    576 	    "\t%llu error%s not generated because old message was icmp\n");
    577 	for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
    578 		if (icmpstat[ICMP_STAT_OUTHIST + i] != 0) {
    579 			if (first) {
    580 				printf("\tOutput histogram:\n");
    581 				first = 0;
    582 			}
    583 			printf("\t\t%s: %llu\n", icmpnames[i],
    584 			   (unsigned long long)icmpstat[ICMP_STAT_OUTHIST + i]);
    585 		}
    586 	p(ICMP_STAT_BADCODE, "\t%llu message%s with bad code fields\n");
    587 	p(ICMP_STAT_TOOSHORT, "\t%llu message%s < minimum length\n");
    588 	p(ICMP_STAT_CHECKSUM, "\t%llu bad checksum%s\n");
    589 	p(ICMP_STAT_BADLEN, "\t%llu message%s with bad length\n");
    590 	for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
    591 		if (icmpstat[ICMP_STAT_INHIST + i] != 0) {
    592 			if (first) {
    593 				printf("\tInput histogram:\n");
    594 				first = 0;
    595 			}
    596 			printf("\t\t%s: %llu\n", icmpnames[i],
    597 			    (unsigned long long)icmpstat[ICMP_STAT_INHIST + i]);
    598 		}
    599 	p(ICMP_STAT_REFLECT, "\t%llu message response%s generated\n");
    600 	p(ICMP_STAT_PMTUCHG, "\t%llu path MTU change%s\n");
    601 #undef p
    602 }
    603 
    604 /*
    605  * Dump IGMP statistics structure.
    606  */
    607 void
    608 igmp_stats(off, name)
    609 	u_long off;
    610 	char *name;
    611 {
    612 	struct igmpstat igmpstat;
    613 
    614 	if (off == 0)
    615 		return;
    616 	kread(off, (char *)&igmpstat, sizeof (igmpstat));
    617 	printf("%s:\n", name);
    618 
    619 #define	p(f, m) if (igmpstat.f || sflag <= 1) \
    620     printf(m, (unsigned long long)igmpstat.f, plural(igmpstat.f))
    621 #define	py(f, m) if (igmpstat.f || sflag <= 1) \
    622     printf(m, (unsigned long long)igmpstat.f, igmpstat.f != 1 ? "ies" : "y")
    623 	p(igps_rcv_total, "\t%llu message%s received\n");
    624         p(igps_rcv_tooshort, "\t%llu message%s received with too few bytes\n");
    625         p(igps_rcv_badsum, "\t%llu message%s received with bad checksum\n");
    626         py(igps_rcv_queries, "\t%llu membership quer%s received\n");
    627         py(igps_rcv_badqueries, "\t%llu membership quer%s received with invalid field(s)\n");
    628         p(igps_rcv_reports, "\t%llu membership report%s received\n");
    629         p(igps_rcv_badreports, "\t%llu membership report%s received with invalid field(s)\n");
    630         p(igps_rcv_ourreports, "\t%llu membership report%s received for groups to which we belong\n");
    631         p(igps_snd_reports, "\t%llu membership report%s sent\n");
    632 #undef p
    633 #undef py
    634 }
    635 
    636 /*
    637  * Dump CARP statistics structure.
    638  */
    639 void
    640 carp_stats(u_long off, char *name)
    641 {
    642 	struct carpstats carpstat;
    643 
    644 	if (use_sysctl) {
    645 		size_t size = sizeof(carpstat);
    646 
    647 		if (sysctlbyname("net.inet.carp.stats", &carpstat, &size,
    648 				 NULL, 0) == -1) {
    649 			/* most likely CARP is not compiled in the kernel */
    650 			return;
    651 		}
    652 	} else {
    653 		if (off == 0)
    654 			return;
    655 		kread(off, (char *)&carpstat, sizeof(carpstat));
    656 	}
    657 
    658 	printf("%s:\n", name);
    659 
    660 #define p(f, m) if (carpstat.f || sflag <= 1) \
    661 	printf(m, carpstat.f, plural(carpstat.f))
    662 #define p2(f, m) if (carpstat.f || sflag <= 1) \
    663 	printf(m, carpstat.f)
    664 
    665 	p(carps_ipackets, "\t%" PRIu64 " packet%s received (IPv4)\n");
    666 	p(carps_ipackets6, "\t%" PRIu64 " packet%s received (IPv6)\n");
    667 	p(carps_badif,
    668 	    "\t\t%" PRIu64 " packet%s discarded for bad interface\n");
    669 	p(carps_badttl,
    670 	    "\t\t%" PRIu64 " packet%s discarded for wrong TTL\n");
    671 	p(carps_hdrops, "\t\t%" PRIu64 " packet%s shorter than header\n");
    672 	p(carps_badsum, "\t\t%" PRIu64
    673 		" packet%s discarded for bad checksum\n");
    674 	p(carps_badver,
    675 	    "\t\t%" PRIu64 " packet%s discarded with a bad version\n");
    676 	p2(carps_badlen,
    677 	    "\t\t%" PRIu64 " discarded because packet was too short\n");
    678 	p(carps_badauth,
    679 	    "\t\t%" PRIu64 " packet%s discarded for bad authentication\n");
    680 	p(carps_badvhid, "\t\t%" PRIu64 " packet%s discarded for bad vhid\n");
    681 	p(carps_badaddrs, "\t\t%" PRIu64
    682 		" packet%s discarded because of a bad address list\n");
    683 	p(carps_opackets, "\t%" PRIu64 " packet%s sent (IPv4)\n");
    684 	p(carps_opackets6, "\t%" PRIu64 " packet%s sent (IPv6)\n");
    685 	p2(carps_onomem,
    686 	    "\t\t%" PRIu64 " send failed due to mbuf memory error\n");
    687 #undef p
    688 #undef p2
    689 }
    690 
    691 /*
    692  * Dump PIM statistics structure.
    693  */
    694 void
    695 pim_stats(off, name)
    696 	u_long off;
    697 	char *name;
    698 {
    699 	struct pimstat pimstat;
    700 
    701 	if (off == 0)
    702 		return;
    703 	if (kread(off, (char *)&pimstat, sizeof (pimstat)) != 0) {
    704 		/* XXX: PIM is probably not enabled in the kernel */
    705 		return;
    706 	}
    707 
    708 	printf("%s:\n", name);
    709 
    710 #define	p(f, m) if (pimstat.f || sflag <= 1) \
    711 	printf(m, (unsigned long long)pimstat.f, plural(pimstat.f))
    712 
    713 	p(pims_rcv_total_msgs, "\t%llu message%s received\n");
    714 	p(pims_rcv_total_bytes, "\t%llu byte%s received\n");
    715 	p(pims_rcv_tooshort, "\t%llu message%s received with too few bytes\n");
    716         p(pims_rcv_badsum, "\t%llu message%s received with bad checksum\n");
    717 	p(pims_rcv_badversion, "\t%llu message%s received with bad version\n");
    718 	p(pims_rcv_registers_msgs, "\t%llu data register message%s received\n");
    719 	p(pims_rcv_registers_bytes, "\t%llu data register byte%s received\n");
    720 	p(pims_rcv_registers_wrongiif, "\t%llu data register message%s received on wrong iif\n");
    721 	p(pims_rcv_badregisters, "\t%llu bad register%s received\n");
    722 	p(pims_snd_registers_msgs, "\t%llu data register message%s sent\n");
    723 	p(pims_snd_registers_bytes, "\t%llu data register byte%s sent\n");
    724 #undef p
    725 }
    726 
    727 /*
    728  * Dump the ARP statistics structure.
    729  */
    730 void
    731 arp_stats(off, name)
    732 	u_long off;
    733 	char *name;
    734 {
    735 	struct arpstat arpstat;
    736 
    737 	if (off == 0)
    738 		return;
    739 	kread(off, (char *)&arpstat, sizeof (arpstat));
    740 	printf("%s:\n", name);
    741 
    742 #define	ps(f, m) if (arpstat.f || sflag <= 1) \
    743     printf(m, (unsigned long long)arpstat.f)
    744 #define	p(f, m) if (arpstat.f || sflag <= 1) \
    745     printf(m, (unsigned long long)arpstat.f, plural(arpstat.f))
    746 
    747 	p(as_sndtotal, "\t%llu packet%s sent\n");
    748 	p(as_sndreply, "\t\t%llu reply packet%s\n");
    749 	p(as_sndrequest, "\t\t%llu request packet%s\n");
    750 
    751 	p(as_rcvtotal, "\t%llu packet%s received\n");
    752 	p(as_rcvreply, "\t\t%llu reply packet%s\n");
    753 	p(as_rcvrequest, "\t\t%llu valid request packet%s\n");
    754 	p(as_rcvmcast, "\t\t%llu broadcast/multicast packet%s\n");
    755 	p(as_rcvbadproto, "\t\t%llu packet%s with unknown protocol type\n");
    756 	p(as_rcvbadlen, "\t\t%llu packet%s with bad (short) length\n");
    757 	p(as_rcvzerotpa, "\t\t%llu packet%s with null target IP address\n");
    758 	p(as_rcvzerospa, "\t\t%llu packet%s with null source IP address\n");
    759 	ps(as_rcvnoint, "\t\t%llu could not be mapped to an interface\n");
    760 	p(as_rcvlocalsha, "\t\t%llu packet%s sourced from a local hardware "
    761 	    "address\n");
    762 	p(as_rcvbcastsha, "\t\t%llu packet%s with a broadcast "
    763 	    "source hardware address\n");
    764 	p(as_rcvlocalspa, "\t\t%llu duplicate%s for a local IP address\n");
    765 	p(as_rcvoverperm, "\t\t%llu attempt%s to overwrite a static entry\n");
    766 	p(as_rcvoverint, "\t\t%llu packet%s received on wrong interface\n");
    767 	p(as_rcvover, "\t\t%llu entry%s overwritten\n");
    768 	p(as_rcvlenchg, "\t\t%llu change%s in hardware address length\n");
    769 
    770 	p(as_dfrtotal, "\t%llu packet%s deferred pending ARP resolution\n");
    771 	ps(as_dfrsent, "\t\t%llu sent\n");
    772 	ps(as_dfrdropped, "\t\t%llu dropped\n");
    773 
    774 	p(as_allocfail, "\t%llu failure%s to allocate llinfo\n");
    775 
    776 #undef ps
    777 #undef p
    778 }
    779 
    780 /*
    781  * Pretty print an Internet address (net address + port).
    782  * Take numeric_addr and numeric_port into consideration.
    783  */
    784 void
    785 inetprint(in, port, proto, numeric_port)
    786 	struct in_addr *in;
    787 	u_int16_t port;
    788 	const char *proto;
    789 	int numeric_port;
    790 {
    791 	struct servent *sp = 0;
    792 	char line[80], *cp;
    793 	size_t space;
    794 
    795 	(void)snprintf(line, sizeof line, "%.*s.",
    796 	    (Aflag && !numeric_addr) ? 12 : 16, inetname(in));
    797 	cp = strchr(line, '\0');
    798 	if (!numeric_port && port)
    799 		sp = getservbyport((int)port, proto);
    800 	space = sizeof line - (cp-line);
    801 	if (sp || port == 0)
    802 		(void)snprintf(cp, space, "%s", sp ? sp->s_name : "*");
    803 	else
    804 		(void)snprintf(cp, space, "%u", ntohs(port));
    805 	(void)printf(" %-*.*s", width, width, line);
    806 }
    807 
    808 /*
    809  * Construct an Internet address representation.
    810  * If numeric_addr has been supplied, give
    811  * numeric value, otherwise try for symbolic name.
    812  */
    813 char *
    814 inetname(inp)
    815 	struct in_addr *inp;
    816 {
    817 	char *cp;
    818 	static char line[50];
    819 	struct hostent *hp;
    820 	struct netent *np;
    821 	static char domain[MAXHOSTNAMELEN + 1];
    822 	static int first = 1;
    823 
    824 	if (first && !numeric_addr) {
    825 		first = 0;
    826 		if (gethostname(domain, sizeof domain) == 0) {
    827 			domain[sizeof(domain) - 1] = '\0';
    828 			if ((cp = strchr(domain, '.')))
    829 				(void) strlcpy(domain, cp + 1, sizeof(domain));
    830 			else
    831 				domain[0] = 0;
    832 		} else
    833 			domain[0] = 0;
    834 	}
    835 	cp = 0;
    836 	if (!numeric_addr && inp->s_addr != INADDR_ANY) {
    837 		int net = inet_netof(*inp);
    838 		int lna = inet_lnaof(*inp);
    839 
    840 		if (lna == INADDR_ANY) {
    841 			np = getnetbyaddr(net, AF_INET);
    842 			if (np)
    843 				cp = np->n_name;
    844 		}
    845 		if (cp == 0) {
    846 			hp = gethostbyaddr((char *)inp, sizeof (*inp), AF_INET);
    847 			if (hp) {
    848 				if ((cp = strchr(hp->h_name, '.')) &&
    849 				    !strcmp(cp + 1, domain))
    850 					*cp = 0;
    851 				cp = hp->h_name;
    852 			}
    853 		}
    854 	}
    855 	if (inp->s_addr == INADDR_ANY)
    856 		strlcpy(line, "*", sizeof line);
    857 	else if (cp)
    858 		strlcpy(line, cp, sizeof line);
    859 	else {
    860 		inp->s_addr = ntohl(inp->s_addr);
    861 #define C(x)	((x) & 0xff)
    862 		(void)snprintf(line, sizeof line, "%u.%u.%u.%u",
    863 		    C(inp->s_addr >> 24), C(inp->s_addr >> 16),
    864 		    C(inp->s_addr >> 8), C(inp->s_addr));
    865 #undef C
    866 	}
    867 	return (line);
    868 }
    869 
    870 /*
    871  * Dump the contents of a TCP PCB.
    872  */
    873 void
    874 tcp_dump(pcbaddr)
    875 	u_long pcbaddr;
    876 {
    877 	callout_impl_t *ci;
    878 	struct tcpcb tcpcb;
    879 	int i, hardticks;
    880 
    881 	kread(pcbaddr, (char *)&tcpcb, sizeof(tcpcb));
    882 	hardticks = get_hardticks();
    883 
    884 	printf("TCP Protocol Control Block at 0x%08lx:\n\n", pcbaddr);
    885 
    886 	printf("Timers:\n");
    887 	for (i = 0; i < TCPT_NTIMERS; i++) {
    888 		ci = (callout_impl_t *)&tcpcb.t_timer[i];
    889 		printf("\t%s: %d", tcptimers[i],
    890 		    (ci->c_flags & CALLOUT_PENDING) ?
    891 		    ci->c_time - hardticks : 0);
    892 	}
    893 	printf("\n\n");
    894 
    895 	if (tcpcb.t_state < 0 || tcpcb.t_state >= TCP_NSTATES)
    896 		printf("State: %d", tcpcb.t_state);
    897 	else
    898 		printf("State: %s", tcpstates[tcpcb.t_state]);
    899 	printf(", flags 0x%x, inpcb 0x%lx, in6pcb 0x%lx\n\n", tcpcb.t_flags,
    900 	    (u_long)tcpcb.t_inpcb, (u_long)tcpcb.t_in6pcb);
    901 
    902 	printf("rxtshift %d, rxtcur %d, dupacks %d\n", tcpcb.t_rxtshift,
    903 	    tcpcb.t_rxtcur, tcpcb.t_dupacks);
    904 	printf("peermss %u, ourmss %u, segsz %u\n\n", tcpcb.t_peermss,
    905 	    tcpcb.t_ourmss, tcpcb.t_segsz);
    906 
    907 	printf("snd_una %u, snd_nxt %u, snd_up %u\n",
    908 	    tcpcb.snd_una, tcpcb.snd_nxt, tcpcb.snd_up);
    909 	printf("snd_wl1 %u, snd_wl2 %u, iss %u, snd_wnd %lu\n\n",
    910 	    tcpcb.snd_wl1, tcpcb.snd_wl2, tcpcb.iss, tcpcb.snd_wnd);
    911 
    912 	printf("rcv_wnd %lu, rcv_nxt %u, rcv_up %u, irs %u\n\n",
    913 	    tcpcb.rcv_wnd, tcpcb.rcv_nxt, tcpcb.rcv_up, tcpcb.irs);
    914 
    915 	printf("rcv_adv %u, snd_max %u, snd_cwnd %lu, snd_ssthresh %lu\n",
    916 	    tcpcb.rcv_adv, tcpcb.snd_max, tcpcb.snd_cwnd, tcpcb.snd_ssthresh);
    917 
    918 	printf("rcvtime %u, rtttime %u, rtseq %u, srtt %d, rttvar %d, "
    919 	    "rttmin %d, max_sndwnd %lu\n\n", tcpcb.t_rcvtime, tcpcb.t_rtttime,
    920 	    tcpcb.t_rtseq, tcpcb.t_srtt, tcpcb.t_rttvar, tcpcb.t_rttmin,
    921 	    tcpcb.max_sndwnd);
    922 
    923 	printf("oobflags %d, iobc %d, softerror %d\n\n", tcpcb.t_oobflags,
    924 	    tcpcb.t_iobc, tcpcb.t_softerror);
    925 
    926 	printf("snd_scale %d, rcv_scale %d, req_r_scale %d, req_s_scale %d\n",
    927 	    tcpcb.snd_scale, tcpcb.rcv_scale, tcpcb.request_r_scale,
    928 	    tcpcb.requested_s_scale);
    929 	printf("ts_recent %u, ts_regent_age %d, last_ack_sent %u\n",
    930 	    tcpcb.ts_recent, tcpcb.ts_recent_age, tcpcb.last_ack_sent);
    931 }
    932