4 * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC")
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
11 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
12 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
13 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
15 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16 * PERFORMANCE OF THIS SOFTWARE.
19 /* Id: getaddrinfo.c,v 1.3 2009/09/02 23:48:02 tbox Exp */
24 * getaddrinfo() is used to get a list of IP addresses and port
25 * numbers for host hostname and service servname as defined in RFC3493.
26 * hostname and servname are pointers to null-terminated strings
27 * or NULL. hostname is either a host name or a numeric host address
28 * string: a dotted decimal IPv4 address or an IPv6 address. servname is
29 * either a decimal port number or a service name as listed in
32 * If the operating system does not provide a struct addrinfo, the
33 * following structure is used:
37 * int ai_flags; // AI_PASSIVE, AI_CANONNAME
38 * int ai_family; // PF_xxx
39 * int ai_socktype; // SOCK_xxx
40 * int ai_protocol; // 0 or IPPROTO_xxx for IPv4 and IPv6
41 * size_t ai_addrlen; // length of ai_addr
42 * char *ai_canonname; // canonical name for hostname
43 * struct sockaddr *ai_addr; // binary address
44 * struct addrinfo *ai_next; // next structure in linked list
49 * hints is an optional pointer to a struct addrinfo. This structure can
50 * be used to provide hints concerning the type of socket that the caller
51 * supports or wishes to use. The caller can supply the following
52 * structure elements in *hints:
56 * The protocol family that should be used. When ai_family is set
57 * to PF_UNSPEC, it means the caller will accept any protocol
58 * family supported by the operating system.</li>
61 * denotes the type of socket -- SOCK_STREAM, SOCK_DGRAM or
62 * SOCK_RAW -- that is wanted. When ai_socktype is zero the caller
63 * will accept any socket type.</li>
66 * indicates which transport protocol is wanted: IPPROTO_UDP or
67 * IPPROTO_TCP. If ai_protocol is zero the caller will accept any
71 * Flag bits. If the AI_CANONNAME bit is set, a successful call to
72 * getaddrinfo() will return a null-terminated string
73 * containing the canonical name of the specified hostname in
74 * ai_canonname of the first addrinfo structure returned. Setting
75 * the AI_PASSIVE bit indicates that the returned socket address
76 * structure is intended for used in a call to bind(2). In this
77 * case, if the hostname argument is a NULL pointer, then the IP
78 * address portion of the socket address structure will be set to
79 * INADDR_ANY for an IPv4 address or IN6ADDR_ANY_INIT for an IPv6
80 * address.<br /><br />
82 * When ai_flags does not set the AI_PASSIVE bit, the returned
83 * socket address structure will be ready for use in a call to
84 * connect(2) for a connection-oriented protocol or connect(2),
85 * sendto(2), or sendmsg(2) if a connectionless protocol was
86 * chosen. The IP address portion of the socket address structure
87 * will be set to the loopback address if hostname is a NULL
88 * pointer and AI_PASSIVE is not set in ai_flags.<br /><br />
90 * If ai_flags is set to AI_NUMERICHOST it indicates that hostname
91 * should be treated as a numeric string defining an IPv4 or IPv6
92 * address and no name resolution should be attempted.
95 * All other elements of the struct addrinfo passed via hints must be
98 * A hints of NULL is treated as if the caller provided a struct addrinfo
99 * initialized to zero with ai_familyset to PF_UNSPEC.
101 * After a successful call to getaddrinfo(), *res is a pointer to a
102 * linked list of one or more addrinfo structures. Each struct addrinfo
103 * in this list cn be processed by following the ai_next pointer, until a
104 * NULL pointer is encountered. The three members ai_family, ai_socktype,
105 * and ai_protocol in each returned addrinfo structure contain the
106 * corresponding arguments for a call to socket(2). For each addrinfo
107 * structure in the list, the ai_addr member points to a filled-in socket
108 * address structure of length ai_addrlen.
110 * All of the information returned by getaddrinfo() is dynamically
111 * allocated: the addrinfo structures, and the socket address structures
112 * and canonical host name strings pointed to by the addrinfostructures.
113 * Memory allocated for the dynamically allocated structures created by a
114 * successful call to getaddrinfo() is released by freeaddrinfo().
115 * ai is a pointer to a struct addrinfo created by a call to getaddrinfo().
117 * \section irsreturn RETURN VALUES
119 * getaddrinfo() returns zero on success or one of the error codes
120 * listed in gai_strerror() if an error occurs. If both hostname and
121 * servname are NULL getaddrinfo() returns #EAI_NONAME.
123 * \section irssee SEE ALSO
125 * getaddrinfo(), freeaddrinfo(),
126 * gai_strerror(), RFC3493, getservbyname(3), connect(2),
127 * sendto(2), sendmsg(2), socket(2).
137 #include <isc/buffer.h>
140 #include <isc/sockaddr.h>
141 #include <isc/util.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
**,
183 #define FOUND_IPV4 0x1
184 #define FOUND_IPV6 0x2
187 #define ISC_AI_MASK (AI_PASSIVE|AI_CANONNAME|AI_NUMERICHOST)
189 * Get a list of IP addresses and port numbers for host hostname and
193 getaddrinfo(const char *hostname
, const char *servname
,
194 const struct addrinfo
*hints
, struct addrinfo
**res
)
198 int family
, socktype
, flags
, protocol
;
199 struct addrinfo
*ai
, *ai_list
;
202 int (*net_order
[FOUND_MAX
+1])(const char *, int, struct addrinfo
**,
205 if (hostname
== NULL
&& servname
== NULL
)
210 if ((hints
->ai_flags
& ~(ISC_AI_MASK
)) != 0)
211 return (EAI_BADFLAGS
);
212 if (hints
->ai_addrlen
|| hints
->ai_canonname
||
213 hints
->ai_addr
|| hints
->ai_next
) {
217 family
= hints
->ai_family
;
218 socktype
= hints
->ai_socktype
;
219 protocol
= hints
->ai_protocol
;
220 flags
= hints
->ai_flags
;
223 switch (hints
->ai_socktype
) {
234 switch (hints
->ai_socktype
) {
246 return (EAI_SOCKTYPE
);
251 switch (hints
->ai_socktype
) {
259 return (EAI_SOCKTYPE
);
275 * First, deal with AF_LOCAL. If the family was not set,
276 * then assume AF_LOCAL if the first character of the
277 * hostname/servname is '/'.
280 if (hostname
!= NULL
&&
281 (family
== AF_LOCAL
|| (family
== 0 && *hostname
== '/')))
282 return (get_local(hostname
, socktype
, res
));
284 if (servname
!= NULL
&&
285 (family
== AF_LOCAL
|| (family
== 0 && *servname
== '/')))
286 return (get_local(servname
, socktype
, res
));
290 * Ok, only AF_INET and AF_INET6 left.
295 * First, look up the service name (port) if it was
296 * requested. If the socket type wasn't specified, then
297 * try and figure it out.
299 if (servname
!= NULL
) {
302 port
= strtol(servname
, &e
, 10);
305 return (EAI_SOCKTYPE
);
306 if (port
< 0 || port
> 65535)
307 return (EAI_SERVICE
);
308 port
= htons((unsigned short) port
);
310 sp
= getservbyname(servname
, proto
);
312 return (EAI_SERVICE
);
315 if (strcmp(sp
->s_proto
, "tcp") == 0)
316 socktype
= SOCK_STREAM
;
317 else if (strcmp(sp
->s_proto
, "udp") == 0)
318 socktype
= SOCK_DGRAM
;
325 * Next, deal with just a service name, and no hostname.
326 * (we verified that one of them was non-null up above).
328 if (hostname
== NULL
&& (flags
& AI_PASSIVE
) != 0) {
329 if (family
== AF_INET
|| family
== 0) {
330 ai
= ai_alloc(AF_INET
, sizeof(struct sockaddr_in
));
333 ai
->ai_socktype
= socktype
;
334 ai
->ai_protocol
= protocol
;
335 SIN(ai
->ai_addr
)->sin_port
= port
;
336 ai
->ai_next
= ai_list
;
340 if (family
== AF_INET6
|| family
== 0) {
341 ai
= ai_alloc(AF_INET6
, sizeof(struct sockaddr_in6
));
343 freeaddrinfo(ai_list
);
346 ai
->ai_socktype
= socktype
;
347 ai
->ai_protocol
= protocol
;
348 SIN6(ai
->ai_addr
)->sin6_port
= port
;
349 ai
->ai_next
= ai_list
;
358 * If the family isn't specified or AI_NUMERICHOST specified, check
359 * first to see if it is a numeric address.
360 * Though the gethostbyname2() routine will recognize numeric addresses,
361 * it will only recognize the format that it is being called for. Thus,
362 * a numeric AF_INET address will be treated by the AF_INET6 call as
363 * a domain name, and vice versa. Checking for both numerics here
366 if (hostname
!= NULL
&&
367 (family
== 0 || (flags
& AI_NUMERICHOST
) != 0)) {
368 char abuf
[sizeof(struct in6_addr
)];
369 char nbuf
[NI_MAXHOST
];
370 int addrsize
, addroff
;
371 #ifdef IRS_HAVE_SIN6_SCOPE_ID
373 char ntmp
[NI_MAXHOST
];
374 isc_uint32_t scopeid
;
377 #ifdef IRS_HAVE_SIN6_SCOPE_ID
379 * Scope identifier portion.
382 if (strchr(hostname
, '%') != NULL
) {
383 strncpy(ntmp
, hostname
, sizeof(ntmp
) - 1);
384 ntmp
[sizeof(ntmp
) - 1] = '\0';
385 p
= strchr(ntmp
, '%');
389 * Vendors may want to support non-numeric
390 * scopeid around here.
394 scopeid
= (isc_uint32_t
)strtoul(p
+ 1,
396 if (p
!= NULL
&& ep
!= NULL
&& ep
[0] == '\0')
406 if (inet_pton(AF_INET
, hostname
, (struct in_addr
*)abuf
)
408 if (family
== AF_INET6
) {
410 * Convert to a V4 mapped address.
412 struct in6_addr
*a6
= (struct in6_addr
*)abuf
;
413 memcpy(&a6
->s6_addr
[12], &a6
->s6_addr
[0], 4);
414 memset(&a6
->s6_addr
[10], 0xff, 2);
415 memset(&a6
->s6_addr
[0], 0, 10);
418 addrsize
= sizeof(struct in_addr
);
419 addroff
= (char *)(&SIN(0)->sin_addr
) - (char *)0;
422 #ifdef IRS_HAVE_SIN6_SCOPE_ID
423 } else if (ntmp
[0] != '\0' &&
424 inet_pton(AF_INET6
, ntmp
, abuf
) == 1) {
425 if (family
&& family
!= AF_INET6
)
427 addrsize
= sizeof(struct in6_addr
);
428 addroff
= (char *)(&SIN6(0)->sin6_addr
) - (char *)0;
432 } else if (inet_pton(AF_INET6
, hostname
, abuf
) == 1) {
433 if (family
!= 0 && family
!= AF_INET6
)
436 addrsize
= sizeof(struct in6_addr
);
437 addroff
= (char *)(&SIN6(0)->sin6_addr
) - (char *)0;
441 ai
= ai_alloc(family
,
442 ((family
== AF_INET6
) ?
443 sizeof(struct sockaddr_in6
) :
444 sizeof(struct sockaddr_in
)));
448 ai
->ai_socktype
= socktype
;
449 SIN(ai
->ai_addr
)->sin_port
= port
;
450 memcpy((char *)ai
->ai_addr
+ addroff
, abuf
, addrsize
);
451 if ((flags
& AI_CANONNAME
) != 0) {
452 #ifdef IRS_HAVE_SIN6_SCOPE_ID
453 if (ai
->ai_family
== AF_INET6
)
454 SIN6(ai
->ai_addr
)->sin6_scope_id
=
457 if (getnameinfo(ai
->ai_addr
, ai
->ai_addrlen
,
458 nbuf
, sizeof(nbuf
), NULL
, 0,
459 NI_NUMERICHOST
) == 0) {
460 ai
->ai_canonname
= strdup(nbuf
);
461 if (ai
->ai_canonname
== NULL
) {
466 /* XXX raise error? */
467 ai
->ai_canonname
= NULL
;
471 } else if ((flags
& AI_NUMERICHOST
) != 0) {
476 if (hostname
== NULL
&& (flags
& AI_PASSIVE
) == 0) {
477 set_order(family
, net_order
);
478 for (i
= 0; i
< FOUND_MAX
; i
++) {
479 if (net_order
[i
] == NULL
)
481 err
= (net_order
[i
])(hostname
, flags
, &ai_list
,
485 freeaddrinfo(ai_list
);
490 err
= resolve_name(family
, hostname
, flags
, &ai_list
,
493 if (ai_list
== NULL
) {
500 ai_list
= ai_reverse(ai_list
);
506 typedef struct gai_restrans
{
507 dns_clientrestrans_t
*xid
;
508 isc_boolean_t is_inprogress
;
510 struct addrinfo ai_sentinel
;
511 struct gai_resstate
*resstate
;
514 typedef struct gai_resstate
{
516 struct gai_statehead
*head
;
517 dns_fixedname_t fixedname
;
519 gai_restrans_t
*trans4
;
520 gai_restrans_t
*trans6
;
521 ISC_LINK(struct gai_resstate
) link
;
524 typedef struct gai_statehead
{
530 dns_client_t
*dnsclient
;
531 ISC_LIST(struct gai_resstate
) resstates
;
532 unsigned int activestates
;
536 make_resstate(isc_mem_t
*mctx
, gai_statehead_t
*head
, const char *hostname
,
537 const char *domain
, gai_resstate_t
**statep
)
540 gai_resstate_t
*state
;
541 dns_fixedname_t fixeddomain
;
545 isc_boolean_t need_v4
= ISC_FALSE
;
546 isc_boolean_t need_v6
= ISC_FALSE
;
548 state
= isc_mem_get(mctx
, sizeof(*state
));
550 return (ISC_R_NOMEMORY
);
552 /* Construct base domain name */
553 namelen
= strlen(domain
);
554 isc_buffer_init(&b
, domain
, namelen
);
555 isc_buffer_add(&b
, namelen
);
556 dns_fixedname_init(&fixeddomain
);
557 qdomain
= dns_fixedname_name(&fixeddomain
);
558 result
= dns_name_fromtext(qdomain
, &b
, dns_rootname
, 0, NULL
);
559 if (result
!= ISC_R_SUCCESS
) {
560 isc_mem_put(mctx
, state
, sizeof(*state
));
564 /* Construct query name */
565 namelen
= strlen(hostname
);
566 isc_buffer_init(&b
, hostname
, namelen
);
567 isc_buffer_add(&b
, namelen
);
568 dns_fixedname_init(&state
->fixedname
);
569 state
->qname
= dns_fixedname_name(&state
->fixedname
);
570 result
= dns_name_fromtext(state
->qname
, &b
, qdomain
, 0, NULL
);
571 if (result
!= ISC_R_SUCCESS
) {
572 isc_mem_put(mctx
, state
, sizeof(*state
));
576 if (head
->ai_family
== AF_UNSPEC
|| head
->ai_family
== AF_INET
)
578 if (head
->ai_family
== AF_UNSPEC
|| head
->ai_family
== AF_INET6
)
581 state
->trans6
= NULL
;
582 state
->trans4
= NULL
;
584 state
->trans4
= isc_mem_get(mctx
, sizeof(gai_restrans_t
));
585 if (state
->trans4
== NULL
) {
586 isc_mem_put(mctx
, state
, sizeof(*state
));
587 return (ISC_R_NOMEMORY
);
589 state
->trans4
->error
= 0;
590 state
->trans4
->xid
= NULL
;
591 state
->trans4
->resstate
= state
;
592 state
->trans4
->is_inprogress
= ISC_TRUE
;
593 state
->trans4
->ai_sentinel
.ai_next
= NULL
;
596 state
->trans6
= isc_mem_get(mctx
, sizeof(gai_restrans_t
));
597 if (state
->trans6
== NULL
) {
598 if (state
->trans4
!= NULL
)
599 isc_mem_put(mctx
, state
->trans4
,
600 sizeof(*state
->trans4
));
601 isc_mem_put(mctx
, state
, sizeof(*state
));
602 return (ISC_R_NOMEMORY
);
604 state
->trans6
->error
= 0;
605 state
->trans6
->xid
= NULL
;
606 state
->trans6
->resstate
= state
;
607 state
->trans6
->is_inprogress
= ISC_TRUE
;
608 state
->trans6
->ai_sentinel
.ai_next
= NULL
;
613 ISC_LINK_INIT(state
, link
);
617 return (ISC_R_SUCCESS
);
621 make_resstates(isc_mem_t
*mctx
, const char *hostname
, gai_statehead_t
*head
,
622 irs_resconf_t
*resconf
)
625 irs_resconf_searchlist_t
*searchlist
;
626 irs_resconf_search_t
*searchent
;
627 gai_resstate_t
*resstate
, *resstate0
;
630 result
= make_resstate(mctx
, head
, hostname
, ".", &resstate0
);
631 if (result
!= ISC_R_SUCCESS
)
634 searchlist
= irs_resconf_getsearchlist(resconf
);
635 for (searchent
= ISC_LIST_HEAD(*searchlist
); searchent
!= NULL
;
636 searchent
= ISC_LIST_NEXT(searchent
, link
)) {
638 result
= make_resstate(mctx
, head
, hostname
,
639 (const char *)searchent
->domain
,
641 if (result
!= ISC_R_SUCCESS
)
644 ISC_LIST_APPEND(head
->resstates
, resstate
, link
);
645 head
->activestates
++;
649 * Insert the original hostname either at the head or the tail of the
650 * state list, depending on the number of labels contained in the
651 * original name and the 'ndots' configuration parameter.
653 if (dns_name_countlabels(resstate0
->qname
) >
654 irs_resconf_getndots(resconf
) + 1) {
655 ISC_LIST_PREPEND(head
->resstates
, resstate0
, link
);
657 ISC_LIST_APPEND(head
->resstates
, resstate0
, link
);
658 head
->activestates
++;
660 if (result
!= ISC_R_SUCCESS
) {
661 while ((resstate
= ISC_LIST_HEAD(head
->resstates
)) != NULL
) {
662 ISC_LIST_UNLINK(head
->resstates
, resstate
, link
);
663 if (resstate
->trans4
!= NULL
) {
664 isc_mem_put(mctx
, resstate
->trans4
,
665 sizeof(*resstate
->trans4
));
667 if (resstate
->trans6
!= NULL
) {
668 isc_mem_put(mctx
, resstate
->trans6
,
669 sizeof(*resstate
->trans6
));
672 isc_mem_put(mctx
, resstate
, sizeof(*resstate
));
680 process_answer(isc_task_t
*task
, isc_event_t
*event
) {
681 int error
= 0, family
;
682 gai_restrans_t
*trans
= event
->ev_arg
;
683 gai_resstate_t
*resstate
;
684 dns_clientresevent_t
*rev
= (dns_clientresevent_t
*)event
;
685 dns_rdatatype_t qtype
;
688 REQUIRE(trans
!= NULL
);
689 resstate
= trans
->resstate
;
690 REQUIRE(resstate
!= NULL
);
691 REQUIRE(task
!= NULL
);
693 if (trans
== resstate
->trans4
) {
695 qtype
= dns_rdatatype_a
;
697 INSIST(trans
== resstate
->trans6
);
699 qtype
= dns_rdatatype_aaaa
;
702 INSIST(trans
->is_inprogress
);
703 trans
->is_inprogress
= ISC_FALSE
;
705 switch (rev
->result
) {
707 case DNS_R_NCACHENXDOMAIN
: /* treat this as a fatal error? */
708 case DNS_R_NCACHENXRRSET
:
711 switch (rev
->vresult
) {
712 case DNS_R_SIGINVALID
:
713 case DNS_R_SIGEXPIRED
:
714 case DNS_R_SIGFUTURE
:
715 case DNS_R_KEYUNAUTHORIZED
:
716 case DNS_R_MUSTBESECURE
:
717 case DNS_R_COVERINGNSEC
:
718 case DNS_R_NOTAUTHORITATIVE
:
719 case DNS_R_NOVALIDKEY
:
720 case DNS_R_NOVALIDDS
:
721 case DNS_R_NOVALIDSIG
:
722 error
= EAI_INSECUREDATA
;
730 /* Parse the response and construct the addrinfo chain */
731 for (name
= ISC_LIST_HEAD(rev
->answerlist
); name
!= NULL
;
732 name
= ISC_LIST_NEXT(name
, link
)) {
734 dns_rdataset_t
*rdataset
;
739 for (rdataset
= ISC_LIST_HEAD(name
->list
);
741 rdataset
= ISC_LIST_NEXT(rdataset
, link
)) {
742 if (!dns_rdataset_isassociated(rdataset
))
744 if (rdataset
->type
!= qtype
)
747 if ((resstate
->head
->ai_flags
& AI_CANONNAME
) != 0) {
748 isc_buffer_init(&b
, t
, sizeof(t
));
749 result
= dns_name_totext(name
, ISC_TRUE
, &b
);
750 if (result
!= ISC_R_SUCCESS
) {
754 isc_buffer_putuint8(&b
, '\0');
755 isc_buffer_usedregion(&b
, &r
);
758 for (result
= dns_rdataset_first(rdataset
);
759 result
== ISC_R_SUCCESS
;
760 result
= dns_rdataset_next(rdataset
)) {
763 dns_rdata_in_a_t rdata_a
;
764 dns_rdata_in_aaaa_t rdata_aaaa
;
766 ai
= ai_alloc(family
,
767 ((family
== AF_INET6
) ?
768 sizeof(struct sockaddr_in6
) :
769 sizeof(struct sockaddr_in
)));
774 ai
->ai_socktype
= resstate
->head
->ai_socktype
;
775 ai
->ai_next
= trans
->ai_sentinel
.ai_next
;
776 trans
->ai_sentinel
.ai_next
= ai
;
779 * Set AF-specific parameters
780 * (IPv4/v6 address/port)
782 dns_rdata_init(&rdata
);
785 dns_rdataset_current(rdataset
, &rdata
);
786 dns_rdata_tostruct(&rdata
, &rdata_a
,
789 SIN(ai
->ai_addr
)->sin_port
=
790 resstate
->head
->ai_port
;
791 memcpy(&SIN(ai
->ai_addr
)->sin_addr
,
792 &rdata_a
.in_addr
, 4);
793 dns_rdata_freestruct(&rdata_a
);
796 dns_rdataset_current(rdataset
, &rdata
);
797 dns_rdata_tostruct(&rdata
, &rdata_aaaa
,
799 SIN6(ai
->ai_addr
)->sin6_port
=
800 resstate
->head
->ai_port
;
801 memcpy(&SIN6(ai
->ai_addr
)->sin6_addr
,
802 &rdata_aaaa
.in6_addr
, 16);
803 dns_rdata_freestruct(&rdata_aaaa
);
807 if ((resstate
->head
->ai_flags
& AI_CANONNAME
)
810 strdup((const char *)r
.base
);
811 if (ai
->ai_canonname
== NULL
) {
821 dns_client_freeresanswer(resstate
->head
->dnsclient
, &rev
->answerlist
);
822 dns_client_destroyrestrans(&trans
->xid
);
824 isc_event_free(&event
);
826 /* Make sure that error == 0 iff we have a non-empty list */
828 if (trans
->ai_sentinel
.ai_next
== NULL
)
831 if (trans
->ai_sentinel
.ai_next
!= NULL
) {
832 freeaddrinfo(trans
->ai_sentinel
.ai_next
);
833 trans
->ai_sentinel
.ai_next
= NULL
;
836 trans
->error
= error
;
838 /* Check whether we are done */
839 if ((resstate
->trans4
== NULL
|| !resstate
->trans4
->is_inprogress
) &&
840 (resstate
->trans6
== NULL
|| !resstate
->trans6
->is_inprogress
)) {
842 * We're done for this state. If there is no other outstanding
843 * state, we can exit.
845 resstate
->head
->activestates
--;
846 if (resstate
->head
->activestates
== 0) {
847 isc_app_ctxsuspend(resstate
->head
->actx
);
852 * There are outstanding states, but if we are at the head
853 * of the state list (i.e., at the highest search priority)
854 * and have any answer, we can stop now by canceling the
857 if (resstate
== ISC_LIST_HEAD(resstate
->head
->resstates
)) {
858 if ((resstate
->trans4
!= NULL
&&
859 resstate
->trans4
->ai_sentinel
.ai_next
!= NULL
) ||
860 (resstate
->trans6
!= NULL
&&
861 resstate
->trans6
->ai_sentinel
.ai_next
!= NULL
)) {
862 gai_resstate_t
*rest
;
864 for (rest
= ISC_LIST_NEXT(resstate
, link
);
866 rest
= ISC_LIST_NEXT(rest
, link
)) {
867 if (rest
->trans4
!= NULL
&&
868 rest
->trans4
->xid
!= NULL
)
869 dns_client_cancelresolve(
871 if (rest
->trans6
!= NULL
&&
872 rest
->trans6
->xid
!= NULL
)
873 dns_client_cancelresolve(
878 * This search fails, so we move to the tail
879 * of the list so that the next entry will
880 * have the highest priority.
882 ISC_LIST_UNLINK(resstate
->head
->resstates
,
884 ISC_LIST_APPEND(resstate
->head
->resstates
,
892 resolve_name(int family
, const char *hostname
, int flags
,
893 struct addrinfo
**aip
, int socktype
, int port
)
896 irs_context_t
*irsctx
;
903 dns_client_t
*client
;
904 gai_resstate_t
*resstate
;
905 gai_statehead_t head
;
906 isc_boolean_t all_fail
= ISC_TRUE
;
908 /* get IRS context and the associated parameters */
910 result
= irs_context_get(&irsctx
);
911 if (result
!= ISC_R_SUCCESS
)
913 actx
= irs_context_getappctx(irsctx
);
915 mctx
= irs_context_getmctx(irsctx
);
916 task
= irs_context_gettask(irsctx
);
917 conf
= irs_context_getresconf(irsctx
);
918 client
= irs_context_getdnsclient(irsctx
);
920 /* construct resolution states */
921 head
.activestates
= 0;
922 head
.ai_family
= family
;
923 head
.ai_socktype
= socktype
;
924 head
.ai_flags
= flags
;
927 head
.dnsclient
= client
;
928 ISC_LIST_INIT(head
.resstates
);
929 result
= make_resstates(mctx
, hostname
, &head
, conf
);
930 if (result
!= ISC_R_SUCCESS
)
933 for (resstate
= ISC_LIST_HEAD(head
.resstates
);
934 resstate
!= NULL
; resstate
= ISC_LIST_NEXT(resstate
, link
)) {
935 if (resstate
->trans4
!= NULL
) {
936 result
= dns_client_startresolve(client
,
943 &resstate
->trans4
->xid
);
944 if (result
== ISC_R_SUCCESS
) {
945 resstate
->trans4
->is_inprogress
= ISC_TRUE
;
946 all_fail
= ISC_FALSE
;
948 resstate
->trans4
->is_inprogress
= ISC_FALSE
;
950 if (resstate
->trans6
!= NULL
) {
951 result
= dns_client_startresolve(client
,
958 &resstate
->trans6
->xid
);
959 if (result
== ISC_R_SUCCESS
) {
960 resstate
->trans6
->is_inprogress
= ISC_TRUE
;
961 all_fail
= ISC_FALSE
;
963 resstate
->trans6
->is_inprogress
= ISC_FALSE
;
967 /* Start all the events */
968 isc_app_ctxrun(actx
);
973 while ((resstate
= ISC_LIST_HEAD(head
.resstates
)) != NULL
) {
974 int terror4
= 0, terror6
= 0;
976 ISC_LIST_UNLINK(head
.resstates
, resstate
, link
);
979 struct addrinfo
*sentinel4
= NULL
;
980 struct addrinfo
*sentinel6
= NULL
;
982 if (resstate
->trans4
!= NULL
) {
984 resstate
->trans4
->ai_sentinel
.ai_next
;
985 resstate
->trans4
->ai_sentinel
.ai_next
= NULL
;
987 if (resstate
->trans6
!= NULL
) {
989 resstate
->trans6
->ai_sentinel
.ai_next
;
990 resstate
->trans6
->ai_sentinel
.ai_next
= NULL
;
992 *aip
= ai_concat(sentinel4
, sentinel6
);
995 if (resstate
->trans4
!= NULL
) {
996 INSIST(resstate
->trans4
->xid
== NULL
);
997 terror4
= resstate
->trans4
->error
;
998 isc_mem_put(mctx
, resstate
->trans4
,
999 sizeof(*resstate
->trans4
));
1001 if (resstate
->trans6
!= NULL
) {
1002 INSIST(resstate
->trans6
->xid
== NULL
);
1003 terror6
= resstate
->trans6
->error
;
1004 isc_mem_put(mctx
, resstate
->trans6
,
1005 sizeof(*resstate
->trans6
));
1009 * If the entire lookup fails, we need to choose an appropriate
1010 * error code from individual codes. We'll try to provide as
1011 * specific a code as possible. In general, we are going to
1012 * find an error code other than EAI_NONAME (which is too
1013 * generic and may actually not be problematic in some cases).
1014 * EAI_NONAME will be set below if no better code is found.
1016 if (terror
== 0 || terror
== EAI_NONAME
) {
1017 if (terror4
!= 0 && terror4
!= EAI_NONAME
)
1019 else if (terror6
!= 0 && terror6
!= EAI_NONAME
)
1023 isc_mem_put(mctx
, resstate
, sizeof(*resstate
));
1032 #if 1 /* XXX: enabled for finding leaks. should be cleaned up later. */
1033 isc_app_ctxfinish(actx
);
1034 irs_context_destroy(&irsctx
);
1041 irs_strsep(char **stringp
, const char *delim
) {
1042 char *string
= *stringp
;
1050 for (s
= string
; *s
!= '\0'; s
++) {
1052 for (d
= delim
; (dc
= *d
) != '\0'; d
++)
1064 set_order(int family
, int (**net_order
)(const char *, int, struct addrinfo
**,
1073 *net_order
++ = add_ipv4
;
1076 *net_order
++ = add_ipv6
;
1080 order
= getenv("NET_ORDER");
1082 while (order
!= NULL
) {
1084 * We ignore any unknown names.
1086 tok
= irs_strsep(&order
, ":");
1087 if (strcasecmp(tok
, "inet6") == 0) {
1088 if ((found
& FOUND_IPV6
) == 0)
1089 *net_order
++ = add_ipv6
;
1090 found
|= FOUND_IPV6
;
1091 } else if (strcasecmp(tok
, "inet") == 0 ||
1092 strcasecmp(tok
, "inet4") == 0) {
1093 if ((found
& FOUND_IPV4
) == 0)
1094 *net_order
++ = add_ipv4
;
1095 found
|= FOUND_IPV4
;
1100 * Add in anything that we didn't find.
1102 if ((found
& FOUND_IPV4
) == 0)
1103 *net_order
++ = add_ipv4
;
1104 if ((found
& FOUND_IPV6
) == 0)
1105 *net_order
++ = add_ipv6
;
1111 static char v4_loop
[4] = { 127, 0, 0, 1 };
1114 add_ipv4(const char *hostname
, int flags
, struct addrinfo
**aip
,
1115 int socktype
, int port
)
1117 struct addrinfo
*ai
;
1122 ai
= ai_clone(*aip
, AF_INET
); /* don't use ai_clone() */
1125 return (EAI_MEMORY
);
1129 ai
->ai_socktype
= socktype
;
1130 SIN(ai
->ai_addr
)->sin_port
= port
;
1131 memcpy(&SIN(ai
->ai_addr
)->sin_addr
, v4_loop
, 4);
1136 static char v6_loop
[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
1139 add_ipv6(const char *hostname
, int flags
, struct addrinfo
**aip
,
1140 int socktype
, int port
)
1142 struct addrinfo
*ai
;
1147 ai
= ai_clone(*aip
, AF_INET6
); /* don't use ai_clone() */
1150 return (EAI_MEMORY
);
1154 ai
->ai_socktype
= socktype
;
1155 SIN6(ai
->ai_addr
)->sin6_port
= port
;
1156 memcpy(&SIN6(ai
->ai_addr
)->sin6_addr
, v6_loop
, 16);
1161 /*% Free address info. */
1163 freeaddrinfo(struct addrinfo
*ai
) {
1164 struct addrinfo
*ai_next
;
1166 while (ai
!= NULL
) {
1167 ai_next
= ai
->ai_next
;
1168 if (ai
->ai_addr
!= NULL
)
1170 if (ai
->ai_canonname
)
1171 free(ai
->ai_canonname
);
1179 get_local(const char *name
, int socktype
, struct addrinfo
**res
) {
1180 struct addrinfo
*ai
;
1181 struct sockaddr_un
*slocal
;
1184 return (EAI_SOCKTYPE
);
1186 ai
= ai_alloc(AF_LOCAL
, sizeof(*slocal
));
1188 return (EAI_MEMORY
);
1190 slocal
= SLOCAL(ai
->ai_addr
);
1191 strncpy(slocal
->sun_path
, name
, sizeof(slocal
->sun_path
));
1193 ai
->ai_socktype
= socktype
;
1195 * ai->ai_flags, ai->ai_protocol, ai->ai_canonname,
1196 * and ai->ai_next were initialized to zero.
1205 * Allocate an addrinfo structure, and a sockaddr structure
1206 * of the specificed length. We initialize:
1210 * ai_addr->sa_family
1211 * ai_addr->sa_len (IRS_PLATFORM_HAVESALEN)
1212 * and everything else is initialized to zero.
1214 static struct addrinfo
*
1215 ai_alloc(int family
, int addrlen
) {
1216 struct addrinfo
*ai
;
1218 ai
= (struct addrinfo
*)calloc(1, sizeof(*ai
));
1222 ai
->ai_addr
= SA(calloc(1, addrlen
));
1223 if (ai
->ai_addr
== NULL
) {
1227 ai
->ai_addrlen
= addrlen
;
1228 ai
->ai_family
= family
;
1229 ai
->ai_addr
->sa_family
= family
;
1230 #ifdef IRS_PLATFORM_HAVESALEN
1231 ai
->ai_addr
->sa_len
= addrlen
;
1236 static struct addrinfo
*
1237 ai_clone(struct addrinfo
*oai
, int family
) {
1238 struct addrinfo
*ai
;
1240 ai
= ai_alloc(family
, ((family
== AF_INET6
) ?
1241 sizeof(struct sockaddr_in6
) : sizeof(struct sockaddr_in
)));
1251 ai
->ai_flags
= oai
->ai_flags
;
1252 ai
->ai_socktype
= oai
->ai_socktype
;
1253 ai
->ai_protocol
= oai
->ai_protocol
;
1254 ai
->ai_canonname
= NULL
;
1259 static struct addrinfo
*
1260 ai_reverse(struct addrinfo
*oai
) {
1261 struct addrinfo
*nai
, *tai
;
1265 while (oai
!= NULL
) {
1267 * Grab one off the old list.
1272 * Put it on the front of the new list.
1281 static struct addrinfo
*
1282 ai_concat(struct addrinfo
*ai1
, struct addrinfo
*ai2
) {
1283 struct addrinfo
*ai_tmp
;
1287 else if (ai2
== NULL
)
1290 for (ai_tmp
= ai1
; ai_tmp
!= NULL
&& ai_tmp
->ai_next
!= NULL
;
1291 ai_tmp
= ai_tmp
->ai_next
)
1294 ai_tmp
->ai_next
= ai2
;