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