+++ /dev/null
-/*
- * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- *
- * See the COPYRIGHT file distributed with this work for additional
- * information regarding copyright ownership.
- */
-
-#include <config.h>
-
-#include <stdbool.h>
-
-#include <isc/print.h>
-
-/*! \file
- * \brief
- * 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)
-
-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. */
- bool first6;
-#endif
-#ifdef __linux
- FILE * proc;
- char entry[ISC_IF_INET6_SZ];
- isc_result_t valid;
-#endif
- isc_interface_t current; /* Current interface data. */
- isc_result_t result; /* Last result code. */
-};
-
-/*%
- * 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
-#endif
-
-static isc_result_t
-getbuf4(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 "integer 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_t
-getbuf6(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 "integer 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) {
- 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);
-}
-#endif
-
-isc_result_t
-isc_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 = 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;
- }
- result = iter->result6 = getbuf6(iter);
- if (result != ISC_R_NOTIMPLEMENTED && result != 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 __linux
- iter->proc = fopen("/proc/net/if_inet6", "r");
- iter->valid = ISC_R_FAILURE;
-#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);
-}
-
-/*
- * Get information about the current interface to iter->current.
- * 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_t
-internal_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;
-
- REQUIRE(VALID_IFITER(iter));
-
- if (iter->ifc.ifc_len == 0 ||
- iter->pos == (unsigned int)iter->ifc.ifc_len) {
-#ifdef __linux
- return (linux_if_inet6_current(iter));
-#else
- return (ISC_R_NOMORE);
-#endif
- }
-
- INSIST( iter->pos < (unsigned int) iter->ifc.ifc_len);
-
- ifrp = (struct ifreq *)((char *) iter->ifc.ifc_req + iter->pos);
-
- memset(&ifreq, 0, sizeof(ifreq));
- memmove(&ifreq, ifrp, sizeof(ifreq));
-
- family = ifreq.ifr_addr.sa_family;
- if (family != AF_INET && family != AF_INET6)
- 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));
- memmove(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 "integer 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));
- memmove(lifreq.lifr_name, iter->current.name, sizeof(lifreq.lifr_name));
- memmove(&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] =
- (~0U << 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 "integer 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));
- memmove(&ifreq, ifrp, sizeof(ifreq));
- /*
- * 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 (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_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 = (struct LIFREQ *)((char *) iter->lifc.lifc_req + iter->pos6);
-
- memset(&lifreq, 0, sizeof(lifreq));
- memmove(&lifreq, ifrp, sizeof(lifreq));
-
- family = lifreq.lifr_addr.ss_family;
- if (family != AF_INET && family != AF_INET6)
- 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));
- memmove(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 "integer 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 "integer 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));
- memmove(&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] =
- (~0U << bits) & 0xff;
- }
-
- 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 (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);
-}
-#endif
-
-static isc_result_t
-internal_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
- 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_t
-internal_next4(isc_interfaceiter_t *iter) {
-
- if (iter->pos < (unsigned int) iter->ifc.ifc_len) {
- iter->pos += sizeof(struct ifreq);
-
- } else {
- INSIST(iter->pos == (unsigned int) iter->ifc.ifc_len);
-#ifdef __linux
- return (linux_if_inet6_next(iter));
-#else
- return (ISC_R_NOMORE);
-#endif
- }
- return (ISC_R_SUCCESS);
-}
-
-#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
-static isc_result_t
-internal_next6(isc_interfaceiter_t *iter) {
-
- if (iter->result6 != ISC_R_SUCCESS && iter->result6 != ISC_R_IGNORE)
- return (iter->result6);
-
- REQUIRE(iter->pos6 < (unsigned int) iter->lifc.lifc_len);
-
- iter->pos6 += sizeof(struct LIFREQ);
-
- if (iter->pos6 >= (unsigned int) iter->lifc.lifc_len)
- return (ISC_R_NOMORE);
-
- return (ISC_R_SUCCESS);
-}
-#endif
-
-static isc_result_t
-internal_next(isc_interfaceiter_t *iter) {
-#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 = false;
- return (ISC_R_SUCCESS);
- }
- }
-#endif
- return (internal_next4(iter));
-}
-
-static void
-internal_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
-}
-
-static
-void internal_first(isc_interfaceiter_t *iter) {
- iter->pos = 0;
-#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
- iter->pos6 = 0;
- if (iter->result6 == ISC_R_NOMORE)
- iter->result6 = ISC_R_SUCCESS;
- iter->first6 = true;
-#endif
-#ifdef __linux
- linux_if_inet6_first(iter);
-#endif
-}
+++ /dev/null
-/*
- * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- *
- * See the COPYRIGHT file distributed with this work for additional
- * information regarding copyright ownership.
- */
-
-#include <config.h>
-
-/*! \file
- * \brief
- * Obtain the list of network interfaces using sysctl.
- * See TCP/IP Illustrated Volume 2, sections 19.8, 19.14,
- * and 19.16.
- */
-
-#include <inttypes.h>
-
-#include <sys/param.h>
-#include <sys/sysctl.h>
-
-#include <net/route.h>
-#include <net/if_dl.h>
-
-#include <isc/print.h>
-
-/* XXX what about Alpha? */
-#define ROUNDUP(a) ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) \
- : sizeof(long))
-
-#define IFITER_MAGIC ISC_MAGIC('I', 'F', 'I', 'S')
-#define VALID_IFITER(t) ISC_MAGIC_VALID(t, IFITER_MAGIC)
-
-struct isc_interfaceiter {
- unsigned int magic; /* Magic number. */
- isc_mem_t *mctx;
- void *buf; /* Buffer for sysctl data. */
- unsigned int bufsize; /* Bytes allocated. */
- unsigned int bufused; /* Bytes used. */
- unsigned int pos; /* Current offset in
- sysctl data. */
- isc_interface_t current; /* Current interface data. */
- isc_result_t result; /* Last result code. */
-};
-
-static int mib[6] = {
- CTL_NET,
- PF_ROUTE,
- 0,
- 0, /* Any address family. */
- NET_RT_IFLIST,
- 0 /* Flags. */
-};
-
-isc_result_t
-isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) {
- isc_interfaceiter_t *iter;
- isc_result_t result;
- size_t bufsize;
- size_t bufused;
- 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->buf = 0;
-
- /*
- * Determine the amount of memory needed.
- */
- bufsize = 0;
- if (sysctl(mib, 6, NULL, &bufsize, NULL, (size_t) 0) < 0) {
- isc__strerror(errno, strbuf, sizeof(strbuf));
- UNEXPECTED_ERROR(__FILE__, __LINE__,
- isc_msgcat_get(isc_msgcat,
- ISC_MSGSET_IFITERSYSCTL,
- ISC_MSG_GETIFLISTSIZE,
- "getting interface "
- "list size: sysctl: %s"),
- strbuf);
- result = ISC_R_UNEXPECTED;
- goto failure;
- }
- iter->bufsize = bufsize;
-
- iter->buf = isc_mem_get(iter->mctx, iter->bufsize);
- if (iter->buf == NULL) {
- result = ISC_R_NOMEMORY;
- goto failure;
- }
-
- bufused = bufsize;
- if (sysctl(mib, 6, iter->buf, &bufused, NULL, (size_t) 0) < 0) {
- isc__strerror(errno, strbuf, sizeof(strbuf));
- UNEXPECTED_ERROR(__FILE__, __LINE__,
- isc_msgcat_get(isc_msgcat,
- ISC_MSGSET_IFITERSYSCTL,
- ISC_MSG_GETIFLIST,
- "getting interface list: "
- "sysctl: %s"),
- strbuf);
- result = ISC_R_UNEXPECTED;
- goto failure;
- }
- iter->bufused = bufused;
- INSIST(iter->bufused <= iter->bufsize);
-
- /*
- * A newly created iterator has an undefined position
- * until isc_interfaceiter_first() is called.
- */
- iter->pos = (unsigned int) -1;
- iter->result = ISC_R_FAILURE;
-
- iter->magic = IFITER_MAGIC;
- *iterp = iter;
- return (ISC_R_SUCCESS);
-
- failure:
- if (iter->buf != NULL)
- isc_mem_put(mctx, iter->buf, iter->bufsize);
- isc_mem_put(mctx, iter, sizeof(*iter));
- return (result);
-}
-
-/*
- * Get information about the current interface to iter->current.
- * If successful, return ISC_R_SUCCESS.
- * If the interface has an unsupported address family,
- * return ISC_R_IGNORE. In case of other failure,
- * return ISC_R_UNEXPECTED.
- */
-
-static isc_result_t
-internal_current(isc_interfaceiter_t *iter) {
- struct ifa_msghdr *ifam, *ifam_end;
-
- REQUIRE(VALID_IFITER(iter));
- REQUIRE (iter->pos < (unsigned int) iter->bufused);
-
- ifam = (struct ifa_msghdr *) ((char *) iter->buf + iter->pos);
- ifam_end = (struct ifa_msghdr *) ((char *) iter->buf + iter->bufused);
-
- if (ifam->ifam_type == RTM_IFINFO) {
- struct if_msghdr *ifm = (struct if_msghdr *) ifam;
- struct sockaddr_dl *sdl = (struct sockaddr_dl *) (ifm + 1);
- unsigned int namelen;
-
- memset(&iter->current, 0, sizeof(iter->current));
-
- namelen = sdl->sdl_nlen;
- if (namelen > sizeof(iter->current.name) - 1)
- namelen = sizeof(iter->current.name) - 1;
-
- memset(iter->current.name, 0, sizeof(iter->current.name));
- memmove(iter->current.name, sdl->sdl_data, namelen);
-
- iter->current.flags = 0;
-
- if ((ifam->ifam_flags & IFF_UP) != 0)
- iter->current.flags |= INTERFACE_F_UP;
-
- if ((ifam->ifam_flags & IFF_POINTOPOINT) != 0)
- iter->current.flags |= INTERFACE_F_POINTTOPOINT;
-
- if ((ifam->ifam_flags & IFF_LOOPBACK) != 0)
- iter->current.flags |= INTERFACE_F_LOOPBACK;
-
- /*
- * This is not an interface address.
- * Force another iteration.
- */
- return (ISC_R_IGNORE);
- } else if (ifam->ifam_type == RTM_NEWADDR) {
- int i;
- int family;
- struct sockaddr *mask_sa = NULL;
- struct sockaddr *addr_sa = NULL;
- struct sockaddr *dst_sa = NULL;
-
- struct sockaddr *sa = (struct sockaddr *)(ifam + 1);
- family = sa->sa_family;
-
- for (i = 0; i < RTAX_MAX; i++)
- {
- if ((ifam->ifam_addrs & (1 << i)) == 0)
- continue;
-
- INSIST(sa < (struct sockaddr *) ifam_end);
-
- switch (i) {
- case RTAX_NETMASK: /* Netmask */
- mask_sa = sa;
- break;
- case RTAX_IFA: /* Interface address */
- addr_sa = sa;
- break;
- case RTAX_BRD: /* Broadcast or destination address */
- dst_sa = sa;
- break;
- }
- sa = (struct sockaddr *)((char*)(sa)
- + ROUNDUP(sizeof(struct sockaddr)));
- }
-
- if (addr_sa == NULL)
- return (ISC_R_IGNORE);
-
- family = addr_sa->sa_family;
- if (family != AF_INET && family != AF_INET6)
- return (ISC_R_IGNORE);
-
- iter->current.af = family;
-
- get_addr(family, &iter->current.address, addr_sa,
- iter->current.name);
-
- if (mask_sa != NULL)
- get_addr(family, &iter->current.netmask, mask_sa,
- iter->current.name);
-
- if (dst_sa != NULL &&
- (iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0)
- get_addr(family, &iter->current.dstaddress, dst_sa,
- iter->current.name);
-
- return (ISC_R_SUCCESS);
- } else {
- printf("%s",
- isc_msgcat_get(isc_msgcat, ISC_MSGSET_IFITERSYSCTL,
- ISC_MSG_UNEXPECTEDTYPE,
- "warning: unexpected interface list "
- "message type\n"));
- return (ISC_R_IGNORE);
- }
-}
-
-/*
- * 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_t
-internal_next(isc_interfaceiter_t *iter) {
- struct ifa_msghdr *ifam;
- REQUIRE (iter->pos < (unsigned int) iter->bufused);
-
- ifam = (struct ifa_msghdr *) ((char *) iter->buf + iter->pos);
-
- iter->pos += ifam->ifam_msglen;
-
- if (iter->pos >= iter->bufused)
- return (ISC_R_NOMORE);
-
- return (ISC_R_SUCCESS);
-}
-
-static void
-internal_destroy(isc_interfaceiter_t *iter) {
- UNUSED(iter); /* Unused. */
- /*
- * Do nothing.
- */
-}
-
-static
-void internal_first(isc_interfaceiter_t *iter) {
- iter->pos = 0;
-}