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