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