]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
4448. [bug] win32: ::1 was not being found when iterating
authorMark Andrews <marka@isc.org>
Thu, 18 Aug 2016 11:58:13 +0000 (21:58 +1000)
committerMark Andrews <marka@isc.org>
Thu, 18 Aug 2016 11:58:13 +0000 (21:58 +1000)
                        interfaces. [RT #42993]

CHANGES
lib/isc/win32/interfaceiter.c

diff --git a/CHANGES b/CHANGES
index fa9fd0b27ae57427a88b6809e9702a918f94d4b4..65d92714b87613dfae720542f738f8e9a53f165a 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,6 @@
+4448.  [bug]           win32: ::1 was not being found when iterating
+                       interfaces. [RT #42993]
+
 4447.  [tuning]        Allow the fstrm_iothr_init() options to be set using
                        named.conf to control how dnstap manages the data
                        flow. [RT #42974]
index c06ef84b2533cdfbf64382efb367a9b8531d3ce0..c4cba284e7506dd60911625c53d59449de5c652c 100644 (file)
@@ -52,15 +52,17 @@ struct isc_interfaceiter {
        unsigned int            magic;          /* Magic number. */
        isc_mem_t               *mctx;
        SOCKET                  socket;
-       INTERFACE_INFO          IFData;         /* Current Interface Info */
-       int                     numIF;          /* Current Interface count */
+       INTERFACE_INFO          IFData;         /* Current Interface Info. */
+       int                     numIF;          /* Current Interface count. */
        int                     v4IF;           /* Number of IPv4 Interfaces */
        INTERFACE_INFO          *buf4;          /* Buffer for WSAIoctl data. */
        unsigned int            buf4size;       /* Bytes allocated. */
        INTERFACE_INFO          *pos4;          /* Current offset in IF List */
-       SOCKET_ADDRESS_LIST     *buf6;
+       SOCKET_ADDRESS_LIST     *buf6;          /* Buffer for WSAIoctl data. */
        unsigned int            buf6size;       /* Bytes allocated. */
-       unsigned int            pos6;
+       unsigned int            pos6;           /* Which entry to process. */
+       isc_boolean_t           v6loop;         /* See IPv6 loop address. */
+       isc_boolean_t           pos6zero;       /* Done pos6 == 0. */
        isc_interface_t         current;        /* Current interface data. */
        isc_result_t            result;         /* Last result code. */
 };
@@ -119,6 +121,8 @@ isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) {
        iter->buf6 = NULL;
        iter->pos4 = NULL;
        iter->pos6 = 0;
+       iter->v6loop = ISC_TRUE;
+       iter->pos6zero = ISC_TRUE;
        iter->buf6size = 0;
        iter->buf4size = 0;
        iter->result = ISC_R_FAILURE;
@@ -327,14 +331,15 @@ internal_current(isc_interfaceiter_t *iter) {
 
        if ((flags & IFF_POINTTOPOINT) != 0) {
                iter->current.flags |= INTERFACE_F_POINTTOPOINT;
-               sprintf(iter->current.name, "PPP Interface %d", iter->numIF);
+               snprintf(iter->current.name, sizeof(iter->current.name),
+                        "PPP Interface %d", iter->numIF);
                ifNamed = TRUE;
        }
 
        if ((flags & IFF_LOOPBACK) != 0) {
                iter->current.flags |= INTERFACE_F_LOOPBACK;
-               sprintf(iter->current.name, "Loopback Interface %d",
-                       iter->numIF);
+               snprintf(iter->current.name, sizeof(iter->current.name),
+                        "Loopback Interface %d", iter->numIF);
                ifNamed = TRUE;
        }
 
@@ -347,7 +352,7 @@ internal_current(isc_interfaceiter_t *iter) {
        }
 
        if (ifNamed == FALSE)
-               sprintf(iter->current.name,
+               snprintf(iter->current.name, sizeof(iter->current.name),
                        "TCP/IP Interface %d", iter->numIF);
 
        /*
@@ -361,32 +366,68 @@ internal_current(isc_interfaceiter_t *iter) {
 
 static isc_result_t
 internal_current6(isc_interfaceiter_t *iter) {
-       BOOL ifNamed = FALSE;
+       SOCKET fd;
        int i;
 
        REQUIRE(VALID_IFITER(iter));
-       REQUIRE(iter->pos6 >= 0);
-       REQUIRE(iter->buf6 != 0);
+       REQUIRE(iter->buf6 != NULL);
 
        memset(&iter->current, 0, sizeof(iter->current));
        iter->current.af = AF_INET6;
 
-       get_addr(AF_INET6, &iter->current.address,
-                iter->buf6->Address[iter->pos6].lpSockaddr);
-
-       /*
-        * Get interface flags.
-        */
-
-       iter->current.flags = INTERFACE_F_UP;
-
-       if (ifNamed == FALSE)
-               sprintf(iter->current.name,
-                       "TCP/IPv6 Interface %d", iter->pos6 + 1);
-
-       for (i = 0; i< 16; i++)
-               iter->current.netmask.type.in6.s6_addr[i] = 0xff;
-       iter->current.netmask.family = AF_INET6;
+       if (iter->pos6 != 0U || !iter->pos6zero) {
+               if (iter->pos6 == 0U)
+                       iter->pos6zero = ISC_TRUE;
+               get_addr(AF_INET6, &iter->current.address,
+                        iter->buf6->Address[iter->pos6].lpSockaddr);
+
+               /*
+                * Set interface flags.
+                */
+
+               iter->current.flags = INTERFACE_F_UP;
+
+               snprintf(iter->current.name, sizeof(iter->current.name),
+                        "TCP/IPv6 Interface %d", iter->pos6 + 1);
+
+               for (i = 0; i < 16; i++)
+                       iter->current.netmask.type.in6.s6_addr[i] = 0xff;
+               iter->current.netmask.family = AF_INET6;
+               if (IN6_IS_ADDR_LOOPBACK(&iter->current.address.type.in6))
+                          iter->v6loop = ISC_TRUE;
+       } else {
+               /*
+                * See if we can bind to the ::1 and if so return ::1.
+                */
+               struct sockaddr_in6 sin6;
+
+               iter->v6loop = ISC_TRUE;        /* So we don't loop forever. */
+
+               fd = socket(AF_INET6, SOCK_DGRAM, 0);
+               if (fd == INVALID_SOCKET)
+                       return (ISC_R_IGNORE);
+               memset(&sin6, 0, sizeof(sin6));
+               sin6.sin6_family = AF_INET6;
+               sin6.sin6_addr.s6_addr[15] = 1;
+               if (bind(fd, (struct sockaddr *)&sin6, sizeof(sin6)) < 0) {
+                       closesocket(fd);
+                       return (ISC_R_IGNORE);
+               }
+               closesocket(fd);
+
+               iter->current.flags = INTERFACE_F_UP | INTERFACE_F_LOOPBACK;
+               snprintf(iter->current.name, sizeof(iter->current.name),
+                       "TCP/IPv6 Loopback Interface");
+               for (i = 0; i < 16; i++) {
+                       if (i != 15)
+                               iter->current.address.type.in6.s6_addr[i] = 0;
+                       else
+                               iter->current.address.type.in6.s6_addr[i] = 1;
+                       iter->current.netmask.type.in6.s6_addr[i] = 0xff;
+               }
+               iter->current.address.family = AF_INET6;
+               iter->current.netmask.family = AF_INET6;
+       }
        return (ISC_R_SUCCESS);
 }
 
@@ -425,9 +466,10 @@ internal_next(isc_interfaceiter_t *iter) {
 
 static isc_result_t
 internal_next6(isc_interfaceiter_t *iter) {
-       if (iter->pos6 == 0)
+       if (iter->pos6 == 0 && iter->v6loop)
                return (ISC_R_NOMORE);
-       iter->pos6--;
+       if (iter->pos6 != 0)
+               iter->pos6--;
        return (ISC_R_SUCCESS);
 }
 
@@ -444,8 +486,11 @@ isc_interfaceiter_first(isc_interfaceiter_t *iter) {
 
        REQUIRE(VALID_IFITER(iter));
 
-       if (iter->buf6 != NULL)
+       if (iter->buf6 != NULL) {
                iter->pos6 = iter->buf6->iAddressCount;
+               iter->v6loop = ISC_FALSE;
+               iter->pos6zero = ISC_FALSE;
+       }
        iter->result = ISC_R_SUCCESS;
        return (isc_interfaceiter_next(iter));
 }
@@ -464,8 +509,9 @@ isc_interfaceiter_next(isc_interfaceiter_t *iter) {
                        if (result != ISC_R_SUCCESS)
                                break;
                        result = internal_current6(iter);
-                       if (result != ISC_R_IGNORE)
-                               break;
+                       if (result == ISC_R_IGNORE)
+                               continue;
+                       break;
                } else if (result != ISC_R_SUCCESS)
                        break;
                result = internal_current(iter);