"Fossies" - the Fresh Open Source Software Archive

Member "bind-9.16.7/lib/irs/getaddrinfo.c" (4 Sep 2020, 35079 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 "getaddrinfo.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 /**
   15  *    getaddrinfo() is used to get a list of IP addresses and port
   16  *    numbers for host hostname and service servname as defined in RFC3493.
   17  *    hostname and servname are pointers to null-terminated strings
   18  *    or NULL. hostname is either a host name or a numeric host address
   19  *    string: a dotted decimal IPv4 address or an IPv6 address. servname is
   20  *    either a decimal port number or a service name as listed in
   21  *    /etc/services.
   22  *
   23  *    If the operating system does not provide a struct addrinfo, the
   24  *    following structure is used:
   25  *
   26  * \code
   27  * struct  addrinfo {
   28  *         int             ai_flags;       // AI_PASSIVE, AI_CANONNAME
   29  *         int             ai_family;      // PF_xxx
   30  *         int             ai_socktype;    // SOCK_xxx
   31  *         int             ai_protocol;    // 0 or IPPROTO_xxx for IPv4 and IPv6
   32  *         size_t          ai_addrlen;     // length of ai_addr
   33  *         char            *ai_canonname;  // canonical name for hostname
   34  *         struct sockaddr *ai_addr;       // binary address
   35  *         struct addrinfo *ai_next;       // next structure in linked list
   36  * };
   37  * \endcode
   38  *
   39  *
   40  *    hints is an optional pointer to a struct addrinfo. This structure can
   41  *    be used to provide hints concerning the type of socket that the caller
   42  *    supports or wishes to use. The caller can supply the following
   43  *    structure elements in *hints:
   44  *
   45  * <ul>
   46  *    <li>ai_family:
   47  *           The protocol family that should be used. When ai_family is set
   48  *           to PF_UNSPEC, it means the caller will accept any protocol
   49  *           family supported by the operating system.</li>
   50  *
   51  *    <li>ai_socktype:
   52  *           denotes the type of socket -- SOCK_STREAM, SOCK_DGRAM or
   53  *           SOCK_RAW -- that is wanted. When ai_socktype is zero the caller
   54  *           will accept any socket type.</li>
   55  *
   56  *    <li>ai_protocol:
   57  *           indicates which transport protocol is wanted: IPPROTO_UDP or
   58  *           IPPROTO_TCP. If ai_protocol is zero the caller will accept any
   59  *           protocol.</li>
   60  *
   61  *    <li>ai_flags:
   62  *           Flag bits. If the AI_CANONNAME bit is set, a successful call to
   63  *           getaddrinfo() will return a null-terminated string
   64  *           containing the canonical name of the specified hostname in
   65  *           ai_canonname of the first addrinfo structure returned. Setting
   66  *           the AI_PASSIVE bit indicates that the returned socket address
   67  *           structure is intended for used in a call to bind(2). In this
   68  *           case, if the hostname argument is a NULL pointer, then the IP
   69  *           address portion of the socket address structure will be set to
   70  *           INADDR_ANY for an IPv4 address or IN6ADDR_ANY_INIT for an IPv6
   71  *           address.<br /><br />
   72  *
   73  *           When ai_flags does not set the AI_PASSIVE bit, the returned
   74  *           socket address structure will be ready for use in a call to
   75  *           connect(2) for a connection-oriented protocol or connect(2),
   76  *           sendto(2), or sendmsg(2) if a connectionless protocol was
   77  *           chosen. The IP address portion of the socket address structure
   78  *           will be set to the loopback address if hostname is a NULL
   79  *           pointer and AI_PASSIVE is not set in ai_flags.<br /><br />
   80  *
   81  *           If ai_flags is set to AI_NUMERICHOST it indicates that hostname
   82  *           should be treated as a numeric string defining an IPv4 or IPv6
   83  *           address and no name resolution should be attempted.
   84  * </li></ul>
   85  *
   86  *    All other elements of the struct addrinfo passed via hints must be
   87  *    zero.
   88  *
   89  *    A hints of NULL is treated as if the caller provided a struct addrinfo
   90  *    initialized to zero with ai_familyset to PF_UNSPEC.
   91  *
   92  *    After a successful call to getaddrinfo(), *res is a pointer to a
   93  *    linked list of one or more addrinfo structures. Each struct addrinfo
   94  *    in this list cn be processed by following the ai_next pointer, until a
   95  *    NULL pointer is encountered. The three members ai_family, ai_socktype,
   96  *    and ai_protocol in each returned addrinfo structure contain the
   97  *    corresponding arguments for a call to socket(2). For each addrinfo
   98  *    structure in the list, the ai_addr member points to a filled-in socket
   99  *    address structure of length ai_addrlen.
  100  *
  101  *    All of the information returned by getaddrinfo() is dynamically
  102  *    allocated: the addrinfo structures, and the socket address structures
  103  *    and canonical host name strings pointed to by the addrinfostructures.
  104  *    Memory allocated for the dynamically allocated structures created by a
  105  *    successful call to getaddrinfo() is released by freeaddrinfo().
  106  *    ai is a pointer to a struct addrinfo created by a call to getaddrinfo().
  107  *
  108  * \section irsreturn RETURN VALUES
  109  *
  110  *    getaddrinfo() returns zero on success or one of the error codes
  111  *    listed in gai_strerror() if an error occurs. If both hostname and
  112  *    servname are NULL getaddrinfo() returns #EAI_NONAME.
  113  *
  114  * \section irssee SEE ALSO
  115  *
  116  *    getaddrinfo(), freeaddrinfo(),
  117  *    gai_strerror(), RFC3493, getservbyname(3), connect(2),
  118  *    sendto(2), sendmsg(2), socket(2).
  119  */
  120 
  121 #include <errno.h>
  122 #include <inttypes.h>
  123 #include <stdbool.h>
  124 #include <stdlib.h>
  125 #include <string.h>
  126 
  127 #ifdef _WIN32
  128 #include <windows.h>
  129 #include <winsock2.h>
  130 #include <ws2tcpip.h>
  131 #endif /* ifdef _WIN32 */
  132 
  133 #include <isc/app.h>
  134 #include <isc/buffer.h>
  135 #include <isc/lib.h>
  136 #include <isc/mem.h>
  137 #include <isc/mutex.h>
  138 #include <isc/print.h>
  139 #include <isc/sockaddr.h>
  140 #include <isc/string.h>
  141 #include <isc/util.h>
  142 
  143 #include <dns/client.h>
  144 #include <dns/fixedname.h>
  145 #include <dns/name.h>
  146 #include <dns/rdata.h>
  147 #include <dns/rdataset.h>
  148 #include <dns/rdatastruct.h>
  149 #include <dns/rdatatype.h>
  150 #include <dns/result.h>
  151 
  152 #include <irs/context.h>
  153 #include <irs/netdb.h>
  154 #include <irs/resconf.h>
  155 
  156 #define SA(addr)     ((struct sockaddr *)(addr))
  157 #define SIN(addr)    ((struct sockaddr_in *)(addr))
  158 #define SIN6(addr)   ((struct sockaddr_in6 *)(addr))
  159 #define SLOCAL(addr) ((struct sockaddr_un *)(addr))
  160 
  161 /*! \struct addrinfo
  162  */
  163 static struct addrinfo *
  164 ai_concat(struct addrinfo *ai1, struct addrinfo *ai2),
  165     *ai_reverse(struct addrinfo *oai),
  166     *ai_clone(struct addrinfo *oai, int family),
  167     *ai_alloc(int family, int addrlen);
  168 #ifdef AF_LOCAL
  169 static int
  170 get_local(const char *name, int socktype, struct addrinfo **res);
  171 #endif /* ifdef AF_LOCAL */
  172 
  173 static int
  174 resolve_name(int family, const char *hostname, int flags, struct addrinfo **aip,
  175          int socktype, int port);
  176 
  177 static int
  178 add_ipv4(const char *hostname, int flags, struct addrinfo **aip, int socktype,
  179      int port);
  180 static int
  181 add_ipv6(const char *hostname, int flags, struct addrinfo **aip, int socktype,
  182      int port);
  183 static void
  184 set_order(int, int (**)(const char *, int, struct addrinfo **, int, int));
  185 static void
  186 _freeaddrinfo(struct addrinfo *ai);
  187 
  188 #define FOUND_IPV4 0x1
  189 #define FOUND_IPV6 0x2
  190 #define FOUND_MAX  2
  191 
  192 /*%
  193  * Try converting the scope identifier in 'src' to a network interface index.
  194  * Upon success, return true and store the resulting index in 'dst'.  Upon
  195  * failure, return false.
  196  */
  197 static bool
  198 parse_scopeid(const char *src, uint32_t *dst) {
  199     uint32_t scopeid = 0;
  200 
  201     REQUIRE(src != NULL);
  202     REQUIRE(dst != NULL);
  203 
  204 #ifdef HAVE_IF_NAMETOINDEX
  205     /*
  206      * Try using if_nametoindex() first if it is available.  As it does not
  207      * handle numeric scopes, we do not simply return if it fails.
  208      */
  209     scopeid = (uint32_t)if_nametoindex(src);
  210 #endif /* ifdef HAVE_IF_NAMETOINDEX */
  211 
  212     /*
  213      * Fall back to numeric scope processing if if_nametoindex() either
  214      * fails or is unavailable.
  215      */
  216     if (scopeid == 0) {
  217         char *endptr = NULL;
  218         scopeid = (uint32_t)strtoul(src, &endptr, 10);
  219         /*
  220          * The scope identifier must not be empty and no trailing
  221          * characters are allowed after it.
  222          */
  223         if (src == endptr || endptr == NULL || *endptr != '\0') {
  224             return (false);
  225         }
  226     }
  227 
  228     *dst = scopeid;
  229 
  230     return (true);
  231 }
  232 
  233 #define ISC_AI_MASK (AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST)
  234 /*%
  235  * Get a list of IP addresses and port numbers for host hostname and
  236  * service servname.
  237  */
  238 int
  239 getaddrinfo(const char *hostname, const char *servname,
  240         const struct addrinfo *hints, struct addrinfo **res) {
  241     struct servent *sp;
  242     const char *proto;
  243     int family, socktype, flags, protocol;
  244     struct addrinfo *ai, *ai_list;
  245     int err = 0;
  246     int port, i;
  247     int (*net_order[FOUND_MAX + 1])(const char *, int, struct addrinfo **,
  248                     int, int);
  249 
  250     if (hostname == NULL && servname == NULL) {
  251         return (EAI_NONAME);
  252     }
  253 
  254     proto = NULL;
  255     if (hints != NULL) {
  256         if ((hints->ai_flags & ~(ISC_AI_MASK)) != 0) {
  257             return (EAI_BADFLAGS);
  258         }
  259         if (hints->ai_addrlen || hints->ai_canonname ||
  260             hints->ai_addr || hints->ai_next)
  261         {
  262             errno = EINVAL;
  263             return (EAI_SYSTEM);
  264         }
  265         family = hints->ai_family;
  266         socktype = hints->ai_socktype;
  267         protocol = hints->ai_protocol;
  268         flags = hints->ai_flags;
  269         switch (family) {
  270         case AF_UNSPEC:
  271             switch (hints->ai_socktype) {
  272             case SOCK_STREAM:
  273                 proto = "tcp";
  274                 break;
  275             case SOCK_DGRAM:
  276                 proto = "udp";
  277                 break;
  278             }
  279             break;
  280         case AF_INET:
  281         case AF_INET6:
  282             switch (hints->ai_socktype) {
  283             case 0:
  284                 break;
  285             case SOCK_STREAM:
  286                 proto = "tcp";
  287                 break;
  288             case SOCK_DGRAM:
  289                 proto = "udp";
  290                 break;
  291             case SOCK_RAW:
  292                 break;
  293             default:
  294                 return (EAI_SOCKTYPE);
  295             }
  296             break;
  297 #ifdef AF_LOCAL
  298         case AF_LOCAL:
  299             switch (hints->ai_socktype) {
  300             case 0:
  301                 break;
  302             case SOCK_STREAM:
  303                 break;
  304             case SOCK_DGRAM:
  305                 break;
  306             default:
  307                 return (EAI_SOCKTYPE);
  308             }
  309             break;
  310 #endif /* ifdef AF_LOCAL */
  311         default:
  312             return (EAI_FAMILY);
  313         }
  314     } else {
  315         protocol = 0;
  316         family = 0;
  317         socktype = 0;
  318         flags = 0;
  319     }
  320 
  321 #ifdef AF_LOCAL
  322     /*!
  323      * First, deal with AF_LOCAL.  If the family was not set,
  324      * then assume AF_LOCAL if the first character of the
  325      * hostname/servname is '/'.
  326      */
  327 
  328     if (hostname != NULL &&
  329         (family == AF_LOCAL || (family == 0 && *hostname == '/')))
  330     {
  331         return (get_local(hostname, socktype, res));
  332     }
  333 
  334     if (servname != NULL &&
  335         (family == AF_LOCAL || (family == 0 && *servname == '/')))
  336     {
  337         return (get_local(servname, socktype, res));
  338     }
  339 #endif /* ifdef AF_LOCAL */
  340 
  341     /*
  342      * Ok, only AF_INET and AF_INET6 left.
  343      */
  344     ai_list = NULL;
  345 
  346     /*
  347      * First, look up the service name (port) if it was
  348      * requested.  If the socket type wasn't specified, then
  349      * try and figure it out.
  350      */
  351     if (servname != NULL) {
  352         char *e;
  353 
  354         port = strtol(servname, &e, 10);
  355         if (*e == '\0') {
  356             if (socktype == 0) {
  357                 return (EAI_SOCKTYPE);
  358             }
  359             if (port < 0 || port > 65535) {
  360                 return (EAI_SERVICE);
  361             }
  362             port = htons((unsigned short)port);
  363         } else {
  364 #ifdef _WIN32
  365             WORD wVersionRequested;
  366             WSADATA wsaData;
  367 
  368             wVersionRequested = MAKEWORD(2, 0);
  369 
  370             err = WSAStartup(wVersionRequested, &wsaData);
  371             if (err != 0) {
  372                 return (EAI_FAIL);
  373             }
  374 #endif /* ifdef _WIN32 */
  375             sp = getservbyname(servname, proto);
  376             if (sp != NULL) {
  377                 port = sp->s_port;
  378             }
  379 #ifdef _WIN32
  380             WSACleanup();
  381 #endif /* ifdef _WIN32 */
  382             if (sp == NULL) {
  383                 return (EAI_SERVICE);
  384             }
  385             if (socktype == 0) {
  386                 if (strcmp(sp->s_proto, "tcp") == 0) {
  387                     socktype = SOCK_STREAM;
  388                 } else if (strcmp(sp->s_proto, "udp") == 0) {
  389                     socktype = SOCK_DGRAM;
  390                 }
  391             }
  392         }
  393     } else {
  394         port = 0;
  395     }
  396 
  397     /*
  398      * Next, deal with just a service name, and no hostname.
  399      * (we verified that one of them was non-null up above).
  400      */
  401     if (hostname == NULL && (flags & AI_PASSIVE) != 0) {
  402         if (family == AF_INET || family == 0) {
  403             ai = ai_alloc(AF_INET, sizeof(struct sockaddr_in));
  404             if (ai == NULL) {
  405                 return (EAI_MEMORY);
  406             }
  407             ai->ai_socktype = socktype;
  408             ai->ai_protocol = protocol;
  409             SIN(ai->ai_addr)->sin_port = port;
  410             ai->ai_next = ai_list;
  411             ai_list = ai;
  412         }
  413 
  414         if (family == AF_INET6 || family == 0) {
  415             ai = ai_alloc(AF_INET6, sizeof(struct sockaddr_in6));
  416             if (ai == NULL) {
  417                 _freeaddrinfo(ai_list);
  418                 return (EAI_MEMORY);
  419             }
  420             ai->ai_socktype = socktype;
  421             ai->ai_protocol = protocol;
  422             SIN6(ai->ai_addr)->sin6_port = port;
  423             ai->ai_next = ai_list;
  424             ai_list = ai;
  425         }
  426 
  427         *res = ai_list;
  428         return (0);
  429     }
  430 
  431     /*
  432      * If the family isn't specified or AI_NUMERICHOST specified, check
  433      * first to see if it is a numeric address.
  434      * Though the gethostbyname2() routine will recognize numeric addresses,
  435      * it will only recognize the format that it is being called for.  Thus,
  436      * a numeric AF_INET address will be treated by the AF_INET6 call as
  437      * a domain name, and vice versa.  Checking for both numerics here
  438      * avoids that.
  439      */
  440     if (hostname != NULL && (family == 0 || (flags & AI_NUMERICHOST) != 0))
  441     {
  442         char abuf[sizeof(struct in6_addr)];
  443         char nbuf[NI_MAXHOST];
  444         int addrsize, addroff;
  445         char ntmp[NI_MAXHOST];
  446         uint32_t scopeid = 0;
  447 
  448         /*
  449          * Scope identifier portion.
  450          */
  451         ntmp[0] = '\0';
  452         if (strchr(hostname, '%') != NULL) {
  453             char *p;
  454             strlcpy(ntmp, hostname, sizeof(ntmp));
  455             p = strchr(ntmp, '%');
  456 
  457             if (p != NULL && parse_scopeid(p + 1, &scopeid)) {
  458                 *p = '\0';
  459             } else {
  460                 ntmp[0] = '\0';
  461             }
  462         }
  463 
  464         if (inet_pton(AF_INET, hostname, (struct in_addr *)abuf) == 1) {
  465             if (family == AF_INET6) {
  466                 /*
  467                  * Convert to a V4 mapped address.
  468                  */
  469                 struct in6_addr *a6 = (struct in6_addr *)abuf;
  470                 memmove(&a6->s6_addr[12], &a6->s6_addr[0], 4);
  471                 memset(&a6->s6_addr[10], 0xff, 2);
  472                 memset(&a6->s6_addr[0], 0, 10);
  473                 goto inet6_addr;
  474             }
  475             addrsize = sizeof(struct in_addr);
  476             addroff = offsetof(struct sockaddr_in, sin_addr);
  477             family = AF_INET;
  478             goto common;
  479         } else if (ntmp[0] != '\0' &&
  480                inet_pton(AF_INET6, ntmp, abuf) == 1) {
  481             if (family && family != AF_INET6) {
  482                 return (EAI_NONAME);
  483             }
  484             addrsize = sizeof(struct in6_addr);
  485             addroff = offsetof(struct sockaddr_in6, sin6_addr);
  486             family = AF_INET6;
  487             goto common;
  488         } else if (inet_pton(AF_INET6, hostname, abuf) == 1) {
  489             if (family != 0 && family != AF_INET6) {
  490                 return (EAI_NONAME);
  491             }
  492         inet6_addr:
  493             addrsize = sizeof(struct in6_addr);
  494             addroff = offsetof(struct sockaddr_in6, sin6_addr);
  495             family = AF_INET6;
  496 
  497         common:
  498             ai = ai_alloc(family,
  499                       ((family == AF_INET6)
  500                            ? sizeof(struct sockaddr_in6)
  501                            : sizeof(struct sockaddr_in)));
  502             if (ai == NULL) {
  503                 return (EAI_MEMORY);
  504             }
  505             ai_list = ai;
  506             ai->ai_socktype = socktype;
  507             SIN(ai->ai_addr)->sin_port = port;
  508             memmove((char *)ai->ai_addr + addroff, abuf, addrsize);
  509             if (ai->ai_family == AF_INET6) {
  510                 SIN6(ai->ai_addr)->sin6_scope_id = scopeid;
  511             }
  512             if ((flags & AI_CANONNAME) != 0) {
  513                 if (getnameinfo(ai->ai_addr,
  514                         (socklen_t)ai->ai_addrlen, nbuf,
  515                         sizeof(nbuf), NULL, 0,
  516                         NI_NUMERICHOST) == 0)
  517                 {
  518                     ai->ai_canonname = strdup(nbuf);
  519                     if (ai->ai_canonname == NULL) {
  520                         _freeaddrinfo(ai);
  521                         return (EAI_MEMORY);
  522                     }
  523                 } else {
  524                     /* XXX raise error? */
  525                     ai->ai_canonname = NULL;
  526                 }
  527             }
  528             goto done;
  529         } else if ((flags & AI_NUMERICHOST) != 0) {
  530             return (EAI_NONAME);
  531         }
  532     }
  533 
  534     if (hostname == NULL && (flags & AI_PASSIVE) == 0) {
  535         set_order(family, net_order);
  536         for (i = 0; i < FOUND_MAX; i++) {
  537             if (net_order[i] == NULL) {
  538                 break;
  539             }
  540             err = (net_order[i])(hostname, flags, &ai_list,
  541                          socktype, port);
  542             if (err != 0) {
  543                 if (ai_list != NULL) {
  544                     _freeaddrinfo(ai_list);
  545                     ai_list = NULL;
  546                 }
  547                 break;
  548             }
  549         }
  550     } else {
  551         err = resolve_name(family, hostname, flags, &ai_list, socktype,
  552                    port);
  553     }
  554 
  555     if (ai_list == NULL) {
  556         if (err == 0) {
  557             err = EAI_NONAME;
  558         }
  559         return (err);
  560     }
  561 
  562 done:
  563     ai_list = ai_reverse(ai_list);
  564 
  565     *res = ai_list;
  566     return (0);
  567 }
  568 
  569 typedef struct gai_restrans {
  570     dns_clientrestrans_t *xid;
  571     bool is_inprogress;
  572     int error;
  573     struct addrinfo ai_sentinel;
  574     struct gai_resstate *resstate;
  575 } gai_restrans_t;
  576 
  577 typedef struct gai_resstate {
  578     isc_mem_t *mctx;
  579     struct gai_statehead *head;
  580     dns_fixedname_t fixedname;
  581     dns_name_t *qname;
  582     gai_restrans_t *trans4;
  583     gai_restrans_t *trans6;
  584     ISC_LINK(struct gai_resstate) link;
  585 } gai_resstate_t;
  586 
  587 typedef struct gai_statehead {
  588     int ai_family;
  589     int ai_flags;
  590     int ai_socktype;
  591     int ai_port;
  592     isc_appctx_t *actx;
  593     dns_client_t *dnsclient;
  594     isc_mutex_t list_lock;
  595     ISC_LIST(struct gai_resstate) resstates;
  596     unsigned int activestates;
  597 } gai_statehead_t;
  598 
  599 static isc_result_t
  600 make_resstate(isc_mem_t *mctx, gai_statehead_t *head, const char *hostname,
  601           const char *domain, gai_resstate_t **statep) {
  602     isc_result_t result;
  603     gai_resstate_t *state;
  604     dns_fixedname_t fixeddomain;
  605     dns_name_t *qdomain;
  606     unsigned int namelen;
  607     isc_buffer_t b;
  608     bool need_v4 = false;
  609     bool need_v6 = false;
  610 
  611     state = isc_mem_get(mctx, sizeof(*state));
  612 
  613     /* Construct base domain name */
  614     namelen = strlen(domain);
  615     isc_buffer_constinit(&b, domain, namelen);
  616     isc_buffer_add(&b, namelen);
  617     qdomain = dns_fixedname_initname(&fixeddomain);
  618     result = dns_name_fromtext(qdomain, &b, dns_rootname, 0, NULL);
  619     if (result != ISC_R_SUCCESS) {
  620         isc_mem_put(mctx, state, sizeof(*state));
  621         return (result);
  622     }
  623 
  624     /* Construct query name */
  625     namelen = strlen(hostname);
  626     isc_buffer_constinit(&b, hostname, namelen);
  627     isc_buffer_add(&b, namelen);
  628     state->qname = dns_fixedname_initname(&state->fixedname);
  629     result = dns_name_fromtext(state->qname, &b, qdomain, 0, NULL);
  630     if (result != ISC_R_SUCCESS) {
  631         isc_mem_put(mctx, state, sizeof(*state));
  632         return (result);
  633     }
  634 
  635     if (head->ai_family == AF_UNSPEC || head->ai_family == AF_INET) {
  636         need_v4 = true;
  637     }
  638     if (head->ai_family == AF_UNSPEC || head->ai_family == AF_INET6) {
  639         need_v6 = true;
  640     }
  641 
  642     state->trans6 = NULL;
  643     state->trans4 = NULL;
  644     if (need_v4) {
  645         state->trans4 = isc_mem_get(mctx, sizeof(gai_restrans_t));
  646         state->trans4->error = 0;
  647         state->trans4->xid = NULL;
  648         state->trans4->resstate = state;
  649         state->trans4->is_inprogress = true;
  650         state->trans4->ai_sentinel.ai_next = NULL;
  651     }
  652     if (need_v6) {
  653         state->trans6 = isc_mem_get(mctx, sizeof(gai_restrans_t));
  654         state->trans6->error = 0;
  655         state->trans6->xid = NULL;
  656         state->trans6->resstate = state;
  657         state->trans6->is_inprogress = true;
  658         state->trans6->ai_sentinel.ai_next = NULL;
  659     }
  660 
  661     state->mctx = mctx;
  662     state->head = head;
  663     ISC_LINK_INIT(state, link);
  664 
  665     *statep = state;
  666 
  667     return (ISC_R_SUCCESS);
  668 }
  669 
  670 static isc_result_t
  671 make_resstates(isc_mem_t *mctx, const char *hostname, gai_statehead_t *head,
  672            irs_resconf_t *resconf) {
  673     isc_result_t result;
  674     irs_resconf_searchlist_t *searchlist;
  675     irs_resconf_search_t *searchent;
  676     gai_resstate_t *resstate, *resstate0;
  677 
  678     resstate0 = NULL;
  679     result = make_resstate(mctx, head, hostname, ".", &resstate0);
  680     if (result != ISC_R_SUCCESS) {
  681         return (result);
  682     }
  683 
  684     searchlist = irs_resconf_getsearchlist(resconf);
  685     for (searchent = ISC_LIST_HEAD(*searchlist); searchent != NULL;
  686          searchent = ISC_LIST_NEXT(searchent, link))
  687     {
  688         resstate = NULL;
  689         result = make_resstate(mctx, head, hostname,
  690                        (const char *)searchent->domain,
  691                        &resstate);
  692         if (result != ISC_R_SUCCESS) {
  693             break;
  694         }
  695 
  696         ISC_LIST_APPEND(head->resstates, resstate, link);
  697         head->activestates++;
  698     }
  699 
  700     /*
  701      * Insert the original hostname either at the head or the tail of the
  702      * state list, depending on the number of labels contained in the
  703      * original name and the 'ndots' configuration parameter.
  704      */
  705     if (dns_name_countlabels(resstate0->qname) >
  706         irs_resconf_getndots(resconf) + 1) {
  707         ISC_LIST_PREPEND(head->resstates, resstate0, link);
  708     } else {
  709         ISC_LIST_APPEND(head->resstates, resstate0, link);
  710     }
  711     head->activestates++;
  712 
  713     if (result != ISC_R_SUCCESS) {
  714         while ((resstate = ISC_LIST_HEAD(head->resstates)) != NULL) {
  715             ISC_LIST_UNLINK(head->resstates, resstate, link);
  716             if (resstate->trans4 != NULL) {
  717                 isc_mem_put(mctx, resstate->trans4,
  718                         sizeof(*resstate->trans4));
  719             }
  720             if (resstate->trans6 != NULL) {
  721                 isc_mem_put(mctx, resstate->trans6,
  722                         sizeof(*resstate->trans6));
  723             }
  724 
  725             isc_mem_put(mctx, resstate, sizeof(*resstate));
  726         }
  727     }
  728 
  729     return (result);
  730 }
  731 
  732 static void
  733 process_answer(isc_task_t *task, isc_event_t *event) {
  734     int error = 0, family;
  735     gai_restrans_t *trans = event->ev_arg;
  736     gai_resstate_t *resstate;
  737     dns_clientresevent_t *rev = (dns_clientresevent_t *)event;
  738     dns_rdatatype_t qtype;
  739     dns_name_t *name;
  740     bool wantcname;
  741 
  742     REQUIRE(trans != NULL);
  743     resstate = trans->resstate;
  744     REQUIRE(resstate != NULL);
  745     REQUIRE(task != NULL);
  746 
  747     if (trans == resstate->trans4) {
  748         family = AF_INET;
  749         qtype = dns_rdatatype_a;
  750     } else {
  751         INSIST(trans == resstate->trans6);
  752         family = AF_INET6;
  753         qtype = dns_rdatatype_aaaa;
  754     }
  755 
  756     INSIST(trans->is_inprogress);
  757     trans->is_inprogress = false;
  758 
  759     switch (rev->result) {
  760     case ISC_R_SUCCESS:
  761     case DNS_R_NCACHENXDOMAIN: /* treat this as a fatal error? */
  762     case DNS_R_NCACHENXRRSET:
  763         break;
  764     default:
  765         switch (rev->vresult) {
  766         case DNS_R_SIGINVALID:
  767         case DNS_R_SIGEXPIRED:
  768         case DNS_R_SIGFUTURE:
  769         case DNS_R_KEYUNAUTHORIZED:
  770         case DNS_R_MUSTBESECURE:
  771         case DNS_R_COVERINGNSEC:
  772         case DNS_R_NOTAUTHORITATIVE:
  773         case DNS_R_NOVALIDKEY:
  774         case DNS_R_NOVALIDDS:
  775         case DNS_R_NOVALIDSIG:
  776             error = EAI_INSECUREDATA;
  777             break;
  778         default:
  779             error = EAI_FAIL;
  780         }
  781         goto done;
  782     }
  783 
  784     wantcname = ((resstate->head->ai_flags & AI_CANONNAME) != 0);
  785 
  786     /* Parse the response and construct the addrinfo chain */
  787     for (name = ISC_LIST_HEAD(rev->answerlist); name != NULL;
  788          name = ISC_LIST_NEXT(name, link))
  789     {
  790         isc_result_t result;
  791         dns_rdataset_t *rdataset;
  792         char cname[1024];
  793 
  794         if (wantcname) {
  795             isc_buffer_t b;
  796 
  797             isc_buffer_init(&b, cname, sizeof(cname));
  798             result = dns_name_totext(name, true, &b);
  799             if (result != ISC_R_SUCCESS) {
  800                 error = EAI_FAIL;
  801                 goto done;
  802             }
  803             isc_buffer_putuint8(&b, '\0');
  804         }
  805 
  806         for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL;
  807              rdataset = ISC_LIST_NEXT(rdataset, link))
  808         {
  809             if (!dns_rdataset_isassociated(rdataset)) {
  810                 continue;
  811             }
  812             if (rdataset->type != qtype) {
  813                 continue;
  814             }
  815 
  816             for (result = dns_rdataset_first(rdataset);
  817                  result == ISC_R_SUCCESS;
  818                  result = dns_rdataset_next(rdataset))
  819             {
  820                 struct addrinfo *ai;
  821                 dns_rdata_t rdata;
  822                 dns_rdata_in_a_t rdata_a;
  823                 dns_rdata_in_aaaa_t rdata_aaaa;
  824 
  825                 ai = ai_alloc(
  826                     family,
  827                     ((family == AF_INET6)
  828                          ? sizeof(struct sockaddr_in6)
  829                          : sizeof(struct sockaddr_in)));
  830                 if (ai == NULL) {
  831                     error = EAI_MEMORY;
  832                     goto done;
  833                 }
  834                 ai->ai_socktype = resstate->head->ai_socktype;
  835                 ai->ai_next = trans->ai_sentinel.ai_next;
  836                 trans->ai_sentinel.ai_next = ai;
  837 
  838                 /*
  839                  * Set AF-specific parameters
  840                  * (IPv4/v6 address/port)
  841                  */
  842                 dns_rdata_init(&rdata);
  843                 switch (family) {
  844                 case AF_INET:
  845                     dns_rdataset_current(rdataset, &rdata);
  846                     result = dns_rdata_tostruct(
  847                         &rdata, &rdata_a, NULL);
  848                     RUNTIME_CHECK(result == ISC_R_SUCCESS);
  849                     SIN(ai->ai_addr)->sin_port =
  850                         resstate->head->ai_port;
  851                     memmove(&SIN(ai->ai_addr)->sin_addr,
  852                         &rdata_a.in_addr, 4);
  853                     dns_rdata_freestruct(&rdata_a);
  854                     break;
  855                 case AF_INET6:
  856                     dns_rdataset_current(rdataset, &rdata);
  857                     result = dns_rdata_tostruct(
  858                         &rdata, &rdata_aaaa, NULL);
  859                     RUNTIME_CHECK(result == ISC_R_SUCCESS);
  860                     SIN6(ai->ai_addr)->sin6_port =
  861                         resstate->head->ai_port;
  862                     memmove(&SIN6(ai->ai_addr)->sin6_addr,
  863                         &rdata_aaaa.in6_addr, 16);
  864                     dns_rdata_freestruct(&rdata_aaaa);
  865                     break;
  866                 }
  867 
  868                 if (wantcname) {
  869                     ai->ai_canonname = strdup(cname);
  870                     if (ai->ai_canonname == NULL) {
  871                         error = EAI_MEMORY;
  872                         goto done;
  873                     }
  874                 }
  875             }
  876         }
  877     }
  878 
  879 done:
  880     dns_client_freeresanswer(resstate->head->dnsclient, &rev->answerlist);
  881     dns_client_destroyrestrans(&trans->xid);
  882 
  883     isc_event_free(&event);
  884 
  885     /* Make sure that error == 0 iff we have a non-empty list */
  886     if (error == 0) {
  887         if (trans->ai_sentinel.ai_next == NULL) {
  888             error = EAI_NONAME;
  889         }
  890     } else {
  891         if (trans->ai_sentinel.ai_next != NULL) {
  892             _freeaddrinfo(trans->ai_sentinel.ai_next);
  893             trans->ai_sentinel.ai_next = NULL;
  894         }
  895     }
  896     trans->error = error;
  897 
  898     /* Check whether we are done */
  899     if ((resstate->trans4 == NULL || !resstate->trans4->is_inprogress) &&
  900         (resstate->trans6 == NULL || !resstate->trans6->is_inprogress))
  901     {
  902         /*
  903          * We're done for this state.  If there is no other outstanding
  904          * state, we can exit.
  905          */
  906         resstate->head->activestates--;
  907         if (resstate->head->activestates == 0) {
  908             isc_app_ctxsuspend(resstate->head->actx);
  909             return;
  910         }
  911 
  912         /*
  913          * There are outstanding states, but if we are at the head
  914          * of the state list (i.e., at the highest search priority)
  915          * and have any answer, we can stop now by canceling the
  916          * others.
  917          */
  918         LOCK(&resstate->head->list_lock);
  919         if (resstate == ISC_LIST_HEAD(resstate->head->resstates)) {
  920             if ((resstate->trans4 != NULL &&
  921                  resstate->trans4->ai_sentinel.ai_next != NULL) ||
  922                 (resstate->trans6 != NULL &&
  923                  resstate->trans6->ai_sentinel.ai_next != NULL))
  924             {
  925                 gai_resstate_t *rest;
  926 
  927                 for (rest = ISC_LIST_NEXT(resstate, link);
  928                      rest != NULL;
  929                      rest = ISC_LIST_NEXT(rest, link))
  930                 {
  931                     if (rest->trans4 != NULL &&
  932                         rest->trans4->xid != NULL) {
  933                         dns_client_cancelresolve(
  934                             rest->trans4->xid);
  935                     }
  936                     if (rest->trans6 != NULL &&
  937                         rest->trans6->xid != NULL) {
  938                         dns_client_cancelresolve(
  939                             rest->trans6->xid);
  940                     }
  941                 }
  942             } else {
  943                 /*
  944                  * This search fails, so we move to the tail
  945                  * of the list so that the next entry will
  946                  * have the highest priority.
  947                  */
  948                 ISC_LIST_UNLINK(resstate->head->resstates,
  949                         resstate, link);
  950                 ISC_LIST_APPEND(resstate->head->resstates,
  951                         resstate, link);
  952             }
  953         }
  954         UNLOCK(&resstate->head->list_lock);
  955     }
  956 }
  957 
  958 static int
  959 resolve_name(int family, const char *hostname, int flags, struct addrinfo **aip,
  960          int socktype, int port) {
  961     isc_result_t result;
  962     irs_context_t *irsctx;
  963     irs_resconf_t *conf;
  964     isc_mem_t *mctx;
  965     isc_appctx_t *actx;
  966     isc_task_t *task;
  967     int terror = 0;
  968     int error = 0;
  969     dns_client_t *client;
  970     gai_resstate_t *resstate;
  971     gai_statehead_t head;
  972     bool all_fail = true;
  973 
  974     /* get IRS context and the associated parameters */
  975     irsctx = NULL;
  976     result = irs_context_get(&irsctx);
  977     if (result != ISC_R_SUCCESS) {
  978         return (EAI_FAIL);
  979     }
  980     actx = irs_context_getappctx(irsctx);
  981 
  982     mctx = irs_context_getmctx(irsctx);
  983     task = irs_context_gettask(irsctx);
  984     conf = irs_context_getresconf(irsctx);
  985     client = irs_context_getdnsclient(irsctx);
  986 
  987     /* construct resolution states */
  988     head.activestates = 0;
  989     head.ai_family = family;
  990     head.ai_socktype = socktype;
  991     head.ai_flags = flags;
  992     head.ai_port = port;
  993     head.actx = actx;
  994     head.dnsclient = client;
  995     isc_mutex_init(&head.list_lock);
  996 
  997     ISC_LIST_INIT(head.resstates);
  998     result = make_resstates(mctx, hostname, &head, conf);
  999     if (result != ISC_R_SUCCESS) {
 1000         isc_mutex_destroy(&head.list_lock);
 1001         return (EAI_FAIL);
 1002     }
 1003 
 1004     LOCK(&head.list_lock);
 1005     for (resstate = ISC_LIST_HEAD(head.resstates); resstate != NULL;
 1006          resstate = ISC_LIST_NEXT(resstate, link))
 1007     {
 1008         if (resstate->trans4 != NULL) {
 1009             result = dns_client_startresolve(
 1010                 client, resstate->qname, dns_rdataclass_in,
 1011                 dns_rdatatype_a, 0, task, process_answer,
 1012                 resstate->trans4, &resstate->trans4->xid);
 1013             if (result == ISC_R_SUCCESS) {
 1014                 resstate->trans4->is_inprogress = true;
 1015                 all_fail = false;
 1016             } else {
 1017                 resstate->trans4->is_inprogress = false;
 1018             }
 1019         }
 1020         if (resstate->trans6 != NULL) {
 1021             result = dns_client_startresolve(
 1022                 client, resstate->qname, dns_rdataclass_in,
 1023                 dns_rdatatype_aaaa, 0, task, process_answer,
 1024                 resstate->trans6, &resstate->trans6->xid);
 1025             if (result == ISC_R_SUCCESS) {
 1026                 resstate->trans6->is_inprogress = true;
 1027                 all_fail = false;
 1028             } else {
 1029                 resstate->trans6->is_inprogress = false;
 1030             }
 1031         }
 1032     }
 1033     UNLOCK(&head.list_lock);
 1034 
 1035     if (!all_fail) {
 1036         /* Start all the events */
 1037         isc_app_ctxrun(actx);
 1038     } else {
 1039         error = EAI_FAIL;
 1040     }
 1041 
 1042     /* Cleanup */
 1043     while ((resstate = ISC_LIST_HEAD(head.resstates)) != NULL) {
 1044         int terror4 = 0, terror6 = 0;
 1045 
 1046         ISC_LIST_UNLINK(head.resstates, resstate, link);
 1047 
 1048         if (*aip == NULL) {
 1049             struct addrinfo *sentinel4 = NULL;
 1050             struct addrinfo *sentinel6 = NULL;
 1051 
 1052             if (resstate->trans4 != NULL) {
 1053                 sentinel4 =
 1054                     resstate->trans4->ai_sentinel.ai_next;
 1055                 resstate->trans4->ai_sentinel.ai_next = NULL;
 1056             }
 1057             if (resstate->trans6 != NULL) {
 1058                 sentinel6 =
 1059                     resstate->trans6->ai_sentinel.ai_next;
 1060                 resstate->trans6->ai_sentinel.ai_next = NULL;
 1061             }
 1062             *aip = ai_concat(sentinel4, sentinel6);
 1063         }
 1064 
 1065         if (resstate->trans4 != NULL) {
 1066             INSIST(resstate->trans4->xid == NULL);
 1067             terror4 = resstate->trans4->error;
 1068             isc_mem_put(mctx, resstate->trans4,
 1069                     sizeof(*resstate->trans4));
 1070         }
 1071         if (resstate->trans6 != NULL) {
 1072             INSIST(resstate->trans6->xid == NULL);
 1073             terror6 = resstate->trans6->error;
 1074             isc_mem_put(mctx, resstate->trans6,
 1075                     sizeof(*resstate->trans6));
 1076         }
 1077 
 1078         /*
 1079          * If the entire lookup fails, we need to choose an appropriate
 1080          * error code from individual codes.  We'll try to provide as
 1081          * specific a code as possible.  In general, we are going to
 1082          * find an error code other than EAI_NONAME (which is too
 1083          * generic and may actually not be problematic in some cases).
 1084          * EAI_NONAME will be set below if no better code is found.
 1085          */
 1086         if (terror == 0 || terror == EAI_NONAME) {
 1087             if (terror4 != 0 && terror4 != EAI_NONAME) {
 1088                 terror = terror4;
 1089             } else if (terror6 != 0 && terror6 != EAI_NONAME) {
 1090                 terror = terror6;
 1091             }
 1092         }
 1093 
 1094         isc_mem_put(mctx, resstate, sizeof(*resstate));
 1095     }
 1096 
 1097     if (*aip == NULL) {
 1098         error = terror;
 1099         if (error == 0) {
 1100             error = EAI_NONAME;
 1101         }
 1102     }
 1103 
 1104 #if 1 /*  XXX: enabled for finding leaks.  should be cleaned up later. */
 1105     isc_app_ctxfinish(actx);
 1106     irs_context_destroy(&irsctx);
 1107 #endif /* if 1 */
 1108 
 1109     isc_mutex_destroy(&head.list_lock);
 1110     return (error);
 1111 }
 1112 
 1113 static void
 1114 set_order(int family,
 1115       int (**net_order)(const char *, int, struct addrinfo **, int, int)) {
 1116     char *order, *tok, *last;
 1117     int found;
 1118 
 1119     if (family) {
 1120         switch (family) {
 1121         case AF_INET:
 1122             *net_order++ = add_ipv4;
 1123             break;
 1124         case AF_INET6:
 1125             *net_order++ = add_ipv6;
 1126             break;
 1127         }
 1128     } else {
 1129         order = getenv("NET_ORDER");
 1130         found = 0;
 1131         if (order != NULL) {
 1132             last = NULL;
 1133             for (tok = strtok_r(order, ":", &last); tok;
 1134                  tok = strtok_r(NULL, ":", &last)) {
 1135                 if (strcasecmp(tok, "inet6") == 0) {
 1136                     if ((found & FOUND_IPV6) == 0) {
 1137                         *net_order++ = add_ipv6;
 1138                     }
 1139                     found |= FOUND_IPV6;
 1140                 } else if (strcasecmp(tok, "inet") == 0 ||
 1141                        strcasecmp(tok, "inet4") == 0) {
 1142                     if ((found & FOUND_IPV4) == 0) {
 1143                         *net_order++ = add_ipv4;
 1144                     }
 1145                     found |= FOUND_IPV4;
 1146                 }
 1147             }
 1148         }
 1149 
 1150         /*
 1151          * Add in anything that we didn't find.
 1152          */
 1153         if ((found & FOUND_IPV4) == 0) {
 1154             *net_order++ = add_ipv4;
 1155         }
 1156         if ((found & FOUND_IPV6) == 0) {
 1157             *net_order++ = add_ipv6;
 1158         }
 1159     }
 1160     *net_order = NULL;
 1161     return;
 1162 }
 1163 
 1164 static char v4_loop[4] = { 127, 0, 0, 1 };
 1165 
 1166 static int
 1167 add_ipv4(const char *hostname, int flags, struct addrinfo **aip, int socktype,
 1168      int port) {
 1169     struct addrinfo *ai;
 1170 
 1171     UNUSED(hostname);
 1172     UNUSED(flags);
 1173 
 1174     ai = ai_clone(*aip, AF_INET); /* don't use ai_clone() */
 1175     if (ai == NULL) {
 1176         return (EAI_MEMORY);
 1177     }
 1178 
 1179     *aip = ai;
 1180     ai->ai_socktype = socktype;
 1181     SIN(ai->ai_addr)->sin_port = port;
 1182     memmove(&SIN(ai->ai_addr)->sin_addr, v4_loop, 4);
 1183 
 1184     return (0);
 1185 }
 1186 
 1187 static char v6_loop[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
 1188 
 1189 static int
 1190 add_ipv6(const char *hostname, int flags, struct addrinfo **aip, int socktype,
 1191      int port) {
 1192     struct addrinfo *ai;
 1193 
 1194     UNUSED(hostname);
 1195     UNUSED(flags);
 1196 
 1197     ai = ai_clone(*aip, AF_INET6); /* don't use ai_clone() */
 1198     if (ai == NULL) {
 1199         return (EAI_MEMORY);
 1200     }
 1201 
 1202     *aip = ai;
 1203     ai->ai_socktype = socktype;
 1204     SIN6(ai->ai_addr)->sin6_port = port;
 1205     memmove(&SIN6(ai->ai_addr)->sin6_addr, v6_loop, 16);
 1206 
 1207     return (0);
 1208 }
 1209 
 1210 /*% Free address info. */
 1211 void
 1212 freeaddrinfo(struct addrinfo *ai) {
 1213     _freeaddrinfo(ai);
 1214 }
 1215 
 1216 static void
 1217 _freeaddrinfo(struct addrinfo *ai) {
 1218     struct addrinfo *ai_next;
 1219 
 1220     while (ai != NULL) {
 1221         ai_next = ai->ai_next;
 1222         if (ai->ai_addr != NULL) {
 1223             free(ai->ai_addr);
 1224         }
 1225         if (ai->ai_canonname) {
 1226             free(ai->ai_canonname);
 1227         }
 1228         free(ai);
 1229         ai = ai_next;
 1230     }
 1231 }
 1232 
 1233 #ifdef AF_LOCAL
 1234 static int
 1235 get_local(const char *name, int socktype, struct addrinfo **res) {
 1236     struct addrinfo *ai;
 1237     struct sockaddr_un *slocal;
 1238 
 1239     if (socktype == 0) {
 1240         return (EAI_SOCKTYPE);
 1241     }
 1242 
 1243     ai = ai_alloc(AF_LOCAL, sizeof(*slocal));
 1244     if (ai == NULL) {
 1245         return (EAI_MEMORY);
 1246     }
 1247 
 1248     slocal = SLOCAL(ai->ai_addr);
 1249     strlcpy(slocal->sun_path, name, sizeof(slocal->sun_path));
 1250 
 1251     ai->ai_socktype = socktype;
 1252     /*
 1253      * ai->ai_flags, ai->ai_protocol, ai->ai_canonname,
 1254      * and ai->ai_next were initialized to zero.
 1255      */
 1256 
 1257     *res = ai;
 1258     return (0);
 1259 }
 1260 #endif /* ifdef AF_LOCAL */
 1261 
 1262 /*!
 1263  * Allocate an addrinfo structure, and a sockaddr structure
 1264  * of the specified length.  We initialize:
 1265  *  ai_addrlen
 1266  *  ai_family
 1267  *  ai_addr
 1268  *  ai_addr->sa_family
 1269  *  ai_addr->sa_len (IRS_PLATFORM_HAVESALEN)
 1270  * and everything else is initialized to zero.
 1271  */
 1272 static struct addrinfo *
 1273 ai_alloc(int family, int addrlen) {
 1274     struct addrinfo *ai;
 1275 
 1276     ai = (struct addrinfo *)calloc(1, sizeof(*ai));
 1277     if (ai == NULL) {
 1278         return (NULL);
 1279     }
 1280 
 1281     ai->ai_addr = SA(calloc(1, addrlen));
 1282     if (ai->ai_addr == NULL) {
 1283         free(ai);
 1284         return (NULL);
 1285     }
 1286     ai->ai_addrlen = addrlen;
 1287     ai->ai_family = family;
 1288     ai->ai_addr->sa_family = family;
 1289 #ifdef IRS_PLATFORM_HAVESALEN
 1290     ai->ai_addr->sa_len = addrlen;
 1291 #endif /* ifdef IRS_PLATFORM_HAVESALEN */
 1292     return (ai);
 1293 }
 1294 
 1295 static struct addrinfo *
 1296 ai_clone(struct addrinfo *oai, int family) {
 1297     struct addrinfo *ai;
 1298 
 1299     ai = ai_alloc(family,
 1300               ((family == AF_INET6) ? sizeof(struct sockaddr_in6)
 1301                         : sizeof(struct sockaddr_in)));
 1302 
 1303     if (ai == NULL) {
 1304         return (NULL);
 1305     }
 1306     if (oai == NULL) {
 1307         return (ai);
 1308     }
 1309 
 1310     ai->ai_flags = oai->ai_flags;
 1311     ai->ai_socktype = oai->ai_socktype;
 1312     ai->ai_protocol = oai->ai_protocol;
 1313     ai->ai_canonname = NULL;
 1314     ai->ai_next = oai;
 1315     return (ai);
 1316 }
 1317 
 1318 static struct addrinfo *
 1319 ai_reverse(struct addrinfo *oai) {
 1320     struct addrinfo *nai, *tai;
 1321 
 1322     nai = NULL;
 1323 
 1324     while (oai != NULL) {
 1325         /*
 1326          * Grab one off the old list.
 1327          */
 1328         tai = oai;
 1329         oai = oai->ai_next;
 1330         /*
 1331          * Put it on the front of the new list.
 1332          */
 1333         tai->ai_next = nai;
 1334         nai = tai;
 1335     }
 1336     return (nai);
 1337 }
 1338 
 1339 static struct addrinfo *
 1340 ai_concat(struct addrinfo *ai1, struct addrinfo *ai2) {
 1341     struct addrinfo *ai_tmp;
 1342 
 1343     if (ai1 == NULL) {
 1344         return (ai2);
 1345     } else if (ai2 == NULL) {
 1346         return (ai1);
 1347     }
 1348 
 1349     for (ai_tmp = ai1; ai_tmp != NULL && ai_tmp->ai_next != NULL;
 1350          ai_tmp = ai_tmp->ai_next)
 1351     {
 1352     }
 1353 
 1354     ai_tmp->ai_next = ai2;
 1355 
 1356     return (ai1);
 1357 }