/* * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. The rights granted to you under the License * may not be used to create, or enable the creation or redistribution of, * unlawful or unlicensed copies of an Apple operating system, or to * circumvent, violate, or enable the circumvention or violation of, any * terms of an Apple operating system software license agreement. * * Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ /* * Copyright (c) 2007 Bruce M. Simpson * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include /* * Print the running system's current multicast group memberships. * As this relies on getifmaddrs(), it may not be used with a core file. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "netstat.h" union sockunion { struct sockaddr_storage ss; struct sockaddr sa; struct sockaddr_dl sdl; struct sockaddr_in sin; struct sockaddr_in6 sin6; }; typedef union sockunion sockunion_t; /* * This may have been defined in . Note that if is * to be included it must be included before this header file. */ #ifndef ifa_broadaddr #define ifa_broadaddr ifa_dstaddr /* broadcast address interface */ #endif struct ifmaddrs { struct ifmaddrs *ifma_next; struct sockaddr *ifma_name; struct sockaddr *ifma_addr; struct sockaddr *ifma_lladdr; }; void ifmalist_dump_af(const struct ifmaddrs * const ifmap, int const af); #define SALIGN (sizeof(uint32_t) - 1) #define SA_RLEN(sa) (sa ? ((sa)->sa_len ? (((sa)->sa_len + SALIGN) & ~SALIGN) : \ (SALIGN + 1)) : 0) #define MAX_SYSCTL_TRY 5 #define RTA_MASKS (RTA_GATEWAY | RTA_IFP | RTA_IFA) int getifmaddrs(struct ifmaddrs **); void freeifmaddrs(struct ifmaddrs *); int getifmaddrs(struct ifmaddrs **pif) { int icnt = 1; int dcnt = 0; int ntry = 0; size_t len; size_t needed; int mib[6]; int i; char *buf; char *data; char *next; char *p; struct ifma_msghdr2 *ifmam; struct ifmaddrs *ifa, *ift; struct rt_msghdr *rtm; struct sockaddr *sa; mib[0] = CTL_NET; mib[1] = PF_ROUTE; mib[2] = 0; /* protocol */ mib[3] = 0; /* wildcard address family */ mib[4] = NET_RT_IFLIST2; mib[5] = 0; /* no flags */ do { if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) return (-1); if ((buf = malloc(needed)) == NULL) return (-1); if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) { free(buf); return (-1); } free(buf); buf = NULL; } } while (buf == NULL); for (next = buf; next < buf + needed; next += rtm->rtm_msglen) { rtm = (struct rt_msghdr *)(void *)next; if (rtm->rtm_version != RTM_VERSION) continue; switch (rtm->rtm_type) { case RTM_NEWMADDR2: ifmam = (struct ifma_msghdr2 *)(void *)rtm; if ((ifmam->ifmam_addrs & RTA_IFA) == 0) break; icnt++; p = (char *)(ifmam + 1); for (i = 0; i < RTAX_MAX; i++) { if ((RTA_MASKS & ifmam->ifmam_addrs & (1 << i)) == 0) continue; sa = (struct sockaddr *)(void *)p; len = SA_RLEN(sa); dcnt += len; p += len; } break; } } data = malloc(sizeof(struct ifmaddrs) * icnt + dcnt); if (data == NULL) { free(buf); return (-1); } ifa = (struct ifmaddrs *)(void *)data; data += sizeof(struct ifmaddrs) * icnt; memset(ifa, 0, sizeof(struct ifmaddrs) * icnt); ift = ifa; for (next = buf; next < buf + needed; next += rtm->rtm_msglen) { rtm = (struct rt_msghdr *)(void *)next; if (rtm->rtm_version != RTM_VERSION) continue; switch (rtm->rtm_type) { case RTM_NEWMADDR2: ifmam = (struct ifma_msghdr2 *)(void *)rtm; if ((ifmam->ifmam_addrs & RTA_IFA) == 0) break; p = (char *)(ifmam + 1); for (i = 0; i < RTAX_MAX; i++) { if ((RTA_MASKS & ifmam->ifmam_addrs & (1 << i)) == 0) continue; sa = (struct sockaddr *)(void *)p; len = SA_RLEN(sa); switch (i) { case RTAX_GATEWAY: ift->ifma_lladdr = (struct sockaddr *)(void *)data; memcpy(data, p, len); data += len; break; case RTAX_IFP: ift->ifma_name = (struct sockaddr *)(void *)data; memcpy(data, p, len); data += len; break; case RTAX_IFA: ift->ifma_addr = (struct sockaddr *)(void *)data; memcpy(data, p, len); data += len; break; default: data += len; break; } p += len; } ift->ifma_next = ift + 1; ift = ift->ifma_next; break; } } free(buf); if (ift > ifa) { ift--; ift->ifma_next = NULL; *pif = ifa; } else { *pif = NULL; free(ifa); } return (0); } void freeifmaddrs(struct ifmaddrs *ifmp) { free(ifmp); } void ifmalist_dump_af(const struct ifmaddrs * const ifmap, int const af) { const struct ifmaddrs *ifma; sockunion_t *psa; char myifname[IFNAMSIZ]; #ifdef INET6 char addrbuf[INET6_ADDRSTRLEN]; #endif char *pcolon; char *pafname, *pifname, *plladdr = NULL, *pgroup = NULL; #ifdef INET6 void *in6addr; #endif switch (af) { case AF_INET: pafname = "IPv4"; break; #ifdef INET6 case AF_INET6: pafname = "IPv6"; break; #endif case AF_LINK: pafname = "Link-layer"; break; default: return; /* XXX */ } fprintf(stdout, "%s Multicast Group Memberships\n", pafname); fprintf(stdout, "%-20s\t%-16s\t%s\n", "Group", "Link-layer Address", "Netif"); for (ifma = ifmap; ifma; ifma = ifma->ifma_next) { if (ifma->ifma_name == NULL || ifma->ifma_addr == NULL) continue; /* Group address */ psa = (sockunion_t *)ifma->ifma_addr; if (psa->sa.sa_family != af) continue; switch (psa->sa.sa_family) { case AF_INET: pgroup = inet_ntoa(psa->sin.sin_addr); break; #ifdef INET6 case AF_INET6: in6addr = &psa->sin6.sin6_addr; inet_ntop(psa->sa.sa_family, in6addr, addrbuf, sizeof(addrbuf)); pgroup = addrbuf; break; #endif case AF_LINK: if ((psa->sdl.sdl_alen == ETHER_ADDR_LEN) || (psa->sdl.sdl_type == IFT_ETHER)) { pgroup = ether_ntoa((struct ether_addr *)&psa->sdl.sdl_data); #ifdef notyet } else { pgroup = addr2ascii(AF_LINK, &psa->sdl, sizeof(struct sockaddr_dl), addrbuf); #endif } break; default: continue; /* XXX */ } /* Link-layer mapping, if any */ psa = (sockunion_t *)ifma->ifma_lladdr; if (psa != NULL) { if (psa->sa.sa_family == AF_LINK) { if ((psa->sdl.sdl_alen == ETHER_ADDR_LEN) || (psa->sdl.sdl_type == IFT_ETHER)) { /* IEEE 802 */ plladdr = ether_ntoa((struct ether_addr *)&psa->sdl.sdl_data); #ifdef notyet } else { /* something more exotic */ plladdr = addr2ascii(AF_LINK, &psa->sdl, sizeof(struct sockaddr_dl), addrbuf); #endif } } else { int i; /* not a link-layer address */ plladdr = ""; for (i = 0; psa->sa.sa_len > 2 && i < psa->sa.sa_len - 2; i++) printf("0x%x ", psa->sa.sa_data[i]); printf("\n"); } } else { plladdr = ""; } /* Interface upon which the membership exists */ psa = (sockunion_t *)ifma->ifma_name; if (psa != NULL && psa->sa.sa_family == AF_LINK) { strlcpy(myifname, link_ntoa(&psa->sdl), IFNAMSIZ); pcolon = strchr(myifname, ':'); if (pcolon) *pcolon = '\0'; pifname = myifname; } else { pifname = ""; } fprintf(stdout, "%-20s\t%-16s\t%s\n", pgroup, plladdr, pifname); } } void ifmalist_dump(void) { struct ifmaddrs *ifmap; if (getifmaddrs(&ifmap)) err(EX_OSERR, "getifmaddrs"); ifmalist_dump_af(ifmap, AF_LINK); fputs("\n", stdout); ifmalist_dump_af(ifmap, AF_INET); #ifdef INET6 fputs("\n", stdout); ifmalist_dump_af(ifmap, AF_INET6); #endif freeifmaddrs(ifmap); }