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