Home | History | Annotate | Line # | Download | only in netstat
inet.c revision 1.77.2.1
      1 /*	$NetBSD: inet.c,v 1.77.2.1 2009/03/31 17:56:41 bouyer 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.77.2.1 2009/03/31 17:56:41 bouyer Exp $");
     38 #endif
     39 #endif /* not lint */
     40 
     41 #include <sys/param.h>
     42 #include <sys/queue.h>
     43 #include <sys/socket.h>
     44 #include <sys/socketvar.h>
     45 #include <sys/mbuf.h>
     46 #include <sys/protosw.h>
     47 #include <sys/sysctl.h>
     48 
     49 #include <net/if_arp.h>
     50 #include <net/route.h>
     51 #include <netinet/in.h>
     52 #include <netinet/in_systm.h>
     53 #include <netinet/ip.h>
     54 #include <netinet/in_pcb.h>
     55 #include <netinet/ip_icmp.h>
     56 
     57 #ifdef INET6
     58 #include <netinet/ip6.h>
     59 #endif
     60 
     61 #include <netinet/icmp_var.h>
     62 #include <netinet/igmp_var.h>
     63 #include <netinet/ip_var.h>
     64 #include <netinet/pim_var.h>
     65 #include <netinet/tcp.h>
     66 #include <netinet/tcpip.h>
     67 #include <netinet/tcp_seq.h>
     68 #define TCPSTATES
     69 #include <netinet/tcp_fsm.h>
     70 #define	TCPTIMERS
     71 #include <netinet/tcp_timer.h>
     72 #include <netinet/tcp_var.h>
     73 #include <netinet/tcp_debug.h>
     74 #include <netinet/udp.h>
     75 #include <netinet/ip_carp.h>
     76 #include <netinet/udp_var.h>
     77 
     78 #include <arpa/inet.h>
     79 #include <kvm.h>
     80 #include <netdb.h>
     81 #include <stdio.h>
     82 #include <string.h>
     83 #include <unistd.h>
     84 #include <stdlib.h>
     85 #include <err.h>
     86 #include "netstat.h"
     87 
     88 struct	inpcb inpcb;
     89 struct	tcpcb tcpcb;
     90 struct	socket sockb;
     91 
     92 char	*inetname __P((struct in_addr *));
     93 void	inetprint __P((struct in_addr *, u_int16_t, const char *, int));
     94 
     95 /*
     96  * Print a summary of connections related to an Internet
     97  * protocol.  For TCP, also give state of connection.
     98  * Listening processes (aflag) are suppressed unless the
     99  * -a (all) flag is specified.
    100  */
    101 static int width;
    102 static int compact;
    103 
    104 static void
    105 protoprhdr(void)
    106 {
    107 	printf("Active Internet connections");
    108 	if (aflag)
    109 		printf(" (including servers)");
    110 	putchar('\n');
    111 	if (Aflag)
    112 		printf("%-8.8s ", "PCB");
    113 	printf("%-5.5s %-6.6s %-6.6s %s%-*.*s %-*.*s %s\n",
    114 		"Proto", "Recv-Q", "Send-Q", compact ? "" : " ",
    115 		width, width, "Local Address",
    116 		width, width, "Foreign Address",
    117 		"State");
    118 }
    119 
    120 static void
    121 protopr0(intptr_t ppcb, u_long rcv_sb_cc, u_long snd_sb_cc,
    122 	 struct in_addr *laddr, u_int16_t lport,
    123 	 struct in_addr *faddr, u_int16_t fport,
    124 	 short t_state, char *name)
    125 {
    126 	static char *shorttcpstates[] = {
    127 		"CLOSED",	"LISTEN",	"SYNSEN",	"SYSRCV",
    128 		"ESTABL",	"CLWAIT",	"FWAIT1",	"CLOSNG",
    129 		"LASTAK",	"FWAIT2",	"TMWAIT",
    130 	};
    131 	int istcp;
    132 
    133 	istcp = strcmp(name, "tcp") == 0;
    134 
    135 	if (Aflag) {
    136 		printf("%8" PRIxPTR " ", ppcb);
    137 	}
    138 	printf("%-5.5s %6ld %6ld%s", name, rcv_sb_cc, snd_sb_cc,
    139 	       compact ? "" : " ");
    140 	if (numeric_port) {
    141 		inetprint(laddr, lport, name, 1);
    142 		inetprint(faddr, fport, name, 1);
    143 	} else if (inpcb.inp_flags & INP_ANONPORT) {
    144 		inetprint(laddr, lport, name, 1);
    145 		inetprint(faddr, fport, name, 0);
    146 	} else {
    147 		inetprint(laddr, lport, name, 0);
    148 		inetprint(faddr, fport, name, 0);
    149 	}
    150 	if (istcp) {
    151 		if (t_state < 0 || t_state >= TCP_NSTATES)
    152 			printf(" %d", t_state);
    153 		else
    154 			printf(" %s", compact ? shorttcpstates[t_state] :
    155 			       tcpstates[t_state]);
    156 	}
    157 	putchar('\n');
    158 }
    159 
    160 void
    161 protopr(off, name)
    162 	u_long off;
    163 	char *name;
    164 {
    165 	struct inpcbtable table;
    166 	struct inpcb *head, *next, *prev;
    167 	struct inpcb inpcb;
    168 	int istcp;
    169 	static int first = 1;
    170 
    171 	compact = 0;
    172 	if (Aflag) {
    173 		if (!numeric_addr)
    174 			width = 18;
    175 		else {
    176 			width = 21;
    177 			compact = 1;
    178 		}
    179 	} else
    180 		width = 22;
    181 
    182 	if (use_sysctl) {
    183 		struct kinfo_pcb *pcblist;
    184 		int mib[8];
    185 		size_t namelen = 0, size = 0, i;
    186 		char *mibname = NULL;
    187 
    188 		memset(mib, 0, sizeof(mib));
    189 
    190 		if (asprintf(&mibname, "net.inet.%s.pcblist", name) == -1)
    191 			err(1, "asprintf");
    192 
    193 		/* get dynamic pcblist node */
    194 		if (sysctlnametomib(mibname, mib, &namelen) == -1)
    195 			err(1, "sysctlnametomib: %s", mibname);
    196 
    197 		if (sysctl(mib, sizeof(mib) / sizeof(*mib), NULL, &size,
    198 			   NULL, 0) == -1)
    199 			err(1, "sysctl (query)");
    200 
    201 		if ((pcblist = malloc(size)) == NULL)
    202 			err(1, "malloc");
    203 		memset(pcblist, 0, size);
    204 
    205 	        mib[6] = sizeof(*pcblist);
    206         	mib[7] = size / sizeof(*pcblist);
    207 
    208 		if (sysctl(mib, sizeof(mib) / sizeof(*mib), pcblist,
    209 			   &size, NULL, 0) == -1)
    210 			err(1, "sysctl (copy)");
    211 
    212 		for (i = 0; i < size / sizeof(*pcblist); i++) {
    213 			struct sockaddr_in src, dst;
    214 
    215 			memcpy(&src, &pcblist[i].ki_s, sizeof(src));
    216 			memcpy(&dst, &pcblist[i].ki_d, sizeof(dst));
    217 
    218 			if (!aflag &&
    219 			    inet_lnaof(dst.sin_addr) == INADDR_ANY)
    220 				continue;
    221 
    222 			if (first) {
    223 				protoprhdr();
    224 				first = 0;
    225 			}
    226 
    227 	                protopr0((intptr_t) pcblist[i].ki_ppcbaddr,
    228 				 pcblist[i].ki_rcvq, pcblist[i].ki_sndq,
    229 				 &src.sin_addr, src.sin_port,
    230 				 &dst.sin_addr, dst.sin_port,
    231 				 pcblist[i].ki_tstate, name);
    232 		}
    233 
    234 		free(pcblist);
    235 		return;
    236 	}
    237 
    238 	if (off == 0)
    239 		return;
    240 	istcp = strcmp(name, "tcp") == 0;
    241 	kread(off, (char *)&table, sizeof table);
    242 	prev = head =
    243 	    (struct inpcb *)&((struct inpcbtable *)off)->inpt_queue.cqh_first;
    244 	next = (struct inpcb *)table.inpt_queue.cqh_first;
    245 
    246 	while (next != head) {
    247 		kread((u_long)next, (char *)&inpcb, sizeof inpcb);
    248 		if ((struct inpcb *)inpcb.inp_queue.cqe_prev != prev) {
    249 			printf("???\n");
    250 			break;
    251 		}
    252 		prev = next;
    253 		next = (struct inpcb *)inpcb.inp_queue.cqe_next;
    254 
    255 		if (inpcb.inp_af != AF_INET)
    256 			continue;
    257 
    258 		if (!aflag &&
    259 		    inet_lnaof(inpcb.inp_faddr) == INADDR_ANY)
    260 			continue;
    261 		kread((u_long)inpcb.inp_socket, (char *)&sockb, sizeof (sockb));
    262 		if (istcp) {
    263 			kread((u_long)inpcb.inp_ppcb,
    264 			    (char *)&tcpcb, sizeof (tcpcb));
    265 		}
    266 
    267 		if (first) {
    268 			protoprhdr();
    269 			first = 0;
    270 		}
    271 
    272 		protopr0(istcp ? (intptr_t) inpcb.inp_ppcb : (intptr_t) prev,
    273 			 sockb.so_rcv.sb_cc, sockb.so_snd.sb_cc,
    274 			 &inpcb.inp_laddr, inpcb.inp_lport,
    275 			 &inpcb.inp_faddr, inpcb.inp_fport,
    276 			 tcpcb.t_state, name);
    277 	}
    278 }
    279 
    280 /*
    281  * Dump TCP statistics structure.
    282  */
    283 void
    284 tcp_stats(off, name)
    285 	u_long off;
    286 	char *name;
    287 {
    288 	struct tcpstat tcpstat;
    289 
    290 	if (use_sysctl) {
    291 		size_t size = sizeof(tcpstat);
    292 
    293 		if (sysctlbyname("net.inet.tcp.stats", &tcpstat, &size,
    294 				 NULL, 0) == -1)
    295 			err(1, "net.inet.tcp.stats");
    296 	} else {
    297 		if (off == 0)
    298 			return;
    299 		kread(off, (char *)&tcpstat, sizeof (tcpstat));
    300 	}
    301 
    302 	printf ("%s:\n", name);
    303 
    304 #define	ps(f, m) if (tcpstat.f || sflag <= 1) \
    305     printf(m, (unsigned long long)tcpstat.f)
    306 #define	p(f, m) if (tcpstat.f || sflag <= 1) \
    307     printf(m, (unsigned long long)tcpstat.f, plural(tcpstat.f))
    308 #define	p2(f1, f2, m) if (tcpstat.f1 || tcpstat.f2 || sflag <= 1) \
    309     printf(m, (unsigned long long)tcpstat.f1, plural(tcpstat.f1), \
    310     (unsigned long long)tcpstat.f2, plural(tcpstat.f2))
    311 #define	p2s(f1, f2, m) if (tcpstat.f1 || tcpstat.f2 || sflag <= 1) \
    312     printf(m, (unsigned long long)tcpstat.f1, plural(tcpstat.f1), \
    313     (unsigned long long)tcpstat.f2)
    314 #define	p3(f, m) if (tcpstat.f || sflag <= 1) \
    315     printf(m, (unsigned long long)tcpstat.f, plurales(tcpstat.f))
    316 
    317 	p(tcps_sndtotal, "\t%llu packet%s sent\n");
    318 	p2(tcps_sndpack,tcps_sndbyte,
    319 		"\t\t%llu data packet%s (%llu byte%s)\n");
    320 	p2(tcps_sndrexmitpack, tcps_sndrexmitbyte,
    321 		"\t\t%llu data packet%s (%llu byte%s) retransmitted\n");
    322 	p2s(tcps_sndacks, tcps_delack,
    323 		"\t\t%llu ack-only packet%s (%llu delayed)\n");
    324 	p(tcps_sndurg, "\t\t%llu URG only packet%s\n");
    325 	p(tcps_sndprobe, "\t\t%llu window probe packet%s\n");
    326 	p(tcps_sndwinup, "\t\t%llu window update packet%s\n");
    327 	p(tcps_sndctrl, "\t\t%llu control packet%s\n");
    328 	p(tcps_selfquench,
    329 	    "\t\t%llu send attempt%s resulted in self-quench\n");
    330 	p(tcps_rcvtotal, "\t%llu packet%s received\n");
    331 	p2(tcps_rcvackpack, tcps_rcvackbyte,
    332 		"\t\t%llu ack%s (for %llu byte%s)\n");
    333 	p(tcps_rcvdupack, "\t\t%llu duplicate ack%s\n");
    334 	p(tcps_rcvacktoomuch, "\t\t%llu ack%s for unsent data\n");
    335 	p2(tcps_rcvpack, tcps_rcvbyte,
    336 		"\t\t%llu packet%s (%llu byte%s) received in-sequence\n");
    337 	p2(tcps_rcvduppack, tcps_rcvdupbyte,
    338 		"\t\t%llu completely duplicate packet%s (%llu byte%s)\n");
    339 	p(tcps_pawsdrop, "\t\t%llu old duplicate packet%s\n");
    340 	p2(tcps_rcvpartduppack, tcps_rcvpartdupbyte,
    341 		"\t\t%llu packet%s with some dup. data (%llu byte%s duped)\n");
    342 	p2(tcps_rcvoopack, tcps_rcvoobyte,
    343 		"\t\t%llu out-of-order packet%s (%llu byte%s)\n");
    344 	p2(tcps_rcvpackafterwin, tcps_rcvbyteafterwin,
    345 		"\t\t%llu packet%s (%llu byte%s) of data after window\n");
    346 	p(tcps_rcvwinprobe, "\t\t%llu window probe%s\n");
    347 	p(tcps_rcvwinupd, "\t\t%llu window update packet%s\n");
    348 	p(tcps_rcvafterclose, "\t\t%llu packet%s received after close\n");
    349 	p(tcps_rcvbadsum, "\t\t%llu discarded for bad checksum%s\n");
    350 	p(tcps_rcvbadoff, "\t\t%llu discarded for bad header offset field%s\n");
    351 	ps(tcps_rcvshort, "\t\t%llu discarded because packet too short\n");
    352 	p(tcps_connattempt, "\t%llu connection request%s\n");
    353 	p(tcps_accepts, "\t%llu connection accept%s\n");
    354 	p(tcps_connects,
    355 		"\t%llu connection%s established (including accepts)\n");
    356 	p2(tcps_closed, tcps_drops,
    357 		"\t%llu connection%s closed (including %llu drop%s)\n");
    358 	p(tcps_conndrops, "\t%llu embryonic connection%s dropped\n");
    359 	p(tcps_delayed_free, "\t%llu delayed free%s of tcpcb\n");
    360 	p2(tcps_rttupdated, tcps_segstimed,
    361 		"\t%llu segment%s updated rtt (of %llu attempt%s)\n");
    362 	p(tcps_rexmttimeo, "\t%llu retransmit timeout%s\n");
    363 	p(tcps_timeoutdrop,
    364 		"\t\t%llu connection%s dropped by rexmit timeout\n");
    365 	p2(tcps_persisttimeo, tcps_persistdrops,
    366 	   "\t%llu persist timeout%s (resulting in %llu dropped "
    367 		"connection%s)\n");
    368 	p(tcps_keeptimeo, "\t%llu keepalive timeout%s\n");
    369 	p(tcps_keepprobe, "\t\t%llu keepalive probe%s sent\n");
    370 	p(tcps_keepdrops, "\t\t%llu connection%s dropped by keepalive\n");
    371 	p(tcps_predack, "\t%llu correct ACK header prediction%s\n");
    372 	p(tcps_preddat, "\t%llu correct data packet header prediction%s\n");
    373 	p3(tcps_pcbhashmiss, "\t%llu PCB hash miss%s\n");
    374 	ps(tcps_noport, "\t%llu dropped due to no socket\n");
    375 	p(tcps_connsdrained, "\t%llu connection%s drained due to memory "
    376 		"shortage\n");
    377 	p(tcps_pmtublackhole, "\t%llu PMTUD blackhole%s detected\n");
    378 
    379 	p(tcps_badsyn, "\t%llu bad connection attempt%s\n");
    380 	ps(tcps_sc_added, "\t%llu SYN cache entries added\n");
    381 	p(tcps_sc_collisions, "\t\t%llu hash collision%s\n");
    382 	ps(tcps_sc_completed, "\t\t%llu completed\n");
    383 	ps(tcps_sc_aborted, "\t\t%llu aborted (no space to build PCB)\n");
    384 	ps(tcps_sc_timed_out, "\t\t%llu timed out\n");
    385 	ps(tcps_sc_overflowed, "\t\t%llu dropped due to overflow\n");
    386 	ps(tcps_sc_bucketoverflow, "\t\t%llu dropped due to bucket overflow\n");
    387 	ps(tcps_sc_reset, "\t\t%llu dropped due to RST\n");
    388 	ps(tcps_sc_unreach, "\t\t%llu dropped due to ICMP unreachable\n");
    389 	ps(tcps_sc_delayed_free, "\t\t%llu delayed free of SYN cache "
    390 		"entries\n");
    391 	p(tcps_sc_retransmitted, "\t%llu SYN,ACK%s retransmitted\n");
    392 	p(tcps_sc_dupesyn, "\t%llu duplicate SYN%s received for entries "
    393 		"already in the cache\n");
    394 	p(tcps_sc_dropped, "\t%llu SYN%s dropped (no route or no space)\n");
    395 	p(tcps_badsig, "\t%llu packet%s with bad signature\n");
    396 	p(tcps_goodsig, "\t%llu packet%s with good signature\n");
    397 
    398 	p(tcps_ecn_shs, "\t%llu sucessful ECN handshake%s\n");
    399 	p(tcps_ecn_ce, "\t%llu packet%s with ECN CE bit\n");
    400 	p(tcps_ecn_ect, "\t%llu packet%s ECN ECT(0) bit\n");
    401 #undef p
    402 #undef ps
    403 #undef p2
    404 #undef p2s
    405 #undef p3
    406 }
    407 
    408 /*
    409  * Dump UDP statistics structure.
    410  */
    411 void
    412 udp_stats(off, name)
    413 	u_long off;
    414 	char *name;
    415 {
    416 	struct udpstat udpstat;
    417 	u_quad_t delivered;
    418 
    419 	if (use_sysctl) {
    420 		size_t size = sizeof(udpstat);
    421 
    422 		if (sysctlbyname("net.inet.udp.stats", &udpstat, &size,
    423 				 NULL, 0) == -1)
    424 			err(1, "net.inet.udp.stats");
    425 	} else {
    426 		if (off == 0)
    427 			return;
    428 		kread(off, (char *)&udpstat, sizeof (udpstat));
    429 	}
    430 
    431 	printf ("%s:\n", name);
    432 
    433 #define	ps(f, m) if (udpstat.f || sflag <= 1) \
    434     printf(m, (unsigned long long)udpstat.f)
    435 #define	p(f, m) if (udpstat.f || sflag <= 1) \
    436     printf(m, (unsigned long long)udpstat.f, plural(udpstat.f))
    437 #define	p3(f, m) if (udpstat.f || sflag <= 1) \
    438     printf(m, (unsigned long long)udpstat.f, plurales(udpstat.f))
    439 
    440 	p(udps_ipackets, "\t%llu datagram%s received\n");
    441 	ps(udps_hdrops, "\t%llu with incomplete header\n");
    442 	ps(udps_badlen, "\t%llu with bad data length field\n");
    443 	ps(udps_badsum, "\t%llu with bad checksum\n");
    444 	ps(udps_noport, "\t%llu dropped due to no socket\n");
    445 	p(udps_noportbcast, "\t%llu broadcast/multicast datagram%s dropped due to no socket\n");
    446 	ps(udps_fullsock, "\t%llu dropped due to full socket buffers\n");
    447 	delivered = udpstat.udps_ipackets -
    448 		    udpstat.udps_hdrops -
    449 		    udpstat.udps_badlen -
    450 		    udpstat.udps_badsum -
    451 		    udpstat.udps_noport -
    452 		    udpstat.udps_noportbcast -
    453 		    udpstat.udps_fullsock;
    454 	if (delivered || sflag <= 1)
    455 		printf("\t%llu delivered\n", (unsigned long long)delivered);
    456 	p3(udps_pcbhashmiss, "\t%llu PCB hash miss%s\n");
    457 	p(udps_opackets, "\t%llu datagram%s output\n");
    458 
    459 #undef ps
    460 #undef p
    461 #undef p3
    462 }
    463 
    464 /*
    465  * Dump IP statistics structure.
    466  */
    467 void
    468 ip_stats(off, name)
    469 	u_long off;
    470 	char *name;
    471 {
    472 	struct ipstat ipstat;
    473 
    474 	if (use_sysctl) {
    475 		size_t size = sizeof(ipstat);
    476 
    477 		if (sysctlbyname("net.inet.ip.stats", &ipstat, &size,
    478 				 NULL, 0) == -1)
    479 			err(1, "net.inet.ip.stats");
    480 	} else {
    481 		if (off == 0)
    482 			return;
    483 		kread(off, (char *)&ipstat, sizeof (ipstat));
    484 	}
    485 
    486 	printf("%s:\n", name);
    487 
    488 #define	ps(f, m) if (ipstat.f || sflag <= 1) \
    489     printf(m, (unsigned long long)ipstat.f)
    490 #define	p(f, m) if (ipstat.f || sflag <= 1) \
    491     printf(m, (unsigned long long)ipstat.f, plural(ipstat.f))
    492 
    493 	p(ips_total, "\t%llu total packet%s received\n");
    494 	p(ips_badsum, "\t%llu bad header checksum%s\n");
    495 	ps(ips_toosmall, "\t%llu with size smaller than minimum\n");
    496 	ps(ips_tooshort, "\t%llu with data size < data length\n");
    497 	ps(ips_toolong, "\t%llu with length > max ip packet size\n");
    498 	ps(ips_badhlen, "\t%llu with header length < data size\n");
    499 	ps(ips_badlen, "\t%llu with data length < header length\n");
    500 	ps(ips_badoptions, "\t%llu with bad options\n");
    501 	ps(ips_badvers, "\t%llu with incorrect version number\n");
    502 	p(ips_fragments, "\t%llu fragment%s received\n");
    503 	p(ips_fragdropped, "\t%llu fragment%s dropped (dup or out of space)\n");
    504 	p(ips_rcvmemdrop, "\t%llu fragment%s dropped (out of ipqent)\n");
    505 	p(ips_badfrags, "\t%llu malformed fragment%s dropped\n");
    506 	p(ips_fragtimeout, "\t%llu fragment%s dropped after timeout\n");
    507 	p(ips_reassembled, "\t%llu packet%s reassembled ok\n");
    508 	p(ips_delivered, "\t%llu packet%s for this host\n");
    509 	p(ips_noproto, "\t%llu packet%s for unknown/unsupported protocol\n");
    510 	p(ips_forward, "\t%llu packet%s forwarded");
    511 	p(ips_fastforward, " (%llu packet%s fast forwarded)");
    512 	if (ipstat.ips_forward || sflag <= 1)
    513 		putchar('\n');
    514 	p(ips_cantforward, "\t%llu packet%s not forwardable\n");
    515 	p(ips_redirectsent, "\t%llu redirect%s sent\n");
    516 	p(ips_nogif, "\t%llu packet%s no matching gif found\n");
    517 	p(ips_localout, "\t%llu packet%s sent from this host\n");
    518 	p(ips_rawout, "\t%llu packet%s sent with fabricated ip header\n");
    519 	p(ips_odropped, "\t%llu output packet%s dropped due to no bufs, etc.\n");
    520 	p(ips_noroute, "\t%llu output packet%s discarded due to no route\n");
    521 	p(ips_fragmented, "\t%llu output datagram%s fragmented\n");
    522 	p(ips_ofragments, "\t%llu fragment%s created\n");
    523 	p(ips_cantfrag, "\t%llu datagram%s that can't be fragmented\n");
    524 	p(ips_badaddr, "\t%llu datagram%s with bad address in header\n");
    525 #undef ps
    526 #undef p
    527 }
    528 
    529 static	char *icmpnames[] = {
    530 	"echo reply",
    531 	"#1",
    532 	"#2",
    533 	"destination unreachable",
    534 	"source quench",
    535 	"routing redirect",
    536 	"alternate host address",
    537 	"#7",
    538 	"echo",
    539 	"router advertisement",
    540 	"router solicitation",
    541 	"time exceeded",
    542 	"parameter problem",
    543 	"time stamp",
    544 	"time stamp reply",
    545 	"information request",
    546 	"information request reply",
    547 	"address mask request",
    548 	"address mask reply",
    549 };
    550 
    551 /*
    552  * Dump ICMP statistics.
    553  */
    554 void
    555 icmp_stats(off, name)
    556 	u_long off;
    557 	char *name;
    558 {
    559 	struct icmpstat icmpstat;
    560 	int i, first;
    561 
    562 	if (use_sysctl) {
    563 		size_t size = sizeof(icmpstat);
    564 
    565 		if (sysctlbyname("net.inet.icmp.stats", &icmpstat, &size,
    566 				 NULL, 0) == -1)
    567 			err(1, "net.inet.icmp.stats");
    568 	} else {
    569 		if (off == 0)
    570 			return;
    571 		kread(off, (char *)&icmpstat, sizeof (icmpstat));
    572 	}
    573 
    574 	printf("%s:\n", name);
    575 
    576 #define	p(f, m) if (icmpstat.f || sflag <= 1) \
    577     printf(m, (unsigned long long)icmpstat.f, plural(icmpstat.f))
    578 
    579 	p(icps_error, "\t%llu call%s to icmp_error\n");
    580 	p(icps_oldicmp,
    581 	    "\t%llu error%s not generated because old message was icmp\n");
    582 	for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
    583 		if (icmpstat.icps_outhist[i] != 0) {
    584 			if (first) {
    585 				printf("\tOutput histogram:\n");
    586 				first = 0;
    587 			}
    588 			printf("\t\t%s: %llu\n", icmpnames[i],
    589 				(unsigned long long)icmpstat.icps_outhist[i]);
    590 		}
    591 	p(icps_badcode, "\t%llu message%s with bad code fields\n");
    592 	p(icps_tooshort, "\t%llu message%s < minimum length\n");
    593 	p(icps_checksum, "\t%llu bad checksum%s\n");
    594 	p(icps_badlen, "\t%llu message%s with bad length\n");
    595 	for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
    596 		if (icmpstat.icps_inhist[i] != 0) {
    597 			if (first) {
    598 				printf("\tInput histogram:\n");
    599 				first = 0;
    600 			}
    601 			printf("\t\t%s: %llu\n", icmpnames[i],
    602 				(unsigned long long)icmpstat.icps_inhist[i]);
    603 		}
    604 	p(icps_reflect, "\t%llu message response%s generated\n");
    605 	p(icps_pmtuchg, "\t%llu path MTU change%s\n");
    606 #undef p
    607 }
    608 
    609 /*
    610  * Dump IGMP statistics structure.
    611  */
    612 void
    613 igmp_stats(off, name)
    614 	u_long off;
    615 	char *name;
    616 {
    617 	struct igmpstat igmpstat;
    618 
    619 	if (off == 0)
    620 		return;
    621 	kread(off, (char *)&igmpstat, sizeof (igmpstat));
    622 	printf("%s:\n", name);
    623 
    624 #define	p(f, m) if (igmpstat.f || sflag <= 1) \
    625     printf(m, (unsigned long long)igmpstat.f, plural(igmpstat.f))
    626 #define	py(f, m) if (igmpstat.f || sflag <= 1) \
    627     printf(m, (unsigned long long)igmpstat.f, igmpstat.f != 1 ? "ies" : "y")
    628 	p(igps_rcv_total, "\t%llu message%s received\n");
    629         p(igps_rcv_tooshort, "\t%llu message%s received with too few bytes\n");
    630         p(igps_rcv_badsum, "\t%llu message%s received with bad checksum\n");
    631         py(igps_rcv_queries, "\t%llu membership quer%s received\n");
    632         py(igps_rcv_badqueries, "\t%llu membership quer%s received with invalid field(s)\n");
    633         p(igps_rcv_reports, "\t%llu membership report%s received\n");
    634         p(igps_rcv_badreports, "\t%llu membership report%s received with invalid field(s)\n");
    635         p(igps_rcv_ourreports, "\t%llu membership report%s received for groups to which we belong\n");
    636         p(igps_snd_reports, "\t%llu membership report%s sent\n");
    637 #undef p
    638 #undef py
    639 }
    640 
    641 /*
    642  * Dump CARP statistics structure.
    643  */
    644 void
    645 carp_stats(u_long off, char *name)
    646 {
    647 	struct carpstats carpstat;
    648 
    649 	if (use_sysctl) {
    650 		size_t size = sizeof(carpstat);
    651 
    652 		if (sysctlbyname("net.inet.carp.stats", &carpstat, &size,
    653 				 NULL, 0) == -1) {
    654 			/* most likely CARP is not compiled in the kernel */
    655 			return;
    656 		}
    657 	} else {
    658 		if (off == 0)
    659 			return;
    660 		kread(off, (char *)&carpstat, sizeof(carpstat));
    661 	}
    662 
    663 	printf("%s:\n", name);
    664 
    665 #define p(f, m) if (carpstat.f || sflag <= 1) \
    666 	printf(m, carpstat.f, plural(carpstat.f))
    667 #define p2(f, m) if (carpstat.f || sflag <= 1) \
    668 	printf(m, carpstat.f)
    669 
    670 	p(carps_ipackets, "\t%" PRIu64 " packet%s received (IPv4)\n");
    671 	p(carps_ipackets6, "\t%" PRIu64 " packet%s received (IPv6)\n");
    672 	p(carps_badif,
    673 	    "\t\t%" PRIu64 " packet%s discarded for bad interface\n");
    674 	p(carps_badttl,
    675 	    "\t\t%" PRIu64 " packet%s discarded for wrong TTL\n");
    676 	p(carps_hdrops, "\t\t%" PRIu64 " packet%s shorter than header\n");
    677 	p(carps_badsum, "\t\t%" PRIu64
    678 		" packet%s discarded for bad checksum\n");
    679 	p(carps_badver,
    680 	    "\t\t%" PRIu64 " packet%s discarded with a bad version\n");
    681 	p2(carps_badlen,
    682 	    "\t\t%" PRIu64 " discarded because packet was too short\n");
    683 	p(carps_badauth,
    684 	    "\t\t%" PRIu64 " packet%s discarded for bad authentication\n");
    685 	p(carps_badvhid, "\t\t%" PRIu64 " packet%s discarded for bad vhid\n");
    686 	p(carps_badaddrs, "\t\t%" PRIu64
    687 		" packet%s discarded because of a bad address list\n");
    688 	p(carps_opackets, "\t%" PRIu64 " packet%s sent (IPv4)\n");
    689 	p(carps_opackets6, "\t%" PRIu64 " packet%s sent (IPv6)\n");
    690 	p2(carps_onomem,
    691 	    "\t\t%" PRIu64 " send failed due to mbuf memory error\n");
    692 #undef p
    693 #undef p2
    694 }
    695 
    696 /*
    697  * Dump PIM statistics structure.
    698  */
    699 void
    700 pim_stats(off, name)
    701 	u_long off;
    702 	char *name;
    703 {
    704 	struct pimstat pimstat;
    705 
    706 	if (off == 0)
    707 		return;
    708 	if (kread(off, (char *)&pimstat, sizeof (pimstat)) != 0) {
    709 		/* XXX: PIM is probably not enabled in the kernel */
    710 		return;
    711 	}
    712 
    713 	printf("%s:\n", name);
    714 
    715 #define	p(f, m) if (pimstat.f || sflag <= 1) \
    716 	printf(m, (unsigned long long)pimstat.f, plural(pimstat.f))
    717 
    718 	p(pims_rcv_total_msgs, "\t%llu message%s received\n");
    719 	p(pims_rcv_total_bytes, "\t%llu byte%s received\n");
    720 	p(pims_rcv_tooshort, "\t%llu message%s received with too few bytes\n");
    721         p(pims_rcv_badsum, "\t%llu message%s received with bad checksum\n");
    722 	p(pims_rcv_badversion, "\t%llu message%s received with bad version\n");
    723 	p(pims_rcv_registers_msgs, "\t%llu data register message%s received\n");
    724 	p(pims_rcv_registers_bytes, "\t%llu data register byte%s received\n");
    725 	p(pims_rcv_registers_wrongiif, "\t%llu data register message%s received on wrong iif\n");
    726 	p(pims_rcv_badregisters, "\t%llu bad register%s received\n");
    727 	p(pims_snd_registers_msgs, "\t%llu data register message%s sent\n");
    728 	p(pims_snd_registers_bytes, "\t%llu data register byte%s sent\n");
    729 #undef p
    730 }
    731 
    732 /*
    733  * Dump the ARP statistics structure.
    734  */
    735 void
    736 arp_stats(off, name)
    737 	u_long off;
    738 	char *name;
    739 {
    740 	struct arpstat arpstat;
    741 
    742 	if (off == 0)
    743 		return;
    744 	kread(off, (char *)&arpstat, sizeof (arpstat));
    745 	printf("%s:\n", name);
    746 
    747 #define	ps(f, m) if (arpstat.f || sflag <= 1) \
    748     printf(m, (unsigned long long)arpstat.f)
    749 #define	p(f, m) if (arpstat.f || sflag <= 1) \
    750     printf(m, (unsigned long long)arpstat.f, plural(arpstat.f))
    751 
    752 	p(as_sndtotal, "\t%llu packet%s sent\n");
    753 	p(as_sndreply, "\t\t%llu reply packet%s\n");
    754 	p(as_sndrequest, "\t\t%llu request packet%s\n");
    755 
    756 	p(as_rcvtotal, "\t%llu packet%s received\n");
    757 	p(as_rcvreply, "\t\t%llu reply packet%s\n");
    758 	p(as_rcvrequest, "\t\t%llu valid request packet%s\n");
    759 	p(as_rcvmcast, "\t\t%llu broadcast/multicast packet%s\n");
    760 	p(as_rcvbadproto, "\t\t%llu packet%s with unknown protocol type\n");
    761 	p(as_rcvbadlen, "\t\t%llu packet%s with bad (short) length\n");
    762 	p(as_rcvzerotpa, "\t\t%llu packet%s with null target IP address\n");
    763 	p(as_rcvzerospa, "\t\t%llu packet%s with null source IP address\n");
    764 	ps(as_rcvnoint, "\t\t%llu could not be mapped to an interface\n");
    765 	p(as_rcvlocalsha, "\t\t%llu packet%s sourced from a local hardware "
    766 	    "address\n");
    767 	p(as_rcvbcastsha, "\t\t%llu packet%s with a broadcast "
    768 	    "source hardware address\n");
    769 	p(as_rcvlocalspa, "\t\t%llu duplicate%s for a local IP address\n");
    770 	p(as_rcvoverperm, "\t\t%llu attempt%s to overwrite a static entry\n");
    771 	p(as_rcvoverint, "\t\t%llu packet%s received on wrong interface\n");
    772 	p(as_rcvover, "\t\t%llu entry%s overwritten\n");
    773 	p(as_rcvlenchg, "\t\t%llu change%s in hardware address length\n");
    774 
    775 	p(as_dfrtotal, "\t%llu packet%s deferred pending ARP resolution\n");
    776 	ps(as_dfrsent, "\t\t%llu sent\n");
    777 	ps(as_dfrdropped, "\t\t%llu dropped\n");
    778 
    779 	p(as_allocfail, "\t%llu failure%s to allocate llinfo\n");
    780 
    781 #undef ps
    782 #undef p
    783 }
    784 
    785 /*
    786  * Pretty print an Internet address (net address + port).
    787  * Take numeric_addr and numeric_port into consideration.
    788  */
    789 void
    790 inetprint(in, port, proto, numeric_port)
    791 	struct in_addr *in;
    792 	u_int16_t port;
    793 	const char *proto;
    794 	int numeric_port;
    795 {
    796 	struct servent *sp = 0;
    797 	char line[80], *cp;
    798 	size_t space;
    799 
    800 	(void)snprintf(line, sizeof line, "%.*s.",
    801 	    (Aflag && !numeric_addr) ? 12 : 16, inetname(in));
    802 	cp = strchr(line, '\0');
    803 	if (!numeric_port && port)
    804 		sp = getservbyport((int)port, proto);
    805 	space = sizeof line - (cp-line);
    806 	if (sp || port == 0)
    807 		(void)snprintf(cp, space, "%s", sp ? sp->s_name : "*");
    808 	else
    809 		(void)snprintf(cp, space, "%u", ntohs(port));
    810 	(void)printf(" %-*.*s", width, width, line);
    811 }
    812 
    813 /*
    814  * Construct an Internet address representation.
    815  * If numeric_addr has been supplied, give
    816  * numeric value, otherwise try for symbolic name.
    817  */
    818 char *
    819 inetname(inp)
    820 	struct in_addr *inp;
    821 {
    822 	char *cp;
    823 	static char line[50];
    824 	struct hostent *hp;
    825 	struct netent *np;
    826 	static char domain[MAXHOSTNAMELEN + 1];
    827 	static int first = 1;
    828 
    829 	if (first && !numeric_addr) {
    830 		first = 0;
    831 		if (gethostname(domain, sizeof domain) == 0) {
    832 			domain[sizeof(domain) - 1] = '\0';
    833 			if ((cp = strchr(domain, '.')))
    834 				(void) strlcpy(domain, cp + 1, sizeof(domain));
    835 			else
    836 				domain[0] = 0;
    837 		} else
    838 			domain[0] = 0;
    839 	}
    840 	cp = 0;
    841 	if (!numeric_addr && inp->s_addr != INADDR_ANY) {
    842 		int net = inet_netof(*inp);
    843 		int lna = inet_lnaof(*inp);
    844 
    845 		if (lna == INADDR_ANY) {
    846 			np = getnetbyaddr(net, AF_INET);
    847 			if (np)
    848 				cp = np->n_name;
    849 		}
    850 		if (cp == 0) {
    851 			hp = gethostbyaddr((char *)inp, sizeof (*inp), AF_INET);
    852 			if (hp) {
    853 				if ((cp = strchr(hp->h_name, '.')) &&
    854 				    !strcmp(cp + 1, domain))
    855 					*cp = 0;
    856 				cp = hp->h_name;
    857 			}
    858 		}
    859 	}
    860 	if (inp->s_addr == INADDR_ANY)
    861 		strlcpy(line, "*", sizeof line);
    862 	else if (cp)
    863 		strlcpy(line, cp, sizeof line);
    864 	else {
    865 		inp->s_addr = ntohl(inp->s_addr);
    866 #define C(x)	((x) & 0xff)
    867 		(void)snprintf(line, sizeof line, "%u.%u.%u.%u",
    868 		    C(inp->s_addr >> 24), C(inp->s_addr >> 16),
    869 		    C(inp->s_addr >> 8), C(inp->s_addr));
    870 #undef C
    871 	}
    872 	return (line);
    873 }
    874 
    875 /*
    876  * Dump the contents of a TCP PCB.
    877  */
    878 void
    879 tcp_dump(pcbaddr)
    880 	u_long pcbaddr;
    881 {
    882 	struct tcpcb tcpcb;
    883 	int i, hardticks;
    884 
    885 	kread(pcbaddr, (char *)&tcpcb, sizeof(tcpcb));
    886 	hardticks = get_hardticks();
    887 
    888 	printf("TCP Protocol Control Block at 0x%08lx:\n\n", pcbaddr);
    889 
    890 	printf("Timers:\n");
    891 	for (i = 0; i < TCPT_NTIMERS; i++) {
    892 		printf("\t%s: %d", tcptimers[i],
    893 		    (tcpcb.t_timer[i].c_flags & CALLOUT_PENDING) ?
    894 		    tcpcb.t_timer[i].c_time - hardticks : 0);
    895 	}
    896 	printf("\n\n");
    897 
    898 	if (tcpcb.t_state < 0 || tcpcb.t_state >= TCP_NSTATES)
    899 		printf("State: %d", tcpcb.t_state);
    900 	else
    901 		printf("State: %s", tcpstates[tcpcb.t_state]);
    902 	printf(", flags 0x%x, inpcb 0x%lx, in6pcb 0x%lx\n\n", tcpcb.t_flags,
    903 	    (u_long)tcpcb.t_inpcb, (u_long)tcpcb.t_in6pcb);
    904 
    905 	printf("rxtshift %d, rxtcur %d, dupacks %d\n", tcpcb.t_rxtshift,
    906 	    tcpcb.t_rxtcur, tcpcb.t_dupacks);
    907 	printf("peermss %u, ourmss %u, segsz %u\n\n", tcpcb.t_peermss,
    908 	    tcpcb.t_ourmss, tcpcb.t_segsz);
    909 
    910 	printf("snd_una %u, snd_nxt %u, snd_up %u\n",
    911 	    tcpcb.snd_una, tcpcb.snd_nxt, tcpcb.snd_up);
    912 	printf("snd_wl1 %u, snd_wl2 %u, iss %u, snd_wnd %lu\n\n",
    913 	    tcpcb.snd_wl1, tcpcb.snd_wl2, tcpcb.iss, tcpcb.snd_wnd);
    914 
    915 	printf("rcv_wnd %lu, rcv_nxt %u, rcv_up %u, irs %u\n\n",
    916 	    tcpcb.rcv_wnd, tcpcb.rcv_nxt, tcpcb.rcv_up, tcpcb.irs);
    917 
    918 	printf("rcv_adv %u, snd_max %u, snd_cwnd %lu, snd_ssthresh %lu\n",
    919 	    tcpcb.rcv_adv, tcpcb.snd_max, tcpcb.snd_cwnd, tcpcb.snd_ssthresh);
    920 
    921 	printf("rcvtime %u, rtttime %u, rtseq %u, srtt %d, rttvar %d, "
    922 	    "rttmin %d, max_sndwnd %lu\n\n", tcpcb.t_rcvtime, tcpcb.t_rtttime,
    923 	    tcpcb.t_rtseq, tcpcb.t_srtt, tcpcb.t_rttvar, tcpcb.t_rttmin,
    924 	    tcpcb.max_sndwnd);
    925 
    926 	printf("oobflags %d, iobc %d, softerror %d\n\n", tcpcb.t_oobflags,
    927 	    tcpcb.t_iobc, tcpcb.t_softerror);
    928 
    929 	printf("snd_scale %d, rcv_scale %d, req_r_scale %d, req_s_scale %d\n",
    930 	    tcpcb.snd_scale, tcpcb.rcv_scale, tcpcb.request_r_scale,
    931 	    tcpcb.requested_s_scale);
    932 	printf("ts_recent %u, ts_regent_age %d, last_ack_sent %u\n",
    933 	    tcpcb.ts_recent, tcpcb.ts_recent_age, tcpcb.last_ack_sent);
    934 }
    935