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