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