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	xo_close_container("errors");
1067	p(icp6s_pmtuchg, "\t{:path-mtu-changes/%ju} {N:/path MTU change%s}\n");
1068#undef p
1069#undef p_5
1070	xo_close_container(name);
1071}
1072
1073/*
1074 * Dump ICMPv6 per-interface statistics based on RFC 2466.
1075 */
1076void
1077icmp6_ifstats(char *ifname)
1078{
1079	struct in6_ifreq ifr;
1080	int s;
1081
1082#define	p(f, m) if (ifr.ifr_ifru.ifru_icmp6stat.f || sflag <= 1)	\
1083	xo_emit(m, (uintmax_t)ifr.ifr_ifru.ifru_icmp6stat.f,		\
1084	    plural(ifr.ifr_ifru.ifru_icmp6stat.f))
1085#define	p2(f, m) if (ifr.ifr_ifru.ifru_icmp6stat.f || sflag <= 1)	\
1086	xo_emit(m, (uintmax_t)ifr.ifr_ifru.ifru_icmp6stat.f,		\
1087	    pluralies(ifr.ifr_ifru.ifru_icmp6stat.f))
1088
1089	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
1090		xo_warn("Warning: socket(AF_INET6)");
1091		return;
1092	}
1093
1094	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1095	if (ioctl(s, SIOCGIFSTAT_ICMP6, (char *)&ifr) < 0) {
1096		if (errno != EPFNOSUPPORT)
1097			xo_warn("Warning: ioctl(SIOCGIFSTAT_ICMP6)");
1098		goto end;
1099	}
1100
1101	xo_emit("{T:/icmp6 on %s}:\n", ifr.ifr_name);
1102
1103	xo_open_instance("icmp6-interface-statistics");
1104	xo_emit("{ke:name/%s}", ifr.ifr_name);
1105	p(ifs6_in_msg, "\t{:received-packets/%ju} "
1106	    "{N:/total input message%s}\n");
1107	p(ifs6_in_error, "\t{:received-errors/%ju} "
1108	    "{N:/total input error message%s}\n");
1109	p(ifs6_in_dstunreach, "\t{:received-destination-unreachable/%ju} "
1110	    "{N:/input destination unreachable error%s}\n");
1111	p(ifs6_in_adminprohib, "\t{:received-admin-prohibited/%ju} "
1112	    "{N:/input administratively prohibited error%s}\n");
1113	p(ifs6_in_timeexceed, "\t{:received-time-exceeded/%ju} "
1114	    "{N:/input time exceeded error%s}\n");
1115	p(ifs6_in_paramprob, "\t{:received-bad-parameter/%ju} "
1116	    "{N:/input parameter problem error%s}\n");
1117	p(ifs6_in_pkttoobig, "\t{:received-packet-too-big/%ju} "
1118	    "{N:/input packet too big error%s}\n");
1119	p(ifs6_in_echo, "\t{:received-echo-requests/%ju} "
1120	    "{N:/input echo request%s}\n");
1121	p2(ifs6_in_echoreply, "\t{:received-echo-replies/%ju} "
1122	    "{N:/input echo repl%s}\n");
1123	p(ifs6_in_routersolicit, "\t{:received-router-solicitation/%ju} "
1124	    "{N:/input router solicitation%s}\n");
1125	p(ifs6_in_routeradvert, "\t{:received-router-advertisement/%ju} "
1126	    "{N:/input router advertisement%s}\n");
1127	p(ifs6_in_neighborsolicit, "\t{:received-neighbor-solicitation/%ju} "
1128	    "{N:/input neighbor solicitation%s}\n");
1129	p(ifs6_in_neighboradvert, "\t{:received-neighbor-advertisement/%ju} "
1130	    "{N:/input neighbor advertisement%s}\n");
1131	p(ifs6_in_redirect, "\t{received-redirects/%ju} "
1132	    "{N:/input redirect%s}\n");
1133	p2(ifs6_in_mldquery, "\t{:received-mld-queries/%ju} "
1134	    "{N:/input MLD quer%s}\n");
1135	p(ifs6_in_mldreport, "\t{:received-mld-reports/%ju} "
1136	    "{N:/input MLD report%s}\n");
1137	p(ifs6_in_mlddone, "\t{:received-mld-done/%ju} "
1138	    "{N:/input MLD done%s}\n");
1139
1140	p(ifs6_out_msg, "\t{:sent-packets/%ju} "
1141	    "{N:/total output message%s}\n");
1142	p(ifs6_out_error, "\t{:sent-errors/%ju} "
1143	    "{N:/total output error message%s}\n");
1144	p(ifs6_out_dstunreach, "\t{:sent-destination-unreachable/%ju} "
1145	    "{N:/output destination unreachable error%s}\n");
1146	p(ifs6_out_adminprohib, "\t{:sent-admin-prohibited/%ju} "
1147	    "{N:/output administratively prohibited error%s}\n");
1148	p(ifs6_out_timeexceed, "\t{:sent-time-exceeded/%ju} "
1149	    "{N:/output time exceeded error%s}\n");
1150	p(ifs6_out_paramprob, "\t{:sent-bad-parameter/%ju} "
1151	    "{N:/output parameter problem error%s}\n");
1152	p(ifs6_out_pkttoobig, "\t{:sent-packet-too-big/%ju} "
1153	    "{N:/output packet too big error%s}\n");
1154	p(ifs6_out_echo, "\t{:sent-echo-requests/%ju} "
1155	    "{N:/output echo request%s}\n");
1156	p2(ifs6_out_echoreply, "\t{:sent-echo-replies/%ju} "
1157	    "{N:/output echo repl%s}\n");
1158	p(ifs6_out_routersolicit, "\t{:sent-router-solicitation/%ju} "
1159	    "{N:/output router solicitation%s}\n");
1160	p(ifs6_out_routeradvert, "\t{:sent-router-advertisement/%ju} "
1161	    "{N:/output router advertisement%s}\n");
1162	p(ifs6_out_neighborsolicit, "\t{:sent-neighbor-solicitation/%ju} "
1163	    "{N:/output neighbor solicitation%s}\n");
1164	p(ifs6_out_neighboradvert, "\t{:sent-neighbor-advertisement/%ju} "
1165	    "{N:/output neighbor advertisement%s}\n");
1166	p(ifs6_out_redirect, "\t{:sent-redirects/%ju} "
1167	    "{N:/output redirect%s}\n");
1168	p2(ifs6_out_mldquery, "\t{:sent-mld-queries/%ju} "
1169	    "{N:/output MLD quer%s}\n");
1170	p(ifs6_out_mldreport, "\t{:sent-mld-reports/%ju} "
1171	    "{N:/output MLD report%s}\n");
1172	p(ifs6_out_mlddone, "\t{:sent-mld-dones/%ju} "
1173	    "{N:/output MLD done%s}\n");
1174
1175end:
1176	xo_close_instance("icmp6-interface-statistics");
1177	close(s);
1178#undef p
1179}
1180
1181/*
1182 * Dump PIM statistics structure.
1183 */
1184void
1185pim6_stats(u_long off, const char *name, int af1 __unused, int proto __unused)
1186{
1187	struct pim6stat pim6stat;
1188
1189	if (fetch_stats("net.inet6.pim.stats", off, &pim6stat,
1190	    sizeof(pim6stat), kread) != 0)
1191		return;
1192
1193	xo_emit("{T:/%s}:\n", name);
1194	xo_open_container(name);
1195
1196#define	p(f, m) if (pim6stat.f || sflag <= 1) \
1197	xo_emit(m, (uintmax_t)pim6stat.f, plural(pim6stat.f))
1198
1199	p(pim6s_rcv_total, "\t{:received-packets/%ju} "
1200	    "{N:/message%s received}\n");
1201	p(pim6s_rcv_tooshort, "\t{:dropped-too-short/%ju} "
1202	    "{N:/message%s received with too few bytes}\n");
1203	p(pim6s_rcv_badsum, "\t{:dropped-bad-checksum/%ju} "
1204	    "{N:/message%s received with bad checksum}\n");
1205	p(pim6s_rcv_badversion, "\t{:dropped-bad-version/%ju} "
1206	    "{N:/message%s received with bad version}\n");
1207	p(pim6s_rcv_registers, "\t{:received-registers/%ju} "
1208	    "{N:/register%s received}\n");
1209	p(pim6s_rcv_badregisters, "\t{:received-bad-registers/%ju} "
1210	    "{N:/bad register%s received}\n");
1211	p(pim6s_snd_registers, "\t{:sent-registers/%ju} "
1212	    "{N:/register%s sent}\n");
1213#undef p
1214	xo_close_container(name);
1215}
1216
1217/*
1218 * Dump raw ip6 statistics structure.
1219 */
1220void
1221rip6_stats(u_long off, const char *name, int af1 __unused, int proto __unused)
1222{
1223	struct rip6stat rip6stat;
1224	u_quad_t delivered;
1225
1226	if (fetch_stats("net.inet6.ip6.rip6stats", off, &rip6stat,
1227	    sizeof(rip6stat), kread_counters) != 0)
1228		return;
1229
1230	xo_emit("{T:/%s}:\n", name);
1231	xo_open_container(name);
1232
1233#define	p(f, m) if (rip6stat.f || sflag <= 1) \
1234	xo_emit(m, (uintmax_t)rip6stat.f, plural(rip6stat.f))
1235
1236	p(rip6s_ipackets, "\t{:received-packets/%ju} "
1237	    "{N:/message%s received}\n");
1238	p(rip6s_isum, "\t{:input-checksum-computation/%ju} "
1239	    "{N:/checksum calculation%s on inbound}\n");
1240	p(rip6s_badsum, "\t{:received-bad-checksum/%ju} "
1241	    "{N:/message%s with bad checksum}\n");
1242	p(rip6s_nosock, "\t{:dropped-no-socket/%ju} "
1243	    "{N:/message%s dropped due to no socket}\n");
1244	p(rip6s_nosockmcast, "\t{:dropped-multicast-no-socket/%ju} "
1245	    "{N:/multicast message%s dropped due to no socket}\n");
1246	p(rip6s_fullsock, "\t{:dropped-full-socket-buffer/%ju} "
1247	    "{N:/message%s dropped due to full socket buffers}\n");
1248	delivered = rip6stat.rip6s_ipackets -
1249		    rip6stat.rip6s_badsum -
1250		    rip6stat.rip6s_nosock -
1251		    rip6stat.rip6s_nosockmcast -
1252		    rip6stat.rip6s_fullsock;
1253	if (delivered || sflag <= 1)
1254		xo_emit("\t{:delivered-packets/%ju} {N:/delivered}\n",
1255		    (uintmax_t)delivered);
1256	p(rip6s_opackets, "\t{:sent-packets/%ju} "
1257	    "{N:/datagram%s output}\n");
1258#undef p
1259	xo_close_container(name);
1260}
1261
1262/*
1263 * Pretty print an Internet address (net address + port).
1264 * Take numeric_addr and numeric_port into consideration.
1265 */
1266#define	GETSERVBYPORT6(port, proto, ret)\
1267{\
1268	if (strcmp((proto), "tcp6") == 0)\
1269		(ret) = getservbyport((int)(port), "tcp");\
1270	else if (strcmp((proto), "udp6") == 0)\
1271		(ret) = getservbyport((int)(port), "udp");\
1272	else\
1273		(ret) = getservbyport((int)(port), (proto));\
1274};
1275
1276void
1277inet6print(const char *container, struct in6_addr *in6, int port,
1278    const char *proto, int numeric)
1279{
1280	struct servent *sp = 0;
1281	char line[80], *cp;
1282	int width;
1283	size_t alen, plen;
1284
1285	if (container)
1286		xo_open_container(container);
1287
1288	snprintf(line, sizeof(line), "%.*s.",
1289	    Wflag ? 39 : (Aflag && !numeric) ? 12 : 16,
1290	    inet6name(in6));
1291	alen = strlen(line);
1292	cp = line + alen;
1293	if (!numeric && port)
1294		GETSERVBYPORT6(port, proto, sp);
1295	if (sp || port == 0)
1296		snprintf(cp, sizeof(line) - alen,
1297		    "%.15s", sp ? sp->s_name : "*");
1298	else
1299		snprintf(cp, sizeof(line) - alen,
1300		    "%d", ntohs((u_short)port));
1301	width = Wflag ? 45 : Aflag ? 18 : 22;
1302
1303	xo_emit("{d:target/%-*.*s} ", width, width, line);
1304
1305	plen = strlen(cp);
1306	alen--;
1307	xo_emit("{e:address/%*.*s}{e:port/%*.*s}", alen, alen, line, plen,
1308	    plen, cp);
1309
1310	if (container)
1311		xo_close_container(container);
1312}
1313
1314/*
1315 * Construct an Internet address representation.
1316 * If the numeric_addr has been supplied, give
1317 * numeric value, otherwise try for symbolic name.
1318 */
1319
1320char *
1321inet6name(struct in6_addr *ia6)
1322{
1323	struct sockaddr_in6 sin6;
1324	char hbuf[NI_MAXHOST], *cp;
1325	static char line[NI_MAXHOST];
1326	static char domain[MAXHOSTNAMELEN];
1327	static int first = 1;
1328	int flags, error;
1329
1330	if (IN6_IS_ADDR_UNSPECIFIED(ia6)) {
1331		strcpy(line, "*");
1332		return (line);
1333	}
1334	if (first && !numeric_addr) {
1335		first = 0;
1336		if (gethostname(domain, sizeof(domain)) == 0 &&
1337		    (cp = strchr(domain, '.')))
1338			strlcpy(domain, cp + 1, sizeof(domain));
1339		else
1340			domain[0] = 0;
1341	}
1342	memset(&sin6, 0, sizeof(sin6));
1343	memcpy(&sin6.sin6_addr, ia6, sizeof(*ia6));
1344	sin6.sin6_family = AF_INET6;
1345	/* XXX: ia6.s6_addr[2] can contain scopeid. */
1346	in6_fillscopeid(&sin6);
1347	flags = (numeric_addr) ? NI_NUMERICHOST : 0;
1348	error = getnameinfo((struct sockaddr *)&sin6, sizeof(sin6), hbuf,
1349	    sizeof(hbuf), NULL, 0, flags);
1350	if (error == 0) {
1351		if ((flags & NI_NUMERICHOST) == 0 &&
1352		    (cp = strchr(hbuf, '.')) &&
1353		    !strcmp(cp + 1, domain))
1354			*cp = 0;
1355		strlcpy(line, hbuf, sizeof(line));
1356	} else {
1357		/* XXX: this should not happen. */
1358		snprintf(line, sizeof(line), "%s",
1359			inet_ntop(AF_INET6, (void *)&sin6.sin6_addr, ntop_buf,
1360				sizeof(ntop_buf)));
1361	}
1362	return (line);
1363}
1364#endif /*INET6*/
1365