1 /* $OpenBSD: inet6.c,v 1.57 2024/02/05 23:16:39 bluhm 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/types.h>
33 #include <sys/socket.h>
34 #include <sys/socketvar.h>
35 #include <sys/ioctl.h>
36 #include <sys/protosw.h>
37 #include <sys/sysctl.h>
38
39 #include <net/route.h>
40 #include <net/if.h>
41 #include <netinet/in.h>
42 #include <netinet/ip6.h>
43 #include <netinet/icmp6.h>
44 #include <netinet/ip.h>
45 #include <netinet/ip_var.h>
46 #include <netinet6/ip6_var.h>
47 #include <netinet6/in6_var.h>
48 #include <netinet6/raw_ip6.h>
49 #include <netinet6/ip6_divert.h>
50
51 #include <arpa/inet.h>
52 #include <netdb.h>
53
54 #include <err.h>
55 #include <errno.h>
56 #include <stdio.h>
57 #include <string.h>
58 #include <unistd.h>
59 #include <limits.h>
60 #include "netstat.h"
61
62 char *inet6name(struct in6_addr *);
63
64 static char *ip6nh[] = {
65 "hop by hop",
66 "ICMP",
67 "IGMP",
68 "#3",
69 "IP",
70 "#5",
71 "TCP",
72 "#7",
73 "#8",
74 "#9",
75 "#10",
76 "#11",
77 "#12",
78 "#13",
79 "#14",
80 "#15",
81 "#16",
82 "UDP",
83 "#18",
84 "#19",
85 "#20",
86 "#21",
87 "IDP",
88 "#23",
89 "#24",
90 "#25",
91 "#26",
92 "#27",
93 "#28",
94 "TP",
95 "#30",
96 "#31",
97 "#32",
98 "#33",
99 "#34",
100 "#35",
101 "#36",
102 "#37",
103 "#38",
104 "#39",
105 "#40",
106 "IP6",
107 "#42",
108 "routing",
109 "fragment",
110 "#45",
111 "#46",
112 "#47",
113 "#48",
114 "#49",
115 "ESP",
116 "AH",
117 "#52",
118 "#53",
119 "#54",
120 "#55",
121 "#56",
122 "#57",
123 "ICMP6",
124 "no next header",
125 "destination option",
126 "#61",
127 "#62",
128 "#63",
129 "#64",
130 "#65",
131 "#66",
132 "#67",
133 "#68",
134 "#69",
135 "#70",
136 "#71",
137 "#72",
138 "#73",
139 "#74",
140 "#75",
141 "#76",
142 "#77",
143 "#78",
144 "#79",
145 "ISOIP",
146 "#81",
147 "#82",
148 "#83",
149 "#84",
150 "#85",
151 "#86",
152 "#87",
153 "#88",
154 "OSPF",
155 "#80",
156 "#91",
157 "#92",
158 "#93",
159 "#94",
160 "#95",
161 "#96",
162 "Ethernet",
163 "#98",
164 "#99",
165 "#100",
166 "#101",
167 "#102",
168 "#103",
169 "#104",
170 "#105",
171 "#106",
172 "#107",
173 "#108",
174 "#109",
175 "#110",
176 "#111",
177 "#112",
178 "#113",
179 "#114",
180 "#115",
181 "#116",
182 "#117",
183 "#118",
184 "#119",
185 "#120",
186 "#121",
187 "#122",
188 "#123",
189 "#124",
190 "#125",
191 "#126",
192 "#127",
193 "#128",
194 "#129",
195 "#130",
196 "#131",
197 "#132",
198 "#133",
199 "#134",
200 "#135",
201 "#136",
202 "#137",
203 "#138",
204 "#139",
205 "#140",
206 "#141",
207 "#142",
208 "#143",
209 "#144",
210 "#145",
211 "#146",
212 "#147",
213 "#148",
214 "#149",
215 "#150",
216 "#151",
217 "#152",
218 "#153",
219 "#154",
220 "#155",
221 "#156",
222 "#157",
223 "#158",
224 "#159",
225 "#160",
226 "#161",
227 "#162",
228 "#163",
229 "#164",
230 "#165",
231 "#166",
232 "#167",
233 "#168",
234 "#169",
235 "#170",
236 "#171",
237 "#172",
238 "#173",
239 "#174",
240 "#175",
241 "#176",
242 "#177",
243 "#178",
244 "#179",
245 "#180",
246 "#181",
247 "#182",
248 "#183",
249 "#184",
250 "#185",
251 "#186",
252 "#187",
253 "#188",
254 "#189",
255 "#180",
256 "#191",
257 "#192",
258 "#193",
259 "#194",
260 "#195",
261 "#196",
262 "#197",
263 "#198",
264 "#199",
265 "#200",
266 "#201",
267 "#202",
268 "#203",
269 "#204",
270 "#205",
271 "#206",
272 "#207",
273 "#208",
274 "#209",
275 "#210",
276 "#211",
277 "#212",
278 "#213",
279 "#214",
280 "#215",
281 "#216",
282 "#217",
283 "#218",
284 "#219",
285 "#220",
286 "#221",
287 "#222",
288 "#223",
289 "#224",
290 "#225",
291 "#226",
292 "#227",
293 "#228",
294 "#229",
295 "#230",
296 "#231",
297 "#232",
298 "#233",
299 "#234",
300 "#235",
301 "#236",
302 "#237",
303 "#238",
304 "#239",
305 "#240",
306 "#241",
307 "#242",
308 "#243",
309 "#244",
310 "#245",
311 "#246",
312 "#247",
313 "#248",
314 "#249",
315 "#250",
316 "#251",
317 "#252",
318 "#253",
319 "#254",
320 "#255",
321 };
322
323 /*
324 * Dump IP6 statistics structure.
325 */
326 void
ip6_stats(char * name)327 ip6_stats(char *name)
328 {
329 struct ip6stat ip6stat;
330 int first, i;
331 struct protoent *ep;
332 const char *n;
333 int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_STATS };
334 size_t len = sizeof(ip6stat);
335
336 if (sysctl(mib, sizeof(mib) / sizeof(mib[0]),
337 &ip6stat, &len, NULL, 0) == -1) {
338 if (errno != ENOPROTOOPT)
339 warn("%s", name);
340 return;
341 }
342
343 printf("%s:\n", name);
344 #define p(f, m) if (ip6stat.f || sflag <= 1) \
345 printf(m, (unsigned long long)ip6stat.f, plural(ip6stat.f))
346 #define p1(f, m) if (ip6stat.f || sflag <= 1) \
347 printf(m, (unsigned long long)ip6stat.f)
348
349 p(ip6s_total, "\t%llu total packet%s received\n");
350 p1(ip6s_toosmall, "\t%llu with size smaller than minimum\n");
351 p1(ip6s_tooshort, "\t%llu with data size < data length\n");
352 p1(ip6s_badoptions, "\t%llu with bad options\n");
353 p1(ip6s_badvers, "\t%llu with incorrect version number\n");
354 p(ip6s_fragments, "\t%llu fragment%s received\n");
355 p(ip6s_fragdropped,
356 "\t%llu fragment%s dropped (duplicates or out of space)\n");
357 p(ip6s_fragtimeout, "\t%llu fragment%s dropped after timeout\n");
358 p(ip6s_fragoverflow, "\t%llu fragment%s that exceeded limit\n");
359 p(ip6s_reassembled, "\t%llu packet%s reassembled ok\n");
360 p(ip6s_delivered, "\t%llu packet%s for this host\n");
361 p(ip6s_forward, "\t%llu packet%s forwarded\n");
362 p(ip6s_cantforward, "\t%llu packet%s not forwardable\n");
363 p(ip6s_redirectsent, "\t%llu redirect%s sent\n");
364 p(ip6s_localout, "\t%llu packet%s sent from this host\n");
365 p(ip6s_rawout, "\t%llu packet%s sent with fabricated ip header\n");
366 p(ip6s_odropped,
367 "\t%llu output packet%s dropped due to no bufs, etc.\n");
368 p(ip6s_noroute, "\t%llu output packet%s discarded due to no route\n");
369 p(ip6s_fragmented, "\t%llu output datagram%s fragmented\n");
370 p(ip6s_ofragments, "\t%llu fragment%s created\n");
371 p(ip6s_cantfrag, "\t%llu datagram%s that can't be fragmented\n");
372 p(ip6s_badscope, "\t%llu packet%s that violated scope rules\n");
373 p(ip6s_notmember, "\t%llu multicast packet%s which we don't join\n");
374 for (first = 1, i = 0; i < 256; i++)
375 if (ip6stat.ip6s_nxthist[i] != 0) {
376 if (first) {
377 printf("\tInput packet histogram:\n");
378 first = 0;
379 }
380 n = NULL;
381 if (ip6nh[i])
382 n = ip6nh[i];
383 else if ((ep = getprotobynumber(i)) != NULL)
384 n = ep->p_name;
385 if (n)
386 printf("\t\t%s: %llu\n", n,
387 (unsigned long long)ip6stat.ip6s_nxthist[i]);
388 else
389 printf("\t\t#%d: %llu\n", i,
390 (unsigned long long)ip6stat.ip6s_nxthist[i]);
391 }
392 printf("\tMbuf statistics:\n");
393 p(ip6s_m1, "\t\t%llu one mbuf%s\n");
394 for (first = 1, i = 0; i < 32; i++) {
395 char ifbuf[IFNAMSIZ];
396 if (ip6stat.ip6s_m2m[i] != 0) {
397 if (first) {
398 printf("\t\ttwo or more mbuf:\n");
399 first = 0;
400 }
401 printf("\t\t\t%s = %llu\n",
402 if_indextoname(i, ifbuf),
403 (unsigned long long)ip6stat.ip6s_m2m[i]);
404 }
405 }
406 p(ip6s_mext1, "\t\t%llu one ext mbuf%s\n");
407 p(ip6s_mext2m, "\t\t%llu two or more ext mbuf%s\n");
408 p(ip6s_nogif, "\t%llu tunneling packet%s that can't find gif\n");
409 p(ip6s_toomanyhdr,
410 "\t%llu packet%s discarded due to too many headers\n");
411
412 /* for debugging source address selection */
413 #define PRINT_SCOPESTAT(s,i) do {\
414 switch(i) { /* XXX hardcoding in each case */\
415 case 1:\
416 p(s, "\t\t%llu node-local%s\n");\
417 break;\
418 case 2:\
419 p(s, "\t\t%llu link-local%s\n");\
420 break;\
421 case 5:\
422 p(s, "\t\t%llu site-local%s\n");\
423 break;\
424 case 14:\
425 p(s, "\t\t%llu global%s\n");\
426 break;\
427 default:\
428 printf("\t\t%llu addresses scope=%x\n",\
429 (unsigned long long)ip6stat.s, i);\
430 }\
431 } while(0);
432
433 p(ip6s_sources_none,
434 "\t%llu failure%s of source address selection\n");
435 for (first = 1, i = 0; i < 16; i++) {
436 if (ip6stat.ip6s_sources_sameif[i]) {
437 if (first) {
438 printf("\tsource addresses on an outgoing I/F\n");
439 first = 0;
440 }
441 PRINT_SCOPESTAT(ip6s_sources_sameif[i], i);
442 }
443 }
444 for (first = 1, i = 0; i < 16; i++) {
445 if (ip6stat.ip6s_sources_otherif[i]) {
446 if (first) {
447 printf("\tsource addresses on a non-outgoing I/F\n");
448 first = 0;
449 }
450 PRINT_SCOPESTAT(ip6s_sources_otherif[i], i);
451 }
452 }
453 for (first = 1, i = 0; i < 16; i++) {
454 if (ip6stat.ip6s_sources_samescope[i]) {
455 if (first) {
456 printf("\tsource addresses of same scope\n");
457 first = 0;
458 }
459 PRINT_SCOPESTAT(ip6s_sources_samescope[i], i);
460 }
461 }
462 for (first = 1, i = 0; i < 16; i++) {
463 if (ip6stat.ip6s_sources_otherscope[i]) {
464 if (first) {
465 printf("\tsource addresses of a different scope\n");
466 first = 0;
467 }
468 PRINT_SCOPESTAT(ip6s_sources_otherscope[i], i);
469 }
470 }
471 for (first = 1, i = 0; i < 16; i++) {
472 if (ip6stat.ip6s_sources_deprecated[i]) {
473 if (first) {
474 printf("\tdeprecated source addresses\n");
475 first = 0;
476 }
477 PRINT_SCOPESTAT(ip6s_sources_deprecated[i], i);
478 }
479 }
480 p1(ip6s_rtcachehit, "\t%llu route cache hit\n");
481 p1(ip6s_rtcachemiss, "\t%llu route cache miss\n");
482 p(ip6s_wrongif, "\t%llu packet%s received on wrong interface\n");
483 p(ip6s_idropped,
484 "\t%llu input packet%s dropped due to no bufs, etc.\n");
485 #undef p
486 #undef p1
487 }
488
489 static char *icmp6names[] = {
490 "#0",
491 "unreach",
492 "packet too big",
493 "time exceed",
494 "parameter problem",
495 "#5",
496 "#6",
497 "#7",
498 "#8",
499 "#9",
500 "#10",
501 "#11",
502 "#12",
503 "#13",
504 "#14",
505 "#15",
506 "#16",
507 "#17",
508 "#18",
509 "#19",
510 "#20",
511 "#21",
512 "#22",
513 "#23",
514 "#24",
515 "#25",
516 "#26",
517 "#27",
518 "#28",
519 "#29",
520 "#30",
521 "#31",
522 "#32",
523 "#33",
524 "#34",
525 "#35",
526 "#36",
527 "#37",
528 "#38",
529 "#39",
530 "#40",
531 "#41",
532 "#42",
533 "#43",
534 "#44",
535 "#45",
536 "#46",
537 "#47",
538 "#48",
539 "#49",
540 "#50",
541 "#51",
542 "#52",
543 "#53",
544 "#54",
545 "#55",
546 "#56",
547 "#57",
548 "#58",
549 "#59",
550 "#60",
551 "#61",
552 "#62",
553 "#63",
554 "#64",
555 "#65",
556 "#66",
557 "#67",
558 "#68",
559 "#69",
560 "#70",
561 "#71",
562 "#72",
563 "#73",
564 "#74",
565 "#75",
566 "#76",
567 "#77",
568 "#78",
569 "#79",
570 "#80",
571 "#81",
572 "#82",
573 "#83",
574 "#84",
575 "#85",
576 "#86",
577 "#87",
578 "#88",
579 "#89",
580 "#80",
581 "#91",
582 "#92",
583 "#93",
584 "#94",
585 "#95",
586 "#96",
587 "#97",
588 "#98",
589 "#99",
590 "#100",
591 "#101",
592 "#102",
593 "#103",
594 "#104",
595 "#105",
596 "#106",
597 "#107",
598 "#108",
599 "#109",
600 "#110",
601 "#111",
602 "#112",
603 "#113",
604 "#114",
605 "#115",
606 "#116",
607 "#117",
608 "#118",
609 "#119",
610 "#120",
611 "#121",
612 "#122",
613 "#123",
614 "#124",
615 "#125",
616 "#126",
617 "#127",
618 "echo",
619 "echo reply",
620 "multicast listener query",
621 "multicast listener report",
622 "multicast listener done",
623 "router solicitation",
624 "router advertisement",
625 "neighbor solicitation",
626 "neighbor advertisement",
627 "redirect",
628 "router renumbering",
629 "node information request",
630 "node information reply",
631 "#141",
632 "#142",
633 "#143",
634 "#144",
635 "#145",
636 "#146",
637 "#147",
638 "#148",
639 "#149",
640 "#150",
641 "#151",
642 "#152",
643 "#153",
644 "#154",
645 "#155",
646 "#156",
647 "#157",
648 "#158",
649 "#159",
650 "#160",
651 "#161",
652 "#162",
653 "#163",
654 "#164",
655 "#165",
656 "#166",
657 "#167",
658 "#168",
659 "#169",
660 "#170",
661 "#171",
662 "#172",
663 "#173",
664 "#174",
665 "#175",
666 "#176",
667 "#177",
668 "#178",
669 "#179",
670 "#180",
671 "#181",
672 "#182",
673 "#183",
674 "#184",
675 "#185",
676 "#186",
677 "#187",
678 "#188",
679 "#189",
680 "#180",
681 "#191",
682 "#192",
683 "#193",
684 "#194",
685 "#195",
686 "#196",
687 "#197",
688 "#198",
689 "#199",
690 "#200",
691 "#201",
692 "#202",
693 "#203",
694 "#204",
695 "#205",
696 "#206",
697 "#207",
698 "#208",
699 "#209",
700 "#210",
701 "#211",
702 "#212",
703 "#213",
704 "#214",
705 "#215",
706 "#216",
707 "#217",
708 "#218",
709 "#219",
710 "#220",
711 "#221",
712 "#222",
713 "#223",
714 "#224",
715 "#225",
716 "#226",
717 "#227",
718 "#228",
719 "#229",
720 "#230",
721 "#231",
722 "#232",
723 "#233",
724 "#234",
725 "#235",
726 "#236",
727 "#237",
728 "#238",
729 "#239",
730 "#240",
731 "#241",
732 "#242",
733 "#243",
734 "#244",
735 "#245",
736 "#246",
737 "#247",
738 "#248",
739 "#249",
740 "#250",
741 "#251",
742 "#252",
743 "#253",
744 "#254",
745 "#255",
746 };
747
748 /*
749 * Dump ICMPv6 statistics.
750 */
751 void
icmp6_stats(char * name)752 icmp6_stats(char *name)
753 {
754 struct icmp6stat icmp6stat;
755 int i, first;
756 int mib[] = { CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_STATS };
757 size_t len = sizeof(icmp6stat);
758
759 if (sysctl(mib, sizeof(mib) / sizeof(mib[0]),
760 &icmp6stat, &len, NULL, 0) == -1) {
761 if (errno != ENOPROTOOPT)
762 warn("%s", name);
763 return;
764 }
765
766 printf("%s:\n", name);
767 #define p(f, m) if (icmp6stat.f || sflag <= 1) \
768 printf(m, (unsigned long long)icmp6stat.f, plural(icmp6stat.f))
769 #define p_5(f, m) if (icmp6stat.f || sflag <= 1) \
770 printf(m, (unsigned long long)icmp6stat.f)
771
772 p(icp6s_error, "\t%llu call%s to icmp6_error\n");
773 p(icp6s_canterror,
774 "\t%llu error%s not generated because old message was icmp6 or so\n");
775 p(icp6s_toofreq,
776 "\t%llu error%s not generated because of rate limitation\n");
777 for (first = 1, i = 0; i < 256; i++)
778 if (icmp6stat.icp6s_outhist[i] != 0) {
779 if (first) {
780 printf("\tOutput packet histogram:\n");
781 first = 0;
782 }
783 printf("\t\t%s: %llu\n", icmp6names[i],
784 (unsigned long long)icmp6stat.icp6s_outhist[i]);
785 }
786 p(icp6s_badcode, "\t%llu message%s with bad code fields\n");
787 p(icp6s_tooshort, "\t%llu message%s < minimum length\n");
788 p(icp6s_checksum, "\t%llu bad checksum%s\n");
789 p(icp6s_badlen, "\t%llu message%s with bad length\n");
790 for (first = 1, i = 0; i < ICMP6_MAXTYPE; i++)
791 if (icmp6stat.icp6s_inhist[i] != 0) {
792 if (first) {
793 printf("\tInput packet histogram:\n");
794 first = 0;
795 }
796 printf("\t\t%s: %llu\n", icmp6names[i],
797 (unsigned long long)icmp6stat.icp6s_inhist[i]);
798 }
799 printf("\tHistogram of error messages to be generated:\n");
800 p_5(icp6s_odst_unreach_noroute, "\t\t%llu no route\n");
801 p_5(icp6s_odst_unreach_admin, "\t\t%llu administratively prohibited\n");
802 p_5(icp6s_odst_unreach_beyondscope, "\t\t%llu beyond scope\n");
803 p_5(icp6s_odst_unreach_addr, "\t\t%llu address unreachable\n");
804 p_5(icp6s_odst_unreach_noport, "\t\t%llu port unreachable\n");
805 p_5(icp6s_opacket_too_big, "\t\t%llu packet too big\n");
806 p_5(icp6s_otime_exceed_transit, "\t\t%llu time exceed transit\n");
807 p_5(icp6s_otime_exceed_reassembly, "\t\t%llu time exceed reassembly\n");
808 p_5(icp6s_oparamprob_header, "\t\t%llu erroneous header field\n");
809 p_5(icp6s_oparamprob_nextheader, "\t\t%llu unrecognized next header\n");
810 p_5(icp6s_oparamprob_option, "\t\t%llu unrecognized option\n");
811 p_5(icp6s_oredirect, "\t\t%llu redirect\n");
812 p_5(icp6s_ounknown, "\t\t%llu unknown\n");
813
814 p(icp6s_reflect, "\t%llu message response%s generated\n");
815 p(icp6s_nd_toomanyopt, "\t%llu message%s with too many ND options\n");
816 p(icp6s_nd_badopt, "\t%llu message%s with bad ND options\n");
817 p(icp6s_badns, "\t%llu bad neighbor solicitation message%s\n");
818 p(icp6s_badna, "\t%llu bad neighbor advertisement message%s\n");
819 p(icp6s_badrs, "\t%llu bad router solicitation message%s\n");
820 p(icp6s_badra, "\t%llu bad router advertisement message%s\n");
821 p(icp6s_badredirect, "\t%llu bad redirect message%s\n");
822 p(icp6s_pmtuchg, "\t%llu path MTU change%s\n");
823 #undef p
824 #undef p_5
825 }
826
827 /*
828 * Dump raw ip6 statistics structure.
829 */
830 void
rip6_stats(char * name)831 rip6_stats(char *name)
832 {
833 struct rip6stat rip6stat;
834 u_int64_t delivered;
835 int mib[] = { CTL_NET, PF_INET6, IPPROTO_RAW, RIPV6CTL_STATS };
836 size_t len = sizeof(rip6stat);
837
838 if (sysctl(mib, sizeof(mib) / sizeof(mib[0]),
839 &rip6stat, &len, NULL, 0) == -1) {
840 if (errno != ENOPROTOOPT)
841 warn("%s", name);
842 return;
843 }
844
845 printf("%s:\n", name);
846
847 #define p(f, m) if (rip6stat.f || sflag <= 1) \
848 printf(m, (unsigned long long)rip6stat.f, plural(rip6stat.f))
849 p(rip6s_ipackets, "\t%llu message%s received\n");
850 p(rip6s_isum, "\t%llu checksum calculation%s on inbound\n");
851 p(rip6s_badsum, "\t%llu message%s with bad checksum\n");
852 p(rip6s_nosock, "\t%llu message%s dropped due to no socket\n");
853 p(rip6s_nosockmcast,
854 "\t%llu multicast message%s dropped due to no socket\n");
855 p(rip6s_fullsock,
856 "\t%llu message%s dropped due to full socket buffers\n");
857 delivered = rip6stat.rip6s_ipackets -
858 rip6stat.rip6s_nosock -
859 rip6stat.rip6s_nosockmcast -
860 rip6stat.rip6s_fullsock;
861 if (delivered || sflag <= 1)
862 printf("\t%llu delivered\n", (unsigned long long)delivered);
863 p(rip6s_opackets, "\t%llu datagram%s output\n");
864 #undef p
865 }
866
867 /*
868 * Dump divert6 statistics structure.
869 */
870 void
div6_stats(char * name)871 div6_stats(char *name)
872 {
873 struct div6stat div6stat;
874 int mib[] = { CTL_NET, PF_INET6, IPPROTO_DIVERT, DIVERT6CTL_STATS };
875 size_t len = sizeof(div6stat);
876
877 if (sysctl(mib, sizeof(mib) / sizeof(mib[0]),
878 &div6stat, &len, NULL, 0) == -1) {
879 if (errno != ENOPROTOOPT)
880 warn("%s", name);
881 return;
882 }
883
884 printf("%s:\n", name);
885 #define p(f, m) if (div6stat.f || sflag <= 1) \
886 printf(m, div6stat.f, plural(div6stat.f))
887 #define p1(f, m) if (div6stat.f || sflag <= 1) \
888 printf(m, div6stat.f)
889 p(divs_ipackets, "\t%lu total packet%s received\n");
890 p1(divs_noport, "\t%lu dropped due to no socket\n");
891 p1(divs_fullsock, "\t%lu dropped due to full socket buffers\n");
892 p(divs_opackets, "\t%lu packet%s output\n");
893 p1(divs_errors, "\t%lu errors\n");
894 #undef p
895 #undef p1
896 }
897
898 /*
899 * Pretty print an Internet address (net address + port).
900 * If the nflag was specified, use numbers instead of names.
901 */
902
903 void
inet6print(struct in6_addr * in6,int port,const char * proto)904 inet6print(struct in6_addr *in6, int port, const char *proto)
905 {
906
907 #define GETSERVBYPORT6(port, proto, ret) do { \
908 if (strcmp((proto), "tcp6") == 0) \
909 (ret) = getservbyport((int)(port), "tcp"); \
910 else if (strcmp((proto), "udp6") == 0) \
911 (ret) = getservbyport((int)(port), "udp"); \
912 else \
913 (ret) = getservbyport((int)(port), (proto)); \
914 } while (0)
915
916 struct servent *sp = 0;
917 char line[80], *cp;
918 int width;
919 int len = sizeof line;
920
921 width = Aflag ? 12 : 16;
922 if (vflag && width < strlen(inet6name(in6)))
923 width = strlen(inet6name(in6));
924 snprintf(line, len, "%.*s.", width, inet6name(in6));
925 len -= strlen(line);
926 if (len <= 0)
927 goto bail;
928
929 cp = strchr(line, '\0');
930 if (!nflag && port)
931 GETSERVBYPORT6(port, proto, sp);
932 if (sp || port == 0)
933 snprintf(cp, len, "%.8s", sp ? sp->s_name : "*");
934 else
935 snprintf(cp, len, "%d", ntohs((u_short)port));
936 width = Aflag ? 18 : 22;
937 if (vflag && width < strlen(line))
938 width = strlen(line);
939 bail:
940 printf(" %-*.*s", width, width, line);
941 }
942
943 /*
944 * Construct an Internet address representation.
945 * If the nflag has been supplied, give
946 * numeric value, otherwise try for symbolic name.
947 */
948
949 char *
inet6name(struct in6_addr * in6p)950 inet6name(struct in6_addr *in6p)
951 {
952 char *cp;
953 static char line[NI_MAXHOST];
954 struct hostent *hp;
955 static char domain[HOST_NAME_MAX+1];
956 static int first = 1;
957 char hbuf[NI_MAXHOST];
958 struct sockaddr_in6 sin6;
959 const int niflag = NI_NUMERICHOST;
960
961 if (first && !nflag) {
962 first = 0;
963 if (gethostname(domain, sizeof(domain)) == 0 &&
964 (cp = strchr(domain, '.')))
965 (void) strlcpy(domain, cp + 1, sizeof domain);
966 else
967 domain[0] = '\0';
968 }
969 cp = 0;
970 if (!nflag && !IN6_IS_ADDR_UNSPECIFIED(in6p)) {
971 hp = gethostbyaddr((char *)in6p, sizeof(*in6p), AF_INET6);
972 if (hp) {
973 if ((cp = strchr(hp->h_name, '.')) &&
974 !strcmp(cp + 1, domain))
975 *cp = 0;
976 cp = hp->h_name;
977 }
978 }
979 if (IN6_IS_ADDR_UNSPECIFIED(in6p))
980 strlcpy(line, "*", sizeof(line));
981 else if (cp)
982 strlcpy(line, cp, sizeof(line));
983 else {
984 memset(&sin6, 0, sizeof(sin6));
985 sin6.sin6_family = AF_INET6;
986 sin6.sin6_addr = *in6p;
987 #ifdef __KAME__
988 if (IN6_IS_ADDR_LINKLOCAL(in6p) ||
989 IN6_IS_ADDR_MC_LINKLOCAL(in6p) ||
990 IN6_IS_ADDR_MC_INTFACELOCAL(in6p)) {
991 sin6.sin6_scope_id =
992 ntohs(*(u_int16_t *)&in6p->s6_addr[2]);
993 sin6.sin6_addr.s6_addr[2] = 0;
994 sin6.sin6_addr.s6_addr[3] = 0;
995 }
996 #endif
997 if (getnameinfo((struct sockaddr *)&sin6, sizeof(sin6),
998 hbuf, sizeof(hbuf), NULL, 0, niflag) != 0)
999 strlcpy(hbuf, "?", sizeof hbuf);
1000 strlcpy(line, hbuf, sizeof(line));
1001 }
1002 return (line);
1003 }
1004