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