inet6.c revision 281143
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 281143 2015-04-06 09:42:23Z glebius $");
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
74struct	socket sockb;
75
76char	*inet6name(struct in6_addr *);
77
78static char ntop_buf[INET6_ADDRSTRLEN];
79
80static	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
339static 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 */
361void
362ip6_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 */
621void
622ip6_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
696static	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 */
958void
959icmp6_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 */
1090void
1091icmp6_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
1189end:
1190	xo_close_instance("icmp6-interface-statistics");
1191	close(s);
1192#undef p
1193}
1194
1195/*
1196 * Dump PIM statistics structure.
1197 */
1198void
1199pim6_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 */
1246void
1247rip6_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
1312void
1313inet6print(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
1350char *
1351inet6name(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*/
1395