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