xref: /openbsd-src/usr.bin/netstat/inet6.c (revision 850e275390052b330d93020bf619a739a3c277ac)
1 /*	$OpenBSD: inet6.c,v 1.36 2007/12/19 01:47:00 deraadt 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 #ifndef TCP6
47 #include <netinet/ip.h>
48 #include <netinet/ip_var.h>
49 #endif
50 #include <netinet6/ip6_var.h>
51 #include <netinet6/in6_var.h>
52 #include <netinet6/pim6_var.h>
53 #include <netinet6/raw_ip6.h>
54 
55 #include <arpa/inet.h>
56 #if 0
57 #include "gethostbyname2.h"
58 #endif
59 #include <netdb.h>
60 
61 #include <stdio.h>
62 #include <string.h>
63 #include <unistd.h>
64 #include <errno.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_exthdrtoolong,
417 	    "\t%llu packet%s whose headers are not continuous\n");
418 	p(ip6s_nogif, "\t%llu tunneling packet%s that can't find gif\n");
419 	p(ip6s_toomanyhdr,
420 	    "\t%llu packet%s discarded due to too many headers\n");
421 
422 	/* for debugging source address selection */
423 #define PRINT_SCOPESTAT(s,i) do {\
424 		switch(i) { /* XXX hardcoding in each case */\
425 		case 1:\
426 			p(s, "\t\t%llu node-local%s\n");\
427 			break;\
428 		case 2:\
429 			p(s, "\t\t%llu link-local%s\n");\
430 			break;\
431 		case 5:\
432 			p(s, "\t\t%llu site-local%s\n");\
433 			break;\
434 		case 14:\
435 			p(s, "\t\t%llu global%s\n");\
436 			break;\
437 		default:\
438 			printf("\t\t%llu addresses scope=%x\n",\
439 			    (unsigned long long)ip6stat.s, i);\
440 		}\
441 	} while(0);
442 
443 	p(ip6s_sources_none,
444 	    "\t%llu failure%s of source address selection\n");
445 	for (first = 1, i = 0; i < 16; i++) {
446 		if (ip6stat.ip6s_sources_sameif[i]) {
447 			if (first) {
448 				printf("\tsource addresses on an outgoing I/F\n");
449 				first = 0;
450 			}
451 			PRINT_SCOPESTAT(ip6s_sources_sameif[i], i);
452 		}
453 	}
454 	for (first = 1, i = 0; i < 16; i++) {
455 		if (ip6stat.ip6s_sources_otherif[i]) {
456 			if (first) {
457 				printf("\tsource addresses on a non-outgoing I/F\n");
458 				first = 0;
459 			}
460 			PRINT_SCOPESTAT(ip6s_sources_otherif[i], i);
461 		}
462 	}
463 	for (first = 1, i = 0; i < 16; i++) {
464 		if (ip6stat.ip6s_sources_samescope[i]) {
465 			if (first) {
466 				printf("\tsource addresses of same scope\n");
467 				first = 0;
468 			}
469 			PRINT_SCOPESTAT(ip6s_sources_samescope[i], i);
470 		}
471 	}
472 	for (first = 1, i = 0; i < 16; i++) {
473 		if (ip6stat.ip6s_sources_otherscope[i]) {
474 			if (first) {
475 				printf("\tsource addresses of a different scope\n");
476 				first = 0;
477 			}
478 			PRINT_SCOPESTAT(ip6s_sources_otherscope[i], i);
479 		}
480 	}
481 	for (first = 1, i = 0; i < 16; i++) {
482 		if (ip6stat.ip6s_sources_deprecated[i]) {
483 			if (first) {
484 				printf("\tdeprecated source addresses\n");
485 				first = 0;
486 			}
487 			PRINT_SCOPESTAT(ip6s_sources_deprecated[i], i);
488 		}
489 	}
490 
491 	p1(ip6s_forward_cachehit, "\t%llu forward cache hit\n");
492 	p1(ip6s_forward_cachemiss, "\t%llu forward cache miss\n");
493 #undef p
494 #undef p1
495 }
496 
497 /*
498  * Dump IPv6 per-interface statistics based on RFC 2465.
499  */
500 void
501 ip6_ifstats(char *ifname)
502 {
503 	struct in6_ifreq ifr;
504 	int s;
505 
506 #define	p(f, m) if (ifr.ifr_ifru.ifru_stat.f || sflag <= 1) \
507 	printf(m, (unsigned long long)ifr.ifr_ifru.ifru_stat.f, \
508 	    plural(ifr.ifr_ifru.ifru_stat.f))
509 #define	p_5(f, m) if (ifr.ifr_ifru.ifru_stat.f || sflag <= 1) \
510 	printf(m, (unsigned long long)ip6stat.f)
511 
512 	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
513 		perror("Warning: socket(AF_INET6)");
514 		return;
515 	}
516 
517 	strlcpy(ifr.ifr_name, ifname, sizeof ifr.ifr_name);
518 	printf("ip6 on %s:\n", ifr.ifr_name);
519 
520 	if (ioctl(s, SIOCGIFSTAT_IN6, &ifr) < 0) {
521 		perror("Warning: ioctl(SIOCGIFSTAT_IN6)");
522 		goto end;
523 	}
524 
525 	p(ifs6_in_receive, "\t%llu total input datagram%s\n");
526 	p(ifs6_in_hdrerr, "\t%llu datagram%s with invalid header received\n");
527 	p(ifs6_in_toobig, "\t%llu datagram%s exceeded MTU received\n");
528 	p(ifs6_in_noroute, "\t%llu datagram%s with no route received\n");
529 	p(ifs6_in_addrerr, "\t%llu datagram%s with invalid dst received\n");
530 	p(ifs6_in_truncated, "\t%llu truncated datagram%s received\n");
531 	p(ifs6_in_protounknown, "\t%llu datagram%s with unknown proto received\n");
532 	p(ifs6_in_discard, "\t%llu input datagram%s discarded\n");
533 	p(ifs6_in_deliver,
534 	    "\t%llu datagram%s delivered to an upper layer protocol\n");
535 	p(ifs6_out_forward, "\t%llu datagram%s forwarded to this interface\n");
536 	p(ifs6_out_request,
537 	    "\t%llu datagram%s sent from an upper layer protocol\n");
538 	p(ifs6_out_discard, "\t%llu total discarded output datagram%s\n");
539 	p(ifs6_out_fragok, "\t%llu output datagram%s fragmented\n");
540 	p(ifs6_out_fragfail, "\t%llu output datagram%s failed on fragment\n");
541 	p(ifs6_out_fragcreat, "\t%llu output datagram%s succeeded on fragment\n");
542 	p(ifs6_reass_reqd, "\t%llu incoming datagram%s fragmented\n");
543 	p(ifs6_reass_ok, "\t%llu datagram%s reassembled\n");
544 	p(ifs6_reass_fail, "\t%llu datagram%s failed on reassembling\n");
545 	p(ifs6_in_mcast, "\t%llu multicast datagram%s received\n");
546 	p(ifs6_out_mcast, "\t%llu multicast datagram%s sent\n");
547 
548   end:
549 	close(s);
550 
551 #undef p
552 #undef p_5
553 }
554 
555 static	char *icmp6names[] = {
556 	"#0",
557 	"unreach",
558 	"packet too big",
559 	"time exceed",
560 	"parameter problem",
561 	"#5",
562 	"#6",
563 	"#7",
564 	"#8",
565 	"#9",
566 	"#10",
567 	"#11",
568 	"#12",
569 	"#13",
570 	"#14",
571 	"#15",
572 	"#16",
573 	"#17",
574 	"#18",
575 	"#19",
576 	"#20",
577 	"#21",
578 	"#22",
579 	"#23",
580 	"#24",
581 	"#25",
582 	"#26",
583 	"#27",
584 	"#28",
585 	"#29",
586 	"#30",
587 	"#31",
588 	"#32",
589 	"#33",
590 	"#34",
591 	"#35",
592 	"#36",
593 	"#37",
594 	"#38",
595 	"#39",
596 	"#40",
597 	"#41",
598 	"#42",
599 	"#43",
600 	"#44",
601 	"#45",
602 	"#46",
603 	"#47",
604 	"#48",
605 	"#49",
606 	"#50",
607 	"#51",
608 	"#52",
609 	"#53",
610 	"#54",
611 	"#55",
612 	"#56",
613 	"#57",
614 	"#58",
615 	"#59",
616 	"#60",
617 	"#61",
618 	"#62",
619 	"#63",
620 	"#64",
621 	"#65",
622 	"#66",
623 	"#67",
624 	"#68",
625 	"#69",
626 	"#70",
627 	"#71",
628 	"#72",
629 	"#73",
630 	"#74",
631 	"#75",
632 	"#76",
633 	"#77",
634 	"#78",
635 	"#79",
636 	"#80",
637 	"#81",
638 	"#82",
639 	"#83",
640 	"#84",
641 	"#85",
642 	"#86",
643 	"#87",
644 	"#88",
645 	"#89",
646 	"#80",
647 	"#91",
648 	"#92",
649 	"#93",
650 	"#94",
651 	"#95",
652 	"#96",
653 	"#97",
654 	"#98",
655 	"#99",
656 	"#100",
657 	"#101",
658 	"#102",
659 	"#103",
660 	"#104",
661 	"#105",
662 	"#106",
663 	"#107",
664 	"#108",
665 	"#109",
666 	"#110",
667 	"#111",
668 	"#112",
669 	"#113",
670 	"#114",
671 	"#115",
672 	"#116",
673 	"#117",
674 	"#118",
675 	"#119",
676 	"#120",
677 	"#121",
678 	"#122",
679 	"#123",
680 	"#124",
681 	"#125",
682 	"#126",
683 	"#127",
684 	"echo",
685 	"echo reply",
686 	"multicast listener query",
687 	"multicast listener report",
688 	"multicast listener done",
689 	"router solicitation",
690 	"router advertisement",
691 	"neighbor solicitation",
692 	"neighbor advertisement",
693 	"redirect",
694 	"router renumbering",
695 	"node information request",
696 	"node information reply",
697 	"#141",
698 	"#142",
699 	"#143",
700 	"#144",
701 	"#145",
702 	"#146",
703 	"#147",
704 	"#148",
705 	"#149",
706 	"#150",
707 	"#151",
708 	"#152",
709 	"#153",
710 	"#154",
711 	"#155",
712 	"#156",
713 	"#157",
714 	"#158",
715 	"#159",
716 	"#160",
717 	"#161",
718 	"#162",
719 	"#163",
720 	"#164",
721 	"#165",
722 	"#166",
723 	"#167",
724 	"#168",
725 	"#169",
726 	"#170",
727 	"#171",
728 	"#172",
729 	"#173",
730 	"#174",
731 	"#175",
732 	"#176",
733 	"#177",
734 	"#178",
735 	"#179",
736 	"#180",
737 	"#181",
738 	"#182",
739 	"#183",
740 	"#184",
741 	"#185",
742 	"#186",
743 	"#187",
744 	"#188",
745 	"#189",
746 	"#180",
747 	"#191",
748 	"#192",
749 	"#193",
750 	"#194",
751 	"#195",
752 	"#196",
753 	"#197",
754 	"#198",
755 	"#199",
756 	"#200",
757 	"#201",
758 	"#202",
759 	"#203",
760 	"#204",
761 	"#205",
762 	"#206",
763 	"#207",
764 	"#208",
765 	"#209",
766 	"#210",
767 	"#211",
768 	"#212",
769 	"#213",
770 	"#214",
771 	"#215",
772 	"#216",
773 	"#217",
774 	"#218",
775 	"#219",
776 	"#220",
777 	"#221",
778 	"#222",
779 	"#223",
780 	"#224",
781 	"#225",
782 	"#226",
783 	"#227",
784 	"#228",
785 	"#229",
786 	"#230",
787 	"#231",
788 	"#232",
789 	"#233",
790 	"#234",
791 	"#235",
792 	"#236",
793 	"#237",
794 	"#238",
795 	"#239",
796 	"#240",
797 	"#241",
798 	"#242",
799 	"#243",
800 	"#244",
801 	"#245",
802 	"#246",
803 	"#247",
804 	"#248",
805 	"#249",
806 	"#250",
807 	"#251",
808 	"#252",
809 	"#253",
810 	"#254",
811 	"#255",
812 };
813 
814 /*
815  * Dump ICMPv6 statistics.
816  */
817 void
818 icmp6_stats(char *name)
819 {
820 	struct icmp6stat icmp6stat;
821 	int i, first;
822 	int mib[] = { CTL_NET, AF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_STATS };
823 	size_t len = sizeof(icmp6stat);
824 
825 	if (sysctl(mib, sizeof(mib) / sizeof(mib[0]),
826 	    &icmp6stat, &len, NULL, 0) == -1) {
827 		if (errno != ENOPROTOOPT)
828 			warn(name);
829 		return;
830 	}
831 
832 	printf("%s:\n", name);
833 #define	p(f, m) if (icmp6stat.f || sflag <= 1) \
834 	printf(m, (unsigned long long)icmp6stat.f, plural(icmp6stat.f))
835 #define p_5(f, m) if (icmp6stat.f || sflag <= 1) \
836 	printf(m, (unsigned long long)icmp6stat.f)
837 
838 	p(icp6s_error, "\t%llu call%s to icmp6_error\n");
839 	p(icp6s_canterror,
840 	    "\t%llu error%s not generated because old message was icmp6 or so\n");
841 	p(icp6s_toofreq,
842 	    "\t%llu error%s not generated because of rate limitation\n");
843 	for (first = 1, i = 0; i < 256; i++)
844 		if (icmp6stat.icp6s_outhist[i] != 0) {
845 			if (first) {
846 				printf("\tOutput packet histogram:\n");
847 				first = 0;
848 			}
849 			printf("\t\t%s: %llu\n", icmp6names[i],
850 			    (unsigned long long)icmp6stat.icp6s_outhist[i]);
851 		}
852 	p(icp6s_badcode, "\t%llu message%s with bad code fields\n");
853 	p(icp6s_tooshort, "\t%llu message%s < minimum length\n");
854 	p(icp6s_checksum, "\t%llu bad checksum%s\n");
855 	p(icp6s_badlen, "\t%llu message%s with bad length\n");
856 	for (first = 1, i = 0; i < ICMP6_MAXTYPE; i++)
857 		if (icmp6stat.icp6s_inhist[i] != 0) {
858 			if (first) {
859 				printf("\tInput packet histogram:\n");
860 				first = 0;
861 			}
862 			printf("\t\t%s: %llu\n", icmp6names[i],
863 			    (unsigned long long)icmp6stat.icp6s_inhist[i]);
864 		}
865 	printf("\tHistogram of error messages to be generated:\n");
866 	p_5(icp6s_odst_unreach_noroute, "\t\t%llu no route\n");
867 	p_5(icp6s_odst_unreach_admin, "\t\t%llu administratively prohibited\n");
868 	p_5(icp6s_odst_unreach_beyondscope, "\t\t%llu beyond scope\n");
869 	p_5(icp6s_odst_unreach_addr, "\t\t%llu address unreachable\n");
870 	p_5(icp6s_odst_unreach_noport, "\t\t%llu port unreachable\n");
871 	p_5(icp6s_opacket_too_big, "\t\t%llu packet too big\n");
872 	p_5(icp6s_otime_exceed_transit, "\t\t%llu time exceed transit\n");
873 	p_5(icp6s_otime_exceed_reassembly, "\t\t%llu time exceed reassembly\n");
874 	p_5(icp6s_oparamprob_header, "\t\t%llu erroneous header field\n");
875 	p_5(icp6s_oparamprob_nextheader, "\t\t%llu unrecognized next header\n");
876 	p_5(icp6s_oparamprob_option, "\t\t%llu unrecognized option\n");
877 	p_5(icp6s_oredirect, "\t\t%llu redirect\n");
878 	p_5(icp6s_ounknown, "\t\t%llu unknown\n");
879 
880 	p(icp6s_reflect, "\t%llu message response%s generated\n");
881 	p(icp6s_nd_toomanyopt, "\t%llu message%s with too many ND options\n");
882 	p(icp6s_nd_badopt, "\t%llu message%s with bad ND options\n");
883 	p(icp6s_badns, "\t%llu bad neighbor solicitation message%s\n");
884 	p(icp6s_badna, "\t%llu bad neighbor advertisement message%s\n");
885 	p(icp6s_badrs, "\t%llu bad router solicitation message%s\n");
886 	p(icp6s_badra, "\t%llu bad router advertisement message%s\n");
887 	p(icp6s_badredirect, "\t%llu bad redirect message%s\n");
888 	p(icp6s_pmtuchg, "\t%llu path MTU change%s\n");
889 #undef p
890 #undef p_5
891 }
892 
893 /*
894  * Dump ICMPv6 per-interface statistics based on RFC 2466.
895  */
896 void
897 icmp6_ifstats(char *ifname)
898 {
899 	struct in6_ifreq ifr;
900 	int s;
901 
902 #define	p(f, m) if (ifr.ifr_ifru.ifru_icmp6stat.f || sflag <= 1) \
903 	printf(m, (unsigned long long)ifr.ifr_ifru.ifru_icmp6stat.f, \
904 	    plural(ifr.ifr_ifru.ifru_icmp6stat.f))
905 
906 	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
907 		perror("Warning: socket(AF_INET6)");
908 		return;
909 	}
910 
911 	strlcpy(ifr.ifr_name, ifname, sizeof ifr.ifr_name);
912 	printf("icmp6 on %s:\n", ifr.ifr_name);
913 
914 	if (ioctl(s, SIOCGIFSTAT_ICMP6, &ifr) < 0) {
915 		perror("Warning: ioctl(SIOCGIFSTAT_ICMP6)");
916 		goto end;
917 	}
918 
919 	p(ifs6_in_msg, "\t%llu total input message%s\n");
920 	p(ifs6_in_error, "\t%llu total input error message%s\n");
921 	p(ifs6_in_dstunreach, "\t%llu input destination unreachable error%s\n");
922 	p(ifs6_in_adminprohib, "\t%llu input administratively prohibited error%s\n");
923 	p(ifs6_in_timeexceed, "\t%llu input time exceeded error%s\n");
924 	p(ifs6_in_paramprob, "\t%llu input parameter problem error%s\n");
925 	p(ifs6_in_pkttoobig, "\t%llu input packet too big error%s\n");
926 	p(ifs6_in_echo, "\t%llu input echo request%s\n");
927 	p(ifs6_in_echoreply, "\t%llu input echo reply%s\n");
928 	p(ifs6_in_routersolicit, "\t%llu input router solicitation%s\n");
929 	p(ifs6_in_routeradvert, "\t%llu input router advertisement%s\n");
930 	p(ifs6_in_neighborsolicit, "\t%llu input neighbor solicitation%s\n");
931 	p(ifs6_in_neighboradvert, "\t%llu input neighbor advertisement%s\n");
932 	p(ifs6_in_redirect, "\t%llu input redirect%s\n");
933 	p(ifs6_in_mldquery, "\t%llu input MLD query%s\n");
934 	p(ifs6_in_mldreport, "\t%llu input MLD report%s\n");
935 	p(ifs6_in_mlddone, "\t%llu input MLD done%s\n");
936 
937 	p(ifs6_out_msg, "\t%llu total output message%s\n");
938 	p(ifs6_out_error, "\t%llu total output error message%s\n");
939 	p(ifs6_out_dstunreach, "\t%llu output destination unreachable error%s\n");
940 	p(ifs6_out_adminprohib, "\t%llu output administratively prohibited error%s\n");
941 	p(ifs6_out_timeexceed, "\t%llu output time exceeded error%s\n");
942 	p(ifs6_out_paramprob, "\t%llu output parameter problem error%s\n");
943 	p(ifs6_out_pkttoobig, "\t%llu output packet too big error%s\n");
944 	p(ifs6_out_echo, "\t%llu output echo request%s\n");
945 	p(ifs6_out_echoreply, "\t%llu output echo reply%s\n");
946 	p(ifs6_out_routersolicit, "\t%llu output router solicitation%s\n");
947 	p(ifs6_out_routeradvert, "\t%llu output router advertisement%s\n");
948 	p(ifs6_out_neighborsolicit, "\t%llu output neighbor solicitation%s\n");
949 	p(ifs6_out_neighboradvert, "\t%llu output neighbor advertisement%s\n");
950 	p(ifs6_out_redirect, "\t%llu output redirect%s\n");
951 	p(ifs6_out_mldquery, "\t%llu output MLD query%s\n");
952 	p(ifs6_out_mldreport, "\t%llu output MLD report%s\n");
953 	p(ifs6_out_mlddone, "\t%llu output MLD done%s\n");
954 
955   end:
956 	close(s);
957 #undef p
958 }
959 
960 /*
961  * Dump PIM statistics structure.
962  */
963 void
964 pim6_stats(char *name)
965 {
966 	struct pim6stat pim6stat;
967 	int mib[] = { CTL_NET, AF_INET6, IPPROTO_PIM, PIM6CTL_STATS };
968 	size_t len = sizeof(pim6stat);
969 
970 	if (sysctl(mib, sizeof(mib) / sizeof(mib[0]),
971 	    &pim6stat, &len, NULL, 0) == -1) {
972 		if (errno != ENOPROTOOPT)
973 			warn(name);
974 		return;
975 	}
976 
977 	printf("%s:\n", name);
978 #define	p(f, m) if (pim6stat.f || sflag <= 1) \
979 	printf(m, (unsigned long long)pim6stat.f, plural(pim6stat.f))
980 
981 	p(pim6s_rcv_total, "\t%llu message%s received\n");
982 	p(pim6s_rcv_tooshort, "\t%llu message%s received with too few bytes\n");
983 	p(pim6s_rcv_badsum, "\t%llu message%s received with bad checksum\n");
984 	p(pim6s_rcv_badversion, "\t%llu message%s received with bad version\n");
985 	p(pim6s_rcv_registers, "\t%llu register%s received\n");
986 	p(pim6s_rcv_badregisters, "\t%llu bad register%s received\n");
987 	p(pim6s_snd_registers, "\t%llu register%s sent\n");
988 #undef p
989 }
990 
991 /*
992  * Dump raw ip6 statistics structure.
993  */
994 void
995 rip6_stats(char *name)
996 {
997 	struct rip6stat rip6stat;
998 	u_int64_t delivered;
999 	int mib[] = { CTL_NET, AF_INET6, IPPROTO_RAW, RIPV6CTL_STATS };
1000 	size_t len = sizeof(rip6stat);
1001 
1002 	if (sysctl(mib, sizeof(mib) / sizeof(mib[0]),
1003 	    &rip6stat, &len, NULL, 0) == -1) {
1004 		if (errno != ENOPROTOOPT)
1005 			warn(name);
1006 		return;
1007 	}
1008 
1009 	printf("%s:\n", name);
1010 
1011 #define	p(f, m) if (rip6stat.f || sflag <= 1) \
1012     printf(m, (unsigned long long)rip6stat.f, plural(rip6stat.f))
1013 	p(rip6s_ipackets, "\t%llu message%s received\n");
1014 	p(rip6s_isum, "\t%llu checksum calculation%s on inbound\n");
1015 	p(rip6s_badsum, "\t%llu message%s with bad checksum\n");
1016 	p(rip6s_nosock, "\t%llu message%s dropped due to no socket\n");
1017 	p(rip6s_nosockmcast,
1018 	    "\t%llu multicast message%s dropped due to no socket\n");
1019 	p(rip6s_fullsock,
1020 	    "\t%llu message%s dropped due to full socket buffers\n");
1021 	delivered = rip6stat.rip6s_ipackets -
1022 		    rip6stat.rip6s_badsum -
1023 		    rip6stat.rip6s_nosock -
1024 		    rip6stat.rip6s_nosockmcast -
1025 		    rip6stat.rip6s_fullsock;
1026 	if (delivered || sflag <= 1)
1027 		printf("\t%llu delivered\n", (unsigned long long)delivered);
1028 	p(rip6s_opackets, "\t%llu datagram%s output\n");
1029 #undef p
1030 }
1031 
1032 /*
1033  * Pretty print an Internet address (net address + port).
1034  * If the nflag was specified, use numbers instead of names.
1035  */
1036 
1037 void
1038 inet6print(struct in6_addr *in6, int port, char *proto)
1039 {
1040 
1041 #define GETSERVBYPORT6(port, proto, ret) do { \
1042 	if (strcmp((proto), "tcp6") == 0) \
1043 		(ret) = getservbyport((int)(port), "tcp"); \
1044 	else if (strcmp((proto), "udp6") == 0) \
1045 		(ret) = getservbyport((int)(port), "udp"); \
1046 	else \
1047 		(ret) = getservbyport((int)(port), (proto)); \
1048 	} while (0)
1049 
1050 	struct servent *sp = 0;
1051 	char line[80], *cp;
1052 	int width;
1053 	int len = sizeof line;
1054 
1055 	width = Aflag ? 12 : 16;
1056 	if (vflag && width < strlen(inet6name(in6)))
1057 		width = strlen(inet6name(in6));
1058 	snprintf(line, len, "%.*s.", width, inet6name(in6));
1059 	len -= strlen(line);
1060 	if (len <= 0)
1061 		goto bail;
1062 
1063 	cp = strchr(line, '\0');
1064 	if (!nflag && port)
1065 		GETSERVBYPORT6(port, proto, sp);
1066 	if (sp || port == 0)
1067 		snprintf(cp, len, "%.8s", sp ? sp->s_name : "*");
1068 	else
1069 		snprintf(cp, len, "%d", ntohs((u_short)port));
1070 	width = Aflag ? 18 : 22;
1071 	if (vflag && width < strlen(line))
1072 		width = strlen(line);
1073 bail:
1074 	printf(" %-*.*s", width, width, line);
1075 }
1076 
1077 /*
1078  * Construct an Internet address representation.
1079  * If the nflag has been supplied, give
1080  * numeric value, otherwise try for symbolic name.
1081  */
1082 
1083 char *
1084 inet6name(struct in6_addr *in6p)
1085 {
1086 	char *cp;
1087 	static char line[NI_MAXHOST];
1088 	struct hostent *hp;
1089 	static char domain[MAXHOSTNAMELEN];
1090 	static int first = 1;
1091 	char hbuf[NI_MAXHOST];
1092 	struct sockaddr_in6 sin6;
1093 	const int niflag = NI_NUMERICHOST;
1094 
1095 	if (first && !nflag) {
1096 		first = 0;
1097 		if (gethostname(domain, sizeof(domain)) == 0 &&
1098 		    (cp = strchr(domain, '.')))
1099 			(void) strlcpy(domain, cp + 1, sizeof domain);
1100 		else
1101 			domain[0] = '\0';
1102 	}
1103 	cp = 0;
1104 	if (!nflag && !IN6_IS_ADDR_UNSPECIFIED(in6p)) {
1105 		hp = gethostbyaddr((char *)in6p, sizeof(*in6p), AF_INET6);
1106 		if (hp) {
1107 			if ((cp = strchr(hp->h_name, '.')) &&
1108 			    !strcmp(cp + 1, domain))
1109 				*cp = 0;
1110 			cp = hp->h_name;
1111 		}
1112 	}
1113 	if (IN6_IS_ADDR_UNSPECIFIED(in6p))
1114 		strlcpy(line, "*", sizeof(line));
1115 	else if (cp)
1116 		strlcpy(line, cp, sizeof(line));
1117 	else {
1118 		memset(&sin6, 0, sizeof(sin6));
1119 		sin6.sin6_len = sizeof(sin6);
1120 		sin6.sin6_family = AF_INET6;
1121 		sin6.sin6_addr = *in6p;
1122 #ifdef __KAME__
1123 		if (IN6_IS_ADDR_LINKLOCAL(in6p) ||
1124 		    IN6_IS_ADDR_MC_LINKLOCAL(in6p) ||
1125 		    IN6_IS_ADDR_MC_INTFACELOCAL(in6p)) {
1126 			sin6.sin6_scope_id =
1127 			    ntohs(*(u_int16_t *)&in6p->s6_addr[2]);
1128 			sin6.sin6_addr.s6_addr[2] = 0;
1129 			sin6.sin6_addr.s6_addr[3] = 0;
1130 		}
1131 #endif
1132 		if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
1133 		    hbuf, sizeof(hbuf), NULL, 0, niflag) != 0)
1134 			strlcpy(hbuf, "?", sizeof hbuf);
1135 		strlcpy(line, hbuf, sizeof(line));
1136 	}
1137 	return (line);
1138 }
1139 
1140 #ifdef TCP6
1141 /*
1142  * Dump the contents of a TCP6 PCB.
1143  */
1144 void
1145 tcp6_dump(u_long pcbaddr)
1146 {
1147 	struct tcp6cb tcp6cb;
1148 	int i;
1149 
1150 	kread(pcbaddr, &tcp6cb, sizeof(tcp6cb));
1151 
1152 	printf("TCP Protocol Control Block at 0x%08lx:\n\n", pcbaddr);
1153 
1154 	printf("Timers:\n");
1155 	for (i = 0; i < TCP6T_NTIMERS; i++)
1156 		printf("\t%s: %u", tcp6timers[i], tcp6cb.t_timer[i]);
1157 	printf("\n\n");
1158 
1159 	if (tcp6cb.t_state < 0 || tcp6cb.t_state >= TCP6_NSTATES)
1160 		printf("State: %d", tcp6cb.t_state);
1161 	else
1162 		printf("State: %s", tcp6states[tcp6cb.t_state]);
1163 	printf(", flags 0x%x, in6pcb 0x%lx\n\n", tcp6cb.t_flags,
1164 	    (u_long)tcp6cb.t_in6pcb);
1165 
1166 	printf("rxtshift %d, rxtcur %d, dupacks %d\n", tcp6cb.t_rxtshift,
1167 	    tcp6cb.t_rxtcur, tcp6cb.t_dupacks);
1168 	printf("peermaxseg %u, maxseg %u, force %d\n\n", tcp6cb.t_peermaxseg,
1169 	    tcp6cb.t_maxseg, tcp6cb.t_force);
1170 
1171 	printf("snd_una %u, snd_nxt %u, snd_up %u\n",
1172 	    tcp6cb.snd_una, tcp6cb.snd_nxt, tcp6cb.snd_up);
1173 	printf("snd_wl1 %u, snd_wl2 %u, iss %u, snd_wnd %lu\n\n",
1174 	    tcp6cb.snd_wl1, tcp6cb.snd_wl2, tcp6cb.iss, tcp6cb.snd_wnd);
1175 
1176 	printf("rcv_wnd %lu, rcv_nxt %u, rcv_up %u, irs %u\n\n",
1177 	    tcp6cb.rcv_wnd, tcp6cb.rcv_nxt, tcp6cb.rcv_up, tcp6cb.irs);
1178 
1179 	printf("rcv_adv %u, snd_max %u, snd_cwnd %lu, snd_ssthresh %lu\n",
1180 	    tcp6cb.rcv_adv, tcp6cb.snd_max, tcp6cb.snd_cwnd, tcp6cb.snd_ssthresh);
1181 
1182 	printf("idle %d, rtt %d, rtseq %u, srtt %d, rttvar %d, rttmin %d, "
1183 	    "max_sndwnd %lu\n\n", tcp6cb.t_idle, tcp6cb.t_rtt, tcp6cb.t_rtseq,
1184 	    tcp6cb.t_srtt, tcp6cb.t_rttvar, tcp6cb.t_rttmin, tcp6cb.max_sndwnd);
1185 
1186 	printf("oobflags %d, iobc %d, softerror %d\n\n", tcp6cb.t_oobflags,
1187 	    tcp6cb.t_iobc, tcp6cb.t_softerror);
1188 
1189 	printf("snd_scale %d, rcv_scale %d, req_r_scale %d, req_s_scale %d\n",
1190 	    tcp6cb.snd_scale, tcp6cb.rcv_scale, tcp6cb.request_r_scale,
1191 	    tcp6cb.requested_s_scale);
1192 	printf("ts_recent %u, ts_regent_age %d, last_ack_sent %u\n",
1193 	    tcp6cb.ts_recent, tcp6cb.ts_recent_age, tcp6cb.last_ack_sent);
1194 }
1195 #endif
1196