"Fossies" - the Fresh Open Source Software Archive

Member "bind-9.16.7/lib/bind9/getaddresses.c" (4 Sep 2020, 4079 Bytes) of package /linux/misc/dns/bind9/9.16.7/bind-9.16.7.tar.xz:


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 "getaddresses.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 /*! \file */
   13 
   14 #include <inttypes.h>
   15 #include <stdbool.h>
   16 #include <string.h>
   17 
   18 #include <isc/net.h>
   19 #include <isc/netaddr.h>
   20 #include <isc/netdb.h>
   21 #include <isc/netscope.h>
   22 #include <isc/result.h>
   23 #include <isc/sockaddr.h>
   24 #include <isc/string.h>
   25 #include <isc/util.h>
   26 
   27 #include <bind9/getaddresses.h>
   28 
   29 isc_result_t
   30 bind9_getaddresses(const char *hostname, in_port_t port, isc_sockaddr_t *addrs,
   31            int addrsize, int *addrcount) {
   32     struct in_addr in4;
   33     struct in6_addr in6;
   34     bool have_ipv4, have_ipv6;
   35     int i;
   36 
   37     struct addrinfo *ai = NULL, *tmpai, hints;
   38     int result;
   39 
   40     REQUIRE(hostname != NULL);
   41     REQUIRE(addrs != NULL);
   42     REQUIRE(addrcount != NULL);
   43     REQUIRE(addrsize > 0);
   44 
   45     have_ipv4 = (isc_net_probeipv4() == ISC_R_SUCCESS);
   46     have_ipv6 = (isc_net_probeipv6() == ISC_R_SUCCESS);
   47 
   48     /*
   49      * Try IPv4, then IPv6.  In order to handle the extended format
   50      * for IPv6 scoped addresses (address%scope_ID), we'll use a local
   51      * working buffer of 128 bytes.  The length is an ad-hoc value, but
   52      * should be enough for this purpose; the buffer can contain a string
   53      * of at least 80 bytes for scope_ID in addition to any IPv6 numeric
   54      * addresses (up to 46 bytes), the delimiter character and the
   55      * terminating NULL character.
   56      */
   57     if (inet_pton(AF_INET, hostname, &in4) == 1) {
   58         if (have_ipv4) {
   59             isc_sockaddr_fromin(&addrs[0], &in4, port);
   60         } else {
   61             isc_sockaddr_v6fromin(&addrs[0], &in4, port);
   62         }
   63         *addrcount = 1;
   64         return (ISC_R_SUCCESS);
   65     } else if (strlen(hostname) <= 127U) {
   66         char tmpbuf[128], *d;
   67         uint32_t zone = 0;
   68 
   69         strlcpy(tmpbuf, hostname, sizeof(tmpbuf));
   70         d = strchr(tmpbuf, '%');
   71         if (d != NULL) {
   72             *d = '\0';
   73         }
   74 
   75         if (inet_pton(AF_INET6, tmpbuf, &in6) == 1) {
   76             isc_netaddr_t na;
   77 
   78             if (!have_ipv6) {
   79                 return (ISC_R_FAMILYNOSUPPORT);
   80             }
   81 
   82             if (d != NULL) {
   83                 isc_result_t iresult;
   84 
   85                 iresult = isc_netscope_pton(AF_INET6, d + 1,
   86                                 &in6, &zone);
   87 
   88                 if (iresult != ISC_R_SUCCESS) {
   89                     return (iresult);
   90                 }
   91             }
   92 
   93             isc_netaddr_fromin6(&na, &in6);
   94             isc_netaddr_setzone(&na, zone);
   95             isc_sockaddr_fromnetaddr(
   96                 &addrs[0], (const isc_netaddr_t *)&na, port);
   97 
   98             *addrcount = 1;
   99             return (ISC_R_SUCCESS);
  100         }
  101     }
  102     memset(&hints, 0, sizeof(hints));
  103     if (!have_ipv6) {
  104         hints.ai_family = PF_INET;
  105     } else if (!have_ipv4) {
  106         hints.ai_family = PF_INET6;
  107     } else {
  108         hints.ai_family = PF_UNSPEC;
  109 #ifdef AI_ADDRCONFIG
  110         hints.ai_flags = AI_ADDRCONFIG;
  111 #endif /* ifdef AI_ADDRCONFIG */
  112     }
  113     hints.ai_socktype = SOCK_STREAM;
  114 #ifdef AI_ADDRCONFIG
  115 again:
  116 #endif /* ifdef AI_ADDRCONFIG */
  117     result = getaddrinfo(hostname, NULL, &hints, &ai);
  118     switch (result) {
  119     case 0:
  120         break;
  121     case EAI_NONAME:
  122 #if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
  123     case EAI_NODATA:
  124 #endif /* if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME) */
  125         return (ISC_R_NOTFOUND);
  126 #ifdef AI_ADDRCONFIG
  127     case EAI_BADFLAGS:
  128         if ((hints.ai_flags & AI_ADDRCONFIG) != 0) {
  129             hints.ai_flags &= ~AI_ADDRCONFIG;
  130             goto again;
  131         }
  132 #endif /* ifdef AI_ADDRCONFIG */
  133     /* FALLTHROUGH */
  134     default:
  135         return (ISC_R_FAILURE);
  136     }
  137     for (tmpai = ai, i = 0; tmpai != NULL && i < addrsize;
  138          tmpai = tmpai->ai_next) {
  139         if (tmpai->ai_family != AF_INET && tmpai->ai_family != AF_INET6)
  140         {
  141             continue;
  142         }
  143         if (tmpai->ai_family == AF_INET) {
  144             struct sockaddr_in *sin;
  145             sin = (struct sockaddr_in *)tmpai->ai_addr;
  146             isc_sockaddr_fromin(&addrs[i], &sin->sin_addr, port);
  147         } else {
  148             struct sockaddr_in6 *sin6;
  149             sin6 = (struct sockaddr_in6 *)tmpai->ai_addr;
  150             isc_sockaddr_fromin6(&addrs[i], &sin6->sin6_addr, port);
  151         }
  152         i++;
  153     }
  154     freeaddrinfo(ai);
  155     *addrcount = i;
  156     if (*addrcount == 0) {
  157         return (ISC_R_NOTFOUND);
  158     } else {
  159         return (ISC_R_SUCCESS);
  160     }
  161 }