1/*	$OpenBSD: inet6.c,v 1.57 2024/02/05 23:16:39 bluhm Exp $	*/
2/*	BSDI inet.c,v 2.3 1995/10/24 02:19:29 prb Exp	*/
3/*
4 * Copyright (c) 1983, 1988, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#include <sys/types.h>
33#include <sys/socket.h>
34#include <sys/socketvar.h>
35#include <sys/ioctl.h>
36#include <sys/protosw.h>
37#include <sys/sysctl.h>
38
39#include <net/route.h>
40#include <net/if.h>
41#include <netinet/in.h>
42#include <netinet/ip6.h>
43#include <netinet/icmp6.h>
44#include <netinet/ip.h>
45#include <netinet/ip_var.h>
46#include <netinet6/ip6_var.h>
47#include <netinet6/in6_var.h>
48#include <netinet6/raw_ip6.h>
49#include <netinet6/ip6_divert.h>
50
51#include <arpa/inet.h>
52#include <netdb.h>
53
54#include <err.h>
55#include <errno.h>
56#include <stdio.h>
57#include <string.h>
58#include <unistd.h>
59#include <limits.h>
60#include "netstat.h"
61
62char	*inet6name(struct in6_addr *);
63
64static	char *ip6nh[] = {
65	"hop by hop",
66	"ICMP",
67	"IGMP",
68	"#3",
69	"IP",
70	"#5",
71	"TCP",
72	"#7",
73	"#8",
74	"#9",
75	"#10",
76	"#11",
77	"#12",
78	"#13",
79	"#14",
80	"#15",
81	"#16",
82	"UDP",
83	"#18",
84	"#19",
85	"#20",
86	"#21",
87	"IDP",
88	"#23",
89	"#24",
90	"#25",
91	"#26",
92	"#27",
93	"#28",
94	"TP",
95	"#30",
96	"#31",
97	"#32",
98	"#33",
99	"#34",
100	"#35",
101	"#36",
102	"#37",
103	"#38",
104	"#39",
105	"#40",
106	"IP6",
107	"#42",
108	"routing",
109	"fragment",
110	"#45",
111	"#46",
112	"#47",
113	"#48",
114	"#49",
115	"ESP",
116	"AH",
117	"#52",
118	"#53",
119	"#54",
120	"#55",
121	"#56",
122	"#57",
123	"ICMP6",
124	"no next header",
125	"destination option",
126	"#61",
127	"#62",
128	"#63",
129	"#64",
130	"#65",
131	"#66",
132	"#67",
133	"#68",
134	"#69",
135	"#70",
136	"#71",
137	"#72",
138	"#73",
139	"#74",
140	"#75",
141	"#76",
142	"#77",
143	"#78",
144	"#79",
145	"ISOIP",
146	"#81",
147	"#82",
148	"#83",
149	"#84",
150	"#85",
151	"#86",
152	"#87",
153	"#88",
154	"OSPF",
155	"#80",
156	"#91",
157	"#92",
158	"#93",
159	"#94",
160	"#95",
161	"#96",
162	"Ethernet",
163	"#98",
164	"#99",
165	"#100",
166	"#101",
167	"#102",
168	"#103",
169	"#104",
170	"#105",
171	"#106",
172	"#107",
173	"#108",
174	"#109",
175	"#110",
176	"#111",
177	"#112",
178	"#113",
179	"#114",
180	"#115",
181	"#116",
182	"#117",
183	"#118",
184	"#119",
185	"#120",
186	"#121",
187	"#122",
188	"#123",
189	"#124",
190	"#125",
191	"#126",
192	"#127",
193	"#128",
194	"#129",
195	"#130",
196	"#131",
197	"#132",
198	"#133",
199	"#134",
200	"#135",
201	"#136",
202	"#137",
203	"#138",
204	"#139",
205	"#140",
206	"#141",
207	"#142",
208	"#143",
209	"#144",
210	"#145",
211	"#146",
212	"#147",
213	"#148",
214	"#149",
215	"#150",
216	"#151",
217	"#152",
218	"#153",
219	"#154",
220	"#155",
221	"#156",
222	"#157",
223	"#158",
224	"#159",
225	"#160",
226	"#161",
227	"#162",
228	"#163",
229	"#164",
230	"#165",
231	"#166",
232	"#167",
233	"#168",
234	"#169",
235	"#170",
236	"#171",
237	"#172",
238	"#173",
239	"#174",
240	"#175",
241	"#176",
242	"#177",
243	"#178",
244	"#179",
245	"#180",
246	"#181",
247	"#182",
248	"#183",
249	"#184",
250	"#185",
251	"#186",
252	"#187",
253	"#188",
254	"#189",
255	"#180",
256	"#191",
257	"#192",
258	"#193",
259	"#194",
260	"#195",
261	"#196",
262	"#197",
263	"#198",
264	"#199",
265	"#200",
266	"#201",
267	"#202",
268	"#203",
269	"#204",
270	"#205",
271	"#206",
272	"#207",
273	"#208",
274	"#209",
275	"#210",
276	"#211",
277	"#212",
278	"#213",
279	"#214",
280	"#215",
281	"#216",
282	"#217",
283	"#218",
284	"#219",
285	"#220",
286	"#221",
287	"#222",
288	"#223",
289	"#224",
290	"#225",
291	"#226",
292	"#227",
293	"#228",
294	"#229",
295	"#230",
296	"#231",
297	"#232",
298	"#233",
299	"#234",
300	"#235",
301	"#236",
302	"#237",
303	"#238",
304	"#239",
305	"#240",
306	"#241",
307	"#242",
308	"#243",
309	"#244",
310	"#245",
311	"#246",
312	"#247",
313	"#248",
314	"#249",
315	"#250",
316	"#251",
317	"#252",
318	"#253",
319	"#254",
320	"#255",
321};
322
323/*
324 * Dump IP6 statistics structure.
325 */
326void
327ip6_stats(char *name)
328{
329	struct ip6stat ip6stat;
330	int first, i;
331	struct protoent *ep;
332	const char *n;
333	int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_STATS };
334	size_t len = sizeof(ip6stat);
335
336	if (sysctl(mib, sizeof(mib) / sizeof(mib[0]),
337	    &ip6stat, &len, NULL, 0) == -1) {
338		if (errno != ENOPROTOOPT)
339			warn("%s", name);
340		return;
341	}
342
343	printf("%s:\n", name);
344#define	p(f, m) if (ip6stat.f || sflag <= 1) \
345	printf(m, (unsigned long long)ip6stat.f, plural(ip6stat.f))
346#define	p1(f, m) if (ip6stat.f || sflag <= 1) \
347	printf(m, (unsigned long long)ip6stat.f)
348
349	p(ip6s_total, "\t%llu total packet%s received\n");
350	p1(ip6s_toosmall, "\t%llu with size smaller than minimum\n");
351	p1(ip6s_tooshort, "\t%llu with data size < data length\n");
352	p1(ip6s_badoptions, "\t%llu with bad options\n");
353	p1(ip6s_badvers, "\t%llu with incorrect version number\n");
354	p(ip6s_fragments, "\t%llu fragment%s received\n");
355	p(ip6s_fragdropped,
356	    "\t%llu fragment%s dropped (duplicates or out of space)\n");
357	p(ip6s_fragtimeout, "\t%llu fragment%s dropped after timeout\n");
358	p(ip6s_fragoverflow, "\t%llu fragment%s that exceeded limit\n");
359	p(ip6s_reassembled, "\t%llu packet%s reassembled ok\n");
360	p(ip6s_delivered, "\t%llu packet%s for this host\n");
361	p(ip6s_forward, "\t%llu packet%s forwarded\n");
362	p(ip6s_cantforward, "\t%llu packet%s not forwardable\n");
363	p(ip6s_redirectsent, "\t%llu redirect%s sent\n");
364	p(ip6s_localout, "\t%llu packet%s sent from this host\n");
365	p(ip6s_rawout, "\t%llu packet%s sent with fabricated ip header\n");
366	p(ip6s_odropped,
367	    "\t%llu output packet%s dropped due to no bufs, etc.\n");
368	p(ip6s_noroute, "\t%llu output packet%s discarded due to no route\n");
369	p(ip6s_fragmented, "\t%llu output datagram%s fragmented\n");
370	p(ip6s_ofragments, "\t%llu fragment%s created\n");
371	p(ip6s_cantfrag, "\t%llu datagram%s that can't be fragmented\n");
372	p(ip6s_badscope, "\t%llu packet%s that violated scope rules\n");
373	p(ip6s_notmember, "\t%llu multicast packet%s which we don't join\n");
374	for (first = 1, i = 0; i < 256; i++)
375		if (ip6stat.ip6s_nxthist[i] != 0) {
376			if (first) {
377				printf("\tInput packet histogram:\n");
378				first = 0;
379			}
380			n = NULL;
381			if (ip6nh[i])
382				n = ip6nh[i];
383			else if ((ep = getprotobynumber(i)) != NULL)
384				n = ep->p_name;
385			if (n)
386				printf("\t\t%s: %llu\n", n,
387				    (unsigned long long)ip6stat.ip6s_nxthist[i]);
388			else
389				printf("\t\t#%d: %llu\n", i,
390				    (unsigned long long)ip6stat.ip6s_nxthist[i]);
391		}
392	printf("\tMbuf statistics:\n");
393	p(ip6s_m1, "\t\t%llu one mbuf%s\n");
394	for (first = 1, i = 0; i < 32; i++) {
395		char ifbuf[IFNAMSIZ];
396		if (ip6stat.ip6s_m2m[i] != 0) {
397			if (first) {
398				printf("\t\ttwo or more mbuf:\n");
399				first = 0;
400			}
401			printf("\t\t\t%s = %llu\n",
402			    if_indextoname(i, ifbuf),
403			    (unsigned long long)ip6stat.ip6s_m2m[i]);
404		}
405	}
406	p(ip6s_mext1, "\t\t%llu one ext mbuf%s\n");
407	p(ip6s_mext2m, "\t\t%llu two or more ext mbuf%s\n");
408	p(ip6s_nogif, "\t%llu tunneling packet%s that can't find gif\n");
409	p(ip6s_toomanyhdr,
410	    "\t%llu packet%s discarded due to too many headers\n");
411
412	/* for debugging source address selection */
413#define PRINT_SCOPESTAT(s,i) do {\
414		switch(i) { /* XXX hardcoding in each case */\
415		case 1:\
416			p(s, "\t\t%llu node-local%s\n");\
417			break;\
418		case 2:\
419			p(s, "\t\t%llu link-local%s\n");\
420			break;\
421		case 5:\
422			p(s, "\t\t%llu site-local%s\n");\
423			break;\
424		case 14:\
425			p(s, "\t\t%llu global%s\n");\
426			break;\
427		default:\
428			printf("\t\t%llu addresses scope=%x\n",\
429			    (unsigned long long)ip6stat.s, i);\
430		}\
431	} while(0);
432
433	p(ip6s_sources_none,
434	    "\t%llu failure%s of source address selection\n");
435	for (first = 1, i = 0; i < 16; i++) {
436		if (ip6stat.ip6s_sources_sameif[i]) {
437			if (first) {
438				printf("\tsource addresses on an outgoing I/F\n");
439				first = 0;
440			}
441			PRINT_SCOPESTAT(ip6s_sources_sameif[i], i);
442		}
443	}
444	for (first = 1, i = 0; i < 16; i++) {
445		if (ip6stat.ip6s_sources_otherif[i]) {
446			if (first) {
447				printf("\tsource addresses on a non-outgoing I/F\n");
448				first = 0;
449			}
450			PRINT_SCOPESTAT(ip6s_sources_otherif[i], i);
451		}
452	}
453	for (first = 1, i = 0; i < 16; i++) {
454		if (ip6stat.ip6s_sources_samescope[i]) {
455			if (first) {
456				printf("\tsource addresses of same scope\n");
457				first = 0;
458			}
459			PRINT_SCOPESTAT(ip6s_sources_samescope[i], i);
460		}
461	}
462	for (first = 1, i = 0; i < 16; i++) {
463		if (ip6stat.ip6s_sources_otherscope[i]) {
464			if (first) {
465				printf("\tsource addresses of a different scope\n");
466				first = 0;
467			}
468			PRINT_SCOPESTAT(ip6s_sources_otherscope[i], i);
469		}
470	}
471	for (first = 1, i = 0; i < 16; i++) {
472		if (ip6stat.ip6s_sources_deprecated[i]) {
473			if (first) {
474				printf("\tdeprecated source addresses\n");
475				first = 0;
476			}
477			PRINT_SCOPESTAT(ip6s_sources_deprecated[i], i);
478		}
479	}
480	p1(ip6s_rtcachehit, "\t%llu route cache hit\n");
481	p1(ip6s_rtcachemiss, "\t%llu route cache miss\n");
482	p(ip6s_wrongif, "\t%llu packet%s received on wrong interface\n");
483	p(ip6s_idropped,
484	    "\t%llu input packet%s dropped due to no bufs, etc.\n");
485#undef p
486#undef p1
487}
488
489static	char *icmp6names[] = {
490	"#0",
491	"unreach",
492	"packet too big",
493	"time exceed",
494	"parameter problem",
495	"#5",
496	"#6",
497	"#7",
498	"#8",
499	"#9",
500	"#10",
501	"#11",
502	"#12",
503	"#13",
504	"#14",
505	"#15",
506	"#16",
507	"#17",
508	"#18",
509	"#19",
510	"#20",
511	"#21",
512	"#22",
513	"#23",
514	"#24",
515	"#25",
516	"#26",
517	"#27",
518	"#28",
519	"#29",
520	"#30",
521	"#31",
522	"#32",
523	"#33",
524	"#34",
525	"#35",
526	"#36",
527	"#37",
528	"#38",
529	"#39",
530	"#40",
531	"#41",
532	"#42",
533	"#43",
534	"#44",
535	"#45",
536	"#46",
537	"#47",
538	"#48",
539	"#49",
540	"#50",
541	"#51",
542	"#52",
543	"#53",
544	"#54",
545	"#55",
546	"#56",
547	"#57",
548	"#58",
549	"#59",
550	"#60",
551	"#61",
552	"#62",
553	"#63",
554	"#64",
555	"#65",
556	"#66",
557	"#67",
558	"#68",
559	"#69",
560	"#70",
561	"#71",
562	"#72",
563	"#73",
564	"#74",
565	"#75",
566	"#76",
567	"#77",
568	"#78",
569	"#79",
570	"#80",
571	"#81",
572	"#82",
573	"#83",
574	"#84",
575	"#85",
576	"#86",
577	"#87",
578	"#88",
579	"#89",
580	"#80",
581	"#91",
582	"#92",
583	"#93",
584	"#94",
585	"#95",
586	"#96",
587	"#97",
588	"#98",
589	"#99",
590	"#100",
591	"#101",
592	"#102",
593	"#103",
594	"#104",
595	"#105",
596	"#106",
597	"#107",
598	"#108",
599	"#109",
600	"#110",
601	"#111",
602	"#112",
603	"#113",
604	"#114",
605	"#115",
606	"#116",
607	"#117",
608	"#118",
609	"#119",
610	"#120",
611	"#121",
612	"#122",
613	"#123",
614	"#124",
615	"#125",
616	"#126",
617	"#127",
618	"echo",
619	"echo reply",
620	"multicast listener query",
621	"multicast listener report",
622	"multicast listener done",
623	"router solicitation",
624	"router advertisement",
625	"neighbor solicitation",
626	"neighbor advertisement",
627	"redirect",
628	"router renumbering",
629	"node information request",
630	"node information reply",
631	"#141",
632	"#142",
633	"#143",
634	"#144",
635	"#145",
636	"#146",
637	"#147",
638	"#148",
639	"#149",
640	"#150",
641	"#151",
642	"#152",
643	"#153",
644	"#154",
645	"#155",
646	"#156",
647	"#157",
648	"#158",
649	"#159",
650	"#160",
651	"#161",
652	"#162",
653	"#163",
654	"#164",
655	"#165",
656	"#166",
657	"#167",
658	"#168",
659	"#169",
660	"#170",
661	"#171",
662	"#172",
663	"#173",
664	"#174",
665	"#175",
666	"#176",
667	"#177",
668	"#178",
669	"#179",
670	"#180",
671	"#181",
672	"#182",
673	"#183",
674	"#184",
675	"#185",
676	"#186",
677	"#187",
678	"#188",
679	"#189",
680	"#180",
681	"#191",
682	"#192",
683	"#193",
684	"#194",
685	"#195",
686	"#196",
687	"#197",
688	"#198",
689	"#199",
690	"#200",
691	"#201",
692	"#202",
693	"#203",
694	"#204",
695	"#205",
696	"#206",
697	"#207",
698	"#208",
699	"#209",
700	"#210",
701	"#211",
702	"#212",
703	"#213",
704	"#214",
705	"#215",
706	"#216",
707	"#217",
708	"#218",
709	"#219",
710	"#220",
711	"#221",
712	"#222",
713	"#223",
714	"#224",
715	"#225",
716	"#226",
717	"#227",
718	"#228",
719	"#229",
720	"#230",
721	"#231",
722	"#232",
723	"#233",
724	"#234",
725	"#235",
726	"#236",
727	"#237",
728	"#238",
729	"#239",
730	"#240",
731	"#241",
732	"#242",
733	"#243",
734	"#244",
735	"#245",
736	"#246",
737	"#247",
738	"#248",
739	"#249",
740	"#250",
741	"#251",
742	"#252",
743	"#253",
744	"#254",
745	"#255",
746};
747
748/*
749 * Dump ICMPv6 statistics.
750 */
751void
752icmp6_stats(char *name)
753{
754	struct icmp6stat icmp6stat;
755	int i, first;
756	int mib[] = { CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_STATS };
757	size_t len = sizeof(icmp6stat);
758
759	if (sysctl(mib, sizeof(mib) / sizeof(mib[0]),
760	    &icmp6stat, &len, NULL, 0) == -1) {
761		if (errno != ENOPROTOOPT)
762			warn("%s", name);
763		return;
764	}
765
766	printf("%s:\n", name);
767#define	p(f, m) if (icmp6stat.f || sflag <= 1) \
768	printf(m, (unsigned long long)icmp6stat.f, plural(icmp6stat.f))
769#define p_5(f, m) if (icmp6stat.f || sflag <= 1) \
770	printf(m, (unsigned long long)icmp6stat.f)
771
772	p(icp6s_error, "\t%llu call%s to icmp6_error\n");
773	p(icp6s_canterror,
774	    "\t%llu error%s not generated because old message was icmp6 or so\n");
775	p(icp6s_toofreq,
776	    "\t%llu error%s not generated because of rate limitation\n");
777	for (first = 1, i = 0; i < 256; i++)
778		if (icmp6stat.icp6s_outhist[i] != 0) {
779			if (first) {
780				printf("\tOutput packet histogram:\n");
781				first = 0;
782			}
783			printf("\t\t%s: %llu\n", icmp6names[i],
784			    (unsigned long long)icmp6stat.icp6s_outhist[i]);
785		}
786	p(icp6s_badcode, "\t%llu message%s with bad code fields\n");
787	p(icp6s_tooshort, "\t%llu message%s < minimum length\n");
788	p(icp6s_checksum, "\t%llu bad checksum%s\n");
789	p(icp6s_badlen, "\t%llu message%s with bad length\n");
790	for (first = 1, i = 0; i < ICMP6_MAXTYPE; i++)
791		if (icmp6stat.icp6s_inhist[i] != 0) {
792			if (first) {
793				printf("\tInput packet histogram:\n");
794				first = 0;
795			}
796			printf("\t\t%s: %llu\n", icmp6names[i],
797			    (unsigned long long)icmp6stat.icp6s_inhist[i]);
798		}
799	printf("\tHistogram of error messages to be generated:\n");
800	p_5(icp6s_odst_unreach_noroute, "\t\t%llu no route\n");
801	p_5(icp6s_odst_unreach_admin, "\t\t%llu administratively prohibited\n");
802	p_5(icp6s_odst_unreach_beyondscope, "\t\t%llu beyond scope\n");
803	p_5(icp6s_odst_unreach_addr, "\t\t%llu address unreachable\n");
804	p_5(icp6s_odst_unreach_noport, "\t\t%llu port unreachable\n");
805	p_5(icp6s_opacket_too_big, "\t\t%llu packet too big\n");
806	p_5(icp6s_otime_exceed_transit, "\t\t%llu time exceed transit\n");
807	p_5(icp6s_otime_exceed_reassembly, "\t\t%llu time exceed reassembly\n");
808	p_5(icp6s_oparamprob_header, "\t\t%llu erroneous header field\n");
809	p_5(icp6s_oparamprob_nextheader, "\t\t%llu unrecognized next header\n");
810	p_5(icp6s_oparamprob_option, "\t\t%llu unrecognized option\n");
811	p_5(icp6s_oredirect, "\t\t%llu redirect\n");
812	p_5(icp6s_ounknown, "\t\t%llu unknown\n");
813
814	p(icp6s_reflect, "\t%llu message response%s generated\n");
815	p(icp6s_nd_toomanyopt, "\t%llu message%s with too many ND options\n");
816	p(icp6s_nd_badopt, "\t%llu message%s with bad ND options\n");
817	p(icp6s_badns, "\t%llu bad neighbor solicitation message%s\n");
818	p(icp6s_badna, "\t%llu bad neighbor advertisement message%s\n");
819	p(icp6s_badrs, "\t%llu bad router solicitation message%s\n");
820	p(icp6s_badra, "\t%llu bad router advertisement message%s\n");
821	p(icp6s_badredirect, "\t%llu bad redirect message%s\n");
822	p(icp6s_pmtuchg, "\t%llu path MTU change%s\n");
823#undef p
824#undef p_5
825}
826
827/*
828 * Dump raw ip6 statistics structure.
829 */
830void
831rip6_stats(char *name)
832{
833	struct rip6stat rip6stat;
834	u_int64_t delivered;
835	int mib[] = { CTL_NET, PF_INET6, IPPROTO_RAW, RIPV6CTL_STATS };
836	size_t len = sizeof(rip6stat);
837
838	if (sysctl(mib, sizeof(mib) / sizeof(mib[0]),
839	    &rip6stat, &len, NULL, 0) == -1) {
840		if (errno != ENOPROTOOPT)
841			warn("%s", name);
842		return;
843	}
844
845	printf("%s:\n", name);
846
847#define	p(f, m) if (rip6stat.f || sflag <= 1) \
848    printf(m, (unsigned long long)rip6stat.f, plural(rip6stat.f))
849	p(rip6s_ipackets, "\t%llu message%s received\n");
850	p(rip6s_isum, "\t%llu checksum calculation%s on inbound\n");
851	p(rip6s_badsum, "\t%llu message%s with bad checksum\n");
852	p(rip6s_nosock, "\t%llu message%s dropped due to no socket\n");
853	p(rip6s_nosockmcast,
854	    "\t%llu multicast message%s dropped due to no socket\n");
855	p(rip6s_fullsock,
856	    "\t%llu message%s dropped due to full socket buffers\n");
857	delivered = rip6stat.rip6s_ipackets -
858		    rip6stat.rip6s_nosock -
859		    rip6stat.rip6s_nosockmcast -
860		    rip6stat.rip6s_fullsock;
861	if (delivered || sflag <= 1)
862		printf("\t%llu delivered\n", (unsigned long long)delivered);
863	p(rip6s_opackets, "\t%llu datagram%s output\n");
864#undef p
865}
866
867/*
868 * Dump divert6 statistics structure.
869 */
870void
871div6_stats(char *name)
872{
873	struct div6stat div6stat;
874	int mib[] = { CTL_NET, PF_INET6, IPPROTO_DIVERT, DIVERT6CTL_STATS };
875	size_t len = sizeof(div6stat);
876
877	if (sysctl(mib, sizeof(mib) / sizeof(mib[0]),
878	    &div6stat, &len, NULL, 0) == -1) {
879		if (errno != ENOPROTOOPT)
880			warn("%s", name);
881		return;
882	}
883
884	printf("%s:\n", name);
885#define p(f, m) if (div6stat.f || sflag <= 1) \
886    printf(m, div6stat.f, plural(div6stat.f))
887#define p1(f, m) if (div6stat.f || sflag <= 1) \
888    printf(m, div6stat.f)
889	p(divs_ipackets, "\t%lu total packet%s received\n");
890	p1(divs_noport, "\t%lu dropped due to no socket\n");
891	p1(divs_fullsock, "\t%lu dropped due to full socket buffers\n");
892	p(divs_opackets, "\t%lu packet%s output\n");
893	p1(divs_errors, "\t%lu errors\n");
894#undef p
895#undef p1
896}
897
898/*
899 * Pretty print an Internet address (net address + port).
900 * If the nflag was specified, use numbers instead of names.
901 */
902
903void
904inet6print(struct in6_addr *in6, int port, const char *proto)
905{
906
907#define GETSERVBYPORT6(port, proto, ret) do { \
908	if (strcmp((proto), "tcp6") == 0) \
909		(ret) = getservbyport((int)(port), "tcp"); \
910	else if (strcmp((proto), "udp6") == 0) \
911		(ret) = getservbyport((int)(port), "udp"); \
912	else \
913		(ret) = getservbyport((int)(port), (proto)); \
914	} while (0)
915
916	struct servent *sp = 0;
917	char line[80], *cp;
918	int width;
919	int len = sizeof line;
920
921	width = Aflag ? 12 : 16;
922	if (vflag && width < strlen(inet6name(in6)))
923		width = strlen(inet6name(in6));
924	snprintf(line, len, "%.*s.", width, inet6name(in6));
925	len -= strlen(line);
926	if (len <= 0)
927		goto bail;
928
929	cp = strchr(line, '\0');
930	if (!nflag && port)
931		GETSERVBYPORT6(port, proto, sp);
932	if (sp || port == 0)
933		snprintf(cp, len, "%.8s", sp ? sp->s_name : "*");
934	else
935		snprintf(cp, len, "%d", ntohs((u_short)port));
936	width = Aflag ? 18 : 22;
937	if (vflag && width < strlen(line))
938		width = strlen(line);
939bail:
940	printf(" %-*.*s", width, width, line);
941}
942
943/*
944 * Construct an Internet address representation.
945 * If the nflag has been supplied, give
946 * numeric value, otherwise try for symbolic name.
947 */
948
949char *
950inet6name(struct in6_addr *in6p)
951{
952	char *cp;
953	static char line[NI_MAXHOST];
954	struct hostent *hp;
955	static char domain[HOST_NAME_MAX+1];
956	static int first = 1;
957	char hbuf[NI_MAXHOST];
958	struct sockaddr_in6 sin6;
959	const int niflag = NI_NUMERICHOST;
960
961	if (first && !nflag) {
962		first = 0;
963		if (gethostname(domain, sizeof(domain)) == 0 &&
964		    (cp = strchr(domain, '.')))
965			(void) strlcpy(domain, cp + 1, sizeof domain);
966		else
967			domain[0] = '\0';
968	}
969	cp = 0;
970	if (!nflag && !IN6_IS_ADDR_UNSPECIFIED(in6p)) {
971		hp = gethostbyaddr((char *)in6p, sizeof(*in6p), AF_INET6);
972		if (hp) {
973			if ((cp = strchr(hp->h_name, '.')) &&
974			    !strcmp(cp + 1, domain))
975				*cp = 0;
976			cp = hp->h_name;
977		}
978	}
979	if (IN6_IS_ADDR_UNSPECIFIED(in6p))
980		strlcpy(line, "*", sizeof(line));
981	else if (cp)
982		strlcpy(line, cp, sizeof(line));
983	else {
984		memset(&sin6, 0, sizeof(sin6));
985		sin6.sin6_family = AF_INET6;
986		sin6.sin6_addr = *in6p;
987#ifdef __KAME__
988		if (IN6_IS_ADDR_LINKLOCAL(in6p) ||
989		    IN6_IS_ADDR_MC_LINKLOCAL(in6p) ||
990		    IN6_IS_ADDR_MC_INTFACELOCAL(in6p)) {
991			sin6.sin6_scope_id =
992			    ntohs(*(u_int16_t *)&in6p->s6_addr[2]);
993			sin6.sin6_addr.s6_addr[2] = 0;
994			sin6.sin6_addr.s6_addr[3] = 0;
995		}
996#endif
997		if (getnameinfo((struct sockaddr *)&sin6, sizeof(sin6),
998		    hbuf, sizeof(hbuf), NULL, 0, niflag) != 0)
999			strlcpy(hbuf, "?", sizeof hbuf);
1000		strlcpy(line, hbuf, sizeof(line));
1001	}
1002	return (line);
1003}
1004