static isc_result_t linux_if_inet6_current(isc_interfaceiter_t *iter) { char address[33]; char name[IF_NAMESIZE+1]; struct in6_addr addr6; int ifindex, prefix, flag3, flag4; int res; unsigned int i; if (iter->valid != ISC_R_SUCCESS) return (iter->valid); if (iter->proc == NULL) { isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_INTERFACE, ISC_LOG_ERROR, "/proc/net/if_inet6:iter->proc == NULL"); return (ISC_R_FAILURE); } res = sscanf(iter->entry, "%32[a-f0-9] %x %x %x %x %16s\n", address, &ifindex, &prefix, &flag3, &flag4, name); if (res != 6) { isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_INTERFACE, ISC_LOG_ERROR, "/proc/net/if_inet6:sscanf() -> %d (expected 6)", res); return (ISC_R_FAILURE); } if (strlen(address) != 32) { isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_INTERFACE, ISC_LOG_ERROR, "/proc/net/if_inet6:strlen(%s) != 32", address); return (ISC_R_FAILURE); } for (i = 0; i < 16; i++) { unsigned char byte; static const char hex[] = "0123456789abcdef"; byte = ((strchr(hex, address[i * 2]) - hex) << 4) | (strchr(hex, address[i * 2 + 1]) - hex); addr6.s6_addr[i] = byte; } iter->current.af = AF_INET6; iter->current.flags = INTERFACE_F_UP; isc_netaddr_fromin6(&iter->current.address, &addr6); if (isc_netaddr_islinklocal(&iter->current.address)) { isc_netaddr_setzone(&iter->current.address, (isc_uint32_t)ifindex); } for (i = 0; i < 16; i++) { if (prefix > 8) { addr6.s6_addr[i] = 0xff; prefix -= 8; } else { addr6.s6_addr[i] = (0xff << (8 - prefix)) & 0xff; prefix = 0; } } isc_netaddr_fromin6(&iter->current.netmask, &addr6); strncpy(iter->current.name, name, sizeof(iter->current.name)); return (ISC_R_SUCCESS); }
isc_boolean_t isc_sockaddr_islinklocal(const isc_sockaddr_t *sockaddr) { isc_netaddr_t netaddr; if (sockaddr->type.sa.sa_family == AF_INET6) { isc_netaddr_fromsockaddr(&netaddr, sockaddr); return (isc_netaddr_islinklocal(&netaddr)); } return (ISC_FALSE); }
static isc_result_t internal_current6(isc_interfaceiter_t *iter) { struct LIFREQ *ifrp; struct LIFREQ lifreq; int family; char strbuf[ISC_STRERRORSIZE]; int fd; REQUIRE(VALID_IFITER(iter)); if (iter->result6 != ISC_R_SUCCESS) return (iter->result6); REQUIRE(iter->pos6 < (unsigned int) iter->lifc.lifc_len); ifrp = (void *)((char *)iter->lifc.lifc_req + iter->pos6); memset(&lifreq, 0, sizeof(lifreq)); memcpy(&lifreq, ifrp, sizeof(lifreq)); family = lifreq.lifr_addr.ss_family; #ifdef ISC_PLATFORM_HAVEIPV6 if (family != AF_INET && family != AF_INET6) #else if (family != AF_INET) #endif return (ISC_R_IGNORE); memset(&iter->current, 0, sizeof(iter->current)); iter->current.af = family; INSIST(sizeof(lifreq.lifr_name) <= sizeof(iter->current.name)); memset(iter->current.name, 0, sizeof(iter->current.name)); memcpy(iter->current.name, lifreq.lifr_name, sizeof(lifreq.lifr_name)); get_addr(family, &iter->current.address, (struct sockaddr *)&lifreq.lifr_addr, lifreq.lifr_name); if (isc_netaddr_islinklocal(&iter->current.address)) isc_netaddr_setzone(&iter->current.address, (isc_uint32_t)lifreq.lifr_index); /* * If the interface does not have a address ignore it. */ switch (family) { case AF_INET: if (iter->current.address.type.in.s_addr == htonl(INADDR_ANY)) return (ISC_R_IGNORE); break; case AF_INET6: if (memcmp(&iter->current.address.type.in6, &in6addr_any, sizeof(in6addr_any)) == 0) return (ISC_R_IGNORE); break; } /* * Get interface flags. */ iter->current.flags = 0; if (family == AF_INET6) fd = iter->socket6; else fd = iter->socket; /* * Ignore the HP/UX warning about "integer overflow during * conversion. It comes from its own macro definition, * and is really hard to shut up. */ if (isc_ioctl(fd, SIOCGLIFFLAGS, (char *) &lifreq) < 0) { isc__strerror(errno, strbuf, sizeof(strbuf)); UNEXPECTED_ERROR(__FILE__, __LINE__, "%s: getting interface flags: %s", lifreq.lifr_name, strbuf); return (ISC_R_IGNORE); } if ((lifreq.lifr_flags & IFF_UP) != 0) iter->current.flags |= INTERFACE_F_UP; #ifdef IFF_POINTOPOINT if ((lifreq.lifr_flags & IFF_POINTOPOINT) != 0) iter->current.flags |= INTERFACE_F_POINTTOPOINT; #endif if ((lifreq.lifr_flags & IFF_LOOPBACK) != 0) iter->current.flags |= INTERFACE_F_LOOPBACK; if ((lifreq.lifr_flags & IFF_BROADCAST) != 0) { iter->current.flags |= INTERFACE_F_BROADCAST; } #ifdef IFF_MULTICAST if ((lifreq.lifr_flags & IFF_MULTICAST) != 0) { iter->current.flags |= INTERFACE_F_MULTICAST; } #endif #ifdef IFF_POINTOPOINT /* * If the interface is point-to-point, get the destination address. */ if ((iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0) { /* * Ignore the HP/UX warning about "integer overflow during * conversion. It comes from its own macro definition, * and is really hard to shut up. */ if (isc_ioctl(fd, SIOCGLIFDSTADDR, (char *)&lifreq) < 0) { isc__strerror(errno, strbuf, sizeof(strbuf)); UNEXPECTED_ERROR(__FILE__, __LINE__, isc_msgcat_get(isc_msgcat, ISC_MSGSET_IFITERIOCTL, ISC_MSG_GETDESTADDR, "%s: getting " "destination address: %s"), lifreq.lifr_name, strbuf); return (ISC_R_IGNORE); } get_addr(family, &iter->current.dstaddress, (struct sockaddr *)&lifreq.lifr_dstaddr, lifreq.lifr_name); } #endif #ifdef SIOCGLIFBRDADDR if ((iter->current.flags & INTERFACE_F_BROADCAST) != 0) { /* * Ignore the HP/UX warning about "integer overflow during * conversion. It comes from its own macro definition, * and is really hard to shut up. */ if (isc_ioctl(iter->socket, SIOCGLIFBRDADDR, (char *)&lifreq) < 0) { isc__strerror(errno, strbuf, sizeof(strbuf)); UNEXPECTED_ERROR(__FILE__, __LINE__, isc_msgcat_get(isc_msgcat, ISC_MSGSET_IFITERIOCTL, ISC_MSG_GETBCSTADDR, "%s: getting " "broadcast address: %s"), lifreq.lifr_name, strbuf); return (ISC_R_IGNORE); } get_addr(family, &iter->current.broadcast, (struct sockaddr *)&lifreq.lifr_broadaddr, lifreq.lifr_name); } #endif /* SIOCGLIFBRDADDR */ /* * Get the network mask. Netmask already zeroed. */ memset(&lifreq, 0, sizeof(lifreq)); memcpy(&lifreq, ifrp, sizeof(lifreq)); #ifdef lifr_addrlen /* * Special case: if the system provides lifr_addrlen member, the * netmask of an IPv6 address can be derived from the length, since * an IPv6 address always has a contiguous mask. */ if (family == AF_INET6) { int i, bits; iter->current.netmask.family = family; for (i = 0; i < lifreq.lifr_addrlen; i += 8) { bits = lifreq.lifr_addrlen - i; bits = (bits < 8) ? (8 - bits) : 0; iter->current.netmask.type.in6.s6_addr[i / 8] = (~0 << bits) & 0xff; } #ifdef ISC_PLATFORM_HAVEIFNAMETOINDEX iter->current.ifindex = if_nametoindex(iter->current.name); #endif return (ISC_R_SUCCESS); } #endif /* * Ignore the HP/UX warning about "integer overflow during * conversion. It comes from its own macro definition, * and is really hard to shut up. */ if (isc_ioctl(fd, SIOCGLIFNETMASK, (char *)&lifreq) < 0) { isc__strerror(errno, strbuf, sizeof(strbuf)); UNEXPECTED_ERROR(__FILE__, __LINE__, isc_msgcat_get(isc_msgcat, ISC_MSGSET_IFITERIOCTL, ISC_MSG_GETNETMASK, "%s: getting netmask: %s"), lifreq.lifr_name, strbuf); return (ISC_R_IGNORE); } get_addr(family, &iter->current.netmask, (struct sockaddr *)&lifreq.lifr_addr, lifreq.lifr_name); #ifdef ISC_PLATFORM_HAVEIFNAMETOINDEX iter->current.ifindex = if_nametoindex(iter->current.name); #endif return (ISC_R_SUCCESS); }