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