📄 ifiter_ioctl.c
字号:
* If successful, return ISC_R_SUCCESS. * If the interface has an unsupported address family, or if * some operation on it fails, return ISC_R_IGNORE to make * the higher-level iterator code ignore it. */static isc_result_tinternal_current4(isc_interfaceiter_t *iter) { struct ifreq *ifrp; struct ifreq ifreq; int family; char strbuf[ISC_STRERRORSIZE];#if !defined(ISC_PLATFORM_HAVEIF_LADDRREQ) && defined(SIOCGLIFADDR) struct lifreq lifreq;#else char sabuf[256];#endif int i, bits, prefixlen;#ifdef __linux isc_result_t result;#endif REQUIRE(VALID_IFITER(iter)); REQUIRE (iter->pos < (unsigned int) iter->ifc.ifc_len);#ifdef __linux result = linux_if_inet6_current(iter); if (result != ISC_R_NOMORE) return (result); iter->first = ISC_TRUE;#endif ifrp = (struct ifreq *)((char *) iter->ifc.ifc_req + iter->pos); memset(&ifreq, 0, sizeof(ifreq)); memcpy(&ifreq, ifrp, sizeof(ifreq)); family = ifreq.ifr_addr.sa_family;#if defined(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(ifreq.ifr_name) <= sizeof(iter->current.name)); memset(iter->current.name, 0, sizeof(iter->current.name)); memcpy(iter->current.name, ifreq.ifr_name, sizeof(ifreq.ifr_name)); get_addr(family, &iter->current.address, (struct sockaddr *)&ifrp->ifr_addr, ifreq.ifr_name); /* * 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; /* * Ignore the HP/UX warning about "interger overflow during * conversion. It comes from its own macro definition, * and is really hard to shut up. */ if (ioctl(iter->socket, SIOCGIFFLAGS, (char *) &ifreq) < 0) { isc__strerror(errno, strbuf, sizeof(strbuf)); UNEXPECTED_ERROR(__FILE__, __LINE__, "%s: getting interface flags: %s", ifreq.ifr_name, strbuf); return (ISC_R_IGNORE); } if ((ifreq.ifr_flags & IFF_UP) != 0) iter->current.flags |= INTERFACE_F_UP;#ifdef IFF_POINTOPOINT if ((ifreq.ifr_flags & IFF_POINTOPOINT) != 0) iter->current.flags |= INTERFACE_F_POINTTOPOINT;#endif if ((ifreq.ifr_flags & IFF_LOOPBACK) != 0) iter->current.flags |= INTERFACE_F_LOOPBACK; if (family == AF_INET) goto inet;#if !defined(ISC_PLATFORM_HAVEIF_LADDRREQ) && defined(SIOCGLIFADDR) memset(&lifreq, 0, sizeof(lifreq)); memcpy(lifreq.lifr_name, iter->current.name, sizeof(lifreq.lifr_name)); memcpy(&lifreq.lifr_addr, &iter->current.address.type.in6, sizeof(iter->current.address.type.in6)); if (ioctl(iter->socket, SIOCGLIFADDR, &lifreq) < 0) { isc__strerror(errno, strbuf, sizeof(strbuf)); UNEXPECTED_ERROR(__FILE__, __LINE__, "%s: getting interface address: %s", ifreq.ifr_name, strbuf); return (ISC_R_IGNORE); } prefixlen = lifreq.lifr_addrlen;#else isc_netaddr_format(&iter->current.address, sabuf, sizeof(sabuf)); isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_INTERFACE, ISC_LOG_INFO, isc_msgcat_get(isc_msgcat, ISC_MSGSET_IFITERIOCTL, ISC_MSG_GETIFCONFIG, "prefix length for %s is unknown " "(assume 128)"), sabuf); prefixlen = 128;#endif /* * Netmask already zeroed. */ iter->current.netmask.family = family; for (i = 0; i < 16; i++) { if (prefixlen > 8) { bits = 0; prefixlen -= 8; } else { bits = 8 - prefixlen; prefixlen = 0; } iter->current.netmask.type.in6.s6_addr[i] = (~0 << bits) & 0xff; } return (ISC_R_SUCCESS); inet: if (family != AF_INET) return (ISC_R_IGNORE);#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 "interger overflow during * conversion. It comes from its own macro definition, * and is really hard to shut up. */ if (ioctl(iter->socket, SIOCGIFDSTADDR, (char *)&ifreq) < 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"), ifreq.ifr_name, strbuf); return (ISC_R_IGNORE); } get_addr(family, &iter->current.dstaddress, (struct sockaddr *)&ifreq.ifr_dstaddr, ifreq.ifr_name); }#endif /* * Get the network mask. */ memset(&ifreq, 0, sizeof(ifreq)); memcpy(&ifreq, ifrp, sizeof(ifreq)); /* * Ignore the HP/UX warning about "interger overflow during * conversion. It comes from its own macro definition, * and is really hard to shut up. */ if (ioctl(iter->socket, SIOCGIFNETMASK, (char *)&ifreq) < 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"), ifreq.ifr_name, strbuf); return (ISC_R_IGNORE); } get_addr(family, &iter->current.netmask, (struct sockaddr *)&ifreq.ifr_addr, ifreq.ifr_name); return (ISC_R_SUCCESS);}#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)static isc_result_tinternal_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 = (struct LIFREQ *)((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 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 "interger overflow during * conversion. It comes from its own macro definition, * and is really hard to shut up. */ if (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;#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 "interger overflow during * conversion. It comes from its own macro definition, * and is really hard to shut up. */ if (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 /* * 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; } return (ISC_R_SUCCESS); }#endif /* * Ignore the HP/UX warning about "interger overflow during * conversion. It comes from its own macro definition, * and is really hard to shut up. */ if (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); return (ISC_R_SUCCESS);}#endifstatic isc_result_tinternal_current(isc_interfaceiter_t *iter) {#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) if (iter->mode == 6) { iter->result6 = internal_current6(iter); if (iter->result6 != ISC_R_NOMORE) return (iter->result6); }#endif#ifdef HAVE_TRUCLUSTER if (!iter->clua_done) return(internal_current_clusteralias(iter));#endif return (internal_current4(iter));}/* * Step the iterator to the next interface. Unlike * isc_interfaceiter_next(), this may leave the iterator * positioned on an interface that will ultimately * be ignored. Return ISC_R_NOMORE if there are no more * interfaces, otherwise ISC_R_SUCCESS. */static isc_result_tinternal_next4(isc_interfaceiter_t *iter) { struct ifreq *ifrp; REQUIRE (iter->pos < (unsigned int) iter->ifc.ifc_len);#ifdef __linux if (linux_if_inet6_next(iter) == ISC_R_SUCCESS) return (ISC_R_SUCCESS); if (!iter->first) return (ISC_R_SUCCESS);#endif ifrp = (struct ifreq *)((char *) iter->ifc.ifc_req + iter->pos);#ifdef ISC_PLATFORM_HAVESALEN if (ifrp->ifr_addr.sa_len > sizeof(struct sockaddr)) iter->pos += sizeof(ifrp->ifr_name) + ifrp->ifr_addr.sa_len; else#endif iter->pos += sizeof(*ifrp); if (iter->pos >= (unsigned int) iter->ifc.ifc_len) return (ISC_R_NOMORE); return (ISC_R_SUCCESS);}#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)static isc_result_tinternal_next6(isc_interfaceiter_t *iter) { struct LIFREQ *ifrp; if (iter->result6 != ISC_R_SUCCESS && iter->result6 != ISC_R_IGNORE) return (iter->result6); REQUIRE(iter->pos6 < (unsigned int) iter->lifc.lifc_len); ifrp = (struct LIFREQ *)((char *) iter->lifc.lifc_req + iter->pos6);#ifdef ISC_PLATFORM_HAVESALEN if (ifrp->lifr_addr.sa_len > sizeof(struct sockaddr)) iter->pos6 += sizeof(ifrp->lifr_name) + ifrp->lifr_addr.sa_len; else#endif iter->pos6 += sizeof(*ifrp); if (iter->pos6 >= (unsigned int) iter->lifc.lifc_len) return (ISC_R_NOMORE); return (ISC_R_SUCCESS);}#endifstatic isc_result_tinternal_next(isc_interfaceiter_t *iter) {#ifdef HAVE_TRUCLUSTER int clua_result;#endif#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) if (iter->mode == 6) { iter->result6 = internal_next6(iter); if (iter->result6 != ISC_R_NOMORE) return (iter->result6); if (iter->first6) { iter->first6 = ISC_FALSE; return (ISC_R_SUCCESS); } }#endif#ifdef HAVE_TRUCLUSTER if (!iter->clua_done) { clua_result = clua_getaliasaddress(&iter->clua_sa, &iter->clua_context); if (clua_result != CLUA_SUCCESS) iter->clua_done = ISC_TRUE; return (ISC_R_SUCCESS); }#endif return (internal_next4(iter));}static voidinternal_destroy(isc_interfaceiter_t *iter) { (void) close(iter->socket);#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) if (iter->socket6 != -1) (void) close(iter->socket6); if (iter->buf6 != NULL) { isc_mem_put(iter->mctx, iter->buf6, iter->bufsize6); }#endif#ifdef __linux if (iter->proc != NULL) fclose(iter->proc);#endif}staticvoid internal_first(isc_interfaceiter_t *iter) {#ifdef HAVE_TRUCLUSTER int clua_result;#endif iter->pos = 0;#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) iter->pos6 = 0; if (iter->result6 == ISC_R_NOMORE) iter->result6 = ISC_R_SUCCESS; iter->first6 = ISC_TRUE;#endif#ifdef HAVE_TRUCLUSTER iter->clua_context = 0; clua_result = clua_getaliasaddress(&iter->clua_sa, &iter->clua_context); iter->clua_done = ISC_TF(clua_result != CLUA_SUCCESS);#endif#ifdef __linux linux_if_inet6_first(iter);#endif}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -