]> git.ipfire.org Git - thirdparty/ntp.git/commitdiff
First upgrade of interfaceiter routines
authorDanny Mayer <mayer@ntp.org>
Fri, 31 Dec 2004 03:52:08 +0000 (22:52 -0500)
committerDanny Mayer <mayer@ntp.org>
Fri, 31 Dec 2004 03:52:08 +0000 (22:52 -0500)
bk: 41d4cce8txWESxHGb4MIGaBkKxUKAQ

libisc/ifiter_getifaddrs.c
libisc/ifiter_ioctl.c
libisc/ifiter_sysctl.c
libisc/interfaceiter.c

index ad6e1e0b040998c5d52b632ddc14350bf196c175..fd2a38bcff1fb5eebef53c2ebf5d296a2cf89042 100644 (file)
@@ -43,7 +43,6 @@ isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) {
        isc_result_t result;
        char strbuf[ISC_STRERRORSIZE];
 
-       REQUIRE(mctx != NULL);
        REQUIRE(iterp != NULL);
        REQUIRE(*iterp == NULL);
 
@@ -120,6 +119,7 @@ internal_current(isc_interfaceiter_t *iter) {
 
        memset(iter->current.name, 0, sizeof(iter->current.name));
        memcpy(iter->current.name, ifa->ifa_name, namelen);
+       iter->current.ifindex = ifa.ifa_index;  /* Save the if index */
 
        iter->current.flags = 0;
 
@@ -132,6 +132,15 @@ internal_current(isc_interfaceiter_t *iter) {
        if ((ifa->ifa_flags & IFF_LOOPBACK) != 0)
                iter->current.flags |= INTERFACE_F_LOOPBACK;
 
+       if ((ifa->ifa_flags & IFF_BROADCAST) != 0) {
+               iter->current.flags |= INTERFACE_F_BROADCAST;
+       }
+
+#ifdef IFF_MULTICAST
+       if ((ifa->ifa_flags & IFF_MULTICAST) != 0) {
+               iter->current.flags |= INTERFACE_F_MULTICAST;
+       }
+#endif
        iter->current.af = family;
 
        get_addr(family, &iter->current.address, ifa->ifa_addr, ifa->ifa_name);
@@ -145,6 +154,11 @@ internal_current(isc_interfaceiter_t *iter) {
                get_addr(family, &iter->current.dstaddress, ifa->ifa_dstaddr,
                         ifa->ifa_name);
 
+       if (ifa->ifa_broadaddr != NULL &&
+           (iter->current.flags & IFF_BROADCAST) != 0)
+               get_addr(family, &iter->current.broadcast, ifa->ifa_broadaddr,
+                        ifa->ifa_name);
+
        return (ISC_R_SUCCESS);
 }
 
index e313f8749d508208ccf904a3b509ae8b9090f1c4..064dbb65ce41fc53adde7a5c31a3a3f9d6c3b56b 100644 (file)
@@ -1,21 +1,21 @@
 /*
- * Copyright (C) 1999-2001  Internet Software Consortium.
+ * 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 INTERNET SOFTWARE CONSORTIUM
- * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
- * INTERNET SOFTWARE CONSORTIUM 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.
+ * 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.34 2002/08/16 00:05:57 marka Exp $ */
+/* $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.
 #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                     socket;
        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
-       void                    *buf;           /* Buffer for sysctl data. */
-       unsigned int            bufsize;        /* Bytes allocated. */
 #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
-       unsigned int            pos;            /* Current offset in
-                                                  SIOCGLIFCONF data */
        isc_interface_t         current;        /* Current interface data. */
        isc_result_t            result;         /* Last result code. */
 };
@@ -84,6 +102,16 @@ struct isc_interfaceiter {
 #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];
@@ -148,7 +176,6 @@ getbuf4(isc_interfaceiter_t *iter) {
 
                iter->bufsize *= 2;
        }
-       iter->mode = 4;
        return (ISC_R_SUCCESS);
 
  unexpected:
@@ -157,37 +184,34 @@ getbuf4(isc_interfaceiter_t *iter) {
        return (ISC_R_UNEXPECTED);
 }
 
+#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
 static isc_result_t
 getbuf6(isc_interfaceiter_t *iter) {
-#if !defined(SIOCGLIFCONF) || !defined(SIOCGLIFADDR)
-       UNUSED(iter);
-       return (ISC_R_NOTIMPLEMENTED);
-#else
        char strbuf[ISC_STRERRORSIZE];
        isc_result_t result;
 
-       iter->bufsize = IFCONF_BUFSIZE_INITIAL;
+       iter->bufsize6 = IFCONF_BUFSIZE_INITIAL;
 
        for (;;) {
-               iter->buf = isc_mem_get(iter->mctx, iter->bufsize);
-               if (iter->buf == NULL)
+               iter->buf6 = isc_mem_get(iter->mctx, iter->bufsize6);
+               if (iter->buf6 == NULL)
                        return (ISC_R_NOMEMORY);
 
-               memset(&iter->lifc.lifc_len, 0, sizeof(iter->lifc.lifc_len));
+               memset(&iter->lifc, 0, sizeof(iter->lifc));
 #ifdef ISC_HAVE_LIFC_FAMILY
-               iter->lifc.lifc_family = AF_UNSPEC;
+               iter->lifc.lifc_family = AF_INET6;
 #endif
 #ifdef ISC_HAVE_LIFC_FLAGS
                iter->lifc.lifc_flags = 0;
 #endif
-               iter->lifc.lifc_len = iter->bufsize;
-               iter->lifc.lifc_buf = iter->buf;
+               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->socket, SIOCGLIFCONF, (char *)&iter->lifc)
+               if (ioctl(iter->socket6, SIOCGLIFCONF, (char *)&iter->lifc)
                    == -1) {
 #ifdef __hpux
                        /*
@@ -233,10 +257,10 @@ getbuf6(isc_interfaceiter_t *iter) {
                         * retry.
                         */
                        if (iter->lifc.lifc_len + 2 * sizeof(struct LIFREQ)
-                           < iter->bufsize)
+                           < iter->bufsize6)
                                break;
                }
-               if (iter->bufsize >= IFCONF_BUFSIZE_MAX) {
+               if (iter->bufsize6 >= IFCONF_BUFSIZE_MAX) {
                        UNEXPECTED_ERROR(__FILE__, __LINE__,
                                         isc_msgcat_get(isc_msgcat,
                                                        ISC_MSGSET_IFITERIOCTL,
@@ -248,20 +272,21 @@ getbuf6(isc_interfaceiter_t *iter) {
                        result = ISC_R_UNEXPECTED;
                        goto cleanup;
                }
-               isc_mem_put(iter->mctx, iter->buf, iter->bufsize);
+               isc_mem_put(iter->mctx, iter->buf6, iter->bufsize6);
 
-               iter->bufsize *= 2;
+               iter->bufsize6 *= 2;
        }
 
-       iter->mode = 6;
+       if (iter->lifc.lifc_len != 0)
+               iter->mode = 6;
        return (ISC_R_SUCCESS);
 
  cleanup:
-       isc_mem_put(iter->mctx, iter->buf, iter->bufsize);
-       iter->buf = NULL;
+       isc_mem_put(iter->mctx, iter->buf6, iter->bufsize6);
+       iter->buf6 = NULL;
        return (result);
-#endif
 }
+#endif
 
 isc_result_t
 isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) {
@@ -277,12 +302,48 @@ isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) {
                return (ISC_R_NOMEMORY);
 
        iter->mctx = mctx;
+       iter->mode = 4;
        iter->buf = NULL;
-       iter->mode = 0;
+       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
 
        /*
-        * Create an unbound datagram socket to do the SIOCGLIFADDR ioctl on.
+        * 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__,
@@ -295,17 +356,7 @@ isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) {
                result = ISC_R_UNEXPECTED;
                goto socket_failure;
        }
-
-       /*
-        * Get the interface configuration, allocating more memory if
-        * necessary.
-        */
-
-       result = isc_net_probeipv6();
-       if (result == ISC_R_SUCCESS)
-               result = getbuf6(iter);
-       if (result != ISC_R_SUCCESS)
-               result = getbuf4(iter);
+       result = getbuf4(iter);
        if (result != ISC_R_SUCCESS)
                goto ioctl_failure;
 
@@ -315,8 +366,13 @@ isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) {
         */
 #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->pos = (unsigned int) -1;
        iter->result = ISC_R_FAILURE;
 
        iter->magic = IFITER_MAGIC;
@@ -329,6 +385,15 @@ isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) {
        (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);
 }
@@ -342,21 +407,100 @@ get_inaddr(isc_netaddr_t *dst, struct in_addr *src) {
 
 static isc_result_t
 internal_current_clusteralias(isc_interfaceiter_t *iter) {
-       struct sockaddr sa;
        struct clua_info ci;
-       while (clua_getaliasaddress(&sa, &iter->clua_context) == CLUA_SUCCESS) {
-               if (clua_getaliasinfo(&sa, &ci) != CLUA_SUCCESS)
-                       continue;
-               memset(&iter->current, 0, sizeof(iter->current));
-               iter->current.af = 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);
+       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 __linux
+static isc_result_t
+linux_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 void
+linux_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_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 = ((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;
+               }
        }
-       return (ISC_R_NOMORE);
+       isc_netaddr_fromin6(&iter->current.netmask, &addr6);
+       strncpy(iter->current.name, name, sizeof(iter->current.name));
+       return (ISC_R_SUCCESS);
 }
 #endif
 
@@ -374,22 +518,33 @@ internal_current4(isc_interfaceiter_t *iter) {
        struct ifreq ifreq;
        int family;
        char strbuf[ISC_STRERRORSIZE];
-#if !defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
-       struct if_laddrreq if_laddrreq;
-       int i, bits;
+#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 (SIOCGLIFCONF) && defined(SIOCGLIFADDR) && \
-    defined(ISC_PLATFORM_HAVEIPV6)
+#if defined(ISC_PLATFORM_HAVEIPV6)
        if (family != AF_INET && family != AF_INET6)
 #else
        if (family != AF_INET)
@@ -414,7 +569,7 @@ internal_current4(isc_interfaceiter_t *iter) {
 #endif
 
        get_addr(family, &iter->current.address,
-                (struct sockaddr *)&ifrp->ifr_addr);
+                (struct sockaddr *)&ifrp->ifr_addr, ifreq.ifr_name);
 
        /*
         * If the interface does not have a address ignore it.
@@ -453,8 +608,10 @@ internal_current4(isc_interfaceiter_t *iter) {
        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;
@@ -469,44 +626,56 @@ internal_current4(isc_interfaceiter_t *iter) {
        }
 #endif
 
-#if !defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
-       if (family == AF_INET) 
+       if (family == AF_INET)
                goto inet;
 
-       memset(&if_laddrreq, 0, sizeof(if_laddrreq));
-       memcpy(if_laddrreq.iflr_name, iter->current.name,
-              sizeof(if_laddrreq.iflr_name));
-       memcpy(&if_laddrreq.addr, &iter->current.address.type.in6,
+#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, &if_laddrreq) < 0) {
+       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 (if_laddrreq.prefixlen > 8) {
+               if (prefixlen > 8) {
                        bits = 0;
-                       if_laddrreq.prefixlen -= 8;
+                       prefixlen -= 8;
                } else {
-                       bits = 8 - if_laddrreq.prefixlen;
-                       if_laddrreq.prefixlen = 0;
+                       bits = 8 - prefixlen;
+                       prefixlen = 0;
                }
                iter->current.netmask.type.in6.s6_addr[i] = (~0 << bits) & 0xff;
        }
        return (ISC_R_SUCCESS);
 
  inet:
-#endif
        if (family != AF_INET)
                return (ISC_R_IGNORE);
+#ifdef IFF_POINTOPOINT
        /*
         * If the interface is point-to-point, get the destination address.
         */
@@ -529,9 +698,9 @@ internal_current4(isc_interfaceiter_t *iter) {
                        return (ISC_R_IGNORE);
                }
                get_addr(family, &iter->current.dstaddress,
-                        (struct sockaddr *)&ifreq.ifr_dstaddr);
+                        (struct sockaddr *)&ifreq.ifr_dstaddr, ifreq.ifr_name);
        }
-
+#endif
        if ((iter->current.flags & INTERFACE_F_BROADCAST) != 0) {
                /*
                 * Ignore the HP/UX warning about "integer overflow during
@@ -551,8 +720,9 @@ internal_current4(isc_interfaceiter_t *iter) {
                        return (ISC_R_IGNORE);
                }
                get_addr(family, &iter->current.broadcast,
-                        (struct sockaddr *)&ifreq.ifr_broadaddr);
+                        (struct sockaddr *)&ifreq.ifr_broadaddr, ifreq.ifr_name);
        }
+
        /*
         * Get the network mask.
         */
@@ -563,8 +733,7 @@ internal_current4(isc_interfaceiter_t *iter) {
         * conversion.  It comes from its own macro definition,
         * and is really hard to shut up.
         */
-       if (ioctl(iter->socket, SIOCGIFNETMASK, (char *)&ifreq)
-           < 0) {
+       if (ioctl(iter->socket, SIOCGIFNETMASK, (char *)&ifreq) < 0) {
                isc__strerror(errno, strbuf, sizeof(strbuf));
                UNEXPECTED_ERROR(__FILE__, __LINE__,
                        isc_msgcat_get(isc_msgcat,
@@ -575,25 +744,25 @@ internal_current4(isc_interfaceiter_t *iter) {
                return (ISC_R_IGNORE);
        }
        get_addr(family, &iter->current.netmask,
-                (struct sockaddr *)&ifreq.ifr_addr);
+                (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) {
-#if !defined(SIOCGLIFCONF) || !defined(SIOCGLIFADDR)
-       UNUSED(iter);
-       return (ISC_R_NOTIMPLEMENTED);
-#else
        struct LIFREQ *ifrp;
        struct LIFREQ lifreq;
        int family;
        char strbuf[ISC_STRERRORSIZE];
+       int fd;
 
        REQUIRE(VALID_IFITER(iter));
-       REQUIRE (iter->pos < (unsigned int) iter->lifc.lifc_len);
+       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->pos);
+       ifrp = (struct LIFREQ *)((char *) iter->lifc.lifc_req + iter->pos6);
 
        memset(&lifreq, 0, sizeof(lifreq));
        memcpy(&lifreq, ifrp, sizeof(lifreq));
@@ -615,11 +784,8 @@ internal_current6(isc_interfaceiter_t *iter) {
        iter->current.ifindex = lifreq.lifr_index;      /* Save the if index */
 
        get_addr(family, &iter->current.address,
-                (struct sockaddr *)&lifreq.lifr_addr);
+                (struct sockaddr *)&lifreq.lifr_addr, lifreq.lifr_name);
 
-#ifdef ISC_PLATFORM_HAVEIPV6
-       iter->current.scopeid = get_scopeid(family, (struct sockaddr *)&lifreq.lifr_addr);
-#endif
        /*
         * If the interface does not have a address ignore it.
         */
@@ -641,32 +807,31 @@ internal_current6(isc_interfaceiter_t *iter) {
 
        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(iter->socket, SIOCGLIFFLAGS, (char *) &lifreq) < 0) {
-
-               /*
-                * XXX This should be looked at further since it looks strange.
-                * If we get an ENXIO then we ignore the error and not worry
-                * about the flags.
-                */
-               if (errno != ENXIO) {
-                       isc__strerror(errno, strbuf, sizeof(strbuf));
-                       UNEXPECTED_ERROR(__FILE__, __LINE__,
+       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);
-               }
+               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;
@@ -681,6 +846,7 @@ internal_current6(isc_interfaceiter_t *iter) {
        }
 #endif
 
+#ifdef IFF_POINTOPOINT
        /*
         * If the interface is point-to-point, get the destination address.
         */
@@ -690,7 +856,7 @@ internal_current6(isc_interfaceiter_t *iter) {
                 * conversion.  It comes from its own macro definition,
                 * and is really hard to shut up.
                 */
-               if (ioctl(iter->socket, SIOCGLIFDSTADDR, (char *)&lifreq)
+               if (ioctl(fd, SIOCGLIFDSTADDR, (char *)&lifreq)
                    < 0) {
                        isc__strerror(errno, strbuf, sizeof(strbuf));
                        UNEXPECTED_ERROR(__FILE__, __LINE__,
@@ -703,8 +869,11 @@ internal_current6(isc_interfaceiter_t *iter) {
                        return (ISC_R_IGNORE);
                }
                get_addr(family, &iter->current.dstaddress,
-                        (struct sockaddr *)&lifreq.lifr_dstaddr);
+                        (struct sockaddr *)&lifreq.lifr_dstaddr,
+                        lifreq.lifr_name);
        }
+#endif
+
 #ifdef SIOCGLIFBRDADDR
        if ((iter->current.flags & INTERFACE_F_BROADCAST) != 0) {
                /*
@@ -725,43 +894,26 @@ internal_current6(isc_interfaceiter_t *iter) {
                        return (ISC_R_IGNORE);
                }
                get_addr(family, &iter->current.broadcast,
-                        (struct sockaddr *)&lifreq.lifr_broadaddr);
+                        (struct sockaddr *)&lifreq.lifr_broadaddr,
+                        lifreq.lifr_name);
        }
 #endif /* SIOCGLIFBRDADDR */
 
        /*
-        * Get the network mask.
+        * Get the network mask.  Netmask already zeroed.
         */
        memset(&lifreq, 0, sizeof(lifreq));
        memcpy(&lifreq, ifrp, sizeof(lifreq));
-       switch (family) {
-       case AF_INET:
-               /*
-                * 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, 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);
-               break;
-       case AF_INET6: {
+
 #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;
 
-               /*
-                * Netmask already zeroed.
-                */
                iter->current.netmask.family = family;
                for (i = 0; i < lifreq.lifr_addrlen; i += 8) {
                        bits = lifreq.lifr_addrlen - i;
@@ -769,19 +921,46 @@ internal_current6(isc_interfaceiter_t *iter) {
                        iter->current.netmask.type.in6.s6_addr[i / 8] =
                                (~0 << bits) & 0xff;
                }
-#endif
-               break;
+
+               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
 }
+#endif
 
 static isc_result_t
 internal_current(isc_interfaceiter_t *iter) {
-       if (iter->mode == 6)
-               return (internal_current6(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));
 }
 
@@ -798,8 +977,10 @@ internal_next4(isc_interfaceiter_t *iter) {
 
        REQUIRE (iter->pos < (unsigned int) iter->ifc.ifc_len);
 
-#ifdef HAVE_TRUCLUSTER
-       if (internal_current_clusteralias(iter) == ISC_R_SUCCESS)
+#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);
@@ -817,40 +998,95 @@ internal_next4(isc_interfaceiter_t *iter) {
        return (ISC_R_SUCCESS);
 }
 
+#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
 static isc_result_t
 internal_next6(isc_interfaceiter_t *iter) {
-#if !defined(SIOCGLIFCONF) || !defined(SIOCGLIFADDR)
-       UNUSED(iter);
-       return (ISC_R_NOTIMPLEMENTED);
-#else
        struct LIFREQ *ifrp;
+       
+       if (iter->result6 != ISC_R_SUCCESS && iter->result6 != ISC_R_IGNORE)
+               return (iter->result6);
 
-       REQUIRE (iter->pos < (unsigned int) iter->lifc.lifc_len);
+       REQUIRE(iter->pos6 < (unsigned int) iter->lifc.lifc_len);
 
-       ifrp = (struct LIFREQ *)((char *) iter->lifc.lifc_req + iter->pos);
+       ifrp = (struct LIFREQ *)((char *) iter->lifc.lifc_req + iter->pos6);
 
 #ifdef ISC_PLATFORM_HAVESALEN
        if (ifrp->lifr_addr.sa_len > sizeof(struct sockaddr))
-               iter->pos += sizeof(ifrp->lifr_name) + ifrp->lifr_addr.sa_len;
+               iter->pos6 += sizeof(ifrp->lifr_name) + ifrp->lifr_addr.sa_len;
        else
 #endif
-               iter->pos += sizeof(*ifrp);
+               iter->pos6 += sizeof(*ifrp);
 
-       if (iter->pos >= (unsigned int) iter->lifc.lifc_len)
+       if (iter->pos6 >= (unsigned int) iter->lifc.lifc_len)
                return (ISC_R_NOMORE);
 
        return (ISC_R_SUCCESS);
-#endif
 }
+#endif
 
 static isc_result_t
 internal_next(isc_interfaceiter_t *iter) {
-       if (iter->mode == 6)
-               return (internal_next6(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 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) {
+#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
 }
index 5f9e7b6429bf0e3a10a0fbc1be94343d7f221232..a2916abd13bbc4484e6e198e5d8006654331cc23 100644 (file)
@@ -1,21 +1,21 @@
 /*
- * Copyright (C) 1999-2001  Internet Software Consortium.
+ * 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 INTERNET SOFTWARE CONSORTIUM
- * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
- * INTERNET SOFTWARE CONSORTIUM 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.
+ * 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_sysctl.c,v 1.17 2002/05/30 01:24:12 marka Exp $ */
+/* $Id: ifiter_sysctl.c,v 1.14.12.7 2004/03/08 09:04:56 marka Exp $ */
 
 /*
  * Obtain the list of network interfaces using sysctl.
@@ -252,19 +252,23 @@ internal_current(isc_interfaceiter_t *iter) {
 
                iter->current.af = family;
 
-               get_addr(family, &iter->current.address, addr_sa);
-
-               iter->current.scopeid = get_scopeid(family, addr_sa);
+               get_addr(family, &iter->current.address, addr_sa,
+                        iter->current.name);
 
                if (mask_sa != NULL)
-                       get_addr(family, &iter->current.netmask, mask_sa);
+                       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);
+                       get_addr(family, &iter->current.dstaddress, dst_sa,
+                                iter->current.name);
+
                if (dst_sa != NULL &&
                    (iter->current.flags & INTERFACE_F_BROADCAST) != 0)
-                       get_addr(family, &iter->current.broadcast, dst_sa);
+                       get_addr(family, &iter->current.dstaddress, dst_sa,
+                                iter->current.name);
+
 
                return (ISC_R_SUCCESS);
        } else {
@@ -306,3 +310,7 @@ internal_destroy(isc_interfaceiter_t *iter) {
         */
 }
 
+static
+void internal_first(isc_interfaceiter_t *iter) {
+       iter->pos = 0;
+}
index 6705a4314f7fdf88ad66c66ba23762f740a73ee4..ea465e207a35c4a8cac8e37dc982f4c7d31006f1 100644 (file)
@@ -1,21 +1,21 @@
 /*
- * Copyright (C) 1999-2001  Internet Software Consortium.
+ * 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 INTERNET SOFTWARE CONSORTIUM
- * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
- * INTERNET SOFTWARE CONSORTIUM 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.
+ * 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: interfaceiter.c,v 1.27 2002/07/02 05:51:43 marka Exp $ */
+/* $Id: interfaceiter.c,v 1.22.2.1.10.14 2004/08/28 06:25:22 marka Exp $ */
 
 #include <config.h>
 
@@ -37,6 +37,7 @@
 #include <isc/mem.h>
 #include <isc/msgs.h>
 #include <isc/net.h>
+#include <isc/print.h>
 #include <isc/result.h>
 #include <isc/strerror.h>
 #include <isc/string.h>
 /*
  * Extract the network address part from a "struct sockaddr".
  *
- * The address family is given explicity
+ * The address family is given explicitly
  * instead of using src->sa_family, because the latter does not work
  * for copying a network mask obtained by SIOCGIFNETMASK (it does
  * not have a valid address family).
  */
 
 static void
-get_addr(unsigned int family, isc_netaddr_t *dst, struct sockaddr *src) {
+get_addr(unsigned int family, isc_netaddr_t *dst, struct sockaddr *src,
+        char *ifname)
+{
+       struct sockaddr_in6 *sa6;
+
+#if !defined(ISC_PLATFORM_HAVEIFNAMETOINDEX) || \
+    !defined(ISC_PLATFORM_HAVESCOPEID)
+       UNUSED(ifname);
+#endif
+
+       /* clear any remaining value for safety */
+       memset(dst, 0, sizeof(*dst));
+
        dst->family = family;
        switch (family) {
        case AF_INET:
@@ -69,21 +82,56 @@ get_addr(unsigned int family, isc_netaddr_t *dst, struct sockaddr *src) {
                       &((struct sockaddr_in *) src)->sin_addr,
                       sizeof(struct in_addr));
                break;
-       case    AF_INET6:
-               memcpy(&dst->type.in6,
-                      &((struct sockaddr_in6 *) src)->sin6_addr,
+       case AF_INET6:
+               sa6 = (struct sockaddr_in6 *)src;
+               memcpy(&dst->type.in6, &sa6->sin6_addr,
                       sizeof(struct in6_addr));
-
-               /*
-                * For KAME addresses we need to fix up the address
-                * for public consumption if it is a multicast address
-                */
-#ifdef __KAME__
-               if (IN6_IS_ADDR_MC_LINKLOCAL( &((struct sockaddr_in6 *)src)->sin6_addr)) {
-                       dst->type.in6.s6_addr[2] = 0;
-                       dst->type.in6.s6_addr[3] = 0;
+#ifdef ISC_PLATFORM_HAVESCOPEID
+               if (sa6->sin6_scope_id != 0)
+                       isc_netaddr_setzone(dst, sa6->sin6_scope_id);
+               else {
+                       /*
+                        * BSD variants embed scope zone IDs in the 128bit
+                        * address as a kernel internal form.  Unfortunately,
+                        * the embedded IDs are not hidden from applications
+                        * when getting access to them by sysctl or ioctl.
+                        * We convert the internal format to the pure address
+                        * part and the zone ID part.
+                        * Since multicast addresses should not appear here
+                        * and they cannot be distinguished from netmasks,
+                        * we only consider unicast link-local addresses.
+                        */
+                       if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) {
+                               isc_uint16_t zone16;
+
+                               memcpy(&zone16, &sa6->sin6_addr.s6_addr[2],
+                                      sizeof(zone16));
+                               zone16 = ntohs(zone16);
+                               if (zone16 != 0) {
+                                       /* the zone ID is embedded */
+                                       isc_netaddr_setzone(dst,
+                                                           (isc_uint32_t)zone16);
+                                       dst->type.in6.s6_addr[2] = 0;
+                                       dst->type.in6.s6_addr[3] = 0;
+#ifdef ISC_PLATFORM_HAVEIFNAMETOINDEX
+                               } else if (ifname != NULL) {
+                                       unsigned int zone;
+
+                                       /*
+                                        * sin6_scope_id is still not provided,
+                                        * but the corresponding interface name
+                                        * is know.  Use the interface ID as
+                                        * the link ID.
+                                        */
+                                       zone = if_nametoindex(ifname);
+                                       if (zone != 0) {
+                                               isc_netaddr_setzone(dst,
+                                                                   (isc_uint32_t)zone);
+                                       }
+#endif
+                               }
+                       }
                }
-
 #endif
                break;
        default:
@@ -92,53 +140,13 @@ get_addr(unsigned int family, isc_netaddr_t *dst, struct sockaddr *src) {
        }
 }
 
-#ifdef ISC_PLATFORM_HAVEIPV6
-/*
- * Get the scope id here for multicasting purposes
- * For the KAME stack we need to play games to get the scope.
- */
-static unsigned int
-get_scopeid(unsigned int family, struct sockaddr *src) {
-
-       unsigned int scopeid;
-
-       switch (family) {
-       case AF_INET:
-               return (0);
-               break;
-       case AF_INET6:
-#ifdef __KAME__
-       if (IN6_IS_ADDR_LINKLOCAL( &((struct sockaddr_in6 *)src)->sin6_addr)
-               && ((struct sockaddr_in6 *)src)->sin6_scope_id == 0) {
-               u_int8_t *p;
-               p = &((struct sockaddr_in6 *)src)->sin6_addr.s6_addr[0];
-               scopeid = ((u_int16_t)p[2] << 8) | p[3];
-       } else
-#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
-               scopeid = ((struct sockaddr_in6 *)src)->sin6_scope_id;
-#else
-               scopeid = 0;
-#endif
-#else
-#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
-       scopeid = ((struct sockaddr_in6 *)src)->sin6_scope_id;
-#else
-       scopeid = 0;
-#endif
-#endif
-              return (scopeid);
-       default:
-               INSIST(0);
-               break;
-       }
-       return (0);
-}
-#endif
 /*
  * Include system-dependent code.
  */
 
-#if HAVE_IFLIST_SYSCTL
+#if HAVE_GETIFADDRS
+#include "ifiter_getifaddrs.c"
+#elif HAVE_IFLIST_SYSCTL
 #include "ifiter_sysctl.c"
 #else
 #include "ifiter_ioctl.c"
@@ -163,10 +171,7 @@ isc_interfaceiter_first(isc_interfaceiter_t *iter) {
 
        REQUIRE(VALID_IFITER(iter));
 
-       iter->pos = 0;
-#ifdef HAVE_TRUCLUSTER
-       iter->clua_context = 0;
-#endif
+       internal_first(iter);
        for (;;) {
                result = internal_current(iter);
                if (result != ISC_R_IGNORE)
@@ -207,7 +212,8 @@ isc_interfaceiter_destroy(isc_interfaceiter_t **iterp)
        REQUIRE(VALID_IFITER(iter));
 
        internal_destroy(iter);
-       isc_mem_put(iter->mctx, iter->buf, iter->bufsize);
+       if (iter->buf != NULL)
+               isc_mem_put(iter->mctx, iter->buf, iter->bufsize);
 
        iter->magic = 0;
        isc_mem_put(iter->mctx, iter, sizeof(*iter));