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