xref: /netbsd-src/usr.bin/netstat/inet.c (revision 8b0f9554ff8762542c4defc4f70e1eb76fb508fa)
1 /*	$NetBSD: inet.c,v 1.78 2007/07/10 21:12:33 ad 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.78 2007/07/10 21:12:33 ad 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(off, name)
411 	u_long off;
412 	char *name;
413 {
414 	struct udpstat udpstat;
415 	u_quad_t delivered;
416 
417 	if (use_sysctl) {
418 		size_t size = sizeof(udpstat);
419 
420 		if (sysctlbyname("net.inet.udp.stats", &udpstat, &size,
421 				 NULL, 0) == -1)
422 			err(1, "net.inet.udp.stats");
423 	} else {
424 		if (off == 0)
425 			return;
426 		kread(off, (char *)&udpstat, sizeof (udpstat));
427 	}
428 
429 	printf ("%s:\n", name);
430 
431 #define	ps(f, m) if (udpstat.f || sflag <= 1) \
432     printf(m, (unsigned long long)udpstat.f)
433 #define	p(f, m) if (udpstat.f || sflag <= 1) \
434     printf(m, (unsigned long long)udpstat.f, plural(udpstat.f))
435 #define	p3(f, m) if (udpstat.f || sflag <= 1) \
436     printf(m, (unsigned long long)udpstat.f, plurales(udpstat.f))
437 
438 	p(udps_ipackets, "\t%llu datagram%s received\n");
439 	ps(udps_hdrops, "\t%llu with incomplete header\n");
440 	ps(udps_badlen, "\t%llu with bad data length field\n");
441 	ps(udps_badsum, "\t%llu with bad checksum\n");
442 	ps(udps_noport, "\t%llu dropped due to no socket\n");
443 	p(udps_noportbcast, "\t%llu broadcast/multicast datagram%s dropped due to no socket\n");
444 	ps(udps_fullsock, "\t%llu dropped due to full socket buffers\n");
445 	delivered = udpstat.udps_ipackets -
446 		    udpstat.udps_hdrops -
447 		    udpstat.udps_badlen -
448 		    udpstat.udps_badsum -
449 		    udpstat.udps_noport -
450 		    udpstat.udps_noportbcast -
451 		    udpstat.udps_fullsock;
452 	if (delivered || sflag <= 1)
453 		printf("\t%llu delivered\n", (unsigned long long)delivered);
454 	p3(udps_pcbhashmiss, "\t%llu PCB hash miss%s\n");
455 	p(udps_opackets, "\t%llu datagram%s output\n");
456 
457 #undef ps
458 #undef p
459 #undef p3
460 }
461 
462 /*
463  * Dump IP statistics structure.
464  */
465 void
466 ip_stats(off, name)
467 	u_long off;
468 	char *name;
469 {
470 	struct ipstat ipstat;
471 
472 	if (use_sysctl) {
473 		size_t size = sizeof(ipstat);
474 
475 		if (sysctlbyname("net.inet.ip.stats", &ipstat, &size,
476 				 NULL, 0) == -1)
477 			err(1, "net.inet.ip.stats");
478 	} else {
479 		if (off == 0)
480 			return;
481 		kread(off, (char *)&ipstat, sizeof (ipstat));
482 	}
483 
484 	printf("%s:\n", name);
485 
486 #define	ps(f, m) if (ipstat.f || sflag <= 1) \
487     printf(m, (unsigned long long)ipstat.f)
488 #define	p(f, m) if (ipstat.f || sflag <= 1) \
489     printf(m, (unsigned long long)ipstat.f, plural(ipstat.f))
490 
491 	p(ips_total, "\t%llu total packet%s received\n");
492 	p(ips_badsum, "\t%llu bad header checksum%s\n");
493 	ps(ips_toosmall, "\t%llu with size smaller than minimum\n");
494 	ps(ips_tooshort, "\t%llu with data size < data length\n");
495 	ps(ips_toolong, "\t%llu with length > max ip packet size\n");
496 	ps(ips_badhlen, "\t%llu with header length < data size\n");
497 	ps(ips_badlen, "\t%llu with data length < header length\n");
498 	ps(ips_badoptions, "\t%llu with bad options\n");
499 	ps(ips_badvers, "\t%llu with incorrect version number\n");
500 	p(ips_fragments, "\t%llu fragment%s received\n");
501 	p(ips_fragdropped, "\t%llu fragment%s dropped (dup or out of space)\n");
502 	p(ips_rcvmemdrop, "\t%llu fragment%s dropped (out of ipqent)\n");
503 	p(ips_badfrags, "\t%llu malformed fragment%s dropped\n");
504 	p(ips_fragtimeout, "\t%llu fragment%s dropped after timeout\n");
505 	p(ips_reassembled, "\t%llu packet%s reassembled ok\n");
506 	p(ips_delivered, "\t%llu packet%s for this host\n");
507 	p(ips_noproto, "\t%llu packet%s for unknown/unsupported protocol\n");
508 	p(ips_forward, "\t%llu packet%s forwarded");
509 	p(ips_fastforward, " (%llu packet%s fast forwarded)");
510 	if (ipstat.ips_forward || sflag <= 1)
511 		putchar('\n');
512 	p(ips_cantforward, "\t%llu packet%s not forwardable\n");
513 	p(ips_redirectsent, "\t%llu redirect%s sent\n");
514 	p(ips_nogif, "\t%llu packet%s no matching gif found\n");
515 	p(ips_localout, "\t%llu packet%s sent from this host\n");
516 	p(ips_rawout, "\t%llu packet%s sent with fabricated ip header\n");
517 	p(ips_odropped, "\t%llu output packet%s dropped due to no bufs, etc.\n");
518 	p(ips_noroute, "\t%llu output packet%s discarded due to no route\n");
519 	p(ips_fragmented, "\t%llu output datagram%s fragmented\n");
520 	p(ips_ofragments, "\t%llu fragment%s created\n");
521 	p(ips_cantfrag, "\t%llu datagram%s that can't be fragmented\n");
522 	p(ips_badaddr, "\t%llu datagram%s with bad address in header\n");
523 #undef ps
524 #undef p
525 }
526 
527 static	char *icmpnames[] = {
528 	"echo reply",
529 	"#1",
530 	"#2",
531 	"destination unreachable",
532 	"source quench",
533 	"routing redirect",
534 	"alternate host address",
535 	"#7",
536 	"echo",
537 	"router advertisement",
538 	"router solicitation",
539 	"time exceeded",
540 	"parameter problem",
541 	"time stamp",
542 	"time stamp reply",
543 	"information request",
544 	"information request reply",
545 	"address mask request",
546 	"address mask reply",
547 };
548 
549 /*
550  * Dump ICMP statistics.
551  */
552 void
553 icmp_stats(off, name)
554 	u_long off;
555 	char *name;
556 {
557 	struct icmpstat icmpstat;
558 	int i, first;
559 
560 	if (use_sysctl) {
561 		size_t size = sizeof(icmpstat);
562 
563 		if (sysctlbyname("net.inet.icmp.stats", &icmpstat, &size,
564 				 NULL, 0) == -1)
565 			err(1, "net.inet.icmp.stats");
566 	} else {
567 		if (off == 0)
568 			return;
569 		kread(off, (char *)&icmpstat, sizeof (icmpstat));
570 	}
571 
572 	printf("%s:\n", name);
573 
574 #define	p(f, m) if (icmpstat.f || sflag <= 1) \
575     printf(m, (unsigned long long)icmpstat.f, plural(icmpstat.f))
576 
577 	p(icps_error, "\t%llu call%s to icmp_error\n");
578 	p(icps_oldicmp,
579 	    "\t%llu error%s not generated because old message was icmp\n");
580 	for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
581 		if (icmpstat.icps_outhist[i] != 0) {
582 			if (first) {
583 				printf("\tOutput histogram:\n");
584 				first = 0;
585 			}
586 			printf("\t\t%s: %llu\n", icmpnames[i],
587 				(unsigned long long)icmpstat.icps_outhist[i]);
588 		}
589 	p(icps_badcode, "\t%llu message%s with bad code fields\n");
590 	p(icps_tooshort, "\t%llu message%s < minimum length\n");
591 	p(icps_checksum, "\t%llu bad checksum%s\n");
592 	p(icps_badlen, "\t%llu message%s with bad length\n");
593 	for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
594 		if (icmpstat.icps_inhist[i] != 0) {
595 			if (first) {
596 				printf("\tInput histogram:\n");
597 				first = 0;
598 			}
599 			printf("\t\t%s: %llu\n", icmpnames[i],
600 				(unsigned long long)icmpstat.icps_inhist[i]);
601 		}
602 	p(icps_reflect, "\t%llu message response%s generated\n");
603 	p(icps_pmtuchg, "\t%llu path MTU change%s\n");
604 #undef p
605 }
606 
607 /*
608  * Dump IGMP statistics structure.
609  */
610 void
611 igmp_stats(off, name)
612 	u_long off;
613 	char *name;
614 {
615 	struct igmpstat igmpstat;
616 
617 	if (off == 0)
618 		return;
619 	kread(off, (char *)&igmpstat, sizeof (igmpstat));
620 	printf("%s:\n", name);
621 
622 #define	p(f, m) if (igmpstat.f || sflag <= 1) \
623     printf(m, (unsigned long long)igmpstat.f, plural(igmpstat.f))
624 #define	py(f, m) if (igmpstat.f || sflag <= 1) \
625     printf(m, (unsigned long long)igmpstat.f, igmpstat.f != 1 ? "ies" : "y")
626 	p(igps_rcv_total, "\t%llu message%s received\n");
627         p(igps_rcv_tooshort, "\t%llu message%s received with too few bytes\n");
628         p(igps_rcv_badsum, "\t%llu message%s received with bad checksum\n");
629         py(igps_rcv_queries, "\t%llu membership quer%s received\n");
630         py(igps_rcv_badqueries, "\t%llu membership quer%s received with invalid field(s)\n");
631         p(igps_rcv_reports, "\t%llu membership report%s received\n");
632         p(igps_rcv_badreports, "\t%llu membership report%s received with invalid field(s)\n");
633         p(igps_rcv_ourreports, "\t%llu membership report%s received for groups to which we belong\n");
634         p(igps_snd_reports, "\t%llu membership report%s sent\n");
635 #undef p
636 #undef py
637 }
638 
639 /*
640  * Dump CARP statistics structure.
641  */
642 void
643 carp_stats(u_long off, char *name)
644 {
645 	struct carpstats carpstat;
646 
647 	if (use_sysctl) {
648 		size_t size = sizeof(carpstat);
649 
650 		if (sysctlbyname("net.inet.carp.stats", &carpstat, &size,
651 				 NULL, 0) == -1) {
652 			/* most likely CARP is not compiled in the kernel */
653 			return;
654 		}
655 	} else {
656 		if (off == 0)
657 			return;
658 		kread(off, (char *)&carpstat, sizeof(carpstat));
659 	}
660 
661 	printf("%s:\n", name);
662 
663 #define p(f, m) if (carpstat.f || sflag <= 1) \
664 	printf(m, carpstat.f, plural(carpstat.f))
665 #define p2(f, m) if (carpstat.f || sflag <= 1) \
666 	printf(m, carpstat.f)
667 
668 	p(carps_ipackets, "\t%" PRIu64 " packet%s received (IPv4)\n");
669 	p(carps_ipackets6, "\t%" PRIu64 " packet%s received (IPv6)\n");
670 	p(carps_badif,
671 	    "\t\t%" PRIu64 " packet%s discarded for bad interface\n");
672 	p(carps_badttl,
673 	    "\t\t%" PRIu64 " packet%s discarded for wrong TTL\n");
674 	p(carps_hdrops, "\t\t%" PRIu64 " packet%s shorter than header\n");
675 	p(carps_badsum, "\t\t%" PRIu64
676 		" packet%s discarded for bad checksum\n");
677 	p(carps_badver,
678 	    "\t\t%" PRIu64 " packet%s discarded with a bad version\n");
679 	p2(carps_badlen,
680 	    "\t\t%" PRIu64 " discarded because packet was too short\n");
681 	p(carps_badauth,
682 	    "\t\t%" PRIu64 " packet%s discarded for bad authentication\n");
683 	p(carps_badvhid, "\t\t%" PRIu64 " packet%s discarded for bad vhid\n");
684 	p(carps_badaddrs, "\t\t%" PRIu64
685 		" packet%s discarded because of a bad address list\n");
686 	p(carps_opackets, "\t%" PRIu64 " packet%s sent (IPv4)\n");
687 	p(carps_opackets6, "\t%" PRIu64 " packet%s sent (IPv6)\n");
688 	p2(carps_onomem,
689 	    "\t\t%" PRIu64 " send failed due to mbuf memory error\n");
690 #undef p
691 #undef p2
692 }
693 
694 /*
695  * Dump PIM statistics structure.
696  */
697 void
698 pim_stats(off, name)
699 	u_long off;
700 	char *name;
701 {
702 	struct pimstat pimstat;
703 
704 	if (off == 0)
705 		return;
706 	if (kread(off, (char *)&pimstat, sizeof (pimstat)) != 0) {
707 		/* XXX: PIM is probably not enabled in the kernel */
708 		return;
709 	}
710 
711 	printf("%s:\n", name);
712 
713 #define	p(f, m) if (pimstat.f || sflag <= 1) \
714 	printf(m, (unsigned long long)pimstat.f, plural(pimstat.f))
715 
716 	p(pims_rcv_total_msgs, "\t%llu message%s received\n");
717 	p(pims_rcv_total_bytes, "\t%llu byte%s received\n");
718 	p(pims_rcv_tooshort, "\t%llu message%s received with too few bytes\n");
719         p(pims_rcv_badsum, "\t%llu message%s received with bad checksum\n");
720 	p(pims_rcv_badversion, "\t%llu message%s received with bad version\n");
721 	p(pims_rcv_registers_msgs, "\t%llu data register message%s received\n");
722 	p(pims_rcv_registers_bytes, "\t%llu data register byte%s received\n");
723 	p(pims_rcv_registers_wrongiif, "\t%llu data register message%s received on wrong iif\n");
724 	p(pims_rcv_badregisters, "\t%llu bad register%s received\n");
725 	p(pims_snd_registers_msgs, "\t%llu data register message%s sent\n");
726 	p(pims_snd_registers_bytes, "\t%llu data register byte%s sent\n");
727 #undef p
728 }
729 
730 /*
731  * Dump the ARP statistics structure.
732  */
733 void
734 arp_stats(off, name)
735 	u_long off;
736 	char *name;
737 {
738 	struct arpstat arpstat;
739 
740 	if (off == 0)
741 		return;
742 	kread(off, (char *)&arpstat, sizeof (arpstat));
743 	printf("%s:\n", name);
744 
745 #define	ps(f, m) if (arpstat.f || sflag <= 1) \
746     printf(m, (unsigned long long)arpstat.f)
747 #define	p(f, m) if (arpstat.f || sflag <= 1) \
748     printf(m, (unsigned long long)arpstat.f, plural(arpstat.f))
749 
750 	p(as_sndtotal, "\t%llu packet%s sent\n");
751 	p(as_sndreply, "\t\t%llu reply packet%s\n");
752 	p(as_sndrequest, "\t\t%llu request packet%s\n");
753 
754 	p(as_rcvtotal, "\t%llu packet%s received\n");
755 	p(as_rcvreply, "\t\t%llu reply packet%s\n");
756 	p(as_rcvrequest, "\t\t%llu valid request packet%s\n");
757 	p(as_rcvmcast, "\t\t%llu broadcast/multicast packet%s\n");
758 	p(as_rcvbadproto, "\t\t%llu packet%s with unknown protocol type\n");
759 	p(as_rcvbadlen, "\t\t%llu packet%s with bad (short) length\n");
760 	p(as_rcvzerotpa, "\t\t%llu packet%s with null target IP address\n");
761 	p(as_rcvzerospa, "\t\t%llu packet%s with null source IP address\n");
762 	ps(as_rcvnoint, "\t\t%llu could not be mapped to an interface\n");
763 	p(as_rcvlocalsha, "\t\t%llu packet%s sourced from a local hardware "
764 	    "address\n");
765 	p(as_rcvbcastsha, "\t\t%llu packet%s with a broadcast "
766 	    "source hardware address\n");
767 	p(as_rcvlocalspa, "\t\t%llu duplicate%s for a local IP address\n");
768 	p(as_rcvoverperm, "\t\t%llu attempt%s to overwrite a static entry\n");
769 	p(as_rcvoverint, "\t\t%llu packet%s received on wrong interface\n");
770 	p(as_rcvover, "\t\t%llu entry%s overwritten\n");
771 	p(as_rcvlenchg, "\t\t%llu change%s in hardware address length\n");
772 
773 	p(as_dfrtotal, "\t%llu packet%s deferred pending ARP resolution\n");
774 	ps(as_dfrsent, "\t\t%llu sent\n");
775 	ps(as_dfrdropped, "\t\t%llu dropped\n");
776 
777 	p(as_allocfail, "\t%llu failure%s to allocate llinfo\n");
778 
779 #undef ps
780 #undef p
781 }
782 
783 /*
784  * Pretty print an Internet address (net address + port).
785  * Take numeric_addr and numeric_port into consideration.
786  */
787 void
788 inetprint(in, port, proto, numeric_port)
789 	struct in_addr *in;
790 	u_int16_t port;
791 	const char *proto;
792 	int numeric_port;
793 {
794 	struct servent *sp = 0;
795 	char line[80], *cp;
796 	size_t space;
797 
798 	(void)snprintf(line, sizeof line, "%.*s.",
799 	    (Aflag && !numeric_addr) ? 12 : 16, inetname(in));
800 	cp = strchr(line, '\0');
801 	if (!numeric_port && port)
802 		sp = getservbyport((int)port, proto);
803 	space = sizeof line - (cp-line);
804 	if (sp || port == 0)
805 		(void)snprintf(cp, space, "%s", sp ? sp->s_name : "*");
806 	else
807 		(void)snprintf(cp, space, "%u", ntohs(port));
808 	(void)printf(" %-*.*s", width, width, line);
809 }
810 
811 /*
812  * Construct an Internet address representation.
813  * If numeric_addr has been supplied, give
814  * numeric value, otherwise try for symbolic name.
815  */
816 char *
817 inetname(inp)
818 	struct in_addr *inp;
819 {
820 	char *cp;
821 	static char line[50];
822 	struct hostent *hp;
823 	struct netent *np;
824 	static char domain[MAXHOSTNAMELEN + 1];
825 	static int first = 1;
826 
827 	if (first && !numeric_addr) {
828 		first = 0;
829 		if (gethostname(domain, sizeof domain) == 0) {
830 			domain[sizeof(domain) - 1] = '\0';
831 			if ((cp = strchr(domain, '.')))
832 				(void) strlcpy(domain, cp + 1, sizeof(domain));
833 			else
834 				domain[0] = 0;
835 		} else
836 			domain[0] = 0;
837 	}
838 	cp = 0;
839 	if (!numeric_addr && inp->s_addr != INADDR_ANY) {
840 		int net = inet_netof(*inp);
841 		int lna = inet_lnaof(*inp);
842 
843 		if (lna == INADDR_ANY) {
844 			np = getnetbyaddr(net, AF_INET);
845 			if (np)
846 				cp = np->n_name;
847 		}
848 		if (cp == 0) {
849 			hp = gethostbyaddr((char *)inp, sizeof (*inp), AF_INET);
850 			if (hp) {
851 				if ((cp = strchr(hp->h_name, '.')) &&
852 				    !strcmp(cp + 1, domain))
853 					*cp = 0;
854 				cp = hp->h_name;
855 			}
856 		}
857 	}
858 	if (inp->s_addr == INADDR_ANY)
859 		strlcpy(line, "*", sizeof line);
860 	else if (cp)
861 		strlcpy(line, cp, sizeof line);
862 	else {
863 		inp->s_addr = ntohl(inp->s_addr);
864 #define C(x)	((x) & 0xff)
865 		(void)snprintf(line, sizeof line, "%u.%u.%u.%u",
866 		    C(inp->s_addr >> 24), C(inp->s_addr >> 16),
867 		    C(inp->s_addr >> 8), C(inp->s_addr));
868 #undef C
869 	}
870 	return (line);
871 }
872 
873 /*
874  * Dump the contents of a TCP PCB.
875  */
876 void
877 tcp_dump(pcbaddr)
878 	u_long pcbaddr;
879 {
880 	callout_impl_t *ci;
881 	struct tcpcb tcpcb;
882 	int i, hardticks;
883 
884 	kread(pcbaddr, (char *)&tcpcb, sizeof(tcpcb));
885 	hardticks = get_hardticks();
886 
887 	printf("TCP Protocol Control Block at 0x%08lx:\n\n", pcbaddr);
888 
889 	printf("Timers:\n");
890 	for (i = 0; i < TCPT_NTIMERS; i++) {
891 		ci = (callout_impl_t *)&tcpcb.t_timer[i];
892 		printf("\t%s: %d", tcptimers[i],
893 		    (ci->c_flags & CALLOUT_PENDING) ?
894 		    ci->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