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