/* get ia6_flags for link-local addr on if. returns -1 on error. */ static int get_llflag(const char *name) { #ifdef HAVE_GETIFADDRS struct ifaddrs *ifap, *ifa; struct in6_ifreq ifr6; struct sockaddr_in6 *sin6; int s; if ((s = socket(PF_INET6, SOCK_DGRAM, 0)) < 0) { warnmsg(LOG_ERR, __func__, "socket(SOCK_DGRAM): %s", strerror(errno)); exit(1); } if (getifaddrs(&ifap) != 0) { warnmsg(LOG_ERR, __func__, "etifaddrs: %s", strerror(errno)); exit(1); } for (ifa = ifap; ifa; ifa = ifa->ifa_next) { if (strlen(ifa->ifa_name) != strlen(name) || strncmp(ifa->ifa_name, name, strlen(name)) != 0) continue; if (ifa->ifa_addr->sa_family != AF_INET6) continue; sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; if (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) continue; memset(&ifr6, 0, sizeof(ifr6)); strcpy(ifr6.ifr_name, name); memcpy(&ifr6.ifr_ifru.ifru_addr, sin6, sin6->sin6_len); if (ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) < 0) { warnmsg(LOG_ERR, __func__, "ioctl(SIOCGIFAFLAG_IN6): %s", strerror(errno)); exit(1); } freeifaddrs(ifap); close(s); return ifr6.ifr_ifru.ifru_flags6; } freeifaddrs(ifap); close(s); return -1; #else int s; unsigned int maxif; struct ifreq *iflist; struct ifconf ifconf; struct ifreq *ifr, *ifr_end; struct sockaddr_in6 *sin6; struct in6_ifreq ifr6; maxif = if_maxindex() + 1; iflist = (struct ifreq *)malloc(maxif * BUFSIZ); /* XXX */ if (iflist == NULL) { warnmsg(LOG_ERR, __func__, "not enough core"); exit(1); } if ((s = socket(PF_INET6, SOCK_DGRAM, 0)) < 0) { warnmsg(LOG_ERR, __func__, "socket(SOCK_DGRAM): %s", strerror(errno)); exit(1); } memset(&ifconf, 0, sizeof(ifconf)); ifconf.ifc_req = iflist; ifconf.ifc_len = maxif * BUFSIZ; /* XXX */ if (ioctl(s, SIOCGIFCONF, &ifconf) < 0) { warnmsg(LOG_ERR, __func__, "ioctl(SIOCGIFCONF): %s", strerror(errno)); exit(1); } /* Look for this interface in the list */ ifr_end = (struct ifreq *) (ifconf.ifc_buf + ifconf.ifc_len); for (ifr = ifconf.ifc_req; ifr < ifr_end; ifr = (struct ifreq *) ((char *) &ifr->ifr_addr + ifr->ifr_addr.sa_len)) { if (strlen(ifr->ifr_name) != strlen(name) || strncmp(ifr->ifr_name, name, strlen(name)) != 0) continue; if (ifr->ifr_addr.sa_family != AF_INET6) continue; sin6 = (struct sockaddr_in6 *)&ifr->ifr_addr; if (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) continue; memset(&ifr6, 0, sizeof(ifr6)); strcpy(ifr6.ifr_name, name); memcpy(&ifr6.ifr_ifru.ifru_addr, sin6, sin6->sin6_len); if (ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) < 0) { warnmsg(LOG_ERR, __func__, "ioctl(SIOCGIFAFLAG_IN6): %s", strerror(errno)); exit(1); } free(iflist); close(s); return ifr6.ifr_ifru.ifru_flags6; } free(iflist); close(s); return -1; #endif }
/* * Return the interface list */ int ifaddrlist(register struct ifaddrlist **ipaddrp, register char *errbuf, size_t l) { #ifdef HAVE_GETIFADDRS struct ifaddrs *ifap, *ifa; int nipaddr; struct ifaddrlist *al; struct ifaddrlist *ifaddrlist; unsigned int maxif; struct sockaddr_in *sin; #if 1 maxif = if_maxindex() * 3; /* 3 is a magic number... */ #else maxif = 64; #endif ifaddrlist = (struct ifaddrlist *)malloc(maxif * sizeof(struct ifaddrlist)); if (ifaddrlist == NULL) return -1; if (getifaddrs(&ifap) != 0) return -1; al = ifaddrlist; nipaddr = 0; for (ifa = ifap; ifa && nipaddr < maxif; ifa = ifa->ifa_next) { if (ifa->ifa_addr->sa_family != AF_INET) continue; if (((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr == htonl(INADDR_ANY)) continue; if ((ifa->ifa_flags & IFF_UP) == 0) continue; #ifdef IFF_LOOPBACK if ((ifa->ifa_flags & IFF_LOOPBACK) != 0) continue; #else if (strcmp(ifa->ifa_name, "lo0") == 0) continue; #endif sin = (struct sockaddr_in *)ifa->ifa_addr; al->addr = sin->sin_addr.s_addr; al->device = strdup(ifa->ifa_name); ++al; ++nipaddr; } *ipaddrp = ifaddrlist; #ifdef HAVE_FREEIFADDRS freeifaddrs(ifap); #else free(ifap); #endif return nipaddr; #else register int fd, nipaddr; #ifdef HAVE_SOCKADDR_SA_LEN register int n; #endif register struct ifreq *ifrp, *ifend, *ifnext, *mp; register struct sockaddr_in *sin; register struct ifaddrlist *al; struct ifconf ifc; struct ifreq *ibuf, ifr; char device[sizeof(ifr.ifr_name) + 1]; struct ifaddrlist *ifaddrlist; unsigned int maxif; #if 1 maxif = if_maxindex() * 3; /* 3 is a magic number... */ #else maxif = 64; #endif ifaddrlist = (struct ifaddrlist *)malloc(maxif * sizeof(struct ifaddrlist)); if (ifaddrlist == NULL) return -1; ibuf = (struct ifreq *)malloc(maxif * sizeof(struct ifreq)); if (ibuf == NULL) { free(ifaddrlist); return -1; } fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) { (void)snprintf(errbuf, l, "socket: %s", strerror(errno)); free(ifaddrlist); free(ibuf); return (-1); } ifc.ifc_len = maxif * sizeof(struct ifreq); ifc.ifc_buf = (caddr_t)ibuf; if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0 || ifc.ifc_len < sizeof(struct ifreq)) { (void)snprintf(errbuf, l, "SIOCGIFCONF: %s", strerror(errno)); (void)close(fd); free(ifaddrlist); free(ibuf); return (-1); } ifrp = ibuf; ifend = (struct ifreq *)((char *)ibuf + ifc.ifc_len); al = ifaddrlist; mp = NULL; nipaddr = 0; for (; ifrp < ifend; ifrp = ifnext) { #ifdef HAVE_SOCKADDR_SA_LEN n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name); if (n < sizeof(*ifrp)) ifnext = ifrp + 1; else ifnext = (struct ifreq *)((char *)ifrp + n); if (ifrp->ifr_addr.sa_family != AF_INET) continue; #else ifnext = ifrp + 1; #endif if (((struct sockaddr_in *)&ifrp->ifr_addr)->sin_addr.s_addr == htonl(INADDR_ANY)) continue; /* * Need a template to preserve address info that is * used below to locate the next entry. (Otherwise, * SIOCGIFFLAGS stomps over it because the requests * are returned in a union.) */ strncpy(ifr.ifr_name, ifrp->ifr_name, sizeof(ifrp->ifr_name)); if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifr) < 0) { if (errno == ENXIO) continue; (void)snprintf(errbuf, l, "SIOCGIFFLAGS: %.*s: %s", (int)sizeof(ifr.ifr_name), ifr.ifr_name, strerror(errno)); (void)close(fd); free(ifaddrlist); free(ibuf); return (-1); } /* Must be up and not the loopback */ if ((ifr.ifr_flags & IFF_UP) == 0 || ISLOOPBACK(&ifr)) continue; (void)strncpy(device, ifr.ifr_name, sizeof(ifr.ifr_name)); device[sizeof(device) - 1] = '\0'; if (ioctl(fd, SIOCGIFADDR, (char *)&ifr) < 0) { (void)snprintf(errbuf, l, "SIOCGIFADDR: %s: %s", device, strerror(errno)); (void)close(fd); free(ifaddrlist); free(ibuf); return (-1); } sin = (struct sockaddr_in *)&ifr.ifr_addr; al->addr = sin->sin_addr.s_addr; al->device = strdup(device); ++al; ++nipaddr; } (void)close(fd); *ipaddrp = ifaddrlist; free(ibuf); return (nipaddr); #endif }