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