📄 ifiter_ioctl.c
字号:
/* * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. *//* $Id: ifiter_ioctl.c,v 1.19.2.5.2.14 2004/06/22 04:40:23 marka Exp $ *//* * Obtain the list of network interfaces using the SIOCGLIFCONF ioctl. * See netintro(4). */#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)#ifdef ISC_PLATFORM_HAVEIF_LADDRCONF#define lifc_len iflc_len#define lifc_buf iflc_buf#define lifc_req iflc_req#define LIFCONF if_laddrconf#else#define ISC_HAVE_LIFC_FAMILY 1#define ISC_HAVE_LIFC_FLAGS 1#define LIFCONF lifconf#endif#ifdef ISC_PLATFORM_HAVEIF_LADDRREQ#define lifr_addr iflr_addr#define lifr_name iflr_name#define lifr_dstaddr iflr_dstaddr#define lifr_flags iflr_flags#define ss_family sa_family#define LIFREQ if_laddrreq#else#define LIFREQ lifreq#endif#endif#define IFITER_MAGIC ISC_MAGIC('I', 'F', 'I', 'T')#define VALID_IFITER(t) ISC_MAGIC_VALID(t, IFITER_MAGIC)#define ISC_IF_INET6_SZ \ sizeof("00000000000000000000000000000001 01 80 10 80 XXXXXXloXXXXXXXX\n")struct isc_interfaceiter { unsigned int magic; /* Magic number. */ isc_mem_t *mctx; int mode; int socket; struct ifconf ifc; void *buf; /* Buffer for sysctl data. */ unsigned int bufsize; /* Bytes allocated. */ unsigned int pos; /* Current offset in SIOCGIFCONF data */#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) int socket6; struct LIFCONF lifc; void *buf6; /* Buffer for sysctl data. */ unsigned int bufsize6; /* Bytes allocated. */ unsigned int pos6; /* Current offset in SIOCGLIFCONF data */ isc_result_t result6; /* Last result code. */ isc_boolean_t first6;#endif#ifdef HAVE_TRUCLUSTER int clua_context; /* Cluster alias context */ isc_boolean_t clua_done; struct sockaddr clua_sa;#endif#ifdef __linux FILE * proc; char entry[ISC_IF_INET6_SZ]; isc_result_t valid; isc_boolean_t first;#endif isc_interface_t current; /* Current interface data. */ isc_result_t result; /* Last result code. */};#ifdef HAVE_TRUCLUSTER#include <clua/clua.h>#include <sys/socket.h>#endif/* * Size of buffer for SIOCGLIFCONF, in bytes. We assume no sane system * will have more than a megabyte of interface configuration data. */#define IFCONF_BUFSIZE_INITIAL 4096#define IFCONF_BUFSIZE_MAX 1048576#ifdef __linux#ifndef IF_NAMESIZE# ifdef IFNAMSIZ# define IF_NAMESIZE IFNAMSIZ # else# define IF_NAMESIZE 16# endif#endif#endifstatic isc_result_tgetbuf4(isc_interfaceiter_t *iter) { char strbuf[ISC_STRERRORSIZE]; iter->bufsize = IFCONF_BUFSIZE_INITIAL; for (;;) { iter->buf = isc_mem_get(iter->mctx, iter->bufsize); if (iter->buf == NULL) return (ISC_R_NOMEMORY); memset(&iter->ifc.ifc_len, 0, sizeof(iter->ifc.ifc_len)); iter->ifc.ifc_len = iter->bufsize; iter->ifc.ifc_buf = iter->buf; /* * 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, SIOCGIFCONF, (char *)&iter->ifc) == -1) { if (errno != EINVAL) { isc__strerror(errno, strbuf, sizeof(strbuf)); UNEXPECTED_ERROR(__FILE__, __LINE__, isc_msgcat_get(isc_msgcat, ISC_MSGSET_IFITERIOCTL, ISC_MSG_GETIFCONFIG, "get interface " "configuration: %s"), strbuf); goto unexpected; } /* * EINVAL. Retry with a bigger buffer. */ } else { /* * The ioctl succeeded. * Some OS's just return what will fit rather * than set EINVAL if the buffer is too small * to fit all the interfaces in. If * ifc.lifc_len is too near to the end of the * buffer we will grow it just in case and * retry. */ if (iter->ifc.ifc_len + 2 * sizeof(struct ifreq) < iter->bufsize) break; } if (iter->bufsize >= IFCONF_BUFSIZE_MAX) { UNEXPECTED_ERROR(__FILE__, __LINE__, isc_msgcat_get(isc_msgcat, ISC_MSGSET_IFITERIOCTL, ISC_MSG_BUFFERMAX, "get interface " "configuration: " "maximum buffer " "size exceeded")); goto unexpected; } isc_mem_put(iter->mctx, iter->buf, iter->bufsize); iter->bufsize *= 2; } return (ISC_R_SUCCESS); unexpected: isc_mem_put(iter->mctx, iter->buf, iter->bufsize); iter->buf = NULL; return (ISC_R_UNEXPECTED);}#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)static isc_result_tgetbuf6(isc_interfaceiter_t *iter) { char strbuf[ISC_STRERRORSIZE]; isc_result_t result; iter->bufsize6 = IFCONF_BUFSIZE_INITIAL; for (;;) { iter->buf6 = isc_mem_get(iter->mctx, iter->bufsize6); if (iter->buf6 == NULL) return (ISC_R_NOMEMORY); memset(&iter->lifc, 0, sizeof(iter->lifc));#ifdef ISC_HAVE_LIFC_FAMILY iter->lifc.lifc_family = AF_INET6;#endif#ifdef ISC_HAVE_LIFC_FLAGS iter->lifc.lifc_flags = 0;#endif iter->lifc.lifc_len = iter->bufsize6; iter->lifc.lifc_buf = iter->buf6; /* * 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->socket6, SIOCGLIFCONF, (char *)&iter->lifc) == -1) {#ifdef __hpux /* * IPv6 interface scanning is not available on all * kernels w/ IPv6 sockets. */ if (errno == ENOENT) { isc__strerror(errno, strbuf, sizeof(strbuf)); isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_INTERFACE, ISC_LOG_DEBUG(1), isc_msgcat_get(isc_msgcat, ISC_MSGSET_IFITERIOCTL, ISC_MSG_GETIFCONFIG, "get interface " "configuration: %s"), strbuf); result = ISC_R_FAILURE; goto cleanup; }#endif if (errno != EINVAL) { isc__strerror(errno, strbuf, sizeof(strbuf)); UNEXPECTED_ERROR(__FILE__, __LINE__, isc_msgcat_get(isc_msgcat, ISC_MSGSET_IFITERIOCTL, ISC_MSG_GETIFCONFIG, "get interface " "configuration: %s"), strbuf); result = ISC_R_UNEXPECTED; goto cleanup; } /* * EINVAL. Retry with a bigger buffer. */ } else { /* * The ioctl succeeded. * Some OS's just return what will fit rather * than set EINVAL if the buffer is too small * to fit all the interfaces in. If * ifc.ifc_len is too near to the end of the * buffer we will grow it just in case and * retry. */ if (iter->lifc.lifc_len + 2 * sizeof(struct LIFREQ) < iter->bufsize6) break; } if (iter->bufsize6 >= IFCONF_BUFSIZE_MAX) { UNEXPECTED_ERROR(__FILE__, __LINE__, isc_msgcat_get(isc_msgcat, ISC_MSGSET_IFITERIOCTL, ISC_MSG_BUFFERMAX, "get interface " "configuration: " "maximum buffer " "size exceeded")); result = ISC_R_UNEXPECTED; goto cleanup; } isc_mem_put(iter->mctx, iter->buf6, iter->bufsize6); iter->bufsize6 *= 2; } if (iter->lifc.lifc_len != 0) iter->mode = 6; return (ISC_R_SUCCESS); cleanup: isc_mem_put(iter->mctx, iter->buf6, iter->bufsize6); iter->buf6 = NULL; return (result);}#endifisc_result_tisc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) { isc_interfaceiter_t *iter; isc_result_t result; char strbuf[ISC_STRERRORSIZE]; REQUIRE(mctx != NULL); REQUIRE(iterp != NULL); REQUIRE(*iterp == NULL); iter = isc_mem_get(mctx, sizeof(*iter)); if (iter == NULL) return (ISC_R_NOMEMORY); iter->mctx = mctx; iter->mode = 4; iter->buf = NULL; iter->pos = (unsigned int) -1;#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) iter->buf6 = NULL; iter->pos6 = (unsigned int) -1; iter->result6 = ISC_R_NOMORE; iter->socket6 = -1; iter->first6 = ISC_FALSE;#endif /* * Get the interface configuration, allocating more memory if * necessary. */#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) result = isc_net_probeipv6(); if (result == ISC_R_SUCCESS) { /* * Create an unbound datagram socket to do the SIOCGLIFCONF * ioctl on. HP/UX requires an AF_INET6 socket for * SIOCGLIFCONF to get IPv6 addresses. */ if ((iter->socket6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { isc__strerror(errno, strbuf, sizeof(strbuf)); UNEXPECTED_ERROR(__FILE__, __LINE__, isc_msgcat_get(isc_msgcat, ISC_MSGSET_IFITERIOCTL, ISC_MSG_MAKESCANSOCKET, "making interface " "scan socket: %s"), strbuf); result = ISC_R_UNEXPECTED; goto socket6_failure; } iter->result6 = getbuf6(iter); if (iter->result6 != ISC_R_NOTIMPLEMENTED && iter->result6 != ISC_R_SUCCESS) goto ioctl6_failure; }#endif if ((iter->socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { isc__strerror(errno, strbuf, sizeof(strbuf)); UNEXPECTED_ERROR(__FILE__, __LINE__, isc_msgcat_get(isc_msgcat, ISC_MSGSET_IFITERIOCTL, ISC_MSG_MAKESCANSOCKET, "making interface " "scan socket: %s"), strbuf); result = ISC_R_UNEXPECTED; goto socket_failure; } result = getbuf4(iter); if (result != ISC_R_SUCCESS) goto ioctl_failure; /* * A newly created iterator has an undefined position * until isc_interfaceiter_first() is called. */#ifdef HAVE_TRUCLUSTER iter->clua_context = -1; iter->clua_done = ISC_TRUE;#endif#ifdef __linux iter->proc = fopen("/proc/net/if_inet6", "r"); iter->valid = ISC_R_FAILURE; iter->first = ISC_FALSE;#endif iter->result = ISC_R_FAILURE; iter->magic = IFITER_MAGIC; *iterp = iter; return (ISC_R_SUCCESS); ioctl_failure: if (iter->buf != NULL) isc_mem_put(mctx, iter->buf, iter->bufsize); (void) close(iter->socket); socket_failure:#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) if (iter->buf6 != NULL) isc_mem_put(mctx, iter->buf6, iter->bufsize6); ioctl6_failure: if (iter->socket6 != -1) (void) close(iter->socket6); socket6_failure:#endif isc_mem_put(mctx, iter, sizeof(*iter)); return (result);}#ifdef HAVE_TRUCLUSTERstatic voidget_inaddr(isc_netaddr_t *dst, struct in_addr *src) { dst->family = AF_INET; memcpy(&dst->type.in, src, sizeof(struct in_addr));}static isc_result_tinternal_current_clusteralias(isc_interfaceiter_t *iter) { struct clua_info ci; if (clua_getaliasinfo(&iter->clua_sa, &ci) != CLUA_SUCCESS) return (ISC_R_IGNORE); memset(&iter->current, 0, sizeof(iter->current)); iter->current.af = iter->clua_sa.sa_family; memset(iter->current.name, 0, sizeof(iter->current.name)); sprintf(iter->current.name, "clua%d", ci.aliasid); iter->current.flags = INTERFACE_F_UP; get_inaddr(&iter->current.address, &ci.addr); get_inaddr(&iter->current.netmask, &ci.netmask); return (ISC_R_SUCCESS);}#endif#ifdef __linuxstatic isc_result_tlinux_if_inet6_next(isc_interfaceiter_t *iter) { if (iter->proc != NULL && fgets(iter->entry, sizeof(iter->entry), iter->proc) != NULL) iter->valid = ISC_R_SUCCESS; else iter->valid = ISC_R_NOMORE; return (iter->valid);}static voidlinux_if_inet6_first(isc_interfaceiter_t *iter) { if (iter->proc != NULL) { rewind(iter->proc); (void)linux_if_inet6_next(iter); } else iter->valid = ISC_R_NOMORE; iter->first = ISC_FALSE;}static isc_result_tlinux_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 = ((index(hex, address[i * 2]) - hex) << 4) | (index(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);}#endif/* * Get information about the current interface to iter->current.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -