xref: /netbsd-src/usr.sbin/ifmcstat/ifmcstat.c (revision 5ef06edbc38c9316f272d771ea3f43fc455f4807)
1*5ef06edbSnisimura /*	$NetBSD: ifmcstat.c,v 1.22 2020/03/03 08:56:05 nisimura Exp $	*/
226c3d764Sitojun 
345124457Sitojun /*
445124457Sitojun  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
545124457Sitojun  * All rights reserved.
645124457Sitojun  *
745124457Sitojun  * Redistribution and use in source and binary forms, with or without
845124457Sitojun  * modification, are permitted provided that the following conditions
945124457Sitojun  * are met:
1045124457Sitojun  * 1. Redistributions of source code must retain the above copyright
1145124457Sitojun  *    notice, this list of conditions and the following disclaimer.
1245124457Sitojun  * 2. Redistributions in binary form must reproduce the above copyright
1345124457Sitojun  *    notice, this list of conditions and the following disclaimer in the
1445124457Sitojun  *    documentation and/or other materials provided with the distribution.
1545124457Sitojun  * 3. Neither the name of the project nor the names of its contributors
1645124457Sitojun  *    may be used to endorse or promote products derived from this software
1745124457Sitojun  *    without specific prior written permission.
1845124457Sitojun  *
1945124457Sitojun  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
2045124457Sitojun  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2145124457Sitojun  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2245124457Sitojun  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
2345124457Sitojun  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2445124457Sitojun  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2545124457Sitojun  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2645124457Sitojun  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2745124457Sitojun  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2845124457Sitojun  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2945124457Sitojun  * SUCH DAMAGE.
3045124457Sitojun  */
31539332ecSjoerg #include <sys/cdefs.h>
32*5ef06edbSnisimura __RCSID("$NetBSD: ifmcstat.c,v 1.22 2020/03/03 08:56:05 nisimura Exp $");
3345124457Sitojun 
34539332ecSjoerg #include <err.h>
35539332ecSjoerg #include <errno.h>
3645124457Sitojun #include <stdio.h>
3745124457Sitojun #include <stdlib.h>
3845124457Sitojun #include <fcntl.h>
3945124457Sitojun #include <kvm.h>
4045124457Sitojun #include <nlist.h>
4145124457Sitojun #include <string.h>
426002e343Sitojun #include <limits.h>
43539332ecSjoerg #include <util.h>
4445124457Sitojun 
4545124457Sitojun #include <sys/types.h>
4645124457Sitojun #include <sys/socket.h>
47539332ecSjoerg #include <sys/sysctl.h>
4845124457Sitojun #include <net/if.h>
494265f28eSitojun #include <net/if_types.h>
5045124457Sitojun #include <net/if_dl.h>
5145124457Sitojun #include <netinet/in.h>
5245124457Sitojun #include <net/if_ether.h>
5345124457Sitojun #include <netinet/in_var.h>
5445124457Sitojun #include <arpa/inet.h>
5545124457Sitojun 
562925a0d6Sitojun #include <netdb.h>
572925a0d6Sitojun 
58539332ecSjoerg static const char *inet6_n2a(void *);
59539332ecSjoerg static void print_ether_mcast(u_short);
60539332ecSjoerg static void print_inet6_mcast(u_short, const char *);
614d9ae69bSitojun 
6279c2ddeeSjoerg static const char *
inet6_n2a(void * p)63539332ecSjoerg inet6_n2a(void *p)
6445124457Sitojun {
652925a0d6Sitojun 	static char buf[NI_MAXHOST];
662925a0d6Sitojun 	struct sockaddr_in6 sin6;
672925a0d6Sitojun 	const int niflags = NI_NUMERICHOST;
6845124457Sitojun 
692925a0d6Sitojun 	memset(&sin6, 0, sizeof(sin6));
702925a0d6Sitojun 	sin6.sin6_family = AF_INET6;
712925a0d6Sitojun 	sin6.sin6_len = sizeof(struct sockaddr_in6);
72539332ecSjoerg 	memcpy(&sin6.sin6_addr, p, sizeof(sin6.sin6_addr));
7394a96ec4Schristos 	inet6_getscopeid(&sin6, INET6_IS_ADDR_LINKLOCAL|
7494a96ec4Schristos 	    INET6_IS_ADDR_MC_LINKLOCAL);
752925a0d6Sitojun 	if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
762925a0d6Sitojun 			buf, sizeof(buf), NULL, 0, niflags) == 0)
772925a0d6Sitojun 		return buf;
782925a0d6Sitojun 	else
792925a0d6Sitojun 		return "(invalid)";
8045124457Sitojun }
8145124457Sitojun 
8226e6c607Sozaki-r static bool
check_inet6_availability(void)8326e6c607Sozaki-r check_inet6_availability(void)
8426e6c607Sozaki-r {
8526e6c607Sozaki-r 	size_t dummy;
8626e6c607Sozaki-r 
8726e6c607Sozaki-r 	return sysctlnametomib("net.inet6.multicast", NULL, &dummy) == 0;
8826e6c607Sozaki-r }
8926e6c607Sozaki-r 
9079c2ddeeSjoerg int
main(void)9179c2ddeeSjoerg main(void)
9245124457Sitojun {
93539332ecSjoerg 	struct if_nameindex  *ifps;
94539332ecSjoerg 	size_t i;
9526e6c607Sozaki-r 	bool inet6_available = check_inet6_availability();
9645124457Sitojun 
97539332ecSjoerg 	ifps = if_nameindex();
98539332ecSjoerg 	if (ifps == NULL)
99539332ecSjoerg 		errx(1, "failed to obtain list of interfaces");
10026e6c607Sozaki-r 
101539332ecSjoerg 	for (i = 0; ifps[i].if_name != NULL; ++i) {
102539332ecSjoerg 		printf("%s:\n", ifps[i].if_name);
10326e6c607Sozaki-r 		if (inet6_available)
104539332ecSjoerg 			print_inet6_mcast(ifps[i].if_index, ifps[i].if_name);
105539332ecSjoerg 		print_ether_mcast(ifps[i].if_index);
10645124457Sitojun 	}
107539332ecSjoerg 	if_freenameindex(ifps);
10845124457Sitojun 
10945124457Sitojun 	exit(0);
11045124457Sitojun 	/*NOTREACHED*/
11145124457Sitojun }
11245124457Sitojun 
11379c2ddeeSjoerg static void
print_hwaddr(const uint8_t * hwaddr,size_t len)114539332ecSjoerg print_hwaddr(const uint8_t *hwaddr, size_t len)
11545124457Sitojun {
116539332ecSjoerg 	while (len)
117*5ef06edbSnisimura 		printf("%02x%s", *hwaddr++, --len > 0 ? ":" : "");
11845124457Sitojun }
11945124457Sitojun 
12079c2ddeeSjoerg static void
print_ether_mcast(u_short ifindex)121539332ecSjoerg print_ether_mcast(u_short ifindex)
12245124457Sitojun {
123539332ecSjoerg 	static int ems_oids[4], sdl_oids[3];
124539332ecSjoerg 	size_t i, ems_len, sdl_len;
125539332ecSjoerg 	void *hwaddr;
126539332ecSjoerg 	struct ether_multi_sysctl *ems;
12745124457Sitojun 
128539332ecSjoerg 	if (ems_oids[0] == 0) {
129539332ecSjoerg 		size_t oidlen = __arraycount(ems_oids);
130539332ecSjoerg 		if (sysctlnametomib("net.ether.multicast", ems_oids, &oidlen) == -1)
131539332ecSjoerg 			errx(1, "net.ether.multicast not found");
132539332ecSjoerg 		if (oidlen != 3)
133539332ecSjoerg 			errx(1, "Wrong OID path for net.ether.multicast");
1344d9ae69bSitojun 	}
1354d9ae69bSitojun 
136539332ecSjoerg 	if (sdl_oids[0] == 0) {
137539332ecSjoerg 		size_t oidlen = __arraycount(sdl_oids);
138539332ecSjoerg 		if (sysctlnametomib("net.sdl", sdl_oids, &oidlen) == -1)
139539332ecSjoerg 			errx(1, "net.sdl not found");
140539332ecSjoerg 		if (oidlen != 2)
141539332ecSjoerg 			errx(1, "Wrong OID path for net.sdl");
1424d9ae69bSitojun 	}
143539332ecSjoerg 
144539332ecSjoerg 	sdl_oids[2] = ifindex;
1450142924aSjoerg 	hwaddr = asysctl(sdl_oids, 3, &sdl_len);
146539332ecSjoerg 
147539332ecSjoerg 	if (sdl_len == 0) {
148539332ecSjoerg 		free(hwaddr);
149539332ecSjoerg 		return;
150539332ecSjoerg 	}
1510142924aSjoerg 	if (hwaddr == NULL) {
1520142924aSjoerg 		warn("failed to read net.sdl");
1530142924aSjoerg 	}
154539332ecSjoerg 
155539332ecSjoerg 	ems_oids[3] = ifindex;
1560142924aSjoerg 	ems = asysctl(ems_oids, 4, &ems_len);
157539332ecSjoerg 	ems_len /= sizeof(*ems);
158539332ecSjoerg 
1590142924aSjoerg 	if (ems == NULL && ems_len != 0) {
1600142924aSjoerg 		warn("failed to read net.ether.multicast");
1610142924aSjoerg 		return;
1620142924aSjoerg 	}
1630142924aSjoerg 
164539332ecSjoerg 	printf("\tenaddr ");
165539332ecSjoerg 	print_hwaddr(hwaddr, sdl_len);
166539332ecSjoerg 	printf(" multicnt %zu\n", ems_len);
167539332ecSjoerg 
168539332ecSjoerg 	for (i = 0; i < ems_len; ++i) {
169539332ecSjoerg 		printf("\t\t");
170*5ef06edbSnisimura 		print_hwaddr(ems[i].enm_addrlo, sdl_len);
171539332ecSjoerg 		printf(" -- ");
172*5ef06edbSnisimura 		print_hwaddr(ems[i].enm_addrhi, sdl_len);
173*5ef06edbSnisimura 		printf(" refcount %d\n", ems[i].enm_refcount);
174539332ecSjoerg 	}
175539332ecSjoerg 	free(ems);
176539332ecSjoerg 	free(hwaddr);
17745124457Sitojun }
17845124457Sitojun 
17979c2ddeeSjoerg static void
print_inet6_mcast(u_short ifindex,const char * ifname)180539332ecSjoerg print_inet6_mcast(u_short ifindex, const char *ifname)
18145124457Sitojun {
18200a9cf74Sozaki-r 	static int mcast_oids[4];
183539332ecSjoerg 	const char *addr;
18400a9cf74Sozaki-r 	uint8_t *mcast_addrs, *p, *last_p;
185539332ecSjoerg 	uint32_t refcnt;
186539332ecSjoerg 	size_t len;
18774b10119Sjoerg 
188539332ecSjoerg 	if (mcast_oids[0] == 0) {
189539332ecSjoerg 		size_t oidlen = __arraycount(mcast_oids);
190539332ecSjoerg 		if (sysctlnametomib("net.inet6.multicast", mcast_oids,
191539332ecSjoerg 		    &oidlen) == -1)
192539332ecSjoerg 			errx(1, "net.inet6.multicast not found");
193539332ecSjoerg 		if (oidlen != 3)
194539332ecSjoerg 			errx(1, "Wrong OID path for net.inet6.multicast");
19574b10119Sjoerg 	}
196539332ecSjoerg 
197539332ecSjoerg 	mcast_oids[3] = ifindex;
198539332ecSjoerg 
1990142924aSjoerg 	mcast_addrs = asysctl(mcast_oids, 4, &len);
2000142924aSjoerg 	if (mcast_addrs == NULL && len != 0) {
2010142924aSjoerg 		warn("failed to read net.inet6.multicast");
2020142924aSjoerg 		return;
2030142924aSjoerg 	}
204539332ecSjoerg 	if (len) {
205539332ecSjoerg 		p = mcast_addrs;
206539332ecSjoerg 		last_p = NULL;
207539332ecSjoerg 		while (len >= 2 * sizeof(struct in6_addr) + sizeof(uint32_t)) {
208539332ecSjoerg 			if (last_p == NULL ||
209539332ecSjoerg 			    memcmp(p, last_p, sizeof(struct in6_addr)))
210539332ecSjoerg 				printf("\tinet6 %s\n", inet6_n2a(p));
211539332ecSjoerg 			last_p = p;
212539332ecSjoerg 			p += sizeof(struct in6_addr);
213539332ecSjoerg 			addr = inet6_n2a(p);
214539332ecSjoerg 			p += sizeof(struct in6_addr);
215539332ecSjoerg 			memcpy(&refcnt, p, sizeof(refcnt));
216539332ecSjoerg 			p += sizeof(refcnt);
217539332ecSjoerg 			printf("\t\tgroup %s refcount %" PRIu32 "\n", addr,
218539332ecSjoerg 			    refcnt);
219539332ecSjoerg 			len -= 2 * sizeof(struct in6_addr) + sizeof(uint32_t);
220539332ecSjoerg 		}
221539332ecSjoerg 	}
222539332ecSjoerg 	free(mcast_addrs);
22345124457Sitojun }
224