1 /* BSDI inet.c,v 2.3 1995/10/24 02:19:29 prb Exp */
2 /*-
3 * Copyright (c) 1983, 1988, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 4. Neither the name of the University nor the names of its contributors
15 * may be used to endorse or promote products derived from this software
16 * without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31 #if 0
32 #ifndef lint
33 static char sccsid[] = "@(#)inet6.c 8.4 (Berkeley) 4/20/94";
34 #endif /* not lint */
35 #endif
36
37 #include <sys/cdefs.h>
38 __FBSDID("$FreeBSD$");
39
40 #ifdef INET6
41 #include <sys/param.h>
42 #include <sys/socket.h>
43 #include <sys/socketvar.h>
44 #include <sys/ioctl.h>
45 #include <sys/mbuf.h>
46 #include <sys/protosw.h>
47 #include <sys/sysctl.h>
48
49 #include <net/route.h>
50 #include <net/if.h>
51 #include <net/if_var.h>
52 #include <netinet/in.h>
53 #include <netinet/ip6.h>
54 #include <netinet/icmp6.h>
55 #include <netinet/in_systm.h>
56 #include <netinet6/in6_pcb.h>
57 #include <netinet6/in6_var.h>
58 #include <netinet6/ip6_var.h>
59 #include <netinet6/pim6_var.h>
60 #include <netinet6/raw_ip6.h>
61
62 #include <arpa/inet.h>
63 #include <netdb.h>
64
65 #include <err.h>
66 #include <stdint.h>
67 #include <stdio.h>
68 #include <errno.h>
69 #include <string.h>
70 #include <unistd.h>
71 #include "netstat.h"
72
73 struct socket sockb;
74
75 char *inet6name(struct in6_addr *);
76
77 static char ntop_buf[INET6_ADDRSTRLEN];
78
79 static const char *ip6nh[] = {
80 "hop by hop",
81 "ICMP",
82 "IGMP",
83 "#3",
84 "IP",
85 "#5",
86 "TCP",
87 "#7",
88 "#8",
89 "#9",
90 "#10",
91 "#11",
92 "#12",
93 "#13",
94 "#14",
95 "#15",
96 "#16",
97 "UDP",
98 "#18",
99 "#19",
100 "#20",
101 "#21",
102 "IDP",
103 "#23",
104 "#24",
105 "#25",
106 "#26",
107 "#27",
108 "#28",
109 "TP",
110 "#30",
111 "#31",
112 "#32",
113 "#33",
114 "#34",
115 "#35",
116 "#36",
117 "#37",
118 "#38",
119 "#39",
120 "#40",
121 "IP6",
122 "#42",
123 "routing",
124 "fragment",
125 "#45",
126 "#46",
127 "#47",
128 "#48",
129 "#49",
130 "ESP",
131 "AH",
132 "#52",
133 "#53",
134 "#54",
135 "#55",
136 "#56",
137 "#57",
138 "ICMP6",
139 "no next header",
140 "destination option",
141 "#61",
142 "mobility",
143 "#63",
144 "#64",
145 "#65",
146 "#66",
147 "#67",
148 "#68",
149 "#69",
150 "#70",
151 "#71",
152 "#72",
153 "#73",
154 "#74",
155 "#75",
156 "#76",
157 "#77",
158 "#78",
159 "#79",
160 "ISOIP",
161 "#81",
162 "#82",
163 "#83",
164 "#84",
165 "#85",
166 "#86",
167 "#87",
168 "#88",
169 "OSPF",
170 "#80",
171 "#91",
172 "#92",
173 "#93",
174 "#94",
175 "#95",
176 "#96",
177 "Ethernet",
178 "#98",
179 "#99",
180 "#100",
181 "#101",
182 "#102",
183 "PIM",
184 "#104",
185 "#105",
186 "#106",
187 "#107",
188 "#108",
189 "#109",
190 "#110",
191 "#111",
192 "#112",
193 "#113",
194 "#114",
195 "#115",
196 "#116",
197 "#117",
198 "#118",
199 "#119",
200 "#120",
201 "#121",
202 "#122",
203 "#123",
204 "#124",
205 "#125",
206 "#126",
207 "#127",
208 "#128",
209 "#129",
210 "#130",
211 "#131",
212 "#132",
213 "#133",
214 "#134",
215 "#135",
216 "#136",
217 "#137",
218 "#138",
219 "#139",
220 "#140",
221 "#141",
222 "#142",
223 "#143",
224 "#144",
225 "#145",
226 "#146",
227 "#147",
228 "#148",
229 "#149",
230 "#150",
231 "#151",
232 "#152",
233 "#153",
234 "#154",
235 "#155",
236 "#156",
237 "#157",
238 "#158",
239 "#159",
240 "#160",
241 "#161",
242 "#162",
243 "#163",
244 "#164",
245 "#165",
246 "#166",
247 "#167",
248 "#168",
249 "#169",
250 "#170",
251 "#171",
252 "#172",
253 "#173",
254 "#174",
255 "#175",
256 "#176",
257 "#177",
258 "#178",
259 "#179",
260 "#180",
261 "#181",
262 "#182",
263 "#183",
264 "#184",
265 "#185",
266 "#186",
267 "#187",
268 "#188",
269 "#189",
270 "#180",
271 "#191",
272 "#192",
273 "#193",
274 "#194",
275 "#195",
276 "#196",
277 "#197",
278 "#198",
279 "#199",
280 "#200",
281 "#201",
282 "#202",
283 "#203",
284 "#204",
285 "#205",
286 "#206",
287 "#207",
288 "#208",
289 "#209",
290 "#210",
291 "#211",
292 "#212",
293 "#213",
294 "#214",
295 "#215",
296 "#216",
297 "#217",
298 "#218",
299 "#219",
300 "#220",
301 "#221",
302 "#222",
303 "#223",
304 "#224",
305 "#225",
306 "#226",
307 "#227",
308 "#228",
309 "#229",
310 "#230",
311 "#231",
312 "#232",
313 "#233",
314 "#234",
315 "#235",
316 "#236",
317 "#237",
318 "#238",
319 "#239",
320 "#240",
321 "#241",
322 "#242",
323 "#243",
324 "#244",
325 "#245",
326 "#246",
327 "#247",
328 "#248",
329 "#249",
330 "#250",
331 "#251",
332 "#252",
333 "#253",
334 "#254",
335 "#255",
336 };
337
338 static const char *srcrule_str[] = {
339 "first candidate",
340 "same address",
341 "appropriate scope",
342 "deprecated address",
343 "home address",
344 "outgoing interface",
345 "matching label",
346 "public/temporary address",
347 "alive interface",
348 "better virtual status",
349 "preferred source",
350 "rule #11",
351 "rule #12",
352 "rule #13",
353 "longest match",
354 "rule #15",
355 };
356
357 /*
358 * Dump IP6 statistics structure.
359 */
360 void
ip6_stats(u_long off,const char * name,int af1 __unused,int proto __unused)361 ip6_stats(u_long off, const char *name, int af1 __unused, int proto __unused)
362 {
363 struct ip6stat ip6stat, zerostat;
364 int first, i;
365 size_t len;
366
367 len = sizeof ip6stat;
368 if (live) {
369 memset(&ip6stat, 0, len);
370 if (zflag)
371 memset(&zerostat, 0, len);
372 if (sysctlbyname("net.inet6.ip6.stats", &ip6stat, &len,
373 zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
374 if (errno != ENOENT)
375 warn("sysctl: net.inet6.ip6.stats");
376 return;
377 }
378 } else
379 kread_counters(off, &ip6stat, len);
380
381 printf("%s:\n", name);
382
383 #define p(f, m) if (ip6stat.f || sflag <= 1) \
384 printf(m, (uintmax_t)ip6stat.f, plural(ip6stat.f))
385 #define p1a(f, m) if (ip6stat.f || sflag <= 1) \
386 printf(m, (uintmax_t)ip6stat.f)
387
388 p(ip6s_total, "\t%ju total packet%s received\n");
389 p1a(ip6s_toosmall, "\t%ju with size smaller than minimum\n");
390 p1a(ip6s_tooshort, "\t%ju with data size < data length\n");
391 p1a(ip6s_badoptions, "\t%ju with bad options\n");
392 p1a(ip6s_badvers, "\t%ju with incorrect version number\n");
393 p(ip6s_fragments, "\t%ju fragment%s received\n");
394 p(ip6s_fragdropped, "\t%ju fragment%s dropped (dup or out of space)\n");
395 p(ip6s_fragtimeout, "\t%ju fragment%s dropped after timeout\n");
396 p(ip6s_fragoverflow, "\t%ju fragment%s that exceeded limit\n");
397 p(ip6s_reassembled, "\t%ju packet%s reassembled ok\n");
398 p(ip6s_delivered, "\t%ju packet%s for this host\n");
399 p(ip6s_forward, "\t%ju packet%s forwarded\n");
400 p(ip6s_cantforward, "\t%ju packet%s not forwardable\n");
401 p(ip6s_redirectsent, "\t%ju redirect%s sent\n");
402 p(ip6s_localout, "\t%ju packet%s sent from this host\n");
403 p(ip6s_rawout, "\t%ju packet%s sent with fabricated ip header\n");
404 p(ip6s_odropped, "\t%ju output packet%s dropped due to no bufs, etc.\n");
405 p(ip6s_noroute, "\t%ju output packet%s discarded due to no route\n");
406 p(ip6s_fragmented, "\t%ju output datagram%s fragmented\n");
407 p(ip6s_ofragments, "\t%ju fragment%s created\n");
408 p(ip6s_cantfrag, "\t%ju datagram%s that can't be fragmented\n");
409 p(ip6s_badscope, "\t%ju packet%s that violated scope rules\n");
410 p(ip6s_notmember, "\t%ju multicast packet%s which we don't join\n");
411 for (first = 1, i = 0; i < IP6S_HDRCNT; i++)
412 if (ip6stat.ip6s_nxthist[i] != 0) {
413 if (first) {
414 printf("\tInput histogram:\n");
415 first = 0;
416 }
417 printf("\t\t%s: %ju\n", ip6nh[i],
418 (uintmax_t)ip6stat.ip6s_nxthist[i]);
419 }
420 printf("\tMbuf statistics:\n");
421 printf("\t\t%ju one mbuf\n", (uintmax_t)ip6stat.ip6s_m1);
422 for (first = 1, i = 0; i < IP6S_M2MMAX; i++) {
423 char ifbuf[IFNAMSIZ];
424 if (ip6stat.ip6s_m2m[i] != 0) {
425 if (first) {
426 printf("\t\ttwo or more mbuf:\n");
427 first = 0;
428 }
429 printf("\t\t\t%s= %ju\n",
430 if_indextoname(i, ifbuf),
431 (uintmax_t)ip6stat.ip6s_m2m[i]);
432 }
433 }
434 printf("\t\t%ju one ext mbuf\n",
435 (uintmax_t)ip6stat.ip6s_mext1);
436 printf("\t\t%ju two or more ext mbuf\n",
437 (uintmax_t)ip6stat.ip6s_mext2m);
438 p(ip6s_exthdrtoolong,
439 "\t%ju packet%s whose headers are not contiguous\n");
440 p(ip6s_nogif, "\t%ju tunneling packet%s that can't find gif\n");
441 p(ip6s_toomanyhdr,
442 "\t%ju packet%s discarded because of too many headers\n");
443
444 /* for debugging source address selection */
445 #define PRINT_SCOPESTAT(s,i) do {\
446 switch(i) { /* XXX hardcoding in each case */\
447 case 1:\
448 p(s, "\t\t%ju interface-local%s\n");\
449 break;\
450 case 2:\
451 p(s,"\t\t%ju link-local%s\n");\
452 break;\
453 case 5:\
454 p(s,"\t\t%ju site-local%s\n");\
455 break;\
456 case 14:\
457 p(s,"\t\t%ju global%s\n");\
458 break;\
459 default:\
460 printf("\t\t%ju addresses scope=%x\n",\
461 (uintmax_t)ip6stat.s, i);\
462 }\
463 } while (0);
464
465 p(ip6s_sources_none,
466 "\t%ju failure%s of source address selection\n");
467 for (first = 1, i = 0; i < IP6S_SCOPECNT; i++) {
468 if (ip6stat.ip6s_sources_sameif[i]) {
469 if (first) {
470 printf("\tsource addresses on an outgoing I/F\n");
471 first = 0;
472 }
473 PRINT_SCOPESTAT(ip6s_sources_sameif[i], i);
474 }
475 }
476 for (first = 1, i = 0; i < IP6S_SCOPECNT; i++) {
477 if (ip6stat.ip6s_sources_otherif[i]) {
478 if (first) {
479 printf("\tsource addresses on a non-outgoing I/F\n");
480 first = 0;
481 }
482 PRINT_SCOPESTAT(ip6s_sources_otherif[i], i);
483 }
484 }
485 for (first = 1, i = 0; i < IP6S_SCOPECNT; i++) {
486 if (ip6stat.ip6s_sources_samescope[i]) {
487 if (first) {
488 printf("\tsource addresses of same scope\n");
489 first = 0;
490 }
491 PRINT_SCOPESTAT(ip6s_sources_samescope[i], i);
492 }
493 }
494 for (first = 1, i = 0; i < IP6S_SCOPECNT; i++) {
495 if (ip6stat.ip6s_sources_otherscope[i]) {
496 if (first) {
497 printf("\tsource addresses of a different scope\n");
498 first = 0;
499 }
500 PRINT_SCOPESTAT(ip6s_sources_otherscope[i], i);
501 }
502 }
503 for (first = 1, i = 0; i < IP6S_SCOPECNT; i++) {
504 if (ip6stat.ip6s_sources_deprecated[i]) {
505 if (first) {
506 printf("\tdeprecated source addresses\n");
507 first = 0;
508 }
509 PRINT_SCOPESTAT(ip6s_sources_deprecated[i], i);
510 }
511 }
512
513 printf("\tSource addresses selection rule applied:\n");
514 for (i = 0; i < IP6S_RULESMAX; i++) {
515 if (ip6stat.ip6s_sources_rule[i])
516 printf("\t\t%ju %s\n",
517 (uintmax_t)ip6stat.ip6s_sources_rule[i],
518 srcrule_str[i]);
519 }
520 #undef p
521 #undef p1a
522 }
523
524 /*
525 * Dump IPv6 per-interface statistics based on RFC 2465.
526 */
527 void
ip6_ifstats(char * ifname)528 ip6_ifstats(char *ifname)
529 {
530 struct in6_ifreq ifr;
531 int s;
532 #define p(f, m) if (ifr.ifr_ifru.ifru_stat.f || sflag <= 1) \
533 printf(m, (uintmax_t)ifr.ifr_ifru.ifru_stat.f, plural(ifr.ifr_ifru.ifru_stat.f))
534 #define p_5(f, m) if (ifr.ifr_ifru.ifru_stat.f || sflag <= 1) \
535 printf(m, (uintmax_t)ip6stat.f)
536
537 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
538 perror("Warning: socket(AF_INET6)");
539 return;
540 }
541
542 strcpy(ifr.ifr_name, ifname);
543 if (ioctl(s, SIOCGIFSTAT_IN6, (char *)&ifr) < 0) {
544 if (errno != EPFNOSUPPORT)
545 perror("Warning: ioctl(SIOCGIFSTAT_IN6)");
546 goto end;
547 }
548
549 printf("ip6 on %s:\n", ifr.ifr_name);
550 p(ifs6_in_receive, "\t%ju total input datagram%s\n");
551 p(ifs6_in_hdrerr, "\t%ju datagram%s with invalid header received\n");
552 p(ifs6_in_toobig, "\t%ju datagram%s exceeded MTU received\n");
553 p(ifs6_in_noroute, "\t%ju datagram%s with no route received\n");
554 p(ifs6_in_addrerr, "\t%ju datagram%s with invalid dst received\n");
555 p(ifs6_in_protounknown, "\t%ju datagram%s with unknown proto received\n");
556 p(ifs6_in_truncated, "\t%ju truncated datagram%s received\n");
557 p(ifs6_in_discard, "\t%ju input datagram%s discarded\n");
558 p(ifs6_in_deliver,
559 "\t%ju datagram%s delivered to an upper layer protocol\n");
560 p(ifs6_out_forward, "\t%ju datagram%s forwarded to this interface\n");
561 p(ifs6_out_request,
562 "\t%ju datagram%s sent from an upper layer protocol\n");
563 p(ifs6_out_discard, "\t%ju total discarded output datagram%s\n");
564 p(ifs6_out_fragok, "\t%ju output datagram%s fragmented\n");
565 p(ifs6_out_fragfail, "\t%ju output datagram%s failed on fragment\n");
566 p(ifs6_out_fragcreat, "\t%ju output datagram%s succeeded on fragment\n");
567 p(ifs6_reass_reqd, "\t%ju incoming datagram%s fragmented\n");
568 p(ifs6_reass_ok, "\t%ju datagram%s reassembled\n");
569 p(ifs6_reass_fail, "\t%ju datagram%s failed on reassembly\n");
570 p(ifs6_in_mcast, "\t%ju multicast datagram%s received\n");
571 p(ifs6_out_mcast, "\t%ju multicast datagram%s sent\n");
572
573 end:
574 close(s);
575
576 #undef p
577 #undef p_5
578 }
579
580 static const char *icmp6names[] = {
581 "#0",
582 "unreach",
583 "packet too big",
584 "time exceed",
585 "parameter problem",
586 "#5",
587 "#6",
588 "#7",
589 "#8",
590 "#9",
591 "#10",
592 "#11",
593 "#12",
594 "#13",
595 "#14",
596 "#15",
597 "#16",
598 "#17",
599 "#18",
600 "#19",
601 "#20",
602 "#21",
603 "#22",
604 "#23",
605 "#24",
606 "#25",
607 "#26",
608 "#27",
609 "#28",
610 "#29",
611 "#30",
612 "#31",
613 "#32",
614 "#33",
615 "#34",
616 "#35",
617 "#36",
618 "#37",
619 "#38",
620 "#39",
621 "#40",
622 "#41",
623 "#42",
624 "#43",
625 "#44",
626 "#45",
627 "#46",
628 "#47",
629 "#48",
630 "#49",
631 "#50",
632 "#51",
633 "#52",
634 "#53",
635 "#54",
636 "#55",
637 "#56",
638 "#57",
639 "#58",
640 "#59",
641 "#60",
642 "#61",
643 "#62",
644 "#63",
645 "#64",
646 "#65",
647 "#66",
648 "#67",
649 "#68",
650 "#69",
651 "#70",
652 "#71",
653 "#72",
654 "#73",
655 "#74",
656 "#75",
657 "#76",
658 "#77",
659 "#78",
660 "#79",
661 "#80",
662 "#81",
663 "#82",
664 "#83",
665 "#84",
666 "#85",
667 "#86",
668 "#87",
669 "#88",
670 "#89",
671 "#80",
672 "#91",
673 "#92",
674 "#93",
675 "#94",
676 "#95",
677 "#96",
678 "#97",
679 "#98",
680 "#99",
681 "#100",
682 "#101",
683 "#102",
684 "#103",
685 "#104",
686 "#105",
687 "#106",
688 "#107",
689 "#108",
690 "#109",
691 "#110",
692 "#111",
693 "#112",
694 "#113",
695 "#114",
696 "#115",
697 "#116",
698 "#117",
699 "#118",
700 "#119",
701 "#120",
702 "#121",
703 "#122",
704 "#123",
705 "#124",
706 "#125",
707 "#126",
708 "#127",
709 "echo",
710 "echo reply",
711 "multicast listener query",
712 "MLDv1 listener report",
713 "MLDv1 listener done",
714 "router solicitation",
715 "router advertisement",
716 "neighbor solicitation",
717 "neighbor advertisement",
718 "redirect",
719 "router renumbering",
720 "node information request",
721 "node information reply",
722 "inverse neighbor solicitation",
723 "inverse neighbor advertisement",
724 "MLDv2 listener report",
725 "#144",
726 "#145",
727 "#146",
728 "#147",
729 "#148",
730 "#149",
731 "#150",
732 "#151",
733 "#152",
734 "#153",
735 "#154",
736 "#155",
737 "#156",
738 "#157",
739 "#158",
740 "#159",
741 "#160",
742 "#161",
743 "#162",
744 "#163",
745 "#164",
746 "#165",
747 "#166",
748 "#167",
749 "#168",
750 "#169",
751 "#170",
752 "#171",
753 "#172",
754 "#173",
755 "#174",
756 "#175",
757 "#176",
758 "#177",
759 "#178",
760 "#179",
761 "#180",
762 "#181",
763 "#182",
764 "#183",
765 "#184",
766 "#185",
767 "#186",
768 "#187",
769 "#188",
770 "#189",
771 "#180",
772 "#191",
773 "#192",
774 "#193",
775 "#194",
776 "#195",
777 "#196",
778 "#197",
779 "#198",
780 "#199",
781 "#200",
782 "#201",
783 "#202",
784 "#203",
785 "#204",
786 "#205",
787 "#206",
788 "#207",
789 "#208",
790 "#209",
791 "#210",
792 "#211",
793 "#212",
794 "#213",
795 "#214",
796 "#215",
797 "#216",
798 "#217",
799 "#218",
800 "#219",
801 "#220",
802 "#221",
803 "#222",
804 "#223",
805 "#224",
806 "#225",
807 "#226",
808 "#227",
809 "#228",
810 "#229",
811 "#230",
812 "#231",
813 "#232",
814 "#233",
815 "#234",
816 "#235",
817 "#236",
818 "#237",
819 "#238",
820 "#239",
821 "#240",
822 "#241",
823 "#242",
824 "#243",
825 "#244",
826 "#245",
827 "#246",
828 "#247",
829 "#248",
830 "#249",
831 "#250",
832 "#251",
833 "#252",
834 "#253",
835 "#254",
836 "#255",
837 };
838
839 /*
840 * Dump ICMP6 statistics.
841 */
842 void
icmp6_stats(u_long off,const char * name,int af1 __unused,int proto __unused)843 icmp6_stats(u_long off, const char *name, int af1 __unused, int proto __unused)
844 {
845 struct icmp6stat icmp6stat, zerostat;
846 int i, first;
847 size_t len;
848
849 len = sizeof icmp6stat;
850 if (live) {
851 memset(&icmp6stat, 0, len);
852 if (zflag)
853 memset(&zerostat, 0, len);
854 if (sysctlbyname("net.inet6.icmp6.stats", &icmp6stat, &len,
855 zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
856 if (errno != ENOENT)
857 warn("sysctl: net.inet6.icmp6.stats");
858 return;
859 }
860 } else
861 kread_counters(off, &icmp6stat, len);
862
863 printf("%s:\n", name);
864
865 #define p(f, m) if (icmp6stat.f || sflag <= 1) \
866 printf(m, (uintmax_t)icmp6stat.f, plural(icmp6stat.f))
867 #define p_5(f, m) if (icmp6stat.f || sflag <= 1) \
868 printf(m, (uintmax_t)icmp6stat.f)
869
870 p(icp6s_error, "\t%ju call%s to icmp6_error\n");
871 p(icp6s_canterror,
872 "\t%ju error%s not generated in response to an icmp6 message\n");
873 p(icp6s_toofreq,
874 "\t%ju error%s not generated because of rate limitation\n");
875 #define NELEM (int)(sizeof(icmp6stat.icp6s_outhist)/sizeof(icmp6stat.icp6s_outhist[0]))
876 for (first = 1, i = 0; i < NELEM; i++)
877 if (icmp6stat.icp6s_outhist[i] != 0) {
878 if (first) {
879 printf("\tOutput histogram:\n");
880 first = 0;
881 }
882 printf("\t\t%s: %ju\n", icmp6names[i],
883 (uintmax_t)icmp6stat.icp6s_outhist[i]);
884 }
885 #undef NELEM
886 p(icp6s_badcode, "\t%ju message%s with bad code fields\n");
887 p(icp6s_tooshort, "\t%ju message%s < minimum length\n");
888 p(icp6s_checksum, "\t%ju bad checksum%s\n");
889 p(icp6s_badlen, "\t%ju message%s with bad length\n");
890 #define NELEM (int)(sizeof(icmp6stat.icp6s_inhist)/sizeof(icmp6stat.icp6s_inhist[0]))
891 for (first = 1, i = 0; i < NELEM; i++)
892 if (icmp6stat.icp6s_inhist[i] != 0) {
893 if (first) {
894 printf("\tInput histogram:\n");
895 first = 0;
896 }
897 printf("\t\t%s: %ju\n", icmp6names[i],
898 (uintmax_t)icmp6stat.icp6s_inhist[i]);
899 }
900 #undef NELEM
901 printf("\tHistogram of error messages to be generated:\n");
902 p_5(icp6s_odst_unreach_noroute, "\t\t%ju no route\n");
903 p_5(icp6s_odst_unreach_admin, "\t\t%ju administratively prohibited\n");
904 p_5(icp6s_odst_unreach_beyondscope, "\t\t%ju beyond scope\n");
905 p_5(icp6s_odst_unreach_addr, "\t\t%ju address unreachable\n");
906 p_5(icp6s_odst_unreach_noport, "\t\t%ju port unreachable\n");
907 p_5(icp6s_opacket_too_big, "\t\t%ju packet too big\n");
908 p_5(icp6s_otime_exceed_transit, "\t\t%ju time exceed transit\n");
909 p_5(icp6s_otime_exceed_reassembly, "\t\t%ju time exceed reassembly\n");
910 p_5(icp6s_oparamprob_header, "\t\t%ju erroneous header field\n");
911 p_5(icp6s_oparamprob_nextheader, "\t\t%ju unrecognized next header\n");
912 p_5(icp6s_oparamprob_option, "\t\t%ju unrecognized option\n");
913 p_5(icp6s_oredirect, "\t\t%ju redirect\n");
914 p_5(icp6s_ounknown, "\t\t%ju unknown\n");
915
916 p(icp6s_reflect, "\t%ju message response%s generated\n");
917 p(icp6s_nd_toomanyopt, "\t%ju message%s with too many ND options\n");
918 p(icp6s_nd_badopt, "\t%ju message%s with bad ND options\n");
919 p(icp6s_badns, "\t%ju bad neighbor solicitation message%s\n");
920 p(icp6s_badna, "\t%ju bad neighbor advertisement message%s\n");
921 p(icp6s_badrs, "\t%ju bad router solicitation message%s\n");
922 p(icp6s_badra, "\t%ju bad router advertisement message%s\n");
923 p(icp6s_badredirect, "\t%ju bad redirect message%s\n");
924 p(icp6s_pmtuchg, "\t%ju path MTU change%s\n");
925 #undef p
926 #undef p_5
927 }
928
929 /*
930 * Dump ICMPv6 per-interface statistics based on RFC 2466.
931 */
932 void
icmp6_ifstats(char * ifname)933 icmp6_ifstats(char *ifname)
934 {
935 struct in6_ifreq ifr;
936 int s;
937 #define p(f, m) if (ifr.ifr_ifru.ifru_icmp6stat.f || sflag <= 1) \
938 printf(m, (uintmax_t)ifr.ifr_ifru.ifru_icmp6stat.f, plural(ifr.ifr_ifru.ifru_icmp6stat.f))
939 #define p2(f, m) if (ifr.ifr_ifru.ifru_icmp6stat.f || sflag <= 1) \
940 printf(m, (uintmax_t)ifr.ifr_ifru.ifru_icmp6stat.f, pluralies(ifr.ifr_ifru.ifru_icmp6stat.f))
941
942 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
943 perror("Warning: socket(AF_INET6)");
944 return;
945 }
946
947 strcpy(ifr.ifr_name, ifname);
948 if (ioctl(s, SIOCGIFSTAT_ICMP6, (char *)&ifr) < 0) {
949 if (errno != EPFNOSUPPORT)
950 perror("Warning: ioctl(SIOCGIFSTAT_ICMP6)");
951 goto end;
952 }
953
954 printf("icmp6 on %s:\n", ifr.ifr_name);
955 p(ifs6_in_msg, "\t%ju total input message%s\n");
956 p(ifs6_in_error, "\t%ju total input error message%s\n");
957 p(ifs6_in_dstunreach, "\t%ju input destination unreachable error%s\n");
958 p(ifs6_in_adminprohib, "\t%ju input administratively prohibited error%s\n");
959 p(ifs6_in_timeexceed, "\t%ju input time exceeded error%s\n");
960 p(ifs6_in_paramprob, "\t%ju input parameter problem error%s\n");
961 p(ifs6_in_pkttoobig, "\t%ju input packet too big error%s\n");
962 p(ifs6_in_echo, "\t%ju input echo request%s\n");
963 p2(ifs6_in_echoreply, "\t%ju input echo repl%s\n");
964 p(ifs6_in_routersolicit, "\t%ju input router solicitation%s\n");
965 p(ifs6_in_routeradvert, "\t%ju input router advertisement%s\n");
966 p(ifs6_in_neighborsolicit, "\t%ju input neighbor solicitation%s\n");
967 p(ifs6_in_neighboradvert, "\t%ju input neighbor advertisement%s\n");
968 p(ifs6_in_redirect, "\t%ju input redirect%s\n");
969 p2(ifs6_in_mldquery, "\t%ju input MLD quer%s\n");
970 p(ifs6_in_mldreport, "\t%ju input MLD report%s\n");
971 p(ifs6_in_mlddone, "\t%ju input MLD done%s\n");
972
973 p(ifs6_out_msg, "\t%ju total output message%s\n");
974 p(ifs6_out_error, "\t%ju total output error message%s\n");
975 p(ifs6_out_dstunreach, "\t%ju output destination unreachable error%s\n");
976 p(ifs6_out_adminprohib, "\t%ju output administratively prohibited error%s\n");
977 p(ifs6_out_timeexceed, "\t%ju output time exceeded error%s\n");
978 p(ifs6_out_paramprob, "\t%ju output parameter problem error%s\n");
979 p(ifs6_out_pkttoobig, "\t%ju output packet too big error%s\n");
980 p(ifs6_out_echo, "\t%ju output echo request%s\n");
981 p2(ifs6_out_echoreply, "\t%ju output echo repl%s\n");
982 p(ifs6_out_routersolicit, "\t%ju output router solicitation%s\n");
983 p(ifs6_out_routeradvert, "\t%ju output router advertisement%s\n");
984 p(ifs6_out_neighborsolicit, "\t%ju output neighbor solicitation%s\n");
985 p(ifs6_out_neighboradvert, "\t%ju output neighbor advertisement%s\n");
986 p(ifs6_out_redirect, "\t%ju output redirect%s\n");
987 p2(ifs6_out_mldquery, "\t%ju output MLD quer%s\n");
988 p(ifs6_out_mldreport, "\t%ju output MLD report%s\n");
989 p(ifs6_out_mlddone, "\t%ju output MLD done%s\n");
990
991 end:
992 close(s);
993 #undef p
994 }
995
996 /*
997 * Dump PIM statistics structure.
998 */
999 void
pim6_stats(u_long off,const char * name,int af1 __unused,int proto __unused)1000 pim6_stats(u_long off, const char *name, int af1 __unused, int proto __unused)
1001 {
1002 struct pim6stat pim6stat, zerostat;
1003 size_t len = sizeof pim6stat;
1004
1005 if (live) {
1006 if (zflag)
1007 memset(&zerostat, 0, len);
1008 if (sysctlbyname("net.inet6.pim.stats", &pim6stat, &len,
1009 zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
1010 if (errno != ENOENT)
1011 warn("sysctl: net.inet6.pim.stats");
1012 return;
1013 }
1014 } else {
1015 if (off == 0)
1016 return;
1017 kread(off, &pim6stat, len);
1018 }
1019
1020 printf("%s:\n", name);
1021
1022 #define p(f, m) if (pim6stat.f || sflag <= 1) \
1023 printf(m, (uintmax_t)pim6stat.f, plural(pim6stat.f))
1024 p(pim6s_rcv_total, "\t%ju message%s received\n");
1025 p(pim6s_rcv_tooshort, "\t%ju message%s received with too few bytes\n");
1026 p(pim6s_rcv_badsum, "\t%ju message%s received with bad checksum\n");
1027 p(pim6s_rcv_badversion, "\t%ju message%s received with bad version\n");
1028 p(pim6s_rcv_registers, "\t%ju register%s received\n");
1029 p(pim6s_rcv_badregisters, "\t%ju bad register%s received\n");
1030 p(pim6s_snd_registers, "\t%ju register%s sent\n");
1031 #undef p
1032 }
1033
1034 /*
1035 * Dump raw ip6 statistics structure.
1036 */
1037 void
rip6_stats(u_long off,const char * name,int af1 __unused,int proto __unused)1038 rip6_stats(u_long off, const char *name, int af1 __unused, int proto __unused)
1039 {
1040 struct rip6stat rip6stat, zerostat;
1041 u_quad_t delivered;
1042 size_t len;
1043
1044 len = sizeof(rip6stat);
1045 if (live) {
1046 if (zflag)
1047 memset(&zerostat, 0, len);
1048 if (sysctlbyname("net.inet6.ip6.rip6stats", &rip6stat, &len,
1049 zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
1050 if (errno != ENOENT)
1051 warn("sysctl: net.inet6.ip6.rip6stats");
1052 return;
1053 }
1054 } else
1055 kread_counters(off, &rip6stat, len);
1056
1057 printf("%s:\n", name);
1058
1059 #define p(f, m) if (rip6stat.f || sflag <= 1) \
1060 printf(m, (uintmax_t)rip6stat.f, plural(rip6stat.f))
1061 p(rip6s_ipackets, "\t%ju message%s received\n");
1062 p(rip6s_isum, "\t%ju checksum calculation%s on inbound\n");
1063 p(rip6s_badsum, "\t%ju message%s with bad checksum\n");
1064 p(rip6s_nosock, "\t%ju message%s dropped due to no socket\n");
1065 p(rip6s_nosockmcast,
1066 "\t%ju multicast message%s dropped due to no socket\n");
1067 p(rip6s_fullsock,
1068 "\t%ju message%s dropped due to full socket buffers\n");
1069 delivered = rip6stat.rip6s_ipackets -
1070 rip6stat.rip6s_badsum -
1071 rip6stat.rip6s_nosock -
1072 rip6stat.rip6s_nosockmcast -
1073 rip6stat.rip6s_fullsock;
1074 if (delivered || sflag <= 1)
1075 printf("\t%ju delivered\n", (uintmax_t)delivered);
1076 p(rip6s_opackets, "\t%ju datagram%s output\n");
1077 #undef p
1078 }
1079
1080 /*
1081 * Pretty print an Internet address (net address + port).
1082 * Take numeric_addr and numeric_port into consideration.
1083 */
1084 #define GETSERVBYPORT6(port, proto, ret)\
1085 {\
1086 if (strcmp((proto), "tcp6") == 0)\
1087 (ret) = getservbyport((int)(port), "tcp");\
1088 else if (strcmp((proto), "udp6") == 0)\
1089 (ret) = getservbyport((int)(port), "udp");\
1090 else\
1091 (ret) = getservbyport((int)(port), (proto));\
1092 };
1093
1094 void
inet6print(struct in6_addr * in6,int port,const char * proto,int numeric)1095 inet6print(struct in6_addr *in6, int port, const char *proto, int numeric)
1096 {
1097 struct servent *sp = 0;
1098 char line[80], *cp;
1099 int width;
1100
1101 sprintf(line, "%.*s.", Wflag ? 39 :
1102 (Aflag && !numeric) ? 12 : 16, inet6name(in6));
1103 cp = strchr(line, '\0');
1104 if (!numeric && port)
1105 GETSERVBYPORT6(port, proto, sp);
1106 if (sp || port == 0)
1107 sprintf(cp, "%.15s", sp ? sp->s_name : "*");
1108 else
1109 sprintf(cp, "%d", ntohs((u_short)port));
1110 width = Wflag ? 45 : Aflag ? 18 : 22;
1111 printf("%-*.*s ", width, width, line);
1112 }
1113
1114 /*
1115 * Construct an Internet address representation.
1116 * If the numeric_addr has been supplied, give
1117 * numeric value, otherwise try for symbolic name.
1118 */
1119
1120 char *
inet6name(struct in6_addr * in6p)1121 inet6name(struct in6_addr *in6p)
1122 {
1123 struct sockaddr_in6 sin6;
1124 char hbuf[NI_MAXHOST], *cp;
1125 static char line[50];
1126 static char domain[MAXHOSTNAMELEN];
1127 static int first = 1;
1128 int flags, error;
1129
1130 if (IN6_IS_ADDR_UNSPECIFIED(in6p)) {
1131 strcpy(line, "*");
1132 return (line);
1133 }
1134 if (first && !numeric_addr) {
1135 first = 0;
1136 if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
1137 (cp = strchr(domain, '.')))
1138 (void) strcpy(domain, cp + 1);
1139 else
1140 domain[0] = 0;
1141 }
1142 memset(&sin6, 0, sizeof(sin6));
1143 memcpy(&sin6.sin6_addr, in6p, sizeof(*in6p));
1144 sin6.sin6_family = AF_INET6;
1145 /* XXX: in6p.s6_addr[2] can contain scopeid. */
1146 in6_fillscopeid(&sin6);
1147 flags = (numeric_addr) ? NI_NUMERICHOST : 0;
1148 error = getnameinfo((struct sockaddr *)&sin6, sizeof(sin6), hbuf,
1149 sizeof(hbuf), NULL, 0, flags);
1150 if (error == 0) {
1151 if ((flags & NI_NUMERICHOST) == 0 &&
1152 (cp = strchr(hbuf, '.')) &&
1153 !strcmp(cp + 1, domain))
1154 *cp = 0;
1155 strcpy(line, hbuf);
1156 } else {
1157 /* XXX: this should not happen. */
1158 sprintf(line, "%s",
1159 inet_ntop(AF_INET6, (void *)&sin6.sin6_addr, ntop_buf,
1160 sizeof(ntop_buf)));
1161 }
1162 return (line);
1163 }
1164 #endif /*INET6*/
1165