2 * Copyright (C) 2009, 2012-2015 Internet Systems Consortium, Inc. ("ISC")
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
9 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
11 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
13 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14 * PERFORMANCE OF THIS SOFTWARE.
17 /* $Id: getaddrinfo.c,v 1.3 2009/09/02 23:48:02 tbox Exp $ */
22 * getaddrinfo() is used to get a list of IP addresses and port
23 * numbers for host hostname and service servname as defined in RFC3493.
24 * hostname and servname are pointers to null-terminated strings
25 * or NULL. hostname is either a host name or a numeric host address
26 * string: a dotted decimal IPv4 address or an IPv6 address. servname is
27 * either a decimal port number or a service name as listed in
30 * If the operating system does not provide a struct addrinfo, the
31 * following structure is used:
35 * int ai_flags; // AI_PASSIVE, AI_CANONNAME
36 * int ai_family; // PF_xxx
37 * int ai_socktype; // SOCK_xxx
38 * int ai_protocol; // 0 or IPPROTO_xxx for IPv4 and IPv6
39 * size_t ai_addrlen; // length of ai_addr
40 * char *ai_canonname; // canonical name for hostname
41 * struct sockaddr *ai_addr; // binary address
42 * struct addrinfo *ai_next; // next structure in linked list
47 * hints is an optional pointer to a struct addrinfo. This structure can
48 * be used to provide hints concerning the type of socket that the caller
49 * supports or wishes to use. The caller can supply the following
50 * structure elements in *hints:
54 * The protocol family that should be used. When ai_family is set
55 * to PF_UNSPEC, it means the caller will accept any protocol
56 * family supported by the operating system.</li>
59 * denotes the type of socket -- SOCK_STREAM, SOCK_DGRAM or
60 * SOCK_RAW -- that is wanted. When ai_socktype is zero the caller
61 * will accept any socket type.</li>
64 * indicates which transport protocol is wanted: IPPROTO_UDP or
65 * IPPROTO_TCP. If ai_protocol is zero the caller will accept any
69 * Flag bits. If the AI_CANONNAME bit is set, a successful call to
70 * getaddrinfo() will return a null-terminated string
71 * containing the canonical name of the specified hostname in
72 * ai_canonname of the first addrinfo structure returned. Setting
73 * the AI_PASSIVE bit indicates that the returned socket address
74 * structure is intended for used in a call to bind(2). In this
75 * case, if the hostname argument is a NULL pointer, then the IP
76 * address portion of the socket address structure will be set to
77 * INADDR_ANY for an IPv4 address or IN6ADDR_ANY_INIT for an IPv6
78 * address.<br /><br />
80 * When ai_flags does not set the AI_PASSIVE bit, the returned
81 * socket address structure will be ready for use in a call to
82 * connect(2) for a connection-oriented protocol or connect(2),
83 * sendto(2), or sendmsg(2) if a connectionless protocol was
84 * chosen. The IP address portion of the socket address structure
85 * will be set to the loopback address if hostname is a NULL
86 * pointer and AI_PASSIVE is not set in ai_flags.<br /><br />
88 * If ai_flags is set to AI_NUMERICHOST it indicates that hostname
89 * should be treated as a numeric string defining an IPv4 or IPv6
90 * address and no name resolution should be attempted.
93 * All other elements of the struct addrinfo passed via hints must be
96 * A hints of NULL is treated as if the caller provided a struct addrinfo
97 * initialized to zero with ai_familyset to PF_UNSPEC.
99 * After a successful call to getaddrinfo(), *res is a pointer to a
100 * linked list of one or more addrinfo structures. Each struct addrinfo
101 * in this list cn be processed by following the ai_next pointer, until a
102 * NULL pointer is encountered. The three members ai_family, ai_socktype,
103 * and ai_protocol in each returned addrinfo structure contain the
104 * corresponding arguments for a call to socket(2). For each addrinfo
105 * structure in the list, the ai_addr member points to a filled-in socket
106 * address structure of length ai_addrlen.
108 * All of the information returned by getaddrinfo() is dynamically
109 * allocated: the addrinfo structures, and the socket address structures
110 * and canonical host name strings pointed to by the addrinfostructures.
111 * Memory allocated for the dynamically allocated structures created by a
112 * successful call to getaddrinfo() is released by freeaddrinfo().
113 * ai is a pointer to a struct addrinfo created by a call to getaddrinfo().
115 * \section irsreturn RETURN VALUES
117 * getaddrinfo() returns zero on success or one of the error codes
118 * listed in gai_strerror() if an error occurs. If both hostname and
119 * servname are NULL getaddrinfo() returns #EAI_NONAME.
121 * \section irssee SEE ALSO
123 * getaddrinfo(), freeaddrinfo(),
124 * gai_strerror(), RFC3493, getservbyname(3), connect(2),
125 * sendto(2), sendmsg(2), socket(2).
135 #include <isc/buffer.h>
138 #include <isc/sockaddr.h>
139 #include <isc/string.h>
140 #include <isc/util.h>
141 #include <isc/mutex.h>
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>
152 #include <irs/context.h>
153 #include <irs/netdb.h>
154 #include <irs/resconf.h>
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))
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);
169 static int get_local(const char *name, int socktype, struct addrinfo **res);
173 resolve_name(int family, const char *hostname, int flags,
174 struct addrinfo **aip, int socktype, int port);
176 static int add_ipv4(const char *hostname, int flags, struct addrinfo **aip,
177 int socktype, int port);
178 static int add_ipv6(const char *hostname, int flags, struct addrinfo **aip,
179 int socktype, int port);
180 static void set_order(int, int (**)(const char *, int, struct addrinfo **,
182 static void _freeaddrinfo(struct addrinfo *ai);
184 #define FOUND_IPV4 0x1
185 #define FOUND_IPV6 0x2
188 #define ISC_AI_MASK (AI_PASSIVE|AI_CANONNAME|AI_NUMERICHOST)
190 * Get a list of IP addresses and port numbers for host hostname and
194 getaddrinfo(const char *hostname, const char *servname,
195 const struct addrinfo *hints, struct addrinfo **res)
199 int family, socktype, flags, protocol;
200 struct addrinfo *ai, *ai_list;
203 int (*net_order[FOUND_MAX+1])(const char *, int, struct addrinfo **,
206 if (hostname == NULL && servname == NULL)
211 if ((hints->ai_flags & ~(ISC_AI_MASK)) != 0)
212 return (EAI_BADFLAGS);
213 if (hints->ai_addrlen || hints->ai_canonname ||
214 hints->ai_addr || hints->ai_next) {
218 family = hints->ai_family;
219 socktype = hints->ai_socktype;
220 protocol = hints->ai_protocol;
221 flags = hints->ai_flags;
224 switch (hints->ai_socktype) {
235 switch (hints->ai_socktype) {
247 return (EAI_SOCKTYPE);
252 switch (hints->ai_socktype) {
260 return (EAI_SOCKTYPE);
276 * First, deal with AF_LOCAL. If the family was not set,
277 * then assume AF_LOCAL if the first character of the
278 * hostname/servname is '/'.
281 if (hostname != NULL &&
282 (family == AF_LOCAL || (family == 0 && *hostname == '/')))
283 return (get_local(hostname, socktype, res));
285 if (servname != NULL &&
286 (family == AF_LOCAL || (family == 0 && *servname == '/')))
287 return (get_local(servname, socktype, res));
291 * Ok, only AF_INET and AF_INET6 left.
296 * First, look up the service name (port) if it was
297 * requested. If the socket type wasn't specified, then
298 * try and figure it out.
300 if (servname != NULL) {
303 port = strtol(servname, &e, 10);
306 return (EAI_SOCKTYPE);
307 if (port < 0 || port > 65535)
308 return (EAI_SERVICE);
309 port = htons((unsigned short) port);
311 sp = getservbyname(servname, proto);
313 return (EAI_SERVICE);
316 if (strcmp(sp->s_proto, "tcp") == 0)
317 socktype = SOCK_STREAM;
318 else if (strcmp(sp->s_proto, "udp") == 0)
319 socktype = SOCK_DGRAM;
326 * Next, deal with just a service name, and no hostname.
327 * (we verified that one of them was non-null up above).
329 if (hostname == NULL && (flags & AI_PASSIVE) != 0) {
330 if (family == AF_INET || family == 0) {
331 ai = ai_alloc(AF_INET, sizeof(struct sockaddr_in));
334 ai->ai_socktype = socktype;
335 ai->ai_protocol = protocol;
336 SIN(ai->ai_addr)->sin_port = port;
337 ai->ai_next = ai_list;
341 if (family == AF_INET6 || family == 0) {
342 ai = ai_alloc(AF_INET6, sizeof(struct sockaddr_in6));
344 _freeaddrinfo(ai_list);
347 ai->ai_socktype = socktype;
348 ai->ai_protocol = protocol;
349 SIN6(ai->ai_addr)->sin6_port = port;
350 ai->ai_next = ai_list;
359 * If the family isn't specified or AI_NUMERICHOST specified, check
360 * first to see if it is a numeric address.
361 * Though the gethostbyname2() routine will recognize numeric addresses,
362 * it will only recognize the format that it is being called for. Thus,
363 * a numeric AF_INET address will be treated by the AF_INET6 call as
364 * a domain name, and vice versa. Checking for both numerics here
367 if (hostname != NULL &&
368 (family == 0 || (flags & AI_NUMERICHOST) != 0)) {
369 char abuf[sizeof(struct in6_addr)];
370 char nbuf[NI_MAXHOST];
371 int addrsize, addroff;
372 #ifdef IRS_HAVE_SIN6_SCOPE_ID
374 char ntmp[NI_MAXHOST];
375 isc_uint32_t scopeid;
378 #ifdef IRS_HAVE_SIN6_SCOPE_ID
380 * Scope identifier portion.
383 if (strchr(hostname, '%') != NULL) {
384 strncpy(ntmp, hostname, sizeof(ntmp) - 1);
385 ntmp[sizeof(ntmp) - 1] = '\0';
386 p = strchr(ntmp, '%');
390 * Vendors may want to support non-numeric
391 * scopeid around here.
395 scopeid = (isc_uint32_t)strtoul(p + 1,
397 if (p != NULL && ep != NULL && ep[0] == '\0')
407 if (inet_pton(AF_INET, hostname, (struct in_addr *)abuf)
409 if (family == AF_INET6) {
411 * Convert to a V4 mapped address.
413 struct in6_addr *a6 = (struct in6_addr *)abuf;
414 memmove(&a6->s6_addr[12], &a6->s6_addr[0], 4);
415 memset(&a6->s6_addr[10], 0xff, 2);
416 memset(&a6->s6_addr[0], 0, 10);
419 addrsize = sizeof(struct in_addr);
420 addroff = (char *)(&SIN(0)->sin_addr) - (char *)0;
423 #ifdef IRS_HAVE_SIN6_SCOPE_ID
424 } else if (ntmp[0] != '\0' &&
425 inet_pton(AF_INET6, ntmp, abuf) == 1) {
426 if (family && family != AF_INET6)
428 addrsize = sizeof(struct in6_addr);
429 addroff = (char *)(&SIN6(0)->sin6_addr) - (char *)0;
433 } else if (inet_pton(AF_INET6, hostname, abuf) == 1) {
434 if (family != 0 && family != AF_INET6)
437 addrsize = sizeof(struct in6_addr);
438 addroff = (char *)(&SIN6(0)->sin6_addr) - (char *)0;
442 ai = ai_alloc(family,
443 ((family == AF_INET6) ?
444 sizeof(struct sockaddr_in6) :
445 sizeof(struct sockaddr_in)));
449 ai->ai_socktype = socktype;
450 SIN(ai->ai_addr)->sin_port = port;
451 memmove((char *)ai->ai_addr + addroff, abuf, addrsize);
452 if ((flags & AI_CANONNAME) != 0) {
453 #ifdef IRS_HAVE_SIN6_SCOPE_ID
454 if (ai->ai_family == AF_INET6)
455 SIN6(ai->ai_addr)->sin6_scope_id =
458 if (getnameinfo(ai->ai_addr, ai->ai_addrlen,
459 nbuf, sizeof(nbuf), NULL, 0,
460 NI_NUMERICHOST) == 0) {
461 ai->ai_canonname = strdup(nbuf);
462 if (ai->ai_canonname == NULL) {
467 /* XXX raise error? */
468 ai->ai_canonname = NULL;
472 } else if ((flags & AI_NUMERICHOST) != 0) {
477 if (hostname == NULL && (flags & AI_PASSIVE) == 0) {
478 set_order(family, net_order);
479 for (i = 0; i < FOUND_MAX; i++) {
480 if (net_order[i] == NULL)
482 err = (net_order[i])(hostname, flags, &ai_list,
485 if (ai_list != NULL) {
486 _freeaddrinfo(ai_list);
493 err = resolve_name(family, hostname, flags, &ai_list,
496 if (ai_list == NULL) {
503 ai_list = ai_reverse(ai_list);
509 typedef struct gai_restrans {
510 dns_clientrestrans_t *xid;
511 isc_boolean_t is_inprogress;
513 struct addrinfo ai_sentinel;
514 struct gai_resstate *resstate;
517 typedef struct gai_resstate {
519 struct gai_statehead *head;
520 dns_fixedname_t fixedname;
522 gai_restrans_t *trans4;
523 gai_restrans_t *trans6;
524 ISC_LINK(struct gai_resstate) link;
527 typedef struct gai_statehead {
533 dns_client_t *dnsclient;
534 isc_mutex_t list_lock;
535 ISC_LIST(struct gai_resstate) resstates;
536 unsigned int activestates;
540 make_resstate(isc_mem_t *mctx, gai_statehead_t *head, const char *hostname,
541 const char *domain, gai_resstate_t **statep)
544 gai_resstate_t *state;
545 dns_fixedname_t fixeddomain;
549 isc_boolean_t need_v4 = ISC_FALSE;
550 isc_boolean_t need_v6 = ISC_FALSE;
552 state = isc_mem_get(mctx, sizeof(*state));
554 return (ISC_R_NOMEMORY);
556 /* Construct base domain name */
557 namelen = strlen(domain);
558 isc_buffer_constinit(&b, domain, namelen);
559 isc_buffer_add(&b, namelen);
560 dns_fixedname_init(&fixeddomain);
561 qdomain = dns_fixedname_name(&fixeddomain);
562 result = dns_name_fromtext(qdomain, &b, dns_rootname, 0, NULL);
563 if (result != ISC_R_SUCCESS) {
564 isc_mem_put(mctx, state, sizeof(*state));
568 /* Construct query name */
569 namelen = strlen(hostname);
570 isc_buffer_constinit(&b, hostname, namelen);
571 isc_buffer_add(&b, namelen);
572 dns_fixedname_init(&state->fixedname);
573 state->qname = dns_fixedname_name(&state->fixedname);
574 result = dns_name_fromtext(state->qname, &b, qdomain, 0, NULL);
575 if (result != ISC_R_SUCCESS) {
576 isc_mem_put(mctx, state, sizeof(*state));
580 if (head->ai_family == AF_UNSPEC || head->ai_family == AF_INET)
582 if (head->ai_family == AF_UNSPEC || head->ai_family == AF_INET6)
585 state->trans6 = NULL;
586 state->trans4 = NULL;
588 state->trans4 = isc_mem_get(mctx, sizeof(gai_restrans_t));
589 if (state->trans4 == NULL) {
590 isc_mem_put(mctx, state, sizeof(*state));
591 return (ISC_R_NOMEMORY);
593 state->trans4->error = 0;
594 state->trans4->xid = NULL;
595 state->trans4->resstate = state;
596 state->trans4->is_inprogress = ISC_TRUE;
597 state->trans4->ai_sentinel.ai_next = NULL;
600 state->trans6 = isc_mem_get(mctx, sizeof(gai_restrans_t));
601 if (state->trans6 == NULL) {
602 if (state->trans4 != NULL)
603 isc_mem_put(mctx, state->trans4,
604 sizeof(*state->trans4));
605 isc_mem_put(mctx, state, sizeof(*state));
606 return (ISC_R_NOMEMORY);
608 state->trans6->error = 0;
609 state->trans6->xid = NULL;
610 state->trans6->resstate = state;
611 state->trans6->is_inprogress = ISC_TRUE;
612 state->trans6->ai_sentinel.ai_next = NULL;
617 ISC_LINK_INIT(state, link);
621 return (ISC_R_SUCCESS);
625 make_resstates(isc_mem_t *mctx, const char *hostname, gai_statehead_t *head,
626 irs_resconf_t *resconf)
629 irs_resconf_searchlist_t *searchlist;
630 irs_resconf_search_t *searchent;
631 gai_resstate_t *resstate, *resstate0;
634 result = make_resstate(mctx, head, hostname, ".", &resstate0);
635 if (result != ISC_R_SUCCESS)
638 searchlist = irs_resconf_getsearchlist(resconf);
639 for (searchent = ISC_LIST_HEAD(*searchlist); searchent != NULL;
640 searchent = ISC_LIST_NEXT(searchent, link)) {
642 result = make_resstate(mctx, head, hostname,
643 (const char *)searchent->domain,
645 if (result != ISC_R_SUCCESS)
648 ISC_LIST_APPEND(head->resstates, resstate, link);
649 head->activestates++;
653 * Insert the original hostname either at the head or the tail of the
654 * state list, depending on the number of labels contained in the
655 * original name and the 'ndots' configuration parameter.
657 if (dns_name_countlabels(resstate0->qname) >
658 irs_resconf_getndots(resconf) + 1) {
659 ISC_LIST_PREPEND(head->resstates, resstate0, link);
661 ISC_LIST_APPEND(head->resstates, resstate0, link);
662 head->activestates++;
664 if (result != ISC_R_SUCCESS) {
665 while ((resstate = ISC_LIST_HEAD(head->resstates)) != NULL) {
666 ISC_LIST_UNLINK(head->resstates, resstate, link);
667 if (resstate->trans4 != NULL) {
668 isc_mem_put(mctx, resstate->trans4,
669 sizeof(*resstate->trans4));
671 if (resstate->trans6 != NULL) {
672 isc_mem_put(mctx, resstate->trans6,
673 sizeof(*resstate->trans6));
676 isc_mem_put(mctx, resstate, sizeof(*resstate));
684 process_answer(isc_task_t *task, isc_event_t *event) {
685 int error = 0, family;
686 gai_restrans_t *trans = event->ev_arg;
687 gai_resstate_t *resstate;
688 dns_clientresevent_t *rev = (dns_clientresevent_t *)event;
689 dns_rdatatype_t qtype;
692 REQUIRE(trans != NULL);
693 resstate = trans->resstate;
694 REQUIRE(resstate != NULL);
695 REQUIRE(task != NULL);
697 if (trans == resstate->trans4) {
699 qtype = dns_rdatatype_a;
701 INSIST(trans == resstate->trans6);
703 qtype = dns_rdatatype_aaaa;
706 INSIST(trans->is_inprogress);
707 trans->is_inprogress = ISC_FALSE;
709 switch (rev->result) {
711 case DNS_R_NCACHENXDOMAIN: /* treat this as a fatal error? */
712 case DNS_R_NCACHENXRRSET:
715 switch (rev->vresult) {
716 case DNS_R_SIGINVALID:
717 case DNS_R_SIGEXPIRED:
718 case DNS_R_SIGFUTURE:
719 case DNS_R_KEYUNAUTHORIZED:
720 case DNS_R_MUSTBESECURE:
721 case DNS_R_COVERINGNSEC:
722 case DNS_R_NOTAUTHORITATIVE:
723 case DNS_R_NOVALIDKEY:
724 case DNS_R_NOVALIDDS:
725 case DNS_R_NOVALIDSIG:
726 error = EAI_INSECUREDATA;
734 /* Parse the response and construct the addrinfo chain */
735 for (name = ISC_LIST_HEAD(rev->answerlist); name != NULL;
736 name = ISC_LIST_NEXT(name, link)) {
738 dns_rdataset_t *rdataset;
743 for (rdataset = ISC_LIST_HEAD(name->list);
745 rdataset = ISC_LIST_NEXT(rdataset, link)) {
746 if (!dns_rdataset_isassociated(rdataset))
748 if (rdataset->type != qtype)
751 if ((resstate->head->ai_flags & AI_CANONNAME) != 0) {
752 isc_buffer_init(&b, t, sizeof(t));
753 result = dns_name_totext(name, ISC_TRUE, &b);
754 if (result != ISC_R_SUCCESS) {
758 isc_buffer_putuint8(&b, '\0');
759 isc_buffer_usedregion(&b, &r);
762 for (result = dns_rdataset_first(rdataset);
763 result == ISC_R_SUCCESS;
764 result = dns_rdataset_next(rdataset)) {
767 dns_rdata_in_a_t rdata_a;
768 dns_rdata_in_aaaa_t rdata_aaaa;
770 ai = ai_alloc(family,
771 ((family == AF_INET6) ?
772 sizeof(struct sockaddr_in6) :
773 sizeof(struct sockaddr_in)));
778 ai->ai_socktype = resstate->head->ai_socktype;
779 ai->ai_next = trans->ai_sentinel.ai_next;
780 trans->ai_sentinel.ai_next = ai;
783 * Set AF-specific parameters
784 * (IPv4/v6 address/port)
786 dns_rdata_init(&rdata);
789 dns_rdataset_current(rdataset, &rdata);
790 result = dns_rdata_tostruct(&rdata, &rdata_a,
792 RUNTIME_CHECK(result == ISC_R_SUCCESS);
793 SIN(ai->ai_addr)->sin_port =
794 resstate->head->ai_port;
795 memmove(&SIN(ai->ai_addr)->sin_addr,
796 &rdata_a.in_addr, 4);
797 dns_rdata_freestruct(&rdata_a);
800 dns_rdataset_current(rdataset, &rdata);
801 result = dns_rdata_tostruct(&rdata, &rdata_aaaa,
803 RUNTIME_CHECK(result == ISC_R_SUCCESS);
804 SIN6(ai->ai_addr)->sin6_port =
805 resstate->head->ai_port;
806 memmove(&SIN6(ai->ai_addr)->sin6_addr,
807 &rdata_aaaa.in6_addr, 16);
808 dns_rdata_freestruct(&rdata_aaaa);
812 if ((resstate->head->ai_flags & AI_CANONNAME)
815 strdup((const char *)r.base);
816 if (ai->ai_canonname == NULL) {
826 dns_client_freeresanswer(resstate->head->dnsclient, &rev->answerlist);
827 dns_client_destroyrestrans(&trans->xid);
829 isc_event_free(&event);
831 /* Make sure that error == 0 iff we have a non-empty list */
833 if (trans->ai_sentinel.ai_next == NULL)
836 if (trans->ai_sentinel.ai_next != NULL) {
837 _freeaddrinfo(trans->ai_sentinel.ai_next);
838 trans->ai_sentinel.ai_next = NULL;
841 trans->error = error;
843 /* Check whether we are done */
844 if ((resstate->trans4 == NULL || !resstate->trans4->is_inprogress) &&
845 (resstate->trans6 == NULL || !resstate->trans6->is_inprogress)) {
847 * We're done for this state. If there is no other outstanding
848 * state, we can exit.
850 resstate->head->activestates--;
851 if (resstate->head->activestates == 0) {
852 isc_app_ctxsuspend(resstate->head->actx);
857 * There are outstanding states, but if we are at the head
858 * of the state list (i.e., at the highest search priority)
859 * and have any answer, we can stop now by canceling the
862 LOCK(&resstate->head->list_lock);
863 if (resstate == ISC_LIST_HEAD(resstate->head->resstates)) {
864 if ((resstate->trans4 != NULL &&
865 resstate->trans4->ai_sentinel.ai_next != NULL) ||
866 (resstate->trans6 != NULL &&
867 resstate->trans6->ai_sentinel.ai_next != NULL)) {
868 gai_resstate_t *rest;
870 for (rest = ISC_LIST_NEXT(resstate, link);
872 rest = ISC_LIST_NEXT(rest, link)) {
873 if (rest->trans4 != NULL &&
874 rest->trans4->xid != NULL)
875 dns_client_cancelresolve(
877 if (rest->trans6 != NULL &&
878 rest->trans6->xid != NULL)
879 dns_client_cancelresolve(
884 * This search fails, so we move to the tail
885 * of the list so that the next entry will
886 * have the highest priority.
888 ISC_LIST_UNLINK(resstate->head->resstates,
890 ISC_LIST_APPEND(resstate->head->resstates,
894 UNLOCK(&resstate->head->list_lock);
899 resolve_name(int family, const char *hostname, int flags,
900 struct addrinfo **aip, int socktype, int port)
903 irs_context_t *irsctx;
910 dns_client_t *client;
911 gai_resstate_t *resstate;
912 gai_statehead_t head;
913 isc_boolean_t all_fail = ISC_TRUE;
915 /* get IRS context and the associated parameters */
917 result = irs_context_get(&irsctx);
918 if (result != ISC_R_SUCCESS)
920 actx = irs_context_getappctx(irsctx);
922 mctx = irs_context_getmctx(irsctx);
923 task = irs_context_gettask(irsctx);
924 conf = irs_context_getresconf(irsctx);
925 client = irs_context_getdnsclient(irsctx);
927 /* construct resolution states */
928 head.activestates = 0;
929 head.ai_family = family;
930 head.ai_socktype = socktype;
931 head.ai_flags = flags;
934 head.dnsclient = client;
935 result = isc_mutex_init(&head.list_lock);
936 if (result != ISC_R_SUCCESS) {
940 ISC_LIST_INIT(head.resstates);
941 result = make_resstates(mctx, hostname, &head, conf);
942 if (result != ISC_R_SUCCESS) {
943 DESTROYLOCK(&head.list_lock);
947 LOCK(&head.list_lock);
948 for (resstate = ISC_LIST_HEAD(head.resstates);
949 resstate != NULL; resstate = ISC_LIST_NEXT(resstate, link)) {
950 if (resstate->trans4 != NULL) {
951 result = dns_client_startresolve(client,
958 &resstate->trans4->xid);
959 if (result == ISC_R_SUCCESS) {
960 resstate->trans4->is_inprogress = ISC_TRUE;
961 all_fail = ISC_FALSE;
963 resstate->trans4->is_inprogress = ISC_FALSE;
965 if (resstate->trans6 != NULL) {
966 result = dns_client_startresolve(client,
973 &resstate->trans6->xid);
974 if (result == ISC_R_SUCCESS) {
975 resstate->trans6->is_inprogress = ISC_TRUE;
976 all_fail = ISC_FALSE;
978 resstate->trans6->is_inprogress= ISC_FALSE;
981 UNLOCK(&head.list_lock);
984 /* Start all the events */
985 isc_app_ctxrun(actx);
990 while ((resstate = ISC_LIST_HEAD(head.resstates)) != NULL) {
991 int terror4 = 0, terror6 = 0;
993 ISC_LIST_UNLINK(head.resstates, resstate, link);
996 struct addrinfo *sentinel4 = NULL;
997 struct addrinfo *sentinel6 = NULL;
999 if (resstate->trans4 != NULL) {
1001 resstate->trans4->ai_sentinel.ai_next;
1002 resstate->trans4->ai_sentinel.ai_next = NULL;
1004 if (resstate->trans6 != NULL) {
1006 resstate->trans6->ai_sentinel.ai_next;
1007 resstate->trans6->ai_sentinel.ai_next = NULL;
1009 *aip = ai_concat(sentinel4, sentinel6);
1012 if (resstate->trans4 != NULL) {
1013 INSIST(resstate->trans4->xid == NULL);
1014 terror4 = resstate->trans4->error;
1015 isc_mem_put(mctx, resstate->trans4,
1016 sizeof(*resstate->trans4));
1018 if (resstate->trans6 != NULL) {
1019 INSIST(resstate->trans6->xid == NULL);
1020 terror6 = resstate->trans6->error;
1021 isc_mem_put(mctx, resstate->trans6,
1022 sizeof(*resstate->trans6));
1026 * If the entire lookup fails, we need to choose an appropriate
1027 * error code from individual codes. We'll try to provide as
1028 * specific a code as possible. In general, we are going to
1029 * find an error code other than EAI_NONAME (which is too
1030 * generic and may actually not be problematic in some cases).
1031 * EAI_NONAME will be set below if no better code is found.
1033 if (terror == 0 || terror == EAI_NONAME) {
1034 if (terror4 != 0 && terror4 != EAI_NONAME)
1036 else if (terror6 != 0 && terror6 != EAI_NONAME)
1040 isc_mem_put(mctx, resstate, sizeof(*resstate));
1049 #if 1 /* XXX: enabled for finding leaks. should be cleaned up later. */
1050 isc_app_ctxfinish(actx);
1051 irs_context_destroy(&irsctx);
1054 DESTROYLOCK(&head.list_lock);
1059 irs_strsep(char **stringp, const char *delim) {
1060 char *string = *stringp;
1068 for (s = string; *s != '\0'; s++) {
1070 for (d = delim; (dc = *d) != '\0'; d++)
1082 set_order(int family, int (**net_order)(const char *, int, struct addrinfo **,
1091 *net_order++ = add_ipv4;
1094 *net_order++ = add_ipv6;
1098 order = getenv("NET_ORDER");
1100 while (order != NULL) {
1102 * We ignore any unknown names.
1104 tok = irs_strsep(&order, ":");
1105 if (strcasecmp(tok, "inet6") == 0) {
1106 if ((found & FOUND_IPV6) == 0)
1107 *net_order++ = add_ipv6;
1108 found |= FOUND_IPV6;
1109 } else if (strcasecmp(tok, "inet") == 0 ||
1110 strcasecmp(tok, "inet4") == 0) {
1111 if ((found & FOUND_IPV4) == 0)
1112 *net_order++ = add_ipv4;
1113 found |= FOUND_IPV4;
1118 * Add in anything that we didn't find.
1120 if ((found & FOUND_IPV4) == 0)
1121 *net_order++ = add_ipv4;
1122 if ((found & FOUND_IPV6) == 0)
1123 *net_order++ = add_ipv6;
1129 static char v4_loop[4] = { 127, 0, 0, 1 };
1132 add_ipv4(const char *hostname, int flags, struct addrinfo **aip,
1133 int socktype, int port)
1135 struct addrinfo *ai;
1140 ai = ai_clone(*aip, AF_INET); /* don't use ai_clone() */
1142 return (EAI_MEMORY);
1145 ai->ai_socktype = socktype;
1146 SIN(ai->ai_addr)->sin_port = port;
1147 memmove(&SIN(ai->ai_addr)->sin_addr, v4_loop, 4);
1152 static char v6_loop[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
1155 add_ipv6(const char *hostname, int flags, struct addrinfo **aip,
1156 int socktype, int port)
1158 struct addrinfo *ai;
1163 ai = ai_clone(*aip, AF_INET6); /* don't use ai_clone() */
1165 return (EAI_MEMORY);
1168 ai->ai_socktype = socktype;
1169 SIN6(ai->ai_addr)->sin6_port = port;
1170 memmove(&SIN6(ai->ai_addr)->sin6_addr, v6_loop, 16);
1175 /*% Free address info. */
1177 freeaddrinfo(struct addrinfo *ai) {
1182 _freeaddrinfo(struct addrinfo *ai) {
1183 struct addrinfo *ai_next;
1185 while (ai != NULL) {
1186 ai_next = ai->ai_next;
1187 if (ai->ai_addr != NULL)
1189 if (ai->ai_canonname)
1190 free(ai->ai_canonname);
1198 get_local(const char *name, int socktype, struct addrinfo **res) {
1199 struct addrinfo *ai;
1200 struct sockaddr_un *slocal;
1203 return (EAI_SOCKTYPE);
1205 ai = ai_alloc(AF_LOCAL, sizeof(*slocal));
1207 return (EAI_MEMORY);
1209 slocal = SLOCAL(ai->ai_addr);
1210 strlcpy(slocal->sun_path, name, sizeof(slocal->sun_path));
1212 ai->ai_socktype = socktype;
1214 * ai->ai_flags, ai->ai_protocol, ai->ai_canonname,
1215 * and ai->ai_next were initialized to zero.
1224 * Allocate an addrinfo structure, and a sockaddr structure
1225 * of the specificed length. We initialize:
1229 * ai_addr->sa_family
1230 * ai_addr->sa_len (IRS_PLATFORM_HAVESALEN)
1231 * and everything else is initialized to zero.
1233 static struct addrinfo *
1234 ai_alloc(int family, int addrlen) {
1235 struct addrinfo *ai;
1237 ai = (struct addrinfo *)calloc(1, sizeof(*ai));
1241 ai->ai_addr = SA(calloc(1, addrlen));
1242 if (ai->ai_addr == NULL) {
1246 ai->ai_addrlen = addrlen;
1247 ai->ai_family = family;
1248 ai->ai_addr->sa_family = family;
1249 #ifdef IRS_PLATFORM_HAVESALEN
1250 ai->ai_addr->sa_len = addrlen;
1255 static struct addrinfo *
1256 ai_clone(struct addrinfo *oai, int family) {
1257 struct addrinfo *ai;
1259 ai = ai_alloc(family, ((family == AF_INET6) ?
1260 sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)));
1267 ai->ai_flags = oai->ai_flags;
1268 ai->ai_socktype = oai->ai_socktype;
1269 ai->ai_protocol = oai->ai_protocol;
1270 ai->ai_canonname = NULL;
1275 static struct addrinfo *
1276 ai_reverse(struct addrinfo *oai) {
1277 struct addrinfo *nai, *tai;
1281 while (oai != NULL) {
1283 * Grab one off the old list.
1288 * Put it on the front of the new list.
1297 static struct addrinfo *
1298 ai_concat(struct addrinfo *ai1, struct addrinfo *ai2) {
1299 struct addrinfo *ai_tmp;
1303 else if (ai2 == NULL)
1306 for (ai_tmp = ai1; ai_tmp != NULL && ai_tmp->ai_next != NULL;
1307 ai_tmp = ai_tmp->ai_next)
1310 ai_tmp->ai_next = ai2;