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