From 5fd83771641d15c418f747bd343ba6738d3875f7 Mon Sep 17 00:00:00 2001 From: Cameron Katri Date: Sun, 9 May 2021 14:20:58 -0400 Subject: Import macOS userland adv_cmds-176 basic_cmds-55 bootstrap_cmds-116.100.1 developer_cmds-66 diskdev_cmds-667.40.1 doc_cmds-53.60.1 file_cmds-321.40.3 mail_cmds-35 misc_cmds-34 network_cmds-606.40.1 patch_cmds-17 remote_cmds-63 shell_cmds-216.60.1 system_cmds-880.60.2 text_cmds-106 --- network_cmds/netstat.tproj/mcast.c | 887 +++++++++++++++++++++++++++++++++++++ 1 file changed, 887 insertions(+) create mode 100644 network_cmds/netstat.tproj/mcast.c (limited to 'network_cmds/netstat.tproj/mcast.c') diff --git a/network_cmds/netstat.tproj/mcast.c b/network_cmds/netstat.tproj/mcast.c new file mode 100644 index 0000000..3637f4d --- /dev/null +++ b/network_cmds/netstat.tproj/mcast.c @@ -0,0 +1,887 @@ +/* + * Copyright (c) 2008-2010 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 +#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); +static int ifmalist_dump_mcstat(struct ifmaddrs *); +static void in_ifinfo(struct igmp_ifinfo *); +static const char *inm_mode(u_int); +static void inm_print_sources_sysctl(uint32_t, struct in_addr); +#ifdef INET6 +static void in6_ifinfo(struct mld_ifinfo *); +static void in6m_print_sources_sysctl(uint32_t, struct in6_addr *); +static const char *inet6_n2a(struct in6_addr *); +#endif +static void printb(const char *, unsigned int, const char *); +static const char *sdl_addr_to_hex(const struct sockaddr_dl *, char *, int); + +extern char *routename6(struct sockaddr_in6 *); + +#define sa_equal(a1, a2) \ + (bcmp((a1), (a2), ((a1))->sa_len) == 0) + +#define sa_dl_equal(a1, a2) \ + ((((struct sockaddr_dl *)(a1))->sdl_len == \ + ((struct sockaddr_dl *)(a2))->sdl_len) && \ + (bcmp(LLADDR((struct sockaddr_dl *)(a1)), \ + LLADDR((struct sockaddr_dl *)(a2)), \ + ((struct sockaddr_dl *)(a1))->sdl_alen) == 0)) + +#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) + +void +ifmalist_dump_af(const struct ifmaddrs * const ifmap, int const af) +{ + const struct ifmaddrs *ifma; + sockunion_t *psa; + char myifname[IFNAMSIZ]; + char *pcolon; + char *pafname, *pifname, *plladdr = NULL, *pgroup = NULL; + + 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: + pgroup = routename6(&(psa->sin6)); + 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), sizeof(myifname)); + 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 + if (sflag) { + fputs("\n", stdout); + ifmalist_dump_mcstat(ifmap); + } + + freeifmaddrs(ifmap); +} + +static int +ifmalist_dump_mcstat(struct ifmaddrs *ifmap) +{ + char thisifname[IFNAMSIZ]; + char addrbuf[NI_MAXHOST]; + struct ifaddrs *ifap, *ifa; + struct ifmaddrs *ifma; + sockunion_t lastifasa; + sockunion_t *psa, *pgsa, *pllsa, *pifasa; + char *pcolon; + char *pafname; + uint32_t lastifindex, thisifindex; + int error; + uint32_t ifindex = 0; + + if (interface != NULL) + ifindex = if_nametoindex(interface); + + error = 0; + ifap = NULL; + lastifindex = 0; + thisifindex = 0; + lastifasa.ss.ss_family = AF_UNSPEC; + + if (getifaddrs(&ifap) != 0) { + warn("getifmaddrs"); + return (-1); + } + + for (ifma = ifmap; ifma; ifma = ifma->ifma_next) { + error = 0; + if (ifma->ifma_name == NULL || ifma->ifma_addr == NULL) + continue; + + psa = (sockunion_t *)ifma->ifma_name; + if (psa->sa.sa_family != AF_LINK) { + fprintf(stderr, + "WARNING: Kernel returned invalid data.\n"); + error = -1; + break; + } + + /* Filter on interface name. */ + thisifindex = psa->sdl.sdl_index; + if (ifindex != 0 && thisifindex != ifindex) + continue; + + /* Filter on address family. */ + pgsa = (sockunion_t *)ifma->ifma_addr; + if (af != 0 && pgsa->sa.sa_family != af) + continue; + + strlcpy(thisifname, link_ntoa(&psa->sdl), sizeof(thisifname)); + pcolon = strchr(thisifname, ':'); + if (pcolon) + *pcolon = '\0'; + + /* Only print the banner for the first ifmaddrs entry. */ + if (lastifindex == 0 || lastifindex != thisifindex) { + lastifindex = thisifindex; + fprintf(stdout, "%s:\n", thisifname); + } + + /* + * Currently, multicast joins only take place on the + * primary IPv4 address, and only on the link-local IPv6 + * address, as per IGMPv2/3 and MLDv1/2 semantics. + * Therefore, we only look up the primary address on + * the first pass. + */ + pifasa = NULL; + for (ifa = ifap; ifa; ifa = ifa->ifa_next) { + if ((strcmp(ifa->ifa_name, thisifname) != 0) || + (ifa->ifa_addr == NULL) || + (ifa->ifa_addr->sa_family != pgsa->sa.sa_family)) + continue; + /* + * For AF_INET6 only the link-local address should + * be returned. If built without IPv6 support, + * skip this address entirely. + */ + pifasa = (sockunion_t *)ifa->ifa_addr; + if (pifasa->sa.sa_family == AF_INET6 +#ifdef INET6 + && !IN6_IS_ADDR_LINKLOCAL(&pifasa->sin6.sin6_addr) +#endif + ) { + pifasa = NULL; + continue; + } + break; + } + if (pifasa == NULL) + continue; /* primary address not found */ + + if (!vflag && pifasa->sa.sa_family == AF_LINK) + continue; + + /* Parse and print primary address, if not already printed. */ + if (lastifasa.ss.ss_family == AF_UNSPEC || + ((lastifasa.ss.ss_family == AF_LINK && + !sa_dl_equal(&lastifasa.sa, &pifasa->sa)) || + !sa_equal(&lastifasa.sa, &pifasa->sa))) { + + switch (pifasa->sa.sa_family) { + case AF_INET: + pafname = "inet"; + break; + case AF_INET6: + pafname = "inet6"; + break; + case AF_LINK: + pafname = "link"; + break; + default: + pafname = "unknown"; + break; + } + + switch (pifasa->sa.sa_family) { + case AF_INET6: +#ifdef INET6 + { + const char *p = + inet6_n2a(&pifasa->sin6.sin6_addr); + strlcpy(addrbuf, p, sizeof(addrbuf)); + break; + } +#else + /* FALLTHROUGH */ +#endif + case AF_INET: + error = getnameinfo(&pifasa->sa, + pifasa->sa.sa_len, + addrbuf, sizeof(addrbuf), NULL, 0, + NI_NUMERICHOST); + if (error) + printf("getnameinfo: %s\n", + gai_strerror(error)); + break; + case AF_LINK: { + (void) sdl_addr_to_hex(&pifasa->sdl, addrbuf, + sizeof (addrbuf)); + break; + } + default: + addrbuf[0] = '\0'; + break; + } + + fprintf(stdout, "\t%s %s\n", pafname, addrbuf); + /* + * Print per-link IGMP information, if available. + */ + if (pifasa->sa.sa_family == AF_INET) { + struct igmp_ifinfo igi; + size_t mibsize, len; + int mib[5]; + + mibsize = sizeof(mib) / sizeof(mib[0]); + if (sysctlnametomib("net.inet.igmp.ifinfo", + mib, &mibsize) == -1) { + perror("sysctlnametomib"); + goto next_ifnet; + } + mib[mibsize] = thisifindex; + len = sizeof(struct igmp_ifinfo); + if (sysctl(mib, mibsize + 1, &igi, &len, NULL, + 0) == -1) { + perror("sysctl net.inet.igmp.ifinfo"); + goto next_ifnet; + } + in_ifinfo(&igi); + } +#ifdef INET6 + /* + * Print per-link MLD information, if available. + */ + if (pifasa->sa.sa_family == AF_INET6) { + struct mld_ifinfo mli; + size_t mibsize, len; + int mib[5]; + + mibsize = sizeof(mib) / sizeof(mib[0]); + if (sysctlnametomib("net.inet6.mld.ifinfo", + mib, &mibsize) == -1) { + perror("sysctlnametomib"); + goto next_ifnet; + } + mib[mibsize] = thisifindex; + len = sizeof(struct mld_ifinfo); + if (sysctl(mib, mibsize + 1, &mli, &len, NULL, + 0) == -1) { + perror("sysctl net.inet6.mld.ifinfo"); + goto next_ifnet; + } + in6_ifinfo(&mli); + } +#endif /* INET6 */ +#if defined(INET6) +next_ifnet: +#endif + lastifasa = *pifasa; + } + + /* Print this group address. */ +#ifdef INET6 + if (pgsa->sa.sa_family == AF_INET6) { + const char *p = inet6_n2a(&pgsa->sin6.sin6_addr); + strlcpy(addrbuf, p, sizeof(addrbuf)); + } else +#endif + if (pgsa->sa.sa_family == AF_INET) { + error = getnameinfo(&pgsa->sa, pgsa->sa.sa_len, + addrbuf, sizeof(addrbuf), NULL, 0, NI_NUMERICHOST); + if (error) + printf("getnameinfo: %s\n", + gai_strerror(error)); + } else { + (void) sdl_addr_to_hex(&pgsa->sdl, addrbuf, + sizeof (addrbuf)); + } + + fprintf(stdout, "\t\tgroup %s", addrbuf); + if (pgsa->sa.sa_family == AF_INET) { + inm_print_sources_sysctl(thisifindex, + pgsa->sin.sin_addr); + } +#ifdef INET6 + if (pgsa->sa.sa_family == AF_INET6) { + in6m_print_sources_sysctl(thisifindex, + &pgsa->sin6.sin6_addr); + } +#endif + fprintf(stdout, "\n"); + + /* Link-layer mapping, if present. */ + pllsa = (sockunion_t *)ifma->ifma_lladdr; + if (pllsa != NULL) { + (void) sdl_addr_to_hex(&pllsa->sdl, addrbuf, + sizeof (addrbuf)); + fprintf(stdout, "\t\t\tmcast-macaddr %s\n", addrbuf); + } + } + + if (ifap != NULL) + freeifaddrs(ifap); + + return (error); +} + +static void +in_ifinfo(struct igmp_ifinfo *igi) +{ + + printf("\t"); + switch (igi->igi_version) { + case IGMP_VERSION_1: + case IGMP_VERSION_2: + case IGMP_VERSION_3: + printf("igmpv%d", igi->igi_version); + break; + default: + printf("igmpv?(%d)", igi->igi_version); + break; + } + printb(" flags", igi->igi_flags, "\020\1SILENT\2LOOPBACK"); + if (igi->igi_version == IGMP_VERSION_3) { + printf(" rv %u qi %u qri %u uri %u", + igi->igi_rv, igi->igi_qi, igi->igi_qri, igi->igi_uri); + } + if (vflag >= 2) { + printf(" v1timer %u v2timer %u v3timer %u", + igi->igi_v1_timer, igi->igi_v2_timer, igi->igi_v3_timer); + } + printf("\n"); +} + +static const char *inm_modes[] = { + "undefined", + "include", + "exclude", +}; + +static const char * +inm_mode(u_int mode) +{ + + if (mode >= MCAST_UNDEFINED && mode <= MCAST_EXCLUDE) + return (inm_modes[mode]); + return (NULL); +} + +/* + * Retrieve per-group source filter mode and lists via sysctl. + */ +static void +inm_print_sources_sysctl(uint32_t ifindex, struct in_addr gina) +{ +#define MAX_SYSCTL_TRY 5 + int mib[7]; + int ntry = 0; + size_t mibsize; + size_t len; + size_t needed; + size_t cnt; + int i; + char *buf; + struct in_addr *pina; + uint32_t *p; + uint32_t fmode; + const char *modestr; + + mibsize = sizeof(mib) / sizeof(mib[0]); + if (sysctlnametomib("net.inet.ip.mcast.filters", mib, &mibsize) == -1) { + perror("sysctlnametomib"); + return; + } + + needed = 0; + mib[5] = ifindex; + mib[6] = gina.s_addr; /* 32 bits wide */ + mibsize = sizeof(mib) / sizeof(mib[0]); + do { + if (sysctl(mib, mibsize, NULL, &needed, NULL, 0) == -1) { + perror("sysctl net.inet.ip.mcast.filters"); + return; + } + if ((buf = malloc(needed)) == NULL) { + perror("malloc"); + return; + } + if (sysctl(mib, mibsize, buf, &needed, NULL, 0) == -1) { + if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) { + perror("sysctl"); + goto out_free; + } + free(buf); + buf = NULL; + } + } while (buf == NULL); + + len = needed; + if (len < sizeof(uint32_t)) { + perror("sysctl"); + goto out_free; + } + + p = (uint32_t *)buf; + fmode = *p++; + len -= sizeof(uint32_t); + + modestr = inm_mode(fmode); + if (modestr) + printf(" mode %s", modestr); + else + printf(" mode (%u)", fmode); + + if (vflag == 0) + goto out_free; + + cnt = len / sizeof(struct in_addr); + pina = (struct in_addr *)p; + + for (i = 0; i < cnt; i++) { + if (i == 0) + printf(" srcs "); + fprintf(stdout, "%s%s", (i == 0 ? "" : ","), + inet_ntoa(*pina++)); + len -= sizeof(struct in_addr); + } + if (len > 0) { + fprintf(stderr, "warning: %u trailing bytes from %s\n", + (unsigned int)len, "net.inet.ip.mcast.filters"); + } + +out_free: + free(buf); +#undef MAX_SYSCTL_TRY +} + +#ifdef INET6 + +static void +in6_ifinfo(struct mld_ifinfo *mli) +{ + + printf("\t"); + switch (mli->mli_version) { + case MLD_VERSION_1: + case MLD_VERSION_2: + printf("mldv%d", mli->mli_version); + break; + default: + printf("mldv?(%d)", mli->mli_version); + break; + } + printb(" flags", mli->mli_flags, "\020\1SILENT"); + if (mli->mli_version == MLD_VERSION_2) { + printf(" rv %u qi %u qri %u uri %u", + mli->mli_rv, mli->mli_qi, mli->mli_qri, mli->mli_uri); + } + if (vflag >= 2) { + printf(" v1timer %u v2timer %u", mli->mli_v1_timer, + mli->mli_v2_timer); + } + printf("\n"); +} + +/* + * Retrieve MLD per-group source filter mode and lists via sysctl. + * + * Note: The 128-bit IPv6 group addres needs to be segmented into + * 32-bit pieces for marshaling to sysctl. So the MIB name ends + * up looking like this: + * a.b.c.d.e.ifindex.g[0].g[1].g[2].g[3] + * Assumes that pgroup originated from the kernel, so its components + * are already in network-byte order. + */ +static void +in6m_print_sources_sysctl(uint32_t ifindex, struct in6_addr *pgroup) +{ +#define MAX_SYSCTL_TRY 5 + char addrbuf[INET6_ADDRSTRLEN]; + int mib[10]; + int ntry = 0; + int *pi; + size_t mibsize; + size_t len; + size_t needed; + size_t cnt; + int i; + char *buf; + struct in6_addr *pina; + uint32_t *p; + uint32_t fmode; + const char *modestr; + + mibsize = sizeof(mib) / sizeof(mib[0]); + if (sysctlnametomib("net.inet6.ip6.mcast.filters", mib, + &mibsize) == -1) { + perror("sysctlnametomib"); + return; + } + + needed = 0; + mib[5] = ifindex; + pi = (int *)pgroup; + for (i = 0; i < 4; i++) + mib[6 + i] = *pi++; + + mibsize = sizeof(mib) / sizeof(mib[0]); + do { + if (sysctl(mib, mibsize, NULL, &needed, NULL, 0) == -1) { + perror("sysctl net.inet6.ip6.mcast.filters"); + return; + } + if ((buf = malloc(needed)) == NULL) { + perror("malloc"); + return; + } + if (sysctl(mib, mibsize, buf, &needed, NULL, 0) == -1) { + if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) { + perror("sysctl"); + goto out_free; + } + free(buf); + buf = NULL; + } + } while (buf == NULL); + + len = needed; + if (len < sizeof(uint32_t)) { + perror("sysctl"); + goto out_free; + } + + p = (uint32_t *)buf; + fmode = *p++; + len -= sizeof(uint32_t); + + modestr = inm_mode(fmode); + if (modestr) + printf(" mode %s", modestr); + else + printf(" mode (%u)", fmode); + + if (vflag == 0) + goto out_free; + + cnt = len / sizeof(struct in6_addr); + pina = (struct in6_addr *)p; + + for (i = 0; i < cnt; i++) { + if (i == 0) + printf(" srcs "); + inet_ntop(AF_INET6, (const char *)pina++, addrbuf, + INET6_ADDRSTRLEN); + fprintf(stdout, "%s%s", (i == 0 ? "" : ","), addrbuf); + len -= sizeof(struct in6_addr); + } + if (len > 0) { + fprintf(stderr, "warning: %u trailing bytes from %s\n", + (unsigned int)len, "net.inet6.ip6.mcast.filters"); + } + +out_free: + free(buf); +#undef MAX_SYSCTL_TRY +} + +static const char * +inet6_n2a(struct in6_addr *p) +{ + static char buf[NI_MAXHOST]; + struct sockaddr_in6 sin6; + u_int32_t scopeid; + const int niflags = NI_NUMERICHOST; + + memset(&sin6, 0, sizeof(sin6)); + sin6.sin6_family = AF_INET6; + sin6.sin6_len = sizeof(struct sockaddr_in6); + sin6.sin6_addr = *p; + if (IN6_IS_ADDR_LINKLOCAL(p) || IN6_IS_ADDR_MC_LINKLOCAL(p) || + IN6_IS_ADDR_MC_NODELOCAL(p)) { + scopeid = ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]); + if (scopeid) { + sin6.sin6_scope_id = scopeid; + sin6.sin6_addr.s6_addr[2] = 0; + sin6.sin6_addr.s6_addr[3] = 0; + } + } + if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, + buf, sizeof(buf), NULL, 0, niflags) == 0) { + return (buf); + } else { + return ("(invalid)"); + } +} +#endif /* INET6 */ + +/* + * Print a value a la the %b format of the kernel's printf + */ +void +printb(const char *s, unsigned int v, const char *bits) +{ + int i, any = 0; + char c; + + if (bits && *bits == 8) + printf("%s=%o", s, v); + else + printf("%s=%x", s, v); + bits++; + if (bits) { + putchar('<'); + while ((i = *bits++) != '\0') { + if (v & (1 << (i-1))) { + if (any) + putchar(','); + any = 1; + for (; (c = *bits) > 32; bits++) + putchar(c); + } else + for (; *bits > 32; bits++) + ; + } + putchar('>'); + } +} + +/* + * convert hardware address to hex string for logging errors. + */ +static const char * +sdl_addr_to_hex(const struct sockaddr_dl *sdl, char *orig_buf, int buflen) +{ + char *buf = orig_buf; + int i; + const u_char *lladdr; + int maxbytes = buflen / 3; + + lladdr = (u_char *)(size_t)sdl->sdl_data + sdl->sdl_nlen; + + if (maxbytes > sdl->sdl_alen) { + maxbytes = sdl->sdl_alen; + } + *buf = '\0'; + for (i = 0; i < maxbytes; i++) { + snprintf(buf, 3, "%02x", lladdr[i]); + buf += 2; + *buf = (i == maxbytes - 1) ? '\0' : ':'; + buf++; + } + return (orig_buf); +} + -- cgit v1.2.3-56-ge451