"Fossies" - the Fresh Open Source Software Archive

Member "bind-9.11.23/lib/isc/win32/interfaceiter.c" (7 Sep 2020, 13933 Bytes) of package /linux/misc/dns/bind9/9.11.23/bind-9.11.23.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "interfaceiter.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
    3  *
    4  * This Source Code Form is subject to the terms of the Mozilla Public
    5  * License, v. 2.0. If a copy of the MPL was not distributed with this
    6  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
    7  *
    8  * See the COPYRIGHT file distributed with this work for additional
    9  * information regarding copyright ownership.
   10  */
   11 
   12 
   13 /*
   14  * Note that this code will need to be revisited to support IPv6 Interfaces.
   15  * For now we just iterate through IPv4 interfaces.
   16  */
   17 
   18 #include <config.h>
   19 #include <winsock2.h>
   20 #include <ws2tcpip.h>
   21 #include <sys/types.h>
   22 
   23 #include <stdbool.h>
   24 #include <stdio.h>
   25 #include <stdlib.h>
   26 #include <errno.h>
   27 
   28 #include <isc/interfaceiter.h>
   29 #include <isc/mem.h>
   30 #include <isc/print.h>
   31 #include <isc/result.h>
   32 #include <isc/string.h>
   33 #include <isc/strerror.h>
   34 #include <isc/types.h>
   35 #include <isc/util.h>
   36 
   37 void InitSockets(void);
   38 
   39 /* Common utility functions */
   40 
   41 /*
   42  * Extract the network address part from a "struct sockaddr".
   43  *
   44  * The address family is given explicitly
   45  * instead of using src->sa_family, because the latter does not work
   46  * for copying a network mask obtained by SIOCGIFNETMASK (it does
   47  * not have a valid address family).
   48  */
   49 
   50 
   51 #define IFITER_MAGIC        0x49464954U /* IFIT. */
   52 #define VALID_IFITER(t)     ((t) != NULL && (t)->magic == IFITER_MAGIC)
   53 
   54 struct isc_interfaceiter {
   55     unsigned int        magic;      /* Magic number. */
   56     isc_mem_t       *mctx;
   57     SOCKET          socket;
   58     INTERFACE_INFO      IFData;     /* Current Interface Info. */
   59     int         numIF;      /* Current Interface count. */
   60     int         v4IF;       /* Number of IPv4 Interfaces */
   61     INTERFACE_INFO      *buf4;      /* Buffer for WSAIoctl data. */
   62     unsigned int        buf4size;   /* Bytes allocated. */
   63     INTERFACE_INFO      *pos4;      /* Current offset in IF List */
   64     SOCKET_ADDRESS_LIST *buf6;      /* Buffer for WSAIoctl data. */
   65     unsigned int        buf6size;   /* Bytes allocated. */
   66     unsigned int        pos6;       /* Which entry to process. */
   67     bool        v6loop;     /* See IPv6 loop address. */
   68     bool        pos6zero;   /* Done pos6 == 0. */
   69     isc_interface_t     current;    /* Current interface data. */
   70     isc_result_t        result;     /* Last result code. */
   71 };
   72 
   73 
   74 /*
   75  * Size of buffer for SIO_GET_INTERFACE_LIST, in number of interfaces.
   76  * We assume no sane system will have more than than 1K of IP addresses on
   77  * all of its adapters.
   78  */
   79 #define IFCONF_SIZE_INITIAL   16
   80 #define IFCONF_SIZE_INCREMENT     64
   81 #define IFCONF_SIZE_MAX     1040
   82 
   83 static void
   84 get_addr(unsigned int family, isc_netaddr_t *dst, struct sockaddr *src) {
   85     dst->family = family;
   86     switch (family) {
   87     case AF_INET:
   88         memmove(&dst->type.in,
   89             &((struct sockaddr_in *) src)->sin_addr,
   90             sizeof(struct in_addr));
   91         break;
   92     case    AF_INET6:
   93         memmove(&dst->type.in6,
   94             &((struct sockaddr_in6 *) src)->sin6_addr,
   95             sizeof(struct in6_addr));
   96         dst->zone = ((struct sockaddr_in6 *) src)->sin6_scope_id;
   97         break;
   98     default:
   99         INSIST(0);
  100         ISC_UNREACHABLE();
  101     }
  102 }
  103 
  104 isc_result_t
  105 isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) {
  106     char strbuf[ISC_STRERRORSIZE];
  107     isc_interfaceiter_t *iter;
  108     isc_result_t result;
  109     int error;
  110     unsigned long bytesReturned = 0;
  111 
  112     REQUIRE(mctx != NULL);
  113     REQUIRE(iterp != NULL);
  114     REQUIRE(*iterp == NULL);
  115 
  116     iter = isc_mem_get(mctx, sizeof(*iter));
  117     if (iter == NULL)
  118         return (ISC_R_NOMEMORY);
  119 
  120     InitSockets();
  121 
  122     iter->mctx = mctx;
  123     iter->buf4 = NULL;
  124     iter->buf6 = NULL;
  125     iter->pos4 = NULL;
  126     iter->pos6 = 0;
  127     iter->v6loop = true;
  128     iter->pos6zero = true;
  129     iter->buf6size = 0;
  130     iter->buf4size = 0;
  131     iter->result = ISC_R_FAILURE;
  132     iter->numIF = 0;
  133     iter->v4IF = 0;
  134 
  135     /*
  136      * Create an unbound datagram socket to do the
  137      * SIO_GET_INTERFACE_LIST WSAIoctl on.
  138      */
  139     iter->socket = socket(AF_INET, SOCK_DGRAM, 0);
  140     if (iter->socket == INVALID_SOCKET) {
  141         error = WSAGetLastError();
  142         if (error == WSAEAFNOSUPPORT)
  143             goto inet6_only;
  144         isc__strerror(error, strbuf, sizeof(strbuf));
  145         UNEXPECTED_ERROR(__FILE__, __LINE__,
  146                 "making interface scan socket: %s",
  147                 strbuf);
  148         result = ISC_R_UNEXPECTED;
  149         goto socket_failure;
  150     }
  151 
  152     /*
  153      * Get the interface configuration, allocating more memory if
  154      * necessary.
  155      */
  156     iter->buf4size = IFCONF_SIZE_INITIAL*sizeof(INTERFACE_INFO);
  157 
  158     for (;;) {
  159         iter->buf4 = isc_mem_get(mctx, iter->buf4size);
  160         if (iter->buf4 == NULL) {
  161             result = ISC_R_NOMEMORY;
  162             goto alloc_failure;
  163         }
  164 
  165         if (WSAIoctl(iter->socket, SIO_GET_INTERFACE_LIST,
  166                  0, 0, iter->buf4, iter->buf4size,
  167                  &bytesReturned, 0, 0) == SOCKET_ERROR)
  168         {
  169             error = WSAGetLastError();
  170             if (error != WSAEFAULT && error != WSAENOBUFS) {
  171                 errno = error;
  172                 isc__strerror(error, strbuf, sizeof(strbuf));
  173                 UNEXPECTED_ERROR(__FILE__, __LINE__,
  174                         "get interface configuration: %s",
  175                         strbuf);
  176                 result = ISC_R_UNEXPECTED;
  177                 goto ioctl_failure;
  178             }
  179             /*
  180              * EINVAL.  Retry with a bigger buffer.
  181              */
  182         } else {
  183             /*
  184              * The WSAIoctl succeeded.
  185              * If the number of the returned bytes is the same
  186              * as the buffer size, we will grow it just in
  187              * case and retry.
  188              */
  189             if (bytesReturned > 0 &&
  190                 (bytesReturned < iter->buf4size))
  191                 break;
  192         }
  193         if (iter->buf4size >= IFCONF_SIZE_MAX*sizeof(INTERFACE_INFO)) {
  194             UNEXPECTED_ERROR(__FILE__, __LINE__,
  195                      "get interface configuration: "
  196                      "maximum buffer size exceeded");
  197             result = ISC_R_UNEXPECTED;
  198             goto ioctl_failure;
  199         }
  200         isc_mem_put(mctx, iter->buf4, iter->buf4size);
  201 
  202         iter->buf4size += IFCONF_SIZE_INCREMENT *
  203             sizeof(INTERFACE_INFO);
  204     }
  205 
  206     /*
  207      * A newly created iterator has an undefined position
  208      * until isc_interfaceiter_first() is called.
  209      */
  210     iter->v4IF = bytesReturned/sizeof(INTERFACE_INFO);
  211 
  212     /* We don't need the socket any more, so close it */
  213     closesocket(iter->socket);
  214 
  215  inet6_only:
  216     /*
  217      * Create an unbound datagram socket to do the
  218      * SIO_ADDRESS_LIST_QUERY WSAIoctl on.
  219      */
  220     iter->socket = socket(AF_INET6, SOCK_DGRAM, 0);
  221     if (iter->socket == INVALID_SOCKET) {
  222         error = WSAGetLastError();
  223         if (error == WSAEAFNOSUPPORT)
  224             goto inet_only;
  225         isc__strerror(error, strbuf, sizeof(strbuf));
  226         UNEXPECTED_ERROR(__FILE__, __LINE__,
  227                 "making interface scan socket: %s",
  228                 strbuf);
  229         result = ISC_R_UNEXPECTED;
  230         goto ioctl_failure;
  231     }
  232 
  233     /*
  234      * Get the interface configuration, allocating more memory if
  235      * necessary.
  236      */
  237     iter->buf6size = sizeof(SOCKET_ADDRESS_LIST) +
  238              IFCONF_SIZE_INITIAL*sizeof(SOCKET_ADDRESS);
  239 
  240     for (;;) {
  241         iter->buf6 = isc_mem_get(mctx, iter->buf6size);
  242         if (iter->buf6 == NULL) {
  243             result = ISC_R_NOMEMORY;
  244             goto ioctl_failure;
  245         }
  246 
  247         if (WSAIoctl(iter->socket, SIO_ADDRESS_LIST_QUERY,
  248                  0, 0, iter->buf6, iter->buf6size,
  249                  &bytesReturned, 0, 0) == SOCKET_ERROR)
  250         {
  251             error = WSAGetLastError();
  252             if (error != WSAEFAULT && error != WSAENOBUFS) {
  253                 errno = error;
  254                 isc__strerror(error, strbuf, sizeof(strbuf));
  255                 UNEXPECTED_ERROR(__FILE__, __LINE__,
  256                          "sio address list query: %s",
  257                          strbuf);
  258                 result = ISC_R_UNEXPECTED;
  259                 goto ioctl6_failure;
  260             }
  261             /*
  262              * EINVAL.  Retry with a bigger buffer.
  263              */
  264         } else
  265             break;
  266 
  267         if (iter->buf6size >= IFCONF_SIZE_MAX*sizeof(SOCKET_ADDRESS)) {
  268             UNEXPECTED_ERROR(__FILE__, __LINE__,
  269                      "get interface configuration: "
  270                      "maximum buffer size exceeded");
  271             result = ISC_R_UNEXPECTED;
  272             goto ioctl6_failure;
  273         }
  274         isc_mem_put(mctx, iter->buf6, iter->buf6size);
  275 
  276         iter->buf6size += IFCONF_SIZE_INCREMENT *
  277             sizeof(SOCKET_ADDRESS);
  278     }
  279 
  280     closesocket(iter->socket);
  281 
  282  inet_only:
  283     iter->magic = IFITER_MAGIC;
  284     *iterp = iter;
  285     return (ISC_R_SUCCESS);
  286 
  287  ioctl6_failure:
  288     isc_mem_put(mctx, iter->buf6, iter->buf6size);
  289 
  290  ioctl_failure:
  291     if (iter->buf4 != NULL)
  292         isc_mem_put(mctx, iter->buf4, iter->buf4size);
  293 
  294  alloc_failure:
  295     if (iter->socket != INVALID_SOCKET)
  296         (void) closesocket(iter->socket);
  297 
  298  socket_failure:
  299     isc_mem_put(mctx, iter, sizeof(*iter));
  300     return (result);
  301 }
  302 
  303 /*
  304  * Get information about the current interface to iter->current.
  305  * If successful, return ISC_R_SUCCESS.
  306  * If the interface has an unsupported address family, or if
  307  * some operation on it fails, return ISC_R_IGNORE to make
  308  * the higher-level iterator code ignore it.
  309  */
  310 
  311 static isc_result_t
  312 internal_current(isc_interfaceiter_t *iter) {
  313     BOOL ifNamed = FALSE;
  314     unsigned long flags;
  315 
  316     REQUIRE(VALID_IFITER(iter));
  317     REQUIRE(iter->numIF >= 0);
  318 
  319     memset(&iter->current, 0, sizeof(iter->current));
  320     iter->current.af = AF_INET;
  321 
  322     get_addr(AF_INET, &iter->current.address,
  323          (struct sockaddr *)&(iter->IFData.iiAddress));
  324 
  325     /*
  326      * Get interface flags.
  327      */
  328 
  329     iter->current.flags = 0;
  330     flags = iter->IFData.iiFlags;
  331 
  332     if ((flags & IFF_UP) != 0)
  333         iter->current.flags |= INTERFACE_F_UP;
  334 
  335     if ((flags & IFF_POINTTOPOINT) != 0) {
  336         iter->current.flags |= INTERFACE_F_POINTTOPOINT;
  337         snprintf(iter->current.name, sizeof(iter->current.name),
  338              "PPP Interface %d", iter->numIF);
  339         ifNamed = TRUE;
  340     }
  341 
  342     if ((flags & IFF_LOOPBACK) != 0) {
  343         iter->current.flags |= INTERFACE_F_LOOPBACK;
  344         snprintf(iter->current.name, sizeof(iter->current.name),
  345              "Loopback Interface %d", iter->numIF);
  346         ifNamed = TRUE;
  347     }
  348 
  349     /*
  350      * If the interface is point-to-point, get the destination address.
  351      */
  352     if ((iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0) {
  353         get_addr(AF_INET, &iter->current.dstaddress,
  354         (struct sockaddr *)&(iter->IFData.iiBroadcastAddress));
  355     }
  356 
  357     if (ifNamed == FALSE)
  358         snprintf(iter->current.name, sizeof(iter->current.name),
  359             "TCP/IP Interface %d", iter->numIF);
  360 
  361     /*
  362      * Get the network mask.
  363      */
  364     get_addr(AF_INET, &iter->current.netmask,
  365          (struct sockaddr *)&(iter->IFData.iiNetmask));
  366 
  367     return (ISC_R_SUCCESS);
  368 }
  369 
  370 static isc_result_t
  371 internal_current6(isc_interfaceiter_t *iter) {
  372     SOCKET fd;
  373     int i;
  374 
  375     REQUIRE(VALID_IFITER(iter));
  376     REQUIRE(iter->buf6 != NULL);
  377 
  378     memset(&iter->current, 0, sizeof(iter->current));
  379     iter->current.af = AF_INET6;
  380 
  381     if (!iter->pos6zero) {
  382         if (iter->pos6 == 0U)
  383             iter->pos6zero = true;
  384         get_addr(AF_INET6, &iter->current.address,
  385              iter->buf6->Address[iter->pos6].lpSockaddr);
  386 
  387         /*
  388          * Set interface flags.
  389          */
  390 
  391         iter->current.flags = INTERFACE_F_UP;
  392 
  393         snprintf(iter->current.name, sizeof(iter->current.name),
  394              "TCP/IPv6 Interface %u", iter->pos6 + 1);
  395 
  396         for (i = 0; i < 16; i++)
  397             iter->current.netmask.type.in6.s6_addr[i] = 0xff;
  398         iter->current.netmask.family = AF_INET6;
  399         if (IN6_IS_ADDR_LOOPBACK(&iter->current.address.type.in6))
  400                iter->v6loop = true;
  401     } else {
  402         /*
  403          * See if we can bind to the ::1 and if so return ::1.
  404          */
  405         struct sockaddr_in6 sin6;
  406 
  407         iter->v6loop = true;    /* So we don't loop forever. */
  408 
  409         fd = socket(AF_INET6, SOCK_DGRAM, 0);
  410         if (fd == INVALID_SOCKET)
  411             return (ISC_R_IGNORE);
  412         memset(&sin6, 0, sizeof(sin6));
  413         sin6.sin6_family = AF_INET6;
  414         sin6.sin6_addr.s6_addr[15] = 1;
  415         if (bind(fd, (struct sockaddr *)&sin6, sizeof(sin6)) < 0) {
  416             closesocket(fd);
  417             return (ISC_R_IGNORE);
  418         }
  419         closesocket(fd);
  420 
  421         iter->current.flags = INTERFACE_F_UP | INTERFACE_F_LOOPBACK;
  422         snprintf(iter->current.name, sizeof(iter->current.name),
  423             "TCP/IPv6 Loopback Interface");
  424         for (i = 0; i < 16; i++) {
  425             if (i != 15)
  426                 iter->current.address.type.in6.s6_addr[i] = 0;
  427             else
  428                 iter->current.address.type.in6.s6_addr[i] = 1;
  429             iter->current.netmask.type.in6.s6_addr[i] = 0xff;
  430         }
  431         iter->current.address.family = AF_INET6;
  432         iter->current.netmask.family = AF_INET6;
  433     }
  434     return (ISC_R_SUCCESS);
  435 }
  436 
  437 /*
  438  * Step the iterator to the next interface.  Unlike
  439  * isc_interfaceiter_next(), this may leave the iterator
  440  * positioned on an interface that will ultimately
  441  * be ignored.  Return ISC_R_NOMORE if there are no more
  442  * interfaces, otherwise ISC_R_SUCCESS.
  443  */
  444 static isc_result_t
  445 internal_next(isc_interfaceiter_t *iter) {
  446     if (iter->numIF >= iter->v4IF)
  447         return (ISC_R_NOMORE);
  448 
  449     /*
  450      * The first one needs to be set up to point to the last
  451      * Element of the array.  Go to the end and back up
  452      * Microsoft's implementation is peculiar for returning
  453      * the list in reverse order
  454      */
  455 
  456     if (iter->numIF == 0)
  457         iter->pos4 = (INTERFACE_INFO *)(iter->buf4 + (iter->v4IF));
  458 
  459     iter->pos4--;
  460     if (&(iter->pos4) < &(iter->buf4))
  461         return (ISC_R_NOMORE);
  462 
  463     memset(&(iter->IFData), 0, sizeof(INTERFACE_INFO));
  464     memmove(&(iter->IFData), iter->pos4, sizeof(INTERFACE_INFO));
  465     iter->numIF++;
  466 
  467     return (ISC_R_SUCCESS);
  468 }
  469 
  470 static isc_result_t
  471 internal_next6(isc_interfaceiter_t *iter) {
  472     if (iter->pos6 == 0U && iter->v6loop)
  473         return (ISC_R_NOMORE);
  474     if (iter->pos6 != 0U)
  475         iter->pos6--;
  476     return (ISC_R_SUCCESS);
  477 }
  478 
  479 isc_result_t
  480 isc_interfaceiter_current(isc_interfaceiter_t *iter,
  481               isc_interface_t *ifdata) {
  482     REQUIRE(iter->result == ISC_R_SUCCESS);
  483     memmove(ifdata, &iter->current, sizeof(*ifdata));
  484     return (ISC_R_SUCCESS);
  485 }
  486 
  487 isc_result_t
  488 isc_interfaceiter_first(isc_interfaceiter_t *iter) {
  489 
  490     REQUIRE(VALID_IFITER(iter));
  491 
  492     if (iter->buf6 != NULL) {
  493         iter->pos6 = iter->buf6->iAddressCount;
  494         iter->v6loop = false;
  495         iter->pos6zero = (iter->pos6 == 0U);
  496     }
  497     iter->result = ISC_R_SUCCESS;
  498     return (isc_interfaceiter_next(iter));
  499 }
  500 
  501 isc_result_t
  502 isc_interfaceiter_next(isc_interfaceiter_t *iter) {
  503     isc_result_t result;
  504 
  505     REQUIRE(VALID_IFITER(iter));
  506     REQUIRE(iter->result == ISC_R_SUCCESS);
  507 
  508     for (;;) {
  509         result = internal_next(iter);
  510         if (result == ISC_R_NOMORE) {
  511             result = internal_next6(iter);
  512             if (result != ISC_R_SUCCESS)
  513                 break;
  514             result = internal_current6(iter);
  515             if (result == ISC_R_IGNORE)
  516                 continue;
  517             break;
  518         } else if (result != ISC_R_SUCCESS)
  519             break;
  520         result = internal_current(iter);
  521         if (result != ISC_R_IGNORE)
  522             break;
  523     }
  524     iter->result = result;
  525     return (result);
  526 }
  527 
  528 void
  529 isc_interfaceiter_destroy(isc_interfaceiter_t **iterp) {
  530     isc_interfaceiter_t *iter;
  531     REQUIRE(iterp != NULL);
  532     iter = *iterp;
  533     REQUIRE(VALID_IFITER(iter));
  534 
  535     if (iter->buf4 != NULL)
  536         isc_mem_put(iter->mctx, iter->buf4, iter->buf4size);
  537     if (iter->buf6 != NULL)
  538         isc_mem_put(iter->mctx, iter->buf6, iter->buf6size);
  539 
  540     iter->magic = 0;
  541     isc_mem_put(iter->mctx, iter, sizeof(*iter));
  542     *iterp = NULL;
  543 }