1 /* $NetBSD: getaddrinfo.c,v 1.7 2014/12/10 04:37:59 christos Exp $ */
4 * Copyright (C) 2009, 2012-2014 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/string.h>
142 #include <isc/util.h>
144 #include <dns/client.h>
145 #include <dns/fixedname.h>
146 #include <dns/name.h>
147 #include <dns/rdata.h>
148 #include <dns/rdataset.h>
149 #include <dns/rdatastruct.h>
150 #include <dns/rdatatype.h>
151 #include <dns/result.h>
153 #include <irs/context.h>
154 #include <irs/netdb.h>
155 #include <irs/resconf.h>
157 #define SA(addr) ((struct sockaddr *)(addr))
158 #define SIN(addr) ((struct sockaddr_in *)(addr))
159 #define SIN6(addr) ((struct sockaddr_in6 *)(addr))
160 #define SLOCAL(addr) ((struct sockaddr_un *)(addr))
164 static struct addrinfo
165 *ai_concat(struct addrinfo
*ai1
, struct addrinfo
*ai2
),
166 *ai_reverse(struct addrinfo
*oai
),
167 *ai_clone(struct addrinfo
*oai
, int family
),
168 *ai_alloc(int family
, int addrlen
);
170 static int get_local(const char *name
, int socktype
, struct addrinfo
**res
);
174 resolve_name(int family
, const char *hostname
, int flags
,
175 struct addrinfo
**aip
, int socktype
, int port
);
177 static int add_ipv4(const char *hostname
, int flags
, struct addrinfo
**aip
,
178 int socktype
, int port
);
179 static int add_ipv6(const char *hostname
, int flags
, struct addrinfo
**aip
,
180 int socktype
, int port
);
181 static void set_order(int, int (**)(const char *, int, struct addrinfo
**,
183 static void _freeaddrinfo(struct addrinfo
*ai
);
185 #define FOUND_IPV4 0x1
186 #define FOUND_IPV6 0x2
189 #define ISC_AI_MASK (AI_PASSIVE|AI_CANONNAME|AI_NUMERICHOST)
191 * Get a list of IP addresses and port numbers for host hostname and
195 getaddrinfo(const char *hostname
, const char *servname
,
196 const struct addrinfo
*hints
, struct addrinfo
**res
)
200 int family
, socktype
, flags
, protocol
;
201 struct addrinfo
*ai
, *ai_list
;
204 int (*net_order
[FOUND_MAX
+1])(const char *, int, struct addrinfo
**,
207 if (hostname
== NULL
&& servname
== NULL
)
212 if ((hints
->ai_flags
& ~(ISC_AI_MASK
)) != 0)
213 return (EAI_BADFLAGS
);
214 if (hints
->ai_addrlen
|| hints
->ai_canonname
||
215 hints
->ai_addr
|| hints
->ai_next
) {
219 family
= hints
->ai_family
;
220 socktype
= hints
->ai_socktype
;
221 protocol
= hints
->ai_protocol
;
222 flags
= hints
->ai_flags
;
225 switch (hints
->ai_socktype
) {
236 switch (hints
->ai_socktype
) {
248 return (EAI_SOCKTYPE
);
253 switch (hints
->ai_socktype
) {
261 return (EAI_SOCKTYPE
);
277 * First, deal with AF_LOCAL. If the family was not set,
278 * then assume AF_LOCAL if the first character of the
279 * hostname/servname is '/'.
282 if (hostname
!= NULL
&&
283 (family
== AF_LOCAL
|| (family
== 0 && *hostname
== '/')))
284 return (get_local(hostname
, socktype
, res
));
286 if (servname
!= NULL
&&
287 (family
== AF_LOCAL
|| (family
== 0 && *servname
== '/')))
288 return (get_local(servname
, socktype
, res
));
292 * Ok, only AF_INET and AF_INET6 left.
297 * First, look up the service name (port) if it was
298 * requested. If the socket type wasn't specified, then
299 * try and figure it out.
301 if (servname
!= NULL
) {
304 port
= strtol(servname
, &e
, 10);
307 return (EAI_SOCKTYPE
);
308 if (port
< 0 || port
> 65535)
309 return (EAI_SERVICE
);
310 port
= htons((unsigned short) port
);
312 sp
= getservbyname(servname
, proto
);
314 return (EAI_SERVICE
);
317 if (strcmp(sp
->s_proto
, "tcp") == 0)
318 socktype
= SOCK_STREAM
;
319 else if (strcmp(sp
->s_proto
, "udp") == 0)
320 socktype
= SOCK_DGRAM
;
327 * Next, deal with just a service name, and no hostname.
328 * (we verified that one of them was non-null up above).
330 if (hostname
== NULL
&& (flags
& AI_PASSIVE
) != 0) {
331 if (family
== AF_INET
|| family
== 0) {
332 ai
= ai_alloc(AF_INET
, sizeof(struct sockaddr_in
));
335 ai
->ai_socktype
= socktype
;
336 ai
->ai_protocol
= protocol
;
337 SIN(ai
->ai_addr
)->sin_port
= port
;
338 ai
->ai_next
= ai_list
;
342 if (family
== AF_INET6
|| family
== 0) {
343 ai
= ai_alloc(AF_INET6
, sizeof(struct sockaddr_in6
));
345 _freeaddrinfo(ai_list
);
348 ai
->ai_socktype
= socktype
;
349 ai
->ai_protocol
= protocol
;
350 SIN6(ai
->ai_addr
)->sin6_port
= port
;
351 ai
->ai_next
= ai_list
;
360 * If the family isn't specified or AI_NUMERICHOST specified, check
361 * first to see if it is a numeric address.
362 * Though the gethostbyname2() routine will recognize numeric addresses,
363 * it will only recognize the format that it is being called for. Thus,
364 * a numeric AF_INET address will be treated by the AF_INET6 call as
365 * a domain name, and vice versa. Checking for both numerics here
368 if (hostname
!= NULL
&&
369 (family
== 0 || (flags
& AI_NUMERICHOST
) != 0)) {
370 char abuf
[sizeof(struct in6_addr
)];
371 char nbuf
[NI_MAXHOST
];
372 int addrsize
, addroff
;
373 #ifdef IRS_HAVE_SIN6_SCOPE_ID
375 char ntmp
[NI_MAXHOST
];
376 isc_uint32_t scopeid
;
379 #ifdef IRS_HAVE_SIN6_SCOPE_ID
381 * Scope identifier portion.
384 if (strchr(hostname
, '%') != NULL
) {
385 strncpy(ntmp
, hostname
, sizeof(ntmp
) - 1);
386 ntmp
[sizeof(ntmp
) - 1] = '\0';
387 p
= strchr(ntmp
, '%');
391 * Vendors may want to support non-numeric
392 * scopeid around here.
396 scopeid
= (isc_uint32_t
)strtoul(p
+ 1,
398 if (p
!= NULL
&& ep
!= NULL
&& ep
[0] == '\0')
408 if (inet_pton(AF_INET
, hostname
, (struct in_addr
*)abuf
)
410 if (family
== AF_INET6
) {
412 * Convert to a V4 mapped address.
414 struct in6_addr
*a6
= (struct in6_addr
*)abuf
;
415 memmove(&a6
->s6_addr
[12], &a6
->s6_addr
[0], 4);
416 memset(&a6
->s6_addr
[10], 0xff, 2);
417 memset(&a6
->s6_addr
[0], 0, 10);
420 addrsize
= sizeof(struct in_addr
);
421 addroff
= (char *)(&SIN(0)->sin_addr
) - (char *)0;
424 #ifdef IRS_HAVE_SIN6_SCOPE_ID
425 } else if (ntmp
[0] != '\0' &&
426 inet_pton(AF_INET6
, ntmp
, abuf
) == 1) {
427 if (family
&& family
!= AF_INET6
)
429 addrsize
= sizeof(struct in6_addr
);
430 addroff
= (char *)(&SIN6(0)->sin6_addr
) - (char *)0;
434 } else if (inet_pton(AF_INET6
, hostname
, abuf
) == 1) {
435 if (family
!= 0 && family
!= AF_INET6
)
438 addrsize
= sizeof(struct in6_addr
);
439 addroff
= (char *)(&SIN6(0)->sin6_addr
) - (char *)0;
443 ai
= ai_alloc(family
,
444 ((family
== AF_INET6
) ?
445 sizeof(struct sockaddr_in6
) :
446 sizeof(struct sockaddr_in
)));
450 ai
->ai_socktype
= socktype
;
451 SIN(ai
->ai_addr
)->sin_port
= port
;
452 memmove((char *)ai
->ai_addr
+ addroff
, abuf
, addrsize
);
453 if ((flags
& AI_CANONNAME
) != 0) {
454 #ifdef IRS_HAVE_SIN6_SCOPE_ID
455 if (ai
->ai_family
== AF_INET6
)
456 SIN6(ai
->ai_addr
)->sin6_scope_id
=
459 if (getnameinfo(ai
->ai_addr
,
460 (socklen_t
)ai
->ai_addrlen
,
461 nbuf
, sizeof(nbuf
), NULL
, 0,
462 NI_NUMERICHOST
) == 0) {
463 ai
->ai_canonname
= strdup(nbuf
);
464 if (ai
->ai_canonname
== NULL
) {
469 /* XXX raise error? */
470 ai
->ai_canonname
= NULL
;
474 } else if ((flags
& AI_NUMERICHOST
) != 0) {
479 if (hostname
== NULL
&& (flags
& AI_PASSIVE
) == 0) {
480 set_order(family
, net_order
);
481 for (i
= 0; i
< FOUND_MAX
; i
++) {
482 if (net_order
[i
] == NULL
)
484 err
= (net_order
[i
])(hostname
, flags
, &ai_list
,
487 if (ai_list
!= NULL
) {
488 _freeaddrinfo(ai_list
);
495 err
= resolve_name(family
, hostname
, flags
, &ai_list
,
498 if (ai_list
== NULL
) {
505 ai_list
= ai_reverse(ai_list
);
511 typedef struct gai_restrans
{
512 dns_clientrestrans_t
*xid
;
513 isc_boolean_t is_inprogress
;
515 struct addrinfo ai_sentinel
;
516 struct gai_resstate
*resstate
;
519 typedef struct gai_resstate
{
521 struct gai_statehead
*head
;
522 dns_fixedname_t fixedname
;
524 gai_restrans_t
*trans4
;
525 gai_restrans_t
*trans6
;
526 ISC_LINK(struct gai_resstate
) link
;
529 typedef struct gai_statehead
{
535 dns_client_t
*dnsclient
;
536 ISC_LIST(struct gai_resstate
) resstates
;
537 unsigned int activestates
;
541 make_resstate(isc_mem_t
*mctx
, gai_statehead_t
*head
, const char *hostname
,
542 const char *domain
, gai_resstate_t
**statep
)
545 gai_resstate_t
*state
;
546 dns_fixedname_t fixeddomain
;
548 unsigned int namelen
;
550 isc_boolean_t need_v4
= ISC_FALSE
;
551 isc_boolean_t need_v6
= ISC_FALSE
;
553 state
= isc_mem_get(mctx
, sizeof(*state
));
555 return (ISC_R_NOMEMORY
);
557 /* Construct base domain name */
558 namelen
= strlen(domain
);
559 isc_buffer_constinit(&b
, domain
, namelen
);
560 isc_buffer_add(&b
, namelen
);
561 dns_fixedname_init(&fixeddomain
);
562 qdomain
= dns_fixedname_name(&fixeddomain
);
563 result
= dns_name_fromtext(qdomain
, &b
, dns_rootname
, 0, NULL
);
564 if (result
!= ISC_R_SUCCESS
) {
565 isc_mem_put(mctx
, state
, sizeof(*state
));
569 /* Construct query name */
570 namelen
= strlen(hostname
);
571 isc_buffer_constinit(&b
, hostname
, namelen
);
572 isc_buffer_add(&b
, namelen
);
573 dns_fixedname_init(&state
->fixedname
);
574 state
->qname
= dns_fixedname_name(&state
->fixedname
);
575 result
= dns_name_fromtext(state
->qname
, &b
, qdomain
, 0, NULL
);
576 if (result
!= ISC_R_SUCCESS
) {
577 isc_mem_put(mctx
, state
, sizeof(*state
));
581 if (head
->ai_family
== AF_UNSPEC
|| head
->ai_family
== AF_INET
)
583 if (head
->ai_family
== AF_UNSPEC
|| head
->ai_family
== AF_INET6
)
586 state
->trans6
= NULL
;
587 state
->trans4
= NULL
;
589 state
->trans4
= isc_mem_get(mctx
, sizeof(gai_restrans_t
));
590 if (state
->trans4
== NULL
) {
591 isc_mem_put(mctx
, state
, sizeof(*state
));
592 return (ISC_R_NOMEMORY
);
594 state
->trans4
->error
= 0;
595 state
->trans4
->xid
= NULL
;
596 state
->trans4
->resstate
= state
;
597 state
->trans4
->is_inprogress
= ISC_TRUE
;
598 state
->trans4
->ai_sentinel
.ai_next
= NULL
;
601 state
->trans6
= isc_mem_get(mctx
, sizeof(gai_restrans_t
));
602 if (state
->trans6
== NULL
) {
603 if (state
->trans4
!= NULL
)
604 isc_mem_put(mctx
, state
->trans4
,
605 sizeof(*state
->trans4
));
606 isc_mem_put(mctx
, state
, sizeof(*state
));
607 return (ISC_R_NOMEMORY
);
609 state
->trans6
->error
= 0;
610 state
->trans6
->xid
= NULL
;
611 state
->trans6
->resstate
= state
;
612 state
->trans6
->is_inprogress
= ISC_TRUE
;
613 state
->trans6
->ai_sentinel
.ai_next
= NULL
;
618 ISC_LINK_INIT(state
, link
);
622 return (ISC_R_SUCCESS
);
626 make_resstates(isc_mem_t
*mctx
, const char *hostname
, gai_statehead_t
*head
,
627 irs_resconf_t
*resconf
)
630 irs_resconf_searchlist_t
*searchlist
;
631 irs_resconf_search_t
*searchent
;
632 gai_resstate_t
*resstate
, *resstate0
;
635 result
= make_resstate(mctx
, head
, hostname
, ".", &resstate0
);
636 if (result
!= ISC_R_SUCCESS
)
639 searchlist
= irs_resconf_getsearchlist(resconf
);
640 for (searchent
= ISC_LIST_HEAD(*searchlist
); searchent
!= NULL
;
641 searchent
= ISC_LIST_NEXT(searchent
, link
)) {
643 result
= make_resstate(mctx
, head
, hostname
,
644 (const char *)searchent
->domain
,
646 if (result
!= ISC_R_SUCCESS
)
649 ISC_LIST_APPEND(head
->resstates
, resstate
, link
);
650 head
->activestates
++;
654 * Insert the original hostname either at the head or the tail of the
655 * state list, depending on the number of labels contained in the
656 * original name and the 'ndots' configuration parameter.
658 if (dns_name_countlabels(resstate0
->qname
) >
659 irs_resconf_getndots(resconf
) + 1) {
660 ISC_LIST_PREPEND(head
->resstates
, resstate0
, link
);
662 ISC_LIST_APPEND(head
->resstates
, resstate0
, link
);
663 head
->activestates
++;
665 if (result
!= ISC_R_SUCCESS
) {
666 while ((resstate
= ISC_LIST_HEAD(head
->resstates
)) != NULL
) {
667 ISC_LIST_UNLINK(head
->resstates
, resstate
, link
);
668 if (resstate
->trans4
!= NULL
) {
669 isc_mem_put(mctx
, resstate
->trans4
,
670 sizeof(*resstate
->trans4
));
672 if (resstate
->trans6
!= NULL
) {
673 isc_mem_put(mctx
, resstate
->trans6
,
674 sizeof(*resstate
->trans6
));
677 isc_mem_put(mctx
, resstate
, sizeof(*resstate
));
685 process_answer(isc_task_t
*task
, isc_event_t
*event
) {
686 int error
= 0, family
;
687 gai_restrans_t
*trans
= event
->ev_arg
;
688 gai_resstate_t
*resstate
;
689 dns_clientresevent_t
*rev
= (dns_clientresevent_t
*)event
;
690 dns_rdatatype_t qtype
;
693 REQUIRE(trans
!= NULL
);
694 resstate
= trans
->resstate
;
695 REQUIRE(resstate
!= NULL
);
696 REQUIRE(task
!= NULL
);
698 if (trans
== resstate
->trans4
) {
700 qtype
= dns_rdatatype_a
;
702 INSIST(trans
== resstate
->trans6
);
704 qtype
= dns_rdatatype_aaaa
;
707 INSIST(trans
->is_inprogress
);
708 trans
->is_inprogress
= ISC_FALSE
;
710 switch (rev
->result
) {
712 case DNS_R_NCACHENXDOMAIN
: /* treat this as a fatal error? */
713 case DNS_R_NCACHENXRRSET
:
716 switch (rev
->vresult
) {
717 case DNS_R_SIGINVALID
:
718 case DNS_R_SIGEXPIRED
:
719 case DNS_R_SIGFUTURE
:
720 case DNS_R_KEYUNAUTHORIZED
:
721 case DNS_R_MUSTBESECURE
:
722 case DNS_R_COVERINGNSEC
:
723 case DNS_R_NOTAUTHORITATIVE
:
724 case DNS_R_NOVALIDKEY
:
725 case DNS_R_NOVALIDDS
:
726 case DNS_R_NOVALIDSIG
:
727 error
= EAI_INSECUREDATA
;
735 /* Parse the response and construct the addrinfo chain */
736 for (name
= ISC_LIST_HEAD(rev
->answerlist
); name
!= NULL
;
737 name
= ISC_LIST_NEXT(name
, link
)) {
739 dns_rdataset_t
*rdataset
;
744 for (rdataset
= ISC_LIST_HEAD(name
->list
);
746 rdataset
= ISC_LIST_NEXT(rdataset
, link
)) {
747 if (!dns_rdataset_isassociated(rdataset
))
749 if (rdataset
->type
!= qtype
)
752 if ((resstate
->head
->ai_flags
& AI_CANONNAME
) != 0) {
753 isc_buffer_init(&b
, t
, sizeof(t
));
754 result
= dns_name_totext(name
, ISC_TRUE
, &b
);
755 if (result
!= ISC_R_SUCCESS
) {
759 isc_buffer_putuint8(&b
, '\0');
760 isc_buffer_usedregion(&b
, &r
);
763 for (result
= dns_rdataset_first(rdataset
);
764 result
== ISC_R_SUCCESS
;
765 result
= dns_rdataset_next(rdataset
)) {
768 dns_rdata_in_a_t rdata_a
;
769 dns_rdata_in_aaaa_t rdata_aaaa
;
771 ai
= ai_alloc(family
,
772 ((family
== AF_INET6
) ?
773 sizeof(struct sockaddr_in6
) :
774 sizeof(struct sockaddr_in
)));
779 ai
->ai_socktype
= resstate
->head
->ai_socktype
;
780 ai
->ai_next
= trans
->ai_sentinel
.ai_next
;
781 trans
->ai_sentinel
.ai_next
= ai
;
784 * Set AF-specific parameters
785 * (IPv4/v6 address/port)
787 dns_rdata_init(&rdata
);
790 dns_rdataset_current(rdataset
, &rdata
);
791 result
= dns_rdata_tostruct(&rdata
, &rdata_a
,
793 RUNTIME_CHECK(result
== ISC_R_SUCCESS
);
794 SIN(ai
->ai_addr
)->sin_port
=
795 resstate
->head
->ai_port
;
796 memmove(&SIN(ai
->ai_addr
)->sin_addr
,
797 &rdata_a
.in_addr
, 4);
798 dns_rdata_freestruct(&rdata_a
);
801 dns_rdataset_current(rdataset
, &rdata
);
802 result
= dns_rdata_tostruct(&rdata
, &rdata_aaaa
,
804 RUNTIME_CHECK(result
== ISC_R_SUCCESS
);
805 SIN6(ai
->ai_addr
)->sin6_port
=
806 resstate
->head
->ai_port
;
807 memmove(&SIN6(ai
->ai_addr
)->sin6_addr
,
808 &rdata_aaaa
.in6_addr
, 16);
809 dns_rdata_freestruct(&rdata_aaaa
);
813 if ((resstate
->head
->ai_flags
& AI_CANONNAME
)
816 strdup((const char *)r
.base
);
817 if (ai
->ai_canonname
== NULL
) {
827 dns_client_freeresanswer(resstate
->head
->dnsclient
, &rev
->answerlist
);
828 dns_client_destroyrestrans(&trans
->xid
);
830 isc_event_free(&event
);
832 /* Make sure that error == 0 iff we have a non-empty list */
834 if (trans
->ai_sentinel
.ai_next
== NULL
)
837 if (trans
->ai_sentinel
.ai_next
!= NULL
) {
838 _freeaddrinfo(trans
->ai_sentinel
.ai_next
);
839 trans
->ai_sentinel
.ai_next
= NULL
;
842 trans
->error
= error
;
844 /* Check whether we are done */
845 if ((resstate
->trans4
== NULL
|| !resstate
->trans4
->is_inprogress
) &&
846 (resstate
->trans6
== NULL
|| !resstate
->trans6
->is_inprogress
)) {
848 * We're done for this state. If there is no other outstanding
849 * state, we can exit.
851 resstate
->head
->activestates
--;
852 if (resstate
->head
->activestates
== 0) {
853 isc_app_ctxsuspend(resstate
->head
->actx
);
858 * There are outstanding states, but if we are at the head
859 * of the state list (i.e., at the highest search priority)
860 * and have any answer, we can stop now by canceling the
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
,
898 resolve_name(int family
, const char *hostname
, int flags
,
899 struct addrinfo
**aip
, int socktype
, int port
)
902 irs_context_t
*irsctx
;
909 dns_client_t
*client
;
910 gai_resstate_t
*resstate
;
911 gai_statehead_t head
;
912 isc_boolean_t all_fail
= ISC_TRUE
;
914 /* get IRS context and the associated parameters */
916 result
= irs_context_get(&irsctx
);
917 if (result
!= ISC_R_SUCCESS
)
919 actx
= irs_context_getappctx(irsctx
);
921 mctx
= irs_context_getmctx(irsctx
);
922 task
= irs_context_gettask(irsctx
);
923 conf
= irs_context_getresconf(irsctx
);
924 client
= irs_context_getdnsclient(irsctx
);
926 /* construct resolution states */
927 head
.activestates
= 0;
928 head
.ai_family
= family
;
929 head
.ai_socktype
= socktype
;
930 head
.ai_flags
= flags
;
933 head
.dnsclient
= client
;
934 ISC_LIST_INIT(head
.resstates
);
935 result
= make_resstates(mctx
, hostname
, &head
, conf
);
936 if (result
!= ISC_R_SUCCESS
)
939 for (resstate
= ISC_LIST_HEAD(head
.resstates
);
940 resstate
!= NULL
; resstate
= ISC_LIST_NEXT(resstate
, link
)) {
941 if (resstate
->trans4
!= NULL
) {
942 result
= dns_client_startresolve(client
,
949 &resstate
->trans4
->xid
);
950 if (result
== ISC_R_SUCCESS
) {
951 resstate
->trans4
->is_inprogress
= ISC_TRUE
;
952 all_fail
= ISC_FALSE
;
954 resstate
->trans4
->is_inprogress
= ISC_FALSE
;
956 if (resstate
->trans6
!= NULL
) {
957 result
= dns_client_startresolve(client
,
964 &resstate
->trans6
->xid
);
965 if (result
== ISC_R_SUCCESS
) {
966 resstate
->trans6
->is_inprogress
= ISC_TRUE
;
967 all_fail
= ISC_FALSE
;
969 resstate
->trans6
->is_inprogress
= ISC_FALSE
;
973 /* Start all the events */
974 isc_app_ctxrun(actx
);
979 while ((resstate
= ISC_LIST_HEAD(head
.resstates
)) != NULL
) {
980 int terror4
= 0, terror6
= 0;
982 ISC_LIST_UNLINK(head
.resstates
, resstate
, link
);
985 struct addrinfo
*sentinel4
= NULL
;
986 struct addrinfo
*sentinel6
= NULL
;
988 if (resstate
->trans4
!= NULL
) {
990 resstate
->trans4
->ai_sentinel
.ai_next
;
991 resstate
->trans4
->ai_sentinel
.ai_next
= NULL
;
993 if (resstate
->trans6
!= NULL
) {
995 resstate
->trans6
->ai_sentinel
.ai_next
;
996 resstate
->trans6
->ai_sentinel
.ai_next
= NULL
;
998 *aip
= ai_concat(sentinel4
, sentinel6
);
1001 if (resstate
->trans4
!= NULL
) {
1002 INSIST(resstate
->trans4
->xid
== NULL
);
1003 terror4
= resstate
->trans4
->error
;
1004 isc_mem_put(mctx
, resstate
->trans4
,
1005 sizeof(*resstate
->trans4
));
1007 if (resstate
->trans6
!= NULL
) {
1008 INSIST(resstate
->trans6
->xid
== NULL
);
1009 terror6
= resstate
->trans6
->error
;
1010 isc_mem_put(mctx
, resstate
->trans6
,
1011 sizeof(*resstate
->trans6
));
1015 * If the entire lookup fails, we need to choose an appropriate
1016 * error code from individual codes. We'll try to provide as
1017 * specific a code as possible. In general, we are going to
1018 * find an error code other than EAI_NONAME (which is too
1019 * generic and may actually not be problematic in some cases).
1020 * EAI_NONAME will be set below if no better code is found.
1022 if (terror
== 0 || terror
== EAI_NONAME
) {
1023 if (terror4
!= 0 && terror4
!= EAI_NONAME
)
1025 else if (terror6
!= 0 && terror6
!= EAI_NONAME
)
1029 isc_mem_put(mctx
, resstate
, sizeof(*resstate
));
1038 #if 1 /* XXX: enabled for finding leaks. should be cleaned up later. */
1039 isc_app_ctxfinish(actx
);
1040 irs_context_destroy(&irsctx
);
1047 irs_strsep(char **stringp
, const char *delim
) {
1048 char *string
= *stringp
;
1056 for (s
= string
; *s
!= '\0'; s
++) {
1058 for (d
= delim
; (dc
= *d
) != '\0'; d
++)
1070 set_order(int family
, int (**net_order
)(const char *, int, struct addrinfo
**,
1079 *net_order
++ = add_ipv4
;
1082 *net_order
++ = add_ipv6
;
1086 order
= getenv("NET_ORDER");
1088 while (order
!= NULL
) {
1090 * We ignore any unknown names.
1092 tok
= irs_strsep(&order
, ":");
1093 if (strcasecmp(tok
, "inet6") == 0) {
1094 if ((found
& FOUND_IPV6
) == 0)
1095 *net_order
++ = add_ipv6
;
1096 found
|= FOUND_IPV6
;
1097 } else if (strcasecmp(tok
, "inet") == 0 ||
1098 strcasecmp(tok
, "inet4") == 0) {
1099 if ((found
& FOUND_IPV4
) == 0)
1100 *net_order
++ = add_ipv4
;
1101 found
|= FOUND_IPV4
;
1106 * Add in anything that we didn't find.
1108 if ((found
& FOUND_IPV4
) == 0)
1109 *net_order
++ = add_ipv4
;
1110 if ((found
& FOUND_IPV6
) == 0)
1111 *net_order
++ = add_ipv6
;
1117 static char v4_loop
[4] = { 127, 0, 0, 1 };
1120 add_ipv4(const char *hostname
, int flags
, struct addrinfo
**aip
,
1121 int socktype
, int port
)
1123 struct addrinfo
*ai
;
1128 ai
= ai_clone(*aip
, AF_INET
); /* don't use ai_clone() */
1130 _freeaddrinfo(*aip
);
1131 return (EAI_MEMORY
);
1135 ai
->ai_socktype
= socktype
;
1136 SIN(ai
->ai_addr
)->sin_port
= port
;
1137 memmove(&SIN(ai
->ai_addr
)->sin_addr
, v4_loop
, 4);
1142 static char v6_loop
[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
1145 add_ipv6(const char *hostname
, int flags
, struct addrinfo
**aip
,
1146 int socktype
, int port
)
1148 struct addrinfo
*ai
;
1153 ai
= ai_clone(*aip
, AF_INET6
); /* don't use ai_clone() */
1155 return (EAI_MEMORY
);
1158 ai
->ai_socktype
= socktype
;
1159 SIN6(ai
->ai_addr
)->sin6_port
= port
;
1160 memmove(&SIN6(ai
->ai_addr
)->sin6_addr
, v6_loop
, 16);
1165 /*% Free address info. */
1167 freeaddrinfo(struct addrinfo
*ai
) {
1172 _freeaddrinfo(struct addrinfo
*ai
) {
1173 struct addrinfo
*ai_next
;
1175 while (ai
!= NULL
) {
1176 ai_next
= ai
->ai_next
;
1177 if (ai
->ai_addr
!= NULL
)
1179 if (ai
->ai_canonname
)
1180 free(ai
->ai_canonname
);
1188 get_local(const char *name
, int socktype
, struct addrinfo
**res
) {
1189 struct addrinfo
*ai
;
1190 struct sockaddr_un
*slocal
;
1193 return (EAI_SOCKTYPE
);
1195 ai
= ai_alloc(AF_LOCAL
, sizeof(*slocal
));
1197 return (EAI_MEMORY
);
1199 slocal
= SLOCAL(ai
->ai_addr
);
1200 strlcpy(slocal
->sun_path
, name
, sizeof(slocal
->sun_path
));
1202 ai
->ai_socktype
= socktype
;
1204 * ai->ai_flags, ai->ai_protocol, ai->ai_canonname,
1205 * and ai->ai_next were initialized to zero.
1214 * Allocate an addrinfo structure, and a sockaddr structure
1215 * of the specificed length. We initialize:
1219 * ai_addr->sa_family
1220 * ai_addr->sa_len (IRS_PLATFORM_HAVESALEN)
1221 * and everything else is initialized to zero.
1223 static struct addrinfo
*
1224 ai_alloc(int family
, int addrlen
) {
1225 struct addrinfo
*ai
;
1227 ai
= (struct addrinfo
*)calloc(1, sizeof(*ai
));
1231 ai
->ai_addr
= SA(calloc(1, addrlen
));
1232 if (ai
->ai_addr
== NULL
) {
1236 ai
->ai_addrlen
= addrlen
;
1237 ai
->ai_family
= family
;
1238 ai
->ai_addr
->sa_family
= family
;
1239 #ifdef IRS_PLATFORM_HAVESALEN
1240 ai
->ai_addr
->sa_len
= addrlen
;
1245 static struct addrinfo
*
1246 ai_clone(struct addrinfo
*oai
, int family
) {
1247 struct addrinfo
*ai
;
1249 ai
= ai_alloc(family
, ((family
== AF_INET6
) ?
1250 sizeof(struct sockaddr_in6
) : sizeof(struct sockaddr_in
)));
1260 ai
->ai_flags
= oai
->ai_flags
;
1261 ai
->ai_socktype
= oai
->ai_socktype
;
1262 ai
->ai_protocol
= oai
->ai_protocol
;
1263 ai
->ai_canonname
= NULL
;
1268 static struct addrinfo
*
1269 ai_reverse(struct addrinfo
*oai
) {
1270 struct addrinfo
*nai
, *tai
;
1274 while (oai
!= NULL
) {
1276 * Grab one off the old list.
1281 * Put it on the front of the new list.
1290 static struct addrinfo
*
1291 ai_concat(struct addrinfo
*ai1
, struct addrinfo
*ai2
) {
1292 struct addrinfo
*ai_tmp
;
1296 else if (ai2
== NULL
)
1299 for (ai_tmp
= ai1
; ai_tmp
!= NULL
&& ai_tmp
->ai_next
!= NULL
;
1300 ai_tmp
= ai_tmp
->ai_next
)
1303 ai_tmp
->ai_next
= ai2
;