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