xref: /netbsd/usr.bin/netstat/inet6.c (revision 4218bdda)
1 /*	$NetBSD: inet6.c,v 1.84 2022/10/28 05:27:17 ozaki-r Exp $	*/
2 /*	BSDI inet.c,v 2.3 1995/10/24 02:19:29 prb Exp	*/
3 
4 /*
5  * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the project nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 
33 /*
34  * Copyright (c) 1983, 1988, 1993
35  *	The Regents of the University of California.  All rights reserved.
36  *
37  * Redistribution and use in source and binary forms, with or without
38  * modification, are permitted provided that the following conditions
39  * are met:
40  * 1. Redistributions of source code must retain the above copyright
41  *    notice, this list of conditions and the following disclaimer.
42  * 2. Redistributions in binary form must reproduce the above copyright
43  *    notice, this list of conditions and the following disclaimer in the
44  *    documentation and/or other materials provided with the distribution.
45  * 3. Neither the name of the University nor the names of its contributors
46  *    may be used to endorse or promote products derived from this software
47  *    without specific prior written permission.
48  *
49  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59  * SUCH DAMAGE.
60  */
61 
62 #include <sys/cdefs.h>
63 #ifndef lint
64 #if 0
65 static char sccsid[] = "@(#)inet.c	8.4 (Berkeley) 4/20/94";
66 #else
67 __RCSID("$NetBSD: inet6.c,v 1.84 2022/10/28 05:27:17 ozaki-r Exp $");
68 #endif
69 #endif /* not lint */
70 
71 #define _CALLOUT_PRIVATE
72 
73 #include <sys/param.h>
74 #include <sys/socket.h>
75 #include <sys/socketvar.h>
76 #include <sys/ioctl.h>
77 #include <sys/mbuf.h>
78 #include <sys/protosw.h>
79 #include <sys/sysctl.h>
80 
81 #include <net/route.h>
82 #include <net/if.h>
83 #include <netinet/in.h>
84 #include <netinet/ip6.h>
85 #include <netinet/icmp6.h>
86 #include <netinet/in_systm.h>
87 #ifndef TCP6
88 #include <netinet/ip.h>
89 #include <netinet/ip_var.h>
90 #endif
91 #include <netinet6/ip6_var.h>
92 #include <netinet6/in6_pcb.h>
93 #include <netinet6/in6_var.h>
94 #ifdef TCP6
95 #include <netinet/tcp6.h>
96 #include <netinet/tcp6_seq.h>
97 #define TCP6STATES
98 #include <netinet/tcp6_fsm.h>
99 #define TCP6TIMERS
100 #include <netinet/tcp6_timer.h>
101 #include <netinet/tcp6_var.h>
102 #include <netinet/tcp6_debug.h>
103 #else
104 #define TCP6T_NTIMERS	TCPT_NTIMERS
105 #define tcp6timers tcptimers
106 #define tcp6states tcpstates
107 #define TCP6_NSTATES	TCP_NSTATES
108 #define tcp6cb tcpcb
109 #include <netinet/tcp.h>
110 #include <netinet/tcp_seq.h>
111 #include <netinet/tcp_fsm.h>
112 extern const char * const tcpstates[];
113 extern const char * const tcptimers[];
114 #include <netinet/tcp_timer.h>
115 #include <netinet/tcp_var.h>
116 #include <netinet/tcp_debug.h>
117 #endif /*TCP6*/
118 #include <netinet6/udp6.h>
119 #include <netinet6/udp6_var.h>
120 #include <netinet6/pim6_var.h>
121 #include <netinet6/raw_ip6.h>
122 #include <netinet/tcp_vtw.h>
123 
124 #include <arpa/inet.h>
125 #if 0
126 #include "gethostbyname2.h"
127 #endif
128 #include <netdb.h>
129 
130 #include <err.h>
131 #include <errno.h>
132 #include <kvm.h>
133 #include <stdio.h>
134 #include <stdlib.h>
135 #include <string.h>
136 #include <unistd.h>
137 #include <util.h>
138 #include "netstat.h"
139 #include "vtw.h"
140 #include "prog_ops.h"
141 
142 #ifdef INET6
143 
144 struct	in6pcb in6pcb;
145 #ifdef TCP6
146 struct	tcp6cb tcp6cb;
147 #else
148 struct	tcpcb tcpcb;
149 #endif
150 
151 char	*inet6name(const struct in6_addr *);
152 void	inet6print(const struct in6_addr *, int, const char *);
153 void	print_vtw_v6(const vtw_t *);
154 
155 /*
156  * Print a summary of connections related to an Internet
157  * protocol.  For TCP, also give state of connection.
158  * Listening processes (aflag) are suppressed unless the
159  * -a (all) flag is specified.
160  */
161 static int width;
162 static int compact;
163 
164 /* VTW-related variables. */
165 static struct timeval now;
166 
167 static void
ip6protoprhdr(void)168 ip6protoprhdr(void)
169 {
170 
171 	printf("Active Internet6 connections");
172 
173 	if (aflag)
174 		printf(" (including servers)");
175 	putchar('\n');
176 
177 	if (Aflag) {
178 		printf("%-8.8s ", "PCB");
179 		width = 18;
180 	}
181 	printf(
182 	    Vflag ? "%-5.5s %-6.6s %-6.6s  %*.*s %*.*s %-13.13s Expires\n"
183 		  : "%-5.5s %-6.6s %-6.6s  %*.*s %*.*s %s\n",
184 	    "Proto", "Recv-Q", "Send-Q",
185 	    -width, width, "Local Address",
186 	    -width, width, "Foreign Address", "(state)");
187 }
188 
189 static void
ip6protopr0(intptr_t ppcb,u_long rcv_sb_cc,u_long snd_sb_cc,const struct in6_addr * laddr,uint16_t lport,const struct in6_addr * faddr,uint16_t fport,short t_state,const char * name,const struct timeval * expires)190 ip6protopr0(intptr_t ppcb, u_long rcv_sb_cc, u_long snd_sb_cc,
191 	const struct in6_addr *laddr, uint16_t lport,
192 	const struct in6_addr *faddr, uint16_t fport,
193 	short t_state, const char *name, const struct timeval *expires)
194 {
195 	static const char *shorttcpstates[] = {
196 		"CLOSED",       "LISTEN",       "SYNSEN",       "SYSRCV",
197 		"ESTABL",       "CLWAIT",       "FWAIT1",       "CLOSNG",
198 		"LASTAK",       "FWAIT2",       "TMWAIT"
199 	};
200 	int istcp;
201 
202 	istcp = strcmp(name, "tcp6") == 0;
203 	if (Aflag)
204 		printf("%8" PRIxPTR " ", ppcb);
205 
206 	printf("%-5.5s %6ld %6ld%s", name, rcv_sb_cc, snd_sb_cc,
207 	    compact ? "" : " ");
208 
209 	inet6print(laddr, (int)lport, name);
210 	inet6print(faddr, (int)fport, name);
211 	if (istcp) {
212 #ifdef TCP6
213 		if (t_state < 0 || t_state >= TCP6_NSTATES)
214 			printf(" %d", t_state);
215 		else
216 			printf(" %s", tcp6states[t_state]);
217 #else
218 		if (t_state < 0 || t_state >= TCP_NSTATES)
219 			printf(" %d", t_state);
220 		else
221 			printf(" %s", compact ? shorttcpstates[t_state] :
222 			    tcpstates[t_state]);
223 #endif
224 	}
225 	if (Vflag && expires != NULL) {
226 		if (expires->tv_sec == 0 && expires->tv_usec == -1)
227 			printf(" reclaimed");
228 		else {
229 			struct timeval delta;
230 
231 			timersub(expires, &now, &delta);
232 			printf(" %.3fms",
233 			    delta.tv_sec * 1000.0 + delta.tv_usec / 1000.0);
234 		}
235 	}
236 	putchar('\n');
237 }
238 
239 static void
dbg_printf(const char * fmt,...)240 dbg_printf(const char *fmt, ...)
241 {
242 
243 	return;
244 }
245 
246 void
print_vtw_v6(const vtw_t * vtw)247 print_vtw_v6(const vtw_t *vtw)
248 {
249 	const vtw_v6_t *v6 = (const vtw_v6_t *)vtw;
250 	struct timeval delta;
251 	char buf[2][128];
252 	static const struct timeval zero = {.tv_sec = 0, .tv_usec = 0};
253 
254 	inet_ntop(AF_INET6, &v6->laddr, buf[0], sizeof(buf[0]));
255 	inet_ntop(AF_INET6, &v6->faddr, buf[1], sizeof(buf[1]));
256 
257 	timersub(&vtw->expire, &now, &delta);
258 
259 	if (vtw->expire.tv_sec == 0 && vtw->expire.tv_usec == -1) {
260 		dbg_printf("%15.15s:%d %15.15s:%d reclaimed\n",
261 		    buf[0], ntohs(v6->lport),
262 		    buf[1], ntohs(v6->fport));
263 		if (!(Vflag && vflag))
264 			return;
265 	} else if (vtw->expire.tv_sec == 0)
266 		return;
267 	else if (timercmp(&delta, &zero, <) && !(Vflag && vflag)) {
268 		dbg_printf("%15.15s:%d %15.15s:%d expired\n",
269 		    buf[0], ntohs(v6->lport),
270 		    buf[1], ntohs(v6->fport));
271 		return;
272 	} else {
273 		dbg_printf("%15.15s:%d %15.15s:%d expires in %.3fms\n",
274 		    buf[0], ntohs(v6->lport),
275 		    buf[1], ntohs(v6->fport),
276 		    delta.tv_sec * 1000.0 + delta.tv_usec / 1000.0);
277 	}
278 	ip6protopr0(0, 0, 0,
279 		 &v6->laddr, v6->lport,
280 		 &v6->faddr, v6->fport,
281 		 TCPS_TIME_WAIT, "tcp6", &vtw->expire);
282 }
283 
284 
285 static struct kinfo_pcb *
getpcblist_kmem(u_long off,const char * name,size_t * len)286 getpcblist_kmem(u_long off, const char *name, size_t *len)
287 {
288 	struct socket sockb;
289 	struct inpcbtable table;
290 	struct inpcb *next, *prev;
291 	struct inpcb *inp;
292 	int istcp = strcmp(name, "tcp6") == 0;
293 	struct kinfo_pcb *pcblist;
294 	size_t size = 100, i;
295 	struct sockaddr_in6 sin6;
296 	struct inpcbqueue *head;
297 
298 	if (off == 0) {
299 		*len = 0;
300 		return NULL;
301 	}
302 	kread(off, (char *)&table, sizeof (table));
303 	head = &table.inpt_queue;
304 	next = TAILQ_FIRST(head);
305 	prev = TAILQ_END(head);
306 
307 	pcblist = NULL;
308 	if (reallocarr(&pcblist, size, sizeof(*pcblist)) != 0)
309 		err(1, "reallocarr");
310 
311 	i = 0;
312 	while (next != TAILQ_END(head)) {
313 		kread((u_long)next, (char *)&in6pcb, sizeof in6pcb);
314 		inp = (struct inpcb *)&in6pcb;
315 		next = TAILQ_NEXT(inp, inp_queue);
316 		prev = next;
317 
318 		if (inp->inp_af != AF_INET6)
319 			continue;
320 
321 		kread((u_long)inp->inp_socket, (char *)&sockb,
322 		    sizeof (sockb));
323 		if (istcp) {
324 #ifdef TCP6
325 			kread((u_long)inp->inp_ppcb,
326 			    (char *)&tcp6cb, sizeof (tcp6cb));
327 #else
328 			kread((u_long)inp->inp_ppcb,
329 			    (char *)&tcpcb, sizeof (tcpcb));
330 #endif
331 		}
332 		pcblist[i].ki_ppcbaddr =
333 		    istcp ? (uintptr_t) inp->inp_ppcb : (uintptr_t) prev;
334 		pcblist[i].ki_rcvq = (uint64_t)sockb.so_rcv.sb_cc;
335 		pcblist[i].ki_sndq = (uint64_t)sockb.so_snd.sb_cc;
336 		sin6.sin6_addr = in6p_laddr(inp);
337 		sin6.sin6_port = inp->inp_lport;
338 		memcpy(&pcblist[i].ki_s, &sin6, sizeof(sin6));
339 		sin6.sin6_addr = in6p_faddr(inp);
340 		sin6.sin6_port = inp->inp_fport;
341 		memcpy(&pcblist[i].ki_d, &sin6, sizeof(sin6));
342 		pcblist[i].ki_tstate = tcpcb.t_state;
343 		if (i++ == size) {
344 			size += 100;
345 			if (reallocarr(&pcblist, size, sizeof(*pcblist)) != 0)
346 				err(1, "reallocarr");
347 		}
348 	}
349 	*len = i;
350 	return pcblist;
351 }
352 
353 void
ip6protopr(u_long off,const char * name)354 ip6protopr(u_long off, const char *name)
355 {
356 	struct kinfo_pcb *pcblist;
357 	size_t i, len;
358 	static int first = 1;
359 
360 	compact = 0;
361 	if (Aflag) {
362 		if (!numeric_addr)
363 			width = 18;
364 		else {
365 			width = 21;
366 			compact = 1;
367 		}
368 	} else
369 		width = 22;
370 
371 	if (use_sysctl)
372 		pcblist = getpcblist_sysctl(name, &len);
373 	else
374 		pcblist = getpcblist_kmem(off, name, &len);
375 
376 	for (i = 0; i < len; i++) {
377 		struct sockaddr_in6 src, dst;
378 
379 		memcpy(&src, &pcblist[i].ki_s, sizeof(src));
380 		memcpy(&dst, &pcblist[i].ki_d, sizeof(dst));
381 
382 		if (!aflag && IN6_IS_ADDR_UNSPECIFIED(&dst.sin6_addr))
383 			continue;
384 
385 		if (first) {
386 			ip6protoprhdr();
387 			first = 0;
388 		}
389 
390 		ip6protopr0((intptr_t) pcblist[i].ki_ppcbaddr,
391 		    pcblist[i].ki_rcvq, pcblist[i].ki_sndq,
392 		    &src.sin6_addr, src.sin6_port,
393 		    &dst.sin6_addr, dst.sin6_port,
394 		    pcblist[i].ki_tstate, name, NULL);
395 	}
396 
397 	free(pcblist);
398 
399 	if (strcmp(name, "tcp6") == 0) {
400 		struct timeval t;
401 		timebase(&t);
402 		gettimeofday(&now, NULL);
403 		timersub(&now, &t, &now);
404 		show_vtw_v6(print_vtw_v6);
405 	}
406 }
407 
408 #ifdef TCP6
409 /*
410  * Dump TCP6 statistics structure.
411  */
412 void
tcp6_stats(u_long off,const char * name)413 tcp6_stats(u_long off, const char *name)
414 {
415 	struct tcp6stat tcp6stat;
416 
417 	if (use_sysctl) {
418 		size_t size = sizeof(tcp6stat);
419 
420 		if (prog_sysctlbyname("net.inet6.tcp6.stats", &tcp6stat, &size,
421 		    NULL, 0) == -1 && errno != ENOMEM)
422 			return;
423 	} else {
424 		warnx("%s stats not available via KVM.", name);
425 		return;
426 	}
427 
428 	printf ("%s:\n", name);
429 
430 #define	p(f, m) if (tcp6stat.f || sflag <= 1)			\
431 		printf(m, tcp6stat.f, plural(tcp6stat.f))
432 #define	p2(f1, f2, m) if (tcp6stat.f1 || tcp6stat.f2 || sflag <= 1)	 \
433 		printf(m, tcp6stat.f1, plural(tcp6stat.f1), tcp6stat.f2, \
434 		    plural(tcp6stat.f2))
435 #define	p3(f, m) if (tcp6stat.f || sflag <= 1)			\
436 		printf(m, tcp6stat.f, plurales(tcp6stat.f))
437 
438 	p(tcp6s_sndtotal, "\t%ld packet%s sent\n");
439 	p2(tcp6s_sndpack,tcp6s_sndbyte,
440 	    "\t\t%ld data packet%s (%ld byte%s)\n");
441 	p2(tcp6s_sndrexmitpack, tcp6s_sndrexmitbyte,
442 	    "\t\t%ld data packet%s (%ld byte%s) retransmitted\n");
443 	p2(tcp6s_sndacks, tcp6s_delack,
444 	    "\t\t%ld ack-only packet%s (%ld packet%s delayed)\n");
445 	p(tcp6s_sndurg, "\t\t%ld URG only packet%s\n");
446 	p(tcp6s_sndprobe, "\t\t%ld window probe packet%s\n");
447 	p(tcp6s_sndwinup, "\t\t%ld window update packet%s\n");
448 	p(tcp6s_sndctrl, "\t\t%ld control packet%s\n");
449 	p(tcp6s_rcvtotal, "\t%ld packet%s received\n");
450 	p2(tcp6s_rcvackpack, tcp6s_rcvackbyte,
451 	    "\t\t%ld ack%s (for %ld byte%s)\n");
452 	p(tcp6s_rcvdupack, "\t\t%ld duplicate ack%s\n");
453 	p(tcp6s_rcvacktoomuch, "\t\t%ld ack%s for unsent data\n");
454 	p2(tcp6s_rcvpack, tcp6s_rcvbyte,
455 	    "\t\t%ld packet%s (%ld byte%s) received in-sequence\n");
456 	p2(tcp6s_rcvduppack, tcp6s_rcvdupbyte,
457 	    "\t\t%ld completely duplicate packet%s (%ld byte%s)\n");
458 	p(tcp6s_pawsdrop, "\t\t%ld old duplicate packet%s\n");
459 	p2(tcp6s_rcvpartduppack, tcp6s_rcvpartdupbyte,
460 	    "\t\t%ld packet%s with some dup. data (%ld byte%s duped)\n");
461 	p2(tcp6s_rcvoopack, tcp6s_rcvoobyte,
462 	    "\t\t%ld out-of-order packet%s (%ld byte%s)\n");
463 	p2(tcp6s_rcvpackafterwin, tcp6s_rcvbyteafterwin,
464 	    "\t\t%ld packet%s (%ld byte%s) of data after window\n");
465 	p(tcp6s_rcvwinprobe, "\t\t%ld window probe%s\n");
466 	p(tcp6s_rcvwinupd, "\t\t%ld window update packet%s\n");
467 	p(tcp6s_rcvafterclose, "\t\t%ld packet%s received after close\n");
468 	p(tcp6s_rcvbadsum, "\t\t%ld discarded for bad checksum%s\n");
469 	p(tcp6s_rcvbadoff,
470 	    "\t\t%ld discarded for bad header offset field%s\n");
471 	p(tcp6s_rcvshort, "\t\t%ld discarded because packet%s too short\n");
472 	p(tcp6s_connattempt, "\t%ld connection request%s\n");
473 	p(tcp6s_accepts, "\t%ld connection accept%s\n");
474 	p(tcp6s_badsyn, "\t%ld bad connection attempt%s\n");
475 	p(tcp6s_connects,
476 	    "\t%ld connection%s established (including accepts)\n");
477 	p2(tcp6s_closed, tcp6s_drops,
478 	    "\t%ld connection%s closed (including %ld drop%s)\n");
479 	p(tcp6s_conndrops, "\t%ld embryonic connection%s dropped\n");
480 	p2(tcp6s_rttupdated, tcp6s_segstimed,
481 	    "\t%ld segment%s updated rtt (of %ld attempt%s)\n");
482 	p(tcp6s_rexmttimeo, "\t%ld retransmit timeout%s\n");
483 	p(tcp6s_timeoutdrop,
484 	    "\t\t%ld connection%s dropped by rexmit timeout\n");
485 	p(tcp6s_persisttimeo, "\t%ld persist timeout%s\n");
486 	p(tcp6s_persistdrop, "\t%ld connection%s timed out in persist\n");
487 	p(tcp6s_keeptimeo, "\t%ld keepalive timeout%s\n");
488 	p(tcp6s_keepprobe, "\t\t%ld keepalive probe%s sent\n");
489 	p(tcp6s_keepdrops, "\t\t%ld connection%s dropped by keepalive\n");
490 	p(tcp6s_predack, "\t%ld correct ACK header prediction%s\n");
491 	p(tcp6s_preddat, "\t%ld correct data packet header prediction%s\n");
492 	p3(tcp6s_pcbcachemiss, "\t%ld PCB cache miss%s\n");
493 #undef p
494 #undef p2
495 #undef p3
496 }
497 #endif
498 
499 /*
500  * Dump UDP6 statistics structure.
501  */
502 void
udp6_stats(u_long off,const char * name)503 udp6_stats(u_long off, const char *name)
504 {
505 	uint64_t udp6stat[UDP6_NSTATS];
506 	uint64_t delivered;
507 
508 	if (use_sysctl) {
509 		size_t size = sizeof(udp6stat);
510 
511 		if (prog_sysctlbyname("net.inet6.udp6.stats", udp6stat, &size,
512 		    NULL, 0) == -1 && errno != ENOMEM)
513 			return;
514 	} else {
515 		warnx("%s stats not available via KVM.", name);
516 		return;
517 	}
518 	printf("%s:\n", name);
519 #define	p(f, m) if (udp6stat[f] || sflag <= 1)				      \
520 		printf(m, (unsigned long long)udp6stat[f], plural(udp6stat[f]))
521 #define	p1(f, m) if (udp6stat[f] || sflag <= 1)			\
522 		printf(m, (unsigned long long)udp6stat[f])
523 	p(UDP6_STAT_IPACKETS, "\t%llu datagram%s received\n");
524 	p1(UDP6_STAT_HDROPS, "\t%llu with incomplete header\n");
525 	p1(UDP6_STAT_BADLEN, "\t%llu with bad data length field\n");
526 	p1(UDP6_STAT_BADSUM, "\t%llu with bad checksum\n");
527 	p1(UDP6_STAT_NOSUM, "\t%llu with no checksum\n");
528 	p1(UDP6_STAT_NOPORT, "\t%llu dropped due to no socket\n");
529 	p(UDP6_STAT_NOPORTMCAST,
530 	    "\t%llu multicast datagram%s dropped due to no socket\n");
531 	p1(UDP6_STAT_FULLSOCK, "\t%llu dropped due to full socket buffers\n");
532 	delivered = udp6stat[UDP6_STAT_IPACKETS] -
533 		    udp6stat[UDP6_STAT_HDROPS] -
534 		    udp6stat[UDP6_STAT_BADLEN] -
535 		    udp6stat[UDP6_STAT_BADSUM] -
536 		    udp6stat[UDP6_STAT_NOPORT] -
537 		    udp6stat[UDP6_STAT_NOPORTMCAST] -
538 		    udp6stat[UDP6_STAT_FULLSOCK];
539 	if (delivered || sflag <= 1)
540 		printf("\t%llu delivered\n", (unsigned long long)delivered);
541 	p(UDP6_STAT_OPACKETS, "\t%llu datagram%s output\n");
542 #undef p
543 #undef p1
544 }
545 
546 static	const char *ip6nh[] = {
547 /*0*/	"hop by hop",
548 	"ICMP",
549 	"IGMP",
550 	NULL,
551 	"IP",
552 /*5*/	NULL,
553 	"TCP",
554 	NULL,
555 	NULL,
556 	NULL,
557 /*10*/	NULL, NULL, NULL, NULL, NULL,
558 /*15*/	NULL,
559 	NULL,
560 	"UDP",
561 	NULL,
562 	NULL,
563 /*20*/	NULL,
564 	NULL,
565 	"IDP",
566 	NULL,
567 	NULL,
568 /*25*/	NULL,
569 	NULL,
570 	NULL,
571 	NULL,
572 	NULL,
573 /*30*/	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
574 /*40*/	NULL,
575 	"IP6",
576 	NULL,
577 	"routing",
578 	"fragment",
579 /*45*/	NULL, NULL, NULL, NULL, NULL,
580 /*50*/	"ESP",
581 	"AH",
582 	NULL,
583 	NULL,
584 	NULL,
585 /*55*/	NULL,
586 	NULL,
587 	NULL,
588 	"ICMP6",
589 	"no next header",
590 /*60*/	"destination option",
591 	NULL,
592 	NULL,
593 	NULL,
594 	NULL,
595 /*65*/	NULL, NULL, NULL, NULL, NULL,
596 /*70*/	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
597 /*80*/	NULL,
598 	NULL,
599 	NULL,
600 	NULL,
601 	NULL,
602 	NULL,
603 	NULL,
604 	NULL,
605 	NULL,
606 	"OSPF",
607 /*90*/	NULL, NULL, NULL, NULL, NULL,
608 /*95*/	NULL,
609 	NULL,
610 	"Ethernet",
611 	NULL,
612 	NULL,
613 /*100*/	NULL,
614 	NULL,
615 	NULL,
616 	"PIM",
617 	NULL,
618 /*105*/	NULL, NULL, NULL, NULL, NULL,
619 /*110*/	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
620 /*120*/	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
621 /*130*/	NULL,
622 	NULL,
623 	"SCTP",
624 	NULL,
625 	NULL,
626 /*135*/	NULL, NULL, NULL, NULL, NULL,
627 /*140*/	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
628 	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
629 /*160*/	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
630 	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
631 /*180*/	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
632 	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
633 /*200*/	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
634 	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
635 /*220*/	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
636 	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
637 /*240*/	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
638 	NULL, NULL, NULL, NULL, NULL, NULL
639 };
640 
641 /*
642  * Dump IP6 statistics structure.
643  */
644 void
ip6_stats(u_long off,const char * name)645 ip6_stats(u_long off, const char *name)
646 {
647 	uint64_t ip6stat[IP6_NSTATS];
648 	int first, i;
649 	struct protoent *ep;
650 	const char *n;
651 
652 	if (use_sysctl) {
653 		size_t size = sizeof(ip6stat);
654 
655 		if (prog_sysctlbyname("net.inet6.ip6.stats", ip6stat, &size,
656 		    NULL, 0) == -1 && errno != ENOMEM)
657 			return;
658 	} else {
659 		warnx("%s stats not available via KVM.", name);
660 		return;
661 	}
662 	printf("%s:\n", name);
663 
664 #define	p(f, m) if (ip6stat[f] || sflag <= 1)				     \
665 		printf(m, (unsigned long long)ip6stat[f], plural(ip6stat[f]))
666 #define	p1(f, m) if (ip6stat[f] || sflag <= 1)			\
667 		printf(m, (unsigned long long)ip6stat[f])
668 
669 	p(IP6_STAT_TOTAL, "\t%llu total packet%s received\n");
670 	p1(IP6_STAT_TOOSMALL, "\t%llu with size smaller than minimum\n");
671 	p1(IP6_STAT_TOOSHORT, "\t%llu with data size < data length\n");
672 	p1(IP6_STAT_BADOPTIONS, "\t%llu with bad options\n");
673 	p1(IP6_STAT_BADVERS, "\t%llu with incorrect version number\n");
674 	p(IP6_STAT_FRAGMENTS, "\t%llu fragment%s received\n");
675 	p(IP6_STAT_FRAGDROPPED,
676 	    "\t%llu fragment%s dropped (dup or out of space)\n");
677 	p(IP6_STAT_FRAGTIMEOUT, "\t%llu fragment%s dropped after timeout\n");
678 	p(IP6_STAT_FRAGOVERFLOW, "\t%llu fragment%s that exceeded limit\n");
679 	p(IP6_STAT_REASSEMBLED, "\t%llu packet%s reassembled ok\n");
680 	p(IP6_STAT_DELIVERED, "\t%llu packet%s for this host\n");
681 	p(IP6_STAT_FORWARD, "\t%llu packet%s forwarded\n");
682 	p(IP6_STAT_FASTFORWARD, "\t%llu packet%s fast forwarded\n");
683 	p1(IP6_STAT_FASTFORWARDFLOWS, "\t%llu fast forward flows\n");
684 	p(IP6_STAT_CANTFORWARD, "\t%llu packet%s not forwardable\n");
685 	p(IP6_STAT_REDIRECTSENT, "\t%llu redirect%s sent\n");
686 	p(IP6_STAT_LOCALOUT, "\t%llu packet%s sent from this host\n");
687 	p(IP6_STAT_RAWOUT, "\t%llu packet%s sent with fabricated ip header\n");
688 	p(IP6_STAT_ODROPPED,
689 	    "\t%llu output packet%s dropped due to no bufs, etc.\n");
690 	p(IP6_STAT_NOROUTE,
691 	    "\t%llu output packet%s discarded due to no route\n");
692 	p(IP6_STAT_FRAGMENTED, "\t%llu output datagram%s fragmented\n");
693 	p(IP6_STAT_OFRAGMENTS, "\t%llu fragment%s created\n");
694 	p(IP6_STAT_CANTFRAG, "\t%llu datagram%s that can't be fragmented\n");
695 	p(IP6_STAT_BADSCOPE, "\t%llu packet%s that violated scope rules\n");
696 	p(IP6_STAT_NOTMEMBER, "\t%llu multicast packet%s which we don't join\n");
697 	for (first = 1, i = 0; i < 256; i++)
698 		if (ip6stat[IP6_STAT_NXTHIST + i] != 0) {
699 			if (first) {
700 				printf("\tInput packet histogram:\n");
701 				first = 0;
702 			}
703 			n = NULL;
704 			if (ip6nh[i])
705 				n = ip6nh[i];
706 			else if ((ep = getprotobynumber(i)) != NULL)
707 				n = ep->p_name;
708 			if (n)
709 				printf("\t\t%s: %llu\n", n,
710 				    (unsigned long long)ip6stat[IP6_STAT_NXTHIST + i]);
711 			else
712 				printf("\t\t#%d: %llu\n", i,
713 				    (unsigned long long)ip6stat[IP6_STAT_NXTHIST + i]);
714 		}
715 	printf("\tMbuf statistics:\n");
716 	p(IP6_STAT_M1, "\t\t%llu one mbuf%s\n");
717 	for (first = 1, i = 0; i < 32; i++) {
718 		char ifbuf[IFNAMSIZ];
719 		if (ip6stat[IP6_STAT_M2M + i] != 0) {
720 			if (first) {
721 				printf("\t\ttwo or more mbuf:\n");
722 				first = 0;
723 			}
724 			printf("\t\t\t%s = %llu\n",
725 			    if_indextoname(i, ifbuf),
726 			    (unsigned long long)ip6stat[IP6_STAT_M2M + i]);
727 		}
728 	}
729 	p(IP6_STAT_MEXT1, "\t\t%llu one ext mbuf%s\n");
730 	p(IP6_STAT_MEXT2M, "\t\t%llu two or more ext mbuf%s\n");
731 	p(IP6_STAT_EXTHDRTOOLONG,
732 	    "\t%llu packet%s whose headers are not continuous\n");
733 	p(IP6_STAT_NOGIF, "\t%llu tunneling packet%s that can't find gif\n");
734 	p(IP6_STAT_NOIPSEC,
735 	    "\t%llu tunneling packet%s that can't find ipsecif\n");
736 	p(IP6_STAT_TOOMANYHDR,
737 	    "\t%llu packet%s discarded due to too many headers\n");
738 
739 	/* for debugging source address selection */
740 #define PRINT_SCOPESTAT(s, i) do {				\
741 		switch (i) { /* XXX hardcoding in each case */	\
742 		case 1:						\
743 			p(s, "\t\t%llu node-local%s\n");	\
744 			break;					\
745 		case 2:						\
746 			p(s, "\t\t%llu link-local%s\n");	\
747 			break;					\
748 		case 5:						\
749 			p(s, "\t\t%llu site-local%s\n");	\
750 			break;					\
751 		case 14:					\
752 			p(s, "\t\t%llu global%s\n");		\
753 			break;					\
754 		default:					\
755 			printf("\t\t%llu addresses scope=%x\n",	\
756 			    (unsigned long long)ip6stat[s], i);	\
757 		}						\
758 	} while(0);
759 
760 	p(IP6_STAT_SOURCES_NONE,
761 	  "\t%llu failure%s of source address selection\n");
762 	for (first = 1, i = 0; i < 16; i++) {
763 		if (ip6stat[IP6_STAT_SOURCES_SAMEIF + i]) {
764 			if (first) {
765 				printf("\tsource addresses on an outgoing I/F\n");
766 				first = 0;
767 			}
768 			PRINT_SCOPESTAT(IP6_STAT_SOURCES_SAMEIF + i, i);
769 		}
770 	}
771 	for (first = 1, i = 0; i < 16; i++) {
772 		if (ip6stat[IP6_STAT_SOURCES_OTHERIF + i]) {
773 			if (first) {
774 				printf("\tsource addresses on a non-outgoing I/F\n");
775 				first = 0;
776 			}
777 			PRINT_SCOPESTAT(IP6_STAT_SOURCES_OTHERIF + i, i);
778 		}
779 	}
780 	for (first = 1, i = 0; i < 16; i++) {
781 		if (ip6stat[IP6_STAT_SOURCES_SAMESCOPE + i]) {
782 			if (first) {
783 				printf("\tsource addresses of same scope\n");
784 				first = 0;
785 			}
786 			PRINT_SCOPESTAT(IP6_STAT_SOURCES_SAMESCOPE + i, i);
787 		}
788 	}
789 	for (first = 1, i = 0; i < 16; i++) {
790 		if (ip6stat[IP6_STAT_SOURCES_OTHERSCOPE + i]) {
791 			if (first) {
792 				printf("\tsource addresses of a different scope\n");
793 				first = 0;
794 			}
795 			PRINT_SCOPESTAT(IP6_STAT_SOURCES_OTHERSCOPE + i, i);
796 		}
797 	}
798 	for (first = 1, i = 0; i < 16; i++) {
799 		if (ip6stat[IP6_STAT_SOURCES_DEPRECATED + i]) {
800 			if (first) {
801 				printf("\tdeprecated source addresses\n");
802 				first = 0;
803 			}
804 			PRINT_SCOPESTAT(IP6_STAT_SOURCES_DEPRECATED + i, i);
805 		}
806 	}
807 
808 	p1(IP6_STAT_FORWARD_CACHEHIT, "\t%llu forward cache hit\n");
809 	p1(IP6_STAT_FORWARD_CACHEMISS, "\t%llu forward cache miss\n");
810 	p(IP6_STAT_PFILDROP_IN, "\t%llu input packet%s dropped by pfil\n");
811 	p(IP6_STAT_PFILDROP_OUT, "\t%llu output packet%s dropped by pfil\n");
812 	p(IP6_STAT_IPSECDROP_IN, "\t%llu input packet%s dropped by IPsec\n");
813 	p(IP6_STAT_IPSECDROP_OUT, "\t%llu output packet%s dropped by IPsec\n");
814 	p(IP6_STAT_IFDROP,
815 	    "\t%llu input packet%s dropped due to interface state\n");
816 	p(IP6_STAT_IDROPPED,
817 	    "\t%llu input packet%s dropped due to no bufs, etc.\n");
818 	p(IP6_STAT_TIMXCEED,
819 	    "\t%llu packet%s dropped due to hop limit exceeded\n");
820 	p(IP6_STAT_TOOBIG, "\t%llu packet%s dropped (too big)\n");
821 	p(IP6_STAT_RTREJECT,
822 	    "\t%llu output packet%s discarded due to reject route\n");
823 #undef p
824 #undef p1
825 }
826 
827 /*
828  * Dump IPv6 per-interface statistics based on RFC 2465.
829  */
830 void
ip6_ifstats(const char * ifname)831 ip6_ifstats(const char *ifname)
832 {
833 	struct in6_ifreq ifr;
834 	int s;
835 #define	p(f, m) if (ifr.ifr_ifru.ifru_stat.f || sflag <= 1)		\
836 		printf(m, (unsigned long long)ifr.ifr_ifru.ifru_stat.f, \
837 		    plural(ifr.ifr_ifru.ifru_stat.f))
838 #define	p_5(f, m) if (ifr.ifr_ifru.ifru_stat.f || sflag <= 1)	\
839 		printf(m, (unsigned long long)ip6stat.f)
840 
841 	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
842 		perror("Warning: socket(AF_INET6)");
843 		return;
844 	}
845 
846 	strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
847 	printf("ip6 on %s:\n", ifname);
848 
849 	if (ioctl(s, SIOCGIFSTAT_IN6, (char *)&ifr) < 0) {
850 		perror("Warning: ioctl(SIOCGIFSTAT_IN6)");
851 		goto end;
852 	}
853 
854 	p(ifs6_in_receive, "\t%llu total input datagram%s\n");
855 	p(ifs6_in_hdrerr, "\t%llu datagram%s with invalid header received\n");
856 	p(ifs6_in_toobig, "\t%llu datagram%s exceeded MTU received\n");
857 	p(ifs6_in_noroute, "\t%llu datagram%s with no route received\n");
858 	p(ifs6_in_addrerr, "\t%llu datagram%s with invalid dst received\n");
859 	p(ifs6_in_truncated, "\t%llu truncated datagram%s received\n");
860 	p(ifs6_in_protounknown,
861 	    "\t%llu datagram%s with unknown proto received\n");
862 	p(ifs6_in_discard, "\t%llu input datagram%s discarded\n");
863 	p(ifs6_in_deliver,
864 	    "\t%llu datagram%s delivered to an upper layer protocol\n");
865 	p(ifs6_out_forward, "\t%llu datagram%s forwarded to this interface\n");
866 	p(ifs6_out_request,
867 	    "\t%llu datagram%s sent from an upper layer protocol\n");
868 	p(ifs6_out_discard, "\t%llu total discarded output datagram%s\n");
869 	p(ifs6_out_fragok, "\t%llu output datagram%s fragmented\n");
870 	p(ifs6_out_fragfail, "\t%llu output datagram%s failed on fragment\n");
871 	p(ifs6_out_fragcreat,
872 	    "\t%llu output datagram%s succeeded on fragment\n");
873 	p(ifs6_reass_reqd, "\t%llu incoming datagram%s fragmented\n");
874 	p(ifs6_reass_ok, "\t%llu datagram%s reassembled\n");
875 	p(ifs6_reass_fail, "\t%llu datagram%s failed on reassembling\n");
876 	p(ifs6_in_mcast, "\t%llu multicast datagram%s received\n");
877 	p(ifs6_out_mcast, "\t%llu multicast datagram%s sent\n");
878 
879   end:
880 	close(s);
881 
882 #undef p
883 #undef p_5
884 }
885 
886 static	const char *icmp6names[256] = {
887 	"#0",
888 	"unreach",
889 	"packet too big",
890 	"time exceed",
891 	"parameter problem",
892 	"#5",
893 	"#6",
894 	"#7",
895 	"#8",
896 	"#9",
897 	"#10",
898 	"#11",
899 	"#12",
900 	"#13",
901 	"#14",
902 	"#15",
903 	"#16",
904 	"#17",
905 	"#18",
906 	"#19",
907 	"#20",
908 	"#21",
909 	"#22",
910 	"#23",
911 	"#24",
912 	"#25",
913 	"#26",
914 	"#27",
915 	"#28",
916 	"#29",
917 	"#30",
918 	"#31",
919 	"#32",
920 	"#33",
921 	"#34",
922 	"#35",
923 	"#36",
924 	"#37",
925 	"#38",
926 	"#39",
927 	"#40",
928 	"#41",
929 	"#42",
930 	"#43",
931 	"#44",
932 	"#45",
933 	"#46",
934 	"#47",
935 	"#48",
936 	"#49",
937 	"#50",
938 	"#51",
939 	"#52",
940 	"#53",
941 	"#54",
942 	"#55",
943 	"#56",
944 	"#57",
945 	"#58",
946 	"#59",
947 	"#60",
948 	"#61",
949 	"#62",
950 	"#63",
951 	"#64",
952 	"#65",
953 	"#66",
954 	"#67",
955 	"#68",
956 	"#69",
957 	"#70",
958 	"#71",
959 	"#72",
960 	"#73",
961 	"#74",
962 	"#75",
963 	"#76",
964 	"#77",
965 	"#78",
966 	"#79",
967 	"#80",
968 	"#81",
969 	"#82",
970 	"#83",
971 	"#84",
972 	"#85",
973 	"#86",
974 	"#87",
975 	"#88",
976 	"#89",
977 	"#80",
978 	"#91",
979 	"#92",
980 	"#93",
981 	"#94",
982 	"#95",
983 	"#96",
984 	"#97",
985 	"#98",
986 	"#99",
987 	"#100",
988 	"#101",
989 	"#102",
990 	"#103",
991 	"#104",
992 	"#105",
993 	"#106",
994 	"#107",
995 	"#108",
996 	"#109",
997 	"#110",
998 	"#111",
999 	"#112",
1000 	"#113",
1001 	"#114",
1002 	"#115",
1003 	"#116",
1004 	"#117",
1005 	"#118",
1006 	"#119",
1007 	"#120",
1008 	"#121",
1009 	"#122",
1010 	"#123",
1011 	"#124",
1012 	"#125",
1013 	"#126",
1014 	"#127",
1015 	"echo",
1016 	"echo reply",
1017 	"multicast listener query",
1018 	"multicast listener report",
1019 	"multicast listener done",
1020 	"router solicitation",
1021 	"router advertisement",
1022 	"neighbor solicitation",
1023 	"neighbor advertisement",
1024 	"redirect",
1025 	"router renumbering",
1026 	"node information request",
1027 	"node information reply",
1028 	"#141",
1029 	"#142",
1030 	"multicast listener report (v2)",
1031 	"home agent discovery request",
1032 	"home agent discovery reply",
1033 	"mobile prefix solicitation",
1034 	"mobile prefix advertisement",
1035 	"#148",
1036 	"#149",
1037 	"#150",
1038 	"multicast router advertisement",
1039 	"multicast router solicitation",
1040 	"multicast router termination",
1041 	"#154",
1042 	"#155",
1043 	"#156",
1044 	"#157",
1045 	"#158",
1046 	"#159",
1047 	"#160",
1048 	"#161",
1049 	"#162",
1050 	"#163",
1051 	"#164",
1052 	"#165",
1053 	"#166",
1054 	"#167",
1055 	"#168",
1056 	"#169",
1057 	"#170",
1058 	"#171",
1059 	"#172",
1060 	"#173",
1061 	"#174",
1062 	"#175",
1063 	"#176",
1064 	"#177",
1065 	"#178",
1066 	"#179",
1067 	"#180",
1068 	"#181",
1069 	"#182",
1070 	"#183",
1071 	"#184",
1072 	"#185",
1073 	"#186",
1074 	"#187",
1075 	"#188",
1076 	"#189",
1077 	"#180",
1078 	"#191",
1079 	"#192",
1080 	"#193",
1081 	"#194",
1082 	"#195",
1083 	"#196",
1084 	"#197",
1085 	"#198",
1086 	"#199",
1087 	"#200",
1088 	"#201",
1089 	"#202",
1090 	"#203",
1091 	"#204",
1092 	"#205",
1093 	"#206",
1094 	"#207",
1095 	"#208",
1096 	"#209",
1097 	"#210",
1098 	"#211",
1099 	"#212",
1100 	"#213",
1101 	"#214",
1102 	"#215",
1103 	"#216",
1104 	"#217",
1105 	"#218",
1106 	"#219",
1107 	"#220",
1108 	"#221",
1109 	"#222",
1110 	"#223",
1111 	"#224",
1112 	"#225",
1113 	"#226",
1114 	"#227",
1115 	"#228",
1116 	"#229",
1117 	"#230",
1118 	"#231",
1119 	"#232",
1120 	"#233",
1121 	"#234",
1122 	"#235",
1123 	"#236",
1124 	"#237",
1125 	"#238",
1126 	"#239",
1127 	"#240",
1128 	"#241",
1129 	"#242",
1130 	"#243",
1131 	"#244",
1132 	"#245",
1133 	"#246",
1134 	"#247",
1135 	"#248",
1136 	"#249",
1137 	"#250",
1138 	"#251",
1139 	"#252",
1140 	"#253",
1141 	"#254",
1142 	"#255"
1143 };
1144 
1145 /*
1146  * Dump ICMPv6 statistics.
1147  */
1148 void
icmp6_stats(u_long off,const char * name)1149 icmp6_stats(u_long off, const char *name)
1150 {
1151 	uint64_t icmp6stat[ICMP6_NSTATS];
1152 	int i, first;
1153 
1154 	if (use_sysctl) {
1155 		size_t size = sizeof(icmp6stat);
1156 
1157 		if (prog_sysctlbyname("net.inet6.icmp6.stats", icmp6stat,
1158 		    &size, NULL, 0) == -1 && errno != ENOMEM)
1159 			return;
1160 	} else {
1161 		warnx("%s stats not available via KVM.", name);
1162 		return;
1163 	}
1164 
1165 	printf("%s:\n", name);
1166 
1167 #define	p(f, m) if (icmp6stat[f] || sflag <= 1)			\
1168 		printf(m, (unsigned long long)icmp6stat[f],	\
1169 		    plural(icmp6stat[f]))
1170 #define p_oerr(f, m) if (icmp6stat[ICMP6_STAT_OUTERRHIST + f] || sflag <= 1) \
1171 		printf(m,						     \
1172 		    (unsigned long long)icmp6stat[ICMP6_STAT_OUTERRHIST + f])
1173 
1174 	p(ICMP6_STAT_ERROR, "\t%llu call%s to icmp6_error\n");
1175 	p(ICMP6_STAT_CANTERROR,
1176 	    "\t%llu error%s not generated because old message was icmp6 or so\n");
1177 	p(ICMP6_STAT_TOOFREQ,
1178 	    "\t%llu error%s not generated because of rate limitation\n");
1179 	for (first = 1, i = 0; i < 256; i++)
1180 		if (icmp6stat[ICMP6_STAT_OUTHIST + i] != 0) {
1181 			if (first) {
1182 				printf("\tOutput packet histogram:\n");
1183 				first = 0;
1184 			}
1185 			printf("\t\t%s: %llu\n", icmp6names[i],
1186 			 (unsigned long long)icmp6stat[ICMP6_STAT_OUTHIST + i]);
1187 		}
1188 	p(ICMP6_STAT_BADCODE, "\t%llu message%s with bad code fields\n");
1189 	p(ICMP6_STAT_TOOSHORT, "\t%llu message%s < minimum length\n");
1190 	p(ICMP6_STAT_CHECKSUM, "\t%llu bad checksum%s\n");
1191 	p(ICMP6_STAT_BADLEN, "\t%llu message%s with bad length\n");
1192 	for (first = 1, i = 0; i < ICMP6_MAXTYPE; i++)
1193 		if (icmp6stat[ICMP6_STAT_INHIST + i] != 0) {
1194 			if (first) {
1195 				printf("\tInput packet histogram:\n");
1196 				first = 0;
1197 			}
1198 			printf("\t\t%s: %llu\n", icmp6names[i],
1199 			  (unsigned long long)icmp6stat[ICMP6_STAT_INHIST + i]);
1200 		}
1201 	printf("\tHistogram of error messages to be generated:\n");
1202 	p_oerr(ICMP6_ERRSTAT_DST_UNREACH_NOROUTE, "\t\t%llu no route\n");
1203 	p_oerr(ICMP6_ERRSTAT_DST_UNREACH_ADMIN,
1204 	    "\t\t%llu administratively prohibited\n");
1205 	p_oerr(ICMP6_ERRSTAT_DST_UNREACH_BEYONDSCOPE,
1206 	    "\t\t%llu beyond scope\n");
1207 	p_oerr(ICMP6_ERRSTAT_DST_UNREACH_ADDR,
1208 	    "\t\t%llu address unreachable\n");
1209 	p_oerr(ICMP6_ERRSTAT_DST_UNREACH_NOPORT,
1210 	    "\t\t%llu port unreachable\n");
1211 	p_oerr(ICMP6_ERRSTAT_PACKET_TOO_BIG, "\t\t%llu packet too big\n");
1212 	p_oerr(ICMP6_ERRSTAT_TIME_EXCEED_TRANSIT,
1213 	    "\t\t%llu time exceed transit\n");
1214 	p_oerr(ICMP6_ERRSTAT_TIME_EXCEED_REASSEMBLY,
1215 	    "\t\t%llu time exceed reassembly\n");
1216 	p_oerr(ICMP6_ERRSTAT_PARAMPROB_HEADER,
1217 	    "\t\t%llu erroneous header field\n");
1218 	p_oerr(ICMP6_ERRSTAT_PARAMPROB_NEXTHEADER,
1219 	    "\t\t%llu unrecognized next header\n");
1220 	p_oerr(ICMP6_ERRSTAT_PARAMPROB_OPTION,
1221 	    "\t\t%llu unrecognized option\n");
1222 	p_oerr(ICMP6_ERRSTAT_REDIRECT, "\t\t%llu redirect\n");
1223 	p_oerr(ICMP6_ERRSTAT_UNKNOWN, "\t\t%llu unknown\n");
1224 
1225 	p(ICMP6_STAT_REFLECT, "\t%llu message response%s generated\n");
1226 	p(ICMP6_STAT_ND_TOOMANYOPT,
1227 	    "\t%llu message%s with too many ND options\n");
1228 	p(ICMP6_STAT_ND_BADOPT, "\t%llu message%s with bad ND options\n");
1229 	p(ICMP6_STAT_BADNS, "\t%llu bad neighbor solicitation message%s\n");
1230 	p(ICMP6_STAT_BADNA, "\t%llu bad neighbor advertisement message%s\n");
1231 	p(ICMP6_STAT_BADRS, "\t%llu bad router solicitation message%s\n");
1232 	p(ICMP6_STAT_BADRA, "\t%llu bad router advertisement message%s\n");
1233 	p(ICMP6_STAT_DROPPED_RAROUTE,
1234 	    "\t%llu router advertisement route%s dropped\n");
1235 	p(ICMP6_STAT_BADREDIRECT, "\t%llu bad redirect message%s\n");
1236 	p(ICMP6_STAT_PMTUCHG, "\t%llu path MTU change%s\n");
1237 #undef p
1238 #undef p_oerr
1239 }
1240 
1241 /*
1242  * Dump ICMPv6 per-interface statistics based on RFC 2466.
1243  */
1244 void
icmp6_ifstats(const char * ifname)1245 icmp6_ifstats(const char *ifname)
1246 {
1247 	struct in6_ifreq ifr;
1248 	int s;
1249 #define	p(f, m) if (ifr.ifr_ifru.ifru_icmp6stat.f || sflag <= 1)	      \
1250 		printf(m, (unsigned long long)ifr.ifr_ifru.ifru_icmp6stat.f,  \
1251 		    plural(ifr.ifr_ifru.ifru_icmp6stat.f))
1252 
1253 	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
1254 		perror("Warning: socket(AF_INET6)");
1255 		return;
1256 	}
1257 
1258 	strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1259 	printf("icmp6 on %s:\n", ifname);
1260 
1261 	if (ioctl(s, SIOCGIFSTAT_ICMP6, (char *)&ifr) < 0) {
1262 		perror("Warning: ioctl(SIOCGIFSTAT_ICMP6)");
1263 		goto end;
1264 	}
1265 
1266 	p(ifs6_in_msg, "\t%llu total input message%s\n");
1267 	p(ifs6_in_error, "\t%llu total input error message%s\n");
1268 	p(ifs6_in_dstunreach,
1269 	    "\t%llu input destination unreachable error%s\n");
1270 	p(ifs6_in_adminprohib,
1271 	    "\t%llu input administratively prohibited error%s\n");
1272 	p(ifs6_in_timeexceed, "\t%llu input time exceeded error%s\n");
1273 	p(ifs6_in_paramprob, "\t%llu input parameter problem error%s\n");
1274 	p(ifs6_in_pkttoobig, "\t%llu input packet too big error%s\n");
1275 	p(ifs6_in_echo, "\t%llu input echo request%s\n");
1276 	p(ifs6_in_echoreply, "\t%llu input echo reply%s\n");
1277 	p(ifs6_in_routersolicit, "\t%llu input router solicitation%s\n");
1278 	p(ifs6_in_routeradvert, "\t%llu input router advertisement%s\n");
1279 	p(ifs6_in_neighborsolicit, "\t%llu input neighbor solicitation%s\n");
1280 	p(ifs6_in_neighboradvert, "\t%llu input neighbor advertisement%s\n");
1281 	p(ifs6_in_redirect, "\t%llu input redirect%s\n");
1282 	p(ifs6_in_mldquery, "\t%llu input MLD query%s\n");
1283 	p(ifs6_in_mldreport, "\t%llu input MLD report%s\n");
1284 	p(ifs6_in_mlddone, "\t%llu input MLD done%s\n");
1285 
1286 	p(ifs6_out_msg, "\t%llu total output message%s\n");
1287 	p(ifs6_out_error, "\t%llu total output error message%s\n");
1288 	p(ifs6_out_dstunreach,
1289 	    "\t%llu output destination unreachable error%s\n");
1290 	p(ifs6_out_adminprohib,
1291 	    "\t%llu output administratively prohibited error%s\n");
1292 	p(ifs6_out_timeexceed, "\t%llu output time exceeded error%s\n");
1293 	p(ifs6_out_paramprob, "\t%llu output parameter problem error%s\n");
1294 	p(ifs6_out_pkttoobig, "\t%llu output packet too big error%s\n");
1295 	p(ifs6_out_echo, "\t%llu output echo request%s\n");
1296 	p(ifs6_out_echoreply, "\t%llu output echo reply%s\n");
1297 	p(ifs6_out_routersolicit, "\t%llu output router solicitation%s\n");
1298 	p(ifs6_out_routeradvert, "\t%llu output router advertisement%s\n");
1299 	p(ifs6_out_neighborsolicit, "\t%llu output neighbor solicitation%s\n");
1300 	p(ifs6_out_neighboradvert, "\t%llu output neighbor advertisement%s\n");
1301 	p(ifs6_out_redirect, "\t%llu output redirect%s\n");
1302 	p(ifs6_out_mldquery, "\t%llu output MLD query%s\n");
1303 	p(ifs6_out_mldreport, "\t%llu output MLD report%s\n");
1304 	p(ifs6_out_mlddone, "\t%llu output MLD done%s\n");
1305 
1306   end:
1307 	close(s);
1308 #undef p
1309 }
1310 
1311 /*
1312  * Dump PIM statistics structure.
1313  */
1314 void
pim6_stats(u_long off,const char * name)1315 pim6_stats(u_long off, const char *name)
1316 {
1317 	uint64_t pim6stat[PIM6_NSTATS];
1318 
1319 	if (use_sysctl) {
1320 		size_t size = sizeof(pim6stat);
1321 
1322 		if (prog_sysctlbyname("net.inet6.pim6.stats", pim6stat, &size,
1323 		    NULL, 0) == -1 && errno != ENOMEM)
1324 			return;
1325 	} else {
1326 		warnx("%s stats not available via KVM.", name);
1327 		return;
1328 	}
1329 	printf("%s:\n", name);
1330 
1331 #define	p(f, m) if (pim6stat[f] || sflag <= 1)				      \
1332 		printf(m, (unsigned long long)pim6stat[f], plural(pim6stat[f]))
1333 
1334 	p(PIM6_STAT_RCV_TOTAL, "\t%llu message%s received\n");
1335 	p(PIM6_STAT_RCV_TOOSHORT,
1336 	    "\t%llu message%s received with too few bytes\n");
1337 	p(PIM6_STAT_RCV_BADSUM,
1338 	    "\t%llu message%s received with bad checksum\n");
1339 	p(PIM6_STAT_RCV_BADVERSION,
1340 	    "\t%llu message%s received with bad version\n");
1341 	p(PIM6_STAT_RCV_REGISTERS, "\t%llu register%s received\n");
1342 	p(PIM6_STAT_RCV_BADREGISTERS, "\t%llu bad register%s received\n");
1343 	p(PIM6_STAT_SND_REGISTERS, "\t%llu register%s sent\n");
1344 #undef p
1345 }
1346 
1347 /*
1348  * Dump raw ip6 statistics structure.
1349  */
1350 void
rip6_stats(u_long off,const char * name)1351 rip6_stats(u_long off, const char *name)
1352 {
1353 	uint64_t rip6stat[RIP6_NSTATS];
1354 	uint64_t delivered;
1355 
1356 	if (use_sysctl) {
1357 		size_t size = sizeof(rip6stat);
1358 
1359 		if (prog_sysctlbyname("net.inet6.raw6.stats", rip6stat, &size,
1360 		    NULL, 0) == -1 && errno != ENOMEM)
1361 			return;
1362 	} else {
1363 		warnx("%s stats not available via KVM.", name);
1364 		return;
1365 	}
1366 	printf("%s:\n", name);
1367 
1368 #define	p(f, m) if (rip6stat[f] || sflag <= 1) \
1369     printf(m, (unsigned long long)rip6stat[f], plural(rip6stat[f]))
1370 	p(RIP6_STAT_IPACKETS, "\t%llu message%s received\n");
1371 	p(RIP6_STAT_ISUM, "\t%llu checksum calculation%s on inbound\n");
1372 	p(RIP6_STAT_BADSUM, "\t%llu message%s with bad checksum\n");
1373 	p(RIP6_STAT_NOSOCK, "\t%llu message%s dropped due to no socket\n");
1374 	p(RIP6_STAT_NOSOCKMCAST,
1375 	    "\t%llu multicast message%s dropped due to no socket\n");
1376 	p(RIP6_STAT_FULLSOCK,
1377 	    "\t%llu message%s dropped due to full socket buffers\n");
1378 	delivered = rip6stat[RIP6_STAT_IPACKETS] -
1379 		    rip6stat[RIP6_STAT_BADSUM] -
1380 		    rip6stat[RIP6_STAT_NOSOCK] -
1381 		    rip6stat[RIP6_STAT_NOSOCKMCAST] -
1382 		    rip6stat[RIP6_STAT_FULLSOCK];
1383 	if (delivered || sflag <= 1)
1384 		printf("\t%llu delivered\n", (unsigned long long)delivered);
1385 	p(RIP6_STAT_OPACKETS, "\t%llu datagram%s output\n");
1386 #undef p
1387 }
1388 
1389 /*
1390  * Pretty print an Internet address (net address + port).
1391  * Take numeric_addr and numeric_port into consideration.
1392  */
1393 void
inet6print(const struct in6_addr * in6,int port,const char * proto)1394 inet6print(const struct in6_addr *in6, int port, const char *proto)
1395 {
1396 #define GETSERVBYPORT6(port, proto, ret)				\
1397 	do {								\
1398 		if (strcmp((proto), "tcp6") == 0)			\
1399 			(ret) = getservbyport((int)(port), "tcp");	\
1400 		else if (strcmp((proto), "udp6") == 0)			\
1401 			(ret) = getservbyport((int)(port), "udp");	\
1402 		else							\
1403 			(ret) = getservbyport((int)(port), (proto));	\
1404 	} while (0)
1405 
1406 	struct servent *sp = 0;
1407 	char line[80], *cp;
1408 	int lwidth;
1409 
1410 	lwidth = Aflag ? 12 : 16;
1411 	if (vflag && lwidth < (int)strlen(inet6name(in6)))
1412 		lwidth = strlen(inet6name(in6));
1413 	snprintf(line, sizeof(line), "%.*s.", lwidth, inet6name(in6));
1414 	cp = strchr(line, '\0');
1415 	if (!numeric_port && port)
1416 		GETSERVBYPORT6(port, proto, sp);
1417 	if (sp || port == 0)
1418 		snprintf(cp, sizeof(line) - (cp - line),
1419 		    "%s", sp ? sp->s_name : "*");
1420 	else
1421 		snprintf(cp, sizeof(line) - (cp - line),
1422 		    "%d", ntohs((u_short)port));
1423 	lwidth = Aflag ? 18 : 22;
1424 	if (vflag && lwidth < (int)strlen(line))
1425 		lwidth = strlen(line);
1426 	printf(" %-*.*s", lwidth, lwidth, line);
1427 }
1428 
1429 /*
1430  * Construct an Internet address representation.
1431  * If the numeric_addr has been supplied, give
1432  * numeric value, otherwise try for symbolic name.
1433  */
1434 
1435 char *
inet6name(const struct in6_addr * inp)1436 inet6name(const struct in6_addr *inp)
1437 {
1438 	char *cp;
1439 	static char line[NI_MAXHOST];
1440 	struct hostent *hp;
1441 	static char domain[MAXHOSTNAMELEN + 1];
1442 	static int first = 1;
1443 	char hbuf[NI_MAXHOST];
1444 	struct sockaddr_in6 sin6;
1445 	const int niflag = NI_NUMERICHOST;
1446 
1447 	if (first && !numeric_addr) {
1448 		first = 0;
1449 		if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
1450 		    (cp = strchr(domain, '.')))
1451 			(void) strlcpy(domain, cp + 1, sizeof(domain));
1452 		else
1453 			domain[0] = 0;
1454 	}
1455 	cp = 0;
1456 	if (!numeric_addr && !IN6_IS_ADDR_UNSPECIFIED(inp)) {
1457 		hp = gethostbyaddr((const char *)inp, sizeof(*inp), AF_INET6);
1458 		if (hp) {
1459 			if ((cp = strchr(hp->h_name, '.')) &&
1460 			    !strcmp(cp + 1, domain))
1461 				*cp = 0;
1462 			cp = hp->h_name;
1463 		}
1464 	}
1465 	if (IN6_IS_ADDR_UNSPECIFIED(inp))
1466 		strlcpy(line, "*", sizeof(line));
1467 	else if (cp)
1468 		strlcpy(line, cp, sizeof(line));
1469 	else {
1470 		memset(&sin6, 0, sizeof(sin6));
1471 		sin6.sin6_len = sizeof(sin6);
1472 		sin6.sin6_family = AF_INET6;
1473 		sin6.sin6_addr = *inp;
1474 		inet6_getscopeid(&sin6,
1475 		    INET6_IS_ADDR_LINKLOCAL | INET6_IS_ADDR_MC_LINKLOCAL);
1476 		if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
1477 				hbuf, sizeof(hbuf), NULL, 0, niflag) != 0)
1478 			strlcpy(hbuf, "?", sizeof(hbuf));
1479 		strlcpy(line, hbuf, sizeof(line));
1480 	}
1481 	return line;
1482 }
1483 
1484 /*
1485  * Dump the contents of a TCP6 PCB.
1486  */
1487 void
tcp6_dump(u_long off,const char * name,u_long pcbaddr)1488 tcp6_dump(u_long off, const char *name, u_long pcbaddr)
1489 {
1490 	callout_impl_t *ci;
1491 	int i, hardticks;
1492 	struct kinfo_pcb *pcblist;
1493 #ifdef TCP6
1494 #define mypcb tcp6cb
1495 #else
1496 #define mypcb tcpcb
1497 #endif
1498 	size_t j, len;
1499 
1500 	if (use_sysctl)
1501 		pcblist = getpcblist_sysctl(name, &len);
1502 	else
1503 		pcblist = getpcblist_kmem(off, name, &len);
1504 
1505 	for (j = 0; j < len; j++)
1506 		if (pcblist[j].ki_ppcbaddr == pcbaddr)
1507 			break;
1508 	free(pcblist);
1509 
1510 	if (j == len)
1511 		errx(1, "0x%lx is not a valid pcb address", pcbaddr);
1512 
1513 	kread(pcbaddr, (char *)&mypcb, sizeof(mypcb));
1514 	hardticks = get_hardticks();
1515 
1516 	printf("TCP Protocol Control Block at 0x%08lx:\n\n", pcbaddr);
1517 	printf("Timers:\n");
1518 	for (i = 0; i < TCP6T_NTIMERS; i++) {
1519 		char buf[128];
1520 		ci = (callout_impl_t *)&tcpcb.t_timer[i];
1521 		snprintb(buf, sizeof(buf), CALLOUT_FMT, ci->c_flags);
1522 		printf("\t%s\t%s", tcptimers[i], buf);
1523 		if (ci->c_flags & CALLOUT_PENDING)
1524 			printf("\t%d\n", ci->c_time - hardticks);
1525 		else
1526 			printf("\n");
1527 	}
1528 	printf("\n\n");
1529 
1530 	if (mypcb.t_state < 0 || mypcb.t_state >= TCP6_NSTATES)
1531 		printf("State: %d", mypcb.t_state);
1532 	else
1533 		printf("State: %s", tcp6states[mypcb.t_state]);
1534 	printf(", flags 0x%x, inpcb 0x%lx\n\n", mypcb.t_flags,
1535 	    (u_long)mypcb.t_inpcb);
1536 
1537 	printf("rxtshift %d, rxtcur %d, dupacks %d\n", mypcb.t_rxtshift,
1538 	    mypcb.t_rxtcur, mypcb.t_dupacks);
1539 #ifdef TCP6
1540 	printf("peermaxseg %u, maxseg %u, force %d\n\n", mypcb.t_peermaxseg,
1541 	    mypcb.t_maxseg, mypcb.t_force);
1542 #else
1543 	printf("peermss %u, ourmss %u, segsz %u, segqlen %u\n\n",
1544 	    tcpcb.t_peermss, tcpcb.t_ourmss, tcpcb.t_segsz, tcpcb.t_segqlen);
1545 #endif
1546 
1547 	printf("snd_una %u, snd_nxt %u, snd_up %u\n",
1548 	    mypcb.snd_una, mypcb.snd_nxt, mypcb.snd_up);
1549 	printf("snd_wl1 %u, snd_wl2 %u, iss %u, snd_wnd %llu\n\n",
1550 	    mypcb.snd_wl1, mypcb.snd_wl2, mypcb.iss,
1551 	    (unsigned long long)mypcb.snd_wnd);
1552 
1553 	printf("rcv_wnd %llu, rcv_nxt %u, rcv_up %u, irs %u\n\n",
1554 	    (unsigned long long)mypcb.rcv_wnd, mypcb.rcv_nxt,
1555 	    mypcb.rcv_up, mypcb.irs);
1556 
1557 	printf("rcv_adv %u, snd_max %u, snd_cwnd %llu, snd_ssthresh %llu\n",
1558 	    mypcb.rcv_adv, mypcb.snd_max, (unsigned long long)mypcb.snd_cwnd,
1559 	    (unsigned long long)mypcb.snd_ssthresh);
1560 
1561 #ifdef TCP6
1562 	printf("idle %d, rtt %d, " mypcb.t_idle, mypcb.t_rtt);
1563 #else
1564 	printf("rcvtime %u, rtttime %u, ", tcpcb.t_rcvtime, tcpcb.t_rtttime);
1565 #endif
1566 
1567 	printf("rtseq %u, srtt %d, rttvar %d, rttmin %d, "
1568 	    "max_sndwnd %llu\n\n", mypcb.t_rtseq,
1569 	    mypcb.t_srtt, mypcb.t_rttvar, mypcb.t_rttmin,
1570 	    (unsigned long long)mypcb.max_sndwnd);
1571 
1572 	printf("oobflags %d, iobc %d, softerror %d\n\n", mypcb.t_oobflags,
1573 	    mypcb.t_iobc, mypcb.t_softerror);
1574 
1575 	printf("snd_scale %d, rcv_scale %d, req_r_scale %d, req_s_scale %d\n",
1576 	    mypcb.snd_scale, mypcb.rcv_scale, mypcb.request_r_scale,
1577 	    mypcb.requested_s_scale);
1578 	printf("ts_recent %u, ts_regent_age %d, last_ack_sent %u\n",
1579 	    mypcb.ts_recent, mypcb.ts_recent_age, mypcb.last_ack_sent);
1580 }
1581 
1582 #endif /*INET6*/
1583